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