xref: /onnv-gate/usr/src/cmd/svc/configd/file_object.c (revision 471:fb6202c3da23)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * file_object.c - enter objects into and load them from the backend
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * The primary entry points in this layer are object_create(),
330Sstevel@tonic-gate  * object_create_pg(), object_delete(), and object_fill_children().  They each
340Sstevel@tonic-gate  * take an rc_node_t and use the functions in the object_info_t info array for
350Sstevel@tonic-gate  * the node's type.
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <assert.h>
390Sstevel@tonic-gate #include <pthread.h>
400Sstevel@tonic-gate #include <stdio.h>
410Sstevel@tonic-gate #include <stdlib.h>
420Sstevel@tonic-gate #include <string.h>
430Sstevel@tonic-gate #include <strings.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include "configd.h"
460Sstevel@tonic-gate #include "repcache_protocol.h"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate typedef struct child_info {
490Sstevel@tonic-gate 	rc_node_t	*ci_parent;
500Sstevel@tonic-gate 	backend_tx_t	*ci_tx;			/* only for properties */
510Sstevel@tonic-gate 	rc_node_lookup_t ci_base_nl;
520Sstevel@tonic-gate } child_info_t;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate typedef struct delete_ent delete_ent_t;
550Sstevel@tonic-gate typedef struct delete_stack delete_stack_t;
560Sstevel@tonic-gate typedef struct delete_info delete_info_t;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate typedef int	delete_cb_func(delete_info_t *, const delete_ent_t *);
590Sstevel@tonic-gate 
600Sstevel@tonic-gate struct delete_ent {
610Sstevel@tonic-gate 	delete_cb_func	*de_cb;		/* callback */
620Sstevel@tonic-gate 	uint32_t	de_backend;
630Sstevel@tonic-gate 	uint32_t	de_id;
640Sstevel@tonic-gate 	uint32_t	de_gen;		/* only for property groups */
650Sstevel@tonic-gate };
660Sstevel@tonic-gate 
670Sstevel@tonic-gate struct delete_stack {
680Sstevel@tonic-gate 	struct delete_stack *ds_next;
690Sstevel@tonic-gate 	uint32_t	ds_size;	/* number of elements */
700Sstevel@tonic-gate 	uint32_t	ds_cur;		/* current offset */
710Sstevel@tonic-gate 	delete_ent_t	ds_buf[1];	/* actually ds_size */
720Sstevel@tonic-gate };
730Sstevel@tonic-gate #define	DELETE_STACK_SIZE(x)	offsetof(delete_stack_t, ds_buf[(x)])
740Sstevel@tonic-gate 
750Sstevel@tonic-gate struct delete_info {
760Sstevel@tonic-gate 	backend_tx_t	*di_tx;
770Sstevel@tonic-gate 	backend_tx_t	*di_np_tx;
780Sstevel@tonic-gate 	delete_stack_t	*di_stack;
790Sstevel@tonic-gate 	delete_stack_t	*di_free;
800Sstevel@tonic-gate };
810Sstevel@tonic-gate 
820Sstevel@tonic-gate typedef struct object_info {
830Sstevel@tonic-gate 	uint32_t	obj_type;
840Sstevel@tonic-gate 	enum id_space	obj_id_space;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	int (*obj_fill_children)(rc_node_t *);
870Sstevel@tonic-gate 	int (*obj_setup_child_info)(rc_node_t *, uint32_t, child_info_t *);
880Sstevel@tonic-gate 	int (*obj_query_child)(backend_query_t *, rc_node_lookup_t *,
890Sstevel@tonic-gate 	    const char *);
900Sstevel@tonic-gate 	int (*obj_insert_child)(backend_tx_t *, rc_node_lookup_t *,
910Sstevel@tonic-gate 	    const char *);
920Sstevel@tonic-gate 	int (*obj_insert_pg_child)(backend_tx_t *, rc_node_lookup_t *,
930Sstevel@tonic-gate 	    const char *, const char *, uint32_t, uint32_t);
940Sstevel@tonic-gate 	int (*obj_delete_start)(rc_node_t *, delete_info_t *);
950Sstevel@tonic-gate } object_info_t;
960Sstevel@tonic-gate 
97407Sjwadams static void
98407Sjwadams string_to_id(const char *str, uint32_t *output, const char *fieldname)
99407Sjwadams {
100407Sjwadams 	if (uu_strtouint(str, output, sizeof (*output), 0, 0, 0) == -1)
101407Sjwadams 		backend_panic("invalid integer \"%s\" in field \"%s\"",
102407Sjwadams 		    str, fieldname);
103407Sjwadams }
104407Sjwadams 
1050Sstevel@tonic-gate #define	NUM_NEEDED	50
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate static int
1080Sstevel@tonic-gate delete_stack_push(delete_info_t *dip, uint32_t be, delete_cb_func *cb,
1090Sstevel@tonic-gate     uint32_t id, uint32_t gen)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate 	delete_stack_t *cur = dip->di_stack;
1120Sstevel@tonic-gate 	delete_ent_t *ent;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	if (cur == NULL || cur->ds_cur == cur->ds_size) {
1150Sstevel@tonic-gate 		delete_stack_t *new = dip->di_free;
1160Sstevel@tonic-gate 		dip->di_free = NULL;
1170Sstevel@tonic-gate 		if (new == NULL) {
1180Sstevel@tonic-gate 			new = uu_zalloc(DELETE_STACK_SIZE(NUM_NEEDED));
1190Sstevel@tonic-gate 			if (new == NULL)
1200Sstevel@tonic-gate 				return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1210Sstevel@tonic-gate 			new->ds_size = NUM_NEEDED;
1220Sstevel@tonic-gate 		}
1230Sstevel@tonic-gate 		new->ds_cur = 0;
1240Sstevel@tonic-gate 		new->ds_next = dip->di_stack;
1250Sstevel@tonic-gate 		dip->di_stack = new;
1260Sstevel@tonic-gate 		cur = new;
1270Sstevel@tonic-gate 	}
1280Sstevel@tonic-gate 	assert(cur->ds_cur < cur->ds_size);
1290Sstevel@tonic-gate 	ent = &cur->ds_buf[cur->ds_cur++];
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	ent->de_backend = be;
1320Sstevel@tonic-gate 	ent->de_cb = cb;
1330Sstevel@tonic-gate 	ent->de_id = id;
1340Sstevel@tonic-gate 	ent->de_gen = gen;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate static int
1400Sstevel@tonic-gate delete_stack_pop(delete_info_t *dip, delete_ent_t *out)
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate 	delete_stack_t *cur = dip->di_stack;
1430Sstevel@tonic-gate 	delete_ent_t *ent;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	if (cur == NULL)
146*471Shg115875 		return (0);
1470Sstevel@tonic-gate 	assert(cur->ds_cur > 0 && cur->ds_cur <= cur->ds_size);
1480Sstevel@tonic-gate 	ent = &cur->ds_buf[--cur->ds_cur];
1490Sstevel@tonic-gate 	if (cur->ds_cur == 0) {
1500Sstevel@tonic-gate 		dip->di_stack = cur->ds_next;
1510Sstevel@tonic-gate 		cur->ds_next = NULL;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 		if (dip->di_free != NULL)
1540Sstevel@tonic-gate 			uu_free(dip->di_free);
1550Sstevel@tonic-gate 		dip->di_free = cur;
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 	if (ent == NULL)
1580Sstevel@tonic-gate 		return (0);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	*out = *ent;
1610Sstevel@tonic-gate 	return (1);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate static void
1650Sstevel@tonic-gate delete_stack_cleanup(delete_info_t *dip)
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate 	delete_stack_t *cur;
1680Sstevel@tonic-gate 	while ((cur = dip->di_stack) != NULL) {
1690Sstevel@tonic-gate 		dip->di_stack = cur->ds_next;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 		uu_free(cur);
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	if ((cur = dip->di_free) != NULL) {
1750Sstevel@tonic-gate 		assert(cur->ds_next == NULL);	/* should only be one */
1760Sstevel@tonic-gate 		uu_free(cur);
1770Sstevel@tonic-gate 		dip->di_free = NULL;
1780Sstevel@tonic-gate 	}
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate struct delete_cb_info {
1820Sstevel@tonic-gate 	delete_info_t	*dci_dip;
1830Sstevel@tonic-gate 	uint32_t	dci_be;
1840Sstevel@tonic-gate 	delete_cb_func	*dci_cb;
1850Sstevel@tonic-gate 	int		dci_result;
1860Sstevel@tonic-gate };
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*ARGSUSED*/
1890Sstevel@tonic-gate static int
1900Sstevel@tonic-gate push_delete_callback(void *data, int columns, char **vals, char **names)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	struct delete_cb_info *info = data;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	const char *id_str = *vals++;
1950Sstevel@tonic-gate 	const char *gen_str = *vals++;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	uint32_t id;
1980Sstevel@tonic-gate 	uint32_t gen;
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	assert(columns == 2);
2010Sstevel@tonic-gate 
202407Sjwadams 	string_to_id(id_str, &id, "id");
203407Sjwadams 	string_to_id(gen_str, &gen, "gen_id");
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	info->dci_result = delete_stack_push(info->dci_dip, info->dci_be,
2060Sstevel@tonic-gate 	    info->dci_cb, id, gen);
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	if (info->dci_result != REP_PROTOCOL_SUCCESS)
2090Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
2100Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate static int
2140Sstevel@tonic-gate value_delete(delete_info_t *dip, const delete_ent_t *ent)
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
2170Sstevel@tonic-gate 	int r;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	backend_query_t *q;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
2220Sstevel@tonic-gate 	    dip->di_np_tx;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	q = backend_query_alloc();
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	backend_query_add(q,
2270Sstevel@tonic-gate 	    "SELECT 1 FROM prop_lnk_tbl WHERE (lnk_val_id = %d); "
2280Sstevel@tonic-gate 	    "DELETE FROM value_tbl WHERE (value_id = %d); ",
2290Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
2300Sstevel@tonic-gate 	r = backend_tx_run(tx, q, backend_fail_if_seen, NULL);
2310Sstevel@tonic-gate 	backend_query_free(q);
2320Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE)
2330Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);		/* still in use */
2340Sstevel@tonic-gate 	return (r);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate static int
2380Sstevel@tonic-gate pg_lnk_tbl_delete(delete_info_t *dip, const delete_ent_t *ent)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate 	struct delete_cb_info info;
2410Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
2420Sstevel@tonic-gate 	int r;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	backend_query_t *q;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
2470Sstevel@tonic-gate 	    dip->di_np_tx;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	/*
2500Sstevel@tonic-gate 	 * For non-persistent backends, we could only have one parent, and
2510Sstevel@tonic-gate 	 * he's already been deleted.
2520Sstevel@tonic-gate 	 *
2530Sstevel@tonic-gate 	 * For normal backends, we need to check to see if we're in
2540Sstevel@tonic-gate 	 * a snapshot or are the active generation for the property
2550Sstevel@tonic-gate 	 * group.  If we are, there's nothing to be done.
2560Sstevel@tonic-gate 	 */
2570Sstevel@tonic-gate 	if (be == BACKEND_TYPE_NORMAL) {
2580Sstevel@tonic-gate 		q = backend_query_alloc();
2590Sstevel@tonic-gate 		backend_query_add(q,
2600Sstevel@tonic-gate 		    "SELECT 1 "
2610Sstevel@tonic-gate 		    "FROM pg_tbl "
2620Sstevel@tonic-gate 		    "WHERE (pg_id = %d AND pg_gen_id = %d); "
2630Sstevel@tonic-gate 		    "SELECT 1 "
2640Sstevel@tonic-gate 		    "FROM snaplevel_lnk_tbl "
2650Sstevel@tonic-gate 		    "WHERE (snaplvl_pg_id = %d AND snaplvl_gen_id = %d);",
2660Sstevel@tonic-gate 		    ent->de_id, ent->de_gen,
2670Sstevel@tonic-gate 		    ent->de_id, ent->de_gen);
2680Sstevel@tonic-gate 		r = backend_tx_run(tx, q, backend_fail_if_seen, NULL);
2690Sstevel@tonic-gate 		backend_query_free(q);
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 		if (r == REP_PROTOCOL_DONE)
2720Sstevel@tonic-gate 			return (REP_PROTOCOL_SUCCESS);	/* still in use */
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	info.dci_dip = dip;
2760Sstevel@tonic-gate 	info.dci_be =  be;
2770Sstevel@tonic-gate 	info.dci_cb = &value_delete;
2780Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	q = backend_query_alloc();
2810Sstevel@tonic-gate 	backend_query_add(q,
2820Sstevel@tonic-gate 	    "SELECT DISTINCT lnk_val_id, 0 FROM prop_lnk_tbl "
2830Sstevel@tonic-gate 	    "WHERE "
2840Sstevel@tonic-gate 	    "    (lnk_pg_id = %d AND lnk_gen_id = %d AND lnk_val_id NOTNULL); "
2850Sstevel@tonic-gate 	    "DELETE FROM prop_lnk_tbl "
2860Sstevel@tonic-gate 	    "WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)",
2870Sstevel@tonic-gate 	    ent->de_id, ent->de_gen, ent->de_id, ent->de_gen);
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	r = backend_tx_run(tx, q, push_delete_callback, &info);
2900Sstevel@tonic-gate 	backend_query_free(q);
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
2930Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
2940Sstevel@tonic-gate 		return (info.dci_result);
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 	return (r);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate static int
3000Sstevel@tonic-gate propertygrp_delete(delete_info_t *dip, const delete_ent_t *ent)
3010Sstevel@tonic-gate {
3020Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
3030Sstevel@tonic-gate 	backend_query_t *q;
3040Sstevel@tonic-gate 	uint32_t gen;
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	int r;
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
3090Sstevel@tonic-gate 	    dip->di_np_tx;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	q = backend_query_alloc();
3120Sstevel@tonic-gate 	backend_query_add(q,
3130Sstevel@tonic-gate 	    "SELECT pg_gen_id FROM pg_tbl WHERE pg_id = %d; "
3140Sstevel@tonic-gate 	    "DELETE FROM pg_tbl WHERE pg_id = %d",
3150Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
3160Sstevel@tonic-gate 	r = backend_tx_run_single_int(tx, q, &gen);
3170Sstevel@tonic-gate 	backend_query_free(q);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
3200Sstevel@tonic-gate 		return (r);
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	return (delete_stack_push(dip, be, &pg_lnk_tbl_delete,
3230Sstevel@tonic-gate 	    ent->de_id, gen));
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate static int
3270Sstevel@tonic-gate snaplevel_lnk_delete(delete_info_t *dip, const delete_ent_t *ent)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
3300Sstevel@tonic-gate 	backend_query_t *q;
3310Sstevel@tonic-gate 	struct delete_cb_info info;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	int r;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
3360Sstevel@tonic-gate 	    dip->di_np_tx;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	info.dci_dip = dip;
3390Sstevel@tonic-gate 	info.dci_be = be;
3400Sstevel@tonic-gate 	info.dci_cb = &pg_lnk_tbl_delete;
3410Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	q = backend_query_alloc();
3440Sstevel@tonic-gate 	backend_query_add(q,
3450Sstevel@tonic-gate 	    "SELECT snaplvl_pg_id, snaplvl_gen_id "
3460Sstevel@tonic-gate 	    "    FROM snaplevel_lnk_tbl "
3470Sstevel@tonic-gate 	    "    WHERE snaplvl_level_id = %d; "
3480Sstevel@tonic-gate 	    "DELETE FROM snaplevel_lnk_tbl WHERE snaplvl_level_id = %d",
3490Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
3500Sstevel@tonic-gate 	r = backend_tx_run(tx, q, push_delete_callback, &info);
3510Sstevel@tonic-gate 	backend_query_free(q);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
3540Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
3550Sstevel@tonic-gate 		return (info.dci_result);
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate 	return (r);
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate static int
3610Sstevel@tonic-gate snaplevel_tbl_delete(delete_info_t *dip, const delete_ent_t *ent)
3620Sstevel@tonic-gate {
3630Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
3640Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
3650Sstevel@tonic-gate 	    dip->di_np_tx;
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	struct delete_cb_info info;
3680Sstevel@tonic-gate 	backend_query_t *q;
3690Sstevel@tonic-gate 	int r;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	assert(be == BACKEND_TYPE_NORMAL);
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	q = backend_query_alloc();
3740Sstevel@tonic-gate 	backend_query_add(q,
3750Sstevel@tonic-gate 	    "SELECT 1 FROM snapshot_lnk_tbl WHERE lnk_snap_id = %d",
3760Sstevel@tonic-gate 	    ent->de_id);
3770Sstevel@tonic-gate 	r = backend_tx_run(tx, q, backend_fail_if_seen, NULL);
3780Sstevel@tonic-gate 	backend_query_free(q);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE)
3810Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);		/* still in use */
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	info.dci_dip = dip;
3840Sstevel@tonic-gate 	info.dci_be = be;
3850Sstevel@tonic-gate 	info.dci_cb = &snaplevel_lnk_delete;
3860Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	q = backend_query_alloc();
3890Sstevel@tonic-gate 	backend_query_add(q,
3900Sstevel@tonic-gate 	    "SELECT snap_level_id, 0 FROM snaplevel_tbl WHERE snap_id = %d;"
3910Sstevel@tonic-gate 	    "DELETE FROM snaplevel_tbl WHERE snap_id = %d",
3920Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
3930Sstevel@tonic-gate 	r = backend_tx_run(tx, q, push_delete_callback, &info);
3940Sstevel@tonic-gate 	backend_query_free(q);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
3970Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
3980Sstevel@tonic-gate 		return (info.dci_result);
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 	return (r);
4010Sstevel@tonic-gate }
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate static int
4040Sstevel@tonic-gate snapshot_lnk_delete(delete_info_t *dip, const delete_ent_t *ent)
4050Sstevel@tonic-gate {
4060Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
4070Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
4080Sstevel@tonic-gate 	    dip->di_np_tx;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	backend_query_t *q;
4110Sstevel@tonic-gate 	uint32_t snapid;
4120Sstevel@tonic-gate 	int r;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	assert(be == BACKEND_TYPE_NORMAL);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	q = backend_query_alloc();
4170Sstevel@tonic-gate 	backend_query_add(q,
4180Sstevel@tonic-gate 	    "SELECT lnk_snap_id FROM snapshot_lnk_tbl WHERE lnk_id = %d; "
4190Sstevel@tonic-gate 	    "DELETE FROM snapshot_lnk_tbl WHERE lnk_id = %d",
4200Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
4210Sstevel@tonic-gate 	r = backend_tx_run_single_int(tx, q, &snapid);
4220Sstevel@tonic-gate 	backend_query_free(q);
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
4250Sstevel@tonic-gate 		return (r);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	return (delete_stack_push(dip, be, &snaplevel_tbl_delete, snapid, 0));
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate static int
4310Sstevel@tonic-gate pgparent_delete_add_pgs(delete_info_t *dip, uint32_t parent_id)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate 	struct delete_cb_info info;
4340Sstevel@tonic-gate 	backend_query_t *q;
4350Sstevel@tonic-gate 	int r;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	info.dci_dip = dip;
4380Sstevel@tonic-gate 	info.dci_be = BACKEND_TYPE_NORMAL;
4390Sstevel@tonic-gate 	info.dci_cb = &propertygrp_delete;
4400Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	q = backend_query_alloc();
4430Sstevel@tonic-gate 	backend_query_add(q,
4440Sstevel@tonic-gate 	    "SELECT pg_id, 0 FROM pg_tbl WHERE pg_parent_id = %d",
4450Sstevel@tonic-gate 	    parent_id);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	r = backend_tx_run(dip->di_tx, q, push_delete_callback, &info);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
4500Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
4510Sstevel@tonic-gate 		backend_query_free(q);
4520Sstevel@tonic-gate 		return (info.dci_result);
4530Sstevel@tonic-gate 	}
4540Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS) {
4550Sstevel@tonic-gate 		backend_query_free(q);
4560Sstevel@tonic-gate 		return (r);
4570Sstevel@tonic-gate 	}
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	if (dip->di_np_tx != NULL) {
4600Sstevel@tonic-gate 		info.dci_be = BACKEND_TYPE_NONPERSIST;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		r = backend_tx_run(dip->di_np_tx, q, push_delete_callback,
4630Sstevel@tonic-gate 		    &info);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 		if (r == REP_PROTOCOL_DONE) {
4660Sstevel@tonic-gate 			assert(info.dci_result != REP_PROTOCOL_SUCCESS);
4670Sstevel@tonic-gate 			backend_query_free(q);
4680Sstevel@tonic-gate 			return (info.dci_result);
4690Sstevel@tonic-gate 		}
4700Sstevel@tonic-gate 		if (r != REP_PROTOCOL_SUCCESS) {
4710Sstevel@tonic-gate 			backend_query_free(q);
4720Sstevel@tonic-gate 			return (r);
4730Sstevel@tonic-gate 		}
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 	backend_query_free(q);
4760Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate static int
4800Sstevel@tonic-gate service_delete(delete_info_t *dip, const delete_ent_t *ent)
4810Sstevel@tonic-gate {
4820Sstevel@tonic-gate 	int r;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	r = backend_tx_run_update_changed(dip->di_tx,
4850Sstevel@tonic-gate 	    "DELETE FROM service_tbl WHERE svc_id = %d", ent->de_id);
4860Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
4870Sstevel@tonic-gate 		return (r);
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	return (pgparent_delete_add_pgs(dip, ent->de_id));
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate static int
4930Sstevel@tonic-gate instance_delete(delete_info_t *dip, const delete_ent_t *ent)
4940Sstevel@tonic-gate {
4950Sstevel@tonic-gate 	struct delete_cb_info info;
4960Sstevel@tonic-gate 	int r;
4970Sstevel@tonic-gate 	backend_query_t *q;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	r = backend_tx_run_update_changed(dip->di_tx,
5000Sstevel@tonic-gate 	    "DELETE FROM instance_tbl WHERE instance_id = %d", ent->de_id);
5010Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
5020Sstevel@tonic-gate 		return (r);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	r = pgparent_delete_add_pgs(dip, ent->de_id);
5050Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
5060Sstevel@tonic-gate 		return (r);
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	info.dci_dip = dip;
5090Sstevel@tonic-gate 	info.dci_be = BACKEND_TYPE_NORMAL;
5100Sstevel@tonic-gate 	info.dci_cb = &snapshot_lnk_delete;
5110Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	q = backend_query_alloc();
5140Sstevel@tonic-gate 	backend_query_add(q,
5150Sstevel@tonic-gate 	    "SELECT lnk_id, 0 FROM snapshot_lnk_tbl WHERE lnk_inst_id = %d",
5160Sstevel@tonic-gate 	    ent->de_id);
5170Sstevel@tonic-gate 	r = backend_tx_run(dip->di_tx, q, push_delete_callback, &info);
5180Sstevel@tonic-gate 	backend_query_free(q);
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
5210Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
5220Sstevel@tonic-gate 		return (info.dci_result);
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 	return (r);
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate /*ARGSUSED*/
5280Sstevel@tonic-gate static int
5290Sstevel@tonic-gate fill_child_callback(void *data, int columns, char **vals, char **names)
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate 	child_info_t *cp = data;
5320Sstevel@tonic-gate 	rc_node_t *np;
5330Sstevel@tonic-gate 	uint32_t main_id;
5340Sstevel@tonic-gate 	const char *name;
5350Sstevel@tonic-gate 	const char *cur;
5360Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cp->ci_base_nl;
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	assert(columns == 2);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	name = *vals++;
5410Sstevel@tonic-gate 	columns--;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	cur = *vals++;
5440Sstevel@tonic-gate 	columns--;
545407Sjwadams 	string_to_id(cur, &main_id, "id");
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	lp->rl_main_id = main_id;
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	if ((np = rc_node_alloc()) == NULL)
5500Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	np = rc_node_setup(np, lp, name, cp->ci_parent);
5530Sstevel@tonic-gate 	rc_node_rele(np);
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate /*ARGSUSED*/
5590Sstevel@tonic-gate static int
5600Sstevel@tonic-gate fill_snapshot_callback(void *data, int columns, char **vals, char **names)
5610Sstevel@tonic-gate {
5620Sstevel@tonic-gate 	child_info_t *cp = data;
5630Sstevel@tonic-gate 	rc_node_t *np;
5640Sstevel@tonic-gate 	uint32_t main_id;
5650Sstevel@tonic-gate 	uint32_t snap_id;
5660Sstevel@tonic-gate 	const char *name;
5670Sstevel@tonic-gate 	const char *cur;
5680Sstevel@tonic-gate 	const char *snap;
5690Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cp->ci_base_nl;
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	assert(columns == 3);
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	name = *vals++;
5740Sstevel@tonic-gate 	columns--;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	cur = *vals++;
5770Sstevel@tonic-gate 	columns--;
5780Sstevel@tonic-gate 	snap = *vals++;
5790Sstevel@tonic-gate 	columns--;
580407Sjwadams 
581407Sjwadams 	string_to_id(cur, &main_id, "lnk_id");
582407Sjwadams 	string_to_id(snap, &snap_id, "lnk_snap_id");
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	lp->rl_main_id = main_id;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	if ((np = rc_node_alloc()) == NULL)
5870Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	np = rc_node_setup_snapshot(np, lp, name, snap_id, cp->ci_parent);
5900Sstevel@tonic-gate 	rc_node_rele(np);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate /*ARGSUSED*/
5960Sstevel@tonic-gate static int
5970Sstevel@tonic-gate fill_pg_callback(void *data, int columns, char **vals, char **names)
5980Sstevel@tonic-gate {
5990Sstevel@tonic-gate 	child_info_t *cip = data;
6000Sstevel@tonic-gate 	const char *name;
6010Sstevel@tonic-gate 	const char *type;
6020Sstevel@tonic-gate 	const char *cur;
6030Sstevel@tonic-gate 	uint32_t main_id;
6040Sstevel@tonic-gate 	uint32_t flags;
6050Sstevel@tonic-gate 	uint32_t gen_id;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cip->ci_base_nl;
6080Sstevel@tonic-gate 	rc_node_t *newnode, *pg;
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	assert(columns == 5);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	name = *vals++;		/* pg_name */
6130Sstevel@tonic-gate 	columns--;
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	cur = *vals++;		/* pg_id */
6160Sstevel@tonic-gate 	columns--;
617407Sjwadams 	string_to_id(cur, &main_id, "pg_id");
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	lp->rl_main_id = main_id;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	cur = *vals++;		/* pg_gen_id */
6220Sstevel@tonic-gate 	columns--;
623407Sjwadams 	string_to_id(cur, &gen_id, "pg_gen_id");
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	type = *vals++;		/* pg_type */
6260Sstevel@tonic-gate 	columns--;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	cur = *vals++;		/* pg_flags */
6290Sstevel@tonic-gate 	columns--;
630407Sjwadams 	string_to_id(cur, &flags, "pg_flags");
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	if ((newnode = rc_node_alloc()) == NULL)
6330Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	pg = rc_node_setup_pg(newnode, lp, name, type, flags, gen_id,
6360Sstevel@tonic-gate 	    cip->ci_parent);
6370Sstevel@tonic-gate 	if (pg == NULL) {
6380Sstevel@tonic-gate 		rc_node_destroy(newnode);
6390Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
6400Sstevel@tonic-gate 	}
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	rc_node_rele(pg);
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate struct property_value_info {
6480Sstevel@tonic-gate 	char		*pvi_base;
6490Sstevel@tonic-gate 	size_t		pvi_pos;
6500Sstevel@tonic-gate 	size_t		pvi_size;
6510Sstevel@tonic-gate 	size_t		pvi_count;
6520Sstevel@tonic-gate };
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate /*ARGSUSED*/
6550Sstevel@tonic-gate static int
6560Sstevel@tonic-gate property_value_size_cb(void *data, int columns, char **vals, char **names)
6570Sstevel@tonic-gate {
6580Sstevel@tonic-gate 	struct property_value_info *info = data;
6590Sstevel@tonic-gate 	assert(columns == 1);
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	info->pvi_size += strlen(vals[0]) + 1;		/* count the '\0' */
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate /*ARGSUSED*/
6670Sstevel@tonic-gate static int
6680Sstevel@tonic-gate property_value_cb(void *data, int columns, char **vals, char **names)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate 	struct property_value_info *info = data;
6710Sstevel@tonic-gate 	size_t pos, left, len;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	assert(columns == 1);
6740Sstevel@tonic-gate 	pos = info->pvi_pos;
6750Sstevel@tonic-gate 	left = info->pvi_size - pos;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	pos = info->pvi_pos;
6780Sstevel@tonic-gate 	left = info->pvi_size - pos;
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	if ((len = strlcpy(&info->pvi_base[pos], vals[0], left)) >= left) {
6810Sstevel@tonic-gate 		/*
6820Sstevel@tonic-gate 		 * since we preallocated, above, this shouldn't happen
6830Sstevel@tonic-gate 		 */
6840Sstevel@tonic-gate 		backend_panic("unexpected database change");
6850Sstevel@tonic-gate 	}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	len += 1;	/* count the '\0' */
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	info->pvi_pos += len;
6900Sstevel@tonic-gate 	info->pvi_count++;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate /*ARGSUSED*/
6960Sstevel@tonic-gate void
6970Sstevel@tonic-gate object_free_values(const char *vals, uint32_t type, size_t count, size_t size)
6980Sstevel@tonic-gate {
6990Sstevel@tonic-gate 	if (vals != NULL)
7000Sstevel@tonic-gate 		uu_free((void *)vals);
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate /*ARGSUSED*/
7040Sstevel@tonic-gate static int
7050Sstevel@tonic-gate fill_property_callback(void *data, int columns, char **vals, char **names)
7060Sstevel@tonic-gate {
7070Sstevel@tonic-gate 	child_info_t *cp = data;
7080Sstevel@tonic-gate 	backend_tx_t *tx = cp->ci_tx;
7090Sstevel@tonic-gate 	uint32_t main_id;
7100Sstevel@tonic-gate 	const char *name;
7110Sstevel@tonic-gate 	const char *cur;
7120Sstevel@tonic-gate 	rep_protocol_value_type_t type;
7130Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cp->ci_base_nl;
7140Sstevel@tonic-gate 	struct property_value_info info;
7150Sstevel@tonic-gate 	int rc;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	assert(columns == 4);
7180Sstevel@tonic-gate 	assert(tx != NULL);
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	info.pvi_base = NULL;
7210Sstevel@tonic-gate 	info.pvi_pos = 0;
7220Sstevel@tonic-gate 	info.pvi_size = 0;
7230Sstevel@tonic-gate 	info.pvi_count = 0;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	name = *vals++;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	cur = *vals++;
728407Sjwadams 	string_to_id(cur, &main_id, "lnk_prop_id");
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	cur = *vals++;
7310Sstevel@tonic-gate 	assert(('a' <= cur[0] && 'z' >= cur[0]) ||
7320Sstevel@tonic-gate 	    ('A' <= cur[0] && 'Z' >= cur[0]) &&
7330Sstevel@tonic-gate 	    (cur[1] == 0 || ('a' <= cur[1] && 'z' >= cur[1]) ||
7340Sstevel@tonic-gate 	    ('A' <= cur[1] && 'Z' >= cur[1])));
7350Sstevel@tonic-gate 	type = cur[0] | (cur[1] << 8);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	lp->rl_main_id = main_id;
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	/*
7400Sstevel@tonic-gate 	 * fill in the values, if any
7410Sstevel@tonic-gate 	 */
7420Sstevel@tonic-gate 	if ((cur = *vals++) != NULL) {
7430Sstevel@tonic-gate 		rep_protocol_responseid_t r;
7440Sstevel@tonic-gate 		backend_query_t *q = backend_query_alloc();
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 		backend_query_add(q,
7470Sstevel@tonic-gate 		    "SELECT value_value FROM value_tbl "
7480Sstevel@tonic-gate 		    "WHERE (value_id = '%q')", cur);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 		switch (r = backend_tx_run(tx, q, property_value_size_cb,
7510Sstevel@tonic-gate 		    &info)) {
7520Sstevel@tonic-gate 		case REP_PROTOCOL_SUCCESS:
7530Sstevel@tonic-gate 			break;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 		case REP_PROTOCOL_FAIL_NO_RESOURCES:
7560Sstevel@tonic-gate 			backend_query_free(q);
7570Sstevel@tonic-gate 			return (BACKEND_CALLBACK_ABORT);
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 		case REP_PROTOCOL_DONE:
7600Sstevel@tonic-gate 		default:
7610Sstevel@tonic-gate 			backend_panic("backend_tx_run() returned %d", r);
7620Sstevel@tonic-gate 		}
7630Sstevel@tonic-gate 		if (info.pvi_size > 0) {
7640Sstevel@tonic-gate 			info.pvi_base = uu_zalloc(info.pvi_size);
7650Sstevel@tonic-gate 			if (info.pvi_base == NULL) {
7660Sstevel@tonic-gate 				backend_query_free(q);
7670Sstevel@tonic-gate 				return (BACKEND_CALLBACK_ABORT);
7680Sstevel@tonic-gate 			}
7690Sstevel@tonic-gate 			switch (r = backend_tx_run(tx, q, property_value_cb,
7700Sstevel@tonic-gate 			    &info)) {
7710Sstevel@tonic-gate 			case REP_PROTOCOL_SUCCESS:
7720Sstevel@tonic-gate 				break;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 			case REP_PROTOCOL_FAIL_NO_RESOURCES:
7750Sstevel@tonic-gate 				uu_free(info.pvi_base);
7760Sstevel@tonic-gate 				backend_query_free(q);
7770Sstevel@tonic-gate 				return (BACKEND_CALLBACK_ABORT);
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 			case REP_PROTOCOL_DONE:
7800Sstevel@tonic-gate 			default:
7810Sstevel@tonic-gate 				backend_panic("backend_tx_run() returned %d",
7820Sstevel@tonic-gate 				    r);
7830Sstevel@tonic-gate 			}
7840Sstevel@tonic-gate 		}
7850Sstevel@tonic-gate 		backend_query_free(q);
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	rc = rc_node_create_property(cp->ci_parent, lp, name, type,
7890Sstevel@tonic-gate 	    info.pvi_base, info.pvi_count, info.pvi_size);
7900Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS) {
7910Sstevel@tonic-gate 		assert(rc == REP_PROTOCOL_FAIL_NO_RESOURCES);
7920Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
7930Sstevel@tonic-gate 	}
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate /*
7990Sstevel@tonic-gate  * The *_setup_child_info() functions fill in a child_info_t structure with the
8000Sstevel@tonic-gate  * information for the children of np with type type.
8010Sstevel@tonic-gate  *
8020Sstevel@tonic-gate  * They fail with
8030Sstevel@tonic-gate  *   _TYPE_MISMATCH - object cannot have children of type type
8040Sstevel@tonic-gate  */
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate static int
8070Sstevel@tonic-gate scope_setup_child_info(rc_node_t *np, uint32_t type, child_info_t *cip)
8080Sstevel@tonic-gate {
8090Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_SERVICE)
8100Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
8130Sstevel@tonic-gate 	cip->ci_parent = np;
8140Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
8150Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = np->rn_id.rl_backend;
8160Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate static int
8200Sstevel@tonic-gate service_setup_child_info(rc_node_t *np, uint32_t type, child_info_t *cip)
8210Sstevel@tonic-gate {
8220Sstevel@tonic-gate 	switch (type) {
8230Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE:
8240Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
8250Sstevel@tonic-gate 		break;
8260Sstevel@tonic-gate 	default:
8270Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
8310Sstevel@tonic-gate 	cip->ci_parent = np;
8320Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
8330Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = np->rn_id.rl_backend;
8340Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SERVICE] = np->rn_id.rl_main_id;
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
8370Sstevel@tonic-gate }
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate static int
8400Sstevel@tonic-gate instance_setup_child_info(rc_node_t *np, uint32_t type, child_info_t *cip)
8410Sstevel@tonic-gate {
8420Sstevel@tonic-gate 	switch (type) {
8430Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
8440Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
8450Sstevel@tonic-gate 		break;
8460Sstevel@tonic-gate 	default:
8470Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
8480Sstevel@tonic-gate 	}
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
8510Sstevel@tonic-gate 	cip->ci_parent = np;
8520Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
8530Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = np->rn_id.rl_backend;
8540Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SERVICE] = np->rn_id.rl_ids[ID_SERVICE];
8550Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_INSTANCE] = np->rn_id.rl_main_id;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate static int
8610Sstevel@tonic-gate snaplevel_setup_child_info(rc_node_t *np, uint32_t type, child_info_t *cip)
8620Sstevel@tonic-gate {
8630Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
8640Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
8670Sstevel@tonic-gate 	cip->ci_parent = np;
8680Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
8690Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = np->rn_id.rl_backend;
8700Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SERVICE] = np->rn_id.rl_ids[ID_SERVICE];
8710Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_INSTANCE] = np->rn_id.rl_ids[ID_INSTANCE];
8720Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_NAME] = np->rn_id.rl_ids[ID_NAME];
8730Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SNAPSHOT] = np->rn_id.rl_ids[ID_SNAPSHOT];
8740Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_LEVEL] = np->rn_id.rl_main_id;
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
8770Sstevel@tonic-gate }
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate static int
8800Sstevel@tonic-gate propertygrp_setup_child_info(rc_node_t *pg, uint32_t type, child_info_t *cip)
8810Sstevel@tonic-gate {
8820Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_PROPERTY)
8830Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
8860Sstevel@tonic-gate 	cip->ci_parent = pg;
8870Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
8880Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = pg->rn_id.rl_backend;
8890Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SERVICE] = pg->rn_id.rl_ids[ID_SERVICE];
8900Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_INSTANCE] = pg->rn_id.rl_ids[ID_INSTANCE];
8910Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_PG] = pg->rn_id.rl_main_id;
8920Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_GEN] = pg->rn_gen_id;
8930Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_NAME] = pg->rn_id.rl_ids[ID_NAME];
8940Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SNAPSHOT] = pg->rn_id.rl_ids[ID_SNAPSHOT];
8950Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_LEVEL] = pg->rn_id.rl_ids[ID_LEVEL];
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
8980Sstevel@tonic-gate }
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate /*
9010Sstevel@tonic-gate  * The *_fill_children() functions populate the children of the given rc_node_t
9020Sstevel@tonic-gate  * by querying the database and calling rc_node_setup_*() functions (usually
9030Sstevel@tonic-gate  * via a fill_*_callback()).
9040Sstevel@tonic-gate  *
9050Sstevel@tonic-gate  * They fail with
9060Sstevel@tonic-gate  *   _NO_RESOURCES
9070Sstevel@tonic-gate  */
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate  * Returns
9110Sstevel@tonic-gate  *   _NO_RESOURCES
9120Sstevel@tonic-gate  *   _SUCCESS
9130Sstevel@tonic-gate  */
9140Sstevel@tonic-gate static int
9150Sstevel@tonic-gate scope_fill_children(rc_node_t *np)
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate 	backend_query_t *q;
9180Sstevel@tonic-gate 	child_info_t ci;
9190Sstevel@tonic-gate 	int res;
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	(void) scope_setup_child_info(np, REP_PROTOCOL_ENTITY_SERVICE, &ci);
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	q = backend_query_alloc();
9240Sstevel@tonic-gate 	backend_query_append(q, "SELECT svc_name, svc_id FROM service_tbl");
9250Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_child_callback, &ci);
9260Sstevel@tonic-gate 	backend_query_free(q);
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
9290Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
9300Sstevel@tonic-gate 	return (res);
9310Sstevel@tonic-gate }
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate /*
9340Sstevel@tonic-gate  * Returns
9350Sstevel@tonic-gate  *   _NO_RESOURCES
9360Sstevel@tonic-gate  *   _SUCCESS
9370Sstevel@tonic-gate  */
9380Sstevel@tonic-gate static int
9390Sstevel@tonic-gate service_fill_children(rc_node_t *np)
9400Sstevel@tonic-gate {
9410Sstevel@tonic-gate 	backend_query_t *q;
9420Sstevel@tonic-gate 	child_info_t ci;
9430Sstevel@tonic-gate 	int res;
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	assert(np->rn_id.rl_backend == BACKEND_TYPE_NORMAL);
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	(void) service_setup_child_info(np, REP_PROTOCOL_ENTITY_INSTANCE, &ci);
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	q = backend_query_alloc();
9500Sstevel@tonic-gate 	backend_query_add(q,
9510Sstevel@tonic-gate 	    "SELECT instance_name, instance_id FROM instance_tbl"
9520Sstevel@tonic-gate 	    "    WHERE (instance_svc = %d)",
9530Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
9540Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_child_callback, &ci);
9550Sstevel@tonic-gate 	backend_query_free(q);
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
9580Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
9590Sstevel@tonic-gate 	if (res != REP_PROTOCOL_SUCCESS)
9600Sstevel@tonic-gate 		return (res);
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	(void) service_setup_child_info(np, REP_PROTOCOL_ENTITY_PROPERTYGRP,
9630Sstevel@tonic-gate 	    &ci);
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	q = backend_query_alloc();
9660Sstevel@tonic-gate 	backend_query_add(q,
9670Sstevel@tonic-gate 	    "SELECT pg_name, pg_id, pg_gen_id, pg_type, pg_flags FROM pg_tbl"
9680Sstevel@tonic-gate 	    "    WHERE (pg_parent_id = %d)",
9690Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	ci.ci_base_nl.rl_backend = BACKEND_TYPE_NORMAL;
9720Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_pg_callback, &ci);
9730Sstevel@tonic-gate 	if (res == REP_PROTOCOL_SUCCESS) {
9740Sstevel@tonic-gate 		ci.ci_base_nl.rl_backend = BACKEND_TYPE_NONPERSIST;
9750Sstevel@tonic-gate 		res = backend_run(BACKEND_TYPE_NONPERSIST, q,
9760Sstevel@tonic-gate 		    fill_pg_callback, &ci);
9770Sstevel@tonic-gate 		/* nonpersistant database may not exist */
9780Sstevel@tonic-gate 		if (res == REP_PROTOCOL_FAIL_BACKEND_ACCESS)
9790Sstevel@tonic-gate 			res = REP_PROTOCOL_SUCCESS;
9800Sstevel@tonic-gate 	}
9810Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
9820Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
9830Sstevel@tonic-gate 	backend_query_free(q);
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	return (res);
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate /*
9890Sstevel@tonic-gate  * Returns
9900Sstevel@tonic-gate  *   _NO_RESOURCES
9910Sstevel@tonic-gate  *   _SUCCESS
9920Sstevel@tonic-gate  */
9930Sstevel@tonic-gate static int
9940Sstevel@tonic-gate instance_fill_children(rc_node_t *np)
9950Sstevel@tonic-gate {
9960Sstevel@tonic-gate 	backend_query_t *q;
9970Sstevel@tonic-gate 	child_info_t ci;
9980Sstevel@tonic-gate 	int res;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	assert(np->rn_id.rl_backend == BACKEND_TYPE_NORMAL);
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	/* Get child property groups */
10030Sstevel@tonic-gate 	(void) instance_setup_child_info(np, REP_PROTOCOL_ENTITY_PROPERTYGRP,
10040Sstevel@tonic-gate 	    &ci);
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	q = backend_query_alloc();
10070Sstevel@tonic-gate 	backend_query_add(q,
10080Sstevel@tonic-gate 	    "SELECT pg_name, pg_id, pg_gen_id, pg_type, pg_flags FROM pg_tbl"
10090Sstevel@tonic-gate 	    "    WHERE (pg_parent_id = %d)",
10100Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
10110Sstevel@tonic-gate 	ci.ci_base_nl.rl_backend = BACKEND_TYPE_NORMAL;
10120Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_pg_callback, &ci);
10130Sstevel@tonic-gate 	if (res == REP_PROTOCOL_SUCCESS) {
10140Sstevel@tonic-gate 		ci.ci_base_nl.rl_backend = BACKEND_TYPE_NONPERSIST;
10150Sstevel@tonic-gate 		res = backend_run(BACKEND_TYPE_NONPERSIST, q,
10160Sstevel@tonic-gate 		    fill_pg_callback, &ci);
10170Sstevel@tonic-gate 		/* nonpersistant database may not exist */
10180Sstevel@tonic-gate 		if (res == REP_PROTOCOL_FAIL_BACKEND_ACCESS)
10190Sstevel@tonic-gate 			res = REP_PROTOCOL_SUCCESS;
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
10220Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
10230Sstevel@tonic-gate 	backend_query_free(q);
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	if (res != REP_PROTOCOL_SUCCESS)
10260Sstevel@tonic-gate 		return (res);
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	/* Get child snapshots */
10290Sstevel@tonic-gate 	(void) instance_setup_child_info(np, REP_PROTOCOL_ENTITY_SNAPSHOT,
10300Sstevel@tonic-gate 	    &ci);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	q = backend_query_alloc();
10330Sstevel@tonic-gate 	backend_query_add(q,
10340Sstevel@tonic-gate 	    "SELECT lnk_snap_name, lnk_id, lnk_snap_id FROM snapshot_lnk_tbl"
10350Sstevel@tonic-gate 	    "    WHERE (lnk_inst_id = %d)",
10360Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
10370Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_snapshot_callback, &ci);
10380Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
10390Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
10400Sstevel@tonic-gate 	backend_query_free(q);
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	return (res);
10430Sstevel@tonic-gate }
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate /*
10460Sstevel@tonic-gate  * Returns
10470Sstevel@tonic-gate  *   _NO_RESOURCES
10480Sstevel@tonic-gate  *   _SUCCESS
10490Sstevel@tonic-gate  */
10500Sstevel@tonic-gate static int
10510Sstevel@tonic-gate snapshot_fill_children(rc_node_t *np)
10520Sstevel@tonic-gate {
10530Sstevel@tonic-gate 	rc_node_t *nnp;
10540Sstevel@tonic-gate 	rc_snapshot_t *sp, *oldsp;
10550Sstevel@tonic-gate 	rc_snaplevel_t *lvl;
10560Sstevel@tonic-gate 	rc_node_lookup_t nl;
10570Sstevel@tonic-gate 	int r;
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	/* Get the rc_snapshot_t (& its rc_snaplevel_t's). */
10600Sstevel@tonic-gate 	(void) pthread_mutex_lock(&np->rn_lock);
10610Sstevel@tonic-gate 	sp = np->rn_snapshot;
10620Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&np->rn_lock);
10630Sstevel@tonic-gate 	if (sp == NULL) {
10640Sstevel@tonic-gate 		r = rc_snapshot_get(np->rn_snapshot_id, &sp);
10650Sstevel@tonic-gate 		if (r != REP_PROTOCOL_SUCCESS) {
10660Sstevel@tonic-gate 			assert(r == REP_PROTOCOL_FAIL_NO_RESOURCES);
10670Sstevel@tonic-gate 			return (r);
10680Sstevel@tonic-gate 		}
10690Sstevel@tonic-gate 		(void) pthread_mutex_lock(&np->rn_lock);
10700Sstevel@tonic-gate 		oldsp = np->rn_snapshot;
10710Sstevel@tonic-gate 		assert(oldsp == NULL || oldsp == sp);
10720Sstevel@tonic-gate 		np->rn_snapshot = sp;
10730Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&np->rn_lock);
10740Sstevel@tonic-gate 		if (oldsp != NULL)
10750Sstevel@tonic-gate 			rc_snapshot_rele(oldsp);
10760Sstevel@tonic-gate 	}
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	bzero(&nl, sizeof (nl));
10790Sstevel@tonic-gate 	nl.rl_type = REP_PROTOCOL_ENTITY_SNAPLEVEL;
10800Sstevel@tonic-gate 	nl.rl_backend = np->rn_id.rl_backend;
10810Sstevel@tonic-gate 	nl.rl_ids[ID_SERVICE] = np->rn_id.rl_ids[ID_SERVICE];
10820Sstevel@tonic-gate 	nl.rl_ids[ID_INSTANCE] = np->rn_id.rl_ids[ID_INSTANCE];
10830Sstevel@tonic-gate 	nl.rl_ids[ID_NAME] = np->rn_id.rl_main_id;
10840Sstevel@tonic-gate 	nl.rl_ids[ID_SNAPSHOT] = np->rn_snapshot_id;
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	/* Create rc_node_t's for the snapshot's rc_snaplevel_t's. */
10870Sstevel@tonic-gate 	for (lvl = sp->rs_levels; lvl != NULL; lvl = lvl->rsl_next) {
10880Sstevel@tonic-gate 		nnp = rc_node_alloc();
10890Sstevel@tonic-gate 		assert(nnp != NULL);
10900Sstevel@tonic-gate 		nl.rl_main_id = lvl->rsl_level_id;
10910Sstevel@tonic-gate 		nnp = rc_node_setup_snaplevel(nnp, &nl, lvl, np);
10920Sstevel@tonic-gate 		rc_node_rele(nnp);
10930Sstevel@tonic-gate 	}
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate /*
10990Sstevel@tonic-gate  * Returns
11000Sstevel@tonic-gate  *   _NO_RESOURCES
11010Sstevel@tonic-gate  *   _SUCCESS
11020Sstevel@tonic-gate  */
11030Sstevel@tonic-gate static int
11040Sstevel@tonic-gate snaplevel_fill_children(rc_node_t *np)
11050Sstevel@tonic-gate {
11060Sstevel@tonic-gate 	rc_snaplevel_t *lvl = np->rn_snaplevel;
11070Sstevel@tonic-gate 	child_info_t ci;
11080Sstevel@tonic-gate 	int res;
11090Sstevel@tonic-gate 	backend_query_t *q;
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	(void) snaplevel_setup_child_info(np, REP_PROTOCOL_ENTITY_PROPERTYGRP,
11120Sstevel@tonic-gate 	    &ci);
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	q = backend_query_alloc();
11150Sstevel@tonic-gate 	backend_query_add(q,
11160Sstevel@tonic-gate 	    "SELECT snaplvl_pg_name, snaplvl_pg_id, snaplvl_gen_id, "
11170Sstevel@tonic-gate 	    "    snaplvl_pg_type, snaplvl_pg_flags "
11180Sstevel@tonic-gate 	    "    FROM snaplevel_lnk_tbl "
11190Sstevel@tonic-gate 	    "    WHERE (snaplvl_level_id = %d)",
11200Sstevel@tonic-gate 	    lvl->rsl_level_id);
11210Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_pg_callback, &ci);
11220Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
11230Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
11240Sstevel@tonic-gate 	backend_query_free(q);
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	return (res);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate /*
11300Sstevel@tonic-gate  * Returns
11310Sstevel@tonic-gate  *   _NO_RESOURCES
11320Sstevel@tonic-gate  *   _SUCCESS
11330Sstevel@tonic-gate  */
11340Sstevel@tonic-gate static int
11350Sstevel@tonic-gate propertygrp_fill_children(rc_node_t *np)
11360Sstevel@tonic-gate {
11370Sstevel@tonic-gate 	backend_query_t *q;
11380Sstevel@tonic-gate 	child_info_t ci;
11390Sstevel@tonic-gate 	int res;
11400Sstevel@tonic-gate 	backend_tx_t *tx;
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	backend_type_t backend = np->rn_id.rl_backend;
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 	(void) propertygrp_setup_child_info(np, REP_PROTOCOL_ENTITY_PROPERTY,
11450Sstevel@tonic-gate 	    &ci);
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 	res = backend_tx_begin_ro(backend, &tx);
11480Sstevel@tonic-gate 	if (res != REP_PROTOCOL_SUCCESS) {
11490Sstevel@tonic-gate 		/*
11500Sstevel@tonic-gate 		 * If the backend didn't exist, we wouldn't have got this
11510Sstevel@tonic-gate 		 * property group.
11520Sstevel@tonic-gate 		 */
11530Sstevel@tonic-gate 		assert(res != REP_PROTOCOL_FAIL_BACKEND_ACCESS);
11540Sstevel@tonic-gate 		return (res);
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	ci.ci_tx = tx;
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 	q = backend_query_alloc();
11600Sstevel@tonic-gate 	backend_query_add(q,
11610Sstevel@tonic-gate 	    "SELECT lnk_prop_name, lnk_prop_id, lnk_prop_type, lnk_val_id "
11620Sstevel@tonic-gate 	    "FROM prop_lnk_tbl "
11630Sstevel@tonic-gate 	    "WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)",
11640Sstevel@tonic-gate 	    np->rn_id.rl_main_id, np->rn_gen_id);
11650Sstevel@tonic-gate 	res = backend_tx_run(tx, q, fill_property_callback, &ci);
11660Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
11670Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
11680Sstevel@tonic-gate 	backend_query_free(q);
11690Sstevel@tonic-gate 	backend_tx_end_ro(tx);
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 	return (res);
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate /*
11750Sstevel@tonic-gate  * Fails with
11760Sstevel@tonic-gate  *   _TYPE_MISMATCH - lp is not for a service
11770Sstevel@tonic-gate  *   _INVALID_TYPE - lp has invalid type
11780Sstevel@tonic-gate  *   _BAD_REQUEST - name is invalid
11790Sstevel@tonic-gate  */
11800Sstevel@tonic-gate static int
11810Sstevel@tonic-gate scope_query_child(backend_query_t *q, rc_node_lookup_t *lp, const char *name)
11820Sstevel@tonic-gate {
11830Sstevel@tonic-gate 	uint32_t type = lp->rl_type;
11840Sstevel@tonic-gate 	int rc;
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_SERVICE)
11870Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 	if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS)
11900Sstevel@tonic-gate 		return (rc);
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	backend_query_add(q,
11930Sstevel@tonic-gate 	    "SELECT svc_id FROM service_tbl "
11940Sstevel@tonic-gate 	    "WHERE svc_name = '%q'",
11950Sstevel@tonic-gate 	    name);
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate /*
12010Sstevel@tonic-gate  * Fails with
12020Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
12030Sstevel@tonic-gate  */
12040Sstevel@tonic-gate static int
12050Sstevel@tonic-gate scope_insert_child(backend_tx_t *tx, rc_node_lookup_t *lp, const char *name)
12060Sstevel@tonic-gate {
12070Sstevel@tonic-gate 	return (backend_tx_run_update(tx,
12080Sstevel@tonic-gate 	    "INSERT INTO service_tbl (svc_id, svc_name) "
12090Sstevel@tonic-gate 	    "VALUES (%d, '%q')",
12100Sstevel@tonic-gate 	    lp->rl_main_id, name));
12110Sstevel@tonic-gate }
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate /*
12140Sstevel@tonic-gate  * Fails with
12150Sstevel@tonic-gate  *   _TYPE_MISMATCH - lp is not for an instance or property group
12160Sstevel@tonic-gate  *   _INVALID_TYPE - lp has invalid type
12170Sstevel@tonic-gate  *   _BAD_REQUEST - name is invalid
12180Sstevel@tonic-gate  */
12190Sstevel@tonic-gate static int
12200Sstevel@tonic-gate service_query_child(backend_query_t *q, rc_node_lookup_t *lp, const char *name)
12210Sstevel@tonic-gate {
12220Sstevel@tonic-gate 	uint32_t type = lp->rl_type;
12230Sstevel@tonic-gate 	int rc;
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_INSTANCE &&
12260Sstevel@tonic-gate 	    type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
12270Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS)
12300Sstevel@tonic-gate 		return (rc);
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	switch (type) {
12330Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE:
12340Sstevel@tonic-gate 		backend_query_add(q,
12350Sstevel@tonic-gate 		    "SELECT instance_id FROM instance_tbl "
12360Sstevel@tonic-gate 		    "WHERE instance_name = '%q' AND instance_svc = %d",
12370Sstevel@tonic-gate 		    name, lp->rl_ids[ID_SERVICE]);
12380Sstevel@tonic-gate 		break;
12390Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
12400Sstevel@tonic-gate 		backend_query_add(q,
12410Sstevel@tonic-gate 		    "SELECT pg_id FROM pg_tbl "
12420Sstevel@tonic-gate 		    "    WHERE pg_name = '%q' AND pg_parent_id = %d",
12430Sstevel@tonic-gate 		    name, lp->rl_ids[ID_SERVICE]);
12440Sstevel@tonic-gate 		break;
12450Sstevel@tonic-gate 	default:
12460Sstevel@tonic-gate 		assert(0);
12470Sstevel@tonic-gate 		abort();
12480Sstevel@tonic-gate 	}
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
12510Sstevel@tonic-gate }
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate /*
12540Sstevel@tonic-gate  * Fails with
12550Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
12560Sstevel@tonic-gate  */
12570Sstevel@tonic-gate static int
12580Sstevel@tonic-gate service_insert_child(backend_tx_t *tx, rc_node_lookup_t *lp, const char *name)
12590Sstevel@tonic-gate {
12600Sstevel@tonic-gate 	return (backend_tx_run_update(tx,
12610Sstevel@tonic-gate 	    "INSERT INTO instance_tbl "
12620Sstevel@tonic-gate 	    "    (instance_id, instance_name, instance_svc) "
12630Sstevel@tonic-gate 	    "VALUES (%d, '%q', %d)",
12640Sstevel@tonic-gate 	    lp->rl_main_id, name, lp->rl_ids[ID_SERVICE]));
12650Sstevel@tonic-gate }
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate /*
12680Sstevel@tonic-gate  * Fails with
12690Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
12700Sstevel@tonic-gate  */
12710Sstevel@tonic-gate static int
12720Sstevel@tonic-gate instance_insert_child(backend_tx_t *tx, rc_node_lookup_t *lp, const char *name)
12730Sstevel@tonic-gate {
12740Sstevel@tonic-gate 	return (backend_tx_run_update(tx,
12750Sstevel@tonic-gate 	    "INSERT INTO snapshot_lnk_tbl "
12760Sstevel@tonic-gate 	    "    (lnk_id, lnk_inst_id, lnk_snap_name, lnk_snap_id) "
12770Sstevel@tonic-gate 	    "VALUES (%d, %d, '%q', 0)",
12780Sstevel@tonic-gate 	    lp->rl_main_id, lp->rl_ids[ID_INSTANCE], name));
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate /*
12820Sstevel@tonic-gate  * Fails with
12830Sstevel@tonic-gate  *   _TYPE_MISMATCH - lp is not for a property group or snapshot
12840Sstevel@tonic-gate  *   _INVALID_TYPE - lp has invalid type
12850Sstevel@tonic-gate  *   _BAD_REQUEST - name is invalid
12860Sstevel@tonic-gate  */
12870Sstevel@tonic-gate static int
12880Sstevel@tonic-gate instance_query_child(backend_query_t *q, rc_node_lookup_t *lp, const char *name)
12890Sstevel@tonic-gate {
12900Sstevel@tonic-gate 	uint32_t type = lp->rl_type;
12910Sstevel@tonic-gate 	int rc;
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP &&
12940Sstevel@tonic-gate 	    type != REP_PROTOCOL_ENTITY_SNAPSHOT)
12950Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS)
12980Sstevel@tonic-gate 		return (rc);
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	switch (type) {
13010Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
13020Sstevel@tonic-gate 		backend_query_add(q,
13030Sstevel@tonic-gate 		    "SELECT pg_id FROM pg_tbl "
13040Sstevel@tonic-gate 		    "    WHERE pg_name = '%q' AND pg_parent_id = %d",
13050Sstevel@tonic-gate 		    name, lp->rl_ids[ID_INSTANCE]);
13060Sstevel@tonic-gate 		break;
13070Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
13080Sstevel@tonic-gate 		backend_query_add(q,
13090Sstevel@tonic-gate 		    "SELECT lnk_id FROM snapshot_lnk_tbl "
13100Sstevel@tonic-gate 		    "    WHERE lnk_snap_name = '%q' AND lnk_inst_id = %d",
13110Sstevel@tonic-gate 		    name, lp->rl_ids[ID_INSTANCE]);
13120Sstevel@tonic-gate 		break;
13130Sstevel@tonic-gate 	default:
13140Sstevel@tonic-gate 		assert(0);
13150Sstevel@tonic-gate 		abort();
13160Sstevel@tonic-gate 	}
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate static int
13220Sstevel@tonic-gate generic_insert_pg_child(backend_tx_t *tx, rc_node_lookup_t *lp,
13230Sstevel@tonic-gate     const char *name, const char *pgtype, uint32_t flags, uint32_t gen)
13240Sstevel@tonic-gate {
13250Sstevel@tonic-gate 	int parent_id = (lp->rl_ids[ID_INSTANCE] != 0)?
13260Sstevel@tonic-gate 	    lp->rl_ids[ID_INSTANCE] : lp->rl_ids[ID_SERVICE];
13270Sstevel@tonic-gate 	return (backend_tx_run_update(tx,
13280Sstevel@tonic-gate 	    "INSERT INTO pg_tbl "
13290Sstevel@tonic-gate 	    "    (pg_id, pg_name, pg_parent_id, pg_type, pg_flags, pg_gen_id) "
13300Sstevel@tonic-gate 	    "VALUES (%d, '%q', %d, '%q', %d, %d)",
13310Sstevel@tonic-gate 	    lp->rl_main_id, name, parent_id, pgtype, flags, gen));
13320Sstevel@tonic-gate }
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate static int
13350Sstevel@tonic-gate service_delete_start(rc_node_t *np, delete_info_t *dip)
13360Sstevel@tonic-gate {
13370Sstevel@tonic-gate 	int r;
13380Sstevel@tonic-gate 	backend_query_t *q = backend_query_alloc();
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	/*
13410Sstevel@tonic-gate 	 * Check for child instances, and refuse to delete if they exist.
13420Sstevel@tonic-gate 	 */
13430Sstevel@tonic-gate 	backend_query_add(q,
13440Sstevel@tonic-gate 	    "SELECT 1 FROM instance_tbl WHERE instance_svc = %d",
13450Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	r = backend_tx_run(dip->di_tx, q, backend_fail_if_seen, NULL);
13480Sstevel@tonic-gate 	backend_query_free(q);
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE)
13510Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_EXISTS);	/* instances exist */
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	return (delete_stack_push(dip, BACKEND_TYPE_NORMAL, &service_delete,
13540Sstevel@tonic-gate 	    np->rn_id.rl_main_id, 0));
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate static int
13580Sstevel@tonic-gate instance_delete_start(rc_node_t *np, delete_info_t *dip)
13590Sstevel@tonic-gate {
13600Sstevel@tonic-gate 	return (delete_stack_push(dip, BACKEND_TYPE_NORMAL, &instance_delete,
13610Sstevel@tonic-gate 	    np->rn_id.rl_main_id, 0));
13620Sstevel@tonic-gate }
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate static int
13650Sstevel@tonic-gate snapshot_delete_start(rc_node_t *np, delete_info_t *dip)
13660Sstevel@tonic-gate {
13670Sstevel@tonic-gate 	return (delete_stack_push(dip, BACKEND_TYPE_NORMAL,
13680Sstevel@tonic-gate 	    &snapshot_lnk_delete, np->rn_id.rl_main_id, 0));
13690Sstevel@tonic-gate }
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate static int
13720Sstevel@tonic-gate propertygrp_delete_start(rc_node_t *np, delete_info_t *dip)
13730Sstevel@tonic-gate {
13740Sstevel@tonic-gate 	return (delete_stack_push(dip, np->rn_id.rl_backend,
13750Sstevel@tonic-gate 	    &propertygrp_delete, np->rn_id.rl_main_id, 0));
13760Sstevel@tonic-gate }
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate static object_info_t info[] = {
13790Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_NONE},
13800Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_SCOPE,
13810Sstevel@tonic-gate 		BACKEND_ID_INVALID,
13820Sstevel@tonic-gate 		scope_fill_children,
13830Sstevel@tonic-gate 		scope_setup_child_info,
13840Sstevel@tonic-gate 		scope_query_child,
13850Sstevel@tonic-gate 		scope_insert_child,
13860Sstevel@tonic-gate 		NULL,
13870Sstevel@tonic-gate 		NULL,
13880Sstevel@tonic-gate 	},
13890Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_SERVICE,
13900Sstevel@tonic-gate 		BACKEND_ID_SERVICE_INSTANCE,
13910Sstevel@tonic-gate 		service_fill_children,
13920Sstevel@tonic-gate 		service_setup_child_info,
13930Sstevel@tonic-gate 		service_query_child,
13940Sstevel@tonic-gate 		service_insert_child,
13950Sstevel@tonic-gate 		generic_insert_pg_child,
13960Sstevel@tonic-gate 		service_delete_start,
13970Sstevel@tonic-gate 	},
13980Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_INSTANCE,
13990Sstevel@tonic-gate 		BACKEND_ID_SERVICE_INSTANCE,
14000Sstevel@tonic-gate 		instance_fill_children,
14010Sstevel@tonic-gate 		instance_setup_child_info,
14020Sstevel@tonic-gate 		instance_query_child,
14030Sstevel@tonic-gate 		instance_insert_child,
14040Sstevel@tonic-gate 		generic_insert_pg_child,
14050Sstevel@tonic-gate 		instance_delete_start,
14060Sstevel@tonic-gate 	},
14070Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_SNAPSHOT,
14080Sstevel@tonic-gate 		BACKEND_ID_SNAPNAME,
14090Sstevel@tonic-gate 		snapshot_fill_children,
14100Sstevel@tonic-gate 		NULL,
14110Sstevel@tonic-gate 		NULL,
14120Sstevel@tonic-gate 		NULL,
14130Sstevel@tonic-gate 		NULL,
14140Sstevel@tonic-gate 		snapshot_delete_start,
14150Sstevel@tonic-gate 	},
14160Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_SNAPLEVEL,
14170Sstevel@tonic-gate 		BACKEND_ID_SNAPLEVEL,
14180Sstevel@tonic-gate 		snaplevel_fill_children,
14190Sstevel@tonic-gate 		snaplevel_setup_child_info,
14200Sstevel@tonic-gate 	},
14210Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_PROPERTYGRP,
14220Sstevel@tonic-gate 		BACKEND_ID_PROPERTYGRP,
14230Sstevel@tonic-gate 		propertygrp_fill_children,
14240Sstevel@tonic-gate 		NULL,
14250Sstevel@tonic-gate 		NULL,
14260Sstevel@tonic-gate 		NULL,
14270Sstevel@tonic-gate 		NULL,
14280Sstevel@tonic-gate 		propertygrp_delete_start,
14290Sstevel@tonic-gate 	},
14300Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_PROPERTY},
14310Sstevel@tonic-gate 	{-1UL}
14320Sstevel@tonic-gate };
14330Sstevel@tonic-gate #define	NUM_INFO (sizeof (info) / sizeof (*info))
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate /*
14360Sstevel@tonic-gate  * object_fill_children() populates the child list of an rc_node_t by calling
14370Sstevel@tonic-gate  * the appropriate <type>_fill_children() which runs backend queries that
14380Sstevel@tonic-gate  * call an appropriate fill_*_callback() which takes a row of results,
14390Sstevel@tonic-gate  * decodes them, and calls an rc_node_setup*() function in rc_node.c to create
14400Sstevel@tonic-gate  * a child.
14410Sstevel@tonic-gate  *
14420Sstevel@tonic-gate  * Fails with
14430Sstevel@tonic-gate  *   _NO_RESOURCES
14440Sstevel@tonic-gate  */
14450Sstevel@tonic-gate int
14460Sstevel@tonic-gate object_fill_children(rc_node_t *pp)
14470Sstevel@tonic-gate {
14480Sstevel@tonic-gate 	uint32_t type = pp->rn_id.rl_type;
14490Sstevel@tonic-gate 	assert(type > 0 && type < NUM_INFO);
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	return ((*info[type].obj_fill_children)(pp));
14520Sstevel@tonic-gate }
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate int
14550Sstevel@tonic-gate object_delete(rc_node_t *pp)
14560Sstevel@tonic-gate {
14570Sstevel@tonic-gate 	int rc;
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	delete_info_t dip;
14600Sstevel@tonic-gate 	delete_ent_t de;
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	uint32_t type = pp->rn_id.rl_type;
14630Sstevel@tonic-gate 	assert(type > 0 && type < NUM_INFO);
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	if (info[type].obj_delete_start == NULL)
14660Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	(void) memset(&dip, '\0', sizeof (dip));
14690Sstevel@tonic-gate 	rc = backend_tx_begin(BACKEND_TYPE_NORMAL, &dip.di_tx);
14700Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS)
14710Sstevel@tonic-gate 		return (rc);
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 	rc = backend_tx_begin(BACKEND_TYPE_NONPERSIST, &dip.di_np_tx);
14740Sstevel@tonic-gate 	if (rc == REP_PROTOCOL_FAIL_BACKEND_ACCESS ||
14750Sstevel@tonic-gate 	    rc == REP_PROTOCOL_FAIL_BACKEND_READONLY)
14760Sstevel@tonic-gate 		dip.di_np_tx = NULL;
14770Sstevel@tonic-gate 	else if (rc != REP_PROTOCOL_SUCCESS) {
14780Sstevel@tonic-gate 		backend_tx_rollback(dip.di_tx);
14790Sstevel@tonic-gate 		return (rc);
14800Sstevel@tonic-gate 	}
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 	if ((rc = (*info[type].obj_delete_start)(pp, &dip)) !=
14830Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
14840Sstevel@tonic-gate 		goto fail;
14850Sstevel@tonic-gate 	}
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	while (delete_stack_pop(&dip, &de)) {
14880Sstevel@tonic-gate 		rc = (*de.de_cb)(&dip, &de);
14890Sstevel@tonic-gate 		if (rc != REP_PROTOCOL_SUCCESS)
14900Sstevel@tonic-gate 			goto fail;
14910Sstevel@tonic-gate 	}
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	rc = backend_tx_commit(dip.di_tx);
14940Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS)
14950Sstevel@tonic-gate 		backend_tx_rollback(dip.di_np_tx);
14960Sstevel@tonic-gate 	else if (dip.di_np_tx)
14970Sstevel@tonic-gate 		(void) backend_tx_commit(dip.di_np_tx);
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 	delete_stack_cleanup(&dip);
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	return (rc);
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate fail:
15040Sstevel@tonic-gate 	backend_tx_rollback(dip.di_tx);
15050Sstevel@tonic-gate 	backend_tx_rollback(dip.di_np_tx);
15060Sstevel@tonic-gate 	delete_stack_cleanup(&dip);
15070Sstevel@tonic-gate 	return (rc);
15080Sstevel@tonic-gate }
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate int
15110Sstevel@tonic-gate object_do_create(backend_tx_t *tx, child_info_t *cip, rc_node_t *pp,
15120Sstevel@tonic-gate     uint32_t type, const char *name, rc_node_t **cpp)
15130Sstevel@tonic-gate {
15140Sstevel@tonic-gate 	uint32_t ptype = pp->rn_id.rl_type;
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	backend_query_t *q;
15170Sstevel@tonic-gate 	uint32_t id;
15180Sstevel@tonic-gate 	rc_node_t *np = NULL;
15190Sstevel@tonic-gate 	int rc;
15200Sstevel@tonic-gate 	object_info_t *ip;
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cip->ci_base_nl;
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	assert(ptype > 0 && ptype < NUM_INFO);
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 	ip = &info[ptype];
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 	if (type == REP_PROTOCOL_ENTITY_PROPERTYGRP)
15290Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate 	if (ip->obj_setup_child_info == NULL ||
15320Sstevel@tonic-gate 	    ip->obj_query_child == NULL ||
15330Sstevel@tonic-gate 	    ip->obj_insert_child == NULL)
15340Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	if ((rc = (*ip->obj_setup_child_info)(pp, type, cip)) !=
15370Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS)
15380Sstevel@tonic-gate 		return (rc);
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 	q = backend_query_alloc();
15410Sstevel@tonic-gate 	if ((rc = (*ip->obj_query_child)(q, lp, name)) !=
15420Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
15430Sstevel@tonic-gate 		assert(rc == REP_PROTOCOL_FAIL_BAD_REQUEST);
15440Sstevel@tonic-gate 		backend_query_free(q);
15450Sstevel@tonic-gate 		return (rc);
15460Sstevel@tonic-gate 	}
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 	rc = backend_tx_run_single_int(tx, q, &id);
15490Sstevel@tonic-gate 	backend_query_free(q);
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	if (rc == REP_PROTOCOL_SUCCESS)
15520Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_EXISTS);
15530Sstevel@tonic-gate 	else if (rc != REP_PROTOCOL_FAIL_NOT_FOUND)
15540Sstevel@tonic-gate 		return (rc);
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate 	if ((lp->rl_main_id = backend_new_id(tx,
15570Sstevel@tonic-gate 	    info[type].obj_id_space)) == 0) {
15580Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	if ((np = rc_node_alloc()) == NULL)
15620Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	if ((rc = (*ip->obj_insert_child)(tx, lp, name)) !=
15650Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
15660Sstevel@tonic-gate 		rc_node_destroy(np);
15670Sstevel@tonic-gate 		return (rc);
15680Sstevel@tonic-gate 	}
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 	*cpp = np;
15710Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
15720Sstevel@tonic-gate }
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate /*
15750Sstevel@tonic-gate  * Fails with
15760Sstevel@tonic-gate  *   _NOT_APPLICABLE - type is _PROPERTYGRP
15770Sstevel@tonic-gate  *   _BAD_REQUEST - cannot create children for this type of node
15780Sstevel@tonic-gate  *		    name is invalid
15790Sstevel@tonic-gate  *   _TYPE_MISMATCH - object cannot have children of type type
15800Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory, or could not allocate new id
15810Sstevel@tonic-gate  *   _BACKEND_READONLY
15820Sstevel@tonic-gate  *   _BACKEND_ACCESS
15830Sstevel@tonic-gate  *   _EXISTS - child already exists
15840Sstevel@tonic-gate  */
15850Sstevel@tonic-gate int
15860Sstevel@tonic-gate object_create(rc_node_t *pp, uint32_t type, const char *name, rc_node_t **cpp)
15870Sstevel@tonic-gate {
15880Sstevel@tonic-gate 	backend_tx_t *tx;
15890Sstevel@tonic-gate 	rc_node_t *np = NULL;
15900Sstevel@tonic-gate 	child_info_t ci;
15910Sstevel@tonic-gate 	int rc;
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate 	if ((rc = backend_tx_begin(pp->rn_id.rl_backend, &tx)) !=
15940Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
15950Sstevel@tonic-gate 		return (rc);
15960Sstevel@tonic-gate 	}
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	if ((rc = object_do_create(tx, &ci, pp, type, name, &np)) !=
15990Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
16000Sstevel@tonic-gate 		backend_tx_rollback(tx);
16010Sstevel@tonic-gate 		return (rc);
16020Sstevel@tonic-gate 	}
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 	rc = backend_tx_commit(tx);
16050Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS) {
16060Sstevel@tonic-gate 		rc_node_destroy(np);
16070Sstevel@tonic-gate 		return (rc);
16080Sstevel@tonic-gate 	}
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	*cpp = rc_node_setup(np, &ci.ci_base_nl, name, ci.ci_parent);
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
16130Sstevel@tonic-gate }
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate /*ARGSUSED*/
16160Sstevel@tonic-gate int
16170Sstevel@tonic-gate object_create_pg(rc_node_t *pp, uint32_t type, const char *name,
16180Sstevel@tonic-gate     const char *pgtype, uint32_t flags, rc_node_t **cpp)
16190Sstevel@tonic-gate {
16200Sstevel@tonic-gate 	uint32_t ptype = pp->rn_id.rl_type;
16210Sstevel@tonic-gate 	backend_tx_t *tx_ro, *tx_wr;
16220Sstevel@tonic-gate 	backend_query_t *q;
16230Sstevel@tonic-gate 	uint32_t id;
16240Sstevel@tonic-gate 	uint32_t gen = 0;
16250Sstevel@tonic-gate 	rc_node_t *np = NULL;
16260Sstevel@tonic-gate 	int rc;
16270Sstevel@tonic-gate 	int rc_wr;
16280Sstevel@tonic-gate 	int rc_ro;
16290Sstevel@tonic-gate 	object_info_t *ip;
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	int nonpersist = (flags & SCF_PG_FLAG_NONPERSISTENT);
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	child_info_t ci;
16340Sstevel@tonic-gate 	rc_node_lookup_t *lp = &ci.ci_base_nl;
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	assert(ptype > 0 && ptype < NUM_INFO);
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 	if (ptype != REP_PROTOCOL_ENTITY_SERVICE &&
16390Sstevel@tonic-gate 	    ptype != REP_PROTOCOL_ENTITY_INSTANCE)
16400Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
16410Sstevel@tonic-gate 
16420Sstevel@tonic-gate 	ip = &info[ptype];
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	assert(ip->obj_setup_child_info != NULL &&
16450Sstevel@tonic-gate 	    ip->obj_query_child != NULL &&
16460Sstevel@tonic-gate 	    ip->obj_insert_pg_child != NULL);
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	if ((rc = (*ip->obj_setup_child_info)(pp, type, &ci)) !=
16490Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS)
16500Sstevel@tonic-gate 		return (rc);
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 	q = backend_query_alloc();
16530Sstevel@tonic-gate 	if ((rc = (*ip->obj_query_child)(q, lp, name)) !=
16540Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
16550Sstevel@tonic-gate 		backend_query_free(q);
16560Sstevel@tonic-gate 		return (rc);
16570Sstevel@tonic-gate 	}
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	if (!nonpersist) {
16600Sstevel@tonic-gate 		lp->rl_backend = BACKEND_TYPE_NORMAL;
16610Sstevel@tonic-gate 		rc_wr = backend_tx_begin(BACKEND_TYPE_NORMAL, &tx_wr);
16620Sstevel@tonic-gate 		rc_ro = backend_tx_begin_ro(BACKEND_TYPE_NONPERSIST, &tx_ro);
16630Sstevel@tonic-gate 	} else {
16640Sstevel@tonic-gate 		lp->rl_backend = BACKEND_TYPE_NONPERSIST;
16650Sstevel@tonic-gate 		rc_ro = backend_tx_begin_ro(BACKEND_TYPE_NORMAL, &tx_ro);
16660Sstevel@tonic-gate 		rc_wr = backend_tx_begin(BACKEND_TYPE_NONPERSIST, &tx_wr);
16670Sstevel@tonic-gate 	}
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 	if (rc_wr != REP_PROTOCOL_SUCCESS) {
16700Sstevel@tonic-gate 		rc = rc_wr;
16710Sstevel@tonic-gate 		goto fail;
16720Sstevel@tonic-gate 	}
16730Sstevel@tonic-gate 	if (rc_ro != REP_PROTOCOL_SUCCESS &&
16740Sstevel@tonic-gate 	    rc_ro != REP_PROTOCOL_FAIL_BACKEND_ACCESS) {
16750Sstevel@tonic-gate 		rc = rc_ro;
16760Sstevel@tonic-gate 		goto fail;
16770Sstevel@tonic-gate 	}
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 	if (tx_ro != NULL) {
16800Sstevel@tonic-gate 		rc = backend_tx_run_single_int(tx_ro, q, &id);
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 		if (rc == REP_PROTOCOL_SUCCESS) {
16830Sstevel@tonic-gate 			backend_query_free(q);
16840Sstevel@tonic-gate 			rc = REP_PROTOCOL_FAIL_EXISTS;
16850Sstevel@tonic-gate 			goto fail;
16860Sstevel@tonic-gate 		} else if (rc != REP_PROTOCOL_FAIL_NOT_FOUND) {
16870Sstevel@tonic-gate 			backend_query_free(q);
16880Sstevel@tonic-gate 			goto fail;
16890Sstevel@tonic-gate 		}
16900Sstevel@tonic-gate 	}
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	rc = backend_tx_run_single_int(tx_wr, q, &id);
16930Sstevel@tonic-gate 	backend_query_free(q);
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 	if (rc == REP_PROTOCOL_SUCCESS) {
16960Sstevel@tonic-gate 		rc = REP_PROTOCOL_FAIL_EXISTS;
16970Sstevel@tonic-gate 		goto fail;
16980Sstevel@tonic-gate 	} else if (rc != REP_PROTOCOL_FAIL_NOT_FOUND) {
16990Sstevel@tonic-gate 		goto fail;
17000Sstevel@tonic-gate 	}
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 	if (tx_ro != NULL)
17030Sstevel@tonic-gate 		backend_tx_end_ro(tx_ro);
17040Sstevel@tonic-gate 	tx_ro = NULL;
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate 	if ((lp->rl_main_id = backend_new_id(tx_wr,
17070Sstevel@tonic-gate 	    info[type].obj_id_space)) == 0) {
17080Sstevel@tonic-gate 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
17090Sstevel@tonic-gate 		goto fail;
17100Sstevel@tonic-gate 	}
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	if ((np = rc_node_alloc()) == NULL) {
17130Sstevel@tonic-gate 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
17140Sstevel@tonic-gate 		goto fail;
17150Sstevel@tonic-gate 	}
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	if ((rc = (*ip->obj_insert_pg_child)(tx_wr, lp, name, pgtype, flags,
17180Sstevel@tonic-gate 	    gen)) != REP_PROTOCOL_SUCCESS) {
17190Sstevel@tonic-gate 		rc_node_destroy(np);
17200Sstevel@tonic-gate 		goto fail;
17210Sstevel@tonic-gate 	}
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	rc = backend_tx_commit(tx_wr);
17240Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS) {
17250Sstevel@tonic-gate 		rc_node_destroy(np);
17260Sstevel@tonic-gate 		return (rc);
17270Sstevel@tonic-gate 	}
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	*cpp = rc_node_setup_pg(np, lp, name, pgtype, flags, gen, ci.ci_parent);
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate fail:
17340Sstevel@tonic-gate 	if (tx_ro != NULL)
17350Sstevel@tonic-gate 		backend_tx_end_ro(tx_ro);
17360Sstevel@tonic-gate 	if (tx_wr != NULL)
17370Sstevel@tonic-gate 		backend_tx_rollback(tx_wr);
17380Sstevel@tonic-gate 	return (rc);
17390Sstevel@tonic-gate }
17400Sstevel@tonic-gate 
17410Sstevel@tonic-gate /*
17420Sstevel@tonic-gate  * Given a row of snaplevel number, snaplevel id, service id, service name,
17430Sstevel@tonic-gate  * instance id, & instance name, create a rc_snaplevel_t & prepend it onto the
17440Sstevel@tonic-gate  * rs_levels list of the rc_snapshot_t passed in as data.
17450Sstevel@tonic-gate  * Returns _CONTINUE on success or _ABORT if any allocations fail.
17460Sstevel@tonic-gate  */
17470Sstevel@tonic-gate /*ARGSUSED*/
17480Sstevel@tonic-gate static int
17490Sstevel@tonic-gate fill_snapshot_cb(void *data, int columns, char **vals, char **names)
17500Sstevel@tonic-gate {
17510Sstevel@tonic-gate 	rc_snapshot_t *sp = data;
17520Sstevel@tonic-gate 	rc_snaplevel_t *lvl;
17530Sstevel@tonic-gate 	char *num = vals[0];
17540Sstevel@tonic-gate 	char *id = vals[1];
17550Sstevel@tonic-gate 	char *service_id = vals[2];
17560Sstevel@tonic-gate 	char *service = vals[3];
17570Sstevel@tonic-gate 	char *instance_id = vals[4];
17580Sstevel@tonic-gate 	char *instance = vals[5];
17590Sstevel@tonic-gate 	assert(columns == 6);
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 	lvl = uu_zalloc(sizeof (*lvl));
17620Sstevel@tonic-gate 	if (lvl == NULL)
17630Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
17640Sstevel@tonic-gate 	lvl->rsl_parent = sp;
17650Sstevel@tonic-gate 	lvl->rsl_next = sp->rs_levels;
17660Sstevel@tonic-gate 	sp->rs_levels = lvl;
17670Sstevel@tonic-gate 
1768407Sjwadams 	string_to_id(num, &lvl->rsl_level_num, "snap_level_num");
1769407Sjwadams 	string_to_id(id, &lvl->rsl_level_id, "snap_level_id");
1770407Sjwadams 	string_to_id(service_id, &lvl->rsl_service_id, "snap_level_service_id");
1771407Sjwadams 	if (instance_id != NULL)
1772407Sjwadams 		string_to_id(instance_id, &lvl->rsl_instance_id,
1773407Sjwadams 		    "snap_level_instance_id");
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	lvl->rsl_scope = (const char *)"localhost";
17760Sstevel@tonic-gate 	lvl->rsl_service = strdup(service);
17770Sstevel@tonic-gate 	if (lvl->rsl_service == NULL) {
17780Sstevel@tonic-gate 		uu_free(lvl);
17790Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
17800Sstevel@tonic-gate 	}
17810Sstevel@tonic-gate 	if (instance) {
17820Sstevel@tonic-gate 		assert(lvl->rsl_instance_id != 0);
17830Sstevel@tonic-gate 		lvl->rsl_instance = strdup(instance);
17840Sstevel@tonic-gate 		if (lvl->rsl_instance == NULL) {
17850Sstevel@tonic-gate 			free((void *)lvl->rsl_instance);
17860Sstevel@tonic-gate 			uu_free(lvl);
17870Sstevel@tonic-gate 			return (BACKEND_CALLBACK_ABORT);
17880Sstevel@tonic-gate 		}
17890Sstevel@tonic-gate 	} else {
17900Sstevel@tonic-gate 		assert(lvl->rsl_instance_id == 0);
17910Sstevel@tonic-gate 	}
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
17940Sstevel@tonic-gate }
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate /*
17970Sstevel@tonic-gate  * Populate sp's rs_levels list from the snaplevel_tbl table.
17980Sstevel@tonic-gate  * Fails with
17990Sstevel@tonic-gate  *   _NO_RESOURCES
18000Sstevel@tonic-gate  */
18010Sstevel@tonic-gate int
18020Sstevel@tonic-gate object_fill_snapshot(rc_snapshot_t *sp)
18030Sstevel@tonic-gate {
18040Sstevel@tonic-gate 	backend_query_t *q;
18050Sstevel@tonic-gate 	rc_snaplevel_t *sl;
18060Sstevel@tonic-gate 	int result;
18070Sstevel@tonic-gate 	int i;
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 	q = backend_query_alloc();
18100Sstevel@tonic-gate 	backend_query_add(q,
18110Sstevel@tonic-gate 	    "SELECT snap_level_num, snap_level_id, "
18120Sstevel@tonic-gate 	    "    snap_level_service_id, snap_level_service, "
18130Sstevel@tonic-gate 	    "    snap_level_instance_id, snap_level_instance "
18140Sstevel@tonic-gate 	    "FROM snaplevel_tbl "
18150Sstevel@tonic-gate 	    "WHERE snap_id = %d "
18160Sstevel@tonic-gate 	    "ORDER BY snap_level_id DESC",
18170Sstevel@tonic-gate 	    sp->rs_snap_id);
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 	result = backend_run(BACKEND_TYPE_NORMAL, q, fill_snapshot_cb, sp);
18200Sstevel@tonic-gate 	if (result == REP_PROTOCOL_DONE)
18210Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_NO_RESOURCES;
18220Sstevel@tonic-gate 	backend_query_free(q);
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS) {
18250Sstevel@tonic-gate 		i = 0;
18260Sstevel@tonic-gate 		for (sl = sp->rs_levels; sl != NULL; sl = sl->rsl_next) {
18270Sstevel@tonic-gate 			if (sl->rsl_level_num != ++i) {
18280Sstevel@tonic-gate 				backend_panic("snaplevels corrupt; expected "
18290Sstevel@tonic-gate 				    "level %d, got %d", i, sl->rsl_level_num);
18300Sstevel@tonic-gate 			}
18310Sstevel@tonic-gate 		}
18320Sstevel@tonic-gate 	}
18330Sstevel@tonic-gate 	return (result);
18340Sstevel@tonic-gate }
18350Sstevel@tonic-gate 
1836407Sjwadams /*
1837407Sjwadams  * This represents a property group in a snapshot.
1838407Sjwadams  */
1839407Sjwadams typedef struct check_snapshot_elem {
1840407Sjwadams 	uint32_t cse_parent;
1841407Sjwadams 	uint32_t cse_pg_id;
1842407Sjwadams 	uint32_t cse_pg_gen;
1843407Sjwadams 	char	cse_seen;
1844407Sjwadams } check_snapshot_elem_t;
1845407Sjwadams 
1846407Sjwadams #define	CSI_MAX_PARENTS		COMPOSITION_DEPTH
1847407Sjwadams typedef struct check_snapshot_info {
1848407Sjwadams 	size_t			csi_count;
1849407Sjwadams 	size_t			csi_array_size;
1850407Sjwadams 	check_snapshot_elem_t	*csi_array;
1851407Sjwadams 	size_t			csi_nparents;
1852407Sjwadams 	uint32_t		csi_parent_ids[CSI_MAX_PARENTS];
1853407Sjwadams } check_snapshot_info_t;
1854407Sjwadams 
1855407Sjwadams /*ARGSUSED*/
1856407Sjwadams static int
1857407Sjwadams check_snapshot_fill_cb(void *data, int columns, char **vals, char **names)
1858407Sjwadams {
1859407Sjwadams 	check_snapshot_info_t *csip = data;
1860407Sjwadams 	check_snapshot_elem_t *cur;
1861407Sjwadams 	const char *parent;
1862407Sjwadams 	const char *pg_id;
1863407Sjwadams 	const char *pg_gen_id;
1864407Sjwadams 
1865407Sjwadams 	if (columns == 1) {
1866407Sjwadams 		uint32_t *target;
1867407Sjwadams 
1868407Sjwadams 		if (csip->csi_nparents >= CSI_MAX_PARENTS)
1869407Sjwadams 			backend_panic("snaplevel table has too many elements");
1870407Sjwadams 
1871407Sjwadams 		target = &csip->csi_parent_ids[csip->csi_nparents++];
1872407Sjwadams 		string_to_id(vals[0], target, "snap_level_*_id");
1873407Sjwadams 
1874407Sjwadams 		return (BACKEND_CALLBACK_CONTINUE);
1875407Sjwadams 	}
1876407Sjwadams 
1877407Sjwadams 	assert(columns == 3);
1878407Sjwadams 
1879407Sjwadams 	parent = vals[0];
1880407Sjwadams 	pg_id = vals[1];
1881407Sjwadams 	pg_gen_id = vals[2];
1882407Sjwadams 
1883407Sjwadams 	if (csip->csi_count == csip->csi_array_size) {
1884407Sjwadams 		size_t newsz = (csip->csi_array_size > 0) ?
1885407Sjwadams 		    csip->csi_array_size * 2 : 8;
1886407Sjwadams 		check_snapshot_elem_t *new = uu_zalloc(newsz * sizeof (*new));
1887407Sjwadams 
1888407Sjwadams 		if (new == NULL)
1889407Sjwadams 			return (BACKEND_CALLBACK_ABORT);
1890407Sjwadams 
1891407Sjwadams 		(void) memcpy(new, csip->csi_array,
1892407Sjwadams 		    sizeof (*new) * csip->csi_array_size);
1893407Sjwadams 		uu_free(csip->csi_array);
1894407Sjwadams 		csip->csi_array = new;
1895407Sjwadams 		csip->csi_array_size = newsz;
1896407Sjwadams 	}
1897407Sjwadams 
1898407Sjwadams 	cur = &csip->csi_array[csip->csi_count++];
1899407Sjwadams 
1900407Sjwadams 	string_to_id(parent, &cur->cse_parent, "snap_level_*_id");
1901407Sjwadams 	string_to_id(pg_id, &cur->cse_pg_id, "snaplvl_pg_id");
1902407Sjwadams 	string_to_id(pg_gen_id, &cur->cse_pg_gen, "snaplvl_gen_id");
1903407Sjwadams 	cur->cse_seen = 0;
1904407Sjwadams 
1905407Sjwadams 	return (BACKEND_CALLBACK_CONTINUE);
1906407Sjwadams }
1907407Sjwadams 
1908407Sjwadams static int
1909407Sjwadams check_snapshot_elem_cmp(const void *lhs_arg, const void *rhs_arg)
1910407Sjwadams {
1911407Sjwadams 	const check_snapshot_elem_t *lhs = lhs_arg;
1912407Sjwadams 	const check_snapshot_elem_t *rhs = rhs_arg;
1913407Sjwadams 
1914407Sjwadams 	if (lhs->cse_parent < rhs->cse_parent)
1915407Sjwadams 		return (-1);
1916407Sjwadams 	if (lhs->cse_parent > rhs->cse_parent)
1917407Sjwadams 		return (1);
1918407Sjwadams 
1919407Sjwadams 	if (lhs->cse_pg_id < rhs->cse_pg_id)
1920407Sjwadams 		return (-1);
1921407Sjwadams 	if (lhs->cse_pg_id > rhs->cse_pg_id)
1922407Sjwadams 		return (1);
1923407Sjwadams 
1924407Sjwadams 	if (lhs->cse_pg_gen < rhs->cse_pg_gen)
1925407Sjwadams 		return (-1);
1926407Sjwadams 	if (lhs->cse_pg_gen > rhs->cse_pg_gen)
1927407Sjwadams 		return (1);
1928407Sjwadams 
1929407Sjwadams 	return (0);
1930407Sjwadams }
1931407Sjwadams 
1932407Sjwadams /*ARGSUSED*/
1933407Sjwadams static int
1934407Sjwadams check_snapshot_check_cb(void *data, int columns, char **vals, char **names)
1935407Sjwadams {
1936407Sjwadams 	check_snapshot_info_t *csip = data;
1937407Sjwadams 	check_snapshot_elem_t elem;
1938407Sjwadams 	check_snapshot_elem_t *cur;
1939407Sjwadams 
1940407Sjwadams 	const char *parent = vals[0];
1941407Sjwadams 	const char *pg_id = vals[1];
1942407Sjwadams 	const char *pg_gen_id = vals[2];
1943407Sjwadams 
1944407Sjwadams 	assert(columns == 3);
1945407Sjwadams 
1946407Sjwadams 	string_to_id(parent, &elem.cse_parent, "snap_level_*_id");
1947407Sjwadams 	string_to_id(pg_id, &elem.cse_pg_id, "snaplvl_pg_id");
1948407Sjwadams 	string_to_id(pg_gen_id, &elem.cse_pg_gen, "snaplvl_gen_id");
1949407Sjwadams 
1950407Sjwadams 	if ((cur = bsearch(&elem, csip->csi_array, csip->csi_count,
1951407Sjwadams 	    sizeof (*csip->csi_array), check_snapshot_elem_cmp)) == NULL)
1952407Sjwadams 		return (BACKEND_CALLBACK_ABORT);
1953407Sjwadams 
1954407Sjwadams 	if (cur->cse_seen)
1955407Sjwadams 		backend_panic("duplicate property group reported");
1956407Sjwadams 	cur->cse_seen = 1;
1957407Sjwadams 	return (BACKEND_CALLBACK_CONTINUE);
1958407Sjwadams }
1959407Sjwadams 
1960407Sjwadams /*
1961407Sjwadams  * Check that a snapshot matches up with the latest in the repository.
1962407Sjwadams  * Returns:
1963407Sjwadams  *	REP_PROTOCOL_SUCCESS		if it is up-to-date,
1964407Sjwadams  *	REP_PROTOCOL_DONE		if it is out-of-date, or
1965407Sjwadams  *	REP_PROTOCOL_FAIL_NO_RESOURCES	if we ran out of memory.
1966407Sjwadams  */
1967407Sjwadams static int
1968407Sjwadams object_check_snapshot(uint32_t snap_id)
1969407Sjwadams {
1970407Sjwadams 	check_snapshot_info_t csi;
1971407Sjwadams 	backend_query_t *q;
1972407Sjwadams 	int result;
1973407Sjwadams 	size_t idx;
1974407Sjwadams 
1975407Sjwadams 	/* if the snapshot has never been taken, it must be out of date. */
1976407Sjwadams 	if (snap_id == 0)
1977407Sjwadams 		return (REP_PROTOCOL_DONE);
1978407Sjwadams 
1979407Sjwadams 	(void) memset(&csi, '\0', sizeof (csi));
1980407Sjwadams 
1981407Sjwadams 	q = backend_query_alloc();
1982407Sjwadams 	backend_query_add(q,
1983407Sjwadams 	    "SELECT\n"
1984407Sjwadams 	    "    CASE snap_level_instance_id\n"
1985407Sjwadams 	    "        WHEN 0 THEN snap_level_service_id\n"
1986407Sjwadams 	    "        ELSE snap_level_instance_id\n"
1987407Sjwadams 	    "    END\n"
1988407Sjwadams 	    "FROM snaplevel_tbl\n"
1989407Sjwadams 	    "WHERE snap_id = %d;\n"
1990407Sjwadams 	    "\n"
1991407Sjwadams 	    "SELECT\n"
1992407Sjwadams 	    "    CASE snap_level_instance_id\n"
1993407Sjwadams 	    "        WHEN 0 THEN snap_level_service_id\n"
1994407Sjwadams 	    "        ELSE snap_level_instance_id\n"
1995407Sjwadams 	    "    END,\n"
1996407Sjwadams 	    "    snaplvl_pg_id,\n"
1997407Sjwadams 	    "    snaplvl_gen_id\n"
1998407Sjwadams 	    "FROM snaplevel_tbl, snaplevel_lnk_tbl\n"
1999407Sjwadams 	    "WHERE\n"
2000407Sjwadams 	    "    (snaplvl_level_id = snap_level_id AND\n"
2001407Sjwadams 	    "    snap_id = %d);",
2002407Sjwadams 	    snap_id, snap_id);
2003407Sjwadams 
2004407Sjwadams 	result = backend_run(BACKEND_TYPE_NORMAL, q, check_snapshot_fill_cb,
2005407Sjwadams 	    &csi);
2006407Sjwadams 	if (result == REP_PROTOCOL_DONE)
2007407Sjwadams 		result = REP_PROTOCOL_FAIL_NO_RESOURCES;
2008407Sjwadams 	backend_query_free(q);
2009407Sjwadams 
2010407Sjwadams 	if (result != REP_PROTOCOL_SUCCESS)
2011407Sjwadams 		goto fail;
2012407Sjwadams 
2013407Sjwadams 	if (csi.csi_count > 0) {
2014407Sjwadams 		qsort(csi.csi_array, csi.csi_count, sizeof (*csi.csi_array),
2015407Sjwadams 		    check_snapshot_elem_cmp);
2016407Sjwadams 	}
2017407Sjwadams 
2018407Sjwadams #if COMPOSITION_DEPTH == 2
2019407Sjwadams 	if (csi.csi_nparents != COMPOSITION_DEPTH) {
2020407Sjwadams 		result = REP_PROTOCOL_DONE;
2021407Sjwadams 		goto fail;
2022407Sjwadams 	}
2023407Sjwadams 
2024407Sjwadams 	q = backend_query_alloc();
2025407Sjwadams 	backend_query_add(q,
2026407Sjwadams 	    "SELECT "
2027407Sjwadams 	    "    pg_parent_id, pg_id, pg_gen_id "
2028407Sjwadams 	    "FROM "
2029407Sjwadams 	    "    pg_tbl "
2030407Sjwadams 	    "WHERE (pg_parent_id = %d OR pg_parent_id = %d)",
2031407Sjwadams 	    csi.csi_parent_ids[0], csi.csi_parent_ids[1]);
2032407Sjwadams 
2033407Sjwadams 	result = backend_run(BACKEND_TYPE_NORMAL, q, check_snapshot_check_cb,
2034407Sjwadams 	    &csi);
2035407Sjwadams #else
2036407Sjwadams #error This code must be updated
2037407Sjwadams #endif
2038407Sjwadams 	/*
2039407Sjwadams 	 * To succeed, the callback must not have aborted, and we must have
2040407Sjwadams 	 * found all of the items.
2041407Sjwadams 	 */
2042407Sjwadams 	if (result == REP_PROTOCOL_SUCCESS) {
2043407Sjwadams 		for (idx = 0; idx < csi.csi_count; idx++) {
2044407Sjwadams 			if (csi.csi_array[idx].cse_seen == 0) {
2045407Sjwadams 				result = REP_PROTOCOL_DONE;
2046407Sjwadams 				goto fail;
2047407Sjwadams 			}
2048407Sjwadams 		}
2049407Sjwadams 	}
2050407Sjwadams 
2051407Sjwadams fail:
2052407Sjwadams 	uu_free(csi.csi_array);
2053407Sjwadams 	return (result);
2054407Sjwadams }
2055407Sjwadams 
20560Sstevel@tonic-gate /*ARGSUSED*/
20570Sstevel@tonic-gate static int
20580Sstevel@tonic-gate object_copy_string(void *data_arg, int columns, char **vals, char **names)
20590Sstevel@tonic-gate {
20600Sstevel@tonic-gate 	char **data = data_arg;
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	assert(columns == 1);
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate 	if (*data != NULL)
20650Sstevel@tonic-gate 		free(*data);
20660Sstevel@tonic-gate 	*data = NULL;
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate 	if (vals[0] != NULL) {
20690Sstevel@tonic-gate 		if ((*data = strdup(vals[0])) == NULL)
20700Sstevel@tonic-gate 			return (BACKEND_CALLBACK_ABORT);
20710Sstevel@tonic-gate 	}
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
20740Sstevel@tonic-gate }
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate struct snaplevel_add_info {
20770Sstevel@tonic-gate 	backend_query_t *sai_q;
20780Sstevel@tonic-gate 	uint32_t	sai_level_id;
20790Sstevel@tonic-gate 	int		sai_used;		/* sai_q has been used */
20800Sstevel@tonic-gate };
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate /*ARGSUSED*/
20830Sstevel@tonic-gate static int
20840Sstevel@tonic-gate object_snaplevel_process_pg(void *data_arg, int columns, char **vals,
20850Sstevel@tonic-gate     char **names)
20860Sstevel@tonic-gate {
20870Sstevel@tonic-gate 	struct snaplevel_add_info *data = data_arg;
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 	assert(columns == 5);
20900Sstevel@tonic-gate 
20910Sstevel@tonic-gate 	backend_query_add(data->sai_q,
20920Sstevel@tonic-gate 	    "INSERT INTO snaplevel_lnk_tbl "
20930Sstevel@tonic-gate 	    "    (snaplvl_level_id, snaplvl_pg_id, snaplvl_pg_name, "
20940Sstevel@tonic-gate 	    "    snaplvl_pg_type, snaplvl_pg_flags, snaplvl_gen_id)"
20950Sstevel@tonic-gate 	    "VALUES (%d, %s, '%q', '%q', %s, %s);",
20960Sstevel@tonic-gate 	    data->sai_level_id, vals[0], vals[1], vals[2], vals[3], vals[4]);
20970Sstevel@tonic-gate 
20980Sstevel@tonic-gate 	data->sai_used = 1;
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
21010Sstevel@tonic-gate }
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate /*ARGSUSED*/
21040Sstevel@tonic-gate static int
21050Sstevel@tonic-gate object_snapshot_add_level(backend_tx_t *tx, uint32_t snap_id,
21060Sstevel@tonic-gate     uint32_t snap_level_num, uint32_t svc_id, const char *svc_name,
21070Sstevel@tonic-gate     uint32_t inst_id, const char *inst_name)
21080Sstevel@tonic-gate {
21090Sstevel@tonic-gate 	struct snaplevel_add_info data;
21100Sstevel@tonic-gate 	backend_query_t *q;
21110Sstevel@tonic-gate 	int result;
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate 	assert((snap_level_num == 1 && inst_name != NULL) ||
21140Sstevel@tonic-gate 	    snap_level_num == 2 && inst_name == NULL);
21150Sstevel@tonic-gate 
21160Sstevel@tonic-gate 	data.sai_level_id = backend_new_id(tx, BACKEND_ID_SNAPLEVEL);
21170Sstevel@tonic-gate 	if (data.sai_level_id == 0) {
21180Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
21190Sstevel@tonic-gate 	}
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate 	result = backend_tx_run_update(tx,
21220Sstevel@tonic-gate 	    "INSERT INTO snaplevel_tbl "
21230Sstevel@tonic-gate 	    "    (snap_id, snap_level_num, snap_level_id, "
21240Sstevel@tonic-gate 	    "    snap_level_service_id, snap_level_service, "
21250Sstevel@tonic-gate 	    "    snap_level_instance_id, snap_level_instance) "
21260Sstevel@tonic-gate 	    "VALUES (%d, %d, %d, %d, %Q, %d, %Q);",
21270Sstevel@tonic-gate 	    snap_id, snap_level_num, data.sai_level_id, svc_id, svc_name,
21280Sstevel@tonic-gate 	    inst_id, inst_name);
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 	q = backend_query_alloc();
21310Sstevel@tonic-gate 	backend_query_add(q,
21320Sstevel@tonic-gate 	    "SELECT pg_id, pg_name, pg_type, pg_flags, pg_gen_id FROM pg_tbl "
21330Sstevel@tonic-gate 	    "WHERE (pg_parent_id = %d);",
21340Sstevel@tonic-gate 	    (inst_name != NULL)? inst_id : svc_id);
21350Sstevel@tonic-gate 
21360Sstevel@tonic-gate 	data.sai_q = backend_query_alloc();
21370Sstevel@tonic-gate 	data.sai_used = 0;
21380Sstevel@tonic-gate 	result = backend_tx_run(tx, q, object_snaplevel_process_pg,
21390Sstevel@tonic-gate 	    &data);
21400Sstevel@tonic-gate 	backend_query_free(q);
21410Sstevel@tonic-gate 
21420Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS && data.sai_used != 0)
21430Sstevel@tonic-gate 		result = backend_tx_run(tx, data.sai_q, NULL, NULL);
21440Sstevel@tonic-gate 	backend_query_free(data.sai_q);
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate 	return (result);
21470Sstevel@tonic-gate }
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate /*
21500Sstevel@tonic-gate  * Fails with:
21510Sstevel@tonic-gate  *	_NO_RESOURCES - no new id or out of disk space
21520Sstevel@tonic-gate  *	_BACKEND_READONLY - persistent backend is read-only
21530Sstevel@tonic-gate  */
21540Sstevel@tonic-gate static int
21550Sstevel@tonic-gate object_snapshot_do_take(uint32_t instid, const char *inst_name,
21560Sstevel@tonic-gate     uint32_t svcid, const char *svc_name,
21570Sstevel@tonic-gate     backend_tx_t **tx_out, uint32_t *snapid_out)
21580Sstevel@tonic-gate {
21590Sstevel@tonic-gate 	backend_tx_t *tx;
21600Sstevel@tonic-gate 	backend_query_t *q;
21610Sstevel@tonic-gate 	int result;
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 	char *svc_name_alloc = NULL;
21640Sstevel@tonic-gate 	char *inst_name_alloc = NULL;
21650Sstevel@tonic-gate 	uint32_t snapid;
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	result = backend_tx_begin(BACKEND_TYPE_NORMAL, &tx);
21680Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
21690Sstevel@tonic-gate 		return (result);
21700Sstevel@tonic-gate 
21710Sstevel@tonic-gate 	snapid = backend_new_id(tx, BACKEND_ID_SNAPSHOT);
21720Sstevel@tonic-gate 	if (snapid == 0) {
21730Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_NO_RESOURCES;
21740Sstevel@tonic-gate 		goto fail;
21750Sstevel@tonic-gate 	}
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate 	if (svc_name == NULL) {
21780Sstevel@tonic-gate 		q = backend_query_alloc();
21790Sstevel@tonic-gate 		backend_query_add(q,
21800Sstevel@tonic-gate 		    "SELECT svc_name FROM service_tbl "
21810Sstevel@tonic-gate 		    "WHERE (svc_id = %d)", svcid);
21820Sstevel@tonic-gate 		result = backend_tx_run(tx, q, object_copy_string,
21830Sstevel@tonic-gate 		    &svc_name_alloc);
21840Sstevel@tonic-gate 		backend_query_free(q);
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 		svc_name = svc_name_alloc;
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 		if (result == REP_PROTOCOL_DONE) {
21890Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_NO_RESOURCES;
21900Sstevel@tonic-gate 			goto fail;
21910Sstevel@tonic-gate 		}
21920Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS && svc_name == NULL)
21930Sstevel@tonic-gate 			backend_panic("unable to find name for svc id %d\n",
21940Sstevel@tonic-gate 			    svcid);
21950Sstevel@tonic-gate 
21960Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
21970Sstevel@tonic-gate 			goto fail;
21980Sstevel@tonic-gate 	}
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 	if (inst_name == NULL) {
22010Sstevel@tonic-gate 		q = backend_query_alloc();
22020Sstevel@tonic-gate 		backend_query_add(q,
22030Sstevel@tonic-gate 		    "SELECT instance_name FROM instance_tbl "
22040Sstevel@tonic-gate 		    "WHERE (instance_id = %d)", instid);
22050Sstevel@tonic-gate 		result = backend_tx_run(tx, q, object_copy_string,
22060Sstevel@tonic-gate 		    &inst_name_alloc);
22070Sstevel@tonic-gate 		backend_query_free(q);
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 		inst_name = inst_name_alloc;
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 		if (result == REP_PROTOCOL_DONE) {
22120Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_NO_RESOURCES;
22130Sstevel@tonic-gate 			goto fail;
22140Sstevel@tonic-gate 		}
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS && inst_name == NULL)
22170Sstevel@tonic-gate 			backend_panic(
22180Sstevel@tonic-gate 			    "unable to find name for instance id %d\n", instid);
22190Sstevel@tonic-gate 
22200Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
22210Sstevel@tonic-gate 			goto fail;
22220Sstevel@tonic-gate 	}
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 	result = object_snapshot_add_level(tx, snapid, 1,
22250Sstevel@tonic-gate 	    svcid, svc_name, instid, inst_name);
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
22280Sstevel@tonic-gate 		goto fail;
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 	result = object_snapshot_add_level(tx, snapid, 2,
22310Sstevel@tonic-gate 	    svcid, svc_name, 0, NULL);
22320Sstevel@tonic-gate 
22330Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
22340Sstevel@tonic-gate 		goto fail;
22350Sstevel@tonic-gate 
22360Sstevel@tonic-gate 	*snapid_out = snapid;
22370Sstevel@tonic-gate 	*tx_out = tx;
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 	free(svc_name_alloc);
22400Sstevel@tonic-gate 	free(inst_name_alloc);
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate fail:
22450Sstevel@tonic-gate 	backend_tx_rollback(tx);
22460Sstevel@tonic-gate 	free(svc_name_alloc);
22470Sstevel@tonic-gate 	free(inst_name_alloc);
22480Sstevel@tonic-gate 	return (result);
22490Sstevel@tonic-gate }
22500Sstevel@tonic-gate 
22510Sstevel@tonic-gate /*
22520Sstevel@tonic-gate  * Fails with:
22530Sstevel@tonic-gate  *	_TYPE_MISMATCH - pp is not an instance
22540Sstevel@tonic-gate  *	_NO_RESOURCES - no new id or out of disk space
22550Sstevel@tonic-gate  *	_BACKEND_READONLY - persistent backend is read-only
22560Sstevel@tonic-gate  */
22570Sstevel@tonic-gate int
22580Sstevel@tonic-gate object_snapshot_take_new(rc_node_t *pp,
22590Sstevel@tonic-gate     const char *svc_name, const char *inst_name,
22600Sstevel@tonic-gate     const char *name, rc_node_t **outp)
22610Sstevel@tonic-gate {
22620Sstevel@tonic-gate 	rc_node_lookup_t *insti = &pp->rn_id;
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	uint32_t instid = insti->rl_main_id;
22650Sstevel@tonic-gate 	uint32_t svcid = insti->rl_ids[ID_SERVICE];
22660Sstevel@tonic-gate 	uint32_t snapid = 0;
22670Sstevel@tonic-gate 	backend_tx_t *tx = NULL;
22680Sstevel@tonic-gate 	child_info_t ci;
22690Sstevel@tonic-gate 	rc_node_t *np;
22700Sstevel@tonic-gate 	int result;
22710Sstevel@tonic-gate 
22720Sstevel@tonic-gate 	if (insti->rl_type != REP_PROTOCOL_ENTITY_INSTANCE)
22730Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 	result = object_snapshot_do_take(instid, inst_name, svcid, svc_name,
22760Sstevel@tonic-gate 	    &tx, &snapid);
22770Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
22780Sstevel@tonic-gate 		return (result);
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate 	if ((result = object_do_create(tx, &ci, pp,
22810Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SNAPSHOT, name, &np)) != REP_PROTOCOL_SUCCESS) {
22820Sstevel@tonic-gate 		backend_tx_rollback(tx);
22830Sstevel@tonic-gate 		return (result);
22840Sstevel@tonic-gate 	}
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate 	/*
22870Sstevel@tonic-gate 	 * link the new object to the new snapshot.
22880Sstevel@tonic-gate 	 */
22890Sstevel@tonic-gate 	np->rn_snapshot_id = snapid;
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 	result = backend_tx_run_update(tx,
22920Sstevel@tonic-gate 	    "UPDATE snapshot_lnk_tbl SET lnk_snap_id = %d WHERE lnk_id = %d;",
22930Sstevel@tonic-gate 	    snapid, ci.ci_base_nl.rl_main_id);
22940Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS) {
22950Sstevel@tonic-gate 		backend_tx_rollback(tx);
22960Sstevel@tonic-gate 		rc_node_destroy(np);
22970Sstevel@tonic-gate 		return (result);
22980Sstevel@tonic-gate 	}
22990Sstevel@tonic-gate 	result = backend_tx_commit(tx);
23000Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS) {
23010Sstevel@tonic-gate 		rc_node_destroy(np);
23020Sstevel@tonic-gate 		return (result);
23030Sstevel@tonic-gate 	}
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 	*outp = rc_node_setup(np, &ci.ci_base_nl, name, ci.ci_parent);
23060Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
23070Sstevel@tonic-gate }
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate /*
23100Sstevel@tonic-gate  * Fails with:
23110Sstevel@tonic-gate  *	_TYPE_MISMATCH - pp is not an instance
23120Sstevel@tonic-gate  *	_NO_RESOURCES - no new id or out of disk space
23130Sstevel@tonic-gate  *	_BACKEND_READONLY - persistent backend is read-only
23140Sstevel@tonic-gate  */
23150Sstevel@tonic-gate int
23160Sstevel@tonic-gate object_snapshot_attach(rc_node_lookup_t *snapi, uint32_t *snapid_ptr,
23170Sstevel@tonic-gate     int takesnap)
23180Sstevel@tonic-gate {
23190Sstevel@tonic-gate 	uint32_t svcid = snapi->rl_ids[ID_SERVICE];
23200Sstevel@tonic-gate 	uint32_t instid = snapi->rl_ids[ID_INSTANCE];
23210Sstevel@tonic-gate 	uint32_t snapid = *snapid_ptr;
23220Sstevel@tonic-gate 	uint32_t oldsnapid = 0;
23230Sstevel@tonic-gate 	backend_tx_t *tx = NULL;
23240Sstevel@tonic-gate 	backend_query_t *q;
23250Sstevel@tonic-gate 	int result;
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate 	delete_info_t dip;
23280Sstevel@tonic-gate 	delete_ent_t de;
23290Sstevel@tonic-gate 
23300Sstevel@tonic-gate 	if (snapi->rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT)
23310Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 	if (takesnap) {
2334407Sjwadams 		/* first, check that we're actually out of date */
2335407Sjwadams 		if (object_check_snapshot(snapid) == REP_PROTOCOL_SUCCESS)
2336407Sjwadams 			return (REP_PROTOCOL_SUCCESS);
2337407Sjwadams 
23380Sstevel@tonic-gate 		result = object_snapshot_do_take(instid, NULL,
23390Sstevel@tonic-gate 		    svcid, NULL, &tx, &snapid);
23400Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
23410Sstevel@tonic-gate 			return (result);
23420Sstevel@tonic-gate 	} else {
23430Sstevel@tonic-gate 		result = backend_tx_begin(BACKEND_TYPE_NORMAL, &tx);
23440Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
23450Sstevel@tonic-gate 			return (result);
23460Sstevel@tonic-gate 	}
23470Sstevel@tonic-gate 
23480Sstevel@tonic-gate 	q = backend_query_alloc();
23490Sstevel@tonic-gate 	backend_query_add(q,
23500Sstevel@tonic-gate 	    "SELECT lnk_snap_id FROM snapshot_lnk_tbl WHERE lnk_id = %d; "
23510Sstevel@tonic-gate 	    "UPDATE snapshot_lnk_tbl SET lnk_snap_id = %d WHERE lnk_id = %d;",
23520Sstevel@tonic-gate 	    snapi->rl_main_id, snapid, snapi->rl_main_id);
23530Sstevel@tonic-gate 	result = backend_tx_run_single_int(tx, q, &oldsnapid);
23540Sstevel@tonic-gate 	backend_query_free(q);
23550Sstevel@tonic-gate 
23560Sstevel@tonic-gate 	if (result == REP_PROTOCOL_FAIL_NOT_FOUND) {
23570Sstevel@tonic-gate 		backend_tx_rollback(tx);
23580Sstevel@tonic-gate 		backend_panic("unable to find snapshot id %d",
23590Sstevel@tonic-gate 		    snapi->rl_main_id);
23600Sstevel@tonic-gate 	}
23610Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
23620Sstevel@tonic-gate 		goto fail;
23630Sstevel@tonic-gate 
23640Sstevel@tonic-gate 	/*
23650Sstevel@tonic-gate 	 * Now we use the delete stack to handle the possible unreferencing
23660Sstevel@tonic-gate 	 * of oldsnapid.
23670Sstevel@tonic-gate 	 */
23680Sstevel@tonic-gate 	(void) memset(&dip, 0, sizeof (dip));
23690Sstevel@tonic-gate 	dip.di_tx = tx;
23700Sstevel@tonic-gate 	dip.di_np_tx = NULL;	/* no need for non-persistant backend */
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 	if ((result = delete_stack_push(&dip, BACKEND_TYPE_NORMAL,
23730Sstevel@tonic-gate 	    &snaplevel_tbl_delete, oldsnapid, 0)) != REP_PROTOCOL_SUCCESS)
23740Sstevel@tonic-gate 		goto fail;
23750Sstevel@tonic-gate 
23760Sstevel@tonic-gate 	while (delete_stack_pop(&dip, &de)) {
23770Sstevel@tonic-gate 		result = (*de.de_cb)(&dip, &de);
23780Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
23790Sstevel@tonic-gate 			goto fail;
23800Sstevel@tonic-gate 	}
23810Sstevel@tonic-gate 
23820Sstevel@tonic-gate 	result = backend_tx_commit(tx);
23830Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
23840Sstevel@tonic-gate 		goto fail;
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 	delete_stack_cleanup(&dip);
23870Sstevel@tonic-gate 	*snapid_ptr = snapid;
23880Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
23890Sstevel@tonic-gate 
23900Sstevel@tonic-gate fail:
23910Sstevel@tonic-gate 	backend_tx_rollback(tx);
23920Sstevel@tonic-gate 	delete_stack_cleanup(&dip);
23930Sstevel@tonic-gate 	return (result);
23940Sstevel@tonic-gate }
2395