From ddef2e1bc1da7a70ffbc03f68a16918b54f7622b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Jaroszy=C5=84ski?= Date: Mon, 31 May 2010 19:07:13 +0200 Subject: [PATCH] [linux] Add command line arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support qemu-like arguments for network setup: --net driver_name[,setting=value]* and global settings: --settings setting=value[,setting=value]* Signed-off-by: Piotr Jaroszyński Signed-off-by: Michael Brown --- src/arch/i386/prefix/linuxprefix.S | 3 + src/arch/x86_64/prefix/linuxprefix.S | 3 + src/hci/linux_args.c | 190 +++++++++++++++++++++++++++ src/include/hci/linux_args.h | 31 +++++ 4 files changed, 227 insertions(+) create mode 100644 src/hci/linux_args.c create mode 100644 src/include/hci/linux_args.h diff --git a/src/arch/i386/prefix/linuxprefix.S b/src/arch/i386/prefix/linuxprefix.S index 881c61df..b32b08f2 100644 --- a/src/arch/i386/prefix/linuxprefix.S +++ b/src/arch/i386/prefix/linuxprefix.S @@ -16,6 +16,9 @@ _start: pushl %edi // argv -> C arg2 pushl %esi // argc -> C arg1 + call save_args + + /* Our main doesn't use any arguments */ call main movl %eax, %ebx // rc -> syscall arg1 diff --git a/src/arch/x86_64/prefix/linuxprefix.S b/src/arch/x86_64/prefix/linuxprefix.S index 20163b8a..4aa0b840 100644 --- a/src/arch/x86_64/prefix/linuxprefix.S +++ b/src/arch/x86_64/prefix/linuxprefix.S @@ -13,6 +13,9 @@ _start: andq $~15, %rsp // 16-byte align the stack + call save_args + + /* Our main doesn't use any arguments */ call main movq %rax, %rdi // rc -> syscall arg1 diff --git a/src/hci/linux_args.c b/src/hci/linux_args.c new file mode 100644 index 00000000..0bce4af9 --- /dev/null +++ b/src/hci/linux_args.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2010 Piotr Jaroszyński + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +FILE_LICENCE(GPL2_OR_LATER); + +#include +#include +#include +#include +#include +#include +#include +#include + +/** Saved argc */ +static int saved_argc = 0; +/** Saved argv */ +static char ** saved_argv; + +/** + * Save argc and argv for later access. + * + * To be called by linuxprefix + */ +__asmcall void save_args(int argc, char **argv) +{ + saved_argc = argc; + saved_argv = argv; +} + +/** Supported command-line options */ +static struct option options[] = { + {"net", 1, 0, 'n'}, + {"settings", 1, 0, 's'}, + {0, 0, 0, 0} +}; + +/** + * Parse k1=v1[,k2=v2]* into linux_settings + */ +static int parse_kv(char *kv, struct list_head *list) +{ + char *token; + char *name; + char *value; + struct linux_setting *setting; + + while ((token = strsep(&kv, ",")) != NULL) { + name = strsep(&token, "="); + if (name == NULL) + continue; + value = token; + if (value == NULL) { + DBG("Bad parameter: '%s'\n", name); + continue; + } + + setting = malloc(sizeof(*setting)); + + if (! setting) + return -1; + + setting->name = name; + setting->value = value; + setting->applied = 0; + list_add(&setting->list, list); + } + + return 0; +} + +/** + * Parse --net arguments + * + * Format is --net driver_name[,name=value]* + */ +static int parse_net_args(char *args) +{ + char *driver; + struct linux_device_request *dev_request; + int rc; + + driver = strsep(&args, ","); + + if (strlen(driver) == 0) { + printf("Missing driver name"); + return -1; + } + + dev_request = malloc(sizeof(*dev_request)); + + dev_request->driver = driver; + INIT_LIST_HEAD(&dev_request->settings); + list_add_tail(&dev_request->list, &linux_device_requests); + + /* Parse rest of the settings */ + rc = parse_kv(args, &dev_request->settings); + + if (rc) + printf("Parsing net settings failed"); + + return rc; +} + +/** + * Parse --settings arguments + * + * Format is --settings name=value[,name=value]* + */ +static int parse_settings_args(char *args) +{ + return parse_kv(args, &linux_global_settings); +} + + +/** Parse passed command-line arguments */ +void linux_args_parse() +{ + int c; + int rc; + + reset_getopt(); + while (1) { + int option_index = 0; + + c = getopt_long(saved_argc, saved_argv, "", options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'n': + if ((rc = parse_net_args(optarg)) != 0) + return; + break; + case 's': + if ((rc = parse_settings_args(optarg)) != 0) + return; + break; + default: + return; + } + } + + return; +} + +/** Clean up requests and settings */ +void linux_args_cleanup(int flags __unused) +{ + struct linux_device_request *request; + struct linux_device_request *rtmp; + struct linux_setting *setting; + struct linux_setting *stmp; + + /* Clean up requests and their settings */ + list_for_each_entry_safe(request, rtmp, &linux_device_requests, list) { + list_for_each_entry_safe(setting, stmp, &request->settings, list) { + list_del(&setting->list); + free(setting); + } + list_del(&request->list); + free(request); + } + + /* Clean up global settings */ + list_for_each_entry_safe(setting, stmp, &linux_global_settings, list) { + list_del(&setting->list); + free(setting); + } +} + +struct startup_fn startup_linux_args __startup_fn(STARTUP_EARLY) = { + .startup = linux_args_parse, + .shutdown = linux_args_cleanup, +}; diff --git a/src/include/hci/linux_args.h b/src/include/hci/linux_args.h new file mode 100644 index 00000000..ae1ed052 --- /dev/null +++ b/src/include/hci/linux_args.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010 Piotr Jaroszyński + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _HCI_LINUX_ARGS_H +#define _HCI_LINUX_ARGS_H + +FILE_LICENCE(GPL2_OR_LATER); + +/** + * Save argc and argv for later access. + * + * To be called by linuxprefix + */ +extern __asmcall void save_args(int argc, char **argv); + +#endif /* _HCI_LINUX_ARGS_H */