busybox/procps/pgrep.c
<<
>>
Prefs
   1/* 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 GPLv2 or later, see file LICENSE in this source tree.
   8 */
   9//config:config PGREP
  10//config:       bool "pgrep"
  11//config:       default y
  12//config:       help
  13//config:         Look for processes by name.
  14//config:
  15//config:config PKILL
  16//config:       bool "pkill"
  17//config:       default y
  18//config:       help
  19//config:         Send signals to processes by name.
  20
  21//applet:IF_PGREP(APPLET(pgrep, BB_DIR_USR_BIN, BB_SUID_DROP))
  22//applet:IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill))
  23
  24//kbuild:lib-$(CONFIG_PGREP) += pgrep.o
  25//kbuild:lib-$(CONFIG_PKILL) += pgrep.o
  26
  27//usage:#define pgrep_trivial_usage
  28//usage:       "[-flnovx] [-s SID|-P PPID|PATTERN]"
  29//usage:#define pgrep_full_usage "\n\n"
  30//usage:       "Display process(es) selected by regex PATTERN\n"
  31//usage:     "\n        -l      Show command name too"
  32//usage:     "\n        -f      Match against entire command line"
  33//usage:     "\n        -n      Show the newest process only"
  34//usage:     "\n        -o      Show the oldest process only"
  35//usage:     "\n        -v      Negate the match"
  36//usage:     "\n        -x      Match whole name (not substring)"
  37//usage:     "\n        -s      Match session ID (0 for current)"
  38//usage:     "\n        -P      Match parent process ID"
  39//usage:
  40//usage:#define pkill_trivial_usage
  41//usage:       "[-l|-SIGNAL] [-fnovx] [-s SID|-P PPID|PATTERN]"
  42//usage:#define pkill_full_usage "\n\n"
  43//usage:       "Send a signal to process(es) selected by regex PATTERN\n"
  44//usage:     "\n        -l      List all signals"
  45//usage:     "\n        -f      Match against entire command line"
  46//usage:     "\n        -n      Signal the newest process only"
  47//usage:     "\n        -o      Signal the oldest process only"
  48//usage:     "\n        -v      Negate the match"
  49//usage:     "\n        -x      Match whole name (not substring)"
  50//usage:     "\n        -s      Match session ID (0 for current)"
  51//usage:     "\n        -P      Match parent process ID"
  52
  53#include "libbb.h"
  54#include "xregex.h"
  55
  56/* Idea taken from kill.c */
  57#define pgrep (ENABLE_PGREP && applet_name[1] == 'g')
  58#define pkill (ENABLE_PKILL && applet_name[1] == 'k')
  59
  60enum {
  61        /* "vlfxons:P:" */
  62        OPTBIT_V = 0, /* must be first, we need OPT_INVERT = 0/1 */
  63        OPTBIT_L,
  64        OPTBIT_F,
  65        OPTBIT_X,
  66        OPTBIT_O,
  67        OPTBIT_N,
  68        OPTBIT_S,
  69        OPTBIT_P,
  70};
  71
  72#define OPT_INVERT      (opt & (1 << OPTBIT_V))
  73#define OPT_LIST        (opt & (1 << OPTBIT_L))
  74#define OPT_FULL        (opt & (1 << OPTBIT_F))
  75#define OPT_ANCHOR      (opt & (1 << OPTBIT_X))
  76#define OPT_FIRST       (opt & (1 << OPTBIT_O))
  77#define OPT_LAST        (opt & (1 << OPTBIT_N))
  78#define OPT_SID         (opt & (1 << OPTBIT_S))
  79#define OPT_PPID        (opt & (1 << OPTBIT_P))
  80
  81static void act(unsigned pid, char *cmd, int signo)
  82{
  83        if (pgrep) {
  84                if (option_mask32 & (1 << OPTBIT_L)) /* OPT_LIST */
  85                        printf("%u %s\n", pid, cmd);
  86                else
  87                        printf("%u\n", pid);
  88        } else
  89                kill(pid, signo);
  90}
  91
  92int pgrep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  93int pgrep_main(int argc UNUSED_PARAM, char **argv)
  94{
  95        unsigned pid;
  96        int signo;
  97        unsigned opt;
  98        int scan_mask;
  99        int matched_pid;
 100        int sid2match, ppid2match;
 101        char *cmd_last;
 102        procps_status_t *proc;
 103        /* These are initialized to 0 */
 104        struct {
 105                regex_t re_buffer;
 106                regmatch_t re_match[1];
 107        } Z;
 108#define re_buffer (Z.re_buffer)
 109#define re_match  (Z.re_match )
 110
 111        memset(&Z, 0, sizeof(Z));
 112
 113        /* Parse -SIGNAL for pkill. Must be first option, if present */
 114        signo = SIGTERM;
 115        if (pkill && argv[1] && argv[1][0] == '-') {
 116                int temp = get_signum(argv[1]+1);
 117                if (temp != -1) {
 118                        signo = temp;
 119                        argv++;
 120                }
 121        }
 122
 123        /* Parse remaining options */
 124        ppid2match = -1;
 125        sid2match = -1;
 126        opt = getopt32(argv, "vlfxons:+P:+", &sid2match, &ppid2match);
 127        argv += optind;
 128
 129        if (pkill && OPT_LIST) { /* -l: print the whole signal list */
 130                print_signames();
 131                return 0;
 132        }
 133
 134        pid = getpid();
 135        if (sid2match == 0)
 136                sid2match = getsid(pid);
 137
 138        scan_mask = PSSCAN_COMM | PSSCAN_ARGV0;
 139        if (OPT_FULL)
 140                scan_mask |= PSSCAN_ARGVN;
 141
 142        /* One pattern is required, if no -s and no -P */
 143        if ((sid2match & ppid2match) < 0 && (!argv[0] || argv[1]))
 144                bb_show_usage();
 145
 146        if (argv[0])
 147                xregcomp(&re_buffer, argv[0], OPT_ANCHOR ? REG_EXTENDED : (REG_EXTENDED|REG_NOSUB));
 148
 149        matched_pid = 0;
 150        cmd_last = NULL;
 151        proc = NULL;
 152        while ((proc = procps_scan(proc, scan_mask)) != NULL) {
 153                char *cmd;
 154
 155                if (proc->pid == pid)
 156                        continue;
 157
 158                cmd = proc->argv0;
 159                if (!cmd) {
 160                        cmd = proc->comm;
 161                } else {
 162                        int i = proc->argv_len;
 163                        while (--i >= 0) {
 164                                if ((unsigned char)cmd[i] < ' ')
 165                                        cmd[i] = ' ';
 166                        }
 167                }
 168
 169                if (ppid2match >= 0 && ppid2match != proc->ppid)
 170                        continue;
 171                if (sid2match >= 0 && sid2match != proc->sid)
 172                        continue;
 173
 174                /* NB: OPT_INVERT is always 0 or 1 */
 175                if (!argv[0]
 176                 || (regexec(&re_buffer, cmd, 1, re_match, 0) == 0 /* match found */
 177                    && (!OPT_ANCHOR || (re_match[0].rm_so == 0 && re_match[0].rm_eo == (regoff_t)strlen(cmd)))
 178                    ) ^ OPT_INVERT
 179                ) {
 180                        matched_pid = proc->pid;
 181                        if (OPT_LAST) {
 182                                free(cmd_last);
 183                                cmd_last = xstrdup(cmd);
 184                                continue;
 185                        }
 186                        act(proc->pid, cmd, signo);
 187                        if (OPT_FIRST)
 188                                break;
 189                }
 190        }
 191
 192        if (cmd_last) {
 193                act(matched_pid, cmd_last, signo);
 194                if (ENABLE_FEATURE_CLEAN_UP)
 195                        free(cmd_last);
 196        }
 197        return matched_pid == 0; /* return 1 if no processes listed/signaled */
 198}
 199