diff options
-rw-r--r-- | Config.h | 1 | ||||
-rw-r--r-- | applets.h | 3 | ||||
-rw-r--r-- | applets/usage.h | 14 | ||||
-rw-r--r-- | debianutils/start_stop_daemon.c | 271 | ||||
-rw-r--r-- | include/applets.h | 3 | ||||
-rw-r--r-- | include/usage.h | 14 | ||||
-rw-r--r-- | init/start_stop_daemon.c | 271 | ||||
-rw-r--r-- | start_stop_daemon.c | 271 | ||||
-rw-r--r-- | usage.h | 14 |
9 files changed, 862 insertions, 0 deletions
@@ -114,6 +114,7 @@ #define BB_SLEEP #define BB_SORT //#define BB_STTY +//#define BB_START_STOP_DAEMON #define BB_SWAPONOFF #define BB_SYNC #define BB_SYSLOGD @@ -386,6 +386,9 @@ #ifdef BB_SORT APPLET(sort, sort_main, _BB_DIR_USR_BIN) #endif +#ifdef BB_START_STOP_DAEMON + APPLET_ODDNAME("start-stop-daemon", start_stop_daemon_main, _BB_DIR_SBIN, start_stop_daemon) +#endif #ifdef BB_STTY APPLET(stty, stty_main, _BB_DIR_BIN) #endif diff --git a/applets/usage.h b/applets/usage.h index 0d830c9cc..5e514274a 100644 --- a/applets/usage.h +++ b/applets/usage.h @@ -1458,6 +1458,20 @@ "e\n" \ "f\n" +#define start_stop_daemon_trivial_usage \ + "[OPTIONS]" +#define start_stop_daemon_full_usage \ + "Program to start and stop services.\n"\ + "Options:\n" \ + "-S\t\t\tstart\n"\ + "-K\t\t\tstop\n"\ + "-x <executable>\t\tprogram to start/check if it is running\n"\ + "-p <pid-file>\t\tpid file to check\n"\ + "-u <username>|<uid>\tstop this user's processes\n"\ + "-n <process-name>\tstop processes with this name\n"\ + "-s <signal>\t\tsignal to send (default 15)\n"\ + "-a <pathname>\t\tprogram to start (default <executable>)\n" + #define stty_trivial_usage \ "[-a|g] [-F DEVICE] [SETTING]..." #define stty_full_usage \ diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c new file mode 100644 index 000000000..0152283ad --- /dev/null +++ b/debianutils/start_stop_daemon.c @@ -0,0 +1,271 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini start-stop-daemon implementation(s) for busybox + * + * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, + * public domain. + * Adapted for busybox David Kimdon <dwhedon@gordian.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <signal.h> +#include <errno.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <pwd.h> + +#include "busybox.h" + +static int start = 0; +static int stop = 0; +static int signal_nr = 15; +static int user_id = -1; +static const char *userspec = NULL; +static const char *cmdname = NULL; +static char *execname = NULL; +static char *startas = NULL; +static const char *progname = ""; + +struct pid_list { + struct pid_list *next; + int pid; +}; + +static struct pid_list *found = NULL; +static struct pid_list *killed = NULL; + +static void +push(struct pid_list **list, int pid) +{ + struct pid_list *p; + + p = xmalloc(sizeof(*p)); + p->next = *list; + p->pid = pid; + *list = p; +} + + +static void +parse_options(int argc, char * const *argv) +{ + + int c; + + for (;;) { + c = getopt (argc, argv, "a:n:s:u:x:KS"); + if (c == EOF) + break; + switch (c) { + case 'K': + stop = 1; + break; + case 'S': + start = 1; + break; + case 'a': + startas = optarg; + break; + case 'n': + cmdname = optarg; + break; + case 's': + if (sscanf(optarg, "%d", &signal_nr) != 1) + error_msg_and_die ("-s takes a numeric argument"); + break; + case 'u': + userspec = optarg; + break; + case 'x': + execname = optarg; + break; + default: + show_usage(); + exit(1); + } + } + + if (start == stop) + error_msg_and_die ("need one of -S or -K"); + + if (!execname && !userspec) + error_msg_and_die ("need at least one of -x or -u"); + + if (!startas) + startas = execname; + + if (start && !startas) + error_msg_and_die ("-S needs -x or -a"); +} + + +static int +pid_is_exec(int pid, const char *exec) +{ + char buf[PATH_MAX]; + FILE *fp; + + sprintf(buf, "/proc/%d/cmdline", pid); + fp = fopen(buf, "r"); + if (fp && fgets (buf, sizeof (buf), fp) ) { + if (strncmp (buf, exec, strlen(exec)) == 0) + return 1; + } + return 0; +} + + +static int +pid_is_user(int pid, int uid) +{ + struct stat sb; + char buf[32]; + + sprintf(buf, "/proc/%d", pid); + if (stat(buf, &sb) != 0) + return 0; + return (sb.st_uid == uid); +} + + +static int +pid_is_cmd(int pid, const char *name) +{ + char buf[32]; + FILE *f; + int c; + + sprintf(buf, "/proc/%d/stat", pid); + f = fopen(buf, "r"); + if (!f) + return 0; + while ((c = getc(f)) != EOF && c != '(') + ; + if (c != '(') { + fclose(f); + return 0; + } + /* this hopefully handles command names containing ')' */ + while ((c = getc(f)) != EOF && c == *name) + name++; + fclose(f); + return (c == ')' && *name == '\0'); +} + + +static void +check(int pid) +{ + if (execname && !pid_is_exec(pid, execname)) { + return; + } + if (userspec && !pid_is_user(pid, user_id)) { + return; + } + if (cmdname && !pid_is_cmd(pid, cmdname)) { + return; + } + push(&found, pid); +} + + + +static void +do_procfs(void) +{ + DIR *procdir; + struct dirent *entry; + int foundany, pid; + + procdir = opendir("/proc"); + if (!procdir) + perror_msg_and_die ("opendir /proc"); + + foundany = 0; + while ((entry = readdir(procdir)) != NULL) { + if (sscanf(entry->d_name, "%d", &pid) != 1) + continue; + foundany++; + check(pid); + } + closedir(procdir); + if (!foundany) + error_msg_and_die ("nothing in /proc - not mounted?"); +} + + +static void +do_stop(void) +{ + char what[1024]; + struct pid_list *p; + + if (cmdname) + strcpy(what, cmdname); + else if (execname) + strcpy(what, execname); + else if (userspec) + sprintf(what, "process(es) owned by `%s'", userspec); + else + error_msg_and_die ("internal error, please report"); + + if (!found) { + printf("no %s found; none killed.\n", what); + exit(0); + } + for (p = found; p; p = p->next) { + if (kill(p->pid, signal_nr) == 0) + push(&killed, p->pid); + else + printf("%s: warning: failed to kill %d: %s\n", + progname, p->pid, strerror(errno)); + } + if (killed) { + printf("stopped %s (pid", what); + for (p = killed; p; p = p->next) + printf(" %d", p->pid); + printf(").\n"); + } +} + + +int +start_stop_daemon_main(int argc, char **argv) +{ + progname = argv[0]; + + parse_options(argc, argv); + argc -= optind; + argv += optind; + + if (userspec && sscanf(userspec, "%d", &user_id) != 1) { + struct passwd *pw; + + pw = getpwnam(userspec); + if (!pw) + error_msg_and_die ("user `%s' not found\n", userspec); + + user_id = pw->pw_uid; + } + + do_procfs(); + + if (stop) { + do_stop(); + exit(0); + } + + if (found) { + printf("%s already running.\n", execname); + printf("%d\n",found->pid); + exit(0); + } + *--argv = startas; + execv(startas, argv); + perror_msg_and_die ("unable to start %s", startas); +} + diff --git a/include/applets.h b/include/applets.h index 461c878df..5ecfe3cba 100644 --- a/include/applets.h +++ b/include/applets.h @@ -386,6 +386,9 @@ #ifdef BB_SORT APPLET(sort, sort_main, _BB_DIR_USR_BIN) #endif +#ifdef BB_START_STOP_DAEMON + APPLET_ODDNAME("start-stop-daemon", start_stop_daemon_main, _BB_DIR_SBIN, start_stop_daemon) +#endif #ifdef BB_STTY APPLET(stty, stty_main, _BB_DIR_BIN) #endif diff --git a/include/usage.h b/include/usage.h index 0d830c9cc..5e514274a 100644 --- a/include/usage.h +++ b/include/usage.h @@ -1458,6 +1458,20 @@ "e\n" \ "f\n" +#define start_stop_daemon_trivial_usage \ + "[OPTIONS]" +#define start_stop_daemon_full_usage \ + "Program to start and stop services.\n"\ + "Options:\n" \ + "-S\t\t\tstart\n"\ + "-K\t\t\tstop\n"\ + "-x <executable>\t\tprogram to start/check if it is running\n"\ + "-p <pid-file>\t\tpid file to check\n"\ + "-u <username>|<uid>\tstop this user's processes\n"\ + "-n <process-name>\tstop processes with this name\n"\ + "-s <signal>\t\tsignal to send (default 15)\n"\ + "-a <pathname>\t\tprogram to start (default <executable>)\n" + #define stty_trivial_usage \ "[-a|g] [-F DEVICE] [SETTING]..." #define stty_full_usage \ diff --git a/init/start_stop_daemon.c b/init/start_stop_daemon.c new file mode 100644 index 000000000..0152283ad --- /dev/null +++ b/init/start_stop_daemon.c @@ -0,0 +1,271 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini start-stop-daemon implementation(s) for busybox + * + * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, + * public domain. + * Adapted for busybox David Kimdon <dwhedon@gordian.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <signal.h> +#include <errno.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <pwd.h> + +#include "busybox.h" + +static int start = 0; +static int stop = 0; +static int signal_nr = 15; +static int user_id = -1; +static const char *userspec = NULL; +static const char *cmdname = NULL; +static char *execname = NULL; +static char *startas = NULL; +static const char *progname = ""; + +struct pid_list { + struct pid_list *next; + int pid; +}; + +static struct pid_list *found = NULL; +static struct pid_list *killed = NULL; + +static void +push(struct pid_list **list, int pid) +{ + struct pid_list *p; + + p = xmalloc(sizeof(*p)); + p->next = *list; + p->pid = pid; + *list = p; +} + + +static void +parse_options(int argc, char * const *argv) +{ + + int c; + + for (;;) { + c = getopt (argc, argv, "a:n:s:u:x:KS"); + if (c == EOF) + break; + switch (c) { + case 'K': + stop = 1; + break; + case 'S': + start = 1; + break; + case 'a': + startas = optarg; + break; + case 'n': + cmdname = optarg; + break; + case 's': + if (sscanf(optarg, "%d", &signal_nr) != 1) + error_msg_and_die ("-s takes a numeric argument"); + break; + case 'u': + userspec = optarg; + break; + case 'x': + execname = optarg; + break; + default: + show_usage(); + exit(1); + } + } + + if (start == stop) + error_msg_and_die ("need one of -S or -K"); + + if (!execname && !userspec) + error_msg_and_die ("need at least one of -x or -u"); + + if (!startas) + startas = execname; + + if (start && !startas) + error_msg_and_die ("-S needs -x or -a"); +} + + +static int +pid_is_exec(int pid, const char *exec) +{ + char buf[PATH_MAX]; + FILE *fp; + + sprintf(buf, "/proc/%d/cmdline", pid); + fp = fopen(buf, "r"); + if (fp && fgets (buf, sizeof (buf), fp) ) { + if (strncmp (buf, exec, strlen(exec)) == 0) + return 1; + } + return 0; +} + + +static int +pid_is_user(int pid, int uid) +{ + struct stat sb; + char buf[32]; + + sprintf(buf, "/proc/%d", pid); + if (stat(buf, &sb) != 0) + return 0; + return (sb.st_uid == uid); +} + + +static int +pid_is_cmd(int pid, const char *name) +{ + char buf[32]; + FILE *f; + int c; + + sprintf(buf, "/proc/%d/stat", pid); + f = fopen(buf, "r"); + if (!f) + return 0; + while ((c = getc(f)) != EOF && c != '(') + ; + if (c != '(') { + fclose(f); + return 0; + } + /* this hopefully handles command names containing ')' */ + while ((c = getc(f)) != EOF && c == *name) + name++; + fclose(f); + return (c == ')' && *name == '\0'); +} + + +static void +check(int pid) +{ + if (execname && !pid_is_exec(pid, execname)) { + return; + } + if (userspec && !pid_is_user(pid, user_id)) { + return; + } + if (cmdname && !pid_is_cmd(pid, cmdname)) { + return; + } + push(&found, pid); +} + + + +static void +do_procfs(void) +{ + DIR *procdir; + struct dirent *entry; + int foundany, pid; + + procdir = opendir("/proc"); + if (!procdir) + perror_msg_and_die ("opendir /proc"); + + foundany = 0; + while ((entry = readdir(procdir)) != NULL) { + if (sscanf(entry->d_name, "%d", &pid) != 1) + continue; + foundany++; + check(pid); + } + closedir(procdir); + if (!foundany) + error_msg_and_die ("nothing in /proc - not mounted?"); +} + + +static void +do_stop(void) +{ + char what[1024]; + struct pid_list *p; + + if (cmdname) + strcpy(what, cmdname); + else if (execname) + strcpy(what, execname); + else if (userspec) + sprintf(what, "process(es) owned by `%s'", userspec); + else + error_msg_and_die ("internal error, please report"); + + if (!found) { + printf("no %s found; none killed.\n", what); + exit(0); + } + for (p = found; p; p = p->next) { + if (kill(p->pid, signal_nr) == 0) + push(&killed, p->pid); + else + printf("%s: warning: failed to kill %d: %s\n", + progname, p->pid, strerror(errno)); + } + if (killed) { + printf("stopped %s (pid", what); + for (p = killed; p; p = p->next) + printf(" %d", p->pid); + printf(").\n"); + } +} + + +int +start_stop_daemon_main(int argc, char **argv) +{ + progname = argv[0]; + + parse_options(argc, argv); + argc -= optind; + argv += optind; + + if (userspec && sscanf(userspec, "%d", &user_id) != 1) { + struct passwd *pw; + + pw = getpwnam(userspec); + if (!pw) + error_msg_and_die ("user `%s' not found\n", userspec); + + user_id = pw->pw_uid; + } + + do_procfs(); + + if (stop) { + do_stop(); + exit(0); + } + + if (found) { + printf("%s already running.\n", execname); + printf("%d\n",found->pid); + exit(0); + } + *--argv = startas; + execv(startas, argv); + perror_msg_and_die ("unable to start %s", startas); +} + diff --git a/start_stop_daemon.c b/start_stop_daemon.c new file mode 100644 index 000000000..0152283ad --- /dev/null +++ b/start_stop_daemon.c @@ -0,0 +1,271 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini start-stop-daemon implementation(s) for busybox + * + * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>, + * public domain. + * Adapted for busybox David Kimdon <dwhedon@gordian.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <signal.h> +#include <errno.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <pwd.h> + +#include "busybox.h" + +static int start = 0; +static int stop = 0; +static int signal_nr = 15; +static int user_id = -1; +static const char *userspec = NULL; +static const char *cmdname = NULL; +static char *execname = NULL; +static char *startas = NULL; +static const char *progname = ""; + +struct pid_list { + struct pid_list *next; + int pid; +}; + +static struct pid_list *found = NULL; +static struct pid_list *killed = NULL; + +static void +push(struct pid_list **list, int pid) +{ + struct pid_list *p; + + p = xmalloc(sizeof(*p)); + p->next = *list; + p->pid = pid; + *list = p; +} + + +static void +parse_options(int argc, char * const *argv) +{ + + int c; + + for (;;) { + c = getopt (argc, argv, "a:n:s:u:x:KS"); + if (c == EOF) + break; + switch (c) { + case 'K': + stop = 1; + break; + case 'S': + start = 1; + break; + case 'a': + startas = optarg; + break; + case 'n': + cmdname = optarg; + break; + case 's': + if (sscanf(optarg, "%d", &signal_nr) != 1) + error_msg_and_die ("-s takes a numeric argument"); + break; + case 'u': + userspec = optarg; + break; + case 'x': + execname = optarg; + break; + default: + show_usage(); + exit(1); + } + } + + if (start == stop) + error_msg_and_die ("need one of -S or -K"); + + if (!execname && !userspec) + error_msg_and_die ("need at least one of -x or -u"); + + if (!startas) + startas = execname; + + if (start && !startas) + error_msg_and_die ("-S needs -x or -a"); +} + + +static int +pid_is_exec(int pid, const char *exec) +{ + char buf[PATH_MAX]; + FILE *fp; + + sprintf(buf, "/proc/%d/cmdline", pid); + fp = fopen(buf, "r"); + if (fp && fgets (buf, sizeof (buf), fp) ) { + if (strncmp (buf, exec, strlen(exec)) == 0) + return 1; + } + return 0; +} + + +static int +pid_is_user(int pid, int uid) +{ + struct stat sb; + char buf[32]; + + sprintf(buf, "/proc/%d", pid); + if (stat(buf, &sb) != 0) + return 0; + return (sb.st_uid == uid); +} + + +static int +pid_is_cmd(int pid, const char *name) +{ + char buf[32]; + FILE *f; + int c; + + sprintf(buf, "/proc/%d/stat", pid); + f = fopen(buf, "r"); + if (!f) + return 0; + while ((c = getc(f)) != EOF && c != '(') + ; + if (c != '(') { + fclose(f); + return 0; + } + /* this hopefully handles command names containing ')' */ + while ((c = getc(f)) != EOF && c == *name) + name++; + fclose(f); + return (c == ')' && *name == '\0'); +} + + +static void +check(int pid) +{ + if (execname && !pid_is_exec(pid, execname)) { + return; + } + if (userspec && !pid_is_user(pid, user_id)) { + return; + } + if (cmdname && !pid_is_cmd(pid, cmdname)) { + return; + } + push(&found, pid); +} + + + +static void +do_procfs(void) +{ + DIR *procdir; + struct dirent *entry; + int foundany, pid; + + procdir = opendir("/proc"); + if (!procdir) + perror_msg_and_die ("opendir /proc"); + + foundany = 0; + while ((entry = readdir(procdir)) != NULL) { + if (sscanf(entry->d_name, "%d", &pid) != 1) + continue; + foundany++; + check(pid); + } + closedir(procdir); + if (!foundany) + error_msg_and_die ("nothing in /proc - not mounted?"); +} + + +static void +do_stop(void) +{ + char what[1024]; + struct pid_list *p; + + if (cmdname) + strcpy(what, cmdname); + else if (execname) + strcpy(what, execname); + else if (userspec) + sprintf(what, "process(es) owned by `%s'", userspec); + else + error_msg_and_die ("internal error, please report"); + + if (!found) { + printf("no %s found; none killed.\n", what); + exit(0); + } + for (p = found; p; p = p->next) { + if (kill(p->pid, signal_nr) == 0) + push(&killed, p->pid); + else + printf("%s: warning: failed to kill %d: %s\n", + progname, p->pid, strerror(errno)); + } + if (killed) { + printf("stopped %s (pid", what); + for (p = killed; p; p = p->next) + printf(" %d", p->pid); + printf(").\n"); + } +} + + +int +start_stop_daemon_main(int argc, char **argv) +{ + progname = argv[0]; + + parse_options(argc, argv); + argc -= optind; + argv += optind; + + if (userspec && sscanf(userspec, "%d", &user_id) != 1) { + struct passwd *pw; + + pw = getpwnam(userspec); + if (!pw) + error_msg_and_die ("user `%s' not found\n", userspec); + + user_id = pw->pw_uid; + } + + do_procfs(); + + if (stop) { + do_stop(); + exit(0); + } + + if (found) { + printf("%s already running.\n", execname); + printf("%d\n",found->pid); + exit(0); + } + *--argv = startas; + execv(startas, argv); + perror_msg_and_die ("unable to start %s", startas); +} + @@ -1458,6 +1458,20 @@ "e\n" \ "f\n" +#define start_stop_daemon_trivial_usage \ + "[OPTIONS]" +#define start_stop_daemon_full_usage \ + "Program to start and stop services.\n"\ + "Options:\n" \ + "-S\t\t\tstart\n"\ + "-K\t\t\tstop\n"\ + "-x <executable>\t\tprogram to start/check if it is running\n"\ + "-p <pid-file>\t\tpid file to check\n"\ + "-u <username>|<uid>\tstop this user's processes\n"\ + "-n <process-name>\tstop processes with this name\n"\ + "-s <signal>\t\tsignal to send (default 15)\n"\ + "-a <pathname>\t\tprogram to start (default <executable>)\n" + #define stty_trivial_usage \ "[-a|g] [-F DEVICE] [SETTING]..." #define stty_full_usage \ |