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 (c) 1996-1997, by Sun Microsystems, Inc. 24 * All Rights reserved. 25 */ 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 31 */ 32 33 /* LINTLIBRARY */ 34 35 /* 36 * putdev.c 37 * 38 * Global Definitions: 39 * _adddevtabrec() Add a record to the device table 40 * _putdevtabrec() Write a record to the device table 41 * _moddevtabrec() Modify a device-table record 42 * _rmdevtabrec() Remove a device-table record 43 * _rmdevtabattrs() Remove attributes from a device-table record 44 * oam_devtab File descriptor of the open device table 45 */ 46 47 /* 48 * G L O B A L R E F E R E N C E S 49 * 50 * Header Files 51 * Externals Referenced 52 */ 53 54 /* 55 * Header Files 56 * <sys/types.h> UNIX(r) Data Types 57 * <sys/stat.h> 58 * <stdio.h> Standard I/O definitions 59 * <fcntl.h> Definitions for file control 60 * <errno.h> Error handling definitions 61 * <string.h> String Handling Definitions 62 * <devmgmt.h> Device Management Definitions 63 * <unistd.h> Get UNIX(r) Standard Definitions 64 * "devtab.h" Local Device Management Definitions 65 */ 66 67 #include <sys/types.h> 68 #include <sys/stat.h> 69 #include <stdio.h> 70 #include <fcntl.h> 71 #include <errno.h> 72 #include <string.h> 73 #include <devmgmt.h> 74 #include <unistd.h> 75 #include <stdlib.h> 76 #include "devtab.h" 77 78 /* 79 * L O C A L D E F I N I T I O N S 80 * 81 * TDTABNM Name of the temporary device table (in the 82 * directory of the existing table) 83 */ 84 85 #define TDTABNM "%sdevtab.%6.6d" 86 87 88 /* 89 * Static functions 90 * strcatesc Copies a character-string from one place to another 91 * escaping the appropriate characters 92 * lkdevtab Locks the device table 93 * unlkdevtab Unlocks the device table 94 * mkdevtabent Builds a device-table entry from the alias and the 95 * list of attr=val pairs given 96 * opennewdevtab Opens a new device table (as a temp file) 97 * mknewdevtab Makes the temp device table the new devtab 98 * rmnewdevtab Remove the temporary device table and free space 99 * allocated to the filename of that file. 100 */ 101 102 static char *strcatesc(char *, char *); 103 static int lkdevtab(char *, short); 104 static int unlkdevtab(void); 105 static struct devtabent *mkdevtabent(char *, char **); 106 static FILE *opennewdevtab(char **); 107 static int mknewdevtab(char *); 108 static int rmnewdevtab(char *); 109 110 /* 111 * char *strcatesc(p, q) 112 * char *p 113 * char *q 114 * 115 * Write the character-string pointed to by "q" to the place 116 * pointed to by "p", escaping those characters in "q" found in the 117 * string "DTAB_ESCS" by preceding them with '\\'. Return a pointer to 118 * the byte beyond the last character written to "p". 119 * 120 * Arguments: 121 * p The place to begin writing to 122 * q The string to write 123 * 124 * Returns: char * 125 * The address of the byte beyond the last character written into "p" 126 */ 127 128 static char * 129 strcatesc( 130 char *p, /* Place to write to */ 131 char *q) /* Thing to write */ 132 { 133 while (*q) { 134 if (strchr(DTAB_ESCS, *q)) *p++ = '\\'; 135 *p++ = *q++; 136 } 137 return (p); 138 } 139 140 /* 141 * FILE *opennewdevtab(pname) 142 * char **pname 143 * 144 * Generates a temporary device-table name from the existing 145 * device table name (in the same directory) and opens that 146 * file for writing. It puts a pointer to the malloc()ed space 147 * containing the temp device table's name at the place referenced 148 * by <pname>. 149 * 150 * Arguments: 151 * pname Pointer to the char * to contain the address of the name 152 * of the temporary file 153 * 154 * Returns: FILE * 155 * A pointer to the opened stream or (FILE *) NULL if an error occurred. 156 * If an error occurred, "errno" will be set to reflect the problem. 157 */ 158 159 static FILE * 160 opennewdevtab(char **pname) /* A(ptr to temp filename's path) */ 161 { 162 char *oldname; /* Ptr to the device-table's name */ 163 char *buf; /* Ptr to the temp file's name */ 164 char *dirname; /* Directory containing devtab */ 165 char *p; /* Ptr to last '/' in devtab name */ 166 int fd; /* Opened file descriptor */ 167 FILE *fp; /* Opened file pointer */ 168 struct stat64 sbuf; /* stat buf for old devtab file */ 169 170 fp = NULL; 171 if (oldname = _devtabpath()) { 172 /* 173 * It is possible for us to have sufficient permissions to create 174 * the new file without having sufficient permissions to write the 175 * original devtab file. For consistency with the operations which 176 * modify the original file by writing it directly we require write 177 * permissions for the original file in order to make a new one. 178 */ 179 if ((fd = open(oldname, O_WRONLY)) == -1) 180 return (NULL); 181 182 if (fstat64(fd, &sbuf) == -1) { 183 (void) close(fd); 184 return (NULL); 185 } 186 (void) close(fd); 187 188 if (p = strrchr(oldname, '/')) { 189 *(p+1) = '\0'; 190 dirname = oldname; 191 } else dirname = "./"; 192 if (asprintf(&buf, TDTABNM, dirname, getpid()) >= 0) { 193 194 /* 195 * Build the name of the temp device table and 196 * open the file. We must reset the owner, group 197 * and perms to those of the original devtab file. 198 */ 199 if (fp = fopen(buf, "w")) { 200 *pname = buf; 201 (void) fchmod(fileno(fp), sbuf.st_mode & 0777); 202 (void) fchown(fileno(fp), sbuf.st_uid, sbuf.st_gid); 203 } else { 204 free(buf); 205 } 206 } 207 208 /* 209 * 210 * Free the space containing the device table's name. 211 */ 212 free(oldname); 213 } 214 215 /* Finished. Return what we've got */ 216 return (fp); 217 } 218 219 /* 220 * int rmnewdevtab(tempname) 221 * char *tempname 222 * 223 * Unlink the temp device table and free the memory allocated to 224 * contain the name of that file 225 * 226 * Arguments: 227 * tempname Name of the temporary file 228 * 229 * Returns: int 230 * TRUE if successful, FALSE otherwise 231 */ 232 233 static int 234 rmnewdevtab(char *tempname) /* Filename of new device table */ 235 { 236 int noerr; /* Flag, TRUE if no error, FALSE otherwise */ 237 238 /* Unlink the file */ 239 noerr = (unlink(tempname) == 0); 240 241 /* Free the space allocated to the filename */ 242 free(tempname); 243 244 /* Return success indicator */ 245 return (noerr); 246 } 247 248 /* 249 * int mknewdevtab(tempname) 250 * char *tempname 251 * 252 * Make the temporary device-table the new system device table 253 * 254 * Arguments: 255 * tempname Name of the temporary file 256 * 257 * Returns: int 258 * TRUE if successful, FALSE otherwise 259 * 260 * Notes: 261 * - Need to use rename() someday instead of link()/unlink() 262 * - This code is somewhat ineffecient in that asks for the name 263 * of the device-table more than once. Done so that we don't 264 * have to manage that space, but this may be somewhat lazy. 265 */ 266 267 static int 268 mknewdevtab(char *tempname) /* Ptr to name of temp dev tab */ 269 { 270 char *devtabname; /* Ptr to the device table's name */ 271 int noerr; /* FLAG, TRUE if all's well */ 272 273 /* Get the device table's pathname */ 274 if (devtabname = _devtabpath()) { 275 276 /* Unlink the existing file */ 277 if (unlink(devtabname) == 0) { 278 279 /* Make the temp file the real device table */ 280 noerr = (link(tempname, devtabname) == 0) ? TRUE : FALSE; 281 282 /* Remove the temp file (and resources) */ 283 if (noerr) (void) rmnewdevtab(tempname); 284 285 } else noerr = FALSE; /* unlink() failed */ 286 287 /* Free the device table's name */ 288 free(devtabname); 289 290 } else noerr = FALSE; /* devtabpath() failed */ 291 292 /* Finished. Return success indicator */ 293 return (noerr); 294 } 295 296 /* 297 * static int lkdevtab(o_mode, lktype) 298 * char *o_mode 299 * short lktype 300 * 301 * Lock the device table for writing. If it isn't available, it waits 302 * until it is. 303 * 304 * Arguments: 305 * o_mode The open() mode to use when opening the device table 306 * lktype The type of lock to apply 307 * 308 * Returns: int 309 * TRUE if successful, FALSE with errno set otherwise 310 */ 311 312 static int 313 lkdevtab( 314 char *o_mode, /* Open mode */ 315 short lktype) /* Lock type */ 316 { 317 /* Automatic data */ 318 struct flock lockinfo; /* File locking structure */ 319 int noerr; /* FLAG, TRUE if no error */ 320 int olderrno; /* Old value of "errno" */ 321 322 323 /* Close the device table (if it's open) */ 324 _enddevtab(); 325 326 /* Open the device table for read/append */ 327 noerr = TRUE; 328 if (_opendevtab(o_mode)) { 329 330 /* 331 * Lock the device table (for writing). If it's not 332 * available, wait until it is, then close and open the 333 * table (modify and delete change the table!) and try 334 * to lock it again 335 */ 336 337 /* Build the locking structure */ 338 lockinfo.l_type = lktype; 339 lockinfo.l_whence = 0; 340 lockinfo.l_start = 0L; 341 lockinfo.l_len = 0L; 342 olderrno = errno; 343 344 /* Keep on going until we lock the file or an error happens */ 345 while ((fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) == -1) && 346 !noerr) { 347 if (errno == EACCES) { 348 if (fcntl(fileno(oam_devtab), F_SETLKW, &lockinfo) == -1) 349 noerr = FALSE; 350 else { 351 /* Reopen the file (maybe it's moved?) */ 352 _enddevtab(); 353 if (!_opendevtab(o_mode)) noerr = FALSE; 354 else errno = olderrno; 355 } 356 } else noerr = FALSE; 357 } 358 359 if (!noerr) _enddevtab(); /* Don't keep open if in error */ 360 361 } else noerr = FALSE; 362 363 /* Done */ 364 return (noerr); 365 } 366 367 /* 368 * int unlkdevtab() 369 * 370 * Unlock the locked device table. 371 * 372 * Arguments: None 373 * 374 * Returns: int 375 * Whatever fcntl() returns... 376 */ 377 378 static int 379 unlkdevtab(void) 380 { 381 /* Automatic data */ 382 struct flock lockinfo; /* Locking structure */ 383 int noerr; /* FLAG, TRUE if all's well */ 384 385 /* Build the locking structure */ 386 lockinfo.l_type = F_UNLCK; /* Lock type */ 387 lockinfo.l_whence = 0; /* Count from top of file */ 388 lockinfo.l_start = 0L; /* From beginning */ 389 lockinfo.l_len = 0L; /* Length of locked data */ 390 391 /* Unlock it */ 392 noerr = (fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) != -1); 393 _enddevtab(); 394 395 /* Finished */ 396 return (noerr); 397 } 398 399 /* 400 * struct devtabent *mkdevtabent(alias, attrlist) 401 * char *alias 402 * char **attrlist 403 * 404 * This function builds a struct devtabent structure describing the 405 * alias <alias> using the information in the attribute list <attrlist>. 406 * The <attrlist> contains data of the form attr=value where attr is 407 * the name of an attribute and value is the value of that attribute. 408 * 409 * Arguments: 410 * alias The alias being added to the device table 411 * attrlist The attributes and values for that alias 412 * 413 * Returns: struct devtabent * 414 * A completed struct devtabent structure containing the description 415 * of the alias. The structure, and all of the data in the structure 416 * are each in space allocated using the malloc() function and should 417 * be freed using the free() function (or the _freedevtabent() function). 418 * 419 * Errors: 420 * EINVAL If "alias" is used as an attribute in an attr=val pair 421 * EAGAIN If an attribute is specified more than once 422 */ 423 424 static struct devtabent * 425 mkdevtabent( 426 char *alias, /* Alias of entry */ 427 char **attrlist) /* Attributes of new entry */ 428 { 429 /* Automatic data */ 430 struct devtabent *devtabent; /* * to struct we're making */ 431 struct attrval *prevattrval; /* * to prev attr/val struct */ 432 struct attrval *attrval; /* * to current struct */ 433 char **pp; /* Ptr into list of ptrs */ 434 char *peq; /* Ptr to '=' in string */ 435 char *val; /* Ptr to space for value */ 436 char *name; /* Ptr to space for name */ 437 ssize_t len; /* Length of name */ 438 int noerr; /* TRUE if all's well */ 439 int found; /* TRUE the attr is found */ 440 441 442 /* No problems (yet) */ 443 noerr = TRUE; 444 445 /* Get space for the structure */ 446 if (devtabent = malloc(sizeof (struct devtabent))) { 447 448 /* Fill in default values */ 449 if (devtabent->alias = malloc(strlen(alias)+1)) { 450 451 (void) strcpy(devtabent->alias, alias); /* alias */ 452 devtabent->comment = FALSE; /* data rec */ 453 devtabent->cdevice = NULL; /* cdevice */ 454 devtabent->bdevice = NULL; /* bdevice */ 455 devtabent->pathname = NULL; /* pathname */ 456 devtabent->attrstr = NULL; /* string */ 457 devtabent->attrlist = NULL; /* attr list */ 458 459 /* Add attributes to the structure */ 460 prevattrval = NULL; 461 if ((pp = attrlist) != NULL) 462 while (*pp && noerr) { 463 464 /* Valid attr=value pair? */ 465 if (((peq = strchr(*pp, '=')) != NULL) && 466 ((len = peq - *pp) > 0)) { 467 468 /* Get space for the value */ 469 if (val = malloc(strlen(peq))) { 470 (void) strcpy(val, peq+1); /* Copy it */ 471 472 /* Get space for attribute name */ 473 if (name = malloc((size_t)(len + 1))) { 474 (void) strncpy(name, *pp, (size_t)len); 475 *(name+len) = '\0'; 476 477 /* Specifying the alias? If so, ERROR */ 478 if (strcmp(name, DTAB_ALIAS) == 0) { 479 noerr = FALSE; 480 free(name); 481 free(val); 482 errno = EINVAL; 483 } 484 485 /* Specifying the char device path? */ 486 else if (strcmp(name, DTAB_CDEVICE) == 0) { 487 if (!devtabent->cdevice) { 488 if (val[0] != '/') { 489 noerr = FALSE; 490 free(name); 491 free(val); 492 errno = ENXIO; 493 } else { 494 devtabent->cdevice = val; 495 free(name); 496 } 497 } else { 498 noerr = FALSE; 499 free(name); 500 free(val); 501 errno = EAGAIN; 502 } 503 } 504 505 /* Specifying the block device path? */ 506 else if (strcmp(name, DTAB_BDEVICE) == 0) { 507 if (!devtabent->bdevice) { 508 if (val[0] != '/') { 509 noerr = FALSE; 510 free(name); 511 free(val); 512 errno = ENXIO; 513 } else { 514 devtabent->bdevice = val; 515 free(name); 516 } 517 } else { 518 noerr = FALSE; 519 free(name); 520 free(val); 521 errno = EAGAIN; 522 } 523 } 524 525 /* Specifying the pathname (generic)? */ 526 else if (strcmp(name, DTAB_PATHNAME) == 0) { 527 if (!devtabent->pathname) { 528 if (val[0] != '/') { 529 noerr = FALSE; 530 free(name); 531 free(val); 532 errno = ENXIO; 533 } else { 534 devtabent->pathname = val; 535 free(name); 536 } 537 } else { 538 noerr = FALSE; 539 free(name); 540 free(val); 541 errno = EAGAIN; 542 } 543 } 544 545 /* Some other attribute */ 546 else { 547 found = FALSE; 548 if ((attrval = devtabent->attrlist) != NULL) 549 do { 550 if (strcmp(attrval->attr, 551 name) == 0) { 552 553 noerr = FALSE; 554 free(name); 555 free(val); 556 errno = EAGAIN; 557 } 558 } while (!found && noerr && 559 (attrval = attrval->next)); 560 561 if (!found && noerr) { 562 563 /* Get space for attr/val structure */ 564 if (attrval = 565 malloc(sizeof (struct attrval))) { 566 567 /* Fill attr/val structure */ 568 attrval->attr = name; 569 attrval->val = val; 570 attrval->next = NULL; 571 572 /* 573 * Link into the list of attributes 574 */ 575 if (prevattrval) 576 prevattrval->next = attrval; 577 else devtabent->attrlist = attrval; 578 prevattrval = attrval; 579 580 } else { 581 /* malloc() for attrval failed */ 582 noerr = FALSE; 583 free(name); 584 free(val); 585 } 586 } 587 } /* End else (some other attribute) */ 588 589 } else { /* malloc() for attribute name failed */ 590 noerr = FALSE; 591 free(val); 592 } 593 594 } else noerr = FALSE; /* Malloc() for "val" failed */ 595 596 /* If we saw an error, free structure, returning NULL */ 597 if (!noerr) { 598 _freedevtabent(devtabent); 599 devtabent = NULL; 600 } 601 602 } /* Ignore invalid attr=val pair */ 603 604 if (noerr) pp++; 605 606 } /* End attribute processing loop */ 607 608 } else { /* malloc() failed */ 609 free(devtabent); 610 devtabent = NULL; 611 } 612 } 613 614 /* Finished */ 615 return (devtabent); 616 } 617 618 /* 619 * int _putdevtabrec(stream, rec) 620 * FILE *stream 621 * struct devtabent *rec 622 * 623 * Write a device table record containing the information in the struct 624 * devtab structure <rec> to the current position of the standard I/O 625 * stream <stream>. 626 * 627 * Arguments: 628 * stream The stream to write to 629 * rec The structure containing the information to write 630 * 631 * Returns: int 632 * The number of characters written or EOF if there was some error. 633 */ 634 635 int 636 _putdevtabrec( 637 FILE *stream, /* Stream to which to write */ 638 struct devtabent *rec) /* Record to write */ 639 { 640 /* Automatic Data */ 641 struct attrval *attrval; /* Ptr to attr/val pair */ 642 char *buf; /* Allocated buffer */ 643 char *p; /* Temp char pointer */ 644 int count; /* Number of chars written */ 645 size_t size = 0; /* Size of needed buffer */ 646 647 648 /* Comment or data record? */ 649 if (rec->comment) { 650 651 /* 652 * Record is a comment 653 */ 654 655 /* Copy (escaping chars) record into temp buffer */ 656 size = (strlen(rec->attrstr)*2)+1; /* Max rec size */ 657 if (buf = malloc(size+1)) { 658 /* Alloc space */ 659 p = strcatesc(buf, rec->attrstr); /* Copy "escaped" */ 660 *(p-2) = '\n'; /* Unescape last \n */ 661 *(p-1) = '\0'; /* Terminate string */ 662 663 /* Write the record */ 664 count = fputs(buf, stream); 665 free(buf); 666 667 } else count = EOF; /* malloc() failed */ 668 } 669 670 else { 671 672 /* 673 * Record is a data record 674 */ 675 676 /* 677 * Figure out maximum amount of space you're going to need. 678 * (Assume every escapable character is escaped to determine the 679 * maximum size needed) 680 */ 681 682 if (rec->cdevice) 683 size += (strlen(rec->cdevice)*2) + 1; /* cdevice: */ 684 if (rec->bdevice) 685 size += (strlen(rec->bdevice)*2) + 1; /* bdevice: */ 686 if (rec->pathname) 687 size += (strlen(rec->pathname)*2) + 1; /* pathname: */ 688 if ((attrval = rec->attrlist) != NULL) do { /* Attributes */ 689 if (attrval->attr) 690 size += (strlen(attrval->attr)*2); /* attr */ 691 if (attrval->val) { 692 /* val & '="" ' or val & '=""\n' */ 693 size += (strlen(attrval->val)*2) +4; 694 } 695 } while ((attrval = attrval->next) != NULL); /* Next attr/val */ 696 else size++; /* Else make room for trailing '\n' */ 697 698 /* Alloc space for "escaped" record */ 699 if (buf = malloc(size+1)) { 700 701 /* Initializations */ 702 p = buf; 703 704 /* Write the alias ("alias" attribute) */ 705 p = strcatesc(p, rec->alias); 706 *p++ = ':'; 707 708 /* Write the character device ("cdevice" attribute) */ 709 if (rec->cdevice) p = strcatesc(p, rec->cdevice); 710 *p++ = ':'; 711 712 /* Write the block device ("bdevice" attribute) */ 713 if (rec->bdevice) p = strcatesc(p, rec->bdevice); 714 *p++ = ':'; 715 716 /* Write the pathname ("pathname" attribute) */ 717 if (rec->pathname) p = strcatesc(p, rec->pathname); 718 *p++ = ':'; 719 720 /* Write the rest of the attributes */ 721 if ((attrval = rec->attrlist) != NULL) 722 do { 723 p = strcatesc(p, attrval->attr); 724 *p++ = '='; 725 *p++ = '"'; 726 p = strcatesc(p, attrval->val); 727 *p++ = '"'; 728 if ((attrval = attrval->next) != NULL) 729 *p++ = ' '; 730 } while (attrval); 731 732 /* Terminate the record */ 733 *p++ = '\n'; 734 *p = '\0'; 735 736 /* Write the record */ 737 count = fputs(buf, stream); 738 free(buf); 739 } else count = EOF; /* malloc() failed */ 740 } 741 742 /* Finished */ 743 return (count); 744 } 745 746 /* 747 * int _adddevtabrec(alias, attrval) 748 * char *alias 749 * char **attrval 750 * 751 * This function adds a record to the device table. That record will 752 * have the alias <alias> and will have the attributes described in 753 * the list referenced by <attrval>. 754 * 755 * It always adds the record to the end of the table. 756 * 757 * Arguments: 758 * alias The alias of the device whose description is being 759 * added to the device table. 760 * attrval The pointer to the first item of a list of attributes 761 * defining the device whose description is being added. 762 * (This value may be (char **) NULL). 763 * 764 * Returns: int 765 * TRUE if successful, FALSE with errno set otherwise. 766 */ 767 768 int 769 _adddevtabrec( 770 char *alias, /* Alias to add to the device table */ 771 char **attrval) /* Attributes for that device */ 772 { 773 /* Automatic data */ 774 struct devtabent *devtabent; /* Ptr to dev tab entry */ 775 int olderrno; /* Errno on entry */ 776 int noerr; /* FLAG, TRUE if all's well */ 777 778 /* Validate the device alias. Error (EINVAL) if it's not valid */ 779 if (!_validalias(alias)) { 780 errno = EINVAL; 781 return (FALSE); 782 } 783 784 /* 785 * Lock the device table. This only returns if the table is locked or 786 * some error occurred. It waits until the table is available. 787 */ 788 if (!lkdevtab("a+", F_WRLCK)) 789 return (FALSE); 790 791 /* Make sure that the alias isn't already in the table */ 792 noerr = TRUE; 793 olderrno = errno; 794 if (devtabent = _getdevrec(alias)) { 795 796 /* The alias is already in the table */ 797 _freedevtabent(devtabent); /* Free device table info */ 798 errno = EEXIST; /* Set errno, entry exists */ 799 noerr = FALSE; /* All's not well */ 800 } else if ((errno == ENOENT) || (errno == ENODEV)) { 801 802 /* The alias wasn't in the table or there wasn't a table. */ 803 804 errno = olderrno; /* Reset errno */ 805 806 /* Build a struct devtabent that describes the new alias */ 807 if (devtabent = mkdevtabent(alias, attrval)) { 808 809 /* Position to the end of the existing table */ 810 if (fseek(oam_devtab, 0, SEEK_END) == 0) 811 812 /* Write the new entry */ 813 noerr = (_putdevtabrec(oam_devtab, devtabent) != EOF); 814 815 /* Free the info we just wrote */ 816 _freedevtabent(devtabent); 817 818 } else noerr = FALSE; /* mkdevtabent() failed */ 819 } else noerr = FALSE; /* Some odd error, _devtab */ 820 821 /* Unlock and close the device table */ 822 (void) unlkdevtab(); 823 824 /* Fini */ 825 return (noerr); 826 } 827 828 /* 829 * int _moddevtabrec(device, attrval) 830 * char *device 831 * char **attrval 832 * 833 * This function modifies the description for the specified device 834 * so that it has the attributes and values as specified in the 835 * given list. 836 * 837 * Arguments: 838 * device The name of the device whose description 839 * is being modified 840 * attrval The first attr/val value in the list (attr=val) of 841 * the attributes that are to change 842 * 843 * Returns: int 844 * TRUE if all went well, FALSE with errno set otherwise 845 */ 846 847 int 848 _moddevtabrec( 849 char *device, /* Device to modify */ 850 char **attrval) /* Attributes to add or change */ 851 { 852 /* Automatic data */ 853 FILE *fd; /* File ptr, new device table */ 854 struct devtabent *ent; /* Device's current description */ 855 struct devtabent *chg; /* Changes to make to description */ 856 struct attrval *new; /* New attribute/value desc */ 857 struct attrval *old; /* Old attribute/value desc */ 858 struct attrval *newnew; /* Next "new" value to look at */ 859 struct attrval *prevnew; /* Previous item in the 'new' list */ 860 char *tname; /* name of temp devtab file */ 861 int noerr; /* FLAG, TRUE if all's well */ 862 int found; /* FLAG, TRUE if attr found for dev */ 863 864 /* Lock the device table */ 865 if (!lkdevtab("r", F_WRLCK)) 866 return (FALSE); 867 868 /* No problems (so far) */ 869 noerr = TRUE; 870 871 /* Get the entry to modify */ 872 if (ent = _getdevrec(device)) { 873 874 /* Build a structure describing the changes */ 875 if (chg = mkdevtabent(device, attrval)) { 876 877 /* If the "cdevice" field is specified, change it */ 878 if (chg->cdevice) { 879 if (ent->cdevice) free(ent->cdevice); 880 ent->cdevice = chg->cdevice; 881 chg->cdevice = NULL; 882 } 883 884 /* If the "bdevice" field is specified, change it */ 885 if (chg->bdevice) { 886 if (ent->bdevice) free(ent->bdevice); 887 ent->bdevice = chg->bdevice; 888 chg->bdevice = NULL; 889 } 890 891 /* If the "pathname" field is specified, change it */ 892 if (chg->pathname) { 893 if (ent->pathname) free(ent->pathname); 894 ent->pathname = chg->pathname; 895 chg->pathname = NULL; 896 } 897 898 /* Change the other attributes (if any) */ 899 if (ent->attrlist) { 900 prevnew = NULL; 901 if ((new = chg->attrlist) != NULL) do { 902 903 found = FALSE; 904 for (old = ent->attrlist; !found && old; 905 old = old->next) { 906 if (strcmp(old->attr, new->attr) == 0) { 907 found = TRUE; 908 free(old->val); 909 old->val = new->val; 910 new->val = NULL; 911 } 912 } /* Loop through the existing attribute list */ 913 914 /* 915 * If the attribute wasn't found, add it to the list 916 * of attributes for the device. If it was found, just 917 * bump to the next one and look for it 918 */ 919 920 if (!found) { 921 922 /* 923 * Not found. Move attr/val description to the 924 * device's list of attributes 925 */ 926 927 if (prevnew) prevnew->next = new->next; 928 else chg->attrlist = new->next; 929 newnew = new->next; 930 new->next = ent->attrlist; 931 ent->attrlist = new; 932 new = newnew; 933 } else { 934 935 /* Attribute changed, bump to the next one */ 936 prevnew = new; 937 new = new->next; 938 } 939 } while (new); /* Loop for each attr to add or modify */ 940 941 } else { 942 943 /* Device had no attributes -- add entire list */ 944 ent->attrlist = chg->attrlist; 945 chg->attrlist = NULL; 946 } 947 948 /* Free the structure containing the changes */ 949 _freedevtabent(chg); 950 951 } else noerr = FALSE; /* Couldn't build changes struct */ 952 953 /* If there hasn't been an error (so far), write the new record */ 954 if (noerr) { 955 956 /* Open the new device table */ 957 if (fd = opennewdevtab(&tname)) { 958 959 /* 960 * For each entry in the existing table, write that entry 961 * to the new table. If the entry is the one being 962 * modified, write the modified entry instead of the 963 * original entry. 964 */ 965 966 _setdevtab(); /* Rewind existing table */ 967 chg = ent; /* Remember new record */ 968 while (((ent = _getdevtabent()) != NULL) && noerr) { 969 if (ent->entryno != chg->entryno) 970 noerr = _putdevtabrec(fd, ent) != EOF; 971 else noerr = _putdevtabrec(fd, chg) != EOF; 972 _freedevtabent(ent); 973 } 974 975 /* 976 * If we successfully generated the new table, make it the 977 * new system device table. Otherwise, just remove the 978 * temporary file we've created. 979 */ 980 981 if (noerr) { 982 (void) fclose(fd); 983 noerr = mknewdevtab(tname); 984 } else { 985 (void) fclose(fd); 986 (void) rmnewdevtab(tname); 987 } 988 989 /* Free the changed device structure */ 990 _freedevtabent(chg); 991 992 } /* if (_opennewdevtab()) */ 993 else noerr = FALSE; 994 995 } else _freedevtabent(ent); /* if (noerr) */ 996 997 } else noerr = FALSE; /* Device not found? */ 998 999 /* Finished. Unlock the device table and quit */ 1000 (void) unlkdevtab(); 1001 return (noerr); 1002 } 1003 1004 /* 1005 * int _rmdevtabrec(device) 1006 * char *device 1007 * 1008 * This function removes the record in the device table for the specified 1009 * device. 1010 * 1011 * Arguments: 1012 * device The device (alias, cdevice, bdevice, pathname, or link to one) 1013 * whose entry is to be removed 1014 * 1015 * Returns: int 1016 * Success indicator: TRUE if successful, FALSE with errno set otherwise. 1017 */ 1018 1019 int 1020 _rmdevtabrec(char *device) /* Device to remove */ 1021 { 1022 struct devtabent *rment; 1023 struct devtabent *devtabent; 1024 char *tempname; 1025 FILE *fd; 1026 int noerr; 1027 1028 if (!lkdevtab("r", F_WRLCK)) 1029 return (FALSE); 1030 noerr = TRUE; 1031 if (rment = _getdevrec(device)) { 1032 if (fd = opennewdevtab(&tempname)) { 1033 _setdevtab(); 1034 while (((devtabent = _getdevtabent()) != NULL) && noerr) { 1035 if (devtabent->entryno != rment->entryno) 1036 noerr = _putdevtabrec(fd, devtabent) != EOF; 1037 _freedevtabent(devtabent); 1038 } 1039 if (noerr) { 1040 (void) fclose(fd); 1041 noerr = mknewdevtab(tempname); 1042 } else { 1043 (void) fclose(fd); 1044 (void) rmnewdevtab(tempname); 1045 } 1046 } else noerr = FALSE; 1047 _freedevtabent(rment); 1048 } else noerr = FALSE; 1049 (void) unlkdevtab(); 1050 return (noerr); 1051 } 1052 1053 /* 1054 * int _rmdevtabattrs(device, attributes, notfounds) 1055 * char *device 1056 * char **attributes 1057 * char ***notfounds 1058 * 1059 * Remove the specified attributes from the specified device. The 1060 * device is specified by <device>, <attributes> is the address of 1061 * the first char * in the list of char * pointing to the attributes 1062 * to remove from the device, and <notfounds> is the address of a 1063 * char ** to put the address of the first element in the malloc()ed 1064 * list of (char *) pointing to requested attributes that were not 1065 * defined for the device <device>. 1066 * 1067 * Arguments: 1068 * device The device from which attributes are to be removed 1069 * attributes The address of the first element in the list of 1070 * attributes to remove. This list is terminated by 1071 * (char *) NULL. 1072 * notfounds The place to put the address of the list of addresses 1073 * referencing the requested attributes that are not 1074 * defined for the specified device. 1075 * 1076 * Returns: int 1077 * TRUE if successful, FALSE with errno set otherwise. 1078 * 1079 * Notes: 1080 * - "alias" may not be undefined 1081 * - "cdevice", "bdevice", and "pathname" are made "null", not really 1082 * undefined 1083 */ 1084 1085 int 1086 _rmdevtabattrs( 1087 char *device, /* Device to modify */ 1088 char **attributes, /* Attributes to remove */ 1089 char ***notfounds) /* Attributes req'd but not found */ 1090 { 1091 /* Automatics */ 1092 char **pnxt; /* Ptr to next attribute */ 1093 char **pp; /* Ptr to current attr name */ 1094 struct devtabent *modent; /* Entry being modified */ 1095 struct devtabent *devtabent; /* Entry being copied */ 1096 struct attrval *attrval; /* Ptr to attr/val desc */ 1097 struct attrval *prevattrval; /* Ptr to prev attr/val */ 1098 FILE *fd; /* File desc, temp file */ 1099 char *tempname; /* Name of temp file */ 1100 int nattrs; /* Number of attrs to remove */ 1101 int nobaderr; /* TRUE if no fatal error */ 1102 int noerr; /* TRUE if no non-fatal error */ 1103 int found; /* TRUE if attribute found */ 1104 int nonotfounds; /* TRUE if no attrs not fount */ 1105 1106 1107 /* Initializations */ 1108 nobaderr = TRUE; 1109 noerr = TRUE; 1110 1111 /* Count attributes to remove -- make sure "alias" isn't specified */ 1112 for (pp = attributes, nattrs = 0; *pp; pp++, nattrs++) 1113 if (strcmp(*pp, DTAB_ALIAS) == 0) { 1114 *notfounds = NULL; 1115 errno = EINVAL; 1116 return (FALSE); 1117 } 1118 1119 /* Lock the device table */ 1120 if (!lkdevtab("r", F_WRLCK)) 1121 return (FALSE); 1122 1123 /* Is there a record for the requested device? */ 1124 if (modent = _getdevrec(device)) { 1125 1126 /* Record found. Try to modify it */ 1127 nonotfounds = TRUE; 1128 1129 /* For each of the attributes in the attribute list ... */ 1130 for (pp = attributes; nobaderr && *pp; pp++) { 1131 1132 /* 1133 * Modify the device description, removing the requested 1134 * attributes from the structure 1135 */ 1136 1137 found = FALSE; /* Not found yet */ 1138 1139 /* If it's the "cdevice" attribute, make it a null-string */ 1140 if (strcmp(*pp, DTAB_CDEVICE) == 0) { 1141 if (modent->cdevice) { 1142 free(modent->cdevice); 1143 modent->cdevice = NULL; 1144 } 1145 found = TRUE; 1146 } 1147 1148 /* If it's the "bdevice" attribute, make it a null-string */ 1149 else if (strcmp(*pp, DTAB_BDEVICE) == 0) { 1150 if (modent->bdevice) { 1151 free(modent->bdevice); 1152 modent->bdevice = NULL; 1153 } 1154 found = TRUE; 1155 } 1156 1157 /* If it's the "pathname" attribute, make it a null-string */ 1158 else if (strcmp(*pp, DTAB_PATHNAME) == 0) { 1159 if (modent->pathname) { 1160 free(modent->pathname); 1161 modent->pathname = NULL; 1162 } 1163 found = TRUE; 1164 } 1165 1166 /* Must be one of the other "auxilliary" attributes */ 1167 else { 1168 1169 /* Search the attribute list for the attribute */ 1170 prevattrval = NULL; 1171 if ((attrval = modent->attrlist) != NULL) do { 1172 if (strcmp(*pp, attrval->attr) == 0) { 1173 1174 /* Found. Remove from attribute list */ 1175 found = TRUE; 1176 free(attrval->attr); 1177 free(attrval->val); 1178 if (prevattrval) { 1179 prevattrval->next = attrval->next; 1180 free(attrval); 1181 attrval = prevattrval->next; 1182 } else { 1183 modent->attrlist = attrval->next; 1184 free(attrval); 1185 attrval = modent->attrlist; 1186 } 1187 } else { 1188 prevattrval = attrval; /* Advance to next */ 1189 attrval = attrval->next; 1190 } 1191 } while (!found && attrval); 1192 1193 } /* End attribute search loop */ 1194 1195 /* 1196 * If the requested attribute wasn't defined for the device, 1197 * put it in the list of attributes not found 1198 */ 1199 1200 if (!found) { 1201 1202 /* 1203 * If there's no list (yet), alloc enough space for 1204 * the list 1205 */ 1206 1207 if (nonotfounds) 1208 if (*notfounds = malloc(sizeof (char **)*(nattrs+1))) { 1209 1210 /* List allocated -- put in the first entry */ 1211 nonotfounds = FALSE; 1212 pnxt = *notfounds; 1213 if (*pnxt = malloc(strlen(*pp)+1)) { 1214 errno = EINVAL; 1215 noerr = FALSE; 1216 (void) strcpy(*pnxt++, *pp); 1217 } else { 1218 /* malloc() failed, free list */ 1219 free(*notfounds); 1220 *notfounds = NULL; 1221 nonotfounds = TRUE; 1222 nobaderr = FALSE; 1223 } 1224 1225 } else nobaderr = FALSE; /* malloc() failed */ 1226 1227 else { 1228 /* Already a list, add this attribute to it */ 1229 if (*pnxt = malloc(strlen(*pp)+1)) 1230 (void) strcpy(*pnxt++, *pp); 1231 else { 1232 /* Out of memory, clean up */ 1233 for (pnxt = *notfounds; *pnxt; pnxt++) 1234 free(*pnxt); 1235 free(*notfounds); 1236 *notfounds = NULL; 1237 nonotfounds = TRUE; 1238 nobaderr = FALSE; 1239 } 1240 } 1241 1242 } /* end if (!found) */ 1243 1244 /* Terminate the not-found list */ 1245 if (!nonotfounds) *pnxt = NULL; 1246 1247 } /* end (for each attribute in attribute list) loop */ 1248 1249 1250 /* 1251 * If we haven't seen any problems so far, 1252 * write the new device table 1253 */ 1254 1255 if (nobaderr) { 1256 1257 /* Open the new device table */ 1258 if (fd = opennewdevtab(&tempname)) { 1259 1260 /* 1261 * For each entry in the existing table, write that entry 1262 * to the new table. If the entry is the one being 1263 * modified, write the modified entry instead of the 1264 * original entry. 1265 */ 1266 1267 _setdevtab(); /* Rewind existing table */ 1268 while (((devtabent = _getdevtabent()) != NULL) && 1269 nobaderr) { 1270 1271 if (devtabent->entryno != modent->entryno) 1272 nobaderr = _putdevtabrec(fd, devtabent) != EOF; 1273 else nobaderr = _putdevtabrec(fd, modent) != EOF; 1274 _freedevtabent(devtabent); 1275 } 1276 1277 /* 1278 * If we successfully generated the new table, make it the 1279 * new system device table. Otherwise, just remove the 1280 * temporary file we've created. 1281 */ 1282 1283 if (nobaderr) { 1284 (void) fclose(fd); 1285 nobaderr = mknewdevtab(tempname); 1286 } else { 1287 (void) fclose(fd); 1288 (void) rmnewdevtab(tempname); 1289 } 1290 1291 } /* if (_opennewdevtab()) */ 1292 else nobaderr = FALSE; 1293 1294 /* 1295 * If there was some error, we need to clean up 1296 * allocated resources 1297 */ 1298 if (!nobaderr && !nonotfounds) { 1299 for (pnxt = *notfounds; *pnxt; pnxt++) 1300 free(*pnxt); 1301 free(*notfounds); 1302 *notfounds = NULL; 1303 nonotfounds = TRUE; 1304 } 1305 1306 } /* if (nobaderr) */ 1307 1308 /* Free the resources alloc'ed for <device>'s entry */ 1309 _freedevtabent(modent); 1310 1311 } else { 1312 /* _getdevrec(device) failed */ 1313 nobaderr = FALSE; 1314 *notfounds = NULL; 1315 } 1316 1317 /* Unlock the device table */ 1318 (void) unlkdevtab(); 1319 1320 /* We're finished */ 1321 return (noerr && nobaderr); 1322 } 1323