From: BlaisorBlade <blaisorblade_spam@yahoo.it>
To: user-mode-linux-devel@lists.sourceforge.net
Subject: Re: [uml-devel] [PATCH] Starting a command inside UML from mconsole
Date: Tue, 16 Sep 2003 20:27:21 +0200 [thread overview]
Message-ID: <200309162027.22242.blaisorblade_spam@yahoo.it> (raw)
In-Reply-To: <200309131820.45833.blaisorblade_spam@yahoo.it>
[-- Attachment #1: Type: text/plain, Size: 1139 bytes --]
Hi, I have finally some working code. I've cleaned it up and it works quite
well, now I only need to setup the file handling. Also, it can be configured
with CONFIG_MCONSOLE_EXEC. Note that if disabled, for header issues, it
defines the exec command anyway but it pretends not to exist(and is not
showed in the
However, there is a problem I'm investigating on. Even if the execve fails, it
reports success. I've debugged it and it showed up that threads synchronize
properly(i.e. CLONE_VFORK works) and that the fault seems to be in
kmod.c:exec_usermodehelper.
It seems that this code, at the end of the function:
if (execve(program_path, argv, envp) < 0)
return -errno;
return 0;
is wrong. Execve returns -2(i.e. -ENOENT), but I've not found a place where
errno is set. It seems that it's not a UML problem, either: simply that code
should be:
return execve(program_path, argv, envp);
because kernel functions don't set errno. However I need confirms on this.
--
cat <<EOSIGN
Paolo Giarrusso, aka Blaisorblade
Linux Kernel 2.4.21/2.6.0-test on an i686; Linux registered user n. 292729
EOSIGN
[-- Attachment #2: mconsole_exec.patch --]
[-- Type: text/x-diff, Size: 7049 bytes --]
--- linuxUm/arch/um/drivers/mconsole_user.c.saved 2003-09-13 20:22:06.000000000 +0200
+++ linuxUm/arch/um/drivers/mconsole_user.c 2003-09-16 18:01:24.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/arch/um/drivers/mconsole_kern.c.saved 2003-09-13 20:22:06.000000000 +0200
+++ linuxUm/arch/um/drivers/mconsole_kern.c 2003-09-16 19:08:14.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"
@@ -203,13 +204,19 @@
/* put_filesystem(proc); */
out: ;
}
+#ifdef CONFIG_MCONSOLE_EXEC
+# define EXEC_HELPTEXT "\
+ exec - execute a command as root inside the UML\n"
+#else
+# define EXEC_HELPTEXT ""
+#endif
#define UML_MCONSOLE_HELPTEXT \
"Commands: \n\
version - Get kernel version \n\
help - Print this message \n\
halt - Halt UML \n\
- reboot - Reboot UML \n\
+ reboot - Reboot UML \n" EXEC_HELPTEXT "\
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\
@@ -265,6 +272,149 @@
reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
mconsole_reply(req, "", 0, 0);
}
+#ifdef CONFIG_MCONSOLE_EXEC
+/* 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;
+ int retval;
+};
+
+/* This function parses arguments from buf to the argv array.
+ * When it goes on a space, starts a new arguments. If it starts with a quote,
+ * it will end at the first matching quote(of the same tipe) which is not escaped with a \.
+ * Otherwise, the arg ends at the first space and can freely contain quotes.
+ * After this, in each argument \<char> is replaced by char.*/
+static void parse_args(char *buf, size_t size, char **argv) {
+ char *start_arg = buf, *end_arg;
+ int i = 0, must_not_break = 1;
+
+ start_arg += strlen("exec");
+
+ while (i < size - 1 && must_not_break) {
+ while(isspace(*start_arg))
+ start_arg++;
+
+ if (*start_arg == '\0')
+ break;
+
+ end_arg = start_arg;
+ if (*start_arg == '\"' || *start_arg == '\'') { /*quoted arg*/
+ end_arg++;
+ /*while (1) {
+ while (*end_arg != *start_arg && *end_arg != '\0')
+ end_arg++;
+ if (*(end_arg - 1) != '\\' || *end_arg == '\0')
+ break;
+ end_arg++;
+ }*/
+ while ((*end_arg != *start_arg || *(end_arg - 1) == '\\')
+ && *end_arg != '\0')
+ end_arg++;
+ start_arg++; /*skips the first quote*/
+ } else {
+ while(!isspace(*end_arg) && *end_arg != '\0')
+ end_arg++;
+ }
+ argv[i++] = start_arg;
+
+ if (*end_arg == '\0')
+ must_not_break = 0; /*we have finished, but the break must
+ be done after we strip '\' out.*/
+ *end_arg = '\0';
+
+ /*let's remove those '\'! The text is shifted back to cover the \'s*/
+ char *curs = start_arg;
+ int displacement = 0;
+ while (*curs != '\\' && *curs != '\0')
+ curs++;
+ while (*curs != '\0') {
+ displacement++;
+ curs++;
+ do {
+ *(curs-displacement) = *curs;
+ curs++;
+ } while (*curs != '\\' && *curs != '\0');
+ }
+ *(curs - displacement) = '\0';
+ start_arg = end_arg + 1;
+ }
+
+ argv[i] = NULL;
+}
+
+/* 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*/
+static int runner_thread(void * data)
+{
+ struct subprocess_info *sub_info = data;
+
+ char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
+
+ char *path, *argv[MCONSOLE_MAX_DATA / 2 + 1];
+ char buf[MCONSOLE_MAX_DATA];
+ int retval;
+
+ strcpy(buf, sub_info->command);
+
+ parse_args(buf, MCONSOLE_MAX_DATA / 2 + 1, argv);
+ if (*argv[0] == '\0')
+ sub_info->retval = -EINVAL; /*invalid command to execute, though this maybe
+ is not needed.*/
+ path = argv[0];
+
+ retval = exec_usermodehelper(path, argv, envp);
+
+ /* Exec failed? */
+ sub_info->retval = 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);
+ return;
+ }
+ 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);
+ return;
+ }
+
+ mconsole_reply(req, "The command has been started successfully.", 0, 0);
+}
+#else
+/* I must put mconsole_exec in the commands table always, because there
+ * linux/config.h cannot be included. So I pretend it doesn't exist by hiding
+ * it in the help text*/
+void mconsole_exec(struct mc_request *req)
+{
+ mconsole_reply(req, "Unknown command", 1, 0);
+ /*must be the same as in mconsole_reply*/
+}
+/* Patch end */
+#endif /*CONFIG_MCONSOLE_EXEC*/
/* This list is populated by __initcall routines. */
--- linuxUm/arch/um/config.in.saved 2003-09-13 20:22:06.000000000 +0200
+++ linuxUm/arch/um/config.in 2003-09-16 16:31:13.000000000 +0200
@@ -40,6 +40,7 @@
tristate 'Host filesystem' CONFIG_HOSTFS
tristate 'Honeypot proc filesystem' CONFIG_HPPFS
bool 'Management console' CONFIG_MCONSOLE
+dep_bool 'Execution through management console' CONFIG_MCONSOLE_EXEC $CONFIG_MCONSOLE
dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_MCONSOLE
bool '2G/2G host address space split' CONFIG_HOST_2G_2G
bool 'Symmetric multi-processing support' CONFIG_UML_SMP
--- linuxUm/arch/um/include/mconsole.h.saved 2003-09-13 20:22:07.000000000 +0200
+++ linuxUm/arch/um/include/mconsole.h 2003-09-16 18:11:48.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);
next prev parent reply other threads:[~2003-09-16 18:36 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-09-13 16:20 [uml-devel] [PATCH] Starting a command inside UML from mconsole BlaisorBlade
2003-09-13 19:48 ` Matt Zimmerman
2003-09-14 18:50 ` BlaisorBlade
2003-09-14 20:33 ` Henrik Nordstrom
2003-09-15 17:12 ` BlaisorBlade
2003-09-14 2:33 ` Jeff Dike
2003-09-14 6:30 ` Matt Zimmerman
2003-09-14 6:45 ` Russell Coker
2003-09-14 7:59 ` Steve Schnepp
2003-09-14 13:50 ` Jeff Dike
2003-09-14 16:36 ` Matt Zimmerman
2003-09-14 17:10 ` BlaisorBlade
2003-09-14 17:45 ` Michael Richardson
2003-09-14 20:28 ` Henrik Nordstrom
2003-09-14 20:32 ` Michael Richardson
2003-09-15 7:31 ` Ulf Bartelt
2003-09-15 9:20 ` Henrik Nordstrom
2003-09-16 18:27 ` BlaisorBlade [this message]
2003-09-17 17:39 ` BlaisorBlade
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200309162027.22242.blaisorblade_spam@yahoo.it \
--to=blaisorblade_spam@yahoo.it \
--cc=user-mode-linux-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox