patch-2_6_7-vs1_9_1_12
[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         machine_restart(NULL);
102 }
103
104 static struct sysrq_key_op sysrq_reboot_op = {
105         .handler        = sysrq_handle_reboot,
106         .help_msg       = "reBoot",
107         .action_msg     = "Resetting",
108 };
109
110 static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
111                               struct tty_struct *tty) 
112 {
113         emergency_sync();
114 }
115
116 static struct sysrq_key_op sysrq_sync_op = {
117         .handler        = sysrq_handle_sync,
118         .help_msg       = "Sync",
119         .action_msg     = "Emergency Sync",
120 };
121
122 static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
123                                  struct tty_struct *tty) 
124 {
125         emergency_remount();
126 }
127
128 static struct sysrq_key_op sysrq_mountro_op = {
129         .handler        = sysrq_handle_mountro,
130         .help_msg       = "Unmount",
131         .action_msg     = "Emergency Remount R/O",
132 };
133
134 /* END SYNC SYSRQ HANDLERS BLOCK */
135
136
137 /* SHOW SYSRQ HANDLERS BLOCK */
138
139 static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
140                                   struct tty_struct *tty) 
141 {
142         if (pt_regs)
143                 show_regs(pt_regs);
144 }
145 static struct sysrq_key_op sysrq_showregs_op = {
146         .handler        = sysrq_handle_showregs,
147         .help_msg       = "showPc",
148         .action_msg     = "Show Regs",
149 };
150
151
152 static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
153                                    struct tty_struct *tty) 
154 {
155         show_state();
156 }
157 static struct sysrq_key_op sysrq_showstate_op = {
158         .handler        = sysrq_handle_showstate,
159         .help_msg       = "showTasks",
160         .action_msg     = "Show State",
161 };
162
163
164 static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
165                                  struct tty_struct *tty) 
166 {
167         show_mem();
168 }
169 static struct sysrq_key_op sysrq_showmem_op = {
170         .handler        = sysrq_handle_showmem,
171         .help_msg       = "showMem",
172         .action_msg     = "Show Memory",
173 };
174
175 /* SHOW SYSRQ HANDLERS BLOCK */
176
177
178 /* SIGNAL SYSRQ HANDLERS BLOCK */
179
180 /* signal sysrq helper function
181  * Sends a signal to all user processes */
182 static void send_sig_all(int sig)
183 {
184         struct task_struct *p;
185
186         for_each_process(p) {
187                 if (p->mm && p->pid != 1)
188                         /* Not swapper, init nor kernel thread */
189                         force_sig(sig, p);
190         }
191 }
192
193 static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
194                               struct tty_struct *tty) 
195 {
196         send_sig_all(SIGTERM);
197         console_loglevel = 8;
198 }
199 static struct sysrq_key_op sysrq_term_op = {
200         .handler        = sysrq_handle_term,
201         .help_msg       = "tErm",
202         .action_msg     = "Terminate All Tasks",
203 };
204
205 static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
206                               struct tty_struct *tty) 
207 {
208         send_sig_all(SIGKILL);
209         console_loglevel = 8;
210 }
211 static struct sysrq_key_op sysrq_kill_op = {
212         .handler        = sysrq_handle_kill,
213         .help_msg       = "kIll",
214         .action_msg     = "Kill All Tasks",
215 };
216
217 /* END SIGNAL SYSRQ HANDLERS BLOCK */
218
219
220 /* Key Operations table and lock */
221 static spinlock_t sysrq_key_table_lock = SPIN_LOCK_UNLOCKED;
222 #define SYSRQ_KEY_TABLE_LENGTH 36
223 static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
224 /* 0 */ &sysrq_loglevel_op,
225 /* 1 */ &sysrq_loglevel_op,
226 /* 2 */ &sysrq_loglevel_op,
227 /* 3 */ &sysrq_loglevel_op,
228 /* 4 */ &sysrq_loglevel_op,
229 /* 5 */ &sysrq_loglevel_op,
230 /* 6 */ &sysrq_loglevel_op,
231 /* 7 */ &sysrq_loglevel_op,
232 /* 8 */ &sysrq_loglevel_op,
233 /* 9 */ &sysrq_loglevel_op,
234 /* a */ NULL, /* Don't use for system provided sysrqs,
235                  it is handled specially on the sparc
236                  and will never arrive */
237 /* b */ &sysrq_reboot_op,
238 /* c */ NULL,
239 /* d */ NULL,
240 /* e */ &sysrq_term_op,
241 /* f */ NULL,
242 /* g */ NULL,
243 /* h */ NULL,
244 /* i */ &sysrq_kill_op,
245 /* j */ NULL,
246 #ifdef CONFIG_VT
247 /* k */ &sysrq_SAK_op,
248 #else
249 /* k */ NULL,
250 #endif
251 /* l */ NULL,
252 /* m */ &sysrq_showmem_op,
253 /* n */ NULL,
254 /* o */ NULL, /* This will often be registered
255                  as 'Off' at init time */
256 /* p */ &sysrq_showregs_op,
257 /* q */ NULL,
258 #ifdef CONFIG_VT
259 /* r */ &sysrq_unraw_op,
260 #else
261 /* r */ NULL,
262 #endif
263 /* s */ &sysrq_sync_op,
264 /* t */ &sysrq_showstate_op,
265 /* u */ &sysrq_mountro_op,
266 /* v */ NULL, /* May be assigned at init time by SMP VOYAGER */
267 /* w */ NULL,
268 /* x */ NULL,
269 /* y */ NULL,
270 /* z */ NULL
271 };
272
273 /* key2index calculation, -1 on invalid index */
274 static int sysrq_key_table_key2index(int key) {
275         int retval;
276         if ((key >= '0') && (key <= '9')) {
277                 retval = key - '0';
278         } else if ((key >= 'a') && (key <= 'z')) {
279                 retval = key + 10 - 'a';
280         } else {
281                 retval = -1;
282         }
283         return retval;
284 }
285
286 /*
287  * table lock and unlocking functions, exposed to modules
288  */
289
290 void __sysrq_lock_table (void) { spin_lock(&sysrq_key_table_lock); }
291
292 void __sysrq_unlock_table (void) { spin_unlock(&sysrq_key_table_lock); }
293
294 /*
295  * get and put functions for the table, exposed to modules.
296  */
297
298 struct sysrq_key_op *__sysrq_get_key_op (int key) {
299         struct sysrq_key_op *op_p;
300         int i;
301         
302         i = sysrq_key_table_key2index(key);
303         op_p = (i == -1) ? NULL : sysrq_key_table[i];
304         return op_p;
305 }
306
307 void __sysrq_put_key_op (int key, struct sysrq_key_op *op_p) {
308         int i;
309
310         i = sysrq_key_table_key2index(key);
311         if (i != -1)
312                 sysrq_key_table[i] = op_p;
313 }
314
315 /*
316  * This is the non-locking version of handle_sysrq
317  * It must/can only be called by sysrq key handlers,
318  * as they are inside of the lock
319  */
320
321 void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
322 {
323         struct sysrq_key_op *op_p;
324         int orig_log_level;
325         int i, j;
326
327         __sysrq_lock_table();
328         orig_log_level = console_loglevel;
329         console_loglevel = 7;
330         printk(KERN_INFO "SysRq : ");
331
332         op_p = __sysrq_get_key_op(key);
333         if (op_p) {
334                 printk ("%s\n", op_p->action_msg);
335                 console_loglevel = orig_log_level;
336                 op_p->handler(key, pt_regs, tty);
337         } else {
338                 printk("HELP : ");
339                 /* Only print the help msg once per handler */
340                 for (i=0; i<SYSRQ_KEY_TABLE_LENGTH; i++) 
341                 if (sysrq_key_table[i]) {
342                         for (j=0; sysrq_key_table[i] != sysrq_key_table[j]; j++);
343                         if (j == i)
344                                 printk ("%s ", sysrq_key_table[i]->help_msg);
345                 }
346                 printk ("\n");
347                 console_loglevel = orig_log_level;
348         }
349         __sysrq_unlock_table();
350 }
351
352 /*
353  * This function is called by the keyboard handler when SysRq is pressed
354  * and any other keycode arrives.
355  */
356
357 void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
358 {
359         if (!sysrq_enabled)
360                 return;
361         __handle_sysrq(key, pt_regs, tty);
362 }
363
364 EXPORT_SYMBOL(handle_sysrq);
365 EXPORT_SYMBOL(__sysrq_lock_table);
366 EXPORT_SYMBOL(__sysrq_unlock_table);
367 EXPORT_SYMBOL(__sysrq_get_key_op);
368 EXPORT_SYMBOL(__sysrq_put_key_op);