Date: Thu, 30 Oct 2025 10:38:46 GMT From: Dag-Erling =?utf-8?Q?Sm=C3=B8rgrav?= <des@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: cacba7a15e35 - stable/14 - pwait: Add an option to print remaining processes Message-ID: <202510301038.59UAckwc082544@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch stable/14 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=cacba7a15e35857da7adece3bc3cf1a3a2679b9c commit cacba7a15e35857da7adece3bc3cf1a3a2679b9c Author: Dag-Erling Smørgrav <des@FreeBSD.org> AuthorDate: 2025-10-28 11:56:36 +0000 Commit: Dag-Erling Smørgrav <des@FreeBSD.org> CommitDate: 2025-10-30 10:38:18 +0000 pwait: Add an option to print remaining processes * On startup, insert all valid PIDs into a tree. * In our main loop, whenever a process terminates, remove its PID from the tree. * On exit, if the -p flag was specified, print the remaining PIDs. MFC after: 3 days Reviewed by: bcr, markj Differential Revision: https://reviews.freebsd.org/D53293 (cherry picked from commit 3d73146baeb933fe955c7496572b483a9f92914c) --- bin/pwait/pwait.1 | 6 ++- bin/pwait/pwait.c | 98 ++++++++++++++++++++++++++++--------------- bin/pwait/tests/pwait_test.sh | 38 +++++++++++++++++ 3 files changed, 107 insertions(+), 35 deletions(-) diff --git a/bin/pwait/pwait.1 b/bin/pwait/pwait.1 index 9310b74d5683..c61f6854358b 100644 --- a/bin/pwait/pwait.1 +++ b/bin/pwait/pwait.1 @@ -30,7 +30,7 @@ .\" USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY .\" OF SUCH DAMAGE. .\" -.Dd January 21, 2021 +.Dd October 22, 2025 .Dt PWAIT 1 .Os .Sh NAME @@ -39,7 +39,7 @@ .Sh SYNOPSIS .Nm .Op Fl t Ar duration -.Op Fl ov +.Op Fl opv .Ar pid \&... .Sh DESCRIPTION @@ -51,6 +51,8 @@ The following option is available: .Bl -tag -width indent .It Fl o Exit when any of the given processes has terminated. +.It Fl p +On exit, print a list of processes that have not terminated. .It Fl t Ar duration If any process is still running after .Ar duration , diff --git a/bin/pwait/pwait.c b/bin/pwait/pwait.c index b2fea04c1b72..6e9e634b4526 100644 --- a/bin/pwait/pwait.c +++ b/bin/pwait/pwait.c @@ -34,7 +34,9 @@ #include <sys/cdefs.h> #include <sys/types.h> #include <sys/event.h> +#include <sys/sysctl.h> #include <sys/time.h> +#include <sys/tree.h> #include <sys/wait.h> #include <err.h> @@ -47,10 +49,25 @@ #include <sysexits.h> #include <unistd.h> +struct pid { + RB_ENTRY(pid) entry; + pid_t pid; +}; + +static int +pidcmp(const struct pid *a, const struct pid *b) +{ + return (a->pid > b->pid ? 1 : a->pid < b->pid ? -1 : 0); +} + +RB_HEAD(pidtree, pid); +static struct pidtree pids = RB_INITIALIZER(&pids); +RB_GENERATE_STATIC(pidtree, pid, entry, pidcmp); + static void usage(void) { - fprintf(stderr, "usage: pwait [-t timeout] [-ov] pid ...\n"); + fprintf(stderr, "usage: pwait [-t timeout] [-opv] pid ...\n"); exit(EX_USAGE); } @@ -62,22 +79,28 @@ main(int argc, char *argv[]) { struct itimerval itv; struct kevent *e; + struct pid k, *p; char *end, *s; double timeout; + size_t sz; long pid; pid_t mypid; - int i, kq, n, nleft, opt, status; - bool oflag, tflag, verbose; + int i, kq, n, ndone, nleft, opt, pid_max, ret, status; + bool oflag, pflag, tflag, verbose; oflag = false; + pflag = false; tflag = false; verbose = false; memset(&itv, 0, sizeof(itv)); - while ((opt = getopt(argc, argv, "ot:v")) != -1) { + while ((opt = getopt(argc, argv, "opt:v")) != -1) { switch (opt) { case 'o': - oflag = 1; + oflag = true; + break; + case 'p': + pflag = true; break; case 't': tflag = true; @@ -129,16 +152,17 @@ main(int argc, char *argv[]) usage(); } - kq = kqueue(); - if (kq == -1) { + if ((kq = kqueue()) < 0) err(EX_OSERR, "kqueue"); - } - e = malloc((argc + tflag) * sizeof(struct kevent)); - if (e == NULL) { + sz = sizeof(pid_max); + if (sysctlbyname("kern.pid_max", &pid_max, &sz, NULL, 0) != 0) { + pid_max = 99999; + } + if ((e = malloc((argc + tflag) * sizeof(*e))) == NULL) { err(EX_OSERR, "malloc"); } - nleft = 0; + ndone = nleft = 0; mypid = getpid(); for (n = 0; n < argc; n++) { s = argv[n]; @@ -148,7 +172,7 @@ main(int argc, char *argv[]) } errno = 0; pid = strtol(s, &end, 10); - if (pid < 0 || *end != '\0' || errno != 0) { + if (pid < 0 || pid > pid_max || *end != '\0' || errno != 0) { warnx("%s: bad process id", s); continue; } @@ -156,27 +180,29 @@ main(int argc, char *argv[]) warnx("%s: skipping my own pid", s); continue; } - for (i = 0; i < nleft; i++) { - if (e[i].ident == (uintptr_t)pid) { - break; - } + if ((p = malloc(sizeof(*p))) == NULL) { + err(EX_OSERR, NULL); } - if (i < nleft) { + p->pid = pid; + if (RB_INSERT(pidtree, &pids, p) != NULL) { /* Duplicate. */ + free(p); continue; } EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) { + if (errno != ESRCH) + err(EX_OSERR, "kevent()"); warn("%ld", pid); - if (oflag) { - exit(EX_OK); - } + RB_REMOVE(pidtree, &pids, p); + free(p); + ndone++; } else { nleft++; } } - if (nleft > 0 && tflag) { + if ((ndone == 0 || !oflag) && nleft > 0 && tflag) { /* * Explicitly detect SIGALRM so that an exit status of 124 * can be returned rather than 142. @@ -191,7 +217,8 @@ main(int argc, char *argv[]) err(EX_OSERR, "setitimer"); } } - while (nleft > 0) { + ret = EX_OK; + while ((ndone == 0 || !oflag) && ret == EX_OK && nleft > 0) { n = kevent(kq, NULL, 0, e, nleft + tflag, NULL); if (n == -1) { err(EX_OSERR, "kevent"); @@ -201,29 +228,34 @@ main(int argc, char *argv[]) if (verbose) { printf("timeout\n"); } - exit(124); + ret = 124; } + pid = e[i].ident; if (verbose) { status = e[i].data; if (WIFEXITED(status)) { printf("%ld: exited with status %d.\n", - (long)e[i].ident, - WEXITSTATUS(status)); + pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("%ld: killed by signal %d.\n", - (long)e[i].ident, - WTERMSIG(status)); + pid, WTERMSIG(status)); } else { - printf("%ld: terminated.\n", - (long)e[i].ident); + printf("%ld: terminated.\n", pid); } } - if (oflag) { - exit(EX_OK); + k.pid = pid; + if ((p = RB_FIND(pidtree, &pids, &k)) != NULL) { + RB_REMOVE(pidtree, &pids, p); + free(p); + ndone++; } --nleft; } } - - exit(EX_OK); + if (pflag) { + RB_FOREACH(p, pidtree, &pids) { + printf("%d\n", p->pid); + } + } + exit(ret); } diff --git a/bin/pwait/tests/pwait_test.sh b/bin/pwait/tests/pwait_test.sh index 66bdd6981704..d31ca21cff93 100644 --- a/bin/pwait/tests/pwait_test.sh +++ b/bin/pwait/tests/pwait_test.sh @@ -310,6 +310,43 @@ or_flag_cleanup() wait $p2 $p4 $p6 >/dev/null 2>&1 } +atf_test_case print +print_head() +{ + atf_set "descr" "Test the -p flag" +} + +print_body() +{ + sleep 1 & + p1=$! + + sleep 5 & + p5=$! + + sleep 10 & + p10=$! + + atf_check \ + -o inline:"$p5\n$p10\n" \ + -s exit:124 \ + pwait -t 2 -p $p10 $p5 $p1 $p5 $p10 + + atf_check \ + -e inline:"kill: $p1: No such process\n" \ + -s exit:1 \ + kill -0 $p1 + + atf_check kill -0 $p5 + atf_check kill -0 $p10 +} + +print_cleanup() +{ + kill $p1 $p5 $p10 >/dev/null 2>&1 + wait $p1 $p5 $p10 >/dev/null 2>&1 +} + atf_init_test_cases() { atf_add_test_case basic @@ -318,4 +355,5 @@ atf_init_test_cases() atf_add_test_case timeout_no_timeout atf_add_test_case timeout_many atf_add_test_case or_flag + atf_add_test_case print }home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202510301038.59UAckwc082544>
