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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20