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