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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20