Sfoglia il codice sorgente

s-s-d: Add LSB --status command to check for process status

The new command follows the LSB Init Script status action specification,
and returns exit codes accordingly.
Guillem Jover 15 anni fa
parent
commit
5bced9fc3b
3 ha cambiato i file con 94 aggiunte e 25 eliminazioni
  1. 2 0
      debian/changelog
  2. 19 0
      man/start-stop-daemon.8
  3. 73 25
      utils/start-stop-daemon.c

+ 2 - 0
debian/changelog

@@ -47,6 +47,8 @@ dpkg (1.16.1) UNRELEASED; urgency=low
     “deselected”. Closes: #231089
   * Clarify exit status in dpkg-split and start-stop-daemon --help output.
   * Clarify “EXIT STATUS” section in man pages by using a table.
+  * Add a --status command to start-stop-daemon returning LSB Init Script
+    status action exit codes.
 
   [ Updated man page translations ]
   * German (Helge Kreutzmann).

+ 19 - 0
man/start-stop-daemon.8

@@ -69,6 +69,10 @@ is specified, then
 .B start\-stop\-daemon
 will check that the process(es) have terminated.
 .TP
+.BR \-T ", " \-\-status
+Check for the existence of a specified process, and returns an exit status
+code, according to the LSB Init Script Actions.
+.TP
 .BR \-H ", " \-\-help
 Show usage information and exit.
 .TP
@@ -279,6 +283,21 @@ still running.
 .TP
 .B 3
 Any other error.
+.PP
+When using the \fB\-\-status\fP command, the following status codes are
+returned:
+.TP
+.B 0
+Program is running.
+.TP
+.B 1
+Program is not running and the pid file exists.
+.TP
+.B 3
+Program is not running.
+.TP
+.B 4
+Unable to determine program status.
 .
 .SH EXAMPLE
 Start the \fBfood\fP daemon, unless one is already running (a process named

+ 73 - 25
utils/start-stop-daemon.c

@@ -141,6 +141,7 @@ enum action_code {
 	action_none,
 	action_start,
 	action_stop,
+	action_status,
 };
 
 static enum action_code action;
@@ -177,6 +178,14 @@ static struct stat exec_stat;
 static struct proc_stat_list *procset = NULL;
 #endif
 
+/* LSB Init Script process status exit codes. */
+enum status_code {
+	status_ok = 0,
+	status_dead_pidfile = 1,
+	status_dead_lockfile = 2,
+	status_dead = 3,
+	status_unknown = 4,
+};
 
 struct pid_list {
 	struct pid_list *next;
@@ -238,7 +247,10 @@ fatal(const char *format, ...)
 	else
 		fprintf(stderr, "\n");
 
-	exit(2);
+	if (action == action_status)
+		exit(status_unknown);
+	else
+		exit(2);
 }
 
 static void *
@@ -375,6 +387,7 @@ usage(void)
 "Commands:\n"
 "  -S|--start -- <argument> ...  start a program and pass <arguments> to it\n"
 "  -K|--stop                     stop a program\n"
+"  -T|--status                   get the program status\n"
 "  -H|--help                     print help information\n"
 "  -V|--version                  print version\n"
 "\n"
@@ -424,7 +437,12 @@ usage(void)
 "  0 = done\n"
 "  1 = nothing done (=> 0 if --oknodo)\n"
 "  2 = with --retry, processes would not die\n"
-"  3 = trouble\n");
+"  3 = trouble\n"
+"Exit status with --status:\n"
+"  0 = program is running\n"
+"  1 = program is not running and the pid file exists\n"
+"  3 = program is not running\n"
+"  4 = unable to determine status\n");
 }
 
 static void
@@ -441,7 +459,11 @@ badusage(const char *msg)
 	if (msg)
 		fprintf(stderr, "%s: %s\n", progname, msg);
 	fprintf(stderr, "Try '%s --help' for more information.\n", progname);
