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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20