/*
* 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) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 1997, by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*LINTLIBRARY*/
/*
* Globals defined:
*
* devreserv() Reserve a set of OA&M devices
* devfree() Free a reserved device
* reservdev() Get a list of reserved devices
* _openlkfile() Opens the lock file
* _rsvtabpath() Get the pathname of the lock table file
* _closelkfile() Closes the lock file
*/
/*
* Headers referenced:
* <errno.h> Error definitions (including "errno")
* <string.h> String handling definitions
* <fcntl.h> File control definitions
* <unistd.h> Unix standard value definitions
* <devmgmt.h> Global Device Management definitions
* "devtab.h" Local Device Management definitions
*/
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <devmgmt.h>
#include "devtab.h"
/*
* Local Definitions:
*/
/*
* Local data types:
* struct devlks Structure that defines locking information (key
* with alias name (may be '\0' terminated)
*/
struct devlks {
int lk_key;
};
/*
* Local Functions:
* isanullstr() Is a character string a null string ("")?
* getlkcnt() Get the number of devices locked
* locklkfile() Lock the OA&M Device locking file
* getlocks() Get the device locks from the device-lock file
* islocked() Determines if a device is locked
* putlocks() Close the device locks w/ update
* freelkfile() Close the device locks w/o updating
* compresslks() Compresses the table containing lock info
*/
static int locklkfile(short); /* Lock the lock file */
static int getlkcnt(void); /* Get the number of locked devices */
static int getlocks(void); /* Get the lock information */
static int putlocks(char **, int); /* Update lock information */
static int freelkfile(void); /* Free lock information (no update) */
static char *islocked(char *); /* Determines if a device is locked */
/*
* Static data
*/
static int lockcount;
/*
* char *_rsvtabpath()
*
* Determines the pathname of the device reservation table file
*
* Uses the following sequential steps:
* 1) If OAM_DEVLKFILE is defined and is not null, use that as
* the pathname to the file
* 2) Otherwise, use the devault name found in DVLK_PATH (defined
* in the header file <devtab.h>
*
* Arguments: None
*
* Returns: char *
* A pointer to the filename in malloc()ed memory or (char *) NULL if
* it fails. "errno" will indicate the error if it fails.
*/
char *
_rsvtabpath(void)
{
/* Automatics */
#ifdef DEBUG
char *p; /* Temporary pointer */
#endif
#ifdef DEBUG
p = getenv(OAM_DEVLKTAB);
if ((p != NULL) && (*p != '\0')) {
} else {
#endif
#ifdef DEBUG
}
#endif
/* Fini -- return a pointer to the lockfile pathname */
return (lockname);
}
/*
* int _openlkfile()
*
* The _openlkfile() function opens a device-reservation table file
*
* Arguments: None
*
* Returns: int
* TRUE if successful, FALSE otherwise.
*
* Statics Used:
* lkfilefd Lock file file descriptor
*/
int
_openlkfile(void)
{
/*
* Automatic data
*/
/* Close the lockfile -- it might be open */
(void) _closelkfile();
/* If we can get the name of the lock file ... */
if (lockname = _rsvtabpath()) {
/* Open it */
}
/* Finis */
}
/*
* int _closelkfile()
*
* Function closes the device-reservation table file and sets the
* necessary external variables to indicate such.
*
* Arguments: None
*
* Returns: int
* Same as close()
*
* Statics referenced:
* lkfilefd The device reservation table file's file descriptor
*/
int
_closelkfile(void)
{
/* Automatics */
/* Close the lock file if it's open */
else rtnval = 0;
/* Indicate that the lock-file is closed */
lkfilefd = -1;
/* Finis */
return (rtnval);
}
/*
* int locklkfile(lkflag)
* short lkflag
*
* This function locks the device lock file. If the request cannot
* be serviced, it keeps on trying until it manages to lock the file
* or it encounters an error.
*
* Arguments:
* lkflag Flag (from FCNTL(BA_OS)) indicating which type
* of lock is being requested. Values that make
* sense:
* F_RDLCK: Read lock.
* F_WRLCK: Write lock.
*
* Returns: int
* TRUE (non-zero) if the function managed to lock the file, FALSE
* otherwise ("errno" will indicate the problem).
*
* Statics used:
* int lkfilefd File descriptor of the open lock file
* struct flock lkinfo Structure used by fcntl() to lock a file
*/
static int
{
/* Automatic data */
/* Set up the locking structure */
/* Try to lock the file. If it's locked, wait and try again */
else {
}
}
/* Return a success flag */
return (locked);
}
/*
* int getlkcnt()
*
* This function extracts the number of currently-locked devices
* from the lock file.
*
* Arguments: None
*
* Returns: int
* The number of devices locked or -1 if an error occurred.
*
* Statics used:
* lkfilefd File descriptor of the open lockfile
*
* Assumptions:
* - The file is positioned to the beginning-of-file
*/
static int
getlkcnt(void)
{
/* Automatics */
/* Get the lock count from the file */
/* If there wasn't one, set to 0. If error, set to -1 */
if (cntread != (int)sizeof (int))
/* Return the lock count */
return (lkcnt);
}
/*
* int readlocks()
*
* The readlocks() function reads the reserved-device list from
* the reserved-device file (which has already been opened)
*
* Arguments: None
*
* Returns: int
* TRUE if all went well, FALSE otherwise.
*
* Statics Used:
* lockcount Sets this to the number of locks in the lock list
* locklist Sets this to the malloc()ed space containing the
* list of reserved devices.
* lkfilefd Reads data from this file
*/
static int
readlocks(void)
{
/* Automatics */
/* Initializations */
/* Get the number of devices currently locked */
/* Allocate space for the locks */
/* Read the locks into the malloc()ed buffer */
/* If the read failed, free malloc()ed buffer */
/* Finished */
if (noerror)
return (noerror);
}
/*
* int getlocks()
*
* getlocks() extracts the list of locked devices from the file
* containing that information. It returns the number of locked
* devices. If there are any locked devices, it allocates a buffer
* for the locked file information, saves that buffer address in
* the allocated buffer. Also, the device lock file is open and
* locked if the function is successful.
*
* Arguments: None
*
* Returns: int
* TRUE if successful, FALSE otherwise. "errno" will reflect the
* error if the function returns FALSE.
*
* Static data referenced:
* int lkfilefd File descriptor of the lock file
*/
static int
getlocks(void)
{
/* Automatic data */
/* Initializations */
/* Open the lock file */
if (_openlkfile()) {
/* Lock the lock file */
if (locklkfile(F_WRLCK)) {
/* Get the number of devices currently locked */
/* If something happened, unlock the file */
if (!noerror) (void) freelkfile();
/* If something happened, close the lock file */
if (!noerror)
(void) _closelkfile();
/* Done */
return (noerror);
}
/*
* int writelks(tblcnt)
* int tblcnt
*
* writelks() writes the lock information to the lock file. Lock
* information includes the number of locks (to be) in the table.
* Note that functions may still be appending new locks after this
* call...
*
* Arguments:
* tblcnt Number of locks in the lock table
*
* Returns:
* TRUE if successful, FALSE otherwise with "errno" containing an
* indication of the error.
*
* Statics Used:
* lockcount Number of locks to exist
* locklist Table of locks (may not include new ones)
* lkfilefd File descriptor of the lock file
*
* Notes:
* - The number of locks that are going to be in the lock file
* is in the static variable "lockcount". <tblcnt> indicates
* the number of entries in the lock table.
*/
static int
{
/* Automatic data */
/* Initializations */
/* Rewind the OA&M Device Lock File */
/* Write the number of locks that will (eventually) exist */
/* Write the table as we currently know it */
if (tblsz)
/* Return an indicator of our success */
return (noerr);
}
/*
* int appendlk(key, alias)
* int key
* char *alias
*
* Write device locking information to the device locking file.
*
* Arguments:
* key Key the device is being locked on
* alias The device alias being locked
*
* Returns: int
* TRUE if we successfully appended a lock to the lock file,
* FALSE with "errno" set otherwise.
*
* Static data used:
* lkfilefd The open file descriptor for the open device
* locking file
*/
static int
int key, /* Lock key */
char *alias) /* Alias to lock */
{
/* Automatic data */
/* Set up the data to write */
/* Write the data, returning an indicator of our success */
}
/*
* int compresslks()
*
* This function compresses the lock table, squeezing out the empty
* lock entries.
*
* Arguments: none
*
* Returns: int
* The number of non-empty entries in the table. They will be the
* first 'n' entries in the table after compression.
*
* Statics Used
* lockcount Number of locks in the device lock list
* locklist The device lock list
*/
static int
compresslks(void)
{
/* Automatics */
struct devlks *p; /* Running pointer to locks */
int i; /* Temporary counter */
/* Initializations */
p = locklist;
/* Loop through the lock list squeezing out unused slots */
for (i = 0; i < lockcount; i++) {
/* If we've found an empty slot ... */
if (isanullstr(p->lk_alias)) {
/*
* If we've an empty slot to move to, just decrement
* count of used slots. Otherwise, make it the next
* available slot
*/
nlocks--;
}
else if (avail) {
/*
* If we found a slot in use and there's an
* available slot, move this one there
*/
avail++;
}
/* Next, please */
p++;
}
return (nlocks);
}
/*
* int freelkfile()
*
* This function unlocks the OA&M device locking file.
*
* Arguments: None
*
* Returns: int
* TRUE if it successfully unlocked the file, FALSE otherwise
* with "errno" set to indicate the problem.
*
* Statics Used:
* lkinfo File-locking structure
* lkfilefd File-descriptor of the open lock file
*/
static int
freelkfile(void)
{
/* Automatic data */
/* Set the action to "unlock" */
/* Unlock the file */
/* Return an indication of our success */
return (noerr);
}
/*
* int putlocks(newlist, key)
* char **newlist
* int key
*
* This function updates the file containing OA&M device locks.
*
* Arguments:
* newlist The address of the list of addresses of device
* aliases to add to the list of locked devices
* key The key on which to lock the devices
*
* Returns: int
* TRUE if all went well, FALSE otherwise with "errno" set to an
* error code that indicates the problem.
*
* Statics Used:
* lockcount Number of locks in the locked device structure
* locklist Locked device structure
*/
static int
char **newlist, /* New devices to lock */
int key) /* Key we're locking stuff on */
{
/* Automatic data */
/*
* Look through the existing lock list, looking for holes we can
* use for the newly locked devices
*/
lkndx = 0;
}
lkndx++;
plk++;
}
/*
* Update the locks file (algorithm depends on whether we're adding
* new locks or not. May be replacing old locks!)
*/
if (*pp) {
/*
* Need to expand the locks file
* - Remember the old lock count (in existing lock buffer)
* - Count the number of new locks we need to add
* - Write out the old locks structure
* - Append locks for the newly added locks
*/
} else {
/*
* Don't need to expand the locks file. Compress the locks
* then write out the locks information
*/
lockcount = compresslks();
}
/* Done. Return an indication of our success */
return (noerr);
}
/*
* char *islocked(device)
* char *device
*
* This function checks a device to see if it is locked. If it is
* not locked, it returns the device alias.
*
* A device is not locked if the device's alias does not appear in
* the device locks table, or the key on which the device was locked
* is no longer active.
*
* Argumetns:
* char *device The device to be reserved. This can be
* a pathname to the device or a device
* alias.
*
* Returns: char *
* Returns a pointer to the device alias if it's not locked, or
* (char *) NULL if it's locked or some error occurred.
*
* Static data used:
* struct devlks *locklist Pointer to the list of device locks
* int lockcount The number of devices that are locked
*/
static char *
{
/* Automatic data */
int i; /* Temp counter */
/* Get the device's alias */
/*
* Look through the device locks to see if this device alias
* is locked
*/
else plk++;
}
if (locked) {
}
} /* devattr() failed, no such device? */
/* Return pointer to the device */
return (alias);
}
/*
* int unreserv(key, device)
* int key
* char *device
*
* This function removes a device reservation.
*
* Arguments:
* int key The key on which the device was allocated
* char *device The device to be freed.
*
* Returns: int
* TRUE if successful, FALSE otherwise with "errno" set.
*
* Explicit "errno" settings:
* (This follows the "signal()" model which gives one the ability
* to determine if a device is allocated without having the
* permission to free it.)
*
* EINVAL The device specified was not locked
* EPERM The device specified was locked but not on the
* specified key
*
* Static data used:
* locklist List of locked devices
* lockcount Number of entries in the locked-device list
*/
int
{
/* Automatics */
int i; /* Counter of locks */
/* Initializations */
/*
* Get the device alias. If none can be found, try to free
* whatever it is that was given to us (the possibility exists
* that the device has been removed from the device table since
* it was reserved, so the device not being in the table shouldn't
* pose too much of a problem with us...)
*/
else {
}
/* Loop through the locked-device list looking for what we've got... */
else plk++;
}
/* Free the alias string (if any), we don't need it anymore */
/* If the device is locked ... */
if (locked) {
/*
* If it's locked on the key we've been given, free it.
* Otherwise, don't free it and set errno to EPERM
*/
} else {
}
} else {
/* The device isn't locked. Set errno to EINVAL */
}
/* Finished. Return an indication of our success */
return (noerr);
}
/*
* char **devreserv(key, rsvlst)
* int key
* char **rsvlist[]
*
* The devreserv() function reserves devices known to the OA&M Device
* Management family of functions. Once a device is reserved, it can't
* be reserved by another until it is freed or the process with the
* "key" is no longer active. It returns a list aliases of the devices
* it allocated.
*
* The function attempts to reserve a single device from each of the
* lists. It scans each list sequentially until it was able to
* reserve a requested device. If it successfully reserved a device
* from each of the lists, it updates the device-locked file and
* returns those aliases to the caller. If it fails, it allocates
* nothing and returns (char **) NULL to the caller. "errno"
* indicates the error.
*
* Arguments:
* int key The key on which this device is being reserved.
*
* char **rsvlist[] The address of the list of addresses of lists
* of pointers to the devices to allocate.
*
* Returns: char **
* A pointer to malloc()ed space containing pointers to the aliases
* of the reserved devices. The aliases are in malloc()ed space also.
* The list is terminated by the value (char *) NULL.
*
* Static Data Used:
* None directly, but functions called share hidden information
* that really isn't of concern to devreserv().
*/
char **
int key, /* Key to reserve device on */
char **rsvlst[]) /* List of lists of devs to reserve */
{
;
if (getlocks()) {
/* Go through the lists of devices we're to reserve */
/* Try to reserve a device from each list */
/*
* Check the next device in the list. If islocked()
* returns that device's alias, it's ours to have
*/
} else {
}
} else {
else {
}
}
}
/*
* If no device from the list could be reserved,
* we've failed
*/
}
} /* End of loop through lists loop */
/*
* If all went well, update lock file.
* Then, free locks
*/
if (noerr) {
}
/* Free resources */
if (!noerr)
if (!noerr) {
}
/* Return list or an indication of an error */
}
/*
* int devfree(key, device)
* int key
* char *device
*
* This function unreserves (frees) the given device. It returns
* an indication of success with "errno" containing information about
* a failure.
*
* Arguments:
* int key The key that the device is locked on
* char *device The device (alias, pathname to, etc.) to be freed.
*
* Returns: int
* 0 if successful, -1 with "errno" set if fails.
*/
int
int key, /* Key device is locked on */
char *device) /* Device to free */
{
/* Automatics */
int noerr;
/* Initializations */
/* Get the locks, locking the lock file */
if (getlocks()) {
/* Attempt to unreserve the device */
/*
* Successful. Compress the lock structure and
* write the new locks
*/
lockcount = compresslks();
/* Unlock and close the locks file */
/* Return 0 if successful, something else otherwise */
return (noerr? 0 : -1);
}
/*
* struct reservdev **reservdev()
*
* This function returns the list of reserved devices
* along with the key on which those devices were locked.
*
* Arguments: None.
*
* Returns: struct reservdev **
* Pointer to the list of pointers to structures describing
* the reserved devices, or (struct reservdev **) NULL if an
* error occurred. The list of pointers is terminated by
* (struct reservdev *) NULL.
*
* Statics Used:
* locklist List of reserved devices
* lockcount Number of items in the reserved-devices list
*/
struct reservdev **
reservdev(void)
{
/* Automatics */
struct devlks *p; /* Running ptr, locklist */
struct reservdev **q; /* Running ptr, rtnlist */
char *r; /* Temp ptr to char */
int i; /* Lock counter */
/* Initializations */
/* Open the lock file ... */
if (_openlkfile()) {
/* Put a read-lock on the lock-file ... */
if (locklkfile(F_RDLCK)) {
/* Read the locks ... */
if (readlocks()) {
/* Alloc space for the return list */
/* Build the return list from the lock list */
p = locklist;
q = rtnlist;
p++;
q++;
}
/*
* If no error, terminate the list. Otherwise, free
* the space we've allocated
*/
else {
for (q = rtnlist; *q; q++) {
free(*q);
}
}
/* Free the lock file */
(void) freelkfile();
/* Close the lock file */
(void) _closelkfile();
/* Return ptr to list of locks or NULL if an error has occurred */
}