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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20