blob: 2ebcca1c01f4b546c1fd54aa64f722963eb90b73 [file] [log] [blame]
Denis Vlasenko72e1c892007-09-29 22:26:01 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Mini pgrep/pkill implementation for busybox
4 *
5 * Copyright (C) 2007 Loic Grenie <loic.grenie@gmail.com>
6 *
7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8 */
9
10#include <getopt.h>
11
12#include "libbb.h"
13#include "xregex.h"
14
15/* Idea taken from kill.c */
16#define pgrep (ENABLE_PGREP && applet_name[1] == 'g')
17#define pkill (ENABLE_PKILL && applet_name[1] == 'k')
18
19enum {
20 /* "vlfxon" */
21 PGREPOPTBIT_V = 0, /* must be first, we need OPT_INVERT = 0/1 */
22 PGREPOPTBIT_L,
23 PGREPOPTBIT_F,
24 PGREPOPTBIT_X,
25 PGREPOPTBIT_O,
26 PGREPOPTBIT_N,
27};
28
29#define OPT_INVERT (opt & (1 << PGREPOPTBIT_V))
30#define OPT_LIST (opt & (1 << PGREPOPTBIT_L))
31#define OPT_FULL (opt & (1 << PGREPOPTBIT_F))
32#define OPT_ANCHOR (opt & (1 << PGREPOPTBIT_X))
33#define OPT_FIRST (opt & (1 << PGREPOPTBIT_O))
34#define OPT_LAST (opt & (1 << PGREPOPTBIT_N))
35
36static void act(unsigned pid, char *cmd, int signo, unsigned opt)
37{
38 if (pgrep) {
39 if (OPT_LIST)
40 printf("%d %s\n", pid, cmd);
41 else
42 printf("%d\n", pid);
43 } else
44 kill(pid, signo);
45}
46
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000047int pgrep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko72e1c892007-09-29 22:26:01 +000048int pgrep_main(int argc, char **argv)
49{
50 unsigned pid = getpid();
51 int signo = SIGTERM;
52 unsigned opt;
53 int scan_mask = PSSCAN_COMM;
54 char *first_arg;
55 int first_arg_idx;
56 int matched_pid;
57 char *cmd_last;
58 procps_status_t *proc;
59 /* These are initialized to 0 */
60 struct {
61 regex_t re_buffer;
62 regmatch_t re_match[1];
63 } Z;
64#define re_buffer (Z.re_buffer)
65#define re_match (Z.re_match )
66
67 memset(&Z, 0, sizeof(Z));
68
69 /* We must avoid interpreting -NUM (signal num) as an option */
70 first_arg_idx = 1;
71 while (1) {
72 first_arg = argv[first_arg_idx];
73 if (!first_arg)
74 break;
75 if (first_arg[0] != '-' || first_arg[1] < 'a' || first_arg[1] > 'z') {
76 argv[first_arg_idx] = NULL;
77 break;
78 }
79 first_arg_idx++;
80 }
81 opt = getopt32(argv, "vlfxon");
82 argv[first_arg_idx] = first_arg;
83
84 argv += optind;
85 //argc -= optind; - unused anyway
86 if (OPT_FULL)
87 scan_mask |= PSSCAN_ARGVN;
88
89 if (pkill) {
Denis Vlasenkoa4f4de92007-09-30 16:32:01 +000090 if (OPT_LIST) { /* -l: print the whole signal list */
91 print_signames();
92 return 0;
93 }
Denis Vlasenko72e1c892007-09-29 22:26:01 +000094 if (first_arg && first_arg[0] == '-') {
95 signo = get_signum(&first_arg[1]);
96 if (signo < 0) /* || signo > MAX_SIGNUM ? */
97 bb_error_msg_and_die("bad signal name '%s'", &first_arg[1]);
98 argv++;
99 }
100 }
101
102 /* One pattern is required */
103 if (!argv[0] || argv[1])
104 bb_show_usage();
105
106 xregcomp(&re_buffer, argv[0], 0);
107 matched_pid = 0;
108 cmd_last = NULL;
109 proc = NULL;
110 while ((proc = procps_scan(proc, scan_mask)) != NULL) {
111 char *cmd;
112 if (proc->pid == pid)
113 continue;
114 cmd = proc->argv0;
115 if (!cmd)
116 cmd = proc->comm;
117 /* NB: OPT_INVERT is always 0 or 1 */
118 if ((regexec(&re_buffer, cmd, 1, re_match, 0) == 0 /* match found */
Denis Vlasenko6b404432008-01-07 16:13:14 +0000119 && (!OPT_ANCHOR || (re_match[0].rm_so == 0 && re_match[0].rm_eo == strlen(cmd)))) ^ OPT_INVERT
Denis Vlasenko72e1c892007-09-29 22:26:01 +0000120 ) {
121 matched_pid = proc->pid;
122 if (OPT_LAST) {
123 free(cmd_last);
Denis Vlasenko5fb09652007-09-30 16:36:02 +0000124 cmd_last = xstrdup(cmd);
Denis Vlasenko72e1c892007-09-29 22:26:01 +0000125 continue;
126 }
127 act(proc->pid, cmd, signo, opt);
128 if (OPT_FIRST)
129 break;
130 }
131 }
132 if (cmd_last) {
133 act(matched_pid, cmd_last, signo, opt);
134 if (ENABLE_FEATURE_CLEAN_UP)
135 free(cmd_last);
136 }
137 return matched_pid == 0; /* return 1 if no processes listed/signaled */
138}