xref: /illumos-gate/usr/src/lib/libinstzones/common/zones_locks.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 /*
30  * Module:	zones_locks.c
31  * Group:	libinstzones
32  * Description:	Provide "zones" locking interfaces for install consolidation
33  *		code
34  *
35  * Public Methods:
36  *
37  * _z_acquire_lock - acquire a lock on an object on a zone
38  * _z_adjust_lock_object_for_rootpath - Given a lock object and a root path,
39  *	if the root path is not
40  * _z_lock_zone - Acquire specified locks on specified zone
41  * _z_lock_zone_object - lock a single lock object in a specified zone
42  * _z_release_lock - release a lock held on a zone
43  * _z_unlock_zone - Released specified locks on specified zone
44  * _z_unlock_zone_object - unlock a single lock object in a specified zone
45  */
46 
47 /*
48  * System includes
49  */
50 
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <fcntl.h>
55 #include <ctype.h>
56 #include <sys/types.h>
57 #include <sys/param.h>
58 #include <string.h>
59 #include <strings.h>
60 #include <stdarg.h>
61 #include <limits.h>
62 #include <errno.h>
63 #include <time.h>
64 #include <stropts.h>
65 #include <libintl.h>
66 #include <locale.h>
67 #include <assert.h>
68 
69 /*
70  * local includes
71  */
72 
73 #include "instzones_lib.h"
74 #include "zones_strings.h"
75 
76 /*
77  * Private structures
78  */
79 
80 /*
81  * Library Function Prototypes
82  */
83 
84 /*
85  * Local Function Prototypes
86  */
87 
88 boolean_t	_z_adjust_lock_object_for_rootpath(char **r_result,
89 		    char *a_lockObject);
90 boolean_t	_z_acquire_lock(char **r_lockKey, char *a_zoneName,
91 		    char *a_lock, pid_t a_pid, boolean_t a_wait);
92 boolean_t	_z_lock_zone(zoneListElement_t *a_zlst,
93 		    ZLOCKS_T a_lflags);
94 boolean_t	_z_lock_zone_object(char **r_objectLocks,
95 		    char *a_zoneName, char *a_lockObject,
96 		    pid_t a_pid, char *a_waitingMsg,
97 		    char *a_busyMsg);
98 boolean_t	_z_release_lock(char *a_zoneName, char *a_lock,
99 		    char *a_key, boolean_t a_wait);
100 		    boolean_t	_z_unlock_zone(zoneListElement_t *a_zlst,
101 		    ZLOCKS_T a_lflags);
102 boolean_t	_z_unlock_zone_object(char **r_objectLocks,
103 		    char *a_zoneName, char *a_lockObject,
104 		    char *a_errMsg);
105 
106 /*
107  * global internal (private) declarations
108  */
109 
110 /*
111  * *****************************************************************************
112  * global external (public) functions
113  * *****************************************************************************
114  */
115 
116 /*
117  * Name:	_z_acquire_lock
118  * Description:	acquire a lock on an object on a zone
119  * Arguments:	r_lockKey - [RW, *RW] - (char *)
120  *			Pointer to handle to string representing the lock key
121  *			associated with the lock object to be acquired - this
122  *			key is returned when the lock is acquired and must be
123  *			provided when releasing the lock
124  *			== (char *)NULL - lock not acquired
125  *		a_zoneName - [RO, *RO] - (char *)
126  *			Pointer to string representing the name of the zone to
127  *			acquire the specified lock on
128  *		a_lockObject - [RO, *RO] - (char *)
129  *			Pointer to string representing the lock object to
130  *			acquire on the specified zone
131  *		a_pid - [RO, *RO] - (pid_t)
132  *			Process i.d. to associate with this lock
133  *			== 0 - no process i.d. associated with the lock
134  *		a_wait - [RO, *RO] - (int)
135  *			Determines what to do if the lock cannot be acquired:
136  *			== B_TRUE - wait for the lock to be acquired
137  *			== B_FALSE - do not wait for the lock to be acquired
138  * Returns:	boolean_t
139  *			B_TRUE - lock acquired
140  *			B_FALSE - lock not acquired
141  */
142 
143 boolean_t
144 _z_acquire_lock(char **r_lockKey, char *a_zoneName, char *a_lockObject,
145 	pid_t a_pid, boolean_t a_wait)
146 {
147 	argArray_t	*args;
148 	boolean_t	b;
149 	char		*adjustedLockObject = (char *)NULL;
150 	char		*p;
151 	char		*results = (char *)NULL;
152 	int		r;
153 	int		status;
154 
155 	/* entry assertions */
156 
157 	assert(a_zoneName != (char *)NULL);
158 	assert(a_lockObject != (char *)NULL);
159 	assert(*a_lockObject != '\0');
160 	assert(r_lockKey != (char **)NULL);
161 
162 	/* entry debugging info */
163 
164 	_z_echoDebug(DBG_ZONES_APLK, a_zoneName, a_lockObject, a_pid);
165 
166 	/* reset returned lock key handle */
167 
168 	*r_lockKey = (char *)NULL;
169 
170 	/*
171 	 * Only one lock file must ever be used - the one located on the root
172 	 * file system of the currently running Solaris instance. To allow for
173 	 * alternative roots to be properly locked, adjust the lock object to
174 	 * take root path into account; if necessary, the root path will be
175 	 * prepended to the lock object.
176 	 */
177 
178 	b = _z_adjust_lock_object_for_rootpath(&adjustedLockObject,
179 	    a_lockObject);
180 	if (!b) {
181 		return (B_FALSE);
182 	}
183 
184 	/*
185 	 * construct command arguments:
186 	 * pkgadm lock -a -q -o adjustedLockObject [ -w -W timeout ]
187 	 *		[ -p a_pid -z zoneid ]
188 	 */
189 
190 	args = _z_new_args(20);			/* generate new arg list */
191 	(void) _z_add_arg(args, PKGADM_CMD);	/* pkgadm command */
192 	(void) _z_add_arg(args, "lock");		/* lock sub-command */
193 	(void) _z_add_arg(args, "-a");		/* acquire lock */
194 	(void) _z_add_arg(args, "-q");		/* quiet (no extra messages) */
195 	(void) _z_add_arg(args, "-o");		/* object to acquire */
196 	(void) _z_add_arg(args, "%s", adjustedLockObject);
197 
198 	/* add [ -w -W timeout ] if waiting for lock */
199 
200 	if (a_wait == B_TRUE) {
201 		(void) _z_add_arg(args, "-w");		/* wait */
202 		(void) _z_add_arg(args, "-W");		/* wait timeout */
203 		(void) _z_add_arg(args, "%ld",
204 		    (long)MAX_RETRIES*RETRY_DELAY_SECS);
205 	}
206 
207 	/* add process/zone i.d.s if process i.d. provided */
208 
209 	if (a_pid > 0) {
210 		(void) _z_add_arg(args, "-p");	/* lock valid process i.d. */
211 		(void) _z_add_arg(args, "%ld", getpid());
212 		(void) _z_add_arg(args, "-z");	/* lock valid zone i.d. */
213 		(void) _z_add_arg(args, "%ld", getzoneid());
214 	}
215 
216 	/* execute command */
217 
218 	r = _z_zone_exec(&status, &results, (char *)NULL, PKGADM_CMD,
219 	    _z_get_argv(args), a_zoneName, (int *)NULL);
220 
221 	/* free generated argument list */
222 
223 	_z_free_args(args);
224 
225 	/* return error if failed to acquire */
226 
227 	if ((r != 0) || (status != 0)) {
228 		_z_echoDebug(DBG_ZONES_APLK_EXIT, a_zoneName,
229 		    adjustedLockObject, a_pid, r, status,
230 		    results ? results : "");
231 
232 		/* free up results if returned */
233 		if (results) {
234 			free(results);
235 		}
236 
237 		/* free adjusted lock object */
238 		free(adjustedLockObject);
239 
240 		/* return failure */
241 		return (B_FALSE);
242 	}
243 
244 	/* return success if no results returned */
245 
246 	if (results == (char *)NULL) {
247 		return (B_TRUE);
248 	}
249 
250 	/* return the lock key */
251 
252 	p = _z_strGetToken((char *)NULL, results, 0, "\n");
253 	_z_strRemoveLeadingWhitespace(&p);
254 	*r_lockKey = p;
255 
256 	/* exit debugging info */
257 
258 	_z_echoDebug(DBG_ZONES_APLK_RESULTS, a_zoneName, adjustedLockObject, p,
259 	    results);
260 
261 	/* free up results */
262 
263 	free(results);
264 
265 	/* free adjusted lock object */
266 
267 	free(adjustedLockObject);
268 
269 	/* return success */
270 
271 	return (B_TRUE);
272 }
273 
274 /*
275  * Name:	_z_adjust_lock_object_for_rootpath
276  * Description:	Given a lock object and a root path, if the root path is not
277  *		the current running system root, then alter the lock object
278  *		to contain a reference to the root path. Only one lock file must
279  *		ever be used to create and maintain locks - the lock file that
280  *		is located in /tmp on the root file system of the currently
281  *		running Solaris instance. To allow for alternative roots to be
282  *		properly locked, if necessary adjust the lock object to take
283  *		root path into account. If the root path does not indicate the
284  *		current running Solaris instance, then the root path will be
285  *		prepended to the lock object.
286  * Arguments:	r_result - [RW, *RW] - (char **)
287  *			Pointer to handle to character string that will contain
288  *			the lock object to use.
289  *		a_lockObject - [RO, *RO] - (char *)
290  *			Pointer to string representing the lock object to adjust
291  * Returns:	boolean_t
292  *			B_TRUE - lock object adjusted and returned
293  *			B_FALSE - unable to adjust lock object
294  * NOTE:    	Any string returned is placed in new storage for the
295  *		calling function. The caller must use 'free' to dispose
296  *		of the storage once the string is no longer needed.
297  *
298  * A lock object has this form:
299  *
300  * name.value [ /name.value [ /name.value ... ] ]
301  *
302  * The "value is either a specific object or a "*", for example:
303  *
304  *     package.test
305  *
306  * This locks the package "test"
307  *
308  *     zone.* /package.*
309  *
310  * This locks all packages on all zones.
311  *
312  *     zone.* /package.SUNWluu
313  *
314  * This locks the package SUNWluu on all zones.
315  *
316  * If a -R rootpath is specified, since there is only one lock file in
317  * the current /tmp, the lock object is modified to include the root
318  * path:
319  *
320  *     rootpath.rootpath/zone.* /package.*
321  *
322  * locks all packages on all zones in the root path "?"
323  *
324  * The characters "/" and "*" and "." cannot be part of the "value"; that
325  * is if "-R /tmp/gmg*dir.test-path" is specified, the final object
326  * cannot be:
327  *
328  *     rootpath./tmp/gmg*dir.test-path/zone.* /package.*
329  *
330  * This would be parsed as:
331  *
332  *      "rootpath." "/tmp" "gmg*dir.test-path" "zone.*" "package.*"
333  *
334  * which is not correct.
335  *
336  * So the path is modified by the loop, in this case it would result in
337  * this lock object:
338  *
339  *     rootpath.-1tmp-1gmg-3dir-2test---path/zone.* /package.*
340  *
341  * This is parsed as:
342  *
343  *     "rootpath.-1tmp-1gmg-3dir-2test---path" "zone.*" "package.*"
344  *
345  * which is then interpreted as:
346  *
347  *     "rootpath./tmp/gmg*dir.test-path" "zone.*" "package.*"
348  */
349 
350 boolean_t
351 _z_adjust_lock_object_for_rootpath(char **r_result, char *a_lockObject)
352 {
353 	char		realRootPath[PATH_MAX] = {'\0'};
354 	const char	*a_rootPath;
355 
356 	/* entry assertions */
357 
358 	assert(r_result != (char **)NULL);
359 	assert(a_lockObject != (char *)NULL);
360 	assert(*a_lockObject != '\0');
361 
362 	/* reset returned lock object handle */
363 
364 	*r_result = (char *)NULL;
365 
366 	/*
367 	 * if root path points to "/" return a duplicate of the passed in
368 	 * lock objects; otherwise, resolve root path and adjust lock object by
369 	 * prepending the rootpath to the lock object (using LOBJ_ROOTPATH).
370 	 */
371 
372 	a_rootPath = _z_global_data._z_root_dir;
373 	if ((a_rootPath == (char *)NULL) ||
374 	    (*a_rootPath == '\0') ||
375 	    (strcmp(a_rootPath, "/") == 0)) {
376 
377 		/* root path not specified or is only "/" - no -R specified */
378 
379 		*r_result = _z_strdup(a_lockObject);
380 	} else {
381 		/*
382 		 * root path is not "" or "/" - -R to an alternative root has
383 		 * been specified; resolve all symbolic links and relative nodes
384 		 * of path name and determine absolute path to the root path.
385 		 */
386 
387 		if (realpath(a_rootPath, realRootPath) == (char *)NULL) {
388 			/* cannot determine absolute path; use path specified */
389 			(void) strlcpy(realRootPath, a_rootPath,
390 			    sizeof (realRootPath));
391 		}
392 
393 		/*
394 		 * if root path points to "/" duplicate existing lock object;
395 		 * otherwise, resolve root path and adjust lock object by
396 		 * prepending the rootpath to the lock object
397 		 */
398 
399 		if (strcmp(realRootPath, "/") == 0) {
400 			*r_result = _z_strdup(a_lockObject);
401 		} else {
402 			char *p1, *p2, *p3;
403 
404 			/* prefix out /.* which cannot be part of lock object */
405 
406 			p1 = _z_calloc((strlen(realRootPath)*2)+1);
407 			for (p3 = p1, p2 = realRootPath; *p2 != '\0'; p2++) {
408 				switch (*p2) {
409 				case '/':	/* / becomes -1 */
410 					*p3++ = '-';
411 					*p3++ = '1';
412 					break;
413 				case '.':	/* . becomes -2 */
414 					*p3++ = '-';
415 					*p3++ = '2';
416 					break;
417 				case '*':	/* * becomes -3 */
418 					*p3++ = '-';
419 					*p3++ = '3';
420 					break;
421 				case '-':	/* - becomes -- */
422 					*p3++ = '-';
423 					*p3++ = '-';
424 					break;
425 				default:	/* do not prefix out char */
426 					*p3++ = *p2;
427 					break;
428 				}
429 			}
430 
431 			/* create "realpath.%s" object */
432 
433 			p2 = _z_strPrintf(LOBJ_ROOTPATH, p1);
434 			free(p1);
435 			if (p2 == (char *)NULL) {
436 				_z_program_error(ERR_MALLOC, "<path>", errno,
437 				    strerror(errno));
438 				return (B_FALSE);
439 			}
440 
441 			/* create "realpath.%s/..." final lock object */
442 
443 			*r_result = _z_strPrintf("%s/%s", p2, a_lockObject);
444 			free(p2);
445 			if (*r_result == (char *)NULL) {
446 				_z_program_error(ERR_MALLOC, "<path>", errno,
447 				    strerror(errno));
448 				return (B_FALSE);
449 			}
450 		}
451 	}
452 
453 	/* exit debugging info */
454 
455 	_z_echoDebug(DBG_ZONES_ADJLCKOBJ_EXIT, a_lockObject, *r_result,
456 	    a_rootPath ? a_rootPath : "",
457 	    realRootPath ? realRootPath : "");
458 
459 	/* return success */
460 
461 	return (B_TRUE);
462 }
463 
464 /*
465  * Name:	_z_lock_zone
466  * Description:	Acquire specified locks on specified zone
467  * Arguments:	a_zlst - [RO, *RW] - (zoneListElement_t *)
468  *			Pointer to zone list structure element describing
469  *			the zone the lock - the structure is updated with
470  *			the lock objects and keys if the locks are acquired
471  *		a_lflags - [RO, *RO] - (ZLOCKS_T)
472  *			Flags indicating which locks to acquire on the zone
473  * Returns:	boolean_t
474  *			== B_TRUE - locks successfully acquired
475  *			== B_FALSE - failed to acquire the locks
476  */
477 
478 boolean_t
479 _z_lock_zone(zoneListElement_t *a_zlst, ZLOCKS_T a_lflags)
480 {
481 	char *scratchName;
482 	boolean_t	b;
483 
484 	/* entry assertions */
485 
486 	assert(a_zlst != (zoneListElement_t *)NULL);
487 
488 	/* entry debugging info */
489 
490 	_z_echoDebug(DBG_ZONES_LCK_ZONE, a_zlst->_zlName, a_lflags);
491 
492 	scratchName = a_zlst->_zlScratchName == NULL ? a_zlst->_zlName :
493 	    a_zlst->_zlScratchName;
494 
495 	/*
496 	 * acquire zone lock
497 	 */
498 
499 	if (a_lflags & ZLOCKS_ZONE_ADMIN) {
500 		/*
501 		 * lock zone administration if not already locked
502 		 * if the lock cannot be released, stop and return an error
503 		 */
504 
505 		_z_echoDebug(DBG_ZONES_LCK_ZONE_ZONEADM, a_zlst->_zlName,
506 		    LOBJ_ZONEADMIN);
507 
508 		b = _z_lock_zone_object(&a_zlst->_zlLockObjects,
509 		    scratchName, LOBJ_ZONEADMIN, (pid_t)0,
510 		    MSG_ZONES_LCK_ZONE_ZONEADM,
511 		    ERR_ZONES_LCK_ZONE_ZONEADM);
512 		if (b == B_FALSE) {
513 			return (b);
514 		}
515 	}
516 
517 	/*
518 	 * acquire package lock
519 	 */
520 
521 	if (a_lflags & ZLOCKS_PKG_ADMIN) {
522 
523 		/*
524 		 * zone administration is locked; lock package administration if
525 		 * not already locked; if the lock cannot be released, stop,
526 		 * release the zone administration lock and return an error
527 		 */
528 
529 		_z_echoDebug(DBG_ZONES_LCK_ZONE_PKGADM, a_zlst->_zlName,
530 		    LOBJ_PKGADMIN);
531 
532 		b = _z_lock_zone_object(&a_zlst->_zlLockObjects,
533 		    scratchName, LOBJ_PKGADMIN, (pid_t)0,
534 		    MSG_ZONES_LCK_ZONE_PKGADM,
535 		    ERR_ZONES_LCK_ZONE_PKGADM);
536 		if (b == B_FALSE) {
537 			(void) _z_unlock_zone(a_zlst, a_lflags);
538 			return (b);
539 		}
540 	}
541 
542 	/*
543 	 * acquire patch lock
544 	 */
545 
546 	if (a_lflags & ZLOCKS_PATCH_ADMIN) {
547 
548 		/*
549 		 * zone and package administration is locked; lock patch
550 		 * administration; if the lock cannot be released, stop,
551 		 * release the other locks and return an error
552 		 */
553 
554 		_z_echoDebug(DBG_ZONES_LCK_ZONE_PATCHADM, a_zlst->_zlName,
555 		    LOBJ_PATCHADMIN);
556 
557 		b = _z_lock_zone_object(&a_zlst->_zlLockObjects,
558 		    scratchName, LOBJ_PATCHADMIN, (pid_t)0,
559 		    MSG_ZONES_LCK_ZONE_PATCHADM,
560 		    ERR_ZONES_LCK_ZONE_PATCHADM);
561 		if (b == B_FALSE) {
562 			(void) _z_unlock_zone(a_zlst, a_lflags);
563 			return (b);
564 		}
565 	}
566 
567 	/*
568 	 * all locks have been obtained - return success!
569 	 */
570 
571 	return (B_TRUE);
572 }
573 
574 /*
575  * Name:	_z_lock_zone_object
576  * Description:	lock a single lock object in a specified zone
577  * Arguments:	r_objectLocks - [RW, *RW] - (char **)
578  *			Pointer to handle to character string containing a list
579  *			of all objects locked for this zone - this string will
580  *			have the key to release the specified object added to it
581  *			if the lock is acquired.
582  *		a_zoneName - [RO, *RO] - (char *)
583  *			Pointer to string representing the name of the zone to
584  *			acquire the specified lock on
585  *		a_lockObject - [RO, *RO] - (char *)
586  *			Pointer to string representing the lock object to
587  *			acquire on the specified zone
588  *		a_pid - [RO, *RO] - (pid_t)
589  *			Process i.d. to associate with this lock
590  *			== 0 - no process i.d. associated with the lock
591  *		a_waitingMsg - [RO, *RO] - (char *)
592  *			Localized message to be output if waiting for the lock
593  *			because the lock cannot be immediately be acquired
594  *		a_busyMsg - [RO, *RO] - (char *)
595  *			Localized message to be output if the lock cannot be
596  *			released
597  * Returns:	boolean_t
598  *			B_TRUE - lock released
599  *			B_FALSE - lock not released
600  */
601 
602 boolean_t
603 _z_lock_zone_object(char **r_objectLocks, char *a_zoneName, char *a_lockObject,
604 	pid_t a_pid, char *a_waitingMsg, char *a_busyMsg)
605 {
606 	boolean_t	b;
607 	char		*p = (char *)NULL;
608 	char		lockItem[LOCK_OBJECT_MAXLEN+LOCK_KEY_MAXLEN+4];
609 	char		lockKey[LOCK_KEY_MAXLEN+2];
610 	char		lockObject[LOCK_OBJECT_MAXLEN+2];
611 	int		i;
612 
613 	/* entry assertions */
614 
615 	assert(r_objectLocks != (char **)NULL);
616 	assert(a_zoneName != (char *)NULL);
617 	assert(a_waitingMsg != (char *)NULL);
618 	assert(a_busyMsg != (char *)NULL);
619 	assert(a_lockObject != (char *)NULL);
620 	assert(*a_lockObject != '\0');
621 
622 	/* entry debugging info */
623 
624 	_z_echoDebug(DBG_ZONES_LCK_OBJ, a_lockObject, a_zoneName, a_pid,
625 	    *r_objectLocks ? *r_objectLocks : "");
626 
627 	/* if lock objects held search for object to lock */
628 
629 	if (*r_objectLocks != (char *)NULL) {
630 		for (i = 0; ; i++) {
631 			/* get next object locked on this zone */
632 			_z_strGetToken_r((char *)NULL, *r_objectLocks, i, "\n",
633 			    lockItem, sizeof (lockItem));
634 
635 			/* break out of loop if no more locks in list */
636 
637 			if (lockItem[0] == '\0') {
638 				_z_echoDebug(DBG_ZONES_LCK_OBJ_NOTHELD,
639 				    a_lockObject, a_zoneName);
640 				break;
641 			}
642 
643 			/* get object and key for this lock */
644 			_z_strGetToken_r((char *)NULL, lockItem, 0, "\t",
645 			    lockObject, sizeof (lockObject));
646 			_z_strGetToken_r((char *)NULL, lockItem, 1, "\t",
647 			    lockKey, sizeof (lockKey));
648 
649 			/* return success if the lock is held */
650 
651 			if (strcmp(lockObject, a_lockObject) == 0) {
652 				_z_echoDebug(DBG_ZONES_LCK_OBJ_FOUND,
653 				    lockObject, lockKey);
654 				return (B_TRUE);
655 			}
656 
657 			/* not the object to lock - scan next object */
658 			_z_echoDebug(DBG_ZONES_LCK_OBJ_NOTFOUND, lockObject,
659 			    lockKey);
660 		}
661 	}
662 
663 	/*
664 	 * the object to lock is not held - acquire the lock
665 	 */
666 
667 	/* acquire object with no wait */
668 	b = _z_acquire_lock(&p, a_zoneName, a_lockObject, a_pid, B_FALSE);
669 	if (b == B_FALSE) {
670 		/* failure - output message and acquire with wait */
671 		_z_echo(a_waitingMsg, (long)MAX_RETRIES*RETRY_DELAY_SECS,
672 		    a_zoneName, _z_global_data._z_root_dir);
673 		b = _z_acquire_lock(&p, a_zoneName, a_lockObject, a_pid,
674 		    B_TRUE);
675 	}
676 
677 	/* output error message and return failure if both acquires failed */
678 	if (b == B_FALSE) {
679 		_z_program_error(a_busyMsg, a_zoneName);
680 		return (b);
681 	}
682 
683 	/* add object/key to held locks */
684 
685 	_z_strPrintf_r(lockItem, sizeof (lockItem), "%s\t%s", a_lockObject, p);
686 	_z_strAddToken(r_objectLocks, lockItem, '\n');
687 
688 	free(p);
689 
690 	/* return success */
691 	return (B_TRUE);
692 }
693 
694 /*
695  * Name:	_z_release_lock
696  * Description:	release a lock held on a zone
697  * Arguments:	a_zoneName - [RO, *RO] - (char *)
698  *			Pointer to string representing the name of the zone to
699  *			release the specified lock on
700  *		a_lockObject - [RO, *RO] - (char *)
701  *			Pointer to string representing the lock object to
702  *			release on the specified zone
703  *		a_lockKey - [RO, *RO] - (char *)
704  *			Pointer to string representing the lock key associated
705  *			with the lock object to be released - this key is
706  *			returned when the lock is acquired and must be provided
707  *			when releasing the lock
708  *		a_wait - [RO, *RO] - (int)
709  *			Determines what to do if the lock cannot be released:
710  *			== B_TRUE - wait for the lock to be released
711  *			== B_FALSE - do not wait for the lock to be released
712  * Returns:	boolean_t
713  *			B_TRUE - lock released
714  *			B_FALSE - lock not released
715  */
716 
717 boolean_t
718 _z_release_lock(char *a_zoneName, char *a_lockObject, char *a_lockKey,
719 	boolean_t a_wait)
720 {
721 	argArray_t	*args;
722 	boolean_t	b;
723 	char		*adjustedLockObject = (char *)NULL;
724 	char		*results = (char *)NULL;
725 	int		r;
726 	int		status;
727 
728 	/* entry assertions */
729 
730 	assert(a_zoneName != (char *)NULL);
731 	assert(a_lockObject != (char *)NULL);
732 	assert(*a_lockObject != '\0');
733 	assert(a_lockKey != (char *)NULL);
734 	assert(*a_lockKey != '\0');
735 
736 	/* entry debugging info */
737 
738 	_z_echoDebug(DBG_ZONES_RELK, a_zoneName, a_lockObject,
739 	    a_lockKey ? a_lockKey : "");
740 
741 	/*
742 	 * Only one lock file must ever be used - the one located on the root
743 	 * file system of the currently running Solaris instance. To allow for
744 	 * alternative roots to be properly locked, adjust the lock object to
745 	 * take root path into account; if necessary, the root path will be
746 	 * prepended to the lock object.
747 	 */
748 
749 	b = _z_adjust_lock_object_for_rootpath(&adjustedLockObject,
750 	    a_lockObject);
751 	if (!b) {
752 		return (B_FALSE);
753 	}
754 
755 	/*
756 	 * construct command arguments:
757 	 * pkgadm lock -r -o adjustedLockObject -k a_lockKey [-w -W timeout]
758 	 */
759 
760 	args = _z_new_args(20);			/* generate new arg list */
761 	(void) _z_add_arg(args, PKGADM_CMD);		/* pkgadm command */
762 	(void) _z_add_arg(args, "lock");		/* lock sub-command */
763 	(void) _z_add_arg(args, "-r");			/* release lock */
764 	(void) _z_add_arg(args, "-o");			/* object to release */
765 	(void) _z_add_arg(args, "%s", adjustedLockObject);
766 	(void) _z_add_arg(args, "-k");			/* object's key */
767 	(void) _z_add_arg(args, "%s", a_lockKey);
768 
769 	/* add [ -w -W timeout ] if waiting for lock */
770 
771 	if (a_wait == B_TRUE) {
772 		(void) _z_add_arg(args, "-w");		/* wait */
773 		(void) _z_add_arg(args, "-W");		/* wait timeout */
774 		(void) _z_add_arg(args, "%ld",
775 		    (long)MAX_RETRIES*RETRY_DELAY_SECS);
776 	}
777 
778 	/* execute command */
779 
780 	r = _z_zone_exec(&status, &results, (char *)NULL, PKGADM_CMD,
781 	    _z_get_argv(args), a_zoneName, (int *)NULL);
782 
783 	/* free generated argument list */
784 
785 	_z_free_args(args);
786 
787 	/* exit debugging info */
788 
789 	_z_echoDebug(DBG_ZONES_RELK_EXIT, adjustedLockObject, a_lockKey,
790 	    a_zoneName, r, status, results ? results : "");
791 
792 	/* free adjusted lock object */
793 
794 	free(adjustedLockObject);
795 	free(results);
796 
797 	return (((r == 0) && (status == 0)) ? B_TRUE : B_FALSE);
798 }
799 
800 
801 
802 /*
803  * Name:	_z_unlock_zone
804  * Description:	Released specified locks on specified zone
805  * Arguments:	a_zlst - [RO, *RW] - (zoneListElement_t *)
806  *			Pointer to zone list structure element describing
807  *			the zone the unlock - the structure is updated by
808  *			removing the lock object and key if the locks are
809  *			successfully released
810  *		a_lflags - [RO, *RO] - (ZLOCKS_T)
811  *			Flags indicating which locks to release on the zone
812  * Returns:	boolean_t
813  *			== B_TRUE - locks successfully released
814  *			== B_FALSE - failed to release the locks
815  */
816 
817 boolean_t
818 _z_unlock_zone(zoneListElement_t *a_zlst, ZLOCKS_T a_lflags)
819 {
820 	char		*scratchName;
821 	boolean_t	b;
822 	boolean_t	errors = B_FALSE;
823 
824 	/* entry assertions */
825 
826 	assert(a_zlst != (zoneListElement_t *)NULL);
827 
828 	/* entry debugging info */
829 
830 	_z_echoDebug(DBG_ZONES_ULK_ZONE, a_zlst->_zlName, a_lflags);
831 
832 	scratchName = a_zlst->_zlScratchName == NULL ? a_zlst->_zlName :
833 	    a_zlst->_zlScratchName;
834 
835 	if (a_lflags & ZLOCKS_PATCH_ADMIN) {
836 		/*
837 		 * if locked, unlock patch administration lock
838 		 * if the lock cannot be released, continue anyway
839 		 */
840 
841 		_z_echoDebug(DBG_ZONES_ULK_ZONE_PATCHADM, a_zlst->_zlName,
842 		    LOBJ_PATCHADMIN);
843 
844 		b = _z_unlock_zone_object(&a_zlst->_zlLockObjects,
845 		    scratchName, LOBJ_PATCHADMIN,
846 		    WRN_ZONES_ULK_ZONE_PATCHADM);
847 		if (b == B_FALSE) {
848 			errors = B_TRUE;
849 		}
850 	}
851 
852 	if (a_lflags & ZLOCKS_PKG_ADMIN) {
853 		/*
854 		 * if locked, unlock package administration lock
855 		 * if the lock cannot be released, continue anyway
856 		 */
857 
858 		_z_echoDebug(DBG_ZONES_ULK_ZONE_PKGADM, a_zlst->_zlName,
859 		    LOBJ_PKGADMIN);
860 
861 		b = _z_unlock_zone_object(&a_zlst->_zlLockObjects,
862 		    scratchName, LOBJ_PKGADMIN,
863 		    WRN_ZONES_ULK_ZONE_PKGADM);
864 		if (b == B_FALSE) {
865 			errors = B_TRUE;
866 		}
867 	}
868 
869 	if (a_lflags & ZLOCKS_ZONE_ADMIN) {
870 
871 		/*
872 		 * if locked, unlock zone administration lock
873 		 * if the lock cannot be released, continue anyway
874 		 */
875 
876 		_z_echoDebug(DBG_ZONES_ULK_ZONE_ZONEADM, a_zlst->_zlName,
877 		    LOBJ_ZONEADMIN);
878 
879 		b = _z_unlock_zone_object(&a_zlst->_zlLockObjects,
880 		    scratchName, LOBJ_ZONEADMIN,
881 		    WRN_ZONES_ULK_ZONE_ZONEADM);
882 		if (b == B_FALSE) {
883 			errors = B_TRUE;
884 		}
885 	}
886 
887 	return (!errors);
888 }
889 
890 /*
891  * Name:	_z_unlock_zone_object
892  * Description:	unlock a single lock object in a specified zone
893  * Arguments:	r_objectLocks - [RW, *RW] - (char **)
894  *			Pointer to handle to character string containing a list
895  *			of all objects locked for this zone - this string must
896  *			contain the key to release the specified object - if not
897  *			then the lock is not released - if so then the lock is
898  *			released and the key is removed from this list.
899  *		a_zoneName - [RO, *RO] - (char *)
900  *			Pointer to string representing the name of the zone to
901  *			release the specified lock on
902  *		a_lockObject - [RO, *RO] - (char *)
903  *			Pointer to string representing the lock object to
904  *			release on the specified zone
905  *		a_errMsg - [RO, *RO] - (char *)
906  *			Localized message to be output if the lock cannot be
907  *			released
908  * Returns:	boolean_t
909  *			B_TRUE - lock released
910  *			B_FALSE - lock not released
911  */
912 
913 boolean_t
914 _z_unlock_zone_object(char **r_objectLocks, char *a_zoneName,
915 	char *a_lockObject, char *a_errMsg)
916 {
917 	boolean_t	b;
918 	char		lockItem[LOCK_OBJECT_MAXLEN+LOCK_KEY_MAXLEN+4];
919 	char		lockKey[LOCK_KEY_MAXLEN+2];
920 	char		lockObject[LOCK_OBJECT_MAXLEN+2];
921 	int		i;
922 
923 	/* entry assertions */
924 
925 	assert(r_objectLocks != (char **)NULL);
926 	assert(a_zoneName != (char *)NULL);
927 	assert(a_errMsg != (char *)NULL);
928 	assert(a_lockObject != (char *)NULL);
929 	assert(*a_lockObject != '\0');
930 
931 	/* entry debugging info */
932 
933 	_z_echoDebug(DBG_ZONES_ULK_OBJ, a_lockObject, a_zoneName,
934 	    *r_objectLocks ? *r_objectLocks : "");
935 
936 	/* return success if no objects are locked */
937 
938 	if (*r_objectLocks == (char *)NULL) {
939 		_z_echoDebug(DBG_ZONES_ULK_OBJ_NONE, a_zoneName);
940 		return (B_TRUE);
941 	}
942 
943 	/* see if the specified lock is held on this zone */
944 
945 	for (i = 0; ; i++) {
946 		/* get next object locked on this zone */
947 		_z_strGetToken_r((char *)NULL, *r_objectLocks, i, "\n",
948 		    lockItem, sizeof (lockItem));
949 
950 		/* return success if no more objects locked */
951 		if (lockItem[0] == '\0') {
952 			_z_echoDebug(DBG_ZONES_ULK_OBJ_NOTHELD, a_lockObject,
953 			    a_zoneName);
954 			return (B_TRUE);
955 		}
956 
957 		/* get object and key for this lock */
958 		_z_strGetToken_r((char *)NULL, lockItem, 0, "\t",
959 		    lockObject, sizeof (lockObject));
960 		_z_strGetToken_r((char *)NULL, lockItem, 1, "\t",
961 		    lockKey, sizeof (lockKey));
962 
963 		/* break out of loop if object is the one to unlock */
964 
965 		if (strcmp(lockObject, a_lockObject) == 0) {
966 			_z_echoDebug(DBG_ZONES_ULK_OBJ_FOUND, lockObject,
967 			    lockKey);
968 			break;
969 		}
970 
971 		/* not the object to unlock - scan next object */
972 		_z_echoDebug(DBG_ZONES_ULK_OBJ_NOTFOUND, lockObject, lockKey);
973 	}
974 
975 	/*
976 	 * the object to unlock is held - release the lock
977 	 */
978 
979 	/* release object with wait */
980 
981 	b = _z_release_lock(a_zoneName, a_lockObject, lockKey, B_TRUE);
982 	if (b == B_FALSE) {
983 		/* failure - issue error message and return failure */
984 		_z_program_error(a_errMsg, a_zoneName);
985 		return (b);
986 	}
987 
988 	/* remove object/key from held locks */
989 
990 	_z_strRemoveToken(r_objectLocks, lockItem, "\n", 0);
991 
992 	/* return success */
993 
994 	return (B_TRUE);
995 }
996