.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
-.TH PGREP "1" "2022-08-31" "procps-ng" "User Commands"
+.TH PGREP "1" "2022-11-01" "procps-ng" "User Commands"
.SH NAME
pgrep, pkill, pidwait \- look up, signal, or wait for processes based on name and other attributes
.SH SYNOPSIS
.TQ
\fB\-\-signal\fR \fIsignal\fR
Defines the signal to send to each matched process. Either the numeric or
-the symbolic signal name can be used.
-.RB ( pkill
-only.)
+the symbolic signal name can be used. In
+.B pgrep
+or
+.B pidwait
+mode this has no effect unless used in conjunction with
+\fB\-\-require\-handler\fR to filter to processes with a userspace signal
+handler present for a particular signal.
+
.TP
\fB\-c\fR, \fB\-\-count\fR
Suppress normal output; instead print a count of matching processes. When
.BR sudo
or similar tools.
.TP
+\fB\-H\fR, \fB\-\-require\-handler\fR\fR
+Only match processes with a userspace signal handler present for the signal to
+be sent.
+.TP
\fB\-\-cgroup \fIname\fP,...
Match on provided control group (cgroup) v2 name. See
.BR cgroups (8)
PIDS_CMDLINE,
PIDS_STATE,
PIDS_TIME_ELAPSED,
- PIDS_CGROUP_V
+ PIDS_CGROUP_V,
+ PIDS_SIGCATCH
};
enum rel_items {
EU_PID, EU_PPID, EU_PGRP, EU_EUID, EU_RUID, EU_RGID, EU_SESSION,
EU_TGID, EU_STARTTIME, EU_TTYNAME, EU_CMD, EU_CMDLINE, EU_STA, EU_ELAPSED,
- EU_CGROUP
+ EU_CGROUP, EU_SIGCATCH
};
#define grow_size(x) do { \
if ((x) < 0 || (size_t)(x) >= INT_MAX / 5 / sizeof(struct el)) \
static int opt_threads = 0;
static pid_t opt_ns_pid = 0;
static bool use_sigqueue = false;
+static bool require_handler = false;
static union sigval sigval = {0};
static const char *opt_delim = "\n";
fputs(_(" -w, --lightweight list all TID\n"), fp);
break;
case PKILL:
- fputs(_(" -<sig>, --signal <sig> signal to send (either number or name)\n"), fp);
+ fputs(_(" -H, --require-handler match only if signal handler is present\n"), fp);
fputs(_(" -q, --queue <value> integer value to be sent with the signal\n"), fp);
fputs(_(" -e, --echo display what is killed\n"), fp);
break;
break;
#endif
}
+ fputs(_(" -<sig>, --signal <sig> signal to send (either number or name)\n"), fp);
fputs(_(" -c, --count count of matching processes\n"), fp);
fputs(_(" -f, --full use full process name to match\n"), fp);
fputs(_(" -g, --pgroup <PGID,...> match listed process group IDs\n"), fp);
while (!done) {
struct pids_info *info = NULL;
- if (procps_pids_new(&info, Items, 15) < 0)
+ if (procps_pids_new(&info, Items, 16) < 0)
xerrx(EXIT_FATAL, _("Unable to create pid info structure"));
if (i == size) {
return found;
}
+static unsigned long long unhex (const char *restrict in)
+{
+ unsigned long long ret;
+ char *rem;
+ errno = 0;
+ ret = strtoull(in, &rem, 16);
+ if (errno || *rem != '\0') {
+ xwarnx(_("not a hex string: %s"), in);
+ return 0;
+ }
+ return ret;
+}
+
+static int match_signal_handler (const char *restrict sigcgt, const int signal)
+{
+ return sigcgt && (((1UL << (signal - 1)) & unhex(sigcgt)) != 0);
+}
+
static int match_strlist (const char *restrict value, const struct el *restrict list)
{
int found = 0;
_("Error reading reference namespace information\n"));
}
- if (procps_pids_new(&info, Items, 15) < 0)
+ if (procps_pids_new(&info, Items, 16) < 0)
xerrx(EXIT_FATAL,
_("Unable to create pid info structure"));
which = PIDS_FETCH_TASKS_ONLY;
match = 0;
else if (opt_cgroup && ! match_cgroup_list (PIDS_GETSTV(CGROUP), opt_cgroup))
match = 0;
+ else if (require_handler && ! match_signal_handler (PIDS_GETSTR(SIGCATCH), opt_signal))
+ match = 0;
task_cmdline = PIDS_GETSTR(CMDLINE);
static void parse_opts (int argc, char **argv)
{
char opts[64] = "";
+ int sig;
int opt;
int criteria_count = 0;
static const struct option longopts[] = {
{"signal", required_argument, NULL, SIGNAL_OPTION},
{"ignore-ancestors", no_argument, NULL, 'A'},
+ {"require-handler", no_argument, NULL, 'H'},
{"count", no_argument, NULL, 'c'},
{"cgroup", required_argument, NULL, CGROUP_OPTION},
{"delimiter", required_argument, NULL, 'd'},
{NULL, 0, NULL, 0}
};
+ sig = signal_option(&argc, argv);
+ if (-1 < sig)
+ opt_signal = sig;
+
#ifdef ENABLE_PIDWAIT
if (strcmp (program_invocation_short_name, "pidwait") == 0 ||
strcmp (program_invocation_short_name, "lt-pidwait") == 0) {
#endif
if (strcmp (program_invocation_short_name, "pkill") == 0 ||
strcmp (program_invocation_short_name, "lt-pkill") == 0) {
- int sig;
prog_mode = PKILL;
- sig = signal_option(&argc, argv);
- if (-1 < sig)
- opt_signal = sig;
strcat (opts, "eq:");
} else {
strcat (opts, "lad:vw");
prog_mode = PGREP;
}
- strcat (opts, "LF:cfinoxP:O:Ag:s:u:U:G:t:r:?Vh");
+ strcat (opts, "LF:cfinoxP:O:AHg:s:u:U:G:t:r:?Vh");
while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != -1) {
switch (opt) {
usage ('?');
++criteria_count;
break;
+ case 'H':
+ require_handler = true;
+ ++criteria_count;
+ break;
case 'h':
case '?':
usage (opt);