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