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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2765 - (show annotations) (download) (as text)
Tue Jul 10 20:11:42 2007 UTC (7 years, 4 months ago) by uberlord
File MIME type: text/x-csrc
File size: 34878 byte(s)
Allow non root users to describe
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 char *svc;
994
995 /* We need the full path to the service */
996 if (*argv[1] == '/')
997 service = rc_xstrdup (argv[1]);
998 else {
999 char pwd[PATH_MAX];
1000 if (! getcwd (pwd, PATH_MAX))
1001 eerrorx ("getcwd: %s", strerror (errno));
1002 service = rc_strcatpaths (pwd, argv[1], (char *) NULL);
1003 }
1004
1005 applet = rc_xstrdup (basename (service));
1006 atexit (cleanup);
1007
1008 /* Change dir to / to ensure all init scripts don't use stuff in pwd */
1009 chdir ("/");
1010
1011 /* Show help if insufficient args */
1012 if (argc < 3) {
1013 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1014 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1015 applet, strerror (errno));
1016 }
1017
1018 #ifdef __linux__
1019 /* coldplug events can trigger init scripts, but we don't want to run them
1020 until after rc sysinit has completed so we punt them to the boot runlevel */
1021 if (rc_exists ("/dev/.rcsysinit")) {
1022 eerror ("%s: cannot run until sysvinit completes", applet);
1023 if (mkdir ("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
1024 eerrorx ("%s: mkdir `/dev/.rcboot': %s", applet, strerror (errno));
1025 tmp = rc_strcatpaths ("/dev/.rcboot", applet, (char *) NULL);
1026 symlink (service, tmp);
1027 exit (EXIT_FAILURE);
1028 }
1029 #endif
1030
1031 if ((softlevel = getenv ("RC_SOFTLEVEL")) == NULL) {
1032 /* Ensure our environment is pure
1033 Also, add our configuration to it */
1034 env = rc_filter_env ();
1035 env = rc_config_env (env);
1036
1037 if (env) {
1038 char *p;
1039
1040 #ifdef __linux__
1041 /* clearenv isn't portable, but there's no harm in using it
1042 if we have it */
1043 clearenv ();
1044 #else
1045 char *var;
1046 /* No clearenv present here then.
1047 We could manipulate environ directly ourselves, but it seems that
1048 some kernels bitch about this according to the environ man pages
1049 so we walk though environ and call unsetenv for each value. */
1050 while (environ[0]) {
1051 tmp = rc_xstrdup (environ[0]);
1052 p = tmp;
1053 var = strsep (&p, "=");
1054 unsetenv (var);
1055 free (tmp);
1056 }
1057 tmp = NULL;
1058 #endif
1059
1060 STRLIST_FOREACH (env, p, i)
1061 putenv (p);
1062
1063 /* We don't free our list as that would be null in environ */
1064 }
1065
1066 softlevel = rc_get_runlevel ();
1067
1068 /* If not called from RC or another service then don't be parallel */
1069 unsetenv ("RC_PARALLEL");
1070 }
1071
1072 setenv ("RC_ELOG", service, 1);
1073 setenv ("SVCNAME", applet, 1);
1074
1075 /* Set an env var so that we always know our pid regardless of any
1076 subshells the init script may create so that our mark_service_*
1077 functions can always instruct us of this change */
1078 snprintf (pid, sizeof (pid), "%d", (int) getpid ());
1079 setenv ("RC_RUNSCRIPT_PID", pid, 1);
1080
1081 /* eprefix is kinda klunky, but it works for our purposes */
1082 if (rc_is_env ("RC_PREFIX", "yes")) {
1083 int l = 0;
1084 int ll;
1085
1086 /* Get the longest service name */
1087 services = rc_services_in_runlevel (NULL);
1088 STRLIST_FOREACH (services, svc, i) {
1089 ll = strlen (svc);
1090 if (ll > l)
1091 l = ll;
1092 }
1093
1094 /* Make our prefix string */
1095 prefix = rc_xmalloc (sizeof (char *) * l);
1096 ll = strlen (applet);
1097 memcpy (prefix, applet, ll);
1098 memset (prefix + ll, ' ', l - ll);
1099 memset (prefix + l, 0, 1);
1100 eprefix (prefix);
1101 }
1102
1103 /* If we're in parallel and we're not prefixing then we need the ebuffer */
1104 if (rc_is_env ("RC_PARALLEL", "yes") && ! rc_is_env ("RC_PREFIX", "yes")) {
1105 char ebname[PATH_MAX];
1106 char *eb;
1107
1108 snprintf (ebname, sizeof (ebname), "%s.%s", applet, pid);
1109 eb = rc_strcatpaths (RC_SVCDIR "ebuffer", ebname, (char *) NULL);
1110 ebuffer (eb);
1111 free (eb);
1112 }
1113
1114 #ifdef __linux__
1115 /* Ok, we are ready to go, so setup selinux if applicable */
1116 setup_selinux (argc, argv);
1117 #endif
1118
1119 /* Punt the first arg as it's our service name */
1120 argc--;
1121 argv++;
1122
1123 /* Right then, parse any options there may be */
1124 while ((opt = getopt_long (argc, argv, getoptstring,
1125 longopts, (int *) 0)) != -1)
1126 switch (opt) {
1127 case 'd':
1128 setenv ("RC_DEBUG", "yes", 1);
1129 break;
1130 case 'h':
1131 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1132 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1133 applet, strerror (errno));
1134 case 'C':
1135 setenv ("RC_NOCOLOR", "yes", 1);
1136 break;
1137 case 'D':
1138 deps = false;
1139 break;
1140 case 'q':
1141 setenv ("RC_QUIET", "yes", 1);
1142 break;
1143 case 'v':
1144 setenv ("RC_VERBOSE", "yes", 1);
1145 break;
1146 default:
1147 exit (EXIT_FAILURE);
1148 }
1149
1150 /* Save the IN_BACKGROUND env flag so it's ONLY passed to the service
1151 that is being called and not any dependents */
1152 if (getenv ("IN_BACKGROUND")) {
1153 in_background = rc_is_env ("IN_BACKGROUND", "true");
1154 ibsave = rc_xstrdup (getenv ("IN_BACKGROUND"));
1155 unsetenv ("IN_BACKGROUND");
1156 }
1157
1158 if (rc_is_env ("IN_HOTPLUG", "1")) {
1159 if (! rc_is_env ("RC_HOTPLUG", "yes") || ! rc_allow_plug (applet))
1160 eerrorx ("%s: not allowed to be hotplugged", applet);
1161 }
1162
1163 /* Setup a signal handler */
1164 signal (SIGHUP, handle_signal);
1165 signal (SIGINT, handle_signal);
1166 signal (SIGQUIT, handle_signal);
1167 signal (SIGTERM, handle_signal);
1168 signal (SIGCHLD, handle_signal);
1169
1170 /* Load our plugins */
1171 rc_plugin_load ();
1172
1173 /* Now run each option */
1174 retval = EXIT_SUCCESS;
1175 while (optind < argc) {
1176 optarg = argv[optind++];
1177
1178 /* Abort on a sighup here */
1179 if (sighup)
1180 exit (EXIT_FAILURE);
1181
1182 if (strcmp (optarg, "status") != 0 &&
1183 strcmp (optarg, "help") != 0) {
1184 /* Only root should be able to run us */
1185 }
1186
1187 /* Export the command we're running.
1188 This is important as we stamp on the restart function now but
1189 some start/stop routines still need to behave differently if
1190 restarting. */
1191 unsetenv ("RC_CMD");
1192 setenv ("RC_CMD", optarg, 1);
1193
1194 doneone = true;
1195
1196 if (strcmp (optarg, "describe") == 0) {
1197 svc_exec (optarg, NULL);
1198 } else if (strcmp (optarg, "help") == 0) {
1199 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1200 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1201 applet, strerror (errno));
1202 } else if (strcmp (optarg, "ineed") == 0 ||
1203 strcmp (optarg, "iuse") == 0 ||
1204 strcmp (optarg, "needsme") == 0 ||
1205 strcmp (optarg, "usesme") == 0 ||
1206 strcmp (optarg, "iafter") == 0 ||
1207 strcmp (optarg, "ibefore") == 0 ||
1208 strcmp (optarg, "iprovide") == 0) {
1209 if (! deptree && ((deptree = rc_load_deptree ()) == NULL))
1210 eerrorx ("failed to load deptree");
1211
1212 rc_strlist_free (types);
1213 types = rc_strlist_add (NULL, optarg);
1214 rc_strlist_free (svclist);
1215 svclist = rc_strlist_add (NULL, applet);
1216 rc_strlist_free (services);
1217 services = rc_get_depends (deptree, types, svclist, softlevel, 0);
1218 STRLIST_FOREACH (services, svc, i)
1219 printf ("%s%s", i == 1 ? "" : " ", svc);
1220 printf ("\n");
1221 } else if (strcmp (optarg, "status") == 0) {
1222 rc_service_state_t r = svc_status (service);
1223 retval = (int) r;
1224
1225 } else if (strcmp (optarg, "help") == 0) {
1226 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, "help", (char *) NULL);
1227 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1228 applet, strerror (errno));
1229 } else {
1230 if (geteuid () != 0)
1231 eerrorx ("%s: root access required", applet);
1232
1233 if (strcmp (optarg, "conditionalrestart") == 0 ||
1234 strcmp (optarg, "condrestart") == 0)
1235 {
1236 if (rc_service_state (service, rc_service_started))
1237 svc_restart (deps);
1238 } else if (strcmp (optarg, "restart") == 0) {
1239 svc_restart (deps);
1240 } else if (strcmp (optarg, "start") == 0) {
1241 svc_start (deps);
1242 } else if (strcmp (optarg, "stop") == 0) {
1243 if (in_background)
1244 get_started_services ();
1245
1246 svc_stop (deps);
1247
1248 if (! in_background &&
1249 ! rc_runlevel_stopping () &&
1250 rc_service_state (service, rc_service_stopped))
1251 uncoldplug ();
1252
1253 if (in_background &&
1254 rc_service_state (service, rc_service_inactive))
1255 {
1256 int j;
1257 STRLIST_FOREACH (restart_services, svc, j)
1258 if (rc_service_state (svc, rc_service_stopped))
1259 rc_schedule_start_service (service, svc);
1260 }
1261 } else if (strcmp (optarg, "zap") == 0) {
1262 einfo ("Manually resetting %s to stopped state", applet);
1263 rc_mark_service (applet, rc_service_stopped);
1264 uncoldplug ();
1265 } else
1266 svc_exec (optarg, NULL);
1267
1268 /* Flush our buffered output if any */
1269 eflush ();
1270
1271 /* We should ensure this list is empty after an action is done */
1272 rc_strlist_free (restart_services);
1273 restart_services = NULL;
1274 }
1275
1276 if (! doneone) {
1277 execl (RCSCRIPT_HELP, RCSCRIPT_HELP, service, (char *) NULL);
1278 eerrorx ("%s: failed to exec `" RCSCRIPT_HELP "': %s",
1279 applet, strerror (errno));
1280 }
1281 }
1282
1283 return (retval);
1284 }

  ViewVC Help
Powered by ViewVC 1.1.20