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

  ViewVC Help
Powered by ViewVC 1.1.20