/* * 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, NULL, 'n'}, {"settings", 1, NULL, 's'}, {NULL, 0, NULL, 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) = { .name = "linux_args", .startup = linux_args_parse, .shutdown = linux_args_cleanup, };