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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20