From 0c887b157e2697400b9f4a3ca919fa6595acee05 Mon Sep 17 00:00:00 2001 From: Jan Rybar Date: Thu, 22 Dec 2022 15:08:39 +0100 Subject: [PATCH] Rebase to 4.0.2 New version and name of libproc is introduced. The library is completely rewritten and different from procps-ng-3.*. All dependencies on procps-ng-devel must align with this change. --- .gitignore | 7 +- covscan-findings.patch | 49 -- free-si-fix.patch | 12 - pidof-show-worker-threads.patch | 41 - pidof-show-workers-option.patch | 99 --- pkill-manpage-e-option.patch | 22 - procps-ng-3.3.12-ps-luid-format-option.patch | 61 -- procps-ng-3.3.13-build-fails-due-libio.patch | 11 - procps-ng-3.3.14-CVE-2018-1124.patch | 337 -------- procps-ng.spec | 43 +- ps-exe-format-option.patch | 58 -- pwait-to-pidwait.patch | 286 ------- sources | 2 +- sysctl-hyphen-param.patch | 833 ------------------- sysctl-print-dotted-keys-again.patch | 153 ---- 15 files changed, 16 insertions(+), 1998 deletions(-) delete mode 100644 covscan-findings.patch delete mode 100644 free-si-fix.patch delete mode 100644 pidof-show-worker-threads.patch delete mode 100644 pidof-show-workers-option.patch delete mode 100644 pkill-manpage-e-option.patch delete mode 100644 procps-ng-3.3.12-ps-luid-format-option.patch delete mode 100644 procps-ng-3.3.13-build-fails-due-libio.patch delete mode 100644 procps-ng-3.3.14-CVE-2018-1124.patch delete mode 100644 ps-exe-format-option.patch delete mode 100644 pwait-to-pidwait.patch delete mode 100644 sysctl-hyphen-param.patch delete mode 100644 sysctl-print-dotted-keys-again.patch diff --git a/.gitignore b/.gitignore index 8aa742d..3e6cb44 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1 @@ -/procps-ng-3.3.12.tar.xz -/procps-ng-3.3.13.tar.xz -/procps-ng-3.3.14.tar.xz -/procps-ng-3.3.15.tar.xz -/procps-ng-3.3.16.tar.xz -/procps-ng-3.3.17.tar.xz +/procps-ng-4.0.2.tar.xz diff --git a/covscan-findings.patch b/covscan-findings.patch deleted file mode 100644 index c9a3b22..0000000 --- a/covscan-findings.patch +++ /dev/null @@ -1,49 +0,0 @@ -diff --git a/lib/test_process.c b/lib/test_process.c -index e20b270d..f8ff5ed0 100644 ---- a/lib/test_process.c -+++ b/lib/test_process.c -@@ -69,6 +69,7 @@ signal_handler(int signum, siginfo_t *siginfo, void *ucontext) - exit(EXIT_FAILURE); - } - -+ free(signame); - } - - int main(int argc, char *argv[]) -diff --git a/pmap.c b/pmap.c -index 49a2a6a8..d8565fc3 100644 ---- a/pmap.c -+++ b/pmap.c -@@ -346,6 +346,9 @@ static void print_extended_maps (FILE *f) - if (listnode == NULL) { - assert(firstmapping == 2); - listnode = calloc(1, sizeof *listnode); -+ if (listnode == NULL) -+ xerrx(EXIT_FAILURE, _("ERROR: memory allocation failed")); -+ - if (listhead == NULL) { - assert(listtail == NULL); - listhead = listnode; -diff --git a/watch.c b/watch.c -index 1a95454e..772879cd 100644 ---- a/watch.c -+++ b/watch.c -@@ -124,8 +124,6 @@ static void reset_ansi(void) - - static void init_ansi_colors(void) - { -- int color; -- - short ncurses_colors[] = { - -1, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, - COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE -@@ -172,6 +170,9 @@ static int process_ansi_color_escape_sequence(char** escape_sequence) { - // ESC[ 48;2;⟨r⟩;⟨g⟩;⟨b⟩ m Select RGB background color - int num; - -+ if (!escape_sequence) -+ return 0; /* avoid NULLPTR dereference, return "not understood" */ -+ - if ((*escape_sequence)[0] != ';') - return 0; /* not understood */ - diff --git a/free-si-fix.patch b/free-si-fix.patch deleted file mode 100644 index c414a98..0000000 --- a/free-si-fix.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up ./free.c.ori ./free.c ---- ./free.c.ori 2022-09-20 15:02:22.469320938 +0200 -+++ ./free.c 2022-09-20 15:03:33.767710892 +0200 -@@ -120,7 +120,7 @@ static const char *scale_size(unsigned l - - /* default output */ - if (args.exponent == 0 && !(flags & FREE_HUMANREADABLE)) { -- snprintf(buf, sizeof(buf), "%ld", size); -+ snprintf(buf, sizeof(buf), "%ld", (long)( ((long long int)size) * 1024 / (long long int)base)); - return buf; - } - diff --git a/pidof-show-worker-threads.patch b/pidof-show-worker-threads.patch deleted file mode 100644 index 229204b..0000000 --- a/pidof-show-worker-threads.patch +++ /dev/null @@ -1,41 +0,0 @@ -diff --git a/pidof.c b/pidof.c -index b0d08cc..90ecb13 100644 ---- a/pidof.c -+++ b/pidof.c -@@ -142,6 +142,7 @@ static void select_procs (void) - static int size = 0; - char *cmd_arg0, *cmd_arg0base; - char *cmd_arg1, *cmd_arg1base; -+ char *stat_cmd; - char *program_base; - char *root_link; - char *exe_link; -@@ -167,9 +168,10 @@ static void select_procs (void) - } - } - -- if (!is_omitted(task.XXXID) && task.cmdline && *task.cmdline) { -+ if (!is_omitted(task.XXXID)) { - -- cmd_arg0 = *task.cmdline; -+ cmd_arg0 = (task.cmdline && *task.cmdline) ? *task.cmdline : "\0"; -+ stat_cmd = task.cmd ? task.cmd : "\0"; - - /* processes starting with '-' are login shells */ - if (*cmd_arg0 == '-') { -@@ -191,12 +193,14 @@ static void select_procs (void) - !strcmp(program_base, cmd_arg0) || - !strcmp(program, cmd_arg0) || - -+ !strcmp(program, stat_cmd) || -+ - !strcmp(program, exe_link_base) || - !strcmp(program, exe_link)) - { - match = 1; - -- } else if (opt_scripts_too && *(task.cmdline+1)) { -+ } else if (opt_scripts_too && task.cmdline && *(task.cmdline+1)) { - - cmd_arg1 = *(task.cmdline+1); - diff --git a/pidof-show-workers-option.patch b/pidof-show-workers-option.patch deleted file mode 100644 index d674140..0000000 --- a/pidof-show-workers-option.patch +++ /dev/null @@ -1,99 +0,0 @@ -diff --git a/pidof.1 b/pidof.1 -index 8ef4abf..5f95b85 100644 ---- a/pidof.1 -+++ b/pidof.1 -@@ -45,6 +45,9 @@ the current root directory of processes they do not own. - .IP \-x - Scripts too - this causes the program to also return process id's of - shells running the named scripts. -+.IP \-w -+Show also processes that do not have visible command line (e.g. kernel -+worker threads). - .IP "-o \fIomitpid\fP" - Tells \fIpidof\fP to omit processes with that process id. The special - pid \fB%PPID\fP can be used to name the parent process of the \fIpidof\fP -diff --git a/pidof.c b/pidof.c -index 90ecb13..0754754 100644 ---- a/pidof.c -+++ b/pidof.c -@@ -55,6 +55,8 @@ static char *program = NULL; - static int opt_single_shot = 0; /* -s */ - static int opt_scripts_too = 0; /* -x */ - static int opt_rootdir_check = 0; /* -c */ -+static int opt_with_workers = 0; /* -w */ -+ - - static char *pidof_root = NULL; - -@@ -69,6 +71,7 @@ static int __attribute__ ((__noreturn__)) usage(int opt) - fputs(_(" -s, --single-shot return one PID only\n"), fp); - fputs(_(" -c, --check-root omit processes with different root\n"), fp); - fputs(_(" -x also find shells running the named scripts\n"), fp); -+ fputs(_(" -w, --with-workers show kernel workers too\n"), fp); - fputs(_(" -o, --omit-pid omit processes with PID\n"), fp); - fputs(_(" -S, --separator SEP use SEP as separator put between PIDs"), fp); - fputs(USAGE_SEPARATOR, fp); -@@ -142,7 +145,6 @@ static void select_procs (void) - static int size = 0; - char *cmd_arg0, *cmd_arg0base; - char *cmd_arg1, *cmd_arg1base; -- char *stat_cmd; - char *program_base; - char *root_link; - char *exe_link; -@@ -168,10 +170,9 @@ static void select_procs (void) - } - } - -- if (!is_omitted(task.XXXID)) { -+ if (!is_omitted(task.XXXID) && ((task.cmdline && *task.cmdline) || opt_with_workers)) { - - cmd_arg0 = (task.cmdline && *task.cmdline) ? *task.cmdline : "\0"; -- stat_cmd = task.cmd ? task.cmd : "\0"; - - /* processes starting with '-' are login shells */ - if (*cmd_arg0 == '-') { -@@ -193,7 +194,7 @@ static void select_procs (void) - !strcmp(program_base, cmd_arg0) || - !strcmp(program, cmd_arg0) || - -- !strcmp(program, stat_cmd) || -+ (opt_with_workers && !strcmp(program, task.cmd)) || - - !strcmp(program, exe_link_base) || - !strcmp(program, exe_link)) -@@ -293,13 +294,14 @@ int main (int argc, char **argv) - int first_pid = 1; - - const char *separator = " "; -- const char *opts = "scdnxmo:S:?Vh"; -+ const char *opts = "scdnxwmo:S:?Vh"; - - static const struct option longopts[] = { - {"check-root", no_argument, NULL, 'c'}, - {"single-shot", no_argument, NULL, 's'}, - {"omit-pid", required_argument, NULL, 'o'}, - {"separator", required_argument, NULL, 'S'}, -+ {"with-workers", no_argument, NULL, 'w'}, - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'V'}, - {NULL, 0, NULL, 0} -@@ -325,6 +327,9 @@ int main (int argc, char **argv) - case 'x': - opt_scripts_too = 1; - break; -+ case 'w': -+ opt_with_workers = 1; -+ break; - case 'c': - if (geteuid() == 0) { - opt_rootdir_check = 1; -@@ -359,6 +364,8 @@ int main (int argc, char **argv) - - program = argv[optind++]; - -+ if (*program == '\0') continue; -+ - select_procs(); /* get the list of matching processes */ - - if (proc_count) { diff --git a/pkill-manpage-e-option.patch b/pkill-manpage-e-option.patch deleted file mode 100644 index 8d306fe..0000000 --- a/pkill-manpage-e-option.patch +++ /dev/null @@ -1,22 +0,0 @@ -commit 584c65ba375a4f7242ddeb74f6006f8f9f5c8d08 -Author: Jan Rybar -Date: Fri Nov 6 14:45:56 2020 +0000 - - pkill manpage to document '-e' option - -diff --git a/pgrep.1 b/pgrep.1 -index 9c29fb9c..a1810f0d 100644 ---- a/pgrep.1 -+++ b/pgrep.1 -@@ -62,6 +62,11 @@ newline). - .RB ( pgrep - only.) - .TP -+\fB\-e\fR, \fB\-\-echo\fR -+Display name and PID of the process being killed. -+.RB ( pkill -+only.) -+.TP - \fB\-f\fR, \fB\-\-full\fR - The - .I pattern diff --git a/procps-ng-3.3.12-ps-luid-format-option.patch b/procps-ng-3.3.12-ps-luid-format-option.patch deleted file mode 100644 index 807db29..0000000 --- a/procps-ng-3.3.12-ps-luid-format-option.patch +++ /dev/null @@ -1,61 +0,0 @@ -diff -up ./ps/output.c.ori ./ps/output.c ---- ./ps/output.c.ori 2016-07-09 23:49:25.825306872 +0200 -+++ ./ps/output.c 2018-02-26 15:09:38.291043349 +0100 -@@ -1201,6 +1201,34 @@ static int pr_sgi_p(char *restrict const - return snprintf(outbuf, COLWID, "*"); - } - -+/* LoginID implementation */ -+static int pr_luid(char *restrict const outbuf, const proc_t *restrict const pp){ -+ char filename[48]; -+ ssize_t num_read; -+ int fd; -+ u_int32_t luid; -+ -+ snprintf(filename, sizeof filename, "/proc/%d/loginuid", pp->tgid); -+ -+ if ((fd = open(filename, O_RDONLY, 0)) != -1) { -+ num_read = read(fd, outbuf, OUTBUF_SIZE - 1); -+ close(fd); -+ if (num_read > 0) { -+ outbuf[num_read] = '\0'; -+ -+ // processes born before audit have no LoginID set -+ luid = (u_int32_t) atoi(outbuf); -+ if (luid != -1) -+ return num_read; -+ } -+ } -+ outbuf[0] = '-'; -+ outbuf[1] = '\0'; -+ num_read = 1; -+ return num_read; -+} -+ -+ - /************************* Systemd stuff ********************************/ - static int pr_sd_unit(char *restrict const outbuf, const proc_t *restrict const pp){ - return snprintf(outbuf, COLWID, "%s", pp->sd_unit); -@@ -1513,7 +1541,7 @@ static const format_struct format_array[ - {"longtname", "TTY", pr_tty8, sr_tty, 8, 0, DEC, PO|LEFT}, - {"lsession", "SESSION", pr_sd_session, sr_nop, 11, SD, LNX, ET|LEFT}, - {"lstart", "STARTED", pr_lstart, sr_nop, 24, 0, XXX, ET|RIGHT}, --{"luid", "LUID", pr_nop, sr_nop, 5, 0, LNX, ET|RIGHT}, /* login ID */ -+{"luid", "LUID", pr_luid, sr_nop, 5, 0, LNX, ET|RIGHT}, /* login ID */ - {"luser", "LUSER", pr_nop, sr_nop, 8, USR, LNX, ET|USER}, /* login USER */ - {"lwp", "LWP", pr_tasks, sr_tasks, 5, 0, SUN, TO|PIDMAX|RIGHT}, - {"lxc", "LXC", pr_lxcname, sr_lxcname, 8, LXC, LNX, ET|LEFT}, -diff -up ./ps/ps.1.ori ./ps/ps.1 ---- ./ps/ps.1.ori 2016-05-07 13:15:32.014390172 +0200 -+++ ./ps/ps.1 2018-02-26 15:09:38.292043345 +0100 -@@ -1322,6 +1322,10 @@ displays the login session identifier of - if systemd support has been included. - T} - -+luid LUID T{ -+displays Login ID associated with a process. -+T} -+ - lwp LWP T{ - light weight process (thread) ID of the dispatchable entity (alias - .BR spid , \ tid ). diff --git a/procps-ng-3.3.13-build-fails-due-libio.patch b/procps-ng-3.3.13-build-fails-due-libio.patch deleted file mode 100644 index f7ec65c..0000000 --- a/procps-ng-3.3.13-build-fails-due-libio.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -up ./procio.c.ori ./procio.c ---- ./procio.c.ori 2018-04-05 13:16:16.926741440 +0200 -+++ ./procio.c 2018-04-05 13:16:31.076685287 +0200 -@@ -24,7 +24,6 @@ - #endif - #include - #include --#include - #include - #include - #include diff --git a/procps-ng-3.3.14-CVE-2018-1124.patch b/procps-ng-3.3.14-CVE-2018-1124.patch deleted file mode 100644 index 1207558..0000000 --- a/procps-ng-3.3.14-CVE-2018-1124.patch +++ /dev/null @@ -1,337 +0,0 @@ -From 9d2ec74b76d220f5343e548fcb7058d723293a22 Mon Sep 17 00:00:00 2001 -From: Qualys Security Advisory -Date: Thu, 1 Jan 1970 00:00:00 +0000 -Subject: [PATCH 1/3] proc/alloc.*: Use size_t, not unsigned int. - -Otherwise this can truncate sizes on 64-bit platforms, and is one of the -reasons the integer overflows in file2strvec() are exploitable at all. -Also: catch potential integer overflow in xstrdup() (should never -happen, but better safe than sorry), and use memcpy() instead of -strcpy() (faster). - -Warnings: - -- in glibc, realloc(ptr, 0) is equivalent to free(ptr), but not here, - because of the ++size; - -- here, xstrdup() can return NULL (if str is NULL), which goes against - the idea of the xalloc wrappers. - -We were tempted to call exit() or xerrx() in those cases, but decided -against it, because it might break things in unexpected places; TODO? ---- - proc/alloc.c | 20 ++++++++++++-------- - proc/alloc.h | 4 ++-- - 2 files changed, 14 insertions(+), 10 deletions(-) - -diff --git a/proc/alloc.c b/proc/alloc.c -index 94af47f..1768d73 100644 ---- a/proc/alloc.c -+++ b/proc/alloc.c -@@ -37,14 +37,14 @@ static void xdefault_error(const char *restrict fmts, ...) { - message_fn xalloc_err_handler = xdefault_error; - - --void *xcalloc(unsigned int size) { -+void *xcalloc(size_t size) { - void * p; - - if (size == 0) - ++size; - p = calloc(1, size); - if (!p) { -- xalloc_err_handler("%s failed to allocate %u bytes of memory", __func__, size); -+ xalloc_err_handler("%s failed to allocate %zu bytes of memory", __func__, size); - exit(EXIT_FAILURE); - } - return p; -@@ -57,20 +57,20 @@ void *xmalloc(size_t size) { - ++size; - p = malloc(size); - if (!p) { -- xalloc_err_handler("%s failed to allocate %zu bytes of memory", __func__, size); -+ xalloc_err_handler("%s failed to allocate %zu bytes of memory", __func__, size); - exit(EXIT_FAILURE); - } - return(p); - } - --void *xrealloc(void *oldp, unsigned int size) { -+void *xrealloc(void *oldp, size_t size) { - void *p; - - if (size == 0) - ++size; - p = realloc(oldp, size); - if (!p) { -- xalloc_err_handler("%s failed to allocate %u bytes of memory", __func__, size); -+ xalloc_err_handler("%s failed to allocate %zu bytes of memory", __func__, size); - exit(EXIT_FAILURE); - } - return(p); -@@ -80,13 +80,17 @@ char *xstrdup(const char *str) { - char *p = NULL; - - if (str) { -- unsigned int size = strlen(str) + 1; -+ size_t size = strlen(str) + 1; -+ if (size < 1) { -+ xalloc_err_handler("%s refused to allocate %zu bytes of memory", __func__, size); -+ exit(EXIT_FAILURE); -+ } - p = malloc(size); - if (!p) { -- xalloc_err_handler("%s failed to allocate %u bytes of memory", __func__, size); -+ xalloc_err_handler("%s failed to allocate %zu bytes of memory", __func__, size); - exit(EXIT_FAILURE); - } -- strcpy(p, str); -+ memcpy(p, str, size); - } - return(p); - } -diff --git a/proc/alloc.h b/proc/alloc.h -index 19c91d7..6787a72 100644 ---- a/proc/alloc.h -+++ b/proc/alloc.h -@@ -10,9 +10,9 @@ typedef void (*message_fn)(const char *__restrict, ...) __attribute__((format(pr - /* change xalloc_err_handler to override the default fprintf(stderr... */ - extern message_fn xalloc_err_handler; - --extern void *xcalloc(unsigned int size) MALLOC; -+extern void *xcalloc(size_t size) MALLOC; - extern void *xmalloc(size_t size) MALLOC; --extern void *xrealloc(void *oldp, unsigned int size) MALLOC; -+extern void *xrealloc(void *oldp, size_t size) MALLOC; - extern char *xstrdup(const char *str) MALLOC; - - EXTERN_C_END --- -2.14.3 - - -From de660b14b80188d9b323c4999d1b91a9456ed687 Mon Sep 17 00:00:00 2001 -From: Qualys Security Advisory -Date: Thu, 1 Jan 1970 00:00:00 +0000 -Subject: [PATCH 2/3] proc/readproc.c: Harden file2str(). - -1/ Replace sprintf() with snprintf() (and check for truncation). - -2/ Prevent an integer overflow of ub->siz. The "tot_read--" is needed to -avoid an off-by-one overflow in "ub->buf[tot_read] = '\0'". It is safe -to decrement tot_read here, because we know that tot_read is equal to -ub->siz (and ub->siz is very large). - -We believe that truncation is a better option than failure (implementing -failure instead should be as easy as replacing the "tot_read--" with -"tot_read = 0"). ---- - proc/readproc.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/proc/readproc.c b/proc/readproc.c -index 9e3afc9..39235c7 100644 ---- a/proc/readproc.c -+++ b/proc/readproc.c -@@ -35,6 +35,7 @@ - #include - #include - #include -+#include - #include - #include - #ifdef WITH_SYSTEMD -@@ -635,7 +636,7 @@ static void statm2proc(const char* s, proc_t *restrict P) { - static int file2str(const char *directory, const char *what, struct utlbuf_s *ub) { - #define buffGRW 1024 - char path[PROCPATHLEN]; -- int fd, num, tot_read = 0; -+ int fd, num, tot_read = 0, len; - - /* on first use we preallocate a buffer of minimum size to emulate - former 'local static' behavior -- even if this read fails, that -@@ -643,11 +644,16 @@ static int file2str(const char *directory, const char *what, struct utlbuf_s *ub - ( besides, with this xcalloc we will never need to use memcpy ) */ - if (ub->buf) ub->buf[0] = '\0'; - else ub->buf = xcalloc((ub->siz = buffGRW)); -- sprintf(path, "%s/%s", directory, what); -+ len = snprintf(path, sizeof path, "%s/%s", directory, what); -+ if (len <= 0 || (size_t)len >= sizeof path) return -1; - if (-1 == (fd = open(path, O_RDONLY, 0))) return -1; - while (0 < (num = read(fd, ub->buf + tot_read, ub->siz - tot_read))) { - tot_read += num; - if (tot_read < ub->siz) break; -+ if (ub->siz >= INT_MAX - buffGRW) { -+ tot_read--; -+ break; -+ } - ub->buf = xrealloc(ub->buf, (ub->siz += buffGRW)); - }; - ub->buf[tot_read] = '\0'; --- -2.14.3 - - -From 44a4b658f45bc3fbd7170662a52038a7b35c83de Mon Sep 17 00:00:00 2001 -From: Qualys Security Advisory -Date: Thu, 1 Jan 1970 00:00:00 +0000 -Subject: [PATCH 3/3] proc/readproc.c: Fix bugs and overflows in file2strvec(). - -Note: this is by far the most important and complex patch of the whole -series, please review it carefully; thank you very much! - -For this patch, we decided to keep the original function's design and -skeleton, to avoid regressions and behavior changes, while fixing the -various bugs and overflows. And like the "Harden file2str()" patch, this -patch does not fail when about to overflow, but truncates instead: there -is information available about this process, so return it to the caller; -also, we used INT_MAX as a limit, but a lower limit could be used. - -The easy changes: - -- Replace sprintf() with snprintf() (and check for truncation). - -- Replace "if (n == 0 && rbuf == 0)" with "if (n <= 0 && tot <= 0)" and - do break instead of return: it simplifies the code (only one place to - handle errors), and also guarantees that in the while loop either n or - tot is > 0 (or both), even if n is reset to 0 when about to overflow. - -- Remove the "if (n < 0)" block in the while loop: it is (and was) dead - code, since we enter the while loop only if n >= 0. - -- Rewrite the missing-null-terminator detection: in the original - function, if the size of the file is a multiple of 2047, a null- - terminator is appended even if the file is already null-terminated. - -- Replace "if (n <= 0 && !end_of_file)" with "if (n < 0 || tot <= 0)": - originally, it was equivalent to "if (n < 0)", but we added "tot <= 0" - to handle the first break of the while loop, and to guarantee that in - the rest of the function tot is > 0. - -- Double-force ("belt and suspenders") the null-termination of rbuf: - this is (and was) essential to the correctness of the function. - -- Replace the final "while" loop with a "for" loop that behaves just - like the preceding "for" loop: in the original function, this would - lead to unexpected results (for example, if rbuf is |\0|A|\0|, this - would return the array {"",NULL} but should return {"","A",NULL}; and - if rbuf is |A|\0|B| (should never happen because rbuf should be null- - terminated), this would make room for two pointers in ret, but would - write three pointers to ret). - -The hard changes: - -- Prevent the integer overflow of tot in the while loop, but unlike - file2str(), file2strvec() cannot let tot grow until it almost reaches - INT_MAX, because it needs more space for the pointers: this is why we - introduced ARG_LEN, which also guarantees that we can add "align" and - a few sizeof(char*)s to tot without overflowing. - -- Prevent the integer overflow of "tot + c + align": when INT_MAX is - (almost) reached, we write the maximal safe amount of pointers to ret - (ARG_LEN guarantees that there is always space for *ret = rbuf and the - NULL terminator). ---- - proc/readproc.c | 53 ++++++++++++++++++++++++++++++++--------------------- - 1 file changed, 32 insertions(+), 21 deletions(-) - -diff --git a/proc/readproc.c b/proc/readproc.c -index 39235c7..94ca4e9 100644 ---- a/proc/readproc.c -+++ b/proc/readproc.c -@@ -665,11 +665,12 @@ static int file2str(const char *directory, const char *what, struct utlbuf_s *ub - - static char** file2strvec(const char* directory, const char* what) { - char buf[2048]; /* read buf bytes at a time */ -- char *p, *rbuf = 0, *endbuf, **q, **ret; -+ char *p, *rbuf = 0, *endbuf, **q, **ret, *strp; - int fd, tot = 0, n, c, end_of_file = 0; - int align; - -- sprintf(buf, "%s/%s", directory, what); -+ const int len = snprintf(buf, sizeof buf, "%s/%s", directory, what); -+ if(len <= 0 || (size_t)len >= sizeof buf) return NULL; - fd = open(buf, O_RDONLY, 0); - if(fd==-1) return NULL; - -@@ -677,18 +678,23 @@ static char** file2strvec(const char* directory, const char* what) { - while ((n = read(fd, buf, sizeof buf - 1)) >= 0) { - if (n < (int)(sizeof buf - 1)) - end_of_file = 1; -- if (n == 0 && rbuf == 0) { -- close(fd); -- return NULL; /* process died between our open and read */ -+ if (n <= 0 && tot <= 0) { /* nothing read now, nothing read before */ -+ break; /* process died between our open and read */ - } -- if (n < 0) { -- if (rbuf) -- free(rbuf); -- close(fd); -- return NULL; /* read error */ -+ /* ARG_LEN is our guesstimated median length of a command-line argument -+ or environment variable (the minimum is 1, the maximum is 131072) */ -+ #define ARG_LEN 64 -+ if (tot >= INT_MAX / (ARG_LEN + (int)sizeof(char*)) * ARG_LEN - n) { -+ end_of_file = 1; /* integer overflow: null-terminate and break */ -+ n = 0; /* but tot > 0 */ - } -- if (end_of_file && (n == 0 || buf[n-1]))/* last read char not null */ -+ #undef ARG_LEN -+ if (end_of_file && -+ ((n > 0 && buf[n-1] != '\0') || /* last read char not null */ -+ (n <= 0 && rbuf[tot-1] != '\0'))) /* last read char not null */ - buf[n++] = '\0'; /* so append null-terminator */ -+ -+ if (n <= 0) break; /* unneeded (end_of_file = 1) but avoid realloc */ - rbuf = xrealloc(rbuf, tot + n); /* allocate more memory */ - memcpy(rbuf + tot, buf, n); /* copy buffer into it */ - tot += n; /* increment total byte ctr */ -@@ -696,29 +702,34 @@ static char** file2strvec(const char* directory, const char* what) { - break; - } - close(fd); -- if (n <= 0 && !end_of_file) { -+ if (n < 0 || tot <= 0) { /* error, or nothing read */ - if (rbuf) free(rbuf); - return NULL; /* read error */ - } -+ rbuf[tot-1] = '\0'; /* belt and suspenders (the while loop did it, too) */ - endbuf = rbuf + tot; /* count space for pointers */ - align = (sizeof(char*)-1) - ((tot + sizeof(char*)-1) & (sizeof(char*)-1)); -- for (c = 0, p = rbuf; p < endbuf; p++) { -- if (!*p || *p == '\n') -+ c = sizeof(char*); /* one extra for NULL term */ -+ for (p = rbuf; p < endbuf; p++) { -+ if (!*p || *p == '\n') { -+ if (c >= INT_MAX - (tot + (int)sizeof(char*) + align)) break; - c += sizeof(char*); -+ } - if (*p == '\n') - *p = 0; - } -- c += sizeof(char*); /* one extra for NULL term */ - - rbuf = xrealloc(rbuf, tot + c + align); /* make room for ptrs AT END */ - endbuf = rbuf + tot; /* addr just past data buf */ - q = ret = (char**) (endbuf+align); /* ==> free(*ret) to dealloc */ -- *q++ = p = rbuf; /* point ptrs to the strings */ -- endbuf--; /* do not traverse final NUL */ -- while (++p < endbuf) -- if (!*p) /* NUL char implies that */ -- *q++ = p+1; /* next string -> next char */ -- -+ for (strp = p = rbuf; p < endbuf; p++) { -+ if (!*p) { /* NUL char implies that */ -+ if (c < 2 * (int)sizeof(char*)) break; -+ c -= sizeof(char*); -+ *q++ = strp; /* point ptrs to the strings */ -+ strp = p+1; /* next string -> next char */ -+ } -+ } - *q = 0; /* null ptr list terminator */ - return ret; - } --- -2.14.3 - diff --git a/procps-ng.spec b/procps-ng.spec index 2a6fe2d..88a521a 100644 --- a/procps-ng.spec +++ b/procps-ng.spec @@ -3,23 +3,12 @@ Summary: System and process monitoring utilities Name: procps-ng -Version: 3.3.17 -Release: 9%{?dist} +Version: 4.0.2 +Release: 1%{?dist} License: GPL+ and GPLv2 and GPLv2+ and GPLv3+ and LGPLv2+ URL: https://sourceforge.net/projects/procps-ng/ Source0: https://downloads.sourceforge.net/%{name}/%{name}-%{version}.tar.xz -# README files are missing in latest tarball -# wget https://gitlab.com/procps-ng/procps/raw/e0784ddaed30d095bb1d9a8ad6b5a23d10a212c4/README.md -Source1: README.md -# wget https://gitlab.com/procps-ng/procps/raw/e0784ddaed30d095bb1d9a8ad6b5a23d10a212c4/top/README.top -Source2: README.top - -Patch1: pwait-to-pidwait.patch -Patch2: covscan-findings.patch -Patch3: sysctl-hyphen-param.patch -Patch4: free-si-fix.patch -Patch5: sysctl-print-dotted-keys-again.patch BuildRequires: make @@ -38,7 +27,7 @@ BuildRequires: dejagnu %endif Provides: procps = %{version}-%{release} -Obsoletes: procps < 3.2.9-1 +Obsoletes: procps < 4.0.1-1 # usrmove hack - will be removed once initscripts are fixed Provides: /sbin/sysctl @@ -72,7 +61,7 @@ waits for processes of specified names. Summary: System and process monitoring utilities Requires: %{name}%{?_isa} = %{version}-%{release} Provides: procps-devel = %{version}-%{release} -Obsoletes: procps-devel < 3.2.9-1 +Obsoletes: procps-devel < 3.3.17-8 %description devel System and process monitoring utilities development headers @@ -91,11 +80,7 @@ Conflicts: man-pages-pl < 0.7-5 Internationalization pack for procps-ng %prep -%setup -q -n procps-%{version} -%autopatch -p1 - -cp -p %{SOURCE1} . -cp -p %{SOURCE2} top/ +%autosetup -S git %build # The following stuff is needed for git archives only @@ -106,7 +91,6 @@ autoreconf --verbose --force --install %configure \ --exec-prefix=/ \ - --docdir=/unwanted \ --disable-static \ --disable-w-from \ --disable-kill \ @@ -140,29 +124,30 @@ ln -s %{_bindir}/pidof %{buildroot}%{_sbindir}/pidof %ldconfig_scriptlets %files -%doc AUTHORS Documentation/bugs.md Documentation/FAQ NEWS README.md top/README.top Documentation/TODO +%doc AUTHORS bugs.md FAQ NEWS README.md %license COPYING COPYING.LIB -%{_libdir}/libprocps.so.* +%{_libdir}/libproc2.so.* %{_bindir}/* %{_sbindir}/* %{_mandir}/man1/* %{_mandir}/man8/* %{_mandir}/man5/* - -%exclude %{_libdir}/libprocps.la -%exclude /unwanted/* +%exclude %{_pkgdocdir}/libproc.supp %files devel %license COPYING COPYING.LIB -%{_libdir}/libprocps.so -%{_libdir}/pkgconfig/libprocps.pc -%{_includedir}/proc +%{_libdir}/libproc2.so +%{_libdir}/pkgconfig/libproc2.pc +%{_includedir}/libproc2 %{_mandir}/man3/* %files i18n -f %{name}.lang %changelog +* Mon Feb 13 2023 Jan Rybar - 4.0.2-1 +- rebase to 4.0.2 + * Fri Jan 20 2023 Fedora Release Engineering - 3.3.17-9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild diff --git a/ps-exe-format-option.patch b/ps-exe-format-option.patch deleted file mode 100644 index 3d6dfa2..0000000 --- a/ps-exe-format-option.patch +++ /dev/null @@ -1,58 +0,0 @@ -diff --git a/ps/output.c b/ps/output.c -index e718f19..b66d543 100644 ---- a/ps/output.c -+++ b/ps/output.c -@@ -1250,6 +1250,26 @@ static int pr_luid(char *restrict const outbuf, const proc_t *restrict const pp) - } - - -+/* full path to executable */ -+static int pr_exe(char *restrict const outbuf, const proc_t *restrict const pp){ -+ char filename[48]; -+ ssize_t num_read = 0; -+ -+ snprintf(filename, sizeof filename, "/proc/%d/exe", pp->tgid); -+ -+ num_read = readlink(filename, outbuf, OUTBUF_SIZE-1); -+ if (num_read > 0) { -+ outbuf[num_read] = '\0'; -+ } -+ else { -+ outbuf[0] = '-'; -+ outbuf[1] = '\0'; -+ num_read = 1; -+ } -+ -+ return num_read; -+} -+ - /************************* Systemd stuff ********************************/ - static int pr_sd_unit(char *restrict const outbuf, const proc_t *restrict const pp){ - return snprintf(outbuf, COLWID, "%s", pp->sd_unit); -@@ -1533,6 +1553,7 @@ static const format_struct format_array[] = { - {"etimes", "ELAPSED", pr_etimes, sr_etime, 7, 0, BSD, ET|RIGHT}, /* FreeBSD */ - {"euid", "EUID", pr_euid, sr_euid, 5, 0, LNX, ET|RIGHT}, - {"euser", "EUSER", pr_euser, sr_euser, 8, USR, LNX, ET|USER}, -+{"exe", "EXE", pr_exe, sr_nop, 27, 0, LNX, PO|UNLIMITED}, - {"f", "F", pr_flag, sr_flags, 1, 0, XXX, ET|RIGHT}, /*flags*/ - {"fgid", "FGID", pr_fgid, sr_fgid, 5, 0, LNX, ET|RIGHT}, - {"fgroup", "FGROUP", pr_fgroup, sr_fgroup, 8, GRP, LNX, ET|USER}, -diff --git a/ps/ps.1 b/ps/ps.1 -index 844341c..6818667 100644 ---- a/ps/ps.1 -+++ b/ps/ps.1 -@@ -1253,6 +1253,14 @@ option can be used to force the decimal representation. (alias - .BR uname ", " user ). - T} - -+exe EXE T{ -+path to the executable. Useful if path cannot be printed via -+.BR cmd ", " comm -+or -+.BR args -+format options. -+T} -+ - f F T{ - flags associated with the process, see the - .B PROCESS FLAGS diff --git a/pwait-to-pidwait.patch b/pwait-to-pidwait.patch deleted file mode 100644 index b599709..0000000 --- a/pwait-to-pidwait.patch +++ /dev/null @@ -1,286 +0,0 @@ -From 52afb3a8d31871d28b1c39573a7ed5196c2d5023 Mon Sep 17 00:00:00 2001 -From: Craig Small -Date: Mon, 15 Feb 2021 21:10:06 +1100 -Subject: [PATCH] pidwait: Rename from pwait - -pwait is already in at least Debian in a different package - -References: - https://bugs.debian.org/982391 ---- -diff --git a/Makefile.am b/Makefile.am -index e037e4c..de15e13 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -49,8 +49,8 @@ bin_PROGRAMS = \ - uptime \ - vmstat \ - w --if BUILD_PWAIT --bin_PROGRAMS += pwait -+if BUILD_PIDWAIT -+bin_PROGRAMS += pidwait - endif - else - usrbin_exec_PROGRAMS += \ -@@ -85,8 +85,8 @@ dist_man_MANS += \ - sysctl.conf.5 \ - ps/ps.1 - --if BUILD_PWAIT --dist_man_MANS += pwait.1 -+if BUILD_PIDWAIT -+dist_man_MANS += pidwait.1 - endif - endif - -@@ -199,8 +199,8 @@ free_SOURCES = free.c lib/strutils.c lib/fileutils.c - pgrep_SOURCES = pgrep.c lib/fileutils.c lib/nsutils.c - pkill_SOURCES = pgrep.c lib/fileutils.c lib/nsutils.c - pmap_SOURCES = pmap.c lib/fileutils.c --if BUILD_PWAIT --pwait_SOURCES = pgrep.c lib/fileutils.c lib/nsutils.c -+if BUILD_PIDWAIT -+pidwait_SOURCES = pgrep.c lib/fileutils.c lib/nsutils.c - endif - if !CYGWIN - pwdx_SOURCES = pwdx.c lib/fileutils.c -diff --git a/NEWS b/NEWS -index da63c9c..5fe6761 100644 ---- a/NEWS -+++ b/NEWS -@@ -1,3 +1,7 @@ -+procps-ng-NEXT -+--------------- -+ * Rename pwait to pidwait -+ - procps-ng-3.3.17 - --------------- - * library: Incremented to 8:3:0 -diff --git a/configure.ac b/configure.ac -index 56a8669..750c0fb 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -132,20 +132,20 @@ AC_TRY_COMPILE([#include ], - AC_MSG_RESULT(yes), - AC_MSG_RESULT(no)) - --AC_CHECK_FUNC([pidfd_open], [enable_pwait=yes], [ -+AC_CHECK_FUNC([pidfd_open], [enable_pidwait=yes], [ - AC_MSG_CHECKING([for __NR_pidfd_open]) - AC_COMPILE_IFELSE([AC_LANG_SOURCE([ - #include - #ifndef __NR_pidfd_open - #error __NR_pidfd_open not defined - #endif -- ])], [enable_pwait=yes], [enable_pwait=no]) -- AC_MSG_RESULT([$enable_pwait]) -+ ])], [enable_pidwait=yes], [enable_pidwait=no]) -+ AC_MSG_RESULT([$enable_pidwait]) - ]) --if test "$enable_pwait" = yes; then -- AC_DEFINE([ENABLE_PWAIT], [1], [Enable pwait]) -+if test "$enable_pidwait" = yes; then -+ AC_DEFINE([ENABLE_PIDWAIT], [1], [Enable pidwait]) - fi --AM_CONDITIONAL([BUILD_PWAIT], [test x$enable_pwait = xyes]) -+AM_CONDITIONAL([BUILD_PIDWAIT], [test x$enable_pidwait = xyes]) - - dnl watch8bit must be before the AC_ARG_WITH set as it sets up ncurses - AC_SUBST([WITH_WATCH8BIT]) -diff --git a/pgrep.1 b/pgrep.1 -index 4f8907b..af6dcd5 100644 ---- a/pgrep.1 -+++ b/pgrep.1 -@@ -9,7 +9,7 @@ - .\" - .TH PGREP "1" "2020-06-04" "procps-ng" "User Commands" - .SH NAME --pgrep, pkill, pwait \- look up, signal, or wait for processes based on name and other attributes -+pgrep, pkill, pidwait \- look up, signal, or wait for processes based on name and other attributes - .SH SYNOPSIS - .B pgrep - [options] pattern -@@ -17,7 +17,7 @@ pgrep, pkill, pwait \- look up, signal, or wait for processes based on name and - .B pkill - [options] pattern - .br --.B pwait -+.B pidwait - [options] pattern - .SH DESCRIPTION - .B pgrep -@@ -45,7 +45,7 @@ will send the specified signal (by default - .BR SIGTERM ) - to each process instead of listing them on stdout. - .PP --.B pwait -+.B pidwait - will wait for each process instead of listing them on stdout. - .SH OPTIONS - .TP -@@ -60,7 +60,7 @@ only.) - \fB\-c\fR, \fB\-\-count\fR - Suppress normal output; instead print a count of matching processes. When - count does not match anything, e.g. returns zero, the command will return --non-zero value. Note that for pkill and pwait, the count is the number of -+non-zero value. Note that for pkill and pidwait, the count is the number of - matching processes, not the processes that were successfully signaled or waited - for. - .TP -@@ -88,7 +88,7 @@ translated into - .BR pgrep 's, - .BR pkill 's, - or --.BR pwait 's -+.BR pidwait 's - own process group. - .TP - \fB\-G\fR, \fB\-\-group\fR \fIgid\fP,... -@@ -126,7 +126,7 @@ is translated into - .BR pgrep 's, - .BR pkill 's, - or --.BR pwait 's -+.BR pidwait 's - own session ID. - .TP - \fB\-t\fR, \fB\-\-terminal\fR \fIterm\fP,... -@@ -145,7 +145,7 @@ symbolical value may be used. - Negates the matching. This option is usually used in - .BR pgrep 's - or --.BR pwait 's -+.BR pidwait 's - context. In - .BR pkill 's - context the short option is disabled to avoid accidental usage of the option. -@@ -154,7 +154,7 @@ context the short option is disabled to avoid accidental usage of the option. - Shows all thread ids instead of pids in - .BR pgrep 's - or --.BR pwait 's -+.BR pidwait 's - context. In - .BR pkill 's - context this option is disabled. -@@ -167,7 +167,7 @@ match the - .TP - \fB\-F\fR, \fB\-\-pidfile\fR \fIfile\fR - Read \fIPID\fRs from \fIfile\fR. This option is more useful for --.BR pkill or pwait -+.BR pkill or pidwait - than - .BR pgrep . - .TP -@@ -237,7 +237,7 @@ $ renice +4 $(pgrep chrome) - .PD 0 - .TP - 0 --One or more processes matched the criteria. For pkill and pwait, one or more -+One or more processes matched the criteria. For pkill and pidwait, one or more - processes must also have been successfully signalled or waited for. - .TP - 1 -@@ -258,7 +258,7 @@ The running - .BR pgrep , - .BR pkill , - or --.B pwait -+.B pidwait - process will never report itself as a - match. - .SH BUGS -diff --git a/pgrep.c b/pgrep.c -index 4fe5e8a..1905cd1 100644 ---- a/pgrep.c -+++ b/pgrep.c -@@ -38,7 +38,7 @@ - #include - #include - --#if defined(ENABLE_PWAIT) && !defined(HAVE_PIDFD_OPEN) -+#if defined(ENABLE_PIDWAIT) && !defined(HAVE_PIDFD_OPEN) - #include - #include - #endif -@@ -68,8 +68,8 @@ - static enum { - PGREP = 0, - PKILL, --#ifdef ENABLE_PWAIT -- PWAIT, -+#ifdef ENABLE_PIDWAIT -+ PIDWAIT, - #endif - } prog_mode; - -@@ -136,8 +136,8 @@ static int __attribute__ ((__noreturn__)) usage(int opt) - fputs(_(" -q, --queue integer value to be sent with the signal\n"), fp); - fputs(_(" -e, --echo display what is killed\n"), fp); - break; --#ifdef ENABLE_PWAIT -- case PWAIT: -+#ifdef ENABLE_PIDWAIT -+ case PIDWAIT: - fputs(_(" -e, --echo display PIDs before waiting\n"), fp); - break; - #endif -@@ -687,7 +687,7 @@ static struct el * select_procs (int *num) - xerrx(EXIT_FAILURE, _("internal error")); - } - -- // pkill and pwait don't support -w, but this is checked in getopt -+ // pkill and pidwait don't support -w, but this is checked in getopt - if (opt_threads) { - while (readtask(ptp, &task, &subtask)){ - // don't add redundant tasks -@@ -742,7 +742,7 @@ static int signal_option(int *argc, char **argv) - return -1; - } - --#if defined(ENABLE_PWAIT) && !defined(HAVE_PIDFD_OPEN) -+#if defined(ENABLE_PIDWAIT) && !defined(HAVE_PIDFD_OPEN) - static int pidfd_open (pid_t pid, unsigned int flags) - { - return syscall(__NR_pidfd_open, pid, flags); -@@ -793,9 +793,9 @@ static void parse_opts (int argc, char **argv) - {NULL, 0, NULL, 0} - }; - --#ifdef ENABLE_PWAIT -- if (strcmp (program_invocation_short_name, "pwait") == 0) { -- prog_mode = PWAIT; -+#ifdef ENABLE_PIDWAIT -+ if (strcmp (program_invocation_short_name, "pidwait") == 0) { -+ prog_mode = PIDWAIT; - strcat (opts, "e"); - } else - #endif -@@ -1008,7 +1008,7 @@ int main (int argc, char **argv) - int num; - int i; - int kill_count = 0; --#ifdef ENABLE_PWAIT -+#ifdef ENABLE_PIDWAIT - int poll_count = 0; - int wait_count = 0; - int epollfd = epoll_create(1); -@@ -1055,8 +1055,8 @@ int main (int argc, char **argv) - fprintf(stdout, "%d\n", num); - return !kill_count; - --#ifdef ENABLE_PWAIT -- case PWAIT: -+#ifdef ENABLE_PIDWAIT -+ case PIDWAIT: - if (opt_count) - fprintf(stdout, "%d\n", num); - -diff --git a/pwait.1 b/pidwait.1 -similarity index 100% -rename from pwait.1 -rename to pidwait.1 --- -GitLab - diff --git a/sources b/sources index 1aac52a..da369e6 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (procps-ng-3.3.17.tar.xz) = 59e9a5013430fd9da508c4655d58375dc32e025bb502bb28fb9a92a48e4f2838b3355e92b4648f7384b2050064d17079bf4595d889822ebb5030006bc154a1a7 +SHA512 (procps-ng-4.0.2.tar.xz) = 5327e62084bf801786785aad98cc2f0463f48336864d1dd92d138097ffaac7ffbc8d5127b325a0e9d06b29d101f19bbfaecf612f659035b00e6627cb5e267544 diff --git a/sysctl-hyphen-param.patch b/sysctl-hyphen-param.patch deleted file mode 100644 index 5b4a145..0000000 --- a/sysctl-hyphen-param.patch +++ /dev/null @@ -1,833 +0,0 @@ -diff -up ./NEWS.ori ./NEWS -diff -up ./sysctl.c.ori ./sysctl.c ---- ./sysctl.c.ori 2021-02-09 11:11:25.000000000 +0100 -+++ ./sysctl.c 2022-03-31 18:27:36.536486629 +0200 -@@ -17,6 +17,7 @@ - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * -+ * Part of this code comes from systemd, especially sysctl.c - * Changelog: - * v1.01: - * - added -p to preload values from a file -@@ -40,6 +41,7 @@ - #include - #include - #include -+#include - - #include "c.h" - #include "fileutils.h" -@@ -66,12 +68,34 @@ static bool PrintName; - static bool PrintNewline; - static bool IgnoreError; - static bool Quiet; -+static bool DryRun; - static char *pattern; - - #define LINELEN 4096 - static char *iobuf; - static size_t iolen = LINELEN; - -+typedef struct SysctlSetting { -+ char *key; -+ char *path; -+ char *value; -+ bool ignore_failure; -+ bool glob_exclude; -+ struct SysctlSetting *next; -+} SysctlSetting; -+ -+typedef struct SettingList { -+ struct SysctlSetting *head; -+ struct SysctlSetting *tail; -+} SettingList; -+ -+#define GLOB_CHARS "*?[" -+static inline bool string_is_glob(const char *p) -+{ -+ return !!strpbrk(p, GLOB_CHARS); -+} -+ -+ - /* Function prototypes. */ - static int pattern_match(const char *string, const char *pat); - static int DisplayAll(const char *restrict const path); -@@ -100,6 +124,81 @@ static void slashdot(char *restrict p, c - } - } - -+static void setting_free(SysctlSetting *s) { -+ if (!s) -+ return; -+ -+ free(s->key); -+ free(s->path); -+ free(s->value); -+ free(s); -+} -+ -+static SysctlSetting *setting_new( -+ const char *key, -+ const char *value, -+ bool ignore_failure, -+ bool glob_exclude) { -+ -+ SysctlSetting *s = NULL; -+ char *path = NULL; -+ int proc_len; -+ -+ proc_len = strlen(PROC_PATH); -+ /* used to open the file */ -+ path = xmalloc(strlen(key) + proc_len + 2); -+ strcpy(path, PROC_PATH); -+ if (key[0] == '-') -+ strcat(path + proc_len, key+1); -+ else -+ strcat(path + proc_len, key); -+ /* change . to / */ -+ slashdot(path + proc_len, '.', '/'); -+ -+ s = xmalloc(sizeof(SysctlSetting)); -+ -+ *s = (SysctlSetting) { -+ .key = strdup(key), -+ .path = path, -+ .value = value? strdup(value): NULL, -+ .ignore_failure = ignore_failure, -+ .glob_exclude = glob_exclude, -+ .next = NULL, -+ }; -+ -+ return s; -+} -+ -+static void settinglist_add(SettingList *l, SysctlSetting *s) { -+ SysctlSetting *old_tail; -+ -+ if (!l) -+ return; -+ -+ if (l->head == NULL) -+ l->head = s; -+ -+ if (l->tail != NULL) { -+ old_tail = l->tail; -+ old_tail->next = s; -+ } -+ l->tail = s; -+} -+ -+static SysctlSetting *settinglist_findpath(const SettingList *l, const char *path) { -+ SysctlSetting *node; -+ -+ for (node=l->head; node != NULL; node = node->next) { -+ if (strcmp(node->path, path) == 0) -+ return node; -+ } -+ return NULL; -+} -+ -+/* Function prototypes. */ -+static int pattern_match(const char *string, const char *pat); -+static int DisplayAll(const char *restrict const path); -+ - /* - * Display the usage format - */ -@@ -115,6 +214,7 @@ static void __attribute__ ((__noreturn__ - fputs(_(" -A alias of -a\n"), out); - fputs(_(" -X alias of -a\n"), out); - fputs(_(" --deprecated include deprecated parameters to listing\n"), out); -+ fputs(_(" --dry-run Print the key and values but do not write\n"), out); - fputs(_(" -b, --binary print value without new line\n"), out); - fputs(_(" -e, --ignore ignore unknown variables errors\n"), out); - fputs(_(" -N, --names print variable names without values\n"), out); -@@ -138,6 +238,39 @@ static void __attribute__ ((__noreturn__ - } - - /* -+ * Strip left/leading side of a string -+ */ -+static char *lstrip(char *line) -+{ -+ char *start; -+ -+ if (!line || !*line) -+ return line; -+ -+ start = line; -+ while(isspace(*start)) start++; -+ -+ return start; -+} -+ -+/* -+ * Strip right/trailing side of a string -+ * by placing a \0 -+ */ -+static void rstrip(char *line) -+{ -+ char *end; -+ -+ if (!line || !*line) -+ return; -+ -+ end = line + strlen(line) - 1; -+ while(end > line && isspace(*end)) end--; -+ -+ end[1] = '\0'; -+} -+ -+/* - * Strip the leading and trailing spaces from a string - */ - static char *StripLeadingAndTrailingSpaces(char *oneline) -@@ -166,7 +299,7 @@ static char *StripLeadingAndTrailingSpac - */ - static int ReadSetting(const char *restrict const name) - { -- int rc = 0; -+ int rc = EXIT_SUCCESS; - char *restrict tmpname; - char *restrict outname; - ssize_t rlen; -@@ -198,7 +331,7 @@ static int ReadSetting(const char *restr - if (stat(tmpname, &ts) < 0) { - if (!IgnoreError) { - xwarn(_("cannot stat %s"), tmpname); -- rc = -1; -+ rc = EXIT_FAILURE; - } - goto out; - } -@@ -215,7 +348,7 @@ static int ReadSetting(const char *restr - } - - if (pattern && !pattern_match(outname, pattern)) { -- rc = 0; -+ rc = EXIT_SUCCESS; - goto out; - } - -@@ -231,19 +364,19 @@ static int ReadSetting(const char *restr - case ENOENT: - if (!IgnoreError) { - xwarnx(_("\"%s\" is an unknown key"), outname); -- rc = -1; -+ rc = EXIT_FAILURE; - } - break; - case EACCES: - xwarnx(_("permission denied on key '%s'"), outname); -- rc = -1; -+ rc = EXIT_FAILURE; - break; - case EIO: /* Ignore stable_secret below /proc/sys/net/ipv6/conf */ -- rc = -1; -+ rc = EXIT_FAILURE; - break; - default: - xwarn(_("reading key \"%s\""), outname); -- rc = -1; -+ rc = EXIT_FAILURE; - break; - } - } else { -@@ -279,7 +412,7 @@ static int ReadSetting(const char *restr - case EACCES: - xwarnx(_("permission denied on key '%s'"), - outname); -- rc = -1; -+ rc = EXIT_FAILURE; - break; - case EISDIR: { - size_t len; -@@ -291,11 +424,11 @@ static int ReadSetting(const char *restr - goto out; - } - case EIO: /* Ignore stable_secret below /proc/sys/net/ipv6/conf */ -- rc = -1; -+ rc = EXIT_FAILURE; - break; - default: - xwarnx(_("reading key \"%s\""), outname); -- rc = -1; -+ rc = EXIT_FAILURE; - case 0: - break; - } -@@ -323,7 +456,7 @@ static int is_deprecated(char *filename) - */ - static int DisplayAll(const char *restrict const path) - { -- int rc = 0; -+ int rc = EXIT_SUCCESS; - int rc2; - DIR *restrict dp; - struct dirent *restrict de; -@@ -333,7 +466,7 @@ static int DisplayAll(const char *restri - - if (!dp) { - xwarnx(_("unable to open directory \"%s\""), path); -- rc = -1; -+ rc = EXIT_FAILURE; - } else { - readdir(dp); /* skip . */ - readdir(dp); /* skip .. */ -@@ -369,130 +502,183 @@ static int DisplayAll(const char *restri - /* - * Write a sysctl setting - */ --static int WriteSetting(const char *setting) --{ -- int rc = 0; -- const char *name = setting; -- const char *value; -- const char *equals; -- char *tmpname; -- char *outname; -- char *last_dot; -- bool ignore_failure; -+static int WriteSetting( -+ const char *key, -+ const char *path, -+ const char *value, -+ const bool ignore_failure) { - -- FILE *fp; -+ int rc = EXIT_SUCCESS; -+ FILE *fp; - struct stat ts; - -- if (!name) -- /* probably don't want to display this err */ -- return 0; -- -- equals = strchr(setting, '='); -- -- if (!equals) { -- xwarnx(_("\"%s\" must be of the form name=value"), -- setting); -- return -1; -- } -- -- /* point to the value in name=value */ -- value = equals + 1; -- -- if (!*name || name == equals) { -- xwarnx(_("malformed setting \"%s\""), setting); -- return -2; -- } -- -- ignore_failure = name[0] == '-'; -- if (ignore_failure) -- name++; -+ if (!key || !path) -+ return rc; - -- /* used to open the file */ -- tmpname = xmalloc(equals - name + 1 + strlen(PROC_PATH)); -- strcpy(tmpname, PROC_PATH); -- strncat(tmpname, name, (int) (equals - name)); -- tmpname[equals - name + strlen(PROC_PATH)] = 0; -- /* change . to / */ -- slashdot(tmpname + strlen(PROC_PATH), '.', '/'); -- -- /* used to display the output */ -- outname = xmalloc(equals - name + 1); -- strncpy(outname, name, (int) (equals - name)); -- outname[equals - name] = 0; -- /* change / to . */ -- slashdot(outname, '/', '.'); -- last_dot = strrchr(outname, '.'); -- if (last_dot != NULL && is_deprecated(last_dot + 1)) { -- xwarnx(_("%s is deprecated, value not set"), outname); -- goto out; -- } -- -- if (stat(tmpname, &ts) < 0) { -+ if (stat(path, &ts) < 0) { - if (!IgnoreError) { -- xwarn(_("cannot stat %s"), tmpname); -- rc = -1; -+ xwarn(_("cannot stat %s"), path); -+ rc = EXIT_FAILURE; - } -- goto out; -+ return rc; - } - - if ((ts.st_mode & S_IWUSR) == 0) { -- xwarn(_("setting key \"%s\""), outname); -- goto out; -+ xwarn(_("setting key \"%s\""), key); -+ return rc; - } - - if (S_ISDIR(ts.st_mode)) { -- xwarn(_("setting key \"%s\""), outname); -- goto out; -+ xwarn(_("setting key \"%s\""), key); -+ return rc; - } - -- fp = fprocopen(tmpname, "w"); -- -- if (!fp) { -- switch (errno) { -- case ENOENT: -- if (!IgnoreError) { -- xwarnx(_("\"%s\" is an unknown key%s"), outname, (ignore_failure?_(", ignoring"):"")); -+ if (!DryRun) { -+ if ((fp = fprocopen(path, "w")) == NULL) { -+ switch (errno) { -+ case ENOENT: -+ if (!IgnoreError) { -+ xwarnx(_("\"%s\" is an unknown key%s"), -+ key, (ignore_failure?_(", ignoring"):"")); - if (!ignore_failure) -- rc = -1; -+ rc = EXIT_FAILURE; - } - break; -- case EPERM: -- case EROFS: -- case EACCES: -- xwarnx(_("permission denied on key \"%s\"%s"), outname, (ignore_failure?_(", ignoring"):"")); -- break; -- default: -- xwarn(_("setting key \"%s\"%s"), outname, (ignore_failure?_(", ignoring"):"")); -- break; -- } -- if (!ignore_failure && errno != ENOENT) -- rc = -1; -- } else { -- rc = fprintf(fp, "%s\n", value); -- if (0 < rc) -- rc = 0; -- if (close_stream(fp) != 0) -- xwarn(_("setting key \"%s\""), outname); -- else if (rc == 0 && !Quiet) { -- if (NameOnly) { -- fprintf(stdout, "%s\n", outname); -- } else { -- if (PrintName) { -- fprintf(stdout, "%s = %s\n", -- outname, value); -- } else { -- if (PrintNewline) -- fprintf(stdout, "%s\n", value); -- else -- fprintf(stdout, "%s", value); -- } -- } -- } -- } -- out: -- free(tmpname); -- free(outname); -- return rc; -+ case EPERM: -+ case EROFS: -+ case EACCES: -+ xwarnx(_("permission denied on key \"%s\"%s"), -+ key, (ignore_failure?_(", ignoring"):"")); -+ break; -+ default: -+ xwarn(_("setting key \"%s\"%s"), -+ key, (ignore_failure?_(", ignoring"):"")); -+ break; -+ } -+ if (!ignore_failure && errno != ENOENT) -+ rc = EXIT_FAILURE; -+ } else { -+ if (0 < fprintf(fp, "%s\n", value)) -+ rc = EXIT_SUCCESS; -+ if (close_stream(fp) != 0) { -+ xwarn(_("setting key \"%s\""), path); -+ return rc; -+ } -+ } -+ } -+ if ((rc == EXIT_SUCCESS && !Quiet) || DryRun) { -+ if (NameOnly) { -+ printf("%s\n", value); -+ } else { -+ if (PrintName) { -+ printf("%s = %s\n", path, value); -+ } else { -+ if (PrintNewline) -+ printf("%s\n", value); -+ else -+ printf("%s", value); -+ } -+ } -+ } -+ return rc; -+} -+ -+/* -+ * parse each configuration line, there are multiple ways of specifying -+ * a key/value here: -+ * -+ * key = value simple setting -+ * -key = value ignore errors -+ * key.pattern.*.with.glob = value set keys that match glob -+ * -key.pattern.exclude.with.glob dont set this value -+ * key.pattern.override.with.glob = value set this glob match to value -+ * -+ */ -+ -+static SysctlSetting *parse_setting_line( -+ const char *path, -+ const int linenum, -+ char *line) -+{ -+ SysctlSetting *s; -+ char *key; -+ char *value; -+ bool glob_exclude = FALSE; -+ bool ignore_failure = FALSE; -+ -+ key = lstrip(line); -+ if (strlen(key) < 2) -+ return NULL; -+ -+ /* skip over comments */ -+ if (key[0] == '#' || key[0] == ';') -+ return NULL; -+ -+ if (pattern && !pattern_match(key, pattern)) -+ return NULL; -+ -+ value = strchr(key, '='); -+ if (value == NULL) { -+ if (key[0] == '-') { -+ glob_exclude = TRUE; -+ key++; -+ value = NULL; -+ rstrip(key); -+ } else { -+ xwarnx(_("%s(%d): invalid syntax, continuing..."), -+ path, linenum); -+ return NULL; -+ } -+ } else { -+ value[0]='\0'; -+ if (key[0] == '-') { -+ ignore_failure = TRUE; -+ key++; -+ } -+ value++; // skip over = -+ value=lstrip(value); -+ rstrip(value); -+ rstrip(key); -+ } -+ return setting_new(key, value, ignore_failure, glob_exclude); -+} -+ -+/* Go through the setting list, expand and sort out -+ * setting globs and actually write the settings out -+ */ -+static int write_setting_list(const SettingList *sl) -+{ -+ SysctlSetting *node; -+ int rc = EXIT_SUCCESS; -+ -+ for (node=sl->head; node != NULL; node=node->next) { -+ if (node->glob_exclude) -+ continue; -+ -+ if (string_is_glob(node->path)) { -+ char *gl_path; -+ glob_t globbuf; -+ int i; -+ -+ if (glob(node->path, 0, NULL, &globbuf) != 0) -+ continue; -+ -+ for(i=0; i < globbuf.gl_pathc; i++) { -+ if (settinglist_findpath(sl, globbuf.gl_pathv[i])) -+ continue; // override or exclude -+ -+ rc |= WriteSetting(node->key, globbuf.gl_pathv[i], node->value, -+ node->ignore_failure); -+ } -+ } else { -+ rc |= WriteSetting(node->key, node->path, node->value, -+ node->ignore_failure); -+ } -+ -+ -+ } -+ -+ return rc; - } - - static int pattern_match(const char *string, const char *pat) -@@ -513,12 +699,12 @@ static int pattern_match(const char *str - * Preload the sysctl's from the conf file. We parse the file and then - * reform it (strip out whitespace). - */ --static int Preload(const char *restrict const filename) -+static int Preload(SettingList *setlist, const char *restrict const filename) - { - FILE *fp; - char *t; - int n = 0; -- int rc = 0; -+ int rc = EXIT_SUCCESS; - ssize_t rlen; - char *name, *value; - glob_t globbuf; -@@ -547,62 +733,26 @@ static int Preload(const char *restrict - ? stdin : fopen(globbuf.gl_pathv[j], "r"); - if (!fp) { - xwarn(_("cannot open \"%s\""), globbuf.gl_pathv[j]); -- rc = -1; -- goto out; -+ return EXIT_FAILURE; - } - - while ((rlen = getline(&iobuf, &iolen, fp)) > 0) { - size_t offset; -+ SysctlSetting *setting; - - n++; - - if (rlen < 2) - continue; - -- t = StripLeadingAndTrailingSpaces(iobuf); -- if (strlen(t) < 2) -- continue; -- -- if (*t == '#' || *t == ';') -- continue; -- -- name = strtok(t, "="); -- if (!name || !*name) { -- xwarnx(_("%s(%d): invalid syntax, continuing..."), -- globbuf.gl_pathv[j], n); -- continue; -- } -- -- StripLeadingAndTrailingSpaces(name); -- -- if (pattern && !pattern_match(name, pattern)) -- continue; -- -- offset = strlen(name); -- memmove(&iobuf[0], name, offset); -- iobuf[offset++] = '='; -- -- value = strtok(NULL, "\n\r"); -- if (!value || !*value) { -- xwarnx(_("%s(%d): invalid syntax, continuing..."), -- globbuf.gl_pathv[j], n); -- continue; -- } -- -- while ((*value == ' ' || *value == '\t') && *value != 0) -- value++; -- -- /* should NameOnly affect this? */ -- memmove(&iobuf[offset], value, strlen(value)); -- offset += strlen(value); -- iobuf[offset] = '\0'; -- -- rc |= WriteSetting(iobuf); -+ if ( (setting = parse_setting_line(globbuf.gl_pathv[j], n, iobuf)) -+ == NULL) -+ continue; -+ settinglist_add(setlist, setting); - } - - fclose(fp); - } --out: - return rc; - } - -@@ -618,7 +768,7 @@ static int sortpairs(const void *A, cons - return strcmp(a->name, b->name); - } - --static int PreloadSystem(void) -+static int PreloadSystem(SettingList *setlist) - { - unsigned di, i; - const char *dirs[] = { -@@ -630,7 +780,7 @@ static int PreloadSystem(void) - }; - struct pair **cfgs = NULL; - unsigned ncfgs = 0; -- int rc = 0; -+ int rc = EXIT_SUCCESS; - struct stat ts; - enum { nprealloc = 16 }; - -@@ -688,14 +838,14 @@ static int PreloadSystem(void) - for (i = 0; i < ncfgs; ++i) { - if (!Quiet) - printf(_("* Applying %s ...\n"), cfgs[i]->value); -- rc |= Preload(cfgs[i]->value); -+ rc |= Preload(setlist, cfgs[i]->value); - } - - - if (stat(DEFAULT_PRELOAD, &ts) == 0 && S_ISREG(ts.st_mode)) { - if (!Quiet) - printf(_("* Applying %s ...\n"), DEFAULT_PRELOAD); -- rc |= Preload(DEFAULT_PRELOAD); -+ rc |= Preload(setlist, DEFAULT_PRELOAD); - } - - /* cleaning */ -@@ -717,15 +867,19 @@ int main(int argc, char *argv[]) - bool preloadfileOpt = false; - int ReturnCode = 0; - int c; -+ int rc; - const char *preloadfile = NULL; -+ SettingList *setlist; - - enum { - DEPRECATED_OPTION = CHAR_MAX + 1, -- SYSTEM_OPTION -+ SYSTEM_OPTION, -+ DRYRUN_OPTION - }; - static const struct option longopts[] = { - {"all", no_argument, NULL, 'a'}, - {"deprecated", no_argument, NULL, DEPRECATED_OPTION}, -+ {"dry-run", no_argument, NULL, DRYRUN_OPTION}, - {"binary", no_argument, NULL, 'b'}, - {"ignore", no_argument, NULL, 'e'}, - {"names", no_argument, NULL, 'N'}, -@@ -753,6 +907,10 @@ int main(int argc, char *argv[]) - IgnoreError = false; - Quiet = false; - IgnoreDeprecated = true; -+ DryRun = false; -+ setlist = xmalloc(sizeof(SettingList)); -+ setlist->head = NULL; -+ setlist->tail = NULL; - - if (argc < 2) - Usage(stderr); -@@ -805,7 +963,12 @@ int main(int argc, char *argv[]) - break; - case SYSTEM_OPTION: - IgnoreError = true; -- return PreloadSystem(); -+ rc |= PreloadSystem(setlist); -+ rc |= write_setting_list(setlist); -+ return rc; -+ case DRYRUN_OPTION: -+ DryRun = true; -+ break; - case 'r': - pattern = xstrdup(optarg); - break; -@@ -833,15 +996,16 @@ int main(int argc, char *argv[]) - int ret = EXIT_SUCCESS, i; - if (!preloadfile) { - if (!argc) { -- ret |= Preload(DEFAULT_PRELOAD); -+ ret |= Preload(setlist, DEFAULT_PRELOAD); - } - } else { - /* This happens when -pfile option is - * used without space. */ -- ret |= Preload(preloadfile); -+ ret |= Preload(setlist, preloadfile); - } - for (i = 0; i < argc; i++) -- ret |= Preload(argv[i]); -+ ret |= Preload(setlist, argv[i]); -+ ret |= write_setting_list(setlist); - return ret; - } - -@@ -855,9 +1019,14 @@ int main(int argc, char *argv[]) - program_invocation_short_name); - - for ( ; *argv; argv++) { -- if (WriteMode || strchr(*argv, '=')) -- ReturnCode += WriteSetting(*argv); -- else -+ if (WriteMode || strchr(*argv, '=')) { -+ SysctlSetting *s; -+ if ( (s = parse_setting_line("command line", 0, *argv)) != NULL) -+ ReturnCode |= WriteSetting(s->key, s->path, s->value, -+ s->ignore_failure); -+ else -+ ReturnCode |= EXIT_FAILURE; -+ } else - ReturnCode += ReadSetting(*argv); - } - return ReturnCode; -diff -up ./testsuite/config/unix.exp.ori ./testsuite/config/unix.exp ---- ./testsuite/config/unix.exp.ori 2021-02-09 11:11:25.000000000 +0100 -+++ ./testsuite/config/unix.exp 2022-03-31 18:27:36.536486629 +0200 -@@ -136,6 +136,15 @@ proc expect_table_dsc { test match_heade - #} - } - -+proc expect_spawn_retval { test retval } { -+ foreach {pid spawnid os_error_flag value} [wait] break -+ -+ if {$value == $retval} { -+ return -+ } -+ fail "$test (exit value)" -+} -+ - proc make_pipeproc { } { - global pipeproc_pid pipeproc_spawnid topdir - -diff -up ./testsuite/sysctl_glob_test.conf.ori ./testsuite/sysctl_glob_test.conf ---- ./testsuite/sysctl_glob_test.conf.ori 2022-03-31 18:27:36.537486635 +0200 -+++ ./testsuite/sysctl_glob_test.conf 2022-03-31 18:27:36.537486635 +0200 -@@ -0,0 +1,6 @@ -+# -+# Test configuration for for glob in sysctl -+# -+fs.protected_* = 2 -+fs.protected_hardlinks = 1 -+-fs.protected_regular -diff -up ./testsuite/sysctl.test/sysctl_write.exp.ori ./testsuite/sysctl.test/sysctl_write.exp ---- ./testsuite/sysctl.test/sysctl_write.exp.ori 2022-03-31 18:27:36.536486629 +0200 -+++ ./testsuite/sysctl.test/sysctl_write.exp 2022-03-31 18:27:36.536486629 +0200 -@@ -0,0 +1,29 @@ -+ -+set sysctl ${topdir}sysctl -+ -+set test "sysctl write from command line" -+spawn $sysctl --dry-run kernel.hostname=procps-test -+expect_pass "$test" "/proc/sys/kernel/hostname = procps-test" -+ -+set test "sysctl write from configuration file" -+spawn $sysctl --dry-run -f ${topdir}testsuite/sysctl_glob_test.conf -+expect_pass "$test" "/proc/sys/fs/protected_fifos = 2\\s+/proc/sys/fs/protected_symlinks = 2\\s+/proc/sys/fs/protected_hardlinks = 1" -+ -+set hostname_file "/proc/sys/kernel/hostname" -+if {[file exists ${hostname_file}]} { -+ if {[file writable ${hostname_file}]} { -+ unsupported "sysctl write: hostname file is writable" -+ } else { -+ set test "sysctl write unwritable file" -+ spawn $sysctl -q kernel.hostname=procpstest -+ expect_pass "$test" "sysctl: permission denied on key \"kernel.hostname\"\\s*$" -+ expect_spawn_retval "$test" 1 -+ -+ set test "sysctl write unwritable file ignored" -+ spawn $sysctl -q -- -kernel.hostname=procpstest -+ expect_pass "$test" "sysctl: permission denied on key \"kernel.hostname\", ignoring\\s*$" -+ expect_spawn_retval "$test" 0 -+ } -+} else { -+ unsupported "sysctl write: hostname file doe not exist" -+} diff --git a/sysctl-print-dotted-keys-again.patch b/sysctl-print-dotted-keys-again.patch deleted file mode 100644 index b8c32d7..0000000 --- a/sysctl-print-dotted-keys-again.patch +++ /dev/null @@ -1,153 +0,0 @@ -diff -up ./NEWS.ori ./NEWS ---- ./NEWS.ori 2022-08-15 11:59:35.929714848 +0200 -+++ ./NEWS 2022-08-15 12:00:12.892937479 +0200 -@@ -1,4 +1,14 @@ - procps-ng-NEXT -+<<<<<<< HEAD -+======= -+ * library -+ Re-add elogind support merge #151 -+ * ps: threads again display when -L is used with -q issue #234 -+ * ps: proper aix format string behavior was restored -+ * sysctl: print dotted keys again -+ -+procps-ng-4.0.0 -+>>>>>>> b159c198 (sysctl: print dotted keys again) - --------------- - * Rename pwait to pidwait - -diff -up ./sysctl.c.ori ./sysctl.c ---- ./sysctl.c.ori 2022-08-15 11:59:35.934714878 +0200 -+++ ./sysctl.c 2022-08-15 12:00:12.893937485 +0200 -@@ -152,7 +152,7 @@ static SysctlSetting *setting_new( - strcat(path + proc_len, key+1); - else - strcat(path + proc_len, key); -- /* change . to / */ -+ /* change . to / for path */ - slashdot(path + proc_len, '.', '/'); - - s = xmalloc(sizeof(SysctlSetting)); -@@ -510,7 +510,8 @@ static int WriteSetting( - - int rc = EXIT_SUCCESS; - FILE *fp; -- struct stat ts; -+ struct stat ts; -+ char *dotted_key; - - if (!key || !path) - return rc; -@@ -523,13 +524,22 @@ static int WriteSetting( - return rc; - } - -- if ((ts.st_mode & S_IWUSR) == 0) { -- xwarn(_("setting key \"%s\""), key); -+ /* Convert the globbed path into a dotted key */ -+ if ( (dotted_key = strdup(path + strlen(PROC_PATH))) == NULL) { -+ xerrx(EXIT_FAILURE, _("strdup key")); -+ return EXIT_FAILURE; -+ } -+ slashdot(dotted_key, '/', '.'); -+ -+ if ((ts.st_mode & S_IWUSR) == 0) { -+ xwarn(_("setting key \"%s\""), dotted_key); -+ free(dotted_key); - return rc; - } - -- if (S_ISDIR(ts.st_mode)) { -- xwarn(_("setting key \"%s\""), key); -+ if (S_ISDIR(ts.st_mode)) { -+ xwarn(_("setting key \"%s\""), dotted_key); -+ free(dotted_key); - return rc; - } - -@@ -539,7 +549,7 @@ static int WriteSetting( - case ENOENT: - if (!IgnoreError) { - xwarnx(_("\"%s\" is an unknown key%s"), -- key, (ignore_failure?_(", ignoring"):"")); -+ dotted_key, (ignore_failure?_(", ignoring"):"")); - if (!ignore_failure) - rc = EXIT_FAILURE; - } -@@ -548,11 +558,11 @@ static int WriteSetting( - case EROFS: - case EACCES: - xwarnx(_("permission denied on key \"%s\"%s"), -- key, (ignore_failure?_(", ignoring"):"")); -+ dotted_key, (ignore_failure?_(", ignoring"):"")); - break; - default: - xwarn(_("setting key \"%s\"%s"), -- key, (ignore_failure?_(", ignoring"):"")); -+ dotted_key, (ignore_failure?_(", ignoring"):"")); - break; - } - if (!ignore_failure && errno != ENOENT) -@@ -561,7 +571,7 @@ static int WriteSetting( - if (0 < fprintf(fp, "%s\n", value)) - rc = EXIT_SUCCESS; - if (close_stream(fp) != 0) { -- xwarn(_("setting key \"%s\""), path); -+ xwarn(_("setting key \"%s\""), dotted_key); - return rc; - } - } -@@ -571,7 +581,7 @@ static int WriteSetting( - printf("%s\n", value); - } else { - if (PrintName) { -- printf("%s = %s\n", path, value); -+ printf("%s = %s\n", dotted_key, value); - } else { - if (PrintNewline) - printf("%s\n", value); -@@ -580,6 +590,7 @@ static int WriteSetting( - } - } - } -+ free(dotted_key); - return rc; - } - -diff -up ./testsuite/sysctl_slash_test.conf.ori ./testsuite/sysctl_slash_test.conf ---- ./testsuite/sysctl_slash_test.conf.ori 2022-08-15 12:00:12.894937491 +0200 -+++ ./testsuite/sysctl_slash_test.conf 2022-08-15 12:00:12.893937485 +0200 -@@ -0,0 +1 @@ -+kernel/hostname = procps-test -diff -up ./testsuite/sysctl.test/sysctl_write.exp.ori ./testsuite/sysctl.test/sysctl_write.exp ---- ./testsuite/sysctl.test/sysctl_write.exp.ori 2022-08-15 11:59:35.934714878 +0200 -+++ ./testsuite/sysctl.test/sysctl_write.exp 2022-08-15 12:00:12.893937485 +0200 -@@ -3,11 +3,19 @@ set sysctl ${topdir}sysctl - - set test "sysctl write from command line" - spawn $sysctl --dry-run kernel.hostname=procps-test --expect_pass "$test" "/proc/sys/kernel/hostname = procps-test" -+expect_pass "$test" "kernel.hostname = procps-test" -+ -+set test "sysctl write from command line using slash" -+spawn $sysctl --dry-run kernel/hostname=procps-test -+expect_pass "$test" "kernel.hostname = procps-test" - - set test "sysctl write from configuration file" - spawn $sysctl --dry-run -f ${topdir}testsuite/sysctl_glob_test.conf --expect_pass "$test" "/proc/sys/fs/protected_fifos = 2\\s+/proc/sys/fs/protected_symlinks = 2\\s+/proc/sys/fs/protected_hardlinks = 1" -+expect_pass "$test" "fs.protected_fifos = 2\\s+fs.protected_symlinks = 2\\s+fs.protected_hardlinks = 1" -+ -+set test "sysctl write from file with slashes" -+spawn $sysctl --dry-run -f ${topdir}testsuite/sysctl_slash_test.conf -+expect_pass "$test" "kernel.hostname = procps-test" - - set hostname_file "/proc/sys/kernel/hostname" - if {[file exists ${hostname_file}]} { -@@ -25,5 +33,5 @@ if {[file exists ${hostname_file}]} { - expect_spawn_retval "$test" 0 - } - } else { -- unsupported "sysctl write: hostname file doe not exist" -+ unsupported "sysctl write: hostname file does not exist" - }