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