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