blob: ab4c0d00a94dbf62fa32ef5860298c76283bbc65 [file] [log] [blame]
/*
* splash.c
*
* Bootsplash integration into the suspend and resume tools
*
* Copyright (C) 2006 Holger Macht <holger@homac.de>
*
* This file is released under the GPLv2.
*
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <limits.h>
#include <dirent.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "splash.h"
#include "bootsplash.h"
#include "splashy_funcs.h"
#include "fbsplash_funcs.h"
#include "encrypt.h"
#define INPUT_PATH "/dev/input/by-path"
#define MAX_INPUT_FD 8
static struct {
int fds[MAX_INPUT_FD];
int count;
int highest;
} input_fds;
struct splash splash;
/**
* dummy functions in case if no splash system was found or
* bootsplashing is disabled
*/
static int splash_dummy_int_void(void) { return 0; }
static int splash_dummy_int_int(int p) { return 0; }
static void splash_dummy_void_void(void) { return; }
static void splash_dummy_set_caption(const char *message) { return; }
#ifndef CONFIG_ENCRYPT
static void splash_dummy_readpass(char *a, int b) { }
#endif
static int splash_dialog(const char *prompt)
{
printf(prompt);
return getchar();
}
static int prepare_abort(struct termios *oldtrm, struct termios *newtrm)
{
int ret;
ret = tcgetattr(0, oldtrm);
if (!ret) {
*newtrm = *oldtrm;
newtrm->c_cc[VMIN] = 0;
newtrm->c_cc[VTIME] = 0;
newtrm->c_iflag = IGNBRK | IGNPAR | ICRNL | IMAXBEL;
newtrm->c_lflag = 0;
ret = tcsetattr(0, TCSANOW, newtrm);
}
return ret;
}
static char simple_key_pressed(void)
{
char c;
if (read(0, &c, 1) == 0)
return 0;
switch (c) {
case 127:
return KEY_BACKSPACE;
case 'r':
return KEY_R;
case '\n':
return KEY_ENTER;
}
return 0;
}
static char key_pressed(void)
{
int err, i, active;
struct input_event ev;
struct timeval timeout = {0, 0};
fd_set fds;
if (!input_fds.count)
return 0;
active = -1; /* GCC STFU */
FD_ZERO(&fds);
for (i = 0; i < input_fds.count; i++)
FD_SET(input_fds.fds[i], &fds);
err = select(input_fds.highest + 1, &fds, NULL, NULL, &timeout);
if (err <= 0) {
if (err < 0)
perror("select() failed");
return 0;
}
/* Get only the fist active fd */
for (i = 0; i < input_fds.count; i++) {
if (FD_ISSET(input_fds.fds[i], &fds)) {
active = input_fds.fds[i];
break;
}
}
while ((err = read(active, &ev, sizeof(ev))) != -1) {
/* we only need key release events */
if (ev.type == EV_KEY && ev.value == 0)
return ev.code;
}
return 0;
}
static void restore_abort(struct termios *oldtrm)
{
tcsetattr(0, TCSANOW, oldtrm);
}
static int open_input_fd(void)
{
int fd, i;
struct dirent *it;
DIR *dir;
char input_dev[PATH_MAX];
int err = 0;
if (!(dir = opendir(INPUT_PATH))) {
perror("Cannot open input directory");
return -EIO;
}
i = 0;
errno = 0;
while ((it = readdir(dir))) {
if (i >= MAX_INPUT_FD)
break;
if (!strstr(it->d_name, "-event-kbd"))
continue;
snprintf(input_dev, PATH_MAX, "%s/%s", INPUT_PATH, it->d_name);
fd = open(input_dev, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror("Unable to open input fd");
continue;
}
input_fds.fds[i++] = fd;
input_fds.count++;
if (fd > input_fds.highest)
input_fds.highest = fd;
}
if (!it && errno) {
perror("readdir() failed");
err = -errno;
}
closedir(dir);
if (err)
fprintf(stderr, "Could not open keyboard input device\n");
return err;
}
/* Tries to find a splash system and initializes interface functions */
void splash_prepare(struct splash *splash, int mode)
{
splash->finish = splash_dummy_int_void;
splash->progress = splash_dummy_int_int;
splash->switch_to = splash_dummy_void_void;
splash->dialog = splash_dialog;
#ifdef CONFIG_ENCRYPT
splash->read_password = read_password;
#else
splash->read_password = splash_dummy_readpass;
#endif
splash->prepare_abort = prepare_abort;
splash->restore_abort = restore_abort;
splash->key_pressed = simple_key_pressed;
splash->set_caption = splash_dummy_set_caption;
if (!mode)
return;
printf("Looking for splash system... ");
if (!bootsplash_open()) {
splash->finish = bootsplash_finish;
splash->progress = bootsplash_progress;
splash->switch_to = bootsplash_switch_to;
splash->dialog = bootsplash_dialog;
splash->read_password = bootsplash_read_password;
if (!open_input_fd())
splash->key_pressed = key_pressed;
#ifdef CONFIG_FBSPLASH
} else if (!fbsplashfuncs_open(mode)) {
splash->finish = fbsplashfuncs_finish;
splash->progress = fbsplashfuncs_progress;
splash->dialog = fbsplashfuncs_dialog;
splash->read_password = fbsplashfuncs_read_password;
splash->key_pressed = fbsplashfuncs_key_pressed;
splash->set_caption = fbsplashfuncs_set_caption;
#endif
#ifdef CONFIG_SPLASHY
} else if (!splashy_open(mode)) {
splash->finish = splashy_finish;
splash->progress = splashy_progress;
splash->dialog = splashy_dialog;
splash->read_password = splashy_read_password;
if (!open_input_fd())
splash->key_pressed = key_pressed;
#endif
} else if (0) {
/* add another splash system here */
} else {
printf("none\n");
if (!open_input_fd())
splash->key_pressed = key_pressed;
return;
}
printf("found\n");
splash->progress(0);
}