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
_z_acquire_lock(char ** r_lockKey,char * a_zoneName,char * a_lockObject,pid_t a_pid,boolean_t a_wait)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
_z_adjust_lock_object_for_rootpath(char ** r_result,char * a_lockObject)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
_z_lock_zone(zoneListElement_t * a_zlst,ZLOCKS_T a_lflags)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
_z_lock_zone_object(char ** r_objectLocks,char * a_zoneName,char * a_lockObject,pid_t a_pid,char * a_waitingMsg,char * a_busyMsg)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
_z_release_lock(char * a_zoneName,char * a_lockObject,char * a_lockKey,boolean_t a_wait)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
_z_unlock_zone(zoneListElement_t * a_zlst,ZLOCKS_T a_lflags)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
_z_unlock_zone_object(char ** r_objectLocks,char * a_zoneName,char * a_lockObject,char * a_errMsg)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