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