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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This is the main program file for the configuration administration 31 * command as set out in manual page cfgadm(1M). It uses the configuration 32 * administration library interface, libcfgadm, as set out in manual 33 * page config_admin(3X). 34 */ 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <locale.h> 40 #include <langinfo.h> 41 #include <time.h> 42 #include <assert.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <sys/param.h> 46 #include <sys/sunddi.h> 47 #include <sys/openpromio.h> 48 #include <sys/ddi_impldefs.h> 49 #include <sys/systeminfo.h> 50 #include <ctype.h> 51 52 #include <config_admin.h> 53 #include "cfgadm.h" 54 55 #define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0) 56 #define GET_DYN(a) (strstr((a), CFGA_DYN_SEP)) 57 /* 58 * forward declarations 59 */ 60 static char *basename(char *); 61 static void cfgadm_error(int, char *); 62 static int confirm_interactive(void *, const char *); 63 static int confirm_no(void *, const char *); 64 static int confirm_yes(void *, const char *); 65 static void usage(void); 66 static void usage_field(void); 67 static int extract_list_suboptions(char *, char **, char **, char **, 68 int *, char **, char **, char **); 69 static int message_output(void *appdata_ptr, const char *message); 70 static void *config_calloc_check(size_t, size_t); 71 static cfga_ap_types_t find_arg_type(const char *); 72 static int yesno(char *, char *); 73 74 75 static int compare_ap_id(cfga_list_data_t *, cfga_list_data_t *, match_type_t); 76 static int compare_r_state(cfga_list_data_t *, cfga_list_data_t *, 77 match_type_t); 78 static int compare_o_state(cfga_list_data_t *, cfga_list_data_t *, 79 match_type_t); 80 static int compare_cond(cfga_list_data_t *, cfga_list_data_t *, match_type_t); 81 static int compare_time(cfga_list_data_t *, cfga_list_data_t *, match_type_t); 82 static int compare_info(cfga_list_data_t *, cfga_list_data_t *, match_type_t); 83 static int compare_type(cfga_list_data_t *, cfga_list_data_t *, match_type_t); 84 static int compare_busy(cfga_list_data_t *, cfga_list_data_t *, match_type_t); 85 static int compare_class(cfga_list_data_t *, cfga_list_data_t *, match_type_t); 86 static int compare_null(cfga_list_data_t *, cfga_list_data_t *, match_type_t); 87 static void print_log_id(cfga_list_data_t *, int, char *); 88 static void print_r_state(cfga_list_data_t *, int, char *); 89 static void print_o_state(cfga_list_data_t *, int, char *); 90 static void print_cond(cfga_list_data_t *, int, char *); 91 static void print_time(cfga_list_data_t *, int, char *); 92 static void print_time_p(cfga_list_data_t *, int, char *); 93 static void print_info(cfga_list_data_t *, int, char *); 94 static void print_type(cfga_list_data_t *, int, char *); 95 static void print_busy(cfga_list_data_t *, int, char *); 96 static void print_phys_id(cfga_list_data_t *, int, char *); 97 static void print_class(cfga_list_data_t *, int, char *); 98 static void print_null(cfga_list_data_t *, int, char *); 99 static int count_fields(char *, char); 100 static int process_sort_fields(int, struct sort_el *, char *); 101 static int process_fields(int, struct print_col *, int, char *); 102 static cfga_err_t print_fields(int, struct print_col *, int, int, char *, 103 cfga_list_data_t *, FILE *); 104 static int ldata_compare(const void *, const void *); 105 106 static void arg_got_resp(ap_arg_t *inp, ap_out_t *out_array, int nouts, 107 int dyn_exp); 108 static void out_was_req(ap_out_t *outp, ap_arg_t *in_array, int nargs, 109 int no_dyn); 110 static void report_no_response(ap_arg_t *arg_array, int napids_to_list); 111 112 static cfga_err_t set_log_flt(cfga_list_data_t *p, const char *val); 113 static cfga_err_t set_type_flt(cfga_list_data_t *p, const char *val); 114 static cfga_err_t set_class_flt(cfga_list_data_t *p, const char *val); 115 116 static char *get_dyn(const char *ap_id); 117 static void remove_dyn(char *ap_id); 118 static char *s_strdup(char *str); 119 120 /* 121 * global data 122 */ 123 /* command name for messages */ 124 static char *cmdname; 125 126 /* 127 * control for comparing, printing and filtering cfga_list_data 128 * NOTE:Field names (i.e. member 0 of field_info struct) may not contain '('. 129 * The post filtering code depends on it. 130 * NOTE:A NULL value for the set_filter member indicates that filtering based 131 * on that field is currently not supported. 132 */ 133 static struct field_info all_fields[] = { 134 {"ap_id", "Ap_Id", SZ_EL(ap_log_id), compare_ap_id, print_log_id, set_log_flt}, 135 {"r_state", "Receptacle", STATE_WIDTH, compare_r_state, print_r_state, NULL}, 136 {"o_state", "Occupant", STATE_WIDTH, compare_o_state, print_o_state, NULL}, 137 {"condition", "Condition", COND_WIDTH, compare_cond, print_cond, NULL}, 138 {"status_time", "When", TIME_WIDTH, compare_time, print_time, NULL}, 139 {"status_time_p", "When", TIME_P_WIDTH, compare_time, print_time_p, NULL}, 140 {"info", "Information", SZ_EL(ap_info), compare_info, print_info, NULL}, 141 {"type", "Type", SZ_EL(ap_type), compare_type, print_type, set_type_flt}, 142 {"busy", "Busy", 8, compare_busy, print_busy, NULL}, 143 {"physid", "Phys_Id", SZ_EL(ap_phys_id), compare_ap_id, print_phys_id, NULL}, 144 {"class", "Class", SZ_EL(ap_class), compare_class, print_class, set_class_flt} 145 }; 146 147 #define PREFILT_CLASS_STR "class=" 148 149 typedef struct { 150 cfga_list_data_t ldata; /* Selection criteria */ 151 match_type_t match_type_p[N_FIELDS]; /* Type of match */ 152 } post_filter_t; 153 154 static struct field_info null_field = 155 {"null", "", 0, compare_null, print_null, NULL}; 156 157 static struct sort_el *sort_list; /* Used in ldata_compare() */ 158 static int nsort_list; 159 static char unk_field[] = "%s: field \"%s\" unknown\n"; 160 161 static char aptype_no_dyn[] = "%s: Invalid ap_id: %s\n"; 162 163 /* strings that make up the usage message */ 164 static char *usage_tab[] = { 165 " %s [-f] [-y|-n] [-v] [-o hardware_opts ] -c function ap_id [ap_id...]\n", 166 " %s [-f] [-y|-n] [-v] [-o hardware_opts ] -x function ap_id [ap_id...]\n", 167 " %s [-v] [-s listing_options ] [-o hardware_opts ] [-a]\n" 168 "\t[-l [ap_id|ap_type...]]\n", 169 " %s [-v] [-o hardware_opts ] -t ap_id [ap_id...]\n", 170 " %s [-v] [-o hardware_opts ] -h [ap_id|ap_type...]\n", 171 }; 172 173 /* Type of matches currently supported by the select sub-option */ 174 static match_cvt_t match_type_array[] = { 175 {"partial", CFGA_MATCH_PARTIAL}, 176 {"exact", CFGA_MATCH_EXACT} 177 }; 178 179 #define N_MATCH_TYPES (sizeof (match_type_array)/sizeof (match_type_array[0])) 180 181 static cfga_err_t setup_filter(const char *selectp, const char *matchp, 182 post_filter_t *post_filtp, char **prefilt_optpp); 183 static cfga_err_t parse_select_opt(const char *selectp, 184 post_filter_t *post_filtp, match_type_t match_type); 185 static int do_config_list(int, char *[], cfga_list_data_t *, int, char *, 186 char *, char *, int, char *, post_filter_t *, int); 187 static void do_post_filter(ap_out_t *outp, post_filter_t *post_filtp, int *jp); 188 189 190 /* 191 * main - the main routine of cfgadm, processes the command line 192 * and dispatches functions off to libraries. 193 */ 194 int 195 main( 196 int argc, 197 char *argv[]) 198 { 199 extern char *optarg; 200 extern int optind; 201 int c; 202 char *subopts; 203 char *subvalue; 204 char *const *ap_args = NULL; 205 cfga_cmd_t sc_opt = NULL; 206 struct cfga_confirm confirm; 207 struct cfga_msg message; 208 int ret = CFGA_ERROR; 209 int i; 210 char *estrp = NULL; 211 cfga_op_t action = CFGA_OP_NONE; 212 char *plat_opts = NULL; 213 char *act_arg = NULL; 214 enum confirm confarg = CONFIRM_DEFAULT; 215 char *list_opts = NULL; 216 cfga_flags_t flags = 0; 217 int arg_error = 0; 218 int dyn_exp = 0; 219 220 estrp = NULL; 221 if (argc > 0) 222 cmdname = basename(argv[0]); 223 else 224 cmdname = "cfgadm"; 225 (void) setlocale(LC_ALL, ""); 226 #if !defined(TEXT_DOMAIN) 227 #define TEXT_DOMAIN "SYS_TEST" 228 #endif 229 (void) textdomain(TEXT_DOMAIN); 230 231 while ((c = getopt(argc, argv, OPTIONS)) != EOF) { 232 static char dup_action[] = 233 "%s: more than one action specified (-c,-l,-t,-x)\n"; 234 static char dup_option[] = 235 "%s: more than one -%c option specified\n"; 236 switch (c) { 237 case 'a': 238 if (dyn_exp) { 239 arg_error = 1; 240 (void) fprintf(stderr, gettext(dup_option), 241 cmdname, c); 242 } 243 dyn_exp = 1; 244 break; 245 case 'c': 246 if (action != CFGA_OP_NONE) { 247 arg_error = 1; 248 (void) fprintf(stderr, gettext(dup_action), 249 cmdname); 250 } 251 action = CFGA_OP_CHANGE_STATE; 252 subopts = optarg; 253 subvalue = NULL; 254 /* 255 * Reject -c suboption if they are unrecognized 256 * or more than one or have a associated value. 257 */ 258 if ((sc_opt = getsubopt(&subopts, state_opts, 259 &subvalue)) == -1 || *subopts != '\0' || 260 subvalue != NULL) { 261 arg_error = 1; 262 break; 263 } 264 break; 265 case 'f': 266 if ((flags & CFGA_FLAG_FORCE) != 0) { 267 arg_error = 1; 268 (void) fprintf(stderr, gettext(dup_option), 269 cmdname, c); 270 } 271 flags |= CFGA_FLAG_FORCE; 272 break; 273 case 'h': 274 if (action != CFGA_OP_NONE) { 275 arg_error = 1; 276 (void) fprintf(stderr, gettext(dup_action), 277 cmdname); 278 } 279 action = CFGA_OP_HELP; 280 break; 281 case 'l': 282 if (action != CFGA_OP_NONE) { 283 arg_error = 1; 284 (void) fprintf(stderr, gettext(dup_action), 285 cmdname); 286 } 287 action = CFGA_OP_LIST; 288 break; 289 case 'n': 290 if (confarg != CONFIRM_DEFAULT) { 291 arg_error = 1; 292 (void) fprintf(stderr, gettext(dup_option), 293 cmdname, c); 294 } 295 confarg = CONFIRM_NO; 296 break; 297 case 'o': 298 if (plat_opts != NULL) { 299 arg_error = 1; 300 (void) fprintf(stderr, gettext(dup_option), 301 cmdname, c); 302 } 303 plat_opts = optarg; 304 break; 305 case 's': 306 if (list_opts != NULL) { 307 arg_error = 1; 308 (void) fprintf(stderr, gettext(dup_option), 309 cmdname, c); 310 } 311 list_opts = optarg; 312 break; 313 case 't': 314 if (action != CFGA_OP_NONE) { 315 arg_error = 1; 316 (void) fprintf(stderr, gettext(dup_action), 317 cmdname); 318 } 319 action = CFGA_OP_TEST; 320 break; 321 case 'x': 322 if (action != CFGA_OP_NONE) { 323 arg_error = 1; 324 (void) fprintf(stderr, gettext(dup_action), 325 cmdname); 326 } 327 action = CFGA_OP_PRIVATE; 328 act_arg = optarg; 329 break; 330 case 'v': 331 if ((flags & CFGA_FLAG_VERBOSE) != 0) { 332 arg_error = 1; 333 (void) fprintf(stderr, gettext(dup_option), 334 cmdname, c); 335 } 336 flags |= CFGA_FLAG_VERBOSE; 337 break; 338 case 'y': 339 if (confarg != CONFIRM_DEFAULT) { 340 arg_error = 1; 341 (void) fprintf(stderr, gettext(dup_option), 342 cmdname, c); 343 } 344 confarg = CONFIRM_YES; 345 break; 346 case '?': /* getopts issues message is this case */ 347 default: /* catch programming errors */ 348 arg_error = 1; 349 break; 350 } 351 } 352 353 /* default action is list */ 354 if (action == CFGA_OP_NONE) 355 action = CFGA_OP_LIST; 356 357 /* -s and -a option only for list */ 358 if (action != CFGA_OP_LIST && (list_opts != NULL || dyn_exp)) { 359 arg_error = 1; 360 } 361 362 if (arg_error) { 363 usage(); 364 exit(EXIT_ARGERROR); 365 /*NOTREACHED*/ 366 } 367 368 ap_args = &argv[optind]; 369 370 /* 371 * If neither -n of -y was specified, interactive confirmation 372 * is used. Check if the program has terminal I/O and 373 * enforce -n if not. 374 */ 375 (void) memset(&confirm, 0, sizeof (confirm)); 376 if (action == CFGA_OP_CHANGE_STATE || action == CFGA_OP_PRIVATE) { 377 if (confarg == CONFIRM_DEFAULT && 378 !(isatty(fileno(stdin)) && isatty(fileno(stderr)))) 379 confarg = CONFIRM_NO; 380 switch (confarg) { 381 case CONFIRM_DEFAULT: 382 confirm.confirm = confirm_interactive; 383 break; 384 case CONFIRM_NO: 385 confirm.confirm = confirm_no; 386 break; 387 case CONFIRM_YES: 388 confirm.confirm = confirm_yes; 389 break; 390 default: /* paranoia */ 391 abort(); 392 /*NOTREACHED*/ 393 } 394 } 395 396 /* 397 * set up message output routine 398 */ 399 message.message_routine = message_output; 400 401 switch (action) { 402 case CFGA_OP_CHANGE_STATE: 403 /* Sanity check - requires an argument */ 404 if ((argc - optind) <= 0) { 405 usage(); 406 break; 407 } 408 /* Sanity check - args cannot be ap_types */ 409 for (i = 0; i < (argc - optind); i++) { 410 if (find_arg_type(ap_args[i]) == AP_TYPE) { 411 usage(); 412 exit(EXIT_ARGERROR); 413 /*NOTREACHED*/ 414 } 415 } 416 ret = config_change_state(sc_opt, argc - optind, ap_args, plat_opts, 417 &confirm, &message, &estrp, flags); 418 if (ret != CFGA_OK) 419 cfgadm_error(ret, estrp); 420 break; 421 case CFGA_OP_PRIVATE: 422 /* Sanity check - requires an argument */ 423 if ((argc - optind) <= 0) { 424 usage(); 425 break; 426 } 427 /* Sanity check - args cannot be ap_types */ 428 for (i = 0; i < (argc - optind); i++) { 429 if (find_arg_type(ap_args[i]) == AP_TYPE) { 430 usage(); 431 exit(EXIT_ARGERROR); 432 /*NOTREACHED*/ 433 } 434 } 435 436 ret = config_private_func(act_arg, argc - optind, ap_args, 437 plat_opts, &confirm, &message, &estrp, flags); 438 439 if (ret != CFGA_OK) 440 cfgadm_error(ret, estrp); 441 break; 442 case CFGA_OP_TEST: 443 /* Sanity check - requires an argument */ 444 if ((argc - optind) <= 0) { 445 usage(); 446 break; 447 } 448 449 if ((flags & ~CFGA_FLAG_VERBOSE) != 0) { 450 usage(); 451 exit(EXIT_ARGERROR); 452 /*NOTREACHED*/ 453 } 454 455 /* Sanity check - args cannot be ap_types */ 456 for (i = 0; i < (argc - optind); i++) { 457 if (find_arg_type(ap_args[i]) == AP_TYPE) { 458 usage(); 459 exit(EXIT_ARGERROR); 460 /*NOTREACHED*/ 461 } 462 } 463 ret = config_test(argc - optind, ap_args, plat_opts, &message, 464 &estrp, flags); 465 if (ret != CFGA_OK) 466 cfgadm_error(ret, estrp); 467 break; 468 case CFGA_OP_HELP: 469 470 if ((flags & ~CFGA_FLAG_VERBOSE) != 0) { 471 usage(); 472 exit(EXIT_ARGERROR); 473 /*NOTREACHED*/ 474 } 475 476 /* always do usage? */ 477 usage(); 478 ret = config_help(argc - optind, ap_args, &message, plat_opts, 479 flags); 480 if (ret != CFGA_OK) 481 cfgadm_error(ret, estrp); 482 break; 483 484 case CFGA_OP_LIST: { 485 /* 486 * Note that we leak the strdup strings below (we never free 487 * them). This is ok in this context since cfgadm is 488 * a short lived process that will exit shortly freeing 489 * the memory. 490 */ 491 cfga_list_data_t *list_array = NULL; 492 int nlist = 0; 493 char *sort_fields = s_strdup(DEF_SORT_FIELDS); 494 char *cols = s_strdup(DEF_COLS); 495 char *cols2 = s_strdup(DEF_COLS2); 496 int noheadings = 0; 497 char *delim = s_strdup(DEF_DELIM); 498 int exitcode = EXIT_OK; 499 int i; 500 int type = 0; 501 char *selectp = NULL, *matchp = NULL, *prefilt_optp = NULL; 502 post_filter_t *post_filtp = NULL; 503 504 if ((flags & ~CFGA_FLAG_VERBOSE) != 0) { 505 usage(); 506 exit(EXIT_ARGERROR); 507 /*NOTREACHED*/ 508 } 509 510 if (flags & CFGA_FLAG_VERBOSE) { 511 cols = s_strdup(DEF_COLS_VERBOSE); 512 cols2 = s_strdup(DEF_COLS2_VERBOSE); 513 } 514 515 if (list_opts != NULL && !extract_list_suboptions(list_opts, 516 &sort_fields, &cols, &cols2, &noheadings, &delim, 517 &selectp, &matchp)) { 518 usage_field(); 519 exit(EXIT_ARGERROR); 520 /*NOTREACHED*/ 521 } 522 523 /* 524 * Scan any args and see if there are any ap_types. 525 * If there are we get all attachment point stats and 526 * then filter what gets printed. 527 */ 528 529 type = 0; 530 for (i = 0; i < (argc - optind); i++) { 531 if (find_arg_type(ap_args[i]) == AP_TYPE) { 532 type = 1; 533 /* ap_types cannot have dynamic components */ 534 if (get_dyn(ap_args[i]) != NULL) { 535 (void) fprintf(stderr, 536 gettext(aptype_no_dyn), 537 cmdname, ap_args[i]); 538 exit(EXIT_ARGERROR); 539 /*NOTREACHED*/ 540 } 541 break; 542 } 543 } 544 545 /* Setup filter */ 546 post_filtp = config_calloc_check(1, sizeof (*post_filtp)); 547 if (post_filtp == NULL) { 548 exit(EXIT_OPFAILED); 549 /*NOTREACHED*/ 550 } 551 if (setup_filter(selectp, matchp, post_filtp, &prefilt_optp) 552 != CFGA_OK) { 553 S_FREE(post_filtp); 554 exit(EXIT_ARGERROR); 555 /*NOTREACHED*/ 556 } 557 558 list_array = NULL; 559 exitcode = EXIT_OK; 560 561 /* 562 * Check for args. No args means find all libs 563 * and call the cfga_list_ext routine with no ap_ids specified. 564 * With args, if any one of the args are ap_types we 565 * again find all attachment points as in the 566 * no-args case above and then select which attachment points 567 * are actually displayed. 568 */ 569 if (((argc - optind) == 0) || (type == 1)) { 570 /* 571 * No args, or atleast 1 ap_type arg 572 */ 573 ret = config_list_ext(0, NULL, &list_array, 574 &nlist, plat_opts, prefilt_optp, &estrp, 575 dyn_exp ? CFGA_FLAG_LIST_ALL : 0); 576 } else { 577 /* 578 * If the args are all ap_ids (no ap_types) we call the 579 * cfga_list_ext routine with those specific ap_ids. 580 */ 581 ret = config_list_ext(argc - optind, ap_args, 582 &list_array, &nlist, plat_opts, prefilt_optp, 583 &estrp, dyn_exp ? CFGA_FLAG_LIST_ALL : 0); 584 } 585 586 S_FREE(prefilt_optp); 587 588 if (ret == CFGA_OK) { 589 590 if (do_config_list( 591 (argc - optind), &argv[optind], list_array, nlist, 592 sort_fields, cols, cols2, noheadings, delim, 593 post_filtp, dyn_exp) != CFGA_OK) { 594 exitcode = EXIT_ARGERROR; 595 } else { 596 exitcode = EXIT_OK; 597 } 598 599 S_FREE(list_array); 600 S_FREE(post_filtp); 601 602 if (exitcode != EXIT_OK) { 603 exit(exitcode); 604 /*NOTREACHED*/ 605 } 606 } else { 607 608 S_FREE(post_filtp); 609 cfgadm_error(ret, estrp); 610 } 611 break; 612 } 613 default: /* paranoia */ 614 abort(); 615 /*NOTREACHED*/ 616 } 617 618 if (ret == CFGA_NOTSUPP) { 619 return (EXIT_NOTSUPP); 620 } else if (ret != CFGA_OK) { 621 return (EXIT_OPFAILED); 622 } else { 623 return (EXIT_OK); 624 } 625 /*NOTREACHED*/ 626 } 627 628 /* 629 * usage - outputs the usage help message. 630 */ 631 static void 632 usage( 633 void) 634 { 635 int i; 636 637 (void) fprintf(stderr, "%s\n", gettext("Usage:")); 638 for (i = 0; i < sizeof (usage_tab)/sizeof (usage_tab[0]); i++) { 639 (void) fprintf(stderr, gettext(usage_tab[i]), cmdname); 640 } 641 } 642 643 /* 644 * Emit an error message. 645 * As a side-effect the hardware specific error message is deallocated 646 * as described in config_admin(3X). 647 */ 648 static void 649 cfgadm_error(int errnum, char *estrp) 650 { 651 const char *ep; 652 653 ep = config_strerror(errnum); 654 if (ep == NULL) 655 ep = gettext("configuration administration unknown error"); 656 if (estrp != NULL && *estrp != '\0') { 657 (void) fprintf(stderr, "%s: %s: %s\n", cmdname, ep, estrp); 658 } else { 659 (void) fprintf(stderr, "%s: %s\n", cmdname, ep); 660 } 661 if (estrp != NULL) 662 free((void *)estrp); 663 if (errnum == CFGA_INVAL) 664 usage(); 665 } 666 667 /* 668 * confirm_interactive - prompt user for confirmation 669 */ 670 static int 671 confirm_interactive( 672 void *appdata_ptr, 673 const char *message) 674 { 675 static char yeschr[YESNO_STR_MAX + 2]; 676 static char nochr[YESNO_STR_MAX + 2]; 677 static int inited = 0; 678 int isyes; 679 680 #ifdef lint 681 appdata_ptr = appdata_ptr; 682 #endif /* lint */ 683 /* 684 * First time through initialisation. In the original 685 * version of this command this function is only called once, 686 * but this function is generalized for the future. 687 */ 688 if (!inited) { 689 (void) strncpy(yeschr, nl_langinfo(YESSTR), YESNO_STR_MAX + 1); 690 (void) strncpy(nochr, nl_langinfo(NOSTR), YESNO_STR_MAX + 1); 691 inited = 1; 692 } 693 694 do { 695 (void) fprintf(stderr, "%s (%s/%s)? ", message, yeschr, nochr); 696 isyes = yesno(yeschr, nochr); 697 } while (isyes == -1); 698 return (isyes); 699 } 700 701 /* 702 * If any text is input it must sub-string match either yes or no. 703 * Failure of this match is indicated by return of -1. 704 * If an empty line is input, this is taken as no. 705 */ 706 static int 707 yesno( 708 char *yesp, 709 char *nop) 710 { 711 int i, b; 712 char ans[YESNO_STR_MAX + 1]; 713 714 i = 0; 715 716 /*CONSTCOND*/ 717 while (1) { 718 b = getc(stdin); /* more explicit that rm.c version */ 719 if (b == '\n' || b == '\0' || b == EOF) { 720 if (i < YESNO_STR_MAX) /* bug fix to rm.c version */ 721 ans[i] = 0; 722 break; 723 } 724 if (i < YESNO_STR_MAX) 725 ans[i] = b; 726 i++; 727 } 728 if (i >= YESNO_STR_MAX) { 729 i = YESNO_STR_MAX; 730 ans[YESNO_STR_MAX] = 0; 731 } 732 /* changes to rm.c version follow */ 733 if (i == 0) 734 return (0); 735 if (strncmp(nop, ans, i) == 0) 736 return (0); 737 if (strncmp(yesp, ans, i) == 0) 738 return (1); 739 return (-1); 740 } 741 742 /*ARGSUSED*/ 743 static int 744 confirm_no( 745 void *appdata_ptr, 746 const char *message) 747 { 748 return (0); 749 } 750 751 /*ARGSUSED*/ 752 static int 753 confirm_yes( 754 void *appdata_ptr, 755 const char *message) 756 { 757 return (1); 758 } 759 760 /* 761 * Find base name of filename. 762 */ 763 static char * 764 basename( 765 char *cp) 766 { 767 char *sp; 768 769 if ((sp = strrchr(cp, '/')) != NULL) 770 return (sp + 1); 771 return (cp); 772 } 773 774 /*ARGSUSED*/ 775 static int 776 message_output( 777 void *appdata_ptr, 778 const char *message) 779 { 780 (void) fprintf(stderr, "%s", message); 781 return (CFGA_OK); 782 783 } 784 785 /* 786 * extract_list_suboptions - process list option string 787 */ 788 static int 789 extract_list_suboptions( 790 char *arg, 791 char **sortpp, 792 char **colspp, 793 char **cols2pp, 794 int *noheadingsp, 795 char **delimpp, 796 char **selectpp, 797 char **matchpp) 798 { 799 char *value = NULL; 800 int subopt = 0; 801 int err = 0; 802 803 while (*arg != '\0') { 804 static char need_value[] = 805 "%s: sub-option \"%s\" requires a value\n"; 806 static char no_value[] = 807 "%s: sub-option \"%s\" does not take a value\n"; 808 static char unk_subopt[] = 809 "%s: sub-option \"%s\" unknown\n"; 810 char **pptr; 811 812 subopt = getsubopt(&arg, list_options, &value); 813 switch (subopt) { 814 case LIST_SORT: 815 pptr = sortpp; 816 goto valcom; 817 case LIST_COLS: 818 pptr = colspp; 819 goto valcom; 820 case LIST_COLS2: 821 pptr = cols2pp; 822 goto valcom; 823 case LIST_SELECT: 824 pptr = selectpp; 825 goto valcom; 826 case LIST_MATCH: 827 pptr = matchpp; 828 goto valcom; 829 case LIST_DELIM: 830 pptr = delimpp; 831 valcom: 832 if (value == NULL) { 833 (void) fprintf(stderr, gettext(need_value), 834 cmdname, list_options[subopt]); 835 err = 1; 836 } else 837 *pptr = value; 838 break; 839 case LIST_NOHEADINGS: 840 if (value != NULL) { 841 (void) fprintf(stderr, gettext(no_value), 842 cmdname, list_options[subopt]); 843 err = 1; 844 } else 845 *noheadingsp = 1; 846 break; 847 default: 848 (void) fprintf(stderr, gettext(unk_subopt), 849 cmdname, value); 850 err = 1; 851 break; 852 } 853 } 854 return (err == 0); 855 } 856 857 static cfga_err_t 858 setup_prefilter(post_filter_t *post_filtp, char **prefilt_optpp) 859 { 860 size_t len; 861 const char *clopt = PREFILT_CLASS_STR; 862 int idx; 863 864 865 *prefilt_optpp = NULL; 866 867 /* Get the index for the "class" field */ 868 for (idx = 0; idx < N_FIELDS; idx++) { 869 if (strcmp(all_fields[idx].name, PREFILT_CLASS_STR) == 0) 870 break; 871 } 872 873 /* 874 * Currently pre-filter available only for class fld w/ EXACT match 875 */ 876 if (idx >= N_FIELDS || 877 post_filtp->match_type_p[idx] != CFGA_MATCH_EXACT) { 878 return (CFGA_OK); 879 } 880 881 len = strlen(clopt) + strlen(post_filtp->ldata.ap_class) + 1; 882 if ((*prefilt_optpp = config_calloc_check(1, len)) == NULL) { 883 return (CFGA_LIB_ERROR); 884 } 885 886 (void) strcpy(*prefilt_optpp, clopt); 887 (void) strcat(*prefilt_optpp, post_filtp->ldata.ap_class); 888 889 /* 890 * Since it is being pre-filtered, this attribute does not need 891 * post-filtering. 892 */ 893 post_filtp->match_type_p[idx] = CFGA_MATCH_NOFILTER; 894 if (all_fields[idx].set_filter != NULL) { 895 (void) all_fields[idx].set_filter(&post_filtp->ldata, ""); 896 } 897 898 return (CFGA_OK); 899 } 900 901 static cfga_err_t 902 set_attrval( 903 const char *attr, 904 const char *val, 905 post_filter_t *post_filtp, 906 match_type_t match_type) 907 { 908 int fld = 0; 909 cfga_err_t ret = CFGA_ERROR; 910 911 for (fld = 0; fld < N_FIELDS; fld++) { 912 if (strcmp(attr, all_fields[fld].name) == 0) 913 break; 914 } 915 916 /* Valid field or is the select option supported for this field */ 917 if (fld >= N_FIELDS || all_fields[fld].set_filter == NULL) { 918 return (CFGA_ATTR_INVAL); 919 } 920 921 if ((ret = all_fields[fld].set_filter(&post_filtp->ldata, val)) 922 == CFGA_OK) { 923 post_filtp->match_type_p[fld] = match_type; 924 } 925 926 return (ret); 927 928 } 929 930 static char inval_optarg[] = 931 "%s: invalid value \"%s\" for %s suboption.\n"; 932 933 /* 934 * Parses the "select" string and fills in the post_filter structure 935 */ 936 static cfga_err_t 937 parse_select_opt( 938 const char *selectp, 939 post_filter_t *post_filtp, 940 match_type_t match_type) 941 { 942 parse_state_t state = CFGA_PSTATE_INIT; 943 char *cp = NULL, *optstr = NULL, *attr = NULL, *val = NULL; 944 int bal = 0; /* Tracks balancing */ 945 char chr; 946 cfga_err_t ret; 947 948 949 if (selectp == NULL || post_filtp == NULL) { 950 return (CFGA_ERROR); 951 } 952 953 optstr = config_calloc_check(1, strlen(selectp) + 1); 954 if (optstr == NULL) { 955 return (CFGA_LIB_ERROR); 956 } 957 958 (void) strcpy(optstr, selectp); 959 960 /* Init */ 961 ret = CFGA_ATTR_INVAL; 962 bal = 0; 963 cp = attr = optstr; 964 state = CFGA_PSTATE_INIT; 965 966 for (; *cp != '\0'; cp++) { 967 switch (state) { 968 case CFGA_PSTATE_INIT: 969 if (*cp != LEFT_PAREN) 970 break; 971 *cp = '\0'; 972 val = cp + 1; 973 bal = 1; 974 state = CFGA_PSTATE_ATTR_DONE; 975 break; 976 case CFGA_PSTATE_ATTR_DONE: 977 chr = *cp; 978 switch (chr) { 979 case LEFT_PAREN: 980 bal++; 981 break; 982 case RIGHT_PAREN: 983 bal--; 984 if (bal == 0) { 985 *cp = '\0'; 986 state = CFGA_PSTATE_VAL_DONE; 987 } 988 break; 989 } 990 break; 991 case CFGA_PSTATE_VAL_DONE: 992 if (*cp != ':') { 993 state = CFGA_PSTATE_ERR; 994 goto out; 995 } 996 997 *cp = '\0'; 998 if (set_attrval(attr, val, post_filtp, 999 match_type) != CFGA_OK) { 1000 state = CFGA_PSTATE_ERR; 1001 goto out; 1002 } 1003 state = CFGA_PSTATE_INIT; 1004 attr = cp + 1; 1005 break; 1006 default: 1007 state = CFGA_PSTATE_ERR; 1008 /* FALLTHROUGH */ 1009 case CFGA_PSTATE_ERR: 1010 goto out; 1011 } 1012 } 1013 1014 /*FALLTHRU*/ 1015 out: 1016 if (state == CFGA_PSTATE_VAL_DONE) { 1017 ret = set_attrval(attr, val, post_filtp, match_type); 1018 } else { 1019 ret = CFGA_ATTR_INVAL; 1020 } 1021 1022 if (ret != CFGA_OK) { 1023 (void) fprintf(stderr, gettext(inval_optarg), cmdname, 1024 selectp, list_options[LIST_SELECT]); 1025 } 1026 1027 S_FREE(optstr); 1028 return (ret); 1029 } 1030 1031 1032 1033 static cfga_err_t 1034 setup_filter( 1035 const char *selectp, 1036 const char *matchp, 1037 post_filter_t *post_filtp, 1038 char **prefilt_optpp) 1039 { 1040 cfga_err_t ret = CFGA_ERROR; 1041 match_type_t match_type = CFGA_MATCH_NOFILTER; 1042 int i; 1043 1044 static char match_needs_select[] = 1045 "%s: %s suboption can only be used with %s suboption.\n"; 1046 1047 1048 *prefilt_optpp = NULL; 1049 1050 /* 1051 * Initial: no filtering. 1052 * CFGA_MATCH_NOFILTER is NOT a valid user input 1053 */ 1054 for (i = 0; i < N_FIELDS; i++) { 1055 post_filtp->match_type_p[i] = CFGA_MATCH_NOFILTER; 1056 } 1057 1058 /* Determine type of match */ 1059 if (matchp == NULL && selectp == NULL) { 1060 /* No filtering */ 1061 return (CFGA_OK); 1062 } else if (matchp == NULL && selectp != NULL) { 1063 match_type = CFGA_DEFAULT_MATCH; 1064 } else if (matchp != NULL && selectp == NULL) { 1065 /* If only match specified, select criteria also needed */ 1066 (void) fprintf(stderr, gettext(match_needs_select), 1067 cmdname, list_options[LIST_MATCH], 1068 list_options[LIST_SELECT]); 1069 return (CFGA_ERROR); 1070 } else { 1071 for (i = 0; i < N_MATCH_TYPES; i++) { 1072 if (strcmp(matchp, match_type_array[i].str) == 0) { 1073 match_type = match_type_array[i].type; 1074 break; 1075 } 1076 } 1077 if (i >= N_MATCH_TYPES) { 1078 (void) fprintf(stderr, gettext(inval_optarg), cmdname, 1079 matchp, list_options[LIST_MATCH]); 1080 return (CFGA_ERROR); 1081 } 1082 } 1083 1084 if ((ret = parse_select_opt(selectp, post_filtp, match_type)) 1085 != CFGA_OK) { 1086 return (ret); 1087 } 1088 1089 /* Handle pre-filtering. */ 1090 if ((ret = setup_prefilter(post_filtp, prefilt_optpp)) != CFGA_OK) { 1091 /* Cleanup */ 1092 for (i = 0; i < N_FIELDS; i++) { 1093 post_filtp->match_type_p[i] = CFGA_MATCH_NOFILTER; 1094 } 1095 return (ret); 1096 } 1097 1098 1099 return (CFGA_OK); 1100 } 1101 1102 /* 1103 * compare_ap_id - compare two ap_id's 1104 * 1105 * For partial matches, argument order is significant. The filtering criterion 1106 * should be the first argument. 1107 */ 1108 1109 static int 1110 compare_ap_id( 1111 cfga_list_data_t *p1, 1112 cfga_list_data_t *p2, 1113 match_type_t match_type) 1114 { 1115 1116 switch (match_type) { 1117 case CFGA_MATCH_NOFILTER: 1118 return (0); /* No filtering. all pass */ 1119 case CFGA_MATCH_PARTIAL: 1120 return (strncmp(p1->ap_log_id, p2->ap_log_id, 1121 strlen(p1->ap_log_id))); 1122 case CFGA_MATCH_EXACT: 1123 return (strcmp(p1->ap_log_id, p2->ap_log_id)); 1124 case CFGA_MATCH_ORDER: 1125 default: 1126 return (config_ap_id_cmp(p1->ap_log_id, p2->ap_log_id)); 1127 } 1128 } 1129 1130 /* 1131 * print_log_id - print logical ap_id 1132 */ 1133 static void 1134 print_log_id( 1135 cfga_list_data_t *p, 1136 int width, 1137 char *lp) 1138 { 1139 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_log_id), 1140 p->ap_log_id); 1141 } 1142 1143 /* 1144 * set_log_flt - Setup filter for logical ap_id 1145 */ 1146 static cfga_err_t 1147 set_log_flt( 1148 cfga_list_data_t *p, 1149 const char *val) 1150 { 1151 if (strlen(val) > sizeof (p->ap_log_id) - 1) 1152 return (CFGA_ATTR_INVAL); 1153 1154 (void) strcpy(p->ap_log_id, val); 1155 1156 return (CFGA_OK); 1157 } 1158 1159 /* 1160 * set_type_flt - Setup filter for type field 1161 */ 1162 1163 static cfga_err_t 1164 set_type_flt( 1165 cfga_list_data_t *p, 1166 const char *val) 1167 { 1168 if (strlen(val) > sizeof (p->ap_type) - 1) 1169 return (CFGA_ATTR_INVAL); 1170 1171 (void) strcpy(p->ap_type, val); 1172 1173 return (CFGA_OK); 1174 } 1175 1176 /* 1177 * set_class_flt - Setup filter for class field 1178 */ 1179 static cfga_err_t 1180 set_class_flt( 1181 cfga_list_data_t *p, 1182 const char *val) 1183 { 1184 if (strlen(val) > sizeof (p->ap_class) - 1) 1185 return (CFGA_ATTR_INVAL); 1186 1187 (void) strcpy(p->ap_class, val); 1188 1189 return (CFGA_OK); 1190 } 1191 1192 1193 /* 1194 * compare_r_state - compare receptacle state of two ap_id's 1195 */ 1196 static int 1197 compare_r_state( 1198 cfga_list_data_t *p1, 1199 cfga_list_data_t *p2, 1200 match_type_t match_type) 1201 { 1202 switch (match_type) { 1203 case CFGA_MATCH_NOFILTER: /* no filtering. pass all */ 1204 return (0); 1205 case CFGA_MATCH_ORDER: 1206 default: 1207 return (p1->ap_r_state - p2->ap_r_state); 1208 } 1209 } 1210 1211 /* 1212 * compare_o_state - compare occupant state of two ap_id's 1213 */ 1214 static int 1215 compare_o_state( 1216 cfga_list_data_t *p1, 1217 cfga_list_data_t *p2, 1218 match_type_t match_type) 1219 { 1220 switch (match_type) { 1221 case CFGA_MATCH_NOFILTER: /* no filtering. all pass */ 1222 return (0); 1223 case CFGA_MATCH_ORDER: 1224 default: 1225 return (p1->ap_o_state - p2->ap_o_state); 1226 } 1227 } 1228 1229 /* 1230 * compare_busy - compare busy field of two ap_id's 1231 */ 1232 static int 1233 compare_busy( 1234 cfga_list_data_t *p1, 1235 cfga_list_data_t *p2, 1236 match_type_t match_type) 1237 { 1238 1239 switch (match_type) { 1240 case CFGA_MATCH_NOFILTER: /* no filtering. all pass */ 1241 return (0); 1242 case CFGA_MATCH_ORDER: 1243 default: 1244 return (p1->ap_busy - p2->ap_busy); 1245 } 1246 } 1247 1248 /* 1249 * print_r_state - print receptacle state 1250 */ 1251 static void 1252 print_r_state( 1253 cfga_list_data_t *p, 1254 int width, 1255 char *lp) 1256 { 1257 char *cp; 1258 1259 switch (p->ap_r_state) { 1260 case CFGA_STAT_EMPTY: 1261 cp = "empty"; 1262 break; 1263 case CFGA_STAT_CONNECTED: 1264 cp = "connected"; 1265 break; 1266 case CFGA_STAT_DISCONNECTED: 1267 cp = "disconnected"; 1268 break; 1269 default: 1270 cp = "???"; 1271 break; 1272 } 1273 (void) sprintf(lp, "%-*s", width, cp); 1274 } 1275 1276 /* 1277 * print_o_state - print occupant state 1278 */ 1279 static void 1280 print_o_state( 1281 cfga_list_data_t *p, 1282 int width, 1283 char *lp) 1284 { 1285 char *cp; 1286 1287 switch (p->ap_o_state) { 1288 case CFGA_STAT_UNCONFIGURED: 1289 cp = "unconfigured"; 1290 break; 1291 case CFGA_STAT_CONFIGURED: 1292 cp = "configured"; 1293 break; 1294 default: 1295 cp = "???"; 1296 break; 1297 } 1298 (void) sprintf(lp, "%-*s", width, cp); 1299 } 1300 1301 /* 1302 * compare_cond - compare condition field of two ap_id's 1303 */ 1304 static int 1305 compare_cond( 1306 cfga_list_data_t *p1, 1307 cfga_list_data_t *p2, 1308 match_type_t match_type) 1309 { 1310 1311 switch (match_type) { 1312 case CFGA_MATCH_NOFILTER: 1313 return (0); 1314 case CFGA_MATCH_ORDER: 1315 default: 1316 return (p1->ap_cond - p2->ap_cond); 1317 } 1318 } 1319 1320 /* 1321 * print_cond - print attachment point condition 1322 */ 1323 static void 1324 print_cond( 1325 cfga_list_data_t *p, 1326 int width, 1327 char *lp) 1328 { 1329 char *cp; 1330 1331 switch (p->ap_cond) { 1332 case CFGA_COND_UNKNOWN: 1333 cp = "unknown"; 1334 break; 1335 case CFGA_COND_UNUSABLE: 1336 cp = "unusable"; 1337 break; 1338 case CFGA_COND_FAILING: 1339 cp = "failing"; 1340 break; 1341 case CFGA_COND_FAILED: 1342 cp = "failed"; 1343 break; 1344 case CFGA_COND_OK: 1345 cp = "ok"; 1346 break; 1347 default: 1348 cp = "???"; 1349 break; 1350 } 1351 (void) sprintf(lp, "%-*s", width, cp); 1352 } 1353 1354 /* 1355 * compare_time - compare time field of two ap_id's 1356 */ 1357 static int 1358 compare_time( 1359 cfga_list_data_t *p1, 1360 cfga_list_data_t *p2, 1361 match_type_t match_type) 1362 { 1363 switch (match_type) { 1364 case CFGA_MATCH_NOFILTER: 1365 return (0); 1366 case CFGA_MATCH_ORDER: 1367 default: 1368 return (p1->ap_status_time - p2->ap_status_time); 1369 } 1370 } 1371 1372 1373 /* 1374 * print_time - print time from cfga_list_data. 1375 * Time print based on ls(1). 1376 */ 1377 static void 1378 print_time( 1379 cfga_list_data_t *p, 1380 int width, 1381 char *lp) 1382 { 1383 static time_t year, now; 1384 time_t stime; 1385 char time_buf[50]; /* array to hold day and time */ 1386 1387 if (year == 0) { 1388 now = time((long *)NULL); 1389 year = now - 6L*30L*24L*60L*60L; /* 6 months ago */ 1390 now = now + 60; 1391 } 1392 stime = p->ap_status_time; 1393 if (stime == (time_t)-1) { 1394 (void) sprintf(lp, "%-*s", width, gettext("unavailable")); 1395 return; 1396 } 1397 1398 if ((stime < year) || (stime > now)) { 1399 (void) strftime(time_buf, sizeof (time_buf), 1400 dcgettext(NULL, FORMAT1, LC_TIME), localtime(&stime)); 1401 } else { 1402 (void) strftime(time_buf, sizeof (time_buf), 1403 dcgettext(NULL, FORMAT2, LC_TIME), localtime(&stime)); 1404 } 1405 (void) sprintf(lp, "%-*s", width, time_buf); 1406 } 1407 1408 /* 1409 * print_time_p - print time from cfga_list_data. 1410 */ 1411 static void 1412 print_time_p( 1413 cfga_list_data_t *p, 1414 int width, 1415 char *lp) 1416 { 1417 struct tm *tp; 1418 char tstr[TIME_P_WIDTH+1]; 1419 1420 tp = localtime(&p->ap_status_time); 1421 (void) sprintf(tstr, "%04d%02d%02d%02d%02d%02d", tp->tm_year + 1900, 1422 tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec); 1423 (void) sprintf(lp, "%-*s", width, tstr); 1424 } 1425 1426 /* 1427 * compare_info - compare info from two cfga_list_data structs 1428 */ 1429 static int 1430 compare_info( 1431 cfga_list_data_t *p1, 1432 cfga_list_data_t *p2, 1433 match_type_t match_type) 1434 { 1435 switch (match_type) { 1436 case CFGA_MATCH_NOFILTER: 1437 return (0); 1438 case CFGA_MATCH_ORDER: 1439 default: 1440 return (strncmp(p1->ap_info, p2->ap_info, 1441 sizeof (p2->ap_info))); 1442 } 1443 } 1444 1445 /* 1446 * print_info - print info from cfga_list_data struct 1447 */ 1448 static void 1449 print_info( 1450 cfga_list_data_t *p, 1451 int width, 1452 char *lp) 1453 { 1454 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_info), p->ap_info); 1455 } 1456 1457 /* 1458 * compare_type - compare type from two cfga_list_data structs 1459 * 1460 * For partial matches, argument order is significant. The filtering criterion 1461 * should be the first argument. 1462 */ 1463 static int 1464 compare_type( 1465 cfga_list_data_t *p1, 1466 cfga_list_data_t *p2, 1467 match_type_t match_type) 1468 { 1469 switch (match_type) { 1470 case CFGA_MATCH_NOFILTER: 1471 return (0); 1472 case CFGA_MATCH_PARTIAL: 1473 return (strncmp(p1->ap_type, p2->ap_type, strlen(p1->ap_type))); 1474 case CFGA_MATCH_EXACT: 1475 case CFGA_MATCH_ORDER: 1476 default: 1477 return (strncmp(p1->ap_type, p2->ap_type, 1478 sizeof (p2->ap_type))); 1479 } 1480 } 1481 1482 /* 1483 * print_type - print type from cfga_list_data struct 1484 */ 1485 static void 1486 print_type( 1487 cfga_list_data_t *p, 1488 int width, 1489 char *lp) 1490 { 1491 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_type), p->ap_type); 1492 } 1493 1494 1495 /* 1496 * compare_class - compare class from two cfga_list_data structs 1497 * 1498 * For partial matches, argument order is significant. The filtering criterion 1499 * should be the first argument. 1500 */ 1501 static int 1502 compare_class( 1503 cfga_list_data_t *p1, 1504 cfga_list_data_t *p2, 1505 match_type_t match_type) 1506 { 1507 1508 switch (match_type) { 1509 case CFGA_MATCH_NOFILTER: 1510 return (0); 1511 case CFGA_MATCH_PARTIAL: 1512 return (strncmp(p1->ap_class, p2->ap_class, 1513 strlen(p1->ap_class))); 1514 case CFGA_MATCH_EXACT: 1515 case CFGA_MATCH_ORDER: 1516 default: 1517 return (strncmp(p1->ap_class, p2->ap_class, 1518 sizeof (p2->ap_class))); 1519 } 1520 } 1521 1522 /* 1523 * print_class - print class from cfga_list_data struct 1524 */ 1525 static void 1526 print_class( 1527 cfga_list_data_t *p, 1528 int width, 1529 char *lp) 1530 { 1531 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_class), p->ap_class); 1532 } 1533 /* 1534 * print_busy - print busy from cfga_list_data struct 1535 */ 1536 /* ARGSUSED */ 1537 static void 1538 print_busy( 1539 cfga_list_data_t *p, 1540 int width, 1541 char *lp) 1542 { 1543 if (p->ap_busy) 1544 (void) sprintf(lp, "%-*.*s", width, width, "y"); 1545 else 1546 (void) sprintf(lp, "%-*.*s", width, width, "n"); 1547 } 1548 1549 /* 1550 * print_phys_id - print physical ap_id 1551 */ 1552 static void 1553 print_phys_id( 1554 cfga_list_data_t *p, 1555 int width, 1556 char *lp) 1557 { 1558 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_phys_id), 1559 p->ap_phys_id); 1560 } 1561 1562 1563 /* 1564 * find_field - find the named field 1565 */ 1566 static struct field_info * 1567 find_field(char *fname) 1568 { 1569 struct field_info *fldp; 1570 1571 for (fldp = all_fields; fldp < &all_fields[N_FIELDS]; fldp++) 1572 if (strcmp(fname, fldp->name) == 0) 1573 return (fldp); 1574 return (NULL); 1575 } 1576 1577 /* 1578 * usage_field - print field usage 1579 */ 1580 static void 1581 usage_field() 1582 { 1583 struct field_info *fldp = NULL; 1584 const char *sep; 1585 static char field_list[] = "%s: print or sort fields must be one of:"; 1586 1587 (void) fprintf(stderr, gettext(field_list), cmdname); 1588 sep = ""; 1589 1590 for (fldp = all_fields; fldp < &all_fields[N_FIELDS]; fldp++) { 1591 (void) fprintf(stderr, "%s %s", sep, fldp->name); 1592 sep = ","; 1593 } 1594 (void) fprintf(stderr, "\n"); 1595 } 1596 1597 /* 1598 * compare_null - null comparison routine 1599 */ 1600 /*ARGSUSED*/ 1601 static int 1602 compare_null( 1603 cfga_list_data_t *p1, 1604 cfga_list_data_t *p2, 1605 match_type_t match_type) 1606 { 1607 return (0); 1608 } 1609 1610 /* 1611 * print_null - print out a field of spaces 1612 */ 1613 /*ARGSUSED*/ 1614 static void 1615 print_null( 1616 cfga_list_data_t *p, 1617 int width, 1618 char *lp) 1619 { 1620 (void) sprintf(lp, "%-*s", width, ""); 1621 } 1622 1623 /* 1624 * do_config_list - directs the output of the listing functions 1625 */ 1626 static int 1627 do_config_list( 1628 int l_argc, 1629 char *l_argv[], 1630 cfga_list_data_t *statlist, 1631 int nlist, 1632 char *sortp, 1633 char *colsp, 1634 char *cols2p, 1635 int noheadings, 1636 char *delimp, 1637 post_filter_t *post_filtp, 1638 int dyn_exp) 1639 { 1640 int nprcols = 0, ncols2 = 0; 1641 struct print_col *prnt_list = NULL; 1642 int napids_to_list = 0; 1643 FILE *fp = NULL; 1644 int f_err; 1645 cfga_list_data_t **sel_boards = NULL; 1646 int nsel = 0; 1647 int i, j; 1648 cfga_err_t ret; 1649 1650 ap_arg_t *arg_array = NULL; 1651 ap_out_t *out_array = NULL; 1652 1653 1654 sort_list = NULL; 1655 f_err = 0; 1656 fp = stdout; 1657 nsort_list = count_fields(sortp, FDELIM); 1658 if (nsort_list != 0) { 1659 sort_list = config_calloc_check(nsort_list, 1660 sizeof (*sort_list)); 1661 if (sort_list == NULL) { 1662 ret = CFGA_LIB_ERROR; 1663 goto out; 1664 } 1665 f_err |= process_sort_fields(nsort_list, sort_list, sortp); 1666 } else 1667 sort_list = NULL; 1668 1669 nprcols = count_fields(colsp, FDELIM); 1670 if ((ncols2 = count_fields(cols2p, FDELIM)) > nprcols) 1671 nprcols = ncols2; 1672 if (nprcols != 0) { 1673 prnt_list = config_calloc_check(nprcols, sizeof (*prnt_list)); 1674 if (prnt_list == NULL) { 1675 ret = CFGA_LIB_ERROR; 1676 goto out; 1677 } 1678 f_err |= process_fields(nprcols, prnt_list, 0, colsp); 1679 if (ncols2 != 0) 1680 f_err |= process_fields(nprcols, prnt_list, 1, cols2p); 1681 } else 1682 prnt_list = NULL; 1683 1684 if (f_err) { 1685 usage_field(); 1686 ret = CFGA_ERROR; 1687 goto out; 1688 } 1689 1690 /* Create an array of all user args (if any) */ 1691 if (l_argc != 0) { 1692 int i, j; 1693 1694 napids_to_list = 0; 1695 1696 for (i = 0; i < l_argc; i++) { 1697 napids_to_list += count_fields(l_argv[i], ARG_DELIM); 1698 } 1699 1700 arg_array = config_calloc_check(napids_to_list, 1701 sizeof (*arg_array)); 1702 if (arg_array == NULL) { 1703 ret = CFGA_LIB_ERROR; 1704 goto out; 1705 } 1706 1707 for (i = 0, j = 0; i < l_argc; i++) { 1708 int n; 1709 1710 n = count_fields(l_argv[i], ARG_DELIM); 1711 if (n == 0) { 1712 continue; 1713 } else if (n == 1) { 1714 arg_array[j].arg = l_argv[i]; 1715 arg_array[j].resp = 0; 1716 j++; 1717 } else { 1718 char *cp, *ncp; 1719 1720 cp = l_argv[i]; 1721 for (;;) { 1722 arg_array[j].arg = cp; 1723 arg_array[j].resp = 0; 1724 j++; 1725 ncp = strchr(cp, ARG_DELIM); 1726 if (ncp == NULL) 1727 break; 1728 *ncp = '\0'; 1729 cp = ncp + 1; 1730 } 1731 } 1732 } 1733 assert(j == napids_to_list); 1734 } else { 1735 napids_to_list = 0; 1736 arg_array = NULL; 1737 } 1738 1739 assert(nlist != 0); 1740 1741 out_array = config_calloc_check(nlist, sizeof (*out_array)); 1742 if (out_array == NULL) { 1743 ret = CFGA_LIB_ERROR; 1744 goto out; 1745 } 1746 1747 1748 /* create a list of output stat data */ 1749 for (i = 0; i < nlist; i++) { 1750 out_array[i].ldatap = &statlist[i]; 1751 out_array[i].req = 0; 1752 } 1753 1754 /* 1755 * Mark all user input which got atleast 1 stat data in response 1756 */ 1757 for (i = 0; i < napids_to_list; i++) { 1758 arg_got_resp(&arg_array[i], out_array, nlist, dyn_exp); 1759 } 1760 1761 /* 1762 * Process output data 1763 */ 1764 nsel = 0; 1765 for (i = 0; i < nlist; i++) { 1766 /* 1767 * Mark all the stats which were actually requested by user 1768 */ 1769 out_was_req(&out_array[i], arg_array, napids_to_list, 0); 1770 if (out_array[i].req == 0 && dyn_exp) { 1771 /* 1772 * Try again without the dynamic component for the 1773 * if dynamic expansion was requested. 1774 */ 1775 out_was_req(&out_array[i], arg_array, 1776 napids_to_list, 1); 1777 } 1778 1779 /* 1780 * post filter data which was actually requested 1781 */ 1782 if (out_array[i].req == 1) { 1783 do_post_filter(&out_array[i], post_filtp, &nsel); 1784 } 1785 } 1786 1787 sel_boards = config_calloc_check(nsel, sizeof (*sel_boards)); 1788 if (sel_boards == NULL) { 1789 ret = CFGA_LIB_ERROR; 1790 goto out; 1791 } 1792 1793 for (i = 0, j = 0; i < nlist; i++) { 1794 if (out_array[i].req == 1) { 1795 sel_boards[j] = out_array[i].ldatap; 1796 j++; 1797 } 1798 } 1799 1800 assert(j == nsel); 1801 1802 /* 1803 * Print headings even if no list entries - Bug or feature ? 1804 */ 1805 if (!noheadings && prnt_list != NULL) { 1806 if ((ret = print_fields(nprcols, prnt_list, 1, 0, 1807 delimp, NULL, fp)) != CFGA_OK) { 1808 goto out; 1809 } 1810 if (ncols2 != 0) { 1811 if ((ret = print_fields(nprcols, prnt_list, 1, 1812 1, delimp, NULL, fp)) != CFGA_OK) { 1813 goto out; 1814 } 1815 } 1816 } 1817 1818 if (nsel != 0) { 1819 if (sort_list != NULL && nsel > 1) { 1820 qsort(sel_boards, nsel, sizeof (sel_boards[0]), 1821 ldata_compare); 1822 } 1823 1824 if (prnt_list != NULL) { 1825 for (i = 0; i < nsel; i++) { 1826 if ((ret = print_fields(nprcols, 1827 prnt_list, 0, 0, delimp, sel_boards[i], fp)) 1828 != CFGA_OK) 1829 goto out; 1830 if (ncols2 != 0) { 1831 if ((ret = print_fields( 1832 nprcols, prnt_list, 0, 1, delimp, 1833 sel_boards[i], fp)) != CFGA_OK) 1834 goto out; 1835 } 1836 } 1837 } 1838 } 1839 /* 1840 * Go thru the argument list and notify user about args 1841 * which did not have a match 1842 */ 1843 report_no_response(arg_array, napids_to_list); 1844 ret = CFGA_OK; 1845 /*FALLTHRU*/ 1846 out: 1847 S_FREE(sel_boards); 1848 S_FREE(arg_array); 1849 S_FREE(out_array); 1850 1851 S_FREE(sort_list); 1852 S_FREE(prnt_list); 1853 1854 return (ret); 1855 } 1856 1857 1858 /* 1859 * Mark all user inputs which got a response 1860 */ 1861 static void 1862 arg_got_resp(ap_arg_t *inp, ap_out_t *out_array, int nouts, int dyn_exp) 1863 { 1864 int i; 1865 cfga_ap_types_t type; 1866 1867 1868 if (nouts == 0) { 1869 return; 1870 } 1871 1872 type = find_arg_type(inp->arg); 1873 1874 /* 1875 * Go through list of output stats and check if argument 1876 * produced that output 1877 */ 1878 for (i = 0; i < nouts; i++) { 1879 if (type == PHYSICAL_AP_ID) { 1880 if (config_ap_id_cmp(out_array[i].ldatap->ap_phys_id, 1881 inp->arg) == 0) { 1882 break; 1883 } 1884 } else if (type == LOGICAL_AP_ID) { 1885 if (config_ap_id_cmp(out_array[i].ldatap->ap_log_id, 1886 inp->arg) == 0) { 1887 break; 1888 } 1889 } else if (type == AP_TYPE) { 1890 /* 1891 * An AP_TYPE argument cannot generate dynamic 1892 * attachment point stats unless dynamic expansion was 1893 * requested by user. 1894 */ 1895 if (!dyn_exp && get_dyn(out_array[i].ldatap->ap_log_id) 1896 != NULL) { 1897 continue; 1898 } 1899 1900 if (strncmp(out_array[i].ldatap->ap_log_id, inp->arg, 1901 strlen(inp->arg)) == 0) { 1902 break; 1903 } 1904 } else { 1905 return; 1906 } 1907 } 1908 1909 if (i < nouts) { 1910 inp->resp = 1; 1911 } 1912 } 1913 1914 /* Mark all stat data which were requested by user */ 1915 static void 1916 out_was_req(ap_out_t *outp, ap_arg_t *in_array, int nargs, int no_dyn) 1917 { 1918 int i; 1919 cfga_ap_types_t type = UNKNOWN_AP; 1920 char physid[MAXPATHLEN], logid[MAXPATHLEN]; 1921 1922 1923 /* If no user args, all output is acceptable */ 1924 if (nargs == 0) { 1925 outp->req = 1; 1926 return; 1927 } 1928 1929 1930 (void) snprintf(physid, sizeof (physid), "%s", 1931 outp->ldatap->ap_phys_id); 1932 (void) snprintf(logid, sizeof (logid), "%s", outp->ldatap->ap_log_id); 1933 1934 /* 1935 * Do comparison with or without dynamic component as requested by 1936 * user. 1937 */ 1938 if (no_dyn) { 1939 /* Remove the dynamic component */ 1940 remove_dyn(physid); 1941 remove_dyn(logid); 1942 } 1943 1944 for (i = 0; i < nargs; i++) { 1945 type = find_arg_type(in_array[i].arg); 1946 if (type == PHYSICAL_AP_ID) { 1947 1948 if (config_ap_id_cmp(in_array[i].arg, physid) == 0) { 1949 break; 1950 } 1951 } else if (type == LOGICAL_AP_ID) { 1952 1953 if (config_ap_id_cmp(in_array[i].arg, logid) == 0) { 1954 break; 1955 } 1956 } else if (type == AP_TYPE) { 1957 /* 1958 * Aptypes cannot generate dynamic attachment 1959 * points unless dynamic expansion is specified. 1960 * in which case this routine would be called a 1961 * 2nd time with the no_dyn flag set and there 1962 * would be no dynamic ap_ids. 1963 */ 1964 if (get_dyn(logid) != NULL) { 1965 continue; 1966 } 1967 1968 if (strncmp(in_array[i].arg, logid, 1969 strlen(in_array[i].arg)) == 0) { 1970 break; 1971 } 1972 } else { 1973 continue; 1974 } 1975 } 1976 1977 if (i < nargs) { 1978 /* Ok, this output was requested */ 1979 outp->req = 1; 1980 } 1981 1982 } 1983 1984 static void 1985 do_post_filter(ap_out_t *outp, post_filter_t *post_filtp, int *nselp) 1986 { 1987 int i; 1988 1989 if (outp->req != 1) { 1990 return; 1991 } 1992 1993 /* 1994 * For fields without filtering (CFGA_MATCH_NOFILTER), 1995 * compare always returns 0 (success) 1996 */ 1997 for (i = 0; i < N_FIELDS; i++) { 1998 /* 1999 * Note: Order is important for partial match (via strncmp). 2000 * The first argument for compare must be the filter. 2001 */ 2002 if (all_fields[i].compare(&post_filtp->ldata, outp->ldatap, 2003 post_filtp->match_type_p[i])) { 2004 outp->req = 0; /* Blocked by filter */ 2005 return; 2006 } 2007 } 2008 2009 /* 2010 * Passed through filter 2011 */ 2012 (*nselp)++; 2013 } 2014 2015 static void 2016 report_no_response(ap_arg_t *arg_array, int nargs) 2017 { 2018 int i; 2019 2020 if (nargs == 0) { 2021 return; 2022 } 2023 2024 2025 /* 2026 * nop if no user arguments 2027 */ 2028 for (i = 0; i < nargs; i++) { 2029 if (arg_array[i].resp == 0) { 2030 (void) fprintf(stderr, 2031 gettext("%s: No matching library found\n"), 2032 arg_array[i].arg); 2033 } 2034 } 2035 } 2036 2037 /* 2038 * ldata_compare - compare two attachment point list data structures. 2039 */ 2040 static int 2041 ldata_compare( 2042 const void *vb1, 2043 const void *vb2) 2044 { 2045 int i; 2046 int res = -1; 2047 cfga_list_data_t *b1, *b2; 2048 2049 2050 b1 = *(cfga_list_data_t **)vb1; 2051 b2 = *(cfga_list_data_t **)vb2; 2052 2053 for (i = 0; i < nsort_list; i++) { 2054 res = (*(sort_list[i].fld->compare))(b1, b2, CFGA_MATCH_ORDER); 2055 if (res != 0) { 2056 if (sort_list[i].reverse) 2057 res = -res; 2058 break; 2059 } 2060 } 2061 2062 return (res); 2063 } 2064 2065 /* 2066 * count_fields - Count the number of fields, using supplied delimiter. 2067 */ 2068 static int 2069 count_fields(char *fspec, char delim) 2070 { 2071 char *cp = NULL; 2072 int n; 2073 2074 if (fspec == 0 || *fspec == '\0') 2075 return (0); 2076 n = 1; 2077 for (cp = fspec; *cp != '\0'; cp++) 2078 if (*cp == delim) 2079 n++; 2080 return (n); 2081 } 2082 2083 /* 2084 * get_field 2085 * This function is not a re-implementation of strtok(). 2086 * There can be null fields - strtok() eats spans of delimiters. 2087 */ 2088 static char * 2089 get_field(char **fspp) 2090 { 2091 char *cp = NULL, *fld; 2092 2093 fld = *fspp; 2094 2095 if (fld != NULL && *fld == '\0') 2096 fld = NULL; 2097 2098 if (fld != NULL) { 2099 cp = strchr(*fspp, FDELIM); 2100 if (cp == NULL) { 2101 *fspp = NULL; 2102 } else { 2103 *cp = '\0'; 2104 *fspp = cp + 1; 2105 if (*fld == '\0') 2106 fld = NULL; 2107 } 2108 } 2109 return (fld); 2110 } 2111 2112 /* 2113 * process_fields - 2114 */ 2115 static int 2116 process_fields( 2117 int ncol, 2118 struct print_col *list, 2119 int line2, 2120 char *fmt) 2121 { 2122 struct print_col *pp = NULL; 2123 struct field_info *fldp = NULL; 2124 char *fmtx; 2125 char *fldn; 2126 int err; 2127 2128 err = 0; 2129 fmtx = fmt; 2130 for (pp = list; pp < &list[ncol]; pp++) { 2131 fldn = get_field(&fmtx); 2132 fldp = &null_field; 2133 if (fldn != NULL) { 2134 struct field_info *tfldp; 2135 2136 tfldp = find_field(fldn); 2137 if (tfldp != NULL) { 2138 fldp = tfldp; 2139 } else { 2140 (void) fprintf(stderr, gettext(unk_field), 2141 cmdname, fldn); 2142 err = 1; 2143 } 2144 } 2145 if (line2) { 2146 pp->line2 = fldp; 2147 if (fldp->width > pp->width) 2148 pp->width = fldp->width; 2149 } else { 2150 pp->line1 = fldp; 2151 pp->width = fldp->width; 2152 } 2153 } 2154 return (err); 2155 } 2156 2157 /* 2158 * process_sort_fields - 2159 */ 2160 static int 2161 process_sort_fields( 2162 int nsort, 2163 struct sort_el *list, 2164 char *fmt) 2165 { 2166 int i; 2167 int rev; 2168 struct field_info *fldp = NULL; 2169 char *fmtx; 2170 char *fldn; 2171 int err; 2172 2173 err = 0; 2174 fmtx = fmt; 2175 for (i = 0; i < nsort; i++) { 2176 fldn = get_field(&fmtx); 2177 fldp = &null_field; 2178 rev = 0; 2179 if (fldn != NULL) { 2180 struct field_info *tfldp = NULL; 2181 2182 if (*fldn == '-') { 2183 rev = 1; 2184 fldn++; 2185 } 2186 tfldp = find_field(fldn); 2187 if (tfldp != NULL) { 2188 fldp = tfldp; 2189 } else { 2190 (void) fprintf(stderr, gettext(unk_field), 2191 cmdname, fldn); 2192 err = 1; 2193 } 2194 } 2195 list[i].reverse = rev; 2196 list[i].fld = fldp; 2197 } 2198 return (err); 2199 } 2200 2201 /* 2202 * print_fields - 2203 */ 2204 static cfga_err_t 2205 print_fields( 2206 int ncol, 2207 struct print_col *list, 2208 int heading, 2209 int line2, 2210 char *delim, 2211 cfga_list_data_t *bdp, 2212 FILE *fp) 2213 { 2214 char *del = NULL; 2215 struct print_col *pp = NULL; 2216 struct field_info *fldp = NULL; 2217 static char *outline, *end; 2218 char *lp; 2219 2220 if (outline == NULL) { 2221 int out_len, delim_len; 2222 2223 delim_len = strlen(delim); 2224 out_len = 0; 2225 for (pp = list; pp < &list[ncol]; pp++) { 2226 out_len += pp->width; 2227 out_len += delim_len; 2228 } 2229 out_len -= delim_len; 2230 outline = config_calloc_check(out_len + 1, 1); 2231 if (outline == NULL) { 2232 return (CFGA_LIB_ERROR); 2233 } 2234 end = &outline[out_len + 1]; 2235 } 2236 2237 lp = outline; 2238 del = ""; 2239 for (pp = list; pp < &list[ncol]; pp++) { 2240 fldp = line2 ? pp->line2 : pp->line1; 2241 (void) snprintf(lp, end - lp, "%s", del); 2242 lp += strlen(lp); 2243 if (heading) { 2244 (void) snprintf(lp, end - lp, "%-*s", 2245 fldp->width, fldp->heading); 2246 } else { 2247 (*fldp->printfn)(bdp, fldp->width, lp); 2248 } 2249 lp += strlen(lp); 2250 del = delim; 2251 } 2252 2253 /* 2254 * Trim trailing spaces 2255 */ 2256 while (--lp >= outline && *lp == ' ') 2257 *lp = '\0'; 2258 (void) fprintf(fp, "%s\n", outline); 2259 return (CFGA_OK); 2260 } 2261 2262 /* 2263 * config_calloc_check - perform allocation, check result and 2264 * set error indicator 2265 */ 2266 static void * 2267 config_calloc_check( 2268 size_t nelem, 2269 size_t elsize) 2270 { 2271 void *p; 2272 static char alloc_fail[] = 2273 "%s: memory allocation failed (%d*%d bytes)\n"; 2274 2275 2276 p = calloc(nelem, elsize); 2277 if (p == NULL) { 2278 (void) fprintf(stderr, gettext(alloc_fail), cmdname, 2279 nelem, elsize); 2280 } 2281 return (p); 2282 } 2283 2284 /* 2285 * find_arg_type - determine if an argument is an ap_id or an ap_type. 2286 */ 2287 static cfga_ap_types_t 2288 find_arg_type(const char *ap_id) 2289 { 2290 struct stat sbuf; 2291 cfga_ap_types_t type; 2292 char *mkr = NULL, *cp; 2293 int size_ap = 0, size_mkr = 0, digit = 0, i = 0; 2294 char path[MAXPATHLEN]; 2295 char apbuf[MAXPATHLEN]; 2296 size_t len; 2297 2298 2299 /* 2300 * sanity checks 2301 */ 2302 if (ap_id == NULL || *ap_id == '\0') { 2303 return (UNKNOWN_AP); 2304 } 2305 2306 /* 2307 * Mask the dynamic component if any 2308 */ 2309 if ((cp = GET_DYN(ap_id)) != NULL) { 2310 len = cp - ap_id; 2311 } else { 2312 len = strlen(ap_id); 2313 } 2314 2315 if (len >= sizeof (apbuf)) { 2316 return (UNKNOWN_AP); 2317 } 2318 2319 (void) strncpy(apbuf, ap_id, len); 2320 apbuf[len] = '\0'; 2321 2322 /* 2323 * If it starts with a slash and is stat-able 2324 * its a physical. 2325 */ 2326 if (*apbuf == '/' && stat(apbuf, &sbuf) == 0) { 2327 return (PHYSICAL_AP_ID); 2328 } 2329 2330 /* 2331 * Is this a symlink in CFGA_DEV_DIR ? 2332 */ 2333 (void) snprintf(path, sizeof (path), "%s/%s", CFGA_DEV_DIR, apbuf); 2334 2335 if (lstat(path, &sbuf) == 0 && S_ISLNK(sbuf.st_mode) && 2336 stat(path, &sbuf) == 0) { 2337 return (LOGICAL_AP_ID); 2338 } 2339 2340 /* 2341 * Check for ":" which is always present in an ap_id but not maybe 2342 * present or absent in an ap_type. 2343 * We need to check that the characters right before the : are digits 2344 * since an ap_id is of the form <name><instance>:<specific ap name> 2345 */ 2346 if ((mkr = strchr(apbuf, ':')) == NULL) { 2347 type = AP_TYPE; 2348 } else { 2349 size_ap = strlen(apbuf); 2350 size_mkr = strlen(mkr); 2351 mkr = apbuf; 2352 2353 digit = 0; 2354 for (i = size_ap - size_mkr - 1; i > 0; i--) { 2355 if ((int)isdigit(mkr[i])) { 2356 digit++; 2357 break; 2358 } 2359 } 2360 if (digit == 0) { 2361 type = AP_TYPE; 2362 } else { 2363 type = LOGICAL_AP_ID; 2364 } 2365 } 2366 2367 return (type); 2368 } 2369 2370 2371 static char * 2372 get_dyn(const char *ap_id) 2373 { 2374 if (ap_id == NULL) { 2375 return (NULL); 2376 } 2377 2378 return (strstr(ap_id, CFGA_DYN_SEP)); 2379 } 2380 2381 /* 2382 * removes the dynamic component 2383 */ 2384 static void 2385 remove_dyn(char *ap_id) 2386 { 2387 char *cp; 2388 2389 if (ap_id == NULL) { 2390 return; 2391 } 2392 2393 cp = strstr(ap_id, CFGA_DYN_SEP); 2394 if (cp != NULL) { 2395 *cp = '\0'; 2396 } 2397 } 2398 2399 2400 static char * 2401 s_strdup(char *str) 2402 { 2403 char *dup; 2404 2405 /* 2406 * sometimes NULL strings may be passed in (see DEF_COLS2). This 2407 * is not an error. 2408 */ 2409 if (str == NULL) { 2410 return (NULL); 2411 } 2412 2413 dup = strdup(str); 2414 if (dup == NULL) { 2415 (void) fprintf(stderr, 2416 "%s \"%s\"\n", gettext("Cannot copy string"), str); 2417 return (NULL); 2418 } 2419 2420 return (dup); 2421 } 2422