diff -r 20356d2fe017 Makefile.target --- a/Makefile.target Sun Feb 18 10:42:33 2007 -0600 +++ b/Makefile.target Sun Feb 18 15:37:03 2007 -0600 @@ -321,7 +321,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.o -VL_OBJS+=cutils.o migration.o +VL_OBJS+=cutils.o migration.o conf.o VL_OBJS+=block.o block-raw.o VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o ifdef CONFIG_WIN32 diff -r 20356d2fe017 hw/ide.c --- a/hw/ide.c Sun Feb 18 10:42:33 2007 -0600 +++ b/hw/ide.c Sun Feb 18 16:50:00 2007 -0600 @@ -2460,6 +2460,7 @@ void pci_cmd646_ide_init(PCIBus *bus, Bl for(i = 0; i < 4; i++) d->ide_if[i].pci_dev = (PCIDevice *)d; + ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], cmd646_set_irq, d, 0); ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], diff -r 20356d2fe017 hw/pc.c --- a/hw/pc.c Sun Feb 18 10:42:33 2007 -0600 +++ b/hw/pc.c Sun Feb 18 16:32:24 2007 -0600 @@ -898,23 +898,36 @@ static void pc_init1(int ram_size, int v if (i440fx_state) { i440fx_init_memory_mappings(i440fx_state); } -#if 0 - /* ??? Need to figure out some way for the user to - specify SCSI devices. */ - if (pci_enabled) { + + if (pci_enabled && config_get_bool(config_state, "lsi53c895a", "enabled", 0)) { void *scsi; BlockDriverState *bdrv; - + char name[256]; + const char *devices; + scsi = lsi_scsi_init(pci_bus, -1); - bdrv = bdrv_new("scsidisk"); - bdrv_open(bdrv, "scsi_disk.img", 0); - lsi_scsi_attach(scsi, bdrv, -1); - bdrv = bdrv_new("scsicd"); - bdrv_open(bdrv, "scsi_cd.iso", 0); - bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); - lsi_scsi_attach(scsi, bdrv, -1); - } -#endif + + devices = config_get(config_state, "lsi53c895a", "devices"); + while (devices && *devices) { + const char *ptr = strchr(devices, ' '); + if (ptr) { + memcpy(name, devices, ptr - devices); + name[ptr - devices] = 0; + devices = ptr + 1; + } else { + strcpy(name, devices); + devices = ptr; + } + + if (config_get_bool(config_state, name, "enabled", 0)) { + bdrv = bdrv_new(name); + bdrv_open(bdrv, config_get(config_state, name, "device"), 0); + if (config_get_bool(config_state, name, "cdrom", 0)) + bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); + lsi_scsi_attach(scsi, bdrv, -1); + } + } + } } static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, diff -r 20356d2fe017 vl.c --- a/vl.c Sun Feb 18 10:42:33 2007 -0600 +++ b/vl.c Sun Feb 18 16:49:25 2007 -0600 @@ -175,6 +175,8 @@ int autostart = 1; int autostart = 1; CharDriverState *cga_hd = NULL; const char *qemu_name; +const char *disk_section[] = {"ide0-master", "ide0-slave", + "ide1-master", "ide1-slave"}; /***********************************************************/ /* x86 ISA bus support */ @@ -6631,6 +6633,7 @@ enum { QEMU_OPTION_incoming, QEMU_OPTION_name, QEMU_OPTION_gui, + QEMU_OPTION_config, }; typedef struct QEMUOption { @@ -6722,6 +6725,7 @@ const QEMUOption qemu_options[] = { #endif { "name", HAS_ARG, QEMU_OPTION_name }, { "gui", 0, QEMU_OPTION_gui }, + { "config", HAS_ARG, QEMU_OPTION_config }, { NULL }, }; @@ -6935,6 +6939,41 @@ void qemu_get_launch_info(int *argc, cha *argv = saved_argv; *opt_daemonize = daemonize; *opt_incoming = incoming; +} + +ConfigState *config_state; + +static int load_config(const char *filename) +{ + int ret = -1; + int fd; + + fd = open(filename, O_RDONLY); + if (fd != -1) { + if (config_parse(config_state, fd) == -1) { + printf("error parsing config\n"); + } else + ret = 0; + close(fd); + } + + return ret; +} + +static void load_default_config(void) +{ + char *home, *path; + + config_state = config_new(); + load_config("/etc/qemurc"); + + home = getenv("HOME"); + if (!home) + return; + if (asprintf(&path, "%s/.qemurc", home) == -1) + return; + load_config(path); + free(path); } int main(int argc, char **argv) @@ -6968,6 +7007,8 @@ int main(int argc, char **argv) const char *pid_file = NULL; int gui = 0; + load_default_config(); + saved_argc = argc; saved_argv = argv; @@ -7050,9 +7091,7 @@ int main(int argc, char **argv) if (optind >= argc) break; r = argv[optind]; - if (r[0] != '-') { - hd_filename[0] = argv[optind++]; - } else { + { const QEMUOption *popt; optind++; @@ -7099,16 +7138,16 @@ int main(int argc, char **argv) initrd_filename = optarg; break; case QEMU_OPTION_hda: + config_set(config_state, NULL, "hda", optarg); + break; case QEMU_OPTION_hdb: + config_set(config_state, NULL, "hdb", optarg); + break; case QEMU_OPTION_hdc: + config_set(config_state, NULL, "hdc", optarg); + break; case QEMU_OPTION_hdd: - { - int hd_index; - hd_index = popt->index - QEMU_OPTION_hda; - hd_filename[hd_index] = optarg; - if (hd_index == cdrom_index) - cdrom_index = -1; - } + config_set(config_state, NULL, "hdd", optarg); break; case QEMU_OPTION_snapshot: snapshot = 1; @@ -7161,9 +7200,7 @@ int main(int argc, char **argv) kernel_cmdline = optarg; break; case QEMU_OPTION_cdrom: - if (cdrom_index >= 0) { - hd_filename[cdrom_index] = optarg; - } + config_set(config_state, NULL, "cdrom", optarg); break; case QEMU_OPTION_boot: boot_device = optarg[0]; @@ -7419,6 +7456,13 @@ int main(int argc, char **argv) case QEMU_OPTION_gui: gui = 1; break; + case QEMU_OPTION_config: + if (load_config(optarg) == -1) { + fprintf(stderr, + "Could not parse config file: %s\n", optarg); + exit(1); + } + break; } } } @@ -7508,19 +7552,8 @@ int main(int argc, char **argv) #endif linux_boot = (kernel_filename != NULL); - if (!linux_boot && - hd_filename[0] == '\0' && - (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && - fd_filename[0] == '\0') - help(); - /* boot to floppy or the default cd if no hard disk defined yet */ - if (hd_filename[0] == '\0' && boot_device == 'c') { - if (fd_filename[0] != '\0') - boot_device = 'a'; - else - boot_device = 'd'; - } + boot_device = 'c'; setvbuf(stdout, NULL, _IOLBF, 0); @@ -7580,24 +7613,27 @@ int main(int argc, char **argv) /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); - if (cdrom_index >= 0) { - bs_table[cdrom_index] = bdrv_new("cdrom"); - bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); - } /* open the virtual block devices */ for(i = 0; i < MAX_DISKS; i++) { - if (hd_filename[i]) { - if (!bs_table[i]) { - char buf[64]; - snprintf(buf, sizeof(buf), "hd%c", i + 'a'); - bs_table[i] = bdrv_new(buf); - } - if (bdrv_open(bs_table[i], hd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { + const char *filename; + + filename = config_get(config_state, disk_section[i], "device"); + if (*filename) { + char buf[64]; + + snprintf(buf, sizeof(buf), "hd%c", i + 'a'); + bs_table[i] = bdrv_new(buf); + + if (config_get_bool(config_state, disk_section[i], "cdrom", 0)) + bdrv_set_type_hint(bs_table[i], BDRV_TYPE_CDROM); + + if (bdrv_open(bs_table[i], filename, snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { fprintf(stderr, "qemu: could not open hard disk image '%s'\n", - hd_filename[i]); + filename); exit(1); } + if (i == 0 && cyls != 0) { bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs); bdrv_set_translation_hint(bs_table[i], translation); diff -r 20356d2fe017 vl.h --- a/vl.h Sun Feb 18 10:42:33 2007 -0600 +++ b/vl.h Sun Feb 18 15:47:22 2007 -0600 @@ -83,6 +83,9 @@ static inline char *realpath(const char #include "audio/audio.h" #include "cpu.h" +#include "conf.h" + +extern ConfigState *config_state; #endif /* !defined(QEMU_TOOL) */ diff -r 20356d2fe017 conf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf.c Sun Feb 18 16:31:48 2007 -0600 @@ -0,0 +1,383 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "conf.h" + +static char *strndup_and_trim(const char *ptr, size_t length) +{ + char *ret; + + while (isspace(*ptr)) { + ptr++; + length--; + } + + while (length && isspace(ptr[length - 1])) + length--; + + ret = malloc(length + 1); + memcpy(ret, ptr, length); + ret[length] = 0; + + return ret; +} + +static char *strappend(char *lhs, const char *rhs, size_t n_rhs) +{ + size_t n_lhs = lhs ? strlen(lhs) : 0; + char *ret; + + ret = realloc(lhs, n_lhs + n_rhs + 1); + if (ret == NULL) { + free(lhs); + return NULL; + } + + memcpy(ret + n_lhs, rhs, n_rhs); + ret[n_lhs + n_rhs] = 0; + + return ret; +} + +static const char *config_interpolate(ConfigState *s, ConfigSection *c, ConfigEntry *e) +{ + const char *ptr = e->value; + char *interpolation = NULL; + + if (e->interpolation) + return e->interpolation; + + /* actually interpolate */ + while (*ptr) { + if (*ptr != '%') { + interpolation = strappend(interpolation, ptr, 1); + ptr++; + continue; + } + + ptr++; + if (*ptr == '(') { + const char *end = strchr(ptr, ')'); + char *name; + const char *ivalue; + + if (!end) { + fprintf(stderr, "Missing interpolation terminator\n"); + return ""; + } + + name = strndup_and_trim(ptr + 1, end - ptr - 1); + + ivalue = config_get(s, c->name, name); + if (!ivalue || !*ivalue) + ivalue = config_get(s, "DEFAULTS", name); + + free(name); + ptr = end + 1; + + switch (*ptr) { + case 's': + interpolation = strappend(interpolation, ivalue, strlen(ivalue)); + ptr++; + break; + case 'b': + if (!*ivalue) + interpolation = strappend(interpolation, "false", 5); + else + interpolation = strappend(interpolation, "true", 4); + ptr++; + break; + default: + fprintf(stderr, "Unknown interpolation modifier %c\n", *ptr); + break; + } + } + } + + e->interpolation = interpolation; + + return e->interpolation; +} + +ConfigEntry *config_get_entry(ConfigSection *c, const char *key) +{ + ConfigEntry *e; + + for (e = c->entries; e; e = e->next) { + if (strcmp(e->key, key) == 0) + return e; + } + + return NULL; +} + +int config_get_bool(ConfigState *s, const char *section, const char *key, int def) +{ + const char *value; + + value = config_get(s, section, key); + if (!*value) + return def; + + if (strcasecmp(value, "true") == 0 || + strcasecmp(value, "on") == 0 || + strcasecmp(value, "1") == 0) + return 1; + else if (strcasecmp(value, "false") == 0 || + strcasecmp(value, "off") == 0 || + strcasecmp(value, "0") == 0) + return 0; + + fprintf(stderr, + "Unknown boolean value `%s' parsing `%s/%s'\n", + value, section, key); + + return def; +} + +const char *config_get(ConfigState *s, const char *section, const char *key) +{ + ConfigSection *c; + ConfigEntry *e; + + section = section ?: "DEFAULTS"; + + c = config_get_section(s, section); + if (!c) + return ""; + + e = config_get_entry(c, key); + if (e) + return config_interpolate(s, c, e); + + return ""; +} + +static ConfigEntry *config_set_entry(ConfigSection *c, + const char *key, const char *value) +{ + ConfigEntry *e; + + e = config_get_entry(c, key); + if (!e) { + e = malloc(sizeof(ConfigEntry)); + if (!e) + return NULL; + + e->key = strdup(key); + if (!e->key) { + free(e); + return NULL; + } + e->value = NULL; + e->interpolation = NULL; + + e->next = c->entries; + c->entries = e; + } + + free(e->value); + e->value = strdup(value); + + return e; +} + +ConfigSection *config_get_section(ConfigState *s, const char *name) +{ + ConfigSection *c; + + for (c = s->sections; c; c = c->next) { + if (strcmp(c->name, name) == 0) + return c; + } + + return NULL; +} + +static ConfigSection *config_add_section(ConfigState *s, const char *name) +{ + ConfigSection *c; + + c = config_get_section(s, name); + if (c) + return c; + + c = malloc(sizeof(ConfigSection)); + if (!c) + return NULL; + + c->name = strdup(name); + if (!c->name) { + free(c); + errno = ENOMEM; + return NULL; + } + + c->entries = NULL; + c->next = s->sections; + s->sections = c; + + return c; +} + +int config_set(ConfigState *s, const char *section, + const char *key, const char *value) +{ + ConfigSection *c; + + section = section ?: "DEFAULTS"; + + c = config_add_section(s, section); + if (!c) + return -1; + + if (!config_set_entry(c, key, value)) + return -1; + + return 0; +} + +typedef struct ConfigParserState +{ + int fd; + ConfigState *s; + ConfigSection *section; +} ConfigParserState; + +static char line[4096]; +static FILE *fp; + +static char *read_line(int fd) +{ + if (!fp) + fp = fdopen(fd, "r"); + + return fgets(line, sizeof(line), fp); +} + +static int config_parse_line(ConfigParserState *p, const char *line) +{ + const char *ptr = line; + + while (isspace(*ptr)) ptr++; + if (!*ptr || *ptr == '#') + return 0; + + if (*ptr == '[') { /* in a section */ + const char *end; + char *section; + + ptr++; + end = strchr(ptr, ']'); + if (!end) + return -1; + + section = strndup_and_trim(ptr, end - ptr); + p->section = config_add_section(p->s, section); + free(section); + } else { /* in a key/value pair */ + const char *equals = strchr(ptr, '='); + const char *end = ptr + strlen(ptr); + char *key, *value; + + if (!equals) + return -1; + + key = strndup_and_trim(ptr, equals - ptr); + value = strndup_and_trim(equals + 1, end - equals - 1); + + if (!key || !value) + return -1; + + config_set_entry(p->section, key, value); + + free(key); + free(value); + } + + return 0; +} + +ConfigState *config_new(void) +{ + ConfigState *s; + ConfigSection *defaults; + + s = malloc(sizeof(ConfigState)); + if (!s) { + return NULL; + } + + s->sections = NULL; + + defaults = config_add_section(s, "DEFAULTS"); + if (!defaults) { + free(s); + errno = ENOMEM; + return NULL; + } + + return s; +} + +int config_parse(ConfigState *s, int fd) +{ + ConfigParserState *p; + int ret = 0; + + p = malloc(sizeof(ConfigParserState)); + if (!p) + return -1; + + p->fd = fd; + p->s = s; + p->section = config_get_section(s, "DEFAULTS"); + fp = NULL; + + do { + char *line = read_line(fd); + if (line == NULL) + break; + + ret = config_parse_line(p, line); + if (ret == -1) + break; + } while (1); + + free(p); + + return ret; +} + +static void config_section_free(ConfigSection *c) +{ + while (c->entries) { + ConfigEntry *e = c->entries; + c->entries = e->next; + + free(e->key); + free(e->value); + free(e->interpolation); + free(e); + } +} + +void config_free(ConfigState *s) +{ + while (s->sections) { + ConfigSection *c = s->sections; + s->sections = c->next; + + config_section_free(c); + + free(c->name); + free(c); + } + + free(s); +} diff -r 20356d2fe017 conf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf.h Sun Feb 18 15:36:47 2007 -0600 @@ -0,0 +1,47 @@ +#ifndef _CONF_H_ +#define _CONF_H_ + +typedef struct ConfigEntry ConfigEntry; +typedef struct ConfigSection ConfigSection; +typedef struct ConfigState ConfigState; + +struct ConfigEntry +{ + char *key; + char *value; + char *interpolation; + + ConfigEntry *next; +}; + +struct ConfigSection +{ + char *name; + ConfigEntry *entries; + + ConfigSection *next; +}; + +struct ConfigState +{ + ConfigSection *sections; +}; + +ConfigState *config_new(void); + +int config_parse(ConfigState *s, int fd); + +void config_free(ConfigState *s); + +ConfigEntry *config_get_entry(ConfigSection *c, const char *key); + +const char *config_get(ConfigState *s, const char *section, const char *key); + +int config_get_bool(ConfigState *s, const char *section, const char *key, int def); + +ConfigSection *config_get_section(ConfigState *s, const char *name); + +int config_set(ConfigState *s, const char *section, + const char *key, const char *value); + +#endif