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
admin_lock(int argc,char ** argv)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 int 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
lock_acquire(LOCK_T * a_theLock,int * a_fd,char * a_root,char * a_key,char * a_object,int a_quiet,int a_wait,long a_timeout,int a_exclusive,char * a_altRoot,pid_t a_pid,zoneid_t a_zid)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
lock_release(int a_fd,char * a_key,char * a_object,int a_quiet)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
lock_status(int a_fd,char * a_key,char * a_object,int a_quiet)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
_lock_acquire(LOCK_T * a_theLock,int a_fd,char * a_key,char * a_object,int a_quiet,int a_exclusive,pid_t a_pid,zoneid_t a_zid)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
_openLockFile(char * a_root)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
_lockMatch(char * a_s1Lock,char * a_s2Lock)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
_findLock(LOCK_T * a_theLock,RECORDNUM_T * r_recordNum,int a_fd,char * a_object,char * a_key)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
_addLock(char * r_key,int a_fd,char * a_object,int a_exclusive,pid_t a_pid,zoneid_t a_zid)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
_incrementLockCount(int a_fd,LOCK_T * a_theLock)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
_validateLock(int a_fd,LOCK_T * a_theLock,int a_quiet)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
_decrementLockCount(int a_fd,LOCK_T * a_theLock)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 *
_getUniqueId(void)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
sigint_handler(int a_signo)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
sighup_handler(int a_signo)2107 sighup_handler(int a_signo)
2108 {
2109 signal_received++;
2110 }
2111