pgrep: add pwait
This commit is contained in:
		
				
					committed by
					
						
						Craig Small
					
				
			
			
				
	
			
			
			
						parent
						
							9f33a6bcd0
						
					
				
				
					commit
					c8384e682c
				
			
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -37,6 +37,7 @@ pgrep
 | 
			
		||||
pidof
 | 
			
		||||
pkill
 | 
			
		||||
pmap
 | 
			
		||||
pwait
 | 
			
		||||
procps-ng-*.tar.xz
 | 
			
		||||
proc/.depend
 | 
			
		||||
proc/libprocps.la
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Makefile.am
									
									
									
									
									
								
							@@ -54,6 +54,9 @@ bin_PROGRAMS = \
 | 
			
		||||
	uptime \
 | 
			
		||||
	vmstat \
 | 
			
		||||
	w
 | 
			
		||||
if BUILD_PWAIT
 | 
			
		||||
bin_PROGRAMS += pwait
 | 
			
		||||
endif
 | 
			
		||||
else
 | 
			
		||||
usrbin_exec_PROGRAMS += \
 | 
			
		||||
	ps/pscommand \
 | 
			
		||||
@@ -88,6 +91,10 @@ dist_man_MANS += \
 | 
			
		||||
	sysctl.8 \
 | 
			
		||||
	sysctl.conf.5 \
 | 
			
		||||
	ps/ps.1
 | 
			
		||||
 | 
			
		||||
if BUILD_PWAIT
 | 
			
		||||
dist_man_MANS += pwait.1
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST = \
 | 
			
		||||
@@ -201,6 +208,9 @@ free_SOURCES = free.c lib/strutils.c lib/fileutils.c
 | 
			
		||||
pgrep_SOURCES = pgrep.c lib/fileutils.c lib/signals.c
 | 
			
		||||
pkill_SOURCES = pgrep.c lib/fileutils.c lib/signals.c
 | 
			
		||||
pmap_SOURCES = pmap.c lib/fileutils.c
 | 
			
		||||
if BUILD_PWAIT
 | 
			
		||||
pwait_SOURCES = pgrep.c lib/fileutils.c lib/nsutils.c
 | 
			
		||||
endif
 | 
			
		||||
if !CYGWIN
 | 
			
		||||
pwdx_SOURCES = pwdx.c lib/fileutils.c
 | 
			
		||||
