Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | /* |
2 | * kernel/power/tuxonice_ui.c | |
3 | * | |
4 | * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu> | |
5 | * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz> | |
6 | * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr> | |
7 | * Copyright (C) 2002-2010 Nigel Cunningham (nigel at tuxonice net) | |
8 | * | |
9 | * This file is released under the GPLv2. | |
10 | * | |
11 | * Routines for TuxOnIce's user interface. | |
12 | * | |
13 | * The user interface code talks to a userspace program via a | |
14 | * netlink socket. | |
15 | * | |
16 | * The kernel side: | |
17 | * - starts the userui program; | |
18 | * - sends text messages and progress bar status; | |
19 | * | |
20 | * The user space side: | |
21 | * - passes messages regarding user requests (abort, toggle reboot etc) | |
22 | * | |
23 | */ | |
24 | ||
25 | #define __KERNEL_SYSCALLS__ | |
26 | ||
27 | #include <linux/reboot.h> | |
28 | ||
29 | #include "tuxonice_sysfs.h" | |
30 | #include "tuxonice_modules.h" | |
31 | #include "tuxonice.h" | |
32 | #include "tuxonice_ui.h" | |
33 | #include "tuxonice_netlink.h" | |
34 | #include "tuxonice_power_off.h" | |
35 | #include "tuxonice_builtin.h" | |
36 | ||
37 | static char local_printf_buf[1024]; /* Same as printk - should be safe */ | |
38 | struct ui_ops *toi_current_ui; | |
39 | EXPORT_SYMBOL_GPL(toi_current_ui); | |
40 | ||
41 | /** | |
42 | * toi_wait_for_keypress - Wait for keypress via userui or /dev/console. | |
43 | * | |
44 | * @timeout: Maximum time to wait. | |
45 | * | |
46 | * Wait for a keypress, either from userui or /dev/console if userui isn't | |
47 | * available. The non-userui path is particularly for at boot-time, prior | |
48 | * to userui being started, when we have an important warning to give to | |
49 | * the user. | |
50 | */ | |
51 | #if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE) | |
52 | static char toi_wait_for_keypress(int timeout) | |
53 | { | |
54 | if (toi_current_ui && toi_current_ui->wait_for_key(timeout)) | |
55 | return ' '; | |
56 | ||
57 | return toi_wait_for_keypress_dev_console(timeout); | |
58 | } | |
59 | #endif | |
60 | ||
61 | /* toi_early_boot_message() | |
62 | * Description: Handle errors early in the process of booting. | |
63 | * The user may press C to continue booting, perhaps | |
64 | * invalidating the image, or space to reboot. | |
65 | * This works from either the serial console or normally | |
66 | * attached keyboard. | |
67 | * | |
68 | * Note that we come in here from init, while the kernel is | |
69 | * locked. If we want to get events from the serial console, | |
70 | * we need to temporarily unlock the kernel. | |
71 | * | |
72 | * toi_early_boot_message may also be called post-boot. | |
73 | * In this case, it simply printks the message and returns. | |
74 | * | |
75 | * Arguments: int Whether we are able to erase the image. | |
76 | * int default_answer. What to do when we timeout. This | |
77 | * will normally be continue, but the user might | |
78 | * provide command line options (__setup) to override | |
79 | * particular cases. | |
80 | * Char *. Pointer to a string explaining why we're moaning. | |
81 | */ | |
82 | ||
83 | #define say(message, a...) printk(KERN_EMERG message, ##a) | |
84 | ||
85 | void toi_early_boot_message(int message_detail, int default_answer, char *warning_reason, ...) | |
86 | { | |
87 | unsigned long orig_state = get_toi_state(), continue_req = 0; | |
88 | #if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE) | |
89 | unsigned long orig_loglevel = console_loglevel; | |
90 | int can_ask = 1; | |
91 | #else | |
92 | int can_ask = 0; | |
93 | #endif | |
94 | ||
95 | va_list args; | |
96 | int printed_len; | |
97 | ||
98 | if (!toi_wait) { | |
99 | set_toi_state(TOI_CONTINUE_REQ); | |
100 | can_ask = 0; | |
101 | } | |
102 | ||
103 | if (warning_reason) { | |
104 | va_start(args, warning_reason); | |
105 | printed_len = vsnprintf(local_printf_buf, | |
106 | sizeof(local_printf_buf), warning_reason, args); | |
107 | va_end(args); | |
108 | } | |
109 | ||
110 | if (!test_toi_state(TOI_BOOT_TIME)) { | |
111 | printk("TuxOnIce: %s\n", local_printf_buf); | |
112 | return; | |
113 | } | |
114 | ||
115 | if (!can_ask) { | |
116 | continue_req = !!default_answer; | |
117 | goto post_ask; | |
118 | } | |
119 | #if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE) | |
120 | console_loglevel = 7; | |
121 | ||
122 | say("=== TuxOnIce ===\n\n"); | |
123 | if (warning_reason) { | |
124 | say("BIG FAT WARNING!! %s\n\n", local_printf_buf); | |
125 | switch (message_detail) { | |
126 | case 0: | |
127 | say("If you continue booting, note that any image WILL" | |
128 | "NOT BE REMOVED.\nTuxOnIce is unable to do so " | |
129 | "because the appropriate modules aren't\n" | |
130 | "loaded. You should manually remove the image " | |
131 | "to avoid any\npossibility of corrupting your " | |
132 | "filesystem(s) later.\n"); | |
133 | break; | |
134 | case 1: | |
135 | say("If you want to use the current TuxOnIce image, " | |
136 | "reboot and try\nagain with the same kernel " | |
137 | "that you hibernated from. If you want\n" | |
138 | "to forget that image, continue and the image " "will be erased.\n"); | |
139 | break; | |
140 | } | |
141 | say("Press SPACE to reboot or C to continue booting with " "this kernel\n\n"); | |
142 | if (toi_wait > 0) | |
143 | say("Default action if you don't select one in %d " | |
144 | "seconds is: %s.\n", | |
145 | toi_wait, | |
146 | default_answer == TOI_CONTINUE_REQ ? "continue booting" : "reboot"); | |
147 | } else { | |
148 | say("BIG FAT WARNING!!\n\n" | |
149 | "You have tried to resume from this image before.\n" | |
150 | "If it failed once, it may well fail again.\n" | |
151 | "Would you like to remove the image and boot " | |
152 | "normally?\nThis will be equivalent to entering " | |
153 | "noresume on the\nkernel command line.\n\n" | |
154 | "Press SPACE to remove the image or C to continue " "resuming.\n\n"); | |
155 | if (toi_wait > 0) | |
156 | say("Default action if you don't select one in %d " | |
157 | "seconds is: %s.\n", toi_wait, | |
158 | !!default_answer ? "continue resuming" : "remove the image"); | |
159 | } | |
160 | console_loglevel = orig_loglevel; | |
161 | ||
162 | set_toi_state(TOI_SANITY_CHECK_PROMPT); | |
163 | clear_toi_state(TOI_CONTINUE_REQ); | |
164 | ||
165 | if (toi_wait_for_keypress(toi_wait) == 0) /* We timed out */ | |
166 | continue_req = !!default_answer; | |
167 | else | |
168 | continue_req = test_toi_state(TOI_CONTINUE_REQ); | |
169 | ||
170 | #endif /* CONFIG_VT or CONFIG_SERIAL_CONSOLE */ | |
171 | ||
172 | post_ask: | |
173 | if ((warning_reason) && (!continue_req)) | |
174 | kernel_restart(NULL); | |
175 | ||
176 | restore_toi_state(orig_state); | |
177 | if (continue_req) | |
178 | set_toi_state(TOI_CONTINUE_REQ); | |
179 | } | |
180 | EXPORT_SYMBOL_GPL(toi_early_boot_message); | |
181 | #undef say | |
182 | ||
183 | /* | |
184 | * User interface specific /sys/power/tuxonice entries. | |
185 | */ | |
186 | ||
187 | static struct toi_sysfs_data sysfs_params[] = { | |
188 | #if defined(CONFIG_NET) && defined(CONFIG_SYSFS) | |
189 | SYSFS_INT("default_console_level", SYSFS_RW, | |
190 | &toi_bkd.toi_default_console_level, 0, 7, 0, NULL), | |
191 | SYSFS_UL("debug_sections", SYSFS_RW, &toi_bkd.toi_debug_state, 0, | |
192 | 1 << 30, 0), | |
193 | SYSFS_BIT("log_everything", SYSFS_RW, &toi_bkd.toi_action, TOI_LOGALL, | |
194 | 0) | |
195 | #endif | |
196 | }; | |
197 | ||
198 | static struct toi_module_ops userui_ops = { | |
199 | .type = MISC_HIDDEN_MODULE, | |
200 | .name = "printk ui", | |
201 | .directory = "user_interface", | |
202 | .module = THIS_MODULE, | |
203 | .sysfs_data = sysfs_params, | |
204 | .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct toi_sysfs_data), | |
205 | }; | |
206 | ||
207 | int toi_register_ui_ops(struct ui_ops *this_ui) | |
208 | { | |
209 | if (toi_current_ui) { | |
210 | printk(KERN_INFO "Only one TuxOnIce user interface module can " | |
211 | "be loaded at a time."); | |
212 | return -EBUSY; | |
213 | } | |
214 | ||
215 | toi_current_ui = this_ui; | |
216 | ||
217 | return 0; | |
218 | } | |
219 | EXPORT_SYMBOL_GPL(toi_register_ui_ops); | |
220 | ||
221 | void toi_remove_ui_ops(struct ui_ops *this_ui) | |
222 | { | |
223 | if (toi_current_ui != this_ui) | |
224 | return; | |
225 | ||
226 | toi_current_ui = NULL; | |
227 | } | |
228 | EXPORT_SYMBOL_GPL(toi_remove_ui_ops); | |
229 | ||
230 | /* toi_console_sysfs_init | |
231 | * Description: Boot time initialisation for user interface. | |
232 | */ | |
233 | ||
234 | int toi_ui_init(void) | |
235 | { | |
236 | return toi_register_module(&userui_ops); | |
237 | } | |
238 | ||
239 | void toi_ui_exit(void) | |
240 | { | |
241 | toi_unregister_module(&userui_ops); | |
242 | } |