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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20