diff --git a/client/Makefile.am b/client/Makefile.am index 357067ba6..3fb8f5197 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -53,6 +53,8 @@ endif wicked_SOURCES = \ arputil.c \ compat.c \ + duid.c \ + iaid.c \ ifup.c \ ifdown.c \ ifcheck.c \ @@ -65,14 +67,13 @@ wicked_SOURCES = \ tester.c noinst_HEADERS = \ - arputil.h \ ifup.h \ ifdown.h \ ifcheck.h \ ifreload.h \ ifstatus.h \ + main.h \ reachable.h \ - tester.h \ wicked-client.h install-data-local: diff --git a/client/arputil.h b/client/arputil.h deleted file mode 100644 index 17608dfc9..000000000 --- a/client/arputil.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * wicked client arp actions and utilities - * - * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. - * - * 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 - * (at your option) 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, see or write - * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Authors: - * Marius Tomaschewski - * - */ -#ifndef __WICKED_CLIENT_ARPUTIL_H__ -#define __WICKED_CLIENT_ARPUTIL_H__ - -extern int ni_do_arp(int argc, char **argv); - -#endif /* __WICKED_CLIENT_ARPUTIL_H__ */ diff --git a/client/duid.c b/client/duid.c new file mode 100644 index 000000000..5bc4f8336 --- /dev/null +++ b/client/duid.c @@ -0,0 +1,837 @@ +/* + * wicked client main commands + * + * Copyright (C) 2017 SUSE LINUX GmbH, Nuernberg, Germany. + * + * 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 + * (at your option) 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, see . + * + * Authors: + * Marius Tomaschewski + * Nirmoy Das + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "duid.h" + + +static int +ni_do_duid_dump(int argc, char **argv) +{ + enum { OPT_HELP = 'h' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + ni_var_array_t vars = NI_VAR_ARRAY_INIT; + ni_duid_map_t *map = NULL; + ni_var_t *var; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) { + switch (opt) { + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options]\n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + "\n", argv[0]); + goto cleanup; + } + } + if (argc - optind) + goto usage; + + status = NI_WICKED_RC_ERROR; + if (!(map = ni_duid_map_load(NULL))) + goto cleanup; + + status = NI_WICKED_RC_SUCCESS; + if (ni_duid_map_to_vars(map, &vars)) { + unsigned int i; + + for (i = 0, var = vars.data; i < vars.count; ++i, ++var) { + printf("%s\t%s\n", var->name ? var->name : "default", var->value); + } + ni_var_array_destroy(&vars); + } + +cleanup: + ni_duid_map_free(map); + return status; +} + +static int +ni_do_duid_get(int argc, char **argv) +{ + enum { OPT_HELP = 'h', OPT_SCOPE = 's' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { "scope", required_argument, NULL, OPT_SCOPE }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + ni_duid_map_t *map = NULL; + const char *scope = NULL; + const char *duid = NULL; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+hs:", options, NULL)) != EOF) { + switch (opt) { + case OPT_SCOPE: + if (optarg && !ni_string_eq(optarg, "default")) + scope = optarg; + break; + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options]\n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + " --scope show device specific duid instead of default\n" + "\n", argv[0]); + goto cleanup; + } + } + if (argc - optind) + goto usage; + + if (scope && !ni_netdev_name_is_valid(scope)) { + fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], + ni_print_suspect(scope, ni_string_len(scope))); + status = NI_WICKED_RC_ERROR; + goto cleanup; + } + + status = NI_WICKED_RC_ERROR; + if (!(map = ni_duid_map_load(NULL))) + goto cleanup; + + status = NI_WICKED_RC_NO_DEVICE; + if (ni_duid_map_get_duid(map, scope, &duid, NULL)) { + printf("%s\t%s\n", scope ? scope : "default", duid); + status = NI_WICKED_RC_SUCCESS; + } else + if (scope && ni_duid_map_get_duid(map, NULL, &duid, NULL)) { + printf("%s\t%s\n", "default", duid); + status = NI_WICKED_RC_SUCCESS; + } + +cleanup: + ni_duid_map_free(map); + return status; +} + +static int +ni_do_duid_del(int argc, char **argv) +{ + enum { OPT_HELP = 'h', OPT_SCOPE = 's' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { "scope", required_argument, NULL, OPT_SCOPE }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + ni_duid_map_t *map = NULL; + const char *scope = NULL; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+hs:", options, NULL)) != EOF) { + switch (opt) { + case OPT_SCOPE: + if (optarg && !ni_string_eq(optarg, "default")) + scope = optarg; + break; + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options]\n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + " --scope delete device specific duid instead of default\n" + "\n", argv[0]); + goto cleanup; + } + } + if (argc - optind) + goto usage; + + if (scope && !ni_netdev_name_is_valid(scope)) { + fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], + ni_print_suspect(scope, ni_string_len(scope))); + status = NI_WICKED_RC_ERROR; + goto cleanup; + } + + status = NI_WICKED_RC_ERROR; + if (!(map = ni_duid_map_load(NULL))) + goto cleanup; + + if (ni_duid_map_del(map, scope)) { + if (ni_duid_map_save(map)) + status = NI_WICKED_RC_SUCCESS; + } + +cleanup: + ni_duid_map_free(map); + return status; +} + +static int +ni_do_duid_set(int argc, char **argv) +{ + enum { OPT_HELP = 'h', OPT_SCOPE = 's' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { "scope", required_argument, NULL, OPT_SCOPE }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + ni_duid_map_t *map = NULL; + const char *scope = NULL; + const char *duid = NULL; + ni_opaque_t raw; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+hs:", options, NULL)) != EOF) { + switch (opt) { + case OPT_SCOPE: + if (optarg && !ni_string_eq(optarg, "default")) + scope = optarg; + break; + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options] \n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + " --scope set device specific duid instead of default\n" + "\n" + "Arguments:\n" + " duid duid string as colon-separated hex bytes\n" + "\n", argv[0]); + goto cleanup; + } + } + switch (argc - optind) { + case 1: + duid = argv[optind++]; + break; + default: + goto usage; + } + + if (scope && !ni_netdev_name_is_valid(scope)) { + fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], + ni_print_suspect(scope, ni_string_len(scope))); + status = NI_WICKED_RC_ERROR; + goto cleanup; + } + if (ni_string_empty(duid) || !ni_duid_parse_hex(&raw, duid)) { + fprintf(stderr, "%s: unable to parse duid hex string argument\n", argv[0]); + status = NI_WICKED_RC_ERROR; + goto cleanup; + } + + status = NI_WICKED_RC_ERROR; + if (!(map = ni_duid_map_load(NULL))) + goto cleanup; + + if (!ni_duid_map_set(map, scope, duid)) + goto cleanup; + + if (!ni_duid_map_save(map)) + goto cleanup; + + status = NI_WICKED_RC_SUCCESS; + +cleanup: + ni_duid_map_free(map); + return status; +} + +static int +ni_do_duid_create_update(const char *scope, const char *duid) +{ + int status = NI_WICKED_RC_ERROR; + ni_duid_map_t *map = NULL; + + if (!(map = ni_duid_map_load(NULL))) + goto cleanup; + + if (!ni_duid_map_set(map, scope, duid)) + goto cleanup; + + if (!ni_duid_map_save(map)) + goto cleanup; + + status = NI_WICKED_RC_SUCCESS; + +cleanup: + ni_duid_map_free(map); + return status; +} + +static int +ni_do_duid_create_en(int argc, char **argv) +{ + enum { OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { "scope", required_argument, NULL, OPT_SCOPE }, + { "update", no_argument, NULL, OPT_UPDATE }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + const char *scope = NULL; + ni_bool_t update = FALSE; + const char *en = NULL; + const char *id = NULL; + const char *hex = NULL; + ni_opaque_t raw; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+hs:u", options, NULL)) != EOF) { + switch (opt) { + case OPT_UPDATE: + update = TRUE; + break; + case OPT_SCOPE: + if (optarg && !ni_string_eq(optarg, "default")) + scope = optarg; + break; + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options] \n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + " --scope create device specific duid instead of default\n" + " --update create a duid and update duid map file\n" + "\n" + "Arguments:\n" + " enterprise-number IANA assigned 32bit enterprise number\n" + " machine-identifier machine identifier as colon-separated hex bytes\n" + "\n", argv[0]); + goto cleanup; + } + } + switch (argc - optind) { + case 2: + en = argv[optind++]; + id = argv[optind++]; + break; + default: + goto usage; + } + + status = NI_WICKED_RC_ERROR; + if (scope && !ni_netdev_name_is_valid(scope)) { + fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], + ni_print_suspect(scope, ni_string_len(scope))); + goto cleanup; + } + + if (!ni_duid_create_en(&raw, en, id)) { + fprintf(stderr, "%s: cannot create duid using enterprise-number '%s' and identifier '%s'\n", + argv[0], en, id); + goto cleanup; + } + + hex = raw.len ? ni_duid_print_hex(&raw) : NULL; + if (ni_string_empty(hex)) { + fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]); + goto cleanup; + } + + if (update) { + status = ni_do_duid_create_update(scope, hex); + if (status != NI_WICKED_RC_SUCCESS) { + fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]); + goto cleanup; + } + } + + printf("%s\t%s\n", scope ? scope : "default", hex); + status = NI_WICKED_RC_SUCCESS; + +cleanup: + return status; +} + +static inline void +ni_do_duid_create_ll_print_hwtypes(FILE *out) +{ + const ni_intmap_t *hwtype = ni_duid_hwtype_map(); + unsigned int alias = -1U; + + fprintf(out, "Supported hardware types are:\n"); + for (; hwtype && hwtype->name; ++hwtype) { + if (alias == hwtype->value) + continue; + alias = hwtype->value; + fprintf(out, " %s\n", hwtype->name); + } +} + +static int +ni_do_duid_create_ll_type(uint16_t type, int argc, char **argv) +{ + enum { OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { "scope", required_argument, NULL, OPT_SCOPE }, + { "update", no_argument, NULL, OPT_UPDATE }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + const char *scope = NULL; + ni_bool_t update = FALSE; + const char *ifname = NULL; + const char *hwtype = NULL; + const char *hwaddr = NULL; + const char *hex = NULL; + ni_opaque_t raw; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+hs:u", options, NULL)) != EOF) { + switch (opt) { + case OPT_UPDATE: + update = TRUE; + break; + case OPT_SCOPE: + if (optarg && !ni_string_eq(optarg, "default")) + scope = optarg; + break; + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options] [ [ifname] | ]\n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + " --scope create device specific duid instead of default\n" + " --update create a duid and update duid map file\n" + "\n" + "Arguments:\n" + " ifname get hardware type and address from interface\n" + " htwype hardware type to use in the duid\n" + " htaddr hardware address to use in the duid\n" + "\n", argv[0]); + ni_do_duid_create_ll_print_hwtypes(stderr); + goto cleanup; + } + } + switch (argc - optind) { + case 2: + hwtype = argv[optind++]; + hwaddr = argv[optind++]; + break; + case 1: + ifname = argv[optind++]; + break; + case 0: + break; + default: + goto usage; + } + + status = NI_WICKED_RC_ERROR; + if (scope && !ni_netdev_name_is_valid(scope)) { + fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], + ni_print_suspect(scope, ni_string_len(scope))); + goto cleanup; + } + + if (hwtype || hwaddr) { + switch (type) { + case NI_DUID_TYPE_LL: + if (ni_duid_create_ll(&raw, hwtype, hwaddr)) + status = NI_WICKED_RC_SUCCESS; + break; + case NI_DUID_TYPE_LLT: + if (ni_duid_create_llt(&raw, hwtype, hwaddr)) + status = NI_WICKED_RC_SUCCESS; + break; + default: + break; + } + if (status != NI_WICKED_RC_SUCCESS) { + fprintf(stderr, "%s: cannot create duid using hardware type '%s' and address '%s'\n", + argv[0], hwtype, hwaddr); + goto cleanup; + } + } else { + ni_netconfig_t *nc = ni_global_state_handle(1); + ni_netdev_t *dev = NULL; + + if (!nc) { + fprintf(stderr, "%s: cannot retrieve interface properties", argv[0]); + goto cleanup; + } + + if (ifname) { + dev = ni_netdev_by_name(nc, ifname); + if (!dev || !ni_duid_create_from_device(&raw, type, dev)) { + hwtype = dev ? ni_duid_hwtype_to_name(dev->link.hwaddr.type) : "missing"; + fprintf(stderr, "%s: unable to create %s duid using %s device '%s'\n", + argv[0], ni_duid_type_to_name(type), + hwtype ? hwtype : "unsupported", ifname); + goto cleanup; + } + } else { + dev = scope ? ni_netdev_by_name(nc, scope) : NULL; + if (!ni_duid_create_pref_device(&raw, type, nc, dev)) { + fprintf(stderr, "%s: unable to create any %s duid (no usable devices)", + argv[0], ni_duid_type_to_name(type)); + goto cleanup; + } + } + } + + status = NI_WICKED_RC_ERROR; + hex = raw.len ? ni_duid_print_hex(&raw) : NULL; + if (ni_string_empty(hex)) { + fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]); + goto cleanup; + } + + if (update) { + status = ni_do_duid_create_update(scope, hex); + if (status != NI_WICKED_RC_SUCCESS) { + fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]); + goto cleanup; + } + } + + printf("%s\t%s\n", scope ? scope : "default", hex); + status = NI_WICKED_RC_SUCCESS; + +cleanup: + return status; +} + +static inline int +ni_do_duid_create_ll(int argc, char **argv) +{ + return ni_do_duid_create_ll_type(NI_DUID_TYPE_LL, argc, argv); +} + +static inline int +ni_do_duid_create_llt(int argc, char **argv) +{ + return ni_do_duid_create_ll_type(NI_DUID_TYPE_LLT, argc, argv); +} + +static int +ni_do_duid_create_uuid(int argc, char **argv) +{ + enum { OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u', + OPT_MACHINE_ID = 'm', OPT_PRODUCT_ID = 'p' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { "scope", required_argument, NULL, OPT_SCOPE }, + { "update", no_argument, NULL, OPT_UPDATE }, + { "machine-id", optional_argument, NULL, OPT_MACHINE_ID }, + { "product-id", optional_argument, NULL, OPT_PRODUCT_ID }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + const char *scope = NULL; + ni_bool_t update = FALSE; + unsigned int type = 0; + const char *from = NULL; + const char *hex = NULL; + ni_opaque_t raw; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+hs:um::p::", options, NULL)) != EOF) { + switch (opt) { + case OPT_MACHINE_ID: + type = OPT_MACHINE_ID; + from = optarg; + break; + case OPT_PRODUCT_ID: + type = OPT_PRODUCT_ID; + from = optarg; + break; + case OPT_UPDATE: + update = TRUE; + break; + case OPT_SCOPE: + if (optarg && !ni_string_eq(optarg, "default")) + scope = optarg; + break; + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options] [uuid]\n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + " --scope create device specific duid instead of default\n" + " --update create a duid and update duid map file\n" + " --machine-id[=FILE] import uuid from /etc/machine-id file\n" + " --product-id[=FILE] import uuid from dmi product-id sysfs file\n" + "\n" + "Arguments:\n" + " uuid create duid using specified uuid-string\n" + "\n", argv[0]); + goto cleanup; + } + } + switch (type) { + case OPT_MACHINE_ID: + case OPT_PRODUCT_ID: + if ((argc - optind) != 0) + goto usage; + break; + default: + if ((argc - optind) != 1) + goto usage; + from = argv[optind++]; + break; + } + + status = NI_WICKED_RC_ERROR; + if (scope && !ni_netdev_name_is_valid(scope)) { + fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], + ni_print_suspect(scope, ni_string_len(scope))); + goto cleanup; + } + + switch (type) { + case OPT_MACHINE_ID: + if (!ni_duid_create_uuid_machine_id(&raw, from)) { + fprintf(stderr, "%s: cannot create duid by importing uuid from machine-id%s%s", + argv[0], from ? " file ": "", from ? from : ""); + goto cleanup; + } + break; + case OPT_PRODUCT_ID: + if (!ni_duid_create_uuid_dmi_product_id(&raw, from)) { + fprintf(stderr, "%s: cannot create duid by importing uuid from dmi product-id%s%s", + argv[0], from ? " file ": "", from ? from : ""); + goto cleanup; + } + break; + default: + if (!ni_duid_create_uuid_string(&raw, from)) { + fprintf(stderr, "%s: cannot create duid by importing uuid string '%s'", + argv[0], from); + goto cleanup; + } + break; + } + + hex = raw.len ? ni_duid_print_hex(&raw) : NULL; + if (ni_string_empty(hex)) { + fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]); + goto cleanup; + } + + if (update) { + status = ni_do_duid_create_update(scope, hex); + if (status != NI_WICKED_RC_SUCCESS) { + fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]); + goto cleanup; + } + } + + printf("%s\t%s\n", scope ? scope : "default", hex); + status = NI_WICKED_RC_SUCCESS; + +cleanup: + return status; +} + +static int +ni_do_duid_create(int argc, char **argv) +{ + enum { OPT_HELP = 'h' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + const char *type = NULL; + char *command = NULL; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) { + switch (opt) { + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options] ...\n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + "\n", argv[0]); + goto cleanup; + } + } + if (optind >= argc || ni_string_empty(argv[optind])) { + fprintf(stderr, "%s: missing duid type argument\n\n", argv[0]); + goto usage; + } + + type = argv[optind]; + ni_string_printf(&command, "%s %s", argv[0], type); + argv[optind] = command; + + if (ni_string_eq(type, "ll")) { + status = ni_do_duid_create_ll(argc - optind, argv + optind); + } else + if (ni_string_eq(type, "llt")) { + status = ni_do_duid_create_llt(argc - optind, argv + optind); + } else + if (ni_string_eq(type, "en")) { + status = ni_do_duid_create_en(argc - optind, argv + optind); + } else + if (ni_string_eq(type, "uuid")) { + status = ni_do_duid_create_uuid(argc - optind, argv + optind); + } else { + argv[optind] = (char *)type; + fprintf(stderr, "%s: unsupported duid type '%s'\n", argv[0], + ni_print_suspect(type, ni_string_len(type))); + goto usage; + } + argv[optind] = (char *)type; + +cleanup: + ni_string_free(&command); + return status; +} + +int +ni_do_duid(const char *caller, int argc, char **argv) +{ + enum { OPT_HELP = 'h' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + char *program = NULL; + char *command = NULL; + const char *cmd; + + ni_string_printf(&program, "%s %s", caller ? caller : "wicked", + argv[0] ? argv[0] : "duid"); + + optind = 1; + argv[0] = program; + while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) { + switch (opt) { + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "\nUsage:\n" + " %s [common options] [...]\n" + "\n" + "Common options:\n" + " --help, -h show this help text and exit.\n" + "\n" + "Supported commands:\n" + " help show this help text and exit.\n" + " dump, show show the duid map contents\n" + " get [options] get current duid\n" + " del [options] delete current duid\n" + " set [options] set/update the duid\n" + " create [...] create a new duid\n" + "\n", argv[0]); + goto cleanup; + } + } + + if (optind >= argc || ni_string_empty(argv[optind])) { + fprintf(stderr, "%s: missing command argument\n", argv[0]); + goto usage; + } + + cmd = argv[optind]; + ni_string_printf(&command, "%s %s", program, cmd); + argv[optind] = command; + + if (ni_string_eq(cmd, "help")) { + argv[optind] = (char *)cmd; + status = NI_WICKED_RC_SUCCESS; + goto usage; + } else + if (ni_string_eq(cmd, "dump")) { + status = ni_do_duid_dump(argc - optind, argv + optind); + } else + if (ni_string_eq(cmd, "get")) { + status = ni_do_duid_get (argc - optind, argv + optind); + } else + if (ni_string_eq(cmd, "set")) { + status = ni_do_duid_set (argc - optind, argv + optind); + } else + if (ni_string_eq(cmd, "del")) { + status = ni_do_duid_del (argc - optind, argv + optind); + } else + if (ni_string_eq(cmd, "create")) { + status = ni_do_duid_create (argc - optind, argv + optind); + } else { + argv[optind] = (char *)cmd; + fprintf(stderr, "%s: unsupported command %s\n", program, (char *)cmd); + goto usage; + } + argv[optind] = (char *)cmd; + +cleanup: + argv[0] = NULL; + ni_string_free(&command); + ni_string_free(&program); + return status; +} + diff --git a/client/iaid.c b/client/iaid.c new file mode 100644 index 000000000..97d033fdc --- /dev/null +++ b/client/iaid.c @@ -0,0 +1,458 @@ +/* + * wicked client iaid commands + * + * Copyright (C) 2017 SUSE LINUX GmbH, Nuernberg, Germany. + * + * 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 + * (at your option) 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, see . + * + * Authors: + * Marius Tomaschewski + * Nirmoy Das + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "iaid.h" + +static int +ni_do_iaid_dump(int argc, char **argv) +{ + enum { OPT_HELP = 'h' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + ni_var_array_t vars = NI_VAR_ARRAY_INIT; + ni_iaid_map_t *map = NULL; + const ni_var_t *var; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) { + switch (opt) { + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options]\n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + "\n", argv[0]); + goto cleanup; + } + } + if (argc - optind) + goto usage; + + status = NI_WICKED_RC_ERROR; + if (!(map = ni_iaid_map_load(NULL))) + goto cleanup; + + status = NI_WICKED_RC_SUCCESS; + if (ni_iaid_map_to_vars(map, &vars)) { + unsigned int i; + + for (i = 0, var = vars.data; i < vars.count; ++i, ++var) { + printf("%s\t%s\n", var->name, var->value); + } + } + ni_var_array_destroy(&vars); + +cleanup: + ni_iaid_map_free(map); + return status; +} + +static int +ni_do_iaid_get(int argc, char **argv) +{ + enum { OPT_HELP = 'h' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + ni_iaid_map_t *map = NULL; + const char *ifname = NULL; + unsigned int iaid; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) { + switch (opt) { + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options] \n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + "\n", argv[0]); + goto cleanup; + } + } + switch (argc - optind) { + case 1: + ifname = argv[optind++]; + break; + default: + goto usage; + } + + if (!ni_netdev_name_is_valid(ifname)) { + fprintf(stderr, "%s: invalid interface name '%s'\n", argv[0], + ni_print_suspect(ifname, ni_string_len(ifname))); + status = NI_WICKED_RC_ERROR; + goto cleanup; + } + + status = NI_WICKED_RC_ERROR; + if (!(map = ni_iaid_map_load(NULL))) + goto cleanup; + + status = NI_WICKED_RC_NO_DEVICE; + if (ni_iaid_map_get_iaid(map, ifname, &iaid)) { + printf("%s\t%u\n", ifname, iaid); + status = NI_WICKED_RC_SUCCESS; + } + +cleanup: + ni_iaid_map_free(map); + return status; +} + +static int +ni_do_iaid_del(int argc, char **argv) +{ + enum { OPT_HELP = 'h' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + ni_iaid_map_t *map = NULL; + const char *ifname = NULL; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) { + switch (opt) { + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options] \n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + "\n", argv[0]); + goto cleanup; + } + } + switch (argc - optind) { + case 1: + ifname = argv[optind++]; + break; + default: + goto usage; + } + + if (!ni_netdev_name_is_valid(ifname)) { + fprintf(stderr, "%s: invalid interface name '%s'\n", argv[0], + ni_print_suspect(ifname, ni_string_len(ifname))); + status = NI_WICKED_RC_ERROR; + goto cleanup; + } + + status = NI_WICKED_RC_ERROR; + if (!(map = ni_iaid_map_load(NULL))) + goto cleanup; + + status = NI_WICKED_RC_NO_DEVICE; + if (ni_iaid_map_del_name(map, ifname)) { + if (ni_iaid_map_save(map)) + status = NI_WICKED_RC_SUCCESS; + } + +cleanup: + ni_iaid_map_free(map); + return status; +} + +static int +ni_do_iaid_set(int argc, char **argv) +{ + enum { OPT_HELP = 'h', OPT_UNIQUE = 'U' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { "unique", no_argument, NULL, OPT_UNIQUE }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + ni_iaid_map_t *map = NULL; + const char *ifname = NULL; + const char *ifiaid = NULL; + ni_bool_t unique = FALSE; + const char *conflict; + unsigned int iaid; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+hU", options, NULL)) != EOF) { + switch (opt) { + case OPT_UNIQUE: + unique = TRUE; + break; + + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options] \n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + "\n", argv[0]); + goto cleanup; + } + } + switch (argc - optind) { + case 2: + ifname = argv[optind++]; + ifiaid = argv[optind++]; + break; + default: + goto usage; + } + + if (!ni_netdev_name_is_valid(ifname)) { + fprintf(stderr, "%s: invalid interface name '%s'\n", argv[0], + ni_print_suspect(ifname, ni_string_len(ifname))); + status = NI_WICKED_RC_ERROR; + goto cleanup; + } + + if (ni_parse_uint(ifiaid, &iaid, 0) != 0) { + fprintf(stderr, "%s: unable to parse iaid argument '%s'\n", argv[0], + ni_print_suspect(ifiaid, ni_string_len(ifiaid))); + status = NI_WICKED_RC_ERROR; + goto cleanup; + } + + status = NI_WICKED_RC_ERROR; + if (!(map = ni_iaid_map_load(NULL))) + goto cleanup; + + if (unique && ni_iaid_map_get_name(map, iaid, &conflict)) { + fprintf(stderr, "%s: iaid %u in use by '%s'\n", argv[0], iaid, conflict); + status = NI_WICKED_RC_NO_DEVICE; + goto cleanup; + } + + if (ni_iaid_map_set(map, ifname, iaid)) { + if (ni_iaid_map_save(map)) + status = NI_WICKED_RC_SUCCESS; + } + + if (status == NI_WICKED_RC_SUCCESS) + printf("%s\t%u\n", ifname, iaid); + +cleanup: + ni_iaid_map_free(map); + return status; +} + +static int +ni_do_iaid_create(int argc, char **argv) +{ + enum { OPT_HELP = 'h', OPT_UPDATE = 'u' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { "update", no_argument, NULL, OPT_UPDATE }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + ni_iaid_map_t *map = NULL; + const char *ifname = NULL; + ni_bool_t update = TRUE; + ni_netconfig_t *nc; + ni_netdev_t *dev; + unsigned int iaid; + + optind = 1; + while ((opt = getopt_long(argc, argv, "+hu", options, NULL)) != EOF) { + switch (opt) { + case OPT_UPDATE: + update = TRUE; + break; + + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "Usage: %s [options] \n" + "\n" + "Options:\n" + " --help, -h show this help text and exit.\n" + "\n", argv[0]); + goto cleanup; + } + } + switch (argc - optind) { + case 1: + ifname = argv[optind++]; + break; + default: + goto usage; + } + + if (ni_netdev_name_is_valid(ifname)) { + fprintf(stderr, "%s: invalid interface name '%s'\n", argv[0], + ni_print_suspect(ifname, ni_string_len(ifname))); + status = NI_WICKED_RC_ERROR; + goto cleanup; + } + + if (!(nc = ni_global_state_handle(1))) { + fprintf(stderr, "%s: cannot retrieve interface properties", argv[0]); + goto cleanup; + } + + if (!(dev = ni_netdev_by_name(nc, ifname))) { + fprintf(stderr, "%s: interface %s does not exists\n", argv[0], ifname); + goto cleanup; + } + + if (!(map = ni_iaid_map_load(NULL))) + goto cleanup; + + if (!ni_iaid_create(&iaid, dev, map)) { + fprintf(stderr, "%s: cannot create iaid for interface %s\n", argv[0], ifname); + goto cleanup; + } + + if (update && (!ni_iaid_map_set(map, ifname, iaid) || !ni_iaid_map_save(map))) { + fprintf(stderr, "%s: unable to update iaid map file\n", argv[0]); + goto cleanup; + } + + printf("%s\t%u\n", ifname, iaid); + status = NI_WICKED_RC_SUCCESS; + +cleanup: + ni_iaid_map_free(map); + return status; +} + +int +ni_do_iaid(const char *caller, int argc, char **argv) +{ + enum { OPT_HELP = 'h' }; + static struct option options[] = { + { "help", no_argument, NULL, OPT_HELP }, + { NULL, no_argument, NULL, 0 } + }; + int opt = 0, status = NI_WICKED_RC_USAGE; + char *program = NULL; + char *command = NULL; + const char *cmd; + + ni_string_printf(&program, "%s %s", caller ? caller : "wicked", + argv[0] ? argv[0] : "iaid"); + + optind = 1; + argv[0] = program; + while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) { + switch (opt) { + case OPT_HELP: + status = NI_WICKED_RC_SUCCESS; + default: + usage: + fprintf(stderr, + "\nUsage:\n" + " %s [common options] command [...]\n" + "\n" + "Common options:\n" + " --help, -h show this help text and exit.\n" + "\n" + "Supported Commands:\n" + " help show this help text and exit.\n" + " dump show the iaid map contents\n" + " get get current device iaid\n" + " del delete current device iaid\n" + " set set/update the device iaid\n" + " create create a new device iaid\n" + "\n", argv[0]); + goto cleanup; + } + } + + if (optind >= argc || ni_string_empty(argv[optind])) { + fprintf(stderr, "%s: missing command\n", program); + goto usage; + } + + cmd = argv[optind]; + ni_string_printf(&command, "%s %s", program, cmd); + argv[optind] = command; + + if (ni_string_eq(cmd, "help")) { + argv[optind] = (char *)cmd; + status = NI_WICKED_RC_SUCCESS; + goto usage; + } else + if (ni_string_eq(cmd, "dump")) { + status = ni_do_iaid_dump(argc - optind, argv + optind); + } else + if (ni_string_eq(cmd, "get")) { + status = ni_do_iaid_get (argc - optind, argv + optind); + } else + if (ni_string_eq(cmd, "del")) { + status = ni_do_iaid_del (argc - optind, argv + optind); + } else + if (ni_string_eq(cmd, "set")) { + status = ni_do_iaid_set (argc - optind, argv + optind); + } else + if (ni_string_eq(cmd, "create")) { + status = ni_do_iaid_create (argc - optind, argv + optind); + } else { + argv[optind] = (char *)cmd; + fprintf(stderr, "%s: unsupported command %s\n", program, cmd); + goto usage; + } + argv[optind] = (char *)cmd; + +cleanup: + argv[0] = NULL; + ni_string_free(&command); + ni_string_free(&program); + return status; +} + diff --git a/client/main.c b/client/main.c index b57634558..6fd89f7f8 100644 --- a/client/main.c +++ b/client/main.c @@ -55,8 +55,7 @@ #include "ifcheck.h" #include "ifreload.h" #include "ifstatus.h" -#include "arputil.h" -#include "tester.h" +#include "main.h" enum { OPT_HELP, @@ -180,6 +179,8 @@ main(int argc, char **argv) " convert [subcommand]\n" " xpath [options] expr ...\n" " test [subcommand]\n" + " iaid [subcommand]\n" + " duid [subcommand]\n" " arp [options] \n" "\n", program); goto done; @@ -314,11 +315,17 @@ main(int argc, char **argv) if (!strcmp(cmd, "convert")) { status = do_convert(argc - optind, argv + optind); } else + if (!strcmp(cmd, "duid")) { + status = ni_do_duid(program, argc - optind, argv + optind); + } else + if (!strcmp(cmd, "iaid")) { + status = ni_do_iaid(program, argc - optind, argv + optind); + } else if (!strcmp(cmd, "test")) { status = ni_do_test(program, argc - optind, argv + optind); } else if (!strcmp(cmd, "arp")) { - status = ni_do_arp(argc - optind, argv + optind); + status = ni_do_arp(program, argc - optind, argv + optind); } else { fprintf(stderr, "Unsupported command %s\n", cmd); goto usage; diff --git a/client/main.h b/client/main.h new file mode 100644 index 000000000..0d3ac29c9 --- /dev/null +++ b/client/main.h @@ -0,0 +1,32 @@ +/* + * wicked client main commands + * + * Copyright (C) 2017 SUSE LINUX GmbH, Nuernberg, Germany. + * + * 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 + * (at your option) 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, see . + * + * Authors: + * Marius Tomaschewski + * Nirmoy Das + * + */ +#ifndef WICKED_CLIENT_MAIN_H +#define WICKED_CLIENT_MAIN_H + +extern int ni_do_arp (const char *caller, int argc, char **argv); +extern int ni_do_test(const char *caller, int argc, char **argv); +extern int ni_do_duid(const char *caller, int argc, char **argv); +extern int ni_do_iaid(const char *caller, int argc, char **argv); + +#endif /* WICKED_CLIENT_MAIN_H */ diff --git a/client/tester.c b/client/tester.c index c0f2c4d9b..950603bb1 100644 --- a/client/tester.c +++ b/client/tester.c @@ -37,7 +37,6 @@ #include #include -#include "tester.h" #include "dhcp4/tester.h" #include "dhcp6/tester.h" #include "netinfo_priv.h" diff --git a/client/tester.h b/client/tester.h deleted file mode 100644 index 550d5c3c2..000000000 --- a/client/tester.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * wicked client tester commands - * - * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. - * - * 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 - * (at your option) 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, see or write - * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. - * - * Authors: - * Marius Tomaschewski - * - */ -#ifndef WICKED_CLIENT_TESTER_H -#define WICKED_CLIENT_TESTER_H - -extern int ni_do_test(const char *caller, int argc, char **argv); - -#endif /* WICKED_CLIENT_TESTER_H */