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