/*
* 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
* 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
* <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
* <devmgmt.h> Global Device Management definitions
* "devtab.h" Local Device Management definitions
*/
#include <sys/sysmacros.h>
#ifndef SUNOS41
#endif
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.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 int recbufsz = 0;
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
{
int same;
/* If the devices are of the same type ... */
/*
* 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.
*/
else
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) {
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 *
char *ptr, /* String to parse */
char *delims) /* List of delimiters */
{
char *p, *q; /* Temp pointers */
/*
* Figure out where to start.
* If given a pointer, use that.
* Otherwise, use where we left off.
*/
/*
* 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 */
while (*q && !done) { /* Any more chars */
if (*q == '\\') { /* Escaped ? */
if (*(++q)) q++; /* Skip escaped char */
} else /* Not escaped */
}
if (*q) { /* Terminator found? */
*q++ = '\0'; /* Null-terminate token */
leftoff = q; /* Remember restart pt. */
} else
}
/* 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 *
{
/* Automatic data */
char *p, *q; /* Temps */
/* Figure out where to start off */
/* If there's anything to parse and it's a quoted string ... */
/* Copy string for the caller */
q = rtn; /* Set up temp ptr */
do {
if (*p == '\\') p++; /* Skip escape */
*q++ = *p; /* Copy char */
} while (*p++); /* While there's chars */
/* 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 *
{
/* Automatic data */
char *p, *q; /* Temp pointers */
/* Use what's given to us or wherever we left off */
/* 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 */
/* Allocate space for the attribute name */
/* Copy the attribute name into alloc'd space */
do {
if (*p == '\\') p++; /* Skip escape */
*q++ = *p; /* Copy char */
} while (*p++); /* While more */
/* Extract the value */
/* Error getting value, free resources */
}
} else {
/* Error getting space for attribute, free resources */
}
} else {
/* No space for attr struct */
}
} else {
/* No attribute name */
}
} else {
/* Nothing to parse */
}
/* 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 *p; /* Temp pointer */
/* If there's no buffer for records, try to get one */
if (!recbuf) {
xtndcnt = 0;
} else return (NULL);
}
/* Get the next record */
/* While we've something to return and we're not finished ... */
/* If our return string isn't a null-string ... */
/* If we have a complete record, we're finished */
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 */
/* Have we reached our maximum extension count? */
if (xtndcnt < XTND_MAXCNT) {
/* Expand the record buffer */
/* Update buffer information */
xtndcnt++;
recbuf = p;
recbufsz += DTAB_BUFINC;
} else {
/* Expansion failed */
}
} else {
/* Maximum extend count exceeded. Insane table */
}
}
/* Complete the record */
if (!done) {
/* Read stuff into the expanded space */
} else {
/* Read failed, corrupt record? */
}
}
} /* End incomplete record handling */
} else {
/* Read a null string? (corrupt table) */
}
} /* 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
#endif
/*
* If compiled with -DDEBUG=1,
* look for the pathname in the environment
*/
#ifdef DEBUG
} else {
#endif
/*
* Use the standard device table.
*/
#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
{
/*
* Automatic data
*/
if (devtabname = _devtabpath()) {
dtabrecnum = 0; /* :-) */
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
{
/* Automatic data */
char *p; /* Temp pointer */
/* Assume the worst */
/*
* A valid alias contains 0 < i <= 14 characters. The first
* must be alphanumeric or "@$_." and the rest must be alphanumeric
* or "@#$_+-."
*/
/* Check length */
/* Check the first character */
p = alias;
/* Check the rest of the characters */
for (p++; *p && (isalnum((unsigned char)*p) ||
strchr("@#$_-+.", *p)); p++)
;
}
}
/* 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 */
char *p, *q; /* Tmp char ptrs */
/* 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 */
return (NULL);
}
/* Save record number in structure */
/* Comment record? If so, just save the value and we're through */
p = record;
do {
if (*p == '\\') p++;
*q++ = *p;
} while (*p++);
} else {
}
}
else {
/* Record is a data record. Parse it. */
/* Extract the device alias */
if (*p) {
do {
if (*p == '\\') p++;
*q++ = *p;
} while (*p++);
}
/* Extract the character-device name */
} else {
if (*p) {
do {
if (*p == '\\') p++;
*q++ = *p;
} while (*p++);
}
/* Extract the block-device name */
} else {
if (*p) {
do {
if (*p == '\\') p++;
*q++ = *p;
} while (*p++);
}
} else
/* Extract the pathname */
} else {
if (*p) {
do {
if (*p == '\\') p++;
*q++ = *p;
} while (*p++);
}
} else
/* Found a valid record */
/*
* Extract attributes, build a linked list of
* 'em (may be none)
*/
t = attr;
t = attr;
}
} else
} /* pathname extracted */
} /* bdevice extracted */
} /* cdevice extracted */
} /* alias extracted */
}
} /* !done && record read */
/* If no entry was read, free space allocated to the structure */
if (!done) {
}
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
{
/*
* Automatic data
*/
struct attrval *p; /* Structure being freed */
struct attrval *q; /* Next structure to free */
/*
* 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.
*/
if (q)
do {
p = q;
q = p->next;
free(p);
} while (q);
/* Free the standard fields (alias, cdevice, bdevice, pathname) */
}
/* Free the attribute string */
/* Free the space allocated to the structure */
}
/*
* 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 *
{
/*
* Automatic data
*/
/*
* Search the device table looking for the requested device
*/
_setdevtab();
} 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 */
else {
/*
* If <device> is a block-special device. See if it is
* in the table by matching its file-system indicator
* "bdevice" entries.
*/
} else {
/* Ignore stat() errs */
}
}
}
/*
* If <device> is a block-special device. See if it is
* in the table by matching its file-system indicator
* "bdevice" entries.
*/
} else {
/* Ignore stat() errs */
}
}
}
/*
* If <device> is neither a block-special or character-
* special device. See if it is in the table by
* device numbers against the file-system and
*/
else {
&tblstatbuf) == 0) {
} else {
/* Ignore stat() errs */
}
}
}
if (!found) {
}
} /* 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 {
else _freedevtabent(devrec);
}
if (!found) {
}
}
/* Fini */
return (devrec);
}