/*
* 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);
}