svccfg_libscf.c revision 9e9ae1fc5a2cf0c35d578ad826dff4763cd0a605
/*
* 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 <alloca.h>
#include <assert.h>
#include <ctype.h>
#include <door.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <libintl.h>
#include <libscf.h>
#include <libscf_priv.h>
#include <libtecla.h>
#include <libuutil.h>
#include <limits.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include "svccfg.h"
/* The colon namespaces in each entity (each followed by a newline). */
#define COLON_NAMESPACES ":properties\n"
#define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
/* These are characters which the lexer requires to be in double-quotes. */
#define CHARS_TO_QUOTE " \t\n>=\"()"
#define HASH_SIZE 16
#define HASH_PG_TYPE "framework"
#define HASH_PG_FLAGS 0
#define HASH_PROP "md5sum"
/*
* These are the classes of elements which may appear as children of service
* or instance elements in XML manifests.
*/
struct entity_elts {
};
/*
* Likewise for property_group elements.
*/
struct pg_elts {
};
/*
* Likewise for template elements.
*/
struct template_elts {
};
/*
* This structure is for snaplevel lists. They are convenient because libscf
* only allows traversing snaplevels in one direction.
*/
struct snaplevel {
};
const char * const scf_pg_general = SCF_PG_GENERAL;
const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
const char * const scf_property_external = "external";
const char * const snap_initial = "initial";
const char * const snap_lastimport = "last-import";
const char * const snap_previous = "previous";
const char * const snap_running = "running";
static size_t max_scf_len;
static scf_scope_t *cur_scope;
static uu_list_pool_t *snaplevel_pool;
/* cur_levels is the snaplevels of cur_snap, from least specific to most. */
static uu_list_t *cur_levels;
static const char *emsg_entity_not_selected;
static const char *emsg_permission_denied;
static const char *emsg_create_xml;
static const char *emsg_cant_modify_snapshots;
static const char *emsg_read_only;
static const char *emsg_deleted;
static const char *emsg_invalid_pg_name;
static const char *emsg_invalid_prop_name;
static const char *emsg_no_such_pg;
static const char *emsg_fmri_invalid_pg_name;
static const char *emsg_fmri_invalid_pg_name_type;
static const char *emsg_pg_added;
static const char *emsg_pg_changed;
static const char *emsg_pg_deleted;
static const char *emsg_pg_mod_perm;
static const char *emsg_pg_add_perm;
static const char *emsg_pg_del_perm;
static const char *emsg_snap_perm;
static const char *emsg_dpt_dangling;
static const char *emsg_dpt_no_dep;
static int li_only;
static int no_refresh = 0;
/* import globals, to minimize allocations */
static size_t imp_str_sz;
static char *imp_tsname = NULL;
/* upgrade_dependents() globals */
static int ud_run_dpts_pg_set = 0;
static char *ud_oldtarg = NULL;
/* export globals */
static scf_instance_t *exp_inst;
static scf_propertygroup_t *exp_pg;
static scf_property_t *exp_prop;
static scf_value_t *exp_val;
static char *exp_str;
static size_t exp_str_sz;
static char *start_method_names[] = {
"start",
"inetd_start",
};
static void
safe_printf(const char *fmt, ...)
{
}
/*
* For unexpected libscf errors.
*/
#ifdef NDEBUG
static void
scfdie(void)
{
if (err == SCF_ERROR_CONNECTION_BROKEN)
scf_strerror(err));
}
#else
static void
scfdie_lineno(int lineno)
{
if (err == SCF_ERROR_CONNECTION_BROKEN)
}
#endif
static void
scfwarn(void)
{
scf_strerror(scf_error()));
}
/*
* Clear a field of a structure.
*/
static int
clear_int(void *a, void *b)
{
/* LINTED */
*(int *)((char *)a + (size_t)b) = 0;
return (UU_WALK_NEXT);
}
static int
{
switch (err) {
case SCF_ERROR_BACKEND_ACCESS:
return (EACCES);
return (EROFS);
return (ECONNABORTED);
return (EINVAL);
case SCF_ERROR_DELETED:
return (ECANCELED);
case SCF_ERROR_EXISTS:
return (EEXIST);
case SCF_ERROR_NO_MEMORY:
return (ENOMEM);
case SCF_ERROR_NO_RESOURCES:
return (ENOSPC);
case SCF_ERROR_NOT_FOUND:
return (ENOENT);
return (EPERM);
default:
#ifndef NDEBUG
#else
#endif
abort();
/* NOTREACHED */
}
}
static int
{
if (issvc)
else
}
static void
{
if (issvc)
else
}
/*
* Find a snaplevel in a snapshot. If get_svc is true, find the service
* snaplevel. Otherwise find the instance snaplevel.
*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ECANCELED - instance containing snap was deleted
* ENOENT - snap has no snaplevels
* - requested snaplevel not found
*/
static int
{
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_snapshot_get_base_snaplevel",
scf_error());
}
}
for (;;) {
if (ssz >= 0) {
if (!get_svc)
return (0);
} else {
switch (scf_error()) {
if (get_svc)
return (0);
break;
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_snaplevel_get_instance_name",
scf_error());
}
}
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_snaplevel_get_next_snaplevel",
scf_error());
}
}
}
}
/*
* If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has
* a running snapshot, and that snapshot has an instance snaplevel, set pg to
* the property group named name in it. If it doesn't have a running
* snapshot, set pg to the instance's current property group named name.
*
* If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
* its instances. If one has a running snapshot with a service snaplevel, set
* pg to the property group named name in it. If no such snaplevel could be
* found, set pg to the service's current property group named name.
*
* iter, inst, snap, and snpl are required scratch objects.
*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ECANCELED - ent was deleted
* ENOENT - no such property group
* EINVAL - name is an invalid property group name
* EBADF - found running snapshot is missing a snaplevel
*/
static int
{
int r;
if (issvc) {
/* Search for an instance with a running snapshot. */
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_iter_service_instances",
scf_error());
}
}
for (;;) {
if (r == 0) {
return (0);
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_get_pg",
scf_error());
}
}
if (r != 1) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_iter_next_instance",
scf_error());
}
}
snap) == 0)
break;
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
continue;
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
}
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
return (0);
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
}
switch (r) {
case 0:
break;
case ECONNABORTED:
case ECANCELED:
return (r);
case ENOENT:
return (EBADF);
default:
bad_error("get_snaplevel", r);
}
return (0);
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
/* NOTREACHED */
}
}
/*
* To be registered with atexit().
*/
static void
remove_tempfile(void)
{
int ret;
}
if (tempfilename[0] != '\0') {
do
if (ret == -1)
tempfilename[0] = '\0';
}
}
/*
* Launch private svc.configd(1M) for manipulating alternate repositories.
*/
static void
{
/*
* 1. Create a temporary file for the door.
*/
if (fd < 0)
"repository server"));
/*
* 2. Launch a configd with that door, using the specified
* repository.
*/
NULL);
do
if (pid == -1)
stat);
} else if (WEXITSTATUS(stat) != 0) {
WEXITSTATUS(stat));
}
/*
* See if it was successful by checking if the door is a door.
*/
if (fd < 0)
}
void
lscf_cleanup(void)
{
/*
* In the case where we've launched a private svc.configd(1M)
* instance, we must terminate our child and remove the temporary
* rendezvous point.
*/
if (est->sc_repo_pid > 0) {
est->sc_repo_pid = 0;
}
}
void
unselect_cursnap(void)
{
void *cookie;
}
}
void
lscf_prep_hndl(void)
{
return;
scfdie();
int ret;
if (repo_value == NULL)
scfdie();
scfdie();
}
if (scf_handle_bind(g_hndl) != 0)
scf_strerror(scf_error()));
scfdie();
scfdie();
}
static void
repository_teardown(void)
{
lscf_cleanup();
}
}
void
lscf_set_repository(const char *repfile)
{
}
void
{
0 ||
scfdie();
if (max_scf_name_len > max_scf_len)
if (max_scf_pg_type_len > max_scf_len)
if (max_scf_value_len > max_scf_len)
if (atexit(remove_tempfile) != 0)
gettext("Invalid property group name \"%s\".\n");
"with invalid name \"%s\".\n");
"group with invalid name \"%s\" or type \"%s\".\n");
"(property group \"%s\" added).\n");
"(property group \"%s\" changed).\n");
"(property group \"%s\" or an ancestor was deleted).\n");
"in %s (permission denied).\n");
"in %s (permission denied).\n");
"in %s (permission denied).\n");
"(permission denied).\n");
"new dependent \"%s\" because it already exists). Warning: The "
"current dependent's target (%s) does not exist.\n");
"dependent \"%s\" because it already exists). Warning: The "
"current dependent's target (%s) does not have a dependency named "
"\"%s\" as expected.\n");
NULL, 0);
}
static const char *
{
scfdie();
return (scf_type_to_string(ty));
}
static scf_type_t
string_to_type(const char *type)
{
char *buf;
return (SCF_TYPE_INVALID);
return (scf_string_to_type(buf));
}
static scf_value_t *
{
scf_value_t *v;
v = scf_value_create(g_hndl);
if (v == NULL)
scfdie();
if (require_quotes &&
"with spaces must be quoted with '\"'.\n"));
return (NULL);
}
if (dup[0] == '\"') {
/*
* Strip out the first and the last quote.
*/
}
v = NULL;
}
return (v);
}
/*
* Print str to strm, quoting double-quotes and backslashes with backslashes.
*/
static int
{
const char *cp;
}
}
/*
* These wrappers around lowlevel functions provide consistent error checking
* and warnings.
*/
static int
{
return (0);
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (g_verbose) {
char *fmri;
if (len < 0)
scfdie();
scfdie();
}
return (-1);
}
static int
{
scfdie();
return (0);
if (g_verbose) {
char *fmri;
const char *tystr;
if (len < 0)
scfdie();
scfdie();
tystr = "?";
}
return (-1);
}
static int
{
return (0);
scfdie();
if (g_verbose) {
if (len < 0)
scfdie();
scfdie();
if (err == SCF_ERROR_NOT_FOUND)
"one.\n");
else
"expected one.\n");
}
return (-1);
}
static boolean_t
{
if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
scfdie();
return (0);
} else {
return (1);
}
}
/*
* Decode FMRI into a service or instance, and put the result in *ep. If
* memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is
* invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify
* an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be
* found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point
* *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
* whether *ep is a service.
*/
static scf_error_t
{
char *fmri_copy;
return (SCF_ERROR_NO_MEMORY);
SCF_SUCCESS) {
return (SCF_ERROR_INVALID_ARGUMENT);
}
return (SCF_ERROR_CONSTRAINT_VIOLATED);
svc = scf_service_create(h);
return (SCF_ERROR_NO_MEMORY);
SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
return (SCF_ERROR_NOT_FOUND);
}
*isservice = 1;
} else {
inst = scf_instance_create(h);
return (SCF_ERROR_NO_MEMORY);
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
return (SCF_ERROR_NOT_FOUND);
}
*isservice = 0;
}
return (SCF_ERROR_NONE);
}
/*
* Create the entity named by fmri. Place a pointer to its libscf handle in
* *ep, and set or clear *isservicep if it is a service or an instance.
* Returns
* SCF_ERROR_NONE - success
* SCF_ERROR_NO_MEMORY - scf_*_create() failed
* SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
* SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
* SCF_ERROR_NOT_FOUND - no such scope
* SCF_ERROR_PERMISSION_DENIED
* SCF_ERROR_BACKEND_READONLY
* SCF_ERROR_BACKEND_ACCESS
*/
static scf_error_t
{
char *fmri_copy;
0) {
return (SCF_ERROR_INVALID_ARGUMENT);
}
return (SCF_ERROR_CONSTRAINT_VIOLATED);
}
goto out;
}
switch (scf_error()) {
scfdie();
/* NOTREACHED */
case SCF_ERROR_NOT_FOUND:
goto out;
case SCF_ERROR_NOT_BOUND:
default:
}
}
switch (scf_error()) {
scfdie();
/* NOTREACHED */
case SCF_ERROR_DELETED:
goto get_scope;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
switch (scf_error()) {
scfdie();
/* NOTREACHED */
case SCF_ERROR_DELETED:
goto get_scope;
case SCF_ERROR_BACKEND_ACCESS:
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
}
*isservicep = 1;
goto out;
}
switch (scf_error()) {
scfdie();
/* NOTREACHED */
case SCF_ERROR_DELETED:
goto get_svc;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
switch (scf_error()) {
scfdie();
/* NOTREACHED */
case SCF_ERROR_DELETED:
goto get_svc;
case SCF_ERROR_BACKEND_ACCESS:
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_add_instance",
scf_error());
}
}
}
*isservicep = 0;
out:
return (scfe);
}
/*
* Refresh entity. If isservice is zero, take entity to be an scf_instance_t *.
* Otherwise take entity to be an scf_service_t * and refresh all of its child
* instances. fmri is used for messages. inst, iter, and name_buf are used
* for scratch space. Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ECANCELED - entity was deleted
* EACCES - backend denied access
* EPERM - permission denied
* -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
*/
static int
{
int r;
if (!isservice) {
if (_smf_refresh_instance_i(entity) == 0) {
if (g_verbose)
return (0);
}
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
return (EACCES);
return (EPERM);
default:
return (-1);
}
}
switch (scf_error()) {
return (ECONNABORTED);
case SCF_ERROR_DELETED:
return (ECANCELED);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
for (;;) {
if (r == 0)
break;
if (r != 1) {
switch (scf_error()) {
return (ECONNABORTED);
case SCF_ERROR_DELETED:
return (ECANCELED);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_next_instance",
scf_error());
}
}
if (_smf_refresh_instance_i(inst) == 0) {
if (g_verbose) {
max_scf_name_len + 1) < 0)
}
} else {
if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
g_verbose) {
max_scf_name_len + 1) < 0)
"Refresh of %s:%s failed: %s.\n"), fmri,
}
}
}
return (0);
}
static int
{
return (UU_WALK_ERROR);
}
static int
{
}
/*
* Import. These functions import a bundle into the repository.
*/
/*
* Add a transaction entry to lcbdata->sc_trans for this property_t. Uses
* sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success,
* returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
* lcbdata->sc_err to
* ENOMEM - out of memory
* ECONNABORTED - repository connection broken
* ECANCELED - sc_trans's property group was deleted
* EINVAL - p's name is invalid (error printed)
* - p has an invalid value (error printed)
*/
static int
lscf_property_import(void *v, void *pvt)
{
property_t *p = v;
return (UU_WALK_NEXT);
switch (scf_error()) {
case SCF_ERROR_NO_MEMORY:
return (stash_scferror(lcbdata));
default:
}
}
tp = p->sc_value_type;
p->sc_property_name, tp) != 0) {
switch (scf_error()) {
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
break;
case SCF_ERROR_DELETED:
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
p->sc_property_name, tp) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (stash_scferror(lcbdata));
p->sc_property_name);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
"scf_transaction_property_change_type",
scf_error());
}
}
}
switch (scf_error()) {
case SCF_ERROR_NO_MEMORY:
return (stash_scferror(lcbdata));
default:
}
}
switch (tp) {
case SCF_TYPE_BOOLEAN:
break;
case SCF_TYPE_COUNT:
break;
case SCF_TYPE_INTEGER:
break;
default:
if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
bad_error("scf_value_set_from_string",
scf_error());
return (stash_scferror(lcbdata));
}
break;
}
}
return (UU_WALK_NEXT);
}
/*
* Import a pgroup_t into the repository. Uses sc_handle, sc_parent,
* sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
* sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
* On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
* lcbdata->sc_err to
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - svc.configd is out of resources
* ECANCELED - sc_parent was deleted
* EPERM - could not create property group (permission denied) (error printed)
* - could not modify property group (permission denied) (error printed)
* - could not delete property group (permission denied) (error printed)
* EROFS - could not create property group (repository is read-only)
* - could not delete property group (repository is read-only)
* EACCES - could not create property group (backend access denied)
* - could not delete property group (backend access denied)
* EEXIST - could not create property group (already exists)
* EINVAL - invalid property group name (error printed)
* - invalid property name (error printed)
* - invalid value (error printed)
* EBUSY - new property group deleted (error printed)
* - new property group changed (error printed)
* - property group added (error printed)
* - property group deleted (error printed)
*/
static int
entity_pgroup_import(void *v, void *pvt)
{
pgroup_t *p = v;
int r;
"(new property group \"%s\" changed).\n");
/* Never import deleted property groups. */
if (p->sc_pgroup_delete)
return (UU_WALK_NEXT);
lcbdata->sc_general = p;
return (UU_WALK_NEXT);
}
if (issvc)
else
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NO_RESOURCES:
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
break;
return (stash_scferror(lcbdata));
p->sc_pgroup_name, p->sc_pgroup_type);
return (stash_scferror(lcbdata));
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (stash_scferror(lcbdata));
p->sc_pgroup_name);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_FOUND:
p->sc_pgroup_name);
return (UU_WALK_ERROR);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
goto props;
if (scf_pg_delete(imp_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
p->sc_pgroup_name);
return (UU_WALK_ERROR);
return (stash_scferror(lcbdata));
case SCF_ERROR_BACKEND_ACCESS:
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_SET:
default:
}
}
goto add_pg;
}
/*
* Add properties to property group, if any.
*/
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
return (stash_scferror(lcbdata));
case SCF_ERROR_DELETED:
p->sc_pgroup_name);
return (UU_WALK_ERROR);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_IN_USE:
default:
}
}
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
p->sc_pgroup_name);
}
return (UU_WALK_ERROR);
}
r = scf_transaction_commit(imp_tx);
switch (r) {
case 1:
r = UU_WALK_NEXT;
break;
case 0:
r = UU_WALK_ERROR;
break;
case -1:
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
break;
case SCF_ERROR_DELETED:
p->sc_pgroup_name);
r = UU_WALK_ERROR;
break;
r = stash_scferror(lcbdata);
break;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
default:
bad_error("scf_transaction_commit", r);
}
return (r);
}
/*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - svc.configd is out of resources
* ECANCELED - inst was deleted
* EPERM - could not create property group (permission denied) (error printed)
* - could not modify property group (permission denied) (error printed)
* EROFS - could not create property group (repository is read-only)
* EACCES - could not create property group (backend access denied)
* EEXIST - could not create property group (already exists)
* EINVAL - invalid property group name (error printed)
* - invalid property name (error printed)
* - invalid value (error printed)
* EBUSY - new property group changed (error printed)
*/
static int
{
cbdata.sc_service = 0;
cbdata.sc_general = 0;
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
}
!= UU_WALK_NEXT)
}
return (0);
}
/*
* Report the reasons why we can't upgrade pg2 to pg1.
*/
static void
int new)
{
return;
new);
continue;
}
if (new)
"group \"%s\" is missing property \"%s\").\n"),
else
"\"%s/%s\" is missing).\n"), fmri,
}
/*
* Since pg1 should be from the manifest, any properties in pg2 which
* aren't in pg1 shouldn't be reported as conflicts.
*/
}
/*
* Add transaction entries to tx which will upgrade cur's pg according to old
* & new.
*
* Returns
* 0 - success
* EINVAL - new has a property with an invalid name or value (message emitted)
* ENOMEM - out of memory
*/
static int
{
int r;
int is_general;
int is_protected;
p != NULL;
/* p is a property in the old property group. */
/* Protect live properties. */
is_protected = 0;
if (is_general) {
0 ||
SCF_PROPERTY_RESTARTER) == 0)
is_protected = 1;
}
/* Look for the same property in the new properties. */
/*
* If the new property is the same as the old, don't do
* anything (leave any user customizations).
*/
continue;
if (new_p->sc_property_override)
goto upgrade;
}
/*
* p has been deleted from the repository. If we were
* going to delete it anyway, do nothing. Otherwise
* report a conflict.
*/
continue;
if (is_protected)
continue;
"(property \"%s/%s\" is missing).\n"), fmri,
continue;
}
/*
* Conflict. Don't warn if the property is already the
* way we want it, though.
*/
if (is_protected)
continue;
old->sc_pgroup_name, 0);
else
old->sc_pgroup_name, 0);
continue;
}
if (is_protected) {
if (speak)
"\"%s/%s\" (live property).\n"), fmri,
continue;
}
/* p hasn't been customized in the repository. Upgrade it. */
/* p was deleted. Delete from cur if unchanged. */
if (speak)
"%s: Deleting property \"%s/%s\".\n"),
p->sc_property_name);
e = scf_entry_create(g_hndl);
if (e == NULL)
return (ENOMEM);
if (scf_transaction_property_delete(tx, e,
p->sc_property_name) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ECANCELED);
return (ECONNABORTED);
case SCF_ERROR_NOT_FOUND:
/*
* This can happen if cur is from the
* running snapshot (and it differs
* from the live properties).
*/
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
"scf_transaction_property_delete",
scf_error());
}
}
} else {
if (speak)
"%s: Upgrading property \"%s/%s\".\n"),
p->sc_property_name);
if (r != UU_WALK_NEXT) {
if (r != UU_WALK_ERROR)
bad_error("lscf_property_import", r);
return (EINVAL);
}
}
}
/* Go over the properties which were added. */
continue;
/* This is a new property. */
if (r != UU_WALK_NEXT) {
if (r != UU_WALK_ERROR)
bad_error("lscf_property_import", r);
return (EINVAL);
}
continue;
}
/*
* Report a conflict if the new property differs from the
* never in the last-import snapshot.
*/
0 &&
continue;
}
return (0);
}
/*
* Upgrade pg according to old & new.
*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - svc.configd is out of resources
* ECANCELED - pg was deleted
* EPERM - couldn't modify pg (permission denied)
* EROFS - couldn't modify pg (backend read-only)
* EACCES - couldn't modify pg (backend access denied)
* EINVAL - new has a property with invalid name or value (error printed)
* EBUSY - pg changed unexpectedly
*/
static int
{
int r;
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_BACKEND_ACCESS:
return (scferror2errno(scf_error()));
case SCF_ERROR_IN_USE:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
switch (r) {
case 0:
break;
case EINVAL:
case ENOMEM:
return (r);
default:
bad_error("add_upgrade_entries", r);
}
r = scf_transaction_commit(imp_tx);
switch (r) {
case 1:
break;
case 0:
return (EBUSY);
case -1:
switch (scf_error()) {
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
default:
bad_error("scf_transaction_commit", r);
}
return (0);
}
/*
* Compares two entity FMRIs. Returns
*
* 1 - equal
* 0 - not equal
* -1 - f1 is invalid or not an entity
* -2 - f2 is invalid or not an entity
*/
static int
{
int r;
return (-1);
return (-1);
return (-1);
return (-2);
return (-2);
return (-2);
if (r != 0)
return (0);
return (1);
return (0);
}
/*
* Import a dependent by creating a dependency property group in the dependent
* entity. If lcbdata->sc_trans is set, assume it's been started on the
* dependents pg, and add an entry to create a new property for this
* dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
*
* On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets
* lcbdata->sc_err to
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - configd is out of resources
* EINVAL - target is invalid (error printed)
* - target is not an entity (error printed)
* - dependent has invalid name (error printed)
* - invalid property name (error printed)
* - invalid value (error printed)
* - scope of target does not exist (error printed)
* EPERM - couldn't create target (permission denied) (error printed)
* - couldn't create dependency pg (permission denied) (error printed)
* - couldn't modify dependency pg (permission denied) (error printed)
* EROFS - couldn't create target (repository read-only)
* - couldn't create dependency pg (repository read-only)
* EACCES - couldn't create target (backend access denied)
* - couldn't create dependency pg (backend access denied)
* ECANCELED - sc_trans's pg was deleted
* EALREADY - property for dependent already exists in sc_trans's pg
* EEXIST - dependency pg already exists in target (error printed)
* EBUSY - target deleted (error printed)
* - property group changed during import (error printed)
*/
static int
{
int isservice;
int ret;
/*
* Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if
* it's invalid, we fail before modifying the repository.
*/
switch (scfe) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
"specifies neither a service nor an instance.\n"),
case SCF_ERROR_NOT_FOUND:
switch (scfe) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NOT_FOUND:
"\"%s\" dependent does not exist.\n"),
return (UU_WALK_ERROR);
"Could not create %s (permission denied).\n"),
default:
}
break;
default:
}
if (e == NULL) {
if (scf_error() != SCF_ERROR_NO_MEMORY)
return (stash_scferror(lcbdata));
}
switch (scf_error()) {
/* FALLTHROUGH */
case SCF_ERROR_DELETED:
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
return (UU_WALK_ERROR);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_property_new",
scf_error());
}
}
if (scf_error() != SCF_ERROR_NO_MEMORY)
return (stash_scferror(lcbdata));
}
pgrp->sc_pgroup_fmri) != 0)
/* invalid should have been caught above */
if (scf_entry_add_value(e, val) != 0)
}
/* Add the property group to the target entity. */
dependent_cbdata.sc_flags = 0;
if (ret == UU_WALK_NEXT)
return (ret);
if (ret != UU_WALK_ERROR)
switch (dependent_cbdata.sc_err) {
case ECANCELED:
break;
case EEXIST:
/* FALLTHROUGH */
default:
}
return (UU_WALK_ERROR);
}
const scf_snaplevel_t *, scf_transaction_t *);
const pgroup_t *);
/*
* Upgrade uncustomized dependents of ent to those specified in ient. Read
* the current dependent targets from running (the snaplevel of a running
* snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
* scf_instance_t * according to ient, otherwise). Draw the ancestral
* dependent targets and dependency properties from li_dpts_pg (the
* "dependents" property group in snpl) and snpl (the snaplevel which
* corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then
* snpl doesn't have a "dependents" property group, and any dependents in ient
* are new.
*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - configd is out of resources
* ECANCELED - ent was deleted
* ENODEV - the entity containing li_dpts_pg was deleted
* EPERM - could not modify dependents pg (permission denied) (error printed)
* - couldn't upgrade dependent (permission denied) (error printed)
* - couldn't create dependent (permission denied) (error printed)
* EROFS - could not modify dependents pg (repository read-only)
* - couldn't upgrade dependent (repository read-only)
* - couldn't create dependent (repository read-only)
* EACCES - could not modify dependents pg (backend access denied)
* - could not upgrade dependent (backend access denied)
* - could not create dependent (backend access denied)
* EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
* - dependent target deleted (error printed)
* - dependent pg changed (error printed)
* EINVAL - new dependent is invalid (error printed)
* EBADF - snpl is corrupt (error printed)
* - snpl has corrupt pg (error printed)
* - dependency pg in target is corrupt (error printed)
* - target has corrupt snapshot (error printed)
* EEXIST - dependency pg already existed in target service (error printed)
*/
static int
{
int r, unseen, tx_started = 0;
int have_cur_depts;
const char * const dependents = "dependents";
/* Nothing to do. */
return (0);
/* Fetch the current version of the "dependents" property group. */
have_cur_depts = 1;
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
have_cur_depts = 0;
}
/* Fetch the running version of the "dependents" property group. */
ud_run_dpts_pg_set = 0;
else
if (r == 0) {
ud_run_dpts_pg_set = 1;
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
"entity_get_pg", scf_error());
}
}
/*
* Clear the seen fields of the dependents, so we can tell which ones
* are new.
*/
if (li_dpts_pg != NULL) {
/*
* Each property in li_dpts_pg represents a dependent tag in
* the old manifest. For each, call upgrade_dependent(),
* which will change ud_cur_depts_pg or dependencies in other
* services as appropriate. Note (a) that changes to
* ud_cur_depts_pg are accumulated in ud_tx so they can all be
* made en masse, and (b) it's ok if the entity doesn't have
* a current version of the "dependents" property group,
* because we'll just consider all dependents as customized
* (by being deleted).
*/
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
return (ECONNABORTED);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
}
if (have_cur_depts &&
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
return (EBUSY);
return (scferror2errno(scf_error()));
case SCF_ERROR_IN_USE:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
for (;;) {
if (r == 0)
break;
if (r == 1) {
switch (r) {
case 0:
continue;
case ECONNABORTED:
case ENOMEM:
case ENOSPC:
case EBADF:
case EBUSY:
case EINVAL:
case EPERM:
case EROFS:
case EACCES:
case EEXIST:
break;
case ECANCELED:
r = ENODEV;
break;
default:
bad_error("upgrade_dependent", r);
}
if (tx_started)
return (r);
}
if (r != -1)
bad_error("scf_iter_next_property", r);
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = ENODEV;
break;
r = ECONNABORTED;
break;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_iter_next_property",
scf_error());
}
if (tx_started)
return (r);
}
}
/* import unseen dependents */
unseen = 0;
new_dpt_pgroup != NULL;
new_dpt_pgroup)) {
if (!new_dpt_pgroup->sc_pgroup_seen) {
unseen = 1;
break;
}
}
/* If there are none, exit early. */
if (unseen == 0)
goto commit;
/* Set up for lscf_dependent_import() */
if (!have_cur_depts) {
/*
* We have new dependents to import, so we need a "dependents"
* property group.
*/
if (issvc)
else
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NO_RESOURCES:
return (scferror2errno(scf_error()));
case SCF_ERROR_EXISTS:
return (EBUSY);
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
}
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
return (EBUSY);
return (scferror2errno(scf_error()));
case SCF_ERROR_IN_USE:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
tx_started = 1;
new_dpt_pgroup != NULL;
new_dpt_pgroup)) {
if (new_dpt_pgroup->sc_pgroup_seen)
continue;
if (ud_run_dpts_pg_set) {
/*
* If the dependent is already there, then we have
* a conflict.
*/
switch (r) {
case 0:
continue;
case ECONNABORTED:
case ENOMEM:
case EBUSY:
case EBADF:
case EINVAL:
return (r);
default:
bad_error("handle_dependent_conflict",
r);
}
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
return (EINVAL);
case SCF_ERROR_DELETED:
return (EBUSY);
return (ECONNABORTED);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_get_property",
scf_error());
}
}
}
if (r != UU_WALK_NEXT) {
if (r != UU_WALK_ERROR)
bad_error("lscf_dependent_import", r);
/* Collisions were handled preemptively. */
bad_error("lscf_dependent_import",
}
}
}
if (!tx_started)
return (0);
r = scf_transaction_commit(ud_tx);
switch (r) {
case 1:
return (0);
case 0:
return (EBUSY);
case -1:
break;
default:
bad_error("scf_transaction_commit", r);
}
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NO_RESOURCES:
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
return (EBUSY);
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
/* NOTREACHED */
}
}
/*
* prop is taken to be a property in the "dependents" property group of snpl,
* which is taken to be the snaplevel of a last-import snapshot corresponding
* to ient. If prop is a valid dependents property, upgrade the dependent it
* represents according to the repository & ient. If ud_run_dpts_pg_set is
* true, then ud_run_dpts_pg is taken to be the "dependents" property group
* of the entity ient represents (possibly in the running snapshot). If it
* needs to be changed, an entry will be added to tx, if not NULL.
*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - configd was out of resources
* ECANCELED - snpl's entity was deleted
* EINVAL - dependent target is invalid (error printed)
* - dependent is invalid (error printed)
* EBADF - snpl is corrupt (error printed)
* - snpl has corrupt pg (error printed)
* - dependency pg in target is corrupt (error printed)
* - running snapshot in dependent is missing snaplevel (error printed)
* EPERM - couldn't delete dependency pg (permission denied) (error printed)
* - couldn't create dependent (permission denied) (error printed)
* - couldn't modify dependent pg (permission denied) (error printed)
* EROFS - couldn't delete dependency pg (repository read-only)
* - couldn't create dependent (repository read-only)
* EACCES - couldn't delete dependency pg (backend access denied)
* - couldn't create dependent (backend access denied)
* EBUSY - ud_run_dpts_pg was deleted (error printed)
* - tx's pg was deleted (error printed)
* - dependent pg was changed or deleted (error printed)
* EEXIST - dependency pg already exists in new target (error printed)
*/
static int
{
int tissvc;
void *target_ent;
int r;
"(dependent \"%s\" has invalid dependents property).\n");
"(dependent \"%s\" is missing).\n");
"(dependent \"%s\" has new dependency property group).\n");
"(dependent \"%s\" has new target).\n");
const char * const li_corrupt =
gettext("%s: \"last-import\" snapshot is corrupt.\n");
const char * const upgrading =
gettext("%s: Upgrading dependent \"%s\".\n");
"corrupt (missing snaplevel).\n");
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
return (EBADF);
}
/*
* prop represents a dependent in the old manifest. It is named after
* the dependent.
*/
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
/* See if it's in the new manifest. */
/* If it's not, delete it... if it hasn't been customized. */
if (new_dpt_pgroup == NULL) {
if (!ud_run_dpts_pg_set)
return (0);
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (EBADF);
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
max_scf_value_len + 1) < 0)
0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (0);
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
"dependents");
return (EBUSY);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (0);
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
return (0);
}
max_scf_value_len + 1) < 0)
switch (r) {
case 1:
break;
case 0:
case -1: /* warn? */
return (0);
case -2:
return (EBADF);
default:
bad_error("fmri_equal", r);
}
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (EBADF);
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
switch (r) {
case 0:
break;
case ECANCELED:
case ECONNABORTED:
case ENOMEM:
case EBADF:
return (r);
default:
bad_error("load_pg", r);
}
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
return (ENOMEM);
case SCF_ERROR_NOT_FOUND:
goto delprop;
case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */
case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
default:
}
switch (r) {
case 0:
break;
case ECONNABORTED:
return (r);
case ECANCELED:
case ENOENT:
goto delprop;
case EBADF:
return (r);
case EINVAL:
default:
bad_error("entity_get_running_pg", r);
}
/* load it */
switch (r) {
case 0:
break;
case ECANCELED:
goto delprop;
case ECONNABORTED:
case ENOMEM:
case EBADF:
return (r);
default:
bad_error("load_pg", r);
}
/* compare property groups */
return (0);
}
if (g_verbose)
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
goto delprop;
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
if (scf_pg_delete(ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_BACKEND_ACCESS:
return (scferror2errno(scf_error()));
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
default:
}
}
/*
* This service was changed, so it must be refreshed. But
* since it's not mentioned in the new manifest, we have to
* record its FMRI here for use later. We record the name
* & the entity (via sc_parent) in case we need to print error
* messages during the refresh.
*/
dpt = internal_pgroup_new();
return (ENOMEM);
return (ENOMEM);
uu_strerror(uu_error()));
return (0);
return (ENOMEM);
switch (scf_error()) {
case SCF_ERROR_DELETED:
"dependents");
return (EBUSY);
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_property_delete",
scf_error());
}
}
return (0);
}
/*
* Decide whether the dependent has changed in the manifest.
*/
/* Compare the target. */
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (EBADF);
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
0)
switch (r) {
case 0:
break;
case 1:
/* Compare the dependency pgs. */
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (EBADF);
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
switch (r) {
case 0:
break;
case ECANCELED:
case ECONNABORTED:
case ENOMEM:
case EBADF:
return (r);
default:
bad_error("load_pg", r);
}
/* no change, leave customizations */
return (0);
}
break;
case -1:
return (EBADF);
case -2:
return (EINVAL);
default:
bad_error("fmri_equal", r);
}
/*
* The dependent has changed in the manifest. Upgrade the current
* properties if they haven't been customized.
*/
/*
* If new_dpt_pgroup->sc_override, then act as though the property
* group hasn't been customized.
*/
goto nocust;
if (!ud_run_dpts_pg_set) {
r = 0;
goto out;
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
r = 0;
goto out;
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
r = EBUSY;
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
r = 0;
goto out;
case SCF_ERROR_DELETED:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
r = 0;
goto out;
}
0)
if (r == -1) {
r = 0;
goto out;
} else if (r == -2) {
r = EBADF;
goto out;
} else if (r == 0) {
/*
* Target has been changed. Only abort now if it's been
* changed to something other than what's in the manifest.
*/
if (r == -1) {
r = 0;
goto out;
} else if (r == 0) {
r = 0;
goto out;
} else if (r != 1) {
/* invalid sc_pgroup_fmri caught above */
bad_error("fmri_equal", r);
}
/*
* Fetch the current dependency pg. If it's what the manifest
* says, then no problem.
*/
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NOT_FOUND:
r = 0;
goto out;
case SCF_ERROR_NO_MEMORY:
r = ENOMEM;
goto out;
default:
}
switch (r) {
case 0:
break;
case ECONNABORTED:
goto out;
case ECANCELED:
case ENOENT:
r = 0;
goto out;
case EBADF:
goto out;
case EINVAL:
default:
bad_error("entity_get_running_pg", r);
}
switch (r) {
case 0:
break;
case ECANCELED:
r = 0;
goto out;
case ECONNABORTED:
case ENOMEM:
case EBADF:
goto out;
default:
bad_error("load_pg", r);
}
r = 0;
goto out;
} else if (r != 1) {
bad_error("fmri_equal", r);
}
/*
* Target has not been customized. Check the dependency property
* group.
*/
if (old_dpt_pgroup == NULL) {
ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (EBADF);
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
switch (r) {
case 0:
break;
case ECANCELED:
case ECONNABORTED:
case ENOMEM:
case EBADF:
return (r);
default:
bad_error("load_pg", r);
}
}
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NOT_FOUND:
r = 0;
goto out;
case SCF_ERROR_NO_MEMORY:
r = ENOMEM;
goto out;
default:
}
switch (r) {
case 0:
break;
case ECONNABORTED:
goto out;
case ECANCELED:
case ENOENT:
r = 0;
goto out;
case EBADF:
goto out;
case EINVAL:
default:
bad_error("entity_get_running_pg", r);
}
switch (r) {
case 0:
break;
case ECANCELED:
goto out;
case ECONNABORTED:
case ENOMEM:
case EBADF:
goto out;
default:
bad_error("load_pg", r);
}
r = 0;
goto out;
}
/* Uncustomized. Upgrade. */
switch (r) {
case 1:
/* Already upgraded. */
r = 0;
goto out;
}
/* upgrade current_pg */
switch (scf_error()) {
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
r = 0;
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
if (tissvc)
SCF_GROUP_DEPENDENCY, 0, ud_pg);
else
SCF_GROUP_DEPENDENCY, 0, ud_pg);
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_ACCESS:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
ud_name);
r = 0;
goto out;
ud_name);
r = EPERM;
goto out;
case SCF_ERROR_EXISTS:
r = EBUSY;
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
}
switch (r) {
case 0:
break;
case ECANCELED:
goto out;
case ECONNABORTED:
case ENOMEM:
case EBADF:
goto out;
default:
bad_error("load_pg", r);
}
if (g_verbose)
switch (r) {
case 0:
break;
case ECANCELED:
r = EBUSY;
goto out;
case EPERM:
goto out;
case EBUSY:
goto out;
case ECONNABORTED:
case ENOMEM:
case ENOSPC:
case EROFS:
case EACCES:
case EINVAL:
goto out;
default:
bad_error("upgrade_pg", r);
}
break;
case 0: {
/* delete old pg */
if (g_verbose)
switch (scf_error()) {
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
r = 0;
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
} else if (scf_pg_delete(ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_BACKEND_ACCESS:
r = scferror2errno(scf_error());
goto out;
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_NOT_SET:
default:
}
}
/* import new one */
if (r != UU_WALK_NEXT) {
if (r != UU_WALK_ERROR)
bad_error("lscf_dependent_import", r);
goto out;
}
break;
if (scf_error() == SCF_ERROR_NO_MEMORY)
return (ENOMEM);
}
SCF_TYPE_FMRI) != 0) {
switch (scf_error()) {
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
"dependents");
r = EBUSY;
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_property_"
"change_type", scf_error());
}
SCF_TYPE_FMRI) != 0) {
switch (scf_error()) {
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
"dependents");
r = EBUSY;
goto out;
case SCF_ERROR_EXISTS:
"dependents");
r = EBUSY;
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_property_"
"new", scf_error());
}
}
}
new_dpt_pgroup->sc_pgroup_fmri) != 0)
/* invalid sc_pgroup_fmri caught above */
bad_error("scf_value_set_from_string",
scf_error());
break;
}
case -2:
r = EBADF;
goto out;
case -1:
default:
/* invalid sc_pgroup_fmri caught above */
bad_error("fmri_equal", r);
}
r = 0;
out:
if (old_dpt_pgroup != NULL)
return (r);
}
/*
* new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
* would import it, except it seems to exist in the service anyway. Compare
* the existent dependent with the one we would import, and report any
* differences (if there are none, be silent). prop is the property which
* represents the existent dependent (in the dependents property group) in the
* entity corresponding to ient.
*
* Returns
* 0 - success (Sort of. At least, we can continue importing.)
* ECONNABORTED - repository connection broken
* EBUSY - ancestor of prop was deleted (error printed)
* ENOMEM - out of memory
* EBADF - corrupt property group (error printed)
* EINVAL - new_dpt_pgroup has invalid target (error printed)
*/
static int
{
int r;
void *tptr;
int tissvc;
switch (scf_error()) {
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
return (EBUSY);
case SCF_ERROR_NOT_FOUND:
"dependent \"%s\" because it already exists.) "
"Warning: The \"%s/%2$s\" property has more or "
return (0);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
"\"%s\" because it already exists). Warning: The "
"\"%s/%s\" property has unexpected type \"%s\")).\n"),
return (0);
}
0)
switch (r) {
case 0:
"\"%s\" (target \"%s\") because it already exists with "
return (0);
case 1:
break;
case -1:
"\"%s\" because it already exists). Warning: The current "
return (0);
case -2:
return (EINVAL);
default:
bad_error("fmri_equal", r);
}
/* compare dependency pgs in target */
switch (scfe) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
return (ENOMEM);
case SCF_ERROR_NOT_FOUND:
return (0);
default:
}
switch (r) {
case 0:
break;
case ECONNABORTED:
return (r);
case ECANCELED:
return (0);
case EBADF:
if (tissvc)
"snapshot which is missing a snaplevel.\n"),
ud_ctarg, "running");
else
/* FALLTHROUGH */
case ENOENT:
return (0);
case EINVAL:
default:
bad_error("entity_get_running_pg", r);
}
return (ENOMEM);
switch (r) {
case 0:
break;
case ECONNABORTED:
case EBADF:
case ENOMEM:
return (r);
case ECANCELED:
return (0);
default:
bad_error("load_pg", r);
}
/* report differences */
return (0);
}
/*
* lipg is a property group in the last-import snapshot of ent, which is an
* scf_service_t or an scf_instance_t (according to ient). If lipg is not in
* ient's pgroups, delete it from ent if it hasn't been customized. If it is
* in ents's property groups, compare and upgrade ent appropriately.
*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - configd is out of resources
* EINVAL - ient has invalid dependent (error printed)
* - ient has invalid pgroup_t (error printed)
* ECANCELED - ent has been deleted
* ENODEV - entity containing lipg has been deleted
* - entity containing running has been deleted
* EPERM - could not delete pg (permission denied) (error printed)
* - couldn't upgrade dependents (permission denied) (error printed)
* - couldn't import pg (permission denied) (error printed)
* - couldn't upgrade pg (permission denied) (error printed)
* EROFS - could not delete pg (repository read-only)
* - couldn't upgrade dependents (repository read-only)
* - couldn't import pg (repository read-only)
* - couldn't upgrade pg (repository read-only)
* EACCES - could not delete pg (backend access denied)
* - couldn't upgrade dependents (backend access denied)
* - couldn't import pg (backend access denied)
* - couldn't upgrade pg (backend access denied)
* EBUSY - property group was added (error printed)
* - property group was deleted (error printed)
* - property group changed (error printed)
* - "dependents" pg was added, changed, or deleted (error printed)
* - dependent target deleted (error printed)
* - dependent pg changed (error printed)
* EBADF - imp_snpl is corrupt (error printed)
* - ent has bad pg (error printed)
* EEXIST - dependent collision in target service (error printed)
*/
static int
const scf_snaplevel_t *running)
{
int r;
const char * const cf_pg_missing =
gettext("Conflict upgrading %s (property group %s is missing)\n");
const char * const deleting =
gettext("%s: Deleting property group \"%s\".\n");
/* Skip dependent property groups. */
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
return (0);
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
return (ECONNABORTED);
case SCF_ERROR_DELETED:
return (ENODEV);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
/* lookup pg in new properties */
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
/* Special handling for dependents */
/* property group was deleted from manifest */
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (0);
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
if (g_verbose)
if (scf_pg_delete(imp_pg2) == 0)
return (0);
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (0);
case SCF_ERROR_BACKEND_ACCESS:
return (scferror2errno(scf_error()));
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
default:
}
}
switch (r) {
case 0:
break;
case ECANCELED:
return (ENODEV);
case ECONNABORTED:
case ENOMEM:
case EBADF:
return (r);
default:
bad_error("load_pg", r);
}
switch (r) {
case 0:
break;
case ECANCELED:
case ECONNABORTED:
case ENOMEM:
case EBADF:
return (r);
default:
bad_error("load_pg", r);
}
if (g_verbose)
if (scf_pg_delete(imp_pg2) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
} else {
}
return (0);
}
/*
* Only dependent pgs can have override set, and we skipped those
* above.
*/
/* compare */
switch (r) {
case 0:
break;
case ECANCELED:
return (ENODEV);
case ECONNABORTED:
case EBADF:
case ENOMEM:
return (r);
default:
bad_error("load_pg", r);
}
/* The manifest pg has not changed. Move on. */
r = 0;
goto out;
}
/* upgrade current properties according to lipg & mpg */
else
if (r != 0) {
switch (scf_error()) {
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
r = ENODEV;
else
r = ECANCELED;
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
r = 0;
goto out;
}
switch (r) {
case 0:
break;
case ECANCELED:
r = 0;
goto out;
case ECONNABORTED:
case ENOMEM:
goto out;
default:
bad_error("load_pg_attrs", r);
}
r = 0;
goto out;
}
switch (r) {
case 0:
break;
case ECANCELED:
r = 0;
goto out;
case ECONNABORTED:
case EBADF:
case ENOMEM:
goto out;
default:
bad_error("load_pg", r);
}
int do_delete = 1;
if (g_verbose)
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = ECANCELED;
goto out;
case SCF_ERROR_NOT_FOUND:
do_delete = 0;
break;
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_BACKEND_ACCESS:
r = scferror2errno(scf_error());
goto out;
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
switch (r) {
case UU_WALK_NEXT:
r = 0;
goto out;
case UU_WALK_ERROR:
r = EBUSY;
} else {
}
goto out;
default:
bad_error("entity_pgroup_import", r);
}
}
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
switch (r) {
case UU_WALK_NEXT:
r = 0;
goto out;
case UU_WALK_ERROR:
r = EBUSY;
} else {
}
goto out;
default:
bad_error("entity_pgroup_import", r);
}
}
switch (r) {
case 0:
break;
case ECANCELED:
r = EBUSY;
break;
case EPERM:
break;
case EBUSY:
break;
case ECONNABORTED:
case ENOMEM:
case ENOSPC:
case EROFS:
case EACCES:
case EINVAL:
break;
default:
bad_error("upgrade_pg", r);
}
out:
return (r);
}
/*
* Upgrade the properties of ent according to snpl & ient.
*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - configd is out of resources
* ECANCELED - ent was deleted
* ENODEV - entity containing snpl was deleted
* - entity containing running was deleted
* EBADF - imp_snpl is corrupt (error printed)
* - ent has corrupt pg (error printed)
* - dependent has corrupt pg (error printed)
* - dependent target has a corrupt snapshot (error printed)
* EBUSY - pg was added, changed, or deleted (error printed)
* - dependent target was deleted (error printed)
* - dependent pg changed (error printed)
* EINVAL - invalid property group name (error printed)
* - invalid property name (error printed)
* - invalid value (error printed)
* - ient has invalid pgroup or dependent (error printed)
* EPERM - could not create property group (permission denied) (error printed)
* - could not modify property group (permission denied) (error printed)
* - couldn't delete, upgrade, or import pg or dependent (error printed)
* EROFS - could not create property group (repository read-only)
* - couldn't delete, upgrade, or import pg or dependent
* EACCES - could not create property group (backend access denied)
* - couldn't delete, upgrade, or import pg or dependent
* EEXIST - dependent collision in target service (error printed)
*/
static int
{
int r;
/* clear sc_sceen for pgs */
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
for (;;) {
if (r == 0)
break;
if (r == 1) {
switch (r) {
case 0:
break;
case ECONNABORTED:
case ENOMEM:
case ENOSPC:
case ECANCELED:
case ENODEV:
case EPERM:
case EROFS:
case EACCES:
case EBADF:
case EBUSY:
case EINVAL:
case EEXIST:
return (r);
default:
bad_error("process_old_pg", r);
}
continue;
}
if (r != -1)
bad_error("scf_iter_next_pg", r);
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
return (ECONNABORTED);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
if (pg->sc_pgroup_seen)
continue;
/* pg is new */
ent);
switch (r) {
case 0:
break;
case ECONNABORTED:
case ENOMEM:
case ENOSPC:
case ECANCELED:
case ENODEV:
case EBADF:
case EBUSY:
case EINVAL:
case EPERM:
case EROFS:
case EACCES:
case EEXIST:
return (r);
default:
bad_error("upgrade_dependents", r);
}
continue;
}
imp_pg);
else
imp_pg);
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
return (ENODEV);
else
return (scferror2errno(scf_error()));
pg->sc_pgroup_name);
return (EINVAL);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
/* User doesn't have pg, so import it. */
switch (r) {
case UU_WALK_NEXT:
continue;
case UU_WALK_ERROR:
pg->sc_pgroup_name);
return (EBUSY);
}
default:
bad_error("entity_pgroup_import", r);
}
}
/* report differences between pg & current */
switch (r) {
case 0:
break;
case ECANCELED:
pg->sc_pgroup_name);
return (EBUSY);
case ECONNABORTED:
case EBADF:
case ENOMEM:
return (r);
default:
bad_error("load_pg", r);
}
}
return (0);
}
/*
* Create or update a snapshot of inst. Uses imp_snap.
*
* Returns
* 0 - success
* ECONNABORTED - repository connection broken
* EPERM - permission denied
* ENOSPC - configd is out of resources
* ECANCELED - inst was deleted
* -1 - unknown libscf error (message printed)
*/
static int
{
switch (scf_error()) {
case SCF_ERROR_NO_RESOURCES:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
default:
bad_error("_scf_snapshot_take_attach",
scf_error());
}
}
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
switch (scf_error()) {
case SCF_ERROR_EXISTS:
goto again;
case SCF_ERROR_NO_RESOURCES:
return (scferror2errno(scf_error()));
default:
scfwarn();
return (-1);
case SCF_ERROR_NOT_SET:
bad_error("_scf_snapshot_take_new",
scf_error());
}
}
}
return (0);
}
/*
* Import an instance. If it doesn't exist, create it. If it has
* a last-import snapshot, upgrade its properties. Finish by updating its
* last-import snapshot. If it doesn't have a last-import snapshot then it
* could have been created for a dependent tag in another manifest. Import the
* new properties. If there's a conflict, don't override, like now?
*
* On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets
* lcbdata->sc_err to
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - svc.configd is out of resources
* EEXIST - dependency collision in dependent service (error printed)
* EPERM - couldn't create temporary instance (permission denied)
* - couldn't import into temporary instance (permission denied)
* - couldn't take snapshot (permission denied)
* - couldn't upgrade properties (permission denied)
* - couldn't import properties (permission denied)
* - couldn't import dependents (permission denied)
* EROFS - couldn't create temporary instance (repository read-only)
* - couldn't import into temporary instance (repository read-only)
* - couldn't upgrade properties (repository read-only)
* - couldn't import properties (repository read-only)
* - couldn't import dependents (repository read-only)
* EACCES - couldn't create temporary instance (backend access denied)
* - couldn't import into temporary instance (backend access denied)
* - couldn't upgrade properties (backend access denied)
* - couldn't import properties (backend access denied)
* - couldn't import dependents (backend access denied)
* EINVAL - invalid instance name (error printed)
* - invalid pgroup_t's (error printed)
* - invalid dependents (error printed)
* EBUSY - temporary service deleted (error printed)
* - temporary instance deleted (error printed)
* - temporary instance changed (error printed)
* - temporary instance already exists (error printed)
* - instance deleted (error printed)
* EBADF - instance has corrupt last-import snapshot (error printed)
* - instance is corrupt (error printed)
* - dependent has corrupt pg (error printed)
* - dependent target has a corrupt snapshot (error printed)
* -1 - unknown libscf error (error printed)
*/
static int
lscf_instance_import(void *v, void *pvt)
{
int r;
const char * const emsg_tdel =
gettext("Temporary instance svc:/%s:%s was deleted.\n");
"changed unexpectedly.\n");
"(instance \"%s\" was deleted.)\n");
const char * const emsg_badsnap = gettext(
"\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
/*
* prepare last-import snapshot:
* create temporary instance (service was precreated)
* populate with properties from bundle
* take snapshot
*/
switch (scf_error()) {
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_ACCESS:
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
"changed unexpectedly (instance \"%s\" added).\n"),
return (UU_WALK_ERROR);
case SCF_ERROR_DELETED:
"was deleted unexpectedly.\n"), imp_tsname);
return (UU_WALK_ERROR);
return (stash_scferror(lcbdata));
"\"%s\" in svc:/%s (permission denied).\n"),
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
if (r < 0)
switch (r) {
case 0:
break;
case ECANCELED:
r = UU_WALK_ERROR;
goto deltemp;
case EEXIST:
r = UU_WALK_ERROR;
goto deltemp;
case ECONNABORTED:
goto connaborted;
case ENOMEM:
case ENOSPC:
case EPERM:
case EROFS:
case EACCES:
case EINVAL:
case EBUSY:
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("lscf_import_instance_pgs", r);
}
if (r < 0)
ctx.sc_service = 0;
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
case ECONNABORTED:
goto connaborted;
case ECANCELED:
break;
case EEXIST:
break;
default:
}
r = UU_WALK_ERROR;
goto deltemp;
}
switch (scf_error()) {
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
r = UU_WALK_ERROR;
goto deltemp;
"(permission denied).\n"), snap_lastimport,
imp_str);
r = stash_scferror(lcbdata);
goto deltemp;
default:
scfwarn();
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_NOT_SET:
}
}
goto fresh;
imp_lisnap) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_NOT_FOUND:
goto nosnap;
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
}
/* upgrade */
/*
* compare new properties with last-import properties
* upgrade current properties
*/
/* clear sc_sceen for pgs */
0)
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
r = UU_WALK_ERROR;
goto deltemp;
case ENOENT:
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("get_snaplevel", r);
}
imp_rsnap) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_NOT_FOUND:
break;
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
} else {
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
r = UU_WALK_ERROR;
goto deltemp;
case ENOENT:
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("get_snaplevel", r);
}
}
switch (r) {
case 0:
break;
case ECANCELED:
case ENODEV:
r = UU_WALK_ERROR;
goto deltemp;
case ECONNABORTED:
goto connaborted;
case ENOMEM:
case ENOSPC:
case EBADF:
case EBUSY:
case EINVAL:
case EPERM:
case EROFS:
case EACCES:
case EEXIST:
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("upgrade_props", r);
}
} else {
switch (scf_error()) {
goto connaborted;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
/* create instance */
imp_inst) != 0) {
switch (scf_error()) {
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_ACCESS:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
"(instance \"%s\" added).\n"),
r = UU_WALK_ERROR;
goto deltemp;
"in %s (permission denied).\n"),
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_INVALID_ARGUMENT: /* caught above */
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_add_instance",
scf_error());
}
}
/*
* Create a last-import snapshot to serve as an attachment
* point for the real one from the temporary instance. Since
* the contents is irrelevent, take it now, while the instance
* is empty, to minimize svc.configd's work.
*/
imp_lisnap) != 0) {
switch (scf_error()) {
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
"(snapshot \"%s\" added).\n"),
r = UU_WALK_ERROR;
goto deltemp;
"of %s (permission denied).\n"),
r = stash_scferror(lcbdata);
goto deltemp;
default:
scfwarn();
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_NOT_SET:
bad_error("_scf_snapshot_take_new",
scf_error());
}
}
if (li_only)
goto lionly;
flags);
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
"(instance \"%s\" deleted).\n"),
r = UU_WALK_ERROR;
goto deltemp;
case EEXIST:
r = UU_WALK_ERROR;
goto deltemp;
default:
r = UU_WALK_ERROR;
goto deltemp;
case EINVAL: /* caught above */
bad_error("lscf_import_instance_pgs", r);
}
ctx.sc_service = 0;
&ctx, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
goto connaborted;
r = UU_WALK_ERROR;
goto deltemp;
}
if (g_verbose)
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ENOSPC:
case -1:
r = UU_WALK_ERROR;
goto deltemp;
case ECANCELED:
"(instance %s deleted).\n"),
r = UU_WALK_ERROR;
goto deltemp;
case EPERM:
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("take_snap", r);
}
}
/* transfer snapshot from temporary instance */
if (g_verbose)
switch (scf_error()) {
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
goto deltemp;
"(permission denied).\n"), snap_lastimport,
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_NOT_SET:
default:
}
}
r = UU_WALK_NEXT;
/* delete temporary instance */
if (scf_instance_delete(imp_tinst) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
goto connaborted;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
return (r);
return (UU_WALK_ERROR);
}
/*
* If the service is missing, create it, import its properties, and import the
* instances. Since the service is brand new, it should be empty, and if we
* run into any existing entities (SCF_ERROR_EXISTS), abort.
*
* If the service exists, we want to upgrade its properties and import the
* instances. Upgrade requires a last-import snapshot, though, which are
* children of instances, so first we'll have to go through the instances
* looking for a last-import snapshot. If we don't find one then we'll just
* override-import the service properties (but don't delete existing
* properties: another service might have declared us as a dependent). Before
* we change anything, though, we want to take the previous snapshots. We
* also give lscf_instance_import() a leg up on taking last-import snapshots
* by importing the manifest's service properties into a temporary service.
*
* On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and
* sets lcbdata->sc_err to
* ECONNABORTED - repository connection broken
* ENOMEM - out of memory
* ENOSPC - svc.configd is out of resources
* EPERM - couldn't create temporary service (error printed)
* - couldn't import into temp service (error printed)
* - couldn't create service (error printed)
* - couldn't import dependent (error printed)
* - couldn't take snapshot (error printed)
* - couldn't create instance (error printed)
* - couldn't create, modify, or delete pg (error printed)
* - couldn't create, modify, or delete dependent (error printed)
* - couldn't import instance (error printed)
* EROFS - couldn't create temporary service (repository read-only)
* - couldn't import into temporary service (repository read-only)
* - couldn't create service (repository read-only)
* - couldn't import dependent (repository read-only)
* - couldn't create instance (repository read-only)
* - couldn't create, modify, or delete pg or dependent
* - couldn't import instance (repository read-only)
* EACCES - couldn't create temporary service (backend access denied)
* - couldn't import into temporary service (backend access denied)
* - couldn't create service (backend access denied)
* - couldn't import dependent (backend access denied)
* - couldn't create instance (backend access denied)
* - couldn't create, modify, or delete pg or dependent
* - couldn't import instance (backend access denied)
* EINVAL - service name is invalid (error printed)
* - service name is too long (error printed)
* - s has invalid pgroup (error printed)
* - s has invalid dependent (error printed)
* - instance name is invalid (error printed)
* - instance entity_t is invalid (error printed)
* EEXIST - couldn't create temporary service (already exists) (error printed)
* - couldn't import dependent (dependency pg already exists) (printed)
* - dependency collision in dependent service (error printed)
* EBUSY - temporary service deleted (error printed)
* - property group added to temporary service (error printed)
* - new property group changed or was deleted (error printed)
* - service was added unexpectedly (error printed)
* - service was deleted unexpectedly (error printed)
* - property group added to new service (error printed)
* - instance added unexpectedly (error printed)
* - instance deleted unexpectedly (error printed)
* - dependent service deleted unexpectedly (error printed)
* - pg was added, changed, or deleted (error printed)
* - dependent pg changed (error printed)
* - temporary instance added, changed, or deleted (error printed)
* EBADF - a last-import snapshot is corrupt (error printed)
* - the service is corrupt (error printed)
* - a dependent is corrupt (error printed)
* - an instance is corrupt (error printed)
* - an instance has a corrupt last-import snapshot (error printed)
* - dependent target has a corrupt snapshot (error printed)
* -1 - unknown libscf error (error printed)
*/
static int
lscf_service_import(void *v, void *pvt)
{
entity_t *s = v;
int r;
int fresh = 0;
int have_ge;
"was deleted unexpectedly.\n");
"changed unexpectedly (property group added).\n");
const char * const s_deleted =
gettext("%s was deleted unexpectedly.\n");
const char * const i_deleted =
gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
"is corrupt (missing service snaplevel).\n");
/* Validate the service name */
switch (scf_error()) {
return (stash_scferror(lcbdata));
"Cannot import.\n"), s->sc_name);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
/* create temporary service */
if (r < 0)
if (r > max_scf_name_len) {
"Service name \"%s\" is too long. Cannot import.\n"),
s->sc_name);
return (UU_WALK_ERROR);
}
switch (scf_error()) {
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_ACCESS:
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
"Temporary service \"%s\" must be deleted before "
"this manifest can be imported.\n"), imp_tsname);
return (stash_scferror(lcbdata));
"\"%s\" (permission denied).\n"), imp_tsname);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
if (r < 0)
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
case ECONNABORTED:
goto connaborted;
case ECANCELED:
return (UU_WALK_ERROR);
case EEXIST:
return (UU_WALK_ERROR);
}
r = UU_WALK_ERROR;
goto deltemp;
}
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
case ECONNABORTED:
goto connaborted;
case ECANCELED:
return (UU_WALK_ERROR);
case EEXIST:
return (UU_WALK_ERROR);
}
r = UU_WALK_ERROR;
goto deltemp;
}
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
switch (scf_error()) {
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_ACCESS:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
" (service \"%s\" added).\n"),
SCF_SCOPE_LOCAL, s->sc_name);
goto deltemp;
"(permission denied).\n"), s->sc_name);
goto deltemp;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
/* import service properties */
&cbdata, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
case ECONNABORTED:
goto connaborted;
case ECANCELED:
return (UU_WALK_ERROR);
case EEXIST:
"(property group added).\n"), s->sc_fmri);
return (UU_WALK_ERROR);
case EINVAL:
/* caught above */
bad_error("entity_pgroup_import",
}
r = UU_WALK_ERROR;
goto deltemp;
}
&cbdata, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
goto connaborted;
r = UU_WALK_ERROR;
goto deltemp;
}
/*
* This is a new service, so we can't take previous snapshots
* or upgrade service properties.
*/
fresh = 1;
goto instances;
}
/* Clear sc_seen for the instances. */
/*
* Take previous snapshots for all instances. Even for ones not
* mentioned in the bundle, since we might change their service
* properties.
*/
switch (scf_error()) {
goto connaborted;
case SCF_ERROR_DELETED:
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
for (;;) {
if (r == 0)
break;
if (r != 1) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = UU_WALK_ERROR;
goto deltemp;
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_next_instance",
scf_error());
}
}
switch (scf_error()) {
case SCF_ERROR_DELETED:
continue;
goto connaborted;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
if (g_verbose)
"Taking \"%s\" snapshot for svc:/%s:%s.\n"),
switch (r) {
case 0:
break;
case ECANCELED:
continue;
case ECONNABORTED:
goto connaborted;
case EPERM:
"svc:/%s:%s (permission denied).\n"),
return (UU_WALK_ERROR);
case ENOSPC:
case -1:
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("take_snap", r);
}
}
}
/*
* Create the new instances and take previous snapshots of
* them. This is not necessary, but it maximizes data preservation.
*/
inst)) {
continue;
imp_inst) != 0) {
switch (scf_error()) {
goto connaborted;
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
"(instance \"%s\" added).\n"), s->sc_fmri,
r = UU_WALK_ERROR;
goto deltemp;
"invalid name \"%s\".\n"), s->sc_name,
r = stash_scferror(lcbdata);
goto deltemp;
"in %s (permission denied).\n"),
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_add_instance",
scf_error());
}
}
if (g_verbose)
switch (r) {
case 0:
break;
case ECANCELED:
r = UU_WALK_ERROR;
goto deltemp;
case ECONNABORTED:
goto connaborted;
case EPERM:
r = UU_WALK_ERROR;
goto deltemp;
case ENOSPC:
case -1:
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("take_snap", r);
}
}
/*
* Upgrade service properties, if we can find a last-import snapshot.
* Any will do because we don't support different service properties
* in different manifests, so all snaplevels of the service in all of
* the last-import snapshots of the instances should be the same.
*/
switch (scf_error()) {
goto connaborted;
case SCF_ERROR_DELETED:
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
have_ge = 0;
li_only = 0;
for (;;) {
if (r == -1) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = UU_WALK_ERROR;
goto deltemp;
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_next_instance",
scf_error());
}
}
if (r == 0) {
/*
* Didn't find any last-import snapshots. Override-
* import the properties. Unless one of the instances
* probably running a last-import-capable svccfg for
* the first time, and we should only take the
* last-import snapshot.
*/
if (have_ge) {
li_only = 1;
no_refresh = 1;
break;
}
&cbdata, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
case ECONNABORTED:
goto connaborted;
case ECANCELED:
break;
case EINVAL: /* caught above */
case EEXIST:
bad_error("entity_pgroup_import",
}
r = UU_WALK_ERROR;
goto deltemp;
}
if (uu_list_walk(s->sc_dependents,
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
goto connaborted;
r = UU_WALK_ERROR;
goto deltemp;
}
break;
}
imp_snap) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
continue;
case SCF_ERROR_NOT_FOUND:
break;
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
if (have_ge)
continue;
/*
* we tell whether to import if there turn out to be
* no last-import snapshots.
*/
imp_pg) == 0) {
SCF_PROPERTY_ENABLED, imp_prop) == 0) {
have_ge = 1;
} else {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
continue;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_get_property",
scf_error());
}
}
} else {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
continue;
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_pg",
scf_error());
}
}
continue;
}
/* find service snaplevel */
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
continue;
case ENOENT:
imp_str_sz) < 0)
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("get_snaplevel", r);
}
imp_rsnap) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
continue;
case SCF_ERROR_NOT_FOUND:
break;
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
} else {
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
continue;
case ENOENT:
imp_str_sz) < 0)
imp_str);
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("get_snaplevel", r);
}
}
if (g_verbose) {
imp_str_sz) < 0)
}
/* upgrade service properties */
if (r == 0)
break;
switch (r) {
case ECONNABORTED:
goto connaborted;
case ECANCELED:
break;
case ENODEV:
imp_str_sz) < 0)
break;
default:
}
r = UU_WALK_ERROR;
goto deltemp;
}
/* import instances */
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
goto connaborted;
r = UU_WALK_ERROR;
goto deltemp;
}
r = UU_WALK_NEXT;
/* delete temporary service */
if (scf_service_delete(imp_tsvc) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
goto connaborted;
case SCF_ERROR_EXISTS:
"Could not delete svc:/%s (instances exist).\n"),
break;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
return (r);
"(repository connection broken).\n"), imp_tsname);
return (UU_WALK_ERROR);
}
static const char *
import_progress(int st)
{
switch (st) {
case 0:
return (gettext("not reached."));
case IMPORT_PREVIOUS:
return (gettext("previous snapshot taken."));
case IMPORT_PROP_BEGUN:
return (gettext("some properties imported."));
case IMPORT_PROP_DONE:
return (gettext("properties imported."));
case IMPORT_COMPLETE:
return (gettext("imported."));
case IMPORT_REFRESHED:
return (gettext("refresh requested."));
default:
#ifndef NDEBUG
#endif
abort();
/* NOTREACHED */
}
}
/*
* Returns
* 0 - success
* - fmri wasn't found (error printed)
* - entity was deleted (error printed)
* - backend denied access (error printed)
* ENOMEM - out of memory (error printed)
* ECONNABORTED - repository connection broken (error printed)
* EPERM - permission denied (error printed)
* -1 - unknown libscf error (error printed)
*/
static int
{
void *ent;
int issvc;
int r;
"(dependent \"%s\" of %s) (deleted).\n");
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
fmri);
else
"(dependent \"%s\" of %s) (out of memory).\n"),
return (ENOMEM);
case SCF_ERROR_NOT_FOUND:
else
return (0);
default:
}
switch (r) {
case 0:
break;
case ECONNABORTED:
"(dependent \"%s\" of %s) "
d_fmri);
return (r);
case ECANCELED:
else
return (0);
case EACCES:
if (!g_verbose)
return (0);
"(backend access denied).\n"), fmri);
else
"(dependent \"%s\" of %s) "
return (0);
case EPERM:
"(permission denied).\n"), fmri);
else
"(dependent \"%s\" of %s) "
return (r);
case -1:
scfwarn();
return (r);
default:
bad_error("refresh_entity", r);
}
if (issvc)
else
return (0);
}
int
{
int result = 0;
int r;
void *cookie;
const char * const emsg_nores =
if (scf_error() == SCF_ERROR_NO_RESOURCES)
else
result = -1;
goto out;
}
r = load_init();
switch (r) {
case 0:
break;
case ENOMEM:
result = -1;
goto out;
default:
bad_error("load_init", r);
}
switch (scf_error()) {
result = -1;
goto out;
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NOT_BOUND:
default:
}
}
/*
* Clear the sc_import_state's of all services & instances so we can
* report how far we got if we fail.
*/
svc->sc_import_state = 0;
UU_DEFAULT) != 0)
}
&cbdata, UU_DEFAULT) == 0) {
/* Success. Refresh everything. */
result = 0;
goto out;
}
switch (r) {
case 0:
break;
case ENOMEM:
case ECONNABORTED:
case EPERM:
case -1:
goto progress;
default:
bad_error("imp_refresh_fmri", r);
}
dpt))
if (imp_refresh_fmri(
goto progress;
}
goto progress;
}
goto progress;
result = 0;
goto out;
}
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
/* If the error hasn't been printed yet, do so here. */
case ECONNABORTED:
break;
case ENOMEM:
break;
case ENOSPC:
break;
case EROFS:
break;
case EACCES:
break;
case EPERM:
case EINVAL:
case EEXIST:
case EBUSY:
case EBADF:
case -1:
break;
default:
}
}
result = -1;
out:
load_fini();
NULL) {
}
return (result);
}
/*
* Returns
* 0 - success
* -1 - lscf_import_instance_pgs() failed.
*/
int
{
int r;
scfdie();
scfdie();
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
if (g_verbose)
continue;
default:
scfdie();
}
}
for (inst = uu_list_first(
inst = uu_list_next(
rinst) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
if (g_verbose)
"nonexistant instance "
"%s:%s.\n"),
continue;
default:
scfdie();
}
}
switch (r) {
case 0:
if (g_verbose)
break;
case ECONNABORTED:
"(repository connection broken).\n"),
goto out;
case ENOMEM:
goto out;
case ENOSPC:
"(repository server out of resources).\n"),
goto out;
case ECANCELED:
"Could not update %s (deleted).\n"),
break;
case EPERM:
case EINVAL:
case EBUSY:
break;
case EROFS:
"(repository read-only).\n"),
goto out;
case EACCES:
"(backend access denied).\n"),
break;
case EEXIST:
default:
bad_error("lscf_import_instance_pgs", r);
}
}
}
out:
return (0);
}
/*
* Export. These functions create and output an XML tree of a service
* description from the repository. This is largely the inverse of
* lxml_get_bundle() in svccfg_xml.c, but with some kickers:
*
* - We must include any properties which are not represented specifically by
* a service manifest, e.g., properties created by an admin post-import. To
* do so we'll iterate through all properties and deal with each
* apropriately.
*
* - Children of services and instances must must be in the order set by the
* DTD, but we iterate over the properties in undefined order. The elements
* are not easily (or efficiently) sortable by name. Since there's a fixed
* number of classes of them, however, we'll keep the classes separate and
* assemble them in order.
*/
/*
* Convenience function to handle xmlSetProp errors (and type casting).
*/
static void
{
}
/*
* Convenience function to set an XML attribute to the single value of an
* astring property. If the value happens to be the default, don't set the
* attribute. "dval" should be the default value supplied by the DTD, or
* NULL for no default.
*/
static int
{
char *str;
scfdie();
return (-1);
}
if (len < 0)
scfdie();
scfdie();
return (0);
}
/*
* As above, but the attribute is always set.
*/
static int
{
}
/*
* Dump the given document onto f, with "'s replaced by ''s.
*/
static int
{
int sz, i;
return (-1);
}
/*
* Fortunately libxml produces " instead of ", so we can blindly
* replace all " with '. Cursed libxml2! Why must you #ifdef out the
* ' code?!
*/
for (i = 0; i < sz; ++i) {
char c = (char)mem[i];
if (c == '"')
(void) fputc('\'', f);
else if (c == '\'')
else
(void) fputc(c, f);
}
return (0);
}
/*
* Create the DOM elements in elts necessary to (generically) represent prop
* (i.e., a property or propval element). If the name of the property is
* known, it should be passed as name_arg. Otherwise, pass NULL.
*/
static void
{
const char *type;
char *lnname;
int ret;
/* name */
} else {
scfdie();
}
/* type */
exp_str);
/* Is there a single value? */
xmlNodePtr n;
/* Single value, so use propval */
if (n == NULL)
scfdie();
else
return;
}
scfdie();
/* Multiple (or no) values, so use property */
if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
scfdie();
1) {
NULL);
exp_str_sz) < 0)
scfdie();
}
if (ret != 0)
scfdie();
}
else
}
/*
* Add a property_group element for this property group to elts.
*/
static void
{
xmlNodePtr n;
int ret;
/* name */
scfdie();
/* type */
scfdie();
/* properties */
scfdie();
scfdie();
xmlNodePtr m;
if (m == NULL)
continue;
}
xmlFreeNode(m);
}
}
if (ret == -1)
scfdie();
eelts->property_groups = n;
else
}
/*
* Create an XML node representing the dependency described by the given
* property group and put it in eelts. Unless the dependency is not valid, in
* which case create a generic property_group element which represents it and
* put it in eelts.
*/
static void
{
xmlNodePtr n;
if (n == NULL)
/*
* If the external flag is present, skip this dependency because it
* should have been created by another manifest.
*/
uint8_t b;
scfdie();
if (b)
return;
}
} else if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
/* Get the required attributes. */
/* name */
scfdie();
/* grouping */
err = 1;
/* restart_on */
err = 1;
/* type */
err = 1;
/*
* entities: Not required, but if we create no children, it will be
* created as empty on import, so fail if it's missing.
*/
int ret2;
scfdie();
scfdie();
exp_str_sz) < 0)
scfdie();
/*
* service_fmri's must be first, so we can add them
* here.
*/
NULL);
}
if (ret2 == -1)
scfdie();
} else
err = 1;
if (err) {
xmlFreeNode(n);
return;
}
/* Iterate through the properties & handle each. */
scfdie();
scfdie();
continue;
xmlNodePtr m;
if (m == NULL)
continue;
}
xmlFreeNode(m);
}
}
if (ret == -1)
scfdie();
eelts->dependencies = n;
else
}
static xmlNodePtr
{
int ret;
int children = 0;
return (NULL);
scfdie();
scfdie();
char *cp;
scfdie();
exp_str);
continue;
"\"SMF_\" prefix is reserved.\n"), exp_str);
continue;
}
*cp = '\0';
cp++;
children++;
}
if (ret != 0)
scfdie();
if (children == 0) {
return (NULL);
}
return (env);
}
/*
* As above, but for a method property group.
*/
static void
{
xmlNodePtr n, env;
char *str;
/* Get the required attributes. */
/* name */
scfdie();
/* type */
err = 1;
/* exec */
err = 1;
/* timeout */
uint64_t c;
scfdie();
} else
err = 1;
if (err) {
xmlFreeNode(n);
return;
}
/*
* If we're going to have a method_context child, we need to know
* before we iterate through the properties. Since method_context's
* are optional, we don't want to complain about any properties
* missing if none of them are there. Thus we can't use the
* convenience functions.
*/
nonenv =
SCF_SUCCESS ||
SCF_SUCCESS ||
SCF_SUCCESS ||
if (nonenv) {
/*
* We only want to complain about profile or credential
* properties if we will use them. To determine that we must
* examine USE_PROFILE.
*/
scfdie();
} else
/*
* USE_PROFILE is misconfigured. Since we should have
* complained just now, we don't want to complain
* about any of the other properties, so don't look
* for them.
*/
nonenv = 0;
}
if (nonenv) {
0 ||
"working_directory", ":default") != 0)
err = 1;
":default") != 0)
err = 1;
0 ||
"resource_pool", ":default") != 0)
err = 1;
if (use_profile) {
name_attr) != 0)
err = 1;
} else {
err = 1;
0 ||
"group", ":default") != 0)
err = 1;
exp_prop) != 0 ||
"supp_groups", ":default") != 0)
err = 1;
exp_prop) != 0 ||
"privileges", ":default") != 0)
err = 1;
exp_prop) != 0 ||
"limit_privileges", ":default") != 0)
err = 1;
}
}
(void) xmlAddChild(n, ctxt);
else
scfdie();
scfdie();
continue;
xmlNodePtr m;
if (m == NULL)
continue;
}
xmlFreeNode(m);
0 ||
if (nonenv)
continue;
if (nonenv && !use_profile)
continue;
if (nonenv && use_profile)
continue;
continue;
}
}
if (ret == -1)
scfdie();
eelts->exec_methods = n;
else
}
static void
struct entity_elts *eelts)
{
else
}
/*
* Process the general property group for a service. This is the one with the
* goodies.
*/
static void
{
int ret;
/*
* In case there are properties which don't correspond to child
* entities of the service entity, we'll set up a pg_elts structure to
* put them in.
*/
/* Walk the properties, looking for special ones. */
scfdie();
scfdie();
uint8_t b;
if (scf_value_get_boolean(exp_val, &b) !=
scfdie();
if (b) {
(xmlChar *)"single_instance");
}
continue;
}
value_attr) == 0) {
continue;
}
0) {
xmlNodePtr s;
if (s == NULL)
continue;
}
xmlFreeNode(s);
}
}
if (ret == -1)
scfdie();
selts);
}
static void
{
/* Need to know whether we'll use a profile or not. */
(void) xmlAddChild(n, env);
elts->method_context = n;
} else {
xmlFreeNode(n);
}
return;
}
scfdie();
if (use_profile)
else
cred =
(void) xmlAddChild(n, env);
scfdie();
scfdie();
if (set_attr_from_prop(exp_prop, n,
"working_directory") != 0)
err = 1;
err = 1;
if (set_attr_from_prop(exp_prop, n,
"resource_pool") != 0)
err = 1;
/* EMPTY */
if (use_profile ||
err = 1;
if (use_profile ||
err = 1;
"supp_groups") != 0)
err = 1;
"privileges") != 0)
err = 1;
0) {
"limit_privileges") != 0)
err = 1;
err = 1;
} else {
/* Can't have generic properties in method_context's */
err = 1;
}
}
if (ret == -1)
scfdie();
xmlFreeNode(n);
return;
}
elts->method_context = n;
}
/*
* Given a dependency property group in the tfmri entity (target fmri), return
* a dependent element which represents it.
*/
static xmlNodePtr
{
uint8_t b;
xmlNodePtr n, sf;
/*
* If external isn't set to true then exporting the service will
* export this as a normal dependency, so we should stop to avoid
* duplication.
*/
scf_value_get_boolean(exp_val, &b) != 0 || !b) {
if (g_verbose) {
"properly because the \"%s\" property of the "
"\"%s\" dependency of %s is not set to true.\n"),
}
return (NULL);
}
if (n == NULL)
/* Get the required attributes */
err = 1;
err = 1;
/* EMPTY */
} else
err = 1;
if (err) {
xmlFreeNode(n);
return (NULL);
}
/*
* Now add elements for the other properties.
*/
scfdie();
scfdie();
continue;
sizeof (type)) < 0)
scfdie();
continue;
}
xmlNodePtr s;
if (s == NULL)
continue;
}
xmlFreeNode(s);
}
}
if (ret == -1)
scfdie();
return (n);
}
static void
{
int ret;
xmlNodePtr n;
scfdie();
/* Can't use exp_prop_iter due to export_dependent(). */
scfdie();
/* Get an extra byte so we can tell if values are too long. */
void *entity;
int isservice;
scfdie();
if ((ty != SCF_TYPE_ASTRING &&
continue;
}
scfdie();
max_scf_fmri_len + 2) < 0)
scfdie();
/* Look for a dependency group in the target fmri. */
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
/* NOTREACHED */
if (g_verbose) {
max_scf_fmri_len + 2) < 0)
scfdie();
"FMRI.\n"), fmri);
}
continue;
if (g_verbose) {
max_scf_fmri_len + 2) < 0)
scfdie();
"a service or an instance.\n"), fmri);
}
continue;
case SCF_ERROR_NOT_FOUND:
if (g_verbose) {
max_scf_fmri_len + 2) < 0)
scfdie();
"not exist.\n"), fmri);
}
continue;
default:
#ifndef NDEBUG
"fmri_to_entity", serr);
#endif
abort();
}
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
continue;
}
scfdie();
scfdie();
continue;
}
if (n == NULL)
else {
eelts->dependents = n;
else
n);
}
}
if (ret == -1)
scfdie();
eelts);
}
static void
{
}
}
static xmlNodePtr
{
int ret;
scfdie();
continue;
scfdie();
scfdie();
}
if (ret == -1)
scfdie();
return (parent);
}
static xmlNodePtr
{
return (NULL);
}
(void) set_attr_from_prop_default(exp_prop,
return (manpage);
}
static xmlNodePtr
{
return (NULL);
}
return (doc_link);
}
/*
* Process template information for a service or instances.
*/
static void
struct template_elts *telts)
{
scfdie();
return;
return;
}
}
} else {
}
}
/*
* Process the general property group for an instance.
*/
static void
struct entity_elts *elts)
{
int ret;
/* enabled */
scfdie();
} else {
enabled = 0;
}
scfdie();
scfdie();
continue;
value_attr) == 0) {
continue;
}
}
}
if (ret == -1)
scfdie();
elts);
}
/*
* Put an instance element for the given instance into selts.
*/
static void
{
xmlNodePtr n;
struct entity_elts elts;
struct template_elts template_elts;
int ret;
if (n == NULL)
/* name */
scfdie();
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (g_verbose) {
scfdie();
"group; it will be marked disabled.\n"), exp_str);
}
safe_setprop(n, enabled_attr, false);
if (g_verbose) {
scfdie();
"framework; the instance will be marked "
"disabled.\n"), exp_str);
}
safe_setprop(n, enabled_attr, false);
}
/* property groups */
scfdie();
scfdie();
if (flags & SCF_PG_FLAG_NONPERSISTENT)
continue;
scfdie();
continue;
continue;
max_scf_name_len + 1) < 0)
scfdie();
continue;
0) {
continue;
continue;
}
continue;
}
/* Ordinary pg. */
}
if (ret == -1)
scfdie();
} else {
}
/* This is a default instance */
xmlFreeNode(n);
if (n == NULL)
selts->create_default_instance = n;
} else {
/* Assemble the children in order. */
else
}
}
/*
* Return a service element for the given service.
*/
static xmlNodePtr
{
struct entity_elts elts;
struct template_elts template_elts;
int ret;
/* Get & set name attribute */
scfdie();
/* Acquire child elements. */
scfdie();
scfdie();
if (flags & SCF_PG_FLAG_NONPERSISTENT)
continue;
scfdie();
continue;
continue;
max_scf_name_len + 1) < 0)
scfdie();
continue;
0) {
continue;
continue;
}
continue;
}
}
if (ret == -1)
scfdie();
} else {
}
/* Iterate instances */
scfdie();
if (ret == -1)
scfdie();
/* Now add all of the accumulated elements in order. */
return (snode);
}
static int
{
FILE *f;
int result;
scfdie();
errno = 0;
if (f == NULL) {
if (errno == 0)
"stdio streams.\n"), filename);
else
filename);
}
} else
f = stdout;
if (f != stdout)
(void) fclose(f);
return (result);
}
/*
* Get the service named by fmri, build an XML tree which represents it, and
* dump it into filename (or stdout if filename is NULL).
*/
int
{
err = 0;
if (ret != -1)
scf_strerror(ret));
return (-1);
}
/*
* Error message has already been printed.
*/
if (err != 0)
return (-1);
return (0);
}
/*
* Archive
*/
static xmlNodePtr
{
int r;
scfdie();
scfdie();
scfdie();
for (;;) {
if (r == 0)
break;
if (r != 1)
scfdie();
max_scf_name_len + 1) < 0)
scfdie();
continue;
}
return (sb);
}
int
lscf_archive(const char *filename)
{
FILE *f;
int result;
errno = 0;
if (f == NULL) {
if (errno == 0)
"stdio streams.\n"), filename);
else
filename);
}
} else
f = stdout;
if (f != stdout)
(void) fclose(f);
return (result);
}
/*
* "Extract" a profile.
*/
int
lscf_profile_extract(const char *filename)
{
FILE *f;
int r, s;
char *namebuf;
uint8_t b;
int result;
errno = 0;
if (f == NULL) {
if (errno == 0)
"free stdio streams.\n"), filename);
else
filename);
}
} else
f = stdout;
scfdie();
scfdie();
scfdie();
scfdie();
0)
scfdie();
SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (g_verbose) {
char *fmri;
len =
if (len < 0)
scfdie();
len + 1) < 0)
scfdie();
warn("Instance %s has no \"%s\" "
"property group.\n", fmri,
}
continue;
}
continue;
NULL);
max_scf_name_len + 1) < 0)
scfdie();
scfdie();
}
if (s < 0)
scfdie();
else
}
if (r < 0)
scfdie();
if (f != stdout)
(void) fclose(f);
return (result);
}
/*
* Entity manipulation commands
*/
/*
* Entity selection. If no entity is selected, then the current scope is in
* cur_scope, and cur_svc and cur_inst are NULL. When a service is selected,
* only cur_inst is NULL, and when an instance is selected, none are NULL.
* When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
* cur_inst will be non-NULL.
*/
/* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
static int
select_inst(const char *name)
{
scfdie();
return (0);
}
scfdie();
return (1);
}
/* Returns as above. */
static int
select_svc(const char *name)
{
scfdie();
return (0);
}
scfdie();
return (1);
}
/* ARGSUSED */
static int
{
scfdie();
scfdie();
} else {
scfdie();
scfdie();
}
/* Clear out the current selection */
return (0);
}
void
lscf_select(const char *fmri)
{
char *buf;
/* Error unless name is that of the next level. */
return;
}
max_scf_name_len + 1) < 0)
scfdie();
return;
}
return;
}
/*
* Special case for 'svc:', which takes the user to the scope level.
*/
return;
}
/*
* Special case for ':properties'. This appears as part of 'list' but
* can't be selected. Give a more helpful error message in this case.
*/
"to list properties.\n"));
return;
}
/*
* First try the argument as relative to the current selection.
*/
/* EMPTY */;
return;
} else {
return;
}
err = 0;
scf_strerror(ret));
}
}
void
lscf_unselect(void)
{
} else {
}
} else {
}
}
/*
* Return the FMRI of the current selection, for the prompt.
*/
void
{
char *cp;
return;
}
/* [ snapshot ] FMRI [: instance ] */
buf[0] = '[';
max_scf_name_len + 1);
if (szret < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto snap_deleted;
}
max_scf_name_len + 1);
if (szret < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto snap_deleted;
}
if (snaplevel_is_instance(cur_level)) {
*cp++ = ':';
max_scf_name_len + 1) < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto snap_deleted;
}
} else {
*cp++ = '[';
*cp++ = ':';
max_scf_name_len + 1) < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto snap_deleted;
}
}
return;
}
if (fmrilen >= 0) {
if (deleted)
return;
}
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
if (szret >= 0) {
if (deleted)
return;
}
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
if (fmrilen < 0)
scfdie();
if (deleted)
}
/*
* Entity listing. Entities and colon namespaces (e.g., :properties and
* :statistics) are listed for the current selection.
*/
void
{
char *buf;
int ret;
return;
/*
* For now, we know that the next level is an instance. But
* if we ever have multiple scopes, this could be complicated.
*/
max_scf_name_len + 1) >= 0) {
} else {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
return;
}
return;
}
scfdie();
/* List the instances in this service. */
scfdie();
for (;;) {
if (ret == 0)
break;
if (ret != 1) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
break;
}
max_scf_name_len + 1) >= 0) {
} else {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
}
} else {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
} else {
/* List the services in this scope. */
scfdie();
scfdie();
for (;;) {
if (ret == 0)
break;
if (ret != 1)
scfdie();
max_scf_name_len + 1) >= 0) {
} else {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
}
}
}
/*
* Entity addition. Creates an empty entity in the current selection.
*/
void
{
SCF_SUCCESS) {
switch (scf_error()) {
break;
case SCF_ERROR_EXISTS:
break;
break;
default:
scfdie();
}
}
} else {
SCF_SUCCESS) {
switch (scf_error()) {
break;
case SCF_ERROR_EXISTS:
break;
break;
break;
default:
scfdie();
}
}
}
}
/*
* Entity deletion.
*/
/*
* Delete the property group <fmri>/:properties/<name>. Returns
* SCF_ERROR_NONE on success (or if the entity is not found),
* SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
* the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
* denied.
*/
static scf_error_t
{
int isservice;
char *pgty;
switch (result) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
/* NOTREACHED */
return (SCF_ERROR_INVALID_ARGUMENT);
case SCF_ERROR_NOT_FOUND:
goto out;
default:
}
scfdie();
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
goto out;
}
scfdie();
goto out;
}
if (scf_pg_delete(pg) == 0) {
if (isservice) {
scfdie();
}
name_buf);
} else if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
else
out:
return (result);
}
static int
{
int r;
/* Verify that the pg has the correct type. */
scfdie();
if (g_verbose) {
scfdie();
}
return (-1);
}
/* map delete_dependency_pg onto the properties. */
scfdie();
scfdie();
scfdie();
scfdie();
if ((ty != SCF_TYPE_ASTRING &&
continue;
scfdie();
max_scf_fmri_len + 2) < 0)
scfdie();
fmri);
"of entity \"%s\" (permission denied).\n"), name,
fmri);
}
}
if (r == -1)
scfdie();
return (0);
}
/*
* Returns 1 if the instance may be running, and 0 otherwise.
*/
static int
{
char buf[MAX_SCF_STATE_STRING_SZ];
int ret = 0;
scfdie();
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
goto out;
}
goto out;
out:
return (ret);
}
static int
{
/* If we're not forcing and the instance is running, refuse. */
char *fmri;
scfdie();
"Use delete -f if it is not.\n"), fmri);
return (-1);
}
scfdie();
(void) delete_dependents(pg);
else if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
return (-1);
}
return (0);
}
static int
{
int r;
scfdie();
scfdie();
r == 1;
return (-1);
}
}
if (r != 0)
scfdie();
/* Delete dependency property groups in dependent services. */
(void) delete_dependents(pg);
else if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (r != 0)
return (-1);
return (0);
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
return (-1);
}
static int
{
else
return (0);
}
void
{
int ret;
if (!snaplevel_is_instance(cur_level)) {
char *buf;
max_scf_name_len + 1) >= 0) {
return;
}
} else if (scf_error() != SCF_ERROR_DELETED) {
scfdie();
}
}
/* EMPTY */;
scfdie();
SCF_SUCCESS) {
return;
}
if (scf_error() != SCF_ERROR_NOT_FOUND &&
scfdie();
} else {
scfdie();
SCF_SUCCESS) {
return;
}
if (scf_error() != SCF_ERROR_NOT_FOUND &&
scfdie();
}
/*
* Match FMRI to entity.
*/
scf_strerror(ret));
}
}
/*
* :properties commands. These all end with "pg" or "prop" and generally
* operate on the currently selected entity.
*/
/*
* Property listing. List the property groups, properties, their types and
* their values for the currently selected entity.
*/
static void
{
char *buf;
scfdie();
scfdie();
if (flags & SCF_PG_FLAG_NONPERSISTENT)
safe_printf("\tNONPERSISTENT");
safe_printf("\n");
}
static boolean_t
{
return (B_FALSE);
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (B_FALSE);
return (B_TRUE);
default:
scfdie();
/*NOTREACHED*/
}
}
}
static void
{
const char *type;
int multiple_strings = 0;
int ret;
scfdie();
multiple_strings = 1;
scfdie();
char *buf;
if (vlen < 0)
scfdie();
if (szret < 0)
scfdie();
/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
safe_printf(" \"");
(void) putchar('"');
(void) putchar('\n');
}
} else {
}
}
if (ret != 0)
scfdie();
}
static void
{
void **objects;
char **names;
int allocd, i;
int ret;
return;
}
scfdie();
else
if (ret != 0) {
if (scf_error() == SCF_ERROR_DELETED)
scfdie();
return;
}
/*
* We want to only list items which match pattern, and we want the
* second column to line up, so during the first pass we'll save
* matching items & their names in objects and names, computing the
* maximum name length as we go, and then we'll print them out.
*
* Note: We always keep an extra slot available so the array can be
* NULL-terminated.
*/
i = 0;
allocd = 1;
int new_pg = 0;
if (pgnlen < 0)
scfdie();
if (szret < 0)
scfdie();
if (i+1 >= allocd) {
allocd *= 2;
names =
}
++i;
new_pg = 1;
}
if (only_pgs) {
if (new_pg) {
scfdie();
} else
continue;
}
scfdie();
max_scf_name_len + 1);
if (prnlen < 0)
scfdie();
/* Will prepend the property group name and a slash. */
prnbuf) < 0)
uu_die("snprintf");
if (i+1 >= allocd) {
allocd *= 2;
"memory"));
}
++i;
} else {
}
}
if (new_pg) {
scfdie();
} else
}
if (ret != 0)
scfdie();
/* property group */
} else {
/* property */
}
}
}
void
lscf_listpg(const char *pattern)
{
}
/*
* Property group and property creation, setting, and deletion. setprop (and
* its alias, addprop) can either create a property group of a given type, or
* it can create or set a property to a given type and list of values.
*/
void
{
int ret;
const char *cp;
return;
}
return;
}
switch (*cp) {
case 'P':
break;
case 'p':
break;
default:
"%c."), *cp);
return;
}
}
}
scfdie();
else
if (ret != SCF_SUCCESS) {
switch (scf_error()) {
break;
case SCF_ERROR_EXISTS:
break;
break;
case SCF_ERROR_BACKEND_ACCESS:
break;
default:
scfdie();
}
}
}
void
lscf_delpg(char *name)
{
return;
}
return;
}
return;
}
}
void
lscf_listprop(const char *pattern)
{
}
int
{
scf_value_t *v;
char *propname;
int req_quotes = 0;
scfdie();
goto fail;
}
goto fail;
}
goto fail;
}
*propname = '\0';
++propname;
if (ty == SCF_TYPE_INVALID) {
goto fail;
}
}
else
if (ret != SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
goto fail;
goto fail;
default:
scfdie();
break;
}
}
do {
scfdie();
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
goto fail;
}
if (ret == SCF_SUCCESS) {
scfdie();
ty = current_ty;
scfdie();
} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
gettext("Type required for new properties.\n"));
goto fail;
}
ty) == -1)
scfdie();
} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
goto fail;
} else {
scfdie();
}
req_quotes = 1;
if (v == NULL)
goto fail;
ret = scf_entry_add_value(e, v);
} else {
if (v == NULL) {
goto fail;
}
ret = scf_entry_add_value(e, v);
}
}
} while (result == 0);
if (result < 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
goto fail;
}
return (0);
fail:
return (-1);
}
void
lscf_delprop(char *pgn)
{
int ret;
return;
}
return;
}
scfdie();
} else {
*slash = '\0';
}
else
if (ret != SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
break;
default:
scfdie();
}
return;
}
/* Try to delete the property group. */
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
}
return;
}
e = scf_entry_create(g_hndl);
do {
scfdie();
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
break;
}
if (scf_error() == SCF_ERROR_NOT_FOUND) {
break;
} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
break;
} else {
scfdie();
}
}
if (ret == 0)
} while (ret == 0);
if (ret < 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
}
}
/*
* Property editing.
*/
static int
{
char *fmribuf;
const char *emsg_write_error;
/* select fmri */
if (fmrilen < 0)
scfdie();
scfdie();
} else {
if (fmrilen < 0)
scfdie();
scfdie();
}
return (-1);
}
scfdie();
else
if (ret != SCF_SUCCESS)
scfdie();
int ret2;
/*
* # delprop pg
* # addpg pg type
*/
scfdie();
scfdie();
"# delprop %s\n"
result = -1;
goto out;
}
scfdie();
int first = 1;
int ret3;
int multiple_strings = 0;
max_scf_name_len + 1) < 0)
scfdie();
scfdie();
result = -1;
goto out;
}
multiple_strings = 1;
scfdie();
char *buf;
if (buflen < 0)
scfdie();
buflen + 1) < 0)
scfdie();
if (first)
first = 0;
else {
result = -1;
goto out;
}
}
if (multiple_strings ||
result = -1;
goto out;
}
} else {
result = -1;
goto out;
}
}
}
if (ret3 < 0)
scfdie();
result = -1;
goto out;
}
}
if (ret2 < 0)
scfdie();
result = -1;
goto out;
}
}
if (ret < 0)
scfdie();
out:
if (result == 0) {
return (-1);
}
}
return (result);
}
int
{
int tmpfd;
char tempname[] = TEMP_FILE_PATTERN;
return (-1);
}
return (-1);
}
if (tmpfd == -1) {
return (-1);
}
return (-1);
}
return (-1);
}
editor = "vi";
return (-1);
}
return (0);
}
static void
{
uu_strerror(uu_error()));
}
/*
* Get all property values that don't match the given glob pattern,
* if a pattern is specified.
*/
static void
const char *pattern)
{
int ret;
scfdie();
scfdie();
char *buf;
if (vlen < 0)
scfdie();
if (szret < 0)
scfdie();
}
if (ret == -1)
scfdie();
}
static int
{
scf_value_t *v;
char *propname;
uu_strerror(uu_error()));
if (!isadd)
scfdie();
goto fail;
}
goto fail;
}
goto fail;
}
*propname = '\0';
++propname;
if (ty == SCF_TYPE_INVALID) {
goto fail;
}
}
else
if (ret != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
if (isnotfoundok) {
result = 0;
} else {
result = -1;
}
goto out;
goto fail;
default:
scfdie();
}
}
do {
scfdie();
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
goto fail;
}
if (ret == 0) {
scfdie();
if (isadd) {
"of type \"%s\".\n"), propname,
type);
goto fail;
}
} else {
pat++;
}
if (isadd)
if (scf_transaction_property_change(tx, e,
scfdie();
} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
if (isadd) {
"for new properties.\n"));
goto fail;
}
if (scf_transaction_property_new(tx, e,
scfdie();
} else if (isnotfoundok) {
result = 0;
goto out;
} else {
result = -1;
goto out;
}
} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
goto fail;
} else {
scfdie();
}
if (v == NULL) {
goto fail;
}
ret = scf_entry_add_value(e, v);
}
} while (result == 0);
if (result < 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
goto fail;
}
result = 0;
out:
}
return (result);
fail:
result = -1;
goto out;
}
int
{
}
int
{
}
/*
* Look for a standard start method, first in the instance (if any),
* then the service.
*/
static const char *
start_method_name(int *in_instance)
{
char **p;
int ret;
scfdie();
for (p = start_method_names; *p != NULL; p++) {
else
if (ret == 0) {
continue;
}
continue;
}
return (*p);
}
if (scf_error() == SCF_ERROR_NOT_FOUND)
continue;
scfdie();
}
goto again;
}
return (NULL);
}
static int
{
int ret;
scfdie();
else
if (ret != 0) {
switch (scf_error()) {
case SCF_ERROR_EXISTS:
ret = 0;
break;
break;
default:
scfdie();
}
}
return (ret);
}
int
{
int ret = 0;
size_t i;
int argc;
char *pattern;
char *prop;
int do_service = 0;
int do_instance = 0;
if (argc < 1)
goto usage;
opterr = 0;
optind = 0;
for (;;) {
if (ret == -1)
break;
switch (ret) {
case 's':
do_service = 1;
break;
case 'i':
do_instance = 1;
break;
case 'm':
break;
case '?':
goto usage;
default:
}
}
if ((do_service && do_instance) ||
goto usage;
if (!isunset)
ret = -1;
goto out;
}
ret = -1;
goto out;
}
ret = -1;
goto out;
}
ret = -1;
goto out;
}
if (do_instance || do_service) {
method = "method_context";
if (!isunset) {
if (ret != 0)
goto out;
}
} else {
int in_instance;
"Couldn't find start method; please "
"specify a method with '-m'.\n"));
ret = -1;
goto out;
}
if (!in_instance)
}
} else {
char *buf;
int ret;
scfdie();
else
if (ret != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
"\"%s\".\n"), method);
goto out;
method);
goto out;
default:
scfdie();
}
}
"\"method\".\n"), method);
ret = -1;
goto out;
}
}
}
out:
return (ret);
ret = -2;
goto out;
}
/*
* Snapshot commands
*/
void
{
char *nb;
int r;
return;
}
scfdie();
scfdie();
scfdie();
}
if (r < 0)
scfdie();
}
void
lscf_selectsnap(const char *name)
{
return;
}
char *cur_snap_name;
max_scf_name_len + 1) < 0)
scfdie();
if (nochange)
return;
}
}
return;
scfdie();
SCF_SUCCESS) {
switch (scf_error()) {
break;
case SCF_ERROR_NOT_FOUND:
break;
default:
scfdie();
}
return;
}
/* Load the snaplevels into our list. */
if (cur_levels == NULL)
uu_strerror(uu_error()));
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
return;
}
for (;;) {
uu_strerror(uu_error()));
scfdie();
level) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
break;
}
}
}
/*
* Copies the properties & values in src to dst. Assumes src won't change.
* Returns -1 if permission is denied, -2 if another transaction interrupts,
* and 0 on success.
*
* If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
* property, if it is copied and has type boolean. (See comment in
* lscf_revert()).
*/
static int
{
scf_value_t *v;
char *nbuf;
int r;
scfdie();
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
return (-1);
}
scfdie();
scfdie();
for (;;) {
if (r == -1)
scfdie();
if (r == 0)
break;
e = scf_entry_create(g_hndl);
if (e == NULL)
scfdie();
scfdie();
scfdie();
ty) != SCF_SUCCESS)
scfdie();
ty == SCF_TYPE_BOOLEAN) {
v = scf_value_create(g_hndl);
if (v == NULL)
scfdie();
if (scf_entry_add_value(e, v) != 0)
scfdie();
} else {
scfdie();
for (;;) {
v = scf_value_create(g_hndl);
if (v == NULL)
scfdie();
r = scf_iter_next_value(viter, v);
if (r == -1)
scfdie();
if (r == 0) {
break;
}
if (scf_entry_add_value(e, v) != SCF_SUCCESS)
scfdie();
}
}
}
r = scf_transaction_commit(tx);
scfdie();
switch (r) {
case 1: return (0);
case 0: return (-2);
case -1: return (-1);
default:
abort();
}
/* NOTREACHED */
}
void
lscf_revert(const char *snapname)
{
return;
}
scfdie();
SCF_SUCCESS) {
switch (scf_error()) {
"\"%s\".\n"), snapname);
break;
case SCF_ERROR_NOT_FOUND:
break;
default:
scfdie();
}
return;
}
} else {
} else {
return;
}
}
scfdie();
/* Take the "previous" snapshot before we blow away the properties. */
scfdie();
} else {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
scfdie();
}
enabled = 2;
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
goto out;
}
for (;;) {
int r;
/* Clear the properties from the corresponding entity. */
if (!isinst)
else
if (r != SCF_SUCCESS)
scfdie();
scfdie();
/* Skip nonpersistent pgs. */
if (flags & SCF_PG_FLAG_NONPERSISTENT)
continue;
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
goto out;
}
}
if (r == -1)
scfdie();
/* Copy the properties to the corresponding entity. */
scfdie();
scfdie();
0)
scfdie();
scfdie();
if (!isinst)
else
if (r != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
goto out;
}
else
switch (r) {
case 0:
break;
case -1:
goto out;
case -2:
"Interrupted by another change.\n"));
goto out;
default:
abort();
}
}
if (r == -1)
scfdie();
/* Get next level. */
scfdie();
SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
break;
}
}
}
out:
}
#ifndef NATIVE_BUILD
/* ARGSUSED */
{
int word_start, err = 0, r;
char *buf;
return (0);
return (0);
return (0);
scfdie();
scfdie();
for (;;) {
if (r == 0)
break;
if (r != 1)
scfdie();
max_scf_name_len + 1) < 0)
scfdie();
if (err != 0)
break;
}
}
return (err);
} else {
scfdie();
scfdie();
for (;;) {
if (r == 0)
break;
if (r != 1)
scfdie();
max_scf_name_len + 1) < 0)
scfdie();
if (err != 0)
break;
}
}
return (err);
}
}
/* ARGSUSED */
{
else
}
#endif /* NATIVE_BUILD */