--- linuxUm-2.4.22/arch/um/drivers/mconsole_user.c.saved 2003-09-13 20:22:06.000000000 +0200 +++ linuxUm-2.4.22/arch/um/drivers/mconsole_user.c 2003-09-14 18:15:13.000000000 +0200 @@ -21,6 +21,7 @@ { "version", mconsole_version, MCONSOLE_INTR }, { "halt", mconsole_halt, MCONSOLE_PROC }, { "reboot", mconsole_reboot, MCONSOLE_PROC }, + { "exec", mconsole_exec, MCONSOLE_PROC }, { "config", mconsole_config, MCONSOLE_PROC }, { "remove", mconsole_remove, MCONSOLE_PROC }, { "sysrq", mconsole_sysrq, MCONSOLE_INTR }, --- linuxUm-2.4.22/arch/um/drivers/mconsole_kern.c.saved 2003-09-13 20:22:06.000000000 +0200 +++ linuxUm-2.4.22/arch/um/drivers/mconsole_kern.c 2003-09-14 20:27:00.000000000 +0200 @@ -18,6 +18,7 @@ #include "linux/file.h" #include "linux/fs.h" #include "linux/proc_fs.h" +#include "linux/kmod.h" #include "asm/irq.h" #include "asm/uaccess.h" #include "user_util.h" @@ -210,6 +211,7 @@ help - Print this message \n\ halt - Halt UML \n\ reboot - Reboot UML \n\ + exec - execute a command as root inside the UML\n\ config = - Add a new device to UML; \n\ same syntax as command line \n\ config - Query the configuration of a device \n\ @@ -266,6 +268,95 @@ mconsole_reply(req, "", 0, 0); } +/* This is the focal point of the exec patch. Much code comes from + * kernel/kmod.c. But I just couldn't use call_usermodehelper, because it must be + * called from process context.*/ +struct subprocess_info { + char *command; + pid_t retval; +}; + +/* This code must be called in a new thread, and uses 2.4 exec_usermodehelper + * (which seems to be gone inside 2.6) to start the specified program. + * This function is like ____call_usermodehelper*/ +int runner_thread(void * data) +{ + struct subprocess_info *sub_info = data; + char buf[MCONSOLE_MAX_DATA]; + char *ptr = buf, *endptr; + char *path, *argv[21]; /*For now.*/ + char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + int i = 0, retval; + strcpy(buf, sub_info->command); + + ptr += strlen("exec"); + + while (i < 20) { + while(isspace(*ptr)) ptr++; + + if (ptr == NULL) + break; + + endptr = ptr; + if (*ptr == '\"' || *ptr == '\'') { /*quoted arg*/ + while (*endptr != *ptr || *(endptr - 1) == '\\') endptr++; + ptr++; /*skips the first quote*/ + } else { + while(!isspace(*endptr)) endptr++; + } + argv[i++] = ptr; + *endptr = '\0'; + ptr = endptr + 1; + } + + if (*argv[0] == '\0') + sub_info->retval = -EINVAL; /*invalid command to execute, though this maybe + is not needed.*/ + path = argv[0]; + argv[i] = NULL; + + /*path = "/bin/sleep"; + argv = { path, "20", NULL };*/ + retval = exec_usermodehelper(path, argv, envp); + + /* Exec failed? */ + sub_info->retval = (pid_t)retval; + do_exit(0); +} + +/* This is like __call_usermodehelper. Only exception is that it's not a callback of keventd, and that + * it bundles the declaration of sub_info from call_usermodehelper.*/ +void mconsole_exec(struct mc_request *req) +{ + pid_t pid; + + struct subprocess_info sub_info = { + command: req->request.data, + retval: 0, + }; + + /* + * CLONE_VFORK: wait until the usermode helper has execve'd successfully + * We need the data structures to stay around until that is done. + */ + pid = kernel_thread(runner_thread, &sub_info, CLONE_VFORK | SIGCHLD); + + if (pid < 0) { + char buf[60]; + snprintf(buf, 60, "kernel_thread failed in mconsole_exec with error code: %d", -pid); + mconsole_reply(req, buf, 1, 0); + } + if (sub_info.retval < 0) { + char buf[50]; + snprintf(buf, 50, "execve failed in mconsole_exec with errno = %d", -sub_info.retval); + mconsole_reply(req, buf, 1, 0); + } + + mconsole_reply(req, "The command has been started successfully.", 0, 0); +} + +/* Patch end */ + /* This list is populated by __initcall routines. */ LIST_HEAD(mconsole_devices); --- linuxUm-2.4.22/arch/um/include/mconsole.h.saved 2003-09-13 20:22:07.000000000 +0200 +++ linuxUm-2.4.22/arch/um/include/mconsole.h 2003-09-14 12:19:53.000000000 +0200 @@ -73,6 +73,7 @@ extern void mconsole_help(struct mc_request *req); extern void mconsole_halt(struct mc_request *req); extern void mconsole_reboot(struct mc_request *req); +extern void mconsole_exec(struct mc_request *req); extern void mconsole_config(struct mc_request *req); extern void mconsole_remove(struct mc_request *req); extern void mconsole_sysrq(struct mc_request *req);