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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20