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