diff options
Diffstat (limited to 'procps/pgrep.c')
-rw-r--r-- | procps/pgrep.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/procps/pgrep.c b/procps/pgrep.c new file mode 100644 index 000000000..3bf087f28 --- /dev/null +++ b/procps/pgrep.c @@ -0,0 +1,136 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini pgrep/pkill implementation for busybox + * + * Copyright (C) 2007 Loic Grenie <loic.grenie@gmail.com> + * + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + */ + +#include <getopt.h> + +#include "libbb.h" +#include "xregex.h" + +/* Idea taken from kill.c */ +#define pgrep (ENABLE_PGREP && applet_name[1] == 'g') +#define pkill (ENABLE_PKILL && applet_name[1] == 'k') + +enum { + /* "vlfxon" */ + PGREPOPTBIT_V = 0, /* must be first, we need OPT_INVERT = 0/1 */ + PGREPOPTBIT_L, + PGREPOPTBIT_F, + PGREPOPTBIT_X, + PGREPOPTBIT_O, + PGREPOPTBIT_N, +}; + +#define OPT_INVERT (opt & (1 << PGREPOPTBIT_V)) +#define OPT_LIST (opt & (1 << PGREPOPTBIT_L)) +#define OPT_FULL (opt & (1 << PGREPOPTBIT_F)) +#define OPT_ANCHOR (opt & (1 << PGREPOPTBIT_X)) +#define OPT_FIRST (opt & (1 << PGREPOPTBIT_O)) +#define OPT_LAST (opt & (1 << PGREPOPTBIT_N)) + +static void act(unsigned pid, char *cmd, int signo, unsigned opt) +{ + if (pgrep) { + if (OPT_LIST) + printf("%d %s\n", pid, cmd); + else + printf("%d\n", pid); + } else + kill(pid, signo); +} + +int pgrep_main(int argc, char **argv); +int pgrep_main(int argc, char **argv) +{ + unsigned pid = getpid(); + int signo = SIGTERM; + unsigned opt; + int scan_mask = PSSCAN_COMM; + char *first_arg; + int first_arg_idx; + int matched_pid; + char *cmd_last; + procps_status_t *proc; + /* These are initialized to 0 */ + struct { + regex_t re_buffer; + regmatch_t re_match[1]; + } Z; +#define re_buffer (Z.re_buffer) +#define re_match (Z.re_match ) + + memset(&Z, 0, sizeof(Z)); + + /* We must avoid interpreting -NUM (signal num) as an option */ + first_arg_idx = 1; + while (1) { + first_arg = argv[first_arg_idx]; + if (!first_arg) + break; + if (first_arg[0] != '-' || first_arg[1] < 'a' || first_arg[1] > 'z') { + argv[first_arg_idx] = NULL; + break; + } + first_arg_idx++; + } + opt = getopt32(argv, "vlfxon"); + argv[first_arg_idx] = first_arg; + + argv += optind; + //argc -= optind; - unused anyway + if (OPT_FULL) + scan_mask |= PSSCAN_ARGVN; + + if (pkill) { + if (OPT_LIST) /* -l: print the whole signal list */ + print_signames_and_exit(); + if (first_arg && first_arg[0] == '-') { + signo = get_signum(&first_arg[1]); + if (signo < 0) /* || signo > MAX_SIGNUM ? */ + bb_error_msg_and_die("bad signal name '%s'", &first_arg[1]); + argv++; + } + } + + /* One pattern is required */ + if (!argv[0] || argv[1]) + bb_show_usage(); + + xregcomp(&re_buffer, argv[0], 0); + matched_pid = 0; + cmd_last = NULL; + proc = NULL; + while ((proc = procps_scan(proc, scan_mask)) != NULL) { + char *cmd; + if (proc->pid == pid) + continue; + cmd = proc->argv0; + if (!cmd) + cmd = proc->comm; + /* NB: OPT_INVERT is always 0 or 1 */ + if ((regexec(&re_buffer, cmd, 1, re_match, 0) == 0 /* match found */ + && (!OPT_ANCHOR || (re_match[0].rm_so == 0 && re_match[0].rm_eo == strlen(cmd)))) ^ OPT_INVERT + ) { + matched_pid = proc->pid; + if (OPT_LAST) { + free(cmd_last); + cmd_last = xstrdup(cmd_last); + continue; + } + act(proc->pid, cmd, signo, opt); + if (OPT_FIRST) + break; + } + } + if (cmd_last) { + act(matched_pid, cmd_last, signo, opt); + if (ENABLE_FEATURE_CLEAN_UP) + free(cmd_last); + } + return matched_pid == 0; /* return 1 if no processes listed/signaled */ +} |