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