Mercurial > illumos > illumos-gate
view usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.c @ 13046:b615ff9cec13
6971008 nwamcfg revert emits confusing message
author | Anurag S. Maskey <Anurag.Maskey@Oracle.COM> |
---|---|
date | Fri, 06 Aug 2010 14:58:14 -0400 |
parents | 8f30d0e611c6 |
children |
line wrap: on
line source
/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ /* * nwamcfg is a lex/yacc based command interpreter used to manage network * configurations. The lexer (see nwamcfg_lex.l) builds up tokens, which * the grammar (see nwamcfg_grammar.y) builds up into commands, some of * which takes resources and/or properties as arguments. */ #include <arpa/inet.h> #include <assert.h> #include <ctype.h> #include <errno.h> #include <libnwam.h> #include <libtecla.h> #include <locale.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/sysmacros.h> #include <sys/types.h> #include <unistd.h> #include "nwamcfg.h" #if !defined(TEXT_DOMAIN) /* should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ #endif struct help { uint_t cmd_num; const char *cmd_name; const char *cmd_usage; }; extern int yyparse(void); extern int lex_lineno; #define MAX_LINE_LEN 1024 #define MAX_CMD_HIST 1024 /* usage of commands */ #define SHELP_CANCEL "cancel" #define SHELP_CLEAR "clear <prop-name>" #define SHELP_COMMIT "commit" #define SHELP_CREATE "create [-t <template>] <object-type> [<class>] " \ "<object-name>" #define SHELP_DESTROY "destroy {-a | <object-type> [<class>] <object-name>}" #define SHELP_END "end" #define SHELP_EXIT "exit" #define SHELP_EXPORT "export [-d] [-f <output-file>] " \ "[<object-type> [<class>] <object-name>]" #define SHELP_GET "get [-V] <prop-name>" #define SHELP_HELP "help [command-name]" #define SHELP_LIST "list [-a] [<object-type> [<class>] <object-name>]" #define SHELP_REVERT "revert" #define SHELP_SELECT "select <object-type> [<class>] <object-name>" #define SHELP_SET "set <prop-name>=<value1>[,<value2>...]" #define SHELP_VERIFY "verify" #define SHELP_WALK "walkprop [-a]" /* * Scope Definitions: * Locations, ENMs, NCPs and Known WLANs are one scope level below global (GBL). * NCUs are one more level beneath the NCP scope. * Because the commands in Locations/ENM/Known WLAN and NCP level are different, * the scope are divided accordingly. * GBL->LOC, GBL->ENM, GBL->WLAN or GBL->NCP->NCU */ #define NWAM_SCOPE_GBL 0 #define NWAM_SCOPE_LOC 1 #define NWAM_SCOPE_ENM 2 #define NWAM_SCOPE_WLAN 3 #define NWAM_SCOPE_NCP 4 #define NWAM_SCOPE_NCU 5 /* delimiter used for list of values */ #define NWAM_VALUE_DELIMITER_CHAR ',' #define NWAM_VALUE_DELIMITER_STR "," /* the max number of values for an enum used by some properties in libnwam */ /* * All arrays/tables are null-terminated, rather than defining the length of * the array. When looping, check for NULL rather than using the size. */ static struct help helptab[] = { { CMD_CANCEL, "cancel", SHELP_CANCEL }, { CMD_CLEAR, "clear", SHELP_CLEAR }, { CMD_COMMIT, "commit", SHELP_COMMIT }, { CMD_CREATE, "create", SHELP_CREATE }, { CMD_DESTROY, "destroy", SHELP_DESTROY }, { CMD_END, "end", SHELP_END }, { CMD_EXIT, "exit", SHELP_EXIT }, { CMD_EXPORT, "export", SHELP_EXPORT }, { CMD_GET, "get", SHELP_GET }, { CMD_HELP, "help", SHELP_HELP }, { CMD_LIST, "list", SHELP_LIST }, { CMD_REVERT, "revert", SHELP_REVERT }, { CMD_SELECT, "select", SHELP_SELECT }, { CMD_SET, "set", SHELP_SET }, { CMD_VERIFY, "verify", SHELP_VERIFY }, { CMD_WALKPROP, "walkprop", SHELP_WALK }, { 0, NULL, NULL } }; /* These *must* match the order of the RT1_ define's from nwamcfg.h */ static char *res1_types[] = { "unknown", "loc", "ncp", "enm", "wlan", NULL }; /* These *must* match the order of the RT2_ define's from nwamcfg.h */ static char *res2_types[] = { "unknown", "ncu", NULL }; /* * No array for NCU_CLASS_. The #define's in nwamcfg.h matches the * enum nwam_ncu_class_t in libnwam and thus uses libnwam functions to * retrieve the string representation. */ /* These *MUST* match the order of the PT_ define's from nwamcfg.h */ static char *pt_types[] = { "unknown", NWAM_NCU_PROP_ACTIVATION_MODE, NWAM_NCU_PROP_ENABLED, NWAM_NCU_PROP_TYPE, NWAM_NCU_PROP_CLASS, NWAM_NCU_PROP_PARENT_NCP, NWAM_NCU_PROP_PRIORITY_GROUP, NWAM_NCU_PROP_PRIORITY_MODE, NWAM_NCU_PROP_LINK_MAC_ADDR, NWAM_NCU_PROP_LINK_AUTOPUSH, NWAM_NCU_PROP_LINK_MTU, NWAM_NCU_PROP_IP_VERSION, NWAM_NCU_PROP_IPV4_ADDRSRC, NWAM_NCU_PROP_IPV4_ADDR, NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE, NWAM_NCU_PROP_IPV6_ADDRSRC, NWAM_NCU_PROP_IPV6_ADDR, NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE, NWAM_LOC_PROP_CONDITIONS, NWAM_ENM_PROP_FMRI, NWAM_ENM_PROP_START, NWAM_ENM_PROP_STOP, NWAM_LOC_PROP_NAMESERVICES, NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE, NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC, NWAM_LOC_PROP_DNS_NAMESERVICE_DOMAIN, NWAM_LOC_PROP_DNS_NAMESERVICE_SERVERS, NWAM_LOC_PROP_DNS_NAMESERVICE_SEARCH, NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC, NWAM_LOC_PROP_NIS_NAMESERVICE_SERVERS, NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC, NWAM_LOC_PROP_LDAP_NAMESERVICE_SERVERS, NWAM_LOC_PROP_DEFAULT_DOMAIN, NWAM_LOC_PROP_NFSV4_DOMAIN, NWAM_LOC_PROP_IPFILTER_CONFIG_FILE, NWAM_LOC_PROP_IPFILTER_V6_CONFIG_FILE, NWAM_LOC_PROP_IPNAT_CONFIG_FILE, NWAM_LOC_PROP_IPPOOL_CONFIG_FILE, NWAM_LOC_PROP_IKE_CONFIG_FILE, NWAM_LOC_PROP_IPSECPOLICY_CONFIG_FILE, NWAM_KNOWN_WLAN_PROP_BSSIDS, NWAM_KNOWN_WLAN_PROP_PRIORITY, NWAM_KNOWN_WLAN_PROP_KEYNAME, NWAM_KNOWN_WLAN_PROP_KEYSLOT, NWAM_KNOWN_WLAN_PROP_SECURITY_MODE }; /* properties table: maps PT_* constants to property names */ typedef struct prop_table_entry { int pte_type; const char *pte_name; } prop_table_entry_t; /* NCU properties table */ static prop_table_entry_t ncu_prop_table[] = { { PT_TYPE, NWAM_NCU_PROP_TYPE }, { PT_CLASS, NWAM_NCU_PROP_CLASS }, { PT_PARENT, NWAM_NCU_PROP_PARENT_NCP }, { PT_ACTIVATION_MODE, NWAM_NCU_PROP_ACTIVATION_MODE }, { PT_ENABLED, NWAM_NCU_PROP_ENABLED }, { PT_PRIORITY_GROUP, NWAM_NCU_PROP_PRIORITY_GROUP }, { PT_PRIORITY_MODE, NWAM_NCU_PROP_PRIORITY_MODE }, { PT_LINK_MACADDR, NWAM_NCU_PROP_LINK_MAC_ADDR }, { PT_LINK_AUTOPUSH, NWAM_NCU_PROP_LINK_AUTOPUSH }, { PT_LINK_MTU, NWAM_NCU_PROP_LINK_MTU }, { PT_IP_VERSION, NWAM_NCU_PROP_IP_VERSION }, { PT_IPV4_ADDRSRC, NWAM_NCU_PROP_IPV4_ADDRSRC }, { PT_IPV4_ADDR, NWAM_NCU_PROP_IPV4_ADDR }, { PT_IPV4_DEFAULT_ROUTE, NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE }, { PT_IPV6_ADDRSRC, NWAM_NCU_PROP_IPV6_ADDRSRC }, { PT_IPV6_ADDR, NWAM_NCU_PROP_IPV6_ADDR }, { PT_IPV6_DEFAULT_ROUTE, NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE }, { 0, NULL } }; /* ENM properties table */ static prop_table_entry_t enm_prop_table[] = { { PT_ENM_FMRI, NWAM_ENM_PROP_FMRI }, { PT_ENM_START, NWAM_ENM_PROP_START }, { PT_ENM_STOP, NWAM_ENM_PROP_STOP }, { PT_ACTIVATION_MODE, NWAM_ENM_PROP_ACTIVATION_MODE }, { PT_CONDITIONS, NWAM_ENM_PROP_CONDITIONS }, { PT_ENABLED, NWAM_ENM_PROP_ENABLED }, { 0, NULL } }; /* LOCation properties table */ static prop_table_entry_t loc_prop_table[] = { { PT_ACTIVATION_MODE, NWAM_LOC_PROP_ACTIVATION_MODE }, { PT_CONDITIONS, NWAM_LOC_PROP_CONDITIONS }, { PT_ENABLED, NWAM_LOC_PROP_ENABLED }, { PT_LOC_NAMESERVICES, NWAM_LOC_PROP_NAMESERVICES }, { PT_LOC_NAMESERVICES_CONFIG, NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE }, { PT_LOC_DNS_CONFIGSRC, NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC }, { PT_LOC_DNS_DOMAIN, NWAM_LOC_PROP_DNS_NAMESERVICE_DOMAIN }, { PT_LOC_DNS_SERVERS, NWAM_LOC_PROP_DNS_NAMESERVICE_SERVERS }, { PT_LOC_DNS_SEARCH, NWAM_LOC_PROP_DNS_NAMESERVICE_SEARCH }, { PT_LOC_NIS_CONFIGSRC, NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC }, { PT_LOC_NIS_SERVERS, NWAM_LOC_PROP_NIS_NAMESERVICE_SERVERS }, { PT_LOC_LDAP_CONFIGSRC, NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC }, { PT_LOC_LDAP_SERVERS, NWAM_LOC_PROP_LDAP_NAMESERVICE_SERVERS }, { PT_LOC_DEFAULT_DOMAIN, NWAM_LOC_PROP_DEFAULT_DOMAIN }, { PT_LOC_NFSV4_DOMAIN, NWAM_LOC_PROP_NFSV4_DOMAIN }, { PT_LOC_IPF_CONFIG, NWAM_LOC_PROP_IPFILTER_CONFIG_FILE }, { PT_LOC_IPF_V6_CONFIG, NWAM_LOC_PROP_IPFILTER_V6_CONFIG_FILE }, { PT_LOC_IPNAT_CONFIG, NWAM_LOC_PROP_IPNAT_CONFIG_FILE }, { PT_LOC_IPPOOL_CONFIG, NWAM_LOC_PROP_IPPOOL_CONFIG_FILE }, { PT_LOC_IKE_CONFIG, NWAM_LOC_PROP_IKE_CONFIG_FILE }, { PT_LOC_IPSECPOL_CONFIG, NWAM_LOC_PROP_IPSECPOLICY_CONFIG_FILE }, { 0, NULL } }; /* Known WLAN properties table */ static prop_table_entry_t wlan_prop_table[] = { { PT_WLAN_BSSIDS, NWAM_KNOWN_WLAN_PROP_BSSIDS }, { PT_WLAN_PRIORITY, NWAM_KNOWN_WLAN_PROP_PRIORITY }, { PT_WLAN_KEYNAME, NWAM_KNOWN_WLAN_PROP_KEYNAME }, { PT_WLAN_KEYSLOT, NWAM_KNOWN_WLAN_PROP_KEYSLOT }, { PT_WLAN_SECURITY_MODE, NWAM_KNOWN_WLAN_PROP_SECURITY_MODE }, { 0, NULL } }; /* Returns the appropriate properties table for the given object type */ static prop_table_entry_t * get_prop_table(nwam_object_type_t object_type) { switch (object_type) { case NWAM_OBJECT_TYPE_NCU: return (ncu_prop_table); case NWAM_OBJECT_TYPE_LOC: return (loc_prop_table); case NWAM_OBJECT_TYPE_ENM: return (enm_prop_table); case NWAM_OBJECT_TYPE_KNOWN_WLAN: return (wlan_prop_table); } return (NULL); } /* Global variables */ /* set early in main(), never modified thereafter, used all over the place */ static char *execname; /* set in modifying functions, checked in read_input() */ boolean_t saw_error = B_FALSE; /* set in yacc parser, checked in read_input() */ boolean_t newline_terminated; /* set in main(), checked in lex error handler */ boolean_t cmd_file_mode = B_FALSE; /* set in exit_func(), checked in read_input() */ static boolean_t time_to_exit = B_FALSE; /* used in nerr() and nwamerr() */ static char *cmd_file_name = NULL; /* used with cmd_file to destroy all configurations */ static boolean_t remove_all_configurations = B_FALSE; /* checked in read_input() and other places */ static boolean_t ok_to_prompt = B_FALSE; /* initialized in do_interactive(), checked in initialize() */ static boolean_t interactive_mode; static boolean_t need_to_commit = B_FALSE; /* The gl_get_line() resource object */ static GetLine *gl; /* set when create or read objects, used by other func */ static nwam_loc_handle_t loc_h = NULL; static nwam_enm_handle_t enm_h = NULL; static nwam_known_wlan_handle_t wlan_h = NULL; static nwam_ncu_handle_t ncu_h = NULL; static nwam_ncp_handle_t ncp_h = NULL; static int current_scope = NWAM_SCOPE_GBL; /* obj1_* are used in NWAM_SCOPE_{NCP,LOC,ENM,WLAN} */ static int obj1_type; static char obj1_name[NWAM_MAX_NAME_LEN + 1]; /* obj2_* are used in NWAM_SCOPE_NCU only */ static int obj2_type; static char obj2_name[NWAM_MAX_NAME_LEN + 1]; /* arrays for tab-completion */ /* commands at NWAM_SCOPE_GBL */ static const char *global_scope_cmds[] = { "create ", "destroy ", "end ", "exit ", "export ", "help ", "list ", "select ", NULL }; static const char *global_create_cmds[] = { "create loc ", "create enm ", "create ncp ", "create wlan ", "create -t ", /* template */ NULL }; static const char *global_destroy_cmds[] = { "destroy -a ", "destroy loc ", "destroy enm ", "destroy ncp ", "destroy wlan ", NULL }; static const char *global_export_cmds[] = { "export ", "export -d ", /* add destroy -a */ "export -f ", /* to file */ "export -d -f ", /* add destroy -a to file */ "export loc ", "export enm ", "export ncp ", "export wlan ", NULL }; static const char *global_list_cmds[] = { "list ", "list loc ", "list enm ", "list ncp ", "list wlan ", "list -a loc ", "list -a enm ", "list -a wlan ", NULL }; static const char *global_select_cmds[] = { "select loc ", "select enm ", "select ncp ", "select wlan ", NULL }; /* commands at NWAM_SCOPE_LOC, _ENM, _WLAN and _NCU */ static const char *non_ncp_scope_cmds[] = { "cancel ", "clear ", "commit ", "end ", "exit ", "export ", "export -f ", "get ", "get -V ", /* value only */ "help ", "list ", "list -a ", /* all properties */ "revert ", "set ", "verify ", "walkprop ", "walkprop -a ", /* all properties */ NULL }; /* commands at NWAM_SCOPE_NCP */ static const char *ncp_scope_cmds[] = { "cancel ", "create ", "destroy ", "end ", "exit ", "export ", "help ", "list ", "select ", NULL }; static const char *ncp_create_cmds[] = { "create ncu ip ", "create ncu phys ", "create -t ", /* template */ NULL }; static const char *ncp_destroy_cmds[] = { "destroy ncu ", "destroy ncu ip ", "destroy ncu phys ", NULL }; static const char *ncp_export_cmds[] = { "export ", "export -f ", /* to file */ "export ncu ", "export ncu ip ", "export ncu phys ", NULL }; static const char *ncp_list_cmds[] = { "list ", "list ncu ", "list ncu ip ", "list ncu phys ", "list -a ncu ", "list -a ncu ip ", "list -a ncu phys ", NULL }; static const char *ncp_select_cmds[] = { "select ncu ", "select ncu ip ", "select ncu phys ", NULL }; /* Functions begin here */ cmd_t * alloc_cmd(void) { cmd_t *cmd = calloc(1, sizeof (cmd_t)); if (cmd == NULL) { nerr("Out of memory"); return (NULL); } cmd->cmd_argc = 0; cmd->cmd_argv[0] = NULL; return (cmd); } void free_cmd(cmd_t *cmd) { int i; for (i = 0; i < cmd->cmd_argc; i++) free(cmd->cmd_argv[i]); free(cmd); } void array_free(void **array, int nelem) { int i; for (i = 0; i < nelem; i++) free(array[i]); free(array); } static boolean_t initial_match(const char *line1, const char *line2, int word_end) { if (word_end <= 0) return (B_TRUE); return (strncmp(line1, line2, word_end) == 0); } static int add_stuff(WordCompletion *cpl, const char *line1, const char **list, int word_end) { int i, err; for (i = 0; list[i] != NULL; i++) { if (initial_match(line1, list[i], word_end)) { err = cpl_add_completion(cpl, line1, 0, word_end, list[i] + word_end, "", ""); if (err != 0) return (err); } } return (0); } /* * To fill in the rest of a string when user types the tab key. * First digital number is the length of the string, the second digital number * is the min number of chars that is needed to uniquely identify a string. */ #define MINI_STR(l, s, m, n) strncmp(l, s, MAX(MIN(sizeof (s) - 1, m), n)) /* ARGSUSED */ static CPL_MATCH_FN(cmd_cpl_fn) { /* tab-complete according to the current scope */ switch (current_scope) { case NWAM_SCOPE_GBL: if (MINI_STR(line, "create ", word_end, 2) == 0) return (add_stuff(cpl, line, global_create_cmds, word_end)); if (MINI_STR(line, "destroy ", word_end, 1) == 0) return (add_stuff(cpl, line, global_destroy_cmds, word_end)); if (MINI_STR(line, "export ", word_end, 3) == 0) return (add_stuff(cpl, line, global_export_cmds, word_end)); if (MINI_STR(line, "list ", word_end, 1) == 0) return (add_stuff(cpl, line, global_list_cmds, word_end)); if (MINI_STR(line, "select ", word_end, 1) == 0) return (add_stuff(cpl, line, global_select_cmds, word_end)); return (add_stuff(cpl, line, global_scope_cmds, word_end)); case NWAM_SCOPE_LOC: case NWAM_SCOPE_ENM: case NWAM_SCOPE_WLAN: case NWAM_SCOPE_NCU: return (add_stuff(cpl, line, non_ncp_scope_cmds, word_end)); case NWAM_SCOPE_NCP: if (MINI_STR(line, "create ", word_end, 2) == 0) return (add_stuff(cpl, line, ncp_create_cmds, word_end)); if (MINI_STR(line, "destroy ", word_end, 1) == 0) return (add_stuff(cpl, line, ncp_destroy_cmds, word_end)); if (MINI_STR(line, "export ", word_end, 3) == 0) return (add_stuff(cpl, line, ncp_export_cmds, word_end)); if (MINI_STR(line, "list ", word_end, 1) == 0) return (add_stuff(cpl, line, ncp_list_cmds, word_end)); if (MINI_STR(line, "select ", word_end, 1) == 0) return (add_stuff(cpl, line, ncp_select_cmds, word_end)); return (add_stuff(cpl, line, ncp_scope_cmds, word_end)); } /* should never get here */ return (NULL); } const char * cmd_to_str(int cmd_num) { assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); return (helptab[cmd_num].cmd_name); } /* Returns "loc", "enm", "wlan" or "ncp" as string */ static const char * rt1_to_str(int res_type) { assert(res_type >= RT1_MIN && res_type <= RT1_MAX); return (res1_types[res_type]); } /* Returns "ncu" as string */ static const char * rt2_to_str(int res_type) { assert(res_type >= RT2_MIN && res_type <= RT2_MAX); return (res2_types[res_type]); } /* Returns "ncp, "ncu", "loc", "enm", or "wlan" according to the scope */ static const char * scope_to_str(int scope) { switch (scope) { case NWAM_SCOPE_GBL: return ("global"); case NWAM_SCOPE_NCP: return ("ncp"); case NWAM_SCOPE_NCU: return ("ncu"); case NWAM_SCOPE_LOC: return ("loc"); case NWAM_SCOPE_ENM: return ("enm"); case NWAM_SCOPE_WLAN: return ("wlan"); default: return ("invalid"); } } /* Given an enm property and value, returns it as a string */ static const char * propval_to_str(const char *propname, uint64_t value) { const char *str; if (nwam_uint64_get_value_string(propname, value, &str) == NWAM_SUCCESS) return (str); return (NULL); } /* Given an int for a prop, returns it as string */ static const char * pt_to_str(int prop_type) { assert(prop_type >= PT_MIN && prop_type <= PT_MAX); return (pt_types[prop_type]); } /* Return B_TRUE if string starts with "t" or is 1, B_FALSE otherwise */ static boolean_t str_to_boolean(const char *str) { if (strncasecmp(str, "t", 1) == 0 || atoi(str) == 1) return (B_TRUE); else return (B_FALSE); } /* * This is a separate function rather than a set of define's because of the * gettext() wrapping. */ /* * TRANSLATION_NOTE * Each string below should have \t follow \n whenever needed; the * initial \t and the terminal \n will be provided by the calling function. */ static const char * long_help(int cmd_num) { assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX); switch (cmd_num) { case CMD_CANCEL: return (gettext("Cancels the current configuration " "changes.")); case CMD_CLEAR: return (gettext("Clears the value for the specified " "property.")); case CMD_COMMIT: return (gettext("Commits the current configuration.")); case CMD_CREATE: return (gettext("Creates a new profile or resource.")); case CMD_DESTROY: return (gettext("Destroys the specified profile or " "resource.")); case CMD_END: return (gettext("Ends specification of a resource.")); case CMD_EXIT: return (gettext("Exits the program.")); case CMD_EXPORT: return (gettext("Exports the configuration.")); case CMD_GET: return (gettext("Gets the value of the specified " "property.")); case CMD_HELP: return (gettext("Prints help message.")); case CMD_LIST: return (gettext("Lists existing objects.")); case CMD_REVERT: return (gettext("Reverts to the previous " "configuration.")); case CMD_SELECT: return (gettext("Selects a resource to modify.")); case CMD_SET: return (gettext("Sets the value of the specified " "property.")); case CMD_VERIFY: return (gettext("Verifies an object.")); case CMD_WALKPROP: return (gettext("Iterates over properties.")); default: return (gettext("Unknown command.")); } } void command_usage(int command) { if (command < CMD_MIN || command > CMD_MAX) { nerr("Unknown command"); } else { nerr("%s: %s: %s", gettext("Error"), gettext("usage"), helptab[command].cmd_usage); } } static void long_usage(uint_t cmd_num) { (void) printf("%s: %s\n", gettext("usage"), helptab[cmd_num].cmd_usage); (void) printf("\t%s\n", long_help(cmd_num)); } /* Prints usage for command line options */ static void cmd_line_usage() { (void) printf("%s:\t%s\t\t\t\t(%s)\n", gettext("usage"), execname, gettext("interactive-mode")); (void) printf("\t%s <%s> [%s...]\n", execname, gettext("command"), gettext("options")); (void) printf("\t%s [-d] -f <%s>\n", execname, gettext("command-file")); (void) printf("\t%s %s [<%s>]\n", execname, cmd_to_str(CMD_HELP), gettext("command")); } /* Prints the line number of the current command if in command-file mode */ static void print_lineno() { static int last_lineno; /* lex_lineno has already been incremented in the lexer; compensate */ if (cmd_file_mode && lex_lineno > last_lineno) { if (strcmp(cmd_file_name, "-") == 0) (void) fprintf(stderr, gettext("On line %d:\n"), lex_lineno - 1); else (void) fprintf(stderr, gettext("On line %d of %s:\n"), lex_lineno - 1, cmd_file_name); last_lineno = lex_lineno; } } /* PRINTFLIKE1 */ void nerr(const char *format, ...) { va_list alist; print_lineno(); format = gettext(format); va_start(alist, format); (void) vfprintf(stderr, format, alist); va_end(alist); (void) fprintf(stderr, "\n"); saw_error = B_TRUE; } /* PRINTFLIKE2 */ static void nwamerr(nwam_error_t err, const char *format, ...) { va_list alist; print_lineno(); format = gettext(format); va_start(alist, format); (void) vfprintf(stderr, format, alist); va_end(alist); (void) fprintf(stderr, ": %s\n", nwam_strerror(err)); saw_error = B_TRUE; } void properr(const char *prop) { nerr("Invalid property: '%s'", prop); } /* * If free_ncu_only == B_TRUE, only ncu handle is freed, ncp handle remains the * same. Since nwam_ncp_free() takes care of its ncus, no need to explicitly * call nwam_ncu_free() afterwards. */ static void free_handle(boolean_t free_ncu_only) { if (ncp_h != NULL) { if (!free_ncu_only) { nwam_ncp_free(ncp_h); ncp_h = NULL; ncu_h = NULL; } else if (ncu_h != NULL) { nwam_ncu_free(ncu_h); ncu_h = NULL; } } if (enm_h != NULL) { nwam_enm_free(enm_h); enm_h = NULL; } if (loc_h != NULL) { nwam_loc_free(loc_h); loc_h = NULL; } if (wlan_h != NULL) { nwam_known_wlan_free(wlan_h); wlan_h = NULL; } } /* * On input, TRUE => yes, FALSE => no. * On return, TRUE => 1, FALSE => no, could not ask => -1. */ static int ask_yesno(boolean_t default_answer, const char *question) { char line[64]; /* should be enough to answer yes or no */ if (!ok_to_prompt) { saw_error = B_TRUE; return (-1); } for (;;) { if (printf("%s (%s)? ", gettext(question), default_answer ? "[y]/n" : "y/[n]") < 0) return (-1); if (fgets(line, sizeof (line), stdin) == NULL) return (-1); if (line[0] == '\n') return (default_answer ? 1 : 0); if (tolower(line[0]) == 'y') return (1); if (tolower(line[0]) == 'n') return (0); } } /* This is the back-end helper function for read_input() below. */ static int cleanup() { int answer; if (!interactive_mode && !cmd_file_mode) { /* * If we're not in interactive mode, and we're not in command * file mode, then we must be in commands-from-the-command-line * mode. As such, we can't loop back and ask for more input. * It was OK to prompt for such things as whether or not to * really delete something in the command handler called from * yyparse() above, but "really quit?" makes no sense in this * context. So disable prompting. */ ok_to_prompt = B_FALSE; } if (need_to_commit) { answer = ask_yesno(B_FALSE, "Configuration not saved; really quit"); switch (answer) { case -1: /* issue error here */ return (NWAM_ERR); case 1: /* * don't want to save, just exit. handles are freed at * end_func() or exit_func(). */ return (NWAM_OK); default: /* loop back to read input */ time_to_exit = B_FALSE; yyin = stdin; return (NWAM_REPEAT); } } return (saw_error ? NWAM_ERR : NWAM_OK); } static int string_to_yyin(char *string) { if ((yyin = tmpfile()) == NULL) goto error; if (fwrite(string, strlen(string), 1, yyin) != 1) goto error; if (fseek(yyin, 0, SEEK_SET) != 0) goto error; return (NWAM_OK); error: nerr("problem creating temporary file"); return (NWAM_ERR); } /* * read_input() is the driver of this program. It is a wrapper around * yyparse(), printing appropriate prompts when needed, checking for * exit conditions and reacting appropriately. This function is * called when in interactive mode or command-file mode. */ static int read_input(void) { boolean_t yyin_is_a_tty = isatty(fileno(yyin)); /* * The prompt is "e> " or "e:t1:o1> " or "e:t1:o1:t2:o2> " where e is * execname, t is resource type, o is object name. */ char prompt[MAXPATHLEN + (2 * (NWAM_MAX_TYPE_LEN + NWAM_MAX_NAME_LEN)) + sizeof ("::::> ")]; char *line; /* yyin should have been set to the appropriate (FILE *) if not stdin */ newline_terminated = B_TRUE; for (;;) { if (yyin_is_a_tty) { if (newline_terminated) { switch (current_scope) { case NWAM_SCOPE_GBL: (void) snprintf(prompt, sizeof (prompt), "%s> ", execname); break; case NWAM_SCOPE_LOC: case NWAM_SCOPE_ENM: case NWAM_SCOPE_WLAN: case NWAM_SCOPE_NCP: (void) snprintf(prompt, sizeof (prompt), "%s:%s:%s> ", execname, rt1_to_str(obj1_type), obj1_name); break; case NWAM_SCOPE_NCU: (void) snprintf(prompt, sizeof (prompt), "%s:%s:%s:%s:%s> ", execname, rt1_to_str(obj1_type), obj1_name, rt2_to_str(obj2_type), obj2_name); } } /* * If the user hits ^C then we want to catch it and * start over. If the user hits EOF then we want to * bail out. */ line = gl_get_line(gl, prompt, NULL, -1); if (gl_return_status(gl) == GLR_SIGNAL) { gl_abandon_line(gl); continue; } if (line == NULL) break; if (string_to_yyin(line) != NWAM_OK) break; while (!feof(yyin)) { yyparse(); /* * If any command on a list of commands * give an error, don't continue with the * remaining commands. */ if (saw_error || time_to_exit) break; } } else { yyparse(); } /* Bail out on an error in command-file mode. */ if (saw_error && cmd_file_mode && !interactive_mode) time_to_exit = B_TRUE; if (time_to_exit || (!yyin_is_a_tty && feof(yyin))) break; } return (cleanup()); } /* * This function is used in the interactive-mode scenario: it just calls * read_input() until we are done. */ static int do_interactive(void) { int err; interactive_mode = B_TRUE; do { err = read_input(); } while (err == NWAM_REPEAT); return (err); } /* Calls the help_func() to print the usage of all commands */ void help_wrap() { cmd_t *help_cmd; if ((help_cmd = alloc_cmd()) == NULL) exit(NWAM_ERR); help_func(help_cmd); free_cmd(help_cmd); } /* Check if the given command is allowed in the current scope */ boolean_t check_scope(int cmd) { /* allowed in all scopes */ switch (cmd) { case CMD_END: case CMD_EXIT: case CMD_HELP: case CMD_LIST: case CMD_EXPORT: return (B_TRUE); } /* scope-specific */ switch (current_scope) { case NWAM_SCOPE_GBL: switch (cmd) { case CMD_CREATE: case CMD_DESTROY: case CMD_SELECT: return (B_TRUE); } break; case NWAM_SCOPE_LOC: case NWAM_SCOPE_ENM: case NWAM_SCOPE_WLAN: case NWAM_SCOPE_NCU: switch (cmd) { case CMD_CANCEL: case CMD_CLEAR: case CMD_COMMIT: case CMD_GET: case CMD_REVERT: case CMD_SET: case CMD_VERIFY: case CMD_WALKPROP: return (B_TRUE); } break; case NWAM_SCOPE_NCP: switch (cmd) { case CMD_CANCEL: case CMD_CREATE: case CMD_DESTROY: case CMD_SELECT: return (B_TRUE); } break; default: nerr("Invalid scope"); } nerr("'%s' is not allowed at this scope", cmd_to_str(cmd)); return (B_FALSE); } /* Returns the active object type depending on which handle is not NULL */ static nwam_object_type_t active_object_type() { /* Check ncu_h before ncp_h, ncp_h must be loaded before ncu_h */ if (ncu_h != NULL) return (NWAM_OBJECT_TYPE_NCU); else if (ncp_h != NULL) return (NWAM_OBJECT_TYPE_NCP); else if (loc_h != NULL) return (NWAM_OBJECT_TYPE_LOC); else if (enm_h != NULL) return (NWAM_OBJECT_TYPE_ENM); else if (wlan_h != NULL) return (NWAM_OBJECT_TYPE_KNOWN_WLAN); else return (NWAM_OBJECT_TYPE_UNKNOWN); } /* Retrive the name of the object from its handle */ static nwam_error_t object_name_from_handle(nwam_object_type_t object_type, void *handle, char **namep) { switch (object_type) { case NWAM_OBJECT_TYPE_NCP: return (nwam_ncp_get_name(handle, namep)); case NWAM_OBJECT_TYPE_NCU: return (nwam_ncu_get_name(handle, namep)); case NWAM_OBJECT_TYPE_LOC: return (nwam_loc_get_name(handle, namep)); case NWAM_OBJECT_TYPE_ENM: return (nwam_enm_get_name(handle, namep)); case NWAM_OBJECT_TYPE_KNOWN_WLAN: return (nwam_known_wlan_get_name(handle, namep)); } return (NWAM_INVALID_ARG); } static void do_commit() { nwam_error_t ret = NWAM_SUCCESS; const char *errprop; if (!need_to_commit) return; switch (active_object_type()) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_commit(ncu_h, 0); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_commit(enm_h, 0); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_commit(loc_h, 0); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_commit(wlan_h, 0); break; } if (ret == NWAM_SUCCESS) { need_to_commit = B_FALSE; if (interactive_mode) (void) printf(gettext("Committed changes\n")); } else { nwam_error_t verr; /* Find property that caused failure */ switch (active_object_type()) { case NWAM_OBJECT_TYPE_NCU: verr = nwam_ncu_validate(ncu_h, &errprop); break; case NWAM_OBJECT_TYPE_ENM: verr = nwam_enm_validate(enm_h, &errprop); break; case NWAM_OBJECT_TYPE_LOC: verr = nwam_loc_validate(loc_h, &errprop); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: verr = nwam_known_wlan_validate(wlan_h, &errprop); break; } if (verr != NWAM_SUCCESS) nwamerr(ret, "Commit error on property '%s'", errprop); else nwamerr(ret, "Commit error"); } } /* * Saves the current configuration to persistent storage. */ /* ARGSUSED */ void commit_func(cmd_t *cmd) { if (!need_to_commit) { if (interactive_mode) (void) printf(gettext("Nothing to commit\n")); } else { do_commit(); } } static void do_cancel() { switch (current_scope) { case NWAM_SCOPE_NCU: current_scope = NWAM_SCOPE_NCP; obj2_type = 0; free_handle(B_TRUE); break; case NWAM_SCOPE_NCP: case NWAM_SCOPE_ENM: case NWAM_SCOPE_WLAN: case NWAM_SCOPE_LOC: current_scope = NWAM_SCOPE_GBL; obj1_type = 0; free_handle(B_FALSE); break; case NWAM_SCOPE_GBL: free_handle(B_FALSE); break; default: nerr("Invalid scope"); return; } need_to_commit = B_FALSE; } /* * End operation on current scope and go up one scope. * Changes are not saved, no prompt either. */ /* ARGSUSED */ void cancel_func(cmd_t *cmd) { do_cancel(); } /* * Removes leading and trailing quotes from a string. * Caller must free returned string. */ static char * trim_quotes(const char *quoted_str) { char *str; int end; /* export_func() and list_func() can pass NULL here */ if (quoted_str == NULL) return (NULL); /* remove leading quote */ if (quoted_str[0] == '"') str = strdup(quoted_str + 1); else str = strdup(quoted_str); if (str == NULL) return (NULL); /* remove trailing quote and newline */ end = strlen(str) - 1; while (end >= 0 && (str[end] == '"' || str[end] == '\n')) end--; str[end+1] = 0; return (str); } /* * Creates a new resource and enters the scope of that resource. * The new resource can also be a copy of an existing resource (-t option). * If in interactive mode, then after creation call walkprop_func() * to do walk the properties for the new object. */ void create_func(cmd_t *cmd) { nwam_error_t ret = NWAM_SUCCESS; int c; boolean_t template = B_FALSE; char *newname = NULL, *oldname = NULL; cmd_t *walkprop_cmd; /* make sure right command at the right scope */ if (current_scope == NWAM_SCOPE_GBL && cmd->cmd_res2_type == RT2_NCU) { nerr("cannot create ncu at global scope"); return; } if (current_scope == NWAM_SCOPE_NCP && cmd->cmd_res2_type != RT2_NCU) { nerr("Cannot create given object at this scope"); return; } assert(cmd->cmd_argc > 0); optind = 0; while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "t:")) != EOF) { switch (c) { case 't': template = B_TRUE; break; default: command_usage(CMD_CREATE); return; } } if (!template) { /* no template given */ /* argv[0] is name */ newname = trim_quotes(cmd->cmd_argv[0]); if (cmd->cmd_res1_type == RT1_ENM) { ret = nwam_enm_create(newname, NULL, &enm_h); } else if (cmd->cmd_res1_type == RT1_LOC) { ret = nwam_loc_create(newname, &loc_h); } else if (cmd->cmd_res1_type == RT1_WLAN) { ret = nwam_known_wlan_create(newname, &wlan_h); } else if (cmd->cmd_res1_type == RT1_NCP && current_scope == NWAM_SCOPE_GBL) { ret = nwam_ncp_create(newname, 0, &ncp_h); } else if (cmd->cmd_res2_type == RT2_NCU) { nwam_ncu_type_t ncu_type; nwam_ncu_class_t ncu_class; /* ncp must already be read */ if (ncp_h == NULL) { nerr("Create error: NCP has not been read"); goto done; } ncu_class = (nwam_ncu_class_t)cmd->cmd_ncu_class_type; ncu_type = nwam_ncu_class_to_type(ncu_class); ret = nwam_ncu_create(ncp_h, newname, ncu_type, ncu_class, &ncu_h); } if (ret != NWAM_SUCCESS) { nwamerr(ret, "Create error"); goto done; } } else { /* template given */ /* argv[0] is -t, argv[1] is old name, argv[2] is new name */ oldname = trim_quotes(cmd->cmd_argv[1]); newname = trim_quotes(cmd->cmd_argv[2]); if (cmd->cmd_res1_type == RT1_ENM) { nwam_enm_handle_t oldenm_h; ret = nwam_enm_read(oldname, 0, &oldenm_h); if (ret != NWAM_SUCCESS) goto read_error; ret = nwam_enm_copy(oldenm_h, newname, &enm_h); nwam_enm_free(oldenm_h); } else if (cmd->cmd_res1_type == RT1_LOC) { nwam_loc_handle_t oldloc_h; ret = nwam_loc_read(oldname, 0, &oldloc_h); if (ret != NWAM_SUCCESS) goto read_error; ret = nwam_loc_copy(oldloc_h, newname, &loc_h); nwam_loc_free(oldloc_h); } else if (cmd->cmd_res1_type == RT1_WLAN) { nwam_known_wlan_handle_t oldwlan_h; ret = nwam_known_wlan_read(oldname, 0, &oldwlan_h); if (ret != NWAM_SUCCESS) goto read_error; ret = nwam_known_wlan_copy(oldwlan_h, newname, &wlan_h); nwam_known_wlan_free(oldwlan_h); } else if (cmd->cmd_res1_type == RT1_NCP && current_scope == NWAM_SCOPE_GBL) { nwam_ncp_handle_t oldncp_h; ret = nwam_ncp_read(oldname, 0, &oldncp_h); if (ret != NWAM_SUCCESS) goto read_error; ret = nwam_ncp_copy(oldncp_h, newname, &ncp_h); nwam_ncp_free(oldncp_h); } else if (cmd->cmd_res2_type == RT2_NCU) { nwam_ncu_handle_t oldncu_h; nwam_ncu_type_t ncu_type; nwam_ncu_class_t ncu_class; /* ncp must already be read */ if (ncp_h == NULL) { nerr("Copy error: NCP has not been read"); goto done; } ncu_class = (nwam_ncu_class_t)cmd->cmd_ncu_class_type; ncu_type = nwam_ncu_class_to_type(ncu_class); ret = nwam_ncu_read(ncp_h, oldname, ncu_type, 0, &oldncu_h); if (ret != NWAM_SUCCESS) goto read_error; ret = nwam_ncu_copy(oldncu_h, newname, &ncu_h); nwam_ncu_free(oldncu_h); } if (ret != NWAM_SUCCESS) { nwamerr(ret, "Copy error"); goto done; } } if (current_scope == NWAM_SCOPE_GBL) { (void) strlcpy(obj1_name, newname, sizeof (obj1_name)); obj1_type = cmd->cmd_res1_type; if (obj1_type == RT1_ENM) current_scope = NWAM_SCOPE_ENM; else if (obj1_type == RT1_LOC) current_scope = NWAM_SCOPE_LOC; else if (obj1_type == RT1_WLAN) current_scope = NWAM_SCOPE_WLAN; else if (obj1_type == RT1_NCP) current_scope = NWAM_SCOPE_NCP; } else { (void) strlcpy(obj2_name, newname, sizeof (obj2_name)); current_scope = NWAM_SCOPE_NCU; obj2_type = cmd->cmd_res2_type; } if (current_scope != NWAM_SCOPE_NCP) need_to_commit = B_TRUE; /* do a walk of the properties if in interactive mode */ if (interactive_mode && current_scope != NWAM_SCOPE_NCP) { (void) printf(gettext("Created %s '%s'. " "Walking properties ...\n"), scope_to_str(current_scope), newname); if ((walkprop_cmd = alloc_cmd()) == NULL) goto done; walkprop_func(walkprop_cmd); free(walkprop_cmd); } read_error: if (ret != NWAM_SUCCESS) nwamerr(ret, "Copy error reading '%s'", oldname); done: free(oldname); free(newname); } /* Processing of return value for destroy_*_callback() */ static int destroy_ret(nwam_object_type_t object_type, nwam_error_t ret, void *handle) { if (ret == NWAM_ENTITY_NOT_DESTROYABLE) { /* log a message to stderr, but don't consider it an error */ char *name; if (object_name_from_handle(object_type, handle, &name) == NWAM_SUCCESS) { (void) fprintf(stderr, gettext("%s '%s' cannot be removed\n"), nwam_object_type_to_string(object_type), name); free(name); } return (0); } if (ret == NWAM_SUCCESS || ret == NWAM_ENTITY_IN_USE) return (0); return (1); } /* * NWAM_FLAG_DO_NOT_FREE is passed to nwam_*_destory() so that it does not * free the handle. The calling nwam_walk_*() function frees this handle * as it is the function that created the handle. * * Objects that are not destroyable or are active cannot be destroyed. * Don't return error in these situations so the walk can continue. */ /* ARGSUSED */ static int destroy_ncp_callback(nwam_ncp_handle_t ncp, void *arg) { /* The file is deleted, so NCUs are also removed */ nwam_error_t ret = nwam_ncp_destroy(ncp, NWAM_FLAG_DO_NOT_FREE); return (destroy_ret(NWAM_OBJECT_TYPE_NCP, ret, ncp)); } /* ARGSUSED */ static int destroy_loc_callback(nwam_loc_handle_t loc, void *arg) { nwam_error_t ret = nwam_loc_destroy(loc, NWAM_FLAG_DO_NOT_FREE); return (destroy_ret(NWAM_OBJECT_TYPE_LOC, ret, loc)); } /* ARGSUSED */ static int destroy_enm_callback(nwam_enm_handle_t enm, void *arg) { nwam_error_t ret = nwam_enm_destroy(enm, NWAM_FLAG_DO_NOT_FREE); return (destroy_ret(NWAM_OBJECT_TYPE_ENM, ret, enm)); } /* ARGSUSED */ static int destroy_wlan_callback(nwam_known_wlan_handle_t wlan, void *arg) { nwam_error_t ret = nwam_known_wlan_destroy(wlan, NWAM_FLAG_DO_NOT_FREE); return (destroy_ret(NWAM_OBJECT_TYPE_KNOWN_WLAN, ret, wlan)); } /* * Remove all existing configuration that are not read-only. * walk through all ncps, locs, enms, wlans and destroy each one. */ static nwam_error_t destroy_all(void) { nwam_error_t ret; assert(remove_all_configurations); ret = nwam_walk_ncps(destroy_ncp_callback, NULL, 0, NULL); if (ret != NWAM_SUCCESS) goto done; ret = nwam_walk_enms(destroy_enm_callback, NULL, NWAM_FLAG_ACTIVATION_MODE_ALL, NULL); if (ret != NWAM_SUCCESS) goto done; ret = nwam_walk_locs(destroy_loc_callback, NULL, NWAM_FLAG_ACTIVATION_MODE_ALL, NULL); if (ret != NWAM_SUCCESS) goto done; ret = nwam_walk_known_wlans(destroy_wlan_callback, NULL, 0, NULL); if (ret != NWAM_SUCCESS) goto done; if (interactive_mode) (void) printf(gettext("All user-defined entities destroyed\n")); remove_all_configurations = B_FALSE; done: if (ret != NWAM_SUCCESS) { nwamerr(ret, "Destroy error: " "could not destroy all configurations"); } return (ret); } /* * Destroys an instance in persistent repository, and is permanent. * If interactive mode, it is allowed at global scope only * option -a destroys everything. */ void destroy_func(cmd_t *cmd) { nwam_error_t ret; char *name, *realname = NULL; if (current_scope == NWAM_SCOPE_NCP && (cmd->cmd_res1_type == RT1_ENM || cmd->cmd_res1_type == RT1_LOC || cmd->cmd_res1_type == RT1_WLAN)) { nerr("Destroy error: only NCUs can be destroyed in NCP scope"); return; } assert(cmd->cmd_argc > 0); /* res1_type is -1 if -a flag is used */ if (cmd->cmd_res1_type == -1) { int c; if (current_scope != NWAM_SCOPE_GBL) { nerr("Cannot destroy all configurations in a " "non-global scope"); return; } optind = 0; while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "a")) != EOF) { switch (c) { case 'a': remove_all_configurations = B_TRUE; break; default: command_usage(CMD_DESTROY); return; } } if (remove_all_configurations) { (void) destroy_all(); return; } } /* argv[0] is name */ name = trim_quotes(cmd->cmd_argv[0]); if (cmd->cmd_res2_type == RT2_NCU) { nwam_ncu_type_t ncu_type; nwam_ncu_class_t ncu_class; /* ncp must already be read */ if (ncp_h == NULL) { nerr("Destroy ncu error: NCP has not been read"); return; } ncu_class = (nwam_ncu_class_t)cmd->cmd_ncu_class_type; ncu_type = nwam_ncu_class_to_type(ncu_class); ret = nwam_ncu_read(ncp_h, name, ncu_type, 0, &ncu_h); if (ret != NWAM_SUCCESS) goto done; (void) object_name_from_handle(NWAM_OBJECT_TYPE_NCU, ncu_h, &realname); ret = nwam_ncu_destroy(ncu_h, 0); ncu_h = NULL; } else if (cmd->cmd_res1_type == RT1_ENM) { if ((ret = nwam_enm_read(name, 0, &enm_h)) != NWAM_SUCCESS) goto done; (void) object_name_from_handle(NWAM_OBJECT_TYPE_ENM, enm_h, &realname); ret = nwam_enm_destroy(enm_h, 0); enm_h = NULL; } else if (cmd->cmd_res1_type == RT1_LOC) { if ((ret = nwam_loc_read(name, 0, &loc_h)) != NWAM_SUCCESS) goto done; (void) object_name_from_handle(NWAM_OBJECT_TYPE_LOC, loc_h, &realname); ret = nwam_loc_destroy(loc_h, 0); loc_h = NULL; } else if (cmd->cmd_res1_type == RT1_WLAN) { if ((ret = nwam_known_wlan_read(name, 0, &wlan_h)) != NWAM_SUCCESS) goto done; (void) object_name_from_handle(NWAM_OBJECT_TYPE_KNOWN_WLAN, wlan_h, &realname); ret = nwam_known_wlan_destroy(wlan_h, 0); wlan_h = NULL; } else if (cmd->cmd_res1_type == RT1_NCP) { if ((ret = nwam_ncp_read(name, 0, &ncp_h)) != NWAM_SUCCESS) goto done; (void) object_name_from_handle(NWAM_OBJECT_TYPE_NCP, ncp_h, &realname); ret = nwam_ncp_destroy(ncp_h, 0); ncp_h = NULL; } else { nerr("Destroy error: unknown object-type"); } done: if (ret == NWAM_ENTITY_IN_USE) { nerr("Destroy error: active entity cannot be destroyed"); } else if (ret != NWAM_SUCCESS) { nwamerr(ret, "Destroy error"); } else if (interactive_mode) { (void) printf(gettext("Destroyed %s '%s'\n"), (cmd->cmd_res2_type == RT2_NCU ? rt2_to_str(cmd->cmd_res2_type) : rt1_to_str(cmd->cmd_res1_type)), realname != NULL ? realname : name); } free(name); free(realname); } /* * End operation on current scope and go up one scope. * Changes are saved. */ /* ARGSUSED */ void end_func(cmd_t *cmd) { /* if need_to_commit is set, commit changes */ if (need_to_commit) do_commit(); /* * Call do_cancel() to go up one scope. If commit fails, * need_to_commit is not reset and users are asked if they want to end. */ if (!need_to_commit || (need_to_commit && (ask_yesno(B_FALSE, "Configuration not saved; really end")) == 1)) { /* set time_to_exit if in global scope */ if (current_scope == NWAM_SCOPE_GBL) time_to_exit = B_TRUE; /* call do_cancel() to go up one scope */ do_cancel(); } } /* * Exit immediately. Configuration changes are saved by calling end_func(). */ /* ARGSUSED */ void exit_func(cmd_t *cmd) { cmd_t *end_cmd; if (need_to_commit) { if ((end_cmd = alloc_cmd()) == NULL) { nerr("Exit error"); return; } end_func(end_cmd); free_cmd(end_cmd); } /* * If need_to_commit is still set, then the commit failed. * Otherwise, exit. */ if (!need_to_commit) time_to_exit = B_TRUE; } void help_func(cmd_t *cmd) { int i; if (cmd->cmd_argc == 0) { (void) printf(gettext("commands:\n")); for (i = CMD_MIN; i <= CMD_MAX; i++) (void) printf("\t%s\n", helptab[i].cmd_usage); return; } for (i = CMD_MIN; i <= CMD_MAX; i++) { if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) { long_usage(i); return; } } (void) fprintf(stderr, gettext("Unknown command: '%s'\n"), cmd->cmd_argv[0]); help_wrap(); } /* * Revert configuration of an instance to latest previous version. * Free the handle and read again. */ /* ARGSUSED */ void revert_func(cmd_t *cmd) { nwam_error_t ret; char *name = NULL; nwam_ncu_type_t ncu_type; nwam_object_type_t object_type = active_object_type(); switch (object_type) { case NWAM_OBJECT_TYPE_NCU: /* retrieve name and type to use later */ if ((ret = nwam_ncu_get_ncu_type(ncu_h, &ncu_type)) != NWAM_SUCCESS) { nwamerr(ret, "Revert error: Get ncu type error"); return; } if ((ret = nwam_ncu_get_name(ncu_h, &name)) != NWAM_SUCCESS) goto name_error; nwam_ncu_free(ncu_h); ncu_h = NULL; ret = nwam_ncu_read(ncp_h, name, ncu_type, 0, &ncu_h); break; case NWAM_OBJECT_TYPE_ENM: if ((ret = nwam_enm_get_name(enm_h, &name)) != NWAM_SUCCESS) goto name_error; nwam_enm_free(enm_h); enm_h = NULL; ret = nwam_enm_read(name, 0, &enm_h); break; case NWAM_OBJECT_TYPE_LOC: if ((ret = nwam_loc_get_name(loc_h, &name)) != NWAM_SUCCESS) goto name_error; nwam_loc_free(loc_h); loc_h = NULL; ret = nwam_loc_read(name, 0, &loc_h); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: if ((ret = nwam_known_wlan_get_name(wlan_h, &name)) != NWAM_SUCCESS) goto name_error; nwam_known_wlan_free(wlan_h); wlan_h = NULL; ret = nwam_known_wlan_read(name, 0, &wlan_h); break; } /* Exit this scope because handle already freed (call do_cancel()) */ need_to_commit = B_FALSE; if (ret != NWAM_SUCCESS) { if (ret == NWAM_ENTITY_NOT_FOUND) { nerr("%s '%s' does not exist to revert to, removing it", nwam_object_type_to_string(object_type), name); } else { nwamerr(ret, "Revert error"); } do_cancel(); } free(name); return; name_error: if (ret != NWAM_SUCCESS) nwamerr(ret, "Revert error: get name error"); } /* * Load a resource from persistent repository and enter the scope * of that resource. */ void select_func(cmd_t *cmd) { nwam_error_t ret; char *name, *realname = NULL; assert(cmd->cmd_argc > 0); if (current_scope == NWAM_SCOPE_NCP && cmd->cmd_res2_type != RT2_NCU) { nerr("cannot select '%s' at this scope", rt1_to_str(cmd->cmd_res1_type)); return; } /* argv[0] is name */ name = trim_quotes(cmd->cmd_argv[0]); switch (cmd->cmd_res1_type) { case RT1_LOC: ret = nwam_loc_read(name, 0, &loc_h); if (ret == NWAM_SUCCESS) { current_scope = NWAM_SCOPE_LOC; (void) object_name_from_handle(NWAM_OBJECT_TYPE_LOC, loc_h, &realname); } break; case RT1_ENM: ret = nwam_enm_read(name, 0, &enm_h); if (ret == NWAM_SUCCESS) { current_scope = NWAM_SCOPE_ENM; (void) object_name_from_handle(NWAM_OBJECT_TYPE_ENM, enm_h, &realname); } break; case RT1_WLAN: ret = nwam_known_wlan_read(name, 0, &wlan_h); if (ret == NWAM_SUCCESS) { current_scope = NWAM_SCOPE_WLAN; (void) object_name_from_handle (NWAM_OBJECT_TYPE_KNOWN_WLAN, wlan_h, &realname); } break; case RT1_NCP: if (cmd->cmd_res2_type == RT2_NCU) { nwam_ncu_type_t ncu_type; nwam_ncu_class_t ncu_class; /* ncp must already be read */ if (ncp_h == NULL) { nerr("Select error: NCP has not been read"); free(name); return; } ncu_class = (nwam_ncu_class_t)cmd->cmd_ncu_class_type; ncu_type = nwam_ncu_class_to_type(ncu_class); ret = nwam_ncu_read(ncp_h, name, ncu_type, 0, &ncu_h); if (ret == NWAM_SUCCESS) { current_scope = NWAM_SCOPE_NCU; (void) object_name_from_handle (NWAM_OBJECT_TYPE_NCU, ncu_h, &realname); } } else { ret = nwam_ncp_read(name, 0, &ncp_h); if (ret == NWAM_SUCCESS) { current_scope = NWAM_SCOPE_NCP; (void) object_name_from_handle (NWAM_OBJECT_TYPE_NCP, ncp_h, &realname); } } break; default: nerr("Select error: unknown object-type"); free(name); return; } if (ret != NWAM_SUCCESS) { nwamerr(ret, "Select error"); } else { /* set the obj*_name or obj*_type depending on current scope */ if (current_scope == NWAM_SCOPE_NCU) { obj2_type = RT2_NCU; (void) strlcpy(obj2_name, realname != NULL ? realname : name, sizeof (obj2_name)); } else { (void) strlcpy(obj1_name, realname != NULL ? realname : name, sizeof (obj1_name)); obj1_type = cmd->cmd_res1_type; } } free(name); free(realname); } /* Given an int for prop, returns it as string */ static const char * pt_to_prop_name(nwam_object_type_t object_type, int pt_type) { int i; prop_table_entry_t *prop_table = get_prop_table(object_type); for (i = 0; prop_table[i].pte_name != NULL; i++) { if (pt_type == prop_table[i].pte_type) return (prop_table[i].pte_name); } return (NULL); } /* Given a prop as a string, returns it as an int */ static int prop_to_pt(nwam_object_type_t object_type, const char *prop) { int i; prop_table_entry_t *prop_table = get_prop_table(object_type); for (i = 0; prop_table[i].pte_name != NULL; i++) { if (strcmp(prop, prop_table[i].pte_name) == 0) return (prop_table[i].pte_type); } return (-1); } /* Given a prop as an int, returns its type (nwam_value_type_t) */ static nwam_value_type_t prop_value_type(nwam_object_type_t object_type, const char *prop) { nwam_error_t ret; nwam_value_type_t value_type; switch (object_type) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_get_prop_type(prop, &value_type); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_get_prop_type(prop, &value_type); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_get_prop_type(prop, &value_type); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_get_prop_type(prop, &value_type); break; } if (ret != NWAM_SUCCESS) value_type = NWAM_VALUE_TYPE_UNKNOWN; return (value_type); } /* * Converts input_str to an array nwam_value. * If is_list_prop, break input_str into array of strings first. */ static nwam_value_t str_to_nwam_value(nwam_object_type_t object_type, char *input_str, int pt_type, boolean_t is_list_prop) { int i, n = 0, ret; nwam_value_t data; char **val; int max_str_num; nwam_value_type_t value_type; int64_t *int_vals; uint64_t *uint_vals; boolean_t *boolean_vals; /* * Worst case is that each char separated by DELIMITER, so the * max number of sub strings is half of string length + 1. */ max_str_num = strlen(input_str) / 2 + 1; val = calloc(max_str_num, sizeof (char *)); if (val == NULL) { nerr("Out of memory"); return (NULL); } if (is_list_prop) { char *tmp, *next; /* * Break down input_str and save as array of sub strings. * Set num as the number of the sub strings. * Use nwam_tokenize_by_unescaped_delim() rather than strtok() * because DELIMITER may be escaped */ tmp = (char *)input_str; while ((tmp = nwam_tokenize_by_unescaped_delim(tmp, NWAM_VALUE_DELIMITER_CHAR, &next)) != NULL) { val[n++] = trim_quotes(tmp); tmp = next; } } else { val[n++] = trim_quotes(input_str); } /* initialize int_vals or booleans_vals depending on pt_type */ value_type = prop_value_type(object_type, pt_to_prop_name(object_type, pt_type)); if (value_type == NWAM_VALUE_TYPE_INT64) { int_vals = calloc(n, sizeof (int64_t)); if (int_vals == NULL) { nerr("Out of memory"); array_free((void **)val, max_str_num); return (NULL); } } else if (value_type == NWAM_VALUE_TYPE_UINT64) { uint_vals = calloc(n, sizeof (uint64_t)); if (uint_vals == NULL) { nerr("Out of memory"); array_free((void **)val, max_str_num); return (NULL); } } else if (value_type == NWAM_VALUE_TYPE_BOOLEAN) { boolean_vals = calloc(n, sizeof (boolean_t)); if (boolean_vals == NULL) { nerr("Out of memory"); array_free((void **)val, max_str_num); return (NULL); } } /* set the appropriate array */ for (i = 0; i < n; i++) { switch (value_type) { case NWAM_VALUE_TYPE_STRING: /* nothing to do - val already has the char** array */ break; case NWAM_VALUE_TYPE_INT64: { int_vals[i] = (int64_t)atoi(val[i]); break; } case NWAM_VALUE_TYPE_UINT64: { uint64_t str_as_enum; char *endptr; ret = nwam_value_string_get_uint64( pt_to_prop_name(object_type, pt_type), val[i], &str_as_enum); /* * Returns _SUCCESS if value for enum is valid. * Returns _INVALID_ARG if property is not an enum. */ if (ret == NWAM_SUCCESS) { uint_vals[i] = str_as_enum; } else if (ret == NWAM_INVALID_ARG) { uint_vals[i] = strtoul(val[i], &endptr, 10); /* verify conversion is valid */ if (endptr == val[i]) { free(uint_vals); array_free((void **)val, max_str_num); return (NULL); } } else { free(uint_vals); array_free((void **)val, max_str_num); return (NULL); } break; } case NWAM_VALUE_TYPE_BOOLEAN: boolean_vals[i] = str_to_boolean(val[i]); break; default: array_free((void **)val, max_str_num); return (NULL); } } /* create nwam_value_t */ if (value_type == NWAM_VALUE_TYPE_STRING) { ret = nwam_value_create_string_array(val, n, &data); } else if (value_type == NWAM_VALUE_TYPE_INT64) { ret = nwam_value_create_int64_array(int_vals, n, &data); free(int_vals); } else if (value_type == NWAM_VALUE_TYPE_UINT64) { ret = nwam_value_create_uint64_array(uint_vals, n, &data); free(uint_vals); } else if (value_type == NWAM_VALUE_TYPE_BOOLEAN) { ret = nwam_value_create_boolean_array(boolean_vals, n, &data); free(boolean_vals); } array_free((void **)val, max_str_num); if (ret != NWAM_SUCCESS) { nwamerr(ret, "Failed creating nwam_value"); return (NULL); } return (data); } /* * Displaying/Skipping of properties * --------------------------------- * * This table shows if a specific property should be shown if some * other property has a specific value. This table is used by * show_prop_test(), which is called by set_func() and walkprop_func(). * * An entry in the table looks like: * { property1, property2, { val1, val2, -1 } } * This is read as: * "show property1 only if property2 has value val1 or val2" * * NB: If a property does not appear in this table, then that implies * that the property is always shown. * * A property can have more than one rule. In such a case, the property is * displayed only any of the rules is satisfied. This checking, however, * is recursive. If a rule says that a property can be displayed, then the * property that's checked should also satisfy its rules. In the above * example, if property1 is to be displayed, then property2 should also * satisfy its rules and be displayable. This recursion is necessary as * properties that are not displayed (because rules are not satisfied) are * not deleted. */ /* The most number of values in pde_checkvals below */ #define NWAM_CHECKVALS_MAX 5 typedef struct prop_display_entry { const char *pde_name; /* property to show */ const char *pde_checkname; /* property to check */ int64_t pde_checkvals[NWAM_CHECKVALS_MAX]; /* show prop for these */ } prop_display_entry_t; /* Rules for showing properties: commented for clarity */ /* * Rules for NCUs * NB: There is no need to have an entry if a property is for IP only. * This is taken care of in libnwam_ncp.c */ static prop_display_entry_t ncu_prop_display_entry_table[] = { /* show priority-{group,mode} if activation == prioritized */ { NWAM_NCU_PROP_PRIORITY_GROUP, NWAM_NCU_PROP_ACTIVATION_MODE, { NWAM_ACTIVATION_MODE_PRIORITIZED, -1 } }, { NWAM_NCU_PROP_PRIORITY_MODE, NWAM_NCU_PROP_ACTIVATION_MODE, { NWAM_ACTIVATION_MODE_PRIORITIZED, -1 } }, /* show ipv4-addrsrc if ip-version == ipv4 */ { NWAM_NCU_PROP_IPV4_ADDRSRC, NWAM_NCU_PROP_IP_VERSION, { IPV4_VERSION, -1 } }, /* show ipv4-addr if ipv4-addrsrc == static */ { NWAM_NCU_PROP_IPV4_ADDR, NWAM_NCU_PROP_IPV4_ADDRSRC, { NWAM_ADDRSRC_STATIC, -1 } }, /* show ipv4-default-route if ip-version == ipv4 */ { NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE, NWAM_NCU_PROP_IP_VERSION, { IPV4_VERSION, -1 } }, /* show ipv6-addrsrc if ip-version == ipv6 */ { NWAM_NCU_PROP_IPV6_ADDRSRC, NWAM_NCU_PROP_IP_VERSION, { IPV6_VERSION, -1 } }, /* show ipv6-addr if ipv6-addrsrc == static */ { NWAM_NCU_PROP_IPV6_ADDR, NWAM_NCU_PROP_IPV6_ADDRSRC, { NWAM_ADDRSRC_STATIC, -1 } }, /* show ipv6-default-route if ip-version == ipv6 */ { NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE, NWAM_NCU_PROP_IP_VERSION, { IPV6_VERSION, -1 } }, { NULL, NULL, { -1 } } }; /* Rules for ENMs */ static prop_display_entry_t enm_prop_display_entry_table[] = { /* show conditions if activation-mode == conditional-{all,any} */ { NWAM_ENM_PROP_CONDITIONS, NWAM_ENM_PROP_ACTIVATION_MODE, { NWAM_ACTIVATION_MODE_CONDITIONAL_ALL, NWAM_ACTIVATION_MODE_CONDITIONAL_ANY, -1 } }, { NULL, NULL, { -1 } } }; /* Rules for LOCations */ static prop_display_entry_t loc_prop_display_entry_table[] = { /* show conditions if activation-mode == conditional-{all,any} */ { NWAM_LOC_PROP_CONDITIONS, NWAM_LOC_PROP_ACTIVATION_MODE, { NWAM_ACTIVATION_MODE_CONDITIONAL_ALL, NWAM_ACTIVATION_MODE_CONDITIONAL_ANY, -1 } }, /* show dns-nameservice-configsrc if nameservices == dns */ { NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC, NWAM_LOC_PROP_NAMESERVICES, { NWAM_NAMESERVICES_DNS, -1 } }, /* show other DNS options if dns-nameservices-configsrc == manual */ { NWAM_LOC_PROP_DNS_NAMESERVICE_DOMAIN, NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC, { NWAM_CONFIGSRC_MANUAL, -1 } }, { NWAM_LOC_PROP_DNS_NAMESERVICE_SERVERS, NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC, { NWAM_CONFIGSRC_MANUAL, -1 } }, { NWAM_LOC_PROP_DNS_NAMESERVICE_SEARCH, NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC, { NWAM_CONFIGSRC_MANUAL, -1 } }, /* show nis-nameservice-configsrc if nameservices == nis */ { NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC, NWAM_LOC_PROP_NAMESERVICES, { NWAM_NAMESERVICES_NIS, -1 } }, /* show nis-nameservice-servers if nis-nameservice-configsrc = manual */ { NWAM_LOC_PROP_NIS_NAMESERVICE_SERVERS, NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC, { NWAM_CONFIGSRC_MANUAL, -1 } }, /* show ldap-nameservice-configsrc if nameservices == ldap */ { NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC, NWAM_LOC_PROP_NAMESERVICES, { NWAM_NAMESERVICES_LDAP, -1 } }, /* show ldap-nameservice-servers if ldap-nameservice-configsrc=manual */ { NWAM_LOC_PROP_LDAP_NAMESERVICE_SERVERS, NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC, { NWAM_CONFIGSRC_MANUAL, -1 } }, /* show default-domain if {nis,ldap}-nameservice-configsrc == manual */ { NWAM_LOC_PROP_DEFAULT_DOMAIN, NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC, { NWAM_CONFIGSRC_MANUAL, -1 } }, { NWAM_LOC_PROP_DEFAULT_DOMAIN, NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC, { NWAM_CONFIGSRC_MANUAL, -1 } }, { NULL, NULL, { -1 } } }; /* Rules for Known WLANs */ static prop_display_entry_t wlan_prop_display_entry_table[] = { /* no rules for WLANs */ { NULL, NULL, { -1 } } }; /* Returns the appropriate rules table for the given object type */ static prop_display_entry_t * get_prop_display_table(nwam_object_type_t object_type) { switch (object_type) { case NWAM_OBJECT_TYPE_NCU: return (ncu_prop_display_entry_table); case NWAM_OBJECT_TYPE_LOC: return (loc_prop_display_entry_table); case NWAM_OBJECT_TYPE_ENM: return (enm_prop_display_entry_table); case NWAM_OBJECT_TYPE_KNOWN_WLAN: return (wlan_prop_display_entry_table); } return (NULL); } /* * Tests whether prop must be shown during a walk depending on the * value of a different property. * * This function is also used by set_func() to determine whether the * property being set should be allowed or not. If the property * would not be displayed in a walk, then it should not be set. * * The checked_props and num_checked arguments are used to avoid circular * dependencies between properties. When this function recursively calls * itself, it adds the property that it just checked to the checked_props * list. */ static boolean_t show_prop_test(nwam_object_type_t object_type, const char *prop, prop_display_entry_t *display_list, char **checked_props, int num_checked) { nwam_error_t ret; nwam_value_t prop_val; nwam_value_type_t prop_type; int i, j, k; boolean_t prop_found = B_FALSE, show_prop = B_FALSE; /* * Check if this property has already been checked previously in * the recursion. If so, return B_FALSE so that the initial prop * is not displayed. */ for (i = 0; i < num_checked; i++) { if (strcmp(prop, checked_props[i]) == 0) { free(checked_props); return (B_FALSE); } } for (i = 0; display_list[i].pde_name != NULL; i++) { if (strcmp(prop, display_list[i].pde_name) != 0) continue; prop_found = B_TRUE; /* get the value(s) of the (other) property to check */ switch (object_type) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_get_prop_value(ncu_h, display_list[i].pde_checkname, &prop_val); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_get_prop_value(loc_h, display_list[i].pde_checkname, &prop_val); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_get_prop_value(enm_h, display_list[i].pde_checkname, &prop_val); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: return (B_TRUE); } if (ret != NWAM_SUCCESS) continue; /* prop_val may contain a uint64 array or a boolean */ if (nwam_value_get_type(prop_val, &prop_type) != NWAM_SUCCESS) continue; if (prop_type == NWAM_VALUE_TYPE_UINT64) { uint64_t *prop_uvals; int64_t *check_uvals; uint_t numvals; if (nwam_value_get_uint64_array(prop_val, &prop_uvals, &numvals) != NWAM_SUCCESS) { nwam_value_free(prop_val); continue; } /* for each value in uvals, check each value in table */ for (j = 0; j < numvals; j++) { check_uvals = display_list[i].pde_checkvals; for (k = 0; check_uvals[k] != -1; k++) { /* show if uvals[j] matches */ if (prop_uvals[j] == (uint64_t)check_uvals[k]) { show_prop = B_TRUE; goto next_rule; } } } } else if (prop_type == NWAM_VALUE_TYPE_BOOLEAN) { boolean_t bval; if (nwam_value_get_boolean(prop_val, &bval) != NWAM_SUCCESS) { nwam_value_free(prop_val); continue; } for (k = 0; display_list[i].pde_checkvals[k] != -1; k++) { /* show if bval matches */ if (bval == (boolean_t) display_list[i].pde_checkvals[k]) { show_prop = B_TRUE; goto next_rule; } } } next_rule: nwam_value_free(prop_val); /* * If show_prop is set, then a rule is satisfied; no need to * check other rules for this prop. However, recursively * check if the checked prop (pde_checkname) satisfies its * rules. Also, update the check_props array with this prop. */ if (show_prop) { char **newprops = realloc(checked_props, ++num_checked * sizeof (char *)); if (newprops == NULL) { free(checked_props); return (B_FALSE); } checked_props = newprops; checked_props[num_checked - 1] = (char *)prop; return (show_prop_test(object_type, display_list[i].pde_checkname, display_list, checked_props, num_checked)); } } /* * If we are here and prop_found is set, it means that no rules were * satisfied by prop; return B_FALSE. If prop_found is not set, then * prop did not have a rule so it must be displayed; return B_TRUE. */ free(checked_props); if (prop_found) return (B_FALSE); else return (B_TRUE); } /* * Returns true if the given property is read-only and cannot be modified. */ static boolean_t is_prop_read_only(nwam_object_type_t object_type, const char *prop) { boolean_t ro; switch (object_type) { case NWAM_OBJECT_TYPE_NCU: if (nwam_ncu_prop_read_only(prop, &ro) == NWAM_SUCCESS && ro) return (B_TRUE); break; case NWAM_OBJECT_TYPE_ENM: if (nwam_enm_prop_read_only(prop, &ro) == NWAM_SUCCESS && ro) return (B_TRUE); break; case NWAM_OBJECT_TYPE_LOC: if (nwam_loc_prop_read_only(prop, &ro) == NWAM_SUCCESS && ro) return (B_TRUE); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: /* no read-only properties for WLANs */ return (B_FALSE); } return (B_FALSE); } /* Returns true if the property is multi-valued */ static boolean_t is_prop_multivalued(nwam_object_type_t object_type, const char *prop) { nwam_error_t ret; boolean_t multi; switch (object_type) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_prop_multivalued(prop, &multi); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_prop_multivalued(prop, &multi); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_prop_multivalued(prop, &multi); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_prop_multivalued(prop, &multi); break; } if (ret != NWAM_SUCCESS) multi = B_FALSE; return (multi); } /* * Prints out error message specific to property that could not be set. * Property description is used to help guide user in entering correct value. */ static void invalid_set_prop_msg(const char *prop, nwam_error_t err) { const char *description; if (err == NWAM_SUCCESS) return; if (err != NWAM_ENTITY_INVALID_VALUE) { nwamerr(err, "Set error"); return; } switch (active_object_type()) { case NWAM_OBJECT_TYPE_NCU: (void) nwam_ncu_get_prop_description(prop, &description); break; case NWAM_OBJECT_TYPE_LOC: (void) nwam_loc_get_prop_description(prop, &description); break; case NWAM_OBJECT_TYPE_ENM: (void) nwam_enm_get_prop_description(prop, &description); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: (void) nwam_known_wlan_get_prop_description(prop, &description); break; } nerr("Set error: invalid value\n'%s' %s", prop, description); } /* * Sets the property value. * Read-only properties and objects cannot be set. * "read-only" is a special in that it can be set on a read-only object. * The object has to be committed before other properties can be set. * Also uses show_prop_test() to test if the property being set would * be skipped during a walk (as determined by the value of some other * property). If so, then it cannot be set. */ void set_func(cmd_t *cmd) { int pt_type = cmd->cmd_prop_type; nwam_error_t ret = NWAM_SUCCESS; nwam_value_t prop_value; const char *prop; boolean_t is_listprop = B_FALSE; nwam_object_type_t object_type; prop_display_entry_t *prop_table; char **checked = NULL; assert(cmd->cmd_argc > 0); object_type = active_object_type(); prop_table = get_prop_display_table(object_type); /* argv[0] is property value */ if ((prop = pt_to_prop_name(object_type, pt_type)) == NULL) { nerr("Set error: invalid %s property: '%s'", scope_to_str(current_scope), pt_to_str(pt_type)); return; } /* check if property can be set */ if (is_prop_read_only(object_type, prop)) { nerr("Set error: property '%s' is read-only", prop); return; } if (!show_prop_test(object_type, prop, prop_table, checked, 0)) { if (interactive_mode) { (void) printf(gettext("setting property '%s' " "has no effect\n"), prop); } } is_listprop = is_prop_multivalued(object_type, prop); prop_value = str_to_nwam_value(object_type, cmd->cmd_argv[0], pt_type, is_listprop); if (prop_value == NULL) { invalid_set_prop_msg(prop, NWAM_ENTITY_INVALID_VALUE); return; } /* set the property value */ switch (object_type) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_set_prop_value(ncu_h, prop, prop_value); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_set_prop_value(loc_h, prop, prop_value); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_set_prop_value(enm_h, prop, prop_value); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_set_prop_value(wlan_h, prop, prop_value); break; } nwam_value_free(prop_value); /* delete other properties if needed */ if (ret == NWAM_SUCCESS) need_to_commit = B_TRUE; else invalid_set_prop_msg(prop, ret); } static int list_callback(nwam_object_type_t object_type, void *handle, boolean_t *list_msgp, const char *msg) { nwam_error_t ret; char *name; nwam_ncu_class_t class; if (*list_msgp) { (void) printf("%s:\n", msg); *list_msgp = B_FALSE; } ret = object_name_from_handle(object_type, handle, &name); if (ret != NWAM_SUCCESS) { nwamerr(ret, "List error: failed to get name"); return (1); } /* If NCU, get its class and print */ if (object_type == NWAM_OBJECT_TYPE_NCU) { if ((ret = nwam_ncu_get_ncu_class(handle, &class)) != NWAM_SUCCESS) { nwamerr(ret, "List error: failed to get ncu class"); free(name); return (1); } else { (void) printf("\t%s", propval_to_str(NWAM_NCU_PROP_CLASS, class)); } } (void) printf("\t%s\n", name); free(name); return (0); } /* Print out name, type and status */ static int list_loc_callback(nwam_loc_handle_t loc, void *arg) { return (list_callback(NWAM_OBJECT_TYPE_LOC, loc, arg, "Locations")); } static int list_enm_callback(nwam_enm_handle_t enm, void *arg) { return (list_callback(NWAM_OBJECT_TYPE_ENM, enm, arg, "ENMs")); } static int list_wlan_callback(nwam_known_wlan_handle_t wlan, void *arg) { return (list_callback(NWAM_OBJECT_TYPE_KNOWN_WLAN, wlan, arg, "WLANs")); } static int list_ncp_callback(nwam_ncp_handle_t ncp, void *arg) { return (list_callback(NWAM_OBJECT_TYPE_NCP, ncp, arg, "NCPs")); } static int list_ncu_callback(nwam_ncu_handle_t ncu, void *arg) { return (list_callback(NWAM_OBJECT_TYPE_NCU, ncu, arg, "NCUs")); } /* functions to convert a value to a string */ /* ARGSUSED */ static const char * str2str(void *s, const char *prop, char *str) { (void) snprintf(str, NWAM_MAX_VALUE_LEN, "%s", s); return (str); } /* ARGSUSED */ static const char * str2qstr(void *s, const char *prop, char *qstr) { /* quoted strings */ (void) snprintf(qstr, NWAM_MAX_VALUE_LEN, "\"%s\"", s); return (qstr); } /* ARGSUSED */ static const char * int2str(void *in, const char *prop, char *instr) { (void) snprintf(instr, NWAM_MAX_VALUE_LEN, "%lld", *((int64_t *)in)); return (instr); } static const char * uint2str(void *uin, const char *prop, char *uintstr) { /* returns NWAM_SUCCESS if prop is enum with string in uintstr */ if (nwam_uint64_get_value_string(prop, *((uint64_t *)uin), (const char **)&uintstr) != NWAM_SUCCESS) { (void) snprintf(uintstr, NWAM_MAX_VALUE_LEN, "%lld", *((uint64_t *)uin)); } return (uintstr); } /* ARGSUSED */ static const char * bool2str(void *bool, const char *prop, char *boolstr) { (void) snprintf(boolstr, NWAM_MAX_VALUE_LEN, "%s", *((boolean_t *)bool) ? "true" : "false"); return (boolstr); } /* * Print the value (enums are converted to string), use DELIMITER for * array. If strings are to be "quoted", pass B_TRUE for quoted_strings. */ static void output_prop_val(const char *prop_name, nwam_value_t value, FILE *wf, boolean_t quoted_strings) { nwam_value_type_t value_type; uint_t num; /* arrays for values retrieved according to the type of value */ char **svals; uint64_t *uvals; int64_t *ivals; boolean_t *bvals; /* pointer to function to generate string representation of value */ const char *(*tostr)(void *, const char *, char *); char str[NWAM_MAX_VALUE_LEN]; /* to store the string */ int i; if (nwam_value_get_type(value, &value_type) != NWAM_SUCCESS) { nerr("Get value type error"); return; } if (value_type == NWAM_VALUE_TYPE_STRING) { if (nwam_value_get_string_array(value, &svals, &num) != NWAM_SUCCESS) { nerr("Get string array error"); return; } tostr = quoted_strings ? str2qstr : str2str; } else if (value_type == NWAM_VALUE_TYPE_INT64) { if (nwam_value_get_int64_array(value, &ivals, &num) != NWAM_SUCCESS) { nerr("Get int64 array error"); return; } tostr = int2str; } else if (value_type == NWAM_VALUE_TYPE_UINT64) { if (nwam_value_get_uint64_array(value, &uvals, &num) != NWAM_SUCCESS) { nerr("Get uint64 array error"); return; } tostr = uint2str; } else if (value_type == NWAM_VALUE_TYPE_BOOLEAN) { if (nwam_value_get_boolean_array(value, &bvals, &num) != NWAM_SUCCESS) { nerr("Get boolean array error"); return; } tostr = bool2str; } /* now, loop and print each value */ for (i = 0; i < num; i++) { void *val; /* get the pointer to the ith value to pass to func() */ if (value_type == NWAM_VALUE_TYPE_STRING) val = svals[i]; else if (value_type == NWAM_VALUE_TYPE_UINT64) val = &(uvals[i]); else if (value_type == NWAM_VALUE_TYPE_INT64) val = &(ivals[i]); else if (value_type == NWAM_VALUE_TYPE_BOOLEAN) val = &(bvals[i]); (void) fprintf(wf, "%s%s", tostr(val, prop_name, str), i != num-1 ? NWAM_VALUE_DELIMITER_STR : ""); } } /* Prints the property names aligned (for list/get) or "prop=" (for export) */ static int output_propname_common(const char *prop, nwam_value_t values, void *arg, int width) { FILE *of = (arg == NULL) ? stdout : arg; /* arg is NULL for list/get, not NULL for export */ if (arg == NULL) (void) fprintf(of, "\t%-*s\t", width, prop); else (void) fprintf(of, "%s=", prop); if (values != NULL) output_prop_val(prop, values, of, B_TRUE); (void) fprintf(of, "\n"); return (0); } static int output_propname(const char *prop, nwam_value_t values, void *arg) { return (output_propname_common(prop, values, arg, 16)); } /* For locations because of longer property names */ static int output_loc_propname(const char *prop, nwam_value_t values, void *arg) { return (output_propname_common(prop, values, arg, 25)); } /* * all_props specifies whether properties that have not been set should be * printed or not. ncp and ncu_type are used only when the object_type is * NCU. */ static nwam_error_t listprop(nwam_object_type_t object_type, void *handle, const char *name, boolean_t all_props, nwam_ncp_handle_t ncp, nwam_ncu_type_t ncu_type) { nwam_error_t ret; char *lname = NULL, *realname = NULL; boolean_t lhandle = B_FALSE; const char **props = NULL; uint_t prop_num; int i; nwam_value_t vals; /* * handle is NULL if called from a scope higher than the object's * scope, but name must be given; so get the handle. */ if (handle == NULL) { lname = trim_quotes(name); /* name may have quotes */ switch (object_type) { case NWAM_OBJECT_TYPE_NCP: if ((ret = nwam_ncp_read(lname, 0, (nwam_ncp_handle_t *)&handle)) != NWAM_SUCCESS) goto readfail; break; case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_read(ncp, lname, ncu_type, 0, (nwam_ncu_handle_t *)&handle); if (ret == NWAM_ENTITY_MULTIPLE_VALUES) { /* * Multiple NCUs with the given name exists. * Call listprop() for each NCU type. */ if ((ret = listprop(object_type, NULL, lname, all_props, ncp, NWAM_NCU_TYPE_LINK)) != NWAM_SUCCESS) goto done; ret = listprop(object_type, NULL, lname, all_props, ncp, NWAM_NCU_TYPE_INTERFACE); goto done; } else if (ret != NWAM_SUCCESS) { goto readfail; } break; case NWAM_OBJECT_TYPE_LOC: if ((ret = nwam_loc_read(lname, 0, (nwam_loc_handle_t *)&handle)) != NWAM_SUCCESS) goto readfail; break; case NWAM_OBJECT_TYPE_ENM: if ((ret = nwam_enm_read(lname, 0, (nwam_enm_handle_t *)&handle)) != NWAM_SUCCESS) goto readfail; break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: if ((ret = nwam_known_wlan_read(lname, 0, (nwam_known_wlan_handle_t *)&handle)) != NWAM_SUCCESS) goto readfail; break; } lhandle = B_TRUE; } if ((ret = object_name_from_handle(object_type, handle, &realname)) != NWAM_SUCCESS) goto done; /* get the property list */ switch (object_type) { case NWAM_OBJECT_TYPE_NCP: { /* walk NCUs */ boolean_t list_msg = B_TRUE; ret = nwam_ncp_walk_ncus(handle, list_ncu_callback, &list_msg, NWAM_FLAG_NCU_TYPE_CLASS_ALL, NULL); goto done; } case NWAM_OBJECT_TYPE_NCU: { nwam_ncu_type_t ncu_type; nwam_ncu_class_t ncu_class; if ((ret = nwam_ncu_get_ncu_type(handle, &ncu_type)) != NWAM_SUCCESS) goto done; if ((ret = nwam_ncu_get_ncu_class(handle, &ncu_class)) != NWAM_SUCCESS) goto done; ret = nwam_ncu_get_default_proplist(ncu_type, ncu_class, &props, &prop_num); break; } case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_get_default_proplist(&props, &prop_num); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_get_default_proplist(&props, &prop_num); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_get_default_proplist(&props, &prop_num); break; } if (ret != NWAM_SUCCESS) goto done; /* print object type and name */ (void) printf("%s:%s\n", nwam_object_type_to_string(object_type), realname); /* Loop through the properties and print */ for (i = 0; i < prop_num; i++) { /* get the existing value for this property */ switch (object_type) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_get_prop_value(handle, props[i], &vals); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_get_prop_value(handle, props[i], &vals); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_get_prop_value(handle, props[i], &vals); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_get_prop_value(handle, props[i], &vals); break; } if (ret != NWAM_SUCCESS) { /* _ENTITY_NOT_FOUND is ok if listing for all props */ if (!all_props) continue; else if (ret != NWAM_ENTITY_NOT_FOUND) continue; } /* print property and value */ if (object_type == NWAM_OBJECT_TYPE_LOC) output_loc_propname(props[i], vals, NULL); else output_propname(props[i], vals, NULL); nwam_value_free(vals); } done: free(lname); free(realname); if (props != NULL) free(props); if (lhandle) { switch (object_type) { case NWAM_OBJECT_TYPE_NCP: nwam_ncp_free(handle); break; case NWAM_OBJECT_TYPE_NCU: nwam_ncu_free(handle); break; case NWAM_OBJECT_TYPE_LOC: nwam_loc_free(handle); break; case NWAM_OBJECT_TYPE_ENM: nwam_enm_free(handle); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: nwam_known_wlan_free(handle); break; } } /* don't treat _ENTITY_NOT_FOUND as an error */ if (ret == NWAM_ENTITY_NOT_FOUND) ret = NWAM_SUCCESS; return (ret); readfail: /* When nwam_*_read() fails */ free(lname); return (ret); } /* * List profiles or property and its values. * If the -a option is specified, all properties are listed. */ void list_func(cmd_t *cmd) { nwam_error_t ret = NWAM_SUCCESS; boolean_t list_msg = B_TRUE; boolean_t list_loc = B_FALSE, list_enm = B_FALSE; boolean_t list_ncp = B_FALSE, list_ncu = B_FALSE; boolean_t list_wlan = B_FALSE; /* whether all properties should be listed, given by the -a option */ boolean_t all_props = B_FALSE; /* * list_props says whether the properties should be listed. * Note that, here NCUs are treated as properties of NCPs. */ boolean_t list_props = B_FALSE; /* determine which properties to list, also validity tests */ if (current_scope == NWAM_SCOPE_GBL) { /* res1_type is -1 if only "list -a" is used */ if (cmd->cmd_res1_type == -1) { nerr("'list' requires an object to be specified with " "the -a option in the global scope"); return; } if (cmd->cmd_res1_type == RT1_LOC) { list_props = B_TRUE; list_loc = B_TRUE; } else if (cmd->cmd_res1_type == RT1_ENM) { list_props = B_TRUE; list_enm = B_TRUE; } else if (cmd->cmd_res1_type == RT1_WLAN) { list_props = B_TRUE; list_wlan = B_TRUE; } else if (cmd->cmd_res1_type == RT1_NCP) { list_ncp = B_TRUE; list_props = B_TRUE; } else { list_loc = B_TRUE; list_enm = B_TRUE; list_wlan = B_TRUE; list_ncp = B_TRUE; } } if ((current_scope == NWAM_SCOPE_LOC || current_scope == NWAM_SCOPE_ENM || current_scope == NWAM_SCOPE_WLAN || current_scope == NWAM_SCOPE_NCU) && (cmd->cmd_argc >= 1 && cmd->cmd_res1_type != -1)) { nerr("Additional options are not allowed with the -a option " "at this scope"); return; } if (current_scope == NWAM_SCOPE_LOC) { list_loc = B_TRUE; list_props = B_TRUE; } if (current_scope == NWAM_SCOPE_ENM) { list_enm = B_TRUE; list_props = B_TRUE; } if (current_scope == NWAM_SCOPE_WLAN) { list_wlan = B_TRUE; list_props = B_TRUE; } if (current_scope == NWAM_SCOPE_NCP) { if (cmd->cmd_res1_type == RT1_ENM || cmd->cmd_res1_type == RT1_LOC || cmd->cmd_res1_type == RT1_WLAN) { nerr("only ncu can be listed at this scope"); return; } if (cmd->cmd_res2_type == RT2_NCU) { list_ncu = B_TRUE; list_props = B_TRUE; } else { list_ncp = B_TRUE; list_props = B_TRUE; } } if (current_scope == NWAM_SCOPE_NCU) { list_ncu = B_TRUE; list_props = B_TRUE; } /* Check if the -a option is specified to list all properties */ if (cmd->cmd_res1_type == -1 || cmd->cmd_argc == 2) { int c, argc = 1; char **argv; optind = 0; /* if res1_type is -1, option is in argv[0], else in argv[1] */ if (cmd->cmd_res1_type == -1) argv = cmd->cmd_argv; else argv = &(cmd->cmd_argv[1]); while ((c = getopt(argc, argv, "a")) != EOF) { switch (c) { case 'a': all_props = B_TRUE; break; default: command_usage(CMD_LIST); return; } } if (cmd->cmd_res1_type == -1) cmd->cmd_argv[0] = NULL; } /* * Now, print objects and/or according to the flags set. * name, if requested, is in argv[0]. */ if (list_ncp) { list_msg = B_TRUE; if (list_props) { ret = listprop(NWAM_OBJECT_TYPE_NCP, ncp_h, cmd->cmd_argv[0], all_props, NULL, -1); } else { ret = nwam_walk_ncps(list_ncp_callback, &list_msg, 0, NULL); } if (ret != NWAM_SUCCESS) goto done; } if (list_ncu) { list_msg = B_TRUE; if (ncp_h == NULL) { nerr("NCP has not been read"); return; } if (list_props) { nwam_ncu_class_t ncu_class; nwam_ncu_type_t ncu_type; /* determine the NCU type first */ if (ncu_h == NULL) { ncu_class = (nwam_ncu_class_t) cmd->cmd_ncu_class_type; ncu_type = nwam_ncu_class_to_type(ncu_class); } else { if ((ret = nwam_ncu_get_ncu_type(ncu_h, &ncu_type)) != NWAM_SUCCESS) goto done; } ret = listprop(NWAM_OBJECT_TYPE_NCU, ncu_h, cmd->cmd_argv[0], all_props, ncp_h, ncu_type); if (ret != NWAM_SUCCESS) goto done; } } if (list_loc) { list_msg = B_TRUE; if (list_props) { ret = listprop(NWAM_OBJECT_TYPE_LOC, loc_h, cmd->cmd_argv[0], all_props, NULL, -1); } else { ret = nwam_walk_locs(list_loc_callback, &list_msg, NWAM_FLAG_ACTIVATION_MODE_ALL, NULL); } if (ret != NWAM_SUCCESS) goto done; } if (list_enm) { list_msg = B_TRUE; if (list_props) { ret = listprop(NWAM_OBJECT_TYPE_ENM, enm_h, cmd->cmd_argv[0], all_props, NULL, -1); } else { ret = nwam_walk_enms(list_enm_callback, &list_msg, NWAM_FLAG_ACTIVATION_MODE_ALL, NULL); } if (ret != NWAM_SUCCESS) goto done; } if (list_wlan) { list_msg = B_TRUE; if (list_props) { ret = listprop(NWAM_OBJECT_TYPE_KNOWN_WLAN, wlan_h, cmd->cmd_argv[0], all_props, NULL, -1); } else { ret = nwam_walk_known_wlans(list_wlan_callback, &list_msg, NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, NULL); } if (ret != NWAM_SUCCESS) goto done; } done: if (ret != NWAM_SUCCESS) nwamerr(ret, "List error"); } static int write_export_command(nwam_object_type_t object_type, const char *prop, nwam_value_t values, FILE *of) { /* exclude read-only properties */ if (is_prop_read_only(object_type, prop)) return (0); (void) fprintf(of, "set "); output_propname(prop, values, of); return (0); } static int export_ncu_callback(nwam_ncu_handle_t ncu, void *arg) { char *name; const char **props; nwam_ncu_type_t type; nwam_ncu_class_t class; nwam_value_t vals; nwam_error_t ret; uint_t num; int i; FILE *of = arg; assert(of != NULL); /* get the NCU's type and class */ if ((ret = nwam_ncu_get_ncu_type(ncu, &type)) != NWAM_SUCCESS) return (ret); if ((ret = nwam_ncu_get_ncu_class(ncu, &class)) != NWAM_SUCCESS) return (ret); if ((ret = nwam_ncu_get_name(ncu, &name)) != NWAM_SUCCESS) return (ret); (void) fprintf(of, "create ncu %s \"%s\"\n", propval_to_str(NWAM_NCU_PROP_CLASS, class), name); free(name); /* * Because of dependencies between properties, they have to be * exported in the same order as when they are walked. */ if ((ret = nwam_ncu_get_default_proplist(type, class, &props, &num)) != NWAM_SUCCESS) return (ret); for (i = 0; i < num; i++) { ret = nwam_ncu_get_prop_value(ncu, props[i], &vals); if (ret == NWAM_SUCCESS) { write_export_command(NWAM_OBJECT_TYPE_NCU, props[i], vals, of); nwam_value_free(vals); } } (void) fprintf(of, "end\n"); free(props); return (0); } static int export_ncp_callback(nwam_ncp_handle_t ncp, void *arg) { char *name; nwam_error_t ret; FILE *of = arg; assert(of != NULL); if ((ret = nwam_ncp_get_name(ncp, &name)) != NWAM_SUCCESS) return (ret); /* Do not export "automatic" NCP */ if (NWAM_NCP_AUTOMATIC(name)) { free(name); return (0); } (void) fprintf(of, "create ncp \"%s\"\n", name); free(name); /* now walk NCUs for this ncp */ ret = nwam_ncp_walk_ncus(ncp, export_ncu_callback, of, NWAM_FLAG_NCU_TYPE_CLASS_ALL, NULL); if (ret != NWAM_SUCCESS) { nwamerr(ret, "Export ncp error: failed to walk ncus"); return (ret); } (void) fprintf(of, "end\n"); return (0); } static int export_enm_callback(nwam_enm_handle_t enm, void *arg) { char *name; const char **props; nwam_value_t vals; nwam_error_t ret; uint_t num; int i; FILE *of = arg; assert(of != NULL); if ((ret = nwam_enm_get_name(enm, &name)) != NWAM_SUCCESS) return (ret); (void) fprintf(of, "create enm \"%s\"\n", name); free(name); /* * Because of dependencies between properties, they have to be * exported in the same order as when they are walked. */ if ((ret = nwam_enm_get_default_proplist(&props, &num)) != NWAM_SUCCESS) return (ret); for (i = 0; i < num; i++) { ret = nwam_enm_get_prop_value(enm, props[i], &vals); if (ret == NWAM_SUCCESS) { write_export_command(NWAM_OBJECT_TYPE_ENM, props[i], vals, of); nwam_value_free(vals); } } (void) fprintf(of, "end\n"); free(props); return (0); } static int export_loc_callback(nwam_loc_handle_t loc, void *arg) { char *name; const char **props; nwam_value_t vals; nwam_error_t ret; uint_t num; int i; FILE *of = arg; assert(of != NULL); if ((ret = nwam_loc_get_name(loc, &name)) != NWAM_SUCCESS) return (ret); /* Do not export Automatic, NoNet or Legacy locations */ if (NWAM_LOC_NAME_PRE_DEFINED(name)) { free(name); return (0); } (void) fprintf(of, "create loc \"%s\"\n", name); free(name); /* * Because of dependencies between properties, they have to be * exported in the same order as when they are walked. */ if ((ret = nwam_loc_get_default_proplist(&props, &num)) != NWAM_SUCCESS) return (ret); for (i = 0; i < num; i++) { ret = nwam_loc_get_prop_value(loc, props[i], &vals); if (ret == NWAM_SUCCESS) { write_export_command(NWAM_OBJECT_TYPE_LOC, props[i], vals, of); nwam_value_free(vals); } } (void) fprintf(of, "end\n"); free(props); return (0); } static int export_wlan_callback(nwam_known_wlan_handle_t wlan, void *arg) { char *name; const char **props; nwam_value_t vals; nwam_error_t ret; uint_t num; int i; FILE *of = arg; assert(of != NULL); if ((ret = nwam_known_wlan_get_name(wlan, &name)) != NWAM_SUCCESS) return (ret); (void) fprintf(of, "create wlan \"%s\"\n", name); free(name); /* * Because of dependencies between properties, they have to be * exported in the same order as when they are walked. */ if ((ret = nwam_known_wlan_get_default_proplist(&props, &num)) != NWAM_SUCCESS) return (ret); for (i = 0; i < num; i++) { ret = nwam_known_wlan_get_prop_value(wlan, props[i], &vals); if (ret == NWAM_SUCCESS) { write_export_command(NWAM_OBJECT_TYPE_KNOWN_WLAN, props[i], vals, of); nwam_value_free(vals); } } (void) fprintf(of, "end\n"); free(props); return (0); } /* * Writes configuration to screen or file (with -f option). * Writes a "destroy -a" if option -d is given. */ void export_func(cmd_t *cmd) { int c; boolean_t need_to_close = B_FALSE, write_to_file = B_FALSE; boolean_t add_destroy = B_FALSE, lhandle = B_FALSE; char filepath[MAXPATHLEN]; nwam_error_t ret = NWAM_SUCCESS; FILE *of = NULL; /* either filename or stdout */ /* what to export */ boolean_t export_ncp = B_FALSE, export_ncu = B_FALSE; boolean_t export_loc = B_FALSE, export_enm = B_FALSE; boolean_t export_wlan = B_FALSE; char *name = NULL; /* check for -d and -f flags */ filepath[0] = '\0'; optind = 0; while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "df:")) != EOF) { switch (c) { case 'f': write_to_file = B_TRUE; break; case 'd': add_destroy = B_TRUE; break; default: command_usage(CMD_EXPORT); return; } } /* determine where to export */ if (!write_to_file) { of = stdout; } else { /* * If -d was specified with -f, then argv[2] is filename, * otherwise, argv[1] is filename. */ (void) strlcpy(filepath, (add_destroy ? cmd->cmd_argv[2] : cmd->cmd_argv[1]), sizeof (filepath)); if ((of = fopen(filepath, "w")) == NULL) { nerr(gettext("opening file '%s': %s"), filepath, strerror(errno)); goto done; } setbuf(of, NULL); need_to_close = B_TRUE; } if (add_destroy) { /* only possible in global scope */ if (current_scope == NWAM_SCOPE_GBL) { (void) fprintf(of, "destroy -a\n"); } else { nerr("Option -d is not allowed in non-global scope"); goto done; } } /* In the following scopes, only the -f argument is valid */ if (((current_scope == NWAM_SCOPE_LOC || current_scope == NWAM_SCOPE_ENM || current_scope == NWAM_SCOPE_WLAN || current_scope == NWAM_SCOPE_NCU) && cmd->cmd_argc != 0 && !write_to_file)) { nerr("'export' does not take arguments at this scope"); goto done; } if (current_scope == NWAM_SCOPE_NCP) { if (cmd->cmd_res1_type == RT1_ENM || cmd->cmd_res1_type == RT1_LOC || cmd->cmd_res1_type == RT1_WLAN) { nerr("only ncu can be exported at this scope"); goto done; } } /* * Determine what objects to export depending on scope and command * arguments. If -f is specified, then the object name is argv[2]. * Otherwise, argv[0] is name, unless exporting all in global * scope in which case name is set back to NULL. */ switch (current_scope) { case NWAM_SCOPE_GBL: name = (write_to_file ? trim_quotes(cmd->cmd_argv[2]) : trim_quotes(cmd->cmd_argv[0])); switch (cmd->cmd_res1_type) { case RT1_LOC: export_loc = B_TRUE; break; case RT1_ENM: export_enm = B_TRUE; break; case RT1_WLAN: export_wlan = B_TRUE; break; case RT1_NCP: export_ncp = B_TRUE; if (cmd->cmd_res2_type == RT2_NCU) { nerr("cannot export ncu at from global scope"); goto done; } break; default: /* export everything */ export_loc = B_TRUE; export_enm = B_TRUE; export_wlan = B_TRUE; export_ncp = B_TRUE; /* NCP will export the NCUs */ free(name); name = NULL; /* exporting all, undo name */ break; } break; case NWAM_SCOPE_LOC: export_loc = B_TRUE; ret = nwam_loc_get_name(loc_h, &name); if (ret != NWAM_SUCCESS) goto fail; break; case NWAM_SCOPE_ENM: export_enm = B_TRUE; ret = nwam_enm_get_name(enm_h, &name); if (ret != NWAM_SUCCESS) goto fail; break; case NWAM_SCOPE_WLAN: export_wlan = B_TRUE; ret = nwam_known_wlan_get_name(wlan_h, &name); if (ret != NWAM_SUCCESS) goto fail; break; case NWAM_SCOPE_NCP: if (cmd->cmd_res2_type == RT2_NCU) { export_ncu = B_TRUE; name = (write_to_file ? trim_quotes(cmd->cmd_argv[2]) : trim_quotes(cmd->cmd_argv[0])); } else { export_ncp = B_TRUE; ret = nwam_ncp_get_name(ncp_h, &name); if (ret != NWAM_SUCCESS) goto fail; } break; case NWAM_SCOPE_NCU: export_ncu = B_TRUE; ret = nwam_ncu_get_name(ncu_h, &name); if (ret != NWAM_SUCCESS) goto fail; break; default: nerr("Invalid scope"); goto done; } /* Now, export objects according to the flags set */ if (export_ncp) { lhandle = B_FALSE; if (name == NULL) { /* export all NCPs */ ret = nwam_walk_ncps(export_ncp_callback, of, 0, NULL); } else if (NWAM_NCP_AUTOMATIC(name)) { nerr("'%s' ncp cannot be exported", name); goto fail; } else { if (ncp_h == NULL) { ret = nwam_ncp_read(name, 0, &ncp_h); if (ret != NWAM_SUCCESS) goto fail; lhandle = B_TRUE; } /* will export NCUs also */ ret = export_ncp_callback(ncp_h, of); if (lhandle) { nwam_ncp_free(ncp_h); ncp_h = NULL; } } if (ret != NWAM_SUCCESS) goto fail; } if (export_ncu) { if (name == NULL) { /* export all NCUs */ ret = nwam_ncp_walk_ncus(ncp_h, export_ncu_callback, of, NWAM_FLAG_NCU_TYPE_CLASS_ALL, NULL); } else { if (ncu_h == NULL) { /* no NCU handle -> called from NCP scope */ nwam_ncu_type_t ncu_type; nwam_ncu_class_t ncu_class; ncu_class = (nwam_ncu_class_t) cmd->cmd_ncu_class_type; ncu_type = nwam_ncu_class_to_type(ncu_class); ret = nwam_ncu_read(ncp_h, name, ncu_type, 0, &ncu_h); if (ret == NWAM_SUCCESS) { /* one NCU with given name */ ret = export_ncu_callback(ncu_h, of); nwam_ncu_free(ncu_h); ncu_h = NULL; } else if (ret == NWAM_ENTITY_MULTIPLE_VALUES) { /* multiple NCUs with given name */ ret = nwam_ncu_read(ncp_h, name, NWAM_NCU_TYPE_LINK, 0, &ncu_h); if (ret != NWAM_SUCCESS) goto fail; ret = export_ncu_callback(ncu_h, of); nwam_ncu_free(ncu_h); ncu_h = NULL; ret = nwam_ncu_read(ncp_h, name, NWAM_NCU_TYPE_INTERFACE, 0, &ncu_h); if (ret != NWAM_SUCCESS) goto fail; ret = export_ncu_callback(ncu_h, of); nwam_ncu_free(ncu_h); ncu_h = NULL; } else { goto fail; } } else { /* NCU handle exists */ ret = export_ncu_callback(ncu_h, of); } } if (ret != NWAM_SUCCESS) goto fail; } if (export_loc) { lhandle = B_FALSE; if (name == NULL) { /* export all locations */ ret = nwam_walk_locs(export_loc_callback, of, NWAM_FLAG_ACTIVATION_MODE_ALL, NULL); } else if (NWAM_LOC_NAME_PRE_DEFINED(name)) { nerr("'%s' loc cannot be exported", name); goto fail; } else { if (loc_h == NULL) { ret = nwam_loc_read(name, 0, &loc_h); if (ret != NWAM_SUCCESS) goto fail; lhandle = B_TRUE; } ret = export_loc_callback(loc_h, of); if (lhandle) { nwam_loc_free(loc_h); loc_h = NULL; } } if (ret != NWAM_SUCCESS) goto fail; } if (export_enm) { lhandle = B_FALSE; if (name == NULL) { /* export all ENMs */ ret = nwam_walk_enms(export_enm_callback, of, NWAM_FLAG_ACTIVATION_MODE_ALL, NULL); } else { if (enm_h == NULL) { ret = nwam_enm_read(name, 0, &enm_h); if (ret != NWAM_SUCCESS) goto fail; lhandle = B_TRUE; } ret = export_enm_callback(enm_h, of); if (lhandle) { nwam_enm_free(enm_h); enm_h = NULL; } } if (ret != NWAM_SUCCESS) goto fail; } if (export_wlan) { lhandle = B_FALSE; if (name == NULL) { /* export all WLANs */ ret = nwam_walk_known_wlans(export_wlan_callback, of, NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, NULL); } else { if (wlan_h == NULL) { ret = nwam_known_wlan_read(name, 0, &wlan_h); if (ret != NWAM_SUCCESS) goto fail; lhandle = B_TRUE; } ret = export_wlan_callback(wlan_h, of); if (lhandle) { nwam_known_wlan_free(wlan_h); wlan_h = NULL; } } if (ret != NWAM_SUCCESS) goto fail; } fail: free(name); if (ret != NWAM_SUCCESS) nwamerr(ret, "Export error"); done: if (need_to_close) (void) fclose(of); } /* * Get property value. If the -V option is specified, only the value is * printed without the property name. */ void get_func(cmd_t *cmd) { nwam_error_t ret = NWAM_SUCCESS; nwam_value_t prop_value; const char *prop; boolean_t value_only = B_FALSE; nwam_object_type_t object_type = active_object_type(); /* check if option is -V to print value only */ if (cmd->cmd_argc == 1) { int c; optind = 0; while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "V")) != EOF) { switch (c) { case 'V': value_only = B_TRUE; break; default: command_usage(CMD_GET); return; } } } /* property to get is in cmd->cmd_prop_type */ if ((prop = pt_to_prop_name(object_type, cmd->cmd_prop_type)) == NULL) { nerr("Get error: invalid %s property: '%s'", scope_to_str(current_scope), pt_to_str(cmd->cmd_prop_type)); return; } switch (object_type) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_get_prop_value(ncu_h, prop, &prop_value); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_get_prop_value(loc_h, prop, &prop_value); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_get_prop_value(enm_h, prop, &prop_value); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_get_prop_value(wlan_h, prop, &prop_value); break; } if (ret != NWAM_SUCCESS) { if (ret == NWAM_ENTITY_NOT_FOUND) nerr("Get error: property '%s' has not been set", prop); else nwamerr(ret, "Get error"); return; } if (value_only) { output_prop_val(prop, prop_value, stdout, B_FALSE); (void) printf("\n"); } else { output_propname(prop, prop_value, NULL); } nwam_value_free(prop_value); } /* * Clears value of a property. * Read-only properties cannot be cleared. * If clearing a property invalidates the object, then that property * cannot be cleared. */ void clear_func(cmd_t *cmd) { nwam_error_t ret; const char *prop; nwam_object_type_t object_type = active_object_type(); /* property to clear is in cmd->cmd_prop_type */ if ((prop = pt_to_prop_name(object_type, cmd->cmd_prop_type)) == NULL) { nerr("Clear error: invalid %s property: '%s'", scope_to_str(current_scope), pt_to_str(cmd->cmd_prop_type)); return; } if (is_prop_read_only(object_type, prop)) { nerr("Clear error: property '%s' is read-only", prop); return; } switch (object_type) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_delete_prop(ncu_h, prop); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_delete_prop(loc_h, prop); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_delete_prop(enm_h, prop); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_delete_prop(wlan_h, prop); break; } if (ret != NWAM_SUCCESS) { if (ret == NWAM_INVALID_ARG || ret == NWAM_ENTITY_NOT_FOUND) { nerr("Clear error: property '%s' has not been set", prop); } else { nwamerr(ret, "Clear error"); } return; } need_to_commit = B_TRUE; } /* * Prints all the choices available for an enum property [c1|c2|c3]. * Prints [true|false] for a boolean property. */ static void print_all_prop_choices(nwam_object_type_t object_type, const char *prop) { uint64_t i = 0; const char *str; boolean_t choices = B_FALSE; nwam_value_type_t value_type; nwam_error_t ret; /* Special case: print object-specific options for activation-mode */ if (strcmp(prop, NWAM_NCU_PROP_ACTIVATION_MODE) == 0) { /* "manual" for all objects */ (void) printf(" [%s|", propval_to_str(NWAM_NCU_PROP_ACTIVATION_MODE, NWAM_ACTIVATION_MODE_MANUAL)); if (object_type == NWAM_OBJECT_TYPE_NCU) { (void) printf("%s]", propval_to_str(NWAM_NCU_PROP_ACTIVATION_MODE, NWAM_ACTIVATION_MODE_PRIORITIZED)); } else { (void) printf("%s|%s]", propval_to_str(NWAM_NCU_PROP_ACTIVATION_MODE, NWAM_ACTIVATION_MODE_CONDITIONAL_ANY), propval_to_str(NWAM_NCU_PROP_ACTIVATION_MODE, NWAM_ACTIVATION_MODE_CONDITIONAL_ALL)); } return; } /* Special case: only "manual" configsrc is allowed for LDAP */ if (strcmp(prop, NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC) == 0) { (void) printf(" [%s]", propval_to_str(NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC, NWAM_CONFIGSRC_MANUAL)); return; } value_type = prop_value_type(object_type, prop); switch (value_type) { case NWAM_VALUE_TYPE_UINT64: /* uint64 may be an enum, will print nothing if not an enum */ while ((ret = nwam_uint64_get_value_string(prop, i++, &str)) == NWAM_SUCCESS || ret == NWAM_ENTITY_INVALID_VALUE) { /* No string representation for i, continue. */ if (ret == NWAM_ENTITY_INVALID_VALUE) continue; if (!choices) (void) printf("%s", " ["); (void) printf("%s%s", choices ? "|" : "", str); choices = B_TRUE; } if (choices) (void) putchar(']'); break; case NWAM_VALUE_TYPE_BOOLEAN: (void) printf(" [%s|%s]", "true", "false"); break; case NWAM_VALUE_TYPE_STRING: break; } } /* * Walk through object properties. * For newly-created object, the property name with no value is displayed, and * the user can input a value for each property. * For existing object, the current value is displayed and user input overwrites * the existing one. If no input is given, the existing value remains. * Read-only properties are not displayed. * Read-only objects cannot be walked. * If the -a option is specified, no properties are skipped. */ void walkprop_func(cmd_t *cmd) { nwam_error_t ret = NWAM_SUCCESS; nwam_value_t vals = NULL; /* freed in _wait_input() */ int i; uint_t prop_num; const char **props; boolean_t read_only = B_FALSE, all_props = B_FALSE; nwam_object_type_t object_type; prop_display_entry_t *prop_table; if (!interactive_mode) { nerr("'walkprop' is only allowed in interactive mode"); return; } /* check if option -a is specified to show all properties */ if (cmd->cmd_argc == 1) { int c; optind = 0; while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "a")) != EOF) { switch (c) { case 'a': all_props = B_TRUE; break; default: command_usage(CMD_WALKPROP); return; } } } /* read-only objects cannot be walked */ if (obj1_type == RT1_NCP) { /* must be in NCU scope, NCP scope doesn't get here */ (void) nwam_ncu_get_read_only(ncu_h, &read_only); } if (read_only) { nerr("'walkprop' cannot be used in read-only objects"); return; } /* get the current object type and the prop_display_table */ object_type = active_object_type(); prop_table = get_prop_display_table(object_type); /* get the property list depending on the object type */ switch (object_type) { case NWAM_OBJECT_TYPE_NCU: { nwam_ncu_type_t ncu_type; nwam_ncu_class_t ncu_class; if ((ret = nwam_ncu_get_ncu_type(ncu_h, &ncu_type)) != NWAM_SUCCESS) break; if ((ret = nwam_ncu_get_ncu_class(ncu_h, &ncu_class)) != NWAM_SUCCESS) break; ret = nwam_ncu_get_default_proplist(ncu_type, ncu_class, &props, &prop_num); break; } case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_get_default_proplist(&props, &prop_num); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_get_default_proplist(&props, &prop_num); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_get_default_proplist(&props, &prop_num); break; } if (ret != NWAM_SUCCESS) { nwamerr(ret, "Walkprop error: could not get property list"); return; } /* Loop through the properties */ if (all_props) (void) printf(gettext("Walking all properties ...\n")); for (i = 0; i < prop_num; i++) { char line[NWAM_MAX_VALUE_LEN]; char **checked = NULL; /* check if this property should be displayed */ if (is_prop_read_only(object_type, props[i])) continue; if (!all_props && !show_prop_test(object_type, props[i], prop_table, checked, 0)) continue; /* get the existing value for this property */ switch (object_type) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_get_prop_value(ncu_h, props[i], &vals); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_get_prop_value(loc_h, props[i], &vals); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_get_prop_value(enm_h, props[i], &vals); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_get_prop_value(wlan_h, props[i], &vals); break; } /* returns NWAM_ENTITY_NOT_FOUND if no existing value */ if (ret != NWAM_SUCCESS && ret != NWAM_ENTITY_NOT_FOUND) continue; /* print property */ (void) printf("%s", props[i]); /* print the existing value(s) if they exist */ if (ret == NWAM_SUCCESS) { (void) printf(" ("); output_prop_val(props[i], vals, stdout, B_TRUE); (void) putchar(')'); nwam_value_free(vals); } /* print choices, won't print anything if there aren't any */ print_all_prop_choices(object_type, props[i]); (void) printf("> "); /* wait for user input */ if (fgets(line, sizeof (line), stdin) == NULL) continue; /* if user input new value, existing value is overrode */ if (line[0] != '\n') { boolean_t is_listprop; int pt_type = prop_to_pt(object_type, props[i]); is_listprop = is_prop_multivalued(object_type, props[i]); vals = str_to_nwam_value(object_type, line, pt_type, is_listprop); if (vals == NULL) { ret = NWAM_ENTITY_INVALID_VALUE; goto repeat; } /* set the new value for the property */ switch (object_type) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_set_prop_value(ncu_h, props[i], vals); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_set_prop_value(loc_h, props[i], vals); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_set_prop_value(enm_h, props[i], vals); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_set_prop_value(wlan_h, props[i], vals); break; } nwam_value_free(vals); if (ret != NWAM_SUCCESS) goto repeat; need_to_commit = B_TRUE; continue; repeat: invalid_set_prop_msg(props[i], ret); i--; /* decrement i to repeat */ } } free(props); } /* * Verify whether all properties of a resource are valid. */ /* ARGSUSED */ void verify_func(cmd_t *cmd) { nwam_error_t ret; const char *errprop; switch (active_object_type()) { case NWAM_OBJECT_TYPE_NCU: ret = nwam_ncu_validate(ncu_h, &errprop); break; case NWAM_OBJECT_TYPE_LOC: ret = nwam_loc_validate(loc_h, &errprop); break; case NWAM_OBJECT_TYPE_ENM: ret = nwam_enm_validate(enm_h, &errprop); break; case NWAM_OBJECT_TYPE_KNOWN_WLAN: ret = nwam_known_wlan_validate(wlan_h, &errprop); break; } if (ret != NWAM_SUCCESS) nwamerr(ret, "Verify error on property '%s'", errprop); else if (interactive_mode) (void) printf(gettext("All properties verified\n")); } /* * command-line mode (# nwamcfg list or # nwamcfg "select loc test; list") */ static int one_command_at_a_time(int argc, char *argv[]) { char *command; size_t len = 2; /* terminal \n\0 */ int i, err; for (i = 0; i < argc; i++) len += strlen(argv[i]) + 1; if ((command = malloc(len)) == NULL) { nerr("Out of memory"); return (NWAM_ERR); } (void) strlcpy(command, argv[0], len); for (i = 1; i < argc; i++) { (void) strlcat(command, " ", len); (void) strlcat(command, argv[i], len); } (void) strlcat(command, "\n", len); err = string_to_yyin(command); free(command); if (err != NWAM_OK) return (err); while (!feof(yyin)) { yyparse(); /* * If any command on a list of commands give an error, * don't continue with the remaining commands. */ if (saw_error || time_to_exit) return (cleanup()); } /* if there are changes to commit, commit it */ if (need_to_commit) { do_commit(); /* if need_to_commit is not set, then there was a error */ if (need_to_commit) return (NWAM_ERR); } if (!interactive_mode) return (cleanup()); else { yyin = stdin; return (read_input()); } } /* * cmd_file is slightly more complicated, as it has to open the command file * and set yyin appropriately. Once that is done, though, it just calls * read_input(), and only once, since prompting is not possible. */ static int cmd_file(char *file) { FILE *infile; int err; struct stat statbuf; boolean_t using_real_file = (strcmp(file, "-") != 0); if (using_real_file) { /* * nerr() prints a line number in cmd_file_mode, which we do * not want here, so temporarily unset it. */ cmd_file_mode = B_FALSE; if ((infile = fopen(file, "r")) == NULL) { nerr(gettext("could not open file '%s': %s"), file, strerror(errno)); return (1); } if ((err = fstat(fileno(infile), &statbuf)) != 0) { nerr(gettext("could not stat file '%s': %s"), file, strerror(errno)); err = 1; goto done; } if (!S_ISREG(statbuf.st_mode)) { nerr(gettext("'%s' is not a regular file."), file); err = 1; goto done; } /* * If -d was passed on the command-line, we need to * start by removing any existing configuration. * Alternatively, the file may begin with 'destroy -a'; * but in that case, the line will go through the lexer * and be processed as it's encountered in the file. */ if (remove_all_configurations && destroy_all() != NWAM_SUCCESS) goto done; /* set up for lexer */ yyin = infile; cmd_file_mode = B_TRUE; ok_to_prompt = B_FALSE; } else { /* * "-f -" is essentially the same as interactive mode, * so treat it that way. */ interactive_mode = B_TRUE; } /* NWAM_REPEAT is for interactive mode; treat it like NWAM_ERR here. */ if ((err = read_input()) == NWAM_REPEAT) err = NWAM_ERR; if (err == NWAM_OK) (void) printf(gettext("Configuration read.\n")); done: if (using_real_file) (void) fclose(infile); return (err); } int main(int argc, char *argv[]) { int err; char c; /* This must be before anything goes to stdout. */ setbuf(stdout, NULL); if ((execname = strrchr(argv[0], '/')) == NULL) execname = argv[0]; else execname++; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); while ((c = getopt(argc, argv, "?hf:d")) != EOF) { switch (c) { case 'f': cmd_file_name = optarg; cmd_file_mode = B_TRUE; break; case '?': case 'h': cmd_line_usage(); return (NWAM_OK); case 'd': remove_all_configurations = B_TRUE; break; default: cmd_line_usage(); return (NWAM_ERR); } } /* -d can only be used with -f */ if (remove_all_configurations && !cmd_file_mode) { nerr("Option -d can only be used with -f"); return (NWAM_ERR); } /* * This may get set back to FALSE again in cmd_file() if cmd_file_name * is a "real" file as opposed to "-" (i.e. meaning use stdin). */ if (isatty(STDIN_FILENO)) ok_to_prompt = B_TRUE; if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) exit(NWAM_ERR); if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0) exit(NWAM_ERR); (void) sigset(SIGINT, SIG_IGN); if (optind == argc) { /* interactive or command-file mode */ if (!cmd_file_mode) err = do_interactive(); else err = cmd_file(cmd_file_name); } else { /* command-line mode */ err = one_command_at_a_time(argc - optind, &(argv[optind])); } (void) del_GetLine(gl); return (err); }