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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <unistd.h> 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <sys/sockio.h> 30 #include <netinet/in.h> 31 #include <arpa/inet.h> 32 #include <net/if.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <strings.h> 36 #include <ctype.h> 37 #include <errno.h> 38 #include <libintl.h> 39 #include <locale.h> 40 #include <libdevinfo.h> 41 42 #define DATADM_OP_VIEW 0x0000 43 #define DATADM_OP_UPDATE 0x0001 44 #define DATADM_OP_ADD 0x0002 45 #define DATADM_OP_REMOVE 0x0003 46 #define DATADM_NUM_OPS 0x0004 47 #define DATADM_DAT_CONF "/etc/dat/dat.conf" 48 #define DATADM_LINESZ 1024 49 #define DATADM_NUM_SP_TOKENS 7 50 #define DATADM_NUM_DAT_TOKENS 8 51 #define DATADM_IA_NAME "ibd" 52 #define DATADM_DRV_NAME "driver_name" 53 #define DATADM_MAX_TOKENS 16 54 55 /* 56 * generic entry 57 * placed at the top of all entry types 58 */ 59 typedef struct datadm_entry { 60 struct datadm_entry *de_next; 61 } datadm_entry_t; 62 63 /* 64 * list structure 65 * can be manipulated using datadm_walk_list or 66 * datadm_enqueue_entry 67 */ 68 typedef struct datadm_list { 69 datadm_entry_t *dl_head; 70 datadm_entry_t *dl_tail; 71 uint_t dl_count; 72 } datadm_list_t; 73 74 /* 75 * internal representation of the version string in 76 * dat.conf or service_provider.conf. the format is 77 * <dv_name><dv_major>.<dv_minor> 78 */ 79 typedef struct datadm_version { 80 char *dv_name; 81 uint_t dv_major; 82 uint_t dv_minor; 83 } datadm_version_t; 84 85 /* 86 * each sp_entry corresponds to an entry in dat.conf or 87 * service_provider.conf. an sp_entry is processed by the 88 * function datadm_process_sp_entry. 89 */ 90 typedef struct datadm_sp_entry { 91 datadm_entry_t spe_header; 92 char *spe_devname; 93 datadm_version_t spe_api_version; 94 int spe_threadsafe; 95 int spe_default; 96 char *spe_libpath; 97 datadm_version_t spe_sp_version; 98 char *spe_sp_data; 99 int spe_invalid; 100 } datadm_sp_entry_t; 101 102 /* 103 * an hca_entry is created whenever a new hca device is 104 * encountered during sp_entry processing. this structure 105 * contains two lists. the sp_list holds sp entries that 106 * are added when sp entry processing occurs. duplicate 107 * sp entries are not added to this list. the ia_list may 108 * be built statically using the information in dat.conf or 109 * dynamically using libdevinfo. similar to the sp_list, 110 * the ia_list contains only unique entries. 111 */ 112 typedef struct datadm_hca_entry { 113 datadm_entry_t he_header; 114 char *he_name; 115 datadm_list_t he_sp_list; 116 datadm_list_t he_ia_list; 117 } datadm_hca_entry_t; 118 119 /* 120 * an ia_entry is created when a new ia name is encountered 121 * during sp_entry processing or when a new ia name is 122 * discovered by datadm_fill_ia_list. ia_entry holds the ia 123 * device's instance number. 124 */ 125 typedef struct datadm_ia_entry { 126 datadm_entry_t iae_header; 127 int iae_devnum; 128 } datadm_ia_entry_t; 129 130 /* 131 * a comment entry represents one of the comment lines at the 132 * top of dat.conf. a list of these lines are saved during the 133 * parsing of dat.conf. these lines are written back to dat.conf 134 * when dat.conf gets regenerated. 135 */ 136 typedef struct datadm_cmnt_entry { 137 datadm_entry_t cmnt_header; 138 char *cmnt_line; 139 } datadm_cmnt_entry_t; 140 141 /* 142 * 2nd argument to datadm_hca_entry_find. 143 * hf_hca_entry is filled in if an hca_entry with 144 * a matching he_name is found. 145 */ 146 typedef struct datadm_hca_find { 147 datadm_sp_entry_t *hf_sp_entry; 148 datadm_hca_entry_t *hf_hca_entry; 149 } datadm_hca_find_t; 150 151 /* 152 * 2nd argument to datadm_ia_entry_find. 153 * if_ia_entry is filled in if an ia_entry with 154 * a matching ia_devnum is found. 155 */ 156 typedef struct datadm_ia_find { 157 int if_ia_devnum; 158 datadm_ia_entry_t *if_ia_entry; 159 } datadm_ia_find_t; 160 161 /* 162 * this gets passed to datadm_fill_ia_list. 163 * we do this to avoid regenerating the device 164 * tree for each hca_entry we process. 165 */ 166 typedef struct datadm_fill_ia_list { 167 di_node_t ia_root_node; 168 int ia_sock_fd_v4; 169 int ia_sock_fd_v6; 170 } datadm_fill_ia_list_t; 171 172 /* 173 * this defines the commandline parameters specified 174 * by the user. 175 */ 176 typedef struct datadm_args { 177 char *da_sp_conf; 178 char *da_dat_conf; 179 int da_op_type; 180 } datadm_args_t; 181 182 static datadm_args_t datadm_args; 183 static datadm_list_t datadm_conf_header; 184 static char *datadm_conf_header_default = 185 "#\n" 186 "# Copyright 2004 Sun Microsystems, Inc. All rights reserved.\n" 187 "# Use is subject to license terms.\n" 188 "#\n" 189 "# ident \"@(#)dat.conf 1.1 03/08/26 SMI\"\n" 190 "#\n" 191 "# DAT configuration file.\n" 192 "#\n" 193 "# This file is updated using the datadm(1) command.\n" 194 "# Do not hand edit this file.\n" 195 "# See datadm(1) man page for more details.\n" 196 "#\n" 197 "# The fields in this file are -\n" 198 "#\n" 199 "# IAname version threadsafe default library-path provider-version \\\n" 200 "# instance-data platform-information\n" 201 "#\n"; 202 203 /* 204 * common parsing functions. 205 */ 206 typedef int (*datadm_parse_func_t)(char *, void *); 207 static int datadm_parse_line(char *, char *[], int *); 208 static int datadm_parse_generic_str(char *, char **); 209 static int datadm_parse_nonnull_str(char *, char **); 210 static int datadm_parse_version(char *, datadm_version_t *); 211 static int datadm_parse_devname(char *, datadm_sp_entry_t *); 212 static int datadm_parse_api_version(char *, datadm_sp_entry_t *); 213 static int datadm_parse_threadsafe(char *, datadm_sp_entry_t *); 214 static int datadm_parse_default(char *, datadm_sp_entry_t *); 215 static int datadm_parse_libpath(char *, datadm_sp_entry_t *); 216 static int datadm_parse_sp_version(char *, datadm_sp_entry_t *); 217 static int datadm_parse_sp_data(char *, datadm_sp_entry_t *); 218 static int datadm_parse_ia_name(char *, int *); 219 220 /* 221 * utility functions 222 */ 223 static void datadm_enqueue_entry(datadm_list_t *, datadm_entry_t *); 224 static int datadm_walk_list(datadm_list_t *, 225 int (*)(datadm_entry_t *, void *), void *); 226 static int datadm_str_match(char *, char *); 227 static int datadm_version_match(datadm_version_t *, datadm_version_t *); 228 static int datadm_sp_entry_match(datadm_sp_entry_t *, datadm_sp_entry_t *); 229 230 /* 231 * entry allocation/deallocation 232 */ 233 static datadm_sp_entry_t *datadm_alloc_sp_entry(void); 234 static datadm_ia_entry_t *datadm_alloc_ia_entry(void); 235 static datadm_hca_entry_t *datadm_alloc_hca_entry(void); 236 static datadm_cmnt_entry_t *datadm_alloc_cmnt_entry(void); 237 static void datadm_free_sp_entry(datadm_sp_entry_t *); 238 static void datadm_free_ia_entry(datadm_ia_entry_t *); 239 static void datadm_free_hca_entry(datadm_hca_entry_t *); 240 static void datadm_free_cmnt_entry(datadm_cmnt_entry_t *); 241 242 243 /* 244 * high level parsing functions 245 */ 246 static int datadm_parse_sp_conf(datadm_list_t *); 247 static int datadm_parse_dat_conf(datadm_list_t *); 248 static int datadm_process_sp_entry(datadm_list_t *, datadm_sp_entry_t *, int); 249 250 /* 251 * ia devices discovery 252 */ 253 static int datadm_build_ia_lists(datadm_list_t *); 254 static int datadm_fill_ia_list(datadm_hca_entry_t *, datadm_fill_ia_list_t *); 255 256 /* 257 * helper function for OP_REMOVE 258 */ 259 static void datadm_invalidate_common_sp_entries(datadm_list_t *, 260 datadm_list_t *); 261 262 /* 263 * output generation 264 */ 265 static int datadm_generate_dat_conf(datadm_list_t *); 266 static int datadm_generate_conf_header(FILE *); 267 static int datadm_generate_conf_entry(FILE *, datadm_ia_entry_t *, 268 datadm_sp_entry_t *); 269 270 /* 271 * datadm operations 272 */ 273 static int datadm_view(void); 274 static int datadm_update(void); 275 static int datadm_add(void); 276 static int datadm_remove(void); 277 278 /* 279 * usage 280 */ 281 static void datadm_usage(void); 282 283 284 /* 285 * parse function tables 286 */ 287 static datadm_parse_func_t datadm_sp_parse_funcs[DATADM_NUM_SP_TOKENS] = { 288 (datadm_parse_func_t)datadm_parse_devname, 289 (datadm_parse_func_t)datadm_parse_api_version, 290 (datadm_parse_func_t)datadm_parse_threadsafe, 291 (datadm_parse_func_t)datadm_parse_default, 292 (datadm_parse_func_t)datadm_parse_libpath, 293 (datadm_parse_func_t)datadm_parse_sp_version, 294 (datadm_parse_func_t)datadm_parse_sp_data 295 }; 296 297 static datadm_parse_func_t datadm_dat_parse_funcs[DATADM_NUM_DAT_TOKENS] = { 298 (datadm_parse_func_t)datadm_parse_ia_name, 299 (datadm_parse_func_t)datadm_parse_api_version, 300 (datadm_parse_func_t)datadm_parse_threadsafe, 301 (datadm_parse_func_t)datadm_parse_default, 302 (datadm_parse_func_t)datadm_parse_libpath, 303 (datadm_parse_func_t)datadm_parse_sp_version, 304 (datadm_parse_func_t)datadm_parse_sp_data, 305 (datadm_parse_func_t)datadm_parse_devname 306 }; 307 308 /* 309 * operation table 310 */ 311 static int (*datadm_ops[DATADM_NUM_OPS])(void) = { 312 datadm_view, 313 datadm_update, 314 datadm_add, 315 datadm_remove 316 }; 317 318 static void 319 datadm_usage(void) 320 { 321 (void) fprintf(stderr, gettext( 322 "usage: datadm -v\n" 323 " -u\n" 324 " -a <service_provider.conf>\n" 325 " -r <service_provider.conf>\n")); 326 } 327 328 static int 329 datadm_parse_generic_str(char *str, char **strptr) 330 { 331 int len; 332 333 len = strlen(str); 334 *strptr = (char *)malloc(len + 1); 335 if (*strptr == NULL) { 336 return (-1); 337 } 338 (void) strcpy(*strptr, str); 339 return (0); 340 } 341 342 /* 343 * this function strips off leading and trailing 344 * whitespaces and returns an error for null or 345 * empty strings. 346 */ 347 static int 348 datadm_parse_nonnull_str(char *str, char **strptr) 349 { 350 int len, i; 351 char *start; 352 353 if (str[0] == '\0') { 354 return (-1); 355 } 356 start = str; 357 for (i = 0; str[i] != '\0'; i++) { 358 if (!isspace(str[i])) { 359 start = &str[i]; 360 break; 361 } 362 } 363 for (; str[i] != '\0'; i++) { 364 if (isspace(str[i])) { 365 str[i] = '\0'; 366 } 367 } 368 len = strlen(start); 369 *strptr = (char *)malloc(len + 1); 370 if (*strptr == NULL) { 371 return (-1); 372 } 373 (void) strcpy(*strptr, start); 374 return (0); 375 } 376 377 /* 378 * parses the api_version and sp_version fields in 379 * dat.conf and service_provider.conf 380 */ 381 static int 382 datadm_parse_version(char *str, datadm_version_t *version) 383 { 384 int i = 0, len; 385 int major_idx, minor_idx; 386 387 len = strlen(str); 388 389 for (i = 0; i < len; i++) { 390 if (isdigit(str[i])) break; 391 } 392 if (i == len) { 393 return (-1); 394 } 395 if (i > 0) { 396 version->dv_name = (char *)malloc(i + 1); 397 bcopy(str, version->dv_name, i); 398 version->dv_name[i] = '\0'; 399 } else { 400 version->dv_name = NULL; 401 } 402 major_idx = i; 403 404 for (; i < len; i++) { 405 if (!isdigit(str[i])) break; 406 } 407 if (i == len) { 408 return (-1); 409 } 410 if (str[i] != '.') { 411 return (-1); 412 } 413 minor_idx = ++i; 414 if (i == len) { 415 return (-1); 416 } 417 for (; i < len; i++) { 418 if (!isdigit(str[i])) break; 419 } 420 if (i != len) { 421 return (-1); 422 } 423 version->dv_major = atoi(str + major_idx); 424 version->dv_minor = atoi(str + minor_idx); 425 return (0); 426 } 427 428 /* 429 * parses the ia_name field in dat.conf 430 */ 431 static int 432 datadm_parse_ia_name(char *str, int *ia_devnum) 433 { 434 int len; 435 int i, start; 436 437 len = strlen(DATADM_IA_NAME); 438 if (strncmp(str, DATADM_IA_NAME, len) != 0) { 439 return (-1); 440 } 441 start = i = len; 442 len = strlen(str); 443 if (str[i] == '\0') { 444 return (-1); 445 } 446 for (; i < len; i++) { 447 if (!isdigit(str[i])) break; 448 } 449 if (i != len) { 450 return (-1); 451 } 452 *ia_devnum = atoi(str + start); 453 return (0); 454 } 455 456 /* 457 * parses the device name, strips leading and trailing spaces. 458 * the format should be "driver_name=<dev_name>" 459 */ 460 static int 461 datadm_parse_devname(char *str, datadm_sp_entry_t *sp_entry) 462 { 463 int len, dlen, i, j = 0; 464 char *drv_name = DATADM_DRV_NAME; 465 466 len = strlen(str); 467 dlen = strlen(drv_name); 468 469 /* 470 * strip out leading spaces and try to match 471 * the expected string 472 */ 473 for (i = 0; i < len; i++) { 474 if (isspace(str[i]) && j == 0) { 475 continue; 476 } else { 477 if (str[i] == drv_name[j]) { 478 j++; 479 if (j == dlen) { 480 break; 481 } else { 482 continue; 483 } 484 } else { 485 break; 486 } 487 } 488 } 489 490 /* 491 * j must be dlen if the matching string is found 492 */ 493 if (j != dlen) { 494 return (-1); 495 } 496 497 /* 498 * skip past the last char of drv_name 499 */ 500 i++; 501 502 /* 503 * strip the spaces before the '=' 504 */ 505 for (; i < len; i++) { 506 if (!isspace(str[i])) { 507 break; 508 } 509 } 510 511 /* 512 * return if the string is too long or if 513 * the '=' isn't found 514 */ 515 if (i >= len || str[i] != '=') { 516 return (-1); 517 } 518 i++; 519 if (i >= len) { 520 /* 521 * no string after the equal 522 */ 523 return (-1); 524 } 525 return (datadm_parse_nonnull_str(str + i, &sp_entry->spe_devname)); 526 } 527 528 static int 529 datadm_parse_api_version(char *str, datadm_sp_entry_t *sp_entry) 530 { 531 return (datadm_parse_version(str, &sp_entry->spe_api_version)); 532 } 533 534 static int 535 datadm_parse_threadsafe(char *str, datadm_sp_entry_t *sp_entry) 536 { 537 int retval = 0; 538 539 if (strcmp(str, "threadsafe") == 0) { 540 sp_entry->spe_threadsafe = 1; 541 } else if (strcmp(str, "nonthreadsafe") == 0) { 542 sp_entry->spe_threadsafe = 0; 543 } else { 544 retval = -1; 545 } 546 return (retval); 547 } 548 549 static int 550 datadm_parse_default(char *str, datadm_sp_entry_t *sp_entry) 551 { 552 int retval = 0; 553 554 if (strcmp(str, "default") == 0) { 555 sp_entry->spe_default = 1; 556 } else if (strcmp(str, "nondefault") == 0) { 557 sp_entry->spe_default = 0; 558 } else { 559 retval = -1; 560 } 561 return (retval); 562 } 563 564 static int 565 datadm_parse_libpath(char *str, datadm_sp_entry_t *sp_entry) 566 { 567 return (datadm_parse_nonnull_str(str, &sp_entry->spe_libpath)); 568 } 569 570 static int 571 datadm_parse_sp_version(char *str, datadm_sp_entry_t *sp_entry) 572 { 573 return (datadm_parse_version(str, &sp_entry->spe_sp_version)); 574 } 575 576 static int 577 datadm_parse_sp_data(char *str, datadm_sp_entry_t *sp_entry) 578 { 579 return (datadm_parse_generic_str(str, &sp_entry->spe_sp_data)); 580 } 581 582 static void 583 datadm_enqueue_entry(datadm_list_t *list, datadm_entry_t *entry) 584 { 585 if (list->dl_head == NULL) { 586 list->dl_head = entry; 587 list->dl_tail = entry; 588 list->dl_count = 1; 589 } else { 590 list->dl_tail->de_next = entry; 591 list->dl_tail = entry; 592 list->dl_count++; 593 } 594 } 595 596 /* 597 * iterates through the list applying func on each element. 598 * break and return if func returns non-zero. 599 */ 600 static int 601 datadm_walk_list(datadm_list_t *list, int (*func)(datadm_entry_t *, void *), 602 void *arg) 603 { 604 datadm_entry_t *entry; 605 int retval = 0; 606 607 entry = list->dl_head; 608 while (entry != NULL) { 609 retval = (*func)(entry, arg); 610 if (retval != 0) break; 611 entry = entry->de_next; 612 } 613 return (retval); 614 } 615 616 /* 617 * iterates through the list applying free_func to each element. 618 * list becomes empty when the function returns. 619 */ 620 static void 621 datadm_free_list(datadm_list_t *list, void (*free_func)(datadm_entry_t *)) 622 { 623 while (list->dl_head != NULL) { 624 datadm_entry_t *entry; 625 626 entry = list->dl_head; 627 list->dl_head = entry->de_next; 628 (*free_func)(entry); 629 } 630 list->dl_count = 0; 631 list->dl_tail = NULL; 632 } 633 634 static datadm_sp_entry_t * 635 datadm_alloc_sp_entry(void) 636 { 637 datadm_sp_entry_t *sp_entry; 638 639 sp_entry = (datadm_sp_entry_t *)malloc(sizeof (*sp_entry)); 640 if (sp_entry == NULL) { 641 return (NULL); 642 } 643 bzero(sp_entry, sizeof (*sp_entry)); 644 return (sp_entry); 645 } 646 647 static void 648 datadm_free_sp_entry(datadm_sp_entry_t *sp_entry) 649 { 650 if (sp_entry->spe_devname != NULL) { 651 free(sp_entry->spe_devname); 652 sp_entry->spe_devname = NULL; 653 } 654 if (sp_entry->spe_api_version.dv_name != NULL) { 655 free(sp_entry->spe_api_version.dv_name); 656 sp_entry->spe_api_version.dv_name = NULL; 657 } 658 sp_entry->spe_api_version.dv_major = 0; 659 sp_entry->spe_api_version.dv_minor = 0; 660 sp_entry->spe_threadsafe = 0; 661 sp_entry->spe_default = 0; 662 if (sp_entry->spe_libpath != NULL) { 663 free(sp_entry->spe_libpath); 664 sp_entry->spe_libpath = NULL; 665 } 666 if (sp_entry->spe_sp_version.dv_name != NULL) { 667 free(sp_entry->spe_sp_version.dv_name); 668 sp_entry->spe_sp_version.dv_name = NULL; 669 } 670 sp_entry->spe_sp_version.dv_major = 0; 671 sp_entry->spe_sp_version.dv_minor = 0; 672 if (sp_entry->spe_sp_data != NULL) { 673 free(sp_entry->spe_sp_data); 674 sp_entry->spe_sp_data = NULL; 675 } 676 free(sp_entry); 677 } 678 679 static int 680 datadm_str_match(char *s1, char *s2) 681 { 682 if (s1 == NULL || s2 == NULL) { 683 if (s1 != s2) { 684 return (0); 685 } 686 } else { 687 if (strcmp(s1, s2) != 0) { 688 return (0); 689 } 690 } 691 return (1); 692 } 693 694 static int 695 datadm_version_match(datadm_version_t *v1, datadm_version_t *v2) 696 { 697 if (!datadm_str_match(v1->dv_name, v2->dv_name)) { 698 return (0); 699 } 700 if (v1->dv_major != v2->dv_major) { 701 return (0); 702 } 703 if (v1->dv_minor != v2->dv_minor) { 704 return (0); 705 } 706 return (1); 707 } 708 709 static int 710 datadm_sp_entry_match(datadm_sp_entry_t *sp1, datadm_sp_entry_t *sp2) 711 { 712 if (!datadm_str_match(sp1->spe_devname, sp2->spe_devname)) { 713 return (0); 714 } 715 if (!datadm_version_match(&sp1->spe_api_version, 716 &sp2->spe_api_version)) { 717 return (0); 718 } 719 if (sp1->spe_threadsafe != sp2->spe_threadsafe) { 720 return (0); 721 } 722 if (sp2->spe_default != sp2->spe_default) { 723 return (0); 724 } 725 if (!datadm_str_match(sp1->spe_libpath, sp2->spe_libpath)) { 726 return (0); 727 } 728 if (!datadm_version_match(&sp1->spe_sp_version, 729 &sp2->spe_sp_version)) { 730 return (0); 731 } 732 if (!datadm_str_match(sp1->spe_sp_data, sp2->spe_sp_data)) { 733 return (0); 734 } 735 return (1); 736 } 737 738 static datadm_ia_entry_t * 739 datadm_alloc_ia_entry(void) 740 { 741 datadm_ia_entry_t *ia_entry; 742 743 ia_entry = (datadm_ia_entry_t *)malloc(sizeof (*ia_entry)); 744 if (ia_entry == NULL) { 745 return (NULL); 746 } 747 bzero(ia_entry, sizeof (*ia_entry)); 748 return (ia_entry); 749 } 750 751 static void 752 datadm_free_ia_entry(datadm_ia_entry_t *ia_entry) 753 { 754 free(ia_entry); 755 } 756 757 static datadm_hca_entry_t * 758 datadm_alloc_hca_entry(void) 759 { 760 datadm_hca_entry_t *hca_entry; 761 762 hca_entry = (datadm_hca_entry_t *)malloc(sizeof (*hca_entry)); 763 if (hca_entry == NULL) { 764 return (NULL); 765 } 766 bzero(hca_entry, sizeof (*hca_entry)); 767 return (hca_entry); 768 } 769 770 static void 771 datadm_free_hca_entry(datadm_hca_entry_t *hca_entry) 772 { 773 if (hca_entry->he_name != NULL) { 774 free(hca_entry->he_name); 775 hca_entry->he_name = NULL; 776 } 777 datadm_free_list(&hca_entry->he_sp_list, 778 (void (*)(datadm_entry_t *))datadm_free_sp_entry); 779 datadm_free_list(&hca_entry->he_ia_list, 780 (void (*)(datadm_entry_t *))datadm_free_ia_entry); 781 free(hca_entry); 782 } 783 784 static int 785 datadm_hca_entry_match(datadm_hca_entry_t *h1, datadm_hca_entry_t *h2) 786 { 787 if (!datadm_str_match(h1->he_name, h2->he_name)) { 788 return (0); 789 } 790 return (1); 791 } 792 793 static int 794 datadm_hca_entry_find(datadm_hca_entry_t *h1, datadm_hca_find_t *hf) 795 { 796 if (datadm_str_match(h1->he_name, hf->hf_sp_entry->spe_devname)) { 797 hf->hf_hca_entry = h1; 798 return (1); 799 } 800 return (0); 801 } 802 803 static int 804 datadm_ia_entry_find(datadm_ia_entry_t *i1, datadm_ia_find_t *iaf) 805 { 806 if (i1->iae_devnum == iaf->if_ia_devnum) { 807 iaf->if_ia_entry = i1; 808 return (1); 809 } 810 return (0); 811 } 812 813 static datadm_cmnt_entry_t * 814 datadm_alloc_cmnt_entry(void) 815 { 816 datadm_cmnt_entry_t *cmnt_entry; 817 818 cmnt_entry = (datadm_cmnt_entry_t *)malloc(sizeof (*cmnt_entry)); 819 if (cmnt_entry == NULL) { 820 return (NULL); 821 } 822 bzero(cmnt_entry, sizeof (*cmnt_entry)); 823 return (cmnt_entry); 824 } 825 826 static void 827 datadm_free_cmnt_entry(datadm_cmnt_entry_t *cmnt_entry) 828 { 829 if (cmnt_entry->cmnt_line != NULL) { 830 free(cmnt_entry->cmnt_line); 831 cmnt_entry->cmnt_line = NULL; 832 } 833 free(cmnt_entry); 834 } 835 836 /* 837 * tokenizes a line and strips off the quotes from quoted strings 838 */ 839 static int 840 datadm_parse_line(char *line_buf, char *tokens[], int *token_count) 841 { 842 int len, i; 843 int count = 0; 844 char *start = NULL; 845 846 /* the line must not be longer than DATADM_LINESZ */ 847 len = strlen(line_buf); 848 if (line_buf[len - 1] != '\n') { 849 return (-1); 850 } 851 /* discard blank lines and comments */ 852 if (len == 1) { 853 *token_count = 0; 854 return (0); 855 } 856 if (len >= 2 && line_buf[0] == '#') { 857 *token_count = 0; 858 return (0); 859 } 860 /* removes the new line */ 861 line_buf[len - 1] = '\0'; 862 len--; 863 864 for (i = 0; i < len; i++) { 865 if (start != NULL) { 866 /* 867 * start points to the start of 868 * a new token. if start is '"', 869 * we should expect a quoted 870 * string. 871 */ 872 if (*start == '\"') { 873 /* 874 * keep scanning until we 875 * hit the end quote. 876 */ 877 if (line_buf[i] != '\"') { 878 continue; 879 } 880 /* 881 * skip past the start quote 882 */ 883 start++; 884 } else { 885 /* 886 * our token is not a quoted 887 * string. our token ends only 888 * when we hit a whitespace. 889 */ 890 if (!isspace(line_buf[i])) { 891 continue; 892 } 893 } 894 /* 895 * nullify the end quote (if any) 896 * and update the tokens array. 897 */ 898 line_buf[i] = '\0'; 899 tokens[count] = start; 900 start = NULL; 901 count++; 902 } else { 903 /* 904 * skip whitespaces 905 */ 906 if (isspace(line_buf[i])) { 907 continue; 908 } else { 909 start = &line_buf[i]; 910 } 911 } 912 if (count == DATADM_MAX_TOKENS) { 913 start = NULL; 914 break; 915 } 916 } 917 if (start != NULL) { 918 tokens[count] = start; 919 start = NULL; 920 count++; 921 } 922 *token_count = count; 923 return (0); 924 } 925 926 /* 927 * attempts to save sp_entry into hca_list. 928 * becomes no-op if sp entry already exists. 929 * new hca entries and ia entries are created as needed. 930 */ 931 static int 932 datadm_process_sp_entry(datadm_list_t *hca_list, datadm_sp_entry_t *sp_entry, 933 int ia_devnum) 934 { 935 datadm_hca_find_t hca_find; 936 datadm_ia_find_t ia_find; 937 datadm_hca_entry_t *hca_entry; 938 939 hca_find.hf_sp_entry = sp_entry; 940 hca_find.hf_hca_entry = NULL; 941 (void) datadm_walk_list(hca_list, (int (*)(datadm_entry_t *, void *)) 942 datadm_hca_entry_find, (void *)&hca_find); 943 944 if (hca_find.hf_hca_entry == NULL) { 945 int dlen; 946 947 /* 948 * hca_entry not found, need to create 949 * and insert one. 950 */ 951 hca_entry = datadm_alloc_hca_entry(); 952 if (hca_entry == NULL) { 953 return (-1); 954 } 955 dlen = strlen(sp_entry->spe_devname); 956 hca_entry->he_name = (char *)malloc(dlen + 1); 957 if (hca_entry->he_name == NULL) { 958 datadm_free_hca_entry(hca_entry); 959 return (-1); 960 } 961 (void) strcpy(hca_entry->he_name, sp_entry->spe_devname); 962 datadm_enqueue_entry(hca_list, (datadm_entry_t *)hca_entry); 963 } else { 964 hca_entry = hca_find.hf_hca_entry; 965 } 966 if (ia_devnum == -1) { 967 goto put_sp_entry; 968 } 969 ia_find.if_ia_devnum = ia_devnum; 970 ia_find.if_ia_entry = NULL; 971 (void) datadm_walk_list(&hca_entry->he_ia_list, 972 (int (*)(datadm_entry_t *, void *))datadm_ia_entry_find, &ia_find); 973 974 if (ia_find.if_ia_entry == NULL) { 975 datadm_ia_entry_t *ia_entry; 976 977 /* 978 * ia_entry not found, need to create 979 * and insert one. 980 */ 981 ia_entry = datadm_alloc_ia_entry(); 982 if (ia_entry == NULL) { 983 return (-1); 984 } 985 ia_entry->iae_devnum = ia_devnum; 986 datadm_enqueue_entry(&hca_entry->he_ia_list, 987 (datadm_entry_t *)ia_entry); 988 } 989 990 put_sp_entry:; 991 992 if (datadm_walk_list(&hca_entry->he_sp_list, 993 (int (*)(datadm_entry_t *, void *))datadm_sp_entry_match, 994 (void *)sp_entry)) { 995 return (1); 996 } else { 997 /* 998 * only insert sp_entry if it is not found. 999 */ 1000 datadm_enqueue_entry(&hca_entry->he_sp_list, 1001 (datadm_entry_t *)sp_entry); 1002 } 1003 return (0); 1004 } 1005 1006 /* 1007 * parses service_provider.conf 1008 */ 1009 static int 1010 datadm_parse_sp_conf(datadm_list_t *hca_list) 1011 { 1012 datadm_sp_entry_t *sp_entry; 1013 FILE *sp_file; 1014 char *sp_conf = datadm_args.da_sp_conf; 1015 char *tokens[DATADM_MAX_TOKENS]; 1016 char line_buf[DATADM_LINESZ]; 1017 int retval = 0; 1018 int token_count = 0; 1019 int line_count = 0; 1020 1021 sp_file = fopen(sp_conf, "r"); 1022 if (sp_file == NULL) { 1023 (void) fprintf(stderr, 1024 gettext("datadm: cannot open %s\n"), sp_conf); 1025 return (-1); 1026 } 1027 1028 for (;;) { 1029 bzero(line_buf, DATADM_LINESZ); 1030 if (fgets(line_buf, DATADM_LINESZ, sp_file) == NULL) { 1031 break; 1032 } 1033 token_count = 0; 1034 line_count++; 1035 retval = datadm_parse_line(line_buf, tokens, &token_count); 1036 if (retval != 0) { 1037 (void) fprintf(stderr, gettext( 1038 "datadm: %s: line %d exceeded max length %d\n"), 1039 sp_conf, line_count, DATADM_LINESZ); 1040 break; 1041 } 1042 if (token_count == 0) continue; 1043 if (token_count == DATADM_NUM_SP_TOKENS) { 1044 int i = 0; 1045 1046 sp_entry = datadm_alloc_sp_entry(); 1047 if (sp_entry == NULL) { 1048 retval = -1; 1049 break; 1050 } 1051 1052 /* 1053 * sp_entry gets filled incrementally by 1054 * each parsing function 1055 */ 1056 for (i = 0; i < DATADM_NUM_SP_TOKENS && 1057 retval == 0; i++) { 1058 retval = (*datadm_sp_parse_funcs[i]) 1059 (tokens[i], (void *)sp_entry); 1060 } 1061 if (retval != 0) { 1062 (void) fprintf(stderr, gettext( 1063 "datadm: parse error: %s, " 1064 "line %d, token: %s\n"), 1065 sp_conf, line_count, tokens[i - 1]); 1066 datadm_free_sp_entry(sp_entry); 1067 sp_entry = NULL; 1068 break; 1069 } 1070 1071 retval = datadm_process_sp_entry(hca_list, 1072 sp_entry, -1); 1073 if (retval != 0) { 1074 datadm_free_sp_entry(sp_entry); 1075 if (retval == 1) { 1076 retval = 0; 1077 } else { 1078 break; 1079 } 1080 } 1081 } else { 1082 (void) fprintf(stderr, gettext( 1083 "datadm: parse error: %s, line %d, " 1084 "# of tokens: %d, expected %d\n"), sp_conf, 1085 line_count, token_count, DATADM_NUM_SP_TOKENS); 1086 retval = -1; 1087 break; 1088 } 1089 } 1090 if (retval != 0) { 1091 datadm_free_list(hca_list, 1092 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1093 } 1094 (void) fclose(sp_file); 1095 return (retval); 1096 } 1097 1098 /* 1099 * parses dat.conf 1100 */ 1101 static int 1102 datadm_parse_dat_conf(datadm_list_t *hca_list) 1103 { 1104 boolean_t save_header = B_TRUE; 1105 datadm_sp_entry_t *sp_entry; 1106 FILE *dat_file; 1107 char *dat_conf = datadm_args.da_dat_conf; 1108 char *tokens[DATADM_MAX_TOKENS]; 1109 char line_buf[DATADM_LINESZ]; 1110 int retval = 0; 1111 int token_count = 0; 1112 int line_count = 0; 1113 1114 dat_file = fopen(dat_conf, "r"); 1115 if (dat_file == NULL) { 1116 /* dat.conf not existing is not an error for OP_ADD */ 1117 if (datadm_args.da_op_type == DATADM_OP_ADD) { 1118 return (0); 1119 } 1120 (void) fprintf(stderr, gettext("datadm: cannot open %s\n"), 1121 dat_conf); 1122 return (-1); 1123 } 1124 1125 for (;;) { 1126 bzero(line_buf, DATADM_LINESZ); 1127 if (fgets(line_buf, DATADM_LINESZ, dat_file) == NULL) { 1128 break; 1129 } 1130 token_count = 0; 1131 line_count++; 1132 retval = datadm_parse_line(line_buf, tokens, &token_count); 1133 if (retval != 0) { 1134 (void) fprintf(stderr, gettext( 1135 "datadm: %s: line %d exceeded max length %d\n"), 1136 dat_conf, line_count, DATADM_LINESZ); 1137 break; 1138 } 1139 if (token_count == 0) { 1140 datadm_cmnt_entry_t *cmnt_entry; 1141 int cmnt_len; 1142 1143 /* 1144 * comments are saved only if they are 1145 * at the top of dat.conf. 1146 */ 1147 if (!save_header) continue; 1148 cmnt_entry = datadm_alloc_cmnt_entry(); 1149 if (cmnt_entry == NULL) { 1150 perror("datadm: malloc"); 1151 retval = -1; 1152 break; 1153 } 1154 cmnt_len = strlen(line_buf); 1155 cmnt_entry->cmnt_line = (char *)malloc(cmnt_len + 1); 1156 if (cmnt_entry->cmnt_line == NULL) { 1157 perror("datadm: malloc"); 1158 datadm_free_cmnt_entry(cmnt_entry); 1159 retval = -1; 1160 break; 1161 } 1162 (void) strncpy(cmnt_entry->cmnt_line, 1163 line_buf, cmnt_len); 1164 cmnt_entry->cmnt_line[cmnt_len] = '\0'; 1165 datadm_enqueue_entry(&datadm_conf_header, 1166 (datadm_entry_t *)cmnt_entry); 1