#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 <libxml/tree.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "svccfg.h"
#include "notify_params.h"
#include "manifest_hash.h"
#include "manifest_find.h"
#define COLON_NAMESPACES ":properties\n"
#define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX"
#define CHARS_TO_QUOTE " \t\n\\>=\"()"
#define HASH_SIZE 16
#define HASH_PG_TYPE "framework"
#define HASH_PG_FLAGS 0
#define HASH_PROP "md5sum"
#define TMPL_VALUE_INDENT " "
#define TMPL_INDENT " "
#define TMPL_INDENT_2X " "
#define TMPL_CHOICE_INDENT " "
#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
struct entity_elts {
xmlNodePtr create_default_instance;
xmlNodePtr single_instance;
xmlNodePtr restarter;
xmlNodePtr dependencies;
xmlNodePtr dependents;
xmlNodePtr method_context;
xmlNodePtr exec_methods;
xmlNodePtr notify_params;
xmlNodePtr property_groups;
xmlNodePtr instances;
xmlNodePtr stability;
xmlNodePtr template;
};
struct pg_elts {
xmlNodePtr stability;
xmlNodePtr propvals;
xmlNodePtr properties;
};
struct template_elts {
xmlNodePtr common_name;
xmlNodePtr description;
xmlNodePtr documentation;
};
struct params_elts {
xmlNodePtr paramval;
xmlNodePtr parameter;
};
struct snaplevel {
uu_list_node_t list_node;
scf_snaplevel_t *sl;
};
struct export_args {
const char *filename;
int flags;
};
typedef struct service_manifest {
const char *servicename;
uu_list_t *mfstlist;
size_t mfstlist_sz;
uu_avl_node_t svcmfst_node;
} service_manifest_t;
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";
scf_handle_t *g_hndl = NULL;
ssize_t max_scf_fmri_len;
ssize_t max_scf_name_len;
ssize_t max_scf_pg_type_len;
ssize_t max_scf_value_len;
static size_t max_scf_len;
static scf_scope_t *cur_scope;
static scf_service_t *cur_svc = NULL;
static scf_instance_t *cur_inst = NULL;
static scf_snapshot_t *cur_snap = NULL;
static scf_snaplevel_t *cur_level = NULL;
static uu_list_pool_t *snaplevel_pool;
static uu_list_t *cur_levels;
static struct snaplevel *cur_elt;
static FILE *tempfile = NULL;
static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
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;
static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
static scf_scope_t *imp_scope = NULL;
static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
static scf_snapshot_t *imp_rsnap = NULL;
static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
static scf_property_t *imp_prop = NULL;
static scf_iter_t *imp_iter = NULL;
static scf_iter_t *imp_rpg_iter = NULL;
static scf_iter_t *imp_up_iter = NULL;
static scf_transaction_t *imp_tx = NULL;
static char *imp_str = NULL;
static size_t imp_str_sz;
static char *imp_tsname = NULL;
static char *imp_fe1 = NULL;
static char *imp_fe2 = NULL;
static uu_list_t *imp_deleted_dpts = NULL;
static scf_instance_t *ud_inst = NULL;
static scf_snaplevel_t *ud_snpl = NULL;
static scf_propertygroup_t *ud_pg = NULL;
static scf_propertygroup_t *ud_cur_depts_pg = NULL;
static scf_propertygroup_t *ud_run_dpts_pg = NULL;
static int ud_run_dpts_pg_set = 0;
static scf_property_t *ud_prop = NULL;
static scf_property_t *ud_dpt_prop = NULL;
static scf_value_t *ud_val = NULL;
static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
static scf_transaction_t *ud_tx = NULL;
static char *ud_ctarg = NULL;
static char *ud_oldtarg = NULL;
static char *ud_name = NULL;
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 scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
static char *exp_str;
static size_t exp_str_sz;
static uu_avl_pool_t *service_manifest_pool = NULL;
static uu_avl_t *service_manifest_tree = NULL;
static void scfdie_lineno(int lineno) __NORETURN;
static char *start_method_names[] = {
"start",
"inetd_start",
NULL
};
static struct uri_scheme {
const char *scheme;
const char *protocol;
} uri_scheme[] = {
{ "mailto", "smtp" },
{ "snmp", "snmp" },
{ "syslog", "syslog" },
{ NULL, NULL }
};
#define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
sizeof (struct uri_scheme)) - 1)
static int
check_uri_scheme(const char *scheme)
{
int i;
for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
if (strcmp(scheme, uri_scheme[i].scheme) == 0)
return (i);
}
return (-1);
}
static int
check_uri_protocol(const char *p)
{
int i;
for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
if (strcmp(p, uri_scheme[i].protocol) == 0)
return (i);
}
return (-1);
}
#ifdef NDEBUG
static void scfdie(void) __NORETURN;
static void
scfdie(void)
{
scf_error_t err = scf_error();
if (err == SCF_ERROR_CONNECTION_BROKEN)
uu_die(gettext("Repository connection broken. Exiting.\n"));
uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"),
scf_strerror(err));
}
#else
#define scfdie() scfdie_lineno(__LINE__)
static void
scfdie_lineno(int lineno)
{
scf_error_t err = scf_error();
if (err == SCF_ERROR_CONNECTION_BROKEN)
uu_die(gettext("Repository connection broken. Exiting.\n"));
uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
": %s.\n"), lineno, scf_strerror(err));
}
#endif
static void
scfwarn(void)
{
warn(gettext("Unexpected libscf error: %s.\n"),
scf_strerror(scf_error()));
}
static int
clear_int(void *a, void *b)
{
*(int *)((char *)a + (size_t)b) = 0;
return (UU_WALK_NEXT);
}
static int
scferror2errno(scf_error_t err)
{
switch (err) {
case SCF_ERROR_BACKEND_ACCESS:
return (EACCES);
case SCF_ERROR_BACKEND_READONLY:
return (EROFS);
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_CONSTRAINT_VIOLATED:
case SCF_ERROR_INVALID_ARGUMENT:
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);
case SCF_ERROR_PERMISSION_DENIED:
return (EPERM);
default:
#ifndef NDEBUG
(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
__FILE__, __LINE__, err);
#else
(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
#endif
abort();
}
}
static int
entity_get_pg(void *ent, int issvc, const char *name,
scf_propertygroup_t *pg)
{
if (issvc)
return (scf_service_get_pg(ent, name, pg));
else
return (scf_instance_get_pg(ent, name, pg));
}
static void
entity_destroy(void *ent, int issvc)
{
if (issvc)
scf_service_destroy(ent);
else
scf_instance_destroy(ent);
}
static int
get_pg(const char *pg_name, scf_propertygroup_t *pg)
{
int ret;
if (cur_level != NULL)
ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
else if (cur_inst != NULL)
ret = scf_instance_get_pg(cur_inst, pg_name, pg);
else
ret = scf_service_get_pg(cur_svc, pg_name, pg);
return (ret);
}
static int
get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
{
if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
return (scferror2errno(scf_error()));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_snapshot_get_base_snaplevel",
scf_error());
}
}
for (;;) {
ssize_t ssz;
ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
if (ssz >= 0) {
if (!get_svc)
return (0);
} else {
switch (scf_error()) {
case SCF_ERROR_CONSTRAINT_VIOLATED:
if (get_svc)
return (0);
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_snaplevel_get_instance_name",
scf_error());
}
}
if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("scf_snaplevel_get_next_snaplevel",
scf_error());
}
}
}
}
static int
entity_get_running_pg(void *ent, int issvc, const char *name,
scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
scf_snapshot_t *snap, scf_snaplevel_t *snpl)
{
int r;
if (issvc) {
if (scf_iter_service_instances(iter, ent) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("scf_iter_service_instances",
scf_error());
}
}
for (;;) {
r = scf_iter_next_instance(iter, inst);
if (r == 0) {
if (scf_service_get_pg(ent, name, pg) == 0)
return (0);
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_get_pg",
scf_error());
}
}
if (r != 1) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("scf_iter_next_instance",
scf_error());
}
}
if (scf_instance_get_snapshot(inst, snap_running,
snap) == 0)
break;
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
continue;
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
}
} else {
if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
if (scf_instance_get_pg(ent, name, pg) == 0)
return (0);
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_pg", scf_error());
}
}
}
r = get_snaplevel(snap, issvc, snpl);
switch (r) {
case 0:
break;
case ECONNABORTED:
case ECANCELED:
return (r);
case ENOENT:
return (EBADF);
default:
bad_error("get_snaplevel", r);
}
if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
return (0);
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NOT_FOUND:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_snaplevel_get_pg", scf_error());
}
}
static void
remove_tempfile(void)
{
int ret;
if (tempfile != NULL) {
if (fclose(tempfile) == EOF)
(void) warn(gettext("Could not close temporary file"));
tempfile = NULL;
}
if (tempfilename[0] != '\0') {
do {
ret = remove(tempfilename);
} while (ret == -1 && errno == EINTR);
if (ret == -1)
warn(gettext("Could not remove temporary file"));
tempfilename[0] = '\0';
}
}
static void
start_private_repository(engine_state_t *est)
{
int fd, stat;
struct door_info info;
pid_t pid;
if (est->sc_repo_doorname != NULL)
free((void *)est->sc_repo_doorname);
est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
if (est->sc_repo_doorname == NULL)
uu_die(gettext("Could not acquire temporary filename"));
fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
if (fd < 0)
uu_die(gettext("Could not create temporary file for "
"repository server"));
(void) close(fd);
if ((est->sc_repo_pid = fork()) == 0) {
(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
"-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
NULL);
uu_die(gettext("Could not execute %s"), est->sc_repo_server);
} else if (est->sc_repo_pid == -1)
uu_die(gettext("Attempt to fork failed"));
do {
pid = waitpid(est->sc_repo_pid, &stat, 0);
} while (pid == -1 && errno == EINTR);
if (pid == -1)
uu_die(gettext("Could not waitpid() for repository server"));
if (!WIFEXITED(stat)) {
uu_die(gettext("Repository server failed (status %d).\n"),
stat);
} else if (WEXITSTATUS(stat) != 0) {
uu_die(gettext("Repository server failed (exit %d).\n"),
WEXITSTATUS(stat));
}
fd = open(est->sc_repo_doorname, O_RDWR);
if (fd < 0)
uu_die(gettext("Could not open door \"%s\""),
est->sc_repo_doorname);
if (door_info(fd, &info) < 0)
uu_die(gettext("Unexpected door_info() error"));
if (close(fd) == -1)
warn(gettext("Could not close repository door"),
strerror(errno));
est->sc_repo_pid = info.di_target;
}
void
lscf_cleanup(void)
{
if (est->sc_repo_pid > 0) {
(void) kill(est->sc_repo_pid, SIGTERM);
(void) waitpid(est->sc_repo_pid, NULL, 0);
(void) unlink(est->sc_repo_doorname);
est->sc_repo_pid = 0;
}
}
void
unselect_cursnap(void)
{
void *cookie;
cur_level = NULL;
cookie = NULL;
while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
scf_snaplevel_destroy(cur_elt->sl);
free(cur_elt);
}
scf_snapshot_destroy(cur_snap);
cur_snap = NULL;
}
void
lscf_prep_hndl(void)
{
if (g_hndl != NULL)
return;
g_hndl = scf_handle_create(SCF_VERSION);
if (g_hndl == NULL)
scfdie();
if (est->sc_repo_filename != NULL)
start_private_repository(est);
if (est->sc_repo_doorname != NULL) {
scf_value_t *repo_value;
int ret;
repo_value = scf_value_create(g_hndl);
if (repo_value == NULL)
scfdie();
ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
assert(ret == SCF_SUCCESS);
if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
SCF_SUCCESS)
scfdie();
scf_value_destroy(repo_value);
} else if (g_do_zone != 0) {
scf_value_t *zone;
if ((zone = scf_value_create(g_hndl)) == NULL)
scfdie();
if (scf_value_set_astring(zone, g_zonename) != SCF_SUCCESS)
scfdie();
if (scf_handle_decorate(g_hndl, "zone", zone) != SCF_SUCCESS) {
uu_die(gettext("zone '%s': %s\n"),
g_zonename, scf_strerror(scf_error()));
}
scf_value_destroy(zone);
}
if (scf_handle_bind(g_hndl) != 0)
uu_die(gettext("Could not connect to repository server: %s.\n"),
scf_strerror(scf_error()));
cur_scope = scf_scope_create(g_hndl);
if (cur_scope == NULL)
scfdie();
if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
scfdie();
}
static void
repository_teardown(void)
{
if (g_hndl != NULL) {
if (cur_snap != NULL)
unselect_cursnap();
scf_instance_destroy(cur_inst);
scf_service_destroy(cur_svc);
scf_scope_destroy(cur_scope);
scf_handle_destroy(g_hndl);
cur_inst = NULL;
cur_svc = NULL;
cur_scope = NULL;
g_hndl = NULL;
lscf_cleanup();
}
}
void
lscf_set_repository(const char *repfile, int force)
{
repository_teardown();
if (est->sc_repo_filename != NULL) {
free((void *)est->sc_repo_filename);
est->sc_repo_filename = NULL;
}
if ((force == 0) && (access(repfile, R_OK) != 0)) {
warn(gettext("Cannot access \"%s\": %s\n"),
repfile, strerror(errno));
} else {
est->sc_repo_filename = safe_strdup(repfile);
}
lscf_prep_hndl();
}
void
lscf_init()
{
if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
(max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
(max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
0 ||
(max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
scfdie();
max_scf_len = max_scf_fmri_len;
if (max_scf_name_len > max_scf_len)
max_scf_len = max_scf_name_len;
if (max_scf_pg_type_len > max_scf_len)
max_scf_len = max_scf_pg_type_len;
if (2 * max_scf_value_len > max_scf_len)
max_scf_len = 2 * max_scf_value_len;
if (atexit(remove_tempfile) != 0)
uu_die(gettext("Could not register atexit() function"));
emsg_entity_not_selected = gettext("An entity is not selected.\n");
emsg_permission_denied = gettext("Permission denied.\n");
emsg_create_xml = gettext("Could not create XML node.\n");
emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
emsg_invalid_for_snapshot =
gettext("Invalid operation on a snapshot.\n");
emsg_read_only = gettext("Backend read-only.\n");
emsg_deleted = gettext("Current selection has been deleted.\n");
emsg_invalid_pg_name =
gettext("Invalid property group name \"%s\".\n");
emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
emsg_no_such_pg = gettext("No such property group \"%s\".\n");
emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
"with invalid name \"%s\".\n");
emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
"group with invalid name \"%s\" or type \"%s\".\n");
emsg_pg_added = gettext("%s changed unexpectedly "
"(property group \"%s\" added).\n");
emsg_pg_changed = gettext("%s changed unexpectedly "
"(property group \"%s\" changed).\n");
emsg_pg_deleted = gettext("%s changed unexpectedly "
"(property group \"%s\" or an ancestor was deleted).\n");
emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
"in %s (permission denied).\n");
emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
"in %s (permission denied).\n");
emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
"in %s (permission denied).\n");
emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
"(permission denied).\n");
emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
"new dependent \"%s\" because it already exists). Warning: The "
"current dependent's target (%s) does not exist.\n");
emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
"dependent \"%s\" because it already exists). Warning: The "
"current dependent's target (%s) does not have a dependency named "
"\"%s\" as expected.\n");
string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
offsetof(string_list_t, node), NULL, 0);
snaplevel_pool = uu_list_pool_create("snaplevels",
sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
NULL, 0);
}
static const char *
prop_to_typestr(const scf_property_t *prop)
{
scf_type_t ty;
if (scf_property_type(prop, &ty) != SCF_SUCCESS)
scfdie();
return (scf_type_to_string(ty));
}
static scf_type_t
string_to_type(const char *type)
{
size_t len = strlen(type);
char *buf;
if (len == 0 || type[len - 1] != ':')
return (SCF_TYPE_INVALID);
buf = (char *)alloca(len + 1);
(void) strlcpy(buf, type, len + 1);
buf[len - 1] = 0;
return (scf_string_to_type(buf));
}
static scf_value_t *
string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
{
scf_value_t *v;
char *dup, *nstr;
size_t len;
v = scf_value_create(g_hndl);
if (v == NULL)
scfdie();
len = strlen(str);
if (require_quotes &&
(len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
semerr(gettext("Multiple string values or string values "
"with spaces must be quoted with '\"'.\n"));
scf_value_destroy(v);
return (NULL);
}
nstr = dup = safe_strdup(str);
if (dup[0] == '\"') {
dup[len - 1] = '\0';
nstr = dup + 1;
}
if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
scf_type_to_string(ty), nstr);
scf_value_destroy(v);
v = NULL;
}
free(dup);
return (v);
}
static int
quote_and_print(const char *str, FILE *strm, int commentnl)
{
const char *cp;
for (cp = str; *cp != '\0'; ++cp) {
if (*cp == '"' || *cp == '\\')
(void) putc('\\', strm);
(void) putc(*cp, strm);
if (commentnl && *cp == '\n') {
(void) putc('#', strm);
}
}
return (ferror(strm));
}
static int
pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
{
if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
return (0);
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (g_verbose) {
ssize_t len;
char *fmri;
len = scf_pg_to_fmri(pg, NULL, 0);
if (len < 0)
scfdie();
fmri = safe_malloc(len + 1);
if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
scfdie();
warn(gettext("Expected property %s of property group %s is "
"missing.\n"), propname, fmri);
free(fmri);
}
return (-1);
}
static int
prop_check_type(scf_property_t *prop, scf_type_t ty)
{
scf_type_t pty;
if (scf_property_type(prop, &pty) != SCF_SUCCESS)
scfdie();
if (ty == pty)
return (0);
if (g_verbose) {
ssize_t len;
char *fmri;
const char *tystr;
len = scf_property_to_fmri(prop, NULL, 0);
if (len < 0)
scfdie();
fmri = safe_malloc(len + 1);
if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
scfdie();
tystr = scf_type_to_string(ty);
if (tystr == NULL)
tystr = "?";
warn(gettext("Property %s is not of expected type %s.\n"),
fmri, tystr);
free(fmri);
}
return (-1);
}
static int
prop_get_val(scf_property_t *prop, scf_value_t *val)
{
scf_error_t err;
if (scf_property_get_value(prop, val) == SCF_SUCCESS)
return (0);
err = scf_error();
if (err != SCF_ERROR_NOT_FOUND &&
err != SCF_ERROR_CONSTRAINT_VIOLATED &&
err != SCF_ERROR_PERMISSION_DENIED)
scfdie();
if (g_verbose) {
ssize_t len;
char *fmri, *emsg;
len = scf_property_to_fmri(prop, NULL, 0);
if (len < 0)
scfdie();
fmri = safe_malloc(len + 1);
if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
scfdie();
if (err == SCF_ERROR_NOT_FOUND)
emsg = gettext("Property %s has no values; expected "
"one.\n");
else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
emsg = gettext("Property %s has multiple values; "
"expected one.\n");
else
emsg = gettext("No permission to read property %s.\n");
warn(emsg, fmri);
free(fmri);
}
return (-1);
}
static boolean_t
snaplevel_is_instance(const scf_snaplevel_t *level)
{
if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
scfdie();
return (0);
} else {
return (1);
}
}
static scf_error_t
fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
{
char *fmri_copy;
const char *sstr, *istr, *pgstr;
scf_service_t *svc;
scf_instance_t *inst;
fmri_copy = strdup(fmri);
if (fmri_copy == NULL)
return (SCF_ERROR_NO_MEMORY);
if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
SCF_SUCCESS) {
free(fmri_copy);
return (SCF_ERROR_INVALID_ARGUMENT);
}
free(fmri_copy);
if (sstr == NULL || pgstr != NULL)
return (SCF_ERROR_CONSTRAINT_VIOLATED);
if (istr == NULL) {
svc = scf_service_create(h);
if (svc == NULL)
return (SCF_ERROR_NO_MEMORY);
if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
return (SCF_ERROR_NOT_FOUND);
}
*ep = svc;
*isservice = 1;
} else {
inst = scf_instance_create(h);
if (inst == NULL)
return (SCF_ERROR_NO_MEMORY);
if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
return (SCF_ERROR_NOT_FOUND);
}
*ep = inst;
*isservice = 0;
}
return (SCF_ERROR_NONE);
}
static scf_error_t
create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
{
char *fmri_copy;
const char *scstr, *sstr, *istr, *pgstr;
scf_scope_t *scope = NULL;
scf_service_t *svc = NULL;
scf_instance_t *inst = NULL;
scf_error_t scfe;
fmri_copy = safe_strdup(fmri);
if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
0) {
free(fmri_copy);
return (SCF_ERROR_INVALID_ARGUMENT);
}
if (scstr == NULL || sstr == NULL || pgstr != NULL) {
free(fmri_copy);
return (SCF_ERROR_CONSTRAINT_VIOLATED);
}
*ep = NULL;
if ((scope = scf_scope_create(h)) == NULL ||
(svc = scf_service_create(h)) == NULL ||
(inst = scf_instance_create(h)) == NULL) {
scfe = SCF_ERROR_NO_MEMORY;
goto out;
}
get_scope:
if (scf_handle_get_scope(h, scstr, scope) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
scfdie();
case SCF_ERROR_NOT_FOUND:
scfe = SCF_ERROR_NOT_FOUND;
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("scf_handle_get_scope", scf_error());
}
}
get_svc:
if (scf_scope_get_service(scope, sstr, svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
scfdie();
case SCF_ERROR_DELETED:
goto get_scope;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_scope_get_service", scf_error());
}
if (scf_scope_add_service(scope, sstr, svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
scfdie();
case SCF_ERROR_DELETED:
goto get_scope;
case SCF_ERROR_PERMISSION_DENIED:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
scfe = scf_error();
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_scope_get_service", scf_error());
}
}
}
if (istr == NULL) {
scfe = SCF_ERROR_NONE;
*ep = svc;
*isservicep = 1;
goto out;
}
if (scf_service_get_instance(svc, istr, inst) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
scfdie();
case SCF_ERROR_DELETED:
goto get_svc;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_get_instance", scf_error());
}
if (scf_service_add_instance(svc, istr, inst) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
scfdie();
case SCF_ERROR_DELETED:
goto get_svc;
case SCF_ERROR_PERMISSION_DENIED:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
scfe = scf_error();
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_add_instance",
scf_error());
}
}
}
scfe = SCF_ERROR_NONE;
*ep = inst;
*isservicep = 0;
out:
if (*ep != inst)
scf_instance_destroy(inst);
if (*ep != svc)
scf_service_destroy(svc);
scf_scope_destroy(scope);
free(fmri_copy);
return (scfe);
}
static int
take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
{
again:
if (scf_instance_get_snapshot(inst, name, snap) == 0) {
if (_scf_snapshot_take_attach(inst, snap) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_PERMISSION_DENIED:
case SCF_ERROR_NO_RESOURCES:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("_scf_snapshot_take_attach",
scf_error());
}
}
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot", scf_error());
}
if (_scf_snapshot_take_new(inst, name, snap) != 0) {
switch (scf_error()) {
case SCF_ERROR_EXISTS:
goto again;
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_PERMISSION_DENIED:
return (scferror2errno(scf_error()));
default:
scfwarn();
return (-1);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INTERNAL:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
bad_error("_scf_snapshot_take_new",
scf_error());
}
}
}
return (0);
}
static int
refresh_running_snapshot(void *entity)
{
scf_snapshot_t *snap;
int r;
if ((snap = scf_snapshot_create(g_hndl)) == NULL)
scfdie();
r = take_snap(entity, snap_running, snap);
scf_snapshot_destroy(snap);
return (r);
}
static int
refresh_entity(int isservice, void *entity, const char *fmri,
scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
{
scf_error_t scfe;
int r;
if (!isservice) {
if (est->sc_repo_filename == NULL &&
est->sc_repo_doorname == NULL &&
est->sc_in_emi == 0) {
if (_smf_refresh_instance_i(entity) == 0) {
if (g_verbose)
warn(gettext("Refreshed %s.\n"), fmri);
return (0);
}
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
return (EACCES);
case SCF_ERROR_PERMISSION_DENIED:
return (EPERM);
default:
return (-1);
}
} else {
r = refresh_running_snapshot(entity);
switch (r) {
case 0:
break;
case ECONNABORTED:
case ECANCELED:
case EPERM:
case ENOSPC:
break;
default:
bad_error("refresh_running_snapshot",
scf_error());
}
return (r);
}
}
if (scf_iter_service_instances(iter, entity) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_DELETED:
return (ECANCELED);
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances", scf_error());
}
}
for (;;) {
r = scf_iter_next_instance(iter, inst);
if (r == 0)
break;
if (r != 1) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_DELETED:
return (ECANCELED);
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("scf_iter_next_instance",
scf_error());
}
}
if (est->sc_repo_filename != NULL ||
est->sc_repo_doorname != NULL ||
est->sc_in_emi == 1) {
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) {
if (scf_instance_get_name(inst, name_buf,
max_scf_name_len + 1) < 0)
(void) strcpy(name_buf, "?");
warn(gettext("Refreshed %s:%s.\n"),
fmri, name_buf);
}
} else {
if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
g_verbose) {
scfe = scf_error();
if (scf_instance_to_fmri(inst, name_buf,
max_scf_name_len + 1) < 0)
(void) strcpy(name_buf, "?");
warn(gettext(
"Refresh of %s:%s failed: %s.\n"), fmri,
name_buf, scf_strerror(scfe));
}
}
}
return (0);
}
static void
private_refresh(void)
{
scf_instance_t *pinst = NULL;
scf_iter_t *piter = NULL;
ssize_t fmrilen;
size_t bufsz;
char *fmribuf;
void *ent;
int issvc;
int r;
if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
return;
assert(cur_svc != NULL);
bufsz = max_scf_fmri_len + 1;
fmribuf = safe_malloc(bufsz);
if (cur_inst) {
issvc = 0;
ent = cur_inst;
fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
} else {
issvc = 1;
ent = cur_svc;
fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
if ((pinst = scf_instance_create(g_hndl)) == NULL)
scfdie();
if ((piter = scf_iter_create(g_hndl)) == NULL)
scfdie();
}
if (fmrilen < 0) {
free(fmribuf);
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
warn(emsg_deleted);
return;
}
assert(fmrilen < bufsz);
r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
switch (r) {
case 0:
break;
case ECONNABORTED:
warn(gettext("Could not refresh %s "
"(repository connection broken).\n"), fmribuf);
break;
case ECANCELED:
warn(emsg_deleted);
break;
case EPERM:
warn(gettext("Could not refresh %s "
"(permission denied).\n"), fmribuf);
break;
case ENOSPC:
warn(gettext("Could not refresh %s "
"(repository server out of resources).\n"),
fmribuf);
break;
case EACCES:
default:
bad_error("refresh_entity", scf_error());
}
if (issvc) {
scf_instance_destroy(pinst);
scf_iter_destroy(piter);
}
free(fmribuf);
}
static int
stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
{
cbp->sc_err = scferror2errno(err);
return (UU_WALK_ERROR);
}
static int
stash_scferror(scf_callback_t *cbp)
{
return (stash_scferror_err(cbp, scf_error()));
}
static int select_inst(const char *);
static int select_svc(const char *);
static int
find_current_prop_type(void *p, void *g)
{
property_t *prop = p;
scf_callback_t *lcb = g;
pgroup_t *pg = NULL;
const char *fmri = NULL;
char *lfmri = NULL;
char *cur_selection = NULL;
scf_propertygroup_t *sc_pg = NULL;
scf_property_t *sc_prop = NULL;
scf_pg_tmpl_t *t_pg = NULL;
scf_prop_tmpl_t *t_prop = NULL;
scf_type_t prop_type;
value_t *vp;
int issvc = lcb->sc_service;
int r = UU_WALK_ERROR;
if (prop->sc_value_type != SCF_TYPE_INVALID)
return (UU_WALK_NEXT);
t_prop = scf_tmpl_prop_create(g_hndl);
sc_prop = scf_property_create(g_hndl);
if (sc_prop == NULL || t_prop == NULL) {
warn(gettext("Unable to create the property to attempt and "
"find a missing type.\n"));
scf_property_destroy(sc_prop);
scf_tmpl_prop_destroy(t_prop);
return (UU_WALK_ERROR);
}
if (lcb->sc_flags == 1) {
pg = lcb->sc_parent;
issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
fmri = pg->sc_parent->sc_fmri;
retry_pg:
if (cur_svc && cur_selection == NULL) {
cur_selection = safe_malloc(max_scf_fmri_len + 1);
lscf_get_selection_str(cur_selection,
max_scf_fmri_len + 1);
if (strcmp(cur_selection, fmri) != 0) {
lscf_select(fmri);
} else {
free(cur_selection);
cur_selection = NULL;
}
} else {
lscf_select(fmri);
}
if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
warn(gettext("Unable to create property group to "
"find a missing property type.\n"));
goto out;
}
if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
if (sc_pg != lcb->sc_parent)
scf_pg_destroy(sc_pg);
sc_pg = NULL;
if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
warn(gettext("Unable to create template "
"property group to find a property "
"type.\n"));
goto out;
}
if (scf_tmpl_get_by_pg_name(fmri, NULL,
pg->sc_pgroup_name, NULL, t_pg,
SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
scf_tmpl_pg_destroy(t_pg);
t_pg = NULL;
if (issvc == 0) {
entity_t *e = pg->sc_parent->sc_parent;
fmri = e->sc_fmri;
issvc = 1;
goto retry_pg;
} else {
goto out;
}
}
}
} else {
sc_pg = lcb->sc_parent;
}
if (sc_pg != NULL &&
pg_get_prop(sc_pg, prop->sc_property_name,
sc_prop) == SCF_SUCCESS &&
scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
prop->sc_value_type = prop_type;
for (vp = uu_list_first(prop->sc_property_values);
vp != NULL;
vp = uu_list_next(prop->sc_property_values, vp)) {
vp->sc_type = prop->sc_value_type;
lxml_store_value(vp, 0, NULL);
}
r = UU_WALK_NEXT;
goto out;
}
do_tmpl :
if (t_pg != NULL &&
scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
t_prop, 0) == SCF_SUCCESS) {
if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
prop->sc_value_type = prop_type;
for (vp = uu_list_first(prop->sc_property_values);
vp != NULL;
vp = uu_list_next(prop->sc_property_values, vp)) {
vp->sc_type = prop->sc_value_type;
lxml_store_value(vp, 0, NULL);
}
r = UU_WALK_NEXT;
goto out;
}
} else {
if (t_pg == NULL && sc_pg) {
if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
warn(gettext("Unable to create template "
"property group to find a property "
"type.\n"));
goto out;
}
if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
scf_tmpl_pg_destroy(t_pg);
t_pg = NULL;
} else {
goto do_tmpl;
}
}
}
if (issvc == 0) {
scf_instance_t *i;
scf_service_t *s;
issvc = 1;
if (lcb->sc_flags == 1) {
entity_t *e = pg->sc_parent->sc_parent;
fmri = e->sc_fmri;
goto retry_pg;
}
if ((pg = internal_pgroup_new()) == NULL) {
warn(gettext("Could not create internal property group "
"to find a missing type."));
goto out;
}
pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
max_scf_name_len + 1) < 0)
goto out;
i = scf_instance_create(g_hndl);
s = scf_service_create(g_hndl);
if (i == NULL || s == NULL ||
scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
warn(gettext("Could not get a service for the instance "
"to find a missing type."));
goto out;
}
lfmri = safe_malloc(max_scf_fmri_len + 1);
if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
goto out;
else
fmri = (const char *)lfmri;
goto retry_pg;
}
out :
if (sc_pg != lcb->sc_parent) {
scf_pg_destroy(sc_pg);
}
if (pg != NULL && pg != lcb->sc_parent) {
free((char *)pg->sc_pgroup_name);
internal_pgroup_free(pg);
}
if (cur_selection) {
lscf_select(cur_selection);
free(cur_selection);
}
scf_tmpl_pg_destroy(t_pg);
scf_tmpl_prop_destroy(t_prop);
scf_property_destroy(sc_prop);
if (r != UU_WALK_NEXT)
warn(gettext("Could not find property type for \"%s\" "
"from \"%s\"\n"), prop->sc_property_name,
fmri != NULL ? fmri : lcb->sc_source_fmri);
free(lfmri);
return (r);
}
static int
find_current_pg_type(void *p, void *sori)
{
entity_t *si = sori;
pgroup_t *pg = p;
const char *ofmri, *fmri;
char *cur_selection = NULL;
char *pg_type = NULL;
scf_propertygroup_t *sc_pg = NULL;
scf_pg_tmpl_t *t_pg = NULL;
int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
int r = UU_WALK_ERROR;
ofmri = fmri = si->sc_fmri;
if (pg->sc_pgroup_type != NULL) {
r = UU_WALK_NEXT;
goto out;
}
sc_pg = scf_pg_create(g_hndl);
if (sc_pg == NULL) {
warn(gettext("Unable to create property group to attempt "
"and find a missing type.\n"));
return (UU_WALK_ERROR);
}
if (cur_svc) {
cur_selection = safe_malloc(max_scf_fmri_len + 1);
lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
}
retry_svc:
lscf_select(fmri);
if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
pg_type = safe_malloc(max_scf_pg_type_len + 1);
if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
max_scf_pg_type_len + 1) != -1) {
pg->sc_pgroup_type = pg_type;
r = UU_WALK_NEXT;
goto out;
} else {
free(pg_type);
}
} else {
if ((t_pg == NULL) &&
(t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
goto out;
if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
pg->sc_pgroup_type = pg_type;
r = UU_WALK_NEXT;
goto out;
}
}
if (!issvc) {
si = si->sc_parent;
fmri = si->sc_fmri;
issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
goto retry_svc;
}
out :
if (cur_selection) {
lscf_select(cur_selection);
free(cur_selection);
}
if (r == UU_WALK_NEXT) {
scf_callback_t cb;
cb.sc_service = issvc;
cb.sc_source_fmri = ofmri;
if (sc_pg != NULL) {
cb.sc_parent = sc_pg;
cb.sc_flags = 0;
} else {
cb.sc_parent = pg;
cb.sc_flags = 1;
}
if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
&cb, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
r = UU_WALK_ERROR;
}
} else {
warn(gettext("Could not find property group type for "
"\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
}
scf_tmpl_pg_destroy(t_pg);
scf_pg_destroy(sc_pg);
return (r);
}
static int
lscf_property_import(void *v, void *pvt)
{
property_t *p = v;
scf_callback_t *lcbdata = pvt;
value_t *vp;
scf_transaction_t *trans = lcbdata->sc_trans;
scf_transaction_entry_t *entr;
scf_value_t *val;
scf_type_t tp;
if ((lcbdata->sc_flags & SCI_NOENABLED ||
lcbdata->sc_flags & SCI_DELAYENABLE) &&
strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
lcbdata->sc_enable = p;
return (UU_WALK_NEXT);
}
entr = scf_entry_create(lcbdata->sc_handle);
if (entr == NULL) {
switch (scf_error()) {
case SCF_ERROR_NO_MEMORY:
return (stash_scferror(lcbdata));
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("scf_entry_create", scf_error());
}
}
tp = p->sc_value_type;
if (scf_transaction_property_new(trans, entr,
p->sc_property_name, tp) != 0) {
switch (scf_error()) {
case SCF_ERROR_INVALID_ARGUMENT:
semerr(emsg_invalid_prop_name, p->sc_property_name);
scf_entry_destroy(entr);
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
scf_entry_destroy(entr);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_property_new", scf_error());
}
if (scf_transaction_property_change_type(trans, entr,
p->sc_property_name, tp) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
scf_entry_destroy(entr);
return (stash_scferror(lcbdata));
case SCF_ERROR_INVALID_ARGUMENT:
semerr(emsg_invalid_prop_name,
p->sc_property_name);
scf_entry_destroy(entr);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
default:
bad_error(
"scf_transaction_property_change_type",
scf_error());
}
}
}
for (vp = uu_list_first(p->sc_property_values);
vp != NULL;
vp = uu_list_next(p->sc_property_values, vp)) {
val = scf_value_create(g_hndl);
if (val == NULL) {
switch (scf_error()) {
case SCF_ERROR_NO_MEMORY:
return (stash_scferror(lcbdata));
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("scf_value_create", scf_error());
}
}
switch (tp) {
case SCF_TYPE_BOOLEAN:
scf_value_set_boolean(val, vp->sc_u.sc_count);
break;
case SCF_TYPE_COUNT:
scf_value_set_count(val, vp->sc_u.sc_count);
break;
case SCF_TYPE_INTEGER:
scf_value_set_integer(val, vp->sc_u.sc_integer);
break;
default:
assert(vp->sc_u.sc_string != NULL);
if (scf_value_set_from_string(val, tp,
vp->sc_u.sc_string) != 0) {
if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
bad_error("scf_value_set_from_string",
scf_error());
warn(gettext("Value \"%s\" is not a valid "
"%s.\n"), vp->sc_u.sc_string,
scf_type_to_string(tp));
scf_value_destroy(val);
return (stash_scferror(lcbdata));
}
break;
}
if (scf_entry_add_value(entr, val) != 0)
bad_error("scf_entry_add_value", scf_error());
}
return (UU_WALK_NEXT);
}
static int
entity_pgroup_import(void *v, void *pvt)
{
pgroup_t *p = v;
scf_callback_t cbdata;
scf_callback_t *lcbdata = pvt;
void *ent = lcbdata->sc_parent;
int issvc = lcbdata->sc_service;
int r;
const char * const pg_changed = gettext("%s changed unexpectedly "
"(new property group \"%s\" changed).\n");
if (p->sc_pgroup_delete) {
if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
goto delete_pg;
}
return (UU_WALK_NEXT);
}
if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
lcbdata->sc_general = p;
return (UU_WALK_NEXT);
}
add_pg:
if (issvc)
r = scf_service_add_pg(ent, p->sc_pgroup_name,
p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
else
r = scf_instance_add_pg(ent, p->sc_pgroup_name,
p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NO_RESOURCES:
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
if (lcbdata->sc_flags & SCI_FORCE)
break;
return (stash_scferror(lcbdata));
case SCF_ERROR_INVALID_ARGUMENT:
warn(emsg_fmri_invalid_pg_name_type,
lcbdata->sc_source_fmri,
p->sc_pgroup_name, p->sc_pgroup_type);
return (stash_scferror(lcbdata));
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_add_perm, p->sc_pgroup_name,
lcbdata->sc_target_fmri);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_add_pg", scf_error());
}
if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_DELETED:
return (stash_scferror(lcbdata));
case SCF_ERROR_INVALID_ARGUMENT:
warn(emsg_fmri_invalid_pg_name,
lcbdata->sc_source_fmri,
p->sc_pgroup_name);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_FOUND:
warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
p->sc_pgroup_name);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("entity_get_pg", scf_error());
}
}
if (lcbdata->sc_flags & SCI_KEEP)
goto props;
delete_pg:
if (scf_pg_delete(imp_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
p->sc_pgroup_name);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_del_perm, p->sc_pgroup_name,
lcbdata->sc_target_fmri);
return (stash_scferror(lcbdata));
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_CONNECTION_BROKEN:
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_delete", scf_error());
}
}
if (p->sc_pgroup_delete)
return (UU_WALK_NEXT);
goto add_pg;
}
props:
cbdata.sc_handle = lcbdata->sc_handle;
cbdata.sc_parent = imp_pg;
cbdata.sc_flags = lcbdata->sc_flags;
cbdata.sc_trans = imp_tx;
cbdata.sc_enable = NULL;
if (scf_transaction_start(imp_tx, imp_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_CONNECTION_BROKEN:
return (stash_scferror(lcbdata));
case SCF_ERROR_DELETED:
warn(pg_changed, lcbdata->sc_target_fmri,
p->sc_pgroup_name);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_mod_perm, p->sc_pgroup_name,
lcbdata->sc_target_fmri);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_IN_USE:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("scf_transaction_start", scf_error());
}
}
if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
scf_transaction_reset(imp_tx);
lcbdata->sc_err = cbdata.sc_err;
if (cbdata.sc_err == ECANCELED) {
warn(pg_changed, lcbdata->sc_target_fmri,
p->sc_pgroup_name);
lcbdata->sc_err = EBUSY;
}
return (UU_WALK_ERROR);
}
if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
r = take_snap(ent, snap_running, imp_rsnap);
switch (r) {
case 0:
break;
case ECONNABORTED:
warn(gettext("Could not take %s snapshot on import "
"(repository connection broken).\n"),
snap_running);
lcbdata->sc_err = r;
return (UU_WALK_ERROR);
case ECANCELED:
warn(emsg_deleted);
lcbdata->sc_err = r;
return (UU_WALK_ERROR);
case EPERM:
warn(gettext("Could not take %s snapshot "
"(permission denied).\n"), snap_running);
lcbdata->sc_err = r;
return (UU_WALK_ERROR);
case ENOSPC:
warn(gettext("Could not take %s snapshot"
"(repository server out of resources).\n"),
snap_running);
lcbdata->sc_err = r;
return (UU_WALK_ERROR);
default:
bad_error("take_snap", r);
}
r = lscf_property_import(cbdata.sc_enable, &cbdata);
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:
warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
break;
case -1:
switch (scf_error()) {
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
break;
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
p->sc_pgroup_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
break;
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_mod_perm, p->sc_pgroup_name,
lcbdata->sc_target_fmri);
r = stash_scferror(lcbdata);
break;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_transaction_commit", scf_error());
}
break;
default:
bad_error("scf_transaction_commit", r);
}
scf_transaction_destroy_children(imp_tx);
return (r);
}
static int
lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
const entity_t *isvc, int flags)
{
scf_callback_t cbdata;
cbdata.sc_handle = scf_service_handle(svc);
cbdata.sc_parent = svc;
cbdata.sc_service = 1;
cbdata.sc_general = 0;
cbdata.sc_enable = 0;
cbdata.sc_flags = flags;
cbdata.sc_source_fmri = isvc->sc_fmri;
cbdata.sc_target_fmri = target_fmri;
if (isvc->sc_op != SVCCFG_OP_NONE) {
switch (isvc->sc_op) {
case SVCCFG_OP_IMPORT :
cbdata.sc_flags |= SCI_OP_IMPORT;
break;
case SVCCFG_OP_APPLY :
cbdata.sc_flags |= SCI_OP_APPLY;
break;
case SVCCFG_OP_RESTORE :
cbdata.sc_flags |= SCI_OP_RESTORE;
break;
default :
uu_die(gettext("lscf_import_service_pgs : "
"Unknown op stored in the service entity\n"));
}
}
if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
return (cbdata.sc_err);
}
return (0);
}
static int
lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
const entity_t *iinst, int flags)
{
scf_callback_t cbdata;
cbdata.sc_handle = scf_instance_handle(inst);
cbdata.sc_parent = inst;
cbdata.sc_service = 0;
cbdata.sc_general = NULL;
cbdata.sc_enable = NULL;
cbdata.sc_flags = flags;
cbdata.sc_source_fmri = iinst->sc_fmri;
cbdata.sc_target_fmri = target_fmri;
if (iinst->sc_op != SVCCFG_OP_NONE) {
switch (iinst->sc_op) {
case SVCCFG_OP_IMPORT :
cbdata.sc_flags |= SCI_OP_IMPORT;
break;
case SVCCFG_OP_APPLY :
cbdata.sc_flags |= SCI_OP_APPLY;
break;
case SVCCFG_OP_RESTORE :
cbdata.sc_flags |= SCI_OP_RESTORE;
break;
default :
uu_die(gettext("lscf_import_instance_pgs : "
"Unknown op stored in the instance entity\n"));
}
}
if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
return (cbdata.sc_err);
}
if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
cbdata.sc_flags = flags & (~SCI_GENERALLAST);
if (!(cbdata.sc_flags & SCI_NOENABLED)) {
cbdata.sc_flags |= SCI_DELAYENABLE;
}
if (entity_pgroup_import(cbdata.sc_general, &cbdata)
!= UU_WALK_NEXT)
return (cbdata.sc_err);
}
return (0);
}
static void
report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
int new)
{
property_t *p1, *p2;
assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
if (!pg_attrs_equal(pg1, pg2, fmri, new))
return;
for (p1 = uu_list_first(pg1->sc_pgroup_props);
p1 != NULL;
p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
if (p2 != NULL) {
(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
new);
continue;
}
if (new)
warn(gettext("Conflict upgrading %s (new property "
"group \"%s\" is missing property \"%s\").\n"),
fmri, pg1->sc_pgroup_name, p1->sc_property_name);
else
warn(gettext("Conflict upgrading %s (property "
"\"%s/%s\" is missing).\n"), fmri,
pg1->sc_pgroup_name, p1->sc_property_name);
}
}
static int
add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
pgroup_t *cur, int speak, const char *fmri)
{
property_t *p, *new_p, *cur_p;
scf_transaction_entry_t *e;
int r;
int is_general;
int is_protected;
if (uu_list_walk(new->sc_pgroup_props, clear_int,
(void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
bad_error("uu_list_walk", uu_error());
is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
for (p = uu_list_first(old->sc_pgroup_props);
p != NULL;
p = uu_list_next(old->sc_pgroup_props, p)) {
is_protected = 0;
if (is_general) {
if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
0 ||
strcmp(p->sc_property_name,
SCF_PROPERTY_RESTARTER) == 0)
is_protected = 1;
}
new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
if (new_p != NULL) {
new_p->sc_seen = 1;
if (prop_equal(p, new_p, NULL, NULL, 0))
continue;
if (new_p->sc_property_override)
goto upgrade;
}
cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
if (cur_p == NULL) {
if (new_p == NULL)
continue;
if (is_protected)
continue;
warn(gettext("Conflict upgrading %s "
"(property \"%s/%s\" is missing).\n"), fmri,
old->sc_pgroup_name, p->sc_property_name);
continue;
}
if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
if (is_protected)
continue;
if (new_p == NULL)
(void) prop_equal(p, cur_p, fmri,
old->sc_pgroup_name, 0);
else
(void) prop_equal(cur_p, new_p, fmri,
old->sc_pgroup_name, 0);
continue;
}
if (is_protected) {
if (speak)
warn(gettext("%s: Refusing to upgrade "
"\"%s/%s\" (live property).\n"), fmri,
old->sc_pgroup_name, p->sc_property_name);
continue;
}
upgrade:
if (new_p == NULL) {
if (speak)
warn(gettext(
"%s: Deleting property \"%s/%s\".\n"),
fmri, old->sc_pgroup_name,
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:
scf_entry_destroy(e);
return (ECANCELED);
case SCF_ERROR_CONNECTION_BROKEN:
scf_entry_destroy(e);
return (ECONNABORTED);
case SCF_ERROR_NOT_FOUND:
scf_entry_destroy(e);
break;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error(
"scf_transaction_property_delete",
scf_error());
}
}
} else {
scf_callback_t ctx;
if (speak)
warn(gettext(
"%s: Upgrading property \"%s/%s\".\n"),
fmri, old->sc_pgroup_name,
p->sc_property_name);
ctx.sc_handle = g_hndl;
ctx.sc_trans = tx;
ctx.sc_flags = 0;
r = lscf_property_import(new_p, &ctx);
if (r != UU_WALK_NEXT) {
if (r != UU_WALK_ERROR)
bad_error("lscf_property_import", r);
return (EINVAL);
}
}
}
for (new_p = uu_list_first(new->sc_pgroup_props);
new_p != NULL;
new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
if (new_p->sc_seen)
continue;
cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
if (cur_p == NULL) {
scf_callback_t ctx;
ctx.sc_handle = g_hndl;
ctx.sc_trans = tx;
ctx.sc_flags = 0;
r = lscf_property_import(new_p, &ctx);
if (r != UU_WALK_NEXT) {
if (r != UU_WALK_ERROR)
bad_error("lscf_property_import", r);
return (EINVAL);
}
continue;
}
if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
0 &&
strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
continue;
(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
}
return (0);
}
static int
upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
pgroup_t *new, int speak, const char *fmri)
{
int r;
if (scf_transaction_start(imp_tx, pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_DELETED:
case SCF_ERROR_PERMISSION_DENIED:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
return (scferror2errno(scf_error()));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_IN_USE:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_start", scf_error());
}
}
r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
switch (r) {
case 0:
break;
case EINVAL:
case ENOMEM:
scf_transaction_destroy_children(imp_tx);
return (r);
default:
bad_error("add_upgrade_entries", r);
}
r = scf_transaction_commit(imp_tx);
scf_transaction_destroy_children(imp_tx);
switch (r) {
case 1:
break;
case 0:
return (EBUSY);
case -1:
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_PERMISSION_DENIED:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_DELETED:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_commit", scf_error());
}
default:
bad_error("scf_transaction_commit", r);
}
return (0);
}
static int
fmri_equal(const char *f1, const char *f2)
{
int r;
const char *s1, *i1, *pg1;
const char *s2, *i2, *pg2;
if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
return (-1);
if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
return (-1);
if (s1 == NULL || pg1 != NULL)
return (-1);
if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
return (-2);
if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
return (-2);
if (s2 == NULL || pg2 != NULL)
return (-2);
r = strcmp(s1, s2);
if (r != 0)
return (0);
if (i1 == NULL && i2 == NULL)
return (1);
if (i1 == NULL || i2 == NULL)
return (0);
return (strcmp(i1, i2) == 0);
}
static int
lscf_dependent_import(void *a1, void *pvt)
{
pgroup_t *pgrp = a1;
scf_callback_t *lcbdata = pvt;
int isservice;
int ret;
scf_transaction_entry_t *e;
scf_value_t *val;
scf_callback_t dependent_cbdata;
scf_error_t scfe;
scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
&dependent_cbdata.sc_parent, &isservice);
switch (scfe) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
return (stash_scferror_err(lcbdata, scfe));
case SCF_ERROR_INVALID_ARGUMENT:
semerr(gettext("The FMRI for the \"%s\" dependent is "
"invalid.\n"), pgrp->sc_pgroup_name);
return (stash_scferror_err(lcbdata, scfe));
case SCF_ERROR_CONSTRAINT_VIOLATED:
semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
"specifies neither a service nor an instance.\n"),
pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
return (stash_scferror_err(lcbdata, scfe));
case SCF_ERROR_NOT_FOUND:
scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
&dependent_cbdata.sc_parent, &isservice);
switch (scfe) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
return (stash_scferror_err(lcbdata, scfe));
case SCF_ERROR_NOT_FOUND:
semerr(gettext("The scope in FMRI \"%s\" for the "
"\"%s\" dependent does not exist.\n"),
pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
lcbdata->sc_err = EINVAL;
return (UU_WALK_ERROR);
case SCF_ERROR_PERMISSION_DENIED:
warn(gettext(
"Could not create %s (permission denied).\n"),
pgrp->sc_pgroup_fmri);
return (stash_scferror_err(lcbdata, scfe));
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_CONSTRAINT_VIOLATED:
default:
bad_error("create_entity", scfe);
}
break;
default:
bad_error("fmri_to_entity", scfe);
}
if (lcbdata->sc_trans != NULL) {
e = scf_entry_create(lcbdata->sc_handle);
if (e == NULL) {
if (scf_error() != SCF_ERROR_NO_MEMORY)
bad_error("scf_entry_create", scf_error());
entity_destroy(dependent_cbdata.sc_parent, isservice);
return (stash_scferror(lcbdata));
}
if (scf_transaction_property_new(lcbdata->sc_trans, e,
pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
switch (scf_error()) {
case SCF_ERROR_INVALID_ARGUMENT:
warn(gettext("Dependent of %s has invalid name "
"\"%s\".\n"), pgrp->sc_parent->sc_fmri,
pgrp->sc_pgroup_name);
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
scf_entry_destroy(e);
entity_destroy(dependent_cbdata.sc_parent,
isservice);
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
scf_entry_destroy(e);
entity_destroy(dependent_cbdata.sc_parent,
isservice);
lcbdata->sc_err = EALREADY;
return (UU_WALK_ERROR);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_property_new",
scf_error());
}
}
val = scf_value_create(lcbdata->sc_handle);
if (val == NULL) {
if (scf_error() != SCF_ERROR_NO_MEMORY)
bad_error("scf_value_create", scf_error());
entity_destroy(dependent_cbdata.sc_parent, isservice);
return (stash_scferror(lcbdata));
}
if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
pgrp->sc_pgroup_fmri) != 0)
bad_error("scf_value_set_from_string", scf_error());
if (scf_entry_add_value(e, val) != 0)
bad_error("scf_entry_add_value", scf_error());
}
dependent_cbdata.sc_handle = lcbdata->sc_handle;
dependent_cbdata.sc_flags = lcbdata->sc_flags;
dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
ret = entity_pgroup_import(pgrp, &dependent_cbdata);
entity_destroy(dependent_cbdata.sc_parent, isservice);
if (ret == UU_WALK_NEXT)
return (ret);
if (ret != UU_WALK_ERROR)
bad_error("entity_pgroup_import", ret);
switch (dependent_cbdata.sc_err) {
case ECANCELED:
warn(gettext("%s deleted unexpectedly.\n"),
pgrp->sc_pgroup_fmri);
lcbdata->sc_err = EBUSY;
break;
case EEXIST:
warn(gettext("Could not create \"%s\" dependency in %s "
"(already exists).\n"), pgrp->sc_pgroup_name,
pgrp->sc_pgroup_fmri);
default:
lcbdata->sc_err = dependent_cbdata.sc_err;
}
return (UU_WALK_ERROR);
}
static int upgrade_dependent(const scf_property_t *, const entity_t *,
const scf_snaplevel_t *, scf_transaction_t *);
static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
const pgroup_t *);
static int
upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
const scf_snaplevel_t *snpl, const entity_t *ient,
const scf_snaplevel_t *running, void *ent)
{
pgroup_t *new_dpt_pgroup;
scf_callback_t cbdata;
int r, unseen, tx_started = 0;
int have_cur_depts;
const char * const dependents = "dependents";
const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
return (0);
have_cur_depts = 1;
if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("entity_get_pg", scf_error());
}
have_cur_depts = 0;
}
ud_run_dpts_pg_set = 0;
if (running != NULL)
r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
else
r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
if (r == 0) {
ud_run_dpts_pg_set = 1;
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
default:
bad_error(running ? "scf_snaplevel_get_pg" :
"entity_get_pg", scf_error());
}
}
if (uu_list_walk(ient->sc_dependents, clear_int,
(void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
bad_error("uu_list_walk", uu_error());
if (li_dpts_pg != NULL) {
if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
}
if (have_cur_depts &&
scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri,
dependents);
return (EBUSY);
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_mod_perm, dependents,
ient->sc_fmri);
return (scferror2errno(scf_error()));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_IN_USE:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_start", scf_error());
}
}
tx_started = have_cur_depts;
for (;;) {
r = scf_iter_next_property(ud_iter, ud_dpt_prop);
if (r == 0)
break;
if (r == 1) {
r = upgrade_dependent(ud_dpt_prop, ient, snpl,
tx_started ? ud_tx : NULL);
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)
scf_transaction_destroy_children(ud_tx);
return (r);
}
if (r != -1)
bad_error("scf_iter_next_property", r);
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = ENODEV;
break;
case SCF_ERROR_CONNECTION_BROKEN:
r = ECONNABORTED;
break;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("scf_iter_next_property",
scf_error());
}
if (tx_started)
scf_transaction_destroy_children(ud_tx);
return (r);
}
}
unseen = 0;
for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
new_dpt_pgroup != NULL;
new_dpt_pgroup = uu_list_next(ient->sc_dependents,
new_dpt_pgroup)) {
if (!new_dpt_pgroup->sc_pgroup_seen) {
unseen = 1;
break;
}
}
if (unseen == 0)
goto commit;
cbdata.sc_handle = g_hndl;
cbdata.sc_parent = ent;
cbdata.sc_service = issvc;
cbdata.sc_flags = 0;
if (!have_cur_depts) {
if (issvc)
r = scf_service_add_pg(ent, dependents,
SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
else
r = scf_instance_add_pg(ent, dependents,
SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NO_RESOURCES:
return (scferror2errno(scf_error()));
case SCF_ERROR_EXISTS:
warn(emsg_pg_added, ient->sc_fmri, dependents);
return (EBUSY);
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_add_perm, dependents,
ient->sc_fmri);
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_add_pg", scf_error());
}
}
}
cbdata.sc_trans = ud_tx;
if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_BACKEND_READONLY:
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri, dependents);
return (EBUSY);
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
return (scferror2errno(scf_error()));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_IN_USE:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_start", scf_error());
}
}
tx_started = 1;
for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
new_dpt_pgroup != NULL;
new_dpt_pgroup = uu_list_next(ient->sc_dependents,
new_dpt_pgroup)) {
if (new_dpt_pgroup->sc_pgroup_seen)
continue;
if (ud_run_dpts_pg_set) {
if (scf_pg_get_property(ud_run_dpts_pg,
new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
r = handle_dependent_conflict(ient, ud_prop,
new_dpt_pgroup);
switch (r) {
case 0:
continue;
case ECONNABORTED:
case ENOMEM:
case EBUSY:
case EBADF:
case EINVAL:
scf_transaction_destroy_children(ud_tx);
return (r);
default:
bad_error("handle_dependent_conflict",
r);
}
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_INVALID_ARGUMENT:
warn(emsg_fmri_invalid_pg_name,
ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name);
scf_transaction_destroy_children(ud_tx);
return (EINVAL);
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name);
scf_transaction_destroy_children(ud_tx);
return (EBUSY);
case SCF_ERROR_CONNECTION_BROKEN:
scf_transaction_destroy_children(ud_tx);
return (ECONNABORTED);
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_get_property",
scf_error());
}
}
}
r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
if (r != UU_WALK_NEXT) {
if (r != UU_WALK_ERROR)
bad_error("lscf_dependent_import", r);
if (cbdata.sc_err == EALREADY) {
bad_error("lscf_dependent_import",
cbdata.sc_err);
}
scf_transaction_destroy_children(ud_tx);
return (cbdata.sc_err);
}
}
commit:
if (!tx_started)
return (0);
r = scf_transaction_commit(ud_tx);
scf_transaction_destroy_children(ud_tx);
switch (r) {
case 1:
return (0);
case 0:
warn(emsg_pg_changed, ient->sc_fmri, dependents);
return (EBUSY);
case -1:
break;
default:
bad_error("scf_transaction_commit", r);
}
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NO_RESOURCES:
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri, dependents);
return (EBUSY);
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_destroy", scf_error());
}
}
static int
upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
const scf_snaplevel_t *running, void *ent)
{
scf_propertygroup_t *ud_mfsts_pg = NULL;
scf_property_t *ud_prop = NULL;
scf_iter_t *ud_prop_iter;
scf_value_t *fname_value;
scf_callback_t cbdata;
pgroup_t *mfst_pgroup;
property_t *mfst_prop;
property_t *old_prop;
char *pname;
char *fval;
char *old_pname;
char *old_fval;
int no_upgrade_pg;
int mfst_seen;
int r;
const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
ud_mfsts_pg = scf_pg_create(g_hndl);
ud_prop = scf_property_create(g_hndl);
ud_prop_iter = scf_iter_create(g_hndl);
fname_value = scf_value_create(g_hndl);
no_upgrade_pg = 0;
r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
ud_mfsts_pg);
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
no_upgrade_pg = 1;
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
default:
bad_error(running ? "scf_snaplevel_get_pg" :
"entity_get_pg", scf_error());
}
}
if (no_upgrade_pg) {
cbdata.sc_handle = g_hndl;
cbdata.sc_parent = ent;
cbdata.sc_service = issvc;
cbdata.sc_flags = SCI_FORCE;
cbdata.sc_source_fmri = ient->sc_fmri;
cbdata.sc_target_fmri = ient->sc_fmri;
if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
return (cbdata.sc_err);
return (0);
}
mfst_pgroup = internal_pgroup_find_or_create(ient,
SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
assert(mfst_pgroup != NULL);
if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
SCF_SUCCESS)
return (-1);
if ((pname = malloc(MAXPATHLEN)) == NULL)
return (ENOMEM);
if ((fval = malloc(MAXPATHLEN)) == NULL) {
free(pname);
return (ENOMEM);
}
while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
mfst_seen = 0;
if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
continue;
for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
mfst_prop != NULL;
mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
mfst_prop)) {
if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
mfst_seen = 1;
}
}
if (mfst_seen == 0) {
if (prop_get_val(ud_prop, fname_value) == 0 &&
scf_value_get_astring(fname_value, fval,
MAXPATHLEN) != -1) {
old_pname = safe_strdup(pname);
old_fval = safe_strdup(fval);
old_prop = internal_property_create(old_pname,
SCF_TYPE_ASTRING, 1, old_fval);
(void) internal_attach_property(mfst_pgroup,
old_prop);
}
}
}
free(pname);
free(fval);
cbdata.sc_handle = g_hndl;
cbdata.sc_parent = ent;
cbdata.sc_service = issvc;
cbdata.sc_flags = SCI_FORCE;
cbdata.sc_source_fmri = ient->sc_fmri;
cbdata.sc_target_fmri = ient->sc_fmri;
if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
return (cbdata.sc_err);
return (r);
}
static int
upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
const scf_snaplevel_t *snpl, scf_transaction_t *tx)
{
pgroup_t pgrp;
scf_type_t ty;
pgroup_t *new_dpt_pgroup;
pgroup_t *old_dpt_pgroup = NULL;
pgroup_t *current_pg;
pgroup_t *dpt;
scf_callback_t cbdata;
int tissvc;
void *target_ent;
scf_error_t serr;
int r;
scf_transaction_entry_t *ent;
const char * const cf_inval = gettext("Conflict upgrading %s "
"(dependent \"%s\" has invalid dependents property).\n");
const char * const cf_missing = gettext("Conflict upgrading %s "
"(dependent \"%s\" is missing).\n");
const char * const cf_newdpg = gettext("Conflict upgrading %s "
"(dependent \"%s\" has new dependency property group).\n");
const char * const cf_newtarg = gettext("Conflict upgrading %s "
"(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");
const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
"corrupt (missing snaplevel).\n");
if (scf_property_type(prop, &ty) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_property_type", scf_error());
}
}
if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
warn(li_corrupt, ient->sc_fmri);
return (EBADF);
}
if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_property_get_name", scf_error());
}
}
pgrp.sc_pgroup_name = ud_name;
new_dpt_pgroup =
uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
if (new_dpt_pgroup == NULL) {
if (!ud_run_dpts_pg_set)
return (0);
if (scf_property_get_value(prop, ud_val) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_CONSTRAINT_VIOLATED:
warn(li_corrupt, ient->sc_fmri);
return (EBADF);
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_PERMISSION_DENIED:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
if (scf_value_get_as_string(ud_val, ud_oldtarg,
max_scf_value_len + 1) < 0)
bad_error("scf_value_get_as_string", scf_error());
if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (0);
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri,
"dependents");
return (EBUSY);
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_get_property", scf_error());
}
}
if (scf_property_get_value(ud_prop, ud_val) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_CONSTRAINT_VIOLATED:
warn(cf_inval, ient->sc_fmri, ud_name);
return (0);
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_PERMISSION_DENIED:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
ty = scf_value_type(ud_val);
assert(ty != SCF_TYPE_INVALID);
if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
warn(cf_inval, ient->sc_fmri, ud_name);
return (0);
}
if (scf_value_get_as_string(ud_val, ud_ctarg,
max_scf_value_len + 1) < 0)
bad_error("scf_value_get_as_string", scf_error());
r = fmri_equal(ud_ctarg, ud_oldtarg);
switch (r) {
case 1:
break;
case 0:
case -1:
warn(cf_newtarg, ient->sc_fmri, ud_name);
return (0);
case -2:
warn(li_corrupt, ient->sc_fmri);
return (EBADF);
default:
bad_error("fmri_equal", r);
}
if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
warn(li_corrupt, ient->sc_fmri);
return (EBADF);
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_snaplevel_get_pg", scf_error());
}
}
r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
snap_lastimport);
switch (r) {
case 0:
break;
case ECANCELED:
case ECONNABORTED:
case ENOMEM:
case EBADF:
return (r);
case EACCES:
default:
bad_error("load_pg", r);
}
serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
internal_pgroup_free(old_dpt_pgroup);
return (ENOMEM);
case SCF_ERROR_NOT_FOUND:
internal_pgroup_free(old_dpt_pgroup);
goto delprop;
case SCF_ERROR_CONSTRAINT_VIOLATED:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("fmri_to_entity", serr);
}
r = entity_get_running_pg(target_ent, tissvc, ud_name,
ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
switch (r) {
case 0:
break;
case ECONNABORTED:
internal_pgroup_free(old_dpt_pgroup);
return (r);
case ECANCELED:
case ENOENT:
internal_pgroup_free(old_dpt_pgroup);
goto delprop;
case EBADF:
warn(r_no_lvl, ud_ctarg);
internal_pgroup_free(old_dpt_pgroup);
return (r);
case EINVAL:
default:
bad_error("entity_get_running_pg", r);
}
r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
switch (r) {
case 0:
break;
case ECANCELED:
internal_pgroup_free(old_dpt_pgroup);
goto delprop;
case ECONNABORTED:
case ENOMEM:
case EBADF:
internal_pgroup_free(old_dpt_pgroup);
return (r);
case EACCES:
default:
bad_error("load_pg", r);
}
if (!pg_equal(old_dpt_pgroup, current_pg)) {
warn(cf_newdpg, ient->sc_fmri, ud_name);
internal_pgroup_free(old_dpt_pgroup);
internal_pgroup_free(current_pg);
return (0);
}
internal_pgroup_free(old_dpt_pgroup);
internal_pgroup_free(current_pg);
if (g_verbose)
warn(gettext("%s: Deleting dependent \"%s\".\n"),
ient->sc_fmri, ud_name);
if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
internal_pgroup_free(old_dpt_pgroup);
goto delprop;
case SCF_ERROR_CONNECTION_BROKEN:
internal_pgroup_free(old_dpt_pgroup);
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("entity_get_pg", scf_error());
}
}
if (scf_pg_delete(ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
return (scferror2errno(scf_error()));
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_delete", scf_error());
}
}
dpt = internal_pgroup_new();
if (dpt == NULL)
return (ENOMEM);
dpt->sc_pgroup_name = strdup(ud_name);
dpt->sc_pgroup_fmri = strdup(ud_ctarg);
if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
return (ENOMEM);
dpt->sc_parent = (entity_t *)ient;
if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
uu_die(gettext("libuutil error: %s\n"),
uu_strerror(uu_error()));
delprop:
if (tx == NULL)
return (0);
ent = scf_entry_create(g_hndl);
if (ent == NULL)
return (ENOMEM);
if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
scf_entry_destroy(ent);
switch (scf_error()) {
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri,
"dependents");
return (EBUSY);
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_property_delete",
scf_error());
}
}
return (0);
}
new_dpt_pgroup->sc_pgroup_seen = 1;
if (scf_property_get_value(prop, ud_val) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_CONSTRAINT_VIOLATED:
warn(li_corrupt, ient->sc_fmri);
return (EBADF);
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_PERMISSION_DENIED:
default:
bad_error("scf_property_get_value", scf_error());
}
}
if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
0)
bad_error("scf_value_get_as_string", scf_error());
r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
switch (r) {
case 0:
dpt = internal_pgroup_new();
if (dpt == NULL)
return (ENOMEM);
dpt->sc_pgroup_name = strdup(ud_name);
dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
return (ENOMEM);
dpt->sc_parent = (entity_t *)ient;
if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
uu_die(gettext("libuutil error: %s\n"),
uu_strerror(uu_error()));
break;
case 1:
if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
warn(li_corrupt, ient->sc_fmri);
return (EBADF);
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_snaplevel_get_pg", scf_error());
}
}
r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
snap_lastimport);
switch (r) {
case 0:
break;
case ECANCELED:
case ECONNABORTED:
case ENOMEM:
case EBADF:
return (r);
case EACCES:
default:
bad_error("load_pg", r);
}
if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
internal_pgroup_free(old_dpt_pgroup);
return (0);
}
break;
case -1:
warn(li_corrupt, ient->sc_fmri);
return (EBADF);
case -2:
warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
ud_name, new_dpt_pgroup->sc_pgroup_fmri);
return (EINVAL);
default:
bad_error("fmri_equal", r);
}
if (new_dpt_pgroup->sc_pgroup_override) {
(void) strcpy(ud_ctarg, ud_oldtarg);
goto nocust;
}
if (!ud_run_dpts_pg_set) {
warn(cf_missing, ient->sc_fmri, ud_name);
r = 0;
goto out;
} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
warn(cf_missing, ient->sc_fmri, ud_name);
r = 0;
goto out;
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
r = EBUSY;
goto out;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_get_property", scf_error());
}
}
if (scf_property_get_value(ud_prop, ud_val) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_CONSTRAINT_VIOLATED:
warn(cf_inval, ient->sc_fmri, ud_name);
r = 0;
goto out;
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_PERMISSION_DENIED:
default:
bad_error("scf_property_get_value", scf_error());
}
}
ty = scf_value_type(ud_val);
assert(ty != SCF_TYPE_INVALID);
if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
warn(cf_inval, ient->sc_fmri, ud_name);
r = 0;
goto out;
}
if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
0)
bad_error("scf_value_get_as_string", scf_error());
r = fmri_equal(ud_ctarg, ud_oldtarg);
if (r == -1) {
warn(cf_inval, ient->sc_fmri, ud_name);
r = 0;
goto out;
} else if (r == -2) {
warn(li_corrupt, ient->sc_fmri);
r = EBADF;
goto out;
} else if (r == 0) {
r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
if (r == -1) {
warn(cf_inval, ient->sc_fmri, ud_name);
r = 0;
goto out;
} else if (r == 0) {
warn(cf_newtarg, ient->sc_fmri, ud_name);
r = 0;
goto out;
} else if (r != 1) {
bad_error("fmri_equal", r);
}
serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NOT_FOUND:
warn(cf_missing, ient->sc_fmri, ud_name);
r = 0;
goto out;
case SCF_ERROR_NO_MEMORY:
r = ENOMEM;
goto out;
case SCF_ERROR_CONSTRAINT_VIOLATED:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("fmri_to_entity", serr);
}
r = entity_get_running_pg(target_ent, tissvc, ud_name,
ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
switch (r) {
case 0:
break;
case ECONNABORTED:
goto out;
case ECANCELED:
case ENOENT:
warn(cf_missing, ient->sc_fmri, ud_name);
r = 0;
goto out;
case EBADF:
warn(r_no_lvl, ud_ctarg);
goto out;
case EINVAL:
default:
bad_error("entity_get_running_pg", r);
}
r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
switch (r) {
case 0:
break;
case ECANCELED:
warn(cf_missing, ient->sc_fmri, ud_name);
r = 0;
goto out;
case ECONNABORTED:
case ENOMEM:
case EBADF:
goto out;
case EACCES:
default:
bad_error("load_pg", r);
}
if (!pg_equal(current_pg, new_dpt_pgroup))
warn(cf_newdpg, ient->sc_fmri, ud_name);
internal_pgroup_free(current_pg);
r = 0;
goto out;
} else if (r != 1) {
bad_error("fmri_equal", r);
}
nocust:
if (old_dpt_pgroup == NULL) {
if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
warn(li_corrupt, ient->sc_fmri);
return (EBADF);
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_snaplevel_get_pg", scf_error());
}
}
r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
snap_lastimport);
switch (r) {
case 0:
break;
case ECANCELED:
case ECONNABORTED:
case ENOMEM:
case EBADF:
return (r);
case EACCES:
default:
bad_error("load_pg", r);
}
}
serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NOT_FOUND:
warn(cf_missing, ient->sc_fmri, ud_name);
r = 0;
goto out;
case SCF_ERROR_NO_MEMORY:
r = ENOMEM;
goto out;
case SCF_ERROR_CONSTRAINT_VIOLATED:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("fmri_to_entity", serr);
}
r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
ud_iter2, ud_inst, imp_snap, ud_snpl);
switch (r) {
case 0:
break;
case ECONNABORTED:
goto out;
case ECANCELED:
case ENOENT:
warn(cf_missing, ient->sc_fmri, ud_name);
r = 0;
goto out;
case EBADF:
warn(r_no_lvl, ud_ctarg);
goto out;
case EINVAL:
default:
bad_error("entity_get_running_pg", r);
}
r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
switch (r) {
case 0:
break;
case ECANCELED:
warn(cf_missing, ient->sc_fmri, ud_name);
goto out;
case ECONNABORTED:
case ENOMEM:
case EBADF:
goto out;
case EACCES:
default:
bad_error("load_pg", r);
}
if (!pg_equal(current_pg, old_dpt_pgroup)) {
if (!pg_equal(current_pg, new_dpt_pgroup))
warn(cf_newdpg, ient->sc_fmri, ud_name);
internal_pgroup_free(current_pg);
r = 0;
goto out;
}
r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
switch (r) {
case 1:
if (pg_equal(current_pg, new_dpt_pgroup)) {
internal_pgroup_free(current_pg);
r = 0;
goto out;
}
internal_pgroup_free(current_pg);
if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
warn(cf_missing, ient->sc_fmri, ud_name);
r = 0;
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("entity_get_pg", scf_error());
}
if (tissvc)
r = scf_service_add_pg(target_ent, ud_name,
SCF_GROUP_DEPENDENCY, 0, ud_pg);
else
r = scf_instance_add_pg(target_ent, ud_name,
SCF_GROUP_DEPENDENCY, 0, ud_pg);
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
warn(cf_missing, ient->sc_fmri,
ud_name);
r = 0;
goto out;
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_deleted, ud_ctarg,
ud_name);
r = EPERM;
goto out;
case SCF_ERROR_EXISTS:
warn(emsg_pg_added, ud_ctarg, ud_name);
r = EBUSY;
goto out;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("entity_add_pg", scf_error());
}
}
}
r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL);
switch (r) {
case 0:
break;
case ECANCELED:
warn(cf_missing, ient->sc_fmri, ud_name);
goto out;
case ECONNABORTED:
case ENOMEM:
case EBADF:
goto out;
case EACCES:
default:
bad_error("load_pg", r);
}
if (g_verbose)
warn(upgrading, ient->sc_fmri, ud_name);
r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
new_dpt_pgroup, 0, ient->sc_fmri);
switch (r) {
case 0:
break;
case ECANCELED:
warn(emsg_pg_deleted, ud_ctarg, ud_name);
r = EBUSY;
goto out;
case EPERM:
warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
goto out;
case EBUSY:
warn(emsg_pg_changed, ud_ctarg, ud_name);
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: {
scf_transaction_entry_t *ent;
scf_value_t *val;
internal_pgroup_free(current_pg);
if (g_verbose)
warn(upgrading, ient->sc_fmri, ud_name);
if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
warn(cf_missing, ient->sc_fmri, ud_name);
r = 0;
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("entity_get_pg", scf_error());
}
} else if (scf_pg_delete(ud_pg) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_delete", scf_error());
}
}
cbdata.sc_handle = g_hndl;
cbdata.sc_trans = NULL;
cbdata.sc_flags = 0;
r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
if (r != UU_WALK_NEXT) {
if (r != UU_WALK_ERROR)
bad_error("lscf_dependent_import", r);
r = cbdata.sc_err;
goto out;
}
if (tx == NULL)
break;
if ((ent = scf_entry_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL) {
if (scf_error() == SCF_ERROR_NO_MEMORY)
return (ENOMEM);
bad_error("scf_entry_create", scf_error());
}
if (scf_transaction_property_change_type(tx, ent, ud_name,
SCF_TYPE_FMRI) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri,
"dependents");
r = EBUSY;
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_property_"
"change_type", scf_error());
}
if (scf_transaction_property_new(tx, ent, ud_name,
SCF_TYPE_FMRI) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri,
"dependents");
r = EBUSY;
goto out;
case SCF_ERROR_EXISTS:
warn(emsg_pg_changed, ient->sc_fmri,
"dependents");
r = EBUSY;
goto out;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_transaction_property_"
"new", scf_error());
}
}
}
if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
new_dpt_pgroup->sc_pgroup_fmri) != 0)
bad_error("scf_value_set_from_string",
scf_error());
if (scf_entry_add_value(ent, val) != 0)
bad_error("scf_entry_add_value", scf_error());
break;
}
case -2:
warn(li_corrupt, ient->sc_fmri);
internal_pgroup_free(current_pg);
r = EBADF;
goto out;
case -1:
default:
bad_error("fmri_equal", r);
}
r = 0;
out:
if (old_dpt_pgroup != NULL)
internal_pgroup_free(old_dpt_pgroup);
return (r);
}
static int
handle_dependent_conflict(const entity_t * const ient,
const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
{
int r;
scf_type_t ty;
scf_error_t scfe;
void *tptr;
int tissvc;
pgroup_t *pgroup;
if (scf_property_get_value(prop, ud_val) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
warn(emsg_pg_deleted, ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name);
return (EBUSY);
case SCF_ERROR_CONSTRAINT_VIOLATED:
case SCF_ERROR_NOT_FOUND:
warn(gettext("Conflict upgrading %s (not importing "
"dependent \"%s\" because it already exists.) "
"Warning: The \"%s/%2$s\" property has more or "
"fewer than one value)).\n"), ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name, "dependents");
return (0);
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_PERMISSION_DENIED:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
ty = scf_value_type(ud_val);
assert(ty != SCF_TYPE_INVALID);
if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
warn(gettext("Conflict upgrading %s (not importing dependent "
"\"%s\" because it already exists). Warning: The "
"\"%s/%s\" property has unexpected type \"%s\")).\n"),
ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
scf_type_to_string(ty), "dependents");
return (0);
}
if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
0)
bad_error("scf_value_get_as_string", scf_error());
r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
switch (r) {
case 0:
warn(gettext("Conflict upgrading %s (not importing dependent "
"\"%s\" (target \"%s\") because it already exists with "
"target \"%s\").\n"), ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name,
new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
return (0);
case 1:
break;
case -1:
warn(gettext("Conflict upgrading %s (not importing dependent "
"\"%s\" because it already exists). Warning: The current "
"dependent's target (%s) is invalid.\n"), ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
return (0);
case -2:
warn(gettext("Dependent \"%s\" of %s has invalid target "
"\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_fmri);
return (EINVAL);
default:
bad_error("fmri_equal", r);
}
scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
switch (scfe) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
return (ENOMEM);
case SCF_ERROR_NOT_FOUND:
warn(emsg_dpt_dangling, ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
return (0);
case SCF_ERROR_CONSTRAINT_VIOLATED:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("fmri_to_entity", scfe);
}
r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
switch (r) {
case 0:
break;
case ECONNABORTED:
return (r);
case ECANCELED:
warn(emsg_dpt_dangling, ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
return (0);
case EBADF:
if (tissvc)
warn(gettext("%s has an instance with a \"%s\" "
"snapshot which is missing a snaplevel.\n"),
ud_ctarg, "running");
else
warn(gettext("%s has a \"%s\" snapshot which is "
"missing a snaplevel.\n"), ud_ctarg, "running");
case ENOENT:
warn(emsg_dpt_no_dep, ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
new_dpt_pgroup->sc_pgroup_name);
return (0);
case EINVAL:
default:
bad_error("entity_get_running_pg", r);
}
pgroup = internal_pgroup_new();
if (pgroup == NULL)
return (ENOMEM);
r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
switch (r) {
case 0:
break;
case ECONNABORTED:
case EBADF:
case ENOMEM:
internal_pgroup_free(pgroup);
return (r);
case ECANCELED:
warn(emsg_dpt_no_dep, ient->sc_fmri,
new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
new_dpt_pgroup->sc_pgroup_name);
internal_pgroup_free(pgroup);
return (0);
case EACCES:
default:
bad_error("load_pg", r);
}
report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
internal_pgroup_free(pgroup);
return (0);
}
static int
process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
const scf_snaplevel_t *running)
{
int r;
pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
scf_callback_t cbdata;
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");
const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_pg_get_type", scf_error());
}
}
if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
if (scf_pg_get_property(lipg, "external", NULL) == 0)
return (0);
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_DELETED:
return (ENODEV);
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_get_property", scf_error());
}
}
if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_pg_get_name", scf_error());
}
}
pgrp.sc_pgroup_name = imp_str;
mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
if (mpg != NULL)
mpg->sc_pgroup_seen = 1;
if (strcmp(imp_str, "dependents") == 0)
return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
return (upgrade_manifestfiles(NULL, ient, running, ent));
if (mpg == NULL || mpg->sc_pgroup_delete) {
if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (0);
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("entity_get_pg", scf_error());
}
}
if (mpg != NULL && mpg->sc_pgroup_delete) {
if (g_verbose)
warn(deleting, ient->sc_fmri, imp_str);
if (scf_pg_delete(imp_pg2) == 0)
return (0);
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (0);
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
return (scferror2errno(scf_error()));
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
return (scferror2errno(scf_error()));
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_pg_delete", scf_error());
}
}
r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
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);
}
r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
switch (r) {
case 0:
break;
case ECANCELED:
case ECONNABORTED:
case ENOMEM:
case EBADF:
case EACCES:
internal_pgroup_free(lipg_i);
return (r);
default:
bad_error("load_pg", r);
}
if (pg_equal(lipg_i, curpg_i)) {
if (g_verbose)
warn(deleting, ient->sc_fmri, imp_str);
if (scf_pg_delete(imp_pg2) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_CONNECTION_BROKEN:
internal_pgroup_free(lipg_i);
internal_pgroup_free(curpg_i);
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_pg_delete", scf_error());
}
}
} else {
report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
}
internal_pgroup_free(lipg_i);
internal_pgroup_free(curpg_i);
return (0);
}
assert(!mpg->sc_pgroup_override);
r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
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);
}
if (pg_equal(mpg, lipg_i)) {
r = 0;
goto out;
}
if (running != NULL)
r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
else
r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
if (r != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_DELETED:
if (running != NULL)
r = ENODEV;
else
r = ECANCELED;
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("entity_get_pg", scf_error());
}
warn(cf_pg_missing, ient->sc_fmri, imp_str);
r = 0;
goto out;
}
r = load_pg_attrs(imp_pg2, &curpg_i);
switch (r) {
case 0:
break;
case ECANCELED:
warn(cf_pg_missing, ient->sc_fmri, imp_str);
r = 0;
goto out;
case ECONNABORTED:
case ENOMEM:
goto out;
default:
bad_error("load_pg_attrs", r);
}
if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
internal_pgroup_free(curpg_i);
r = 0;
goto out;
}
internal_pgroup_free(curpg_i);
r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
switch (r) {
case 0:
break;
case ECANCELED:
warn(cf_pg_missing, ient->sc_fmri, imp_str);
r = 0;
goto out;
case ECONNABORTED:
case EBADF:
case ENOMEM:
case EACCES:
goto out;
default:
bad_error("load_pg", r);
}
if (pg_equal(lipg_i, curpg_i) &&
!pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
int do_delete = 1;
if (g_verbose)
warn(gettext("%s: Upgrading property group \"%s\".\n"),
ient->sc_fmri, mpg->sc_pgroup_name);
internal_pgroup_free(curpg_i);
if (running != NULL &&
entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
r = ECANCELED;
goto out;
case SCF_ERROR_NOT_FOUND:
do_delete = 0;
break;
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("entity_get_pg", scf_error());
}
}
if (do_delete && scf_pg_delete(imp_pg2) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_PERMISSION_DENIED:
warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
ient->sc_fmri);
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_pg_delete", scf_error());
}
}
cbdata.sc_handle = g_hndl;
cbdata.sc_parent = ent;
cbdata.sc_service = issvc;
cbdata.sc_flags = 0;
cbdata.sc_source_fmri = ient->sc_fmri;
cbdata.sc_target_fmri = ient->sc_fmri;
r = entity_pgroup_import(mpg, &cbdata);
switch (r) {
case UU_WALK_NEXT:
r = 0;
goto out;
case UU_WALK_ERROR:
if (cbdata.sc_err == EEXIST) {
warn(emsg_pg_added, ient->sc_fmri,
mpg->sc_pgroup_name);
r = EBUSY;
} else {
r = cbdata.sc_err;
}
goto out;
default:
bad_error("entity_pgroup_import", r);
}
}
if (running != NULL &&
entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_DELETED:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("entity_get_pg", scf_error());
}
cbdata.sc_handle = g_hndl;
cbdata.sc_parent = ent;
cbdata.sc_service = issvc;
cbdata.sc_flags = SCI_FORCE;
cbdata.sc_source_fmri = ient->sc_fmri;
cbdata.sc_target_fmri = ient->sc_fmri;
r = entity_pgroup_import(mpg, &cbdata);
switch (r) {
case UU_WALK_NEXT:
r = 0;
goto out;
case UU_WALK_ERROR:
if (cbdata.sc_err == EEXIST) {
warn(emsg_pg_added, ient->sc_fmri,
mpg->sc_pgroup_name);
r = EBUSY;
} else {
r = cbdata.sc_err;
}
goto out;
default:
bad_error("entity_pgroup_import", r);
}
}
r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
internal_pgroup_free(curpg_i);
switch (r) {
case 0:
ient->sc_import_state = IMPORT_PROP_BEGUN;
break;
case ECANCELED:
warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
r = EBUSY;
break;
case EPERM:
warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
break;
case EBUSY:
warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
break;
case ECONNABORTED:
case ENOMEM:
case ENOSPC:
case EROFS:
case EACCES:
case EINVAL:
break;
default:
bad_error("upgrade_pg", r);
}
out:
internal_pgroup_free(lipg_i);
return (r);
}
static int
upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
entity_t *ient)
{
pgroup_t *pg, *rpg;
int r;
uu_list_t *pgs = ient->sc_pgroups;
const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
if (uu_list_walk(pgs, clear_int,
(void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
bad_error("uu_list_walk", uu_error());
if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("scf_iter_snaplevel_pgs", scf_error());
}
}
for (;;) {
r = scf_iter_next_pg(imp_up_iter, imp_pg);
if (r == 0)
break;
if (r == 1) {
r = process_old_pg(imp_pg, ient, ent, running);
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);
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("scf_iter_next_pg", scf_error());
}
}
for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
if (pg->sc_pgroup_seen)
continue;
if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
r = upgrade_dependents(NULL, imp_snpl, ient, running,
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;
}
if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
r = upgrade_manifestfiles(pg, ient, running, 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_manifestfiles", r);
}
continue;
}
if (running != NULL) {
r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
imp_pg);
} else {
r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
imp_pg);
}
if (r != 0) {
scf_callback_t cbdata;
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_CONNECTION_BROKEN:
return (scferror2errno(scf_error()));
case SCF_ERROR_DELETED:
if (running != NULL)
return (ENODEV);
else
return (scferror2errno(scf_error()));
case SCF_ERROR_INVALID_ARGUMENT:
warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
pg->sc_pgroup_name);
return (EINVAL);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("entity_get_pg", scf_error());
}
cbdata.sc_handle = g_hndl;
cbdata.sc_parent = ent;
cbdata.sc_service = issvc;
cbdata.sc_flags = SCI_FORCE;
cbdata.sc_source_fmri = ient->sc_fmri;
cbdata.sc_target_fmri = ient->sc_fmri;
r = entity_pgroup_import(pg, &cbdata);
switch (r) {
case UU_WALK_NEXT:
ient->sc_import_state = IMPORT_PROP_BEGUN;
continue;
case UU_WALK_ERROR:
if (cbdata.sc_err == EEXIST) {
warn(emsg_pg_added, ient->sc_fmri,
pg->sc_pgroup_name);
return (EBUSY);
}
return (cbdata.sc_err);
default:
bad_error("entity_pgroup_import", r);
}
}
r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
switch (r) {
case 0:
break;
case ECANCELED:
warn(emsg_pg_deleted, ient->sc_fmri,
pg->sc_pgroup_name);
return (EBUSY);
case ECONNABORTED:
case EBADF:
case ENOMEM:
case EACCES:
return (r);
default:
bad_error("load_pg", r);
}
report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
internal_pgroup_free(rpg);
rpg = NULL;
}
return (0);
}
static int
lscf_instance_import(void *v, void *pvt)
{
entity_t *inst = v;
scf_callback_t ctx;
scf_callback_t *lcbdata = pvt;
scf_service_t *rsvc = lcbdata->sc_parent;
int r;
scf_snaplevel_t *running;
int flags = lcbdata->sc_flags;
const char * const emsg_tdel =
gettext("Temporary instance svc:/%s:%s was deleted.\n");
const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
"changed unexpectedly.\n");
const char * const emsg_del = gettext("%s changed unexpectedly "
"(instance \"%s\" was deleted.)\n");
const char * const emsg_badsnap = gettext(
"\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
warn(gettext("Temporary service svc:/%s "
"changed unexpectedly (instance \"%s\" added).\n"),
imp_tsname, inst->sc_name);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
case SCF_ERROR_DELETED:
warn(gettext("Temporary service svc:/%s "
"was deleted unexpectedly.\n"), imp_tsname);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
case SCF_ERROR_INVALID_ARGUMENT:
warn(gettext("Invalid instance name \"%s\".\n"),
inst->sc_name);
return (stash_scferror(lcbdata));
case SCF_ERROR_PERMISSION_DENIED:
warn(gettext("Could not create temporary instance "
"\"%s\" in svc:/%s (permission denied).\n"),
inst->sc_name, imp_tsname);
return (stash_scferror(lcbdata));
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_add_instance", scf_error());
}
}
r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
inst->sc_name);
if (r < 0)
bad_error("snprintf", errno);
r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
lcbdata->sc_flags | SCI_NOENABLED);
switch (r) {
case 0:
break;
case ECANCELED:
warn(emsg_tdel, imp_tsname, inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case EEXIST:
warn(emsg_tchg, imp_tsname, inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case ECONNABORTED:
goto connaborted;
case ENOMEM:
case ENOSPC:
case EPERM:
case EROFS:
case EACCES:
case EINVAL:
case EBUSY:
lcbdata->sc_err = r;
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("lscf_import_instance_pgs", r);
}
r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
inst->sc_name);
if (r < 0)
bad_error("snprintf", errno);
ctx.sc_handle = lcbdata->sc_handle;
ctx.sc_parent = imp_tinst;
ctx.sc_service = 0;
ctx.sc_source_fmri = inst->sc_fmri;
ctx.sc_target_fmri = imp_str;
if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
switch (ctx.sc_err) {
case ECONNABORTED:
goto connaborted;
case ECANCELED:
warn(emsg_tdel, imp_tsname, inst->sc_name);
lcbdata->sc_err = EBUSY;
break;
case EEXIST:
warn(emsg_tchg, imp_tsname, inst->sc_name);
lcbdata->sc_err = EBUSY;
break;
default:
lcbdata->sc_err = ctx.sc_err;
}
r = UU_WALK_ERROR;
goto deltemp;
}
if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
warn(emsg_tchg, imp_tsname, inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_PERMISSION_DENIED:
warn(gettext("Could not take \"%s\" snapshot of %s "
"(permission denied).\n"), snap_lastimport,
imp_str);
r = stash_scferror(lcbdata);
goto deltemp;
default:
scfwarn();
lcbdata->sc_err = -1;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
bad_error("_scf_snapshot_take_new_named", scf_error());
}
}
if (lcbdata->sc_flags & SCI_FRESH)
goto fresh;
if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
imp_lisnap) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
warn(emsg_del, inst->sc_parent->sc_fmri,
inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_NOT_FOUND:
flags |= SCI_FORCE;
goto nosnap;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
}
if (uu_list_walk(inst->sc_pgroups, clear_int,
(void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
0)
bad_error("uu_list_walk", uu_error());
r = get_snaplevel(imp_lisnap, 0, imp_snpl);
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case ENOENT:
warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
lcbdata->sc_err = EBADF;
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("get_snaplevel", r);
}
if (scf_instance_get_snapshot(imp_inst, snap_running,
imp_rsnap) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
warn(emsg_del, inst->sc_parent->sc_fmri,
inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
running = NULL;
} else {
r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
switch (r) {
case 0:
running = imp_rsnpl;
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
warn(emsg_del, inst->sc_parent->sc_fmri,
inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case ENOENT:
warn(emsg_badsnap, snap_running, inst->sc_fmri);
lcbdata->sc_err = EBADF;
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("get_snaplevel", r);
}
}
r = upgrade_props(imp_inst, running, imp_snpl, inst);
switch (r) {
case 0:
break;
case ECANCELED:
case ENODEV:
warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
lcbdata->sc_err = EBUSY;
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:
lcbdata->sc_err = r;
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("upgrade_props", r);
}
inst->sc_import_state = IMPORT_PROP_DONE;
} else {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_get_instance", scf_error());
}
fresh:
if (scf_service_add_instance(rsvc, inst->sc_name,
imp_inst) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
warn(gettext("%s changed unexpectedly "
"(instance \"%s\" added).\n"),
inst->sc_parent->sc_fmri, inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_PERMISSION_DENIED:
warn(gettext("Could not create \"%s\" instance "
"in %s (permission denied).\n"),
inst->sc_name, inst->sc_parent->sc_fmri);
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_add_instance",
scf_error());
}
}
nosnap:
if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
imp_lisnap) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
warn(gettext("%s changed unexpectedly "
"(snapshot \"%s\" added).\n"),
inst->sc_fmri, snap_lastimport);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_PERMISSION_DENIED:
warn(gettext("Could not take \"%s\" snapshot "
"of %s (permission denied).\n"),
snap_lastimport, inst->sc_fmri);
r = stash_scferror(lcbdata);
goto deltemp;
default:
scfwarn();
lcbdata->sc_err = -1;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INTERNAL:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
bad_error("_scf_snapshot_take_new",
scf_error());
}
}
if (li_only)
goto lionly;
inst->sc_import_state = IMPORT_PROP_BEGUN;
r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
flags);
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
warn(gettext("%s changed unexpectedly "
"(instance \"%s\" deleted).\n"),
inst->sc_parent->sc_fmri, inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case EEXIST:
warn(gettext("%s changed unexpectedly "
"(property group added).\n"), inst->sc_fmri);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
default:
lcbdata->sc_err = r;
r = UU_WALK_ERROR;
goto deltemp;
case EINVAL:
bad_error("lscf_import_instance_pgs", r);
}
ctx.sc_parent = imp_inst;
ctx.sc_service = 0;
ctx.sc_trans = NULL;
ctx.sc_flags = 0;
if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
&ctx, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
if (ctx.sc_err == ECONNABORTED)
goto connaborted;
lcbdata->sc_err = ctx.sc_err;
r = UU_WALK_ERROR;
goto deltemp;
}
inst->sc_import_state = IMPORT_PROP_DONE;
if (g_verbose)
warn(gettext("Taking \"%s\" snapshot for %s.\n"),
snap_initial, inst->sc_fmri);
r = take_snap(imp_inst, snap_initial, imp_snap);
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ENOSPC:
case -1:
lcbdata->sc_err = r;
r = UU_WALK_ERROR;
goto deltemp;
case ECANCELED:
warn(gettext("%s changed unexpectedly "
"(instance %s deleted).\n"),
inst->sc_parent->sc_fmri, inst->sc_name);
lcbdata->sc_err = r;
r = UU_WALK_ERROR;
goto deltemp;
case EPERM:
warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
lcbdata->sc_err = r;
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("take_snap", r);
}
}
lionly:
if (lcbdata->sc_flags & SCI_NOSNAP)
goto deltemp;
if (g_verbose)
warn(gettext("Taking \"%s\" snapshot for %s.\n"),
snap_lastimport, inst->sc_fmri);
if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_PERMISSION_DENIED:
warn(gettext("Could not take \"%s\" snapshot for %s "
"(permission denied).\n"), snap_lastimport,
inst->sc_fmri);
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("_scf_snapshot_attach", scf_error());
}
}
inst->sc_import_state = IMPORT_COMPLETE;
r = UU_WALK_NEXT;
deltemp:
if (scf_instance_delete(imp_tinst) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_instance_delete", scf_error());
}
}
return (r);
connaborted:
warn(gettext("Could not delete svc:/%s:%s "
"(repository connection broken).\n"), imp_tsname, inst->sc_name);
lcbdata->sc_err = ECONNABORTED;
return (UU_WALK_ERROR);
}
#ifndef NATIVE_BUILD
static int
lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
{
int ret, err;
struct timespec ts;
char *emi_state;
if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
return (0);
}
if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
warn(gettext("Not validating instance %s:%s because EMI's "
"state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
free(emi_state);
return (0);
}
free(emi_state);
if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
ret = scf_error();
warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
return (ret);
}
if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
!= 0) {
ret = scf_error();
warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
switch (ret) {
case SCF_ERROR_DELETED:
err = ENODEV;
break;
case SCF_ERROR_CONNECTION_BROKEN:
warn(gettext("Lost repository connection\n"));
err = ECONNABORTED;
break;
case SCF_ERROR_NOT_FOUND:
warn(gettext("Instance \"%s\" disappeared out from "
"under us.\n"), inst->sc_name);
err = ENOENT;
break;
default:
bad_error("scf_service_get_instance", ret);
}
return (err);
}
while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
!= SCF_SUCCESS) {
ret = scf_error();
if (ret != SCF_ERROR_NOT_FOUND) {
warn(gettext("Failed to get restarter property "
"group for instance: %s\n"), inst->sc_name);
switch (ret) {
case SCF_ERROR_DELETED:
err = ENODEV;
break;
case SCF_ERROR_CONNECTION_BROKEN:
warn(gettext("Lost repository connection\n"));
err = ECONNABORTED;
break;
default:
bad_error("scf_service_get_instance", ret);
}
return (err);
}
ts.tv_sec = pg_timeout / NANOSEC;
ts.tv_nsec = pg_timeout % NANOSEC;
(void) nanosleep(&ts, NULL);
}
while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
imp_prop)) != 0) {
ret = scf_error();
if (ret != SCF_ERROR_NOT_FOUND) {
warn(gettext("Failed to get property %s from the "
"restarter property group of instance %s\n"),
SCF_PROPERTY_STATE, inst->sc_name);
switch (ret) {
case SCF_ERROR_CONNECTION_BROKEN:
warn(gettext("Lost repository connection\n"));
err = ECONNABORTED;
break;
case SCF_ERROR_DELETED:
err = ENODEV;
break;
default:
bad_error("scf_pg_get_property", ret);
}
return (err);
}
ts.tv_sec = pg_timeout / NANOSEC;
ts.tv_nsec = pg_timeout % NANOSEC;
(void) nanosleep(&ts, NULL);
ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
if (ret != SCF_SUCCESS) {
warn(gettext("Failed to get restarter property "
"group for instance: %s\n"), inst->sc_name);
switch (ret) {
case SCF_ERROR_DELETED:
err = ENODEV;
break;
case SCF_ERROR_CONNECTION_BROKEN:
warn(gettext("Lost repository connection\n"));
err = ECONNABORTED;
break;
default:
bad_error("scf_service_get_instance", ret);
}
return (err);
}
}
return (0);
}
#endif
static int
lscf_service_import(void *v, void *pvt)
{
entity_t *s = v;
scf_callback_t cbdata;
scf_callback_t *lcbdata = pvt;
scf_scope_t *scope = lcbdata->sc_parent;
entity_t *inst, linst;
int r;
int fresh = 0;
scf_snaplevel_t *running;
int have_ge = 0;
boolean_t retried = B_FALSE;
const char * const ts_deleted = gettext("Temporary service svc:/%s "
"was deleted unexpectedly.\n");
const char * const ts_pg_added = gettext("Temporary service svc:/%s "
"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");
const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
"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;
if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
return (stash_scferror(lcbdata));
case SCF_ERROR_INVALID_ARGUMENT:
warn(gettext("\"%s\" is an invalid service name. "
"Cannot import.\n"), s->sc_name);
return (stash_scferror(lcbdata));
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_scope_get_service", scf_error());
}
}
r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
if (r < 0)
bad_error("snprintf", errno);
if (r > max_scf_name_len) {
warn(gettext(
"Service name \"%s\" is too long. Cannot import.\n"),
s->sc_name);
lcbdata->sc_err = EINVAL;
return (UU_WALK_ERROR);
}
retry:
if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
return (stash_scferror(lcbdata));
case SCF_ERROR_EXISTS:
if (!retried) {
lscf_delete(imp_tsname, 0);
retried = B_TRUE;
goto retry;
}
warn(gettext(
"Temporary service \"%s\" must be deleted before "
"this manifest can be imported.\n"), imp_tsname);
return (stash_scferror(lcbdata));
case SCF_ERROR_PERMISSION_DENIED:
warn(gettext("Could not create temporary service "
"\"%s\" (permission denied).\n"), imp_tsname);
return (stash_scferror(lcbdata));
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_scope_add_service", scf_error());
}
}
r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
if (r < 0)
bad_error("snprintf", errno);
cbdata.sc_handle = lcbdata->sc_handle;
cbdata.sc_parent = imp_tsvc;
cbdata.sc_service = 1;
cbdata.sc_source_fmri = s->sc_fmri;
cbdata.sc_target_fmri = imp_str;
cbdata.sc_flags = 0;
if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
lcbdata->sc_err = cbdata.sc_err;
switch (cbdata.sc_err) {
case ECONNABORTED:
goto connaborted;
case ECANCELED:
warn(ts_deleted, imp_tsname);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
case EEXIST:
warn(ts_pg_added, imp_tsname);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
}
r = UU_WALK_ERROR;
goto deltemp;
}
if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
lcbdata->sc_err = cbdata.sc_err;
switch (cbdata.sc_err) {
case ECONNABORTED:
goto connaborted;
case ECANCELED:
warn(ts_deleted, imp_tsname);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
case EEXIST:
warn(ts_pg_added, imp_tsname);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
}
r = UU_WALK_ERROR;
goto deltemp;
}
if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_scope_get_service", scf_error());
}
if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
warn(gettext("Scope \"%s\" changed unexpectedly"
" (service \"%s\" added).\n"),
SCF_SCOPE_LOCAL, s->sc_name);
lcbdata->sc_err = EBUSY;
goto deltemp;
case SCF_ERROR_PERMISSION_DENIED:
warn(gettext("Could not create service \"%s\" "
"(permission denied).\n"), s->sc_name);
goto deltemp;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_scope_add_service", scf_error());
}
}
s->sc_import_state = IMPORT_PROP_BEGUN;
cbdata.sc_handle = lcbdata->sc_handle;
cbdata.sc_parent = imp_svc;
cbdata.sc_service = 1;
cbdata.sc_flags = lcbdata->sc_flags;
cbdata.sc_source_fmri = s->sc_fmri;
cbdata.sc_target_fmri = s->sc_fmri;
if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
&cbdata, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
lcbdata->sc_err = cbdata.sc_err;
switch (cbdata.sc_err) {
case ECONNABORTED:
goto connaborted;
case ECANCELED:
warn(s_deleted, s->sc_fmri);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
case EEXIST:
warn(gettext("%s changed unexpectedly "
"(property group added).\n"), s->sc_fmri);
lcbdata->sc_err = EBUSY;
return (UU_WALK_ERROR);
case EINVAL:
bad_error("entity_pgroup_import",
cbdata.sc_err);
}
r = UU_WALK_ERROR;
goto deltemp;
}
cbdata.sc_trans = NULL;
cbdata.sc_flags = 0;
if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
&cbdata, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
lcbdata->sc_err = cbdata.sc_err;
if (cbdata.sc_err == ECONNABORTED)
goto connaborted;
r = UU_WALK_ERROR;
goto deltemp;
}
s->sc_import_state = IMPORT_PROP_DONE;
fresh = 1;
goto instances;
}
if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
(void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
bad_error("uu_list_walk", uu_error());
if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_DELETED:
warn(s_deleted, s->sc_fmri);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances", scf_error());
}
}
for (;;) {
r = scf_iter_next_instance(imp_iter, imp_inst);
if (r == 0)
break;
if (r != 1) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
warn(s_deleted, s->sc_fmri);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_next_instance",
scf_error());
}
}
if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
continue;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_instance_get_name", scf_error());
}
}
if (g_verbose)
warn(gettext(
"Taking \"%s\" snapshot for svc:/%s:%s.\n"),
snap_previous, s->sc_name, imp_str);
r = take_snap(imp_inst, snap_previous, imp_snap);
switch (r) {
case 0:
break;
case ECANCELED:
continue;
case ECONNABORTED:
goto connaborted;
case EPERM:
warn(gettext("Could not take \"%s\" snapshot of "
"svc:/%s:%s (permission denied).\n"),
snap_previous, s->sc_name, imp_str);
lcbdata->sc_err = r;
return (UU_WALK_ERROR);
case ENOSPC:
case -1:
lcbdata->sc_err = r;
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("take_snap", r);
}
linst.sc_name = imp_str;
inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
&linst, NULL, NULL);
if (inst != NULL) {
inst->sc_import_state = IMPORT_PREVIOUS;
inst->sc_seen = 1;
}
}
for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
inst != NULL;
inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
inst)) {
if (inst->sc_seen)
continue;
if (scf_service_add_instance(imp_svc, inst->sc_name,
imp_inst) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_BACKEND_READONLY:
case SCF_ERROR_BACKEND_ACCESS:
case SCF_ERROR_NO_RESOURCES:
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_EXISTS:
warn(gettext("%s changed unexpectedly "
"(instance \"%s\" added).\n"), s->sc_fmri,
inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_INVALID_ARGUMENT:
warn(gettext("Service \"%s\" has instance with "
"invalid name \"%s\".\n"), s->sc_name,
inst->sc_name);
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_PERMISSION_DENIED:
warn(gettext("Could not create instance \"%s\" "
"in %s (permission denied).\n"),
inst->sc_name, s->sc_fmri);
r = stash_scferror(lcbdata);
goto deltemp;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_service_add_instance",
scf_error());
}
}
if (g_verbose)
warn(gettext("Taking \"%s\" snapshot for "
"new service %s.\n"), snap_previous, inst->sc_fmri);
r = take_snap(imp_inst, snap_previous, imp_snap);
switch (r) {
case 0:
break;
case ECANCELED:
warn(i_deleted, s->sc_fmri, inst->sc_name);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case ECONNABORTED:
goto connaborted;
case EPERM:
warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
lcbdata->sc_err = r;
r = UU_WALK_ERROR;
goto deltemp;
case ENOSPC:
case -1:
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("take_snap", r);
}
}
s->sc_import_state = IMPORT_PREVIOUS;
if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_DELETED:
warn(s_deleted, s->sc_fmri);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances", scf_error());
}
}
for (;;) {
r = scf_iter_next_instance(imp_iter, imp_inst);
if (r == -1) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
warn(s_deleted, s->sc_fmri);
lcbdata->sc_err = EBUSY;
r = UU_WALK_ERROR;
goto deltemp;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_next_instance",
scf_error());
}
}
if (r == 0) {
if (have_ge) {
pgroup_t *mfpg;
scf_callback_t mfcbdata;
li_only = 1;
no_refresh = 1;
mfpg = internal_pgroup_find(s,
SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
if (mfpg) {
mfcbdata.sc_handle = g_hndl;
mfcbdata.sc_parent = imp_svc;
mfcbdata.sc_service = 1;
mfcbdata.sc_flags = SCI_FORCE;
mfcbdata.sc_source_fmri = s->sc_fmri;
mfcbdata.sc_target_fmri = s->sc_fmri;
if (entity_pgroup_import(mfpg,
&mfcbdata) != UU_WALK_NEXT) {
warn(s_mfile_upd, s->sc_fmri);
r = UU_WALK_ERROR;
goto deltemp;
}
}
break;
}
s->sc_import_state = IMPORT_PROP_BEGUN;
cbdata.sc_handle = g_hndl;
cbdata.sc_parent = imp_svc;
cbdata.sc_service = 1;
cbdata.sc_flags = SCI_FORCE;
cbdata.sc_source_fmri = s->sc_fmri;
cbdata.sc_target_fmri = s->sc_fmri;
if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
&cbdata, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
lcbdata->sc_err = cbdata.sc_err;
switch (cbdata.sc_err) {
case ECONNABORTED:
goto connaborted;
case ECANCELED:
warn(s_deleted, s->sc_fmri);
lcbdata->sc_err = EBUSY;
break;
case EINVAL:
case EEXIST:
bad_error("entity_pgroup_import",
cbdata.sc_err);
}
r = UU_WALK_ERROR;
goto deltemp;
}
cbdata.sc_trans = NULL;
cbdata.sc_flags = 0;
if (uu_list_walk(s->sc_dependents,
lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
lcbdata->sc_err = cbdata.sc_err;
if (cbdata.sc_err == ECONNABORTED)
goto connaborted;
r = UU_WALK_ERROR;
goto deltemp;
}
break;
}
if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
imp_snap) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
continue;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
if (have_ge)
continue;
if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
imp_pg) == 0) {
if (scf_pg_get_property(imp_pg,
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_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_CONNECTION_BROKEN:
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;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("scf_instance_get_pg",
scf_error());
}
}
continue;
}
r = get_snaplevel(imp_snap, 1, imp_snpl);
switch (r) {
case 0:
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
continue;
case ENOENT:
if (scf_instance_get_name(imp_inst, imp_str,
imp_str_sz) < 0)
(void) strcpy(imp_str, "?");
warn(badsnap, snap_lastimport, s->sc_name, imp_str);
lcbdata->sc_err = EBADF;
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("get_snaplevel", r);
}
if (scf_instance_get_snapshot(imp_inst, snap_running,
imp_rsnap) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
continue;
case SCF_ERROR_NOT_FOUND:
break;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_instance_get_snapshot",
scf_error());
}
running = NULL;
} else {
r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
switch (r) {
case 0:
running = imp_rsnpl;
break;
case ECONNABORTED:
goto connaborted;
case ECANCELED:
continue;
case ENOENT:
if (scf_instance_get_name(imp_inst, imp_str,
imp_str_sz) < 0)
(void) strcpy(imp_str, "?");
warn(badsnap, snap_running, s->sc_name,
imp_str);
lcbdata->sc_err = EBADF;
r = UU_WALK_ERROR;
goto deltemp;
default:
bad_error("get_snaplevel", r);
}
}
if (g_verbose) {
if (scf_instance_get_name(imp_inst, imp_str,
imp_str_sz) < 0)
(void) strcpy(imp_str, "?");
warn(gettext("Upgrading properties of %s according to "
"instance \"%s\".\n"), s->sc_fmri, imp_str);
}
r = upgrade_props(imp_svc, running, imp_snpl, s);
if (r == 0)
break;
switch (r) {
case ECONNABORTED:
goto connaborted;
case ECANCELED:
warn(s_deleted, s->sc_fmri);
lcbdata->sc_err = EBUSY;
break;
case ENODEV:
if (scf_instance_get_name(imp_inst, imp_str,
imp_str_sz) < 0)
(void) strcpy(imp_str, "?");
warn(i_deleted, s->sc_fmri, imp_str);
lcbdata->sc_err = EBUSY;
break;
default:
lcbdata->sc_err = r;
}
r = UU_WALK_ERROR;
goto deltemp;
}
s->sc_import_state = IMPORT_PROP_DONE;
instances:
cbdata.sc_handle = lcbdata->sc_handle;
cbdata.sc_parent = imp_svc;
cbdata.sc_service = 1;
cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
cbdata.sc_general = NULL;
if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
lcbdata->sc_err = cbdata.sc_err;
if (cbdata.sc_err == ECONNABORTED)
goto connaborted;
r = UU_WALK_ERROR;
goto deltemp;
}
s->sc_import_state = IMPORT_COMPLETE;
r = UU_WALK_NEXT;
deltemp:
if (scf_service_delete(imp_tsvc) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_CONNECTION_BROKEN:
goto connaborted;
case SCF_ERROR_EXISTS:
warn(gettext(
"Could not delete svc:/%s (instances exist).\n"),
imp_tsname);
break;
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_service_delete", scf_error());
}
}
return (r);
connaborted:
warn(gettext("Could not delete svc:/%s "
"(repository connection broken).\n"), imp_tsname);
lcbdata->sc_err = ECONNABORTED;
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
(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
__FILE__, __LINE__, st);
#endif
abort();
}
}
static int
imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
{
scf_error_t serr;
void *ent;
int issvc;
int r;
const char *deleted = gettext("Could not refresh %s (deleted).\n");
const char *dpt_deleted = gettext("Could not refresh %s "
"(dependent \"%s\" of %s) (deleted).\n");
serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
if (name == NULL)
warn(gettext("Could not refresh %s (out of memory).\n"),
fmri);
else
warn(gettext("Could not refresh %s "
"(dependent \"%s\" of %s) (out of memory).\n"),
fmri, name, d_fmri);
return (ENOMEM);
case SCF_ERROR_NOT_FOUND:
if (name == NULL)
warn(deleted, fmri);
else
warn(dpt_deleted, fmri, name, d_fmri);
return (0);
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_CONSTRAINT_VIOLATED:
default:
bad_error("fmri_to_entity", serr);
}
r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
switch (r) {
case 0:
break;
case ECONNABORTED:
if (name != NULL)
warn(gettext("Could not refresh %s "
"(dependent \"%s\" of %s) "
"(repository connection broken).\n"), fmri, name,
d_fmri);
return (r);
case ECANCELED:
if (name == NULL)
warn(deleted, fmri);
else
warn(dpt_deleted, fmri, name, d_fmri);
return (0);
case EACCES:
if (!g_verbose)
return (0);
if (name == NULL)
warn(gettext("Could not refresh %s "
"(backend access denied).\n"), fmri);
else
warn(gettext("Could not refresh %s "
"(dependent \"%s\" of %s) "
"(backend access denied).\n"), fmri, name, d_fmri);
return (0);
case EPERM:
if (name == NULL)
warn(gettext("Could not refresh %s "
"(permission denied).\n"), fmri);
else
warn(gettext("Could not refresh %s "
"(dependent \"%s\" of %s) "
"(permission denied).\n"), fmri, name, d_fmri);
return (r);
case ENOSPC:
if (name == NULL)
warn(gettext("Could not refresh %s "
"(repository server out of resources).\n"),
fmri);
else
warn(gettext("Could not refresh %s "
"(dependent \"%s\" of %s) "
"(repository server out of resources).\n"),
fmri, name, d_fmri);
return (r);
case -1:
scfwarn();
return (r);
default:
bad_error("refresh_entity", r);
}
if (issvc)
scf_service_destroy(ent);
else
scf_instance_destroy(ent);
return (0);
}
static int
alloc_imp_globals()
{
int r;
const char * const emsg_nomem = gettext("Out of memory.\n");
const char * const emsg_nores =
gettext("svc.configd is out of resources.\n");
imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
max_scf_name_len : max_scf_fmri_len) + 1;
if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
(imp_svc = scf_service_create(g_hndl)) == NULL ||
(imp_tsvc = scf_service_create(g_hndl)) == NULL ||
(imp_inst = scf_instance_create(g_hndl)) == NULL ||
(imp_tinst = scf_instance_create(g_hndl)) == NULL ||
(imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
(imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
(imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
(imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
(imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
(imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
(imp_pg = scf_pg_create(g_hndl)) == NULL ||
(imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
(imp_prop = scf_property_create(g_hndl)) == NULL ||
(imp_iter = scf_iter_create(g_hndl)) == NULL ||
(imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
(imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
(imp_tx = scf_transaction_create(g_hndl)) == NULL ||
(imp_str = malloc(imp_str_sz)) == NULL ||
(imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
(imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
(imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
(imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
(ud_inst = scf_instance_create(g_hndl)) == NULL ||
(ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
(ud_pg = scf_pg_create(g_hndl)) == NULL ||
(ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
(ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
(ud_prop = scf_property_create(g_hndl)) == NULL ||
(ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
(ud_val = scf_value_create(g_hndl)) == NULL ||
(ud_iter = scf_iter_create(g_hndl)) == NULL ||
(ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
(ud_tx = scf_transaction_create(g_hndl)) == NULL ||
(ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
(ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
(ud_name = malloc(max_scf_name_len + 1)) == NULL) {
if (scf_error() == SCF_ERROR_NO_RESOURCES)
warn(emsg_nores);
else
warn(emsg_nomem);
return (-1);
}
r = load_init();
switch (r) {
case 0:
break;
case ENOMEM:
warn(emsg_nomem);
return (-1);
default:
bad_error("load_init", r);
}
return (0);
}
static void
free_imp_globals()
{
pgroup_t *old_dpt;
void *cookie;
load_fini();
free(ud_ctarg);
free(ud_oldtarg);
free(ud_name);
ud_ctarg = ud_oldtarg = ud_name = NULL;
scf_transaction_destroy(ud_tx);
ud_tx = NULL;
scf_iter_destroy(ud_iter);
scf_iter_destroy(ud_iter2);
ud_iter = ud_iter2 = NULL;
scf_value_destroy(ud_val);
ud_val = NULL;
scf_property_destroy(ud_prop);
scf_property_destroy(ud_dpt_prop);
ud_prop = ud_dpt_prop = NULL;
scf_pg_destroy(ud_pg);
scf_pg_destroy(ud_cur_depts_pg);
scf_pg_destroy(ud_run_dpts_pg);
ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
scf_snaplevel_destroy(ud_snpl);
ud_snpl = NULL;
scf_instance_destroy(ud_inst);
ud_inst = NULL;
free(imp_str);
free(imp_tsname);
free(imp_fe1);
free(imp_fe2);
imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
cookie = NULL;
while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
NULL) {
free((char *)old_dpt->sc_pgroup_name);
free((char *)old_dpt->sc_pgroup_fmri);
internal_pgroup_free(old_dpt);
}
uu_list_destroy(imp_deleted_dpts);
scf_transaction_destroy(imp_tx);
imp_tx = NULL;
scf_iter_destroy(imp_iter);
scf_iter_destroy(imp_rpg_iter);
scf_iter_destroy(imp_up_iter);
imp_iter = imp_rpg_iter = imp_up_iter = NULL;
scf_property_destroy(imp_prop);
imp_prop = NULL;
scf_pg_destroy(imp_pg);
scf_pg_destroy(imp_pg2);
imp_pg = imp_pg2 = NULL;
scf_snaplevel_destroy(imp_snpl);
scf_snaplevel_destroy(imp_rsnpl);
imp_snpl = imp_rsnpl = NULL;
scf_snapshot_destroy(imp_snap);
scf_snapshot_destroy(imp_lisnap);
scf_snapshot_destroy(imp_tlisnap);
scf_snapshot_destroy(imp_rsnap);
imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
scf_instance_destroy(imp_inst);
scf_instance_destroy(imp_tinst);
imp_inst = imp_tinst = NULL;
scf_service_destroy(imp_svc);
scf_service_destroy(imp_tsvc);
imp_svc = imp_tsvc = NULL;
scf_scope_destroy(imp_scope);
imp_scope = NULL;
load_fini();
}
int
lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
{
scf_callback_t cbdata;
int result = 0;
entity_t *svc, *inst;
uu_list_t *insts;
int r;
pgroup_t *old_dpt;
int annotation_set = 0;
const char * const emsg_nomem = gettext("Out of memory.\n");
const char * const emsg_nores =
gettext("svc.configd is out of resources.\n");
lscf_prep_hndl();
if (alloc_imp_globals())
goto out;
if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
warn(gettext("Repository connection broken.\n"));
repository_teardown();
result = -1;
goto out;
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_HANDLE_MISMATCH:
default:
bad_error("scf_handle_get_scope", scf_error());
}
}
if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
annotation_set = 1;
} else {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
warn(gettext("Repository connection broken.\n"));
repository_teardown();
result = -1;
goto out;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_INTERNAL:
bad_error("_scf_set_annotation", scf_error());
default:
warn(gettext("_scf_set_annotation() unexpectedly "
"failed with return code of %d\n"), scf_error());
break;
}
}
for (svc = uu_list_first(bndl->sc_bundle_services);
svc != NULL;
svc = uu_list_next(bndl->sc_bundle_services, svc)) {
svc->sc_import_state = 0;
if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
clear_int, (void *)offsetof(entity_t, sc_import_state),
UU_DEFAULT) != 0)
bad_error("uu_list_walk", uu_error());
}
cbdata.sc_handle = g_hndl;
cbdata.sc_parent = imp_scope;
cbdata.sc_flags = flags;
cbdata.sc_general = NULL;
if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
&cbdata, UU_DEFAULT) == 0) {
char *eptr;
if (flags & SCI_NOREFRESH || no_refresh) {
no_refresh = 0;
result = 0;
goto out;
}
for (svc = uu_list_first(bndl->sc_bundle_services);
svc != NULL;
svc = uu_list_next(bndl->sc_bundle_services, svc)) {
pgroup_t *dpt;
insts = svc->sc_u.sc_service.sc_service_instances;
for (inst = uu_list_first(insts);
inst != NULL;
inst = uu_list_next(insts, inst)) {
r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
switch (r) {
case 0:
break;
case ENOMEM:
case ECONNABORTED:
case EPERM:
case -1:
goto progress;
default:
bad_error("imp_refresh_fmri", r);
}
inst->sc_import_state = IMPORT_REFRESHED;
for (dpt = uu_list_first(inst->sc_dependents);
dpt != NULL;
dpt = uu_list_next(inst->sc_dependents,
dpt))
if (imp_refresh_fmri(
dpt->sc_pgroup_fmri,
dpt->sc_pgroup_name,
inst->sc_fmri) != 0)
goto progress;
}
for (dpt = uu_list_first(svc->sc_dependents);
dpt != NULL;
dpt = uu_list_next(svc->sc_dependents, dpt))
if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
dpt->sc_pgroup_name, svc->sc_fmri) != 0)
goto progress;
}
for (old_dpt = uu_list_first(imp_deleted_dpts);
old_dpt != NULL;
old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
old_dpt->sc_pgroup_name,
old_dpt->sc_parent->sc_fmri) != 0)
goto progress;
result = 0;
#ifndef NATIVE_BUILD
eptr = getenv("SVCCFG_REPOSITORY");
for (svc = uu_list_first(bndl->sc_bundle_services);
svc != NULL && eptr == NULL;
svc = uu_list_next(bndl->sc_bundle_services, svc)) {
insts = svc->sc_u.sc_service.sc_service_instances;
for (inst = uu_list_first(insts);
inst != NULL;
inst = uu_list_next(insts, inst)) {
if (lscf_instance_verify(imp_scope, svc,
inst) != 0)
goto progress;
}
}
#endif
goto out;
}
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
switch (cbdata.sc_err) {
case ECONNABORTED:
warn(gettext("Repository connection broken.\n"));
break;
case ENOMEM:
warn(emsg_nomem);
break;
case ENOSPC:
warn(emsg_nores);
break;
case EROFS:
warn(gettext("Repository is read-only.\n"));
break;
case EACCES:
warn(gettext("Repository backend denied access.\n"));
break;
case EPERM:
case EINVAL:
case EEXIST:
case EBUSY:
case EBADF:
case -1:
break;
default:
bad_error("lscf_service_import", cbdata.sc_err);
}
progress:
warn(gettext("Import of %s failed. Progress:\n"), filename);
for (svc = uu_list_first(bndl->sc_bundle_services);
svc != NULL;
svc = uu_list_next(bndl->sc_bundle_services, svc)) {
insts = svc->sc_u.sc_service.sc_service_instances;
warn(gettext(" Service \"%s\": %s\n"), svc->sc_name,
import_progress(svc->sc_import_state));
for (inst = uu_list_first(insts);
inst != NULL;
inst = uu_list_next(insts, inst))
warn(gettext(" Instance \"%s\": %s\n"),
inst->sc_name,
import_progress(inst->sc_import_state));
}
if (cbdata.sc_err == ECONNABORTED)
repository_teardown();
result = -1;
out:
if (annotation_set != 0) {
(void) _scf_set_annotation(g_hndl, NULL, NULL);
}
free_imp_globals();
return (result);
}
#define IMPORT_BAD -1
#define IMPORT_NEXT 0
#define IMPORT_OUT 1
static int
_lscf_import_err(int err, const char *fmri)
{
switch (err) {
case 0:
if (g_verbose)
warn(gettext("%s updated.\n"), fmri);
return (IMPORT_NEXT);
case ECONNABORTED:
warn(gettext("Could not update %s "
"(repository connection broken).\n"), fmri);
return (IMPORT_OUT);
case ENOMEM:
warn(gettext("Could not update %s (out of memory).\n"), fmri);
return (IMPORT_OUT);
case ENOSPC:
warn(gettext("Could not update %s "
"(repository server out of resources).\n"), fmri);
return (IMPORT_OUT);
case ECANCELED:
warn(gettext(
"Could not update %s (deleted).\n"), fmri);
return (IMPORT_NEXT);
case EPERM:
case EINVAL:
case EBUSY:
return (IMPORT_NEXT);
case EROFS:
warn(gettext("Could not update %s (repository read-only).\n"),
fmri);
return (IMPORT_OUT);
case EACCES:
warn(gettext("Could not update %s "
"(backend access denied).\n"), fmri);
return (IMPORT_NEXT);
case EEXIST:
default:
return (IMPORT_BAD);
}
}
static int
lscf_dependent_apply(void *dpg, void *e)
{
scf_callback_t cb;
pgroup_t *dpt_pgroup = dpg;
pgroup_t *deldpt;
entity_t *ent = e;
int tissvc;
void *sc_ent, *tent;
scf_error_t serr;
int r;
const char * const dependents = "dependents";
const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
if (issvc)
sc_ent = imp_svc;
else
sc_ent = imp_inst;
if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
imp_prop) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("entity_get_pg", scf_error());
}
} else {
if (scf_property_get_value(imp_prop, ud_val) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
break;
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NOT_SET:
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
if (scf_value_get_as_string(ud_val, ud_oldtarg,
max_scf_value_len + 1) < 0)
bad_error("scf_value_get_as_string", scf_error());
r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
switch (r) {
case 1:
break;
case 0:
if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
&tissvc)) != SCF_ERROR_NONE) {
if (serr == SCF_ERROR_NOT_FOUND) {
break;
} else {
bad_error("fmri_to_entity", serr);
}
}
if (entity_get_pg(tent, tissvc,
dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
serr = scf_error();
if (serr == SCF_ERROR_NOT_FOUND ||
serr == SCF_ERROR_DELETED) {
break;
} else {
bad_error("entity_get_pg", scf_error());
}
}
if (scf_pg_delete(imp_pg) != 0) {
serr = scf_error();
if (serr == SCF_ERROR_NOT_FOUND ||
serr == SCF_ERROR_DELETED) {
break;
} else {
bad_error("scf_pg_delete", scf_error());
}
}
deldpt = internal_pgroup_new();
if (deldpt == NULL)
return (ENOMEM);
deldpt->sc_pgroup_name =
strdup(dpt_pgroup->sc_pgroup_name);
deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
if (deldpt->sc_pgroup_name == NULL ||
deldpt->sc_pgroup_fmri == NULL)
return (ENOMEM);
deldpt->sc_parent = (entity_t *)ent;
if (uu_list_insert_after(imp_deleted_dpts, NULL,
deldpt) != 0)
uu_die(gettext("libuutil error: %s\n"),
uu_strerror(uu_error()));
break;
default:
bad_error("fmri_equal", r);
}
}
cb.sc_handle = g_hndl;
cb.sc_parent = ent;
cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
cb.sc_source_fmri = ent->sc_fmri;
cb.sc_target_fmri = ent->sc_fmri;
cb.sc_trans = NULL;
cb.sc_flags = SCI_FORCE;
if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
return (UU_WALK_ERROR);
r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
switch (r) {
case 0:
break;
case ENOMEM:
case ECONNABORTED:
case EPERM:
case -1:
warn(gettext("Unable to refresh \"%s\"\n"),
dpt_pgroup->sc_pgroup_fmri);
return (UU_WALK_ERROR);
default:
bad_error("imp_refresh_fmri", r);
}
return (UU_WALK_NEXT);
}
int
lscf_bundle_apply(bundle_t *bndl, const char *file)
{
pgroup_t *old_dpt;
entity_t *svc, *inst;
int annotation_set = 0;
int ret = 0;
int r = 0;
lscf_prep_hndl();
if ((ret = alloc_imp_globals()))
goto out;
if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
scfdie();
if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
annotation_set = 1;
} else {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
warn(gettext("Repository connection broken.\n"));
goto out;
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NO_RESOURCES:
case SCF_ERROR_INTERNAL:
bad_error("_scf_set_annotation", scf_error());
default:
warn(gettext("_scf_set_annotation() unexpectedly "
"failed with return code of %d\n"), scf_error());
break;
}
}
for (svc = uu_list_first(bndl->sc_bundle_services);
svc != NULL;
svc = uu_list_next(bndl->sc_bundle_services, svc)) {
int refresh = 0;
if (scf_scope_get_service(imp_scope, svc->sc_name,
imp_svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
if (g_verbose)
warn(gettext("Ignoring nonexistent "
"service %s.\n"), svc->sc_name);
continue;
default:
scfdie();
}
}
if (svc->sc_miss_type) {
if (uu_list_numnodes(svc->sc_pgroups) &&
uu_list_walk(svc->sc_pgroups, find_current_pg_type,
svc, UU_DEFAULT) != 0) {
if (uu_error() != UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk", uu_error());
ret = -1;
continue;
}
for (inst = uu_list_first(
svc->sc_u.sc_service.sc_service_instances);
inst != NULL;
inst = uu_list_next(
svc->sc_u.sc_service.sc_service_instances, inst)) {
if (scf_service_get_instance(imp_svc,
inst->sc_name, imp_inst) != 0)
continue;
if (uu_list_walk(inst->sc_pgroups,
find_current_pg_type, inst,
UU_DEFAULT) != 0) {
if (uu_error() !=
UU_ERROR_CALLBACK_FAILED)
bad_error("uu_list_walk",
uu_error());
ret = -1;
inst->sc_miss_type = B_TRUE;
}
}
}
if (uu_list_numnodes(svc->sc_pgroups) != 0) {
refresh = 1;
r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
SCI_FORCE | SCI_KEEP);
switch (_lscf_import_err(r, svc->sc_fmri)) {
case IMPORT_NEXT:
break;
case IMPORT_OUT:
goto out;
case IMPORT_BAD:
default:
bad_error("lscf_import_service_pgs", r);
}
}
if (uu_list_numnodes(svc->sc_dependents) != 0) {
uu_list_walk(svc->sc_dependents,
lscf_dependent_apply, svc, UU_DEFAULT);
}
for (inst = uu_list_first(
svc->sc_u.sc_service.sc_service_instances);
inst != NULL;
inst = uu_list_next(
svc->sc_u.sc_service.sc_service_instances, inst)) {
if (inst->sc_miss_type) {
if (g_verbose)
warn(gettext("Ignoring instance "
"%s:%s with missing types\n"),
inst->sc_parent->sc_name,
inst->sc_name);
continue;
}
if (scf_service_get_instance(imp_svc, inst->sc_name,
imp_inst) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
if (g_verbose)
warn(gettext("Ignoring "
"nonexistant instance "
"%s:%s.\n"),
inst->sc_parent->sc_name,
inst->sc_name);
continue;
default:
scfdie();
}
}
if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
imp_snap) != 0) {
if (scf_instance_get_pg(imp_inst,
SCF_PG_GENERAL, imp_pg) != 0 ||
scf_pg_get_property(imp_pg,
SCF_PROPERTY_ENABLED, imp_prop) != 0) {
if (g_verbose)
warn(gettext("Ignoreing "
"partial instance "
"%s:%s.\n"),
inst->sc_parent->sc_name,
inst->sc_name);
continue;
}
}
r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
inst, SCI_FORCE | SCI_KEEP);
switch (_lscf_import_err(r, inst->sc_fmri)) {
case IMPORT_NEXT:
break;
case IMPORT_OUT:
goto out;
case IMPORT_BAD:
default:
bad_error("lscf_import_instance_pgs", r);
}
if (uu_list_numnodes(inst->sc_dependents) != 0) {
uu_list_walk(inst->sc_dependents,
lscf_dependent_apply, inst, UU_DEFAULT);
}
if (refresh == 0)
(void) refresh_entity(0, imp_inst,
inst->sc_fmri, NULL, NULL, NULL);
}
if (refresh == 1) {
char *name_buf = safe_malloc(max_scf_name_len + 1);
(void) refresh_entity(1, imp_svc, svc->sc_name,
imp_inst, imp_iter, name_buf);
free(name_buf);
}
for (old_dpt = uu_list_first(imp_deleted_dpts);
old_dpt != NULL;
old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
old_dpt->sc_pgroup_name,
old_dpt->sc_parent->sc_fmri) != 0) {
warn(gettext("Unable to refresh \"%s\"\n"),
old_dpt->sc_pgroup_fmri);
}
}
}
out:
if (annotation_set) {
(void) _scf_set_annotation(g_hndl, NULL, NULL);
}
free_imp_globals();
return (ret);
}
static void
safe_setprop(xmlNodePtr n, const char *name, const char *val)
{
if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
uu_die(gettext("Could not set XML property.\n"));
}
static int
set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
const char *name, const char *dval)
{
scf_value_t *val;
ssize_t len;
char *str;
val = scf_value_create(g_hndl);
if (val == NULL)
scfdie();
if (prop_get_val(prop, val) != 0) {
scf_value_destroy(val);
return (-1);
}
len = scf_value_get_as_string(val, NULL, 0);
if (len < 0)
scfdie();
str = safe_malloc(len + 1);
if (scf_value_get_as_string(val, str, len + 1) < 0)
scfdie();
scf_value_destroy(val);
if (dval == NULL || strcmp(str, dval) != 0)
safe_setprop(n, name, str);
free(str);
return (0);
}
static int
set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
{
return (set_attr_from_prop_default(prop, n, name, NULL));
}
static int
write_service_bundle(xmlDocPtr doc, FILE *f)
{
xmlChar *mem;
int sz, i;
mem = NULL;
xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
if (mem == NULL) {
semerr(gettext("Could not dump XML tree.\n"));
return (-1);
}
for (i = 0; i < sz; ++i) {
char c = (char)mem[i];
if (c == '"')
(void) fputc('\'', f);
else if (c == '\'')
(void) fwrite("'", sizeof ("'") - 1, 1, f);
else
(void) fputc(c, f);
}
return (0);
}
static void
export_property(scf_property_t *prop, const char *name_arg,
struct pg_elts *elts, int flags)
{
const char *type;
scf_error_t err = 0;
xmlNodePtr pnode, lnode;
char *lnname;
int ret;
if (name_arg != NULL) {
(void) strcpy(exp_str, name_arg);
} else {
if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
scfdie();
}
type = prop_to_typestr(prop);
if (type == NULL)
uu_die(gettext("Can't export property %s: unknown type.\n"),
exp_str);
if (!(flags & SCE_ALL_VALUES))
goto empty;
if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
xmlNodePtr n;
n = xmlNewNode(NULL, (xmlChar *)"propval");
if (n == NULL)
uu_die(emsg_create_xml);
safe_setprop(n, name_attr, exp_str);
safe_setprop(n, type_attr, type);
if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
scfdie();
safe_setprop(n, value_attr, exp_str);
if (elts->propvals == NULL)
elts->propvals = n;
else
(void) xmlAddSibling(elts->propvals, n);
return;
}
err = scf_error();
if (err == SCF_ERROR_PERMISSION_DENIED) {
semerr(emsg_permission_denied);
return;
}
if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
err != SCF_ERROR_NOT_FOUND &&
err != SCF_ERROR_PERMISSION_DENIED)
scfdie();
empty:
pnode = xmlNewNode(NULL, (xmlChar *)"property");
if (pnode == NULL)
uu_die(emsg_create_xml);
safe_setprop(pnode, name_attr, exp_str);
safe_setprop(pnode, type_attr, type);
if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
lnname = uu_msprintf("%s_list", type);
if (lnname == NULL)
uu_die(gettext("Could not create string"));
lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
if (lnode == NULL)
uu_die(emsg_create_xml);
uu_free(lnname);
if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
1) {
xmlNodePtr vn;
vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
NULL);
if (vn == NULL)
uu_die(emsg_create_xml);
if (scf_value_get_as_string(exp_val, exp_str,
exp_str_sz) < 0)
scfdie();
safe_setprop(vn, value_attr, exp_str);
}
if (ret != 0)
scfdie();
}
if (elts->properties == NULL)
elts->properties = pnode;
else
(void) xmlAddSibling(elts->properties, pnode);
}
static void
export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
{
xmlNodePtr n;
struct pg_elts elts;
int ret;
boolean_t read_protected;
n = xmlNewNode(NULL, (xmlChar *)"property_group");
if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
scfdie();
safe_setprop(n, name_attr, exp_str);
if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
scfdie();
safe_setprop(n, type_attr, exp_str);
if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
scfdie();
(void) memset(&elts, 0, sizeof (elts));
if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
scfdie();
if (!read_protected)
flags |= SCE_ALL_VALUES;
while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
xmlNodePtr m;
m = xmlNewNode(NULL, (xmlChar *)"stability");
if (m == NULL)
uu_die(emsg_create_xml);
if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
elts.stability = m;
continue;
}
xmlFreeNode(m);
}
export_property(exp_prop, NULL, &elts, flags);
}
if (ret == -1)
scfdie();
(void) xmlAddChild(n, elts.stability);
(void) xmlAddChildList(n, elts.propvals);
(void) xmlAddChildList(n, elts.properties);
if (eelts->property_groups == NULL)
eelts->property_groups = n;
else
(void) xmlAddSibling(eelts->property_groups, n);
}
static void
export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
{
xmlNodePtr n;
int err = 0, ret;
struct pg_elts elts;
n = xmlNewNode(NULL, (xmlChar *)"dependency");
if (n == NULL)
uu_die(emsg_create_xml);
if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
prop_get_val(exp_prop, exp_val) == 0) {
uint8_t b;
if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
scfdie();
if (b)
return;
}
} else if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
scfdie();
safe_setprop(n, name_attr, exp_str);
if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, n, "grouping") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, n, "restart_on") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, n, type_attr) != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
scf_iter_t *eiter;
int ret2;
eiter = scf_iter_create(g_hndl);
if (eiter == NULL)
scfdie();
if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
scfdie();
while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
xmlNodePtr ch;
if (scf_value_get_astring(exp_val, exp_str,
exp_str_sz) < 0)
scfdie();
ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
NULL);
if (ch == NULL)
uu_die(emsg_create_xml);
safe_setprop(ch, value_attr, exp_str);
}
if (ret2 == -1)
scfdie();
scf_iter_destroy(eiter);
} else
err = 1;
if (err) {
xmlFreeNode(n);
export_pg(pg, eelts, SCE_ALL_VALUES);
return;
}
if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
scfdie();
(void) memset(&elts, 0, sizeof (elts));
while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
continue;
} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
xmlNodePtr m;
m = xmlNewNode(NULL, (xmlChar *)"stability");
if (m == NULL)
uu_die(emsg_create_xml);
if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
elts.stability = m;
continue;
}
xmlFreeNode(m);
}
export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
}
if (ret == -1)
scfdie();
(void) xmlAddChild(n, elts.stability);
(void) xmlAddChildList(n, elts.propvals);
(void) xmlAddChildList(n, elts.properties);
if (eelts->dependencies == NULL)
eelts->dependencies = n;
else
(void) xmlAddSibling(eelts->dependencies, n);
}
static xmlNodePtr
export_method_environment(scf_propertygroup_t *pg)
{
xmlNodePtr env;
int ret;
int children = 0;
if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
return (NULL);
env = xmlNewNode(NULL, (xmlChar *)"method_environment");
if (env == NULL)
uu_die(emsg_create_xml);
if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
scfdie();
if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
xmlNodePtr ev;
char *cp;
if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
scfdie();
if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
warn(gettext("Invalid environment variable \"%s\".\n"),
exp_str);
continue;
} else if (strncmp(exp_str, "SMF_", 4) == 0) {
warn(gettext("Invalid environment variable \"%s\"; "
"\"SMF_\" prefix is reserved.\n"), exp_str);
continue;
}
*cp = '\0';
cp++;
ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
if (ev == NULL)
uu_die(emsg_create_xml);
safe_setprop(ev, name_attr, exp_str);
safe_setprop(ev, value_attr, cp);
children++;
}
if (ret != 0)
scfdie();
if (children == 0) {
xmlFreeNode(env);
return (NULL);
}
return (env);
}
static void
export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
{
xmlNodePtr n, env;
char *str;
int err = 0, nonenv, ret;
uint8_t use_profile;
struct pg_elts elts;
xmlNodePtr ctxt = NULL;
n = xmlNewNode(NULL, (xmlChar *)"exec_method");
if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
scfdie();
safe_setprop(n, name_attr, exp_str);
if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, n, type_attr) != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, n, "exec") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
prop_get_val(exp_prop, exp_val) == 0) {
uint64_t c;
if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
scfdie();
str = uu_msprintf("%llu", c);
if (str == NULL)
uu_die(gettext("Could not create string"));
safe_setprop(n, "timeout_seconds", str);
free(str);
} else
err = 1;
if (err) {
xmlFreeNode(n);
export_pg(pg, eelts, SCE_ALL_VALUES);
return;
}
nonenv =
scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
SCF_SUCCESS ||
scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
SCF_SUCCESS ||
scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
SCF_SUCCESS ||
scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
SCF_SUCCESS ||
scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
SCF_SUCCESS;
if (nonenv) {
ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
if (ctxt == NULL)
uu_die(emsg_create_xml);
if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
0 &&
set_attr_from_prop_default(exp_prop, ctxt,
"working_directory", ":default") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
set_attr_from_prop_default(exp_prop, ctxt, "project",
":default") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
0 &&
set_attr_from_prop_default(exp_prop, ctxt,
"resource_pool", ":default") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
set_attr_from_prop_default(exp_prop, ctxt,
"security_flags", ":default") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
prop_get_val(exp_prop, exp_val) == 0) {
if (scf_value_get_boolean(exp_val, &use_profile) !=
SCF_SUCCESS) {
scfdie();
}
if (use_profile) {
xmlNodePtr prof;
prof = xmlNewChild(ctxt, NULL,
(xmlChar *)"method_profile", NULL);
if (prof == NULL)
uu_die(emsg_create_xml);
if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
exp_prop) != 0 ||
set_attr_from_prop(exp_prop, prof,
name_attr) != 0)
err = 1;
} else {
xmlNodePtr cred;
cred = xmlNewChild(ctxt, NULL,
(xmlChar *)"method_credential", NULL);
if (cred == NULL)
uu_die(emsg_create_xml);
if (pg_get_prop(pg, SCF_PROPERTY_USER,
exp_prop) != 0 ||
set_attr_from_prop(exp_prop, cred,
"user") != 0) {
err = 1;
}
if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
exp_prop) == 0 &&
set_attr_from_prop_default(exp_prop, cred,
"group", ":default") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
exp_prop) == 0 &&
set_attr_from_prop_default(exp_prop, cred,
"supp_groups", ":default") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
exp_prop) == 0 &&
set_attr_from_prop_default(exp_prop, cred,
"privileges", ":default") != 0)
err = 1;
if (pg_get_prop(pg,
SCF_PROPERTY_LIMIT_PRIVILEGES,
exp_prop) == 0 &&
set_attr_from_prop_default(exp_prop, cred,
"limit_privileges", ":default") != 0)
err = 1;
}
}
}
if ((env = export_method_environment(pg)) != NULL) {
if (ctxt == NULL) {
ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
if (ctxt == NULL)
uu_die(emsg_create_xml);
}
(void) xmlAddChild(ctxt, env);
}
if (env != NULL || (nonenv && err == 0))
(void) xmlAddChild(n, ctxt);
else
xmlFreeNode(ctxt);
nonenv = (err == 0);
if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
scfdie();
(void) memset(&elts, 0, sizeof (elts));
while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
continue;
} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
xmlNodePtr m;
m = xmlNewNode(NULL, (xmlChar *)"stability");
if (m == NULL)
uu_die(emsg_create_xml);
if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
elts.stability = m;
continue;
}
xmlFreeNode(m);
} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
0 ||
strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
if (nonenv)
continue;
} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
if (nonenv && !use_profile)
continue;
} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
if (nonenv && use_profile)
continue;
} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
if (env != NULL)
continue;
}
export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
}
if (ret == -1)
scfdie();
(void) xmlAddChild(n, elts.stability);
(void) xmlAddChildList(n, elts.propvals);
(void) xmlAddChildList(n, elts.properties);
if (eelts->exec_methods == NULL)
eelts->exec_methods = n;
else
(void) xmlAddSibling(eelts->exec_methods, n);
}
static void
export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
struct entity_elts *eelts)
{
xmlNodePtr pgnode;
pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
if (pgnode == NULL)
uu_die(emsg_create_xml);
safe_setprop(pgnode, name_attr, name);
safe_setprop(pgnode, type_attr, type);
(void) xmlAddChildList(pgnode, elts->propvals);
(void) xmlAddChildList(pgnode, elts->properties);
if (eelts->property_groups == NULL)
eelts->property_groups = pgnode;
else
(void) xmlAddSibling(eelts->property_groups, pgnode);
}
static void
export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
{
struct pg_elts elts;
int ret;
(void) memset(&elts, 0, sizeof (elts));
if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
prop_get_val(exp_prop, exp_val) == 0) {
uint8_t b;
if (scf_value_get_boolean(exp_val, &b) !=
SCF_SUCCESS)
scfdie();
if (b) {
selts->single_instance =
xmlNewNode(NULL,
(xmlChar *)"single_instance");
if (selts->single_instance == NULL)
uu_die(emsg_create_xml);
}
continue;
}
} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
xmlNodePtr rnode, sfnode;
rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
if (rnode == NULL)
uu_die(emsg_create_xml);
sfnode = xmlNewChild(rnode, NULL,
(xmlChar *)"service_fmri", NULL);
if (sfnode == NULL)
uu_die(emsg_create_xml);
if (set_attr_from_prop(exp_prop, sfnode,
value_attr) == 0) {
selts->restarter = rnode;
continue;
}
xmlFreeNode(rnode);
} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
0) {
xmlNodePtr s;
s = xmlNewNode(NULL, (xmlChar *)"stability");
if (s == NULL)
uu_die(emsg_create_xml);
if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
selts->stability = s;
continue;
}
xmlFreeNode(s);
}
export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
}
if (ret == -1)
scfdie();
if (elts.propvals != NULL || elts.properties != NULL)
export_pg_elts(&elts, scf_pg_general, scf_group_framework,
selts);
}
static void
export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
{
xmlNodePtr n, prof, cred, env;
uint8_t use_profile;
int ret, err = 0;
n = xmlNewNode(NULL, (xmlChar *)"method_context");
env = export_method_environment(pg);
if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
prop_get_val(exp_prop, exp_val) == 0) {
if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
scfdie();
if (use_profile)
prof =
xmlNewChild(n, NULL, (xmlChar *)"method_profile",
NULL);
else
cred =
xmlNewChild(n, NULL, (xmlChar *)"method_credential",
NULL);
}
if (env != NULL)
(void) xmlAddChild(n, env);
if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
if (set_attr_from_prop(exp_prop, n,
"working_directory") != 0)
err = 1;
} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
if (set_attr_from_prop(exp_prop, n, "project") != 0)
err = 1;
} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
if (set_attr_from_prop(exp_prop, n,
"resource_pool") != 0)
err = 1;
} else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
if (set_attr_from_prop(exp_prop, n,
"security_flags") != 0)
err = 1;
} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
if (use_profile ||
set_attr_from_prop(exp_prop, cred, "user") != 0)
err = 1;
} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
if (use_profile ||
set_attr_from_prop(exp_prop, cred, "group") != 0)
err = 1;
} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
if (use_profile || set_attr_from_prop(exp_prop, cred,
"supp_groups") != 0)
err = 1;
} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
if (use_profile || set_attr_from_prop(exp_prop, cred,
"privileges") != 0)
err = 1;
} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
0) {
if (use_profile || set_attr_from_prop(exp_prop, cred,
"limit_privileges") != 0)
err = 1;
} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
if (!use_profile || set_attr_from_prop(exp_prop,
prof, name_attr) != 0)
err = 1;
} else {
err = 1;
}
}
if (ret == -1)
scfdie();
if (err && env == NULL) {
xmlFreeNode(n);
export_pg(pg, elts, SCE_ALL_VALUES);
return;
}
elts->method_context = n;
}
static xmlNodePtr
export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
{
uint8_t b;
xmlNodePtr n, sf;
int err = 0, ret;
struct pg_elts pgelts;
if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
scf_property_get_value(exp_prop, exp_val) != 0 ||
scf_value_get_boolean(exp_val, &b) != 0 || !b) {
if (g_verbose) {
warn(gettext("Dependent \"%s\" cannot be exported "
"properly because the \"%s\" property of the "
"\"%s\" dependency of %s is not set to true.\n"),
name, scf_property_external, name, tfmri);
}
return (NULL);
}
n = xmlNewNode(NULL, (xmlChar *)"dependent");
if (n == NULL)
uu_die(emsg_create_xml);
safe_setprop(n, name_attr, name);
if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, n, "restart_on") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, n, "grouping") != 0)
err = 1;
if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
prop_get_val(exp_prop, exp_val) == 0) {
} else
err = 1;
if (err) {
xmlFreeNode(n);
return (NULL);
}
sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
if (sf == NULL)
uu_die(emsg_create_xml);
safe_setprop(sf, value_attr, tfmri);
if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
scfdie();
(void) memset(&pgelts, 0, sizeof (pgelts));
while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, scf_property_external) == 0 ||
strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
continue;
} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
prop_get_val(exp_prop, exp_val) == 0) {
char type[sizeof ("service") + 1];
if (scf_value_get_astring(exp_val, type,
sizeof (type)) < 0)
scfdie();
if (strcmp(type, "service") == 0)
continue;
}
} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
xmlNodePtr s;
s = xmlNewNode(NULL, (xmlChar *)"stability");
if (s == NULL)
uu_die(emsg_create_xml);
if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
pgelts.stability = s;
continue;
}
xmlFreeNode(s);
}
export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
}
if (ret == -1)
scfdie();
(void) xmlAddChild(n, pgelts.stability);
(void) xmlAddChildList(n, pgelts.propvals);
(void) xmlAddChildList(n, pgelts.properties);
return (n);
}
static void
export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
{
scf_propertygroup_t *opg;
scf_iter_t *iter;
char *type, *fmri;
int ret;
struct pg_elts pgelts;
xmlNodePtr n;
scf_error_t serr;
if ((opg = scf_pg_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
scfdie();
type = safe_malloc(max_scf_pg_type_len + 1);
fmri = safe_malloc(max_scf_fmri_len + 2);
(void) memset(&pgelts, 0, sizeof (pgelts));
while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
void *entity;
int isservice;
scf_type_t ty;
if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
scfdie();
if ((ty != SCF_TYPE_ASTRING &&
prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
prop_get_val(exp_prop, exp_val) != 0) {
export_property(exp_prop, NULL, &pgelts,
SCE_ALL_VALUES);
continue;
}
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
if (scf_value_get_astring(exp_val, fmri,
max_scf_fmri_len + 2) < 0)
scfdie();
serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
switch (serr) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
uu_die(gettext("Out of memory.\n"));
case SCF_ERROR_INVALID_ARGUMENT:
if (g_verbose) {
if (scf_property_to_fmri(exp_prop, fmri,
max_scf_fmri_len + 2) < 0)
scfdie();
warn(gettext("The value of %s is not a valid "
"FMRI.\n"), fmri);
}
export_property(exp_prop, exp_str, &pgelts,
SCE_ALL_VALUES);
continue;
case SCF_ERROR_CONSTRAINT_VIOLATED:
if (g_verbose) {
if (scf_property_to_fmri(exp_prop, fmri,
max_scf_fmri_len + 2) < 0)
scfdie();
warn(gettext("The value of %s does not specify "
"a service or an instance.\n"), fmri);
}
export_property(exp_prop, exp_str, &pgelts,
SCE_ALL_VALUES);
continue;
case SCF_ERROR_NOT_FOUND:
if (g_verbose) {
if (scf_property_to_fmri(exp_prop, fmri,
max_scf_fmri_len + 2) < 0)
scfdie();
warn(gettext("The entity specified by %s does "
"not exist.\n"), fmri);
}
export_property(exp_prop, exp_str, &pgelts,
SCE_ALL_VALUES);
continue;
default:
#ifndef NDEBUG
(void) fprintf(stderr, "%s:%d: %s() failed with "
"unexpected error %d.\n", __FILE__, __LINE__,
"fmri_to_entity", serr);
#endif
abort();
}
if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
warn(gettext("Entity %s is missing dependency property "
"group %s.\n"), fmri, exp_str);
export_property(exp_prop, NULL, &pgelts,
SCE_ALL_VALUES);
continue;
}
if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
scfdie();
if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
scfdie();
warn(gettext("Property group %s is not of "
"expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
export_property(exp_prop, NULL, &pgelts,
SCE_ALL_VALUES);
continue;
}
n = export_dependent(opg, exp_str, fmri);
if (n == NULL) {
export_property(exp_prop, exp_str, &pgelts,
SCE_ALL_VALUES);
} else {
if (eelts->dependents == NULL)
eelts->dependents = n;
else
(void) xmlAddSibling(eelts->dependents,
n);
}
}
if (ret == -1)
scfdie();
free(fmri);
free(type);
scf_iter_destroy(iter);
scf_pg_destroy(opg);
if (pgelts.propvals != NULL || pgelts.properties != NULL)
export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
eelts);
}
static void
make_node(xmlNodePtr *nodep, const char *name)
{
if (*nodep == NULL) {
*nodep = xmlNewNode(NULL, (xmlChar *)name);
if (*nodep == NULL)
uu_die(emsg_create_xml);
}
}
static xmlNodePtr
export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
{
int ret;
xmlNodePtr parent = NULL;
xmlNodePtr loctext = NULL;
if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
prop_get_val(exp_prop, exp_val) != 0)
continue;
if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
scfdie();
make_node(&parent, parname);
loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
(xmlChar *)exp_str);
if (loctext == NULL)
uu_die(emsg_create_xml);
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
safe_setprop(loctext, "xml:lang", exp_str);
}
if (ret == -1)
scfdie();
return (parent);
}
static xmlNodePtr
export_tm_manpage(scf_propertygroup_t *pg)
{
xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
if (manpage == NULL)
uu_die(emsg_create_xml);
if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, manpage, "section") != 0) {
xmlFreeNode(manpage);
return (NULL);
}
if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
(void) set_attr_from_prop_default(exp_prop,
manpage, "manpath", ":default");
return (manpage);
}
static xmlNodePtr
export_tm_doc_link(scf_propertygroup_t *pg)
{
xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
if (doc_link == NULL)
uu_die(emsg_create_xml);
if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
xmlFreeNode(doc_link);
return (NULL);
}
return (doc_link);
}
static void
export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
struct template_elts *telts)
{
size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
xmlNodePtr child = NULL;
if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
telts->common_name = export_tm_loctext(pg, "common_name");
if (telts->common_name == NULL)
export_pg(pg, elts, SCE_ALL_VALUES);
return;
} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
telts->description = export_tm_loctext(pg, "description");
if (telts->description == NULL)
export_pg(pg, elts, SCE_ALL_VALUES);
return;
}
if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
child = export_tm_manpage(pg);
} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
child = export_tm_doc_link(pg);
}
if (child != NULL) {
make_node(&telts->documentation, "documentation");
(void) xmlAddChild(telts->documentation, child);
} else {
export_pg(pg, elts, SCE_ALL_VALUES);
}
}
static void
export_parameter(scf_property_t *prop, const char *name,
struct params_elts *elts)
{
xmlNodePtr param;
scf_error_t err = 0;
int ret;
if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
uu_die(emsg_create_xml);
safe_setprop(param, name_attr, name);
if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
scfdie();
safe_setprop(param, value_attr, exp_str);
if (elts->paramval == NULL)
elts->paramval = param;
else
(void) xmlAddSibling(elts->paramval, param);
return;
}
err = scf_error();
if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
err != SCF_ERROR_NOT_FOUND)
scfdie();
if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
uu_die(emsg_create_xml);
safe_setprop(param, name_attr, name);
if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
1) {
xmlNodePtr vn;
if ((vn = xmlNewChild(param, NULL,
(xmlChar *)"value_node", NULL)) == NULL)
uu_die(emsg_create_xml);
if (scf_value_get_as_string(exp_val, exp_str,
exp_str_sz) < 0)
scfdie();
safe_setprop(vn, value_attr, exp_str);
}
if (ret != 0)
scfdie();
}
if (elts->parameter == NULL)
elts->parameter = param;
else
(void) xmlAddSibling(elts->parameter, param);
}
static void
export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
{
xmlNodePtr n, event, *type;
struct params_elts *eelts;
int ret, err, i;
char *s;
n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
event = xmlNewNode(NULL, (xmlChar *)"event");
if (n == NULL || event == NULL)
uu_die(emsg_create_xml);
if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
scfdie();
if ((s = strchr(exp_str, ',')) != NULL)
*s = '\0';
safe_setprop(event, value_attr, exp_str);
(void) xmlAddChild(n, event);
if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
(eelts = calloc(URI_SCHEME_NUM,
sizeof (struct params_elts))) == NULL)
uu_die(gettext("Out of memory.\n"));
err = 0;
if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
char *t, *p;
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
err = 1;
break;
}
if ((i = check_uri_protocol(t)) < 0) {
err = 1;
break;
}
if (type[i] == NULL) {
if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
NULL)
uu_die(emsg_create_xml);
safe_setprop(type[i], name_attr, t);
}
if (strcmp(p, active_attr) == 0) {
if (set_attr_from_prop(exp_prop, type[i],
active_attr) != 0) {
err = 1;
break;
}
continue;
}
export_parameter(exp_prop, p, &eelts[i]);
}
if (ret == -1)
scfdie();
if (err == 1) {
for (i = 0; i < URI_SCHEME_NUM; ++i)
xmlFree(type[i]);
free(type);
export_pg(pg, elts, SCE_ALL_VALUES);
return;
} else {
for (i = 0; i < URI_SCHEME_NUM; ++i)
if (type[i] != NULL) {
(void) xmlAddChildList(type[i],
eelts[i].paramval);
(void) xmlAddChildList(type[i],
eelts[i].parameter);
(void) xmlAddSibling(event, type[i]);
}
}
free(type);
if (elts->notify_params == NULL)
elts->notify_params = n;
else
(void) xmlAddSibling(elts->notify_params, n);
}
static void
export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
struct entity_elts *elts)
{
uint8_t enabled;
struct pg_elts pgelts;
int ret;
if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
prop_get_val(exp_prop, exp_val) == 0) {
if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
scfdie();
} else {
enabled = 0;
}
safe_setprop(inode, enabled_attr, enabled ? true : false);
if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
scfdie();
(void) memset(&pgelts, 0, sizeof (pgelts));
while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, scf_property_enabled) == 0) {
continue;
} else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) {
continue;
} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
xmlNodePtr rnode, sfnode;
rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
if (rnode == NULL)
uu_die(emsg_create_xml);
sfnode = xmlNewChild(rnode, NULL,
(xmlChar *)"service_fmri", NULL);
if (sfnode == NULL)
uu_die(emsg_create_xml);
if (set_attr_from_prop(exp_prop, sfnode,
value_attr) == 0) {
elts->restarter = rnode;
continue;
}
xmlFreeNode(rnode);
}
export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
}
if (ret == -1)
scfdie();
if (pgelts.propvals != NULL || pgelts.properties != NULL)
export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
elts);
}
static void
export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
{
xmlNodePtr n;
boolean_t isdefault;
struct entity_elts elts;
struct template_elts template_elts;
int ret;
n = xmlNewNode(NULL, (xmlChar *)"instance");
if (n == NULL)
uu_die(emsg_create_xml);
if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
scfdie();
safe_setprop(n, name_attr, exp_str);
isdefault = strcmp(exp_str, "default") == 0;
if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (g_verbose) {
if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
scfdie();
warn(gettext("Instance %s has no general property "
"group; it will be marked disabled.\n"), exp_str);
}
safe_setprop(n, enabled_attr, false);
} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
strcmp(exp_str, scf_group_framework) != 0) {
if (g_verbose) {
if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
scfdie();
warn(gettext("Property group %s is not of type "
"framework; the instance will be marked "
"disabled.\n"), exp_str);
}
safe_setprop(n, enabled_attr, false);
}
if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
scfdie();
(void) memset(&elts, 0, sizeof (elts));
(void) memset(&template_elts, 0, sizeof (template_elts));
while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
uint32_t pgflags;
if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
scfdie();
if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
continue;
if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
export_dependency(exp_pg, &elts);
continue;
} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
export_method(exp_pg, &elts);
continue;
} else if (strcmp(exp_str, scf_group_framework) == 0) {
if (scf_pg_get_name(exp_pg, exp_str,
max_scf_name_len + 1) < 0)
scfdie();
if (strcmp(exp_str, scf_pg_general) == 0) {
export_inst_general(exp_pg, n, &elts);
continue;
} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
0) {
export_method_context(exp_pg, &elts);
continue;
} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
export_dependents(exp_pg, &elts);
continue;
}
} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
export_template(exp_pg, &elts, &template_elts);
continue;
} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
export_notify_params(exp_pg, &elts);
continue;
}
export_pg(exp_pg, &elts, flags);
}
if (ret == -1)
scfdie();
if (template_elts.common_name != NULL) {
elts.template = xmlNewNode(NULL, (xmlChar *)"template");
(void) xmlAddChild(elts.template, template_elts.common_name);
(void) xmlAddChild(elts.template, template_elts.description);
(void) xmlAddChild(elts.template, template_elts.documentation);
} else {
xmlFreeNode(template_elts.description);
xmlFreeNode(template_elts.documentation);
}
if (isdefault && elts.restarter == NULL &&
elts.dependencies == NULL && elts.method_context == NULL &&
elts.exec_methods == NULL && elts.notify_params == NULL &&
elts.property_groups == NULL && elts.template == NULL) {
xmlChar *eval;
eval = xmlGetProp(n, (xmlChar *)enabled_attr);
xmlFreeNode(n);
n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
if (n == NULL)
uu_die(emsg_create_xml);
safe_setprop(n, enabled_attr, (char *)eval);
xmlFree(eval);
selts->create_default_instance = n;
} else {
(void) xmlAddChild(n, elts.restarter);
(void) xmlAddChildList(n, elts.dependencies);
(void) xmlAddChildList(n, elts.dependents);
(void) xmlAddChild(n, elts.method_context);
(void) xmlAddChildList(n, elts.exec_methods);
(void) xmlAddChildList(n, elts.notify_params);
(void) xmlAddChildList(n, elts.property_groups);
(void) xmlAddChild(n, elts.template);
if (selts->instances == NULL)
selts->instances = n;
else
(void) xmlAddSibling(selts->instances, n);
}
}
static xmlNodePtr
export_service(scf_service_t *svc, int flags)
{
xmlNodePtr snode;
struct entity_elts elts;
struct template_elts template_elts;
int ret;
snode = xmlNewNode(NULL, (xmlChar *)"service");
if (snode == NULL)
uu_die(emsg_create_xml);
if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
scfdie();
safe_setprop(snode, name_attr, exp_str);
safe_setprop(snode, type_attr, "service");
safe_setprop(snode, "version", "0");
if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
scfdie();
(void) memset(&elts, 0, sizeof (elts));
(void) memset(&template_elts, 0, sizeof (template_elts));
while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
uint32_t pgflags;
if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
scfdie();
if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
continue;
if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
scfdie();
if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
export_dependency(exp_pg, &elts);
continue;
} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
export_method(exp_pg, &elts);
continue;
} else if (strcmp(exp_str, scf_group_framework) == 0) {
if (scf_pg_get_name(exp_pg, exp_str,
max_scf_name_len + 1) < 0)
scfdie();
if (strcmp(exp_str, scf_pg_general) == 0) {
export_svc_general(exp_pg, &elts);
continue;
} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
0) {
export_method_context(exp_pg, &elts);
continue;
} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
export_dependents(exp_pg, &elts);
continue;
} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
continue;
}
} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
export_template(exp_pg, &elts, &template_elts);
continue;
} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
export_notify_params(exp_pg, &elts);
continue;
}
export_pg(exp_pg, &elts, flags);
}
if (ret == -1)
scfdie();
if (template_elts.common_name != NULL) {
elts.template = xmlNewNode(NULL, (xmlChar *)"template");
(void) xmlAddChild(elts.template, template_elts.common_name);
(void) xmlAddChild(elts.template, template_elts.description);
(void) xmlAddChild(elts.template, template_elts.documentation);
} else {
xmlFreeNode(template_elts.description);
xmlFreeNode(template_elts.documentation);
}
if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
export_instance(exp_inst, &elts, flags);
if (ret == -1)
scfdie();
(void) xmlAddChild(snode, elts.create_default_instance);
(void) xmlAddChild(snode, elts.single_instance);
(void) xmlAddChild(snode, elts.restarter);
(void) xmlAddChildList(snode, elts.dependencies);
(void) xmlAddChildList(snode, elts.dependents);
(void) xmlAddChild(snode, elts.method_context);
(void) xmlAddChildList(snode, elts.exec_methods);
(void) xmlAddChildList(snode, elts.notify_params);
(void) xmlAddChildList(snode, elts.property_groups);
(void) xmlAddChildList(snode, elts.instances);
(void) xmlAddChild(snode, elts.stability);
(void) xmlAddChild(snode, elts.template);
return (snode);
}
static int
export_callback(void *data, scf_walkinfo_t *wip)
{
FILE *f;
xmlDocPtr doc;
xmlNodePtr sb;
int result;
struct export_args *argsp = (struct export_args *)data;
if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
(exp_pg = scf_pg_create(g_hndl)) == NULL ||
(exp_prop = scf_property_create(g_hndl)) == NULL ||
(exp_val = scf_value_create(g_hndl)) == NULL ||
(exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
(exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
(exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
(exp_val_iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
exp_str_sz = max_scf_len + 1;
exp_str = safe_malloc(exp_str_sz);
if (argsp->filename != NULL) {
errno = 0;
f = fopen(argsp->filename, "wb");
if (f == NULL) {
if (errno == 0)
uu_die(gettext("Could not open \"%s\": no free "
"stdio streams.\n"), argsp->filename);
else
uu_die(gettext("Could not open \"%s\""),
argsp->filename);
}
} else
f = stdout;
doc = xmlNewDoc((xmlChar *)"1.0");
if (doc == NULL)
uu_die(gettext("Could not create XML document.\n"));
if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
(xmlChar *)MANIFEST_DTD_PATH) == NULL)
uu_die(emsg_create_xml);
sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
if (sb == NULL)
uu_die(emsg_create_xml);
safe_setprop(sb, type_attr, "manifest");
safe_setprop(sb, name_attr, "export");
(void) xmlAddSibling(doc->children, sb);
(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
result = write_service_bundle(doc, f);
free(exp_str);
scf_iter_destroy(exp_val_iter);
scf_iter_destroy(exp_prop_iter);
scf_iter_destroy(exp_pg_iter);
scf_iter_destroy(exp_inst_iter);
scf_value_destroy(exp_val);
scf_property_destroy(exp_prop);
scf_pg_destroy(exp_pg);
scf_instance_destroy(exp_inst);
xmlFreeDoc(doc);
if (f != stdout)
(void) fclose(f);
return (result);
}
int
lscf_service_export(char *fmri, const char *filename, int flags)
{
struct export_args args;
char *fmridup;
const char *scope, *svc, *inst;
size_t cblen = 3 * max_scf_name_len;
char *canonbuf = alloca(cblen);
int ret, err;
lscf_prep_hndl();
bzero(&args, sizeof (args));
args.filename = filename;
args.flags = flags;
fmridup = alloca(strlen(fmri) + 1);
(void) strcpy(fmridup, fmri);
if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
inst != NULL) {
(void) strlcpy(canonbuf, "svc:/", cblen);
if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
(void) strlcat(canonbuf, "/", cblen);
(void) strlcat(canonbuf, scope, cblen);
}
(void) strlcat(canonbuf, svc, cblen);
fmri = canonbuf;
warn(gettext("Only services may be exported; ignoring "
"instance portion of argument.\n"));
}
err = 0;
if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
&args, &err, semerr)) != 0) {
if (ret != -1)
semerr(gettext("Failed to walk instances: %s\n"),
scf_strerror(ret));
return (-1);
}
if (err != 0)
return (-1);
return (0);
}
static xmlNodePtr
make_archive(int flags)
{
xmlNodePtr sb;
scf_scope_t *scope;
scf_service_t *svc;
scf_iter_t *iter;
int r;
if ((scope = scf_scope_create(g_hndl)) == NULL ||
(svc = scf_service_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL ||
(exp_inst = scf_instance_create(g_hndl)) == NULL ||
(exp_pg = scf_pg_create(g_hndl)) == NULL ||
(exp_prop = scf_property_create(g_hndl)) == NULL ||
(exp_val = scf_value_create(g_hndl)) == NULL ||
(exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
(exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
(exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
(exp_val_iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
exp_str_sz = max_scf_len + 1;
exp_str = safe_malloc(exp_str_sz);
sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
if (sb == NULL)
uu_die(emsg_create_xml);
safe_setprop(sb, type_attr, "archive");
safe_setprop(sb, name_attr, "none");
if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
scfdie();
if (scf_iter_scope_services(iter, scope) != 0)
scfdie();
for (;;) {
r = scf_iter_next_service(iter, svc);
if (r == 0)
break;
if (r != 1)
scfdie();
if (scf_service_get_name(svc, exp_str,
max_scf_name_len + 1) < 0)
scfdie();
if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
continue;
(void) xmlAddChild(sb, export_service(svc, flags));
}
free(exp_str);
scf_iter_destroy(exp_val_iter);
scf_iter_destroy(exp_prop_iter);
scf_iter_destroy(exp_pg_iter);
scf_iter_destroy(exp_inst_iter);
scf_value_destroy(exp_val);
scf_property_destroy(exp_prop);
scf_pg_destroy(exp_pg);
scf_instance_destroy(exp_inst);
scf_iter_destroy(iter);
scf_service_destroy(svc);
scf_scope_destroy(scope);
return (sb);
}
int
lscf_archive(const char *filename, int flags)
{
FILE *f;
xmlDocPtr doc;
int result;
lscf_prep_hndl();
if (filename != NULL) {
errno = 0;
f = fopen(filename, "wb");
if (f == NULL) {
if (errno == 0)
uu_die(gettext("Could not open \"%s\": no free "
"stdio streams.\n"), filename);
else
uu_die(gettext("Could not open \"%s\""),
filename);
}
} else
f = stdout;
doc = xmlNewDoc((xmlChar *)"1.0");
if (doc == NULL)
uu_die(gettext("Could not create XML document.\n"));
if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
(xmlChar *)MANIFEST_DTD_PATH) == NULL)
uu_die(emsg_create_xml);
(void) xmlAddSibling(doc->children, make_archive(flags));
result = write_service_bundle(doc, f);
xmlFreeDoc(doc);
if (f != stdout)
(void) fclose(f);
return (result);
}
int
lscf_profile_extract(const char *filename)
{
FILE *f;
xmlDocPtr doc;
xmlNodePtr sb, snode, inode;
scf_scope_t *scope;
scf_service_t *svc;
scf_instance_t *inst;
scf_propertygroup_t *pg;
scf_property_t *prop;
scf_value_t *val;
scf_iter_t *siter, *iiter;
int r, s;
char *namebuf;
uint8_t b;
int result;
lscf_prep_hndl();
if (filename != NULL) {
errno = 0;
f = fopen(filename, "wb");
if (f == NULL) {
if (errno == 0)
uu_die(gettext("Could not open \"%s\": no "
"free stdio streams.\n"), filename);
else
uu_die(gettext("Could not open \"%s\""),
filename);
}
} else
f = stdout;
doc = xmlNewDoc((xmlChar *)"1.0");
if (doc == NULL)
uu_die(gettext("Could not create XML document.\n"));
if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
(xmlChar *)MANIFEST_DTD_PATH) == NULL)
uu_die(emsg_create_xml);
sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
if (sb == NULL)
uu_die(emsg_create_xml);
safe_setprop(sb, type_attr, "profile");
safe_setprop(sb, name_attr, "extract");
(void) xmlAddSibling(doc->children, sb);
if ((scope = scf_scope_create(g_hndl)) == NULL ||
(svc = scf_service_create(g_hndl)) == NULL ||
(inst = scf_instance_create(g_hndl)) == NULL ||
(pg = scf_pg_create(g_hndl)) == NULL ||
(prop = scf_property_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL ||
(siter = scf_iter_create(g_hndl)) == NULL ||
(iiter = scf_iter_create(g_hndl)) == NULL)
scfdie();
if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
scfdie();
if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
scfdie();
namebuf = safe_malloc(max_scf_name_len + 1);
while ((r = scf_iter_next_service(siter, svc)) == 1) {
if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
scfdie();
snode = xmlNewNode(NULL, (xmlChar *)"service");
if (snode == NULL)
uu_die(emsg_create_xml);
if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
0)
scfdie();
safe_setprop(snode, name_attr, namebuf);
safe_setprop(snode, type_attr, "service");
safe_setprop(snode, "version", "0");
while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (g_verbose) {
ssize_t len;
char *fmri;
len =
scf_instance_to_fmri(inst, NULL, 0);
if (len < 0)
scfdie();
fmri = safe_malloc(len + 1);
if (scf_instance_to_fmri(inst, fmri,
len + 1) < 0)
scfdie();
warn("Instance %s has no \"%s\" "
"property group.\n", fmri,
scf_pg_general);
free(fmri);
}
continue;
}
if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
prop_get_val(prop, val) != 0)
continue;
inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
NULL);
if (inode == NULL)
uu_die(emsg_create_xml);
if (scf_instance_get_name(inst, namebuf,
max_scf_name_len + 1) < 0)
scfdie();
safe_setprop(inode, name_attr, namebuf);
if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
scfdie();
safe_setprop(inode, enabled_attr, b ? true : false);
}
if (s < 0)
scfdie();
if (snode->children != NULL)
(void) xmlAddChild(sb, snode);
else
xmlFreeNode(snode);
}
if (r < 0)
scfdie();
free(namebuf);
result = write_service_bundle(doc, f);
xmlFreeDoc(doc);
if (f != stdout)
(void) fclose(f);
return (result);
}
static int
select_inst(const char *name)
{
scf_instance_t *inst;
scf_error_t err;
assert(cur_svc != NULL);
inst = scf_instance_create(g_hndl);
if (inst == NULL)
scfdie();
if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
cur_inst = inst;
return (0);
}
err = scf_error();
if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
scfdie();
scf_instance_destroy(inst);
return (1);
}
static int
select_svc(const char *name)
{
scf_service_t *svc;
scf_error_t err;
assert(cur_scope != NULL);
svc = scf_service_create(g_hndl);
if (svc == NULL)
scfdie();
if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
cur_svc = svc;
return (0);
}
err = scf_error();
if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
scfdie();
scf_service_destroy(svc);
return (1);
}
static int
select_callback(void *unused, scf_walkinfo_t *wip)
{
scf_instance_t *inst;
scf_service_t *svc;
scf_scope_t *scope;
if (wip->inst != NULL) {
if ((scope = scf_scope_create(g_hndl)) == NULL ||
(svc = scf_service_create(g_hndl)) == NULL ||
(inst = scf_instance_create(g_hndl)) == NULL)
scfdie();
if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
scfdie();
} else {
assert(wip->svc != NULL);
if ((scope = scf_scope_create(g_hndl)) == NULL ||
(svc = scf_service_create(g_hndl)) == NULL)
scfdie();
if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
scfdie();
inst = NULL;
}
assert(cur_scope != NULL);
scf_scope_destroy(cur_scope);
scf_service_destroy(cur_svc);
scf_instance_destroy(cur_inst);
cur_scope = scope;
cur_svc = svc;
cur_inst = inst;
return (0);
}
static int
validate_callback(void *fmri_p, scf_walkinfo_t *wip)
{
char **fmri = fmri_p;
*fmri = strdup(wip->fmri);
if (*fmri == NULL)
uu_die(gettext("Out of memory.\n"));
return (0);
}
void
lscf_validate_fmri(const char *fmri)
{
int ret = 0;
size_t inst_sz;
char *inst_fmri = NULL;
scf_tmpl_errors_t *errs = NULL;
char *snapbuf = NULL;
lscf_prep_hndl();
if (fmri == NULL) {
inst_sz = max_scf_fmri_len + 1;
inst_fmri = safe_malloc(inst_sz);
if (cur_snap != NULL) {
snapbuf = safe_malloc(max_scf_name_len + 1);
if (scf_snapshot_get_name(cur_snap, snapbuf,
max_scf_name_len + 1) < 0)
scfdie();
}
if (cur_inst == NULL) {
semerr(gettext("No instance selected\n"));
goto cleanup;
} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
inst_sz) >= inst_sz) {
uu_die(gettext("Unexpected error! file %s, line %d\n"),
__FILE__, __LINE__);
}
} else {
scf_error_t scf_err;
int err = 0;
if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
validate_callback, &inst_fmri, &err, semerr)) != 0) {
uu_warn("Failed to walk instances: %s\n",
scf_strerror(scf_err));
goto cleanup;
}
if (err != 0) {
goto cleanup;
}
}
ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
SCF_TMPL_VALIDATE_FLAG_CURRENT);
if (ret == -1) {
if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
warn(gettext("Template data for %s is 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()));
}
} else if (ret == 1 && errs != NULL) {
scf_tmpl_error_t *err = NULL;
char *msg;
size_t len = 256;
int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
SCF_TMPL_STRERROR_HUMAN : 0;
msg = safe_malloc(len);
while ((err = scf_tmpl_next_error(errs)) != NULL) {
int ret;
if ((ret = scf_tmpl_strerror(err, msg, len,
flag)) >= len) {
len = ret + 1;
msg = realloc(msg, len);
if (msg == NULL)
uu_die(gettext(
"Out of memory.\n"));
(void) scf_tmpl_strerror(err, msg, len,
flag);
}
(void) fprintf(stderr, "%s\n", msg);
}
if (msg != NULL)
free(msg);
}
if (errs != NULL)
scf_tmpl_errors_destroy(errs);
cleanup:
free(inst_fmri);
free(snapbuf);
}
static void
lscf_validate_file(const char *filename)
{
tmpl_errors_t *errs;
bundle_t *b = internal_bundle_new();
if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
tmpl_errors_print(stderr, errs, "");
semerr(gettext("Validation failed.\n"));
}
tmpl_errors_destroy(errs);
}
(void) internal_bundle_free(b);
}
void
lscf_validate(const char *arg)
{
const char *str;
if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
lscf_validate_file(str);
} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
lscf_validate_fmri(str);
} else if (access(arg, R_OK | F_OK) == 0) {
lscf_validate_file(arg);
} else {
lscf_validate_fmri(arg);
}
}
void
lscf_select(const char *fmri)
{
int ret, err;
lscf_prep_hndl();
if (cur_snap != NULL) {
struct snaplevel *elt;
char *buf;
elt = uu_list_next(cur_levels, cur_elt);
if (elt == NULL) {
semerr(gettext("No children.\n"));
return;
}
buf = safe_malloc(max_scf_name_len + 1);
if (scf_snaplevel_get_instance_name(elt->sl, buf,
max_scf_name_len + 1) < 0)
scfdie();
if (strcmp(buf, fmri) != 0) {
semerr(gettext("No such child.\n"));
free(buf);
return;
}
free(buf);
cur_elt = elt;
cur_level = elt->sl;
return;
}
if (strcmp(fmri, "svc:") == 0) {
scf_instance_destroy(cur_inst);
scf_service_destroy(cur_svc);
cur_inst = NULL;
cur_svc = NULL;
return;
}
if (strcmp(fmri, ":properties") == 0) {
semerr(gettext(":properties is not an entity. Try 'listprop' "
"to list properties.\n"));
return;
}
if (cur_inst != NULL) {
;
} else if (cur_svc != NULL) {
if (select_inst(fmri) != 1)
return;
} else {
if (select_svc(fmri) != 1)
return;
}
err = 0;
if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
select_callback, NULL, &err, semerr)) != 0) {
semerr(gettext("Failed to walk instances: %s\n"),
scf_strerror(ret));
}
}
void
lscf_unselect(void)
{
lscf_prep_hndl();
if (cur_snap != NULL) {
struct snaplevel *elt;
elt = uu_list_prev(cur_levels, cur_elt);
if (elt == NULL) {
semerr(gettext("No parent levels.\n"));
} else {
cur_elt = elt;
cur_level = elt->sl;
}
} else if (cur_inst != NULL) {
scf_instance_destroy(cur_inst);
cur_inst = NULL;
} else if (cur_svc != NULL) {
scf_service_destroy(cur_svc);
cur_svc = NULL;
} else {
semerr(gettext("Cannot unselect at scope level.\n"));
}
}
void
lscf_get_selection_str(char *buf, size_t bufsz)
{
char *cp;
ssize_t fmrilen, szret;
boolean_t deleted = B_FALSE;
if (g_hndl == NULL) {
(void) strlcpy(buf, "svc:", bufsz);
return;
}
if (cur_level != NULL) {
assert(cur_snap != NULL);
assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
+ 2 + max_scf_name_len + 1 + 1);
buf[0] = '[';
szret = scf_snapshot_get_name(cur_snap, buf + 1,
max_scf_name_len + 1);
if (szret < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto snap_deleted;
}
(void) strcat(buf, "]svc:/");
cp = strchr(buf, '\0');
szret = scf_snaplevel_get_service_name(cur_level, cp,
max_scf_name_len + 1);
if (szret < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto snap_deleted;
}
cp = strchr(cp, '\0');
if (snaplevel_is_instance(cur_level)) {
*cp++ = ':';
if (scf_snaplevel_get_instance_name(cur_level, cp,
max_scf_name_len + 1) < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto snap_deleted;
}
} else {
*cp++ = '[';
*cp++ = ':';
if (scf_instance_get_name(cur_inst, cp,
max_scf_name_len + 1) < 0) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
goto snap_deleted;
}
(void) strcat(buf, "]");
}
return;
snap_deleted:
deleted = B_TRUE;
free(buf);
unselect_cursnap();
}
assert(cur_snap == NULL);
if (cur_inst != NULL) {
assert(cur_svc != NULL);
assert(cur_scope != NULL);
fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
if (fmrilen >= 0) {
assert(fmrilen < bufsz);
if (deleted)
warn(emsg_deleted);
return;
}
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
deleted = B_TRUE;
scf_instance_destroy(cur_inst);
cur_inst = NULL;
}
if (cur_svc != NULL) {
assert(cur_scope != NULL);
szret = scf_service_to_fmri(cur_svc, buf, bufsz);
if (szret >= 0) {
assert(szret < bufsz);
if (deleted)
warn(emsg_deleted);
return;
}
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
deleted = B_TRUE;
scf_service_destroy(cur_svc);
cur_svc = NULL;
}
assert(cur_scope != NULL);
fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
if (fmrilen < 0)
scfdie();
assert(fmrilen < bufsz);
if (deleted)
warn(emsg_deleted);
}
void
lscf_list(const char *pattern)
{
scf_iter_t *iter;
char *buf;
int ret;
lscf_prep_hndl();
if (cur_level != NULL) {
struct snaplevel *elt;
(void) fputs(COLON_NAMESPACES, stdout);
elt = uu_list_next(cur_levels, cur_elt);
if (elt == NULL)
return;
buf = safe_malloc(max_scf_name_len + 1);
if (scf_snaplevel_get_instance_name(elt->sl, buf,
max_scf_name_len + 1) >= 0) {
(void) puts(buf);
} else {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
free(buf);
return;
}
if (cur_inst != NULL) {
(void) fputs(COLON_NAMESPACES, stdout);
return;
}
iter = scf_iter_create(g_hndl);
if (iter == NULL)
scfdie();
buf = safe_malloc(max_scf_name_len + 1);
if (cur_svc != NULL) {
scf_instance_t *inst;
inst = scf_instance_create(g_hndl);
if (inst == NULL)
scfdie();
if (scf_iter_service_instances(iter, cur_svc) == 0) {
safe_printf(COLON_NAMESPACES);
for (;;) {
ret = scf_iter_next_instance(iter, inst);
if (ret == 0)
break;
if (ret != 1) {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
break;
}
if (scf_instance_get_name(inst, buf,
max_scf_name_len + 1) >= 0) {
if (pattern == NULL ||
fnmatch(pattern, buf, 0) == 0)
(void) puts(buf);
} else {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
}
} else {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
scf_instance_destroy(inst);
} else {
scf_service_t *svc;
assert(cur_scope != NULL);
svc = scf_service_create(g_hndl);
if (svc == NULL)
scfdie();
if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
scfdie();
for (;;) {
ret = scf_iter_next_service(iter, svc);
if (ret == 0)
break;
if (ret != 1)
scfdie();
if (scf_service_get_name(svc, buf,
max_scf_name_len + 1) >= 0) {
if (pattern == NULL ||
fnmatch(pattern, buf, 0) == 0)
safe_printf("%s\n", buf);
} else {
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
}
}
scf_service_destroy(svc);
}
free(buf);
scf_iter_destroy(iter);
}
void
lscf_add(const char *name)
{
lscf_prep_hndl();
if (cur_snap != NULL) {
semerr(emsg_cant_modify_snapshots);
} else if (cur_inst != NULL) {
semerr(gettext("Cannot add entities to an instance.\n"));
} else if (cur_svc != NULL) {
if (scf_service_add_instance(cur_svc, name, NULL) !=
SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_INVALID_ARGUMENT:
semerr(gettext("Invalid name.\n"));
break;
case SCF_ERROR_EXISTS:
semerr(gettext("Instance already exists.\n"));
break;
case SCF_ERROR_PERMISSION_DENIED:
semerr(emsg_permission_denied);
break;
default:
scfdie();
}
}
} else {
assert(cur_scope != NULL);
if (scf_scope_add_service(cur_scope, name, NULL) !=
SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_INVALID_ARGUMENT:
semerr(gettext("Invalid name.\n"));
break;
case SCF_ERROR_EXISTS:
semerr(gettext("Service already exists.\n"));
break;
case SCF_ERROR_PERMISSION_DENIED:
semerr(emsg_permission_denied);
break;
case SCF_ERROR_BACKEND_READONLY:
semerr(emsg_read_only);
break;
default:
scfdie();
}
}
}
}
static int
entity_has_no_pgs(void *ent, int isservice)
{
scf_iter_t *iter = NULL;
scf_propertygroup_t *pg = NULL;
uint32_t flags;
int err;
int ret = 1;
if ((iter = scf_iter_create(g_hndl)) == NULL ||
(pg = scf_pg_create(g_hndl)) == NULL)
scfdie();
if (isservice) {
if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
scfdie();
} else {
if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
scfdie();
}
while ((err = scf_iter_next_pg(iter, pg)) == 1) {
if (scf_pg_get_flags(pg, &flags) != 0)
scfdie();
if (flags & SCF_PG_FLAG_NONPERSISTENT)
continue;
ret = 0;
break;
}
if (err == -1)
scfdie();
scf_pg_destroy(pg);
scf_iter_destroy(iter);
return (ret);
}
static int
svc_has_no_insts(scf_service_t *svc)
{
scf_instance_t *inst;
scf_iter_t *iter;
int r;
int ret = 1;
if ((inst = scf_instance_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_service_instances(iter, svc) != 0)
scfdie();
r = scf_iter_next_instance(iter, inst);
if (r == 1) {
ret = 0;
} else if (r == 0) {
ret = 1;
} else if (r == -1) {
scfdie();
} else {
bad_error("scf_iter_next_instance", r);
}
scf_iter_destroy(iter);
scf_instance_destroy(inst);
return (ret);
}
static scf_error_t
delete_dependency_pg(const char *fmri, const char *name)
{
void *entity = NULL;
int isservice;
scf_propertygroup_t *pg = NULL;
scf_error_t result;
char *pgty;
scf_service_t *svc = NULL;
scf_instance_t *inst = NULL;
scf_iter_t *iter = NULL;
char *name_buf = NULL;
result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
switch (result) {
case SCF_ERROR_NONE:
break;
case SCF_ERROR_NO_MEMORY:
uu_die(gettext("Out of memory.\n"));
case SCF_ERROR_INVALID_ARGUMENT:
case SCF_ERROR_CONSTRAINT_VIOLATED:
return (SCF_ERROR_INVALID_ARGUMENT);
case SCF_ERROR_NOT_FOUND:
result = SCF_ERROR_NONE;
goto out;
default:
bad_error("fmri_to_entity", result);
}
pg = scf_pg_create(g_hndl);
if (pg == NULL)
scfdie();
if (entity_get_pg(entity, isservice, name, pg) != 0) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
result = SCF_ERROR_NONE;
goto out;
}
pgty = safe_malloc(max_scf_pg_type_len + 1);
if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
scfdie();
if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
result = SCF_ERROR_TYPE_MISMATCH;
free(pgty);
goto out;
}
free(pgty);
if (scf_pg_delete(pg) != 0) {
result = scf_error();
if (result != SCF_ERROR_PERMISSION_DENIED)
scfdie();
goto out;
}
result = SCF_ERROR_NONE;
if (isservice) {
svc = (scf_service_t *)entity;
if ((inst = scf_instance_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
name_buf = safe_malloc(max_scf_name_len + 1);
} else {
inst = (scf_instance_t *)entity;
}
if (!isservice && entity_has_no_pgs(entity, isservice)) {
if ((svc = scf_service_create(g_hndl)) == NULL)
scfdie();
if (scf_instance_get_parent(inst, svc) != 0)
scfdie();
if (scf_instance_delete(inst) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
result = SCF_ERROR_PERMISSION_DENIED;
goto out;
}
inst = NULL;
}
if (svc != NULL &&
svc_has_no_insts(svc) &&
entity_has_no_pgs((void *)svc, 1)) {
if (scf_service_delete(svc) == 0) {
if (isservice) {
svc = NULL;
}
goto out;
}
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
result = SCF_ERROR_PERMISSION_DENIED;
}
if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
(void) refresh_entity(isservice, entity, fmri, inst, iter,
name_buf);
}
out:
if (isservice && (inst != NULL && iter != NULL)) {
free(name_buf);
scf_iter_destroy(iter);
scf_instance_destroy(inst);
}
if (!isservice && svc != NULL) {
scf_service_destroy(svc);
}
scf_pg_destroy(pg);
if (entity != NULL)
entity_destroy(entity, isservice);
return (result);
}
static int
delete_dependents(scf_propertygroup_t *pg)
{
char *pgty, *name, *fmri;
scf_property_t *prop;
scf_value_t *val;
scf_iter_t *iter;
int r;
scf_error_t err;
pgty = safe_malloc(max_scf_pg_type_len + 1);
if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
scfdie();
if (strcmp(pgty, scf_group_framework) != 0) {
if (g_verbose) {
fmri = safe_malloc(max_scf_fmri_len + 1);
if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
scfdie();
warn(gettext("Property group %s is not of expected "
"type %s.\n"), fmri, scf_group_framework);
free(fmri);
}
free(pgty);
return (-1);
}
free(pgty);
if ((prop = scf_property_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
scfdie();
name = safe_malloc(max_scf_name_len + 1);
fmri = safe_malloc(max_scf_fmri_len + 2);
while ((r = scf_iter_next_property(iter, prop)) == 1) {
scf_type_t ty;
if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
scfdie();
if (scf_property_type(prop, &ty) != SCF_SUCCESS)
scfdie();
if ((ty != SCF_TYPE_ASTRING &&
prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
prop_get_val(prop, val) != 0)
continue;
if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
scfdie();
err = delete_dependency_pg(fmri, name);
if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
if (scf_property_to_fmri(prop, fmri,
max_scf_fmri_len + 2) < 0)
scfdie();
warn(gettext("Value of %s is not a valid FMRI.\n"),
fmri);
} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
warn(gettext("Property group \"%s\" of entity \"%s\" "
"does not have dependency type.\n"), name, fmri);
} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
warn(gettext("Could not delete property group \"%s\" "
"of entity \"%s\" (permission denied).\n"), name,
fmri);
}
}
if (r == -1)
scfdie();
scf_value_destroy(val);
scf_property_destroy(prop);
return (0);
}
static int
inst_is_running(scf_instance_t *inst)
{
scf_propertygroup_t *pg;
scf_property_t *prop;
scf_value_t *val;
char buf[MAX_SCF_STATE_STRING_SZ];
int ret = 0;
ssize_t szret;
if ((pg = scf_pg_create(g_hndl)) == NULL ||
(prop = scf_property_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL)
scfdie();
if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
goto out;
}
if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
prop_get_val(prop, val) != 0)
goto out;
szret = scf_value_get_astring(val, buf, sizeof (buf));
assert(szret >= 0);
ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
out:
scf_value_destroy(val);
scf_property_destroy(prop);
scf_pg_destroy(pg);
return (ret);
}
static uint8_t
pg_is_external_dependency(scf_propertygroup_t *pg)
{
char *type;
scf_value_t *val;
scf_property_t *prop;
uint8_t b = B_FALSE;
type = safe_malloc(max_scf_pg_type_len + 1);
if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
scfdie();
if ((prop = scf_property_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL)
scfdie();
if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
if (pg_get_prop(pg, scf_property_external, prop) == 0) {
if (scf_property_get_value(prop, val) != 0)
scfdie();
if (scf_value_get_boolean(val, &b) != 0)
scfdie();
}
}
free(type);
(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
static int
lscf_instance_delete(scf_instance_t *inst, int force)
{
scf_propertygroup_t *pg;
scf_snapshot_t *snap;
scf_iter_t *iter;
int err;
int external = 0;
if (!force && inst_is_running(inst)) {
char *fmri;
fmri = safe_malloc(max_scf_fmri_len + 1);
if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
scfdie();
semerr(gettext("Instance %s may be running. "
"Use delete -f if it is not.\n"), fmri);
free(fmri);
return (DELETE_FAILURE);
}
pg = scf_pg_create(g_hndl);
if (pg == NULL)
scfdie();
if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
(void) delete_dependents(pg);
else if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
scf_pg_destroy(pg);
if ((iter = scf_iter_create(g_hndl)) == NULL ||
(pg = scf_pg_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_instance_pgs(iter, inst) < 0)
scfdie();
while ((err = scf_iter_next_pg(iter, pg)) == 1) {
if (pg_is_external_dependency(pg)) {
external = 1;
continue;
}
if (scf_pg_delete(pg) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
else {
semerr(emsg_permission_denied);
(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) {
if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
NULL)
scfdie();
if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
scfdie();
if (scf_iter_instance_snapshots(iter, inst) == -1)
scfdie();
while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
if (_scf_snapshot_delete(snap) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
(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();
semerr(emsg_permission_denied);
return (DELETE_FAILURE);
}
return (DELETE_SUCCESS_NOEXTDEPS);
}
static int
lscf_service_delete(scf_service_t *svc, int force)
{
int r;
scf_instance_t *inst;
scf_propertygroup_t *pg;
scf_iter_t *iter;
int ret;
int external = 0;
if ((inst = scf_instance_create(g_hndl)) == NULL ||
(pg = scf_pg_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_service_instances(iter, svc) != 0)
scfdie();
for (r = scf_iter_next_instance(iter, inst);
r == 1;
r = scf_iter_next_instance(iter, inst)) {
ret = lscf_instance_delete(inst, force);
if (ret == DELETE_FAILURE) {
scf_iter_destroy(iter);
scf_pg_destroy(pg);
scf_instance_destroy(inst);
return (DELETE_FAILURE);
}
if (ret == DELETE_SUCCESS_EXTDEPS)
external |= 1;
}
if (r != 0)
scfdie();
if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
(void) delete_dependents(pg);
else if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
scf_iter_destroy(iter);
scf_pg_destroy(pg);
scf_instance_destroy(inst);
if ((pg = scf_pg_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_service_pgs(iter, svc) < 0)
scfdie();
while ((r = scf_iter_next_pg(iter, pg)) == 1) {
if (pg_is_external_dependency(pg)) {
external |= 2;
continue;
}
if (scf_pg_delete(pg) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
else {
semerr(emsg_permission_denied);
(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();
semerr(emsg_permission_denied);
return (DELETE_FAILURE);
}
static int
delete_callback(void *data, scf_walkinfo_t *wip)
{
int force = (int)data;
if (wip->inst != NULL)
(void) lscf_instance_delete(wip->inst, force);
else
(void) lscf_service_delete(wip->svc, force);
return (0);
}
void
lscf_delete(const char *fmri, int force)
{
scf_service_t *svc;
scf_instance_t *inst;
int ret;
lscf_prep_hndl();
if (cur_snap != NULL) {
if (!snaplevel_is_instance(cur_level)) {
char *buf;
buf = safe_malloc(max_scf_name_len + 1);
if (scf_instance_get_name(cur_inst, buf,
max_scf_name_len + 1) >= 0) {
if (strcmp(buf, fmri) == 0) {
semerr(emsg_cant_modify_snapshots);
free(buf);
return;
}
} else if (scf_error() != SCF_ERROR_DELETED) {
scfdie();
}
free(buf);
}
} else if (cur_inst != NULL) {
;
} else if (cur_svc != NULL) {
inst = scf_instance_create(g_hndl);
if (inst == NULL)
scfdie();
if (scf_service_get_instance(cur_svc, fmri, inst) ==
SCF_SUCCESS) {
(void) lscf_instance_delete(inst, force);
scf_instance_destroy(inst);
return;
}
if (scf_error() != SCF_ERROR_NOT_FOUND &&
scf_error() != SCF_ERROR_INVALID_ARGUMENT)
scfdie();
scf_instance_destroy(inst);
} else {
assert(cur_scope != NULL);
svc = scf_service_create(g_hndl);
if (svc == NULL)
scfdie();
if (scf_scope_get_service(cur_scope, fmri, svc) ==
SCF_SUCCESS) {
(void) lscf_service_delete(svc, force);
scf_service_destroy(svc);
return;
}
if (scf_error() != SCF_ERROR_NOT_FOUND &&
scf_error() != SCF_ERROR_INVALID_ARGUMENT)
scfdie();
scf_service_destroy(svc);
}
if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
delete_callback, (void *)force, NULL, semerr)) != 0) {
semerr(gettext("Failed to walk instances: %s\n"),
scf_strerror(ret));
}
}
static void
list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
{
char *buf;
uint32_t flags;
buf = safe_malloc(max_scf_pg_type_len + 1);
if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
scfdie();
if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
scfdie();
safe_printf("%-*s %s", namewidth, name, buf);
if (flags & SCF_PG_FLAG_NONPERSISTENT)
safe_printf("\tNONPERSISTENT");
safe_printf("\n");
free(buf);
}
static boolean_t
prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
{
if (scf_property_get_value(prop, val) == 0) {
return (B_FALSE);
} else {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
return (B_FALSE);
case SCF_ERROR_PERMISSION_DENIED:
case SCF_ERROR_CONSTRAINT_VIOLATED:
return (B_TRUE);
default:
scfdie();
}
}
}
static void
list_prop_info(const scf_property_t *prop, const char *name, size_t len)
{
scf_iter_t *iter;
scf_value_t *val;
const char *type;
int multiple_strings = 0;
int ret;
if ((iter = scf_iter_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL)
scfdie();
type = prop_to_typestr(prop);
assert(type != NULL);
safe_printf("%-*s %-7s ", len, name, type);
if (prop_has_multiple_values(prop, val) &&
(scf_value_type(val) == SCF_TYPE_ASTRING ||
scf_value_type(val) == SCF_TYPE_USTRING))
multiple_strings = 1;
if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_value(iter, val)) == 1) {
char *buf;
ssize_t vlen, szret;
vlen = scf_value_get_as_string(val, NULL, 0);
if (vlen < 0)
scfdie();
buf = safe_malloc(vlen + 1);
szret = scf_value_get_as_string(val, buf, vlen + 1);
if (szret < 0)
scfdie();
assert(szret <= vlen);
if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
safe_printf(" \"");
(void) quote_and_print(buf, stdout, 0);
(void) putchar('"');
if (ferror(stdout)) {
(void) putchar('\n');
uu_die(gettext("Error writing to stdout.\n"));
}
} else {
safe_printf(" %s", buf);
}
free(buf);
}
if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
if (putchar('\n') != '\n')
uu_die(gettext("Could not output newline"));
}
static void
list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
{
char *buf;
uint8_t required;
scf_property_t *stability_prop;
scf_value_t *stability_val;
if (templates == 0)
return;
if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
(stability_val = scf_value_create(g_hndl)) == NULL)
scfdie();
if (templates == 2 && pg != NULL) {
if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
stability_prop) == 0) {
if (prop_check_type(stability_prop,
SCF_TYPE_ASTRING) == 0 &&
prop_get_val(stability_prop, stability_val) == 0) {
char *stability;
stability = safe_malloc(max_scf_value_len + 1);
if (scf_value_get_astring(stability_val,
stability, max_scf_value_len + 1) == -1 &&
scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
safe_printf("%s%s: %s\n", TMPL_INDENT,
gettext("stability"), stability);
free(stability);
}
} else if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
}
scf_property_destroy(stability_prop);
scf_value_destroy(stability_val);
if (pgt == NULL)
return;
if (pg == NULL || templates == 2) {
if (scf_tmpl_pg_name(pgt, &buf) != -1) {
if (pg != NULL)
safe_printf("%s", TMPL_INDENT);
safe_printf("%s: ", gettext("name"));
safe_printf("%s\n", buf);
free(buf);
}
if (scf_tmpl_pg_type(pgt, &buf) != -1) {
if (pg != NULL)
safe_printf("%s", TMPL_INDENT);
safe_printf("%s: ", gettext("type"));
safe_printf("%s\n", buf);
free(buf);
}
}
if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
required ? "true" : "false");
if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
buf);
free(buf);
}
if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
buf);
free(buf);
}
if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
if (templates == 2)
safe_printf("%s%s: %s\n", TMPL_INDENT,
gettext("description"), buf);
else
safe_printf("%s%s\n", TMPL_INDENT, buf);
free(buf);
}
}
static void
print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
int as_value)
{
char *buf;
if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
if (as_value == 0)
safe_printf("%s", TMPL_CHOICE_INDENT);
else
safe_printf("%s", TMPL_INDENT);
safe_printf("%s: %s\n", gettext("value common name"), buf);
free(buf);
}
if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
if (as_value == 0)
safe_printf("%s", TMPL_CHOICE_INDENT);
else
safe_printf("%s", TMPL_INDENT);
safe_printf("%s: %s\n", gettext("value description"), buf);
free(buf);
}
}
static void
print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
{
safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
safe_printf("%s\n", val_buf);
print_template_value_details(prt, val_buf, 1);
}
static void
print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
{
int i, printed = 0;
scf_values_t values;
scf_count_ranges_t c_ranges;
scf_int_ranges_t i_ranges;
printed = 0;
i = 0;
if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
gettext("value constraints"));
printed++;
for (i = 0; i < values.value_count; ++i) {
safe_printf("%s%s: %s\n", TMPL_INDENT,
gettext("value name"), values.values_as_strings[i]);
if (verbose == 1)
print_template_value_details(prt,
values.values_as_strings[i], 0);
}
scf_values_destroy(&values);
}
if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
if (printed++ == 0)
safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
gettext("value constraints"));
for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
gettext("range"), c_ranges.scr_min[i],
c_ranges.scr_max[i]);
}
scf_count_ranges_destroy(&c_ranges);
} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
if (printed++ == 0)
safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
gettext("value constraints"));
for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
gettext("range"), i_ranges.sir_min[i],
i_ranges.sir_max[i]);
}
scf_int_ranges_destroy(&i_ranges);
}
}
static void
print_template_choices(scf_prop_tmpl_t *prt, int verbose)
{
int i = 0, printed = 0;
scf_values_t values;
scf_count_ranges_t c_ranges;
scf_int_ranges_t i_ranges;
printed = 0;
if (scf_tmpl_value_name_choices(prt, &values) == 0) {
safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
gettext("value constraints"));
printed++;
for (i = 0; i < values.value_count; i++) {
safe_printf("%s%s: %s\n", TMPL_INDENT,
gettext("value name"), values.values_as_strings[i]);
if (verbose == 1)
print_template_value_details(prt,
values.values_as_strings[i], 0);
}
scf_values_destroy(&values);
}
if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
if (printed++ == 0)
safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
gettext("value choices"));
safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
gettext("range"), c_ranges.scr_min[i],
c_ranges.scr_max[i]);
}
scf_count_ranges_destroy(&c_ranges);
} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
if (printed++ == 0)
safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
gettext("value choices"));
safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
gettext("range"), i_ranges.sir_min[i],
i_ranges.sir_max[i]);
}
scf_int_ranges_destroy(&i_ranges);
}
}
static void
list_values_by_template(scf_prop_tmpl_t *prt)
{
print_template_constraints(prt, 1);
print_template_choices(prt, 1);
}
static void
list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
{
char *val_buf;
scf_iter_t *iter;
scf_value_t *val;
int ret;
if ((iter = scf_iter_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
scfdie();
val_buf = safe_malloc(max_scf_value_len + 1);
while ((ret = scf_iter_next_value(iter, val)) == 1) {
if (scf_value_get_as_string(val, val_buf,
max_scf_value_len + 1) < 0)
scfdie();
print_template_value(prt, val_buf);
}
if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
free(val_buf);
print_template_constraints(prt, 0);
print_template_choices(prt, 0);
}
static void
list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
{
char *buf;
uint8_t u_buf;
int i;
uint64_t min, max;
scf_values_t values;
if (prt == NULL || templates == 0)
return;
if (prop == NULL) {
safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
if (scf_tmpl_prop_name(prt, &buf) > 0) {
safe_printf("%s\n", buf);
free(buf);
} else
safe_printf("(%s)\n", gettext("any"));
}
if (prop == NULL || templates == 2) {
if (prop != NULL)
safe_printf("%s", TMPL_INDENT);
else
safe_printf("%s", TMPL_VALUE_INDENT);
safe_printf("%s: ", gettext("type"));
if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
safe_printf("%s\n", buf);
free(buf);
} else
safe_printf("(%s)\n", gettext("any"));
}
if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
u_buf ? "true" : "false");
if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
buf);
free(buf);
}
if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
buf);
free(buf);
}
if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
safe_printf("%s%s\n", TMPL_INDENT, buf);
free(buf);
}
if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
scf_tmpl_visibility_to_string(u_buf));
if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
gettext("minimum number of values"), min);
if (max == ULLONG_MAX) {
safe_printf("%s%s: %s\n", TMPL_INDENT,
gettext("maximum number of values"),
gettext("unlimited"));
} else {
safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
gettext("maximum number of values"), max);
}
}
if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
for (i = 0; i < values.value_count; i++) {
if (i == 0) {
safe_printf("%s%s:", TMPL_INDENT,
gettext("internal separators"));
}
safe_printf(" \"%s\"", values.values_as_strings[i]);
}
safe_printf("\n");
}
if (templates != 2)
return;
if (prop != NULL)
list_values_tmpl(prt, prop);
else
list_values_by_template(prt);
}
static char *
read_astring(scf_propertygroup_t *pg, const char *prop_name)
{
char *rv;
rv = _scf_read_single_astring_from_pg(pg, prop_name);
if (rv == NULL) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
break;
default:
scfdie();
}
}
return (rv);
}
static void
display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
{
size_t doc_len;
size_t man_len;
char *pg_name;
char *text = NULL;
int rv;
doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
man_len = strlen(SCF_PG_TM_MAN_PREFIX);
pg_name = safe_malloc(max_scf_name_len + 1);
while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
scfdie();
}
if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
safe_printf("%s%s:\n", TMPL_INDENT,
gettext("doc_link"));
text = read_astring(pg, SCF_PROPERTY_TM_NAME);
if (text != NULL) {
safe_printf("%s%s%s: %s\n", TMPL_INDENT,
TMPL_INDENT, gettext("name"), text);
uu_free(text);
}
text = read_astring(pg, SCF_PROPERTY_TM_URI);
if (text != NULL) {
safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
gettext("uri"), text);
uu_free(text);
}
} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
man_len) == 0) {
safe_printf("%s%s:\n", TMPL_INDENT,
gettext("manpage"));
text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
if (text != NULL) {
safe_printf("%s%s%s: %s\n", TMPL_INDENT,
TMPL_INDENT, gettext("title"), text);
uu_free(text);
}
text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
if (text != NULL) {
safe_printf("%s%s%s: %s\n", TMPL_INDENT,
TMPL_INDENT, gettext("section"), text);
uu_free(text);
}
text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
if (text != NULL) {
safe_printf("%s%s%s: %s\n", TMPL_INDENT,
TMPL_INDENT, gettext("manpath"), text);
uu_free(text);
}
}
}
if (rv == -1)
scfdie();
free(pg_name);
}
static void
list_entity_tmpl(int templates)
{
char *common_name = NULL;
char *description = NULL;
char *locale = NULL;
scf_iter_t *iter;
scf_propertygroup_t *pg;
scf_property_t *prop;
int r;
scf_value_t *val;
if ((pg = scf_pg_create(g_hndl)) == NULL ||
(prop = scf_property_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
locale = setlocale(LC_MESSAGES, NULL);
if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
common_name = safe_malloc(max_scf_value_len + 1);
if (scf_pg_get_property(pg, locale, prop) == 0 ||
(scf_error() == SCF_ERROR_NOT_FOUND &&
scf_pg_get_property(pg, "C", prop) == 0)) {
if (prop_get_val(prop, val) == 0 &&
scf_value_get_ustring(val, common_name,
max_scf_value_len + 1) != -1) {
safe_printf("%s%s: %s\n", TMPL_INDENT,
gettext("common name"), common_name);
}
}
}
if (templates == 2) {
if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
description = safe_malloc(max_scf_value_len + 1);
if (scf_pg_get_property(pg, locale, prop) == 0 ||
(scf_error() == SCF_ERROR_NOT_FOUND &&
scf_pg_get_property(pg, "C", prop) == 0)) {
if (prop_get_val(prop, val) == 0 &&
scf_value_get_ustring(val, description,
max_scf_value_len + 1) != -1) {
safe_printf("%s%s: %s\n", TMPL_INDENT,
gettext("description"),
description);
}
}
}
if (cur_level != NULL) {
r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
SCF_GROUP_TEMPLATE);
} else if (cur_inst != NULL) {
r = scf_iter_instance_pgs_typed(iter, cur_inst,
SCF_GROUP_TEMPLATE);
} else {
r = scf_iter_service_pgs_typed(iter, cur_svc,
SCF_GROUP_TEMPLATE);
}
if (r == 0) {
display_documentation(iter, pg);
}
}
free(common_name);
free(description);
scf_pg_destroy(pg);
scf_property_destroy(prop);
scf_value_destroy(val);
scf_iter_destroy(iter);
}
static void
listtmpl(const char *pattern, int templates)
{
scf_pg_tmpl_t *pgt;
scf_prop_tmpl_t *prt;
char *snapbuf = NULL;
char *fmribuf;
char *pg_name = NULL, *prop_name = NULL;
ssize_t prop_name_size;
char *qual_prop_name;
char *search_name;
int listed = 0;
if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
(prt = scf_tmpl_prop_create(g_hndl)) == NULL)
scfdie();
fmribuf = safe_malloc(max_scf_name_len + 1);
qual_prop_name = safe_malloc(max_scf_name_len + 1);
if (cur_snap != NULL) {
snapbuf = safe_malloc(max_scf_name_len + 1);
if (scf_snapshot_get_name(cur_snap, snapbuf,
max_scf_name_len + 1) < 0)
scfdie();
}
if (cur_inst != NULL) {
if (scf_instance_to_fmri(cur_inst, fmribuf,
max_scf_name_len + 1) < 0)
scfdie();
} else if (cur_svc != NULL) {
if (scf_service_to_fmri(cur_svc, fmribuf,
max_scf_name_len + 1) < 0)
scfdie();
} else
abort();
while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
listed = 0;
if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
fnmatch(pattern, pg_name, 0) == 0)) {
list_pg_tmpl(pgt, NULL, templates);
listed++;
}
scf_tmpl_prop_reset(prt);
while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
search_name = NULL;
prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
if ((prop_name_size > 0) && (pg_name != NULL)) {
if (snprintf(qual_prop_name,
max_scf_name_len + 1, "%s/%s",
pg_name, prop_name) >=
max_scf_name_len + 1) {
prop_name_size = -1;
} else {
search_name = qual_prop_name;
}
}
if (listed > 0 || pattern == NULL ||
(prop_name_size > 0 &&
fnmatch(pattern, search_name,
FNM_PATHNAME) == 0))
list_prop_tmpl(prt, NULL, templates);
if (prop_name != NULL) {
free(prop_name);
prop_name = NULL;
}
}
if (pg_name != NULL) {
free(pg_name);
pg_name = NULL;
}
}
scf_tmpl_prop_destroy(prt);
scf_tmpl_pg_destroy(pgt);
free(snapbuf);
free(fmribuf);
free(qual_prop_name);
}
static void
listprop(const char *pattern, int only_pgs, int templates)
{
scf_propertygroup_t *pg;
scf_property_t *prop;
scf_iter_t *iter, *piter;
char *pgnbuf, *prnbuf, *ppnbuf;
scf_pg_tmpl_t *pgt, *pgtp;
scf_prop_tmpl_t *prt;
void **objects;
char **names;
void **tmpls;
int allocd, i;
int ret;
ssize_t pgnlen, prnlen, szret;
size_t max_len = 0;
if (cur_svc == NULL && cur_inst == NULL) {
semerr(emsg_entity_not_selected);
return;
}
if ((pg = scf_pg_create(g_hndl)) == NULL ||
(prop = scf_property_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL ||
(piter = scf_iter_create(g_hndl)) == NULL ||
(prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
(pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
scfdie();
prnbuf = safe_malloc(max_scf_name_len + 1);
if (cur_level != NULL)
ret = scf_iter_snaplevel_pgs(iter, cur_level);
else if (cur_inst != NULL)
ret = scf_iter_instance_pgs(iter, cur_inst);
else
ret = scf_iter_service_pgs(iter, cur_svc);
if (ret != 0) {
return;
}
i = 0;
allocd = 1;
objects = safe_malloc(sizeof (*objects));
names = safe_malloc(sizeof (*names));
tmpls = safe_malloc(sizeof (*tmpls));
while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
int new_pg = 0;
int print_props = 0;
pgtp = NULL;
pgnlen = scf_pg_get_name(pg, NULL, 0);
if (pgnlen < 0)
scfdie();
pgnbuf = safe_malloc(pgnlen + 1);
szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
if (szret < 0)
scfdie();
assert(szret <= pgnlen);
if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
pgtp = NULL;
} else {
pgtp = pgt;
}
if (pattern == NULL ||
fnmatch(pattern, pgnbuf, 0) == 0) {
if (i+1 >= allocd) {
allocd *= 2;
objects = realloc(objects,
sizeof (*objects) * allocd);
names =
realloc(names, sizeof (*names) * allocd);
tmpls = realloc(tmpls,
sizeof (*tmpls) * allocd);
if (objects == NULL || names == NULL ||
tmpls == NULL)
uu_die(gettext("Out of memory"));
}
objects[i] = pg;
names[i] = pgnbuf;
if (pgtp == NULL)
tmpls[i] = NULL;
else
tmpls[i] = pgt;
++i;
if (pgnlen > max_len)
max_len = pgnlen;
new_pg = 1;
print_props = 1;
}
if (only_pgs) {
if (new_pg) {
pg = scf_pg_create(g_hndl);
if (pg == NULL)
scfdie();
pgt = scf_tmpl_pg_create(g_hndl);
if (pgt == NULL)
scfdie();
} else
free(pgnbuf);
continue;
}
if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_property(piter, prop)) == 1) {
prnlen = scf_property_get_name(prop, prnbuf,
max_scf_name_len + 1);
if (prnlen < 0)
scfdie();
prnlen += pgnlen + 1;
ppnbuf = safe_malloc(prnlen + 1);
if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
prnbuf) < 0)
uu_die("snprintf");
if (pattern == NULL || print_props == 1 ||
fnmatch(pattern, ppnbuf, 0) == 0) {
if (i+1 >= allocd) {
allocd *= 2;
objects = realloc(objects,
sizeof (*objects) * allocd);
names = realloc(names,
sizeof (*names) * allocd);
tmpls = realloc(tmpls,
sizeof (*tmpls) * allocd);
if (objects == NULL || names == NULL ||
tmpls == NULL)
uu_die(gettext(
"Out of memory"));
}
objects[i] = prop;
names[i] = ppnbuf;
if (pgtp != NULL) {
if (scf_tmpl_get_by_prop(pgt, prnbuf,
prt, 0) < 0) {
if (scf_error() !=
SCF_ERROR_NOT_FOUND)
scfdie();
tmpls[i] = NULL;
} else {
tmpls[i] = prt;
}
} else {
tmpls[i] = NULL;
}
++i;
if (prnlen > max_len)
max_len = prnlen;
prop = scf_property_create(g_hndl);
prt = scf_tmpl_prop_create(g_hndl);
} else {
free(ppnbuf);
}
}
if (new_pg) {
pg = scf_pg_create(g_hndl);
if (pg == NULL)
scfdie();
pgt = scf_tmpl_pg_create(g_hndl);
if (pgt == NULL)
scfdie();
} else
free(pgnbuf);
}
if (ret != 0)
scfdie();
objects[i] = NULL;
scf_pg_destroy(pg);
scf_tmpl_pg_destroy(pgt);
scf_property_destroy(prop);
scf_tmpl_prop_destroy(prt);
for (i = 0; objects[i] != NULL; ++i) {
if (strchr(names[i], '/') == NULL) {
pg = (scf_propertygroup_t *)objects[i];
pgt = (scf_pg_tmpl_t *)tmpls[i];
list_pg_info(pg, names[i], max_len);
list_pg_tmpl(pgt, pg, templates);
free(names[i]);
scf_pg_destroy(pg);
if (pgt != NULL)
scf_tmpl_pg_destroy(pgt);
} else {
prop = (scf_property_t *)objects[i];
prt = (scf_prop_tmpl_t *)tmpls[i];
list_prop_info(prop, names[i], max_len);
list_prop_tmpl(prt, prop, templates);
free(names[i]);
scf_property_destroy(prop);
if (prt != NULL)
scf_tmpl_prop_destroy(prt);
}
}
free(names);
free(objects);
free(tmpls);
}
void
lscf_listpg(const char *pattern)
{
lscf_prep_hndl();
listprop(pattern, 1, 0);
}
void
lscf_addpg(const char *name, const char *type, const char *flags)
{
scf_propertygroup_t *pg;
int ret;
uint32_t flgs = 0;
const char *cp;
lscf_prep_hndl();
if (cur_snap != NULL) {
semerr(emsg_cant_modify_snapshots);
return;
}
if (cur_inst == NULL && cur_svc == NULL) {
semerr(emsg_entity_not_selected);
return;
}
if (flags != NULL) {
for (cp = flags; *cp != '\0'; ++cp) {
switch (*cp) {
case 'P':
flgs |= SCF_PG_FLAG_NONPERSISTENT;
break;
case 'p':
flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
break;
default:
semerr(gettext("Invalid property group flag "
"%c."), *cp);
return;
}
}
}
pg = scf_pg_create(g_hndl);
if (pg == NULL)
scfdie();
if (cur_inst != NULL)
ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
else
ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
if (ret != SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_INVALID_ARGUMENT:
semerr(gettext("Name, type, or flags are invalid.\n"));
break;
case SCF_ERROR_EXISTS:
semerr(gettext("Property group already exists.\n"));
break;
case SCF_ERROR_PERMISSION_DENIED:
semerr(emsg_permission_denied);
break;
case SCF_ERROR_BACKEND_ACCESS:
semerr(gettext("Backend refused access.\n"));
break;
default:
scfdie();
}
}
scf_pg_destroy(pg);
private_refresh();
}
void
lscf_delpg(char *name)
{
lscf_prep_hndl();
if (cur_snap != NULL) {
semerr(emsg_cant_modify_snapshots);
return;
}
if (cur_inst == NULL && cur_svc == NULL) {
semerr(emsg_entity_not_selected);
return;
}
if (strchr(name, '/') != NULL) {
semerr(emsg_invalid_pg_name, name);
return;
}
lscf_delprop(name);
}
void
lscf_delhash(char *manifest, int deathrow)
{
char *pgname;
if (cur_snap != NULL ||
cur_inst != NULL || cur_svc != NULL) {
warn(gettext("error, an entity is selected\n"));
return;
}
lscf_select(HASH_SVC);
pgname = mhash_filename_to_propname(manifest,
deathrow ? B_TRUE : B_FALSE);
if (pgname == NULL) {
warn(gettext("cannot resolve pathname for %s\n"), manifest);
return;
}
lscf_delpg(pgname);
}
void
lscf_listprop(const char *pattern)
{
lscf_prep_hndl();
listprop(pattern, 0, 0);
}
int
lscf_setprop(const char *pgname, const char *type, const char *value,
const uu_list_t *values)
{
scf_type_t ty, current_ty;
scf_service_t *svc;
scf_propertygroup_t *pg, *parent_pg;
scf_property_t *prop, *parent_prop;
scf_pg_tmpl_t *pgt;
scf_prop_tmpl_t *prt;
int ret, result = 0;
scf_transaction_t *tx;
scf_transaction_entry_t *e;
scf_value_t *v;
uu_list_walk_t *walk;
string_list_t *sp;
char *propname;
int req_quotes = 0;
lscf_prep_hndl();
if ((e = scf_entry_create(g_hndl)) == NULL ||
(svc = scf_service_create(g_hndl)) == NULL ||
(parent_pg = scf_pg_create(g_hndl)) == NULL ||
(pg = scf_pg_create(g_hndl)) == NULL ||
(parent_prop = scf_property_create(g_hndl)) == NULL ||
(prop = scf_property_create(g_hndl)) == NULL ||
(pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
(prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
(tx = scf_transaction_create(g_hndl)) == NULL)
scfdie();
if (cur_snap != NULL) {
semerr(emsg_cant_modify_snapshots);
goto fail;
}
if (cur_inst == NULL && cur_svc == NULL) {
semerr(emsg_entity_not_selected);
goto fail;
}
propname = strchr(pgname, '/');
if (propname == NULL) {
semerr(gettext("Property names must contain a `/'.\n"));
goto fail;
}
*propname = '\0';
++propname;
if (type != NULL) {
ty = string_to_type(type);
if (ty == SCF_TYPE_INVALID) {
semerr(gettext("Unknown type \"%s\".\n"), type);
goto fail;
}
}
if (cur_inst != NULL)
ret = scf_instance_get_pg(cur_inst, pgname, pg);
else
ret = scf_service_get_pg(cur_svc, pgname, pg);
if (ret != SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
semerr(emsg_no_such_pg, pgname);
goto fail;
case SCF_ERROR_INVALID_ARGUMENT:
semerr(emsg_invalid_pg_name, pgname);
goto fail;
default:
scfdie();
break;
}
}
do {
if (scf_pg_update(pg) == -1)
scfdie();
if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
goto fail;
}
ret = scf_pg_get_property(pg, propname, prop);
if (ret == SCF_SUCCESS) {
if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS)
scfdie();
if (type == NULL)
ty = current_ty;
if (scf_transaction_property_change_type(tx, e,
propname, ty) == -1)
scfdie();
} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
if (type == NULL) {
if (cur_inst != NULL &&
scf_instance_get_parent(cur_inst,
svc) == 0 &&
scf_service_get_pg(cur_svc, pgname,
parent_pg) == 0 &&
scf_pg_get_property(parent_pg, propname,
parent_prop) == 0 &&
scf_property_type(parent_prop,
¤t_ty) == 0) {
ty = current_ty;
} else if (scf_tmpl_get_by_pg(pg, pgt,
0) == 0 &&
scf_tmpl_get_by_prop(pgt, propname, prt,
0) == 0 &&
scf_tmpl_prop_type(prt, ¤t_ty) == 0) {
ty = current_ty;
} else {
semerr(gettext("Type required for new "
"properties.\n"));
goto fail;
}
}
if (scf_transaction_property_new(tx, e, propname,
ty) == -1)
scfdie();
} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
semerr(emsg_invalid_prop_name, propname);
goto fail;
} else {
scfdie();
}
if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
req_quotes = 1;
if (value != NULL) {
v = string_to_value(value, ty, 0);
if (v == NULL)
goto fail;
ret = scf_entry_add_value(e, v);
assert(ret == SCF_SUCCESS);
} else {
assert(values != NULL);
walk = uu_list_walk_start((uu_list_t *)values,
UU_DEFAULT);
if (walk == NULL)
uu_die(gettext("Could not walk list"));
for (sp = uu_list_walk_next(walk); sp != NULL;
sp = uu_list_walk_next(walk)) {
v = string_to_value(sp->str, ty, req_quotes);
if (v == NULL) {
scf_entry_destroy_children(e);
goto fail;
}
ret = scf_entry_add_value(e, v);
assert(ret == SCF_SUCCESS);
}
uu_list_walk_end(walk);
}
result = scf_transaction_commit(tx);
scf_transaction_reset(tx);
scf_entry_destroy_children(e);
} while (result == 0);
if (result < 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
goto fail;
}
ret = 0;
private_refresh();
goto cleanup;
fail:
ret = -1;
cleanup:
scf_transaction_destroy(tx);
scf_entry_destroy(e);
scf_service_destroy(svc);
scf_pg_destroy(parent_pg);
scf_pg_destroy(pg);
scf_property_destroy(parent_prop);
scf_property_destroy(prop);
scf_tmpl_pg_destroy(pgt);
scf_tmpl_prop_destroy(prt);
return (ret);
}
void
lscf_delprop(char *pgn)
{
char *slash, *pn;
scf_propertygroup_t *pg;
scf_transaction_t *tx;
scf_transaction_entry_t *e;
int ret;
lscf_prep_hndl();
if (cur_snap != NULL) {
semerr(emsg_cant_modify_snapshots);
return;
}
if (cur_inst == NULL && cur_svc == NULL) {
semerr(emsg_entity_not_selected);
return;
}
pg = scf_pg_create(g_hndl);
if (pg == NULL)
scfdie();
slash = strchr(pgn, '/');
if (slash == NULL) {
pn = NULL;
} else {
*slash = '\0';
pn = slash + 1;
}
if (cur_inst != NULL)
ret = scf_instance_get_pg(cur_inst, pgn, pg);
else
ret = scf_service_get_pg(cur_svc, pgn, pg);
if (ret != SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
semerr(emsg_no_such_pg, pgn);
break;
case SCF_ERROR_INVALID_ARGUMENT:
semerr(emsg_invalid_pg_name, pgn);
break;
default:
scfdie();
}
scf_pg_destroy(pg);
return;
}
if (pn == NULL) {
if (scf_pg_delete(pg) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
} else {
private_refresh();
}
scf_pg_destroy(pg);
return;
}
e = scf_entry_create(g_hndl);
tx = scf_transaction_create(g_hndl);
do {
if (scf_pg_update(pg) == -1)
scfdie();
if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
break;
}
if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
if (scf_error() == SCF_ERROR_NOT_FOUND) {
semerr(gettext("No such property %s/%s.\n"),
pgn, pn);
break;
} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
semerr(emsg_invalid_prop_name, pn);
break;
} else {
scfdie();
}
}
ret = scf_transaction_commit(tx);
if (ret == 0)
scf_transaction_reset(tx);
} while (ret == 0);
if (ret < 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
} else {
private_refresh();
}
scf_transaction_destroy(tx);
scf_entry_destroy(e);
scf_pg_destroy(pg);
}
static int
write_edit_script(FILE *strm)
{
char *fmribuf;
ssize_t fmrilen;
scf_propertygroup_t *pg;
scf_property_t *prop;
scf_value_t *val;
scf_type_t ty;
int ret, result = 0;
scf_iter_t *iter, *piter, *viter;
char *buf, *tybuf, *pname;
const char *emsg_write_error;
emsg_write_error = gettext("Error writing temoprary file: %s.\n");
if (cur_inst != NULL) {
fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
if (fmrilen < 0)
scfdie();
fmribuf = safe_malloc(fmrilen + 1);
if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
scfdie();
} else {
assert(cur_svc != NULL);
fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
if (fmrilen < 0)
scfdie();
fmribuf = safe_malloc(fmrilen + 1);
if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
scfdie();
}
if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
warn(emsg_write_error, strerror(errno));
free(fmribuf);
return (-1);
}
free(fmribuf);
if ((pg = scf_pg_create(g_hndl)) == NULL ||
(prop = scf_property_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL ||
(piter = scf_iter_create(g_hndl)) == NULL ||
(viter = scf_iter_create(g_hndl)) == NULL)
scfdie();
buf = safe_malloc(max_scf_name_len + 1);
tybuf = safe_malloc(max_scf_pg_type_len + 1);
pname = safe_malloc(max_scf_name_len + 1);
if (cur_inst != NULL)
ret = scf_iter_instance_pgs(iter, cur_inst);
else
ret = scf_iter_service_pgs(iter, cur_svc);
if (ret != SCF_SUCCESS)
scfdie();
while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
int ret2;
if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
scfdie();
if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
scfdie();
if (fprintf(strm, "# Property group \"%s\"\n"
"# delprop %s\n"
"# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
warn(emsg_write_error, strerror(errno));
result = -1;
goto out;
}
if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
scfdie();
while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
int first = 1;
int ret3;
int multiple;
int is_str;
scf_type_t bty;
if (scf_property_get_name(prop, pname,
max_scf_name_len + 1) < 0)
scfdie();
if (scf_property_type(prop, &ty) != 0)
scfdie();
multiple = prop_has_multiple_values(prop, val);
if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
pname, scf_type_to_string(ty), multiple ? "(" : "")
< 0) {
warn(emsg_write_error, strerror(errno));
result = -1;
goto out;
}
(void) scf_type_base_type(ty, &bty);
is_str = (bty == SCF_TYPE_ASTRING);
if (scf_iter_property_values(viter, prop) !=
SCF_SUCCESS)
scfdie();
while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
char *buf;
ssize_t buflen;
buflen = scf_value_get_as_string(val, NULL, 0);
if (buflen < 0)
scfdie();
buf = safe_malloc(buflen + 1);
if (scf_value_get_as_string(val, buf,
buflen + 1) < 0)
scfdie();
if (first)
first = 0;
else {
if (putc(' ', strm) != ' ') {
warn(emsg_write_error,
strerror(errno));
result = -1;
goto out;
}
}
if ((is_str && multiple) ||
strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
(void) putc('"', strm);
(void) quote_and_print(buf, strm, 1);
(void) putc('"', strm);
if (ferror(strm)) {
warn(emsg_write_error,
strerror(errno));
result = -1;
goto out;
}
} else {
if (fprintf(strm, "%s", buf) < 0) {
warn(emsg_write_error,
strerror(errno));
result = -1;
goto out;
}
}
free(buf);
}
if (ret3 < 0 &&
scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
if ((multiple && putc(')', strm) == EOF) ||
fputc('\n', strm) == EOF) {
warn(emsg_write_error, strerror(errno));
result = -1;
goto out;
}
}
if (ret2 < 0)
scfdie();
if (fputc('\n', strm) == EOF) {
warn(emsg_write_error, strerror(errno));
result = -1;
goto out;
}
}
if (ret < 0)
scfdie();
out:
free(pname);
free(tybuf);
free(buf);
scf_iter_destroy(viter);
scf_iter_destroy(piter);
scf_iter_destroy(iter);
scf_value_destroy(val);
scf_property_destroy(prop);
scf_pg_destroy(pg);
if (result == 0) {
if (fflush(strm) != 0) {
warn(emsg_write_error, strerror(errno));
return (-1);
}
}
return (result);
}
int
lscf_editprop(void)
{
char *buf, *editor;
size_t bufsz;
int tmpfd;
char tempname[] = TEMP_FILE_PATTERN;
lscf_prep_hndl();
if (cur_snap != NULL) {
semerr(emsg_cant_modify_snapshots);
return (-1);
}
if (cur_svc == NULL && cur_inst == NULL) {
semerr(emsg_entity_not_selected);
return (-1);
}
tmpfd = mkstemp(tempname);
if (tmpfd == -1) {
semerr(gettext("Could not create temporary file.\n"));
return (-1);
}
(void) strcpy(tempfilename, tempname);
tempfile = fdopen(tmpfd, "r+");
if (tempfile == NULL) {
warn(gettext("Could not create temporary file.\n"));
if (close(tmpfd) == -1)
warn(gettext("Could not close temporary file: %s.\n"),
strerror(errno));
remove_tempfile();
return (-1);
}
if (write_edit_script(tempfile) == -1) {
remove_tempfile();
return (-1);
}
editor = getenv("EDITOR");
if (editor == NULL)
editor = "vi";
bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
buf = safe_malloc(bufsz);
if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
uu_die(gettext("Error creating editor command"));
if (system(buf) == -1) {
semerr(gettext("Could not launch editor %s: %s\n"), editor,
strerror(errno));
free(buf);
remove_tempfile();
return (-1);
}
free(buf);
(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
remove_tempfile();
return (0);
}
static void
add_string(uu_list_t *strlist, const char *str)
{
string_list_t *elem;
elem = safe_malloc(sizeof (*elem));
uu_list_node_init(elem, &elem->node, string_pool);
elem->str = safe_strdup(str);
if (uu_list_append(strlist, elem) != 0)
uu_die(gettext("libuutil error: %s\n"),
uu_strerror(uu_error()));
}
static int
remove_string(uu_list_t *strlist, const char *str)
{
uu_list_walk_t *elems;
string_list_t *sp;
elems = uu_list_walk_start(strlist, UU_DEFAULT);
while ((sp = uu_list_walk_next(elems)) != NULL) {
if (strcmp(sp->str, str) == 0)
break;
}
uu_list_walk_end(elems);
if (sp == NULL) {
return (1);
}
uu_list_remove(strlist, sp);
free(sp->str);
free(sp);
return (0);
}
static void
get_prop_values(scf_property_t *prop, uu_list_t *values,
const char *pattern)
{
scf_iter_t *iter;
scf_value_t *val;
int ret;
if ((iter = scf_iter_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_property_values(iter, prop) != 0)
scfdie();
while ((ret = scf_iter_next_value(iter, val)) == 1) {
char *buf;
ssize_t vlen, szret;
vlen = scf_value_get_as_string(val, NULL, 0);
if (vlen < 0)
scfdie();
buf = safe_malloc(vlen + 1);
szret = scf_value_get_as_string(val, buf, vlen + 1);
if (szret < 0)
scfdie();
assert(szret <= vlen);
if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
add_string(values, buf);
free(buf);
}
if (ret == -1)
scfdie();
scf_value_destroy(val);
scf_iter_destroy(iter);
}
static int
lscf_setpropvalue(const char *pgname, const char *type,
const char *arg, int isadd, int isnotfoundok)
{
scf_type_t ty;
scf_propertygroup_t *pg;
scf_property_t *prop;
int ret, result = 0;
scf_transaction_t *tx;
scf_transaction_entry_t *e;
scf_value_t *v;
string_list_t *sp;
char *propname;
uu_list_t *values;
uu_list_walk_t *walk;
void *cookie = NULL;
char *pattern = NULL;
lscf_prep_hndl();
if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
uu_die(gettext("Could not create property list: %s\n"),
uu_strerror(uu_error()));
if (!isadd)
pattern = safe_strdup(arg);
if ((e = scf_entry_create(g_hndl)) == NULL ||
(pg = scf_pg_create(g_hndl)) == NULL ||
(prop = scf_property_create(g_hndl)) == NULL ||
(tx = scf_transaction_create(g_hndl)) == NULL)
scfdie();
if (cur_snap != NULL) {
semerr(emsg_cant_modify_snapshots);
goto fail;
}
if (cur_inst == NULL && cur_svc == NULL) {
semerr(emsg_entity_not_selected);
goto fail;
}
propname = strchr(pgname, '/');
if (propname == NULL) {
semerr(gettext("Property names must contain a `/'.\n"));
goto fail;
}
*propname = '\0';
++propname;
if (type != NULL) {
ty = string_to_type(type);
if (ty == SCF_TYPE_INVALID) {
semerr(gettext("Unknown type \"%s\".\n"), type);
goto fail;
}
}
if (cur_inst != NULL)
ret = scf_instance_get_pg(cur_inst, pgname, pg);
else
ret = scf_service_get_pg(cur_svc, pgname, pg);
if (ret != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
if (isnotfoundok) {
result = 0;
} else {
semerr(emsg_no_such_pg, pgname);
result = -1;
}
goto out;
case SCF_ERROR_INVALID_ARGUMENT:
semerr(emsg_invalid_pg_name, pgname);
goto fail;
default:
scfdie();
}
}
do {
if (scf_pg_update(pg) == -1)
scfdie();
if (scf_transaction_start(tx, pg) != 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
goto fail;
}
ret = scf_pg_get_property(pg, propname, prop);
if (ret == 0) {
scf_type_t ptype;
char *pat = pattern;
if (scf_property_type(prop, &ptype) != 0)
scfdie();
if (isadd) {
if (type != NULL && ptype != ty) {
semerr(gettext("Property \"%s\" is not "
"of type \"%s\".\n"), propname,
type);
goto fail;
}
pat = NULL;
} else {
size_t len = strlen(pat);
if (len > 0 && pat[len - 1] == '\"')
pat[len - 1] = '\0';
if (len > 0 && pat[0] == '\"')
pat++;
}
ty = ptype;
get_prop_values(prop, values, pat);
if (isadd)
add_string(values, arg);
if (scf_transaction_property_change(tx, e,
propname, ty) == -1)
scfdie();
} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
if (isadd) {
if (type == NULL) {
semerr(gettext("Type required "
"for new properties.\n"));
goto fail;
}
add_string(values, arg);
if (scf_transaction_property_new(tx, e,
propname, ty) == -1)
scfdie();
} else if (isnotfoundok) {
result = 0;
goto out;
} else {
semerr(gettext("No such property %s/%s.\n"),
pgname, propname);
result = -1;
goto out;
}
} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
semerr(emsg_invalid_prop_name, propname);
goto fail;
} else {
scfdie();
}
walk = uu_list_walk_start(values, UU_DEFAULT);
if (walk == NULL)
uu_die(gettext("Could not walk property list.\n"));
for (sp = uu_list_walk_next(walk); sp != NULL;
sp = uu_list_walk_next(walk)) {
v = string_to_value(sp->str, ty, 0);
if (v == NULL) {
scf_entry_destroy_children(e);
goto fail;
}
ret = scf_entry_add_value(e, v);
assert(ret == 0);
}
uu_list_walk_end(walk);
result = scf_transaction_commit(tx);
scf_transaction_reset(tx);
scf_entry_destroy_children(e);
} while (result == 0);
if (result < 0) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
goto fail;
}
result = 0;
private_refresh();
out:
scf_transaction_destroy(tx);
scf_entry_destroy(e);
scf_pg_destroy(pg);
scf_property_destroy(prop);
free(pattern);
while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
free(sp->str);
free(sp);
}
uu_list_destroy(values);
return (result);
fail:
result = -1;
goto out;
}
int
lscf_addpropvalue(const char *pgname, const char *type, const char *value)
{
return (lscf_setpropvalue(pgname, type, value, 1, 0));
}
int
lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
{
return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
}
static const char *
start_method_name(int *in_instance)
{
scf_propertygroup_t *pg;
char **p;
int ret;
scf_instance_t *inst = cur_inst;
if ((pg = scf_pg_create(g_hndl)) == NULL)
scfdie();
again:
for (p = start_method_names; *p != NULL; p++) {
if (inst != NULL)
ret = scf_instance_get_pg(inst, *p, pg);
else
ret = scf_service_get_pg(cur_svc, *p, pg);
if (ret == 0) {
size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
char *buf = safe_malloc(bufsz);
if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
free(buf);
continue;
}
if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
free(buf);
continue;
}
free(buf);
*in_instance = (inst != NULL);
scf_pg_destroy(pg);
return (*p);
}
if (scf_error() == SCF_ERROR_NOT_FOUND)
continue;
scfdie();
}
if (inst != NULL) {
inst = NULL;
goto again;
}
scf_pg_destroy(pg);
return (NULL);
}
static int
addpg(const char *name, const char *type)
{
scf_propertygroup_t *pg;
int ret;
pg = scf_pg_create(g_hndl);
if (pg == NULL)
scfdie();
if (cur_inst != NULL)
ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
else
ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
if (ret != 0) {
switch (scf_error()) {
case SCF_ERROR_EXISTS:
ret = 0;
break;
case SCF_ERROR_PERMISSION_DENIED:
semerr(emsg_permission_denied);
break;
default:
scfdie();
}
}
scf_pg_destroy(pg);
return (ret);
}
int
lscf_setenv(uu_list_t *args, int isunset)
{
int ret = 0;
size_t i;
int argc;
char **argv = NULL;
string_list_t *slp;
char *pattern;
char *prop;
int do_service = 0;
int do_instance = 0;
const char *method = NULL;
const char *name = NULL;
const char *value = NULL;
scf_instance_t *saved_cur_inst = cur_inst;
lscf_prep_hndl();
argc = uu_list_numnodes(args);
if (argc < 1)
goto usage;
argv = calloc(argc + 1, sizeof (char *));
if (argv == NULL)
uu_die(gettext("Out of memory.\n"));
for (slp = uu_list_first(args), i = 0;
slp != NULL;
slp = uu_list_next(args, slp), ++i)
argv[i] = slp->str;
argv[i] = NULL;
opterr = 0;
optind = 0;
for (;;) {
ret = getopt(argc, argv, "sim:");
if (ret == -1)
break;
switch (ret) {
case 's':
do_service = 1;
cur_inst = NULL;
break;
case 'i':
do_instance = 1;
break;
case 'm':
method = optarg;
break;
case '?':
goto usage;
default:
bad_error("getopt", ret);
}
}
argc -= optind;
if ((do_service && do_instance) ||
(isunset && argc != 1) ||
(!isunset && argc != 2))
goto usage;
name = argv[optind];
if (!isunset)
value = argv[optind + 1];
if (cur_snap != NULL) {
semerr(emsg_cant_modify_snapshots);
ret = -1;
goto out;
}
if (cur_inst == NULL && cur_svc == NULL) {
semerr(emsg_entity_not_selected);
ret = -1;
goto out;
}
if (do_instance && cur_inst == NULL) {
semerr(gettext("No instance is selected.\n"));
ret = -1;
goto out;
}
if (do_service && cur_svc == NULL) {
semerr(gettext("No service is selected.\n"));
ret = -1;
goto out;
}
if (method == NULL) {
if (do_instance || do_service) {
method = "method_context";
if (!isunset) {
ret = addpg("method_context",
SCF_GROUP_FRAMEWORK);
if (ret != 0)
goto out;
}
} else {
int in_instance;
method = start_method_name(&in_instance);
if (method == NULL) {
semerr(gettext(
"Couldn't find start method; please "
"specify a method with '-m'.\n"));
ret = -1;
goto out;
}
if (!in_instance)
cur_inst = NULL;
}
} else {
scf_propertygroup_t *pg;
size_t bufsz;
char *buf;
int ret;
if ((pg = scf_pg_create(g_hndl)) == NULL)
scfdie();
if (cur_inst != NULL)
ret = scf_instance_get_pg(cur_inst, method, pg);
else
ret = scf_service_get_pg(cur_svc, method, pg);
if (ret != 0) {
scf_pg_destroy(pg);
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
semerr(gettext("Couldn't find the method "
"\"%s\".\n"), method);
goto out;
case SCF_ERROR_INVALID_ARGUMENT:
semerr(gettext("Invalid method name \"%s\".\n"),
method);
goto out;
default:
scfdie();
}
}
bufsz = strlen(SCF_GROUP_METHOD) + 1;
buf = safe_malloc(bufsz);
if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
strcmp(buf, SCF_GROUP_METHOD) != 0) {
semerr(gettext("Property group \"%s\" is not of type "
"\"method\".\n"), method);
ret = -1;
free(buf);
scf_pg_destroy(pg);
goto out;
}
free(buf);
scf_pg_destroy(pg);
}
prop = uu_msprintf("%s/environment", method);
pattern = uu_msprintf("%s=*", name);
if (prop == NULL || pattern == NULL)
uu_die(gettext("Out of memory.\n"));
ret = lscf_delpropvalue(prop, pattern, !isunset);
if (ret == 0 && !isunset) {
uu_free(pattern);
uu_free(prop);
prop = uu_msprintf("%s/environment", method);
pattern = uu_msprintf("%s=%s", name, value);
if (prop == NULL || pattern == NULL)
uu_die(gettext("Out of memory.\n"));
ret = lscf_addpropvalue(prop, "astring:", pattern);
}
uu_free(pattern);
uu_free(prop);
out:
cur_inst = saved_cur_inst;
free(argv);
return (ret);
usage:
ret = -2;
goto out;
}
void
lscf_listsnap()
{
scf_snapshot_t *snap;
scf_iter_t *iter;
char *nb;
int r;
lscf_prep_hndl();
if (cur_inst == NULL) {
semerr(gettext("Instance not selected.\n"));
return;
}
if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
scfdie();
nb = safe_malloc(max_scf_name_len + 1);
while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
scfdie();
(void) puts(nb);
}
if (r < 0)
scfdie();
free(nb);
scf_iter_destroy(iter);
scf_snapshot_destroy(snap);
}
void
lscf_selectsnap(const char *name)
{
scf_snapshot_t *snap;
scf_snaplevel_t *level;
lscf_prep_hndl();
if (cur_inst == NULL) {
semerr(gettext("Instance not selected.\n"));
return;
}
if (cur_snap != NULL) {
if (name != NULL) {
char *cur_snap_name;
boolean_t nochange;
cur_snap_name = safe_malloc(max_scf_name_len + 1);
if (scf_snapshot_get_name(cur_snap, cur_snap_name,
max_scf_name_len + 1) < 0)
scfdie();
nochange = strcmp(name, cur_snap_name) == 0;
free(cur_snap_name);
if (nochange)
return;
}
unselect_cursnap();
}
if (name == NULL)
return;
if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
(level = scf_snaplevel_create(g_hndl)) == NULL)
scfdie();
if (scf_instance_get_snapshot(cur_inst, name, snap) !=
SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_INVALID_ARGUMENT:
semerr(gettext("Invalid name \"%s\".\n"), name);
break;
case SCF_ERROR_NOT_FOUND:
semerr(gettext("No such snapshot \"%s\".\n"), name);
break;
default:
scfdie();
}
scf_snaplevel_destroy(level);
scf_snapshot_destroy(snap);
return;
}
cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
if (cur_levels == NULL)
uu_die(gettext("Could not create list: %s\n"),
uu_strerror(uu_error()));
if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
semerr(gettext("Snapshot has no snaplevels.\n"));
scf_snaplevel_destroy(level);
scf_snapshot_destroy(snap);
return;
}
cur_snap = snap;
for (;;) {
cur_elt = safe_malloc(sizeof (*cur_elt));
uu_list_node_init(cur_elt, &cur_elt->list_node,
snaplevel_pool);
cur_elt->sl = level;
if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
uu_die(gettext("libuutil error: %s\n"),
uu_strerror(uu_error()));
level = scf_snaplevel_create(g_hndl);
if (level == NULL)
scfdie();
if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
level) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
scf_snaplevel_destroy(level);
break;
}
}
cur_elt = uu_list_last(cur_levels);
cur_level = cur_elt->sl;
}
static int
pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
uint8_t enabled)
{
scf_transaction_t *tx;
scf_iter_t *iter, *viter;
scf_property_t *prop;
scf_value_t *v;
char *nbuf;
int r;
tx = scf_transaction_create(g_hndl);
if (tx == NULL)
scfdie();
if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
scf_transaction_destroy(tx);
return (-1);
}
if ((iter = scf_iter_create(g_hndl)) == NULL ||
(prop = scf_property_create(g_hndl)) == NULL ||
(viter = scf_iter_create(g_hndl)) == NULL)
scfdie();
nbuf = safe_malloc(max_scf_name_len + 1);
if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
scfdie();
for (;;) {
scf_transaction_entry_t *e;
scf_type_t ty;
r = scf_iter_next_property(iter, prop);
if (r == -1)
scfdie();
if (r == 0)
break;
e = scf_entry_create(g_hndl);
if (e == NULL)
scfdie();
if (scf_property_type(prop, &ty) != SCF_SUCCESS)
scfdie();
if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
scfdie();
if (scf_transaction_property_new(tx, e, nbuf,
ty) != SCF_SUCCESS)
scfdie();
if ((enabled == 0 || enabled == 1) &&
strcmp(nbuf, scf_property_enabled) == 0 &&
ty == SCF_TYPE_BOOLEAN) {
v = scf_value_create(g_hndl);
if (v == NULL)
scfdie();
scf_value_set_boolean(v, enabled);
if (scf_entry_add_value(e, v) != 0)
scfdie();
} else {
if (scf_iter_property_values(viter, prop) != 0)
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) {
scf_value_destroy(v);
break;
}
if (scf_entry_add_value(e, v) != SCF_SUCCESS)
scfdie();
}
}
}
free(nbuf);
scf_iter_destroy(viter);
scf_property_destroy(prop);
scf_iter_destroy(iter);
r = scf_transaction_commit(tx);
if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
scf_transaction_destroy_children(tx);
scf_transaction_destroy(tx);
switch (r) {
case 1: return (0);
case 0: return (-2);
case -1: return (-1);
default:
abort();
}
}
void
lscf_revert(const char *snapname)
{
scf_snapshot_t *snap, *prev;
scf_snaplevel_t *level, *nlevel;
scf_iter_t *iter;
scf_propertygroup_t *pg, *npg;
scf_property_t *prop;
scf_value_t *val;
char *nbuf, *tbuf;
uint8_t enabled;
lscf_prep_hndl();
if (cur_inst == NULL) {
semerr(gettext("Instance not selected.\n"));
return;
}
if (snapname != NULL) {
snap = scf_snapshot_create(g_hndl);
if (snap == NULL)
scfdie();
if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_INVALID_ARGUMENT:
semerr(gettext("Invalid snapshot name "
"\"%s\".\n"), snapname);
break;
case SCF_ERROR_NOT_FOUND:
semerr(gettext("No such snapshot.\n"));
break;
default:
scfdie();
}
scf_snapshot_destroy(snap);
return;
}
} else {
if (cur_snap != NULL) {
snap = cur_snap;
} else {
semerr(gettext("No snapshot selected.\n"));
return;
}
}
if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
(level = scf_snaplevel_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL ||
(pg = scf_pg_create(g_hndl)) == NULL ||
(npg = scf_pg_create(g_hndl)) == NULL ||
(prop = scf_property_create(g_hndl)) == NULL ||
(val = scf_value_create(g_hndl)) == NULL)
scfdie();
nbuf = safe_malloc(max_scf_name_len + 1);
tbuf = safe_malloc(max_scf_pg_type_len + 1);
if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
scfdie();
} else {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
scfdie();
}
enabled = 2;
if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
scf_property_get_value(prop, val) == 0)
(void) scf_value_get_boolean(val, &enabled);
if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
goto out;
}
for (;;) {
boolean_t isinst;
uint32_t flags;
int r;
isinst = snaplevel_is_instance(level);
if (!isinst)
r = scf_iter_service_pgs(iter, cur_svc);
else
r = scf_iter_instance_pgs(iter, cur_inst);
if (r != SCF_SUCCESS)
scfdie();
while ((r = scf_iter_next_pg(iter, pg)) == 1) {
if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
scfdie();
if (flags & SCF_PG_FLAG_NONPERSISTENT)
continue;
if (scf_pg_delete(pg) != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
goto out;
}
}
if (r == -1)
scfdie();
if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
scfdie();
while ((r = scf_iter_next_pg(iter, pg)) == 1) {
if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
scfdie();
if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
0)
scfdie();
if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
scfdie();
if (!isinst)
r = scf_service_add_pg(cur_svc, nbuf, tbuf,
flags, npg);
else
r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
flags, npg);
if (r != SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
scfdie();
semerr(emsg_permission_denied);
goto out;
}
if ((enabled == 0 || enabled == 1) &&
strcmp(nbuf, scf_pg_general) == 0)
r = pg_copy(pg, npg, enabled);
else
r = pg_copy(pg, npg, 2);
switch (r) {
case 0:
break;
case -1:
semerr(emsg_permission_denied);
goto out;
case -2:
semerr(gettext(
"Interrupted by another change.\n"));
goto out;
default:
abort();
}
}
if (r == -1)
scfdie();
nlevel = scf_snaplevel_create(g_hndl);
if (nlevel == NULL)
scfdie();
if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
scfdie();
scf_snaplevel_destroy(nlevel);
break;
}
scf_snaplevel_destroy(level);
level = nlevel;
}
if (snapname == NULL) {
lscf_selectsnap(NULL);
snap = NULL;
}
out:
free(tbuf);
free(nbuf);
scf_value_destroy(val);
scf_property_destroy(prop);
scf_pg_destroy(npg);
scf_pg_destroy(pg);
scf_iter_destroy(iter);
scf_snaplevel_destroy(level);
scf_snapshot_destroy(prev);
if (snap != cur_snap)
scf_snapshot_destroy(snap);
}
void
lscf_refresh(void)
{
ssize_t fmrilen;
size_t bufsz;
char *fmribuf;
int r;
lscf_prep_hndl();
if (cur_inst == NULL) {
semerr(gettext("Instance not selected.\n"));
return;
}
bufsz = max_scf_fmri_len + 1;
fmribuf = safe_malloc(bufsz);
fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
if (fmrilen < 0) {
free(fmribuf);
if (scf_error() != SCF_ERROR_DELETED)
scfdie();
scf_instance_destroy(cur_inst);
cur_inst = NULL;
warn(emsg_deleted);
return;
}
assert(fmrilen < bufsz);
r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
switch (r) {
case 0:
break;
case ECONNABORTED:
warn(gettext("Could not refresh %s "
"(repository connection broken).\n"), fmribuf);
break;
case ECANCELED:
warn(emsg_deleted);
break;
case EPERM:
warn(gettext("Could not refresh %s "
"(permission denied).\n"), fmribuf);
break;
case ENOSPC:
warn(gettext("Could not refresh %s "
"(repository server out of resources).\n"),
fmribuf);
break;
case EACCES:
default:
bad_error("refresh_entity", scf_error());
}
free(fmribuf);
}
int
lscf_describe(uu_list_t *args, int hasargs)
{
int ret = 0;
size_t i;
int argc;
char **argv = NULL;
string_list_t *slp;
int do_verbose = 0;
int do_templates = 0;
char *pattern = NULL;
lscf_prep_hndl();
if (hasargs != 0) {
argc = uu_list_numnodes(args);
if (argc < 1)
goto usage;
argv = calloc(argc + 1, sizeof (char *));
if (argv == NULL)
uu_die(gettext("Out of memory.\n"));
for (slp = uu_list_first(args), i = 0;
slp != NULL;
slp = uu_list_next(args, slp), ++i)
argv[i] = slp->str;
argv[i] = NULL;
optind = 0;
opterr = 0;
for (;;) {
ret = getopt(argc, argv, "vt");
if (ret == -1)
break;
switch (ret) {
case 'v':
do_verbose = 1;
break;
case 't':
do_templates = 1;
break;
case '?':
goto usage;
default:
bad_error("getopt", ret);
}
}
pattern = argv[optind];
}
if (cur_inst == NULL && cur_svc == NULL) {
semerr(emsg_entity_not_selected);
ret = -1;
goto out;
}
if (pattern == NULL) {
if (do_verbose == 1)
list_entity_tmpl(2);
else
list_entity_tmpl(1);
}
if (do_templates == 0) {
if (do_verbose == 1)
listprop(pattern, 0, 2);
else
listprop(pattern, 0, 1);
} else {
if (do_verbose == 1)
listtmpl(pattern, 2);
else
listtmpl(pattern, 1);
}
ret = 0;
out:
if (argv != NULL)
free(argv);
return (ret);
usage:
ret = -2;
goto out;
}
#define PARAM_ACTIVE ((const char *) "active")
#define PARAM_INACTIVE ((const char *) "inactive")
#define PARAM_SMTP_TO ((const char *) "to")
char **
tokenize(char *str, const char *sep)
{
char *token, *lasts;
char **buf;
int n = 0;
int size = 8;
buf = safe_malloc(size * sizeof (char *));
for (token = strtok_r(str, sep, &lasts); token != NULL;
token = strtok_r(NULL, sep, &lasts), ++n) {
if (n + 1 >= size) {
size *= 2;
if ((buf = realloc(buf, size * sizeof (char *))) ==
NULL) {
uu_die(gettext("Out of memory"));
}
}
buf[n] = token;
}
buf[n] = NULL;
return (buf);
}
int32_t
check_tokens(char **p)
{
int32_t smf = 0;
int32_t fma = 0;
while (*p) {
int32_t t = string_to_tset(*p);
if (t == 0) {
if (is_fma_token(*p) == 0)
return (INVALID_TOKENS);
fma = 1;
} else {
smf |= t;
}
if (smf != 0 && fma == 1)
return (MIXED_TOKENS);
++p;
}
if (smf > 0)
return (smf);
else if (fma == 1)
return (FMA_TOKENS);
return (INVALID_TOKENS);
}
static int
get_selection_str(char *fmri, size_t sz)
{
if (g_hndl == NULL) {
semerr(emsg_entity_not_selected);
return (-1);
} else if (cur_level != NULL) {
semerr(emsg_invalid_for_snapshot);
return (-1);
} else {
lscf_get_selection_str(fmri, sz);
}
return (0);
}
void
lscf_delnotify(const char *set, int global)
{
char *str = strdup(set);
char **pgs;
char **p;
int32_t tset;
char *fmri = NULL;
if (str == NULL)
uu_die(gettext("Out of memory.\n"));
pgs = tokenize(str, ",");
if ((tset = check_tokens(pgs)) > 0) {
size_t sz = max_scf_fmri_len + 1;
fmri = safe_malloc(sz);
if (global) {
(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
} else if (get_selection_str(fmri, sz) != 0) {
goto out;
}
if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
tset) != SCF_SUCCESS) {
uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
scf_strerror(scf_error()));
}
} else if (tset == FMA_TOKENS) {
if (global) {
semerr(gettext("Can't use option '-g' with FMA event "
"definitions\n"));
goto out;
}
for (p = pgs; *p; ++p) {
if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
SCF_SUCCESS) {
uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
scf_strerror(scf_error()));
goto out;
}
}
} else if (tset == MIXED_TOKENS) {
semerr(gettext("Can't mix SMF and FMA event definitions\n"));
goto out;
} else {
uu_die(gettext("Invalid input.\n"));
}
out:
free(fmri);
free(pgs);
free(str);
}
void
lscf_listnotify(const char *set, int global)
{
char *str = safe_strdup(set);
char **pgs;
char **p;
int32_t tset;
nvlist_t *nvl;
char *fmri = NULL;
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
uu_die(gettext("Out of memory.\n"));
pgs = tokenize(str, ",");
if ((tset = check_tokens(pgs)) > 0) {
size_t sz = max_scf_fmri_len + 1;
fmri = safe_malloc(sz);
if (global) {
(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
} else if (get_selection_str(fmri, sz) != 0) {
goto out;
}
if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
SCF_SUCCESS) {
if (scf_error() != SCF_ERROR_NOT_FOUND &&
scf_error() != SCF_ERROR_DELETED)
uu_warn(gettext(
"Failed listnotify: %s\n"),
scf_strerror(scf_error()));
goto out;
}
listnotify_print(nvl, NULL);
} else if (tset == FMA_TOKENS) {
if (global) {
semerr(gettext("Can't use option '-g' with FMA event "
"definitions\n"));
goto out;
}
for (p = pgs; *p; ++p) {
if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
SCF_SUCCESS) {
if (scf_error() == SCF_ERROR_NOT_FOUND ||
scf_error() == SCF_ERROR_DELETED)
continue;
uu_warn(gettext(
"Failed listnotify: %s\n"),
scf_strerror(scf_error()));
goto out;
}
listnotify_print(nvl, re_tag(*p));
}
} else if (tset == MIXED_TOKENS) {
semerr(gettext("Can't mix SMF and FMA event definitions\n"));
goto out;
} else {
semerr(gettext("Invalid input.\n"));
}
out:
nvlist_free(nvl);
free(fmri);
free(pgs);
free(str);
}
static char *
strip_quotes_and_blanks(char *s)
{
char *start = s;
char *end = strrchr(s, '\"');
if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
start = s + 1;
while (isblank(*start))
start++;
while (isblank(*(end - 1)) && end > start) {
end--;
}
*end = '\0';
}
return (start);
}
static int
set_active(nvlist_t *mech, const char *hier_part)
{
boolean_t b;
if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
b = B_TRUE;
} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
b = B_FALSE;
} else {
return (-1);
}
if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
uu_die(gettext("Out of memory.\n"));
return (0);
}
static int
add_snmp_params(nvlist_t *mech, char *hier_part)
{
return (set_active(mech, hier_part));
}
static int
add_syslog_params(nvlist_t *mech, char *hier_part)
{
return (set_active(mech, hier_part));
}
static int
add_mailto_params(nvlist_t *mech, char *hier_part)
{
const char *tok = "?&";
char *p;
char *lasts;
char *param;
char *val;
if (set_active(mech, hier_part) == 0)
return (0);
else if (set_active(mech, PARAM_ACTIVE) != 0)
return (-1);
if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
uu_die("strtok_r");
}
if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
uu_die(gettext("Out of memory.\n"));
while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
if ((param = strtok_r(p, "=", &val)) != NULL)
if (nvlist_add_string(mech, param, val) != 0)
uu_die(gettext("Out of memory.\n"));
return (0);
}
static int
uri_split(char *uri, char **scheme, char **hier_part)
{
int r = -1;
if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
*hier_part == NULL) {
semerr(gettext("'%s' is not an URI\n"), uri);
return (r);
}
if ((r = check_uri_scheme(*scheme)) < 0) {
semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
return (r);
}
return (r);
}
static int
process_uri(nvlist_t *params, char *uri)
{
char *scheme;
char *hier_part;
nvlist_t *mech;
int index;
int r;
if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
return (-1);
if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
uu_die(gettext("Out of memory.\n"));
switch (index) {
case 0:
r = add_mailto_params(mech, hier_part);
break;
case 1:
if ((r = add_snmp_params(mech, hier_part)) != 0)
semerr(gettext("Not valid parameters: '%s'\n"),
hier_part);
break;
case 2:
if ((r = add_syslog_params(mech, hier_part)) != 0)
semerr(gettext("Not valid parameters: '%s'\n"),
hier_part);
break;
default:
r = -1;
}
if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
mech) != 0)
uu_die(gettext("Out of memory.\n"));
nvlist_free(mech);
return (r);
}
static int
set_params(nvlist_t *params, char **p)
{
char *uri;
if (p == NULL)
uu_die("set_params");
while (*p) {
uri = strip_quotes_and_blanks(*p);
if (process_uri(params, uri) != 0)
return (-1);
++p;
}
return (0);
}
static int
setnotify(const char *e, char **p, int global)
{
char *str = safe_strdup(e);
char **events;
int32_t tset;
int r = -1;
nvlist_t *nvl, *params;
char *fmri = NULL;
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 ||
nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
SCF_NOTIFY_PARAMS_VERSION) != 0)
uu_die(gettext("Out of memory.\n"));
events = tokenize(str, ",");
if ((tset = check_tokens(events)) > 0) {
size_t sz = max_scf_fmri_len + 1;
fmri = safe_malloc(sz);
if (global) {
(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
} else if (get_selection_str(fmri, sz) != 0) {
goto out;
}
if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
uu_die(gettext("Out of memory.\n"));
if ((r = set_params(params, p)) == 0) {
if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
params) != 0)
uu_die(gettext("Out of memory.\n"));
if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
nvl) != SCF_SUCCESS) {
r = -1;
uu_warn(gettext(
"Failed smf_notify_set_params(3SCF): %s\n"),
scf_strerror(scf_error()));
}
}
} else if (tset == FMA_TOKENS) {
if (global) {
semerr(gettext("Can't use option '-g' with FMA event "
"definitions\n"));
goto out;
}
if ((r = set_params(params, p)) != 0)
goto out;
if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
uu_die(gettext("Out of memory.\n"));
while (*events) {
if (smf_notify_set_params(de_tag(*events), nvl) !=
SCF_SUCCESS)
uu_warn(gettext(
"Failed smf_notify_set_params(3SCF) for "
"event %s: %s\n"), *events,
scf_strerror(scf_error()));
events++;
}
} else if (tset == MIXED_TOKENS) {
semerr(gettext("Can't mix SMF and FMA event definitions\n"));
} else {
uu_die(gettext("Invalid input.\n"));
}
out:
nvlist_free(nvl);
nvlist_free(params);
free(fmri);
free(str);
return (r);
}
int
lscf_setnotify(uu_list_t *args)
{
int argc;
char **argv = NULL;
string_list_t *slp;
int global;
char *events;
char **p;
int i;
int ret;
if ((argc = uu_list_numnodes(args)) < 2)
goto usage;
argv = calloc(argc + 1, sizeof (char *));
if (argv == NULL)
uu_die(gettext("Out of memory.\n"));
for (slp = uu_list_first(args), i = 0;
slp != NULL;
slp = uu_list_next(args, slp), ++i)
argv[i] = slp->str;
argv[i] = NULL;
if (strcmp(argv[0], "-g") == 0) {
global = 1;
events = argv[1];
p = argv + 2;
} else {
global = 0;
events = argv[0];
p = argv + 1;
}
ret = setnotify(events, p, global);
out:
free(argv);
return (ret);
usage:
ret = -2;
goto out;
}
static uu_list_t *
create_instance_list(scf_service_t *svc, int wohandcrafted)
{
scf_snapshot_t *snap = NULL;
scf_instance_t *inst;
scf_iter_t *inst_iter;
uu_list_t *instances;
char *instname = NULL;
int r;
inst_iter = scf_iter_create(g_hndl);
inst = scf_instance_create(g_hndl);
if (inst_iter == NULL || inst == NULL) {
uu_warn(gettext("Could not create instance or iterator\n"));
scfdie();
}
if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
return (instances);
if (scf_iter_service_instances(inst_iter, svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_DELETED:
uu_list_destroy(instances);
instances = NULL;
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances", scf_error());
}
}
instname = safe_malloc(max_scf_name_len + 1);
while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
if (r == -1) {
(void) uu_warn(gettext("Unable to iterate through "
"instances to create instance list : %s\n"),
scf_strerror(scf_error()));
uu_list_destroy(instances);
instances = NULL;
goto out;
}
if (wohandcrafted) {
if (snap == NULL &&
(snap = scf_snapshot_create(g_hndl)) == NULL) {
uu_warn(gettext("Unable to create snapshot "
"entity\n"));
scfdie();
}
if (scf_instance_get_snapshot(inst,
snap_lastimport, snap) != 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND :
case SCF_ERROR_DELETED:
continue;
case SCF_ERROR_CONNECTION_BROKEN:
uu_list_destroy(instances);
instances = NULL;
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances",
scf_error());
}
}
}
if (scf_instance_get_name(inst, instname,
max_scf_name_len + 1) < 0) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND :
continue;
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_DELETED:
uu_list_destroy(instances);
instances = NULL;
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances",
scf_error());
}
}
add_string(instances, instname);
}
out:
if (snap)
scf_snapshot_destroy(snap);
scf_instance_destroy(inst);
scf_iter_destroy(inst_iter);
free(instname);
return (instances);
}
static int
disable_instance(scf_instance_t *instance)
{
char *fmribuf;
int enabled = 10000;
if (inst_is_running(instance)) {
fmribuf = safe_malloc(max_scf_name_len + 1);
if (scf_instance_to_fmri(instance, fmribuf,
max_scf_name_len + 1) < 0) {
free(fmribuf);
return (0);
}
if (smf_disable_instance(fmribuf, 0) != 0) {
free(fmribuf);
return (0);
}
while (enabled) {
if (!inst_is_running(instance))
break;
(void) poll(NULL, 0, 5);
enabled = enabled - 5;
}
free(fmribuf);
}
return (enabled);
}
static int
service_manifest_compare(const void *left, const void *right, void *unused)
{
service_manifest_t *l = (service_manifest_t *)left;
service_manifest_t *r = (service_manifest_t *)right;
int rc;
rc = strcmp(l->servicename, r->servicename);
return (rc);
}
service_manifest_t *
find_add_svc_mfst(const char *svnbuf, const char *mfst)
{
service_manifest_t elem;
service_manifest_t *fnelem;
uu_avl_index_t marker;
elem.servicename = svnbuf;
fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
if (mfst) {
if (fnelem) {
add_string(fnelem->mfstlist, strdup(mfst));
} else {
fnelem = safe_malloc(sizeof (*fnelem));
fnelem->servicename = safe_strdup(svnbuf);
if ((fnelem->mfstlist =
uu_list_create(string_pool, NULL, 0)) == NULL)
uu_die(gettext("Could not create property "
"list: %s\n"), uu_strerror(uu_error()));
add_string(fnelem->mfstlist, safe_strdup(mfst));
uu_avl_insert(service_manifest_tree, fnelem, marker);
}
}
return (fnelem);
}
static void
create_manifest_tree(void)
{
manifest_info_t **entry;
manifest_info_t **manifests;
uu_list_walk_t *svcs;
bundle_t *b;
entity_t *mfsvc;
char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
int c, status;
if (service_manifest_pool)
return;
service_manifest_pool = uu_avl_pool_create("service_manifest",
sizeof (service_manifest_t),
offsetof(service_manifest_t, svcmfst_node),
service_manifest_compare, UU_DEFAULT);
if (service_manifest_pool == NULL)
uu_die(gettext("service_manifest pool creation failed: %s\n"),
uu_strerror(uu_error()));
service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
UU_DEFAULT);
if (service_manifest_tree == NULL)
uu_die(gettext("service_manifest tree creation failed: %s\n"),
uu_strerror(uu_error()));
for (c = 0; dirs[c]; c++) {
status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
if (status < 0) {
uu_warn(gettext("file tree walk of %s encountered "
"error %s\n"), dirs[c], strerror(errno));
uu_avl_destroy(service_manifest_tree);
service_manifest_tree = NULL;
return;
}
if (manifests != NULL) {
for (entry = manifests; *entry != NULL; entry++) {
b = internal_bundle_new();
if (lxml_get_bundle_file(b, (*entry)->mi_path,
SVCCFG_OP_IMPORT) != 0) {
internal_bundle_free(b);
continue;
}
svcs = uu_list_walk_start(b->sc_bundle_services,
0);
if (svcs == NULL) {
internal_bundle_free(b);
continue;
}
while ((mfsvc = uu_list_walk_next(svcs)) !=
NULL) {
(void) find_add_svc_mfst(mfsvc->sc_name,
(*entry)->mi_path);
}
uu_list_walk_end(svcs);
internal_bundle_free(b);
}
free_manifest_array(manifests);
}
}
}
static int
check_mfst_history(const char *svcname)
{
struct stat st;
caddr_t mfsthist_start;
char *svnbuf;
int fd;
int r = 1;
fd = open(MFSTHISTFILE, O_RDONLY);
if (fd == -1) {
uu_warn(gettext("Unable to open the history file\n"));
return (-1);
}
if (fstat(fd, &st) == -1) {
uu_warn(gettext("Unable to stat the history file\n"));
return (-1);
}
mfsthist_start = mmap(0, st.st_size, PROT_READ,
MAP_PRIVATE, fd, 0);
(void) close(fd);
if (mfsthist_start == MAP_FAILED ||
*(mfsthist_start + st.st_size) != '\0') {
(void) munmap(mfsthist_start, st.st_size);
return (-1);
}
svnbuf = uu_msprintf("%s ", svcname);
if (svnbuf == NULL)
uu_die(gettext("Out of memory"));
if (strstr(mfsthist_start, svnbuf) != NULL)
r = 0;
(void) munmap(mfsthist_start, st.st_size);
uu_free(svnbuf);
return (r);
}
static void
teardown_service(scf_service_t *svc, const char *svnbuf)
{
scf_instance_t *instance;
scf_iter_t *iter;
int r;
safe_printf(gettext("Delete service %s as there are no "
"supporting manifests\n"), svnbuf);
instance = scf_instance_create(g_hndl);
iter = scf_iter_create(g_hndl);
if (iter == NULL || instance == NULL) {
uu_warn(gettext("Unable to create supporting entities to "
"teardown the service\n"));
uu_warn(gettext("scf error is : %s\n"),
scf_strerror(scf_error()));
scfdie();
}
if (scf_iter_service_instances(iter, svc) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_DELETED:
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_service_instances",
scf_error());
}
}
while ((r = scf_iter_next_instance(iter, instance)) != 0) {
if (r == -1) {
uu_warn(gettext("Error - %s\n"),
scf_strerror(scf_error()));
goto out;
}
(void) disable_instance(instance);
}
(void) lscf_service_delete(svc, 1);
out:
scf_instance_destroy(instance);
scf_iter_destroy(iter);
}
static int
check_instance_support(char *mfstfile, const char *svcname,
uu_list_t *instances)
{
uu_list_walk_t *svcs, *insts;
uu_list_t *ilist;
bundle_t *b;
entity_t *mfsvc, *mfinst;
const char *svcn;
int rminstcnt = 0;
b = internal_bundle_new();
if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
internal_bundle_free(b);
return (0);
}
svcs = uu_list_walk_start(b->sc_bundle_services, 0);
if (svcs == NULL) {
internal_bundle_free(b);
return (0);
}
svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
(sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
if (strcmp(mfsvc->sc_name, svcn) == 0)
break;
}
uu_list_walk_end(svcs);
if (mfsvc == NULL) {
internal_bundle_free(b);
return (-1);
}
ilist = mfsvc->sc_u.sc_service.sc_service_instances;
if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
internal_bundle_free(b);
return (0);
}
while ((mfinst = uu_list_walk_next(insts)) != NULL) {
(void) remove_string(instances,
mfinst->sc_name);
rminstcnt++;
}
uu_list_walk_end(insts);
internal_bundle_free(b);
return (rminstcnt);
}
static void
svc_add_no_support(scf_service_t *svc)
{
char *pname;
cur_svc = svc;
if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
return;
pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
if (pname == NULL)
uu_die(gettext("Out of memory.\n"));
(void) lscf_addpropvalue(pname, "boolean:", "0");
uu_free(pname);
cur_svc = NULL;
}
static void
upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
{
service_manifest_t *elem;
uu_list_walk_t *mfwalk;
string_list_t *mfile;
uu_list_t *instances;
const char *sname;
char *pname;
int r;
if (IGNORE_VAR)
return;
if (service_manifest_tree == NULL) {
create_manifest_tree();
}
sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
strlen(SCF_FMRI_SERVICE_PREFIX);
elem = find_add_svc_mfst(sname, NULL);
if (elem == NULL) {
instances = create_instance_list(svc, 1);
if (instances == NULL) {
uu_warn(gettext("Unable to create instance list %s\n"),
svcname);
return;
}
if (uu_list_numnodes(instances) == 0) {
svc_add_no_support(svc);
return;
}
r = check_mfst_history(svcname);
if (r == -1)
return;
if (r) {
svc_add_no_support(svc);
} else {
teardown_service(svc, svcname);
}
return;
}
mfwalk = uu_list_walk_start(elem->mfstlist, 0);
if (mfwalk == NULL)
return;
cur_svc = svc;
r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
if (r != 0) {
cur_svc = NULL;
return;
}
while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
mhash_filename_to_propname(mfile->str, 0));
if (pname == NULL)
uu_die(gettext("Out of memory.\n"));
(void) lscf_addpropvalue(pname, "astring:", mfile->str);
uu_free(pname);
}
uu_list_walk_end(mfwalk);
cur_svc = NULL;
}
int
lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
{
struct mpg_mfile *mpntov = NULL;
struct mpg_mfile **mpvarry = NULL;
scf_service_t *svc;
scf_propertygroup_t *mpg;
scf_property_t *mp;
scf_value_t *mv;
scf_iter_t *mi;
scf_instance_t *instance;
uu_list_walk_t *insts;
uu_list_t *instances = NULL;
boolean_t activity = (boolean_t)act;
char *mpnbuf = NULL;
char *mpvbuf = NULL;
char *pgpropbuf;
int mfstcnt, rminstct, instct, mfstmax;
int index;
int r = 0;
assert(g_hndl != NULL);
assert(wip->svc != NULL);
assert(wip->fmri != NULL);
svc = wip->svc;
mpg = scf_pg_create(g_hndl);
mp = scf_property_create(g_hndl);
mi = scf_iter_create(g_hndl);
mv = scf_value_create(g_hndl);
instance = scf_instance_create(g_hndl);
if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
instance == NULL) {
uu_warn(gettext("Unable to create the supporting entities\n"));
uu_warn(gettext("scf error is : %s\n"),
scf_strerror(scf_error()));
scfdie();
}
if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
switch (scf_error()) {
case SCF_ERROR_NOT_FOUND:
upgrade_svc_mfst_connection(svc, wip->fmri);
break;
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
goto out;
}
if (scf_iter_pg_properties(mi, mpg) != 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
}
mfstcnt = 0;
mfstmax = MFSTFILE_MAX;
mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
while ((r = scf_iter_next_property(mi, mp)) != 0) {
if (r == -1)
bad_error(gettext("Unable to iterate through "
"manifestfiles properties : %s"),
scf_error());
mpntov = safe_malloc(sizeof (struct mpg_mfile));
mpnbuf = safe_malloc(max_scf_name_len + 1);
mpvbuf = safe_malloc(max_scf_value_len + 1);
mpntov->mpg = mpnbuf;
mpntov->mfile = mpvbuf;
mpntov->access = 1;
if (scf_property_get_name(mp, mpnbuf,
max_scf_name_len + 1) < 0) {
uu_warn(gettext("Unable to get manifest file "
"property : %s\n"),
scf_strerror(scf_error()));
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out_free;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
}
if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
uint8_t support;
if (scf_property_get_value(mp, mv) != 0 ||
scf_value_get_boolean(mv, &support) != 0) {
uu_warn(gettext("Unable to get the manifest "
"support value: %s\n"),
scf_strerror(scf_error()));
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out_free;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_iter_pg_properties",
scf_error());
}
}
if (support == B_FALSE)
goto out_free;
}
if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
if (strncmp(mpnbuf, VARSVC_PR,
strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
goto out_free;
}
}
if (scf_property_get_value(mp, mv) != 0) {
uu_warn(gettext("Unable to get the manifest file "
"value: %s\n"),
scf_strerror(scf_error()));
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out_free;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
if (scf_value_get_astring(mv, mpvbuf,
max_scf_value_len + 1) < 0) {
uu_warn(gettext("Unable to get the manifest "
"file : %s\n"),
scf_strerror(scf_error()));
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out_free;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_NOT_SET:
default:
bad_error("scf_value_get_astring",
scf_error());
}
}
mpvarry[mfstcnt] = mpntov;
mfstcnt++;
if (mfstcnt >= (mfstmax - 1)) {
struct mpg_mfile **newmpvarry;
mfstmax = mfstmax * 2;
newmpvarry = realloc(mpvarry,
sizeof (struct mpg_mfile *) * mfstmax);
if (newmpvarry == NULL)
goto out_free;
mpvarry = newmpvarry;
}
mpvarry[mfstcnt] = NULL;
}
for (index = 0; mpvarry[index]; index++) {
mpntov = mpvarry[index];
mpnbuf = mpntov->mpg;
mpvbuf = mpntov->mfile;
if (access(mpvbuf, F_OK) != 0) {
mpntov->access = 0;
activity++;
mfstcnt--;
cur_svc = svc;
pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
mpnbuf);
if (pgpropbuf == NULL)
uu_die(gettext("Out of memory.\n"));
lscf_delprop(pgpropbuf);
cur_svc = NULL;
uu_free(pgpropbuf);
}
}
if (mfstcnt == 0) {
teardown_service(svc, wip->fmri);
goto out_free;
}
if (activity) {
int nosvcsupport = 0;
instances = create_instance_list(svc, 1);
if (instances == NULL) {
uu_warn(gettext("Unable to create instance list %s\n"),
wip->fmri);
goto out_free;
}
rminstct = uu_list_numnodes(instances);
instct = rminstct;
for (index = 0; mpvarry[index]; index++) {
mpntov = mpvarry[index];
if (mpntov->access == 0)
continue;
mpnbuf = mpntov->mpg;
mpvbuf = mpntov->mfile;
r = check_instance_support(mpvbuf, wip->fmri,
instances);
if (r == -1) {
nosvcsupport++;
} else {
rminstct -= r;
}
}
if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
teardown_service(svc, wip->fmri);
goto out_free;
}
}
if (instances != NULL && uu_list_numnodes(instances)) {
string_list_t *sp;
insts = uu_list_walk_start(instances, 0);
while ((sp = uu_list_walk_next(insts)) != NULL) {
safe_printf(gettext("Delete instance %s from "
"service %s\n"), sp->str, wip->fmri);
if (scf_service_get_instance(svc, sp->str,
instance) != SCF_SUCCESS) {
(void) uu_warn("scf_error - %s\n",
scf_strerror(scf_error()));
continue;
}
(void) disable_instance(instance);
(void) lscf_instance_delete(instance, 1);
}
scf_instance_destroy(instance);
uu_list_walk_end(insts);
}
out_free:
if (mpvarry) {
struct mpg_mfile *fmpntov;
for (index = 0; mpvarry[index]; index++) {
fmpntov = mpvarry[index];
if (fmpntov->mpg == mpnbuf)
mpnbuf = NULL;
free(fmpntov->mpg);
if (fmpntov->mfile == mpvbuf)
mpvbuf = NULL;
free(fmpntov->mfile);
if (fmpntov == mpntov)
mpntov = NULL;
free(fmpntov);
}
if (mpnbuf)
free(mpnbuf);
if (mpvbuf)
free(mpvbuf);
if (mpntov)
free(mpntov);
free(mpvarry);
}
out:
scf_pg_destroy(mpg);
scf_property_destroy(mp);
scf_iter_destroy(mi);
scf_value_destroy(mv);
return (0);
}
int
lscf_hash_cleanup()
{
scf_service_t *svc;
scf_scope_t *scope;
scf_propertygroup_t *pg;
scf_property_t *prop;
scf_value_t *val;
scf_iter_t *iter;
char *pgname = NULL;
char *mfile = NULL;
int r;
svc = scf_service_create(g_hndl);
scope = scf_scope_create(g_hndl);
pg = scf_pg_create(g_hndl);
prop = scf_property_create(g_hndl);
val = scf_value_create(g_hndl);
iter = scf_iter_create(g_hndl);
if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
svc == NULL || scope == NULL) {
uu_warn(gettext("Unable to create a property group, or "
"property\n"));
uu_warn("%s\n", pg == NULL ? "pg is NULL" :
"pg is not NULL");
uu_warn("%s\n", prop == NULL ? "prop is NULL" :
"prop is not NULL");
uu_warn("%s\n", val == NULL ? "val is NULL" :
"val is not NULL");
uu_warn("%s\n", iter == NULL ? "iter is NULL" :
"iter is not NULL");
uu_warn("%s\n", svc == NULL ? "svc is NULL" :
"svc is not NULL");
uu_warn("%s\n", scope == NULL ? "scope is NULL" :
"scope is not NULL");
uu_warn(gettext("scf error is : %s\n"),
scf_strerror(scf_error()));
scfdie();
}
if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
switch (scf_error()) {
case SCF_ERROR_CONNECTION_BROKEN:
case SCF_ERROR_NOT_FOUND:
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
case SCF_ERROR_INVALID_ARGUMENT:
default:
bad_error("scf_handle_get_scope", scf_error());
}
}
if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
uu_warn(gettext("Unable to process the hash service, %s\n"),
HASH_SVC);
goto out;
}
pgname = safe_malloc(max_scf_name_len + 1);
mfile = safe_malloc(max_scf_value_len + 1);
if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
scf_strerror(scf_error()));
goto out;
}
while ((r = scf_iter_next_pg(iter, pg)) != 0) {
if (r == -1)
goto out;
if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
switch (scf_error()) {
case SCF_ERROR_DELETED:
return (ENODEV);
case SCF_ERROR_CONNECTION_BROKEN:
return (ECONNABORTED);
case SCF_ERROR_NOT_SET:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_pg_get_name", scf_error());
}
}
if (IGNORE_VAR) {
if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
continue;
}
if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
continue;
}
if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
uu_warn(gettext("Unable to get value from %s\n"),
pgname);
switch (scf_error()) {
case SCF_ERROR_DELETED:
case SCF_ERROR_CONSTRAINT_VIOLATED:
case SCF_ERROR_NOT_FOUND:
case SCF_ERROR_NOT_SET:
continue;
case SCF_ERROR_CONNECTION_BROKEN:
r = scferror2errno(scf_error());
goto out;
case SCF_ERROR_HANDLE_MISMATCH:
case SCF_ERROR_NOT_BOUND:
default:
bad_error("scf_property_get_value",
scf_error());
}
}
if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
== -1) {
uu_warn(gettext("Unable to get astring from %s : %s\n"),
pgname, scf_strerror(scf_error()));
switch (scf_error()) {
case SCF_ERROR_NOT_SET:
case SCF_ERROR_TYPE_MISMATCH:
continue;
default:
bad_error("scf_value_get_astring", scf_error());
}
}
if (access(mfile, F_OK) == 0)
continue;
(void) scf_pg_delete(pg);
}
out:
scf_scope_destroy(scope);
scf_service_destroy(svc);
scf_pg_destroy(pg);
scf_property_destroy(prop);
scf_value_destroy(val);
scf_iter_destroy(iter);
free(pgname);
free(mfile);
return (0);
}
#ifndef NATIVE_BUILD
CPL_MATCH_FN(complete_select)
{
const char *arg0, *arg1, *arg1end;
int word_start, err = 0, r;
size_t len;
char *buf;
lscf_prep_hndl();
arg0 = line + strspn(line, " \t");
assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
arg1 = arg0 + sizeof ("select") - 1;
arg1 += strspn(arg1, " \t");
word_start = arg1 - line;
arg1end = arg1 + strcspn(arg1, " \t");
if (arg1end < line + word_end)
return (0);
len = line + word_end - arg1;
buf = safe_malloc(max_scf_name_len + 1);
if (cur_snap != NULL) {
return (0);
} else if (cur_inst != NULL) {
return (0);
} else if (cur_svc != NULL) {
scf_instance_t *inst;
scf_iter_t *iter;
if ((inst = scf_instance_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_service_instances(iter, cur_svc) != 0)
scfdie();
for (;;) {
r = scf_iter_next_instance(iter, inst);
if (r == 0)
break;
if (r != 1)
scfdie();
if (scf_instance_get_name(inst, buf,
max_scf_name_len + 1) < 0)
scfdie();
if (strncmp(buf, arg1, len) == 0) {
err = cpl_add_completion(cpl, line, word_start,
word_end, buf + len, "", " ");
if (err != 0)
break;
}
}
scf_iter_destroy(iter);
scf_instance_destroy(inst);
return (err);
} else {
scf_service_t *svc;
scf_iter_t *iter;
assert(cur_scope != NULL);
if ((svc = scf_service_create(g_hndl)) == NULL ||
(iter = scf_iter_create(g_hndl)) == NULL)
scfdie();
if (scf_iter_scope_services(iter, cur_scope) != 0)
scfdie();
for (;;) {
r = scf_iter_next_service(iter, svc);
if (r == 0)
break;
if (r != 1)
scfdie();
if (scf_service_get_name(svc, buf,
max_scf_name_len + 1) < 0)
scfdie();
if (strncmp(buf, arg1, len) == 0) {
err = cpl_add_completion(cpl, line, word_start,
word_end, buf + len, "", " ");
if (err != 0)
break;
}
}
scf_iter_destroy(iter);
scf_service_destroy(svc);
return (err);
}
}
CPL_MATCH_FN(complete_command)
{
uint32_t scope = 0;
if (cur_snap != NULL)
scope = CS_SNAP;
else if (cur_inst != NULL)
scope = CS_INST;
else if (cur_svc != NULL)
scope = CS_SVC;
else
scope = CS_SCOPE;
return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
}
#endif