diff --git a/src/librc/librc-daemon.c b/src/librc/librc-daemon.c index 7ea66faa..2622f383 100644 --- a/src/librc/librc-daemon.c +++ b/src/librc/librc-daemon.c @@ -58,7 +58,7 @@ static bool pid_is_cmd (pid_t pid, const char *cmd) return ((c == ')' && *cmd == '\0') ? true : false); } -static bool pid_is_exec (pid_t pid, const char *exec) +static bool pid_is_exec (pid_t pid, const char *const *argv) { char cmdline[32]; char buffer[PATH_MAX]; @@ -68,6 +68,7 @@ static bool pid_is_exec (pid_t pid, const char *exec) snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid); memset (buffer, 0, sizeof (buffer)); +#if 0 if (readlink (cmdline, buffer, sizeof (buffer)) != -1) { if (strcmp (exec, buffer) == 0) return (true); @@ -82,22 +83,32 @@ static bool pid_is_exec (pid_t pid, const char *exec) } } } +#endif snprintf (cmdline, sizeof (cmdline), "/proc/%u/cmdline", pid); if ((fd = open (cmdline, O_RDONLY)) < 0) return (false); - r = read(fd, buffer, sizeof (buffer)); + r = read (fd, buffer, sizeof (buffer)); close (fd); if (r == -1) return 0; buffer[r] = 0; - return (strcmp (exec, buffer) == 0 ? true : false); + p = buffer; + while (*argv) { + if (strcmp (*argv, p) != 0) + return (false); + argv++; + p += strlen (p) + 1; + if (p - buffer > (unsigned) sizeof (buffer)) + return (false); + } + return (true); } -pid_t *rc_find_pids (const char *exec, const char *cmd, +pid_t *rc_find_pids (const char *const *argv, const char *cmd, uid_t uid, pid_t pid) { DIR *procdir; @@ -149,7 +160,7 @@ pid_t *rc_find_pids (const char *exec, const char *cmd, if (cmd && ! pid_is_cmd (p, cmd)) continue; - if (exec && ! cmd && ! pid_is_exec (p, exec)) + if (argv && ! cmd && ! pid_is_exec (p, (const char *const *)argv)) continue; tmp = realloc (pids, sizeof (pid_t) * (npids + 2)); @@ -193,7 +204,7 @@ librc_hidden_def(rc_find_pids) # define _KVM_PATH NULL # endif -pid_t *rc_find_pids (const char *exec, const char *cmd, +pid_t *rc_find_pids (const char *const *argv, const char *cmd, uid_t uid, pid_t pid) { static kvm_t *kd = NULL; @@ -201,11 +212,13 @@ pid_t *rc_find_pids (const char *exec, const char *cmd, struct _KINFO_PROC *kp; int i; int processes = 0; - int argc = 0; - char **argv; + int pargc = 0; + char **pargv; pid_t *pids = NULL; pid_t *tmp; + char *arg; int npids = 0; + int match; if ((kd = kvm_openfiles (_KVM_PATH, _KVM_PATH, NULL, O_RDONLY, errbuf)) == NULL) @@ -239,11 +252,21 @@ pid_t *rc_find_pids (const char *exec, const char *cmd, continue; } - if (exec && ! cmd) { - if ((argv = _KVM_GETARGV (kd, &kp[i], argc)) == NULL || ! *argv) + if (argv && ! cmd) { + pargv = _KVM_GETARGV (kd, &kp[i], pargc); + if (! pargv || ! *pargv) continue; - if (strcmp (*argv, exec) != 0) + arg = argv; + match = 1; + + while (arg && *pargv) + if (strcmp (arg++, *pargv++) != 0) { + match = 0; + break; + } + + if (! match) continue; } @@ -312,7 +335,7 @@ static bool _match_daemon (const char *path, const char *file, return (m == 111 ? true : false); } -bool rc_service_daemon_set (const char *service, const char *exec, +bool rc_service_daemon_set (const char *service, const char *const *argv, const char *name, const char *pidfile, bool started) { @@ -328,7 +351,7 @@ bool rc_service_daemon_set (const char *service, const char *exec, DIR *dp; struct dirent *d; - if (! exec && ! name && ! pidfile) { + if (! argv && ! name && ! pidfile) { errno = EINVAL; return (false); } @@ -336,10 +359,10 @@ bool rc_service_daemon_set (const char *service, const char *exec, dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", basename_c (service), (char *) NULL); - if (exec) { - l = strlen (exec) + 6; + if (argv) { + l = strlen (*argv) + 6; mexec = xmalloc (sizeof (char) * l); - snprintf (mexec, l, "exec=%s", exec); + snprintf (mexec, l, "exec=%s", *argv); } else mexec = xstrdup ("exec="); @@ -464,6 +487,7 @@ bool rc_service_daemons_crashed (const char *service) char *path; FILE *fp; char *line; + char **argv = NULL; char *exec = NULL; char *name = NULL; char *pidfile = NULL; @@ -506,7 +530,9 @@ bool rc_service_daemons_crashed (const char *service) continue; } - if (strcmp (token, "exec") == 0) { + if (strcmp (token, "argv") == 0) { + rc_strlist_add (&argv, p); + } else if (strcmp (token, "exec") == 0) { if (exec) free (exec); exec = xstrdup (p); @@ -546,24 +572,35 @@ bool rc_service_daemons_crashed (const char *service) pidfile = NULL; /* We have the pid, so no need to match on name */ + rc_strlist_free (argv); + argv = NULL; free (exec); exec = NULL; free (name); name = NULL; } - if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL) { + if (exec && ! argv) { + rc_strlist_add (&argv, exec); + free (exec); + exec = NULL; + } + + if ((pids = rc_find_pids ((const char *const *)argv, name, 0, pid)) == NULL) { retval = true; break; } free (pids); + rc_strlist_free (argv); + argv = NULL; free (exec); exec = NULL; free (name); name = NULL; } + rc_strlist_free (argv); free (exec); free (name); free (dirpath); diff --git a/src/librc/rc.h b/src/librc/rc.h index 726d7f98..1f1a9a76 100644 --- a/src/librc/rc.h +++ b/src/librc/rc.h @@ -117,7 +117,7 @@ bool rc_service_delete (const char *runlevel, const char *service); * @param name of the process (optional) * @param pidfile of the process (optional) * @param started if true, add the arguments otherwise remove existing matching arguments */ -bool rc_service_daemon_set (const char *service, const char *exec, +bool rc_service_daemon_set (const char *service, const char *const *argv, const char *name, const char *pidfile, bool started); @@ -445,7 +445,7 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...) SENTINEL; * @param uid to check for * @param pid to check for * @return NULL terminated list of pids */ -pid_t *rc_find_pids (const char *exec, const char *cmd, +pid_t *rc_find_pids (const char *const *argv, const char *cmd, uid_t uid, pid_t pid); #endif diff --git a/src/rc/start-stop-daemon.c b/src/rc/start-stop-daemon.c index abd7f13a..d523b7c0 100644 --- a/src/rc/start-stop-daemon.c +++ b/src/rc/start-stop-daemon.c @@ -305,7 +305,7 @@ static pid_t get_pid (const char *pidfile, bool quiet) } /* return number of processed killed, -1 on error */ -static int do_stop (const char *exec, const char *cmd, +static int do_stop (const char *const *argv, const char *cmd, const char *pidfile, uid_t uid,int sig, bool quiet, bool verbose, bool test) { @@ -320,7 +320,7 @@ static int do_stop (const char *exec, const char *cmd, return (quiet ? 0 : -1); pids = rc_find_pids (NULL, NULL, 0, pid); } else - pids = rc_find_pids (exec, cmd, uid, pid); + pids = rc_find_pids (argv, cmd, uid, pid); if (! pids) return (0); @@ -352,7 +352,7 @@ static int do_stop (const char *exec, const char *cmd, return (nkilled); } -static int run_stop_schedule (const char *exec, const char *cmd, +static int run_stop_schedule (const char *const *argv, const char *cmd, const char *pidfile, uid_t uid, bool quiet, bool verbose, bool test) { @@ -368,8 +368,8 @@ static int run_stop_schedule (const char *exec, const char *cmd, einfo ("Will stop PID in pidfile `%s'", pidfile); if (uid) einfo ("Will stop processes owned by UID %d", uid); - if (exec) - einfo ("Will stop processes of `%s'", exec); + if (argv) + einfo ("Will stop processes of `%s'", *argv); if (cmd) einfo ("Will stop processes called `%s'", cmd); } @@ -382,7 +382,7 @@ static int run_stop_schedule (const char *exec, const char *cmd, case schedule_signal: nrunning = 0; - nkilled = do_stop (exec, cmd, pidfile, uid, item->value, + nkilled = do_stop (argv, cmd, pidfile, uid, item->value, quiet, verbose, test); if (nkilled == 0) { if (tkilled == 0) { @@ -407,7 +407,7 @@ static int run_stop_schedule (const char *exec, const char *cmd, ts.tv_nsec = POLL_INTERVAL; while (nloops) { - if ((nrunning = do_stop (exec, cmd, pidfile, + if ((nrunning = do_stop (argv, cmd, pidfile, uid, 0, true, false, true)) == 0) return (true); @@ -496,6 +496,7 @@ static const struct option longopts[] = { { "background", 0, NULL, 'b'}, { "chuid", 1, NULL, 'c'}, { "chdir", 1, NULL, 'd'}, + { "env", 1, NULL, 'e'}, { "group", 1, NULL, 'g'}, { "make-pidfile", 0, NULL, 'm'}, { "name", 1, NULL, 'n'}, @@ -519,6 +520,7 @@ static const char * const longopts_help[] = { "Force daemon to background", "deprecated, use --user", "Change the PWD", + "Set an environment string", "Change the process group", "Create a pidfile", "Match process name", @@ -574,6 +576,8 @@ int start_stop_daemon (int argc, char **argv) int i; char *svcname = getenv ("SVCNAME"); char *env; + bool sethome = false; + bool setuser = false; atexit (cleanup); @@ -585,7 +589,7 @@ int start_stop_daemon (int argc, char **argv) if (sscanf (env, "%d", &nicelevel) != 1) eerror ("%s: invalid nice level `%s' (SSD_NICELEVEL)", applet, env); - while ((opt = getopt_long (argc, argv, getoptstring, longopts, + while ((opt = getopt_long (argc, argv, "e:" getoptstring, longopts, (int *) 0)) != -1) switch (opt) { case 'K': /* --stop */ @@ -648,6 +652,15 @@ int start_stop_daemon (int argc, char **argv) ch_dir = optarg; break; + case 'e': /* --env */ + if (putenv (optarg) == 0) { + if (strncmp ("HOME=", optarg, 5) == 0) + sethome = true; + else if (strncmp ("USER=", optarg, 5) == 0) + setuser = true; + } + break; + case 'g': /* --group | */ { struct group *gr = getgrnam (optarg); @@ -761,6 +774,9 @@ int start_stop_daemon (int argc, char **argv) free (tmp); } + /* Add exec to our arguments */ + *--argv = exec; + if (stop) { int result; @@ -771,7 +787,8 @@ int start_stop_daemon (int argc, char **argv) parse_schedule (NULL, sig); } - result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test); + result = run_stop_schedule ((const char *const *)argv, cmd, + pidfile, uid, quiet, verbose, test); if (test || oknodo) return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE); if (result < 1) @@ -781,21 +798,24 @@ int start_stop_daemon (int argc, char **argv) unlink (pidfile); if (svcname) - rc_service_daemon_set (svcname, exec, cmd, pidfile, false); + rc_service_daemon_set (svcname, + (const char *const *)argv, + cmd, pidfile, false); exit (EXIT_SUCCESS); } - if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) + if (do_stop ((const char * const *)argv, cmd, pidfile, uid, + 0, true, false, true) > 0) eerrorx ("%s: %s is already running", applet, exec); if (test) { if (quiet) exit (EXIT_SUCCESS); - einfon ("Would start %s", exec); - while (argc-- > 0) - printf("%s ", *argv++); + einfon ("Would start"); + while (argc-- >= 0) + printf(" %s", *argv++); printf ("\n"); eindent (); if (uid != 0) @@ -824,7 +844,6 @@ int start_stop_daemon (int argc, char **argv) if (background) signal_setup (SIGCHLD, handle_signal); - *--argv = exec; if ((pid = fork ()) == -1) eerrorx ("%s: fork: %s", applet, strerror (errno)); @@ -884,12 +903,16 @@ int start_stop_daemon (int argc, char **argv) else { struct passwd *passwd = getpwuid (uid); if (passwd) { - unsetenv ("HOME"); - if (passwd->pw_dir) - setenv ("HOME", passwd->pw_dir, 1); - unsetenv ("USER"); - if (passwd->pw_name) - setenv ("USER", passwd->pw_name, 1); + if (! sethome) { + unsetenv ("HOME"); + if (passwd->pw_dir) + setenv ("HOME", passwd->pw_dir, 1); + } + if (! setuser) { + unsetenv ("USER"); + if (passwd->pw_name) + setenv ("USER", passwd->pw_name, 1); + } } } @@ -1056,7 +1079,8 @@ int start_stop_daemon (int argc, char **argv) } else nloopsp = 0; } - if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) + if (do_stop ((const char *const *)argv, cmd, + pidfile, uid, 0, true, false, true) > 0) alive = true; } @@ -1066,7 +1090,7 @@ int start_stop_daemon (int argc, char **argv) } if (svcname) - rc_service_daemon_set (svcname, exec, cmd, pidfile, true); + rc_service_daemon_set (svcname, (const char *const *)argv, cmd, pidfile, true); exit (EXIT_SUCCESS); /* NOTREACHED */