pwdx_LDADD= $(CYGWINFLAGS)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								configure.ac
									
									
									
									
									
								
							@@ -10,6 +10,7 @@ AM_INIT_AUTOMAKE([foreign 1.11 subdir-objects -Wall -Wno-portability tar-pax no-
 | 
			
		||||
AM_SILENT_RULES([yes])
 | 
			
		||||
AC_CONFIG_SRCDIR([free.c])
 | 
			
		||||
AC_CONFIG_HEADERS([config.h])
 | 
			
		||||
AC_LANG([C])
 | 
			
		||||
 | 
			
		||||
# Checks for programs.
 | 
			
		||||
AC_USE_SYSTEM_EXTENSIONS
 | 
			
		||||
@@ -120,6 +121,21 @@ AC_TRY_COMPILE([#include <errno.h>],
 | 
			
		||||
		AC_MSG_RESULT(yes),
 | 
			
		||||
		AC_MSG_RESULT(no))
 | 
			
		||||
 | 
			
		||||
AC_CHECK_FUNC([pidfd_open], [enable_pwait=yes], [
 | 
			
		||||
  AC_MSG_CHECKING([for __NR_pidfd_open])
 | 
			
		||||
  AC_COMPILE_IFELSE([AC_LANG_SOURCE([
 | 
			
		||||
#include <sys/syscall.h>
 | 
			
		||||
#ifndef __NR_pidfd_open
 | 
			
		||||
#error __NR_pidfd_open not defined
 | 
			
		||||
#endif
 | 
			
		||||
    ])], [enable_pwait=yes], [enable_pwait=no])
 | 
			
		||||
  AC_MSG_RESULT([$enable_pwait])
 | 
			
		||||
])
 | 
			
		||||
if test "$enable_pwait" = yes; then
 | 
			
		||||
  AC_DEFINE([ENABLE_PWAIT], [1], [Enable pwait])
 | 
			
		||||
fi
 | 
			
		||||
AM_CONDITIONAL([BUILD_PWAIT], [test x$enable_pwait = xyes])
 | 
			
		||||
 | 
			
		||||
dnl watch8bit must be before the AC_ARG_WITH set as it sets up ncurses
 | 
			
		||||
AC_SUBST([WITH_WATCH8BIT])
 | 
			
		||||
AC_ARG_ENABLE([watch8bit],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								pgrep.1
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								pgrep.1
									
									
									
									
									
								
							@@ -9,13 +9,16 @@
 | 
			
		||||
.\"
 | 
			
		||||
.TH PGREP "1" "2020-06-04" "procps-ng" "User Commands"
 | 
			
		||||
.SH NAME
 | 
			
		||||
pgrep, pkill \- look up or signal processes based on name and other attributes
 | 
			
		||||
pgrep, pkill, pwait \- look up, signal, or wait for processes based on name and other attributes
 | 
			
		||||
.SH SYNOPSIS
 | 
			
		||||
.B pgrep
 | 
			
		||||
[options] pattern
 | 
			
		||||
.br
 | 
			
		||||
.B pkill
 | 
			
		||||
[options] pattern
 | 
			
		||||
.br
 | 
			
		||||
.B pwait
 | 
			
		||||
[options] pattern
 | 
			
		||||
.SH DESCRIPTION
 | 
			
		||||
.B pgrep
 | 
			
		||||
looks through the currently running processes and lists the process IDs which
 | 
			
		||||
@@ -41,6 +44,9 @@ OR
 | 
			
		||||
will send the specified signal (by default
 | 
			
		||||
.BR SIGTERM )
 | 
			
		||||
to each process instead of listing them on stdout.
 | 
			
		||||
.PP
 | 
			
		||||
.B pwait
 | 
			
		||||
will wait for each process instead of listing them on stdout.
 | 
			
		||||
.SH OPTIONS
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-\fR\fIsignal\fP
 | 
			
		||||
@@ -54,7 +60,9 @@ only.)
 | 
			
		||||
\fB\-c\fR, \fB\-\-count\fR
 | 
			
		||||
Suppress normal output; instead print a count of matching processes.  When
 | 
			
		||||
count does not match anything, e.g. returns zero, the command will return
 | 
			
		||||
non-zero value.
 | 
			
		||||
non-zero value. Note that for pkill and pwait, the count is the number of
 | 
			
		||||
matching processes, not the processes that were successfully signaled or waited
 | 
			
		||||
for.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-d\fR, \fB\-\-delimiter\fR \fIdelimiter\fP
 | 
			
		||||
Sets the string used to delimit each process ID in the output (by default a
 | 
			
		||||
@@ -77,9 +85,10 @@ is set, the full command line is used.
 | 
			
		||||
\fB\-g\fR, \fB\-\-pgroup\fR \fIpgrp\fP,...
 | 
			
		||||
Only match processes in the process group IDs listed.  Process group 0 is
 | 
			
		||||
translated into
 | 
			
		||||
.BR pgrep 's
 | 
			
		||||
.BR pgrep 's,
 | 
			
		||||
.BR pkill 's,
 | 
			
		||||
or
 | 
			
		||||
.BR pkill 's
 | 
			
		||||
.BR pwait 's
 | 
			
		||||
own process group.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-G\fR, \fB\-\-group\fR \fIgid\fP,...
 | 
			
		||||
@@ -114,9 +123,10 @@ Only match processes whose parent process ID is listed.
 | 
			
		||||
\fB\-s\fR, \fB\-\-session\fR \fIsid\fP,...
 | 
			
		||||
Only match processes whose process session ID is listed.  Session ID 0
 | 
			
		||||
is translated into
 | 
			
		||||
.BR pgrep 's
 | 
			
		||||
.BR pgrep 's,
 | 
			
		||||
.BR pkill 's,
 | 
			
		||||
or
 | 
			
		||||
.BR pkill 's
 | 
			
		||||
.BR pwait 's
 | 
			
		||||
own session ID.
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-t\fR, \fB\-\-terminal\fR \fIterm\fP,...
 | 
			
		||||
@@ -134,6 +144,8 @@ symbolical value may be used.
 | 
			
		||||
\fB\-v\fR, \fB\-\-inverse\fR\fR
 | 
			
		||||
Negates the matching.  This option is usually used in
 | 
			
		||||
.BR pgrep 's
 | 
			
		||||
or
 | 
			
		||||
.BR pwait 's
 | 
			
		||||
context.  In
 | 
			
		||||
.BR pkill 's
 | 
			
		||||
context the short option is disabled to avoid accidental usage of the option.
 | 
			
		||||
@@ -141,6 +153,8 @@ context the short option is disabled to avoid accidental usage of the option.
 | 
			
		||||
\fB\-w\fR, \fB\-\-lightweight\fR\fR
 | 
			
		||||
Shows all thread ids instead of pids in
 | 
			
		||||
.BR pgrep 's
 | 
			
		||||
or
 | 
			
		||||
.BR pwait 's
 | 
			
		||||
context.  In
 | 
			
		||||
.BR pkill 's
 | 
			
		||||
context this option is disabled.
 | 
			
		||||
@@ -152,8 +166,8 @@ match the
 | 
			
		||||
.IR pattern .
 | 
			
		||||
.TP
 | 
			
		||||
\fB\-F\fR, \fB\-\-pidfile\fR \fIfile\fR
 | 
			
		||||
Read \fIPID\fRs from \fIfile\fR.  This option is perhaps more useful for
 | 
			
		||||
.B pkill
 | 
			
		||||
Read \fIPID\fRs from \fIfile\fR.  This option is more useful for
 | 
			
		||||
.BR pkill or pwait
 | 
			
		||||
than
 | 
			
		||||
.BR pgrep .
 | 
			
		||||
.TP
 | 
			
		||||
@@ -223,8 +237,8 @@ $ renice +4 $(pgrep chrome)
 | 
			
		||||
.PD 0
 | 
			
		||||
.TP
 | 
			
		||||
0
 | 
			
		||||
One or more processes matched the criteria. For pkill the process must also
 | 
			
		||||
have been successfully signalled.
 | 
			
		||||
One or more processes matched the criteria. For pkill and pwait, one or more
 | 
			
		||||
processes must also have been successfully signalled or waited for.
 | 
			
		||||
.TP
 | 
			
		||||
1
 | 
			
		||||
No processes matched or none of them could be signalled.
 | 
			
		||||
@@ -242,9 +256,10 @@ complete command line, /proc/\fIpid\fP/cmdline. Threads may not have the
 | 
			
		||||
same process name as the parent process but will have the same command line.
 | 
			
		||||
.PP
 | 
			
		||||
The running
 | 
			
		||||
.B pgrep
 | 
			
		||||
.BR pgrep ,
 | 
			
		||||
.BR pkill ,
 | 
			
		||||
or
 | 
			
		||||
.B pkill
 | 
			
		||||
.B pwait
 | 
			
		||||
process will never report itself as a
 | 
			
		||||
match.
 | 
			
		||||
.SH BUGS
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										112
									
								
								pgrep.c
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								pgrep.c
									
									
									
									
									
								
							@@ -38,6 +38,11 @@
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
#if defined(ENABLE_PWAIT) && !defined(HAVE_PIDFD_OPEN)
 | 
			
		||||
#include <sys/epoll.h>
 | 
			
		||||
#include <sys/syscall.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* EXIT_SUCCESS is 0 */
 | 
			
		||||
/* EXIT_FAILURE is 1 */
 | 
			
		||||
#define EXIT_USAGE 2
 | 
			
		||||
@@ -80,7 +85,13 @@ enum rel_items {
 | 
			
		||||
	(x) = (x) * 5 / 4 + 4; \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
static int i_am_pkill = 0;
 | 
			
		||||
static enum {
 | 
			
		||||
    PGREP = 0,
 | 
			
		||||
    PKILL,
 | 
			
		||||
#ifdef ENABLE_PWAIT
 | 
			
		||||
    PWAIT,
 | 
			
		||||
#endif
 | 
			
		||||
} prog_mode;
 | 
			
		||||
 | 
			
		||||
struct el {
 | 
			
		||||
    long    num;
 | 
			
		||||
@@ -132,17 +143,23 @@ static int __attribute__ ((__noreturn__)) usage(int opt)
 | 
			
		||||
    fputs(USAGE_HEADER, fp);
 | 
			
		||||
    fprintf(fp, _(" %s [options] <pattern>\n"), program_invocation_short_name);
 | 
			
		||||
    fputs(USAGE_OPTIONS, fp);
 | 
			
		||||
    if (i_am_pkill == 0) {
 | 
			
		||||
    switch (prog_mode) {
 | 
			
		||||
    case PGREP:
 | 
			
		||||
        fputs(_(" -d, --delimiter <string>  specify output delimiter\n"),fp);
 | 
			
		||||
        fputs(_(" -l, --list-name           list PID and process name\n"),fp);
 | 
			
		||||
        fputs(_(" -a, --list-full           list PID and full command line\n"),fp);
 | 
			
		||||
        fputs(_(" -v, --inverse             negates the matching\n"),fp);
 | 
			
		||||
        fputs(_(" -w, --lightweight         list all TID\n"), fp);
 | 
			
		||||
    }
 | 
			
		||||
    if (i_am_pkill == 1) {
 | 
			
		||||
        break;
 | 
			
		||||
    case PKILL:
 | 
			
		||||
        fputs(_(" -<sig>, --signal <sig>    signal to send (either number or name)\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);
 | 
			
		||||
#ifdef ENABLE_PWAIT
 | 
			
		||||
    case PWAIT:
 | 
			
		||||
        fputs(_(" -e, --echo                display PIDs before waiting\n"), fp);
 | 
			
		||||
        break;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    fputs(_(" -c, --count               count of matching processes\n"), fp);
 | 
			
		||||
    fputs(_(" -f, --full                use full process name to match\n"), fp);
 | 
			
		||||
@@ -676,6 +693,13 @@ static int signal_option(int *argc, char **argv)
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(ENABLE_PWAIT) && !defined(HAVE_PIDFD_OPEN)
 | 
			
		||||
static int pidfd_open (pid_t pid, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	return syscall(__NR_pidfd_open, pid, flags);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void parse_opts (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    char opts[64] = "";
 | 
			
		||||
@@ -720,17 +744,22 @@ static void parse_opts (int argc, char **argv)
 | 
			
		||||
        {NULL, 0, NULL, 0}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (strstr (program_invocation_short_name, "pkill")) {
 | 
			
		||||
#ifdef ENABLE_PWAIT
 | 
			
		||||
    if (strcmp (program_invocation_short_name, "pwait") == 0) {
 | 
			
		||||
        prog_mode = PWAIT;
 | 
			
		||||
        strcat (opts, "e");
 | 
			
		||||
    } else
 | 
			
		||||
#endif
 | 
			
		||||
    if (strcmp (program_invocation_short_name, "pkill") == 0) {
 | 
			
		||||
        int sig;
 | 
			
		||||
        i_am_pkill = 1;
 | 
			
		||||
        prog_mode = PKILL;
 | 
			
		||||
        sig = signal_option(&argc, argv);
 | 
			
		||||
        if (-1 < sig)
 | 
			
		||||
            opt_signal = sig;
 | 
			
		||||
        /* These options are for pkill only */
 | 
			
		||||
	strcat (opts, "eq:");
 | 
			
		||||
    } else {
 | 
			
		||||
        /* These options are for pgrep only */
 | 
			
		||||
        strcat (opts, "lad:vw");
 | 
			
		||||
        prog_mode = PGREP;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    strcat (opts, "LF:cfinoxP:O:g:s:u:U:G:t:r:?Vh");
 | 
			
		||||
@@ -868,9 +897,6 @@ static void parse_opts (int argc, char **argv)
 | 
			
		||||
        case NS_OPTION:
 | 
			
		||||
            opt_ns_pid = atoi(optarg);
 | 
			
		||||
            if (opt_ns_pid == 0)
 | 
			
		||||
                usage ('?');
 | 
			
		||||
            ++criteria_count;
 | 
			
		||||
            break;
 | 
			
		||||
		case 'r': /* match by runstate */
 | 
			
		||||
			opt_runstates = xstrdup (optarg);
 | 
			
		||||
			++criteria_count;
 | 
			
		||||
@@ -929,6 +955,14 @@ int main (int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
    struct el *procs;
 | 
			
		||||
    int num;
 | 
			
		||||
    int i;
 | 
			
		||||
    int kill_count = 0;
 | 
			
		||||
#ifdef ENABLE_PWAIT
 | 
			
		||||
    int poll_count = 0;
 | 
			
		||||
    int wait_count = 0;
 | 
			
		||||
    int epollfd = epoll_create(1);
 | 
			
		||||
    struct epoll_event ev, events[32];
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_PROGRAM_INVOCATION_NAME
 | 
			
		||||
    program_invocation_name = program_invocation_short_name;
 | 
			
		||||
@@ -941,9 +975,18 @@ int main (int argc, char **argv)
 | 
			
		||||
    parse_opts (argc, argv);
 | 
			
		||||
 | 
			
		||||
    procs = select_procs (&num);
 | 
			
		||||
    if (i_am_pkill) {
 | 
			
		||||
        int i;
 | 
			
		||||
        int kill_count = 0;
 | 
			
		||||
    switch (prog_mode) {
 | 
			
		||||
    case PGREP:
 | 
			
		||||
        if (opt_count) {
 | 
			
		||||
            fprintf(stdout, "%d\n", num);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (opt_long || opt_longlong)
 | 
			
		||||
                output_strlist (procs,num);
 | 
			
		||||
            else
 | 
			
		||||
                output_numlist (procs,num);
 | 
			
		||||
        }
 | 
			
		||||
        return !num;
 | 
			
		||||
    case PKILL:
 | 
			
		||||
        for (i = 0; i < num; i++) {
 | 
			
		||||
            if (execute_kill (procs[i].num, opt_signal) != -1) {
 | 
			
		||||
                if (opt_echo)
 | 
			
		||||
@@ -959,15 +1002,40 @@ int main (int argc, char **argv)
 | 
			
		||||
        if (opt_count)
 | 
			
		||||
            fprintf(stdout, "%d\n", num);
 | 
			
		||||
        return !kill_count;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (opt_count) {
 | 
			
		||||
#ifdef ENABLE_PWAIT
 | 
			
		||||
    case PWAIT:
 | 
			
		||||
        if (opt_count)
 | 
			
		||||
            fprintf(stdout, "%d\n", num);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (opt_long || opt_longlong)
 | 
			
		||||
                output_strlist (procs,num);
 | 
			
		||||
            else
 | 
			
		||||
                output_numlist (procs,num);
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < num; i++) {
 | 
			
		||||
            if (opt_echo)
 | 
			
		||||
                printf(_("waiting for %s (pid %lu)\n"), procs[i].str, procs[i].num);
 | 
			
		||||
            int pidfd = pidfd_open(procs[i].num, 0);
 | 
			
		||||
            if (pidfd == -1) {
 | 
			
		||||
                /* ignore ESRCH, same as pkill */
 | 
			
		||||
                if (errno != ESRCH)
 | 
			
		||||
                    xwarn(_("opening pid %ld failed"), procs[i].num);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            ev.events = EPOLLIN | EPOLLET;
 | 
			
		||||
            ev.data.fd = pidfd;
 | 
			
		||||
            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pidfd, &ev) != -1)
 | 
			
		||||
                poll_count++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while (wait_count < poll_count) {
 | 
			
		||||
            int ew = epoll_wait(epollfd, events, sizeof(events)/sizeof(events[0]), -1);
 | 
			
		||||
            if (ew == -1) {
 | 
			
		||||
                if (errno == EINTR)
 | 
			
		||||
                    continue;
 | 
			
		||||
                xwarn(_("epoll_wait failed"));
 | 
			
		||||
            }
 | 
			
		||||
            wait_count += ew;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return !wait_count;
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
    return !num; /* exit(EXIT_SUCCESS) if match, otherwise exit(EXIT_FAILURE) */
 | 
			
		||||
    /* Not sure if it is possible to get here */
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user