pgrep,pkill: new applets by Loic Grenie <loic.grenie@gmail.com>

This commit is contained in:
Denis Vlasenko 2007-09-29 22:26:01 +00:00
parent 2450e4ba44
commit 72e1c89d97
9 changed files with 226 additions and 28 deletions

View File

@ -251,11 +251,13 @@ USE_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
USE_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
USE_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS)) USE_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
USE_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
USE_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
USE_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE)) USE_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE))
USE_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_PIPE_PROGRESS(APPLET_NOUSAGE(pipe_progress, pipe_progress, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_PIPE_PROGRESS(APPLET_NOUSAGE(pipe_progress, pipe_progress, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_NEVER))
USE_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER, pkill))
USE_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, poweroff)) USE_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, poweroff))
USE_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_PRINTF(APPLET(printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) USE_PRINTF(APPLET(printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER))

View File

@ -787,6 +787,7 @@ int bb_make_directory(char *path, long mode, int flags);
int get_signum(const char *name); int get_signum(const char *name);
const char *get_signame(int number); const char *get_signame(int number);
void print_signames_and_exit(void) ATTRIBUTE_NORETURN;
char *bb_simplify_path(const char *path); char *bb_simplify_path(const char *path);
@ -973,7 +974,8 @@ enum {
PSSCAN_UTIME = 1 << 13, PSSCAN_UTIME = 1 << 13,
PSSCAN_TTY = 1 << 14, PSSCAN_TTY = 1 << 14,
PSSCAN_SMAPS = (1 << 15) * ENABLE_FEATURE_TOPMEM, PSSCAN_SMAPS = (1 << 15) * ENABLE_FEATURE_TOPMEM,
USE_SELINUX(PSSCAN_CONTEXT = 1 << 16,) PSSCAN_ARGVN = (1 << 16) * (ENABLE_PGREP | ENABLE_PKILL),
USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,)
/* These are all retrieved from proc/NN/stat in one go: */ /* These are all retrieved from proc/NN/stat in one go: */
PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID
| PSSCAN_COMM | PSSCAN_STATE | PSSCAN_COMM | PSSCAN_STATE

View File

@ -2558,6 +2558,18 @@
"$ patch -p1 < example.diff\n" \ "$ patch -p1 < example.diff\n" \
"$ patch -p0 -i example.diff" "$ patch -p0 -i example.diff"
#define pgrep_trivial_usage \
"[-flnovx] pattern"
#define pgrep_full_usage \
"Display process(es) selected by regex pattern" \
"\n\nOptions:\n" \
" -l Show command name too\n" \
" -f Match against entire command line\n" \
" -n Signal the newest process only\n" \
" -o Signal the oldest process only\n" \
" -v Negate the matching\n" \
" -x Match whole name (not substring)"
#if (ENABLE_FEATURE_PIDOF_SINGLE || ENABLE_FEATURE_PIDOF_OMIT) #if (ENABLE_FEATURE_PIDOF_SINGLE || ENABLE_FEATURE_PIDOF_OMIT)
#define USAGE_PIDOF "Options:" #define USAGE_PIDOF "Options:"
#else #else
@ -2640,6 +2652,18 @@
"Move the current root file system to PUT_OLD and make NEW_ROOT\n" \ "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \
"the new root file system" "the new root file system"
#define pkill_trivial_usage \
"[-l] | [-fnovx] [-signal] pattern"
#define pkill_full_usage \
"Send a signal to process(es) selected by regex pattern" \
"\n\nOptions:\n" \
" -l List all signals\n" \
" -f Match against entire command line\n" \
" -n Signal the newest process only\n" \
" -o Signal the oldest process only\n" \
" -v Negate the matching\n" \
" -x Match whole name (not substring)"
#define poweroff_trivial_usage \ #define poweroff_trivial_usage \
"[-d delay] [-n] [-f]" "[-d delay] [-n] [-f]"
#define poweroff_full_usage \ #define poweroff_full_usage \

View File

@ -375,13 +375,22 @@ procps_status_t *procps_scan(procps_status_t* sp, int flags)
} }
} }
#else #else
if (flags & PSSCAN_ARGV0) { if (flags & *PSSCAN_ARGV0|PSSCAN_ARGVN)) {
free(sp->argv0); free(sp->argv0);
sp->argv0 = NULL; sp->argv0 = NULL;
strcpy(filename_tail, "/cmdline"); strcpy(filename_tail, "/cmdline");
n = read_to_buf(filename, buf); n = read_to_buf(filename, buf);
if (n <= 0) if (n <= 0)
break; break;
#if ENABLE_PGREP || ENABLE_PKILL
if (flags & PSSCAN_ARGVN) {
do {
n--;
if (buf[n] == '\0')
buf[n] = ' ';
} while (n);
}
#endif
sp->argv0 = xstrdup(buf); sp->argv0 = xstrdup(buf);
} }
#endif #endif

