1298 lines
34 KiB
C
Executable File
1298 lines
34 KiB
C
Executable File
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
||
/* All Rights Reserved */
|
||
|
||
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
||
/* The copyright notice above does not evidence any */
|
||
/* actual or intended publication of such source code. */
|
||
|
||
#ident "@(#)putdev.c 1.4 92/07/14 SMI" /* SVr4.0 1.2 */
|
||
/* LINTLIBRARY */
|
||
|
||
/*
|
||
* putdev.c
|
||
*
|
||
* Global Definitions:
|
||
* _adddevtabrec() Add a record to the device table
|
||
* _putdevtabrec() Write a record to the device table
|
||
* _moddevtabrec() Modify a device-table record
|
||
* _rmdevtabrec() Remove a device-table record
|
||
* _rmdevtabattrs() Remove attributes from a device-table record
|
||
* oam_devtab File descriptor of the open device table
|
||
*/
|
||
|
||
/*
|
||
* G L O B A L R E F E R E N C E S
|
||
*
|
||
* Header Files
|
||
* Externals Referenced
|
||
*/
|
||
|
||
/*
|
||
* Header Files
|
||
* <sys/types.h> UNIX(r) Data Types
|
||
* <sys/stat.h>
|
||
* <stdio.h> Standard I/O definitions
|
||
* <fcntl.h> Definitions for file control
|
||
* <errno.h> Error handling definitions
|
||
* <string.h> String Handling Definitions
|
||
* <devmgmt.h> Device Management Definitions
|
||
* <unistd.h> Get UNIX(r) Standard Definitions
|
||
* "devtab.h" Local Device Management Definitions
|
||
*/
|
||
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <stdio.h>
|
||
#include <fcntl.h>
|
||
#include <errno.h>
|
||
#include <string.h>
|
||
#include <devmgmt.h>
|
||
#include <unistd.h>
|
||
#include "devtab.h"
|
||
|
||
|
||
/*
|
||
* External functions referenced
|
||
* malloc() Allocate memory
|
||
* free() Free malloc()ed memory
|
||
* getpid() Get process-ID
|
||
* umask() File-permissions mask
|
||
* unlink() Unlink a file (USE rename() SOMEDAY)
|
||
* link() Link a file (USE rename() SOMEDAY)
|
||
*/
|
||
|
||
extern void *malloc();
|
||
extern void free();
|
||
extern pid_t getpid();
|
||
extern mode_t umask();
|
||
extern int link();
|
||
extern int unlink();
|
||
|
||
|
||
/*
|
||
* External data referenced:
|
||
* oam_devtab Open file descriptor for the device table
|
||
*/
|
||
|
||
extern FILE *oam_devtab;
|
||
|
||
/*
|
||
* L O C A L D E F I N I T I O N S
|
||
*
|
||
* TDTABNM Name of the temporary device table (in the
|
||
* directory of the existing table)
|
||
* TDTABNMLN Number of characters added to the directory
|
||
* name -- the length of the device table temp name
|
||
*/
|
||
|
||
#define TDTABNM "%sdevtab.%6.6ld"
|
||
#define TDTABNMLN 13
|
||
|
||
|
||
/*
|
||
* Static functions
|
||
* strcatesc Copies a character-string from one place to another
|
||
* escaping the appropriate characters
|
||
* lkdevtab Locks the device table
|
||
* unlkdevtab Unlocks the device table
|
||
* mkdevtabent Builds a device-table entry from the alias and the
|
||
* list of attr=val pairs given
|
||
* opennewdevtab Opens a new device table (as a temp file)
|
||
* mknewdevtab Makes the temp device table the new devtab
|
||
* rmnewdevtab Remove the temporary device table and free space
|
||
* allocated to the filename of that file.
|
||
*/
|
||
|
||
static char *strcatesc();
|
||
static int lkdevtab();
|
||
static int unlkdevtab();
|
||
static struct devtabent *mkdevtabent();
|
||
static FILE *opennewdevtab();
|
||
static int mknewdevtab();
|
||
static int rmnewdevtab();
|
||
|
||
/*
|
||
* char *strcatesc(p, q)
|
||
* char *p
|
||
* char *q
|
||
*
|
||
* Write the character-string pointed to by "q" to the place
|
||
* pointed to by "p", escaping those characters in "q" found in the
|
||
* string "DTAB_ESCS" by preceding them with '\\'. Return a pointer to
|
||
* the byte beyond the last character written to "p".
|
||
*
|
||
* Arguments:
|
||
* p The place to begin writing to
|
||
* q The string to write
|
||
*
|
||
* Returns: char *
|
||
* The address of the byte beyond the last character written into "p"
|
||
*/
|
||
|
||
static char *
|
||
strcatesc(p, q)
|
||
char *p; /* Place to write to */
|
||
char *q; /* Thing to write */
|
||
{
|
||
while (*q) {
|
||
if (strchr(DTAB_ESCS, *q)) *p++ = '\\';
|
||
*p++ = *q++;
|
||
}
|
||
return(p);
|
||
}
|
||
|
||
/*
|
||
* FILE *opennewdevtab(pname)
|
||
* char **pname
|
||
*
|
||
* Generates a temporary device-table name from the existing
|
||
* device table name (in the same directory) and opens that
|
||
* file for writing. It puts a pointer to the malloc()ed space
|
||
* containing the temp device table's name at the place referenced
|
||
* by <pname>.
|
||
*
|
||
* Arguments:
|
||
* pname Pointer to the char * to contain the address of the name
|
||
* of the temporary file
|
||
*
|
||
* Returns: FILE *
|
||
* A pointer to the opened stream or (FILE *) NULL if an error occurred.
|
||
* If an error occurred, "errno" will be set to reflect the problem.
|
||
*/
|
||
|
||
static FILE *
|
||
opennewdevtab(pname)
|
||
char **pname; /* A(ptr to temp filename's path) */
|
||
{
|
||
char *oldname; /* Ptr to the device-table's name */
|
||
char *buf; /* Ptr to the temp file's name */
|
||
char *dirname; /* Directory containing devtab */
|
||
char *p; /* Ptr to last '/' in devtab name */
|
||
int fd; /* Opened file descriptor */
|
||
FILE *fp; /* Opened file pointer */
|
||
struct stat sbuf; /* stat buf for old devtab file */
|
||
|
||
fp = (FILE *) NULL;
|
||
if (oldname = _devtabpath()) {
|
||
/*
|
||
* It is possible for us to have sufficient permissions to create
|
||
* the new file without having sufficient permissions to write the
|
||
* original devtab file. For consistency with the operations which
|
||
* modify the original file by writing it directly we require write
|
||
* permissions for the original file in order to make a new one.
|
||
*/
|
||
if ((fd = open(oldname, O_WRONLY)) == -1)
|
||
return(NULL);
|
||
|
||
if (fstat(fd, &sbuf) == -1) {
|
||
close(fd);
|
||
return(NULL);
|
||
}
|
||
close(fd);
|
||
|
||
if (p = strrchr(oldname, '/')) {
|
||
*(p+1) = '\0';
|
||
dirname = oldname;
|
||
}
|
||
else dirname = "./";
|
||
if (buf = (char *) malloc(TDTABNMLN + strlen(dirname) + 1)) {
|
||
|
||
/* Build the name of the temp device table and open the
|
||
* file. We must reset the owner, group and perms to those
|
||
* of the original devtab file.
|
||
*/
|
||
(void) sprintf(buf, TDTABNM, dirname, getpid());
|
||
if (fp = fopen(buf, "w")) {
|
||
*pname = buf;
|
||
fchmod(fileno(fp), sbuf.st_mode & 0777);
|
||
fchown(fileno(fp), sbuf.st_uid, sbuf.st_gid);
|
||
} else {
|
||
free(buf);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Free the space containing the device table's name.
|
||
*/
|
||
free(oldname);
|
||
}
|
||
|
||
/* Finished. Return what we've got */
|
||
return(fp);
|
||
}
|
||
|
||
/*
|
||
* int rmnewdevtab(tempname)
|
||
* char *tempname
|
||
*
|
||
* Unlink the temp device table and free the memory allocated to
|
||
* contain the name of that file
|
||
*
|
||
* Arguments:
|
||
* tempname Name of the temporary file
|
||
*
|
||
* Returns: int
|
||
* TRUE if successful, FALSE otherwise
|
||
*/
|
||
|
||
static int
|
||
rmnewdevtab(tempname)
|
||
char *tempname; /* Filename of new device table */
|
||
{
|
||
int noerr; /* Flag, TRUE if no error, FALSE otherwise */
|
||
|
||
/* Unlink the file */
|
||
noerr = (unlink(tempname) == 0);
|
||
|
||
/* Free the space allocated to the filename */
|
||
free(tempname);
|
||
|
||
/* Return success indicator */
|
||
return(noerr);
|
||
}
|
||
|
||
/*
|
||
* int mknewdevtab(tempname)
|
||
* char *tempname
|
||
*
|
||
* Make the temporary device-table the new system device table
|
||
*
|
||
* Arguments:
|
||
* tempname Name of the temporary file
|
||
*
|
||
* Returns: int
|
||
* TRUE if successful, FALSE otherwise
|
||
*
|
||
* Notes:
|
||
* - Need to use rename() someday instead of link()/unlink()
|
||
* - This code is somewhat ineffecient in that asks for the name
|
||
* of the device-table more than once. Done so that we don't
|
||
* have to manage that space, but this may be somewhat lazy.
|
||
*/
|
||
|
||
static int
|
||
mknewdevtab(tempname)
|
||
char *tempname; /* Ptr to name of temp dev tab */
|
||
{
|
||
char *devtabname; /* Ptr to the device table's name */
|
||
int noerr; /* FLAG, TRUE if all's well */
|
||
|
||
/* Get the device table's pathname */
|
||
if (devtabname = _devtabpath()) {
|
||
|
||
/* Unlink the existing file */
|
||
if (unlink(devtabname) == 0) {
|
||
|
||
/* Make the temp file the real device table */
|
||
noerr = (link(tempname, devtabname) == 0) ? TRUE : FALSE;
|
||
|
||
/* Remove the temp file (and resources) */
|
||
if (noerr) (void) rmnewdevtab(tempname);
|
||
|
||
} else noerr = FALSE; /* unlink() failed */
|
||
|
||
/* Free the device table's name */
|
||
free(devtabname);
|
||
|
||
} else noerr = FALSE; /* devtabpath() failed */
|
||
|
||
/* Finished. Return success indicator */
|
||
return(noerr);
|
||
}
|
||
|
||
/*
|
||
* int lkdevtab(o_mode, lktype)
|
||
* char *o_mode
|
||
* int lktype
|
||
*
|
||
* Lock the device table for writing. If it isn't available, it waits
|
||
* until it is.
|
||
*
|
||
* Arguments:
|
||
* o_mode The open() mode to use when opening the device table
|
||
* lktype The type of lock to apply
|
||
*
|
||
* Returns: int
|
||
* TRUE if successful, FALSE with errno set otherwise
|
||
*/
|
||
|
||
static int
|
||
lkdevtab(o_mode, lktype)
|
||
char *o_mode; /* Open mode */
|
||
int lktype; /* Lock type */
|
||
{
|
||
/* Automatic data */
|
||
struct flock lockinfo; /* File locking structure */
|
||
int noerr; /* FLAG, TRUE if no error */
|
||
int olderrno; /* Old value of "errno" */
|
||
|
||
|
||
/* Close the device table (if it's open) */
|
||
_enddevtab();
|
||
|
||
/* Open the device table for read/append */
|
||
noerr = TRUE;
|
||
if (_opendevtab(o_mode)) {
|
||
|
||
/*
|
||
* Lock the device table (for writing). If it's not
|
||
* available, wait until it is, then close and open the
|
||
* table (modify and delete change the table!) and try
|
||
* to lock it again
|
||
*/
|
||
|
||
/* Build the locking structure */
|
||
lockinfo.l_type = (short) lktype;
|
||
lockinfo.l_whence = 0;
|
||
lockinfo.l_start = 0L;
|
||
lockinfo.l_len = 0L;
|
||
olderrno = errno;
|
||
|
||
/* Keep on going until we lock the file or an error happens */
|
||
while ((fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) == -1) && !noerr) {
|
||
if (errno == EACCES) {
|
||
if (fcntl(fileno(oam_devtab), F_SETLKW, &lockinfo) == -1)
|
||
noerr = FALSE;
|
||
else {
|
||
/* Reopen the file (maybe it's moved?) */
|
||
_enddevtab();
|
||
if (!_opendevtab(o_mode)) noerr = FALSE;
|
||
else errno = olderrno;
|
||
}
|
||
} else noerr = FALSE;
|
||
}
|
||
|
||
if (!noerr) _enddevtab(); /* Don't keep open if in error */
|
||
|
||
} else noerr = FALSE;
|
||
|
||
/* Done */
|
||
return(noerr);
|
||
}
|
||
|
||
/*
|
||
* int unlkdevtab()
|
||
*
|
||
* Unlock the locked device table.
|
||
*
|
||
* Arguments: None
|
||
*
|
||
* Returns: int
|
||
* Whatever fcntl() returns...
|
||
*/
|
||
|
||
static int
|
||
unlkdevtab()
|
||
{
|
||
/* Automatic data */
|
||
struct flock lockinfo; /* Locking structure */
|
||
int noerr; /* FLAG, TRUE if all's well */
|
||
|
||
/* Build the locking structure */
|
||
lockinfo.l_type = F_UNLCK; /* Lock type */
|
||
lockinfo.l_whence = 0; /* Count from top of file */
|
||
lockinfo.l_start = 0L; /* From beginning */
|
||
lockinfo.l_len = 0L; /* Length of locked data */
|
||
|
||
/* Unlock it */
|
||
noerr = (fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) != -1);
|
||
_enddevtab();
|
||
|
||
/* Finished */
|
||
return(noerr);
|
||
}
|
||
|
||
/*
|
||
* struct devtabent *mkdevtabent(alias, attrlist)
|
||
* char *alias
|
||
* char **attrlist
|
||
*
|
||
* This function builds a struct devtabent structure describing the
|
||
* alias <alias> using the information in the attribute list <attrlist>.
|
||
* The <attrlist> contains data of the form attr=value where attr is
|
||
* the name of an attribute and value is the value of that attribute.
|
||
*
|
||
* Arguments:
|
||
* alias The alias being added to the device table
|
||
* attrlist The attributes and values for that alias
|
||
*
|
||
* Returns: struct devtabent *
|
||
* A completed struct devtabent structure containing the description
|
||
* of the alias. The structure, and all of the data in the structure
|
||
* are each in space allocated using the malloc() function and should
|
||
* be freed using the free() function (or the _freedevtabent() function).
|
||
*
|
||
* Errors:
|
||
* EINVAL If "alias" is used as an attribute in an attr=val pair
|
||
* EAGAIN If an attribute is specified more than once
|
||
*/
|
||
|
||
static struct devtabent *
|
||
mkdevtabent(alias, attrlist)
|
||
char *alias; /* Alias of entry */
|
||
char **attrlist; /* Attributes of new entry */
|
||
{
|
||
/* Automatic data */
|
||
struct devtabent *devtabent; /* * to struct we're making */
|
||
struct attrval *prevattrval; /* * to prev attr/val struct */
|
||
struct attrval *attrval; /* * to current struct */
|
||
char **pp; /* Ptr into list of ptrs */
|
||
char *peq; /* Ptr to '=' in string */
|
||
char *val; /* Ptr to space for value */
|
||
char *name; /* Ptr to space for name */
|
||
int len; /* Length of name */
|
||
int noerr; /* TRUE if all's well */
|
||
int found; /* TRUE the attr is found */
|
||
|
||
|
||
/* No problems (yet) */
|
||
noerr = TRUE;
|
||
|
||
/* Get space for the structure */
|
||
if (devtabent = (struct devtabent *) malloc(sizeof(struct devtabent))) {
|
||
|
||
/* Fill in default values */
|
||
if (devtabent->alias = (char *) malloc(strlen(alias)+1)) {
|
||
|
||
(void) strcpy(devtabent->alias, alias); /* alias */
|
||
devtabent->comment = FALSE; /* data rec */
|
||
devtabent->cdevice = (char *) NULL; /* cdevice */
|
||
devtabent->bdevice = (char *) NULL; /* bdevice */
|
||
devtabent->pathname = (char *) NULL; /* pathname */
|
||
devtabent->attrstr = (char *) NULL; /* string */
|
||
devtabent->attrlist = (struct attrval *) NULL; /* attr list */
|
||
|
||
/* Add attributes to the structure */
|
||
prevattrval = (struct attrval *) NULL;
|
||
if (pp = attrlist) while (*pp && noerr) {
|
||
|
||
/* Valid attr=value pair? */
|
||
if ((peq = strchr(*pp, '=')) && ((len = peq-*pp) > 0)) {
|
||
|
||
/* Get space for the value */
|
||
if (val = (char *) malloc((unsigned int) strlen(peq))) {
|
||
(void) strcpy(val, peq+1); /* Copy it */
|
||
|
||
/* Get space for attribute name */
|
||
if (name = (char *) malloc(len + 1)) {
|
||
(void) strncpy(name, *pp, len);
|
||
*(name+len) = '\0';
|
||
|
||
/* Specifying the alias? If so, ERROR */
|
||
if (strcmp(name, DTAB_ALIAS) == 0) {
|
||
noerr = FALSE;
|
||
free(name);
|
||
free(val);
|
||
errno = EINVAL;
|
||
}
|
||
|
||
/* Specifying the char device path? */
|
||
else if (strcmp(name, DTAB_CDEVICE) == 0) {
|
||
if (!devtabent->cdevice) {
|
||
if (val[0] != '/') {
|
||
noerr = FALSE;
|
||
free(name);
|
||
free(val);
|
||
errno = ENXIO;
|
||
} else {
|
||
devtabent->cdevice = val;
|
||
free(name);
|
||
}
|
||
} else {
|
||
noerr = FALSE;
|
||
free(name);
|
||
free(val);
|
||
errno = EAGAIN;
|
||
}
|
||
}
|
||
|
||
/* Specifying the block device path? */
|
||
else if (strcmp(name, DTAB_BDEVICE) == 0) {
|
||
if (!devtabent->bdevice) {
|
||
if (val[0] != '/') {
|
||
noerr = FALSE;
|
||
free(name);
|
||
free(val);
|
||
errno = ENXIO;
|
||
} else {
|
||
devtabent->bdevice = val;
|
||
free(name);
|
||
}
|
||
} else {
|
||
noerr = FALSE;
|
||
free(name);
|
||
free(val);
|
||
errno = EAGAIN;
|
||
}
|
||
}
|
||
|
||
/* Specifying the pathname (generic)? */
|
||
else if (strcmp(name, DTAB_PATHNAME) == 0) {
|
||
if (!devtabent->pathname) {
|
||
if (val[0] != '/') {
|
||
noerr = FALSE;
|
||
free(name);
|
||
free(val);
|
||
errno = ENXIO;
|
||
} else {
|
||
devtabent->pathname = val;
|
||
free(name);
|
||
}
|
||
} else {
|
||
noerr = FALSE;
|
||
free(name);
|
||
free(val);
|
||
errno = EAGAIN;
|
||
}
|
||
}
|
||
|
||
/* Some other attribute */
|
||
else {
|
||
found = FALSE;
|
||
if (attrval = devtabent->attrlist) do {
|
||
if (strcmp(attrval->attr, name) == 0) {
|
||
noerr = FALSE;
|
||
free(name);
|
||
free(val);
|
||
errno = EAGAIN;
|
||
}
|
||
} while (!found && noerr && (attrval = attrval->next));
|
||
|
||
if (!found && noerr) {
|
||
|
||
/* Get space for attr/val structure */
|
||
if (attrval = (struct attrval *) malloc(sizeof(struct attrval))) {
|
||
|
||
/* Fill attr/val structure */
|
||
attrval->attr = name;
|
||
attrval->val = val;
|
||
attrval->next = (struct attrval *) NULL;
|
||
|
||
/* Link into the list of attributes */
|
||
if (prevattrval) prevattrval->next = attrval;
|
||
else devtabent->attrlist = attrval;
|
||
prevattrval = attrval;
|
||
|
||
} else { /* malloc() for attrval failed */
|
||
noerr = FALSE;
|
||
free(name);
|
||
free(val);
|
||
}
|
||
}
|
||
} /* End else (some other attribute) */
|
||
|
||
} else { /* malloc() for attribute name failed */
|
||
noerr = FALSE;
|
||
free(val);
|
||
}
|
||
|
||
} else noerr = FALSE; /* Malloc() for "val" failed */
|
||
|
||
/* If we saw an error, free structure, returning NULL */
|
||
if (!noerr) {
|
||
_freedevtabent(devtabent);
|
||
devtabent = (struct devtabent *) NULL;
|
||
}
|
||
|
||
} /* Ignore invalid attr=val pair */
|
||
|
||
if (noerr) pp++;
|
||
|
||
} /* End attribute processing loop */
|
||
|
||
} else { /* malloc() failed */
|
||
free(devtabent);
|
||
devtabent = (struct devtabent *) NULL;
|
||
noerr = FALSE;
|
||
}
|
||
} else noerr = FALSE; /* if (malloc(devtabent space)) */
|
||
|
||
/* Finished */
|
||
return(devtabent);
|
||
}
|
||
|
||
/*
|
||
* int _putdevtabrec(stream, rec)
|
||
* FILE *stream
|
||
* struct devtabent *rec
|
||
*
|
||
* Write a device table record containing the information in the struct
|
||
* devtab structure <rec> to the current position of the standard I/O
|
||
* stream <stream>.
|
||
*
|
||
* Arguments:
|
||
* stream The stream to write to
|
||
* rec The structure containing the information to write
|
||
*
|
||
* Returns: int
|
||
* The number of characters written or EOF if there was some error.
|
||
*/
|
||
|
||
int
|
||
_putdevtabrec(stream, rec)
|
||
FILE *stream; /* Stream to which to write */
|
||
struct devtabent *rec; /* Record to write */
|
||
{
|
||
/* Automatic Data */
|
||
struct attrval *attrval; /* Ptr to attr/val pair */
|
||
char *buf; /* Allocated buffer */
|
||
char *p; /* Temp char pointer */
|
||
int count; /* Number of chars written */
|
||
int size=0; /* Size of needed buffer */
|
||
|
||
|
||
/* Comment or data record? */
|
||
if (rec->comment) {
|
||
|
||
/*
|
||
* Record is a comment
|
||
*/
|
||
|
||
/* Copy (escaping chars) record into temp buffer */
|
||
size = (strlen(rec->attrstr)*2)+1; /* Max rec size */
|
||
if (buf = (char *) malloc((unsigned int) size+1)) { /* Alloc space */
|
||
p = strcatesc(buf, rec->attrstr); /* Copy "escaped" */
|
||
*(p-2) = '\n'; /* Unescape last \n */
|
||
*(p-1) = '\0'; /* Terminate string */
|
||
|
||
/* Write the record */
|
||
count = fputs(buf, stream);
|
||
free(buf);
|
||
|
||
} else count = EOF; /* malloc() failed */
|
||
}
|
||
|
||
else {
|
||
|
||
/*
|
||
* Record is a data record
|
||
*/
|
||
|
||
/*
|
||
* Figure out maximum amount of space you're going to need.
|
||
* (Assume every escapable character is escaped to determine the
|
||
* maximum size needed)
|
||
*/
|
||
|
||
if(rec->cdevice)size += (strlen(rec->cdevice)*2) + 1; /* cdevice: */
|
||
if(rec->bdevice) size += (strlen(rec->bdevice)*2) + 1; /* bdevice: */
|
||
if(rec->pathname) size += (strlen(rec->pathname)*2) + 1; /* pathname: */
|
||
if (attrval = rec->attrlist) do { /* Attributes */
|
||
if(attrval->attr) size += (strlen(attrval->attr)*2); /* attr */
|
||
if(attrval->val) size += (strlen(attrval->val)*2) +4; /* val & '="" ' or val & '=""\n' */
|
||
} while (attrval = attrval->next) ; /* Next attr/val */
|
||
else size++; /* Else make room for trailing '\n' */
|
||
|
||
/* Alloc space for "escaped" record */
|
||
if (buf = (char *) malloc((unsigned int) size+1)) {
|
||
|
||
/* Initializations */
|
||
p = buf;
|
||
|
||
/* Write the alias ("alias" attribute) */
|
||
p = strcatesc(p, rec->alias);
|
||
*p++ = ':';
|
||
|
||
/* Write the character device ("cdevice" attribute) */
|
||
if (rec->cdevice) p = strcatesc(p, rec->cdevice);
|
||
*p++ = ':';
|
||
|
||
/* Write the block device ("bdevice" attribute) */
|
||
if (rec->bdevice) p = strcatesc(p, rec->bdevice);
|
||
*p++ = ':';
|
||
|
||
/* Write the pathname ("pathname" attribute) */
|
||
if (rec->pathname) p = strcatesc(p, rec->pathname);
|
||
*p++ = ':';
|
||
|
||
/* Write the rest of the attributes */
|
||
if (attrval = rec->attrlist) do {
|
||
p = strcatesc(p, attrval->attr);
|
||
*p++ = '=';
|
||
*p++ = '"';
|
||
p = strcatesc(p, attrval->val);
|
||
*p++ = '"';
|
||
if (attrval = attrval->next) *p++ = ' ';
|
||
} while (attrval);
|
||
|
||
/* Terminate the record */
|
||
*p++ = '\n';
|
||
*p = '\0';
|
||
|
||
/* Write the record */
|
||
count = fputs(buf, stream);
|
||
free(buf);
|
||
}
|
||
else count = EOF; /* malloc() failed */
|
||
}
|
||
|
||
/* Finished */
|
||
return(count);
|
||
}
|
||
|
||
/*
|
||
* int _adddevtabrec(alias, attrval)
|
||
* char *alias
|
||
* char **attrval
|
||
*
|
||
* This function adds a record to the device table. That record will
|
||
* have the alias <alias> and will have the attributes described in
|
||
* the list referenced by <attrval>.
|
||
*
|
||
* It always adds the record to the end of the table.
|
||
*
|
||
* Arguments:
|
||
* alias The alias of the device whose description is being
|
||
* added to the device table.
|
||
* attrval The pointer to the first item of a list of attributes
|
||
* defining the device whose description is being added.
|
||
* (This value may be (char **) NULL).
|
||
*
|
||
* Returns: int
|
||
* TRUE if successful, FALSE with errno set otherwise.
|
||
*/
|
||
|
||
int
|
||
_adddevtabrec(alias, attrval)
|
||
char *alias; /* Alias to add to the device table */
|
||
char **attrval; /* Attributes for that device */
|
||
{
|
||
/* Automatic data */
|
||
struct devtabent *devtabent; /* Ptr to dev tab entry */
|
||
int olderrno; /* Errno on entry */
|
||
int noerr; /* FLAG, TRUE if all's well */
|
||
|
||
olderrno=noerr=0; /* Initialize error flags */
|
||
|
||
/* Validate the device alias. Error (EINVAL) if it's not valid */
|
||
if (!_validalias(alias)) {
|
||
errno = EINVAL;
|
||
return(FALSE);
|
||
}
|
||
|
||
/* Lock the device table. This only returns if the table is locked or
|
||
* some error occurred. It waits until the table is available. */
|
||
if (!lkdevtab("a+", F_WRLCK)) return(FALSE);
|
||
|
||
/* Make sure that the alias isn't already in the table */
|
||
noerr = TRUE;
|
||
olderrno = errno;
|
||
if (devtabent = _getdevrec(alias)) {
|
||
|
||
/* The alias is already in the table */
|
||
_freedevtabent(devtabent); /* Free device table info */
|
||
errno = EEXIST; /* Set errno, entry exists */
|
||
noerr = FALSE; /* All's not well */
|
||
}
|
||
else if ((errno == ENOENT) || (errno == ENODEV)) {
|
||
|
||
/* The alias wasn't in the table or there wasn't a table. */
|
||
|
||
errno = olderrno; /* Reset errno */
|
||
|
||
/* Build a struct devtabent that describes the new alias */
|
||
if (devtabent = mkdevtabent(alias, attrval)) {
|
||
|
||
/* Position to the end of the existing table */
|
||
if (fseek(oam_devtab, 0, SEEK_END) == 0)
|
||
|
||
/* Write the new entry */
|
||
noerr = (_putdevtabrec(oam_devtab, devtabent) != EOF);
|
||
|
||
/* Free the info we just wrote */
|
||
_freedevtabent(devtabent);
|
||
|
||
} else noerr = FALSE; /* mkdevtabent() failed */
|
||
} else noerr = FALSE; /* Some odd error, _devtab */
|
||
|
||
/* Unlock and close the device table */
|
||
(void) unlkdevtab();
|
||
|
||
/* Fini */
|
||
return(noerr);
|
||
}
|
||
|
||
/*
|
||
* int _moddevtabrec(device, attrval)
|
||
* char *device
|
||
* char **attrval
|
||
*
|
||
* This function modifies the description for the specified device
|
||
* so that it has the attributes and values as specified in the
|
||
* given list.
|
||
*
|
||
* Arguments:
|
||
* device The name of the device whose description
|
||
* is being modified
|
||
* attrval The first attr/val value in the list (attr=val) of
|
||
* the attributes that are to change
|
||
*
|
||
* Returns: int
|
||
* TRUE if all went well, FALSE with errno set otherwise
|
||
*/
|
||
|
||
int
|
||
_moddevtabrec(device, attrval)
|
||
char *device; /* Device to modify */
|
||
char **attrval; /* Attributes to add or change */
|
||
{
|
||
/* Automatic data */
|
||
FILE *fd; /* File ptr, new device table */
|
||
struct devtabent *ent; /* Device's current description */
|
||
struct devtabent *chg; /* Changes to make to description */
|
||
struct attrval *new; /* New attribute/value desc */
|
||
struct attrval *old; /* Old attribute/value desc */
|
||
struct attrval *newnew; /* Next "new" value to look at */
|
||
struct attrval *prevnew;/* Previous item in the 'new' list */
|
||
char *tname; /* name of temp devtab file */
|
||
int noerr; /* FLAG, TRUE if all's well */
|
||
int found; /* FLAG, TRUE if attr found for dev */
|
||
|
||
/* Lock the device table */
|
||
if (!lkdevtab("r", F_WRLCK)) return(FALSE);
|
||
|
||
/* No problems (so far) */
|
||
noerr = TRUE;
|
||
|
||
/* Get the entry to modify */
|
||
if (ent = _getdevrec(device)) {
|
||
|
||
/* Build a structure describing the changes */
|
||
if (chg = mkdevtabent(device, attrval)) {
|
||
|
||
/* If the "cdevice" field is specified, change it */
|
||
if (chg->cdevice) {
|
||
if (ent->cdevice) free(ent->cdevice);
|
||
ent->cdevice = chg->cdevice;
|
||
chg->cdevice = (char *) NULL;
|
||
}
|
||
|
||
/* If the "bdevice" field is specified, change it */
|
||
if (chg->bdevice) {
|
||
if (ent->bdevice) free(ent->bdevice);
|
||
ent->bdevice = chg->bdevice;
|
||
chg->bdevice = (char *) NULL;
|
||
}
|
||
|
||
/* If the "pathname" field is specified, change it */
|
||
if (chg->pathname) {
|
||
if (ent->pathname) free(ent->pathname);
|
||
ent->pathname = chg->pathname;
|
||
chg->pathname = (char *) NULL;
|
||
}
|
||
|
||
/* Change the other attributes (if any) */
|
||
if (ent->attrlist) {
|
||
prevnew = (struct attrval *) NULL;
|
||
if (new = chg->attrlist) do {
|
||
|
||
found = FALSE;
|
||
for (old = ent->attrlist ; !found && old ; old = old->next) {
|
||
if (strcmp(old->attr, new->attr) == 0) {
|
||
found = TRUE;
|
||
free(old->val);
|
||
old->val = new->val;
|
||
new->val = (char *) NULL;
|
||
}
|
||
} /* Loop through the existing attribute list */
|
||
|
||
/*
|
||
* If the attribute wasn't found, add it to the list
|
||
* of attributes for the device. If it was found, just
|
||
* bump to the next one and look for it
|
||
*/
|
||
|
||
if (!found) {
|
||
|
||
/* Not found. Move attr/val description to the
|
||
* device's list of attributes */
|
||
|
||
if (prevnew) prevnew->next = new->next;
|
||
else chg->attrlist = new->next;
|
||
newnew = new->next;
|
||
new->next = ent->attrlist;
|
||
ent->attrlist = new;
|
||
new = newnew;
|
||
}
|
||
else {
|
||
|
||
/* Attribute changed, bump to the next one */
|
||
prevnew = new;
|
||
new = new->next;
|
||
}
|
||
} while (new); /* Loop for each attr to add or modify */
|
||
|
||
} else {
|
||
|
||
/* Device had no attributes -- add entire list */
|
||
ent->attrlist = chg->attrlist;
|
||
chg->attrlist = (struct attrval *) NULL;
|
||
}
|
||
|
||
/* Free the structure containing the changes */
|
||
_freedevtabent(chg);
|
||
|
||
} else noerr = FALSE; /* Couldn't build changes struct */
|
||
|
||
/* If there hasn't been an error (so far), write the new record */
|
||
if (noerr) {
|
||
|
||
/* Open the new device table */
|
||
if (fd = opennewdevtab(&tname)) {
|
||
|
||
/*
|
||
* For each entry in the existing table, write that entry
|
||
* to the new table. If the entry is the one being
|
||
* modified, write the modified entry instead of the
|
||
* original entry.
|
||
*/
|
||
|
||
_setdevtab(); /* Rewind existing table */
|
||
chg = ent; /* Remember new record */
|
||
while ((ent = _getdevtabent()) && noerr) {
|
||
if (ent->entryno != chg->entryno)
|
||
noerr = _putdevtabrec(fd, ent) != EOF;
|
||
else noerr = _putdevtabrec(fd, chg) != EOF;
|
||
_freedevtabent(ent);
|
||
}
|
||
|
||
/*
|
||
* If we successfully generated the new table, make it the
|
||
* new system device table. Otherwise, just remove the
|
||
* temporary file we've created.
|
||
*/
|
||
|
||
if (noerr) {
|
||
(void) fclose(fd);
|
||
noerr = mknewdevtab(tname);
|
||
} else {
|
||
(void) fclose(fd);
|
||
(void) rmnewdevtab(tname);
|
||
}
|
||
|
||
/* Free the changed device structure */
|
||
_freedevtabent(chg);
|
||
|
||
} /* if (_opennewdevtab()) */
|
||
else noerr = FALSE;
|
||
|
||
} else _freedevtabent(ent); /* if (noerr) */
|
||
|
||
} else noerr = FALSE; /* Device not found? */
|
||
|
||
/* Finished. Unlock the device table and quit */
|
||
(void) unlkdevtab();
|
||
return(noerr);
|
||
}
|
||
|
||
/*
|
||
* int _rmdevtabrec(device)
|
||
* char *device
|
||
*
|
||
* This function removes the record in the device table for the specified
|
||
* device.
|
||
*
|
||
* Arguments:
|
||
* device The device (alias, cdevice, bdevice, pathname, or link to one)
|
||
* whose entry is to be removed
|
||
*
|
||
* Returns: int
|
||
* Success indicator: TRUE if successful, FALSE with errno set otherwise.
|
||
*/
|
||
|
||
int
|
||
_rmdevtabrec(device)
|
||
char *device; /* Device to remove */
|
||
{
|
||
struct devtabent *rment;
|
||
struct devtabent *devtabent;
|
||
char *tempname;
|
||
FILE *fd;
|
||
int noerr;
|
||
|
||
if (!lkdevtab("r", F_WRLCK)) return(FALSE);
|
||
noerr = TRUE;
|
||
if (rment = _getdevrec(device)) {
|
||
if (fd = opennewdevtab(&tempname)) {
|
||
_setdevtab();
|
||
while ((devtabent = _getdevtabent()) && noerr) {
|
||
if (devtabent->entryno != rment->entryno)
|
||
noerr = _putdevtabrec(fd, devtabent) != EOF;
|
||
_freedevtabent(devtabent);
|
||
}
|
||
if (noerr) {
|
||
(void) fclose(fd);
|
||
noerr = mknewdevtab(tempname);
|
||
} else {
|
||
(void) fclose(fd);
|
||
(void) rmnewdevtab(tempname);
|
||
}
|
||
} else noerr = FALSE;
|
||
_freedevtabent(rment);
|
||
} else noerr = FALSE;
|
||
(void) unlkdevtab();
|
||
return(noerr);
|
||
}
|
||
|
||
/*
|
||
* int _rmdevtabattrs(device, attributes, notfounds)
|
||
* char *device
|
||
* char **attributes
|
||
* char ***notfounds
|
||
*
|
||
* Remove the specified attributes from the specified device. The
|
||
* device is specified by <device>, <attributes> is the address of
|
||
* the first char * in the list of char * pointing to the attributes
|
||
* to remove from the device, and <notfounds> is the address of a
|
||
* char ** to put the address of the first element in the malloc()ed
|
||
* list of (char *) pointing to requested attributes that were not
|
||
* defined for the device <device>.
|
||
*
|
||
* Arguments:
|
||
* device The device from which attributes are to be removed
|
||
* attributes The address of the first element in the list of
|
||
* attributes to remove. This list is terminated by
|
||
* (char *) NULL.
|
||
* notfounds The place to put the address of the list of addresses
|
||
* referencing the requested attributes that are not
|
||
* defined for the specified device.
|
||
*
|
||
* Returns: int
|
||
* TRUE if successful, FALSE with errno set otherwise.
|
||
*
|
||
* Notes:
|
||
* - "alias" may not be undefined
|
||
* - "cdevice", "bdevice", and "pathname" are made "null", not really
|
||
* undefined
|
||
*/
|
||
|
||
int
|
||
_rmdevtabattrs(device, attributes, notfounds)
|
||
char *device; /* Device to modify */
|
||
char **attributes; /* Attributes to remove */
|
||
char ***notfounds; /* Attributes req'd but not found */
|
||
{
|
||
/* Automatics */
|
||
char **pnxt; /* Ptr to next attribute */
|
||
char **pp; /* Ptr to current attr name */
|
||
struct devtabent *modent; /* Entry being modified */
|
||
struct devtabent *devtabent; /* Entry being copied */
|
||
struct attrval *attrval; /* Ptr to attr/val desc */
|
||
struct attrval *prevattrval; /* Ptr to prev attr/val */
|
||
FILE *fd; /* File desc, temp file */
|
||
char *tempname; /* Name of temp file */
|
||
int nattrs; /* Number of attrs to remove */
|
||
int nobaderr; /* TRUE if no fatal error */
|
||
int noerr; /* TRUE if no non-fatal error */
|
||
int found; /* TRUE if attribute found */
|
||
int nonotfounds; /* TRUE if no attrs not fount */
|
||
|
||
|
||
/* Initializations */
|
||
nobaderr = TRUE;
|
||
noerr = TRUE;
|
||
|
||
/* Count attributes to remove -- make sure "alias" isn't specified */
|
||
for (pp = attributes, nattrs = 0 ; *pp ; pp++, nattrs++)
|
||
if (strcmp(*pp, DTAB_ALIAS) == 0) {
|
||
*notfounds = (char **) NULL;
|
||
errno = EINVAL;
|
||
return(FALSE);
|
||
}
|
||
|
||
/* Lock the device table */
|
||
if (!lkdevtab("r", F_WRLCK)) return(FALSE);
|
||
|
||
/* Is there a record for the requested device? */
|
||
if (modent = _getdevrec(device)) {
|
||
|
||
/* Record found. Try to modify it */
|
||
nonotfounds = TRUE;
|
||
|
||
/* For each of the attributes in the attribute list ... */
|
||
for (pp = attributes ; nobaderr && *pp ; pp++) {
|
||
|
||
/*
|
||
* Modify the device description, removing the requested
|
||
* attributes from the structure
|
||
*/
|
||
|
||
found = FALSE; /* Not found yet */
|
||
|
||
/* If it's the "cdevice" attribute, make it a null-string */
|
||
if (strcmp(*pp, DTAB_CDEVICE) == 0) {
|
||
if (modent->cdevice) {
|
||
free(modent->cdevice);
|
||
modent->cdevice = (char *) NULL;
|
||
}
|
||
found = TRUE;
|
||
}
|
||
|
||
/* If it's the "bdevice" attribute, make it a null-string */
|
||
else if (strcmp(*pp, DTAB_BDEVICE) == 0) {
|
||
if (modent->bdevice) {
|
||
free(modent->bdevice);
|
||
modent->bdevice = (char *) NULL;
|
||
}
|
||
found = TRUE;
|
||
}
|
||
|
||
/* If it's the "pathname" attribute, make it a null-string */
|
||
else if (strcmp(*pp, DTAB_PATHNAME) == 0) {
|
||
if (modent->pathname) {
|
||
free(modent->pathname);
|
||
modent->pathname = (char *) NULL;
|
||
}
|
||
found = TRUE;
|
||
}
|
||
|
||
/* Must be one of the other "auxilliary" attributes */
|
||
else {
|
||
|
||
/* Search the attribute list for the attribute */
|
||
prevattrval = (struct attrval *) NULL;
|
||
if (attrval = modent->attrlist) do {
|
||
if (strcmp(*pp, attrval->attr) == 0) {
|
||
|
||
/* Found. Remove from attribute list */
|
||
found = TRUE;
|
||
free(attrval->attr);
|
||
free(attrval->val);
|
||
if (prevattrval) {
|
||
prevattrval->next = attrval->next;
|
||
free((char *) attrval);
|
||
attrval = prevattrval->next;
|
||
} else {
|
||
modent->attrlist = attrval->next;
|
||
free((char *) attrval);
|
||
attrval = modent->attrlist;
|
||
}
|
||
} else {
|
||
prevattrval = attrval; /* Advance to next */
|
||
attrval = attrval->next;
|
||
}
|
||
} while (!found && attrval);
|
||
|
||
} /* End attribute search loop */
|
||
|
||
/* If the requested attribute wasn't defined for the device,
|
||
put it in the list of attributes not found */
|
||
|
||
if (!found) {
|
||
|
||
/* If there's no list (yet), alloc enough space for
|
||
the list */
|
||
|
||
if (nonotfounds)
|
||
if (*notfounds = (char **) malloc(sizeof(char **)*(nattrs+1))) {
|
||
|
||
/* List allocated -- put in the first entry */
|
||
nonotfounds = FALSE;
|
||
pnxt = *notfounds;
|
||
if (*pnxt = (char *) malloc(strlen(*pp)+1)) {
|
||
errno = EINVAL;
|
||
noerr = FALSE;
|
||
(void) strcpy(*pnxt++, *pp);
|
||
} else {
|
||
/* malloc() failed, free list */
|
||
free(*notfounds);
|
||
*notfounds = (char **) NULL;
|
||
nonotfounds = TRUE;
|
||
nobaderr = FALSE;
|
||
}
|
||
|
||
} else nobaderr = FALSE; /* malloc() failed */
|
||
|
||
else {
|
||
/* Already a list, add this attribute to it */
|
||
if (*pnxt = (char *) malloc(strlen(*pp)+1))
|
||
(void) strcpy(*pnxt++, *pp);
|
||
else {
|
||
/* Out of memory, clean up */
|
||
for (pnxt = *notfounds ; *pnxt ; pnxt++)
|
||
free(*pnxt);
|
||
free(*notfounds);
|
||
*notfounds = (char **) NULL;
|
||
nonotfounds = TRUE;
|
||
nobaderr = FALSE;
|
||
}
|
||
}
|
||
|
||
} /* end if (!found) */
|
||
|
||
/* Terminate the not-found list */
|
||
if (!nonotfounds) *pnxt = (char *) NULL;
|
||
|
||
} /* end (for each attribute in attribute list) loop */
|
||
|
||
|
||
/*
|
||
* If we haven't seen any problems so far,
|
||
* write the new device table
|
||
*/
|
||
|
||
if (nobaderr) {
|
||
|
||
/* Open the new device table */
|
||
if (fd = opennewdevtab(&tempname)) {
|
||
|
||
/*
|
||
* For each entry in the existing table, write that entry
|
||
* to the new table. If the entry is the one being
|
||
* modified, write the modified entry instead of the
|
||
* original entry.
|
||
*/
|
||
|
||
_setdevtab(); /* Rewind existing table */
|
||
while ((devtabent = _getdevtabent()) && nobaderr) {
|
||
if (devtabent->entryno != modent->entryno)
|
||
nobaderr = _putdevtabrec(fd, devtabent) != EOF;
|
||
else nobaderr = _putdevtabrec(fd, modent) != EOF;
|
||
_freedevtabent(devtabent);
|
||
}
|
||
|
||
/*
|
||
* If we successfully generated the new table, make it the
|
||
* new system device table. Otherwise, just remove the
|
||
* temporary file we've created.
|
||
*/
|
||
|
||
if (nobaderr) {
|
||
(void) fclose(fd);
|
||
nobaderr = mknewdevtab(tempname);
|
||
} else {
|
||
(void) fclose(fd);
|
||
(void) rmnewdevtab(tempname);
|
||
}
|
||
|
||
} /* if (_opennewdevtab()) */
|
||
else nobaderr = FALSE;
|
||
|
||
/* If there was some error, we need to clean up
|
||
allocated resources */
|
||
if (!nobaderr && !nonotfounds) {
|
||
for (pnxt = *notfounds ; *pnxt ; pnxt++)
|
||
free(*pnxt);
|
||
free(*notfounds);
|
||
*notfounds = (char **) NULL;
|
||
nonotfounds = TRUE;
|
||
}
|
||
|
||
} /* if (nobaderr) */
|
||
|
||
/* Free the resources alloc'ed for <device>'s entry */
|
||
_freedevtabent(modent);
|
||
|
||
} else {
|
||
/* _getdevrec(device) failed */
|
||
nobaderr = FALSE;
|
||
*notfounds = (char **) NULL;
|
||
}
|
||
|
||
/* Unlock the device table */
|
||
(void) unlkdevtab();
|
||
|
||
/* We're finished */
|
||
return(noerr && nobaderr);
|
||
}
|