/*
* 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-1997, by Sun Microsystems, Inc.
* All Rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
*/
/* 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
* <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 <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <devmgmt.h>
#include <unistd.h>
#include <stdlib.h>
#include "devtab.h"
/*
* 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)
*/
/*
* 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(char *, char *);
static int lkdevtab(char *, short);
static int unlkdevtab(void);
static struct devtabent *mkdevtabent(char *, char **);
static FILE *opennewdevtab(char **);
static int mknewdevtab(char *);
static int rmnewdevtab(char *);
/*
* 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 *
char *p, /* Place to write to */
char *q) /* Thing to write */
{
while (*q) {
*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 *
{
char *p; /* Ptr to last '/' in devtab name */
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.
*/
return (NULL);
return (NULL);
}
*(p+1) = '\0';
} else dirname = "./";
/*
* 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.
*/
} else {
}
}
/*
*
* Free the space containing the device table's name.
*/
}
/* 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
{
/* Unlink the file */
/* Free the space allocated to the filename */
/* 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
{
/* 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 */
/* Remove the temp file (and resources) */
/* Free the device table's name */
/* Finished. Return success indicator */
return (noerr);
}
/*
* static int lkdevtab(o_mode, lktype)
* char *o_mode
* short 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
char *o_mode, /* Open mode */
short lktype) /* Lock type */
{
/* Automatic data */
/* Close the device table (if it's open) */
_enddevtab();
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 */
/* Keep on going until we lock the file or an error happens */
!noerr) {
else {
/* Reopen the file (maybe it's moved?) */
_enddevtab();
}
}
/* Done */
return (noerr);
}
/*
* int unlkdevtab()
*
* Unlock the locked device table.
*
* Arguments: None
*
* Returns: int
* Whatever fcntl() returns...
*/
static int
unlkdevtab(void)
{
/* Automatic data */
/* Build the locking structure */
/* Unlock it */
_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 *
char *alias, /* Alias of entry */
char **attrlist) /* Attributes of new entry */
{
/* Automatic data */
/* No problems (yet) */
/* Get space for the structure */
/* Fill in default values */
/* Add attributes to the structure */
prevattrval = NULL;
/* Valid attr=value pair? */
/* Get space for the value */
/* Get space for attribute name */
/* Specifying the alias? If so, ERROR */
}
/* Specifying the char device path? */
if (val[0] != '/') {
} else {
}
} else {
}
}
/* Specifying the block device path? */
if (val[0] != '/') {
} else {
}
} else {
}
}
/* Specifying the pathname (generic)? */
if (val[0] != '/') {
} else {
}
} else {
}
}
/* Some other attribute */
else {
do {
name) == 0) {
}
if (attrval =
/*
* Link into the list of attributes
*/
if (prevattrval)
} else {
/* malloc() for attrval failed */
}
}
} /* End else (some other attribute) */
} else { /* malloc() for attribute name failed */
}
/* If we saw an error, free structure, returning NULL */
if (!noerr) {
}
} /* Ignore invalid attr=val pair */
} /* End attribute processing loop */
} else { /* malloc() failed */
}
}
/* 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
{
/* Automatic Data */
char *p; /* Temp char pointer */
/* Comment or data record? */
/*
* Record is a comment
*/
/* Copy (escaping chars) record into temp buffer */
/* Alloc space */
*(p-2) = '\n'; /* Unescape last \n */
*(p-1) = '\0'; /* Terminate string */
/* Write the record */
}
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)
*/
/* val & '="" ' or val & '=""\n' */
}
else size++; /* Else make room for trailing '\n' */
/* Alloc space for "escaped" record */
/* Initializations */
p = buf;
/* Write the alias ("alias" attribute) */
*p++ = ':';
/* Write the character device ("cdevice" attribute) */
*p++ = ':';
/* Write the block device ("bdevice" attribute) */
*p++ = ':';
/* Write the pathname ("pathname" attribute) */
*p++ = ':';
/* Write the rest of the attributes */
do {
*p++ = '=';
*p++ = '"';
*p++ = '"';
*p++ = ' ';
} while (attrval);
/* Terminate the record */
*p++ = '\n';
*p = '\0';
/* Write the record */
}
/* 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
char *alias, /* Alias to add to the device table */
char **attrval) /* Attributes for that device */
{
/* Automatic data */
/* Validate the device alias. Error (EINVAL) if it's not valid */
if (!_validalias(alias)) {
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.
*/
return (FALSE);
/* Make sure that the alias isn't already in the table */
/* The alias is already in the table */
/* The alias wasn't in the table or there wasn't a table. */
/* Build a struct devtabent that describes the new alias */
/* Position to the end of the existing table */
/* Write the new entry */
/* Free the info we just wrote */
/* 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
* the attributes that are to change
*
* Returns: int
* TRUE if all went well, FALSE with errno set otherwise
*/
int
char *device, /* Device to modify */
char **attrval) /* Attributes to add or change */
{
/* Automatic data */
/* Lock the device table */
return (FALSE);
/* No problems (so far) */
/* Get the entry to modify */
/* Build a structure describing the changes */
/* If the "cdevice" field is specified, change it */
}
/* If the "bdevice" field is specified, change it */
}
/* If the "pathname" field is specified, change it */
}
/* Change the other attributes (if any) */
}
} /* 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) {
/*
* device's list of attributes
*/
} else {
/* Attribute changed, bump to the next one */
}
} while (new); /* Loop for each attr to add or modify */
} else {
/* Device had no attributes -- add entire list */
}
/* Free the structure containing the changes */
/* If there hasn't been an error (so far), write the new record */
if (noerr) {
/* Open the new device table */
/*
* 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 */
}
/*
* 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) {
} else {
(void) rmnewdevtab(tname);
}
/* Free the changed device structure */
} /* if (_opennewdevtab()) */
/* 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
{
char *tempname;
int noerr;
return (FALSE);
_setdevtab();
}
if (noerr) {
} else {
(void) rmnewdevtab(tempname);
}
(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
char *device, /* Device to modify */
char **attributes, /* Attributes to remove */
char ***notfounds) /* Attributes req'd but not found */
{
/* Automatics */
/* Initializations */
/* Count attributes to remove -- make sure "alias" isn't specified */
return (FALSE);
}
/* Lock the device table */
return (FALSE);
/* Is there a record for the requested device? */
/* Record found. Try to modify it */
nonotfounds = TRUE;
/* For each of the attributes in the attribute list ... */
/*
* Modify the device description, removing the requested
* attributes from the structure
*/
/* If it's the "cdevice" attribute, make it a null-string */
}
}
/* If it's the "bdevice" attribute, make it a null-string */
}
}
/* If it's the "pathname" attribute, make it a null-string */
}
}
/* Must be one of the other "auxilliary" attributes */
else {
/* Search the attribute list for the attribute */
prevattrval = NULL;
/* Found. Remove from attribute list */
if (prevattrval) {
} else {
}
} else {
}
} /* 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)
/* List allocated -- put in the first entry */
nonotfounds = FALSE;
} else {
/* malloc() failed, free list */
nonotfounds = TRUE;
}
else {
/* Already a list, add this attribute to it */
else {
/* Out of memory, clean up */
nonotfounds = TRUE;
}
}
} /* end if (!found) */
/* Terminate the not-found list */
} /* 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 */
/*
* 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 */
nobaderr) {
}
/*
* 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) {
} else {
(void) rmnewdevtab(tempname);
}
} /* if (_opennewdevtab()) */
/*
* If there was some error, we need to clean up
* allocated resources
*/
if (!nobaderr && !nonotfounds) {
nonotfounds = TRUE;
}
} /* if (nobaderr) */
/* Free the resources alloc'ed for <device>'s entry */
} else {
/* _getdevrec(device) failed */
}
/* Unlock the device table */
(void) unlkdevtab();
/* We're finished */
}