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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20