From nobody Tue Oct 28 11:57:43 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cwplq6NXPz6DmSp; Tue, 28 Oct 2025 11:57:43 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cwplq5tgJz3WGy; Tue, 28 Oct 2025 11:57:43 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1761652663; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4csUDJQ6pdsJ1lFV1nX8iaV3eLuNLAUOJrq+2O/SXJM=; b=Z1Vj8vQ0Wc7QgnKure/JPKXX5X1EMwKW1aMuU21OCbwUHDskyi7fPC9AnIoukKQckZtcEN 8BDnHcbQs/7jRDXdChVKCMUMg0u0HUfQaeuzAKAZlDtbaQBeCDxsBtZWvYDITTQN+nWEee VzZ9WiADcIJcQl4ubteOOOTQ5o7/njN0XIqvpa4YiBxVwHYDLa75x4sYvVwbz3drRjy6Nf hcsT1+U9Rit3lUH6DtHhCwviTiBf6ThZcXrM6okH8RVLB5Y708b5ZBKeux+BRqMdqPsMNn QKlcdMOafsXv0sqZjyvb2puWafqcr+s7/FCTDcyjjcn0K1sgd6ALUEvJcjvI2w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1761652663; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=4csUDJQ6pdsJ1lFV1nX8iaV3eLuNLAUOJrq+2O/SXJM=; b=BTIBA9rqs8GHItbHa/jU/RlfsNybdiJhS72R7DvofJRrofENFOBGxNDMg9kMVbJqRHoY4o dZxBJSnz7swuVSk/qMuQbwRv5iFyqpbi3/WSWcWwBKkRyKNdFFJzaUo65IG6F70sP/W2Fa MG0TJnV5J9rlOONXjgtdnbS3LdODJOFNmnuqrn+eIYBn39cVEQfw1IH6VFZ+XZza6A1tdY Fvxu2xatLVBfhYklv144wMjC3me5pIsvUmLvI56oLyozxnA3xSN+hkJduqKDsdCFobwuIN 18RxT+ZKTiCUze5ZWd9hLiSy5VKfvYjVl4aZtOTsVwXotcI8vyLEMhqOOlI9XA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1761652663; a=rsa-sha256; cv=none; b=ZhIGtBom/wyqFsl2/qw9FQ/r+CZofYgcEVyb6++V5ALTpLyc8N+gzw9wNxDCkweA2/JTKS at42JSbzvYU+o7dYDrdgiW4pabM//0tMLC1XjyaUygvlsr65kDziJm52gdiZcZn14M/Lvr pF8fEp1oKKa9rbqIZ75D9r8DMtZpY9IStTWk7tCfMdbQhjuSejG6N1vkCLfUs7GFs8IEwf y36ciL3Nj3cBdThFqhMU3Wmx/gAgfxX+D2QVAHWvWG4JkL/MsjH5eDcJosJZgMSpzE7MBH d2B22GyGphJAabJsJhZb62aN8kThC6gW5u4LzOOq3dTIHAwm4+noiaI3nyvxKw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4cwplq5N8bzpyD; Tue, 28 Oct 2025 11:57:43 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 59SBvhES002873; Tue, 28 Oct 2025 11:57:43 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 59SBvhNB002870; Tue, 28 Oct 2025 11:57:43 GMT (envelope-from git) Date: Tue, 28 Oct 2025 11:57:43 GMT Message-Id: <202510281157.59SBvhNB002870@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dag-Erling =?utf-8?Q?Sm=C3=B8rgrav?= Subject: git: 3d73146baeb9 - main - pwait: Add an option to print remaining processes List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 3d73146baeb933fe955c7496572b483a9f92914c Auto-Submitted: auto-generated The branch main has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=3d73146baeb933fe955c7496572b483a9f92914c commit 3d73146baeb933fe955c7496572b483a9f92914c Author: Dag-Erling Smørgrav AuthorDate: 2025-10-28 11:56:36 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2025-10-28 11:57:16 +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 --- 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 83ac8bcef317..d92b829b1d6a 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 27f4c8e9858d..59bf0eb93ced 100644 --- a/bin/pwait/pwait.c +++ b/bin/pwait/pwait.c @@ -33,7 +33,9 @@ #include #include +#include #include +#include #include #include @@ -46,10 +48,25 @@ #include #include +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); } @@ -61,22 +78,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; @@ -128,16 +151,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]; @@ -147,7 +171,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; } @@ -155,27 +179,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. @@ -190,7 +216,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"); @@ -200,29 +227,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 }