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