diff --git a/NEWS b/NEWS index fb83a672..083391a6 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ procps-ng NEXT * kill: 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: Add older than selection merge #79 * pidof: show worker threads Redhat #1803640 * ps.1: Mention stime alias issue #164 * sysctl: Match systemd directory order diff --git a/pgrep.1 b/pgrep.1 index f626a6bb..6dc4081d 100644 --- a/pgrep.1 +++ b/pgrep.1 @@ -7,7 +7,7 @@ .\" the Free Software Foundation; either version 2 of the License, or .\" (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 pgrep, pkill \- look up or signal processes based on name and other attributes .SH SYNOPSIS @@ -100,6 +100,9 @@ Select only the newest (most recently started) of the matching processes. \fB\-o\fR, \fB\-\-oldest\fR Select only the oldest (least recently started) of the matching processes. .TP +\fB\-O\fR, \fB\-\-older\fR \fIsecs\fP +Select processes older than secs. +.TP \fB\-P\fR, \fB\-\-parent\fR \fIppid\fP,... Only match processes whose parent process ID is listed. .TP diff --git a/pgrep.c b/pgrep.c index 0123e2db..a55f49f0 100644 --- a/pgrep.c +++ b/pgrep.c @@ -36,6 +36,7 @@ #include #include #include +#include /* EXIT_SUCCESS is 0 */ /* EXIT_FAILURE is 1 */ @@ -63,11 +64,12 @@ enum pids_item Items[] = { PIDS_TTY_NAME, PIDS_CMD, PIDS_CMDLINE, - PIDS_STATE + PIDS_STATE, + PIDS_TIME_ELAPSED }; 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_TGID, EU_STARTTIME, EU_TTYNAME, EU_CMD, EU_CMDLINE, EU_STA, EU_ELAPSED }; #define grow_size(x) do { \ 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_longlong = 0; static int opt_oldest = 0; +static int opt_older = 0; static int opt_newest = 0; static int opt_negate = 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(_(" -n, --newest select most recently started\n"), fp); fputs(_(" -o, --oldest select least recently started\n"), fp); + fputs(_(" -O, --older select where older than seconds\n"), fp); fputs(_(" -P, --parent match only child processes of the given parent\n"), fp); fputs(_(" -s, --session match session IDs\n"), fp); fputs(_(" -t, --terminal match by controlling terminal\n"), fp); @@ -525,9 +529,15 @@ static struct el * select_procs (int *num) char *cmdoutput = xmalloc(cmdlen); char *task_cmdline; enum pids_fetch_type which; + time_t now; + double uptime_secs; preg = do_regcomp(); + now = time(NULL); + if (procps_uptime(&uptime_secs, NULL) < 0) + xerrx(EXIT_FAILURE, "uptime"); + if (opt_newest) 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")); } - if (procps_pids_new(&info, Items, 13) < 0) + if (procps_pids_new(&info, Items, 14) < 0) xerrx(EXIT_FATAL, _("Unable to create pid info structure")); which = PIDS_FETCH_TASKS_ONLY; @@ -570,9 +580,11 @@ static struct el * select_procs (int *num) match = 0; else if (opt_ns_pid && ! match_ns (PIDS_GETINT(PID), &nsp)) match = 0; + else if (opt_older && PIDS_GETULL(ELAPSED) < opt_older) + match = 0; else if (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; task_cmdline = PIDS_GETSTR(CMDLINE); @@ -686,6 +698,7 @@ static void parse_opts (int argc, char **argv) {"ignore-case", no_argument, NULL, 'i'}, {"newest", no_argument, NULL, 'n'}, {"oldest", no_argument, NULL, 'o'}, + {"older", required_argument, NULL, 'O'}, {"parent", required_argument, NULL, 'P'}, {"session", required_argument, NULL, 's'}, {"terminal", required_argument, NULL, 't'}, @@ -719,7 +732,7 @@ static void parse_opts (int argc, char **argv) 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) { switch (opt) { @@ -815,6 +828,10 @@ static void parse_opts (int argc, char **argv) opt_oldest = 1; ++criteria_count; break; + case 'O': + opt_older = atoi (optarg); + ++criteria_count; + break; case 's': /* Solaris: match by session ID -- zero means self */ opt_sid = split_list (optarg, conv_sid); if (opt_sid == NULL)