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); 1167 continue; 1168 } 1169 if (token_count == DATADM_NUM_DAT_TOKENS) { 1170 int i = 0; 1171 int ia_devnum = -1; 1172 1173 /* 1174 * we stop saving comment lines once 1175 * we see the first valid line. 1176 */ 1177 save_header = B_FALSE; 1178 sp_entry = datadm_alloc_sp_entry(); 1179 if (sp_entry == NULL) { 1180 retval = -1; 1181 break; 1182 } 1183 1184 /* 1185 * sp_entry gets filled incrementally by 1186 * each parsing function 1187 */ 1188 for (i = 0; i < DATADM_NUM_DAT_TOKENS && 1189 retval == 0; i++) { 1190 void *arg; 1191 1192 if (i == 0) { 1193 /* 1194 * the first token (ia name) 1195 * does not belong to an 1196 * sp_entry 1197 */ 1198 arg = (void *)&ia_devnum; 1199 } else { 1200 arg = (void *)sp_entry; 1201 } 1202 retval = (*datadm_dat_parse_funcs[i]) 1203 (tokens[i], arg); 1204 } 1205 if (retval != 0) { 1206 (void) fprintf(stderr, gettext( 1207 "datadm: parse error: %s, " 1208 "line %d, token: %s\n"), dat_conf, 1209 line_count, tokens[i - 1]); 1210 datadm_free_sp_entry(sp_entry); 1211 sp_entry = NULL; 1212 break; 1213 } 1214 1215 /* 1216 * we ignore the ibds in dat.conf if we are 1217 * doing update 1218 */ 1219 if (datadm_args.da_op_type == DATADM_OP_UPDATE) { 1220 ia_devnum = -1; 1221 } 1222 retval = datadm_process_sp_entry(hca_list, sp_entry, 1223 ia_devnum); 1224 if (retval != 0) { 1225 datadm_free_sp_entry(sp_entry); 1226 if (retval == 1) { 1227 retval = 0; 1228 } else { 1229 break; 1230 } 1231 } 1232 } else { 1233 (void) fprintf(stderr, gettext( 1234 "datadm: parse error: %s, line %d, " 1235 "# of tokens: %d, expected %d\n"), dat_conf, 1236 line_count, token_count, DATADM_NUM_DAT_TOKENS); 1237 retval = -1; 1238 break; 1239 } 1240 } 1241 if (retval != 0) { 1242 datadm_free_list(&datadm_conf_header, 1243 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1244 datadm_free_list(hca_list, 1245 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1246 } 1247 (void) fclose(dat_file); 1248 return (retval); 1249 } 1250 1251 /* 1252 * discovers all ibd devices under a particular hca 1253 */ 1254 static int 1255 datadm_fill_ia_list(datadm_hca_entry_t *hca, datadm_fill_ia_list_t *args) 1256 { 1257 di_node_t root_node; 1258 di_node_t hca_node; 1259 int retval = 0; 1260 int sv4, sv6; 1261 1262 root_node = args->ia_root_node; 1263 sv4 = args->ia_sock_fd_v4; 1264 sv6 = args->ia_sock_fd_v6; 1265 1266 hca_node = di_drv_first_node(hca->he_name, root_node); 1267 if (hca_node == DI_NODE_NIL) { 1268 return (0); 1269 } 1270 while (hca_node != DI_NODE_NIL) { 1271 di_node_t ibd_node; 1272 1273 ibd_node = di_drv_first_node(DATADM_IA_NAME, hca_node); 1274 while (ibd_node != DI_NODE_NIL) { 1275 datadm_ia_find_t ia_find; 1276 datadm_ia_entry_t *ia_entry; 1277 struct lifreq req; 1278 int devnum, rval; 1279 1280 if (hca_node != di_parent_node(ibd_node)) { 1281 ibd_node = di_drv_next_node(ibd_node); 1282 continue; 1283 } 1284 devnum = di_instance(ibd_node); 1285 if (devnum == -1) { 1286 ibd_node = di_drv_next_node(ibd_node); 1287 continue; 1288 } 1289 1290 (void) snprintf(req.lifr_name, sizeof (req.lifr_name), 1291 "%s%d", DATADM_IA_NAME, devnum); 1292 /* 1293 * we don't really need to know the ip address. 1294 * we just want to check if the device is plumbed 1295 * or not. 1296 */ 1297 rval = ioctl(sv4, SIOCGLIFADDR, (caddr_t)&req); 1298 if (rval != 0) { 1299 /* 1300 * we try v6 if the v4 address isn't found. 1301 */ 1302 rval = ioctl(sv6, SIOCGLIFADDR, (caddr_t)&req); 1303 if (rval != 0) { 1304 ibd_node = di_drv_next_node(ibd_node); 1305 continue; 1306 } 1307 } 1308 ia_find.if_ia_devnum = devnum; 1309 ia_find.if_ia_entry = NULL; 1310 (void) datadm_walk_list(&hca->he_ia_list, 1311 (int (*)(datadm_entry_t *, void *)) 1312 datadm_ia_entry_find, &ia_find); 1313 1314 if (ia_find.if_ia_entry == NULL) { 1315 /* 1316 * we insert an ia entry only if 1317 * it is unique. 1318 */ 1319 ia_entry = datadm_alloc_ia_entry(); 1320 if (ia_entry == NULL) { 1321 retval = -1; 1322 break; 1323 } 1324 ia_entry->iae_devnum = devnum; 1325 datadm_enqueue_entry(&hca->he_ia_list, 1326 (datadm_entry_t *)ia_entry); 1327 } else { 1328 ia_entry = ia_find.if_ia_entry; 1329 } 1330 ibd_node = di_drv_next_node(ibd_node); 1331 } 1332 hca_node = di_drv_next_node(hca_node); 1333 } 1334 if (retval != 0) { 1335 datadm_free_list(&hca->he_ia_list, 1336 (void (*)(datadm_entry_t *))datadm_free_ia_entry); 1337 } 1338 return (0); 1339 } 1340 1341 /* 1342 * used by OP_REMOVE to invalidate common sp entries between hl1 and hl2. 1343 * invalid sp entries will be ignored by datadm_generate_dat_conf. 1344 */ 1345 static void 1346 datadm_invalidate_common_sp_entries(datadm_list_t *hl1, datadm_list_t *hl2) 1347 { 1348 datadm_entry_t *he1, *he2; 1349 1350 he1 = hl1->dl_head; 1351 while (he1 != NULL) { 1352 he2 = hl2->dl_head; 1353 while (he2 != NULL) { 1354 datadm_entry_t *se1, *se2; 1355 1356 if (!datadm_hca_entry_match( 1357 (datadm_hca_entry_t *)he1, 1358 (datadm_hca_entry_t *)he2)) { 1359 he2 = he2->de_next; 1360 continue; 1361 } 1362 se1 = ((datadm_hca_entry_t *)he1)->he_sp_list.dl_head; 1363 while (se1 != NULL) { 1364 se2 = ((datadm_hca_entry_t *)he2)-> 1365 he_sp_list.dl_head; 1366 while (se2 != NULL) { 1367 if (!datadm_sp_entry_match( 1368 (datadm_sp_entry_t *)se1, 1369 (datadm_sp_entry_t *)se2)) { 1370 se2 = se2->de_next; 1371 continue; 1372 } 1373 ((datadm_sp_entry_t *)se1)-> 1374 spe_invalid = 1; 1375 break; 1376 } 1377 se1 = se1->de_next; 1378 } 1379 break; 1380 } 1381 he1 = he1->de_next; 1382 } 1383 } 1384 1385 /* 1386 * applies datadm_fill_ia_list on each hca_list element 1387 */ 1388 static int 1389 datadm_build_ia_lists(datadm_list_t *hca_list) 1390 { 1391 datadm_fill_ia_list_t ia_args; 1392 di_node_t root_node; 1393 int retval = 0; 1394 int sv4, sv6; 1395 1396 root_node = di_init("/", DINFOCPYALL); 1397 if (root_node == DI_NODE_NIL) { 1398 perror("datadm: di_init"); 1399 return (-1); 1400 } 1401 sv4 = socket(AF_INET, SOCK_DGRAM, 0); 1402 if (sv4 < 0) { 1403 perror("datadm: socket"); 1404 di_fini(root_node); 1405 return (-1); 1406 } 1407 sv6 = socket(AF_INET6, SOCK_DGRAM, 0); 1408 if (sv6 < 0) { 1409 perror("datadm: socket"); 1410 di_fini(root_node); 1411 return (-1); 1412 } 1413 ia_args.ia_root_node = root_node; 1414 ia_args.ia_sock_fd_v4 = sv4; 1415 ia_args.ia_sock_fd_v6 = sv6; 1416 1417 retval = datadm_walk_list(hca_list, 1418 (int (*)(datadm_entry_t *, void *))datadm_fill_ia_list, &ia_args); 1419 1420 (void) close(sv4); 1421 (void) close(sv6); 1422 di_fini(root_node); 1423 return (retval); 1424 } 1425 1426 static int 1427 datadm_generate_conf_entry(FILE *outfile, datadm_ia_entry_t *ia_entry, 1428 datadm_sp_entry_t *sp_entry) 1429 { 1430 int retval; 1431 1432 retval = fprintf(outfile, 1433 "%s%d %s%d.%d %s %s %s %s%d.%d \"%s\" \"%s%s%s\"\n", 1434 DATADM_IA_NAME, ia_entry->iae_devnum, 1435 (sp_entry->spe_api_version.dv_name ? 1436 sp_entry->spe_api_version.dv_name : ""), 1437 sp_entry->spe_api_version.dv_major, 1438 sp_entry->spe_api_version.dv_minor, 1439 (sp_entry->spe_threadsafe ? "threadsafe" : "nonthreadsafe"), 1440 (sp_entry->spe_default ? "default" : "nondefault"), 1441 sp_entry->spe_libpath, 1442 (sp_entry->spe_sp_version.dv_name ? 1443 sp_entry->spe_sp_version.dv_name : ""), 1444 sp_entry->spe_sp_version.dv_major, 1445 sp_entry->spe_sp_version.dv_minor, 1446 sp_entry->spe_sp_data, 1447 DATADM_DRV_NAME, "=", sp_entry->spe_devname); 1448 1449 if (retval < 0) { 1450 return (-1); 1451 } 1452 return (0); 1453 } 1454 1455 /* 1456 * generate dat.conf header 1457 */ 1458 static int 1459 datadm_generate_conf_header(FILE *outfile) 1460 { 1461 datadm_entry_t *cep; 1462 datadm_cmnt_entry_t *cmnt; 1463 int retval = 0; 1464 1465 cep = datadm_conf_header.dl_head; 1466 if (cep == NULL) { 1467 /* 1468 * if dat.conf doesn't have a header, we prepend a 1469 * default one. 1470 */ 1471 retval = fprintf(outfile, "%s", datadm_conf_header_default); 1472 goto done; 1473 } 1474 while (cep != NULL) { 1475 cmnt = (datadm_cmnt_entry_t *)cep; 1476 if (cmnt->cmnt_line != NULL) { 1477 int len; 1478 1479 retval = fprintf(outfile, "%s", cmnt->cmnt_line); 1480 if (retval < 0) { 1481 break; 1482 } 1483 1484 /* 1485 * append a newline if the comment line doesn't 1486 * have one. 1487 */ 1488 len = strlen(cmnt->cmnt_line); 1489 if (cmnt->cmnt_line[len - 1] != '\n') { 1490 retval = fprintf(outfile, "\n"); 1491 if (retval < 0) { 1492 break; 1493 } 1494 } 1495 } 1496 cep = cep->de_next; 1497 } 1498 done:; 1499 if (retval < 0) { 1500 return (-1); 1501 } 1502 return (0); 1503 } 1504 1505 /* 1506 * outputs dat.conf to stdout or to basedir/etc/dat/dat.conf 1507 */ 1508 static int 1509 datadm_generate_dat_conf(datadm_list_t *hca_list) 1510 { 1511 FILE *outfile = NULL; 1512 char *dat_conf = datadm_args.da_dat_conf; 1513 datadm_entry_t *hep; 1514 int retval = 0; 1515 1516 if (datadm_args.da_op_type == DATADM_OP_VIEW) { 1517 outfile = stdout; 1518 } else { 1519 outfile = fopen(dat_conf, "w+"); 1520 if (outfile == NULL) { 1521 (void) fprintf(stderr, gettext( 1522 "datadm: cannot open %s: %s\n"), 1523 dat_conf, strerror(errno)); 1524 return (-1); 1525 } 1526 } 1527 if (outfile != stdout) { 1528 /* 1529 * do not generate the header if we are 1530 * printing to the screen 1531 */ 1532 retval = datadm_generate_conf_header(outfile); 1533 if (retval != 0) { 1534 goto done; 1535 } 1536 } 1537 hep = hca_list->dl_head; 1538 while (hep != NULL) { 1539 datadm_entry_t *iep; 1540 1541 iep = ((datadm_hca_entry_t *)hep)->he_ia_list.dl_head; 1542 while (iep != NULL) { 1543 datadm_entry_t *sep; 1544 1545 sep = ((datadm_hca_entry_t *)hep)->he_sp_list.dl_head; 1546 while (sep != NULL) { 1547 if (((datadm_sp_entry_t *)sep)->spe_invalid) { 1548 sep = sep->de_next; 1549 continue; 1550 } 1551 retval = datadm_generate_conf_entry(outfile, 1552 (datadm_ia_entry_t *)iep, 1553 (datadm_sp_entry_t *)sep); 1554 if (retval != 0) { 1555 goto done; 1556 } 1557 sep = sep->de_next; 1558 } 1559 iep = iep->de_next; 1560 } 1561 hep = hep->de_next; 1562 } 1563 retval = fflush(outfile); 1564 done:; 1565 if (outfile != stdout) { 1566 (void) fclose(outfile); 1567 } 1568 if (retval < 0) { 1569 perror("datadm: fprintf"); 1570 } 1571 return (retval); 1572 } 1573 1574 static int 1575 datadm_view(void) 1576 { 1577 int retval = 0; 1578 datadm_list_t hca_list; 1579 1580 bzero(&hca_list, sizeof (hca_list)); 1581 1582 retval = datadm_parse_dat_conf(&hca_list); 1583 if (retval != 0) { 1584 goto cleanup; 1585 } 1586 retval = datadm_generate_dat_conf(&hca_list); 1587 if (retval != 0) { 1588 goto cleanup; 1589 } 1590 1591 cleanup:; 1592 datadm_free_list(&datadm_conf_header, 1593 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1594 datadm_free_list(&hca_list, 1595 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1596 return (retval); 1597 } 1598 1599 static int 1600 datadm_update(void) 1601 { 1602 int retval = 0; 1603 datadm_list_t hca_list; 1604 1605 bzero(&hca_list, sizeof (hca_list)); 1606 1607 retval = datadm_parse_dat_conf(&hca_list); 1608 if (retval != 0) { 1609 goto cleanup; 1610 } 1611 retval = datadm_build_ia_lists(&hca_list); 1612 if (retval != 0) { 1613 goto cleanup; 1614 } 1615 retval = datadm_generate_dat_conf(&hca_list); 1616 if (retval != 0) { 1617 goto cleanup; 1618 } 1619 1620 cleanup:; 1621 datadm_free_list(&datadm_conf_header, 1622 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1623 datadm_free_list(&hca_list, 1624 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1625 return (retval); 1626 } 1627 1628 static int 1629 datadm_add(void) 1630 { 1631 int retval = 0; 1632 datadm_list_t hca_list; 1633 1634 bzero(&hca_list, sizeof (hca_list)); 1635 1636 retval = datadm_parse_dat_conf(&hca_list); 1637 if (retval != 0) { 1638 goto cleanup; 1639 } 1640 retval = datadm_parse_sp_conf(&hca_list); 1641 if (retval != 0) { 1642 goto cleanup; 1643 } 1644 retval = datadm_build_ia_lists(&hca_list); 1645 if (retval != 0) { 1646 goto cleanup; 1647 } 1648 retval = datadm_generate_dat_conf(&hca_list); 1649 if (retval != 0) { 1650 goto cleanup; 1651 } 1652 1653 cleanup:; 1654 datadm_free_list(&datadm_conf_header, 1655 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1656 datadm_free_list(&hca_list, 1657 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1658 return (retval); 1659 } 1660 1661 static int 1662 datadm_remove(void) 1663 { 1664 int retval = 0; 1665 datadm_list_t hca_list; 1666 datadm_list_t hca_list2; 1667 1668 bzero(&hca_list, sizeof (hca_list)); 1669 bzero(&hca_list2, sizeof (hca_list2)); 1670 1671 retval = datadm_parse_dat_conf(&hca_list); 1672 if (retval != 0) { 1673 goto cleanup; 1674 } 1675 retval = datadm_parse_sp_conf(&hca_list2); 1676 if (retval != 0) { 1677 goto cleanup; 1678 } 1679 datadm_invalidate_common_sp_entries(&hca_list, &hca_list2); 1680 1681 retval = datadm_generate_dat_conf(&hca_list); 1682 if (retval != 0) { 1683 goto cleanup; 1684 } 1685 1686 cleanup:; 1687 datadm_free_list(&datadm_conf_header, 1688 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1689 datadm_free_list(&hca_list, 1690 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1691 datadm_free_list(&hca_list2, 1692 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1693 return (retval); 1694 } 1695 1696 static int 1697 datadm_locate_dat_conf(char *basedir) 1698 { 1699 char *dat_conf; 1700 1701 if (basedir == NULL) { 1702 datadm_args.da_dat_conf = DATADM_DAT_CONF; 1703 return (0); 1704 } 1705 dat_conf = (char *)malloc(strlen(basedir) + 1706 strlen(DATADM_DAT_CONF) + 1); 1707 if (dat_conf == NULL) { 1708 return (-1); 1709 } 1710 dat_conf[0] = '\0'; 1711 (void) strcat(dat_conf, basedir); 1712 (void) strcat(dat_conf, DATADM_DAT_CONF); 1713 datadm_args.da_dat_conf = dat_conf; 1714 return (0); 1715 } 1716 1717 int 1718 main(int argc, char **argv) 1719 { 1720 extern char *optarg; 1721 extern int optind; 1722 char *basedir = NULL; 1723 int c, retval; 1724 int op_type = -1, errflg = 0; 1725 1726 bzero(&datadm_args, sizeof (datadm_args)); 1727 bzero(&datadm_conf_header, sizeof (datadm_conf_header)); 1728 1729 (void) setlocale(LC_ALL, ""); 1730 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1731 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 1732 #endif 1733 (void) textdomain(TEXT_DOMAIN); 1734 1735 while ((c = getopt(argc, argv, "vua:r:b:")) != EOF) { 1736 switch (c) { 1737 case 'v': 1738 if (op_type != -1) errflg = 1; 1739 op_type = DATADM_OP_VIEW; 1740 break; 1741 case 'u': 1742 if (op_type != -1) errflg = 1; 1743 op_type = DATADM_OP_UPDATE; 1744 break; 1745 case 'a': 1746 if (op_type != -1) errflg = 1; 1747 op_type = DATADM_OP_ADD; 1748 datadm_args.da_sp_conf = optarg; 1749 break; 1750 case 'r': 1751 if (op_type != -1) errflg = 1; 1752 op_type = DATADM_OP_REMOVE; 1753 datadm_args.da_sp_conf = optarg; 1754 break; 1755 case 'b': 1756 basedir = optarg; 1757 break; 1758 default: 1759 errflg = 1; 1760 break; 1761 } 1762 if (errflg != 0) { 1763 break; 1764 } 1765 } 1766 if (errflg != 0 || op_type == -1 || optind < argc) { 1767 datadm_usage(); 1768 return (1); 1769 } 1770 datadm_args.da_op_type = op_type; 1771 if (datadm_locate_dat_conf(basedir)) { 1772 return (1); 1773 } 1774 1775 retval = (*datadm_ops[op_type])(); 1776 return (retval); 1777 } 1778