/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* Module: zones_locks.c
* Group: libinstzones
* Description: Provide "zones" locking interfaces for install consolidation
* code
*
* Public Methods:
*
* _z_acquire_lock - acquire a lock on an object on a zone
* _z_adjust_lock_object_for_rootpath - Given a lock object and a root path,
* if the root path is not
* _z_lock_zone - Acquire specified locks on specified zone
* _z_lock_zone_object - lock a single lock object in a specified zone
* _z_release_lock - release a lock held on a zone
* _z_unlock_zone - Released specified locks on specified zone
* _z_unlock_zone_object - unlock a single lock object in a specified zone
*/
/*
* System includes
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <stdarg.h>
#include <limits.h>
#include <errno.h>
#include <time.h>
#include <stropts.h>
#include <libintl.h>
#include <locale.h>
#include <assert.h>
/*
* local includes
*/
#include "instzones_lib.h"
#include "zones_strings.h"
/*
* Private structures
*/
/*
* Library Function Prototypes
*/
/*
* Local Function Prototypes
*/
char *a_lockObject);
char *a_zoneName, char *a_lockObject,
char *a_busyMsg);
char *a_zoneName, char *a_lockObject,
char *a_errMsg);
/*
* global internal (private) declarations
*/
/*
* *****************************************************************************
* global external (public) functions
* *****************************************************************************
*/
/*
* Name: _z_acquire_lock
* Description: acquire a lock on an object on a zone
* Arguments: r_lockKey - [RW, *RW] - (char *)
* Pointer to handle to string representing the lock key
* associated with the lock object to be acquired - this
* key is returned when the lock is acquired and must be
* provided when releasing the lock
* == (char *)NULL - lock not acquired
* a_zoneName - [RO, *RO] - (char *)
* Pointer to string representing the name of the zone to
* acquire the specified lock on
* a_lockObject - [RO, *RO] - (char *)
* Pointer to string representing the lock object to
* acquire on the specified zone
* a_pid - [RO, *RO] - (pid_t)
* Process i.d. to associate with this lock
* == 0 - no process i.d. associated with the lock
* a_wait - [RO, *RO] - (int)
* Determines what to do if the lock cannot be acquired:
* == B_TRUE - wait for the lock to be acquired
* == B_FALSE - do not wait for the lock to be acquired
* Returns: boolean_t
* B_TRUE - lock acquired
* B_FALSE - lock not acquired
*/
{
boolean_t b;
char *p;
int r;
int status;
/* entry assertions */
/* entry debugging info */
/* reset returned lock key handle */
/*
* Only one lock file must ever be used - the one located on the root
* file system of the currently running Solaris instance. To allow for
* alternative roots to be properly locked, adjust the lock object to
* take root path into account; if necessary, the root path will be
* prepended to the lock object.
*/
if (!b) {
return (B_FALSE);
}
/*
* construct command arguments:
* pkgadm lock -a -q -o adjustedLockObject [ -w -W timeout ]
* [ -p a_pid -z zoneid ]
*/
/* add [ -w -W timeout ] if waiting for lock */
(long)MAX_RETRIES*RETRY_DELAY_SECS);
}
if (a_pid > 0) {
}
/* execute command */
/* free generated argument list */
/* return error if failed to acquire */
if ((r != 0) || (status != 0)) {
/* free up results if returned */
if (results) {
}
/* free adjusted lock object */
/* return failure */
return (B_FALSE);
}
/* return success if no results returned */
return (B_TRUE);
}
/* return the lock key */
*r_lockKey = p;
/* exit debugging info */
results);
/* free up results */
/* free adjusted lock object */
/* return success */
return (B_TRUE);
}
/*
* Name: _z_adjust_lock_object_for_rootpath
* Description: Given a lock object and a root path, if the root path is not
* the current running system root, then alter the lock object
* to contain a reference to the root path. Only one lock file must
* ever be used to create and maintain locks - the lock file that
* is located in /tmp on the root file system of the currently
* running Solaris instance. To allow for alternative roots to be
* properly locked, if necessary adjust the lock object to take
* root path into account. If the root path does not indicate the
* current running Solaris instance, then the root path will be
* prepended to the lock object.
* Arguments: r_result - [RW, *RW] - (char **)
* Pointer to handle to character string that will contain
* the lock object to use.
* a_lockObject - [RO, *RO] - (char *)
* Pointer to string representing the lock object to adjust
* Returns: boolean_t
* B_TRUE - lock object adjusted and returned
* B_FALSE - unable to adjust lock object
* NOTE: Any string returned is placed in new storage for the
* calling function. The caller must use 'free' to dispose
* of the storage once the string is no longer needed.
*
* A lock object has this form:
*
* name.value [ /name.value [ /name.value ... ] ]
*
* The "value is either a specific object or a "*", for example:
*
* package.test
*
* This locks the package "test"
*
* zone.* /package.*
*
* This locks all packages on all zones.
*
* zone.* /package.SUNWluu
*
* This locks the package SUNWluu on all zones.
*
* If a -R rootpath is specified, since there is only one lock file in
* the current /tmp, the lock object is modified to include the root
* path:
*
* rootpath.rootpath/zone.* /package.*
*
* locks all packages on all zones in the root path "?"
*
* The characters "/" and "*" and "." cannot be part of the "value"; that
* cannot be:
*
* rootpath./tmp/gmg*dir.test-path/zone.* /package.*
*
* This would be parsed as:
*
* "rootpath." "/tmp" "gmg*dir.test-path" "zone.*" "package.*"
*
* which is not correct.
*
* So the path is modified by the loop, in this case it would result in
* this lock object:
*
* rootpath.-1tmp-1gmg-3dir-2test---path/zone.* /package.*
*
* This is parsed as:
*
* "rootpath.-1tmp-1gmg-3dir-2test---path" "zone.*" "package.*"
*
* which is then interpreted as:
*
*/
{
const char *a_rootPath;
/* entry assertions */
/* reset returned lock object handle */
/*
* if root path points to "/" return a duplicate of the passed in
* lock objects; otherwise, resolve root path and adjust lock object by
* prepending the rootpath to the lock object (using LOBJ_ROOTPATH).
*/
if ((a_rootPath == (char *)NULL) ||
(*a_rootPath == '\0') ||
/* root path not specified or is only "/" - no -R specified */
} else {
/*
* root path is not "" or "/" - -R to an alternative root has
* been specified; resolve all symbolic links and relative nodes
* of path name and determine absolute path to the root path.
*/
/* cannot determine absolute path; use path specified */
sizeof (realRootPath));
}
/*
* if root path points to "/" duplicate existing lock object;
* otherwise, resolve root path and adjust lock object by
* prepending the rootpath to the lock object
*/
} else {
/* prefix out /.* which cannot be part of lock object */
switch (*p2) {
case '/': /* / becomes -1 */
*p3++ = '-';
*p3++ = '1';
break;
case '.': /* . becomes -2 */
*p3++ = '-';
*p3++ = '2';
break;
case '*': /* * becomes -3 */
*p3++ = '-';
*p3++ = '3';
break;
case '-': /* - becomes -- */
*p3++ = '-';
*p3++ = '-';
break;
default: /* do not prefix out char */
break;
}
}
/* create "realpath.%s" object */
return (B_FALSE);
}
/* create "realpath.%s/..." final lock object */
return (B_FALSE);
}
}
}
/* exit debugging info */
/* return success */
return (B_TRUE);
}
/*
* Name: _z_lock_zone_object
* Description: lock a single lock object in a specified zone
* Arguments: r_objectLocks - [RW, *RW] - (char **)
* Pointer to handle to character string containing a list
* of all objects locked for this zone - this string will
* have the key to release the specified object added to it
* if the lock is acquired.
* a_zoneName - [RO, *RO] - (char *)
* Pointer to string representing the name of the zone to
* acquire the specified lock on
* a_lockObject - [RO, *RO] - (char *)
* Pointer to string representing the lock object to
* acquire on the specified zone
* a_pid - [RO, *RO] - (pid_t)
* Process i.d. to associate with this lock
* == 0 - no process i.d. associated with the lock
* a_waitingMsg - [RO, *RO] - (char *)
* Localized message to be output if waiting for the lock
* because the lock cannot be immediately be acquired
* a_busyMsg - [RO, *RO] - (char *)
* Localized message to be output if the lock cannot be
* released
* Returns: boolean_t
* B_TRUE - lock released
* B_FALSE - lock not released
*/
{
boolean_t b;
char *p = (char *)NULL;
int i;
/* entry assertions */
/* entry debugging info */
/* if lock objects held search for object to lock */
if (*r_objectLocks != (char *)NULL) {
for (i = 0; ; i++) {
/* get next object locked on this zone */
/* break out of loop if no more locks in list */
if (lockItem[0] == '\0') {
break;
}
/* get object and key for this lock */
lockObject, sizeof (lockObject));
/* return success if the lock is held */
return (B_TRUE);
}
/* not the object to lock - scan next object */
lockKey);
}
}
/*
* the object to lock is not held - acquire the lock
*/
/* acquire object with no wait */
if (b == B_FALSE) {
/* failure - output message and acquire with wait */
B_TRUE);
}
/* output error message and return failure if both acquires failed */
if (b == B_FALSE) {
return (b);
}
free(p);
/* return success */
return (B_TRUE);
}
/*
* Name: _z_release_lock
* Description: release a lock held on a zone
* Arguments: a_zoneName - [RO, *RO] - (char *)
* Pointer to string representing the name of the zone to
* release the specified lock on
* a_lockObject - [RO, *RO] - (char *)
* Pointer to string representing the lock object to
* release on the specified zone
* a_lockKey - [RO, *RO] - (char *)
* Pointer to string representing the lock key associated
* with the lock object to be released - this key is
* returned when the lock is acquired and must be provided
* when releasing the lock
* a_wait - [RO, *RO] - (int)
* Determines what to do if the lock cannot be released:
* == B_TRUE - wait for the lock to be released
* == B_FALSE - do not wait for the lock to be released
* Returns: boolean_t
* B_TRUE - lock released
* B_FALSE - lock not released
*/
{
boolean_t b;
int r;
int status;
/* entry assertions */
/* entry debugging info */
/*
* Only one lock file must ever be used - the one located on the root
* file system of the currently running Solaris instance. To allow for
* alternative roots to be properly locked, adjust the lock object to
* take root path into account; if necessary, the root path will be
* prepended to the lock object.
*/
if (!b) {
return (B_FALSE);
}
/*
* construct command arguments:
* pkgadm lock -r -o adjustedLockObject -k a_lockKey [-w -W timeout]
*/
/* add [ -w -W timeout ] if waiting for lock */
(long)MAX_RETRIES*RETRY_DELAY_SECS);
}
/* execute command */
/* free generated argument list */
/* exit debugging info */
/* free adjusted lock object */
}
/*
* Name: _z_unlock_zone_object
* Description: unlock a single lock object in a specified zone
* Arguments: r_objectLocks - [RW, *RW] - (char **)
* Pointer to handle to character string containing a list
* of all objects locked for this zone - this string must
* contain the key to release the specified object - if not
* then the lock is not released - if so then the lock is
* released and the key is removed from this list.
* a_zoneName - [RO, *RO] - (char *)
* Pointer to string representing the name of the zone to
* release the specified lock on
* a_lockObject - [RO, *RO] - (char *)
* Pointer to string representing the lock object to
* release on the specified zone
* a_errMsg - [RO, *RO] - (char *)
* Localized message to be output if the lock cannot be
* released
* Returns: boolean_t
* B_TRUE - lock released
* B_FALSE - lock not released
*/
char *a_lockObject, char *a_errMsg)
{
boolean_t b;
int i;
/* entry assertions */
/* entry debugging info */
/* return success if no objects are locked */
if (*r_objectLocks == (char *)NULL) {
return (B_TRUE);
}
/* see if the specified lock is held on this zone */
for (i = 0; ; i++) {
/* get next object locked on this zone */
/* return success if no more objects locked */
if (lockItem[0] == '\0') {
return (B_TRUE);
}
/* get object and key for this lock */
lockObject, sizeof (lockObject));
/* break out of loop if object is the one to unlock */
lockKey);
break;
}
/* not the object to unlock - scan next object */
}
/*
* the object to unlock is held - release the lock
*/
/* release object with wait */
if (b == B_FALSE) {
/* failure - issue error message and return failure */
return (b);
}
/* return success */
return (B_TRUE);
}