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