[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH] Add --cmdpart to filter processes by argv elements.



The user can supplies a list of strings by using --cmdpart multiple
times, such as

$ start-stop-daemon --cmdpart /usr/bin/python --cmdpart mydaemon.py ....

This list is prefix-matched against the argv list of existing
processes. Only matching processes are considered to be the daemon in
question. As by the example above, the main intended use case is
allowing start-stop-daemon to detect running scripts.

This is only implemented for Linux ATM, making use of
/proc/pid/cmdline.
---
 utils/start-stop-daemon.c | 54 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 52 insertions(+), 2 deletions(-)

diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c
index 93850e3..0f34b6a 100644
--- a/utils/start-stop-daemon.c
+++ b/utils/start-stop-daemon.c
@@ -178,6 +178,8 @@ static const char *changegroup = NULL;
 static char *changeroot = NULL;
 static const char *changedir = "/";
 static const char *cmdname = NULL;
+static const char **cmdparts_v = NULL;
+static unsigned int cmdparts_c = 0;
 static char *execname = NULL;
 static char *startas = NULL;
 static pid_t match_pid = -1;
@@ -451,6 +453,8 @@ usage(void)
 "  -x|--exec <executable>        program to start/check if it is running\n"
 "  -n|--name <process-name>      process name to check\n"
 "  -u|--user <username|uid>      process owner to check\n"
+"    |--cmdpart <cmdpart>        sequentially check process arguments, can be\n"
+"                                specified multiple times.\n"
 "\n"
 "Options:\n"
 "  -g|--group <group|gid>        run process as this group\n"
@@ -814,6 +818,7 @@ set_action(enum action_code new_action)
 
 #define OPT_PID		500
 #define OPT_PPID	501
+#define OPT_CMDPART	502
 
 static void
 parse_options(int argc, char * const *argv)
@@ -848,6 +853,7 @@ parse_options(int argc, char * const *argv)
 		{ "make-pidfile", 0, NULL, 'm'},
 		{ "retry",	  1, NULL, 'R'},
 		{ "chdir",	  1, NULL, 'd'},
+		{ "cmdpart",	  1, NULL, OPT_CMDPART},
 		{ NULL,		  0, NULL, 0  }
 	};
 	const char *pid_str = NULL;
@@ -957,6 +963,10 @@ parse_options(int argc, char * const *argv)
 		case 'd':  /* --chdir /new/dir */
 			changedir = optarg;
 			break;
+		case OPT_CMDPART:  /* --cmdpart /bin/bash --cmdpart some-script.sh */
+		        cmdparts_v = realloc(cmdparts_v, (cmdparts_c + 1) * sizeof(char *));
+			cmdparts_v[cmdparts_c++] = optarg;
+			break;
 		default:
 			/* Message printed by getopt. */
 			badusage(NULL);
@@ -998,8 +1008,8 @@ parse_options(int argc, char * const *argv)
 		badusage("need one of --start or --stop or --status");
 
 	if (!execname && !pid_str && !ppid_str && !pidfile && !userspec &&
-	    !cmdname)
-		badusage("need at least one of --exec, --pid, --ppid, --pidfile, --user or --name");
+	    !cmdname && !cmdparts_c)
+		badusage("need at least one of --exec, --pid, --ppid, --pidfile, --user, --name or --cmdparts");
 
 #ifdef PROCESS_NAME_SIZE
 	if (cmdname && strlen(cmdname) > PROCESS_NAME_SIZE)
@@ -1543,6 +1553,44 @@ pid_is_running(pid_t pid)
 }
 #endif
 
+#if defined(OSLinux)
+static bool
+pid_has_cmdparts(pid_t pid)
+{
+	char filename[32];
+	FILE *fp;
+	unsigned int i, res = false, len = 0;
+	char *prefix = NULL, *cmdline = NULL;
+
+	sprintf(filename, "/proc/%d/cmdline", pid);
+	fp = fopen(filename, "r");
+	if (!fp)
+		return NULL;
+
+	for (i = 0; i < cmdparts_c; i++) {
+		unsigned int new_len = len + strlen(cmdparts_v[i]) + 1;
+		prefix = realloc(prefix, new_len);
+		strcpy(prefix + len, cmdparts_v[i]);
+		len = new_len;
+	}
+
+	cmdline = malloc(len);
+	if (fread(cmdline, 1, len, fp) == len &&
+	   !memcmp(cmdline, prefix, len)) {
+		res = true;
+	}
+	free(cmdline);
+	free(prefix);
+	fclose(fp);
+	return res;
+}
+#else /* !OSLinux */
+static bool
+pid_has_cmdparts(pid_t pid)
+{
+	fatal("argv prefix matching not implemented for your OS.");
+}
+#endif
 static enum status_code
 pid_check(pid_t pid)
 {
@@ -1554,6 +1602,8 @@ pid_check(pid_t pid)
 		return STATUS_DEAD;
 	if (cmdname && !pid_is_cmd(pid, cmdname))
 		return STATUS_DEAD;
+	if (cmdparts_c && !pid_has_cmdparts(pid))
+		return STATUS_DEAD;
 	if (action != ACTION_STOP && !pid_is_running(pid))
 		return STATUS_DEAD;
 
-- 
2.1.0


Reply to: