summaryrefslogtreecommitdiff
path: root/usr/src/lib/libinstzones
diff options
context:
space:
mode:
authorMoriah Waterland <Moriah.Waterland@Sun.COM>2009-06-03 20:16:25 -0600
committerMoriah Waterland <Moriah.Waterland@Sun.COM>2009-06-03 20:16:25 -0600
commit5c51f1241dbbdf2656d0e10011981411ed0c9673 (patch)
tree0f30a2e38fe4e5d53a5a67264ba548577d82a86f /usr/src/lib/libinstzones
parent2b79d384d32b4ea1e278466cd9b0f3bb56daae22 (diff)
downloadillumos-joyent-5c51f1241dbbdf2656d0e10011981411ed0c9673.tar.gz
6739234 move SVR4 packaging to ONNV gate
Diffstat (limited to 'usr/src/lib/libinstzones')
-rw-r--r--usr/src/lib/libinstzones/Makefile43
-rw-r--r--usr/src/lib/libinstzones/Makefile.com78
-rw-r--r--usr/src/lib/libinstzones/common/instzones_api.h187
-rw-r--r--usr/src/lib/libinstzones/common/instzones_lib.h387
-rw-r--r--usr/src/lib/libinstzones/common/llib-linstzones31
-rw-r--r--usr/src/lib/libinstzones/common/mapfile-vers94
-rw-r--r--usr/src/lib/libinstzones/common/zones.c2425
-rw-r--r--usr/src/lib/libinstzones/common/zones_args.c307
-rw-r--r--usr/src/lib/libinstzones/common/zones_exec.c1120
-rw-r--r--usr/src/lib/libinstzones/common/zones_locks.c995
-rw-r--r--usr/src/lib/libinstzones/common/zones_lofs.c288
-rw-r--r--usr/src/lib/libinstzones/common/zones_paths.c464
-rw-r--r--usr/src/lib/libinstzones/common/zones_states.c585
-rw-r--r--usr/src/lib/libinstzones/common/zones_str.c711
-rw-r--r--usr/src/lib/libinstzones/common/zones_strings.h238
-rw-r--r--usr/src/lib/libinstzones/common/zones_utils.c689
-rw-r--r--usr/src/lib/libinstzones/i386/Makefile28
-rw-r--r--usr/src/lib/libinstzones/sparc/Makefile28
18 files changed, 8698 insertions, 0 deletions
diff --git a/usr/src/lib/libinstzones/Makefile b/usr/src/lib/libinstzones/Makefile
new file mode 100644
index 0000000000..a00bec1cf5
--- /dev/null
+++ b/usr/src/lib/libinstzones/Makefile
@@ -0,0 +1,43 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+SUBDIRS = $(MACH)
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+_msg := TARGET = _msg
+lint := TARGET = lint
+
+
+.KEEP_STATE:
+
+all clean clobber install _msg lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/libinstzones/Makefile.com b/usr/src/lib/libinstzones/Makefile.com
new file mode 100644
index 0000000000..994d0e5e91
--- /dev/null
+++ b/usr/src/lib/libinstzones/Makefile.com
@@ -0,0 +1,78 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY= libinstzones.a
+VERS= .1
+
+OBJECTS = \
+ zones_args.o \
+ zones_exec.o \
+ zones_locks.o \
+ zones_paths.o \
+ zones_states.o \
+ zones_str.o \
+ zones_utils.o \
+ zones_lofs.o \
+ zones.o
+
+# include library definitions
+include $(SRC)/lib/Makefile.lib
+
+SRCDIR= ../common
+
+POFILE = libinstzones.po
+MSGFILES = $(OBJECTS:%.o=../common/%.i)
+CLEANFILES += $(MSGFILES)
+
+# openssl forces us to ignore dubious pointer casts, thanks to its clever
+# use of macros for stack management.
+LINTFLAGS= -umx -errtags \
+ -erroff=E_BAD_PTR_CAST_ALIGN,E_BAD_PTR_CAST
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+LIBS = $(DYNLIB) $(LINTLIB)
+
+DYNFLAGS += $(ZLAZYLOAD)
+
+LDLIBS += -lc -lcontract -lzonecfg
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+$(POFILE): $(MSGFILES)
+ $(BUILDPO.msgfiles)
+
+_msg: $(MSGDOMAINPOFILE)
+
+lint: lintcheck
+
+# include library targets
+include $(SRC)/lib/Makefile.targ
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/lib/libinstzones/common/instzones_api.h b/usr/src/lib/libinstzones/common/instzones_api.h
new file mode 100644
index 0000000000..5fea8c0ce6
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/instzones_api.h
@@ -0,0 +1,187 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _INSTZONES_API_H
+#define _INSTZONES_API_H
+
+
+/*
+ * Module: instzones_api.h
+ * Group: libinstzones
+ * Description: This module contains the libinstzones API data structures,
+ * constants, and function prototypes.
+ */
+
+/*
+ * required includes
+ */
+
+/* System includes */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <libzonecfg.h>
+
+/*
+ * C++ prefix
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* function prototypes */
+
+/* PRINTFLIKE1 */
+typedef void (*_z_printf_fcn_t)(char *a_format, ...);
+
+/* zone list structure */
+
+typedef struct _zoneListElement_t *zoneList_t;
+
+/* zone brand list structure */
+
+typedef struct _zoneBrandList zoneBrandList_t;
+
+/* flag for zone locking functions */
+
+typedef unsigned long ZLOCKS_T;
+
+/* flags for zone locking */
+
+#define ZLOCKS_ZONE_ADMIN ((ZLOCKS_T)0x00000001) /* zone admin */
+#define ZLOCKS_PKG_ADMIN ((ZLOCKS_T)0x00000002) /* package admin */
+#define ZLOCKS_PATCH_ADMIN ((ZLOCKS_T)0x00000004) /* patch admin */
+#define ZLOCKS_ALL ((ZLOCKS_T)0xFFFFFFFF) /* all locks */
+#define ZLOCKS_NONE ((ZLOCKS_T)0x00000000) /* no locks */
+
+/*
+ * external function definitions
+ */
+
+/* zones.c */
+
+extern boolean_t z_zones_are_implemented(void);
+extern void z_set_zone_root(const char *zroot);
+extern boolean_t z_zlist_is_zone_runnable(zoneList_t a_zoneList,
+ int a_zoneIndex);
+extern boolean_t z_zlist_restore_zone_state(zoneList_t a_zoneList,
+ int a_zoneIndex);
+extern boolean_t z_zlist_change_zone_state(zoneList_t a_zoneList,
+ int a_zoneIndex, zone_state_t a_newState);
+extern char *z_get_zonename(void);
+extern zone_state_t z_zlist_get_current_state(zoneList_t a_zoneList,
+ int a_zoneIndex);
+extern char **z_zlist_get_inherited_pkg_dirs(zoneList_t a_zoneList,
+ int a_zoneIndex);
+extern zone_state_t z_zlist_get_original_state(zoneList_t a_zoneList,
+ int a_zoneIndex);
+extern int z_zoneExecCmdArray(int *r_status, char **r_results,
+ char *a_inputFile, char *a_path, char *a_argv[],
+ const char *a_zoneName, int *a_fds);
+extern int z_zone_exec(const char *zonename, const char *path,
+ char *argv[], char *a_stdoutPath,
+ char *a_stderrPath, int *a_fds);
+extern boolean_t z_create_zone_admin_file(char *a_zoneAdminFilename,
+ char *a_userAdminFilename);
+extern void z_free_zone_list(zoneList_t a_zoneList);
+extern zoneList_t z_get_nonglobal_zone_list(void);
+extern zoneList_t z_get_nonglobal_zone_list_by_brand(zoneBrandList_t *);
+extern void z_free_brand_list(zoneBrandList_t *a_brandList);
+extern zoneBrandList_t *z_make_brand_list(const char *brandList,
+ const char *delim);
+extern boolean_t z_lock_zones(zoneList_t a_zlst, ZLOCKS_T a_lflags);
+extern boolean_t z_non_global_zones_exist(void);
+extern boolean_t z_running_in_global_zone(void);
+extern void z_set_output_functions(_z_printf_fcn_t a_echo_fcn,
+ _z_printf_fcn_t a_echo_debug_fcn,
+ _z_printf_fcn_t a_progerr_fcn);
+extern int z_set_zone_spec(const char *zlist);
+extern int z_verify_zone_spec(void);
+extern boolean_t z_on_zone_spec(const char *zonename);
+extern boolean_t z_global_only(void);
+extern boolean_t z_unlock_zones(zoneList_t a_zlst, ZLOCKS_T a_lflags);
+extern boolean_t z_lock_this_zone(ZLOCKS_T a_lflags);
+extern boolean_t z_unlock_this_zone(ZLOCKS_T a_lflags);
+extern char *z_zlist_get_zonename(zoneList_t a_zoneList,
+ int a_zoneId);
+extern char *z_zlist_get_zonepath(zoneList_t a_zoneList,
+ int a_zoneId);
+extern char *z_zlist_get_scratch(zoneList_t a_zoneList,
+ int a_zoneId);
+extern boolean_t z_umount_lz_mount(char *a_lzMountPoint);
+extern boolean_t z_mount_in_lz(char **r_lzMountPoint,
+ char **r_lzRootPath,
+ char *a_zoneName, char *a_gzPath,
+ char *a_mountPointPrefix);
+extern boolean_t z_is_zone_branded(char *zoneName);
+extern boolean_t z_is_zone_brand_in_list(char *zoneName,
+ zoneBrandList_t *brands);
+extern boolean_t z_zones_are_implemented(void);
+
+/* zones_exec.c */
+extern int z_ExecCmdArray(int *r_status, char **r_results,
+ char *a_inputFile, char *a_cmd, char **a_args);
+/*VARARGS*/
+extern int z_ExecCmdList(int *r_status, char **r_results,
+ char *a_inputFile, char *a_cmd, ...);
+
+/* zones_paths.c */
+extern boolean_t z_add_inherited_file_system(
+ char *a_inheritedFileSystem);
+extern boolean_t z_path_is_inherited(char *a_path, char a_ftype,
+ char *a_rootDir);
+extern char ** z_get_inherited_file_systems(void);
+extern char *z_make_zone_root(char *);
+extern void z_path_canonize(char *file);
+extern void z_canoninplace(char *file);
+extern void z_free_inherited_file_systems(void);
+
+/* zones_lofs.c */
+extern void z_destroyMountTable(void);
+extern int z_createMountTable(void);
+extern int z_isPathWritable(const char *);
+extern void z_resolve_lofs(char *path, size_t);
+
+/* zones_states.c */
+extern int UmountAllZones(char *mntpnt);
+
+/*
+ * C++ postfix
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _INSTZONES_API_H */
diff --git a/usr/src/lib/libinstzones/common/instzones_lib.h b/usr/src/lib/libinstzones/common/instzones_lib.h
new file mode 100644
index 0000000000..3dbceabe8f
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/instzones_lib.h
@@ -0,0 +1,387 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+#ifndef _INSTZONES_LIB_H
+#define _INSTZONES_LIB_H
+
+
+/*
+ * Module: instzones_lib.h
+ * Group: libinstzones
+ * Description: This module contains the libinstzones internal data structures,
+ * constants, and function prototypes. This include should not be
+ * needed by any external code (consumers of this library).
+ */
+
+/*
+ * required includes
+ */
+
+/* System includes */
+
+#include <zone.h>
+#include <libzonecfg.h>
+#include <libcontract.h>
+
+/* Local includes */
+
+#include "instzones_api.h"
+
+/*
+ * C++ prefix
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* constants */
+
+
+/* macros */
+
+/*
+ * argument array processing type
+ */
+
+/*
+ * This is the "argument array" definition that is returned by _z_new_args
+ * and is used by _z_add_args, _z_free_args, etc.
+ */
+
+struct _argArray_t {
+ long _aaNumArgs; /* number of arguments set */
+ long _aaMaxArgs; /* number of arguments allocated */
+ char **_aaArgs; /* actual arguments */
+};
+
+typedef struct _argArray_t argArray_t;
+
+/*
+ * lock objects
+ */
+
+/*
+ * this allows a root path to be prepended to a lock object; e.g.
+ * rootpath.%s/zone.%s/...
+ */
+#define LOBJ_ROOTPATH "rootpath.%s"
+
+/* this locks a single zone (zone.name) */
+#define LOBJ_ONE_ZONE "zone.%s"
+
+/* this locks all zones */
+#define LOBJ_ZONEADMIN "zone.*"
+
+/* this locks all packages, in all zones */
+#define LOBJ_PKGADMIN "zone.*/package.*"
+
+/* this locks all patches, in all zones */
+#define LOBJ_PATCHADMIN "zone.*/patch.*"
+
+#define LOCK_OBJECT_MAXLEN 512
+#define LOCK_KEY_MAXLEN 37
+
+/* paths to commands executed by this module */
+
+#define PKGADM_CMD "/usr/bin/pkgadm"
+#define ZONEADM_CMD "/usr/sbin/zoneadm"
+
+/* max message size for program output functions (echo, echo debug, progerr) */
+
+#define MAX_MESSAGE_SIZE 4096
+
+/* maximum number of retries when waiting for lock */
+
+#define MAX_RETRIES 300
+
+/* delay (in seconds) between retries when waiting for lock */
+
+#define RETRY_DELAY_SECS 1
+
+/* Size of buffer increments when reading from pipe */
+
+#define PIPE_BUFFER_INCREMENT 256
+
+/* Maximum number of arguments to pkg_ExecCmdList */
+
+#define MAX_EXEC_CMD_ARGS 100
+
+/*
+ * These dynamic libraries are required in order to use the zones
+ * functionality - if these libraries are not available at runtime,
+ * then zones are assumed to NOT be available, and it is assumed that
+ * the program is running in the global zone with no non-global zones.
+ */
+
+#if defined(LIBZONECFG_PATH)
+#define ZONECFG1_LIBRARY LIBZONECFG_PATH
+#else /* defined(LIBZONECFG_PATH) */
+#define ZONECFG1_LIBRARY "libzonecfg.so.1"
+#endif /* defined(LIBZONECFG_PATH) */
+
+#define ZONECFG_LIBRARY "libzonecfg.so"
+
+#define CONTRACT1_LIBRARY "libcontract.so.1"
+#define CONTRACT_LIBRARY "libcontract.so"
+
+/*
+ * Environment values used when running commands within a non-global zone
+ */
+
+/* SHELL= */
+
+#define ZONE_FAILSAFESHELL "/sbin/sh"
+
+/* PATH= */
+
+#define ZONE_DEF_PATH "/usr/sbin:/usr/bin"
+
+/* error codes */
+#define ERR_MALLOC_FAIL -50
+
+/*
+ * zone brand list structure
+ */
+
+struct _zoneBrandList {
+ char *string_ptr;
+ struct _zoneBrandList *next;
+};
+
+/*
+ * zone status structure - used to retrieve and hold status of zones
+ */
+
+typedef unsigned long _zone_status_t;
+
+struct _zoneListElement_t {
+ char **_zlInheritedDirs;
+ char *_zlName;
+ char *_zlPath;
+ char *_zlScratchName;
+ char *_zlLockObjects;
+ /*
+ * the install "state" refers to the zone states listed in
+ * /usr/include/libzonecfg.h that is stored in the zone_state_t
+ * structure and returned from getzoneent_private() - such as:
+ * ZONE_STATE_CONFIGURED, ZONE_STATE_INCOMPLETE,
+ * ZONE_STATE_INSTALLED, ZONE_STATE_READY, ZONE_STATE_MOUNTED,
+ * ZONE_STATE_SHUTTING_DOWN, ZONE_STATE_DOWN.
+ */
+ zone_state_t _zlOrigInstallState;
+ zone_state_t _zlCurrInstallState;
+ /*
+ * the kernel "status" refers to the zone status listed in
+ * /usr/include/sys/zone.h, returned by zone_get_state(),
+ * and defined in the zone_status_t enum - such as:
+ * ZONE_IS_UNINITIALIZED, ZONE_IS_READY, ZONE_IS_BOOTING,
+ * ZONE_IS_RUNNING, ZONE_IS_SHUTTING_DOWN, ZONE_IS_EMPTY,
+ * ZONE_IS_DOWN, ZONE_IS_DYING, ZONE_IS_DEAD.
+ */
+ zone_status_t _zlOrigKernelStatus;
+ zone_status_t _zlCurrKernelStatus;
+ /*
+ * this is an internal state recorded about the zone (ZSF_xxx).
+ */
+ _zone_status_t _zlStatus;
+};
+
+typedef struct _zoneListElement_t zoneListElement_t;
+
+/* bits used in the _zoneListElement _zlStatus variable */
+
+#define ZST_NOT_BOOTABLE ((_zone_status_t)0x00000001)
+#define ZST_LOCKED ((_zone_status_t)0x00000002)
+
+/*
+ * User-specified list of zones.
+ */
+
+typedef struct zone_spec_s {
+ struct zone_spec_s *zl_next;
+ boolean_t zl_used;
+ char zl_name[ZONENAME_MAX];
+} zone_spec_t;
+
+/*
+ * The global data structure used to hold all of the global (extern) data
+ * used by this library.
+ *
+ * --> THESE DEFINITIONS ARE ORDER DEPENDENT BASED <--
+ * --> ON THE ORDER OF THE STRUCTURE INITIALIZERS! <--
+ */
+
+struct _z_global_data_t {
+ char *_z_ObjectLocks; /* object locks held */
+ char *_z_root_dir; /* root for zone lib fctns */
+ int _z_SigReceived; /* received signal count */
+ pid_t _z_ChildProcessId; /* child to propagate sigs to */
+ zone_spec_t *_zone_spec; /* zones to operate on */
+ _z_printf_fcn_t _z_echo; /* operational message fcn */
+ _z_printf_fcn_t _z_echo_debug; /* debug message fcn */
+ _z_printf_fcn_t _z_progerr; /* program error fcn */
+};
+
+typedef struct _z_global_data_t z_global_data_t;
+
+/*
+ * When _INSTZONES_LIB_Z_DEFINE_GLOBAL_DATA is defined,
+ * instzones_lib.h will define the z_global_data structure.
+ * Otherwise an extern to the structure is inserted.
+ *
+ * --> THESE DEFINITIONS ARE ORDER DEPENDENT BASED ON <--
+ * --> THE ORDER OF THE _z_global_data_t STRUCTURE!!! <--
+ */
+
+#if defined(_INSTZONES_LIB_Z_DEFINE_GLOBAL_DATA)
+
+/* define and initialize structure */
+
+z_global_data_t _z_global_data = {
+ NULL, /* *_z_ObjectLocks */
+ "", /* *_z_root_dir */
+ 0, /* _z_SigReceived */
+ -1, /* _z_ChildProcessId */
+ NULL, /* *_zone_spec */
+ NULL, /* _z_echo */
+ NULL, /* _z_echo_debug */
+ NULL /* _z_progerr */
+};
+
+#else /* !defined(_INSTZONES_LIB__Z_DEFINE_GLOBAL_DATA) */
+
+/* define structure extern */
+
+extern z_global_data_t _z_global_data;
+
+#endif /* defined(_INSTZONES_LIB_Z_DEFINE_GLOBAL_DATA) */
+
+/* function prototypes */
+
+/*
+ * The following functions can be used by other libs, but not
+ * by applications.
+ */
+
+/* ---> zones_states.c */
+
+boolean_t _z_make_zone_ready(zoneListElement_t *a_zlem);
+boolean_t _z_make_zone_down(zoneListElement_t *a_zlem);
+boolean_t _z_make_zone_running(zoneListElement_t *a_zlem);
+int UmountAllZones(char *mntpnt);
+void *_z_calloc(size_t size);
+void *_z_malloc(size_t size);
+void *_z_realloc(void *ptr, size_t size);
+void *_z_strdup(char *str);
+
+/* ---> zones_utils.c */
+
+/*PRINTFLIKE1*/
+void _z_program_error(char *fmt, ...);
+/*PRINTFLIKE1*/
+void _z_echo(char *fmt, ...);
+/*PRINTFLIKE1*/
+void _z_echoDebug(char *a_fmt, ...);
+int _z_is_directory(char *path);
+char **_z_get_inherited_dirs(char *a_zoneName);
+boolean_t _z_running_in_global_zone(void);
+boolean_t _z_zones_are_implemented(void);
+void _z_sig_trap(int a_signo);
+int _z_close_file_descriptors(void *a_fds, int a_fd);
+boolean_t _z_brands_are_implemented(void);
+
+
+/* ---> zones_locks.c */
+
+boolean_t _z_adjust_lock_object_for_rootpath(char **r_result,
+ char *a_lockObject);
+boolean_t _z_acquire_lock(char **r_lockKey, char *a_zoneName,
+ char *a_lock, pid_t a_pid, boolean_t a_wait);
+boolean_t _z_lock_zone(zoneListElement_t *a_zlst,
+ ZLOCKS_T a_lflags);
+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);
+boolean_t _z_release_lock(char *a_zoneName, char *a_lock,
+ char *a_key, boolean_t a_wait);
+boolean_t _z_unlock_zone(zoneListElement_t *a_zlst,
+ ZLOCKS_T a_lflags);
+boolean_t _z_unlock_zone_object(char **r_objectLocks,
+ char *a_zoneName, char *a_lockObject,
+ char *a_errMsg);
+
+/* ---> zones_args.c */
+
+void _z_free_args(argArray_t *a_args);
+argArray_t *_z_new_args(int initialCount);
+/*PRINTFLIKE2*/
+boolean_t _z_add_arg(argArray_t *a_args, char *a_format, ...);
+int _z_get_argc(argArray_t *a_args);
+char **_z_get_argv(argArray_t *a_args);
+
+/* ---> zones_str.c */
+
+boolean_t _z_strContainsToken(char *a_string, char *a_token,
+ char *a_separators);
+char *_z_strGetToken(char *r_sep, char *a_string,
+ int a_index, char *a_separators);
+void _z_strRemoveLeadingWhitespace(char **a_str);
+void _z_strGetToken_r(char *r_sep, char *a_string,
+ int a_index, char *a_separators, char *a_buf,
+ int a_bufLen);
+void _z_strAddToken(char **a_old, char *a_new,
+ char a_separator);
+void _z_strRemoveToken(char **r_string, char *a_token,
+ char *a_separators, int a_index);
+/*PRINTFLIKE3*/
+void _z_strPrintf_r(char *a_buf, int a_bufLen,
+ char *a_format, ...);
+/*PRINTFLIKE1*/
+char *_z_strPrintf(char *a_format, ...);
+
+/* ---> zones_exec.c */
+
+int _z_zone_exec(int *r_status, char **r_results, char *a_inputFile,
+ char *a_path, char *a_argv[], const char *a_zoneName,
+ int *a_fds);
+int _zexec(const char *a_zoneName,
+ const char *path, char *argv[]);
+char *_zexec_add_env(char *name, char *value);
+int _zexec_init_template(void);
+char **_zexec_prep_env();
+
+/*
+ * C++ postfix
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _INSTZONES_LIB_H */
diff --git a/usr/src/lib/libinstzones/common/llib-linstzones b/usr/src/lib/libinstzones/common/llib-linstzones
new file mode 100644
index 0000000000..9d1d8a5f69
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/llib-linstzones
@@ -0,0 +1,31 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include "instzones_api.h"
diff --git a/usr/src/lib/libinstzones/common/mapfile-vers b/usr/src/lib/libinstzones/common/mapfile-vers
new file mode 100644
index 0000000000..4b3e5c32f5
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/mapfile-vers
@@ -0,0 +1,94 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate {
+ global:
+ UmountAllZones;
+ z_add_inherited_file_system;
+ z_brands_are_implemented;
+ z_canoninplace;
+ z_createMountTable;
+ z_create_zone_admin_file;
+ z_destroyMountTable;
+ z_ExecCmdArray;
+ z_ExecCmdList;
+ z_free_brand_list;
+ z_free_inherited_file_systems;
+ z_free_zone_list;
+ z_get_inherited_file_systems;
+ z_get_nonglobal_zone_list;
+ z_get_nonglobal_zone_list_by_brand;
+ z_get_zonename;
+ z_global_only;
+ z_isPathWritable;
+ z_is_zone_branded;
+ z_is_zone_brand_in_list;
+ z_lock_this_zone;
+ z_lock_zones;
+ z_make_brand_list;
+ z_make_zone_root;
+ z_mount_in_lz;
+ z_non_global_zones_exist;
+ z_on_zone_spec;
+ z_path_canonize;
+ z_path_is_inherited;
+ z_resolve_lofs;
+ z_running_in_global_zone;
+ z_set_output_functions;
+ z_set_zone_root;
+ z_set_zone_spec;
+ z_umount_lz_mount;
+ z_unlock_this_zone;
+ z_unlock_zones;
+ z_verify_zone_spec;
+ z_zlist_change_zone_state;
+ z_zlist_get_current_state;
+ z_zlist_get_inherited_pkg_dirs;
+ z_zlist_get_original_state;
+ z_zlist_get_scratch;
+ z_zlist_get_zonename;
+ z_zlist_get_zonepath;
+ z_zlist_is_zone_runnable;
+ z_zlist_restore_zone_state;
+ z_zone_exec;
+ local:
+ *;
+};
+
diff --git a/usr/src/lib/libinstzones/common/zones.c b/usr/src/lib/libinstzones/common/zones.c
new file mode 100644
index 0000000000..8b62e15751
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones.c
@@ -0,0 +1,2425 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Module: zones.c
+ * Group: libinstzones
+ * Description: Provide "zones" interface for install consolidation code
+ *
+ * Public Methods:
+ * z_create_zone_admin_file - Given a location to create the file, and
+ * optionally an existing administration file, generate an
+ * administration file that can be used to perform "non-interactive"
+ * operations in a non-global zone.
+ * z_free_zone_list - free contents of zoneList_t object
+ * z_get_nonglobal_zone_list - return zoneList_t object describing all
+ * non-global native zones
+ * z_get_nonglobal_zone_list_by_brand - return zoneList_t object describing
+ * all non-global zones matching the list of zone brands passed in.
+ * z_free_brand_list - free contents of a zoneBrandList_t object
+ * z_make_brand_list - return a zoneBrandList_t object describing the list
+ * of all zone brands passed in.
+ * z_get_zonename - return the name of the current zone
+ * z_global_only - Determine if the global zone is only zone on the spec list
+ * z_lock_this_zone - lock this zone
+ * z_lock_zones - lock specified zones
+ * z_mount_in_lz - Mount global zone directory in specified zone's root file
+ * system
+ * z_non_global_zones_exist - Determine if any non-global native zones exist
+ * z_on_zone_spec - Determine if named zone is on the zone_spec list
+ * z_running_in_global_zone - Determine if running in the "global" zone
+ * z_set_output_functions - Link program specific output functions
+ * z_set_zone_root - Set root for zones library operations
+ * z_set_zone_spec - Set list of zones on which actions will be performed
+ * z_umount_lz_mount - Unmount directory mounted with z_mount_in_lz
+ * z_unlock_this_zone - unlock this zone
+ * z_unlock_zones - unlock specified zones
+ * z_verify_zone_spec - Verify list of zones on which actions will be performed
+ * z_zlist_change_zone_state - Change the current state of the specified zone
+ * z_zlist_get_current_state - Determine the current kernel state of the
+ * specified zone
+ * z_zlist_get_inherited_pkg_dirs - Determine directories inherited by
+ * specified zone
+ * z_zlist_get_original_state - Return the original kernal state of the
+ * specified zone
+ * z_zlist_get_scratch - Determine name of scratch zone
+ * z_zlist_get_zonename - Determine name of specified zone
+ * z_zlist_get_zonepath - Determine zonepath of specified zone
+ * z_zlist_restore_zone_state - Return the zone to the state it was originally
+ * in
+ * z_zone_exec - Execute a Unix command in a specified zone and return results
+ * z_zones_are_implemented - Determine if any zone operations can be performed
+ * z_is_zone_branded - determine if zone has a non-native brand
+ * z_is_zone_brand_in_list - determine if the zone's brand matches the
+ * brand list passed in.
+ * z_brands_are_implemented - determine if branded zones are implemented on
+ * this system
+ */
+
+/*
+ * System includes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysmacros.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+#include <time.h>
+#include <signal.h>
+#include <stropts.h>
+#include <wait.h>
+#include <zone.h>
+#include <sys/brand.h>
+#include <libintl.h>
+#include <locale.h>
+#include <libzonecfg.h>
+#include <libcontract.h>
+#include <sys/contract/process.h>
+#include <sys/ctfs.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <time.h>
+
+/*
+ * local includes
+ */
+
+/*
+ * When _INSTZONES_LIB_Z_DEFINE_GLOBAL_DATA is defined,
+ * instzones_lib.h will define the z_global_data structure.
+ * Otherwise an extern to the structure is inserted.
+ */
+
+#define _INSTZONES_LIB_Z_DEFINE_GLOBAL_DATA
+#include "instzones_lib.h"
+#include "zones_strings.h"
+
+/*
+ * Private structures
+ */
+
+#define CLUSTER_BRAND_NAME "cluster"
+
+/* maximum number of arguments to exec() call */
+
+#define UUID_FORMAT "%02d%02d%02d%03d-%02d%02d%02d%d-%016llx"
+
+/*
+ * Library Function Prototypes
+ */
+
+#define streq(a, b) (strcmp((a), (b)) == 0)
+
+/*
+ * Local Function Prototypes
+ */
+
+/*
+ * global internal (private) declarations
+ */
+
+/*
+ * *****************************************************************************
+ * global external (public) functions
+ * *****************************************************************************
+ */
+
+/*
+ * Name: z_create_zone_admin_file
+ * Description: Given a location to create the file, and optionally an existing
+ * administration file, generate an administration file that
+ * can be used to perform "non-interactive" operations in a
+ * non-global zone.
+ * Arguments: a_zoneAdminFilename - pointer to string representing the
+ * full path of zone admin file to create
+ * a_userAdminFilename - pointer to string representing the path
+ * to an existing "user" administration file - the
+ * administration file created will contain the
+ * settings contained in this file, modified as
+ * appropriate to supress any interaction;
+ * If this is == NULL then the administration file
+ * created will not contain any extra settings
+ * Returns: boolean_t
+ * == B_TRUE - admin file created
+ * == B_FALSE - failed to create admin file
+ */
+
+boolean_t
+z_create_zone_admin_file(char *a_zoneAdminFilename, char *a_userAdminFilename)
+{
+ FILE *zFp;
+ FILE *uFp = (FILE *)NULL;
+
+ /* entry assertions */
+
+ assert(a_zoneAdminFilename != NULL);
+ assert(*a_zoneAdminFilename != '\0');
+
+ /* create temporary zone admin file */
+
+ zFp = fopen(a_zoneAdminFilename, "w");
+ if (zFp == (FILE *)NULL) {
+ return (B_FALSE);
+ }
+
+ /* open user admin file if specified */
+
+ if (a_userAdminFilename != (char *)NULL) {
+ uFp = fopen(a_userAdminFilename, "r");
+ }
+
+ /* create default admin file for zone pkg ops if no user admin file */
+
+ if (uFp == (FILE *)NULL) {
+ /* create default admin file */
+ (void) fprintf(zFp, "action=nocheck\nauthentication=nocheck\n"
+ "basedir=default\nconflict=nocheck\nidepend=nocheck\n"
+ "instance=unique\npartial=nocheck\nrdepend=nocheck\n"
+ "runlevel=nocheck\nsetuid=nocheck\nspace=nocheck\n"
+ "mail=\n");
+ } else for (;;) {
+ /* copy user admin file substitute/change appropriate entries */
+ char buf[LINE_MAX+1];
+ char *p;
+
+ /* read next line of user admin file */
+
+ p = fgets(buf, sizeof (buf), uFp);
+ if (p == (char *)NULL) {
+ (void) fclose(uFp);
+ break;
+ }
+
+ /* modify / replace / accept as appropriate */
+
+ if (strncmp(buf, "instance=quit", 13) == 0) {
+ (void) fprintf(zFp, "%s", "instance=unique\n");
+ /*LINTED*/
+ } else if (strncmp(buf, "keystore=", 9) == 0) {
+ } else if (strncmp(buf, "action=", 7) == 0) {
+ (void) fprintf(zFp, "action=nocheck\n");
+ } else if (strncmp(buf, "authentication=", 15) == 0) {
+ (void) fprintf(zFp, "authentication=nocheck\n");
+ } else if (strncmp(buf, "conflict=", 9) == 0) {
+ (void) fprintf(zFp, "conflict=nocheck\n");
+ } else if (strncmp(buf, "idepend=", 8) == 0) {
+ (void) fprintf(zFp, "idepend=nocheck\n");
+ } else if (strncmp(buf, "mail=", 5) == 0) {
+ (void) fprintf(zFp, "mail=\n");
+ } else if (strncmp(buf, "partial=", 8) == 0) {
+ (void) fprintf(zFp, "partial=nocheck\n");
+ } else if (strncmp(buf, "rdepend=", 8) == 0) {
+ (void) fprintf(zFp, "rdepend=nocheck\n");
+ } else if (strncmp(buf, "runlevel=", 9) == 0) {
+ (void) fprintf(zFp, "runlevel=nocheck\n");
+ } else if (strncmp(buf, "setuid=", 7) == 0) {
+ (void) fprintf(zFp, "setuid=nocheck\n");
+ } else if (strncmp(buf, "space=", 6) == 0) {
+ (void) fprintf(zFp, "space=nocheck\n");
+ } else {
+ (void) fprintf(zFp, "%s", buf);
+ }
+ }
+
+ /* close admin file and return success */
+
+ (void) fclose(zFp);
+ return (B_TRUE);
+}
+
+/*
+ * Name: z_brands_are_implemented
+ * Description: Determine if any branded zones may be present
+ * Arguments: void
+ * Returns: boolean_t
+ * == B_TRUE - branded zones are supported
+ * == B_FALSE - branded zones are not supported
+ */
+
+boolean_t
+z_brands_are_implemented(void)
+{
+static boolean_t _brandsImplementedDetermined = B_FALSE;
+static boolean_t _brandsAreImplemented = B_FALSE;
+
+ /* if availability has not been determined, cache it now */
+
+ if (!_brandsImplementedDetermined) {
+ _brandsImplementedDetermined = B_TRUE;
+ _brandsAreImplemented = _z_brands_are_implemented();
+ if (_brandsAreImplemented) {
+ _z_echoDebug(DBG_BRANDS_ARE_IMPLEMENTED);
+ } else {
+ _z_echoDebug(DBG_BRANDS_NOT_IMPLEMENTED);
+ }
+ }
+
+ /* return cached answer */
+
+ return (_brandsAreImplemented);
+}
+
+/*
+ * Name: z_free_zone_list
+ * Description: free contents of zoneList_t object
+ * Arguments: a_zlst - handle to zoneList_t object to free
+ * Returns: void
+ */
+
+void
+z_free_zone_list(zoneList_t a_zlst)
+{
+ int numzones;
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ return;
+ }
+
+ /* free each entry in the zone list */
+
+ for (numzones = 0; a_zlst[numzones]._zlName != (char *)NULL;
+ numzones++) {
+ zoneListElement_t *zelm = &a_zlst[numzones];
+
+ /* free zone name string */
+
+ free(zelm->_zlName);
+
+ /* free zonepath string */
+
+ if (zelm->_zlPath != (char *)NULL) {
+ free(zelm->_zlPath);
+ }
+
+ /* free list of inherited package directories */
+
+ if (zelm->_zlInheritedDirs != (char **)NULL) {
+ int n;
+
+ for (n = 0;
+ (zelm->_zlInheritedDirs)[n] != (char *)NULL;
+ n++) {
+ (void) free((zelm->_zlInheritedDirs)[n]);
+ }
+ (void) free(zelm->_zlInheritedDirs);
+ }
+ }
+
+ /* free handle to the list */
+
+ free(a_zlst);
+}
+
+/*
+ * Name: z_get_nonglobal_zone_list
+ * Description: return zoneList_t object describing all non-global
+ * native zones - branded zones are not included in list
+ * Arguments: None.
+ * Returns: zoneList_t
+ * == NULL - error, list could not be generated
+ * != NULL - success, list returned
+ * NOTE: Any zoneList_t returned is placed in new storage for the
+ * calling function. The caller must use 'z_free_zone_list' to
+ * dispose of the storage once the list is no longer needed.
+ */
+
+zoneList_t
+z_get_nonglobal_zone_list(void)
+{
+ zoneList_t zones;
+ zoneBrandList_t *brands = NULL;
+
+ if ((brands = z_make_brand_list("native cluster", " ")) == NULL)
+ return (NULL);
+
+ zones = z_get_nonglobal_zone_list_by_brand(brands);
+
+ z_free_brand_list(brands);
+
+ return (zones);
+}
+
+/*
+ * Name: z_free_brand_list
+ * Description: Free contents of zoneBrandList_t object
+ * Arguments: brands - pointer to zoneBrandList_t object to free
+ * Returns: void
+ */
+void
+z_free_brand_list(zoneBrandList_t *brands)
+{
+ while (brands != NULL) {
+ zoneBrandList_t *temp = brands;
+ free(brands->string_ptr);
+ brands = brands->next;
+ free(temp);
+ }
+}
+
+/*
+ * Name: z_make_brand_list
+ * Description: Given a string with a list of brand name delimited by
+ * the delimeter passed in, build a zoneBrandList_t structure
+ * with the list of brand names and return it to the caller.
+ * Arguments:
+ * brands - const char pointer to string list of brand names
+ * delim - const char pointer to string representing the
+ * delimeter for brands string.
+ * Returns: zoneBrandList_t *
+ * == NULL - error, list could not be generated
+ * != NULL - success, list returned
+ * NOTE: Any zoneBrandList_t returned is placed in new storage for the
+ * calling function. The caller must use 'z_free_brand_list' to
+ * dispose of the storage once the list is no longer needed.
+ */
+zoneBrandList_t *
+z_make_brand_list(const char *brands, const char *delim)
+{
+ zoneBrandList_t *brand = NULL, *head = NULL;
+ char *blist = NULL;
+ char *str = NULL;
+
+ if ((blist = strdup(brands)) == NULL)
+ return (NULL);
+
+ if ((str = strtok(blist, delim)) != NULL) {
+ if ((brand = (zoneBrandList_t *)
+ malloc(sizeof (struct _zoneBrandList))) == NULL) {
+ return (NULL);
+ }
+
+ head = brand;
+ brand->string_ptr = strdup(str);
+ brand->next = NULL;
+
+ while ((str = strtok(NULL, delim)) != NULL) {
+ if ((brand->next = (zoneBrandList_t *)
+ malloc(sizeof (struct _zoneBrandList))) == NULL) {
+ return (NULL);
+ }
+
+ brand = brand->next;
+ brand->string_ptr = strdup(str);
+ brand->next = NULL;
+ }
+ }
+
+ free(blist);
+ return (head);
+}
+
+/*
+ * Name: z_get_nonglobal_zone_list_by_brand
+ * Description: return zoneList_t object describing all non-global
+ * zones matching the list of brands passed in.
+ * Arguments: brands - The list of zone brands to look for.
+ * Returns: zoneList_t
+ * == NULL - error, list could not be generated
+ * != NULL - success, list returned
+ * NOTE: Any zoneList_t returned is placed in new storage for the
+ * calling function. The caller must use 'z_free_zone_list' to
+ * dispose of the storage once the list is no longer needed.
+ */
+zoneList_t
+z_get_nonglobal_zone_list_by_brand(zoneBrandList_t *brands)
+{
+ FILE *zoneIndexFP;
+ int numzones = 0;
+ struct zoneent *ze;
+ zoneList_t zlst = NULL;
+ FILE *mapFP;
+ char zonename[ZONENAME_MAX];
+ zone_spec_t *zent;
+
+ /* if zones are not implemented, return empty list */
+
+ if (!z_zones_are_implemented()) {
+ return ((zoneList_t)NULL);
+ }
+
+ /*
+ * Open the zone index file. Note that getzoneent_private() handles
+ * NULL.
+ */
+ zoneIndexFP = setzoneent();
+
+ mapFP = zonecfg_open_scratch("", B_FALSE);
+
+ /* index file open; scan all zones; see if any are at least installed */
+
+ while ((ze = getzoneent_private(zoneIndexFP)) != NULL) {
+ zone_state_t st;
+
+ /* skip the global zone */
+
+ if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0) {
+ free(ze);
+ continue;
+ }
+
+ /*
+ * skip any zones with brands not on the brand list
+ */
+ if (!z_is_zone_brand_in_list(ze->zone_name, brands)) {
+ free(ze);
+ continue;
+ }
+
+ /*
+ * If the user specified an explicit zone list, then ignore any
+ * zones that aren't on that list.
+ */
+ if ((zent = _z_global_data._zone_spec) != NULL) {
+ while (zent != NULL) {
+ if (strcmp(zent->zl_name, ze->zone_name) == 0)
+ break;
+ zent = zent->zl_next;
+ }
+ if (zent == NULL) {
+ free(ze);
+ continue;
+ }
+ }
+
+ /* non-global zone: create entry for this zone */
+
+ if (numzones == 0) {
+ zlst = (zoneList_t)_z_calloc(
+ sizeof (zoneListElement_t)*2);
+ } else {
+ zlst = (zoneList_t)_z_realloc(zlst,
+ sizeof (zoneListElement_t)*(numzones+2));
+ (void) memset(&zlst[numzones], 0L,
+ sizeof (zoneListElement_t)*2);
+ }
+
+ /*
+ * remember the zone name, zonepath and the current
+ * zone state of the zone.
+ */
+ zlst[numzones]._zlName = _z_strdup(ze->zone_name);
+ zlst[numzones]._zlPath = _z_strdup(ze->zone_path);
+ zlst[numzones]._zlOrigInstallState = ze->zone_state;
+ zlst[numzones]._zlCurrInstallState = ze->zone_state;
+
+ /* get the zone kernel status */
+
+ if (zone_get_state(ze->zone_name, &st) != Z_OK) {
+ st = ZONE_STATE_INCOMPLETE;
+ }
+
+ _z_echoDebug(DBG_ZONES_NGZ_LIST_STATES,
+ ze->zone_name, ze->zone_state, st);
+
+ /*
+ * For a scratch zone, we need to know the kernel zone name.
+ */
+ if (zonecfg_in_alt_root() && mapFP != NULL &&
+ zonecfg_find_scratch(mapFP, ze->zone_name,
+ zonecfg_get_root(), zonename, sizeof (zonename)) != -1) {
+ free(zlst[numzones]._zlScratchName);
+ zlst[numzones]._zlScratchName = _z_strdup(zonename);
+ }
+
+ /*
+ * remember the current kernel status of the zone.
+ */
+
+ zlst[numzones]._zlOrigKernelStatus = st;
+ zlst[numzones]._zlCurrKernelStatus = st;
+
+ zlst[numzones]._zlInheritedDirs =
+ _z_get_inherited_dirs(ze->zone_name);
+
+ numzones++;
+ free(ze);
+ }
+
+ /* close the index file */
+ endzoneent(zoneIndexFP);
+
+ if (mapFP != NULL)
+ zonecfg_close_scratch(mapFP);
+
+ /* return generated list */
+
+ return (zlst);
+}
+
+/*
+ * Name: z_get_zonename
+ * Description: return the name of the current zone
+ * Arguments: void
+ * Returns: char *
+ * - pointer to string representing the name of the current
+ * zone
+ * 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.
+ */
+
+char *
+z_get_zonename(void)
+{
+ ssize_t zonenameLen;
+ char zonename[ZONENAME_MAX];
+ zoneid_t zoneid = (zoneid_t)-1;
+
+ /* if zones are not implemented, return "" */
+
+ if (!z_zones_are_implemented()) {
+ return (_z_strdup(""));
+ }
+
+ /* get the zone i.d. of the current zone */
+
+ zoneid = getzoneid();
+
+ /* get the name of the current zone */
+
+ zonenameLen = getzonenamebyid(zoneid, zonename, sizeof (zonename));
+
+ /* return "" if could not get zonename */
+
+ if (zonenameLen < 1) {
+ return (_z_strdup(""));
+ }
+
+ return (_z_strdup(zonename));
+}
+
+/*
+ * Name: z_global_only
+ * Description: Determine if the global zone is only zone on the spec list.
+ * Arguments: None
+ * Returns: B_TRUE if global zone is the only zone on the list,
+ * B_FALSE otherwise.
+ */
+
+boolean_t
+z_global_only(void)
+{
+ /* return true if zones are not implemented - treate as global zone */
+
+ if (!z_zones_are_implemented()) {
+ return (B_TRUE);
+ }
+
+ /* return true if this is the global zone */
+
+ if (_z_global_data._zone_spec != NULL &&
+ _z_global_data._zone_spec->zl_next == NULL &&
+ strcmp(_z_global_data._zone_spec->zl_name, GLOBAL_ZONENAME) == 0) {
+ return (B_TRUE);
+ }
+
+ /* return false - not the global zone */
+
+ return (B_FALSE);
+}
+
+/*
+ * Name: z_lock_this_zone
+ * Description: lock this zone
+ * Arguments: a_lflags - [RO, *RO] - (ZLOCKS_T)
+ * Flags indicating which locks to acquire
+ * Returns: boolean_t
+ * == B_TRUE - success specified locks acquired
+ * == B_FALSE - failure specified locks not acquired
+ * NOTE: the lock objects for "this zone" are maintained internally.
+ */
+
+boolean_t
+z_lock_this_zone(ZLOCKS_T a_lflags)
+{
+ boolean_t b;
+ char *zoneName;
+ pid_t pid = (pid_t)0;
+
+ /* entry assertions */
+
+ assert(a_lflags != ZLOCKS_NONE);
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_LCK_THIS, a_lflags);
+
+ zoneName = z_get_zonename();
+ pid = getpid();
+
+ /* lock zone administration */
+
+ if (a_lflags & ZLOCKS_ZONE_ADMIN) {
+ b = _z_lock_zone_object(&_z_global_data._z_ObjectLocks,
+ zoneName, LOBJ_ZONEADMIN, pid,
+ MSG_ZONES_LCK_THIS_ZONEADM,
+ ERR_ZONES_LCK_THIS_ZONEADM);
+ if (!b) {
+ (void) free(zoneName);
+ return (B_FALSE);
+ }
+ }
+
+ /* lock package administration always */
+
+ if (a_lflags & ZLOCKS_PKG_ADMIN) {
+ b = _z_lock_zone_object(&_z_global_data._z_ObjectLocks,
+ zoneName, LOBJ_PKGADMIN, pid,
+ MSG_ZONES_LCK_THIS_PKGADM,
+ ERR_ZONES_LCK_THIS_PKGADM);
+ if (!b) {
+ (void) z_unlock_this_zone(a_lflags);
+ (void) free(zoneName);
+ return (B_FALSE);
+ }
+ }
+
+ /* lock patch administration always */
+
+ if (a_lflags & ZLOCKS_PATCH_ADMIN) {
+ b = _z_lock_zone_object(&_z_global_data._z_ObjectLocks,
+ zoneName, LOBJ_PATCHADMIN, pid,
+ MSG_ZONES_LCK_THIS_PATCHADM,
+ ERR_ZONES_LCK_THIS_PATCHADM);
+ if (!b) {
+ (void) z_unlock_this_zone(a_lflags);
+ (void) free(zoneName);
+ return (B_FALSE);
+ }
+ }
+
+ (void) free(zoneName);
+
+ return (B_TRUE);
+}
+
+/*
+ * Name: z_lock_zones
+ * Description: lock specified zones
+ * Arguments: a_zlst - zoneList_t object describing zones to lock
+ * a_lflags - [RO, *RO] - (ZLOCKS_T)
+ * Flags indicating which locks to acquire
+ * Returns: boolean_t
+ * == B_TRUE - success, zones locked
+ * == B_FALSE - failure, zones not locked
+ */
+
+boolean_t
+z_lock_zones(zoneList_t a_zlst, ZLOCKS_T a_lflags)
+{
+ boolean_t b;
+ int i;
+
+ /* entry assertions */
+
+ assert(a_lflags != ZLOCKS_NONE);
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_LCK_ZONES, a_lflags);
+
+ /* if zones are not implemented, return TRUE */
+
+ if (z_zones_are_implemented() == B_FALSE) {
+ _z_echoDebug(DBG_ZONES_LCK_ZONES_UNIMP);
+ return (B_TRUE);
+ }
+
+ /* lock this zone first before locking other zones */
+
+ b = z_lock_this_zone(a_lflags);
+ if (b == B_FALSE) {
+ return (b);
+ }
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ _z_echoDebug(DBG_ZONES_LCK_ZONES_NOZONES);
+ return (B_FALSE);
+ }
+
+ /* zones exist */
+
+ _z_echoDebug(DBG_ZONES_LCK_ZONES_EXIST);
+
+ /*
+ * lock each listed zone that is currently running
+ */
+
+ for (i = 0; (a_zlst[i]._zlName != (char *)NULL); i++) {
+ /* ignore zone if already locked */
+ if (a_zlst[i]._zlStatus & ZST_LOCKED) {
+ continue;
+ }
+
+ /* ignore zone if not running */
+ if (a_zlst[i]._zlCurrKernelStatus != ZONE_STATE_RUNNING &&
+ a_zlst[i]._zlCurrKernelStatus != ZONE_STATE_MOUNTED) {
+ continue;
+ }
+
+ /*
+ * mark zone locked - if interrupted out during lock, an attempt
+ * will be made to release the lock
+ */
+ a_zlst[i]._zlStatus |= ZST_LOCKED;
+
+ /* lock this zone */
+ b = _z_lock_zone(&a_zlst[i], a_lflags);
+
+ /* on failure unlock all zones and return error */
+ if (b != B_TRUE) {
+ _z_program_error(ERR_ZONES_LCK_ZONES_FAILED,
+ a_zlst[i]._zlName);
+ (void) z_unlock_zones(a_zlst, a_lflags);
+ return (B_FALSE);
+ }
+ }
+
+ /* success */
+
+ return (B_TRUE);
+}
+
+/*
+ * Name: z_mount_in_lz
+ * Description: Mount global zone directory in specified zone's root file system
+ * Arguments: r_lzMountPoint - pointer to handle to string - on success, the
+ * full path to the mount point relative to the global zone
+ * root file system is returned here - this is needed to
+ * unmount the directory when it is no longer needed
+ * r_lzRootPath - pointer to handle to string - on success, the
+ * full path to the mount point relative to the specified
+ * zone's root file system is returned here - this is
+ * passed to any command executing in the specified zone to
+ * access the directory mounted
+ * a_zoneName - pointer to string representing the name of the zone
+ * to mount the specified global zone directory in
+ * a_gzPath - pointer to string representing the full absolute path
+ * of the global zone directory to LOFS mount inside of the
+ * specified non-global zone
+ * a_mountPointPrefix - pointer to string representing the prefix
+ * to be used when creating the mount point name in the
+ * specified zone's root directory
+ * Returns: boolean_t
+ * == B_TRUE - global zone directory mounted successfully
+ * == B_FALSE - failed to mount directory in specified zone
+ * NOTE: Any strings returned is placed in new storage for the
+ * calling function. The caller must use 'Free' to dispose
+ * of the storage once the strings are no longer needed.
+ */
+
+boolean_t
+z_mount_in_lz(char **r_lzMountPoint, char **r_lzRootPath, char *a_zoneName,
+ char *a_gzPath, char *a_mountPointPrefix)
+{
+ char lzRootPath[MAXPATHLEN] = {'\0'};
+ char uuid[MAXPATHLEN] = {'\0'};
+ char gzMountPoint[MAXPATHLEN] = {'\0'};
+ char lzMountPoint[MAXPATHLEN] = {'\0'};
+ hrtime_t hretime;
+ int err;
+ int slen;
+ struct tm tstruct;
+ time_t thetime;
+ zoneid_t zid;
+
+ /* entry assertions */
+
+ assert(a_zoneName != (char *)NULL);
+ assert(*a_zoneName != '\0');
+ assert(a_gzPath != (char *)NULL);
+ assert(*a_gzPath != '\0');
+ assert(r_lzMountPoint != (char **)NULL);
+ assert(r_lzRootPath != (char **)NULL);
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_MOUNT_IN_LZ_ENTRY, a_zoneName, a_gzPath);
+
+ /* reset returned non-global zone mount point path handle */
+
+ *r_lzMountPoint = (char *)NULL;
+ *r_lzRootPath = (char *)NULL;
+
+ /* if zones are not implemented, return FALSE */
+
+ if (z_zones_are_implemented() == B_FALSE) {
+ return (B_FALSE);
+ }
+
+ /* error if global zone path is not absolute */
+
+ if (*a_gzPath != '/') {
+ _z_program_error(ERR_GZPATH_NOT_ABSOLUTE, a_gzPath);
+ return (B_FALSE);
+ }
+
+ /* error if global zone path does not exist */
+
+ if (_z_is_directory(a_gzPath) != 0) {
+ _z_program_error(ERR_GZPATH_NOT_DIR, a_gzPath, strerror(errno));
+ return (B_FALSE);
+ }
+
+ /* verify that specified non-global zone exists */
+
+ err = zone_get_id(a_zoneName, &zid);
+ if (err != Z_OK) {
+ _z_program_error(ERR_GET_ZONEID, a_zoneName,
+ zonecfg_strerror(err));
+ return (B_FALSE);
+ }
+
+ /* obtain global zone path to non-global zones root file system */
+
+ err = zone_get_rootpath(a_zoneName, lzRootPath, sizeof (lzRootPath));
+ if (err != Z_OK) {
+ _z_program_error(ERR_NO_ZONE_ROOTPATH, a_zoneName,
+ zonecfg_strerror(err));
+ return (B_FALSE);
+ }
+
+ if (lzRootPath[0] == '\0') {
+ _z_program_error(ERR_ROOTPATH_EMPTY, a_zoneName);
+ return (B_FALSE);
+ }
+
+ /*
+ * lofs resolve the non-global zone's root path first in case
+ * its in a path that's been lofs mounted read-only.
+ * (e.g. This happens when we're tyring to patch a zone in an ABE
+ * that lives on a filesystem that the ABE shares with the currently
+ * running BE.)
+ */
+ z_resolve_lofs(lzRootPath, sizeof (lzRootPath));
+
+ /* verify that the root path exists */
+
+ if (_z_is_directory(lzRootPath) != 0) {
+ _z_program_error(ERR_LZROOT_NOTDIR, lzRootPath,
+ strerror(errno));
+ return (B_FALSE);
+ }
+
+ /*
+ * generate a unique key - the key is the same length as unique uid
+ * but contains different information that is as unique as can be made;
+ * include current hires time (nanosecond real timer). Such a unique
+ * i.d. will look like:
+ * 0203104092-1145345-0004e94d6af481a0
+ */
+
+ hretime = gethrtime();
+
+ thetime = time((time_t *)NULL);
+ (void) localtime_r(&thetime, &tstruct);
+
+ slen = snprintf(uuid, sizeof (uuid),
+ UUID_FORMAT,
+ tstruct.tm_mday, tstruct.tm_mon, tstruct.tm_year,
+ tstruct.tm_yday, tstruct.tm_hour, tstruct.tm_min,
+ tstruct.tm_sec, tstruct.tm_wday, hretime);
+ if (slen > sizeof (uuid)) {
+ _z_program_error(ERR_GZMOUNT_SNPRINTFUUID_FAILED,
+ UUID_FORMAT, sizeof (uuid));
+ return (B_FALSE);
+ }
+
+ /* create the global zone mount point */
+
+ slen = snprintf(gzMountPoint, sizeof (gzMountPoint), "%s/.SUNW_%s_%s",
+ lzRootPath,
+ a_mountPointPrefix ? a_mountPointPrefix : "zones", uuid);
+ if (slen > sizeof (gzMountPoint)) {
+ _z_program_error(ERR_GZMOUNT_SNPRINTFGMP_FAILED,
+ "%s/.SUNW_%s_%s", lzRootPath,
+ a_mountPointPrefix ? a_mountPointPrefix : "zones",
+ uuid, sizeof (gzMountPoint));
+ return (B_FALSE);
+ }
+
+ slen = snprintf(lzMountPoint, sizeof (lzMountPoint), "%s",
+ gzMountPoint+strlen(lzRootPath));
+ if (slen > sizeof (lzMountPoint)) {
+ _z_program_error(ERR_GZMOUNT_SNPRINTFLMP_FAILED,
+ "%s", gzMountPoint+strlen(lzRootPath),
+ sizeof (lzMountPoint));
+ return (B_FALSE);
+ }
+
+ _z_echoDebug(DBG_MNTPT_NAMES, a_gzPath, a_zoneName, gzMountPoint,
+ lzMountPoint);
+
+ /* error if the mount point already exists */
+
+ if (_z_is_directory(gzMountPoint) == 0) {
+ _z_program_error(ERR_ZONEROOT_NOTDIR, gzMountPoint,
+ a_zoneName, strerror(errno));
+ return (B_FALSE);
+ }
+
+ /* create the temporary mount point */
+
+ if (mkdir(gzMountPoint, 0600) != 0) {
+ _z_program_error(ERR_MNTPT_MKDIR, gzMountPoint, a_zoneName,
+ strerror(errno));
+ return (B_FALSE);
+ }
+
+ /* mount the global zone path on the non-global zone root file system */
+
+ err = mount(a_gzPath, gzMountPoint, MS_RDONLY|MS_DATA, "lofs",
+ (char *)NULL, 0, (char *)NULL, 0);
+ if (err != 0) {
+ _z_program_error(ERR_GZMOUNT_FAILED, a_gzPath,
+ gzMountPoint, a_zoneName, strerror(errno));
+ return (B_FALSE);
+ }
+
+ /* success - return both mountpoints to caller */
+
+ *r_lzMountPoint = _z_strdup(gzMountPoint);
+
+ *r_lzRootPath = _z_strdup(lzMountPoint);
+
+ /* return success */
+
+ return (B_TRUE);
+}
+
+/*
+ * Name: z_non_global_zones_exist
+ * Description: Determine if any non-global native zones exist
+ * Arguments: None.
+ * Returns: boolean_t
+ * == B_TRUE - at least one non-global native zone exists
+ * == B_FALSE - no non-global native zone exists
+ */
+
+boolean_t
+z_non_global_zones_exist(void)
+{
+ FILE *zoneIndexFP;
+ boolean_t anyExist = B_FALSE;
+ struct zoneent *ze;
+ zone_spec_t *zent;
+
+ /* if zones are not implemented, return FALSE */
+
+ if (z_zones_are_implemented() == B_FALSE) {
+ return (B_FALSE);
+ }
+
+ /* determine if any zones are configured */
+ zoneIndexFP = setzoneent();
+ if (zoneIndexFP == NULL) {
+ return (B_FALSE);
+ }
+
+ /* index file open; scan all zones; see if any are at least installed */
+
+ while ((ze = getzoneent_private(zoneIndexFP)) != NULL) {
+ /*
+ * If the user specified an explicit zone list, then ignore any
+ * zones that aren't on that list.
+ */
+ if ((zent = _z_global_data._zone_spec) != NULL) {
+ while (zent != NULL) {
+ if (strcmp(zent->zl_name, ze->zone_name) == 0)
+ break;
+ zent = zent->zl_next;
+ }
+ if (zent == NULL) {
+ free(ze);
+ continue;
+ }
+ }
+
+ /* skip the global zone */
+ if (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0) {
+ free(ze);
+ continue;
+ }
+
+ /* skip any branded zones */
+ if (z_is_zone_branded(ze->zone_name)) {
+ free(ze);
+ continue;
+ }
+
+ /* is this zone installed? */
+ if (ze->zone_state >= ZONE_STATE_INSTALLED) {
+ free(ze);
+ anyExist = B_TRUE;
+ break;
+ }
+ free(ze);
+ }
+
+ /* close the index file */
+
+ endzoneent(zoneIndexFP);
+
+ /* return results */
+
+ return (anyExist);
+}
+
+/*
+ * Name: z_on_zone_spec
+ * Description: Determine if named zone is on the zone_spec list.
+ * Arguments: Pointer to name to test.
+ * Returns: B_TRUE if named zone is on the list or if the user specified
+ * no list at all (all zones is the default), B_FALSE otherwise.
+ */
+
+boolean_t
+z_on_zone_spec(const char *zonename)
+{
+ zone_spec_t *zent;
+
+ /* entry assertions */
+
+ assert(zonename != NULL);
+ assert(*zonename != '\0');
+
+ /* return true if zones not implemented or no zone spec list defined */
+
+ if (!z_zones_are_implemented() || _z_global_data._zone_spec == NULL) {
+ return (B_TRUE);
+ }
+
+ /* return true if named zone is on the zone spec list */
+
+ for (zent = _z_global_data._zone_spec;
+ zent != NULL; zent = zent->zl_next) {
+ if (strcmp(zent->zl_name, zonename) == 0)
+ return (B_TRUE);
+ }
+
+ /* named zone is not on the zone spec list */
+
+ return (B_FALSE);
+}
+
+/*
+ * Name: z_running_in_global_zone
+ * Description: Determine if running in the "global" zone
+ * Arguments: void
+ * Returns: boolean_t
+ * == B_TRUE - running in global zone
+ * == B_FALSE - not running in global zone
+ */
+
+boolean_t
+z_running_in_global_zone(void)
+{
+ static boolean_t _zoneIdDetermined = B_FALSE;
+ static boolean_t _zoneIsGlobal = B_FALSE;
+
+ /* if ID has not been determined, cache it now */
+
+ if (!_zoneIdDetermined) {
+ _zoneIdDetermined = B_TRUE;
+ _zoneIsGlobal = _z_running_in_global_zone();
+ }
+
+ return (_zoneIsGlobal);
+}
+
+/*
+ * Name: z_set_output_functions
+ * Description: Link program specific output functions to this library.
+ * Arguments: a_echo_fcn - (_z_printf_fcn_t)
+ * Function to call to cause "normal operation" messages
+ * to be output/displayed
+ * a_echo_debug_fcn - (_z_printf_fcn_t)
+ * Function to call to cause "debugging" messages
+ * to be output/displayed
+ * a_progerr_fcn - (_z_printf_fcn_t)
+ * Function to call to cause "program error" messages
+ * to be output/displayed
+ * Returns: void
+ * NOTE: If NULL is specified for any function, then the functionality
+ * associated with that function is disabled.
+ * NOTE: The function pointers provided must call a function that
+ * takes two arguments:
+ * function(char *format, char *message)
+ * Any registered function will be called like:
+ * function("%s", "message")
+ */
+
+void
+z_set_output_functions(_z_printf_fcn_t a_echo_fcn,
+ _z_printf_fcn_t a_echo_debug_fcn,
+ _z_printf_fcn_t a_progerr_fcn)
+{
+ _z_global_data._z_echo = a_echo_fcn;
+ _z_global_data._z_echo_debug = a_echo_debug_fcn;
+ _z_global_data._z_progerr = a_progerr_fcn;
+}
+
+/*
+ * Name: z_set_zone_root
+ * Description: Set root for zones library operations
+ * Arguments: Path to root of boot environment containing zone; must be
+ * absolute.
+ * Returns: None.
+ * NOTE: Must be called before performing any zone-related operations.
+ * (Currently called directly by set_inst_root() during -R
+ * argument handling.)
+ */
+
+void
+z_set_zone_root(const char *zroot)
+{
+ char *rootdir;
+
+ /* if zones are not implemented, just return */
+
+ if (!z_zones_are_implemented())
+ return;
+
+ /* entry assertions */
+
+ assert(zroot != NULL);
+
+ rootdir = _z_strdup((char *)zroot);
+ z_canoninplace(rootdir);
+
+ if (strcmp(rootdir, "/") == 0) {
+ rootdir[0] = '\0';
+ }
+
+ /* free any existing cached root path */
+
+ if (*_z_global_data._z_root_dir != '\0') {
+ free(_z_global_data._z_root_dir);
+ }
+
+ /* store duplicate of new zone root path */
+
+ if (*rootdir != '\0') {
+ _z_global_data._z_root_dir = _z_strdup(rootdir);
+ } else {
+ *_z_global_data._z_root_dir = '\0';
+ }
+
+ /* set zone root path */
+
+ zonecfg_set_root(rootdir);
+
+ free(rootdir);
+}
+
+/*
+ * Name: z_set_zone_spec
+ * Description: Set list of zones on which actions will be performed.
+ * Arguments: Whitespace-separated list of zone names.
+ * Returns: 0 on success, -1 on error.
+ * NOTES: Will call _z_program_error if argument can't be parsed or
+ * memory not available.
+ */
+
+int
+z_set_zone_spec(const char *zlist)
+{
+ const char *zend;
+ ptrdiff_t zlen;
+ zone_spec_t *zent;
+ zone_spec_t *zhead;
+ zone_spec_t **znextp = &zhead;
+
+ /* entry assertions */
+
+ assert(zlist != NULL);
+
+ /* parse list to zone_spec_t list, store in global data */
+
+ for (;;) {
+ while (isspace(*zlist)) {
+ zlist++;
+ }
+ if (*zlist == '\0') {
+ break;
+ }
+ for (zend = zlist; *zend != '\0'; zend++) {
+ if (isspace(*zend)) {
+ break;
+ }
+ }
+ zlen = ((ptrdiff_t)zend) - ((ptrdiff_t)zlist);
+ if (zlen >= ZONENAME_MAX) {
+ _z_program_error(ERR_ZONE_NAME_ILLEGAL, zlen, zlist);
+ return (-1);
+ }
+ zent = _z_malloc(sizeof (*zent));
+ (void) memcpy(zent->zl_name, zlist, zlen);
+ zent->zl_name[zlen] = '\0';
+ zent->zl_used = B_FALSE;
+ *znextp = zent;
+ znextp = &zent->zl_next;
+ zlist = zend;
+ }
+ *znextp = NULL;
+
+ if (zhead == NULL) {
+ _z_program_error(ERR_ZONE_LIST_EMPTY);
+ return (-1);
+ }
+
+ _z_global_data._zone_spec = zhead;
+ return (0);
+}
+
+/*
+ * Name: z_umount_lz_mount
+ * Description: Unmount directory mounted with z_mount_in_lz
+ * Arguments: a_lzMountPointer - pointer to string returned by z_mount_in_lz
+ * Returns: boolean_t
+ * == B_TRUE - successfully unmounted directory
+ * == B_FALSE - failed to unmount directory
+ */
+
+boolean_t
+z_umount_lz_mount(char *a_lzMountPoint)
+{
+ int err;
+
+ /* entry assertions */
+
+ assert(a_lzMountPoint != (char *)NULL);
+ assert(*a_lzMountPoint != '\0');
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_UNMOUNT_FROM_LZ_ENTRY, a_lzMountPoint);
+
+ /* if zones are not implemented, return TRUE */
+
+ if (z_zones_are_implemented() == B_FALSE) {
+ return (B_FALSE);
+ }
+
+ /* error if global zone path is not absolute */
+
+ if (*a_lzMountPoint != '/') {
+ _z_program_error(ERR_LZMNTPT_NOT_ABSOLUTE, a_lzMountPoint);
+ return (B_FALSE);
+ }
+
+ /* verify mount point exists */
+
+ if (_z_is_directory(a_lzMountPoint) != 0) {
+ _z_program_error(ERR_LZMNTPT_NOTDIR, a_lzMountPoint,
+ strerror(errno));
+ return (B_FALSE);
+ }
+
+ /* unmount */
+
+ err = umount2(a_lzMountPoint, 0);
+ if (err != 0) {
+ _z_program_error(ERR_GZUMOUNT_FAILED, a_lzMountPoint,
+ strerror(errno));
+ return (B_FALSE);
+ }
+
+ /* remove the mount point */
+
+ (void) remove(a_lzMountPoint);
+
+ /* return success */
+
+ return (B_TRUE);
+}
+
+/*
+ * Name: z_unlock_this_zone
+ * Description: unlock this zone
+ * Arguments: a_lflags - [RO, *RO] - (ZLOCKS_T)
+ * Flags indicating which locks to release
+ * Returns: boolean_t
+ * == B_TRUE - success specified locks released
+ * == B_FALSE - failure specified locks may not be released
+ * NOTE: the lock objects for "this zone" are maintained internally.
+ */
+
+boolean_t
+z_unlock_this_zone(ZLOCKS_T a_lflags)
+{
+ boolean_t b;
+ boolean_t errors = B_FALSE;
+ char *zoneName;
+
+ /* entry assertions */
+
+ assert(a_lflags != ZLOCKS_NONE);
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_ULK_THIS, a_lflags);
+
+ /* return if no objects locked */
+
+ if ((_z_global_data._z_ObjectLocks == (char *)NULL) ||
+ (*_z_global_data._z_ObjectLocks == '\0')) {
+ return (B_TRUE);
+ }
+
+ zoneName = z_get_zonename();
+
+ /* unlock patch administration */
+
+ if (a_lflags & ZLOCKS_PATCH_ADMIN) {
+ b = _z_unlock_zone_object(&_z_global_data._z_ObjectLocks,
+ zoneName, LOBJ_PATCHADMIN, ERR_ZONES_ULK_THIS_PATCH);
+ if (!b) {
+ errors = B_TRUE;
+ }
+ }
+
+ /* unlock package administration */
+
+ if (a_lflags & ZLOCKS_PKG_ADMIN) {
+ b = _z_unlock_zone_object(&_z_global_data._z_ObjectLocks,
+ zoneName, LOBJ_PKGADMIN, ERR_ZONES_ULK_THIS_PACKAGE);
+ if (!b) {
+ errors = B_TRUE;
+ }
+ }
+
+ /* unlock zone administration */
+
+ if (a_lflags & ZLOCKS_ZONE_ADMIN) {
+ b = _z_unlock_zone_object(&_z_global_data._z_ObjectLocks,
+ zoneName, LOBJ_ZONEADMIN, ERR_ZONES_ULK_THIS_ZONES);
+ if (!b) {
+ errors = B_TRUE;
+ }
+ }
+
+ (void) free(zoneName);
+ return (!errors);
+}
+
+/*
+ * Name: z_unlock_zones
+ * Description: unlock specified zones
+ * Arguments: a_zlst - zoneList_t object describing zones to unlock
+ * a_lflags - [RO, *RO] - (ZLOCKS_T)
+ * Flags indicating which locks to release
+ * Returns: boolean_t
+ * == B_TRUE - success, zones unlocked
+ * == B_FALSE - failure, zones not unlocked
+ */
+
+boolean_t
+z_unlock_zones(zoneList_t a_zlst, ZLOCKS_T a_lflags)
+{
+ boolean_t b;
+ boolean_t errors = B_FALSE;
+ int i;
+
+ /* entry assertions */
+
+ assert(a_lflags != ZLOCKS_NONE);
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_ULK_ZONES, a_lflags);
+
+ /* if zones are not implemented, return TRUE */
+
+ if (z_zones_are_implemented() == B_FALSE) {
+ _z_echoDebug(DBG_ZONES_ULK_ZONES_UNIMP);
+ return (B_TRUE);
+ }
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ _z_echoDebug(DBG_ZONES_ULK_ZONES_NOZONES);
+ /* unlock this zone before returning */
+ return (z_unlock_this_zone(a_lflags));
+ }
+
+ /* zones exist */
+
+ _z_echoDebug(DBG_ZONES_ULK_ZONES_EXIST);
+
+ /*
+ * unlock each listed zone that is currently running
+ */
+
+ for (i = 0; (a_zlst[i]._zlName != (char *)NULL); i++) {
+ /* ignore zone if not locked */
+ if (!(a_zlst[i]._zlStatus & ZST_LOCKED)) {
+ continue;
+ }
+
+ /* ignore zone if not running */
+ if (a_zlst[i]._zlCurrKernelStatus != ZONE_STATE_RUNNING &&
+ a_zlst[i]._zlCurrKernelStatus != ZONE_STATE_MOUNTED) {
+ continue;
+ }
+
+ /* unlock this zone */
+ b = _z_unlock_zone(&a_zlst[i], a_lflags);
+
+ if (b != B_TRUE) {
+ errors = B_TRUE;
+ } else {
+ /* mark zone as unlocked */
+ a_zlst[i]._zlStatus &= ~ZST_LOCKED;
+ }
+ }
+
+ /* unlock this zone */
+
+ if (z_unlock_this_zone(a_lflags) != B_TRUE) {
+ errors = B_TRUE;
+ }
+
+ return (errors);
+}
+
+/*
+ * Name: z_verify_zone_spec
+ * Description: Verify list of zones on which actions will be performed.
+ * Arguments: None.
+ * Returns: 0 on success, -1 on error.
+ * NOTES: Will call _z_program_error if there are zones on the specified
+ * list that don't exist on the system. Requires that
+ * z_set_zone_root is called first (if it is called at all).
+ */
+
+int
+z_verify_zone_spec(void)
+{
+ FILE *zoneIndexFP;
+ boolean_t errors;
+ char zoneIndexPath[MAXPATHLEN];
+ struct zoneent *ze;
+ zone_spec_t *zent;
+
+ if (!z_zones_are_implemented()) {
+ _z_program_error(ERR_ZONES_NOT_IMPLEMENTED);
+ return (-1);
+ }
+
+ zoneIndexFP = setzoneent();
+ if (zoneIndexFP == NULL) {
+ _z_program_error(ERR_ZONEINDEX_OPEN, zoneIndexPath,
+ strerror(errno));
+ return (-1);
+ }
+
+ while ((ze = getzoneent_private(zoneIndexFP)) != NULL) {
+ for (zent = _z_global_data._zone_spec;
+ zent != NULL; zent = zent->zl_next) {
+ if (strcmp(zent->zl_name, ze->zone_name) == 0) {
+ zent->zl_used = B_TRUE;
+ break;
+ }
+ }
+ free(ze);
+ }
+ endzoneent(zoneIndexFP);
+
+ errors = B_FALSE;
+ for (zent = _z_global_data._zone_spec;
+ zent != NULL; zent = zent->zl_next) {
+ if (!zent->zl_used) {
+ _z_program_error(ERR_ZONE_NONEXISTENT, zent->zl_name);
+ errors = B_TRUE;
+ }
+ }
+ return (errors ? -1 : 0);
+}
+
+/*
+ * Name: z_zlist_change_zone_state
+ * Description: Change the current state of the specified zone
+ * Arguments: a_zlst - handle to zoneList_t object describing all zones
+ * a_zoneIndex - index into a_zlst of the zone to return the
+ * a_newState - the state to put the specified zone in
+ * Returns: boolean_t
+ * == B_TRUE - the zone is in the new state
+ * == B_FALSE - unable to transition the zone to the
+ * specified state
+ * NOTE: This changes the "current kernel" state of the specified
+ * zone. For example, to boot the zone, change the state
+ * to "ZONE_STATE_RUNNING". To halt the zone, change the
+ * state to "ZONE_STATE_INSTALLED".
+ */
+
+boolean_t
+z_zlist_change_zone_state(zoneList_t a_zlst, int a_zoneIndex,
+ zone_state_t a_newState)
+{
+ int i;
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_CHG_Z_STATE_ENTRY, a_zoneIndex, a_newState);
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ return (B_FALSE);
+ }
+
+ /* find the specified zone in the list */
+
+ for (i = 0; (i != a_zoneIndex) &&
+ (a_zlst[i]._zlName != (char *)NULL); i++)
+ ;
+
+ /* return error if the specified zone does not exist */
+
+ if (a_zlst[i]._zlName == (char *)NULL) {
+ return (B_FALSE);
+ }
+
+ /* return success if the zone is already in this state */
+
+ if (a_zlst[i]._zlCurrKernelStatus == a_newState) {
+ return (B_TRUE);
+ }
+
+ /* take action on new state to set zone to */
+
+ _z_echoDebug(DBG_ZONES_CHG_Z_STATE, a_zlst[i]._zlName,
+ a_zlst[i]._zlCurrKernelStatus, a_newState);
+
+ switch (a_newState) {
+ case ZONE_STATE_RUNNING:
+ case ZONE_STATE_MOUNTED:
+ /* these states mean "boot the zone" */
+ return (_z_make_zone_running(&a_zlst[i]));
+
+ case ZONE_STATE_DOWN:
+ case ZONE_STATE_INSTALLED:
+ /* these states mean "halt the zone" */
+ return (_z_make_zone_down(&a_zlst[i]));
+
+ case ZONE_STATE_READY:
+ return (_z_make_zone_ready(&a_zlst[i]));
+
+ case ZONE_STATE_CONFIGURED:
+ case ZONE_STATE_INCOMPLETE:
+ case ZONE_STATE_SHUTTING_DOWN:
+ default:
+ /* do not know how to change zone to this state */
+ return (B_FALSE);
+ }
+}
+
+/*
+ * Name: z_is_zone_branded
+ * Description: Determine whether zone has a non-native brand
+ * Arguments: a_zoneName - name of the zone to check for branding
+ * Returns: boolean_t
+ * == B_TRUE - zone has a non-native brand
+ * == B_FALSE - zone is native
+ */
+boolean_t
+z_is_zone_branded(char *zoneName)
+{
+ char brandname[MAXNAMELEN];
+ int err;
+
+ /* if zones are not implemented, return FALSE */
+ if (!z_zones_are_implemented()) {
+ return (B_FALSE);
+ }
+
+ /* if brands are not implemented, return FALSE */
+ if (!z_brands_are_implemented()) {
+ return (B_FALSE);
+ }
+
+ err = zone_get_brand(zoneName, brandname, sizeof (brandname));
+ if (err != Z_OK) {
+ _z_program_error(ERR_BRAND_GETBRAND, zonecfg_strerror(err));
+ return (B_FALSE);
+ }
+
+ /*
+ * Both "native" and "cluster" are native brands
+ * that use the standard facilities in the areas
+ * of packaging/installation/patching/update.
+ */
+ if (streq(brandname, NATIVE_BRAND_NAME) ||
+ streq(brandname, CLUSTER_BRAND_NAME)) {
+ return (B_FALSE);
+ } else {
+ return (B_TRUE);
+ }
+}
+
+/*
+ * Name: z_is_zone_brand_in_list
+ * Description: Determine whether zone's brand has a match in the list
+ * brands passed in.
+ * Arguments: zoneName - name of the zone to check for branding
+ * list - list of brands to check the zone against
+ * Returns: boolean_t
+ * == B_TRUE - zone has a matching brand
+ * == B_FALSE - zone brand is not in list
+ */
+boolean_t
+z_is_zone_brand_in_list(char *zoneName, zoneBrandList_t *list)
+{
+ char brandname[MAXNAMELEN];
+ int err;
+ zoneBrandList_t *sp;
+
+ if (zoneName == NULL || list == NULL)
+ return (B_FALSE);
+
+ /* if zones are not implemented, return FALSE */
+ if (!z_zones_are_implemented()) {
+ return (B_FALSE);
+ }
+
+ /* if brands are not implemented, return FALSE */
+ if (!z_brands_are_implemented()) {
+ return (B_FALSE);
+ }
+
+ err = zone_get_brand(zoneName, brandname, sizeof (brandname));
+ if (err != Z_OK) {
+ _z_program_error(ERR_BRAND_GETBRAND, zonecfg_strerror(err));
+ return (B_FALSE);
+ }
+
+ for (sp = list; sp != NULL; sp = sp->next) {
+ if (sp->string_ptr != NULL &&
+ strcmp(sp->string_ptr, brandname) == 0) {
+ return (B_TRUE);
+ }
+ }
+
+ return (B_FALSE);
+}
+
+/*
+ * Name: z_zlist_get_current_state
+ * Description: Determine the current kernel state of the specified zone
+ * Arguments: a_zlst - handle to zoneList_t object describing all zones
+ * a_zoneIndex - index into a_zlst of the zone to return
+ * Returns: zone_state_t
+ * The current state of the specified zone is returned
+ */
+
+zone_state_t
+z_zlist_get_current_state(zoneList_t a_zlst, int a_zoneIndex)
+{
+ int i;
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ return (ZONE_STATE_INCOMPLETE);
+ }
+
+ /* find the specified zone in the list */
+
+ for (i = 0; (i != a_zoneIndex) &&
+ (a_zlst[i]._zlName != (char *)NULL); i++)
+ ;
+
+ /* return error if the specified zone does not exist */
+
+ if (a_zlst[i]._zlName == (char *)NULL) {
+ return (ZONE_STATE_INCOMPLETE);
+ }
+
+ /* return selected zone's current kernel state */
+
+ _z_echoDebug(DBG_ZONES_GET_ZONE_STATE,
+ a_zlst[i]._zlName ? a_zlst[i]._zlName : "",
+ a_zlst[i]._zlCurrKernelStatus);
+
+ return (a_zlst[i]._zlCurrKernelStatus);
+}
+
+/*
+ * Name: z_zlist_get_inherited_pkg_dirs
+ * Description: Determine directories inherited by specified zone
+ * Arguments: a_zlst - handle to zoneList_t object describing all zones
+ * a_zoneIndex - index into a_zlst of the zone to return the
+ * inherited directories list
+ * Returns: char **
+ * == NULL - zone does not inherit any directories
+ * - zone index is invalid
+ * != NULL - array of inherited directories
+ * NOTE: Any directory list returned is located in static storage that
+ * must NEVER be free()ed by the caller.
+ */
+
+extern char **
+z_zlist_get_inherited_pkg_dirs(zoneList_t a_zlst, int a_zoneIndex)
+{
+ int i;
+
+ /* if zones are not implemented, return empty list */
+
+ if (z_zones_are_implemented() == B_FALSE) {
+ return (NULL);
+ }
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ return (NULL);
+ }
+
+ /* find the specified zone in the list */
+
+ for (i = 0; (i != a_zoneIndex) &&
+ (a_zlst[i]._zlName != (char *)NULL); i++)
+ ;
+
+ /* return error if the specified zone does not exist */
+
+ if (a_zlst[i]._zlName == (char *)NULL) {
+ return (NULL);
+ }
+
+ /* return selected zone's inherited directories */
+
+ return (a_zlst[i]._zlInheritedDirs);
+}
+
+/*
+ * Name: z_zlist_get_original_state
+ * Description: Return the original kernal state of the specified zone
+ * Arguments: a_zlst - handle to zoneList_t object describing all zones
+ * a_zoneIndex - index into a_zlst of the zone to return the
+ * Returns: zone_state_t
+ * The original state of the specified zone is returned.
+ * This is the state of the zone when the zoneList_t
+ * object was first generated.
+ */
+
+zone_state_t
+z_zlist_get_original_state(zoneList_t a_zlst, int a_zoneIndex)
+{
+ int i;
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ return (ZONE_STATE_INCOMPLETE);
+ }
+
+ /* find the specified zone in the list */
+
+ for (i = 0; (i != a_zoneIndex) &&
+ (a_zlst[i]._zlName != (char *)NULL); i++)
+ ;
+
+ /* return error if the specified zone does not exist */
+
+ if (a_zlst[i]._zlName == (char *)NULL) {
+ return (ZONE_STATE_INCOMPLETE);
+ }
+
+ /* return selected zone's original kernel state */
+
+ return (a_zlst[i]._zlOrigKernelStatus);
+}
+
+/*
+ * Name: z_zlist_get_scratch
+ * Description: Determine name of scratch zone
+ * Arguments: a_zlst - handle to zoneList_t object describing all zones
+ * a_zoneIndex - index into a_zlst of the zone to use
+ * Return: char *
+ * == NULL - zone name could not be determined
+ * != NULL - pointer to string representing scratch zone
+ * NOTE: Any name returned is placed in static storage that must
+ * NEVER be free()ed by the caller.
+ */
+
+char *
+z_zlist_get_scratch(zoneList_t a_zlst, int a_zoneIndex)
+{
+ int i;
+
+ /* ignore empty list */
+
+ if (a_zlst == NULL)
+ return (NULL);
+
+ /* find the specified zone in the list */
+
+ for (i = 0; i != a_zoneIndex; i++) {
+ if (a_zlst[i]._zlName == NULL)
+ return (NULL);
+ }
+
+ /* return selected zone's scratch name */
+
+ return (a_zlst[i]._zlScratchName == NULL ? a_zlst[i]._zlName :
+ a_zlst[i]._zlScratchName);
+}
+
+/*
+ * Name: z_zlist_get_zonename
+ * Description: Determine name of specified zone
+ * Arguments: a_zlst - handle to zoneList_t object describing all zones
+ * a_zoneIndex - index into a_zlst of the zone to return the
+ * Return: char *
+ * == NULL - zone name could not be determined
+ * != NULL - pointer to string representing zone name
+ * NOTE: Any zoneList_t returned is placed in static storage that must
+ * NEVER be free()ed by the caller.
+ */
+
+char *
+z_zlist_get_zonename(zoneList_t a_zlst, int a_zoneIndex)
+{
+ int i;
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ return ((char *)NULL);
+ }
+
+ /* find the specified zone in the list */
+
+ for (i = 0; (i != a_zoneIndex) &&
+ (a_zlst[i]._zlName != (char *)NULL); i++)
+ ;
+
+ /* return error if the specified zone does not exist */
+
+ if (a_zlst[i]._zlName == (char *)NULL) {
+ return (NULL);
+ }
+
+ /* return selected zone's name */
+
+ return (a_zlst[i]._zlName);
+}
+
+/*
+ * Name: z_zlist_get_zonepath
+ * Description: Determine zonepath of specified zone
+ * Arguments: a_zlst - handle to zoneList_t object describing all zones
+ * a_zoneIndex - index into a_zlst of the zone to return
+ * Return: char *
+ * == NULL - zonepath could not be determined
+ * != NULL - pointer to string representing zonepath
+ * NOTE: Any zoneList_t returned is placed in static storage that must
+ * NEVER be free()ed by the caller.
+ */
+
+char *
+z_zlist_get_zonepath(zoneList_t a_zlst, int a_zoneIndex)
+{
+ int i;
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ return ((char *)NULL);
+ }
+
+ /* find the specified zone in the list */
+
+ for (i = 0; (i != a_zoneIndex) &&
+ (a_zlst[i]._zlName != (char *)NULL); i++)
+ ;
+
+ /* return error if the specified zone does not exist */
+
+ if (a_zlst[i]._zlName == (char *)NULL) {
+ return (NULL);
+ }
+
+ /* return selected zone's zonepath */
+
+ return (a_zlst[i]._zlPath);
+}
+
+boolean_t
+z_zlist_is_zone_runnable(zoneList_t a_zlst, int a_zoneIndex)
+{
+ int i;
+
+ /* if zones are not implemented, return error */
+
+ if (z_zones_are_implemented() == B_FALSE) {
+ return (B_FALSE);
+ }
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ return (B_FALSE);
+ }
+
+ /* find the specified zone in the list */
+
+ for (i = 0; (i != a_zoneIndex) &&
+ (a_zlst[i]._zlName != (char *)NULL); i++)
+ ;
+
+ /* return error if the specified zone does not exist */
+
+ if (a_zlst[i]._zlName == (char *)NULL) {
+ return (B_FALSE);
+ }
+
+ /* choose based on current state */
+
+ switch (a_zlst[i]._zlCurrKernelStatus) {
+ case ZONE_STATE_RUNNING:
+ case ZONE_STATE_MOUNTED:
+ /* already running */
+ return (B_TRUE);
+
+ case ZONE_STATE_INSTALLED:
+ case ZONE_STATE_DOWN:
+ case ZONE_STATE_READY:
+ case ZONE_STATE_SHUTTING_DOWN:
+ /* return false if the zone cannot be booted */
+
+ if (a_zlst[i]._zlStatus & ZST_NOT_BOOTABLE) {
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+
+ case ZONE_STATE_CONFIGURED:
+ case ZONE_STATE_INCOMPLETE:
+ default:
+ /* cannot transition (boot) these states */
+ return (B_FALSE);
+ }
+}
+
+/*
+ * Name: z_zlist_restore_zone_state
+ * Description: Return the zone to the state it was originally in
+ * Arguments: a_zlst - handle to zoneList_t object describing all zones
+ * a_zoneIndex - index into a_zlst of the zone to return the
+ * Returns: boolean_t
+ * == B_TRUE - the zone's state has been restored
+ * == B_FALSE - unable to transition the zone to its
+ * original state
+ */
+
+boolean_t
+z_zlist_restore_zone_state(zoneList_t a_zlst, int a_zoneIndex)
+{
+ int i;
+
+ /* ignore empty list */
+
+ if (a_zlst == (zoneList_t)NULL) {
+ return (B_FALSE);
+ }
+
+ /* find the specified zone in the list */
+
+ for (i = 0; (i != a_zoneIndex) &&
+ (a_zlst[i]._zlName != (char *)NULL); i++)
+ ;
+
+ /* return error if the specified zone does not exist */
+
+ if (a_zlst[i]._zlName == (char *)NULL) {
+ return (B_FALSE);
+ }
+
+ /* transition the zone back to its original state */
+
+ return (z_zlist_change_zone_state(a_zlst,
+ a_zoneIndex, a_zlst[i]._zlOrigKernelStatus));
+}
+
+/*
+ * Name: z_zone_exec
+ * Description: Execute a Unix command in a specified zone and return results
+ * Arguments: a_zoneName - pointer to string representing the name of the zone
+ * to execute the specified command in
+ * a_path - pointer to string representing the full path *in the
+ * non-global zone named by a_zoneName* of the Unix command
+ * to be executed
+ * a_argv[] - Pointer to array of character strings representing
+ * the arguments to be passed to the Unix command. The list
+ * must be termianted with an element that is (char *)NULL
+ * NOTE: a_argv[0] is the "command name" passed to the command
+ * a_stdoutPath - Pointer to string representing the path to a file
+ * into which all output to "stdout" from the Unix command
+ * is placed.
+ * == (char *)NULL - leave stdout open and pass through
+ * == "/dev/null" - discard stdout output
+ * a_strerrPath - Pointer to string representing the path to a file
+ * into which all output to "stderr" from the Unix command
+ * is placed.
+ * == (char *)NULL - leave stderr open and pass through
+ * == "/dev/null" - discard stderr output
+ * a_fds - Pointer to array of integers representing file
+ * descriptors to remain open during the call - all
+ * file descriptors above STDERR_FILENO not in this
+ * list will be closed.
+ * Returns: int
+ * The return (exit) code from the specified Unix command
+ * Special return codes:
+ * -1 : failure to exec process
+ * -2 : could not create contract for greenline
+ * -3 : fork() failed
+ * -4 : could not open stdout capture file
+ * -5 : error from 'waitpid' other than EINTR
+ * -6 : zones are not supported
+ * NOTE: All file descriptores other than 0, 1 and 2 are closed except
+ * for those file descriptors listed in the a_fds array.
+ */
+
+int
+z_zone_exec(const char *a_zoneName, const char *a_path, char *a_argv[],
+ char *a_stdoutPath, char *a_stderrPath, int *a_fds)
+{
+ int final_status;
+ int lerrno;
+ int status;
+ int tmpl_fd;
+ pid_t child_pid;
+ pid_t result_pid;
+ struct sigaction nact;
+ struct sigaction oact;
+ void (*funcSighup)();
+ void (*funcSigint)();
+
+ /* if zones are not implemented, return TRUE */
+
+ if (z_zones_are_implemented() == B_FALSE) {
+ return (-6); /* -6 : zones are not supported */
+ }
+
+ if ((tmpl_fd = _zexec_init_template()) == -1) {
+ _z_program_error(ERR_CANNOT_CREATE_CONTRACT, strerror(errno));
+ return (-2); /* -2 : could not create greenline contract */
+ }
+
+ /*
+ * hold SIGINT/SIGHUP signals and reset signal received counter;
+ * after the fork1() the parent and child need to setup their respective
+ * interrupt handling and release the hold on the signals
+ */
+
+ (void) sighold(SIGINT);
+ (void) sighold(SIGHUP);
+
+ _z_global_data._z_SigReceived = 0; /* no signals received */
+
+ /*
+ * fork off a new process to execute command in;
+ * fork1() is used instead of vfork() so the child process can
+ * perform operations that would modify the parent process if
+ * vfork() were used
+ */
+
+ child_pid = fork1();
+
+ if (child_pid < 0) {
+ /*
+ * *************************************************************
+ * fork failed!
+ * *************************************************************
+ */
+
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+ _z_program_error(ERR_FORK, strerror(errno));
+
+ /* release hold on signals */
+
+ (void) sigrelse(SIGHUP);
+ (void) sigrelse(SIGINT);
+
+ return (-3); /* -3 : fork() failed */
+ }
+
+ if (child_pid == 0) {
+ int i;
+
+ /*
+ * *************************************************************
+ * This is the forked (child) process
+ * *************************************************************
+ */
+
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+
+ /* reset any signals to default */
+
+ for (i = 0; i < NSIG; i++) {
+ (void) sigset(i, SIG_DFL);
+ }
+
+ /*
+ * close all file descriptors not in the a_fds list
+ */
+
+ (void) fdwalk(&_z_close_file_descriptors, (void *)a_fds);
+
+ /*
+ * if a file for stdout is present, open the file and use the
+ * file to capture stdout from the _zexec process
+ */
+
+ if (a_stdoutPath != (char *)NULL) {
+ int stdoutfd;
+
+ stdoutfd = open(a_stdoutPath,
+ O_WRONLY|O_CREAT|O_TRUNC, 0600);
+ if (stdoutfd < 0) {
+ _z_program_error(ERR_CAPTURE_FILE, a_stdoutPath,
+ strerror(errno));
+ return (-4);
+ }
+
+ (void) dup2(stdoutfd, STDOUT_FILENO);
+ (void) close(stdoutfd);
+ }
+
+ /*
+ * if a file for stderr is present, open the file and use the
+ * file to capture stderr from the _zexec process
+ */
+
+ if (a_stderrPath != (char *)NULL) {
+ int stderrfd;
+
+ stderrfd = open(a_stderrPath,
+ O_WRONLY|O_CREAT|O_TRUNC, 0600);
+ if (stderrfd < 0) {
+ _z_program_error(ERR_CAPTURE_FILE, a_stderrPath,
+ strerror(errno));
+ return (-4);
+ }
+
+ (void) dup2(stderrfd, STDERR_FILENO);
+ (void) close(stderrfd);
+ }
+
+ /* release all held signals */
+
+ (void) sigrelse(SIGHUP);
+ (void) sigrelse(SIGINT);
+
+ /* execute command in the specified non-global zone */
+
+ _exit(_zexec(a_zoneName, a_path, a_argv));
+ }
+
+ /*
+ * *********************************************************************
+ * This is the forking (parent) process
+ * *********************************************************************
+ */
+
+ /* register child process i.d. so signal handlers can pass signal on */
+
+ _z_global_data._z_ChildProcessId = child_pid;
+
+ /*
+ * setup signal handlers for SIGINT and SIGHUP and release hold
+ */
+
+ /* hook SIGINT to _z_sig_trap() */
+
+ nact.sa_handler = _z_sig_trap;
+ nact.sa_flags = SA_RESTART;
+ (void) sigemptyset(&nact.sa_mask);
+
+ if (sigaction(SIGINT, &nact, &oact) < 0) {
+ funcSigint = SIG_DFL;
+ } else {
+ funcSigint = oact.sa_handler;
+ }
+
+ /* hook SIGHUP to _z_sig_trap() */
+
+ nact.sa_handler = _z_sig_trap;
+ nact.sa_flags = SA_RESTART;
+ (void) sigemptyset(&nact.sa_mask);
+
+ if (sigaction(SIGHUP, &nact, &oact) < 0) {
+ funcSighup = SIG_DFL;
+ } else {
+ funcSighup = oact.sa_handler;
+ }
+
+ /* release hold on signals */
+
+ (void) sigrelse(SIGHUP);
+ (void) sigrelse(SIGINT);
+
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+
+ /*
+ * wait for the process to exit, reap child exit status
+ */
+
+ for (;;) {
+ result_pid = waitpid(child_pid, &status, 0L);
+ lerrno = (result_pid == -1 ? errno : 0);
+
+ /* break loop if child process status reaped */
+
+ if (result_pid != -1) {
+ break;
+ }
+
+ /* break loop if not interrupted out of waitpid */
+
+ if (errno != EINTR) {
+ break;
+ }
+ }
+
+ /* reset child process i.d. so signal handlers do not pass signals on */
+
+ _z_global_data._z_ChildProcessId = -1;
+
+ /*
+ * If the child process terminated due to a call to exit(), then
+ * set results equal to the 8-bit exit status of the child process;
+ * otherwise, set the exit status to "-1" indicating that the child
+ * exited via a signal.
+ */
+
+ if (WIFEXITED(status)) {
+ final_status = WEXITSTATUS(status);
+ if ((_z_global_data._z_SigReceived != 0) &&
+ (final_status == 0)) {
+ final_status = 1;
+ }
+ } else {
+ final_status = -1; /* -1 : failure to exec process */
+ }
+
+ /* determine proper exit code */
+
+ if (result_pid == -1) {
+ final_status = -5; /* -5 : error from waitpid not EINTR */
+ } else if (_z_global_data._z_SigReceived != 0) {
+ final_status = -7; /* -7 : interrupt received */
+ }
+
+ /*
+ * reset signal handlers
+ */
+
+ /* reset SIGINT */
+
+ nact.sa_handler = funcSigint;
+ nact.sa_flags = SA_RESTART;
+ (void) sigemptyset(&nact.sa_mask);
+
+ (void) sigaction(SIGINT, &nact, (struct sigaction *)NULL);
+
+ /* reset SIGHUP */
+
+ nact.sa_handler = funcSighup;
+ nact.sa_flags = SA_RESTART;
+ (void) sigemptyset(&nact.sa_mask);
+
+ (void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL);
+
+ /*
+ * if signal received during command execution, interrupt
+ * this process now.
+ */
+
+ if (_z_global_data._z_SigReceived != 0) {
+ (void) kill(getpid(), SIGINT);
+ }
+
+ /* set errno and return */
+
+ errno = lerrno;
+
+ return (final_status);
+}
+
+/*
+ * Name: z_zones_are_implemented
+ * Description: Determine if any zone operations can be performed
+ * Arguments: void
+ * Returns: boolean_t
+ * == B_TRUE - zone operations are available
+ * == B_FALSE - no zone operations can be done
+ */
+
+boolean_t
+z_zones_are_implemented(void)
+{
+ static boolean_t _zonesImplementedDetermined = B_FALSE;
+ static boolean_t _zonesAreImplemented = B_FALSE;
+
+ /* if availability has not been determined, cache it now */
+
+ if (!_zonesImplementedDetermined) {
+ _zonesImplementedDetermined = B_TRUE;
+ _zonesAreImplemented = _z_zones_are_implemented();
+ if (!_zonesAreImplemented) {
+ _z_echoDebug(DBG_ZONES_NOT_IMPLEMENTED);
+ } else {
+ _z_echoDebug(DBG_ZONES_ARE_IMPLEMENTED);
+ }
+ }
+
+ return (_zonesAreImplemented);
+}
diff --git a/usr/src/lib/libinstzones/common/zones_args.c b/usr/src/lib/libinstzones/common/zones_args.c
new file mode 100644
index 0000000000..a400cfef9a
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones_args.c
@@ -0,0 +1,307 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+/*
+ * Module: zones_args.c
+ * Group: libinstzones
+ * Description: Private functions used by zones library functions to manipulate
+ * argument lists
+ *
+ * Public Methods:
+ *
+ * _z_add_arg - add new argument to argument array for use in exec() calls
+ * _z_free_args - free all storage contained in an argument array previously
+ * _z_get_argc - return (int) argc count from argument array
+ * _z_get_argv - return (char **)argv pointer from argument array
+ * _z_new_args - create a new argument array for use in exec() calls
+ */
+
+/*
+ * System includes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <strings.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.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
+ */
+
+/*
+ * Global internal (private) declarations
+ */
+
+/*
+ * *****************************************************************************
+ * global external (public) functions
+ * *****************************************************************************
+ */
+
+/*
+ * Name: _z_add_arg
+ * Description: add new argument to argument array for use in exec() calls
+ * Arguments: a_args - [RO, *RW] - (argArray_t *)
+ * Pointer to argument array (previously allocated via
+ * a call to _z_new_args) to add the argument to
+ * a_format - [RO, *RO] - (char *)
+ * Pointer to "printf(3C)" style format argument
+ * ... - [RO, *RO] - (varies)
+ * Arguments as appropriate for format argument specified
+ * Returns: boolean_t
+ * B_TRUE - success
+ * B_FALSE - failure
+ * Examples:
+ * - to add an argument that specifies a file descriptor:
+ * int fd;
+ * _z_add_arg(aa, "/proc/self/fd/%d", fd);
+ * - to add a flag or other known text:
+ * _z_add_arg(aa, "-s")
+ * - to add random text:
+ * char *random_text;
+ * _z_add_arg(aa, "%s", random_text);
+ */
+
+/*PRINTFLIKE2*/
+boolean_t
+_z_add_arg(argArray_t *a_args, char *a_format, ...)
+{
+ char *rstr = NULL;
+ char bfr[MAX_CANON];
+ size_t vres = 0;
+ va_list ap;
+
+ /* entry assertions */
+
+ assert(a_args != NULL);
+ assert(a_format != NULL);
+ assert(*a_format != '\0');
+
+ /*
+ * double argument array if array is full
+ */
+
+ if (a_args->_aaNumArgs >= a_args->_aaMaxArgs) {
+ int newMax;
+ char **newArgs;
+
+ newMax = a_args->_aaMaxArgs * 2;
+ newArgs = (char **)_z_realloc(a_args->_aaArgs,
+ (newMax+1) * sizeof (char *));
+ a_args->_aaArgs = newArgs;
+ a_args->_aaMaxArgs = newMax;
+ }
+
+ /*
+ * determine size of argument to add to list
+ */
+
+ va_start(ap, a_format);
+ vres = vsnprintf(bfr, sizeof (bfr), a_format, ap);
+ va_end(ap);
+
+ /*
+ * use the expanded argument if it will fit in the built in buffer,
+ * otherwise, allocate space to hold the argument
+ */
+
+ if (vres < sizeof (bfr)) {
+ /* duplicate text already generated in buffer */
+ rstr = _z_strdup(bfr);
+ } else {
+ /* allocate new space for argument to add */
+
+ rstr = (char *)_z_malloc(vres+2);
+
+ /* generate argument to add */
+
+ va_start(ap, a_format);
+ vres = vsnprintf(rstr, vres+1, a_format, ap);
+ va_end(ap);
+ }
+
+ /* add argument to the end of the argument array */
+
+ a_args->_aaArgs[a_args->_aaNumArgs++] = rstr;
+ a_args->_aaArgs[a_args->_aaNumArgs] = NULL;
+
+ /* successful - return */
+
+ return (B_TRUE);
+}
+
+/*
+ * Name: _z_free_args
+ * Description: free all storage contained in an argument array previously
+ * allocated by a call to _z_new_args
+ * Arguments: a_args - [RO, *RW] - (argArray_t *)
+ * Pointer to argument array (previously allocated via
+ * a call to _z_new_args) to free
+ * Returns: void
+ * NOTE: preserves errno (usually called right after e_execCmd*())
+ */
+
+void
+_z_free_args(argArray_t *a_args)
+{
+ int i;
+ int lerrno = errno;
+
+ /* entry assertions */
+
+ assert(a_args != NULL);
+ assert(a_args->_aaArgs != NULL);
+
+ /* free all arguments in the argument array */
+
+ for (i = (a_args->_aaNumArgs-1); i >= 0; i--) {
+ assert(a_args->_aaArgs[i] != NULL);
+ (void) free(a_args->_aaArgs[i]);
+ }
+
+ /* free argument array */
+
+ (void) free(a_args->_aaArgs);
+
+ /* free argument array structure */
+
+ (void) free(a_args);
+
+ /* restore errno */
+
+ errno = lerrno;
+}
+
+/*
+ * Name: _z_get_argc
+ * Description: return (int) argc count from argument array
+ * Arguments: a_args - [RO, *RW] - (argArray_t *)
+ * Pointer to argument array (previously allocated via
+ * a call to _z_new_args) to return argc count for
+ * Returns: int
+ * Count of the number of arguments in the argument array
+ * suitable for use in an exec*() call
+ */
+
+int
+_z_get_argc(argArray_t *a_args)
+{
+ return (a_args->_aaNumArgs);
+}
+
+/*
+ * Name: _z_get_argv
+ * Description: return (char **)argv pointer from argument array
+ * Arguments: a_args - [RO, *RW] - (argArray_t *)
+ * Pointer to argument array (previously allocated via
+ * a call to _z_new_args) to return argv pointer for
+ * Returns: char **
+ * Pointer to (char **)argv pointer suitable for use
+ * in an exec*() call
+ * NOTE: the actual character array is always terminated with a NULL
+ */
+
+char **
+_z_get_argv(argArray_t *a_args)
+{
+ return (a_args->_aaArgs);
+}
+
+/*
+ * Name: _z_new_args
+ * Description: create a new argument array for use in exec() calls
+ * Arguments: initialCount - [RO, *RO] - (int)
+ * Initial number of elements to populate the
+ * argument array with - use best guess
+ * Returns: argArray_t *
+ * Pointer to argument array that can be used in other
+ * functions that accept it as an argument
+ * == (argArray_t *)NULL - error
+ * NOTE: you must call _z_free_args() when the returned argument array is
+ * no longer needed so that all storage used can be freed up.
+ */
+
+argArray_t *
+_z_new_args(int initialCount)
+{
+ argArray_t *aa;
+
+ /* entry assertions */
+
+ assert(initialCount >= 0);
+
+ /* if no guess on size, then assume 1 */
+
+ if (initialCount == 0) {
+ initialCount = 1;
+ }
+
+ /* allocate new argument array structure */
+
+ aa = (argArray_t *)_z_calloc(sizeof (argArray_t));
+
+ /* allocate initial argument array */
+
+ aa->_aaArgs = (char **)_z_calloc((initialCount+1) * sizeof (char *));
+
+ /* initialize argument indexes */
+
+ aa->_aaNumArgs = 0;
+ aa->_aaMaxArgs = initialCount;
+
+ /* successful - return pointer to argument array created */
+
+ return (aa);
+}
diff --git a/usr/src/lib/libinstzones/common/zones_exec.c b/usr/src/lib/libinstzones/common/zones_exec.c
new file mode 100644
index 0000000000..808437285a
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones_exec.c
@@ -0,0 +1,1120 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+/*
+ * Module: zones_exec.c
+ * Group: libinstzones
+ * Description: Provide "zones" execution interface for install
+ * consolidation code
+ *
+ * Public Methods:
+ *
+ * z_ExecCmdArray - Execute a Unix command and return results and status
+ * _zexec - run a command with arguments on a specified zone
+ * _zexec_init_template - used by _zexec to establish contracts
+ * _z_zone_exec - Execute a Unix command in a specified zone and return results
+ * z_ExecCmdList - Execute a Unix command and return results and status
+ */
+
+/*
+ * System includes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <strings.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+#include <signal.h>
+#include <wait.h>
+#include <stropts.h>
+#include <libintl.h>
+#include <locale.h>
+#include <libcontract.h>
+#include <sys/contract/process.h>
+#include <sys/ctfs.h>
+#include <assert.h>
+
+/*
+ * local includes
+ */
+
+#include "instzones_lib.h"
+#include "zones_strings.h"
+
+/*
+ * Private structures
+ */
+
+/*
+ * Library Function Prototypes
+ */
+
+/*
+ * Local Function Prototypes
+ */
+
+/*
+ * global internal (private) declarations
+ */
+
+/*
+ * *****************************************************************************
+ * global external (public) functions
+ * *****************************************************************************
+ */
+
+/*
+ * Name: z_ExecCmdArray
+ * Synopsis: Execute Unix command and return results
+ * Description: Execute a Unix command and return results and status
+ * Arguments:
+ * r_status - [RO, *RW] - (int *)
+ * Return (exit) status from Unix command:
+ * == -1 : child terminated with a signal
+ * != -1 : lower 8-bit value child passed to exit()
+ * r_results - [RO, *RW] - (char **)
+ * Any output generated by the Unix command to stdout
+ * and to stderr
+ * == (char *)NULL if no output generated
+ * a_inputFile - [RO, *RO] - (char *)
+ * Pointer to character string representing file to be
+ * used as "standard input" for the command.
+ * == (char *)NULL to use "/dev/null" as standard input
+ * a_cmd - [RO, *RO] - (char *)
+ * Pointer to character string representing the full path
+ * of the Unix command to execute
+ * char **a_args - [RO, *RO] - (char **)
+ * List of character strings representing the arguments
+ * to be passed to the Unix command. The list must be
+ * terminated with an element that is (char *)NULL
+ * Returns: int
+ * == 0 - Command executed
+ * Look at r_status for results of Unix command
+ * != 0 - problems executing command
+ * r_status and r_results have no meaning;
+ * r_status will be -1
+ * r_results will be NULL
+ * NOTE: Any results returned is placed in new storage for the
+ * calling method. The caller must use 'free' to dispose
+ * of the storage once the results are no longer needed.
+ * NOTE: If 0 is returned, 'r_status' must be queried to
+ * determine the results of the Unix command.
+ * NOTE: The system "errno" value from immediately after waitpid() call
+ * is preserved for the calling method to use to determine
+ * the system reason why the operation failed.
+ */
+
+int
+z_ExecCmdArray(int *r_status, char **r_results,
+ char *a_inputFile, char *a_cmd, char **a_args)
+{
+ char *buffer;
+ int bufferIndex;
+ int bufferSize;
+ int ipipe[2] = {0, 0};
+ int lerrno;
+ int status;
+ int stdinfile = -1;
+ pid_t pid;
+ pid_t resultPid;
+
+ /* entry assertions */
+
+ assert(r_status != NULL);
+ assert(a_cmd != NULL);
+ assert(*a_cmd != '\0');
+ assert(a_args != NULL);
+
+ /* reset return results buffer pointer */
+
+ if (r_results != (char **)NULL) {
+ *r_results = (char *)NULL;
+ }
+
+ *r_status = -1;
+
+ /*
+ * See if command exists
+ */
+
+ if (access(a_cmd, F_OK|X_OK) != 0) {
+ return (-1);
+ }
+
+ /*
+ * See if input file exists
+ */
+
+ if (a_inputFile != (char *)NULL) {
+ stdinfile = open(a_inputFile, O_RDONLY);
+ } else {
+ stdinfile = open("/dev/null", O_RDONLY); /* stdin = /dev/null */
+ }
+
+ if (stdinfile < 0) {
+ return (-1);
+ }
+
+ /*
+ * Create a pipe to be used to capture the command output
+ */
+
+ if (pipe(ipipe) != 0) {
+ (void) close(stdinfile);
+ return (-1);
+ }
+
+
+ bufferSize = PIPE_BUFFER_INCREMENT;
+ bufferIndex = 0;
+ buffer = calloc(1, bufferSize);
+ if (buffer == (char *)NULL) {
+ (void) close(stdinfile);
+ return (-1);
+ }
+
+ /* flush standard i/o before creating new process */
+
+ (void) fflush(stderr);
+ (void) fflush(stdout);
+
+ /*
+ * create new process to execute command in;
+ * vfork() is being used to avoid duplicating the parents
+ * memory space - this means that the child process may
+ * not modify any of the parents memory including the
+ * standard i/o descriptors - all the child can do is
+ * adjust interrupts and open files as a prelude to a
+ * call to exec().
+ */
+
+ pid = vfork();
+
+ if (pid == 0) {
+ /*
+ * This is the forked (child) process ======================
+ */
+
+ int i;
+
+ /* reset any signals to default */
+
+ for (i = 0; i < NSIG; i++) {
+ (void) sigset(i, SIG_DFL);
+ }
+
+ /* assign stdin, stdout, stderr as appropriate */
+
+ (void) dup2(stdinfile, STDIN_FILENO);
+ (void) close(ipipe[0]); /* close out pipe reader side */
+ (void) dup2(ipipe[1], STDOUT_FILENO);
+ (void) dup2(ipipe[1], STDERR_FILENO);
+
+ /* Close all open files except standard i/o */
+
+ closefrom(3);
+
+ /* execute target executable */
+
+ (void) execvp(a_cmd, a_args);
+ perror(a_cmd); /* Emit error msg - ends up in callers buffer */
+ _exit(0x00FE);
+ } else if (pid == -1) {
+ _z_program_error(ERR_FORK, strerror(errno));
+ *r_status = -1;
+ return (-1);
+ }
+
+ /*
+ * This is the forking (parent) process ====================
+ */
+
+ (void) close(stdinfile);
+ (void) close(ipipe[1]); /* Close write side of pipe */
+
+ /*
+ * Spin reading data from the child into the buffer - when the read eofs
+ * the child has exited
+ */
+
+ for (;;) {
+ ssize_t bytesRead;
+
+ /* read as much child data as there is available buffer space */
+
+ bytesRead = read(ipipe[0], buffer + bufferIndex,
+ bufferSize - bufferIndex);
+
+ /* break out of read loop if end-of-file encountered */
+
+ if (bytesRead == 0) {
+ break;
+ }
+
+ /* if error, continue if recoverable, else break out of loop */
+
+ if (bytesRead == -1) {
+ /* try again: EAGAIN - insufficient resources */
+
+ if (errno == EAGAIN) {
+ continue;
+ }
+
+ /* try again: EINTR - interrupted system call */
+
+ if (errno == EINTR) {
+ continue;
+ }
+
+ /* break out of loop - error not recoverable */
+ break;
+ }
+
+ /* at least 1 byte read: expand buffer if at end */
+
+ bufferIndex += bytesRead;
+ if (bufferIndex >= bufferSize) {
+ buffer = realloc(buffer,
+ bufferSize += PIPE_BUFFER_INCREMENT);
+ (void) memset(buffer + bufferIndex, 0,
+ bufferSize - bufferIndex);
+ }
+ }
+
+ (void) close(ipipe[0]); /* Close read side of pipe */
+
+ /* Get subprocess exit status */
+
+ for (;;) {
+ resultPid = waitpid(pid, &status, 0L);
+ lerrno = (resultPid == -1 ? errno : 0);
+
+ /* break loop if child process status reaped */
+
+ if (resultPid != -1) {
+ break;
+ }
+
+ /* break loop if not interrupted out of waitpid */
+
+ if (errno != EINTR) {
+ break;
+ }
+ }
+
+ /*
+ * If the child process terminated due to a call to exit(), then
+ * set results equal to the 8-bit exit status of the child process;
+ * otherwise, set the exit status to "-1" indicating that the child
+ * exited via a signal.
+ */
+
+ *r_status = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+
+ /* return appropriate output */
+
+ if (!*buffer) {
+ /* No contents in output buffer - discard */
+ free(buffer);
+ } else if (r_results == (char **)NULL) {
+ /* Not requested to return results - discard */
+ free(buffer);
+ } else {
+ /* have output and request to return: pass to calling method */
+ *r_results = buffer;
+ }
+
+ errno = lerrno;
+ return (resultPid == -1 ? -1 : 0);
+}
+
+/*
+ * Name: _zexec
+ * Description: run a command with arguments on a specified zone
+ * Arguments: a_zoneName - pointer to string representing the name of the zone
+ * to execute the specified command in
+ * a_path - pointer to string representing the full path *in the
+ * non-global zone named by a_zoneName* of the Unix command
+ * to be executed
+ * a_argv[] - Pointer to array of character strings representing
+ * the arguments to be passed to the Unix command. The list
+ * must be termianted with an element that is (char *)NULL
+ * NOTE: a_argv[0] is the "command name" passed to the command
+ * Returns: int
+ * This function must be treated like a call to exec()
+ * If the exec() is successful, the thread of control is
+ * NOT returned, and the process will exit when completed.
+ * If this function returns, it means the exec() could not
+ * be done, or another fatal error occurred.
+ */
+
+int
+_zexec(const char *a_zoneName, const char *a_path, char *a_argv[])
+{
+ zoneid_t zoneid;
+ zone_state_t st;
+ char **new_env = { NULL };
+ priv_set_t *privset;
+
+ /* entry assertions */
+
+ assert(a_zoneName != NULL);
+ assert(*a_zoneName != '\0');
+ assert(a_path != NULL);
+ assert(*a_path != '\0');
+
+ /* establish locale settings */
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ /* can only be invoked from within the global zone */
+
+ if (getzoneid() != GLOBAL_ZONEID) {
+ _z_program_error(ERR_ZEXEC_NOT_IN_GZ, a_zoneName);
+ return (-1);
+ }
+
+ if (strcmp(a_zoneName, GLOBAL_ZONENAME) == 0) {
+ _z_program_error(ERR_ZEXEC_GZUSED, a_zoneName);
+ return (-1);
+ }
+
+ /* get the state of the specified zone */
+
+ if (zone_get_state((char *)a_zoneName, &st) != Z_OK) {
+ _z_program_error(ERR_ZEXEC_BADZONE, a_zoneName);
+ return (-1);
+ }
+
+ if (st < ZONE_STATE_INSTALLED) {
+ _z_program_error(ERR_ZEXEC_BADSTATE, a_zoneName,
+ zone_state_str(st));
+ return (-1);
+ }
+
+ if (st != ZONE_STATE_RUNNING && st != ZONE_STATE_MOUNTED) {
+ _z_program_error(ERR_ZEXEC_NOTRUNNING, a_zoneName,
+ zone_state_str(st));
+ return (-1);
+ }
+
+ /*
+ * In both console and non-console cases, we require all privs.
+ * In the console case, because we may need to startup zoneadmd.
+ * In the non-console case in order to do zone_enter(2), zonept()
+ * and other tasks.
+ *
+ * Future work: this solution is temporary. Ultimately, we need to
+ * move to a flexible system which allows the global admin to
+ * designate that a particular user can zlogin (and probably zlogin
+ * -C) to a particular zone. This all-root business we have now is
+ * quite sketchy.
+ */
+
+ if ((privset = priv_allocset()) == NULL) {
+ _z_program_error(ERR_ZEXEC_PRIV_ALLOCSET, a_zoneName,
+ strerror(errno));
+ return (-1);
+ }
+
+ if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
+ _z_program_error(ERR_ZEXEC_GETPPRIV, a_zoneName,
+ strerror(errno));
+ priv_freeset(privset);
+ return (-1);
+ }
+
+ if (priv_isfullset(privset) == B_FALSE) {
+ _z_program_error(ERR_ZEXEC_PRIVS, a_zoneName);
+ priv_freeset(privset);
+ return (-1);
+ }
+ priv_freeset(privset);
+
+ if ((zoneid = getzoneidbyname(a_zoneName)) == -1) {
+ _z_program_error(ERR_ZEXEC_NOZONEID, a_zoneName,
+ strerror(errno));
+ return (-1);
+ }
+
+ if ((new_env = _zexec_prep_env()) == NULL) {
+ _z_program_error(ERR_ZEXEC_ASSEMBLE, a_zoneName);
+ return (-1);
+ }
+
+ /*
+ * In case any of stdin, stdout or stderr are streams,
+ * anchor them to prevent malicious I_POPs.
+ *
+ * Future work: use pipes to entirely eliminate FD leakage
+ * into the zone.
+ */
+
+ (void) ioctl(STDIN_FILENO, I_ANCHOR);
+ (void) ioctl(STDOUT_FILENO, I_ANCHOR);
+ (void) ioctl(STDERR_FILENO, I_ANCHOR);
+
+ if (zone_enter(zoneid) == -1) {
+ int lerrno = errno;
+
+ _z_program_error(ERR_ZEXEC_ZONEENTER, a_zoneName,
+ strerror(errno));
+
+ if (lerrno == EFAULT) {
+ _z_program_error(ERR_ZEXEC_EFAULT, a_zoneName);
+ }
+
+ free(new_env);
+
+ return (-1);
+ }
+
+ (void) execve(a_path, &a_argv[0], new_env);
+
+ _z_program_error(ERR_ZEXEC_EXECFAILURE, a_zoneName, strerror(errno));
+
+ return (-1);
+}
+
+/*
+ * Name: _zexec_init_template
+ * Description: used by _zexec to establish contracts
+ */
+
+int
+_zexec_init_template(void)
+{
+ int fd;
+ int err = 0;
+
+ fd = open64(CTFS_ROOT "/process/template", O_RDWR);
+ if (fd == -1) {
+ return (-1);
+ }
+
+ /*
+ * zlogin doesn't do anything with the contract.
+ * Deliver no events, don't inherit, and allow it to be orphaned.
+ */
+ err |= ct_tmpl_set_critical(fd, 0);
+ err |= ct_tmpl_set_informative(fd, 0);
+ err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
+ err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
+ if (err || ct_tmpl_activate(fd)) {
+ (void) close(fd);
+ return (-1);
+ }
+
+ return (fd);
+}
+
+/*
+ * Helper routine for _zexec_prep_env below.
+ */
+char *
+_zexec_add_env(char *name, char *value)
+{
+ size_t sz = strlen(name) + strlen(value) + 1;
+ char *str;
+
+ if ((str = malloc(sz)) == NULL)
+ return (NULL);
+
+ (void) snprintf(str, sz, "%s%s", name, value);
+ return (str);
+}
+
+/*
+ * Prepare envp array for exec'd process.
+ */
+char **
+_zexec_prep_env()
+{
+ int e = 0, size = 1;
+ char **new_env, *estr;
+ char *term = getenv("TERM");
+
+ size++; /* for $PATH */
+ if (term != NULL)
+ size++;
+
+ /*
+ * In failsafe mode we set $HOME
+ */
+ size++;
+
+ /*
+ * In failsafe mode we set $SHELL, since login won't be around to do it.
+ */
+ size++;
+
+ if ((new_env = malloc(sizeof (char *) * size)) == NULL)
+ return (NULL);
+
+ if ((estr = _zexec_add_env("PATH=", ZONE_DEF_PATH)) == NULL) {
+ free(new_env);
+ return (NULL);
+ }
+ new_env[e++] = estr;
+
+ if (term != NULL) {
+ if ((estr = _zexec_add_env("TERM=", term)) == NULL) {
+ free(new_env);
+ return (NULL);
+ }
+ new_env[e++] = estr;
+ }
+
+ if ((estr = _zexec_add_env("HOME=", "/")) == NULL) {
+ free(new_env);
+ return (NULL);
+ }
+ new_env[e++] = estr;
+
+ if ((estr = _zexec_add_env("SHELL=", ZONE_FAILSAFESHELL)) == NULL) {
+ free(new_env);
+ return (NULL);
+ }
+ new_env[e++] = estr;
+
+ new_env[e++] = NULL;
+
+ return (new_env);
+}
+
+/*
+ * Name: _z_zone_exec
+ * Description: Execute a Unix command in a specified zone and return results
+ * Arguments:
+ * r_status - [RO, *RW] - (int *)
+ * Return (exit) status from Unix command:
+ * == -1 : child terminated with a signal
+ * != -1 : lower 8-bit value child passed to exit()
+ * r_results - [RO, *RW] - (char **)
+ * Any output generated by the Unix command to stdout
+ * and to stderr
+ * == (char *)NULL if no output generated
+ * a_inputFile - [RO, *RO] - (char *)
+ * Pointer to character string representing file to be
+ * used as "standard input" for the command.
+ * == (char *)NULL to use "/dev/null" as standard input
+ * a_path - [RO, *RO] - (char *)
+ * Pointer to character string representing the full path
+ * *in the non-global zone named by a_zoneName*of the Unix
+ * command to be executed
+ * char **a_args - [RO, *RO] - (char **)
+ * List of character strings representing the arguments
+ * to be passed to the Unix command.
+ * NOTE: The list must be terminated with an element that
+ * ----- is (char *)NULL
+ * NOTE: a_argv[0] is the "command name" passed to the
+ * ----- command executed in the specified non-global zone
+ * a_zoneName - pointer to string representing the name of the zone
+ * to execute the specified command in
+ * a_fds - Pointer to array of integers representing file
+ * descriptors to remain open during the call - all
+ * file descriptors above STDERR_FILENO not in this
+ * list will be closed.
+ * Returns: int
+ * == 0 - Command executed
+ * Look at r_status for results of Unix command
+ * != 0 - problems executing command
+ * r_status and r_results have no meaning;
+ * r_status will be -1
+ * r_results will be NULL
+ * The return (exit) code from the specified Unix command
+ * Special return codes:
+ * -1 : failure to exec process
+ * -2 : could not create contract for greenline
+ * -3 : fork() failed
+ * -4 : could not open stdin source file
+ * -5 : error from 'waitpid' other than EINTR
+ * -6 : zones are not supported
+ * -7 : interrupt received
+ * NOTE: All file descriptores other than 0, 1 and 2 are closed except
+ * for those file descriptors listed in the a_fds array.
+ */
+
+int
+_z_zone_exec(int *r_status, char **r_results, char *a_inputFile,
+ char *a_path, char *a_argv[], const char *a_zoneName, int *a_fds)
+{
+ struct sigaction nact;
+ struct sigaction oact;
+ char *buffer;
+ char *thisZoneName;
+ int bufferIndex;
+ int bufferSize;
+ int exit_no;
+ int ipipe[2] = {0, 0};
+ int lerrno;
+ int n;
+ int status;
+ int stdinfile = -1;
+ int tmpl_fd;
+ pid_t child_pid;
+ pid_t result_pid;
+ void (*funcSighup)();
+ void (*funcSigint)();
+
+ /* entry assertions */
+
+ assert(a_path != (char *)NULL);
+ assert(*a_path != '\0');
+ assert(a_argv != (char **)NULL);
+ assert(a_argv[0] != (char *)NULL);
+ assert(*a_argv[0] != '\0');
+ assert(a_zoneName != (char *)NULL);
+
+ /*
+ * if requested to execute in current zone name, directly execute
+ */
+
+ thisZoneName = z_get_zonename();
+ status = (strcmp(a_zoneName, thisZoneName) == 0);
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONE_EXEC_CMD_ENTER, a_path, a_zoneName, thisZoneName);
+ (void) free(thisZoneName);
+ for (n = 0; a_argv[n]; n++) {
+ _z_echoDebug(DBG_ARG, n, a_argv[n]);
+ }
+
+ /* if this zone, just exec the command directly */
+
+ if (status != 0) {
+ return (z_ExecCmdArray(r_status, r_results, a_inputFile,
+ a_path, a_argv));
+ }
+
+ /* reset return results buffer pointer */
+
+ if (r_results != (char **)NULL) {
+ *r_results = (char *)NULL;
+ }
+
+ *r_status = -1; /* -1 : failure to exec process */
+
+ /* if zones are not implemented, return TRUE */
+
+ if (!z_zones_are_implemented()) {
+ return (-6); /* -6 : zones are not supported */
+ }
+
+ if ((tmpl_fd = _zexec_init_template()) == -1) {
+ _z_program_error(ERR_CANNOT_CREATE_CONTRACT, strerror(errno));
+ return (-2); /* -2 : cannot create greenline contract */
+ }
+
+ /*
+ * See if input file exists
+ */
+
+ if (a_inputFile != (char *)NULL) {
+ stdinfile = open(a_inputFile, O_RDONLY);
+ } else {
+ stdinfile = open("/dev/null", O_RDONLY); /* stdin = /dev/null */
+ }
+
+ if (stdinfile < 0) {
+ return (-4); /* -4 : could not open stdin source file */
+ }
+
+ /*
+ * Create a pipe to be used to capture the command output
+ */
+
+ if (pipe(ipipe) != 0) {
+ (void) close(stdinfile);
+ return (-1);
+ }
+
+ bufferSize = PIPE_BUFFER_INCREMENT;
+ bufferIndex = 0;
+ buffer = calloc(1, bufferSize);
+ if (buffer == (char *)NULL) {
+ (void) close(stdinfile);
+ return (-1);
+ }
+
+ /* flush standard i/o before creating new process */
+
+ (void) fflush(stderr);
+ (void) fflush(stdout);
+
+ /*
+ * hold SIGINT/SIGHUP signals and reset signal received counter;
+ * after the fork1() the parent and child need to setup their respective
+ * interrupt handling and release the hold on the signals
+ */
+
+ (void) sighold(SIGINT);
+ (void) sighold(SIGHUP);
+
+ _z_global_data._z_SigReceived = 0; /* no signals received */
+
+ /*
+ * fork off a new process to execute command in;
+ * fork1() is used instead of vfork() so the child process can
+ * perform operations that would modify the parent process if
+ * vfork() were used
+ */
+
+ child_pid = fork1();
+
+ if (child_pid < 0) {
+ /*
+ * *************************************************************
+ * fork failed!
+ * *************************************************************
+ */
+
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+ (void) free(buffer);
+ _z_program_error(ERR_FORK, strerror(errno));
+
+ /* release hold on signals */
+ (void) sigrelse(SIGHUP);
+ (void) sigrelse(SIGINT);
+
+ return (-3); /* -3 : fork() failed */
+ }
+
+ if (child_pid == 0) {
+ int i;
+
+ /*
+ * *************************************************************
+ * This is the forked (child) process
+ * *************************************************************
+ */
+
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+
+ /* reset any signals to default */
+
+ for (i = 0; i < NSIG; i++) {
+ (void) sigset(i, SIG_DFL);
+ }
+
+ /* assign stdin, stdout, stderr as appropriate */
+
+ (void) dup2(stdinfile, STDIN_FILENO);
+ (void) close(ipipe[0]); /* close out pipe reader side */
+ (void) dup2(ipipe[1], STDOUT_FILENO);
+ (void) dup2(ipipe[1], STDERR_FILENO);
+
+ /*
+ * close all file descriptors not in the a_fds list
+ */
+
+ (void) fdwalk(&_z_close_file_descriptors, (void *)a_fds);
+
+ /* release all held signals */
+
+ (void) sigrelse(SIGHUP);
+ (void) sigrelse(SIGINT);
+
+ /* execute command in the specified non-global zone */
+
+ _exit(_zexec(a_zoneName, a_path, a_argv));
+ }
+
+ /*
+ * *********************************************************************
+ * This is the forking (parent) process
+ * *********************************************************************
+ */
+
+ /* register child process i.d. so signal handlers can pass signal on */
+
+ _z_global_data._z_ChildProcessId = child_pid;
+
+ /*
+ * setup signal handlers for SIGINT and SIGHUP and release hold
+ */
+
+ /* hook SIGINT to _z_sig_trap() */
+
+ nact.sa_handler = _z_sig_trap;
+ nact.sa_flags = SA_RESTART;
+ (void) sigemptyset(&nact.sa_mask);
+
+ if (sigaction(SIGINT, &nact, &oact) < 0) {
+ funcSigint = SIG_DFL;
+ } else {
+ funcSigint = oact.sa_handler;
+ }
+
+ /* hook SIGHUP to _z_sig_trap() */
+
+ nact.sa_handler = _z_sig_trap;
+ nact.sa_flags = SA_RESTART;
+ (void) sigemptyset(&nact.sa_mask);
+
+ if (sigaction(SIGHUP, &nact, &oact) < 0) {
+ funcSighup = SIG_DFL;
+ } else {
+ funcSighup = oact.sa_handler;
+ }
+
+ /* release hold on signals */
+
+ (void) sigrelse(SIGHUP);
+ (void) sigrelse(SIGINT);
+
+ (void) ct_tmpl_clear(tmpl_fd);
+ (void) close(tmpl_fd);
+
+ (void) close(stdinfile);
+ (void) close(ipipe[1]); /* Close write side of pipe */
+
+ /*
+ * Spin reading data from the child into the buffer - when the read eofs
+ * the child has exited
+ */
+
+ for (;;) {
+ ssize_t bytesRead;
+
+ /* read as much child data as there is available buffer space */
+
+ bytesRead = read(ipipe[0], buffer + bufferIndex,
+ bufferSize - bufferIndex);
+
+ /* break out of read loop if end-of-file encountered */
+
+ if (bytesRead == 0) {
+ break;
+ }
+
+ /* if error, continue if recoverable, else break out of loop */
+
+ if (bytesRead == -1) {
+ /* try again: EAGAIN - insufficient resources */
+
+ if (errno == EAGAIN) {
+ continue;
+ }
+
+ /* try again: EINTR - interrupted system call */
+
+ if (errno == EINTR) {
+ continue;
+ }
+
+ /* break out of loop - error not recoverable */
+ break;
+ }
+
+ /* at least 1 byte read: expand buffer if at end */
+
+ bufferIndex += bytesRead;
+ if (bufferIndex >= bufferSize) {
+ buffer = realloc(buffer,
+ bufferSize += PIPE_BUFFER_INCREMENT);
+ (void) memset(buffer + bufferIndex, 0,
+ bufferSize - bufferIndex);
+ }
+ }
+
+ (void) close(ipipe[0]); /* Close read side of pipe */
+
+ /*
+ * wait for the process to exit, reap child exit status
+ */
+
+ for (;;) {
+ result_pid = waitpid(child_pid, &status, 0L);
+ lerrno = (result_pid == -1 ? errno : 0);
+
+ /* break loop if child process status reaped */
+
+ if (result_pid != -1) {
+ break;
+ }
+
+ /* break loop if not interrupted out of waitpid */
+
+ if (errno != EINTR) {
+ break;
+ }
+ }
+
+ /* reset child process i.d. so signal handlers do not pass signals on */
+
+ _z_global_data._z_ChildProcessId = -1;
+
+ /*
+ * If the child process terminated due to a call to exit(), then
+ * set results equal to the 8-bit exit status of the child process;
+ * otherwise, set the exit status to "-1" indicating that the child
+ * exited via a signal.
+ */
+
+ if (WIFEXITED(status)) {
+ *r_status = WEXITSTATUS(status);
+ if ((_z_global_data._z_SigReceived != 0) && (*r_status == 0)) {
+ *r_status = 1;
+ }
+ } else {
+ *r_status = -1; /* -1 : failure to exec process */
+ }
+
+ /* determine proper exit code */
+
+ if (result_pid == -1) {
+ exit_no = -5; /* -5 : error from 'waitpid' other than EINTR */
+ } else if (_z_global_data._z_SigReceived != 0) {
+ exit_no = -7; /* -7 : interrupt received */
+ } else {
+ exit_no = 0;
+ }
+
+ /* return appropriate output */
+
+ if (!*buffer) {
+ /* No contents in output buffer - discard */
+ free(buffer);
+ } else if (r_results == (char **)NULL) {
+ /* Not requested to return results - discard */
+ free(buffer);
+ } else {
+ /* have output and request to return: pass to calling method */
+ *r_results = buffer;
+ }
+
+ /*
+ * reset signal handlers
+ */
+
+ /* reset SIGINT */
+
+ nact.sa_handler = funcSigint;
+ nact.sa_flags = SA_RESTART;
+ (void) sigemptyset(&nact.sa_mask);
+
+ (void) sigaction(SIGINT, &nact, (struct sigaction *)NULL);
+
+ /* reset SIGHUP */
+
+ nact.sa_handler = funcSighup;
+ nact.sa_flags = SA_RESTART;
+ (void) sigemptyset(&nact.sa_mask);
+
+ (void) sigaction(SIGHUP, &nact, (struct sigaction *)NULL);
+
+ /*
+ * if signal received during command execution, interrupt
+ * this process now.
+ */
+
+ if (_z_global_data._z_SigReceived != 0) {
+ (void) kill(getpid(), SIGINT);
+ }
+
+ /* set errno and return */
+
+ errno = lerrno;
+
+ return (exit_no);
+}
+
+/*
+ * Name: z_ExecCmdList
+ * Synopsis: Execute Unix command and return results
+ * Description: Execute a Unix command and return results and status
+ * Arguments:
+ * r_status - [RO, *RW] - (int *)
+ * Return (exit) status from Unix command
+ * r_results - [RO, *RW] - (char **)
+ * Any output generated by the Unix command to stdout
+ * and to stderr
+ * == (char *)NULL if no output generated
+ * a_inputFile - [RO, *RO] - (char *)
+ * Pointer to character string representing file to be
+ * used as "standard input" for the command.
+ * == (char *)NULL to use "/dev/null" as standard input
+ * a_cmd - [RO, *RO] - (char *)
+ * Pointer to character string representing the full path
+ * of the Unix command to execute
+ * ... - [RO] (?)
+ * Zero or more arguments to the Unix command
+ * The argument list must be ended with (void *)NULL
+ * Returns: int
+ * == 0 - Command executed
+ * Look at r_status for results of Unix command
+ * != 0 - problems executing command
+ * r_status and r_results have no meaning
+ * NOTE: Any results returned is placed in new storage for the
+ * calling method. The caller must use 'free' to dispose
+ * of the storage once the results are no longer needed.
+ * NOTE: If LU_SUCCESS is returned, 'r_status' must be queried to
+ * determine the results of the Unix command.
+ */
+
+/*VARARGS*/
+int
+z_ExecCmdList(int *r_status, char **r_results,
+ char *a_inputFile, char *a_cmd, ...)
+{
+ va_list ap; /* references variable argument list */
+ char *array[MAX_EXEC_CMD_ARGS+1];
+ int argno = 0;
+
+ /*
+ * Create argument array for exec system call
+ */
+
+ bzero(array, sizeof (array));
+
+ va_start(ap, a_cmd); /* Begin variable argument processing */
+
+ for (argno = 0; argno < MAX_EXEC_CMD_ARGS; argno++) {
+ array[argno] = va_arg(ap, char *);
+ if (array[argno] == (char *)NULL) {
+ break;
+ }
+ }
+
+ va_end(ap);
+ return (z_ExecCmdArray(r_status, r_results, a_inputFile,
+ a_cmd, array));
+}
diff --git a/usr/src/lib/libinstzones/common/zones_locks.c b/usr/src/lib/libinstzones/common/zones_locks.c
new file mode 100644
index 0000000000..36db482657
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones_locks.c
@@ -0,0 +1,995 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+/*
+ * 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 <sys/types.h>
+#include <sys/param.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
+ */
+
+boolean_t _z_adjust_lock_object_for_rootpath(char **r_result,
+ char *a_lockObject);
+boolean_t _z_acquire_lock(char **r_lockKey, char *a_zoneName,
+ char *a_lock, pid_t a_pid, boolean_t a_wait);
+boolean_t _z_lock_zone(zoneListElement_t *a_zlst,
+ ZLOCKS_T a_lflags);
+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);
+boolean_t _z_release_lock(char *a_zoneName, char *a_lock,
+ char *a_key, boolean_t a_wait);
+ boolean_t _z_unlock_zone(zoneListElement_t *a_zlst,
+ ZLOCKS_T a_lflags);
+boolean_t _z_unlock_zone_object(char **r_objectLocks,
+ 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
+_z_acquire_lock(char **r_lockKey, char *a_zoneName, char *a_lockObject,
+ pid_t a_pid, boolean_t a_wait)
+{
+ argArray_t *args;
+ boolean_t b;
+ char *adjustedLockObject = (char *)NULL;
+ char *p;
+ char *results = (char *)NULL;
+ int r;
+ int status;
+
+ /* entry assertions */
+
+ assert(a_zoneName != (char *)NULL);
+ assert(a_lockObject != (char *)NULL);
+ assert(*a_lockObject != '\0');
+ assert(r_lockKey != (char **)NULL);
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_APLK, a_zoneName, a_lockObject, a_pid);
+
+ /* reset returned lock key handle */
+
+ *r_lockKey = (char *)NULL;
+
+ /*
+ * 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.
+ */
+
+ b = _z_adjust_lock_object_for_rootpath(&adjustedLockObject,
+ a_lockObject);
+ if (!b) {
+ return (B_FALSE);
+ }
+
+ /*
+ * construct command arguments:
+ * pkgadm lock -a -q -o adjustedLockObject [ -w -W timeout ]
+ * [ -p a_pid -z zoneid ]
+ */
+
+ args = _z_new_args(20); /* generate new arg list */
+ (void) _z_add_arg(args, PKGADM_CMD); /* pkgadm command */
+ (void) _z_add_arg(args, "lock"); /* lock sub-command */
+ (void) _z_add_arg(args, "-a"); /* acquire lock */
+ (void) _z_add_arg(args, "-q"); /* quiet (no extra messages) */
+ (void) _z_add_arg(args, "-o"); /* object to acquire */
+ (void) _z_add_arg(args, "%s", adjustedLockObject);
+
+ /* add [ -w -W timeout ] if waiting for lock */
+
+ if (a_wait == B_TRUE) {
+ (void) _z_add_arg(args, "-w"); /* wait */
+ (void) _z_add_arg(args, "-W"); /* wait timeout */
+ (void) _z_add_arg(args, "%ld",
+ (long)MAX_RETRIES*RETRY_DELAY_SECS);
+ }
+
+ /* add process/zone i.d.s if process i.d. provided */
+
+ if (a_pid > 0) {
+ (void) _z_add_arg(args, "-p"); /* lock valid process i.d. */
+ (void) _z_add_arg(args, "%ld", getpid());
+ (void) _z_add_arg(args, "-z"); /* lock valid zone i.d. */
+ (void) _z_add_arg(args, "%ld", getzoneid());
+ }
+
+ /* execute command */
+
+ r = _z_zone_exec(&status, &results, (char *)NULL, PKGADM_CMD,
+ _z_get_argv(args), a_zoneName, (int *)NULL);
+
+ /* free generated argument list */
+
+ _z_free_args(args);
+
+ /* return error if failed to acquire */
+
+ if ((r != 0) || (status != 0)) {
+ _z_echoDebug(DBG_ZONES_APLK_EXIT, a_zoneName,
+ adjustedLockObject, a_pid, r, status,
+ results ? results : "");
+
+ /* free up results if returned */
+ if (results) {
+ free(results);
+ }
+
+ /* free adjusted lock object */
+ free(adjustedLockObject);
+
+ /* return failure */
+ return (B_FALSE);
+ }
+
+ /* return success if no results returned */
+
+ if (results == (char *)NULL) {
+ return (B_TRUE);
+ }
+
+ /* return the lock key */
+
+ p = _z_strGetToken((char *)NULL, results, 0, "\n");
+ _z_strRemoveLeadingWhitespace(&p);
+ *r_lockKey = p;
+
+ /* exit debugging info */
+
+ _z_echoDebug(DBG_ZONES_APLK_RESULTS, a_zoneName, adjustedLockObject, p,
+ results);
+
+ /* free up results */
+
+ free(results);
+
+ /* free adjusted lock object */
+
+ free(adjustedLockObject);
+
+ /* 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
+ * is if "-R /tmp/gmg*dir.test-path" is specified, the final object
+ * 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:
+ *
+ * "rootpath./tmp/gmg*dir.test-path" "zone.*" "package.*"
+ */
+
+boolean_t
+_z_adjust_lock_object_for_rootpath(char **r_result, char *a_lockObject)
+{
+ char realRootPath[PATH_MAX] = {'\0'};
+ const char *a_rootPath;
+
+ /* entry assertions */
+
+ assert(r_result != (char **)NULL);
+ assert(a_lockObject != (char *)NULL);
+ assert(*a_lockObject != '\0');
+
+ /* reset returned lock object handle */
+
+ *r_result = (char *)NULL;
+
+ /*
+ * 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).
+ */
+
+ a_rootPath = _z_global_data._z_root_dir;
+ if ((a_rootPath == (char *)NULL) ||
+ (*a_rootPath == '\0') ||
+ (strcmp(a_rootPath, "/") == 0)) {
+
+ /* root path not specified or is only "/" - no -R specified */
+
+ *r_result = _z_strdup(a_lockObject);
+ } 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.
+ */
+
+ if (realpath(a_rootPath, realRootPath) == (char *)NULL) {
+ /* cannot determine absolute path; use path specified */
+ (void) strlcpy(realRootPath, a_rootPath,
+ 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
+ */
+
+ if (strcmp(realRootPath, "/") == 0) {
+ *r_result = _z_strdup(a_lockObject);
+ } else {
+ char *p1, *p2, *p3;
+
+ /* prefix out /.* which cannot be part of lock object */
+
+ p1 = _z_calloc((strlen(realRootPath)*2)+1);
+ for (p3 = p1, p2 = realRootPath; *p2 != '\0'; p2++) {
+ 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 */
+ *p3++ = *p2;
+ break;
+ }
+ }
+
+ /* create "realpath.%s" object */
+
+ p2 = _z_strPrintf(LOBJ_ROOTPATH, p1);
+ free(p1);
+ if (p2 == (char *)NULL) {
+ _z_program_error(ERR_MALLOC, "<path>", errno,
+ strerror(errno));
+ return (B_FALSE);
+ }
+
+ /* create "realpath.%s/..." final lock object */
+
+ *r_result = _z_strPrintf("%s/%s", p2, a_lockObject);
+ free(p2);
+ if (*r_result == (char *)NULL) {
+ _z_program_error(ERR_MALLOC, "<path>", errno,
+ strerror(errno));
+ return (B_FALSE);
+ }
+ }
+ }
+
+ /* exit debugging info */
+
+ _z_echoDebug(DBG_ZONES_ADJLCKOBJ_EXIT, a_lockObject, *r_result,
+ a_rootPath ? a_rootPath : "",
+ realRootPath ? realRootPath : "");
+
+ /* return success */
+
+ return (B_TRUE);
+}
+
+/*
+ * Name: _z_lock_zone
+ * Description: Acquire specified locks on specified zone
+ * Arguments: a_zlst - [RO, *RW] - (zoneListElement_t *)
+ * Pointer to zone list structure element describing
+ * the zone the lock - the structure is updated with
+ * the lock objects and keys if the locks are acquired
+ * a_lflags - [RO, *RO] - (ZLOCKS_T)
+ * Flags indicating which locks to acquire on the zone
+ * Returns: boolean_t
+ * == B_TRUE - locks successfully acquired
+ * == B_FALSE - failed to acquire the locks
+ */
+
+boolean_t
+_z_lock_zone(zoneListElement_t *a_zlst, ZLOCKS_T a_lflags)
+{
+ char *scratchName;
+ boolean_t b;
+
+ /* entry assertions */
+
+ assert(a_zlst != (zoneListElement_t *)NULL);
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_LCK_ZONE, a_zlst->_zlName, a_lflags);
+
+ scratchName = a_zlst->_zlScratchName == NULL ? a_zlst->_zlName :
+ a_zlst->_zlScratchName;
+
+ /*
+ * acquire zone lock
+ */
+
+ if (a_lflags & ZLOCKS_ZONE_ADMIN) {
+ /*
+ * lock zone administration if not already locked
+ * if the lock cannot be released, stop and return an error
+ */
+
+ _z_echoDebug(DBG_ZONES_LCK_ZONE_ZONEADM, a_zlst->_zlName,
+ LOBJ_ZONEADMIN);
+
+ b = _z_lock_zone_object(&a_zlst->_zlLockObjects,
+ scratchName, LOBJ_ZONEADMIN, (pid_t)0,
+ MSG_ZONES_LCK_ZONE_ZONEADM,
+ ERR_ZONES_LCK_ZONE_ZONEADM);
+ if (b == B_FALSE) {
+ return (b);
+ }
+ }
+
+ /*
+ * acquire package lock
+ */
+
+ if (a_lflags & ZLOCKS_PKG_ADMIN) {
+
+ /*
+ * zone administration is locked; lock package administration if
+ * not already locked; if the lock cannot be released, stop,
+ * release the zone administration lock and return an error
+ */
+
+ _z_echoDebug(DBG_ZONES_LCK_ZONE_PKGADM, a_zlst->_zlName,
+ LOBJ_PKGADMIN);
+
+ b = _z_lock_zone_object(&a_zlst->_zlLockObjects,
+ scratchName, LOBJ_PKGADMIN, (pid_t)0,
+ MSG_ZONES_LCK_ZONE_PKGADM,
+ ERR_ZONES_LCK_ZONE_PKGADM);
+ if (b == B_FALSE) {
+ (void) _z_unlock_zone(a_zlst, a_lflags);
+ return (b);
+ }
+ }
+
+ /*
+ * acquire patch lock
+ */
+
+ if (a_lflags & ZLOCKS_PATCH_ADMIN) {
+
+ /*
+ * zone and package administration is locked; lock patch
+ * administration; if the lock cannot be released, stop,
+ * release the other locks and return an error
+ */
+
+ _z_echoDebug(DBG_ZONES_LCK_ZONE_PATCHADM, a_zlst->_zlName,
+ LOBJ_PATCHADMIN);
+
+ b = _z_lock_zone_object(&a_zlst->_zlLockObjects,
+ scratchName, LOBJ_PATCHADMIN, (pid_t)0,
+ MSG_ZONES_LCK_ZONE_PATCHADM,
+ ERR_ZONES_LCK_ZONE_PATCHADM);
+ if (b == B_FALSE) {
+ (void) _z_unlock_zone(a_zlst, a_lflags);
+ return (b);
+ }
+ }
+
+ /*
+ * all locks have been obtained - 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
+_z_lock_zone_object(char **r_objectLocks, char *a_zoneName, char *a_lockObject,
+ pid_t a_pid, char *a_waitingMsg, char *a_busyMsg)
+{
+ boolean_t b;
+ char *p = (char *)NULL;
+ char lockItem[LOCK_OBJECT_MAXLEN+LOCK_KEY_MAXLEN+4];
+ char lockKey[LOCK_KEY_MAXLEN+2];
+ char lockObject[LOCK_OBJECT_MAXLEN+2];
+ int i;
+
+ /* entry assertions */
+
+ assert(r_objectLocks != (char **)NULL);
+ assert(a_zoneName != (char *)NULL);
+ assert(a_waitingMsg != (char *)NULL);
+ assert(a_busyMsg != (char *)NULL);
+ assert(a_lockObject != (char *)NULL);
+ assert(*a_lockObject != '\0');
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_LCK_OBJ, a_lockObject, a_zoneName, a_pid,
+ *r_objectLocks ? *r_objectLocks : "");
+
+ /* 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 */
+ _z_strGetToken_r((char *)NULL, *r_objectLocks, i, "\n",
+ lockItem, sizeof (lockItem));
+
+ /* break out of loop if no more locks in list */
+
+ if (lockItem[0] == '\0') {
+ _z_echoDebug(DBG_ZONES_LCK_OBJ_NOTHELD,
+ a_lockObject, a_zoneName);
+ break;
+ }
+
+ /* get object and key for this lock */
+ _z_strGetToken_r((char *)NULL, lockItem, 0, "\t",
+ lockObject, sizeof (lockObject));
+ _z_strGetToken_r((char *)NULL, lockItem, 1, "\t",
+ lockKey, sizeof (lockKey));
+
+ /* return success if the lock is held */
+
+ if (strcmp(lockObject, a_lockObject) == 0) {
+ _z_echoDebug(DBG_ZONES_LCK_OBJ_FOUND,
+ lockObject, lockKey);
+ return (B_TRUE);
+ }
+
+ /* not the object to lock - scan next object */
+ _z_echoDebug(DBG_ZONES_LCK_OBJ_NOTFOUND, lockObject,
+ lockKey);
+ }
+ }
+
+ /*
+ * the object to lock is not held - acquire the lock
+ */
+
+ /* acquire object with no wait */
+ b = _z_acquire_lock(&p, a_zoneName, a_lockObject, a_pid, B_FALSE);
+ if (b == B_FALSE) {
+ /* failure - output message and acquire with wait */
+ _z_echo(a_waitingMsg, (long)MAX_RETRIES*RETRY_DELAY_SECS,
+ a_zoneName, _z_global_data._z_root_dir);
+ b = _z_acquire_lock(&p, a_zoneName, a_lockObject, a_pid,
+ B_TRUE);
+ }
+
+ /* output error message and return failure if both acquires failed */
+ if (b == B_FALSE) {
+ _z_program_error(a_busyMsg, a_zoneName);
+ return (b);
+ }
+
+ /* add object/key to held locks */
+
+ _z_strPrintf_r(lockItem, sizeof (lockItem), "%s\t%s", a_lockObject, p);
+ _z_strAddToken(r_objectLocks, lockItem, '\n');
+
+ 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
+_z_release_lock(char *a_zoneName, char *a_lockObject, char *a_lockKey,
+ boolean_t a_wait)
+{
+ argArray_t *args;
+ boolean_t b;
+ char *adjustedLockObject = (char *)NULL;
+ char *results = (char *)NULL;
+ int r;
+ int status;
+
+ /* entry assertions */
+
+ assert(a_zoneName != (char *)NULL);
+ assert(a_lockObject != (char *)NULL);
+ assert(*a_lockObject != '\0');
+ assert(a_lockKey != (char *)NULL);
+ assert(*a_lockKey != '\0');
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_RELK, a_zoneName, a_lockObject,
+ a_lockKey ? a_lockKey : "");
+
+ /*
+ * 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.
+ */
+
+ b = _z_adjust_lock_object_for_rootpath(&adjustedLockObject,
+ a_lockObject);
+ if (!b) {
+ return (B_FALSE);
+ }
+
+ /*
+ * construct command arguments:
+ * pkgadm lock -r -o adjustedLockObject -k a_lockKey [-w -W timeout]
+ */
+
+ args = _z_new_args(20); /* generate new arg list */
+ (void) _z_add_arg(args, PKGADM_CMD); /* pkgadm command */
+ (void) _z_add_arg(args, "lock"); /* lock sub-command */
+ (void) _z_add_arg(args, "-r"); /* release lock */
+ (void) _z_add_arg(args, "-o"); /* object to release */
+ (void) _z_add_arg(args, "%s", adjustedLockObject);
+ (void) _z_add_arg(args, "-k"); /* object's key */
+ (void) _z_add_arg(args, "%s", a_lockKey);
+
+ /* add [ -w -W timeout ] if waiting for lock */
+
+ if (a_wait == B_TRUE) {
+ (void) _z_add_arg(args, "-w"); /* wait */
+ (void) _z_add_arg(args, "-W"); /* wait timeout */
+ (void) _z_add_arg(args, "%ld",
+ (long)MAX_RETRIES*RETRY_DELAY_SECS);
+ }
+
+ /* execute command */
+
+ r = _z_zone_exec(&status, &results, (char *)NULL, PKGADM_CMD,
+ _z_get_argv(args), a_zoneName, (int *)NULL);
+
+ /* free generated argument list */
+
+ _z_free_args(args);
+
+ /* exit debugging info */
+
+ _z_echoDebug(DBG_ZONES_RELK_EXIT, adjustedLockObject, a_lockKey,
+ a_zoneName, r, status, results ? results : "");
+
+ /* free adjusted lock object */
+
+ free(adjustedLockObject);
+ free(results);
+
+ return (((r == 0) && (status == 0)) ? B_TRUE : B_FALSE);
+}
+
+
+
+/*
+ * Name: _z_unlock_zone
+ * Description: Released specified locks on specified zone
+ * Arguments: a_zlst - [RO, *RW] - (zoneListElement_t *)
+ * Pointer to zone list structure element describing
+ * the zone the unlock - the structure is updated by
+ * removing the lock object and key if the locks are
+ * successfully released
+ * a_lflags - [RO, *RO] - (ZLOCKS_T)
+ * Flags indicating which locks to release on the zone
+ * Returns: boolean_t
+ * == B_TRUE - locks successfully released
+ * == B_FALSE - failed to release the locks
+ */
+
+boolean_t
+_z_unlock_zone(zoneListElement_t *a_zlst, ZLOCKS_T a_lflags)
+{
+ char *scratchName;
+ boolean_t b;
+ boolean_t errors = B_FALSE;
+
+ /* entry assertions */
+
+ assert(a_zlst != (zoneListElement_t *)NULL);
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_ULK_ZONE, a_zlst->_zlName, a_lflags);
+
+ scratchName = a_zlst->_zlScratchName == NULL ? a_zlst->_zlName :
+ a_zlst->_zlScratchName;
+
+ if (a_lflags & ZLOCKS_PATCH_ADMIN) {
+ /*
+ * if locked, unlock patch administration lock
+ * if the lock cannot be released, continue anyway
+ */
+
+ _z_echoDebug(DBG_ZONES_ULK_ZONE_PATCHADM, a_zlst->_zlName,
+ LOBJ_PATCHADMIN);
+
+ b = _z_unlock_zone_object(&a_zlst->_zlLockObjects,
+ scratchName, LOBJ_PATCHADMIN,
+ WRN_ZONES_ULK_ZONE_PATCHADM);
+ if (b == B_FALSE) {
+ errors = B_TRUE;
+ }
+ }
+
+ if (a_lflags & ZLOCKS_PKG_ADMIN) {
+ /*
+ * if locked, unlock package administration lock
+ * if the lock cannot be released, continue anyway
+ */
+
+ _z_echoDebug(DBG_ZONES_ULK_ZONE_PKGADM, a_zlst->_zlName,
+ LOBJ_PKGADMIN);
+
+ b = _z_unlock_zone_object(&a_zlst->_zlLockObjects,
+ scratchName, LOBJ_PKGADMIN,
+ WRN_ZONES_ULK_ZONE_PKGADM);
+ if (b == B_FALSE) {
+ errors = B_TRUE;
+ }
+ }
+
+ if (a_lflags & ZLOCKS_ZONE_ADMIN) {
+
+ /*
+ * if locked, unlock zone administration lock
+ * if the lock cannot be released, continue anyway
+ */
+
+ _z_echoDebug(DBG_ZONES_ULK_ZONE_ZONEADM, a_zlst->_zlName,
+ LOBJ_ZONEADMIN);
+
+ b = _z_unlock_zone_object(&a_zlst->_zlLockObjects,
+ scratchName, LOBJ_ZONEADMIN,
+ WRN_ZONES_ULK_ZONE_ZONEADM);
+ if (b == B_FALSE) {
+ errors = B_TRUE;
+ }
+ }
+
+ return (!errors);
+}
+
+/*
+ * 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
+ */
+
+boolean_t
+_z_unlock_zone_object(char **r_objectLocks, char *a_zoneName,
+ char *a_lockObject, char *a_errMsg)
+{
+ boolean_t b;
+ char lockItem[LOCK_OBJECT_MAXLEN+LOCK_KEY_MAXLEN+4];
+ char lockKey[LOCK_KEY_MAXLEN+2];
+ char lockObject[LOCK_OBJECT_MAXLEN+2];
+ int i;
+
+ /* entry assertions */
+
+ assert(r_objectLocks != (char **)NULL);
+ assert(a_zoneName != (char *)NULL);
+ assert(a_errMsg != (char *)NULL);
+ assert(a_lockObject != (char *)NULL);
+ assert(*a_lockObject != '\0');
+
+ /* entry debugging info */
+
+ _z_echoDebug(DBG_ZONES_ULK_OBJ, a_lockObject, a_zoneName,
+ *r_objectLocks ? *r_objectLocks : "");
+
+ /* return success if no objects are locked */
+
+ if (*r_objectLocks == (char *)NULL) {
+ _z_echoDebug(DBG_ZONES_ULK_OBJ_NONE, a_zoneName);
+ return (B_TRUE);
+ }
+
+ /* see if the specified lock is held on this zone */
+
+ for (i = 0; ; i++) {
+ /* get next object locked on this zone */
+ _z_strGetToken_r((char *)NULL, *r_objectLocks, i, "\n",
+ lockItem, sizeof (lockItem));
+
+ /* return success if no more objects locked */
+ if (lockItem[0] == '\0') {
+ _z_echoDebug(DBG_ZONES_ULK_OBJ_NOTHELD, a_lockObject,
+ a_zoneName);
+ return (B_TRUE);
+ }
+
+ /* get object and key for this lock */
+ _z_strGetToken_r((char *)NULL, lockItem, 0, "\t",
+ lockObject, sizeof (lockObject));
+ _z_strGetToken_r((char *)NULL, lockItem, 1, "\t",
+ lockKey, sizeof (lockKey));
+
+ /* break out of loop if object is the one to unlock */
+
+ if (strcmp(lockObject, a_lockObject) == 0) {
+ _z_echoDebug(DBG_ZONES_ULK_OBJ_FOUND, lockObject,
+ lockKey);
+ break;
+ }
+
+ /* not the object to unlock - scan next object */
+ _z_echoDebug(DBG_ZONES_ULK_OBJ_NOTFOUND, lockObject, lockKey);
+ }
+
+ /*
+ * the object to unlock is held - release the lock
+ */
+
+ /* release object with wait */
+
+ b = _z_release_lock(a_zoneName, a_lockObject, lockKey, B_TRUE);
+ if (b == B_FALSE) {
+ /* failure - issue error message and return failure */
+ _z_program_error(a_errMsg, a_zoneName);
+ return (b);
+ }
+
+ /* remove object/key from held locks */
+
+ _z_strRemoveToken(r_objectLocks, lockItem, "\n", 0);
+
+ /* return success */
+
+ return (B_TRUE);
+}
diff --git a/usr/src/lib/libinstzones/common/zones_lofs.c b/usr/src/lib/libinstzones/common/zones_lofs.c
new file mode 100644
index 0000000000..2977edc46a
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones_lofs.c
@@ -0,0 +1,288 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <sys/param.h>
+#include <libzonecfg.h>
+#include "zones_strings.h"
+#include "instzones_lib.h"
+
+#define MNTTAB "/etc/mnttab"
+
+#define MNTTAB_HUNK 32
+
+static struct mnttab *mountTable;
+static size_t mountTableSize = 0;
+static boolean_t createdFlag = B_FALSE;
+
+/*
+ * Name : z_createMountTable
+ * Description : Populate the mountTable Array with mnttab entries
+ * Arguments : void
+ * Returns : int
+ * 0: The Mount Table was succesfully initialized
+ * -1: There was an error during initialisation
+ */
+int
+z_createMountTable(void)
+{
+ FILE *fp;
+ struct mnttab ent;
+ struct mnttab *entp;
+
+ if (createdFlag) {
+ return (0);
+ }
+
+ fp = fopen(MNTTAB, "r");
+ if (fp == NULL) {
+ _z_program_error(ERR_OPEN_READ, MNTTAB, errno,
+ strerror(errno));
+ return (-1);
+ }
+
+ /* Put the entries into the table */
+ mountTable = NULL;
+ mountTableSize = 0;
+ createdFlag = B_TRUE;
+ while (getmntent(fp, &ent) == 0) {
+ if (mountTableSize % MNTTAB_HUNK == 0) {
+ mountTable = _z_realloc(mountTable,
+ (mountTableSize + MNTTAB_HUNK) * sizeof (ent));
+ }
+ entp = &mountTable[mountTableSize++];
+
+ /*
+ * Zero out any fields we're not using.
+ */
+ (void) memset(entp, 0, sizeof (*entp));
+
+ if (ent.mnt_special != NULL)
+ entp->mnt_special = _z_strdup(ent.mnt_special);
+ if (ent.mnt_mntopts != NULL)
+ entp->mnt_mntopts = _z_strdup(ent.mnt_mntopts);
+ entp->mnt_mountp = _z_strdup(ent.mnt_mountp);
+ entp->mnt_fstype = _z_strdup(ent.mnt_fstype);
+ }
+
+ (void) fclose(fp);
+ return (0);
+}
+
+/*
+ * Name : findPathRWStatus
+ * Description : Check whether the given path is an mnttab entry
+ * Arguments : char * - The Path to be verified
+ * Returns : int
+ * -1: The Path is NOT present in the table (mnttab)
+ * 0: The Path is present in the table and is mounted read-only
+ * 1: The Path is present in the table and is mounted read-write
+ */
+static int
+findPathRWStatus(const char *a_path)
+{
+ int i;
+
+ for (i = 0; i < mountTableSize; i++) {
+ if (strcmp(a_path, mountTable[i].mnt_mountp) == 0) {
+ if (hasmntopt(&mountTable[i], MNTOPT_RO) != NULL) {
+ return (0);
+ } else {
+ return (1);
+ }
+ }
+ }
+
+ return (-1);
+}
+
+
+/*
+ * Name : z_isPathWritable
+ * Description : Check if the given path is in a writable area
+ * Arguments : char * - The Path to be verified
+ * Returns : int
+ * 0: The Path is under a read-only mount
+ * 1: The Path is under a read-write mount
+ * NOTE : This funcion automatically initialises
+ * the mountPoint table if needed.
+ */
+int
+z_isPathWritable(const char *a_str)
+{
+ int i, result, slen;
+ char a_path[MAXPATHLEN];
+
+ if (!createdFlag) {
+ if (z_createMountTable() != 0) {
+ return (1);
+ }
+ }
+
+ (void) strlcpy(a_path, a_str, sizeof (a_path));
+ slen = strlen(a_path);
+
+ /*
+ * This for loop traverses Path backwards, incrementally removing the
+ * basename of Path and looking for the resultant directory in the
+ * mnttab. Once found, it returns the rw status of that file system.
+ */
+ for (i = slen; i > 0; i--) {
+ if ((a_path[i] == '/') || (a_path[i] == '\0')) {
+ a_path[i] = '\0';
+ result = findPathRWStatus(a_path);
+ if (result != -1) {
+ return (result);
+ }
+ }
+ }
+
+ return (1);
+}
+
+/*
+ * Name : z_destroyMountTable
+ * Description : Clear the entries in the mount table
+ * Arguments : void
+ * Returns : void
+ */
+void
+z_destroyMountTable(void)
+{
+ int i;
+
+ if (!createdFlag) {
+ return;
+ }
+
+ if (mountTable == NULL) {
+ return;
+ }
+
+ for (i = 0; i < mountTableSize; i++) {
+ free(mountTable[i].mnt_mountp);
+ free(mountTable[i].mnt_fstype);
+ free(mountTable[i].mnt_special);
+ free(mountTable[i].mnt_mntopts);
+ assert(mountTable[i].mnt_time == NULL);
+ }
+
+ free(mountTable);
+ mountTable = NULL;
+ mountTableSize = 0;
+ createdFlag = B_FALSE;
+}
+
+/*
+ * Name : z_resolve_lofs
+ * Description : Loop over potential loopback mounts and symlinks in a
+ * given path and resolve them all down to an absolute path.
+ * Arguments : char * - path to resolve. path is in writable storage.
+ * size_t - length of path storage.
+ * Returns : void
+ */
+void
+z_resolve_lofs(char *path, size_t pathlen)
+{
+ int len, arlen, i;
+ const char *altroot;
+ char tmppath[MAXPATHLEN];
+ boolean_t outside_altroot;
+
+ if ((len = resolvepath(path, tmppath, sizeof (tmppath))) == -1)
+ return;
+
+ tmppath[len] = '\0';
+ (void) strlcpy(path, tmppath, pathlen);
+
+ if (z_createMountTable() == -1)
+ return;
+
+ altroot = zonecfg_get_root();
+ arlen = strlen(altroot);
+ outside_altroot = B_FALSE;
+ for (;;) {
+ struct mnttab *mnp;
+
+ /* Search in reverse order to find longest match */
+ for (i = mountTableSize; i > 0; i--) {
+ mnp = &mountTable[i - 1];
+ if (mnp->mnt_fstype == NULL ||
+ mnp->mnt_mountp == NULL ||
+ mnp->mnt_special == NULL)
+ continue;
+ len = strlen(mnp->mnt_mountp);
+ if (strncmp(mnp->mnt_mountp, path, len) == 0 &&
+ (path[len] == '/' || path[len] == '\0'))
+ break;
+ }
+ if (i <= 0)
+ break;
+
+ /* If it's not a lofs then we're done */
+ if (strcmp(mnp->mnt_fstype, MNTTYPE_LOFS) != 0)
+ break;
+
+ if (outside_altroot) {
+ char *cp;
+ int olen = sizeof (MNTOPT_RO) - 1;
+
+ /*
+ * If we run into a read-only mount outside of the
+ * alternate root environment, then the user doesn't
+ * want this path to be made read-write.
+ */
+ if (mnp->mnt_mntopts != NULL &&
+ (cp = strstr(mnp->mnt_mntopts, MNTOPT_RO)) !=
+ NULL &&
+ (cp == mnp->mnt_mntopts || cp[-1] == ',') &&
+ (cp[olen] == '\0' || cp[olen] == ',')) {
+ break;
+ }
+ } else if (arlen > 0 &&
+ (strncmp(mnp->mnt_special, altroot, arlen) != 0 ||
+ (mnp->mnt_special[arlen] != '\0' &&
+ mnp->mnt_special[arlen] != '/'))) {
+ outside_altroot = B_TRUE;
+ }
+ /* use temporary buffer because new path might be longer */
+ (void) snprintf(tmppath, sizeof (tmppath), "%s%s",
+ mnp->mnt_special, path + len);
+ if ((len = resolvepath(tmppath, path, pathlen)) == -1)
+ break;
+ path[len] = '\0';
+ }
+}
diff --git a/usr/src/lib/libinstzones/common/zones_paths.c b/usr/src/lib/libinstzones/common/zones_paths.c
new file mode 100644
index 0000000000..ffcae1d40e
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones_paths.c
@@ -0,0 +1,464 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+/*
+ * System includes
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <assert.h>
+#include <locale.h>
+#include <libintl.h>
+
+/*
+ * local includes
+ */
+
+#include "instzones_lib.h"
+#include "zones_strings.h"
+
+#define isdot(x) ((x[0] == '.') && (!x[1] || (x[1] == '/')))
+#define isdotdot(x) ((x[0] == '.') && (x[1] == '.') && \
+ (!x[2] || (x[2] == '/')))
+
+/*
+ * forward declarations
+ */
+
+static char **inheritedFileSystems = (char **)NULL;
+static size_t *inheritedFileSystemsLen = (size_t *)NULL;
+static int numInheritedFileSystems = 0;
+
+/*
+ * *****************************************************************************
+ * global external (public) functions
+ * *****************************************************************************
+ */
+
+/*
+ * Name: z_get_inherited_file_systems
+ * Description: Return list of file systems inherited from the global zone;
+ * These file systems are entered into the list when the function
+ * pkgAddInheritedFileSystem() is called.
+ * Arguments: void
+ * Returns: char **
+ * - pointer to array of character pointers, each pointer
+ * being a pointer to a string representing a file
+ * system that is inherited from the global zone
+ * the last entry will be (char *)NULL
+ * - (char **)NULL - no file systems inherited
+ *
+ */
+
+char **
+z_get_inherited_file_systems(void)
+{
+ return (inheritedFileSystems);
+}
+
+/*
+ * Name: z_add_inherited_file_system
+ * Description: Add specified package to internal list of inherited file systems
+ * Arguments: a_inheritedFileSystem - absolute path to file systen "inherited"
+ *
+ * This function is called to register a directory (or
+ * file system) as being inherited from the global zone
+ * into the non-global zone being operated on. The
+ * inherited directory must be specified relative to the
+ * root file system ("/"). For example, if "/usr" is
+ * inherited, then the path specified would be "/usr".
+ *
+ * Any path subsequently checked for being present in a
+ * directory inherited read-only from the global zone:
+ *
+ * -- will NOT have $PKG_INSTALL_ROOT prepended to it
+ * -- if $PKG_INSTALL_ROOT is set and $BASEDIR is not set.
+ * -- WILL have $BASEDIR prepended to it (if set).
+ * -- $BASEDIR always has $PKG_INSTALL_ROOT included in it.
+ * -- For example, if $PKG_INSTALL_ROOT is set to /a, and
+ * -- the base install directory is set to "/opt", then the
+ * -- $BASEDIR variable will be set to "/a/opt".
+ *
+ * Any path that is checked for being present in an inherited
+ * directory will be specified relative to the root file system
+ * of the non-global zone in which the path is located.
+ *
+ * When a path to update is checked for being present in
+ * an inherited directory, $PKG_INSTALL_ROOT is stripped
+ * off the path before it is checked.
+ *
+ * If the non-global zone is not running, the scratch zone
+ * is used to access the non-global zone. In this case,
+ * $PKG_INSTALL_ROOT will be set to "/a" and both the
+ * non-global zone's root file system and all inherited
+ * directories will be mounted on "/a". When a path is checked
+ * for being inherited, it will have $PKG_INSTALL_ROOT stripped
+ * from the beginning, so any inherited directories must be
+ * specified relative to "/" and not $PKG_INSTALL_ROOT.
+ *
+ * If the non-global zone is running, the non-global zone
+ * is used directly. In this case, $PKG_INSTALL_ROOT will
+ * be set to "/" and both the non-global zone's root file
+ * system and all inherited directories will be mounted on
+ * "/". $PKG_INSTALL_ROOT is set to "/" so the path is unchanged
+ * before being checked against the list of inherited directories.
+ *
+ * Returns: boolean_t
+ * B_TRUE - file system successfully added to list
+ * B_FALSE - failed to add file system to list
+ */
+
+boolean_t
+z_add_inherited_file_system(char *a_inheritedFileSystem)
+{
+#define IPSLOP 2 /* for trailing '/' and '\0' */
+#define IPMAX ((sizeof (rp))-IPSLOP)
+
+ char rp[PATH_MAX+1+IPSLOP] = {'\0'};
+ int n;
+
+ /* file system cannot be empty */
+
+ if (a_inheritedFileSystem == NULL || *a_inheritedFileSystem == '\0') {
+ _z_program_error(ERR_INHERITED_PATH_NULL);
+ return (B_FALSE);
+ }
+
+ /* file system must be absolute */
+
+ if (*a_inheritedFileSystem != '/') {
+ _z_program_error(ERR_INHERITED_PATH_NOT_ABSOLUTE,
+ a_inheritedFileSystem);
+ return (B_FALSE);
+ }
+
+ /* make a local copy of the path and canonize it */
+
+ n = strlcpy(rp, a_inheritedFileSystem, IPMAX);
+ if (n > IPMAX) {
+ _z_program_error(ERR_INHERITED_PATH_TOO_LONG,
+ strlen(a_inheritedFileSystem), IPMAX,
+ a_inheritedFileSystem);
+ return (B_FALSE);
+ }
+
+ assert(n > 0); /* path must have at least 1 byte in it */
+
+ z_path_canonize(rp); /* remove duplicate "/"s, ./, etc */
+
+ /* add trailing "/" if it's not already there */
+ n = strlen(rp);
+ if (rp[n-1] != '/') {
+ rp[n++] = '/';
+ }
+
+ /* null terminate the string */
+
+ rp[n] = '\0';
+
+ /* add file system to internal list */
+
+ if (inheritedFileSystems == (char **)NULL) {
+ inheritedFileSystems = (char **)_z_calloc(
+ 2 * (sizeof (char **)));
+ inheritedFileSystemsLen =
+ (size_t *)_z_calloc(2 * (sizeof (size_t *)));
+ } else {
+ inheritedFileSystems = (char **)_z_realloc(inheritedFileSystems,
+ sizeof (char **)*(numInheritedFileSystems+2));
+ inheritedFileSystemsLen = (size_t *)_z_realloc(
+ inheritedFileSystemsLen,
+ sizeof (size_t *)*(numInheritedFileSystems+2));
+ }
+
+ /* add this entry to the end of the list */
+
+ inheritedFileSystemsLen[numInheritedFileSystems] = strlen(rp);
+ inheritedFileSystems[numInheritedFileSystems] = _z_strdup(rp);
+
+ numInheritedFileSystems++;
+
+ /* make sure end of the list is properly terminated */
+
+ inheritedFileSystemsLen[numInheritedFileSystems] = 0;
+ inheritedFileSystems[numInheritedFileSystems] = (char *)NULL;
+
+ /* exit debugging info */
+
+ _z_echoDebug(DBG_PATHS_ADD_FS, numInheritedFileSystems,
+ inheritedFileSystems[numInheritedFileSystems-1]);
+
+ return (B_TRUE);
+}
+
+/*
+ * Name: z_path_is_inherited
+ * Description: Determine if the specified path is in a file system that is
+ * in the internal list of inherited file systems
+ * Arguments: a_path - pointer to string representing path to verify
+ * a_ftype - file "type" if known otherwise '\0'
+ * Type can be "f" (file), or "d" (directory)
+ * a_rootDir - pointer to string representing root directory where
+ * a_path is relative to - typically this would either be
+ * "/" or the path specified as an alternative root to -R
+ * Returns: boolean_t
+ * B_TRUE - the path is in inherited file system space
+ * B_FALSE - the path is NOT in inherited file system space
+ */
+
+boolean_t
+z_path_is_inherited(char *a_path, char a_ftype, char *a_rootDir)
+{
+ int n;
+
+ /* entry assertions */
+
+ assert(a_path != (char *)NULL);
+ assert(*a_path != '\0');
+
+ /* if no inherited file systems, there can be no match */
+
+ if (numInheritedFileSystems == 0) {
+ _z_echoDebug(DBG_PATHS_NOT_INHERITED, a_path);
+ return (B_FALSE);
+ }
+
+ /* normalize root directory */
+
+ if ((a_rootDir == (char *)NULL) || (*a_rootDir == '\0')) {
+ a_rootDir = "/";
+ }
+
+ /*
+ * if a_path resides on an inherited filesystem then
+ * it must be read-only.
+ */
+
+ if (z_isPathWritable(a_path) != 0) {
+ return (B_FALSE);
+ }
+
+ /*
+ * remove the root path from the target path before comparing:
+ * Example 1:
+ * -- path is "/export/zone1/root/usr/test"
+ * -- root path is "/export/zone1/root"
+ * --- final path should be "/usr/test"
+ * Example 2:
+ * -- path is "/usr/test"
+ * -- root path is "/"
+ * --- final path should be "/usr/test"
+ */
+
+ /* advance past given root directory if path begins with it */
+
+ n = strlen(a_rootDir);
+ if (strncmp(a_rootDir, a_path, n) == 0) {
+ char *p;
+
+ /* advance past the root path */
+
+ p = a_path + n;
+
+ /* go back to the first occurance of the path separator */
+
+ while ((*p != '/') && (p > a_path)) {
+ p--;
+ }
+
+ /* use this location in the path to compare */
+
+ a_path = p;
+ }
+
+ /*
+ * see if this path is in any inherited file system path
+ * note that all paths in the inherited list are directories
+ * so they end in "/" to prevent a partial match, such as
+ * comparing "/usr/libx" with "/usr/lib" - by making the comparison
+ * "/usr/libx" with "/usr/lib/" the partial false positive will not
+ * occur. This complicates matters when the object to compare is a
+ * directory - in this case, comparing "/usr" with "/usr/" will fail,
+ * so if the object is a directory, compare one less byte from the
+ * inherited file system so that the trailing "/" is ignored.
+ */
+
+ for (n = 0; n < numInheritedFileSystems; n++) {
+ int fslen;
+
+ /* get target fs len; adjust -1 if directory */
+
+ fslen = inheritedFileSystemsLen[n];
+ if ((a_ftype == 'd') && (fslen > 1)) {
+ fslen--;
+ }
+
+ if (strncmp(a_path, inheritedFileSystems[n], fslen) == 0) {
+ _z_echoDebug(DBG_PATHS_IS_INHERITED, a_path,
+ inheritedFileSystems[n]);
+ return (B_TRUE);
+ }
+ }
+
+ /* path is not in inherited file system space */
+
+ _z_echoDebug(DBG_PATHS_IS_NOT_INHERITED, a_path, a_rootDir);
+
+ return (B_FALSE);
+}
+
+/*
+ * Name: z_make_zone_root
+ * Description: Given its zonepath, generate a string representing the
+ * mountpoint of where the root path for a nonglobal zone is
+ * mounted. The zone is mounted using 'zoneadm', which mounts
+ * the zone's filesystems wrt <zonepath>/lu/a
+ * Arguments: zone_path - non-NULL pointer to string representing zonepath
+ * Returns: char * - pointer to string representing zonepath of zone
+ * NULL - if zone_path is NULL.
+ * Notes: The string returned is in static storage and should not be
+ * free()ed by the caller.
+ */
+char *
+z_make_zone_root(char *zone_path)
+{
+ static char zone_root_buf[MAXPATHLEN];
+
+ if (zone_path == NULL)
+ return (NULL);
+
+ (void) snprintf(zone_root_buf, MAXPATHLEN, "%s%slu/a", zone_path,
+ (zone_path[0] != '\0' &&
+ zone_path[strlen(zone_path) - 1] == '/') ? "" : "/");
+
+ return (zone_root_buf);
+}
+
+void
+z_path_canonize(char *a_file)
+{
+ char *pt;
+ char *last;
+ int level;
+
+ /* remove references such as "./" and "../" and "//" */
+ for (pt = a_file; *pt; /* void */) {
+ if (isdot(pt)) {
+ (void) strcpy(pt, pt[1] ? pt+2 : pt+1);
+ } else if (isdotdot(pt)) {
+ level = 0;
+ last = pt;
+ do {
+ level++;
+ last += 2;
+ if (*last) {
+ last++;
+ }
+ } while (isdotdot(last));
+ --pt; /* point to previous '/' */
+ while (level--) {
+ if (pt <= a_file) {
+ return;
+ }
+ while ((*--pt != '/') && (pt > a_file))
+ ;
+ }
+ if (*pt == '/') {
+ pt++;
+ }
+ (void) strcpy(pt, last);
+ } else {
+ while (*pt && (*pt != '/')) {
+ pt++;
+ }
+ if (*pt == '/') {
+ while (pt[1] == '/') {
+ (void) strcpy(pt, pt+1);
+ }
+ pt++;
+ }
+ }
+ }
+
+ if ((--pt > a_file) && (*pt == '/')) {
+ *pt = '\0';
+ }
+}
+
+void
+z_canoninplace(char *src)
+{
+ char *dst;
+ char *src_start;
+
+ /* keep a ptr to the beginning of the src string */
+ src_start = src;
+
+ dst = src;
+ while (*src) {
+ if (*src == '/') {
+ *dst++ = '/';
+ while (*src == '/')
+ src++;
+ } else
+ *dst++ = *src++;
+ }
+
+ /*
+ * remove any trailing slashes, unless the whole string is just "/".
+ * If the whole string is "/" (i.e. if the last '/' cahr in dst
+ * in the beginning of the original string), just terminate it
+ * and return "/".
+ */
+ if ((*(dst - 1) == '/') && ((dst - 1) != src_start))
+ dst--;
+ *dst = '\0';
+}
+
+void
+z_free_inherited_file_systems(void)
+{
+ int i;
+
+ for (i = 0; i < numInheritedFileSystems; i++) {
+ free(inheritedFileSystems[i]);
+ }
+ free(inheritedFileSystems);
+ inheritedFileSystems = NULL;
+ free(inheritedFileSystemsLen);
+ inheritedFileSystemsLen = NULL;
+ numInheritedFileSystems = 0;
+}
diff --git a/usr/src/lib/libinstzones/common/zones_states.c b/usr/src/lib/libinstzones/common/zones_states.c
new file mode 100644
index 0000000000..914af2075c
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones_states.c
@@ -0,0 +1,585 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * Module: zones_states.c
+ * Group: libinstzones
+ * Description: Provide "zones" state interfaces for install consolidation code
+ *
+ * Public Methods:
+ *
+ * z_make_zone_running - change state of non-global zone to "running"
+ * _z_make_zone_ready - change state of non-global zone to "ready"
+ * _z_make_zone_down - change state of non-global zone to "down"
+ */
+
+/*
+ * System includes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.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
+ */
+
+/*
+ * global internal (private) declarations
+ */
+
+/*
+ * *****************************************************************************
+ * global external (public) functions
+ * *****************************************************************************
+ */
+
+/*
+ * Name: _z_make_zone_running
+ * Description: Given a zone element entry for the non-global zone to affect,
+ * change the state of that non-global zone to "running"
+ * Arguments: a_zlem - [RO, *RW] - (zoneListElement_t)
+ * Zone list element describing the non-global zone to
+ * make running
+ * Returns: boolean_t
+ * B_TRUE - non-global zone state changed successfully
+ * B_FALSE - failed to make the non-global zone run
+ */
+
+boolean_t
+_z_make_zone_running(zoneListElement_t *a_zlem)
+{
+ FILE *fp;
+ argArray_t *args;
+ char zonename[ZONENAME_MAX];
+ char *results = (char *)NULL;
+ int ret;
+ int status = 0;
+
+ /* entry assertions */
+
+ assert(a_zlem != NULL);
+
+ /* act based on the zone's current kernel state */
+
+ switch (a_zlem->_zlCurrKernelStatus) {
+ case ZONE_STATE_RUNNING:
+ case ZONE_STATE_MOUNTED:
+ /* already running */
+ return (B_TRUE);
+
+ case ZONE_STATE_READY:
+ /* This should never happen */
+ if (zonecfg_in_alt_root())
+ return (B_FALSE);
+
+ /*
+ * We're going to upset the zone anyway, so might as well just
+ * halt it now and fall through to normal mounting.
+ */
+
+ _z_echoDebug(DBG_TO_ZONEHALT, a_zlem->_zlName);
+
+ args = _z_new_args(5); /* generate new arg list */
+ (void) _z_add_arg(args, ZONEADM_CMD);
+ (void) _z_add_arg(args, "-z");
+ (void) _z_add_arg(args, a_zlem->_zlName);
+ (void) _z_add_arg(args, "halt");
+
+ ret = z_ExecCmdArray(&status, &results, (char *)NULL,
+ ZONEADM_CMD, _z_get_argv(args));
+
+ /* free generated argument list */
+
+ _z_free_args(args);
+
+ if (ret != 0) {
+ _z_program_error(ERR_ZONEHALT_EXEC, ZONEADM_CMD,
+ strerror(errno));
+ free(results);
+ return (B_FALSE);
+ }
+ if (status != 0) {
+ if (status == -1) {
+ _z_program_error(ERR_ZONEBOOT_CMD_SIGNAL,
+ ZONEADM_CMD, a_zlem->_zlName);
+ } else {
+ _z_program_error(ERR_ZONEBOOT_CMD_ERROR,
+ ZONEADM_CMD, a_zlem->_zlName, status,
+ results == NULL ? "" : "\n",
+ results == NULL ? "" : results);
+ }
+ free(results);
+ return (B_FALSE);
+ }
+
+ free(results);
+
+ a_zlem->_zlCurrKernelStatus = ZONE_STATE_INSTALLED;
+ /* FALLTHROUGH */
+
+ case ZONE_STATE_INSTALLED:
+ case ZONE_STATE_DOWN:
+ /* return false if the zone cannot be booted */
+
+ if (a_zlem->_zlStatus & ZST_NOT_BOOTABLE) {
+ return (B_FALSE);
+ }
+
+ _z_echoDebug(DBG_TO_ZONERUNNING, a_zlem->_zlName);
+
+ /* these states can be booted - do so */
+
+ args = _z_new_args(10); /* generate new arg list */
+ (void) _z_add_arg(args, ZONEADM_CMD);
+ if (zonecfg_in_alt_root()) {
+ (void) _z_add_arg(args, "-R");
+ (void) _z_add_arg(args, "%s",
+ (char *)zonecfg_get_root());
+ }
+
+ (void) _z_add_arg(args, "-z");
+ (void) _z_add_arg(args, "%s", a_zlem->_zlName);
+ (void) _z_add_arg(args, "mount");
+
+ ret = z_ExecCmdArray(&status, &results, (char *)NULL,
+ ZONEADM_CMD, _z_get_argv(args));
+
+ /* free generated argument list */
+
+ _z_free_args(args);
+
+ if (ret != 0) {
+ _z_program_error(ERR_ZONEBOOT_EXEC, ZONEADM_CMD,
+ strerror(errno));
+ free(results);
+ return (B_FALSE);
+ }
+
+ if (status != 0) {
+ if (status == -1) {
+ _z_program_error(ERR_ZONEBOOT_CMD_SIGNAL,
+ ZONEADM_CMD, a_zlem->_zlName);
+ } else {
+ _z_program_error(ERR_ZONEBOOT_CMD_ERROR,
+ ZONEADM_CMD, a_zlem->_zlName, status,
+ results == NULL ? "" : "\n",
+ results == NULL ? "" : results);
+ }
+ free(results);
+
+ /* remember this zone cannot be booted */
+
+ a_zlem->_zlStatus |= ZST_NOT_BOOTABLE;
+
+ return (B_FALSE);
+ }
+ free(results);
+
+ if (zonecfg_in_alt_root()) {
+ if ((fp = zonecfg_open_scratch("", B_FALSE)) == NULL ||
+ zonecfg_find_scratch(fp, a_zlem->_zlName,
+ zonecfg_get_root(), zonename,
+ sizeof (zonename)) == -1) {
+ _z_program_error(ERR_ZONEBOOT_DIDNT_BOOT,
+ a_zlem->_zlName);
+ if (fp != NULL)
+ zonecfg_close_scratch(fp);
+ return (B_FALSE);
+ }
+ zonecfg_close_scratch(fp);
+ free(a_zlem->_zlScratchName);
+ a_zlem->_zlScratchName = _z_strdup(zonename);
+ }
+ a_zlem->_zlCurrKernelStatus = ZONE_STATE_MOUNTED;
+ return (B_TRUE);
+
+ case ZONE_STATE_CONFIGURED:
+ case ZONE_STATE_INCOMPLETE:
+ case ZONE_STATE_SHUTTING_DOWN:
+ default:
+ /* cannot transition (boot) these states */
+ return (B_FALSE);
+ }
+}
+
+/*
+ * Name: _z_make_zone_ready
+ * Description: Given a zone element entry for the non-global zone to affect,
+ * restore the ready state of the zone when the zone is currently
+ * in the running state.
+ * Arguments: a_zlem - [RO, *RW] - (zoneListElement_t)
+ * Zone list element describing the non-global zone to
+ * make ready
+ * Returns: boolean_t
+ * B_TRUE - non-global zone state changed successfully
+ * B_FALSE - failed to make the non-global zone ready
+ */
+
+boolean_t
+_z_make_zone_ready(zoneListElement_t *a_zlem)
+{
+ argArray_t *args;
+ char *results = (char *)NULL;
+ int status = 0;
+ int i;
+ int ret;
+ zone_state_t st;
+
+ /* entry assertions */
+
+ assert(a_zlem != (zoneListElement_t *)NULL);
+
+ /* act based on the zone's current kernel state */
+
+ switch (a_zlem->_zlCurrKernelStatus) {
+ case ZONE_STATE_DOWN:
+ case ZONE_STATE_READY:
+ /* already down */
+ return (B_TRUE);
+
+ case ZONE_STATE_MOUNTED:
+ _z_echoDebug(DBG_TO_ZONEUNMOUNT, a_zlem->_zlName);
+
+ args = _z_new_args(10); /* generate new arg list */
+ (void) _z_add_arg(args, ZONEADM_CMD);
+ (void) _z_add_arg(args, "-z");
+ (void) _z_add_arg(args, "%s", a_zlem->_zlName);
+ (void) _z_add_arg(args, "unmount");
+ ret = z_ExecCmdArray(&status, &results, NULL,
+ ZONEADM_CMD, _z_get_argv(args));
+ if (ret != 0) {
+ _z_program_error(ERR_ZONEUNMOUNT_EXEC,
+ ZONEADM_CMD, strerror(errno));
+ free(results);
+ _z_free_args(args);
+ return (B_FALSE);
+ }
+ if (status != 0) {
+ if (status == -1) {
+ _z_program_error(ERR_ZONEUNMOUNT_CMD_SIGNAL,
+ ZONEADM_CMD, a_zlem->_zlName);
+ } else {
+ _z_program_error(ERR_ZONEUNMOUNT_CMD_ERROR,
+ ZONEADM_CMD, a_zlem->_zlName, status,
+ results == NULL ? "" : "\n",
+ results == NULL ? "" : results);
+ }
+ if (results != NULL) {
+ free(results);
+ }
+ _z_free_args(args);
+ return (B_FALSE);
+ }
+ if (results != NULL) {
+ free(results);
+ }
+ _z_free_args(args);
+ a_zlem->_zlCurrKernelStatus = ZONE_STATE_INSTALLED;
+ _z_echoDebug(DBG_TO_ZONEREADY, a_zlem->_zlName);
+
+ args = _z_new_args(10); /* generate new arg list */
+ (void) _z_add_arg(args, ZONEADM_CMD);
+ (void) _z_add_arg(args, "-z");
+ (void) _z_add_arg(args, "%s", a_zlem->_zlName);
+ (void) _z_add_arg(args, "ready");
+
+ ret = z_ExecCmdArray(&status, &results, NULL,
+ ZONEADM_CMD, _z_get_argv(args));
+ if (ret != 0) {
+ _z_program_error(ERR_ZONEREADY_EXEC, ZONEADM_CMD,
+ strerror(errno));
+ free(results);
+ _z_free_args(args);
+ return (B_FALSE);
+ }
+ if (status != 0) {
+ _z_program_error(ERR_ZONEREADY_CMDFAIL, ZONEADM_CMD,
+ a_zlem->_zlName, strerror(errno),
+ results == NULL ? "" : "\n",
+ results == NULL ? "" : results);
+ if (results != NULL) {
+ free(results);
+ }
+ _z_free_args(args);
+ return (B_FALSE);
+ }
+ if (results != NULL) {
+ free(results);
+ }
+ /* success - zone is now in the ready state */
+ a_zlem->_zlCurrKernelStatus = ZONE_STATE_READY;
+ return (B_TRUE);
+
+ case ZONE_STATE_RUNNING:
+
+ _z_echoDebug(DBG_TO_ZONEREADY, a_zlem->_zlName);
+
+ args = _z_new_args(10); /* generate new arg list */
+ (void) _z_add_arg(args, ZONEADM_CMD);
+ (void) _z_add_arg(args, "-z");
+ (void) _z_add_arg(args, "%s", a_zlem->_zlName);
+ (void) _z_add_arg(args, "ready");
+
+ ret = z_ExecCmdArray(&status, &results, (char *)NULL,
+ ZONEADM_CMD, _z_get_argv(args));
+
+ /* free generated argument list */
+
+ _z_free_args(args);
+
+ if (ret != 0) {
+ _z_program_error(ERR_ZONEREADY_EXEC, ZONEADM_CMD,
+ strerror(errno));
+ free(results);
+ _z_free_args(args);
+ return (B_FALSE);
+ }
+ if (status != 0) {
+ _z_program_error(ERR_ZONEREADY_CMDFAIL, ZONEADM_CMD,
+ a_zlem->_zlName, strerror(errno),
+ results == (char *)NULL ? "" : "\n",
+ results == (char *)NULL ? "" : results);
+ if (results != (char *)NULL) {
+ (void) free(results);
+ }
+ return (B_FALSE);
+ }
+
+ if (results != (char *)NULL) {
+ (void) free(results);
+ }
+
+ for (i = 0; i < MAX_RETRIES; i++) {
+ if (zone_get_state(a_zlem->_zlName, &st) != Z_OK) {
+ break;
+ }
+ if ((st == ZONE_STATE_DOWN) ||
+ (st == ZONE_STATE_INSTALLED)||
+ (st == ZONE_STATE_READY)) {
+ break;
+ }
+ (void) sleep(RETRY_DELAY_SECS);
+ }
+
+ /* failure if maximum retries reached */
+
+ if (i >= MAX_RETRIES) {
+ _z_program_error(ERR_ZONEREADY_DIDNT_READY,
+ a_zlem->_zlName);
+ a_zlem->_zlCurrKernelStatus = st;
+ return (B_FALSE);
+ }
+
+ /* success - zone is now in the ready state */
+
+ a_zlem->_zlCurrKernelStatus = ZONE_STATE_READY;
+
+ return (B_TRUE);
+
+ case ZONE_STATE_INSTALLED:
+ case ZONE_STATE_CONFIGURED:
+ case ZONE_STATE_INCOMPLETE:
+ case ZONE_STATE_SHUTTING_DOWN:
+ default:
+ return (B_FALSE);
+ }
+}
+
+/*
+ * Name: _z_make_zone_down
+ * Description: Given a zone element entry for the non-global zone to affect,
+ * change the state of that non-global zone to "down"
+ * Arguments: a_zlem - [RO, *RW] - (zoneListElement_t)
+ * Zone list element describing the non-global zone to
+ * make down
+ * Returns: boolean_t
+ * B_TRUE - non-global zone state changed successfully
+ * B_FALSE - failed to make the non-global zone down
+ */
+
+boolean_t
+_z_make_zone_down(zoneListElement_t *a_zlem)
+{
+ argArray_t *args;
+ char *results = (char *)NULL;
+ int status = 0;
+ int ret;
+
+ /* entry assertions */
+
+ assert(a_zlem != NULL);
+
+ /* act based on the zone's current kernel state */
+
+ switch (a_zlem->_zlCurrKernelStatus) {
+ case ZONE_STATE_DOWN:
+ case ZONE_STATE_READY:
+ case ZONE_STATE_RUNNING:
+ /* shouldn't be touched */
+ return (B_TRUE);
+
+ case ZONE_STATE_MOUNTED:
+
+ _z_echoDebug(DBG_TO_ZONEHALT, a_zlem->_zlName);
+
+ /* these states can be halted - do so */
+
+ args = _z_new_args(10); /* generate new arg list */
+ (void) _z_add_arg(args, ZONEADM_CMD);
+
+ if (zonecfg_in_alt_root()) {
+ (void) _z_add_arg(args, "-R");
+ (void) _z_add_arg(args, "%s",
+ (char *)zonecfg_get_root());
+ }
+
+ (void) _z_add_arg(args, "-z");
+ (void) _z_add_arg(args, "%s", a_zlem->_zlName);
+ (void) _z_add_arg(args, "unmount");
+
+ ret = z_ExecCmdArray(&status, &results, (char *)NULL,
+ ZONEADM_CMD, _z_get_argv(args));
+
+ /* free generated argument list */
+
+ _z_free_args(args);
+
+ if (ret != 0) {
+ _z_program_error(ERR_ZONEHALT_EXEC, ZONEADM_CMD,
+ strerror(errno));
+ free(results);
+ return (B_FALSE);
+ }
+ if (status != 0) {
+ if (status == -1) {
+ _z_program_error(ERR_ZONEBOOT_CMD_SIGNAL,
+ ZONEADM_CMD, a_zlem->_zlName);
+ } else {
+ _z_program_error(ERR_ZONEBOOT_CMD_ERROR,
+ ZONEADM_CMD, a_zlem->_zlName, status,
+ results == NULL ? "" : "\n",
+ results == NULL ? "" : results);
+ }
+ free(results);
+ return (B_FALSE);
+ }
+
+ free(results);
+
+ a_zlem->_zlCurrKernelStatus = ZONE_STATE_INSTALLED;
+ /*
+ * Leave the scratch name in place because the upper level
+ * software may have used it to construct file names and the
+ * like.
+ */
+ return (B_TRUE);
+
+ case ZONE_STATE_INSTALLED:
+ case ZONE_STATE_CONFIGURED:
+ case ZONE_STATE_INCOMPLETE:
+ case ZONE_STATE_SHUTTING_DOWN:
+ default:
+ return (B_FALSE);
+ }
+}
+
+/*
+ * Function: UmountAllZones
+ * Description: Unmount all mounted zones under a specified directory.
+ *
+ * Scope: public
+ * Parameters: mntpnt [RO, *RO]
+ * Non-NULL pointer to name of directory to be unmounted.
+ * Return: 0 - successfull
+ * -1 - unmount failed; see errno for reason
+ */
+int
+UmountAllZones(char *mntpnt) {
+
+ zoneList_t zlst;
+ int k;
+ int ret = 0;
+
+ if (z_zones_are_implemented()) {
+
+ z_set_zone_root(mntpnt);
+
+ zlst = z_get_nonglobal_zone_list();
+ if (zlst == (zoneList_t)NULL) {
+ return (0);
+ }
+
+ for (k = 0; z_zlist_get_zonename(zlst, k) != (char *)NULL;
+ k++) {
+ if (z_zlist_get_current_state(zlst, k) >
+ ZONE_STATE_INSTALLED) {
+ if (!z_zlist_change_zone_state(zlst, k,
+ ZONE_STATE_INSTALLED)) {
+ ret = -1;
+ break;
+ }
+ }
+ }
+
+ /* Free zlst */
+ z_free_zone_list(zlst);
+ }
+
+ return (ret);
+
+}
diff --git a/usr/src/lib/libinstzones/common/zones_str.c b/usr/src/lib/libinstzones/common/zones_str.c
new file mode 100644
index 0000000000..bc79f0665c
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones_str.c
@@ -0,0 +1,711 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+/*
+ * Module: zones_str.c
+ * Group: libinstzones
+ * Description: Private functions used by zones library functions to manipulate
+ * strings
+ *
+ * Public Methods:
+ *
+ * _z_strAddToken - Add a token to a string
+ * _z_strContainsToken - Does a given string contain a specified substring
+ * _z_strGetToken - Get a separator delimited token from a string
+ * _z_strGetToken_r - Get separator delimited token from string to fixed buffer
+ * _z_strPrintf - Create string from printf style format and arguments
+ * _z_strPrintf_r - Create string from printf style format and arguments
+ * _z_strRemoveLeadingWhitespace - Remove leading whitespace from string
+ * _z_strRemoveToken - Remove a token from a string
+ */
+
+/*
+ * System includes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <strings.h>
+#include <stdarg.h>
+#include <limits.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
+ */
+
+/*
+ * Global internal (private) declarations
+ */
+
+/*
+ * *****************************************************************************
+ * global external (public) functions
+ * *****************************************************************************
+ */
+
+/*
+ * Name: _z_strAddToken
+ * Synopsis: Add a token to a string
+ * Description: Append a token (sequence of one or more characters) to a
+ * string that is in allocated space - create new string if
+ * no string to append to exists
+ * Arguments: a_old - [RO, *RW] - (char **)
+ * - Pointer to handle to string to append token to
+ * == NULL - new string is created
+ * a_new - [RO, *RO] - (char *)
+ * - Pointer to string representing token to append
+ * to the end of the "a_old" string
+ * == NULL - no action is performed
+ * a_new[0] == '\0' - no action is performed
+ * a_separator - [RO, *RO] - (char)
+ * - One character placed between the old (existing)
+ * string and the new token to be added IF the old
+ * string exists and is not empty (zero length)
+ * Returns: void
+ * CAUTION: The old (existing) string must be allocated space (via lu_mem*
+ * or _z_str* methods) - it must not be a static or inline
+ * character string
+ * NOTE: The old (existing) string may be freed with 'free'
+ * if a token is appended to it
+ * NOTE: Any string returned in 'a_old' is placed in new storage for the
+ * calling method. The caller must use 'free' to dispose
+ * of the storage once the token string is no longer needed.
+ */
+
+void
+_z_strAddToken(char **a_old, char *a_new, char a_separator)
+{
+ /* entry assertions */
+
+ assert(a_old != NULL);
+ assert(a_separator != '\0');
+
+ /* if token to add is null or token is zero length, just return */
+
+ if (a_new == NULL || *a_new == '\0') {
+ return;
+ }
+
+ /* make sure that new token does not contain the separator */
+
+ assert(strchr(a_new, (int)a_separator) == NULL);
+
+ /* if old string is empty (zero length), deallocate */
+
+ if ((*a_old != NULL) && ((*a_old)[0] == '\0')) {
+ /* *a_old is set to NULL by free */
+ free(*a_old);
+ *a_old = NULL;
+ }
+
+ /* if old string exists, append separator and token */
+
+ if (*a_old != NULL) {
+ char *p;
+ p = _z_strPrintf("%s%c%s", *a_old, a_separator, a_new);
+ free(*a_old);
+ *a_old = p;
+ return;
+ }
+
+ /* old string does not exist - return duplicate of token */
+
+ assert(*a_old == NULL);
+ *a_old = _z_strdup(a_new);
+}
+
+/*
+ * Name: _z_strContainsToken
+ * Synopsis: Does a given string contain a specified substring
+ * Description: Determine if a given substring exists in a larger string
+ * Arguments: a_string - [RO, *RO] - (char *)
+ * Pointer to string to look for substring in
+ * a_token - [RO, *RO] - (char *)
+ * Pointer to substring to look for in larger string
+ * Results: boolean_t
+ * B_TRUE - substring exists in larger string
+ * B_FALSE - substring does NOT exist in larger string
+ * NOTE: The substring must match on a "token" basis; that is, the
+ * substring must exist in the larger string delineated with
+ * either spaces or tabs to match.
+ */
+
+boolean_t
+_z_strContainsToken(char *a_string, char *a_token, char *a_separators)
+{
+ char *lasts;
+ char *current;
+ char *p;
+
+ /* entry assertions */
+
+ assert(a_separators != NULL);
+ assert(*a_separators != '\0');
+
+ /*
+ * if token is not supplied, no string provided,
+ * or the string is an empty string, return false
+ */
+
+ if (a_token == NULL || a_string == NULL || *a_string == '\0') {
+ return (B_FALSE);
+ }
+
+ /* if no string provided, return false */
+
+ /* if string empty (zero length), return false */
+
+ /* duplicate larger string because strtok_r changes it */
+
+ p = _z_strdup(a_string);
+
+ lasts = p;
+
+ /* scan each token looking for a match */
+
+ while ((current = strtok_r(NULL, a_separators, &lasts)) !=
+ NULL) {
+ if (strcmp(current, a_token) == 0) {
+ free(p);
+ return (B_TRUE);
+ }
+ }
+
+ /* free up temporary storage */
+
+ free(p);
+
+ /* not found */
+
+ return (B_FALSE);
+}
+
+/*
+ * Name: _z_strGetToken
+ * Synopsis: Get a separator delimited token from a string
+ * Description: Given a string and a list of one or more separators,
+ * return the position specified token (sequence of one or
+ * more characters that do not include any of the separators)
+ * Arguments: r_sep - [*RW] - (char *)
+ * - separator that ended the token returned
+ * - NOTE: this is a pointer to a "char", e.g.:
+ * - char a;
+ * - _z_strGetToken(&a, ...)
+ * a_string - [RO, *RO] - (char *)
+ * - pointer to string to extract token from
+ * a_index - [RO, *RO] - (int)
+ * - Index of token to return; '0' is first matching
+ * token, '1' is second matching token, etc.
+ * a_separators - [RO, *RO] - (char *)
+ * - String containing one or more characters that
+ * can separate one "token" from another
+ * Returns: char *
+ * == NULL - no token matching criteria found
+ * != NULL - token matching criteria
+ * NOTE: Any token string returned is placed in new storage for the
+ * calling method. The caller must use 'free' to dispose
+ * of the storage once the token string is no longer needed.
+ */
+
+char *
+_z_strGetToken(char *r_sep, char *a_string, int a_index, char *a_separators)
+{
+ char *p;
+ char *q;
+ char *lasts;
+
+ /* entry assertions */
+
+ assert(a_string != NULL);
+ assert(a_index >= 0);
+ assert(a_separators != NULL);
+ assert(*a_separators != '\0');
+
+ /* if returned separator requested, reset to null until token found */
+
+ if (r_sep != NULL) {
+ *r_sep = '\0';
+ }
+
+ /* duplicate original string before breaking down into tokens */
+
+ p = _z_strdup(a_string);
+
+ lasts = p;
+
+ /* scan for separators and return 'index'th token found */
+
+ while (q = strtok_r(NULL, a_separators, &lasts)) {
+ /* retrieve separator if requested */
+
+ if (r_sep != NULL) {
+ char *x;
+
+ x = strpbrk(a_string, a_separators);
+ if (x != NULL) {
+ *r_sep = *x;
+ }
+ }
+
+ /* if this is the 'index'th token requested return it */
+
+ if (a_index-- == 0) {
+ char *tmp;
+
+ /* duplicate token into its own storage */
+
+ tmp = _z_strdup(q);
+
+ /* free up copy of original input string */
+
+ free(p);
+
+ /* return token found */
+
+ return (tmp);
+ }
+ }
+
+ /*
+ * token not found
+ */
+
+ /* free up copy of original input string */
+
+ free(p);
+
+ /* return NULL pointer (token not found) */
+
+ return (NULL);
+}
+
+/*
+ * Name: _z_strGetToken_r
+ * Synopsis: Get separator delimited token from a string into a fixed buffer
+ * Description: Given a string and a list of one or more separators,
+ * return the position specified token (sequence of one or
+ * more characters that do not include any of the separators)
+ * into a specified buffer of a fixed maximum size
+ * Arguments: r_sep - [*RW] - (char *)
+ * - separator that ended the token returned
+ * - NOTE: this is a pointer to a "char", e.g.:
+ * - char a;
+ * - _z_strGetToken(&a, ...)
+ * a_string - [RO, *RO] - (char *)
+ * - pointer to string to extract token from
+ * a_index - [RO, *RO] - (int)
+ * - Index of token to return; '0' is first matching
+ * token, '1' is second matching token, etc.
+ * a_separators - [RO, *RO] - (char *)
+ * - String containing one or more characters that
+ * can separate one "token" from another
+ * a_buf - [RO, *RW] - (char *)
+ * - Pointer to buffer used as storage space for the
+ * returned token - the returned token is always
+ * null terminated
+ * a_buf[0] == '\0' - no token meeting criteria found
+ * a_buf[0] != '\0' - token meeting criteria returned
+ * a_bufLen - [RO, *RO] - (int)
+ * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1'
+ * bytes will be placed in 'a_buf' - the returned
+ * token is always null terminated
+ * Returns: void
+ */
+
+void
+_z_strGetToken_r(char *r_sep, char *a_string, int a_index,
+ char *a_separators, char *a_buf, int a_bufLen)
+{
+ char *p;
+ char *q;
+ char *lasts;
+
+ /* entry assertions */
+
+ assert(a_string != NULL);
+ assert(a_index >= 0);
+ assert(a_separators != NULL);
+ assert(*a_separators != '\0');
+ assert(a_buf != NULL);
+ assert(a_bufLen > 0);
+
+ /* reset returned separator */
+
+ if (r_sep != NULL) {
+ *r_sep = '\0';
+ }
+
+ /* zero out contents of return buffer */
+
+ bzero(a_buf, a_bufLen);
+
+ /* duplicate original string before breaking down into tokens */
+
+ p = _z_strdup(a_string);
+
+ lasts = p;
+
+ /* scan for separators and return 'index'th token found */
+
+ while (q = strtok_r(NULL, a_separators, &lasts)) {
+ /* retrieve separator if requested */
+
+ if (r_sep != NULL) {
+ char *x;
+ x = strpbrk(a_string, a_separators);
+ if (x != NULL) {
+ *r_sep = *x;
+ }
+ }
+
+ /* if this is the 'index'th token requested return it */
+
+ if (a_index-- == 0) {
+ /* copy as many characters as possible to return buf */
+
+ (void) strncpy(a_buf, q, a_bufLen-1);
+ break;
+ }
+ }
+
+ /* free up copy of original input string */
+
+ free(p);
+}
+
+/*
+ * Name: _z_strPrintf
+ * Synopsis: Create string from printf style format and arguments
+ * Description: Call to convert a printf style format and arguments into a
+ * string of characters placed in allocated storage
+ * Arguments: format - [RO, RO*] (char *)
+ * printf-style format for string to be formatted
+ * VARG_LIST - [RO] (?)
+ * arguments as appropriate to 'format' specified
+ * Returns: char *
+ * A string representing the printf conversion results
+ * NOTE: Any string returned is placed in new storage for the
+ * calling method. The caller must use 'free' to dispose
+ * of the storage once the string is no longer needed.
+ * Errors: If the string cannot be created, the process exits
+ */
+
+/*PRINTFLIKE1*/
+char *
+_z_strPrintf(char *a_format, ...)
+{
+ va_list ap;
+ size_t vres = 0;
+ char bfr[1];
+ char *rstr = NULL;
+
+ /* entry assertions */
+
+ assert(a_format != NULL);
+ assert(*a_format != '\0');
+
+ /* determine size of the message in bytes */
+
+ va_start(ap, a_format);
+ vres = vsnprintf(bfr, 1, a_format, ap);
+ va_end(ap);
+
+ assert(vres > 0);
+ assert(vres < LINE_MAX);
+
+ /* allocate storage to hold the message */
+
+ rstr = (char *)_z_calloc(vres+2);
+
+ /* generate the results of the printf conversion */
+
+ va_start(ap, a_format);
+ vres = vsnprintf(rstr, vres+1, a_format, ap);
+ va_end(ap);
+
+ assert(vres > 0);
+ assert(vres < LINE_MAX);
+ assert(*rstr != '\0');
+
+ /* return the results */
+
+ return (rstr);
+}
+
+/*
+ * Name: _z_strPrintf_r
+ * Synopsis: Create string from printf style format and arguments
+ * Description: Call to convert a printf style format and arguments into a
+ * string of characters placed in allocated storage
+ * Arguments: a_buf - [RO, *RW] - (char *)
+ * - Pointer to buffer used as storage space for the
+ * returned string created
+ * a_bufLen - [RO, *RO] - (int)
+ * - Size of 'a_buf' in bytes - a maximum of 'a_bufLen-1'
+ * bytes will be placed in 'a_buf' - the returned
+ * string is always null terminated
+ * a_format - [RO, RO*] (char *)
+ * printf-style format for string to be formatted
+ * VARG_LIST - [RO] (?)
+ * arguments as appropriate to 'format' specified
+ * Returns: void
+ */
+
+/*PRINTFLIKE3*/
+void
+_z_strPrintf_r(char *a_buf, int a_bufLen, char *a_format, ...)
+{
+ va_list ap;
+ size_t vres = 0;
+
+ /* entry assertions */
+
+ assert(a_format != NULL);
+ assert(*a_format != '\0');
+ assert(a_buf != NULL);
+ assert(a_bufLen > 1);
+
+ /* generate the results of the printf conversion */
+
+ va_start(ap, a_format);
+ vres = vsnprintf(a_buf, a_bufLen-1, a_format, ap);
+ va_end(ap);
+
+ assert(vres > 0);
+ assert(vres < a_bufLen);
+
+ a_buf[a_bufLen-1] = '\0';
+}
+
+/*
+ * Name: _z_strRemoveLeadingWhitespace
+ * Synopsis: Remove leading whitespace from string
+ * Description: Remove all leading whitespace characters from a string
+ * Arguments: a_str - [RO, *RW] - (char **)
+ * Pointer to handle to string (in allocated storage) to
+ * remove all leading whitespace from
+ * Returns: void
+ * The input string is modified as follows:
+ * == NULL:
+ * - input string was NULL
+ * - input string is all whitespace
+ * != NULL:
+ * - copy of input string with leading
+ * whitespace removed
+ * CAUTION: The input string must be allocated space (via mem* or
+ * _z_str* methods) - it must not be a static or inline
+ * character string
+ * NOTE: The input string a_str will be freed with 'free'
+ * if it is all whitespace, or if it contains any leading
+ * whitespace characters
+ * NOTE: Any string returned is placed in new storage for the
+ * calling method. The caller must use 'free' to dispose
+ * of the storage once the string is no longer needed.
+ * Errors: If the string cannot be created, the process exits
+ */
+
+void
+_z_strRemoveLeadingWhitespace(char **a_str)
+{
+ char *o_str;
+
+ /* entry assertions */
+
+ assert(a_str != NULL);
+
+ /* if string is null, just return */
+
+ if (*a_str == NULL) {
+ return;
+ }
+ o_str = *a_str;
+
+ /* if string is empty, deallocate and return NULL */
+
+ if (*o_str == '\0') {
+ /* free string - handle is not reset to NULL by free */
+ free(*a_str);
+ *a_str = NULL;
+ return;
+ }
+
+ /* if first character is not a space, just return */
+
+ if (!isspace(*o_str)) {
+ return;
+ }
+
+ /* advance past all space characters */
+
+ while ((*o_str != '\0') && (isspace(*o_str))) {
+ o_str++;
+ }
+
+ /* if string was all space characters, deallocate and return NULL */
+
+ if (*o_str == '\0') {
+ /* free string - *a_str is not reset to NULL by free */
+ free(*a_str);
+ *a_str = NULL;
+ return;
+ }
+
+ /* have non-space/null byte, return dup, deallocate original */
+
+ free(*a_str);
+ *a_str = _z_strdup(o_str);
+}
+
+/*
+ * Name: _z_strRemoveToken
+ * Synopsis: Remove a token from a string
+ * Description: Remove a token (sequence of one or more characters) from a
+ * string that is in allocated space
+ * Arguments: r_string - [RO, *RW] - (char **)
+ * - Pointer to handle to string to remove token from
+ * a_token - [RO, *RO] - (char *)
+ * Pointer to token (substring) to look for and remove
+ * from r_string provided
+ * a_separators - [RO, *RO] - (char *)
+ * - String containing one or more characters that
+ * separate one "token" from another in r_string
+ * a_index - [RO, *RO] - (int)
+ * - Index of token to remove; '0' is first matching
+ * token, '1' is second matching token, etc.
+ * Returns: void
+ * CAUTION: The input string must be allocated space (via lu_mem* or
+ * _z_str* methods) - it must not be a static or inline
+ * character string
+ * NOTE: The input string r_string will be freed with 'free'
+ * if the token to be removed is found
+ * NOTE: Any token string returned is placed in new storage for the
+ * calling method. The caller must use 'free' to dispose
+ * of the storage once the token string is no longer needed.
+ * Errors: If the new token string cannot be created, the process exits
+ */
+
+void
+_z_strRemoveToken(char **r_string, char *a_token, char *a_separators,
+ int a_index)
+{
+ char *a_string;
+ char *copyString;
+ char sep = 0;
+ int copyLength;
+ int i;
+
+ /* entry assertions */
+
+ assert(r_string != NULL);
+ assert(a_token != NULL);
+ assert(*a_token != '\0');
+ assert(a_separators != NULL);
+ assert(*a_separators != '\0');
+
+ /* simple case: input string is null; return empty string */
+
+ a_string = *r_string;
+ if (*a_string == '\0') {
+ return;
+ }
+
+ /* simple case: token == input string; return empty string */
+
+ if (strcmp(a_string, a_token) == 0) {
+ /*
+ * deallocate input string; free doesn't
+ * set *r_string to NULL
+ */
+ free(*r_string);
+ *r_string = NULL;
+ return;
+ }
+
+ /* simple case: token not in input string: return */
+
+ if (!_z_strContainsToken(a_string, a_token, a_separators)) {
+ return;
+ }
+
+ /*
+ * Pick apart the old string building the new one as we go along
+ * removing the first occurance of the token provided
+ */
+
+ copyLength = (strlen(a_string)-strlen(a_token))+2;
+ copyString = (char *)_z_calloc(copyLength);
+
+ for (i = 0; ; i++) {
+ char *p;
+
+ p = _z_strGetToken(&sep, a_string, i, a_separators);
+ if (p == NULL) {
+ break;
+ }
+
+ if ((strcmp(p, a_token) == 0) && (a_index-- == 0)) {
+ free(p);
+ continue;
+ }
+
+ if (*copyString) {
+ assert(sep != '\0');
+ (void) strncat(copyString, &sep, 1);
+ }
+
+ (void) strcat(copyString, p);
+ free(p);
+ }
+
+ free(*r_string);
+ assert(*copyString);
+ *r_string = copyString;
+}
diff --git a/usr/src/lib/libinstzones/common/zones_strings.h b/usr/src/lib/libinstzones/common/zones_strings.h
new file mode 100644
index 0000000000..8c22e1c370
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones_strings.h
@@ -0,0 +1,238 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+#ifndef _ZONES_STRINGS_H
+#define _ZONES_STRINGS_H
+
+
+/*
+ * Module: zones_strings.h
+ * Group: libinstzones
+ * Description: This header contains strings used in libinstzones
+ * library modules.
+ */
+
+#include <libintl.h>
+
+/*
+ * C++ prefix
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* constants */
+
+#ifndef TEXT_DOMAIN
+#define TEXT_DOMAIN "SUNW_INSTALL_LIBZONES"
+#endif
+
+#ifndef ILIBSTR
+#define ILIBSTR(x) dgettext(TEXT_DOMAIN, x)
+#endif
+
+/*
+ * message strings
+ */
+
+/* BEGIN CSTYLED */
+
+/*
+ * I18N: these messages are debugging message and are only displayed
+ * when special debugging output has been enabled - these messages
+ * will never be displayed during normal product usage
+ */
+
+#define DBG_ARG ILIBSTR("argument <%d> = <%s>")
+#define DBG_LIBRARY_NOT_FOUND ILIBSTR("unable to dlopen library <%s>: %s")
+#define DBG_MNTPT_NAMES ILIBSTR("mount point for global zone path <%s> in zone <%s> is global zone mount point <%s> non-global zone mount point <%s>")
+#define DBG_PATHS_ADD_FS ILIBSTR("add inherited file system entry <%d> path <%s>")
+#define DBG_PATHS_IS_INHERITED ILIBSTR("path <%s> is inherited from <%s>")
+#define DBG_PATHS_IS_NOT_INHERITED ILIBSTR("path <%s> in root <%s> not inherited")
+#define DBG_PATHS_NOT_INHERITED ILIBSTR("path <%s> not inherited: no inherited file systems")
+#define DBG_TO_ZONEHALT ILIBSTR("halting zone <%s>")
+#define DBG_TO_ZONEREADY ILIBSTR("readying zone <%s>")
+#define DBG_TO_ZONERUNNING ILIBSTR("running zone <%s>")
+#define DBG_TO_ZONEUNMOUNT ILIBSTR("unmounting zone <%s>")
+#define DBG_UNMOUNTING_DEV ILIBSTR("unmounting package device <%s>")
+#define DBG_ZONES_ADJLCKOBJ_EXIT ILIBSTR("lock object <%s> adjusted to <%s> for root path <%s> resolved <%s>")
+#define DBG_ZONES_APLK ILIBSTR("acquire lock zone <%s> lock <%s> pid <%ld>")
+#define DBG_ZONES_APLK_EXIT ILIBSTR("acquire lock failure zone <%s> lock <%s> pid <%ld>: return <%d> status <%d> <%s>")
+#define DBG_ZONES_APLK_RESULTS ILIBSTR("acquire lock success zone <%s> lock <%s> key <%s> results <%s>")
+#define DBG_ZONES_ARE_IMPLEMENTED ILIBSTR("zones are implemented")
+#define DBG_ZONES_CHG_Z_STATE ILIBSTR("change zone <%s> from state <%d> to state <%d>")
+#define DBG_ZONES_CHG_Z_STATE_ENTRY ILIBSTR("change zone <%d> to state <%d>")
+#define DBG_ZONES_GET_ZONE_STATE ILIBSTR("state of zone <%s> is <%ld>")
+#define DBG_ZONES_LCK_OBJ ILIBSTR("lock zone object <%s> zone <%s> pid <%ld> locks <%s>")
+#define DBG_ZONES_LCK_OBJ_FOUND ILIBSTR("lock zone examining object <%s> key <%s>: match")
+#define DBG_ZONES_LCK_OBJ_NOTFOUND ILIBSTR("lock zone examining object <%s> key <%s>: NO MATCH")
+#define DBG_ZONES_LCK_OBJ_NOTHELD ILIBSTR("object <%s> not locked on zone <%s>")
+#define DBG_ZONES_LCK_THIS ILIBSTR("lock this zone flags <0x%08lx>")
+#define DBG_ZONES_LCK_ZONE ILIBSTR("lock zone <%s> flags <0x%08lx>")
+#define DBG_ZONES_LCK_ZONES ILIBSTR("lock zones flags <0x%08lx>")
+#define DBG_ZONES_LCK_ZONES_EXIST ILIBSTR("locking all non-global zones defined")
+#define DBG_ZONES_LCK_ZONES_NOZONES ILIBSTR("no zones locked: no non-global zones exist")
+#define DBG_ZONES_LCK_ZONES_UNIMP ILIBSTR("no zones locked: zones are not implemented")
+#define DBG_ZONES_LCK_ZONE_PATCHADM ILIBSTR("locking patch administration: zone <%s> object <%s>")
+#define DBG_ZONES_LCK_ZONE_PKGADM ILIBSTR("locking package administration: zone <%s> object <%s>")
+#define DBG_ZONES_LCK_ZONE_ZONEADM ILIBSTR("locking zone administration: zone <%s> object <%s>")
+#define DBG_ZONES_MOUNT_IN_LZ_ENTRY ILIBSTR("mount in non-global zone: zone <%s> global-zone path <%s>")
+#define DBG_ZONES_NGZ_LIST_STATES ILIBSTR("non-global zone <%s> current state <%d> kernel status <%d>")
+#define DBG_ZONES_NOT_IMPLEMENTED ILIBSTR("zones are NOT implemented")
+#define DBG_ZONES_RELK ILIBSTR("release lock zone <%s> lock <%s> key <%s>")
+#define DBG_ZONES_RELK_EXIT ILIBSTR("release lock <%s> key <%s> to zone <%s>: return <%d> status <%d> results <%s>")
+#define DBG_ZONES_ULK_OBJ ILIBSTR("unlock zone object <%s> zone <%s> locks <%s>")
+#define DBG_ZONES_ULK_OBJ_FOUND ILIBSTR("unlock zone examining object <%s> key <%s>: match")
+#define DBG_ZONES_ULK_OBJ_NONE ILIBSTR("no objects locked on zone <%s>")
+#define DBG_ZONES_ULK_OBJ_NOTFOUND ILIBSTR("unlock zone examining object <%s> key <%s>: NO MATCH")
+#define DBG_ZONES_ULK_OBJ_NOTHELD ILIBSTR("object <%s> not locked on zone <%s>")
+#define DBG_ZONES_ULK_THIS ILIBSTR("unlock this zone flags <0x%08lx>")
+#define DBG_ZONES_ULK_ZONE ILIBSTR("unlock zone <%s> flags <0x%08lx>")
+#define DBG_ZONES_ULK_ZONES ILIBSTR("unlock zones flags <0x%08lx>")
+#define DBG_ZONES_ULK_ZONES_EXIST ILIBSTR("unlocking all non-global zones defined")
+#define DBG_ZONES_ULK_ZONES_NOZONES ILIBSTR("no zones unlocked: no non-global zones exist")
+#define DBG_ZONES_ULK_ZONES_UNIMP ILIBSTR("no zones unlocked: zones are not implemented")
+#define DBG_ZONES_ULK_ZONE_PATCHADM ILIBSTR("unlocking patch administration: zone <%s> object <%s>")
+#define DBG_ZONES_ULK_ZONE_PKGADM ILIBSTR("unlocking package administration: zone <%s> object <%s>")
+#define DBG_ZONES_ULK_ZONE_ZONEADM ILIBSTR("unlocking zone administration: zone <%s> object <%s>")
+#define DBG_ZONES_UNMOUNT_FROM_LZ_ENTRY ILIBSTR("unmount non-global zone: mount point <%s>")
+#define DBG_ZONE_EXEC_CMD_ENTER ILIBSTR("execute command <%s> on zone <%s> this zone <%s>")
+#define DBG_BRANDS_ARE_IMPLEMENTED ILIBSTR("brands are implemented")
+#define DBG_BRANDS_NOT_IMPLEMENTED ILIBSTR("brands are NOT implemented")
+
+/*
+ * I18N: these messages are error messages that can be displayed
+ * during the normal usage of the products
+ */
+
+#define ERR_CANNOT_CREATE_CONTRACT ILIBSTR("unable to create contract: %s")
+#define ERR_CAPTURE_FILE ILIBSTR("unable to open command output capture file <%s>: %s")
+#define ERR_FORK ILIBSTR("unable to create new process: %s")
+#define ERR_GET_ZONEID ILIBSTR("unable to get id of zone <%s>: %s")
+#define ERR_GZMOUNT_FAILED ILIBSTR("unable to mount global path <%s> local path <%s> zone <%s>: %s")
+#define ERR_GZMOUNT_RESOLVEPATH ILIBSTR("unable to determine zone <%s> dev path from <%s>: %s")
+#define ERR_GZMOUNT_SNPRINTFGMP_FAILED ILIBSTR("unable to create global zone mount point <%s> from <%s> <%s> <%s>: combined path exceeds maximum length of <%ld>")
+#define ERR_GZMOUNT_SNPRINTFLMP_FAILED ILIBSTR("unable to create local zone mount point <%s> from <%s>: combined path exceeds maximum length of <%ld>")
+#define ERR_GZMOUNT_SNPRINTFUUID_FAILED ILIBSTR("unable to create uuid <%s>: combined uuid exceeds maximum length of <%ld>")
+#define ERR_GZMOUNT_SNPRINTF_FAILED ILIBSTR("unable to create path <%s> from <%s>: combined path exceeds maximum length of <%ld>")
+#define ERR_GZPATH_NOT_ABSOLUTE ILIBSTR("unable to mount global zone path <%s>: path must be absolute")
+#define ERR_GZPATH_NOT_DIR ILIBSTR("unable to mount global zone path <%s>: %s")
+#define ERR_GZUMOUNT_FAILED ILIBSTR("unable to unmount <%s>: %s")
+#define ERR_INHERITED_PATH_NOT_ABSOLUTE ILIBSTR("inherited file system must be absolute path: <%s>")
+#define ERR_INHERITED_PATH_NOT_DIR ILIBSTR("inherited file system <%s> must be absolute path to directory: %s")
+#define ERR_INHERITED_PATH_NULL ILIBSTR("empty path specified for inherited file system: must be absolute path")
+#define ERR_LZMNTPT_NOTDIR ILIBSTR("unable to unmount global zone mount point <%s>: %s")
+#define ERR_LZMNTPT_NOT_ABSOLUTE ILIBSTR("unable to unmount <%s>: path must be absolute")
+#define ERR_LZROOT_NOTDIR ILIBSTR("unable to use <%s> as zone root path: %s")
+#define ERR_MALLOC ILIBSTR("unable to allocate %s memory, errno %d: %s")
+#define ERR_MEM ILIBSTR("unable to allocate memory.")
+#define ERR_MEMORY ILIBSTR("memory allocation failure, errno=%d")
+#define ERR_MNTPT_MKDIR ILIBSTR("unable to create temporary mount point <%s> in zone <%s>: %s")
+#define ERR_NO_ZONE_ROOTPATH ILIBSTR("unable to get root path of zone <%s>: %s")
+#define ERR_PKGDIR_GETHANDLE ILIBSTR("unable to get inherited directories: zonecfg_get_handle: %s")
+#define ERR_PKGDIR_NOHANDLE ILIBSTR("unable to get inherited directories: zonecfg_init_handle: %s")
+#define ERR_PKGDIR_SETIPDENT ILIBSTR("unable to get inherited directories: zonecfg_setipdent: %s")
+#define ERR_ROOTPATH_EMPTY ILIBSTR("unable to get root path of zone <%s>: empty path returned")
+#define ERR_ZEXEC_ASSEMBLE ILIBSTR("unable to establish connection with zone <%s>: could not assemble new environment")
+#define ERR_ZEXEC_BADSTATE ILIBSTR("unable to establish connection with zone <%s>: zone is in state '%s'")
+#define ERR_ZEXEC_BADZONE ILIBSTR("unable to establish connection with zone <%s>: no such zone")
+#define ERR_ZEXEC_EFAULT ILIBSTR("one or more file descriptors may be non-local (such as open across nfs): %s")
+#define ERR_ZEXEC_EXECFAILURE ILIBSTR("unable to establish connection with zone <%s>: exec failure: %s")
+#define ERR_ZEXEC_GETPPRIV ILIBSTR("unable to establish connection with zone <%s>: getppriv failed: %s")
+#define ERR_ZEXEC_GZUSED ILIBSTR("unable to establish connection with zone <%s>: global zone specified")
+#define ERR_ZEXEC_NOROOTPATH ILIBSTR("unable to establish connection with zone <%s>: cannot get root path: %s")
+#define ERR_ZEXEC_NOTRUNNING ILIBSTR("unable to establish connection with zone <%s>: not running - in state '%s'")
+#define ERR_ZEXEC_NOT_IN_GZ ILIBSTR("unable to establish connection with zone <%s>: not in the global zone")
+#define ERR_ZEXEC_NOZONEID ILIBSTR("unable to establish connection with zone <%s>: cannot get zone id: %s")
+#define ERR_ZEXEC_PRIVS ILIBSTR("unable to establish connection with zone <%s>: you lack sufficient privilege to access the zone")
+#define ERR_ZEXEC_PRIV_ALLOCSET ILIBSTR("unable to establish connection with zone <%s>o: priv_allocset failed: %s")
+#define ERR_ZEXEC_ZONEENTER ILIBSTR("unable to establish connection with zone <%s>: could not enter zone: %s")
+#define ERR_ZONEBOOT_CMD_ERROR ILIBSTR("unable to boot zone: problem running <%s> on zone <%s>: error %d%s%s")
+#define ERR_ZONEBOOT_CMD_SIGNAL ILIBSTR("unable to boot zone: problem running <%s> on zone <%s>: terminated by signal")
+#define ERR_ZONEBOOT_DIDNT_BOOT ILIBSTR("unable to boot zone <%s>: zone failed to transition to running state")
+#define ERR_ZONEBOOT_EXEC ILIBSTR("unable to boot zone: could not execute zone administration command <%s>: %s")
+#define ERR_ZONEHALT_EXEC ILIBSTR("unable to halt zone: could not execute zone administration command <%s>: %s")
+#define ERR_ZONEINDEX_OPEN ILIBSTR("unable to open zone index file %s: %s")
+#define ERR_ZONEREADY_CMDFAIL ILIBSTR("unable to ready zone: problem running <%s> on zone <%s>: %s%s%s")
+#define ERR_ZONEREADY_DIDNT_READY ILIBSTR("unable to ready zone <%s>: zone failed to transition to ready state")
+#define ERR_ZONEREADY_EXEC ILIBSTR("unable to ready zone: could not execute zone administration command <%s>: %s")
+#define ERR_ZONEROOT_NOTDIR ILIBSTR("unable to use temporary mount point <%s> in zone <%s>: %s")
+#define ERR_ZONES_LCK_THIS_PATCHADM ILIBSTR("Unable to acquire patch administration lock for this system; try again later")
+#define ERR_ZONES_LCK_THIS_PKGADM ILIBSTR("Unable to acquire package administration lock for this system; try again later")
+#define ERR_ZONES_LCK_THIS_ZONEADM ILIBSTR("Unable to acquire zone administration lock for this system; please try again later")
+#define ERR_ZONES_LCK_ZONES_FAILED ILIBSTR("Unable to acquire lock on non-global zone <%s>: releasing all locks")
+#define ERR_ZONES_LCK_ZONE_PATCHADM ILIBSTR("Unable to acquire patch administration lock for zone <%s>; please try again later")
+#define ERR_ZONES_LCK_ZONE_PKGADM ILIBSTR("Unable to acquire package administration lock for zone <%s>; please try again later")
+#define ERR_ZONES_LCK_ZONE_ZONEADM ILIBSTR("Unable to acquire zone administration lock for zone <%s>; please try again later")
+#define ERR_ZONES_NOT_IMPLEMENTED ILIBSTR("error: zones not implemented")
+#define ERR_ZONES_ULK_THIS_PACKAGE ILIBSTR("Unable to release package administration lock for this system; try again later")
+#define ERR_ZONES_ULK_THIS_PATCH ILIBSTR("Unable to release patch administration lock for this system; try again later")
+#define ERR_ZONES_ULK_THIS_ZONES ILIBSTR("Unable to release zone administration lock for this system; please try again later")
+#define ERR_ZONE_LIST_EMPTY ILIBSTR("empty zone list specified")
+#define ERR_ZONE_NAME_ILLEGAL ILIBSTR("illegal zone name %.*s")
+#define ERR_ZONE_NONEXISTENT ILIBSTR("zone %s does not exist")
+#define ERR_INHERITED_PATH_TOO_LONG ILIBSTR("inherited path too long current length <%d> maximum length <%d> bytes: <%s>")
+#define ERR_OPEN_READ ILIBSTR("unable to open <%s> for reading: (%d) %s")
+#define ERR_ZONEUNMOUNT_CMD_SIGNAL ILIBSTR("unable to unmount zone: problem running <%s> on zone <%s>: terminated by signal")
+#define ERR_ZONEUNMOUNT_EXEC ILIBSTR("unable to unmount zone: could not execute zone administration command <%s>: %s")
+#define ERR_ZONEUNMOUNT_CMD_ERROR ILIBSTR("unable to unmount zone: problem running <%s> on zone <%s>: error %d%s%s")
+#define ERR_BRAND_GETBRAND ILIBSTR("unable to get zone brand: zonecfg_get_brand: %s")
+
+/*
+ * I18N: these are messages that can be displayed during the normal
+ * usage of the products
+ */
+
+#define MSG_PROG_ERR ILIBSTR("ERROR: %s")
+#define MSG_ZONES_LCK_THIS_PATCHADM ILIBSTR("## Waiting for up to <%ld> seconds for patch administration commands to become available (another user is administering patches)")
+#define MSG_ZONES_LCK_THIS_PKGADM ILIBSTR("## Waiting for up to <%ld> seconds for package administration commands to become available (another user is administering packages)")
+#define MSG_ZONES_LCK_THIS_ZONEADM ILIBSTR("## Waiting for up to <%ld> seconds for zone administration commands to become available (another user is administering zones)")
+#define MSG_ZONES_LCK_ZONE_PATCHADM ILIBSTR("## Waiting for up to <%ld> seconds for patch administration commands to become available (another user is administering patches on zone <%s>)")
+#define MSG_ZONES_LCK_ZONE_PKGADM ILIBSTR("## Waiting for up to <%ld> seconds for package administration commands to become available (another user is administering packages on zone <%s>)")
+#define MSG_ZONES_LCK_ZONE_ZONEADM ILIBSTR("## Waiting for up to <%ld> seconds for zone administration commands to become available (another user is administering zones on zone <%s>)")
+
+/*
+ * I18N: these messages are warning messages that can be displayed
+ * during the normal usage of the products
+ */
+
+#define WRN_ZONES_ULK_ZONE_PATCHADM ILIBSTR("WARNING: Unable to release patch administration lock for zone <%s>")
+#define WRN_ZONES_ULK_ZONE_PKGADM ILIBSTR("WARNING: Unable to release package administration lock for zone <%s>")
+#define WRN_ZONES_ULK_ZONE_ZONEADM ILIBSTR("WARNING: Unable to release zone administration lock for zone <%s>")
+
+/* END CSTYLED */
+
+/*
+ * C++ postfix
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZONES_STRINGS_H */
diff --git a/usr/src/lib/libinstzones/common/zones_utils.c b/usr/src/lib/libinstzones/common/zones_utils.c
new file mode 100644
index 0000000000..cd0edec9c4
--- /dev/null
+++ b/usr/src/lib/libinstzones/common/zones_utils.c
@@ -0,0 +1,689 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+/*
+ * Module: zones.c
+ * Group: libinstzones
+ * Description: Provide "zones" interface for install consolidation code
+ *
+ * Public Methods:
+ *
+ * _z_close_file_descriptors - close a file descriptor "a_fd" not in the
+ * list "a_fds"
+ * _z_echo - Output an interactive message if interaction is enabled
+ * _z_echoDebug - Output a debugging message if debugging is enabled
+ * _z_get_inherited_dirs - return array of directories inherited by
+ * specified zone
+ * _z_is_directory - determine if specified path exists and is a directory
+ * _z_program_error - Output an error message to the appropriate destinations
+ * _z_pluginCatchSigint - SIGINT/SIGHUP interrupt handler
+ * _z_running_in_global_zone - Determine if this process is running in the
+ * global zone
+ * _z_zones_are_implemented - Determine if zones are supported by the
+ * current system
+ * _z_brands_are_implemented - determine if branded zones are implemented on
+ * this system
+ */
+
+/*
+ * System includes
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+#include <signal.h>
+#include <stropts.h>
+#include <libintl.h>
+#include <locale.h>
+#include <assert.h>
+#include <dlfcn.h>
+
+/*
+ * local includes
+ */
+
+#include "instzones_lib.h"
+#include "zones_strings.h"
+
+/*
+ * Private structures
+ */
+
+/*
+ * these dynamic libraries are required in order to use the branded zones
+ * functionality. If these libraries are not available at runtime,
+ * then the zones we find are assumed to be native zones.
+ */
+
+#define BRAND1_LIBRARY "libbrand.so.1"
+#define BRAND_LIBRARY "libbrand.so"
+
+/*
+ * Library Function Prototypes
+ */
+
+/*
+ * Local Function Prototypes
+ */
+
+static void error_and_exit(int error_num);
+
+static void (*fatal_err_func)() = &error_and_exit;
+
+/* ----------------------- private functions -------------------------- */
+/*
+ * error_and_exit()
+ * Abort routine. An exit code of '2' is used by all applications
+ * to indicate a non-recoverable fatal error.
+ * Parameters:
+ * error_num - error index number:
+ * ERR_MALLOC_FAIL
+ * Return:
+ * none
+ * Status:
+ * private
+ */
+static void
+error_and_exit(int error_num)
+{
+ if (error_num == ERR_MALLOC_FAIL)
+ (void) fprintf(stderr, "Allocation of memory failed\n");
+ else
+ (void) fprintf(stderr, "ERROR: code %d\n", error_num);
+ exit(2);
+}
+
+/*
+ * *****************************************************************************
+ * global external (public) functions
+ * *****************************************************************************
+ */
+
+/*
+ * Name: _z_close_file_descriptors
+ * Description: close a file descriptor "a_fd" not in the list "a_fds"
+ * This function is called from the fdwalk() library function.
+ * If the file descriptor passed in is NOT in the list passed in,
+ * the file is closed.
+ * Arguments: a_fds - [RO, *RO] - (void *)
+ * Pointer to list of file descriptors to keep open
+ * a_fd - [RO, *RO] - (int)
+ * File descriptor to check
+ * Returns: int
+ * 0 - success
+ */
+
+int
+_z_close_file_descriptors(void *a_fds, int a_fd)
+{
+ int *fds;
+ int i;
+
+ /* do not close standard input, output, or error file descriptors */
+
+ if (a_fd == STDIN_FILENO || a_fd == STDOUT_FILENO ||
+ a_fd == STDERR_FILENO) {
+ return (0);
+ }
+
+ /* if no file descriptor retention list, close this file */
+
+ if (a_fds == (void *)NULL) {
+ (void) close(a_fd);
+ return (0);
+ }
+
+ /*
+ * retention list provided, skip this descriptor if its in the list
+ */
+
+ fds = (int *)a_fds;
+
+ for (i = 0; fds[i] != -1; i++) {
+ if (fds[i] == a_fd) {
+ return (0);
+ }
+ }
+
+ /* this descriptor not in retention list - close this file */
+
+ (void) close(a_fd);
+
+ return (0);
+}
+
+/*
+ * Name: _z_echo
+ * Synopsis: Output an interactive message if interaction is enabled
+ * Description: Main method for outputting an interactive message; call to
+ * output interactive message if interation has not been disabled
+ * by a previous call to echoSetFlag(0).
+ * Arguments: format - [RO, RO*] (char *)
+ * printf-style format for debugging message to be output
+ * VARG_LIST - [RO] (?)
+ * arguments as appropriate to 'format' specified
+ * Returns: void
+ */
+
+/*PRINTFLIKE1*/
+void
+_z_echo(char *a_format, ...)
+{
+ va_list ap;
+ char message[MAX_MESSAGE_SIZE];
+
+ /* entry assertions */
+
+ assert(a_format != NULL);
+
+ /* return if no progerr function registered */
+
+ if (_z_global_data._z_echo == NULL) {
+ return;
+ }
+
+ /* capture message */
+
+ va_start(ap, a_format);
+ (void) vsnprintf(message, sizeof (message), a_format, ap);
+ va_end(ap);
+
+ /* pass message to registered function */
+
+ (_z_global_data._z_echo)("%s", message);
+}
+
+/*
+ * Name: _z_echoDebug
+ * Synopsis: Output a debugging message if debugging is enabled
+ * Description: Main method for outputting a debugging message; call to
+ * output debugging message if debugging has been enabled
+ * by a previous call to _z_echoDebugSetFlag(1).
+ * Arguments: format - [RO, RO*] (char *)
+ * printf-style format for debugging message to be output
+ * VARG_LIST - [RO] (?)
+ * arguments as appropriate to 'format' specified
+ * Returns: void
+ * NOTE: format of message will be:
+ * # [ aaa bbb ccc ] message
+ * where: aaa - process i.d.
+ * bbb - zone i.d.
+ * ccc - name of program
+ * for example:
+ * # [ 25685 0 pkgadd ] unable to get package list
+ */
+
+/*PRINTFLIKE1*/
+void
+_z_echoDebug(char *a_format, ...)
+{
+ va_list ap;
+ char message[MAX_MESSAGE_SIZE];
+
+ /* entry assertions */
+
+ assert(a_format != NULL);
+
+ /* return if no progerr function registered */
+
+ if (_z_global_data._z_echo_debug == NULL) {
+ return;
+ }
+
+ /* capture message */
+
+ va_start(ap, a_format);
+ (void) vsnprintf(message, sizeof (message), a_format, ap);
+ va_end(ap);
+
+ /* pass message to registered function */
+
+ (_z_global_data._z_echo_debug)("%s", message);
+}
+
+/*
+ * Name: _z_get_inherited_dirs
+ * Description: return array of directories inherited by specified zone
+ * Arguments: a_zoneName - [RO, *RO] - (char *)
+ * Pointer to string representing the name of the zone
+ * to return the list of inherited directories for
+ * Returns: char **
+ * != NULL - list of inherited directories, terminated
+ * by a NULL pointer
+ * == NULL - error - unable to retrieve list
+ */
+
+char **
+_z_get_inherited_dirs(char *a_zoneName)
+{
+ char **dirs = NULL;
+ int err;
+ int numIpdents = 0;
+ struct zone_fstab lookup;
+ zone_dochandle_t handle = NULL;
+
+ /* entry assertions */
+
+ assert(a_zoneName != NULL);
+ assert(*a_zoneName != '\0');
+
+ /* initialize the zone configuration interface handle */
+
+ handle = zonecfg_init_handle();
+ if (handle == NULL) {
+ _z_program_error(ERR_PKGDIR_NOHANDLE,
+ zonecfg_strerror(Z_NOMEM));
+ return (NULL);
+ }
+
+ /* get handle to configuration information for the specified zone */
+
+ err = zonecfg_get_handle(a_zoneName, handle);
+ if (err != Z_OK) {
+ /* If there was no zone before, that's OK */
+ if (err != Z_NO_ZONE) {
+ _z_program_error(ERR_PKGDIR_GETHANDLE,
+ zonecfg_strerror(err));
+ zonecfg_fini_handle(handle);
+ return (NULL);
+ }
+ }
+ assert(handle != NULL);
+
+ /* get handle to non-global zone ipd enumerator */
+
+ err = zonecfg_setipdent(handle);
+ if (err != Z_OK) {
+ _z_program_error(ERR_PKGDIR_SETIPDENT, zonecfg_strerror(err));
+ zonecfg_fini_handle(handle);
+ return (NULL);
+ }
+
+ /* enumerate the non-global zone ipd's */
+
+ while (zonecfg_getipdent(handle, &lookup) == Z_OK) {
+ dirs = _z_realloc(dirs, sizeof (char **)*(numIpdents+1));
+ dirs[numIpdents++] = strdup(lookup.zone_fs_dir);
+ }
+
+ if (dirs != NULL) {
+ dirs = _z_realloc(dirs, sizeof (char **)*(numIpdents+1));
+ dirs[numIpdents] = NULL;
+ }
+
+ /* toss non-global zone ipd enumerator handle */
+
+ (void) zonecfg_endipdent(handle);
+
+ return (dirs);
+}
+
+/*
+ * Name: _z_is_directory
+ * Description: determine if specified path exists and is a directory
+ * Arguments: path - pointer to string representing the path to verify
+ * returns: 0 - directory exists
+ * 1 - directory does not exist or is not a directory
+ * NOTE: errno is set appropriately
+ */
+
+int
+_z_is_directory(char *path)
+{
+ struct stat statbuf;
+
+ /* entry assertions */
+
+ assert(path != NULL);
+ assert(*path != '\0');
+
+ /* return error if path does not exist */
+
+ if (stat(path, &statbuf) != 0) {
+ return (1);
+ }
+
+ /* return error if path is not a directory */
+
+ if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
+ errno = ENOTDIR;
+ return (1);
+ }
+
+ /* path exists and is a directory */
+
+ return (0);
+}
+
+/*
+ * Name: _z_pluginCatchSigint
+ * Synopsis: SIGINT/SIGHUP interrupt handler
+ * Description: Catch the "SIGINT" and "SIGHUP" signals:
+ * -> increment _z_SigReceived global variable
+ * -> propagate signal to "_z_ChildProcessId" if registered (!= -1)
+ * Arguments: signo - [RO, *RO] - (int)
+ * Signal number that was caught
+ * Returns: void
+ */
+
+void
+_z_sig_trap(int a_signo)
+{
+ /* bump signals received count */
+
+ _z_global_data._z_SigReceived++;
+
+ /* if child process registered, propagate signal to child */
+
+ if (_z_global_data._z_ChildProcessId > 0) {
+ (void) kill(_z_global_data._z_ChildProcessId, a_signo);
+ }
+}
+
+/*
+ * Name: _z_program_error
+ * Description: Output an error message to the appropriate destinations
+ * Arguments: format - [RO, RO*] (char *)
+ * printf-style format for debugging message to be output
+ * VARG_LIST - [RO] (?)
+ * arguments as appropriate to 'format' specified
+ * Returns: void
+ * NOTE: format of message will be:
+ * [aaa: ] ERROR: message
+ * where: aaa - program name (if set)
+ * message - results of format and arguments
+ * for example:
+ * ERROR: unable to get package list
+ */
+
+/*PRINTFLIKE1*/
+void
+_z_program_error(char *a_format, ...)
+{
+ va_list ap;
+ char message[MAX_MESSAGE_SIZE];
+
+ /* entry assertions */
+
+ assert(a_format != NULL);
+
+ /* return if no progerr function registered */
+
+ if (_z_global_data._z_progerr == NULL) {
+ return;
+ }
+
+ /* capture message */
+
+ va_start(ap, a_format);
+ (void) vsnprintf(message, sizeof (message), a_format, ap);
+ va_end(ap);
+
+ /* pass message to registered function */
+
+ (_z_global_data._z_progerr)(MSG_PROG_ERR, message);
+}
+
+/*
+ * Name: _z_running_in_global_zone
+ * Synopsis: Determine if this process is running in the global zone
+ * Arguments: void
+ * Returns: boolean_t
+ * == B_TRUE - this process is running in the global zone
+ * == B_FALSE - this process is running in a nonglobal zone
+ */
+
+boolean_t
+_z_running_in_global_zone(void)
+{
+ zoneid_t zoneid = (zoneid_t)-1;
+
+ /*
+ * if zones are not implemented, there is no way to tell if zones
+ * are supported or not - in this case, we can only be running in the
+ * global zone (since non-global zones cannot exist) so return TRUE
+ */
+
+ if (z_zones_are_implemented() == B_FALSE) {
+ return (B_TRUE);
+ }
+
+ /* get the zone i.d. of the current zone */
+
+ zoneid = getzoneid();
+
+ /* return TRUE if this is the global zone i.d. */
+
+ if (zoneid == GLOBAL_ZONEID) {
+ return (B_TRUE);
+ }
+
+ /* return FALSE - not in the global zone */
+
+ return (B_FALSE);
+}
+
+/*
+ * Name: _z_zones_are_implemented
+ * Synopsis: Determine if zones are supported by the current system
+ * Arguments: void
+ * Returns: boolean_t
+ * == B_TRUE - zones are supported
+ * == B_FALSE - zones are not supported
+ */
+
+boolean_t
+_z_zones_are_implemented(void)
+{
+ void *libptr = NULL;
+
+ /* locate zone cfg library */
+
+ libptr = dlopen(ZONECFG_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
+ if (libptr == (void *)NULL) {
+ _z_echoDebug(DBG_LIBRARY_NOT_FOUND, ZONECFG_LIBRARY, dlerror());
+ libptr = dlopen(ZONECFG1_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
+ }
+
+ /* return false if library not available */
+
+ if (libptr == (void *)NULL) {
+ _z_echoDebug(DBG_LIBRARY_NOT_FOUND, ZONECFG1_LIBRARY,
+ dlerror());
+ return (B_FALSE);
+ }
+
+ /* library available - close handle */
+
+ (void) dlclose(libptr);
+
+ /* locate contract filesystem library */
+
+ libptr = dlopen(CONTRACT_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
+ if (libptr == (void *)NULL) {
+ _z_echoDebug(DBG_LIBRARY_NOT_FOUND, CONTRACT_LIBRARY,
+ dlerror());
+ libptr = dlopen(CONTRACT1_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
+ }
+
+ /* return false if library not available */
+
+ if (libptr == (void *)NULL) {
+ _z_echoDebug(DBG_LIBRARY_NOT_FOUND, CONTRACT1_LIBRARY,
+ dlerror());
+ return (B_FALSE);
+ }
+
+ /* library available - close handle */
+
+ (void) dlclose(libptr);
+
+ /* return success */
+
+ return (B_TRUE);
+}
+
+boolean_t
+_z_brands_are_implemented(void)
+{
+ void *libptr;
+
+ /* locate brand library */
+
+ libptr = dlopen(BRAND_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
+ if (libptr == NULL) {
+ _z_echoDebug(DBG_LIBRARY_NOT_FOUND, BRAND_LIBRARY, dlerror());
+ libptr = dlopen(BRAND1_LIBRARY, RTLD_NOW|RTLD_GLOBAL);
+ }
+
+ /* return false if library not available */
+
+ if (libptr == NULL) {
+ _z_echoDebug(DBG_LIBRARY_NOT_FOUND, BRAND1_LIBRARY, dlerror());
+ return (B_FALSE);
+ }
+
+ /* library available - close handle */
+
+ (void) dlclose(libptr);
+
+ /* return success */
+
+ return (B_TRUE);
+}
+
+/*
+ * z_calloc()
+ * Allocate 'size' bytes from the heap using calloc()
+ * Parameters:
+ * size - number of bytes to allocate
+ * Return:
+ * NULL - calloc() failure
+ * void * - pointer to allocated structure
+ * Status:
+ * public
+ */
+void *
+_z_calloc(size_t size)
+{
+ void * tmp;
+
+ if ((tmp = (void *) malloc(size)) == NULL) {
+ fatal_err_func(ERR_MALLOC_FAIL);
+ return (NULL);
+ }
+
+ (void) memset(tmp, 0, size);
+ return (tmp);
+}
+
+/*
+ * z_malloc()
+ * Alloc 'size' bytes from heap using malloc()
+ * Parameters:
+ * size - number of bytes to malloc
+ * Return:
+ * NULL - malloc() failure
+ * void * - pointer to allocated structure
+ * Status:
+ * public
+ */
+void *
+_z_malloc(size_t size)
+{
+ void *tmp;
+
+ if ((tmp = (void *) malloc(size)) == NULL) {
+ fatal_err_func(ERR_MALLOC_FAIL);
+ return (NULL);
+ } else
+ return (tmp);
+}
+
+/*
+ * _z_realloc()
+ * Calls realloc() with the specfied parameters. _z_realloc()
+ * checks for realloc failures and adjusts the return value
+ * automatically.
+ * Parameters:
+ * ptr - pointer to existing data block
+ * size - number of bytes additional
+ * Return:
+ * NULL - realloc() failed
+ * void * - pointer to realloc'd structured
+ * Status:
+ * public
+ */
+void *
+_z_realloc(void *ptr, size_t size)
+{
+ void *tmp;
+
+ if ((tmp = (void *)realloc(ptr, size)) == (void *)NULL) {
+ fatal_err_func(ERR_MALLOC_FAIL);
+ return ((void *)NULL);
+ } else
+ return (tmp);
+}
+
+/*
+ * z_strdup()
+ * Allocate space for the string from the heap, copy 'str' into it,
+ * and return a pointer to it.
+ * Parameters:
+ * str - string to duplicate
+ * Return:
+ * NULL - duplication failed or 'str' was NULL
+ * char * - pointer to newly allocated/initialized structure
+ * Status:
+ * public
+ */
+void *
+_z_strdup(char *str)
+{
+ char *tmp;
+
+ if (str == NULL)
+ return ((char *)NULL);
+
+ if ((tmp = strdup(str)) == NULL) {
+ fatal_err_func(ERR_MALLOC_FAIL);
+ return ((char *)NULL);
+ } else
+ return (tmp);
+}
diff --git a/usr/src/lib/libinstzones/i386/Makefile b/usr/src/lib/libinstzones/i386/Makefile
new file mode 100644
index 0000000000..c86be4377c
--- /dev/null
+++ b/usr/src/lib/libinstzones/i386/Makefile
@@ -0,0 +1,28 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libinstzones/sparc/Makefile b/usr/src/lib/libinstzones/sparc/Makefile
new file mode 100644
index 0000000000..c86be4377c
--- /dev/null
+++ b/usr/src/lib/libinstzones/sparc/Makefile
@@ -0,0 +1,28 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)