vserver 1.9.3
[linux-2.6.git] / arch / um / drivers / mconsole_kern.c
index b12cb18..9076c06 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
  * Licensed under the GPL
  */
 
@@ -15,6 +15,9 @@
 #include "linux/sysrq.h"
 #include "linux/workqueue.h"
 #include "linux/module.h"
+#include "linux/file.h"
+#include "linux/fs.h"
+#include "linux/namei.h"
 #include "linux/proc_fs.h"
 #include "asm/irq.h"
 #include "asm/uaccess.h"
@@ -27,6 +30,7 @@
 #include "init.h"
 #include "os.h"
 #include "umid.h"
+#include "irq_kern.h"
 
 static int do_unlink_socket(struct notifier_block *notifier, 
                            unsigned long what, void *data)
@@ -47,27 +51,26 @@ static struct notifier_block reboot_notifier = {
 
 LIST_HEAD(mc_requests);
 
-void mc_work_proc(void *unused)
+static void mc_work_proc(void *unused)
 {
        struct mconsole_entry *req;
        unsigned long flags;
-       int done;
 
-       do {
+       while(!list_empty(&mc_requests)){
                local_save_flags(flags);
                req = list_entry(mc_requests.next, struct mconsole_entry, 
                                 list);
                list_del(&req->list);
-               done = list_empty(&mc_requests);
                local_irq_restore(flags);
                req->request.cmd->handler(&req->request);
                kfree(req);
-       } while(!done);
+       }
 }
 
 DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
 
-void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mconsole_interrupt(int irq, void *dev_id,
+                                     struct pt_regs *regs)
 {
        int fd;
        struct mconsole_entry *new;
@@ -75,9 +78,10 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        fd = (int) dev_id;
        while (mconsole_get_request(fd, &req)){
-               if(req.cmd->as_interrupt) (*req.cmd->handler)(&req);
+               if(req.cmd->context == MCONSOLE_INTR)
+                       (*req.cmd->handler)(&req);
                else {
-                       new = kmalloc(sizeof(req), GFP_ATOMIC);
+                       new = kmalloc(sizeof(*new), GFP_ATOMIC);
                        if(new == NULL)
                                mconsole_reply(&req, "Out of memory", 1, 0);
                        else {
@@ -86,8 +90,10 @@ void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        }
                }
        }
-       if(!list_empty(&mc_requests)) schedule_work(&mconsole_work);
+       if(!list_empty(&mc_requests))
+               schedule_work(&mconsole_work);
        reactivate_fd(fd, MCONSOLE_IRQ);
+       return(IRQ_HANDLED);
 }
 
 void mconsole_version(struct mc_request *req)
@@ -100,20 +106,109 @@ void mconsole_version(struct mc_request *req)
        mconsole_reply(req, version, 0, 0);
 }
 
