We need to be able to locate pids by argv, instead of just argv0.

This commit is contained in:
Roy Marples 2008-02-17 15:12:00 +00:00
parent fbdc85f3b3
commit 27f97f2106
3 changed files with 104 additions and 43 deletions

View File

@ -58,7 +58,7 @@ static bool pid_is_cmd (pid_t pid, const char *cmd)
return ((c == ')' && *cmd == '\0') ? true : false); return ((c == ')' && *cmd == '\0') ? true : false);
} }
static bool pid_is_exec (pid_t pid, const char *exec) static bool pid_is_exec (pid_t pid, const char *const *argv)
{ {
char cmdline[32]; char cmdline[32];
char buffer[PATH_MAX]; char buffer[PATH_MAX];
@ -68,6 +68,7 @@ static bool pid_is_exec (pid_t pid, const char *exec)
snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid); snprintf (cmdline, sizeof (cmdline), "/proc/%u/exe", pid);
memset (buffer, 0, sizeof (buffer)); memset (buffer, 0, sizeof (buffer));
#if 0
if (readlink (cmdline, buffer, sizeof (buffer)) != -1) { if (readlink (cmdline, buffer, sizeof (buffer)) != -1) {
if (strcmp (exec, buffer) == 0) if (strcmp (exec, buffer) == 0)
return (true); return (true);
@ -82,22 +83,32 @@ static bool pid_is_exec (pid_t pid, const char *exec)
} }
} }
} }
#endif
snprintf (cmdline, sizeof (cmdline), "/proc/%u/cmdline", pid); snprintf (cmdline, sizeof (cmdline), "/proc/%u/cmdline", pid);
if ((fd = open (cmdline, O_RDONLY)) < 0) if ((fd = open (cmdline, O_RDONLY)) < 0)
return (false); return (false);
r = read(fd, buffer, sizeof (buffer)); r = read (fd, buffer, sizeof (buffer));
close (fd); close (fd);
if (r == -1) if (r == -1)
return 0; return 0;
buffer[r] = 0; buffer[r] = 0;
return (strcmp (exec, buffer) == 0 ? true : false); p = buffer;
while (*argv) {
if (strcmp (*argv, p) != 0)
return (false);
argv++;
p += strlen (p) + 1;
if (p - buffer > (unsigned) sizeof (buffer))
return (false);
}
return (true);
} }
pid_t *rc_find_pids (const char *exec, const char *cmd, pid_t *rc_find_pids (const char *const *argv, const char *cmd,
uid_t uid, pid_t pid) uid_t uid, pid_t pid)
{ {
DIR *procdir; DIR *procdir;
@ -149,7 +160,7 @@ pid_t *rc_find_pids (const char *exec, const char *cmd,
if (cmd && ! pid_is_cmd (p, cmd)) if (cmd && ! pid_is_cmd (p, cmd))
continue; continue;
if (exec && ! cmd && ! pid_is_exec (p, exec)) if (argv && ! cmd && ! pid_is_exec (p, (const char *const *)argv))
continue; continue;
tmp = realloc (pids, sizeof (pid_t) * (npids + 2)); tmp = realloc (pids, sizeof (pid_t) * (npids + 2));
@ -193,7 +204,7 @@ librc_hidden_def(rc_find_pids)
# define _KVM_PATH NULL # define _KVM_PATH NULL
# endif # endif
pid_t *rc_find_pids (const char *exec, const char *cmd, pid_t *rc_find_pids (const char *const *argv, const char *cmd,
uid_t uid, pid_t pid) uid_t uid, pid_t pid)
{ {
static kvm_t *kd = NULL; static kvm_t *kd = NULL;
@ -201,11 +212,13 @@ pid_t *rc_find_pids (const char *exec, const char *cmd,
struct _KINFO_PROC *kp; struct _KINFO_PROC *kp;
int i; int i;
int processes = 0; int processes = 0;
int argc = 0; int pargc = 0;
char **argv; char **pargv;
pid_t *pids = NULL; pid_t *pids = NULL;
pid_t *tmp; pid_t *tmp;
char *arg;
int npids = 0; int npids = 0;
int match;
if ((kd = kvm_openfiles (_KVM_PATH, _KVM_PATH, if ((kd = kvm_openfiles (_KVM_PATH, _KVM_PATH,
NULL, O_RDONLY, errbuf)) == NULL) NULL, O_RDONLY, errbuf)) == NULL)
@ -239,11 +252,21 @@ pid_t *rc_find_pids (const char *exec, const char *cmd,
continue; continue;
} }
if (exec && ! cmd) { if (argv && ! cmd) {
if ((argv = _KVM_GETARGV (kd, &kp[i], argc)) == NULL || ! *argv) pargv = _KVM_GETARGV (kd, &kp[i], pargc);
if (! pargv || ! *pargv)
continue; continue;
if (strcmp (*argv, exec) != 0) arg = argv;
match = 1;
while (arg && *pargv)
if (strcmp (arg++, *pargv++) != 0) {
match = 0;
break;
}
if (! match)
continue; continue;
} }
@ -312,7 +335,7 @@ static bool _match_daemon (const char *path, const char *file,
return (m == 111 ? true : false); return (m == 111 ? true : false);
} }
bool rc_service_daemon_set (const char *service, const char *exec, bool rc_service_daemon_set (const char *service, const char *const *argv,
const char *name, const char *pidfile, const char *name, const char *pidfile,
bool started) bool started)
{ {
@ -328,7 +351,7 @@ bool rc_service_daemon_set (const char *service, const char *exec,
DIR *dp; DIR *dp;
struct dirent *d; struct dirent *d;
if (! exec && ! name && ! pidfile) { if (! argv && ! name && ! pidfile) {
errno = EINVAL; errno = EINVAL;
return (false); return (false);
} }
@ -336,10 +359,10 @@ bool rc_service_daemon_set (const char *service, const char *exec,
dirpath = rc_strcatpaths (RC_SVCDIR, "daemons", dirpath = rc_strcatpaths (RC_SVCDIR, "daemons",
basename_c (service), (char *) NULL); basename_c (service), (char *) NULL);
if (exec) { if (argv) {
l = strlen (exec) + 6; l = strlen (*argv) + 6;
mexec = xmalloc (sizeof (char) * l); mexec = xmalloc (sizeof (char) * l);
snprintf (mexec, l, "exec=%s", exec); snprintf (mexec, l, "exec=%s", *argv);
} else } else
mexec = xstrdup ("exec="); mexec = xstrdup ("exec=");
@ -464,6 +487,7 @@ bool rc_service_daemons_crashed (const char *service)
char *path; char *path;
FILE *fp; FILE *fp;
char *line; char *line;
char **argv = NULL;
char *exec = NULL; char *exec = NULL;
char *name = NULL; char *name = NULL;
char *pidfile = NULL; char *pidfile = NULL;
@ -506,7 +530,9 @@ bool rc_service_daemons_crashed (const char *service)
continue; continue;
} }
if (strcmp (token, "exec") == 0) { if (strcmp (token, "argv") == 0) {
rc_strlist_add (&argv, p);
} else if (strcmp (token, "exec") == 0) {
if (exec) if (exec)
free (exec); free (exec);
exec = xstrdup (p); exec = xstrdup (p);
@ -546,24 +572,35 @@ bool rc_service_daemons_crashed (const char *service)
pidfile = NULL; pidfile = NULL;
/* We have the pid, so no need to match on name */ /* We have the pid, so no need to match on name */
rc_strlist_free (argv);
argv = NULL;
free (exec); free (exec);
exec = NULL; exec = NULL;
free (name); free (name);
name = NULL; name = NULL;
} }
if ((pids = rc_find_pids (exec, name, 0, pid)) == NULL) { if (exec && ! argv) {
rc_strlist_add (&argv, exec);
free (exec);
exec = NULL;
}
if ((pids = rc_find_pids ((const char *const *)argv, name, 0, pid)) == NULL) {
retval = true; retval = true;
break; break;
} }
free (pids); free (pids);
rc_strlist_free (argv);
argv = NULL;
free (exec); free (exec);
exec = NULL; exec = NULL;
free (name); free (name);
name = NULL; name = NULL;
} }
rc_strlist_free (argv);
free (exec); free (exec);
free (name); free (name);
free (dirpath); free (dirpath);

View File

@ -117,7 +117,7 @@ bool rc_service_delete (const char *runlevel, const char *service);
* @param name of the process (optional) * @param name of the process (optional)
* @param pidfile of the process (optional) * @param pidfile of the process (optional)
* @param started if true, add the arguments otherwise remove existing matching arguments */ * @param started if true, add the arguments otherwise remove existing matching arguments */
bool rc_service_daemon_set (const char *service, const char *exec, bool rc_service_daemon_set (const char *service, const char *const *argv,
const char *name, const char *pidfile, const char *name, const char *pidfile,
bool started); bool started);
@ -445,7 +445,7 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...) SENTINEL;
* @param uid to check for * @param uid to check for
* @param pid to check for * @param pid to check for
* @return NULL terminated list of pids */ * @return NULL terminated list of pids */
pid_t *rc_find_pids (const char *exec, const char *cmd, pid_t *rc_find_pids (const char *const *argv, const char *cmd,
uid_t uid, pid_t pid); uid_t uid, pid_t pid);
#endif #endif

View File

@ -305,7 +305,7 @@ static pid_t get_pid (const char *pidfile, bool quiet)
} }
/* return number of processed killed, -1 on error */ /* return number of processed killed, -1 on error */
static int do_stop (const char *exec, const char *cmd, static int do_stop (const char *const *argv, const char *cmd,
const char *pidfile, uid_t uid,int sig, const char *pidfile, uid_t uid,int sig,
bool quiet, bool verbose, bool test) bool quiet, bool verbose, bool test)
{ {
@ -320,7 +320,7 @@ static int do_stop (const char *exec, const char *cmd,
return (quiet ? 0 : -1); return (quiet ? 0 : -1);
pids = rc_find_pids (NULL, NULL, 0, pid); pids = rc_find_pids (NULL, NULL, 0, pid);
} else } else
pids = rc_find_pids (exec, cmd, uid, pid); pids = rc_find_pids (argv, cmd, uid, pid);
if (! pids) if (! pids)
return (0); return (0);
@ -352,7 +352,7 @@ static int do_stop (const char *exec, const char *cmd,
return (nkilled); return (nkilled);
} }
static int run_stop_schedule (const char *exec, const char *cmd, static int run_stop_schedule (const char *const *argv, const char *cmd,
const char *pidfile, uid_t uid, const char *pidfile, uid_t uid,
bool quiet, bool verbose, bool test) bool quiet, bool verbose, bool test)
{ {
@ -368,8 +368,8 @@ static int run_stop_schedule (const char *exec, const char *cmd,
einfo ("Will stop PID in pidfile `%s'", pidfile); einfo ("Will stop PID in pidfile `%s'", pidfile);
if (uid) if (uid)
einfo ("Will stop processes owned by UID %d", uid); einfo ("Will stop processes owned by UID %d", uid);
if (exec) if (argv)
einfo ("Will stop processes of `%s'", exec); einfo ("Will stop processes of `%s'", *argv);
if (cmd) if (cmd)
einfo ("Will stop processes called `%s'", cmd); einfo ("Will stop processes called `%s'", cmd);
} }
@ -382,7 +382,7 @@ static int run_stop_schedule (const char *exec, const char *cmd,
case schedule_signal: case schedule_signal:
nrunning = 0; nrunning = 0;
nkilled = do_stop (exec, cmd, pidfile, uid, item->value, nkilled = do_stop (argv, cmd, pidfile, uid, item->value,
quiet, verbose, test); quiet, verbose, test);
if (nkilled == 0) { if (nkilled == 0) {
if (tkilled == 0) { if (tkilled == 0) {
@ -407,7 +407,7 @@ static int run_stop_schedule (const char *exec, const char *cmd,
ts.tv_nsec = POLL_INTERVAL; ts.tv_nsec = POLL_INTERVAL;
while (nloops) { while (nloops) {
if ((nrunning = do_stop (exec, cmd, pidfile, if ((nrunning = do_stop (argv, cmd, pidfile,
uid, 0, true, false, true)) == 0) uid, 0, true, false, true)) == 0)
return (true); return (true);
@ -496,6 +496,7 @@ static const struct option longopts[] = {
{ "background", 0, NULL, 'b'}, { "background", 0, NULL, 'b'},
{ "chuid", 1, NULL, 'c'}, { "chuid", 1, NULL, 'c'},
{ "chdir", 1, NULL, 'd'}, { "chdir", 1, NULL, 'd'},
{ "env", 1, NULL, 'e'},
{ "group", 1, NULL, 'g'}, { "group", 1, NULL, 'g'},
{ "make-pidfile", 0, NULL, 'm'}, { "make-pidfile", 0, NULL, 'm'},
{ "name", 1, NULL, 'n'}, { "name", 1, NULL, 'n'},
@ -519,6 +520,7 @@ static const char * const longopts_help[] = {
"Force daemon to background", "Force daemon to background",
"deprecated, use --user", "deprecated, use --user",
"Change the PWD", "Change the PWD",
"Set an environment string",
"Change the process group", "Change the process group",
"Create a pidfile", "Create a pidfile",
"Match process name", "Match process name",
@ -574,6 +576,8 @@ int start_stop_daemon (int argc, char **argv)
int i; int i;
char *svcname = getenv ("SVCNAME"); char *svcname = getenv ("SVCNAME");
char *env; char *env;
bool sethome = false;
bool setuser = false;
atexit (cleanup); atexit (cleanup);
@ -585,7 +589,7 @@ int start_stop_daemon (int argc, char **argv)
if (sscanf (env, "%d", &nicelevel) != 1) if (sscanf (env, "%d", &nicelevel) != 1)
eerror ("%s: invalid nice level `%s' (SSD_NICELEVEL)", applet, env); eerror ("%s: invalid nice level `%s' (SSD_NICELEVEL)", applet, env);
while ((opt = getopt_long (argc, argv, getoptstring, longopts, while ((opt = getopt_long (argc, argv, "e:" getoptstring, longopts,
(int *) 0)) != -1) (int *) 0)) != -1)
switch (opt) { switch (opt) {
case 'K': /* --stop */ case 'K': /* --stop */
@ -648,6 +652,15 @@ int start_stop_daemon (int argc, char **argv)
ch_dir = optarg; ch_dir = optarg;
break; break;
case 'e': /* --env */
if (putenv (optarg) == 0) {
if (strncmp ("HOME=", optarg, 5) == 0)
sethome = true;
else if (strncmp ("USER=", optarg, 5) == 0)
setuser = true;
}
break;
case 'g': /* --group <group>|<gid> */ case 'g': /* --group <group>|<gid> */
{ {
struct group *gr = getgrnam (optarg); struct group *gr = getgrnam (optarg);
@ -761,6 +774,9 @@ int start_stop_daemon (int argc, char **argv)
free (tmp); free (tmp);
} }
/* Add exec to our arguments */
*--argv = exec;
if (stop) { if (stop) {
int result; int result;
@ -771,7 +787,8 @@ int start_stop_daemon (int argc, char **argv)
parse_schedule (NULL, sig); parse_schedule (NULL, sig);
} }
result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test); result = run_stop_schedule ((const char *const *)argv, cmd,
pidfile, uid, quiet, verbose, test);
if (test || oknodo) if (test || oknodo)
return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE); return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE);
if (result < 1) if (result < 1)
@ -781,21 +798,24 @@ int start_stop_daemon (int argc, char **argv)
unlink (pidfile); unlink (pidfile);
if (svcname) if (svcname)
rc_service_daemon_set (svcname, exec, cmd, pidfile, false); rc_service_daemon_set (svcname,
(const char *const *)argv,
cmd, pidfile, false);
exit (EXIT_SUCCESS); exit (EXIT_SUCCESS);
} }
if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) if (do_stop ((const char * const *)argv, cmd, pidfile, uid,
0, true, false, true) > 0)
eerrorx ("%s: %s is already running", applet, exec); eerrorx ("%s: %s is already running", applet, exec);
if (test) { if (test) {
if (quiet) if (quiet)
exit (EXIT_SUCCESS); exit (EXIT_SUCCESS);
einfon ("Would start %s", exec); einfon ("Would start");
while (argc-- > 0) while (argc-- >= 0)
printf("%s ", *argv++); printf(" %s", *argv++);
printf ("\n"); printf ("\n");
eindent (); eindent ();
if (uid != 0) if (uid != 0)
@ -824,7 +844,6 @@ int start_stop_daemon (int argc, char **argv)
if (background) if (background)
signal_setup (SIGCHLD, handle_signal); signal_setup (SIGCHLD, handle_signal);
*--argv = exec;
if ((pid = fork ()) == -1) if ((pid = fork ()) == -1)
eerrorx ("%s: fork: %s", applet, strerror (errno)); eerrorx ("%s: fork: %s", applet, strerror (errno));
@ -884,12 +903,16 @@ int start_stop_daemon (int argc, char **argv)
else { else {
struct passwd *passwd = getpwuid (uid); struct passwd *passwd = getpwuid (uid);
if (passwd) { if (passwd) {
unsetenv ("HOME"); if (! sethome) {
if (passwd->pw_dir) unsetenv ("HOME");
setenv ("HOME", passwd->pw_dir, 1); if (passwd->pw_dir)
unsetenv ("USER"); setenv ("HOME", passwd->pw_dir, 1);
if (passwd->pw_name) }
setenv ("USER", passwd->pw_name, 1); if (! setuser) {
unsetenv ("USER");
if (passwd->pw_name)
setenv ("USER", passwd->pw_name, 1);
}
} }
} }
@ -1056,7 +1079,8 @@ int start_stop_daemon (int argc, char **argv)
} else } else
nloopsp = 0; nloopsp = 0;
} }
if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) if (do_stop ((const char *const *)argv, cmd,
pidfile, uid, 0, true, false, true) > 0)
alive = true; alive = true;
} }
@ -1066,7 +1090,7 @@ int start_stop_daemon (int argc, char **argv)
} }
if (svcname) if (svcname)
rc_service_daemon_set (svcname, exec, cmd, pidfile, true); rc_service_daemon_set (svcname, (const char *const *)argv, cmd, pidfile, true);
exit (EXIT_SUCCESS); exit (EXIT_SUCCESS);
/* NOTREACHED */ /* NOTREACHED */