summaryrefslogtreecommitdiff
path: root/utils/start-stop-daemon.c
diff options
context:
space:
mode:
authorGuillem Jover <guillem@debian.org>2014-03-26 17:26:26 +0100
committerGuillem Jover <guillem@debian.org>2014-04-21 16:54:28 +0200
commit3fabf94e0b5fe1bcdea26fecee1c87e74fab98b2 (patch)
tree1c3272d77659bb9ae3c33a105215dff1fc26a974 /utils/start-stop-daemon.c
parent861e165c26d2f62e658d95aedd2746ce0c7445e2 (diff)
downloaddpkg-3fabf94e0b5fe1bcdea26fecee1c87e74fab98b2.tar.gz
s-s-d: Add a new --ppid matching option
This allows to check for processes with a specific parent PID. Suggested-by: Alex Mestiashvili <mailatgoogl@gmail.com>
Diffstat (limited to 'utils/start-stop-daemon.c')
-rw-r--r--utils/start-stop-daemon.c93
1 files changed, 91 insertions, 2 deletions
diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c
index 9c5cfcbdd..1d93a6168 100644
--- a/utils/start-stop-daemon.c
+++ b/utils/start-stop-daemon.c
@@ -176,6 +176,7 @@ static const char *cmdname = NULL;
static char *execname = NULL;
static char *startas = NULL;
static pid_t match_pid = -1;
+static pid_t match_ppid = -1;
static const char *pidfile = NULL;
static char what_stop[1024];
static const char *progname = "";
@@ -440,6 +441,7 @@ usage(void)
"\n"
"Matching options (at least one is required):\n"
" --pid <pid> pid to check\n"
+" --ppid <ppid> parent pid to check\n"
" -p|--pidfile <pid-file> pid file to check\n"
" -x|--exec <executable> program to start/check if it is running\n"
" -n|--name <process-name> process name to check\n"
@@ -806,6 +808,7 @@ set_action(enum action_code new_action)
}
#define OPT_PID 500
+#define OPT_PPID 501
static void
parse_options(int argc, char * const *argv)
@@ -820,6 +823,7 @@ parse_options(int argc, char * const *argv)
{ "name", 1, NULL, 'n'},
{ "oknodo", 0, NULL, 'o'},
{ "pid", 1, NULL, OPT_PID},
+ { "ppid", 1, NULL, OPT_PPID},
{ "pidfile", 1, NULL, 'p'},
{ "quiet", 0, NULL, 'q'},
{ "signal", 1, NULL, 's'},
@@ -842,6 +846,7 @@ parse_options(int argc, char * const *argv)
{ NULL, 0, NULL, 0 }
};
const char *pid_str = NULL;
+ const char *ppid_str = NULL;
const char *umask_str = NULL;
const char *signal_str = NULL;
const char *schedule_str = NULL;
@@ -883,6 +888,9 @@ parse_options(int argc, char * const *argv)
case OPT_PID: /* --pid <pid> */
pid_str = optarg;
break;
+ case OPT_PPID: /* --ppid <ppid> */
+ ppid_str = optarg;
+ break;
case 'p': /* --pidfile <pid-file> */
pidfile = optarg;
break;
@@ -955,6 +963,11 @@ parse_options(int argc, char * const *argv)
badusage("pid value must be a number greater than 0");
}
+ if (ppid_str != NULL) {
+ if (parse_pid(ppid_str, &match_ppid) != 0)
+ badusage("ppid value must be a number greater than 0");
+ }
+
if (signal_str != NULL) {
if (parse_signal(signal_str, &signal_nr) != 0)
badusage("signal value must be numeric or name"
@@ -979,8 +992,9 @@ parse_options(int argc, char * const *argv)
if (action == action_none)
badusage("need one of --start or --stop or --status");
- if (!execname && !pid_str && !pidfile && !userspec && !cmdname)
- badusage("need at least one of --exec, --pid, --pidfile, --user or --name");
+ if (!execname && !pid_str && !ppid_str && !pidfile && !userspec &&
+ !cmdname)
+ badusage("need at least one of --exec, --pid, --ppid, --pidfile, --user or --name");
#ifdef PROCESS_NAME_SIZE
if (cmdname && strlen(cmdname) > PROCESS_NAME_SIZE)
@@ -1275,6 +1289,79 @@ pid_is_exec(pid_t pid, const struct stat *esb)
#if defined(OSLinux)
static bool
+pid_is_child(pid_t pid, pid_t ppid)
+{
+ const char *ppid_str;
+ pid_t proc_ppid;
+ int rc;
+
+ ppid_str = proc_status_field(pid, "PPid:");
+ if (ppid_str == NULL)
+ return false;
+
+ rc = parse_pid(ppid_str, &proc_ppid);
+ if (rc < 0)
+ return false;
+
+ return proc_ppid == ppid;
+}
+#elif defined(OSHurd)
+static bool
+pid_is_child(pid_t pid, pid_t ppid)
+{
+ struct proc_stat *ps;
+ struct procinfo *pi;
+
+ ps = get_proc_stat(pid, PSTAT_PROC_INFO);
+ if (ps == NULL)
+ return false;
+
+ pi = proc_stat_proc_info(ps);
+
+ return pi->ppid == ppid;
+}
+#elif defined(OShpux)
+static bool
+pid_is_child(pid_t pid, pid_t ppid)
+{
+ struct pst_status pst;
+
+ if (pstat_getproc(&pst, sizeof(pst), (size_t)0, (int)pid) < 0)
+ return false;
+
+ return pst.pst_ppid == ppid;
+}
+#elif defined(HAVE_KVM_H)
+static bool
+pid_is_child(pid_t pid, pid_t ppid)
+{
+ kvm_t *kd;
+ int nentries;
+ struct kinfo_proc *kp;
+ char errbuf[_POSIX2_LINE_MAX];
+ pid_t proc_ppid;
+
+ kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
+ if (kd == NULL)
+ errx(1, "%s", errbuf);
+ kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries);
+ if (kp == NULL)
+ errx(1, "%s", kvm_geterr(kd));
+
+#if defined(OSFreeBSD)
+ proc_ppid = kp->ki_ppid;
+#elif defined(OSOpenBSD)
+ proc_ppid = kp->p_ppid;
+#else
+ proc_ppid = kp->kp_proc.p_ppid;
+#endif
+
+ return proc_ppid == ppid;
+}
+#endif
+
+#if defined(OSLinux)
+static bool
pid_is_user(pid_t pid, uid_t uid)
{
struct stat sb;
@@ -1444,6 +1531,8 @@ pid_check(pid_t pid)
{
if (execname && !pid_is_exec(pid, &exec_stat))
return status_dead;
+ if (match_ppid > 0 && !pid_is_child(pid, match_ppid))
+ return status_dead;
if (userspec && !pid_is_user(pid, user_id))
return status_dead;
if (cmdname && !pid_is_cmd(pid, cmdname))