Просмотр исходного кода

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
Родитель
Сommit
5bced9fc3b
3 измененных файлов с 94 добавлено и 25 удалено
  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)