Environment variables for user-mode QEMU

Message ID 87k3nrq56l.fsf@schwinge.name
State Superseded, archived
Headers show

Commit Message

Thomas Schwinge April 24, 2013, 4:11 p.m.

On Wed, 24 Apr 2013 15:16:27 +0200, I wrote:
> We have a need to pass environment variable assignments containing commas
> to user-mode QEMU.  The usage information currently says:
>     You can use -E and -U options or the QEMU_SET_ENV and
>     QEMU_UNSET_ENV environment variables to set and unset
>     environment variables for the target process.
>     It is possible to provide several variables by separating them
>     by commas in getsubopt(3) style. Additionally it is possible to
>     provide the -E and -U options multiple times.
>     $ env -i x86_64-linux-user/qemu-x86_64 -E x=y,y=z /usr/bin/printenv
>     y=z
>     x=y
> Instead of this, we'd like to see:
>     $ env -i x86_64-linux-user/qemu-x86_64 -E x=y,y=z /usr/bin/printenv
>     x=y,y=z
> Due to the tokenization based on comma in
> linux-user/main.c:handle_arg_set_env, there is currently no way to
> achieve this -- other than pre-setting environment variables before
> running user-mode QEMU, which obviously isn't always desirable/possible
> (LD_LIBRARY_PATH, etc.).
> Assuming there is a consensus, how would you like this implemented?
> Is it OK to change the semantics of -E (as well as -U, for symmetry?) to
> not handle multiple environment variable assignments (preliminary patch
> below), or does that functionality need to be preserved?  Something needs
> to be done about QEMU_SET_ENV and QEMU_UNSET_ENV then (if anyone is using
> these at all, which we can't disprove), as these are not very useful if
> they can handle only one environment variable.

That is actually a "regression"/change introduced in commit
fc9c54124d134dbd76338a92a91804dab2df8166 (Johannes Schauer CCed, for your
information).  I'm attaching
0001-linux-user-Document-E-and-U-options.patch to update the
documentation for the linux-user QEMU.

The bsd-user QEMU has not been changed accordingly, by the way.

I'm attaching
0002-linux-user-Use-existing-envlist_parse_set-envlist_pa.patch for some
code simplifications.

> Or, should we perhaps have a new -env option that causes any later
> non-option arguments, that contain an equal sign, to be handled as
> environment variable assignments, just like the env command does?
>     $ env -i x86_64-linux-user/qemu-x86_64 [some options] -env [more options] a=b,c d=e,f=a /usr/bin/printenv
>     a=b,c
>     d=e,f=a
> I think I might prefer that solution.  As it is a new option, it also
> won't interfere with anyone's usage/expectations of the current behavior.

I'm attaching 0003-linux-user-New-env-option.patch for implementing that.

The patches have only been lightly tested; please review.



From 71461a2caccfc31287e26ca1edf8ff0053a563f7 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 24 Apr 2013 17:59:17 +0200
Subject: [PATCH 3/3] linux-user: New -env option.

Signed-off-by: Thomas Schwinge <thomas@codesourcery.com>
 linux-user/main.c |   29 ++++++++++++++++++++++++++++-
 qemu-doc.texi     |    6 +++++-
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git linux-user/main.c linux-user/main.c
index 7f81821..7b38b54 100644
--- linux-user/main.c
+++ linux-user/main.c
@@ -38,6 +38,7 @@ 
 char *exec_path;
 int singlestep;
+int env_mode;
 const char *filename;
 const char *argv0;
 int gdbstub_port;
@@ -3202,6 +3203,11 @@  static void handle_arg_log_filename(const char *arg)
+static void handle_arg_env(const char *arg)
+    env_mode = 1;
 static void handle_arg_set_env(const char *arg)
     if (envlist_parse_set(envlist, arg) != 0) {
@@ -3354,6 +3360,8 @@  static const struct qemu_argument arg_table[] = {
      "size",       "set the stack size to 'size' bytes"},
     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
      "model",      "select CPU (-cpu help for list)"},
+    {"env",        "",                 false, handle_arg_env,
+     "",           "enable parsing of the ENV LIST (see below)"},
     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
      "var=value",  "sets targets environment variable (see below)"},
     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
@@ -3390,7 +3398,7 @@  static void usage(void)
     int maxarglen;
     int maxenvlen;
-    printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
+    printf("usage: qemu-" TARGET_ARCH " [options] [env list] program [arguments...]\n"
            "Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n"
            "Options and associated environment variables:\n"
@@ -3444,9 +3452,11 @@  static void usage(void)
            "It is possible to provide several variables by separating them\n"
            "by commas in getsubopt(3) style. Additionally it is possible to\n"
            "provide the -E and -U options multiple times.\n"
+           "Only with -env it is possible to specify values containing commas.\n"
            "The following lines are equivalent:\n"
            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
+           "    -env -U LD_PRELOAD,LD_DEBUG var1=val2 var2=val2\n"
            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
            "Note that if you provide several changes to a single variable\n"
            "the last change will stay in effect.\n");
@@ -3507,6 +3517,23 @@  static int parse_args(int argc, char **argv)
+    if (env_mode) {
+        for (;;) {
+            if (optind >= argc) {
+                break;
+            }
+            r = argv[optind];
+            if (strchr(r, '=') == NULL) {
+                break;
+            }
+            if (envlist_setenv(envlist, r) != 0) {
+                usage();
+            }
+            optind++;
+        }
+    }
     if (optind >= argc) {
diff --git qemu-doc.texi qemu-doc.texi
index 3034af4..f48a53e 100644
--- qemu-doc.texi
+++ qemu-doc.texi
@@ -2671,7 +2671,7 @@  qemu-i386 /usr/local/qemu-i386/wine/bin/wine \
 @subsection Command line options
-usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] [-R size] program [arguments...]
+usage: qemu-i386 [-h] [-d] [-L path] [-s size] [-cpu model] [-g port] [-B offset] [-R size] [env list] program [arguments...]
 @end example
 @table @option
@@ -2683,6 +2683,10 @@  Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386)
 Set the x86 stack size in bytes (default=524288)
 @item -cpu model
 Select CPU model (-cpu help for list and additional feature selection)
+@item -env
+Enable parsing of the @var{env list}.  This means that any
+@var{var}=@var{value} assignments before @var{program} will be added
+to the environment.
 @item -E @var{var}=@var{value}[,@var{var2}=@var{value2},...]
 Set environment @var{var} to @var{value}, @var{var2} to @var{value2},
 and so on.