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
55struct help {
56	uint_t		cmd_num;
57	const char	*cmd_name;
58	const char	*cmd_usage;
59};
60
61extern int yyparse(void);
62extern 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
113static 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 */
134static 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 */
144static 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 */
157static 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 */
208typedef struct prop_table_entry {
209	int			pte_type;
210	const char		*pte_name;
211} prop_table_entry_t;
212
213/* NCU properties table */
214static 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 */
238static 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 */
249static 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 */
275static 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 */
285static prop_table_entry_t *
286get_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 */
304static char *execname;
305
306/* set in modifying functions, checked in read_input() */
307boolean_t saw_error = B_FALSE;
308
309/* set in yacc parser, checked in read_input() */
310boolean_t newline_terminated;
311
312/* set in main(), checked in lex error handler */
313boolean_t cmd_file_mode = B_FALSE;
314
315/* set in exit_func(), checked in read_input() */
316static boolean_t time_to_exit = B_FALSE;
317
318/* used in nerr() and nwamerr() */
319static char *cmd_file_name = NULL;
320
321/* used with cmd_file to destroy all configurations */
322static boolean_t remove_all_configurations = B_FALSE;
323
324/* checked in read_input() and other places */
325static boolean_t ok_to_prompt = B_FALSE;
326
327/* initialized in do_interactive(), checked in initialize() */
328static boolean_t interactive_mode;
329
330static boolean_t need_to_commit = B_FALSE;
331
332/* The gl_get_line() resource object */
333static GetLine *gl;
334
335/* set when create or read objects, used by other func */
336static nwam_loc_handle_t loc_h = NULL;
337static nwam_enm_handle_t enm_h = NULL;
338static nwam_known_wlan_handle_t wlan_h = NULL;
339static nwam_ncu_handle_t ncu_h = NULL;
340static nwam_ncp_handle_t ncp_h = NULL;
341
342static int current_scope = NWAM_SCOPE_GBL;
343
344/* obj1_* are used in NWAM_SCOPE_{NCP,LOC,ENM,WLAN} */
345static int obj1_type;
346static char obj1_name[NWAM_MAX_NAME_LEN + 1];
347
348/* obj2_* are used in NWAM_SCOPE_NCU only */
349static int obj2_type;
350static char obj2_name[NWAM_MAX_NAME_LEN + 1];
351
352/* arrays for tab-completion */
353/* commands at NWAM_SCOPE_GBL */
354static 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
366static 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
375static const char *global_destroy_cmds[] = {
376	"destroy -a ",
377	"destroy loc ",
378	"destroy enm ",
379	"destroy ncp ",
380	"destroy wlan ",
381	NULL
382};
383
384static 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
396static 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
408static 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 */
417static 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 */
439static 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
452static const char *ncp_create_cmds[] = {
453	"create ncu ip ",
454	"create ncu phys ",
455	"create -t ",		/* template */
456	NULL
457};
458
459static const char *ncp_destroy_cmds[] = {
460	"destroy ncu ",
461	"destroy ncu ip ",
462	"destroy ncu phys ",
463	NULL
464};
465
466static 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
475static 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
486static 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
495cmd_t *
496alloc_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
509void
510free_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
519void
520array_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
528static boolean_t
529initial_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
536static int
537add_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 */
561static
562CPL_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 (0);
607}
608
609const char *
610cmd_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 */
617static const char *
618rt1_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 */
625static const char *
626rt2_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 */
633static const char *
634scope_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 */
655static const char *
656propval_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 */
666static const char *
667pt_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 */
677static boolean_t
678str_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
698static const char *
699long_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
746void
747command_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
757static void
758long_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 */
766static void
767cmd_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 */
779static void
780print_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 */
797void
798nerr(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 */
814static void
815nwamerr(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
830void
831properr(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 */
841static void
842free_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 */
875static int
876ask_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. */
901static int
902cleanup()
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
941static int
942string_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
953error:
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 */
964static int
965read_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 */
1044static int
1045do_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 */
1057void
1058help_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 */
1069boolean_t
1070check_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 */
1124static nwam_object_type_t
1125active_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 */
1143static nwam_error_t
1144object_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
1162static void
1163do_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 */
1220void
1221commit_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
1231static void
1232do_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 */
1263void
1264cancel_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 */
1273static char *
1274trim_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 */
1306void
1307create_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
1468read_error:
1469	if (ret != NWAM_SUCCESS)
1470		nwamerr(ret, "Copy error reading '%s'", oldname);
1471
1472done:
1473	free(oldname);
1474	free(newname);
1475}
1476
1477/* Processing of return value for destroy_*_callback() */
1478static int
1479destroy_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 */
1509static int
1510destroy_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 */
1518static int
1519destroy_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 */
1526static int
1527destroy_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 */
1534static int
1535destroy_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 */
1545static nwam_error_t
1546destroy_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
1574done:
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 */
1587void
1588destroy_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
1682done:
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 */
1703void
1704end_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 */
1729void
1730exit_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
1751void
1752help_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 */
1779void
1780revert_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
1840name_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 */
1849void
1850select_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 */
1944static const char *
1945pt_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 */
1958static int
1959prop_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) */
1972static nwam_value_type_t
1973prop_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 */
2003static nwam_value_t
2004str_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
2173typedef 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 */
2186static 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 */
2220static 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 */
2229static 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 */
2271static 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 */
2277static prop_display_entry_t *
2278get_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 */
2306static boolean_t
2307show_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
2401next_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 */
2440static boolean_t
2441is_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 */
2466static boolean_t
2467is_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 */
2496static void
2497invalid_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 */
2536void
2537set_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
2604static int
2605list_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 */
2642static int
2643list_loc_callback(nwam_loc_handle_t loc, void *arg)
2644{
2645	return (list_callback(NWAM_OBJECT_TYPE_LOC, loc, arg, "Locations"));
2646}
2647
2648static int
2649list_enm_callback(nwam_enm_handle_t enm, void *arg)
2650{
2651	return (list_callback(NWAM_OBJECT_TYPE_ENM, enm, arg, "ENMs"));
2652}
2653
2654static int
2655list_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
2660static int
2661list_ncp_callback(nwam_ncp_handle_t ncp, void *arg)
2662{
2663	return (list_callback(NWAM_OBJECT_TYPE_NCP, ncp, arg, "NCPs"));
2664}
2665
2666static int
2667list_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 */
2674static const char *
2675str2str(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 */
2682static const char *
2683str2qstr(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 */
2691static const char *
2692int2str(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
2698static const char *
2699uint2str(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 */
2711static const char *
2712bool2str(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 */
2723static void
2724output_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) */
2796static int
2797output_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
2815static int
2816output_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 */
2822static int
2823output_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 */
2833static nwam_error_t
2834listprop(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
2977done:
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
3006readfail:
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 */
3016void
3017list_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
3212done:
3213	if (ret != NWAM_SUCCESS)
3214		nwamerr(ret, "List error");
3215}
3216
3217static int
3218write_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
3230static int
3231export_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
3278static int
3279export_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
3310static int
3311export_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
3348static int
3349export_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
3392static int
3393export_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 */
3435void
3436export_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
3745fail:
3746	free(name);
3747	if (ret != NWAM_SUCCESS)
3748		nwamerr(ret, "Export error");
3749
3750done:
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 */
3759void
3760get_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 */
3830void
3831clear_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 */
3880static void
3881print_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 */
3953void
3954walkprop_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
4127repeat:
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 */
4140void
4141verify_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 */
4169static int
4170one_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 */
4224static int
4225cmd_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
4282done:
4283	if (using_real_file)
4284		(void) fclose(infile);
4285	return (err);
4286}
4287
4288int
4289main(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