blob: 0e8e5294e8f3a9ada5aa5679b62c6cb4794b1787 [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
Denis Vlasenko72e1c892007-09-29 22:26:01 +000010#include "libbb.h"
11#include "xregex.h"
12
13/* Idea taken from kill.c */
14#define pgrep (ENABLE_PGREP && applet_name[1] == 'g')
15#define pkill (ENABLE_PKILL && applet_name[1] == 'k')
16
17enum {
18 /* "vlfxon" */
19 PGREPOPTBIT_V = 0, /* must be first, we need OPT_INVERT = 0/1 */
20 PGREPOPTBIT_L,
21 PGREPOPTBIT_F,
22 PGREPOPTBIT_X,
23 PGREPOPTBIT_O,
24 PGREPOPTBIT_N,
25};
26
27#define OPT_INVERT (opt & (1 << PGREPOPTBIT_V))
28#define OPT_LIST (opt & (1 << PGREPOPTBIT_L))
29#define OPT_FULL (opt & (1 << PGREPOPTBIT_F))
30#define OPT_ANCHOR (opt & (1 << PGREPOPTBIT_X))
31#define OPT_FIRST (opt & (1 << PGREPOPTBIT_O))
32#define OPT_LAST (opt & (1 << PGREPOPTBIT_N))
33
34static void act(unsigned pid, char *cmd, int signo, unsigned opt)
35{
36 if (pgrep) {
37 if (OPT_LIST)
38 printf("%d %s\n", pid, cmd);
39 else
40 printf("%d\n", pid);
41 } else
42 kill(pid, signo);
43}
44
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000045int pgrep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000046int pgrep_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko72e1c892007-09-29 22:26:01 +000047{
48 unsigned pid = getpid();
49 int signo = SIGTERM;
50 unsigned opt;
51 int scan_mask = PSSCAN_COMM;
52 char *first_arg;
53 int first_arg_idx;
54 int matched_pid;
55 char *cmd_last;
56 procps_status_t *proc;
57 /* These are initialized to 0 */
58 struct {
59 regex_t re_buffer;
60 regmatch_t re_match[1];
61 } Z;
62#define re_buffer (Z.re_buffer)
63#define re_match (Z.re_match )
64
65 memset(&Z, 0, sizeof(Z));
66
67 /* We must avoid interpreting -NUM (signal num) as an option */
68 first_arg_idx = 1;
69 while (1) {
70 first_arg = argv[first_arg_idx];
71 if (!first_arg)
72 break;
Denis Vlasenkocdf62772008-03-17 08:42:43 +000073 /* not "-<small_letter>..."? */
Denis Vlasenko72e1c892007-09-29 22:26:01 +000074 if (first_arg[0] != '-' || first_arg[1] < 'a' || first_arg[1] > 'z') {
Denis Vlasenkocdf62772008-03-17 08:42:43 +000075 argv[first_arg_idx] = NULL; /* terminate argv here */
Denis Vlasenko72e1c892007-09-29 22:26:01 +000076 break;
77 }
78 first_arg_idx++;
79 }
80 opt = getopt32(argv, "vlfxon");
81 argv[first_arg_idx] = first_arg;
82
83 argv += optind;
84 //argc -= optind; - unused anyway
85 if (OPT_FULL)
86 scan_mask |= PSSCAN_ARGVN;
87
88 if (pkill) {
Denis Vlasenkoa4f4de92007-09-30 16:32:01 +000089 if (OPT_LIST) { /* -l: print the whole signal list */
90 print_signames();
91 return 0;
92 }
Denis Vlasenko72e1c892007-09-29 22:26:01 +000093 if (first_arg && first_arg[0] == '-') {
94 signo = get_signum(&first_arg[1]);
95 if (signo < 0) /* || signo > MAX_SIGNUM ? */
96 bb_error_msg_and_die("bad signal name '%s'", &first_arg[1]);
97 argv++;
98 }
99 }
100
101 /* One pattern is required */
102 if (!argv[0] || argv[1])
103 bb_show_usage();
104
105 xregcomp(&re_buffer, argv[0], 0);
106 matched_pid = 0;
107 cmd_last = NULL;
108 proc = NULL;
109 while ((proc = procps_scan(proc, scan_mask)) != NULL) {
110 char *cmd;
111 if (proc->pid == pid)
112 continue;
113 cmd = proc->argv0;
Denis Vlasenko3b3ca112008-07-17 18:39:36 +0000114 if (!cmd) {
Denis Vlasenko72e1c892007-09-29 22:26:01 +0000115 cmd = proc->comm;
Denis Vlasenko3b3ca112008-07-17 18:39:36 +0000116 } else {
117 int i = proc->argv_len;
118 while (i) {
119 if (!cmd[i]) cmd[i] = ' ';
120 i--;
121 }
122 }
Denis Vlasenko72e1c892007-09-29 22:26:01 +0000123 /* NB: OPT_INVERT is always 0 or 1 */
124 if ((regexec(&re_buffer, cmd, 1, re_match, 0) == 0 /* match found */
Denis Vlasenko6b06cb82008-05-15 21:30:45 +0000125 && (!OPT_ANCHOR || (re_match[0].rm_so == 0 && re_match[0].rm_eo == (regoff_t)strlen(cmd)))) ^ OPT_INVERT
Denis Vlasenko72e1c892007-09-29 22:26:01 +0000126 ) {
127 matched_pid = proc->pid;
128 if (OPT_LAST) {
129 free(cmd_last);
Denis Vlasenko5fb09652007-09-30 16:36:02 +0000130 cmd_last = xstrdup(cmd);
Denis Vlasenko72e1c892007-09-29 22:26:01 +0000131 continue;
132 }
133 act(proc->pid, cmd, signo, opt);
134 if (OPT_FIRST)
135 break;
136 }
137 }
138 if (cmd_last) {
139 act(matched_pid, cmd_last, signo, opt);
140 if (ENABLE_FEATURE_CLEAN_UP)
141 free(cmd_last);
142 }
143 return matched_pid == 0; /* return 1 if no processes listed/signaled */
144}