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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2017 Peter Tribble. 24 */ 25 26 /* 27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 32 /* 33 * Module: lock.c 34 * Program: pkgadm (/usr/bin/pkgadm) 35 * Synopsis: implements the zone/package administrative lock interface 36 * Public methods: 37 * admin_lock 38 * Usage: 39 * Acquire: -a [ -e | -s ] [ -o obj ] [ -k key ] [ -R root ] [ -q ] \ 40 * [ -w ] [ -W timeout ] 41 * Release: -r -o object -k key [ -R altRoot ] [ -q ] 42 * Status: [ -o object ] [ -k key ] [ -R altRoot ] [ -q ] 43 */ 44 45 /* enable extentions to standard Unix libraries */ 46 47 #define __EXTENSIONS__ 48 49 /* unix system includes */ 50 51 #include <stdio.h> 52 #include <stdarg.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <strings.h> 56 #include <sys/types.h> 57 #include <wait.h> 58 #include <sys/stat.h> 59 #include <fcntl.h> 60 #include <unistd.h> 61 #include <signal.h> 62 #include <locale.h> 63 #include <libgen.h> 64 #include <sys/param.h> 65 #include <errno.h> 66 #include <assert.h> 67 #include <time.h> 68 #include <fnmatch.h> 69 #include <zone.h> 70 71 /* local includes */ 72 73 #include <libinst.h> 74 #include <pkglib.h> 75 #include "pkgadm.h" 76 #include "pkgadm_msgs.h" 77 78 /* definition and conversion of sleep units */ 79 80 #define SECONDS(x) ((unsigned int)(x)) 81 #define MINUTES(x) ((unsigned int)(seconds(x)*60)) 82 83 /* define how waits are timed */ 84 85 #define WAITER_INITIAL SECONDS(1) 86 #define WAITER_MAX SECONDS(60) 87 #define WAITER_NEXT(x) ((x)*2) 88 89 typedef unsigned int WAITER_T; 90 91 /* 92 * The administrative lock file resides in /tmp 93 * It does not survive a reboot 94 * It consists of fixed length records 95 * Each record has the following information: 96 * record number - record position within the lock file 97 * lock count - number of lock holders maintaining this lock 98 * lock object - object being locked 99 * lock key - key needed to manipulate existing lock 100 * lock exclusive - is the lock exclusive (single locker only) 101 */ 102 103 #define LOCK_OBJECT_MAXLEN 512-1 104 #define LOCK_KEY_MAXLEN 37 105 106 #define LOCK_DIRECTORY "/tmp" 107 108 /* 109 * this is the "well known name" of the lock file that is used by the 110 * package, patch, and zone administration commands to synchronize their 111 * various efforts - it must live in a temporary directory that is cleared 112 * on system reboot but it is NOT a temporary file in that it survives 113 * the process that creates and updates it - if the format of the lock 114 * file ever changes, this path should be updated with a later "uuid" 115 * so that previous (incompatible) pkgadm's will not use the later data. 116 */ 117 118 #define LOCK_FILENAME \ 119 "/tmp/.ai.pkg.zone.lock-afdb66cf-1dd1-11b2-a049-000d560ddc3e" 120 121 /* mode to use for LOCK_FILENAME */ 122 123 #define LOCK_FILEMODE \ 124 (S_ISGID|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) 125 126 #define LOCK_SLEEP_INTERVAL SECONDS(2) 127 128 /* lock contents types */ 129 130 typedef unsigned long RECORDNUM_T; 131 132 #define RECORDNUM_NONE 0xFFFFFFFF 133 134 /* actual lock data */ 135 136 struct _adminLock 137 { 138 RECORDNUM_T lockRecordNum; 139 unsigned long lockCount; 140 unsigned long lockExclusive; 141 pid_t lockPid; 142 zoneid_t lockZoneId; 143 char lockKey[LOCK_KEY_MAXLEN+1]; 144 char lockObject[LOCK_OBJECT_MAXLEN+1]; 145 }; 146 147 typedef struct _adminLock ADMINLOCK_T; 148 149 /* size of an individual "lock" */ 150 151 #define LOCK_SIZE sizeof (ADMINLOCK_T) 152 153 /* union to allow lock to be accessed as raw or structured data */ 154 155 union _lockRecord 156 { 157 char _lrLockData[LOCK_SIZE]; 158 ADMINLOCK_T _lrLock; 159 }; 160 161 typedef union _lockRecord LOCK_T; 162 163 /* return codes from "_findLock" */ 164 165 typedef unsigned long FINDLOCK_T; 166 167 #define FINDLOCK_FOUND ((FINDLOCK_T)0) 168 #define FINDLOCK_ERROR ((FINDLOCK_T)-1) 169 #define FINDLOCK_NOTFOUND ((FINDLOCK_T)-2) 170 #define FINDLOCK_KEYMISMATCH ((FINDLOCK_T)-3) 171 #define FINDLOCK_LOCKED ((FINDLOCK_T)-4) 172 #define FINDLOCK_NOTLOCKED ((FINDLOCK_T)-5) 173 #define FINDLOCK_LOCKACQUIRED ((FINDLOCK_T)-6) 174 175 /* 176 * Forward declarations 177 */ 178 179 /* local main function implementation methods */ 180 181 static FINDLOCK_T lock_acquire(LOCK_T *a_lock, int *a_fd, char *a_root, 182 char *a_key, char *a_object, int a_quiet, 183 int a_wait, long a_timeout, int a_exclusive, 184 char *a_altRoot, pid_t a_pid, zoneid_t a_zid); 185 static int lock_release(int a_fd, char *a_key, char *a_object, 186 int a_quiet); 187 static int lock_status(int a_fd, char *a_key, char *a_object, 188 int a_quiet); 189 190 /* local utility functions */ 191 192 static int _lockMatch(char *a_s1Lock, char *a_s2Lock); 193 static FINDLOCK_T _findLock(LOCK_T *a_theLock, RECORDNUM_T *r_recordNum, 194 int a_fd, char *a_object, char *a_key); 195 static int _decrementLockCount(int a_fd, LOCK_T *a_theLock); 196 static int _addLock(char *r_key, int a_fd, char *a_object, 197 int a_exclusive, pid_t a_pid, zoneid_t a_zid); 198 static int _incrementLockCount(int a_fd, LOCK_T *a_theLock); 199 static FINDLOCK_T _lock_acquire(LOCK_T *a_lock, int a_fd, char *a_key, 200 char *a_object, int a_quiet, int a_exclusive, 201 pid_t a_pid, zoneid_t a_zid); 202 static char *_getUniqueId(void); 203 static int _openLockFile(char *a_root); 204 static void sighup_handler(int a_signo); 205 static void sigint_handler(int a_signo); 206 static boolean_t _validateLock(int a_fd, LOCK_T *a_theLock, int a_quiet); 207 208 static int signal_received = 0; 209 210 /* 211 * main methods with external entry points 212 */ 213 214 /* 215 * Name: admin_lock 216 * Synopsis: main entry point for pkgadm "lock" subcommand 217 * Description: Control zone/package administrative locking 218 * Returns: 0 on success, non-zero otherwise. 219 */ 220 221 int 222 admin_lock(int argc, char **argv) 223 { 224 FINDLOCK_T tResult; 225 LOCK_T theLock; 226 char *RFlag = "/"; /* altRoot */ 227 char *endptr; 228 char *kFlag = ""; /* key */ 229 char *oFlag = ""; /* object */ 230 char *p; 231 char c; 232 int aFlag = 0; /* acquire lock */ 233 int eFlag = 0; /* exclusive lock */ 234 int exclusive = 1; /* exclusive vs shared lock */ 235 int fd; 236 int qFlag = 0; /* quiet */ 237 int rFlag = 0; /* release lock */ 238 int result; 239 int sFlag = 0; /* shared lock */ 240 int tFlag = 0; /* test comparison */ 241 int wFlag = 0; /* wait */ 242 long WFlag = 0; /* wait timeout */ 243 pid_t pFlag = 0; /* process # */ 244 struct sigaction nact; 245 struct sigaction oact; 246 zoneid_t zFlag = -1; /* zone i.d. */ 247 248 while ((c = getopt(argc, argv, ":aek:o:p:qrR:stwW:z:")) != EOF) { 249 switch (c) { 250 case 'a': /* acquire lock */ 251 aFlag++; 252 break; 253 254 case 'e': /* exclusive lock */ 255 eFlag++; 256 break; 257 258 case 'k': /* lock-key */ 259 kFlag = optarg; 260 if (strlen(optarg) > LOCK_KEY_MAXLEN) { 261 log_msg(LOG_MSG_ERR, 262 MSG_LOCK_kARG_TOOLONG, 263 strlen(optarg), LOCK_KEY_MAXLEN); 264 return (1); 265 } 266 break; 267 268 case 'o': /* object */ 269 oFlag = optarg; 270 if (strlen(optarg) > LOCK_OBJECT_MAXLEN) { 271 log_msg(LOG_MSG_ERR, 272 MSG_LOCK_oARG_TOOLONG, 273 strlen(optarg), LOCK_OBJECT_MAXLEN); 274 return (1); 275 } 276 break; 277 278 case 'p': /* process i.d. */ 279 errno = 0; 280 endptr = 0; 281 pFlag = strtol(optarg, &endptr, 10); 282 if ((endptr != (char *)NULL) && (*endptr != '\0')) { 283 log_msg(LOG_MSG_ERR, MSG_LOCK_pFLAG_BADINT, 284 optarg, *endptr); 285 return (1); 286 } 287 if ((pFlag == 0) && (errno != 0)) { 288 log_msg(LOG_MSG_ERR, 289 MSG_LOCK_pFLAG_ERROR, 290 optarg, strerror(errno)); 291 return (1); 292 } 293 break; 294 295 case 'q': /* quiet */ 296 qFlag++; 297 break; 298 299 case 'r': /* release lock */ 300 rFlag++; 301 break; 302 303 case 'R': /* alternative root */ 304 /* if root directory is not absolute path, error */ 305 if (*optarg != '/') { 306 log_msg(LOG_MSG_ERR, 307 MSG_LOCK_RARG_NOT_ABSOLUTE, optarg); 308 return (1); 309 } 310 311 /* if root directory does not exist, create it */ 312 if (access(optarg, F_OK) != 0) { 313 314 /* create top level root directory */ 315 if (mkdirp(optarg, 0755) != 0) { 316 log_msg(LOG_MSG_ERR, 317 MSG_LOCK_ALTROOT_CANTCREATE, 318 optarg, strerror(errno)); 319 return (1); 320 } 321 } 322 323 /* if $ALTROOT/tmp directory does not exist create it */ 324 p = pkgstrPrintf("%s/tmp", optarg); 325 if (access(p, F_OK) != 0) { 326 327 /* create $ALTROOT/tmp directory */ 328 if (mkdirp(p, 0777) != 0) { 329 log_msg(LOG_MSG_ERR, 330 MSG_LOCK_ALTROOT_CANTCREATE, 331 p, strerror(errno)); 332 return (1); 333 } 334 } 335 336 /* if $ALTROOT/tmp directory cannot be created, exit */ 337 if (access(p, F_OK) != 0) { 338 log_msg(LOG_MSG_ERR, MSG_LOCK_ALTROOT_NONEXIST, 339 optarg, strerror(errno)); 340 return (1); 341 } 342 343 (void) free(p); 344 345 RFlag = optarg; 346 break; 347 348 case 's': /* shared */ 349 sFlag++; 350 break; 351 352 case 't': /* test comparison */ 353 tFlag++; 354 break; 355 356 case 'w': /* wait */ 357 wFlag++; 358 break; 359 360 case 'W': /* wait with timeout */ 361 errno = 0; 362 endptr = 0; 363 WFlag = strtol(optarg, &endptr, 10); 364 if ((endptr != (char *)NULL) && (*endptr != '\0')) { 365 log_msg(LOG_MSG_ERR, MSG_LOCK_WFLAG_BADINT, 366 optarg, *endptr); 367 return (1); 368 } 369 if ((WFlag == 0) && (errno != 0)) { 370 log_msg(LOG_MSG_ERR, 371 MSG_LOCK_WFLAG_ERROR, 372 optarg, strerror(errno)); 373 return (1); 374 } 375 wFlag++; 376 break; 377 378 case 'z': /* zone i.d. */ 379 errno = 0; 380 endptr = 0; 381 zFlag = strtol(optarg, &endptr, 10); 382 if ((endptr != (char *)NULL) && (*endptr != '\0')) { 383 log_msg(LOG_MSG_ERR, MSG_LOCK_zFLAG_BADINT, 384 optarg, *endptr); 385 return (1); 386 } 387 if ((zFlag == 0) && (errno != 0)) { 388 log_msg(LOG_MSG_ERR, 389 MSG_LOCK_zFLAG_ERROR, 390 optarg, strerror(errno)); 391 return (1); 392 } 393 break; 394 395 case ':': 396 log_msg(LOG_MSG_ERR, MSG_MISSING_OPERAND, optopt); 397 /* FALLTHROUGH */ 398 case '?': 399 400 default: 401 log_msg(LOG_MSG_ERR, MSG_USAGE); 402 return (1); 403 } 404 } 405 406 /* 407 * validate arguments 408 */ 409 410 /* if -t option is specified, override all other options */ 411 412 if (tFlag) { 413 int rs = 0; 414 int rx; 415 int a; 416 417 /* only 2 or 3 args are valid */ 418 419 a = argc-optind; 420 if ((a < 2) || (a > 3)) { 421 (void) fprintf(stderr, MSG_T_OPTION_ARGS, argc-optind); 422 return (1); 423 } 424 425 /* if 3rd argument given, it is return value to check */ 426 427 if (a == 3) { 428 rs = atoi(argv[optind+2]); 429 } 430 rx = _lockMatch(argv[optind+0], argv[optind+1]); 431 432 /* if 3rd argument not given, code to check is code returned */ 433 434 if (a == 2) { 435 rs = rx; 436 } 437 438 /* report results */ 439 440 if (a == 2) { 441 (void) fprintf(stderr, MSG_T_RESULT_TWO, 442 rx, argv[optind+0], argv[optind+1]); 443 return (rx); 444 } 445 446 if (rx != rs) { 447 (void) fprintf(stderr, MSG_T_RESULT_THREE, 448 rs, rx, argv[optind+0], argv[optind+1]); 449 } 450 451 /* always successful */ 452 453 return (rx == rs ? 0 : 1); 454 } 455 456 /* must be no non-option arguments left */ 457 458 if ((argc-optind) > 0) { 459 log_msg(LOG_MSG_ERR, MSG_USAGE); 460 return (1); 461 } 462 463 /* -a and -r cannot be used together */ 464 465 if (aFlag && rFlag) { 466 log_msg(LOG_MSG_ERR, MSG_LOCK_ar_TOGETHER); 467 return (1); 468 } 469 470 /* -e and -s cannot be used together */ 471 472 if (eFlag && sFlag) { 473 log_msg(LOG_MSG_ERR, MSG_LOCK_es_TOGETHER); 474 return (1); 475 } 476 477 /* -e can only be used if -a is used */ 478 479 if (!aFlag && eFlag) { 480 log_msg(LOG_MSG_ERR, MSG_LOCK_e_without_a); 481 return (1); 482 } 483 484 /* -s can only be used if -a is used */ 485 486 if (!aFlag && sFlag) { 487 log_msg(LOG_MSG_ERR, MSG_LOCK_s_without_a); 488 return (1); 489 } 490 491 /* 492 * perform the requested operation 493 */ 494 495 /* 496 * hook SIGINT and SIGHUP interrupts into quit.c's trap handler 497 */ 498 499 /* hold SIGINT/SIGHUP interrupts */ 500 501 (void) sighold(SIGHUP); 502 (void) sighold(SIGINT); 503 504 /* connect sigint_handler() to SIGINT */ 505 506 nact.sa_handler = sigint_handler; 507 nact.sa_flags = SA_RESTART; 508 (void) sigemptyset(&nact.sa_mask); 509 510 (void) sigaction(SIGINT, &nact, &oact); 511 512 /* connect sighup_handler() to SIGHUP */ 513 514 nact.sa_handler = sighup_handler; 515 nact.sa_flags = SA_RESTART; 516 (void) sigemptyset(&nact.sa_mask); 517 518 (void) sigaction(SIGHUP, &nact, &oact); 519 520 /* release hold on signals */ 521 522 (void) sigrelse(SIGHUP); 523 (void) sigrelse(SIGINT); 524 525 /* open the lock file */ 526 527 fd = _openLockFile(RFlag); 528 if (fd < 0) { 529 return (1); 530 } 531 532 if (aFlag) { 533 /* set "exclusive" mode based on -e/-s flag used */ 534 535 if (sFlag) { 536 exclusive = 0; 537 } else if (eFlag) { 538 exclusive = 1; 539 } 540 541 /* acquire lock */ 542 543 tResult = lock_acquire(&theLock, &fd, RFlag, kFlag, oFlag, 544 qFlag, wFlag, WFlag, exclusive, RFlag, pFlag, zFlag); 545 546 switch (tResult) { 547 case FINDLOCK_LOCKACQUIRED: 548 (void) fprintf(stdout, "%s\n", 549 theLock._lrLock.lockKey); 550 result = 0; 551 break; 552 case FINDLOCK_LOCKED: 553 (void) fprintf(stdout, "%s\n", 554 theLock._lrLock.lockObject); 555 result = 1; 556 break; 557 default: 558 result = 1; 559 break; 560 } 561 562 } else if (rFlag) { 563 /* release lock */ 564 result = lock_release(fd, kFlag, oFlag, qFlag); 565 } else { 566 /* lock status */ 567 result = lock_status(fd, kFlag, oFlag, qFlag); 568 } 569 570 /* close the lock file */ 571 572 (void) close(fd); 573 574 /* return results of operation */ 575 576 return (result); 577 } 578 579 /* 580 * local main function implementation methods 581 */ 582 583 /* 584 * Name: lock_acquire 585 * Description: implement lock acquisition implementing the wait/timeouts 586 * Calls _lock_acquire to attempt lock acquisition. 587 * Arguments: 588 * a_theLock - lock object filled with contents of existing lock 589 * a_fd - file descriptor opened on the lock file 590 * a_root - root of file system to manipulate locks on 591 * a_key - key associated with lock to acquire 592 * a_object - object associated with lock to acquire 593 * a_wait - wait if lock cannot be acquired flag: 594 * == 0 - do not wait 595 * != 0 - wait 596 * a_timeout - timeout if waiting to acquire busy lock: 597 * == 0 - no timeout (wait forever) 598 * != 0 - max # seconds to wait to acquire busy lock 599 * a_quiet - quiet mode enabled flag 600 * a_exclusive - exclusive/shared lock flag 601 * a_pid - if != 0 process i.d. to associate with this lock 602 * a_zid - if >= 0 - zone i.d. to associate with this lock 603 * Returns: int 604 * == 0 - successful 605 * != 0 - not successful 606 */ 607 608 static FINDLOCK_T 609 lock_acquire(LOCK_T *a_theLock, int *a_fd, char *a_root, char *a_key, 610 char *a_object, int a_quiet, int a_wait, long a_timeout, 611 int a_exclusive, char *a_altRoot, pid_t a_pid, zoneid_t a_zid) 612 { 613 int notified = 0; 614 FINDLOCK_T result; 615 time_t timeout; 616 int closeOnExit = 0; 617 618 /* reset the lock */ 619 620 bzero(a_theLock, sizeof (LOCK_T)); 621 622 /* open file if not open */ 623 624 if ((*a_fd) < 0) { 625 (*a_fd) = _openLockFile(a_altRoot); 626 if ((*a_fd) < 0) { 627 return (FINDLOCK_ERROR); 628 } 629 closeOnExit++; 630 } 631 632 /* compute time after which acquire times out */ 633 634 timeout = time((time_t *)NULL) + a_timeout; 635 636 for (;;) { 637 time_t curtime; 638 639 /* attempt to aquire the lock */ 640 641 result = _lock_acquire(a_theLock, *a_fd, a_key, a_object, 642 a_quiet, a_exclusive, a_pid, a_zid); 643 644 /* return result if any result other than object is locked */ 645 646 switch (result) { 647 case FINDLOCK_LOCKACQUIRED: 648 649 /* close lock file if opened in this function */ 650 651 if (closeOnExit) { 652 (void) close(*a_fd); 653 *a_fd = -1; 654 } 655 656 return (FINDLOCK_LOCKACQUIRED); 657 658 case FINDLOCK_FOUND: 659 case FINDLOCK_NOTFOUND: 660 case FINDLOCK_KEYMISMATCH: 661 case FINDLOCK_NOTLOCKED: 662 case FINDLOCK_ERROR: 663 default: 664 /* close lock file if opened in this function */ 665 666 if (closeOnExit) { 667 (void) close(*a_fd); 668 *a_fd = -1; 669 } 670 671 return (result); 672 673 case FINDLOCK_LOCKED: 674 ; 675 /* FALLTHROUGH */ 676 } 677 678 /* 679 * object locked OR SIGINT/SIGHUP interrupt received; 680 * return error if not waiting for lock OR signal received 681 */ 682 683 if ((a_wait == 0) || (signal_received != 0)) { 684 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR, 685 MSG_LOCK_ACQUIRE_BUSY_FIRST, 686 a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR, 687 a_object, a_key, 688 a_theLock->_lrLock.lockObject, 689 a_theLock->_lrLock.lockExclusive ? 690 MSG_LOCK_EXC : MSG_LOCK_SHR, 691 a_theLock->_lrLock.lockExclusive != 692 a_exclusive ? "" : 693 MSG_LOCK_ACQUIRE_BUSY_ADDITIONAL); 694 695 /* close lock file if opened in this function */ 696 697 if (closeOnExit) { 698 (void) close(*a_fd); 699 *a_fd = -1; 700 } 701 702 return (FINDLOCK_LOCKED); 703 } 704 705 /* waiting for lock - if timeout specified see if time left */ 706 707 if (a_timeout > 0) { 708 curtime = time((time_t *)NULL); 709 if (curtime > timeout) { 710 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR, 711 MSG_LOCK_ACQUIRE_TIMEDOUT, 712 a_exclusive ? 713 MSG_LOCK_EXC : MSG_LOCK_SHR, 714 a_object, a_key); 715 716 /* close lock file if opened in this function */ 717 718 if (closeOnExit) { 719 (void) close(*a_fd); 720 *a_fd = -1; 721 } 722 723 return (FINDLOCK_ERROR); 724 } 725 } 726 727 /* 728 * waiting to aquire lock: 729 * - notify waiting (one time only) 730 * - close lock file 731 * - sleep 732 * - open lock file 733 * - try again 734 */ 735 736 /* notify once */ 737 738 if (notified++ == 0) { 739 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_WRN, 740 MSG_LOCK_ACQUIRE_WAITING, 741 a_object); 742 } 743 744 /* close lock file */ 745 746 (void) close(*a_fd); 747 748 /* wait (sleep) */ 749 750 (void) sleep(LOCK_SLEEP_INTERVAL); 751 752 /* open the lock file and try again */ 753 754 *a_fd = _openLockFile(a_root); 755 if (*a_fd < 0) { 756 log_msg(LOG_MSG_ERR, MSG_LOCK_ACQUIRE_REOPEN_FAILED, 757 a_object); 758 759 /* close lock file if opened in this function */ 760 761 if (closeOnExit) { 762 (void) close(*a_fd); 763 *a_fd = -1; 764 } 765 766 return (FINDLOCK_ERROR); 767 } 768 } 769 } 770 771 /* 772 * Name: lock_release 773 * Description: implement lock release 774 * Arguments: 775 * a_fd - file descriptor opened on the lock file 776 * a_key - key associated with lock to release 777 * a_object - object associated with lock to release 778 * a_quiet - quiet mode enabled flag 779 * Returns: int 780 * == 0 - successful 781 * != 0 - not successful 782 */ 783 784 static int 785 lock_release(int a_fd, char *a_key, char *a_object, int a_quiet) 786 { 787 RECORDNUM_T recordNum; 788 LOCK_T theLock; 789 FINDLOCK_T result; 790 791 /* entry debugging info */ 792 793 log_msg(LOG_MSG_DEBUG, MSG_LOCK_RELEASE_ENTRY, 794 a_key, a_object, a_quiet); 795 796 /* find the lock to be released */ 797 798 result = _findLock(&theLock, &recordNum, a_fd, a_object, a_key); 799 800 log_msg(LOG_MSG_DEBUG, MSG_LOCK_RELEASE_FINDRESULT, 801 result, recordNum); 802 803 /* determine how to release the lock if found */ 804 805 switch (result) { 806 /* 807 * object is not locked but a key was specified 808 */ 809 case FINDLOCK_NOTLOCKED: 810 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR, 811 MSG_LOCK_RELEASE_NOTLOCKED, 812 a_object, a_key); 813 return (result); 814 815 /* 816 * object is locked and no matching key was specified 817 */ 818 case FINDLOCK_LOCKED: 819 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR, 820 MSG_LOCK_RELEASE_LOCKED, 821 a_object, a_key); 822 return (result); 823 824 /* 825 * object is not locked 826 */ 827 case FINDLOCK_NOTFOUND: 828 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR, 829 MSG_LOCK_RELEASE_NOTFOUND, 830 a_object, a_key); 831 return (result); 832 833 /* 834 * object is locked and specified key does not match 835 */ 836 case FINDLOCK_KEYMISMATCH: 837 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR, 838 MSG_LOCK_RELEASE_KEYMISMATCH, 839 a_object); 840 return (result); 841 842 /* 843 * error determining if object is locked 844 */ 845 case FINDLOCK_ERROR: 846 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR, 847 MSG_LOCK_RELEASE_ERROR, 848 a_object, a_key); 849 perror(LOCK_FILENAME); 850 return (result); 851 852 /* 853 * object is locked and specified key matches 854 */ 855 case FINDLOCK_FOUND: 856 log_msg(LOG_MSG_DEBUG, MSG_LOCK_RELEASE_FOUND, 857 a_object, a_key); 858 (void) _decrementLockCount(a_fd, &theLock); 859 break; 860 861 /* 862 * unknown return 863 */ 864 default: 865 result = FINDLOCK_ERROR; 866 break; 867 868 } 869 return (result); 870 } 871 872 /* 873 * Name: lock_status 874 * Description: implement lock status display/inquiry 875 * Arguments: 876 * a_fd - file descriptor opened on the lock file 877 * a_key - key associated with lock to look up 878 * a_object - object associated with lock to look up 879 * a_quiet - quiet mode enabled flag 880 * Returns: int 881 * == 0 - successful 882 * != 0 - not successful 883 */ 884 885 static int 886 lock_status(int a_fd, char *a_key, char *a_object, int a_quiet) 887 { 888 ADMINLOCK_T *pll; 889 LOCK_T theLock; 890 RECORDNUM_T recordNum = 0; 891 char *pld; 892 int found = 0; 893 long pls; 894 895 /* entry debugging info */ 896 897 log_msg(LOG_MSG_DEBUG, MSG_LOCK_STATUS_ENTRY, 898 a_key, a_object); 899 900 /* localize references to lock object */ 901 902 pld = &theLock._lrLockData[0]; 903 pll = &theLock._lrLock; 904 pls = sizeof (theLock._lrLockData); 905 906 bzero(pld, pls); 907 908 /* read and process each lock */ 909 910 for (; pread(a_fd, pld, pls, pls*recordNum) == pls; recordNum++) { 911 /* debug info on this lock */ 912 913 log_msg(LOG_MSG_DEBUG, MSG_LOCK_STATUS_READRECORD, 914 recordNum, pll->lockCount, 915 pll->lockObject, pll->lockKey, pll->lockPid, 916 pll->lockZoneId); 917 918 /* ignore if key specified and key does not match */ 919 920 if ((*a_key != '\0') && 921 (strcmp(pll->lockKey, a_key) != 0)) { 922 continue; 923 } 924 925 /* ignore if object specified and object does not match */ 926 927 if ((*a_object != '\0') && 928 (strcmp(pll->lockObject, a_object) != 0)) { 929 continue; 930 } 931 932 found++; 933 934 /* process next lock if quiet operation */ 935 936 if (a_quiet != 0) { 937 continue; 938 } 939 940 /* output header if first lock object */ 941 942 if (found == 1) { 943 (void) fprintf(stdout, 944 "%2s %2s %3s %8s %3s %9s %37s %s\n", 945 "i#", "l#", "cnt", "pid", "zid", "lock-type", 946 "---------------lock-key-------------", 947 "lock-object"); 948 } 949 950 /* output status line for this lock object */ 951 952 (void) fprintf(stdout, 953 "%2ld %2ld %3ld %8ld %3d %9s %37s %s\n", 954 recordNum, pll->lockRecordNum, pll->lockCount, 955 pll->lockPid, pll->lockZoneId, 956 pll->lockExclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR, 957 pll->lockKey, 958 *pll->lockObject == '\0' ? "*" : pll->lockObject); 959 } 960 961 /* return == 0 if found, != 0 if not found */ 962 963 return (found == 0 ? 1 : 0); 964 } 965 966 /* 967 * local utility functions 968 */ 969 970 /* 971 * Name: _lock_acquire 972 * Description: implement lock acquisition without wait/timeouts 973 * Arguments: 974 * a_theLock - lock object filled with contents of existing lock 975 * a_fd - file descriptor opened on the lock file 976 * a_key - key associated with lock to acquire 977 * a_object - object associated with lock to acquire 978 * a_quiet - quiet mode enabled flag 979 * a_exclusive - exclusive/shared lock flag 980 * a_pid - if != 0 process i.d. to associate with this lock 981 * a_zid - if >= 0 zone i.d. to associate with this lock 982 * Returns: FINDLOCK_T 983 */ 984 985 static FINDLOCK_T 986 _lock_acquire(LOCK_T *a_theLock, int a_fd, char *a_key, 987 char *a_object, int a_quiet, int a_exclusive, pid_t a_pid, 988 zoneid_t a_zid) 989 { 990 RECORDNUM_T recordNum; 991 FINDLOCK_T result; 992 char key[LOCK_KEY_MAXLEN+1] = {'\0'}; 993 994 /* entry debugging info */ 995 996 log_msg(LOG_MSG_DEBUG, MSG_LOCK_ACQUIRE_ENTRY, 997 a_key, a_object, a_quiet, a_exclusive); 998 999 /* is the specified object already locked? */ 1000 1001 for (;;) { 1002 result = _findLock(a_theLock, &recordNum, a_fd, a_object, 1003 a_key); 1004 1005 if (result != FINDLOCK_LOCKED) { 1006 break; 1007 } 1008 1009 if (_validateLock(a_fd, a_theLock, a_quiet) == B_TRUE) { 1010 break; 1011 } 1012 } 1013 1014 1015 /* debug info on result of find of lock */ 1016 1017 log_msg(LOG_MSG_DEBUG, MSG_LOCK_ACQUIRE_FINDRESULT, 1018 a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR, 1019 result, recordNum); 1020 1021 /* determine how to acquire the lock */ 1022 1023 switch (result) { 1024 /* 1025 * object is not locked but a key was specified 1026 */ 1027 case FINDLOCK_NOTLOCKED: 1028 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR, 1029 MSG_LOCK_ACQUIRE_NOTLOCKED, 1030 a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR, 1031 a_object, a_key); 1032 break; 1033 1034 /* 1035 * object is locked and no key was specified: 1036 * - if lock is exclusively held, return "locked" 1037 * - if exclusive lock requested, return "locked" 1038 * - otherwise lock is shared and shared lock requested, 1039 * - increment lock count and return the key 1040 */ 1041 case FINDLOCK_LOCKED: 1042 /* return error if current lock exclusive */ 1043 1044 if (a_theLock->_lrLock.lockExclusive) { 1045 break; 1046 } 1047 1048 /* return error if requesting exclusive lock */ 1049 1050 if (a_exclusive) { 1051 break; 1052 } 1053 1054 /* shared requesting shared - add to shared lock */ 1055 1056 log_msg(LOG_MSG_DEBUG, 1057 MSG_LOCK_ACQUIRE_LOCKED_SHARED, 1058 a_object, a_key); 1059 1060 /* increment shared lock count */ 1061 1062 if (_incrementLockCount(a_fd, a_theLock) == 0) { 1063 result = FINDLOCK_LOCKACQUIRED; 1064 } else { 1065 result = FINDLOCK_ERROR; 1066 } 1067 1068 break; 1069 1070 /* 1071 * object is not locked 1072 */ 1073 case FINDLOCK_NOTFOUND: 1074 log_msg(LOG_MSG_DEBUG, 1075 MSG_LOCK_ACQUIRE_NOTFOUND, 1076 a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR, 1077 a_object); 1078 1079 if (_addLock(key, a_fd, a_object, a_exclusive, 1080 a_pid, a_zid) == 0) { 1081 (void) strncpy(a_theLock->_lrLock.lockKey, key, 1082 sizeof (a_theLock->_lrLock.lockKey)); 1083 result = FINDLOCK_LOCKACQUIRED; 1084 } else { 1085 result = FINDLOCK_ERROR; 1086 } 1087 break; 1088 1089 /* 1090 * object is locked, key specified, specified key does not match 1091 */ 1092 case FINDLOCK_KEYMISMATCH: 1093 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_ERR, 1094 MSG_LOCK_ACQUIRE_KEYMISMATCH, 1095 a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR, 1096 a_object); 1097 break; 1098 1099 /* 1100 * error determining if object is locked 1101 */ 1102 case FINDLOCK_ERROR: 1103 log_msg(LOG_MSG_ERR, MSG_LOCK_ACQUIRE_ERROR, 1104 a_object, a_key, strerror(errno)); 1105 break; 1106 1107 /* 1108 * object is locked and specified key matches 1109 */ 1110 case FINDLOCK_FOUND: 1111 /* return locked if object currently locked */ 1112 if (a_exclusive != a_theLock->_lrLock.lockExclusive) { 1113 result = FINDLOCK_LOCKED; 1114 break; 1115 } 1116 1117 log_msg(LOG_MSG_DEBUG, MSG_LOCK_ACQUIRE_FOUND_INC, 1118 a_object, a_key, 1119 a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR); 1120 1121 /* increment shared lock */ 1122 1123 if (_incrementLockCount(a_fd, a_theLock) == 0) { 1124 result = FINDLOCK_LOCKACQUIRED; 1125 } else { 1126 result = FINDLOCK_ERROR; 1127 } 1128 break; 1129 1130 /* 1131 * unknown return 1132 */ 1133 default: 1134 result = FINDLOCK_ERROR; 1135 break; 1136 } 1137 1138 return (result); 1139 } 1140 1141 /* 1142 * Name: _openLockFile 1143 * Description: open the lock file, acquiring exclusive record locks 1144 * Arguments: 1145 * a_root - root of file system to manipulate locks on 1146 * Returns: int 1147 * >= 0 - successful - file descriptor lock file opened on 1148 * < 0 - not successful 1149 */ 1150 1151 static int 1152 _openLockFile(char *a_root) 1153 { 1154 WAITER_T waiter; 1155 char lockpath[MAXPATHLEN]; 1156 int fd; 1157 int result; 1158 1159 /* entry debugging info */ 1160 1161 log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_ENTRY, 1162 a_root, LOCK_FILENAME); 1163 1164 /* generate path to lock directory */ 1165 1166 (void) snprintf(lockpath, sizeof (lockpath), "%s/%s", 1167 a_root, LOCK_DIRECTORY); 1168 1169 if (access(lockpath, F_OK) != 0) { 1170 log_msg(LOG_MSG_ERR, MSG_LOCK_ROOTDIR_INVALID, 1171 lockpath, strerror(errno)); 1172 return (-1); 1173 } 1174 1175 /* generate path to lock file */ 1176 1177 (void) snprintf(lockpath, sizeof (lockpath), 1178 "%s/%s", a_root, LOCK_FILENAME); 1179 1180 /* wait for open to succeed up to limits */ 1181 1182 for (waiter = WAITER_INITIAL; 1183 waiter < WAITER_MAX; 1184 waiter = WAITER_NEXT(waiter)) { 1185 1186 /* LINTED O_CREAT without O_EXCL specified in call to open() */ 1187 fd = open(lockpath, O_CREAT|O_RDWR, LOCK_FILEMODE); 1188 1189 /* break out of loop if file opened */ 1190 1191 if (fd >= 0) { 1192 break; 1193 } 1194 1195 /* failed - exit loop if due to access (permissions) failure */ 1196 1197 if (errno == EACCES) { 1198 break; 1199 } 1200 1201 /* file is busy - wait and try again */ 1202 1203 if (waiter == WAITER_INITIAL) { 1204 log_msg(LOG_MSG_DEBUG, 1205 MSG_LOCK_OPENFILE_SLEEPING, 1206 strerror(errno), waiter); 1207 } 1208 1209 (void) sleep(waiter); 1210 } 1211 1212 /* if open filed generate error message and return error */ 1213 1214 if (fd < 0) { 1215 log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_FAILURE, 1216 strerror(errno)); 1217 perror(lockpath); 1218 return (-1); 1219 } 1220 1221 /* 1222 * lock file opened - acquire exclusive section lock on entire file; 1223 * wait for lockf to succeed up to limits 1224 */ 1225 1226 for (waiter = WAITER_INITIAL; 1227 waiter < WAITER_MAX; 1228 waiter = WAITER_NEXT(waiter)) { 1229 1230 /* acquire exclusive section lock on entire file */ 1231 1232 result = lockf(fd, F_LOCK, 0xFFFFF); 1233 1234 /* break out of loop if entire file locked */ 1235 1236 if (result == 0) { 1237 break; 1238 } 1239 1240 /* file is busy - wait and try again */ 1241 1242 if (waiter == WAITER_INITIAL) { 1243 log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_SLEEP2, 1244 strerror(errno), waiter); 1245 } 1246 1247 (void) sleep(waiter); 1248 } 1249 1250 /* if section lock failed generate error message and return error */ 1251 1252 if (result < 0) { 1253 log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_FAIL2, 1254 strerror(errno)); 1255 perror(lockpath); 1256 (void) close(fd); 1257 return (-1); 1258 } 1259 1260 /* file opened and locked - return success */ 1261 1262 log_msg(LOG_MSG_DEBUG, MSG_LOCK_OPENFILE_SUCCESS, fd); 1263 1264 return (fd); 1265 } 1266 1267 /* 1268 * Name: _lockMatch 1269 * Description: Compare two lock objects using file name match criteria 1270 * Arguments: 1271 * a_s1Lock - first lock object to compare against the second 1272 * a_s2Lock - second lock object to compare against the first 1273 * Returns: 1274 * == 0 - the locks match at some level 1275 * != 0 - the locks do not match at any level 1276 */ 1277 1278 static int 1279 _lockMatch(char *a_s1Lock, char *a_s2Lock) 1280 { 1281 boolean_t s1Sfx = B_FALSE; 1282 boolean_t s2Sfx = B_FALSE; 1283 char *final1Lock = (char *)NULL; 1284 char *final2Lock = (char *)NULL; 1285 char s1Buf[MAXPATHLEN] = {'\0'}; 1286 char s1Prefix[MAXPATHLEN] = {'\0'}; 1287 char s2Buf[MAXPATHLEN] = {'\0'}; 1288 char s2Prefix[MAXPATHLEN] = {'\0'}; 1289 int result = 0; 1290 int s1Cnt; 1291 int s2Cnt = 0; 1292 1293 /* entry assertions */ 1294 1295 assert(a_s1Lock != (char *)NULL); 1296 assert(a_s2Lock != (char *)NULL); 1297 1298 /* entry debugging info */ 1299 1300 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_ENTRY, a_s1Lock, a_s2Lock); 1301 1302 /* 1303 * attempt to find a common anchor between the two locks; that is, 1304 * find the first node in the first lock that matches any node 1305 * in the second lock; for example: 1306 * --> a/b/c vs b/c/d 1307 * -> common anchor is "b"; comparison would expand to: 1308 * --> a/b/c/? vs ?/b/c/d 1309 */ 1310 1311 /* process each node in the first lock */ 1312 1313 for (s1Cnt = 0; ; s1Cnt++) { 1314 /* get next first lock node */ 1315 1316 pkgstrGetToken_r((char *)NULL, a_s1Lock, s1Cnt, "/", 1317 s1Buf, sizeof (s1Buf)); 1318 1319 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_FSTNODE, s1Cnt, s1Buf); 1320 1321 /* exit if no more nodes left */ 1322 1323 if (s1Buf[0] == '\0') { 1324 break; 1325 } 1326 1327 /* discover "." prefix for this node */ 1328 1329 pkgstrGetToken_r((char *)NULL, s1Buf, 0, ".", s1Prefix, 1330 sizeof (s1Prefix)); 1331 1332 s1Sfx = (strlen(s1Prefix) == strlen(s1Buf) ? B_FALSE : B_TRUE); 1333 1334 /* search each second lock node; look for the first node lock */ 1335 1336 for (s2Cnt = 0; ; s2Cnt++) { 1337 /* get next second lock node */ 1338 1339 pkgstrGetToken_r((char *)NULL, a_s2Lock, s2Cnt, "/", 1340 s2Buf, sizeof (s2Buf)); 1341 1342 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_SCNDNODE, s2Cnt, 1343 s2Buf); 1344 1345 /* exit if no nodes left */ 1346 1347 if (s2Buf[0] == '\0') { 1348 break; 1349 } 1350 1351 /* discover "." prefix for this node */ 1352 1353 pkgstrGetToken_r((char *)NULL, s2Buf, 0, ".", s2Prefix, 1354 sizeof (s2Prefix)); 1355 1356 s2Sfx = (strlen(s2Prefix) == 1357 strlen(s2Buf) ? B_FALSE : B_TRUE); 1358 1359 /* 1360 * process this pair of nodes: 1361 * if both nodes do not have a prefix, then directly 1362 * compare the nodes (e.g. a/b vs c/d: a vs c, b vs d) 1363 * and break out of the loop if there is a match; 1364 * otherwise, compare prefixes and break out of the 1365 * loop if there is a match (e.g. a.* / b.* vs 1366 * vs c.* / d.*: a.* vs c.*, a.* vs d.*, b.* vs c.*, 1367 * b.* vs d.*). 1368 */ 1369 1370 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_NODES, s1Buf, 1371 s1Prefix, s1Sfx, s2Buf, s2Prefix, s2Sfx); 1372 1373 if ((s1Sfx == B_FALSE) || (s2Sfx == B_FALSE)) { 1374 /* one doesnt have a prefix direct comparison */ 1375 1376 if (strcmp(s1Buf, s2Buf) == 0) { 1377 log_msg(LOG_MSG_DEBUG, 1378 MSG_LCKMCH_DIRMCH, 1379 s1Buf, s2Buf); 1380 break; 1381 } 1382 1383 /* nodes do not directly match, continue */ 1384 1385 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_DIRNOMCH, 1386 s1Buf, s2Buf); 1387 continue; 1388 } 1389 1390 /* both have prefix, compare prefixes */ 1391 1392 if (strcmp(s1Prefix, s2Prefix) == 0) { 1393 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_PFXMCH, 1394 s1Prefix, s2Prefix); 1395 break; 1396 } 1397 1398 /* prefixes do not match, continue */ 1399 1400 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_PFXNOMCH, s1Prefix, 1401 s2Prefix); 1402 } 1403 1404 /* 1405 * match found if not at the end of the second lock node list, 1406 * break out of loop because some match between the two lock 1407 * objects has been found 1408 */ 1409 1410 if (s2Buf[0] != '\0') { 1411 break; 1412 } 1413 } 1414 1415 /* 1416 * at this point, either a match has been found between the nodes in 1417 * the two lock objects, or there is no commonality at all between 1418 * the two lock objects. 1419 * 1420 * s1Buf[0] == '\0' && s2Buf[0] == '\0': 1421 * --> nothing in first lock matches anything in second lock: 1422 * ----> (s1Cnt == 1) || (s2Cnt == 1) && (s1Sfx == B_FALSE) 1423 * ----> || (s2Sfx == B_FALSE) 1424 * --------> an absolute lock do not match 1425 * ----> else both object locks have nothing in common - match 1426 * 1427 * s2Buf[0] != '\0' && s1Buf[0] != '\0' && s1Cnt > 0 && s2Cnt > 0 1428 * --> locks have incompatible overlaps - no match, such as: 1429 * ----> a.* / b.* / c.* / d.* and y.* / b.* / c.* 1430 * 1431 * s1Cnt == 0 && s2Cnt == 0: 1432 * --> locks begin with same node - do comparison 1433 * 1434 * s1Cnt != 0 && s2Cnt == 0 && s2Buf[0] != '\0' 1435 * --> second lock is subset of first lock 1436 * 1437 * s2Cnt == 0 && s2Buf[0] != '\0': 1438 * --> s1Buf[s1Cnt] matches s2Buf[0] - second is subset of first 1439 * 1440 * s2Cnt != 0 && s1Cnt == 0 && s1Buf[0] != '\0': 1441 * --> first lock is subset of second lock 1442 * 1443 */ 1444 1445 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_FSTLCK, s1Cnt, s1Buf, 1446 s1Prefix, s1Sfx); 1447 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_SCNDLCK, s2Cnt, s2Buf, 1448 s2Prefix, s2Sfx); 1449 1450 /* process any direct comparisons that might be possible */ 1451 1452 if ((s1Buf[0] == '\0') && (s2Buf[0] == '\0')) { 1453 /* nothing in first matches anything in second lock */ 1454 1455 if (((s1Cnt == 1) || (s2Cnt == 1)) && 1456 ((s1Sfx == B_FALSE) || (s2Sfx == B_FALSE))) { 1457 /* two absolute locks match (e.g. 'file' and 'dir') */ 1458 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_ABSNOMCH, a_s1Lock, 1459 a_s2Lock); 1460 return (1); 1461 } 1462 1463 /* two object locks have nothing in common: match */ 1464 1465 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_OBJMCH, a_s1Lock, a_s2Lock); 1466 1467 return (0); 1468 } 1469 1470 if ((s2Buf[0] != '\0') && (s1Buf[0] != '\0') && 1471 (s1Cnt > 0) && (s2Cnt > 0)) { 1472 /* incompatible overlapping objects */ 1473 1474 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_OVLPNOMCH, a_s1Lock, a_s2Lock, 1475 s1Cnt+1, s1Buf); 1476 1477 return (1); 1478 } 1479 1480 /* 1481 * must compare each node of each lock to determine match; 1482 * start off at the first byte of both locks 1483 */ 1484 1485 final1Lock = a_s1Lock; 1486 final2Lock = a_s2Lock; 1487 1488 if ((s1Cnt == 0) && (s2Cnt == 0)) { 1489 /* both have first match - start comparison from the begining */ 1490 1491 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_SAME, a_s1Lock, a_s2Lock, 1492 s1Buf); 1493 1494 } else if ((s1Cnt != 0) && (s2Cnt == 0) && (s2Buf[0] != '\0')) { 1495 /* second lock begins somewhere inside of the first lock */ 1496 1497 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_SCNDSUB, a_s2Lock, a_s1Lock, 1498 s1Cnt+1, s1Buf); 1499 1500 /* advance first lock to matching node in second lock */ 1501 1502 if (strchr(a_s1Lock, '/') != (char *)NULL) { 1503 for (; s1Cnt > 0 && (*final1Lock != '\0'); 1504 final1Lock++) { 1505 if (*final1Lock == '/') { 1506 s1Cnt--; 1507 } 1508 } 1509 } 1510 } else if ((s2Cnt != 0) && (s1Cnt == 0) && (s1Buf[0] != '\0')) { 1511 /* first lock begins somewhere inside of the second lock */ 1512 1513 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_FRSTSUB, a_s1Lock, a_s2Lock, 1514 s2Cnt+1, s2Buf); 1515 1516 /* advance second lock to matching node in first lock */ 1517 1518 if (strchr(a_s2Lock, '/') != (char *)NULL) { 1519 for (; s2Cnt > 0 && (*final2Lock != '\0'); 1520 final2Lock++) { 1521 if (*final2Lock == '/') { 1522 s2Cnt--; 1523 } 1524 } 1525 } 1526 } else { 1527 /* unknown condition (probably impossible): directly compare */ 1528 1529 log_msg(LOG_MSG_ERR, MSG_LCKMCH_DONTKNOW, a_s1Lock, a_s2Lock); 1530 } 1531 1532 /* 1533 * locks have common node - compare from that node forward 1534 */ 1535 1536 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_READY, final1Lock, final2Lock); 1537 1538 /* compare each node (prefix) - success when no more nodes to compare */ 1539 1540 for (s1Cnt = 0; ; s1Cnt++) { 1541 /* get next node from first lock */ 1542 1543 pkgstrGetToken_r((char *)NULL, final1Lock, s1Cnt, "/", s1Buf, 1544 sizeof (s1Buf)); 1545 1546 /* success if at end of lock */ 1547 1548 if (s1Buf[0] == '\0') { 1549 break; 1550 } 1551 1552 /* get next node from second lock */ 1553 1554 pkgstrGetToken_r((char *)NULL, final2Lock, s1Cnt, "/", s2Buf, 1555 sizeof (s2Buf)); 1556 1557 /* success if at end of lock */ 1558 1559 if (s2Buf[0] == '\0') { 1560 break; 1561 } 1562 1563 /* compare both nodes */ 1564 1565 result = fnmatch(s1Buf, s2Buf, 0); 1566 if (result != 0) { 1567 result = fnmatch(s2Buf, s1Buf, 0); 1568 } 1569 1570 /* failure if nodes do not match */ 1571 1572 if (result != 0) { 1573 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_NODEFAIL, 1574 s1Cnt, s1Buf, s2Buf); 1575 return (1); 1576 } 1577 1578 /* nodes match, continue and compare next set of nodes */ 1579 1580 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_NODEOK, s1Cnt, s1Buf, s2Buf); 1581 } 1582 1583 /* no more nodes to compare - locks match */ 1584 1585 log_msg(LOG_MSG_DEBUG, MSG_LCKMCH_MATCHOK, final1Lock, final2Lock); 1586 1587 return (0); 1588 } 1589 1590 /* 1591 * Name: _findLock 1592 * Description: Locate specified lock in lock file 1593 * Arguments: 1594 * a_theLock - lock object filled with contents of lock (if found) 1595 * r_recordNum - will contain record number if lock found 1596 * - will be RECORDNUM_NONE if lock not found 1597 * a_fd - file descriptor opened on the lock file 1598 * a_key - key associated with lock to look up 1599 * a_object - object associated with lock to look up 1600 * Returns: 1601 * FINDLOCK_FOUND - specified lock found; a_theLock contains contents 1602 * of found lock, r_recordNum contain record number of lock 1603 * FINDLOCK_ERROR - failed - error occurred looking up the lock 1604 * FINDLOCK_NOTFOUND - specified object is not locked 1605 * FINDLOCK_KEYMISMATCH - object lock found but specified key doesnt match 1606 * FINDLOCK_LOCKED - object lock found but no key specified 1607 * FINDLOCK_NOTLOCKED - object not locked 1608 */ 1609 1610 static FINDLOCK_T 1611 _findLock(LOCK_T *a_theLock, RECORDNUM_T *r_recordNum, 1612 int a_fd, char *a_object, char *a_key) 1613 { 1614 ADMINLOCK_T *pll; 1615 char *pld; 1616 int recordNum = 0; 1617 long pls; 1618 off_t pos; 1619 1620 /* reset returned record number to "none" */ 1621 1622 *r_recordNum = RECORDNUM_NONE; 1623 1624 /* localize references to lock object */ 1625 1626 pld = &a_theLock->_lrLockData[0]; 1627 pll = &a_theLock->_lrLock; 1628 pls = sizeof (a_theLock->_lrLockData); 1629 1630 /* zero out returned lock data */ 1631 1632 bzero(pld, pls); 1633 1634 /* debug info before processing lock file */ 1635 1636 log_msg(LOG_MSG_DEBUG, MSG_LOCK_FINDLOCK_ENTRY, 1637 a_object, a_key); 1638 1639 /* rewind to beginning of lock file */ 1640 1641 pos = lseek(a_fd, 0L, SEEK_SET); 1642 if (pos == (off_t)-1) { 1643 log_msg(LOG_MSG_ERR, MSG_LOCK_FINDLOCK_LSEEK_FAILURE, 1644 a_object, a_key, strerror(errno)); 1645 return (FINDLOCK_ERROR); 1646 } 1647 1648 /* read and process each lock */ 1649 1650 for (; pread(a_fd, pld, pls, pls*recordNum) == pls; recordNum++) { 1651 /* debug info on this lock */ 1652 1653 log_msg(LOG_MSG_DEBUG, MSG_LOCK_FINDLOCK_READRECORD, 1654 recordNum, pll->lockCount, 1655 pll->lockObject, pll->lockKey, pll->lockPid, 1656 pll->lockZoneId); 1657 1658 /* continue if object is not the one we are looking for */ 1659 1660 if (_lockMatch(a_object, pll->lockObject) != 0) { 1661 continue; 1662 } 1663 1664 /* 1665 * object found; return locked if searching for no key 1666 */ 1667 1668 if (*a_key == '\0') { 1669 /* no key specified - object is locked */ 1670 *r_recordNum = recordNum; 1671 return (FINDLOCK_LOCKED); 1672 } 1673 1674 /* 1675 * object found and keys present; see if keys match 1676 */ 1677 1678 if (strcmp(pll->lockKey, a_key) != 0) { 1679 /* keys do not match */ 1680 *r_recordNum = recordNum; 1681 return (FINDLOCK_KEYMISMATCH); 1682 } 1683 1684 /* object found and keys match - return match */ 1685 1686 log_msg(LOG_MSG_DEBUG, MSG_LOCK_FINDLOCK_FOUND); 1687 1688 *r_recordNum = recordNum; 1689 return (FINDLOCK_FOUND); 1690 } 1691 1692 /* object not locked - return error if key supplied */ 1693 1694 if (*a_key != '\0') { 1695 return (FINDLOCK_NOTLOCKED); 1696 } 1697 1698 /* object not locked and key not supplied - no lock found */ 1699 1700 log_msg(LOG_MSG_DEBUG, MSG_LOCK_FINDLOCK_NOTFOUND); 1701 1702 return (FINDLOCK_NOTFOUND); 1703 } 1704 1705 /* 1706 * Name: _addLock 1707 * Description: Add a new lock to the lock file 1708 * Arguments: 1709 * r_key - if lock acquired key is placed here 1710 * a_fd - file descriptor opened on the lock file 1711 * a_object - object to lock 1712 * a_exclusive - type of lock to add: 1713 * == 0 - shared lock 1714 * != 0 - exclusive lock 1715 * a_pid - if != 0 process i.d. to associate with this lock 1716 * a_zid - if >= 0 zone i.d. to associate with this lock 1717 * Returns: int 1718 * == 0 - success 1719 * != 0 - failure 1720 */ 1721 1722 static int 1723 _addLock(char *r_key, int a_fd, char *a_object, int a_exclusive, pid_t a_pid, 1724 zoneid_t a_zid) 1725 { 1726 LOCK_T theLock; 1727 char *key; 1728 off_t pos; 1729 ssize_t result; 1730 1731 /* get unique i.d. for this lock */ 1732 1733 key = _getUniqueId(); 1734 1735 /* determine record number for next record in lock file */ 1736 1737 pos = lseek(a_fd, 0L, SEEK_END); 1738 if (pos == (off_t)-1) { 1739 log_msg(LOG_MSG_ERR, MSG_LOCK_ADDLOCK_LSEEK_FAILURE, 1740 a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR, 1741 a_object, strerror(errno)); 1742 return (1); 1743 } 1744 1745 /* allocate storace for this lock */ 1746 1747 bzero(&theLock, sizeof (theLock)); 1748 1749 /* fill in components of the lock */ 1750 1751 (void) strlcpy(theLock._lrLock.lockObject, a_object, 1752 LOCK_OBJECT_MAXLEN); 1753 (void) strlcpy(theLock._lrLock.lockKey, key, LOCK_KEY_MAXLEN); 1754 theLock._lrLock.lockCount = 1; 1755 theLock._lrLock.lockPid = (a_pid > 0 ? a_pid : 0); 1756 theLock._lrLock.lockRecordNum = (pos == 0 ? 0 : (pos/sizeof (LOCK_T))); 1757 theLock._lrLock.lockExclusive = a_exclusive; 1758 theLock._lrLock.lockZoneId = (a_zid >= 0 ? a_zid : -1); 1759 1760 /* debug info on new lock */ 1761 1762 log_msg(LOG_MSG_DEBUG, MSG_LOCK_ADDLOCK_ADDING, 1763 a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR, 1764 pos, theLock._lrLock.lockObject, theLock._lrLock.lockKey, 1765 theLock._lrLock.lockPid, theLock._lrLock.lockZoneId); 1766 1767 /* write the new lock record to the end of the lock file */ 1768 1769 result = pwrite(a_fd, &theLock, LOCK_SIZE, pos); 1770 if (result != LOCK_SIZE) { 1771 log_msg(LOG_MSG_ERR, MSG_LOCK_ADDLOCK_PWRITE_FAILURE, 1772 a_exclusive ? MSG_LOCK_EXC : MSG_LOCK_SHR, 1773 a_object, strerror(errno)); 1774 return (1); 1775 } 1776 1777 /* output the key assigned to standard out */ 1778 1779 (void) strncpy(r_key, key, LOCK_KEY_MAXLEN); 1780 1781 return (0); 1782 } 1783 1784 static int 1785 _incrementLockCount(int a_fd, LOCK_T *a_theLock) 1786 { 1787 ADMINLOCK_T *pll; 1788 char *pld; 1789 long pls; 1790 ssize_t result; 1791 1792 /* localize references to lock object */ 1793 1794 pld = &a_theLock->_lrLockData[0]; 1795 pll = &a_theLock->_lrLock; 1796 pls = sizeof (a_theLock->_lrLockData); 1797 1798 /* debug info on incrementing lock */ 1799 1800 log_msg(LOG_MSG_DEBUG, MSG_LOCK_INCLOCK_ENTRY, 1801 a_theLock->_lrLock.lockExclusive ? 1802 MSG_LOCK_EXC : MSG_LOCK_SHR, 1803 pll->lockRecordNum, pll->lockCount); 1804 1805 /* increment lock count */ 1806 1807 pll->lockCount++; 1808 1809 /* write out updated lock */ 1810 1811 result = pwrite(a_fd, pld, pls, pll->lockRecordNum*pls); 1812 if (result != pls) { 1813 log_msg(LOG_MSG_ERR, MSG_LOCK_INCLOCK_PWRITE_FAILURE, 1814 a_theLock->_lrLock.lockExclusive ? 1815 MSG_LOCK_EXC : MSG_LOCK_SHR, 1816 a_theLock->_lrLock.lockObject, 1817 strerror(errno)); 1818 return (1); 1819 } 1820 1821 /* debug info lock incremented */ 1822 1823 log_msg(LOG_MSG_DEBUG, MSG_LOCK_INCLOCK_DONE, 1824 pll->lockRecordNum, pll->lockCount, 1825 pll->lockObject, pll->lockKey); 1826 1827 return (0); 1828 } 1829 1830 /* 1831 * Name: _validateLock 1832 * Description: determine if a specified lock is valid; if the lock is not valid 1833 * then remove the lock 1834 * Arguments: a_fd - file descriptor opened on the lock file 1835 * a_theLock - lock object to validate 1836 * Returns: boolean_t 1837 * B_TRUE - the lock is valid 1838 * B_FALSE - the lock is not valid and has been removed 1839 */ 1840 1841 static boolean_t 1842 _validateLock(int a_fd, LOCK_T *a_theLock, int a_quiet) 1843 { 1844 ADMINLOCK_T *pll; 1845 char path[MAXPATHLEN]; 1846 1847 /* localize references to lock object */ 1848 1849 pll = &a_theLock->_lrLock; 1850 1851 /* return true if no process i.d. associated with lock */ 1852 1853 if (pll->lockPid <= 0) { 1854 log_msg(LOG_MSG_DEBUG, MSG_VALID_NOPID, pll->lockObject); 1855 return (B_TRUE); 1856 } 1857 1858 /* see if the zone i.d. matches */ 1859 1860 if (pll->lockZoneId != getzoneid()) { 1861 log_msg(LOG_MSG_DEBUG, MSG_VALID_BADZID, pll->lockObject, 1862 pll->lockZoneId, getzoneid()); 1863 return (B_TRUE); 1864 } else { 1865 log_msg(LOG_MSG_DEBUG, MSG_VALID_ZIDOK, pll->lockObject, 1866 pll->lockZoneId, getzoneid()); 1867 } 1868 1869 /* see if the process is still active */ 1870 1871 pkgstrPrintf_r(path, sizeof (path), "/proc/%d", pll->lockPid); 1872 if (access(path, F_OK) == 0) { 1873 log_msg(LOG_MSG_DEBUG, MSG_VALID_OK, pll->lockObject, 1874 pll->lockPid, path); 1875 return (B_TRUE); 1876 } 1877 1878 log_msg(LOG_MSG_DEBUG, MSG_VALID_NOTOK, pll->lockObject, pll->lockPid, 1879 path); 1880 1881 /* delete this lock */ 1882 1883 log_msg(a_quiet ? LOG_MSG_DEBUG : LOG_MSG_WRN, 1884 MSG_VALID_STALE, pll->lockObject, pll->lockPid, 1885 pll->lockZoneId); 1886 1887 _decrementLockCount(a_fd, a_theLock); 1888 1889 return (B_FALSE); 1890 } 1891 1892 static int 1893 _decrementLockCount(int a_fd, LOCK_T *a_theLock) 1894 { 1895 ADMINLOCK_T *pll; 1896 LOCK_T tmpLock; 1897 RECORDNUM_T lastRecord; 1898 char *pld; 1899 long pls; 1900 off_t lastPos; 1901 ssize_t result; 1902 int res; 1903 1904 /* localize references to lock object */ 1905 1906 pld = &a_theLock->_lrLockData[0]; 1907 pll = &a_theLock->_lrLock; 1908 pls = sizeof (a_theLock->_lrLockData); 1909 1910 /* decrement lock count */ 1911 1912 pll->lockCount--; 1913 1914 /* if lock count > 0 then write out and leave locked */ 1915 1916 if (pll->lockCount > 0) { 1917 log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_DECING, 1918 a_theLock->_lrLock.lockExclusive ? 1919 MSG_LOCK_EXC : MSG_LOCK_SHR, 1920 pll->lockRecordNum, pll->lockCount); 1921 1922 result = pwrite(a_fd, pld, pls, pll->lockRecordNum*pls); 1923 if (result != pls) { 1924 log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_PWRITE_FAILURE, 1925 a_theLock->_lrLock.lockExclusive ? 1926 MSG_LOCK_EXC : MSG_LOCK_SHR, 1927 a_theLock->_lrLock.lockObject, 1928 strerror(errno)); 1929 return (1); 1930 } 1931 1932 log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_DONE, 1933 pll->lockRecordNum, pll->lockCount, 1934 pll->lockObject, pll->lockKey); 1935 1936 return (0); 1937 } 1938 1939 /* 1940 * lock count zero - erase the record 1941 */ 1942 1943 /* find last record in the lock file */ 1944 1945 lastPos = lseek(a_fd, 0L, SEEK_END); /* get size of lock file */ 1946 if (lastPos == (off_t)-1) { 1947 log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_LSEEK_FAILURE, 1948 a_theLock->_lrLock.lockExclusive ? 1949 MSG_LOCK_EXC : MSG_LOCK_SHR, 1950 a_theLock->_lrLock.lockObject, 1951 strerror(errno)); 1952 return (1); 1953 } 1954 1955 lastRecord = (lastPos/pls)-1; /* convert size to record # */ 1956 1957 log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_REMOVE, 1958 lastPos, lastRecord, pll->lockRecordNum); 1959 1960 /* see if removing last record of file */ 1961 1962 if (lastRecord == pll->lockRecordNum) { 1963 /* debug info removing last record */ 1964 1965 log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_LASTONE, 1966 a_theLock->_lrLock.lockExclusive ? 1967 MSG_LOCK_EXC : MSG_LOCK_SHR, 1968 lastRecord, lastPos-pls); 1969 1970 /* removing last record of file, truncate */ 1971 1972 res = ftruncate(a_fd, lastPos-pls); 1973 if (res == -1) { 1974 log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_FTRUNCATE_FAILURE, 1975 a_theLock->_lrLock.lockExclusive ? 1976 MSG_LOCK_EXC : MSG_LOCK_SHR, 1977 a_theLock->_lrLock.lockObject, 1978 strerror(errno)); 1979 return (1); 1980 } 1981 return (0); 1982 } 1983 1984 /* 1985 * not removing last record of file: 1986 * read last record, truncate file one record, 1987 * replace record to be removed with last record read 1988 */ 1989 1990 log_msg(LOG_MSG_DEBUG, MSG_LOCK_DECLOCK_REMOVING, 1991 pll->lockRecordNum, lastRecord, lastPos-pls); 1992 1993 /* read in the last record */ 1994 1995 result = pread(a_fd, tmpLock._lrLockData, pls, lastRecord*pls); 1996 if (result != pls) { 1997 log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_PREAD_FAILURE, 1998 a_theLock->_lrLock.lockExclusive ? 1999 MSG_LOCK_EXC : MSG_LOCK_SHR, 2000 a_theLock->_lrLock.lockObject, 2001 strerror(errno)); 2002 return (1); 2003 2004 } 2005 2006 /* truncate lock file removing the last record (just read in) */ 2007 2008 res = ftruncate(a_fd, lastPos-pls); 2009 if (res == -1) { 2010 log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_FTRUNCATE_FAILURE, 2011 a_theLock->_lrLock.lockExclusive ? 2012 MSG_LOCK_EXC : MSG_LOCK_SHR, 2013 a_theLock->_lrLock.lockObject, 2014 strerror(errno)); 2015 return (1); 2016 } 2017 2018 /* update record to indicate its new position in the lock file */ 2019 2020 tmpLock._lrLock.lockRecordNum = pll->lockRecordNum; 2021 2022 /* write out the updated record to the new location */ 2023 2024 result = pwrite(a_fd, tmpLock._lrLockData, pls, pll->lockRecordNum*pls); 2025 if (result != pls) { 2026 log_msg(LOG_MSG_ERR, MSG_LOCK_DECLOCK_PWRITE_FAILURE, 2027 a_theLock->_lrLock.lockExclusive ? 2028 MSG_LOCK_EXC : MSG_LOCK_SHR, 2029 a_theLock->_lrLock.lockObject, 2030 strerror(errno)); 2031 return (1); 2032 } 2033 2034 return (0); 2035 } 2036 2037 /* 2038 * Name: _getUniqueId 2039 * Description: Generate a unique ID that can be used as a key for a new lock 2040 * Arguments: None 2041 * Returns: char * 2042 * == NULL - error, no key generated 2043 * != NULL - generated key 2044 * NOTE: Any results returned is placed in new storage for the 2045 * calling method. The caller must use 'lu_memFree' to dispose 2046 * of the storage once the results are no longer needed. 2047 */ 2048 2049 static char * 2050 _getUniqueId(void) 2051 { 2052 char newkey[LOCK_KEY_MAXLEN]; 2053 hrtime_t hretime; 2054 struct tm tstruct; 2055 time_t thetime; 2056 2057 /* 2058 * generate own unique key - the key is the 2059 * same length as unique uid but contains different information that 2060 * is as unique as can be made - include current hires time (nanosecond 2061 * real timer). Such a unique i.d. will look like: 2062 * 0203104092-1145345-0004e94d6af481a0 2063 */ 2064 2065 hretime = gethrtime(); 2066 2067 thetime = time((time_t *)NULL); 2068 (void) localtime_r(&thetime, &tstruct); 2069 2070 (void) snprintf(newkey, sizeof (newkey), 2071 "%02d%02d%02d%03d-%02d%02d%02d%d-%016llx", tstruct.tm_mday, 2072 tstruct.tm_mon, tstruct.tm_year, tstruct.tm_yday, 2073 tstruct.tm_hour, tstruct.tm_min, tstruct.tm_sec, 2074 tstruct.tm_wday, hretime); 2075 2076 log_msg(LOG_MSG_DEBUG, MSG_LOCK_GENUID_INTERNAL, newkey); 2077 return (strdup(newkey)); 2078 } 2079 2080 /* 2081 * Name: sigint_handler 2082 * Synopsis: SIGINT interrupt handler 2083 * Description: Catch the "SIGINT" signal; increment signal_received 2084 * global variable, 2085 * Arguments: signo - [RO, *RO] - (int) 2086 * Signal number that was caught 2087 * Returns: void 2088 */ 2089 2090 static void 2091 sigint_handler(int a_signo) 2092 { 2093 signal_received++; 2094 } 2095 2096 /* 2097 * Name: sighup_handler 2098 * Synopsis: SIGHUP interrupt handler 2099 * Description: Catch the "SIGHUP" signal; increment signal_received 2100 * global variable, 2101 * Arguments: signo - [RO, *RO] - (int) 2102 * Signal number that was caught 2103 * Returns: void 2104 */ 2105 2106 static void 2107 sighup_handler(int a_signo) 2108 { 2109 signal_received++; 2110 } 2111