-	exit(3);
+
+	if (action == action_status)
+		exit(status_unknown);
+	else
+		exit(3);
 }
 
 struct sigpair {
@@ -735,6 +757,7 @@ parse_options(int argc, char * const *argv)
 		{ "help",	  0, NULL, 'H'},
 		{ "stop",	  0, NULL, 'K'},
 		{ "start",	  0, NULL, 'S'},
+		{ "status",	  0, NULL, 'T'},
 		{ "version",	  0, NULL, 'V'},
 		{ "startas",	  1, NULL, 'a'},
 		{ "name",	  1, NULL, 'n'},
@@ -768,7 +791,7 @@ parse_options(int argc, char * const *argv)
 
 	for (;;) {
 		c = getopt_long(argc, argv,
-		                "HKSVa:n:op:qr:s:tu:vx:c:N:P:I:k:bmR:g:d:",
+		                "HKSVTa:n:op:qr:s:tu:vx:c:N:P:I:k:bmR:g:d:",
 		                longopts, NULL);
 		if (c == -1)
 			break;
@@ -782,6 +805,9 @@ parse_options(int argc, char * const *argv)
 		case 'S':  /* --start */
 			set_action(action_start);
 			break;
+		case 'T':  /* --status */
+			set_action(action_status);
+			break;
 		case 'V':  /* --version */
 			do_version();
 			exit(0);
@@ -880,7 +906,7 @@ parse_options(int argc, char * const *argv)
 	}
 
 	if (action == action_none)
-		badusage("need one of --start or --stop");
+		badusage("need one of --start or --stop or --status");
 
 	if (!execname && !pidfile && !userspec && !cmdname)
 		badusage("need at least one of --exec, --pidfile, --user or --name");
@@ -1166,57 +1192,68 @@ pid_is_running(pid_t pid)
 }
 #endif
 
-static void
+static enum status_code
 pid_check(pid_t pid)
 {
 #if defined(OSLinux) || defined(OShpux)
 	if (execname && !pid_is_exec(pid, &exec_stat))
-		return;
+		return status_dead;
 #elif defined(HAVE_KVM_H)
 	if (execname && !pid_is_exec(pid, execname))
-		return;
+		return status_dead;
 #elif defined(OSHurd) || defined(OSFreeBSD) || defined(OSNetBSD)
 	/* Let's try this to see if it works. */
 	if (execname && !pid_is_cmd(pid, execname))
-		return;
+		return status_dead;
 #endif
 	if (userspec && !pid_is_user(pid, user_id))
-		return;
+		return status_dead;
 	if (cmdname && !pid_is_cmd(pid, cmdname))
-		return;
+		return status_dead;
 	if (action == action_start && !pid_is_running(pid))
-		return;
+		return status_dead;
+
 	pid_list_push(&found, pid);
+
+	return status_ok;
 }
 
-static void
+static enum status_code
 do_pidfile(const char *name)
 {
 	FILE *f;
 	static pid_t pid = 0;
 
-	if (pid) {
-		pid_check(pid);
-		return;
-	}
+	if (pid)
+		return pid_check(pid);
 
 	f = fopen(name, "r");
 	if (f) {
+		enum status_code pid_status;
+
 		if (fscanf(f, "%d", &pid) == 1)
-			pid_check(pid);
+			pid_status = pid_check(pid);
 		fclose(f);
-	} else if (errno != ENOENT)
+
+		if (pid_status == status_dead)
+			return status_dead_pidfile;
+		else
+			return pid_status;
+	} else if (errno == ENOENT)
+		return status_dead;
+	else
 		fatal("unable to open pidfile %s", name);
 }
 
 #if defined(OSLinux) || defined (OSsunos)
-static void
+static enum status_code
 do_procinit(void)
 {
 	DIR *procdir;
 	struct dirent *entry;
 	int foundany;
 	pid_t pid;
+	enum status_code prog_status = status_dead;
 
 	procdir = opendir("/proc");
 	if (!procdir)
@@ -1224,14 +1261,21 @@ do_procinit(void)
 
 	foundany = 0;
 	while ((entry = readdir(procdir)) != NULL) {
+		enum status_code pid_status;
+
 		if (sscanf(entry->d_name, "%d", &pid) != 1)
 			continue;
 		foundany++;
-		pid_check(pid);
+
+		pid_status = pid_check(pid);
+		if (pid_status < prog_status)
+			prog_status = pid_status;
 	}
 	closedir(procdir);
 	if (!foundany)
 		fatal("nothing in /proc - not mounted?");
+
+	return prog_status;
 }
 #elif defined(OSHurd)
 static int
@@ -1271,15 +1315,15 @@ do_procinit(void)
 }
 #endif
 
-static void
+static enum status_code
 do_findprocs(void)
 {
 	pid_list_free(&found);
 
 	if (pidfile)
-		do_pidfile(pidfile);
+		return do_pidfile(pidfile);
 	else
-		do_procinit();
+		return do_procinit();
 }
 
 static void
@@ -1492,6 +1536,7 @@ run_stop_schedule(void)
 int
 main(int argc, char **argv)
 {
+	enum status_code prog_status;
 	int devnull_fd = -1;
 	gid_t rgid;
 	uid_t ruid;
@@ -1562,7 +1607,10 @@ main(int argc, char **argv)
 		exit(i);
 	}
 
-	do_findprocs();
+	prog_status = do_findprocs();
+
+	if (action == action_status)
+		exit(prog_status);
 
 	if (found) {
 		if (quietmode <= 0)