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