* Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
* Adapted for busybox David Kimdon <dwhedon@gordian.com>
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
/*
[TODO: can PROCESS_NAME be a full pathname? Should we require full match then
with /proc/$PID/exe or argv[0] (comm can't be matched, it never contains path)]
-x,--exec EXECUTABLE Look for processes that were started with this
- command in /proc/$PID/cmdline.
+ command in /proc/$PID/exe and /proc/$PID/cmdline
+ (/proc/$PID/cmdline is a bbox extension)
Unlike -n, we match against the full path:
"ntpd" != "./ntpd" != "/path/to/ntpd"
-p,--pidfile PID_FILE Look for processes with PID from this file
-q,--quiet Quiet
-v,--verbose Verbose
*/
+//config:config START_STOP_DAEMON
+//config: bool "start-stop-daemon"
+//config: default y
+//config: help
+//config: start-stop-daemon is used to control the creation and
+//config: termination of system-level processes, usually the ones
+//config: started during the startup of the system.
+//config:
+//config:config FEATURE_START_STOP_DAEMON_LONG_OPTIONS
+//config: bool "Enable long options"
+//config: default y
+//config: depends on START_STOP_DAEMON && LONG_OPTS
+//config:
+//config:config FEATURE_START_STOP_DAEMON_FANCY
+//config: bool "Support additional arguments"
+//config: default y
+//config: depends on START_STOP_DAEMON
+//config: help
+//config: -o|--oknodo ignored since we exit with 0 anyway
+//config: -v|--verbose
+//config: -N|--nicelevel N
+
+//applet:IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon))
+
+//kbuild:lib-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o
+
+//usage:#define start_stop_daemon_trivial_usage
+//usage: "[OPTIONS] [-S|-K] ... [-- ARGS...]"
+//usage:#define start_stop_daemon_full_usage "\n\n"
+//usage: "Search for matching processes, and then\n"
+//usage: "-K: stop all matching processes.\n"
+//usage: "-S: start a process unless a matching process is found.\n"
+//usage: IF_FEATURE_START_STOP_DAEMON_LONG_OPTIONS(
+//usage: "\nProcess matching:"
+//usage: "\n -u,--user USERNAME|UID Match only this user's processes"
+//usage: "\n -n,--name NAME Match processes with NAME"
+//usage: "\n in comm field in /proc/PID/stat"
+//usage: "\n -x,--exec EXECUTABLE Match processes with this command"
+//usage: "\n in /proc/PID/{exe,cmdline}"
+//usage: "\n -p,--pidfile FILE Match a process with PID from the file"
+//usage: "\n All specified conditions must match"
+//usage: "\n-S only:"
+//usage: "\n -x,--exec EXECUTABLE Program to run"
+//usage: "\n -a,--startas NAME Zeroth argument"
+//usage: "\n -b,--background Background"
+//usage: IF_FEATURE_START_STOP_DAEMON_FANCY(
+//usage: "\n -N,--nicelevel N Change nice level"
+//usage: )
+//usage: "\n -c,--chuid USER[:[GRP]] Change to user/group"
+//usage: "\n -m,--make-pidfile Write PID to the pidfile specified by -p"
+//usage: "\n-K only:"
+//usage: "\n -s,--signal SIG Signal to send"
+//usage: "\n -t,--test Match only, exit with 0 if a process is found"
+//usage: "\nOther:"
+//usage: IF_FEATURE_START_STOP_DAEMON_FANCY(
+//usage: "\n -o,--oknodo Exit with status 0 if nothing is done"
+//usage: "\n -v,--verbose Verbose"
+//usage: )
+//usage: "\n -q,--quiet Quiet"
+//usage: )
+//usage: IF_NOT_FEATURE_START_STOP_DAEMON_LONG_OPTIONS(
+//usage: "\nProcess matching:"
+//usage: "\n -u USERNAME|UID Match only this user's processes"
+//usage: "\n -n NAME Match processes with NAME"
+//usage: "\n in comm field in /proc/PID/stat"
+//usage: "\n -x EXECUTABLE Match processes with this command"
+//usage: "\n command in /proc/PID/cmdline"
+//usage: "\n -p FILE Match a process with PID from the file"
+//usage: "\n All specified conditions must match"
+//usage: "\n-S only:"
+//usage: "\n -x EXECUTABLE Program to run"
+//usage: "\n -a NAME Zeroth argument"
+//usage: "\n -b Background"
+//usage: IF_FEATURE_START_STOP_DAEMON_FANCY(
+//usage: "\n -N N Change nice level"
+//usage: )
+//usage: "\n -c USER[:[GRP]] Change to user/group"
+//usage: "\n -m Write PID to the pidfile specified by -p"
+//usage: "\n-K only:"
+//usage: "\n -s SIG Signal to send"
+//usage: "\n -t Match only, exit with 0 if a process is found"
+//usage: "\nOther:"
+//usage: IF_FEATURE_START_STOP_DAEMON_FANCY(
+//usage: "\n -o Exit with status 0 if nothing is done"
+//usage: "\n -v Verbose"
+//usage: )
+//usage: "\n -q Quiet"
+//usage: )
#include <sys/resource.h>
/* Override ENABLE_FEATURE_PIDFILE */
#define WANT_PIDFILE 1
#include "libbb.h"
+#include "common_bufsiz.h"
struct pid_list {
struct pid_list *next;
int user_id;
smallint signal_nr;
} FIX_ALIASING;
-#define G (*(struct globals*)&bb_common_bufsiz1)
+#define G (*(struct globals*)bb_common_bufsiz1)
#define userspec (G.userspec )
#define cmdname (G.cmdname )
#define execname (G.execname )
#define user_id (G.user_id )
#define signal_nr (G.signal_nr )
#define INIT_G() do { \
+ setup_common_bufsiz(); \
user_id = -1; \
signal_nr = 15; \
} while (0)
{
ssize_t bytes;
char buf[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
+ char *procname, *exelink;
+ int match;
- sprintf(buf, "/proc/%u/cmdline", (unsigned)pid);
+ procname = buf + sprintf(buf, "/proc/%u/exe", (unsigned)pid) - 3;
+
+ exelink = xmalloc_readlink(buf);
+ match = (exelink && strcmp(execname, exelink) == 0);
+ free(exelink);
+ if (match)
+ return match;
+
+ strcpy(procname, "cmdline");
bytes = open_read_close(buf, G.execname_cmpbuf, G.execname_sizeof);
if (bytes > 0) {
G.execname_cmpbuf[bytes] = '\0';
goto ret;
}
for (p = G.found_procs; p; p = p->next) {
- if (TEST || kill(p->pid, signal_nr) == 0) {
+ if (kill(p->pid, TEST ? 0 : signal_nr) == 0) {
killed++;
} else {
- p->pid = 0;
bb_perror_msg("warning: killing process %u", (unsigned)p->pid);
+ p->pid = 0;
+ if (TEST) {
+ /* Example: -K --test --pidfile PIDFILE detected
+ * that PIDFILE's pid doesn't exist */
+ killed = -1;
+ goto ret;
+ }
}
}
if (!QUIET && killed) {
*--argv = startas;
if (opt & OPT_BACKGROUND) {
#if BB_MMU
- bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS);
+ bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK);
/* DAEMON_DEVNULL_STDIO is superfluous -
* it's always done by bb_daemonize() */
#else
write_pidfile(pidfile);
}
if (opt & OPT_c) {
- struct bb_uidgid_t ugid = { -1, -1 };
+ struct bb_uidgid_t ugid;
parse_chown_usergroup_or_die(&ugid, chuid);
- if (ugid.gid != (gid_t) -1) xsetgid(ugid.gid);
- if (ugid.uid != (uid_t) -1) xsetuid(ugid.uid);
+ if (ugid.uid != (uid_t) -1L) {
+ struct passwd *pw = xgetpwuid(ugid.uid);
+ if (ugid.gid != (gid_t) -1L)
+ pw->pw_gid = ugid.gid;
+ /* initgroups, setgid, setuid: */
+ change_identity(pw);
+ } else if (ugid.gid != (gid_t) -1L) {
+ xsetgid(ugid.gid);
+ setgroups(1, &ugid.gid);
+ }
}
#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
if (opt & OPT_NICELEVEL) {