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

Contents of /trunk/src/runscript.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20