gentoo: only coldplug services started by autoconfig if autoconfig is in the default...
[fbsplash.git] / gentoo / splash.c
blob47529147de23623f47d222244bb080511eefd526
1 /*
2 * splash.c - Splash plugin for the Gentoo RC system.
4 * Copyright (c) 2007-2008, Michal Januszewski <spock@gentoo.org>
6 * Original splash plugin compatible with baselayout-1's splash-functions.sh
7 * written by Roy Marples <uberlord@gentoo.org>.
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License v2. See the file COPYING in the main directory of this archive for
11 * more details.
14 #include <sys/stat.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <sys/wait.h>
22 #include <sys/ioctl.h>
23 #include <linux/kd.h>
24 #include <linux/fb.h>
25 #include <einfo.h>
26 #include <rc.h>
27 #include <fbsplash.h>
29 #define SPLASH_CMD "export SPLASH_XRES='%d'; export SPLASH_YRES='%d';" \
30 "export SOFTLEVEL='%s'; export BOOTLEVEL='%s';" \
31 "export DEFAULTLEVEL='%s'; export svcdir=${RC_SVCDIR};" \
32 ". /sbin/splash-functions.sh; %s %s %s"
34 static char *bootlevel = NULL;
35 static char *defaultlevel = NULL;
36 static char **svcs = NULL;
37 static char **svcs_done = NULL;
38 static int svcs_cnt = 0;
39 static int svcs_done_cnt = 0;
40 static pid_t pid_daemon = 0;
41 static fbspl_cfg_t *config = NULL;
43 static int xres = 0;
44 static int yres = 0;
47 * Check whether a strlist contains a specific item.
49 static bool list_has(char **list, const char *item)
51 for (; list && *list; list++) {
52 if (strcmp(*list, item) == 0)
53 return true;
55 return false;
59 * Merge two strlists keeping them sorted.
61 static char** strlist_merge_sort(char **dest, char **src)
63 int i;
65 for (i = 0; src && src[i]; i++) {
66 rc_strlist_addsort(&dest, src[i]);
68 return dest;
72 * Count the number of items in a strlist.
74 static int strlist_count(char **list)
76 int c;
78 for (c = 0; list && *list; list++)
79 c++;
81 return c;
85 * Create a strlist from a file pointer. Can be used
86 * to get a list of words printed by an app/script.
88 static char **get_list_fp(char **list, FILE *fp)
90 char buffer[512];
91 char *p;
92 char *token;
94 while (fgets(buffer, 512, fp)) {
95 p = buffer;
97 /* Remove the newline character */
98 if (p[strlen(p)-1] == '\n')
99 p[strlen(p)-1] = 0;
101 /* Strip leading spaces/tabs */
102 while ((*p == ' ') || (*p == '\t'))
103 p++;
105 /* Get entry - we do not want comments */
106 token = strsep(&p, "#");
107 if (!(token && (strlen(token) > 1)))
108 continue;
110 while ((p = strsep(&token, " ")) != NULL) {
111 if (strlen(p) > 1) {
112 rc_strlist_add(&list, p);
117 return list;
121 * Create a strlist from a file. Used for svcs_start/svcs_stop.
123 static char **get_list(char **list, const char *file)
125 FILE *fp;
127 if (!(fp = fopen(file, "r"))) {
128 ewarn("%s: `%s': %s", __func__, file, strerror(errno));
129 return list;
132 list = get_list_fp(list, fp);
133 fclose(fp);
135 return list;
139 * Get splash settings from /etc/conf.d/splash
141 static int splash_config_gentoo(fbspl_cfg_t *cfg, fbspl_type_t type)
143 char **confd;
144 char *t;
146 confd = rc_config_load("/etc/conf.d/splash");
148 t = rc_config_value(confd, "SPLASH_KDMODE");
149 if (t) {
150 if (!strcasecmp(t, "graphics")) {
151 cfg->kdmode = KD_GRAPHICS;
152 } else if (!strcasecmp(t, "text")) {
153 cfg->kdmode = KD_TEXT;
157 t = rc_config_value(confd, "SPLASH_PROFILE");
158 if (t) {
159 if (!strcasecmp(t, "on") || !strcasecmp(t, "yes"))
160 cfg->profile = true;
163 t = rc_config_value(confd, "SPLASH_TTY");
164 if (t) {
165 int i;
166 if (sscanf(t, "%d", &i) == 1 && i > 0) {
167 cfg->tty_s = i;
171 t = rc_config_value(confd, "SPLASH_THEME");
172 if (t)
173 fbsplash_acc_theme_set(t);
175 t = rc_config_value(confd, "SPLASH_MODE_REQ");
176 if (t) {
177 if (!strcasecmp(t, "verbose")) {
178 cfg->reqmode = FBSPL_MODE_VERBOSE;
179 } else if (!strcasecmp(t, "silent")) {
180 cfg->reqmode = FBSPL_MODE_VERBOSE | FBSPL_MODE_SILENT;
181 } else if (!strcasecmp(t, "silentonly")) {
182 cfg->reqmode = FBSPL_MODE_SILENT;
186 t = rc_config_value(confd, "SPLASH_VERBOSE_ON_ERRORS");
187 if (t && (!strcasecmp(t, "on") || !strcasecmp(t, "yes")))
188 cfg->vonerr = true;
190 switch(type) {
191 case fbspl_reboot:
192 t = rc_config_value(confd, "SPLASH_REBOOT_MESSAGE");
193 if (t)
194 fbsplash_acc_message_set(t);
195 break;
197 case fbspl_shutdown:
198 t = rc_config_value(confd, "SPLASH_SHUTDOWN_MESSAGE");
199 if (t)
200 fbsplash_acc_message_set(t);
201 break;
203 case fbspl_bootup:
204 default:
205 t = rc_config_value(confd, "SPLASH_BOOT_MESSAGE");
206 if (t)
207 fbsplash_acc_message_set(t);
208 break;
211 t = rc_config_value(confd, "SPLASH_TEXTBOX");
212 if (t) {
213 if (!strcasecmp(t, "on") || !strcasecmp(t, "yes"))
214 cfg->textbox_visible = true;
217 t = rc_config_value(confd, "SPLASH_AUTOVERBOSE");
218 if (t) {
219 cfg->autoverbose = atoi(t);
222 t = rc_config_value(confd, "SPLASH_EFFECTS");
223 if (t) {
224 char *opt;
226 while ((opt = strsep(&t, ",")) != NULL) {
227 if (!strcmp(opt, "fadein")) {
228 cfg->effects |= FBSPL_EFF_FADEIN;
229 } else if (!strcmp(opt, "fadeout")) {
230 cfg->effects |= FBSPL_EFF_FADEOUT;
235 rc_strlist_free(confd);
236 return 0;
240 * Call a function from /sbin/splash-functions.sh.
241 * This is rather slow, so use it only when really necessary.
243 static int splash_call(const char *cmd, const char *arg1, const char *arg2)
245 char *c;
246 int l;
247 char *soft = getenv("RC_SOFTLEVEL");
249 if (!cmd || !soft)
250 return -1;
252 l = strlen(SPLASH_CMD) + strlen(soft) + strlen(cmd) + 10;
253 if (arg1)
254 l += strlen(arg1);
255 if (arg2)
256 l += strlen(arg2);
258 c = malloc(sizeof(char*) * l);
259 if (!c)
260 return -1;
262 snprintf(c, l, SPLASH_CMD, xres, yres,
263 arg1 ? (strcmp(arg1, RC_LEVEL_SYSINIT) == 0 ? bootlevel : soft) : soft,
264 bootlevel, defaultlevel, cmd, arg1 ? arg1 : "", arg2 ? arg2 : "");
265 l = system(c);
266 free(c);
267 return l;
271 * Run a theme hook script.
273 static int splash_theme_hook(const char *name, const char *type, const char *arg1)
275 char *buf;
276 int l = 256;
277 struct stat st;
279 if (arg1)
280 fbsplash_profile("%s %s %s\n", type, name, arg1);
281 else
282 fbsplash_profile("%s %s\n", type, name);
284 l += strlen(name);
285 l += strlen(config->theme);
287 buf = malloc(l * sizeof(char*));
288 snprintf(buf, l, "/etc/splash/%s/scripts/%s-%s", config->theme, name, type);
289 if (stat(buf, &st) != 0) {
290 free(buf);
291 return 0;
294 l = splash_call(buf, arg1, NULL);
295 free(buf);
296 return l;
300 * Update service state.
302 static int splash_svc_state(const char *name, const char *state, bool paint)
304 if (paint)
305 splash_theme_hook(state, "pre", name);
308 if (!strcmp(state, "svc_started")) {
309 fbsplash_send("log Service '%s' started.\n", name);
310 } else if (!strcmp(state, "svc_start_failed")) {
311 fbsplash_send("log Service '%s' failed to start.\n", name);
312 } else if (!strcmp(state, "svc_stopped")) {
313 fbsplash_send("log Service '%s' stopped.\n", name);
314 } else if (!strcmp(state, "svc_stop_failed")) {
315 fbsplash_send("log Service '%s' failed to stop.\n", name);
318 fbsplash_send("update_svc %s %s\n", name, state);
320 if (paint) {
321 fbsplash_send("paint\n");
322 splash_theme_hook(state, "post", name);
325 return 0;
329 * Get the resolution that the silent splash will use.
331 static void splash_init_res()
333 struct fb_var_screeninfo var;
334 int fh;
336 if ((fh = open("/dev/fb0", O_RDONLY)) == -1)
337 if ((fh = open("/dev/fb/0", O_RDONLY)) == -1)
338 return;
340 if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
341 return;
343 close(fh);
345 fbsplash_get_res(config->theme, (int*)&var.xres, (int*)&var.yres);
346 xres = var.xres;
347 yres = var.yres;
351 * Init splash config variables and check that the splash daemon
352 * is running.
354 static int splash_init(bool start)
356 char **tmp;
358 config->verbosity = FBSPL_VERB_QUIET;
359 if (fbsplash_check_daemon(&pid_daemon)) {
360 config->verbosity = FBSPL_VERB_NORMAL;
361 return -1;
364 config->verbosity = FBSPL_VERB_NORMAL;
366 if (svcs)
367 ewarn("%s: We already have a svcs list!", __func__);
369 /* Booting.. */
370 if (start) {
371 svcs = get_list(NULL, FBSPLASH_CACHEDIR"/svcs_start");
372 svcs_cnt = strlist_count(svcs);
374 svcs_done = rc_services_in_state(RC_SERVICE_STARTED);
376 tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
377 svcs_done = strlist_merge_sort(svcs_done, tmp);
378 rc_strlist_free(tmp);
380 tmp = rc_services_in_state(RC_SERVICE_FAILED);
381 svcs_done = strlist_merge_sort(svcs_done, tmp);
382 rc_strlist_free(tmp);
384 tmp = rc_services_in_state(RC_SERVICE_SCHEDULED);
385 svcs_done = strlist_merge_sort(svcs_done, tmp);
386 rc_strlist_free(tmp);
388 svcs_done_cnt = strlist_count(svcs_done);
389 /* .. or rebooting? */
390 } else {
391 svcs = get_list(NULL, FBSPLASH_CACHEDIR"/svcs_stop");
392 svcs_cnt = strlist_count(svcs);
394 svcs_done = rc_services_in_state(RC_SERVICE_STARTED);
396 tmp = rc_services_in_state(RC_SERVICE_STARTING);
397 svcs_done = strlist_merge_sort(svcs_done, tmp);
398 rc_strlist_free(tmp);
400 tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
401 svcs_done = strlist_merge_sort(svcs_done, tmp);
402 rc_strlist_free(tmp);
404 svcs_done_cnt = svcs_cnt - strlist_count(svcs_done);
407 splash_init_res();
409 return 0;
413 * Handle the start/stop of a single service.
415 static int splash_svc_handle(const char *name, const char *state, bool skip)
417 if (!skip) {
418 /* If we don't have any services, something must be broken.
419 * Bail out since there is nothing we can do about it. */
420 if (svcs_cnt == 0)
421 return -1;
423 /* Don't process services twice. */
424 if (list_has(svcs_done, name))
425 return 0;
427 rc_strlist_add(&svcs_done, name);
428 svcs_done_cnt++;
431 /* Recalculate progress */
432 config->progress = svcs_done_cnt * FBSPL_PROGRESS_MAX / svcs_cnt;
434 splash_theme_hook(state, "pre", name);
435 splash_svc_state(name, state, 0);
436 fbsplash_send("progress %d\n", config->progress);
437 fbsplash_send("paint\n");
438 splash_theme_hook(state, "post", name);
440 return 0;
444 * Create a list of services that will be started during bootup.
446 int splash_svcs_start()
448 rc_depinfo_t *deptree;
449 FILE *fp;
450 char **t, **deporder, *s, *r;
451 int i, j, err = 0;
453 fp = fopen(FBSPLASH_CACHEDIR"/svcs_start", "w");
454 if (!fp) {
455 ewarn("%s: `%s': %s", __func__, FBSPLASH_CACHEDIR"/svcs_start", strerror(errno));
456 return -1;
459 if ((deptree = rc_deptree_load()) == NULL) {
460 eerror("%s: failed to load deptree", __func__);
461 err = -2;
462 goto out;
465 deporder = rc_deptree_order(deptree, bootlevel, RC_DEP_START);
467 /* Save what we've got so far to the svcs_start. */
468 i = 0;
469 if (deporder && deporder[0]) {
470 while ((s = deporder[i++])) {
471 if (i > 1)
472 fprintf(fp, " ");
473 fprintf(fp, "%s", s);
477 t = deporder;
478 deporder = rc_deptree_order(deptree, defaultlevel, RC_DEP_START);
480 /* Print the new services and skip ones that have already been started
481 * in the 'boot' runlevel. */
482 i = 0;
483 if (deporder && deporder[0]) {
484 while ((s = deporder[i])) {
485 j = 0;
486 while ((r = t[j++])) {
487 if (!strcmp(deporder[i], r))
488 goto next;
490 fprintf(fp, " %s", s);
491 next: i++;
495 rc_strlist_free(deporder);
496 rc_strlist_free(t);
497 rc_deptree_free(deptree);
499 out:
500 fclose(fp);
501 return 0;
505 * Create a list of services that will be stopped during reboot/shutdown.
507 int splash_svcs_stop(const char *runlevel)
509 rc_depinfo_t *deptree;
510 char **deporder, *s;
511 FILE *fp;
512 int i, err = 0;
514 fp = fopen(FBSPLASH_CACHEDIR"/svcs_stop", "w");
515 if (!fp) {
516 ewarn("%s: `%s': %s", __func__, FBSPLASH_CACHEDIR"/svcs_stop", strerror(errno));
517 return -1;
520 if ((deptree = rc_deptree_load()) == NULL) {
521 eerror("%s: failed to load deptree", __func__);
522 err = -2;
523 goto out;
526 deporder = rc_deptree_order(deptree, runlevel, RC_DEP_STOP);
528 i = 0;
529 if (deporder && deporder[0]) {
530 while ((s = deporder[i++])) {
531 if (i > 1)
532 fprintf(fp, " ");
533 fprintf(fp, "%s", s);
537 rc_strlist_free(deporder);
538 rc_deptree_free(deptree);
539 out:
540 fclose(fp);
541 return err;
545 * Start the splash daemon during boot/reboot.
547 static int splash_start(const char *runlevel)
549 bool start;
550 int i, err = 0;
551 char buf[2048];
553 /* Get a list of services that we'll have to handle. */
554 /* We're rebooting/shutting down. */
555 if (!strcmp(runlevel, RC_LEVEL_SHUTDOWN) || !strcmp(runlevel, RC_LEVEL_REBOOT)) {
556 if ((err = fbsplash_cache_prep()))
557 return err;
558 splash_svcs_stop(runlevel);
559 start = false;
560 /* We're booting. */
561 } else {
562 if ((err = fbsplash_cache_prep()))
563 return err;
564 splash_svcs_start();
565 start = true;
567 splash_init_res();
568 splash_theme_hook("rc_init", "pre", runlevel);
570 /* Perform sanity checks (console=, CONSOLE= etc). */
571 if (fbsplash_check_sanity())
572 return -1;
574 /* Start the splash daemon */
575 snprintf(buf, 2048, "BOOT_MSG='%s' " FBSPLASH_DAEMON " --theme=\"%s\" --pidfile=" FBSPLASH_PIDFILE " --type=%s %s %s %s",
576 config->message, config->theme,
577 (config->type == fbspl_reboot) ? "reboot" : ((config->type == fbspl_shutdown) ? "shutdown" : "bootup"),
578 (config->kdmode == KD_GRAPHICS) ? "--kdgraphics" : "",
579 (config->textbox_visible) ? "--textbox" : "",
580 (config->effects & (FBSPL_EFF_FADEOUT | FBSPL_EFF_FADEIN)) ? "--effects=fadeout,fadein" :
581 ((config->effects & FBSPL_EFF_FADEOUT) ? "--effects=fadeout" :
582 ((config->effects & FBSPL_EFF_FADEIN) ? "--effects=fadein" : "")));
584 err = system(buf);
585 if (err == -1 || WEXITSTATUS(err) != 0) {
586 eerror("Failed to start the splash daemon, error code %d", err);
587 return err;
590 err = splash_init(start);
591 if (err)
592 return err;
594 /* Set the initial state of all services. */
595 for (i = 0; svcs && svcs[i]; i++) {
596 splash_svc_state(svcs[i], start ? "svc_inactive_start" : "svc_inactive_stop", 0);
599 fbsplash_set_evdev();
600 fbsplash_send("set autoverbose %d\n", config->autoverbose);
601 fbsplash_send("set tty silent %d\n", config->tty_s);
602 fbsplash_send("set mode silent\n");
603 fbsplash_send("repaint\n");
604 return err;
608 * Stop the splash daemon.
610 static int splash_stop(const char *runlevel)
612 char *save[] = { "profile", "svcs_start", NULL };
613 char buf[128];
614 struct stat st;
615 int cnt = 0;
617 if (rc_service_state("xdm") & RC_SERVICE_STARTED) {
618 fbsplash_send("exit staysilent\n");
619 } else {
620 fbsplash_send("exit\n");
622 snprintf(buf, 128, "/proc/%d", pid_daemon);
624 /* Wait up to 1.0s for the splash daemon to exit. */
625 while (stat(buf, &st) == 0 && cnt < 100) {
626 usleep(10000);
627 cnt++;
630 /* Just to be sure we aren't stuck in a black ex-silent tty.. */
631 if (fbsplash_is_silent())
632 fbsplash_set_verbose(0);
634 /* If we don't get a runlevel argument, then we're being executed
635 * because of a rc-abort event and we don't save any data. */
636 if (runlevel == NULL) {
637 return fbsplash_cache_cleanup(NULL);
638 } else {
639 return fbsplash_cache_cleanup(save);
643 int rc_plugin_hook (rc_hook_t hook, const char *name)
645 int i = 0;
646 fbspl_type_t type = fbspl_bootup;
647 char *runlev;
648 bool skip = false;
649 int retval = 0;
651 runlev = rc_runlevel_get();
652 if (!strcmp(runlev, RC_LEVEL_REBOOT))
653 type = fbspl_reboot;
654 else if (!strcmp(runlev, RC_LEVEL_SHUTDOWN))
655 type = fbspl_shutdown;
657 /* Get boot and default levels from env variables exported by RC.
658 * If unavailable, use the default ones. */
659 bootlevel = getenv("RC_BOOTLEVEL");
660 defaultlevel = getenv("RC_DEFAULTLEVEL");
662 /* We generally do nothing if we're in sysinit. Except if the
663 * autoconfig service is present, when we get a list of services
664 * that will be started by it and mark them as coldplugged. */
665 if (name && !strcmp(name, RC_LEVEL_SYSINIT)) {
666 if (hook == RC_HOOK_RUNLEVEL_START_OUT && rc_service_in_runlevel("autoconfig", defaultlevel)) {
667 FILE *fp;
668 char **list = NULL;
669 int i;
671 fp = popen("if [ -e /etc/init.d/autoconfig ]; then . /etc/init.d/autoconfig ; list_services ; fi", "r");
672 if (!fp)
673 goto exit;
675 list = get_list_fp(NULL, fp);
676 for (i = 0; list && list[i]; i++) {
677 rc_service_mark(list[i], RC_SERVICE_COLDPLUGGED);
679 pclose(fp);
681 goto exit;
684 /* Don't do anything if we're starting/stopping a service, but
685 * we aren't in the middle of a runlevel switch. */
686 if (!(rc_runlevel_starting() || rc_runlevel_stopping())) {
687 if (hook != RC_HOOK_RUNLEVEL_STOP_IN &&
688 hook != RC_HOOK_RUNLEVEL_STOP_OUT &&
689 hook != RC_HOOK_RUNLEVEL_START_IN &&
690 hook != RC_HOOK_RUNLEVEL_START_OUT)
691 goto exit;
692 } else {
693 /* We're starting/stopping a runlevel. Check whether we're
694 * actually booting/rebooting. */
695 if (rc_runlevel_starting() && strcmp(runlev, bootlevel) &&
696 strcmp(runlev, defaultlevel) && strcmp(runlev, RC_LEVEL_SYSINIT))
697 goto exit;
699 if (rc_runlevel_stopping() && strcmp(runlev, bootlevel) &&
700 strcmp(runlev, RC_LEVEL_REBOOT) && strcmp(runlev, RC_LEVEL_SHUTDOWN))
701 goto exit;
704 if (!config) {
705 config = fbsplash_lib_init(type);
706 splash_config_gentoo(config, type);
707 fbsplash_parse_kcmdline(false);
710 /* Extremely weird.. should never happen. */
711 if (!config) {
712 retval = -1;
713 goto exit;
716 /* Don't do anything if we're not running in silent mode. */
717 if (!(config->reqmode & FBSPL_MODE_SILENT))
718 goto exit;
720 switch (hook) {
721 case RC_HOOK_RUNLEVEL_STOP_IN:
722 /* Start the splash daemon on reboot. The theme hook is called
723 * from splash_start(). */
724 if (strcmp(name, RC_LEVEL_REBOOT) == 0 || strcmp(name, RC_LEVEL_SHUTDOWN) == 0) {
725 if ((i = splash_start(name))) {
726 fbsplash_set_verbose(0);
727 retval= i;
728 goto exit;
729 } else {
730 if (rc_service_state("gpm") & RC_SERVICE_STARTED) {
731 fbsplash_send("set gpm\n");
732 fbsplash_send("repaint\n");
735 splash_theme_hook("rc_init", "post", name);
736 retval = i;
737 goto exit;
738 } else {
739 splash_theme_hook("rc_exit", "pre", name);
740 splash_theme_hook("rc_exit", "post", name);
741 fbsplash_lib_cleanup();
742 config = NULL;
744 break;
746 case RC_HOOK_RUNLEVEL_STOP_OUT:
747 /* Make sure the progress indicator reaches 100%, even if
748 * something went wrong along the way. */
749 if (strcmp(name, RC_LEVEL_REBOOT) == 0 || strcmp(name, RC_LEVEL_SHUTDOWN) == 0) {
750 config->verbosity = FBSPL_VERB_QUIET;
751 i = fbsplash_check_daemon(&pid_daemon);
752 config->verbosity = FBSPL_VERB_NORMAL;
753 if (i) {
754 retval = -1;
755 goto exit;
758 fbsplash_send("progress %d\n", FBSPL_PROGRESS_MAX);
759 fbsplash_send("paint\n");
760 fbsplash_cache_cleanup(NULL);
762 break;
764 case RC_HOOK_RUNLEVEL_START_IN:
765 /* Start the splash daemon during boot right after we finish
766 * sysinit and are entering the boot runlevel. Due to historical
767 * reasons, we simulate a full sysinit cycle here for the theme
768 * scripts. */
769 if (strcmp(name, bootlevel) == 0) {
770 if ((i = splash_start(RC_LEVEL_SYSINIT)))
771 fbsplash_set_verbose(0);
772 splash_theme_hook("rc_init", "post", RC_LEVEL_SYSINIT);
773 splash_theme_hook("rc_exit", "pre", RC_LEVEL_SYSINIT);
774 splash_theme_hook("rc_exit", "post", RC_LEVEL_SYSINIT);
776 splash_theme_hook("rc_init", "pre", name);
777 splash_theme_hook("rc_init", "post", name);
778 break;
780 case RC_HOOK_RUNLEVEL_START_OUT:
781 /* Stop the splash daemon after boot-up is finished. */
782 if (strcmp(name, bootlevel)) {
783 config->verbosity = FBSPL_VERB_QUIET;
784 i = fbsplash_check_daemon(&pid_daemon);
785 config->verbosity = FBSPL_VERB_NORMAL;
786 if (i) {
787 retval = -1;
788 goto exit;
791 /* Make sure the progress indicator reaches 100%, even if
792 * something went wrong along the way. */
793 fbsplash_send("progress %d\n", FBSPL_PROGRESS_MAX);
794 fbsplash_send("paint\n");
795 splash_theme_hook("rc_exit", "pre", name);
796 i = splash_stop(name);
797 splash_theme_hook("rc_exit", "post", name);
798 fbsplash_lib_cleanup();
799 config = NULL;
801 break;
803 case RC_HOOK_SERVICE_START_NOW:
804 do_start:
805 /* If we've been inactive, do nothing since the service has
806 * already been handled before it went inactive. */
807 if (rc_service_state(name) & RC_SERVICE_WASINACTIVE)
808 goto exit;
810 /* If we're starting or stopping a service, we're being called by
811 * runscript and thus have to reload our config. */
812 if (splash_init(true)) {
813 retval = -1;
814 goto exit;
816 i = splash_svc_handle(name, "svc_start", skip);
817 break;
819 case RC_HOOK_SERVICE_START_OUT:
820 /* If a service gets scheduled, we want to increment the progress
821 * bar (as it is no longer blocking boot completion). However,
822 * the service may actually start during boot (some time after
823 * being scheduled), so we don't want to increment the progress
824 * bar twice. The following if clause satisfies this by catching
825 * the first case but not the second. */
826 if ((rc_service_state(name) & RC_SERVICE_SCHEDULED) &&
827 !(rc_service_state(name) & RC_SERVICE_STARTING)) {
828 skip = true;
829 goto do_start;
831 break;
833 case RC_HOOK_SERVICE_START_DONE:
834 config->verbosity = FBSPL_VERB_QUIET;
835 i = fbsplash_check_daemon(&pid_daemon);
836 config->verbosity = FBSPL_VERB_NORMAL;
837 if (i) {
838 retval = -1;
839 goto exit;
842 if (!(rc_service_state(name) & RC_SERVICE_FAILED) &&
843 !(rc_service_state(name) & RC_SERVICE_STOPPED)) {
844 bool gpm = false;
846 if (!strcmp(name, "gpm")) {
847 struct stat st;
848 int cnt = 0;
849 gpm = true;
850 /* Wait up to 0.25s for the GPM socket to appear. */
851 while (stat("/dev/gpmctl", &st) == 0 && cnt < 25) {
852 usleep(10000);
853 cnt++;
855 fbsplash_send("set gpm\n");
858 i = splash_svc_state(name, "svc_started", 1);
860 if (gpm) {
861 fbsplash_send("repaint\n");
863 } else {
864 i = splash_svc_state(name, "svc_start_failed", 1);
865 if (config->vonerr) {
866 fbsplash_set_verbose(0);
869 fbsplash_lib_cleanup();
870 config = NULL;
871 break;
873 case RC_HOOK_SERVICE_STOP_NOW:
874 if (splash_init(false)) {
875 retval = -1;
876 goto exit;
879 /* We need to stop localmount from unmounting our cache dir.
880 Luckily plugins can add to the unmount list. */
881 if (name && !strcmp(name, "localmount")) {
882 char *umounts = getenv("RC_NO_UMOUNTS");
884 if (umounts)
885 fprintf(rc_environ_fd, "RC_NO_UMOUNTS=%s:%s", umounts, FBSPLASH_CACHEDIR);
886 else
887 fprintf(rc_environ_fd, "RC_NO_UMOUNTS=%s", FBSPLASH_CACHEDIR);
889 i = splash_svc_handle(name, "svc_stop", false);
890 break;
892 case RC_HOOK_SERVICE_STOP_DONE:
893 config->verbosity = FBSPL_VERB_QUIET;
894 i = fbsplash_check_daemon(&pid_daemon);
895 config->verbosity = FBSPL_VERB_NORMAL;
896 if (i) {
897 retval = -1;
898 goto exit;
901 if (rc_service_state(name) & RC_SERVICE_STOPPED) {
902 i = splash_svc_state(name, "svc_stopped", 1);
903 } else {
904 i = splash_svc_state(name, "svc_stop_failed", 1);
905 if (config->vonerr) {
906 fbsplash_set_verbose(0);
909 fbsplash_lib_cleanup();
910 config = NULL;
911 break;
913 case RC_HOOK_ABORT:
914 i = splash_stop(name);
915 fbsplash_lib_cleanup();
916 config = NULL;
917 break;
919 default:
920 break;
923 if (svcs) {
924 rc_strlist_free(svcs);
925 svcs = NULL;
928 exit:
929 free (runlev);
930 return i;