xref: /illumos-gate/usr/src/lib/libinstzones/common/zones_locks.c (revision e5803b76927480e8f9b67b22201c484ccf4c2bcf)
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 	 * all locks have been obtained - return success!
544 	 */
545 
546 	return (B_TRUE);
547 }
548 
549 /*
550  * Name:	_z_lock_zone_object
551  * Description:	lock a single lock object in a specified zone
552  * Arguments:	r_objectLocks - [RW, *RW] - (char **)
553  *			Pointer to handle to character string containing a list
554  *			of all objects locked for this zone - this string will
555  *			have the key to release the specified object added to it
556  *			if the lock is acquired.
557  *		a_zoneName - [RO, *RO] - (char *)
558  *			Pointer to string representing the name of the zone to
559  *			acquire the specified lock on
560  *		a_lockObject - [RO, *RO] - (char *)
561  *			Pointer to string representing the lock object to
562  *			acquire on the specified zone
563  *		a_pid - [RO, *RO] - (pid_t)
564  *			Process i.d. to associate with this lock
565  *			== 0 - no process i.d. associated with the lock
566  *		a_waitingMsg - [RO, *RO] - (char *)
567  *			Localized message to be output if waiting for the lock
568  *			because the lock cannot be immediately be acquired
569  *		a_busyMsg - [RO, *RO] - (char *)
570  *			Localized message to be output if the lock cannot be
571  *			released
572  * Returns:	boolean_t
573  *			B_TRUE - lock released
574  *			B_FALSE - lock not released
575  */
576 
577 boolean_t
578 _z_lock_zone_object(char **r_objectLocks, char *a_zoneName, char *a_lockObject,
579 	pid_t a_pid, char *a_waitingMsg, char *a_busyMsg)
580 {
581 	boolean_t	b;
582 	char		*p = (char *)NULL;
583 	char		lockItem[LOCK_OBJECT_MAXLEN+LOCK_KEY_MAXLEN+4];
584 	char		lockKey[LOCK_KEY_MAXLEN+2];
585 	char		lockObject[LOCK_OBJECT_MAXLEN+2];
586 	int		i;
587 
588 	/* entry assertions */
589 
590 	assert(r_objectLocks != (char **)NULL);
591 	assert(a_zoneName != (char *)NULL);
592 	assert(a_waitingMsg != (char *)NULL);
593 	assert(a_busyMsg != (char *)NULL);
594 	assert(a_lockObject != (char *)NULL);
595 	assert(*a_lockObject != '\0');
596 
597 	/* entry debugging info */
598 
599 	_z_echoDebug(DBG_ZONES_LCK_OBJ, a_lockObject, a_zoneName, a_pid,
600 	    *r_objectLocks ? *r_objectLocks : "");
601 
602 	/* if lock objects held search for object to lock */
603 
604 	if (*r_objectLocks != (char *)NULL) {
605 		for (i = 0; ; i++) {
606 			/* get next object locked on this zone */
607 			_z_strGetToken_r((char *)NULL, *r_objectLocks, i, "\n",
608 			    lockItem, sizeof (lockItem));
609 
610 			/* break out of loop if no more locks in list */
611 
612 			if (lockItem[0] == '\0') {
613 				_z_echoDebug(DBG_ZONES_LCK_OBJ_NOTHELD,
614 				    a_lockObject, a_zoneName);
615 				break;
616 			}
617 
618 			/* get object and key for this lock */
619 			_z_strGetToken_r((char *)NULL, lockItem, 0, "\t",
620 			    lockObject, sizeof (lockObject));
621 			_z_strGetToken_r((char *)NULL, lockItem, 1, "\t",
622 			    lockKey, sizeof (lockKey));
623 
624 			/* return success if the lock is held */
625 
626 			if (strcmp(lockObject, a_lockObject) == 0) {
627 				_z_echoDebug(DBG_ZONES_LCK_OBJ_FOUND,
628 				    lockObject, lockKey);
629 				return (B_TRUE);
630 			}
631 
632 			/* not the object to lock - scan next object */
633 			_z_echoDebug(DBG_ZONES_LCK_OBJ_NOTFOUND, lockObject,
634 			    lockKey);
635 		}
636 	}
637 
638 	/*
639 	 * the object to lock is not held - acquire the lock
640 	 */
641 
642 	/* acquire object with no wait */
643 	b = _z_acquire_lock(&p, a_zoneName, a_lockObject, a_pid, B_FALSE);
644 	if (b == B_FALSE) {
645 		/* failure - output message and acquire with wait */
646 		_z_echo(a_waitingMsg, (long)MAX_RETRIES*RETRY_DELAY_SECS,
647 		    a_zoneName, _z_global_data._z_root_dir);
648 		b = _z_acquire_lock(&p, a_zoneName, a_lockObject, a_pid,
649 		    B_TRUE);
650 	}
651 
652 	/* output error message and return failure if both acquires failed */
653 	if (b == B_FALSE) {
654 		_z_program_error(a_busyMsg, a_zoneName);
655 		return (b);
656 	}
657 
658 	/* add object/key to held locks */
659 
660 	_z_strPrintf_r(lockItem, sizeof (lockItem), "%s\t%s", a_lockObject, p);
661 	_z_strAddToken(r_objectLocks, lockItem, '\n');
662 
663 	free(p);
664 
665 	/* return success */
666 	return (B_TRUE);
667 }
668 
669 /*
670  * Name:	_z_release_lock
671  * Description:	release a lock held on a zone
672  * Arguments:	a_zoneName - [RO, *RO] - (char *)
673  *			Pointer to string representing the name of the zone to
674  *			release the specified lock on
675  *		a_lockObject - [RO, *RO] - (char *)
676  *			Pointer to string representing the lock object to
677  *			release on the specified zone
678  *		a_lockKey - [RO, *RO] - (char *)
679  *			Pointer to string representing the lock key associated
680  *			with the lock object to be released - this key is
681  *			returned when the lock is acquired and must be provided
682  *			when releasing the lock
683  *		a_wait - [RO, *RO] - (int)
684  *			Determines what to do if the lock cannot be released:
685  *			== B_TRUE - wait for the lock to be released
686  *			== B_FALSE - do not wait for the lock to be released
687  * Returns:	boolean_t
688  *			B_TRUE - lock released
689  *			B_FALSE - lock not released
690  */
691 
692 boolean_t
693 _z_release_lock(char *a_zoneName, char *a_lockObject, char *a_lockKey,
694 	boolean_t a_wait)
695 {
696 	argArray_t	*args;
697 	boolean_t	b;
698 	char		*adjustedLockObject = (char *)NULL;
699 	char		*results = (char *)NULL;
700 	int		r;
701 	int		status;
702 
703 	/* entry assertions */
704 
705 	assert(a_zoneName != (char *)NULL);
706 	assert(a_lockObject != (char *)NULL);
707 	assert(*a_lockObject != '\0');
708 	assert(a_lockKey != (char *)NULL);
709 	assert(*a_lockKey != '\0');
710 
711 	/* entry debugging info */
712 
713 	_z_echoDebug(DBG_ZONES_RELK, a_zoneName, a_lockObject,
714 	    a_lockKey ? a_lockKey : "");
715 
716 	/*
717 	 * Only one lock file must ever be used - the one located on the root
718 	 * file system of the currently running Solaris instance. To allow for
719 	 * alternative roots to be properly locked, adjust the lock object to
720 	 * take root path into account; if necessary, the root path will be
721 	 * prepended to the lock object.
722 	 */
723 
724 	b = _z_adjust_lock_object_for_rootpath(&adjustedLockObject,
725 	    a_lockObject);
726 	if (!b) {
727 		return (B_FALSE);
728 	}
729 
730 	/*
731 	 * construct command arguments:
732 	 * pkgadm lock -r -o adjustedLockObject -k a_lockKey [-w -W timeout]
733 	 */
734 
735 	args = _z_new_args(20);			/* generate new arg list */
736 	(void) _z_add_arg(args, PKGADM_CMD);		/* pkgadm command */
737 	(void) _z_add_arg(args, "lock");		/* lock sub-command */
738 	(void) _z_add_arg(args, "-r");			/* release lock */
739 	(void) _z_add_arg(args, "-o");			/* object to release */
740 	(void) _z_add_arg(args, "%s", adjustedLockObject);
741 	(void) _z_add_arg(args, "-k");			/* object's key */
742 	(void) _z_add_arg(args, "%s", a_lockKey);
743 
744 	/* add [ -w -W timeout ] if waiting for lock */
745 
746 	if (a_wait == B_TRUE) {
747 		(void) _z_add_arg(args, "-w");		/* wait */
748 		(void) _z_add_arg(args, "-W");		/* wait timeout */
749 		(void) _z_add_arg(args, "%ld",
750 		    (long)MAX_RETRIES*RETRY_DELAY_SECS);
751 	}
752 
753 	/* execute command */
754 
755 	r = _z_zone_exec(&status, &results, (char *)NULL, PKGADM_CMD,
756 	    _z_get_argv(args), a_zoneName, (int *)NULL);
757 
758 	/* free generated argument list */
759 
760 	_z_free_args(args);
761 
762 	/* exit debugging info */
763 
764 	_z_echoDebug(DBG_ZONES_RELK_EXIT, adjustedLockObject, a_lockKey,
765 	    a_zoneName, r, status, results ? results : "");
766 
767 	/* free adjusted lock object */
768 
769 	free(adjustedLockObject);
770 	free(results);
771 
772 	return (((r == 0) && (status == 0)) ? B_TRUE : B_FALSE);
773 }
774 
775 
776 
777 /*
778  * Name:	_z_unlock_zone
779  * Description:	Released specified locks on specified zone
780  * Arguments:	a_zlst - [RO, *RW] - (zoneListElement_t *)
781  *			Pointer to zone list structure element describing
782  *			the zone the unlock - the structure is updated by
783  *			removing the lock object and key if the locks are
784  *			successfully released
785  *		a_lflags - [RO, *RO] - (ZLOCKS_T)
786  *			Flags indicating which locks to release on the zone
787  * Returns:	boolean_t
788  *			== B_TRUE - locks successfully released
789  *			== B_FALSE - failed to release the locks
790  */
791 
792 boolean_t
793 _z_unlock_zone(zoneListElement_t *a_zlst, ZLOCKS_T a_lflags)
794 {
795 	char		*scratchName;
796 	boolean_t	b;
797 	boolean_t	errors = B_FALSE;
798 
799 	/* entry assertions */
800 
801 	assert(a_zlst != (zoneListElement_t *)NULL);
802 
803 	/* entry debugging info */
804 
805 	_z_echoDebug(DBG_ZONES_ULK_ZONE, a_zlst->_zlName, a_lflags);
806 
807 	scratchName = a_zlst->_zlScratchName == NULL ? a_zlst->_zlName :
808 	    a_zlst->_zlScratchName;
809 
810 	if (a_lflags & ZLOCKS_PKG_ADMIN) {
811 		/*
812 		 * if locked, unlock package administration lock
813 		 * if the lock cannot be released, continue anyway
814 		 */
815 
816 		_z_echoDebug(DBG_ZONES_ULK_ZONE_PKGADM, a_zlst->_zlName,
817 		    LOBJ_PKGADMIN);
818 
819 		b = _z_unlock_zone_object(&a_zlst->_zlLockObjects,
820 		    scratchName, LOBJ_PKGADMIN,
821 		    WRN_ZONES_ULK_ZONE_PKGADM);
822 		if (b == B_FALSE) {
823 			errors = B_TRUE;
824 		}
825 	}
826 
827 	if (a_lflags & ZLOCKS_ZONE_ADMIN) {
828 
829 		/*
830 		 * if locked, unlock zone administration lock
831 		 * if the lock cannot be released, continue anyway
832 		 */
833 
834 		_z_echoDebug(DBG_ZONES_ULK_ZONE_ZONEADM, a_zlst->_zlName,
835 		    LOBJ_ZONEADMIN);
836 
837 		b = _z_unlock_zone_object(&a_zlst->_zlLockObjects,
838 		    scratchName, LOBJ_ZONEADMIN,
839 		    WRN_ZONES_ULK_ZONE_ZONEADM);
840 		if (b == B_FALSE) {
841 			errors = B_TRUE;
842 		}
843 	}
844 
845 	return (!errors);
846 }
847 
848 /*
849  * Name:	_z_unlock_zone_object
850  * Description:	unlock a single lock object in a specified zone
851  * Arguments:	r_objectLocks - [RW, *RW] - (char **)
852  *			Pointer to handle to character string containing a list
853  *			of all objects locked for this zone - this string must
854  *			contain the key to release the specified object - if not
855  *			then the lock is not released - if so then the lock is
856  *			released and the key is removed from this list.
857  *		a_zoneName - [RO, *RO] - (char *)
858  *			Pointer to string representing the name of the zone to
859  *			release the specified lock on
860  *		a_lockObject - [RO, *RO] - (char *)
861  *			Pointer to string representing the lock object to
862  *			release on the specified zone
863  *		a_errMsg - [RO, *RO] - (char *)
864  *			Localized message to be output if the lock cannot be
865  *			released
866  * Returns:	boolean_t
867  *			B_TRUE - lock released
868  *			B_FALSE - lock not released
869  */
870 
871 boolean_t
872 _z_unlock_zone_object(char **r_objectLocks, char *a_zoneName,
873 	char *a_lockObject, char *a_errMsg)
874 {
875 	boolean_t	b;
876 	char		lockItem[LOCK_OBJECT_MAXLEN+LOCK_KEY_MAXLEN+4];
877 	char		lockKey[LOCK_KEY_MAXLEN+2];
878 	char		lockObject[LOCK_OBJECT_MAXLEN+2];
879 	int		i;
880 
881 	/* entry assertions */
882 
883 	assert(r_objectLocks != (char **)NULL);
884 	assert(a_zoneName != (char *)NULL);
885 	assert(a_errMsg != (char *)NULL);
886 	assert(a_lockObject != (char *)NULL);
887 	assert(*a_lockObject != '\0');
888 
889 	/* entry debugging info */
890 
891 	_z_echoDebug(DBG_ZONES_ULK_OBJ, a_lockObject, a_zoneName,
892 	    *r_objectLocks ? *r_objectLocks : "");
893 
894 	/* return success if no objects are locked */
895 
896 	if (*r_objectLocks == (char *)NULL) {
897 		_z_echoDebug(DBG_ZONES_ULK_OBJ_NONE, a_zoneName);
898 		return (B_TRUE);
899 	}
900 
901 	/* see if the specified lock is held on this zone */
902 
903 	for (i = 0; ; i++) {
904 		/* get next object locked on this zone */
905 		_z_strGetToken_r((char *)NULL, *r_objectLocks, i, "\n",
906 		    lockItem, sizeof (lockItem));
907 
908 		/* return success if no more objects locked */
909 		if (lockItem[0] == '\0') {
910 			_z_echoDebug(DBG_ZONES_ULK_OBJ_NOTHELD, a_lockObject,
911 			    a_zoneName);
912 			return (B_TRUE);
913 		}
914 
915 		/* get object and key for this lock */
916 		_z_strGetToken_r((char *)NULL, lockItem, 0, "\t",
917 		    lockObject, sizeof (lockObject));
918 		_z_strGetToken_r((char *)NULL, lockItem, 1, "\t",
919 		    lockKey, sizeof (lockKey));
920 
921 		/* break out of loop if object is the one to unlock */
922 
923 		if (strcmp(lockObject, a_lockObject) == 0) {
924 			_z_echoDebug(DBG_ZONES_ULK_OBJ_FOUND, lockObject,
925 			    lockKey);
926 			break;
927 		}
928 
929 		/* not the object to unlock - scan next object */
930 		_z_echoDebug(DBG_ZONES_ULK_OBJ_NOTFOUND, lockObject, lockKey);
931 	}
932 
933 	/*
934 	 * the object to unlock is held - release the lock
935 	 */
936 
937 	/* release object with wait */
938 
939 	b = _z_release_lock(a_zoneName, a_lockObject, lockKey, B_TRUE);
940 	if (b == B_FALSE) {
941 		/* failure - issue error message and return failure */
942 		_z_program_error(a_errMsg, a_zoneName);
943 		return (b);
944 	}
945 
946 	/* remove object/key from held locks */
947 
948 	_z_strRemoveToken(r_objectLocks, lockItem, "\n", 0);
949 
950 	/* return success */
951 
952 	return (B_TRUE);
953 }
954