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 2009 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 = 0; 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, 422 plat_opts, &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 (estrp != NULL && *estrp != '\0') 608 cfgadm_error(CFGA_NOTSUPP, estrp); 609 if (exitcode != EXIT_OK) { 610 exit(exitcode); 611 /*NOTREACHED*/ 612 } 613 } else { 614 615 S_FREE(post_filtp); 616 cfgadm_error(ret, estrp); 617 } 618 break; 619 } 620 default: /* paranoia */ 621 abort(); 622 /*NOTREACHED*/ 623 } 624 625 if (ret == CFGA_NOTSUPP) { 626 return (EXIT_NOTSUPP); 627 } else if (ret != CFGA_OK) { 628 return (EXIT_OPFAILED); 629 } else { 630 return (EXIT_OK); 631 } 632 /*NOTREACHED*/ 633 } 634 635 /* 636 * usage - outputs the usage help message. 637 */ 638 static void 639 usage(void) 640 { 641 int i; 642 643 (void) fprintf(stderr, "%s\n", gettext("Usage:")); 644 for (i = 0; i < sizeof (usage_tab)/sizeof (usage_tab[0]); i++) { 645 (void) fprintf(stderr, gettext(usage_tab[i]), cmdname); 646 } 647 } 648 649 /* 650 * Emit an error message. 651 * As a side-effect the hardware specific error message is deallocated 652 * as described in config_admin(3X). 653 */ 654 static void 655 cfgadm_error(int errnum, char *estrp) 656 { 657 const char *ep; 658 659 ep = config_strerror(errnum); 660 if (ep == NULL) 661 ep = gettext("configuration administration unknown error"); 662 if (estrp != NULL && *estrp != '\0') { 663 (void) fprintf(stderr, "%s: %s: %s\n", cmdname, ep, estrp); 664 } else { 665 (void) fprintf(stderr, "%s: %s\n", cmdname, ep); 666 } 667 if (estrp != NULL) 668 free((void *)estrp); 669 if (errnum == CFGA_INVAL) 670 usage(); 671 } 672 673 /* 674 * confirm_interactive - prompt user for confirmation 675 */ 676 static int 677 confirm_interactive( 678 void *appdata_ptr, 679 const char *message) 680 { 681 static char yeschr[YESNO_STR_MAX + 2]; 682 static char nochr[YESNO_STR_MAX + 2]; 683 static int inited = 0; 684 int isyes; 685 686 #ifdef lint 687 appdata_ptr = appdata_ptr; 688 #endif /* lint */ 689 /* 690 * First time through initialisation. In the original 691 * version of this command this function is only called once, 692 * but this function is generalized for the future. 693 */ 694 if (!inited) { 695 (void) strncpy(yeschr, nl_langinfo(YESSTR), YESNO_STR_MAX + 1); 696 (void) strncpy(nochr, nl_langinfo(NOSTR), YESNO_STR_MAX + 1); 697 inited = 1; 698 } 699 700 do { 701 (void) fprintf(stderr, "%s (%s/%s)? ", message, yeschr, nochr); 702 isyes = yesno(yeschr, nochr); 703 } while (isyes == -1); 704 return (isyes); 705 } 706 707 /* 708 * If any text is input it must sub-string match either yes or no. 709 * Failure of this match is indicated by return of -1. 710 * If an empty line is input, this is taken as no. 711 */ 712 static int 713 yesno( 714 char *yesp, 715 char *nop) 716 { 717 int i, b; 718 char ans[YESNO_STR_MAX + 1]; 719 720 i = 0; 721 722 /*CONSTCOND*/ 723 while (1) { 724 b = getc(stdin); /* more explicit that rm.c version */ 725 if (b == '\n' || b == '\0' || b == EOF) { 726 if (i < YESNO_STR_MAX) /* bug fix to rm.c version */ 727 ans[i] = 0; 728 break; 729 } 730 if (i < YESNO_STR_MAX) 731 ans[i] = b; 732 i++; 733 } 734 if (i >= YESNO_STR_MAX) { 735 i = YESNO_STR_MAX; 736 ans[YESNO_STR_MAX] = 0; 737 } 738 /* changes to rm.c version follow */ 739 if (i == 0) 740 return (0); 741 if (strncmp(nop, ans, i) == 0) 742 return (0); 743 if (strncmp(yesp, ans, i) == 0) 744 return (1); 745 return (-1); 746 } 747 748 /*ARGSUSED*/ 749 static int 750 confirm_no( 751 void *appdata_ptr, 752 const char *message) 753 { 754 return (0); 755 } 756 757 /*ARGSUSED*/ 758 static int 759 confirm_yes( 760 void *appdata_ptr, 761 const char *message) 762 { 763 return (1); 764 } 765 766 /* 767 * Find base name of filename. 768 */ 769 static char * 770 basename( 771 char *cp) 772 { 773 char *sp; 774 775 if ((sp = strrchr(cp, '/')) != NULL) 776 return (sp + 1); 777 return (cp); 778 } 779 780 /*ARGSUSED*/ 781 static int 782 message_output( 783 void *appdata_ptr, 784 const char *message) 785 { 786 (void) fprintf(stderr, "%s", message); 787 return (CFGA_OK); 788 789 } 790 791 /* 792 * extract_list_suboptions - process list option string 793 */ 794 static int 795 extract_list_suboptions( 796 char *arg, 797 char **sortpp, 798 char **colspp, 799 char **cols2pp, 800 int *noheadingsp, 801 char **delimpp, 802 char **selectpp, 803 char **matchpp) 804 { 805 char *value = NULL; 806 int subopt = 0; 807 int err = 0; 808 809 while (*arg != '\0') { 810 static char need_value[] = 811 "%s: sub-option \"%s\" requires a value\n"; 812 static char no_value[] = 813 "%s: sub-option \"%s\" does not take a value\n"; 814 static char unk_subopt[] = 815 "%s: sub-option \"%s\" unknown\n"; 816 char **pptr; 817 818 subopt = getsubopt(&arg, list_options, &value); 819 switch (subopt) { 820 case LIST_SORT: 821 pptr = sortpp; 822 goto valcom; 823 case LIST_COLS: 824 pptr = colspp; 825 goto valcom; 826 case LIST_COLS2: 827 pptr = cols2pp; 828 goto valcom; 829 case LIST_SELECT: 830 pptr = selectpp; 831 goto valcom; 832 case LIST_MATCH: 833 pptr = matchpp; 834 goto valcom; 835 case LIST_DELIM: 836 pptr = delimpp; 837 valcom: 838 if (value == NULL) { 839 (void) fprintf(stderr, gettext(need_value), 840 cmdname, list_options[subopt]); 841 err = 1; 842 } else 843 *pptr = value; 844 break; 845 case LIST_NOHEADINGS: 846 if (value != NULL) { 847 (void) fprintf(stderr, gettext(no_value), 848 cmdname, list_options[subopt]); 849 err = 1; 850 } else 851 *noheadingsp = 1; 852 break; 853 default: 854 (void) fprintf(stderr, gettext(unk_subopt), 855 cmdname, value); 856 err = 1; 857 break; 858 } 859 } 860 return (err == 0); 861 } 862 863 static cfga_err_t 864 setup_prefilter(post_filter_t *post_filtp, char **prefilt_optpp) 865 { 866 size_t len; 867 const char *clopt = PREFILT_CLASS_STR; 868 int idx; 869 870 871 *prefilt_optpp = NULL; 872 873 /* Get the index for the "class" field */ 874 for (idx = 0; idx < N_FIELDS; idx++) { 875 if (strcmp(all_fields[idx].name, PREFILT_CLASS_STR) == 0) 876 break; 877 } 878 879 /* 880 * Currently pre-filter available only for class fld w/ EXACT match 881 */ 882 if (idx >= N_FIELDS || 883 post_filtp->match_type_p[idx] != CFGA_MATCH_EXACT) { 884 return (CFGA_OK); 885 } 886 887 len = strlen(clopt) + strlen(post_filtp->ldata.ap_class) + 1; 888 if ((*prefilt_optpp = config_calloc_check(1, len)) == NULL) { 889 return (CFGA_LIB_ERROR); 890 } 891 892 (void) strcpy(*prefilt_optpp, clopt); 893 (void) strcat(*prefilt_optpp, post_filtp->ldata.ap_class); 894 895 /* 896 * Since it is being pre-filtered, this attribute does not need 897 * post-filtering. 898 */ 899 post_filtp->match_type_p[idx] = CFGA_MATCH_NOFILTER; 900 if (all_fields[idx].set_filter != NULL) { 901 (void) all_fields[idx].set_filter(&post_filtp->ldata, ""); 902 } 903 904 return (CFGA_OK); 905 } 906 907 static cfga_err_t 908 set_attrval( 909 const char *attr, 910 const char *val, 911 post_filter_t *post_filtp, 912 match_type_t match_type) 913 { 914 int fld = 0; 915 cfga_err_t ret = CFGA_ERROR; 916 917 for (fld = 0; fld < N_FIELDS; fld++) { 918 if (strcmp(attr, all_fields[fld].name) == 0) 919 break; 920 } 921 922 /* Valid field or is the select option supported for this field */ 923 if (fld >= N_FIELDS || all_fields[fld].set_filter == NULL) { 924 return (CFGA_ATTR_INVAL); 925 } 926 927 if ((ret = all_fields[fld].set_filter(&post_filtp->ldata, val)) 928 == CFGA_OK) { 929 post_filtp->match_type_p[fld] = match_type; 930 } 931 932 return (ret); 933 934 } 935 936 static char inval_optarg[] = 937 "%s: invalid value \"%s\" for %s suboption.\n"; 938 939 /* 940 * Parses the "select" string and fills in the post_filter structure 941 */ 942 static cfga_err_t 943 parse_select_opt( 944 const char *selectp, 945 post_filter_t *post_filtp, 946 match_type_t match_type) 947 { 948 parse_state_t state = CFGA_PSTATE_INIT; 949 char *cp = NULL, *optstr = NULL, *attr = NULL, *val = NULL; 950 int bal = 0; /* Tracks balancing */ 951 char chr; 952 cfga_err_t ret; 953 954 955 if (selectp == NULL || post_filtp == NULL) { 956 return (CFGA_ERROR); 957 } 958 959 optstr = config_calloc_check(1, strlen(selectp) + 1); 960 if (optstr == NULL) { 961 return (CFGA_LIB_ERROR); 962 } 963 964 (void) strcpy(optstr, selectp); 965 966 /* Init */ 967 ret = CFGA_ATTR_INVAL; 968 bal = 0; 969 cp = attr = optstr; 970 state = CFGA_PSTATE_INIT; 971 972 for (; *cp != '\0'; cp++) { 973 switch (state) { 974 case CFGA_PSTATE_INIT: 975 if (*cp != LEFT_PAREN) 976 break; 977 *cp = '\0'; 978 val = cp + 1; 979 bal = 1; 980 state = CFGA_PSTATE_ATTR_DONE; 981 break; 982 case CFGA_PSTATE_ATTR_DONE: 983 chr = *cp; 984 switch (chr) { 985 case LEFT_PAREN: 986 bal++; 987 break; 988 case RIGHT_PAREN: 989 bal--; 990 if (bal == 0) { 991 *cp = '\0'; 992 state = CFGA_PSTATE_VAL_DONE; 993 } 994 break; 995 } 996 break; 997 case CFGA_PSTATE_VAL_DONE: 998 if (*cp != ':') { 999 state = CFGA_PSTATE_ERR; 1000 goto out; 1001 } 1002 1003 *cp = '\0'; 1004 if (set_attrval(attr, val, post_filtp, 1005 match_type) != CFGA_OK) { 1006 state = CFGA_PSTATE_ERR; 1007 goto out; 1008 } 1009 state = CFGA_PSTATE_INIT; 1010 attr = cp + 1; 1011 break; 1012 default: 1013 state = CFGA_PSTATE_ERR; 1014 /* FALLTHROUGH */ 1015 case CFGA_PSTATE_ERR: 1016 goto out; 1017 } 1018 } 1019 1020 /*FALLTHRU*/ 1021 out: 1022 if (state == CFGA_PSTATE_VAL_DONE) { 1023 ret = set_attrval(attr, val, post_filtp, match_type); 1024 } else { 1025 ret = CFGA_ATTR_INVAL; 1026 } 1027 1028 if (ret != CFGA_OK) { 1029 (void) fprintf(stderr, gettext(inval_optarg), cmdname, 1030 selectp, list_options[LIST_SELECT]); 1031 } 1032 1033 S_FREE(optstr); 1034 return (ret); 1035 } 1036 1037 1038 1039 static cfga_err_t 1040 setup_filter( 1041 const char *selectp, 1042 const char *matchp, 1043 post_filter_t *post_filtp, 1044 char **prefilt_optpp) 1045 { 1046 cfga_err_t ret = CFGA_ERROR; 1047 match_type_t match_type = CFGA_MATCH_NOFILTER; 1048 int i; 1049 1050 static char match_needs_select[] = 1051 "%s: %s suboption can only be used with %s suboption.\n"; 1052 1053 1054 *prefilt_optpp = NULL; 1055 1056 /* 1057 * Initial: no filtering. 1058 * CFGA_MATCH_NOFILTER is NOT a valid user input 1059 */ 1060 for (i = 0; i < N_FIELDS; i++) { 1061 post_filtp->match_type_p[i] = CFGA_MATCH_NOFILTER; 1062 } 1063 1064 /* Determine type of match */ 1065 if (matchp == NULL && selectp == NULL) { 1066 /* No filtering */ 1067 return (CFGA_OK); 1068 } else if (matchp == NULL && selectp != NULL) { 1069 match_type = CFGA_DEFAULT_MATCH; 1070 } else if (matchp != NULL && selectp == NULL) { 1071 /* If only match specified, select criteria also needed */ 1072 (void) fprintf(stderr, gettext(match_needs_select), 1073 cmdname, list_options[LIST_MATCH], 1074 list_options[LIST_SELECT]); 1075 return (CFGA_ERROR); 1076 } else { 1077 for (i = 0; i < N_MATCH_TYPES; i++) { 1078 if (strcmp(matchp, match_type_array[i].str) == 0) { 1079 match_type = match_type_array[i].type; 1080 break; 1081 } 1082 } 1083 if (i >= N_MATCH_TYPES) { 1084 (void) fprintf(stderr, gettext(inval_optarg), cmdname, 1085 matchp, list_options[LIST_MATCH]); 1086 return (CFGA_ERROR); 1087 } 1088 } 1089 1090 if ((ret = parse_select_opt(selectp, post_filtp, match_type)) 1091 != CFGA_OK) { 1092 return (ret); 1093 } 1094 1095 /* Handle pre-filtering. */ 1096 if ((ret = setup_prefilter(post_filtp, prefilt_optpp)) != CFGA_OK) { 1097 /* Cleanup */ 1098 for (i = 0; i < N_FIELDS; i++) { 1099 post_filtp->match_type_p[i] = CFGA_MATCH_NOFILTER; 1100 } 1101 return (ret); 1102 } 1103 1104 1105 return (CFGA_OK); 1106 } 1107 1108 /* 1109 * compare_ap_id - compare two ap_id's 1110 * 1111 * For partial matches, argument order is significant. The filtering criterion 1112 * should be the first argument. 1113 */ 1114 1115 static int 1116 compare_ap_id( 1117 cfga_list_data_t *p1, 1118 cfga_list_data_t *p2, 1119 match_type_t match_type) 1120 { 1121 1122 switch (match_type) { 1123 case CFGA_MATCH_NOFILTER: 1124 return (0); /* No filtering. all pass */ 1125 case CFGA_MATCH_PARTIAL: 1126 return (strncmp(p1->ap_log_id, p2->ap_log_id, 1127 strlen(p1->ap_log_id))); 1128 case CFGA_MATCH_EXACT: 1129 return (strcmp(p1->ap_log_id, p2->ap_log_id)); 1130 case CFGA_MATCH_ORDER: 1131 default: 1132 return (config_ap_id_cmp(p1->ap_log_id, p2->ap_log_id)); 1133 } 1134 } 1135 1136 /* 1137 * print_log_id - print logical ap_id 1138 */ 1139 static void 1140 print_log_id( 1141 cfga_list_data_t *p, 1142 int width, 1143 char *lp) 1144 { 1145 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_log_id), 1146 p->ap_log_id); 1147 } 1148 1149 /* 1150 * set_log_flt - Setup filter for logical ap_id 1151 */ 1152 static cfga_err_t 1153 set_log_flt( 1154 cfga_list_data_t *p, 1155 const char *val) 1156 { 1157 if (strlen(val) > sizeof (p->ap_log_id) - 1) 1158 return (CFGA_ATTR_INVAL); 1159 1160 (void) strcpy(p->ap_log_id, val); 1161 1162 return (CFGA_OK); 1163 } 1164 1165 /* 1166 * set_type_flt - Setup filter for type field 1167 */ 1168 1169 static cfga_err_t 1170 set_type_flt( 1171 cfga_list_data_t *p, 1172 const char *val) 1173 { 1174 if (strlen(val) > sizeof (p->ap_type) - 1) 1175 return (CFGA_ATTR_INVAL); 1176 1177 (void) strcpy(p->ap_type, val); 1178 1179 return (CFGA_OK); 1180 } 1181 1182 /* 1183 * set_class_flt - Setup filter for class field 1184 */ 1185 static cfga_err_t 1186 set_class_flt( 1187 cfga_list_data_t *p, 1188 const char *val) 1189 { 1190 if (strlen(val) > sizeof (p->ap_class) - 1) 1191 return (CFGA_ATTR_INVAL); 1192 1193 (void) strcpy(p->ap_class, val); 1194 1195 return (CFGA_OK); 1196 } 1197 1198 1199 /* 1200 * compare_r_state - compare receptacle state of two ap_id's 1201 */ 1202 static int 1203 compare_r_state( 1204 cfga_list_data_t *p1, 1205 cfga_list_data_t *p2, 1206 match_type_t match_type) 1207 { 1208 switch (match_type) { 1209 case CFGA_MATCH_NOFILTER: /* no filtering. pass all */ 1210 return (0); 1211 case CFGA_MATCH_ORDER: 1212 default: 1213 return (p1->ap_r_state - p2->ap_r_state); 1214 } 1215 } 1216 1217 /* 1218 * compare_o_state - compare occupant state of two ap_id's 1219 */ 1220 static int 1221 compare_o_state( 1222 cfga_list_data_t *p1, 1223 cfga_list_data_t *p2, 1224 match_type_t match_type) 1225 { 1226 switch (match_type) { 1227 case CFGA_MATCH_NOFILTER: /* no filtering. all pass */ 1228 return (0); 1229 case CFGA_MATCH_ORDER: 1230 default: 1231 return (p1->ap_o_state - p2->ap_o_state); 1232 } 1233 } 1234 1235 /* 1236 * compare_busy - compare busy field of two ap_id's 1237 */ 1238 static int 1239 compare_busy( 1240 cfga_list_data_t *p1, 1241 cfga_list_data_t *p2, 1242 match_type_t match_type) 1243 { 1244 1245 switch (match_type) { 1246 case CFGA_MATCH_NOFILTER: /* no filtering. all pass */ 1247 return (0); 1248 case CFGA_MATCH_ORDER: 1249 default: 1250 return (p1->ap_busy - p2->ap_busy); 1251 } 1252 } 1253 1254 /* 1255 * print_r_state - print receptacle state 1256 */ 1257 static void 1258 print_r_state( 1259 cfga_list_data_t *p, 1260 int width, 1261 char *lp) 1262 { 1263 char *cp; 1264 1265 switch (p->ap_r_state) { 1266 case CFGA_STAT_EMPTY: 1267 cp = "empty"; 1268 break; 1269 case CFGA_STAT_CONNECTED: 1270 cp = "connected"; 1271 break; 1272 case CFGA_STAT_DISCONNECTED: 1273 cp = "disconnected"; 1274 break; 1275 default: 1276 cp = "???"; 1277 break; 1278 } 1279 (void) sprintf(lp, "%-*s", width, cp); 1280 } 1281 1282 /* 1283 * print_o_state - print occupant state 1284 */ 1285 static void 1286 print_o_state( 1287 cfga_list_data_t *p, 1288 int width, 1289 char *lp) 1290 { 1291 char *cp; 1292 1293 switch (p->ap_o_state) { 1294 case CFGA_STAT_UNCONFIGURED: 1295 cp = "unconfigured"; 1296 break; 1297 case CFGA_STAT_CONFIGURED: 1298 cp = "configured"; 1299 break; 1300 default: 1301 cp = "???"; 1302 break; 1303 } 1304 (void) sprintf(lp, "%-*s", width, cp); 1305 } 1306 1307 /* 1308 * compare_cond - compare condition field of two ap_id's 1309 */ 1310 static int 1311 compare_cond( 1312 cfga_list_data_t *p1, 1313 cfga_list_data_t *p2, 1314 match_type_t match_type) 1315 { 1316 1317 switch (match_type) { 1318 case CFGA_MATCH_NOFILTER: 1319 return (0); 1320 case CFGA_MATCH_ORDER: 1321 default: 1322 return (p1->ap_cond - p2->ap_cond); 1323 } 1324 } 1325 1326 /* 1327 * print_cond - print attachment point condition 1328 */ 1329 static void 1330 print_cond( 1331 cfga_list_data_t *p, 1332 int width, 1333 char *lp) 1334 { 1335 char *cp; 1336 1337 switch (p->ap_cond) { 1338 case CFGA_COND_UNKNOWN: 1339 cp = "unknown"; 1340 break; 1341 case CFGA_COND_UNUSABLE: 1342 cp = "unusable"; 1343 break; 1344 case CFGA_COND_FAILING: 1345 cp = "failing"; 1346 break; 1347 case CFGA_COND_FAILED: 1348 cp = "failed"; 1349 break; 1350 case CFGA_COND_OK: 1351 cp = "ok"; 1352 break; 1353 default: 1354 cp = "???"; 1355 break; 1356 } 1357 (void) sprintf(lp, "%-*s", width, cp); 1358 } 1359 1360 /* 1361 * compare_time - compare time field of two ap_id's 1362 */ 1363 static int 1364 compare_time( 1365 cfga_list_data_t *p1, 1366 cfga_list_data_t *p2, 1367 match_type_t match_type) 1368 { 1369 switch (match_type) { 1370 case CFGA_MATCH_NOFILTER: 1371 return (0); 1372 case CFGA_MATCH_ORDER: 1373 default: 1374 return (p1->ap_status_time - p2->ap_status_time); 1375 } 1376 } 1377 1378 1379 /* 1380 * print_time - print time from cfga_list_data. 1381 * Time print based on ls(1). 1382 */ 1383 static void 1384 print_time( 1385 cfga_list_data_t *p, 1386 int width, 1387 char *lp) 1388 { 1389 static time_t year, now; 1390 time_t stime; 1391 char time_buf[50]; /* array to hold day and time */ 1392 1393 if (year == 0) { 1394 now = time((long *)NULL); 1395 year = now - 6L*30L*24L*60L*60L; /* 6 months ago */ 1396 now = now + 60; 1397 } 1398 stime = p->ap_status_time; 1399 if (stime == (time_t)-1) { 1400 (void) sprintf(lp, "%-*s", width, gettext("unavailable")); 1401 return; 1402 } 1403 1404 if ((stime < year) || (stime > now)) { 1405 (void) strftime(time_buf, sizeof (time_buf), 1406 dcgettext(NULL, FORMAT1, LC_TIME), localtime(&stime)); 1407 } else { 1408 (void) strftime(time_buf, sizeof (time_buf), 1409 dcgettext(NULL, FORMAT2, LC_TIME), localtime(&stime)); 1410 } 1411 (void) sprintf(lp, "%-*s", width, time_buf); 1412 } 1413 1414 /* 1415 * print_time_p - print time from cfga_list_data. 1416 */ 1417 static void 1418 print_time_p( 1419 cfga_list_data_t *p, 1420 int width, 1421 char *lp) 1422 { 1423 struct tm *tp; 1424 char tstr[TIME_P_WIDTH+1]; 1425 1426 tp = localtime(&p->ap_status_time); 1427 (void) sprintf(tstr, "%04d%02d%02d%02d%02d%02d", tp->tm_year + 1900, 1428 tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec); 1429 (void) sprintf(lp, "%-*s", width, tstr); 1430 } 1431 1432 /* 1433 * compare_info - compare info from two cfga_list_data structs 1434 */ 1435 static int 1436 compare_info( 1437 cfga_list_data_t *p1, 1438 cfga_list_data_t *p2, 1439 match_type_t match_type) 1440 { 1441 switch (match_type) { 1442 case CFGA_MATCH_NOFILTER: 1443 return (0); 1444 case CFGA_MATCH_ORDER: 1445 default: 1446 return (strncmp(p1->ap_info, p2->ap_info, 1447 sizeof (p2->ap_info))); 1448 } 1449 } 1450 1451 /* 1452 * print_info - print info from cfga_list_data struct 1453 */ 1454 static void 1455 print_info( 1456 cfga_list_data_t *p, 1457 int width, 1458 char *lp) 1459 { 1460 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_info), p->ap_info); 1461 } 1462 1463 /* 1464 * compare_type - compare type from two cfga_list_data structs 1465 * 1466 * For partial matches, argument order is significant. The filtering criterion 1467 * should be the first argument. 1468 */ 1469 static int 1470 compare_type( 1471 cfga_list_data_t *p1, 1472 cfga_list_data_t *p2, 1473 match_type_t match_type) 1474 { 1475 switch (match_type) { 1476 case CFGA_MATCH_NOFILTER: 1477 return (0); 1478 case CFGA_MATCH_PARTIAL: 1479 return (strncmp(p1->ap_type, p2->ap_type, strlen(p1->ap_type))); 1480 case CFGA_MATCH_EXACT: 1481 case CFGA_MATCH_ORDER: 1482 default: 1483 return (strncmp(p1->ap_type, p2->ap_type, 1484 sizeof (p2->ap_type))); 1485 } 1486 } 1487 1488 /* 1489 * print_type - print type from cfga_list_data struct 1490 */ 1491 static void 1492 print_type( 1493 cfga_list_data_t *p, 1494 int width, 1495 char *lp) 1496 { 1497 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_type), p->ap_type); 1498 } 1499 1500 1501 /* 1502 * compare_class - compare class from two cfga_list_data structs 1503 * 1504 * For partial matches, argument order is significant. The filtering criterion 1505 * should be the first argument. 1506 */ 1507 static int 1508 compare_class( 1509 cfga_list_data_t *p1, 1510 cfga_list_data_t *p2, 1511 match_type_t match_type) 1512 { 1513 1514 switch (match_type) { 1515 case CFGA_MATCH_NOFILTER: 1516 return (0); 1517 case CFGA_MATCH_PARTIAL: 1518 return (strncmp(p1->ap_class, p2->ap_class, 1519 strlen(p1->ap_class))); 1520 case CFGA_MATCH_EXACT: 1521 case CFGA_MATCH_ORDER: 1522 default: 1523 return (strncmp(p1->ap_class, p2->ap_class, 1524 sizeof (p2->ap_class))); 1525 } 1526 } 1527 1528 /* 1529 * print_class - print class from cfga_list_data struct 1530 */ 1531 static void 1532 print_class( 1533 cfga_list_data_t *p, 1534 int width, 1535 char *lp) 1536 { 1537 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_class), p->ap_class); 1538 } 1539 /* 1540 * print_busy - print busy from cfga_list_data struct 1541 */ 1542 /* ARGSUSED */ 1543 static void 1544 print_busy( 1545 cfga_list_data_t *p, 1546 int width, 1547 char *lp) 1548 { 1549 if (p->ap_busy) 1550 (void) sprintf(lp, "%-*.*s", width, width, "y"); 1551 else 1552 (void) sprintf(lp, "%-*.*s", width, width, "n"); 1553 } 1554 1555 /* 1556 * print_phys_id - print physical ap_id 1557 */ 1558 static void 1559 print_phys_id( 1560 cfga_list_data_t *p, 1561 int width, 1562 char *lp) 1563 { 1564 (void) sprintf(lp, "%-*.*s", width, sizeof (p->ap_phys_id), 1565 p->ap_phys_id); 1566 } 1567 1568 1569 /* 1570 * find_field - find the named field 1571 */ 1572 static struct field_info * 1573 find_field(char *fname) 1574 { 1575 struct field_info *fldp; 1576 1577 for (fldp = all_fields; fldp < &all_fields[N_FIELDS]; fldp++) 1578 if (strcmp(fname, fldp->name) == 0) 1579 return (fldp); 1580 return (NULL); 1581 } 1582 1583 /* 1584 * usage_field - print field usage 1585 */ 1586 static void 1587 usage_field() 1588 { 1589 struct field_info *fldp = NULL; 1590 const char *sep; 1591 static char field_list[] = "%s: print or sort fields must be one of:"; 1592 1593 (void) fprintf(stderr, gettext(field_list), cmdname); 1594 sep = ""; 1595 1596 for (fldp = all_fields; fldp < &all_fields[N_FIELDS]; fldp++) { 1597 (void) fprintf(stderr, "%s %s", sep, fldp->name); 1598 sep = ","; 1599 } 1600 (void) fprintf(stderr, "\n"); 1601 } 1602 1603 /* 1604 * compare_null - null comparison routine 1605 */ 1606 /*ARGSUSED*/ 1607 static int 1608 compare_null( 1609 cfga_list_data_t *p1, 1610 cfga_list_data_t *p2, 1611 match_type_t match_type) 1612 { 1613 return (0); 1614 } 1615 1616 /* 1617 * print_null - print out a field of spaces 1618 */ 1619 /*ARGSUSED*/ 1620 static void 1621 print_null( 1622 cfga_list_data_t *p, 1623 int width, 1624 char *lp) 1625 { 1626 (void) sprintf(lp, "%-*s", width, ""); 1627 } 1628 1629 /* 1630 * do_config_list - directs the output of the listing functions 1631 */ 1632 static int 1633 do_config_list( 1634 int l_argc, 1635 char *l_argv[], 1636 cfga_list_data_t *statlist, 1637 int nlist, 1638 char *sortp, 1639 char *colsp, 1640 char *cols2p, 1641 int noheadings, 1642 char *delimp, 1643 post_filter_t *post_filtp, 1644 int dyn_exp) 1645 { 1646 int nprcols = 0, ncols2 = 0; 1647 struct print_col *prnt_list = NULL; 1648 int napids_to_list = 0; 1649 FILE *fp = NULL; 1650 int f_err; 1651 cfga_list_data_t **sel_boards = NULL; 1652 int nsel = 0; 1653 int i, j; 1654 cfga_err_t ret; 1655 1656 ap_arg_t *arg_array = NULL; 1657 ap_out_t *out_array = NULL; 1658 1659 1660 sort_list = NULL; 1661 f_err = 0; 1662 fp = stdout; 1663 nsort_list = count_fields(sortp, FDELIM); 1664 if (nsort_list != 0) { 1665 sort_list = config_calloc_check(nsort_list, 1666 sizeof (*sort_list)); 1667 if (sort_list == NULL) { 1668 ret = CFGA_LIB_ERROR; 1669 goto out; 1670 } 1671 f_err |= process_sort_fields(nsort_list, sort_list, sortp); 1672 } else 1673 sort_list = NULL; 1674 1675 nprcols = count_fields(colsp, FDELIM); 1676 if ((ncols2 = count_fields(cols2p, FDELIM)) > nprcols) 1677 nprcols = ncols2; 1678 if (nprcols != 0) { 1679 prnt_list = config_calloc_check(nprcols, sizeof (*prnt_list)); 1680 if (prnt_list == NULL) { 1681 ret = CFGA_LIB_ERROR; 1682 goto out; 1683 } 1684 f_err |= process_fields(nprcols, prnt_list, 0, colsp); 1685 if (ncols2 != 0) 1686 f_err |= process_fields(nprcols, prnt_list, 1, cols2p); 1687 } else 1688 prnt_list = NULL; 1689 1690 if (f_err) { 1691 usage_field(); 1692 ret = CFGA_ERROR; 1693 goto out; 1694 } 1695 1696 /* Create an array of all user args (if any) */ 1697 if (l_argc != 0) { 1698 int i, j; 1699 1700 napids_to_list = 0; 1701 1702 for (i = 0; i < l_argc; i++) { 1703 napids_to_list += count_fields(l_argv[i], ARG_DELIM); 1704 } 1705 1706 arg_array = config_calloc_check(napids_to_list, 1707 sizeof (*arg_array)); 1708 if (arg_array == NULL) { 1709 ret = CFGA_LIB_ERROR; 1710 goto out; 1711 } 1712 1713 for (i = 0, j = 0; i < l_argc; i++) { 1714 int n; 1715 1716 n = count_fields(l_argv[i], ARG_DELIM); 1717 if (n == 0) { 1718 continue; 1719 } else if (n == 1) { 1720 arg_array[j].arg = l_argv[i]; 1721 arg_array[j].resp = 0; 1722 j++; 1723 } else { 1724 char *cp, *ncp; 1725 1726 cp = l_argv[i]; 1727 for (;;) { 1728 arg_array[j].arg = cp; 1729 arg_array[j].resp = 0; 1730 j++; 1731 ncp = strchr(cp, ARG_DELIM); 1732 if (ncp == NULL) 1733 break; 1734 *ncp = '\0'; 1735 cp = ncp + 1; 1736 } 1737 } 1738 } 1739 assert(j == napids_to_list); 1740 } else { 1741 napids_to_list = 0; 1742 arg_array = NULL; 1743 } 1744 1745 assert(nlist != 0); 1746 1747 out_array = config_calloc_check(nlist, sizeof (*out_array)); 1748 if (out_array == NULL) { 1749 ret = CFGA_LIB_ERROR; 1750 goto out; 1751 } 1752 1753 1754 /* create a list of output stat data */ 1755 for (i = 0; i < nlist; i++) { 1756 out_array[i].ldatap = &statlist[i]; 1757 out_array[i].req = 0; 1758 } 1759 1760 /* 1761 * Mark all user input which got atleast 1 stat data in response 1762 */ 1763 for (i = 0; i < napids_to_list; i++) { 1764 arg_got_resp(&arg_array[i], out_array, nlist, dyn_exp); 1765 } 1766 1767 /* 1768 * Process output data 1769 */ 1770 nsel = 0; 1771 for (i = 0; i < nlist; i++) { 1772 /* 1773 * Mark all the stats which were actually requested by user 1774 */ 1775 out_was_req(&out_array[i], arg_array, napids_to_list, 0); 1776 if (out_array[i].req == 0 && dyn_exp) { 1777 /* 1778 * Try again without the dynamic component for the 1779 * if dynamic expansion was requested. 1780 */ 1781 out_was_req(&out_array[i], arg_array, 1782 napids_to_list, 1); 1783 } 1784 1785 /* 1786 * post filter data which was actually requested 1787 */ 1788 if (out_array[i].req == 1) { 1789 do_post_filter(&out_array[i], post_filtp, &nsel); 1790 } 1791 } 1792 1793 sel_boards = config_calloc_check(nsel, sizeof (*sel_boards)); 1794 if (sel_boards == NULL) { 1795 ret = CFGA_LIB_ERROR; 1796 goto out; 1797 } 1798 1799 for (i = 0, j = 0; i < nlist; i++) { 1800 if (out_array[i].req == 1) { 1801 sel_boards[j] = out_array[i].ldatap; 1802 j++; 1803 } 1804 } 1805 1806 assert(j == nsel); 1807 1808 /* 1809 * Print headings even if no list entries - Bug or feature ? 1810 */ 1811 if (!noheadings && prnt_list != NULL) { 1812 if ((ret = print_fields(nprcols, prnt_list, 1, 0, 1813 delimp, NULL, fp)) != CFGA_OK) { 1814 goto out; 1815 } 1816 if (ncols2 != 0) { 1817 if ((ret = print_fields(nprcols, prnt_list, 1, 1818 1, delimp, NULL, fp)) != CFGA_OK) { 1819 goto out; 1820 } 1821 } 1822 } 1823 1824 if (nsel != 0) { 1825 if (sort_list != NULL && nsel > 1) { 1826 qsort(sel_boards, nsel, sizeof (sel_boards[0]), 1827 ldata_compare); 1828 } 1829 1830 if (prnt_list != NULL) { 1831 for (i = 0; i < nsel; i++) { 1832 if ((ret = print_fields(nprcols, 1833 prnt_list, 0, 0, delimp, sel_boards[i], fp)) 1834 != CFGA_OK) 1835 goto out; 1836 if (ncols2 != 0) { 1837 if ((ret = print_fields( 1838 nprcols, prnt_list, 0, 1, delimp, 1839 sel_boards[i], fp)) != CFGA_OK) 1840 goto out; 1841 } 1842 } 1843 } 1844 } 1845 /* 1846 * Go thru the argument list and notify user about args 1847 * which did not have a match 1848 */ 1849 report_no_response(arg_array, napids_to_list); 1850 ret = CFGA_OK; 1851 /*FALLTHRU*/ 1852 out: 1853 S_FREE(sel_boards); 1854 S_FREE(arg_array); 1855 S_FREE(out_array); 1856 1857 S_FREE(sort_list); 1858 S_FREE(prnt_list); 1859 1860 return (ret); 1861 } 1862 1863 1864 /* 1865 * Mark all user inputs which got a response 1866 */ 1867 static void 1868 arg_got_resp(ap_arg_t *inp, ap_out_t *out_array, int nouts, int dyn_exp) 1869 { 1870 int i; 1871 cfga_ap_types_t type; 1872 1873 1874 if (nouts == 0) { 1875 return; 1876 } 1877 1878 type = find_arg_type(inp->arg); 1879 1880 /* 1881 * Go through list of output stats and check if argument 1882 * produced that output 1883 */ 1884 for (i = 0; i < nouts; i++) { 1885 if (type == PHYSICAL_AP_ID) { 1886 if (config_ap_id_cmp(out_array[i].ldatap->ap_phys_id, 1887 inp->arg) == 0) { 1888 break; 1889 } 1890 } else if (type == LOGICAL_AP_ID) { 1891 if (config_ap_id_cmp(out_array[i].ldatap->ap_log_id, 1892 inp->arg) == 0) { 1893 break; 1894 } 1895 } else if (type == AP_TYPE) { 1896 /* 1897 * An AP_TYPE argument cannot generate dynamic 1898 * attachment point stats unless dynamic expansion was 1899 * requested by user. 1900 */ 1901 if (!dyn_exp && get_dyn(out_array[i].ldatap->ap_log_id) 1902 != NULL) { 1903 continue; 1904 } 1905 1906 if (strncmp(out_array[i].ldatap->ap_log_id, inp->arg, 1907 strlen(inp->arg)) == 0) { 1908 break; 1909 } 1910 } else { 1911 return; 1912 } 1913 } 1914 1915 if (i < nouts) { 1916 inp->resp = 1; 1917 } 1918 } 1919 1920 /* Mark all stat data which were requested by user */ 1921 static void 1922 out_was_req(ap_out_t *outp, ap_arg_t *in_array, int nargs, int no_dyn) 1923 { 1924 int i; 1925 cfga_ap_types_t type = UNKNOWN_AP; 1926 char physid[MAXPATHLEN], logid[MAXPATHLEN]; 1927 1928 1929 /* If no user args, all output is acceptable */ 1930 if (nargs == 0) { 1931 outp->req = 1; 1932 return; 1933 } 1934 1935 1936 (void) snprintf(physid, sizeof (physid), "%s", 1937 outp->ldatap->ap_phys_id); 1938 (void) snprintf(logid, sizeof (logid), "%s", outp->ldatap->ap_log_id); 1939 1940 /* 1941 * Do comparison with or without dynamic component as requested by 1942 * user. 1943 */ 1944 if (no_dyn) { 1945 /* Remove the dynamic component */ 1946 remove_dyn(physid); 1947 remove_dyn(logid); 1948 } 1949 1950 for (i = 0; i < nargs; i++) { 1951 type = find_arg_type(in_array[i].arg); 1952 if (type == PHYSICAL_AP_ID) { 1953 1954 if (config_ap_id_cmp(in_array[i].arg, physid) == 0) { 1955 break; 1956 } 1957 } else if (type == LOGICAL_AP_ID) { 1958 1959 if (config_ap_id_cmp(in_array[i].arg, logid) == 0) { 1960 break; 1961 } 1962 } else if (type == AP_TYPE) { 1963 /* 1964 * Aptypes cannot generate dynamic attachment 1965 * points unless dynamic expansion is specified. 1966 * in which case this routine would be called a 1967 * 2nd time with the no_dyn flag set and there 1968 * would be no dynamic ap_ids. 1969 */ 1970 if (get_dyn(logid) != NULL) { 1971 continue; 1972 } 1973 1974 if (strncmp(in_array[i].arg, logid, 1975 strlen(in_array[i].arg)) == 0) { 1976 break; 1977 } 1978 } else { 1979 continue; 1980 } 1981 } 1982 1983 if (i < nargs) { 1984 /* Ok, this output was requested */ 1985 outp->req = 1; 1986 } 1987 1988 } 1989 1990 static void 1991 do_post_filter(ap_out_t *outp, post_filter_t *post_filtp, int *nselp) 1992 { 1993 int i; 1994 1995 if (outp->req != 1) { 1996 return; 1997 } 1998 1999 /* 2000 * For fields without filtering (CFGA_MATCH_NOFILTER), 2001 * compare always returns 0 (success) 2002 */ 2003 for (i = 0; i < N_FIELDS; i++) { 2004 /* 2005 * Note: Order is important for partial match (via strncmp). 2006 * The first argument for compare must be the filter. 2007 */ 2008 if (all_fields[i].compare(&post_filtp->ldata, outp->ldatap, 2009 post_filtp->match_type_p[i])) { 2010 outp->req = 0; /* Blocked by filter */ 2011 return; 2012 } 2013 } 2014 2015 /* 2016 * Passed through filter 2017 */ 2018 (*nselp)++; 2019 } 2020 2021 static void 2022 report_no_response(ap_arg_t *arg_array, int nargs) 2023 { 2024 int i; 2025 2026 if (nargs == 0) { 2027 return; 2028 } 2029 2030 2031 /* 2032 * nop if no user arguments 2033 */ 2034 for (i = 0; i < nargs; i++) { 2035 if (arg_array[i].resp == 0) { 2036 (void) fprintf(stderr, 2037 gettext("%s: No matching library found\n"), 2038 arg_array[i].arg); 2039 } 2040 } 2041 } 2042 2043 /* 2044 * ldata_compare - compare two attachment point list data structures. 2045 */ 2046 static int 2047 ldata_compare( 2048 const void *vb1, 2049 const void *vb2) 2050 { 2051 int i; 2052 int res = -1; 2053 cfga_list_data_t *b1, *b2; 2054 2055 2056 b1 = *(cfga_list_data_t **)vb1; 2057 b2 = *(cfga_list_data_t **)vb2; 2058 2059 for (i = 0; i < nsort_list; i++) { 2060 res = (*(sort_list[i].fld->compare))(b1, b2, CFGA_MATCH_ORDER); 2061 if (res != 0) { 2062 if (sort_list[i].reverse) 2063 res = -res; 2064 break; 2065 } 2066 } 2067 2068 return (res); 2069 } 2070 2071 /* 2072 * count_fields - Count the number of fields, using supplied delimiter. 2073 */ 2074 static int 2075 count_fields(char *fspec, char delim) 2076 { 2077 char *cp = NULL; 2078 int n; 2079 2080 if (fspec == 0 || *fspec == '\0') 2081 return (0); 2082 n = 1; 2083 for (cp = fspec; *cp != '\0'; cp++) 2084 if (*cp == delim) 2085 n++; 2086 return (n); 2087 } 2088 2089 /* 2090 * get_field 2091 * This function is not a re-implementation of strtok(). 2092 * There can be null fields - strtok() eats spans of delimiters. 2093 */ 2094 static char * 2095 get_field(char **fspp) 2096 { 2097 char *cp = NULL, *fld; 2098 2099 fld = *fspp; 2100 2101 if (fld != NULL && *fld == '\0') 2102 fld = NULL; 2103 2104 if (fld != NULL) { 2105 cp = strchr(*fspp, FDELIM); 2106 if (cp == NULL) { 2107 *fspp = NULL; 2108 } else { 2109 *cp = '\0'; 2110 *fspp = cp + 1; 2111 if (*fld == '\0') 2112 fld = NULL; 2113 } 2114 } 2115 return (fld); 2116 } 2117 2118 /* 2119 * process_fields - 2120 */ 2121 static int 2122 process_fields( 2123 int ncol, 2124 struct print_col *list, 2125 int line2, 2126 char *fmt) 2127 { 2128 struct print_col *pp = NULL; 2129 struct field_info *fldp = NULL; 2130 char *fmtx; 2131 char *fldn; 2132 int err; 2133 2134 err = 0; 2135 fmtx = fmt; 2136 for (pp = list; pp < &list[ncol]; pp++) { 2137 fldn = get_field(&fmtx); 2138 fldp = &null_field; 2139 if (fldn != NULL) { 2140 struct field_info *tfldp; 2141 2142 tfldp = find_field(fldn); 2143 if (tfldp != NULL) { 2144 fldp = tfldp; 2145 } else { 2146 (void) fprintf(stderr, gettext(unk_field), 2147 cmdname, fldn); 2148 err = 1; 2149 } 2150 } 2151 if (line2) { 2152 pp->line2 = fldp; 2153 if (fldp->width > pp->width) 2154 pp->width = fldp->width; 2155 } else { 2156 pp->line1 = fldp; 2157 pp->width = fldp->width; 2158 } 2159 } 2160 return (err); 2161 } 2162 2163 /* 2164 * process_sort_fields - 2165 */ 2166 static int 2167 process_sort_fields( 2168 int nsort, 2169 struct sort_el *list, 2170 char *fmt) 2171 { 2172 int i; 2173 int rev; 2174 struct field_info *fldp = NULL; 2175 char *fmtx; 2176 char *fldn; 2177 int err; 2178 2179 err = 0; 2180 fmtx = fmt; 2181 for (i = 0; i < nsort; i++) { 2182 fldn = get_field(&fmtx); 2183 fldp = &null_field; 2184 rev = 0; 2185 if (fldn != NULL) { 2186 struct field_info *tfldp = NULL; 2187 2188 if (*fldn == '-') { 2189 rev = 1; 2190 fldn++; 2191 } 2192 tfldp = find_field(fldn); 2193 if (tfldp != NULL) { 2194 fldp = tfldp; 2195 } else { 2196 (void) fprintf(stderr, gettext(unk_field), 2197 cmdname, fldn); 2198 err = 1; 2199 } 2200 } 2201 list[i].reverse = rev; 2202 list[i].fld = fldp; 2203 } 2204 return (err); 2205 } 2206 2207 /* 2208 * print_fields - 2209 */ 2210 static cfga_err_t 2211 print_fields( 2212 int ncol, 2213 struct print_col *list, 2214 int heading, 2215 int line2, 2216 char *delim, 2217 cfga_list_data_t *bdp, 2218 FILE *fp) 2219 { 2220 char *del = NULL; 2221 struct print_col *pp = NULL; 2222 struct field_info *fldp = NULL; 2223 static char *outline, *end; 2224 char *lp; 2225 2226 if (outline == NULL) { 2227 int out_len, delim_len; 2228 2229 delim_len = strlen(delim); 2230 out_len = 0; 2231 for (pp = list; pp < &list[ncol]; pp++) { 2232 out_len += pp->width; 2233 out_len += delim_len; 2234 } 2235 out_len -= delim_len; 2236 outline = config_calloc_check(out_len + 1, 1); 2237 if (outline == NULL) { 2238 return (CFGA_LIB_ERROR); 2239 } 2240 end = &outline[out_len + 1]; 2241 } 2242 2243 lp = outline; 2244 del = ""; 2245 for (pp = list; pp < &list[ncol]; pp++) { 2246 fldp = line2 ? pp->line2 : pp->line1; 2247 (void) snprintf(lp, end - lp, "%s", del); 2248 lp += strlen(lp); 2249 if (heading) { 2250 (void) snprintf(lp, end - lp, "%-*s", 2251 fldp->width, fldp->heading); 2252 } else { 2253 (*fldp->printfn)(bdp, fldp->width, lp); 2254 } 2255 lp += strlen(lp); 2256 del = delim; 2257 } 2258 2259 /* 2260 * Trim trailing spaces 2261 */ 2262 while (--lp >= outline && *lp == ' ') 2263 *lp = '\0'; 2264 (void) fprintf(fp, "%s\n", outline); 2265 return (CFGA_OK); 2266 } 2267 2268 /* 2269 * config_calloc_check - perform allocation, check result and 2270 * set error indicator 2271 */ 2272 static void * 2273 config_calloc_check( 2274 size_t nelem, 2275 size_t elsize) 2276 { 2277 void *p; 2278 static char alloc_fail[] = 2279 "%s: memory allocation failed (%d*%d bytes)\n"; 2280 2281 2282 p = calloc(nelem, elsize); 2283 if (p == NULL) { 2284 (void) fprintf(stderr, gettext(alloc_fail), cmdname, 2285 nelem, elsize); 2286 } 2287 return (p); 2288 } 2289 2290 /* 2291 * find_arg_type - determine if an argument is an ap_id or an ap_type. 2292 */ 2293 static cfga_ap_types_t 2294 find_arg_type(const char *ap_id) 2295 { 2296 struct stat sbuf; 2297 cfga_ap_types_t type; 2298 char *mkr = NULL, *cp; 2299 int size_ap = 0, size_mkr = 0, digit = 0, i = 0; 2300 char path[MAXPATHLEN]; 2301 char apbuf[MAXPATHLEN]; 2302 size_t len; 2303 2304 2305 /* 2306 * sanity checks 2307 */ 2308 if (ap_id == NULL || *ap_id == '\0') { 2309 return (UNKNOWN_AP); 2310 } 2311 2312 /* 2313 * Mask the dynamic component if any 2314 */ 2315 if ((cp = GET_DYN(ap_id)) != NULL) { 2316 len = cp - ap_id; 2317 } else { 2318 len = strlen(ap_id); 2319 } 2320 2321 if (len >= sizeof (apbuf)) { 2322 return (UNKNOWN_AP); 2323 } 2324 2325 (void) strncpy(apbuf, ap_id, len); 2326 apbuf[len] = '\0'; 2327 2328 /* 2329 * If it starts with a slash and is stat-able 2330 * its a physical. 2331 */ 2332 if (*apbuf == '/' && stat(apbuf, &sbuf) == 0) { 2333 return (PHYSICAL_AP_ID); 2334 } 2335 2336 /* 2337 * Is this a symlink in CFGA_DEV_DIR ? 2338 */ 2339 (void) snprintf(path, sizeof (path), "%s/%s", CFGA_DEV_DIR, apbuf); 2340 2341 if (lstat(path, &sbuf) == 0 && S_ISLNK(sbuf.st_mode) && 2342 stat(path, &sbuf) == 0) { 2343 return (LOGICAL_AP_ID); 2344 } 2345 2346 /* 2347 * Check for ":" which is always present in an ap_id but not maybe 2348 * present or absent in an ap_type. 2349 * We need to check that the characters right before the : are digits 2350 * since an ap_id is of the form <name><instance>:<specific ap name> 2351 */ 2352 if ((mkr = strchr(apbuf, ':')) == NULL) { 2353 type = AP_TYPE; 2354 } else { 2355 size_ap = strlen(apbuf); 2356 size_mkr = strlen(mkr); 2357 mkr = apbuf; 2358 2359 digit = 0; 2360 for (i = size_ap - size_mkr - 1; i > 0; i--) { 2361 if ((int)isdigit(mkr[i])) { 2362 digit++; 2363 break; 2364 } 2365 } 2366 if (digit == 0) { 2367 type = AP_TYPE; 2368 } else { 2369 type = LOGICAL_AP_ID; 2370 } 2371 } 2372 2373 return (type); 2374 } 2375 2376 2377 static char * 2378 get_dyn(const char *ap_id) 2379 { 2380 if (ap_id == NULL) { 2381 return (NULL); 2382 } 2383 2384 return (strstr(ap_id, CFGA_DYN_SEP)); 2385 } 2386 2387 /* 2388 * removes the dynamic component 2389 */ 2390 static void 2391 remove_dyn(char *ap_id) 2392 { 2393 char *cp; 2394 2395 if (ap_id == NULL) { 2396 return; 2397 } 2398 2399 cp = strstr(ap_id, CFGA_DYN_SEP); 2400 if (cp != NULL) { 2401 *cp = '\0'; 2402 } 2403 } 2404 2405 2406 static char * 2407 s_strdup(char *str) 2408 { 2409 char *dup; 2410 2411 /* 2412 * sometimes NULL strings may be passed in (see DEF_COLS2). This 2413 * is not an error. 2414 */ 2415 if (str == NULL) { 2416 return (NULL); 2417 } 2418 2419 dup = strdup(str); 2420 if (dup == NULL) { 2421 (void) fprintf(stderr, 2422 "%s \"%s\"\n", gettext("Cannot copy string"), str); 2423 return (NULL); 2424 } 2425 2426 return (dup); 2427 } 2428