/[baselayout]/trunk/src/start-stop-daemon.c
Gentoo

Contents of /trunk/src/start-stop-daemon.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2911 - (hide annotations) (download) (as text)
Mon Sep 24 12:09:43 2007 UTC (7 years, 3 months ago) by uberlord
File MIME type: text/x-csrc
File size: 23205 byte(s)
Split our rc commands out into general use vs service commands
1 uberlord 2547 /*
2     start-stop-daemon
3     Starts, stops, tests and signals daemons
4     Copyright 2007 Gentoo Foundation
5     Released under the GPLv2
6    
7     This is essentially a ground up re-write of Debians
8     start-stop-daemon for cleaner code and to integrate into our RC
9     system so we can monitor daemons a little.
10     */
11    
12 uberlord 2838 #define APPLET "start-stop-daemon"
13    
14 uberlord 2828 /* nano seconds */
15     #define POLL_INTERVAL 20000000
16     #define START_WAIT 100000000
17     #define ONE_SECOND 1000000000
18 uberlord 2547
19 uberlord 2549 #include <sys/types.h>
20     #include <sys/ioctl.h>
21 uberlord 2547 #include <sys/resource.h>
22     #include <sys/stat.h>
23     #include <sys/termios.h>
24     #include <sys/time.h>
25     #include <sys/wait.h>
26     #include <ctype.h>
27     #include <errno.h>
28     #include <fcntl.h>
29     #include <getopt.h>
30     #include <grp.h>
31     #include <pwd.h>
32     #include <signal.h>
33     #include <stddef.h>
34     #include <stdio.h>
35     #include <stdlib.h>
36     #include <string.h>
37 uberlord 2708 #include <time.h>
38 uberlord 2547 #include <unistd.h>
39    
40     #ifdef HAVE_PAM
41     #include <security/pam_appl.h>
42    
43     /* We are not supporting authentication conversations */
44     static struct pam_conv conv = { NULL, NULL} ;
45     #endif
46    
47 uberlord 2799 #include "builtins.h"
48 uberlord 2547 #include "einfo.h"
49     #include "rc.h"
50     #include "rc-misc.h"
51     #include "strlist.h"
52    
53     typedef struct schedulelist
54     {
55 uberlord 2577 enum
56     {
57     schedule_timeout,
58     schedule_signal,
59     schedule_goto,
60     schedule_forever
61     } type;
62     int value;
63     struct schedulelist *gotolist;
64     struct schedulelist *next;
65 uberlord 2547 } schedulelist_t;
66     static schedulelist_t *schedule;
67    
68 uberlord 2838 static char *applet;
69 uberlord 2547 static char *changeuser;
70     static char **newenv;
71    
72     extern char **environ;
73    
74     static void free_schedulelist (schedulelist_t **list)
75     {
76 uberlord 2577 schedulelist_t *here;
77     schedulelist_t *next;
78 uberlord 2547
79 uberlord 2577 for (here = *list; here; here = next) {
80     next = here->next;
81     free (here);
82     }
83 uberlord 2547
84 uberlord 2577 *list = NULL;
85 uberlord 2547 }
86    
87     static void cleanup (void)
88     {
89 uberlord 2577 if (changeuser)
90     free (changeuser);
91 uberlord 2547
92 uberlord 2577 if (schedule)
93     free_schedulelist (&schedule);
94 uberlord 2547
95 uberlord 2577 if (newenv)
96     rc_strlist_free (newenv);
97 uberlord 2547 }
98    
99     static int parse_signal (const char *sig)
100     {
101 uberlord 2577 typedef struct signalpair
102     {
103     const char *name;
104     int signal;
105     } signalpair_t;
106 uberlord 2547
107 uberlord 2577 static const signalpair_t signallist[] = {
108     { "ABRT", SIGABRT },
109     { "ALRM", SIGALRM },
110     { "FPE", SIGFPE },
111     { "HUP", SIGHUP },
112     { "ILL", SIGILL },
113     { "INT", SIGINT },
114     { "KILL", SIGKILL },
115     { "PIPE", SIGPIPE },
116     { "QUIT", SIGQUIT },
117     { "SEGV", SIGSEGV },
118     { "TERM", SIGTERM },
119     { "USR1", SIGUSR1 },
120     { "USR2", SIGUSR2 },
121     { "CHLD", SIGCHLD },
122     { "CONT", SIGCONT },
123     { "STOP", SIGSTOP },
124     { "TSTP", SIGTSTP },
125     { "TTIN", SIGTTIN },
126     { "TTOU", SIGTTOU }
127     };
128 uberlord 2547
129 uberlord 2577 unsigned int i = 0;
130     char *s;
131 uberlord 2547
132 uberlord 2577 if (! sig || strlen (sig) == 0)
133     return (-1);
134 uberlord 2547
135 uberlord 2577 if (sscanf (sig, "%u", &i) == 1) {
136     if (i > 0 && i < sizeof (signallist) / sizeof (signallist[0]))
137     return (i);
138 uberlord 2838 eerrorx ("%s: `%s' is not a valid signal", applet, sig);
139 uberlord 2577 }
140 uberlord 2547
141 uberlord 2577 if (strncmp (sig, "SIG", 3) == 0)
142     s = (char *) sig + 3;
143     else
144     s = NULL;
145 uberlord 2547
146 uberlord 2577 for (i = 0; i < sizeof (signallist) / sizeof (signallist[0]); i++)
147     if (strcmp (sig, signallist[i].name) == 0 ||
148     (s && strcmp (s, signallist[i].name) == 0))
149     return (signallist[i].signal);
150 uberlord 2547
151 uberlord 2838 eerrorx ("%s: `%s' is not a valid signal", applet, sig);
152 uberlord 2547 }
153    
154     static void parse_schedule_item (schedulelist_t *item, const char *string)
155     {
156 uberlord 2577 const char *after_hyph;
157     int sig;
158 uberlord 2547
159 uberlord 2577 if (strcmp (string,"forever") == 0)
160     item->type = schedule_forever;
161     else if (isdigit (string[0])) {
162     item->type = schedule_timeout;
163     errno = 0;
164     if (sscanf (string, "%d", &item->value) != 1)
165 uberlord 2838 eerrorx ("%s: invalid timeout value in schedule `%s'", applet,
166 uberlord 2577 string);
167     } else if ((after_hyph = string + (string[0] == '-')) &&
168     ((sig = parse_signal (after_hyph)) != -1))
169     {
170     item->type = schedule_signal;
171     item->value = (int) sig;
172     }
173     else
174 uberlord 2838 eerrorx ("%s: invalid schedule item `%s'", applet, string);
175 uberlord 2547 }
176    
177     static void parse_schedule (const char *string, int default_signal)
178     {
179 uberlord 2577 char buffer[20];
180     const char *slash;
181     int count = 0;
182     schedulelist_t *repeatat = NULL;
183     ptrdiff_t len;
184     schedulelist_t *next;
185 uberlord 2547
186 uberlord 2577 if (string)
187     for (slash = string; *slash; slash++)
188     if (*slash == '/')
189     count++;
190 uberlord 2547
191 uberlord 2577 if (schedule)
192     free_schedulelist (&schedule);
193 uberlord 2547
194 uberlord 2577 schedule = rc_xmalloc (sizeof (schedulelist_t));
195     schedule->gotolist = NULL;
196 uberlord 2547
197 uberlord 2577 if (count == 0) {
198     schedule->type = schedule_signal;
199     schedule->value = default_signal;
200     schedule->next = rc_xmalloc (sizeof (schedulelist_t));
201     next = schedule->next;
202     next->type = schedule_timeout;
203     next->gotolist = NULL;
204     if (string) {
205     if (sscanf (string, "%d", &next->value) != 1)
206 uberlord 2838 eerrorx ("%s: invalid timeout value in schedule", applet);
207 uberlord 2577 }
208     else
209     next->value = 5;
210     next->next = NULL;
211 uberlord 2547
212 uberlord 2577 return;
213     }
214 uberlord 2547
215 uberlord 2577 next = schedule;
216     while (string != NULL) {
217     if ((slash = strchr (string, '/')))
218     len = slash - string;
219     else
220     len = strlen (string);
221 uberlord 2547
222 uberlord 2577 if (len >= (ptrdiff_t) sizeof (buffer))
223 uberlord 2838 eerrorx ("%s: invalid schedule item, far too long", applet);
224 uberlord 2547
225 uberlord 2577 memcpy (buffer, string, len);
226     buffer[len] = 0;
227     string = slash ? slash + 1 : NULL;
228 uberlord 2547
229 uberlord 2577 parse_schedule_item (next, buffer);
230     if (next->type == schedule_forever) {
231     if (repeatat)
232     eerrorx ("%s: invalid schedule, `forever' appears more than once",
233 uberlord 2838 applet);
234 uberlord 2547
235 uberlord 2577 repeatat = next;
236     continue;
237     }
238 uberlord 2547
239 uberlord 2577 if (string) {
240     next->next = rc_xmalloc (sizeof (schedulelist_t));
241     next = next->next;
242     next->gotolist = NULL;
243     }
244     }
245 uberlord 2547
246 uberlord 2577 if (repeatat) {
247     next->next = rc_xmalloc (sizeof (schedulelist_t));
248     next = next->next;
249     next->type = schedule_goto;
250     next->value = 0;
251     next->gotolist = repeatat;
252     }
253 uberlord 2547
254 uberlord 2577 next->next = NULL;
255     return;
256 uberlord 2547 }
257    
258     static pid_t get_pid (const char *pidfile, bool quiet)
259     {
260 uberlord 2577 FILE *fp;
261     pid_t pid;
262 uberlord 2547
263 uberlord 2577 if (! pidfile)
264     return (-1);
265 uberlord 2547
266 uberlord 2577 if ((fp = fopen (pidfile, "r")) == NULL) {
267     if (! quiet)
268 uberlord 2838 eerror ("%s: fopen `%s': %s", applet, pidfile, strerror (errno));
269 uberlord 2577 return (-1);
270     }
271 uberlord 2547
272 uberlord 2577 if (fscanf (fp, "%d", &pid) != 1) {
273     if (! quiet)
274 uberlord 2838 eerror ("%s: no pid found in `%s'", applet, pidfile);
275 uberlord 2577 fclose (fp);
276     return (-1);
277     }
278     fclose (fp);
279 uberlord 2547
280 uberlord 2577 return (pid);
281 uberlord 2547 }
282    
283     /* return number of processed killed, -1 on error */
284     static int do_stop (const char *exec, const char *cmd,
285 uberlord 2577 const char *pidfile, uid_t uid,int sig,
286     bool quiet, bool verbose, bool test)
287 uberlord 2547 {
288 uberlord 2577 pid_t *pids;
289     bool killed;
290     int nkilled = 0;
291     pid_t pid = 0;
292     int i;
293 uberlord 2547
294 uberlord 2577 if (pidfile)
295     if ((pid = get_pid (pidfile, quiet)) == -1)
296     return (quiet ? 0 : -1);
297 uberlord 2547
298 uberlord 2577 if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL)
299     return (0);
300 uberlord 2547
301 uberlord 2577 for (i = 0; pids[i]; i++) {
302     if (test) {
303     if (! quiet)
304     einfo ("Would send signal %d to PID %d", sig, pids[i]);
305     nkilled++;
306     continue;
307     }
308 uberlord 2547
309 uberlord 2577 if (verbose)
310     ebegin ("Sending signal %d to PID %d", sig, pids[i]);
311     errno = 0;
312     killed = (kill (pids[i], sig) == 0 || errno == ESRCH ? true : false);
313     if (! killed) {
314     if (! quiet)
315     eerror ("%s: failed to send signal %d to PID %d: %s",
316 uberlord 2838 applet, sig, pids[i], strerror (errno));
317 uberlord 2577 if (verbose)
318     eend (1, NULL);
319     nkilled = -1;
320     } else {
321     if (verbose)
322     eend (0, NULL);
323     if (nkilled != -1)
324     nkilled++;
325     }
326     }
327 uberlord 2547
328 uberlord 2577 free (pids);
329     return (nkilled);
330 uberlord 2547 }
331    
332     static int run_stop_schedule (const char *exec, const char *cmd,
333 uberlord 2577 const char *pidfile, uid_t uid,
334     bool quiet, bool verbose, bool test)
335 uberlord 2547 {
336 uberlord 2577 schedulelist_t *item = schedule;
337     int nkilled = 0;
338     int tkilled = 0;
339     int nrunning = 0;
340 uberlord 2828 long nloops;
341     struct timespec ts;
342 uberlord 2547
343 uberlord 2577 if (verbose) {
344     if (pidfile)
345     einfo ("Will stop PID in pidfile `%s'", pidfile);
346     if (uid)
347     einfo ("Will stop processes owned by UID %d", uid);
348     if (exec)
349     einfo ("Will stop processes of `%s'", exec);
350     if (cmd)
351     einfo ("Will stop processes called `%s'", cmd);
352     }
353 uberlord 2547
354 uberlord 2577 while (item) {
355     switch (item->type) {
356     case schedule_goto:
357     item = item->gotolist;
358     continue;
359 uberlord 2547
360 uberlord 2577 case schedule_signal:
361     nrunning = 0;
362     nkilled = do_stop (exec, cmd, pidfile, uid, item->value,
363     quiet, verbose, test);
364     if (nkilled == 0) {
365     if (tkilled == 0) {
366     if (! quiet)
367 uberlord 2838 eerror ("%s: no matching processes found", applet);
368 uberlord 2577 }
369     return (tkilled);
370     }
371     else if (nkilled == -1)
372     return (0);
373 uberlord 2547
374 uberlord 2577 tkilled += nkilled;
375     break;
376     case schedule_timeout:
377     if (item->value < 1) {
378     item = NULL;
379     break;
380     }
381 uberlord 2547
382 uberlord 2828 nloops = (ONE_SECOND / POLL_INTERVAL) * item->value;
383     ts.tv_sec = 0;
384     ts.tv_nsec = POLL_INTERVAL;
385 uberlord 2547
386 uberlord 2828 while (nloops) {
387 uberlord 2577 if ((nrunning = do_stop (exec, cmd, pidfile,
388     uid, 0, true, false, true)) == 0)
389     return (true);
390 uberlord 2547
391 uberlord 2828 if (nanosleep (&ts, NULL) == -1) {
392 uberlord 2577 if (errno == EINTR)
393 uberlord 2838 eerror ("%s: caught an interupt", applet);
394 uberlord 2657 else {
395 uberlord 2838 eerror ("%s: nanosleep: %s", applet, strerror (errno));
396 uberlord 2657 return (0);
397     }
398 uberlord 2577 }
399 uberlord 2828 nloops --;
400 uberlord 2577 }
401     break;
402 uberlord 2547
403 uberlord 2577 default:
404 uberlord 2838 eerror ("%s: invalid schedule item `%d'", applet, item->type);
405 uberlord 2577 return (0);
406     }
407 uberlord 2547
408 uberlord 2577 if (item)
409     item = item->next;
410     }
411 uberlord 2547
412 uberlord 2577 if (test || (tkilled > 0 && nrunning == 0))
413     return (nkilled);
414 uberlord 2547
415 uberlord 2577 if (! quiet) {
416     if (nrunning == 1)
417 uberlord 2838 eerror ("%s: %d process refused to stop", applet, nrunning);
418 uberlord 2577 else
419 uberlord 2838 eerror ("%s: %d process(es) refused to stop", applet, nrunning);
420 uberlord 2577 }
421 uberlord 2547
422 uberlord 2577 return (-nrunning);
423 uberlord 2547 }
424    
425     static void handle_signal (int sig)
426     {
427 uberlord 2577 int pid;
428     int status;
429     int serrno = errno;
430     char signame[10] = { '\0' };
431 uberlord 2547
432 uberlord 2577 switch (sig) {
433     case SIGINT:
434     if (! signame[0])
435     snprintf (signame, sizeof (signame), "SIGINT");
436     case SIGTERM:
437     if (! signame[0])
438     snprintf (signame, sizeof (signame), "SIGTERM");
439     case SIGQUIT:
440     if (! signame[0])
441     snprintf (signame, sizeof (signame), "SIGQUIT");
442 uberlord 2838 eerrorx ("%s: caught %s, aborting", applet, signame);
443 uberlord 2547
444 uberlord 2577 case SIGCHLD:
445     while (1) {
446     if ((pid = waitpid (-1, &status, WNOHANG)) < 0) {
447     if (errno != ECHILD)
448 uberlord 2838 eerror ("%s: waitpid: %s", applet, strerror (errno));
449 uberlord 2577 break;
450     }
451     }
452     break;
453 uberlord 2569
454 uberlord 2577 default:
455 uberlord 2838 eerror ("%s: caught unknown signal %d", applet, sig);
456 uberlord 2577 }
457 uberlord 2547
458 uberlord 2577 /* Restore errno */
459     errno = serrno;
460 uberlord 2547 }
461    
462 uberlord 2838
463     #include "_usage.h"
464 uberlord 2897 #define getoptstring "KN:R:Sbc:d:g:mn:op:s:tu:r:vx:1:2:" getoptstring_COMMON
465 uberlord 2838 static struct option longopts[] = {
466     { "stop", 0, NULL, 'K'},
467     { "nicelevel", 1, NULL, 'N'},
468     { "retry", 1, NULL, 'R'},
469     { "start", 0, NULL, 'S'},
470     { "startas", 1, NULL, 'a'},
471     { "background", 0, NULL, 'b'},
472     { "chuid", 1, NULL, 'c'},
473     { "chdir", 1, NULL, 'd'},
474     { "group", 1, NULL, 'g'},
475     { "make-pidfile", 0, NULL, 'm'},
476     { "name", 1, NULL, 'n'},
477     { "oknodo", 0, NULL, 'o'},
478     { "pidfile", 1, NULL, 'p'},
479     { "signal", 1, NULL, 's'},
480     { "test", 0, NULL, 't'},
481     { "user", 1, NULL, 'u'},
482     { "chroot", 1, NULL, 'r'},
483     { "verbose", 0, NULL, 'v'},
484     { "exec", 1, NULL, 'x'},
485     { "stdout", 1, NULL, '1'},
486     { "stderr", 1, NULL, '2'},
487     longopts_COMMON
488     { NULL, 0, NULL, 0}
489     };
490     #include "_usage.c"
491    
492 uberlord 2799 int start_stop_daemon (int argc, char **argv)
493 uberlord 2547 {
494 uberlord 2577 int devnull_fd = -1;
495 uberlord 2547 #ifdef TIOCNOTTY
496 uberlord 2577 int tty_fd = -1;
497 uberlord 2547 #endif
498 uberlord 2838
499 uberlord 2547 #ifdef HAVE_PAM
500 uberlord 2577 pam_handle_t *pamh = NULL;
501     int pamr;
502 uberlord 2547 #endif
503    
504 uberlord 2698 int opt;
505 uberlord 2577 bool start = false;
506     bool stop = false;
507     bool oknodo = false;
508     bool test = false;
509 uberlord 2897 bool quiet;
510 uberlord 2577 bool verbose = false;
511     char *exec = NULL;
512     char *cmd = NULL;
513     char *pidfile = NULL;
514     int sig = SIGTERM;
515     int nicelevel = 0;
516     bool background = false;
517     bool makepidfile = false;
518 uberlord 2837 uid_t uid = 0;
519     gid_t gid = 0;
520 uberlord 2577 char *ch_root = NULL;
521     char *ch_dir = NULL;
522     int tid = 0;
523     char *redirect_stderr = NULL;
524     char *redirect_stdout = NULL;
525     int stdout_fd;
526     int stderr_fd;
527     pid_t pid;
528     int i;
529     char *svcname = getenv ("SVCNAME");
530     char *env;
531 uberlord 2547
532 uberlord 2838 applet = argv[0];
533 uberlord 2577 atexit (cleanup);
534 uberlord 2547
535 uberlord 2577 signal (SIGINT, handle_signal);
536     signal (SIGQUIT, handle_signal);
537     signal (SIGTERM, handle_signal);
538 uberlord 2547
539 uberlord 2676 if ((env = getenv ("SSD_NICELEVEL")))
540     if (sscanf (env, "%d", &nicelevel) != 1)
541 uberlord 2838 eerror ("%s: invalid nice level `%s' (SSD_NICELEVEL)", applet, env);
542 uberlord 2676
543 uberlord 2838 while ((opt = getopt_long (argc, argv, getoptstring, longopts,
544     (int *) 0)) != -1)
545 uberlord 2698 switch (opt) {
546 uberlord 2577 case 'K': /* --stop */
547     stop = true;
548     break;
549 uberlord 2547
550 uberlord 2577 case 'N': /* --nice */
551     if (sscanf (optarg, "%d", &nicelevel) != 1)
552 uberlord 2838 eerrorx ("%s: invalid nice level `%s'", applet, optarg);
553 uberlord 2577 break;
554 uberlord 2547
555 uberlord 2577 case 'R': /* --retry <schedule>|<timeout> */
556     parse_schedule (optarg, sig);
557     break;
558 uberlord 2547
559 uberlord 2577 case 'S': /* --start */
560     start = true;
561     break;
562 uberlord 2547
563 uberlord 2577 case 'b': /* --background */
564     background = true;
565     break;
566 uberlord 2547
567 uberlord 2843 case 'u': /* --user <username>|<uid> */
568 uberlord 2577 case 'c': /* --chuid <username>|<uid> */
569     {
570     char *p = optarg;
571     char *cu = strsep (&p, ":");
572 uberlord 2586 struct passwd *pw = NULL;
573    
574 uberlord 2634 changeuser = rc_xstrdup (cu);
575 uberlord 2586 if (sscanf (cu, "%d", &tid) != 1)
576     pw = getpwnam (cu);
577     else
578     pw = getpwuid (tid);
579    
580     if (! pw)
581 uberlord 2838 eerrorx ("%s: user `%s' not found", applet, cu);
582 uberlord 2837 uid = pw->pw_uid;
583     if (! gid)
584     gid = pw->pw_gid;
585 uberlord 2586
586 uberlord 2577 if (p) {
587 uberlord 2586 struct group *gr = NULL;
588 uberlord 2577 char *cg = strsep (&p, ":");
589 uberlord 2586
590     if (sscanf (cg, "%d", &tid) != 1)
591     gr = getgrnam (cg);
592     else
593     gr = getgrgid (tid);
594    
595     if (! gr)
596 uberlord 2838 eerrorx ("%s: group `%s' not found", applet, cg);
597 uberlord 2837 gid = gr->gr_gid;
598 uberlord 2577 }
599     }
600     break;
601 uberlord 2547
602 uberlord 2577 case 'd': /* --chdir /new/dir */
603     ch_dir = optarg;
604     break;
605 uberlord 2547
606 uberlord 2577 case 'g': /* --group <group>|<gid> */
607 uberlord 2586 {
608 uberlord 2577 struct group *gr = getgrnam (optarg);
609 uberlord 2586
610     if (sscanf (optarg, "%d", &tid) != 1)
611     gr = getgrnam (optarg);
612     else
613     gr = getgrgid (tid);
614    
615 uberlord 2577 if (! gr)
616 uberlord 2838 eerrorx ("%s: group `%s' not found", applet, optarg);
617 uberlord 2837 gid = gr->gr_gid;
618 uberlord 2586 }
619 uberlord 2577 break;
620 uberlord 2547
621 uberlord 2577 case 'm': /* --make-pidfile */
622     makepidfile = true;
623     break;
624 uberlord 2547
625 uberlord 2577 case 'n': /* --name <process-name> */
626     cmd = optarg;
627     break;
628 uberlord 2547
629 uberlord 2577 case 'o': /* --oknodo */
630     oknodo = true;
631     break;
632 uberlord 2547
633 uberlord 2577 case 'p': /* --pidfile <pid-file> */
634     pidfile = optarg;
635     break;
636 uberlord 2547
637 uberlord 2577 case 's': /* --signal <signal> */
638     sig = parse_signal (optarg);
639     break;
640 uberlord 2547
641 uberlord 2577 case 't': /* --test */
642     test = true;
643     break;
644 uberlord 2547
645 uberlord 2577 case 'r': /* --chroot /new/root */
646     ch_root = optarg;
647     break;
648 uberlord 2547
649 uberlord 2577 case 'v': /* --verbose */
650     verbose = true;
651     break;
652 uberlord 2547
653 uberlord 2699 case 'a':
654 uberlord 2577 case 'x': /* --exec <executable> */
655     exec = optarg;
656     break;
657 uberlord 2547
658 uberlord 2577 case '1': /* --stdout /path/to/stdout.lgfile */
659     redirect_stdout = optarg;
660     break;
661 uberlord 2547
662 uberlord 2577 case '2': /* --stderr /path/to/stderr.logfile */
663     redirect_stderr = optarg;
664     break;
665 uberlord 2547
666 uberlord 2838 case_RC_COMMON_GETOPT
667 uberlord 2577 }
668 uberlord 2547
669 uberlord 2897 quiet = rc_is_env ("RC_QUIET", "yes");
670 uberlord 2547
671 uberlord 2587 /* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq
672     * instead of forcing --stop --oknodo as well */
673     if (! start && ! stop)
674     if (sig != SIGINT &&
675     sig != SIGTERM &&
676     sig != SIGQUIT &&
677     sig != SIGKILL)
678     {
679     oknodo = true;
680     stop = true;
681     }
682    
683 uberlord 2577 if (start == stop)
684 uberlord 2838 eerrorx ("%s: need one of --start or --stop", applet);
685 uberlord 2547
686 uberlord 2577 if (start && ! exec)
687 uberlord 2838 eerrorx ("%s: --start needs --exec", applet);
688 uberlord 2547
689 uberlord 2577 if (stop && ! exec && ! pidfile && ! cmd && ! uid)
690 uberlord 2838 eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", applet);
691 uberlord 2547
692 uberlord 2577 if (makepidfile && ! pidfile)
693 uberlord 2838 eerrorx ("%s: --make-pidfile is only relevant with --pidfile", applet);
694 uberlord 2547
695 uberlord 2577 if (background && ! start)
696 uberlord 2838 eerrorx ("%s: --background is only relevant with --start", applet);
697 uberlord 2547
698 uberlord 2577 if ((redirect_stdout || redirect_stderr) && ! background)
699     eerrorx ("%s: --stdout and --stderr are only relevant with --background",
700 uberlord 2838 applet);
701 uberlord 2547
702 uberlord 2577 argc -= optind;
703     argv += optind;
704 uberlord 2547
705 uberlord 2828 /* Validate that the binary exists if we are starting */
706 uberlord 2577 if (exec && start) {
707     char *tmp;
708     if (ch_root)
709     tmp = rc_strcatpaths (ch_root, exec, (char *) NULL);
710     else
711     tmp = exec;
712     if (! rc_is_file (tmp)) {
713 uberlord 2838 eerror ("%s: %s does not exist", applet, tmp);
714 uberlord 2577 if (ch_root)
715     free (tmp);
716     exit (EXIT_FAILURE);
717     }
718     if (ch_root)
719     free (tmp);
720     }
721 uberlord 2547
722 uberlord 2577 if (stop) {
723     int result;
724 uberlord 2547
725 uberlord 2577 if (! schedule) {
726     if (test || oknodo)
727     parse_schedule ("0", sig);
728     else
729     parse_schedule (NULL, sig);
730     }
731 uberlord 2547
732 uberlord 2577 result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test);
733     if (test || oknodo)
734     return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE);
735     if (result < 1)
736     exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
737 uberlord 2547
738 uberlord 2577 if (pidfile && rc_is_file (pidfile))
739     unlink (pidfile);
740 uberlord 2547
741 uberlord 2577 if (svcname)
742     rc_set_service_daemon (svcname, exec, cmd, pidfile, false);
743 uberlord 2547
744 uberlord 2577 exit (EXIT_SUCCESS);
745     }
746 uberlord 2547
747 uberlord 2577 if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0)
748 uberlord 2838 eerrorx ("%s: %s is already running", applet, exec);
749 uberlord 2547
750 uberlord 2577 if (test) {
751     if (quiet)
752     exit (EXIT_SUCCESS);
753 uberlord 2547
754 uberlord 2577 einfon ("Would start %s", exec);
755     while (argc-- > 0)
756     printf("%s ", *argv++);
757     printf ("\n");
758     eindent ();
759 uberlord 2837 if (uid != 0)
760     einfo ("as user id %d", uid);
761     if (gid != 0)
762     einfo ("as group id %d", gid);
763 uberlord 2577 if (ch_root)
764     einfo ("in root `%s'", ch_root);
765     if (ch_dir)
766     einfo ("in dir `%s'", ch_dir);
767     if (nicelevel != 0)
768     einfo ("with a priority of %d", nicelevel);
769     eoutdent ();
770     exit (EXIT_SUCCESS);
771     }
772 uberlord 2547
773 uberlord 2577 /* Ensure this is unset, so if the daemon does /etc/init.d/foo
774     Then we filter the environment accordingly */
775     unsetenv ("RC_SOFTLEVEL");
776 uberlord 2547
777 uberlord 2577 if (verbose) {
778     ebegin ("Detaching to start `%s'", exec);
779     eindent ();
780     }
781 uberlord 2547
782 uberlord 2577 if (background)
783     signal (SIGCHLD, handle_signal);
784 uberlord 2547
785 uberlord 2577 *--argv = exec;
786     if ((pid = fork ()) == -1)
787 uberlord 2838 eerrorx ("%s: fork: %s", applet, strerror (errno));
788 uberlord 2547
789 uberlord 2577 /* Child process - lets go! */
790     if (pid == 0) {
791     pid_t mypid = getpid ();
792 uberlord 2547
793     #ifdef TIOCNOTTY
794 uberlord 2577 tty_fd = open("/dev/tty", O_RDWR);
795 uberlord 2547 #endif
796    
797 uberlord 2577 devnull_fd = open("/dev/null", O_RDWR);
798 uberlord 2547
799 uberlord 2577 if (nicelevel) {
800     if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1)
801 uberlord 2838 eerrorx ("%s: setpritory %d: %s", applet, nicelevel,
802 uberlord 2577 strerror(errno));
803     }
804 uberlord 2547
805 uberlord 2577 if (ch_root && chroot (ch_root) < 0)
806 uberlord 2838 eerrorx ("%s: chroot `%s': %s", applet, ch_root, strerror (errno));
807 uberlord 2547
808 uberlord 2577 if (ch_dir && chdir (ch_dir) < 0)
809 uberlord 2838 eerrorx ("%s: chdir `%s': %s", applet, ch_dir, strerror (errno));
810 uberlord 2547
811 uberlord 2577 if (makepidfile && pidfile) {
812     FILE *fp = fopen (pidfile, "w");
813     if (! fp)
814 uberlord 2838 eerrorx ("%s: fopen `%s': %s", applet, pidfile, strerror
815 uberlord 2577 (errno));
816     fprintf (fp, "%d\n", mypid);
817     fclose (fp);
818     }
819 uberlord 2547
820     #ifdef HAVE_PAM
821 uberlord 2577 if (changeuser != NULL)
822     pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh);
823     else
824     pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh);
825 uberlord 2547
826 uberlord 2577 if (pamr == PAM_SUCCESS)
827     pamr = pam_authenticate (pamh, PAM_SILENT);
828     if (pamr == PAM_SUCCESS)
829     pamr = pam_acct_mgmt (pamh, PAM_SILENT);
830     if (pamr == PAM_SUCCESS)
831     pamr = pam_open_session (pamh, PAM_SILENT);
832     if (pamr != PAM_SUCCESS)
833 uberlord 2838 eerrorx ("%s: pam error: %s", applet, pam_strerror(pamh, pamr));
834 uberlord 2547 #endif
835    
836 uberlord 2837 if (gid && setgid (gid))
837 uberlord 2838 eerrorx ("%s: unable to set groupid to %d", applet, gid);
838 uberlord 2837 if (changeuser && initgroups (changeuser, gid))
839 uberlord 2838 eerrorx ("%s: initgroups (%s, %d)", applet, changeuser, gid);
840 uberlord 2837 if (uid && setuid (uid))
841 uberlord 2838 eerrorx ("%s: unable to set userid to %d", applet, uid);
842 uberlord 2577 else {
843 uberlord 2837 struct passwd *passwd = getpwuid (uid);
844 uberlord 2577 if (passwd) {
845     unsetenv ("HOME");
846     if (passwd->pw_dir)
847     setenv ("HOME", passwd->pw_dir, 1);
848     unsetenv ("USER");
849     if (passwd->pw_name)
850     setenv ("USER", passwd->pw_name, 1);
851     }
852     }
853 uberlord 2547
854 uberlord 2577 /* Close any fd's to the passwd database */
855     endpwent ();
856 uberlord 2547
857     #ifdef TIOCNOTTY
858 uberlord 2577 ioctl(tty_fd, TIOCNOTTY, 0);
859     close(tty_fd);
860 uberlord 2547 #endif
861    
862 uberlord 2577 /* Clean the environment of any RC_ variables */
863 uberlord 2911 STRLIST_FOREACH (environ, env, i) {
864     if (strncmp (env, "RC_", 3) == 0 ||
865     strncmp (env, "SSD_NICELEVEL=", strlen ("SSD_NICELEVEL=")) == 0)
866     continue;
867 uberlord 2547
868 uberlord 2911 /* For the path, remove the rcscript bin dir from it */
869     if (strncmp (env, "PATH=", 5) == 0) {
870     char *path = rc_xstrdup (env);
871     char *newpath = NULL;
872     char *p = path;
873     char *token;
874    
875     p += 5;
876     while ((token = strsep (&p, ":"))) {
877     if (strcmp (token, RC_LIBDIR "/bin") == 0 ||
878     strcmp (token, RC_LIBDIR "/sbin") == 0)
879     continue;
880    
881     if (newpath)
882     asprintf (&newpath, "%s:%s", newpath, token);
883     else
884     asprintf (&newpath, "PATH=%s", token);
885     }
886     rc_strlist_add (&newenv, newpath);
887     free (path);
888     free (newpath);
889     } else
890     rc_strlist_add (&newenv, env);
891     }
892    
893     STRLIST_FOREACH (newenv, env, i)
894     einfo ("env %s", env);
895    
896 uberlord 2577 umask (022);
897 uberlord 2547
898 uberlord 2577 stdout_fd = devnull_fd;
899     stderr_fd = devnull_fd;
900     if (redirect_stdout) {
901     if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND,
902     S_IRUSR | S_IWUSR)) == -1)
903     eerrorx ("%s: unable to open the logfile for stdout `%s': %s",
904 uberlord 2838 applet, redirect_stdout, strerror (errno));
905 uberlord 2577 }
906     if (redirect_stderr) {
907     if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND,
908     S_IRUSR | S_IWUSR)) == -1)
909     eerrorx ("%s: unable to open the logfile for stderr `%s': %s",
910 uberlord 2838 applet, redirect_stderr, strerror (errno));
911 uberlord 2577 }
912 uberlord 2547
913 uberlord 2577 if (background) {
914     /* Hmmm, some daemons may need stdin? */
915     dup2 (devnull_fd, STDIN_FILENO);
916     dup2 (stdout_fd, STDOUT_FILENO);
917     dup2 (stderr_fd, STDERR_FILENO);
918     }
919 uberlord 2547
920 uberlord 2577 for (i = getdtablesize () - 1; i >= 3; --i)
921     close(i);
922 uberlord 2547
923 uberlord 2577 setsid ();
924 uberlord 2547
925 uberlord 2577 execve (exec, argv, newenv);
926 uberlord 2547 #ifdef HAVE_PAM
927 uberlord 2577 if (pamr == PAM_SUCCESS)
928     pam_close_session (pamh, PAM_SILENT);
929 uberlord 2547 #endif
930 uberlord 2838 eerrorx ("%s: failed to exec `%s': %s", applet, exec, strerror (errno));
931 uberlord 2577 }
932 uberlord 2547
933 uberlord 2577 /* Parent process */
934     if (! background) {
935     /* As we're not backgrounding the process, wait for our pid to return */
936     int status = 0;
937     int savepid = pid;
938 uberlord 2547
939 uberlord 2577 errno = 0;
940     do {
941     pid = waitpid (savepid, &status, 0);
942     if (pid < 1) {
943     eerror ("waitpid %d: %s", savepid, strerror (errno));
944     return (-1);
945     }
946     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
947 uberlord 2547
948 uberlord 2577 if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) {
949     if (! quiet)
950 uberlord 2838 eerrorx ("%s: failed to start `%s'", applet, exec);
951 uberlord 2577 exit (EXIT_FAILURE);
952     }
953 uberlord 2547
954 uberlord 2577 pid = savepid;
955     }
956 uberlord 2547
957 uberlord 2577 /* Wait a little bit and check that process is still running
958     We do this as some badly written daemons fork and then barf */
959     if (START_WAIT > 0) {
960 uberlord 2828 struct timespec ts;
961     int nloops = START_WAIT / POLL_INTERVAL;
962     bool alive = false;
963 uberlord 2698 bool retestpid = false;
964 uberlord 2828
965     ts.tv_sec = 0;
966     ts.tv_nsec = POLL_INTERVAL;
967 uberlord 2547
968 uberlord 2828 while (nloops) {
969     if (nanosleep (&ts, NULL) == -1) {
970     if (errno == EINTR)
971 uberlord 2838 eerror ("%s: caught an interupt", applet);
972 uberlord 2828 else {
973 uberlord 2838 eerror ("%s: nanosleep: %s", applet, strerror (errno));
974 uberlord 2828 return (0);
975     }
976 uberlord 2577 }
977 uberlord 2828 nloops --;
978 uberlord 2547
979 uberlord 2577 /* This is knarly.
980     If we backgrounded then we know the exact pid.
981     Otherwise if we have a pidfile then it *may* know the exact pid.
982     Failing that, we'll have to query processes.
983     We sleep first as some programs like ntp like to fork, and write
984     their pidfile a LONG time later. */
985     if (background) {
986     if (kill (pid, 0) == 0)
987     alive = true;
988     } else {
989 uberlord 2698 if (pidfile) {
990     /* The pidfile may not have been written yet - give it some time */
991     if (get_pid (pidfile, true) == -1) {
992 uberlord 2577 alive = true;
993 uberlord 2698 retestpid = true;
994     } else {
995     retestpid = false;
996     if (do_stop (NULL, NULL, pidfile, uid, 0,
997     true, false, true) > 0)
998     alive = true;
999     }
1000 uberlord 2577 } else {
1001 uberlord 2698 if (do_stop (exec, cmd, NULL, uid, 0, true, false, true)
1002     > 0)
1003 uberlord 2577 alive = true;
1004     }
1005     }
1006 uberlord 2547
1007 uberlord 2577 if (! alive)
1008 uberlord 2838 eerrorx ("%s: %s died", applet, exec);
1009 uberlord 2577 }
1010 uberlord 2698
1011     if (retestpid) {
1012     if (do_stop (NULL, NULL, pidfile, uid, 0, true,
1013     false, true) < 1)
1014 uberlord 2838 eerrorx ("%s: %s died", applet, exec);
1015 uberlord 2698 }
1016 uberlord 2577 }
1017 uberlord 2547
1018 uberlord 2577 if (svcname)
1019     rc_set_service_daemon (svcname, exec, cmd, pidfile, true);
1020 uberlord 2547
1021 uberlord 2577 exit (EXIT_SUCCESS);
1022 uberlord 2547 }

  ViewVC Help
Powered by ViewVC 1.1.20