+void mconsole_log(struct mc_request *req)
+{
+       int len;
+       char *ptr = req->request.data;
+
+       ptr += strlen("log ");
+
+       len = req->len - (ptr - req->request.data);
+       printk("%.*s", len, ptr);
+       mconsole_reply(req, "", 0, 0);
+}
+
+void mconsole_proc(struct mc_request *req)
+{
+       struct nameidata nd;
+       struct file_system_type *proc;
+       struct super_block *super;
+       struct file *file;
+       int n, err;
+       char *ptr = req->request.data, *buf;
+
+       ptr += strlen("proc");
+       while(isspace(*ptr)) ptr++;
+
+       proc = get_fs_type("proc");
+       if(proc == NULL){
+               mconsole_reply(req, "procfs not registered", 1, 0);
+               goto out;
+       }
+
+       super = (*proc->get_sb)(proc, 0, NULL, NULL);
+       put_filesystem(proc);
+       if(super == NULL){
+               mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
+               goto out;
+       }
+       up_write(&super->s_umount);
+
+       nd.dentry = super->s_root;
+       nd.mnt = NULL;
+       nd.flags = O_RDONLY + 1;
+       nd.last_type = LAST_ROOT;
+
+       err = link_path_walk(ptr, &nd);
+       if(err){
+               mconsole_reply(req, "Failed to look up file", 1, 0);
+               goto out_kill;
+       }
+
+       file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
+       if(IS_ERR(file)){
+               mconsole_reply(req, "Failed to open file", 1, 0);
+               goto out_kill;
+       }
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if(buf == NULL){
+               mconsole_reply(req, "Failed to allocate buffer", 1, 0);
+               goto out_fput;
+       }
+
+       if((file->f_op != NULL) && (file->f_op->read != NULL)){
+               do {
+                       n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
+                                               &file->f_pos);
+                       if(n >= 0){
+                               buf[n] = '\0';
+                               mconsole_reply(req, buf, 0, (n > 0));
+                       }
+                       else {
+                               mconsole_reply(req, "Read of file failed",
+                                              1, 0);
+                               goto out_free;
+                       }
+               } while(n > 0);
+       }
+       else mconsole_reply(req, "", 0, 0);
+
+ out_free:
+       kfree(buf);
+ out_fput:
+       fput(file);
+ out_kill:
+       deactivate_super(super);
+ out: ;
+}
+
 #define UML_MCONSOLE_HELPTEXT \
-"Commands:
-    version - Get kernel version
-    help - Print this message
-    halt - Halt UML
-    reboot - Reboot UML
-    config <dev>=<config> - Add a new device to UML; 
-       same syntax as command line
-    config <dev> - Query the configuration of a device
-    remove <dev> - Remove a device from UML
-    sysrq <letter> - Performs the SysRq action controlled by the letter
-    cad - invoke the Ctl-Alt-Del handler
-    stop - pause the UML; it will do nothing until it receives a 'go'
-    go - continue the UML after a 'stop'
+"Commands: \n\
+    version - Get kernel version \n\
+    help - Print this message \n\
+    halt - Halt UML \n\
+    reboot - Reboot UML \n\
+    config <dev>=<config> - Add a new device to UML;  \n\
+       same syntax as command line \n\
+    config <dev> - Query the configuration of a device \n\
+    remove <dev> - Remove a device from UML \n\
+    sysrq <letter> - Performs the SysRq action controlled by the letter \n\
+    cad - invoke the Ctl-Alt-Del handler \n\
+    stop - pause the UML; it will do nothing until it receives a 'go' \n\
+    go - continue the UML after a 'stop' \n\
+    log <string> - make UML enter <string> into the kernel log\n\
+    proc <file> - returns the contents of the UML's /proc/<file>\n\
 "
 
 void mconsole_help(struct mc_request *req)
@@ -279,8 +374,8 @@ void mconsole_sysrq(struct mc_request *req)
        ptr += strlen("sysrq");
        while(isspace(*ptr)) ptr++;
 
-       handle_sysrq(*ptr, &current->thread.regs, NULL);
        mconsole_reply(req, "", 0, 0);
+       handle_sysrq(*ptr, &current->thread.regs, NULL);
 }
 #else
 void mconsole_sysrq(struct mc_request *req)
@@ -302,7 +397,7 @@ int mconsole_init(void)
        if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
        snprintf(mconsole_socket_name, sizeof(file), "%s", file);
 
-       sock = create_unix_socket(file, sizeof(file));
+       sock = os_create_unix_socket(file, sizeof(file), 1);
        if (sock < 0){
                printk("Failed to initialize management console\n");
                return(1);
@@ -344,11 +439,16 @@ static int write_proc_mconsole(struct file *file, const char *buffer,
        if(buf == NULL) 
                return(-ENOMEM);
 
-       if(copy_from_user(buf, buffer, count))
-               return(-EFAULT);
+       if(copy_from_user(buf, buffer, count)){
+               count = -EFAULT;
+               goto out;
+       }
+
        buf[count] = '\0';
 
        mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
+ out:
+       kfree(buf);
        return(count);
 }