summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/mdb/common/modules/libuutil/libuutil.c20
-rw-r--r--usr/src/cmd/svc/configd/backend.c215
-rw-r--r--usr/src/cmd/svc/configd/client.c78
-rw-r--r--usr/src/cmd/svc/configd/configd.c42
-rw-r--r--usr/src/cmd/svc/configd/configd.h14
-rw-r--r--usr/src/cmd/svc/configd/file_object.c276
-rw-r--r--usr/src/cmd/svc/configd/restore_repository.sh55
-rw-r--r--usr/src/lib/libscf/common/lowlevel.c156
-rw-r--r--usr/src/lib/libscf/common/lowlevel_impl.h8
-rw-r--r--usr/src/lib/libuutil/common/libuutil_impl.h34
-rw-r--r--usr/src/lib/libuutil/common/uu_avl.c45
-rw-r--r--usr/src/lib/libuutil/common/uu_list.c32
12 files changed, 773 insertions, 202 deletions
diff --git a/usr/src/cmd/mdb/common/modules/libuutil/libuutil.c b/usr/src/cmd/mdb/common/modules/libuutil/libuutil.c
index d9444cc3ce..aa890302ec 100644
--- a/usr/src/cmd/mdb/common/modules/libuutil/libuutil.c
+++ b/usr/src/cmd/mdb/common/modules/libuutil/libuutil.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -106,8 +106,8 @@ uutil_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
"ADDR", "POOL", "PARENT", "NODES", "FLAGS");
mdb_printf("%0?p %0?p %0?p %6u %c%c\n",
- addr, ul.ul_pool, ul.ul_parent, ul.ul_numnodes,
- ul.ul_sorted ? 'S' : ' ', ul.ul_debug? 'D' : ' ');
+ addr, ul.ul_pool, UU_PTR_DECODE(ul.ul_parent_enc),
+ ul.ul_numnodes, ul.ul_sorted ? 'S' : ' ', ul.ul_debug? 'D' : ' ');
return (DCMD_OK);
}
@@ -185,21 +185,23 @@ typedef struct uutil_list_walk {
int
uutil_list_walk_init(mdb_walk_state_t *wsp)
{
- uu_list_t null_list;
uutil_list_walk_t *ulw;
uu_list_pool_t ulp;
- bzero(&null_list, sizeof (uu_list_t));
-
if (mdb_vread(&ulp, sizeof (uu_list_pool_t), wsp->walk_addr) == -1) {
mdb_warn("failed to read uu_list_pool_t at given address\n");
return (WALK_ERR);
}
+ if (UU_LIST_PTR(ulp.ulp_null_list.ul_next_enc) ==
+ &((uu_list_pool_t *)wsp->walk_addr)->ulp_null_list)
+ return (WALK_DONE);
+
ulw = mdb_alloc(sizeof (uutil_list_walk_t), UM_SLEEP);
- ulw->ulw_final = (uintptr_t)ulp.ulp_null_list.ul_prev;
- ulw->ulw_current = (uintptr_t)ulp.ulp_null_list.ul_next;
+ ulw->ulw_final = (uintptr_t)UU_LIST_PTR(ulp.ulp_null_list.ul_prev_enc);
+ ulw->ulw_current =
+ (uintptr_t)UU_LIST_PTR(ulp.ulp_null_list.ul_next_enc);
wsp->walk_data = ulw;
return (WALK_NEXT);
@@ -222,7 +224,7 @@ uutil_list_walk_step(mdb_walk_state_t *wsp)
if (ulw->ulw_current == ulw->ulw_final)
return (WALK_DONE);
- ulw->ulw_current = (uintptr_t)ul.ul_next;
+ ulw->ulw_current = (uintptr_t)UU_LIST_PTR(ul.ul_next_enc);
return (status);
}
diff --git a/usr/src/cmd/svc/configd/backend.c b/usr/src/cmd/svc/configd/backend.c
index 141df0c168..8589e82b7d 100644
--- a/usr/src/cmd/svc/configd/backend.c
+++ b/usr/src/cmd/svc/configd/backend.c
@@ -20,12 +20,20 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * sqlite is not compatible with _FILE_OFFSET_BITS=64, but we need to
+ * be able to statvfs(2) possibly large systems. This define gives us
+ * access to the transitional interfaces. See lfcompile64(5) for how
+ * _LARGEFILE64_SOURCE works.
+ */
+#define _LARGEFILE64_SOURCE
+
#include <assert.h>
#include <door.h>
#include <dirent.h>
@@ -37,6 +45,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
#include <unistd.h>
#include <zone.h>
@@ -72,9 +82,10 @@ typedef struct sqlite_backend {
pthread_t be_thread; /* thread holding lock */
struct sqlite *be_db;
const char *be_path; /* path to db */
- int be_readonly; /* backend is read-only */
+ int be_readonly; /* readonly at start, and still is */
int be_writing; /* held for writing */
backend_type_t be_type; /* type of db */
+ hrtime_t be_lastcheck; /* time of last read-only check */
backend_totals_t be_totals[2]; /* one for reading, one for writing */
} sqlite_backend_t;
@@ -119,6 +130,9 @@ int backend_do_trace = 0; /* invoke tracing callback */
int backend_print_trace = 0; /* tracing callback prints SQL */
int backend_panic_abort = 0; /* abort when panicking */
+/* interval between read-only checks while starting up */
+#define BACKEND_READONLY_CHECK_INTERVAL (2 * (hrtime_t)NANOSEC)
+
/*
* Any change to the below schema should bump the version number
*/
@@ -319,18 +333,49 @@ backend_fail_if_seen(void *arg, int columns, char **vals, char **names)
return (BACKEND_CALLBACK_ABORT);
}
+/*
+ * check to see if we can successfully start a transaction; if not, the
+ * filesystem is mounted read-only.
+ */
static int
-backend_is_readonly(struct sqlite *db, char **errp)
+backend_is_readonly(struct sqlite *db, const char *path)
{
- int r = sqlite_exec(db,
+ int r;
+ statvfs64_t stat;
+
+ if (statvfs64(path, &stat) == 0 && (stat.f_flag & ST_RDONLY))
+ return (SQLITE_READONLY);
+
+ r = sqlite_exec(db,
"BEGIN TRANSACTION; "
"UPDATE schema_version SET schema_version = schema_version; ",
- NULL, NULL, errp);
-
+ NULL, NULL, NULL);
(void) sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, NULL);
return (r);
}
+/*
+ * Check to see if the administrator has removed the writable bits on the
+ * repository file. If they have, we don't allow modifications.
+ *
+ * Since we normally run with PRIV_FILE_DAC_WRITE, we have to use a separate
+ * check.
+ */
+static int
+backend_check_perm(const char *path)
+{
+ struct stat64 stat;
+
+ if (access(path, W_OK) < 0)
+ return (SQLITE_READONLY);
+
+ if (stat64(path, &stat) == 0 &&
+ !(stat.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
+ return (SQLITE_READONLY);
+
+ return (SQLITE_OK);
+}
+
static void
backend_trace_sql(void *arg, const char *sql)
{
@@ -655,6 +700,68 @@ backend_backup_base(sqlite_backend_t *be, const char *name,
}
/*
+ * See if a backup is needed. We do a backup unless both files are
+ * byte-for-byte identical.
+ */
+static int
+backend_check_backup_needed(const char *rep_name, const char *backup_name)
+{
+ int repfd = open(rep_name, O_RDONLY);
+ int fd = open(backup_name, O_RDONLY);
+ struct stat s_rep, s_backup;
+ int c1, c2;
+
+ FILE *f_rep = NULL;
+ FILE *f_backup = NULL;
+
+ if (repfd < 0 || fd < 0)
+ goto fail;
+
+ if (fstat(repfd, &s_rep) < 0 || fstat(fd, &s_backup) < 0)
+ goto fail;
+
+ /*
+ * if they are the same file, we need to do a backup to break the
+ * hard link or symlink involved.
+ */
+ if (s_rep.st_ino == s_backup.st_ino && s_rep.st_dev == s_backup.st_dev)
+ goto fail;
+
+ if (s_rep.st_size != s_backup.st_size)
+ goto fail;
+
+ if ((f_rep = fdopen(repfd, "r")) == NULL ||
+ (f_backup = fdopen(fd, "r")) == NULL)
+ goto fail;
+
+ do {
+ c1 = getc(f_rep);
+ c2 = getc(f_backup);
+ if (c1 != c2)
+ goto fail;
+ } while (c1 != EOF);
+
+ if (!ferror(f_rep) && !ferror(f_backup)) {
+ (void) fclose(f_rep);
+ (void) fclose(f_backup);
+ (void) close(repfd);
+ (void) close(fd);
+ return (0);
+ }
+
+fail:
+ if (f_rep != NULL)
+ (void) fclose(f_rep);
+ if (f_backup != NULL)
+ (void) fclose(f_backup);
+ if (repfd >= 0)
+ (void) close(repfd);
+ if (fd >= 0)
+ (void) close(fd);
+ return (1);
+}
+
+/*
* Can return:
* _BAD_REQUEST name is not valid
* _TRUNCATED name is too long for current repository path
@@ -693,6 +800,10 @@ backend_create_backup_locked(sqlite_backend_t *be, const char *name)
if (result != REP_PROTOCOL_SUCCESS)
return (result);
+ if (!backend_check_backup_needed(be->be_path, finalpath)) {
+ return (REP_PROTOCOL_SUCCESS);
+ }
+
/*
* remember the original length, and the basename location
*/
@@ -819,6 +930,58 @@ fail:
return (result);
}
+static int
+backend_check_readonly(sqlite_backend_t *be, int writing, hrtime_t t)
+{
+ char *errp;
+ struct sqlite *new;
+ int r;
+
+ assert(be->be_readonly);
+ assert(be == bes[BACKEND_TYPE_NORMAL]);
+
+ /*
+ * If we don't *need* to be writable, only check every once in a
+ * while.
+ */
+ if (!writing) {
+ if ((uint64_t)(t - be->be_lastcheck) <
+ BACKEND_READONLY_CHECK_INTERVAL)
+ return (REP_PROTOCOL_SUCCESS);
+ be->be_lastcheck = t;
+ }
+
+ new = sqlite_open(be->be_path, 0600, &errp);
+ if (new == NULL) {
+ backend_panic("reopening %s: %s\n", be->be_path, errp);
+ /*NOTREACHED*/
+ }
+ r = backend_is_readonly(new, be->be_path);
+
+ if (r != SQLITE_OK) {
+ sqlite_close(new);
+ if (writing)
+ return (REP_PROTOCOL_FAIL_BACKEND_READONLY);
+ return (REP_PROTOCOL_SUCCESS);
+ }
+
+ /*
+ * We can write! Swap the db handles, mark ourself writable,
+ * and make a backup.
+ */
+ sqlite_close(be->be_db);
+ be->be_db = new;
+ be->be_readonly = 0;
+
+ if (backend_create_backup_locked(be, REPOSITORY_BOOT_BACKUP) !=
+ REP_PROTOCOL_SUCCESS) {
+ configd_critical(
+ "unable to create \"%s\" backup of \"%s\"\n",
+ REPOSITORY_BOOT_BACKUP, be->be_path);
+ }
+
+ return (REP_PROTOCOL_SUCCESS);
+}
/*
* If t is not BACKEND_TYPE_NORMAL, can fail with
@@ -859,41 +1022,23 @@ backend_lock(backend_type_t t, int writing, sqlite_backend_t **bep)
}
be->be_thread = pthread_self();
- if (writing && be->be_readonly) {
- char *errp;
- struct sqlite *new;
+ if (be->be_readonly) {
int r;
-
assert(t == BACKEND_TYPE_NORMAL);
- new = sqlite_open(be->be_path, 0600, &errp);
- if (new == NULL) {
- backend_panic("reopening %s: %s\n", be->be_path, errp);
- /*NOTREACHED*/
- }
- r = backend_is_readonly(new, &errp);
- if (r != SQLITE_OK) {
- free(errp);
- sqlite_close(new);
+ r = backend_check_readonly(be, writing, ts);
+ if (r != REP_PROTOCOL_SUCCESS) {
be->be_thread = 0;
(void) pthread_mutex_unlock(&be->be_lock);
- return (REP_PROTOCOL_FAIL_BACKEND_READONLY);
+ return (r);
}
+ }
- /*
- * We can write! Swap our db handles, mark ourself writable,
- * and make a backup.
- */
- sqlite_close(be->be_db);
- be->be_db = new;
- be->be_readonly = 0;
-
- if (backend_create_backup_locked(be, REPOSITORY_BOOT_BACKUP) !=
- REP_PROTOCOL_SUCCESS) {
- configd_critical(
- "unable to create \"%s\" backup of \"%s\"\n",
- REPOSITORY_BOOT_BACKUP, be->be_path);
- }
+ if (writing && t == BACKEND_TYPE_NORMAL &&
+ backend_check_perm(be->be_path) != SQLITE_OK) {
+ be->be_thread = 0;
+ (void) pthread_mutex_unlock(&be->be_lock);
+ return (REP_PROTOCOL_FAIL_BACKEND_READONLY);
}
if (backend_do_trace)
@@ -1192,7 +1337,7 @@ integrity_fail:
/*
* check if we are writable
*/
- r = backend_is_readonly(be->be_db, &errp);
+ r = backend_is_readonly(be->be_db, be->be_path);
if (r == SQLITE_BUSY || r == SQLITE_LOCKED) {
free(errp);
diff --git a/usr/src/cmd/svc/configd/client.c b/usr/src/cmd/svc/configd/client.c
index 49aed805d1..72aa30d12e 100644
--- a/usr/src/cmd/svc/configd/client.c
+++ b/usr/src/cmd/svc/configd/client.c
@@ -72,8 +72,8 @@
#pragma align 64(client_hash)
static client_bucket_t client_hash[CLIENT_HASH_SIZE];
-static uu_list_pool_t *entity_pool;
-static uu_list_pool_t *iter_pool;
+static uu_avl_pool_t *entity_pool;
+static uu_avl_pool_t *iter_pool;
static uu_list_pool_t *client_pool;
#define CLIENT_HASH(id) (&client_hash[((id) & (CLIENT_HASH_SIZE - 1))])
@@ -228,14 +228,14 @@ client_hash_init(void)
int x;
assert_nolint(offsetof(repcache_entity_t, re_id) == 0);
- entity_pool = uu_list_pool_create("repcache_entitys",
+ entity_pool = uu_avl_pool_create("repcache_entitys",
sizeof (repcache_entity_t), offsetof(repcache_entity_t, re_link),
- entity_compare, UU_LIST_POOL_DEBUG);
+ entity_compare, UU_AVL_POOL_DEBUG);
assert_nolint(offsetof(repcache_iter_t, ri_id) == 0);
- iter_pool = uu_list_pool_create("repcache_iters",
+ iter_pool = uu_avl_pool_create("repcache_iters",
sizeof (repcache_iter_t), offsetof(repcache_iter_t, ri_link),
- iter_compare, UU_LIST_POOL_DEBUG);
+ iter_compare, UU_AVL_POOL_DEBUG);
assert_nolint(offsetof(repcache_client_t, rc_id) == 0);
client_pool = uu_list_pool_create("repcache_clients",
@@ -266,12 +266,12 @@ client_alloc(void)
if (cp == NULL)
return (NULL);
- cp->rc_entity_list = uu_list_create(entity_pool, cp, UU_LIST_SORTED);
- if (cp->rc_entity_list == NULL)
+ cp->rc_entities = uu_avl_create(entity_pool, cp, 0);
+ if (cp->rc_entities == NULL)
goto fail;
- cp->rc_iter_list = uu_list_create(iter_pool, cp, UU_LIST_SORTED);
- if (cp->rc_iter_list == NULL)
+ cp->rc_iters = uu_avl_create(iter_pool, cp, 0);
+ if (cp->rc_iters == NULL)
goto fail;
uu_list_node_init(cp, &cp->rc_link, client_pool);
@@ -286,10 +286,10 @@ client_alloc(void)
return (cp);
fail:
- if (cp->rc_iter_list != NULL)
- uu_list_destroy(cp->rc_iter_list);
- if (cp->rc_entity_list != NULL)
- uu_list_destroy(cp->rc_entity_list);
+ if (cp->rc_iters != NULL)
+ uu_avl_destroy(cp->rc_iters);
+ if (cp->rc_entities != NULL)
+ uu_avl_destroy(cp->rc_entities);
uu_free(cp);
return (NULL);
}
@@ -301,10 +301,10 @@ client_free(repcache_client_t *cp)
assert(cp->rc_refcnt == 0);
assert(cp->rc_doorfd == -1);
assert(cp->rc_doorid == INVALID_DOORID);
- assert(uu_list_first(cp->rc_entity_list) == NULL);
- assert(uu_list_first(cp->rc_iter_list) == NULL);
- uu_list_destroy(cp->rc_entity_list);
- uu_list_destroy(cp->rc_iter_list);
+ assert(uu_avl_first(cp->rc_entities) == NULL);
+ assert(uu_avl_first(cp->rc_iters) == NULL);
+ uu_avl_destroy(cp->rc_entities);
+ uu_avl_destroy(cp->rc_iters);
uu_list_node_fini(cp, &cp->rc_link, client_pool);
(void) pthread_mutex_destroy(&cp->rc_lock);
uu_free(cp);
@@ -398,7 +398,7 @@ entity_alloc(repcache_client_t *cp)
{
repcache_entity_t *ep = uu_zalloc(sizeof (repcache_entity_t));
if (ep != NULL) {
- uu_list_node_init(ep, &ep->re_link, entity_pool);
+ uu_avl_node_init(ep, &ep->re_link, entity_pool);
}
return (ep);
}
@@ -406,13 +406,13 @@ entity_alloc(repcache_client_t *cp)
static void
entity_add(repcache_client_t *cp, repcache_entity_t *ep)
{
- uu_list_index_t idx;
+ uu_avl_index_t idx;
(void) pthread_mutex_lock(&cp->rc_lock);
assert(cp->rc_insert_thr == pthread_self());
- (void) uu_list_find(cp->rc_entity_list, ep, NULL, &idx);
- uu_list_insert(cp->rc_entity_list, ep, idx);
+ (void) uu_avl_find(cp->rc_entities, ep, NULL, &idx);
+ uu_avl_insert(cp->rc_entities, ep, idx);
(void) pthread_mutex_unlock(&cp->rc_lock);
}
@@ -423,7 +423,7 @@ entity_find(repcache_client_t *cp, uint32_t id)
repcache_entity_t *ep;
(void) pthread_mutex_lock(&cp->rc_lock);
- ep = uu_list_find(cp->rc_entity_list, &id, NULL, NULL);
+ ep = uu_avl_find(cp->rc_entities, &id, NULL, NULL);
if (ep != NULL) {
add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, ep);
(void) pthread_mutex_lock(&ep->re_lock);
@@ -449,8 +449,8 @@ entity_find2(repcache_client_t *cp, uint32_t id1, repcache_entity_t **out1,
return (REP_PROTOCOL_FAIL_DUPLICATE_ID);
(void) pthread_mutex_lock(&cp->rc_lock);
- e1 = uu_list_find(cp->rc_entity_list, &id1, NULL, NULL);
- e2 = uu_list_find(cp->rc_entity_list, &id2, NULL, NULL);
+ e1 = uu_avl_find(cp->rc_entities, &id1, NULL, NULL);
+ e2 = uu_avl_find(cp->rc_entities, &id2, NULL, NULL);
if (e1 == NULL || e2 == NULL) {
(void) pthread_mutex_unlock(&cp->rc_lock);
return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
@@ -496,7 +496,7 @@ entity_destroy(repcache_entity_t *entity)
rc_node_clear(&entity->re_node, 0);
(void) pthread_mutex_unlock(&entity->re_lock);
- uu_list_node_fini(entity, &entity->re_link, entity_pool);
+ uu_avl_node_fini(entity, &entity->re_link, entity_pool);
(void) pthread_mutex_destroy(&entity->re_lock);
uu_free(entity);
}
@@ -507,9 +507,9 @@ entity_remove(repcache_client_t *cp, uint32_t id)
repcache_entity_t *entity;
(void) pthread_mutex_lock(&cp->rc_lock);
- entity = uu_list_find(cp->rc_entity_list, &id, NULL, NULL);
+ entity = uu_avl_find(cp->rc_entities, &id, NULL, NULL);
if (entity != NULL)
- uu_list_remove(cp->rc_entity_list, entity);
+ uu_avl_remove(cp->rc_entities, entity);
(void) pthread_mutex_unlock(&cp->rc_lock);
if (entity != NULL)
@@ -523,7 +523,7 @@ entity_cleanup(repcache_client_t *cp)
void *cookie = NULL;
(void) pthread_mutex_lock(&cp->rc_lock);
- while ((ep = uu_list_teardown(cp->rc_entity_list, &cookie)) != NULL) {
+ while ((ep = uu_avl_teardown(cp->rc_entities, &cookie)) != NULL) {
(void) pthread_mutex_unlock(&cp->rc_lock);
entity_destroy(ep);
(void) pthread_mutex_lock(&cp->rc_lock);
@@ -538,7 +538,7 @@ iter_alloc(repcache_client_t *cp)
repcache_iter_t *iter;
iter = uu_zalloc(sizeof (repcache_iter_t));
if (iter != NULL)
- uu_list_node_init(iter, &iter->ri_link, iter_pool);
+ uu_avl_node_init(iter, &iter->ri_link, iter_pool);
return (iter);
}
@@ -550,8 +550,8 @@ iter_add(repcache_client_t *cp, repcache_iter_t *iter)
(void) pthread_mutex_lock(&cp->rc_lock);
assert(cp->rc_insert_thr == pthread_self());
- (void) uu_list_find(cp->rc_iter_list, iter, NULL, &idx);
- uu_list_insert(cp->rc_iter_list, iter, idx);
+ (void) uu_avl_find(cp->rc_iters, iter, NULL, &idx);
+ uu_avl_insert(cp->rc_iters, iter, idx);
(void) pthread_mutex_unlock(&cp->rc_lock);
}
@@ -563,7 +563,7 @@ iter_find(repcache_client_t *cp, uint32_t id)
(void) pthread_mutex_lock(&cp->rc_lock);
- iter = uu_list_find(cp->rc_iter_list, &id, NULL, NULL);
+ iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL);
if (iter != NULL) {
add_log_ptr(get_log(), RC_PTR_TYPE_ITER, id, iter);
(void) pthread_mutex_lock(&iter->ri_lock);
@@ -586,8 +586,8 @@ iter_find_w_entity(repcache_client_t *cp, uint32_t iter_id,
request_log_entry_t *rlp;
(void) pthread_mutex_lock(&cp->rc_lock);
- iter = uu_list_find(cp->rc_iter_list, &iter_id, NULL, NULL);
- ep = uu_list_find(cp->rc_entity_list, &entity_id, NULL, NULL);
+ iter = uu_avl_find(cp->rc_iters, &iter_id, NULL, NULL);
+ ep = uu_avl_find(cp->rc_entities, &entity_id, NULL, NULL);
assert(iter == NULL || !MUTEX_HELD(&iter->ri_lock));
assert(ep == NULL || !MUTEX_HELD(&ep->re_lock));
@@ -626,7 +626,7 @@ iter_destroy(repcache_iter_t *iter)
rc_iter_destroy(&iter->ri_iter);
(void) pthread_mutex_unlock(&iter->ri_lock);
- uu_list_node_fini(iter, &iter->ri_link, iter_pool);
+ uu_avl_node_fini(iter, &iter->ri_link, iter_pool);
(void) pthread_mutex_destroy(&iter->ri_lock);
uu_free(iter);
}
@@ -637,9 +637,9 @@ iter_remove(repcache_client_t *cp, uint32_t id)
repcache_iter_t *iter;
(void) pthread_mutex_lock(&cp->rc_lock);
- iter = uu_list_find(cp->rc_iter_list, &id, NULL, NULL);
+ iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL);
if (iter != NULL)
- uu_list_remove(cp->rc_iter_list, iter);
+ uu_avl_remove(cp->rc_iters, iter);
(void) pthread_mutex_unlock(&cp->rc_lock);
if (iter != NULL)
@@ -653,7 +653,7 @@ iter_cleanup(repcache_client_t *cp)
void *cookie = NULL;
(void) pthread_mutex_lock(&cp->rc_lock);
- while ((iter = uu_list_teardown(cp->rc_iter_list, &cookie)) != NULL) {
+ while ((iter = uu_avl_teardown(cp->rc_iters, &cookie)) != NULL) {
(void) pthread_mutex_unlock(&cp->rc_lock);
iter_destroy(iter);
(void) pthread_mutex_lock(&cp->rc_lock);
diff --git a/usr/src/cmd/svc/configd/configd.c b/usr/src/cmd/svc/configd/configd.c
index 32f6f318c6..5632735834 100644
--- a/usr/src/cmd/svc/configd/configd.c
+++ b/usr/src/cmd/svc/configd/configd.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,6 +30,7 @@
#include <door.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <priv.h>
#include <procfs.h>
#include <pthread.h>
@@ -162,7 +163,8 @@ thread_exiting(void *arg)
{
thread_info_t *ti = arg;
- log_enter(&ti->ti_log);
+ if (ti != NULL)
+ log_enter(&ti->ti_log);
(void) pthread_mutex_lock(&thread_lock);
if (ti != NULL) {
@@ -471,6 +473,23 @@ daemonize_ready(void)
(void) close(pipe_fd);
}
+const char *
+regularize_path(const char *dir, const char *base, char *tmpbuf)
+{
+ if (base == NULL)
+ return (NULL);
+ if (base[0] == '/')
+ return (base);
+
+ if (snprintf(tmpbuf, PATH_MAX, "%s/%s", dir, base) >= PATH_MAX) {
+ (void) fprintf(stderr, "svc.configd: %s/%s: path too long\n",
+ dir, base);
+ exit(CONFIGD_EXIT_BAD_ARGS);
+ }
+
+ return (tmpbuf);
+}
+
int
main(int argc, char *argv[])
{
@@ -485,6 +504,12 @@ main(int argc, char *argv[])
int c;
int ret;
int fd;
+
+ char curdir[PATH_MAX];
+ char dbtmp[PATH_MAX];
+ char npdbtmp[PATH_MAX];
+ char doortmp[PATH_MAX];
+
const char *dbpath = NULL;
const char *npdbpath = NULL;
const char *doorpath = REPOSITORY_DOOR_NAME;
@@ -495,13 +520,20 @@ main(int argc, char *argv[])
closefrom(3); /* get rid of extraneous fds */
+ if (getcwd(curdir, sizeof (curdir)) == NULL) {
+ (void) fprintf(stderr,
+ "%s: unable to get current directory: %s\n",
+ argv[0], strerror(errno));
+ exit(CONFIGD_EXIT_INIT_FAILED);
+ }
+
while ((c = getopt(argc, argv, "Dnpd:r:t:")) != -1) {
switch (c) {
case 'n':
daemonize = 0;
break;
case 'd':
- doorpath = optarg;
+ doorpath = regularize_path(curdir, optarg, doortmp);
is_main_repository = 0;
have_npdb = 0; /* default to no non-persist */
break;
@@ -527,11 +559,11 @@ main(int argc, char *argv[])
privileged_psinfo_fd = fd;
break;
case 'r':
- dbpath = optarg;
+ dbpath = regularize_path(curdir, optarg, dbtmp);
is_main_repository = 0;
break;
case 't':
- npdbpath = optarg;
+ npdbpath = regularize_path(curdir, optarg, npdbtmp);
is_main_repository = 0;
break;
default:
diff --git a/usr/src/cmd/svc/configd/configd.h b/usr/src/cmd/svc/configd/configd.h
index f00bb6467b..7d01a9005e 100644
--- a/usr/src/cmd/svc/configd/configd.h
+++ b/usr/src/cmd/svc/configd/configd.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -404,7 +404,7 @@ enum repcache_txstate {
typedef struct repcache_entity {
uint32_t re_id;
- uu_list_node_t re_link;
+ uu_avl_node_t re_link;
uint32_t re_changeid;
pthread_mutex_t re_lock;
@@ -415,7 +415,7 @@ typedef struct repcache_entity {
typedef struct repcache_iter {
uint32_t ri_id;
- uu_list_node_t ri_link;
+ uu_avl_node_t ri_link;
uint32_t ri_type; /* result type */
@@ -452,10 +452,10 @@ typedef struct repcache_client {
rc_node_ptr_t rc_notify_ptr;
/*
- * register lists, protected by rc_lock
+ * register sets, protected by rc_lock
*/
- uu_list_t *rc_entity_list; /* entities */
- uu_list_t *rc_iter_list; /* iters */
+ uu_avl_t *rc_entities;
+ uu_avl_t *rc_iters;
/*
* Variables, protected by rc_lock
@@ -660,7 +660,7 @@ int object_create_pg(rc_node_t *, uint32_t, const char *, const char *,
int object_delete(rc_node_t *);
void object_free_values(const char *, uint32_t, size_t, size_t);
-int object_fill_snapshot(rc_snapshot_t *sp);
+int object_fill_snapshot(rc_snapshot_t *);
int object_snapshot_take_new(rc_node_t *, const char *, const char *,
const char *, rc_node_t **);
diff --git a/usr/src/cmd/svc/configd/file_object.c b/usr/src/cmd/svc/configd/file_object.c
index 52bff4858f..b4f177f1eb 100644
--- a/usr/src/cmd/svc/configd/file_object.c
+++ b/usr/src/cmd/svc/configd/file_object.c
@@ -94,6 +94,14 @@ typedef struct object_info {
int (*obj_delete_start)(rc_node_t *, delete_info_t *);
} object_info_t;
+static void
+string_to_id(const char *str, uint32_t *output, const char *fieldname)
+{
+ if (uu_strtouint(str, output, sizeof (*output), 0, 0, 0) == -1)
+ backend_panic("invalid integer \"%s\" in field \"%s\"",
+ str, fieldname);
+}
+
#define NUM_NEEDED 50
static int
@@ -191,10 +199,8 @@ push_delete_callback(void *data, int columns, char **vals, char **names)
assert(columns == 2);
- if (uu_strtouint(id_str, &id, sizeof (id), 0, 0, 0) == -1)
- backend_panic("invalid integer in database");
- if (uu_strtouint(gen_str, &gen, sizeof (gen), 0, 0, 0) == -1)
- backend_panic("invalid integer in database");
+ string_to_id(id_str, &id, "id");
+ string_to_id(gen_str, &gen, "gen_id");
info->dci_result = delete_stack_push(info->dci_dip, info->dci_be,
info->dci_cb, id, gen);
@@ -536,8 +542,7 @@ fill_child_callback(void *data, int columns, char **vals, char **names)
cur = *vals++;
columns--;
- if (uu_strtouint(cur, &main_id, sizeof (main_id), 0, 0, 0) == -1)
- backend_panic("invalid integer in database");
+ string_to_id(cur, &main_id, "id");
lp->rl_main_id = main_id;
@@ -572,9 +577,9 @@ fill_snapshot_callback(void *data, int columns, char **vals, char **names)
columns--;
snap = *vals++;
columns--;
- if (uu_strtouint(cur, &main_id, sizeof (main_id), 0, 0, 0) == -1 ||
- uu_strtouint(snap, &snap_id, sizeof (snap_id), 0, 0, 0) == -1)
- backend_panic("invalid integer in database");
+
+ string_to_id(cur, &main_id, "lnk_id");
+ string_to_id(snap, &snap_id, "lnk_snap_id");
lp->rl_main_id = main_id;
@@ -609,23 +614,20 @@ fill_pg_callback(void *data, int columns, char **vals, char **names)
cur = *vals++; /* pg_id */
columns--;
- if (uu_strtouint(cur, &main_id, sizeof (main_id), 0, 0, 0) == -1)
- backend_panic("invalid integer in database");
+ string_to_id(cur, &main_id, "pg_id");
lp->rl_main_id = main_id;
cur = *vals++; /* pg_gen_id */
columns--;
- if (uu_strtouint(cur, &gen_id, sizeof (gen_id), 0, 0, 0) == -1)
- backend_panic("invalid integer in database");
+ string_to_id(cur, &gen_id, "pg_gen_id");
type = *vals++; /* pg_type */
columns--;
cur = *vals++; /* pg_flags */
columns--;
- if (uu_strtouint(cur, &flags, sizeof (flags), 0, 0, 0) == -1)
- backend_panic("invalid integer in database");
+ string_to_id(cur, &flags, "pg_flags");
if ((newnode = rc_node_alloc()) == NULL)
return (BACKEND_CALLBACK_ABORT);
@@ -723,8 +725,7 @@ fill_property_callback(void *data, int columns, char **vals, char **names)
name = *vals++;
cur = *vals++;
- if (uu_strtouint(cur, &main_id, sizeof (main_id), 0, 0, 0) == -1)
- backend_panic("invalid integer in database");
+ string_to_id(cur, &main_id, "lnk_prop_id");
cur = *vals++;
assert(('a' <= cur[0] && 'z' >= cur[0]) ||
@@ -1764,17 +1765,12 @@ fill_snapshot_cb(void *data, int columns, char **vals, char **names)
lvl->rsl_next = sp->rs_levels;
sp->rs_levels = lvl;
- if (uu_strtouint(num, &lvl->rsl_level_num,
- sizeof (lvl->rsl_level_num), 0, 0, 0) == -1 ||
- uu_strtouint(id, &lvl->rsl_level_id,
- sizeof (lvl->rsl_level_id), 0, 0, 0) == -1 ||
- uu_strtouint(service_id, &lvl->rsl_service_id,
- sizeof (lvl->rsl_level_num), 0, 0, 0) == -1 ||
- (instance_id != NULL &&
- uu_strtouint(instance_id, &lvl->rsl_instance_id,
- sizeof (lvl->rsl_instance_id), 0, 0, 0) == -1)) {
- backend_panic("invalid integer in database");
- }
+ string_to_id(num, &lvl->rsl_level_num, "snap_level_num");
+ string_to_id(id, &lvl->rsl_level_id, "snap_level_id");
+ string_to_id(service_id, &lvl->rsl_service_id, "snap_level_service_id");
+ if (instance_id != NULL)
+ string_to_id(instance_id, &lvl->rsl_instance_id,
+ "snap_level_instance_id");
lvl->rsl_scope = (const char *)"localhost";
lvl->rsl_service = strdup(service);
@@ -1837,6 +1833,226 @@ object_fill_snapshot(rc_snapshot_t *sp)
return (result);
}
+/*
+ * This represents a property group in a snapshot.
+ */
+typedef struct check_snapshot_elem {
+ uint32_t cse_parent;
+ uint32_t cse_pg_id;
+ uint32_t cse_pg_gen;
+ char cse_seen;
+} check_snapshot_elem_t;
+
+#define CSI_MAX_PARENTS COMPOSITION_DEPTH
+typedef struct check_snapshot_info {
+ size_t csi_count;
+ size_t csi_array_size;
+ check_snapshot_elem_t *csi_array;
+ size_t csi_nparents;
+ uint32_t csi_parent_ids[CSI_MAX_PARENTS];
+} check_snapshot_info_t;
+
+/*ARGSUSED*/
+static int
+check_snapshot_fill_cb(void *data, int columns, char **vals, char **names)
+{
+ check_snapshot_info_t *csip = data;
+ check_snapshot_elem_t *cur;
+ const char *parent;
+ const char *pg_id;
+ const char *pg_gen_id;
+
+ if (columns == 1) {
+ uint32_t *target;
+
+ if (csip->csi_nparents >= CSI_MAX_PARENTS)
+ backend_panic("snaplevel table has too many elements");
+
+ target = &csip->csi_parent_ids[csip->csi_nparents++];
+ string_to_id(vals[0], target, "snap_level_*_id");
+
+ return (BACKEND_CALLBACK_CONTINUE);
+ }
+
+ assert(columns == 3);
+
+ parent = vals[0];
+ pg_id = vals[1];
+ pg_gen_id = vals[2];
+
+ if (csip->csi_count == csip->csi_array_size) {
+ size_t newsz = (csip->csi_array_size > 0) ?
+ csip->csi_array_size * 2 : 8;
+ check_snapshot_elem_t *new = uu_zalloc(newsz * sizeof (*new));
+
+ if (new == NULL)
+ return (BACKEND_CALLBACK_ABORT);
+
+ (void) memcpy(new, csip->csi_array,
+ sizeof (*new) * csip->csi_array_size);
+ uu_free(csip->csi_array);
+ csip->csi_array = new;
+ csip->csi_array_size = newsz;
+ }
+
+ cur = &csip->csi_array[csip->csi_count++];
+
+ string_to_id(parent, &cur->cse_parent, "snap_level_*_id");
+ string_to_id(pg_id, &cur->cse_pg_id, "snaplvl_pg_id");
+ string_to_id(pg_gen_id, &cur->cse_pg_gen, "snaplvl_gen_id");
+ cur->cse_seen = 0;
+
+ return (BACKEND_CALLBACK_CONTINUE);
+}
+
+static int
+check_snapshot_elem_cmp(const void *lhs_arg, const void *rhs_arg)
+{
+ const check_snapshot_elem_t *lhs = lhs_arg;
+ const check_snapshot_elem_t *rhs = rhs_arg;
+
+ if (lhs->cse_parent < rhs->cse_parent)
+ return (-1);
+ if (lhs->cse_parent > rhs->cse_parent)
+ return (1);
+
+ if (lhs->cse_pg_id < rhs->cse_pg_id)
+ return (-1);
+ if (lhs->cse_pg_id > rhs->cse_pg_id)
+ return (1);
+
+ if (lhs->cse_pg_gen < rhs->cse_pg_gen)
+ return (-1);
+ if (lhs->cse_pg_gen > rhs->cse_pg_gen)
+ return (1);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+check_snapshot_check_cb(void *data, int columns, char **vals, char **names)
+{
+ check_snapshot_info_t *csip = data;
+ check_snapshot_elem_t elem;
+ check_snapshot_elem_t *cur;
+
+ const char *parent = vals[0];
+ const char *pg_id = vals[1];
+ const char *pg_gen_id = vals[2];
+
+ assert(columns == 3);
+
+ string_to_id(parent, &elem.cse_parent, "snap_level_*_id");
+ string_to_id(pg_id, &elem.cse_pg_id, "snaplvl_pg_id");
+ string_to_id(pg_gen_id, &elem.cse_pg_gen, "snaplvl_gen_id");
+
+ if ((cur = bsearch(&elem, csip->csi_array, csip->csi_count,
+ sizeof (*csip->csi_array), check_snapshot_elem_cmp)) == NULL)
+ return (BACKEND_CALLBACK_ABORT);
+
+ if (cur->cse_seen)
+ backend_panic("duplicate property group reported");
+ cur->cse_seen = 1;
+ return (BACKEND_CALLBACK_CONTINUE);
+}
+
+/*
+ * Check that a snapshot matches up with the latest in the repository.
+ * Returns:
+ * REP_PROTOCOL_SUCCESS if it is up-to-date,
+ * REP_PROTOCOL_DONE if it is out-of-date, or
+ * REP_PROTOCOL_FAIL_NO_RESOURCES if we ran out of memory.
+ */
+static int
+object_check_snapshot(uint32_t snap_id)
+{
+ check_snapshot_info_t csi;
+ backend_query_t *q;
+ int result;
+ size_t idx;
+
+ /* if the snapshot has never been taken, it must be out of date. */
+ if (snap_id == 0)
+ return (REP_PROTOCOL_DONE);
+
+ (void) memset(&csi, '\0', sizeof (csi));
+
+ q = backend_query_alloc();
+ backend_query_add(q,
+ "SELECT\n"
+ " CASE snap_level_instance_id\n"
+ " WHEN 0 THEN snap_level_service_id\n"
+ " ELSE snap_level_instance_id\n"
+ " END\n"
+ "FROM snaplevel_tbl\n"
+ "WHERE snap_id = %d;\n"
+ "\n"
+ "SELECT\n"
+ " CASE snap_level_instance_id\n"
+ " WHEN 0 THEN snap_level_service_id\n"
+ " ELSE snap_level_instance_id\n"
+ " END,\n"
+ " snaplvl_pg_id,\n"
+ " snaplvl_gen_id\n"
+ "FROM snaplevel_tbl, snaplevel_lnk_tbl\n"
+ "WHERE\n"
+ " (snaplvl_level_id = snap_level_id AND\n"
+ " snap_id = %d);",
+ snap_id, snap_id);
+
+ result = backend_run(BACKEND_TYPE_NORMAL, q, check_snapshot_fill_cb,
+ &csi);
+ if (result == REP_PROTOCOL_DONE)
+ result = REP_PROTOCOL_FAIL_NO_RESOURCES;
+ backend_query_free(q);
+
+ if (result != REP_PROTOCOL_SUCCESS)
+ goto fail;
+
+ if (csi.csi_count > 0) {
+ qsort(csi.csi_array, csi.csi_count, sizeof (*csi.csi_array),
+ check_snapshot_elem_cmp);
+ }
+
+#if COMPOSITION_DEPTH == 2
+ if (csi.csi_nparents != COMPOSITION_DEPTH) {
+ result = REP_PROTOCOL_DONE;
+ goto fail;
+ }
+
+ q = backend_query_alloc();
+ backend_query_add(q,
+ "SELECT "
+ " pg_parent_id, pg_id, pg_gen_id "
+ "FROM "
+ " pg_tbl "
+ "WHERE (pg_parent_id = %d OR pg_parent_id = %d)",
+ csi.csi_parent_ids[0], csi.csi_parent_ids[1]);
+
+ result = backend_run(BACKEND_TYPE_NORMAL, q, check_snapshot_check_cb,
+ &csi);
+#else
+#error This code must be updated
+#endif
+ /*
+ * To succeed, the callback must not have aborted, and we must have
+ * found all of the items.
+ */
+ if (result == REP_PROTOCOL_SUCCESS) {
+ for (idx = 0; idx < csi.csi_count; idx++) {
+ if (csi.csi_array[idx].cse_seen == 0) {
+ result = REP_PROTOCOL_DONE;
+ goto fail;
+ }
+ }
+ }
+
+fail:
+ uu_free(csi.csi_array);
+ return (result);
+}
+
/*ARGSUSED*/
static int
object_copy_string(void *data_arg, int columns, char **vals, char **names)
@@ -2115,6 +2331,10 @@ object_snapshot_attach(rc_node_lookup_t *snapi, uint32_t *snapid_ptr,
return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
if (takesnap) {
+ /* first, check that we're actually out of date */
+ if (object_check_snapshot(snapid) == REP_PROTOCOL_SUCCESS)
+ return (REP_PROTOCOL_SUCCESS);
+
result = object_snapshot_do_take(instid, NULL,
svcid, NULL, &tx, &snapid);
if (result != REP_PROTOCOL_SUCCESS)
diff --git a/usr/src/cmd/svc/configd/restore_repository.sh b/usr/src/cmd/svc/configd/restore_repository.sh
index 08e916b0f9..8ba38ce70f 100644
--- a/usr/src/cmd/svc/configd/restore_repository.sh
+++ b/usr/src/cmd/svc/configd/restore_repository.sh
@@ -21,28 +21,24 @@
# CDDL HEADER END
#
#
-# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
PATH=/sbin:/usr/bin:/usr/sbin
+LC_ALL=C
+export PATH LC_ALL
. /lib/svc/share/smf_include.sh
. /lib/svc/share/fs_include.sh
-echo >&2 "
-Repository Restore utility
-
-See http://sun.com/msg/SMF-8000-MY for more information on the use of
-this script to restore backup copies of the smf(5) repository.
-
-If there are any problems which need human intervention, this script will
-give instructions and then exit back to your shell."
-
usage()
{
echo "usage: $0 [-r rootdir]" >&2
+ echo "
+See http://sun.com/msg/SMF-8000-MY for more information on the use of
+this script."
exit 2;
}
@@ -79,6 +75,23 @@ if [ $OPTIND -le $# ]; then
usage
fi
+#
+# Note that the below test is carefully constructed to fail *open*; if
+# anything goes wrong, it will drive onward.
+#
+if [ -x /usr/bin/id -a -x /usr/bin/grep ] &&
+ /usr/bin/id 2>/dev/null | /usr/bin/grep -v '^[^=]*=0(' >/dev/null 2>&1; then
+ echo "$0: may only be invoked by root" >&2
+ exit 2
+fi
+
+echo >&2 "
+See http://sun.com/msg/SMF-8000-MY for more information on the use of
+this script to restore backup copies of the smf(5) repository.
+
+If there are any problems which need human intervention, this script will
+give instructions and then exit back to your shell."
+
if [ "$myroot" -eq / ]; then
system="system"
[ "`/sbin/zonename`" != global ] && system="zone"
@@ -99,6 +112,7 @@ rootro=false
if [ ! -x /usr/bin/pgrep ]; then
nouser=true
fi
+
if [ ! -w "$myroot" ]; then
rootro=true
fi
@@ -142,7 +156,8 @@ if [ -z "$oldreps" ]; then
cat >&2 <<EOF
There are no available backups of $myroot$repositorydir/$repository.db.
The only available repository is "-seed-". Note that restoring the seed
-will lose all customizations, and XXX other issues?
+will lose all customizations, including those made by the system during
+the installation and/or upgrade process.
EOF
prompt="Enter -seed- to restore from the seed, or -quit- to exit: \c"
@@ -160,13 +175,17 @@ the repository after system boot. Backups beginning with "manifest_import"
are made after svc:/system/manifest-import:default finishes its processing.
The time of backup is given in YYYYMMDD_HHMMSS format.
-Please enter one of:
- 1) boot, for the most recent post-boot backup
- 2) manifest_import, for the most recent manifest_import backup.
- 3) a specific backup repository from the above list
- 4) -seed-, the initial starting repository. (All customizations
- will be lost.)
- 5) -quit-, to cancel.
+Please enter either a specific backup repository from the above list to
+restore it, or one of the following choices:
+
+ CHOICE ACTION
+ ---------------- ----------------------------------------------
+ boot restore the most recent post-boot backup
+ manifest_import restore the most recent manifest_import backup
+ -seed- restore the initial starting repository (All
+ customizations will be lost, including those
+ made by the install/upgrade process.)
+ -quit- cancel script and quit
EOF
prompt="Enter response [boot]: \c"
diff --git a/usr/src/lib/libscf/common/lowlevel.c b/usr/src/lib/libscf/common/lowlevel.c
index ae9108ab95..16c375d5e2 100644
--- a/usr/src/lib/libscf/common/lowlevel.c
+++ b/usr/src/lib/libscf/common/lowlevel.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -177,7 +177,35 @@ transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
ret = strcmp(l_prop, r_prop);
if (ret > 0)
return (1);
- else if (ret < 0)
+ if (ret < 0)
+ return (-1);
+ return (0);
+}
+
+static int
+datael_compare(const void *l_arg, const void *r_arg, void *private)
+{
+ uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
+ uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
+ *(uint32_t *)private;
+
+ if (l_id > r_id)
+ return (1);
+ if (l_id < r_id)
+ return (-1);
+ return (0);
+}
+
+static int
+iter_compare(const void *l_arg, const void *r_arg, void *private)
+{
+ uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
+ uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
+ *(uint32_t *)private;
+
+ if (l_id > r_id)
+ return (1);
+ if (l_id < r_id)
return (-1);
return (0);
}
@@ -209,11 +237,11 @@ lowlevel_init(void)
datael_pool = uu_list_pool_create("SUNW,libscf_datael",
sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
- NULL, UU_LIST_POOL_DEBUG);
+ datael_compare, UU_LIST_POOL_DEBUG);
iter_pool = uu_list_pool_create("SUNW,libscf_iter",
sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
- NULL, UU_LIST_POOL_DEBUG);
+ iter_compare, UU_LIST_POOL_DEBUG);
assert_nolint(offsetof(scf_transaction_entry_t,
entry_property) == 0);
@@ -506,14 +534,22 @@ handle_is_bound(scf_handle_t *h)
}
static int
-handle_has_server(scf_handle_t *h)
+handle_has_server_locked(scf_handle_t *h)
{
door_info_t i;
+ assert(MUTEX_HELD(&h->rh_lock));
+
+ return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
+ i.di_target != -1);
+}
+
+static int
+handle_has_server(scf_handle_t *h)
+{
int ret;
(void) pthread_mutex_lock(&h->rh_lock);
- ret = (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
- i.di_target != -1);
+ ret = handle_has_server_locked(h);
(void) pthread_mutex_unlock(&h->rh_lock);
return (ret);
@@ -1267,24 +1303,91 @@ scf_myname(scf_handle_t *h, char *out, size_t len)
}
static uint32_t
-handle_alloc_entityid(scf_handle_t *handle)
+handle_alloc_entityid(scf_handle_t *h)
{
- assert(MUTEX_HELD(&handle->rh_lock));
- return (++handle->rh_nextentity);
+ uint32_t nextid;
+
+ assert(MUTEX_HELD(&h->rh_lock));
+
+ if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX)
+ return (0); /* no ids available */
+
+ /*
+ * The following loop assumes that there are not a huge number of
+ * outstanding entities when we've wrapped. If that ends up not
+ * being the case, the O(N^2) nature of this search will hurt a lot,
+ * and the data structure should be switched to an AVL tree.
+ */
+ nextid = h->rh_nextentity + 1;
+ for (;;) {
+ scf_datael_t *cur;
+
+ if (nextid == 0) {
+ nextid++;
+ h->rh_flags |= HANDLE_WRAPPED_ENTITY;
+ }
+ if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
+ break;
+
+ cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL);
+ if (cur == NULL)
+ break; /* not in use */
+
+ if (nextid == h->rh_nextentity)
+ return (0); /* wrapped around; no ids available */
+ nextid++;
+ }
+
+ h->rh_nextentity = nextid;
+ return (nextid);
}
static uint32_t
-handle_alloc_iterid(scf_handle_t *handle)
+handle_alloc_iterid(scf_handle_t *h)
{
- assert(MUTEX_HELD(&handle->rh_lock));
- return (++handle->rh_nextiter);
+ uint32_t nextid;
+
+ assert(MUTEX_HELD(&h->rh_lock));
+
+ if (uu_list_numnodes(h->rh_iters) == UINT32_MAX)
+ return (0); /* no ids available */
+
+ /* see the comment in handle_alloc_entityid */
+ nextid = h->rh_nextiter + 1;
+ for (;;) {
+ scf_iter_t *cur;
+
+ if (nextid == 0) {
+ nextid++;
+ h->rh_flags |= HANDLE_WRAPPED_ITER;
+ }
+ if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
+ break; /* not yet wrapped */
+
+ cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL);
+ if (cur == NULL)
+ break; /* not in use */
+
+ if (nextid == h->rh_nextiter)
+ return (0); /* wrapped around; no ids available */
+ nextid++;
+ }
+
+ h->rh_nextiter = nextid;
+ return (nextid);
}
static uint32_t
-handle_alloc_changeid(scf_handle_t *handle)
+handle_next_changeid(scf_handle_t *handle)
{
+ uint32_t nextid;
+
assert(MUTEX_HELD(&handle->rh_lock));
- return (++handle->rh_nextchangeid);
+
+ nextid = ++handle->rh_nextchangeid;
+ if (nextid == 0)
+ nextid = ++handle->rh_nextchangeid;
+ return (nextid);
}
/*
@@ -1320,6 +1423,11 @@ datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
}
dp->rd_entity = handle_alloc_entityid(h);
+ if (dp->rd_entity == 0) {
+ (void) pthread_mutex_unlock(&h->rh_lock);
+ uu_list_node_fini(dp, &dp->rd_node, datael_pool);
+ return (scf_set_error(SCF_ERROR_NO_MEMORY));
+ }
ret = datael_attach(dp);
if (ret == 0) {
@@ -1767,7 +1875,7 @@ datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
request.rpr_childid = cp->rd_entity;
datael_finish_reset(dp);
- request.rpr_changeid = handle_alloc_changeid(h);
+ request.rpr_changeid = handle_next_changeid(h);
r = make_door_call(h, &request, sizeof (request),
&response, sizeof (response));
(void) pthread_mutex_unlock(&h->rh_lock);
@@ -1831,7 +1939,7 @@ datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
datael_finish_reset(dp);
datael_finish_reset(cp);
- request.rpr_changeid = handle_alloc_changeid(h);
+ request.rpr_changeid = handle_next_changeid(h);
r = make_door_call(h, &request, sizeof (request),
&response, sizeof (response));
(void) pthread_mutex_unlock(&h->rh_lock);
@@ -1867,7 +1975,7 @@ datael_delete(const scf_datael_t *dp)
request.rpr_entityid = dp->rd_entity;
datael_finish_reset(dp);
- request.rpr_changeid = handle_alloc_changeid(h);
+ request.rpr_changeid = handle_next_changeid(h);
r = make_door_call(h, &request, sizeof (request),
&response, sizeof (response));
(void) pthread_mutex_unlock(&h->rh_lock);
@@ -1913,6 +2021,12 @@ scf_iter_create(scf_handle_t *h)
(void) pthread_mutex_lock(&h->rh_lock);
iter->iter_id = handle_alloc_iterid(h);
+ if (iter->iter_id == 0) {
+ (void) pthread_mutex_unlock(&h->rh_lock);
+ uu_list_node_fini(iter, &iter->iter_node, iter_pool);
+ (void) scf_set_error(SCF_ERROR_NO_MEMORY);
+ return (NULL);
+ }
if (iter_attach(iter) == -1) {
uu_list_node_fini(iter, &iter->iter_node, iter_pool);
(void) pthread_mutex_unlock(&h->rh_lock);
@@ -2030,7 +2144,7 @@ scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
return (scf_set_error(SCF_ERROR_NOT_BOUND));
}
- if (!handle_has_server(h)) {
+ if (!handle_has_server_locked(h)) {
(void) pthread_mutex_unlock(&h->rh_lock);
return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
}
@@ -2894,7 +3008,7 @@ datael_update(scf_datael_t *dp)
request.rpr_entityid = dp->rd_entity;
datael_finish_reset(dp);
- request.rpr_changeid = handle_alloc_changeid(h);
+ request.rpr_changeid = handle_next_changeid(h);
r = make_door_call(h, &request, sizeof (request),
&response, sizeof (response));
@@ -6606,7 +6720,7 @@ _scf_request_backup(scf_handle_t *h, const char *name)
(void) pthread_mutex_lock(&h->rh_lock);
request.rpr_request = REP_PROTOCOL_BACKUP;
- request.rpr_changeid = handle_alloc_changeid(h);
+ request.rpr_changeid = handle_next_changeid(h);
r = make_door_call(h, &request, sizeof (request),
&response, sizeof (response));
diff --git a/usr/src/lib/libscf/common/lowlevel_impl.h b/usr/src/lib/libscf/common/lowlevel_impl.h
index 5137eaf8ad..a3bc40aed9 100644
--- a/usr/src/lib/libscf/common/lowlevel_impl.h
+++ b/usr/src/lib/libscf/common/lowlevel_impl.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -101,8 +101,10 @@ struct scf_handle {
scf_property_t *rh_property;
scf_value_t *rh_value;
};
-#define HANDLE_DEAD 0x0001
-#define HANDLE_UNREFED 0x0002
+#define HANDLE_DEAD 0x0001
+#define HANDLE_UNREFED 0x0002
+#define HANDLE_WRAPPED_ENTITY 0x0004
+#define HANDLE_WRAPPED_ITER 0x0008
#define RH_HOLD_ITER 0x0001
#define RH_HOLD_SCOPE 0x0002
diff --git a/usr/src/lib/libuutil/common/libuutil_impl.h b/usr/src/lib/libuutil/common/libuutil_impl.h
index 101671095a..9466e59745 100644
--- a/usr/src/lib/libuutil/common/libuutil_impl.h
+++ b/usr/src/lib/libuutil/common/libuutil_impl.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,6 +33,7 @@
#include <pthread.h>
#include <sys/avl_impl.h>
+#include <sys/byteorder.h>
#ifdef __cplusplus
extern "C" {
@@ -52,6 +53,21 @@ struct uu_dprintf {
};
/*
+ * For debugging purposes, libuutil keeps around linked lists of all uu_lists
+ * and uu_avls, along with pointers to their parents. These can cause false
+ * negatives when looking for memory leaks, so we encode the pointers by
+ * storing them with swapped endianness; this is not perfect, but it's about
+ * the best we can do without wasting a lot of space.
+ */
+#ifdef _LP64
+#define UU_PTR_ENCODE(ptr) BSWAP_64((uintptr_t)(void *)(ptr))
+#else
+#define UU_PTR_ENCODE(ptr) BSWAP_32((uintptr_t)(void *)(ptr))
+#endif
+
+#define UU_PTR_DECODE(ptr) ((void *)UU_PTR_ENCODE(ptr))
+
+/*
* uu_list structures
*/
typedef struct uu_list_node_impl {
@@ -70,11 +86,11 @@ struct uu_list_walk {
};
struct uu_list {
- uu_list_t *ul_next;
- uu_list_t *ul_prev;
+ uintptr_t ul_next_enc;
+ uintptr_t ul_prev_enc;
uu_list_pool_t *ul_pool;
- void *ul_parent;
+ uintptr_t ul_parent_enc; /* encoded parent pointer */
size_t ul_offset;
size_t ul_numnodes;
uint8_t ul_debug;
@@ -85,6 +101,8 @@ struct uu_list {
uu_list_walk_t ul_null_walk; /* for robust walkers */
};
+#define UU_LIST_PTR(ptr) ((uu_list_t *)UU_PTR_DECODE(ptr))
+
#define UU_LIST_POOL_MAXNAME 64
struct uu_list_pool {
@@ -117,11 +135,11 @@ struct uu_avl_walk {
};
struct uu_avl {
- uu_avl_t *ua_next;
- uu_avl_t *ua_prev;
+ uintptr_t ua_next_enc;
+ uintptr_t ua_prev_enc;
uu_avl_pool_t *ua_pool;
- void *ua_parent;
+ uintptr_t ua_parent_enc;
uint8_t ua_debug;
uint8_t ua_index; /* mark for uu_avl_index_ts */
@@ -129,6 +147,8 @@ struct uu_avl {
uu_avl_walk_t ua_null_walk;
};
+#define UU_AVL_PTR(x) ((uu_avl_t *)UU_PTR_DECODE(x))
+
#define UU_AVL_POOL_MAXNAME 64
struct uu_avl_pool {
diff --git a/usr/src/lib/libuutil/common/uu_avl.c b/usr/src/lib/libuutil/common/uu_avl.c
index 8538fcebbc..504b413a3a 100644
--- a/usr/src/lib/libuutil/common/uu_avl.c
+++ b/usr/src/lib/libuutil/common/uu_avl.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -98,8 +98,8 @@ uu_avl_pool_create(const char *name, size_t objsize, size_t nodeoffset,
(void) pthread_mutex_init(&pp->uap_lock, NULL);
- pp->uap_null_avl.ua_next = &pp->uap_null_avl;
- pp->uap_null_avl.ua_prev = &pp->uap_null_avl;
+ pp->uap_null_avl.ua_next_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
+ pp->uap_null_avl.ua_prev_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
(void) pthread_mutex_lock(&uu_apool_list_lock);
pp->uap_next = next = &uu_null_apool;
@@ -115,8 +115,10 @@ void
uu_avl_pool_destroy(uu_avl_pool_t *pp)
{
if (pp->uap_debug) {
- if (pp->uap_null_avl.ua_next != &pp->uap_null_avl ||
- pp->uap_null_avl.ua_prev != &pp->uap_null_avl) {
+ if (pp->uap_null_avl.ua_next_enc !=
+ UU_PTR_ENCODE(&pp->uap_null_avl) ||
+ pp->uap_null_avl.ua_prev_enc !=
+ UU_PTR_ENCODE(&pp->uap_null_avl)) {
uu_panic("uu_avl_pool_destroy: Pool \"%.*s\" (%p) has "
"outstanding avls, or is corrupt.\n",
sizeof (pp->uap_name), pp->uap_name, pp);
@@ -209,7 +211,7 @@ uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags)
{
uu_avl_t *ap, *next, *prev;
- if (flags & UU_AVL_DEBUG) {
+ if (flags & ~UU_AVL_DEBUG) {
uu_set_error(UU_ERROR_UNKNOWN_FLAG);
return (NULL);
}
@@ -221,7 +223,7 @@ uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags)
}
ap->ua_pool = pp;
- ap->ua_parent = parent;
+ ap->ua_parent_enc = UU_PTR_ENCODE(parent);
ap->ua_debug = pp->uap_debug || (flags & UU_AVL_DEBUG);
ap->ua_index = (pp->uap_last_index = INDEX_NEXT(pp->uap_last_index));
@@ -232,10 +234,12 @@ uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags)
ap->ua_null_walk.uaw_prev = &ap->ua_null_walk;
(void) pthread_mutex_lock(&pp->uap_lock);
- ap->ua_next = next = &pp->uap_null_avl;
- ap->ua_prev = prev = next->ua_prev;
- next->ua_prev = ap;
- prev->ua_next = ap;
+ next = &pp->uap_null_avl;
+ prev = UU_PTR_DECODE(next->ua_prev_enc);
+ ap->ua_next_enc = UU_PTR_ENCODE(next);
+ ap->ua_prev_enc = UU_PTR_ENCODE(prev);
+ next->ua_prev_enc = UU_PTR_ENCODE(ap);
+ prev->ua_next_enc = UU_PTR_ENCODE(ap);
(void) pthread_mutex_unlock(&pp->uap_lock);
return (ap);
@@ -257,11 +261,11 @@ uu_avl_destroy(uu_avl_t *ap)
}
}
(void) pthread_mutex_lock(&pp->uap_lock);
- ap->ua_next->ua_prev = ap->ua_prev;
- ap->ua_prev->ua_next = ap->ua_next;
+ UU_AVL_PTR(ap->ua_next_enc)->ua_prev_enc = ap->ua_prev_enc;
+ UU_AVL_PTR(ap->ua_prev_enc)->ua_next_enc = ap->ua_next_enc;
(void) pthread_mutex_unlock(&pp->uap_lock);
- ap->ua_prev = NULL;
- ap->ua_next = NULL;
+ ap->ua_prev_enc = UU_PTR_ENCODE(NULL);
+ ap->ua_next_enc = UU_PTR_ENCODE(NULL);
ap->ua_pool = NULL;
avl_destroy(&ap->ua_tree);
@@ -451,7 +455,16 @@ uu_avl_remove(uu_avl_t *ap, void *elem)
void *
uu_avl_teardown(uu_avl_t *ap, void **cookie)
{
- return (avl_destroy_nodes(&ap->ua_tree, cookie));
+ void *elem = avl_destroy_nodes(&ap->ua_tree, cookie);
+
+ if (elem != NULL) {
+ uu_avl_pool_t *pp = ap->ua_pool;
+ uintptr_t *na = NODE_ARRAY(pp, elem);
+
+ na[0] = POOL_TO_MARKER(pp);
+ na[1] = NULL;
+ }
+ return (elem);
}
void *
diff --git a/usr/src/lib/libuutil/common/uu_list.c b/usr/src/lib/libuutil/common/uu_list.c
index cf7485c905..d9dc86fed4 100644
--- a/usr/src/lib/libuutil/common/uu_list.c
+++ b/usr/src/lib/libuutil/common/uu_list.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -94,8 +94,8 @@ uu_list_pool_create(const char *name, size_t objsize,
(void) pthread_mutex_init(&pp->ulp_lock, NULL);
- pp->ulp_null_list.ul_next = &pp->ulp_null_list;
- pp->ulp_null_list.ul_prev = &pp->ulp_null_list;
+ pp->ulp_null_list.ul_next_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
+ pp->ulp_null_list.ul_prev_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
(void) pthread_mutex_lock(&uu_lpool_list_lock);
pp->ulp_next = next = &uu_null_lpool;
@@ -111,8 +111,10 @@ void
uu_list_pool_destroy(uu_list_pool_t *pp)
{
if (pp->ulp_debug) {
- if (pp->ulp_null_list.ul_next != &pp->ulp_null_list ||
- pp->ulp_null_list.ul_prev != &pp->ulp_null_list) {
+ if (pp->ulp_null_list.ul_next_enc !=
+ UU_PTR_ENCODE(&pp->ulp_null_list) ||
+ pp->ulp_null_list.ul_prev_enc !=
+ UU_PTR_ENCODE(&pp->ulp_null_list)) {
uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has "
"outstanding lists, or is corrupt.\n",
sizeof (pp->ulp_name), pp->ulp_name, pp);
@@ -200,7 +202,7 @@ uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
}
lp->ul_pool = pp;
- lp->ul_parent = parent;
+ lp->ul_parent_enc = UU_PTR_ENCODE(parent);
lp->ul_offset = pp->ulp_nodeoffset;
lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG);
lp->ul_sorted = (flags & UU_LIST_SORTED);
@@ -214,10 +216,12 @@ uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
lp->ul_null_walk.ulw_prev = &lp->ul_null_walk;
(void) pthread_mutex_lock(&pp->ulp_lock);
- lp->ul_next = next = &pp->ulp_null_list;
- lp->ul_prev = prev = next->ul_prev;
- next->ul_prev = lp;
- prev->ul_next = lp;
+ next = &pp->ulp_null_list;
+ prev = UU_PTR_DECODE(next->ul_prev_enc);
+ lp->ul_next_enc = UU_PTR_ENCODE(next);
+ lp->ul_prev_enc = UU_PTR_ENCODE(prev);
+ next->ul_prev_enc = UU_PTR_ENCODE(lp);
+ prev->ul_next_enc = UU_PTR_ENCODE(lp);
(void) pthread_mutex_unlock(&pp->ulp_lock);
return (lp);
@@ -246,11 +250,11 @@ uu_list_destroy(uu_list_t *lp)
}
(void) pthread_mutex_lock(&pp->ulp_lock);
- lp->ul_next->ul_prev = lp->ul_prev;
- lp->ul_prev->ul_next = lp->ul_next;
+ UU_LIST_PTR(lp->ul_next_enc)->ul_prev_enc = lp->ul_prev_enc;
+ UU_LIST_PTR(lp->ul_prev_enc)->ul_next_enc = lp->ul_next_enc;
(void) pthread_mutex_unlock(&pp->ulp_lock);
- lp->ul_prev = NULL;
- lp->ul_next = NULL;
+ lp->ul_prev_enc = UU_PTR_ENCODE(NULL);
+ lp->ul_next_enc = UU_PTR_ENCODE(NULL);
lp->ul_pool = NULL;
uu_free(lp);
}