pgrep: Match on cgroup v2 paths
You can match or filter on cgroup paths. Currently the match is only done for version 2 cgroups because these are way simpler as they have a unified name and always start with "0::". cgroup v1 can have: named groups "1:name=myspecialname:" controllers "9:blkio:" multiple controllers! "4:cpu,cpuacct:" So they are very much more complicated from a options parsing and cgroup matching point of view. In addition, both my Debian bookworm and bullseye systems use v2 cgroups. $ ./pgrep --cgroup /system.slice/cron.service 760 Signed-off-by: Craig Small <csmall@dropbear.xyz>
This commit is contained in:
parent
14d6ab27d6
commit
4cfb0fb763
1
NEWS
1
NEWS
@ -9,6 +9,7 @@ procps-ng-NEXT
|
|||||||
* pkill: Check for lt- variants of program name issue #192
|
* pkill: Check for lt- variants of program name issue #192
|
||||||
* pgrep: Add newline after regex error message merge #91
|
* pgrep: Add newline after regex error message merge #91
|
||||||
* pgrep: Fix selection where uid/gid > 2^31 merge !146
|
* pgrep: Fix selection where uid/gid > 2^31 merge !146
|
||||||
|
* pgrep: Select on cgroup v2 paths issue #168
|
||||||
* ps: Add OOM and OOMADJ fields issue #198
|
* ps: Add OOM and OOMADJ fields issue #198
|
||||||
* ps: Add IO Accounting fields issue #184
|
* ps: Add IO Accounting fields issue #184
|
||||||
* ps: Add PSS and USS fields issue #112
|
* ps: Add PSS and USS fields issue #112
|
||||||
|
9
pgrep.1
9
pgrep.1
@ -7,7 +7,7 @@
|
|||||||
.\" the Free Software Foundation; either version 2 of the License, or
|
.\" the Free Software Foundation; either version 2 of the License, or
|
||||||
.\" (at your option) any later version.
|
.\" (at your option) any later version.
|
||||||
.\"
|
.\"
|
||||||
.TH PGREP "1" "2020-06-04" "procps-ng" "User Commands"
|
.TH PGREP "1" "2021-10-26" "procps-ng" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
pgrep, pkill, pidwait \- 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
|
.SH SYNOPSIS
|
||||||
@ -177,6 +177,10 @@ Fail if pidfile (see \fB\-F\fR) not locked.
|
|||||||
\fB\-r\fR, \fB\-\-runstates\fR \fID,R,S,Z,\fP...
|
\fB\-r\fR, \fB\-\-runstates\fR \fID,R,S,Z,\fP...
|
||||||
Match only processes which match the process state.
|
Match only processes which match the process state.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-cgroup \fIname\fP,...
|
||||||
|
Match on provided control group (cgroup) v2 name. See
|
||||||
|
.BR cgroups (8)
|
||||||
|
.TP
|
||||||
\fB\-\-ns \fIpid\fP
|
\fB\-\-ns \fIpid\fP
|
||||||
Match processes that belong to the same namespaces. Required to run as
|
Match processes that belong to the same namespaces. Required to run as
|
||||||
root to match processes from other users. See \fB\-\-nslist\fR for how to
|
root to match processes from other users. See \fB\-\-nslist\fR for how to
|
||||||
@ -282,7 +286,8 @@ Defunct processes are reported.
|
|||||||
.BR killall (1),
|
.BR killall (1),
|
||||||
.BR skill (1),
|
.BR skill (1),
|
||||||
.BR kill (1),
|
.BR kill (1),
|
||||||
.BR kill (2)
|
.BR kill (2),
|
||||||
|
.BR cgroups (8)
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
.UR kjetilho@ifi.uio.no
|
.UR kjetilho@ifi.uio.no
|
||||||
Kjetil Torgrim Homme
|
Kjetil Torgrim Homme
|
||||||
|
51
pgrep.c
51
pgrep.c
@ -72,11 +72,13 @@ enum pids_item Items[] = {
|
|||||||
PIDS_CMD,
|
PIDS_CMD,
|
||||||
PIDS_CMDLINE,
|
PIDS_CMDLINE,
|
||||||
PIDS_STATE,
|
PIDS_STATE,
|
||||||
PIDS_TIME_ELAPSED
|
PIDS_TIME_ELAPSED,
|
||||||
|
PIDS_CGROUP_V
|
||||||
};
|
};
|
||||||
enum rel_items {
|
enum rel_items {
|
||||||
EU_PID, EU_PPID, EU_PGRP, EU_EUID, EU_RUID, EU_RGID, EU_SESSION,
|
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_TGID, EU_STARTTIME, EU_TTYNAME, EU_CMD, EU_CMDLINE, EU_STA, EU_ELAPSED,
|
||||||
|
EU_CGROUP
|
||||||
};
|
};
|
||||||
#define grow_size(x) do { \
|
#define grow_size(x) do { \
|
||||||
if ((x) < 0 || (size_t)(x) >= INT_MAX / 5 / sizeof(struct el)) \
|
if ((x) < 0 || (size_t)(x) >= INT_MAX / 5 / sizeof(struct el)) \
|
||||||
@ -127,6 +129,7 @@ static struct el *opt_term = NULL;
|
|||||||
static struct el *opt_euid = NULL;
|
static struct el *opt_euid = NULL;
|
||||||
static struct el *opt_ruid = NULL;
|
static struct el *opt_ruid = NULL;
|
||||||
static struct el *opt_nslist = NULL;
|
static struct el *opt_nslist = NULL;
|
||||||
|
static struct el *opt_cgroup = NULL;
|
||||||
static char *opt_pattern = NULL;
|
static char *opt_pattern = NULL;
|
||||||
static char *opt_pidfile = NULL;
|
static char *opt_pidfile = NULL;
|
||||||
static char *opt_runstates = NULL;
|
static char *opt_runstates = NULL;
|
||||||
@ -177,6 +180,7 @@ static int __attribute__ ((__noreturn__)) usage(int opt)
|
|||||||
fputs(_(" -F, --pidfile <file> read PIDs from file\n"), fp);
|
fputs(_(" -F, --pidfile <file> read PIDs from file\n"), fp);
|
||||||
fputs(_(" -L, --logpidfile fail if PID file is not locked\n"), fp);
|
fputs(_(" -L, --logpidfile fail if PID file is not locked\n"), fp);
|
||||||
fputs(_(" -r, --runstates <state> match runstates [D,S,Z,...]\n"), fp);
|
fputs(_(" -r, --runstates <state> match runstates [D,S,Z,...]\n"), fp);
|
||||||
|
fputs(_(" --cgroup <grp,...> match by cgroup v2 names\n"), fp);
|
||||||
fputs(_(" --ns <PID> match the processes that belong to the same\n"
|
fputs(_(" --ns <PID> match the processes that belong to the same\n"
|
||||||
" namespace as <pid>\n"), fp);
|
" namespace as <pid>\n"), fp);
|
||||||
fputs(_(" --nslist <ns,...> list which namespaces will be considered for\n"
|
fputs(_(" --nslist <ns,...> list which namespaces will be considered for\n"
|
||||||
@ -455,6 +459,35 @@ static int match_ns (const int pid,
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cgroup_cmp(const char *restrict cgroup,
|
||||||
|
const char *restrict path)
|
||||||
|
{
|
||||||
|
if (cgroup == NULL || path == NULL)
|
||||||
|
return 1;
|
||||||
|
// Cgroup v2 have 0::
|
||||||
|
if (strncmp("0::", cgroup, 3) == 0) {
|
||||||
|
return strcmp(cgroup+3, path);
|
||||||
|
} //might try for cgroup v1 later
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int match_cgroup_list(char **values,
|
||||||
|
const struct el *restrict list)
|
||||||
|
{
|
||||||
|
if (list != NULL && values != NULL) {
|
||||||
|
int i, j;
|
||||||
|
for (i = list[0].num; i > 0; i--) {
|
||||||
|
for (j=0; values[j] && values[j][0]; j++) {
|
||||||
|
if (! cgroup_cmp (values[j], list[i].str)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void output_numlist (const struct el *restrict list, int num)
|
static void output_numlist (const struct el *restrict list, int num)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -535,6 +568,7 @@ static struct el * select_procs (int *num)
|
|||||||
#define PIDS_GETULL(e) PIDS_VAL(EU_ ## e, ull_int, stack, info)
|
#define PIDS_GETULL(e) PIDS_VAL(EU_ ## e, ull_int, stack, info)
|
||||||
#define PIDS_GETSTR(e) PIDS_VAL(EU_ ## e, str, stack, info)
|
#define PIDS_GETSTR(e) PIDS_VAL(EU_ ## e, str, stack, info)
|
||||||
#define PIDS_GETSCH(e) PIDS_VAL(EU_ ## e, s_ch, stack, info)
|
#define PIDS_GETSCH(e) PIDS_VAL(EU_ ## e, s_ch, stack, info)
|
||||||
|
#define PIDS_GETSTV(e) PIDS_VAL(EU_ ## e, strv, stack, info)
|
||||||
struct pids_info *info=NULL;
|
struct pids_info *info=NULL;
|
||||||
struct procps_ns nsp;
|
struct procps_ns nsp;
|
||||||
struct pids_stack *stack;
|
struct pids_stack *stack;
|
||||||
@ -568,7 +602,7 @@ static struct el * select_procs (int *num)
|
|||||||
_("Error reading reference namespace information\n"));
|
_("Error reading reference namespace information\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (procps_pids_new(&info, Items, 14) < 0)
|
if (procps_pids_new(&info, Items, 15) < 0)
|
||||||
xerrx(EXIT_FATAL,
|
xerrx(EXIT_FATAL,
|
||||||
_("Unable to create pid info structure"));
|
_("Unable to create pid info structure"));
|
||||||
which = PIDS_FETCH_TASKS_ONLY;
|
which = PIDS_FETCH_TASKS_ONLY;
|
||||||
@ -607,6 +641,8 @@ static struct el * select_procs (int *num)
|
|||||||
match = match_strlist(PIDS_GETSTR(TTYNAME), opt_term);
|
match = match_strlist(PIDS_GETSTR(TTYNAME), opt_term);
|
||||||
else if (opt_runstates && ! strchr(opt_runstates, PIDS_GETSCH(STA)))
|
else if (opt_runstates && ! strchr(opt_runstates, PIDS_GETSCH(STA)))
|
||||||
match = 0;
|
match = 0;
|
||||||
|
else if (opt_cgroup && ! match_cgroup_list (PIDS_GETSTV(CGROUP), opt_cgroup))
|
||||||
|
match = 0;
|
||||||
|
|
||||||
task_cmdline = PIDS_GETSTR(CMDLINE);
|
task_cmdline = PIDS_GETSTR(CMDLINE);
|
||||||
|
|
||||||
@ -681,6 +717,7 @@ static struct el * select_procs (int *num)
|
|||||||
#undef PIDS_GETUNT
|
#undef PIDS_GETUNT
|
||||||
#undef PIDS_GETULL
|
#undef PIDS_GETULL
|
||||||
#undef PIDS_GETSTR
|
#undef PIDS_GETSTR
|
||||||
|
#undef PIDS_GETSTV
|
||||||
}
|
}
|
||||||
|
|
||||||
static int signal_option(int *argc, char **argv)
|
static int signal_option(int *argc, char **argv)
|
||||||
@ -718,10 +755,12 @@ static void parse_opts (int argc, char **argv)
|
|||||||
SIGNAL_OPTION = CHAR_MAX + 1,
|
SIGNAL_OPTION = CHAR_MAX + 1,
|
||||||
NS_OPTION,
|
NS_OPTION,
|
||||||
NSLIST_OPTION,
|
NSLIST_OPTION,
|
||||||
|
CGROUP_OPTION,
|
||||||
};
|
};
|
||||||
static const struct option longopts[] = {
|
static const struct option longopts[] = {
|
||||||
{"signal", required_argument, NULL, SIGNAL_OPTION},
|
{"signal", required_argument, NULL, SIGNAL_OPTION},
|
||||||
{"count", no_argument, NULL, 'c'},
|
{"count", no_argument, NULL, 'c'},
|
||||||
|
{"cgroup", required_argument, NULL, CGROUP_OPTION},
|
||||||
{"delimiter", required_argument, NULL, 'd'},
|
{"delimiter", required_argument, NULL, 'd'},
|
||||||
{"list-name", no_argument, NULL, 'l'},
|
{"list-name", no_argument, NULL, 'l'},
|
||||||
{"list-full", no_argument, NULL, 'a'},
|
{"list-full", no_argument, NULL, 'a'},
|
||||||
@ -920,6 +959,12 @@ static void parse_opts (int argc, char **argv)
|
|||||||
sigval.sival_int = atoi(optarg);
|
sigval.sival_int = atoi(optarg);
|
||||||
use_sigqueue = true;
|
use_sigqueue = true;
|
||||||
break;
|
break;
|
||||||
|
case CGROUP_OPTION:
|
||||||
|
opt_cgroup = split_list (optarg, conv_str);
|
||||||
|
if (opt_cgroup == NULL)
|
||||||
|
usage ('?');
|
||||||
|
++criteria_count;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case '?':
|
case '?':
|
||||||
usage (opt);
|
usage (opt);
|
||||||
|
Loading…
Reference in New Issue
Block a user