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