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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20