core: use the default font for the main splash message if not requested otherwise
[fbsplash.git] / gentoo / splash.c
blob6a448fa310728c3b2f8ad10830a48f9d935e8cb5
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 /* Some queue.h implenetations don't have this macro */
30 #ifndef TAILQ_CONCAT
31 #define TAILQ_CONCAT(head1, head2, field) do { \
32 if (!TAILQ_EMPTY(head2)) { \
33 *(head1)->tqh_last = (head2)->tqh_first; \
34 (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
35 (head1)->tqh_last = (head2)->tqh_last; \
36 TAILQ_INIT((head2)); \
37 } \
38 } while (0)
39 #endif
41 #define SPLASH_CMD "export SPLASH_XRES='%d'; export SPLASH_YRES='%d';" \
42 "export SOFTLEVEL='%s'; export BOOTLEVEL='%s';" \
43 "export DEFAULTLEVEL='%s'; export svcdir=${RC_SVCDIR};" \
44 ". /sbin/splash-functions.sh; %s %s %s"
46 static char *bootlevel = NULL;
47 static char *defaultlevel = NULL;
48 static RC_STRINGLIST *svcs = NULL;
49 static RC_STRINGLIST *svcs_done = NULL;
50 static int svcs_cnt = 0;
51 static int svcs_done_cnt = 0;
52 static pid_t pid_daemon = 0;
53 static fbspl_cfg_t *config = NULL;
55 static int xres = 0;
56 static int yres = 0;
59 * Check whether a strlist contains a specific item.
61 static bool list_has(RC_STRINGLIST *list, const char *item)
63 RC_STRING *s;
65 if (list) {
66 TAILQ_FOREACH(s, list, entries)
67 if (strcmp(s->value, item) == 0)
68 return true;
70 return false;
74 * Count the number of items in a strlist.
76 static int strlist_count(RC_STRINGLIST *list)
78 RC_STRING *s;
79 int c = 0;
81 if (list)
82 TAILQ_FOREACH(s, list, entries)
83 c++;
85 return c;
89 * Create a strlist from a file pointer. Can be used
90 * to get a list of words printed by an app/script.
92 static void get_list_fp(RC_STRINGLIST *list, FILE *fp)
94 char buffer[512];
95 char *p;
96 char *token;
98 while (fgets(buffer, 512, fp)) {
99 p = buffer;
101 /* Remove the newline character */
102 if (p[strlen(p)-1] == '\n')
103 p[strlen(p)-1] = 0;
105 /* Strip leading spaces/tabs */
106 while ((*p == ' ') || (*p == '\t'))
107 p++;
109 /* Get entry - we do not want comments */
110 token = strsep(&p, "#");
111 if (!(token && (strlen(token) > 1)))
112 continue;
114 while ((p = strsep(&token, " ")) != NULL) {
115 if (strlen(p) > 1) {
116 rc_stringlist_add(list, p);
123 * Create a strlist from a file. Used for svcs_start/svcs_stop.
125 static void get_list(RC_STRINGLIST *list, const char *file)
127 FILE *fp;
129 if (!(fp = fopen(file, "r"))) {
130 ewarn("%s: `%s': %s", __func__, file, strerror(errno));
131 } else {
132 get_list_fp(list, fp);
133 fclose(fp);
138 * Get splash settings from /etc/conf.d/splash
140 static int splash_config_gentoo(fbspl_cfg_t *cfg, fbspl_type_t type)
142 RC_STRINGLIST *confd;
143 char *t;
145 confd = rc_config_load("/etc/conf.d/splash");
147 t = rc_config_value(confd, "SPLASH_KDMODE");
148 if (t) {
149 if (!strcasecmp(t, "graphics")) {
150 cfg->kdmode = KD_GRAPHICS;
151 } else if (!strcasecmp(t, "text")) {
152 cfg->kdmode = KD_TEXT;
156 t = rc_config_value(confd, "SPLASH_PROFILE");
157 if (t) {
158 if (!strcasecmp(t, "on") || !strcasecmp(t, "yes"))
159 cfg->profile = true;
162 t = rc_config_value(confd, "SPLASH_TTY");
163 if (t) {
164 int i;
165 if (sscanf(t, "%d", &i) == 1 && i > 0) {
166 cfg->tty_s = i;
170 t = rc_config_value(confd, "SPLASH_THEME");
171 if (t)
172 fbsplash_acc_theme_set(t);
174 t = rc_config_value(confd, "SPLASH_MODE_REQ");
175 if (t) {
176 if (!strcasecmp(t, "verbose")) {
177 cfg->reqmode = FBSPL_MODE_VERBOSE;
178 } else if (!strcasecmp(t, "silent")) {
179 cfg->reqmode = FBSPL_MODE_VERBOSE | FBSPL_MODE_SILENT;
180 } else if (!strcasecmp(t, "silentonly")) {
181 cfg->reqmode = FBSPL_MODE_SILENT;
185 t = rc_config_value(confd, "SPLASH_VERBOSE_ON_ERRORS");
186 if (t && (!strcasecmp(t, "on") || !strcasecmp(t, "yes")))
187 cfg->vonerr = true;
189 switch(type) {
190 case fbspl_reboot:
191 t = rc_config_value(confd, "SPLASH_REBOOT_MESSAGE");
192 if (t)
193 fbsplash_acc_message_set(t);
194 break;
196 case fbspl_shutdown:
197 t = rc_config_value(confd, "SPLASH_SHUTDOWN_MESSAGE");
198 if (t)
199 fbsplash_acc_message_set(t);
200 break;
202 case fbspl_bootup:
203 default:
204 t = rc_config_value(confd, "SPLASH_BOOT_MESSAGE");
205 if (t)
206 fbsplash_acc_message_set(t);
207 break;
210 t = rc_config_value(confd, "SPLASH_TEXTBOX");
211 if (t) {
212 if (!strcasecmp(t, "on") || !strcasecmp(t, "yes"))
213 cfg->textbox_visible = true;
216 t = rc_config_value(confd, "SPLASH_AUTOVERBOSE");
217 if (t) {
218 cfg->autoverbose = atoi(t);
221 t = rc_config_value(confd, "SPLASH_EFFECTS");
222 if (t) {
223 char *opt;
225 while ((opt = strsep(&t, ",")) != NULL) {
226 if (!strcmp(opt, "fadein")) {
227 cfg->effects |= FBSPL_EFF_FADEIN;
228 } else if (!strcmp(opt, "fadeout")) {
229 cfg->effects |= FBSPL_EFF_FADEOUT;
234 rc_stringlist_free(confd);
235 return 0;
239 * Call a function from /sbin/splash-functions.sh.
240 * This is rather slow, so use it only when really necessary.
242 static int splash_call(const char *cmd, const char *arg1, const char *arg2)
244 char *c;
245 int l;
246 char *soft = getenv("RC_RUNLEVEL");
248 if (!cmd || !soft)
249 return -1;
251 l = strlen(SPLASH_CMD) + strlen(soft) + strlen(cmd) + 10;
252 if (arg1)
253 l += strlen(arg1);
254 if (arg2)
255 l += strlen(arg2);
257 c = malloc(sizeof(char*) * l);
258 if (!c)
259 return -1;
261 snprintf(c, l, SPLASH_CMD, xres, yres,
262 arg1 ? (strcmp(arg1, RC_LEVEL_SYSINIT) == 0 ? bootlevel : soft) : soft,
263 bootlevel, defaultlevel, cmd, arg1 ? arg1 : "", arg2 ? arg2 : "");
264 l = system(c);
265 free(c);
266 return l;
270 * Run a theme hook script.
272 static int splash_theme_hook(const char *name, const char *type, const char *arg1)
274 char *buf;
275 int l = 256;
276 struct stat st;
278 if (arg1)
279 fbsplash_profile("%s %s %s\n", type, name, arg1);
280 else
281 fbsplash_profile("%s %s\n", type, name);
283 l += strlen(name);
284 l += strlen(config->theme);
286 buf = malloc(l * sizeof(char*));
287 snprintf(buf, l, "/etc/splash/%s/scripts/%s-%s", config->theme, name, type);
288 if (stat(buf, &st) != 0) {
289 free(buf);
290 return 0;
293 l = splash_call(buf, arg1, NULL);
294 free(buf);
295 return l;
299 * Update service state.
301 static int splash_svc_state(const char *name, const char *state, bool paint)
303 if (paint)
304 splash_theme_hook(state, "pre", name);
307 if (!strcmp(state, "svc_started")) {
308 fbsplash_send("log Service '%s' started.\n", name);
309 } else if (!strcmp(state, "svc_start_failed")) {
310 fbsplash_send("log Service '%s' failed to start.\n", name);
311 } else if (!strcmp(state, "svc_stopped")) {
312 fbsplash_send("log Service '%s' stopped.\n", name);
313 } else if (!strcmp(state, "svc_stop_failed")) {
314 fbsplash_send("log Service '%s' failed to stop.\n", name);
317 fbsplash_send("update_svc %s %s\n", name, state);
319 if (paint) {
320 fbsplash_send("paint\n");
321 splash_theme_hook(state, "post", name);
324 return 0;
328 * Get the resolution that the silent splash will use.
330 static void splash_init_res()
332 struct fb_var_screeninfo var;
333 int fh;
335 if ((fh = open("/dev/fb0", O_RDONLY)) == -1)
336 if ((fh = open("/dev/fb/0", O_RDONLY)) == -1)
337 return;
339 if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
340 return;
342 close(fh);
344 fbsplash_get_res(config->theme, (int*)&var.xres, (int*)&var.yres);
345 xres = var.xres;
346 yres = var.yres;
350 * Init splash config variables and check that the splash daemon
351 * is running.
353 static int splash_init(bool start)
355 RC_STRINGLIST *tmp;
357 config->verbosity = FBSPL_VERB_QUIET;
358 if (fbsplash_check_daemon(&pid_daemon)) {
359 config->verbosity = FBSPL_VERB_NORMAL;
360 return -1;
363 config->verbosity = FBSPL_VERB_NORMAL;
365 if (svcs) {
366 ewarn("%s: We already have a svcs list!", __func__);
367 rc_stringlist_free(svcs);
369 svcs = rc_stringlist_new();
371 /* Booting.. */
372 if (start) {
373 get_list(svcs, FBSPLASH_CACHEDIR"/svcs_start");
374 svcs_cnt = strlist_count(svcs);
376 svcs_done = rc_services_in_state(RC_SERVICE_STARTED);
378 tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
379 if (svcs_done && tmp) {
380 TAILQ_CONCAT(svcs_done, tmp, entries);
381 free(tmp);
382 } else if (tmp)
383 svcs_done = tmp;
385 tmp = rc_services_in_state(RC_SERVICE_FAILED);
386 if (svcs_done && tmp) {
387 TAILQ_CONCAT(svcs_done, tmp, entries);
388 free(tmp);
389 } else if (tmp)
390 svcs_done = tmp;
392 tmp = rc_services_in_state(RC_SERVICE_SCHEDULED);
393 if (svcs_done && tmp) {
394 TAILQ_CONCAT(svcs_done, tmp, entries);
395 free(tmp);
396 } else if (tmp)
397 svcs_done = tmp;
399 svcs_done_cnt = strlist_count(svcs_done);
400 /* .. or rebooting? */
401 } else {
402 get_list(svcs, FBSPLASH_CACHEDIR"/svcs_stop");
403 svcs_cnt = strlist_count(svcs);
405 svcs_done = rc_services_in_state(RC_SERVICE_STARTED);
407 tmp = rc_services_in_state(RC_SERVICE_STARTING);
408 if (svcs_done && tmp) {
409 TAILQ_CONCAT(svcs_done, tmp, entries);
410 free(tmp);
411 } else if (tmp)
412 svcs_done = tmp;
414 tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
415 if (svcs_done && tmp) {
416 TAILQ_CONCAT(svcs_done, tmp, entries);
417 free(tmp);
418 } else if (tmp)
419 svcs_done = tmp;
421 svcs_done_cnt = svcs_cnt - strlist_count(svcs_done);
424 splash_init_res();
426 return 0;
430 * Handle the start/stop of a single service.
432 static int splash_svc_handle(const char *name, const char *state, bool skip)
434 if (!skip) {
435 /* If we don't have any services, something must be broken.
436 * Bail out since there is nothing we can do about it. */
437 if (svcs_cnt == 0)
438 return -1;
440 /* Don't process services twice. */
441 if (list_has(svcs_done, name))
442 return 0;
444 if (!svcs_done)
445 svcs_done = rc_stringlist_new();
446 rc_stringlist_add(svcs_done, name);
447 svcs_done_cnt++;
450 /* Recalculate progress */
451 config->progress = svcs_done_cnt * FBSPL_PROGRESS_MAX / svcs_cnt;
453 splash_theme_hook(state, "pre", name);
454 splash_svc_state(name, state, 0);
455 fbsplash_send("progress %d\n", config->progress);
456 fbsplash_send("paint\n");
457 splash_theme_hook(state, "post", name);
459 return 0;
463 * Create a list of services that will be started during bootup.
465 int splash_svcs_start()
467 RC_DEPTREE *deptree;
468 FILE *fp;
469 RC_STRINGLIST *t, *deporder;
470 RC_STRING *s, *r;
471 int i, err = 0;
473 fp = fopen(FBSPLASH_CACHEDIR"/svcs_start", "w");
474 if (!fp) {
475 ewarn("%s: `%s': %s", __func__, FBSPLASH_CACHEDIR"/svcs_start", strerror(errno));
476 return -1;
479 if ((deptree = rc_deptree_load()) == NULL) {
480 eerror("%s: failed to load deptree", __func__);
481 err = -2;
482 goto out;
485 deporder = rc_deptree_order(deptree, bootlevel, RC_DEP_START);
487 /* Save what we've got so far to the svcs_start. */
488 if (deporder) {
489 i = 0;
490 TAILQ_FOREACH(s, deporder, entries) {
491 if (i > 0)
492 fprintf(fp, " ");
493 fprintf(fp, "%s", s->value);
494 i++;
498 t = deporder;
499 deporder = rc_deptree_order(deptree, defaultlevel, RC_DEP_START);
501 /* Print the new services and skip ones that have already been started
502 * in the 'boot' runlevel. */
503 if (deporder) {
504 TAILQ_FOREACH(s, deporder, entries) {
505 char duplicate = 0;
506 TAILQ_FOREACH(r, t, entries) {
507 if (!strcmp(s->value, r->value)) {
508 duplicate = 1;
509 break;
512 if (!duplicate) {
513 fprintf(fp, " %s", s->value);
518 rc_stringlist_free(deporder);
519 rc_stringlist_free(t);
520 rc_deptree_free(deptree);
522 out:
523 fclose(fp);
524 return 0;
528 * Create a list of services that will be stopped during reboot/shutdown.
530 int splash_svcs_stop(const char *runlevel)
532 RC_DEPTREE *deptree;
533 RC_STRINGLIST *deporder;
534 RC_STRING *s;
535 FILE *fp;
536 int i, err = 0;
538 fp = fopen(FBSPLASH_CACHEDIR"/svcs_stop", "w");
539 if (!fp) {
540 ewarn("%s: `%s': %s", __func__, FBSPLASH_CACHEDIR"/svcs_stop", strerror(errno));
541 return -1;
544 if ((deptree = rc_deptree_load()) == NULL) {
545 eerror("%s: failed to load deptree", __func__);
546 err = -2;
547 goto out;
550 deporder = rc_deptree_order(deptree, runlevel, RC_DEP_STOP);
552 if (deporder) {
553 i = 0;
554 TAILQ_FOREACH(s, deporder, entries) {
555 if (i > 0)
556 fprintf(fp, " ");
557 fprintf(fp, "%s", s->value);
558 i++;
562 rc_stringlist_free(deporder);
563 rc_deptree_free(deptree);
564 out:
565 fclose(fp);
566 return err;
570 * Start the splash daemon during boot/reboot.
572 static int splash_start(const char *runlevel)
574 bool start;
575 int err = 0;
576 char buf[2048];
577 RC_STRING *s;
579 /* Get a list of services that we'll have to handle. */
580 /* We're rebooting/shutting down. */
581 if (!strcmp(runlevel, RC_LEVEL_SHUTDOWN) || !strcmp(runlevel, RC_LEVEL_REBOOT)) {
582 if ((err = fbsplash_cache_prep()))
583 return err;
584 splash_svcs_stop(runlevel);
585 start = false;
586 /* We're booting. */
587 } else {
588 if ((err = fbsplash_cache_prep()))
589 return err;
590 splash_svcs_start();
591 start = true;
593 splash_init_res();
594 splash_theme_hook("rc_init", "pre", runlevel);
596 /* Perform sanity checks (console=, CONSOLE= etc). */
597 if (fbsplash_check_sanity())
598 return -1;
600 /* Start the splash daemon */
601 snprintf(buf, 2048, "BOOT_MSG='%s' " FBSPLASH_DAEMON " --theme=\"%s\" --pidfile=" FBSPLASH_PIDFILE " --type=%s %s %s %s",
602 config->message, config->theme,
603 (config->type == fbspl_reboot) ? "reboot" : ((config->type == fbspl_shutdown) ? "shutdown" : "bootup"),
604 (config->kdmode == KD_GRAPHICS) ? "--kdgraphics" : "",
605 (config->textbox_visible) ? "--textbox" : "",
606 (config->effects & (FBSPL_EFF_FADEOUT | FBSPL_EFF_FADEIN)) ? "--effects=fadeout,fadein" :
607 ((config->effects & FBSPL_EFF_FADEOUT) ? "--effects=fadeout" :
608 ((config->effects & FBSPL_EFF_FADEIN) ? "--effects=fadein" : "")));
610 err = system(buf);
611 if (err == -1 || WEXITSTATUS(err) != 0) {
612 eerror("Failed to start the splash daemon, error code %d", err);
613 return err;
616 err = splash_init(start);
617 if (err)
618 return err;
620 /* Set the initial state of all services. */
621 if (svcs)
622 TAILQ_FOREACH(s, svcs, entries)
623 splash_svc_state(s->value, start ? "svc_inactive_start" : "svc_inactive_stop", 0);
625 fbsplash_set_evdev();
626 fbsplash_send("set autoverbose %d\n", config->autoverbose);
627 fbsplash_send("set tty silent %d\n", config->tty_s);
628 fbsplash_send("set mode silent\n");
629 fbsplash_send("repaint\n");
630 return err;
634 * Stop the splash daemon.
636 static int splash_stop(const char *runlevel)
638 char *save[] = { "profile", "svcs_start", NULL };
639 char buf[128];
640 struct stat st;
641 int cnt = 0;
643 if (rc_service_state("xdm") & RC_SERVICE_STARTED) {
644 fbsplash_send("exit staysilent\n");
645 } else {
646 fbsplash_send("exit\n");
648 snprintf(buf, 128, "/proc/%d", pid_daemon);
650 /* Wait up to 1.0s for the splash daemon to exit. */
651 while (stat(buf, &st) == 0 && cnt < 100) {
652 usleep(10000);
653 cnt++;
656 /* Just to be sure we aren't stuck in a black ex-silent tty.. */
657 if (fbsplash_is_silent())
658 fbsplash_set_verbose(0);
660 /* If we don't get a runlevel argument, then we're being executed
661 * because of a rc-abort event and we don't save any data. */
662 if (runlevel == NULL) {
663 return fbsplash_cache_cleanup(NULL);
664 } else {
665 return fbsplash_cache_cleanup(save);
669 int rc_plugin_hook(RC_HOOK hook, const char *name)
671 int i = 0;
672 fbspl_type_t type = fbspl_bootup;
673 char *runlev;
674 bool skip = false;
675 int retval = 0;
677 runlev = rc_runlevel_get();
678 if (!strcmp(runlev, RC_LEVEL_REBOOT))
679 type = fbspl_reboot;
680 else if (!strcmp(runlev, RC_LEVEL_SHUTDOWN))
681 type = fbspl_shutdown;
683 /* Get boot and default levels from env variables exported by RC.
684 * If unavailable, use the default ones. */
685 bootlevel = getenv("RC_BOOTLEVEL");
686 defaultlevel = getenv("RC_DEFAULTLEVEL");
688 /* We generally do nothing if we're in sysinit. Except if the
689 * autoconfig service is present, when we get a list of services
690 * that will be started by it and mark them as coldplugged. */
691 if (name && !strcmp(name, RC_LEVEL_SYSINIT)) {
692 if (hook == RC_HOOK_RUNLEVEL_START_OUT && rc_service_in_runlevel("autoconfig", defaultlevel)) {
693 FILE *fp;
694 RC_STRINGLIST *list;
695 RC_STRING *s;
697 fp = popen("if [ -e /etc/init.d/autoconfig ]; then . /etc/init.d/autoconfig ; list_services ; fi", "r");
698 if (!fp)
699 goto exit;
701 list = rc_stringlist_new();
702 get_list_fp(list, fp);
703 TAILQ_FOREACH(s, list, entries)
704 rc_service_mark(s->value, RC_SERVICE_COLDPLUGGED);
705 pclose(fp);
706 rc_stringlist_free(list);
708 goto exit;
711 /* Don't do anything if we're starting/stopping a service, but
712 * we aren't in the middle of a runlevel switch. */
713 if (!(rc_runlevel_starting() || rc_runlevel_stopping())) {
714 if (hook != RC_HOOK_RUNLEVEL_STOP_IN &&
715 hook != RC_HOOK_RUNLEVEL_STOP_OUT &&
716 hook != RC_HOOK_RUNLEVEL_START_IN &&
717 hook != RC_HOOK_RUNLEVEL_START_OUT)
718 goto exit;
719 } else {
720 /* We're starting/stopping a runlevel. Check whether we're
721 * actually booting/rebooting. */
722 if (rc_runlevel_starting() && strcmp(runlev, bootlevel) &&
723 strcmp(runlev, defaultlevel) && strcmp(runlev, RC_LEVEL_SYSINIT))
724 goto exit;
726 if (rc_runlevel_stopping() && strcmp(runlev, bootlevel) &&
727 strcmp(runlev, RC_LEVEL_REBOOT) && strcmp(runlev, RC_LEVEL_SHUTDOWN))
728 goto exit;
731 if (!config) {
732 config = fbsplash_lib_init(type);
733 splash_config_gentoo(config, type);
734 fbsplash_parse_kcmdline(false);
737 /* Extremely weird.. should never happen. */
738 if (!config) {
739 retval = -1;
740 goto exit;
743 /* Don't do anything if we're not running in silent mode. */
744 if (!(config->reqmode & FBSPL_MODE_SILENT))
745 goto exit;
747 switch (hook) {
748 case RC_HOOK_RUNLEVEL_STOP_IN:
749 /* Start the splash daemon on reboot. The theme hook is called
750 * from splash_start(). */
751 if (strcmp(name, RC_LEVEL_REBOOT) == 0 || strcmp(name, RC_LEVEL_SHUTDOWN) == 0) {
752 if ((i = splash_start(name))) {
753 fbsplash_set_verbose(0);
754 retval= i;
755 goto exit;
756 } else {
757 if (rc_service_state("gpm") & RC_SERVICE_STARTED) {
758 fbsplash_send("set gpm\n");
759 fbsplash_send("repaint\n");
762 splash_theme_hook("rc_init", "post", name);
763 retval = i;
764 goto exit;
765 } else {
766 splash_theme_hook("rc_exit", "pre", name);
767 splash_theme_hook("rc_exit", "post", name);
768 fbsplash_lib_cleanup();
769 config = NULL;
771 break;
773 case RC_HOOK_RUNLEVEL_STOP_OUT:
774 /* Make sure the progress indicator reaches 100%, even if
775 * something went wrong along the way. */
776 if (strcmp(name, RC_LEVEL_REBOOT) == 0 || strcmp(name, RC_LEVEL_SHUTDOWN) == 0) {
777 config->verbosity = FBSPL_VERB_QUIET;
778 i = fbsplash_check_daemon(&pid_daemon);
779 config->verbosity = FBSPL_VERB_NORMAL;
780 if (i) {
781 retval = -1;
782 goto exit;
785 fbsplash_send("progress %d\n", FBSPL_PROGRESS_MAX);
786 fbsplash_send("paint\n");
787 fbsplash_cache_cleanup(NULL);
789 break;
791 case RC_HOOK_RUNLEVEL_START_IN:
792 /* Start the splash daemon during boot right after we finish
793 * sysinit and are entering the boot runlevel. Due to historical
794 * reasons, we simulate a full sysinit cycle here for the theme
795 * scripts. */
796 if (strcmp(name, bootlevel) == 0) {
797 if ((i = splash_start(RC_LEVEL_SYSINIT)))
798 fbsplash_set_verbose(0);
799 splash_theme_hook("rc_init", "post", RC_LEVEL_SYSINIT);
800 splash_theme_hook("rc_exit", "pre", RC_LEVEL_SYSINIT);
801 splash_theme_hook("rc_exit", "post", RC_LEVEL_SYSINIT);
803 splash_theme_hook("rc_init", "pre", name);
804 splash_theme_hook("rc_init", "post", name);
805 break;
807 case RC_HOOK_RUNLEVEL_START_OUT:
808 /* Stop the splash daemon after boot-up is finished. */
809 if (strcmp(name, bootlevel)) {
810 config->verbosity = FBSPL_VERB_QUIET;
811 i = fbsplash_check_daemon(&pid_daemon);
812 config->verbosity = FBSPL_VERB_NORMAL;
813 if (i) {
814 retval = -1;
815 goto exit;
818 /* Make sure the progress indicator reaches 100%, even if
819 * something went wrong along the way. */
820 fbsplash_send("progress %d\n", FBSPL_PROGRESS_MAX);
821 fbsplash_send("paint\n");
822 splash_theme_hook("rc_exit", "pre", name);
823 i = splash_stop(name);
824 splash_theme_hook("rc_exit", "post", name);
825 fbsplash_lib_cleanup();
826 config = NULL;
828 break;
830 case RC_HOOK_SERVICE_START_NOW:
831 do_start:
832 /* If we've been inactive, do nothing since the service has
833 * already been handled before it went inactive. */
834 if (rc_service_state(name) & RC_SERVICE_WASINACTIVE)
835 goto exit;
837 /* If we're starting or stopping a service, we're being called by
838 * runscript and thus have to reload our config. */
839 if (splash_init(true)) {
840 retval = -1;
841 goto exit;
843 i = splash_svc_handle(name, "svc_start", skip);
844 break;
846 case RC_HOOK_SERVICE_START_OUT:
847 /* If a service gets scheduled, we want to increment the progress
848 * bar (as it is no longer blocking boot completion). However,
849 * the service may actually start during boot (some time after
850 * being scheduled), so we don't want to increment the progress
851 * bar twice. The following if clause satisfies this by catching
852 * the first case but not the second. */
853 if ((rc_service_state(name) & RC_SERVICE_SCHEDULED) &&
854 !(rc_service_state(name) & RC_SERVICE_STARTING)) {
855 skip = true;
856 goto do_start;
858 break;
860 case RC_HOOK_SERVICE_START_DONE:
861 config->verbosity = FBSPL_VERB_QUIET;
862 i = fbsplash_check_daemon(&pid_daemon);
863 config->verbosity = FBSPL_VERB_NORMAL;
864 if (i) {
865 retval = -1;
866 goto exit;
869 if (!(rc_service_state(name) & RC_SERVICE_FAILED) &&
870 !(rc_service_state(name) & RC_SERVICE_STOPPED)) {
871 bool gpm = false;
873 if (!strcmp(name, "gpm")) {
874 struct stat st;
875 int cnt = 0;
876 gpm = true;
877 /* Wait up to 0.25s for the GPM socket to appear. */
878 while (stat("/dev/gpmctl", &st) == 0 && cnt < 25) {
879 usleep(10000);
880 cnt++;
882 fbsplash_send("set gpm\n");
885 i = splash_svc_state(name, "svc_started", 1);
887 if (gpm) {
888 fbsplash_send("repaint\n");
890 } else {
891 i = splash_svc_state(name, "svc_start_failed", 1);
892 if (config->vonerr) {
893 fbsplash_set_verbose(0);
896 fbsplash_lib_cleanup();
897 config = NULL;
898 break;
900 case RC_HOOK_SERVICE_STOP_NOW:
901 if (splash_init(false)) {
902 retval = -1;
903 goto exit;
906 /* We need to stop localmount from unmounting our cache dir.
907 Luckily plugins can add to the unmount list. */
908 if (name && !strcmp(name, "localmount")) {
909 char *umounts = getenv("RC_NO_UMOUNTS");
911 if (umounts)
912 fprintf(rc_environ_fd, "RC_NO_UMOUNTS=%s:%s", umounts, FBSPLASH_CACHEDIR);
913 else
914 fprintf(rc_environ_fd, "RC_NO_UMOUNTS=%s", FBSPLASH_CACHEDIR);
916 i = splash_svc_handle(name, "svc_stop", false);
917 break;
919 case RC_HOOK_SERVICE_STOP_DONE:
920 config->verbosity = FBSPL_VERB_QUIET;
921 i = fbsplash_check_daemon(&pid_daemon);
922 config->verbosity = FBSPL_VERB_NORMAL;
923 if (i) {
924 retval = -1;
925 goto exit;
928 if (rc_service_state(name) & RC_SERVICE_STOPPED) {
929 i = splash_svc_state(name, "svc_stopped", 1);
930 } else {
931 i = splash_svc_state(name, "svc_stop_failed", 1);
932 if (config->vonerr) {
933 fbsplash_set_verbose(0);
936 fbsplash_lib_cleanup();
937 config = NULL;
938 break;
940 case RC_HOOK_ABORT:
941 i = splash_stop(name);
942 fbsplash_lib_cleanup();
943 config = NULL;
944 break;
946 default:
947 break;
950 exit:
951 rc_stringlist_free(svcs);
952 free (runlev);
953 return i;