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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include "cfga_ib.h" 27 #include "cfga_conf.h" 28 #include <sys/stat.h> 29 30 /* 31 * cfga_conf.c 32 * 33 * This file supports adding/deleting/listing services from IBCONF_FILE. 34 */ 35 36 /* 37 * function prototypes: 38 */ 39 static ib_service_type_t ib_get_var_type(char *); 40 static ib_token_t ib_lex(char *, char **); 41 static void ib_find_eol(); 42 static int ib_get_string(char **, char *); 43 static int ib_service_record_add(char *, 44 ib_service_type_t); 45 static ib_token_t ib_get_services(char **); 46 static boolean_t ib_cmp_service(); 47 static void ib_free_service_recs(void); 48 static int ib_cleanup_file(int); 49 static int ib_init_file(char **); 50 int ib_add_service(char **); 51 int ib_delete_service(char **); 52 int ib_list_services(struct cfga_msg *, char **); 53 static cfga_ib_ret_t ib_conf_control_ioctl(char *, uint_t); 54 static int ib_service_record_valid(char *); 55 56 extern void cfga_msg(struct cfga_msg *, const char *); 57 58 59 /* Global variables */ 60 61 /* 62 * supported "name=value" pairs from IBCONF_FILE 63 */ 64 static ibcfg_var_t ibcfg_varlist[] = { 65 { "name", IB_NAME }, 66 { "class", IB_CLASS }, 67 { "port-svc-list", IB_PORT_SERVICE }, 68 { "vppa-svc-list", IB_VPPA_SERVICE }, 69 { "hca-svc-list", IB_HCASVC_SERVICE }, 70 { NULL, IB_NONE } 71 }; 72 73 static char ibconf_file[] = IBCONF_FILE; /* file being read */ 74 static int ibcfg_linenum = 1; /* track line#s */ 75 static int ibcfg_cntr = 0; /* current char read */ 76 static int ibcfg_brec = 0; /* beginning of rec */ 77 static int bvpparec = 0; /* begin of vppa rec */ 78 static int bportrec = 0; /* begin of port rec */ 79 static int bhcarec = 0; /* begin of HCA rec */ 80 static int ibcfg_btoken = 0; /* begin of new token */ 81 static mutex_t ibcfg_lock = DEFAULTMUTEX; /* lock for the file */ 82 static int ibcfg_fd = -1; /* file descriptor */ 83 static int ibcfg_tmpfd = 0; /* tmp file "fd" */ 84 static char *file_buf = (char *)NULL; /* read file into buf */ 85 static char *tmpnamef = (char *)NULL; /* tmp file name */ 86 static boolean_t wrote_tmp = B_FALSE; /* tmp file write in */ 87 /* progress indicator */ 88 static struct stat ibcfg_st; /* file stat struct */ 89 90 static int ibcfg_nport_services; /* # of PORT services */ 91 static int ibcfg_nvppa_services; /* # of VPPA services */ 92 static int ibcfg_nhca_services; /* # of HCA services */ 93 static ib_svc_rec_t *ibcfg_vppa_head; /* VPPA service recs */ 94 static ib_svc_rec_t *ibcfg_port_head; /* PORT service recs */ 95 static ib_svc_rec_t *ibcfg_hca_head; /* HCA service recs */ 96 97 extern char *service_name; /* service name */ 98 extern ib_service_type_t service_type; /* service type */ 99 100 101 /* 102 * Function: 103 * ib_get_var_type 104 * Input: 105 * str - A parsed string from IBCONF_FILE 106 * Output: 107 * NONE 108 * Returns: 109 * Service type 110 * Description: 111 * Returns the field from the token 112 */ 113 static ib_service_type_t 114 ib_get_var_type(char *str) 115 { 116 register ibcfg_var_t *cfgvar; 117 118 cfgvar = &ibcfg_varlist[0]; 119 while (cfgvar->type != IB_NONE) { 120 if (strcasecmp(cfgvar->name, str) == 0) 121 break; 122 else 123 cfgvar++; 124 } 125 return (cfgvar->type); 126 } 127 128 129 /* 130 * Function: 131 * ib_lex 132 * Input: 133 * NONE 134 * Output: 135 * val - value just read 136 * errmsg - pointer to error message string, if there are any errors 137 * Returns: 138 * valid IB token 139 * Description: 140 * Read tokens from the IBCONF_FILE and parse them 141 */ 142 /* ARGSUSED */ 143 static ib_token_t 144 ib_lex(char *val, char **errmsg) 145 { 146 int ch, oval, badquote; 147 char *cp = val; 148 ib_token_t token; 149 150 while ((ch = GETC(file_buf, ibcfg_cntr)) == ' ' || ch == '\t') 151 ; 152 153 /* make a note of the beginning of token */ 154 ibcfg_btoken = ibcfg_cntr - 1; 155 156 *cp++ = (char)ch; 157 switch (ch) { 158 case '=': 159 token = EQUALS; 160 break; 161 case '&': 162 token = AMPERSAND; 163 break; 164 case '|': 165 token = BIT_OR; 166 break; 167 case '*': 168 token = STAR; 169 break; 170 case '#': 171 token = POUND; 172 break; 173 case ':': 174 token = COLON; 175 break; 176 case ';': 177 token = SEMICOLON; 178 break; 179 case ',': 180 token = COMMA; 181 break; 182 case '/': 183 token = SLASH; 184 break; 185 case ' ': 186 case '\t': 187 case '\f': 188 while ((ch = GETC(file_buf, ibcfg_cntr)) == ' ' || 189 ch == '\t' || ch == '\f') 190 *cp++ = (char)ch; 191 (void) UNGETC(ibcfg_cntr); 192 token = WHITE_SPACE; 193 break; 194 case '\n': 195 case '\r': 196 token = NEWLINE; 197 break; 198 case '"': 199 cp--; 200 badquote = 0; 201 while (!badquote && (ch = GETC(file_buf, ibcfg_cntr)) != '"') { 202 switch (ch) { 203 case '\n': 204 case -1: 205 (void) snprintf(*errmsg, MAXPATHLEN, 206 "Missing \""); 207 cp = val; 208 *cp++ = '\n'; 209 badquote = 1; 210 /* since we consumed the newline/EOF */ 211 (void) UNGETC(ibcfg_cntr); 212 break; 213 214 case '\\': 215 ch = (char)GETC(file_buf, ibcfg_cntr); 216 if (!isdigit(ch)) { 217 /* escape the character */ 218 *cp++ = (char)ch; 219 break; 220 } 221 oval = 0; 222 while (ch >= '0' && ch <= '7') { 223 ch -= '0'; 224 oval = (oval << 3) + ch; 225 ch = (char)GETC(file_buf, ibcfg_cntr); 226 } 227 (void) UNGETC(ibcfg_cntr); 228 /* check for character overflow? */ 229 if (oval > 127) { 230 (void) snprintf(*errmsg, MAXPATHLEN, 231 "Character overflow detected.\n"); 232 } 233 *cp++ = (char)oval; 234 break; 235 default: 236 *cp++ = (char)ch; 237 break; 238 } 239 } 240 token = STRING; 241 break; 242 default: 243 if (ch == -1) { 244 token = EOF; 245 break; 246 } 247 /* 248 * detect a lone '-' (including at the end of a line), and 249 * identify it as a 'name' 250 */ 251 if (ch == '-') { 252 *cp++ = (char)(ch = GETC(file_buf, ibcfg_cntr)); 253 if (iswhite(ch) || (ch == '\n')) { 254 (void) UNGETC(ibcfg_cntr); 255 cp--; 256 token = NAME; 257 break; 258 } 259 } else if (isunary(ch)) { 260 *cp++ = (char)(ch = GETC(file_buf, ibcfg_cntr)); 261 } 262 263 if (isdigit(ch)) { 264 if (ch == '0') { 265 if ((ch = GETC(file_buf, ibcfg_cntr)) == 'x') { 266 *cp++ = (char)ch; 267 ch = GETC(file_buf, ibcfg_cntr); 268 while (isxdigit(ch)) { 269 *cp++ = (char)ch; 270 ch = GETC(file_buf, ibcfg_cntr); 271 } 272 (void) UNGETC(ibcfg_cntr); 273 token = HEXVAL; 274 } else { 275 goto digit; 276 } 277 } else { 278 ch = GETC(file_buf, ibcfg_cntr); 279 digit: 280 while (isdigit(ch)) { 281 *cp++ = (char)ch; 282 ch = GETC(file_buf, ibcfg_cntr); 283 } 284 (void) UNGETC(ibcfg_cntr); 285 token = DECVAL; 286 } 287 } else if (isalpha(ch) || ch == '\\') { 288 if (ch != '\\') { 289 ch = GETC(file_buf, ibcfg_cntr); 290 } else { 291 /* 292 * if the character was a backslash, 293 * back up so we can overwrite it with 294 * the next (i.e. escaped) character. 295 */ 296 cp--; 297 } 298 299 while (isnamechar(ch) || ch == '\\') { 300 if (ch == '\\') 301 ch = GETC(file_buf, ibcfg_cntr); 302 *cp++ = (char)ch; 303 ch = GETC(file_buf, ibcfg_cntr); 304 } 305 (void) UNGETC(ibcfg_cntr); 306 token = NAME; 307 } else 308 return (-1); 309 break; 310 } 311 *cp = '\0'; 312 return (token); 313 } 314 315 316 /* 317 * Function: 318 * ib_find_eol 319 * Input: 320 * NONE 321 * Output: 322 * NONE 323 * Returns: 324 * NONE 325 * Description: 326 * Leave NEWLINE as the next character. 327 */ 328 static void 329 ib_find_eol() 330 { 331 int ch; 332 333 while ((ch = GETC(file_buf, ibcfg_cntr)) != -1) { 334 if (isnewline(ch)) { 335 (void) UNGETC(ibcfg_cntr); 336 break; 337 } 338 } 339 } 340 341 342 /* 343 * Function: 344 * ib_get_string 345 * Input: 346 * tchar - name of the string 347 * Output: 348 * llptr - Valid string 349 * Returns: 350 * 1 for success, NULL for errors. 351 * Description: 352 * The next item on the line is a string value. Allocate memory for 353 * it and copy the string. Return 1, and set arg ptr to newly allocated 354 * and initialized buffer, or NULL if an error occurs. 355 */ 356 static int 357 ib_get_string(char **llptr, char *tchar) 358 { 359 int tlen = strlen(tchar); 360 char *cp; 361 char *start = (char *)0; 362 363 start = tchar; 364 /* copy string */ 365 if ((cp = (char *)calloc(tlen + 1, sizeof (char))) == (char *)NULL) { 366 *llptr = NULL; 367 return (0); 368 } 369 bzero(cp, tlen + 1); 370 371 *llptr = cp; 372 for (; tlen > 0; tlen--) { 373 /* convert some common escape sequences */ 374 if (*start == '\\') { 375 switch (*(start + 1)) { 376 case 't': 377 /* tab */ 378 *cp++ = '\t'; 379 tlen--; 380 start += 2; 381 break; 382 case 'n': 383 /* new line */ 384 *cp++ = '\n'; 385 tlen--; 386 start += 2; 387 break; 388 case 'b': 389 /* back space */ 390 *cp++ = '\b'; 391 tlen--; 392 start += 2; 393 break; 394 default: 395 /* simply copy it */ 396 *cp++ = *start++; 397 break; 398 } 399 } else { 400 *cp++ = *start++; 401 } 402 } 403 *cp = '\0'; 404 return (1); 405 } 406 407 408 /* 409 * Function: 410 * ib_service_record_add 411 * Input: 412 * service - name of the service 413 * type - type of the service 414 * Output: 415 * rec - one valid service record 416 * Returns: 417 * CFGA_IB_OK on success or an appropriate error 418 * Description: 419 * Add one record to internal data structures 420 */ 421 static int 422 ib_service_record_add(char *service, ib_service_type_t type) 423 { 424 ib_svc_rec_t *tmp, *recp; 425 426 DPRINTF("ib_service_record_add: (%x, %s) " 427 "(#port = %d #vppa = %d #hca = %d)\n", type, service, 428 ibcfg_nport_services, ibcfg_nvppa_services, 429 ibcfg_nhca_services); 430 recp = (ib_svc_rec_t *)calloc(1, sizeof (ib_svc_rec_t)); 431 if (recp == NULL) 432 return (CFGA_IB_ALLOC_FAIL); 433 434 recp->type = type; 435 recp->name = strdup((char *)service); 436 if (type == IB_PORT_SERVICE) { 437 if (ibcfg_port_head) { 438 for (tmp = ibcfg_port_head; tmp->next != NULL; ) 439 tmp = tmp->next; 440 tmp->next = recp; 441 } else 442 ibcfg_port_head = recp; 443 ibcfg_nport_services++; 444 } else if (type == IB_VPPA_SERVICE) { 445 if (ibcfg_vppa_head) { 446 for (tmp = ibcfg_vppa_head; tmp->next != NULL; ) 447 tmp = tmp->next; 448 tmp->next = recp; 449 } else 450 ibcfg_vppa_head = recp; 451 ibcfg_nvppa_services++; 452 } else if (type == IB_HCASVC_SERVICE) { 453 if (ibcfg_hca_head) { 454 for (tmp = ibcfg_hca_head; tmp->next != NULL; ) 455 tmp = tmp->next; 456 tmp->next = recp; 457 } else 458 ibcfg_hca_head = recp; 459 ibcfg_nhca_services++; 460 } 461 462 return (CFGA_IB_OK); 463 } 464 465 466 /* 467 * Function: 468 * ib_get_services 469 * Input: 470 * errmsg - Error message filled in case of a failure 471 * Output: 472 * rec - one valid service record 473 * Returns: 474 * CFGA_IB_OK on success or an appropriate error 475 * Description: 476 * Fetch one record from the IBCONF_FILE 477 */ 478 static ib_token_t 479 ib_get_services(char **errmsg) 480 { 481 char tokval[MAXLINESIZE]; 482 char *llptr; 483 boolean_t sor = B_TRUE; 484 ib_token_t token; 485 ib_service_type_t cfgvar; 486 ib_parse_state_t parse_state = IB_NEWVAR; 487 488 token = ib_lex(tokval, errmsg); 489 while ((token != EOF) && (token != SEMICOLON)) { 490 if (token == STAR || token == POUND) { 491 /* skip comments */ 492 ib_find_eol(); 493 } else if (token == NEWLINE) { 494 ibcfg_linenum++; 495 } else if (token == NAME || token == STRING) { 496 if (parse_state == IB_NEWVAR) { 497 cfgvar = ib_get_var_type(tokval); 498 if (cfgvar == IB_NONE) { 499 parse_state = IB_ERROR; 500 (void) snprintf(*errmsg, MAXPATHLEN, 501 "Syntax Error: Invalid type %s", 502 tokval); 503 } else { 504 /* Note the beginning of the entry */ 505 if (sor) { 506 ibcfg_brec = ibcfg_btoken; 507 sor = B_FALSE; 508 } 509 parse_state = IB_CONFIG_VAR; 510 if (cfgvar == IB_PORT_SERVICE) 511 bportrec = ibcfg_cntr + 1; 512 else if (cfgvar == IB_VPPA_SERVICE) 513 bvpparec = ibcfg_cntr + 1; 514 else if (cfgvar == IB_HCASVC_SERVICE) 515 bhcarec = ibcfg_cntr + 1; 516 } 517 518 } else if (parse_state == IB_VAR_VALUE) { 519 llptr = NULL; 520 if (ib_get_string(&llptr, tokval)) { 521 if ((cfgvar == IB_PORT_SERVICE) || 522 (cfgvar == IB_VPPA_SERVICE) || 523 (cfgvar == IB_HCASVC_SERVICE)) { 524 if (ib_service_record_valid( 525 llptr) && 526 ib_service_record_add( 527 (char *)llptr, cfgvar) != 528 CFGA_IB_OK) { 529 return (E_O_F); 530 } else { 531 parse_state = 532 IB_CONFIG_VAR; 533 } 534 } else if ((cfgvar == IB_NAME) || 535 (cfgvar == IB_CLASS)) { 536 free((char *)llptr); 537 parse_state = IB_NEWVAR; 538 } else { 539 free((char *)llptr); 540 parse_state = IB_ERROR; 541 } 542 } else { 543 parse_state = IB_ERROR; 544 (void) snprintf(*errmsg, MAXPATHLEN, 545 "Syntax Error: Invalid value %s " 546 "for type: %s\n", tokval, 547 ibcfg_varlist[cfgvar].name); 548 } 549 } else if (parse_state == IB_ERROR) { 550 /* just skip */ 551 DPRINTF("ib_get_services: ERROR\n"); 552 } else { 553 parse_state = IB_ERROR; 554 (void) snprintf(*errmsg, MAXPATHLEN, 555 "Syntax Error: at %s", tokval); 556 } 557 } else if (token == COMMA || token == EQUALS) { 558 if (parse_state == IB_CONFIG_VAR) { 559 if (cfgvar == IB_NONE) { 560 parse_state = IB_ERROR; 561 (void) snprintf(*errmsg, MAXPATHLEN, 562 "Syntax Error: unexpected '='"); 563 } else { 564 parse_state = IB_VAR_VALUE; 565 } 566 } else if (parse_state != IB_ERROR) { 567 (void) snprintf(*errmsg, MAXPATHLEN, 568 "Syntax Error: unexpected '='"); 569 parse_state = IB_ERROR; 570 } 571 } else { 572 (void) snprintf(*errmsg, MAXPATHLEN, 573 "Syntax Error: at: %s", tokval); 574 parse_state = IB_ERROR; 575 } 576 token = ib_lex(tokval, errmsg); 577 if (ib_get_var_type(tokval) != IB_NONE) 578 parse_state = IB_NEWVAR; 579 } 580 return (token); 581 } 582 583 /* 584 * Function: 585 * ib_cmp_service 586 * Input: 587 * NONE 588 * Output: 589 * NONE 590 * Returns: 591 * B_TRUE if this service is already seen. B_FALSE if not. 592 * Description: 593 * Compare the service just read from the services already seen. 594 * Check if this service was already seen or not. 595 */ 596 static boolean_t 597 ib_cmp_service() 598 { 599 ib_svc_rec_t *recp; 600 601 DPRINTF("ib_cmp_service: (%x, %s) " 602 "(#port = %d #vppa = %d #hca = %d)\n", service_type, 603 service_name, ibcfg_nport_services, ibcfg_nvppa_services, 604 ibcfg_nhca_services); 605 606 for (recp = ibcfg_port_head; recp != NULL; recp = recp->next) { 607 DPRINTF("ib_cmp_service:P usvc = %s, usvc_name = %s\n", 608 service_name, recp->name ? recp->name : "NONE"); 609 if (recp->name && strcmp(recp->name, service_name) == 0) 610 return (B_TRUE); 611 } 612 for (recp = ibcfg_vppa_head; recp != NULL; recp = recp->next) { 613 DPRINTF("ib_cmp_service:V utype = %x, usvc_name = %s\n", 614 recp->type, recp->name ? recp->name : "NONE"); 615 if (recp->name && strcmp(recp->name, service_name) == 0) 616 return (B_TRUE); 617 } 618 for (recp = ibcfg_hca_head; recp != NULL; recp = recp->next) { 619 DPRINTF("ib_cmp_service:V utype = %x, usvc_name = %s\n", 620 recp->type, recp->name ? recp->name : "NONE"); 621 if (recp->name && strcmp(recp->name, service_name) == 0) 622 return (B_TRUE); 623 } 624 625 return (B_FALSE); 626 } 627 628 629 /* 630 * Function: 631 * ib_free_service_recs 632 * Input: 633 * NONE 634 * Output: 635 * NONE 636 * Returns: 637 * CFGA_IB_OK on success or an appropriate error 638 * Description: 639 * Free the service records allocated in ib_get_services 640 */ 641 static void 642 ib_free_service_recs(void) 643 { 644 ib_svc_rec_t *tmp, *recp; 645 646 DPRINTF("ib_free_service_recs: " 647 "#port_services = %d, #vppa_services = %d, #hca_services = %d\n", 648 ibcfg_nport_services, ibcfg_nvppa_services, ibcfg_nhca_services); 649 650 for (recp = ibcfg_port_head; recp != NULL; ) { 651 if (recp && strlen(recp->name)) 652 S_FREE(recp->name); 653 tmp = recp; 654 recp = recp->next; 655 S_FREE(tmp); 656 } 657 658 for (recp = ibcfg_vppa_head; recp != NULL; ) { 659 if (recp && strlen(recp->name)) 660 S_FREE(recp->name); 661 tmp = recp; 662 recp = recp->next; 663 S_FREE(tmp); 664 } 665 666 for (recp = ibcfg_hca_head; recp != NULL; ) { 667 if (recp && strlen(recp->name)) 668 S_FREE(recp->name); 669 tmp = recp; 670 recp = recp->next; 671 S_FREE(tmp); 672 } 673 } 674 675 676 /* 677 * Function: 678 * ib_cleanup_file 679 * Input: 680 * rval - error return value 681 * Output: 682 * NONE 683 * Returns: 684 * CFGA_IB_OK on success or an appropriate error 685 * Description: 686 * Cleanup IBCONF_FILE etc. 687 */ 688 static int 689 ib_cleanup_file(int rval) 690 { 691 int rv = rval; 692 693 ib_free_service_recs(); 694 if (lockf(ibcfg_fd, F_ULOCK, 0) == -1) { 695 DPRINTF("ib_cleanup_file: unlock file %s failed\n", 696 ibconf_file); 697 rv = CFGA_IB_UNLOCK_FILE_ERR; 698 } 699 S_FREE(file_buf); 700 close(ibcfg_fd); 701 ibcfg_fd = -1; 702 if (ibcfg_tmpfd && wrote_tmp == B_TRUE) { 703 DPRINTF("ib_cleanup_file: tmpfile %s being renamed to %s\n", 704 tmpnamef, IBCONF_FILE); 705 close(ibcfg_tmpfd); 706 rename((const char *)tmpnamef, (const char *)IBCONF_FILE); 707 unlink(tmpnamef); 708 } 709 (void) mutex_unlock(&ibcfg_lock); 710 return (rv); 711 } 712 713 714 /* 715 * Function: 716 * ib_init_file 717 * Input: 718 * NONE 719 * Output: 720 * errmsg - Error message filled in case of a failure 721 * Returns: 722 * CFGA_IB_OK on success or an appropriate error 723 * Description: 724 * Initialize IBCONF_FILE for reading 725 */ 726 static int 727 ib_init_file(char **errmsg) 728 { 729 (void) mutex_lock(&ibcfg_lock); 730 731 if (*errmsg == (char *)NULL) { 732 if ((*errmsg = calloc(MAXPATHLEN, 1)) == (char *)NULL) { 733 (void) mutex_unlock(&ibcfg_lock); 734 DPRINTF("ib_init_file: calloc errmsg failed\n"); 735 return (CFGA_IB_CONFIG_FILE_ERR); 736 } 737 } 738 739 /* Open the .conf file */ 740 if ((ibcfg_fd = open(ibconf_file, O_RDWR, 0666)) == -1) { 741 (void) snprintf(*errmsg, MAXPATHLEN, 742 "failed to open %s file\n", ibconf_file); 743 (void) mutex_unlock(&ibcfg_lock); 744 return (CFGA_IB_CONFIG_FILE_ERR); 745 } 746 747 /* Lock the file so that another cfgadm instance doesn't modify it */ 748 if (lockf(ibcfg_fd, F_TLOCK, 0) == -1) { 749 (void) snprintf(*errmsg, MAXPATHLEN, 750 "failed to lock %s file\n", ibconf_file); 751 close(ibcfg_fd); 752 ibcfg_fd = -1; 753 (void) mutex_unlock(&ibcfg_lock); 754 return (CFGA_IB_LOCK_FILE_ERR); 755 } 756 757 if (fstat(ibcfg_fd, &ibcfg_st) != 0) { 758 DPRINTF("ib_init_file: failed to fstat %s file\n", ibconf_file); 759 return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR)); 760 } 761 762 /* Allocate a buffer for the file */ 763 if ((file_buf = (char *)malloc(ibcfg_st.st_size)) == NULL) { 764 DPRINTF("ib_init_file: failed to fstat %s file\n", 765 ibconf_file); 766 return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL)); 767 } 768 769 /* Check if size matches */ 770 if (ibcfg_st.st_size != read(ibcfg_fd, file_buf, ibcfg_st.st_size)) { 771 DPRINTF("ib_init_file: failed to read %s file\n", ibconf_file); 772 return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR)); 773 } 774 775 /* 776 * These variables need to be reinitialized here as they may 777 * have been modified by a previous thread that called this 778 * function 779 */ 780 ibcfg_linenum = 1; 781 ibcfg_cntr = 0; 782 ibcfg_brec = 0; 783 ibcfg_btoken = 0; 784 785 ibcfg_nport_services = 0; 786 ibcfg_nvppa_services = 0; 787 ibcfg_nhca_services = 0; 788 ibcfg_port_head = (ib_svc_rec_t *)NULL; 789 ibcfg_vppa_head = (ib_svc_rec_t *)NULL; 790 ibcfg_hca_head = (ib_svc_rec_t *)NULL; 791 return (CFGA_IB_OK); 792 } 793 794 795 /* 796 * Function: 797 * ib_add_service 798 * Input: 799 * NONE 800 * Output: 801 * errmsg - Error message filled in case of a failure 802 * Returns: 803 * CFGA_IB_OK on success or an appropriate error 804 * Description: 805 * open IBCONF_FILE and add "service_name". 806 */ 807 int 808 ib_add_service(char **errmsg) 809 { 810 int rval; 811 char *sbuf; 812 boolean_t found = B_FALSE; 813 ib_token_t token = NEWLINE; 814 815 DPRINTF("ib_add_service: type = %x, service_name=%s\n", service_type, 816 service_name); 817 if ((rval = ib_init_file(errmsg)) != CFGA_IB_OK) { 818 DPRINTF("ib_add_service: initializing file failed\n"); 819 return (rval); 820 } 821 822 /* Start reading the file */ 823 while (token != EOF) { 824 token = ib_get_services(errmsg); 825 found = ib_cmp_service(); 826 if (found == B_TRUE) { 827 DPRINTF("ib_add_service: token=%x, found=%x\n", 828 token, found); 829 break; 830 } 831 } 832 833 /* Service shouldn't already exist while adding */ 834 if (found) { 835 (void) snprintf(*errmsg, MAXPATHLEN, "service entry %s exists ", 836 service_name); 837 DPRINTF("ib_add_service: invalid add operation\n"); 838 return (ib_cleanup_file(CFGA_IB_SVC_EXISTS_ERR)); 839 } 840 841 DPRINTF("!FOUND and adding\n"); 842 switch (service_type) { 843 case IB_PORT_SERVICE : 844 ibcfg_brec = bportrec; 845 break; 846 case IB_VPPA_SERVICE : 847 ibcfg_brec = bvpparec; 848 break; 849 case IB_HCASVC_SERVICE : 850 ibcfg_brec = bhcarec; 851 break; 852 default : 853 DPRINTF("ib_add_service: invalid add operation\n"); 854 return (ib_cleanup_file(CFGA_IB_SVC_INVAL_ERR)); 855 } 856 857 858 if ((sbuf = (char *)calloc(12, sizeof (char))) == NULL) { 859 DPRINTF("ib_add_service: failed to calloc sbuf %s file\n", 860 ibconf_file); 861 return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL)); 862 } 863 if (file_buf[ibcfg_brec] == '"' && file_buf[ibcfg_brec + 1] == '"') { 864 (void) snprintf(sbuf, 9, "%s", service_name); 865 ibcfg_brec += 1; 866 } else 867 (void) snprintf(sbuf, 9, "\"%s\", ", service_name); 868 869 870 /* Seek to the beginning of the file */ 871 if (lseek(ibcfg_fd, ibcfg_brec, SEEK_SET) == -1) { 872 DPRINTF("ib_add_service: lseek %s file failed\n", ibconf_file); 873 return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR)); 874 } 875 876 /* Add service to w/ IBNEX */ 877 if (ib_conf_control_ioctl(service_name, IBNEX_CONF_ENTRY_ADD)) { 878 DPRINTF("ib_add_service: ioctl add failed %d\n", errno); 879 (void) snprintf(*errmsg, MAXPATHLEN, "failed to add " 880 "%s service incore ", service_name); 881 return (ib_cleanup_file(CFGA_IB_SVC_EXISTS_ERR)); 882 } 883 884 /* Write the modified file */ 885 if (write(ibcfg_fd, sbuf, strlen(sbuf)) == -1) { 886 DPRINTF("ib_add_service: write %s file failed\n", ibconf_file); 887 return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR)); 888 } 889 890 /* Write the rest of the file as it was */ 891 if (write(ibcfg_fd, file_buf + ibcfg_brec, 892 ibcfg_st.st_size - ibcfg_brec) == -1) { 893 DPRINTF("ib_add_service: write %s file failed 2\n", 894 ibconf_file); 895 return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR)); 896 } 897 898 return (ib_cleanup_file(rval)); 899 } 900 901 902 /* 903 * Function: 904 * ib_delete_service 905 * Input: 906 * NONE 907 * Output: 908 * errmsg - Error message filled in case of a failure 909 * Returns: 910 * CFGA_IB_OK on success or an appropriate error 911 * Description: 912 * open ib.conf file and delete "service_name" 913 */ 914 int 915 ib_delete_service(char **errmsg) 916 { 917 int rval; 918 int num_svcs; 919 int skip_len; 920 int sbuf_len; 921 int tot_len; 922 char tmp[12]; 923 char *sbuf = (char *)NULL; 924 boolean_t found = B_FALSE; 925 ib_token_t token = NEWLINE; 926 ib_svc_rec_t *recp; 927 928 DPRINTF("ib_delete_service: type = %x, service_name=%s\n", 929 service_type, service_name); 930 if ((rval = ib_init_file(errmsg)) != CFGA_IB_OK) { 931 DPRINTF("ib_delete_service: initializing file failed\n"); 932 return (rval); 933 } 934 935 /* Start reading the file */ 936 while (token != EOF) { 937 token = ib_get_services(errmsg); 938 found = ib_cmp_service(); /* search for a match */ 939 if (found == B_TRUE) { 940 DPRINTF("ib_delete_service: token=%x, found=%x\n", 941 token, found); 942 break; 943 } 944 } 945 946 /* No service found, return */ 947 if (!found) { 948 DPRINTF("ib_delete_service: invalid delete operation\n"); 949 (void) snprintf(*errmsg, MAXPATHLEN, "service entry %s " 950 "does not exist ", service_name); 951 return (ib_cleanup_file(CFGA_IB_SVC_NO_EXIST_ERR)); 952 } 953 954 DPRINTF("FOUND and deleting \n"); 955 956 switch (service_type) { 957 case IB_PORT_SERVICE : 958 ibcfg_brec = bportrec; 959 num_svcs = ibcfg_nport_services; 960 break; 961 case IB_VPPA_SERVICE : 962 ibcfg_brec = bvpparec; 963 num_svcs = ibcfg_nvppa_services; 964 break; 965 case IB_HCASVC_SERVICE : 966 ibcfg_brec = bhcarec; 967 num_svcs = ibcfg_nhca_services; 968 break; 969 default : 970 DPRINTF("ib_delete_service: invalid delete " 971 "operation\n"); 972 return (ib_cleanup_file(CFGA_IB_SVC_INVAL_ERR)); 973 } 974 975 if ((sbuf = (char *)calloc(num_svcs * 8, sizeof (char))) == NULL) { 976 DPRINTF("ib_delete_service: sbuf alloc failed %s\n", 977 ibconf_file); 978 return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL)); 979 } 980 981 if (num_svcs == 1) { 982 (void) snprintf(sbuf, 9, "\"\""); 983 sbuf_len = 2; 984 skip_len = 0; 985 } else { 986 if (service_type == IB_PORT_SERVICE) { 987 for (recp = ibcfg_port_head; recp; recp = recp->next) { 988 if (strcmp(recp->name, service_name) == 0) 989 continue; 990 (void) snprintf(tmp, 9, "\"%s\", ", recp->name); 991 (void) strcat(sbuf, tmp); 992 } 993 994 } else if (service_type == IB_VPPA_SERVICE) { 995 for (recp = ibcfg_vppa_head; recp; recp = recp->next) { 996 if (strcmp(recp->name, service_name) == 0) 997 continue; 998 (void) snprintf(tmp, 9, "\"%s\", ", recp->name); 999 (void) strcat(sbuf, tmp); 1000 } 1001 } else { 1002 for (recp = ibcfg_hca_head; recp; recp = recp->next) { 1003 if (strcmp(recp->name, service_name) == 0) 1004 continue; 1005 (void) snprintf(tmp, 9, "\"%s\", ", recp->name); 1006 (void) strcat(sbuf, tmp); 1007 } 1008 } 1009 skip_len = 4; 1010 sbuf_len = strlen(sbuf); 1011 sbuf[sbuf_len - 2] = '\0'; 1012 sbuf_len -= 2; 1013 } 1014 1015 tot_len = strlen(service_name) + skip_len; 1016 1017 tmpnamef = tmpnam(ibconf_file); 1018 DPRINTF("ib_delete_service: tmpnamef = %s\n", tmpnamef); 1019 if ((ibcfg_tmpfd = creat(tmpnamef, 0666)) == -1) { 1020 (void) snprintf(*errmsg, MAXPATHLEN, 1021 "failed to creat %s file\n", ibconf_file); 1022 DPRINTF("ib_delete_service: failed to creat tmpnamef\n"); 1023 return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL)); 1024 } 1025 1026 /* Delete service from IBNEX */ 1027 if (ib_conf_control_ioctl(service_name, IBNEX_CONF_ENTRY_DEL)) { 1028 DPRINTF("ib_delete_service: ioctl delete failed %d\n", errno); 1029 (void) snprintf(*errmsg, MAXPATHLEN, "failed to delete " 1030 "in core %s entry ", service_name); 1031 close(ibcfg_tmpfd); 1032 unlink(tmpnamef); 1033 return (ib_cleanup_file(CFGA_IB_SVC_EXISTS_ERR)); 1034 } 1035 1036 /* write till ibcfg_brec */ 1037 if (write(ibcfg_tmpfd, file_buf, ibcfg_brec) == -1) { 1038 DPRINTF("ib_delete_service: write %s file failed 1\n", 1039 ibconf_file); 1040 close(ibcfg_tmpfd); 1041 unlink(tmpnamef); 1042 return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR)); 1043 } 1044 1045 /* write modified buffer */ 1046 if (write(ibcfg_tmpfd, sbuf, sbuf_len) == -1) { 1047 DPRINTF("ib_delete_service: write %s file failed 2\n", 1048 ibconf_file); 1049 close(ibcfg_tmpfd); 1050 unlink(tmpnamef); 1051 return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR)); 1052 } 1053 1054 /* Write the rest of the file as it was */ 1055 if (write(ibcfg_tmpfd, file_buf + ibcfg_brec + sbuf_len + tot_len, 1056 ibcfg_st.st_size - ibcfg_brec - sbuf_len - tot_len) == -1) { 1057 DPRINTF("ib_delete_service: write %s file failed 3\n", 1058 ibconf_file); 1059 close(ibcfg_tmpfd); 1060 unlink(tmpnamef); 1061 return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR)); 1062 } 1063 wrote_tmp = B_TRUE; 1064 1065 /* No error encountered */ 1066 return (ib_cleanup_file(rval)); 1067 } 1068 1069 1070 /* 1071 * Function: 1072 * ib_list_services 1073 * Input: 1074 * msgp - CFGADM message pointer 1075 * Output: 1076 * errmsg - Error message filled in case of a failure 1077 * Returns: 1078 * CFGA_IB_OK on success or an appropriate error 1079 * Description: 1080 * open IBCONF_FILE and list services. 1081 */ 1082 int 1083 ib_list_services(struct cfga_msg *msgp, char **errmsg) 1084 { 1085 int rval = CFGA_IB_OK; 1086 char pbuf[IBCONF_SERVICE_HDR_LEN]; 1087 ib_token_t token = NEWLINE; 1088 ib_svc_rec_t *recp; 1089 1090 DPRINTF("ib_list_services:\n"); 1091 if ((rval = ib_init_file(errmsg)) != CFGA_IB_OK) { 1092 DPRINTF("ib_list_services: initializing file failed\n"); 1093 return (rval); 1094 } 1095 1096 /* start reading the file */ 1097 while (token != EOF) 1098 token = ib_get_services(errmsg); 1099 1100 DPRINTF("ib_list_services: #port_services = %d, #vppa_services = %d," 1101 " #hca_services = %d\n", ibcfg_nport_services, 1102 ibcfg_nvppa_services, ibcfg_nhca_services); 1103 1104 bzero(pbuf, IBCONF_SERVICE_HDR_LEN); 1105 if (ibcfg_nport_services) { 1106 (void) snprintf(pbuf, IBCONF_SERVICE_HDR_LEN, 1107 IBCONF_PORT_SERVICE_HDR); 1108 cfga_msg(msgp, pbuf); 1109 for (recp = ibcfg_port_head; recp; recp = recp->next) { 1110 DPRINTF("ib_list_services: svc_name = %s\n", 1111 recp->name ? recp->name : "NONE"); 1112 (void) snprintf(pbuf, 14, "\t\t%s\n", recp->name); 1113 cfga_msg(msgp, pbuf); 1114 } 1115 (void) snprintf(pbuf, 2, "\n"); 1116 cfga_msg(msgp, pbuf); 1117 } 1118 1119 if (ibcfg_nvppa_services) { 1120 (void) snprintf(pbuf, IBCONF_SERVICE_HDR_LEN, 1121 IBCONF_VPPA_SERVICE_HDR); 1122 cfga_msg(msgp, pbuf); 1123 for (recp = ibcfg_vppa_head; recp; recp = recp->next) { 1124 DPRINTF("ib_list_services: svc_name = %s\n", 1125 strlen(recp->name) > 0 ? recp->name : "NONE"); 1126 (void) snprintf(pbuf, 14, "\t\t%s\n", recp->name); 1127 cfga_msg(msgp, pbuf); 1128 } 1129 } 1130 1131 if (ibcfg_nhca_services) { 1132 (void) snprintf(pbuf, IBCONF_SERVICE_HDR_LEN, 1133 IBCONF_HCA_SERVICE_HDR); 1134 cfga_msg(msgp, pbuf); 1135 for (recp = ibcfg_hca_head; recp; recp = recp->next) { 1136 DPRINTF("ib_list_services: svc_name = %s\n", 1137 strlen(recp->name) > 0 ? recp->name : "NONE"); 1138 (void) snprintf(pbuf, 14, "\t\t%s\n", recp->name); 1139 cfga_msg(msgp, pbuf); 1140 } 1141 } 1142 return (ib_cleanup_file(CFGA_IB_OK)); 1143 } 1144 1145 1146 /* 1147 * Function: 1148 * ib_conf_control_ioctl 1149 * Input: 1150 * svc - Service being added/deleted 1151 * cmd - Command to DEVCTL_AP_CONTROL devctl 1152 * Output: 1153 * NONE 1154 * Returns: 1155 * CFGA_IB_OK if it succeeds or an appropriate error. 1156 * Description: 1157 * Issues DEVCTL_AP_CONTROL devctl with cmd 1158 */ 1159 static cfga_ib_ret_t 1160 ib_conf_control_ioctl(char *svc, uint_t cmd) 1161 { 1162 int apid_fd = -1; 1163 cfga_ib_ret_t rv = CFGA_IB_OK; 1164 struct ibnex_ioctl_data ioctl_data; 1165 1166 DPRINTF("Service = %s len = %x, type = %x\n", svc, 1167 strlen(svc), service_type); 1168 1169 /* try to open the static IB ap_id */ 1170 if ((apid_fd = open(IB_STATIC_APID, O_RDONLY)) == -1) { 1171 DPRINTF("ib_conf_control_ioctl: open failed: errno = %d\n", 1172 errno); 1173 /* Provides a more useful error msg */ 1174 rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_OPEN_ERR; 1175 return (rv); 1176 } 1177 1178 ioctl_data.cmd = cmd; 1179 ioctl_data.misc_arg = (uint_t)service_type; 1180 ioctl_data.buf = (caddr_t)svc; 1181 ioctl_data.bufsiz = strlen(svc); 1182 ioctl_data.ap_id = (caddr_t)IB_STATIC_APID; 1183 ioctl_data.ap_id_len = strlen(IB_STATIC_APID); 1184 1185 if (ioctl(apid_fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) { 1186 DPRINTF("ib_conf_control_ioctl: size ioctl ERR, errno: %d\n", 1187 errno); 1188 rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_IOCTL_ERR; 1189 } 1190 (void) close(apid_fd); 1191 return (rv); 1192 } 1193 1194 /* 1195 * This functions checks if the service name is valid. Valid 1196 * service names have : 1197 * 0 < strlen(name) <= 4 1198 * Service name is unique 1199 * Returns: 0 - Name is not valid, 1 - Name is valid 1200 */ 1201 static int 1202 ib_service_record_valid(char *sname) 1203 { 1204 int rc = 1, len; 1205 char *tmp_service_name; 1206 1207 tmp_service_name = service_name; 1208 service_name = strdup(sname); 1209 len = strlen(sname); 1210 if (len == 0 || len > 4) { 1211 S_FREE(service_name); 1212 service_name = tmp_service_name; 1213 return (0); 1214 } 1215 if (ib_cmp_service() == B_TRUE) 1216 rc = 0; 1217 S_FREE(service_name); 1218 service_name = tmp_service_name; 1219 return (rc); 1220 } 1221