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

  ViewVC Help
Powered by ViewVC 1.1.20