summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/svc/configd/backend.c132
-rw-r--r--usr/src/cmd/svc/configd/configd.c23
-rw-r--r--usr/src/cmd/svc/configd/configd.h2
-rw-r--r--usr/src/cmd/svc/configd/file_object.c33
-rw-r--r--usr/src/cmd/svc/configd/object.c30
-rw-r--r--usr/src/cmd/svc/svccfg/svccfg_internal.c9
-rw-r--r--usr/src/cmd/svc/svccfg/svccfg_libscf.c4
-rw-r--r--usr/src/lib/libscf/common/lowlevel.c12
-rw-r--r--usr/src/lib/libscf/common/lowlevel_impl.h10
9 files changed, 215 insertions, 40 deletions
diff --git a/usr/src/cmd/svc/configd/backend.c b/usr/src/cmd/svc/configd/backend.c
index 3354b2faee..3c07f41845 100644
--- a/usr/src/cmd/svc/configd/backend.c
+++ b/usr/src/cmd/svc/configd/backend.c
@@ -135,7 +135,12 @@ int backend_panic_abort = 0; /* abort when panicking */
#define BACKEND_READONLY_CHECK_INTERVAL (2 * (hrtime_t)NANOSEC)
/*
- * Any change to the below schema should bump the version number
+ * Any incompatible change to the below schema should bump the version number.
+ * The schema has been changed to support value ordering, but this change
+ * is backwards-compatible - i.e. a previous svc.configd can use a
+ * repository database with the new schema perfectly well. As a result,
+ * the schema version has not been updated, allowing downgrade of systems
+ * without losing repository data.
*/
#define BACKEND_SCHEMA_VERSION 5
@@ -257,13 +262,15 @@ static struct backend_tbl_info tbls_common[] = { /* all backend types */
/*
* value_tbl maps a value_id to a set of values. For any given
- * value_id, value_type is constant.
+ * value_id, value_type is constant. The table definition here
+ * is repeated in backend_check_upgrade(), and must be kept in-sync.
*/
{
"value_tbl",
"value_id INTEGER NOT NULL,"
"value_type CHAR(1) NOT NULL,"
- "value_value VARCHAR NOT NULL"
+ "value_value VARCHAR NOT NULL,"
+ "value_order INTEGER DEFAULT 0"
},
/*
@@ -286,6 +293,10 @@ static struct backend_tbl_info tbls_common[] = { /* all backend types */
{ NULL, NULL }
};
+/*
+ * The indexing of value_tbl is repeated in backend_check_upgrade() and
+ * must be kept in sync with the indexing specification here.
+ */
static struct backend_idx_info idxs_common[] = { /* all backend types */
{ "pg_tbl", "parent", "pg_parent_id" },
{ "pg_tbl", "name", "pg_parent_id, pg_name" },
@@ -368,6 +379,29 @@ backend_trace_sql(void *arg, const char *sql)
static sqlite_backend_t be_info[BACKEND_TYPE_TOTAL];
static sqlite_backend_t *bes[BACKEND_TYPE_TOTAL];
+/*
+ * For a native build, repositories are created from scratch, so upgrade
+ * is not an issue. This variable is implicitly protected by
+ * bes[BACKEND_TYPE_NORMAL]->be_lock.
+ */
+#ifdef NATIVE_BUILD
+static boolean_t be_normal_upgraded = B_TRUE;
+#else
+static boolean_t be_normal_upgraded = B_FALSE;
+#endif /* NATIVE_BUILD */
+
+/*
+ * Has backend been upgraded? In nonpersistent case, answer is always
+ * yes.
+ */
+boolean_t
+backend_is_upgraded(backend_tx_t *bt)
+{
+ if (bt->bt_type == BACKEND_TYPE_NONPERSIST)
+ return (B_TRUE);
+ return (be_normal_upgraded);
+}
+
#define BACKEND_PANIC_TIMEOUT (50 * MILLISEC)
/*
* backend_panic() -- some kind of database problem or corruption has been hit.
@@ -953,6 +987,75 @@ out:
return (result);
}
+/*
+ * Check if value_tbl has been upgraded in the main database, and
+ * if not (if the value_order column is not present), and do_upgrade is true,
+ * upgrade value_tbl in repository to contain the additional value_order
+ * column. The version of sqlite used means ALTER TABLE is not
+ * available, so we cannot simply use "ALTER TABLE value_tbl ADD COLUMN".
+ * Rather we need to create a temporary table with the additional column,
+ * import the value_tbl, drop the original value_tbl, recreate the value_tbl
+ * with the additional column, import the values from value_tbl_tmp,
+ * reindex and finally drop value_tbl_tmp. During boot, we wish to check
+ * if the repository has been upgraded before it is writable, so that
+ * property value retrieval can use the appropriate form of the SELECT
+ * statement that retrieves property values. As a result, we need to check
+ * if the repository has been upgraded prior to the point when we can
+ * actually carry out the update.
+ */
+void
+backend_check_upgrade(sqlite_backend_t *be, boolean_t do_upgrade)
+{
+ char *errp;
+ int r;
+
+ if (be_normal_upgraded)
+ return;
+ /*
+ * Test if upgrade is needed. If value_order column does not exist,
+ * we need to upgrade the schema.
+ */
+ r = sqlite_exec(be->be_db, "SELECT value_order FROM value_tbl LIMIT 1;",
+ NULL, NULL, NULL);
+ if (r == SQLITE_ERROR && do_upgrade) {
+ /* No value_order column - needs upgrade */
+ configd_info("Upgrading SMF repository format...");
+ r = sqlite_exec(be->be_db,
+ "BEGIN TRANSACTION; "
+ "CREATE TABLE value_tbl_tmp ( "
+ "value_id INTEGER NOT NULL, "
+ "value_type CHAR(1) NOT NULL, "
+ "value_value VARCHAR NOT NULL, "
+ "value_order INTEGER DEFAULT 0); "
+ "INSERT INTO value_tbl_tmp "
+ "(value_id, value_type, value_value) "
+ "SELECT value_id, value_type, value_value FROM value_tbl; "
+ "DROP TABLE value_tbl; "
+ "CREATE TABLE value_tbl( "
+ "value_id INTEGER NOT NULL, "
+ "value_type CHAR(1) NOT NULL, "
+ "value_value VARCHAR NOT NULL, "
+ "value_order INTEGER DEFAULT 0); "
+ "INSERT INTO value_tbl SELECT * FROM value_tbl_tmp; "
+ "CREATE INDEX value_tbl_id ON value_tbl (value_id); "
+ "DROP TABLE value_tbl_tmp; "
+ "COMMIT TRANSACTION; "
+ "VACUUM; ",
+ NULL, NULL, &errp);
+ if (r == SQLITE_OK) {
+ configd_info("SMF repository upgrade is complete.");
+ } else {
+ backend_panic("%s: repository upgrade failed: %s",
+ be->be_path, errp);
+ /* NOTREACHED */
+ }
+ }
+ if (r == SQLITE_OK)
+ be_normal_upgraded = B_TRUE;
+ else
+ be_normal_upgraded = B_FALSE;
+}
+
static int
backend_check_readonly(sqlite_backend_t *be, int writing, hrtime_t t)
{
@@ -990,12 +1093,15 @@ backend_check_readonly(sqlite_backend_t *be, int writing, hrtime_t t)
/*
* We can write! Swap the db handles, mark ourself writable,
- * and make a backup.
+ * upgrade if necessary, and make a backup.
*/
sqlite_close(be->be_db);
be->be_db = new;
be->be_readonly = 0;
+ if (be->be_type == BACKEND_TYPE_NORMAL)
+ backend_check_upgrade(be, B_TRUE);
+
if (backend_create_backup_locked(be, REPOSITORY_BOOT_BACKUP) !=
REP_PROTOCOL_SUCCESS) {
configd_critical(
@@ -1435,6 +1541,7 @@ backend_create(backend_type_t backend_id, const char *db_file,
assert(backend_id >= 0 && backend_id < BACKEND_TYPE_TOTAL);
be = &be_info[backend_id];
+
assert(be->be_db == NULL);
(void) pthread_mutex_init(&be->be_lock, NULL);
@@ -1466,7 +1573,6 @@ backend_create(backend_type_t backend_id, const char *db_file,
/*
* check if we are inited and of the correct schema version
*
- * Eventually, we'll support schema upgrade here.
*/
info.rs_out = &val;
info.rs_result = REP_PROTOCOL_FAIL_NOT_FOUND;
@@ -1598,6 +1704,17 @@ integrity_fail:
}
/*
+ * Simply do check if backend has been upgraded. We do not wish
+ * to actually carry out upgrade here - the main repository may
+ * not be writable at this point. Actual upgrade is carried out
+ * via backend_check_readonly(). This check is done so that
+ * we determine repository state - upgraded or not - and then
+ * the appropriate SELECT statement (value-ordered or not)
+ * can be used when retrieving property values early in boot.
+ */
+ if (backend_id == BACKEND_TYPE_NORMAL)
+ backend_check_upgrade(be, B_FALSE);
+ /*
* check if we are writable
*/
r = backend_is_readonly(be->be_db, be->be_path);
@@ -1614,6 +1731,7 @@ integrity_fail:
*bep = be;
return (BACKEND_CREATE_READONLY);
}
+
*bep = be;
return (BACKEND_CREATE_SUCCESS);
@@ -2250,7 +2368,8 @@ backend_init(const char *db_file, const char *npdb_file, int have_np)
/*
* If we started up with a writable filesystem, but the
* non-persistent database needed initialization, we
- * are booting a non-global zone, so do a backup.
+ * are booting a non-global zone, so do a backup, and carry
+ * out upgrade if necessary.
*/
if (r == BACKEND_CREATE_NEED_INIT && writable_persist &&
backend_lock(BACKEND_TYPE_NORMAL, 0, &be) ==
@@ -2262,6 +2381,7 @@ backend_init(const char *db_file, const char *npdb_file, int have_np)
"\"%s\"\n", REPOSITORY_BOOT_BACKUP,
be->be_path);
}
+ backend_check_upgrade(be, B_TRUE);
backend_unlock(be);
}
}
diff --git a/usr/src/cmd/svc/configd/configd.c b/usr/src/cmd/svc/configd/configd.c
index cdbec408c4..563d097310 100644
--- a/usr/src/cmd/svc/configd/configd.c
+++ b/usr/src/cmd/svc/configd/configd.c
@@ -380,13 +380,15 @@ create_connection(ucred_t *uc, repository_door_request_t *rp,
}
void
-configd_vcritical(const char *message, va_list args)
+configd_vlog(int severity, const char *prefix, const char *message,
+ va_list args)
{
if (log_to_syslog)
- vsyslog(LOG_CRIT, message, args);
+ vsyslog(severity, message, args);
else {
flockfile(stderr);
- (void) fprintf(stderr, "svc.configd: Fatal error: ");
+ if (prefix != NULL)
+ (void) fprintf(stderr, "%s", prefix);
(void) vfprintf(stderr, message, args);
if (message[0] == 0 || message[strlen(message) - 1] != '\n')
(void) fprintf(stderr, "\n");
@@ -395,6 +397,12 @@ configd_vcritical(const char *message, va_list args)
}
void
+configd_vcritical(const char *message, va_list args)
+{
+ configd_vlog(LOG_CRIT, "svc.configd: Fatal error: ", message, args);
+}
+
+void
configd_critical(const char *message, ...)
{
va_list args;
@@ -403,6 +411,15 @@ configd_critical(const char *message, ...)
va_end(args);
}
+void
+configd_info(const char *message, ...)
+{
+ va_list args;
+ va_start(args, message);
+ configd_vlog(LOG_INFO, "svc.configd: ", message, args);
+ va_end(args);
+}
+
static void
usage(const char *prog, int ret)
{
diff --git a/usr/src/cmd/svc/configd/configd.h b/usr/src/cmd/svc/configd/configd.h
index a1fdee0d1d..a35239cab4 100644
--- a/usr/src/cmd/svc/configd/configd.h
+++ b/usr/src/cmd/svc/configd/configd.h
@@ -616,6 +616,7 @@ adt_session_data_t *get_audit_session(void);
void configd_critical(const char *, ...);
void configd_vcritical(const char *, va_list);
+void configd_info(const char *, ...);
extern int is_main_repository;
extern int max_repository_backups;
@@ -752,6 +753,7 @@ void rc_snaplevel_rele(rc_snaplevel_t *);
* backend.c
*/
int backend_init(const char *, const char *, int);
+boolean_t backend_is_upgraded(backend_tx_t *);
void backend_fini(void);
rep_protocol_responseid_t backend_create_backup(const char *);
diff --git a/usr/src/cmd/svc/configd/file_object.c b/usr/src/cmd/svc/configd/file_object.c
index bbe400e4bf..ad1da04d8f 100644
--- a/usr/src/cmd/svc/configd/file_object.c
+++ b/usr/src/cmd/svc/configd/file_object.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -743,9 +742,29 @@ fill_property_callback(void *data, int columns, char **vals, char **names)
rep_protocol_responseid_t r;
backend_query_t *q = backend_query_alloc();
- backend_query_add(q,
- "SELECT value_value FROM value_tbl "
- "WHERE (value_id = '%q')", cur);
+ /*
+ * Ensure that select operation is reflective
+ * of repository schema. If the repository has
+ * been upgraded, make use of value ordering
+ * by retrieving values in order using the
+ * value_order column. Otherwise, simply
+ * run the select with no order specified.
+ * The order-insensitive select is necessary
+ * as on first reboot post-upgrade, the repository
+ * contents need to be read before the repository
+ * backend is writable (and upgrade is possible).
+ */
+ if (backend_is_upgraded(tx)) {
+ backend_query_add(q,
+ "SELECT value_value FROM value_tbl "
+ "WHERE (value_id = '%q') ORDER BY value_order",
+ cur);
+ } else {
+ backend_query_add(q,
+ "SELECT value_value FROM value_tbl "
+ "WHERE (value_id = '%q')",
+ cur);
+ }
switch (r = backend_tx_run(tx, q, property_value_size_cb,
&info)) {
diff --git a/usr/src/cmd/svc/configd/object.c b/usr/src/cmd/svc/configd/object.c
index 2c7d6a8652..ba4154329a 100644
--- a/usr/src/cmd/svc/configd/object.c
+++ b/usr/src/cmd/svc/configd/object.c
@@ -194,7 +194,6 @@ tx_process_cmds(tx_commit_data_t *data)
backend_query_t *q;
int do_delete;
- uint32_t nvalues;
/*
* For persistent pgs, we use backend_fail_if_seen to abort the
@@ -283,7 +282,7 @@ tx_process_cmds(tx_commit_data_t *data)
data->txc_pg_id, data->txc_gen, elem->tx_prop,
type);
} else {
- uint32_t *v;
+ uint32_t *v, i = 0;
const char *str;
val_id = backend_new_id(data->txc_tx, BACKEND_ID_VALUE);
@@ -299,16 +298,29 @@ tx_process_cmds(tx_commit_data_t *data)
v = elem->tx_values;
- nvalues = elem->tx_nvalues;
- while (r == REP_PROTOCOL_SUCCESS &&
- nvalues--) {
+ for (i = 0; i < elem->tx_nvalues; i++) {
str = (const char *)&v[1];
+ /*
+ * Update values in backend, imposing
+ * ordering via the value_order column.
+ * This ordering is then used in subseqent
+ * value retrieval operations. We can
+ * safely assume that the repository schema
+ * has been upgraded (and hence has the
+ * value_order column in value_tbl), since
+ * it is upgraded as soon as the repository
+ * is writable.
+ */
r = backend_tx_run_update(data->txc_tx,
- "INSERT INTO value_tbl "
- " (value_id, value_type, value_value) "
- "VALUES (%d, '%c', '%q');\n",
- val_id, elem->tx_cmd->rptc_type, str);
+ "INSERT INTO value_tbl (value_id, "
+ "value_type, value_value, "
+ "value_order) VALUES (%d, '%c', "
+ "'%q', '%d');\n",
+ val_id, elem->tx_cmd->rptc_type,
+ str, i);
+ if (r != REP_PROTOCOL_SUCCESS)
+ break;
/*LINTED alignment*/
v = (uint32_t *)((caddr_t)str + TX_SIZE(*v));
diff --git a/usr/src/cmd/svc/svccfg/svccfg_internal.c b/usr/src/cmd/svc/svccfg/svccfg_internal.c
index 5a4d3515a0..74d206f67a 100644
--- a/usr/src/cmd/svc/svccfg/svccfg_internal.c
+++ b/usr/src/cmd/svc/svccfg/svccfg_internal.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -458,7 +458,7 @@ internal_property_new()
uu_list_node_init(p, &p->sc_node, property_pool);
- p->sc_property_values = uu_list_create(value_pool, p, UU_LIST_SORTED);
+ p->sc_property_values = uu_list_create(value_pool, p, 0);
p->sc_property_name = "<unset>";
return (p);
@@ -669,10 +669,7 @@ internal_attach_property(pgroup_t *pgrp, property_t *prop)
void
internal_attach_value(property_t *prop, value_t *val)
{
- uu_list_index_t idx;
-
- (void) uu_list_find(prop->sc_property_values, val, NULL, &idx);
- uu_list_insert(prop->sc_property_values, val, idx);
+ (void) uu_list_append(prop->sc_property_values, val);
}
/*
diff --git a/usr/src/cmd/svc/svccfg/svccfg_libscf.c b/usr/src/cmd/svc/svccfg/svccfg_libscf.c
index 098e0ce4ad..c152e2cd10 100644
--- a/usr/src/cmd/svc/svccfg/svccfg_libscf.c
+++ b/usr/src/cmd/svc/svccfg/svccfg_libscf.c
@@ -11156,7 +11156,7 @@ lscf_setprop(const char *pgname, const char *type, const char *value,
assert(values != NULL);
walk = uu_list_walk_start((uu_list_t *)values,
- UU_WALK_REVERSE);
+ UU_DEFAULT);
if (walk == NULL)
uu_die(gettext("Could not walk list"));
@@ -11619,7 +11619,7 @@ add_string(uu_list_t *strlist, const char *str)
elem = safe_malloc(sizeof (*elem));
uu_list_node_init(elem, &elem->node, string_pool);
elem->str = safe_strdup(str);
- if (uu_list_prepend(strlist, elem) != 0)
+ if (uu_list_append(strlist, elem) != 0)
uu_die(gettext("libuutil error: %s\n"),
uu_strerror(uu_error()));
}
diff --git a/usr/src/lib/libscf/common/lowlevel.c b/usr/src/lib/libscf/common/lowlevel.c
index 4c25197400..6374590467 100644
--- a/usr/src/lib/libscf/common/lowlevel.c
+++ b/usr/src/lib/libscf/common/lowlevel.c
@@ -3637,6 +3637,7 @@ entry_invalidate(scf_transaction_entry_t *cur, int and_destroy,
scf_value_reset_locked(v, and_destroy);
}
cur->entry_head = NULL;
+ cur->entry_tail = NULL;
}
static void
@@ -4173,8 +4174,15 @@ scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v)
}
v->value_tx = entry;
- v->value_next = entry->entry_head;
- entry->entry_head = v;
+ v->value_next = NULL;
+ if (entry->entry_head == NULL) {
+ entry->entry_head = v;
+ entry->entry_tail = v;
+ } else {
+ entry->entry_tail->value_next = v;
+ entry->entry_tail = v;
+ }
+
(void) pthread_mutex_unlock(&h->rh_lock);
return (SCF_SUCCESS);
diff --git a/usr/src/lib/libscf/common/lowlevel_impl.h b/usr/src/lib/libscf/common/lowlevel_impl.h
index a3bc40aed9..e96ce2ade2 100644
--- a/usr/src/lib/libscf/common/lowlevel_impl.h
+++ b/usr/src/lib/libscf/common/lowlevel_impl.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -171,7 +170,8 @@ struct scf_transaction_entry {
enum scf_entry_state entry_state;
uu_list_node_t entry_link; /* for property name list */
- scf_value_t *entry_head; /* for linked values */
+ scf_value_t *entry_head;
+ scf_value_t *entry_tail; /* for linked values */
enum rep_protocol_transaction_action entry_action;
rep_protocol_value_type_t entry_type;