svn commit: trunk/busybox: debianutils include

vda at busybox.net vda at busybox.net
Sun May 18 21:17:52 UTC 2008


Author: vda
Date: 2008-05-18 14:17:52 -0700 (Sun, 18 May 2008)
New Revision: 22002

Log:
start_stop_daemon: add -test, fix -x to not match by inode,
vastly improve hext text. (mostly by Roy Marples <roy AT marples.name>)

function                                             old     new   delta
packed_usage                                       24124   24190     +66
start_stop_daemon_main                               959     991     +32
start_stop_daemon_longopts                           149     156      +7
check                                               1632    1589     -43
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/1 up/down: 105/-43)            Total: 62 bytes



Modified:
   trunk/busybox/debianutils/start_stop_daemon.c
   trunk/busybox/include/usage.h


Changeset:
Modified: trunk/busybox/debianutils/start_stop_daemon.c
===================================================================
--- trunk/busybox/debianutils/start_stop_daemon.c	2008-05-18 15:14:36 UTC (rev 22001)
+++ trunk/busybox/debianutils/start_stop_daemon.c	2008-05-18 21:17:52 UTC (rev 22002)
@@ -23,15 +23,18 @@
 
 Options controlling process matching:
         -u,--user USERNAME|UID  Only consider this user's processes
