From: Anthony L. <ali...@us...> - 2008-05-13 21:19:14
|
There has been an awful lot of discussion about a configuration file with almost no general agreement except that one is strongly desired. I thought about it a bit, and I think a nice step would be to simply allow the current configuration parameters to be stored in a file using a pretty familiar format. I think this is pretty useful as-is. I think it also gives us a reasonable way to move forward that will keep everyone pretty happy. Here's a short example: qemu-system-x86_64 -hda ~/images/linux.img -snapshot -vnc :2 Would become `foo.qemu': # Main disk image hda=/home/anthony/images/linux.img # Redirect disk writes to a temporary image snapshot # Make the graphical display available on port 5902 vnc=:2 With: qemu-system-x86_64 -config foo.qemu Signed-off-by: Anthony Liguori <ali...@us...> diff --git a/qemu-doc.texi b/qemu-doc.texi index cca483c..4861fc0 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -395,6 +395,12 @@ Sets the @var{name} of the guest. This name will be display in the SDL window caption. The @var{name} will also be used for the VNC server. +@item -config @var{file} +Reads configuration options from @var{file}. The format of @var{file} is the +same as the command line options, except no dash ``-'' is required. Options +that take an argument are in the format @var{option=value}. A pound ``#'' +character can be used as a comment. + @end table Display options: diff --git a/vl.c b/vl.c index 67712f0..2eb39dd 100644 --- a/vl.c +++ b/vl.c @@ -7276,6 +7276,7 @@ static void help(int exitcode) "-clock force the use of the given methods for timer alarm.\n" " To see what timers are available use -clock ?\n" "-startdate select initial date of the clock\n" + "-config FILE read command line options from FILE\n" "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" @@ -7379,6 +7380,7 @@ enum { QEMU_OPTION_old_param, QEMU_OPTION_clock, QEMU_OPTION_startdate, + QEMU_OPTION_config, }; typedef struct QEMUOption { @@ -7490,6 +7492,7 @@ const QEMUOption qemu_options[] = { #endif { "clock", HAS_ARG, QEMU_OPTION_clock }, { "startdate", HAS_ARG, QEMU_OPTION_startdate }, + { "config", HAS_ARG, QEMU_OPTION_config }, { NULL }, }; @@ -7665,9 +7668,106 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) } #endif +static char **insert_opts(char **old_argv, int *old_argc, int index, + char **argv, int argc) +{ + char **new_argv; + + /* Allocate larger array */ + new_argv = realloc(old_argv, (*old_argc + argc) * sizeof(old_argv[0])); + if (new_argv == NULL) { + fprintf(stderr, "allocate failed in insert_opts\n"); + exit(1); + } + + /* move elements after insertion point to end of array */ + memmove(new_argv+index + argc, new_argv + index, + (*old_argc - index) * sizeof(argv[0])); + + /* copy in new elements */ + memcpy(new_argv + index, argv, argc * sizeof(argv[0])); + + *old_argc += argc; + + if (0) { /* for debugging */ + int i; + printf("argv[] = {"); + for (i = 0; i < *old_argc; i++) { + if (i) + printf(", "); + printf("\"%s\"", new_argv[i]); + } + printf("}\n"); + } + + return new_argv; +} + +static char **parse_config_file(const char *file, int *pargc) +{ + FILE *f; + char buffer[4096]; + char **argv = NULL; + int argc = 0; + + f = fopen(file, "r"); + if (f == NULL) + return NULL; + + while (fgets(buffer, sizeof(buffer), f)) { + char *ptr = buffer; + char *tok, *key, *val; + char *targv[2]; + int targc = 0; + + /* skip whitespace */ + while (isspace(*ptr)) ptr++; + + /* skip comments or empty lines */ + if (*ptr == '#' || *ptr == 0) + continue; + + /* trim new line and carriage return if necessary */ + tok = strchr(ptr, '\n'); + if (tok) + *tok = 0; + tok = strchr(ptr, '\r'); + if (tok) + *tok = 0; + + /* check if it has an argument */ + tok = strchr(ptr, '='); + if (tok) + *tok = 0; + + /* add key */ + if (asprintf(&key, "--%s", ptr) == -1) + return NULL; + targv[targc++] = key; + + /* add argument (optionally) */ + if (tok) { + if (asprintf(&val, "%s", tok + 1) == -1) + return NULL; + targv[targc++] = val; + } + + /* insert new arguments */ + argv = insert_opts(argv, &argc, argc, targv, targc); + if (argv == NULL) + return NULL; + } + + fclose(f); + + *pargc = argc; + + return argv; +} + #define MAX_NET_CLIENTS 32 -int main(int argc, char **argv) +int main(int orig_argc, char **orig_argv) { #ifdef CONFIG_GDBSTUB int use_gdbstub; @@ -7700,6 +7800,10 @@ int main(int argc, char **argv) int fds[2]; const char *pid_file = NULL; VLANState *vlan; + char **argv = NULL; + int argc = 0; + + argv = insert_opts(argv, &argc, 0, orig_argv, orig_argc); LIST_INIT (&vm_change_state_head); #ifndef _WIN32 @@ -8297,6 +8401,20 @@ int main(int argc, char **argv) } } break; + case QEMU_OPTION_config: { + char **config_argv; + int config_argc; + + config_argv = parse_config_file(optarg, &config_argc); + if (config_argv == NULL) { + fprintf(stderr, "failed to parse config file `%s'\n", optarg); + exit(1); + } + + argv = insert_opts(argv, &argc, optind, + config_argv, config_argc); + free(config_argv); + } break; } } } |