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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2768 - (show annotations) (download) (as text)
Wed Jul 11 12:06:37 2007 UTC (6 years, 9 months ago) by uberlord
File MIME type: text/x-csrc
File size: 34205 byte(s)
Punt the dodgy ebuffer code. We now force prefixing for parallel starts which also reduces our variable pollution.
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 (! rc_in_plugin && prefix_locked)
238 unlink (PREFIX_LOCK);
239
240 if (hook_out)
241 rc_plugin_run (hook_out, applet);
242 rc_plugin_unload ();
243
244 if (restart_services ) {
245 start_services (restart_services);
246 rc_strlist_free (restart_services);
247 }
248
249 rc_free_deptree (deptree);
250 rc_strlist_free (services);
251 rc_strlist_free (types);
252 rc_strlist_free (svclist);
253 rc_strlist_free (providelist);
254 rc_strlist_free (need_services);
255 rc_strlist_free (use_services);
256 rc_strlist_free (tmplist);
257 free (ibsave);
258
259 if (! rc_in_plugin && in_control ()) {
260 if (rc_service_state (applet, rc_service_stopping)) {
261 /* If the we're shutting down, do it cleanly */
262 if ((softlevel &&
263 rc_runlevel_stopping () &&
264 (strcmp (softlevel, RC_LEVEL_SHUTDOWN) == 0 ||
265 strcmp (softlevel, RC_LEVEL_REBOOT) == 0)))
266 rc_mark_service (applet, rc_service_stopped);
267 else if (rc_service_state (applet, rc_service_wasinactive))
268 rc_mark_service (applet, rc_service_inactive);
269 else
270 rc_mark_service (applet, rc_service_started);
271 }
272 else if (rc_service_state (applet, rc_service_starting))
273 {
274 if (rc_service_state (applet, rc_service_wasinactive))
275 rc_mark_service (applet, rc_service_inactive);
276 else
277 rc_mark_service (applet, rc_service_stopped);
278 }
279 if (exclusive && rc_exists (exclusive))
280 unlink (exclusive);
281 }
282
283 rc_strlist_free (env);
284
285 if (mtime_test)
286 {
287 if (! rc_in_plugin)
288 unlink (mtime_test);
289 free (mtime_test);
290 }
291 free (exclusive);
292 free (applet);
293 free (prefix);
294 free (service);
295 }
296
297 static int write_prefix (int fd, const char *buffer, size_t bytes, bool *prefixed) {
298 unsigned int i;
299 const char *ec;
300 const char *ec_normal = ecolor (ecolor_normal);
301 ssize_t ret = 0;
302
303 if (fd == fileno (stdout))
304 ec = ecolor (ecolor_hilite);
305 else
306 ec = ecolor (ecolor_bad);
307
308 for (i = 0; i < bytes; i++) {
309 /* We don't prefix escape codes, like eend */
310 if (buffer[i] == '\033')
311 *prefixed = true;
312
313 if (! *prefixed) {
314 ret += write (fd, ec, strlen (ec));
315 ret += write (fd, prefix, strlen (prefix));
316 ret += write (fd, ec_normal, strlen (ec_normal));
317 ret += write (fd, "|", 1);
318 *prefixed = true;
319 }
320
321 if (buffer[i] == '\n')
322 *prefixed = false;
323 ret += write (fd, buffer + i, 1);
324 }
325
326 return (ret);
327 }
328
329 static bool svc_exec (const char *arg1, const char *arg2)
330 {
331 bool execok;
332 int stdout_pipes[2];
333 int stderr_pipes[2];
334
335 /* Setup our pipes for prefixed output */
336 if (prefix) {
337 if (pipe (stdout_pipes))
338 eerror ("pipe: %s", strerror (errno));
339 if (pipe (stderr_pipes))
340 eerror ("pipe: %s", strerror (errno));
341 }
342
343 /* We need to disable our child signal handler now so we block
344 until our script returns. */
345 signal (SIGCHLD, NULL);
346
347 service_pid = vfork();
348
349 if (service_pid == -1)
350 eerrorx ("%s: vfork: %s", service, strerror (errno));
351 if (service_pid == 0) {
352 if (prefix) {
353 int flags;
354
355 if (dup2 (stdout_pipes[1], fileno (stdout)) == -1)
356 eerror ("dup2 stdout: %s", strerror (errno));
357 close (stdout_pipes[0]);
358 if (dup2 (stderr_pipes[1], fileno (stderr)) == -1)
359 eerror ("dup2 stderr: %s", strerror (errno));
360 close (stderr_pipes[0]);
361
362 /* Stop any scripts from inheriting us */
363 if ((flags = fcntl (stdout_pipes[1], F_GETFD, 0)) < 0 ||
364 fcntl (stdout_pipes[1], F_SETFD, flags | FD_CLOEXEC) < 0)
365 eerror ("fcntl: %s", strerror (errno));
366 if ((flags = fcntl (stderr_pipes[1], F_GETFD, 0)) < 0 ||
367 fcntl (stderr_pipes[1], F_SETFD, flags | FD_CLOEXEC) < 0)
368 eerror ("fcntl: %s", strerror (errno));
369 }
370
371 if (rc_exists (RC_SVCDIR "runscript.sh")) {
372 execl (RC_SVCDIR "runscript.sh", service, service, arg1, arg2,
373 (char *) NULL);
374 eerror ("%s: exec `" RC_SVCDIR "runscript.sh': %s",
375 service, strerror (errno));
376 _exit (EXIT_FAILURE);
377 } else {
378 execl (RC_LIBDIR "sh/runscript.sh", service, service, arg1, arg2,
379 (char *) NULL);
380 eerror ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s",
381 service, strerror (errno));
382 _exit (EXIT_FAILURE);
383 }
384 }
385
386 /* Prefix our piped output */
387 if (prefix) {
388 bool stdout_done = false;
389 bool stdout_prefix_shown = false;
390 bool stderr_done = false;
391 bool stderr_prefix_shown = false;
392 char buffer[RC_LINEBUFFER];
393
394 close (stdout_pipes[1]);
395 close (stderr_pipes[1]);
396
397 memset (buffer, 0, RC_LINEBUFFER);
398 while (! stdout_done && ! stderr_done) {
399 fd_set fds;
400 int retval;
401
402 FD_ZERO (&fds);
403 FD_SET (stdout_pipes[0], &fds);
404 FD_SET (stderr_pipes[0], &fds);
405 retval = select (MAX (stdout_pipes[0], stderr_pipes[0]) + 1,
406 &fds, 0, 0, 0);
407 if (retval < 0) {
408 if (errno != EINTR) {
409 eerror ("select: %s", strerror (errno));
410 break;
411 }
412 } else if (retval) {
413 ssize_t nr;
414
415 /* Wait until we get a lock */
416 while (true) {
417 struct timeval tv;
418
419 if (mkfifo (PREFIX_LOCK, 0700) == 0) {
420 prefix_locked = true;
421 break;
422 }
423
424 if (errno != EEXIST)
425 eerror ("mkfifo `%s': %s\n", PREFIX_LOCK, strerror (errno));
426 tv.tv_sec = 0;
427 tv.tv_usec = 20000;
428 select (0, NULL, NULL, NULL, &tv);
429 }
430
431 if (FD_ISSET (stdout_pipes[0], &fds)) {
432 if ((nr = read (stdout_pipes[0], buffer,
433 sizeof (buffer))) <= 0)
434 stdout_done = true;
435 else
436 write_prefix (fileno (stdout), buffer, nr,
437 &stdout_prefix_shown);
438 }
439
440 if (FD_ISSET (stderr_pipes[0], &fds)) {
441 if ((nr = read (stderr_pipes[0], buffer,
442 sizeof (buffer))) <= 0)
443 stderr_done = true;
444 else
445 write_prefix (fileno (stderr), buffer, nr,
446 &stderr_prefix_shown);
447 }
448
449 /* Clear the lock */
450 unlink (PREFIX_LOCK);
451 prefix_locked = false;
452 }
453 }
454
455 /* Done now, so close the pipes */
456 close(stdout_pipes[0]);
457 close(stderr_pipes[0]);
458 }
459
460 execok = rc_waitpid (service_pid) == 0 ? true : false;
461 service_pid = 0;
462
463 /* Done, so restore the signal handler */
464 signal (SIGCHLD, handle_signal);
465
466 return (execok);
467 }
468
469 static rc_service_state_t svc_status ()
470 {
471 char status[10];
472 int (*e) (const char *fmt, ...) = &einfo;
473
474 rc_service_state_t retval = rc_service_stopped;
475
476 if (rc_service_state (service, rc_service_stopping)) {
477 snprintf (status, sizeof (status), "stopping");
478 e = &ewarn;
479 retval = rc_service_stopping;
480 } else if (rc_service_state (service, rc_service_starting)) {
481 snprintf (status, sizeof (status), "starting");
482 e = &ewarn;
483 retval = rc_service_starting;
484 } else if (rc_service_state (service, rc_service_inactive)) {
485 snprintf (status, sizeof (status), "inactive");
486 e = &ewarn;
487 retval = rc_service_inactive;
488 } else if (rc_service_state (service, rc_service_crashed)) {
489 snprintf (status, sizeof (status), "crashed");
490 e = &eerror;
491 retval = rc_service_crashed;
492 } else if (rc_service_state (service, rc_service_started)) {
493 snprintf (status, sizeof (status), "started");
494 retval = rc_service_started;
495 } else
496 snprintf (status, sizeof (status), "stopped");
497
498 e ("status: %s", status);
499 return (retval);
500 }
501
502 static void make_exclusive ()
503 {
504 char *path;
505 int i;
506
507 /* We create a fifo so that other services can wait until we complete */
508 if (! exclusive)
509 exclusive = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL);
510
511 if (mkfifo (exclusive, 0600) != 0 && errno != EEXIST &&
512 (errno != EACCES || geteuid () == 0))
513 eerrorx ("%s: unable to create fifo `%s': %s",
514 applet, exclusive, strerror (errno));
515
516 path = rc_strcatpaths (RC_SVCDIR, "exclusive", applet, (char *) NULL);
517 i = strlen (path) + 16;
518 mtime_test = rc_xmalloc (sizeof (char *) * i);
519 snprintf (mtime_test, i, "%s.%d", path, getpid ());
520 free (path);
521
522 if (rc_exists (mtime_test) && unlink (mtime_test) != 0) {
523 eerror ("%s: unlink `%s': %s",
524 applet, mtime_test, strerror (errno));
525 free (mtime_test);
526 mtime_test = NULL;
527 return;
528 }
529
530 if (symlink (service, mtime_test) != 0) {
531 eerror ("%s: symlink `%s' to `%s': %s",
532 applet, service, mtime_test, strerror (errno));
533 free (mtime_test);
534 mtime_test = NULL;
535 }
536 }
537
538 static void unlink_mtime_test ()
539 {
540 if (unlink (mtime_test) != 0)
541 eerror ("%s: unlink `%s': %s", applet, mtime_test, strerror (errno));
542 free (mtime_test);
543 mtime_test = NULL;
544 }
545
546 static void get_started_services ()
547 {
548 char *svc;
549 int i;
550
551 rc_strlist_free (tmplist);
552 tmplist = rc_services_in_state (rc_service_inactive);
553
554 rc_strlist_free (restart_services);
555 restart_services = rc_services_in_state (rc_service_started);
556
557 STRLIST_FOREACH (tmplist, svc, i)
558 restart_services = rc_strlist_addsort (restart_services, svc);
559
560 rc_strlist_free (tmplist);
561 tmplist = NULL;
562 }
563
564 static void svc_start (bool deps)
565 {
566 bool started;
567 bool background = false;
568 char *svc;
569 char *svc2;
570 int i;
571 int j;
572 int depoptions = RC_DEP_TRACE;
573
574 rc_plugin_run (rc_hook_service_start_in, applet);
575 hook_out = rc_hook_service_start_out;
576
577 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
578 depoptions |= RC_DEP_STRICT;
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 (deps) {
603 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
604 eerrorx ("failed to load deptree");
605
606 rc_strlist_free (types);
607 types = rc_strlist_add (NULL, "broken");
608 rc_strlist_free (svclist);
609 svclist = rc_strlist_add (NULL, applet);
610 rc_strlist_free (services);
611 services = rc_get_depends (deptree, types, svclist, softlevel, 0);
612 if (services) {
613 eerrorn ("ERROR: `%s' needs ", applet);
614 STRLIST_FOREACH (services, svc, i) {
615 if (i > 0)
616 fprintf (stderr, ", ");
617 fprintf (stderr, "%s", svc);
618 }
619 exit (EXIT_FAILURE);
620 }
621 rc_strlist_free (services);
622 services = NULL;
623
624 rc_strlist_free (types);
625 types = rc_strlist_add (NULL, "ineed");
626 rc_strlist_free (need_services);
627 need_services = rc_get_depends (deptree, types, svclist,
628 softlevel, depoptions);
629
630 types = rc_strlist_add (types, "iuse");
631 rc_strlist_free (use_services);
632 use_services = rc_get_depends (deptree, types, svclist,
633 softlevel, depoptions);
634
635 if (! rc_runlevel_starting ()) {
636 STRLIST_FOREACH (use_services, svc, i)
637 if (rc_service_state (svc, rc_service_stopped)) {
638 pid_t pid = rc_start_service (svc);
639 if (! rc_is_env ("RC_PARALLEL", "yes"))
640 rc_waitpid (pid);
641 }
642 }
643
644 /* Now wait for them to start */
645 types = rc_strlist_add (types, "iafter");
646 services = rc_get_depends (deptree, types, svclist,
647 softlevel, depoptions);
648
649 /* We use tmplist to hold our scheduled by list */
650 rc_strlist_free (tmplist);
651 tmplist = NULL;
652
653 STRLIST_FOREACH (services, svc, i) {
654 if (rc_service_state (svc, rc_service_started))
655 continue;
656
657 /* Don't wait for services which went inactive but are now in
658 * starting state which we are after */
659 if (rc_service_state (svc, rc_service_starting) &&
660 rc_service_state(svc, rc_service_wasinactive)) {
661 bool use = false;
662 STRLIST_FOREACH (use_services, svc2, j)
663 if (strcmp (svc, svc2) == 0) {
664 use = true;
665 break;
666 }
667 if (! use)
668 continue;
669 }
670
671 if (! rc_wait_service (svc))
672 eerror ("%s: timed out waiting for %s", applet, svc);
673 if (rc_service_state (svc, rc_service_started))
674 continue;
675
676 STRLIST_FOREACH (need_services, svc2, j)
677 if (strcmp (svc, svc2) == 0) {
678 if (rc_service_state (svc, rc_service_inactive) ||
679 rc_service_state (svc, rc_service_wasinactive))
680 tmplist = rc_strlist_add (tmplist, svc);
681 else
682 eerrorx ("ERROR: cannot start %s as %s would not start",
683 applet, svc);
684 }
685 }
686
687 if (tmplist) {
688 int n = 0;
689 int len = 0;
690 char *p;
691
692 /* Set the state now, then unlink our exclusive so that
693 our scheduled list is preserved */
694 rc_mark_service (service, rc_service_stopped);
695 unlink_mtime_test ();
696
697 rc_strlist_free (types);
698 types = rc_strlist_add (NULL, "iprovide");
699 STRLIST_FOREACH (tmplist, svc, i) {
700 rc_schedule_start_service (svc, service);
701
702 rc_strlist_free (svclist);
703 svclist = rc_strlist_add (NULL, svc);
704 rc_strlist_free (providelist);
705 providelist = rc_get_depends (deptree, types, svclist,
706 softlevel, depoptions);
707 STRLIST_FOREACH (providelist, svc2, j)
708 rc_schedule_start_service (svc2, service);
709
710 len += strlen (svc) + 2;
711 n++;
712 }
713
714 len += 5;
715 tmp = rc_xmalloc (sizeof (char *) * len);
716 p = tmp;
717 STRLIST_FOREACH (tmplist, svc, i) {
718 if (i > 1) {
719 if (i == n - 1)
720 p += snprintf (p, len, " or ");
721 else
722 p += snprintf (p, len, ", ");
723 }
724 p += snprintf (p, len, "%s", svc);
725 }
726 ewarnx ("WARNING: %s is scheduled to start when %s has started",
727 applet, tmp);
728 }
729
730 rc_strlist_free (services);
731 services = NULL;
732 rc_strlist_free (types);
733 types = NULL;
734 rc_strlist_free (svclist);
735 svclist = NULL;
736 }
737
738 if (ibsave)
739 setenv ("IN_BACKGROUND", ibsave, 1);
740 rc_plugin_run (rc_hook_service_start_now, applet);
741 started = svc_exec ("start", NULL);
742 if (ibsave)
743 unsetenv ("IN_BACKGROUND");
744
745 if (in_control ()) {
746 if (! started) {
747 if (rc_service_state (service, rc_service_wasinactive))
748 rc_mark_service (service, rc_service_inactive);
749 else {
750 rc_mark_service (service, rc_service_stopped);
751 if (rc_runlevel_starting ())
752 rc_mark_service (service, rc_service_failed);
753 }
754 rc_plugin_run (rc_hook_service_start_done, applet);
755 eerrorx ("ERROR: %s failed to start", applet);
756 }
757 rc_mark_service (service, rc_service_started);
758 unlink_mtime_test ();
759 rc_plugin_run (rc_hook_service_start_done, applet);
760 } else {
761 rc_plugin_run (rc_hook_service_start_done, applet);
762 if (rc_service_state (service, rc_service_inactive))
763 ewarnx ("WARNING: %s has started, but is inactive", applet);
764 else
765 ewarnx ("WARNING: %s not under our control, aborting", applet);
766 }
767
768 /* Now start any scheduled services */
769 rc_strlist_free (services);
770 services = rc_services_scheduled (service);
771 STRLIST_FOREACH (services, svc, i)
772 if (rc_service_state (svc, rc_service_stopped))
773 rc_start_service (svc);
774 rc_strlist_free (services);
775 services = NULL;
776
777 /* Do the same for any services we provide */
778 rc_strlist_free (types);
779 types = rc_strlist_add (NULL, "iprovide");
780 rc_strlist_free (svclist);
781 svclist = rc_strlist_add (NULL, applet);
782 rc_strlist_free (tmplist);
783 tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions);
784
785 STRLIST_FOREACH (tmplist, svc2, j) {
786 rc_strlist_free (services);
787 services = rc_services_scheduled (svc2);
788 STRLIST_FOREACH (services, svc, i)
789 if (rc_service_state (svc, rc_service_stopped))
790 rc_start_service (svc);
791 }
792
793 hook_out = 0;
794 rc_plugin_run (rc_hook_service_start_out, applet);
795 }
796
797 static void svc_stop (bool deps)
798 {
799 bool stopped;
800
801 hook_out = rc_hook_service_stop_out;
802
803 if (rc_runlevel_stopping () &&
804 rc_service_state (service, rc_service_failed))
805 exit (EXIT_FAILURE);
806
807 if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
808 if (! rc_service_state (service, rc_service_started) &&
809 ! rc_service_state (service, rc_service_inactive))
810 exit (EXIT_FAILURE);
811
812 if (rc_service_state (service, rc_service_stopped)) {
813 ewarn ("WARNING: %s is already stopped", applet);
814 return;
815 } else if (rc_service_state (service, rc_service_stopping))
816 ewarnx ("WARNING: %s is already stopping", applet);
817
818 if (! rc_mark_service (service, rc_service_stopping))
819 eerrorx ("ERROR: %s has been stopped by something else", applet);
820
821 make_exclusive (service);
822
823 if (! rc_runlevel_stopping () &&
824 rc_service_in_runlevel (service, RC_LEVEL_BOOT))
825 ewarn ("WARNING: you are stopping a boot service");
826
827 if (deps || ! rc_service_state (service, rc_service_wasinactive)) {
828 int depoptions = RC_DEP_TRACE;
829 char *svc;
830 int i;
831
832 if (rc_is_env ("RC_STRICT_DEPEND", "yes"))
833 depoptions |= RC_DEP_STRICT;
834
835 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
836 eerrorx ("failed to load deptree");
837
838 rc_strlist_free (types);
839 types = rc_strlist_add (NULL, "needsme");
840 rc_strlist_free (svclist);
841 svclist = rc_strlist_add (NULL, applet);
842 rc_strlist_free (tmplist);
843 tmplist = NULL;
844 rc_strlist_free (services);
845 services = rc_get_depends (deptree, types, svclist,
846 softlevel, depoptions);
847 rc_strlist_reverse (services);
848 STRLIST_FOREACH (services, svc, i) {
849 if (rc_service_state (svc, rc_service_started) ||
850 rc_service_state (svc, rc_service_inactive))
851 {
852 rc_wait_service (svc);
853 if (rc_service_state (svc, rc_service_started) ||
854 rc_service_state (svc, rc_service_inactive))
855 {
856 pid_t pid = rc_stop_service (svc);
857 if (! rc_is_env ("RC_PARALLEL", "yes"))
858 rc_waitpid (pid);
859 tmplist = rc_strlist_add (tmplist, svc);
860 }
861 }
862 }
863 rc_strlist_free (services);
864 services = NULL;
865
866 STRLIST_FOREACH (tmplist, svc, i) {
867 if (rc_service_state (svc, rc_service_stopped))
868 continue;
869
870 /* We used to loop 3 times here - maybe re-do this if needed */
871 rc_wait_service (svc);
872 if (! rc_service_state (svc, rc_service_stopped)) {
873 if (rc_runlevel_stopping ())
874 rc_mark_service (svc, rc_service_failed);
875 eerrorx ("ERROR: cannot stop %s as %s is still up",
876 applet, svc);
877 }
878 }
879 rc_strlist_free (tmplist);
880 tmplist = NULL;
881
882 /* We now wait for other services that may use us and are stopping
883 This is important when a runlevel stops */
884 types = rc_strlist_add (types, "usesme");
885 types = rc_strlist_add (types, "ibefore");
886 services = rc_get_depends (deptree, types, svclist,
887 softlevel, depoptions);
888 STRLIST_FOREACH (services, svc, i) {
889 if (rc_service_state (svc, rc_service_stopped))
890 continue;
891 rc_wait_service (svc);
892 }
893
894 rc_strlist_free (services);
895 services = NULL;
896 rc_strlist_free (types);
897 types = NULL;
898 }
899
900 if (ibsave)
901 setenv ("IN_BACKGROUND", ibsave, 1);
902 rc_plugin_run (rc_hook_service_stop_now, applet);
903 stopped = svc_exec ("stop", NULL);
904 if (ibsave)
905 unsetenv ("IN_BACKGROUND");
906
907 if (! in_control ()) {
908 rc_plugin_run (rc_hook_service_stop_done, applet);
909 ewarnx ("WARNING: %s not under our control, aborting", applet);
910 }
911
912 if (! stopped) {
913 if (rc_service_state (service, rc_service_wasinactive))
914 rc_mark_service (service, rc_service_inactive);
915 else
916 rc_mark_service (service, rc_service_started);
917 rc_plugin_run (rc_hook_service_stop_done, applet);
918 eerrorx ("ERROR: %s failed to stop", applet);
919 }
920
921 if (in_background)
922 rc_mark_service (service, rc_service_inactive);
923 else
924 rc_mark_service (service, rc_service_stopped);
925
926 unlink_mtime_test ();
927 rc_plugin_run (rc_hook_service_stop_done, applet);
928 hook_out = 0;
929 rc_plugin_run (rc_hook_service_stop_out, applet);
930 }
931
932 static void svc_restart (bool deps)
933 {
934 /* This is hairly and a better way needs to be found I think!
935 The issue is this - openvpn need net and dns. net can restart
936 dns via resolvconf, so you could have openvpn trying to restart dnsmasq
937 which in turn is waiting on net which in turn is waiting on dnsmasq.
938 The work around is for resolvconf to restart it's services with --nodeps
939 which means just that. The downside is that there is a small window when
940 our status is invalid.
941 One workaround would be to introduce a new status, or status locking. */
942 if (! deps) {
943 if (rc_service_state (service, rc_service_started) ||
944 rc_service_state (service, rc_service_inactive))
945 svc_exec ("stop", "start");
946 else
947 svc_exec ("start", NULL);
948 return;
949 }
950
951 if (! rc_service_state (service, rc_service_stopped)) {
952 get_started_services ();
953 svc_stop (deps);
954 }
955
956 svc_start (deps);
957 start_services (restart_services);
958 rc_strlist_free (restart_services);
959 restart_services = NULL;
960 }
961
962 #define getoptstring "dCDNqvh"
963 static struct option longopts[] = {
964 { "debug", 0, NULL, 'd'},
965 { "nocolor", 0, NULL, 'C'},
966 { "nocolour", 0, NULL, 'C'},
967 { "nodeps", 0, NULL, 'D'},
968 { "quiet", 0, NULL, 'q'},
969 { "verbose", 0, NULL, 'v'},
970 { "help", 0, NULL, 'h'},
971 { NULL, 0, NULL, 0}
972 };
973 // #include "_usage.c"
974
975 int main (int argc, char **argv)
976 {
977 int i;
978 bool deps = true;
979 bool doneone = false;
980 char pid[16];
981 int retval;
982 int opt;
983 char *svc;
984
985 /* We need the full path to the service */
986 if (*argv[1] == '/')
987 service = rc_xstrdup (argv[1]);
988 else {
989 char pwd[PATH_MAX];
990 if (! getcwd (pwd, PATH_MAX))
991 eerrorx ("getcwd: %s", strerror (errno));
992 service = rc_strcatpaths (pwd, argv[1], (char *) NULL);
993 }
994
995 applet = rc_xstrdup (basename (service));
996 atexit (cleanup);
997
998 /* Change dir to / to ensure all init scripts don't use stuff in pwd */
999 chdir ("/");
1000
1001 /* Show help if insufficient args */
1002 if (argc < 3) {
1003 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1004 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1005 applet, strerror (errno));
1006 }
1007
1008 #ifdef __linux__
1009 /* coldplug events can trigger init scripts, but we don't want to run them
1010 until after rc sysinit has completed so we punt them to the boot runlevel */
1011 if (rc_exists ("/dev/.rcsysinit")) {
1012 eerror ("%s: cannot run until sysvinit completes", applet);
1013 if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
1014 eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
1015 tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
1016 symlink (service, tmp);
1017 exit (EXIT_FAILURE);
1018 }
1019 #endif
1020
1021 if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) {
1022 /* Ensure our environment is pure
1023 Also, add our configuration to it */
1024 env = rc_filter_env ();
1025 env = rc_config_env (env);
1026
1027 if (env) {
1028 char *p;
1029
1030 #ifdef __linux__
1031 /* clearenv isn't portable, but there's no harm in using it
1032 if we have it */
1033 clearenv ();
1034 #else
1035 char *var;
1036 /* No clearenv present here then.
1037 We could manipulate environ directly ourselves, but it seems that
1038 some kernels bitch about this according to the environ man pages
1039 so we walk though environ and call unsetenv for each value. */
1040 while (environ[0]) {
1041 tmp = rc_xstrdup (environ[0]);
1042 p = tmp;
1043 var = strsep (&p, "=");
1044 unsetenv (var);
1045 free (tmp);
1046 }
1047 tmp = NULL;
1048 #endif
1049
1050 STRLIST_FOREACH (env, p, i)
1051 putenv (p);
1052
1053 /* We don't free our list as that would be null in environ */
1054 }
1055
1056 softlevel = rc_get_runlevel ();
1057
1058 /* If not called from RC or another service then don't be parallel */
1059 unsetenv ("RC_PARALLEL");
1060 }
1061
1062 setenv ("RC_ELOG", service, 1);
1063 setenv ("SVCNAME", applet, 1);
1064
1065 /* Set an env var so that we always know our pid regardless of any
1066 subshells the init script may create so that our mark_service_*
1067 functions can always instruct us of this change */
1068 snprintf (pid, sizeof (pid), "%d", (int) getpid ());
1069 setenv ("RC_RUNSCRIPT_PID", pid, 1);
1070
1071 /* eprefix is kinda klunky, but it works for our purposes */
1072 if (rc_is_env ("RC_PARALLEL", "yes")) {
1073 int l = 0;
1074 int ll;
1075
1076 /* Get the longest service name */
1077 services = rc_services_in_runlevel (NULL);
1078 STRLIST_FOREACH (services, svc, i) {
1079 ll = strlen (svc);
1080 if (ll > l)
1081 l = ll;
1082 }
1083
1084 /* Make our prefix string */
1085 prefix = rc_xmalloc (sizeof (char *) * l);
1086 ll = strlen (applet);
1087 memcpy (prefix, applet, ll);
1088 memset (prefix + ll, ' ', l - ll);
1089 memset (prefix + l, 0, 1);
1090 eprefix (prefix);
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 }
1165
1166 /* Export the command we're running.
1167 This is important as we stamp on the restart function now but
1168 some start/stop routines still need to behave differently if
1169 restarting. */
1170 unsetenv ("RC_CMD");
1171 setenv ("RC_CMD", optarg, 1);
1172
1173 doneone = true;
1174
1175 if (strcmp (optarg, "describe") == 0) {
1176 svc_exec (optarg, NULL);
1177 } else if (strcmp (optarg, "help") == 0) {
1178 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1179 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1180 applet, strerror (errno));
1181 } else if (strcmp (optarg, "ineed") == 0 ||
1182 strcmp (optarg, "iuse") == 0 ||
1183 strcmp (optarg, "needsme") == 0 ||
1184 strcmp (optarg, "usesme") == 0 ||
1185 strcmp (optarg, "iafter") == 0 ||
1186 strcmp (optarg, "ibefore") == 0 ||
1187 strcmp (optarg, "iprovide") == 0) {
1188 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
1189 eerrorx ("failed to load deptree");
1190
1191 rc_strlist_free (types);
1192 types = rc_strlist_add (NULL, optarg);
1193 rc_strlist_free (svclist);
1194 svclist = rc_strlist_add (NULL, applet);
1195 rc_strlist_free (services);
1196 services = rc_get_depends (deptree, types, svclist, softlevel, 0);
1197 STRLIST_FOREACH (services, svc, i)
1198 printf ("%s%s", i == 1 ? "" : " ", svc);
1199 printf ("\n");
1200 } else if (strcmp (optarg, "status") == 0) {
1201 rc_service_state_t r = svc_status (service);
1202 retval = (int) r;
1203
1204 } else if (strcmp (optarg, "help") == 0) {
1205 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1206 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1207 applet, strerror (errno));
1208 } else {
1209 if (geteuid () != 0)
1210 eerrorx ("%s: root access required", applet);
1211
1212 if (strcmp (optarg, "conditionalrestart") == 0 ||
1213 strcmp (optarg, "condrestart") == 0)
1214 {
1215 if (rc_service_state (service, rc_service_started))
1216 svc_restart (deps);
1217 } else if (strcmp (optarg, "restart") == 0) {
1218 svc_restart (deps);
1219 } else if (strcmp (optarg, "start") == 0) {
1220 svc_start (deps);
1221 } else if (strcmp (optarg, "stop") == 0) {
1222 if (in_background)
1223 get_started_services ();
1224
1225 svc_stop (deps);
1226
1227 if (! in_background &&
1228 ! rc_runlevel_stopping () &&
1229 rc_service_state (service, rc_service_stopped))
1230 uncoldplug ();
1231
1232 if (in_background &&
1233 rc_service_state (service, rc_service_inactive))
1234 {
1235 int j;
1236 STRLIST_FOREACH (restart_services, svc, j)
1237 if (rc_service_state (svc, rc_service_stopped))
1238 rc_schedule_start_service (service, svc);
1239 }
1240 } else if (strcmp (optarg, "zap") == 0) {
1241 einfo ("Manually resetting %s to stopped state", applet);
1242 rc_mark_service (applet, rc_service_stopped);
1243 uncoldplug ();
1244 } else
1245 svc_exec (optarg, NULL);
1246
1247 /* We should ensure this list is empty after an action is done */
1248 rc_strlist_free (restart_services);
1249 restart_services = NULL;
1250 }
1251
1252 if (! doneone) {
1253 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1254 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1255 applet, strerror (errno));
1256 }
1257 }
1258
1259 return (retval);
1260 }

  ViewVC Help
Powered by ViewVC 1.1.20