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

  ViewVC Help
Powered by ViewVC 1.1.20