/[baselayout]/trunk/src/runscript.c
Gentoo

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2740 - (show annotations) (download) (as text)
Mon Jul 2 22:07:58 2007 UTC (7 years, 2 months ago) by uberlord
File MIME type: text/x-csrc
File size: 33029 byte(s)
Don't wait for services that were inactive, #183667 thanks to Daniel Drake
1 /*
2 * runscript.c
3 * Handle launching of Gentoo init scripts.
4 *
5 * Copyright 1999-2007 Gentoo Foundation
6 * Distributed under the terms of the GNU General Public License v2
7 */
8
9 #define APPLET "runscript"
10
11 #include <sys/types.h>
12 #include <sys/param.h>
13 #include <sys/stat.h>
14 #include <sys/wait.h>
15 #include <dlfcn.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <getopt.h>
19 #include <libgen.h>
20 #include <limits.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "einfo.h"
28 #include "rc.h"
29 #include "rc-misc.h"
30 #include "rc-plugin.h"
31 #include "strlist.h"
32
33 #define RCSCRIPT_HELP RC_LIBDIR "/sh/rc-help.sh"
34 #define SELINUX_LIB RC_LIBDIR "/runscript_selinux.so"
35
36 #define PREFIX_LOCK RC_SVCDIR "/prefix.lock"
37
38 static char *applet = NULL;
39 static char *service = NULL;
40 static char *exclusive = NULL;
41 static char *mtime_test = NULL;
42 static rc_depinfo_t *deptree = NULL;
43 static char **services = NULL;
44 static char **svclist = NULL;
45 static char **tmplist = NULL;
46 static char **providelist = NULL;
47 static char **types = NULL;
48 static char **restart_services = NULL;
49 static char **need_services = NULL;
50 static char **env = NULL;
51 static char *tmp = NULL;
52 static char *softlevel = NULL;
53 static bool sighup = false;
54 static char *ibsave = NULL;
55 static bool in_background = false;
56 static rc_hook_t hook_out = 0;
57 static pid_t service_pid = 0;
58 static char *prefix = NULL;
59 static bool prefix_locked = false;
60
61 extern char **environ;
62
63 #ifdef __linux__
64 static void (*selinux_run_init_old) (void);
65 static void (*selinux_run_init_new) (int argc, char **argv);
66
67 static void setup_selinux (int argc, char **argv);
68 #endif
69
70 #ifdef __linux__
71 static void setup_selinux (int argc, char **argv)
72 {
73 void *lib_handle = NULL;
74
75 lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL);
76 if (lib_handle) {
77 /*
78 * FIXME: the below code generates the warning
79 * ISO C forbids assignment between function pointer and 'void *'
80 * which sucks ass
81 * http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html
82 */
83 selinux_run_init_old = (void (*)(void)) dlfunc (lib_handle, "selinux_runscript");
84 selinux_run_init_new = (void (*)(int, char **)) dlfunc (lib_handle, "selinux_runscript2");
85
86 /* Use new run_init if it rc_exists, else fall back to old */
87 if (selinux_run_init_new)
88 selinux_run_init_new (argc, argv);
89 else if (selinux_run_init_old)
90 selinux_run_init_old ();
91 else
92 /* This shouldnt happen... probably corrupt lib */
93 eerrorx ("run_init is missing from runscript_selinux.so!");
94 }
95 }
96 #endif
97
98 static void handle_signal (int sig)
99 {
100 pid_t pid;
101 int status;
102 int serrno = errno;
103 char signame[10] = { '\0' };
104
105 switch (sig) {
106 case SIGHUP:
107 sighup = true;
108 break;
109
110 case SIGCHLD:
111 do {
112 pid = waitpid (-1, &status, WNOHANG);
113 if (pid < 0) {
114 if (errno != ECHILD)
115 eerror ("waitpid: %s", strerror (errno));
116 return;
117 }
118 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
119 if (pid == service_pid)
120 service_pid = 0;
121 break;
122
123 case SIGINT:
124 if (! signame[0])
125 snprintf (signame, sizeof (signame), "SIGINT");
126 case SIGTERM:
127 if (! signame[0])
128 snprintf (signame, sizeof (signame), "SIGTERM");
129 case SIGQUIT:
130 if (! signame[0])
131 snprintf (signame, sizeof (signame), "SIGQUIT");
132 /* Send the signal to our children too */
133 if (service_pid > 0)
134 kill (service_pid, sig);
135 eerrorx ("%s: caught %s, aborting", applet, signame);
136
137 default:
138 eerror ("%s: caught unknown signal %d", applet, sig);
139 }
140
141 /* Restore errno */
142 errno = serrno;
143 }
144
145 static time_t get_mtime (const char *pathname, bool follow_link)
146 {
147 struct stat buf;
148 int retval;
149
150 if (! pathname)
151 return (0);
152
153 retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf);
154 if (! retval)
155 return (buf.st_mtime);
156
157 errno = 0;
158 return (0);
159 }
160
161 static bool in_control ()
162 {
163 char *path;
164 time_t mtime;
165 const char *tests[] = { "starting", "started", "stopping",
166 "inactive", "wasinactive", NULL };
167 int i = 0;
168
169 if (sighup)
170 return (false);
171
172 if (! mtime_test || ! rc_exists (mtime_test))
173 return (false);
174
175 if (rc_service_state (applet, rc_service_stopped))
176 return (false);
177
178 if (! (mtime = get_mtime (mtime_test, false)))
179 return (false);
180
181 while (tests[i]) {
182 path = rc_strcatpaths (RC_SVCDIR, tests[i], applet, (char *) NULL);
183 if (rc_exists (path)) {
184 time_t m = get_mtime (path, false);
185 if (mtime < m && m != 0) {
186 free (path);
187 return (false);
188 }
189 }
190 free (path);
191 i++;
192 }
193
194 return (true);
195 }
196
197 static void uncoldplug ()
198 {
199 char *cold = rc_strcatpaths (RC_SVCDIR "coldplugged", applet, (char *) NULL);
200 if (rc_exists (cold) && unlink (cold) != 0)
201 eerror ("%s: unlink `%s': %s", applet, cold, strerror (errno));
202 free (cold);
203 }
204
205 static void start_services (char **list) {
206 bool inactive;
207 char *svc;
208 int i;
209
210 if (! list)
211 return;
212
213 inactive = rc_service_state (service, rc_service_inactive);
214 if (! inactive)
215 inactive = rc_service_state (service, rc_service_wasinactive);
216
217 if (inactive ||
218 rc_service_state (service, rc_service_starting) ||
219 rc_service_state (service, rc_service_started))
220 {
221 STRLIST_FOREACH (list, svc, i) {
222 if (rc_service_state (svc, rc_service_stopped)) {
223 if (inactive) {
224 rc_schedule_start_service (service, svc);
225 ewarn ("WARNING: %s is scheduled to started when %s has started",
226 svc, applet);
227 } else
228 rc_start_service (svc);
229 }
230 }
231 }
232 }
233
234 static void cleanup (void)
235 {
236 if (prefix_locked)
237 unlink (PREFIX_LOCK);
238
239 /* Flush our buffered output if any */
240 eclose ();
241
242 if (hook_out)
243 rc_plugin_run (hook_out, applet);
244 rc_plugin_unload ();
245
246 if (restart_services ) {
247 start_services (restart_services);
248 rc_strlist_free (restart_services);
249 }
250
251 rc_free_deptree (deptree);
252 rc_strlist_free (services);
253 rc_strlist_free (types);
254 rc_strlist_free (svclist);
255 rc_strlist_free (providelist);
256 rc_strlist_free (need_services);
257 rc_strlist_free (tmplist);
258 free (ibsave);
259
260 if (in_control ()) {
261 if (rc_service_state (applet, rc_service_stopping)) {
262 /* If the we're shutting down, do it cleanly */
263 if ((softlevel &&
264 rc_runlevel_stopping () &&
265 (strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 ||
266 strcmp (softlevel, RC_LEVEL_REBOOT) == 0)))
267 rc_mark_service (applet, rc_service_stopped);
268 else if (rc_service_state (applet, rc_service_wasinactive))
269 rc_mark_service (applet, rc_service_inactive);
270 else
271 rc_mark_service (applet, rc_service_started);
272 }
273 else if (rc_service_state (applet, rc_service_starting))
274 {
275 if (rc_service_state (applet, rc_service_wasinactive))
276 rc_mark_service (applet, rc_service_inactive);
277 else
278 rc_mark_service (applet, rc_service_stopped);
279 }
280 if (exclusive && rc_exists (exclusive))
281 unlink (exclusive);
282 }
283
284 rc_strlist_free (env);
285
286 if (mtime_test)
287 {
288 unlink (mtime_test);
289 free (mtime_test);
290 }
291 free (exclusive);
292 free (applet);
293 free (prefix);
294 }
295
296 static int write_prefix (int fd, const char *buffer, size_t bytes, bool *prefixed) {
297 unsigned int i;
298 int j;
299 const char *ec;
300 const char *ec_normal = ecolor (ecolor_normal);
301 ssize_t ret = 0;
302
303 if (fd == fileno (stdout))
304 ec = ecolor (ecolor_hilite);
305 else
306 ec = ecolor (ecolor_bad);
307
308 for (i = 0; i < bytes; i++) {
309 /* We don't prefix escape codes, like eend */
310 if (buffer[i] == '\033')
311 *prefixed = true;
312
313 if (! *prefixed) {
314 ret += write (fd, ec, strlen (ec));
315 ret += write (fd, applet, strlen (applet));
316 for (j = strlen (applet); j < 11; j++)
317 ret += write (fd, " ", 1);
318 ret += write (fd, ec_normal, strlen (ec_normal));
319 ret += write (fd, " |", 2);
320 *prefixed = true;
321 }
322
323 if (buffer[i] == '\n')
324 *prefixed = false;
325 ret += write (fd, buffer + i, 1);
326 }
327
328 return (ret);
329 }
330
331 static bool svc_exec (const char *arg1, const char *arg2)
332 {
333 bool execok;
334 int stdout_pipes[2];
335 int stderr_pipes[2];
336
337 /* To ensure any output has hit our ebuffer */
338 fflush (stdout);
339 fflush (stderr);
340
341 /* Setup our pipes for prefixed output */
342 if (rc_is_env ("RC_PREFIX", "yes")) {
343 if (pipe (stdout_pipes))
344 eerror ("pipe: %s", strerror (errno));
345 if (pipe (stderr_pipes))
346 eerror ("pipe: %s", strerror (errno));
347 }
348
349 /* We need to disable our child signal handler now so we block
350 until our script returns. */
351 signal (SIGCHLD, NULL);
352
353 service_pid = vfork();
354
355 if (service_pid == -1)
356 eerrorx ("%s: vfork: %s", service, strerror (errno));
357 if (service_pid == 0) {
358 if (rc_is_env ("RC_PREFIX", "yes")) {
359 int flags;
360
361 if (dup2 (stdout_pipes[1], fileno (stdout)) == -1)
362 eerror ("dup2 stdout: %s", strerror (errno));
363 close (stdout_pipes[0]);
364 if (dup2 (stderr_pipes[1], fileno (stderr)) == -1)
365 eerror ("dup2 stderr: %s", strerror (errno));
366 close (stderr_pipes[0]);
367
368 /* Stop any scripts from inheriting us */
369 if ((flags = fcntl (stdout_pipes[1], F_GETFD, 0)) < 0 ||
370 fcntl (stdout_pipes[1], F_SETFD, flags | FD_CLOEXEC) < 0)
371 eerror ("fcntl: %s", strerror (errno));
372 if ((flags = fcntl (stderr_pipes[1], F_GETFD, 0)) < 0 ||
373 fcntl (stderr_pipes[1], F_SETFD, flags | FD_CLOEXEC) < 0)
374 eerror ("fcntl: %s", strerror (errno));
375 }
376
377 if (rc_exists (RC_SVCDIR "runscript.sh")) {
378 execl (RC_SVCDIR "runscript.sh", service, service, arg1, arg2,
379 (char *) NULL);
380 eerror ("%s: exec `" RC_SVCDIR "runscript.sh': %s",
381 service, strerror (errno));
382 _exit (EXIT_FAILURE);
383 } else {
384 execl (RC_LIBDIR "sh/runscript.sh", service, service, arg1, arg2,
385 (char *) NULL);
386 eerror ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s",
387 service, strerror (errno));
388 _exit (EXIT_FAILURE);
389 }
390 }
391
392 /* Prefix our piped output */
393 if (rc_is_env ("RC_PREFIX", "yes")) {
394 bool stdout_done = false;
395 bool stdout_prefix_shown = false;
396 bool stderr_done = false;
397 bool stderr_prefix_shown = false;
398 char buffer[RC_LINEBUFFER];
399
400 close (stdout_pipes[1]);
401 close (stderr_pipes[1]);
402
403 memset (buffer, 0, RC_LINEBUFFER);
404 while (! stdout_done && ! stderr_done) {
405 fd_set fds;
406 int retval;
407
408 FD_ZERO (&fds);
409 FD_SET (stdout_pipes[0], &fds);
410 FD_SET (stderr_pipes[0], &fds);
411 retval = select (MAX (stdout_pipes[0], stderr_pipes[0]) + 1,
412 &fds, 0, 0, 0);
413 if (retval < 0) {
414 if (errno != EINTR) {
415 eerror ("select: %s", strerror (errno));
416 break;
417 }
418 } else if (retval) {
419 ssize_t nr;
420
421 /* Wait until we get a lock */
422 while (true) {
423 struct timeval tv;
424
425 if (mkfifo (PREFIX_LOCK, 0700) == 0) {
426 prefix_locked = true;
427 break;
428 }
429
430 if (errno != EEXIST)
431 eerror ("mkfifo `%s': %s\n", PREFIX_LOCK, strerror (errno));
432 tv.tv_sec = 0;
433 tv.tv_usec = 20000;
434 select (0, NULL, NULL, NULL, &tv);
435 }
436
437 if (FD_ISSET (stdout_pipes[0], &fds)) {
438 if ((nr = read (stdout_pipes[0], buffer,
439 sizeof (buffer))) <= 0)
440 stdout_done = true;
441 else
442 write_prefix (fileno (stdout), buffer, nr,
443 &stdout_prefix_shown);
444 }
445
446 if (FD_ISSET (stderr_pipes[0], &fds)) {
447 if ((nr = read (stderr_pipes[0], buffer,
448 sizeof (buffer))) <= 0)
449 stderr_done = true;
450 else
451 write_prefix (fileno (stderr), buffer, nr,
452 &stderr_prefix_shown);
453 }
454
455 /* Clear the lock */
456 unlink (PREFIX_LOCK);
457 prefix_locked = false;
458 }
459 }
460
461 /* Done now, so close the pipes */
462 close(stdout_pipes[0]);
463 close(stderr_pipes[0]);
464 }
465
466 execok = rc_waitpid (service_pid) == 0 ? true : false;
467 service_pid = 0;
468
469 /* Done, so restore the signal handler */
470 signal (SIGCHLD, handle_signal);
471
472 return (execok);
473 }
474
475 static rc_service_state_t svc_status ()
476 {
477 char status[10];
478 int (*e) (const char *fmt, ...) = &einfo;
479
480 rc_service_state_t retval = rc_service_stopped;
481
482 if (rc_service_state (service, rc_service_stopping)) {
483 snprintf (status, sizeof (status), "stopping");
484 e = &ewarn;
485 retval = rc_service_stopping;
486 } else if (rc_service_state (service, rc_service_starting)) {
487 snprintf (status, sizeof (status), "starting");
488 e = &ewarn;
489 retval = rc_service_starting;
490 } else if (rc_service_state (service, rc_service_inactive)) {
491 snprintf (status, sizeof (status), "inactive");
492 e = &ewarn;
493 retval = rc_service_inactive;
494 } else if (rc_service_state (service, rc_service_crashed)) {
495 snprintf (status, sizeof (status), "crashed");
496 e = &eerror;
497 retval = rc_service_crashed;
498 } else if (rc_service_state (service, rc_service_started)) {
499 snprintf (status, sizeof (status), "started");
500 retval = rc_service_started;
501 } else
502 snprintf (status, sizeof (status), "stopped");
503
504 e ("status: %s", status);
505 return (retval);
506 }
507
508 static void make_exclusive ()
509 {
510 char *path;
511 int i;
512
513 /* We create a fifo so that other services can wait until we complete */
514 if (! exclusive)
515 exclusive = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL);
516
517 if (mkfifo (exclusive, 0600) != 0 && errno != EEXIST &&
518 (errno != EACCES || geteuid () == 0))
519 eerrorx ("%s: unable to create fifo `%s': %s",
520 applet, exclusive, strerror (errno));
521
522 path = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL);
523 i = strlen (path) + 16;
524 mtime_test = rc_xmalloc (sizeof (char *) * i);
525 snprintf (mtime_test, i, "%s.%d", path, getpid ());
526 free (path);
527
528 if (rc_exists (mtime_test) && unlink (mtime_test) != 0) {
529 eerror ("%s: unlink `%s': %s",
530 applet, mtime_test, strerror (errno));
531 free (mtime_test);
532 mtime_test = NULL;
533 return;
534 }
535
536 if (symlink (service, mtime_test) != 0) {
537 eerror ("%s: symlink `%s' to `%s': %s",
538 applet, service, mtime_test, strerror (errno));
539 free (mtime_test);
540 mtime_test = NULL;
541 }
542 }
543
544 static void unlink_mtime_test ()
545 {
546 if (unlink (mtime_test) != 0)
547 eerror ("%s: unlink `%s': %s", applet, mtime_test, strerror (errno));
548 free (mtime_test);
549 mtime_test = NULL;
550 }
551
552 static void get_started_services ()
553 {
554 char *svc;
555 int i;
556
557 rc_strlist_free (tmplist);
558 tmplist = rc_services_in_state (rc_service_inactive);
559
560 rc_strlist_free (restart_services);
561 restart_services = rc_services_in_state (rc_service_started);
562
563 STRLIST_FOREACH (tmplist, svc, i)
564 restart_services = rc_strlist_addsort (restart_services, svc);
565
566 rc_strlist_free (tmplist);
567 tmplist = NULL;
568 }
569
570 static void svc_start (bool deps)
571 {
572 bool started;
573 bool background = false;
574 char *svc;
575 char *svc2;
576 int i;
577 int j;
578 int depoptions = RC_DEP_TRACE;
579
580 rc_plugin_run (rc_hook_service_start_in, applet);
581 hook_out = rc_hook_service_start_out;
582
583 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
584 depoptions |= RC_DEP_STRICT;
585
586 if (rc_is_env ("IN_HOTPLUG", "1") || in_background) {
587 if (! rc_service_state (service, rc_service_inactive) &&
588 ! rc_service_state (service, rc_service_stopped))
589 exit (EXIT_FAILURE);
590 background = true;
591 }
592
593 if (rc_service_state (service, rc_service_started)) {
594 ewarn ("WARNING: %s has already been started", applet);
595 return;
596 } else if (rc_service_state (service, rc_service_starting))
597 ewarnx ("WARNING: %s is already starting", applet);
598 else if (rc_service_state (service, rc_service_stopping))
599 ewarnx ("WARNING: %s is stopping", applet);
600 else if (rc_service_state (service, rc_service_inactive) && ! background)
601 ewarnx ("WARNING: %s has already started, but is inactive", applet);
602
603 if (! rc_mark_service (service, rc_service_starting))
604 eerrorx ("ERROR: %s has been started by something else", applet);
605
606 make_exclusive (service);
607
608 if (deps) {
609 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
610 eerrorx ("failed to load deptree");
611
612 rc_strlist_free (types);
613 types = rc_strlist_add (NULL, "broken");
614 rc_strlist_free (svclist);
615 svclist = rc_strlist_add (NULL, applet);
616 rc_strlist_free (services);
617 services = rc_get_depends (deptree, types, svclist, softlevel, 0);
618 if (services) {
619 eerrorn ("ERROR: `%s' needs ", applet);
620 STRLIST_FOREACH (services, svc, i) {
621 if (i > 0)
622 fprintf (stderr, ", ");
623 fprintf (stderr, "%s", svc);
624 }
625 exit (EXIT_FAILURE);
626 }
627 rc_strlist_free (services);
628 services = NULL;
629
630 rc_strlist_free (types);
631 types = rc_strlist_add (NULL, "ineed");
632 rc_strlist_free (need_services);
633 need_services = rc_get_depends (deptree, types, svclist,
634 softlevel, depoptions);
635 types = rc_strlist_add (types, "iuse");
636 if (! rc_runlevel_starting ()) {
637 services = rc_get_depends (deptree, types, svclist,
638 softlevel, depoptions);
639 STRLIST_FOREACH (services, svc, i)
640 if (rc_service_state (svc, rc_service_stopped)) {
641 pid_t pid = rc_start_service (svc);
642 if (! rc_is_env ("RC_PARALLEL", "yes"))
643 rc_waitpid (pid);
644 }
645
646 rc_strlist_free (services);
647 }
648
649 /* Now wait for them to start */
650 types = rc_strlist_add (types, "iafter");
651 services = rc_get_depends (deptree, types, svclist,
652 softlevel, depoptions);
653
654 /* We use tmplist to hold our scheduled by list */
655 rc_strlist_free (tmplist);
656 tmplist = NULL;
657
658 STRLIST_FOREACH (services, svc, i) {
659 /* don't wait for services which went inactive but are now in
660 * starting state */
661 if (rc_service_state (svc, rc_service_started) ||
662 (rc_service_state (svc, rc_service_starting) &&
663 rc_service_state(svc, rc_service_wasinactive)))
664 continue;
665
666 if (! rc_wait_service (svc))
667 eerror ("%s: timed out waiting for %s", applet, svc);
668 if (rc_service_state (svc, rc_service_started))
669 continue;
670
671 STRLIST_FOREACH (need_services, svc2, j)
672 if (strcmp (svc, svc2) == 0) {
673 if (rc_service_state (svc, rc_service_inactive) ||
674 rc_service_state (svc, rc_service_wasinactive))
675 tmplist = rc_strlist_add (tmplist, svc);
676 else
677 eerrorx ("ERROR: cannot start %s as %s would not start",
678 applet, svc);
679 }
680 }
681
682 if (tmplist) {
683 int n = 0;
684 int len = 0;
685 char *p;
686
687 /* Set the state now, then unlink our exclusive so that
688 our scheduled list is preserved */
689 rc_mark_service (service, rc_service_stopped);
690 unlink_mtime_test ();
691
692 rc_strlist_free (types);
693 types = rc_strlist_add (NULL, "iprovide");
694 STRLIST_FOREACH (tmplist, svc, i) {
695 rc_schedule_start_service (svc, service);
696
697 rc_strlist_free (svclist);
698 svclist = rc_strlist_add (NULL, svc);
699 rc_strlist_free (providelist);
700 providelist = rc_get_depends (deptree, types, svclist,
701 softlevel, depoptions);
702 STRLIST_FOREACH (providelist, svc2, j)
703 rc_schedule_start_service (svc2, service);
704
705 len += strlen (svc) + 2;
706 n++;
707 }
708
709 len += 5;
710 tmp = rc_xmalloc (sizeof (char *) * len);
711 p = tmp;
712 STRLIST_FOREACH (tmplist, svc, i) {
713 if (i > 1) {
714 if (i == n - 1)
715 p += snprintf (p, len, " or ");
716 else
717 p += snprintf (p, len, ", ");
718 }
719 p += snprintf (p, len, "%s", svc);
720 }
721 ewarnx ("WARNING: %s is scheduled to start when %s has started",
722 applet, tmp);
723 }
724
725 rc_strlist_free (services);
726 services = NULL;
727 rc_strlist_free (types);
728 types = NULL;
729 rc_strlist_free (svclist);
730 svclist = NULL;
731 }
732
733 if (ibsave)
734 setenv ("IN_BACKGROUND", ibsave, 1);
735 rc_plugin_run (rc_hook_service_start_now, applet);
736 started = svc_exec ("start", NULL);
737 if (ibsave)
738 unsetenv ("IN_BACKGROUND");
739
740 if (in_control ()) {
741 if (! started) {
742 if (rc_service_state (service, rc_service_wasinactive))
743 rc_mark_service (service, rc_service_inactive);
744 else {
745 rc_mark_service (service, rc_service_stopped);
746 if (rc_runlevel_starting ())
747 rc_mark_service (service, rc_service_failed);
748 }
749 rc_plugin_run (rc_hook_service_start_done, applet);
750 eerrorx ("ERROR: %s failed to start", applet);
751 }
752 rc_mark_service (service, rc_service_started);
753 unlink_mtime_test ();
754 rc_plugin_run (rc_hook_service_start_done, applet);
755 } else {
756 rc_plugin_run (rc_hook_service_start_done, applet);
757 if (rc_service_state (service, rc_service_inactive))
758 ewarnx ("WARNING: %s has started, but is inactive", applet);
759 else
760 ewarnx ("WARNING: %s not under our control, aborting", applet);
761 }
762
763 /* Now start any scheduled services */
764 rc_strlist_free (services);
765 services = rc_services_scheduled (service);
766 STRLIST_FOREACH (services, svc, i)
767 if (rc_service_state (svc, rc_service_stopped))
768 rc_start_service (svc);
769 rc_strlist_free (services);
770 services = NULL;
771
772 /* Do the same for any services we provide */
773 rc_strlist_free (types);
774 types = rc_strlist_add (NULL, "iprovide");
775 rc_strlist_free (svclist);
776 svclist = rc_strlist_add (NULL, applet);
777 rc_strlist_free (tmplist);
778 tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions);
779
780 STRLIST_FOREACH (tmplist, svc2, j) {
781 rc_strlist_free (services);
782 services = rc_services_scheduled (svc2);
783 STRLIST_FOREACH (services, svc, i)
784 if (rc_service_state (svc, rc_service_stopped))
785 rc_start_service (svc);
786 }
787
788 hook_out = 0;
789 rc_plugin_run (rc_hook_service_start_out, applet);
790 }
791
792 static void svc_stop (bool deps)
793 {
794 bool stopped;
795
796 hook_out = rc_hook_service_stop_out;
797
798 if (rc_runlevel_stopping () &&
799 rc_service_state (service, rc_service_failed))
800 exit (EXIT_FAILURE);
801
802 if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
803 if (! rc_service_state (service, rc_service_started) &&
804 ! rc_service_state (service, rc_service_inactive))
805 exit (EXIT_FAILURE);
806
807 if (rc_service_state (service, rc_service_stopped)) {
808 ewarn ("WARNING: %s is already stopped", applet);
809 return;
810 } else if (rc_service_state (service, rc_service_stopping))
811 ewarnx ("WARNING: %s is already stopping", applet);
812
813 if (! rc_mark_service (service, rc_service_stopping))
814 eerrorx ("ERROR: %s has been stopped by something else", applet);
815
816 make_exclusive (service);
817
818 if (! rc_runlevel_stopping () &&
819 rc_service_in_runlevel (service, RC_LEVEL_BOOT))
820 ewarn ("WARNING: you are stopping a boot service");
821
822 if (deps || ! rc_service_state (service, rc_service_wasinactive)) {
823 int depoptions = RC_DEP_TRACE;
824 char *svc;
825 int i;
826
827 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
828 depoptions |= RC_DEP_STRICT;
829
830 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
831 eerrorx ("failed to load deptree");
832
833 rc_strlist_free (types);
834 types = rc_strlist_add (NULL, "needsme");
835 rc_strlist_free (svclist);
836 svclist = rc_strlist_add (NULL, applet);
837 rc_strlist_free (tmplist);
838 tmplist = NULL;
839 rc_strlist_free (services);
840 services = rc_get_depends (deptree, types, svclist,
841 softlevel, depoptions);
842 rc_strlist_reverse (services);
843 STRLIST_FOREACH (services, svc, i) {
844 if (rc_service_state (svc, rc_service_started) ||
845 rc_service_state (svc, rc_service_inactive))
846 {
847 rc_wait_service (svc);
848 if (rc_service_state (svc, rc_service_started) ||
849 rc_service_state (svc, rc_service_inactive))
850 {
851 pid_t pid = rc_stop_service (svc);
852 if (! rc_is_env ("RC_PARALLEL", "yes"))
853 rc_waitpid (pid);
854 tmplist = rc_strlist_add (tmplist, svc);
855 }
856 }
857 }
858 rc_strlist_free (services);
859 services = NULL;
860
861 STRLIST_FOREACH (tmplist, svc, i) {
862 if (rc_service_state (svc, rc_service_stopped))
863 continue;
864
865 /* We used to loop 3 times here - maybe re-do this if needed */
866 rc_wait_service (svc);
867 if (! rc_service_state (svc, rc_service_stopped)) {
868 if (rc_runlevel_stopping ())
869 rc_mark_service (svc, rc_service_failed);
870 eerrorx ("ERROR: cannot stop %s as %s is still up",
871 applet, svc);
872 }
873 }
874 rc_strlist_free (tmplist);
875 tmplist = NULL;
876
877 /* We now wait for other services that may use us and are stopping
878 This is important when a runlevel stops */
879 types = rc_strlist_add (types, "usesme");
880 types = rc_strlist_add (types, "ibefore");
881 services = rc_get_depends (deptree, types, svclist,
882 softlevel, depoptions);
883 STRLIST_FOREACH (services, svc, i) {
884 if (rc_service_state (svc, rc_service_stopped))
885 continue;
886 rc_wait_service (svc);
887 }
888
889 rc_strlist_free (services);
890 services = NULL;
891 rc_strlist_free (types);
892 types = NULL;
893 }
894
895 if (ibsave)
896 setenv ("IN_BACKGROUND", ibsave, 1);
897 rc_plugin_run (rc_hook_service_stop_now, applet);
898 stopped = svc_exec ("stop", NULL);
899 if (ibsave)
900 unsetenv ("IN_BACKGROUND");
901
902 if (! in_control ()) {
903 rc_plugin_run (rc_hook_service_stop_done, applet);
904 ewarnx ("WARNING: %s not under our control, aborting", applet);
905 }
906
907 if (! stopped) {
908 if (rc_service_state (service, rc_service_wasinactive))
909 rc_mark_service (service, rc_service_inactive);
910 else
911 rc_mark_service (service, rc_service_started);
912 rc_plugin_run (rc_hook_service_stop_done, applet);
913 eerrorx ("ERROR: %s failed to stop", applet);
914 }
915
916 if (in_background)
917 rc_mark_service (service, rc_service_inactive);
918 else
919 rc_mark_service (service, rc_service_stopped);
920
921 unlink_mtime_test ();
922 rc_plugin_run (rc_hook_service_stop_done, applet);
923 hook_out = 0;
924 rc_plugin_run (rc_hook_service_stop_out, applet);
925 }
926
927 static void svc_restart (bool deps)
928 {
929 /* This is hairly and a better way needs to be found I think!
930 The issue is this - openvpn need net and dns. net can restart
931 dns via resolvconf, so you could have openvpn trying to restart dnsmasq
932 which in turn is waiting on net which in turn is waiting on dnsmasq.
933 The work around is for resolvconf to restart it's services with --nodeps
934 which means just that. The downside is that there is a small window when
935 our status is invalid.
936 One workaround would be to introduce a new status, or status locking. */
937 if (! deps) {
938 if (rc_service_state (service, rc_service_started) ||
939 rc_service_state (service, rc_service_inactive))
940 svc_exec ("stop", "start");
941 else
942 svc_exec ("start", NULL);
943 return;
944 }
945
946 if (! rc_service_state (service, rc_service_stopped)) {
947 get_started_services ();
948 svc_stop (deps);
949
950 /* Flush our buffered output if any */
951 eflush ();
952 }
953
954 svc_start (deps);
955 start_services (restart_services);
956 rc_strlist_free (restart_services);
957 restart_services = NULL;
958 }
959
960 #define getoptstring "dCDNqvh"
961 static struct option longopts[] = {
962 { "debug", 0, NULL, 'd'},
963 { "nocolor", 0, NULL, 'C'},
964 { "nocolour", 0, NULL, 'C'},
965 { "nodeps", 0, NULL, 'D'},
966 { "quiet", 0, NULL, 'q'},
967 { "verbose", 0, NULL, 'v'},
968 { "help", 0, NULL, 'h'},
969 { NULL, 0, NULL, 0}
970 };
971 // #include "_usage.c"
972
973 int main (int argc, char **argv)
974 {
975 int i;
976 bool deps = true;
977 bool doneone = false;
978 char pid[16];
979 int retval;
980 int opt;
981
982 service = argv[1];
983 applet = rc_xstrdup (basename (service));
984 atexit (cleanup);
985
986 /* Change dir to / to ensure all init scripts don't use stuff in pwd */
987 chdir ("/");
988
989 /* Show help if insufficient args */
990 if (argc < 3) {
991 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
992 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
993 applet, strerror (errno));
994 }
995
996 #ifdef __linux__
997 /* coldplug events can trigger init scripts, but we don't want to run them
998 until after rc sysinit has completed so we punt them to the boot runlevel */
999 if (rc_exists ("/dev/.rcsysinit")) {
1000 eerror ("%s: cannot run until sysvinit completes", applet);
1001 if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
1002 eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
1003 tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
1004 symlink (service, tmp);
1005 exit (EXIT_FAILURE);
1006 }
1007 #endif
1008
1009 if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) {
1010 /* Ensure our environment is pure
1011 Also, add our configuration to it */
1012 env = rc_filter_env ();
1013 env = rc_config_env (env);
1014
1015 if (env) {
1016 char *p;
1017
1018 #ifdef __linux__
1019 /* clearenv isn't portable, but there's no harm in using it
1020 if we have it */
1021 clearenv ();
1022 #else
1023 char *var;
1024 /* No clearenv present here then.
1025 We could manipulate environ directly ourselves, but it seems that
1026 some kernels bitch about this according to the environ man pages
1027 so we walk though environ and call unsetenv for each value. */
1028 while (environ[0]) {
1029 tmp = rc_xstrdup (environ[0]);
1030 p = tmp;
1031 var = strsep (&p, "=");
1032 unsetenv (var);
1033 free (tmp);
1034 }
1035 tmp = NULL;
1036 #endif
1037
1038 STRLIST_FOREACH (env, p, i)
1039 putenv (p);
1040
1041 /* We don't free our list as that would be null in environ */
1042 }
1043
1044 softlevel = rc_get_runlevel ();
1045
1046 /* If not called from RC or another service then don't be parallel */
1047 unsetenv ("RC_PARALLEL");
1048 }
1049
1050 setenv ("RC_ELOG", service, 1);
1051 setenv ("SVCNAME", applet, 1);
1052
1053 /* Set an env var so that we always know our pid regardless of any
1054 subshells the init script may create so that our mark_service_*
1055 functions can always instruct us of this change */
1056 snprintf (pid, sizeof (pid), "%d", (int) getpid ());
1057 setenv ("RC_RUNSCRIPT_PID", pid, 1);
1058
1059 /* eprefix is kinda klunky, but it works for our purposes */
1060 if (rc_is_env ("RC_PREFIX", "yes")) {
1061 int l = strlen (applet);
1062 if (l < 13)
1063 l = 13;
1064 prefix = rc_xmalloc (sizeof (char *) * l);
1065 snprintf (prefix, l, "%s%s", applet, " ");
1066 eprefix (prefix);
1067 }
1068
1069 /* If we're in parallel and we're not prefixing then we need the ebuffer */
1070 if (rc_is_env ("RC_PARALLEL", "yes") && ! rc_is_env ("RC_PREFIX", "yes")) {
1071 char ebname[PATH_MAX];
1072 char *eb;
1073
1074 snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
1075 eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL);
1076 ebuffer (eb);
1077 free (eb);
1078 }
1079
1080 #ifdef __linux__
1081 /* Ok, we are ready to go, so setup selinux if applicable */
1082 setup_selinux (argc, argv);
1083 #endif
1084
1085 /* Punt the first arg as it's our service name */
1086 argc--;
1087 argv++;
1088
1089 /* Right then, parse any options there may be */
1090 while ((opt = getopt_long (argc, argv, getoptstring,
1091 longopts, (int *) 0)) != -1)
1092 switch (opt) {
1093 case 'd':
1094 setenv ("RC_DEBUG", "yes", 1);
1095 break;
1096 case 'h':
1097 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1098 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1099 applet, strerror (errno));
1100 case 'C':
1101 setenv ("RC_NOCOLOR", "yes", 1);
1102 break;
1103 case 'D':
1104 deps = false;
1105 break;
1106 case 'q':
1107 setenv ("RC_QUIET", "yes", 1);
1108 break;
1109 case 'v':
1110 setenv ("RC_VERBOSE", "yes", 1);
1111 break;
1112 default:
1113 exit (EXIT_FAILURE);
1114 }
1115
1116 /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
1117 that is being called and not any dependents */
1118 if (getenv ("IN_BACKGROUND")) {
1119 in_background = rc_is_env ("IN_BACKGROUND", "true");
1120 ibsave = rc_xstrdup (getenv ("IN_BACKGROUND"));
1121 unsetenv ("IN_BACKGROUND");
1122 }
1123
1124 if (rc_is_env ("IN_HOTPLUG", "1")) {
1125 if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
1126 eerrorx ("%s: not allowed to be hotplugged", applet);
1127 }
1128
1129 /* Setup a signal handler */
1130 signal (SIGHUP, handle_signal);
1131 signal (SIGINT, handle_signal);
1132 signal (SIGQUIT, handle_signal);
1133 signal (SIGTERM, handle_signal);
1134 signal (SIGCHLD, handle_signal);
1135
1136 /* Load our plugins */
1137 rc_plugin_load ();
1138
1139 /* Now run each option */
1140 retval = EXIT_SUCCESS;
1141 while (optind < argc) {
1142 optarg = argv[optind++];
1143
1144 /* Abort on a sighup here */
1145 if (sighup)
1146 exit (EXIT_FAILURE);
1147
1148 if (strcmp (optarg, "status") != 0 &&
1149 strcmp (optarg, "help") != 0) {
1150 /* Only root should be able to run us */
1151 if (geteuid () != 0)
1152 eerrorx ("%s: root access required", applet);
1153 }
1154
1155 /* Export the command we're running.
1156 This is important as we stamp on the restart function now but
1157 some start/stop routines still need to behave differently if
1158 restarting. */
1159 unsetenv ("RC_CMD");
1160 setenv ("RC_CMD", optarg, 1);
1161
1162 doneone = true;
1163 if (strcmp (optarg, "conditionalrestart") == 0 ||
1164 strcmp (optarg, "condrestart") == 0)
1165 {
1166 if (rc_service_state (service, rc_service_started))
1167 svc_restart (deps);
1168 }
1169 else if (strcmp (optarg, "restart") == 0)
1170 svc_restart (deps);
1171 else if (strcmp (optarg, "start") == 0)
1172 svc_start (deps);
1173 else if (strcmp (optarg, "status") == 0) {
1174 rc_service_state_t r = svc_status (service);
1175 retval = (int) r;
1176 } else if (strcmp (optarg, "stop") == 0) {
1177 if (in_background)
1178 get_started_services ();
1179
1180 svc_stop (deps);
1181
1182 if (! in_background &&
1183 ! rc_runlevel_stopping () &&
1184 rc_service_state (service, rc_service_stopped))
1185 uncoldplug ();
1186
1187 if (in_background &&
1188 rc_service_state (service, rc_service_inactive))
1189 {
1190 char *svc;
1191 int j;
1192 STRLIST_FOREACH (restart_services, svc, j)
1193 if (rc_service_state (svc, rc_service_stopped))
1194 rc_schedule_start_service (service, svc);
1195 }
1196 } else if (strcmp (optarg, "zap") == 0) {
1197 einfo ("Manually resetting %s to stopped state", applet);
1198 rc_mark_service (applet, rc_service_stopped);
1199 uncoldplug ();
1200 } else if (strcmp (optarg, "help") == 0) {
1201 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1202 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1203 applet, strerror (errno));
1204 }else
1205 svc_exec (optarg, NULL);
1206
1207 /* Flush our buffered output if any */
1208 eflush ();
1209
1210 /* We should ensure this list is empty after an action is done */
1211 rc_strlist_free (restart_services);
1212 restart_services = NULL;
1213 }
1214
1215 if (! doneone) {
1216 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1217 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1218 applet, strerror (errno));
1219 }
1220
1221 return (retval);
1222 }

  ViewVC Help
Powered by ViewVC 1.1.20