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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2706 - (show annotations) (download) (as text)
Tue May 15 15:56:35 2007 UTC (7 years, 4 months ago) by uberlord
File MIME type: text/x-csrc
File size: 32543 byte(s)
/etc/conf.d/rc.$runlevel now works, #177869.
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 if (rc_service_state (svc, rc_service_started))
660 continue;
661 if (! rc_wait_service (svc))
662 eerror ("%s: timed out waiting for %s", applet, svc);
663 if (rc_service_state (svc, rc_service_started))
664 continue;
665
666 STRLIST_FOREACH (need_services, svc2, j)
667 if (strcmp (svc, svc2) == 0) {
668 if (rc_service_state (svc, rc_service_inactive) ||
669 rc_service_state (svc, rc_service_wasinactive))
670 tmplist = rc_strlist_add (tmplist, svc);
671 else
672 eerrorx ("ERROR: cannot start %s as %s would not start",
673 applet, svc);
674 }
675 }
676
677 if (tmplist) {
678 int n = 0;
679 int len = 0;
680 char *p;
681
682 /* Set the state now, then unlink our exclusive so that
683 our scheduled list is preserved */
684 rc_mark_service (service, rc_service_stopped);
685 unlink_mtime_test ();
686
687 rc_strlist_free (types);
688 types = rc_strlist_add (NULL, "iprovide");
689 STRLIST_FOREACH (tmplist, svc, i) {
690 rc_schedule_start_service (svc, service);
691
692 rc_strlist_free (svclist);
693 svclist = rc_strlist_add (NULL, svc);
694 rc_strlist_free (providelist);
695 providelist = rc_get_depends (deptree, types, svclist,
696 softlevel, depoptions);
697 STRLIST_FOREACH (providelist, svc2, j)
698 rc_schedule_start_service (svc2, service);
699
700 len += strlen (svc) + 2;
701 n++;
702 }
703
704 len += 5;
705 tmp = rc_xmalloc (sizeof (char *) * len);
706 p = tmp;
707 STRLIST_FOREACH (tmplist, svc, i) {
708 if (i > 1) {
709 if (i == n - 1)
710 p += snprintf (p, len, " or ");
711 else
712 p += snprintf (p, len, ", ");
713 }
714 p += snprintf (p, len, "%s", svc);
715 }
716 ewarnx ("WARNING: %s is scheduled to start when %s has started",
717 applet, tmp);
718 }
719
720 rc_strlist_free (services);
721 services = NULL;
722 rc_strlist_free (types);
723 types = NULL;
724 rc_strlist_free (svclist);
725 svclist = NULL;
726 }
727
728 if (ibsave)
729 setenv ("IN_BACKGROUND", ibsave, 1);
730 rc_plugin_run (rc_hook_service_start_now, applet);
731 started = svc_exec ("start", NULL);
732 if (ibsave)
733 unsetenv ("IN_BACKGROUND");
734
735 if (in_control ()) {
736 if (! started) {
737 if (rc_service_state (service, rc_service_wasinactive))
738 rc_mark_service (service, rc_service_inactive);
739 else {
740 rc_mark_service (service, rc_service_stopped);
741 if (rc_runlevel_starting ())
742 rc_mark_service (service, rc_service_failed);
743 }
744 rc_plugin_run (rc_hook_service_start_done, applet);
745 eerrorx ("ERROR: %s failed to start", applet);
746 }
747 rc_mark_service (service, rc_service_started);
748 unlink_mtime_test ();
749 rc_plugin_run (rc_hook_service_start_done, applet);
750 } else {
751 rc_plugin_run (rc_hook_service_start_done, applet);
752 if (rc_service_state (service, rc_service_inactive))
753 ewarnx ("WARNING: %s has started, but is inactive", applet);
754 else
755 ewarnx ("WARNING: %s not under our control, aborting", applet);
756 }
757
758 /* Now start any scheduled services */
759 rc_strlist_free (services);
760 services = rc_services_scheduled (service);
761 STRLIST_FOREACH (services, svc, i)
762 if (rc_service_state (svc, rc_service_stopped))
763 rc_start_service (svc);
764 rc_strlist_free (services);
765 services = NULL;
766
767 /* Do the same for any services we provide */
768 rc_strlist_free (types);
769 types = rc_strlist_add (NULL, "iprovide");
770 rc_strlist_free (svclist);
771 svclist = rc_strlist_add (NULL, applet);
772 rc_strlist_free (tmplist);
773 tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions);
774
775 STRLIST_FOREACH (tmplist, svc2, j) {
776 rc_strlist_free (services);
777 services = rc_services_scheduled (svc2);
778 STRLIST_FOREACH (services, svc, i)
779 if (rc_service_state (svc, rc_service_stopped))
780 rc_start_service (svc);
781 }
782
783 hook_out = 0;
784 rc_plugin_run (rc_hook_service_start_out, applet);
785 }
786
787 static void svc_stop (bool deps)
788 {
789 bool stopped;
790
791 hook_out = rc_hook_service_stop_out;
792
793 if (rc_runlevel_stopping () &&
794 rc_service_state (service, rc_service_failed))
795 exit (EXIT_FAILURE);
796
797 if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
798 if (! rc_service_state (service, rc_service_started) &&
799 ! rc_service_state (service, rc_service_inactive))
800 exit (EXIT_FAILURE);
801
802 if (rc_service_state (service, rc_service_stopped)) {
803 ewarn ("WARNING: %s is already stopped", applet);
804 return;
805 } else if (rc_service_state (service, rc_service_stopping))
806 ewarnx ("WARNING: %s is already stopping", applet);
807
808 if (! rc_mark_service (service, rc_service_stopping))
809 eerrorx ("ERROR: %s has been stopped by something else", applet);
810
811 make_exclusive (service);
812
813 if (! rc_runlevel_stopping () &&
814 rc_service_in_runlevel (service, RC_LEVEL_BOOT))
815 ewarn ("WARNING: you are stopping a boot service");
816
817 if (deps || ! rc_service_state (service, rc_service_wasinactive)) {
818 int depoptions = RC_DEP_TRACE;
819 char *svc;
820 int i;
821
822 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
823 depoptions |= RC_DEP_STRICT;
824
825 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
826 eerrorx ("failed to load deptree");
827
828 rc_strlist_free (types);
829 types = rc_strlist_add (NULL, "needsme");
830 rc_strlist_free (svclist);
831 svclist = rc_strlist_add (NULL, applet);
832 rc_strlist_free (tmplist);
833 tmplist = NULL;
834 rc_strlist_free (services);
835 services = rc_get_depends (deptree, types, svclist,
836 softlevel, depoptions);
837 rc_strlist_reverse (services);
838 STRLIST_FOREACH (services, svc, i) {
839 if (rc_service_state (svc, rc_service_started) ||
840 rc_service_state (svc, rc_service_inactive))
841 {
842 rc_wait_service (svc);
843 if (rc_service_state (svc, rc_service_started) ||
844 rc_service_state (svc, rc_service_inactive))
845 {
846 pid_t pid = rc_stop_service (svc);
847 if (! rc_is_env ("RC_PARALLEL", "yes"))
848 rc_waitpid (pid);
849 tmplist = rc_strlist_add (tmplist, svc);
850 }
851 }
852 }
853 rc_strlist_free (services);
854 services = NULL;
855
856 STRLIST_FOREACH (tmplist, svc, i) {
857 if (rc_service_state (svc, rc_service_stopped))
858 continue;
859
860 /* We used to loop 3 times here - maybe re-do this if needed */
861 rc_wait_service (svc);
862 if (! rc_service_state (svc, rc_service_stopped)) {
863 if (rc_runlevel_stopping ())
864 rc_mark_service (svc, rc_service_failed);
865 eerrorx ("ERROR: cannot stop %s as %s is still up",
866 applet, svc);
867 }
868 }
869 rc_strlist_free (tmplist);
870 tmplist = NULL;
871
872 /* We now wait for other services that may use us and are stopping
873 This is important when a runlevel stops */
874 types = rc_strlist_add (types, "usesme");
875 types = rc_strlist_add (types, "ibefore");
876 services = rc_get_depends (deptree, types, svclist,
877 softlevel, depoptions);
878 STRLIST_FOREACH (services, svc, i) {
879 if (rc_service_state (svc, rc_service_stopped))
880 continue;
881 rc_wait_service (svc);
882 }
883
884 rc_strlist_free (services);
885 services = NULL;
886 rc_strlist_free (types);
887 types = NULL;
888 }
889
890 if (ibsave)
891 setenv ("IN_BACKGROUND", ibsave, 1);
892 rc_plugin_run (rc_hook_service_stop_now, applet);
893 stopped = svc_exec ("stop", NULL);
894 if (ibsave)
895 unsetenv ("IN_BACKGROUND");
896
897 if (! in_control ()) {
898 rc_plugin_run (rc_hook_service_stop_done, applet);
899 ewarnx ("WARNING: %s not under our control, aborting", applet);
900 }
901
902 if (! stopped) {
903 if (rc_service_state (service, rc_service_wasinactive))
904 rc_mark_service (service, rc_service_inactive);
905 else
906 rc_mark_service (service, rc_service_started);
907 rc_plugin_run (rc_hook_service_stop_done, applet);
908 eerrorx ("ERROR: %s failed to stop", applet);
909 }
910
911 if (in_background)
912 rc_mark_service (service, rc_service_inactive);
913 else
914 rc_mark_service (service, rc_service_stopped);
915
916 unlink_mtime_test ();
917 rc_plugin_run (rc_hook_service_stop_done, applet);
918 hook_out = 0;
919 rc_plugin_run (rc_hook_service_stop_out, applet);
920 }
921
922 static void svc_restart (bool deps)
923 {
924 /* This is hairly and a better way needs to be found I think!
925 The issue is this - openvpn need net and dns. net can restart
926 dns via resolvconf, so you could have openvpn trying to restart dnsmasq
927 which in turn is waiting on net which in turn is waiting on dnsmasq.
928 The work around is for resolvconf to restart it's services with --nodeps
929 which means just that. The downside is that there is a small window when
930 our status is invalid.
931 One workaround would be to introduce a new status, or status locking. */
932 if (! deps) {
933 if (rc_service_state (service, rc_service_started) ||
934 rc_service_state (service, rc_service_inactive))
935 svc_exec ("stop", "start");
936 else
937 svc_exec ("start", NULL);
938 return;
939 }
940
941 if (! rc_service_state (service, rc_service_stopped)) {
942 get_started_services ();
943 svc_stop (deps);
944
945 /* Flush our buffered output if any */
946 eflush ();
947 }
948
949 svc_start (deps);
950 start_services (restart_services);
951 rc_strlist_free (restart_services);
952 restart_services = NULL;
953 }
954
955 #define getoptstring "dCDNqvh"
956 static struct option longopts[] = {
957 { "debug", 0, NULL, 'd'},
958 { "nocolor", 0, NULL, 'C'},
959 { "nocolour", 0, NULL, 'C'},
960 { "nodeps", 0, NULL, 'D'},
961 { "quiet", 0, NULL, 'q'},
962 { "verbose", 0, NULL, 'v'},
963 { "help", 0, NULL, 'h'},
964 { NULL, 0, NULL, 0}
965 };
966 // #include "_usage.c"
967
968 int main (int argc, char **argv)
969 {
970 int i;
971 bool deps = true;
972 bool doneone = false;
973 char pid[16];
974 int retval;
975 int opt;
976
977 service = argv[1];
978 applet = rc_xstrdup (basename (service));
979 atexit (cleanup);
980
981 /* Show help if insufficient args */
982 if (argc < 3) {
983 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
984 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
985 applet, strerror (errno));
986 }
987
988 #ifdef __linux__
989 /* coldplug events can trigger init scripts, but we don't want to run them
990 until after rc sysinit has completed so we punt them to the boot runlevel */
991 if (rc_exists ("/dev/.rcsysinit")) {
992 eerror ("%s: cannot run until sysvinit completes", applet);
993 if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
994 eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
995 tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
996 symlink (service, tmp);
997 exit (EXIT_FAILURE);
998 }
999 #endif
1000
1001 if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) {
1002 /* Ensure our environment is pure
1003 Also, add our configuration to it */
1004 env = rc_filter_env ();
1005 env = rc_config_env (env);
1006
1007 if (env) {
1008 char *p;
1009
1010 #ifdef __linux__
1011 /* clearenv isn't portable, but there's no harm in using it
1012 if we have it */
1013 clearenv ();
1014 #else
1015 char *var;
1016 /* No clearenv present here then.
1017 We could manipulate environ directly ourselves, but it seems that
1018 some kernels bitch about this according to the environ man pages
1019 so we walk though environ and call unsetenv for each value. */
1020 while (environ[0]) {
1021 tmp = rc_xstrdup (environ[0]);
1022 p = tmp;
1023 var = strsep (&p, "=");
1024 unsetenv (var);
1025 free (tmp);
1026 }
1027 tmp = NULL;
1028 #endif
1029
1030 STRLIST_FOREACH (env, p, i)
1031 putenv (p);
1032
1033 /* We don't free our list as that would be null in environ */
1034 }
1035
1036 softlevel = rc_get_runlevel ();
1037
1038 /* If not called from RC or another service then don't be parallel */
1039 unsetenv ("RC_PARALLEL");
1040 }
1041
1042 setenv ("RC_ELOG", service, 1);
1043 setenv ("SVCNAME", applet, 1);
1044
1045 /* Set an env var so that we always know our pid regardless of any
1046 subshells the init script may create so that our mark_service_*
1047 functions can always instruct us of this change */
1048 snprintf (pid, sizeof (pid), "%d", (int) getpid ());
1049 setenv ("RC_RUNSCRIPT_PID", pid, 1);
1050
1051 /* eprefix is kinda klunky, but it works for our purposes */
1052 if (rc_is_env ("RC_PREFIX", "yes")) {
1053 int l = strlen (applet);
1054 if (l < 13)
1055 l = 13;
1056 prefix = rc_xmalloc (sizeof (char *) * l);
1057 snprintf (prefix, l, "%s%s", applet, " ");
1058 eprefix (prefix);
1059 }
1060
1061 /* If we're in parallel and we're not prefixing then we need the ebuffer */
1062 if (rc_is_env ("RC_PARALLEL", "yes") && ! rc_is_env ("RC_PREFIX", "yes")) {
1063 char ebname[PATH_MAX];
1064 char *eb;
1065
1066 snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
1067 eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL);
1068 ebuffer (eb);
1069 free (eb);
1070 }
1071
1072 #ifdef __linux__
1073 /* Ok, we are ready to go, so setup selinux if applicable */
1074 setup_selinux (argc, argv);
1075 #endif
1076
1077 /* Punt the first arg as it's our service name */
1078 argc--;
1079 argv++;
1080
1081 /* Right then, parse any options there may be */
1082 while ((opt = getopt_long (argc, argv, getoptstring,
1083 longopts, (int *) 0)) != -1)
1084 switch (opt) {
1085 case 'd':
1086 setenv ("RC_DEBUG", "yes", 1);
1087 break;
1088 case 'h':
1089 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1090 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1091 applet, strerror (errno));
1092 case 'C':
1093 setenv ("RC_NOCOLOR", "yes", 1);
1094 break;
1095 case 'D':
1096 deps = false;
1097 break;
1098 case 'q':
1099 setenv ("RC_QUIET", "yes", 1);
1100 break;
1101 case 'v':
1102 setenv ("RC_VERBOSE", "yes", 1);
1103 break;
1104 default:
1105 exit (EXIT_FAILURE);
1106 }
1107
1108 /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
1109 that is being called and not any dependents */
1110 if (getenv ("IN_BACKGROUND")) {
1111 in_background = rc_is_env ("IN_BACKGROUND", "true");
1112 ibsave = rc_xstrdup (getenv ("IN_BACKGROUND"));
1113 unsetenv ("IN_BACKGROUND");
1114 }
1115
1116 if (rc_is_env ("IN_HOTPLUG", "1")) {
1117 if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
1118 eerrorx ("%s: not allowed to be hotplugged", applet);
1119 }
1120
1121 /* Setup a signal handler */
1122 signal (SIGHUP, handle_signal);
1123 signal (SIGINT, handle_signal);
1124 signal (SIGQUIT, handle_signal);
1125 signal (SIGTERM, handle_signal);
1126 signal (SIGCHLD, handle_signal);
1127
1128 /* Load our plugins */
1129 rc_plugin_load ();
1130
1131 /* Now run each option */
1132 retval = EXIT_SUCCESS;
1133 while (optind < argc) {
1134 optarg = argv[optind++];
1135
1136 /* Abort on a sighup here */
1137 if (sighup)
1138 exit (EXIT_FAILURE);
1139
1140 /* Export the command we're running.
1141 This is important as we stamp on the restart function now but
1142 some start/stop routines still need to behave differently if
1143 restarting. */
1144 unsetenv ("RC_CMD");
1145 setenv ("RC_CMD", optarg, 1);
1146
1147 doneone = true;
1148 if (strcmp (optarg, "conditionalrestart") == 0 ||
1149 strcmp (optarg, "condrestart") == 0)
1150 {
1151 if (rc_service_state (service, rc_service_started))
1152 svc_restart (deps);
1153 }
1154 else if (strcmp (optarg, "restart") == 0)
1155 svc_restart (deps);
1156 else if (strcmp (optarg, "start") == 0)
1157 svc_start (deps);
1158 else if (strcmp (optarg, "status") == 0) {
1159 rc_service_state_t r = svc_status (service);
1160 retval = (int) r;
1161 } else if (strcmp (optarg, "stop") == 0) {
1162 if (in_background)
1163 get_started_services ();
1164
1165 svc_stop (deps);
1166
1167 if (! in_background &&
1168 ! rc_runlevel_stopping () &&
1169 rc_service_state (service, rc_service_stopped))
1170 uncoldplug ();
1171
1172 if (in_background &&
1173 rc_service_state (service, rc_service_inactive))
1174 {
1175 char *svc;
1176 int j;
1177 STRLIST_FOREACH (restart_services, svc, j)
1178 if (rc_service_state (svc, rc_service_stopped))
1179 rc_schedule_start_service (service, svc);
1180 }
1181 } else if (strcmp (optarg, "zap") == 0) {
1182 einfo ("Manually resetting %s to stopped state", applet);
1183 rc_mark_service (applet, rc_service_stopped);
1184 uncoldplug ();
1185 } else if (strcmp (optarg, "help") == 0) {
1186 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1187 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1188 applet, strerror (errno));
1189 }else
1190 svc_exec (optarg, NULL);
1191
1192 /* Flush our buffered output if any */
1193 eflush ();
1194
1195 /* We should ensure this list is empty after an action is done */
1196 rc_strlist_free (restart_services);
1197 restart_services = NULL;
1198 }
1199
1200 if (! doneone) {
1201 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1202 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1203 applet, strerror (errno));
1204 }
1205
1206 return (retval);
1207 }

  ViewVC Help
Powered by ViewVC 1.1.20