libzonecfg.c revision cf8f45c7690afabe63bdb8066b11db58d708ad09
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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 <netdb.h>
#include <priv.h>
#include <libxml/xmlmemory.h>
#include <libdevinfo.h>
#include <libzonecfg.h>
#include "zonecfg_impl.h"
#define _PATH_TMPFILE "/zonecfg.XXXXXX"
#define ZONE_CB_RETRY_COUNT 10
#define ZONE_EVENT_PING_SUBCLASS "ping"
#define ZONE_EVENT_PING_PUBLISHER "solaris"
#define DTD_ENTITY_BOOLEAN "boolean"
#define DTD_ENTITY_DEVPATH "devpath"
#define DTD_ENTITY_DRIVER "driver"
#define DTD_ENTITY_DRVMIN "drv_min"
#define DTD_ENTITY_FALSE "false"
#define DTD_ENTITY_INT "int"
#define DTD_ENTITY_STRING "string"
#define DTD_ENTITY_TRUE "true"
#define DTD_ENTITY_UINT "uint"
struct zone_dochandle {
char *zone_dh_rootdir;
char zone_dh_delete_name[ZONENAME_MAX];
};
struct znotify {
void * zn_private;
char zn_subscriber_id[MAX_SUBID_LEN];
int zn_failure_count;
};
char *zonecfg_root = "";
/*
* 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.
*/
void
zonecfg_set_root(const char *rootpath)
{
if (*zonecfg_root != '\0')
zonecfg_root = "";
}
const char *
zonecfg_get_root(void)
{
return (zonecfg_root);
}
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) xmlKeepBlanksDefault(0);
return (handle);
}
int
{
return (Z_BAD_HANDLE);
return (Z_OK);
}
void
{
}
static int
zonecfg_destroy_impl(char *filename)
{
return (Z_ACCES);
return (Z_NO_ZONE);
return (Z_MISC_FS);
}
return (Z_OK);
}
int
{
char path[MAXPATHLEN];
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
zonecfg_destroy_snapshot(const char *zonename)
{
char path[MAXPATHLEN];
return (Z_MISC_FS);
return (zonecfg_destroy_impl(path));
}
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);
}
static int
{
int err;
return (err);
return (Z_BAD_PROPERTY);
return (Z_TOO_BIG);
return (Z_OK);
}
static int
const char *propval)
{
int err;
return (Z_INVAL);
return (err);
return (Z_INVAL);
return (Z_OK);
}
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 */
return (Z_OK);
}
int
{
char path[MAXPATHLEN];
return (Z_MISC_FS);
}
int
{
char path[MAXPATHLEN];
return (Z_MISC_FS);
}
int
{
char path[MAXPATHLEN];
int err;
return (Z_MISC_FS);
return (err);
}
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
zonecfg_validate_zonename(const char *zone)
{
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
{
}
int
{
int err;
return (err);
return (Z_OK);
/*
* Switching zone names to one beginning with SUNW 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);
}
return (Z_OK);
}
int
{
return (Z_TOO_BIG);
}
int
{
}
int
{
char autobootstr[DTD_ENTITY_BOOL_LEN];
int ret;
sizeof (autobootstr))) != Z_OK)
return (ret);
else
return (ret);
}
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
{
char tmpfile[MAXPATHLEN];
if (tmpfd == -1) {
return (Z_TEMP_FILE);
}
/*
* We do a final validation of the document-- but the library has
* malfunctioned if it fails to validate, so it's an assert.
*/
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);
}
int
{
char delpath[MAXPATHLEN];
int err = Z_SAVING_FILE;
return (Z_BAD_HANDLE);
/*
* We don't support saving snapshots at this time.
*/
if (handle->zone_dh_snapshot)
return (Z_INVAL);
return (err);
return (Z_MISC_FS);
"FILE. Use zonecfg(1M) instead.\n");
return (err);
if (is_renaming(handle)) {
}
return (Z_OK);
}
/*
* 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
{
char path[MAXPATHLEN];
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
zonecfg_create_snapshot(const char *zonename)
{
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);
}
static int
{
return (Z_BAD_PROPERTY);
}
return (Z_OK);
}
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
{
int 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
{
int prop_result;
return (B_FALSE);
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);
}
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_fstab *newtabptr)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
static int
{
return (Z_BAD_PROPERTY);
return (Z_TOO_BIG);
return (Z_OK);
}
int
struct zone_fstab *tabptr)
{
int err;
char options_str[MAX_MNTOPT_STR];
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);
}
int
{
int err;
char dirname[MAXPATHLEN];
return (Z_INVAL);
return (err);
/*
* General algorithm:
* 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.
*/
continue;
else
return (Z_INSUFFICIENT_SPEC);
}
}
}
return (Z_NO_RESOURCE_ID);
return (err);
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
{
struct sockaddr_in *sin4;
struct sockaddr_in6 *sin6;
*slashp = '\0';
return (Z_IPV6_ADDR_PREFIX_LEN);
} else {
/* "address" may be a host name */
return (Z_BOGUS_ADDRESS);
/* LINTED E_BAD_PTR_CAST_ALIGN */
sizeof (struct in_addr));
}
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
firstmatch = NULL;
continue;
physical) == 0)) {
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;
}
}
}
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
cur = firstmatch;
return (err);
return (err);
return (Z_OK);
}
static int
{
int err;
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
static int
{
continue;
if (addr_match && phys_match) {
return (Z_OK);
}
}
return (Z_NO_RESOURCE_ID);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
int
struct zone_nwiftab *oldtabptr,
struct zone_nwiftab *newtabptr)
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (err);
return (Z_OK);
}
int
{
int err;
char match[MAXPATHLEN];
return (Z_INVAL);
return (err);
firstmatch = NULL;
continue;
continue;
match) == 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 (Z_OK);
}
static int
{
int err;
return (err);
return (Z_OK);
}
int
{
int err;
return (Z_INVAL);
return (err);
return (err);
return (Z_OK);
}
static int
{
int match_match;
continue;
if (match_match) {
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);
}
/*
* This is the set of devices which must be present in every zone. Users
* can augment this list with additional device rules in their zone
* configuration, but at present cannot remove any of the this set of
* standard devices. All matching is done by /dev pathname (the "/dev"
* part is implicit. Try to keep rules which match a large number of
* devices (like the pts rule) first.
*/
static const char *standard_devs[] = {
"pts/*",
"ptmx",
"random",
"urandom",
"poll",
"pool",
"kstat",
"zero",
"null",
"crypto",
"cryptoadm",
"ticots",
"ticotsord",
"ticlts",
"lo0",
"lo1",
"lo2",
"lo3",
"tty",
"logindmux",
"log",
"conslog",
"arp",
"tcp",
"tcp6",
"udp",
"udp6",
"sysevent",
#ifdef __sparc
"openprom",
#endif
"zfs",
};
/*
* 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 the mount point.
*
* If the callback function returns non-zero zonecfg_find_mounts
* aborts with an error.
*/
int
void *priv) {
struct mnttab m;
size_t l;
int rv = 0;
return (-1);
rv = -1;
goto out;
}
(m.mnt_mountp[l] == '/')) {
rv++;
continue;
rv = -1;
goto out;
}
}
}
out:
return (rv);
}
/*
* This routine is used to determine if a given device should appear in the
* zone represented by 'handle'. First it consults the list of "standard"
* zone devices. Then it scans the user-supplied device entries.
*/
int
struct zone_devtab *out_match)
{
int err;
char match[MAXPATHLEN];
const char **stdmatch;
return (Z_INVAL);
/*
* Check the "standard" devices which we require to be present.
*/
/*
* fnmatch gives us simple but powerful shell-style matching.
*/
if (!out_match)
return (Z_OK);
sizeof (out_match->zone_dev_match),
"/dev/%s", *stdmatch);
return (Z_OK);
}
}
/*
* We got no hits in the set of standard devices. On to the user
* supplied ones.
*/
return (err);
}
return (Z_NO_ENTRY);
char *m;
continue;
return (err);
}
m = match;
/*
* fnmatch gives us simple but powerful shell-style matching;
* but first, we need to strip out /dev/ from the matching rule.
*/
m += 5;
break;
}
}
if (!found)
return (Z_NO_ENTRY);
if (!out_match)
return (Z_OK);
sizeof (out_match->zone_dev_match));
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 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 (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
{
char savedname[MAXNAMELEN];
struct zone_rctlvaltab *valptr;
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
{
struct zone_rctlvaltab *valptr;
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 name_result;
continue;
continue;
if (name_result == 0) {
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 *
zonecfg_strerror(int errnum)
{
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"));
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);
}
int
{
return (zonecfg_setent(handle));
}
int
{
char options_str[MAX_MNTOPT_STR];
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
break;
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);
break;
return (Z_NO_ENTRY);
}
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);
break;
return (Z_NO_ENTRY);
}
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);
break;
return (Z_NO_ENTRY);
}
return (err);
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
int
{
return (zonecfg_setent(handle));
}
int
{
struct zone_rctlvaltab *valptr;
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
break;
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);
break;
return (Z_NO_ENTRY);
}
return (err);
}
return (err);
}
return (err);
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}
/* This will ultimately be configurable. */
static const char *priv_list[] = {
};
int
{
const char **strp;
return (Z_INVAL);
return (Z_INVAL);
}
}
return (Z_OK);
}
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);
}
static zone_state_t
{
char zoneroot[MAXPATHLEN];
switch (kernel_state) {
case ZONE_IS_UNINITIALIZED:
return (ZONE_STATE_READY);
case ZONE_IS_READY:
/*
* it's a mounted scratch zone.
*/
sizeof (zoneroot)) >= 0) {
if (zlen > 3 &&
return (ZONE_STATE_MOUNTED);
}
return (ZONE_STATE_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_DOWN:
case ZONE_IS_DYING:
case ZONE_IS_DEAD:
default:
return (ZONE_STATE_DOWN);
}
/* NOTREACHED */
}
int
{
char kernzone[ZONENAME_MAX];
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 *
{
switch (state_num) {
case ZONE_STATE_CONFIGURED:
return (ZONE_STATE_STR_CONFIGURED);
case ZONE_STATE_INCOMPLETE:
return (ZONE_STATE_STR_INCOMPLETE);
case ZONE_STATE_INSTALLED:
return (ZONE_STATE_STR_INSTALLED);
case ZONE_STATE_READY:
return (ZONE_STATE_STR_READY);
case ZONE_STATE_MOUNTED:
return (ZONE_STATE_STR_MOUNTED);
case ZONE_STATE_RUNNING:
return (ZONE_STATE_STR_RUNNING);
case ZONE_STATE_SHUTTING_DOWN:
return (ZONE_STATE_STR_SHUTTING_DOWN);
case ZONE_STATE_DOWN:
return (ZONE_STATE_STR_DOWN);
default:
return ("unknown");
}
}
/*
* 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.
*/
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.
*/
zonecfg_valid_fs_type(const char *type)
{
/*
* 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.
*/
}
zonecfg_is_rctl(const char *name)
{
}
zonecfg_valid_rctlname(const char *name)
{
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();
return (0);
}
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 out2;
goto out2;
}
goto out2;
}
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 out;
getpid() % 999999l, i);
zevtchan, 0);
i++;
} while (r);
return (zevtchan);
out:
out2:
return (NULL);
}
void
zonecfg_notify_unbind(void *handle)
{
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 (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;
char dataset[MAXNAMELEN];
return (Z_INVAL);
return (err);
firstmatch = NULL;
continue;
dataset) == 0)) {
if (firstmatch == NULL)
firstmatch = cur;
else
return (Z_INSUFFICIENT_SPEC);
}
}
}
if (firstmatch == NULL)
return (Z_NO_RESOURCE_ID);
cur = firstmatch;
return (err);
return (Z_OK);
}
int
{
return (zonecfg_setent(handle));
}
int
{
int err;
return (Z_INVAL);
return (Z_NO_ENTRY);
break;
return (Z_NO_ENTRY);
}
return (err);
}
return (Z_OK);
}
int
{
return (zonecfg_endent(handle));
}