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