/[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 - (show annotations) (download) (as text)
Wed May 16 11:28:45 2007 UTC (7 years, 4 months ago) by uberlord
File MIME type: text/x-csrc
File size: 23889 byte(s)
Remove debug line
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 <time.h>
34 #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 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 } 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 schedulelist_t *here;
72 schedulelist_t *next;
73
74 for (here = *list; here; here = next) {
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 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 static int parse_signal (const char *sig)
109 {
110 typedef struct signalpair
111 {
112 const char *name;
113 int signal;
114 } signalpair_t;
115
116 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
138 unsigned int i = 0;
139 char *s;
140
141 if (! sig || strlen (sig) == 0)
142 return (-1);
143
144 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
150 if (strncmp (sig, "SIG", 3) == 0)
151 s = (char *) sig + 3;
152 else
153 s = NULL;
154
155 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
160 eerrorx ("%s: `%s' is not a valid signal", progname, sig);
161 }
162
163 static void parse_schedule_item (schedulelist_t *item, const char *string)
164 {
165 const char *after_hyph;
166 int sig;
167
168 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 }
185
186 static void parse_schedule (const char *string, int default_signal)
187 {
188 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
195 if (string)
196 for (slash = string; *slash; slash++)
197 if (*slash == '/')
198 count++;
199
200 if (schedule)
201 free_schedulelist (&schedule);
202
203 schedule = rc_xmalloc (sizeof (schedulelist_t));
204 schedule->gotolist = NULL;
205
206 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
221 return;
222 }
223
224 next = schedule;
225 while (string != NULL) {
226 if ((slash = strchr (string, '/')))
227 len = slash - string;
228 else
229 len = strlen (string);
230
231 if (len >= (ptrdiff_t) sizeof (buffer))
232 eerrorx ("%s: invalid schedule item, far too long", progname);
233
234 memcpy (buffer, string, len);
235 buffer[len] = 0;
236 string = slash ? slash + 1 : NULL;
237
238 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
244 repeatat = next;
245 continue;
246 }
247
248 if (string) {
249 next->next = rc_xmalloc (sizeof (schedulelist_t));
250 next = next->next;
251 next->gotolist = NULL;
252 }
253 }
254
255 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
263 next->next = NULL;
264 return;
265 }
266
267 static pid_t get_pid (const char *pidfile, bool quiet)
268 {
269 FILE *fp;
270 pid_t pid;
271
272 if (! pidfile)
273 return (-1);
274
275 if ((fp = fopen (pidfile, "r")) == NULL) {
276 if (! quiet)
277 eerror ("%s: fopen `%s': %s", progname, pidfile, strerror (errno));
278 return (-1);
279 }
280
281 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
289 return (pid);
290 }
291
292 /* return number of processed killed, -1 on error */
293 static int do_stop (const char *exec, const char *cmd,
294 const char *pidfile, uid_t uid,int sig,
295 bool quiet, bool verbose, bool test)
296 {
297 pid_t *pids;
298 bool killed;
299 int nkilled = 0;
300 pid_t pid = 0;
301 int i;
302
303 if (pidfile)
304 if ((pid = get_pid (pidfile, quiet)) == -1)
305 return (quiet ? 0 : -1);
306
307 if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL)
308 return (0);
309
310 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
318 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
337 free (pids);
338 return (nkilled);
339 }
340
341 static int run_stop_schedule (const char *exec, const char *cmd,
342 const char *pidfile, uid_t uid,
343 bool quiet, bool verbose, bool test)
344 {
345 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
353 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
364 while (item) {
365 switch (item->type) {
366 case schedule_goto:
367 item = item->gotolist;
368 continue;
369
370 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
384 tkilled += nkilled;
385 break;
386 case schedule_timeout:
387 if (item->value < 1) {
388 item = NULL;
389 break;
390 }
391
392 if (get_time (&stopat) != 0)
393 return (0);
394
395 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
401 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 else {
407 eerror ("%s: select: %s", progname, strerror (errno));
408 return (0);
409 }
410 }
411
412 if (get_time (&now) != 0)
413 return (0);
414 if (timercmp (&now, &stopat, >))
415 break;
416 }
417 break;
418
419 default:
420 eerror ("%s: invalid schedule item `%d'", progname, item->type);
421 return (0);
422 }
423
424 if (item)
425 item = item->next;
426 }
427
428 if (test || (tkilled > 0 && nrunning == 0))
429 return (nkilled);
430
431 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
438 return (-nrunning);
439 }
440
441 static void handle_signal (int sig)
442 {
443 int pid;
444 int status;
445 int serrno = errno;
446 char signame[10] = { '\0' };
447
448 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
460 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
470 default:
471 eerror ("%s: caught unknown signal %d", progname, sig);
472 }
473
474 /* Restore errno */
475 errno = serrno;
476 }
477
478 int main (int argc, char **argv)
479 {
480 int devnull_fd = -1;
481
482 #ifdef TIOCNOTTY
483 int tty_fd = -1;
484 #endif
485 #ifdef HAVE_PAM
486 pam_handle_t *pamh = NULL;
487 int pamr;
488 #endif
489
490 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 { "startas", 1, NULL, 'a'},
496 { "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 int opt;
516 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
545 progname = argv[0];
546 atexit (cleanup);
547
548 signal (SIGINT, handle_signal);
549 signal (SIGQUIT, handle_signal);
550 signal (SIGTERM, handle_signal);
551
552 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 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 case 'K': /* --stop */
561 stop = true;
562 break;
563
564 case 'N': /* --nice */
565 if (sscanf (optarg, "%d", &nicelevel) != 1)
566 eerrorx ("%s: invalid nice level `%s'", progname, optarg);
567 break;
568
569 case 'R': /* --retry <schedule>|<timeout> */
570 parse_schedule (optarg, sig);
571 break;
572
573 case 'S': /* --start */
574 start = true;
575 break;
576
577 case 'b': /* --background */
578 background = true;
579 break;
580
581 case 'c': /* --chuid <username>|<uid> */
582 {
583 char *p = optarg;
584 char *cu = strsep (&p, ":");
585 struct passwd *pw = NULL;
586
587 changeuser = rc_xstrdup (cu);
588 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 if (p) {
600 struct group *gr = NULL;
601 char *cg = strsep (&p, ":");
602
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 }
612 }
613 break;
614
615 case 'd': /* --chdir /new/dir */
616 ch_dir = optarg;
617 break;
618
619 case 'g': /* --group <group>|<gid> */
620 {
621 struct group *gr = getgrnam (optarg);
622
623 if (sscanf (optarg, "%d", &tid) != 1)
624 gr = getgrnam (optarg);
625 else
626 gr = getgrgid (tid);
627
628 if (! gr)
629 eerrorx ("%s: group `%s' not found", progname, optarg);
630 ch_gid = gr->gr_gid;
631 }
632 break;
633
634 case 'm': /* --make-pidfile */
635 makepidfile = true;
636 break;
637
638 case 'n': /* --name <process-name> */
639 cmd = optarg;
640 break;
641
642 case 'o': /* --oknodo */
643 oknodo = true;
644 break;
645
646 case 'p': /* --pidfile <pid-file> */
647 pidfile = optarg;
648 break;
649
650 case 'q': /* --quiet */
651 quiet = true;
652 break;
653
654 case 's': /* --signal <signal> */
655 sig = parse_signal (optarg);
656 break;
657
658 case 't': /* --test */
659 test = true;
660 break;
661
662 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
672 case 'r': /* --chroot /new/root */
673 ch_root = optarg;
674 break;
675
676 case 'v': /* --verbose */
677 verbose = true;
678 break;
679
680 case 'a':
681 case 'x': /* --exec <executable> */
682 exec = optarg;
683 break;
684
685 case '1': /* --stdout /path/to/stdout.lgfile */
686 redirect_stdout = optarg;
687 break;
688
689 case '2': /* --stderr /path/to/stderr.logfile */
690 redirect_stderr = optarg;
691 break;
692
693 default:
694 exit (EXIT_FAILURE);
695 }
696
697 /* Respect RC as well as how we are called */
698 if (rc_is_env ("RC_QUIET", "yes") && ! verbose)
699 quiet = true;
700
701 /* 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 if (start == stop)
714 eerrorx ("%s: need one of --start or --stop", progname);
715
716 if (start && ! exec)
717 eerrorx ("%s: --start needs --exec", progname);
718
719 if (stop && ! exec && ! pidfile && ! cmd && ! uid)
720 eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname);
721
722 if (makepidfile && ! pidfile)
723 eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname);
724
725 if (background && ! start)
726 eerrorx ("%s: --background is only relevant with --start", progname);
727
728 if ((redirect_stdout || redirect_stderr) && ! background)
729 eerrorx ("%s: --stdout and --stderr are only relevant with --background",
730 progname);
731
732 argc -= optind;
733 argv += optind;
734
735 /* 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
752 if (stop) {
753 int result;
754
755 if (! schedule) {
756 if (test || oknodo)
757 parse_schedule ("0", sig);
758 else
759 parse_schedule (NULL, sig);
760 }
761
762 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
768 if (pidfile && rc_is_file (pidfile))
769 unlink (pidfile);
770
771 if (svcname)
772 rc_set_service_daemon (svcname, exec, cmd, pidfile, false);
773
774 exit (EXIT_SUCCESS);
775 }
776
777 if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0)
778 eerrorx ("%s: %s is already running", progname, exec);
779
780 if (test) {
781 if (quiet)
782 exit (EXIT_SUCCESS);
783
784 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
803 /* 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
807 if (verbose) {
808 ebegin ("Detaching to start `%s'", exec);
809 eindent ();
810 }
811
812 if (background)
813 signal (SIGCHLD, handle_signal);
814
815 *--argv = exec;
816 if ((pid = fork ()) == -1)
817 eerrorx ("%s: fork: %s", progname, strerror (errno));
818
819 /* Child process - lets go! */
820 if (pid == 0) {
821 pid_t mypid = getpid ();
822
823 #ifdef TIOCNOTTY
824 tty_fd = open("/dev/tty", O_RDWR);
825 #endif
826
827 devnull_fd = open("/dev/null", O_RDWR);
828
829 if (nicelevel) {
830 if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1)
831 eerrorx ("%s: setpritory %d: %s", progname, nicelevel,
832 strerror(errno));
833 }
834
835 if (ch_root && chroot (ch_root) < 0)
836 eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno));
837
838 if (ch_dir && chdir (ch_dir) < 0)
839 eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno));
840
841 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
850 #ifdef HAVE_PAM
851 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
856 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 #endif
865
866 if (ch_gid && setgid (ch_gid))
867 eerrorx ("%s: unable to set groupid to %d", progname, ch_gid);
868 if (changeuser && initgroups (changeuser, ch_gid))
869 eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid);
870 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
884 /* Close any fd's to the passwd database */
885 endpwent ();
886
887 #ifdef TIOCNOTTY
888 ioctl(tty_fd, TIOCNOTTY, 0);
889 close(tty_fd);
890 #endif
891
892 /* 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
912 umask (022);
913
914 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
929 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
936 for (i = getdtablesize () - 1; i >= 3; --i)
937 close(i);
938
939 setsid ();
940
941 execve (exec, argv, newenv);
942 #ifdef HAVE_PAM
943 if (pamr == PAM_SUCCESS)
944 pam_close_session (pamh, PAM_SILENT);
945 #endif
946 eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno));
947 }
948
949 /* 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
955 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
964 if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) {
965 if (! quiet)
966 eerrorx ("%s: failed to started `%s'", progname, exec);
967 exit (EXIT_FAILURE);
968 }
969
970 pid = savepid;
971 }
972
973 /* 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 bool retestpid = false;
979
980 if (get_time (&stopat) != 0)
981 exit (EXIT_FAILURE);
982
983 stopat.tv_usec += START_WAIT;
984 while (1) {
985 bool alive = false;
986
987 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
995 /* 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 if (pidfile) {
1006 /* The pidfile may not have been written yet - give it some time */
1007 if (get_pid (pidfile, true) == -1) {
1008 alive = true;
1009 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 } else {
1017 if (do_stop (exec, cmd, NULL, uid, 0, true, false, true)
1018 > 0)
1019 alive = true;
1020 }
1021 }
1022
1023 if (! alive)
1024 eerrorx ("%s: %s died", progname, exec);
1025
1026 if (get_time (&now) != 0)
1027 exit (EXIT_FAILURE);
1028 if (timercmp (&now, &stopat, >))
1029 break;
1030 }
1031
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 }
1038
1039 if (svcname)
1040 rc_set_service_daemon (svcname, exec, cmd, pidfile, true);
1041
1042 exit (EXIT_SUCCESS);
1043 }

  ViewVC Help
Powered by ViewVC 1.1.20