summaryrefslogtreecommitdiff
path: root/usr/src/lib/libscf/common/midlevel.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libscf/common/midlevel.c')
-rw-r--r--usr/src/lib/libscf/common/midlevel.c397
1 files changed, 395 insertions, 2 deletions
diff --git a/usr/src/lib/libscf/common/midlevel.c b/usr/src/lib/libscf/common/midlevel.c
index a15fb445c7..c12cab4027 100644
--- a/usr/src/lib/libscf/common/midlevel.c
+++ b/usr/src/lib/libscf/common/midlevel.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "libscf_impl.h"
#include <libuutil.h>
@@ -36,6 +34,7 @@
#include <sys/param.h>
#include <errno.h>
#include <libgen.h>
+#include <assert.h>
#include "midlevel_impl.h"
#include "lowlevel_impl.h"
@@ -2485,3 +2484,397 @@ gen_filenms_from_fmri(const char *fmri, const char *name, char *filename,
return (0);
}
+
+static scf_type_t
+scf_true_base_type(scf_type_t type)
+{
+ scf_type_t base = type;
+
+ do {
+ type = base;
+ (void) scf_type_base_type(type, &base);
+ } while (base != type);
+
+ return (base);
+}
+
+/*
+ * Convenience routine which frees all strings and opaque data
+ * allocated by scf_read_propvec.
+ *
+ * Like free(3C), this function preserves the value of errno.
+ */
+void
+scf_clean_propvec(scf_propvec_t *propvec)
+{
+ int saved_errno = errno;
+ scf_propvec_t *prop;
+
+ for (prop = propvec; prop->pv_prop != NULL; prop++) {
+ assert(prop->pv_type != SCF_TYPE_INVALID);
+ if (prop->pv_type == SCF_TYPE_OPAQUE) {
+ scf_opaque_t *o = prop->pv_ptr;
+
+ if (o->so_addr != NULL)
+ free(o->so_addr);
+ } else if (scf_true_base_type(prop->pv_type) ==
+ SCF_TYPE_ASTRING) {
+ if (*(char **)prop->pv_ptr != NULL)
+ free(*(char **)prop->pv_ptr);
+ }
+ }
+
+ errno = saved_errno;
+}
+
+static int
+count_props(scf_propvec_t *props)
+{
+ int count = 0;
+
+ for (; props->pv_prop != NULL; props++)
+ count++;
+ return (count);
+}
+
+/*
+ * Reads a vector of properties from the specified fmri/property group.
+ * If 'running' is true, reads from the running snapshot instead of the
+ * editing snapshot.
+ *
+ * For string types, a buffer is allocated using malloc(3C) to hold the
+ * zero-terminated string, a pointer to which is stored in the
+ * caller-provided char **. It is the caller's responsbility to free
+ * this string. To simplify error handling, unread strings are
+ * initialized to NULL.
+ *
+ * For opaque types, a buffer is allocated using malloc(3C) to hold the
+ * opaque data. A pointer to this buffer and its size are stored in
+ * the caller-provided scf_opaque_t. It is the caller's responsibility
+ * to free this buffer. To simplify error handling, the address fields
+ * for unread opaque data are initialized to NULL.
+ *
+ * All other data is stored directly in caller-provided variables or
+ * structures.
+ *
+ * If this function fails to read a specific property, *badprop is set
+ * to point at that property's entry in the properties array.
+ *
+ * On all failures, all memory allocated by this function is freed.
+ */
+int
+scf_read_propvec(const char *fmri, const char *pgname, boolean_t running,
+ scf_propvec_t *properties, scf_propvec_t **badprop)
+{
+ scf_handle_t *h = handle_create();
+ scf_service_t *s = scf_service_create(h);
+ scf_instance_t *i = scf_instance_create(h);
+ scf_snapshot_t *snap = running ? scf_snapshot_create(h) : NULL;
+ scf_propertygroup_t *pg = scf_pg_create(h);
+ scf_property_t *p = scf_property_create(h);
+ scf_value_t *v = scf_value_create(h);
+ boolean_t instance = B_TRUE;
+ scf_propvec_t *prop;
+ int error = 0;
+
+ if (h == NULL || s == NULL || i == NULL || (running && snap == NULL) ||
+ pg == NULL || p == NULL || v == NULL)
+ goto scferror;
+
+ if (scf_handle_decode_fmri(h, fmri, NULL, s, i, NULL, NULL, 0) == -1)
+ goto scferror;
+
+ if (scf_instance_to_fmri(i, NULL, 0) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_SET)
+ goto scferror;
+ instance = B_FALSE;
+ }
+
+ if (running) {
+ if (!instance) {
+ error = SCF_ERROR_TYPE_MISMATCH;
+ goto out;
+ }
+
+ if (scf_instance_get_snapshot(i, "running", snap) !=
+ SCF_SUCCESS)
+ goto scferror;
+ }
+
+ if ((instance ? scf_instance_get_pg_composed(i, snap, pgname, pg) :
+ scf_service_get_pg(s, pgname, pg)) == -1)
+ goto scferror;
+
+ for (prop = properties; prop->pv_prop != NULL; prop++) {
+ if (prop->pv_type == SCF_TYPE_OPAQUE)
+ ((scf_opaque_t *)prop->pv_ptr)->so_addr = NULL;
+ else if (scf_true_base_type(prop->pv_type) == SCF_TYPE_ASTRING)
+ *((char **)prop->pv_ptr) = NULL;
+ }
+
+ for (prop = properties; prop->pv_prop != NULL; prop++) {
+ int ret = 0;
+
+ if (scf_pg_get_property(pg, prop->pv_prop, p) == -1 ||
+ scf_property_get_value(p, v) == -1) {
+ *badprop = prop;
+ goto scferror;
+ }
+ switch (prop->pv_type) {
+ case SCF_TYPE_BOOLEAN: {
+ uint8_t b;
+
+ ret = scf_value_get_boolean(v, &b);
+ if (ret == -1)
+ break;
+ if (prop->pv_aux != 0) {
+ uint64_t *bits = prop->pv_ptr;
+ *bits = b ? (*bits | prop->pv_aux) :
+ (*bits & ~prop->pv_aux);
+ } else {
+ boolean_t *bool = prop->pv_ptr;
+ *bool = b ? B_TRUE : B_FALSE;
+ }
+ break;
+ }
+ case SCF_TYPE_COUNT:
+ ret = scf_value_get_count(v, prop->pv_ptr);
+ break;
+ case SCF_TYPE_INTEGER:
+ ret = scf_value_get_integer(v, prop->pv_ptr);
+ break;
+ case SCF_TYPE_TIME: {
+ scf_time_t *time = prop->pv_ptr;
+
+ ret = scf_value_get_time(v, &time->st_sec,
+ &time->st_nanosec);
+ break;
+ }
+ case SCF_TYPE_OPAQUE: {
+ scf_opaque_t *opaque = prop->pv_ptr;
+ ssize_t size = scf_value_get_opaque(v, NULL, 0);
+
+ if (size == -1) {
+ *badprop = prop;
+ goto scferror;
+ }
+ if ((opaque->so_addr = malloc(size)) == NULL) {
+ error = SCF_ERROR_NO_MEMORY;
+ goto out;
+ }
+ opaque->so_size = size;
+ ret = scf_value_get_opaque(v, opaque->so_addr, size);
+ break;
+ }
+ default: {
+ char *s;
+ ssize_t size;
+
+ assert(scf_true_base_type(prop->pv_type) ==
+ SCF_TYPE_ASTRING);
+
+ size = scf_value_get_astring(v, NULL, 0);
+ if (size == -1) {
+ *badprop = prop;
+ goto scferror;
+ }
+ if ((s = malloc(++size)) == NULL) {
+ error = SCF_ERROR_NO_MEMORY;
+ goto out;
+ }
+ ret = scf_value_get_astring(v, s, size);
+ *(char **)prop->pv_ptr = s;
+ }
+
+ if (ret == -1) {
+ *badprop = prop;
+ goto scferror;
+ }
+
+ }
+ }
+
+ goto out;
+
+scferror:
+ error = scf_error();
+ scf_clean_propvec(properties);
+
+out:
+ scf_pg_destroy(pg);
+ scf_snapshot_destroy(snap);
+ scf_instance_destroy(i);
+ scf_service_destroy(s);
+ scf_handle_destroy(h);
+
+ if (error != 0) {
+ (void) scf_set_error(error);
+ return (SCF_FAILED);
+ }
+
+ return (SCF_SUCCESS);
+}
+
+/*
+ * Writes a vector of properties to the specified fmri/property group.
+ *
+ * If this function fails to write a specific property, *badprop is set
+ * to point at that property's entry in the properties array.
+ *
+ * One significant difference between this function and the
+ * scf_read_propvec function is that for string types, pv_ptr is a
+ * char *, not a char **. This means that you can't write a propvec
+ * you just read, but makes other uses (hopefully the majority) simpler.
+ */
+int
+scf_write_propvec(const char *fmri, const char *pgname,
+ scf_propvec_t *properties, scf_propvec_t **badprop)
+{
+ scf_handle_t *h = handle_create();
+ scf_service_t *s = scf_service_create(h);
+ scf_instance_t *inst = scf_instance_create(h);
+ scf_snapshot_t *snap = scf_snapshot_create(h);
+ scf_propertygroup_t *pg = scf_pg_create(h);
+ scf_property_t *p = scf_property_create(h);
+ scf_transaction_t *tx = scf_transaction_create(h);
+ scf_value_t **v = NULL;
+ scf_transaction_entry_t **e = NULL;
+ boolean_t instance = B_TRUE;
+ int i, n;
+ scf_propvec_t *prop;
+ int error = 0, ret;
+
+ n = count_props(properties);
+ v = calloc(n, sizeof (scf_value_t *));
+ e = calloc(n, sizeof (scf_transaction_entry_t *));
+
+ if (v == NULL || e == NULL) {
+ error = SCF_ERROR_NO_MEMORY;
+ goto out;
+ }
+
+ if (h == NULL || s == NULL || inst == NULL || pg == NULL || p == NULL ||
+ tx == NULL)
+ goto scferror;
+
+ for (i = 0; i < n; i++) {
+ v[i] = scf_value_create(h);
+ e[i] = scf_entry_create(h);
+ if (v[i] == NULL || e[i] == NULL)
+ goto scferror;
+ }
+
+ if (scf_handle_decode_fmri(h, fmri, NULL, s, inst, NULL, NULL, 0)
+ != SCF_SUCCESS)
+ goto scferror;
+
+ if (scf_instance_to_fmri(inst, NULL, 0) == -1) {
+ if (scf_error() != SCF_ERROR_NOT_SET)
+ goto scferror;
+ instance = B_FALSE;
+ }
+
+ if ((instance ? scf_instance_get_pg(inst, pgname, pg) :
+ scf_service_get_pg(s, pgname, pg)) == -1)
+ goto scferror;
+
+top:
+ if (scf_transaction_start(tx, pg) == -1)
+ goto scferror;
+
+ for (prop = properties, i = 0; prop->pv_prop != NULL; prop++, i++) {
+ ret = scf_transaction_property_change(tx, e[i], prop->pv_prop,
+ prop->pv_type);
+ if (ret == -1 && scf_error() == SCF_ERROR_NOT_FOUND)
+ ret = scf_transaction_property_new(tx, e[i],
+ prop->pv_prop, prop->pv_type);
+
+ if (ret == -1) {
+ *badprop = prop;
+ goto scferror;
+ }
+
+ switch (prop->pv_type) {
+ case SCF_TYPE_BOOLEAN: {
+ boolean_t b = (prop->pv_aux != 0) ?
+ (*(uint64_t *)prop->pv_ptr & prop->pv_aux) != 0 :
+ *(boolean_t *)prop->pv_ptr;
+
+ scf_value_set_boolean(v[i], b ? 1 : 0);
+ break;
+ }
+ case SCF_TYPE_COUNT:
+ scf_value_set_count(v[i], *(uint64_t *)prop->pv_ptr);
+ break;
+ case SCF_TYPE_INTEGER:
+ scf_value_set_integer(v[i], *(int64_t *)prop->pv_ptr);
+ break;
+ case SCF_TYPE_TIME: {
+ scf_time_t *time = prop->pv_ptr;
+
+ ret = scf_value_set_time(v[i], time->st_sec,
+ time->st_nanosec);
+ break;
+ }
+ case SCF_TYPE_OPAQUE: {
+ scf_opaque_t *opaque = prop->pv_ptr;
+
+ ret = scf_value_set_opaque(v[i], opaque->so_addr,
+ opaque->so_size);
+ break;
+ }
+ case SCF_TYPE_ASTRING:
+ ret = scf_value_set_astring(v[i],
+ (const char *)prop->pv_ptr);
+ break;
+ default:
+ ret = scf_value_set_from_string(v[i], prop->pv_type,
+ (const char *)prop->pv_ptr);
+ }
+
+ if (ret == -1 || scf_entry_add_value(e[i], v[i]) == -1) {
+ *badprop = prop;
+ goto scferror;
+ }
+ }
+
+ ret = scf_transaction_commit(tx);
+ if (ret == 1)
+ goto out;
+
+ if (ret == 0 && scf_pg_update(pg) != -1) {
+ scf_transaction_reset(tx);
+ goto top;
+ }
+
+scferror:
+ error = scf_error();
+
+out:
+ if (v != NULL) {
+ for (i = 0; i < n; i++)
+ scf_value_destroy(v[i]);
+ free(v);
+ }
+
+ if (e != NULL) {
+ for (i = 0; i < n; i++)
+ scf_entry_destroy(e[i]);
+ free(e);
+ }
+
+ scf_transaction_destroy(tx);
+ scf_property_destroy(p);
+ scf_pg_destroy(pg);
+ scf_snapshot_destroy(snap);
+ scf_instance_destroy(inst);
+ scf_service_destroy(s);
+ scf_handle_destroy(h);
+
+ if (error != 0) {
+ (void) scf_set_error(error);
+ return (SCF_FAILED);
+ }
+
+ return (SCF_SUCCESS);
+}