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