/[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 - (show annotations) (download) (as text)
Mon May 14 12:37:13 2007 UTC (7 years, 4 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 /*
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 #include <sys/types.h>
16 #include <sys/ioctl.h>
17 #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 next = here->next;
75 free (here);
76 }
77
78 *list = NULL;
79 }
80
81 static void cleanup (void)
82 {
83 if (changeuser)
84 free (changeuser);
85
86 if (schedule)
87 free_schedulelist (&schedule);
88
89 if (newenv)
90 rc_strlist_free (newenv);
91 }
92
93 static int parse_signal (const char *sig)
94 {
95 typedef struct signalpair
96 {
97 const char *name;
98 int signal;
99 } signalpair_t;
100
101 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
123 unsigned int i = 0;
124 char *s;
125
126 if (! sig || strlen (sig) == 0)
127 return (-1);
128
129 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
135 if (strncmp (sig, "SIG", 3) == 0)
136 s = (char *) sig + 3;
137 else
138 s = NULL;
139
140 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
145 eerrorx ("%s: `%s' is not a valid signal", progname, sig);
146 }
147
148 static void parse_schedule_item (schedulelist_t *item, const char *string)
149 {
150 const char *after_hyph;
151 int sig;
152
153 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 }
170
171 static void parse_schedule (const char *string, int default_signal)
172 {
173 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
180 if (string)
181 for (slash = string; *slash; slash++)
182 if (*slash == '/')
183 count++;
184
185 if (schedule)
186 free_schedulelist (&schedule);
187
188 schedule = rc_xmalloc (sizeof (schedulelist_t));
189 schedule->gotolist = NULL;
190
191 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
206 return;
207 }
208
209 next = schedule;
210 while (string != NULL) {
211 if ((slash = strchr (string, '/')))
212 len = slash - string;
213 else
214 len = strlen (string);
215
216 if (len >= (ptrdiff_t) sizeof (buffer))
217 eerrorx ("%s: invalid schedule item, far too long", progname);
218
219 memcpy (buffer, string, len);
220 buffer[len] = 0;
221 string = slash ? slash + 1 : NULL;
222
223 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
229 repeatat = next;
230 continue;
231 }
232
233 if (string) {
234 next->next = rc_xmalloc (sizeof (schedulelist_t));
235 next = next->next;
236 next->gotolist = NULL;
237 }
238 }
239
240 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
248 next->next = NULL;
249 return;
250 }
251
252 static pid_t get_pid (const char *pidfile, bool quiet)
253 {
254 FILE *fp;
255 pid_t pid;
256
257 if (! pidfile)
258 return (-1);
259
260 if ((fp = fopen (pidfile, "r")) == NULL) {
261 if (! quiet)
262 eerror ("%s: fopen `%s': %s", progname, pidfile, strerror (errno));
263 return (-1);
264 }
265
266 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
274 return (pid);
275 }
276
277 /* return number of processed killed, -1 on error */
278 static int do_stop (const char *exec, const char *cmd,
279 const char *pidfile, uid_t uid,int sig,
280 bool quiet, bool verbose, bool test)
281 {
282 pid_t *pids;
283 bool killed;
284 int nkilled = 0;
285 pid_t pid = 0;
286 int i;
287
288 if (pidfile)
289 if ((pid = get_pid (pidfile, quiet)) == -1)
290 return (quiet ? 0 : -1);
291
292 if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL)
293 return (0);
294
295 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
303 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
322 free (pids);
323 return (nkilled);
324 }
325
326 static int run_stop_schedule (const char *exec, const char *cmd,
327 const char *pidfile, uid_t uid,
328 bool quiet, bool verbose, bool test)
329 {
330 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
338 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
349 while (item) {
350 switch (item->type) {
351 case schedule_goto:
352 item = item->gotolist;
353 continue;
354
355 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
369 tkilled += nkilled;
370 break;
371 case schedule_timeout:
372 if (item->value < 1) {
373 item = NULL;
374 break;
375 }
376
377 if (gettimeofday (&stopat, NULL) != 0) {
378 eerror ("%s: gettimeofday: %s", progname, strerror (errno));
379 return (0);
380 }
381
382 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
388 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 else {
394 eerror ("%s: select: %s", progname, strerror (errno));
395 return (0);
396 }
397 }
398
399 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
408 default:
409 eerror ("%s: invalid schedule item `%d'", progname, item->type);
410 return (0);
411 }
412
413 if (item)
414 item = item->next;
415 }
416
417 if (test || (tkilled > 0 && nrunning == 0))
418 return (nkilled);
419
420 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
427 return (-nrunning);
428 }
429
430 static void handle_signal (int sig)
431 {
432 int pid;
433 int status;
434 int serrno = errno;
435 char signame[10] = { '\0' };
436
437 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
449 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
459 default:
460 eerror ("%s: caught unknown signal %d", progname, sig);
461 }
462
463 /* Restore errno */
464 errno = serrno;
465 }
466
467 int main (int argc, char **argv)
468 {
469 int devnull_fd = -1;
470
471 #ifdef TIOCNOTTY
472 int tty_fd = -1;
473 #endif
474 #ifdef HAVE_PAM
475 pam_handle_t *pamh = NULL;
476 int pamr;
477 #endif
478
479 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 { "startas", 1, NULL, 'a'},
485 { "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 int opt;
505 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
534 progname = argv[0];
535 atexit (cleanup);
536
537 signal (SIGINT, handle_signal);
538 signal (SIGQUIT, handle_signal);
539 signal (SIGTERM, handle_signal);
540
541 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 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 case 'K': /* --stop */
550 stop = true;
551 break;
552
553 case 'N': /* --nice */
554 if (sscanf (optarg, "%d", &nicelevel) != 1)
555 eerrorx ("%s: invalid nice level `%s'", progname, optarg);
556 break;
557
558 case 'R': /* --retry <schedule>|<timeout> */
559 parse_schedule (optarg, sig);
560 break;
561
562 case 'S': /* --start */
563 start = true;
564 break;
565
566 case 'b': /* --background */
567 background = true;
568 break;
569
570 case 'c': /* --chuid <username>|<uid> */
571 {
572 char *p = optarg;
573 char *cu = strsep (&p, ":");
574 struct passwd *pw = NULL;
575
576 changeuser = rc_xstrdup (cu);
577 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 if (p) {
589 struct group *gr = NULL;
590 char *cg = strsep (&p, ":");
591
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 }
601 }
602 break;
603
604 case 'd': /* --chdir /new/dir */
605 ch_dir = optarg;
606 break;
607
608 case 'g': /* --group <group>|<gid> */
609 {
610 struct group *gr = getgrnam (optarg);
611
612 if (sscanf (optarg, "%d", &tid) != 1)
613 gr = getgrnam (optarg);
614 else
615 gr = getgrgid (tid);
616
617 if (! gr)
618 eerrorx ("%s: group `%s' not found", progname, optarg);
619 ch_gid = gr->gr_gid;
620 }
621 break;
622
623 case 'm': /* --make-pidfile */
624 makepidfile = true;
625 break;
626
627 case 'n': /* --name <process-name> */
628 cmd = optarg;
629 break;
630
631 case 'o': /* --oknodo */
632 oknodo = true;
633 break;
634
635 case 'p': /* --pidfile <pid-file> */
636 pidfile = optarg;
637 break;
638
639 case 'q': /* --quiet */
640 quiet = true;
641 break;
642
643 case 's': /* --signal <signal> */
644 sig = parse_signal (optarg);
645 break;
646
647 case 't': /* --test */
648 test = true;
649 break;
650
651 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
661 case 'r': /* --chroot /new/root */
662 ch_root = optarg;
663 break;
664
665 case 'v': /* --verbose */
666 verbose = true;
667 break;
668
669 case 'a':
670 case 'x': /* --exec <executable> */
671 exec = optarg;
672 break;
673
674 case '1': /* --stdout /path/to/stdout.lgfile */
675 redirect_stdout = optarg;
676 break;
677
678 case '2': /* --stderr /path/to/stderr.logfile */
679 redirect_stderr = optarg;
680 break;
681
682 default:
683 exit (EXIT_FAILURE);
684 }
685
686 /* Respect RC as well as how we are called */
687 if (rc_is_env ("RC_QUIET", "yes") && ! verbose)
688 quiet = true;
689
690 /* 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 if (start == stop)
703 eerrorx ("%s: need one of --start or --stop", progname);
704
705 if (start && ! exec)
706 eerrorx ("%s: --start needs --exec", progname);
707
708 if (stop && ! exec && ! pidfile && ! cmd && ! uid)
709 eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname);
710
711 if (makepidfile && ! pidfile)
712 eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname);
713
714 if (background && ! start)
715 eerrorx ("%s: --background is only relevant with --start", progname);
716
717 if ((redirect_stdout || redirect_stderr) && ! background)
718 eerrorx ("%s: --stdout and --stderr are only relevant with --background",
719 progname);
720
721 argc -= optind;
722 argv += optind;
723
724 /* 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
741 if (stop) {
742 int result;
743
744 if (! schedule) {
745 if (test || oknodo)
746 parse_schedule ("0", sig);
747 else
748 parse_schedule (NULL, sig);
749 }
750
751 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
757 if (pidfile && rc_is_file (pidfile))
758 unlink (pidfile);
759
760 if (svcname)
761 rc_set_service_daemon (svcname, exec, cmd, pidfile, false);
762
763 exit (EXIT_SUCCESS);
764 }
765
766 if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0)
767 eerrorx ("%s: %s is already running", progname, exec);
768
769 if (test) {
770 if (quiet)
771 exit (EXIT_SUCCESS);
772
773 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
792 /* 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
796 if (verbose) {
797 ebegin ("Detaching to start `%s'", exec);
798 eindent ();
799 }
800
801 if (background)
802 signal (SIGCHLD, handle_signal);
803
804 *--argv = exec;
805 if ((pid = fork ()) == -1)
806 eerrorx ("%s: fork: %s", progname, strerror (errno));
807
808 /* Child process - lets go! */
809 if (pid == 0) {
810 pid_t mypid = getpid ();
811
812 #ifdef TIOCNOTTY
813 tty_fd = open("/dev/tty", O_RDWR);
814 #endif
815
816 devnull_fd = open("/dev/null", O_RDWR);
817
818 if (nicelevel) {
819 if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1)
820 eerrorx ("%s: setpritory %d: %s", progname, nicelevel,
821 strerror(errno));
822 }
823
824 if (ch_root && chroot (ch_root) < 0)
825 eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno));
826
827 if (ch_dir && chdir (ch_dir) < 0)
828 eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno));
829
830 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
839 #ifdef HAVE_PAM
840 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
845 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 #endif
854
855 if (ch_gid && setgid (ch_gid))
856 eerrorx ("%s: unable to set groupid to %d", progname, ch_gid);
857 if (changeuser && initgroups (changeuser, ch_gid))
858 eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid);
859 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
873 /* Close any fd's to the passwd database */
874 endpwent ();
875
876 #ifdef TIOCNOTTY
877 ioctl(tty_fd, TIOCNOTTY, 0);
878 close(tty_fd);
879 #endif
880
881 /* 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
901 umask (022);
902
903 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
918 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
925 for (i = getdtablesize () - 1; i >= 3; --i)
926 close(i);
927
928 setsid ();
929
930 execve (exec, argv, newenv);
931 #ifdef HAVE_PAM
932 if (pamr == PAM_SUCCESS)
933 pam_close_session (pamh, PAM_SILENT);
934 #endif
935 eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno));
936 }
937
938 /* 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
944 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
953 if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) {
954 if (! quiet)
955 eerrorx ("%s: failed to started `%s'", progname, exec);
956 exit (EXIT_FAILURE);
957 }
958
959 pid = savepid;
960 }
961
962 /* 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 bool retestpid = false;
968
969 if (gettimeofday (&stopat, NULL) != 0)
970 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
971
972 stopat.tv_usec += START_WAIT;
973 while (1) {
974 bool alive = false;
975
976 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
984 if (gettimeofday (&now, NULL) != 0)
985 eerrorx ("%s: gettimeofday: %s", progname, strerror (errno));
986
987 /* 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 if (pidfile) {
998 /* The pidfile may not have been written yet - give it some time */
999 if (get_pid (pidfile, true) == -1) {
1000 alive = true;
1001 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 } else {
1009 if (do_stop (exec, cmd, NULL, uid, 0, true, false, true)
1010 > 0)
1011 alive = true;
1012 }
1013 }
1014
1015 if (! alive)
1016 eerrorx ("%s: %s died", progname, exec);
1017
1018 if (timercmp (&now, &stopat, >))
1019 break;
1020 }
1021
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 }
1028
1029 if (svcname)
1030 rc_set_service_daemon (svcname, exec, cmd, pidfile, true);
1031
1032 exit (EXIT_SUCCESS);
1033 }

  ViewVC Help
Powered by ViewVC 1.1.20