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