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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20