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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2799 - (show annotations) (download) (as text)
Tue Jul 31 16:05:56 2007 UTC (7 years, 4 months ago) by uberlord
File MIME type: text/x-csrc
File size: 34393 byte(s)
    All our binaries are now mulicalls into rc, which makes our on disk size
    a lot smaller.
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 "builtins.h"
28 #include "einfo.h"
29 #include "rc.h"
30 #include "rc-misc.h"
31 #include "rc-plugin.h"
32 #include "strlist.h"
33
34 #define RCSCRIPT_HELP RC_LIBDIR "/sh/rc-help.sh"
35 #define SELINUX_LIB RC_LIBDIR "/runscript_selinux.so"
36
37 #define PREFIX_LOCK RC_SVCDIR "/prefix.lock"
38
39 static char *applet = NULL;
40 static char *service = NULL;
41 static char *exclusive = NULL;
42 static char *mtime_test = NULL;
43 static rc_depinfo_t *deptree = NULL;
44 static char **services = NULL;
45 static char **svclist = NULL;
46 static char **tmplist = NULL;
47 static char **providelist = NULL;
48 static char **types = NULL;
49 static char **restart_services = NULL;
50 static char **need_services = NULL;
51 static char **use_services = NULL;
52 static char **env = NULL;
53 static char *tmp = NULL;
54 static char *softlevel = NULL;
55 static bool sighup = false;
56 static char *ibsave = NULL;
57 static bool in_background = false;
58 static rc_hook_t hook_out = 0;
59 static pid_t service_pid = 0;
60 static char *prefix = NULL;
61 static bool prefix_locked = false;
62
63 extern char **environ;
64
65 #ifdef __linux__
66 static void (*selinux_run_init_old) (void);
67 static void (*selinux_run_init_new) (int argc, char **argv);
68
69 static void setup_selinux (int argc, char **argv);
70 #endif
71
72 #ifdef __linux__
73 static void setup_selinux (int argc, char **argv)
74 {
75 void *lib_handle = NULL;
76
77 lib_handle = dlopen (SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL);
78 if (lib_handle) {
79 /*
80 * FIXME: the below code generates the warning
81 * ISO C forbids assignment between function pointer and 'void *'
82 * which sucks ass
83 * http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html
84 */
85 selinux_run_init_old = (void (*)(void)) dlfunc (lib_handle, "selinux_runscript");
86 selinux_run_init_new = (void (*)(int, char **)) dlfunc (lib_handle, "selinux_runscript2");
87
88 /* Use new run_init if it rc_exists, else fall back to old */
89 if (selinux_run_init_new)
90 selinux_run_init_new (argc, argv);
91 else if (selinux_run_init_old)
92 selinux_run_init_old ();
93 else
94 /* This shouldnt happen... probably corrupt lib */
95 eerrorx ("run_init is missing from runscript_selinux.so!");
96 }
97 }
98 #endif
99
100 static void handle_signal (int sig)
101 {
102 pid_t pid;
103 int status;
104 int serrno = errno;
105 char signame[10] = { '\0' };
106
107 switch (sig) {
108 case SIGHUP:
109 sighup = true;
110 break;
111
112 case SIGCHLD:
113 do {
114 pid = waitpid (-1, &status, WNOHANG);
115 if (pid < 0) {
116 if (errno != ECHILD)
117 eerror ("waitpid: %s", strerror (errno));
118 return;
119 }
120 } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
121 if (pid == service_pid)
122 service_pid = 0;
123 break;
124
125 case SIGINT:
126 if (! signame[0])
127 snprintf (signame, sizeof (signame), "SIGINT");
128 case SIGTERM:
129 if (! signame[0])
130 snprintf (signame, sizeof (signame), "SIGTERM");
131 case SIGQUIT:
132 if (! signame[0])
133 snprintf (signame, sizeof (signame), "SIGQUIT");
134 /* Send the signal to our children too */
135 if (service_pid > 0)
136 kill (service_pid, sig);
137 eerrorx ("%s: caught %s, aborting", applet, signame);
138
139 default:
140 eerror ("%s: caught unknown signal %d", applet, sig);
141 }
142
143 /* Restore errno */
144 errno = serrno;
145 }
146
147 static time_t get_mtime (const char *pathname, bool follow_link)
148 {
149 struct stat buf;
150 int retval;
151
152 if (! pathname)
153 return (0);
154
155 retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf);
156 if (! retval)
157 return (buf.st_mtime);
158
159 errno = 0;
160 return (0);
161 }
162
163 static bool in_control ()
164 {
165 char *path;
166 time_t mtime;
167 const char *tests[] = { "starting", "started", "stopping",
168 "inactive", "wasinactive", NULL };
169 int i = 0;
170
171 if (sighup)
172 return (false);
173
174 if (! mtime_test || ! rc_exists (mtime_test))
175 return (false);
176
177 if (rc_service_state (applet, rc_service_stopped))
178 return (false);
179
180 if (! (mtime = get_mtime (mtime_test, false)))
181 return (false);
182
183 while (tests[i]) {
184 path = rc_strcatpaths (RC_SVCDIR, tests[i], applet, (char *) NULL);
185 if (rc_exists (path)) {
186 time_t m = get_mtime (path, false);
187 if (mtime < m && m != 0) {
188 free (path);
189 return (false);
190 }
191 }
192 free (path);
193 i++;
194 }
195
196 return (true);
197 }
198
199 static void uncoldplug ()
200 {
201 char *cold = rc_strcatpaths (RC_SVCDIR "coldplugged", applet, (char *) NULL);
202 if (rc_exists (cold) && unlink (cold) != 0)
203 eerror ("%s: unlink `%s': %s", applet, cold, strerror (errno));
204 free (cold);
205 }
206
207 static void start_services (char **list) {
208 bool inactive;
209 char *svc;
210 int i;
211
212 if (! list)
213 return;
214
215 inactive = rc_service_state (service, rc_service_inactive);
216 if (! inactive)
217 inactive = rc_service_state (service, rc_service_wasinactive);
218
219 if (inactive ||
220 rc_service_state (service, rc_service_starting) ||
221 rc_service_state (service, rc_service_started))
222 {
223 STRLIST_FOREACH (list, svc, i) {
224 if (rc_service_state (svc, rc_service_stopped)) {
225 if (inactive) {
226 rc_schedule_start_service (service, svc);
227 ewarn ("WARNING: %s is scheduled to started when %s has started",
228 svc, applet);
229 } else
230 rc_start_service (svc);
231 }
232 }
233 }
234 }
235
236 static void cleanup (void)
237 {
238 if (! rc_in_plugin) {
239 if (prefix_locked)
240 unlink (PREFIX_LOCK);
241 if (hook_out)
242 rc_plugin_run (hook_out, applet);
243 if (restart_services)
244 start_services (restart_services);
245 }
246
247 rc_plugin_unload ();
248 rc_free_deptree (deptree);
249 rc_strlist_free (services);
250 rc_strlist_free (types);
251 rc_strlist_free (svclist);
252 rc_strlist_free (providelist);
253 rc_strlist_free (need_services);
254 rc_strlist_free (use_services);
255 rc_strlist_free (restart_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 ("IN_HOTPLUG", "1") || in_background) {
578 if (! rc_service_state (service, rc_service_inactive) &&
579 ! rc_service_state (service, rc_service_stopped))
580 exit (EXIT_FAILURE);
581 background = true;
582 }
583
584 if (rc_service_state (service, rc_service_started)) {
585 ewarn ("WARNING: %s has already been started", applet);
586 return;
587 } else if (rc_service_state (service, rc_service_starting))
588 ewarnx ("WARNING: %s is already starting", applet);
589 else if (rc_service_state (service, rc_service_stopping))
590 ewarnx ("WARNING: %s is stopping", applet);
591 else if (rc_service_state (service, rc_service_inactive) && ! background)
592 ewarnx ("WARNING: %s has already started, but is inactive", applet);
593
594 if (! rc_mark_service (service, rc_service_starting))
595 eerrorx ("ERROR: %s has been started by something else", applet);
596
597 make_exclusive (service);
598
599 if (rc_is_env ("RC_DEPEND_STRICT", "yes"))
600 depoptions |= RC_DEP_STRICT;
601
602 if (rc_runlevel_starting ())
603 depoptions |= RC_DEP_START;
604
605 if (deps) {
606 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
607 eerrorx ("failed to load deptree");
608
609 rc_strlist_free (types);
610 types = rc_strlist_add (NULL, "broken");
611 rc_strlist_free (svclist);
612 svclist = rc_strlist_add (NULL, applet);
613 rc_strlist_free (services);
614 services = rc_get_depends (deptree, types, svclist, softlevel, 0);
615 if (services) {
616 eerrorn ("ERROR: `%s' needs ", applet);
617 STRLIST_FOREACH (services, svc, i) {
618 if (i > 0)
619 fprintf (stderr, ", ");
620 fprintf (stderr, "%s", svc);
621 }
622 exit (EXIT_FAILURE);
623 }
624 rc_strlist_free (services);
625 services = NULL;
626
627 rc_strlist_free (types);
628 types = rc_strlist_add (NULL, "ineed");
629 rc_strlist_free (need_services);
630 need_services = rc_get_depends (deptree, types, svclist,
631 softlevel, depoptions);
632
633 types = rc_strlist_add (types, "iuse");
634 rc_strlist_free (use_services);
635 use_services = rc_get_depends (deptree, types, svclist,
636 softlevel, depoptions);
637
638 if (! rc_runlevel_starting ()) {
639 STRLIST_FOREACH (use_services, svc, i)
640 if (rc_service_state (svc, rc_service_stopped)) {
641 pid_t pid = rc_start_service (svc);
642 if (! rc_is_env ("RC_PARALLEL", "yes"))
643 rc_waitpid (pid);
644 }
645 }
646
647 /* Now wait for them to start */
648 types = rc_strlist_add (types, "iafter");
649 services = rc_get_depends (deptree, types, svclist,
650 softlevel, depoptions);
651
652 /* We use tmplist to hold our scheduled by list */
653 rc_strlist_free (tmplist);
654 tmplist = NULL;
655
656 STRLIST_FOREACH (services, svc, i) {
657 if (rc_service_state (svc, rc_service_started))
658 continue;
659
660 /* Don't wait for services which went inactive but are now in
661 * starting state which we are after */
662 if (rc_service_state (svc, rc_service_starting) &&
663 rc_service_state(svc, rc_service_wasinactive)) {
664 bool use = false;
665 STRLIST_FOREACH (use_services, svc2, j)
666 if (strcmp (svc, svc2) == 0) {
667 use = true;
668 break;
669 }
670 if (! use)
671 continue;
672 }
673
674 if (! rc_wait_service (svc))
675 eerror ("%s: timed out waiting for %s", applet, svc);
676 if (rc_service_state (svc, rc_service_started))
677 continue;
678
679 STRLIST_FOREACH (need_services, svc2, j)
680 if (strcmp (svc, svc2) == 0) {
681 if (rc_service_state (svc, rc_service_inactive) ||
682 rc_service_state (svc, rc_service_wasinactive))
683 tmplist = rc_strlist_add (tmplist, svc);
684 else
685 eerrorx ("ERROR: cannot start %s as %s would not start",
686 applet, svc);
687 }
688 }
689
690 if (tmplist) {
691 int n = 0;
692 int len = 0;
693 char *p;
694
695 /* Set the state now, then unlink our exclusive so that
696 our scheduled list is preserved */
697 rc_mark_service (service, rc_service_stopped);
698 unlink_mtime_test ();
699
700 rc_strlist_free (types);
701 types = rc_strlist_add (NULL, "iprovide");
702 STRLIST_FOREACH (tmplist, svc, i) {
703 rc_schedule_start_service (svc, service);
704
705 rc_strlist_free (svclist);
706 svclist = rc_strlist_add (NULL, svc);
707 rc_strlist_free (providelist);
708 providelist = rc_get_depends (deptree, types, svclist,
709 softlevel, depoptions);
710 STRLIST_FOREACH (providelist, svc2, j)
711 rc_schedule_start_service (svc2, service);
712
713 len += strlen (svc) + 2;
714 n++;
715 }
716
717 len += 5;
718 tmp = rc_xmalloc (sizeof (char *) * len);
719 p = tmp;
720 STRLIST_FOREACH (tmplist, svc, i) {
721 if (i > 1) {
722 if (i == n)
723 p += snprintf (p, len, " or ");
724 else
725 p += snprintf (p, len, ", ");
726 }
727 p += snprintf (p, len, "%s", svc);
728 }
729 ewarnx ("WARNING: %s is scheduled to start when %s has started",
730 applet, tmp);
731 }
732
733 rc_strlist_free (services);
734 services = NULL;
735 rc_strlist_free (types);
736 types = NULL;
737 rc_strlist_free (svclist);
738 svclist = NULL;
739 }
740
741 if (ibsave)
742 setenv ("IN_BACKGROUND", ibsave, 1);
743 rc_plugin_run (rc_hook_service_start_now, applet);
744 started = svc_exec ("start", NULL);
745 if (ibsave)
746 unsetenv ("IN_BACKGROUND");
747
748 if (in_control ()) {
749 if (! started) {
750 if (rc_service_state (service, rc_service_wasinactive))
751 rc_mark_service (service, rc_service_inactive);
752 else {
753 rc_mark_service (service, rc_service_stopped);
754 if (rc_runlevel_starting ())
755 rc_mark_service (service, rc_service_failed);
756 }
757 rc_plugin_run (rc_hook_service_start_done, applet);
758 eerrorx ("ERROR: %s failed to start", applet);
759 }
760 rc_mark_service (service, rc_service_started);
761 unlink_mtime_test ();
762 rc_plugin_run (rc_hook_service_start_done, applet);
763 } else {
764 rc_plugin_run (rc_hook_service_start_done, applet);
765 if (rc_service_state (service, rc_service_inactive))
766 ewarnx ("WARNING: %s has started, but is inactive", applet);
767 else
768 ewarnx ("WARNING: %s not under our control, aborting", applet);
769 }
770
771 /* Now start any scheduled services */
772 rc_strlist_free (services);
773 services = rc_services_scheduled (service);
774 STRLIST_FOREACH (services, svc, i)
775 if (rc_service_state (svc, rc_service_stopped))
776 rc_start_service (svc);
777 rc_strlist_free (services);
778 services = NULL;
779
780 /* Do the same for any services we provide */
781 rc_strlist_free (types);
782 types = rc_strlist_add (NULL, "iprovide");
783 rc_strlist_free (svclist);
784 svclist = rc_strlist_add (NULL, applet);
785 rc_strlist_free (tmplist);
786 tmplist = rc_get_depends (deptree, types, svclist, softlevel, depoptions);
787
788 STRLIST_FOREACH (tmplist, svc2, j) {
789 rc_strlist_free (services);
790 services = rc_services_scheduled (svc2);
791 STRLIST_FOREACH (services, svc, i)
792 if (rc_service_state (svc, rc_service_stopped))
793 rc_start_service (svc);
794 }
795
796 hook_out = 0;
797 rc_plugin_run (rc_hook_service_start_out, applet);
798 }
799
800 static void svc_stop (bool deps)
801 {
802 bool stopped;
803
804 hook_out = rc_hook_service_stop_out;
805
806 if (rc_runlevel_stopping () &&
807 rc_service_state (service, rc_service_failed))
808 exit (EXIT_FAILURE);
809
810 if (rc_is_env ("IN_HOTPLUG", "1") || in_background)
811 if (! rc_service_state (service, rc_service_started) &&
812 ! rc_service_state (service, rc_service_inactive))
813 exit (EXIT_FAILURE);
814
815 if (rc_service_state (service, rc_service_stopped)) {
816 ewarn ("WARNING: %s is already stopped", applet);
817 return;
818 } else if (rc_service_state (service, rc_service_stopping))
819 ewarnx ("WARNING: %s is already stopping", applet);
820
821 if (! rc_mark_service (service, rc_service_stopping))
822 eerrorx ("ERROR: %s has been stopped by something else", applet);
823
824 make_exclusive (service);
825
826 if (! rc_runlevel_stopping () &&
827 rc_service_in_runlevel (service, RC_LEVEL_BOOT))
828 ewarn ("WARNING: you are stopping a boot service");
829
830 if (deps || ! rc_service_state (service, rc_service_wasinactive)) {
831 int depoptions = RC_DEP_TRACE;
832 char *svc;
833 int i;
834
835 if (rc_is_env ("RC_DEPEND_STRICT", "yes"))
836 depoptions |= RC_DEP_STRICT;
837
838 if (rc_runlevel_stopping ())
839 depoptions |= RC_DEP_STOP;
840
841 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
842 eerrorx ("failed to load deptree");
843
844 rc_strlist_free (types);
845 types = rc_strlist_add (NULL, "needsme");
846 rc_strlist_free (svclist);
847 svclist = rc_strlist_add (NULL, applet);
848 rc_strlist_free (tmplist);
849 tmplist = NULL;
850 rc_strlist_free (services);
851 services = rc_get_depends (deptree, types, svclist,
852 softlevel, depoptions);
853 rc_strlist_reverse (services);
854 STRLIST_FOREACH (services, svc, i) {
855 if (rc_service_state (svc, rc_service_started) ||
856 rc_service_state (svc, rc_service_inactive))
857 {
858 rc_wait_service (svc);
859 if (rc_service_state (svc, rc_service_started) ||
860 rc_service_state (svc, rc_service_inactive))
861 {
862 pid_t pid = rc_stop_service (svc);
863 if (! rc_is_env ("RC_PARALLEL", "yes"))
864 rc_waitpid (pid);
865 tmplist = rc_strlist_add (tmplist, svc);
866 }
867 }
868 }
869 rc_strlist_free (services);
870 services = NULL;
871
872 STRLIST_FOREACH (tmplist, svc, i) {
873 if (rc_service_state (svc, rc_service_stopped))
874 continue;
875
876 /* We used to loop 3 times here - maybe re-do this if needed */
877 rc_wait_service (svc);
878 if (! rc_service_state (svc, rc_service_stopped)) {
879 if (rc_runlevel_stopping ())
880 rc_mark_service (svc, rc_service_failed);
881 eerrorx ("ERROR: cannot stop %s as %s is still up",
882 applet, svc);
883 }
884 }
885 rc_strlist_free (tmplist);
886 tmplist = NULL;
887
888 /* We now wait for other services that may use us and are stopping
889 This is important when a runlevel stops */
890 types = rc_strlist_add (types, "usesme");
891 types = rc_strlist_add (types, "ibefore");
892 services = rc_get_depends (deptree, types, svclist,
893 softlevel, depoptions);
894 STRLIST_FOREACH (services, svc, i) {
895 if (rc_service_state (svc, rc_service_stopped))
896 continue;
897 rc_wait_service (svc);
898 }
899
900 rc_strlist_free (services);
901 services = NULL;
902 rc_strlist_free (types);
903 types = NULL;
904 }
905
906 if (ibsave)
907 setenv ("IN_BACKGROUND", ibsave, 1);
908 rc_plugin_run (rc_hook_service_stop_now, applet);
909 stopped = svc_exec ("stop", NULL);
910 if (ibsave)
911 unsetenv ("IN_BACKGROUND");
912
913 if (! in_control ()) {
914 rc_plugin_run (rc_hook_service_stop_done, applet);
915 ewarnx ("WARNING: %s not under our control, aborting", applet);
916 }
917
918 if (! stopped) {
919 if (rc_service_state (service, rc_service_wasinactive))
920 rc_mark_service (service, rc_service_inactive);
921 else
922 rc_mark_service (service, rc_service_started);
923 rc_plugin_run (rc_hook_service_stop_done, applet);
924 eerrorx ("ERROR: %s failed to stop", applet);
925 }
926
927 if (in_background)
928 rc_mark_service (service, rc_service_inactive);
929 else
930 rc_mark_service (service, rc_service_stopped);
931
932 unlink_mtime_test ();
933 rc_plugin_run (rc_hook_service_stop_done, applet);
934 hook_out = 0;
935 rc_plugin_run (rc_hook_service_stop_out, applet);
936 }
937
938 static void svc_restart (bool deps)
939 {
940 /* This is hairly and a better way needs to be found I think!
941 The issue is this - openvpn need net and dns. net can restart
942 dns via resolvconf, so you could have openvpn trying to restart dnsmasq
943 which in turn is waiting on net which in turn is waiting on dnsmasq.
944 The work around is for resolvconf to restart it's services with --nodeps
945 which means just that. The downside is that there is a small window when
946 our status is invalid.
947 One workaround would be to introduce a new status, or status locking. */
948 if (! deps) {
949 if (rc_service_state (service, rc_service_started) ||
950 rc_service_state (service, rc_service_inactive))
951 svc_exec ("stop", "start");
952 else
953 svc_exec ("start", NULL);
954 return;
955 }
956
957 if (! rc_service_state (service, rc_service_stopped)) {
958 get_started_services ();
959 svc_stop (deps);
960 }
961
962 svc_start (deps);
963 start_services (restart_services);
964 rc_strlist_free (restart_services);
965 restart_services = NULL;
966 }
967
968 #define getoptstring "dCDNqvh"
969 static struct option longopts[] = {
970 { "debug", 0, NULL, 'd'},
971 { "nocolor", 0, NULL, 'C'},
972 { "nocolour", 0, NULL, 'C'},
973 { "nodeps", 0, NULL, 'D'},
974 { "quiet", 0, NULL, 'q'},
975 { "verbose", 0, NULL, 'v'},
976 { "help", 0, NULL, 'h'},
977 { NULL, 0, NULL, 0}
978 };
979 // #include "_usage.c"
980
981 int runscript (int argc, char **argv)
982 {
983 int i;
984 bool deps = true;
985 bool doneone = false;
986 char pid[16];
987 int retval;
988 int opt;
989 char *svc;
990
991 /* We need the full path to the service */
992 if (*argv[1] == '/')
993 service = rc_xstrdup (argv[1]);
994 else {
995 char pwd[PATH_MAX];
996 if (! getcwd (pwd, PATH_MAX))
997 eerrorx ("getcwd: %s", strerror (errno));
998 service = rc_strcatpaths (pwd, argv[1], (char *) NULL);
999 }
1000
1001 applet = rc_xstrdup (basename (service));
1002 atexit (cleanup);
1003
1004 /* Change dir to / to ensure all init scripts don't use stuff in pwd */
1005 chdir ("/");
1006
1007 /* Show help if insufficient args */
1008 if (argc < 3) {
1009 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1010 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1011 applet, strerror (errno));
1012 }
1013
1014 #ifdef __linux__
1015 /* coldplug events can trigger init scripts, but we don't want to run them
1016 until after rc sysinit has completed so we punt them to the boot runlevel */
1017 if (rc_exists ("/dev/.rcsysinit")) {
1018 eerror ("%s: cannot run until sysvinit completes", applet);
1019 if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
1020 eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
1021 tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
1022 symlink (service, tmp);
1023 exit (EXIT_FAILURE);
1024 }
1025 #endif
1026
1027 if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) {
1028 /* Ensure our environment is pure
1029 Also, add our configuration to it */
1030 env = rc_filter_env ();
1031 env = rc_config_env (env);
1032
1033 if (env) {
1034 char *p;
1035
1036 #ifdef __linux__
1037 /* clearenv isn't portable, but there's no harm in using it
1038 if we have it */
1039 clearenv ();
1040 #else
1041 char *var;
1042 /* No clearenv present here then.
1043 We could manipulate environ directly ourselves, but it seems that
1044 some kernels bitch about this according to the environ man pages
1045 so we walk though environ and call unsetenv for each value. */
1046 while (environ[0]) {
1047 tmp = rc_xstrdup (environ[0]);
1048 p = tmp;
1049 var = strsep (&p, "=");
1050 unsetenv (var);
1051 free (tmp);
1052 }
1053 tmp = NULL;
1054 #endif
1055
1056 STRLIST_FOREACH (env, p, i)
1057 putenv (p);
1058 /* We don't free our list as that would be null in environ */
1059 }
1060
1061 softlevel = rc_get_runlevel ();
1062 }
1063
1064 setenv ("RC_ELOG", service, 1);
1065 setenv ("SVCNAME", applet, 1);
1066
1067 /* Set an env var so that we always know our pid regardless of any
1068 subshells the init script may create so that our mark_service_*
1069 functions can always instruct us of this change */
1070 snprintf (pid, sizeof (pid), "%d", (int) getpid ());
1071 setenv ("RC_RUNSCRIPT_PID", pid, 1);
1072
1073 /* eprefix is kinda klunky, but it works for our purposes */
1074 if (rc_is_env ("RC_PARALLEL", "yes")) {
1075 int l = 0;
1076 int ll;
1077
1078 /* Get the longest service name */
1079 services = rc_services_in_runlevel (NULL);
1080 STRLIST_FOREACH (services, svc, i) {
1081 ll = strlen (svc);
1082 if (ll > l)
1083 l = ll;
1084 }
1085
1086 /* Make our prefix string */
1087 prefix = rc_xmalloc (sizeof (char *) * l);
1088 ll = strlen (applet);
1089 memcpy (prefix, applet, ll);
1090 memset (prefix + ll, ' ', l - ll);
1091 memset (prefix + l, 0, 1);
1092 eprefix (prefix);
1093 }
1094
1095 #ifdef __linux__
1096 /* Ok, we are ready to go, so setup selinux if applicable */
1097 setup_selinux (argc, argv);
1098 #endif
1099
1100 /* Punt the first arg as it's our service name */
1101 argc--;
1102 argv++;
1103
1104 /* Right then, parse any options there may be */
1105 while ((opt = getopt_long (argc, argv, getoptstring,
1106 longopts, (int *) 0)) != -1)
1107 switch (opt) {
1108 case 'd':
1109 setenv ("RC_DEBUG", "yes", 1);
1110 break;
1111 case 'h':
1112 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1113 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1114 applet, strerror (errno));
1115 case 'C':
1116 setenv ("RC_NOCOLOR", "yes", 1);
1117 break;
1118 case 'D':
1119 deps = false;
1120 break;
1121 case 'q':
1122 setenv ("RC_QUIET", "yes", 1);
1123 break;
1124 case 'v':
1125 setenv ("RC_VERBOSE", "yes", 1);
1126 break;
1127 default:
1128 exit (EXIT_FAILURE);
1129 }
1130
1131 /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
1132 that is being called and not any dependents */
1133 if (getenv ("IN_BACKGROUND")) {
1134 in_background = rc_is_env ("IN_BACKGROUND", "true");
1135 ibsave = rc_xstrdup (getenv ("IN_BACKGROUND"));
1136 unsetenv ("IN_BACKGROUND");
1137 }
1138
1139 if (rc_is_env ("IN_HOTPLUG", "1")) {
1140 if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
1141 eerrorx ("%s: not allowed to be hotplugged", applet);
1142 }
1143
1144 /* Setup a signal handler */
1145 signal (SIGHUP, handle_signal);
1146 signal (SIGINT, handle_signal);
1147 signal (SIGQUIT, handle_signal);
1148 signal (SIGTERM, handle_signal);
1149 signal (SIGCHLD, handle_signal);
1150
1151 /* Load our plugins */
1152 rc_plugin_load ();
1153
1154 /* Now run each option */
1155 retval = EXIT_SUCCESS;
1156 while (optind < argc) {
1157 optarg = argv[optind++];
1158
1159 /* Abort on a sighup here */
1160 if (sighup)
1161 exit (EXIT_FAILURE);
1162
1163 if (strcmp (optarg, "status") != 0 &&
1164 strcmp (optarg, "help") != 0) {
1165 /* Only root should be able to run us */
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
1177 if (strcmp (optarg, "describe") == 0) {
1178 svc_exec (optarg, NULL);
1179 } else if (strcmp (optarg, "help") == 0) {
1180 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1181 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1182 applet, strerror (errno));
1183 } else if (strcmp (optarg, "ineed") == 0 ||
1184 strcmp (optarg, "iuse") == 0 ||
1185 strcmp (optarg, "needsme") == 0 ||
1186 strcmp (optarg, "usesme") == 0 ||
1187 strcmp (optarg, "iafter") == 0 ||
1188 strcmp (optarg, "ibefore") == 0 ||
1189 strcmp (optarg, "iprovide") == 0) {
1190 int depoptions = RC_DEP_TRACE;
1191
1192 if (rc_is_env ("RC_DEPEND_STRICT", "yes"))
1193 depoptions |= RC_DEP_STRICT;
1194
1195 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
1196 eerrorx ("failed to load deptree");
1197
1198 rc_strlist_free (types);
1199 types = rc_strlist_add (NULL, optarg);
1200 rc_strlist_free (svclist);
1201 svclist = rc_strlist_add (NULL, applet);
1202 rc_strlist_free (services);
1203 services = rc_get_depends (deptree, types, svclist,
1204 softlevel, depoptions);
1205 STRLIST_FOREACH (services, svc, i)
1206 printf ("%s%s", i == 1 ? "" : " ", svc);
1207 printf ("\n");
1208 } else if (strcmp (optarg, "status") == 0) {
1209 rc_service_state_t r = svc_status (service);
1210 retval = (int) r;
1211
1212 } else if (strcmp (optarg, "help") == 0) {
1213 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1214 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1215 applet, strerror (errno));
1216 } else {
1217 if (geteuid () != 0)
1218 eerrorx ("%s: root access required", applet);
1219
1220 if (strcmp (optarg, "conditionalrestart") == 0 ||
1221 strcmp (optarg, "condrestart") == 0)
1222 {
1223 if (rc_service_state (service, rc_service_started))
1224 svc_restart (deps);
1225 } else if (strcmp (optarg, "restart") == 0) {
1226 svc_restart (deps);
1227 } else if (strcmp (optarg, "start") == 0) {
1228 svc_start (deps);
1229 } else if (strcmp (optarg, "stop") == 0) {
1230 if (in_background)
1231 get_started_services ();
1232
1233 svc_stop (deps);
1234
1235 if (! in_background &&
1236 ! rc_runlevel_stopping () &&
1237 rc_service_state (service, rc_service_stopped))
1238 uncoldplug ();
1239
1240 if (in_background &&
1241 rc_service_state (service, rc_service_inactive))
1242 {
1243 int j;
1244 STRLIST_FOREACH (restart_services, svc, j)
1245 if (rc_service_state (svc, rc_service_stopped))
1246 rc_schedule_start_service (service, svc);
1247 }
1248 } else if (strcmp (optarg, "zap") == 0) {
1249 einfo ("Manually resetting %s to stopped state", applet);
1250 rc_mark_service (applet, rc_service_stopped);
1251 uncoldplug ();
1252 } else
1253 svc_exec (optarg, NULL);
1254
1255 /* We should ensure this list is empty after an action is done */
1256 rc_strlist_free (restart_services);
1257 restart_services = NULL;
1258 }
1259
1260 if (! doneone) {
1261 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1262 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1263 applet, strerror (errno));
1264 }
1265 }
1266
1267 return (retval);
1268 }

  ViewVC Help
Powered by ViewVC 1.1.20