blob: 1488816588ea5b2f46c3638af30e5b3236a336d7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
3 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
4 * Licensed under the GPL
5 */
6
7#include "linux/kernel.h"
8#include "linux/slab.h"
9#include "linux/init.h"
10#include "linux/notifier.h"
11#include "linux/reboot.h"
12#include "linux/utsname.h"
13#include "linux/ctype.h"
14#include "linux/interrupt.h"
15#include "linux/sysrq.h"
16#include "linux/workqueue.h"
17#include "linux/module.h"
18#include "linux/file.h"
19#include "linux/fs.h"
20#include "linux/namei.h"
21#include "linux/proc_fs.h"
22#include "linux/syscalls.h"
Jeff Dike6f517d32006-01-06 00:19:04 -080023#include "linux/console.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include "asm/irq.h"
25#include "asm/uaccess.h"
26#include "user_util.h"
27#include "kern_util.h"
28#include "kern.h"
29#include "mconsole.h"
30#include "mconsole_kern.h"
31#include "irq_user.h"
32#include "init.h"
33#include "os.h"
34#include "umid.h"
35#include "irq_kern.h"
Jeff Dike3eddddc2005-09-16 19:27:46 -070036#include "choose-mode.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Jeff Diked50084a2006-01-06 00:18:50 -080038static int do_unlink_socket(struct notifier_block *notifier,
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 unsigned long what, void *data)
40{
41 return(mconsole_unlink_socket());
42}
43
44
45static struct notifier_block reboot_notifier = {
46 .notifier_call = do_unlink_socket,
47 .priority = 0,
48};
49
Jeff Diked50084a2006-01-06 00:18:50 -080050/* Safe without explicit locking for now. Tasklets provide their own
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 * locking, and the interrupt handler is safe because it can't interrupt
52 * itself and it can only happen on CPU 0.
53 */
54
Jeff Dike90107722006-01-06 00:18:54 -080055static LIST_HEAD(mc_requests);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57static void mc_work_proc(void *unused)
58{
59 struct mconsole_entry *req;
60 unsigned long flags;
61
62 while(!list_empty(&mc_requests)){
63 local_save_flags(flags);
Jeff Diked50084a2006-01-06 00:18:50 -080064 req = list_entry(mc_requests.next, struct mconsole_entry,
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 list);
66 list_del(&req->list);
67 local_irq_restore(flags);
68 req->request.cmd->handler(&req->request);
69 kfree(req);
70 }
71}
72
Jeff Dike90107722006-01-06 00:18:54 -080073static DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75static irqreturn_t mconsole_interrupt(int irq, void *dev_id,
76 struct pt_regs *regs)
77{
78 /* long to avoid size mismatch warnings from gcc */
79 long fd;
80 struct mconsole_entry *new;
81 struct mc_request req;
82
83 fd = (long) dev_id;
84 while (mconsole_get_request(fd, &req)){
85 if(req.cmd->context == MCONSOLE_INTR)
86 (*req.cmd->handler)(&req);
87 else {
88 new = kmalloc(sizeof(*new), GFP_ATOMIC);
89 if(new == NULL)
90 mconsole_reply(&req, "Out of memory", 1, 0);
91 else {
92 new->request = req;
93 list_add(&new->list, &mc_requests);
94 }
95 }
96 }
97 if(!list_empty(&mc_requests))
98 schedule_work(&mconsole_work);
99 reactivate_fd(fd, MCONSOLE_IRQ);
100 return(IRQ_HANDLED);
101}
102
103void mconsole_version(struct mc_request *req)
104{
105 char version[256];
106
Jeff Diked50084a2006-01-06 00:18:50 -0800107 sprintf(version, "%s %s %s %s %s", system_utsname.sysname,
108 system_utsname.nodename, system_utsname.release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 system_utsname.version, system_utsname.machine);
110 mconsole_reply(req, version, 0, 0);
111}
112
113void mconsole_log(struct mc_request *req)
114{
115 int len;
116 char *ptr = req->request.data;
117
118 ptr += strlen("log ");
119
120 len = req->len - (ptr - req->request.data);
121 printk("%.*s", len, ptr);
122 mconsole_reply(req, "", 0, 0);
123}
124
125/* This is a more convoluted version of mconsole_proc, which has some stability
126 * problems; however, we need it fixed, because it is expected that UML users
127 * mount HPPFS instead of procfs on /proc. And we want mconsole_proc to still
128 * show the real procfs content, not the ones from hppfs.*/
129#if 0
130void mconsole_proc(struct mc_request *req)
131{
132 struct nameidata nd;
133 struct file_system_type *proc;
134 struct super_block *super;
135 struct file *file;
136 int n, err;
137 char *ptr = req->request.data, *buf;
138
139 ptr += strlen("proc");
140 while(isspace(*ptr)) ptr++;
141
142 proc = get_fs_type("proc");
143 if(proc == NULL){
144 mconsole_reply(req, "procfs not registered", 1, 0);
145 goto out;
146 }
147
148 super = (*proc->get_sb)(proc, 0, NULL, NULL);
149 put_filesystem(proc);
150 if(super == NULL){
151 mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
152 goto out;
153 }
154 up_write(&super->s_umount);
155
156 nd.dentry = super->s_root;
157 nd.mnt = NULL;
158 nd.flags = O_RDONLY + 1;
159 nd.last_type = LAST_ROOT;
160
161 /* START: it was experienced that the stability problems are closed
162 * if commenting out these two calls + the below read cycle. To
163 * make UML crash again, it was enough to readd either one.*/
164 err = link_path_walk(ptr, &nd);
165 if(err){
166 mconsole_reply(req, "Failed to look up file", 1, 0);
167 goto out_kill;
168 }
169
170 file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
171 if(IS_ERR(file)){
172 mconsole_reply(req, "Failed to open file", 1, 0);
173 goto out_kill;
174 }
175 /*END*/
176
177 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
178 if(buf == NULL){
179 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
180 goto out_fput;
181 }
182
183 if((file->f_op != NULL) && (file->f_op->read != NULL)){
184 do {
185 n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
186 &file->f_pos);
187 if(n >= 0){
188 buf[n] = '\0';
189 mconsole_reply(req, buf, 0, (n > 0));
190 }
191 else {
192 mconsole_reply(req, "Read of file failed",
193 1, 0);
194 goto out_free;
195 }
196 } while(n > 0);
197 }
198 else mconsole_reply(req, "", 0, 0);
199
200 out_free:
201 kfree(buf);
202 out_fput:
203 fput(file);
204 out_kill:
205 deactivate_super(super);
206 out: ;
207}
208#endif
209
210void mconsole_proc(struct mc_request *req)
211{
212 char path[64];
213 char *buf;
214 int len;
215 int fd;
216 int first_chunk = 1;
217 char *ptr = req->request.data;
218
219 ptr += strlen("proc");
220 while(isspace(*ptr)) ptr++;
221 snprintf(path, sizeof(path), "/proc/%s", ptr);
222
223 fd = sys_open(path, 0, 0);
224 if (fd < 0) {
225 mconsole_reply(req, "Failed to open file", 1, 0);
226 printk("open %s: %d\n",path,fd);
227 goto out;
228 }
229
230 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
231 if(buf == NULL){
232 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
233 goto out_close;
234 }
235
236 for (;;) {
237 len = sys_read(fd, buf, PAGE_SIZE-1);
238 if (len < 0) {
239 mconsole_reply(req, "Read of file failed", 1, 0);
240 goto out_free;
241 }
242 /*Begin the file content on his own line.*/
243 if (first_chunk) {
244 mconsole_reply(req, "\n", 0, 1);
245 first_chunk = 0;
246 }
247 if (len == PAGE_SIZE-1) {
248 buf[len] = '\0';
249 mconsole_reply(req, buf, 0, 1);
250 } else {
251 buf[len] = '\0';
252 mconsole_reply(req, buf, 0, 0);
253 break;
254 }
255 }
256
257 out_free:
258 kfree(buf);
259 out_close:
260 sys_close(fd);
261 out:
262 /* nothing */;
263}
264
265#define UML_MCONSOLE_HELPTEXT \
266"Commands: \n\
267 version - Get kernel version \n\
268 help - Print this message \n\
269 halt - Halt UML \n\
270 reboot - Reboot UML \n\
271 config <dev>=<config> - Add a new device to UML; \n\
272 same syntax as command line \n\
273 config <dev> - Query the configuration of a device \n\
274 remove <dev> - Remove a device from UML \n\
275 sysrq <letter> - Performs the SysRq action controlled by the letter \n\
Jeff Dikedb805812006-02-01 03:06:23 -0800276 cad - invoke the Ctrl-Alt-Del handler \n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 stop - pause the UML; it will do nothing until it receives a 'go' \n\
278 go - continue the UML after a 'stop' \n\
279 log <string> - make UML enter <string> into the kernel log\n\
280 proc <file> - returns the contents of the UML's /proc/<file>\n\
Jeff Dike3eddddc2005-09-16 19:27:46 -0700281 stack <pid> - returns the stack of the specified pid\n\
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282"
283
284void mconsole_help(struct mc_request *req)
285{
286 mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
287}
288
289void mconsole_halt(struct mc_request *req)
290{
291 mconsole_reply(req, "", 0, 0);
292 machine_halt();
293}
294
295void mconsole_reboot(struct mc_request *req)
296{
297 mconsole_reply(req, "", 0, 0);
298 machine_restart(NULL);
299}
300
301extern void ctrl_alt_del(void);
302
303void mconsole_cad(struct mc_request *req)
304{
305 mconsole_reply(req, "", 0, 0);
306 ctrl_alt_del();
307}
308
309void mconsole_go(struct mc_request *req)
310{
311 mconsole_reply(req, "Not stopped", 1, 0);
312}
313
314void mconsole_stop(struct mc_request *req)
315{
316 deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
317 os_set_fd_block(req->originating_fd, 1);
318 mconsole_reply(req, "", 0, 0);
319 while(mconsole_get_request(req->originating_fd, req)){
320 if(req->cmd->handler == mconsole_go) break;
321 (*req->cmd->handler)(req);
322 }
323 os_set_fd_block(req->originating_fd, 0);
324 reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
325 mconsole_reply(req, "", 0, 0);
326}
327
328/* This list is populated by __initcall routines. */
329
Paolo 'Blaisorblade' Giarrusso42947cb2006-02-01 03:06:29 -0800330static LIST_HEAD(mconsole_devices);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332void mconsole_register_dev(struct mc_device *new)
333{
334 list_add(&new->list, &mconsole_devices);
335}
336
337static struct mc_device *mconsole_find_dev(char *name)
338{
339 struct list_head *ele;
340 struct mc_device *dev;
341
342 list_for_each(ele, &mconsole_devices){
343 dev = list_entry(ele, struct mc_device, list);
344 if(!strncmp(name, dev->name, strlen(dev->name)))
345 return(dev);
346 }
347 return(NULL);
348}
349
350#define CONFIG_BUF_SIZE 64
351
Jeff Diked50084a2006-01-06 00:18:50 -0800352static void mconsole_get_config(int (*get_config)(char *, char *, int,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 char **),
354 struct mc_request *req, char *name)
355{
356 char default_buf[CONFIG_BUF_SIZE], *error, *buf;
357 int n, size;
358
359 if(get_config == NULL){
360 mconsole_reply(req, "No get_config routine defined", 1, 0);
361 return;
362 }
363
364 error = NULL;
365 size = sizeof(default_buf)/sizeof(default_buf[0]);
366 buf = default_buf;
367
368 while(1){
369 n = (*get_config)(name, buf, size, &error);
370 if(error != NULL){
371 mconsole_reply(req, error, 1, 0);
372 goto out;
373 }
374
375 if(n <= size){
376 mconsole_reply(req, buf, 0, 0);
377 goto out;
378 }
379
380 if(buf != default_buf)
381 kfree(buf);
382
383 size = n;
384 buf = kmalloc(size, GFP_KERNEL);
385 if(buf == NULL){
386 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
387 return;
388 }
389 }
390 out:
391 if(buf != default_buf)
392 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393}
394
395void mconsole_config(struct mc_request *req)
396{
397 struct mc_device *dev;
398 char *ptr = req->request.data, *name;
399 int err;
400
401 ptr += strlen("config");
402 while(isspace(*ptr)) ptr++;
403 dev = mconsole_find_dev(ptr);
404 if(dev == NULL){
405 mconsole_reply(req, "Bad configuration option", 1, 0);
406 return;
407 }
408
409 name = &ptr[strlen(dev->name)];
410 ptr = name;
411 while((*ptr != '=') && (*ptr != '\0'))
412 ptr++;
413
414 if(*ptr == '='){
415 err = (*dev->config)(name);
416 mconsole_reply(req, "", err, 0);
417 }
418 else mconsole_get_config(dev->get_config, req, name);
419}
420
421void mconsole_remove(struct mc_request *req)
422{
Jeff Diked50084a2006-01-06 00:18:50 -0800423 struct mc_device *dev;
Jeff Dike29d56cf2005-06-25 14:55:25 -0700424 char *ptr = req->request.data, *err_msg = "";
Jeff Dike3a331a52006-01-06 00:19:05 -0800425 char error[256];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700426 int err, start, end, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 ptr += strlen("remove");
429 while(isspace(*ptr)) ptr++;
430 dev = mconsole_find_dev(ptr);
431 if(dev == NULL){
432 mconsole_reply(req, "Bad remove option", 1, 0);
433 return;
434 }
Jeff Dike29d56cf2005-06-25 14:55:25 -0700435
Jeff Dike3a331a52006-01-06 00:19:05 -0800436 ptr = &ptr[strlen(dev->name)];
Jeff Dike29d56cf2005-06-25 14:55:25 -0700437
Jeff Dike3a331a52006-01-06 00:19:05 -0800438 err = 1;
439 n = (*dev->id)(&ptr, &start, &end);
440 if(n < 0){
441 err_msg = "Couldn't parse device number";
442 goto out;
443 }
444 else if((n < start) || (n > end)){
445 sprintf(error, "Invalid device number - must be between "
446 "%d and %d", start, end);
447 err_msg = error;
448 goto out;
449 }
Jeff Dike29d56cf2005-06-25 14:55:25 -0700450
451 err = (*dev->remove)(n);
Jeff Dike3a331a52006-01-06 00:19:05 -0800452 switch(err){
453 case -ENODEV:
454 err_msg = "Device doesn't exist";
455 break;
456 case -EBUSY:
457 err_msg = "Device is currently open";
458 break;
459 default:
460 break;
461 }
462out:
Jeff Dike29d56cf2005-06-25 14:55:25 -0700463 mconsole_reply(req, err_msg, err, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464}
465
Jeff Dike6f517d32006-01-06 00:19:04 -0800466static DEFINE_SPINLOCK(console_lock);
467static LIST_HEAD(clients);
468static char console_buf[MCONSOLE_MAX_DATA];
469static int console_index = 0;
470
471static void console_write(struct console *console, const char *string,
472 unsigned len)
473{
474 struct list_head *ele;
475 int n;
476
477 if(list_empty(&clients))
478 return;
479
480 while(1){
481 n = min(len, ARRAY_SIZE(console_buf) - console_index);
482 strncpy(&console_buf[console_index], string, n);
483 console_index += n;
484 string += n;
485 len -= n;
486 if(len == 0)
487 return;
488
489 list_for_each(ele, &clients){
490 struct mconsole_entry *entry;
491
492 entry = list_entry(ele, struct mconsole_entry, list);
493 mconsole_reply_len(&entry->request, console_buf,
494 console_index, 0, 1);
495 }
496
497 console_index = 0;
498 }
499}
500
501static struct console mc_console = { .name = "mc",
502 .write = console_write,
Jeff Dikea174b302006-01-11 12:17:28 -0800503 .flags = CON_ENABLED,
Jeff Dike6f517d32006-01-06 00:19:04 -0800504 .index = -1 };
505
506static int mc_add_console(void)
507{
508 register_console(&mc_console);
509 return 0;
510}
511
512late_initcall(mc_add_console);
513
514static void with_console(struct mc_request *req, void (*proc)(void *),
515 void *arg)
516{
517 struct mconsole_entry entry;
518 unsigned long flags;
519
520 INIT_LIST_HEAD(&entry.list);
521 entry.request = *req;
522 list_add(&entry.list, &clients);
523 spin_lock_irqsave(&console_lock, flags);
524
525 (*proc)(arg);
526
527 mconsole_reply_len(req, console_buf, console_index, 0, 0);
528 console_index = 0;
529
530 spin_unlock_irqrestore(&console_lock, flags);
531 list_del(&entry.list);
532}
533
Jeff Dike4111b022006-01-06 00:19:05 -0800534#ifdef CONFIG_MAGIC_SYSRQ
535static void sysrq_proc(void *arg)
536{
537 char *op = arg;
538
539 handle_sysrq(*op, &current->thread.regs, NULL);
540}
541
542void mconsole_sysrq(struct mc_request *req)
543{
544 char *ptr = req->request.data;
545
546 ptr += strlen("sysrq");
547 while(isspace(*ptr)) ptr++;
548
549 /* With 'b', the system will shut down without a chance to reply,
550 * so in this case, we reply first.
551 */
552 if(*ptr == 'b')
553 mconsole_reply(req, "", 0, 0);
554
555 with_console(req, sysrq_proc, ptr);
556}
557#else
558void mconsole_sysrq(struct mc_request *req)
559{
560 mconsole_reply(req, "Sysrq not compiled in", 1, 0);
561}
562#endif
563
Paolo 'Blaisorblade' Giarrusso42947cb2006-02-01 03:06:29 -0800564#ifdef CONFIG_MODE_SKAS
565
Jeff Dike6f517d32006-01-06 00:19:04 -0800566static void stack_proc(void *arg)
567{
568 struct task_struct *from = current, *to = arg;
569
570 to->thread.saved_task = from;
571 switch_to(from, to, from);
572}
573
Jeff Dike3eddddc2005-09-16 19:27:46 -0700574/* Mconsole stack trace
575 * Added by Allan Graves, Jeff Dike
576 * Dumps a stacks registers to the linux console.
577 * Usage stack <pid>.
578 */
Paolo 'Blaisorblade' Giarrusso42947cb2006-02-01 03:06:29 -0800579static void do_stack_trace(struct mc_request *req)
Jeff Dike3eddddc2005-09-16 19:27:46 -0700580{
Jeff Dike3a331a52006-01-06 00:19:05 -0800581 char *ptr = req->request.data;
582 int pid_requested= -1;
Jeff Dike6f517d32006-01-06 00:19:04 -0800583 struct task_struct *from = NULL;
Jeff Dike3eddddc2005-09-16 19:27:46 -0700584 struct task_struct *to = NULL;
585
Jeff Dike3a331a52006-01-06 00:19:05 -0800586 /* Would be nice:
587 * 1) Send showregs output to mconsole.
Jeff Dike3eddddc2005-09-16 19:27:46 -0700588 * 2) Add a way to stack dump all pids.
589 */
590
Jeff Dike3a331a52006-01-06 00:19:05 -0800591 ptr += strlen("stack");
592 while(isspace(*ptr)) ptr++;
Jeff Dike3eddddc2005-09-16 19:27:46 -0700593
Jeff Dike3a331a52006-01-06 00:19:05 -0800594 /* Should really check for multiple pids or reject bad args here */
595 /* What do the arguments in mconsole_reply mean? */
596 if(sscanf(ptr, "%d", &pid_requested) == 0){
597 mconsole_reply(req, "Please specify a pid", 1, 0);
598 return;
599 }
Jeff Dike3eddddc2005-09-16 19:27:46 -0700600
Jeff Dike6f517d32006-01-06 00:19:04 -0800601 from = current;
Jeff Dike3eddddc2005-09-16 19:27:46 -0700602
Jeff Dike6f517d32006-01-06 00:19:04 -0800603 to = find_task_by_pid(pid_requested);
Jeff Dike3a331a52006-01-06 00:19:05 -0800604 if((to == NULL) || (pid_requested == 0)) {
605 mconsole_reply(req, "Couldn't find that pid", 1, 0);
606 return;
607 }
Jeff Dike6f517d32006-01-06 00:19:04 -0800608 with_console(req, stack_proc, to);
Jeff Dike3eddddc2005-09-16 19:27:46 -0700609}
Paolo 'Blaisorblade' Giarrusso42947cb2006-02-01 03:06:29 -0800610#endif /* CONFIG_MODE_SKAS */
Jeff Dike3eddddc2005-09-16 19:27:46 -0700611
612void mconsole_stack(struct mc_request *req)
613{
614 /* This command doesn't work in TT mode, so let's check and then
615 * get out of here
616 */
617 CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode",
618 1, 0),
Paolo 'Blaisorblade' Giarrusso42947cb2006-02-01 03:06:29 -0800619 do_stack_trace(req));
Jeff Dike3eddddc2005-09-16 19:27:46 -0700620}
621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622/* Changed by mconsole_setup, which is __setup, and called before SMP is
623 * active.
624 */
Jeff Diked50084a2006-01-06 00:18:50 -0800625static char *notify_socket = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
Jeff Dike90107722006-01-06 00:18:54 -0800627static int mconsole_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628{
629 /* long to avoid size mismatch warnings from gcc */
630 long sock;
631 int err;
632 char file[256];
633
634 if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
635 snprintf(mconsole_socket_name, sizeof(file), "%s", file);
636
637 sock = os_create_unix_socket(file, sizeof(file), 1);
638 if (sock < 0){
639 printk("Failed to initialize management console\n");
640 return(1);
641 }
642
643 register_reboot_notifier(&reboot_notifier);
644
645 err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
646 SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
647 "mconsole", (void *)sock);
648 if (err){
649 printk("Failed to get IRQ for management console\n");
650 return(1);
651 }
652
653 if(notify_socket != NULL){
Jeff Dike970d6e32006-01-06 00:18:48 -0800654 notify_socket = kstrdup(notify_socket, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 if(notify_socket != NULL)
656 mconsole_notify(notify_socket, MCONSOLE_SOCKET,
Jeff Diked50084a2006-01-06 00:18:50 -0800657 mconsole_socket_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 strlen(mconsole_socket_name) + 1);
659 else printk(KERN_ERR "mconsole_setup failed to strdup "
660 "string\n");
661 }
662
Jeff Diked50084a2006-01-06 00:18:50 -0800663 printk("mconsole (version %d) initialized on %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 MCONSOLE_VERSION, mconsole_socket_name);
665 return(0);
666}
667
668__initcall(mconsole_init);
669
670static int write_proc_mconsole(struct file *file, const char __user *buffer,
671 unsigned long count, void *data)
672{
673 char *buf;
674
675 buf = kmalloc(count + 1, GFP_KERNEL);
Jeff Diked50084a2006-01-06 00:18:50 -0800676 if(buf == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 return(-ENOMEM);
678
679 if(copy_from_user(buf, buffer, count)){
680 count = -EFAULT;
681 goto out;
682 }
683
684 buf[count] = '\0';
685
686 mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
687 out:
688 kfree(buf);
689 return(count);
690}
691
692static int create_proc_mconsole(void)
693{
694 struct proc_dir_entry *ent;
695
696 if(notify_socket == NULL) return(0);
697
698 ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
699 if(ent == NULL){
Christophe Lucas30f417c2005-07-28 21:16:12 -0700700 printk(KERN_INFO "create_proc_mconsole : create_proc_entry failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return(0);
702 }
703
704 ent->read_proc = NULL;
705 ent->write_proc = write_proc_mconsole;
706 return(0);
707}
708
709static DEFINE_SPINLOCK(notify_spinlock);
710
711void lock_notify(void)
712{
713 spin_lock(&notify_spinlock);
714}
715
716void unlock_notify(void)
717{
718 spin_unlock(&notify_spinlock);
719}
720
721__initcall(create_proc_mconsole);
722
723#define NOTIFY "=notify:"
724
725static int mconsole_setup(char *str)
726{
727 if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
728 str += strlen(NOTIFY);
729 notify_socket = str;
730 }
731 else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
732 return(1);
733}
734
735__setup("mconsole", mconsole_setup);
736
737__uml_help(mconsole_setup,
738"mconsole=notify:<socket>\n"
739" Requests that the mconsole driver send a message to the named Unix\n"
740" socket containing the name of the mconsole socket. This also serves\n"
741" to notify outside processes when UML has booted far enough to respond\n"
742" to mconsole requests.\n\n"
743);
744
745static int notify_panic(struct notifier_block *self, unsigned long unused1,
746 void *ptr)
747{
748 char *message = ptr;
749
750 if(notify_socket == NULL) return(0);
751
Jeff Diked50084a2006-01-06 00:18:50 -0800752 mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 strlen(message) + 1);
754 return(0);
755}
756
757static struct notifier_block panic_exit_notifier = {
758 .notifier_call = notify_panic,
759 .next = NULL,
760 .priority = 1
761};
762
763static int add_notifier(void)
764{
Alan Sterne041c682006-03-27 01:16:30 -0800765 atomic_notifier_chain_register(&panic_notifier_list,
766 &panic_exit_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 return(0);
768}
769
770__initcall(add_notifier);
771
772char *mconsole_notify_socket(void)
773{
774 return(notify_socket);
775}
776
777EXPORT_SYMBOL(mconsole_notify_socket);