[BusyBox] start-stop-daemon

David Kimdon dwhedon at gordian.com
Fri Sep 7 14:35:03 UTC 2001


As discussed earlier here is a busybox start-stop-daemon applet.  I have
been using it for a few weeks without problems.  

One issue is that the executable really should be called start-stop-daemon,
but the bb build system didn't take to that filename very well, so I named
it start_stop_daemon.

Okay to commit?

-David

Index: Config.h
===================================================================
RCS file: /var/cvs/busybox/Config.h,v
retrieving revision 1.103
diff -u -r1.103 Config.h
--- Config.h	2001/08/21 23:34:10	1.103
+++ Config.h	2001/09/07 20:27:07
@@ -113,6 +113,7 @@
 #define BB_SLEEP
 #define BB_SORT
 //#define BB_STTY
+//#define BB_START_STOP_DAEMON
 #define BB_SWAPONOFF
 #define BB_SYNC
 #define BB_SYSLOGD
Index: applets.h
===================================================================
RCS file: /var/cvs/busybox/applets.h,v
retrieving revision 1.40
diff -u -r1.40 applets.h
--- applets.h	2001/08/27 18:55:05	1.40
+++ applets.h	2001/09/07 20:27:08
@@ -383,6 +383,9 @@
 #ifdef BB_SORT
 	APPLET(sort, sort_main, _BB_DIR_USR_BIN)
 #endif
+#ifdef BB_START_STOP_DAEMON
+	APPLET(start_stop_daemon, start_stop_daemon_main, _BB_DIR_SBIN)
+#endif
 #ifdef BB_STTY
 	APPLET(stty, stty_main, _BB_DIR_BIN)
 #endif
Index: usage.h
===================================================================
RCS file: /var/cvs/busybox/usage.h,v
retrieving revision 1.62
diff -u -r1.62 usage.h
--- usage.h	2001/08/27 18:55:05	1.62
+++ usage.h	2001/09/07 20:27:14
@@ -1452,6 +1452,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 \
--- /dev/null	Thu Nov 30 07:25:58 2000
+++ start_stop_daemon.c	Thu Sep  6 10:16:45 2001
@@ -0,0 +1,271 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Mini start-stop-daemon implementation(s) for busybox
+ *
+ * Written by Marek Michalkiewicz <marekm at i17linuxb.ists.pwr.wroc.pl>,
+ * public domain.
+ * Adapted for busybox David Kimdon <dwhedon at 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);
+}
+





More information about the busybox mailing list