1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
24
25
26 /*
27 * Copyright (c) 1997, by Sun Microsystems, Inc.
28 * All rights reserved.
29 */
30
31 #pragma ident "%Z%%M% %I% %E% SMI"
32 /*LINTLIBRARY*/
33
34 /*
35 * Globals defined:
36 *
37 * devreserv() Reserve a set of OA&M devices
38 * devfree() Free a reserved device
39 * reservdev() Get a list of reserved devices
40 * _openlkfile() Opens the lock file
41 * _rsvtabpath() Get the pathname of the lock table file
42 * _closelkfile() Closes the lock file
43 */
44
45 /*
46 * Headers referenced:
47 * <sys/types.h> System data types
48 * <errno.h> Error definitions (including "errno")
49 * <string.h> String handling definitions
50 * <fcntl.h> File control definitions
51 * <unistd.h> Unix standard value definitions
52 * <devmgmt.h> Global Device Management definitions
53 * "devtab.h" Local Device Management definitions
54 */
55
56 #include <sys/types.h>
57 #include <errno.h>
58 #include <string.h>
59 #include <fcntl.h>
60 #include <unistd.h>
61 #include <stdlib.h>
62 #include <devmgmt.h>
63 #include "devtab.h"
64
65 /*
66 * Local Definitions:
67 */
68
69
70 /*
71 * Local data types:
72 * struct devlks Structure that defines locking information (key
73 * with alias name (may be '\0' terminated)
74 */
75
76 struct devlks {
77 int lk_key;
78 char lk_alias[((DTAB_MXALIASLN+2)/2)*2];
79 };
80
81
82 /*
83 * Local Functions:
84 * isanullstr() Is a character string a null string ("")?
85 * getlkcnt() Get the number of devices locked
86 * locklkfile() Lock the OA&M Device locking file
87 * getlocks() Get the device locks from the device-lock file
88 * islocked() Determines if a device is locked
89 * putlocks() Close the device locks w/ update
90 * freelkfile() Close the device locks w/o updating
91 * compresslks() Compresses the table containing lock info
92 */
93
94 #define isanullstr(s) (s[0] == '\0')
95
96 static int locklkfile(short); /* Lock the lock file */
97 static int getlkcnt(void); /* Get the number of locked devices */
98 static int getlocks(void); /* Get the lock information */
99 static int putlocks(char **, int); /* Update lock information */
100 static int freelkfile(void); /* Free lock information (no update) */
101 static char *islocked(char *); /* Determines if a device is locked */
102
103
104 /*
105 * Static data
106 */
107
108 static struct flock lkinfo = {0, 0, 0, 0, 0};
109 static struct devlks *locklist;
110 static int lockcount;
111 static int lkfilefd = -1;
112
113 /*
114 * char *_rsvtabpath()
115 *
116 * Determines the pathname of the device reservation table file
117 *
118 * Uses the following sequential steps:
119 * 1) If OAM_DEVLKFILE is defined and is not null, use that as
120 * the pathname to the file
121 * 2) Otherwise, use the devault name found in DVLK_PATH (defined
122 * in the header file <devtab.h>
123 *
124 * Arguments: None
125 *
126 * Returns: char *
127 * A pointer to the filename in malloc()ed memory or (char *) NULL if
128 * it fails. "errno" will indicate the error if it fails.
129 */
130
131 char *
_rsvtabpath(void)132 _rsvtabpath(void)
133 {
134 /* Automatics */
135 char *lockname; /* Name of the lockfile */
136 #ifdef DEBUG
137 char *p; /* Temporary pointer */
138 #endif
139
140 #ifdef DEBUG
141 p = getenv(OAM_DEVLKTAB);
142 if ((p != NULL) && (*p != '\0')) {
143 if (lockname = malloc(strlen(p)+1))
144 (void) strcpy(lockname, p);
145 } else {
146 #endif
147 if (lockname = malloc(strlen(DVLK_PATH)+1))
148 (void) strcpy(lockname, DVLK_PATH);
149
150 #ifdef DEBUG
151 }
152 #endif
153
154 /* Fini -- return a pointer to the lockfile pathname */
155 return (lockname);
156 }
157
158 /*
159 * int _openlkfile()
160 *
161 * The _openlkfile() function opens a device-reservation table file
162 * for read/write access.
163 *
164 * Arguments: None
165 *
166 * Returns: int
167 * TRUE if successful, FALSE otherwise.
168 *
169 * Statics Used:
170 * lkfilefd Lock file file descriptor
171 */
172
173 int
_openlkfile(void)174 _openlkfile(void)
175 {
176 /*
177 * Automatic data
178 */
179
180 char *lockname; /* Name of the lock file */
181
182
183 /* Close the lockfile -- it might be open */
184 (void) _closelkfile();
185
186 /* If we can get the name of the lock file ... */
187 if (lockname = _rsvtabpath()) {
188
189 /* Open it */
190 lkfilefd = open(lockname, O_RDWR|O_CREAT, 0600);
191 free(lockname);
192
193 }
194
195 /* Finis */
196 return ((lkfilefd != -1) ? TRUE : FALSE);
197 }
198
199 /*
200 * int _closelkfile()
201 *
202 * Function closes the device-reservation table file and sets the
203 * necessary external variables to indicate such.
204 *
205 * Arguments: None
206 *
207 * Returns: int
208 * Same as close()
209 *
210 * Statics referenced:
211 * lkfilefd The device reservation table file's file descriptor
212 */
213
214 int
_closelkfile(void)215 _closelkfile(void)
216 {
217 /* Automatics */
218 int rtnval; /* Value to return */
219
220 /* Close the lock file if it's open */
221 if (lkfilefd != -1) rtnval = close(lkfilefd);
222 else rtnval = 0;
223
224 /* Indicate that the lock-file is closed */
225 lkfilefd = -1;
226
227 /* Finis */
228 return (rtnval);
229 }
230
231 /*
232 * int locklkfile(lkflag)
233 * short lkflag
234 *
235 * This function locks the device lock file. If the request cannot
236 * be serviced, it keeps on trying until it manages to lock the file
237 * or it encounters an error.
238 *
239 * Arguments:
240 * lkflag Flag (from FCNTL(BA_OS)) indicating which type
241 * of lock is being requested. Values that make
242 * sense:
243 * F_RDLCK: Read lock.
244 * F_WRLCK: Write lock.
245 *
246 * Returns: int
247 * TRUE (non-zero) if the function managed to lock the file, FALSE
248 * otherwise ("errno" will indicate the problem).
249 *
250 * Statics used:
251 * int lkfilefd File descriptor of the open lock file
252 * struct flock lkinfo Structure used by fcntl() to lock a file
253 */
254
255 static int
locklkfile(short lkflag)256 locklkfile(short lkflag)
257 {
258 /* Automatic data */
259 int noerror; /* TRUE if no error yet */
260 int locked; /* TRUE if the file is locked */
261 int olderrno; /* Value of errno on call */
262
263
264 /* Set up the locking structure */
265 lkinfo.l_type = lkflag;
266
267 /* Try to lock the file. If it's locked, wait and try again */
268 noerror = TRUE;
269 locked = FALSE;
270 olderrno = errno;
271 while (noerror && !locked) {
272 if (fcntl(lkfilefd, F_SETLK, &lkinfo) != -1) locked = TRUE;
273 else {
274 if ((errno == EACCES) || (errno == EAGAIN)) {
275 errno = olderrno;
276 if (sleep(2)) noerror = FALSE;
277 } else noerror = FALSE;
278 }
279 }
280
281 /* Return a success flag */
282 return (locked);
283 }
284
285 /*
286 * int getlkcnt()
287 *
288 * This function extracts the number of currently-locked devices
289 * from the lock file.
290 *
291 * Arguments: None
292 *
293 * Returns: int
294 * The number of devices locked or -1 if an error occurred.
295 *
296 * Statics used:
297 * lkfilefd File descriptor of the open lockfile
298 *
299 * Assumptions:
300 * - The file is positioned to the beginning-of-file
301 */
302
303 static int
getlkcnt(void)304 getlkcnt(void)
305 {
306 /* Automatics */
307 int cntread; /* Number of bytes read */
308 int lkcnt; /* Number of current locks */
309
310 /* Get the lock count from the file */
311 cntread = (int)read(lkfilefd, &lkcnt, sizeof (int));
312
313 /* If there wasn't one, set to 0. If error, set to -1 */
314 if (cntread != (int)sizeof (int))
315 lkcnt = (cntread < 0) ? -1 : 0;
316
317 /* Return the lock count */
318 return (lkcnt);
319 }
320
321 /*
322 * int readlocks()
323 *
324 * The readlocks() function reads the reserved-device list from
325 * the reserved-device file (which has already been opened)
326 *
327 * Arguments: None
328 *
329 * Returns: int
330 * TRUE if all went well, FALSE otherwise.
331 *
332 * Statics Used:
333 * lockcount Sets this to the number of locks in the lock list
334 * locklist Sets this to the malloc()ed space containing the
335 * list of reserved devices.
336 * lkfilefd Reads data from this file
337 */
338
339 static int
readlocks(void)340 readlocks(void)
341 {
342 /* Automatics */
343 struct devlks *alloc; /* Ptr to alloc'ed space */
344 int noerror; /* TRUE if all is well */
345 size_t bufsiz; /* # bytes needed for lock data */
346
347
348 /* Initializations */
349 noerror = TRUE;
350
351 /* Get the number of devices currently locked */
352 if ((lockcount = getlkcnt()) > 0) {
353
354 /* Allocate space for the locks */
355 bufsiz = lockcount * sizeof (struct devlks);
356 if (alloc = malloc(bufsiz)) {
357
358 /* Read the locks into the malloc()ed buffer */
359 if (read(lkfilefd, alloc, bufsiz) != (ssize_t)bufsiz)
360 noerror = FALSE;
361
362 /* If the read failed, free malloc()ed buffer */
363 if (!noerror) free(alloc);
364
365 } else noerror = FALSE; /* malloc() failed */
366
367 } else if (lockcount < 0) noerror = FALSE;
368
369 /* Finished */
370 if (noerror)
371 locklist = (lockcount > 0) ? alloc : NULL;
372 return (noerror);
373 }
374
375 /*
376 * int getlocks()
377 *
378 * getlocks() extracts the list of locked devices from the file
379 * containing that information. It returns the number of locked
380 * devices. If there are any locked devices, it allocates a buffer
381 * for the locked file information, saves that buffer address in
382 * the allocated buffer. Also, the device lock file is open and
383 * locked if the function is successful.
384 *
385 * Arguments: None
386 *
387 * Returns: int
388 * TRUE if successful, FALSE otherwise. "errno" will reflect the
389 * error if the function returns FALSE.
390 *
391 * Static data referenced:
392 * int lkfilefd File descriptor of the lock file
393 */
394
395 static int
getlocks(void)396 getlocks(void)
397 {
398 /* Automatic data */
399 int noerror; /* TRUE if all's well */
400
401
402 /* Initializations */
403 noerror = TRUE;
404
405 /* Open the lock file */
406 if (_openlkfile()) {
407
408 /* Lock the lock file */
409 if (locklkfile(F_WRLCK)) {
410
411 /* Get the number of devices currently locked */
412 if (!readlocks()) noerror = FALSE;
413
414 /* If something happened, unlock the file */
415 if (!noerror) (void) freelkfile();
416
417 } else noerror = FALSE; /* Lock failed */
418
419 /* If something happened, close the lock file */
420 if (!noerror)
421 (void) _closelkfile();
422
423 } else noerror = FALSE; /* Open failed */
424
425 /* Done */
426 return (noerror);
427 }
428
429 /*
430 * int writelks(tblcnt)
431 * int tblcnt
432 *
433 * writelks() writes the lock information to the lock file. Lock
434 * information includes the number of locks (to be) in the table.
435 * Note that functions may still be appending new locks after this
436 * call...
437 *
438 * Arguments:
439 * tblcnt Number of locks in the lock table
440 *
441 * Returns:
442 * TRUE if successful, FALSE otherwise with "errno" containing an
443 * indication of the error.
444 *
445 * Statics Used:
446 * lockcount Number of locks to exist
447 * locklist Table of locks (may not include new ones)
448 * lkfilefd File descriptor of the lock file
449 *
450 * Notes:
451 * - The number of locks that are going to be in the lock file
452 * is in the static variable "lockcount". <tblcnt> indicates
453 * the number of entries in the lock table.
454 */
455
456 static int
writelks(int tblcnt)457 writelks(int tblcnt)
458 {
459 /* Automatic data */
460 int noerr; /* FLAG, TRUE if all's well */
461 size_t tblsz; /* Size of the table to write */
462
463 /* Initializations */
464 noerr = TRUE;
465
466 /* Rewind the OA&M Device Lock File */
467 if (lseek(lkfilefd, 0L, 0) >= 0L)
468
469 /* Write the number of locks that will (eventually) exist */
470 if (write(lkfilefd, &lockcount, sizeof (int)) == sizeof (int)) {
471
472 /* Write the table as we currently know it */
473 tblsz = tblcnt * sizeof (struct devlks);
474 if (tblsz)
475 if (!write(lkfilefd, locklist, tblsz) == (ssize_t)tblsz)
476 noerr = FALSE; /* Write of locks failed */
477
478 } else noerr = FALSE; /* write() of count failed */
479
480 else noerr = FALSE; /* Rewind failed */
481
482 /* Return an indicator of our success */
483 return (noerr);
484 }
485
486 /*
487 * int appendlk(key, alias)
488 * int key
489 * char *alias
490 *
491 * Write device locking information to the device locking file.
492 *
493 * Arguments:
494 * key Key the device is being locked on
495 * alias The device alias being locked
496 *
497 * Returns: int
498 * TRUE if we successfully appended a lock to the lock file,
499 * FALSE with "errno" set otherwise.
500 *
501 * Static data used:
502 * lkfilefd The open file descriptor for the open device
503 * locking file
504 */
505
506 static int
appendlk(int key,char * alias)507 appendlk(
508 int key, /* Lock key */
509 char *alias) /* Alias to lock */
510 {
511 /* Automatic data */
512 struct devlks lk; /* Structure for writing a lock */
513
514 /* Set up the data to write */
515 lk.lk_key = key;
516 (void) strcpy(lk.lk_alias, alias);
517
518 /* Write the data, returning an indicator of our success */
519 return (write(lkfilefd, &lk,
520 sizeof (struct devlks)) == sizeof (struct devlks));
521 }
522
523 /*
524 * int compresslks()
525 *
526 * This function compresses the lock table, squeezing out the empty
527 * lock entries.
528 *
529 * Arguments: none
530 *
531 * Returns: int
532 * The number of non-empty entries in the table. They will be the
533 * first 'n' entries in the table after compression.
534 *
535 * Statics Used
536 * lockcount Number of locks in the device lock list
537 * locklist The device lock list
538 */
539
540 static int
compresslks(void)541 compresslks(void)
542 {
543 /* Automatics */
544 struct devlks *avail; /* Pointer to empty slot */
545 struct devlks *p; /* Running pointer to locks */
546 int nlocks; /* Number of locks (up to date) */
547 int i; /* Temporary counter */
548
549 /* Initializations */
550 p = locklist;
551 nlocks = lockcount;
552 avail = NULL;
553
554 /* Loop through the lock list squeezing out unused slots */
555 for (i = 0; i < lockcount; i++) {
556
557 /* If we've found an empty slot ... */
558 if (isanullstr(p->lk_alias)) {
559
560 /*
561 * If we've an empty slot to move to, just decrement
562 * count of used slots. Otherwise, make it the next
563 * available slot
564 */
565
566 nlocks--;
567 if (!avail) avail = p;
568 }
569
570 else if (avail) {
571
572 /*
573 * If we found a slot in use and there's an
574 * available slot, move this one there
575 */
576
577 (void) strcpy(avail->lk_alias, p->lk_alias);
578 avail->lk_key = p->lk_key;
579 avail++;
580 }
581
582 /* Next, please */
583 p++;
584 }
585
586 return (nlocks);
587 }
588
589 /*
590 * int freelkfile()
591 *
592 * This function unlocks the OA&M device locking file.
593 *
594 * Arguments: None
595 *
596 * Returns: int
597 * TRUE if it successfully unlocked the file, FALSE otherwise
598 * with "errno" set to indicate the problem.
599 *
600 * Statics Used:
601 * lkinfo File-locking structure
602 * lkfilefd File-descriptor of the open lock file
603 */
604
605 static int
freelkfile(void)606 freelkfile(void)
607 {
608 /* Automatic data */
609 int noerr; /* TRUE if all's well */
610
611 /* Set the action to "unlock" */
612 lkinfo.l_type = F_UNLCK;
613
614 /* Unlock the file */
615 noerr = (fcntl(lkfilefd, F_SETLK, &lkinfo) != -1);
616
617 /* Return an indication of our success */
618 return (noerr);
619 }
620
621 /*
622 * int putlocks(newlist, key)
623 * char **newlist
624 * int key
625 *
626 * This function updates the file containing OA&M device locks.
627 *
628 * Arguments:
629 * newlist The address of the list of addresses of device
630 * aliases to add to the list of locked devices
631 * key The key on which to lock the devices
632 *
633 * Returns: int
634 * TRUE if all went well, FALSE otherwise with "errno" set to an
635 * error code that indicates the problem.
636 *
637 * Statics Used:
638 * lockcount Number of locks in the locked device structure
639 * locklist Locked device structure
640 */
641
642 static int
putlocks(char ** newlist,int key)643 putlocks(
644 char **newlist, /* New devices to lock */
645 int key) /* Key we're locking stuff on */
646 {
647 /* Automatic data */
648 struct devlks *plk; /* Ptr into the locks list */
649 char **pp; /* Pointer into the device list */
650 char **qq; /* Another ptr into the dev list */
651 int lkndx; /* Index into locks list */
652 int noerr; /* TRUE if all's well */
653 int lksintbl; /* Number of locks in the table */
654
655
656 /*
657 * Look through the existing lock list, looking for holes we can
658 * use for the newly locked devices
659 */
660
661 plk = locklist;
662 pp = newlist;
663 lkndx = 0;
664 while (*pp && (lkndx < lockcount)) {
665 if (isanullstr(plk->lk_alias)) {
666 plk->lk_key = key;
667 (void) strcpy(plk->lk_alias, *pp++);
668 }
669 lkndx++;
670 plk++;
671 }
672
673 /*
674 * Update the locks file (algorithm depends on whether we're adding
675 * new locks or not. May be replacing old locks!)
676 */
677
678 if (*pp) {
679
680 /*
681 * Need to expand the locks file
682 * - Remember the old lock count (in existing lock buffer)
683 * - Count the number of new locks we need to add
684 * - Write out the old locks structure
685 * - Append locks for the newly added locks
686 */
687
688 lksintbl = lockcount;
689 for (qq = pp; *qq; qq++) lockcount++;
690 noerr = writelks(lksintbl);
691 while (noerr && *pp) noerr = appendlk(key, *pp++);
692 } else {
693
694 /*
695 * Don't need to expand the locks file. Compress the locks
696 * then write out the locks information
697 */
698
699 lockcount = compresslks();
700 noerr = writelks(lockcount);
701 }
702
703 /* Done. Return an indication of our success */
704 return (noerr);
705 }
706
707 /*
708 * char *islocked(device)
709 * char *device
710 *
711 * This function checks a device to see if it is locked. If it is
712 * not locked, it returns the device alias.
713 *
714 * A device is not locked if the device's alias does not appear in
715 * the device locks table, or the key on which the device was locked
716 * is no longer active.
717 *
718 * Argumetns:
719 * char *device The device to be reserved. This can be
720 * a pathname to the device or a device
721 * alias.
722 *
723 * Returns: char *
724 * Returns a pointer to the device alias if it's not locked, or
725 * (char *) NULL if it's locked or some error occurred.
726 *
727 * Static data used:
728 * struct devlks *locklist Pointer to the list of device locks
729 * int lockcount The number of devices that are locked
730 */
731
732 static char *
islocked(char * device)733 islocked(char *device)
734 {
735 /* Automatic data */
736 char *alias; /* Alias of "device" */
737 struct devlks *plk; /* Ptr to locking info */
738 int locked; /* TRUE if device in locked list */
739 int i; /* Temp counter */
740
741 /* Get the device's alias */
742 if (alias = devattr(device, DTAB_ALIAS)) {
743
744 /*
745 * Look through the device locks to see if this device alias
746 * is locked
747 */
748
749 locked = FALSE;
750 plk = locklist;
751 for (i = 0; !locked && (i < lockcount); i++) {
752 if (strncmp(alias, plk->lk_alias, DTAB_MXALIASLN) == 0)
753 locked = TRUE;
754 else plk++;
755 }
756
757 if (locked) {
758 free(alias);
759 alias = NULL;
760 errno = EAGAIN;
761 }
762
763 } /* devattr() failed, no such device? */
764
765 /* Return pointer to the device */
766 return (alias);
767 }
768
769 /*
770 * int unreserv(key, device)
771 * int key
772 * char *device
773 *
774 * This function removes a device reservation.
775 *
776 * Arguments:
777 * int key The key on which the device was allocated
778 * char *device The device to be freed.
779 *
780 * Returns: int
781 * TRUE if successful, FALSE otherwise with "errno" set.
782 *
783 * Explicit "errno" settings:
784 * (This follows the "signal()" model which gives one the ability
785 * to determine if a device is allocated without having the
786 * permission to free it.)
787 *
788 * EINVAL The device specified was not locked
789 * EPERM The device specified was locked but not on the
790 * specified key
791 *
792 * Static data used:
793 * locklist List of locked devices
794 * lockcount Number of entries in the locked-device list
795 */
796
797 int
unreserv(int key,char * device)798 unreserv(int key, char *device)
799 {
800 /* Automatics */
801 char *srchalias; /* Device alias to search table with */
802 char *alias; /* Device's alias (from devattr()) */
803 struct devlks *plk; /* Pointer to a device lock */
804 int locked; /* TRUE if device currently locked */
805 int noerr; /* TRUE if all's well */
806 int olderrno; /* Entry value of "errno" */
807 int i; /* Counter of locks */
808
809
810 /* Initializations */
811 noerr = TRUE;
812
813 /*
814 * Get the device alias. If none can be found, try to free
815 * whatever it is that was given to us (the possibility exists
816 * that the device has been removed from the device table since
817 * it was reserved, so the device not being in the table shouldn't
818 * pose too much of a problem with us...)
819 */
820
821 olderrno = errno;
822 if (alias = devattr(device, DTAB_ALIAS)) srchalias = alias;
823 else {
824 errno = olderrno;
825 srchalias = device;
826 }
827
828 /* Loop through the locked-device list looking for what we've got... */
829 locked = FALSE;
830 plk = locklist;
831 for (i = 0; !locked && (i < lockcount); i++) {
832 if (strcmp(srchalias, plk->lk_alias) == 0)
833 locked = TRUE;
834 else plk++;
835 }
836
837 /* Free the alias string (if any), we don't need it anymore */
838 if (alias) free(alias);
839
840 /* If the device is locked ... */
841 if (locked) {
842
843 /*
844 * If it's locked on the key we've been given, free it.
845 * Otherwise, don't free it and set errno to EPERM
846 */
847
848 if (plk->lk_key == key) {
849 plk->lk_alias[0] = '\0';
850 } else {
851 noerr = FALSE;
852 errno = EPERM;
853 }
854 } else {
855
856 /* The device isn't locked. Set errno to EINVAL */
857 noerr = FALSE;
858 errno = EINVAL;
859 }
860
861 /* Finished. Return an indication of our success */
862 return (noerr);
863 }
864
865 /*
866 * char **devreserv(key, rsvlst)
867 * int key
868 * char **rsvlist[]
869 *
870 * The devreserv() function reserves devices known to the OA&M Device
871 * Management family of functions. Once a device is reserved, it can't
872 * be reserved by another until it is freed or the process with the
873 * "key" is no longer active. It returns a list aliases of the devices
874 * it allocated.
875 *
876 * The function attempts to reserve a single device from each of the
877 * lists. It scans each list sequentially until it was able to
878 * reserve a requested device. If it successfully reserved a device
879 * from each of the lists, it updates the device-locked file and
880 * returns those aliases to the caller. If it fails, it allocates
881 * nothing and returns (char **) NULL to the caller. "errno"
882 * indicates the error.
883 *
884 * Arguments:
885 * int key The key on which this device is being reserved.
886 *
887 * char **rsvlist[] The address of the list of addresses of lists
888 * of pointers to the devices to allocate.
889 *
890 * Returns: char **
891 * A pointer to malloc()ed space containing pointers to the aliases
892 * of the reserved devices. The aliases are in malloc()ed space also.
893 * The list is terminated by the value (char *) NULL.
894 *
895 * Static Data Used:
896 * None directly, but functions called share hidden information
897 * that really isn't of concern to devreserv().
898 */
899
900 char **
devreserv(int key,char ** rsvlst[])901 devreserv(
902 int key, /* Key to reserve device on */
903 char **rsvlst[]) /* List of lists of devs to reserve */
904 {
905 char ***ppp; /* Ptr to current list in rsvlist */
906 char **pp; /* Ptr to current item in list */
907 char **qq; /* Ptr to item in rtnlist */
908 char **rr; /* Ptr to item in aliases */
909 char **aliases; /* List of aliases allocated */
910 char **rtnlist; /* Ptr to buf to return */
911 char *alias; /* Alias of dev to reserve */
912 int noerr; /* TRUE if all's well */
913 int olderrno; /* Old value of errno */
914 int gotone; /* TRUE if unreserved dev found */
915 int foundone; /* Found a valid device in the list */
916 int ndevs; /* # of devs to reserve */
917
918 noerr = TRUE;
919 ppp = rsvlst;
920 olderrno = errno;
921 for (ndevs = 0; *ppp++; ndevs++)
922 ;
923 if (rtnlist = malloc((ndevs+1)*sizeof (char **))) {
924 if (aliases = malloc((ndevs+1)*sizeof (char **))) {
925 if (getlocks()) {
926 qq = rtnlist;
927 rr = aliases;
928
929 /* Go through the lists of devices we're to reserve */
930
931 for (ppp = rsvlst; noerr && *ppp; ppp++) {
932
933 /* Try to reserve a device from each list */
934 gotone = FALSE;
935 foundone = FALSE;
936 for (pp = *ppp; noerr && !gotone && *pp; pp++) {
937
938 /*
939 * Check the next device in the list. If islocked()
940 * returns that device's alias, it's ours to have
941 */
942
943 if (alias = islocked(*pp)) {
944 gotone = TRUE;
945 foundone = TRUE;
946 if (*qq = malloc(strlen(*pp)+1)) {
947 (void) strcpy(*qq++, *pp);
948 *rr++ = alias;
949 } else {
950 *rr = NULL;
951 noerr = FALSE;
952 }
953 } else {
954 if (errno == EAGAIN) {
955 foundone = TRUE;
956 errno = olderrno;
957 } else if (errno == ENODEV) errno = olderrno;
958 else {
959 noerr = FALSE;
960 *rr = NULL;
961 }
962 }
963 }
964
965 /*
966 * If no device from the list could be reserved,
967 * we've failed
968 */
969
970 if (noerr && !gotone) {
971 noerr = FALSE;
972 if (!foundone) errno = ENODEV;
973 else errno = EAGAIN;
974 *qq = NULL;
975 *rr = NULL;
976 }
977
978 } /* End of loop through lists loop */
979
980 /*
981 * If all went well, update lock file.
982 * Then, free locks
983 */
984
985 if (noerr) {
986 *qq = NULL;
987 *rr = NULL;
988 if (!putlocks(aliases, key)) noerr = FALSE;
989 }
990
991 /* Free resources */
992 if (!freelkfile()) noerr = FALSE;
993 if (_closelkfile() != 0) noerr = FALSE;
994 for (qq = aliases; *qq; qq++) free(*qq);
995 if (!noerr)
996 for (pp = rtnlist; *pp; pp++)
997 free(*pp);
998
999 } else noerr = FALSE; /* Error getting locks */
1000
1001 free(aliases);
1002
1003 } else noerr = FALSE; /* Malloc() for alias list failed */
1004
1005 if (!noerr) {
1006 free(rtnlist);
1007 rtnlist = NULL;
1008 }
1009
1010 } else noerr = FALSE; /* malloc() failed */
1011
1012 /* Return list or an indication of an error */
1013 return (noerr ? rtnlist : NULL);
1014 }
1015
1016 /*
1017 * int devfree(key, device)
1018 * int key
1019 * char *device
1020 *
1021 * This function unreserves (frees) the given device. It returns
1022 * an indication of success with "errno" containing information about
1023 * a failure.
1024 *
1025 * Arguments:
1026 * int key The key that the device is locked on
1027 * char *device The device (alias, pathname to, etc.) to be freed.
1028 *
1029 * Returns: int
1030 * 0 if successful, -1 with "errno" set if fails.
1031 */
1032
1033 int
devfree(int key,char * device)1034 devfree(
1035 int key, /* Key device is locked on */
1036 char *device) /* Device to free */
1037 {
1038 /* Automatics */
1039 int noerr;
1040
1041 /* Initializations */
1042 noerr = TRUE;
1043
1044 /* Get the locks, locking the lock file */
1045 if (getlocks()) {
1046
1047 /* Attempt to unreserve the device */
1048 if (unreserv(key, device)) {
1049
1050 /*
1051 * Successful. Compress the lock structure and
1052 * write the new locks
1053 */
1054
1055 lockcount = compresslks();
1056 if (!writelks(lockcount)) noerr = FALSE;
1057
1058 } else noerr = FALSE; /* Couldn't unreserve the device */
1059
1060 /* Unlock and close the locks file */
1061 if (!freelkfile()) noerr = FALSE;
1062 if (_closelkfile() != 0) noerr = FALSE;
1063
1064 } else noerr = FALSE;
1065
1066 /* Return 0 if successful, something else otherwise */
1067 return (noerr? 0 : -1);
1068 }
1069
1070 /*
1071 * struct reservdev **reservdev()
1072 *
1073 * This function returns the list of reserved devices
1074 * along with the key on which those devices were locked.
1075 *
1076 * Arguments: None.
1077 *
1078 * Returns: struct reservdev **
1079 * Pointer to the list of pointers to structures describing
1080 * the reserved devices, or (struct reservdev **) NULL if an
1081 * error occurred. The list of pointers is terminated by
1082 * (struct reservdev *) NULL.
1083 *
1084 * Statics Used:
1085 * locklist List of reserved devices
1086 * lockcount Number of items in the reserved-devices list
1087 */
1088
1089 struct reservdev **
reservdev(void)1090 reservdev(void)
1091 {
1092 /* Automatics */
1093 struct reservdev **rtnlist; /* Ptr to return list */
1094 struct devlks *p; /* Running ptr, locklist */
1095 struct reservdev **q; /* Running ptr, rtnlist */
1096 char *r; /* Temp ptr to char */
1097 size_t bufsiz; /* Size of buffer to alloc */
1098 int noerr; /* TRUE if all's well */
1099 int i; /* Lock counter */
1100
1101
1102 /* Initializations */
1103 noerr = TRUE;
1104
1105 /* Open the lock file ... */
1106 if (_openlkfile()) {
1107
1108 /* Put a read-lock on the lock-file ... */
1109 if (locklkfile(F_RDLCK)) {
1110
1111 /* Read the locks ... */
1112 if (readlocks()) {
1113
1114 /* Alloc space for the return list */
1115 bufsiz = (lockcount+1) * sizeof (struct reservdev *);
1116 if (rtnlist = malloc(bufsiz)) {
1117
1118 /* Build the return list from the lock list */
1119 p = locklist;
1120 q = rtnlist;
1121 for (i = 0; noerr && (i < lockcount); i++) {
1122 if (*q = malloc(sizeof (struct reservdev))) {
1123 if (r = malloc(strlen(p->lk_alias)+1)) {
1124 (*q)->devname = strcpy(r, p->lk_alias);
1125 (*q)->key = p->lk_key;
1126 } else noerr = FALSE; /* malloc() error */
1127 } else noerr = FALSE; /* malloc() error */
1128 p++;
1129 q++;
1130 }
1131
1132 /*
1133 * If no error, terminate the list. Otherwise, free
1134 * the space we've allocated
1135 */
1136
1137 if (noerr) *q = NULL;
1138 else {
1139 for (q = rtnlist; *q; q++) {
1140 free((*q)->devname);
1141 free(*q);
1142 }
1143 free(rtnlist);
1144 }
1145
1146 } else noerr = FALSE; /* Couldn't malloc() list space */
1147
1148 } else noerr = FALSE; /* Problem reading locks */
1149
1150 /* Free the lock file */
1151 (void) freelkfile();
1152
1153 } else noerr = FALSE; /* Error locking the lock file */
1154
1155 /* Close the lock file */
1156 (void) _closelkfile();
1157
1158 } else noerr = FALSE; /* Error opening the lock file */
1159
1160 /* Return ptr to list of locks or NULL if an error has occurred */
1161 return (noerr ? rtnlist : NULL);
1162 }
1163