zonecfg.c revision 6fb06a2b0ecc01d4f918506292946307f234560e
/*
* 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
*/
/*
*/
/*
* configurations. The lexer (see zonecfg_lex.l) builds up tokens, which
* the grammar (see zonecfg_grammar.y) builds up into commands, some of
* comments near the end of zonecfg_grammar.y for how the data structures
* which keep track of these resources and properties are built up.
*
* structure (see zonecfg.h), which also keeps track of command names,
* miscellaneous arguments, and function handlers. The grammar selects
* the appropriate function handler, each of which takes a pointer to a
* command structure as its sole argument, and invokes it. The grammar
* itself is "entered" (a la the Matrix) by yyparse(), which is called
* from read_input(), our main driving function. That in turn is called
* by one of do_interactive(), cmd_file() or one_command_at_a_time(), each
* of which is called from main() depending on how the program was invoked.
*
* The rest of this module consists of the various function handlers and
* their helper functions. Some of these functions, particularly the
* X_to_str() functions, which maps command, resource and property numbers
* to strings, are used quite liberally, as doing so results in a better
*/
#include <sys/sysmacros.h>
#include <errno.h>
#include <fcntl.h>
#include <strings.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include <assert.h>
#include <zone.h>
#include <netdb.h>
#include <locale.h>
#include <libintl.h>
#include <alloca.h>
#include <signal.h>
#include <wait.h>
#include <libtecla.h>
#include <libzfs.h>
#include <libbrand.h>
#include <sys/systeminfo.h>
#include <libdladm.h>
#include <libinetutil.h>
#include <pwd.h>
#include <libzonecfg.h>
#include "zonecfg.h"
#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
#endif
#define EXEC_PREFIX "exec "
struct help {
char *cmd_name;
char *short_usage;
};
extern int yyparse(void);
extern int lex_lineno;
#define MAX_LINE_LEN 1024
#define MAX_CMD_HIST 1024
#define MAX_CMD_LEN 1024
#define ONE_MB 1048576
/*
* Each SHELP_ should be a simple string.
*/
#define SHELP_ADD "add <resource-type>\n\t(global scope)\n" \
"add <property-name> <property-value>\n\t(resource scope)"
#define SHELP_CANCEL "cancel"
#define SHELP_CLEAR "clear <property-name>"
#define SHELP_COMMIT "commit"
#define SHELP_CREATE "create [-F] [ -a <path> | -b | -t <template> ]"
#define SHELP_DELETE "delete [-F]"
#define SHELP_END "end"
#define SHELP_EXIT "exit [-F]"
#define SHELP_EXPORT "export [-f output-file]"
#define SHELP_HELP "help [commands] [syntax] [usage] [<command-name>]"
#define SHELP_INFO "info [<resource-type> [property-name=property-value]*]"
#define SHELP_REMOVE "remove [-F] <resource-type> " \
"[ <property-name>=<property-value> ]*\n" \
"\t(global scope)\n" \
"remove <property-name> <property-value>\n" \
"\t(resource scope)"
#define SHELP_REVERT "revert [-F]"
#define SHELP_SELECT "select <resource-type> { <property-name>=" \
"<property-value> }"
#define SHELP_SET "set <property-name>=<property-value>"
#define SHELP_VERIFY "verify"
{ 0 },
};
#define MAX_RT_STRLEN 16
/* These *must* match the order of the RT_ define's from zonecfg.h */
char *res_types[] = {
"unknown",
"zonename",
"zonepath",
"autoboot",
"pool",
"fs",
"inherit-pkg-dir",
"net",
"device",
"rctl",
"attr",
"dataset",
"limitpriv",
"bootargs",
"brand",
"dedicated-cpu",
"capped-memory",
"scheduling-class",
"ip-type",
"capped-cpu",
"hostid",
"admin",
"fs-allowed",
};
/* These *must* match the order of the PT_ define's from zonecfg.h */
char *prop_types[] = {
"unknown",
"zonename",
"zonepath",
"autoboot",
"pool",
"dir",
"special",
"type",
"options",
"address",
"physical",
"name",
"value",
"match",
"priv",
"limit",
"action",
"raw",
"limitpriv",
"bootargs",
"brand",
"ncpus",
"importance",
"swap",
"locked",
"scheduling-class",
"ip-type",
"defrouter",
"hostid",
"user",
"auths",
"fs-allowed",
};
/* These *must* match the order of the PROP_VAL_ define's from zonecfg.h */
static char *prop_val_types[] = {
"simple",
"complex",
"list",
};
/*
* The various _cmds[] lists below are for command tab-completion.
*/
/*
* remove has a space afterwards because it has qualifiers; the other commands
* that have qualifiers (add, select, etc.) don't need a space here because
* they have their own _cmds[] lists below.
*/
static const char *global_scope_cmds[] = {
"add",
"clear",
"commit",
"create",
"delete",
"exit",
"export",
"help",
"info",
"remove ",
"revert",
"select",
"set",
"verify",
};
static const char *add_cmds[] = {
"add fs",
"add inherit-pkg-dir",
"add net",
"add device",
"add rctl",
"add attr",
"add dataset",
"add dedicated-cpu",
"add capped-cpu",
"add capped-memory",
"add admin",
};
static const char *clear_cmds[] = {
"clear autoboot",
"clear pool",
"clear limitpriv",
"clear bootargs",
"clear scheduling-class",
"clear ip-type",
"clear " ALIAS_MAXLWPS,
"clear " ALIAS_MAXSHMMEM,
"clear " ALIAS_MAXSHMIDS,
"clear " ALIAS_MAXMSGIDS,
"clear " ALIAS_MAXSEMIDS,
"clear " ALIAS_SHARES,
};
static const char *remove_cmds[] = {
"remove fs ",
"remove inherit-pkg-dir ",
"remove net ",
"remove device ",
"remove rctl ",
"remove attr ",
"remove dataset ",
"remove dedicated-cpu ",
"remove capped-cpu ",
"remove capped-memory ",
"remove admin ",
};
static const char *select_cmds[] = {
"select fs ",
"select inherit-pkg-dir ",
"select net ",
"select device ",
"select rctl ",
"select attr ",
"select dataset ",
"select dedicated-cpu",
"select capped-cpu",
"select capped-memory",
"select admin",
};
static const char *set_cmds[] = {
"set zonename=",
"set zonepath=",
"set brand=",
"set autoboot=",
"set pool=",
"set limitpriv=",
"set bootargs=",
"set scheduling-class=",
"set ip-type=",
"set hostid=",
"set fs-allowed=",
};
static const char *info_cmds[] = {
"info fs ",
"info inherit-pkg-dir ",
"info net ",
"info device ",
"info rctl ",
"info attr ",
"info dataset ",
"info capped-memory",
"info dedicated-cpu",
"info capped-cpu",
"info zonename",
"info zonepath",
"info autoboot",
"info pool",
"info limitpriv",
"info bootargs",
"info brand",
"info scheduling-class",
"info ip-type",
"info max-lwps",
"info max-shm-memory",
"info max-shm-ids",
"info max-msg-ids",
"info max-sem-ids",
"info cpu-shares",
"info hostid",
"info admin",
"info fs-allowed",
};
static const char *fs_res_scope_cmds[] = {
"add options ",
"cancel",
"end",
"exit",
"help",
"info",
"remove options ",
"set dir=",
"set raw=",
"set special=",
"set type=",
"clear raw",
};
static const char *net_res_scope_cmds[] = {
"cancel",
"end",
"exit",
"help",
"info",
"set address=",
"set physical=",
"set defrouter=",
};
static const char *ipd_res_scope_cmds[] = {
"cancel",
"end",
"exit",
"help",
"info",
"set dir=",
};
static const char *device_res_scope_cmds[] = {
"cancel",
"end",
"exit",
"help",
"info",
"set match=",
};
static const char *attr_res_scope_cmds[] = {
"cancel",
"end",
"exit",
"help",
"info",
"set name=",
"set type=",
"set value=",
};
static const char *rctl_res_scope_cmds[] = {
"add value ",
"cancel",
"end",
"exit",
"help",
"info",
"remove value ",
"set name=",
};
static const char *dataset_res_scope_cmds[] = {
"cancel",
"end",
"exit",
"help",
"info",
"set name=",
};
static const char *pset_res_scope_cmds[] = {
"cancel",
"end",
"exit",
"help",
"info",
"set ncpus=",
"set importance=",
"clear importance",
};
static const char *pcap_res_scope_cmds[] = {
"cancel",
"end",
"exit",
"help",
"info",
"set ncpus=",
};
static const char *mcap_res_scope_cmds[] = {
"cancel",
"end",
"exit",
"help",
"info",
"set physical=",
"set swap=",
"set locked=",
"clear physical",
"clear swap",
"clear locked",
};
static const char *admin_res_scope_cmds[] = {
"cancel",
"end",
"exit",
"help",
"info",
"set user=",
"set auths=",
};
/* Global variables */
/* set early in main(), never modified thereafter, used all over the place */
static char *execname;
/* set in main(), used all over the place */
static zone_dochandle_t handle;
/* used all over the place */
static char zone[ZONENAME_MAX];
static char revert_zone[ZONENAME_MAX];
/* global brand operations */
static brand_handle_t brand;
/* set in modifying functions, checked in read_input() */
/* set in yacc parser, checked in read_input() */
/* set in main(), checked in lex error handler */
/* set in exit_func(), checked in read_input() */
/* used in short_usage() and zerr() */
static char *cmd_file_name = NULL;
/* checked in read_input() and other places */
/* set and checked in initialize() */
/* initialized in do_interactive(), checked in initialize() */
static boolean_t interactive_mode;
/* set if configuring the global zone */
/* set in main(), checked in multiple places */
static boolean_t read_only_mode;
static int resource_scope; /* should be in the RT_ list from zonecfg.h */
int num_prop_vals; /* for grammar */
/*
* These are for keeping track of resources as they are specified as part of
* the multi-step process. They should be initialized by add_resource() or
* select_func() and filled in by add_property() or set_func().
*/
/* Functions begin here */
static boolean_t
{
if (word_end <= 0)
return (B_TRUE);
}
static int
int word_end)
{
int i, err;
if (err != 0)
return (err);
}
}
return (0);
}
static
/* ARGSUSED */
{
if (global_scope) {
/*
* enough characters to distinguish from other prefixes (MAX)
* but only check MIN(what we have, what we're checking).
*/
}
switch (resource_scope) {
case RT_FS:
case RT_IPD:
case RT_NET:
case RT_DEVICE:
case RT_RCTL:
case RT_ATTR:
case RT_DATASET:
case RT_DCPU:
case RT_PCAP:
case RT_MCAP:
case RT_ADMIN:
}
return (0);
}
/*
* For the main CMD_func() functions below, several of them call getopt()
* then check optind against argc to make sure an extra parameter was not
* passed in. The reason this is not caught in the grammar is that the
* grammar just checks for a miscellaneous TOKEN, which is *expected* to
* be "-F" (for example), but could be anything. So (for example) this
* check will prevent "create bogus".
*/
cmd_t *
alloc_cmd(void)
{
}
void
{
int i;
for (i = 0; i < MAX_EQ_PROP_PAIRS; i++)
case PROP_VAL_SIMPLE:
break;
case PROP_VAL_COMPLEX:
break;
case PROP_VAL_LIST:
break;
}
}
}
alloc_complex(void)
{
}
void
{
return;
}
alloc_list(void)
{
}
void
{
return;
}
void
{
return;
}
static struct zone_rctlvaltab *
alloc_rctlvaltab(void)
{
}
static char *
{
}
static char *
{
return (prop_types[prop_type]);
}
static char *
pvt_to_str(int pv_type)
{
return (prop_val_types[pv_type]);
}
static char *
cmd_to_str(int cmd_num)
{
}
/* PRINTFLIKE1 */
static void
{
static int last_lineno;
/* lex_lineno has already been incremented in the lexer; compensate */
lex_lineno - 1);
else
}
}
/*
* This is a separate function rather than a set of define's because of the
* gettext() wrapping.
*/
/*
* TRANSLATION_NOTE
* Each string below should have \t follow \n whenever needed; the
* initial \t and the terminal \n will be provided by the calling function.
*/
static char *
{
switch (cmd_num) {
case CMD_HELP:
return (gettext("Prints help message."));
case CMD_CREATE:
gettext("Creates a configuration for the "
"specified zone. %s should be\n\tused to "
"begin configuring a new zone. If overwriting an "
"existing\n\tconfiguration, the -F flag can be "
"used to force the action. If\n\t-t template is "
"given, creates a configuration identical to the\n"
"\tspecified template, except that the zone name "
"is changed from\n\ttemplate to zonename. '%s -a' "
"creates a configuration from a\n\tdetached "
"zonepath. '%s -b' results in a blank "
"configuration.\n\t'%s' with no arguments applies "
"the Sun default settings."),
return (line);
case CMD_EXIT:
return (gettext("Exits the program. The -F flag can "
"be used to force the action."));
case CMD_EXPORT:
return (gettext("Prints configuration to standard "
"output, or to output-file if\n\tspecified, in "
"a form suitable for use in a command-file."));
case CMD_ADD:
return (gettext("Add specified resource to "
"configuration."));
case CMD_DELETE:
return (gettext("Deletes the specified zone. The -F "
"flag can be used to force the\n\taction."));
case CMD_REMOVE:
return (gettext("Remove specified resource from "
"configuration. The -F flag can be used\n\tto "
"force the action."));
case CMD_SELECT:
gettext("Selects a resource to modify. "
"Resource modification is completed\n\twith the "
"must uniquely\n\tidentify a resource. Note that "
"the curly braces ('{', '}') mean one\n\tor more "
"of whatever is between them."),
return (line);
case CMD_SET:
return (gettext("Sets property values."));
case CMD_CLEAR:
return (gettext("Clears property values."));
case CMD_INFO:
return (gettext("Displays information about the "
"current configuration. If resource\n\ttype is "
"specified, displays only information about "
"resources of\n\tthe relevant type. If resource "
"id is specified, displays only\n\tinformation "
"about that resource."));
case CMD_VERIFY:
return (gettext("Verifies current configuration "
"for correctness (some resource types\n\thave "
"required properties)."));
case CMD_COMMIT:
gettext("Commits current configuration. "
"Configuration must be committed to\n\tbe used by "
"%s. Until the configuration is committed, "
"changes \n\tcan be removed with the %s "
"command. This operation is\n\tattempted "
"automatically upon completion of a %s "
"zonecfg");
return (line);
case CMD_REVERT:
return (gettext("Reverts configuration back to the "
"last committed state. The -F flag\n\tcan be "
"used to force the action."));
case CMD_CANCEL:
"specification."));
case CMD_END:
"specification."));
}
/* NOTREACHED */
return (NULL);
}
/*
* Called with verbose TRUE when help is explicitly requested, FALSE for
* unexpected errors.
*/
void
{
char *pager;
int i;
/* don't page error output */
if (verbose && interactive_mode) {
}
} else {
}
}
"following:\n"));
"command by typing '%s <command-name>.'\n"),
}
if (flags & HELP_RES_SCOPE) {
switch (resource_scope) {
case RT_FS:
"used to configure a file-system.\n"),
gettext("<file-system options>"));
gettext("<file-system options>"));
"specific manual page, such as mount_ufs(1M), "
"for\ndetails about file-system options. Note "
"that any file-system options with an\nembedded "
"'=' character must be enclosed in double quotes, "
/*CSTYLED*/
"such as \"%s=5\".\n"), MNTOPT_RETRY);
break;
case RT_IPD:
"used to configure a directory\ninherited from the "
"global zone into a non-global zone in read-only "
break;
case RT_NET:
"used to configure a network interface.\n"),
"details of the <interface> string.\n"));
"if the %s property is set to %s, otherwise they "
"must not be set.\n"),
break;
case RT_DEVICE:
"used to configure a device node.\n"),
break;
case RT_RCTL:
"used to configure a resource control.\n"),
break;
case RT_ATTR:
"used to configure a generic attribute.\n"),
break;
case RT_DATASET:
"used to export ZFS datasets.\n"),
break;
case RT_DCPU:
"configures the 'pools' facility to dedicate\na "
"subset of the system's processors to this zone "
"while it is running.\n"),
gettext("<unsigned integer | range>"));
gettext("<unsigned integer>"));
break;
case RT_PCAP:
"used to set an upper limit (a cap) on the\n"
"percentage of CPU that can be used by this zone. "
"A '%s' value of 1\ncorresponds to one cpu. The "
"value can be set higher than 1, up to the total\n"
"number of CPUs on the system. The value can "
"also be less than 1,\nrepresenting a fraction of "
"a cpu.\n"),
break;
case RT_MCAP:
"used to set an upper limit (a cap) on the\n"
"amount of physical memory, swap space and locked "
"memory that can be used by\nthis zone.\n"),
gettext("<qualified unsigned decimal>"));
gettext("<qualified unsigned decimal>"));
gettext("<qualified unsigned decimal>"));
break;
case RT_ADMIN:
"used to delegate specific zone management\n"
"rights to users and roles. These rights are "
"only applicable to this zone.\n"),
gettext("<single user or role name>"));
gettext("<comma separated list>"));
break;
}
"can:\n"));
gettext("(to conclude this operation)"));
gettext("(to cancel this operation)"));
gettext("(to exit the zonecfg utility)"));
}
if (flags & HELP_USAGE) {
execname);
}
if (flags & HELP_SUBCMDS) {
for (i = 0; i <= CMD_MAX; i++) {
if (verbose)
}
}
if (flags & HELP_SYNTAX) {
if (!verbose)
"'%s' and anything starting with '%s')\n"), "global",
"SUNW");
gettext("\tName must be less than %d characters.\n"),
if (verbose)
}
if (flags & HELP_NETADDR) {
gettext("\t<IPv4-address>[/<IPv4-prefix-length>] |\n"));
gettext("\t\t<IPv6-address>/<IPv6-prefix-length> |\n"));
gettext("\t\t<hostname>[/<IPv4-prefix-length>]\n"));
"IPv6 address syntax.\n"));
gettext("<IPv6-prefix-length> := [0-128]\n"));
gettext("<hostname> := [A-Za-z0-9][A-Za-z0-9-.]*\n"));
}
if (flags & HELP_RESOURCES) {
"%s | %s | %s | %s | %s\n\n",
}
if (flags & HELP_PROPS) {
"property types ...:\n"));
}
if (need_to_close)
}
static void
{
if (set_saw)
}
/*
* zone_perror() expects a single string, but for remove and select
* we have both the command and the resource type, so this wrapper
* function serves the same purpose in a slightly different way.
*/
static void
{
if (set_saw)
}
/* returns Z_OK if successful, Z_foo from <libzonecfg.h> otherwise */
static int
{
int err;
char brandname[MAXNAMELEN];
got_handle = B_TRUE;
zerr("Zone %s is inconsistent: missing "
"brand attribute", zone);
}
zerr("Zone %s uses non-existent brand \"%s\"."
}
/*
* If the user_attr file is newer than
* the zone config file, the admins
* may need to be updated since the
* RBAC files are authoritative for
* authorization checks.
*/
"were updated to match "
"the current RBAC configuration.\n"
"Use \"info admin\" and \"revert\" to "
"compare with the previous settings."));
} else if (err != Z_NO_ENTRY) {
"admin rights."));
} else if (need_to_commit) {
"to match RBAC configuration."));
}
!read_only_mode) {
/*
* We implicitly create the global zone config if it
* doesn't exist.
*/
}
return (err);
}
got_handle = B_TRUE;
} else {
"configuring a new zone.\n"),
return (err);
}
}
return (Z_OK);
}
static boolean_t
{
int err;
/* all states are greater than "non-existent" */
return (B_FALSE);
}
}
/*
* short_usage() is for bad syntax: getopt() issues, too many arguments, etc.
*/
void
short_usage(int command)
{
/* lex_lineno has already been incremented in the lexer; compensate */
if (cmd_file_mode) {
gettext("syntax error on line %d\n"),
lex_lineno - 1);
else
gettext("syntax error on line %d of %s\n"),
}
}
/*
* long_usage() is for bad semantics: e.g., wrong property type for a given
* resource type. It is also used by longer_usage() below.
*/
void
{
if (set_saw)
}
/*
* longer_usage() is for 'help foo' and 'foo -?': call long_usage() and also
* any extra usage() flags as appropriate for whatever command.
*/
void
{
(void) printf("\n");
}
}
/*
* scope_usage() is simply used when a command is called from the wrong scope.
*/
static void
{
}
/*
* On input, B_TRUE => yes, B_FALSE => no.
* On return, B_TRUE => 1, B_FALSE => no, could not ask => -1.
*/
static int
{
if (!ok_to_prompt) {
return (-1);
}
for (;;) {
return (-1);
return (-1);
if (line[0] == '\n')
return (default_answer ? 1 : 0);
return (1);
return (0);
}
}
/*
* Prints warning if zone already exists.
* In interactive mode, prompts if we should continue anyway and returns Z_OK
* if so, Z_ERR if not. In non-interactive mode, exits with Z_ERR.
*
* Note that if a zone exists and its state is >= INSTALLED, an error message
* will be printed and this function will return Z_ERR regardless of mode.
*/
static int
{
}
return (Z_OK);
if (state_atleast(ZONE_STATE_INSTALLED)) {
return (Z_ERR);
}
if (force) {
zone);
return (Z_OK);
}
"specified:\n%s command ignored, exiting."),
}
}
static boolean_t
zone_is_read_only(int cmd_num)
{
zone);
return (B_TRUE);
}
if (read_only_mode) {
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Create a new configuration.
*/
void
{
char zone_template[ZONENAME_MAX];
char attach_path[MAXPATHLEN];
/* This is the default if no arguments are given. */
optind = 0;
!= EOF) {
switch (arg) {
case '?':
if (optopt == '?')
else
break;
case 'a':
sizeof (attach_path));
break;
case 'b':
sizeof (zone_template));
break;
case 'F':
break;
case 't':
sizeof (zone_template));
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
if (zone_is_read_only(CMD_CREATE))
return;
return;
/*
* Get a temporary handle first. If that fails, the old handle
* will not be lost. Then finish whichever one we don't need,
* to avoid leaks. Then get the handle for zone_template, and
* set the name to zone: this "copy, rename" method is how
* create -[b|t] works.
*/
}
if (attach)
else
"detached zone\n"));
"earlier release of the operating system\n"));
else
return;
}
got_handle = B_TRUE;
}
/*
* This malloc()'s memory, which must be freed by the caller.
*/
static char *
{
char *outstr;
}
return (outstr);
}
return (outstr);
}
static void
{
char *quote_str;
return;
}
void
{
struct zone_nwiftab nwiftab;
struct zone_fstab fstab;
struct zone_devtab devtab;
struct zone_attrtab attrtab;
struct zone_rctltab rctltab;
struct zone_dstab dstab;
struct zone_psettab psettab;
struct zone_mcaptab mcaptab;
struct zone_rctlvaltab *valptr;
struct zone_admintab admintab;
char bootargs[BOOTARGS_MAX];
char sched[MAXNAMELEN];
char brand[MAXNAMELEN];
char hostidp[HW_HOSTID_LEN];
char fsallowedp[ZONE_FS_ALLOWED_MAX];
char *limitpriv;
outfile[0] = '\0';
optind = 0;
switch (arg) {
case '?':
if (optopt == '?')
else
break;
case 'f':
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
} else {
goto done;
}
}
goto done;
}
}
switch (iptype) {
case ZS_SHARED:
break;
case ZS_EXCLUSIVE:
break;
}
}
}
sizeof (fsallowedp)) == Z_OK) {
}
goto done;
}
}
(void) zonecfg_endipdent(handle);
goto done;
}
/*
* Simple property values with embedded equal signs
* need to be quoted to prevent the lexer from
* mis-parsing them as complex name=value pairs.
*/
else
}
}
(void) zonecfg_endfsent(handle);
goto done;
}
}
(void) zonecfg_endnwifent(handle);
goto done;
}
}
(void) zonecfg_enddevent(handle);
char buf[128];
}
goto done;
}
}
}
(void) zonecfg_endrctlent(handle);
goto done;
}
}
(void) zonecfg_endattrent(handle);
goto done;
}
}
(void) zonecfg_enddsent(handle);
else
}
goto done;
}
}
(void) zonecfg_endadminent(handle);
/*
* There is nothing to export for pcap since this resource is just
* a container for an rctl alias.
*/
done:
if (need_to_close)
}
void
{
optind = 0;
switch (arg) {
case '?':
break;
case 'F':
force_exit = B_TRUE;
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
if (global_scope || force_exit) {
return;
}
if (answer == -1) {
"not from terminal and -F not specified:\n%s command "
} else if (answer == 1) {
}
/* (answer == 0) => just return */
}
static int
validate_zonepath_syntax(char *path)
{
if (path[0] != '/') {
return (Z_ERR);
}
/* If path is all slashes, then fail */
return (Z_ERR);
}
return (Z_OK);
}
static void
{
int type;
struct zone_psettab tmp_psettab;
struct zone_mcaptab tmp_mcaptab;
char pool[MAXNAMELEN];
goto bad;
}
switch (type) {
case RT_FS:
return;
case RT_IPD:
if (state_atleast(ZONE_STATE_INSTALLED)) {
goto bad;
}
return;
case RT_NET:
return;
case RT_DEVICE:
return;
case RT_RCTL:
if (global_zone)
"control too low could deny\nservice "
"to even the root user; "
"this could render the system impossible\n"
"to administer. Please use caution."));
return;
case RT_ATTR:
return;
case RT_DATASET:
return;
case RT_DCPU:
/* Make sure there isn't already a cpu-set or cpu-cap entry. */
goto bad;
}
Z_NO_ENTRY) {
goto bad;
}
/* Make sure the pool property isn't set. */
"A persistent pool is incompatible with\nthe %s "
"resource."),
goto bad;
}
return;
case RT_PCAP:
/*
* Make sure there isn't already a cpu-set or incompatible
* cpu-cap rctls.
*/
goto bad;
}
case Z_ALIAS_DISALLOW:
B_FALSE);
goto bad;
case Z_OK:
goto bad;
default:
break;
}
return;
case RT_MCAP:
/*
* Make sure there isn't already a mem-cap entry or max-swap
* or max-locked rctl.
*/
== Z_OK ||
goto bad;
}
if (global_zone)
"cap too low could deny\nservice "
"to even the root user; "
"this could render the system impossible\n"
"to administer. Please use caution."));
return;
case RT_ADMIN:
return;
default:
}
bad:
end_op = -1;
}
static void
{
struct zone_rctlvaltab *rctlvaltab;
int err;
}
case PT_PRIV:
if (seen_priv) {
goto bad;
}
sizeof (rctlvaltab->zone_rctlval_priv));
break;
case PT_LIMIT:
if (seen_limit) {
goto bad;
}
sizeof (rctlvaltab->zone_rctlval_limit));
seen_limit = B_TRUE;
break;
case PT_ACTION:
if (seen_action) {
goto bad;
}
sizeof (rctlvaltab->zone_rctlval_action));
break;
default:
return;
}
}
if (!seen_priv)
if (!seen_limit)
if (!seen_action)
goto bad;
/*
* Make sure the rctl value looks roughly correct; we won't know if
* it's truly OK until we verify the configuration on the target
* system.
*/
goto bad;
}
return;
bad:
}
static void
{
char *prop_id;
return;
}
return;
}
return;
switch (res_type) {
case RT_FS:
if (prop_type != PT_OPTIONS) {
B_TRUE);
return;
}
return;
}
return;
}
prop_id);
} else {
break;
B_TRUE);
}
}
return;
case RT_RCTL:
B_TRUE);
return;
}
return;
}
return;
}
return;
default:
return;
}
}
static boolean_t
gz_invalid_resource(int type)
{
type == RT_DATASET));
}
static boolean_t
{
}
static boolean_t
gz_invalid_property(int type)
{
}
void
{
int arg;
optind = 0;
switch (arg) {
case '?':
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
if (zone_is_read_only(CMD_ADD))
return;
return;
if (global_scope) {
return;
}
} else
}
/*
* This routine has an unusual implementation, because it tries very
* hard to succeed in the face of a variety of failure modes.
* The most common and most vexing occurs when the index file and
* the /etc/zones/<zonename.xml> file are not both present. In
* this case, delete must eradicate as much of the zone state as is left
* so that the user can later create a new zone with the same name.
*/
void
{
optind = 0;
switch (arg) {
case '?':
break;
case 'F':
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
if (zone_is_read_only(CMD_DELETE))
return;
if (!force) {
/*
* Initialize sets up the global called "handle" and warns the
* user if the zone is not configured. In force mode, we don't
* trust that evaluation, and hence skip it. (We don't need the
* handle to be loaded anyway, since zonecfg_destroy is done by
* zonename). However, we also have to take care to emulate the
* messages spit out by initialize; see below.
*/
return;
"specified:\n%s command ignored, exiting."),
}
if (answer != 1)
return;
}
/*
* This function removes the authorizations from user_attr
* that correspond to those specified in the configuration
*/
}
"allowed. Use -F to force %s."),
} else {
}
}
/*
* Emulate initialize's messaging; if there wasn't a valid handle to
* begin with, then user had typed delete (or delete -F) multiple
* times. So we emit a message.
*
* We only do this in the 'force' case because normally, initialize()
* takes care of this for us.
*/
/*
* Time for a new handle: finish the old one off first
* then get a new one properly to avoid leaks.
*/
if (got_handle) {
}
/* If there was no zone before, that's OK */
}
}
}
static int
{
int err, i;
return (err);
for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
return (Z_INSUFFICIENT_SPEC);
}
switch (cmd->cmd_prop_name[i]) {
case PT_DIR:
sizeof (fstab->zone_fs_dir));
break;
case PT_SPECIAL:
sizeof (fstab->zone_fs_special));
break;
case PT_RAW:
sizeof (fstab->zone_fs_raw));
break;
case PT_TYPE:
sizeof (fstab->zone_fs_type));
break;
default:
return (Z_INSUFFICIENT_SPEC);
}
}
if (fill_in_only)
return (Z_OK);
}
static int
{
int err, i;
return (err);
for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
return (Z_INSUFFICIENT_SPEC);
}
switch (cmd->cmd_prop_name[i]) {
case PT_DIR:
sizeof (ipdtab->zone_fs_dir));
break;
default:
return (Z_INSUFFICIENT_SPEC);
}
}
if (fill_in_only)
return (Z_OK);
}
static int
{
int err, i;
return (err);
for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
return (Z_INSUFFICIENT_SPEC);
}
switch (cmd->cmd_prop_name[i]) {
case PT_ADDRESS:
break;
case PT_PHYSICAL:
sizeof (nwiftab->zone_nwif_physical));
break;
case PT_DEFROUTER:
sizeof (nwiftab->zone_nwif_defrouter));
break;
default:
return (Z_INSUFFICIENT_SPEC);
}
}
if (fill_in_only)
return (Z_OK);
return (err);
}
static int
{
int err, i;
return (err);
for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
return (Z_INSUFFICIENT_SPEC);
}
switch (cmd->cmd_prop_name[i]) {
case PT_MATCH:
sizeof (devtab->zone_dev_match));
break;
default:
return (Z_INSUFFICIENT_SPEC);
}
}
if (fill_in_only)
return (Z_OK);
return (err);
}
static int
{
int err, i;
return (err);
for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
return (Z_INSUFFICIENT_SPEC);
}
switch (cmd->cmd_prop_name[i]) {
case PT_NAME:
sizeof (rctltab->zone_rctl_name));
break;
default:
return (Z_INSUFFICIENT_SPEC);
}
}
if (fill_in_only)
return (Z_OK);
return (err);
}
static int
{
int err, i;
return (err);
for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
return (Z_INSUFFICIENT_SPEC);
}
switch (cmd->cmd_prop_name[i]) {
case PT_NAME:
sizeof (attrtab->zone_attr_name));
break;
case PT_TYPE:
sizeof (attrtab->zone_attr_type));
break;
case PT_VALUE:
sizeof (attrtab->zone_attr_value));
break;
default:
return (Z_INSUFFICIENT_SPEC);
}
}
if (fill_in_only)
return (Z_OK);
return (err);
}
static int
{
int err, i;
return (err);
for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
return (Z_INSUFFICIENT_SPEC);
}
switch (cmd->cmd_prop_name[i]) {
case PT_NAME:
sizeof (dstab->zone_dataset_name));
break;
default:
return (Z_INSUFFICIENT_SPEC);
}
}
if (fill_in_only)
return (Z_OK);
}
static int
{
int err, i;
return (err);
for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
return (Z_INSUFFICIENT_SPEC);
}
switch (cmd->cmd_prop_name[i]) {
case PT_USER:
sizeof (admintab->zone_admin_user));
break;
case PT_AUTHS:
break;
default:
return (Z_INSUFFICIENT_SPEC);
}
}
if (fill_in_only)
return (Z_OK);
return (err);
}
static void
{
int err;
return;
}
} else {
}
}
static boolean_t
{
int num;
int answer;
int arg;
char prompt[128];
optind = 0;
switch (arg) {
case 'F':
break;
default:
break;
}
}
if (arg_err)
return (B_FALSE);
if (num == 0) {
B_TRUE);
return (B_FALSE);
}
if (!interactive_mode) {
"resource. Either qualify the resource to\n"
"remove a single instance or use the -F option to "
"remove all instances."));
return (B_FALSE);
}
"Are you sure you want to remove ALL '%s' resources"),
rsrc);
if (answer == -1) {
return (B_FALSE);
}
if (answer != 1)
return (B_FALSE);
}
return (B_TRUE);
}
static void
{
int err;
/* traditional, qualified fs removal */
if (cmd->cmd_prop_nv_pairs > 0) {
struct zone_fstab fstab;
return;
}
else
return;
}
/*
* unqualified fs removal. remove all fs's but prompt if more
* than one.
*/
return;
else
}
static void
{
int err;
if (state_atleast(ZONE_STATE_INSTALLED)) {
return;
}
/* traditional, qualified ipd removal */
if (cmd->cmd_prop_nv_pairs > 0) {
struct zone_fstab fstab;
return;
}
else
return;
}
/*
* unqualified ipd removal. remove all ipds but prompt if more
* than one.
*/
return;
!= Z_OK)
else
}
static void
{
int err;
/* traditional, qualified net removal */
if (cmd->cmd_prop_nv_pairs > 0) {
struct zone_nwiftab nwiftab;
return;
}
else
return;
}
/*
* unqualified net removal. remove all nets but prompt if more
* than one.
*/
return;
else
}
static void
{
int err;
/* traditional, qualified device removal */
if (cmd->cmd_prop_nv_pairs > 0) {
struct zone_devtab devtab;
return;
}
else
return;
}
/*
* unqualified device removal. remove all devices but prompt if more
* than one.
*/
return;
else
}
static void
{
int err;
/* traditional, qualified attr removal */
if (cmd->cmd_prop_nv_pairs > 0) {
struct zone_attrtab attrtab;
return;
}
else
return;
}
/*
* unqualified attr removal. remove all attrs but prompt if more
* than one.
*/
return;
else
}
static void
{
int err;
/* traditional, qualified dataset removal */
if (cmd->cmd_prop_nv_pairs > 0) {
struct zone_dstab dstab;
return;
}
else
return;
}
/*
* unqualified dataset removal. remove all datasets but prompt if more
* than one.
*/
return;
else
}
static void
{
int err;
/* traditional, qualified rctl removal */
if (cmd->cmd_prop_nv_pairs > 0) {
struct zone_rctltab rctltab;
return;
}
else
return;
}
/*
* unqualified rctl removal. remove all rctls but prompt if more
* than one.
*/
return;
else
}
static void
{
int err;
struct zone_psettab psettab;
return;
}
else
}
static void
{
int err;
return;
}
else
}
static void
{
struct zone_mcaptab mcaptab;
/* if none of these exist, there is no resource to remove */
return;
}
} else {
}
}
!= Z_OK) {
} else {
}
}
!= Z_OK) {
} else {
}
}
if (revert)
}
static void
{
int err;
/* traditional, qualified attr removal */
if (cmd->cmd_prop_nv_pairs > 0) {
struct zone_admintab admintab;
return;
}
zone))
!= Z_OK)
else
return;
} else {
/*
* unqualified admin removal.
* remove all admins but prompt if more
* than one.
*/
return;
!= Z_OK)
else
}
}
static void
{
int type;
int arg;
return;
}
optind = 0;
switch (arg) {
case '?':
break;
case 'F':
break;
default:
break;
}
}
if (arg_err)
return;
return;
switch (type) {
case RT_FS:
return;
case RT_IPD:
return;
case RT_NET:
return;
case RT_DEVICE:
return;
case RT_RCTL:
return;
case RT_ATTR:
return;
case RT_DATASET:
return;
case RT_DCPU:
remove_pset();
return;
case RT_PCAP:
remove_pcap();
return;
case RT_MCAP:
remove_mcap();
return;
case RT_ADMIN:
return;
default:
return;
}
}
static void
{
char *prop_id;
struct zone_rctlvaltab *rctlvaltab;
return;
}
return;
}
return;
switch (res_type) {
case RT_FS:
if (prop_type != PT_OPTIONS) {
B_TRUE);
return;
}
return;
}
return;
}
prop_id);
} else {
break;
B_TRUE);
}
}
return;
case RT_RCTL:
B_TRUE);
return;
}
return;
}
}
case PT_PRIV:
sizeof (rctlvaltab->zone_rctlval_priv));
break;
case PT_LIMIT:
sizeof (rctlvaltab->zone_rctlval_limit));
break;
case PT_ACTION:
sizeof (rctlvaltab->zone_rctlval_action));
break;
default:
return;
}
}
return;
case RT_NET:
if (prop_type != PT_DEFROUTER) {
B_TRUE);
return;
} else {
sizeof (in_progress_nwiftab.zone_nwif_defrouter));
return;
}
default:
return;
}
}
void
{
if (zone_is_read_only(CMD_REMOVE))
return;
if (global_scope) {
return;
}
} else {
}
}
static void
{
return;
}
return;
switch (res_type) {
case RT_FS:
return;
}
break;
case RT_DCPU:
if (prop_type == PT_IMPORTANCE) {
return;
}
break;
case RT_MCAP:
switch (prop_type) {
case PT_PHYSICAL:
return;
case PT_SWAP:
return;
case PT_LOCKED:
return;
}
break;
default:
break;
}
}
static void
{
return;
}
return;
switch (type) {
case PT_ZONENAME:
/* FALLTHRU */
case PT_ZONEPATH:
/* FALLTHRU */
case PT_BRAND:
return;
case PT_AUTOBOOT:
/* false is default; we'll treat as equivalent to clearing */
else
return;
case PT_POOL:
else
return;
case PT_LIMITPRIV:
else
return;
case PT_BOOTARGS:
else
return;
case PT_SCHED:
else
return;
case PT_IPTYPE:
/* shared is default; we'll treat as equivalent to clearing */
else
return;
case PT_MAXLWPS:
return;
case PT_MAXSHMMEM:
return;
case PT_MAXSHMIDS:
return;
case PT_MAXMSGIDS:
return;
case PT_MAXSEMIDS:
return;
case PT_SHARES:
return;
case PT_HOSTID:
else
return;
case PT_FS_ALLOWED:
else
return;
default:
return;
}
}
void
{
if (zone_is_read_only(CMD_CLEAR))
return;
if (global_scope) {
return;
}
} else {
}
}
void
{
if (zone_is_read_only(CMD_SELECT))
return;
if (global_scope) {
end_op = CMD_SELECT;
} else {
return;
}
return;
}
return;
switch (type) {
case RT_FS:
}
sizeof (struct zone_fstab));
return;
case RT_IPD:
if (state_atleast(ZONE_STATE_INCOMPLETE)) {
"allowed."), zone,
end_op = -1;
return;
}
}
sizeof (struct zone_fstab));
return;
case RT_NET:
!= Z_OK) {
}
sizeof (struct zone_nwiftab));
return;
case RT_DEVICE:
}
sizeof (struct zone_devtab));
return;
case RT_RCTL:
!= Z_OK) {
}
sizeof (struct zone_rctltab));
return;
case RT_ATTR:
!= Z_OK) {
}
sizeof (struct zone_attrtab));
return;
case RT_DATASET:
}
sizeof (struct zone_dstab));
return;
case RT_DCPU:
}
sizeof (struct zone_psettab));
return;
case RT_PCAP:
!= Z_OK) {
}
return;
case RT_MCAP:
/* if none of these exist, there is no resource to select */
!= Z_OK &&
!= Z_OK) {
B_TRUE);
}
sizeof (struct zone_mcaptab));
else
sizeof (in_progress_mcaptab));
return;
case RT_ADMIN:
!= Z_OK) {
B_TRUE);
}
sizeof (struct zone_admintab));
return;
default:
return;
}
}
/*
* Network "addresses" can be one of the following forms:
* <IPv4 address>
* <IPv4 address>/<prefix length>
* <IPv6 address>/<prefix length>
* <host name>
* <host name>/<prefix length>
* In other words, the "/" followed by a prefix length is allowed but not
* required for IPv4 addresses and host names, and required for IPv6 addresses.
* If a prefix length is given, it must be in the allowable range: 0 to 32 for
* IPv4 addresses and host names, 0 to 128 for IPv6 addresses.
* Host names must start with an alpha-numeric character, and all subsequent
* characters must be either alpha-numeric or "-".
*/
static int
{
int prefixlen, i;
/*
* Copy the part before any '/' into part1 or copy the whole
* thing if there is no '/'.
*/
*slashp = '\0';
*slashp = '/';
} else {
}
"require /prefix-length suffix."), address);
return (Z_ERR);
}
"prefix lengths must be 0 - 128."), address);
return (Z_ERR);
}
return (Z_OK);
}
/* At this point, any /prefix must be for IPv4. */
"prefix lengths must be 0 - 32."), address);
return (Z_ERR);
}
}
return (Z_OK);
/* address may also be a host name */
part1);
return (Z_ERR);
}
for (i = 1; part1[i]; i++)
"network address syntax"), part1);
return (Z_ERR);
}
return (Z_OK);
}
static int
validate_net_physical_syntax(const char *ifname)
{
"ip-type property"));
return (Z_ERR);
}
switch (iptype) {
case ZS_SHARED:
ifname);
return (Z_ERR);
}
if (ifnameprop.ifsp_lunvalid) {
"interface names"), ifname);
return (Z_ERR);
}
break;
case ZS_EXCLUSIVE:
"required; logical interface name not "
"allowed"), ifname);
else
"name"), ifname);
return (Z_ERR);
}
break;
}
return (Z_OK);
}
static boolean_t
valid_fs_type(const char *type)
{
/*
* Is this a valid path component?
*/
return (B_FALSE);
/*
* Make sure a bad value for "type" doesn't make
*/
return (B_FALSE);
/*
* More detailed verification happens later by zoneadm(1m).
*/
return (B_TRUE);
}
static boolean_t
{
char brand[MAXNAMELEN];
return (B_FALSE);
}
return (B_FALSE);
}
if (!ret)
return (ret);
}
static void
{
int err;
char tmp[128];
"control too low could deny\nservice "
"to even the root user; "
"this could render the system impossible\n"
"to administer. Please use caution."));
/* convert memory based properties */
if (prop_type == PT_MAXSHMMEM) {
if (!zonecfg_valid_memlimit(s, &limit)) {
"scale suffix (K, M, G or T) was expected\nhere."));
return;
}
s = tmp;
}
!= Z_OK) {
} else {
}
}
void
{
char *prop_id;
float cap;
char *unitp;
struct zone_psettab tmp_psettab;
if (zone_is_read_only(CMD_SET))
return;
switch (arg) {
case 'F':
break;
default:
if (optopt == '?')
else
break;
}
}
if (arg_err)
return;
if (global_scope) {
if (gz_invalid_property(prop_type)) {
return;
}
if (prop_type == PT_ZONENAME) {
} else if (prop_type == PT_ZONEPATH) {
} else if (prop_type == PT_AUTOBOOT) {
} else if (prop_type == PT_LIMITPRIV) {
} else if (prop_type == PT_BOOTARGS) {
} else if (prop_type == PT_MAXLWPS) {
} else if (prop_type == PT_MAXSHMMEM) {
} else if (prop_type == PT_MAXSHMIDS) {
} else if (prop_type == PT_MAXMSGIDS) {
} else if (prop_type == PT_MAXSEMIDS) {
} else if (prop_type == PT_FS_ALLOWED) {
} else {
"from the global scope."));
return;
}
} else {
}
if (force_set) {
if (res_type != RT_ZONEPATH) {
return;
}
if (!zonecfg_in_alt_root()) {
"alternate root."));
return;
}
}
/*
* A nasty expression but not that complicated:
* 1. fs options are simple or list (tested below)
* 2. rctl value's are complex or list (tested below)
* Anything else should be simple.
*/
return;
}
if (prop_type == PT_UNKNOWN) {
return;
}
/*
* Special case: the user can change the zone name prior to 'create';
* if the zone already exists, we fall through letting initialize()
* and the rest of the logic run.
*/
return;
}
return;
}
return;
switch (res_type) {
case RT_ZONENAME:
/*
* Use prop_id instead of 'zone' here, since we're
* reporting a problem about the *new* zonename.
*/
} else {
}
return;
case RT_ZONEPATH:
return;
}
return;
}
else
return;
case RT_BRAND:
if (state_atleast(ZONE_STATE_INSTALLED)) {
return;
}
else
return;
case RT_AUTOBOOT:
} else {
return;
}
else
return;
case RT_POOL:
/* don't allow use of the reserved temporary pool names */
"reserved."));
return;
}
/* can't set pool if dedicated-cpu exists */
"A persistent pool is incompatible\nwith the %s "
return;
}
else
return;
case RT_LIMITPRIV:
else
return;
case RT_BOOTARGS:
else
return;
case RT_SCHED:
else
return;
case RT_IPTYPE:
} else {
return;
}
return;
}
else
return;
case RT_MAXLWPS:
return;
case RT_MAXSHMMEM:
return;
case RT_MAXSHMIDS:
return;
case RT_MAXMSGIDS:
return;
case RT_MAXSEMIDS:
return;
case RT_SHARES:
return;
case RT_HOSTID:
prop_id);
} else {
}
return;
}
return;
case RT_FS_ALLOWED:
else
return;
case RT_FS:
switch (prop_type) {
case PT_DIR:
sizeof (in_progress_fstab.zone_fs_dir));
return;
case PT_SPECIAL:
sizeof (in_progress_fstab.zone_fs_special));
return;
case PT_RAW:
return;
case PT_TYPE:
if (!valid_fs_type(prop_id)) {
return;
}
sizeof (in_progress_fstab.zone_fs_type));
return;
case PT_OPTIONS:
return;
}
return;
default:
break;
}
return;
case RT_IPD:
switch (prop_type) {
case PT_DIR:
sizeof (in_progress_ipdtab.zone_fs_dir));
return;
default:
break;
}
return;
case RT_NET:
switch (prop_type) {
case PT_ADDRESS:
return;
}
sizeof (in_progress_nwiftab.zone_nwif_address));
break;
case PT_PHYSICAL:
return;
}
sizeof (in_progress_nwiftab.zone_nwif_physical));
break;
case PT_DEFROUTER:
return;
}
sizeof (in_progress_nwiftab.zone_nwif_defrouter));
break;
default:
B_TRUE);
return;
}
return;
case RT_DEVICE:
switch (prop_type) {
case PT_MATCH:
sizeof (in_progress_devtab.zone_dev_match));
break;
default:
B_TRUE);
return;
}
return;
case RT_RCTL:
switch (prop_type) {
case PT_NAME:
if (!zonecfg_valid_rctlname(prop_id)) {
return;
}
sizeof (in_progress_rctltab.zone_rctl_name));
break;
case PT_VALUE:
return;
}
break;
default:
B_TRUE);
return;
}
return;
case RT_ATTR:
switch (prop_type) {
case PT_NAME:
sizeof (in_progress_attrtab.zone_attr_name));
break;
case PT_TYPE:
sizeof (in_progress_attrtab.zone_attr_type));
break;
case PT_VALUE:
sizeof (in_progress_attrtab.zone_attr_value));
break;
default:
B_TRUE);
return;
}
return;
case RT_DATASET:
switch (prop_type) {
case PT_NAME:
sizeof (in_progress_dstab.zone_dataset_name));
return;
default:
break;
}
return;
case RT_DCPU:
switch (prop_type) {
case PT_NCPUS:
*highp++ = '\0';
else
/* Make sure the input makes sense. */
return;
}
(void) strlcpy(
sizeof (in_progress_psettab.zone_ncpu_min));
(void) strlcpy(
sizeof (in_progress_psettab.zone_ncpu_max));
return;
case PT_IMPORTANCE:
/* Make sure the value makes sense. */
if (!zonecfg_valid_importance(prop_id)) {
return;
}
sizeof (in_progress_psettab.zone_importance));
return;
default:
break;
}
return;
case RT_PCAP:
B_TRUE);
return;
}
/*
* We already checked that an rctl alias is allowed in
* the add_resource() function.
*/
return;
}
else
return;
case RT_MCAP:
switch (prop_type) {
case PT_PHYSICAL:
"required scale suffix (K, M, G or T) was "
"expected here."));
} else {
}
break;
case PT_SWAP:
/*
* We have to check if an rctl is allowed here since
* there might already be a rctl defined that blocks
* the alias.
*/
return;
}
if (global_zone)
else
"required scale suffix (K, M, G or T) was "
"expected here."));
char buf[128];
buf);
} else {
else
}
break;
case PT_LOCKED:
/*
* We have to check if an rctl is allowed here since
* there might already be a rctl defined that blocks
* the alias.
*/
return;
}
"required scale suffix (K, M, G or T) was "
"expected\nhere."));
} else {
else
}
break;
default:
B_TRUE);
return;
}
return;
case RT_ADMIN:
switch (prop_type) {
case PT_USER:
sizeof (in_progress_admintab.zone_admin_user));
return;
case PT_AUTHS:
sizeof (in_progress_admintab.zone_admin_auths));
return;
default:
B_TRUE);
return;
}
default:
return;
}
}
static void
{
char *qstr;
if (*pval != '\0') {
qstr);
else
} else if (print_notspec)
}
static void
{
char zonename[ZONENAME_MAX];
zonename);
else
}
static void
{
char zonepath[MAXPATHLEN];
zonepath);
else {
}
}
static void
{
char brand[MAXNAMELEN];
brand);
else
gettext("not specified"));
}
static void
{
int err;
else
}
static void
{
char pool[MAXNAMELEN];
int err;
else
}
static void
{
char *limitpriv;
int err;
} else {
}
}
static void
{
char bootargs[BOOTARGS_MAX];
int err;
bootargs);
} else {
}
}
static void
{
char sched[MAXNAMELEN];
int err;
== Z_OK) {
} else {
}
}
static void
{
int err;
switch (iptype) {
case ZS_SHARED:
"shared");
break;
case ZS_EXCLUSIVE:
"exclusive");
break;
}
} else {
}
}
static void
{
char hostidp[HW_HOSTID_LEN];
int err;
} else if (err == Z_BAD_PROPERTY) {
} else {
}
}
static void
{
char fsallowedp[ZONE_FS_ALLOWED_MAX];
int err;
sizeof (fsallowedp))) == Z_OK) {
} else if (err == Z_BAD_PROPERTY) {
} else {
}
}
static void
{
else
}
}
static void
{
}
static void
{
return;
if (cmd->cmd_prop_nv_pairs == 0) {
goto loopend;
}
goto loopend;
goto loopend; /* no match */
goto loopend; /* no match */
goto loopend; /* no match */
}
(void) zonecfg_endfsent(handle);
/*
* If a property n/v pair was specified, warn the user if there was
* nothing to output.
*/
}
static void
{
return;
if (cmd->cmd_prop_nv_pairs == 0) {
continue;
}
continue;
continue; /* no match */
}
(void) zonecfg_endipdent(handle);
/*
* If a property n/v pair was specified, warn the user if there was
* nothing to output.
*/
}
static void
{
}
static void
{
return;
if (cmd->cmd_prop_nv_pairs == 0) {
continue;
}
continue;
lookup.zone_nwif_physical) != 0)
continue; /* no match */
/* If present make sure it matches */
continue; /* no match */
}
(void) zonecfg_endnwifent(handle);
/*
* If a property n/v pair was specified, warn the user if there was
* nothing to output.
*/
}
static void
{
}
static void
{
return;
if (cmd->cmd_prop_nv_pairs == 0) {
continue;
}
continue;
continue; /* no match */
}
(void) zonecfg_enddevent(handle);
/*
* If a property n/v pair was specified, warn the user if there was
* nothing to output.
*/
}
static void
{
struct zone_rctlvaltab *valptr;
}
}
static void
{
return;
if (cmd->cmd_prop_nv_pairs == 0) {
}
}
(void) zonecfg_endrctlent(handle);
/*
* If a property n/v pair was specified, warn the user if there was
* nothing to output.
*/
}
static void
{
}
static void
{
return;
if (cmd->cmd_prop_nv_pairs == 0) {
continue;
}
continue;
continue; /* no match */
continue; /* no match */
continue; /* no match */
}
(void) zonecfg_endattrent(handle);
/*
* If a property n/v pair was specified, warn the user if there was
* nothing to output.
*/
}
static void
{
}
static void
{
return;
if (cmd->cmd_prop_nv_pairs == 0) {
continue;
}
continue;
lookup.zone_dataset_name) != 0)
continue; /* no match */
}
(void) zonecfg_enddsent(handle);
/*
* If a property n/v pair was specified, warn the user if there was
* nothing to output.
*/
}
static void
{
else
}
static void
{
struct zone_psettab lookup;
}
static void
{
scaled);
}
}
static void
{
}
static void
{
/* convert memory based properties */
char buf[128];
return;
}
}
}
static void
{
unsigned long long num;
unsigned long long save = 0;
char *units = "BKMGT";
if (num < 1024) {
return;
}
up++; /* next unit of measurement */
}
/* check if we should output a fraction. snprintf will round for us */
*up);
else
}
static void
{
char buf[128];
}
}
if (showlocked == Z_OK) {
}
}
static void
{
struct zone_mcaptab lookup;
&locked_limit);
}
static void
{
}
static void
{
int err;
return;
}
if (cmd->cmd_prop_nv_pairs == 0) {
continue;
}
continue;
continue; /* no match */
}
(void) zonecfg_endadminent(handle);
/*
* If a property n/v pair was specified, warn the user if there was
* nothing to output.
*/
}
void
{
char *pager;
int type;
return;
/* don't page error output */
if (interactive_mode) {
else
} else {
}
}
if (!global_scope) {
switch (resource_scope) {
case RT_FS:
break;
case RT_IPD:
break;
case RT_NET:
break;
case RT_DEVICE:
break;
case RT_RCTL:
break;
case RT_ATTR:
break;
case RT_DATASET:
break;
case RT_DCPU:
break;
case RT_PCAP:
break;
case RT_MCAP:
&swap_limit);
res2, locked_limit);
break;
case RT_ADMIN:
break;
}
goto cleanup;
}
if (gz_invalid_rt_property(type)) {
goto cleanup;
}
if (gz_invalid_resource(type)) {
goto cleanup;
}
switch (cmd->cmd_res_type) {
case RT_UNKNOWN:
if (!global_zone) {
}
if (!global_zone) {
}
if (!global_zone) {
}
if (!global_zone) {
}
break;
case RT_ZONENAME:
break;
case RT_ZONEPATH:
break;
case RT_BRAND:
break;
case RT_AUTOBOOT:
break;
case RT_POOL:
break;
case RT_LIMITPRIV:
break;
case RT_BOOTARGS:
break;
case RT_SCHED:
break;
case RT_IPTYPE:
break;
case RT_MAXLWPS:
break;
case RT_MAXSHMMEM:
break;
case RT_MAXSHMIDS:
break;
case RT_MAXMSGIDS:
break;
case RT_MAXSEMIDS:
break;
case RT_SHARES:
break;
case RT_FS:
break;
case RT_IPD:
break;
case RT_NET:
break;
case RT_DEVICE:
break;
case RT_RCTL:
break;
case RT_ATTR:
break;
case RT_DATASET:
break;
case RT_DCPU:
break;
case RT_PCAP:
break;
case RT_MCAP:
break;
case RT_HOSTID:
break;
case RT_ADMIN:
break;
case RT_FS_ALLOWED:
break;
default:
B_TRUE);
}
if (need_to_close)
}
/*
* Helper function for verify-- checks that a required string property
* exists.
*/
static void
{
}
}
static int
do_subproc(char *cmdbuf)
{
char inbuf[MAX_CMD_LEN];
int status;
return (-1);
}
if (WIFSIGNALED(status)) {
return (-1);
}
return (WEXITSTATUS(status));
}
static int
{
char xml_file[32];
char cmdbuf[MAX_CMD_LEN];
char brand[MAXNAMELEN];
int err;
return (Z_INVALID_DOCUMENT);
}
return (Z_INVALID_DOCUMENT);
}
/*
* Fetch the verify command, if any, from the brand configuration
* and build the command line to execute it.
*/
gettext("could not get brand verification command"));
return (Z_INVALID_DOCUMENT);
}
/*
* If the brand doesn't provide a verification routine, we just
* return success.
*/
return (Z_OK);
/*
* Dump the current config information for this zone to a file.
*/
return (Z_TEMP_FILE);
return (err);
}
/*
* Execute the verification command.
*/
err = Z_BRAND_ERROR;
} else {
}
}
/*
* See the DTD for which attributes are required for which resources.
*
* This function can be called by commit_func(), which needs to save things,
* in addition to the general call from parse_and_run(), which doesn't need
* things saved. Since the parameters are standardized, we distinguish by
* having commit_func() call here with cmd->cmd_arg set to "save" to indicate
* that a save is needed.
*/
void
{
struct zone_nwiftab nwiftab;
struct zone_fstab fstab;
struct zone_attrtab attrtab;
struct zone_rctltab rctltab;
struct zone_dstab dstab;
struct zone_psettab psettab;
struct zone_admintab admintab;
char zonepath[MAXPATHLEN];
char sched[MAXNAMELEN];
char brand[MAXNAMELEN];
char hostidp[HW_HOSTID_LEN];
char fsallowedp[ZONE_FS_ALLOWED_MAX];
int pset_res;
optind = 0;
switch (arg) {
case '?':
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
if (zone_is_read_only(CMD_VERIFY))
return;
return;
!global_zone) {
}
}
return;
}
return;
}
}
return;
}
}
(void) zonecfg_endipdent(handle);
sizeof (hostidp)) == Z_INVALID_PROPERTY) {
return;
}
sizeof (fsallowedp)) == Z_INVALID_PROPERTY) {
zone, fsallowedp);
return;
}
return;
}
&ret_val);
}
(void) zonecfg_endfsent(handle);
return;
}
/*
* physical is required in all cases.
* A shared IP requires an address,
* and may include a default router, while
* an exclusive IP must have neither an address
* nor a default router.
* The physical interface name must be valid in all cases.
*/
PT_PHYSICAL, &ret_val);
Z_OK) {
}
switch (iptype) {
case ZS_SHARED:
PT_ADDRESS, &ret_val);
break;
case ZS_EXCLUSIVE:
"for an exclusive IP type"),
}
"for an exclusive IP type"),
}
break;
}
}
(void) zonecfg_endnwifent(handle);
return;
}
&ret_val);
} else {
}
}
(void) zonecfg_endrctlent(handle);
}
"incompatible"),
}
}
return;
}
&ret_val);
&ret_val);
&ret_val);
}
(void) zonecfg_endattrent(handle);
return;
}
}
}
(void) zonecfg_enddsent(handle);
return;
}
== NULL)) {
}
}
}
(void) zonecfg_endadminent(handle);
if (!global_scope) {
}
if (save) {
sizeof (revert_zone));
}
} else {
}
}
}
void
{
int arg;
optind = 0;
switch (arg) {
case '?':
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
if (global_scope)
}
static int
validate_attr_name(char *name)
{
int i;
return (Z_INVAL);
}
for (i = 1; name[i]; i++)
"alpha-numeric characters, plus '-' and '.'."),
return (Z_INVAL);
}
return (Z_OK);
}
static int
{
char strval[MAXNAMELEN];
return (Z_OK);
return (Z_ERR);
}
return (Z_OK);
return (Z_ERR);
}
return (Z_OK);
return (Z_ERR);
}
return (Z_OK);
return (Z_ERR);
}
return (Z_ERR);
}
/*
* Helper function for end_func-- checks the existence of a given property
* and emits a message if not specified.
*/
static int
{
return (Z_ERR);
}
return (Z_OK);
}
void
{
struct zone_fstab tmp_fstab;
struct zone_nwiftab tmp_nwiftab;
struct zone_devtab tmp_devtab;
struct zone_rctltab tmp_rctltab;
struct zone_attrtab tmp_attrtab;
struct zone_dstab tmp_dstab;
struct zone_admintab tmp_admintab;
optind = 0;
switch (arg) {
case '?':
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
if (global_scope) {
return;
}
switch (resource_scope) {
case RT_FS:
/* First make sure everything was filled in. */
}
}
}
if (validation_failed) {
return;
}
/* Make sure there isn't already one like this. */
sizeof (tmp_fstab.zone_fs_dir));
"with the %s '%s' already exists."),
return;
}
} else {
}
break;
case RT_IPD:
/* First make sure everything was filled in. */
&validation_failed) == Z_OK) {
}
}
if (validation_failed) {
return;
}
/* Make sure there isn't already one like this. */
sizeof (tmp_fstab.zone_fs_dir));
"with the %s '%s' already exists."),
return;
}
} else {
}
break;
case RT_NET:
/*
* First make sure everything was filled in.
* Since we don't know whether IP will be shared
* or exclusive here, some checks are deferred until
* the verify command.
*/
if (validation_failed) {
return;
}
/* Make sure there isn't already one like this. */
sizeof (tmp_nwiftab.zone_nwif_physical));
sizeof (tmp_nwiftab.zone_nwif_address));
"and %s '%s' already exists."),
return;
}
} else {
}
break;
case RT_DEVICE:
/* First make sure everything was filled in. */
if (validation_failed) {
return;
}
/* Make sure there isn't already one like this. */
sizeof (tmp_devtab.zone_dev_match));
return;
}
} else {
}
break;
case RT_RCTL:
/* First make sure everything was filled in. */
}
if (validation_failed) {
return;
}
/* Make sure there isn't already one like this. */
sizeof (tmp_rctltab.zone_rctl_name));
"with the %s '%s' already exists."),
return;
}
} else {
}
}
break;
case RT_ATTR:
/* First make sure everything was filled in. */
Z_OK)
if (validation_failed) {
return;
}
/* Make sure there isn't already one like this. */
sizeof (tmp_attrtab.zone_attr_name));
"with the %s '%s' already exists."),
return;
}
} else {
}
break;
case RT_DATASET:
/* First make sure everything was filled in. */
gettext("not specified"));
}
if (validation_failed)
return;
/* Make sure there isn't already one like this. */
sizeof (tmp_dstab.zone_dataset_name));
"with the %s '%s' already exists."),
return;
}
} else {
}
break;
case RT_DCPU:
/* Make sure everything was filled in. */
return;
}
} else {
}
break;
case RT_PCAP:
/* Make sure everything was filled in. */
!= Z_OK) {
return;
}
break;
case RT_MCAP:
/* Make sure everything was filled in. */
&swap_limit);
&locked_limit);
return;
}
/* if phys & locked are both set, verify locked <= phys */
char *endp;
if (phys_limit < locked_limit) {
"equal to the %s cap."),
return;
}
}
/*
* We could be ending from either an add operation
* or a select operation. Since all of the properties
* within this resource are optional, we always use
* modify on the mcap entry. zonecfg_modify_mcap()
* will handle both adding and modifying a memory cap.
*/
} else if (end_op == CMD_SELECT) {
/*
* If we're ending from a select and the physical
* memory cap is empty then the user could have cleared
* the physical cap value, so try to delete the entry.
*/
(void) zonecfg_delete_mcap(handle);
}
break;
case RT_ADMIN:
/* First make sure everything was filled in. */
== NULL) {
}
}
if (!zonecfg_valid_auths(
zone)) {
}
}
if (validation_failed) {
return;
}
/* Make sure there isn't already one like this. */
sizeof (tmp_admintab.zone_admin_user));
handle, &tmp_admintab);
"with the %s '%s' already exists."),
return;
}
} else {
zone);
}
break;
default:
B_TRUE);
return;
}
} else {
end_op = -1;
}
}
void
{
int arg;
optind = 0;
switch (arg) {
case '?':
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
if (zone_is_read_only(CMD_COMMIT))
return;
/*
* cmd_arg normally comes from a strdup() in the lexer, and the
* whole cmd structure and its (char *) attributes are freed at
* the completion of each command, so the strdup() below is needed
* to match this and prevent a core dump from trying to free()
* something that can't be.
*/
}
}
void
{
optind = 0;
switch (arg) {
case '?':
break;
case 'F':
break;
default:
break;
}
}
if (arg_err)
return;
return;
}
if (zone_is_read_only(CMD_REVERT))
return;
if (!global_scope) {
" '%s' to cancel changes to a resource specification."),
return;
}
return;
}
if (!force) {
gettext("Are you sure you want to revert"));
"specified:\n%s command ignored, exiting."),
}
if (answer != 1)
return;
}
/*
* Reset any pending admins that were
* removed from the previous zone
*/
/*
* Time for a new handle: finish the old one off first
* then get a new one properly to avoid leaks.
*/
}
else
}
}
void
{
int i;
return;
}
return;
}
return;
}
return;
}
return;
}
for (i = 0; i <= CMD_MAX; i++) {
longer_usage(i);
return;
}
}
/* We do not use zerr() here because we do not want its extra \n. */
}
static int
string_to_yyin(char *string)
{
return (Z_ERR);
}
return (Z_ERR);
}
return (Z_ERR);
}
return (Z_OK);
}
/* This is the back-end helper function for read_input() below. */
static int
cleanup()
{
int answer;
if (!interactive_mode && !cmd_file_mode) {
/*
* If we're not in interactive mode, and we're not in command
* file mode, then we must be in commands-from-the-command-line
* mode. As such, we can't loop back and ask for more input.
* It was OK to prompt for such things as whether or not to
* really delete a zone in the command handler called from
* yyparse() above, but "really quit?" makes no sense in this
* context. So disable prompting.
*/
}
if (!global_scope) {
if (!time_to_exit) {
/*
* Just print a simple error message in the -1 case,
* since exit_func() already handles that case, and
* EOF means we are finished anyway.
*/
gettext("Resource incomplete; really quit"));
if (answer == -1) {
return (Z_ERR);
}
if (answer != 1) {
return (Z_REPEAT);
}
} else {
}
}
/*
* Make sure we tried something and that the handle checks
* out, or we would get a false error trying to commit.
*/
return (Z_ERR);
}
/*
* need_to_commit will get set back to FALSE if the
* configuration is saved successfully.
*/
if (need_to_commit) {
if (force_exit) {
return (Z_ERR);
}
gettext("Configuration not saved; really quit"));
if (answer == -1) {
return (Z_ERR);
}
if (answer != 1) {
return (Z_REPEAT);
}
}
}
}
/*
* read_input() is the driver of this program. It is a wrapper around
* yyparse(), printing appropriate prompts when needed, checking for
* exit conditions and reacting appropriately [the latter in its cleanup()
* helper function].
*
* Like most zonecfg functions, it returns Z_OK or Z_ERR, *or* Z_REPEAT
* so do_interactive() knows that we are not really done (i.e, we asked
* the user if we should really quit and the user said no).
*/
static int
{
/*
* The prompt is "e:z> " or "e:z:r> " where e is execname, z is zone
* and r is resource_scope: 5 is for the two ":"s + "> " + terminator.
*/
/* yyin should have been set to the appropriate (FILE *) if not stdin */
for (;;) {
if (yyin_is_a_tty) {
if (newline_terminated) {
if (global_scope)
else
}
/*
* If the user hits ^C then we want to catch it and
* start over. If the user hits EOF then we want to
* bail out.
*/
continue;
}
break;
(void) string_to_yyin(line);
yyparse();
} else {
yyparse();
}
/* Bail out on an error in command file mode. */
break;
}
return (cleanup());
}
/*
* This function is used in the zonecfg-interactive-mode scenario: it just
* calls read_input() until we are done.
*/
static int
do_interactive(void)
{
int err;
if (!read_only_mode) {
/*
* Try to set things up proactively in interactive mode, so
* that if the zone in question does not exist yet, we can
* provide the user with a clue.
*/
(void) initialize(B_FALSE);
}
do {
err = read_input();
return (err);
}
/*
* cmd_file is slightly more complicated, as it has to open the command file
* and set yyin appropriately. Once that is done, though, it just calls
* read_input(), and only once, since prompting is not possible.
*/
static int
{
int err;
if (using_real_file) {
/*
* zerr() prints a line number in cmd_file_mode, which we do
* not want here, so temporarily unset it.
*/
return (Z_ERR);
}
goto done;
}
goto done;
}
} else {
/*
* "-f -" is essentially the same as interactive mode,
* so treat it that way.
*/
}
/* Z_REPEAT is for interactive mode; treat it like Z_ERR here. */
done:
if (using_real_file)
return (err);
}
/*
* Since yacc is based on reading from a (FILE *) whereas what we get from
* the command line is in argv format, we need to convert when the user
* gives us commands directly from the command line. That is done here by
* concatenating the argv list into a space-separated string, writing it
* to a temp file, and rewinding the file so yyin can be set to it. Then
* we call read_input(), and only once, since prompting about whether to
* continue or quit would make no sense in this context.
*/
static int
{
char *command;
int i, err;
for (i = 0; i < argc; i++)
return (Z_ERR);
}
for (i = 1; i < argc; i++) {
}
return (err);
yyparse();
return (cleanup());
}
static char *
get_execbasename(char *execfullname)
{
char *last_slash, *execbasename;
/* guard against '/' at end of command invocation */
for (;;) {
if (last_slash == NULL) {
break;
} else {
if (*execbasename == '\0') {
*last_slash = '\0';
continue;
}
break;
}
}
return (execbasename);
}
int
{
/* This must be before anything goes to stdout. */
(void) textdomain(TEXT_DOMAIN);
if (getzoneid() != GLOBAL_ZONEID) {
execname);
}
if (argc < 2) {
}
}
switch (arg) {
case '?':
if (optopt == '?')
else
/* NOTREACHED */
case 'f':
break;
case 'R':
if (*optarg != '/') {
optarg);
}
"root path must be a directory: %s"),
optarg);
}
break;
case 'z':
}
break;
default:
}
}
}
/* skip this message in one-off from command line mode */
"have write access to this zone's configuration "
"file;\ngoing into read-only mode.\n"));
} else {
}
}
/*
* This may get set back to FALSE again in cmd_file() if cmd_file_name
* is a "real" file as opposed to "-" (i.e. meaning use stdin).
*/
if (isatty(STDIN_FILENO))
if (!cmd_file_mode)
err = do_interactive();
else
} else {
}
(void) del_GetLine(gl);
return (err);
}