summaryrefslogtreecommitdiff
path: root/usr/src/lib/libadm/common/devreserv.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libadm/common/devreserv.c')
-rw-r--r--usr/src/lib/libadm/common/devreserv.c1162
1 files changed, 1162 insertions, 0 deletions
diff --git a/usr/src/lib/libadm/common/devreserv.c b/usr/src/lib/libadm/common/devreserv.c
new file mode 100644
index 0000000000..ed9c5735d1
--- /dev/null
+++ b/usr/src/lib/libadm/common/devreserv.c
@@ -0,0 +1,1162 @@
+/*
+ * 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) 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:
+ * <sys/types.h> System data types
+ * <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 <sys/types.h>
+#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;
+ char lk_alias[((DTAB_MXALIASLN+2)/2)*2];
+};
+
+
+/*
+ * 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
+ */
+
+#define isanullstr(s) (s[0] == '\0')
+
+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 struct flock lkinfo = {0, 0, 0, 0, 0};
+static struct devlks *locklist;
+static int lockcount;
+static int lkfilefd = -1;
+
+/*
+ * 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 */
+ char *lockname; /* Name of the lockfile */
+#ifdef DEBUG
+ char *p; /* Temporary pointer */
+#endif
+
+#ifdef DEBUG
+ p = getenv(OAM_DEVLKTAB);
+ if ((p != NULL) && (*p != '\0')) {
+ if (lockname = malloc(strlen(p)+1))
+ (void) strcpy(lockname, p);
+ } else {
+#endif
+ if (lockname = malloc(strlen(DVLK_PATH)+1))
+ (void) strcpy(lockname, DVLK_PATH);
+
+#ifdef DEBUG
+ }
+#endif
+
+ /* Fini -- return a pointer to the lockfile pathname */
+ return (lockname);
+}
+
+/*
+ * int _openlkfile()
+ *
+ * The _openlkfile() function opens a device-reservation table file
+ * for read/write access.
+ *
+ * Arguments: None
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise.
+ *
+ * Statics Used:
+ * lkfilefd Lock file file descriptor
+ */
+
+int
+_openlkfile(void)
+{
+ /*
+ * Automatic data
+ */
+
+ char *lockname; /* Name of the lock file */
+
+
+ /* Close the lockfile -- it might be open */
+ (void) _closelkfile();
+
+ /* If we can get the name of the lock file ... */
+ if (lockname = _rsvtabpath()) {
+
+ /* Open it */
+ lkfilefd = open(lockname, O_RDWR|O_CREAT, 0600);
+ free(lockname);
+
+ }
+
+ /* Finis */
+ return ((lkfilefd != -1) ? TRUE : FALSE);
+}
+
+/*
+ * 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 */
+ int rtnval; /* Value to return */
+
+ /* Close the lock file if it's open */
+ if (lkfilefd != -1) rtnval = close(lkfilefd);
+ 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
+locklkfile(short lkflag)
+{
+ /* Automatic data */
+ int noerror; /* TRUE if no error yet */
+ int locked; /* TRUE if the file is locked */
+ int olderrno; /* Value of errno on call */
+
+
+ /* Set up the locking structure */
+ lkinfo.l_type = lkflag;
+
+ /* Try to lock the file. If it's locked, wait and try again */
+ noerror = TRUE;
+ locked = FALSE;
+ olderrno = errno;
+ while (noerror && !locked) {
+ if (fcntl(lkfilefd, F_SETLK, &lkinfo) != -1) locked = TRUE;
+ else {
+ if ((errno == EACCES) || (errno == EAGAIN)) {
+ errno = olderrno;
+ if (sleep(2)) noerror = FALSE;
+ } else noerror = FALSE;
+ }
+ }
+
+ /* 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 */
+ int cntread; /* Number of bytes read */
+ int lkcnt; /* Number of current locks */
+
+ /* Get the lock count from the file */
+ cntread = (int)read(lkfilefd, &lkcnt, sizeof (int));
+
+ /* If there wasn't one, set to 0. If error, set to -1 */
+ if (cntread != (int)sizeof (int))
+ lkcnt = (cntread < 0) ? -1 : 0;
+
+ /* 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 */
+ struct devlks *alloc; /* Ptr to alloc'ed space */
+ int noerror; /* TRUE if all is well */
+ size_t bufsiz; /* # bytes needed for lock data */
+
+
+ /* Initializations */
+ noerror = TRUE;
+
+ /* Get the number of devices currently locked */
+ if ((lockcount = getlkcnt()) > 0) {
+
+ /* Allocate space for the locks */
+ bufsiz = lockcount * sizeof (struct devlks);
+ if (alloc = malloc(bufsiz)) {
+
+ /* Read the locks into the malloc()ed buffer */
+ if (read(lkfilefd, alloc, bufsiz) != (ssize_t)bufsiz)
+ noerror = FALSE;
+
+ /* If the read failed, free malloc()ed buffer */
+ if (!noerror) free(alloc);
+
+ } else noerror = FALSE; /* malloc() failed */
+
+ } else if (lockcount < 0) noerror = FALSE;
+
+ /* Finished */
+ if (noerror)
+ locklist = (lockcount > 0) ? alloc : NULL;
+ 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 */
+ int noerror; /* TRUE if all's well */
+
+
+ /* Initializations */
+ noerror = TRUE;
+
+ /* Open the lock file */
+ if (_openlkfile()) {
+
+ /* Lock the lock file */
+ if (locklkfile(F_WRLCK)) {
+
+ /* Get the number of devices currently locked */
+ if (!readlocks()) noerror = FALSE;
+
+ /* If something happened, unlock the file */
+ if (!noerror) (void) freelkfile();
+
+ } else noerror = FALSE; /* Lock failed */
+
+ /* If something happened, close the lock file */
+ if (!noerror)
+ (void) _closelkfile();
+
+ } else noerror = FALSE; /* Open failed */
+
+ /* 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
+writelks(int tblcnt)
+{
+ /* Automatic data */
+ int noerr; /* FLAG, TRUE if all's well */
+ size_t tblsz; /* Size of the table to write */
+
+ /* Initializations */
+ noerr = TRUE;
+
+ /* Rewind the OA&M Device Lock File */
+ if (lseek(lkfilefd, 0L, 0) >= 0L)
+
+ /* Write the number of locks that will (eventually) exist */
+ if (write(lkfilefd, &lockcount, sizeof (int)) == sizeof (int)) {
+
+ /* Write the table as we currently know it */
+ tblsz = tblcnt * sizeof (struct devlks);
+ if (tblsz)
+ if (!write(lkfilefd, locklist, tblsz) == (ssize_t)tblsz)
+ noerr = FALSE; /* Write of locks failed */
+
+ } else noerr = FALSE; /* write() of count failed */
+
+ else noerr = FALSE; /* Rewind failed */
+
+ /* 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
+appendlk(
+ int key, /* Lock key */
+ char *alias) /* Alias to lock */
+{
+ /* Automatic data */
+ struct devlks lk; /* Structure for writing a lock */
+
+ /* Set up the data to write */
+ lk.lk_key = key;
+ (void) strcpy(lk.lk_alias, alias);
+
+ /* Write the data, returning an indicator of our success */
+ return (write(lkfilefd, &lk,
+ sizeof (struct devlks)) == sizeof (struct devlks));
+}
+
+/*
+ * 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 *avail; /* Pointer to empty slot */
+ struct devlks *p; /* Running pointer to locks */
+ int nlocks; /* Number of locks (up to date) */
+ int i; /* Temporary counter */
+
+ /* Initializations */
+ p = locklist;
+ nlocks = lockcount;
+ avail = NULL;
+
+ /* 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--;
+ if (!avail) avail = p;
+ }
+
+ else if (avail) {
+
+ /*
+ * If we found a slot in use and there's an
+ * available slot, move this one there
+ */
+
+ (void) strcpy(avail->lk_alias, p->lk_alias);
+ avail->lk_key = p->lk_key;
+ 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 */
+ int noerr; /* TRUE if all's well */
+
+ /* Set the action to "unlock" */
+ lkinfo.l_type = F_UNLCK;
+
+ /* Unlock the file */
+ noerr = (fcntl(lkfilefd, F_SETLK, &lkinfo) != -1);
+
+ /* 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
+putlocks(
+ char **newlist, /* New devices to lock */
+ int key) /* Key we're locking stuff on */
+{
+ /* Automatic data */
+ struct devlks *plk; /* Ptr into the locks list */
+ char **pp; /* Pointer into the device list */
+ char **qq; /* Another ptr into the dev list */
+ int lkndx; /* Index into locks list */
+ int noerr; /* TRUE if all's well */
+ int lksintbl; /* Number of locks in the table */
+
+
+ /*
+ * Look through the existing lock list, looking for holes we can
+ * use for the newly locked devices
+ */
+
+ plk = locklist;
+ pp = newlist;
+ lkndx = 0;
+ while (*pp && (lkndx < lockcount)) {
+ if (isanullstr(plk->lk_alias)) {
+ plk->lk_key = key;
+ (void) strcpy(plk->lk_alias, *pp++);
+ }
+ 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
+ */
+
+ lksintbl = lockcount;
+ for (qq = pp; *qq; qq++) lockcount++;
+ noerr = writelks(lksintbl);
+ while (noerr && *pp) noerr = appendlk(key, *pp++);
+ } else {
+
+ /*
+ * Don't need to expand the locks file. Compress the locks
+ * then write out the locks information
+ */
+
+ lockcount = compresslks();
+ noerr = writelks(lockcount);
+ }
+
+ /* 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 *
+islocked(char *device)
+{
+ /* Automatic data */
+ char *alias; /* Alias of "device" */
+ struct devlks *plk; /* Ptr to locking info */
+ int locked; /* TRUE if device in locked list */
+ int i; /* Temp counter */
+
+ /* Get the device's alias */
+ if (alias = devattr(device, DTAB_ALIAS)) {
+
+ /*
+ * Look through the device locks to see if this device alias
+ * is locked
+ */
+
+ locked = FALSE;
+ plk = locklist;
+ for (i = 0; !locked && (i < lockcount); i++) {
+ if (strncmp(alias, plk->lk_alias, DTAB_MXALIASLN) == 0)
+ locked = TRUE;
+ else plk++;
+ }
+
+ if (locked) {
+ free(alias);
+ alias = NULL;
+ errno = EAGAIN;
+ }
+
+ } /* 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
+unreserv(int key, char *device)
+{
+ /* Automatics */
+ char *srchalias; /* Device alias to search table with */
+ char *alias; /* Device's alias (from devattr()) */
+ struct devlks *plk; /* Pointer to a device lock */
+ int locked; /* TRUE if device currently locked */
+ int noerr; /* TRUE if all's well */
+ int olderrno; /* Entry value of "errno" */
+ int i; /* Counter of locks */
+
+
+ /* Initializations */
+ noerr = TRUE;
+
+ /*
+ * 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...)
+ */
+
+ olderrno = errno;
+ if (alias = devattr(device, DTAB_ALIAS)) srchalias = alias;
+ else {
+ errno = olderrno;
+ srchalias = device;
+ }
+
+ /* Loop through the locked-device list looking for what we've got... */
+ locked = FALSE;
+ plk = locklist;
+ for (i = 0; !locked && (i < lockcount); i++) {
+ if (strcmp(srchalias, plk->lk_alias) == 0)
+ locked = TRUE;
+ else plk++;
+ }
+
+ /* Free the alias string (if any), we don't need it anymore */
+ if (alias) free(alias);
+
+ /* 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
+ */
+
+ if (plk->lk_key == key) {
+ plk->lk_alias[0] = '\0';
+ } else {
+ noerr = FALSE;
+ errno = EPERM;
+ }
+ } else {
+
+ /* The device isn't locked. Set errno to EINVAL */
+ noerr = FALSE;
+ errno = 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 **
+devreserv(
+ int key, /* Key to reserve device on */
+ char **rsvlst[]) /* List of lists of devs to reserve */
+{
+ char ***ppp; /* Ptr to current list in rsvlist */
+ char **pp; /* Ptr to current item in list */
+ char **qq; /* Ptr to item in rtnlist */
+ char **rr; /* Ptr to item in aliases */
+ char **aliases; /* List of aliases allocated */
+ char **rtnlist; /* Ptr to buf to return */
+ char *alias; /* Alias of dev to reserve */
+ int noerr; /* TRUE if all's well */
+ int olderrno; /* Old value of errno */
+ int gotone; /* TRUE if unreserved dev found */
+ int foundone; /* Found a valid device in the list */
+ int ndevs; /* # of devs to reserve */
+
+ noerr = TRUE;
+ ppp = rsvlst;
+ olderrno = errno;
+ for (ndevs = 0; *ppp++; ndevs++)
+ ;
+ if (rtnlist = malloc((ndevs+1)*sizeof (char **))) {
+ if (aliases = malloc((ndevs+1)*sizeof (char **))) {
+ if (getlocks()) {
+ qq = rtnlist;
+ rr = aliases;
+
+ /* Go through the lists of devices we're to reserve */
+
+ for (ppp = rsvlst; noerr && *ppp; ppp++) {
+
+ /* Try to reserve a device from each list */
+ gotone = FALSE;
+ foundone = FALSE;
+ for (pp = *ppp; noerr && !gotone && *pp; pp++) {
+
+ /*
+ * Check the next device in the list. If islocked()
+ * returns that device's alias, it's ours to have
+ */
+
+ if (alias = islocked(*pp)) {
+ gotone = TRUE;
+ foundone = TRUE;
+ if (*qq = malloc(strlen(*pp)+1)) {
+ (void) strcpy(*qq++, *pp);
+ *rr++ = alias;
+ } else {
+ *rr = NULL;
+ noerr = FALSE;
+ }
+ } else {
+ if (errno == EAGAIN) {
+ foundone = TRUE;
+ errno = olderrno;
+ } else if (errno == ENODEV) errno = olderrno;
+ else {
+ noerr = FALSE;
+ *rr = NULL;
+ }
+ }
+ }
+
+ /*
+ * If no device from the list could be reserved,
+ * we've failed
+ */
+
+ if (noerr && !gotone) {
+ noerr = FALSE;
+ if (!foundone) errno = ENODEV;
+ else errno = EAGAIN;
+ *qq = NULL;
+ *rr = NULL;
+ }
+
+ } /* End of loop through lists loop */
+
+ /*
+ * If all went well, update lock file.
+ * Then, free locks
+ */
+
+ if (noerr) {
+ *qq = NULL;
+ *rr = NULL;
+ if (!putlocks(aliases, key)) noerr = FALSE;
+ }
+
+ /* Free resources */
+ if (!freelkfile()) noerr = FALSE;
+ if (_closelkfile() != 0) noerr = FALSE;
+ for (qq = aliases; *qq; qq++) free(*qq);
+ if (!noerr)
+ for (pp = rtnlist; *pp; pp++)
+ free(*pp);
+
+ } else noerr = FALSE; /* Error getting locks */
+
+ free(aliases);
+
+ } else noerr = FALSE; /* Malloc() for alias list failed */
+
+ if (!noerr) {
+ free(rtnlist);
+ rtnlist = NULL;
+ }
+
+ } else noerr = FALSE; /* malloc() failed */
+
+ /* Return list or an indication of an error */
+ return (noerr ? rtnlist : NULL);
+}
+
+/*
+ * 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
+devfree(
+ int key, /* Key device is locked on */
+ char *device) /* Device to free */
+{
+ /* Automatics */
+ int noerr;
+
+ /* Initializations */
+ noerr = TRUE;
+
+ /* Get the locks, locking the lock file */
+ if (getlocks()) {
+
+ /* Attempt to unreserve the device */
+ if (unreserv(key, device)) {
+
+ /*
+ * Successful. Compress the lock structure and
+ * write the new locks
+ */
+
+ lockcount = compresslks();
+ if (!writelks(lockcount)) noerr = FALSE;
+
+ } else noerr = FALSE; /* Couldn't unreserve the device */
+
+ /* Unlock and close the locks file */
+ if (!freelkfile()) noerr = FALSE;
+ if (_closelkfile() != 0) noerr = FALSE;
+
+ } else noerr = FALSE;
+
+ /* 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 reservdev **rtnlist; /* Ptr to return list */
+ struct devlks *p; /* Running ptr, locklist */
+ struct reservdev **q; /* Running ptr, rtnlist */
+ char *r; /* Temp ptr to char */
+ size_t bufsiz; /* Size of buffer to alloc */
+ int noerr; /* TRUE if all's well */
+ int i; /* Lock counter */
+
+
+ /* Initializations */
+ noerr = TRUE;
+
+ /* 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 */
+ bufsiz = (lockcount+1) * sizeof (struct reservdev *);
+ if (rtnlist = malloc(bufsiz)) {
+
+ /* Build the return list from the lock list */
+ p = locklist;
+ q = rtnlist;
+ for (i = 0; noerr && (i < lockcount); i++) {
+ if (*q = malloc(sizeof (struct reservdev))) {
+ if (r = malloc(strlen(p->lk_alias)+1)) {
+ (*q)->devname = strcpy(r, p->lk_alias);
+ (*q)->key = p->lk_key;
+ } else noerr = FALSE; /* malloc() error */
+ } else noerr = FALSE; /* malloc() error */
+ p++;
+ q++;
+ }
+
+ /*
+ * If no error, terminate the list. Otherwise, free
+ * the space we've allocated
+ */
+
+ if (noerr) *q = NULL;
+ else {
+ for (q = rtnlist; *q; q++) {
+ free((*q)->devname);
+ free(*q);
+ }
+ free(rtnlist);
+ }
+
+ } else noerr = FALSE; /* Couldn't malloc() list space */
+
+ } else noerr = FALSE; /* Problem reading locks */
+
+ /* Free the lock file */
+ (void) freelkfile();
+
+ } else noerr = FALSE; /* Error locking the lock file */
+
+ /* Close the lock file */
+ (void) _closelkfile();
+
+ } else noerr = FALSE; /* Error opening the lock file */
+
+ /* Return ptr to list of locks or NULL if an error has occurred */
+ return (noerr ? rtnlist : NULL);
+}