[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
-v,--verbose Verbose
*/
+//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 */
{
ssize_t bytes;
char buf[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
+ char *procname, *exelink;
+ int match;
+
+ 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;
- sprintf(buf, "/proc/%u/cmdline", (unsigned)pid);
+ 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
if (opt & OPT_c) {
struct bb_uidgid_t ugid = { -1, -1 };
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) -1) {
+ struct passwd *pw = xgetpwuid(ugid.uid);
+ if (ugid.gid != (gid_t) -1)
+ pw->pw_gid = ugid.gid;
+ /* initgroups, setgid, setuid: */
+ change_identity(pw);
+ } else if (ugid.gid != (gid_t) -1) {
+ xsetgid(ugid.gid);
+ setgroups(1, &ugid.gid);
+ }
}
#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
if (opt & OPT_NICELEVEL) {