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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20