From cea206014d80e61e16f53a6c61577d063a7b75b8 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Sun, 27 Jul 2008 11:30:49 +0000 Subject: [PATCH] Attempt to make s-s-d simpler by not enforcing the need for a full path and maybe working better with interpreted scripts. --- man/start-stop-daemon.8 | 15 +- src/librc/librc-daemon.c | 134 ++++++++-------- src/librc/rc.h.in | 10 +- src/rc/Makefile | 5 +- src/rc/rc-applets.c | 14 +- src/rc/start-stop-daemon.c | 311 +++++++++++++++++++------------------ 6 files changed, 251 insertions(+), 238 deletions(-) diff --git a/man/start-stop-daemon.8 b/man/start-stop-daemon.8 index 00ef29f9..33a9ceeb 100644 --- a/man/start-stop-daemon.8 +++ b/man/start-stop-daemon.8 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd Feb 24, 2008 +.Dd Jul 08, 2008 .Dt START-STOP-DAEMON 8 SMM .Os OpenRC .Sh NAME @@ -44,6 +44,11 @@ .Sh DESCRIPTION .Nm provides a consistent method of starting, stopping and signalling daemons. +If neither +.Fl K , -stop +nor +.Fl s , -signal +are provided, then we assume we are starting the daemon. If a daemon cannot background by itself, nor create a pidfile, .Nm can do it for the daemon in a secure fashion. @@ -67,6 +72,8 @@ Here are the options to specify the daemon and how it should start or stop: The .Ar daemon we start or stop. +If this option is not specified, then the first non option argument +is used. If the .Ar daemon is a script and you are not using the pidfile or process name options, @@ -76,7 +83,7 @@ with the interpreter and pass .Ar daemon as an argument. Below is an example: .Pp -start-stop-daemon -Sx /usr/bin/perl -- /usr/bin/daemon.pl +start-stop-daemon perl -- /usr/bin/daemon.pl .It Fl p , -pidfile Ar pidfile When starting, we expect the daemon to create a valid .Ar pidfile @@ -101,6 +108,10 @@ The return value is set as if the command was taken and worked. .Pp These options are only used for starting daemons: .Bl -tag -width indent +.It Fl a , -startas Ar name +Change the process name of the daemon to +.Ar name . +This just changes the first argument passed to the daemon. .It Fl b , -background Force the daemon into the background. Some daemons don't create pidfiles, so a good trick is to get the daemon to run in the foreground, and use the this diff --git a/src/librc/librc-daemon.c b/src/librc/librc-daemon.c index ddee0342..95d4a5f9 100644 --- a/src/librc/librc-daemon.c +++ b/src/librc/librc-daemon.c @@ -40,11 +40,11 @@ static size_t strlcpy(char *dst, const char *src, size_t size) if (n && --n) do { - if (! (*dst++ = *src++)) + if (!(*dst++ = *src++)) break; } while (--n); - if (! n) { + if (!n) { if (size) *dst = '\0'; while (*src++); @@ -57,21 +57,22 @@ static size_t strlcpy(char *dst, const char *src, size_t size) #if defined(__linux__) -static bool pid_is_cmd(pid_t pid, const char *cmd) +static bool pid_is_exec(pid_t pid, const char *exec) { char buffer[32]; FILE *fp; int c; bool retval = false; + exec = basename_c(exec); snprintf(buffer, sizeof(buffer), "/proc/%d/stat", pid); if ((fp = fopen(buffer, "r"))) { while ((c = getc(fp)) != EOF && c != '(') ; if (c == '(') { - while ((c = getc(fp)) != EOF && c == *cmd) - cmd++; - if (c == ')' && *cmd == '\0') + while ((c = getc(fp)) != EOF && c == *exec) + exec++; + if (c == ')' && *exec == '\0') retval = true; } fclose(fp); @@ -79,7 +80,7 @@ static bool pid_is_cmd(pid_t pid, const char *cmd) return retval; } -static bool pid_is_exec(pid_t pid, const char *const *argv) +static bool pid_is_argv(pid_t pid, const char *const *argv) { char cmdline[32]; int fd; @@ -108,7 +109,7 @@ static bool pid_is_exec(pid_t pid, const char *const *argv) return true; } -RC_PIDLIST *rc_find_pids(const char *const *argv, const char *cmd, +RC_PIDLIST *rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid) { DIR *procdir; @@ -143,27 +144,21 @@ RC_PIDLIST *rc_find_pids(const char *const *argv, const char *cmd, while ((entry = readdir(procdir)) != NULL) { if (sscanf(entry->d_name, "%d", &p) != 1) continue; - if (runscript_pid != 0 && runscript_pid == p) continue; - if (pid != 0 && pid != p) continue; - if (uid) { snprintf(buffer, sizeof(buffer), "/proc/%d", p); if (stat(buffer, &sb) != 0 || sb.st_uid != uid) continue; } - - if (cmd && ! pid_is_cmd(p, cmd)) + if (exec && !pid_is_exec(p, exec)) continue; - - if (argv && ! cmd && ! - pid_is_exec(p, (const char *const *)argv)) + if (argv && + !pid_is_argv(p, (const char *const *)argv)) continue; - - if (! pids) { + if (!pids) { pids = xmalloc(sizeof(*pids)); LIST_INIT(pids); } @@ -172,7 +167,6 @@ RC_PIDLIST *rc_find_pids(const char *const *argv, const char *cmd, LIST_INSERT_HEAD(pids, pi, entries); } closedir(procdir); - return pids; } librc_hidden_def(rc_find_pids) @@ -201,7 +195,7 @@ librc_hidden_def(rc_find_pids) # define _KVM_FLAGS O_RDONLY # endif -RC_PIDLIST *rc_find_pids(const char *const *argv, const char *cmd, +RC_PIDLIST *rc_find_pids(const char *exec, const char *const *argv, uid_t uid, pid_t pid) { static kvm_t *kd = NULL; @@ -235,39 +229,34 @@ RC_PIDLIST *rc_find_pids(const char *const *argv, const char *cmd, return NULL; } + if (exec) + exec = basename_c(exec); for (i = 0; i < processes; i++) { p = _GET_KINFO_PID(kp[i]); if (pid != 0 && pid != p) continue; - if (uid != 0 && uid != _GET_KINFO_UID(kp[i])) continue; - - if (cmd) { - if (! _GET_KINFO_COMM(kp[i]) || - strcmp(cmd, _GET_KINFO_COMM(kp[i])) != 0) + if (exec) { + if (!_GET_KINFO_COMM(kp[i]) || + strcmp(exec, _GET_KINFO_COMM(kp[i])) != 0) continue; } - - if (argv && *argv && ! cmd) { + if (argv && *argv) { pargv = _KVM_GETARGV(kd, &kp[i], pargc); - if (! pargv || ! *pargv) + if (!pargv || !*pargv) continue; - arg = argv; match = 1; - while (*arg && *pargv) if (strcmp(*arg++, *pargv++) != 0) { match = 0; break; } - - if (! match) + if (!match) continue; } - - if (! pids) { + if (!pids) { pids = xmalloc(sizeof(*pids)); LIST_INIT(pids); } @@ -297,7 +286,7 @@ static bool _match_daemon(const char *path, const char *file, snprintf(ffile, sizeof(ffile), "%s/%s", path, file); fp = fopen(ffile, "r"); - if (! fp) + if (!fp) return false; while ((rc_getline(&line, &len, fp))) { @@ -306,7 +295,7 @@ static bool _match_daemon(const char *path, const char *file, TAILQ_REMOVE(match, m, entries); break; } - if (! TAILQ_FIRST(match)) + if (!TAILQ_FIRST(match)) break; } fclose(fp); @@ -316,14 +305,22 @@ static bool _match_daemon(const char *path, const char *file, return true; } -static RC_STRINGLIST *_match_list(const char* const* argv, - const char *name, const char *pidfile) +static RC_STRINGLIST *_match_list(const char *exec, const char* const* argv, + const char *pidfile) { RC_STRINGLIST *match = rc_stringlist_new(); int i = 0; size_t l; char *m; + if (exec) { + l = strlen(exec) + 6; + m = xmalloc(sizeof(char) * l); + snprintf(m, l, "exec=%s", exec); + rc_stringlist_add(match, m); + free(m); + } + while (argv && argv[i]) { l = strlen(*argv) + strlen("argv_=") + 16; m = xmalloc(sizeof(char) * l); @@ -332,14 +329,6 @@ static RC_STRINGLIST *_match_list(const char* const* argv, free(m); } - if (name) { - l = strlen(name) + 6; - m = xmalloc(sizeof (char) * l); - snprintf(m, l, "name=%s", name); - rc_stringlist_add(match, m); - free(m); - } - if (pidfile) { l = strlen(pidfile) + 9; m = xmalloc(sizeof (char) * l); @@ -351,8 +340,9 @@ static RC_STRINGLIST *_match_list(const char* const* argv, return match; } -bool rc_service_daemon_set(const char *service, const char *const *argv, - const char *name, const char *pidfile, bool started) +bool rc_service_daemon_set(const char *service, const char *exec, + const char *const *argv, + const char *pidfile, bool started) { char dirpath[PATH_MAX]; char file[PATH_MAX]; @@ -365,7 +355,7 @@ bool rc_service_daemon_set(const char *service, const char *const *argv, int i = 0; FILE *fp; - if (!(argv && *argv) && ! name && ! pidfile) { + if (!exec && !pidfile) { errno = EINVAL; return false; } @@ -375,7 +365,7 @@ bool rc_service_daemon_set(const char *service, const char *const *argv, /* Regardless, erase any existing daemon info */ if ((dp = opendir(dirpath))) { - match = _match_list(argv, name, pidfile); + match = _match_list(exec, argv, pidfile); while ((d = readdir(dp))) { if (d->d_name[0] == '.') continue; @@ -384,7 +374,7 @@ bool rc_service_daemon_set(const char *service, const char *const *argv, dirpath, d->d_name); nfiles++; - if (! *oldfile) { + if (!*oldfile) { if (_match_daemon(dirpath, d->d_name, match)) { unlink(file); strlcpy(oldfile, file, sizeof(oldfile)); @@ -405,13 +395,13 @@ bool rc_service_daemon_set(const char *service, const char *const *argv, snprintf(file, sizeof(file), "%s/%03d", dirpath, nfiles + 1); if ((fp = fopen(file, "w"))) { + fprintf(fp, "exec="); + if (exec) + fprintf(fp, "%s", exec); while (argv && argv[i]) { - fprintf(fp, "argv_%d=%s\n", i, argv[i]); + fprintf(fp, "\nargv_%d=%s", i, argv[i]); i++; } - fprintf(fp, "name="); - if (name) - fprintf(fp, "%s", name); fprintf(fp, "\npidfile="); if (pidfile) fprintf(fp, "%s", pidfile); @@ -427,7 +417,8 @@ bool rc_service_daemon_set(const char *service, const char *const *argv, } librc_hidden_def(rc_service_daemon_set) -bool rc_service_started_daemon(const char *service, const char *const *argv, +bool rc_service_started_daemon(const char *service, + const char *exec, const char *const *argv, int indx) { char dirpath[PATH_MAX]; @@ -442,7 +433,7 @@ bool rc_service_started_daemon(const char *service, const char *const *argv, snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", basename_c(service)); - match = _match_list(argv, NULL, NULL); + match = _match_list(exec, argv, NULL); if (indx > 0) { snprintf(file, sizeof(file), "%03d", indx); @@ -492,7 +483,7 @@ bool rc_service_daemons_crashed(const char *service) path += snprintf(dirpath, sizeof(dirpath), RC_SVCDIR "/daemons/%s", basename_c(service)); - if (! (dp = opendir(dirpath))) + if (!(dp = opendir(dirpath))) return false; while ((d = readdir(dp))) { @@ -502,25 +493,25 @@ bool rc_service_daemons_crashed(const char *service) snprintf(path, sizeof(dirpath) - (path - dirpath), "/%s", d->d_name); fp = fopen(dirpath, "r"); - if (! fp) + if (!fp) break; while ((rc_getline(&line, &len, fp))) { p = line; - if ((token = strsep(&p, "=")) == NULL || ! p) + if ((token = strsep(&p, "=")) == NULL || !p) continue; - if (! *p) + if (!*p) continue; - if (strncmp(token, "argv_", 5) == 0) { - if (! list) - list = rc_stringlist_new(); - rc_stringlist_add(list, p); - } else if (strcmp(token, "exec") == 0) { + if (strcmp(token, "exec") == 0) { if (exec) free(exec); exec = xstrdup(p); + } else if (strncmp(token, "argv_", 5) == 0) { + if (!list) + list = rc_stringlist_new(); + rc_stringlist_add(list, p); } else if (strcmp(token, "name") == 0) { if (name) free(name); @@ -548,9 +539,9 @@ bool rc_service_daemons_crashed(const char *service) name = NULL; } else { if (exec) { - if (! list) + if (!list) list = rc_stringlist_new(); - if (! TAILQ_FIRST(list)) + if (!TAILQ_FIRST(list)) rc_stringlist_add(list, exec); free(exec); @@ -570,9 +561,10 @@ bool rc_service_daemons_crashed(const char *service) } } - if (! retval) { - if ((pids = rc_find_pids((const char *const *)argv, - name, 0, pid))) + if (!retval) { + if ((pids = rc_find_pids(exec, + (const char *const *)argv, + 0, pid))) { p1 = LIST_FIRST(pids); while (p1) { diff --git a/src/librc/rc.h.in b/src/librc/rc.h.in index 373c5308..12cc42c3 100644 --- a/src/librc/rc.h.in +++ b/src/librc/rc.h.in @@ -142,7 +142,7 @@ bool rc_service_delete(const char *, const char *); * @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 *, const char *const *, const char *, const char *, +bool rc_service_daemon_set(const char *, const char *, const char *const *, const char *, bool); /*! Returns a description of what the service and/or option does. @@ -202,9 +202,11 @@ RC_SERVICE rc_service_state(const char *); /*! Check if the service started the daemon * @param service to check * @param exec to check + * @param argv to check * @param indx of the daemon (optional - 1st daemon, 2nd daemon, etc) * @return true if started by this service, otherwise false */ -bool rc_service_started_daemon(const char *, const char *const *, int); +bool rc_service_started_daemon(const char *, const char *, + const char *const *, int); /*! Return a saved value for a service * @param service to check @@ -463,11 +465,11 @@ typedef LIST_HEAD(rc_pidlist, rc_pid) RC_PIDLIST; * pid overrides anything else. * If both exec and cmd are given then we ignore exec. * @param exec to check for - * @param cmd to check for + * @param argv to check for * @param uid to check for * @param pid to check for * @return NULL terminated list of pids */ -RC_PIDLIST *rc_find_pids(const char *const *, const char *, uid_t, pid_t); +RC_PIDLIST *rc_find_pids(const char *, const char *const *, uid_t, pid_t); __END_DECLS #endif diff --git a/src/rc/Makefile b/src/rc/Makefile index 5b3be058..5353416f 100644 --- a/src/rc/Makefile +++ b/src/rc/Makefile @@ -30,15 +30,14 @@ RC_SBINLINKS= mark_service_starting mark_service_started \ ALL_LINKS= ${BINLINKS} ${SBINLINKS} ${RC_BINLINKS} ${RC_SBINLINKS} CLEANFILES+= ${ALL_LINKS} +CPPFLAGS+= -I../includes -I../librc -I../libeinfo LDFLAGS+= -L../librc -L../libeinfo LDADD+= -lutil -lrc -leinfo MK= ../../mk +include ${MK}/debug.mk include ${MK}/prog.mk include ${MK}/cc.mk -include ${MK}/debug.mk - -CPPFLAGS+= -I../includes -I../librc -I../libeinfo include ${MK}/${MKTERMCAP}.mk LDADD+= ${LIBDL} ${LIBKVM} diff --git a/src/rc/rc-applets.c b/src/rc/rc-applets.c index 6a6216c4..2b7d1909 100644 --- a/src/rc/rc-applets.c +++ b/src/rc/rc-applets.c @@ -243,9 +243,9 @@ static int do_e(int argc, char **argv) static int do_service(int argc, char **argv) { bool ok = false; - char *service = NULL; + char *service; + char *exec; int idx = 0; - char *d[] = { NULL, NULL }; if (argc > 1) service = argv[1]; @@ -270,21 +270,19 @@ static int do_service(int argc, char **argv) else if (strcmp(applet, "service_wasinactive") == 0) ok = (rc_service_state(service) & RC_SERVICE_WASINACTIVE); else if (strcmp(applet, "service_started_daemon") == 0) { - d[0] = argv[1]; - service = getenv("RC_SVCNAME"); + exec = argv[1]; if (argc > 3) { service = argv[1]; - d[0] = argv[2]; + exec = argv[2]; sscanf(argv[3], "%d", &idx); } else if (argc == 3) { if (sscanf(argv[2], "%d", &idx) != 1) { service = argv[1]; - d[0] = argv[2]; + exec = argv[2]; } } - ok = rc_service_started_daemon(service, - (const char * const *)d, idx); + ok = rc_service_started_daemon(service, exec, NULL, idx); } else eerrorx("%s: unknown applet", applet); diff --git a/src/rc/start-stop-daemon.c b/src/rc/start-stop-daemon.c index d98a7c06..76f2b028 100644 --- a/src/rc/start-stop-daemon.c +++ b/src/rc/start-stop-daemon.c @@ -157,7 +157,7 @@ static int parse_signal(const char *sig) unsigned int i = 0; const char *s; - if (! sig || *sig == '\0') + if (!sig || *sig == '\0') return -1; if (sscanf(sig, "%u", &i) == 1) { @@ -289,13 +289,13 @@ static pid_t get_pid(const char *pidfile, bool quiet) return -1; if ((fp = fopen(pidfile, "r")) == NULL) { - if (! quiet) + if (!quiet) eerror("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); return -1; } if (fscanf(fp, "%d", &pid) != 1) { - if (! quiet) + if (!quiet) eerror("%s: no pid found in `%s'", applet, pidfile); fclose(fp); return -1; @@ -307,7 +307,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 *const *argv, const char *cmd, +static int do_stop(const char *exec, const char *const *argv, pid_t pid, uid_t uid,int sig, bool quiet, bool verbose, bool test) { @@ -320,14 +320,14 @@ static int do_stop(const char *const *argv, const char *cmd, if (pid) pids = rc_find_pids(NULL, NULL, 0, pid); else - pids = rc_find_pids(argv, cmd, uid, pid); + pids = rc_find_pids(exec, argv, uid, pid); - if (! pids) + if (!pids) return 0; LIST_FOREACH_SAFE(pi, pids, entries, np) { if (test) { - if (! quiet) + if (!quiet) einfo("Would send signal %d to PID %d", sig, pi->pid); nkilled++; @@ -342,7 +342,7 @@ static int do_stop(const char *const *argv, const char *cmd, eend(killed ? 0 : 1, "%s: failed to send signal %d to PID %d: %s", applet, sig, pi->pid, strerror(errno)); - if (! killed) { + if (!killed) { nkilled = -1; } else { if (nkilled != -1) @@ -356,7 +356,7 @@ static int do_stop(const char *const *argv, const char *cmd, return nkilled; } -static int run_stop_schedule(const char *const *argv, const char *cmd, +static int run_stop_schedule(const char *exec, const char *const *argv, const char *pidfile, uid_t uid, bool quiet, bool verbose, bool test) { @@ -369,14 +369,14 @@ static int run_stop_schedule(const char *const *argv, const char *cmd, pid_t pid = 0; if (verbose) { + if (exec) + einfo ("Will stop %s\n", exec); if (pidfile) einfo("Will stop PID in pidfile `%s'", pidfile); if (uid) einfo("Will stop processes owned by UID %d", uid); if (argv && *argv) einfo("Will stop processes of `%s'", *argv); - if (cmd) - einfo("Will stop processes called `%s'", cmd); } if (pidfile) { @@ -393,7 +393,7 @@ static int run_stop_schedule(const char *const *argv, const char *cmd, case SC_SIGNAL: nrunning = 0; - nkilled = do_stop(argv, cmd, pid, uid, item->value, + nkilled = do_stop(exec, argv, pid, uid, item->value, quiet, verbose, test); if (nkilled == 0) { if (tkilled == 0) { @@ -419,7 +419,7 @@ static int run_stop_schedule(const char *const *argv, const char *cmd, ts.tv_nsec = POLL_INTERVAL; while (nloops) { - if ((nrunning = do_stop(argv, cmd, pid, + if ((nrunning = do_stop(exec, argv, pid, uid, 0, true, false, true)) == 0) return 0; @@ -466,15 +466,15 @@ static void handle_signal(int sig) switch (sig) { case SIGINT: - if (! signame[0]) + if (!signame[0]) snprintf(signame, sizeof(signame), "SIGINT"); /* FALLTHROUGH */ case SIGTERM: - if (! signame[0]) + if (!signame[0]) snprintf(signame, sizeof(signame), "SIGTERM"); /* FALLTHROUGH */ case SIGQUIT: - if (! signame[0]) + if (!signame[0]) snprintf(signame, sizeof(signame), "SIGQUIT"); eerrorx("%s: caught %s, aborting", applet, signame); /* NOTREACHED */ @@ -499,7 +499,7 @@ static void handle_signal(int sig) #include "_usage.h" -#define getoptstring "KN:R:Sbc:d:g:mn:op:s:tu:r:x:1:2:" getoptstring_COMMON +#define getoptstring "KN:R:Sbc:d:e:g:mn:op:s:tu:r:x:1:2:" getoptstring_COMMON static const struct option longopts[] = { { "stop", 0, NULL, 'K'}, { "nicelevel", 1, NULL, 'N'}, @@ -529,7 +529,7 @@ static const char * const longopts_help[] = { "Set a nicelevel when starting", "Retry schedule to use when stopping", "Start daemon", - "deprecated, use --exec", + "deprecated, use --exec or --name", "Force daemon to background", "deprecated, use --user", "Change the PWD", @@ -563,14 +563,14 @@ int start_stop_daemon(int argc, char **argv) #endif int opt; - bool start = false; - bool stop = false; + bool start = true; bool oknodo = false; bool test = false; bool quiet; bool verbose = false; char *exec = NULL; - char *cmd = NULL; + char *startas = NULL; + char *name = NULL; char *pidfile = NULL; int sig = SIGTERM; int nicelevel = 0; @@ -585,16 +585,16 @@ int start_stop_daemon(int argc, char **argv) char *redirect_stdout = NULL; int stdout_fd; int stderr_fd; - pid_t pid; + pid_t pid, spid; int i; char *svcname = getenv("RC_SVCNAME"); RC_STRINGLIST *env_list; RC_STRING *env; - char *path; + char *tmp, *newpath, *np; bool sethome = false; bool setuser = false; char *p; - char *tmp; + char *token; char exec_file[PATH_MAX]; struct passwd *pw; struct group *gr; @@ -609,16 +609,16 @@ int start_stop_daemon(int argc, char **argv) signal_setup(SIGQUIT, handle_signal); signal_setup(SIGTERM, handle_signal); - if ((path = getenv("SSD_NICELEVEL"))) - if (sscanf(path, "%d", &nicelevel) != 1) + if ((tmp = getenv("SSD_NICELEVEL"))) + if (sscanf(tmp, "%d", &nicelevel) != 1) eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)", - applet, path); + applet, tmp); - while ((opt = getopt_long(argc, argv, "e:" getoptstring, longopts, + while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) switch (opt) { case 'K': /* --stop */ - stop = true; + start = false; break; case 'N': /* --nice */ @@ -701,7 +701,7 @@ int start_stop_daemon(int argc, char **argv) break; case 'n': /* --name */ - cmd = optarg; + name = optarg; break; case 'o': /* --oknodo */ @@ -724,7 +724,9 @@ int start_stop_daemon(int argc, char **argv) ch_root = optarg; break; - case 'a': + case 'a': /* --startas */ + startas = optarg; + break; case 'x': /* --exec */ exec = optarg; break; @@ -740,106 +742,66 @@ int start_stop_daemon(int argc, char **argv) case_RC_COMMON_GETOPT } + argc -= optind; + argv += optind; quiet = rc_yesno(getenv("EINFO_QUIET")); verbose = rc_yesno(getenv("EINFO_VERBOSE")); /* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq * instead of forcing --stop --oknodo as well */ - if (! start && ! stop) - if (sig != SIGINT && - sig != SIGTERM && - sig != SIGQUIT && - sig != SIGKILL) - { - oknodo = true; - stop = true; - } + if (!start && + sig != SIGINT && + sig != SIGTERM && + sig != SIGQUIT && + sig != SIGKILL) + oknodo = true; - if (start == stop) - eerrorx("%s: need one of --start or --stop", applet); + if (!exec) + exec = startas; + else if (!name) + name = startas; - if (start && ! exec) - eerrorx("%s: --start needs --exec", applet); + if (!exec) { + exec = *argv; + if (name) + *argv = name; + } else if (name) + *--argv = name; + else + *--argv = exec; - if (stop && ! exec && ! pidfile && ! cmd && ! uid) + + if (start && !exec) + eerrorx("%s: nothing to start", applet); + + if (!start && !*argv && !pidfile && !name && !uid) eerrorx("%s: --stop needs --exec, --pidfile, --name or --user", applet); - if (makepidfile && ! pidfile) + if (makepidfile && !pidfile) eerrorx("%s: --make-pidfile is only relevant with --pidfile", applet); - if (background && ! start) + if (background && !start) eerrorx("%s: --background is only relevant with --start", applet); - if ((redirect_stdout || redirect_stderr) && ! background) + if ((redirect_stdout || redirect_stderr) && !background) eerrorx("%s: --stdout and --stderr are only relevant with --background", applet); - argc -= optind; - argv += optind; - - /* Validate that the binary exists if we are starting */ - if (exec) { - if (ch_root) { - snprintf(exec_file, sizeof(exec_file), "%s/%s", ch_root, exec); - tmp = exec_file; - } else - tmp = exec; - if (start && ! exists(tmp)) { - eerror("%s: %s does not exist", applet, tmp); - exit(EXIT_FAILURE); - } - - /* If we don't have a pidfile or name, check it's not - * interpreted, otherwise we should fail */ - if (! pidfile && ! cmd) { - fp = fopen (tmp, "r"); - if (fp) { - fgets(line, sizeof(line), fp); - fclose(fp); - - if (line[0] == '#' && line[1] == '!') { - len = strlen (line) - 1; - - /* Remove the trailing newline */ - if (line[len] == '\n') - line[len] = '\0'; - - eerror("%s: %s is a script", - applet, exec); - eerror("%s: and should be started, stopped" - " or signalled with ", applet); - eerror("%s: --exec %s %s", - applet, line + 2, exec); - eerror("%s: or you should specify a pidfile" - " or process name", applet); - exit(EXIT_FAILURE); - } - } - } - } - - /* Add exec to our arguments */ - *--argv = exec; - - if (stop) { - int result; - - if (! TAILQ_FIRST(&schedule)) { + if (!start) { + if (!TAILQ_FIRST(&schedule)) { if (test || oknodo) parse_schedule("0", sig); else parse_schedule(NULL, sig); } + i = run_stop_schedule(exec, (const char *const *)argv, + pidfile, uid, quiet, verbose, test); - result = run_stop_schedule((const char *const *)argv, cmd, - pidfile, uid, quiet, verbose, test); - - if (result < 0) + if (i < 0) /* We failed to stop something */ exit(EXIT_FAILURE); - if (test || oknodo) - return result > 0 ? EXIT_SUCCESS : EXIT_FAILURE; + return i > 0 ? EXIT_SUCCESS : EXIT_FAILURE; /* Even if we have not actually killed anything, we should * remove information about it as it may have unexpectedly @@ -847,21 +809,75 @@ int start_stop_daemon(int argc, char **argv) * result would be the same. */ if (pidfile && exists(pidfile)) unlink(pidfile); - if (svcname) - rc_service_daemon_set(svcname, + rc_service_daemon_set(svcname, exec, (const char *const *)argv, - cmd, pidfile, false); - + pidfile, false); exit(EXIT_SUCCESS); } - if (pidfile) { + /* Validate that the binary exists if we are starting */ + if (*exec == '/' || *exec == '.') { + /* Full or relative path */ + if (ch_root) + snprintf(exec_file, sizeof(exec_file), "%s/%s", ch_root, exec); + else + snprintf(exec_file, sizeof(exec_file), "%s", exec); + } else { + /* Something in $PATH */ + p = tmp = xstrdup(getenv("PATH")); + *exec_file = '\0'; + while ((token = strsep(&p, ":"))) { + if (ch_root) + snprintf(exec_file, sizeof(exec_file), "%s/%s/%s", ch_root, token, exec); + else + snprintf(exec_file, sizeof(exec_file), "%s/%s", token, exec); + if (exists(exec_file)) + break; + *exec_file = '\0'; + } + free(tmp); + } + if (!exists(exec_file)) { + eerror("%s: %s does not exist", applet, + *exec_file ? exec_file : exec); + exit(EXIT_FAILURE); + } + + /* If we don't have a pidfile or name, check it's not + * interpreted, otherwise we should fail */ + if (!pidfile && !name) { + fp = fopen(tmp, "r"); + if (fp) { + fgets(line, sizeof(line), fp); + fclose(fp); + + if (line[0] == '#' && line[1] == '!') { + len = strlen(line) - 1; + + /* Remove the trailing newline */ + if (line[len] == '\n') + line[len] = '\0'; + + eerror("%s: %s is a script", + applet, exec); + eerror("%s: and should be started, stopped" + " or signalled with ", applet); + eerror("%s: --exec %s %s", + applet, line + 2, exec); + eerror("%s: or you should specify a pidfile" + " or process name", applet); + exit(EXIT_FAILURE); + } + } + } + + if (pidfile) pid = get_pid(pidfile, true); - } else + else pid = 0; - if (do_stop((const char * const *)argv, cmd, pid, uid, + if (do_stop(exec, (const char * const *)argv, pid, uid, 0, true, false, true) > 0) eerrorx("%s: %s is already running", applet, exec); @@ -884,6 +900,8 @@ int start_stop_daemon(int argc, char **argv) einfo("in dir `%s'", ch_dir); if (nicelevel != 0) einfo("with a priority of %d", nicelevel); + if (name) + einfo ("with a process name of %s", name); eoutdent(); exit(EXIT_SUCCESS); } @@ -918,7 +936,7 @@ int start_stop_daemon(int argc, char **argv) if (ch_root && chroot(ch_root) < 0) eerrorx("%s: chroot `%s': %s", applet, ch_root, strerror(errno)); - if (ch_dir && chdir (ch_dir) < 0) + if (ch_dir && chdir(ch_dir) < 0) eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno)); if (makepidfile && pidfile) { @@ -955,12 +973,12 @@ int start_stop_daemon(int argc, char **argv) else { pw = getpwuid(uid); if (pw) { - if (! sethome) { + if (!sethome) { unsetenv("HOME"); if (pw->pw_dir) setenv("HOME", pw->pw_dir, 1); } - if (! setuser) { + if (!setuser) { unsetenv("USER"); if (pw->pw_name) setenv("USER", pw->pw_name, 1); @@ -996,26 +1014,22 @@ int start_stop_daemon(int argc, char **argv) rc_stringlist_free(env_list); /* For the path, remove the rcscript bin dir from it */ - if ((path = getenv("PATH"))) { - size_t mx = strlen(path); - char *newpath = xmalloc(mx); - char *token; - char *np = newpath; - size_t l; - - p = path; - while ((token = strsep (&p, ":"))) { - if (strcmp (token, RC_LIBDIR "/bin") == 0 || - strcmp (token, RC_LIBDIR "/sbin") == 0) + if ((tmp = xstrdup(getenv("PATH")))) { + len = strlen(tmp); + newpath = np = xmalloc(len); + p = tmp; + while ((token = strsep(&p, ":"))) { + if (strcmp(token, RC_LIBDIR "/bin") == 0 || + strcmp(token, RC_LIBDIR "/sbin") == 0) continue; - - l = strlen (token); + len = strlen(token); if (np != newpath) *np++ = ':'; - memcpy (np, token, l); - np += l; + memcpy(np, token, len); + np += len; *np = '\0'; } + free(tmp); unsetenv("PATH"); setenv("PATH", newpath, 1); } @@ -1047,7 +1061,7 @@ int start_stop_daemon(int argc, char **argv) close(i); setsid(); - execv(exec, argv); + execvp(exec, argv); #ifdef HAVE_PAM if (pamr == PAM_SUCCESS) pam_close_session(pamh, PAM_SILENT); @@ -1056,27 +1070,24 @@ int start_stop_daemon(int argc, char **argv) } /* Parent process */ - if (! background) { + if (!background) { /* As we're not backgrounding the process, wait for our pid to return */ - int status = 0; - int savepid = pid; + i = 0; + spid = pid; - errno = 0; do { - pid = waitpid(savepid, &status, 0); + pid = waitpid(spid, &i, 0); if (pid < 1) { - eerror("waitpid %d: %s", savepid, strerror(errno)); + eerror("waitpid %d: %s", spid, strerror(errno)); return -1; } - } while (! WIFEXITED(status) && ! WIFSIGNALED(status)); - - if (! WIFEXITED(status) || WEXITSTATUS(status) != 0) { - if (! quiet) + } while (!WIFEXITED(i) && !WIFSIGNALED(i)); + if (!WIFEXITED(i) || WEXITSTATUS(i) != 0) { + if (!quiet) eerrorx("%s: failed to start `%s'", applet, exec); exit(EXIT_FAILURE); } - - pid = savepid; + pid = spid; } /* Wait a little bit and check that process is still running @@ -1104,10 +1115,10 @@ int start_stop_daemon(int argc, char **argv) * created. Once everything is in place we then wait some more * to ensure that the daemon really is running and won't abort due * to a config error. */ - if (! background && pidfile && nloopsp) - nloopsp --; + if (!background && pidfile && nloopsp) + nloopsp--; else - nloops --; + nloops--; /* This is knarly. If we backgrounded then we know the exact pid. @@ -1131,19 +1142,19 @@ int start_stop_daemon(int argc, char **argv) nloopsp = 0; } else pid = 0; - if (do_stop((const char *const *)argv, cmd, + if (do_stop(exec, (const char *const *)argv, pid, uid, 0, true, false, true) > 0) alive = true; } - if (! alive) + if (!alive) eerrorx("%s: %s died", applet, exec); } } if (svcname) - rc_service_daemon_set(svcname, (const char *const *)argv, - cmd, pidfile, true); + rc_service_daemon_set(svcname, exec, (const char *const *)argv, + pidfile, true); exit(EXIT_SUCCESS); /* NOTREACHED */