vserver 1.9.5.x5
[linux-2.6.git] / drivers / char / sysrq.c
1 /* -*- linux-c -*-
2  *
3  *      $Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $
4  *
5  *      Linux Magic System Request Key Hacks
6  *
7  *      (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
8  *      based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
9  *
10  *      (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
11  *      overhauled to use key registration
12  *      based upon discusions in irc://irc.openprojects.net/#kernelnewbies
13  */
14
15 #include <linux/config.h>
16 #include <linux/sched.h>
17 #include <linux/interrupt.h>
18 #include <linux/mm.h>
19 #include <linux/fs.h>
20 #include <linux/tty.h>
21 #include <linux/mount.h>
22 #include <linux/kdev_t.h>
23 #include <linux/major.h>
24 #include <linux/reboot.h>
25 #include <linux/sysrq.h>
26 #include <linux/kbd_kern.h>
27 #include <linux/quotaops.h>
28 #include <linux/smp_lock.h>
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/suspend.h>
32 #include <linux/writeback.h>
33 #include <linux/buffer_head.h>          /* for fsync_bdev() */
34
35 #include <linux/spinlock.h>
36
37 #include <asm/ptrace.h>
38
39 extern void reset_vc(unsigned int);
40
41 /* Whether we react on sysrq keys or just ignore them */
42 int sysrq_enabled = 1;
43
44 /* Machine specific power off function */
45 void (*sysrq_power_off)(void);
46
47 /* Loglevel sysrq handler */
48 static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
49                                   struct tty_struct *tty) 
50 {
51         int i;
52         i = key - '0';
53         console_loglevel = 7;
54         printk("Loglevel set to %d\n", i);
55         console_loglevel = i;
56 }       
57 static struct sysrq_key_op sysrq_loglevel_op = {
58         .handler        = sysrq_handle_loglevel,
59         .help_msg       = "loglevel0-8",
60         .action_msg     = "Changing Loglevel",
61 };
62
63
64 /* SAK sysrq handler */
65 #ifdef CONFIG_VT
66 static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
67                              struct tty_struct *tty) 
68 {
69         if (tty)
70                 do_SAK(tty);
71         reset_vc(fg_console);
72 }
73 static struct sysrq_key_op sysrq_SAK_op = {
74         .handler        = sysrq_handle_SAK,
75         .help_msg       = "saK",
76         .action_msg     = "SAK",
77 };
78 #endif
79
80 #ifdef CONFIG_VT
81 /* unraw sysrq handler */
82 static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
83                                struct tty_struct *tty) 
84 {
85         struct kbd_struct *kbd = &kbd_table[fg_console];
86
87         if (kbd)
88                 kbd->kbdmode = VC_XLATE;
89 }
90 static struct sysrq_key_op sysrq_unraw_op = {
91         .handler        = sysrq_handle_unraw,
92         .help_msg       = "unRaw",
93         .action_msg     = "Keyboard mode set to XLATE",
94 };
95 #endif /* CONFIG_VT */
96
97 /* reboot sysrq handler */
98 static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
99                                 struct tty_struct *tty) 
100 {
101         local_irq_enable();
102         machine_restart(NULL);
103 }
104
105 static struct sysrq_key_op sysrq_reboot_op = {
106         .handler        = sysrq_handle_reboot,
107         .help_msg       = "reBoot",
108         .action_msg     = "Resetting",
109 };
110
111 static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
112                               struct tty_struct *tty) 
113 {
114         emergency_sync();
115 }
116
117 static struct sysrq_key_op sysrq_sync_op = {
118         .handler        = sysrq_handle_sync,
119         .help_msg       = "Sync",
120         .action_msg     = "Emergency Sync",
121 };
122
123 static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
124                                  struct tty_struct *tty) 
125 {
126         emergency_remount();
127 }
128
129 static struct sysrq_key_op sysrq_mountro_op = {
130         .handler        = sysrq_handle_mountro,
131         .help_msg       = "Unmount",
132         .action_msg     = "Emergency Remount R/O",
133 };
134
135 /* END SYNC SYSRQ HANDLERS BLOCK */
136
137
138 /* SHOW SYSRQ HANDLERS BLOCK */
139
140 static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
141                                   struct tty_struct *tty) 
142 {
143         if (pt_regs)
144                 show_regs(pt_regs);
145 }
146 static struct sysrq_key_op sysrq_showregs_op = {
147         .handler        = sysrq_handle_showregs,
148         .help_msg       = "showPc",
149         .action_msg     = "Show Regs",
150 };
151
152
153 static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
154                                    struct tty_struct *tty) 
155 {
156         show_state();
157 }
158 static struct sysrq_key_op sysrq_showstate_op = {
159         .handler        = sysrq_handle_showstate,
160         .help_msg       = "showTasks",
161         .action_msg     = "Show State",
162 };
163
164
165 static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
166                                  struct tty_struct *tty) 
167 {
168         show_mem();
169 }
170 static struct sysrq_key_op sysrq_showmem_op = {
171         .handler        = sysrq_handle_showmem,
172         .help_msg       = "showMem",
173         .action_msg     = "Show Memory",
174 };
175
176 /* SHOW SYSRQ HANDLERS BLOCK */
177
178
179 /* SIGNAL SYSRQ HANDLERS BLOCK */
180
181 /* signal sysrq helper function
182  * Sends a signal to all user processes */
183 static void send_sig_all(int sig)
184 {
185         struct task_struct *p;
186
187         for_each_process(p) {
188                 if (p->mm && p->pid != 1)
189                         /* Not swapper, init nor kernel thread */
190                         force_sig(sig, p);
191         }
192 }
193
194 static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
195                               struct tty_struct *tty) 
196 {
197         send_sig_all(SIGTERM);
198         console_loglevel = 8;
199 }
200 static struct sysrq_key_op sysrq_term_op = {
201         .handler        = sysrq_handle_term,
202         .help_msg       = "tErm",
203         .action_msg     = "Terminate All Tasks",
204 };
205
206 static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
207                               struct tty_struct *tty) 
208 {
209         send_sig_all(SIGKILL);
210         console_loglevel = 8;
211 }
212 static struct sysrq_key_op sysrq_kill_op = {
213         .handler        = sysrq_handle_kill,
214         .help_msg       = "kIll",
215         .action_msg     = "Kill All Tasks",
216 };
217
218 /* END SIGNAL SYSRQ HANDLERS BLOCK */
219
220 static void sysrq_handle_unrt(int key, struct pt_regs *pt_regs,
221                                 struct tty_struct *tty)
222 {
223         normalize_rt_tasks();
224 }
225 static struct sysrq_key_op sysrq_unrt_op = {
226         .handler        = sysrq_handle_unrt,
227         .help_msg       = "Nice",
228         .action_msg     = "Nice All RT Tasks"
229 };
230
231 /* Key Operations table and lock */
232 static DEFINE_SPINLOCK(sysrq_key_table_lock);
233 #define SYSRQ_KEY_TABLE_LENGTH 36
234 static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
235 /* 0 */ &sysrq_loglevel_op,
236 /* 1 */ &sysrq_loglevel_op,
237 /* 2 */ &sysrq_loglevel_op,
238 /* 3 */ &sysrq_loglevel_op,
239 /* 4 */ &sysrq_loglevel_op,
240 /* 5 */ &sysrq_loglevel_op,
241 /* 6 */ &sysrq_loglevel_op,
242 /* 7 */ &sysrq_loglevel_op,
243 /* 8 */ &sysrq_loglevel_op,
244 /* 9 */ &sysrq_loglevel_op,
245 /* a */ NULL, /* Don't use for system provided sysrqs,
246                  it is handled specially on the sparc
247                  and will never arrive */
248 /* b */ &sysrq_reboot_op,
249 /* c */ NULL,
250 /* d */ NULL,
251 /* e */ &sysrq_term_op,
252 /* f */ NULL,
253 /* g */ NULL,
254 /* h */ NULL,
255 /* i */ &sysrq_kill_op,
256 /* j */ NULL,
257 #ifdef CONFIG_VT
258 /* k */ &sysrq_SAK_op,
259 #else
260 /* k */ NULL,
261 #endif
262 /* l */ NULL,
263 /* m */ &sysrq_showmem_op,
264 /* n */ &sysrq_unrt_op,
265 /* o */ NULL, /* This will often be registered
266                  as 'Off' at init time */
267 /* p */ &sysrq_showregs_op,
268 /* q */ NULL,
269 #ifdef CONFIG_VT
270 /* r */ &sysrq_unraw_op,
271 #else
272 /* r */ NULL,
273 #endif
274 /* s */ &sysrq_sync_op,
275 /* t */ &sysrq_showstate_op,
276 /* u */ &sysrq_mountro_op,
277 /* v */ NULL, /* May be assigned at init time by SMP VOYAGER */
278 /* w */ NULL,
279 /* x */ NULL,
280 /* y */ NULL,
281 /* z */ NULL
282 };
283
284 /* key2index calculation, -1 on invalid index */
285 static int sysrq_key_table_key2index(int key) {
286         int retval;
287         if ((key >= '0') && (key <= '9')) {
288                 retval = key - '0';
289         } else if ((key >= 'a') && (key <= 'z')) {
290                 retval = key + 10 - 'a';
291         } else {
292                 retval = -1;
293         }
294         return retval;
295 }
296
297 /*
298  * get and put functions for the table, exposed to modules.
299  */
300
301 struct sysrq_key_op *__sysrq_get_key_op (int key) {
302         struct sysrq_key_op *op_p;
303         int i;
304         
305         i = sysrq_key_table_key2index(key);
306         op_p = (i == -1) ? NULL : sysrq_key_table[i];
307         return op_p;
308 }
309
310 void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
311         int i;
312
313         i = sysrq_key_table_key2index(key);
314         if (i != -1)
315                 sysrq_key_table[i] = op_p;
316 }
317
318 /*
319  * This is the non-locking version of handle_sysrq
320  * It must/can only be called by sysrq key handlers,
321  * as they are inside of the lock
322  */
323
324 void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
325 {
326         struct sysrq_key_op *op_p;
327         int orig_log_level;
328         int i, j;
329         unsigned long flags;
330
331         spin_lock_irqsave(&sysrq_key_table_lock, flags);
332         orig_log_level = console_loglevel;
333         console_loglevel = 7;
334         printk(KERN_INFO "SysRq : ");
335
336         op_p = __sysrq_get_key_op(key);
337         if (op_p) {
338                 printk ("%s\n", op_p->action_msg);
339                 console_loglevel = orig_log_level;
340                 op_p->handler(key, pt_regs, tty);
341         } else {
342                 printk("HELP : ");
343                 /* Only print the help msg once per handler */
344                 for (i=0; i<SYSRQ_KEY_TABLE_LENGTH; i++) 
345                 if (sysrq_key_table[i]) {
346                         for (j=0; sysrq_key_table[i] != sysrq_key_table[j]; j++);
347                         if (j == i)
348                                 printk ("%s ", sysrq_key_table[i]->help_msg);
349                 }
350                 printk ("\n");
351                 console_loglevel = orig_log_level;
352         }
353         spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
354 }
355
356 /*
357  * This function is called by the keyboard handler when SysRq is pressed
358  * and any other keycode arrives.
359  */
360
361 void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
362 {
363         if (!sysrq_enabled)
364                 return;
365         __handle_sysrq(key, pt_regs, tty);
366 }
367
368 int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
369                                 struct sysrq_key_op *remove_op_p) {
370
371         int retval;
372         unsigned long flags;
373
374         spin_lock_irqsave(&sysrq_key_table_lock, flags);
375         if (__sysrq_get_key_op(key) == remove_op_p) {
376                 __sysrq_put_key_op(key, insert_op_p);
377                 retval = 0;
378         } else {
379                 retval = -1;
380         }
381         spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
382
383         return retval;
384 }
385
386 int register_sysrq_key(int key, struct sysrq_key_op *op_p)
387 {
388         return __sysrq_swap_key_ops(key, op_p, NULL);
389 }
390
391 int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
392 {
393         return __sysrq_swap_key_ops(key, NULL, op_p);
394 }
395
396 EXPORT_SYMBOL(handle_sysrq);
397 EXPORT_SYMBOL(register_sysrq_key);
398 EXPORT_SYMBOL(unregister_sysrq_key);