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