From owner-svn-src-all@freebsd.org Wed Sep 2 05:45:49 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7BCB09C8C70; Wed, 2 Sep 2015 05:45:49 +0000 (UTC) (envelope-from bapt@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 5FFC1A4F; Wed, 2 Sep 2015 05:45:49 +0000 (UTC) (envelope-from bapt@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t825jnYl022575; Wed, 2 Sep 2015 05:45:49 GMT (envelope-from bapt@FreeBSD.org) Received: (from bapt@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t825jmpT022570; Wed, 2 Sep 2015 05:45:48 GMT (envelope-from bapt@FreeBSD.org) Message-Id: <201509020545.t825jmpT022570@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: bapt set sender to bapt@FreeBSD.org using -f From: Baptiste Daroussin Date: Wed, 2 Sep 2015 05:45:48 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r287392 - in stable/10: etc/mtree usr.bin usr.bin/timeout usr.bin/timeout/tests X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 02 Sep 2015 05:45:49 -0000 Author: bapt Date: Wed Sep 2 05:45:47 2015 New Revision: 287392 URL: https://svnweb.freebsd.org/changeset/base/287392 Log: MFC: r268745,r268746,r268747,r268748,r268749,r268861,r268750,r268751,r268763 r273769,r273771,r276771,r278810 New BSDL timeout(1) utility compatible with GNU timeout Relnotes: yes Added: stable/10/usr.bin/timeout/ - copied from r268745, head/usr.bin/timeout/ stable/10/usr.bin/timeout/tests/ - copied from r273771, head/usr.bin/timeout/tests/ Modified: stable/10/etc/mtree/BSD.tests.dist stable/10/usr.bin/Makefile stable/10/usr.bin/timeout/Makefile stable/10/usr.bin/timeout/timeout.1 stable/10/usr.bin/timeout/timeout.c Directory Properties: stable/10/ (props changed) Modified: stable/10/etc/mtree/BSD.tests.dist ============================================================================== --- stable/10/etc/mtree/BSD.tests.dist Wed Sep 2 02:50:41 2015 (r287391) +++ stable/10/etc/mtree/BSD.tests.dist Wed Sep 2 05:45:47 2015 (r287392) @@ -323,6 +323,8 @@ .. .. .. + timeout + .. variables modifier_M .. Modified: stable/10/usr.bin/Makefile ============================================================================== --- stable/10/usr.bin/Makefile Wed Sep 2 02:50:41 2015 (r287391) +++ stable/10/usr.bin/Makefile Wed Sep 2 05:45:47 2015 (r287392) @@ -157,6 +157,7 @@ SUBDIR= alias \ tee \ ${_tests} \ time \ + timeout \ tip \ top \ touch \ Modified: stable/10/usr.bin/timeout/Makefile ============================================================================== --- head/usr.bin/timeout/Makefile Wed Jul 16 09:55:36 2014 (r268745) +++ stable/10/usr.bin/timeout/Makefile Wed Sep 2 05:45:47 2015 (r287392) @@ -1,5 +1,11 @@ # $FreeBSD$ +.include + PROG= timeout +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif + .include Modified: stable/10/usr.bin/timeout/timeout.1 ============================================================================== --- head/usr.bin/timeout/timeout.1 Wed Jul 16 09:55:36 2014 (r268745) +++ stable/10/usr.bin/timeout/timeout.1 Wed Sep 2 05:45:47 2015 (r287392) @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 16, 2014 +.Dd Oct 28, 2014 .Dt TIMEOUT 1 .Os .Sh NAME @@ -44,12 +44,18 @@ starts the .Ar command with its -.Ar args -and kills if it is still runs after -.Ar duration . +.Ar args. +If +.Ar command +is still running after +.Ar duration , +it is killed. +By default, +.Ar SIGTERM. +is sent. .Bl -tag -width "-k time, --kill-after time" .It Fl -preserve-status -Always exist with the same status as +Always exits with the same status as .Ar command even if it times out. .It Fl -foreground @@ -57,14 +63,67 @@ Do not propagate timeout to the .Ar command children. .It Fl s Ar sig , Fl -signal Ar sig -Speficy the signal to send on timeout by default +Specify the signal to send on timeout. +By default, .Ar SIGTERM . +is sent. .It Fl k Ar time , Fl -kill-after Ar time -Send a second kill if the +Send a second kill signal if .Ar command is still running after .Ar time -seconds after the first signal was sent +after the first signal was sent. +.El +.Sh DURATION FORMAT +.Ar duration +and +.Ar time +can be integer or decimal numbers. +Values without unit symbols are interpreted as seconds. +.Pp +Supported unit symbols are: +.Bl -tag -width indent -compact +.It s +seconds +.It m +minutes +.It h +hours +.It d +days +.El +.Sh EXIT STATUS +If the timeout was not reached, the exit status of +.Ar command +is returned. +.Pp +If the timeout was reached and +.Fl -preserve-status +is set, the exit status of +.Ar command +is returned. +If +.Fl -preserve-status +is not set, an exit status of 124 is returned. +.Pp +If +.Ar command +exits after receiving a signal, the exit status returned is the signal number +plus 128. +.Pp +If +.Ar command +is an invalid command, the exit status returned is 126. +.Pp +If +.Ar command +is a non existing command, the exit status returned is 127. +.Pp +If an invalid parameter is passed to +.Fl s +or +.Fl k , +the exit status return is 125. .Sh SEE ALSO -.Xr signal 3 , -.Xr kill 1 +.Xr kill 1 , +.Xr signal 3 Modified: stable/10/usr.bin/timeout/timeout.c ============================================================================== --- head/usr.bin/timeout/timeout.c Wed Jul 16 09:55:36 2014 (r268745) +++ stable/10/usr.bin/timeout/timeout.c Wed Sep 2 05:45:47 2015 (r287392) @@ -2,7 +2,7 @@ * Copyright (c) 2014 Baptiste Daroussin * Copyright (c) 2014 Vsevolod Stakhov * All rights reserved. - *~ + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -12,7 +12,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - *~ + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. @@ -28,20 +28,20 @@ #include __FBSDID("$FreeBSD$"); -#include +#include #include #include + +#include +#include +#include #include +#include #include #include #include #include #include -#include -#include -#include -#include -#include #define EXIT_TIMEOUT 124 @@ -53,6 +53,7 @@ static sig_atomic_t sig_ign = 0; static void usage(void) { + fprintf(stderr, "Usage: %s [--signal sig | -s sig] [--preserve-status]" " [--kill-after time | -k time] [--foreground] " " \n", getprogname()); @@ -68,7 +69,7 @@ parse_duration(const char *duration) ret = strtod(duration, &end); if (ret == 0 && end == duration) - errx(EXIT_FAILURE, "invalid duration"); + errx(125, "invalid duration"); if (end == NULL || *end == '\0') return (ret); @@ -89,11 +90,11 @@ parse_duration(const char *duration) ret *= 60 * 60 * 24; break; default: - errx(EX_USAGE, "invalid duration"); + errx(125, "invalid duration"); } - + if (ret < 0 || ret >= 100000000UL) - errx(EX_USAGE, "invalid duration"); + errx(125, "invalid duration"); return (ret); } @@ -102,11 +103,11 @@ static int parse_signal(const char *str) { int sig, i; - const char *err; + const char *errstr; - sig = strtonum(str, 0, sys_nsig, &err); + sig = strtonum(str, 0, sys_nsig, &errstr); - if (err == NULL) + if (errstr == NULL) return (sig); if (strncasecmp(str, "SIG", 3) == 0) str += 3; @@ -115,8 +116,8 @@ parse_signal(const char *str) if (strcasecmp(str, sys_signame[i]) == 0) return (i); } - - errx(EX_USAGE, "invalid signal"); + + errx(125, "invalid signal"); } static void @@ -166,13 +167,15 @@ main(int argc, char **argv) int foreground, preserve; int error, pstat, status; int killsig = SIGTERM; - int killedwith; - pid_t pgid, pid, cpid; + pid_t pid, cpid; double first_kill; double second_kill; bool timedout = false; bool do_second_kill = false; + bool child_done = false; struct sigaction signals; + struct procctl_reaper_status info; + struct procctl_reaper_kill killemall; int signums[] = { -1, SIGTERM, @@ -185,9 +188,8 @@ main(int argc, char **argv) foreground = preserve = 0; second_kill = 0; - cpid = -1; - struct option longopts[] = { + const struct option longopts[] = { { "preserve-status", no_argument, &preserve, 1 }, { "foreground", no_argument, &foreground, 1 }, { "kill-after", required_argument, NULL, 'k'}, @@ -225,10 +227,9 @@ main(int argc, char **argv) argv++; if (!foreground) { - pgid = setpgid(0,0); - - if (pgid == -1) - err(EX_OSERR, "setpgid()"); + /* Aquire a reaper */ + if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == -1) + err(EX_OSERR, "Fail to acquire the reaper"); } memset(&signals, 0, sizeof(signals)); @@ -260,8 +261,12 @@ main(int argc, char **argv) signal(SIGTTOU, SIG_DFL); error = execvp(argv[0], argv); - if (error == -1) - err(EX_UNAVAILABLE, "exec()"); + if (error == -1) { + if (errno == ENOENT) + err(127, "exec(%s)", argv[0]); + else + err(126, "exec(%s)", argv[0]); + } } if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1) @@ -270,29 +275,44 @@ main(int argc, char **argv) /* parent continues here */ set_interval(first_kill); - sigemptyset(&signals.sa_mask); - for (;;) { - killedwith = killsig; sigemptyset(&signals.sa_mask); sigsuspend(&signals.sa_mask); if (sig_chld) { sig_chld = 0; - while (((cpid = wait(&status)) < 0) && errno != EINTR) - continue; - if (cpid == pid) { - pstat = status; - break; + while ((cpid = waitpid(-1, &status, WNOHANG)) != 0) { + if (cpid < 0) { + if (errno == EINTR) + continue; + else + break; + } else if (cpid == pid) { + pstat = status; + child_done = true; + } + } + if (child_done) { + if (foreground) { + break; + } else { + procctl(P_PID, getpid(), + PROC_REAP_STATUS, &info); + if (info.rs_children == 0) + break; + } } } else if (sig_alrm) { sig_alrm = 0; timedout = true; - if (!foreground) - killpg(pgid, killsig); - else + if (!foreground) { + killemall.rk_sig = killsig; + killemall.rk_flags = 0; + procctl(P_PID, getpid(), PROC_REAP_KILL, + &killemall); + } else kill(pid, killsig); if (do_second_kill) { @@ -304,9 +324,12 @@ main(int argc, char **argv) break; } else if (sig_term) { - if (!foreground) - killpg(pgid, killsig); - else + if (!foreground) { + killemall.rk_sig = sig_term; + killemall.rk_flags = 0; + procctl(P_PID, getpid(), PROC_REAP_KILL, + &killemall); + } else kill(pid, sig_term); if (do_second_kill) { @@ -319,18 +342,21 @@ main(int argc, char **argv) } } - while (cpid != pid && wait(&pstat) == -1) { + while (!child_done && wait(&pstat) == -1) { if (errno != EINTR) err(EX_OSERR, "waitpid()"); } + if (!foreground) + procctl(P_PID, getpid(), PROC_REAP_RELEASE, NULL); + if (WEXITSTATUS(pstat)) pstat = WEXITSTATUS(pstat); else if(WIFSIGNALED(pstat)) pstat = 128 + WTERMSIG(pstat); if (timedout && !preserve) - pstat = EXIT_TIMEOUT; + pstat = EXIT_TIMEOUT; return (pstat); }