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 * 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 ** 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 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 ** 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