pgrep: Allow older than selection

Re-work merge request !79 of @edneville to permit older than
selection using the new library API.

References:
 procps-ng/procps!79
This commit is contained in:
Craig Small 2020-05-17 23:00:27 +10:00
parent eeb8cf00a4
commit 9f751a7538
3 changed files with 27 additions and 6 deletions

1
NEWS
View File

@ -3,6 +3,7 @@ procps-ng NEXT
* kill: Pass int to signalled process merge #32 * kill: Pass int to signalled process merge #32
* pgrep: Pass int to signalled process merge #32 * pgrep: Pass int to signalled process merge #32
* pgrep: Check sanity of SG_ARG_MAX issue #152 * pgrep: Check sanity of SG_ARG_MAX issue #152
* pgrep: Add older than selection merge #79
* pidof: show worker threads Redhat #1803640 * pidof: show worker threads Redhat #1803640
* ps.1: Mention stime alias issue #164 * ps.1: Mention stime alias issue #164
* sysctl: Match systemd directory order * sysctl: Match systemd directory order

View File

@ -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-04-24" "procps-ng" "User Commands" .TH PGREP "1" "2020-05-17" "procps-ng" "User Commands"
.SH NAME .SH NAME
pgrep, pkill \- look up or signal processes based on name and other attributes pgrep, pkill \- look up or signal processes based on name and other attributes
.SH SYNOPSIS .SH SYNOPSIS
@ -100,6 +100,9 @@ Select only the newest (most recently started) of the matching processes.
\fB\-o\fR, \fB\-\-oldest\fR \fB\-o\fR, \fB\-\-oldest\fR
Select only the oldest (least recently started) of the matching processes. Select only the oldest (least recently started) of the matching processes.
.TP .TP
\fB\-O\fR, \fB\-\-older\fR \fIsecs\fP
Select processes older than secs.
.TP
\fB\-P\fR, \fB\-\-parent\fR \fIppid\fP,... \fB\-P\fR, \fB\-\-parent\fR \fIppid\fP,...
Only match processes whose parent process ID is listed. Only match processes whose parent process ID is listed.
.TP .TP

27
pgrep.c
View File

@ -36,6 +36,7 @@
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <stdbool.h> #include <stdbool.h>
#include <time.h>
/* EXIT_SUCCESS is 0 */ /* EXIT_SUCCESS is 0 */
/* EXIT_FAILURE is 1 */ /* EXIT_FAILURE is 1 */
@ -63,11 +64,12 @@ enum pids_item Items[] = {
PIDS_TTY_NAME, PIDS_TTY_NAME,
PIDS_CMD, PIDS_CMD,
PIDS_CMDLINE, PIDS_CMDLINE,
PIDS_STATE PIDS_STATE,
PIDS_TIME_ELAPSED
}; };
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_TGID, EU_STARTTIME, EU_TTYNAME, EU_CMD, EU_CMDLINE, EU_STA, EU_ELAPSED
}; };
#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)) \
@ -88,6 +90,7 @@ static int opt_full = 0;
static int opt_long = 0; static int opt_long = 0;
static int opt_longlong = 0; static int opt_longlong = 0;
static int opt_oldest = 0; static int opt_oldest = 0;
static int opt_older = 0;
static int opt_newest = 0; static int opt_newest = 0;
static int opt_negate = 0; static int opt_negate = 0;
static int opt_exact = 0; static int opt_exact = 0;
@ -145,6 +148,7 @@ static int __attribute__ ((__noreturn__)) usage(int opt)
fputs(_(" -i, --ignore-case match case insensitively\n"), fp); fputs(_(" -i, --ignore-case match case insensitively\n"), fp);
fputs(_(" -n, --newest select most recently started\n"), fp); fputs(_(" -n, --newest select most recently started\n"), fp);
fputs(_(" -o, --oldest select least recently started\n"), fp); fputs(_(" -o, --oldest select least recently started\n"), fp);
fputs(_(" -O, --older <seconds> select where older than seconds\n"), fp);
fputs(_(" -P, --parent <PPID,...> match only child processes of the given parent\n"), fp); fputs(_(" -P, --parent <PPID,...> match only child processes of the given parent\n"), fp);
fputs(_(" -s, --session <SID,...> match session IDs\n"), fp); fputs(_(" -s, --session <SID,...> match session IDs\n"), fp);
fputs(_(" -t, --terminal <tty,...> match by controlling terminal\n"), fp); fputs(_(" -t, --terminal <tty,...> match by controlling terminal\n"), fp);
@ -525,9 +529,15 @@ static struct el * select_procs (int *num)
char *cmdoutput = xmalloc(cmdlen); char *cmdoutput = xmalloc(cmdlen);
char *task_cmdline; char *task_cmdline;
enum pids_fetch_type which; enum pids_fetch_type which;
time_t now;
double uptime_secs;
preg = do_regcomp(); preg = do_regcomp();
now = time(NULL);
if (procps_uptime(&uptime_secs, NULL) < 0)
xerrx(EXIT_FAILURE, "uptime");
if (opt_newest) saved_start_time = 0ULL; if (opt_newest) saved_start_time = 0ULL;
else saved_start_time = ~0ULL; else saved_start_time = ~0ULL;
@ -538,7 +548,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, 13) < 0) if (procps_pids_new(&info, Items, 14) < 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;
@ -570,9 +580,11 @@ static struct el * select_procs (int *num)
match = 0; match = 0;
else if (opt_ns_pid && ! match_ns (PIDS_GETINT(PID), &nsp)) else if (opt_ns_pid && ! match_ns (PIDS_GETINT(PID), &nsp))
match = 0; match = 0;
else if (opt_older && PIDS_GETULL(ELAPSED) < opt_older)
match = 0;
else if (opt_term) else if (opt_term)
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;
task_cmdline = PIDS_GETSTR(CMDLINE); task_cmdline = PIDS_GETSTR(CMDLINE);
@ -686,6 +698,7 @@ static void parse_opts (int argc, char **argv)
{"ignore-case", no_argument, NULL, 'i'}, {"ignore-case", no_argument, NULL, 'i'},
{"newest", no_argument, NULL, 'n'}, {"newest", no_argument, NULL, 'n'},
{"oldest", no_argument, NULL, 'o'}, {"oldest", no_argument, NULL, 'o'},
{"older", required_argument, NULL, 'O'},
{"parent", required_argument, NULL, 'P'}, {"parent", required_argument, NULL, 'P'},
{"session", required_argument, NULL, 's'}, {"session", required_argument, NULL, 's'},
{"terminal", required_argument, NULL, 't'}, {"terminal", required_argument, NULL, 't'},
@ -719,7 +732,7 @@ static void parse_opts (int argc, char **argv)
strcat (opts, "lad:vw"); strcat (opts, "lad:vw");
} }
strcat (opts, "LF:cfinoxP:g:s:u:U:G:t:r:?Vh"); strcat (opts, "LF:cfinoxP:O:g:s:u:U:G:t:r:?Vh");
while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != -1) { while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != -1) {
switch (opt) { switch (opt) {
@ -815,6 +828,10 @@ static void parse_opts (int argc, char **argv)
opt_oldest = 1; opt_oldest = 1;
++criteria_count; ++criteria_count;
break; break;
case 'O':
opt_older = atoi (optarg);
++criteria_count;
break;
case 's': /* Solaris: match by session ID -- zero means self */ case 's': /* Solaris: match by session ID -- zero means self */
opt_sid = split_list (optarg, conv_sid); opt_sid = split_list (optarg, conv_sid);
if (opt_sid == NULL) if (opt_sid == NULL)