svccfg_libscf.c revision a6490d0f4f068b0e0b17b98d03e50301aa6bb3f4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2015 Joyent, Inc.
* Copyright 2012 Milan Jurik. All rights reserved.
*/
#include <alloca.h>
#include <assert.h>
#include <ctype.h>
#include <door.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <inttypes.h>
#include <libintl.h>
#include <libnvpair.h>
#include <libscf.h>
#include <libscf_priv.h>
#include <libtecla.h>
#include <libuutil.h>
#include <limits.h>
#include <locale.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include <wait.h>
#include <poll.h>
#include "svccfg.h"
#include "notify_params.h"
#include "manifest_hash.h"
#include "manifest_find.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"
/*
* Indentation used in the output of the describe subcommand.
*/
#define TMPL_VALUE_INDENT " "
#define TMPL_INDENT " "
#define TMPL_INDENT_2X " "
#define TMPL_CHOICE_INDENT " "
/*
* Directory locations for manifests
*/
#define VARSVC_DIR "/var/svc/manifest"
#define LIBSVC_DIR "/lib/svc/manifest"
#define VARSVC_PR "var_svc_manifest"
#define LIBSVC_PR "lib_svc_manifest"
#define MFSTFILEPR "manifestfile"
#define SUPPORTPROP "support"
#define MFSTHISTFILE "/lib/svc/share/mfsthistory"
#define MFSTFILE_MAX 16
/*
* 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 {
};
/*
* Likewise for type (for notification parameters) elements.
*/
struct params_elts {
};
/*
* This structure is for snaplevel lists. They are convenient because libscf
* only allows traversing snaplevels in one direction.
*/
struct snaplevel {
};
/*
* This is used for communication between lscf_service_export and
* export_callback.
*/
struct export_args {
const char *filename;
int flags;
};
/*
* The service_manifest structure is used by the upgrade process
* to create a list of service to manifest linkages from the manifests
* in a set of given directories.
*/
typedef struct service_manifest {
const char *servicename;
/*
* Structure to track the manifest file property group
* and the manifest file associated with that property
* group. Also, a flag to keep the access once it has
* been checked.
*/
struct mpg_mfile {
char *mpg;
char *mfile;
int access;
};
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_invalid_for_snapshot;
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 = 0;
static int no_refresh = 0;
/* how long in ns we should wait between checks for a pg */
/* 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;
/* cleanup globals */
static char *start_method_names[] = {
"start",
"inetd_start",
};
static struct uri_scheme {
const char *scheme;
const char *protocol;
} uri_scheme[] = {
{ "mailto", "smtp" },
{ "snmp", "snmp" },
{ "syslog", "syslog" },
};
#define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
sizeof (struct uri_scheme)) - 1)
static int
check_uri_scheme(const char *scheme)
{
int i;
return (i);
}
return (-1);
}
static int
check_uri_protocol(const char *p)
{
int i;
return (i);
}
return (-1);
}
/*
* For unexpected libscf errors.
*/
#ifdef NDEBUG
static void scfdie(void) __NORETURN;
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
}
static int
{
int ret;
else
return (ret);
}
/*
* 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
{
}
/*
* Repository file does not exist
* or has no read permission.
*/
} else {
}
}
void
{
0 ||
scfdie();
if (max_scf_name_len > max_scf_len)
if (max_scf_pg_type_len > max_scf_len)
/*
* When a value of type opaque is represented as a string, the
* string contains 2 characters for every byte of data. That is
* because the string contains the hex representation of the opaque
* value.
*/
if (atexit(remove_tempfile) != 0)
gettext("Invalid operation on a snapshot.\n");
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.
* Optionally append a comment prefix ('#') to newlines ('\n').
*/
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);
if (err != SCF_ERROR_NOT_FOUND &&
scfdie();
if (g_verbose) {
if (len < 0)
scfdie();
scfdie();
if (err == SCF_ERROR_NOT_FOUND)
"one.\n");
else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
"expected one.\n");
else
}
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);
}
/*
* Create or update a snapshot of inst. snap is a required scratch object.
*
* 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:
case SCF_ERROR_INTERNAL:
bad_error("_scf_snapshot_take_new",
scf_error());
}
}
}
return (0);
}
static int
refresh_running_snapshot(void *entity)
{
int r;
scfdie();
return (r);
}
/*
* 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
* ENOSPC - repository server out of resources
* -1 - _smf_refresh_instance_i() failed. scf_error() should be set.
*/
static int
{
int r;
if (!isservice) {
/*
* Let restarter handles refreshing and making new running
* snapshot only if operating on a live repository and not
* running in early import.
*/
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);
}
} else {
switch (r) {
case 0:
break;
case ECONNABORTED:
case ECANCELED:
case EPERM:
case ENOSPC:
break;
default:
bad_error("refresh_running_snapshot",
scf_error());
}
return (r);
}
}
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());
}
}
/*
* Similarly, just take a new running snapshot if operating on
* a non-live repository or running during early import.
*/
r = refresh_running_snapshot(inst);
switch (r) {
case 0:
continue;
case ECONNABORTED:
case ECANCELED:
case EPERM:
case ENOSPC:
break;
default:
bad_error("refresh_running_snapshot",
scf_error());
}
return (r);
}
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 void
private_refresh(void)
{
char *fmribuf;
void *ent;
int issvc;
int r;
return;
if (cur_inst) {
issvc = 0;
} else {
issvc = 1;
scfdie();
scfdie();
}
if (fmrilen < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
return;
}
switch (r) {
case 0:
break;
case ECONNABORTED:
"(repository connection broken).\n"), fmribuf);
break;
case ECANCELED:
break;
case EPERM:
"(permission denied).\n"), fmribuf);
break;
case ENOSPC:
"(repository server out of resources).\n"),
fmribuf);
break;
case EACCES:
default:
}
if (issvc) {
}
}
static int
{
return (UU_WALK_ERROR);
}
static int
{
}
static int select_inst(const char *);
static int select_svc(const char *);
/*
* Take a property that does not have a type and check to see if a type
* exists or can be gleened from the current data. Set the type.
*
* Check the current level (instance) and then check the higher level
* (service). This could be the case for adding a new property to
* the instance that's going to "override" a service level property.
*
* For a property :
* 1. Take the type from an existing property
* 2. Take the type from a template entry
*
* If the type can not be found, then leave the type as is, and let the import
* report the problem of the missing type.
*/
static int
find_current_prop_type(void *p, void *g)
{
property_t *prop = p;
scf_callback_t *lcb = g;
char *cur_selection = NULL;
int r = UU_WALK_ERROR;
return (UU_WALK_NEXT);
"find a missing type.\n"));
return (UU_WALK_ERROR);
}
max_scf_fmri_len + 1);
} else {
}
} else {
}
"find a missing property type.\n"));
goto out;
}
/*
* If this is the sc_pg from the parent
* let the caller clean up the sc_pg,
* and just throw it away in this case.
*/
"property group to find a property "
"type.\n"));
goto out;
}
/*
* if instance get service and jump back
*/
if (issvc == 0) {
issvc = 1;
goto retry_pg;
} else {
goto out;
}
}
}
} else {
}
/*
* Attempt to get the type from an existing property. If the property
* cannot be found then attempt to get the type from a template entry
* for the property.
*
* Finally, if at the instance level look at the service level.
*/
sc_prop) == SCF_SUCCESS &&
/*
* Found a type, update the value types and validate
* the actual value against this type.
*/
}
r = UU_WALK_NEXT;
goto out;
}
/*
* If we get here with t_pg set to NULL then we had to have
* gotten an sc_pg but that sc_pg did not have the property
* we are looking for. So if the t_pg is not null look up
* the template entry for the property.
*
* If the t_pg is null then need to attempt to get a matching
* template entry for the sc_pg, and see if there is a property
* entry for that template entry.
*/
do_tmpl :
t_prop, 0) == SCF_SUCCESS) {
/*
* Found a type, update the value types and validate
* the actual value against this type.
*/
}
r = UU_WALK_NEXT;
goto out;
}
} else {
"property group to find a property "
"type.\n"));
goto out;
}
} else {
goto do_tmpl;
}
}
}
if (issvc == 0) {
scf_instance_t *i;
scf_service_t *s;
issvc = 1;
goto retry_pg;
}
/*
* because lcb->sc_flags was not set then this means
* the pg was not used and can be used here.
*/
"to find a missing type."));
goto out;
}
max_scf_name_len + 1) < 0)
goto out;
i = scf_instance_create(g_hndl);
s = scf_service_create(g_hndl);
"to find a missing type."));
goto out;
}
/*
* Check to see truly at the instance level.
*/
if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
goto out;
else
goto retry_pg;
}
out :
}
/*
* If this is true then the pg was allocated
* here, and the name was set so need to free
* the name and the pg.
*/
}
if (cur_selection) {
}
if (r != UU_WALK_NEXT)
return (r);
}
/*
* Take a property group that does not have a type and check to see if a type
* exists or can be gleened from the current data. Set the type.
*
* Check the current level (instance) and then check the higher level
* (service). This could be the case for adding a new property to
* the instance that's going to "override" a service level property.
*
* For a property group
* 1. Take the type from an existing property group
* 2. Take the type from a template entry
*
* If the type can not be found, then leave the type as is, and let the import
* report the problem of the missing type.
*/
static int
find_current_pg_type(void *p, void *sori)
{
char *cur_selection = NULL;
int r = UU_WALK_ERROR;
r = UU_WALK_NEXT;
goto out;
}
"and find a missing type.\n"));
return (UU_WALK_ERROR);
}
/*
* via lscf_select. Need to preserve the current selection
*/
if (cur_svc) {
}
/*
* If the property group exists get the type, and set
* the pgroup_t type of that type.
*
* If not the check for a template pg_pattern entry
* and take the type from that.
*/
r = UU_WALK_NEXT;
goto out;
} else {
}
} else {
goto out;
r = UU_WALK_NEXT;
goto out;
}
}
/*
* If type is not found at the instance level then attempt to
* find the type at the service level.
*/
if (!issvc) {
goto retry_svc;
}
out :
if (cur_selection) {
}
/*
* Now walk the properties of the property group to make sure that
* all properties have the correct type and values are valid for
* those types.
*/
if (r == UU_WALK_NEXT) {
} else {
}
&cb, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
r = UU_WALK_ERROR;
}
} else {
}
return (r);
}
/*
* 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) {
goto delete_pg;
}
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:
}
}
if (p->sc_pgroup_delete)
return (UU_WALK_NEXT);
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);
}
/*
* take the snapshot running snapshot then
*/
switch (r) {
case 0:
break;
case ECONNABORTED:
"(repository connection broken).\n"),
return (UU_WALK_ERROR);
case ECANCELED:
return (UU_WALK_ERROR);
case EPERM:
"(permission denied).\n"), snap_running);
return (UU_WALK_ERROR);
case ENOSPC:
"(repository server out of resources).\n"),
return (UU_WALK_ERROR);
default:
bad_error("take_snap", r);
}
if (r != UU_WALK_NEXT) {
if (r != UU_WALK_ERROR)
bad_error("lscf_property_import", r);
return (EINVAL);
}
}
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:
}
break;
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_general = 0;
/*
* If the op is set, then add the flag to the callback
* flags for later use.
*/
case SVCCFG_OP_IMPORT :
break;
case SVCCFG_OP_APPLY :
break;
case SVCCFG_OP_RESTORE :
break;
default :
"Unknown op stored in the service entity\n"));
}
}
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
}
return (0);
}
/*
* 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;
/*
* If the op is set, then add the flag to the callback
* flags for later use.
*/
case SVCCFG_OP_IMPORT :
break;
case SVCCFG_OP_APPLY :
break;
case SVCCFG_OP_RESTORE :
break;
default :
"Unknown op stored in the instance entity\n"));
}
}
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
}
/*
* If importing with the SCI_NOENABLED flag then
* skip the delay, but if not then add the delay
* of the enable property.
*/
}
!= 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. */
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 */
}
}
/*
* Used to add the manifests to the list of currently supported manifests.
* We can modify the existing manifest list removing entries if the files
* don't exist.
*
* Get the old list and the new file name
* If the new file name is in the list return
* If not then add the file to the list.
* As we process the list check to see if the files in the old list exist
* if not then remove the file from the list.
* Commit the list of manifest file names.
*
*/
static int
{
char *pname;
char *fval;
char *old_pname;
char *old_fval;
int no_upgrade_pg;
int mfst_seen;
int r;
/*
* This should always be the service base on the code
* path, and the fact that the manifests pg is a service
* level property group only.
*/
/* Fetch the "manifests" property group */
no_upgrade_pg = 0;
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
no_upgrade_pg = 1;
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());
}
}
if (no_upgrade_pg) {
return (0);
}
/* Fetch the new manifests property group */
mfst_pgroup != NULL;
SCF_PG_MANIFESTFILES) == 0)
break;
}
return (-1);
return (ENOMEM);
return (ENOMEM);
}
mfst_seen = 0;
continue;
mfst_prop)) {
mfst_seen = 1;
}
}
/*
* If the manifest is not seen then add it to the new mfst
* property list to get proccessed into the repo.
*/
if (mfst_seen == 0) {
/*
* If we cannot get the value then there is no
* reason to attempt to attach the value to
* the property group
*/
MAXPATHLEN) != -1) {
/*
* Already checked to see if the property exists
* in the group, and it does not.
*/
(void) internal_attach_property(mfst_pgroup,
old_prop);
}
}
}
return (r);
}
/*
* 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);
case EACCES:
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);
case EACCES:
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)
/*
* If the fmri's are not equal then the old fmri will need to
* be refreshed to ensure that the changes are properly updated
* in that service.
*/
switch (r) {
case 0:
dpt = internal_pgroup_new();
return (ENOMEM);
return (ENOMEM);
uu_strerror(uu_error()));
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);
case EACCES:
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.
*/
if (new_dpt_pgroup->sc_pgroup_override) {
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;
case EACCES:
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);
case EACCES:
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;
case EACCES:
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;
case EACCES:
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);
case EACCES:
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)
* - couldn't read property (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:
case EACCES:
return (r);
default:
bad_error("load_pg", r);
}
switch (r) {
case 0:
break;
case ECANCELED:
case ECONNABORTED:
case ENOMEM:
case EBADF:
case EACCES:
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:
case EACCES:
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:
case EACCES:
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;
}
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_manifestfiles", 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:
case EACCES:
return (r);
default:
bad_error("load_pg", r);
}
}
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 irrelevant, 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:
case SCF_ERROR_INTERNAL:
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);
}
}
goto deltemp;
/* 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);
}
/*
* When an instance is imported we end up telling configd about it. Once we tell
* configd about these changes, startd eventually notices. If this is a new
* instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
* property group. However, many of the other tools expect that this property
* group exists and has certain values.
*
* These values are added asynchronously by startd. We should not return from
* this routine until we can verify that the property group we need is there.
*
* Before we go ahead and verify this, we have to ask ourselves an important
* question: Is the early manifest service currently running? Because if it is
* running and it has invoked us, then the service will never get a restarter
* property because svc.startd is blocked on EMI finishing before it lets itself
* fully connect to svc.configd. Of course, this means that this race condition
* is in fact impossible to 100% eliminate.
*
* svc.startd makes sure that EMI only runs once and has succeeded by checking
* the state of the EMI instance. If it is online it bails out and makes sure
* that it doesn't run again. In this case, we're going to do something similar,
* only if the state is online, then we're going to actually verify. EMI always
* has to be present, but it can be explicitly disabled to reduce the amount of
* damage it can cause. If EMI has been disabled then we no longer have to worry
* about the implicit race condition and can go ahead and check things. If EMI
* is in some state that isn't online or disabled and isn't runinng, then we
* assume that things are rather bad and we're not going to get in your way,
* even if the rest of SMF does.
*
* Returns 0 on success or returns an errno.
*/
#ifndef NATIVE_BUILD
static int
{
char *emi_state;
/*
* smf_get_state does not distinguish between its different failure
* modes: memory allocation failures, SMF internal failures, and a lack
* of EMI entirely because it's been removed. In these cases, we're
* going to be conservative and opt to say that if we don't know, better
* to not block import or falsely warn to the user.
*/
return (0);
}
/*
* As per the block comment for this function check the state of EMI
*/
return (0);
}
/*
* First we have to get the property.
*/
return (ret);
}
/*
* We should always be able to get the instance. It should already
* exist because we just created it or got it. There probably is a
* slim chance that someone may have come in and deleted it though from
* under us.
*/
!= 0) {
switch (ret) {
case SCF_ERROR_DELETED:
break;
err = ECONNABORTED;
break;
case SCF_ERROR_NOT_FOUND:
break;
default:
}
return (err);
}
/*
* An astute observer may want to use _scf_wait_pg which would notify us
* of a property group change, unfortunately that does not work if the
* property group in question does not exist. So instead we have to
* manually poll and ask smf the best way to get to it.
*/
!= SCF_SUCCESS) {
if (ret != SCF_ERROR_NOT_FOUND) {
switch (ret) {
case SCF_ERROR_DELETED:
break;
err = ECONNABORTED;
break;
default:
}
return (err);
}
}
/*
* svcadm also expects that the SCF_PROPERTY_STATE property is present.
* So in addition to the property group being present, we need to wait
* for the property to be there in some form.
*
* Note that a property group is a frozen snapshot in time. To properly
* get beyond this, you have to refresh the property group each time.
*/
imp_prop)) != 0) {
if (ret != SCF_ERROR_NOT_FOUND) {
"restarter property group of instance %s\n"),
switch (ret) {
err = ECONNABORTED;
break;
case SCF_ERROR_DELETED:
break;
default:
}
return (err);
}
if (ret != SCF_SUCCESS) {
switch (ret) {
case SCF_ERROR_DELETED:
break;
err = ECONNABORTED;
break;
default:
}
return (err);
}
}
/*
* We don't have to free the property groups or other values that we got
* because we stored them in global variables that are allocated and
* freed by the routines that call into these functions. Unless of
* course the rest of the code here that we are basing this on is
* mistaken.
*/
return (0);
}
#endif
/*
* 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 = 0;
"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");
const char * const s_mfile_upd =
gettext("Unable to update the manifest file connection "
"for %s\n");
li_only = 0;
/* 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 */
/*
* the size of the buffer was reduced to max_scf_name_len to prevent
* hitting bug 6681151. After the bug fix, the size of the buffer
* should be restored to its original value (max_scf_name_len +1)
*/
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:
if (!retried) {
lscf_delete(imp_tsname, 0);
goto retry;
}
"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:
}
}
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;
/*
* Need to go ahead and import the manifestfiles
* pg if it exists. If the last-import snapshot
* upgrade code is ever removed this code can
* be removed as well.
*/
mfpg = internal_pgroup_find(s,
if (mfpg) {
if (entity_pgroup_import(mfpg,
&mfcbdata) != UU_WALK_NEXT) {
r = UU_WALK_ERROR;
goto deltemp;
}
}
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 ENOSPC:
"(repository server out of resources).\n"),
fmri);
else
"(dependent \"%s\" of %s) "
"(repository server out of resources).\n"),
return (r);
case -1:
scfwarn();
return (r);
default:
bad_error("refresh_entity", r);
}
if (issvc)
else
return (0);
}
static int
{
int r;
const char * const emsg_nores =
if (scf_error() == SCF_ERROR_NO_RESOURCES)
else
return (-1);
}
r = load_init();
switch (r) {
case 0:
break;
case ENOMEM:
return (-1);
default:
bad_error("load_init", r);
}
return (0);
}
static void
{
void *cookie;
load_fini();
NULL) {
}
load_fini();
}
int
{
int result = 0;
int r;
int annotation_set = 0;
const char * const emsg_nores =
if (alloc_imp_globals())
goto out;
switch (scf_error()) {
result = -1;
goto out;
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NOT_BOUND:
default:
}
}
/* Set up the auditing annotation. */
annotation_set = 1;
} else {
switch (scf_error()) {
result = -1;
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_INTERNAL:
/* NOTREACHED */
default:
/*
* Do not terminate import because of inability to
* generate annotation audit event.
*/
"failed with return code of %d\n"), scf_error());
break;
}
}
/*
* 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) {
char *eptr;
/* Success. Refresh everything. */
no_refresh = 0;
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;
/*
* This snippet of code assumes that we are running svccfg as we
* normally do -- witih svc.startd running. Of course, that is
* not actually the case all the time because we also use a
* varient of svc.configd and svccfg which are only meant to
* run during the build process. During this time we have no
* svc.startd, so this check would hang the build process.
*
* However, we've also given other consolidations, a bit of a
* means to tie themselves into a knot. They're not properly
* using the native build equivalents, but they've been getting
* away with it anyways. Therefore, if we've found that
* SVCCFG_REPOSITORY is set indicating that a separate configd
* should be spun up, then we have to assume it's not using a
* startd and we should not do this check.
*/
#ifndef NATIVE_BUILD
/*
* Verify that the restarter group is preset
*/
inst) != 0)
goto progress;
}
}
#endif
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:
if (annotation_set != 0) {
/* Turn off annotation. It is no longer needed. */
}
return (result);
}
/*
* _lscf_import_err() summarize the error handling returned by
* lscf_import_{instance | service}_pgs
* Return values are:
* IMPORT_NEXT
* IMPORT_OUT
* IMPORT_BAD
*/
#define IMPORT_BAD -1
#define IMPORT_NEXT 0
#define IMPORT_OUT 1
static int
{
switch (err) {
case 0:
if (g_verbose)
return (IMPORT_NEXT);
case ECONNABORTED:
"(repository connection broken).\n"), fmri);
return (IMPORT_OUT);
case ENOMEM:
return (IMPORT_OUT);
case ENOSPC:
"(repository server out of resources).\n"), fmri);
return (IMPORT_OUT);
case ECANCELED:
"Could not update %s (deleted).\n"), fmri);
return (IMPORT_NEXT);
case EPERM:
case EINVAL:
case EBUSY:
return (IMPORT_NEXT);
case EROFS:
fmri);
return (IMPORT_OUT);
case EACCES:
"(backend access denied).\n"), fmri);
return (IMPORT_NEXT);
case EEXIST:
default:
return (IMPORT_BAD);
}
/*NOTREACHED*/
}
/*
* The global imp_svc and imp_inst should be set by the caller in the
* check to make sure the service and instance exist that the apply is
* working on.
*/
static int
lscf_dependent_apply(void *dpg, void *e)
{
int tissvc;
int r;
const char * const dependents = "dependents";
if (issvc)
else
imp_prop) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
} else {
/*
* Found the dependents/<wip dep> so check to
* see if the service is different. If so
* store the service for later refresh, and
* delete the wip dependency from the service
*/
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
max_scf_value_len + 1) < 0)
switch (r) {
case 1:
break;
case 0:
&tissvc)) != SCF_ERROR_NONE) {
if (serr == SCF_ERROR_NOT_FOUND) {
break;
} else {
}
}
if (serr == SCF_ERROR_NOT_FOUND ||
serr == SCF_ERROR_DELETED) {
break;
} else {
}
}
if (scf_pg_delete(imp_pg) != 0) {
if (serr == SCF_ERROR_NOT_FOUND ||
serr == SCF_ERROR_DELETED) {
break;
} else {
}
}
return (ENOMEM);
return (ENOMEM);
deldpt) != 0)
uu_strerror(uu_error()));
break;
default:
bad_error("fmri_equal", r);
}
}
return (UU_WALK_ERROR);
switch (r) {
case 0:
break;
case ENOMEM:
case ECONNABORTED:
case EPERM:
case -1:
return (UU_WALK_ERROR);
default:
bad_error("imp_refresh_fmri", r);
}
return (UU_WALK_NEXT);
}
/*
* Returns
* 0 - success
* -1 - lscf_import_instance_pgs() failed.
*/
int
{
int annotation_set = 0;
int ret = 0;
int r = 0;
if ((ret = alloc_imp_globals()))
goto out;
scfdie();
/*
* Set the strings to be used for the security audit annotation
* event.
*/
annotation_set = 1;
} else {
switch (scf_error()) {
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_INTERNAL:
/* NOTREACHED */
default:
/*
* Do not abort apply operation because of
* inability to create annotation audit event.
*/
"failed with return code of %d\n"), scf_error());
break;
}
}
int refresh = 0;
imp_svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
if (g_verbose)
continue;
default:
scfdie();
}
}
/*
* If there were missing types in the profile, then need to
* attempt to find the types.
*/
if (svc->sc_miss_type) {
svc, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
ret = -1;
continue;
}
for (inst = uu_list_first(
inst = uu_list_next(
/*
* If the instance doesn't exist just
* skip to the next instance and let the
* import note the missing instance.
*/
continue;
UU_DEFAULT) != 0) {
if (uu_error() !=
bad_error("uu_list_walk",
uu_error());
ret = -1;
}
}
}
/*
* if we have pgs in the profile, we need to refresh ALL
* instances of the service
*/
refresh = 1;
case IMPORT_NEXT:
break;
case IMPORT_OUT:
goto out;
case IMPORT_BAD:
default:
bad_error("lscf_import_service_pgs", r);
}
}
}
for (inst = uu_list_first(
inst = uu_list_next(
/*
* This instance still has missing types
* so skip it.
*/
if (inst->sc_miss_type) {
if (g_verbose)
"%s:%s with missing types\n"),
continue;
}
imp_inst) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
if (g_verbose)
"nonexistant instance "
"%s:%s.\n"),
continue;
default:
scfdie();
}
}
/*
* property and no last-import snapshot then the
* instance is not a fully installed instance and
* should not have a profile applied to it.
*
*
*/
imp_snap) != 0) {
SCF_PG_GENERAL, imp_pg) != 0 ||
SCF_PROPERTY_ENABLED, imp_prop) != 0) {
if (g_verbose)
"partial instance "
"%s:%s.\n"),
continue;
}
}
case IMPORT_NEXT:
break;
case IMPORT_OUT:
goto out;
case IMPORT_BAD:
default:
bad_error("lscf_import_instance_pgs", r);
}
}
/* refresh only if there is no pgs in the service */
if (refresh == 0)
(void) refresh_entity(0, imp_inst,
}
if (refresh == 1) {
}
}
}
}
out:
if (annotation_set) {
/* Remove security audit annotation strings. */
}
return (ret);
}
/*
* 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;
scf_error_t err = 0;
char *lnname;
int ret;
/* name */
} else {
scfdie();
}
/* type */
exp_str);
/* If we're exporting values, and there's just one, export it here. */
if (!(flags & SCE_ALL_VALUES))
goto empty;
xmlNodePtr n;
/* Single value, so use propval */
if (n == NULL)
scfdie();
else
return;
}
if (err == SCF_ERROR_PERMISSION_DENIED) {
return;
}
if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
err != SCF_ERROR_NOT_FOUND &&
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();
/*
* If this property group is not read protected, we always want to
* output all the values. Otherwise, we only output the values if the
*/
scfdie();
if (!read_protected)
flags |= SCE_ALL_VALUES;
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) {
0 &&
"working_directory", ":default") != 0)
err = 1;
":default") != 0)
err = 1;
0 &&
"resource_pool", ":default") != 0)
err = 1;
/*
* We only want to complain about profile or credential
* properties if we will use them. To determine that we must
* examine USE_PROFILE.
*/
SCF_SUCCESS) {
scfdie();
}
if (use_profile) {
exp_prop) != 0 ||
name_attr) != 0)
err = 1;
} else {
exp_prop) != 0 ||
"user") != 0) {
err = 1;
}
exp_prop) == 0 &&
"group", ":default") != 0)
err = 1;
exp_prop) == 0 &&
"supp_groups", ":default") != 0)
err = 1;
exp_prop) == 0 &&
"privileges", ":default") != 0)
err = 1;
if (pg_get_prop(pg,
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. */
scfdie();
if (use_profile)
prof =
NULL);
else
cred =
NULL);
}
(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 parameter and paramval elements
*/
static void
struct params_elts *elts)
{
scf_error_t err = 0;
int ret;
scfdie();
else
return;
}
if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
scfdie();
if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
scfdie();
1) {
exp_str_sz) < 0)
scfdie();
}
if (ret != 0)
scfdie();
}
else
}
/*
* Process notification parameters for a service or instance
*/
static void
{
struct params_elts *eelts;
/* event value */
scfdie();
(void) xmlAddChild(n, event);
sizeof (struct params_elts))) == NULL)
err = 0;
scfdie();
char *t, *p;
scfdie();
/*
* this is not a well formed notification parameters
* element, we should export as regular pg
*/
err = 1;
break;
}
if ((i = check_uri_protocol(t)) < 0) {
err = 1;
break;
}
NULL)
}
if (strcmp(p, active_attr) == 0) {
active_attr) != 0) {
err = 1;
break;
}
continue;
}
/*
* We export the parameter
*/
}
if (ret == -1)
scfdie();
if (err == 1) {
for (i = 0; i < URI_SCHEME_NUM; ++i)
return;
} else {
for (i = 0; i < URI_SCHEME_NUM; ++i)
(void) xmlAddChildList(type[i],
(void) xmlAddChildList(type[i],
}
}
elts->notify_params = n;
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 (pgflags & SCF_PG_FLAG_NONPERSISTENT)
continue;
scfdie();
continue;
continue;
max_scf_name_len + 1) < 0)
scfdie();
continue;
0) {
continue;
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 (pgflags & SCF_PG_FLAG_NONPERSISTENT)
continue;
scfdie();
continue;
continue;
max_scf_name_len + 1) < 0)
scfdie();
continue;
0) {
continue;
continue;
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)
else
}
} 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
{
struct export_args args;
char *fmridup;
/*
* If some poor user has passed an exact instance FMRI, of the sort
* one might cut and paste from svcs(1) or an error message, warn
* and chop off the instance instead of failing.
*/
sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
}
"instance portion of argument.\n"));
}
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
make_archive(int flags)
{
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
{
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);
}
static int
{
return (0);
}
/*
* validate [fmri]
* Perform the validation of an FMRI instance.
*/
void
lscf_validate_fmri(const char *fmri)
{
int ret = 0;
max_scf_name_len + 1) < 0)
scfdie();
}
goto cleanup;
/* sanity check. Should never get here */
}
} else {
int err = 0;
uu_warn("Failed to walk instances: %s\n",
goto cleanup;
}
if (err != 0) {
/* error message displayed by scf_walk_fmri */
goto cleanup;
}
}
if (ret == -1) {
if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
"Consider reverting to a previous snapshot or "
"restoring original configuration.\n"), inst_fmri);
} else {
uu_warn("%s: %s\n",
gettext("Error validating the instance"),
scf_strerror(scf_error()));
}
char *msg;
int ret;
"Out of memory.\n"));
flag);
}
}
}
}
static void
lscf_validate_file(const char *filename)
{
bundle_t *b = internal_bundle_new();
}
}
(void) internal_bundle_free(b);
}
/*
* validate [fmri|file]
*/
void
lscf_validate(const char *arg)
{
const char *str;
sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
} else {
}
}
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();
}
}
}
}
/* return 1 if the entity has no persistent pgs, else return 0 */
static int
{
int err;
int ret = 1;
scfdie();
if (isservice) {
scfdie();
} else {
scfdie();
}
scfdie();
/* skip nonpersistent pgs */
if (flags & SCF_PG_FLAG_NONPERSISTENT)
continue;
ret = 0;
break;
}
if (err == -1)
scfdie();
return (ret);
}
/* return 1 if the service has no instances, else return 0 */
static int
{
int r;
int ret = 1;
scfdie();
scfdie();
if (r == 1) {
ret = 0;
} else if (r == 0) {
ret = 1;
} else if (r == -1) {
scfdie();
} else {
bad_error("scf_iter_next_instance", r);
}
return (ret);
}
/*
* 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 (result != SCF_ERROR_PERMISSION_DENIED)
scfdie();
goto out;
}
/*
* We have to handle the case where we've just deleted the last
* property group of a "dummy" entity (instance or service).
* A "dummy" entity is an entity only present to hold an
* external dependency.
* So, in the case we deleted the last property group then we
* can also delete the entity. If the entity is an instance then
* we must verify if this was the last instance for the service
* and if it is, we can also delete the service if it doesn't
* have any property group either.
*/
if (isservice) {
scfdie();
} else {
}
/*
* If the entity is an instance and we've just deleted its last
* property group then we should delete it.
*/
/* find the service before deleting the inst. - needed later */
scfdie();
scfdie();
/* delete the instance */
if (scf_instance_delete(inst) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
goto out;
}
/* no need to refresh the instance */
}
/*
* If the service has no more instances and pgs or we just deleted the
* last instance and the service doesn't have anymore propery groups
* then the service should be deleted.
*/
svc_has_no_insts(svc) &&
if (scf_service_delete(svc) == 0) {
if (isservice) {
/* no need to refresh the service */
}
goto out;
}
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
}
/* if the entity has not been deleted, refresh it */
name_buf);
}
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 uint8_t
{
char *type;
scfdie();
scfdie();
scfdie();
if (scf_value_get_boolean(val, &b) != 0)
scfdie();
}
}
(void) scf_value_destroy(val);
(void) scf_property_destroy(prop);
return (b);
}
#define DELETE_FAILURE -1
#define DELETE_SUCCESS_NOEXTDEPS 0
#define DELETE_SUCCESS_EXTDEPS 1
/*
* lscf_instance_delete() deletes an instance. Before calling
* scf_instance_delete(), though, we make sure the instance isn't
* running and delete dependencies in other entities which the instance
* declared as "dependents". If there are dependencies which were
* created for other entities, then instead of deleting the instance we
* make it "empty" by deleting all other property groups and all
* snapshots.
*
* lscf_instance_delete() verifies that there is no external dependency pgs
* before suppressing the instance. If there is, then we must not remove them
* now in case the instance is re-created otherwise the dependencies would be
* lost. The external dependency pgs will be removed if the dependencies are
* removed.
*
* Returns:
* DELETE_FAILURE on failure
* DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
* DELETE_SUCCESS_EXTDEPS on success - external dependencies
*/
static int
{
int err;
int external = 0;
/* If we're not forcing and the instance is running, refuse. */
char *fmri;
scfdie();
"Use delete -f if it is not.\n"), fmri);
return (DELETE_FAILURE);
}
scfdie();
(void) delete_dependents(pg);
else if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
/*
* If the instance has some external dependencies then we must
* keep them in case the instance is reimported otherwise the
* dependencies would be lost on reimport.
*/
scfdie();
scfdie();
if (pg_is_external_dependency(pg)) {
external = 1;
continue;
}
if (scf_pg_delete(pg) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
else {
(void) scf_iter_destroy(iter);
(void) scf_pg_destroy(pg);
return (DELETE_FAILURE);
}
}
}
if (err == -1)
scfdie();
(void) scf_iter_destroy(iter);
(void) scf_pg_destroy(pg);
if (external) {
/*
* All the pgs have been deleted for the instance except
* the ones holding the external dependencies.
* For the job to be complete, we must also delete the
* snapshots associated with the instance.
*/
NULL)
scfdie();
scfdie();
scfdie();
if (_scf_snapshot_delete(snap) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
(void) scf_iter_destroy(iter);
(void) scf_snapshot_destroy(snap);
return (DELETE_FAILURE);
}
}
if (err == -1)
scfdie();
(void) scf_iter_destroy(iter);
(void) scf_snapshot_destroy(snap);
return (DELETE_SUCCESS_EXTDEPS);
}
if (scf_instance_delete(inst) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
return (DELETE_FAILURE);
}
return (DELETE_SUCCESS_NOEXTDEPS);
}
/*
* lscf_service_delete() deletes a service. Before calling
* scf_service_delete(), though, we call lscf_instance_delete() for
* each of the instances and delete dependencies in other entities
* which were created as "dependents" of this service. If there are
* dependencies which were created for other entities, then we delete
* all other property groups in the service and leave it as "empty".
*
* lscf_service_delete() verifies that there is no external dependency
* pgs at the instance & service level before suppressing the service.
* If there is, then we must not remove them now in case the service
* is re-imported otherwise the dependencies would be lost. The external
* dependency pgs will be removed if the dependencies are removed.
*
* Returns:
* DELETE_FAILURE on failure
* DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies
* DELETE_SUCCESS_EXTDEPS on success - external dependencies
*/
static int
{
int r;
int ret;
int external = 0;
scfdie();
scfdie();
r == 1;
if (ret == DELETE_FAILURE) {
return (DELETE_FAILURE);
}
/*
* Record the fact that there is some external dependencies
* at the instance level.
*/
if (ret == DELETE_SUCCESS_EXTDEPS)
external |= 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 the service has some external dependencies then we don't
* want to remove them in case the service is re-imported.
*/
scfdie();
scfdie();
if (pg_is_external_dependency(pg)) {
external |= 2;
continue;
}
if (scf_pg_delete(pg) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
else {
(void) scf_iter_destroy(iter);
(void) scf_pg_destroy(pg);
return (DELETE_FAILURE);
}
}
}
if (r == -1)
scfdie();
(void) scf_iter_destroy(iter);
(void) scf_pg_destroy(pg);
if (external != 0)
return (DELETE_SUCCESS_EXTDEPS);
if (scf_service_delete(svc) == 0)
return (DELETE_SUCCESS_NOEXTDEPS);
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
return (DELETE_FAILURE);
}
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 {
}
}
scfdie();
}
/*
* Outputs template property group info for the describe subcommand.
* If 'templates' == 2, verbose output is printed in the format expected
* for describe -v, which includes all templates fields. If pg is
* not NULL, we're describing the template data, not an existing property
* group, and formatting should be appropriate for describe -t.
*/
static void
{
char *buf;
if (templates == 0)
return;
scfdie();
stability_prop) == 0) {
SCF_TYPE_ASTRING) == 0 &&
char *stability;
scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
}
} else if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
}
return;
/* print type info only if scf_tmpl_pg_name succeeds */
}
/* print type info only if scf_tmpl_pg_type succeeds */
}
}
buf);
}
buf);
}
if (templates == 2)
else
}
}
/*
* With as_value set to true, indent as appropriate for the value level.
* If false, indent to appropriate level for inclusion in constraint
* or choice printout.
*/
static void
int as_value)
{
char *buf;
if (as_value == 0)
else
}
if (as_value == 0)
else
}
}
static void
{
/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
}
static void
{
int i, printed = 0;
printed = 0;
i = 0;
gettext("value constraints"));
printed++;
for (i = 0; i < values.value_count; ++i) {
if (verbose == 1)
values.values_as_strings[i], 0);
}
}
if (printed++ == 0)
gettext("value constraints"));
for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
}
} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
if (printed++ == 0)
gettext("value constraints"));
for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
}
}
}
static void
{
int i = 0, printed = 0;
printed = 0;
gettext("value constraints"));
printed++;
for (i = 0; i < values.value_count; i++) {
if (verbose == 1)
values.values_as_strings[i], 0);
}
}
for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
if (printed++ == 0)
gettext("value choices"));
}
} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
if (printed++ == 0)
gettext("value choices"));
}
}
}
static void
{
}
static void
{
char *val_buf;
int ret;
scfdie();
scfdie();
max_scf_value_len + 1) < 0)
scfdie();
}
scfdie();
}
/*
* Outputs property info for the describe subcommand
* Verbose output if templates == 2, -v option of svccfg describe
* Displays template data if prop is not NULL, -t option of svccfg describe
*/
static void
{
char *buf;
int i;
return;
} else
}
else
} else
}
buf);
}
buf);
}
}
if (max == ULLONG_MAX) {
gettext("maximum number of values"),
gettext("unlimited"));
} else {
}
}
for (i = 0; i < values.value_count; i++) {
if (i == 0) {
gettext("internal separators"));
}
}
safe_printf("\n");
}
if (templates != 2)
return;
else
}
static char *
{
char *rv;
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
default:
scfdie();
}
}
return (rv);
}
static void
{
char *pg_name;
int rv;
scfdie();
}
/* Display doc_link and and uri */
gettext("doc_link"));
}
}
man_len) == 0) {
/* Display manpage title, section and path */
gettext("manpage"));
}
}
}
}
}
if (rv == -1)
scfdie();
done:
}
static void
{
char *common_name = NULL;
char *description = NULL;
int r;
scfdie();
/* Try both the current locale and the "C" locale. */
(scf_error() == SCF_ERROR_NOT_FOUND &&
}
}
}
/*
* Do description, manpages, and doc links if templates == 2.
*/
if (templates == 2) {
/* Get the description. */
/* Try both the current locale and the "C" locale. */
(scf_error() == SCF_ERROR_NOT_FOUND &&
gettext("description"),
}
}
}
/* Process doc_link & manpage elements. */
} else {
}
if (r == 0) {
}
}
}
static void
{
char *fmribuf;
char *qual_prop_name;
char *search_name;
int listed = 0;
scfdie();
max_scf_name_len + 1) < 0)
scfdie();
}
max_scf_name_len + 1) < 0)
scfdie();
max_scf_name_len + 1) < 0)
scfdie();
} else
abort();
/* If pattern is specified, we want to list only those items. */
listed = 0;
listed++;
}
search_name = NULL;
if (snprintf(qual_prop_name,
max_scf_name_len + 1) {
prop_name_size = -1;
} else {
}
}
(prop_name_size > 0 &&
FNM_PATHNAME) == 0))
}
}
}
}
}
static void
{
void **objects;
char **names;
void **tmpls;
int allocd, i;
int ret;
return;
}
scfdie();
else
if (ret != 0) {
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, and their templates in objects,
* names, and tmpls, 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;
int print_props = 0;
if (pgnlen < 0)
scfdie();
if (szret < 0)
scfdie();
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
} else {
}
if (i+1 >= allocd) {
allocd *= 2;
names =
}
else
++i;
new_pg = 1;
print_props = 1;
}
if (only_pgs) {
if (new_pg) {
scfdie();
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;
"Out of memory"));
}
prt, 0) < 0) {
if (scf_error() !=
scfdie();
} else {
}
} else {
}
++i;
} else {
}
}
if (new_pg) {
scfdie();
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;
}
}
/*
* scf_delhash() is used to remove the property group related to the
* hash entry for a specific manifest in the repository. pgname will be
* constructed from the location of the manifest file. If deathrow isn't 0,
* manifest file doesn't need to exist (manifest string will be used as
* an absolute path).
*/
void
{
char *pgname;
return;
}
/*
* Translate the manifest file name to property name. In the deathrow
* case, the manifest file does not need to exist.
*/
return;
}
/* delete the hash property name */
}
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) {
/* Infer the type, if possible. */
/*
* First check if we're an instance and the
* property is set on the service.
*/
svc) == 0 &&
parent_pg) == 0 &&
parent_prop) == 0 &&
¤t_ty) == 0) {
ty = current_ty;
/* Then check for a type set in a template. */
0) == 0 &&
0) == 0 &&
ty = current_ty;
/* If type can't be inferred, fail. */
} else {
"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;
}
ret = 0;
goto cleanup;
fail:
ret = -1;
return (ret);
}
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();
} else {
}
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();
} else {
}
}
/*
* 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;
int is_str;
max_scf_name_len + 1) < 0)
scfdie();
scfdie();
< 0) {
result = -1;
goto out;
}
scfdie();
char *buf;
if (buflen < 0)
scfdie();
buflen + 1) < 0)
scfdie();
if (first)
first = 0;
else {
result = -1;
goto out;
}
}
result = -1;
goto out;
}
} else {
result = -1;
goto out;
}
}
}
if (ret3 < 0 &&
scfdie();
/* Write closing paren if mult-value property */
/* Write final newline */
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()));
}
static int
{
/*
* Find the element that needs to be removed.
*/
break;
}
/*
* Returning 1 here as the value was not found, this
* might not be an error. Leave it to the caller to
* decide.
*/
return (1);
}
return (0);
}
/*
* 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:
}
void
lscf_refresh(void)
{
char *fmribuf;
int r;
return;
}
if (fmrilen < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
return;
}
switch (r) {
case 0:
break;
case ECONNABORTED:
"(repository connection broken).\n"), fmribuf);
break;
case ECANCELED:
break;
case EPERM:
"(permission denied).\n"), fmribuf);
break;
case ENOSPC:
"(repository server out of resources).\n"),
fmribuf);
break;
case EACCES:
default:
}
}
/*
*/
int
{
int ret = 0;
size_t i;
int argc;
int do_verbose = 0;
int do_templates = 0;
if (hasargs != 0) {
if (argc < 1)
goto usage;
/*
* We start optind = 0 because our list of arguments
* starts at argv[0]
*/
optind = 0;
opterr = 0;
for (;;) {
if (ret == -1)
break;
switch (ret) {
case 'v':
do_verbose = 1;
break;
case 't':
do_templates = 1;
break;
case '?':
goto usage;
default:
}
}
}
ret = -1;
goto out;
}
/*
* list_entity_tmpl(), listprop() and listtmpl() produce verbose
* output if their last parameter is set to 2. Less information is
* produced if the parameter is set to 1.
*/
if (do_verbose == 1)
list_entity_tmpl(2);
else
list_entity_tmpl(1);
}
if (do_templates == 0) {
if (do_verbose == 1)
else
} else {
if (do_verbose == 1)
else
}
ret = 0;
out:
return (ret);
ret = -2;
goto out;
}
#define PARAM_ACTIVE ((const char *) "active")
#define PARAM_INACTIVE ((const char *) "inactive")
#define PARAM_SMTP_TO ((const char *) "to")
/*
* tokenize()
* Breaks down the string according to the tokens passed.
* Caller is responsible for freeing array of pointers returned.
* Returns NULL on failure
*/
char **
{
char **buf;
int n = 0; /* number of elements */
if (n + 1 >= size) {
size *= 2;
NULL) {
}
}
}
/* NULL terminate the pointer array */
return (buf);
}
check_tokens(char **p)
{
while (*p) {
int32_t t = string_to_tset(*p);
if (t == 0) {
if (is_fma_token(*p) == 0)
return (INVALID_TOKENS);
} else {
smf |= t;
}
return (MIXED_TOKENS);
++p;
}
if (smf > 0)
return (smf);
else if (fma == 1)
return (FMA_TOKENS);
return (INVALID_TOKENS);
}
static int
{
return (-1);
return (-1);
} else {
}
return (0);
}
void
{
char **pgs;
char **p;
if (global) {
goto out;
}
tset) != SCF_SUCCESS) {
scf_strerror(scf_error()));
}
} else if (tset == FMA_TOKENS) {
if (global) {
"definitions\n"));
goto out;
}
for (p = pgs; *p; ++p) {
SCF_SUCCESS) {
scf_strerror(scf_error()));
goto out;
}
}
} else if (tset == MIXED_TOKENS) {
goto out;
} else {
}
out:
}
void
{
char **pgs;
char **p;
if (global) {
goto out;
}
SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND &&
scf_error() != SCF_ERROR_DELETED)
"Failed listnotify: %s\n"),
scf_strerror(scf_error()));
goto out;
}
} else if (tset == FMA_TOKENS) {
if (global) {
"definitions\n"));
goto out;
}
for (p = pgs; *p; ++p) {
SCF_SUCCESS) {
/*
* if the preferences have just been deleted
* or does not exist, just skip.
*/
if (scf_error() == SCF_ERROR_NOT_FOUND ||
scf_error() == SCF_ERROR_DELETED)
continue;
"Failed listnotify: %s\n"),
scf_strerror(scf_error()));
goto out;
}
}
} else if (tset == MIXED_TOKENS) {
goto out;
} else {
}
out:
}
static char *
strip_quotes_and_blanks(char *s)
{
char *start = s;
start = s + 1;
start++;
end--;
}
*end = '\0';
}
return (start);
}
static int
{
boolean_t b;
b = B_TRUE;
b = B_FALSE;
} else {
return (-1);
}
return (0);
}
static int
{
}
static int
{
}
/*
* add_mailto_paramas()
* parse the hier_part of mailto URI
* mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
* or mailto:{[active]|inactive}
*/
static int
{
const char *tok = "?&";
char *p;
char *lasts;
char *param;
char *val;
/*
* If the notification parametes are in the form of
*
* malito:{[active]|inactive}
*
* we set the property accordingly and return.
* Otherwise, we make the notification type active and
* process the hier_part.
*/
return (0);
return (-1);
/*
* sanity check: we only get here if hier_part = "", but
* that's handled by set_active
*/
uu_die("strtok_r");
}
return (0);
}
static int
{
int r = -1;
return (r);
}
if ((r = check_uri_scheme(*scheme)) < 0) {
return (r);
}
return (r);
}
static int
{
char *scheme;
char *hier_part;
int index;
int r;
return (-1);
switch (index) {
case 0:
/* error messages displayed by called function */
break;
case 1:
break;
case 2:
break;
default:
r = -1;
}
mech) != 0)
return (r);
}
static int
{
char *uri;
if (p == NULL)
/* sanity check */
uu_die("set_params");
while (*p) {
uri = strip_quotes_and_blanks(*p);
return (-1);
++p;
}
return (0);
}
static int
{
char *str = safe_strdup(e);
char **events;
int r = -1;
SCF_NOTIFY_PARAMS_VERSION) != 0)
/* SMF state transitions parameters */
if (global) {
goto out;
}
if ((r = set_params(params, p)) == 0) {
params) != 0)
nvl) != SCF_SUCCESS) {
r = -1;
"Failed smf_notify_set_params(3SCF): %s\n"),
scf_strerror(scf_error()));
}
}
} else if (tset == FMA_TOKENS) {
/* FMA event parameters */
if (global) {
"definitions\n"));
goto out;
}
if ((r = set_params(params, p)) != 0)
goto out;
while (*events) {
"Failed smf_notify_set_params(3SCF) for "
"event %s: %s\n"), *events,
scf_strerror(scf_error()));
events++;
}
} else if (tset == MIXED_TOKENS) {
} else {
/* Sanity check */
}
out:
return (r);
}
int
{
int argc;
int global;
char *events;
char **p;
int i;
int ret;
goto usage;
global = 1;
p = argv + 2;
} else {
global = 0;
p = argv + 1;
}
out:
return (ret);
ret = -2;
goto out;
}
/*
* Creates a list of instance name strings associated with a service. If
* wohandcrafted flag is set, get only instances that have a last-import
* snapshot, instances that were imported via svccfg.
*/
static uu_list_t *
{
char *instname;
int r;
scfdie();
}
return (instances);
switch (scf_error()) {
case SCF_ERROR_DELETED:
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
}
}
if (r == -1) {
"instances to create instance list : %s\n"),
scf_strerror(scf_error()));
goto out;
}
/*
* If the instance does not have a last-import snapshot
* then do not add it to the list as it is a hand-crafted
* instance that should not be managed.
*/
if (wohandcrafted) {
"entity\n"));
scfdie();
}
snap_lastimport, snap) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND :
case SCF_ERROR_DELETED:
continue;
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances",
scf_error());
}
}
}
max_scf_name_len + 1) < 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND :
continue;
case SCF_ERROR_DELETED:
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances",
scf_error());
}
}
}
out:
if (snap)
return (instances);
}
/*
* disable an instance but wait for the instance to
* move out of the running state.
*
* Returns 0 : if the instance did not disable
* Returns non-zero : if the instance disabled.
*
*/
static int
{
char *fmribuf;
int enabled = 10000;
if (inst_is_running(instance)) {
max_scf_name_len + 1) < 0) {
return (0);
}
/*
* If the instance cannot be disabled then return
* failure to disable and let the caller decide
* if that is of importance.
*/
if (smf_disable_instance(fmribuf, 0) != 0) {
return (0);
}
while (enabled) {
if (!inst_is_running(instance))
break;
}
}
return (enabled);
}
/*
* Function to compare two service_manifest structures.
*/
/* ARGSUSED2 */
static int
{
int rc;
return (rc);
}
/*
* Look for the provided service in the service to manifest
* tree. If the service exists, and a manifest was provided
* then add the manifest to that service. If the service
* does not exist, then add the service and manifest to the
* list.
*
* If the manifest is NULL, return the element if found. If
* the service is not found return NULL.
*/
{
if (mfst) {
if (fnelem) {
} else {
}
}
return (fnelem);
}
/*
* Create the service to manifest avl tree.
*
* Walk each of the manifests currently installed in the supported
* each of the manifests, inventory the services and add them to
* the tree.
*
*/
static void
create_manifest_tree(void)
{
bundle_t *b;
int c, status;
return;
/*
* Create the list pool for the service manifest list
*/
sizeof (service_manifest_t),
if (service_manifest_pool == NULL)
uu_strerror(uu_error()));
/*
* Create the list
*/
if (service_manifest_tree == NULL)
uu_strerror(uu_error()));
/*
* Walk the manifests adding the service(s) from each manifest.
*
* If a service already exists add the manifest to the manifest
* list for that service. This covers the case of a service that
* is supported by multiple manifest files.
*/
for (c = 0; dirs[c]; c++) {
if (status < 0) {
return;
}
/*
* If a manifest that was in the list is not found
* then skip and go to the next manifest file.
*/
b = internal_bundle_new();
SVCCFG_OP_IMPORT) != 0) {
continue;
}
0);
continue;
}
NULL) {
/* Add manifest to service */
}
}
}
}
}
/*
* Check the manifest history file to see
* if the service was ever installed from
* one of the supported directories.
*
* Return Values :
* -1 - if there's error reading manifest history file
* 1 - if the service is not found
* 0 - if the service is found
*/
static int
check_mfst_history(const char *svcname)
{
char *svnbuf;
int fd;
int r = 1;
if (fd == -1) {
return (-1);
}
return (-1);
}
MAP_PRIVATE, fd, 0);
if (mfsthist_start == MAP_FAILED ||
return (-1);
}
/*
* The manifest history file is a space delimited list
* of service and instance to manifest linkage. Adding
* a space to the end of the service name so to get only
* the service that is being searched for.
*/
r = 0;
return (r);
}
/*
* Take down each of the instances in the service
* and remove them, then delete the service.
*/
static void
{
int r;
"supporting manifests\n"), svnbuf);
"teardown the service\n"));
scf_strerror(scf_error()));
scfdie();
}
switch (scf_error()) {
case SCF_ERROR_DELETED:
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances",
scf_error());
}
}
if (r == -1) {
scf_strerror(scf_error()));
goto out;
}
(void) disable_instance(instance);
}
/*
* Delete the service... forcing the deletion in case
* any of the instances did not disable.
*/
out:
}
/*
* Get the list of instances supported by the manifest
* file.
*
* Return 0 if there are no instances.
*
* Return -1 if there are errors attempting to collect instances.
*
* Return the count of instances found if there are no errors.
*
*/
static int
{
bundle_t *b;
const char *svcn;
int rminstcnt = 0;
b = internal_bundle_new();
/*
* Unable to process the manifest file for
* instance support, so just return as
* don't want to remove instances that could
* not be accounted for that might exist here.
*/
return (0);
}
return (0);
}
(sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
break;
}
return (-1);
}
return (0);
}
/*
* Remove the instance from the instances list.
* The unaccounted for instances will be removed
* from the service once all manifests are
* processed.
*/
(void) remove_string(instances,
rminstcnt++;
}
return (rminstcnt);
}
/*
* For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
* 'false' to indicate there's no manifest file(s) found for the service.
*/
static void
{
char *pname;
/* Add no support */
return;
}
/*
* This function handles all upgrade scenarios for a service that doesn't have
* SCF_PG_MANIFESTFILES pg. The function creates and populates
* SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
* manifest(s) mapping. Manifests under supported directories are inventoried
* and a property is added for each file that delivers configuration to the
* service. A service that has no corresponding manifest files (deleted) are
* removed from repository.
*
* Unsupported services:
*
* A service is considered unsupported if there is no corresponding manifest
* in the supported directories for that service and the service isn't in the
* history file list. The history file, MFSTHISTFILE, contains a list of all
* services and instances that were delivered by Solaris before the introduction
* of the SCF_PG_MANIFESTFILES property group. The history file also contains
* the path to the manifest file that defined the service or instance.
*
* Another type of unsupported services is 'handcrafted' services,
* programmatically created services or services created by dependent entries
* in other manifests. A handcrafted service is identified by its lack of any
* instance containing last-import snapshot which is created during svccfg
* import.
*
* This function sets a flag for unsupported services by setting services'
* SCF_PG_MANIFESTFILES/support property to false.
*/
static void
{
const char *sname;
char *pname;
int r;
/*
* Since there's no guarantee manifests under /var are available during
* early import, don't perform any upgrade during early import.
*/
if (IGNORE_VAR)
return;
if (service_manifest_tree == NULL) {
}
/*
* Find service's supporting manifest(s) after
* stripping off the svc:/ prefix that is part
* of the fmri that is not used in the service
* manifest bundle list.
*/
/*
* A handcrafted service, one that has no instance containing
* last-import snapshot, should get unsupported flag.
*/
svcname);
return;
}
if (uu_list_numnodes(instances) == 0) {
return;
}
/*
* If the service is in the history file, and its supporting
* manifests are not found, we can safely delete the service
* because its manifests are removed from the system.
*
* Services not found in the history file are not delivered by
* unsupported flag for these services.
*/
r = check_mfst_history(svcname);
if (r == -1)
return;
if (r) {
/* Set unsupported flag for service */
} else {
/* Delete the service */
}
return;
}
/*
* Walk through the list of manifests and add them
* to the service.
*
* Create a manifestfiles pg and add the property.
*/
return;
if (r != 0) {
return;
}
}
}
/*
* Take a service and process the manifest file entires to see if
* there is continued support for the service and instances. If
* not cleanup as appropriate.
*
* If a service does not have a manifest files entry flag it for
* upgrade and return.
*
* For each manifestfiles property check if the manifest file is
* and if not then return immediately as this service is not supported
* by the cleanup mechanism and should be ignored.
*
* For each manifest file that is supported, check to see if the
* file exists. If not then remove the manifest file property
* file exists then verify that it supports the instances that are
* part of the service.
*
* Once all manifest files have been accounted for remove any instances
* that are no longer supported in the service.
*
* Return values :
* 0 - Successfully processed the service
* non-zero - failed to process the service
*
* On most errors, will just return to wait and get the next service,
* unless in case of unable to create the needed structures which is
* most likely a fatal error that is not going to be recoverable.
*/
int
{
scf_iter_t *mi;
char *mpnbuf;
char *mpvbuf;
char *pgpropbuf;
int index;
int r = 0;
scf_strerror(scf_error()));
scfdie();
}
/*
* Get the manifestfiles property group to be parsed for
* files existence.
*/
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
goto out;
}
/*
* Iterate through each of the manifestfiles properties
* to determine what manifestfiles are available.
*
* If a manifest file is supported then increment the
* count and therefore the service is safe.
*/
switch (scf_error()) {
case SCF_ERROR_DELETED:
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
}
mfstcnt = 0;
if (r == -1)
"manifestfiles properties : %s"),
scf_error());
max_scf_name_len + 1) < 0) {
"property : %s\n"),
scf_strerror(scf_error()));
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = scferror2errno(scf_error());
goto out_free;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
}
/*
* The support property is a boolean value that indicates
* if the service is supported for manifest file deletion.
* Currently at this time there is no code that sets this
* value to true. So while we could just let this be caught
* by the support check below, in the future this by be set
* to true and require processing. So for that, go ahead
* and check here, and just return if false. Otherwise,
* fall through expecting that other support checks will
* handle the entries.
*/
"support value: %s\n"),
scf_strerror(scf_error()));
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = scferror2errno(scf_error());
goto out_free;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
}
goto out_free;
}
/*
* Anything with a manifest outside of the supported
* directories, immediately bail out because that makes
* this service non-supported. We don't even want
* to do instance processing in this case because the
* instances could be part of the non-supported manifest.
*/
/*
*/
/*
* /var is not yet mounted. We ignore the
* manifest either because it is not in a
* standard location or because we cannot
* currently access the manifest.
*/
goto out_free;
}
}
/*
* Get the value to of the manifest file for this entry
* for access verification and instance support
* verification if it still exists.
*
* During Early Manifest Import if the manifest is in
* then defer until Late Manifest Import to cleanup.
*/
"value: %s\n"),
scf_strerror(scf_error()));
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = scferror2errno(scf_error());
goto out_free;
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) {
"file : %s\n"),
scf_strerror(scf_error()));
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = scferror2errno(scf_error());
goto out_free;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_value_get_astring",
scf_error());
}
}
mfstcnt++;
/*
* Check for the need to reallocate array
*/
struct mpg_mfile **newmpvarry;
if (newmpvarry == NULL)
goto out_free;
}
}
/*
* Check to see if the manifestfile is accessable, if so hand
* this service and manifestfile off to be processed for
* instance support.
*/
activity++;
mfstcnt--;
/* Remove the entry from the service */
mpnbuf);
}
}
/*
* If mfstcnt is 0, none of the manifests that supported the service
* existed so remove the service.
*/
if (mfstcnt == 0) {
goto out_free;
}
if (activity) {
int nosvcsupport = 0;
/*
* If the list of service instances is NULL then
* create the list.
*/
goto out_free;
}
continue;
if (r == -1) {
nosvcsupport++;
} else {
rminstct -= r;
}
}
goto out_free;
}
}
/*
* If there are instances left on the instance list, then
* we must remove them.
*/
/*
* Remove the instance from the instances list.
*/
instance) != SCF_SUCCESS) {
(void) uu_warn("scf_error - %s\n",
scf_strerror(scf_error()));
continue;
}
(void) disable_instance(instance);
}
}
if (mpvarry) {
}
if (mpnbuf)
if (mpvbuf)
if (mpntov)
}
out:
return (0);
}
/*
* Take the service and search for the manifestfiles property
* in each of the property groups. If the manifest file
* associated with the property does not exist then remove
* the property group.
*/
int
{
int r;
"property\n"));
"pg is not NULL");
"prop is not NULL");
"val is not NULL");
"iter is not NULL");
"svc is not NULL");
"scope is not NULL");
scf_strerror(scf_error()));
scfdie();
}
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
goto out;
case SCF_ERROR_NOT_BOUND:
default:
}
}
HASH_SVC);
goto out;
}
scf_strerror(scf_error()));
goto out;
}
if (r == -1)
goto out;
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
}
}
if (IGNORE_VAR) {
continue;
}
/*
* If unable to get the property continue as this is an
* entry that has no location to check against.
*/
continue;
}
pgname);
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NOT_SET:
continue;
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
== -1) {
switch (scf_error()) {
case SCF_ERROR_NOT_SET:
case SCF_ERROR_TYPE_MISMATCH:
continue;
default:
}
}
continue;
(void) scf_pg_delete(pg);
}
out:
return (0);
}
#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 */