qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Jorge Lucángeli Obes" <t4m5yn@gmail.com>
To: qemu-devel@nongnu.org, kvm-devel@lists.sourceforge.net
Subject: [Qemu-devel] [PATCH][RFC] Allowing QEMU to directly execute a directory (and storing command line options in it)
Date: Fri, 31 Aug 2007 15:19:00 -0300	[thread overview]
Message-ID: <59abf66e0708311119p2b83fcffg31fac1c298cfc10a@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 6626 bytes --]

Hi all,

The last time this issue was discussed, the executable-directory idea
gained more consensus than the snapshot-based idea. This patch
implements my perception of the first idea. Non-Windows for now, as I
can't test on a Windows system. Suggestions and constructive criticism
more than welcome.

Cheers,
Jorge

This patch allows QEMU to execute a directory with a special format.

This patch allows storing command line options in a configuration file inside
a directory and then directly executing that directory. A simple check is
included to prevent the configuration file to access image files outside
the executed directory. Extra command line options can be passed on invocation,
which will take precedence over the ones stored in the configuration file.

The configuration file specifies, on its first line, the image file to use.
The rest of the file specifies command line options separated by spaces or
newlines. Careful reconstruction of the command line makes sure the speficied
image file gets executed even if other image files were included later in the
configuration file.

Signed-off-by: Jorge Lucángeli Obes
---
diff --git a/qemu/vl.c b/qemu/vl.c
index fcc899b..88cefd2 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -42,8 +42,8 @@
 #include <netinet/in.h>
 #include <dirent.h>
 #include <netdb.h>
-#ifdef _BSD
 #include <sys/stat.h>
+#ifdef _BSD
 #ifndef __APPLE__
 #include <libutil.h>
 #endif
@@ -6367,9 +6367,16 @@ int main_loop(void)
 void help(void)
 {
     printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c)
2003-2007 Fabrice Bellard\n"
-           "usage: %s [options] [disk_image]\n"
+           "usage: %s [options] [disk_image|folder]\n"
            "\n"
+#ifdef _WIN32
            "'disk_image' is a raw hard image image for IDE hard disk 0\n"
+#else
+           "'disk_image' is a raw hard image image for IDE hard disk 0 or\n"
+           "'folder' is a folder with a file 'config' containing in
the first line\n"
+           "the name of an image file inside the folder and in the
rest of the file\n"
+           "options separated by ' ' or '\\n'\n"
+#endif
            "\n"
            "Standard options:\n"
            "-M machine      select emulated machine (-M ? for list)\n"
@@ -6892,6 +6899,20 @@ void qemu_get_launch_info(int *argc, char
***argv, int *opt_daemonize, const cha
     *opt_incoming = incoming;
 }

+char *dir_file_cat(const char *folder, const char *file) {
+    int foldlen = strlen(folder);
+    int filelen = strlen(file);
+    int reslen = foldlen + 1 + filelen + 1;
+
+    char *res = malloc(sizeof(char) * reslen);
+
+    pstrcpy(res, reslen, folder);
+    strncat(res, "/", 1);
+    strncat(res, file, filelen);
+
+    return res;
+}
+
 int main(int argc, char **argv)
 {
 #ifdef CONFIG_GDBSTUB
@@ -7003,7 +7024,120 @@ int main(int argc, char **argv)

     nb_nics = 0;
     /* default mac address of the first network interface */
+
+#ifndef _WIN32
+#define DIR_CMDLINE_SIZE 1<<13
+    int hd_found = 0;
+    char *dir, *opts;
+    struct stat *s = NULL;
+
+    optind = 1;
+    for(;;) {
+        if (optind >= argc)
+            break;
+
+        dir = argv[optind++];
+
+        if (dir[0] != '-') {
+            hd_found = 1;
+            break;
+        }
+    }

+    if (hd_found) {
+        s = malloc(sizeof(*s));
+
+        if (stat(dir, s) < 0) {
+            /* Error */
+            fprintf(stderr, "unable to stat: '%s'\n",
+                    dir);
+            exit(1);
+        }
+
+        if (S_ISDIR(s->st_mode)) {
+            /* The user specified a directory, search for ./config */
+            int configlen = strlen(dir);
+            configlen += 8; /* "/config\0" */
+            char *config = malloc(sizeof(char) * configlen);
+
+            pstrcpy(config, configlen, dir);
+            strncat(config, "/config", 7);
+
+            int fd_config;
+
+            if ((fd_config = open(config, 0)) < 0) {
+                /* Error */
+                if (errno == ENOENT)
+                    fprintf(stderr, "config file not found: '%s'\n",
+                            config);
+                else
+                    fprintf(stderr, "unable to open config file: '%s'\n",
+                            config);
+                exit(1);
+            }
+
+            opts = malloc(sizeof(char) * (DIR_CMDLINE_SIZE));
+
+            ssize_t readb = read(fd_config, opts, (DIR_CMDLINE_SIZE) - 1);
+
+            opts[readb] = '\0';
+
+            char *filename = strsep(&opts, "\n");
+
+            if (filename == NULL) {
+                /* Error */
+                fprintf(stderr, "malformed configuration file: '%s'\n",
+                        config);
+                exit(1);
+            } else if (strchr(filename, '/') != NULL) {
+                /* Error */
+                fprintf(stderr, "'%s' may point outside folder '%s'\n"
+                                "avoid using '/' in config file\n",
+                        filename, dir);
+                exit(1);
+            }
+
+            char tmpopts[DIR_CMDLINE_SIZE];
+            int done = 0;
+            unsigned int nbtoks = 0;
+            char *tok;
+
+            pstrcpy(tmpopts, DIR_CMDLINE_SIZE, opts);
+
+            do {
+                tok = strtok(nbtoks == 0? tmpopts : NULL, " \n");
+
+                if (tok != NULL)
+                    nbtoks++;
+                else
+                    done = 1;
+            } while (!done);
+
+            if (nbtoks > 0) {
+                char **argvprime = malloc((nbtoks + argc + 1) * sizeof(char*));
+
+                argvprime[0] = argv[0];
+
+                for (i = 0; i < nbtoks; i++)
+                    argvprime[i + 1] = strtok(i == 0? opts : NULL, " \n");
+
+                for (i = 1; i < argc; i++)
+                    argvprime[nbtoks + i] = argv[i];
+
+                argvprime[nbtoks + argc] = dir_file_cat(dir, filename);
+
+                argv = argvprime;
+                argc = nbtoks + argc + 1;
+
+                for (i = 0; i < argc; i++)
+                    printf("argv[%d] = %s\n", i, argv[i]);
+            }
+        }
+    }
+
+    free(s);
+#endif
+
     optind = 1;
     for(;;) {
         if (optind >= argc)
@@ -7773,5 +7907,10 @@ int main(int argc, char **argv)

     main_loop();
     quit_timers();
+
+    /* argv was overwritten when parsing config file */
+    if (hd_found)
+    	free(argv);
+
     return 0;
 }

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: exec_dir.patch --]
[-- Type: text/x-patch; name="exec_dir.patch", Size: 6111 bytes --]

