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