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