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