From: Masatake YAMATO Date: Sun, 30 Jun 2024 12:09:44 +0000 (+0900) Subject: kill: add a feature decoding signal masks X-Git-Tag: v2.42-start~265^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=873370b6298b33ca1c757b3238c70a6ad6d4758e;p=thirdparty%2Futil-linux.git kill: add a feature decoding signal masks -l/--list option is extended to work well with the output of ps command: $ ps s $$ UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND 1000 1588189 0000000000000000 0000000000010000 0000000000384004 000000004b813efb S pts/56 0:00 bash $ ./kill --list 0x000000004b813efb HUP INT ILL TRAP ABRT ... If you know the pid you are interested in, you can skip running ps comman with -d/--show-process-state option: $ ./kill --show-process-state $$ Blocked: INT Ignored: TERM TSTP TTIN TTOU Caught: HUP INT PIPE ALRM CHLD WINCH Signed-off-by: Masatake YAMATO --- diff --git a/misc-utils/kill.1.adoc b/misc-utils/kill.1.adoc index 40ab0248d..5421fe16f 100644 --- a/misc-utils/kill.1.adoc +++ b/misc-utils/kill.1.adoc @@ -19,8 +19,9 @@ kill - terminate a process *kill* [**-**_signal_|*-s* _signal_|*-p*] [*-q* _value_] [*-a*] [*--timeout* _milliseconds_ _signal_] [*--*] _pid_|_name_... -*kill* *-l* [_number_] | *-L* +*kill* *-l* [_number_|``0x``_sigmask_] | *-L* +*kill* *-d* _pid_ == DESCRIPTION @@ -54,8 +55,20 @@ All processes invoked using this _name_ will be signaled. *-s*, *--signal* _signal_:: The signal to send. It may be given as a name or a number. -*-l*, *--list* [_number_]:: -Print a list of signal names, or convert the given signal number to a name. The signals can be found in _/usr/include/linux/signal.h_. +*-l*, *--list* [_number_|``0x``_sigmask_]:: +Print a list of signal names, convert the given signal number to a name, or convert the given signal mask to names. +The signals can be found in _/usr/include/linux/signal.h_. ++ +.... +$ ps s $$ + UID PID PENDING BLOCKED IGNORED CAUGHT STAT TTY TIME COMMAND + 1000 1608069 0000000000000000 0000000000000002 0000000000384000 0000000008013003 Ss pts/44 0:02 zsh +$ kill -l 0x0000000000384000 +TERM +TSTP +TTIN +TTOU +.... *-L*, *--table*:: Similar to *-l*, but it will print signal names and their corresponding numbers. *-a*, *--all*:: @@ -81,6 +94,15 @@ As an example, the following command sends the signals *QUIT*, *TERM* and *KILL* kill --verbose --timeout 1000 TERM --timeout 1000 KILL \ --signal QUIT 12345 .... +*-d*, *--show-process-state* _pid_:: +Decode signal related fields in /proc/_pid_/status. ++ +.... +$ kill -d $$ +Blocked: INT +Ignored: TERM TSTP TTIN TTOU +Caught: HUP INT PIPE ALRM CHLD WINCH +.... == EXIT STATUS @@ -114,6 +136,8 @@ The original version was taken from BSD 4.4. *kill*(2), *sigqueue*(3), *signal*(7) +*proc(5)* +*proc_pid_status(5)* include::man-common/bugreports.adoc[] diff --git a/misc-utils/kill.c b/misc-utils/kill.c index 2a42267aa..40f0c2f18 100644 --- a/misc-utils/kill.c +++ b/misc-utils/kill.c @@ -46,6 +46,7 @@ #include /* for isdigit() */ #include +#include #include #include #include @@ -103,21 +104,84 @@ struct kill_control { verbose:1; }; -static void print_signal_name(int signum) +static void print_signal_name(int signum, bool newline) { const char *name = signum_to_signame(signum); + const char *eol = newline? "\n": ""; if (name) { - printf("%s\n", name); + printf("%s%s", name, eol); return; } #ifdef SIGRTMIN if (SIGRTMIN <= signum && signum <= SIGRTMAX) { - printf("RT%d\n", signum - SIGRTMIN); + printf("RT%d%s", signum - SIGRTMIN, eol); return; } #endif - printf("%d\n", signum); + printf("%d%s", signum, eol); +} + +static void print_signal_mask(uint64_t sigmask, const char sep) +{ + for (size_t i = 0; i < sizeof(sigmask) * 8; i++) { + if ((((uint64_t)0x1) << i) & sigmask) { + const int signum = i + 1; + print_signal_name(signum, false); + putchar(sep); + } + } +} + +static void print_process_signal_state(pid_t pid) +{ + struct path_cxt *pc = NULL; + FILE *fp; + char buf[BUFSIZ]; + + static const struct sigfield { + char *key; + char *label; + } sigfields[] = { + { "SigPnd:\t", N_("Pending (thread)") }, + { "ShdPnd:\t", N_("Pending (process)") }, + { "SigBlk:\t", N_("Blocked") }, + { "SigIgn:\t", N_("Ignored") }, + { "SigCgt:\t", N_("Caught") }, + }; + + pc = ul_new_procfs_path(pid, NULL); + if (!pc) + err(EXIT_FAILURE, _("failed to initialize procfs handler")); + fp = ul_path_fopen(pc, "r", "status"); + if (!fp) + err(EXIT_FAILURE, _("cannot open /proc/%d/status"), pid); + + while (fgets(buf, sizeof(buf), fp) != NULL) { + for (size_t i = 0; i < ARRAY_SIZE(sigfields); i++) { + const char *key = sigfields[i].key; + size_t keylen = strlen(key); + + if (strncmp(buf, key, keylen) == 0) { + char *val = buf + keylen; + uint64_t sigmask; + + rtrim_whitespace((unsigned char*)val); + if (ul_strtou64(val, &sigmask, 16) < 0) { + warnx( _("unexpected sigmask format: %s (%s)"), val, key); + continue; + } + if (sigmask != 0) { + printf("%s: ", _(sigfields[i].label)); + print_signal_mask(sigmask, ' '); + putchar('\n'); + } + } + } + } + + fclose(fp); + ul_unref_path(pc); } static void pretty_print_signal(FILE *fp, size_t term_width, size_t *lpos, @@ -211,9 +275,13 @@ static void __attribute__((__noreturn__)) usage(void) " wait up to timeout and send follow-up signal\n"), out); #endif fputs(_(" -p, --pid print pids without signaling them\n"), out); - fputs(_(" -l, --list[=] list signal names, or convert a signal number to a name\n"), out); + fputs(_(" -l, --list[=|=0x]\n" + " list signal names, convert a signal number to a name,\n" + " or convrt a signal mask to names\n"), out); fputs(_(" -L, --table list signal names and numbers\n"), out); fputs(_(" -r, --require-handler do not send signal if signal handler is not present\n"), out); + fputs(_(" -d, --show-process-state \n" + " show signal related fields in /proc//status\n"), out); fputs(_(" --verbose print pids that will be signaled\n"), out); fputs(USAGE_SEPARATOR, out); @@ -286,24 +354,57 @@ static char **parse_arguments(int argc, char **argv, struct kill_control *ctl) errx(EXIT_FAILURE, _("too many arguments")); /* argc == 2, accept "kill -l $?" */ arg = argv[1]; + if (arg[0] == '0' && arg[1] == 'x') { + uint64_t sigmask; + if (ul_strtou64(arg + 2, &sigmask, 16) < 0) + errx(EXIT_FAILURE, _("invalid sigmask format: %s"), arg); + print_signal_mask(sigmask, '\n'); + exit(EXIT_SUCCESS); + } if ((ctl->numsig = arg_to_signum(arg, 1)) < 0) errx(EXIT_FAILURE, _("unknown signal: %s"), arg); - print_signal_name(ctl->numsig); + print_signal_name(ctl->numsig, true); exit(EXIT_SUCCESS); } /* for compatibility with procps kill(1) */ if (!strncmp(arg, "--list=", 7) || !strncmp(arg, "-l=", 3)) { char *p = strchr(arg, '=') + 1; + if (p[0] == '0' && p[1] == 'x') { + uint64_t sigmask; + if (ul_strtou64(p + 2, &sigmask, 16) < 0) + errx(EXIT_FAILURE, _("invalid sigmask format: %s"), p); + print_signal_mask(sigmask, '\n'); + exit(EXIT_SUCCESS); + } if ((ctl->numsig = arg_to_signum(p, 1)) < 0) errx(EXIT_FAILURE, _("unknown signal: %s"), p); - print_signal_name(ctl->numsig); + print_signal_name(ctl->numsig, true); exit(EXIT_SUCCESS); } if (!strcmp(arg, "-L") || !strcmp(arg, "--table")) { print_all_signals(stdout, 1); exit(EXIT_SUCCESS); } + if (!strcmp(arg, "-d") || !strcmp(arg, "--show-process-state")) { + pid_t pid; + if (argc < 2) + errx(EXIT_FAILURE, _("too few arguments")); + if (2 < argc) + errx(EXIT_FAILURE, _("too many arguments")); + arg = argv[1]; + pid = strtopid_or_err(arg, _("invalid pid argument")); + print_process_signal_state(pid); + exit(EXIT_SUCCESS); + } + if (!strncmp(arg, "-d=", 3) || !strncmp(arg, "--show-process-state=", 21)) { + pid_t pid; + char *p = strchr(arg, '=') + 1; + + pid = strtopid_or_err(p, _("invalid pid argument")); + print_process_signal_state((pid_t)pid); + exit(EXIT_SUCCESS); + } if (!strcmp(arg, "-r") || !strcmp(arg, "--require-handler")) { ctl->require_handler = 1; continue;