/* * kernel/power/tuxonice_ui.c * * Copyright (C) 1998-2001 Gabor Kuti * Copyright (C) 1998,2001,2002 Pavel Machek * Copyright (C) 2002-2003 Florent Chabaud * Copyright (C) 2002-2014 Nigel Cunningham (nigel at tuxonice net) * * This file is released under the GPLv2. * * Routines for TuxOnIce's user interface. * * The user interface code talks to a userspace program via a * netlink socket. * * The kernel side: * - starts the userui program; * - sends text messages and progress bar status; * * The user space side: * - passes messages regarding user requests (abort, toggle reboot etc) * */ #define __KERNEL_SYSCALLS__ #include #include "tuxonice_sysfs.h" #include "tuxonice_modules.h" #include "tuxonice.h" #include "tuxonice_ui.h" #include "tuxonice_netlink.h" #include "tuxonice_power_off.h" #include "tuxonice_builtin.h" static char local_printf_buf[1024]; /* Same as printk - should be safe */ struct ui_ops *toi_current_ui; EXPORT_SYMBOL_GPL(toi_current_ui); /** * toi_wait_for_keypress - Wait for keypress via userui or /dev/console. * * @timeout: Maximum time to wait. * * Wait for a keypress, either from userui or /dev/console if userui isn't * available. The non-userui path is particularly for at boot-time, prior * to userui being started, when we have an important warning to give to * the user. */ #if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE) static char toi_wait_for_keypress(int timeout) { if (toi_current_ui && toi_current_ui->wait_for_key(timeout)) return ' '; return toi_wait_for_keypress_dev_console(timeout); } #endif /* toi_early_boot_message() * Description: Handle errors early in the process of booting. * The user may press C to continue booting, perhaps * invalidating the image, or space to reboot. * This works from either the serial console or normally * attached keyboard. * * Note that we come in here from init, while the kernel is * locked. If we want to get events from the serial console, * we need to temporarily unlock the kernel. * * toi_early_boot_message may also be called post-boot. * In this case, it simply printks the message and returns. * * Arguments: int Whether we are able to erase the image. * int default_answer. What to do when we timeout. This * will normally be continue, but the user might * provide command line options (__setup) to override * particular cases. * Char *. Pointer to a string explaining why we're moaning. */ #define say(message, a...) pr_err(message, ##a) void toi_early_boot_message(int message_detail, int default_answer, char *warning_reason, ...) { unsigned long orig_state = get_toi_state(), continue_req = 0; #if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE) unsigned long orig_loglevel = console_loglevel; int can_ask = 1; #else int can_ask = 0; #endif va_list args; int printed_len; if (!toi_wait) { set_toi_state(TOI_CONTINUE_REQ); can_ask = 0; } if (warning_reason) { va_start(args, warning_reason); printed_len = vsnprintf(local_printf_buf, sizeof(local_printf_buf), warning_reason, args); va_end(args); } if (!test_toi_state(TOI_BOOT_TIME)) { pr_warn("TuxOnIce: %s\n", local_printf_buf); return; } if (!can_ask) { continue_req = !!default_answer; goto post_ask; } #if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE) console_loglevel = 7; say("=== TuxOnIce ==="); if (warning_reason) { say("BIG FAT WARNING!! %s", local_printf_buf); switch (message_detail) { case 0: say("If you continue booting, note that any image WILL NOT BE REMOVED") /* TuxOnIce is unable to do so because the appropriate modules aren't loaded. * You should manually remove the image to avoid any possibility of corrupting * your filesystem(s) later. */ break; case 1: say("If you want to use current TuxOnIce image, reboot again with the same kernel"); /* If you want to forget that image, continue and the image will be erased. */ break; } say("Press SPACE to reboot or C to continue booting with " "this kernel\n"); if (toi_wait > 0) say("Default action if you don't select one in %d seconds is: %s.\n", toi_wait, default_answer == TOI_CONTINUE_REQ ? "continue booting" : "reboot"); } else { say("BIG FAT WARNING!!"); /* You have tried to resume from this image before. * If it failed once, it may well fail again. * Would you like to remove the image and boot normally? * This will be equivalent to entering noresume on the kernel command line. */ say("Press SPACE to remove the image or C to continue " "resuming.\n\n"); if (toi_wait > 0) say("Default action if you don't select one in %d seconds is: %s.\n", toi_wait, !!default_answer ? "continue resuming" : "remove the image"); } console_loglevel = orig_loglevel; set_toi_state(TOI_SANITY_CHECK_PROMPT); clear_toi_state(TOI_CONTINUE_REQ); if (toi_wait_for_keypress(toi_wait) == 0) /* We timed out */ continue_req = !!default_answer; else continue_req = test_toi_state(TOI_CONTINUE_REQ); #endif /* CONFIG_VT or CONFIG_SERIAL_CONSOLE */ post_ask: if ((warning_reason) && (!continue_req)) kernel_restart(NULL); restore_toi_state(orig_state); if (continue_req) set_toi_state(TOI_CONTINUE_REQ); } EXPORT_SYMBOL_GPL(toi_early_boot_message); #undef say /* * User interface specific /sys/power/tuxonice entries. */ static struct toi_sysfs_data sysfs_params[] = { #if defined(CONFIG_NET) && defined(CONFIG_SYSFS) SYSFS_INT("default_console_level", SYSFS_RW, &toi_bkd.toi_default_console_level, 0, 7, 0, NULL), SYSFS_UL("debug_sections", SYSFS_RW, &toi_bkd.toi_debug_state, 0, 1 << 30, 0), SYSFS_BIT("log_everything", SYSFS_RW, &toi_bkd.toi_action, TOI_LOGALL, 0) #endif }; static struct toi_module_ops userui_ops = { .type = MISC_HIDDEN_MODULE, .name = "printk ui", .directory = "user_interface", .module = THIS_MODULE, .sysfs_data = sysfs_params, .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct toi_sysfs_data), }; int toi_register_ui_ops(struct ui_ops *this_ui) { if (toi_current_ui) { pr_warn("Only one TuxOnIce user interface module can be loaded at a time."); return -EBUSY; } toi_current_ui = this_ui; return 0; } EXPORT_SYMBOL_GPL(toi_register_ui_ops); void toi_remove_ui_ops(struct ui_ops *this_ui) { if (toi_current_ui != this_ui) return; toi_current_ui = NULL; } EXPORT_SYMBOL_GPL(toi_remove_ui_ops); /* toi_console_sysfs_init * Description: Boot time initialisation for user interface. */ int toi_ui_init(void) { return toi_register_module(&userui_ops); } void toi_ui_exit(void) { toi_unregister_module(&userui_ops); }