/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <libsysevent.h>
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <fnmatch.h>
#include <strings.h>
#include <unistd.h>
#include <assert.h>
#include <libgen.h>
#include <libintl.h>
#include <alloca.h>
#include <ctype.h>
#include <sys/systeminfo.h>
#include <ftw.h>
#include <pool.h>
#include <libscf.h>
#include <libproc.h>
#include <sys/priocntl.h>
#include <wait.h>
#include <auth_attr.h>
#include <auth_list.h>
#include <secdb.h>
#include <user_attr.h>
#include <prof_attr.h>
#include <libzfs.h>
#include <netdb.h>
#include <libxml/xmlmemory.h>
#include <libdevinfo.h>
#include <dirent.h>
#include <libbrand.h>
#include <libzonecfg.h>
#include "zonecfg_impl.h"
/*
*
* If you change something, also change dtd_to_pt(), dtd_to_rt(), etc.
*/
#define DTD_ATTR_ALLOWED_ADDRESS \
(const xmlChar *) "allowed-address"
#define DTD_ATTR_CONFIGURE_ALLOWED_ADDRESS \
(const xmlChar *) "configure-allowed-address"
#define DTD_ATTR_ALLOWED_DHCP_CIDS \
(const xmlChar *) "allowed-dhcp-cids"
#define DTD_ATTR_AUTO_MAC_ADDRESS \
(const xmlChar *) "auto-mac-address"
#define DTD_ATTR_LINK_PROTECTION \
(const xmlChar *) "link-protection"
struct dtd_name {
const char *dn_name;
};
{ "admin", DTD_ELEM_ADMIN },
{ "anet", DTD_ELEM_ANET },
{ "attr", DTD_ELEM_ATTR },
{ "capped-memory", DTD_ELEM_MCAP },
{ "dataset", DTD_ELEM_DATASET },
{ "dedicated-cpu", DTD_ELEM_PSET },
{ "device", DTD_ELEM_DEVICE },
{ "fs", DTD_ELEM_FS },
{ "net", DTD_ELEM_NET },
{ "rctl", DTD_ELEM_RCTL },
{ "readonly-path", DTD_ELEM_ROP },
{ "rootzpool", DTD_ELEM_ROOTZPOOL },
/*
* A property, but an element in the DTD, so a resource from the point
* of view of libzonecfg.
*/
{ "storage", DTD_ELEM_STORAGE },
{ "writable-path", DTD_ELEM_WRP },
{ "zpool", DTD_ELEM_ZPOOL },
};
/*
* See dtd_to_pt() for the complete conversion. In particular, if you're
* re-using an existing DTD attribute, you may need a special case.
*/
{ "action", DTD_ATTR_ACTION },
{ "address", DTD_ATTR_ADDRESS },
{ "alias", DTD_ATTR_ALIAS },
{ "allow-partition", DTD_ATTR_ALLOW_PARTITION },
{ "allow-raw-io", DTD_ATTR_ALLOW_RAW_IO },
{ "allowed-address", DTD_ATTR_ALLOWED_ADDRESS },
{ "allowed-dhcp-cids", DTD_ATTR_ALLOWED_DHCP_CIDS },
{ "auths", DTD_ATTR_AUTHS },
{ "auto-mac-address", DTD_ATTR_AUTO_MAC_ADDRESS },
{ "autoboot", DTD_ATTR_AUTOBOOT },
{ "bootargs", DTD_ATTR_BOOTARGS },
{ "brand", DTD_ATTR_BRAND },
{ "configure-allowed-address", DTD_ATTR_CONFIGURE_ALLOWED_ADDRESS },
{ "cos", DTD_ATTR_COS },
{ "defrouter", DTD_ATTR_DEFROUTER },
{ "dir", DTD_ATTR_DIR },
{ "etsbw-lcl", DTD_ATTR_ETSBWLCL },
{ "file-mac-profile", DTD_ATTR_MAC_PROFILE },
{ "fs-allowed", DTD_ATTR_FS_ALLOWED },
{ "hostid", DTD_ATTR_HOSTID },
{ "importance", DTD_ATTR_IMPORTANCE },
{ "install-size", DTD_ATTR_INSTALL_SIZE },
{ "ip-type", DTD_ATTR_IPTYPE },
{ "limit", DTD_ATTR_LIMIT },
{ "limitpriv", DTD_ATTR_LIMITPRIV },
{ "link-protection", DTD_ATTR_LINK_PROTECTION },
{ "linkmode", DTD_ATTR_LINKMODE },
{ "linkname", DTD_ATTR_LINKNAME },
{ "lower-link", DTD_ATTR_LOWER_LINK },
{ "mac-address", DTD_ATTR_MAC_ADDRESS },
{ "mac-prefix", DTD_ATTR_MAC_PREFIX },
{ "mac-slot", DTD_ATTR_MAC_SLOT },
{ "match", DTD_ATTR_MATCH },
{ "maxbw", DTD_ATTR_MAXBW },
{ "mtu", DTD_ATTR_MTU },
{ "pkey", DTD_ATTR_PKEY },
{ "pool", DTD_ATTR_POOL },
{ "priority", DTD_ATTR_PRIORITY },
{ "priv", DTD_ATTR_PRIV },
{ "raw", DTD_ATTR_RAW },
{ "rxfanout", DTD_ATTR_RXFANOUT },
{ "rxrings", DTD_ATTR_RXRINGS },
{ "scheduling-class", DTD_ATTR_SCHED },
{ "special", DTD_ATTR_SPECIAL },
{ "txrings", DTD_ATTR_TXRINGS },
{ "type", DTD_ATTR_TYPE },
{ "uri", DTD_ATTR_URI },
{ "user", DTD_ATTR_USER },
{ "value", DTD_ATTR_VALUE },
{ "vlan-id", DTD_ATTR_VLAN_ID },
{ "vsi-mgrid", DTD_ATTR_VSIMGRID },
{ "vsi-typeid", DTD_ATTR_VSITYPEID },
{ "vsi-vers", DTD_ATTR_VSIVERS },
{ "zonepath", DTD_ATTR_ZONEPATH },
};
/*
* rctl alias definitions
*
* This holds the alias, the full rctl name, the default priv value, action
* and lower limit. The functions that handle rctl aliases step through
* this table, matching on the alias, and using the full values for setting
* the rctl entry as well the limit for validation.
*/
static struct alias {
char *shortname;
char *realname;
char *priv;
char *action;
} aliases[] = {
};
static struct zone_state_map {
/*
* The value of zone_state must match the index in the zone_states
* array. This is used as a runtime sanity check to ensure that
* zone_state_t and zone_states[] are are properly maintained.
*/
char *zone_state_str;
} zone_states[] = {
/* States must be in same order as zone_state_t enum. */
{ZONE_STATE_CONFIGURED, "configured"},
{ZONE_STATE_INCOMPLETE, "incomplete"},
{ZONE_STATE_UNAVAILABLE, "unavailable"},
{ZONE_STATE_INSTALLED, "installed"},
{ZONE_STATE_READY, "ready"},
{ZONE_STATE_RUNNING, "running"},
{ZONE_STATE_SHUTTING_DOWN, "shutting_down"},
{ZONE_STATE_DOWN, "down"},
{ZONE_STATE_MOUNTED, "mounted"},
/* This must always be last. */
{ZONE_STATE_INVALID, "unknown"}
};
/*
* Structure for applying rctls to a running zone. It allows important
* process values to be passed together easily.
*/
typedef struct pr_info_handle {
struct zone_dochandle {
char *zone_dh_rootdir;
};
struct znotify {
void * zn_private;
int zn_failure_count;
};
/*
* For functions which return int, which is most of the functions herein,
* the return values should be from the Z_foo set defined in <libzonecfg.h>.
* In some instances, we take pains mapping some libc errno values to Z_foo
* values from this set.
*/
/*
* Set the root (/) path for all zonecfg configuration files. This is a
* private interface used by Live Upgrade extensions to access zone
* configuration inside mounted alternate boot environments.
* This interface is also used by zoneadm mount and unmount subcommands.
*/
void
{
if (*zonecfg_root != '\0')
zonecfg_root = "";
}
const char *
zonecfg_get_root(void)
{
return (zonecfg_root);
}
/*
* Similar to realpath() but just collapses unnecessary path elements. Unlike
* or in any way examine the current state of mounted file systems. It does
* not call lstat(), chdir(), etc. That is, the following transforms are
* performed, regardless of whether all or part of the path exists.
*
* /dir1/ -> /dir
* /dir/../dir2 -> /dir2
*/
int
{
const char *next;
/* Absolute path required and newpath must be long enough for "/\0" */
if (*origpath != '/')
return (Z_INVAL);
if (newpathsz < 2)
return (Z_TOO_BIG);
*cur = '/';
while (*next != '\0') {
/*
* There are two phases to each pass. The first phase advances
* the next pointer forward skipping past extra "/", "/." and
* "/.." components. The cur pointer will move backward in
* response to each /.. component, but will never take on a
* value less than newpath. The second phase advances the cur
* pointer, copying from next with each advance.
*/
/* Phase 1 */
while (*next == '/') {
next++;
continue;
}
/* /./ or /. */
next += 2;
continue;
}
/* /../ or /.. */
next += 3;
continue;
do {
cur--;
continue;
}
/* This is /.something - copy it */
next++;
break;
}
/* Phase 2 */
/* next has just moved past a slash. cur must do the same. */
cur++;
/*
* Copy until the end of newpath, the next slash, or the end
* of origpath.
*/
cur++;
next++;
}
/* Copy the next '/' or '\0'. */
if (*cur != '\0')
return (Z_TOO_BIG);
break;
}
}
/*
* cur references the last character copied, which is always '\0'. The
* previous character copied may be / in the case of origpath like
* "/a/b/c/../..".
*
* NB: The cur++ at the beginning of phase 2 ensures cur > newpath.
*/
cur--;
*cur = '\0';
return (Z_OK);
}
zonecfg_in_alt_root(void)
{
return (*zonecfg_root != '\0');
}
/*
* Callers of the _file_path() functions are expected to have the second
* parameter be a (char foo[MAXPATHLEN]).
*/
static boolean_t
{
}
static boolean_t
{
}
/*ARGSUSED*/
static void
{
/*
* This function does nothing by design. Its purpose is to prevent
*/
}
zonecfg_init_handle(void)
{
return (NULL);
}
/* generic libxml initialization */
(void) xmlLineNumbersDefault(1);
(void) xmlKeepBlanksDefault(0);
return (handle);
}
int
{
return (Z_BAD_HANDLE);
return (Z_OK);
}
void
{
}
static int
{
return (Z_ACCES);
return (Z_NO_ZONE);
return (Z_MISC_FS);
}
return (Z_OK);
}
int
{
return (Z_MISC_FS);
/*
* If there is no file, and no index entry, reliably indicate that no
* such zone exists.
*/
return (Z_NO_ZONE);
/*
* Handle any other filesystem related errors (except if the XML
* file is missing, which we treat silently), unless we're forcing,
* in which case we plow on.
*/
return (Z_ACCES);
else if (!force)
return (Z_MISC_FS);
}
if (state > ZONE_STATE_INSTALLED)
return (Z_BAD_ZONE_STATE);
return (Z_BAD_ZONE_STATE);
/*
* Index deletion succeeds even if the entry doesn't exist. So this
* will fail only if we've had some more severe problem.
*/
if (!force)
return (err);
/*
* Treat failure to find the XML file silently, since, well, it's
* gone, and with the index file cleaned up, we're done.
*/
return (Z_OK);
return (err);
}
int
{
return (Z_MISC_FS);
return (zonecfg_destroy_impl(path));
}
/*
* This (and dtd_to_rt()) should include all resources that can contain
* properties (so not the fake ones in zonecfg like "fs-allowed"), and aren't
* synthetic (like the rctl ones).
*/
static const xmlChar *
{
}
return (NULL);
}
static const char *
{
}
return (NULL);
}
/*
* For the most part property types as understood by zonecfg are identical to
* their DTD_ATTRs however they sometimes do differ, for example the attribute:
* DTD_ATTR_DIR ("directory") and the property: PT_DIR ("dir").
*
* In some cases the same DTD_ATTR maps to different property types depending
* on the resource context, so must be handled outside of the table.
*
* DTD_ATTR_NCPU_MIN and DTD_ATTR_NCPU_MAX are also problematic, as they are
* stored in xml as two attributes but presented to the user as a single
* configuration property. The caller should be aware that looking up either of
* these attributes will return "ncpus".
*/
static const char *
{
}
return ("zonename");
else
return ("name");
return ("ncpus");
return ("ncpus");
/*
* The same resource string is used for both DTD_ATTR_PHYSCAP
* and DTD_ATTR_PHYSICAL.
*/
return ("physical");
}
return (NULL);
}
static int
{
return (Z_BAD_HANDLE);
return (Z_EMPTY_DOCUMENT);
return (Z_WRONG_DOC_TYPE);
return (Z_OK);
}
static int
{
int err;
return (err);
return (Z_OK);
}
/*
* If the specific brand isn't installed, use the default brand. We need this
* to deal with zones with uninstalled brands, in particular we must allow
* delete. As zonecfg won't commit a zone config with a non-valid brand, this
* isn't as bad as it sounds.
*/
static int
{
return (Z_BRAND_ERROR);
return (Z_OK);
return (Z_BRAND_ERROR);
return (Z_OK);
return (Z_BRAND_ERROR);
}
static int
{
return (Z_BRAND_ERROR);
/* Fixed property */
return (Z_BRAND_FIXED_CFG);
}
/* Check to see if the property has been disabled */
return (Z_BRAND_DISABLED_CFG);
}
/* Check to see if the property value has been disabled */
return (Z_BRAND_DISABLED_VAL);
}
}
return (Z_OK);
}
static int
{
return (Z_BRAND_ERROR);
return (Z_BRAND_ERROR);
}
return (Z_OK);
}
static int
{
return (Z_BAD_PROPERTY);
return (Z_NOMEM);
}
return (Z_OK);
}
static int
char **dst)
{
int err;
return (err);
/* See if the brand overrides this property or property value */
/* "brand" is a special case - it can't be branded */
switch (err) {
case Z_BRAND_DISABLED_VAL:
return (Z_BAD_PROPERTY);
case Z_BRAND_DISABLED_CFG:
/*
* The case where an empty string is returned and the
* configuration is disabled, return the empty string
* rather than Z_BAD_PROPERTY as some callers of
* libzonecfg expect this.
*/
if (empty_val)
return (Z_BAD_PROPERTY);
case Z_BRAND_FIXED_CFG:
};
return (err);
}
}
static int
{
int err;
return (err);
}
return (Z_TOO_BIG);
return (Z_OK);
}
static int
{
int err;
return (err);
}
static int
char **propval)
{
int err;
return (err);
}
static int
{
return (Z_BRAND_ERROR);
return (Z_BRAND_DISABLED_CFG);
}
return (Z_OK);
}
static int
const char *propval)
{
int err;
/*
* Check to see if the proposed property and value can be set.
* The brand may have disabled the property or value or may have
* fixed this property.
*/
return (err);
/*
* If we get a null propval remove the property (ignore return since it
* may not be set to begin with).
*/
return (Z_OK);
}
return (Z_INVAL);
return (Z_OK);
}
static int
const char *propval)
{
int err;
return (err);
}
static void
{
}
static void
{
continue;
}
}
}
static int
{
int valid;
return (Z_NO_ZONE);
/* distinguish file not found vs. found but not parsed */
return (Z_INVALID_DOCUMENT);
return (Z_NO_ZONE);
}
return (Z_NOMEM);
if (valid == 0)
return (Z_INVALID_DOCUMENT);
/* delete any comments such as inherited Sun copyright / ident str */
/* Update any legacy ipkg branded zones to solaris */
/*
* Treat legacy "ipkg" branded zones as "solaris".
* Attempt to modify the backing file, although this
* may fail due to a read-only file when using ROZR.
*
* Dryrun attach uses a temporary copy of zone xml
* file, so this operation will not re-write the
* real target of a dry run attach.
*/
/* Don't write to alternate roots */
if (!zonecfg_in_alt_root())
(void) zonecfg_save(handle);
}
return (Z_OK);
}
int
{
return (Z_MISC_FS);
}
int
{
int err;
sizeof (migpath))
return (Z_NOMEM);
return (Z_NO_ZONE);
sizeof (migpath))
return (Z_NOMEM);
return (err);
return (err);
}
int
{
return (Z_MISC_FS);
}
int
{
int err;
return (Z_MISC_FS);
return (err);
}
int
{
int err;
return (Z_MISC_FS);
return (err);
return (Z_OK);
}
static boolean_t
{
if (handle->zone_dh_newzone)
return (B_FALSE);
return (B_TRUE);
return (B_FALSE);
}
static boolean_t
{
}
static boolean_t
{
return (handle->zone_dh_snapshot);
}
/*
* It would be great to be able to use libc's ctype(3c) macros, but we
* can't, as they are locale sensitive, and it would break our limited thread
* safety if this routine had to change the app locale on the fly.
*/
int
{
int i;
return (Z_BOGUS_ZONE_NAME);
return (Z_BOGUS_ZONE_NAME);
return (Z_BOGUS_ZONE_NAME);
return (Z_BOGUS_ZONE_NAME);
}
return (Z_OK);
}
/*
* Changing the zone name requires us to track both the old and new
* name of the zone until commit time.
*/
int
{
}
static int
{
int err;
return (err);
}
(void) zonecfg_endadminent(handle);
return (err);
}
}
(void) zonecfg_endadminent(handle);
return (Z_OK);
}
int
{
int err;
return (err);
return (Z_OK);
/*
* Switching zone names to one beginning with the system-reserved
* prefix is not permitted.
*/
return (Z_BOGUS_ZONE_NAME);
return (err);
/*
* Setting the name back to the original name (effectively a revert of
* the name) is fine. But if we carry on, we'll falsely identify the
* name as "in use," so special case here.
*/
return (err);
}
/* Check to see if new name chosen is already in use */
return (Z_NAME_IN_USE);
/*
* If this isn't already "new" or in a renaming transition, then
* we're initiating a rename here; so stash the "delete name"
* (i.e. the name of the zone we'll be removing) for the rename.
*/
sizeof (old_delname));
/*
* Name change is allowed only when the zone we're altering
* is not ready or running.
*/
if (state > ZONE_STATE_INSTALLED)
return (Z_BAD_ZONE_STATE);
return (err);
}
sizeof (handle->zone_dh_delete_name));
} else if (is_renaming(handle)) {
if (state > ZONE_STATE_INSTALLED)
return (Z_BAD_ZONE_STATE);
return (err);
}
}
/*
* Restore the deletename to whatever it was at the
* top of the routine, since we've had a failure.
*/
sizeof (handle->zone_dh_delete_name));
return (err);
}
/*
* Record the old admins from the old zonename
* so that they can be deleted when the operation is committed.
*/
return (err);
else
return (Z_OK);
}
int
{
return (Z_TOO_BIG);
}
int
{
char last_copied;
int ret;
/*
* Collapse multiple contiguous slashes and remove trailing slash.
*/
return (Z_NOMEM);
last_copied = '\0';
copy_mp++;
}
}
if (last_copied == '/')
copy_mp--;
*copy_mp = '\0';
/*
* The user deals in absolute paths in the running global zone, but the
* internal configuration files deal with boot environment relative
* paths. Strip out the alternate root when specified.
*/
return (Z_BAD_PROPERTY);
}
return (ret);
}
static int
{
int ret;
ret = Z_NO_ENTRY;
return (ret);
}
int
{
int ret;
return (ret);
}
int
{
int err;
/*
* We presume that the "solaris" brand is always present.
*/
} else {
/* Verify that this brand actually exists */
return (Z_BRAND_ERROR);
}
/*
* We have to route around setprop() here, otherwise we can end up in a
* loop if we're in an old BE where the default template brand is
* IPKG_BRAND_NAME.
*/
return (err);
return (Z_INVAL);
return (Z_OK);
}
int
{
int ret;
sizeof (autobootstr))) != Z_OK)
return (ret);
else
return (ret);
}
int
{
}
{
return (B_FALSE);
} else {
return (B_TRUE);
}
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
/*
* in the <zonename>.xml file: the path to the zone. This is for performance,
* since we need to walk all zonepath's in order to be able to detect conflicts
* (see crosscheck_zonepaths() in the zoneadm command).
*
* An additional complexity is that when doing a rename, we'd like the entire
* index update operation (rename, and potential state changes) to be atomic.
* In general, the operation of this function should succeed or fail as
* a unit.
*/
int
{
int err;
int opcode;
char *zn;
return (err);
return (err);
if (is_renaming(handle)) {
opcode = PZE_MODIFY;
/*
* Be tolerant of the zone already existing in the index file,
* since we might be forcibly overwriting an existing
* configuration with a new one (for example 'create -F'
* in zonecfg).
*/
cookie = setzoneent();
opcode = PZE_MODIFY;
break;
}
}
} else {
opcode = PZE_MODIFY;
}
return (err);
return (Z_OK);
}
/*
* The goal of this routine is to cause the index file update and the
* document save to happen as an atomic operation. We do the document
* first, saving a backup copy using a hard link; if that succeeds, we go
* on to the index. If that fails, we roll the document back into place.
*
* Strategy:
*
* New zone 'foo' configuration:
* Create tmpfile (zonecfg.xxxxxx)
* Write XML to tmpfile
* Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
* Add entry to index file
* If it fails, delete foo.xml, leaving nothing behind.
*
* Save existing zone 'foo':
* Make backup of foo.xml -> .backup
* Create tmpfile (zonecfg.xxxxxx)
* Write XML to tmpfile
* Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
* Modify index file as needed
* If it fails, recover from .backup -> foo.xml
*
* Rename 'foo' to 'bar':
* Create tmpfile (zonecfg.xxxxxx)
* Write XML to tmpfile
* Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
* Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
*/
static int
{
if (tmpfd == -1) {
return (Z_TEMP_FILE);
}
/*
* We do a final validation of the document. Since the library has
* malfunctioned if it fails to validate, we follow-up with an
* assert() that the doc is valid.
*/
goto err;
/*
* In the event we are doing a standard save, hard link a copy of the
* original file in .backup.<pid>.filename so we can restore it if
* something goes wrong.
*/
return (Z_ACCES);
return (Z_MISC_FS);
}
}
/*
* Move the new document over top of the old.
* i.e.: zonecfg.XXXXXX -> myzone.xml
*/
if (backup)
return (Z_ACCES);
return (Z_MISC_FS);
}
/*
* If this is a snapshot, we're done-- don't add an index entry.
*/
if (is_snapshot(handle))
return (Z_OK);
/* now update the index file to reflect whatever we just did */
if (backup) {
/*
* Try to restore from our backup.
*/
} else {
/*
* Either the zone is new, in which case we can delete
* new.xml, or we're doing a rename, so ditto.
*/
}
return (Z_UPDATING_INDEX);
}
if (backup)
return (Z_OK);
err:
return (Z_SAVING_FILE);
}
static int
{
int err;
/* First pull out the value of the property */
return (Z_BAD_PROPERTY);
/* If it's not settable, it should be cleared */
} else {
}
}
return (Z_OK);
}
int
{
int err;
return (err);
/* Start with the global properties */
return (err);
/* Remove any resources which have been disabled */
} else {
/* Remove any properties which have been disabled */
return (err);
}
}
return (Z_OK);
}
int
{
return (Z_BAD_HANDLE);
if (handle->zone_dh_snapshot)
return (Z_INVAL);
return (err);
return (Z_MISC_FS);
"FILE. Use zonecfg(1M) instead.\n");
/*
* Update user_attr first so that it will be older
* than the config file.
*/
return (err);
if (is_renaming(handle)) {
}
return (Z_OK);
}
int
{
int valid;
return (Z_BAD_HANDLE);
/*
* We do a final validation of the document. Since the library has
* malfunctioned if it fails to validate, we follow-up with an
* assert() that the doc is valid.
*/
return (Z_SAVING_FILE);
return (Z_OK);
}
int
{
int valid;
return (Z_BAD_HANDLE);
if (flags & ZONE_DRY_RUN) {
} else {
!= Z_OK)
return (err);
!= Z_OK)
return (err);
ZONE_DETACHED) >= sizeof (migpath))
return (Z_NOMEM);
}
return (err);
"Use zonecfg(1M) and zoneadm(1M) attach.\n");
/*
* We do a final validation of the document. Since the library has
* malfunctioned if it fails to validate, we follow-up with an
* assert() that the doc is valid.
*/
return (Z_SAVING_FILE);
if (!(flags & ZONE_DRY_RUN))
return (Z_OK);
}
void
{
return;
return;
return;
if (forced) {
} else {
}
}
/*
* Special case: if access(2) fails with ENOENT, then try again using
* ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we
* work around the case of a config file which has not been created yet:
* the user will need access to the directory so use that as a heuristic.
*/
int
{
return (Z_INVAL);
return (Z_OK);
ZONE_CONFIG_ROOT) >= sizeof (path))
return (Z_INVAL);
return (Z_OK);
}
return (Z_ACCES);
return (Z_INVAL);
return (Z_MISC_FS);
}
int
{
return (Z_NOMEM);
}
goto out;
goto out;
goto out;
goto out;
}
/*
* If the resolved path is not the same as the original path, then
* save the resolved path in the snapshot, thus preventing any
* potential problems down the line when zoneadmd goes to unmount
* file systems and depends on initial string matches with resolved
* paths.
*/
goto out;
}
ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
goto out;
}
goto out;
}
goto out;
}
"It is a snapshot of running zone state.\n");
out:
return (error);
}
int
{
int err;
if (err == Z_BAD_PROPERTY) {
/* Return default value */
*iptypep = ZS_EXCLUSIVE;
return (Z_OK);
return (err);
}
/*
* When the default for ip-type was shared, zonecfg_set_iptype() only
* wrote the ip-type property to the zone configuration if it was set
* to exclusive. It now always writes ip-type explicitly regardless
* of its value. As a result, we can assume that a missing ip-type
* property implies shared (getrootattr() returns the empty string if
* the attribute is missing).
*/
*iptypep = ZS_EXCLUSIVE;
else
return (Z_INVALID_PROPERTY);
return (Z_OK);
}
int
{
}
static int
char *src)
{
int err;
/*
* Check to see if the proposed property and value can be set.
* The brand may have disabled the property or value or may have
* fixed this property.
*/
src);
/*
* If the fixed value is the same as the new value, don't return a
* failure, but also don't add it to the zone's XML config as fixed
* properties should only live in the brand XML.
*/
if (err == Z_BRAND_FIXED_CFG) {
return (Z_BRAND_ERROR);
return (Z_BRAND_ERROR);
}
return (Z_OK);
}
return (err);
return (Z_BAD_PROPERTY);
}
return (Z_OK);
}
static int
{
int err;
return (err);
return (0);
}
static int
{
int err;
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
}
}
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
{
return (Z_NOMEM);
sizeof (new->zone_fsopt_opt));
else
return (Z_OK);
}
int
{
else
return (Z_OK);
} else
}
return (Z_NO_PROPERTY_ID);
}
void
{
}
}
void
{
return;
}
static boolean_t
char *user_prop)
{
char *gotten_prop;
int prop_result;
return (B_FALSE); /* shouldn't happen */
return ((prop_result == 0));
}
static int
struct zone_fstab *tabptr)
{
continue;
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
struct zone_fstab *oldtabptr,
struct zone_fstab *newtabptr)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
int
struct zone_fstab *tabptr)
{
int err;
return (Z_INVAL);
return (err);
/*
* Walk the list of children looking for matches on any properties
* specified in the fstab parameter. If more than one resource
* matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
* Z_NO_RESOURCE_ID.
*/
firstmatch = NULL;
continue;
if (firstmatch == NULL)
firstmatch = cur;
else
return (Z_INSUFFICIENT_SPEC);
}
}
special) == 0) {
if (firstmatch == NULL)
firstmatch = cur;
else if (firstmatch != cur)
return (Z_INSUFFICIENT_SPEC);
} else {
/*
* If another property matched but this
* one doesn't then reset firstmatch.
*/
if (firstmatch == cur)
firstmatch = NULL;
}
}
}
if (firstmatch == NULL)
firstmatch = cur;
else if (firstmatch != cur)
return (Z_INSUFFICIENT_SPEC);
} else {
/*
* If another property matched but this
* one doesn't then reset firstmatch.
*/
if (firstmatch == cur)
firstmatch = NULL;
}
}
}
if (firstmatch == NULL)
firstmatch = cur;
else if (firstmatch != cur)
return (Z_INSUFFICIENT_SPEC);
} else {
/*
* If another property matched but this
* one doesn't then reset firstmatch.
*/
if (firstmatch == cur)
firstmatch = NULL;
}
}
}
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
cur = firstmatch;
return (err);
return (err);
return (err);
return (err);
/* options are optional */
sizeof (options_str)) != Z_OK))
break;
break;
}
return (Z_OK);
}
/*
* Compare two IP addresses in string form. Allow for the possibility that
* one might have "/<prefix-length>" at the end: allow a match on just the
* IP address (or host name) part.
*/
{
int result;
return (B_TRUE);
/*
* If neither has a slash or both do, they need to match to be
* considered the same, but they did not match above, so fail.
*/
return (B_FALSE);
/*
* Only one had a slash: pick that one, zero out the slash, compare
* the "address only" strings, restore the slash, and return the
* result of the comparison.
*/
*slashp = '\0';
*slashp = '/';
return ((result == 0));
}
int
{
*slashp = '\0';
return (Z_IPV6_ADDR_PREFIX_LEN);
} else {
/* "address" may be a host name */
goto out;
}
/* LINTED E_BAD_PTR_CAST_ALIGN */
sizeof (struct in_addr));
}
out:
*slashp = '/';
return (ret);
}
{
int so;
int save_errno;
/* Odd - can't tell if the ifname exists */
return (B_FALSE);
}
save_errno = errno;
errno = save_errno;
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Check if a net or anet resource exists with the given linkname.
*/
{
int err;
return (err);
return (B_TRUE);
}
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* Determines whether there is a net resource with the physical interface, IP
* address, and default router specified by 'tabptr' in the zone configuration
* to which 'handle' refers. 'tabptr' must have an interface, an address, a
* default router, or a combination of the three. This function returns Z_OK
* iff there is exactly one net resource matching the query specified by
* 'tabptr'. The function returns Z_INSUFFICIENT_SPEC if there are multiple
* matches or 'tabptr' does not specify a physical interface, address, or
* default router. The function returns Z_NO_RESOURCE_ID if are no matches.
*
* Errors might also be returned if the entry that exactly matches the
* query lacks critical network resource information.
*
* If there is a single match, then the matching entry's physical interface, IP
* address, and default router information are stored in 'tabptr'.
*/
int
{
int err;
return (Z_INVAL);
/*
* Determine the fields that will be searched. There must be at least
* one.
*
* zone_net_address, zone_net_physical, and zone_net_defrouter are
* arrays, so no NULL checks are necessary.
*/
if (addrspec != 0 && allowed_addrspec != 0)
return (Z_INVAL); /* can't specify both */
allowed_addrspec == 0)
return (Z_INSUFFICIENT_SPEC);
return (err);
return (err);
/*
* Iterate over the configuration's elements and look for net elements
* that match the query.
*/
firstmatch = NULL;
/* Skip non-net elements */
continue;
/*
* If any relevant fields don't match the query, then skip
* the current net element.
*/
continue;
address)))
continue;
allowed_addr) != 0))
continue;
defrouter) != 0))
continue;
/*
* The current net element matches the query. Select it if
* it's the first match; otherwise, abort the search.
*/
if (firstmatch == NULL)
firstmatch = cur;
else
return (Z_INSUFFICIENT_SPEC);
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
cur = firstmatch;
return (err);
return (err);
if (iptype == ZS_EXCLUSIVE &&
return (err);
return (err);
return (err);
return (Z_OK);
}
static int
{
int err;
return (err);
return (err);
/*
* Do not add these properties when not set, for backwards
* compatibility and because they are optional.
*/
return (err);
return (err);
}
return (err);
} else {
/*
* Default to "true" unless the property value comes from the
* brand
*/
(char *)DTD_ATTR_CONFIGURE_ALLOWED_ADDRESS,
err != Z_BRAND_DISABLED_VAL &&
err != Z_BRAND_DISABLED_CFG &&
err != Z_BRAND_FIXED_CFG)
return (err);
DTD_ENTITY_TRUE)) != Z_OK)
return (err);
}
}
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
static int
{
continue;
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
struct zone_nettab *newtabptr)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
continue;
int
{
int err;
return (Z_INVAL);
return (Z_INSUFFICIENT_SPEC);
return (err);
/*
* Iterate over the configuration's elements and look for anet elements
* that match the query.
*/
firstmatch = NULL;
/* Skip non-anet elements */
continue;
/*
* If any relevant fields don't match the query, then skip
* the current net element.
* TBD
*/
/*
* The current anet element matches the query. Select it if
* it's the first match; otherwise, abort the search.
*/
if (firstmatch == NULL)
firstmatch = cur;
else
return (Z_INSUFFICIENT_SPEC);
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
cur = firstmatch;
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (Z_OK);
}
static int
{
int err;
return (err);
/* mandatory */
return (err);
/* optional */
return (err);
return (err);
}
return (err);
} else {
/*
* Default to "true" unless the property value comes from the
* brand
*/
(char *)DTD_ATTR_CONFIGURE_ALLOWED_ADDRESS,
err != Z_BRAND_DISABLED_VAL &&
err != Z_BRAND_DISABLED_CFG &&
err != Z_BRAND_FIXED_CFG)
return (err);
DTD_ENTITY_TRUE)) != Z_OK)
return (err);
}
}
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
static int
{
continue;
/*
* Each anet resource will have a unique linkname,
* so we only need to match the linkname for deletion.
*/
tabptr->zone_anet_linkname)) {
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
/*
* Must be a comma-separated list of alpha-numeric file system names.
*/
static int
{
char *p;
return (Z_TOO_BIG);
while (*cp != '\0') {
p = cp;
while (*p != '\0' && *p != ',') {
if (!isalnum(*p))
return (Z_INVALID_PROPERTY);
p++;
}
if (*p == ',') {
if (p == cp)
return (Z_INVALID_PROPERTY);
p++;
if (*p == '\0')
return (Z_INVALID_PROPERTY);
}
cp = p;
}
return (Z_OK);
}
int
{
int err;
return (err);
if (bufp[0] == '\0')
return (Z_BAD_PROPERTY);
return (zonecfg_valid_fs_allowed(bufp));
}
int
{
int err;
return (err);
}
/*
* Determines if the specified string is a valid hostid string. This function
* returns Z_OK if the string is a valid hostid string. It returns Z_INVAL if
* 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
* containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if
* the string has an invalid format.
*/
static int
{
char *currentp;
return (Z_INVAL);
/* Empty strings and strings with whitespace are invalid. */
if (*hostidp == '\0')
return (Z_INVALID_PROPERTY);
return (Z_INVALID_PROPERTY);
}
/*
* The caller might pass a hostid that is larger than the maximum
* unsigned 32-bit integral value. Check for this! Also, make sure
* that the whole string is converted (this helps us find illegal
* characters) and that the whole string fits within a buffer of size
* HW_HOSTID_LEN.
*/
currentp += 2;
return (Z_TOO_BIG);
return (Z_INVALID_PROPERTY);
return (Z_OK);
}
/*
* Gets the zone hostid string stored in the specified zone configuration
* document. This function returns Z_OK on success. Z_BAD_PROPERTY is returned
* if the config file doesn't specify a hostid or if the hostid is blank.
*
* Note that buflen should be at least HW_HOSTID_LEN.
*/
int
{
int err;
return (err);
if (bufp[0] == '\0')
return (Z_BAD_PROPERTY);
return (zonecfg_valid_hostid(bufp));
}
/*
* Sets the hostid string in the specified zone config document to the given
* string value. If 'hostidp' is NULL, then the config document's hostid
* attribute is cleared. Non-NULL hostids are validated. This function returns
* Z_OK on success. Any other return value indicates failure.
*/
int
{
int err;
/*
* A NULL hostid string is interpreted as a request to clear the
* hostid.
*/
return (err);
}
int
{
int err;
return (Z_INVAL);
return (err);
firstmatch = NULL;
continue;
if (firstmatch == NULL)
firstmatch = cur;
else if (firstmatch != cur)
return (Z_INSUFFICIENT_SPEC);
} else {
/*
* If another property matched but this
* one doesn't then reset firstmatch.
*/
if (firstmatch == cur)
firstmatch = NULL;
}
}
if (firstmatch == NULL)
firstmatch = cur;
else if (firstmatch != cur)
return (Z_INSUFFICIENT_SPEC);
} else {
/*
* If another property matched but this
* one doesn't then reset firstmatch.
*/
if (firstmatch == cur)
firstmatch = NULL;
}
}
if (firstmatch == NULL)
firstmatch = cur;
else if (firstmatch != cur)
return (Z_INSUFFICIENT_SPEC);
} else {
/*
* If another property matched but this
* one doesn't then reset firstmatch.
*/
if (firstmatch == cur)
firstmatch = NULL;
}
}
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
cur = firstmatch;
return (err);
return (err);
return (err);
return (Z_OK);
}
static int
{
int err;
return (err);
return (err);
return (err);
}
return (err);
}
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
static int
{
int match_match;
int partition_match;
int raw_io_match;
continue;
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
struct zone_devtab *oldtabptr,
struct zone_devtab *newtabptr)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
static int
char *zonename)
{
int err;
return (err);
return (err);
return (err);
if ((err = zonecfg_remove_userauths(
return (err);
return (Z_OK);
}
int
char *zonename)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
static int
char *zonename)
{
int err;
continue;
if (auth_match) {
if ((err = zonecfg_insert_userauths(
return (err);
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
char *zonename)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
!= Z_OK)
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
firstmatch = NULL;
continue;
if (firstmatch == NULL)
firstmatch = cur;
else
return (Z_INSUFFICIENT_SPEC);
}
}
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
cur = firstmatch;
return (err);
return (err);
return (Z_OK);
}
/*
* This function finds everything mounted under a zone's rootpath.
* This returns the number of mounts under rootpath, or -1 on error.
* callback is called once per mount found with the first argument
* pointing to a mnttab structure containing the mount's information.
*
* If the callback function returns non-zero zonecfg_find_mounts
* aborts with an error.
*/
int
void *), void *priv) {
struct mnttab m;
size_t l;
int zfsl;
int rv = 0;
>= sizeof (zfs_path))
return (-1);
return (-1);
rv = -1;
goto out;
}
(m.mnt_mountp[l] == '/') &&
rv++;
continue;
rv = -1;
goto out;
}
}
}
out:
return (rv);
}
int
{
int err;
return (Z_INVAL);
return (err);
firstmatch = NULL;
continue;
if (firstmatch == NULL)
firstmatch = cur;
else
return (Z_INSUFFICIENT_SPEC);
}
}
if (firstmatch == NULL)
firstmatch = cur;
else if (firstmatch != cur)
return (Z_INSUFFICIENT_SPEC);
} else {
/*
* If another property matched but this
* one doesn't then reset firstmatch.
*/
if (firstmatch == cur)
firstmatch = NULL;
}
}
}
0) {
if (firstmatch == NULL)
firstmatch = cur;
else if (firstmatch != cur)
return (Z_INSUFFICIENT_SPEC);
} else {
/*
* If another property matched but this
* one doesn't then reset firstmatch.
*/
if (firstmatch == cur)
firstmatch = NULL;
}
}
}
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
cur = firstmatch;
return (err);
return (err);
return (err);
return (Z_OK);
}
static int
{
int err;
return (err);
return (err);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
static int
{
continue;
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
struct zone_attrtab *oldtabptr,
struct zone_attrtab *newtabptr)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
int
{
return (Z_INVAL);
return (Z_INVAL);
return (Z_OK);
}
return (Z_OK);
}
return (Z_INVAL);
}
int
{
long long result;
char *endptr;
return (Z_INVAL);
return (Z_INVAL);
errno = 0;
return (Z_INVAL);
return (Z_OK);
}
int
{
return (Z_INVAL);
return (Z_INVAL);
return (Z_TOO_BIG);
return (Z_OK);
}
int
{
unsigned long long result;
long long neg_result;
char *endptr;
return (Z_INVAL);
return (Z_INVAL);
errno = 0;
return (Z_INVAL);
errno = 0;
/*
* Incredibly, strtoull("<negative number>", ...) will not fail but
* return whatever (negative) number cast as a u_longlong_t, so we
* need to look for this here.
*/
if (errno == 0 && neg_result < 0)
return (Z_INVAL);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
continue;
sizeof (struct zone_rctlvaltab));
return (Z_NOMEM);
sizeof (valptr->zone_rctlval_priv)) !=
Z_OK))
break;
sizeof (valptr->zone_rctlval_limit)) !=
Z_OK))
break;
sizeof (valptr->zone_rctlval_action)) !=
Z_OK))
break;
Z_OK)
break;
}
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
static int
{
int err;
return (err);
return (err);
return (err);
return (err);
return (err);
}
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
static int
{
continue;
tabptr->zone_rctl_name)) {
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
struct zone_rctltab *oldtabptr,
struct zone_rctltab *newtabptr)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
int
struct zone_rctltab *tabptr,
struct zone_rctlvaltab *valtabptr)
{
return (Z_INVAL);
if (!zonecfg_valid_rctlblk(rctlblk))
return (Z_INVAL);
else
return (Z_OK);
}
int
struct zone_rctltab *tabptr,
struct zone_rctlvaltab *valtabptr)
{
valtabptr->zone_rctlval_priv) == 0 &&
valtabptr->zone_rctlval_limit) == 0 &&
valtabptr->zone_rctlval_action) == 0) {
else
return (Z_OK);
} else
}
return (Z_NO_PROPERTY_ID);
}
char *
{
switch (errnum) {
case Z_OK:
case Z_EMPTY_DOCUMENT:
case Z_WRONG_DOC_TYPE:
case Z_BAD_PROPERTY:
case Z_TEMP_FILE:
return (dgettext(TEXT_DOMAIN,
"Problem creating temporary file"));
case Z_SAVING_FILE:
case Z_NO_ENTRY:
case Z_BOGUS_ZONE_NAME:
case Z_REQD_RESOURCE_MISSING:
case Z_REQD_PROPERTY_MISSING:
case Z_BAD_HANDLE:
case Z_NOMEM:
case Z_INVAL:
case Z_ACCES:
case Z_TOO_BIG:
case Z_MISC_FS:
return (dgettext(TEXT_DOMAIN,
"Miscellaneous file system error"));
case Z_NO_ZONE:
case Z_NO_RESOURCE_TYPE:
case Z_NO_RESOURCE_ID:
case Z_NO_PROPERTY_TYPE:
case Z_NO_PROPERTY_ID:
case Z_BAD_ZONE_STATE:
return (dgettext(TEXT_DOMAIN,
"Zone state is invalid for the requested operation"));
case Z_INVALID_DOCUMENT:
case Z_NAME_IN_USE:
case Z_NO_SUCH_ID:
case Z_UPDATING_INDEX:
case Z_LOCKING_FILE:
case Z_UNLOCKING_FILE:
case Z_INSUFFICIENT_SPEC:
case Z_RESOLVED_PATH:
case Z_IPV6_ADDR_PREFIX_LEN:
return (dgettext(TEXT_DOMAIN,
"IPv6 address missing required prefix length"));
case Z_BOGUS_ADDRESS:
return (dgettext(TEXT_DOMAIN,
"Neither an IPv4 nor an IPv6 address nor a host name"));
case Z_PRIV_PROHIBITED:
return (dgettext(TEXT_DOMAIN,
"Specified privilege is prohibited"));
case Z_PRIV_REQUIRED:
return (dgettext(TEXT_DOMAIN,
"Required privilege is missing"));
case Z_PRIV_UNKNOWN:
return (dgettext(TEXT_DOMAIN,
"Specified privilege is unknown"));
case Z_BRAND_ERROR:
return (dgettext(TEXT_DOMAIN,
"Brand-specific error"));
case Z_BRAND_DISABLED_CFG:
return (dgettext(TEXT_DOMAIN,
"Brand doesn't support this property or resource"));
case Z_BRAND_DISABLED_VAL:
return (dgettext(TEXT_DOMAIN,
"Brand doesn't support setting this property value"));
case Z_BRAND_FIXED_CFG:
return (dgettext(TEXT_DOMAIN,
"Brand doesn't support setting this property"));
case Z_INCOMPATIBLE:
case Z_ALIAS_DISALLOW:
return (dgettext(TEXT_DOMAIN,
"An incompatible rctl already exists for this property"));
case Z_CLEAR_DISALLOW:
return (dgettext(TEXT_DOMAIN,
"Clearing this property is not allowed"));
case Z_POOL:
case Z_POOLS_NOT_ACTIVE:
"zone will not be bound to pool"));
case Z_POOL_ENABLE:
return (dgettext(TEXT_DOMAIN,
"Could not enable pools facility"));
case Z_NO_POOL:
return (dgettext(TEXT_DOMAIN,
"Pool not found; using default pool"));
case Z_POOL_CREATE:
return (dgettext(TEXT_DOMAIN,
"Could not create a temporary pool"));
case Z_POOL_BIND:
case Z_INVALID_PROPERTY:
case Z_POSSIBLE_CONFLICT:
return (dgettext(TEXT_DOMAIN,
case Z_SYSTEM:
case Z_STORAGE_MISC:
return (dgettext(TEXT_DOMAIN,
"Miscellaneous storage resource error"));
case Z_STORAGE_INUSE:
return (dgettext(TEXT_DOMAIN,
"Storage resource or zpool already in use"));
case Z_STORAGE_AGAIN:
return (dgettext(TEXT_DOMAIN,
"Storage resource or zpool busy"));
case Z_DUP_PROPERTY:
return (dgettext(TEXT_DOMAIN,
"Duplicate property value"));
default:
}
}
/*
* Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
* same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
*/
static int
{
int err;
return (Z_INVAL);
return (err);
}
return (Z_OK);
}
static int
{
return (Z_INVAL);
return (Z_OK);
}
/*
* Do the work required to manipulate a process through libproc.
* If grab_process() returns no errors (0), then release_process()
* must eventually be called.
*
* Return values:
* 0 Successful creation of agent thread
* 1 Error grabbing
* 2 Error creating agent
*/
static int
{
int ret;
return (1);
}
if (Pcreate_agent(p->pr) == 0) {
return (0);
} else {
return (2);
}
} else {
return (1);
}
}
/*
* Release the specified process. This destroys the agent
* and releases the process. If the process is NULL, nothing
* is done. This function should only be called if grab_process()
* has previously been called and returned success.
*
* This function is Pgrab-safe.
*/
static void
{
return;
}
static boolean_t
{
int pid_self;
return (B_FALSE);
return (B_FALSE);
/* Skip self */
continue;
continue;
continue;
/* attempt to grab process */
if (grab_process(p) != 0)
continue;
release_process(p->pr);
continue;
}
return (B_TRUE);
}
return (B_FALSE);
}
static boolean_t
{
return (B_FALSE);
return (B_TRUE);
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Apply the current rctl settings to the specified, running zone.
*/
int
{
int err;
return (err);
(void) zonecfg_endrctlent(handle);
return (Z_NOMEM);
}
if (!grab_zone_proc(zone_name, &p)) {
(void) zonecfg_endrctlent(handle);
return (Z_SYSTEM);
}
char *rname;
/* first delete all current privileged settings for this rctl */
0) {
goto done;
}
}
/* now set each new value for the rctl */
!= Z_OK) {
goto done;
}
goto done;
}
}
}
done:
release_process(p.pr);
(void) zonecfg_endrctlent(handle);
return (res);
}
int
{
int num = 0;
return (num);
return (num);
num++;
(void) zonecfg_endent(handle);
return (num);
}
int
{
int err;
return (Z_NO_RESOURCE_TYPE);
return (err);
continue;
}
}
(void) zonecfg_endent(handle);
return (Z_OK);
}
static boolean_t
{
char *endp;
/* strtoull accepts '-'?! so we want to flag that as an error */
return (B_FALSE);
errno = 0;
return (B_FALSE);
return (B_TRUE);
}
/*
* Convert a string representing a number (possibly a fraction) into an integer.
* The string can have a modifier (K, M, G or T). The modifiers are treated
* as powers of two (not 10).
*/
int
{
long double val;
char *unitp;
*bytes = 0;
return (-1);
/* remove any leading white space from units string */
++unitp;
/* if no units explicitly set, error */
scale = 1;
} else {
int i;
scale = 1024;
/* update scale based on units */
break;
scale <<= 10;
}
return (-1);
}
return (0);
}
{
return (B_FALSE);
return (B_TRUE);
}
{
return (B_FALSE);
return (B_TRUE);
}
{
int i;
break;
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
}
{
return (B_FALSE);
return (B_TRUE);
}
static int
{
return (res);
}
static int
{
/* set the maximum number of cpus for the pset */
}
/* set the minimum number of cpus for the pset */
}
return (Z_OK);
}
static int
struct zone_psettab *pset_tab)
{
/* create a temporary pool configuration */
return (res);
}
goto done;
}
/* set pool importance */
goto done;
}
goto done;
}
!= PO_SUCCESS) {
goto done;
}
}
goto done;
/* validation */
goto done;
}
/*
* This validation is the one we expect to fail if the user specified
* an invalid configuration (too many cpus) for this system.
*/
goto done;
}
/*
* Commit the dynamic configuration but not the pool configuration
* file.
*/
done:
(void) pool_conf_close(pconf);
return (res);
}
static int
struct zone_psettab *pset_tab)
{
int nfound = 0;
!= POC_INVAL) {
nfound++;
}
}
nfound++;
}
nfound++;
}
}
if (nfound == 3)
return (PO_SUCCESS);
return (PO_FAIL);
}
/*
* Determine if a tmp pool is configured and if so, if the configuration is
* still valid or if it has been changed since the tmp pool was created.
* If the tmp pool configuration is no longer valid, delete the tmp pool.
*
* Set *valid=B_TRUE if there is an existing, valid tmp pool configuration.
*/
static int
{
!= PO_SUCCESS) {
return (res);
}
/* no tmp pool configured */
goto done;
}
/*
* If an existing tmp pool for this zone is configured with the proper
* settings, then the tmp pool is valid.
*/
== PO_SUCCESS &&
pset_current.zone_ncpu_min) == 0 &&
pset_current.zone_ncpu_max) == 0 &&
pset_current.zone_importance) == 0) {
} else {
/*
* An out-of-date tmp pool configuration exists. Delete it
* so that we can create the correct tmp pool config.
*/
goto done;
}
goto done;
}
/* commit dynamic config */
}
done:
(void) pool_conf_close(pconf);
return (res);
}
/*
* Destroy any existing tmp pool.
*/
int
{
int status;
/* if pools not enabled then nothing to do */
return (Z_OK);
!= PO_SUCCESS) {
return (res);
}
/* nothing to destroy, we're done */
goto done;
}
goto done;
}
goto done;
}
/* commit dynamic config */
done:
(void) pool_conf_close(pconf);
return (res);
}
/*
* Attempt to bind to a tmp pool for this zone. If there is no tmp pool
* configured, we just return Z_OK.
*
* We either attempt to create the tmp pool for this zone or rebind to an
* existing tmp pool for this zone.
*
* Rebinding is used when a zone with a tmp pool reboots so that we don't have
* to recreate the tmp pool. To do this we need to be sure we work correctly
* for the following cases:
*
* - there is an existing, properly configured tmp pool.
* - zonecfg added tmp pool after zone was booted, must now create.
* - zonecfg updated tmp pool config after zone was booted, in this case
* we destroy the old tmp pool and create a new one.
*/
int
int err_size)
{
int err;
int status;
/* if no temporary pool configured, we're done */
if (err == Z_NO_ENTRY)
return (Z_OK);
/*
* importance might not have a value but we need to validate it here,
* so set the default.
*/
sizeof (pset_tab.zone_importance));
/* if pools not enabled, enable them now */
return (Z_POOL_ENABLE);
}
/*
* reuse it.
*/
return (err);
}
if (!exists)
&pset_tab);
return (err);
/* Bind the zone to the pool. */
return (Z_OK);
}
/*
* Attempt to bind to a permanent pool for this zone. If there is no
* permanent pool configured, we just return Z_OK.
*/
int
int err_size)
{
int status;
int error;
/*
* Find the pool mentioned in the zone configuration, and bind to it.
*/
/*
* The property is not set on the zone, so the pool
* should be bound to the default pool. But that's
* already done by the kernel, so we can just return.
*/
return (Z_OK);
}
/*
* Not an error, even though it shouldn't be happening.
*/
return (Z_OK);
}
/*
* Don't do anything if pools aren't enabled.
*/
return (Z_POOLS_NOT_ACTIVE);
/*
* Try to provide a sane error message if the requested pool doesn't
* exist.
*/
PO_SUCCESS) {
}
(void) pool_conf_close(poolconf);
return (Z_NO_POOL);
/*
* Bind the zone to the pool.
*/
/* if bind fails, return poolname for the error msg */
return (Z_POOL_BIND);
}
return (Z_OK);
}
int
{
int err;
return (err);
/* pset was found so a temporary pool was created */
return (Z_OK);
}
/* lookup the poolname in zonecfg */
}
static boolean_t
{
*scf_simple_prop_next_boolean(prop) != 0)
return (found);
}
/*
* If the zone has capped-memory, make sure the rcap service is enabled.
*/
int
{
if (!svc_enabled(RCAP_SERVICE) &&
return (Z_SYSTEM);
}
return (Z_OK);
}
/*
* Return true if pset has cpu range specified and poold is not enabled.
*/
{
int err;
/* if no temporary pool configured, we're done */
if (err == Z_NO_ENTRY)
return (B_FALSE);
/* range not specified, no need for poold */
return (B_FALSE);
/* we have a range, check if poold service is enabled */
if (svc_enabled(POOLD_SERVICE))
return (B_FALSE);
return (B_TRUE);
}
/*
* Retrieve the specified pool's thread scheduling class. 'poolname' must
* refer to the name of a configured resource pool. The thread scheduling
* class specified by the pool will be stored in the buffer to which 'class'
* points. 'clsize' is the byte size of the buffer to which 'class' points.
*
* This function returns Z_OK if it successfully stored the specified pool's
* thread scheduling class into the buffer to which 'class' points. It returns
* Z_NO_POOL if resource pools are not enabled, the function is unable to
* access the system's resource pools configuration, or the specified pool
* does not exist. The function returns Z_TOO_BIG if the buffer to which
* 'class' points is not large enough to contain the thread scheduling class'
* name. The function returns Z_NO_ENTRY if the pool does not specify a thread
* scheduling class.
*/
static int
{
int status;
const char *sched_str;
return (Z_NO_POOL);
return (Z_NO_POOL);
PO_SUCCESS) {
return (Z_NO_POOL);
}
(void) pool_conf_close(poolconf);
return (Z_NO_POOL);
}
POC_STRING) {
(void) pool_conf_close(poolconf);
return (Z_NO_ENTRY);
}
(void) pool_conf_close(poolconf);
return (Z_TOO_BIG);
return (Z_OK);
}
/*
* Get the default scheduling class for the zone. This will either be the
* class set on the zone's pool or the system default scheduling class.
*/
int
{
/* check if the zone's pool specified a sched class */
return (Z_OK);
}
return (Z_TOO_BIG);
return (Z_OK);
}
int
{
return (zonecfg_setent(handle));
}
static xmlNodePtr
{
/*
* Before searching the doc, the brand needs to be checked to see if
* the resource has been disabled.
*/
return (NULL);
return (NULL);
}
break;
}
return (cur);
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
/* OK for options to be NULL */
sizeof (options_str)) != Z_OK)
break;
break;
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
return (err);
}
return (err);
/* Default to "true" if not set */
>= sz)
return (Z_TOO_BIG);
}
return (err);
}
return (err);
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
/* Default to "true" if not set */
return (Z_TOO_BIG);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (err);
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
return (err);
}
return (err);
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
sizeof (struct zone_rctlvaltab));
return (Z_NOMEM);
break;
break;
break;
break;
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
return (err);
}
return (err);
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
return (err);
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
/*
* The privileges available on the system and described in privileges(5)
* fall into four categories with respect to non-global zones:
*
* Default set of privileges considered safe for all non-global
* zones. These privileges are "safe" in the sense that a
* privileged process in the zone cannot affect processes in any
* other zone on the system.
*
* Set of privileges not currently permitted within a non-global
* zone. These privileges are considered by default, "unsafe,"
* and include ones which affect global resources (such as the
* system clock or physical memory) or are overly broad and cover
* more than one mechanism in the system. In other cases, there
* has not been sufficient virtualization in the parts of the
* system the privilege covers to allow its use within a
* non-global zone.
*
* Set of privileges required in order to get a zone booted and
* init(1M) started. These cannot be removed from the zone's
* privilege set.
*
* All other privileges are optional and are potentially useful for
* processes executing inside a non-global zone.
*
* When privileges are added to the system, a determination needs to be
* made as to which category the privilege belongs to. Ideally,
* privileges should be fine-grained enough and the mechanisms they cover
* virtualized enough so that they can be made available to non-global
* zones.
*/
/*
* Define some of the tokens that priv_str_to_set(3C) recognizes. Since
* the privilege string separator can be any character, although it is
* usually a comma character, define these here as well in the event that
* they change or are augmented in the future.
*/
typedef struct priv_node {
} priv_node_t;
/* Privileges lists can differ across brands */
typedef struct priv_lists {
/* Privileges considered safe for all non-global zones of a brand */
/* Privileges not permitted for all non-global zones of a brand */
/* Privileges required for all non-global zones of a brand */
/*
* ip-type of the zone these privileges lists apply to.
* It is used to pass ip-type to the callback function,
* priv_lists_cb, which has no way of getting the ip-type.
*/
const char *pl_iptype;
} priv_lists_t;
static int
{
/* Skip this privilege if ip-type does not match */
return (0);
/* Allocate a new priv list node. */
return (-1);
return (-1);
}
/* Insert the new priv list node into the right list */
} else {
return (-1);
}
return (0);
}
static void
{
}
}
}
}
static int
const char *curr_iptype)
{
/* handle or brand must be set, but never both */
return (Z_BRAND_ERROR);
} else {
return (Z_BRAND_ERROR);
}
return (Z_NOMEM);
}
/* construct the privilege lists */
return (Z_BRAND_ERROR);
}
return (Z_OK);
}
static int
{
return (Z_INVAL);
}
return (Z_OK);
}
/*
* This function retrieves the property value of the zonecfg/default_template
* value into the template argument.
*/
int
{
DEFAULT_TEMPLATE_PROPNAME)) != NULL) {
else
}
}
return (ret);
}
/*
* The default brand is the global zone's brand, or the current zone's brand
* if called from within a non-global zone.
*/
int
{
int ret;
/*
* If we're running within a zone, then the default brand is the
* current zone's brand.
*/
if (myzoneid != GLOBAL_ZONEID) {
if (ret < 0)
return (Z_OK);
}
return (Z_NOMEM);
/*
* If we're operating on an alternate root, try the old system
* default template, as we could be querying an old boot
* environment.
*/
}
return (ret);
}
return (ret);
}
int
{
int ret;
return (ret);
return (ret);
return (ret);
}
void
{
if (*str != '\0')
}
/*
* Verify that the supplied string is a valid privilege limit set for a
* non-global zone. This string must not only be acceptable to
* priv_str_to_set(3C) which parses it, but it also must resolve to a
* privilege set that includes certain required privileges and lacks
* certain prohibited privileges.
*/
static int
{
const char *token;
/*
* The verification of the privilege string occurs in several
* phases. In the first phase, the supplied string is scanned for
* the ZONE_TOKEN token which is not support as part of the
* "limitpriv" property.
*
* Duplicate the supplied privilege string since strtok_r(3C)
* tokenizes its input by null-terminating the tokens.
*/
return (Z_NOMEM);
return (Z_NOMEM);
else
return (Z_PRIV_UNKNOWN);
}
}
if (add_default) {
/*
* If DEFAULT_TOKEN was specified, a string needs to be
* built containing the privileges from the default, safe
* set along with those of the "limitpriv" property.
*/
*tmp = '\0';
} else {
}
/*
* In the next phase, attempt to convert the merged privilege
* string into a privilege set. In the case of an error, either
* there was a memory allocation failure or there was an invalid
* privilege token in the string. In either case, return an
* appropriate error code but in the event of an invalid token,
* allocate a string containing its name and return that back to
* the caller.
*/
return (Z_NOMEM);
*cp = '\0';
return (Z_NOMEM);
else
return (Z_PRIV_UNKNOWN);
}
/*
* Next, verify that none of the prohibited zone privileges are
* present in the merged privilege set.
*/
return (Z_NOMEM);
else
return (Z_PRIV_PROHIBITED);
}
}
/*
* Finally, verify that all of the required zone privileges are
* present in the merged privilege set.
*/
return (Z_NOMEM);
else
return (Z_PRIV_REQUIRED);
}
}
return (Z_OK);
}
/*
* Fill in the supplied privilege set with either the default, safe set of
* privileges suitable for a non-global zone, or one based on the
* "limitpriv" property in the zone's configuration.
*
* In the event of an invalid privilege specification in the
* configuration, a string is allocated and returned containing the
* "privilege" causing the issue. It is the caller's responsibility to
* free this memory when it is done with it.
*/
int
char **privname)
{
const char *curr_iptype;
/*
* Attempt to lookup the "limitpriv" property. If it does not
* exist or matches the string DEFAULT_TOKEN exactly, then the
* default, safe privilege set is returned.
*/
return (err);
return (err);
switch (iptype) {
case ZS_SHARED:
curr_iptype = "shared";
break;
case ZS_EXCLUSIVE:
curr_iptype = "exclusive";
break;
}
return (err);
return (err);
}
/*
* Check if the string DEFAULT_TOKEN is the first token in a list
* of privileges.
*/
else
return (err);
}
int
{
int err;
char *cp;
return (Z_INVAL);
*--cp = '\0';
if (zonepath[0] == '\0')
return (Z_OK);
}
/*
* First check the index file. Because older versions did not have
* a copy of the zone path, allow for it to be zero length, in which
* case we ignore this result and fall back to the XML files.
*/
cookie = setzoneent();
}
if (found)
break;
}
return (Z_OK);
/* Fall back to the XML files. */
return (Z_NOMEM);
/*
* Check the snapshot first: if a zone is running, its zonepath
* may have changed.
*/
return (err);
}
}
return (err);
}
int
{
int err;
/* This function makes sense for non-global zones only. */
return (Z_BOGUS_ZONE_NAME);
return (err);
return (Z_TOO_BIG);
return (Z_OK);
}
int
{
int err;
/*
* If we are not in the global zone, then we don't have the zone
* .xml files with the brand name available. Thus, we are going to
* have to ask the kernel for the information.
*/
if (myzoneid != GLOBAL_ZONEID) {
if (is_system_labeled()) {
return (Z_OK);
}
sizeof (myzone)) < 0)
return (Z_NO_ZONE);
if (!zonecfg_is_scratch(myzone)) {
return (Z_NO_ZONE);
}
if (err < 0)
return (Z_OK);
}
return (Z_NOMEM);
return (err);
}
/*
* Return the appropriate root for the active /dev.
*/
int
{
int err;
char *suffix;
/* This function makes sense for non-global zones only. */
return (Z_BOGUS_ZONE_NAME);
return (err);
suffix = "/lu";
else
suffix = "/root";
return (Z_TOO_BIG);
return (Z_OK);
}
static zone_state_t
{
switch (kernel_state) {
case ZONE_IS_UNINITIALIZED:
case ZONE_IS_INITIALIZED:
/* The kernel will not return these two states */
return (ZONE_STATE_READY);
case ZONE_IS_READY:
case ZONE_IS_DOWN:
/*
* it's a mounted scratch zone.
*/
sizeof (zoneroot)) >= 0) {
if (zlen > 3 &&
return (ZONE_STATE_MOUNTED);
}
return (kernel_state == ZONE_IS_READY ?
case ZONE_IS_BOOTING:
case ZONE_IS_RUNNING:
return (ZONE_STATE_RUNNING);
case ZONE_IS_SHUTTING_DOWN:
case ZONE_IS_EMPTY:
return (ZONE_STATE_SHUTTING_DOWN);
case ZONE_IS_DYING:
case ZONE_IS_DEAD:
default:
return (ZONE_STATE_DOWN);
}
/* NOTREACHED */
}
int
{
return (Z_INVAL);
/*
* If we're looking at an alternate root, then we need to query the
* kernel using the scratch zone name.
*/
zone_id = -1;
}
} else {
}
/* check to see if zone is running */
if (zone_id != -1 &&
sizeof (status)) >= 0) {
return (Z_OK);
}
cookie = setzoneent();
}
if (found)
break;
}
}
int
{
return (Z_INVAL);
}
/*
* Get id (if any) for specified zone. There are four possible outcomes:
* - If the string corresponds to the numeric id of an active (booted)
* zone, sets *zip to the zone id and returns 0.
* - If the string corresponds to the name of an active (booted) zone,
* sets *zip to the zone id and returns 0.
* - If the string is a name in the configuration but is not booted,
* sets *zip to ZONE_ID_UNDEFINED and returns 0.
* - Otherwise, leaves *zip unchanged and returns -1.
*
* This function acts as an auxiliary filter on the function of the same
* name in libc; the linker binds to this version if libzonecfg exists,
* and the libc version if it doesn't. Any changes to this version of
* the function should probably be reflected in the libc version as well.
*/
int
{
char *cp;
int err;
/* first try looking for active zone by id */
errno = 0;
return (0);
}
/* then look for active zone by name */
return (0);
}
/* if in global zone, try looking up name in configuration database */
if (getzoneid() != GLOBAL_ZONEID ||
return (-1);
/* zone exists but isn't active */
*zip = ZONE_ID_UNDEFINED;
err = 0;
} else {
err = -1;
}
return (err);
}
char *
{
if (state_num < ZONE_STATE_CONFIGURED ||
/* Be sure states are maintained properly. */
}
{
int i;
for (i = 0; i < ZONE_STATE_INVALID; i++) {
/* Be sure states are maintained properly. */
return (zone_states[i].zone_state);
}
return (ZONE_STATE_INVALID);
}
/*
* Given a UUID value, find an associated zone name. This is intended to be
* used by callers who set up some 'default' name (corresponding to the
* expected name for the zone) in the zonename buffer, and thus the function
* doesn't touch this buffer on failure.
*/
int
{
/*
* A small amount of subterfuge via casts is necessary here because
* libuuid doesn't use const correctly, but we don't want to export
* this brokenness to our clients.
*/
if (uuid_is_null(uuid))
return (Z_NO_ZONE);
return (Z_NO_ZONE);
break;
}
endzoneent(fp);
return (Z_OK);
} else {
return (Z_NO_ZONE);
}
}
/*
* Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone
* exists but the file doesn't have a value set yet. Returns an error if the
* zone cannot be located.
*/
int
{
return (Z_NO_ZONE);
break;
}
endzoneent(fp);
return (Z_OK);
} else {
return (Z_NO_ZONE);
}
}
/*
* File-system convenience functions.
*/
{
/*
* We already know which FS types don't work.
*/
return (B_FALSE);
/*
* The caller may do more detailed verification to make sure other
* aspects of this filesystem type make sense.
*/
return (B_TRUE);
}
/*
* Generally uninteresting rctl convenience functions.
*/
int
{
unsigned long long ull;
char *endp;
/* Get the privilege */
priv = RCPRIV_BASIC;
} else {
/* Invalid privilege */
return (Z_INVAL);
}
/* deal with negative input; strtoull(3c) doesn't do what we want */
return (Z_INVAL);
/* Get the limit */
errno = 0;
/* parse failed */
return (Z_INVAL);
}
/* Get the action */
} else {
/* Invalid Action */
return (Z_INVAL);
}
return (Z_OK);
}
static int
{
/*
* Returning 1 here is our signal to zonecfg_is_rctl() that it is
* indeed an rctl name recognized by the system.
*/
}
{
}
{
const char *c;
return (B_FALSE);
return (B_FALSE);
if (!isalpha(*c) && *c != '-')
return (B_FALSE);
}
return (B_TRUE);
}
{
if (priv != RCPRIV_PRIVILEGED)
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
}
{
if (!zonecfg_valid_rctlblk(rctlblk))
return (B_FALSE);
if (!zonecfg_valid_rctlname(name))
return (B_FALSE);
return (B_TRUE); /* not an rctl on this system */
/*
* Make sure the proposed value isn't greater than the current system
* value.
*/
return (B_FALSE); /* shouldn't happen */
}
return (B_FALSE);
/*
* Make sure the proposed action is allowed.
*/
if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
return (B_FALSE);
if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
return (B_FALSE);
return (B_TRUE);
}
/*
* There is always a race condition between reading the initial copy of
* a zones state and its state changing. We address this by providing
* zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
* When zonecfg_critical_enter is called, sets the state field to LOCKED
* and aquires biglock. Biglock protects against other threads executing
* critical_enter and the state field protects against state changes during
* the critical period.
*
* If any state changes occur, zn_cb will set the failed field of the znotify
* structure. This will cause the critical_exit function to re-lock the
* channel and return an error. Since evsnts may be delayed, the critical_exit
* function "flushes" the queue by putting an event on the queue and waiting for
* zn_cb to notify critical_exit that it received the ping event.
*/
static const char *
{
int i = 0;
i++;
if (*in == 0)
return (NULL);
}
return (in);
}
static boolean_t
{
ZONE_EVENT_PING_SUBCLASS) == 0) {
return (B_TRUE);
} else {
return (B_FALSE);
}
}
static boolean_t
{
const char *sender;
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
}
static int
{
nvlist_t *l;
int zid;
char *zonename;
char *newstate;
char *oldstate;
int ret;
ZONE_EVENT_STATUS_SUBCLASS) == 0) {
if (sysevent_get_attr_list(ev, &l) != 0) {
return (EAGAIN);
}
return (0);
}
ret = 0;
== 0) &&
== 0) &&
}
zevtchan->zn_failure_count = 0;
nvlist_free(l);
return (ret);
} else {
/*
* We have received an event in an unknown subclass. Ignore.
*/
zevtchan->zn_failure_count = 0;
return (0);
}
}
static int
{
int error;
return (0);
}
return (0);
}
return (0);
} else {
return (0);
}
}
/*
* Every ENOMEM failure causes do_callback to increment
* zn_failure_count and every success causes it to
* set zn_failure_count to zero. If we got EAGAIN,
* we will sleep for zn_failure_count seconds and return
* EAGAIN to gpec to try again.
*
* After 55 seconds, or 10 try's we give up and drop the
* event.
*/
return (0);
}
}
return (error);
}
return (0);
}
abort();
}
void
zonecfg_notify_critical_enter(void *h)
{
}
int
zonecfg_notify_critical_exit(void * h)
{
return (0);
}
return (1);
}
return (0);
}
void
zonecfg_notify_critical_abort(void *h)
{
/*
* Don't do anything about zn_lock. If it is held, it could only be
* held by zn_cb and it will be unlocked soon.
*/
}
void *
void *p)
{
int i = 1;
int r;
return (NULL);
zevtchan->zn_private = p;
goto out3;
goto out3;
}
goto out3;
}
0) != 0)
goto out2;
do {
/*
* At 4 digits the subscriber ID gets too long and we have
* no chance of successfully registering.
*/
if (i > 999)
goto out1;
getpid() % 999999l, i);
zevtchan, 0);
i++;
} while (r);
return (zevtchan);
out1:
out2:
out3:
return (NULL);
}
void
{
int ret;
/*
* Check that all evc threads have gone away. This should be
* enforced by sysevent_evc_unbind.
*/
if (ret)
abort();
}
static int
{
int err;
return (err);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
static int
{
continue;
tabptr->zone_dataset_name)) {
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
struct zone_dstab *oldtabptr,
struct zone_dstab *newtabptr)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
firstmatch = NULL;
continue;
if (firstmatch == NULL)
firstmatch = cur;
else
return (Z_INSUFFICIENT_SPEC);
}
}
if (firstmatch == NULL)
firstmatch = cur;
else
return (Z_INSUFFICIENT_SPEC);
}
}
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
cur = firstmatch;
return (err);
return (err);
return (Z_OK);
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
/* Dataset alias is an optional property. */
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
/*
* Support for aliased rctls; that is, rctls that have simplified names in
* zonecfg. For example, max-lwps is an alias for a well defined zone.max-lwps
* rctl. If there are multiple existing values for one of these rctls or if
* there is a single value that does not match the well defined template (i.e.
* it has a different action) then we cannot treat the rctl as having an alias
* so we return Z_ALIAS_DISALLOW. That means that the rctl cannot be
* managed in zonecfg via an alias and that the standard rctl syntax must be
* used.
*
* The possible return values are:
* Z_NO_PROPERTY_ID - invalid alias name
* Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition
* Z_NO_ENTRY - no rctl is configured for this alias
* Z_OK - we got a valid rctl for the specified alias
*/
int
{
int i;
int err;
break;
return (Z_NO_PROPERTY_ID);
return (err);
continue;
/*
* If we already saw one of these, we can't have an
* alias since we just found another.
*/
if (found)
return (Z_ALIAS_DISALLOW);
/*
* If we already have one value, we can't have
* an alias since we just found another.
*/
if (found_val)
return (Z_ALIAS_DISALLOW);
break;
break;
break;
}
/* check priv and action match the expected vals */
return (Z_ALIAS_DISALLOW);
}
}
if (found) {
return (Z_OK);
}
return (Z_NO_ENTRY);
}
int
{
int i;
/*
* First check that we have a valid aliased rctl to remove.
* This will catch an rctl entry with non-standard values or
* multiple rctl values for this name. We need to ignore those
* rctl entries.
*/
return (Z_OK);
break;
return (Z_NO_RESOURCE_ID);
sizeof (rctltab.zone_rctl_name));
}
{
case Z_OK:
/*FALLTHRU*/
case Z_NO_ENTRY:
return (B_TRUE);
default:
return (B_FALSE);
}
}
int
{
int i;
int err;
return (Z_ALIAS_DISALLOW);
break;
return (Z_NO_RESOURCE_ID);
/* remove any pre-existing definition for this rctl */
sizeof (rctltab.zone_rctl_name));
return (Z_NOMEM);
sizeof (rctlvaltab->zone_rctlval_priv));
sizeof (rctlvaltab->zone_rctlval_limit));
sizeof (rctlvaltab->zone_rctlval_action));
return (err);
}
static int
{
int err;
return (err);
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
static int
{
int err;
return (err);
if (*pool_importance != '\0') {
return (err);
pool_importance)) != Z_OK)
return (err);
}
return (Z_OK);
}
static int
{
int err;
return (err);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (err);
break;
}
}
/*
* Once we have msets, we should check that a mset
* do not exist before we delete the tmp_pool data.
*/
return (err);
return (res);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
/* this is an optional component */
return (err);
}
return (err);
}
return (err);
}
}
}
return (res);
}
int
{
int err;
return (err);
(void) zonecfg_endent(handle);
return (err);
}
static int
{
int err;
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (err);
continue;
return (Z_OK);
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
/* it is ok if there is no mcap entry */
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
continue;
return (err);
}
return (Z_OK);
}
return (Z_NO_ENTRY);
}
static int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
return (Z_OK);
}
int
{
int err;
return (err);
(void) zonecfg_endent(handle);
return (err);
}
/* PRINTFLIKE1 */
static void
{
}
static void
{
}
/*
* The following routines implement a simple locking mechanism to
* ensure that only one zone utility at a time is able to manipulate
* a given zone. The lock is built on top of an fcntl(2) lock of
* [<altroot>]_PATH_SYSVOL/zones/<zonename>.zoneadm.lock. If a utility
* can grab that lock, it is allowed to manipulate the zone.
*
* One of these lock files is created for each zone (when needed). The
* lock files are not cleaned up (except on system reboot), but since
* there is only one per zone, there is no resource starvation issue.
*
* Since zoneadm may call external applications which in turn invoke
* zoneadm again, we introduce the notion of "lock inheritance". Any
* instance of zoneadm that has another instance in its ancestry is assumed
* to be acting on behalf of the original zoneadm, and is thus allowed to
* manipulate its zone.
*
* This inheritance is implemented by checking if the process holding the
* lock is an ancestor of the current process.
*/
/*
* Check if the supplied pid is an ancestor of the current process.
* Return: 1 if ancestor, 0 if not, -1 on error.
*/
static int
{
int procfd;
do {
return (-1);
}
/*
* Get the info structure for the process and close quickly.
*/
return (-1);
}
if (p == curr)
return (1);
return (0);
}
/*
* Determine which pid (if any) has a lock on the supplied fd.
* Return: 0 if unlocked (or locked by current process) or pid of
* locking process, -1 on error.
*/
static pid_t
{
/*
* Lock the file to synchronize with other utilities
*/
return (-1);
}
return (0);
}
/*
* Ensure the lock file path exists.
* Return: 0 on success, -1 on error.
*/
static int
{
ZONES_TMPDIR) >= sizeof (pathbuf)) {
return (-1);
}
return (-1);
}
return (0);
}
int
{
struct stat s;
int lockfd;
return (-1);
}
return (-1);
}
if (create_lock_file_path(zone_name) < 0)
return (-1);
}
return (-1);
}
/*
* Try to get details of the current lock owner. Return
* an error if we can't get the details.
*/
return (-1);
}
/*
* If an ancestor has previously locked this file,
* return success.
*/
if (owner > 0) {
case -1:
return (-1);
case 0:
break;
case 1:
return (Z_OK);
}
}
/*
* At this point, either the owner is 0 (which means the file is
* locked by this process, or unlocked) or the owner is not
* an ancestor. Try to lock it. We don't wait for the lock, this
* allows the user to control re-try behaviour.
*/
return (-1);
}
/*
* We have locked the file, return success.
*/
return (Z_OK);
}
int
{
struct stat s;
int lockfd;
return (-1);
}
return (-1);
}
return (-1);
}
/*
* Try to get details of the current lock owner. Return
* an error if we can't get the details.
*/
return (-1);
}
/*
* If the file is locked by a non-ancestral process, then we
* cannot unlock it and must return failure. If the owner is
* an ancestor, simply close the file descriptor and return
* success.
*/
if (owner > 0) {
case -1:
case 0:
return (-1);
case 1:
return (Z_OK);
}
}
/*
* At this point, the owner must be 0. This means either that
* the file is unlocked OR that it has been locked by this
* process. In either case, simply closing the file descriptor
* and returning success is the correct course of action.
*/
return (Z_OK);
}
static boolean_t
{
}
/*
* system daemons are not audited. For the global zone, this occurs
* "naturally" since init is started with the default audit
* characteristics. Since zoneadmd is a system daemon and it starts
* init for a zone, it is necessary to clear out the audit
* characteristics inherited from whomever started zoneadmd. This is
* indicated by the audit id, which is set from the ruid parameter of
* adt_set_user(), below.
*/
static void
{
return;
}
(void) adt_end_session(ah);
return;
}
if (adt_set_proc(ah))
(void) adt_end_session(ah);
}
static int
{
int doorfd;
return (-1);
return (1);
}
return (0);
return (-1);
}
return (0);
}
int
{
/*
* First try the door without any lock: the lock might be held
* already, with a functional zoneadmd running.
*/
switch (is_door_open(zone_name)) {
case -1:
return (-1);
case 0:
break;
case 1:
goto out;
}
/*
* The zoneadmd door isn't open; try to start zoneadmd. We want
* to hold the lock to prevent racing against other clients.
* zoneadmd will detect this, and fail, but we prefer this to be
* as seamless as is practical, from a user perspective.
*/
return (-1);
release = 1;
/*
* Recheck the door.
*/
switch (is_door_open(zone_name)) {
case -1:
goto out;
case 0:
break;
case 1:
goto out;
}
goto out;
} else if (child_pid == 0) {
/* child process */
*ap++ = "zoneadmd";
*ap++ = "-z";
if (zonecfg_in_alt_root()) {
*ap++ = "-R";
*ap++ = zonecfg_get_root();
}
/*
* TRANSLATION_NOTE
* zoneadmd is a literal that should not be translated.
*/
_exit(1);
}
/* parent process */
do {
if (WIFSIGNALED(pstatus) ||
goto out;
}
out:
if (release == 1) {
/*
* Release the lock file. Only update the error status if
* there are no errors so far.
*/
else
(void) zonecfg_release_lock_file(zone_name);
}
return (error);
}
int
{
int doorfd;
return (-1);
return (-1);
}
return (Z_OK);
}
return (-1);
}
int
{
rlen = getpagesize();
return (-1);
}
sizeof (uniqid));
}
return (-1);
}
/*
* Loop trying to start zoneadmd; if something goes seriously
* wrong we break out and fail.
*/
for (;;) {
break;
break;
}
/*
* We'll get EBADF if the door has been revoked.
*/
break;
}
continue; /* take another lap */
}
/* Door server is going away; kick it again. */
continue;
}
while (*errbuf != '\0') {
/*
* Remove any newlines since zerror()
* will append one automatically.
*/
*cp = '\0';
break;
}
return (result);
}
return (-1);
}
{
char *right;
char *tmpauths;
char *lasts;
return (B_FALSE);
}
gettext("'%s' is not a valid authorization"),
right);
}
}
return (status);
}
int
{
int err;
return (err);
}
zonename);
(void) zonecfg_endadminent(handle);
return (err);
} else {
}
return (err);
}
}
(void) zonecfg_endadminent(handle);
}
/*
* Checks if a long authorization applies to this zone.
* If so, it returns true, after destructively stripping
* the authorization of its prefix and zone suffix.
*/
static boolean_t
{
char *suffix;
suffix[0] = '\0';
return (B_TRUE);
} else if ((oldzonename != NULL) &&
suffix[0] = '\0';
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* This function determines whether the zone-specific authorization
* than the equivalent data stored in the zone's configuration file.
* This should only happen if the zone-specific authorizations in
* the user_attr file were modified using a tool other than zonecfg.
* If the configuration file is out-of-date with respect to these
* authorization assignments, it is updated to match those specified
*/
int
{
char *authlist;
char *lasts;
int err;
return (Z_ACCES);
return (Z_NO_ZONE);
return (Z_MISC_FS);
}
return (Z_MISC_FS);
}
return (Z_MISC_FS);
}
return (Z_MISC_FS);
}
return (Z_NO_ENTRY);
}
} else if (err != Z_NO_ENTRY) {
return (err);
}
continue;
}
char *cur_auth;
NULL)) {
/*
* Add auths for this zone
*/
if (first) {
} else {
(void) strlcat(
",", MAXAUTHS);
}
(void) strlcat(
}
}
if (!first) {
/*
* Add this right to config file
*/
sizeof (admintab.zone_admin_user));
return (err);
} else {
}
}
}
} /* end-of-while-loop */
}
static void
{
char *cur_prof;
char *lasts;
if (!add) {
continue;
}
}
if (first) {
} else {
MAXPROFS);
}
MAXPROFS);
}
/*
* Now prepend the Zone Management profile at the beginning
* of the list if it is needed, and append the rest.
* Return the updated list in the original buffer.
*/
} else {
rbac_profs[0] = '\0';
}
if (!first)
}
}
static int
{
int status;
return (-1);
}
if (WIFSIGNALED(status)) {
"due to signal %d"),
return (-1);
}
return (WEXITSTATUS(status));
}
/*
* correspond to the admin settings that are currently being
* depending on the type of the specified user. It is also
* invoked to remove entries from user_attr corresponding to
* removed admin assignments, using an empty auths string.
*
* Because the removed entries are no longer included in the
* cofiguration that is being committed, a linked list of
* removed admin entries is maintained to keep track of such
* transactions. The head of the list is stored in the zone_dh_userauths
* element of the handle strcture.
*/
static int
{
char *right;
char *lasts;
userattr_t *u;
/*
* First get the existing authorizations for this user
*/
char *current_auths;
char *current_profs;
char *type;
}
if (current_auths != NULL) {
char *cur_auth;
char *delete_name;
/*
* Next, remove any existing authorizations
* for this zone, and determine if the
* user still needs the Zone Management Profile.
*/
if (is_renaming(handle))
else
delete_name = NULL;
delete_name)) {
if (first) {
} else {
MAXAUTHS);
}
MAXAUTHS);
/*
* If the user has authorizations
* for other zones, then set a
* flag indicate that the Zone
* Management profile should be
* preserved in user_attr.
*/
ZONE_AUTH_PREFIX, offset) == 0)
} else {
new_auth_cnt++;
}
}
}
if (current_profs != NULL) {
}
free_userattr(u);
}
/*
* The following is done to avoid revisiting the
* user_attr entry for this user
*/
/*
* Convert each right into a properly formatted authorization
*/
if (!first)
if (first) {
} else {
}
new_auth_cnt--;
}
/*
* Need to update the authorizations in user_attr unless
* the number of old and new authorizations is unchanged
* and the new auths are a substrings of the old auths.
*
* If the user's previous authorizations have changed
* execute the usermod progam to update them in user_attr.
*/
if ((new_auth_cnt != 0) ||
char *cmdbuf;
return (Z_NOMEM);
}
return (Z_SYSTEM);
}
}
return (Z_OK);
}
int
{
int err;
return (err);
continue;
continue;
continue;
!= Z_OK)
return (Z_SYSTEM);
}
return (Z_OK);
}
int
{
}
int
{
int err;
return (err);
continue;
continue;
return (err);
}
return (Z_OK);
}
int
{
while (next) {
ZONENAME_MAX) == 0)) {
/*
* user is already in list
* which isn't supposed to happen!
*/
return (Z_OK);
}
}
return (Z_NOMEM);
return (Z_OK);
}
int
{
while (next) {
if (deauthorize)
(void) zonecfg_deauthorize_user(handle,
continue;
}
}
return (Z_OK);
}
int
{
char *c;
return (0);
return (-1);
for (c = (char *)str1; *c; c++) {
if (*c == ',')
str1cnt++;
}
for (c = (char *)str2; *c; c++) {
if (*c == ',')
str2cnt++;
}
return (-1);
goto out;
goto out;
goto out;
}
for (i = 0; i < str2cnt; i++) {
break;
}
}
if (i == str2cnt)
goto out;
}
rc = 0;
out:
return (rc);
}
void
{
}
}
void
{
}
}
int
{
return (Z_NOMEM);
sizeof (new->zone_storage_uri));
else
return (Z_OK);
}
int
{
return (Z_NOMEM);
sizeof (new->zone_storage_uri));
else
return (Z_OK);
}
int
{
else
return (Z_OK);
}
}
return (Z_NO_PROPERTY_ID);
}
int
{
else
return (Z_OK);
}
}
return (Z_NO_PROPERTY_ID);
}
static int
{
/* We should always be called here with 2 fully populated entries */
return (Z_BAD_PROPERTY);
return (Z_BAD_PROPERTY);
return (Z_OK); /* entries match */
return (Z_NO_ENTRY); /* no match found */
}
/*
* Compare 2 lists of storage resources if they contain the same URI,
* if yes return Z_OK (check was successfull), if not Z_NO_ENTRY or
* specific error in case a property was suspect.
*/
int
{
return (err); /* no entries (yet), nothing todo */
goto out; /* match found, done here */
} else if (err != Z_NO_ENTRY) {
goto out; /* something wrong, escape */
}
}
}
out:
return (err);
}
/*
* Check an entire storage list whether it contains the URI or not.
* Return Z_OK on match, Z_NO_ENTRY if not or specific error in case a
* property was suspect.
*/
int
{
return (Z_NO_ENTRY); /* no entries (yet), nothing todo */
return (Z_BAD_PROPERTY); /* internal error */
return (Z_OK); /* match found, done */
}
return (Z_NO_ENTRY);
}
static int
{
break;
break;
}
return (err);
}
static int
{
break;
break;
}
return (err);
}
static int
{
int err;
return (err);
this->zone_storage_uri));
}
int
{
int err;
return (Z_INVAL);
return (err);
/* Specific search query or generic resource lookup ? */
firstmatch = NULL;
continue;
/*
* If 'uri' property doesn't match and we've been asked for
* a specific one, ignore it, else select this element.
*/
== Z_OK) {
firstmatch = cur;
}
if (match)
break;
}
/*
* No match, but the resource is present in the config.
* If it was just a lookup if the resource is present
* at all, we're done but don't fail instead return
* the 1st match.
*/
if (!search) {
firstmatch = cur;
break;
}
}
/*
* Fail with different errors for specific search query or generic
* resource lookup.
*/
if (firstmatch == NULL)
cur = firstmatch;
return (err);
/* install-size is optional */
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
/* Specific search query or generic resource lookup ? */
firstmatch = NULL;
continue;
/*
* If 'uri' or 'name' property doesn't match and we've
* been asked for a specific one, ignore it, else
* select the 1st matching element and stop search.
*/
&temp_zptab) == Z_OK) {
firstmatch = cur;
}
if (match)
break;
}
firstmatch = cur;
break;
}
/*
* No match, but the resource is present in the config.
* If it was just a lookup if the resource is present
* at all, we're done but don't fail instead return
* the 1st match.
*/
if (!search) {
firstmatch = cur;
break;
}
}
/*
* Fail with different errors for specific search query or generic
* resource lookup.
*/
if (firstmatch == NULL)
cur = firstmatch;
return (err);
return (err);
/* install-size is optional */
return (Z_OK);
}
/*
* There is only one rootzpool resource per zone so we don't need to match
* any property within to allow deletion.
*/
/* ARGSUSED */
static int
{
continue;
/* found it */
return (Z_OK);
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
}
/*
* Since we can have multiple DTD_ATTR_STORAGE properties per DTD_ELEM_ZPOOL
* resource, selecting via the DTD_ATTR_NAME property is the most reasonable
* criteria as it has to be unique across different DTD_ELEM_ZPOOL resources.
*/
static int
{
continue;
tabptr->zone_zp_name)) {
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
/* install-size is optional */
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
}
return (err);
}
return (err);
}
/* install-size is optional */
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
static int
{
int err;
DTD_ELEM_ROOTZPOOL)) != Z_OK)
return (err);
return (err);
return (err);
}
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
}
static int
{
int err;
return (err);
return (err);
return (err);
return (err);
}
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
/*
* Query function to identify a zoss zone. Check whether or not the zone
* has DTD_ELEM_ROOTZPOOL or DTD_ELEM_ZPOOL resources configured.
* In 'iszoss' return B_TRUE if either of those resources are configured
* indicating a zoss zone, else B_FALSE.
* In 'zpiszoss' return B_TRUE if the zonepath is configured in its own,
* seperate zpool via the DTD_ELEM_ROOTZPOOL resource, else B_FALSE.
*/
int
{
int err;
/*
* Makes only sense in the GZ, if we're not in the GZ there won't be
* any XML repos to query nor any zoss releated actions to execute.
*/
if (myzoneid != GLOBAL_ZONEID)
return (Z_OK);
return (Z_NOMEM);
goto leave;
/* First check if a DTD_ELEM_ROOTZPOOL resource is present */
goto leave;
}
(void) zonecfg_endrzpent(zh);
/*
* If we did not have a DTD_ELEM_ROOTZPOOL resource we have to
* check if any DTD_ELEM_ZPOOL resources are present.
*/
if (err == Z_NO_ENTRY) {
/* Now check if any DTD_ELEM_ZPOOL resources are present */
}
(void) zonecfg_endzpent(zh);
}
}
return (err);
}
/*
* Check whether or not a given name is a valid name for a zpool.
*/
zonecfg_valid_zpoolname(const char *s)
{
if (strcmp(s, ZONE_RZPNAME) == 0 ||
!zfs_name_valid(s, ZFS_TYPE_POOL))
return (B_FALSE);
return (B_TRUE);
}
/*
* Build names for zone zpools.
* For DTD_ELEM_ROOTZPOOL we just use the zonename plus ZONE_RZPNAME to
* build the zpool name. For DTD_ELEM_ZPOOL we use the zonename
* plus the 'name' zonecfg property.
* Example:
* rootzpool: <zonename>_<rpool>
* zpool: <zonename>_<name>
*/
int
{
return (Z_INVAL);
return (Z_OK);
}
static int
{
int err;
return (Z_OK);
return (Z_OK);
return (Z_BRAND_ERROR);
else
return (err);
}
static int
{
}
struct paths_store {
int count;
int max;
char **paths;
};
/*
* Callback to count the number of the paths listed in the profile.
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*
* Callback to store the paths in the paths_store struct pointed to by voidp.
*/
static int
{
return (-1);
return (-1);
return (0);
}
static void
{
int i;
}
}
/*
* Build the white list and the black list for the zone for zoneadmd.
*/
int
{
int err;
int n;
int i, j;
return (err);
return (Z_OK);
return (Z_BRAND_ERROR);
w == ZS_WHITE) != 0) {
return (Z_INVALID_PROPERTY);
}
}
/* Additional entries are added for each fs. */
w == ZS_WHITE) != 0) {
return (Z_INVALID_PROPERTY);
}
}
/*
* Mark the added filesystems as read-write, so add them to the
* writable set.
*/
if (n > 0) {
i = 0;
return (err);
}
}
(void) zonecfg_endfsent(handle);
/*
* Create a wild card matching everything under the mountpoint.
* Make sure that we don't add conflicting patterns.
*/
for (i = 0; i < n; i++) {
int len;
/* Check for a direct match */
break;
/* ... or a wildcard match */
break;
}
}
/* New pattern, add it */
char *newp;
return (Z_NOMEM);
}
}
}
}
/*
* For each list we count the number of bytes needed for every list,
* allocate the memory and then concatenate all the paths (including
* a NUL as separator).
*/
char *temp, *q;
if (totlen == 0)
continue;
if (w == ZS_WHITE)
return (Z_NOMEM);
}
q = temp;
*q = '\0';
}
}
return (Z_OK);
}
int
{
int ret;
return (ret);
}
}
int
{
}
/*
* Iterate through the resource of a given zone configuration calling func()
* each resource.
*/
int
{
int ret;
return (ret);
/* Special case the "global" resource */
return (ret);
return (ret);
}
return (Z_OK);
}
/*
* For each resource (and the "global" resource) iterate through the properties
* calling func() for each property.
* NOTE: func() won't be called for complex types which aren't represented as
* attributes of the resource node.
*/
int
{
int ret;
return (ret);
/* Start with the "global" resource */
return (Z_BAD_PROPERTY);
if (ret != 0)
return (ret);
}
else
}
return (Z_OK);
}