diff options
Diffstat (limited to 'usr/src/lib/libadm/common/devtab.c')
-rw-r--r-- | usr/src/lib/libadm/common/devtab.c | 1057 |
1 files changed, 1057 insertions, 0 deletions
diff --git a/usr/src/lib/libadm/common/devtab.c b/usr/src/lib/libadm/common/devtab.c new file mode 100644 index 0000000000..ae1c812e5d --- /dev/null +++ b/usr/src/lib/libadm/common/devtab.c @@ -0,0 +1,1057 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. + * All Rights reserved. + */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + + +#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */ +/*LINTLIBRARY*/ + +/* + * devtab.c + * + * Contains functions that deal with the device table and are not for + * consumption by the general user population. + * + * Functions defined: + * _opendevtab() Opens the device table for commands + * _setdevtab() Rewinds the open device table + * _enddevtab() Closes the open device table + * _getdevtabent() Gets the next entry in the device table + * _freedevtabent() Frees memory allocated to a device-table entry + * _getdevrec() Gets a specific record from the device table + * _devtabpath() Get the pathname of the device table file + * _validalias() Is a value a valid alias? + */ + +/* + * Header files + * + * <sys/sysmacros.h> System macro definitions + * <sys/types.h> System data types + * <sys/mkdev.h> Device Macros + * <unistd.h> System Symbolic Constants + * <stdio.h> Standard I/O definitions + * <string.h> String handling definitions + * <ctype.h> Character types and macros + * <errno.h> Error codes + * <sys/stat.h> File status information + * <devmgmt.h> Global Device Management definitions + * "devtab.h" Local Device Management definitions + */ + +#include <sys/sysmacros.h> +#include <sys/types.h> +#ifndef SUNOS41 +#include <sys/mkdev.h> +#endif +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <sys/stat.h> +#include <devmgmt.h> +#include "devtab.h" +#include <stdlib.h> + +/* + * Static data definitions: + * dtabrecnum Record number of the current record (0 to n-1) + * leftoff Addr of char to begin next parse using + * getfld(), getattrval(), getquoted() + * recbufsz The size of the buffer used for reading records + * recbuf Addr of malloc() buffer for reading records + * xtndcnt Number of malloc()/realloc() calls on record buffer + */ + +static int xtndcnt = 0; +static char *recbuf = NULL; +static int recbufsz = 0; + +static char *leftoff = NULL; +static int dtabrecnum = 0; + +/* + * int samedev(x, y) + * struct stat x, y + * + * Compares pertinent information in a stat() structure + * to see if the two structures describe the same device. + * If the file modes are the same and they have the same + * file system and i-node (i.e. they're links) or they + * are block or character devices and have the same major + * and minor device numbers (i.e. "mknod"s for the same + * device), it's the same device. + * + * Returns: int + * TRUE if the two structures describe the same device + * FALSE otherwise + */ + +static int +samedev(struct stat64 x, struct stat64 y) +{ + int same; + + + /* If the devices are of the same type ... */ + if ((x.st_mode & 0170000) == (y.st_mode & 0170000)) { + + /* + * If they are described by the same inode on the same device, + * the two devices are the same. Otherwise, if the devices are + * character-special or block-special devices, try to match by + * device type and major and minor device numbers. + */ + + if ((x.st_dev == y.st_dev) && (x.st_ino == y.st_ino)) same = TRUE; + else + if (((x.st_mode & 0170000) == 0020000) || + ((x.st_mode & 0170000) == 0060000)) { + if ((major(x.st_rdev) == major(y.st_rdev)) && + (minor(x.st_rdev) == minor(y.st_rdev))) same = TRUE; + else same = FALSE; + } else same = FALSE; + + } else same = FALSE; + + return (same); +} + +/* + * void _setdevtab() + * + * This function rewinds the open device table so that the next + * _getdevtabent() returns the first record in the device table. + * + * Arguments: None + * + * Returns: Void + */ + +void +_setdevtab(void) +{ + /* If the device table file is open, rewind the file */ + if (oam_devtab != NULL) { + rewind(oam_devtab); + dtabrecnum = 0; + } +} + +/* + * void _enddevtab() + * + * This function closes the open device table. It resets the + * open device table external variable to NULL. + * + * Arguments: None + * + * Returns: Void + */ + +void +_enddevtab(void) +{ + /* If the device table file is open, close it */ + if (oam_devtab != NULL) { + (void) fclose(oam_devtab); + oam_devtab = NULL; + dtabrecnum = 0; + } +} + +/* + * char *getfld(ptr, delims) + * char *ptr + * char *delims + * + * Notes: + * - Can't use "strtok()" because of its use of static data. The caller + * may be using strtok() and we'll really mess them up. + * - The function returns NULL if it didn't find any token -- '\0' can't + * be a delimiter using this algorithm. + */ + +static char * +getfld( + char *ptr, /* String to parse */ + char *delims) /* List of delimiters */ +{ + int done; /* TRUE if we're finished */ + char *p, *q; /* Temp pointers */ + + /* + * Figure out where to start. + * If given a pointer, use that. + * Otherwise, use where we left off. + */ + + p = ptr ? ptr : leftoff; + + + /* + * If there's anything to parse, search the string for the first + * occurrence of any of the delimiters. If one is found, change it + * to '\0' and remember the place to start for next time. If not + * found, forget the restart address and prepare to return NULL. + * Don't terminate on "escaped" characters. + */ + + if (p) { /* Anything to do ?? */ + q = p; /* Where to begin */ + done = FALSE; /* We're not done yet */ + while (*q && !done) { /* Any more chars */ + if (*q == '\\') { /* Escaped ? */ + if (*(++q)) q++; /* Skip escaped char */ + } else /* Not escaped */ + if (!strchr(delims, *q)) q++; /* Skip non-delim */ + else done = TRUE; /* Otherwise, done */ + } + if (*q) { /* Terminator found? */ + *q++ = '\0'; /* Null-terminate token */ + leftoff = q; /* Remember restart pt. */ + } else + leftoff = p = NULL; /* Nothin found or left */ + } + + /* Finished */ + return (p); /* Return ptr to token */ +} + +/* + * char *getquoted(ptr) + * char *ptr; + * + * This function extracts a quoted string from the string pointed + * to by <ptr>, or, if <ptr> is NULL, wherever we left off + * last time. + * + * Arguments: + * char *ptr Pointer to the character-string to parse, or + * (char *) NULL if we're to pick up where we + * [getquoted(), getfld(), and getattrval()] left off. + * + * Returns: char * + * The address of malloc()ed space that contains the possibly quoted + * string. + * + * Notes: + * - This code only works if it can assume that the last character in + * the string it's parsing is a '\n', something that is guarenteed + * by the getnextrec() function. + */ + +static char * +getquoted(char *ptr) +{ + /* Automatic data */ + char *rtn; /* Value to return */ + char *p, *q; /* Temps */ + + /* Figure out where to start off */ + p = ptr ? ptr : leftoff; + + /* If there's anything to parse and it's a quoted string ... */ + if ((p) && (*p == '"') && (p = getfld(p+1, "\""))) { + + /* Copy string for the caller */ + if (rtn = malloc(strlen(p)+1)) { /* Malloc() space */ + q = rtn; /* Set up temp ptr */ + do { + if (*p == '\\') p++; /* Skip escape */ + *q++ = *p; /* Copy char */ + } while (*p++); /* While there's chars */ + } else leftoff = rtn = NULL; + } else leftoff = rtn = NULL; + + /* Fini */ + return (rtn); +} + +/* + * struct attrval *getattrval(ptr) + * char *ptr + * + * This function extracts the next attr=val pair from <ptr> or wherever + * getfld() left off... + * + * Arguments: + * char *ptr The string to parse, or (char *) NULL if we're to + * begin wherever we left off last time. + * + * Returns: struct attrval * + * The address of a malloc()ed structure containing the attribute and the + * value of the attr=val pair extracted. + */ + +static struct attrval * +getattrval(char *ptr) +{ + /* Automatic data */ + struct attrval *rtn; /* Ptr to struct to return */ + char *p, *q; /* Temp pointers */ + + + /* Use what's given to us or wherever we left off */ + p = ptr ? ptr : leftoff; + + /* If there's anything to parse, extract the next attr=val pair */ + if (p) { + + /* Eat white space */ + while (*p && isspace((unsigned char)*p)) p++; + + /* Extract the attribute name, if any */ + if (*p && getfld(p, "=")) { + + /* Allocate space for the structure we're building */ + if (rtn = malloc(sizeof (struct attrval))) { + + /* Allocate space for the attribute name */ + if (rtn->attr = malloc(strlen(p)+1)) { + + /* Copy the attribute name into alloc'd space */ + q = rtn->attr; /* Set up temp ptr */ + do { + if (*p == '\\') p++; /* Skip escape */ + *q++ = *p; /* Copy char */ + } while (*p++); /* While more */ + + /* Extract the value */ + if (!(rtn->val = getquoted(NULL))) { + /* Error getting value, free resources */ + free(rtn->attr); + free(rtn); + leftoff = NULL; + rtn = NULL; + } + } else { + /* Error getting space for attribute, free resources */ + free(rtn); + leftoff = NULL; + rtn = NULL; + } + + } else { + /* No space for attr struct */ + leftoff = NULL; + rtn = NULL; + } + + } else { + /* No attribute name */ + leftoff = NULL; + rtn = NULL; + } + + } else { + /* Nothing to parse */ + leftoff = NULL; + rtn = NULL; + } + + /* Done */ + return (rtn); +} + +/* + * char *getnextrec() + * + * This function gets the next record from the input stream "oam_devtab" + * and puts it in the device-table record buffer (whose address is in + * "recbuf"). If the buffer is not allocated or is too small to + * accommodate the record, the function allocates more space to the + * buffer. + * + * Arguments: None + * + * Returns: char * + * The address of the buffer containing the record. + * + * Static Data Referenced: + * recbuf Address of the buffer containing records read from the + * device table file + * recbufsz Current size of the record buffer + * xtndcnt Number of times the record buffer has been extended + * oam_devtab Device table stream, expected to be open for (at + * least) reading + * + * Notes: + * - The string returned in the buffer <buf> ALWAYS end in a '\n' (newline) + * character followed by a '\0' (null). + */ + +static char * +getnextrec(void) +{ + /* Automatic data */ + char *recp; /* Value to return */ + char *p; /* Temp pointer */ + int done; /* TRUE if we're finished */ + int reclen; /* Number of chars in record */ + + + /* If there's no buffer for records, try to get one */ + if (!recbuf) { + if (recbuf = malloc(DTAB_BUFSIZ)) { + recbufsz = DTAB_BUFSIZ; + xtndcnt = 0; + } else return (NULL); + } + + + /* Get the next record */ + recp = fgets(recbuf, recbufsz, oam_devtab); + done = FALSE; + + /* While we've something to return and we're not finished ... */ + while (recp && !done) { + + /* If our return string isn't a null-string ... */ + if ((reclen = (int)strlen(recp)) != 0) { + + /* If we have a complete record, we're finished */ + if ((*(recp+reclen-1) == '\n') && + ((reclen == 1) || (*(recp+reclen-2) != '\\'))) done = TRUE; + else while (!done) { + + /* + * Need to complete the record. A complete record is + * one which is terminated by an unescaped new-line + * character. + */ + + /* If the buffer is full, expand it and continue reading */ + if (reclen == recbufsz-1) { + + /* Have we reached our maximum extension count? */ + if (xtndcnt < XTND_MAXCNT) { + + /* Expand the record buffer */ + if (p = realloc(recbuf, + (size_t)recbufsz+DTAB_BUFINC)) { + + /* Update buffer information */ + xtndcnt++; + recbuf = p; + recbufsz += DTAB_BUFINC; + + } else { + + /* Expansion failed */ + recp = NULL; + done = TRUE; + } + + } else { + + /* Maximum extend count exceeded. Insane table */ + recp = NULL; + done = TRUE; + } + + } + + /* Complete the record */ + if (!done) { + + /* Read stuff into the expanded space */ + if (fgets(recbuf+reclen, recbufsz-reclen, oam_devtab)) { + reclen = (int)strlen(recbuf); + recp = recbuf; + if ((*(recp+reclen-1) == '\n') && + ((reclen == 1) || (*(recp+reclen-2) != '\\'))) + done = TRUE; + } else { + /* Read failed, corrupt record? */ + recp = NULL; + done = TRUE; + } + } + + } /* End incomplete record handling */ + + } else { + + /* Read a null string? (corrupt table) */ + recp = NULL; + done = TRUE; + } + + } /* while (recp && !done) */ + + /* Return what we've got (if anything) */ + return (recp); +} + +/* + * char *_devtabpath() + * + * Get the pathname of the device table + * + * Arguments: None + * + * Returns: char * + * Returns the pathname to the device table of NULL if + * there was a problem getting the memory needed to contain the + * pathname. + * + * Algorithm: + * 1. If OAM_DEVTAB is defined in the environment and is not + * defined as "", it returns the value of that environment + * variable. + * 2. Otherwise, use the value of the environment variable DTAB_PATH. + */ + + +char * +_devtabpath(void) +{ + + /* Automatic data */ +#ifdef DEBUG + char *path; /* Ptr to path in environment */ +#endif + char *rtnval; /* Ptr to value to return */ + + + /* + * If compiled with -DDEBUG=1, + * look for the pathname in the environment + */ + +#ifdef DEBUG + if (((path = getenv(OAM_DEVTAB)) != NULL) && (*path)) { + if (rtnval = malloc(strlen(path)+1)) + (void) strcpy(rtnval, path); + } else { +#endif + /* + * Use the standard device table. + */ + + if (rtnval = malloc(strlen(DTAB_PATH)+1)) + (void) strcpy(rtnval, DTAB_PATH); + +#ifdef DEBUG + } +#endif + + /* Finished */ + return (rtnval); +} + +/* + * int _opendevtab(mode) + * char *mode + * + * The _opendevtab() function opens a device table for a command. + * + * Arguments: + * mode The open mode to use to open the file. (i.e. "r" for + * reading, "w" for writing. See FOPEN(BA_OS) in SVID.) + * + * Returns: int + * TRUE if it successfully opens the device table file, FALSE otherwise + */ + +int +_opendevtab(char *mode) +{ + /* + * Automatic data + */ + + char *devtabname; /* Ptr to the device table name */ + int rtnval; /* Value to return */ + + + rtnval = TRUE; + if (devtabname = _devtabpath()) { + if (oam_devtab) (void) fclose(oam_devtab); + if (oam_devtab = fopen(devtabname, mode)) + dtabrecnum = 0; /* :-) */ + else rtnval = FALSE; /* :-( */ + } else rtnval = FALSE; /* :-( */ + return (rtnval); +} + +/* + * int _validalias(alias) + * char *alias + * + * Determine if <alias> is a valid alias. Returns TRUE if it is + * a valid alias, FALSE otherwise. + * + * Arguments: + * alias Value to check out + * + * Returns: int + * TRUE if <alias> is a valid alias, FALSE otherwise. + */ + +int +_validalias(char *alias) /* Alias to validate */ +{ + /* Automatic data */ + char *p; /* Temp pointer */ + size_t len; /* Length of <alias> */ + int rtn; /* Value to return */ + + + /* Assume the worst */ + rtn = FALSE; + + /* + * A valid alias contains 0 < i <= 14 characters. The first + * must be alphanumeric or "@$_." and the rest must be alphanumeric + * or "@#$_+-." + */ + + /* Check length */ + if ((alias != NULL) && ((len = strlen(alias)) > 0) && (len <= 14)) { + + /* Check the first character */ + p = alias; + if (isalnum((unsigned char)*p) || strchr("@$_.", *p)) { + + /* Check the rest of the characters */ + for (p++; *p && (isalnum((unsigned char)*p) || + strchr("@#$_-+.", *p)); p++) + ; + if (!(*p)) rtn = TRUE; + } + } + + /* Return indicator... */ + return (rtn); + +} /* int _validalias() */ + +/* + * struct devtabent *_getdevtabent() + * + * This function returns the next entry in the device table. + * If no device table is open, it opens the standard device table + * and returns the first record in the table. + * + * Arguments: None. + * + * Returns: struct devtabent * + * Pointer to the next record in the device table, or + * (struct devtabent *) NULL if it was unable to open the file or there + * are no more records to read. "errno" reflects the situation. If + * errno is not changed and the function returns NULL, there are no more + * records to read. If errno is set, it indicates the error. + * + * Notes: + * - The caller should set "errno" to 0 before calling this function. + */ + +struct devtabent * +_getdevtabent(void) +{ + /* Automatic data */ + struct devtabent *ent; /* Ptr to dev table entry structure */ + struct attrval *attr; /* Ptr to struct for attr/val pair */ + struct attrval *t; /* Tmp ptr to attr/val struct */ + char *record; /* Ptr to the record just read */ + char *p, *q; /* Tmp char ptrs */ + int done; /* TRUE if we've built an entry */ + + + /* Open the device table if it's not already open */ + if (oam_devtab == NULL) { + if (!_opendevtab("r")) + return (NULL); + } + + /* Get space for the structure we're returning */ + if (!(ent = malloc(sizeof (struct devtabent)))) { + return (NULL); + } + + done = FALSE; + while (!done && (record = getnextrec())) { + + /* Save record number in structure */ + ent->entryno = dtabrecnum++; + + /* Comment record? If so, just save the value and we're through */ + if (strchr("#\n", *record) || isspace((unsigned char)*record)) { + ent->comment = TRUE; + done = TRUE; + if (ent->attrstr = malloc(strlen(record)+1)) { + q = ent->attrstr; + p = record; + do { + if (*p == '\\') p++; + *q++ = *p; + } while (*p++); + } else { + free(ent); + ent = NULL; + } + } + + else { + + /* Record is a data record. Parse it. */ + ent->comment = FALSE; + ent->attrstr = NULL; /* For now */ + + /* Extract the device alias */ + if (p = getfld(record, ":")) { + if (*p) { + if (ent->alias = malloc(strlen(p)+1)) { + q = ent->alias; + do { + if (*p == '\\') p++; + *q++ = *p; + } while (*p++); + } + } else ent->alias = NULL; + + /* Extract the character-device name */ + if ((p = getfld(NULL, ":")) == NULL) { + if (ent->alias) + free(ent->alias); + } else { + if (*p) { + if (ent->cdevice = malloc(strlen(p)+1)) { + q = ent->cdevice; + do { + if (*p == '\\') p++; + *q++ = *p; + } while (*p++); + } + } else ent->cdevice = NULL; + + /* Extract the block-device name */ + if (!(p = getfld(NULL, ":"))) { + if (ent->alias) free(ent->alias); + if (ent->cdevice) free(ent->cdevice); + } else { + if (*p) { + if (ent->bdevice = malloc(strlen(p)+1)) { + q = ent->bdevice; + do { + if (*p == '\\') p++; + *q++ = *p; + } while (*p++); + } + } else + ent->bdevice = NULL; + + /* Extract the pathname */ + if ((p = getfld(NULL, ":\n")) == NULL) { + if (ent->alias) free(ent->alias); + if (ent->cdevice) free(ent->cdevice); + if (ent->bdevice) free(ent->bdevice); + } else { + if (*p) { + if (ent->pathname = malloc(strlen(p)+1)) { + q = ent->pathname; + do { + if (*p == '\\') p++; + *q++ = *p; + } while (*p++); + } + } else + ent->pathname = NULL; + + /* Found a valid record */ + done = TRUE; + + /* + * Extract attributes, build a linked list of + * 'em (may be none) + */ + if (attr = getattrval(NULL)) { + ent->attrlist = attr; + t = attr; + while (attr = getattrval(NULL)) { + t->next = attr; + t = attr; + } + t->next = NULL; + } else + ent->attrlist = NULL; + + } /* pathname extracted */ + } /* bdevice extracted */ + } /* cdevice extracted */ + } /* alias extracted */ + } + } /* !done && record read */ + + /* If no entry was read, free space allocated to the structure */ + if (!done) { + free(ent); + ent = NULL; + } + + return (ent); +} + +/* + * void _freedevtabent(devtabent) + * struct devtabent *devtabent; + * + * This function frees space allocated to a device table entry. + * + * Arguments: + * struct devtabent *devtabent The structure whose space is to be + * freed. + * + * Returns: void + */ + +void +_freedevtabent(struct devtabent *ent) +{ + /* + * Automatic data + */ + + struct attrval *p; /* Structure being freed */ + struct attrval *q; /* Next structure to free */ + + if (!ent->comment) { + + /* + * Free the attribute list. For each item in the attribute + * list, + * 1. Free the attribute name (always defined), + * 2. Free the value (if any -- it's not defined if we're + * changing an existing attribute), + * 3. Free the space allocated to the structure. + */ + + q = ent->attrlist; + if (q) + do { + p = q; + q = p->next; + free(p->attr); + if (p->val) free(p->val); + free(p); + } while (q); + + /* Free the standard fields (alias, cdevice, bdevice, pathname) */ + if (ent->alias) free(ent->alias); + if (ent->cdevice) free(ent->cdevice); + if (ent->bdevice) free(ent->bdevice); + if (ent->pathname) free(ent->pathname); + } + + /* Free the attribute string */ + if (ent->attrstr) free(ent->attrstr); + + /* Free the space allocated to the structure */ + free(ent); +} + +/* + * struct devtabent *_getdevrec(device) + * char *device + * + * Thie _getdevrec() function returns a pointer to a structure that + * contains the information in the device-table entry that describes + * the device <device>. + * + * The device <device> can be a device alias, a pathname contained in + * the entry as the "cdevice", "bdevice", or "pathname" attribute, + * or a pathname to a device described using the "cdevice", "bdevice", + * or "pathname" attribute (depending on whether the pathname references + * a character-special file, block-special file, or something else, + * respectively. + * + * Arguments: + * char *device A character-string describing the device whose record + * is to be retrieved from the device table. + * + * Returns: struct devtabent * + * A pointer to a structure describing the device. + * + * Notes: + * - Someday, add a cache so that repeated requests for the same record + * don't require going to the filesystem. (Maybe -- this might belong + * in devattr()...) + */ + +struct devtabent * +_getdevrec(char *device) /* The device to search for */ +{ + /* + * Automatic data + */ + + struct stat64 devstatbuf; /* Stat struct, <device> */ + struct stat64 tblstatbuf; /* Stat struct, tbl entry */ + struct devtabent *devrec; /* Pointer to current record */ + int found; /* TRUE if record found */ + int olderrno; /* Old value of errno */ + + + /* + * Search the device table looking for the requested device + */ + + _setdevtab(); + olderrno = errno; + found = FALSE; + if ((device != NULL) && !_validalias(device)) { + while (!found && (devrec = _getdevtabent())) { + if (!devrec->comment) { + if (devrec->cdevice) + if (strcmp(device, devrec->cdevice) == 0) found = TRUE; + if (devrec->bdevice) + if (strcmp(device, devrec->bdevice) == 0) found = TRUE; + if (devrec->pathname) + if (strcmp(device, devrec->pathname) == 0) found = TRUE; + } else _freedevtabent(devrec); + } + + /* + * If the device <device> wasn't named explicitly in the device + * table, compare it against like entries by comparing file- + * system, major device number, and minor device number + */ + + if (!found) { + _setdevtab(); + + /* Status the file <device>. If fails, invalid device */ + if (stat64(device, &devstatbuf) != 0) errno = ENODEV; + else { + + /* + * If <device> is a block-special device. See if it is + * in the table by matching its file-system indicator + * and major/minor device numbers against the + * file-system and major/minor device numbers of the + * "bdevice" entries. + */ + + if ((devstatbuf.st_mode & 0170000) == 0020000) { + while (!found && (devrec = _getdevtabent())) { + if (!devrec->comment && + (devrec->cdevice != NULL)) + if (stat64(devrec->cdevice, &tblstatbuf) == 0) { + if (samedev(tblstatbuf, devstatbuf)) + found = TRUE; + } else { + /* Ignore stat() errs */ + errno = olderrno; + } + if (!found) _freedevtabent(devrec); + } + } + + /* + * If <device> is a block-special device. See if it is + * in the table by matching its file-system indicator + * and major/minor device numbers against the + * file-system and major/minor device numbers of the + * "bdevice" entries. + */ + + else if ((devstatbuf.st_mode & 0170000) == 0060000) { + while (!found && (devrec = _getdevtabent())) { + if (!devrec->comment && + (devrec->bdevice != NULL)) + if (stat64(devrec->bdevice, &tblstatbuf) == 0) { + if (samedev(tblstatbuf, devstatbuf)) + found = TRUE; + } else { + /* Ignore stat() errs */ + errno = olderrno; + } + if (!found) _freedevtabent(devrec); + } + } + + /* + * If <device> is neither a block-special or character- + * special device. See if it is in the table by + * matching its file-system indicator and major/minor + * device numbers against the file-system and + * major/minor device numbers of the "pathname" entries. + */ + + else { + while (!found && (devrec = _getdevtabent())) { + if (!devrec->comment && + (devrec->pathname != NULL)) + if (stat64(devrec->pathname, + &tblstatbuf) == 0) { + if (samedev(tblstatbuf, devstatbuf)) + found = TRUE; + } else { + /* Ignore stat() errs */ + errno = olderrno; + } + if (!found) _freedevtabent(devrec); + } + } + + if (!found) { + devrec = NULL; + errno = ENODEV; + } + + } /* End case where stat() on the <device> succeeded */ + + } /* End case handling pathname not explicitly in device table */ + + } /* End case handling <device> as a fully-qualified pathname */ + + + /* + * Otherwise the device <device> is an alias. + * Search the table for a record that has as the "alias" attribute + * the value <device>. + */ + + else { + while (!found && (devrec = _getdevtabent())) { + if (!devrec->comment && (device != NULL) && + strcmp(device, devrec->alias) == 0) + found = TRUE; + else _freedevtabent(devrec); + } + if (!found) { + devrec = NULL; + errno = ENODEV; + } + } + + /* Fini */ + return (devrec); +} |