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-1998 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 /*LINTLIBRARY*/ 30 31 /* 32 * devtab.c 33 * 34 * Contains functions that deal with the device table and are not for 35 * consumption by the general user population. 36 * 37 * Functions defined: 38 * _opendevtab() Opens the device table for commands 39 * _setdevtab() Rewinds the open device table 40 * _enddevtab() Closes the open device table 41 * _getdevtabent() Gets the next entry in the device table 42 * _freedevtabent() Frees memory allocated to a device-table entry 43 * _getdevrec() Gets a specific record from the device table 44 * _devtabpath() Get the pathname of the device table file 45 * _validalias() Is a value a valid alias? 46 */ 47 48 /* 49 * Header files 50 * 51 * <sys/sysmacros.h> System macro definitions 52 * <sys/types.h> System data types 53 * <sys/mkdev.h> Device Macros 54 * <unistd.h> System Symbolic Constants 55 * <stdio.h> Standard I/O definitions 56 * <string.h> String handling definitions 57 * <ctype.h> Character types and macros 58 * <errno.h> Error codes 59 * <sys/stat.h> File status information 60 * <devmgmt.h> Global Device Management definitions 61 * "devtab.h" Local Device Management definitions 62 */ 63 64 #include <sys/sysmacros.h> 65 #include <sys/types.h> 66 #ifndef SUNOS41 67 #include <sys/mkdev.h> 68 #endif 69 #include <unistd.h> 70 #include <stdio.h> 71 #include <string.h> 72 #include <ctype.h> 73 #include <errno.h> 74 #include <sys/stat.h> 75 #include <devmgmt.h> 76 #include "devtab.h" 77 #include <stdlib.h> 78 79 /* 80 * Static data definitions: 81 * dtabrecnum Record number of the current record (0 to n-1) 82 * leftoff Addr of char to begin next parse using 83 * getfld(), getattrval(), getquoted() 84 * recbufsz The size of the buffer used for reading records 85 * recbuf Addr of malloc() buffer for reading records 86 * xtndcnt Number of malloc()/realloc() calls on record buffer 87 */ 88 89 static int xtndcnt = 0; 90 static char *recbuf = NULL; 91 static int recbufsz = 0; 92 93 static char *leftoff = NULL; 94 static int dtabrecnum = 0; 95 96 /* 97 * int samedev(x, y) 98 * struct stat x, y 99 * 100 * Compares pertinent information in a stat() structure 101 * to see if the two structures describe the same device. 102 * If the file modes are the same and they have the same 103 * file system and i-node (i.e. they're links) or they 104 * are block or character devices and have the same major 105 * and minor device numbers (i.e. "mknod"s for the same 106 * device), it's the same device. 107 * 108 * Returns: int 109 * TRUE if the two structures describe the same device 110 * FALSE otherwise 111 */ 112 113 static int 114 samedev(struct stat64 x, struct stat64 y) 115 { 116 int same; 117 118 119 /* If the devices are of the same type ... */ 120 if ((x.st_mode & 0170000) == (y.st_mode & 0170000)) { 121 122 /* 123 * If they are described by the same inode on the same device, 124 * the two devices are the same. Otherwise, if the devices are 125 * character-special or block-special devices, try to match by 126 * device type and major and minor device numbers. 127 */ 128 129 if ((x.st_dev == y.st_dev) && (x.st_ino == y.st_ino)) same = TRUE; 130 else 131 if (((x.st_mode & 0170000) == 0020000) || 132 ((x.st_mode & 0170000) == 0060000)) { 133 if ((major(x.st_rdev) == major(y.st_rdev)) && 134 (minor(x.st_rdev) == minor(y.st_rdev))) same = TRUE; 135 else same = FALSE; 136 } else same = FALSE; 137 138 } else same = FALSE; 139 140 return (same); 141 } 142 143 /* 144 * void _setdevtab() 145 * 146 * This function rewinds the open device table so that the next 147 * _getdevtabent() returns the first record in the device table. 148 * 149 * Arguments: None 150 * 151 * Returns: Void 152 */ 153 154 void 155 _setdevtab(void) 156 { 157 /* If the device table file is open, rewind the file */ 158 if (oam_devtab != NULL) { 159 rewind(oam_devtab); 160 dtabrecnum = 0; 161 } 162 } 163 164 /* 165 * void _enddevtab() 166 * 167 * This function closes the open device table. It resets the 168 * open device table external variable to NULL. 169 * 170 * Arguments: None 171 * 172 * Returns: Void 173 */ 174 175 void 176 _enddevtab(void) 177 { 178 /* If the device table file is open, close it */ 179 if (oam_devtab != NULL) { 180 (void) fclose(oam_devtab); 181 oam_devtab = NULL; 182 dtabrecnum = 0; 183 } 184 } 185 186 /* 187 * char *getfld(ptr, delims) 188 * char *ptr 189 * char *delims 190 * 191 * Notes: 192 * - Can't use "strtok()" because of its use of static data. The caller 193 * may be using strtok() and we'll really mess them up. 194 * - The function returns NULL if it didn't find any token -- '\0' can't 195 * be a delimiter using this algorithm. 196 */ 197 198 static char * 199 getfld( 200 char *ptr, /* String to parse */ 201 char *delims) /* List of delimiters */ 202 { 203 int done; /* TRUE if we're finished */ 204 char *p, *q; /* Temp pointers */ 205 206 /* 207 * Figure out where to start. 208 * If given a pointer, use that. 209 * Otherwise, use where we left off. 210 */ 211 212 p = ptr ? ptr : leftoff; 213 214 215 /* 216 * If there's anything to parse, search the string for the first 217 * occurrence of any of the delimiters. If one is found, change it 218 * to '\0' and remember the place to start for next time. If not 219 * found, forget the restart address and prepare to return NULL. 220 * Don't terminate on "escaped" characters. 221 */ 222 223 if (p) { /* Anything to do ?? */ 224 q = p; /* Where to begin */ 225 done = FALSE; /* We're not done yet */ 226 while (*q && !done) { /* Any more chars */ 227 if (*q == '\\') { /* Escaped ? */ 228 if (*(++q)) q++; /* Skip escaped char */ 229 } else /* Not escaped */ 230 if (!strchr(delims, *q)) q++; /* Skip non-delim */ 231 else done = TRUE; /* Otherwise, done */ 232 } 233 if (*q) { /* Terminator found? */ 234 *q++ = '\0'; /* Null-terminate token */ 235 leftoff = q; /* Remember restart pt. */ 236 } else 237 leftoff = p = NULL; /* Nothin found or left */ 238 } 239 240 /* Finished */ 241 return (p); /* Return ptr to token */ 242 } 243 244 /* 245 * char *getquoted(ptr) 246 * char *ptr; 247 * 248 * This function extracts a quoted string from the string pointed 249 * to by <ptr>, or, if <ptr> is NULL, wherever we left off 250 * last time. 251 * 252 * Arguments: 253 * char *ptr Pointer to the character-string to parse, or 254 * (char *) NULL if we're to pick up where we 255 * [getquoted(), getfld(), and getattrval()] left off. 256 * 257 * Returns: char * 258 * The address of malloc()ed space that contains the possibly quoted 259 * string. 260 * 261 * Notes: 262 * - This code only works if it can assume that the last character in 263 * the string it's parsing is a '\n', something that is guarenteed 264 * by the getnextrec() function. 265 */ 266 267 static char * 268 getquoted(char *ptr) 269 { 270 /* Automatic data */ 271 char *rtn; /* Value to return */ 272 char *p, *q; /* Temps */ 273 274 /* Figure out where to start off */ 275 p = ptr ? ptr : leftoff; 276 277 /* If there's anything to parse and it's a quoted string ... */ 278 if ((p) && (*p == '"') && (p = getfld(p+1, "\""))) { 279 280 /* Copy string for the caller */ 281 if (rtn = malloc(strlen(p)+1)) { /* Malloc() space */ 282 q = rtn; /* Set up temp ptr */ 283 do { 284 if (*p == '\\') p++; /* Skip escape */ 285 *q++ = *p; /* Copy char */ 286 } while (*p++); /* While there's chars */ 287 } else leftoff = rtn = NULL; 288 } else leftoff = rtn = NULL; 289 290 /* Fini */ 291 return (rtn); 292 } 293 294 /* 295 * struct attrval *getattrval(ptr) 296 * char *ptr 297 * 298 * This function extracts the next attr=val pair from <ptr> or wherever 299 * getfld() left off... 300 * 301 * Arguments: 302 * char *ptr The string to parse, or (char *) NULL if we're to 303 * begin wherever we left off last time. 304 * 305 * Returns: struct attrval * 306 * The address of a malloc()ed structure containing the attribute and the 307 * value of the attr=val pair extracted. 308 */ 309 310 static struct attrval * 311 getattrval(char *ptr) 312 { 313 /* Automatic data */ 314 struct attrval *rtn; /* Ptr to struct to return */ 315 char *p, *q; /* Temp pointers */ 316 317 318 /* Use what's given to us or wherever we left off */ 319 p = ptr ? ptr : leftoff; 320 321 /* If there's anything to parse, extract the next attr=val pair */ 322 if (p) { 323 324 /* Eat white space */ 325 while (*p && isspace((unsigned char)*p)) p++; 326 327 /* Extract the attribute name, if any */ 328 if (*p && getfld(p, "=")) { 329 330 /* Allocate space for the structure we're building */ 331 if (rtn = malloc(sizeof (struct attrval))) { 332 333 /* Allocate space for the attribute name */ 334 if (rtn->attr = malloc(strlen(p)+1)) { 335 336 /* Copy the attribute name into alloc'd space */ 337 q = rtn->attr; /* Set up temp ptr */ 338 do { 339 if (*p == '\\') p++; /* Skip escape */ 340 *q++ = *p; /* Copy char */ 341 } while (*p++); /* While more */ 342 343 /* Extract the value */ 344 if (!(rtn->val = getquoted(NULL))) { 345 /* Error getting value, free resources */ 346 free(rtn->attr); 347 free(rtn); 348 leftoff = NULL; 349 rtn = NULL; 350 } 351 } else { 352 /* Error getting space for attribute, free resources */ 353 free(rtn); 354 leftoff = NULL; 355 rtn = NULL; 356 } 357 358 } else { 359 /* No space for attr struct */ 360 leftoff = NULL; 361 rtn = NULL; 362 } 363 364 } else { 365 /* No attribute name */ 366 leftoff = NULL; 367 rtn = NULL; 368 } 369 370 } else { 371 /* Nothing to parse */ 372 leftoff = NULL; 373 rtn = NULL; 374 } 375 376 /* Done */ 377 return (rtn); 378 } 379 380 /* 381 * char *getnextrec() 382 * 383 * This function gets the next record from the input stream "oam_devtab" 384 * and puts it in the device-table record buffer (whose address is in 385 * "recbuf"). If the buffer is not allocated or is too small to 386 * accommodate the record, the function allocates more space to the 387 * buffer. 388 * 389 * Arguments: None 390 * 391 * Returns: char * 392 * The address of the buffer containing the record. 393 * 394 * Static Data Referenced: 395 * recbuf Address of the buffer containing records read from the 396 * device table file 397 * recbufsz Current size of the record buffer 398 * xtndcnt Number of times the record buffer has been extended 399 * oam_devtab Device table stream, expected to be open for (at 400 * least) reading 401 * 402 * Notes: 403 * - The string returned in the buffer <buf> ALWAYS end in a '\n' (newline) 404 * character followed by a '\0' (null). 405 */ 406 407 static char * 408 getnextrec(void) 409 { 410 /* Automatic data */ 411 char *recp; /* Value to return */ 412 char *p; /* Temp pointer */ 413 int done; /* TRUE if we're finished */ 414 int reclen; /* Number of chars in record */ 415 416 417 /* If there's no buffer for records, try to get one */ 418 if (!recbuf) { 419 if (recbuf = malloc(DTAB_BUFSIZ)) { 420 recbufsz = DTAB_BUFSIZ; 421 xtndcnt = 0; 422 } else return (NULL); 423 } 424 425 426 /* Get the next record */ 427 recp = fgets(recbuf, recbufsz, oam_devtab); 428 done = FALSE; 429 430 /* While we've something to return and we're not finished ... */ 431 while (recp && !done) { 432 433 /* If our return string isn't a null-string ... */ 434 if ((reclen = (int)strlen(recp)) != 0) { 435 436 /* If we have a complete record, we're finished */ 437 if ((*(recp+reclen-1) == '\n') && 438 ((reclen == 1) || (*(recp+reclen-2) != '\\'))) done = TRUE; 439 else while (!done) { 440 441 /* 442 * Need to complete the record. A complete record is 443 * one which is terminated by an unescaped new-line 444 * character. 445 */ 446 447 /* If the buffer is full, expand it and continue reading */ 448 if (reclen == recbufsz-1) { 449 450 /* Have we reached our maximum extension count? */ 451 if (xtndcnt < XTND_MAXCNT) { 452 453 /* Expand the record buffer */ 454 if (p = realloc(recbuf, 455 (size_t)recbufsz+DTAB_BUFINC)) { 456 457 /* Update buffer information */ 458 xtndcnt++; 459 recbuf = p; 460 recbufsz += DTAB_BUFINC; 461 462 } else { 463 464 /* Expansion failed */ 465 recp = NULL; 466 done = TRUE; 467 } 468 469 } else { 470 471 /* Maximum extend count exceeded. Insane table */ 472 recp = NULL; 473 done = TRUE; 474 } 475 476 } 477 478 /* Complete the record */ 479 if (!done) { 480 481 /* Read stuff into the expanded space */ 482 if (fgets(recbuf+reclen, recbufsz-reclen, oam_devtab)) { 483 reclen = (int)strlen(recbuf); 484 recp = recbuf; 485 if ((*(recp+reclen-1) == '\n') && 486 ((reclen == 1) || (*(recp+reclen-2) != '\\'))) 487 done = TRUE; 488 } else { 489 /* Read failed, corrupt record? */ 490 recp = NULL; 491 done = TRUE; 492 } 493 } 494 495 } /* End incomplete record handling */ 496 497 } else { 498 499 /* Read a null string? (corrupt table) */ 500 recp = NULL; 501 done = TRUE; 502 } 503 504 } /* while (recp && !done) */ 505 506 /* Return what we've got (if anything) */ 507 return (recp); 508 } 509 510 /* 511 * char *_devtabpath() 512 * 513 * Get the pathname of the device table 514 * 515 * Arguments: None 516 * 517 * Returns: char * 518 * Returns the pathname to the device table of NULL if 519 * there was a problem getting the memory needed to contain the 520 * pathname. 521 * 522 * Algorithm: 523 * 1. If OAM_DEVTAB is defined in the environment and is not 524 * defined as "", it returns the value of that environment 525 * variable. 526 * 2. Otherwise, use the value of the environment variable DTAB_PATH. 527 */ 528 529 530 char * 531 _devtabpath(void) 532 { 533 534 /* Automatic data */ 535 #ifdef DEBUG 536 char *path; /* Ptr to path in environment */ 537 #endif 538 char *rtnval; /* Ptr to value to return */ 539 540 541 /* 542 * If compiled with -DDEBUG=1, 543 * look for the pathname in the environment 544 */ 545 546 #ifdef DEBUG 547 if (((path = getenv(OAM_DEVTAB)) != NULL) && (*path)) { 548 if (rtnval = malloc(strlen(path)+1)) 549 (void) strcpy(rtnval, path); 550 } else { 551 #endif 552 /* 553 * Use the standard device table. 554 */ 555 556 if (rtnval = malloc(strlen(DTAB_PATH)+1)) 557 (void) strcpy(rtnval, DTAB_PATH); 558 559 #ifdef DEBUG 560 } 561 #endif 562 563 /* Finished */ 564 return (rtnval); 565 } 566 567 /* 568 * int _opendevtab(mode) 569 * char *mode 570 * 571 * The _opendevtab() function opens a device table for a command. 572 * 573 * Arguments: 574 * mode The open mode to use to open the file. (i.e. "r" for 575 * reading, "w" for writing. See FOPEN(BA_OS) in SVID.) 576 * 577 * Returns: int 578 * TRUE if it successfully opens the device table file, FALSE otherwise 579 */ 580 581 int 582 _opendevtab(char *mode) 583 { 584 /* 585 * Automatic data 586 */ 587 588 char *devtabname; /* Ptr to the device table name */ 589 int rtnval; /* Value to return */ 590 591 592 rtnval = TRUE; 593 if (devtabname = _devtabpath()) { 594 if (oam_devtab) (void) fclose(oam_devtab); 595 if (oam_devtab = fopen(devtabname, mode)) 596 dtabrecnum = 0; /* :-) */ 597 else rtnval = FALSE; /* :-( */ 598 } else rtnval = FALSE; /* :-( */ 599 return (rtnval); 600 } 601 602 /* 603 * int _validalias(alias) 604 * char *alias 605 * 606 * Determine if <alias> is a valid alias. Returns TRUE if it is 607 * a valid alias, FALSE otherwise. 608 * 609 * Arguments: 610 * alias Value to check out 611 * 612 * Returns: int 613 * TRUE if <alias> is a valid alias, FALSE otherwise. 614 */ 615 616 int 617 _validalias(char *alias) /* Alias to validate */ 618 { 619 /* Automatic data */ 620 char *p; /* Temp pointer */ 621 size_t len; /* Length of <alias> */ 622 int rtn; /* Value to return */ 623 624 625 /* Assume the worst */ 626 rtn = FALSE; 627 628 /* 629 * A valid alias contains 0 < i <= 14 characters. The first 630 * must be alphanumeric or "@$_." and the rest must be alphanumeric 631 * or "@#$_+-." 632 */ 633 634 /* Check length */ 635 if ((alias != NULL) && ((len = strlen(alias)) > 0) && (len <= 14)) { 636 637 /* Check the first character */ 638 p = alias; 639 if (isalnum((unsigned char)*p) || strchr("@$_.", *p)) { 640 641 /* Check the rest of the characters */ 642 for (p++; *p && (isalnum((unsigned char)*p) || 643 strchr("@#$_-+.", *p)); p++) 644 ; 645 if (!(*p)) rtn = TRUE; 646 } 647 } 648 649 /* Return indicator... */ 650 return (rtn); 651 652 } /* int _validalias() */ 653 654 /* 655 * struct devtabent *_getdevtabent() 656 * 657 * This function returns the next entry in the device table. 658 * If no device table is open, it opens the standard device table 659 * and returns the first record in the table. 660 * 661 * Arguments: None. 662 * 663 * Returns: struct devtabent * 664 * Pointer to the next record in the device table, or 665 * (struct devtabent *) NULL if it was unable to open the file or there 666 * are no more records to read. "errno" reflects the situation. If 667 * errno is not changed and the function returns NULL, there are no more 668 * records to read. If errno is set, it indicates the error. 669 * 670 * Notes: 671 * - The caller should set "errno" to 0 before calling this function. 672 */ 673 674 struct devtabent * 675 _getdevtabent(void) 676 { 677 /* Automatic data */ 678 struct devtabent *ent; /* Ptr to dev table entry structure */ 679 struct attrval *attr; /* Ptr to struct for attr/val pair */ 680 struct attrval *t; /* Tmp ptr to attr/val struct */ 681 char *record; /* Ptr to the record just read */ 682 char *p, *q; /* Tmp char ptrs */ 683 int done; /* TRUE if we've built an entry */ 684 685 686 /* Open the device table if it's not already open */ 687 if (oam_devtab == NULL) { 688 if (!_opendevtab("r")) 689 return (NULL); 690 } 691 692 /* Get space for the structure we're returning */ 693 if (!(ent = malloc(sizeof (struct devtabent)))) { 694 return (NULL); 695 } 696 697 done = FALSE; 698 while (!done && (record = getnextrec())) { 699 700 /* Save record number in structure */ 701 ent->entryno = dtabrecnum++; 702 703 /* Comment record? If so, just save the value and we're through */ 704 if (strchr("#\n", *record) || isspace((unsigned char)*record)) { 705 ent->comment = TRUE; 706 done = TRUE; 707 if (ent->attrstr = malloc(strlen(record)+1)) { 708 q = ent->attrstr; 709 p = record; 710 do { 711 if (*p == '\\') p++; 712 *q++ = *p; 713 } while (*p++); 714 } else { 715 free(ent); 716 ent = NULL; 717 } 718 } 719 720 else { 721 722 /* Record is a data record. Parse it. */ 723 ent->comment = FALSE; 724 ent->attrstr = NULL; /* For now */ 725 726 /* Extract the device alias */ 727 if (p = getfld(record, ":")) { 728 if (*p) { 729 if (ent->alias = malloc(strlen(p)+1)) { 730 q = ent->alias; 731 do { 732 if (*p == '\\') p++; 733 *q++ = *p; 734 } while (*p++); 735 } 736 } else ent->alias = NULL; 737 738 /* Extract the character-device name */ 739 if ((p = getfld(NULL, ":")) == NULL) { 740 if (ent->alias) 741 free(ent->alias); 742 } else { 743 if (*p) { 744 if (ent->cdevice = malloc(strlen(p)+1)) { 745 q = ent->cdevice; 746 do { 747 if (*p == '\\') p++; 748 *q++ = *p; 749 } while (*p++); 750 } 751 } else ent->cdevice = NULL; 752 753 /* Extract the block-device name */ 754 if (!(p = getfld(NULL, ":"))) { 755 if (ent->alias) free(ent->alias); 756 if (ent->cdevice) free(ent->cdevice); 757 } else { 758 if (*p) { 759 if (ent->bdevice = malloc(strlen(p)+1)) { 760 q = ent->bdevice; 761 do { 762 if (*p == '\\') p++; 763 *q++ = *p; 764 } while (*p++); 765 } 766 } else 767 ent->bdevice = NULL; 768 769 /* Extract the pathname */ 770 if ((p = getfld(NULL, ":\n")) == NULL) { 771 if (ent->alias) free(ent->alias); 772 if (ent->cdevice) free(ent->cdevice); 773 if (ent->bdevice) free(ent->bdevice); 774 } else { 775 if (*p) { 776 if (ent->pathname = malloc(strlen(p)+1)) { 777 q = ent->pathname; 778 do { 779 if (*p == '\\') p++; 780 *q++ = *p; 781 } while (*p++); 782 } 783 } else 784 ent->pathname = NULL; 785 786 /* Found a valid record */ 787 done = TRUE; 788 789 /* 790 * Extract attributes, build a linked list of 791 * 'em (may be none) 792 */ 793 if (attr = getattrval(NULL)) { 794 ent->attrlist = attr; 795 t = attr; 796 while (attr = getattrval(NULL)) { 797 t->next = attr; 798 t = attr; 799 } 800 t->next = NULL; 801 } else 802 ent->attrlist = NULL; 803 804 } /* pathname extracted */ 805 } /* bdevice extracted */ 806 } /* cdevice extracted */ 807 } /* alias extracted */ 808 } 809 } /* !done && record read */ 810 811 /* If no entry was read, free space allocated to the structure */ 812 if (!done) { 813 free(ent); 814 ent = NULL; 815 } 816 817 return (ent); 818 } 819 820 /* 821 * void _freedevtabent(devtabent) 822 * struct devtabent *devtabent; 823 * 824 * This function frees space allocated to a device table entry. 825 * 826 * Arguments: 827 * struct devtabent *devtabent The structure whose space is to be 828 * freed. 829 * 830 * Returns: void 831 */ 832 833 void 834 _freedevtabent(struct devtabent *ent) 835 { 836 /* 837 * Automatic data 838 */ 839 840 struct attrval *p; /* Structure being freed */ 841 struct attrval *q; /* Next structure to free */ 842 843 if (!ent->comment) { 844 845 /* 846 * Free the attribute list. For each item in the attribute 847 * list, 848 * 1. Free the attribute name (always defined), 849 * 2. Free the value (if any -- it's not defined if we're 850 * changing an existing attribute), 851 * 3. Free the space allocated to the structure. 852 */ 853 854 q = ent->attrlist; 855 if (q) 856 do { 857 p = q; 858 q = p->next; 859 free(p->attr); 860 if (p->val) free(p->val); 861 free(p); 862 } while (q); 863 864 /* Free the standard fields (alias, cdevice, bdevice, pathname) */ 865 if (ent->alias) free(ent->alias); 866 if (ent->cdevice) free(ent->cdevice); 867 if (ent->bdevice) free(ent->bdevice); 868 if (ent->pathname) free(ent->pathname); 869 } 870 871 /* Free the attribute string */ 872 if (ent->attrstr) free(ent->attrstr); 873 874 /* Free the space allocated to the structure */ 875 free(ent); 876 } 877 878 /* 879 * struct devtabent *_getdevrec(device) 880 * char *device 881 * 882 * Thie _getdevrec() function returns a pointer to a structure that 883 * contains the information in the device-table entry that describes 884 * the device <device>. 885 * 886 * The device <device> can be a device alias, a pathname contained in 887 * the entry as the "cdevice", "bdevice", or "pathname" attribute, 888 * or a pathname to a device described using the "cdevice", "bdevice", 889 * or "pathname" attribute (depending on whether the pathname references 890 * a character-special file, block-special file, or something else, 891 * respectively. 892 * 893 * Arguments: 894 * char *device A character-string describing the device whose record 895 * is to be retrieved from the device table. 896 * 897 * Returns: struct devtabent * 898 * A pointer to a structure describing the device. 899 * 900 * Notes: 901 * - Someday, add a cache so that repeated requests for the same record 902 * don't require going to the filesystem. (Maybe -- this might belong 903 * in devattr()...) 904 */ 905 906 struct devtabent * 907 _getdevrec(char *device) /* The device to search for */ 908 { 909 /* 910 * Automatic data 911 */ 912 913 struct stat64 devstatbuf; /* Stat struct, <device> */ 914 struct stat64 tblstatbuf; /* Stat struct, tbl entry */ 915 struct devtabent *devrec; /* Pointer to current record */ 916 int found; /* TRUE if record found */ 917 int olderrno; /* Old value of errno */ 918 919 920 /* 921 * Search the device table looking for the requested device 922 */ 923 924 _setdevtab(); 925 olderrno = errno; 926 found = FALSE; 927 if ((device != NULL) && !_validalias(device)) { 928 while (!found && (devrec = _getdevtabent())) { 929 if (!devrec->comment) { 930 if (devrec->cdevice) 931 if (strcmp(device, devrec->cdevice) == 0) found = TRUE; 932 if (devrec->bdevice) 933 if (strcmp(device, devrec->bdevice) == 0) found = TRUE; 934 if (devrec->pathname) 935 if (strcmp(device, devrec->pathname) == 0) found = TRUE; 936 } else _freedevtabent(devrec); 937 } 938 939 /* 940 * If the device <device> wasn't named explicitly in the device 941 * table, compare it against like entries by comparing file- 942 * system, major device number, and minor device number 943 */ 944 945 if (!found) { 946 _setdevtab(); 947 948 /* Status the file <device>. If fails, invalid device */ 949 if (stat64(device, &devstatbuf) != 0) errno = ENODEV; 950 else { 951 952 /* 953 * If <device> is a block-special device. See if it is 954 * in the table by matching its file-system indicator 955 * and major/minor device numbers against the 956 * file-system and major/minor device numbers of the 957 * "bdevice" entries. 958 */ 959 960 if ((devstatbuf.st_mode & 0170000) == 0020000) { 961 while (!found && (devrec = _getdevtabent())) { 962 if (!devrec->comment && 963 (devrec->cdevice != NULL)) 964 if (stat64(devrec->cdevice, &tblstatbuf) == 0) { 965 if (samedev(tblstatbuf, devstatbuf)) 966 found = TRUE; 967 } else { 968 /* Ignore stat() errs */ 969 errno = olderrno; 970 } 971 if (!found) _freedevtabent(devrec); 972 } 973 } 974 975 /* 976 * If <device> is a block-special device. See if it is 977 * in the table by matching its file-system indicator 978 * and major/minor device numbers against the 979 * file-system and major/minor device numbers of the 980 * "bdevice" entries. 981 */ 982 983 else if ((devstatbuf.st_mode & 0170000) == 0060000) { 984 while (!found && (devrec = _getdevtabent())) { 985 if (!devrec->comment && 986 (devrec->bdevice != NULL)) 987 if (stat64(devrec->bdevice, &tblstatbuf) == 0) { 988 if (samedev(tblstatbuf, devstatbuf)) 989 found = TRUE; 990 } else { 991 /* Ignore stat() errs */ 992 errno = olderrno; 993 } 994 if (!found) _freedevtabent(devrec); 995 } 996 } 997 998 /* 999 * If <device> is neither a block-special or character- 1000 * special device. See if it is in the table by 1001 * matching its file-system indicator and major/minor 1002 * device numbers against the file-system and 1003 * major/minor device numbers of the "pathname" entries. 1004 */ 1005 1006 else { 1007 while (!found && (devrec = _getdevtabent())) { 1008 if (!devrec->comment && 1009 (devrec->pathname != NULL)) 1010 if (stat64(devrec->pathname, 1011 &tblstatbuf) == 0) { 1012 if (samedev(tblstatbuf, devstatbuf)) 1013 found = TRUE; 1014 } else { 1015 /* Ignore stat() errs */ 1016 errno = olderrno; 1017 } 1018 if (!found) _freedevtabent(devrec); 1019 } 1020 } 1021 1022 if (!found) { 1023 devrec = NULL; 1024 errno = ENODEV; 1025 } 1026 1027 } /* End case where stat() on the <device> succeeded */ 1028 1029 } /* End case handling pathname not explicitly in device table */ 1030 1031 } /* End case handling <device> as a fully-qualified pathname */ 1032 1033 1034 /* 1035 * Otherwise the device <device> is an alias. 1036 * Search the table for a record that has as the "alias" attribute 1037 * the value <device>. 1038 */ 1039 1040 else { 1041 while (!found && (devrec = _getdevtabent())) { 1042 if (!devrec->comment && (device != NULL) && 1043 strcmp(device, devrec->alias) == 0) 1044 found = TRUE; 1045 else _freedevtabent(devrec); 1046 } 1047 if (!found) { 1048 devrec = NULL; 1049 errno = ENODEV; 1050 } 1051 } 1052 1053 /* Fini */ 1054 return (devrec); 1055 } 1056