core: use a monotonic clock for animation timing calculations
[fbsplash.git] / core / src / daemon_cmd.c
blob44e049ee876d88fc1a8c5643a322fb56b4fd2ce7
1 /*
2 * daemon_cmd.c -- Code handling the daemon commands.
4 * Copyright (C) 2005-2007 Michal Januszewski <spock@gentoo.org>
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License v2. See the file COPYING in the main directory of this archive for
8 * more details.
12 #include <signal.h>
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <sys/time.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <errno.h>
22 #include "common.h"
23 #include "daemon.h"
26 * 'exit' command handler.
28 int cmd_exit(void **args)
30 item *i, *j;
32 pthread_cancel(th_switchmon);
33 pthread_mutex_lock(&mtx_paint);
35 if (ctty == CTTY_SILENT) {
36 if (config.effects & FBSPL_EFF_FADEOUT)
37 fbsplashr_render_screen(theme, true, false, FBSPL_EFF_FADEOUT);
39 if (!args[0] || strcmp(args[0], "staysilent")) {
40 /* Switch to the verbose tty if we're in silent mode when the
41 * 'exit' command is received. */
42 ioctl(fd_tty0, VT_ACTIVATE, config.tty_v);
46 pthread_mutex_unlock(&mtx_paint);
48 pthread_kill(th_sighandler, SIGINT);
49 pthread_join(th_sighandler, NULL);
51 fbsplashr_theme_free(theme);
52 fbsplashr_cleanup();
53 fbsplash_lib_cleanup();
55 for (i = svcs.head; i != NULL; ) {
56 j = i->next;
57 free(i->p);
58 free(i);
59 i = j;
62 exit(0);
64 /* We never get here */
65 return 0;
69 * 'set theme' command handler.
71 * Switches to a new theme.
73 int cmd_set_theme(void **args)
75 fbsplash_acc_theme_set(args[0]);
76 pthread_mutex_lock(&mtx_paint);
77 reload_theme();
78 pthread_mutex_unlock(&mtx_paint);
80 return 0;
84 * 'set mode' command handler.
86 * Switches the splash to verbose or silent mode.
88 int cmd_set_mode(void **args)
90 int n, i = 0;
91 struct itimerval itv;
93 if (!strcmp(args[0], "silent")) {
94 n = config.tty_s;
95 } else if (!strcmp(args[0], "verbose")) {
96 n = config.tty_v;
97 } else {
98 return -1;
101 itv.it_interval.tv_sec = 0;
102 itv.it_interval.tv_usec = 0;
103 itv.it_value.tv_sec = 0;
104 itv.it_value.tv_usec = 250000;
106 vtswitch:
107 if (ioctl(fd_tty0, VT_ACTIVATE, n) == -1) {
108 iprint(MSG_ERROR, "Switch to tty%d failed with: %d '%s'\n", n, errno, strerror(errno));
109 return -1;
113 * Interrupt the VT_WAITACTIVE call every 0.25s. This makes sure we actually
114 * return from this function in a timely manner and that we can complete the
115 * switch to silent mode even when someone does a VT_ACTIVATE before our
116 * VT_WAITACTIVE.
118 * This fixes the problem of the silent mode not being activated when
119 * rebooting directly from X.
121 i++;
122 alarm_type = ALRM_INTERRUPT;
123 setitimer(ITIMER_REAL, &itv, NULL);
125 if (ioctl(fd_tty0, VT_WAITACTIVE, n) == -1) {
126 if (i < 9 && errno == EINTR)
127 goto vtswitch;
129 iprint(MSG_ERROR, "Wait for tty%d failed with: %d '%s'\n", n, errno, strerror(errno));
130 return -1;
133 return 0;
137 * 'set gpm' command handler.
139 * Creates a GPM client for the silent tty.
141 int cmd_set_gpm(void **args)
143 #ifdef CONFIG_GPM
144 Gpm_Connect conn;
146 conn.eventMask = 0;
147 conn.defaultMask = 0;
148 conn.minMod = 0;
149 conn.maxMod = ~0;
150 pthread_mutex_lock(&mtx_tty);
151 fd_gpm = Gpm_Open(&conn, config.tty_s);
152 pthread_mutex_unlock(&mtx_tty);
153 return fd_gpm;
154 #else
155 return 0;
156 #endif
160 * 'set effects' command handler.
162 * Makes it possible to dynamically enable special effects.
164 int cmd_set_effects(void **args)
166 int i;
168 config.effects = FBSPL_EFF_NONE;
170 for (i = 0; i < 4; i++) {
171 if (!args[i])
172 break;
174 if (!strcmp(args[i], "fadein")) {
175 config.effects |= FBSPL_EFF_FADEIN;
176 } else if (!strcmp(args[i], "fadeout")) {
177 config.effects |= FBSPL_EFF_FADEOUT;
181 return 0;
185 * 'set tty' command handlers.
187 * Assigns a TTY for verbose/silent splash screen.
189 int cmd_set_tty(void **args)
191 /* Make sure the new tty setting is sane. */
192 if (*(int*)args[1] < 0 || *(int*)args[1] > MAX_NR_CONSOLES)
193 return -1;
195 if (!strcmp(args[0], "silent")) {
196 pthread_mutex_lock(&mtx_tty);
198 /* Do nothing if the new tty is the same as the old one. */
199 if (config.tty_s == *(int*)args[1]) {
200 pthread_mutex_unlock(&mtx_tty);
201 return 0;
204 pthread_cancel(th_switchmon);
206 switchmon_start(UPD_SILENT, *(int*)args[1]);
207 pthread_mutex_unlock(&mtx_tty);
208 #ifdef CONFIG_GPM
209 if (fd_gpm > 0) {
210 Gpm_Close();
211 cmd_set_gpm(NULL);
213 #endif
214 } else if (!strcmp(args[0], "verbose")) {
216 pthread_mutex_lock(&mtx_tty);
218 /* Do nothing if the new tty is the same as the old one. */
219 if (config.tty_v == *(int*)args[1]) {
220 pthread_mutex_unlock(&mtx_tty);
221 return 0;
224 config.tty_v = *(int*)args[1];
225 pthread_mutex_unlock(&mtx_tty);
226 } else {
227 return -1;
230 return 0;
234 * 'set event dev' command handler.
236 * Sets a new event device to monitor for keypresses.
238 int cmd_set_event_dev(void **args)
240 if (evdev)
241 free(evdev);
243 evdev = strdup(args[0]);
245 pthread_cancel(th_switchmon);
247 if (fd_evdev != -1)
248 close(fd_evdev);
250 fd_evdev = open(evdev, O_RDONLY);
252 switchmon_start(UPD_MON, config.tty_s);
254 return 0;
258 * 'paint' command handler.
260 * Updates the picture displayed on the screen.
262 int cmd_paint(void **args)
264 char ret = 0;
266 pthread_mutex_lock(&mtx_paint);
267 if (!theme) {
268 ret = -1;
269 goto out;
272 if (ctty != CTTY_SILENT)
273 goto out;
275 fbsplashr_render_screen(theme, false, false, FBSPL_EFF_NONE);
276 out:
277 pthread_mutex_unlock(&mtx_paint);
278 return ret;
282 * 'repaint' command handler.
284 * Repaints the whole screen.
286 int cmd_repaint(void **args)
288 char ret = 0;
290 pthread_mutex_lock(&mtx_paint);
291 if (!theme) {
292 ret = -1;
293 goto out;
296 if (ctty != CTTY_SILENT)
297 goto out;
299 if (config.effects & FBSPL_EFF_FADEIN) {
300 config.effects &= ~FBSPL_EFF_FADEIN;
301 fbsplashr_render_screen(theme, true, false, FBSPL_EFF_FADEIN);
302 } else {
303 fbsplashr_render_screen(theme, true, false, FBSPL_EFF_NONE);
305 out:
306 pthread_mutex_unlock(&mtx_paint);
308 return 0;
312 * 'progress' command handler.
314 * Updates the progress indicator. Note that this only updates
315 * an internal variable, it doesn't update the image on the screen.
317 int cmd_progress(void **args)
319 fbsplashr_progress_set(theme, *(int*)args[0]);
320 return 0;
324 * 'set message' command handler.
326 * Sets the system message. This only has any effect if the
327 * splash daemon was compiled with support for truetype fonts.
329 int cmd_set_mesg(void **args)
331 fbsplashr_message_set(theme, args[0]);
332 return 0;
336 * 'log' command handler.
338 * Appends a line of text to the fbsplash message log.
340 int cmd_log(void **args)
342 /* TODO: possibly move this to libfbsplashrender */
343 theme->log_cnt++;
345 if (theme->log_cnt <= theme->log_lines) {
346 list_add(&theme->msglog, strndup(args[0], theme->log_cols));
347 } else {
348 list_ringadd(&theme->msglog, strndup(args[0], theme->log_cols));
351 return 0;
355 * 'set autoverbose' command handler.
357 int cmd_set_autoverbose(void **args)
359 config.autoverbose = *(int*)args[0];
360 return 0;
364 * 'paint rect' command handler.
366 * Paints a rectangular part of the background buffer on thre
367 * screen.
369 int cmd_paint_rect(void **args)
371 rect re;
372 int t, ret = 0;
374 pthread_mutex_lock(&mtx_paint);
375 if (!theme) {
376 ret = -1;
377 goto out;
379 if (ctty != CTTY_SILENT)
380 goto out;
382 re.x1 = *(int*)args[0];
383 re.x2 = *(int*)args[2];
384 re.y1 = *(int*)args[1];
385 re.y2 = *(int*)args[3];
387 if (re.x1 > re.x2) {
388 t = re.x2;
389 re.x2 = re.x1;
390 re.x1 = t;
393 if (re.y1 > re.y2) {
394 t = re.y2;
395 re.y2 = re.y1;
396 re.y1 = t;
399 if (re.y1 < 0)
400 re.y1 = 0;
402 if (re.y2 < 0)
403 re.y2 = 0;
405 if (re.x1 < 0)
406 re.x1 = 0;
408 if (re.x2 < 0)
409 re.x2 = 0;
411 if (re.x1 >= theme->xres)
412 re.x1 = theme->xres-1;
414 if (re.x2 >= theme->xres)
415 re.x2 = theme->xres-1;
417 if (re.y1 >= theme->yres)
418 re.y1 = theme->yres-1;
420 if (re.y2 >= theme->yres)
421 re.y2 = theme->yres-1;
423 paint_rect(theme, fb_mem, theme->bgbuf, re.x1, re.y1, re.x2, re.y2);
424 out:
426 pthread_mutex_unlock(&mtx_paint);
427 return 0;
431 * 'update_svc' command handler.
433 * Updates status of a specific service.
435 int cmd_update_svc(void **args)
437 item *i;
438 svc_state *ss;
439 enum ESVC state;
440 struct timespec ts;
442 if (!parse_svc_state(args[1], &state))
443 return -1;
445 clock_gettime(CLOCK_MONOTONIC, &ts);
447 for (i = svcs.head ; i != NULL; i = i->next) {
448 ss = (svc_state*)i->p;
449 if (!strcmp(ss->svc, args[0]))
450 goto cus_update;
453 ss = malloc(sizeof(svc_state));
454 ss->svc = strdup(args[0]);
455 list_add(&svcs, ss);
457 cus_update:
458 ss->state = state;
460 if (ss->state == e_svc_start) {
461 ss->ts = ts;
462 } else if (ss->state == e_svc_started || ss->state == e_svc_start_failed) {
463 ss->ts.tv_sec = ts.tv_sec - ss->ts.tv_sec;
464 ss->ts.tv_nsec = ts.tv_nsec - ss->ts.tv_nsec;
466 /* Check for overflow of the nanoseconds field */
467 if (ss->ts.tv_nsec < 0) {
468 ss->ts.tv_sec--;
469 ss->ts.tv_nsec += 1000000000;
473 pthread_mutex_lock(&mtx_paint);
474 invalidate_service(theme, args[0], state);
475 pthread_mutex_lock(&mtx_anim);
476 pthread_cond_signal(&cnd_anim);
477 pthread_mutex_unlock(&mtx_anim);
478 pthread_mutex_unlock(&mtx_paint);
480 return 0;
483 int cmd_dump_svc_timings(void **args)
485 svc_state *ss;
486 item *i;
487 FILE *fp = fopen("/lib/splash/cache/svc_timings", "w");
489 if (!fp)
490 return -1;
492 for (i = svcs.head; i != NULL; i = i->next) {
493 ss = (svc_state*)i->p;
494 if (ss->svc && (ss->ts.tv_sec > 0 || ss->ts.tv_nsec > 0)) {
495 fprintf(fp, "%s: %d.%.6d\n", ss->svc, (int)ss->ts.tv_sec, (int)(ss->ts.tv_nsec/1000));
499 fclose(fp);
500 return 0;
503 cmdhandler known_cmds[] =
505 { .cmd = "set theme",
506 .handler = cmd_set_theme,
507 .args = 1,
508 .specs = "s"
511 { .cmd = "set mode",
512 .handler = cmd_set_mode,
513 .args = 1,
514 .specs = "s"
517 { .cmd = "set tty",
518 .handler = cmd_set_tty,
519 .args = 2,
520 .specs = "sd"
523 { .cmd = "set event dev",
524 .handler = cmd_set_event_dev,
525 .args = 1,
526 .specs = "s"
529 { .cmd = "set message",
530 .handler = cmd_set_mesg,
531 .args = 1,
532 .specs = "s"
535 { .cmd = "set autoverbose",
536 .handler = cmd_set_autoverbose,
537 .args = 1,
538 .specs = "d"
541 { .cmd = "set gpm",
542 .handler = cmd_set_gpm,
543 .args = 0,
544 .specs = NULL,
547 { .cmd = "set effects",
548 .handler = cmd_set_effects,
549 .args = 2,
550 .specs = "ss"
553 { .cmd = "paint rect",
554 .handler = cmd_paint_rect,
555 .args = 4,
556 .specs = "dddd"
559 { .cmd = "paint",
560 .handler = cmd_paint,
561 .args = 0,
562 .specs = NULL,
565 { .cmd = "repaint",
566 .handler = cmd_repaint,
567 .args = 0,
568 .specs = NULL,
571 { .cmd = "progress",
572 .handler = cmd_progress,
573 .args = 1,
574 .specs = "d"
577 { .cmd = "update_svc",
578 .handler = cmd_update_svc,
579 .args = 2,
580 .specs = "ss",
584 { .cmd = "dump_svc_timings",
585 .handler = cmd_dump_svc_timings,
586 .args = 0,
587 .specs = NULL,
590 { .cmd = "log",
591 .handler = cmd_log,
592 .args = 1,
593 .specs = "s",
596 { .cmd = "exit",
597 .handler = cmd_exit,
598 .args = 1,
599 .specs = "s",
604 * FIFO communication handler.
606 int daemon_comm(FILE *fp_fifo)
608 char buf[PIPE_BUF];
609 int i,j,k;
611 while (1) {
612 inner:
613 while (fgets(buf, PIPE_BUF, fp_fifo)) {
614 char *t;
615 int args_i[4];
616 void *args[4];
618 memset(&args, 0, sizeof(args));
619 buf[PIPE_BUF-1] = 0;
620 buf[strlen(buf)-1] = 0;
622 for (i = 0; i < sizeof(known_cmds)/sizeof(known_cmds[0]); i++) {
623 k = strlen(known_cmds[i].cmd);
625 if (strncmp(buf, known_cmds[i].cmd, k))
626 continue;
628 for (j = 0; j < known_cmds[i].args; j++) {
629 for (; buf[k] == ' '; buf[k] = 0, k++);
630 if (!buf[k]) {
631 args[j] = NULL;
632 continue;
635 switch (known_cmds[i].specs[j]) {
636 case 's':
637 args[j] = &(buf[k]);
638 for (; buf[k] != ' ' && buf[k]; k++);
639 break;
641 case 'd':
642 args_i[j] = strtol(&(buf[k]), &t, 0);
643 if (t == &(buf[k]))
644 goto inner;
646 args[j] = &(args_i[j]);
647 k = t - buf;
648 break;
652 known_cmds[i].handler(args);
654 /* Activate the autoverbose timer. */
655 if (config.autoverbose > 0) {
656 struct itimerval itv;
658 itv.it_interval.tv_sec = 0;
659 itv.it_interval.tv_usec = 0;
660 itv.it_value.tv_sec = config.autoverbose;
661 itv.it_value.tv_usec = 0;
663 alarm_type = ALRM_AUTOVERBOSE;
664 setitimer(ITIMER_REAL, &itv, NULL);