View File

@ -159,3 +159,18 @@ const char *get_signame(int number)
return itoa(number); return itoa(number);
} }
// Print the whole signal list
void print_signames_and_exit(void)
{
int signo;
for (signo = 1; signo < ARRAY_SIZE(signals); signo++) {
const char *name = signals[signo];
if (name[0])
puts(name);
}
exit(EXIT_SUCCESS);
}

View File

@ -49,6 +49,12 @@ config NMETER
help help
Prints selected system stats continuously, one line per update. Prints selected system stats continuously, one line per update.
config PGREP
bool "pgrep"
default n
help
Look for processes by name.
config PIDOF config PIDOF
bool "pidof" bool "pidof"
default n default n
@ -72,6 +78,12 @@ config FEATURE_PIDOF_OMIT
The special pid %PPID can be used to name the parent process The special pid %PPID can be used to name the parent process
of the pidof, in other words the calling shell or shell script. of the pidof, in other words the calling shell or shell script.
config PKILL
bool "pkill"
default n
help
Send signals to processes by name.
config PS config PS
bool "ps" bool "ps"
default n default n

View File

@ -10,6 +10,8 @@ lib-$(CONFIG_FUSER) += fuser.o
lib-$(CONFIG_KILL) += kill.o lib-$(CONFIG_KILL) += kill.o
lib-$(CONFIG_ASH) += kill.o # used for built-in kill by ash lib-$(CONFIG_ASH) += kill.o # used for built-in kill by ash
lib-$(CONFIG_NMETER) += nmeter.o lib-$(CONFIG_NMETER) += nmeter.o
lib-$(CONFIG_PGREP) += pgrep.o
lib-$(CONFIG_PKILL) += pgrep.o
lib-$(CONFIG_PIDOF) += pidof.o lib-$(CONFIG_PIDOF) += pidof.o
lib-$(CONFIG_PS) += ps.o lib-$(CONFIG_PS) += ps.o
lib-$(CONFIG_RENICE) += renice.o lib-$(CONFIG_RENICE) += renice.o

View File

@ -58,33 +58,29 @@ int kill_main(int argc, char **argv)
if (arg[1] == 'l' && arg[2] == '\0') { if (arg[1] == 'l' && arg[2] == '\0') {
if (argc == 1) { if (argc == 1) {
/* Print the whole signal list */ /* Print the whole signal list */
for (signo = 1; signo < 32; signo++) { print_signames_and_exit();
const char *name = get_signame(signo); }
if (!isdigit(name[0])) /* -l <sig list> */
puts(name); while ((arg = *++argv)) {
} if (isdigit(arg[0])) {
} else { /* -l <sig list> */ signo = bb_strtou(arg, NULL, 10);
while ((arg = *++argv)) { if (errno) {
if (isdigit(arg[0])) { bb_error_msg("unknown signal '%s'", arg);
signo = bb_strtou(arg, NULL, 10); return EXIT_FAILURE;
if (errno) {
bb_error_msg("unknown signal '%s'", arg);
return EXIT_FAILURE;
}
/* Exitcodes >= 0x80 are to be treated
* as "killed by signal (exitcode & 0x7f)" */
puts(get_signame(signo & 0x7f));
/* TODO: 'bad' signal# - coreutils says:
* kill: 127: invalid signal
* we just print "127" instead */
} else {
signo = get_signum(arg);
if (signo < 0) {
bb_error_msg("unknown signal '%s'", arg);
return EXIT_FAILURE;
}
printf("%d\n", signo);
} }
/* Exitcodes >= 0x80 are to be treated
* as "killed by signal (exitcode & 0x7f)" */
puts(get_signame(signo & 0x7f));
/* TODO: 'bad' signal# - coreutils says:
* kill: 127: invalid signal
* we just print "127" instead */
} else {
signo = get_signum(arg);
if (signo < 0) {
bb_error_msg("unknown signal '%s'", arg);
return EXIT_FAILURE;
}
printf("%d\n", signo);
} }
} }
/* If they specified -l, we are all done */ /* If they specified -l, we are all done */

136
procps/pgrep.c Normal file
View File

@ -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 */
}