diff --git a/bin/pkill/pkill.c b/bin/pkill/pkill.c --- a/bin/pkill/pkill.c +++ b/bin/pkill/pkill.c @@ -63,6 +63,7 @@ #include #include #include +#include #define STATUS_MATCH 0 #define STATUS_NOMATCH 1 @@ -130,11 +131,15 @@ static void makelist(struct listhead *, enum listtype, char *); static int takepid(const char *, int); +#define DFLT_BUF_SIZE _POSIX2_LINE_MAX +#define MAX_BUF_INCREMENT USHRT_MAX /* Arbitrary */ + int main(int argc, char **argv) { - char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile; + char *buf, *mstr, **pargv, *p, *q, *pidfile; const char *execf, *coref; + size_t bufsz; int ancestors, debug_opt, did_action; int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock; size_t jsz; @@ -146,6 +151,11 @@ regmatch_t regmatch; pid_t pid; + bufsz = DFLT_BUF_SIZE; + buf = calloc(1, bufsz); + if (buf == NULL) + err(EXIT_FAILURE, "calloc"); + setlocale(LC_ALL, ""); if (strcmp(getprogname(), "pgrep") == 0) { @@ -346,7 +356,7 @@ */ for (; *argv != NULL; argv++) { if ((rv = regcomp(®, *argv, cflags)) != 0) { - regerror(rv, ®, buf, sizeof(buf)); + regerror(rv, ®, buf, bufsz); errx(STATUS_BADUSAGE, "Cannot compile regular expression `%s' (%s)", *argv, buf); @@ -363,9 +373,26 @@ if (matchargs && (pargv = kvm_getargv(kd, kp, 0)) != NULL) { jsz = 0; - while (jsz < sizeof(buf) && *pargv != NULL) { + while (jsz < bufsz && *pargv != NULL) { + size_t arglen; + + arglen = strlen(pargv[0]); + if (jsz + arglen >= bufsz) { + /* + * Grow the buffer to a size + * that hopefully won't require + * further growth. + */ + bufsz += MAX(MIN(MAX_BUF_INCREMENT, + bufsz), arglen); + + buf = realloc(buf, bufsz); + if (buf == NULL) + err(1, "realloc"); + } + jsz += snprintf(buf + jsz, - sizeof(buf) - jsz, + bufsz - jsz, pargv[1] != NULL ? "%s " : "%s", pargv[0]); pargv++; @@ -384,7 +411,7 @@ } else selected[i] = 1; } else if (rv != REG_NOMATCH) { - regerror(rv, ®, buf, sizeof(buf)); + regerror(rv, ®, buf, bufsz); errx(STATUS_ERROR, "Regular expression evaluation error (%s)", buf); @@ -576,6 +603,7 @@ fprintf(stderr, "No matching processes belonging to you were found\n"); + free(buf); exit(rv ? STATUS_MATCH : STATUS_NOMATCH); } diff --git a/bin/pkill/tests/Makefile b/bin/pkill/tests/Makefile --- a/bin/pkill/tests/Makefile +++ b/bin/pkill/tests/Makefile @@ -2,6 +2,8 @@ .include +PACKAGE= tests + TAP_TESTS_SH= pgrep-F_test TAP_TESTS_SH+= pgrep-LF_test TAP_TESTS_SH+= pgrep-P_test @@ -10,6 +12,7 @@ TAP_TESTS_SH+= pgrep-_s_test TAP_TESTS_SH+= pgrep-g_test TAP_TESTS_SH+= pgrep-i_test +TAP_TESTS_SH+= pgrep-f_test TAP_TESTS_SH+= pgrep-j_test TEST_METADATA.pgrep-j_test+= required_user="root" TEST_METADATA.pgrep-j_test+= required_programs="jail jls" @@ -35,4 +38,6 @@ TAP_TESTS_SH+= pkill-t_test TAP_TESTS_SH+= pkill-x_test +${PACKAGE}FILES+= spin.sh + .include diff --git a/bin/pkill/tests/pgrep-f_test.sh b/bin/pkill/tests/pgrep-f_test.sh new file mode 100644 --- /dev/null +++ b/bin/pkill/tests/pgrep-f_test.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# $FreeBSD$ + +base=$(dirname $(realpath "$0")) + +echo "1..3" + +sentinel="findme=test-$$" +name="pgrep -f" +spin="sh ${base}/spin.sh" + +${spin} ${sentinel} & +chpid=$! +sleep 0.3 +pid=$(pgrep -f ${sentinel}) +if [ "$pid" = "$chpid" ]; then + echo "ok - $name" +else + echo "not ok - $name" +fi +kill $chpid + +# This requires growth of the buffer at least one, ideally it will hop +# immediately from the default size of _POSIX2_LINE_MAX (2048) to +# _POSIX2_LINE_MAX + ~8192, despite the ususal doubling behavior. +name="pgrep -f long args" +longargs=$(jot -b "x" -s "" 8192) +${spin} ${longargs} ${sentinel} & +chpid=$! +sleep 0.3 +pid=$(pgrep -f ${sentinel}) +if [ "$pid" = "$chpid" ]; then + echo "ok - $name" +else + echo "not ok - $name" +fi +kill $chpid + +name="pgrep -f multiple long args" +longargs=$(jot -b "x" -s "" 8192) +${spin} ${longargs} ${longargs} ${sentinel} & +chpid=$! +sleep 0.3 +pid=$(pgrep -f ${sentinel}) +if [ "$pid" = "$chpid" ]; then + echo "ok - $name" +else + echo "not ok - $name" +fi +kill $chpid diff --git a/bin/pkill/tests/spin.sh b/bin/pkill/tests/spin.sh new file mode 100644 --- /dev/null +++ b/bin/pkill/tests/spin.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +while true; do + sleep 1 +done