This patch allows QEMU to execute a directory with a special format.       

This patch allows storing command line options in a configuration file inside  
a directory and then directly executing that directory. A simple check is
included to prevent the configuration file to access image files outside
the executed directory. Extra command line options can be passed on invocation,
which will take precedence over the ones stored in the configuration file.

The configuration file specifies, on its first line, the image file to use.
The rest of the file specifies command line options separated by spaces or
newlines. Careful reconstruction of the command line makes sure the speficied
image file gets executed even if other image files were included later in the
configuration file.

Signed-off-by: Jorge Lucángeli Obes
---
diff --git a/qemu/vl.c b/qemu/vl.c
index fcc899b..88cefd2 100644
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -42,8 +42,8 @@
 #include <netinet/in.h>
 #include <dirent.h>
 #include <netdb.h>
-#ifdef _BSD
 #include <sys/stat.h>
+#ifdef _BSD
 #ifndef __APPLE__
 #include <libutil.h>
 #endif
@@ -6367,9 +6367,16 @@ int main_loop(void)
 void help(void)
 {
     printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
-           "usage: %s [options] [disk_image]\n"
+           "usage: %s [options] [disk_image|folder]\n"
            "\n"
+#ifdef _WIN32
            "'disk_image' is a raw hard image image for IDE hard disk 0\n"
+#else
+           "'disk_image' is a raw hard image image for IDE hard disk 0 or\n"
+           "'folder' is a folder with a file 'config' containing in the first line\n"
+           "the name of an image file inside the folder and in the rest of the file\n"
+           "options separated by ' ' or '\\n'\n"
+#endif
            "\n"
            "Standard options:\n"
            "-M machine      select emulated machine (-M ? for list)\n"
@@ -6892,6 +6899,20 @@ void qemu_get_launch_info(int *argc, char ***argv, int *opt_daemonize, const cha
     *opt_incoming = incoming;
 }
 
+char *dir_file_cat(const char *folder, const char *file) {
+    int foldlen = strlen(folder);
+    int filelen = strlen(file);
+    int reslen = foldlen + 1 + filelen + 1;
+
+    char *res = malloc(sizeof(char) * reslen);
+
+    pstrcpy(res, reslen, folder);
+    strncat(res, "/", 1);
+    strncat(res, file, filelen);
+
+    return res;
+}
+
 int main(int argc, char **argv)
 {
 #ifdef CONFIG_GDBSTUB
@@ -7003,7 +7024,120 @@ int main(int argc, char **argv)
 
     nb_nics = 0;
     /* default mac address of the first network interface */
+
+#ifndef _WIN32
+#define DIR_CMDLINE_SIZE 1<<13
+    int hd_found = 0;
+    char *dir, *opts;
+    struct stat *s = NULL;
+
+    optind = 1;
+    for(;;) {
+        if (optind >= argc)
+            break;
+
+        dir = argv[optind++];
+
+        if (dir[0] != '-') {
+            hd_found = 1;
+            break;
+        }
+    }
     
+    if (hd_found) {
+        s = malloc(sizeof(*s));
+
+        if (stat(dir, s) < 0) {
+            /* Error */
+            fprintf(stderr, "unable to stat: '%s'\n",
+                    dir);
+            exit(1);
+        }
+
+        if (S_ISDIR(s->st_mode)) {
+            /* The user specified a directory, search for ./config */
+            int configlen = strlen(dir);
+            configlen += 8; /* "/config\0" */
+            char *config = malloc(sizeof(char) * configlen);
+
+            pstrcpy(config, configlen, dir);
+            strncat(config, "/config", 7);
+
+            int fd_config;
+
+            if ((fd_config = open(config, 0)) < 0) {
+                /* Error */
+                if (errno == ENOENT)
+                    fprintf(stderr, "config file not found: '%s'\n",
+                            config);
+                else
+                    fprintf(stderr, "unable to open config file: '%s'\n",
+                            config);
+                exit(1);
+            }
+
+            opts = malloc(sizeof(char) * (DIR_CMDLINE_SIZE));
+
+            ssize_t readb = read(fd_config, opts, (DIR_CMDLINE_SIZE) - 1);
+
+            opts[readb] = '\0';
+
+            char *filename = strsep(&opts, "\n");
+
+            if (filename == NULL) {
+                /* Error */
+                fprintf(stderr, "malformed configuration file: '%s'\n",
+                        config);
+                exit(1);
+            } else if (strchr(filename, '/') != NULL) {
+                /* Error */
+                fprintf(stderr, "'%s' may point outside folder '%s'\n"
+                                "avoid using '/' in config file\n",
+                        filename, dir);
+                exit(1);
+            }
+
+            char tmpopts[DIR_CMDLINE_SIZE];
+            int done = 0;
+            unsigned int nbtoks = 0;
+            char *tok;
+ 
+            pstrcpy(tmpopts, DIR_CMDLINE_SIZE, opts);
+
+            do {
+                tok = strtok(nbtoks == 0? tmpopts : NULL, " \n");
+
+                if (tok != NULL)
+                    nbtoks++;
+                else
+                    done = 1;
+            } while (!done);
+
+            if (nbtoks > 0) {
+                char **argvprime = malloc((nbtoks + argc + 1) * sizeof(char*));
+
+                argvprime[0] = argv[0];
+
+                for (i = 0; i < nbtoks; i++)
+                    argvprime[i + 1] = strtok(i == 0? opts : NULL, " \n");
+
+                for (i = 1; i < argc; i++)
+                    argvprime[nbtoks + i] = argv[i];
+
+                argvprime[nbtoks + argc] = dir_file_cat(dir, filename);
+
+                argv = argvprime;
+                argc = nbtoks + argc + 1;
+
+                for (i = 0; i < argc; i++)
+                    printf("argv[%d] = %s\n", i, argv[i]);
+            }
+        }
+    }
+
+    free(s);
+#endif
+
     optind = 1;
     for(;;) {
         if (optind >= argc)
@@ -7773,5 +7907,10 @@ int main(int argc, char **argv)
 
     main_loop();
     quit_timers();
+
+    /* argv was overwritten when parsing config file */
+    if (hd_found)
+    	free(argv);
+
     return 0;
 }

             reply	other threads:[~2007-08-31 18:19 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-08-31 18:19 Jorge Lucángeli Obes [this message]
2007-08-31 18:54 ` [Qemu-devel] Re: [kvm-devel] [PATCH][RFC] Allowing QEMU to directly execute a directory (and storing command line options in it) Anthony Liguori
2007-08-31 19:05   ` Jorge Lucángeli Obes
2007-08-31 19:13     ` Anthony Liguori
2007-09-01 11:02   ` Markus Hitter
2007-09-01 14:26     ` Luke -Jr
2007-09-01 14:49       ` Andreas Färber
2007-09-01 14:39     ` Andreas Färber
2007-09-01 18:45       ` Jorge Lucángeli Obes
2007-09-01 19:52         ` Andreas Färber
2007-09-01 20:26           ` Jorge Lucángeli Obes
2007-09-03  9:19             ` Philip Boulain
2007-09-03 10:01               ` Christian Brunschen
2007-09-03 11:10                 ` Philip Boulain
2007-09-03 11:40                 ` Andreas Färber
2007-09-03 13:54                   ` Andreas Färber
2007-09-03 14:54               ` Luke -Jr

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=59abf66e0708311119p2b83fcffg31fac1c298cfc10a@mail.gmail.com \
    --to=t4m5yn@gmail.com \
    --cc=kvm-devel@lists.sourceforge.net \
    --cc=qemu-devel@nongnu.org \
    /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;
as well as URLs for NNTP newsgroup(s).