-        -n,--name PROCESS_NAME  Look for processes with matching argv[0]
-                                or /proc/$PID/exe or /proc/$PID/stat (comm field).
+        -n,--name PROCESS_NAME  Look for processes by matching PROCESS_NAME
+                                with comm field in /proc/$PID/stat.
                                 Only basename is compared:
                                 "ntpd" == "./ntpd" == "/path/to/ntpd".
 [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 with matching /proc/$PID/exe.
-                                Match is performed using device+inode.
+        -x,--exec EXECUTABLE    Look for processes that were started with this
+                                command in /proc/$PID/cmdline.
+                                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
+If multiple conditions are specified, all must match.
 
 Options which are valid for --start only:
         -x,--exec EXECUTABLE    Program to run (1st arg of execvp). Mandatory.
@@ -41,8 +44,13 @@
         -c,--chuid USER[:[GRP]] Change to specified user [and group]
         -m,--make-pidfile       Write PID to the pidfile
                                 (both -m and -p must be given!)
+
+Options which are valid for --stop only:
+        -s,--signal SIG         Signal to send (default:TERM)
+        -t,--test               Exit with status 0 if process is found
+                                (we don't actually start or stop daemons)
+
 Misc options:
-        -s,--signal SIG         Signal to send (default:TERM)
         -o,--oknodo             Exit with status 0 if nothing is done
         -q,--quiet              Quiet
         -v,--verbose            Verbose
@@ -64,19 +72,21 @@
 	CTX_START      = (1 <<  1),
 	OPT_BACKGROUND = (1 <<  2), // -b
 	OPT_QUIET      = (1 <<  3), // -q
-	OPT_MAKEPID    = (1 <<  4), // -m
-	OPT_a          = (1 <<  5), // -a
-	OPT_n          = (1 <<  6), // -n
-	OPT_s          = (1 <<  7), // -s
-	OPT_u          = (1 <<  8), // -u
-	OPT_c          = (1 <<  9), // -c
-	OPT_x          = (1 << 10), // -x
-	OPT_p          = (1 << 11), // -p
-	OPT_OKNODO     = (1 << 12) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o
-	OPT_VERBOSE    = (1 << 13) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v
-	OPT_NICELEVEL  = (1 << 14) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N
+	OPT_TEST       = (1 <<  4), // -t
+	OPT_MAKEPID    = (1 <<  5), // -m
+	OPT_a          = (1 <<  6), // -a
+	OPT_n          = (1 <<  7), // -n
+	OPT_s          = (1 <<  8), // -s
+	OPT_u          = (1 <<  9), // -u
+	OPT_c          = (1 << 10), // -c
+	OPT_x          = (1 << 11), // -x
+	OPT_p          = (1 << 12), // -p
+	OPT_OKNODO     = (1 << 13) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o
+	OPT_VERBOSE    = (1 << 14) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v
+	OPT_NICELEVEL  = (1 << 15) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N
 };
 #define QUIET (option_mask32 & OPT_QUIET)
+#define TEST  (option_mask32 & OPT_TEST)
 
 struct globals {
 	struct pid_list *found;
@@ -86,7 +96,6 @@
 	char *pidfile;
 	int user_id;
 	smallint signal_nr;
-	struct stat execstat;
 };
 #define G (*(struct globals*)&bb_common_bufsiz1)
 #define found             (G.found               )
@@ -96,20 +105,23 @@
 #define pidfile           (G.pidfile             )
 #define user_id           (G.user_id             )
 #define signal_nr         (G.signal_nr           )
-#define execstat          (G.execstat            )
 #define INIT_G() \
         do { \
 		user_id = -1; \
 		signal_nr = 15; \
         } while (0)
 
-
+#ifdef OLDER_VERSION_OF_X
+/* -x,--exec EXECUTABLE
+ * Look for processes with matching /proc/$PID/exe.
+ * Match is performed using device+inode.
+ */
 static int pid_is_exec(pid_t pid)
 {
 	struct stat st;
 	char buf[sizeof("/proc//exe") + sizeof(int)*3];
 
-	sprintf(buf, "/proc/%u/exe", pid);
+	sprintf(buf, "/proc/%u/exe", (unsigned)pid);
 	if (stat(buf, &st) < 0)
 		return 0;
 	if (st.st_dev == execstat.st_dev
@@ -117,24 +129,29 @@
 		return 1;
 	return 0;
 }
+#endif
 
-static int pid_is_user(int pid)
+static int pid_is_exec(pid_t pid)
 {
-	struct stat sb;
-	char buf[sizeof("/proc/") + sizeof(int)*3];
+	ssize_t bytes;
+	char buf[PATH_MAX];
 
-	sprintf(buf, "/proc/%u", pid);
-	if (stat(buf, &sb) != 0)
-		return 0;
-	return (sb.st_uid == (uid_t)user_id);
+	sprintf(buf, "/proc/%u/cmdline", (unsigned)pid);
+	bytes = open_read_close(buf, buf, sizeof(buf) - 1);
+	if (bytes > 0) {
+		buf[bytes] = '\0';
+		return strcmp(buf, execname) == 0;
+	}
+	return 0;
 }
 
-static int pid_is_cmd(pid_t pid)
+static int pid_is_name(pid_t pid)
 {
-	char buf[256]; /* is it big enough? */
+	/* /proc/PID/stat is "PID (comm_15_bytes_max) ..." */
+	char buf[32]; /* should be enough */
 	char *p, *pe;
 
-	sprintf(buf, "/proc/%u/stat", pid);
+	sprintf(buf, "/proc/%u/stat", (unsigned)pid);
 	if (open_read_close(buf, buf, sizeof(buf) - 1) < 0)
 		return 0;
 	buf[sizeof(buf) - 1] = '\0'; /* paranoia */
@@ -145,9 +162,25 @@
 	if (!pe)
 		return 0;
 	*pe = '\0';
-	return !strcmp(p, cmdname);
+	/* we require comm to match and to not be truncated */
+	/* in Linux, if comm is 15 chars, it may be a truncated
+	 * name, so we don't allow that to match */
+	if (strlen(p) >= COMM_LEN - 1) /* COMM_LEN is 16 */
+		return 0;
+	return strcmp(p, cmdname) == 0;
 }
 
+static int pid_is_user(int pid)
+{
+	struct stat sb;
+	char buf[sizeof("/proc/") + sizeof(int)*3];
+
+	sprintf(buf, "/proc/%u", (unsigned)pid);
+	if (stat(buf, &sb) != 0)
+		return 0;
+	return (sb.st_uid == (uid_t)user_id);
+}
+
 static void check(int pid)
 {
 	struct pid_list *p;
@@ -155,10 +188,10 @@
 	if (execname && !pid_is_exec(pid)) {
 		return;
 	}
-	if (userspec && !pid_is_user(pid)) {
+	if (cmdname && !pid_is_name(pid)) {
 		return;
 	}
-	if (cmdname && !pid_is_cmd(pid)) {
+	if (userspec && !pid_is_user(pid)) {
 		return;
 	}
 	p = xmalloc(sizeof(*p));
@@ -195,10 +228,11 @@
 	procdir = xopendir("/proc");
 
 	pid = 0;
-	while(1) {
+	while (1) {
 		errno = 0; /* clear any previous error */
 		entry = readdir(procdir);
-// TODO: check for exact errno(s) which mean that we got stale entry
+// TODO: this check is too generic, it's better
+// to check for exact errno(s) which mean that we got stale entry
 		if (errno) /* Stale entry, process has died after opendir */
 			continue;
 		if (!entry) /* EOF, no more entries */
@@ -225,12 +259,13 @@
 	} else if (execname) {
 		if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(execname);
 		if (!ENABLE_FEATURE_CLEAN_UP) what = execname;
-	} else if (pidfile)
+	} else if (pidfile) {
 		what = xasprintf("process in pidfile '%s'", pidfile);
-	else if (userspec)
+	} else if (userspec) {
 		what = xasprintf("process(es) owned by '%s'", userspec);
-	else
+	} else {
 		bb_error_msg_and_die("internal error, please report");
+	}
 
 	if (!found) {
 		if (!QUIET)
@@ -239,18 +274,18 @@
 		goto ret;
 	}
 	for (p = found; p; p = p->next) {
-		if (kill(p->pid, signal_nr) == 0) {
-			p->pid = - p->pid;
+		if (TEST || kill(p->pid, signal_nr) == 0) {
 			killed++;
 		} else {
-			bb_perror_msg("warning: killing process %u", p->pid);
+			p->pid = 0;
+			bb_perror_msg("warning: killing process %u", (unsigned)p->pid);
 		}
 	}
 	if (!QUIET && killed) {
 		printf("stopped %s (pid", what);
 		for (p = found; p; p = p->next)
-			if (p->pid < 0)
-				printf(" %u", - p->pid);
+			if (p->pid)
+				printf(" %u", (unsigned)p->pid);
 		puts(")");
 	}
  ret:
@@ -265,6 +300,7 @@
 	"start\0"        No_argument       "S"
 	"background\0"   No_argument       "b"
 	"quiet\0"        No_argument       "q"
+	"test\0"         No_argument       "t"
 	"make-pidfile\0" No_argument       "m"
 #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
 	"oknodo\0"       No_argument       "o"
@@ -291,6 +327,7 @@
 	char *signame;
 	char *startas;
 	char *chuid;
+	struct stat execstat;
 #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
 //	char *retry_arg = NULL;
 //	int retries = -1;
@@ -310,7 +347,7 @@
 	/* -q turns off -v */
 	opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa"
 		USE_FEATURE_START_STOP_DAEMON_FANCY("q-v");
-	opt = getopt32(argv, "KSbqma:n:s:u:c:x:p:"
+	opt = getopt32(argv, "KSbqtma:n:s:u:c:x:p:"
 		USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:"),
 //		USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"),
 		&startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile
@@ -338,9 +375,6 @@
 		if (errno)
 			user_id = xuname2uid(userspec);
 	}
-	if (execname)
-		xstat(execname, &execstat);
-
 	do_procinit(); /* Both start and stop needs to know current processes */
 
 	if (opt & CTX_STOP) {
@@ -353,6 +387,10 @@
 			printf("%s already running\n%d\n", execname, found->pid);
 		return !(opt & OPT_OKNODO);
 	}
+
+	if (execname)
+		xstat(execname, &execstat);
+
 	*--argv = startas;
 	if (opt & OPT_BACKGROUND) {
 #if BB_MMU

Modified: trunk/busybox/include/usage.h
===================================================================
--- trunk/busybox/include/usage.h	2008-05-18 15:14:36 UTC (rev 22001)
+++ trunk/busybox/include/usage.h	2008-05-18 21:17:52 UTC (rev 22002)
@@ -3613,46 +3613,65 @@
 	USE_GETOPT_LONG("--start|--stop") SKIP_GETOPT_LONG("-S|-K") \
        "] ... [-- arguments...]"
 #define start_stop_daemon_full_usage "\n\n" \
-       "Start and stop services\n" \
-     "\nOptions:" \
+       "Search for matching processes, and then\n" \
+       "-S: stop all matching processes.\n" \
+       "-K: start a process unless a matching process is found.\n" \
 	USE_GETOPT_LONG( \
-     "\n	-S,--start		Start" \
-     "\n	-K,--stop		Stop" \
-     "\n	-a,--startas pathname	Start process specified by pathname" \
-     "\n	-b,--background		Put process into background" \
-     "\n	-u,--user username|uid	Stop this user's processes" \
-     "\n	-x,--exec executable	Program to either start or check" \
-     "\n	-n,--name process-name	Stop processes with this name" \
-     "\n	-p,--pidfile pid-file	Save or load pid using a pid-file" \
-     "\n	-m,--make-pidfile	Create the -p file and enter pid in it" \
+     "\nProcess matching:" \
+     "\n	-u,--user USERNAME|UID	Match only this user's processes" \
+     "\n	-n,--name NAME		Match processes with NAME" \
+     "\n				in comm field in /proc/PID/stat" \
+     "\n	-x,--exec EXECUTABLE	Match processes with this command" \
+     "\n				in /proc/PID/cmdline" \
+     "\n	-p,--pidfile FILE	Match a process with PID from the file" \
+     "\n	All specified conditions must match" \
+     "\n-K only:" \
+     "\n	-x,--exec EXECUTABLE	Program to run" \
+     "\n	-a,--startas NAME	Zeroth argument" \
+     "\n	-b,--background		Background" \
+	USE_FEATURE_START_STOP_DAEMON_FANCY( \
+     "\n	-N,--nicelevel N	Change nice level" \
+	) \
+     "\n	-c,--chuid USER[:[GRP]]	Change to user/group" \
+     "\n	-m,--make-pidfile	Write PID to the pidfile specified by -p" \
+     "\n-S only:" \
+     "\n	-s,--signal SIG		Signal to send" \
+     "\n	-t,--test		Match only, exit with 0 if a process is found" \
+     "\nOther:" \
+	USE_FEATURE_START_STOP_DAEMON_FANCY( \
+     "\n	-o,--oknodo		Exit with status 0 if nothing is done" \
      "\n	-q,--quiet		Quiet" \
-	USE_FEATURE_START_STOP_DAEMON_FANCY( \
-     "\n	-o,--oknodo		Exit status 0 if nothing done" \
+	) \
      "\n	-v,--verbose		Verbose" \
-     "\n	-N,--nicelevel N	Add N to process's nice level" \
 	) \
-     "\n	-s,--signal signal	Signal to send (default TERM)" \
-     "\n	-c,--chuid user[:[grp]]	Change to specified user/group" \
+	SKIP_GETOPT_LONG( \
+     "\nProcess matching:" \
+     "\n	-u USERNAME|UID	Match only this user's processes" \
+     "\n	-n NAME		Match processes with NAME" \
+     "\n			in comm field in /proc/PID/stat" \
+     "\n	-x EXECUTABLE	Match processes with this command" \
+     "\n			command in /proc/PID/cmdline" \
+     "\n	-p FILE		Match a process with PID from the file" \
+     "\n	All specified conditions must match" \
+     "\n-K only:" \
+     "\n	-x EXECUTABLE	Program to run" \
+     "\n	-a NAME		Zeroth argument" \
+     "\n	-b		Background" \
+	USE_FEATURE_START_STOP_DAEMON_FANCY( \
+     "\n	-N N		Change nice level" \
 	) \
-	SKIP_GETOPT_LONG( \
-     "\n	-S		Start" \
-     "\n	-K		Stop" \
-     "\n	-a pathname	Start process specified by pathname" \
-     "\n	-b		Put process into background" \
-     "\n	-u username|uid	Stop this user's processes" \
-     "\n	-x executable	Program to either start or check" \
-     "\n	-n process-name	Stop processes with this name" \
-     "\n	-p pid-file	Save or load pid using a pid-file" \
-     "\n	-m		Create the -p file and enter pid in it" \
+     "\n	-c USER[:[GRP]]	Change to user/group" \
+     "\n	-m		Write PID to the pidfile specified by -p" \
+     "\n-S only:" \
+     "\n	-s SIG		Signal to send" \
+     "\n	-t		Match only, exit with 0 if a process is found" \
+     "\nOther:" \
+	USE_FEATURE_START_STOP_DAEMON_FANCY( \
+     "\n	-o		Exit with status 0 if nothing is done" \
      "\n	-q		Quiet" \
-	USE_FEATURE_START_STOP_DAEMON_FANCY( \
-     "\n	-o		Exit status 0 if nothing done" \
+	) \
      "\n	-v		Verbose" \
-     "\n	-N N		Add N to process's nice level" \
 	) \
-     "\n	-s signal	Signal to send (default TERM)" \
-     "\n	-c user[:[grp]]	Change to specified user/group" \
-	)
 
 #define stat_trivial_usage \
        "[OPTION] FILE..."




More information about the busybox-cvs mailing list