1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
  25  */
  26 
  27 /*
  28  * nwamcfg is a lex/yacc based command interpreter used to manage network
  29  * configurations.  The lexer (see nwamcfg_lex.l) builds up tokens, which
  30  * the grammar (see nwamcfg_grammar.y) builds up into commands, some of
  31  * which takes resources and/or properties as arguments.
  32  */
  33 
  34 #include <arpa/inet.h>
  35 #include <assert.h>
  36 #include <ctype.h>
  37 #include <errno.h>
  38 #include <libnwam.h>
  39 #include <libtecla.h>
  40 #include <locale.h>
  41 #include <stdarg.h>
  42 #include <stdio.h>
  43 #include <string.h>
  44 #include <sys/stat.h>
  45 #include <sys/sysmacros.h>
  46 #include <sys/types.h>
  47 #include <unistd.h>
  48 
  49 #include "nwamcfg.h"
  50 
  51 #if !defined(TEXT_DOMAIN)               /* should be defined by cc -D */
  52 #define TEXT_DOMAIN     "SYS_TEST"      /* Use this only if it wasn't */
  53 #endif
  54 
  55 struct help {
  56         uint_t          cmd_num;
  57         const char      *cmd_name;
  58         const char      *cmd_usage;
  59 };
  60 
  61 extern int yyparse(void);
  62 extern int lex_lineno;
  63 
  64 #define MAX_LINE_LEN    1024
  65 #define MAX_CMD_HIST    1024
  66 
  67 /* usage of commands */
  68 #define SHELP_CANCEL    "cancel"
  69 #define SHELP_CLEAR     "clear <prop-name>"
  70 #define SHELP_COMMIT    "commit"
  71 #define SHELP_CREATE    "create [-t <template>] <object-type> [<class>] " \
  72                         "<object-name>"
  73 #define SHELP_DESTROY   "destroy {-a | <object-type> [<class>] <object-name>}"
  74 #define SHELP_END       "end"
  75 #define SHELP_EXIT      "exit"
  76 #define SHELP_EXPORT    "export [-d] [-f <output-file>] " \
  77                         "[<object-type> [<class>] <object-name>]"
  78 #define SHELP_GET       "get [-V] <prop-name>"
  79 #define SHELP_HELP      "help [command-name]"
  80 #define SHELP_LIST      "list [-a] [<object-type> [<class>] <object-name>]"
  81 #define SHELP_REVERT    "revert"
  82 #define SHELP_SELECT    "select <object-type> [<class>] <object-name>"
  83 #define SHELP_SET       "set <prop-name>=<value1>[,<value2>...]"
  84 #define SHELP_VERIFY    "verify"
  85 #define SHELP_WALK      "walkprop [-a]"
  86 
  87 /*
  88  * Scope Definitions:
  89  * Locations, ENMs, NCPs and Known WLANs are one scope level below global (GBL).
  90  * NCUs are one more level beneath the NCP scope.
  91  * Because the commands in Locations/ENM/Known WLAN and NCP level are different,
  92  * the scope are divided accordingly.
  93  *     GBL->LOC, GBL->ENM, GBL->WLAN or GBL->NCP->NCU
  94  */
  95 #define NWAM_SCOPE_GBL  0
  96 #define NWAM_SCOPE_LOC  1
  97 #define NWAM_SCOPE_ENM  2
  98 #define NWAM_SCOPE_WLAN 3
  99 #define NWAM_SCOPE_NCP  4
 100 #define NWAM_SCOPE_NCU  5
 101 
 102 /* delimiter used for list of values */
 103 #define NWAM_VALUE_DELIMITER_CHAR       ','
 104 #define NWAM_VALUE_DELIMITER_STR        ","
 105 
 106 /* the max number of values for an enum used by some properties in libnwam */
 107 
 108 /*
 109  * All arrays/tables are null-terminated, rather than defining the length of
 110  * the array.  When looping, check for NULL rather than using the size.
 111  */
 112 
 113 static struct help helptab[] = {
 114         { CMD_CANCEL,   "cancel",       SHELP_CANCEL    },
 115         { CMD_CLEAR,    "clear",        SHELP_CLEAR     },
 116         { CMD_COMMIT,   "commit",       SHELP_COMMIT    },
 117         { CMD_CREATE,   "create",       SHELP_CREATE    },
 118         { CMD_DESTROY,  "destroy",      SHELP_DESTROY   },
 119         { CMD_END,      "end",          SHELP_END       },
 120         { CMD_EXIT,     "exit",         SHELP_EXIT      },
 121         { CMD_EXPORT,   "export",       SHELP_EXPORT    },
 122         { CMD_GET,      "get",          SHELP_GET       },
 123         { CMD_HELP,     "help",         SHELP_HELP      },
 124         { CMD_LIST,     "list",         SHELP_LIST      },
 125         { CMD_REVERT,   "revert",       SHELP_REVERT    },
 126         { CMD_SELECT,   "select",       SHELP_SELECT    },
 127         { CMD_SET,      "set",          SHELP_SET       },
 128         { CMD_VERIFY,   "verify",       SHELP_VERIFY    },
 129         { CMD_WALKPROP, "walkprop",     SHELP_WALK      },
 130         { 0, NULL, NULL }
 131 };
 132 
 133 /* These *must* match the order of the RT1_ define's from nwamcfg.h */
 134 static char *res1_types[] = {
 135         "unknown",
 136         "loc",
 137         "ncp",
 138         "enm",
 139         "wlan",
 140         NULL
 141 };
 142 
 143 /* These *must* match the order of the RT2_ define's from nwamcfg.h */
 144 static char *res2_types[] = {
 145         "unknown",
 146         "ncu",
 147         NULL
 148 };
 149 
 150 /*
 151  * No array for NCU_CLASS_.  The #define's in nwamcfg.h matches the
 152  * enum nwam_ncu_class_t in libnwam and thus uses libnwam functions to
 153  * retrieve the string representation.
 154  */
 155 
 156 /* These *MUST* match the order of the PT_ define's from nwamcfg.h */
 157 static char *pt_types[] = {
 158         "unknown",
 159         NWAM_NCU_PROP_ACTIVATION_MODE,
 160         NWAM_NCU_PROP_ENABLED,
 161         NWAM_NCU_PROP_TYPE,
 162         NWAM_NCU_PROP_CLASS,
 163         NWAM_NCU_PROP_PARENT_NCP,
 164         NWAM_NCU_PROP_PRIORITY_GROUP,
 165         NWAM_NCU_PROP_PRIORITY_MODE,
 166         NWAM_NCU_PROP_LINK_MAC_ADDR,
 167         NWAM_NCU_PROP_LINK_AUTOPUSH,
 168         NWAM_NCU_PROP_LINK_MTU,
 169         NWAM_NCU_PROP_IP_VERSION,
 170         NWAM_NCU_PROP_IPV4_ADDRSRC,
 171         NWAM_NCU_PROP_IPV4_ADDR,
 172         NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE,
 173         NWAM_NCU_PROP_IPV6_ADDRSRC,
 174         NWAM_NCU_PROP_IPV6_ADDR,
 175         NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE,
 176         NWAM_LOC_PROP_CONDITIONS,
 177         NWAM_ENM_PROP_FMRI,
 178         NWAM_ENM_PROP_START,
 179         NWAM_ENM_PROP_STOP,
 180         NWAM_LOC_PROP_NAMESERVICES,
 181         NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE,
 182         NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC,
 183         NWAM_LOC_PROP_DNS_NAMESERVICE_DOMAIN,
 184         NWAM_LOC_PROP_DNS_NAMESERVICE_SERVERS,
 185         NWAM_LOC_PROP_DNS_NAMESERVICE_SEARCH,
 186         NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC,
 187         NWAM_LOC_PROP_NIS_NAMESERVICE_SERVERS,
 188         NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC,
 189         NWAM_LOC_PROP_LDAP_NAMESERVICE_SERVERS,
 190         NWAM_LOC_PROP_DEFAULT_DOMAIN,
 191         NWAM_LOC_PROP_NFSV4_DOMAIN,
 192         NWAM_LOC_PROP_IPFILTER_CONFIG_FILE,
 193         NWAM_LOC_PROP_IPFILTER_V6_CONFIG_FILE,
 194         NWAM_LOC_PROP_IPNAT_CONFIG_FILE,
 195         NWAM_LOC_PROP_IPPOOL_CONFIG_FILE,
 196         NWAM_LOC_PROP_IKE_CONFIG_FILE,
 197         NWAM_LOC_PROP_IPSECPOLICY_CONFIG_FILE,
 198         NWAM_KNOWN_WLAN_PROP_BSSIDS,
 199         NWAM_KNOWN_WLAN_PROP_PRIORITY,
 200         NWAM_KNOWN_WLAN_PROP_KEYNAME,
 201         NWAM_KNOWN_WLAN_PROP_KEYSLOT,
 202         NWAM_KNOWN_WLAN_PROP_SECURITY_MODE,
 203         NWAM_NCU_PROP_IP_PRIMARY,
 204         NWAM_NCU_PROP_IP_REQHOST
 205 };
 206 
 207 /* properties table: maps PT_* constants to property names */
 208 typedef struct prop_table_entry {
 209         int                     pte_type;
 210         const char              *pte_name;
 211 } prop_table_entry_t;
 212 
 213 /* NCU properties table */
 214 static prop_table_entry_t ncu_prop_table[] = {
 215         { PT_TYPE,                      NWAM_NCU_PROP_TYPE },
 216         { PT_CLASS,                     NWAM_NCU_PROP_CLASS },
 217         { PT_PARENT,                    NWAM_NCU_PROP_PARENT_NCP },
 218         { PT_ACTIVATION_MODE,           NWAM_NCU_PROP_ACTIVATION_MODE },
 219         { PT_ENABLED,                   NWAM_NCU_PROP_ENABLED },
 220         { PT_PRIORITY_GROUP,            NWAM_NCU_PROP_PRIORITY_GROUP },
 221         { PT_PRIORITY_MODE,             NWAM_NCU_PROP_PRIORITY_MODE },
 222         { PT_LINK_MACADDR,              NWAM_NCU_PROP_LINK_MAC_ADDR },
 223         { PT_LINK_AUTOPUSH,             NWAM_NCU_PROP_LINK_AUTOPUSH },
 224         { PT_LINK_MTU,                  NWAM_NCU_PROP_LINK_MTU },
 225         { PT_IP_VERSION,                NWAM_NCU_PROP_IP_VERSION },
 226         { PT_IPV4_ADDRSRC,              NWAM_NCU_PROP_IPV4_ADDRSRC },
 227         { PT_IPV4_ADDR,                 NWAM_NCU_PROP_IPV4_ADDR },
 228         { PT_IPV4_DEFAULT_ROUTE,        NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE },
 229         { PT_IPV6_ADDRSRC,              NWAM_NCU_PROP_IPV6_ADDRSRC },
 230         { PT_IPV6_ADDR,                 NWAM_NCU_PROP_IPV6_ADDR },
 231         { PT_IPV6_DEFAULT_ROUTE,        NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE },
 232         { PT_IP_PRIMARY,                NWAM_NCU_PROP_IP_PRIMARY },
 233         { PT_IP_REQHOST,                NWAM_NCU_PROP_IP_REQHOST },
 234         { 0, NULL }
 235 };
 236 
 237 /* ENM properties table */
 238 static prop_table_entry_t enm_prop_table[] = {
 239         { PT_ENM_FMRI,          NWAM_ENM_PROP_FMRI },
 240         { PT_ENM_START,         NWAM_ENM_PROP_START },
 241         { PT_ENM_STOP,          NWAM_ENM_PROP_STOP },
 242         { PT_ACTIVATION_MODE,   NWAM_ENM_PROP_ACTIVATION_MODE },
 243         { PT_CONDITIONS,        NWAM_ENM_PROP_CONDITIONS },
 244         { PT_ENABLED,           NWAM_ENM_PROP_ENABLED },
 245         { 0, NULL }
 246 };
 247 
 248 /* LOCation properties table */
 249 static prop_table_entry_t loc_prop_table[] = {
 250         { PT_ACTIVATION_MODE,   NWAM_LOC_PROP_ACTIVATION_MODE },
 251         { PT_CONDITIONS,        NWAM_LOC_PROP_CONDITIONS },
 252         { PT_ENABLED,           NWAM_LOC_PROP_ENABLED },
 253         { PT_LOC_NAMESERVICES,  NWAM_LOC_PROP_NAMESERVICES },
 254         { PT_LOC_NAMESERVICES_CONFIG, NWAM_LOC_PROP_NAMESERVICES_CONFIG_FILE },
 255         { PT_LOC_DNS_CONFIGSRC, NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC },
 256         { PT_LOC_DNS_DOMAIN,    NWAM_LOC_PROP_DNS_NAMESERVICE_DOMAIN },
 257         { PT_LOC_DNS_SERVERS,   NWAM_LOC_PROP_DNS_NAMESERVICE_SERVERS },
 258         { PT_LOC_DNS_SEARCH,    NWAM_LOC_PROP_DNS_NAMESERVICE_SEARCH },
 259         { PT_LOC_NIS_CONFIGSRC, NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC },
 260         { PT_LOC_NIS_SERVERS,   NWAM_LOC_PROP_NIS_NAMESERVICE_SERVERS },
 261         { PT_LOC_LDAP_CONFIGSRC, NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC },
 262         { PT_LOC_LDAP_SERVERS,  NWAM_LOC_PROP_LDAP_NAMESERVICE_SERVERS },
 263         { PT_LOC_DEFAULT_DOMAIN, NWAM_LOC_PROP_DEFAULT_DOMAIN },
 264         { PT_LOC_NFSV4_DOMAIN,  NWAM_LOC_PROP_NFSV4_DOMAIN },
 265         { PT_LOC_IPF_CONFIG,    NWAM_LOC_PROP_IPFILTER_CONFIG_FILE },
 266         { PT_LOC_IPF_V6_CONFIG, NWAM_LOC_PROP_IPFILTER_V6_CONFIG_FILE },
 267         { PT_LOC_IPNAT_CONFIG,  NWAM_LOC_PROP_IPNAT_CONFIG_FILE },
 268         { PT_LOC_IPPOOL_CONFIG, NWAM_LOC_PROP_IPPOOL_CONFIG_FILE },
 269         { PT_LOC_IKE_CONFIG,    NWAM_LOC_PROP_IKE_CONFIG_FILE },
 270         { PT_LOC_IPSECPOL_CONFIG, NWAM_LOC_PROP_IPSECPOLICY_CONFIG_FILE },
 271         { 0, NULL }
 272 };
 273 
 274 /* Known WLAN properties table */
 275 static prop_table_entry_t wlan_prop_table[] = {
 276         { PT_WLAN_BSSIDS,       NWAM_KNOWN_WLAN_PROP_BSSIDS },
 277         { PT_WLAN_PRIORITY,     NWAM_KNOWN_WLAN_PROP_PRIORITY },
 278         { PT_WLAN_KEYNAME,      NWAM_KNOWN_WLAN_PROP_KEYNAME },
 279         { PT_WLAN_KEYSLOT,      NWAM_KNOWN_WLAN_PROP_KEYSLOT },
 280         { PT_WLAN_SECURITY_MODE, NWAM_KNOWN_WLAN_PROP_SECURITY_MODE },
 281         { 0, NULL }
 282 };
 283 
 284 /* Returns the appropriate properties table for the given object type */
 285 static prop_table_entry_t *
 286 get_prop_table(nwam_object_type_t object_type)
 287 {
 288         switch (object_type) {
 289         case NWAM_OBJECT_TYPE_NCU:
 290                 return (ncu_prop_table);
 291         case NWAM_OBJECT_TYPE_LOC:
 292                 return (loc_prop_table);
 293         case NWAM_OBJECT_TYPE_ENM:
 294                 return (enm_prop_table);
 295         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
 296                 return (wlan_prop_table);
 297         }
 298         return (NULL);
 299 }
 300 
 301 /* Global variables */
 302 
 303 /* set early in main(), never modified thereafter, used all over the place */
 304 static char *execname;
 305 
 306 /* set in modifying functions, checked in read_input() */
 307 boolean_t saw_error = B_FALSE;
 308 
 309 /* set in yacc parser, checked in read_input() */
 310 boolean_t newline_terminated;
 311 
 312 /* set in main(), checked in lex error handler */
 313 boolean_t cmd_file_mode = B_FALSE;
 314 
 315 /* set in exit_func(), checked in read_input() */
 316 static boolean_t time_to_exit = B_FALSE;
 317 
 318 /* used in nerr() and nwamerr() */
 319 static char *cmd_file_name = NULL;
 320 
 321 /* used with cmd_file to destroy all configurations */
 322 static boolean_t remove_all_configurations = B_FALSE;
 323 
 324 /* checked in read_input() and other places */
 325 static boolean_t ok_to_prompt = B_FALSE;
 326 
 327 /* initialized in do_interactive(), checked in initialize() */
 328 static boolean_t interactive_mode;
 329 
 330 static boolean_t need_to_commit = B_FALSE;
 331 
 332 /* The gl_get_line() resource object */
 333 static GetLine *gl;
 334 
 335 /* set when create or read objects, used by other func */
 336 static nwam_loc_handle_t loc_h = NULL;
 337 static nwam_enm_handle_t enm_h = NULL;
 338 static nwam_known_wlan_handle_t wlan_h = NULL;
 339 static nwam_ncu_handle_t ncu_h = NULL;
 340 static nwam_ncp_handle_t ncp_h = NULL;
 341 
 342 static int current_scope = NWAM_SCOPE_GBL;
 343 
 344 /* obj1_* are used in NWAM_SCOPE_{NCP,LOC,ENM,WLAN} */
 345 static int obj1_type;
 346 static char obj1_name[NWAM_MAX_NAME_LEN + 1];
 347 
 348 /* obj2_* are used in NWAM_SCOPE_NCU only */
 349 static int obj2_type;
 350 static char obj2_name[NWAM_MAX_NAME_LEN + 1];
 351 
 352 /* arrays for tab-completion */
 353 /* commands at NWAM_SCOPE_GBL */
 354 static const char *global_scope_cmds[] = {
 355         "create ",
 356         "destroy ",
 357         "end ",
 358         "exit ",
 359         "export ",
 360         "help ",
 361         "list ",
 362         "select ",
 363         NULL
 364 };
 365 
 366 static const char *global_create_cmds[] = {
 367         "create loc ",
 368         "create enm ",
 369         "create ncp ",
 370         "create wlan ",
 371         "create -t ",           /* template */
 372         NULL
 373 };
 374 
 375 static const char *global_destroy_cmds[] = {
 376         "destroy -a ",
 377         "destroy loc ",
 378         "destroy enm ",
 379         "destroy ncp ",
 380         "destroy wlan ",
 381         NULL
 382 };
 383 
 384 static const char *global_export_cmds[] = {
 385         "export ",
 386         "export -d ",           /* add destroy -a */
 387         "export -f ",           /* to file */
 388         "export -d -f ",        /* add destroy -a to file */
 389         "export loc ",
 390         "export enm ",
 391         "export ncp ",
 392         "export wlan ",
 393         NULL
 394 };
 395 
 396 static const char *global_list_cmds[] = {
 397         "list ",
 398         "list loc ",
 399         "list enm ",
 400         "list ncp ",
 401         "list wlan ",
 402         "list -a loc ",
 403         "list -a enm ",
 404         "list -a wlan ",
 405         NULL
 406 };
 407 
 408 static const char *global_select_cmds[] = {
 409         "select loc ",
 410         "select enm ",
 411         "select ncp ",
 412         "select wlan ",
 413         NULL
 414 };
 415 
 416 /* commands at NWAM_SCOPE_LOC, _ENM, _WLAN and _NCU */
 417 static const char *non_ncp_scope_cmds[] = {
 418         "cancel ",
 419         "clear ",
 420         "commit ",
 421         "end ",
 422         "exit ",
 423         "export ",
 424         "export -f ",
 425         "get ",
 426         "get -V ",      /* value only */
 427         "help ",
 428         "list ",
 429         "list -a ",     /* all properties */
 430         "revert ",
 431         "set ",
 432         "verify ",
 433         "walkprop ",
 434         "walkprop -a ", /* all properties */
 435         NULL
 436 };
 437 
 438 /* commands at NWAM_SCOPE_NCP */
 439 static const char *ncp_scope_cmds[] = {
 440         "cancel ",
 441         "create ",
 442         "destroy ",
 443         "end ",
 444         "exit ",
 445         "export ",
 446         "help ",
 447         "list ",
 448         "select ",
 449         NULL
 450 };
 451 
 452 static const char *ncp_create_cmds[] = {
 453         "create ncu ip ",
 454         "create ncu phys ",
 455         "create -t ",           /* template */
 456         NULL
 457 };
 458 
 459 static const char *ncp_destroy_cmds[] = {
 460         "destroy ncu ",
 461         "destroy ncu ip ",
 462         "destroy ncu phys ",
 463         NULL
 464 };
 465 
 466 static const char *ncp_export_cmds[] = {
 467         "export ",
 468         "export -f ",           /* to file */
 469         "export ncu ",
 470         "export ncu ip ",
 471         "export ncu phys ",
 472         NULL
 473 };
 474 
 475 static const char *ncp_list_cmds[] = {
 476         "list ",
 477         "list ncu ",
 478         "list ncu ip ",
 479         "list ncu phys ",
 480         "list -a ncu ",
 481         "list -a ncu ip ",
 482         "list -a ncu phys ",
 483         NULL
 484 };
 485 
 486 static const char *ncp_select_cmds[] = {
 487         "select ncu ",
 488         "select ncu ip ",
 489         "select ncu phys ",
 490         NULL
 491 };
 492 
 493 /* Functions begin here */
 494 
 495 cmd_t *
 496 alloc_cmd(void)
 497 {
 498         cmd_t *cmd = calloc(1, sizeof (cmd_t));
 499         if (cmd == NULL) {
 500                 nerr("Out of memory");
 501                 return (NULL);
 502         }
 503         cmd->cmd_argc = 0;
 504         cmd->cmd_argv[0] = NULL;
 505 
 506         return (cmd);
 507 }
 508 
 509 void
 510 free_cmd(cmd_t *cmd)
 511 {
 512         int i;
 513 
 514         for (i = 0; i < cmd->cmd_argc; i++)
 515                 free(cmd->cmd_argv[i]);
 516         free(cmd);
 517 }
 518 
 519 void
 520 array_free(void **array, int nelem)
 521 {
 522         int i;
 523         for (i = 0; i < nelem; i++)
 524                 free(array[i]);
 525         free(array);
 526 }
 527 
 528 static boolean_t
 529 initial_match(const char *line1, const char *line2, int word_end)
 530 {
 531         if (word_end <= 0)
 532                 return (B_TRUE);
 533         return (strncmp(line1, line2, word_end) == 0);
 534 }
 535 
 536 static int
 537 add_stuff(WordCompletion *cpl, const char *line1, const char **list,
 538     int word_end)
 539 {
 540         int i, err;
 541 
 542         for (i = 0; list[i] != NULL; i++) {
 543                 if (initial_match(line1, list[i], word_end)) {
 544                         err = cpl_add_completion(cpl, line1, 0, word_end,
 545                             list[i] + word_end, "", "");
 546                         if (err != 0)
 547                                 return (err);
 548                 }
 549         }
 550         return (0);
 551 }
 552 
 553 /*
 554  * To fill in the rest of a string when user types the tab key.
 555  * First digital number is the length of the string, the second digital number
 556  * is the min number of chars that is needed to uniquely identify a string.
 557  */
 558 #define MINI_STR(l, s, m, n) strncmp(l, s, MAX(MIN(sizeof (s) - 1, m), n))
 559 
 560 /* ARGSUSED */
 561 static
 562 CPL_MATCH_FN(cmd_cpl_fn)
 563 {
 564         /* tab-complete according to the current scope */
 565         switch (current_scope) {
 566         case NWAM_SCOPE_GBL:
 567                 if (MINI_STR(line, "create ", word_end, 2) == 0)
 568                         return (add_stuff(cpl, line, global_create_cmds,
 569                             word_end));
 570                 if (MINI_STR(line, "destroy ", word_end, 1) == 0)
 571                         return (add_stuff(cpl, line, global_destroy_cmds,
 572                             word_end));
 573                 if (MINI_STR(line, "export ", word_end, 3) == 0)
 574                         return (add_stuff(cpl, line, global_export_cmds,
 575                             word_end));
 576                 if (MINI_STR(line, "list ", word_end, 1) == 0)
 577                         return (add_stuff(cpl, line, global_list_cmds,
 578                             word_end));
 579                 if (MINI_STR(line, "select ", word_end, 1) == 0)
 580                         return (add_stuff(cpl, line, global_select_cmds,
 581                             word_end));
 582                 return (add_stuff(cpl, line, global_scope_cmds, word_end));
 583         case NWAM_SCOPE_LOC:
 584         case NWAM_SCOPE_ENM:
 585         case NWAM_SCOPE_WLAN:
 586         case NWAM_SCOPE_NCU:
 587                 return (add_stuff(cpl, line, non_ncp_scope_cmds, word_end));
 588         case NWAM_SCOPE_NCP:
 589                 if (MINI_STR(line, "create ", word_end, 2) == 0)
 590                         return (add_stuff(cpl, line, ncp_create_cmds,
 591                             word_end));
 592                 if (MINI_STR(line, "destroy ", word_end, 1) == 0)
 593                         return (add_stuff(cpl, line, ncp_destroy_cmds,
 594                             word_end));
 595                 if (MINI_STR(line, "export ", word_end, 3) == 0)
 596                         return (add_stuff(cpl, line, ncp_export_cmds,
 597                             word_end));
 598                 if (MINI_STR(line, "list ", word_end, 1) == 0)
 599                         return (add_stuff(cpl, line, ncp_list_cmds, word_end));
 600                 if (MINI_STR(line, "select ", word_end, 1) == 0)
 601                         return (add_stuff(cpl, line, ncp_select_cmds,
 602                             word_end));
 603                 return (add_stuff(cpl, line, ncp_scope_cmds, word_end));
 604         }
 605         /* should never get here */
 606         return (NULL);
 607 }
 608 
 609 const char *
 610 cmd_to_str(int cmd_num)
 611 {
 612         assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
 613         return (helptab[cmd_num].cmd_name);
 614 }
 615 
 616 /* Returns "loc", "enm", "wlan" or "ncp" as string */
 617 static const char *
 618 rt1_to_str(int res_type)
 619 {
 620         assert(res_type >= RT1_MIN && res_type <= RT1_MAX);
 621         return (res1_types[res_type]);
 622 }
 623 
 624 /* Returns "ncu" as string */
 625 static const char *
 626 rt2_to_str(int res_type)
 627 {
 628         assert(res_type >= RT2_MIN && res_type <= RT2_MAX);
 629         return (res2_types[res_type]);
 630 }
 631 
 632 /* Returns "ncp, "ncu", "loc", "enm", or "wlan" according to the scope */
 633 static const char *
 634 scope_to_str(int scope) {
 635         switch (scope) {
 636         case NWAM_SCOPE_GBL:
 637                 return ("global");
 638         case NWAM_SCOPE_NCP:
 639                 return ("ncp");
 640         case NWAM_SCOPE_NCU:
 641                 return ("ncu");
 642         case NWAM_SCOPE_LOC:
 643                 return ("loc");
 644         case NWAM_SCOPE_ENM:
 645                 return ("enm");
 646         case NWAM_SCOPE_WLAN:
 647                 return ("wlan");
 648         default:
 649                 return ("invalid");
 650         }
 651 }
 652 
 653 /* Given an enm property and value, returns it as a string */
 654 static const char *
 655 propval_to_str(const char *propname, uint64_t value)
 656 {
 657         const char *str;
 658 
 659         if (nwam_uint64_get_value_string(propname, value, &str) == NWAM_SUCCESS)
 660                 return (str);
 661         return (NULL);
 662 }
 663 
 664 /* Given an int for a prop, returns it as string */
 665 static const char *
 666 pt_to_str(int prop_type)
 667 {
 668         assert(prop_type >= PT_MIN && prop_type <= PT_MAX);
 669         return (pt_types[prop_type]);
 670 }
 671 
 672 /*
 673  * Return B_TRUE if string starts with "t" or "on" or is 1;
 674  * B_FALSE otherwise
 675  */
 676 static boolean_t
 677 str_to_boolean(const char *str)
 678 {
 679         if (strncasecmp(str, "t", 1) == 0 || strncasecmp(str, "on", 2) == 0 ||
 680             atoi(str) == 1)
 681                 return (B_TRUE);
 682         else
 683                 return (B_FALSE);
 684 }
 685 
 686 /*
 687  * This is a separate function rather than a set of define's because of the
 688  * gettext() wrapping.
 689  */
 690 
 691 /*
 692  * TRANSLATION_NOTE
 693  * Each string below should have \t follow \n whenever needed; the
 694  * initial \t and the terminal \n will be provided by the calling function.
 695  */
 696 
 697 static const char *
 698 long_help(int cmd_num)
 699 {
 700         assert(cmd_num >= CMD_MIN && cmd_num <= CMD_MAX);
 701         switch (cmd_num) {
 702                 case CMD_CANCEL:
 703                         return (gettext("Cancels the current configuration "
 704                             "changes."));
 705                 case CMD_CLEAR:
 706                         return (gettext("Clears the value for the specified "
 707                             "property."));
 708                 case CMD_COMMIT:
 709                         return (gettext("Commits the current configuration."));
 710                 case CMD_CREATE:
 711                         return (gettext("Creates a new profile or resource."));
 712                 case CMD_DESTROY:
 713                         return (gettext("Destroys the specified profile or "
 714                             "resource."));
 715                 case CMD_END:
 716                         return (gettext("Ends specification of a resource."));
 717                 case CMD_EXIT:
 718                         return (gettext("Exits the program."));
 719                 case CMD_EXPORT:
 720                         return (gettext("Exports the configuration."));
 721                 case CMD_GET:
 722                         return (gettext("Gets the value of the specified "
 723                             "property."));
 724                 case CMD_HELP:
 725                         return (gettext("Prints help message."));
 726                 case CMD_LIST:
 727                         return (gettext("Lists existing objects."));
 728                 case CMD_REVERT:
 729                         return (gettext("Reverts to the previous "
 730                             "configuration."));
 731                 case CMD_SELECT:
 732                         return (gettext("Selects a resource to modify."));
 733                 case CMD_SET:
 734                         return (gettext("Sets the value of the specified "
 735                             "property."));
 736                 case CMD_VERIFY:
 737                         return (gettext("Verifies an object."));
 738                 case CMD_WALKPROP:
 739                         return (gettext("Iterates over properties."));
 740                 default:
 741                         return (gettext("Unknown command."));
 742         }
 743 }
 744 
 745 void
 746 command_usage(int command)
 747 {
 748         if (command < CMD_MIN || command > CMD_MAX) {
 749                 nerr("Unknown command");
 750         } else {
 751                 nerr("%s: %s: %s", gettext("Error"), gettext("usage"),
 752                     helptab[command].cmd_usage);
 753         }
 754 }
 755 
 756 static void
 757 long_usage(uint_t cmd_num)
 758 {
 759         (void) printf("%s: %s\n", gettext("usage"),
 760             helptab[cmd_num].cmd_usage);
 761         (void) printf("\t%s\n", long_help(cmd_num));
 762 }
 763 
 764 /* Prints usage for command line options */
 765 static void
 766 cmd_line_usage()
 767 {
 768         (void) printf("%s:\t%s\t\t\t\t(%s)\n", gettext("usage"), execname,
 769             gettext("interactive-mode"));
 770         (void) printf("\t%s <%s> [%s...]\n", execname, gettext("command"),
 771             gettext("options"));
 772         (void) printf("\t%s [-d] -f <%s>\n", execname, gettext("command-file"));
 773         (void) printf("\t%s %s [<%s>]\n", execname, cmd_to_str(CMD_HELP),
 774             gettext("command"));
 775 }
 776 
 777 /* Prints the line number of the current command if in command-file mode */
 778 static void
 779 print_lineno()
 780 {
 781         static int last_lineno;
 782 
 783         /* lex_lineno has already been incremented in the lexer; compensate */
 784         if (cmd_file_mode && lex_lineno > last_lineno) {
 785                 if (strcmp(cmd_file_name, "-") == 0)
 786                         (void) fprintf(stderr, gettext("On line %d:\n"),
 787                             lex_lineno - 1);
 788                 else
 789                         (void) fprintf(stderr, gettext("On line %d of %s:\n"),
 790                             lex_lineno - 1, cmd_file_name);
 791                 last_lineno = lex_lineno;
 792         }
 793 }
 794 
 795 /* PRINTFLIKE1 */
 796 void
 797 nerr(const char *format, ...)
 798 {
 799         va_list alist;
 800 
 801         print_lineno();
 802 
 803         format = gettext(format);
 804         va_start(alist, format);
 805         (void) vfprintf(stderr, format, alist);
 806         va_end(alist);
 807         (void) fprintf(stderr, "\n");
 808 
 809         saw_error = B_TRUE;
 810 }
 811 
 812 /* PRINTFLIKE2 */
 813 static void
 814 nwamerr(nwam_error_t err, const char *format, ...)
 815 {
 816         va_list alist;
 817 
 818         print_lineno();
 819 
 820         format = gettext(format);
 821         va_start(alist, format);
 822         (void) vfprintf(stderr, format, alist);
 823         va_end(alist);
 824         (void) fprintf(stderr, ": %s\n", nwam_strerror(err));
 825 
 826         saw_error = B_TRUE;
 827 }
 828 
 829 void
 830 properr(const char *prop)
 831 {
 832         nerr("Invalid property: '%s'", prop);
 833 }
 834 
 835 /*
 836  * If free_ncu_only == B_TRUE, only ncu handle is freed, ncp handle remains the
 837  * same.  Since nwam_ncp_free() takes care of its ncus, no need to explicitly
 838  * call nwam_ncu_free() afterwards.
 839  */
 840 static void
 841 free_handle(boolean_t free_ncu_only)
 842 {
 843         if (ncp_h != NULL) {
 844                 if (!free_ncu_only) {
 845                         nwam_ncp_free(ncp_h);
 846                         ncp_h = NULL;
 847                         ncu_h = NULL;
 848                 } else if (ncu_h != NULL) {
 849                         nwam_ncu_free(ncu_h);
 850                         ncu_h = NULL;
 851                 }
 852         }
 853 
 854         if (enm_h != NULL) {
 855                 nwam_enm_free(enm_h);
 856                 enm_h = NULL;
 857         }
 858 
 859         if (loc_h != NULL) {
 860                 nwam_loc_free(loc_h);
 861                 loc_h = NULL;
 862         }
 863 
 864         if (wlan_h != NULL) {
 865                 nwam_known_wlan_free(wlan_h);
 866                 wlan_h = NULL;
 867         }
 868 }
 869 
 870 /*
 871  * On input, TRUE => yes, FALSE => no.
 872  * On return, TRUE => 1, FALSE => no, could not ask => -1.
 873  */
 874 static int
 875 ask_yesno(boolean_t default_answer, const char *question)
 876 {
 877         char line[64];  /* should be enough to answer yes or no */
 878 
 879         if (!ok_to_prompt) {
 880                 saw_error = B_TRUE;
 881                 return (-1);
 882         }
 883         for (;;) {
 884                 if (printf("%s (%s)? ", gettext(question),
 885                     default_answer ? "[y]/n" : "y/[n]") < 0)
 886                         return (-1);
 887                 if (fgets(line, sizeof (line), stdin) == NULL)
 888                         return (-1);
 889 
 890                 if (line[0] == '\n')
 891                         return (default_answer ? 1 : 0);
 892                 if (tolower(line[0]) == 'y')
 893                         return (1);
 894                 if (tolower(line[0]) == 'n')
 895                         return (0);
 896         }
 897 }
 898 
 899 /* This is the back-end helper function for read_input() below. */
 900 static int
 901 cleanup()
 902 {
 903         int answer;
 904 
 905         if (!interactive_mode && !cmd_file_mode) {
 906                 /*
 907                  * If we're not in interactive mode, and we're not in command
 908                  * file mode, then we must be in commands-from-the-command-line
 909                  * mode.  As such, we can't loop back and ask for more input.
 910                  * It was OK to prompt for such things as whether or not to
 911                  * really delete something in the command handler called from
 912                  * yyparse() above, but "really quit?" makes no sense in this
 913                  * context.  So disable prompting.
 914                  */
 915                 ok_to_prompt = B_FALSE;
 916         }
 917         if (need_to_commit) {
 918                 answer = ask_yesno(B_FALSE,
 919                     "Configuration not saved; really quit");
 920                 switch (answer) {
 921                 case -1:
 922                         /* issue error here */
 923                         return (NWAM_ERR);
 924                 case 1:
 925                         /*
 926                          * don't want to save, just exit. handles are freed at
 927                          * end_func() or exit_func().
 928                          */
 929                         return (NWAM_OK);
 930                 default:
 931                         /* loop back to read input */
 932                         time_to_exit = B_FALSE;
 933                         yyin = stdin;
 934                         return (NWAM_REPEAT);
 935                 }
 936         }
 937         return (saw_error ? NWAM_ERR : NWAM_OK);
 938 }
 939 
 940 static int
 941 string_to_yyin(char *string)
 942 {
 943         if ((yyin = tmpfile()) == NULL)
 944                 goto error;
 945         if (fwrite(string, strlen(string), 1, yyin) != 1)
 946                 goto error;
 947         if (fseek(yyin, 0, SEEK_SET) != 0)
 948                 goto error;
 949 
 950         return (NWAM_OK);
 951 
 952 error:
 953         nerr("problem creating temporary file");
 954         return (NWAM_ERR);
 955 }
 956 
 957 /*
 958  * read_input() is the driver of this program.  It is a wrapper around
 959  * yyparse(), printing appropriate prompts when needed, checking for
 960  * exit conditions and reacting appropriately.  This function is
 961  * called when in interactive mode or command-file mode.
 962  */
 963 static int
 964 read_input(void)
 965 {
 966         boolean_t yyin_is_a_tty = isatty(fileno(yyin));
 967         /*
 968          * The prompt is "e> " or "e:t1:o1> " or "e:t1:o1:t2:o2> " where e is
 969          * execname, t is resource type, o is object name.
 970          */
 971         char prompt[MAXPATHLEN + (2 * (NWAM_MAX_TYPE_LEN + NWAM_MAX_NAME_LEN))
 972             + sizeof ("::::> ")];
 973         char *line;
 974 
 975         /* yyin should have been set to the appropriate (FILE *) if not stdin */
 976         newline_terminated = B_TRUE;
 977         for (;;) {
 978                 if (yyin_is_a_tty) {
 979                         if (newline_terminated) {
 980                                 switch (current_scope) {
 981                                 case NWAM_SCOPE_GBL:
 982                                         (void) snprintf(prompt, sizeof (prompt),
 983                                             "%s> ", execname);
 984                                         break;
 985                                 case NWAM_SCOPE_LOC:
 986                                 case NWAM_SCOPE_ENM:
 987                                 case NWAM_SCOPE_WLAN:
 988                                 case NWAM_SCOPE_NCP:
 989                                         (void) snprintf(prompt, sizeof (prompt),
 990                                             "%s:%s:%s> ", execname,
 991                                             rt1_to_str(obj1_type), obj1_name);
 992 
 993                                         break;
 994                                 case NWAM_SCOPE_NCU:
 995                                         (void) snprintf(prompt, sizeof (prompt),
 996                                             "%s:%s:%s:%s:%s> ", execname,
 997                                             rt1_to_str(obj1_type), obj1_name,
 998                                             rt2_to_str(obj2_type), obj2_name);
 999                                 }
1000                         }
1001                         /*
1002                          * If the user hits ^C then we want to catch it and
1003                          * start over.  If the user hits EOF then we want to
1004                          * bail out.
1005                          */
1006                         line = gl_get_line(gl, prompt, NULL, -1);
1007                         if (gl_return_status(gl) == GLR_SIGNAL) {
1008                                 gl_abandon_line(gl);
1009                                 continue;
1010                         }
1011                         if (line == NULL)
1012                                 break;
1013                         if (string_to_yyin(line) != NWAM_OK)
1014                                 break;
1015                         while (!feof(yyin)) {
1016                                 yyparse();
1017 
1018                                 /*
1019                                  * If any command on a list of commands
1020                                  * give an error, don't continue with the
1021                                  * remaining commands.
1022                                  */
1023                                 if (saw_error || time_to_exit)
1024                                         break;
1025                         }
1026                 } else {
1027                         yyparse();
1028                 }
1029 
1030                 /* Bail out on an error in command-file mode. */
1031                 if (saw_error && cmd_file_mode && !interactive_mode)
1032                         time_to_exit = B_TRUE;
1033                 if (time_to_exit || (!yyin_is_a_tty && feof(yyin)))
1034                         break;
1035         }
1036         return (cleanup());
1037 }
1038 
1039 /*
1040  * This function is used in the interactive-mode scenario: it just calls
1041  * read_input() until we are done.
1042  */
1043 static int
1044 do_interactive(void)
1045 {
1046         int err;
1047 
1048         interactive_mode = B_TRUE;
1049         do {
1050                 err = read_input();
1051         } while (err == NWAM_REPEAT);
1052         return (err);
1053 }
1054 
1055 /* Calls the help_func() to print the usage of all commands */
1056 void
1057 help_wrap()
1058 {
1059         cmd_t *help_cmd;
1060 
1061         if ((help_cmd = alloc_cmd()) == NULL)
1062                 exit(NWAM_ERR);
1063         help_func(help_cmd);
1064         free_cmd(help_cmd);
1065 }
1066 
1067 /* Check if the given command is allowed in the current scope */
1068 boolean_t
1069 check_scope(int cmd)
1070 {
1071         /* allowed in all scopes */
1072         switch (cmd) {
1073         case CMD_END:
1074         case CMD_EXIT:
1075         case CMD_HELP:
1076         case CMD_LIST:
1077         case CMD_EXPORT:
1078                 return (B_TRUE);
1079         }
1080         /* scope-specific */
1081         switch (current_scope) {
1082         case NWAM_SCOPE_GBL:
1083                 switch (cmd) {
1084                 case CMD_CREATE:
1085                 case CMD_DESTROY:
1086                 case CMD_SELECT:
1087                         return (B_TRUE);
1088                 }
1089                 break;
1090         case NWAM_SCOPE_LOC:
1091         case NWAM_SCOPE_ENM:
1092         case NWAM_SCOPE_WLAN:
1093         case NWAM_SCOPE_NCU:
1094                 switch (cmd) {
1095                 case CMD_CANCEL:
1096                 case CMD_CLEAR:
1097                 case CMD_COMMIT:
1098                 case CMD_GET:
1099                 case CMD_REVERT:
1100                 case CMD_SET:
1101                 case CMD_VERIFY:
1102                 case CMD_WALKPROP:
1103                         return (B_TRUE);
1104                 }
1105                 break;
1106         case NWAM_SCOPE_NCP:
1107                 switch (cmd) {
1108                 case CMD_CANCEL:
1109                 case CMD_CREATE:
1110                 case CMD_DESTROY:
1111                 case CMD_SELECT:
1112                         return (B_TRUE);
1113                 }
1114                 break;
1115         default:
1116                 nerr("Invalid scope");
1117         }
1118         nerr("'%s' is not allowed at this scope", cmd_to_str(cmd));
1119         return (B_FALSE);
1120 }
1121 
1122 /* Returns the active object type depending on which handle is not NULL */
1123 static nwam_object_type_t
1124 active_object_type()
1125 {
1126         /* Check ncu_h before ncp_h, ncp_h must be loaded before ncu_h */
1127         if (ncu_h != NULL)
1128                 return (NWAM_OBJECT_TYPE_NCU);
1129         else if (ncp_h != NULL)
1130                 return (NWAM_OBJECT_TYPE_NCP);
1131         else if (loc_h != NULL)
1132                 return (NWAM_OBJECT_TYPE_LOC);
1133         else if (enm_h != NULL)
1134                 return (NWAM_OBJECT_TYPE_ENM);
1135         else if (wlan_h != NULL)
1136                 return (NWAM_OBJECT_TYPE_KNOWN_WLAN);
1137         else
1138                 return (NWAM_OBJECT_TYPE_UNKNOWN);
1139 }
1140 
1141 /* Retrive the name of the object from its handle */
1142 static nwam_error_t
1143 object_name_from_handle(nwam_object_type_t object_type, void *handle,
1144     char **namep)
1145 {
1146         switch (object_type) {
1147         case NWAM_OBJECT_TYPE_NCP:
1148                 return (nwam_ncp_get_name(handle, namep));
1149         case NWAM_OBJECT_TYPE_NCU:
1150                 return (nwam_ncu_get_name(handle, namep));
1151         case NWAM_OBJECT_TYPE_LOC:
1152                 return (nwam_loc_get_name(handle, namep));
1153         case NWAM_OBJECT_TYPE_ENM:
1154                 return (nwam_enm_get_name(handle, namep));
1155         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
1156                 return (nwam_known_wlan_get_name(handle, namep));
1157         }
1158         return (NWAM_INVALID_ARG);
1159 }
1160 
1161 static void
1162 do_commit()
1163 {
1164         nwam_error_t    ret = NWAM_SUCCESS;
1165         const char      *errprop;
1166 
1167         if (!need_to_commit)
1168                 return;
1169 
1170         switch (active_object_type()) {
1171         case NWAM_OBJECT_TYPE_NCU:
1172                 ret = nwam_ncu_commit(ncu_h, 0);
1173                 break;
1174         case NWAM_OBJECT_TYPE_ENM:
1175                 ret = nwam_enm_commit(enm_h, 0);
1176                 break;
1177         case NWAM_OBJECT_TYPE_LOC:
1178                 ret = nwam_loc_commit(loc_h, 0);
1179                 break;
1180         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
1181                 ret = nwam_known_wlan_commit(wlan_h, 0);
1182                 break;
1183         }
1184 
1185         if (ret == NWAM_SUCCESS) {
1186                 need_to_commit = B_FALSE;
1187                 if (interactive_mode)
1188                         (void) printf(gettext("Committed changes\n"));
1189         } else {
1190                 nwam_error_t verr;
1191 
1192                 /* Find property that caused failure */
1193                 switch (active_object_type()) {
1194                 case NWAM_OBJECT_TYPE_NCU:
1195                         verr = nwam_ncu_validate(ncu_h, &errprop);
1196                         break;
1197                 case NWAM_OBJECT_TYPE_ENM:
1198                         verr = nwam_enm_validate(enm_h, &errprop);
1199                         break;
1200                 case NWAM_OBJECT_TYPE_LOC:
1201                         verr = nwam_loc_validate(loc_h, &errprop);
1202                         break;
1203                 case NWAM_OBJECT_TYPE_KNOWN_WLAN:
1204                         verr = nwam_known_wlan_validate(wlan_h, &errprop);
1205                         break;
1206                 }
1207 
1208                 if (verr != NWAM_SUCCESS)
1209                         nwamerr(ret, "Commit error on property '%s'", errprop);
1210                 else
1211                         nwamerr(ret, "Commit error");
1212         }
1213 }
1214 
1215 /*
1216  * Saves the current configuration to persistent storage.
1217  */
1218 /* ARGSUSED */
1219 void
1220 commit_func(cmd_t *cmd)
1221 {
1222         if (!need_to_commit) {
1223                 if (interactive_mode)
1224                         (void) printf(gettext("Nothing to commit\n"));
1225         } else {
1226                 do_commit();
1227         }
1228 }
1229 
1230 static void
1231 do_cancel()
1232 {
1233         switch (current_scope) {
1234         case NWAM_SCOPE_NCU:
1235                 current_scope = NWAM_SCOPE_NCP;
1236                 obj2_type = 0;
1237                 free_handle(B_TRUE);
1238                 break;
1239         case NWAM_SCOPE_NCP:
1240         case NWAM_SCOPE_ENM:
1241         case NWAM_SCOPE_WLAN:
1242         case NWAM_SCOPE_LOC:
1243                 current_scope = NWAM_SCOPE_GBL;
1244                 obj1_type = 0;
1245                 free_handle(B_FALSE);
1246                 break;
1247         case NWAM_SCOPE_GBL:
1248                 free_handle(B_FALSE);
1249                 break;
1250         default:
1251                 nerr("Invalid scope");
1252                 return;
1253         }
1254         need_to_commit = B_FALSE;
1255 }
1256 
1257 /*
1258  * End operation on current scope and go up one scope.
1259  * Changes are not saved, no prompt either.
1260  */
1261 /* ARGSUSED */
1262 void
1263 cancel_func(cmd_t *cmd)
1264 {
1265         do_cancel();
1266 }
1267 
1268 /*
1269  * Removes leading and trailing quotes from a string.
1270  * Caller must free returned string.
1271  */
1272 static char *
1273 trim_quotes(const char *quoted_str)
1274 {
1275         char *str;
1276         int end;
1277 
1278         /* export_func() and list_func() can pass NULL here */
1279         if (quoted_str == NULL)
1280                 return (NULL);
1281 
1282         /* remove leading quote */
1283         if (quoted_str[0] == '"')
1284                 str = strdup(quoted_str + 1);
1285         else
1286                 str = strdup(quoted_str);
1287         if (str == NULL)
1288                 return (NULL);
1289 
1290         /* remove trailing quote and newline */
1291         end = strlen(str) - 1;
1292         while (end >= 0 && (str[end] == '"' || str[end] == '\n'))
1293                 end--;
1294         str[end+1] = 0;
1295 
1296         return (str);
1297 }
1298 
1299 /*
1300  * Creates a new resource and enters the scope of that resource.
1301  * The new resource can also be a copy of an existing resource (-t option).
1302  * If in interactive mode, then after creation call walkprop_func()
1303  * to do walk the properties for the new object.
1304  */
1305 void
1306 create_func(cmd_t *cmd)
1307 {
1308         nwam_error_t    ret = NWAM_SUCCESS;
1309         int             c;
1310         boolean_t       template = B_FALSE;
1311         char            *newname = NULL, *oldname = NULL;
1312         cmd_t           *walkprop_cmd;
1313 
1314         /* make sure right command at the right scope */
1315         if (current_scope == NWAM_SCOPE_GBL &&
1316             cmd->cmd_res2_type == RT2_NCU) {
1317                 nerr("cannot create ncu at global scope");
1318                 return;
1319         }
1320         if (current_scope == NWAM_SCOPE_NCP &&
1321             cmd->cmd_res2_type != RT2_NCU) {
1322                 nerr("Cannot create given object at this scope");
1323                 return;
1324         }
1325 
1326         assert(cmd->cmd_argc > 0);
1327         optind = 0;
1328         while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "t:")) != EOF) {
1329                 switch (c) {
1330                 case 't':
1331                         template = B_TRUE;
1332                         break;
1333                 default:
1334                         command_usage(CMD_CREATE);
1335                         return;
1336                 }
1337         }
1338 
1339         if (!template) {
1340                 /* no template given */
1341                 /* argv[0] is name */
1342                 newname = trim_quotes(cmd->cmd_argv[0]);
1343                 if (cmd->cmd_res1_type == RT1_ENM) {
1344                         ret = nwam_enm_create(newname, NULL, &enm_h);
1345                 } else if (cmd->cmd_res1_type == RT1_LOC) {
1346                         ret = nwam_loc_create(newname, &loc_h);
1347                 } else if (cmd->cmd_res1_type == RT1_WLAN) {
1348                         ret = nwam_known_wlan_create(newname, &wlan_h);
1349                 } else if (cmd->cmd_res1_type == RT1_NCP &&
1350                     current_scope == NWAM_SCOPE_GBL) {
1351                         ret = nwam_ncp_create(newname, 0, &ncp_h);
1352                 } else if (cmd->cmd_res2_type == RT2_NCU) {
1353                         nwam_ncu_type_t         ncu_type;
1354                         nwam_ncu_class_t        ncu_class;
1355 
1356                         /* ncp must already be read */
1357                         if (ncp_h == NULL) {
1358                                 nerr("Create error: NCP has not been read");
1359                                 goto done;
1360                         }
1361 
1362                         ncu_class = (nwam_ncu_class_t)cmd->cmd_ncu_class_type;
1363                         ncu_type = nwam_ncu_class_to_type(ncu_class);
1364                         ret = nwam_ncu_create(ncp_h, newname, ncu_type,
1365                             ncu_class, &ncu_h);
1366                 }
1367 
1368                 if (ret != NWAM_SUCCESS) {
1369                         nwamerr(ret, "Create error");
1370                         goto done;
1371                 }
1372 
1373         } else {
1374                 /* template given */
1375                 /* argv[0] is -t, argv[1] is old name, argv[2] is new name */
1376                 oldname = trim_quotes(cmd->cmd_argv[1]);
1377                 newname = trim_quotes(cmd->cmd_argv[2]);
1378                 if (cmd->cmd_res1_type == RT1_ENM) {
1379                         nwam_enm_handle_t oldenm_h;
1380 
1381                         ret = nwam_enm_read(oldname, 0, &oldenm_h);
1382                         if (ret != NWAM_SUCCESS)
1383                                 goto read_error;
1384                         ret = nwam_enm_copy(oldenm_h, newname, &enm_h);
1385                         nwam_enm_free(oldenm_h);
1386                 } else if (cmd->cmd_res1_type == RT1_LOC) {
1387                         nwam_loc_handle_t oldloc_h;
1388 
1389                         ret = nwam_loc_read(oldname, 0, &oldloc_h);
1390                         if (ret != NWAM_SUCCESS)
1391                                 goto read_error;
1392                         ret = nwam_loc_copy(oldloc_h, newname, &loc_h);
1393                         nwam_loc_free(oldloc_h);
1394                 } else if (cmd->cmd_res1_type == RT1_WLAN) {
1395                         nwam_known_wlan_handle_t oldwlan_h;
1396 
1397                         ret = nwam_known_wlan_read(oldname, 0, &oldwlan_h);
1398                         if (ret != NWAM_SUCCESS)
1399                                 goto read_error;
1400                         ret = nwam_known_wlan_copy(oldwlan_h, newname, &wlan_h);
1401                         nwam_known_wlan_free(oldwlan_h);
1402                 } else if (cmd->cmd_res1_type == RT1_NCP &&
1403                     current_scope == NWAM_SCOPE_GBL) {
1404                         nwam_ncp_handle_t oldncp_h;
1405 
1406                         ret = nwam_ncp_read(oldname, 0, &oldncp_h);
1407                         if (ret != NWAM_SUCCESS)
1408                                 goto read_error;
1409                         ret = nwam_ncp_copy(oldncp_h, newname, &ncp_h);
1410                         nwam_ncp_free(oldncp_h);
1411                 } else if (cmd->cmd_res2_type == RT2_NCU) {
1412                         nwam_ncu_handle_t       oldncu_h;
1413                         nwam_ncu_type_t         ncu_type;
1414                         nwam_ncu_class_t        ncu_class;
1415 
1416                         /* ncp must already be read */
1417                         if (ncp_h == NULL) {
1418                                 nerr("Copy error: NCP has not been read");
1419                                 goto done;
1420                         }
1421                         ncu_class = (nwam_ncu_class_t)cmd->cmd_ncu_class_type;
1422                         ncu_type = nwam_ncu_class_to_type(ncu_class);
1423                         ret = nwam_ncu_read(ncp_h, oldname, ncu_type, 0,
1424                             &oldncu_h);
1425                         if (ret != NWAM_SUCCESS)
1426                                 goto read_error;
1427                         ret = nwam_ncu_copy(oldncu_h, newname, &ncu_h);
1428                         nwam_ncu_free(oldncu_h);
1429                 }
1430 
1431                 if (ret != NWAM_SUCCESS) {
1432                         nwamerr(ret, "Copy error");
1433                         goto done;
1434                 }
1435         }
1436 
1437         if (current_scope == NWAM_SCOPE_GBL) {
1438                 (void) strlcpy(obj1_name, newname, sizeof (obj1_name));
1439                 obj1_type = cmd->cmd_res1_type;
1440                 if (obj1_type == RT1_ENM)
1441                         current_scope = NWAM_SCOPE_ENM;
1442                 else if (obj1_type == RT1_LOC)
1443                         current_scope = NWAM_SCOPE_LOC;
1444                 else if (obj1_type == RT1_WLAN)
1445                         current_scope = NWAM_SCOPE_WLAN;
1446                 else if (obj1_type == RT1_NCP)
1447                         current_scope = NWAM_SCOPE_NCP;
1448         } else {
1449                 (void) strlcpy(obj2_name, newname, sizeof (obj2_name));
1450                 current_scope = NWAM_SCOPE_NCU;
1451                 obj2_type = cmd->cmd_res2_type;
1452         }
1453         if (current_scope != NWAM_SCOPE_NCP)
1454                 need_to_commit = B_TRUE;
1455 
1456         /* do a walk of the properties if in interactive mode */
1457         if (interactive_mode && current_scope != NWAM_SCOPE_NCP) {
1458                 (void) printf(gettext("Created %s '%s'.  "
1459                     "Walking properties ...\n"),
1460                     scope_to_str(current_scope), newname);
1461                 if ((walkprop_cmd = alloc_cmd()) == NULL)
1462                         goto done;
1463                 walkprop_func(walkprop_cmd);
1464                 free(walkprop_cmd);
1465         }
1466 
1467 read_error:
1468         if (ret != NWAM_SUCCESS)
1469                 nwamerr(ret, "Copy error reading '%s'", oldname);
1470 
1471 done:
1472         free(oldname);
1473         free(newname);
1474 }
1475 
1476 /* Processing of return value for destroy_*_callback() */
1477 static int
1478 destroy_ret(nwam_object_type_t object_type, nwam_error_t ret, void *handle)
1479 {
1480         if (ret == NWAM_ENTITY_NOT_DESTROYABLE) {
1481                 /* log a message to stderr, but don't consider it an error */
1482                 char *name;
1483                 if (object_name_from_handle(object_type, handle, &name)
1484                     == NWAM_SUCCESS) {
1485                         (void) fprintf(stderr,
1486                             gettext("%s '%s' cannot be removed\n"),
1487                             nwam_object_type_to_string(object_type), name);
1488                         free(name);
1489                 }
1490                 return (0);
1491         }
1492 
1493         if (ret == NWAM_SUCCESS || ret == NWAM_ENTITY_IN_USE)
1494                 return (0);
1495 
1496         return (1);
1497 }
1498 
1499 /*
1500  * NWAM_FLAG_DO_NOT_FREE is passed to nwam_*_destory() so that it does not
1501  * free the handle.  The calling nwam_walk_*() function frees this handle
1502  * as it is the function that created the handle.
1503  *
1504  * Objects that are not destroyable or are active cannot be destroyed.
1505  * Don't return error in these situations so the walk can continue.
1506  */
1507 /* ARGSUSED */
1508 static int
1509 destroy_ncp_callback(nwam_ncp_handle_t ncp, void *arg)
1510 {
1511         /* The file is deleted, so NCUs are also removed */
1512         nwam_error_t ret = nwam_ncp_destroy(ncp, NWAM_FLAG_DO_NOT_FREE);
1513         return (destroy_ret(NWAM_OBJECT_TYPE_NCP, ret, ncp));
1514 }
1515 
1516 /* ARGSUSED */
1517 static int
1518 destroy_loc_callback(nwam_loc_handle_t loc, void *arg)
1519 {
1520         nwam_error_t ret = nwam_loc_destroy(loc, NWAM_FLAG_DO_NOT_FREE);
1521         return (destroy_ret(NWAM_OBJECT_TYPE_LOC, ret, loc));
1522 }
1523 
1524 /* ARGSUSED */
1525 static int
1526 destroy_enm_callback(nwam_enm_handle_t enm, void *arg)
1527 {
1528         nwam_error_t ret = nwam_enm_destroy(enm, NWAM_FLAG_DO_NOT_FREE);
1529         return (destroy_ret(NWAM_OBJECT_TYPE_ENM, ret, enm));
1530 }
1531 
1532 /* ARGSUSED */
1533 static int
1534 destroy_wlan_callback(nwam_known_wlan_handle_t wlan, void *arg)
1535 {
1536         nwam_error_t ret = nwam_known_wlan_destroy(wlan, NWAM_FLAG_DO_NOT_FREE);
1537         return (destroy_ret(NWAM_OBJECT_TYPE_KNOWN_WLAN, ret, wlan));
1538 }
1539 
1540 /*
1541  * Remove all existing configuration that are not read-only.
1542  * walk through all ncps, locs, enms, wlans and destroy each one.
1543  */
1544 static nwam_error_t
1545 destroy_all(void)
1546 {
1547         nwam_error_t    ret;
1548 
1549         assert(remove_all_configurations);
1550 
1551         ret = nwam_walk_ncps(destroy_ncp_callback, NULL, 0, NULL);
1552         if (ret != NWAM_SUCCESS)
1553                 goto done;
1554 
1555         ret = nwam_walk_enms(destroy_enm_callback, NULL,
1556             NWAM_FLAG_ACTIVATION_MODE_ALL, NULL);
1557         if (ret != NWAM_SUCCESS)
1558                 goto done;
1559 
1560         ret = nwam_walk_locs(destroy_loc_callback, NULL,
1561             NWAM_FLAG_ACTIVATION_MODE_ALL, NULL);
1562         if (ret != NWAM_SUCCESS)
1563                 goto done;
1564 
1565         ret = nwam_walk_known_wlans(destroy_wlan_callback, NULL, 0, NULL);
1566         if (ret != NWAM_SUCCESS)
1567                 goto done;
1568 
1569         if (interactive_mode)
1570                 (void) printf(gettext("All user-defined entities destroyed\n"));
1571         remove_all_configurations = B_FALSE;
1572 
1573 done:
1574         if (ret != NWAM_SUCCESS) {
1575                 nwamerr(ret, "Destroy error: "
1576                     "could not destroy all configurations");
1577         }
1578         return (ret);
1579 }
1580 
1581 /*
1582  * Destroys an instance in persistent repository, and is permanent.
1583  * If interactive mode, it is allowed at global scope only
1584  * option -a destroys everything.
1585  */
1586 void
1587 destroy_func(cmd_t *cmd)
1588 {
1589         nwam_error_t    ret;
1590         char            *name, *realname = NULL;
1591 
1592         if (current_scope == NWAM_SCOPE_NCP &&
1593             (cmd->cmd_res1_type == RT1_ENM || cmd->cmd_res1_type == RT1_LOC ||
1594             cmd->cmd_res1_type == RT1_WLAN)) {
1595                 nerr("Destroy error: only NCUs can be destroyed in NCP scope");
1596                 return;
1597         }
1598 
1599         assert(cmd->cmd_argc > 0);
1600 
1601         /* res1_type is -1 if -a flag is used */
1602         if (cmd->cmd_res1_type == -1) {
1603                 int c;
1604 
1605                 if (current_scope != NWAM_SCOPE_GBL) {
1606                         nerr("Cannot destroy all configurations in a "
1607                             "non-global scope");
1608                         return;
1609                 }
1610 
1611                 optind = 0;
1612                 while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "a")) != EOF) {
1613                         switch (c) {
1614                         case 'a':
1615                                 remove_all_configurations = B_TRUE;
1616                                 break;
1617                         default:
1618                                 command_usage(CMD_DESTROY);
1619                                 return;
1620                         }
1621                 }
1622                 if (remove_all_configurations) {
1623                         (void) destroy_all();
1624                         return;
1625                 }
1626         }
1627 
1628         /* argv[0] is name */
1629         name = trim_quotes(cmd->cmd_argv[0]);
1630         if (cmd->cmd_res2_type == RT2_NCU) {
1631                 nwam_ncu_type_t         ncu_type;
1632                 nwam_ncu_class_t        ncu_class;
1633 
1634                 /* ncp must already be read */
1635                 if (ncp_h == NULL) {
1636                         nerr("Destroy ncu error: NCP has not been read");
1637                         return;
1638                 }
1639                 ncu_class = (nwam_ncu_class_t)cmd->cmd_ncu_class_type;
1640                 ncu_type = nwam_ncu_class_to_type(ncu_class);
1641                 ret = nwam_ncu_read(ncp_h, name, ncu_type, 0, &ncu_h);
1642                 if (ret != NWAM_SUCCESS)
1643                         goto done;
1644                 (void) object_name_from_handle(NWAM_OBJECT_TYPE_NCU, ncu_h,
1645                     &realname);
1646                 ret = nwam_ncu_destroy(ncu_h, 0);
1647                 ncu_h = NULL;
1648         } else if (cmd->cmd_res1_type == RT1_ENM) {
1649                 if ((ret = nwam_enm_read(name, 0, &enm_h)) != NWAM_SUCCESS)
1650                         goto done;
1651                 (void) object_name_from_handle(NWAM_OBJECT_TYPE_ENM, enm_h,
1652                     &realname);
1653                 ret = nwam_enm_destroy(enm_h, 0);
1654                 enm_h = NULL;
1655         } else if (cmd->cmd_res1_type == RT1_LOC) {
1656                 if ((ret = nwam_loc_read(name, 0, &loc_h)) != NWAM_SUCCESS)
1657                         goto done;
1658                 (void) object_name_from_handle(NWAM_OBJECT_TYPE_LOC, loc_h,
1659                     &realname);
1660                 ret = nwam_loc_destroy(loc_h, 0);
1661                 loc_h = NULL;
1662         } else if (cmd->cmd_res1_type == RT1_WLAN) {
1663                 if ((ret = nwam_known_wlan_read(name, 0, &wlan_h))
1664                     != NWAM_SUCCESS)
1665                         goto done;
1666                 (void) object_name_from_handle(NWAM_OBJECT_TYPE_KNOWN_WLAN,
1667                     wlan_h, &realname);
1668                 ret = nwam_known_wlan_destroy(wlan_h, 0);
1669                 wlan_h = NULL;
1670         } else if (cmd->cmd_res1_type == RT1_NCP) {
1671                 if ((ret = nwam_ncp_read(name, 0, &ncp_h)) != NWAM_SUCCESS)
1672                         goto done;
1673                 (void) object_name_from_handle(NWAM_OBJECT_TYPE_NCP, ncp_h,
1674                     &realname);
1675                 ret = nwam_ncp_destroy(ncp_h, 0);
1676                 ncp_h = NULL;
1677         } else {
1678                 nerr("Destroy error: unknown object-type");
1679         }
1680 
1681 done:
1682         if (ret == NWAM_ENTITY_IN_USE)  {
1683                 nerr("Destroy error: active entity cannot be destroyed");
1684         } else if (ret != NWAM_SUCCESS) {
1685                 nwamerr(ret, "Destroy error");
1686         } else if (interactive_mode) {
1687                 (void) printf(gettext("Destroyed %s '%s'\n"),
1688                     (cmd->cmd_res2_type == RT2_NCU ?
1689                     rt2_to_str(cmd->cmd_res2_type) :
1690                     rt1_to_str(cmd->cmd_res1_type)),
1691                     realname != NULL ? realname : name);
1692         }
1693         free(name);
1694         free(realname);
1695 }
1696 
1697 /*
1698  * End operation on current scope and go up one scope.
1699  * Changes are saved.
1700  */
1701 /* ARGSUSED */
1702 void
1703 end_func(cmd_t *cmd)
1704 {
1705         /* if need_to_commit is set, commit changes */
1706         if (need_to_commit)
1707                 do_commit();
1708 
1709         /*
1710          * Call do_cancel() to go up one scope.  If commit fails,
1711          * need_to_commit is not reset and users are asked if they want to end.
1712          */
1713         if (!need_to_commit ||
1714             (need_to_commit && (ask_yesno(B_FALSE,
1715             "Configuration not saved; really end")) == 1)) {
1716                 /* set time_to_exit if in global scope */
1717                 if (current_scope == NWAM_SCOPE_GBL)
1718                         time_to_exit = B_TRUE;
1719                 /* call do_cancel() to go up one scope */
1720                 do_cancel();
1721         }
1722 }
1723 
1724 /*
1725  * Exit immediately.  Configuration changes are saved by calling end_func().
1726  */
1727 /* ARGSUSED */
1728 void
1729 exit_func(cmd_t *cmd)
1730 {
1731         cmd_t *end_cmd;
1732 
1733         if (need_to_commit) {
1734                 if ((end_cmd = alloc_cmd()) == NULL) {
1735                         nerr("Exit error");
1736                         return;
1737                 }
1738                 end_func(end_cmd);
1739                 free_cmd(end_cmd);
1740         }
1741 
1742         /*
1743          * If need_to_commit is still set, then the commit failed.
1744          * Otherwise, exit.
1745          */
1746         if (!need_to_commit)
1747                 time_to_exit = B_TRUE;
1748 }
1749 
1750 void
1751 help_func(cmd_t *cmd)
1752 {
1753         int i;
1754 
1755         if (cmd->cmd_argc == 0) {
1756                 (void) printf(gettext("commands:\n"));
1757                 for (i = CMD_MIN; i <= CMD_MAX; i++)
1758                         (void) printf("\t%s\n", helptab[i].cmd_usage);
1759                 return;
1760         }
1761 
1762         for (i = CMD_MIN; i <= CMD_MAX; i++) {
1763                 if (strcmp(cmd->cmd_argv[0], cmd_to_str(i)) == 0) {
1764                         long_usage(i);
1765                         return;
1766                 }
1767         }
1768         (void) fprintf(stderr, gettext("Unknown command: '%s'\n"),
1769             cmd->cmd_argv[0]);
1770         help_wrap();
1771 }
1772 
1773 /*
1774  * Revert configuration of an instance to latest previous version.
1775  * Free the handle and read again.
1776  */
1777 /* ARGSUSED */
1778 void
1779 revert_func(cmd_t *cmd)
1780 {
1781         nwam_error_t            ret;
1782         char                    *name = NULL;
1783         nwam_ncu_type_t         ncu_type;
1784         nwam_object_type_t      object_type = active_object_type();
1785 
1786         switch (object_type) {
1787         case NWAM_OBJECT_TYPE_NCU:
1788                 /* retrieve name and type to use later */
1789                 if ((ret = nwam_ncu_get_ncu_type(ncu_h, &ncu_type))
1790                     != NWAM_SUCCESS) {
1791                         nwamerr(ret, "Revert error: Get ncu type error");
1792                         return;
1793                 }
1794                 if ((ret = nwam_ncu_get_name(ncu_h, &name)) != NWAM_SUCCESS)
1795                         goto name_error;
1796                 nwam_ncu_free(ncu_h);
1797                 ncu_h = NULL;
1798                 ret = nwam_ncu_read(ncp_h, name, ncu_type, 0, &ncu_h);
1799                 break;
1800         case NWAM_OBJECT_TYPE_ENM:
1801                 if ((ret = nwam_enm_get_name(enm_h, &name)) != NWAM_SUCCESS)
1802                         goto name_error;
1803                 nwam_enm_free(enm_h);
1804                 enm_h = NULL;
1805                 ret = nwam_enm_read(name, 0, &enm_h);
1806                 break;
1807         case NWAM_OBJECT_TYPE_LOC:
1808                 if ((ret = nwam_loc_get_name(loc_h, &name)) != NWAM_SUCCESS)
1809                         goto name_error;
1810                 nwam_loc_free(loc_h);
1811                 loc_h = NULL;
1812                 ret = nwam_loc_read(name, 0, &loc_h);
1813                 break;
1814         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
1815                 if ((ret = nwam_known_wlan_get_name(wlan_h, &name))
1816                     != NWAM_SUCCESS)
1817                         goto name_error;
1818                 nwam_known_wlan_free(wlan_h);
1819                 wlan_h = NULL;
1820                 ret = nwam_known_wlan_read(name, 0, &wlan_h);
1821                 break;
1822         }
1823 
1824         /* Exit this scope because handle already freed (call do_cancel()) */
1825         need_to_commit = B_FALSE;
1826 
1827         if (ret != NWAM_SUCCESS) {
1828                 if (ret == NWAM_ENTITY_NOT_FOUND) {
1829                         nerr("%s '%s' does not exist to revert to, removing it",
1830                             nwam_object_type_to_string(object_type), name);
1831                 } else {
1832                         nwamerr(ret, "Revert error");
1833                 }
1834                 do_cancel();
1835         }
1836         free(name);
1837         return;
1838 
1839 name_error:
1840         if (ret != NWAM_SUCCESS)
1841                 nwamerr(ret, "Revert error: get name error");
1842 }
1843 
1844 /*
1845  * Load a resource from persistent repository and enter the scope
1846  * of that resource.
1847  */
1848 void
1849 select_func(cmd_t *cmd)
1850 {
1851         nwam_error_t    ret;
1852         char            *name, *realname = NULL;
1853 
1854         assert(cmd->cmd_argc > 0);
1855         if (current_scope == NWAM_SCOPE_NCP && cmd->cmd_res2_type != RT2_NCU) {
1856                 nerr("cannot select '%s' at this scope",
1857                     rt1_to_str(cmd->cmd_res1_type));
1858                 return;
1859         }
1860 
1861         /* argv[0] is name */
1862         name = trim_quotes(cmd->cmd_argv[0]);
1863         switch (cmd->cmd_res1_type) {
1864         case RT1_LOC:
1865                 ret = nwam_loc_read(name, 0, &loc_h);
1866                 if (ret == NWAM_SUCCESS) {
1867                         current_scope = NWAM_SCOPE_LOC;
1868                         (void) object_name_from_handle(NWAM_OBJECT_TYPE_LOC,
1869                             loc_h, &realname);
1870                 }
1871                 break;
1872         case RT1_ENM:
1873                 ret = nwam_enm_read(name, 0, &enm_h);
1874                 if (ret == NWAM_SUCCESS) {
1875                         current_scope = NWAM_SCOPE_ENM;
1876                         (void) object_name_from_handle(NWAM_OBJECT_TYPE_ENM,
1877                             enm_h, &realname);
1878                 }
1879                 break;
1880         case RT1_WLAN:
1881                 ret = nwam_known_wlan_read(name, 0, &wlan_h);
1882                 if (ret == NWAM_SUCCESS) {
1883                         current_scope = NWAM_SCOPE_WLAN;
1884                         (void) object_name_from_handle
1885                             (NWAM_OBJECT_TYPE_KNOWN_WLAN, wlan_h, &realname);
1886                 }
1887                 break;
1888         case RT1_NCP:
1889                 if (cmd->cmd_res2_type == RT2_NCU) {
1890                         nwam_ncu_type_t         ncu_type;
1891                         nwam_ncu_class_t        ncu_class;
1892 
1893                         /* ncp must already be read */
1894                         if (ncp_h == NULL) {
1895                                 nerr("Select error: NCP has not been read");
1896                                 free(name);
1897                                 return;
1898                         }
1899                         ncu_class = (nwam_ncu_class_t)cmd->cmd_ncu_class_type;
1900                         ncu_type = nwam_ncu_class_to_type(ncu_class);
1901                         ret = nwam_ncu_read(ncp_h, name, ncu_type, 0, &ncu_h);
1902                         if (ret == NWAM_SUCCESS) {
1903                                 current_scope = NWAM_SCOPE_NCU;
1904                                 (void) object_name_from_handle
1905                                     (NWAM_OBJECT_TYPE_NCU, ncu_h, &realname);
1906                         }
1907                 } else {
1908                         ret = nwam_ncp_read(name, 0, &ncp_h);
1909                         if (ret == NWAM_SUCCESS) {
1910                                 current_scope = NWAM_SCOPE_NCP;
1911                                 (void) object_name_from_handle
1912                                     (NWAM_OBJECT_TYPE_NCP, ncp_h, &realname);
1913                         }
1914                 }
1915                 break;
1916         default:
1917                 nerr("Select error: unknown object-type");
1918                 free(name);
1919                 return;
1920         }
1921 
1922         if (ret != NWAM_SUCCESS) {
1923                 nwamerr(ret, "Select error");
1924         } else {
1925                 /* set the obj*_name or obj*_type depending on current scope */
1926                 if (current_scope == NWAM_SCOPE_NCU) {
1927                         obj2_type = RT2_NCU;
1928                         (void) strlcpy(obj2_name,
1929                             realname != NULL ? realname : name,
1930                             sizeof (obj2_name));
1931                 } else {
1932                         (void) strlcpy(obj1_name,
1933                             realname != NULL ? realname : name,
1934                             sizeof (obj1_name));
1935                         obj1_type = cmd->cmd_res1_type;
1936                 }
1937         }
1938         free(name);
1939         free(realname);
1940 }
1941 
1942 /* Given an int for prop, returns it as string */
1943 static const char *
1944 pt_to_prop_name(nwam_object_type_t object_type, int pt_type)
1945 {
1946         int i;
1947         prop_table_entry_t *prop_table = get_prop_table(object_type);
1948 
1949         for (i = 0; prop_table[i].pte_name != NULL; i++) {
1950                 if (pt_type == prop_table[i].pte_type)
1951                         return (prop_table[i].pte_name);
1952         }
1953         return (NULL);
1954 }
1955 
1956 /* Given a prop as a string, returns it as an int */
1957 static int
1958 prop_to_pt(nwam_object_type_t object_type, const char *prop)
1959 {
1960         int i;
1961         prop_table_entry_t *prop_table = get_prop_table(object_type);
1962 
1963         for (i = 0; prop_table[i].pte_name != NULL; i++) {
1964                 if (strcmp(prop, prop_table[i].pte_name) == 0)
1965                         return (prop_table[i].pte_type);
1966         }
1967         return (-1);
1968 }
1969 
1970 /* Given a prop as an int, returns its type (nwam_value_type_t) */
1971 static nwam_value_type_t
1972 prop_value_type(nwam_object_type_t object_type, const char *prop)
1973 {
1974         nwam_error_t            ret;
1975         nwam_value_type_t       value_type;
1976 
1977         switch (object_type) {
1978         case NWAM_OBJECT_TYPE_NCU:
1979                 ret = nwam_ncu_get_prop_type(prop, &value_type);
1980                 break;
1981         case NWAM_OBJECT_TYPE_LOC:
1982                 ret = nwam_loc_get_prop_type(prop, &value_type);
1983                 break;
1984         case NWAM_OBJECT_TYPE_ENM:
1985                 ret = nwam_enm_get_prop_type(prop, &value_type);
1986                 break;
1987         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
1988                 ret = nwam_known_wlan_get_prop_type(prop, &value_type);
1989                 break;
1990         }
1991 
1992         if (ret != NWAM_SUCCESS)
1993                 value_type = NWAM_VALUE_TYPE_UNKNOWN;
1994 
1995         return (value_type);
1996 }
1997 
1998 /*
1999  * Converts input_str to an array nwam_value.
2000  * If is_list_prop, break input_str into array of strings first.
2001  */
2002 static nwam_value_t
2003 str_to_nwam_value(nwam_object_type_t object_type, char *input_str, int pt_type,
2004     boolean_t is_list_prop)
2005 {
2006         int             i, n = 0, ret;
2007         nwam_value_t    data;
2008         char            **val;
2009         int             max_str_num;
2010 
2011         nwam_value_type_t       value_type;
2012         int64_t                 *int_vals;
2013         uint64_t                *uint_vals;
2014         boolean_t               *boolean_vals;
2015 
2016         /*
2017          * Worst case is that each char separated by DELIMITER, so the
2018          * max number of sub strings is half of string length + 1.
2019          */
2020         max_str_num = strlen(input_str) / 2 + 1;
2021 
2022         val = calloc(max_str_num, sizeof (char *));
2023         if (val == NULL) {
2024                 nerr("Out of memory");
2025                 return (NULL);
2026         }
2027 
2028         if (is_list_prop) {
2029                 char *tmp, *next;
2030                 /*
2031                  * Break down input_str and save as array of sub strings.
2032                  * Set num as the number of the sub strings.
2033                  * Use nwam_tokenize_by_unescaped_delim() rather than strtok()
2034                  * because DELIMITER may be escaped
2035                  */
2036                 tmp = (char *)input_str;
2037                 while ((tmp = nwam_tokenize_by_unescaped_delim(tmp,
2038                     NWAM_VALUE_DELIMITER_CHAR, &next)) != NULL) {
2039                         val[n++] = trim_quotes(tmp);
2040                         tmp = next;
2041                 }
2042         } else {
2043                 val[n++] = trim_quotes(input_str);
2044         }
2045 
2046         /* initialize int_vals or booleans_vals depending on pt_type */
2047         value_type = prop_value_type(object_type,
2048             pt_to_prop_name(object_type, pt_type));
2049         if (value_type == NWAM_VALUE_TYPE_INT64) {
2050                 int_vals = calloc(n, sizeof (int64_t));
2051                 if (int_vals == NULL) {
2052                         nerr("Out of memory");
2053                         array_free((void **)val, max_str_num);
2054                         return (NULL);
2055                 }
2056         } else if (value_type == NWAM_VALUE_TYPE_UINT64) {
2057                 uint_vals = calloc(n, sizeof (uint64_t));
2058                 if (uint_vals == NULL) {
2059                         nerr("Out of memory");
2060                         array_free((void **)val, max_str_num);
2061                         return (NULL);
2062                 }
2063         } else if (value_type == NWAM_VALUE_TYPE_BOOLEAN) {
2064                 boolean_vals = calloc(n, sizeof (boolean_t));
2065                 if (boolean_vals == NULL) {
2066                         nerr("Out of memory");
2067                         array_free((void **)val, max_str_num);
2068                         return (NULL);
2069                 }
2070         }
2071         /* set the appropriate array */
2072         for (i = 0; i < n; i++) {
2073                 switch (value_type) {
2074                 case NWAM_VALUE_TYPE_STRING:
2075                         /* nothing to do - val already has the char** array */
2076                         break;
2077                 case NWAM_VALUE_TYPE_INT64:
2078                 {
2079                         int_vals[i] = (int64_t)atoi(val[i]);
2080                         break;
2081                 }
2082                 case NWAM_VALUE_TYPE_UINT64:
2083                 {
2084                         uint64_t str_as_enum;
2085                         char *endptr;
2086 
2087                         ret = nwam_value_string_get_uint64(
2088                             pt_to_prop_name(object_type, pt_type),
2089                             val[i], &str_as_enum);
2090                         /*
2091                          * Returns _SUCCESS if value for enum is valid.
2092                          * Returns _INVALID_ARG if property is not an enum.
2093                          */
2094                         if (ret == NWAM_SUCCESS) {
2095                                 uint_vals[i] = str_as_enum;
2096                         } else if (ret == NWAM_INVALID_ARG) {
2097                                 uint_vals[i] = strtoul(val[i], &endptr, 10);
2098                                 /* verify conversion is valid */
2099                                 if (endptr == val[i]) {
2100                                         free(uint_vals);
2101                                         array_free((void **)val, max_str_num);
2102                                         return (NULL);
2103                                 }
2104                         } else {
2105                                 free(uint_vals);
2106                                 array_free((void **)val, max_str_num);
2107                                 return (NULL);
2108                         }
2109                         break;
2110                 }
2111                 case NWAM_VALUE_TYPE_BOOLEAN:
2112                         boolean_vals[i] = str_to_boolean(val[i]);
2113                         break;
2114                 default:
2115                         array_free((void **)val, max_str_num);
2116                         return (NULL);
2117                 }
2118         }
2119 
2120         /* create nwam_value_t */
2121         if (value_type == NWAM_VALUE_TYPE_STRING) {
2122                 ret = nwam_value_create_string_array(val, n, &data);
2123         } else if (value_type == NWAM_VALUE_TYPE_INT64) {
2124                 ret = nwam_value_create_int64_array(int_vals, n, &data);
2125                 free(int_vals);
2126         } else if (value_type == NWAM_VALUE_TYPE_UINT64) {
2127                 ret = nwam_value_create_uint64_array(uint_vals, n, &data);
2128                 free(uint_vals);
2129         } else if (value_type == NWAM_VALUE_TYPE_BOOLEAN) {
2130                 ret = nwam_value_create_boolean_array(boolean_vals, n, &data);
2131                 free(boolean_vals);
2132         }
2133         array_free((void **)val, max_str_num);
2134 
2135         if (ret != NWAM_SUCCESS) {
2136                 nwamerr(ret, "Failed creating nwam_value");
2137                 return (NULL);
2138         }
2139 
2140         return (data);
2141 }
2142 
2143 /*
2144  * Displaying/Skipping of properties
2145  * ---------------------------------
2146  *
2147  * This table shows if a specific property should be shown if some
2148  * other property has a specific value.  This table is used by
2149  * show_prop_test(), which is called by set_func() and walkprop_func().
2150  *
2151  * An entry in the table looks like:
2152  *      { property1, property2, { val1, val2, -1 } }
2153  * This is read as:
2154  *      "show property1 only if property2 has value val1 or val2"
2155  *
2156  * NB: If a property does not appear in this table, then that implies
2157  * that the property is always shown.
2158  *
2159  * A property can have more than one rule.  In such a case, the property is
2160  * displayed only any of the rules is satisfied.  This checking, however,
2161  * is recursive.  If a rule says that a property can be displayed, then the
2162  * property that's checked should also satisfy its rules.  In the above
2163  * example, if property1 is to be displayed, then property2 should also
2164  * satisfy its rules and be displayable.  This recursion is necessary as
2165  * properties that are not displayed (because rules are not satisfied) are
2166  * not deleted.
2167  */
2168 
2169 /* The most number of values in pde_checkvals below */
2170 #define NWAM_CHECKVALS_MAX      5
2171 
2172 typedef struct prop_display_entry {
2173         const char      *pde_name;              /* property to show */
2174         const char      *pde_checkname;         /* property to check */
2175         int64_t pde_checkvals[NWAM_CHECKVALS_MAX]; /* show prop for these */
2176 } prop_display_entry_t;
2177 
2178 /* Rules for showing properties: commented for clarity */
2179 
2180 /*
2181  * Rules for NCUs
2182  * NB: There is no need to have an entry if a property is for IP only.
2183  *     This is taken care of in libnwam_ncp.c
2184  */
2185 static prop_display_entry_t ncu_prop_display_entry_table[] = {
2186         /* show priority-{group,mode} if activation == prioritized */
2187         { NWAM_NCU_PROP_PRIORITY_GROUP, NWAM_NCU_PROP_ACTIVATION_MODE,
2188             { NWAM_ACTIVATION_MODE_PRIORITIZED, -1 } },
2189         { NWAM_NCU_PROP_PRIORITY_MODE, NWAM_NCU_PROP_ACTIVATION_MODE,
2190             { NWAM_ACTIVATION_MODE_PRIORITIZED, -1 } },
2191         /* show ipv4-addrsrc if ip-version == ipv4 */
2192         { NWAM_NCU_PROP_IPV4_ADDRSRC, NWAM_NCU_PROP_IP_VERSION,
2193             { IPV4_VERSION, -1 } },
2194         /* show ipv4-addr if ipv4-addrsrc == static */
2195         { NWAM_NCU_PROP_IPV4_ADDR, NWAM_NCU_PROP_IPV4_ADDRSRC,
2196             { NWAM_ADDRSRC_STATIC, -1 } },
2197         /* show ipv4-default-route if ip-version == ipv4 */
2198         { NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE, NWAM_NCU_PROP_IP_VERSION,
2199             { IPV4_VERSION, -1 } },
2200         /* show ipv6-addrsrc if ip-version == ipv6 */
2201         { NWAM_NCU_PROP_IPV6_ADDRSRC, NWAM_NCU_PROP_IP_VERSION,
2202             { IPV6_VERSION, -1 } },
2203         /* show ipv6-addr if ipv6-addrsrc == static */
2204         { NWAM_NCU_PROP_IPV6_ADDR, NWAM_NCU_PROP_IPV6_ADDRSRC,
2205             { NWAM_ADDRSRC_STATIC, -1 } },
2206         /* show ipv6-default-route if ip-version == ipv6 */
2207         { NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE, NWAM_NCU_PROP_IP_VERSION,
2208             { IPV6_VERSION, -1 } },
2209         /* show ip-primary if ipv4-addrsrc == dhcp */
2210         { NWAM_NCU_PROP_IP_PRIMARY, NWAM_NCU_PROP_IPV4_ADDRSRC,
2211             { NWAM_ADDRSRC_DHCP, -1 } },
2212         /* show ip-primary if ipv6-addrsrc == dhcp */
2213         { NWAM_NCU_PROP_IP_PRIMARY, NWAM_NCU_PROP_IPV6_ADDRSRC,
2214             { NWAM_ADDRSRC_DHCP, -1 } },
2215         /* show ip-reqhost if ipv4-addrsrc == dhcp */
2216         { NWAM_NCU_PROP_IP_REQHOST, NWAM_NCU_PROP_IPV4_ADDRSRC,
2217             { NWAM_ADDRSRC_DHCP, -1 } },
2218         /* show ip-reqhost if ipv6-addrsrc == dhcp */
2219         { NWAM_NCU_PROP_IP_REQHOST, NWAM_NCU_PROP_IPV6_ADDRSRC,
2220             { NWAM_ADDRSRC_DHCP, -1 } },
2221         { NULL, NULL, { -1 } }
2222 };
2223 
2224 /* Rules for ENMs */
2225 static prop_display_entry_t enm_prop_display_entry_table[] = {
2226         /* show conditions if activation-mode == conditional-{all,any} */
2227         { NWAM_ENM_PROP_CONDITIONS, NWAM_ENM_PROP_ACTIVATION_MODE,
2228             { NWAM_ACTIVATION_MODE_CONDITIONAL_ALL,
2229             NWAM_ACTIVATION_MODE_CONDITIONAL_ANY, -1 } },
2230         { NULL, NULL, { -1 } }
2231 };
2232 
2233 /* Rules for LOCations */
2234 static prop_display_entry_t loc_prop_display_entry_table[] = {
2235         /* show conditions if activation-mode == conditional-{all,any} */
2236         { NWAM_LOC_PROP_CONDITIONS, NWAM_LOC_PROP_ACTIVATION_MODE,
2237             { NWAM_ACTIVATION_MODE_CONDITIONAL_ALL,
2238             NWAM_ACTIVATION_MODE_CONDITIONAL_ANY, -1 } },
2239         /* show dns-nameservice-configsrc if nameservices == dns */
2240         { NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC, NWAM_LOC_PROP_NAMESERVICES,
2241             { NWAM_NAMESERVICES_DNS, -1 } },
2242         /* show other DNS options if dns-nameservices-configsrc == manual */
2243         { NWAM_LOC_PROP_DNS_NAMESERVICE_DOMAIN,
2244             NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC,
2245             { NWAM_CONFIGSRC_MANUAL, -1 } },
2246         { NWAM_LOC_PROP_DNS_NAMESERVICE_SERVERS,
2247             NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC,
2248             { NWAM_CONFIGSRC_MANUAL, -1 } },
2249         { NWAM_LOC_PROP_DNS_NAMESERVICE_SEARCH,
2250             NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC,
2251             { NWAM_CONFIGSRC_MANUAL, -1 } },
2252         /* show nis-nameservice-configsrc if nameservices == nis */
2253         { NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC, NWAM_LOC_PROP_NAMESERVICES,
2254             { NWAM_NAMESERVICES_NIS, -1 } },
2255         /* show nis-nameservice-servers if nis-nameservice-configsrc = manual */
2256         { NWAM_LOC_PROP_NIS_NAMESERVICE_SERVERS,
2257             NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC,
2258             { NWAM_CONFIGSRC_MANUAL, -1 } },
2259         /* show ldap-nameservice-configsrc if nameservices == ldap */
2260         { NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC, NWAM_LOC_PROP_NAMESERVICES,
2261             { NWAM_NAMESERVICES_LDAP, -1 } },
2262         /* show ldap-nameservice-servers if ldap-nameservice-configsrc=manual */
2263         { NWAM_LOC_PROP_LDAP_NAMESERVICE_SERVERS,
2264             NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC,
2265             { NWAM_CONFIGSRC_MANUAL, -1 } },
2266         /* show default-domain if {nis,ldap}-nameservice-configsrc == manual */
2267         { NWAM_LOC_PROP_DEFAULT_DOMAIN, NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC,
2268             { NWAM_CONFIGSRC_MANUAL, -1 } },
2269         { NWAM_LOC_PROP_DEFAULT_DOMAIN,
2270             NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC,
2271             { NWAM_CONFIGSRC_MANUAL, -1 } },
2272         { NULL, NULL, { -1 } }
2273 };
2274 
2275 /* Rules for Known WLANs */
2276 static prop_display_entry_t wlan_prop_display_entry_table[] = {
2277         /* no rules for WLANs */
2278         { NULL, NULL, { -1 } }
2279 };
2280 
2281 /* Returns the appropriate rules table for the given object type */
2282 static prop_display_entry_t *
2283 get_prop_display_table(nwam_object_type_t object_type)
2284 {
2285         switch (object_type) {
2286         case NWAM_OBJECT_TYPE_NCU:
2287                 return (ncu_prop_display_entry_table);
2288         case NWAM_OBJECT_TYPE_LOC:
2289                 return (loc_prop_display_entry_table);
2290         case NWAM_OBJECT_TYPE_ENM:
2291                 return (enm_prop_display_entry_table);
2292         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
2293                 return (wlan_prop_display_entry_table);
2294         }
2295         return (NULL);
2296 }
2297 
2298 /*
2299  * Tests whether prop must be shown during a walk depending on the
2300  * value of a different property.
2301  *
2302  * This function is also used by set_func() to determine whether the
2303  * property being set should be allowed or not.  If the property
2304  * would not be displayed in a walk, then it should not be set.
2305  *
2306  * The checked_props and num_checked arguments are used to avoid circular
2307  * dependencies between properties.  When this function recursively calls
2308  * itself, it adds the property that it just checked to the checked_props
2309  * list.
2310  */
2311 static boolean_t
2312 show_prop_test(nwam_object_type_t object_type, const char *prop,
2313     prop_display_entry_t *display_list, char **checked_props, int num_checked)
2314 {
2315         nwam_error_t            ret;
2316         nwam_value_t            prop_val;
2317         nwam_value_type_t       prop_type;
2318         int                     i, j, k;
2319         boolean_t               prop_found = B_FALSE, show_prop = B_FALSE;
2320 
2321         /*
2322          * Check if this property has already been checked previously in
2323          * the recursion.  If so, return B_FALSE so that the initial prop
2324          * is not displayed.
2325          */
2326         for (i = 0; i < num_checked; i++) {
2327                 if (strcmp(prop, checked_props[i]) == 0) {
2328                         free(checked_props);
2329                         return (B_FALSE);
2330                 }
2331         }
2332 
2333         for (i = 0; display_list[i].pde_name != NULL; i++) {
2334                 if (strcmp(prop, display_list[i].pde_name) != 0)
2335                         continue;
2336                 prop_found = B_TRUE;
2337 
2338                 /* get the value(s) of the (other) property to check */
2339                 switch (object_type) {
2340                 case NWAM_OBJECT_TYPE_NCU:
2341                         ret = nwam_ncu_get_prop_value(ncu_h,
2342                             display_list[i].pde_checkname, &prop_val);
2343                         break;
2344                 case NWAM_OBJECT_TYPE_LOC:
2345                         ret = nwam_loc_get_prop_value(loc_h,
2346                             display_list[i].pde_checkname, &prop_val);
2347                         break;
2348                 case NWAM_OBJECT_TYPE_ENM:
2349                         ret = nwam_enm_get_prop_value(enm_h,
2350                             display_list[i].pde_checkname, &prop_val);
2351                         break;
2352                 case NWAM_OBJECT_TYPE_KNOWN_WLAN:
2353                         return (B_TRUE);
2354                 }
2355                 if (ret != NWAM_SUCCESS)
2356                         continue;
2357 
2358                 /* prop_val may contain a uint64 array or a boolean */
2359                 if (nwam_value_get_type(prop_val, &prop_type) != NWAM_SUCCESS)
2360                         continue;
2361 
2362                 if (prop_type == NWAM_VALUE_TYPE_UINT64) {
2363                         uint64_t        *prop_uvals;
2364                         int64_t         *check_uvals;
2365                         uint_t          numvals;
2366 
2367                         if (nwam_value_get_uint64_array(prop_val, &prop_uvals,
2368                             &numvals) != NWAM_SUCCESS) {
2369                                 nwam_value_free(prop_val);
2370                                 continue;
2371                         }
2372 
2373                         /* for each value in uvals, check each value in table */
2374                         for (j = 0; j < numvals; j++) {
2375                                 check_uvals = display_list[i].pde_checkvals;
2376                                 for (k = 0; check_uvals[k] != -1; k++) {
2377                                         /* show if uvals[j] matches */
2378                                         if (prop_uvals[j] ==
2379                                             (uint64_t)check_uvals[k]) {
2380                                                 show_prop = B_TRUE;
2381                                                 goto next_rule;
2382                                         }
2383                                 }
2384                         }
2385                 } else if (prop_type == NWAM_VALUE_TYPE_BOOLEAN) {
2386                         boolean_t bval;
2387 
2388                         if (nwam_value_get_boolean(prop_val, &bval) !=
2389                             NWAM_SUCCESS) {
2390                                 nwam_value_free(prop_val);
2391                                 continue;
2392                         }
2393 
2394                         for (k = 0;
2395                             display_list[i].pde_checkvals[k] != -1;
2396                             k++) {
2397                                 /* show if bval matches */
2398                                 if (bval == (boolean_t)
2399                                     display_list[i].pde_checkvals[k]) {
2400                                         show_prop = B_TRUE;
2401                                         goto next_rule;
2402                                 }
2403                         }
2404                 }
2405 
2406 next_rule:
2407                 nwam_value_free(prop_val);
2408                 /*
2409                  * If show_prop is set, then a rule is satisfied; no need to
2410                  * check other rules for this prop.  However, recursively
2411                  * check if the checked prop (pde_checkname) satisfies its
2412                  * rules.  Also, update the check_props array with this prop.
2413                  */
2414                 if (show_prop) {
2415                         char **newprops = realloc(checked_props,
2416                             ++num_checked * sizeof (char *));
2417                         if (newprops == NULL) {
2418                                 free(checked_props);
2419                                 return (B_FALSE);
2420                         }
2421                         checked_props = newprops;
2422                         checked_props[num_checked - 1] = (char *)prop;
2423 
2424                         return (show_prop_test(object_type,
2425                             display_list[i].pde_checkname, display_list,
2426                             checked_props, num_checked));
2427                 }
2428         }
2429 
2430         /*
2431          * If we are here and prop_found is set, it means that no rules were
2432          * satisfied by prop; return B_FALSE.  If prop_found is not set, then
2433          * prop did not have a rule so it must be displayed; return B_TRUE.
2434          */
2435         free(checked_props);
2436         if (prop_found)
2437                 return (B_FALSE);
2438         else
2439                 return (B_TRUE);
2440 }
2441 
2442 /*
2443  * Returns true if the given property is read-only and cannot be modified.
2444  */
2445 static boolean_t
2446 is_prop_read_only(nwam_object_type_t object_type, const char *prop)
2447 {
2448         boolean_t ro;
2449 
2450         switch (object_type) {
2451         case NWAM_OBJECT_TYPE_NCU:
2452                 if (nwam_ncu_prop_read_only(prop, &ro) == NWAM_SUCCESS && ro)
2453                         return (B_TRUE);
2454                 break;
2455         case NWAM_OBJECT_TYPE_ENM:
2456                 if (nwam_enm_prop_read_only(prop, &ro) == NWAM_SUCCESS && ro)
2457                         return (B_TRUE);
2458                 break;
2459         case NWAM_OBJECT_TYPE_LOC:
2460                 if (nwam_loc_prop_read_only(prop, &ro) == NWAM_SUCCESS && ro)
2461                         return (B_TRUE);
2462                 break;
2463         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
2464                 /* no read-only properties for WLANs */
2465                 return (B_FALSE);
2466         }
2467         return (B_FALSE);
2468 }
2469 
2470 /* Returns true if the property is multi-valued */
2471 static boolean_t
2472 is_prop_multivalued(nwam_object_type_t object_type, const char *prop)
2473 {
2474         nwam_error_t    ret;
2475         boolean_t       multi;
2476 
2477         switch (object_type) {
2478         case NWAM_OBJECT_TYPE_NCU:
2479                 ret = nwam_ncu_prop_multivalued(prop, &multi);
2480                 break;
2481         case NWAM_OBJECT_TYPE_LOC:
2482                 ret = nwam_loc_prop_multivalued(prop, &multi);
2483                 break;
2484         case NWAM_OBJECT_TYPE_ENM:
2485                 ret = nwam_enm_prop_multivalued(prop, &multi);
2486                 break;
2487         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
2488                 ret = nwam_known_wlan_prop_multivalued(prop, &multi);
2489                 break;
2490         }
2491 
2492         if (ret != NWAM_SUCCESS)
2493                 multi = B_FALSE;
2494         return (multi);
2495 }
2496 
2497 /*
2498  * Prints out error message specific to property that could not be set.
2499  * Property description is used to help guide user in entering correct value.
2500  */
2501 static void
2502 invalid_set_prop_msg(const char *prop, nwam_error_t err)
2503 {
2504         const char *description;
2505 
2506         if (err == NWAM_SUCCESS)
2507                 return;
2508 
2509         if (err != NWAM_ENTITY_INVALID_VALUE) {
2510                 nwamerr(err, "Set error");
2511                 return;
2512         }
2513 
2514         switch (active_object_type()) {
2515         case NWAM_OBJECT_TYPE_NCU:
2516                 (void) nwam_ncu_get_prop_description(prop, &description);
2517                 break;
2518         case NWAM_OBJECT_TYPE_LOC:
2519                 (void) nwam_loc_get_prop_description(prop, &description);
2520                 break;
2521         case NWAM_OBJECT_TYPE_ENM:
2522                 (void) nwam_enm_get_prop_description(prop, &description);
2523                 break;
2524         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
2525                 (void) nwam_known_wlan_get_prop_description(prop,
2526                     &description);
2527                 break;
2528         }
2529         nerr("Set error: invalid value\n'%s' %s", prop, description);
2530 }
2531 
2532 /*
2533  * Sets the property value.
2534  * Read-only properties and objects cannot be set.
2535  * "read-only" is a special in that it can be set on a read-only object.
2536  * The object has to be committed before other properties can be set.
2537  * Also uses show_prop_test() to test if the property being set would
2538  * be skipped during a walk (as determined by the value of some other
2539  * property).  If so, then it cannot be set.
2540  */
2541 void
2542 set_func(cmd_t *cmd)
2543 {
2544         int                     pt_type = cmd->cmd_prop_type;
2545         nwam_error_t            ret = NWAM_SUCCESS;
2546         nwam_value_t            prop_value;
2547         const char              *prop;
2548         boolean_t               is_listprop = B_FALSE;
2549         nwam_object_type_t      object_type;
2550         prop_display_entry_t    *prop_table;
2551         char                    **checked = NULL;
2552 
2553         assert(cmd->cmd_argc > 0);
2554 
2555         object_type = active_object_type();
2556         prop_table = get_prop_display_table(object_type);
2557 
2558         /* argv[0] is property value */
2559         if ((prop = pt_to_prop_name(object_type, pt_type)) == NULL) {
2560                 nerr("Set error: invalid %s property: '%s'",
2561                     scope_to_str(current_scope), pt_to_str(pt_type));
2562                 return;
2563         }
2564 
2565         /* check if property can be set */
2566         if (is_prop_read_only(object_type, prop)) {
2567                 nerr("Set error: property '%s' is read-only", prop);
2568                 return;
2569         }
2570         if (!show_prop_test(object_type, prop, prop_table, checked, 0)) {
2571                 if (interactive_mode) {
2572                         (void) printf(gettext("setting property '%s' "
2573                             "has no effect\n"), prop);
2574                 }
2575         }
2576 
2577         is_listprop = is_prop_multivalued(object_type, prop);
2578         prop_value = str_to_nwam_value(object_type, cmd->cmd_argv[0], pt_type,
2579             is_listprop);
2580         if (prop_value == NULL) {
2581                 invalid_set_prop_msg(prop, NWAM_ENTITY_INVALID_VALUE);
2582                 return;
2583         }
2584 
2585         /* set the property value */
2586         switch (object_type) {
2587         case NWAM_OBJECT_TYPE_NCU:
2588                 ret = nwam_ncu_set_prop_value(ncu_h, prop, prop_value);
2589                 break;
2590         case NWAM_OBJECT_TYPE_LOC:
2591                 ret = nwam_loc_set_prop_value(loc_h, prop, prop_value);
2592                 break;
2593         case NWAM_OBJECT_TYPE_ENM:
2594                 ret = nwam_enm_set_prop_value(enm_h, prop, prop_value);
2595                 break;
2596         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
2597                 ret = nwam_known_wlan_set_prop_value(wlan_h, prop, prop_value);
2598                 break;
2599         }
2600         nwam_value_free(prop_value);
2601 
2602         /* delete other properties if needed */
2603         if (ret == NWAM_SUCCESS)
2604                 need_to_commit = B_TRUE;
2605         else
2606                 invalid_set_prop_msg(prop, ret);
2607 }
2608 
2609 static int
2610 list_callback(nwam_object_type_t object_type, void *handle,
2611     boolean_t *list_msgp, const char *msg)
2612 {
2613         nwam_error_t            ret;
2614         char                    *name;
2615         nwam_ncu_class_t        class;
2616 
2617         if (*list_msgp) {
2618                 (void) printf("%s:\n", msg);
2619                 *list_msgp = B_FALSE;
2620         }
2621 
2622         ret = object_name_from_handle(object_type, handle, &name);
2623         if (ret != NWAM_SUCCESS) {
2624                 nwamerr(ret, "List error: failed to get name");
2625                 return (1);
2626         }
2627 
2628         /* If NCU, get its class and print */
2629         if (object_type == NWAM_OBJECT_TYPE_NCU) {
2630                 if ((ret = nwam_ncu_get_ncu_class(handle, &class))
2631                     != NWAM_SUCCESS) {
2632                         nwamerr(ret, "List error: failed to get ncu class");
2633                         free(name);
2634                         return (1);
2635                 } else {
2636                         (void) printf("\t%s",
2637                             propval_to_str(NWAM_NCU_PROP_CLASS, class));
2638                 }
2639         }
2640         (void) printf("\t%s\n", name);
2641 
2642         free(name);
2643         return (0);
2644 }
2645 
2646 /* Print out name, type and status */
2647 static int
2648 list_loc_callback(nwam_loc_handle_t loc, void *arg)
2649 {
2650         return (list_callback(NWAM_OBJECT_TYPE_LOC, loc, arg, "Locations"));
2651 }
2652 
2653 static int
2654 list_enm_callback(nwam_enm_handle_t enm, void *arg)
2655 {
2656         return (list_callback(NWAM_OBJECT_TYPE_ENM, enm, arg, "ENMs"));
2657 }
2658 
2659 static int
2660 list_wlan_callback(nwam_known_wlan_handle_t wlan, void *arg)
2661 {
2662         return (list_callback(NWAM_OBJECT_TYPE_KNOWN_WLAN, wlan, arg, "WLANs"));
2663 }
2664 
2665 static int
2666 list_ncp_callback(nwam_ncp_handle_t ncp, void *arg)
2667 {
2668         return (list_callback(NWAM_OBJECT_TYPE_NCP, ncp, arg, "NCPs"));
2669 }
2670 
2671 static int
2672 list_ncu_callback(nwam_ncu_handle_t ncu, void *arg)
2673 {
2674         return (list_callback(NWAM_OBJECT_TYPE_NCU, ncu, arg, "NCUs"));
2675 }
2676 
2677 /* functions to convert a value to a string */
2678 /* ARGSUSED */
2679 static const char *
2680 str2str(void *s, const char *prop, char *str)
2681 {
2682         (void) snprintf(str, NWAM_MAX_VALUE_LEN, "%s", s);
2683         return (str);
2684 }
2685 
2686 /* ARGSUSED */
2687 static const char *
2688 str2qstr(void *s, const char *prop, char *qstr)
2689 {
2690         /* quoted strings */
2691         (void) snprintf(qstr, NWAM_MAX_VALUE_LEN, "\"%s\"", s);
2692         return (qstr);
2693 }
2694 
2695 /* ARGSUSED */
2696 static const char *
2697 int2str(void *in, const char *prop, char *instr)
2698 {
2699         (void) snprintf(instr, NWAM_MAX_VALUE_LEN, "%lld", *((int64_t *)in));
2700         return (instr);
2701 }
2702 
2703 static const char *
2704 uint2str(void *uin, const char *prop, char *uintstr)
2705 {
2706         /* returns NWAM_SUCCESS if prop is enum with string in uintstr */
2707         if (nwam_uint64_get_value_string(prop, *((uint64_t *)uin),
2708             (const char **)&uintstr) != NWAM_SUCCESS) {
2709                 (void) snprintf(uintstr, NWAM_MAX_VALUE_LEN, "%lld",
2710                     *((uint64_t *)uin));
2711         }
2712         return (uintstr);
2713 }
2714 
2715 /* ARGSUSED */
2716 static const char *
2717 bool2str(void *bool, const char *prop, char *boolstr)
2718 {
2719         (void) snprintf(boolstr, NWAM_MAX_VALUE_LEN, "%s",
2720             *((boolean_t *)bool) ? "true" : "false");
2721         return (boolstr);
2722 }
2723 
2724 /*
2725  * Print the value (enums are converted to string), use DELIMITER for
2726  * array.  If strings are to be "quoted", pass B_TRUE for quoted_strings.
2727  */
2728 static void
2729 output_prop_val(const char *prop_name, nwam_value_t value, FILE *wf,
2730     boolean_t quoted_strings)
2731 {
2732         nwam_value_type_t       value_type;
2733         uint_t                  num;
2734 
2735         /* arrays for values retrieved according to the type of value */
2736         char            **svals;
2737         uint64_t        *uvals;
2738         int64_t         *ivals;
2739         boolean_t       *bvals;
2740 
2741         /* pointer to function to generate string representation of value */
2742         const char      *(*tostr)(void *, const char *, char *);
2743         char            str[NWAM_MAX_VALUE_LEN]; /* to store the string */
2744         int             i;
2745 
2746         if (nwam_value_get_type(value, &value_type) != NWAM_SUCCESS) {
2747                 nerr("Get value type error");
2748                 return;
2749         }
2750 
2751         if (value_type == NWAM_VALUE_TYPE_STRING) {
2752                 if (nwam_value_get_string_array(value, &svals, &num) !=
2753                     NWAM_SUCCESS) {
2754                         nerr("Get string array error");
2755                         return;
2756                 }
2757                 tostr = quoted_strings ? str2qstr : str2str;
2758         } else if (value_type == NWAM_VALUE_TYPE_INT64) {
2759                 if (nwam_value_get_int64_array(value, &ivals, &num) !=
2760                     NWAM_SUCCESS) {
2761                         nerr("Get int64 array error");
2762                         return;
2763                 }
2764                 tostr = int2str;
2765         } else if (value_type == NWAM_VALUE_TYPE_UINT64) {
2766                 if (nwam_value_get_uint64_array(value, &uvals, &num) !=
2767                     NWAM_SUCCESS) {
2768                         nerr("Get uint64 array error");
2769                         return;
2770                 }
2771                 tostr = uint2str;
2772         } else if (value_type == NWAM_VALUE_TYPE_BOOLEAN) {
2773                 if (nwam_value_get_boolean_array(value, &bvals, &num) !=
2774                     NWAM_SUCCESS) {
2775                         nerr("Get boolean array error");
2776                         return;
2777                 }
2778                 tostr = bool2str;
2779         }
2780 
2781         /* now, loop and print each value */
2782         for (i = 0; i < num; i++) {
2783                 void *val;
2784 
2785                 /* get the pointer to the ith value to pass to func() */
2786                 if (value_type == NWAM_VALUE_TYPE_STRING)
2787                         val = svals[i];
2788                 else if (value_type == NWAM_VALUE_TYPE_UINT64)
2789                         val = &(uvals[i]);
2790                 else if (value_type == NWAM_VALUE_TYPE_INT64)
2791                         val = &(ivals[i]);
2792                 else if (value_type == NWAM_VALUE_TYPE_BOOLEAN)
2793                         val = &(bvals[i]);
2794 
2795                 (void) fprintf(wf, "%s%s", tostr(val, prop_name, str),
2796                     i != num-1 ? NWAM_VALUE_DELIMITER_STR : "");
2797         }
2798 }
2799 
2800 /* Prints the property names aligned (for list/get) or "prop=" (for export) */
2801 static int
2802 output_propname_common(const char *prop, nwam_value_t values, void *arg,
2803     int width)
2804 {
2805         FILE *of = (arg == NULL) ? stdout : arg;
2806 
2807         /* arg is NULL for list/get, not NULL for export */
2808         if (arg == NULL)
2809                 (void) fprintf(of, "\t%-*s\t", width, prop);
2810         else
2811                 (void) fprintf(of, "%s=", prop);
2812 
2813         if (values != NULL)
2814                 output_prop_val(prop, values, of, B_TRUE);
2815 
2816         (void) fprintf(of, "\n");
2817         return (0);
2818 }
2819 
2820 static int
2821 output_propname(const char *prop, nwam_value_t values, void *arg)
2822 {
2823         return (output_propname_common(prop, values, arg, 16));
2824 }
2825 
2826 /* For locations because of longer property names */
2827 static int
2828 output_loc_propname(const char *prop, nwam_value_t values, void *arg)
2829 {
2830         return (output_propname_common(prop, values, arg, 25));
2831 }
2832 
2833 /*
2834  * all_props specifies whether properties that have not been set should be
2835  * printed or not.  ncp and ncu_type are used only when the object_type is
2836  * NCU.
2837  */
2838 static nwam_error_t
2839 listprop(nwam_object_type_t object_type, void *handle, const char *name,
2840     boolean_t all_props, nwam_ncp_handle_t ncp, nwam_ncu_type_t ncu_type)
2841 {
2842         nwam_error_t    ret;
2843         char            *lname = NULL, *realname = NULL;
2844         boolean_t       lhandle = B_FALSE;
2845         const char      **props = NULL;
2846         uint_t          prop_num;
2847         int             i;
2848         nwam_value_t    vals;
2849 
2850         /*
2851          * handle is NULL if called from a scope higher than the object's
2852          * scope, but name must be given; so get the handle.
2853          */
2854         if (handle == NULL) {
2855                 lname = trim_quotes(name); /* name may have quotes */
2856                 switch (object_type) {
2857                 case NWAM_OBJECT_TYPE_NCP:
2858                         if ((ret = nwam_ncp_read(lname, 0,
2859                             (nwam_ncp_handle_t *)&handle)) != NWAM_SUCCESS)
2860                                 goto readfail;
2861                         break;
2862                 case NWAM_OBJECT_TYPE_NCU:
2863                         ret = nwam_ncu_read(ncp, lname, ncu_type, 0,
2864                             (nwam_ncu_handle_t *)&handle);
2865                         if (ret == NWAM_ENTITY_MULTIPLE_VALUES) {
2866                                 /*
2867                                  * Multiple NCUs with the given name exists.
2868                                  * Call listprop() for each NCU type.
2869                                  */
2870                                 if ((ret = listprop(object_type, NULL, lname,
2871                                     all_props, ncp, NWAM_NCU_TYPE_LINK))
2872                                     != NWAM_SUCCESS)
2873                                         goto done;
2874                                 ret = listprop(object_type, NULL, lname,
2875                                     all_props, ncp, NWAM_NCU_TYPE_INTERFACE);
2876                                 goto done;
2877                         } else if (ret != NWAM_SUCCESS) {
2878                                 goto readfail;
2879                         }
2880                         break;
2881                 case NWAM_OBJECT_TYPE_LOC:
2882                         if ((ret = nwam_loc_read(lname, 0,
2883                             (nwam_loc_handle_t *)&handle)) != NWAM_SUCCESS)
2884                                 goto readfail;
2885                         break;
2886                 case NWAM_OBJECT_TYPE_ENM:
2887                         if ((ret = nwam_enm_read(lname, 0,
2888                             (nwam_enm_handle_t *)&handle)) != NWAM_SUCCESS)
2889                                 goto readfail;
2890                         break;
2891                 case NWAM_OBJECT_TYPE_KNOWN_WLAN:
2892                         if ((ret = nwam_known_wlan_read(lname, 0,
2893                             (nwam_known_wlan_handle_t *)&handle))
2894                             != NWAM_SUCCESS)
2895                                 goto readfail;
2896                         break;
2897                 }
2898                 lhandle = B_TRUE;
2899         }
2900 
2901         if ((ret = object_name_from_handle(object_type, handle, &realname))
2902             != NWAM_SUCCESS)
2903                 goto done;
2904 
2905         /* get the property list */
2906         switch (object_type) {
2907         case NWAM_OBJECT_TYPE_NCP:
2908         {
2909                 /* walk NCUs */
2910                 boolean_t list_msg = B_TRUE;
2911                 ret = nwam_ncp_walk_ncus(handle, list_ncu_callback, &list_msg,
2912                     NWAM_FLAG_NCU_TYPE_CLASS_ALL, NULL);
2913                 goto done;
2914         }
2915         case NWAM_OBJECT_TYPE_NCU:
2916         {
2917                 nwam_ncu_type_t         ncu_type;
2918                 nwam_ncu_class_t        ncu_class;
2919 
2920                 if ((ret = nwam_ncu_get_ncu_type(handle, &ncu_type))
2921                     != NWAM_SUCCESS)
2922                         goto done;
2923                 if ((ret = nwam_ncu_get_ncu_class(handle, &ncu_class))
2924                     != NWAM_SUCCESS)
2925                         goto done;
2926 
2927                 ret = nwam_ncu_get_default_proplist(ncu_type, ncu_class, &props,
2928                     &prop_num);
2929                 break;
2930         }
2931         case NWAM_OBJECT_TYPE_LOC:
2932                 ret = nwam_loc_get_default_proplist(&props, &prop_num);
2933                 break;
2934         case NWAM_OBJECT_TYPE_ENM:
2935                 ret = nwam_enm_get_default_proplist(&props, &prop_num);
2936                 break;
2937         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
2938                 ret = nwam_known_wlan_get_default_proplist(&props, &prop_num);
2939                 break;
2940         }
2941         if (ret != NWAM_SUCCESS)
2942                 goto done;
2943 
2944         /* print object type and name */
2945         (void) printf("%s:%s\n", nwam_object_type_to_string(object_type),
2946             realname);
2947 
2948         /* Loop through the properties and print */
2949         for (i = 0; i < prop_num; i++) {
2950                 /* get the existing value for this property */
2951                 switch (object_type) {
2952                 case NWAM_OBJECT_TYPE_NCU:
2953                         ret = nwam_ncu_get_prop_value(handle, props[i], &vals);
2954                         break;
2955                 case NWAM_OBJECT_TYPE_LOC:
2956                         ret = nwam_loc_get_prop_value(handle, props[i], &vals);
2957                         break;
2958                 case NWAM_OBJECT_TYPE_ENM:
2959                         ret = nwam_enm_get_prop_value(handle, props[i], &vals);
2960                         break;
2961                 case NWAM_OBJECT_TYPE_KNOWN_WLAN:
2962                         ret = nwam_known_wlan_get_prop_value(handle, props[i],
2963                             &vals);
2964                         break;
2965                 }
2966                 if (ret != NWAM_SUCCESS) {
2967                         /* _ENTITY_NOT_FOUND is ok if listing for all props */
2968                         if (!all_props)
2969                                 continue;
2970                         else if (ret != NWAM_ENTITY_NOT_FOUND)
2971                                 continue;
2972                 }
2973 
2974                 /* print property and value */
2975                 if (object_type == NWAM_OBJECT_TYPE_LOC)
2976                         output_loc_propname(props[i], vals, NULL);
2977                 else
2978                         output_propname(props[i], vals, NULL);
2979                 nwam_value_free(vals);
2980         }
2981 
2982 done:
2983         free(lname);
2984         free(realname);
2985         if (props != NULL)
2986                 free(props);
2987         if (lhandle) {
2988                 switch (object_type) {
2989                 case NWAM_OBJECT_TYPE_NCP:
2990                         nwam_ncp_free(handle);
2991                         break;
2992                 case NWAM_OBJECT_TYPE_NCU:
2993                         nwam_ncu_free(handle);
2994                         break;
2995                 case NWAM_OBJECT_TYPE_LOC:
2996                         nwam_loc_free(handle);
2997                         break;
2998                 case NWAM_OBJECT_TYPE_ENM:
2999                         nwam_enm_free(handle);
3000                         break;
3001                 case NWAM_OBJECT_TYPE_KNOWN_WLAN:
3002                         nwam_known_wlan_free(handle);
3003                         break;
3004                 }
3005         }
3006         /* don't treat _ENTITY_NOT_FOUND as an error */
3007         if (ret == NWAM_ENTITY_NOT_FOUND)
3008                 ret = NWAM_SUCCESS;
3009         return (ret);
3010 
3011 readfail:
3012         /* When nwam_*_read() fails */
3013         free(lname);
3014         return (ret);
3015 }
3016 
3017 /*
3018  * List profiles or property and its values.
3019  * If the -a option is specified, all properties are listed.
3020  */
3021 void
3022 list_func(cmd_t *cmd)
3023 {
3024         nwam_error_t    ret = NWAM_SUCCESS;
3025         boolean_t       list_msg = B_TRUE;
3026 
3027         boolean_t       list_loc = B_FALSE, list_enm = B_FALSE;
3028         boolean_t       list_ncp = B_FALSE, list_ncu = B_FALSE;
3029         boolean_t       list_wlan = B_FALSE;
3030 
3031         /* whether all properties should be listed, given by the -a option */
3032         boolean_t       all_props = B_FALSE;
3033 
3034         /*
3035          * list_props says whether the properties should be listed.
3036          * Note that, here NCUs are treated as properties of NCPs.
3037          */
3038         boolean_t       list_props = B_FALSE;
3039 
3040         /* determine which properties to list, also validity tests */
3041         if (current_scope == NWAM_SCOPE_GBL) {
3042                 /* res1_type is -1 if only "list -a" is used */
3043                 if (cmd->cmd_res1_type == -1) {
3044                         nerr("'list' requires an object to be specified with "
3045                             "the -a option in the global scope");
3046                         return;
3047                 }
3048                 if (cmd->cmd_res1_type == RT1_LOC) {
3049                         list_props = B_TRUE;
3050                         list_loc = B_TRUE;
3051                 } else if (cmd->cmd_res1_type == RT1_ENM) {
3052                         list_props = B_TRUE;
3053                         list_enm = B_TRUE;
3054                 } else if (cmd->cmd_res1_type == RT1_WLAN) {
3055                         list_props = B_TRUE;
3056                         list_wlan = B_TRUE;
3057                 } else if (cmd->cmd_res1_type == RT1_NCP) {
3058                         list_ncp = B_TRUE;
3059                         list_props = B_TRUE;
3060                 } else {
3061                         list_loc = B_TRUE;
3062                         list_enm = B_TRUE;
3063                         list_wlan = B_TRUE;
3064                         list_ncp = B_TRUE;
3065                 }
3066         }
3067         if ((current_scope == NWAM_SCOPE_LOC ||
3068             current_scope == NWAM_SCOPE_ENM ||
3069             current_scope == NWAM_SCOPE_WLAN ||
3070             current_scope == NWAM_SCOPE_NCU) &&
3071             (cmd->cmd_argc >= 1 && cmd->cmd_res1_type != -1)) {
3072                 nerr("Additional options are not allowed with the -a option "
3073                     "at this scope");
3074                 return;
3075         }
3076         if (current_scope == NWAM_SCOPE_LOC) {
3077                 list_loc = B_TRUE;
3078                 list_props = B_TRUE;
3079         }
3080         if (current_scope == NWAM_SCOPE_ENM) {
3081                 list_enm = B_TRUE;
3082                 list_props = B_TRUE;
3083         }
3084         if (current_scope == NWAM_SCOPE_WLAN) {
3085                 list_wlan = B_TRUE;
3086                 list_props = B_TRUE;
3087         }
3088         if (current_scope == NWAM_SCOPE_NCP) {
3089                 if (cmd->cmd_res1_type == RT1_ENM ||
3090                     cmd->cmd_res1_type == RT1_LOC ||
3091                     cmd->cmd_res1_type == RT1_WLAN) {
3092                         nerr("only ncu can be listed at this scope");
3093                         return;
3094                 }
3095                 if (cmd->cmd_res2_type == RT2_NCU) {
3096                         list_ncu = B_TRUE;
3097                         list_props = B_TRUE;
3098                 } else {
3099                         list_ncp = B_TRUE;
3100                         list_props = B_TRUE;
3101                 }
3102         }
3103         if (current_scope == NWAM_SCOPE_NCU) {
3104                 list_ncu = B_TRUE;
3105                 list_props = B_TRUE;
3106         }
3107 
3108         /* Check if the -a option is specified to list all properties */
3109         if (cmd->cmd_res1_type == -1 || cmd->cmd_argc == 2) {
3110                 int c, argc = 1;
3111                 char **argv;
3112                 optind = 0;
3113 
3114                 /* if res1_type is -1, option is in argv[0], else in argv[1] */
3115                 if (cmd->cmd_res1_type == -1)
3116                         argv = cmd->cmd_argv;
3117                 else
3118                         argv = &(cmd->cmd_argv[1]);
3119                 while ((c = getopt(argc, argv, "a")) != EOF) {
3120                         switch (c) {
3121                         case 'a':
3122                                 all_props = B_TRUE;
3123                                 break;
3124                         default:
3125                                 command_usage(CMD_LIST);
3126                                 return;
3127                         }
3128                 }
3129                 if (cmd->cmd_res1_type == -1)
3130                         cmd->cmd_argv[0] = NULL;
3131         }
3132 
3133         /*
3134          * Now, print objects and/or according to the flags set.
3135          * name, if requested, is in argv[0].
3136          */
3137         if (list_ncp) {
3138                 list_msg = B_TRUE;
3139                 if (list_props) {
3140                         ret = listprop(NWAM_OBJECT_TYPE_NCP, ncp_h,
3141                             cmd->cmd_argv[0], all_props, NULL, -1);
3142                 } else {
3143                         ret = nwam_walk_ncps(list_ncp_callback, &list_msg, 0,
3144                             NULL);
3145                 }
3146                 if (ret != NWAM_SUCCESS)
3147                         goto done;
3148         }
3149 
3150         if (list_ncu) {
3151                 list_msg = B_TRUE;
3152                 if (ncp_h == NULL) {
3153                         nerr("NCP has not been read");
3154                         return;
3155                 }
3156                 if (list_props) {
3157                         nwam_ncu_class_t        ncu_class;
3158                         nwam_ncu_type_t         ncu_type;
3159 
3160                         /* determine the NCU type first */
3161                         if (ncu_h == NULL) {
3162                                 ncu_class = (nwam_ncu_class_t)
3163                                     cmd->cmd_ncu_class_type;
3164                                 ncu_type = nwam_ncu_class_to_type(ncu_class);
3165                         } else {
3166                                 if ((ret = nwam_ncu_get_ncu_type(ncu_h,
3167                                     &ncu_type)) != NWAM_SUCCESS)
3168                                         goto done;
3169                         }
3170                         ret = listprop(NWAM_OBJECT_TYPE_NCU, ncu_h,
3171                             cmd->cmd_argv[0], all_props, ncp_h, ncu_type);
3172                         if (ret != NWAM_SUCCESS)
3173                                 goto done;
3174                 }
3175         }
3176 
3177         if (list_loc) {
3178                 list_msg = B_TRUE;
3179                 if (list_props) {
3180                         ret = listprop(NWAM_OBJECT_TYPE_LOC, loc_h,
3181                             cmd->cmd_argv[0], all_props, NULL, -1);
3182                 } else {
3183                         ret = nwam_walk_locs(list_loc_callback, &list_msg,
3184                             NWAM_FLAG_ACTIVATION_MODE_ALL, NULL);
3185                 }
3186                 if (ret != NWAM_SUCCESS)
3187                         goto done;
3188         }
3189 
3190         if (list_enm) {
3191                 list_msg = B_TRUE;
3192                 if (list_props) {
3193                         ret = listprop(NWAM_OBJECT_TYPE_ENM, enm_h,
3194                             cmd->cmd_argv[0], all_props, NULL, -1);
3195                 } else {
3196                         ret = nwam_walk_enms(list_enm_callback, &list_msg,
3197                             NWAM_FLAG_ACTIVATION_MODE_ALL, NULL);
3198                 }
3199                 if (ret != NWAM_SUCCESS)
3200                         goto done;
3201         }
3202 
3203         if (list_wlan) {
3204                 list_msg = B_TRUE;
3205                 if (list_props) {
3206                         ret = listprop(NWAM_OBJECT_TYPE_KNOWN_WLAN, wlan_h,
3207                             cmd->cmd_argv[0], all_props, NULL, -1);
3208                 } else {
3209                         ret = nwam_walk_known_wlans(list_wlan_callback,
3210                             &list_msg, NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER,
3211                             NULL);
3212                 }
3213                 if (ret != NWAM_SUCCESS)
3214                         goto done;
3215         }
3216 
3217 done:
3218         if (ret != NWAM_SUCCESS)
3219                 nwamerr(ret, "List error");
3220 }
3221 
3222 static int
3223 write_export_command(nwam_object_type_t object_type, const char *prop,
3224     nwam_value_t values, FILE *of)
3225 {
3226         /* exclude read-only properties */
3227         if (is_prop_read_only(object_type, prop))
3228                 return (0);
3229 
3230         (void) fprintf(of, "set ");
3231         output_propname(prop, values, of);
3232         return (0);
3233 }
3234 
3235 static int
3236 export_ncu_callback(nwam_ncu_handle_t ncu, void *arg)
3237 {
3238         char            *name;
3239         const char      **props;
3240         nwam_ncu_type_t type;
3241         nwam_ncu_class_t class;
3242         nwam_value_t    vals;
3243         nwam_error_t    ret;
3244         uint_t          num;
3245         int             i;
3246         FILE            *of = arg;
3247 
3248         assert(of != NULL);
3249 
3250         /* get the NCU's type and class */
3251         if ((ret = nwam_ncu_get_ncu_type(ncu, &type)) != NWAM_SUCCESS)
3252                 return (ret);
3253         if ((ret = nwam_ncu_get_ncu_class(ncu, &class)) != NWAM_SUCCESS)
3254                 return (ret);
3255 
3256         if ((ret = nwam_ncu_get_name(ncu, &name)) != NWAM_SUCCESS)
3257                 return (ret);
3258 
3259         (void) fprintf(of, "create ncu %s \"%s\"\n",
3260             propval_to_str(NWAM_NCU_PROP_CLASS, class), name);
3261         free(name);
3262         /*
3263          * Because of dependencies between properties, they have to be
3264          * exported in the same order as when they are walked.
3265          */
3266         if ((ret = nwam_ncu_get_default_proplist(type, class, &props, &num))
3267             != NWAM_SUCCESS)
3268                 return (ret);
3269         for (i = 0; i < num; i++) {
3270                 ret = nwam_ncu_get_prop_value(ncu, props[i], &vals);
3271                 if (ret == NWAM_SUCCESS) {
3272                         write_export_command(NWAM_OBJECT_TYPE_NCU, props[i],
3273                             vals, of);
3274                         nwam_value_free(vals);
3275                 }
3276         }
3277         (void) fprintf(of, "end\n");
3278 
3279         free(props);
3280         return (0);
3281 }
3282 
3283 static int
3284 export_ncp_callback(nwam_ncp_handle_t ncp, void *arg)
3285 {
3286         char            *name;
3287         nwam_error_t    ret;
3288         FILE            *of = arg;
3289 
3290         assert(of != NULL);
3291 
3292         if ((ret = nwam_ncp_get_name(ncp, &name)) != NWAM_SUCCESS)
3293                 return (ret);
3294 
3295         /* Do not export "automatic" NCP */
3296         if (NWAM_NCP_AUTOMATIC(name)) {
3297                 free(name);
3298                 return (0);
3299         }
3300 
3301         (void) fprintf(of, "create ncp \"%s\"\n", name);
3302         free(name);
3303 
3304         /* now walk NCUs for this ncp */
3305         ret = nwam_ncp_walk_ncus(ncp, export_ncu_callback, of,
3306             NWAM_FLAG_NCU_TYPE_CLASS_ALL, NULL);
3307         if (ret != NWAM_SUCCESS) {
3308                 nwamerr(ret, "Export ncp error: failed to walk ncus");
3309                 return (ret);
3310         }
3311         (void) fprintf(of, "end\n");
3312         return (0);
3313 }
3314 
3315 static int
3316 export_enm_callback(nwam_enm_handle_t enm, void *arg)
3317 {
3318         char            *name;
3319         const char      **props;
3320         nwam_value_t    vals;
3321         nwam_error_t    ret;
3322         uint_t          num;
3323         int             i;
3324         FILE            *of = arg;
3325 
3326         assert(of != NULL);
3327 
3328         if ((ret = nwam_enm_get_name(enm, &name)) != NWAM_SUCCESS)
3329                 return (ret);
3330 
3331         (void) fprintf(of, "create enm \"%s\"\n", name);
3332         free(name);
3333         /*
3334          * Because of dependencies between properties, they have to be
3335          * exported in the same order as when they are walked.
3336          */
3337         if ((ret = nwam_enm_get_default_proplist(&props, &num)) != NWAM_SUCCESS)
3338                 return (ret);
3339         for (i = 0; i < num; i++) {
3340                 ret = nwam_enm_get_prop_value(enm, props[i], &vals);
3341                 if (ret == NWAM_SUCCESS) {
3342                         write_export_command(NWAM_OBJECT_TYPE_ENM, props[i],
3343                             vals, of);
3344                         nwam_value_free(vals);
3345                 }
3346         }
3347         (void) fprintf(of, "end\n");
3348 
3349         free(props);
3350         return (0);
3351 }
3352 
3353 static int
3354 export_loc_callback(nwam_loc_handle_t loc, void *arg)
3355 {
3356         char            *name;
3357         const char      **props;
3358         nwam_value_t    vals;
3359         nwam_error_t    ret;
3360         uint_t          num;
3361         int             i;
3362         FILE            *of = arg;
3363 
3364         assert(of != NULL);
3365 
3366         if ((ret = nwam_loc_get_name(loc, &name)) != NWAM_SUCCESS)
3367                 return (ret);
3368 
3369         /* Do not export Automatic, NoNet or Legacy locations */
3370         if (NWAM_LOC_NAME_PRE_DEFINED(name)) {
3371                 free(name);
3372                 return (0);
3373         }
3374 
3375         (void) fprintf(of, "create loc \"%s\"\n", name);
3376         free(name);
3377         /*
3378          * Because of dependencies between properties, they have to be
3379          * exported in the same order as when they are walked.
3380          */
3381         if ((ret = nwam_loc_get_default_proplist(&props, &num)) != NWAM_SUCCESS)
3382                 return (ret);
3383         for (i = 0; i < num; i++) {
3384                 ret = nwam_loc_get_prop_value(loc, props[i], &vals);
3385                 if (ret == NWAM_SUCCESS) {
3386                         write_export_command(NWAM_OBJECT_TYPE_LOC, props[i],
3387                             vals, of);
3388                         nwam_value_free(vals);
3389                 }
3390         }
3391         (void) fprintf(of, "end\n");
3392 
3393         free(props);
3394         return (0);
3395 }
3396 
3397 static int
3398 export_wlan_callback(nwam_known_wlan_handle_t wlan, void *arg)
3399 {
3400         char            *name;
3401         const char      **props;
3402         nwam_value_t    vals;
3403         nwam_error_t    ret;
3404         uint_t          num;
3405         int             i;
3406         FILE            *of = arg;
3407 
3408         assert(of != NULL);
3409 
3410         if ((ret = nwam_known_wlan_get_name(wlan, &name)) != NWAM_SUCCESS)
3411                 return (ret);
3412 
3413         (void) fprintf(of, "create wlan \"%s\"\n", name);
3414         free(name);
3415         /*
3416          * Because of dependencies between properties, they have to be
3417          * exported in the same order as when they are walked.
3418          */
3419         if ((ret = nwam_known_wlan_get_default_proplist(&props, &num))
3420             != NWAM_SUCCESS)
3421                 return (ret);
3422         for (i = 0; i < num; i++) {
3423                 ret = nwam_known_wlan_get_prop_value(wlan, props[i], &vals);
3424                 if (ret == NWAM_SUCCESS) {
3425                         write_export_command(NWAM_OBJECT_TYPE_KNOWN_WLAN,
3426                             props[i], vals, of);
3427                         nwam_value_free(vals);
3428                 }
3429         }
3430         (void) fprintf(of, "end\n");
3431 
3432         free(props);
3433         return (0);
3434 }
3435 
3436 /*
3437  * Writes configuration to screen or file (with -f option).
3438  * Writes a "destroy -a" if option -d is given.
3439  */
3440 void
3441 export_func(cmd_t *cmd)
3442 {
3443         int             c;
3444         boolean_t       need_to_close = B_FALSE, write_to_file = B_FALSE;
3445         boolean_t       add_destroy = B_FALSE, lhandle = B_FALSE;
3446         char            filepath[MAXPATHLEN];
3447         nwam_error_t    ret = NWAM_SUCCESS;
3448         FILE            *of = NULL; /* either filename or stdout */
3449 
3450         /* what to export */
3451         boolean_t export_ncp = B_FALSE, export_ncu = B_FALSE;
3452         boolean_t export_loc = B_FALSE, export_enm = B_FALSE;
3453         boolean_t export_wlan = B_FALSE;
3454         char *name = NULL;
3455 
3456         /* check for -d and -f flags */
3457         filepath[0] = '\0';
3458         optind = 0;
3459         while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "df:")) != EOF) {
3460                 switch (c) {
3461                 case 'f':
3462                         write_to_file = B_TRUE;
3463                         break;
3464                 case 'd':
3465                         add_destroy = B_TRUE;
3466                         break;
3467                 default:
3468                         command_usage(CMD_EXPORT);
3469                         return;
3470                 }
3471         }
3472 
3473         /* determine where to export */
3474         if (!write_to_file) {
3475                 of = stdout;
3476         } else {
3477                 /*
3478                  * If -d was specified with -f, then argv[2] is filename,
3479                  * otherwise, argv[1] is filename.
3480                  */
3481                 (void) strlcpy(filepath,
3482                     (add_destroy ? cmd->cmd_argv[2] : cmd->cmd_argv[1]),
3483                     sizeof (filepath));
3484                 if ((of = fopen(filepath, "w")) == NULL) {
3485                         nerr(gettext("opening file '%s': %s"), filepath,
3486                             strerror(errno));
3487                         goto done;
3488                 }
3489                 setbuf(of, NULL);
3490                 need_to_close = B_TRUE;
3491         }
3492 
3493         if (add_destroy) {
3494                 /* only possible in global scope */
3495                 if (current_scope == NWAM_SCOPE_GBL) {
3496                         (void) fprintf(of, "destroy -a\n");
3497                 } else {
3498                         nerr("Option -d is not allowed in non-global scope");
3499                         goto done;
3500                 }
3501         }
3502 
3503         /* In the following scopes, only the -f argument is valid */
3504         if (((current_scope == NWAM_SCOPE_LOC ||
3505             current_scope == NWAM_SCOPE_ENM ||
3506             current_scope == NWAM_SCOPE_WLAN ||
3507             current_scope == NWAM_SCOPE_NCU) &&
3508             cmd->cmd_argc != 0 && !write_to_file)) {
3509                 nerr("'export' does not take arguments at this scope");
3510                 goto done;
3511         }
3512         if (current_scope == NWAM_SCOPE_NCP) {
3513                 if (cmd->cmd_res1_type == RT1_ENM ||
3514                     cmd->cmd_res1_type == RT1_LOC ||
3515                     cmd->cmd_res1_type == RT1_WLAN) {
3516                         nerr("only ncu can be exported at this scope");
3517                         goto done;
3518                 }
3519         }
3520 
3521         /*
3522          * Determine what objects to export depending on scope and command
3523          * arguments.  If -f is specified, then the object name is argv[2].
3524          * Otherwise, argv[0] is name, unless exporting all in global
3525          * scope in which case name is set back to NULL.
3526          */
3527         switch (current_scope) {
3528         case NWAM_SCOPE_GBL:
3529                 name = (write_to_file ? trim_quotes(cmd->cmd_argv[2]) :
3530                     trim_quotes(cmd->cmd_argv[0]));
3531                 switch (cmd->cmd_res1_type) {
3532                 case RT1_LOC:
3533                         export_loc = B_TRUE;
3534                         break;
3535                 case RT1_ENM:
3536                         export_enm = B_TRUE;
3537                         break;
3538                 case RT1_WLAN:
3539                         export_wlan = B_TRUE;
3540                         break;
3541                 case RT1_NCP:
3542                         export_ncp = B_TRUE;
3543                         if (cmd->cmd_res2_type == RT2_NCU) {
3544                                 nerr("cannot export ncu at from global scope");
3545                                 goto done;
3546                         }
3547                         break;
3548                 default:
3549                         /* export everything */
3550                         export_loc = B_TRUE;
3551                         export_enm = B_TRUE;
3552                         export_wlan = B_TRUE;
3553                         export_ncp = B_TRUE; /* NCP will export the NCUs */
3554                         free(name);
3555                         name = NULL; /* exporting all, undo name */
3556                         break;
3557                 }
3558                 break;
3559         case NWAM_SCOPE_LOC:
3560                 export_loc = B_TRUE;
3561                 ret = nwam_loc_get_name(loc_h, &name);
3562                 if (ret != NWAM_SUCCESS)
3563                         goto fail;
3564                 break;
3565         case NWAM_SCOPE_ENM:
3566                 export_enm = B_TRUE;
3567                 ret = nwam_enm_get_name(enm_h, &name);
3568                 if (ret != NWAM_SUCCESS)
3569                         goto fail;
3570                 break;
3571         case NWAM_SCOPE_WLAN:
3572                 export_wlan = B_TRUE;
3573                 ret = nwam_known_wlan_get_name(wlan_h, &name);
3574                 if (ret != NWAM_SUCCESS)
3575                         goto fail;
3576                 break;
3577         case NWAM_SCOPE_NCP:
3578                 if (cmd->cmd_res2_type == RT2_NCU) {
3579                         export_ncu = B_TRUE;
3580                         name = (write_to_file ? trim_quotes(cmd->cmd_argv[2]) :
3581                             trim_quotes(cmd->cmd_argv[0]));
3582                 } else {
3583                         export_ncp = B_TRUE;
3584                         ret = nwam_ncp_get_name(ncp_h, &name);
3585                         if (ret != NWAM_SUCCESS)
3586                                 goto fail;
3587                 }
3588                 break;
3589         case NWAM_SCOPE_NCU:
3590                 export_ncu = B_TRUE;
3591                 ret = nwam_ncu_get_name(ncu_h, &name);
3592                 if (ret != NWAM_SUCCESS)
3593                         goto fail;
3594                 break;
3595         default:
3596                 nerr("Invalid scope");
3597                 goto done;
3598         }
3599 
3600         /* Now, export objects according to the flags set */
3601         if (export_ncp) {
3602                 lhandle = B_FALSE;
3603                 if (name == NULL) {
3604                         /* export all NCPs */
3605                         ret = nwam_walk_ncps(export_ncp_callback, of, 0, NULL);
3606                 } else if (NWAM_NCP_AUTOMATIC(name)) {
3607                         nerr("'%s' ncp cannot be exported", name);
3608                         goto fail;
3609                 } else {
3610                         if (ncp_h == NULL) {
3611                                 ret = nwam_ncp_read(name, 0, &ncp_h);
3612                                 if (ret != NWAM_SUCCESS)
3613                                         goto fail;
3614                                 lhandle = B_TRUE;
3615                         }
3616                         /* will export NCUs also */
3617                         ret = export_ncp_callback(ncp_h, of);
3618                         if (lhandle) {
3619                                 nwam_ncp_free(ncp_h);
3620                                 ncp_h = NULL;
3621                         }
3622                 }
3623                 if (ret != NWAM_SUCCESS)
3624                         goto fail;
3625         }
3626 
3627         if (export_ncu) {
3628                 if (name == NULL) {
3629                         /* export all NCUs */
3630                         ret = nwam_ncp_walk_ncus(ncp_h, export_ncu_callback, of,
3631                             NWAM_FLAG_NCU_TYPE_CLASS_ALL, NULL);
3632                 } else {
3633                         if (ncu_h == NULL) {
3634                                 /* no NCU handle -> called from NCP scope */
3635                                 nwam_ncu_type_t         ncu_type;
3636                                 nwam_ncu_class_t        ncu_class;
3637 
3638                                 ncu_class = (nwam_ncu_class_t)
3639                                     cmd->cmd_ncu_class_type;
3640                                 ncu_type = nwam_ncu_class_to_type(ncu_class);
3641                                 ret = nwam_ncu_read(ncp_h, name,
3642                                     ncu_type, 0, &ncu_h);
3643                                 if (ret == NWAM_SUCCESS) {
3644                                         /* one NCU with given name */
3645                                         ret = export_ncu_callback(ncu_h, of);
3646                                         nwam_ncu_free(ncu_h);
3647                                         ncu_h = NULL;
3648                                 } else if (ret == NWAM_ENTITY_MULTIPLE_VALUES) {
3649                                         /* multiple NCUs with given name */
3650                                         ret = nwam_ncu_read(ncp_h, name,
3651                                             NWAM_NCU_TYPE_LINK, 0, &ncu_h);
3652                                         if (ret != NWAM_SUCCESS)
3653                                                 goto fail;
3654                                         ret = export_ncu_callback(ncu_h, of);
3655                                         nwam_ncu_free(ncu_h);
3656                                         ncu_h = NULL;
3657 
3658                                         ret = nwam_ncu_read(ncp_h, name,
3659                                             NWAM_NCU_TYPE_INTERFACE, 0, &ncu_h);
3660                                         if (ret != NWAM_SUCCESS)
3661                                                 goto fail;
3662                                         ret = export_ncu_callback(ncu_h, of);
3663                                         nwam_ncu_free(ncu_h);
3664                                         ncu_h = NULL;
3665                                 } else {
3666                                         goto fail;
3667                                 }
3668                         } else {
3669                                 /* NCU handle exists */
3670                                 ret = export_ncu_callback(ncu_h, of);
3671                         }
3672                 }
3673                 if (ret != NWAM_SUCCESS)
3674                         goto fail;
3675         }
3676 
3677         if (export_loc) {
3678                 lhandle = B_FALSE;
3679                 if (name == NULL) {
3680                         /* export all locations */
3681                         ret = nwam_walk_locs(export_loc_callback, of,
3682                             NWAM_FLAG_ACTIVATION_MODE_ALL, NULL);
3683                 } else if (NWAM_LOC_NAME_PRE_DEFINED(name)) {
3684                         nerr("'%s' loc cannot be exported", name);
3685                         goto fail;
3686                 } else {
3687                         if (loc_h == NULL) {
3688                                 ret = nwam_loc_read(name, 0, &loc_h);
3689                                 if (ret != NWAM_SUCCESS)
3690                                         goto fail;
3691                                 lhandle = B_TRUE;
3692                         }
3693                         ret = export_loc_callback(loc_h, of);
3694                         if (lhandle) {
3695                                 nwam_loc_free(loc_h);
3696                                 loc_h = NULL;
3697                         }
3698                 }
3699                 if (ret != NWAM_SUCCESS)
3700                         goto fail;
3701         }
3702 
3703         if (export_enm) {
3704                 lhandle = B_FALSE;
3705                 if (name == NULL) {
3706                         /* export all ENMs */
3707                         ret = nwam_walk_enms(export_enm_callback, of,
3708                             NWAM_FLAG_ACTIVATION_MODE_ALL, NULL);
3709                 } else {
3710                         if (enm_h == NULL) {
3711                                 ret = nwam_enm_read(name, 0, &enm_h);
3712                                 if (ret != NWAM_SUCCESS)
3713                                         goto fail;
3714                                 lhandle = B_TRUE;
3715                         }
3716                         ret = export_enm_callback(enm_h, of);
3717                         if (lhandle) {
3718                                 nwam_enm_free(enm_h);
3719                                 enm_h = NULL;
3720                         }
3721                 }
3722                 if (ret != NWAM_SUCCESS)
3723                         goto fail;
3724         }
3725 
3726         if (export_wlan) {
3727                 lhandle = B_FALSE;
3728                 if (name == NULL) {
3729                         /* export all WLANs */
3730                         ret = nwam_walk_known_wlans(export_wlan_callback, of,
3731                             NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, NULL);
3732                 } else {
3733                         if (wlan_h == NULL) {
3734                                 ret = nwam_known_wlan_read(name, 0,
3735                                     &wlan_h);
3736                                 if (ret != NWAM_SUCCESS)
3737                                         goto fail;
3738                                 lhandle = B_TRUE;
3739                         }
3740                         ret = export_wlan_callback(wlan_h, of);
3741                         if (lhandle) {
3742                                 nwam_known_wlan_free(wlan_h);
3743                                 wlan_h = NULL;
3744                         }
3745                 }
3746                 if (ret != NWAM_SUCCESS)
3747                         goto fail;
3748         }
3749 
3750 fail:
3751         free(name);
3752         if (ret != NWAM_SUCCESS)
3753                 nwamerr(ret, "Export error");
3754 
3755 done:
3756         if (need_to_close)
3757                 (void) fclose(of);
3758 }
3759 
3760 /*
3761  * Get property value.  If the -V option is specified, only the value is
3762  * printed without the property name.
3763  */
3764 void
3765 get_func(cmd_t *cmd)
3766 {
3767         nwam_error_t            ret = NWAM_SUCCESS;
3768         nwam_value_t            prop_value;
3769         const char              *prop;
3770         boolean_t               value_only = B_FALSE;
3771         nwam_object_type_t      object_type = active_object_type();
3772 
3773         /* check if option is -V to print value only */
3774         if (cmd->cmd_argc == 1) {
3775                 int c;
3776 
3777                 optind = 0;
3778                 while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "V")) != EOF) {
3779                         switch (c) {
3780                         case 'V':
3781                                 value_only = B_TRUE;
3782                                 break;
3783                         default:
3784                                 command_usage(CMD_GET);
3785                                 return;
3786                         }
3787                 }
3788         }
3789 
3790         /* property to get is in cmd->cmd_prop_type */
3791         if ((prop = pt_to_prop_name(object_type, cmd->cmd_prop_type)) == NULL) {
3792                 nerr("Get error: invalid %s property: '%s'",
3793                     scope_to_str(current_scope), pt_to_str(cmd->cmd_prop_type));
3794                 return;
3795         }
3796 
3797         switch (object_type) {
3798         case NWAM_OBJECT_TYPE_NCU:
3799                 ret = nwam_ncu_get_prop_value(ncu_h, prop, &prop_value);
3800                 break;
3801         case NWAM_OBJECT_TYPE_LOC:
3802                 ret = nwam_loc_get_prop_value(loc_h, prop, &prop_value);
3803                 break;
3804         case NWAM_OBJECT_TYPE_ENM:
3805                 ret = nwam_enm_get_prop_value(enm_h, prop, &prop_value);
3806                 break;
3807         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
3808                 ret = nwam_known_wlan_get_prop_value(wlan_h, prop, &prop_value);
3809                 break;
3810         }
3811 
3812         if (ret != NWAM_SUCCESS) {
3813                 if (ret == NWAM_ENTITY_NOT_FOUND)
3814                         nerr("Get error: property '%s' has not been set", prop);
3815                 else
3816                         nwamerr(ret, "Get error");
3817                 return;
3818         }
3819 
3820         if (value_only) {
3821                 output_prop_val(prop, prop_value, stdout, B_FALSE);
3822                 (void) printf("\n");
3823         } else {
3824                 output_propname(prop, prop_value, NULL);
3825         }
3826         nwam_value_free(prop_value);
3827 }
3828 
3829 /*
3830  * Clears value of a property.
3831  * Read-only properties cannot be cleared.
3832  * If clearing a property invalidates the object, then that property
3833  * cannot be cleared.
3834  */
3835 void
3836 clear_func(cmd_t *cmd)
3837 {
3838         nwam_error_t            ret;
3839         const char              *prop;
3840         nwam_object_type_t      object_type = active_object_type();
3841 
3842         /* property to clear is in cmd->cmd_prop_type */
3843         if ((prop = pt_to_prop_name(object_type, cmd->cmd_prop_type)) == NULL) {
3844                 nerr("Clear error: invalid %s property: '%s'",
3845                     scope_to_str(current_scope), pt_to_str(cmd->cmd_prop_type));
3846                 return;
3847         }
3848         if (is_prop_read_only(object_type, prop)) {
3849                 nerr("Clear error: property '%s' is read-only", prop);
3850                 return;
3851         }
3852 
3853         switch (object_type) {
3854         case NWAM_OBJECT_TYPE_NCU:
3855                 ret = nwam_ncu_delete_prop(ncu_h, prop);
3856                 break;
3857         case NWAM_OBJECT_TYPE_LOC:
3858                 ret = nwam_loc_delete_prop(loc_h, prop);
3859                 break;
3860         case NWAM_OBJECT_TYPE_ENM:
3861                 ret = nwam_enm_delete_prop(enm_h, prop);
3862                 break;
3863         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
3864                 ret = nwam_known_wlan_delete_prop(wlan_h, prop);
3865                 break;
3866         }
3867 
3868         if (ret != NWAM_SUCCESS) {
3869                 if (ret == NWAM_INVALID_ARG || ret == NWAM_ENTITY_NOT_FOUND) {
3870                         nerr("Clear error: property '%s' has not been set",
3871                             prop);
3872                 } else {
3873                         nwamerr(ret, "Clear error");
3874                 }
3875                 return;
3876         }
3877 
3878         need_to_commit = B_TRUE;
3879 }
3880 
3881 /*
3882  * Prints all the choices available for an enum property [c1|c2|c3].
3883  * Prints [true|false] for a boolean property.
3884  */
3885 static void
3886 print_all_prop_choices(nwam_object_type_t object_type, const char *prop)
3887 {
3888         uint64_t                i = 0;
3889         const char              *str;
3890         boolean_t               choices = B_FALSE;
3891         nwam_value_type_t       value_type;
3892         nwam_error_t            ret;
3893 
3894         /* Special case: print object-specific options for activation-mode */
3895         if (strcmp(prop, NWAM_NCU_PROP_ACTIVATION_MODE) == 0) {
3896                 /* "manual" for all objects */
3897                 (void) printf(" [%s|",
3898                     propval_to_str(NWAM_NCU_PROP_ACTIVATION_MODE,
3899                     NWAM_ACTIVATION_MODE_MANUAL));
3900                 if (object_type == NWAM_OBJECT_TYPE_NCU) {
3901                         (void) printf("%s]",
3902                             propval_to_str(NWAM_NCU_PROP_ACTIVATION_MODE,
3903                             NWAM_ACTIVATION_MODE_PRIORITIZED));
3904                 } else {
3905                         (void) printf("%s|%s]",
3906                             propval_to_str(NWAM_NCU_PROP_ACTIVATION_MODE,
3907                             NWAM_ACTIVATION_MODE_CONDITIONAL_ANY),
3908                             propval_to_str(NWAM_NCU_PROP_ACTIVATION_MODE,
3909                             NWAM_ACTIVATION_MODE_CONDITIONAL_ALL));
3910                 }
3911                 return;
3912         }
3913 
3914         /* Special case: only "manual" configsrc is allowed for LDAP */
3915         if (strcmp(prop, NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC) == 0) {
3916                 (void) printf(" [%s]",
3917                     propval_to_str(NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC,
3918                     NWAM_CONFIGSRC_MANUAL));
3919                 return;
3920         }
3921 
3922         value_type = prop_value_type(object_type, prop);
3923         switch (value_type) {
3924         case NWAM_VALUE_TYPE_UINT64:
3925                 /* uint64 may be an enum, will print nothing if not an enum */
3926                 while ((ret = nwam_uint64_get_value_string(prop, i++, &str))
3927                     == NWAM_SUCCESS || ret == NWAM_ENTITY_INVALID_VALUE) {
3928                         /* No string representation for i, continue. */
3929                         if (ret == NWAM_ENTITY_INVALID_VALUE)
3930                                 continue;
3931 
3932                         if (!choices)
3933                                 (void) printf("%s", " [");
3934                         (void) printf("%s%s", choices ? "|" : "", str);
3935                         choices = B_TRUE;
3936                 }
3937                 if (choices)
3938                         (void) putchar(']');
3939                 break;
3940         case NWAM_VALUE_TYPE_BOOLEAN:
3941                 (void) printf(" [%s|%s]", "true", "false");
3942                 break;
3943         case NWAM_VALUE_TYPE_STRING:
3944                 break;
3945         }
3946 }
3947 
3948 /*
3949  * Walk through object properties.
3950  * For newly-created object, the property name with no value is displayed, and
3951  * the user can input a value for each property.
3952  * For existing object, the current value is displayed and user input overwrites
3953  * the existing one. If no input is given, the existing value remains.
3954  * Read-only properties are not displayed.
3955  * Read-only objects cannot be walked.
3956  * If the -a option is specified, no properties are skipped.
3957  */
3958 void
3959 walkprop_func(cmd_t *cmd)
3960 {
3961         nwam_error_t    ret = NWAM_SUCCESS;
3962         nwam_value_t    vals = NULL; /* freed in _wait_input() */
3963         int             i;
3964         uint_t          prop_num;
3965         const char      **props;
3966         boolean_t       read_only = B_FALSE, all_props = B_FALSE;
3967 
3968         nwam_object_type_t object_type;
3969         prop_display_entry_t *prop_table;
3970 
3971         if (!interactive_mode) {
3972                 nerr("'walkprop' is only allowed in interactive mode");
3973                 return;
3974         }
3975 
3976         /* check if option -a is specified to show all properties */
3977         if (cmd->cmd_argc == 1) {
3978                 int c;
3979                 optind = 0;
3980                 while ((c = getopt(cmd->cmd_argc, cmd->cmd_argv, "a")) != EOF) {
3981                         switch (c) {
3982                         case 'a':
3983                                 all_props = B_TRUE;
3984                                 break;
3985                         default:
3986                                 command_usage(CMD_WALKPROP);
3987                                 return;
3988                         }
3989                 }
3990         }
3991 
3992         /* read-only objects cannot be walked */
3993         if (obj1_type == RT1_NCP) {
3994                 /* must be in NCU scope, NCP scope doesn't get here */
3995                 (void) nwam_ncu_get_read_only(ncu_h, &read_only);
3996         }
3997         if (read_only) {
3998                 nerr("'walkprop' cannot be used in read-only objects");
3999                 return;
4000         }
4001 
4002         /* get the current object type and the prop_display_table */
4003         object_type = active_object_type();
4004         prop_table = get_prop_display_table(object_type);
4005 
4006         /* get the property list depending on the object type */
4007         switch (object_type) {
4008         case NWAM_OBJECT_TYPE_NCU:
4009         {
4010                 nwam_ncu_type_t         ncu_type;
4011                 nwam_ncu_class_t        ncu_class;
4012 
4013                 if ((ret = nwam_ncu_get_ncu_type(ncu_h, &ncu_type))
4014                     != NWAM_SUCCESS)
4015                         break;
4016                 if ((ret = nwam_ncu_get_ncu_class(ncu_h, &ncu_class))
4017                     != NWAM_SUCCESS)
4018                         break;
4019 
4020                 ret = nwam_ncu_get_default_proplist(ncu_type, ncu_class, &props,
4021                     &prop_num);
4022                 break;
4023         }
4024         case NWAM_OBJECT_TYPE_LOC:
4025                 ret = nwam_loc_get_default_proplist(&props, &prop_num);
4026                 break;
4027         case NWAM_OBJECT_TYPE_ENM:
4028                 ret = nwam_enm_get_default_proplist(&props, &prop_num);
4029                 break;
4030         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
4031                 ret = nwam_known_wlan_get_default_proplist(&props, &prop_num);
4032                 break;
4033         }
4034         if (ret != NWAM_SUCCESS) {
4035                 nwamerr(ret, "Walkprop error: could not get property list");
4036                 return;
4037         }
4038 
4039         /* Loop through the properties */
4040         if (all_props)
4041                 (void) printf(gettext("Walking all properties ...\n"));
4042         for (i = 0; i < prop_num; i++) {
4043                 char line[NWAM_MAX_VALUE_LEN];
4044                 char **checked = NULL;
4045 
4046                 /* check if this property should be displayed */
4047                 if (is_prop_read_only(object_type, props[i]))
4048                         continue;
4049                 if (!all_props &&
4050                     !show_prop_test(object_type, props[i], prop_table,
4051                     checked, 0))
4052                         continue;
4053 
4054                 /* get the existing value for this property */
4055                 switch (object_type) {
4056                 case NWAM_OBJECT_TYPE_NCU:
4057                         ret = nwam_ncu_get_prop_value(ncu_h, props[i], &vals);
4058                         break;
4059                 case NWAM_OBJECT_TYPE_LOC:
4060                         ret = nwam_loc_get_prop_value(loc_h, props[i], &vals);
4061                         break;
4062                 case NWAM_OBJECT_TYPE_ENM:
4063                         ret = nwam_enm_get_prop_value(enm_h, props[i], &vals);
4064                         break;
4065                 case NWAM_OBJECT_TYPE_KNOWN_WLAN:
4066                         ret = nwam_known_wlan_get_prop_value(wlan_h, props[i],
4067                             &vals);
4068                         break;
4069                 }
4070                 /* returns NWAM_ENTITY_NOT_FOUND if no existing value */
4071                 if (ret != NWAM_SUCCESS && ret != NWAM_ENTITY_NOT_FOUND)
4072                         continue;
4073 
4074                 /* print property */
4075                 (void) printf("%s", props[i]);
4076                 /* print the existing value(s) if they exist */
4077                 if (ret == NWAM_SUCCESS) {
4078                         (void) printf(" (");
4079                         output_prop_val(props[i], vals, stdout, B_TRUE);
4080                         (void) putchar(')');
4081                         nwam_value_free(vals);
4082                 }
4083                 /* print choices, won't print anything if there aren't any */
4084                 print_all_prop_choices(object_type, props[i]);
4085                 (void) printf("> ");
4086 
4087                 /* wait for user input */
4088                 if (fgets(line, sizeof (line), stdin) == NULL)
4089                         continue;
4090 
4091                 /* if user input new value, existing value is overrode */
4092                 if (line[0] != '\n') {
4093                         boolean_t is_listprop;
4094                         int pt_type = prop_to_pt(object_type, props[i]);
4095 
4096                         is_listprop = is_prop_multivalued(object_type,
4097                             props[i]);
4098                         vals = str_to_nwam_value(object_type, line, pt_type,
4099                             is_listprop);
4100                         if (vals == NULL) {
4101                                 ret = NWAM_ENTITY_INVALID_VALUE;
4102                                 goto repeat;
4103                         }
4104 
4105                         /* set the new value for the property */
4106                         switch (object_type) {
4107                         case NWAM_OBJECT_TYPE_NCU:
4108                                 ret = nwam_ncu_set_prop_value(ncu_h, props[i],
4109                                     vals);
4110                                 break;
4111                         case NWAM_OBJECT_TYPE_LOC:
4112                                 ret = nwam_loc_set_prop_value(loc_h, props[i],
4113                                     vals);
4114                                 break;
4115                         case NWAM_OBJECT_TYPE_ENM:
4116                                 ret = nwam_enm_set_prop_value(enm_h, props[i],
4117                                     vals);
4118                                 break;
4119                         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
4120                                 ret = nwam_known_wlan_set_prop_value(wlan_h,
4121                                     props[i], vals);
4122                                 break;
4123                         }
4124                         nwam_value_free(vals);
4125 
4126                         if (ret != NWAM_SUCCESS)
4127                                 goto repeat;
4128 
4129                         need_to_commit = B_TRUE;
4130                         continue;
4131 
4132 repeat:
4133                         invalid_set_prop_msg(props[i], ret);
4134                         i--; /* decrement i to repeat */
4135                 }
4136         }
4137 
4138         free(props);
4139 }
4140 
4141 /*
4142  * Verify whether all properties of a resource are valid.
4143  */
4144 /* ARGSUSED */
4145 void
4146 verify_func(cmd_t *cmd)
4147 {
4148         nwam_error_t    ret;
4149         const char      *errprop;
4150 
4151         switch (active_object_type()) {
4152         case NWAM_OBJECT_TYPE_NCU:
4153                 ret = nwam_ncu_validate(ncu_h, &errprop);
4154                 break;
4155         case NWAM_OBJECT_TYPE_LOC:
4156                 ret = nwam_loc_validate(loc_h, &errprop);
4157                 break;
4158         case NWAM_OBJECT_TYPE_ENM:
4159                 ret = nwam_enm_validate(enm_h, &errprop);
4160                 break;
4161         case NWAM_OBJECT_TYPE_KNOWN_WLAN:
4162                 ret = nwam_known_wlan_validate(wlan_h, &errprop);
4163                 break;
4164         }
4165         if (ret != NWAM_SUCCESS)
4166                 nwamerr(ret, "Verify error on property '%s'", errprop);
4167         else if (interactive_mode)
4168                 (void) printf(gettext("All properties verified\n"));
4169 }
4170 
4171 /*
4172  * command-line mode (# nwamcfg list or # nwamcfg "select loc test; list")
4173  */
4174 static int
4175 one_command_at_a_time(int argc, char *argv[])
4176 {
4177         char *command;
4178         size_t len = 2; /* terminal \n\0 */
4179         int i, err;
4180 
4181         for (i = 0; i < argc; i++)
4182                 len += strlen(argv[i]) + 1;
4183         if ((command = malloc(len)) == NULL) {
4184                 nerr("Out of memory");
4185                 return (NWAM_ERR);
4186         }
4187         (void) strlcpy(command, argv[0], len);
4188         for (i = 1; i < argc; i++) {
4189                 (void) strlcat(command, " ", len);
4190                 (void) strlcat(command, argv[i], len);
4191         }
4192         (void) strlcat(command, "\n", len);
4193         err = string_to_yyin(command);
4194         free(command);
4195         if (err != NWAM_OK)
4196                 return (err);
4197         while (!feof(yyin)) {
4198                 yyparse();
4199 
4200                 /*
4201                  * If any command on a list of commands give an error,
4202                  * don't continue with the remaining commands.
4203                  */
4204                 if (saw_error || time_to_exit)
4205                         return (cleanup());
4206         }
4207 
4208         /* if there are changes to commit, commit it */
4209         if (need_to_commit) {
4210                 do_commit();
4211                 /* if need_to_commit is not set, then there was a error */
4212                 if (need_to_commit)
4213                         return (NWAM_ERR);
4214         }
4215 
4216         if (!interactive_mode)
4217                 return (cleanup());
4218         else {
4219                 yyin = stdin;
4220                 return (read_input());
4221         }
4222 }
4223 
4224 /*
4225  * cmd_file is slightly more complicated, as it has to open the command file
4226  * and set yyin appropriately.  Once that is done, though, it just calls
4227  * read_input(), and only once, since prompting is not possible.
4228  */
4229 static int
4230 cmd_file(char *file)
4231 {
4232         FILE *infile;
4233         int err;
4234         struct stat statbuf;
4235         boolean_t using_real_file = (strcmp(file, "-") != 0);
4236 
4237         if (using_real_file) {
4238                 /*
4239                  * nerr() prints a line number in cmd_file_mode, which we do
4240                  * not want here, so temporarily unset it.
4241                  */
4242                 cmd_file_mode = B_FALSE;
4243                 if ((infile = fopen(file, "r")) == NULL) {
4244                         nerr(gettext("could not open file '%s': %s"),
4245                             file, strerror(errno));
4246                         return (1);
4247                 }
4248                 if ((err = fstat(fileno(infile), &statbuf)) != 0) {
4249                         nerr(gettext("could not stat file '%s': %s"),
4250                             file, strerror(errno));
4251                         err = 1;
4252                         goto done;
4253                 }
4254                 if (!S_ISREG(statbuf.st_mode)) {
4255                         nerr(gettext("'%s' is not a regular file."), file);
4256                         err = 1;
4257                         goto done;
4258                 }
4259 
4260                 /*
4261                  * If -d was passed on the command-line, we need to
4262                  * start by removing any existing configuration.
4263                  * Alternatively, the file may begin with 'destroy -a';
4264                  * but in that case, the line will go through the lexer
4265                  * and be processed as it's encountered in the file.
4266                  */
4267                 if (remove_all_configurations && destroy_all() != NWAM_SUCCESS)
4268                         goto done;
4269 
4270                 /* set up for lexer */
4271                 yyin = infile;
4272                 cmd_file_mode = B_TRUE;
4273                 ok_to_prompt = B_FALSE;
4274         } else {
4275                 /*
4276                  * "-f -" is essentially the same as interactive mode,
4277                  * so treat it that way.
4278                  */
4279                 interactive_mode = B_TRUE;
4280         }
4281         /* NWAM_REPEAT is for interactive mode; treat it like NWAM_ERR here. */
4282         if ((err = read_input()) == NWAM_REPEAT)
4283                 err = NWAM_ERR;
4284         if (err == NWAM_OK)
4285                 (void) printf(gettext("Configuration read.\n"));
4286 
4287 done:
4288         if (using_real_file)
4289                 (void) fclose(infile);
4290         return (err);
4291 }
4292 
4293 int
4294 main(int argc, char *argv[])
4295 {
4296         int     err;
4297         char    c;
4298 
4299         /* This must be before anything goes to stdout. */
4300         setbuf(stdout, NULL);
4301 
4302         if ((execname = strrchr(argv[0], '/')) == NULL)
4303                 execname = argv[0];
4304         else
4305                 execname++;
4306 
4307         (void) setlocale(LC_ALL, "");
4308         (void) textdomain(TEXT_DOMAIN);
4309 
4310         while ((c = getopt(argc, argv, "?hf:d")) != EOF) {
4311                 switch (c) {
4312                 case 'f':
4313                         cmd_file_name = optarg;
4314                         cmd_file_mode = B_TRUE;
4315                         break;
4316                 case '?':
4317                 case 'h':
4318                         cmd_line_usage();
4319                         return (NWAM_OK);
4320                 case 'd':
4321                         remove_all_configurations = B_TRUE;
4322                         break;
4323                 default:
4324                         cmd_line_usage();
4325                         return (NWAM_ERR);
4326                 }
4327         }
4328         /* -d can only be used with -f */
4329         if (remove_all_configurations && !cmd_file_mode) {
4330                 nerr("Option -d can only be used with -f");
4331                 return (NWAM_ERR);
4332         }
4333 
4334         /*
4335          * This may get set back to FALSE again in cmd_file() if cmd_file_name
4336          * is a "real" file as opposed to "-" (i.e. meaning use stdin).
4337          */
4338         if (isatty(STDIN_FILENO))
4339                 ok_to_prompt = B_TRUE;
4340         if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL)
4341                 exit(NWAM_ERR);
4342         if (gl_customize_completion(gl, NULL, cmd_cpl_fn) != 0)
4343                 exit(NWAM_ERR);
4344         (void) sigset(SIGINT, SIG_IGN);
4345 
4346         if (optind == argc) {
4347                 /* interactive or command-file mode */
4348                 if (!cmd_file_mode)
4349                         err = do_interactive();
4350                 else
4351                         err = cmd_file(cmd_file_name);
4352         } else {
4353                 /* command-line mode */
4354                 err = one_command_at_a_time(argc - optind, &(argv[optind]));
4355         }
4356         (void) del_GetLine(gl);
4357 
4358         return (err);
4359 }