1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <unistd.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <sys/sockio.h> 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 #include <net/if.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <strings.h> 39 #include <ctype.h> 40 #include <errno.h> 41 #include <libintl.h> 42 #include <locale.h> 43 #include <libdevinfo.h> 44 45 #define DATADM_OP_VIEW 0x0000 46 #define DATADM_OP_UPDATE 0x0001 47 #define DATADM_OP_ADD 0x0002 48 #define DATADM_OP_REMOVE 0x0003 49 #define DATADM_NUM_OPS 0x0004 50 #define DATADM_DAT_CONF "/etc/dat/dat.conf" 51 #define DATADM_LINESZ 1024 52 #define DATADM_NUM_SP_TOKENS 7 53 #define DATADM_NUM_DAT_TOKENS 8 54 #define DATADM_IA_NAME "ibd" 55 #define DATADM_DRV_NAME "driver_name" 56 #define DATADM_MAX_TOKENS 16 57 58 /* 59 * generic entry 60 * placed at the top of all entry types 61 */ 62 typedef struct datadm_entry { 63 struct datadm_entry *de_next; 64 } datadm_entry_t; 65 66 /* 67 * list structure 68 * can be manipulated using datadm_walk_list or 69 * datadm_enqueue_entry 70 */ 71 typedef struct datadm_list { 72 datadm_entry_t *dl_head; 73 datadm_entry_t *dl_tail; 74 uint_t dl_count; 75 } datadm_list_t; 76 77 /* 78 * internal representation of the version string in 79 * dat.conf or service_provider.conf. the format is 80 * <dv_name><dv_major>.<dv_minor> 81 */ 82 typedef struct datadm_version { 83 char *dv_name; 84 uint_t dv_major; 85 uint_t dv_minor; 86 } datadm_version_t; 87 88 /* 89 * each sp_entry corresponds to an entry in dat.conf or 90 * service_provider.conf. an sp_entry is processed by the 91 * function datadm_process_sp_entry. 92 */ 93 typedef struct datadm_sp_entry { 94 datadm_entry_t spe_header; 95 char *spe_devname; 96 datadm_version_t spe_api_version; 97 int spe_threadsafe; 98 int spe_default; 99 char *spe_libpath; 100 datadm_version_t spe_sp_version; 101 char *spe_sp_data; 102 int spe_invalid; 103 } datadm_sp_entry_t; 104 105 /* 106 * an hca_entry is created whenever a new hca device is 107 * encountered during sp_entry processing. this structure 108 * contains two lists. the sp_list holds sp entries that 109 * are added when sp entry processing occurs. duplicate 110 * sp entries are not added to this list. the ia_list may 111 * be built statically using the information in dat.conf or 112 * dynamically using libdevinfo. similar to the sp_list, 113 * the ia_list contains only unique entries. 114 */ 115 typedef struct datadm_hca_entry { 116 datadm_entry_t he_header; 117 char *he_name; 118 datadm_list_t he_sp_list; 119 datadm_list_t he_ia_list; 120 } datadm_hca_entry_t; 121 122 /* 123 * an ia_entry is created when a new ia name is encountered 124 * during sp_entry processing or when a new ia name is 125 * discovered by datadm_fill_ia_list. ia_entry holds the ia 126 * device's instance number. 127 */ 128 typedef struct datadm_ia_entry { 129 datadm_entry_t iae_header; 130 int iae_devnum; 131 } datadm_ia_entry_t; 132 133 /* 134 * a comment entry represents one of the comment lines at the 135 * top of dat.conf. a list of these lines are saved during the 136 * parsing of dat.conf. these lines are written back to dat.conf 137 * when dat.conf gets regenerated. 138 */ 139 typedef struct datadm_cmnt_entry { 140 datadm_entry_t cmnt_header; 141 char *cmnt_line; 142 } datadm_cmnt_entry_t; 143 144 /* 145 * 2nd argument to datadm_hca_entry_find. 146 * hf_hca_entry is filled in if an hca_entry with 147 * a matching he_name is found. 148 */ 149 typedef struct datadm_hca_find { 150 datadm_sp_entry_t *hf_sp_entry; 151 datadm_hca_entry_t *hf_hca_entry; 152 } datadm_hca_find_t; 153 154 /* 155 * 2nd argument to datadm_ia_entry_find. 156 * if_ia_entry is filled in if an ia_entry with 157 * a matching ia_devnum is found. 158 */ 159 typedef struct datadm_ia_find { 160 int if_ia_devnum; 161 datadm_ia_entry_t *if_ia_entry; 162 } datadm_ia_find_t; 163 164 /* 165 * this gets passed to datadm_fill_ia_list. 166 * we do this to avoid regenerating the device 167 * tree for each hca_entry we process. 168 */ 169 typedef struct datadm_fill_ia_list { 170 di_node_t ia_root_node; 171 int ia_sock_fd_v4; 172 int ia_sock_fd_v6; 173 } datadm_fill_ia_list_t; 174 175 /* 176 * this defines the commandline parameters specified 177 * by the user. 178 */ 179 typedef struct datadm_args { 180 char *da_sp_conf; 181 char *da_dat_conf; 182 int da_op_type; 183 } datadm_args_t; 184 185 static datadm_args_t datadm_args; 186 static datadm_list_t datadm_conf_header; 187 static char *datadm_conf_header_default = 188 "#\n" 189 "# Copyright 2004 Sun Microsystems, Inc. All rights reserved.\n" 190 "# Use is subject to license terms.\n" 191 "#\n" 192 "# ident \"@(#)dat.conf 1.1 03/08/26 SMI\"\n" 193 "#\n" 194 "# DAT configuration file.\n" 195 "#\n" 196 "# This file is updated using the datadm(1) command.\n" 197 "# Do not hand edit this file.\n" 198 "# See datadm(1) man page for more details.\n" 199 "#\n" 200 "# The fields in this file are -\n" 201 "#\n" 202 "# IAname version threadsafe default library-path provider-version \\\n" 203 "# instance-data platform-information\n" 204 "#\n"; 205 206 /* 207 * common parsing functions. 208 */ 209 typedef int (*datadm_parse_func_t)(char *, void *); 210 static int datadm_parse_line(char *, char *[], int *); 211 static int datadm_parse_generic_str(char *, char **); 212 static int datadm_parse_nonnull_str(char *, char **); 213 static int datadm_parse_version(char *, datadm_version_t *); 214 static int datadm_parse_devname(char *, datadm_sp_entry_t *); 215 static int datadm_parse_api_version(char *, datadm_sp_entry_t *); 216 static int datadm_parse_threadsafe(char *, datadm_sp_entry_t *); 217 static int datadm_parse_default(char *, datadm_sp_entry_t *); 218 static int datadm_parse_libpath(char *, datadm_sp_entry_t *); 219 static int datadm_parse_sp_version(char *, datadm_sp_entry_t *); 220 static int datadm_parse_sp_data(char *, datadm_sp_entry_t *); 221 static int datadm_parse_ia_name(char *, int *); 222 223 /* 224 * utility functions 225 */ 226 static void datadm_enqueue_entry(datadm_list_t *, datadm_entry_t *); 227 static int datadm_walk_list(datadm_list_t *, 228 int (*)(datadm_entry_t *, void *), void *); 229 static int datadm_str_match(char *, char *); 230 static int datadm_version_match(datadm_version_t *, datadm_version_t *); 231 static int datadm_sp_entry_match(datadm_sp_entry_t *, datadm_sp_entry_t *); 232 233 /* 234 * entry allocation/deallocation 235 */ 236 static datadm_sp_entry_t *datadm_alloc_sp_entry(void); 237 static datadm_ia_entry_t *datadm_alloc_ia_entry(void); 238 static datadm_hca_entry_t *datadm_alloc_hca_entry(void); 239 static datadm_cmnt_entry_t *datadm_alloc_cmnt_entry(void); 240 static void datadm_free_sp_entry(datadm_sp_entry_t *); 241 static void datadm_free_ia_entry(datadm_ia_entry_t *); 242 static void datadm_free_hca_entry(datadm_hca_entry_t *); 243 static void datadm_free_cmnt_entry(datadm_cmnt_entry_t *); 244 245 246 /* 247 * high level parsing functions 248 */ 249 static int datadm_parse_sp_conf(datadm_list_t *); 250 static int datadm_parse_dat_conf(datadm_list_t *); 251 static int datadm_process_sp_entry(datadm_list_t *, datadm_sp_entry_t *, int); 252 253 /* 254 * ia devices discovery 255 */ 256 static int datadm_build_ia_lists(datadm_list_t *); 257 static int datadm_fill_ia_list(datadm_hca_entry_t *, datadm_fill_ia_list_t *); 258 259 /* 260 * helper function for OP_REMOVE 261 */ 262 static void datadm_invalidate_common_sp_entries(datadm_list_t *, 263 datadm_list_t *); 264 265 /* 266 * output generation 267 */ 268 static int datadm_generate_dat_conf(datadm_list_t *); 269 static int datadm_generate_conf_header(FILE *); 270 static int datadm_generate_conf_entry(FILE *, datadm_ia_entry_t *, 271 datadm_sp_entry_t *); 272 273 /* 274 * datadm operations 275 */ 276 static int datadm_view(void); 277 static int datadm_update(void); 278 static int datadm_add(void); 279 static int datadm_remove(void); 280 281 /* 282 * usage 283 */ 284 static void datadm_usage(void); 285 286 287 /* 288 * parse function tables 289 */ 290 static datadm_parse_func_t datadm_sp_parse_funcs[DATADM_NUM_SP_TOKENS] = { 291 (datadm_parse_func_t)datadm_parse_devname, 292 (datadm_parse_func_t)datadm_parse_api_version, 293 (datadm_parse_func_t)datadm_parse_threadsafe, 294 (datadm_parse_func_t)datadm_parse_default, 295 (datadm_parse_func_t)datadm_parse_libpath, 296 (datadm_parse_func_t)datadm_parse_sp_version, 297 (datadm_parse_func_t)datadm_parse_sp_data 298 }; 299 300 static datadm_parse_func_t datadm_dat_parse_funcs[DATADM_NUM_DAT_TOKENS] = { 301 (datadm_parse_func_t)datadm_parse_ia_name, 302 (datadm_parse_func_t)datadm_parse_api_version, 303 (datadm_parse_func_t)datadm_parse_threadsafe, 304 (datadm_parse_func_t)datadm_parse_default, 305 (datadm_parse_func_t)datadm_parse_libpath, 306 (datadm_parse_func_t)datadm_parse_sp_version, 307 (datadm_parse_func_t)datadm_parse_sp_data, 308 (datadm_parse_func_t)datadm_parse_devname 309 }; 310 311 /* 312 * operation table 313 */ 314 static int (*datadm_ops[DATADM_NUM_OPS])(void) = { 315 datadm_view, 316 datadm_update, 317 datadm_add, 318 datadm_remove 319 }; 320 321 static void 322 datadm_usage(void) 323 { 324 (void) fprintf(stderr, gettext( 325 "usage: datadm -v\n" 326 " -u\n" 327 " -a <service_provider.conf>\n" 328 " -r <service_provider.conf>\n")); 329 } 330 331 static int 332 datadm_parse_generic_str(char *str, char **strptr) 333 { 334 int len; 335 336 len = strlen(str); 337 *strptr = (char *)malloc(len + 1); 338 if (*strptr == NULL) { 339 return (-1); 340 } 341 (void) strcpy(*strptr, str); 342 return (0); 343 } 344 345 /* 346 * this function strips off leading and trailing 347 * whitespaces and returns an error for null or 348 * empty strings. 349 */ 350 static int 351 datadm_parse_nonnull_str(char *str, char **strptr) 352 { 353 int len, i; 354 char *start; 355 356 if (str[0] == '\0') { 357 return (-1); 358 } 359 start = str; 360 for (i = 0; str[i] != '\0'; i++) { 361 if (!isspace(str[i])) { 362 start = &str[i]; 363 break; 364 } 365 } 366 for (; str[i] != '\0'; i++) { 367 if (isspace(str[i])) { 368 str[i] = '\0'; 369 } 370 } 371 len = strlen(start); 372 *strptr = (char *)malloc(len + 1); 373 if (*strptr == NULL) { 374 return (-1); 375 } 376 (void) strcpy(*strptr, start); 377 return (0); 378 } 379 380 /* 381 * parses the api_version and sp_version fields in 382 * dat.conf and service_provider.conf 383 */ 384 static int 385 datadm_parse_version(char *str, datadm_version_t *version) 386 { 387 int i = 0, len; 388 int major_idx, minor_idx; 389 390 len = strlen(str); 391 392 for (i = 0; i < len; i++) { 393 if (isdigit(str[i])) break; 394 } 395 if (i == len) { 396 return (-1); 397 } 398 if (i > 0) { 399 version->dv_name = (char *)malloc(i + 1); 400 bcopy(str, version->dv_name, i); 401 version->dv_name[i] = '\0'; 402 } else { 403 version->dv_name = NULL; 404 } 405 major_idx = i; 406 407 for (; i < len; i++) { 408 if (!isdigit(str[i])) break; 409 } 410 if (i == len) { 411 return (-1); 412 } 413 if (str[i] != '.') { 414 return (-1); 415 } 416 minor_idx = ++i; 417 if (i == len) { 418 return (-1); 419 } 420 for (; i < len; i++) { 421 if (!isdigit(str[i])) break; 422 } 423 if (i != len) { 424 return (-1); 425 } 426 version->dv_major = atoi(str + major_idx); 427 version->dv_minor = atoi(str + minor_idx); 428 return (0); 429 } 430 431 /* 432 * parses the ia_name field in dat.conf 433 */ 434 static int 435 datadm_parse_ia_name(char *str, int *ia_devnum) 436 { 437 int len; 438 int i, start; 439 440 len = strlen(DATADM_IA_NAME); 441 if (strncmp(str, DATADM_IA_NAME, len) != 0) { 442 return (-1); 443 } 444 start = i = len; 445 len = strlen(str); 446 if (str[i] == '\0') { 447 return (-1); 448 } 449 for (; i < len; i++) { 450 if (!isdigit(str[i])) break; 451 } 452 if (i != len) { 453 return (-1); 454 } 455 *ia_devnum = atoi(str + start); 456 return (0); 457 } 458 459 /* 460 * parses the device name, strips leading and trailing spaces. 461 * the format should be "driver_name=<dev_name>" 462 */ 463 static int 464 datadm_parse_devname(char *str, datadm_sp_entry_t *sp_entry) 465 { 466 int len, dlen, i, j = 0; 467 char *drv_name = DATADM_DRV_NAME; 468 469 len = strlen(str); 470 dlen = strlen(drv_name); 471 472 /* 473 * strip out leading spaces and try to match 474 * the expected string 475 */ 476 for (i = 0; i < len; i++) { 477 if (isspace(str[i]) && j == 0) { 478 continue; 479 } else { 480 if (str[i] == drv_name[j]) { 481 j++; 482 if (j == dlen) { 483 break; 484 } else { 485 continue; 486 } 487 } else { 488 break; 489 } 490 } 491 } 492 493 /* 494 * j must be dlen if the matching string is found 495 */ 496 if (j != dlen) { 497 return (-1); 498 } 499 500 /* 501 * skip past the last char of drv_name 502 */ 503 i++; 504 505 /* 506 * strip the spaces before the '=' 507 */ 508 for (; i < len; i++) { 509 if (!isspace(str[i])) { 510 break; 511 } 512 } 513 514 /* 515 * return if the string is too long or if 516 * the '=' isn't found 517 */ 518 if (i >= len || str[i] != '=') { 519 return (-1); 520 } 521 i++; 522 if (i >= len) { 523 /* 524 * no string after the equal 525 */ 526 return (-1); 527 } 528 return (datadm_parse_nonnull_str(str + i, &sp_entry->spe_devname)); 529 } 530 531 static int 532 datadm_parse_api_version(char *str, datadm_sp_entry_t *sp_entry) 533 { 534 return (datadm_parse_version(str, &sp_entry->spe_api_version)); 535 } 536 537 static int 538 datadm_parse_threadsafe(char *str, datadm_sp_entry_t *sp_entry) 539 { 540 int retval = 0; 541 542 if (strcmp(str, "threadsafe") == 0) { 543 sp_entry->spe_threadsafe = 1; 544 } else if (strcmp(str, "nonthreadsafe") == 0) { 545 sp_entry->spe_threadsafe = 0; 546 } else { 547 retval = -1; 548 } 549 return (retval); 550 } 551 552 static int 553 datadm_parse_default(char *str, datadm_sp_entry_t *sp_entry) 554 { 555 int retval = 0; 556 557 if (strcmp(str, "default") == 0) { 558 sp_entry->spe_default = 1; 559 } else if (strcmp(str, "nondefault") == 0) { 560 sp_entry->spe_default = 0; 561 } else { 562 retval = -1; 563 } 564 return (retval); 565 } 566 567 static int 568 datadm_parse_libpath(char *str, datadm_sp_entry_t *sp_entry) 569 { 570 return (datadm_parse_nonnull_str(str, &sp_entry->spe_libpath)); 571 } 572 573 static int 574 datadm_parse_sp_version(char *str, datadm_sp_entry_t *sp_entry) 575 { 576 return (datadm_parse_version(str, &sp_entry->spe_sp_version)); 577 } 578 579 static int 580 datadm_parse_sp_data(char *str, datadm_sp_entry_t *sp_entry) 581 { 582 return (datadm_parse_generic_str(str, &sp_entry->spe_sp_data)); 583 } 584 585 static void 586 datadm_enqueue_entry(datadm_list_t *list, datadm_entry_t *entry) 587 { 588 if (list->dl_head == NULL) { 589 list->dl_head = entry; 590 list->dl_tail = entry; 591 list->dl_count = 1; 592 } else { 593 list->dl_tail->de_next = entry; 594 list->dl_tail = entry; 595 list->dl_count++; 596 } 597 } 598 599 /* 600 * iterates through the list applying func on each element. 601 * break and return if func returns non-zero. 602 */ 603 static int 604 datadm_walk_list(datadm_list_t *list, int (*func)(datadm_entry_t *, void *), 605 void *arg) 606 { 607 datadm_entry_t *entry; 608 int retval = 0; 609 610 entry = list->dl_head; 611 while (entry != NULL) { 612 retval = (*func)(entry, arg); 613 if (retval != 0) break; 614 entry = entry->de_next; 615 } 616 return (retval); 617 } 618 619 /* 620 * iterates through the list applying free_func to each element. 621 * list becomes empty when the function returns. 622 */ 623 static void 624 datadm_free_list(datadm_list_t *list, void (*free_func)(datadm_entry_t *)) 625 { 626 while (list->dl_head != NULL) { 627 datadm_entry_t *entry; 628 629 entry = list->dl_head; 630 list->dl_head = entry->de_next; 631 (*free_func)(entry); 632 } 633 list->dl_count = 0; 634 list->dl_tail = NULL; 635 } 636 637 static datadm_sp_entry_t * 638 datadm_alloc_sp_entry(void) 639 { 640 datadm_sp_entry_t *sp_entry; 641 642 sp_entry = (datadm_sp_entry_t *)malloc(sizeof (*sp_entry)); 643 if (sp_entry == NULL) { 644 return (NULL); 645 } 646 bzero(sp_entry, sizeof (*sp_entry)); 647 return (sp_entry); 648 } 649 650 static void 651 datadm_free_sp_entry(datadm_sp_entry_t *sp_entry) 652 { 653 if (sp_entry->spe_devname != NULL) { 654 free(sp_entry->spe_devname); 655 sp_entry->spe_devname = NULL; 656 } 657 if (sp_entry->spe_api_version.dv_name != NULL) { 658 free(sp_entry->spe_api_version.dv_name); 659 sp_entry->spe_api_version.dv_name = NULL; 660 } 661 sp_entry->spe_api_version.dv_major = 0; 662 sp_entry->spe_api_version.dv_minor = 0; 663 sp_entry->spe_threadsafe = 0; 664 sp_entry->spe_default = 0; 665 if (sp_entry->spe_libpath != NULL) { 666 free(sp_entry->spe_libpath); 667 sp_entry->spe_libpath = NULL; 668 } 669 if (sp_entry->spe_sp_version.dv_name != NULL) { 670 free(sp_entry->spe_sp_version.dv_name); 671 sp_entry->spe_sp_version.dv_name = NULL; 672 } 673 sp_entry->spe_sp_version.dv_major = 0; 674 sp_entry->spe_sp_version.dv_minor = 0; 675 if (sp_entry->spe_sp_data != NULL) { 676 free(sp_entry->spe_sp_data); 677 sp_entry->spe_sp_data = NULL; 678 } 679 free(sp_entry); 680 } 681 682 static int 683 datadm_str_match(char *s1, char *s2) 684 { 685 if (s1 == NULL || s2 == NULL) { 686 if (s1 != s2) { 687 return (0); 688 } 689 } else { 690 if (strcmp(s1, s2) != 0) { 691 return (0); 692 } 693 } 694 return (1); 695 } 696 697 static int 698 datadm_version_match(datadm_version_t *v1, datadm_version_t *v2) 699 { 700 if (!datadm_str_match(v1->dv_name, v2->dv_name)) { 701 return (0); 702 } 703 if (v1->dv_major != v2->dv_major) { 704 return (0); 705 } 706 if (v1->dv_minor != v2->dv_minor) { 707 return (0); 708 } 709 return (1); 710 } 711 712 static int 713 datadm_sp_entry_match(datadm_sp_entry_t *sp1, datadm_sp_entry_t *sp2) 714 { 715 if (!datadm_str_match(sp1->spe_devname, sp2->spe_devname)) { 716 return (0); 717 } 718 if (!datadm_version_match(&sp1->spe_api_version, 719 &sp2->spe_api_version)) { 720 return (0); 721 } 722 if (sp1->spe_threadsafe != sp2->spe_threadsafe) { 723 return (0); 724 } 725 if (sp2->spe_default != sp2->spe_default) { 726 return (0); 727 } 728 if (!datadm_str_match(sp1->spe_libpath, sp2->spe_libpath)) { 729 return (0); 730 } 731 if (!datadm_version_match(&sp1->spe_sp_version, 732 &sp2->spe_sp_version)) { 733 return (0); 734 } 735 if (!datadm_str_match(sp1->spe_sp_data, sp2->spe_sp_data)) { 736 return (0); 737 } 738 return (1); 739 } 740 741 static datadm_ia_entry_t * 742 datadm_alloc_ia_entry(void) 743 { 744 datadm_ia_entry_t *ia_entry; 745 746 ia_entry = (datadm_ia_entry_t *)malloc(sizeof (*ia_entry)); 747 if (ia_entry == NULL) { 748 return (NULL); 749 } 750 bzero(ia_entry, sizeof (*ia_entry)); 751 return (ia_entry); 752 } 753 754 static void 755 datadm_free_ia_entry(datadm_ia_entry_t *ia_entry) 756 { 757 free(ia_entry); 758 } 759 760 static datadm_hca_entry_t * 761 datadm_alloc_hca_entry(void) 762 { 763 datadm_hca_entry_t *hca_entry; 764 765 hca_entry = (datadm_hca_entry_t *)malloc(sizeof (*hca_entry)); 766 if (hca_entry == NULL) { 767 return (NULL); 768 } 769 bzero(hca_entry, sizeof (*hca_entry)); 770 return (hca_entry); 771 } 772 773 static void 774 datadm_free_hca_entry(datadm_hca_entry_t *hca_entry) 775 { 776 if (hca_entry->he_name != NULL) { 777 free(hca_entry->he_name); 778 hca_entry->he_name = NULL; 779 } 780 datadm_free_list(&hca_entry->he_sp_list, 781 (void (*)(datadm_entry_t *))datadm_free_sp_entry); 782 datadm_free_list(&hca_entry->he_ia_list, 783 (void (*)(datadm_entry_t *))datadm_free_ia_entry); 784 free(hca_entry); 785 } 786 787 static int 788 datadm_hca_entry_match(datadm_hca_entry_t *h1, datadm_hca_entry_t *h2) 789 { 790 if (!datadm_str_match(h1->he_name, h2->he_name)) { 791 return (0); 792 } 793 return (1); 794 } 795 796 static int 797 datadm_hca_entry_find(datadm_hca_entry_t *h1, datadm_hca_find_t *hf) 798 { 799 if (datadm_str_match(h1->he_name, hf->hf_sp_entry->spe_devname)) { 800 hf->hf_hca_entry = h1; 801 return (1); 802 } 803 return (0); 804 } 805 806 static int 807 datadm_ia_entry_find(datadm_ia_entry_t *i1, datadm_ia_find_t *iaf) 808 { 809 if (i1->iae_devnum == iaf->if_ia_devnum) { 810 iaf->if_ia_entry = i1; 811 return (1); 812 } 813 return (0); 814 } 815 816 static datadm_cmnt_entry_t * 817 datadm_alloc_cmnt_entry(void) 818 { 819 datadm_cmnt_entry_t *cmnt_entry; 820 821 cmnt_entry = (datadm_cmnt_entry_t *)malloc(sizeof (*cmnt_entry)); 822 if (cmnt_entry == NULL) { 823 return (NULL); 824 } 825 bzero(cmnt_entry, sizeof (*cmnt_entry)); 826 return (cmnt_entry); 827 } 828 829 static void 830 datadm_free_cmnt_entry(datadm_cmnt_entry_t *cmnt_entry) 831 { 832 if (cmnt_entry->cmnt_line != NULL) { 833 free(cmnt_entry->cmnt_line); 834 cmnt_entry->cmnt_line = NULL; 835 } 836 free(cmnt_entry); 837 } 838 839 /* 840 * tokenizes a line and strips off the quotes from quoted strings 841 */ 842 static int 843 datadm_parse_line(char *line_buf, char *tokens[], int *token_count) 844 { 845 int len, i; 846 int count = 0; 847 char *start = NULL; 848 849 /* the line must not be longer than DATADM_LINESZ */ 850 len = strlen(line_buf); 851 if (line_buf[len - 1] != '\n') { 852 return (-1); 853 } 854 /* discard blank lines and comments */ 855 if (len == 1) { 856 *token_count = 0; 857 return (0); 858 } 859 if (len >= 2 && line_buf[0] == '#') { 860 *token_count = 0; 861 return (0); 862 } 863 /* removes the new line */ 864 line_buf[len - 1] = '\0'; 865 len--; 866 867 for (i = 0; i < len; i++) { 868 if (start != NULL) { 869 /* 870 * start points to the start of 871 * a new token. if start is '"', 872 * we should expect a quoted 873 * string. 874 */ 875 if (*start == '\"') { 876 /* 877 * keep scanning until we 878 * hit the end quote. 879 */ 880 if (line_buf[i] != '\"') { 881 continue; 882 } 883 /* 884 * skip past the start quote 885 */ 886 start++; 887 } else { 888 /* 889 * our token is not a quoted 890 * string. our token ends only 891 * when we hit a whitespace. 892 */ 893 if (!isspace(line_buf[i])) { 894 continue; 895 } 896 } 897 /* 898 * nullify the end quote (if any) 899 * and update the tokens array. 900 */ 901 line_buf[i] = '\0'; 902 tokens[count] = start; 903 start = NULL; 904 count++; 905 } else { 906 /* 907 * skip whitespaces 908 */ 909 if (isspace(line_buf[i])) { 910 continue; 911 } else { 912 start = &line_buf[i]; 913 } 914 } 915 if (count == DATADM_MAX_TOKENS) { 916 start = NULL; 917 break; 918 } 919 } 920 if (start != NULL) { 921 tokens[count] = start; 922 start = NULL; 923 count++; 924 } 925 *token_count = count; 926 return (0); 927 } 928 929 /* 930 * attempts to save sp_entry into hca_list. 931 * becomes no-op if sp entry already exists. 932 * new hca entries and ia entries are created as needed. 933 */ 934 static int 935 datadm_process_sp_entry(datadm_list_t *hca_list, datadm_sp_entry_t *sp_entry, 936 int ia_devnum) 937 { 938 datadm_hca_find_t hca_find; 939 datadm_ia_find_t ia_find; 940 datadm_hca_entry_t *hca_entry; 941 942 hca_find.hf_sp_entry = sp_entry; 943 hca_find.hf_hca_entry = NULL; 944 (void) datadm_walk_list(hca_list, (int (*)(datadm_entry_t *, void *)) 945 datadm_hca_entry_find, (void *)&hca_find); 946 947 if (hca_find.hf_hca_entry == NULL) { 948 int dlen; 949 950 /* 951 * hca_entry not found, need to create 952 * and insert one. 953 */ 954 hca_entry = datadm_alloc_hca_entry(); 955 if (hca_entry == NULL) { 956 return (-1); 957 } 958 dlen = strlen(sp_entry->spe_devname); 959 hca_entry->he_name = (char *)malloc(dlen + 1); 960 if (hca_entry->he_name == NULL) { 961 datadm_free_hca_entry(hca_entry); 962 return (-1); 963 } 964 (void) strcpy(hca_entry->he_name, sp_entry->spe_devname); 965 datadm_enqueue_entry(hca_list, (datadm_entry_t *)hca_entry); 966 } else { 967 hca_entry = hca_find.hf_hca_entry; 968 } 969 if (ia_devnum == -1) { 970 goto put_sp_entry; 971 } 972 ia_find.if_ia_devnum = ia_devnum; 973 ia_find.if_ia_entry = NULL; 974 (void) datadm_walk_list(&hca_entry->he_ia_list, 975 (int (*)(datadm_entry_t *, void *))datadm_ia_entry_find, &ia_find); 976 977 if (ia_find.if_ia_entry == NULL) { 978 datadm_ia_entry_t *ia_entry; 979 980 /* 981 * ia_entry not found, need to create 982 * and insert one. 983 */ 984 ia_entry = datadm_alloc_ia_entry(); 985 if (ia_entry == NULL) { 986 return (-1); 987 } 988 ia_entry->iae_devnum = ia_devnum; 989 datadm_enqueue_entry(&hca_entry->he_ia_list, 990 (datadm_entry_t *)ia_entry); 991 } 992 993 put_sp_entry:; 994 995 if (datadm_walk_list(&hca_entry->he_sp_list, 996 (int (*)(datadm_entry_t *, void *))datadm_sp_entry_match, 997 (void *)sp_entry)) { 998 return (1); 999 } else { 1000 /* 1001 * only insert sp_entry if it is not found. 1002 */ 1003 datadm_enqueue_entry(&hca_entry->he_sp_list, 1004 (datadm_entry_t *)sp_entry); 1005 } 1006 return (0); 1007 } 1008 1009 /* 1010 * parses service_provider.conf 1011 */ 1012 static int 1013 datadm_parse_sp_conf(datadm_list_t *hca_list) 1014 { 1015 datadm_sp_entry_t *sp_entry; 1016 FILE *sp_file; 1017 char *sp_conf = datadm_args.da_sp_conf; 1018 char *tokens[DATADM_MAX_TOKENS]; 1019 char line_buf[DATADM_LINESZ]; 1020 int retval = 0; 1021 int token_count = 0; 1022 int line_count = 0; 1023 1024 sp_file = fopen(sp_conf, "r"); 1025 if (sp_file == NULL) { 1026 (void) fprintf(stderr, 1027 gettext("datadm: cannot open %s\n"), sp_conf); 1028 return (-1); 1029 } 1030 1031 for (;;) { 1032 bzero(line_buf, DATADM_LINESZ); 1033 if (fgets(line_buf, DATADM_LINESZ, sp_file) == NULL) { 1034 break; 1035 } 1036 token_count = 0; 1037 line_count++; 1038 retval = datadm_parse_line(line_buf, tokens, &token_count); 1039 if (retval != 0) { 1040 (void) fprintf(stderr, gettext( 1041 "datadm: %s: line %d exceeded max length %d\n"), 1042 sp_conf, line_count, DATADM_LINESZ); 1043 break; 1044 } 1045 if (token_count == 0) continue; 1046 if (token_count == DATADM_NUM_SP_TOKENS) { 1047 int i = 0; 1048 1049 sp_entry = datadm_alloc_sp_entry(); 1050 if (sp_entry == NULL) { 1051 retval = -1; 1052 break; 1053 } 1054 1055 /* 1056 * sp_entry gets filled incrementally by 1057 * each parsing function 1058 */ 1059 for (i = 0; i < DATADM_NUM_SP_TOKENS && 1060 retval == 0; i++) { 1061 retval = (*datadm_sp_parse_funcs[i]) 1062 (tokens[i], (void *)sp_entry); 1063 } 1064 if (retval != 0) { 1065 (void) fprintf(stderr, gettext( 1066 "datadm: parse error: %s, " 1067 "line %d, token: %s\n"), 1068 sp_conf, line_count, tokens[i - 1]); 1069 datadm_free_sp_entry(sp_entry); 1070 sp_entry = NULL; 1071 break; 1072 } 1073 1074 retval = datadm_process_sp_entry(hca_list, 1075 sp_entry, -1); 1076 if (retval != 0) { 1077 datadm_free_sp_entry(sp_entry); 1078 if (retval == 1) { 1079 retval = 0; 1080 } else { 1081 break; 1082 } 1083 } 1084 } else { 1085 (void) fprintf(stderr, gettext( 1086 "datadm: parse error: %s, line %d, " 1087 "# of tokens: %d, expected %d\n"), sp_conf, 1088 line_count, token_count, DATADM_NUM_SP_TOKENS); 1089 retval = -1; 1090 break; 1091 } 1092 } 1093 if (retval != 0) { 1094 datadm_free_list(hca_list, 1095 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1096 } 1097 (void) fclose(sp_file); 1098 return (retval); 1099 } 1100 1101 /* 1102 * parses dat.conf 1103 */ 1104 static int 1105 datadm_parse_dat_conf(datadm_list_t *hca_list) 1106 { 1107 boolean_t save_header = B_TRUE; 1108 datadm_sp_entry_t *sp_entry; 1109 FILE *dat_file; 1110 char *dat_conf = datadm_args.da_dat_conf; 1111 char *tokens[DATADM_MAX_TOKENS]; 1112 char line_buf[DATADM_LINESZ]; 1113 int retval = 0; 1114 int token_count = 0; 1115 int line_count = 0; 1116 1117 dat_file = fopen(dat_conf, "r"); 1118 if (dat_file == NULL) { 1119 /* dat.conf not existing is not an error for OP_ADD */ 1120 if (datadm_args.da_op_type == DATADM_OP_ADD) { 1121 return (0); 1122 } 1123 (void) fprintf(stderr, gettext("datadm: cannot open %s\n"), 1124 dat_conf); 1125 return (-1); 1126 } 1127 1128 for (;;) { 1129 bzero(line_buf, DATADM_LINESZ); 1130 if (fgets(line_buf, DATADM_LINESZ, dat_file) == NULL) { 1131 break; 1132 } 1133 token_count = 0; 1134 line_count++; 1135 retval = datadm_parse_line(line_buf, tokens, &token_count); 1136 if (retval != 0) { 1137 (void) fprintf(stderr, gettext( 1138 "datadm: %s: line %d exceeded max length %d\n"), 1139 dat_conf, line_count, DATADM_LINESZ); 1140 break; 1141 } 1142 if (token_count == 0) { 1143 datadm_cmnt_entry_t *cmnt_entry; 1144 int cmnt_len; 1145 1146 /* 1147 * comments are saved only if they are 1148 * at the top of dat.conf. 1149 */ 1150 if (!save_header) continue; 1151 cmnt_entry = datadm_alloc_cmnt_entry(); 1152 if (cmnt_entry == NULL) { 1153 perror("datadm: malloc"); 1154 retval = -1; 1155 break; 1156 } 1157 cmnt_len = strlen(line_buf); 1158 cmnt_entry->cmnt_line = (char *)malloc(cmnt_len + 1); 1159 if (cmnt_entry->cmnt_line == NULL) { 1160 perror("datadm: malloc"); 1161 datadm_free_cmnt_entry(cmnt_entry); 1162 retval = -1; 1163 break; 1164 } 1165 (void) strncpy(cmnt_entry->cmnt_line, 1166 line_buf, cmnt_len); 1167 cmnt_entry->cmnt_line[cmnt_len] = '\0'; 1168 datadm_enqueue_entry(&datadm_conf_header, 1169 (datadm_entry_t *)cmnt_entry); 1170 continue; 1171 } 1172 if (token_count == DATADM_NUM_DAT_TOKENS) { 1173 int i = 0; 1174 int ia_devnum = -1; 1175 1176 /* 1177 * we stop saving comment lines once 1178 * we see the first valid line. 1179 */ 1180 save_header = B_FALSE; 1181 sp_entry = datadm_alloc_sp_entry(); 1182 if (sp_entry == NULL) { 1183 retval = -1; 1184 break; 1185 } 1186 1187 /* 1188 * sp_entry gets filled incrementally by 1189 * each parsing function 1190 */ 1191 for (i = 0; i < DATADM_NUM_DAT_TOKENS && 1192 retval == 0; i++) { 1193 void *arg; 1194 1195 if (i == 0) { 1196 /* 1197 * the first token (ia name) 1198 * does not belong to an 1199 * sp_entry 1200 */ 1201 arg = (void *)&ia_devnum; 1202 } else { 1203 arg = (void *)sp_entry; 1204 } 1205 retval = (*datadm_dat_parse_funcs[i]) 1206 (tokens[i], arg); 1207 } 1208 if (retval != 0) { 1209 (void) fprintf(stderr, gettext( 1210 "datadm: parse error: %s, " 1211 "line %d, token: %s\n"), dat_conf, 1212 line_count, tokens[i - 1]); 1213 datadm_free_sp_entry(sp_entry); 1214 sp_entry = NULL; 1215 break; 1216 } 1217 1218 /* 1219 * we ignore the ibds in dat.conf if we are 1220 * doing update 1221 */ 1222 if (datadm_args.da_op_type == DATADM_OP_UPDATE) { 1223 ia_devnum = -1; 1224 } 1225 retval = datadm_process_sp_entry(hca_list, sp_entry, 1226 ia_devnum); 1227 if (retval != 0) { 1228 datadm_free_sp_entry(sp_entry); 1229 if (retval == 1) { 1230 retval = 0; 1231 } else { 1232 break; 1233 } 1234 } 1235 } else { 1236 (void) fprintf(stderr, gettext( 1237 "datadm: parse error: %s, line %d, " 1238 "# of tokens: %d, expected %d\n"), dat_conf, 1239 line_count, token_count, DATADM_NUM_DAT_TOKENS); 1240 retval = -1; 1241 break; 1242 } 1243 } 1244 if (retval != 0) { 1245 datadm_free_list(&datadm_conf_header, 1246 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1247 datadm_free_list(hca_list, 1248 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1249 } 1250 (void) fclose(dat_file); 1251 return (retval); 1252 } 1253 1254 /* 1255 * discovers all ibd devices under a particular hca 1256 */ 1257 static int 1258 datadm_fill_ia_list(datadm_hca_entry_t *hca, datadm_fill_ia_list_t *args) 1259 { 1260 di_node_t root_node; 1261 di_node_t hca_node; 1262 int retval = 0; 1263 int sv4, sv6; 1264 1265 root_node = args->ia_root_node; 1266 sv4 = args->ia_sock_fd_v4; 1267 sv6 = args->ia_sock_fd_v6; 1268 1269 hca_node = di_drv_first_node(hca->he_name, root_node); 1270 if (hca_node == DI_NODE_NIL) { 1271 return (0); 1272 } 1273 while (hca_node != DI_NODE_NIL) { 1274 di_node_t ibd_node; 1275 1276 ibd_node = di_drv_first_node(DATADM_IA_NAME, hca_node); 1277 while (ibd_node != DI_NODE_NIL) { 1278 datadm_ia_find_t ia_find; 1279 datadm_ia_entry_t *ia_entry; 1280 struct lifreq req; 1281 int devnum, rval; 1282 1283 devnum = di_instance(ibd_node); 1284 if (devnum == -1) { 1285 ibd_node = di_drv_next_node(ibd_node); 1286 continue; 1287 } 1288 1289 (void) snprintf(req.lifr_name, sizeof (req.lifr_name), 1290 "%s%d", DATADM_IA_NAME, devnum); 1291 /* 1292 * we don't really need to know the ip address. 1293 * we just want to check if the device is plumbed 1294 * or not. 1295 */ 1296 rval = ioctl(sv4, SIOCGLIFADDR, (caddr_t)&req); 1297 if (rval != 0) { 1298 /* 1299 * we try v6 if the v4 address isn't found. 1300 */ 1301 rval = ioctl(sv6, SIOCGLIFADDR, (caddr_t)&req); 1302 if (rval != 0) { 1303 ibd_node = di_drv_next_node(ibd_node); 1304 continue; 1305 } 1306 } 1307 ia_find.if_ia_devnum = devnum; 1308 ia_find.if_ia_entry = NULL; 1309 (void) datadm_walk_list(&hca->he_ia_list, 1310 (int (*)(datadm_entry_t *, void *)) 1311 datadm_ia_entry_find, &ia_find); 1312 1313 if (ia_find.if_ia_entry == NULL) { 1314 /* 1315 * we insert an ia entry only if 1316 * it is unique. 1317 */ 1318 ia_entry = datadm_alloc_ia_entry(); 1319 if (ia_entry == NULL) { 1320 retval = -1; 1321 break; 1322 } 1323 ia_entry->iae_devnum = devnum; 1324 datadm_enqueue_entry(&hca->he_ia_list, 1325 (datadm_entry_t *)ia_entry); 1326 } else { 1327 ia_entry = ia_find.if_ia_entry; 1328 } 1329 ibd_node = di_drv_next_node(ibd_node); 1330 } 1331 hca_node = di_drv_next_node(hca_node); 1332 } 1333 if (retval != 0) { 1334 datadm_free_list(&hca->he_ia_list, 1335 (void (*)(datadm_entry_t *))datadm_free_ia_entry); 1336 } 1337 return (0); 1338 } 1339 1340 /* 1341 * used by OP_REMOVE to invalidate common sp entries between hl1 and hl2. 1342 * invalid sp entries will be ignored by datadm_generate_dat_conf. 1343 */ 1344 static void 1345 datadm_invalidate_common_sp_entries(datadm_list_t *hl1, datadm_list_t *hl2) 1346 { 1347 datadm_entry_t *he1, *he2; 1348 1349 he1 = hl1->dl_head; 1350 while (he1 != NULL) { 1351 he2 = hl2->dl_head; 1352 while (he2 != NULL) { 1353 datadm_entry_t *se1, *se2; 1354 1355 if (!datadm_hca_entry_match( 1356 (datadm_hca_entry_t *)he1, 1357 (datadm_hca_entry_t *)he2)) { 1358 he2 = he2->de_next; 1359 continue; 1360 } 1361 se1 = ((datadm_hca_entry_t *)he1)->he_sp_list.dl_head; 1362 while (se1 != NULL) { 1363 se2 = ((datadm_hca_entry_t *)he2)-> 1364 he_sp_list.dl_head; 1365 while (se2 != NULL) { 1366 if (!datadm_sp_entry_match( 1367 (datadm_sp_entry_t *)se1, 1368 (datadm_sp_entry_t *)se2)) { 1369 se2 = se2->de_next; 1370 continue; 1371 } 1372 ((datadm_sp_entry_t *)se1)-> 1373 spe_invalid = 1; 1374 break; 1375 } 1376 se1 = se1->de_next; 1377 } 1378 break; 1379 } 1380 he1 = he1->de_next; 1381 } 1382 } 1383 1384 /* 1385 * applies datadm_fill_ia_list on each hca_list element 1386 */ 1387 static int 1388 datadm_build_ia_lists(datadm_list_t *hca_list) 1389 { 1390 datadm_fill_ia_list_t ia_args; 1391 di_node_t root_node; 1392 int retval = 0; 1393 int sv4, sv6; 1394 1395 root_node = di_init("/", DINFOCPYALL); 1396 if (root_node == DI_NODE_NIL) { 1397 perror("datadm: di_init"); 1398 return (-1); 1399 } 1400 sv4 = socket(AF_INET, SOCK_DGRAM, 0); 1401 if (sv4 < 0) { 1402 perror("datadm: socket"); 1403 di_fini(root_node); 1404 return (-1); 1405 } 1406 sv6 = socket(AF_INET6, SOCK_DGRAM, 0); 1407 if (sv6 < 0) { 1408 perror("datadm: socket"); 1409 di_fini(root_node); 1410 return (-1); 1411 } 1412 ia_args.ia_root_node = root_node; 1413 ia_args.ia_sock_fd_v4 = sv4; 1414 ia_args.ia_sock_fd_v6 = sv6; 1415 1416 retval = datadm_walk_list(hca_list, 1417 (int (*)(datadm_entry_t *, void *))datadm_fill_ia_list, &ia_args); 1418 1419 (void) close(sv4); 1420 (void) close(sv6); 1421 di_fini(root_node); 1422 return (retval); 1423 } 1424 1425 static int 1426 datadm_generate_conf_entry(FILE *outfile, datadm_ia_entry_t *ia_entry, 1427 datadm_sp_entry_t *sp_entry) 1428 { 1429 int retval; 1430 1431 retval = fprintf(outfile, 1432 "%s%d %s%d.%d %s %s %s %s%d.%d \"%s\" \"%s%s%s\"\n", 1433 DATADM_IA_NAME, ia_entry->iae_devnum, 1434 (sp_entry->spe_api_version.dv_name ? 1435 sp_entry->spe_api_version.dv_name : ""), 1436 sp_entry->spe_api_version.dv_major, 1437 sp_entry->spe_api_version.dv_minor, 1438 (sp_entry->spe_threadsafe ? "threadsafe" : "nonthreadsafe"), 1439 (sp_entry->spe_default ? "default" : "nondefault"), 1440 sp_entry->spe_libpath, 1441 (sp_entry->spe_sp_version.dv_name ? 1442 sp_entry->spe_sp_version.dv_name : ""), 1443 sp_entry->spe_sp_version.dv_major, 1444 sp_entry->spe_sp_version.dv_minor, 1445 sp_entry->spe_sp_data, 1446 DATADM_DRV_NAME, "=", sp_entry->spe_devname); 1447 1448 if (retval < 0) { 1449 return (-1); 1450 } 1451 return (0); 1452 } 1453 1454 /* 1455 * generate dat.conf header 1456 */ 1457 static int 1458 datadm_generate_conf_header(FILE *outfile) 1459 { 1460 datadm_entry_t *cep; 1461 datadm_cmnt_entry_t *cmnt; 1462 int retval = 0; 1463 1464 cep = datadm_conf_header.dl_head; 1465 if (cep == NULL) { 1466 /* 1467 * if dat.conf doesn't have a header, we prepend a 1468 * default one. 1469 */ 1470 retval = fprintf(outfile, "%s", datadm_conf_header_default); 1471 goto done; 1472 } 1473 while (cep != NULL) { 1474 cmnt = (datadm_cmnt_entry_t *)cep; 1475 if (cmnt->cmnt_line != NULL) { 1476 int len; 1477 1478 retval = fprintf(outfile, "%s", cmnt->cmnt_line); 1479 if (retval < 0) { 1480 break; 1481 } 1482 1483 /* 1484 * append a newline if the comment line doesn't 1485 * have one. 1486 */ 1487 len = strlen(cmnt->cmnt_line); 1488 if (cmnt->cmnt_line[len - 1] != '\n') { 1489 retval = fprintf(outfile, "\n"); 1490 if (retval < 0) { 1491 break; 1492 } 1493 } 1494 } 1495 cep = cep->de_next; 1496 } 1497 done:; 1498 if (retval < 0) { 1499 return (-1); 1500 } 1501 return (0); 1502 } 1503 1504 /* 1505 * outputs dat.conf to stdout or to basedir/etc/dat/dat.conf 1506 */ 1507 static int 1508 datadm_generate_dat_conf(datadm_list_t *hca_list) 1509 { 1510 FILE *outfile = NULL; 1511 char *dat_conf = datadm_args.da_dat_conf; 1512 datadm_entry_t *hep; 1513 int retval = 0; 1514 1515 if (datadm_args.da_op_type == DATADM_OP_VIEW) { 1516 outfile = stdout; 1517 } else { 1518 outfile = fopen(dat_conf, "w+"); 1519 if (outfile == NULL) { 1520 (void) fprintf(stderr, gettext( 1521 "datadm: cannot open %s: %s\n"), 1522 dat_conf, strerror(errno)); 1523 return (-1); 1524 } 1525 } 1526 if (outfile != stdout) { 1527 /* 1528 * do not generate the header if we are 1529 * printing to the screen 1530 */ 1531 retval = datadm_generate_conf_header(outfile); 1532 if (retval != 0) { 1533 goto done; 1534 } 1535 } 1536 hep = hca_list->dl_head; 1537 while (hep != NULL) { 1538 datadm_entry_t *iep; 1539 1540 iep = ((datadm_hca_entry_t *)hep)->he_ia_list.dl_head; 1541 while (iep != NULL) { 1542 datadm_entry_t *sep; 1543 1544 sep = ((datadm_hca_entry_t *)hep)->he_sp_list.dl_head; 1545 while (sep != NULL) { 1546 if (((datadm_sp_entry_t *)sep)->spe_invalid) { 1547 sep = sep->de_next; 1548 continue; 1549 } 1550 retval = datadm_generate_conf_entry(outfile, 1551 (datadm_ia_entry_t *)iep, 1552 (datadm_sp_entry_t *)sep); 1553 if (retval != 0) { 1554 goto done; 1555 } 1556 sep = sep->de_next; 1557 } 1558 iep = iep->de_next; 1559 } 1560 hep = hep->de_next; 1561 } 1562 retval = fflush(outfile); 1563 done:; 1564 if (outfile != stdout) { 1565 (void) fclose(outfile); 1566 } 1567 if (retval < 0) { 1568 perror("datadm: fprintf"); 1569 } 1570 return (retval); 1571 } 1572 1573 static int 1574 datadm_view(void) 1575 { 1576 int retval = 0; 1577 datadm_list_t hca_list; 1578 1579 bzero(&hca_list, sizeof (hca_list)); 1580 1581 retval = datadm_parse_dat_conf(&hca_list); 1582 if (retval != 0) { 1583 goto cleanup; 1584 } 1585 retval = datadm_generate_dat_conf(&hca_list); 1586 if (retval != 0) { 1587 goto cleanup; 1588 } 1589 1590 cleanup:; 1591 datadm_free_list(&datadm_conf_header, 1592 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1593 datadm_free_list(&hca_list, 1594 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1595 return (retval); 1596 } 1597 1598 static int 1599 datadm_update(void) 1600 { 1601 int retval = 0; 1602 datadm_list_t hca_list; 1603 1604 bzero(&hca_list, sizeof (hca_list)); 1605 1606 retval = datadm_parse_dat_conf(&hca_list); 1607 if (retval != 0) { 1608 goto cleanup; 1609 } 1610 retval = datadm_build_ia_lists(&hca_list); 1611 if (retval != 0) { 1612 goto cleanup; 1613 } 1614 retval = datadm_generate_dat_conf(&hca_list); 1615 if (retval != 0) { 1616 goto cleanup; 1617 } 1618 1619 cleanup:; 1620 datadm_free_list(&datadm_conf_header, 1621 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1622 datadm_free_list(&hca_list, 1623 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1624 return (retval); 1625 } 1626 1627 static int 1628 datadm_add(void) 1629 { 1630 int retval = 0; 1631 datadm_list_t hca_list; 1632 1633 bzero(&hca_list, sizeof (hca_list)); 1634 1635 retval = datadm_parse_dat_conf(&hca_list); 1636 if (retval != 0) { 1637 goto cleanup; 1638 } 1639 retval = datadm_parse_sp_conf(&hca_list); 1640 if (retval != 0) { 1641 goto cleanup; 1642 } 1643 retval = datadm_build_ia_lists(&hca_list); 1644 if (retval != 0) { 1645 goto cleanup; 1646 } 1647 retval = datadm_generate_dat_conf(&hca_list); 1648 if (retval != 0) { 1649 goto cleanup; 1650 } 1651 1652 cleanup:; 1653 datadm_free_list(&datadm_conf_header, 1654 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1655 datadm_free_list(&hca_list, 1656 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1657 return (retval); 1658 } 1659 1660 static int 1661 datadm_remove(void) 1662 { 1663 int retval = 0; 1664 datadm_list_t hca_list; 1665 datadm_list_t hca_list2; 1666 1667 bzero(&hca_list, sizeof (hca_list)); 1668 bzero(&hca_list2, sizeof (hca_list2)); 1669 1670 retval = datadm_parse_dat_conf(&hca_list); 1671 if (retval != 0) { 1672 goto cleanup; 1673 } 1674 retval = datadm_parse_sp_conf(&hca_list2); 1675 if (retval != 0) { 1676 goto cleanup; 1677 } 1678 datadm_invalidate_common_sp_entries(&hca_list, &hca_list2); 1679 1680 retval = datadm_generate_dat_conf(&hca_list); 1681 if (retval != 0) { 1682 goto cleanup; 1683 } 1684 1685 cleanup:; 1686 datadm_free_list(&datadm_conf_header, 1687 (void (*)(datadm_entry_t *))datadm_free_cmnt_entry); 1688 datadm_free_list(&hca_list, 1689 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1690 datadm_free_list(&hca_list2, 1691 (void (*)(datadm_entry_t *))datadm_free_hca_entry); 1692 return (retval); 1693 } 1694 1695 static int 1696 datadm_locate_dat_conf(char *basedir) 1697 { 1698 char *dat_conf; 1699 1700 if (basedir == NULL) { 1701 datadm_args.da_dat_conf = DATADM_DAT_CONF; 1702 return (0); 1703 } 1704 dat_conf = (char *)malloc(strlen(basedir) + 1705 strlen(DATADM_DAT_CONF) + 1); 1706 if (dat_conf == NULL) { 1707 return (-1); 1708 } 1709 dat_conf[0] = '\0'; 1710 (void) strcat(dat_conf, basedir); 1711 (void) strcat(dat_conf, DATADM_DAT_CONF); 1712 datadm_args.da_dat_conf = dat_conf; 1713 return (0); 1714 } 1715 1716 int 1717 main(int argc, char **argv) 1718 { 1719 extern char *optarg; 1720 extern int optind; 1721 char *basedir = NULL; 1722 int c, retval; 1723 int op_type = -1, errflg = 0; 1724 1725 bzero(&datadm_args, sizeof (datadm_args)); 1726 bzero(&datadm_conf_header, sizeof (datadm_conf_header)); 1727 1728 (void) setlocale(LC_ALL, ""); 1729 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1730 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 1731 #endif 1732 (void) textdomain(TEXT_DOMAIN); 1733 1734 while ((c = getopt(argc, argv, "vua:r:b:")) != EOF) { 1735 switch (c) { 1736 case 'v': 1737 if (op_type != -1) errflg = 1; 1738 op_type = DATADM_OP_VIEW; 1739 break; 1740 case 'u': 1741 if (op_type != -1) errflg = 1; 1742 op_type = DATADM_OP_UPDATE; 1743 break; 1744 case 'a': 1745 if (op_type != -1) errflg = 1; 1746 op_type = DATADM_OP_ADD; 1747 datadm_args.da_sp_conf = optarg; 1748 break; 1749 case 'r': 1750 if (op_type != -1) errflg = 1; 1751 op_type = DATADM_OP_REMOVE; 1752 datadm_args.da_sp_conf = optarg; 1753 break; 1754 case 'b': 1755 basedir = optarg; 1756 break; 1757 default: 1758 errflg = 1; 1759 break; 1760 } 1761 if (errflg != 0) { 1762 break; 1763 } 1764 } 1765 if (errflg != 0 || op_type == -1 || optind < argc) { 1766 datadm_usage(); 1767 return (1); 1768 } 1769 datadm_args.da_op_type = op_type; 1770 if (datadm_locate_dat_conf(basedir)) { 1771 return (1); 1772 } 1773 1774 retval = (*datadm_ops[op_type])(); 1775 return (retval); 1776 } 1777