xref: /onnv-gate/usr/src/cmd/svc/configd/file_object.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * file_object.c - enter objects into and load them from the backend
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * The primary entry points in this layer are object_create(),
33*0Sstevel@tonic-gate  * object_create_pg(), object_delete(), and object_fill_children().  They each
34*0Sstevel@tonic-gate  * take an rc_node_t and use the functions in the object_info_t info array for
35*0Sstevel@tonic-gate  * the node's type.
36*0Sstevel@tonic-gate  */
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #include <assert.h>
39*0Sstevel@tonic-gate #include <pthread.h>
40*0Sstevel@tonic-gate #include <stdio.h>
41*0Sstevel@tonic-gate #include <stdlib.h>
42*0Sstevel@tonic-gate #include <string.h>
43*0Sstevel@tonic-gate #include <strings.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include "configd.h"
46*0Sstevel@tonic-gate #include "repcache_protocol.h"
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate typedef struct child_info {
49*0Sstevel@tonic-gate 	rc_node_t	*ci_parent;
50*0Sstevel@tonic-gate 	backend_tx_t	*ci_tx;			/* only for properties */
51*0Sstevel@tonic-gate 	rc_node_lookup_t ci_base_nl;
52*0Sstevel@tonic-gate } child_info_t;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate typedef struct delete_ent delete_ent_t;
55*0Sstevel@tonic-gate typedef struct delete_stack delete_stack_t;
56*0Sstevel@tonic-gate typedef struct delete_info delete_info_t;
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate typedef int	delete_cb_func(delete_info_t *, const delete_ent_t *);
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate struct delete_ent {
61*0Sstevel@tonic-gate 	delete_cb_func	*de_cb;		/* callback */
62*0Sstevel@tonic-gate 	uint32_t	de_backend;
63*0Sstevel@tonic-gate 	uint32_t	de_id;
64*0Sstevel@tonic-gate 	uint32_t	de_gen;		/* only for property groups */
65*0Sstevel@tonic-gate };
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate struct delete_stack {
68*0Sstevel@tonic-gate 	struct delete_stack *ds_next;
69*0Sstevel@tonic-gate 	uint32_t	ds_size;	/* number of elements */
70*0Sstevel@tonic-gate 	uint32_t	ds_cur;		/* current offset */
71*0Sstevel@tonic-gate 	delete_ent_t	ds_buf[1];	/* actually ds_size */
72*0Sstevel@tonic-gate };
73*0Sstevel@tonic-gate #define	DELETE_STACK_SIZE(x)	offsetof(delete_stack_t, ds_buf[(x)])
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate struct delete_info {
76*0Sstevel@tonic-gate 	backend_tx_t	*di_tx;
77*0Sstevel@tonic-gate 	backend_tx_t	*di_np_tx;
78*0Sstevel@tonic-gate 	delete_stack_t	*di_stack;
79*0Sstevel@tonic-gate 	delete_stack_t	*di_free;
80*0Sstevel@tonic-gate };
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate typedef struct object_info {
83*0Sstevel@tonic-gate 	uint32_t	obj_type;
84*0Sstevel@tonic-gate 	enum id_space	obj_id_space;
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	int (*obj_fill_children)(rc_node_t *);
87*0Sstevel@tonic-gate 	int (*obj_setup_child_info)(rc_node_t *, uint32_t, child_info_t *);
88*0Sstevel@tonic-gate 	int (*obj_query_child)(backend_query_t *, rc_node_lookup_t *,
89*0Sstevel@tonic-gate 	    const char *);
90*0Sstevel@tonic-gate 	int (*obj_insert_child)(backend_tx_t *, rc_node_lookup_t *,
91*0Sstevel@tonic-gate 	    const char *);
92*0Sstevel@tonic-gate 	int (*obj_insert_pg_child)(backend_tx_t *, rc_node_lookup_t *,
93*0Sstevel@tonic-gate 	    const char *, const char *, uint32_t, uint32_t);
94*0Sstevel@tonic-gate 	int (*obj_delete_start)(rc_node_t *, delete_info_t *);
95*0Sstevel@tonic-gate } object_info_t;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate #define	NUM_NEEDED	50
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate static int
100*0Sstevel@tonic-gate delete_stack_push(delete_info_t *dip, uint32_t be, delete_cb_func *cb,
101*0Sstevel@tonic-gate     uint32_t id, uint32_t gen)
102*0Sstevel@tonic-gate {
103*0Sstevel@tonic-gate 	delete_stack_t *cur = dip->di_stack;
104*0Sstevel@tonic-gate 	delete_ent_t *ent;
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	if (cur == NULL || cur->ds_cur == cur->ds_size) {
107*0Sstevel@tonic-gate 		delete_stack_t *new = dip->di_free;
108*0Sstevel@tonic-gate 		dip->di_free = NULL;
109*0Sstevel@tonic-gate 		if (new == NULL) {
110*0Sstevel@tonic-gate 			new = uu_zalloc(DELETE_STACK_SIZE(NUM_NEEDED));
111*0Sstevel@tonic-gate 			if (new == NULL)
112*0Sstevel@tonic-gate 				return (REP_PROTOCOL_FAIL_NO_RESOURCES);
113*0Sstevel@tonic-gate 			new->ds_size = NUM_NEEDED;
114*0Sstevel@tonic-gate 		}
115*0Sstevel@tonic-gate 		new->ds_cur = 0;
116*0Sstevel@tonic-gate 		new->ds_next = dip->di_stack;
117*0Sstevel@tonic-gate 		dip->di_stack = new;
118*0Sstevel@tonic-gate 		cur = new;
119*0Sstevel@tonic-gate 	}
120*0Sstevel@tonic-gate 	assert(cur->ds_cur < cur->ds_size);
121*0Sstevel@tonic-gate 	ent = &cur->ds_buf[cur->ds_cur++];
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	ent->de_backend = be;
124*0Sstevel@tonic-gate 	ent->de_cb = cb;
125*0Sstevel@tonic-gate 	ent->de_id = id;
126*0Sstevel@tonic-gate 	ent->de_gen = gen;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate static int
132*0Sstevel@tonic-gate delete_stack_pop(delete_info_t *dip, delete_ent_t *out)
133*0Sstevel@tonic-gate {
134*0Sstevel@tonic-gate 	delete_stack_t *cur = dip->di_stack;
135*0Sstevel@tonic-gate 	delete_ent_t *ent;
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	if (cur == NULL)
138*0Sstevel@tonic-gate 		return (NULL);
139*0Sstevel@tonic-gate 	assert(cur->ds_cur > 0 && cur->ds_cur <= cur->ds_size);
140*0Sstevel@tonic-gate 	ent = &cur->ds_buf[--cur->ds_cur];
141*0Sstevel@tonic-gate 	if (cur->ds_cur == 0) {
142*0Sstevel@tonic-gate 		dip->di_stack = cur->ds_next;
143*0Sstevel@tonic-gate 		cur->ds_next = NULL;
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 		if (dip->di_free != NULL)
146*0Sstevel@tonic-gate 			uu_free(dip->di_free);
147*0Sstevel@tonic-gate 		dip->di_free = cur;
148*0Sstevel@tonic-gate 	}
149*0Sstevel@tonic-gate 	if (ent == NULL)
150*0Sstevel@tonic-gate 		return (0);
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	*out = *ent;
153*0Sstevel@tonic-gate 	return (1);
154*0Sstevel@tonic-gate }
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate static void
157*0Sstevel@tonic-gate delete_stack_cleanup(delete_info_t *dip)
158*0Sstevel@tonic-gate {
159*0Sstevel@tonic-gate 	delete_stack_t *cur;
160*0Sstevel@tonic-gate 	while ((cur = dip->di_stack) != NULL) {
161*0Sstevel@tonic-gate 		dip->di_stack = cur->ds_next;
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 		uu_free(cur);
164*0Sstevel@tonic-gate 	}
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	if ((cur = dip->di_free) != NULL) {
167*0Sstevel@tonic-gate 		assert(cur->ds_next == NULL);	/* should only be one */
168*0Sstevel@tonic-gate 		uu_free(cur);
169*0Sstevel@tonic-gate 		dip->di_free = NULL;
170*0Sstevel@tonic-gate 	}
171*0Sstevel@tonic-gate }
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate struct delete_cb_info {
174*0Sstevel@tonic-gate 	delete_info_t	*dci_dip;
175*0Sstevel@tonic-gate 	uint32_t	dci_be;
176*0Sstevel@tonic-gate 	delete_cb_func	*dci_cb;
177*0Sstevel@tonic-gate 	int		dci_result;
178*0Sstevel@tonic-gate };
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /*ARGSUSED*/
181*0Sstevel@tonic-gate static int
182*0Sstevel@tonic-gate push_delete_callback(void *data, int columns, char **vals, char **names)
183*0Sstevel@tonic-gate {
184*0Sstevel@tonic-gate 	struct delete_cb_info *info = data;
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	const char *id_str = *vals++;
187*0Sstevel@tonic-gate 	const char *gen_str = *vals++;
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	uint32_t id;
190*0Sstevel@tonic-gate 	uint32_t gen;
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	assert(columns == 2);
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	if (uu_strtouint(id_str, &id, sizeof (id), 0, 0, 0) == -1)
195*0Sstevel@tonic-gate 		backend_panic("invalid integer in database");
196*0Sstevel@tonic-gate 	if (uu_strtouint(gen_str, &gen, sizeof (gen), 0, 0, 0) == -1)
197*0Sstevel@tonic-gate 		backend_panic("invalid integer in database");
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate 	info->dci_result = delete_stack_push(info->dci_dip, info->dci_be,
200*0Sstevel@tonic-gate 	    info->dci_cb, id, gen);
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	if (info->dci_result != REP_PROTOCOL_SUCCESS)
203*0Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
204*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
205*0Sstevel@tonic-gate }
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate static int
208*0Sstevel@tonic-gate value_delete(delete_info_t *dip, const delete_ent_t *ent)
209*0Sstevel@tonic-gate {
210*0Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
211*0Sstevel@tonic-gate 	int r;
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	backend_query_t *q;
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
216*0Sstevel@tonic-gate 	    dip->di_np_tx;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	q = backend_query_alloc();
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	backend_query_add(q,
221*0Sstevel@tonic-gate 	    "SELECT 1 FROM prop_lnk_tbl WHERE (lnk_val_id = %d); "
222*0Sstevel@tonic-gate 	    "DELETE FROM value_tbl WHERE (value_id = %d); ",
223*0Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
224*0Sstevel@tonic-gate 	r = backend_tx_run(tx, q, backend_fail_if_seen, NULL);
225*0Sstevel@tonic-gate 	backend_query_free(q);
226*0Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE)
227*0Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);		/* still in use */
228*0Sstevel@tonic-gate 	return (r);
229*0Sstevel@tonic-gate }
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate static int
232*0Sstevel@tonic-gate pg_lnk_tbl_delete(delete_info_t *dip, const delete_ent_t *ent)
233*0Sstevel@tonic-gate {
234*0Sstevel@tonic-gate 	struct delete_cb_info info;
235*0Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
236*0Sstevel@tonic-gate 	int r;
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	backend_query_t *q;
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
241*0Sstevel@tonic-gate 	    dip->di_np_tx;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	/*
244*0Sstevel@tonic-gate 	 * For non-persistent backends, we could only have one parent, and
245*0Sstevel@tonic-gate 	 * he's already been deleted.
246*0Sstevel@tonic-gate 	 *
247*0Sstevel@tonic-gate 	 * For normal backends, we need to check to see if we're in
248*0Sstevel@tonic-gate 	 * a snapshot or are the active generation for the property
249*0Sstevel@tonic-gate 	 * group.  If we are, there's nothing to be done.
250*0Sstevel@tonic-gate 	 */
251*0Sstevel@tonic-gate 	if (be == BACKEND_TYPE_NORMAL) {
252*0Sstevel@tonic-gate 		q = backend_query_alloc();
253*0Sstevel@tonic-gate 		backend_query_add(q,
254*0Sstevel@tonic-gate 		    "SELECT 1 "
255*0Sstevel@tonic-gate 		    "FROM pg_tbl "
256*0Sstevel@tonic-gate 		    "WHERE (pg_id = %d AND pg_gen_id = %d); "
257*0Sstevel@tonic-gate 		    "SELECT 1 "
258*0Sstevel@tonic-gate 		    "FROM snaplevel_lnk_tbl "
259*0Sstevel@tonic-gate 		    "WHERE (snaplvl_pg_id = %d AND snaplvl_gen_id = %d);",
260*0Sstevel@tonic-gate 		    ent->de_id, ent->de_gen,
261*0Sstevel@tonic-gate 		    ent->de_id, ent->de_gen);
262*0Sstevel@tonic-gate 		r = backend_tx_run(tx, q, backend_fail_if_seen, NULL);
263*0Sstevel@tonic-gate 		backend_query_free(q);
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 		if (r == REP_PROTOCOL_DONE)
266*0Sstevel@tonic-gate 			return (REP_PROTOCOL_SUCCESS);	/* still in use */
267*0Sstevel@tonic-gate 	}
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	info.dci_dip = dip;
270*0Sstevel@tonic-gate 	info.dci_be =  be;
271*0Sstevel@tonic-gate 	info.dci_cb = &value_delete;
272*0Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	q = backend_query_alloc();
275*0Sstevel@tonic-gate 	backend_query_add(q,
276*0Sstevel@tonic-gate 	    "SELECT DISTINCT lnk_val_id, 0 FROM prop_lnk_tbl "
277*0Sstevel@tonic-gate 	    "WHERE "
278*0Sstevel@tonic-gate 	    "    (lnk_pg_id = %d AND lnk_gen_id = %d AND lnk_val_id NOTNULL); "
279*0Sstevel@tonic-gate 	    "DELETE FROM prop_lnk_tbl "
280*0Sstevel@tonic-gate 	    "WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)",
281*0Sstevel@tonic-gate 	    ent->de_id, ent->de_gen, ent->de_id, ent->de_gen);
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	r = backend_tx_run(tx, q, push_delete_callback, &info);
284*0Sstevel@tonic-gate 	backend_query_free(q);
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
287*0Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
288*0Sstevel@tonic-gate 		return (info.dci_result);
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 	return (r);
291*0Sstevel@tonic-gate }
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate static int
294*0Sstevel@tonic-gate propertygrp_delete(delete_info_t *dip, const delete_ent_t *ent)
295*0Sstevel@tonic-gate {
296*0Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
297*0Sstevel@tonic-gate 	backend_query_t *q;
298*0Sstevel@tonic-gate 	uint32_t gen;
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	int r;
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
303*0Sstevel@tonic-gate 	    dip->di_np_tx;
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	q = backend_query_alloc();
306*0Sstevel@tonic-gate 	backend_query_add(q,
307*0Sstevel@tonic-gate 	    "SELECT pg_gen_id FROM pg_tbl WHERE pg_id = %d; "
308*0Sstevel@tonic-gate 	    "DELETE FROM pg_tbl WHERE pg_id = %d",
309*0Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
310*0Sstevel@tonic-gate 	r = backend_tx_run_single_int(tx, q, &gen);
311*0Sstevel@tonic-gate 	backend_query_free(q);
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
314*0Sstevel@tonic-gate 		return (r);
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	return (delete_stack_push(dip, be, &pg_lnk_tbl_delete,
317*0Sstevel@tonic-gate 	    ent->de_id, gen));
318*0Sstevel@tonic-gate }
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate static int
321*0Sstevel@tonic-gate snaplevel_lnk_delete(delete_info_t *dip, const delete_ent_t *ent)
322*0Sstevel@tonic-gate {
323*0Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
324*0Sstevel@tonic-gate 	backend_query_t *q;
325*0Sstevel@tonic-gate 	struct delete_cb_info info;
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	int r;
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
330*0Sstevel@tonic-gate 	    dip->di_np_tx;
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	info.dci_dip = dip;
333*0Sstevel@tonic-gate 	info.dci_be = be;
334*0Sstevel@tonic-gate 	info.dci_cb = &pg_lnk_tbl_delete;
335*0Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	q = backend_query_alloc();
338*0Sstevel@tonic-gate 	backend_query_add(q,
339*0Sstevel@tonic-gate 	    "SELECT snaplvl_pg_id, snaplvl_gen_id "
340*0Sstevel@tonic-gate 	    "    FROM snaplevel_lnk_tbl "
341*0Sstevel@tonic-gate 	    "    WHERE snaplvl_level_id = %d; "
342*0Sstevel@tonic-gate 	    "DELETE FROM snaplevel_lnk_tbl WHERE snaplvl_level_id = %d",
343*0Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
344*0Sstevel@tonic-gate 	r = backend_tx_run(tx, q, push_delete_callback, &info);
345*0Sstevel@tonic-gate 	backend_query_free(q);
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
348*0Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
349*0Sstevel@tonic-gate 		return (info.dci_result);
350*0Sstevel@tonic-gate 	}
351*0Sstevel@tonic-gate 	return (r);
352*0Sstevel@tonic-gate }
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate static int
355*0Sstevel@tonic-gate snaplevel_tbl_delete(delete_info_t *dip, const delete_ent_t *ent)
356*0Sstevel@tonic-gate {
357*0Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
358*0Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
359*0Sstevel@tonic-gate 	    dip->di_np_tx;
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	struct delete_cb_info info;
362*0Sstevel@tonic-gate 	backend_query_t *q;
363*0Sstevel@tonic-gate 	int r;
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 	assert(be == BACKEND_TYPE_NORMAL);
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	q = backend_query_alloc();
368*0Sstevel@tonic-gate 	backend_query_add(q,
369*0Sstevel@tonic-gate 	    "SELECT 1 FROM snapshot_lnk_tbl WHERE lnk_snap_id = %d",
370*0Sstevel@tonic-gate 	    ent->de_id);
371*0Sstevel@tonic-gate 	r = backend_tx_run(tx, q, backend_fail_if_seen, NULL);
372*0Sstevel@tonic-gate 	backend_query_free(q);
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE)
375*0Sstevel@tonic-gate 		return (REP_PROTOCOL_SUCCESS);		/* still in use */
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	info.dci_dip = dip;
378*0Sstevel@tonic-gate 	info.dci_be = be;
379*0Sstevel@tonic-gate 	info.dci_cb = &snaplevel_lnk_delete;
380*0Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	q = backend_query_alloc();
383*0Sstevel@tonic-gate 	backend_query_add(q,
384*0Sstevel@tonic-gate 	    "SELECT snap_level_id, 0 FROM snaplevel_tbl WHERE snap_id = %d;"
385*0Sstevel@tonic-gate 	    "DELETE FROM snaplevel_tbl WHERE snap_id = %d",
386*0Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
387*0Sstevel@tonic-gate 	r = backend_tx_run(tx, q, push_delete_callback, &info);
388*0Sstevel@tonic-gate 	backend_query_free(q);
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
391*0Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
392*0Sstevel@tonic-gate 		return (info.dci_result);
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate 	return (r);
395*0Sstevel@tonic-gate }
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate static int
398*0Sstevel@tonic-gate snapshot_lnk_delete(delete_info_t *dip, const delete_ent_t *ent)
399*0Sstevel@tonic-gate {
400*0Sstevel@tonic-gate 	uint32_t be = ent->de_backend;
401*0Sstevel@tonic-gate 	backend_tx_t *tx = (be == BACKEND_TYPE_NORMAL)? dip->di_tx :
402*0Sstevel@tonic-gate 	    dip->di_np_tx;
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	backend_query_t *q;
405*0Sstevel@tonic-gate 	uint32_t snapid;
406*0Sstevel@tonic-gate 	int r;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	assert(be == BACKEND_TYPE_NORMAL);
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	q = backend_query_alloc();
411*0Sstevel@tonic-gate 	backend_query_add(q,
412*0Sstevel@tonic-gate 	    "SELECT lnk_snap_id FROM snapshot_lnk_tbl WHERE lnk_id = %d; "
413*0Sstevel@tonic-gate 	    "DELETE FROM snapshot_lnk_tbl WHERE lnk_id = %d",
414*0Sstevel@tonic-gate 	    ent->de_id, ent->de_id);
415*0Sstevel@tonic-gate 	r = backend_tx_run_single_int(tx, q, &snapid);
416*0Sstevel@tonic-gate 	backend_query_free(q);
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
419*0Sstevel@tonic-gate 		return (r);
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	return (delete_stack_push(dip, be, &snaplevel_tbl_delete, snapid, 0));
422*0Sstevel@tonic-gate }
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate static int
425*0Sstevel@tonic-gate pgparent_delete_add_pgs(delete_info_t *dip, uint32_t parent_id)
426*0Sstevel@tonic-gate {
427*0Sstevel@tonic-gate 	struct delete_cb_info info;
428*0Sstevel@tonic-gate 	backend_query_t *q;
429*0Sstevel@tonic-gate 	int r;
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	info.dci_dip = dip;
432*0Sstevel@tonic-gate 	info.dci_be = BACKEND_TYPE_NORMAL;
433*0Sstevel@tonic-gate 	info.dci_cb = &propertygrp_delete;
434*0Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	q = backend_query_alloc();
437*0Sstevel@tonic-gate 	backend_query_add(q,
438*0Sstevel@tonic-gate 	    "SELECT pg_id, 0 FROM pg_tbl WHERE pg_parent_id = %d",
439*0Sstevel@tonic-gate 	    parent_id);
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	r = backend_tx_run(dip->di_tx, q, push_delete_callback, &info);
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
444*0Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
445*0Sstevel@tonic-gate 		backend_query_free(q);
446*0Sstevel@tonic-gate 		return (info.dci_result);
447*0Sstevel@tonic-gate 	}
448*0Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS) {
449*0Sstevel@tonic-gate 		backend_query_free(q);
450*0Sstevel@tonic-gate 		return (r);
451*0Sstevel@tonic-gate 	}
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	if (dip->di_np_tx != NULL) {
454*0Sstevel@tonic-gate 		info.dci_be = BACKEND_TYPE_NONPERSIST;
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 		r = backend_tx_run(dip->di_np_tx, q, push_delete_callback,
457*0Sstevel@tonic-gate 		    &info);
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 		if (r == REP_PROTOCOL_DONE) {
460*0Sstevel@tonic-gate 			assert(info.dci_result != REP_PROTOCOL_SUCCESS);
461*0Sstevel@tonic-gate 			backend_query_free(q);
462*0Sstevel@tonic-gate 			return (info.dci_result);
463*0Sstevel@tonic-gate 		}
464*0Sstevel@tonic-gate 		if (r != REP_PROTOCOL_SUCCESS) {
465*0Sstevel@tonic-gate 			backend_query_free(q);
466*0Sstevel@tonic-gate 			return (r);
467*0Sstevel@tonic-gate 		}
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate 	backend_query_free(q);
470*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
471*0Sstevel@tonic-gate }
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate static int
474*0Sstevel@tonic-gate service_delete(delete_info_t *dip, const delete_ent_t *ent)
475*0Sstevel@tonic-gate {
476*0Sstevel@tonic-gate 	int r;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	r = backend_tx_run_update_changed(dip->di_tx,
479*0Sstevel@tonic-gate 	    "DELETE FROM service_tbl WHERE svc_id = %d", ent->de_id);
480*0Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
481*0Sstevel@tonic-gate 		return (r);
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	return (pgparent_delete_add_pgs(dip, ent->de_id));
484*0Sstevel@tonic-gate }
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate static int
487*0Sstevel@tonic-gate instance_delete(delete_info_t *dip, const delete_ent_t *ent)
488*0Sstevel@tonic-gate {
489*0Sstevel@tonic-gate 	struct delete_cb_info info;
490*0Sstevel@tonic-gate 	int r;
491*0Sstevel@tonic-gate 	backend_query_t *q;
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	r = backend_tx_run_update_changed(dip->di_tx,
494*0Sstevel@tonic-gate 	    "DELETE FROM instance_tbl WHERE instance_id = %d", ent->de_id);
495*0Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
496*0Sstevel@tonic-gate 		return (r);
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 	r = pgparent_delete_add_pgs(dip, ent->de_id);
499*0Sstevel@tonic-gate 	if (r != REP_PROTOCOL_SUCCESS)
500*0Sstevel@tonic-gate 		return (r);
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 	info.dci_dip = dip;
503*0Sstevel@tonic-gate 	info.dci_be = BACKEND_TYPE_NORMAL;
504*0Sstevel@tonic-gate 	info.dci_cb = &snapshot_lnk_delete;
505*0Sstevel@tonic-gate 	info.dci_result = REP_PROTOCOL_SUCCESS;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	q = backend_query_alloc();
508*0Sstevel@tonic-gate 	backend_query_add(q,
509*0Sstevel@tonic-gate 	    "SELECT lnk_id, 0 FROM snapshot_lnk_tbl WHERE lnk_inst_id = %d",
510*0Sstevel@tonic-gate 	    ent->de_id);
511*0Sstevel@tonic-gate 	r = backend_tx_run(dip->di_tx, q, push_delete_callback, &info);
512*0Sstevel@tonic-gate 	backend_query_free(q);
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE) {
515*0Sstevel@tonic-gate 		assert(info.dci_result != REP_PROTOCOL_SUCCESS);
516*0Sstevel@tonic-gate 		return (info.dci_result);
517*0Sstevel@tonic-gate 	}
518*0Sstevel@tonic-gate 	return (r);
519*0Sstevel@tonic-gate }
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate /*ARGSUSED*/
522*0Sstevel@tonic-gate static int
523*0Sstevel@tonic-gate fill_child_callback(void *data, int columns, char **vals, char **names)
524*0Sstevel@tonic-gate {
525*0Sstevel@tonic-gate 	child_info_t *cp = data;
526*0Sstevel@tonic-gate 	rc_node_t *np;
527*0Sstevel@tonic-gate 	uint32_t main_id;
528*0Sstevel@tonic-gate 	const char *name;
529*0Sstevel@tonic-gate 	const char *cur;
530*0Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cp->ci_base_nl;
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 	assert(columns == 2);
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	name = *vals++;
535*0Sstevel@tonic-gate 	columns--;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	cur = *vals++;
538*0Sstevel@tonic-gate 	columns--;
539*0Sstevel@tonic-gate 	if (uu_strtouint(cur, &main_id, sizeof (main_id), 0, 0, 0) == -1)
540*0Sstevel@tonic-gate 		backend_panic("invalid integer in database");
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	lp->rl_main_id = main_id;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	if ((np = rc_node_alloc()) == NULL)
545*0Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	np = rc_node_setup(np, lp, name, cp->ci_parent);
548*0Sstevel@tonic-gate 	rc_node_rele(np);
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
551*0Sstevel@tonic-gate }
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate /*ARGSUSED*/
554*0Sstevel@tonic-gate static int
555*0Sstevel@tonic-gate fill_snapshot_callback(void *data, int columns, char **vals, char **names)
556*0Sstevel@tonic-gate {
557*0Sstevel@tonic-gate 	child_info_t *cp = data;
558*0Sstevel@tonic-gate 	rc_node_t *np;
559*0Sstevel@tonic-gate 	uint32_t main_id;
560*0Sstevel@tonic-gate 	uint32_t snap_id;
561*0Sstevel@tonic-gate 	const char *name;
562*0Sstevel@tonic-gate 	const char *cur;
563*0Sstevel@tonic-gate 	const char *snap;
564*0Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cp->ci_base_nl;
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	assert(columns == 3);
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	name = *vals++;
569*0Sstevel@tonic-gate 	columns--;
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	cur = *vals++;
572*0Sstevel@tonic-gate 	columns--;
573*0Sstevel@tonic-gate 	snap = *vals++;
574*0Sstevel@tonic-gate 	columns--;
575*0Sstevel@tonic-gate 	if (uu_strtouint(cur, &main_id, sizeof (main_id), 0, 0, 0) == -1 ||
576*0Sstevel@tonic-gate 	    uu_strtouint(snap, &snap_id, sizeof (snap_id), 0, 0, 0) == -1)
577*0Sstevel@tonic-gate 		backend_panic("invalid integer in database");
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 	lp->rl_main_id = main_id;
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 	if ((np = rc_node_alloc()) == NULL)
582*0Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	np = rc_node_setup_snapshot(np, lp, name, snap_id, cp->ci_parent);
585*0Sstevel@tonic-gate 	rc_node_rele(np);
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
588*0Sstevel@tonic-gate }
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate /*ARGSUSED*/
591*0Sstevel@tonic-gate static int
592*0Sstevel@tonic-gate fill_pg_callback(void *data, int columns, char **vals, char **names)
593*0Sstevel@tonic-gate {
594*0Sstevel@tonic-gate 	child_info_t *cip = data;
595*0Sstevel@tonic-gate 	const char *name;
596*0Sstevel@tonic-gate 	const char *type;
597*0Sstevel@tonic-gate 	const char *cur;
598*0Sstevel@tonic-gate 	uint32_t main_id;
599*0Sstevel@tonic-gate 	uint32_t flags;
600*0Sstevel@tonic-gate 	uint32_t gen_id;
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cip->ci_base_nl;
603*0Sstevel@tonic-gate 	rc_node_t *newnode, *pg;
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 	assert(columns == 5);
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	name = *vals++;		/* pg_name */
608*0Sstevel@tonic-gate 	columns--;
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	cur = *vals++;		/* pg_id */
611*0Sstevel@tonic-gate 	columns--;
612*0Sstevel@tonic-gate 	if (uu_strtouint(cur, &main_id, sizeof (main_id), 0, 0, 0) == -1)
613*0Sstevel@tonic-gate 		backend_panic("invalid integer in database");
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	lp->rl_main_id = main_id;
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 	cur = *vals++;		/* pg_gen_id */
618*0Sstevel@tonic-gate 	columns--;
619*0Sstevel@tonic-gate 	if (uu_strtouint(cur, &gen_id, sizeof (gen_id), 0, 0, 0) == -1)
620*0Sstevel@tonic-gate 		backend_panic("invalid integer in database");
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	type = *vals++;		/* pg_type */
623*0Sstevel@tonic-gate 	columns--;
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	cur = *vals++;		/* pg_flags */
626*0Sstevel@tonic-gate 	columns--;
627*0Sstevel@tonic-gate 	if (uu_strtouint(cur, &flags, sizeof (flags), 0, 0, 0) == -1)
628*0Sstevel@tonic-gate 		backend_panic("invalid integer in database");
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 	if ((newnode = rc_node_alloc()) == NULL)
631*0Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	pg = rc_node_setup_pg(newnode, lp, name, type, flags, gen_id,
634*0Sstevel@tonic-gate 	    cip->ci_parent);
635*0Sstevel@tonic-gate 	if (pg == NULL) {
636*0Sstevel@tonic-gate 		rc_node_destroy(newnode);
637*0Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
638*0Sstevel@tonic-gate 	}
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	rc_node_rele(pg);
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
643*0Sstevel@tonic-gate }
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate struct property_value_info {
646*0Sstevel@tonic-gate 	char		*pvi_base;
647*0Sstevel@tonic-gate 	size_t		pvi_pos;
648*0Sstevel@tonic-gate 	size_t		pvi_size;
649*0Sstevel@tonic-gate 	size_t		pvi_count;
650*0Sstevel@tonic-gate };
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate /*ARGSUSED*/
653*0Sstevel@tonic-gate static int
654*0Sstevel@tonic-gate property_value_size_cb(void *data, int columns, char **vals, char **names)
655*0Sstevel@tonic-gate {
656*0Sstevel@tonic-gate 	struct property_value_info *info = data;
657*0Sstevel@tonic-gate 	assert(columns == 1);
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	info->pvi_size += strlen(vals[0]) + 1;		/* count the '\0' */
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
662*0Sstevel@tonic-gate }
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate /*ARGSUSED*/
665*0Sstevel@tonic-gate static int
666*0Sstevel@tonic-gate property_value_cb(void *data, int columns, char **vals, char **names)
667*0Sstevel@tonic-gate {
668*0Sstevel@tonic-gate 	struct property_value_info *info = data;
669*0Sstevel@tonic-gate 	size_t pos, left, len;
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	assert(columns == 1);
672*0Sstevel@tonic-gate 	pos = info->pvi_pos;
673*0Sstevel@tonic-gate 	left = info->pvi_size - pos;
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	pos = info->pvi_pos;
676*0Sstevel@tonic-gate 	left = info->pvi_size - pos;
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	if ((len = strlcpy(&info->pvi_base[pos], vals[0], left)) >= left) {
679*0Sstevel@tonic-gate 		/*
680*0Sstevel@tonic-gate 		 * since we preallocated, above, this shouldn't happen
681*0Sstevel@tonic-gate 		 */
682*0Sstevel@tonic-gate 		backend_panic("unexpected database change");
683*0Sstevel@tonic-gate 	}
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	len += 1;	/* count the '\0' */
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 	info->pvi_pos += len;
688*0Sstevel@tonic-gate 	info->pvi_count++;
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
691*0Sstevel@tonic-gate }
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate /*ARGSUSED*/
694*0Sstevel@tonic-gate void
695*0Sstevel@tonic-gate object_free_values(const char *vals, uint32_t type, size_t count, size_t size)
696*0Sstevel@tonic-gate {
697*0Sstevel@tonic-gate 	if (vals != NULL)
698*0Sstevel@tonic-gate 		uu_free((void *)vals);
699*0Sstevel@tonic-gate }
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate /*ARGSUSED*/
702*0Sstevel@tonic-gate static int
703*0Sstevel@tonic-gate fill_property_callback(void *data, int columns, char **vals, char **names)
704*0Sstevel@tonic-gate {
705*0Sstevel@tonic-gate 	child_info_t *cp = data;
706*0Sstevel@tonic-gate 	backend_tx_t *tx = cp->ci_tx;
707*0Sstevel@tonic-gate 	uint32_t main_id;
708*0Sstevel@tonic-gate 	const char *name;
709*0Sstevel@tonic-gate 	const char *cur;
710*0Sstevel@tonic-gate 	rep_protocol_value_type_t type;
711*0Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cp->ci_base_nl;
712*0Sstevel@tonic-gate 	struct property_value_info info;
713*0Sstevel@tonic-gate 	int rc;
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 	assert(columns == 4);
716*0Sstevel@tonic-gate 	assert(tx != NULL);
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	info.pvi_base = NULL;
719*0Sstevel@tonic-gate 	info.pvi_pos = 0;
720*0Sstevel@tonic-gate 	info.pvi_size = 0;
721*0Sstevel@tonic-gate 	info.pvi_count = 0;
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 	name = *vals++;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 	cur = *vals++;
726*0Sstevel@tonic-gate 	if (uu_strtouint(cur, &main_id, sizeof (main_id), 0, 0, 0) == -1)
727*0Sstevel@tonic-gate 		backend_panic("invalid integer in database");
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 	cur = *vals++;
730*0Sstevel@tonic-gate 	assert(('a' <= cur[0] && 'z' >= cur[0]) ||
731*0Sstevel@tonic-gate 	    ('A' <= cur[0] && 'Z' >= cur[0]) &&
732*0Sstevel@tonic-gate 	    (cur[1] == 0 || ('a' <= cur[1] && 'z' >= cur[1]) ||
733*0Sstevel@tonic-gate 	    ('A' <= cur[1] && 'Z' >= cur[1])));
734*0Sstevel@tonic-gate 	type = cur[0] | (cur[1] << 8);
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	lp->rl_main_id = main_id;
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	/*
739*0Sstevel@tonic-gate 	 * fill in the values, if any
740*0Sstevel@tonic-gate 	 */
741*0Sstevel@tonic-gate 	if ((cur = *vals++) != NULL) {
742*0Sstevel@tonic-gate 		rep_protocol_responseid_t r;
743*0Sstevel@tonic-gate 		backend_query_t *q = backend_query_alloc();
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 		backend_query_add(q,
746*0Sstevel@tonic-gate 		    "SELECT value_value FROM value_tbl "
747*0Sstevel@tonic-gate 		    "WHERE (value_id = '%q')", cur);
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate 		switch (r = backend_tx_run(tx, q, property_value_size_cb,
750*0Sstevel@tonic-gate 		    &info)) {
751*0Sstevel@tonic-gate 		case REP_PROTOCOL_SUCCESS:
752*0Sstevel@tonic-gate 			break;
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 		case REP_PROTOCOL_FAIL_NO_RESOURCES:
755*0Sstevel@tonic-gate 			backend_query_free(q);
756*0Sstevel@tonic-gate 			return (BACKEND_CALLBACK_ABORT);
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 		case REP_PROTOCOL_DONE:
759*0Sstevel@tonic-gate 		default:
760*0Sstevel@tonic-gate 			backend_panic("backend_tx_run() returned %d", r);
761*0Sstevel@tonic-gate 		}
762*0Sstevel@tonic-gate 		if (info.pvi_size > 0) {
763*0Sstevel@tonic-gate 			info.pvi_base = uu_zalloc(info.pvi_size);
764*0Sstevel@tonic-gate 			if (info.pvi_base == NULL) {
765*0Sstevel@tonic-gate 				backend_query_free(q);
766*0Sstevel@tonic-gate 				return (BACKEND_CALLBACK_ABORT);
767*0Sstevel@tonic-gate 			}
768*0Sstevel@tonic-gate 			switch (r = backend_tx_run(tx, q, property_value_cb,
769*0Sstevel@tonic-gate 			    &info)) {
770*0Sstevel@tonic-gate 			case REP_PROTOCOL_SUCCESS:
771*0Sstevel@tonic-gate 				break;
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 			case REP_PROTOCOL_FAIL_NO_RESOURCES:
774*0Sstevel@tonic-gate 				uu_free(info.pvi_base);
775*0Sstevel@tonic-gate 				backend_query_free(q);
776*0Sstevel@tonic-gate 				return (BACKEND_CALLBACK_ABORT);
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate 			case REP_PROTOCOL_DONE:
779*0Sstevel@tonic-gate 			default:
780*0Sstevel@tonic-gate 				backend_panic("backend_tx_run() returned %d",
781*0Sstevel@tonic-gate 				    r);
782*0Sstevel@tonic-gate 			}
783*0Sstevel@tonic-gate 		}
784*0Sstevel@tonic-gate 		backend_query_free(q);
785*0Sstevel@tonic-gate 	}
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 	rc = rc_node_create_property(cp->ci_parent, lp, name, type,
788*0Sstevel@tonic-gate 	    info.pvi_base, info.pvi_count, info.pvi_size);
789*0Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS) {
790*0Sstevel@tonic-gate 		assert(rc == REP_PROTOCOL_FAIL_NO_RESOURCES);
791*0Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
792*0Sstevel@tonic-gate 	}
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
795*0Sstevel@tonic-gate }
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate /*
798*0Sstevel@tonic-gate  * The *_setup_child_info() functions fill in a child_info_t structure with the
799*0Sstevel@tonic-gate  * information for the children of np with type type.
800*0Sstevel@tonic-gate  *
801*0Sstevel@tonic-gate  * They fail with
802*0Sstevel@tonic-gate  *   _TYPE_MISMATCH - object cannot have children of type type
803*0Sstevel@tonic-gate  */
804*0Sstevel@tonic-gate 
805*0Sstevel@tonic-gate static int
806*0Sstevel@tonic-gate scope_setup_child_info(rc_node_t *np, uint32_t type, child_info_t *cip)
807*0Sstevel@tonic-gate {
808*0Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_SERVICE)
809*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
812*0Sstevel@tonic-gate 	cip->ci_parent = np;
813*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
814*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = np->rn_id.rl_backend;
815*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
816*0Sstevel@tonic-gate }
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate static int
819*0Sstevel@tonic-gate service_setup_child_info(rc_node_t *np, uint32_t type, child_info_t *cip)
820*0Sstevel@tonic-gate {
821*0Sstevel@tonic-gate 	switch (type) {
822*0Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE:
823*0Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
824*0Sstevel@tonic-gate 		break;
825*0Sstevel@tonic-gate 	default:
826*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
827*0Sstevel@tonic-gate 	}
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
830*0Sstevel@tonic-gate 	cip->ci_parent = np;
831*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
832*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = np->rn_id.rl_backend;
833*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SERVICE] = np->rn_id.rl_main_id;
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
836*0Sstevel@tonic-gate }
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate static int
839*0Sstevel@tonic-gate instance_setup_child_info(rc_node_t *np, uint32_t type, child_info_t *cip)
840*0Sstevel@tonic-gate {
841*0Sstevel@tonic-gate 	switch (type) {
842*0Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
843*0Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
844*0Sstevel@tonic-gate 		break;
845*0Sstevel@tonic-gate 	default:
846*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
847*0Sstevel@tonic-gate 	}
848*0Sstevel@tonic-gate 
849*0Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
850*0Sstevel@tonic-gate 	cip->ci_parent = np;
851*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
852*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = np->rn_id.rl_backend;
853*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SERVICE] = np->rn_id.rl_ids[ID_SERVICE];
854*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_INSTANCE] = np->rn_id.rl_main_id;
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
857*0Sstevel@tonic-gate }
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate static int
860*0Sstevel@tonic-gate snaplevel_setup_child_info(rc_node_t *np, uint32_t type, child_info_t *cip)
861*0Sstevel@tonic-gate {
862*0Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
863*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
866*0Sstevel@tonic-gate 	cip->ci_parent = np;
867*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
868*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = np->rn_id.rl_backend;
869*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SERVICE] = np->rn_id.rl_ids[ID_SERVICE];
870*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_INSTANCE] = np->rn_id.rl_ids[ID_INSTANCE];
871*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_NAME] = np->rn_id.rl_ids[ID_NAME];
872*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SNAPSHOT] = np->rn_id.rl_ids[ID_SNAPSHOT];
873*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_LEVEL] = np->rn_id.rl_main_id;
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
876*0Sstevel@tonic-gate }
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate static int
879*0Sstevel@tonic-gate propertygrp_setup_child_info(rc_node_t *pg, uint32_t type, child_info_t *cip)
880*0Sstevel@tonic-gate {
881*0Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_PROPERTY)
882*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
883*0Sstevel@tonic-gate 
884*0Sstevel@tonic-gate 	bzero(cip, sizeof (*cip));
885*0Sstevel@tonic-gate 	cip->ci_parent = pg;
886*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_type = type;
887*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_backend = pg->rn_id.rl_backend;
888*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SERVICE] = pg->rn_id.rl_ids[ID_SERVICE];
889*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_INSTANCE] = pg->rn_id.rl_ids[ID_INSTANCE];
890*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_PG] = pg->rn_id.rl_main_id;
891*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_GEN] = pg->rn_gen_id;
892*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_NAME] = pg->rn_id.rl_ids[ID_NAME];
893*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_SNAPSHOT] = pg->rn_id.rl_ids[ID_SNAPSHOT];
894*0Sstevel@tonic-gate 	cip->ci_base_nl.rl_ids[ID_LEVEL] = pg->rn_id.rl_ids[ID_LEVEL];
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
897*0Sstevel@tonic-gate }
898*0Sstevel@tonic-gate 
899*0Sstevel@tonic-gate /*
900*0Sstevel@tonic-gate  * The *_fill_children() functions populate the children of the given rc_node_t
901*0Sstevel@tonic-gate  * by querying the database and calling rc_node_setup_*() functions (usually
902*0Sstevel@tonic-gate  * via a fill_*_callback()).
903*0Sstevel@tonic-gate  *
904*0Sstevel@tonic-gate  * They fail with
905*0Sstevel@tonic-gate  *   _NO_RESOURCES
906*0Sstevel@tonic-gate  */
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate /*
909*0Sstevel@tonic-gate  * Returns
910*0Sstevel@tonic-gate  *   _NO_RESOURCES
911*0Sstevel@tonic-gate  *   _SUCCESS
912*0Sstevel@tonic-gate  */
913*0Sstevel@tonic-gate static int
914*0Sstevel@tonic-gate scope_fill_children(rc_node_t *np)
915*0Sstevel@tonic-gate {
916*0Sstevel@tonic-gate 	backend_query_t *q;
917*0Sstevel@tonic-gate 	child_info_t ci;
918*0Sstevel@tonic-gate 	int res;
919*0Sstevel@tonic-gate 
920*0Sstevel@tonic-gate 	(void) scope_setup_child_info(np, REP_PROTOCOL_ENTITY_SERVICE, &ci);
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate 	q = backend_query_alloc();
923*0Sstevel@tonic-gate 	backend_query_append(q, "SELECT svc_name, svc_id FROM service_tbl");
924*0Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_child_callback, &ci);
925*0Sstevel@tonic-gate 	backend_query_free(q);
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
928*0Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
929*0Sstevel@tonic-gate 	return (res);
930*0Sstevel@tonic-gate }
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate /*
933*0Sstevel@tonic-gate  * Returns
934*0Sstevel@tonic-gate  *   _NO_RESOURCES
935*0Sstevel@tonic-gate  *   _SUCCESS
936*0Sstevel@tonic-gate  */
937*0Sstevel@tonic-gate static int
938*0Sstevel@tonic-gate service_fill_children(rc_node_t *np)
939*0Sstevel@tonic-gate {
940*0Sstevel@tonic-gate 	backend_query_t *q;
941*0Sstevel@tonic-gate 	child_info_t ci;
942*0Sstevel@tonic-gate 	int res;
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	assert(np->rn_id.rl_backend == BACKEND_TYPE_NORMAL);
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 	(void) service_setup_child_info(np, REP_PROTOCOL_ENTITY_INSTANCE, &ci);
947*0Sstevel@tonic-gate 
948*0Sstevel@tonic-gate 	q = backend_query_alloc();
949*0Sstevel@tonic-gate 	backend_query_add(q,
950*0Sstevel@tonic-gate 	    "SELECT instance_name, instance_id FROM instance_tbl"
951*0Sstevel@tonic-gate 	    "    WHERE (instance_svc = %d)",
952*0Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
953*0Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_child_callback, &ci);
954*0Sstevel@tonic-gate 	backend_query_free(q);
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
957*0Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
958*0Sstevel@tonic-gate 	if (res != REP_PROTOCOL_SUCCESS)
959*0Sstevel@tonic-gate 		return (res);
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate 	(void) service_setup_child_info(np, REP_PROTOCOL_ENTITY_PROPERTYGRP,
962*0Sstevel@tonic-gate 	    &ci);
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	q = backend_query_alloc();
965*0Sstevel@tonic-gate 	backend_query_add(q,
966*0Sstevel@tonic-gate 	    "SELECT pg_name, pg_id, pg_gen_id, pg_type, pg_flags FROM pg_tbl"
967*0Sstevel@tonic-gate 	    "    WHERE (pg_parent_id = %d)",
968*0Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 	ci.ci_base_nl.rl_backend = BACKEND_TYPE_NORMAL;
971*0Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_pg_callback, &ci);
972*0Sstevel@tonic-gate 	if (res == REP_PROTOCOL_SUCCESS) {
973*0Sstevel@tonic-gate 		ci.ci_base_nl.rl_backend = BACKEND_TYPE_NONPERSIST;
974*0Sstevel@tonic-gate 		res = backend_run(BACKEND_TYPE_NONPERSIST, q,
975*0Sstevel@tonic-gate 		    fill_pg_callback, &ci);
976*0Sstevel@tonic-gate 		/* nonpersistant database may not exist */
977*0Sstevel@tonic-gate 		if (res == REP_PROTOCOL_FAIL_BACKEND_ACCESS)
978*0Sstevel@tonic-gate 			res = REP_PROTOCOL_SUCCESS;
979*0Sstevel@tonic-gate 	}
980*0Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
981*0Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
982*0Sstevel@tonic-gate 	backend_query_free(q);
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	return (res);
985*0Sstevel@tonic-gate }
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate /*
988*0Sstevel@tonic-gate  * Returns
989*0Sstevel@tonic-gate  *   _NO_RESOURCES
990*0Sstevel@tonic-gate  *   _SUCCESS
991*0Sstevel@tonic-gate  */
992*0Sstevel@tonic-gate static int
993*0Sstevel@tonic-gate instance_fill_children(rc_node_t *np)
994*0Sstevel@tonic-gate {
995*0Sstevel@tonic-gate 	backend_query_t *q;
996*0Sstevel@tonic-gate 	child_info_t ci;
997*0Sstevel@tonic-gate 	int res;
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate 	assert(np->rn_id.rl_backend == BACKEND_TYPE_NORMAL);
1000*0Sstevel@tonic-gate 
1001*0Sstevel@tonic-gate 	/* Get child property groups */
1002*0Sstevel@tonic-gate 	(void) instance_setup_child_info(np, REP_PROTOCOL_ENTITY_PROPERTYGRP,
1003*0Sstevel@tonic-gate 	    &ci);
1004*0Sstevel@tonic-gate 
1005*0Sstevel@tonic-gate 	q = backend_query_alloc();
1006*0Sstevel@tonic-gate 	backend_query_add(q,
1007*0Sstevel@tonic-gate 	    "SELECT pg_name, pg_id, pg_gen_id, pg_type, pg_flags FROM pg_tbl"
1008*0Sstevel@tonic-gate 	    "    WHERE (pg_parent_id = %d)",
1009*0Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
1010*0Sstevel@tonic-gate 	ci.ci_base_nl.rl_backend = BACKEND_TYPE_NORMAL;
1011*0Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_pg_callback, &ci);
1012*0Sstevel@tonic-gate 	if (res == REP_PROTOCOL_SUCCESS) {
1013*0Sstevel@tonic-gate 		ci.ci_base_nl.rl_backend = BACKEND_TYPE_NONPERSIST;
1014*0Sstevel@tonic-gate 		res = backend_run(BACKEND_TYPE_NONPERSIST, q,
1015*0Sstevel@tonic-gate 		    fill_pg_callback, &ci);
1016*0Sstevel@tonic-gate 		/* nonpersistant database may not exist */
1017*0Sstevel@tonic-gate 		if (res == REP_PROTOCOL_FAIL_BACKEND_ACCESS)
1018*0Sstevel@tonic-gate 			res = REP_PROTOCOL_SUCCESS;
1019*0Sstevel@tonic-gate 	}
1020*0Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
1021*0Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
1022*0Sstevel@tonic-gate 	backend_query_free(q);
1023*0Sstevel@tonic-gate 
1024*0Sstevel@tonic-gate 	if (res != REP_PROTOCOL_SUCCESS)
1025*0Sstevel@tonic-gate 		return (res);
1026*0Sstevel@tonic-gate 
1027*0Sstevel@tonic-gate 	/* Get child snapshots */
1028*0Sstevel@tonic-gate 	(void) instance_setup_child_info(np, REP_PROTOCOL_ENTITY_SNAPSHOT,
1029*0Sstevel@tonic-gate 	    &ci);
1030*0Sstevel@tonic-gate 
1031*0Sstevel@tonic-gate 	q = backend_query_alloc();
1032*0Sstevel@tonic-gate 	backend_query_add(q,
1033*0Sstevel@tonic-gate 	    "SELECT lnk_snap_name, lnk_id, lnk_snap_id FROM snapshot_lnk_tbl"
1034*0Sstevel@tonic-gate 	    "    WHERE (lnk_inst_id = %d)",
1035*0Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
1036*0Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_snapshot_callback, &ci);
1037*0Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
1038*0Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
1039*0Sstevel@tonic-gate 	backend_query_free(q);
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 	return (res);
1042*0Sstevel@tonic-gate }
1043*0Sstevel@tonic-gate 
1044*0Sstevel@tonic-gate /*
1045*0Sstevel@tonic-gate  * Returns
1046*0Sstevel@tonic-gate  *   _NO_RESOURCES
1047*0Sstevel@tonic-gate  *   _SUCCESS
1048*0Sstevel@tonic-gate  */
1049*0Sstevel@tonic-gate static int
1050*0Sstevel@tonic-gate snapshot_fill_children(rc_node_t *np)
1051*0Sstevel@tonic-gate {
1052*0Sstevel@tonic-gate 	rc_node_t *nnp;
1053*0Sstevel@tonic-gate 	rc_snapshot_t *sp, *oldsp;
1054*0Sstevel@tonic-gate 	rc_snaplevel_t *lvl;
1055*0Sstevel@tonic-gate 	rc_node_lookup_t nl;
1056*0Sstevel@tonic-gate 	int r;
1057*0Sstevel@tonic-gate 
1058*0Sstevel@tonic-gate 	/* Get the rc_snapshot_t (& its rc_snaplevel_t's). */
1059*0Sstevel@tonic-gate 	(void) pthread_mutex_lock(&np->rn_lock);
1060*0Sstevel@tonic-gate 	sp = np->rn_snapshot;
1061*0Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&np->rn_lock);
1062*0Sstevel@tonic-gate 	if (sp == NULL) {
1063*0Sstevel@tonic-gate 		r = rc_snapshot_get(np->rn_snapshot_id, &sp);
1064*0Sstevel@tonic-gate 		if (r != REP_PROTOCOL_SUCCESS) {
1065*0Sstevel@tonic-gate 			assert(r == REP_PROTOCOL_FAIL_NO_RESOURCES);
1066*0Sstevel@tonic-gate 			return (r);
1067*0Sstevel@tonic-gate 		}
1068*0Sstevel@tonic-gate 		(void) pthread_mutex_lock(&np->rn_lock);
1069*0Sstevel@tonic-gate 		oldsp = np->rn_snapshot;
1070*0Sstevel@tonic-gate 		assert(oldsp == NULL || oldsp == sp);
1071*0Sstevel@tonic-gate 		np->rn_snapshot = sp;
1072*0Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&np->rn_lock);
1073*0Sstevel@tonic-gate 		if (oldsp != NULL)
1074*0Sstevel@tonic-gate 			rc_snapshot_rele(oldsp);
1075*0Sstevel@tonic-gate 	}
1076*0Sstevel@tonic-gate 
1077*0Sstevel@tonic-gate 	bzero(&nl, sizeof (nl));
1078*0Sstevel@tonic-gate 	nl.rl_type = REP_PROTOCOL_ENTITY_SNAPLEVEL;
1079*0Sstevel@tonic-gate 	nl.rl_backend = np->rn_id.rl_backend;
1080*0Sstevel@tonic-gate 	nl.rl_ids[ID_SERVICE] = np->rn_id.rl_ids[ID_SERVICE];
1081*0Sstevel@tonic-gate 	nl.rl_ids[ID_INSTANCE] = np->rn_id.rl_ids[ID_INSTANCE];
1082*0Sstevel@tonic-gate 	nl.rl_ids[ID_NAME] = np->rn_id.rl_main_id;
1083*0Sstevel@tonic-gate 	nl.rl_ids[ID_SNAPSHOT] = np->rn_snapshot_id;
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate 	/* Create rc_node_t's for the snapshot's rc_snaplevel_t's. */
1086*0Sstevel@tonic-gate 	for (lvl = sp->rs_levels; lvl != NULL; lvl = lvl->rsl_next) {
1087*0Sstevel@tonic-gate 		nnp = rc_node_alloc();
1088*0Sstevel@tonic-gate 		assert(nnp != NULL);
1089*0Sstevel@tonic-gate 		nl.rl_main_id = lvl->rsl_level_id;
1090*0Sstevel@tonic-gate 		nnp = rc_node_setup_snaplevel(nnp, &nl, lvl, np);
1091*0Sstevel@tonic-gate 		rc_node_rele(nnp);
1092*0Sstevel@tonic-gate 	}
1093*0Sstevel@tonic-gate 
1094*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1095*0Sstevel@tonic-gate }
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate /*
1098*0Sstevel@tonic-gate  * Returns
1099*0Sstevel@tonic-gate  *   _NO_RESOURCES
1100*0Sstevel@tonic-gate  *   _SUCCESS
1101*0Sstevel@tonic-gate  */
1102*0Sstevel@tonic-gate static int
1103*0Sstevel@tonic-gate snaplevel_fill_children(rc_node_t *np)
1104*0Sstevel@tonic-gate {
1105*0Sstevel@tonic-gate 	rc_snaplevel_t *lvl = np->rn_snaplevel;
1106*0Sstevel@tonic-gate 	child_info_t ci;
1107*0Sstevel@tonic-gate 	int res;
1108*0Sstevel@tonic-gate 	backend_query_t *q;
1109*0Sstevel@tonic-gate 
1110*0Sstevel@tonic-gate 	(void) snaplevel_setup_child_info(np, REP_PROTOCOL_ENTITY_PROPERTYGRP,
1111*0Sstevel@tonic-gate 	    &ci);
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 	q = backend_query_alloc();
1114*0Sstevel@tonic-gate 	backend_query_add(q,
1115*0Sstevel@tonic-gate 	    "SELECT snaplvl_pg_name, snaplvl_pg_id, snaplvl_gen_id, "
1116*0Sstevel@tonic-gate 	    "    snaplvl_pg_type, snaplvl_pg_flags "
1117*0Sstevel@tonic-gate 	    "    FROM snaplevel_lnk_tbl "
1118*0Sstevel@tonic-gate 	    "    WHERE (snaplvl_level_id = %d)",
1119*0Sstevel@tonic-gate 	    lvl->rsl_level_id);
1120*0Sstevel@tonic-gate 	res = backend_run(BACKEND_TYPE_NORMAL, q, fill_pg_callback, &ci);
1121*0Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
1122*0Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
1123*0Sstevel@tonic-gate 	backend_query_free(q);
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 	return (res);
1126*0Sstevel@tonic-gate }
1127*0Sstevel@tonic-gate 
1128*0Sstevel@tonic-gate /*
1129*0Sstevel@tonic-gate  * Returns
1130*0Sstevel@tonic-gate  *   _NO_RESOURCES
1131*0Sstevel@tonic-gate  *   _SUCCESS
1132*0Sstevel@tonic-gate  */
1133*0Sstevel@tonic-gate static int
1134*0Sstevel@tonic-gate propertygrp_fill_children(rc_node_t *np)
1135*0Sstevel@tonic-gate {
1136*0Sstevel@tonic-gate 	backend_query_t *q;
1137*0Sstevel@tonic-gate 	child_info_t ci;
1138*0Sstevel@tonic-gate 	int res;
1139*0Sstevel@tonic-gate 	backend_tx_t *tx;
1140*0Sstevel@tonic-gate 
1141*0Sstevel@tonic-gate 	backend_type_t backend = np->rn_id.rl_backend;
1142*0Sstevel@tonic-gate 
1143*0Sstevel@tonic-gate 	(void) propertygrp_setup_child_info(np, REP_PROTOCOL_ENTITY_PROPERTY,
1144*0Sstevel@tonic-gate 	    &ci);
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate 	res = backend_tx_begin_ro(backend, &tx);
1147*0Sstevel@tonic-gate 	if (res != REP_PROTOCOL_SUCCESS) {
1148*0Sstevel@tonic-gate 		/*
1149*0Sstevel@tonic-gate 		 * If the backend didn't exist, we wouldn't have got this
1150*0Sstevel@tonic-gate 		 * property group.
1151*0Sstevel@tonic-gate 		 */
1152*0Sstevel@tonic-gate 		assert(res != REP_PROTOCOL_FAIL_BACKEND_ACCESS);
1153*0Sstevel@tonic-gate 		return (res);
1154*0Sstevel@tonic-gate 	}
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate 	ci.ci_tx = tx;
1157*0Sstevel@tonic-gate 
1158*0Sstevel@tonic-gate 	q = backend_query_alloc();
1159*0Sstevel@tonic-gate 	backend_query_add(q,
1160*0Sstevel@tonic-gate 	    "SELECT lnk_prop_name, lnk_prop_id, lnk_prop_type, lnk_val_id "
1161*0Sstevel@tonic-gate 	    "FROM prop_lnk_tbl "
1162*0Sstevel@tonic-gate 	    "WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)",
1163*0Sstevel@tonic-gate 	    np->rn_id.rl_main_id, np->rn_gen_id);
1164*0Sstevel@tonic-gate 	res = backend_tx_run(tx, q, fill_property_callback, &ci);
1165*0Sstevel@tonic-gate 	if (res == REP_PROTOCOL_DONE)
1166*0Sstevel@tonic-gate 		res = REP_PROTOCOL_FAIL_NO_RESOURCES;
1167*0Sstevel@tonic-gate 	backend_query_free(q);
1168*0Sstevel@tonic-gate 	backend_tx_end_ro(tx);
1169*0Sstevel@tonic-gate 
1170*0Sstevel@tonic-gate 	return (res);
1171*0Sstevel@tonic-gate }
1172*0Sstevel@tonic-gate 
1173*0Sstevel@tonic-gate /*
1174*0Sstevel@tonic-gate  * Fails with
1175*0Sstevel@tonic-gate  *   _TYPE_MISMATCH - lp is not for a service
1176*0Sstevel@tonic-gate  *   _INVALID_TYPE - lp has invalid type
1177*0Sstevel@tonic-gate  *   _BAD_REQUEST - name is invalid
1178*0Sstevel@tonic-gate  */
1179*0Sstevel@tonic-gate static int
1180*0Sstevel@tonic-gate scope_query_child(backend_query_t *q, rc_node_lookup_t *lp, const char *name)
1181*0Sstevel@tonic-gate {
1182*0Sstevel@tonic-gate 	uint32_t type = lp->rl_type;
1183*0Sstevel@tonic-gate 	int rc;
1184*0Sstevel@tonic-gate 
1185*0Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_SERVICE)
1186*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 	if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS)
1189*0Sstevel@tonic-gate 		return (rc);
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate 	backend_query_add(q,
1192*0Sstevel@tonic-gate 	    "SELECT svc_id FROM service_tbl "
1193*0Sstevel@tonic-gate 	    "WHERE svc_name = '%q'",
1194*0Sstevel@tonic-gate 	    name);
1195*0Sstevel@tonic-gate 
1196*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1197*0Sstevel@tonic-gate }
1198*0Sstevel@tonic-gate 
1199*0Sstevel@tonic-gate /*
1200*0Sstevel@tonic-gate  * Fails with
1201*0Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
1202*0Sstevel@tonic-gate  */
1203*0Sstevel@tonic-gate static int
1204*0Sstevel@tonic-gate scope_insert_child(backend_tx_t *tx, rc_node_lookup_t *lp, const char *name)
1205*0Sstevel@tonic-gate {
1206*0Sstevel@tonic-gate 	return (backend_tx_run_update(tx,
1207*0Sstevel@tonic-gate 	    "INSERT INTO service_tbl (svc_id, svc_name) "
1208*0Sstevel@tonic-gate 	    "VALUES (%d, '%q')",
1209*0Sstevel@tonic-gate 	    lp->rl_main_id, name));
1210*0Sstevel@tonic-gate }
1211*0Sstevel@tonic-gate 
1212*0Sstevel@tonic-gate /*
1213*0Sstevel@tonic-gate  * Fails with
1214*0Sstevel@tonic-gate  *   _TYPE_MISMATCH - lp is not for an instance or property group
1215*0Sstevel@tonic-gate  *   _INVALID_TYPE - lp has invalid type
1216*0Sstevel@tonic-gate  *   _BAD_REQUEST - name is invalid
1217*0Sstevel@tonic-gate  */
1218*0Sstevel@tonic-gate static int
1219*0Sstevel@tonic-gate service_query_child(backend_query_t *q, rc_node_lookup_t *lp, const char *name)
1220*0Sstevel@tonic-gate {
1221*0Sstevel@tonic-gate 	uint32_t type = lp->rl_type;
1222*0Sstevel@tonic-gate 	int rc;
1223*0Sstevel@tonic-gate 
1224*0Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_INSTANCE &&
1225*0Sstevel@tonic-gate 	    type != REP_PROTOCOL_ENTITY_PROPERTYGRP)
1226*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
1227*0Sstevel@tonic-gate 
1228*0Sstevel@tonic-gate 	if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS)
1229*0Sstevel@tonic-gate 		return (rc);
1230*0Sstevel@tonic-gate 
1231*0Sstevel@tonic-gate 	switch (type) {
1232*0Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_INSTANCE:
1233*0Sstevel@tonic-gate 		backend_query_add(q,
1234*0Sstevel@tonic-gate 		    "SELECT instance_id FROM instance_tbl "
1235*0Sstevel@tonic-gate 		    "WHERE instance_name = '%q' AND instance_svc = %d",
1236*0Sstevel@tonic-gate 		    name, lp->rl_ids[ID_SERVICE]);
1237*0Sstevel@tonic-gate 		break;
1238*0Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
1239*0Sstevel@tonic-gate 		backend_query_add(q,
1240*0Sstevel@tonic-gate 		    "SELECT pg_id FROM pg_tbl "
1241*0Sstevel@tonic-gate 		    "    WHERE pg_name = '%q' AND pg_parent_id = %d",
1242*0Sstevel@tonic-gate 		    name, lp->rl_ids[ID_SERVICE]);
1243*0Sstevel@tonic-gate 		break;
1244*0Sstevel@tonic-gate 	default:
1245*0Sstevel@tonic-gate 		assert(0);
1246*0Sstevel@tonic-gate 		abort();
1247*0Sstevel@tonic-gate 	}
1248*0Sstevel@tonic-gate 
1249*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1250*0Sstevel@tonic-gate }
1251*0Sstevel@tonic-gate 
1252*0Sstevel@tonic-gate /*
1253*0Sstevel@tonic-gate  * Fails with
1254*0Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
1255*0Sstevel@tonic-gate  */
1256*0Sstevel@tonic-gate static int
1257*0Sstevel@tonic-gate service_insert_child(backend_tx_t *tx, rc_node_lookup_t *lp, const char *name)
1258*0Sstevel@tonic-gate {
1259*0Sstevel@tonic-gate 	return (backend_tx_run_update(tx,
1260*0Sstevel@tonic-gate 	    "INSERT INTO instance_tbl "
1261*0Sstevel@tonic-gate 	    "    (instance_id, instance_name, instance_svc) "
1262*0Sstevel@tonic-gate 	    "VALUES (%d, '%q', %d)",
1263*0Sstevel@tonic-gate 	    lp->rl_main_id, name, lp->rl_ids[ID_SERVICE]));
1264*0Sstevel@tonic-gate }
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate /*
1267*0Sstevel@tonic-gate  * Fails with
1268*0Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory
1269*0Sstevel@tonic-gate  */
1270*0Sstevel@tonic-gate static int
1271*0Sstevel@tonic-gate instance_insert_child(backend_tx_t *tx, rc_node_lookup_t *lp, const char *name)
1272*0Sstevel@tonic-gate {
1273*0Sstevel@tonic-gate 	return (backend_tx_run_update(tx,
1274*0Sstevel@tonic-gate 	    "INSERT INTO snapshot_lnk_tbl "
1275*0Sstevel@tonic-gate 	    "    (lnk_id, lnk_inst_id, lnk_snap_name, lnk_snap_id) "
1276*0Sstevel@tonic-gate 	    "VALUES (%d, %d, '%q', 0)",
1277*0Sstevel@tonic-gate 	    lp->rl_main_id, lp->rl_ids[ID_INSTANCE], name));
1278*0Sstevel@tonic-gate }
1279*0Sstevel@tonic-gate 
1280*0Sstevel@tonic-gate /*
1281*0Sstevel@tonic-gate  * Fails with
1282*0Sstevel@tonic-gate  *   _TYPE_MISMATCH - lp is not for a property group or snapshot
1283*0Sstevel@tonic-gate  *   _INVALID_TYPE - lp has invalid type
1284*0Sstevel@tonic-gate  *   _BAD_REQUEST - name is invalid
1285*0Sstevel@tonic-gate  */
1286*0Sstevel@tonic-gate static int
1287*0Sstevel@tonic-gate instance_query_child(backend_query_t *q, rc_node_lookup_t *lp, const char *name)
1288*0Sstevel@tonic-gate {
1289*0Sstevel@tonic-gate 	uint32_t type = lp->rl_type;
1290*0Sstevel@tonic-gate 	int rc;
1291*0Sstevel@tonic-gate 
1292*0Sstevel@tonic-gate 	if (type != REP_PROTOCOL_ENTITY_PROPERTYGRP &&
1293*0Sstevel@tonic-gate 	    type != REP_PROTOCOL_ENTITY_SNAPSHOT)
1294*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 	if ((rc = rc_check_type_name(type, name)) != REP_PROTOCOL_SUCCESS)
1297*0Sstevel@tonic-gate 		return (rc);
1298*0Sstevel@tonic-gate 
1299*0Sstevel@tonic-gate 	switch (type) {
1300*0Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_PROPERTYGRP:
1301*0Sstevel@tonic-gate 		backend_query_add(q,
1302*0Sstevel@tonic-gate 		    "SELECT pg_id FROM pg_tbl "
1303*0Sstevel@tonic-gate 		    "    WHERE pg_name = '%q' AND pg_parent_id = %d",
1304*0Sstevel@tonic-gate 		    name, lp->rl_ids[ID_INSTANCE]);
1305*0Sstevel@tonic-gate 		break;
1306*0Sstevel@tonic-gate 	case REP_PROTOCOL_ENTITY_SNAPSHOT:
1307*0Sstevel@tonic-gate 		backend_query_add(q,
1308*0Sstevel@tonic-gate 		    "SELECT lnk_id FROM snapshot_lnk_tbl "
1309*0Sstevel@tonic-gate 		    "    WHERE lnk_snap_name = '%q' AND lnk_inst_id = %d",
1310*0Sstevel@tonic-gate 		    name, lp->rl_ids[ID_INSTANCE]);
1311*0Sstevel@tonic-gate 		break;
1312*0Sstevel@tonic-gate 	default:
1313*0Sstevel@tonic-gate 		assert(0);
1314*0Sstevel@tonic-gate 		abort();
1315*0Sstevel@tonic-gate 	}
1316*0Sstevel@tonic-gate 
1317*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1318*0Sstevel@tonic-gate }
1319*0Sstevel@tonic-gate 
1320*0Sstevel@tonic-gate static int
1321*0Sstevel@tonic-gate generic_insert_pg_child(backend_tx_t *tx, rc_node_lookup_t *lp,
1322*0Sstevel@tonic-gate     const char *name, const char *pgtype, uint32_t flags, uint32_t gen)
1323*0Sstevel@tonic-gate {
1324*0Sstevel@tonic-gate 	int parent_id = (lp->rl_ids[ID_INSTANCE] != 0)?
1325*0Sstevel@tonic-gate 	    lp->rl_ids[ID_INSTANCE] : lp->rl_ids[ID_SERVICE];
1326*0Sstevel@tonic-gate 	return (backend_tx_run_update(tx,
1327*0Sstevel@tonic-gate 	    "INSERT INTO pg_tbl "
1328*0Sstevel@tonic-gate 	    "    (pg_id, pg_name, pg_parent_id, pg_type, pg_flags, pg_gen_id) "
1329*0Sstevel@tonic-gate 	    "VALUES (%d, '%q', %d, '%q', %d, %d)",
1330*0Sstevel@tonic-gate 	    lp->rl_main_id, name, parent_id, pgtype, flags, gen));
1331*0Sstevel@tonic-gate }
1332*0Sstevel@tonic-gate 
1333*0Sstevel@tonic-gate static int
1334*0Sstevel@tonic-gate service_delete_start(rc_node_t *np, delete_info_t *dip)
1335*0Sstevel@tonic-gate {
1336*0Sstevel@tonic-gate 	int r;
1337*0Sstevel@tonic-gate 	backend_query_t *q = backend_query_alloc();
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 	/*
1340*0Sstevel@tonic-gate 	 * Check for child instances, and refuse to delete if they exist.
1341*0Sstevel@tonic-gate 	 */
1342*0Sstevel@tonic-gate 	backend_query_add(q,
1343*0Sstevel@tonic-gate 	    "SELECT 1 FROM instance_tbl WHERE instance_svc = %d",
1344*0Sstevel@tonic-gate 	    np->rn_id.rl_main_id);
1345*0Sstevel@tonic-gate 
1346*0Sstevel@tonic-gate 	r = backend_tx_run(dip->di_tx, q, backend_fail_if_seen, NULL);
1347*0Sstevel@tonic-gate 	backend_query_free(q);
1348*0Sstevel@tonic-gate 
1349*0Sstevel@tonic-gate 	if (r == REP_PROTOCOL_DONE)
1350*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_EXISTS);	/* instances exist */
1351*0Sstevel@tonic-gate 
1352*0Sstevel@tonic-gate 	return (delete_stack_push(dip, BACKEND_TYPE_NORMAL, &service_delete,
1353*0Sstevel@tonic-gate 	    np->rn_id.rl_main_id, 0));
1354*0Sstevel@tonic-gate }
1355*0Sstevel@tonic-gate 
1356*0Sstevel@tonic-gate static int
1357*0Sstevel@tonic-gate instance_delete_start(rc_node_t *np, delete_info_t *dip)
1358*0Sstevel@tonic-gate {
1359*0Sstevel@tonic-gate 	return (delete_stack_push(dip, BACKEND_TYPE_NORMAL, &instance_delete,
1360*0Sstevel@tonic-gate 	    np->rn_id.rl_main_id, 0));
1361*0Sstevel@tonic-gate }
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate static int
1364*0Sstevel@tonic-gate snapshot_delete_start(rc_node_t *np, delete_info_t *dip)
1365*0Sstevel@tonic-gate {
1366*0Sstevel@tonic-gate 	return (delete_stack_push(dip, BACKEND_TYPE_NORMAL,
1367*0Sstevel@tonic-gate 	    &snapshot_lnk_delete, np->rn_id.rl_main_id, 0));
1368*0Sstevel@tonic-gate }
1369*0Sstevel@tonic-gate 
1370*0Sstevel@tonic-gate static int
1371*0Sstevel@tonic-gate propertygrp_delete_start(rc_node_t *np, delete_info_t *dip)
1372*0Sstevel@tonic-gate {
1373*0Sstevel@tonic-gate 	return (delete_stack_push(dip, np->rn_id.rl_backend,
1374*0Sstevel@tonic-gate 	    &propertygrp_delete, np->rn_id.rl_main_id, 0));
1375*0Sstevel@tonic-gate }
1376*0Sstevel@tonic-gate 
1377*0Sstevel@tonic-gate static object_info_t info[] = {
1378*0Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_NONE},
1379*0Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_SCOPE,
1380*0Sstevel@tonic-gate 		BACKEND_ID_INVALID,
1381*0Sstevel@tonic-gate 		scope_fill_children,
1382*0Sstevel@tonic-gate 		scope_setup_child_info,
1383*0Sstevel@tonic-gate 		scope_query_child,
1384*0Sstevel@tonic-gate 		scope_insert_child,
1385*0Sstevel@tonic-gate 		NULL,
1386*0Sstevel@tonic-gate 		NULL,
1387*0Sstevel@tonic-gate 	},
1388*0Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_SERVICE,
1389*0Sstevel@tonic-gate 		BACKEND_ID_SERVICE_INSTANCE,
1390*0Sstevel@tonic-gate 		service_fill_children,
1391*0Sstevel@tonic-gate 		service_setup_child_info,
1392*0Sstevel@tonic-gate 		service_query_child,
1393*0Sstevel@tonic-gate 		service_insert_child,
1394*0Sstevel@tonic-gate 		generic_insert_pg_child,
1395*0Sstevel@tonic-gate 		service_delete_start,
1396*0Sstevel@tonic-gate 	},
1397*0Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_INSTANCE,
1398*0Sstevel@tonic-gate 		BACKEND_ID_SERVICE_INSTANCE,
1399*0Sstevel@tonic-gate 		instance_fill_children,
1400*0Sstevel@tonic-gate 		instance_setup_child_info,
1401*0Sstevel@tonic-gate 		instance_query_child,
1402*0Sstevel@tonic-gate 		instance_insert_child,
1403*0Sstevel@tonic-gate 		generic_insert_pg_child,
1404*0Sstevel@tonic-gate 		instance_delete_start,
1405*0Sstevel@tonic-gate 	},
1406*0Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_SNAPSHOT,
1407*0Sstevel@tonic-gate 		BACKEND_ID_SNAPNAME,
1408*0Sstevel@tonic-gate 		snapshot_fill_children,
1409*0Sstevel@tonic-gate 		NULL,
1410*0Sstevel@tonic-gate 		NULL,
1411*0Sstevel@tonic-gate 		NULL,
1412*0Sstevel@tonic-gate 		NULL,
1413*0Sstevel@tonic-gate 		snapshot_delete_start,
1414*0Sstevel@tonic-gate 	},
1415*0Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_SNAPLEVEL,
1416*0Sstevel@tonic-gate 		BACKEND_ID_SNAPLEVEL,
1417*0Sstevel@tonic-gate 		snaplevel_fill_children,
1418*0Sstevel@tonic-gate 		snaplevel_setup_child_info,
1419*0Sstevel@tonic-gate 	},
1420*0Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_PROPERTYGRP,
1421*0Sstevel@tonic-gate 		BACKEND_ID_PROPERTYGRP,
1422*0Sstevel@tonic-gate 		propertygrp_fill_children,
1423*0Sstevel@tonic-gate 		NULL,
1424*0Sstevel@tonic-gate 		NULL,
1425*0Sstevel@tonic-gate 		NULL,
1426*0Sstevel@tonic-gate 		NULL,
1427*0Sstevel@tonic-gate 		propertygrp_delete_start,
1428*0Sstevel@tonic-gate 	},
1429*0Sstevel@tonic-gate 	{REP_PROTOCOL_ENTITY_PROPERTY},
1430*0Sstevel@tonic-gate 	{-1UL}
1431*0Sstevel@tonic-gate };
1432*0Sstevel@tonic-gate #define	NUM_INFO (sizeof (info) / sizeof (*info))
1433*0Sstevel@tonic-gate 
1434*0Sstevel@tonic-gate /*
1435*0Sstevel@tonic-gate  * object_fill_children() populates the child list of an rc_node_t by calling
1436*0Sstevel@tonic-gate  * the appropriate <type>_fill_children() which runs backend queries that
1437*0Sstevel@tonic-gate  * call an appropriate fill_*_callback() which takes a row of results,
1438*0Sstevel@tonic-gate  * decodes them, and calls an rc_node_setup*() function in rc_node.c to create
1439*0Sstevel@tonic-gate  * a child.
1440*0Sstevel@tonic-gate  *
1441*0Sstevel@tonic-gate  * Fails with
1442*0Sstevel@tonic-gate  *   _NO_RESOURCES
1443*0Sstevel@tonic-gate  */
1444*0Sstevel@tonic-gate int
1445*0Sstevel@tonic-gate object_fill_children(rc_node_t *pp)
1446*0Sstevel@tonic-gate {
1447*0Sstevel@tonic-gate 	uint32_t type = pp->rn_id.rl_type;
1448*0Sstevel@tonic-gate 	assert(type > 0 && type < NUM_INFO);
1449*0Sstevel@tonic-gate 
1450*0Sstevel@tonic-gate 	return ((*info[type].obj_fill_children)(pp));
1451*0Sstevel@tonic-gate }
1452*0Sstevel@tonic-gate 
1453*0Sstevel@tonic-gate int
1454*0Sstevel@tonic-gate object_delete(rc_node_t *pp)
1455*0Sstevel@tonic-gate {
1456*0Sstevel@tonic-gate 	int rc;
1457*0Sstevel@tonic-gate 
1458*0Sstevel@tonic-gate 	delete_info_t dip;
1459*0Sstevel@tonic-gate 	delete_ent_t de;
1460*0Sstevel@tonic-gate 
1461*0Sstevel@tonic-gate 	uint32_t type = pp->rn_id.rl_type;
1462*0Sstevel@tonic-gate 	assert(type > 0 && type < NUM_INFO);
1463*0Sstevel@tonic-gate 
1464*0Sstevel@tonic-gate 	if (info[type].obj_delete_start == NULL)
1465*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1466*0Sstevel@tonic-gate 
1467*0Sstevel@tonic-gate 	(void) memset(&dip, '\0', sizeof (dip));
1468*0Sstevel@tonic-gate 	rc = backend_tx_begin(BACKEND_TYPE_NORMAL, &dip.di_tx);
1469*0Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS)
1470*0Sstevel@tonic-gate 		return (rc);
1471*0Sstevel@tonic-gate 
1472*0Sstevel@tonic-gate 	rc = backend_tx_begin(BACKEND_TYPE_NONPERSIST, &dip.di_np_tx);
1473*0Sstevel@tonic-gate 	if (rc == REP_PROTOCOL_FAIL_BACKEND_ACCESS ||
1474*0Sstevel@tonic-gate 	    rc == REP_PROTOCOL_FAIL_BACKEND_READONLY)
1475*0Sstevel@tonic-gate 		dip.di_np_tx = NULL;
1476*0Sstevel@tonic-gate 	else if (rc != REP_PROTOCOL_SUCCESS) {
1477*0Sstevel@tonic-gate 		backend_tx_rollback(dip.di_tx);
1478*0Sstevel@tonic-gate 		return (rc);
1479*0Sstevel@tonic-gate 	}
1480*0Sstevel@tonic-gate 
1481*0Sstevel@tonic-gate 	if ((rc = (*info[type].obj_delete_start)(pp, &dip)) !=
1482*0Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
1483*0Sstevel@tonic-gate 		goto fail;
1484*0Sstevel@tonic-gate 	}
1485*0Sstevel@tonic-gate 
1486*0Sstevel@tonic-gate 	while (delete_stack_pop(&dip, &de)) {
1487*0Sstevel@tonic-gate 		rc = (*de.de_cb)(&dip, &de);
1488*0Sstevel@tonic-gate 		if (rc != REP_PROTOCOL_SUCCESS)
1489*0Sstevel@tonic-gate 			goto fail;
1490*0Sstevel@tonic-gate 	}
1491*0Sstevel@tonic-gate 
1492*0Sstevel@tonic-gate 	rc = backend_tx_commit(dip.di_tx);
1493*0Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS)
1494*0Sstevel@tonic-gate 		backend_tx_rollback(dip.di_np_tx);
1495*0Sstevel@tonic-gate 	else if (dip.di_np_tx)
1496*0Sstevel@tonic-gate 		(void) backend_tx_commit(dip.di_np_tx);
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate 	delete_stack_cleanup(&dip);
1499*0Sstevel@tonic-gate 
1500*0Sstevel@tonic-gate 	return (rc);
1501*0Sstevel@tonic-gate 
1502*0Sstevel@tonic-gate fail:
1503*0Sstevel@tonic-gate 	backend_tx_rollback(dip.di_tx);
1504*0Sstevel@tonic-gate 	backend_tx_rollback(dip.di_np_tx);
1505*0Sstevel@tonic-gate 	delete_stack_cleanup(&dip);
1506*0Sstevel@tonic-gate 	return (rc);
1507*0Sstevel@tonic-gate }
1508*0Sstevel@tonic-gate 
1509*0Sstevel@tonic-gate int
1510*0Sstevel@tonic-gate object_do_create(backend_tx_t *tx, child_info_t *cip, rc_node_t *pp,
1511*0Sstevel@tonic-gate     uint32_t type, const char *name, rc_node_t **cpp)
1512*0Sstevel@tonic-gate {
1513*0Sstevel@tonic-gate 	uint32_t ptype = pp->rn_id.rl_type;
1514*0Sstevel@tonic-gate 
1515*0Sstevel@tonic-gate 	backend_query_t *q;
1516*0Sstevel@tonic-gate 	uint32_t id;
1517*0Sstevel@tonic-gate 	rc_node_t *np = NULL;
1518*0Sstevel@tonic-gate 	int rc;
1519*0Sstevel@tonic-gate 	object_info_t *ip;
1520*0Sstevel@tonic-gate 
1521*0Sstevel@tonic-gate 	rc_node_lookup_t *lp = &cip->ci_base_nl;
1522*0Sstevel@tonic-gate 
1523*0Sstevel@tonic-gate 	assert(ptype > 0 && ptype < NUM_INFO);
1524*0Sstevel@tonic-gate 
1525*0Sstevel@tonic-gate 	ip = &info[ptype];
1526*0Sstevel@tonic-gate 
1527*0Sstevel@tonic-gate 	if (type == REP_PROTOCOL_ENTITY_PROPERTYGRP)
1528*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NOT_APPLICABLE);
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate 	if (ip->obj_setup_child_info == NULL ||
1531*0Sstevel@tonic-gate 	    ip->obj_query_child == NULL ||
1532*0Sstevel@tonic-gate 	    ip->obj_insert_child == NULL)
1533*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1534*0Sstevel@tonic-gate 
1535*0Sstevel@tonic-gate 	if ((rc = (*ip->obj_setup_child_info)(pp, type, cip)) !=
1536*0Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS)
1537*0Sstevel@tonic-gate 		return (rc);
1538*0Sstevel@tonic-gate 
1539*0Sstevel@tonic-gate 	q = backend_query_alloc();
1540*0Sstevel@tonic-gate 	if ((rc = (*ip->obj_query_child)(q, lp, name)) !=
1541*0Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
1542*0Sstevel@tonic-gate 		assert(rc == REP_PROTOCOL_FAIL_BAD_REQUEST);
1543*0Sstevel@tonic-gate 		backend_query_free(q);
1544*0Sstevel@tonic-gate 		return (rc);
1545*0Sstevel@tonic-gate 	}
1546*0Sstevel@tonic-gate 
1547*0Sstevel@tonic-gate 	rc = backend_tx_run_single_int(tx, q, &id);
1548*0Sstevel@tonic-gate 	backend_query_free(q);
1549*0Sstevel@tonic-gate 
1550*0Sstevel@tonic-gate 	if (rc == REP_PROTOCOL_SUCCESS)
1551*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_EXISTS);
1552*0Sstevel@tonic-gate 	else if (rc != REP_PROTOCOL_FAIL_NOT_FOUND)
1553*0Sstevel@tonic-gate 		return (rc);
1554*0Sstevel@tonic-gate 
1555*0Sstevel@tonic-gate 	if ((lp->rl_main_id = backend_new_id(tx,
1556*0Sstevel@tonic-gate 	    info[type].obj_id_space)) == 0) {
1557*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1558*0Sstevel@tonic-gate 	}
1559*0Sstevel@tonic-gate 
1560*0Sstevel@tonic-gate 	if ((np = rc_node_alloc()) == NULL)
1561*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1562*0Sstevel@tonic-gate 
1563*0Sstevel@tonic-gate 	if ((rc = (*ip->obj_insert_child)(tx, lp, name)) !=
1564*0Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
1565*0Sstevel@tonic-gate 		rc_node_destroy(np);
1566*0Sstevel@tonic-gate 		return (rc);
1567*0Sstevel@tonic-gate 	}
1568*0Sstevel@tonic-gate 
1569*0Sstevel@tonic-gate 	*cpp = np;
1570*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1571*0Sstevel@tonic-gate }
1572*0Sstevel@tonic-gate 
1573*0Sstevel@tonic-gate /*
1574*0Sstevel@tonic-gate  * Fails with
1575*0Sstevel@tonic-gate  *   _NOT_APPLICABLE - type is _PROPERTYGRP
1576*0Sstevel@tonic-gate  *   _BAD_REQUEST - cannot create children for this type of node
1577*0Sstevel@tonic-gate  *		    name is invalid
1578*0Sstevel@tonic-gate  *   _TYPE_MISMATCH - object cannot have children of type type
1579*0Sstevel@tonic-gate  *   _NO_RESOURCES - out of memory, or could not allocate new id
1580*0Sstevel@tonic-gate  *   _BACKEND_READONLY
1581*0Sstevel@tonic-gate  *   _BACKEND_ACCESS
1582*0Sstevel@tonic-gate  *   _EXISTS - child already exists
1583*0Sstevel@tonic-gate  */
1584*0Sstevel@tonic-gate int
1585*0Sstevel@tonic-gate object_create(rc_node_t *pp, uint32_t type, const char *name, rc_node_t **cpp)
1586*0Sstevel@tonic-gate {
1587*0Sstevel@tonic-gate 	backend_tx_t *tx;
1588*0Sstevel@tonic-gate 	rc_node_t *np = NULL;
1589*0Sstevel@tonic-gate 	child_info_t ci;
1590*0Sstevel@tonic-gate 	int rc;
1591*0Sstevel@tonic-gate 
1592*0Sstevel@tonic-gate 	if ((rc = backend_tx_begin(pp->rn_id.rl_backend, &tx)) !=
1593*0Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
1594*0Sstevel@tonic-gate 		return (rc);
1595*0Sstevel@tonic-gate 	}
1596*0Sstevel@tonic-gate 
1597*0Sstevel@tonic-gate 	if ((rc = object_do_create(tx, &ci, pp, type, name, &np)) !=
1598*0Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
1599*0Sstevel@tonic-gate 		backend_tx_rollback(tx);
1600*0Sstevel@tonic-gate 		return (rc);
1601*0Sstevel@tonic-gate 	}
1602*0Sstevel@tonic-gate 
1603*0Sstevel@tonic-gate 	rc = backend_tx_commit(tx);
1604*0Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS) {
1605*0Sstevel@tonic-gate 		rc_node_destroy(np);
1606*0Sstevel@tonic-gate 		return (rc);
1607*0Sstevel@tonic-gate 	}
1608*0Sstevel@tonic-gate 
1609*0Sstevel@tonic-gate 	*cpp = rc_node_setup(np, &ci.ci_base_nl, name, ci.ci_parent);
1610*0Sstevel@tonic-gate 
1611*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1612*0Sstevel@tonic-gate }
1613*0Sstevel@tonic-gate 
1614*0Sstevel@tonic-gate /*ARGSUSED*/
1615*0Sstevel@tonic-gate int
1616*0Sstevel@tonic-gate object_create_pg(rc_node_t *pp, uint32_t type, const char *name,
1617*0Sstevel@tonic-gate     const char *pgtype, uint32_t flags, rc_node_t **cpp)
1618*0Sstevel@tonic-gate {
1619*0Sstevel@tonic-gate 	uint32_t ptype = pp->rn_id.rl_type;
1620*0Sstevel@tonic-gate 	backend_tx_t *tx_ro, *tx_wr;
1621*0Sstevel@tonic-gate 	backend_query_t *q;
1622*0Sstevel@tonic-gate 	uint32_t id;
1623*0Sstevel@tonic-gate 	uint32_t gen = 0;
1624*0Sstevel@tonic-gate 	rc_node_t *np = NULL;
1625*0Sstevel@tonic-gate 	int rc;
1626*0Sstevel@tonic-gate 	int rc_wr;
1627*0Sstevel@tonic-gate 	int rc_ro;
1628*0Sstevel@tonic-gate 	object_info_t *ip;
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 	int nonpersist = (flags & SCF_PG_FLAG_NONPERSISTENT);
1631*0Sstevel@tonic-gate 
1632*0Sstevel@tonic-gate 	child_info_t ci;
1633*0Sstevel@tonic-gate 	rc_node_lookup_t *lp = &ci.ci_base_nl;
1634*0Sstevel@tonic-gate 
1635*0Sstevel@tonic-gate 	assert(ptype > 0 && ptype < NUM_INFO);
1636*0Sstevel@tonic-gate 
1637*0Sstevel@tonic-gate 	if (ptype != REP_PROTOCOL_ENTITY_SERVICE &&
1638*0Sstevel@tonic-gate 	    ptype != REP_PROTOCOL_ENTITY_INSTANCE)
1639*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1640*0Sstevel@tonic-gate 
1641*0Sstevel@tonic-gate 	ip = &info[ptype];
1642*0Sstevel@tonic-gate 
1643*0Sstevel@tonic-gate 	assert(ip->obj_setup_child_info != NULL &&
1644*0Sstevel@tonic-gate 	    ip->obj_query_child != NULL &&
1645*0Sstevel@tonic-gate 	    ip->obj_insert_pg_child != NULL);
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate 	if ((rc = (*ip->obj_setup_child_info)(pp, type, &ci)) !=
1648*0Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS)
1649*0Sstevel@tonic-gate 		return (rc);
1650*0Sstevel@tonic-gate 
1651*0Sstevel@tonic-gate 	q = backend_query_alloc();
1652*0Sstevel@tonic-gate 	if ((rc = (*ip->obj_query_child)(q, lp, name)) !=
1653*0Sstevel@tonic-gate 	    REP_PROTOCOL_SUCCESS) {
1654*0Sstevel@tonic-gate 		backend_query_free(q);
1655*0Sstevel@tonic-gate 		return (rc);
1656*0Sstevel@tonic-gate 	}
1657*0Sstevel@tonic-gate 
1658*0Sstevel@tonic-gate 	if (!nonpersist) {
1659*0Sstevel@tonic-gate 		lp->rl_backend = BACKEND_TYPE_NORMAL;
1660*0Sstevel@tonic-gate 		rc_wr = backend_tx_begin(BACKEND_TYPE_NORMAL, &tx_wr);
1661*0Sstevel@tonic-gate 		rc_ro = backend_tx_begin_ro(BACKEND_TYPE_NONPERSIST, &tx_ro);
1662*0Sstevel@tonic-gate 	} else {
1663*0Sstevel@tonic-gate 		lp->rl_backend = BACKEND_TYPE_NONPERSIST;
1664*0Sstevel@tonic-gate 		rc_ro = backend_tx_begin_ro(BACKEND_TYPE_NORMAL, &tx_ro);
1665*0Sstevel@tonic-gate 		rc_wr = backend_tx_begin(BACKEND_TYPE_NONPERSIST, &tx_wr);
1666*0Sstevel@tonic-gate 	}
1667*0Sstevel@tonic-gate 
1668*0Sstevel@tonic-gate 	if (rc_wr != REP_PROTOCOL_SUCCESS) {
1669*0Sstevel@tonic-gate 		rc = rc_wr;
1670*0Sstevel@tonic-gate 		goto fail;
1671*0Sstevel@tonic-gate 	}
1672*0Sstevel@tonic-gate 	if (rc_ro != REP_PROTOCOL_SUCCESS &&
1673*0Sstevel@tonic-gate 	    rc_ro != REP_PROTOCOL_FAIL_BACKEND_ACCESS) {
1674*0Sstevel@tonic-gate 		rc = rc_ro;
1675*0Sstevel@tonic-gate 		goto fail;
1676*0Sstevel@tonic-gate 	}
1677*0Sstevel@tonic-gate 
1678*0Sstevel@tonic-gate 	if (tx_ro != NULL) {
1679*0Sstevel@tonic-gate 		rc = backend_tx_run_single_int(tx_ro, q, &id);
1680*0Sstevel@tonic-gate 
1681*0Sstevel@tonic-gate 		if (rc == REP_PROTOCOL_SUCCESS) {
1682*0Sstevel@tonic-gate 			backend_query_free(q);
1683*0Sstevel@tonic-gate 			rc = REP_PROTOCOL_FAIL_EXISTS;
1684*0Sstevel@tonic-gate 			goto fail;
1685*0Sstevel@tonic-gate 		} else if (rc != REP_PROTOCOL_FAIL_NOT_FOUND) {
1686*0Sstevel@tonic-gate 			backend_query_free(q);
1687*0Sstevel@tonic-gate 			goto fail;
1688*0Sstevel@tonic-gate 		}
1689*0Sstevel@tonic-gate 	}
1690*0Sstevel@tonic-gate 
1691*0Sstevel@tonic-gate 	rc = backend_tx_run_single_int(tx_wr, q, &id);
1692*0Sstevel@tonic-gate 	backend_query_free(q);
1693*0Sstevel@tonic-gate 
1694*0Sstevel@tonic-gate 	if (rc == REP_PROTOCOL_SUCCESS) {
1695*0Sstevel@tonic-gate 		rc = REP_PROTOCOL_FAIL_EXISTS;
1696*0Sstevel@tonic-gate 		goto fail;
1697*0Sstevel@tonic-gate 	} else if (rc != REP_PROTOCOL_FAIL_NOT_FOUND) {
1698*0Sstevel@tonic-gate 		goto fail;
1699*0Sstevel@tonic-gate 	}
1700*0Sstevel@tonic-gate 
1701*0Sstevel@tonic-gate 	if (tx_ro != NULL)
1702*0Sstevel@tonic-gate 		backend_tx_end_ro(tx_ro);
1703*0Sstevel@tonic-gate 	tx_ro = NULL;
1704*0Sstevel@tonic-gate 
1705*0Sstevel@tonic-gate 	if ((lp->rl_main_id = backend_new_id(tx_wr,
1706*0Sstevel@tonic-gate 	    info[type].obj_id_space)) == 0) {
1707*0Sstevel@tonic-gate 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
1708*0Sstevel@tonic-gate 		goto fail;
1709*0Sstevel@tonic-gate 	}
1710*0Sstevel@tonic-gate 
1711*0Sstevel@tonic-gate 	if ((np = rc_node_alloc()) == NULL) {
1712*0Sstevel@tonic-gate 		rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
1713*0Sstevel@tonic-gate 		goto fail;
1714*0Sstevel@tonic-gate 	}
1715*0Sstevel@tonic-gate 
1716*0Sstevel@tonic-gate 	if ((rc = (*ip->obj_insert_pg_child)(tx_wr, lp, name, pgtype, flags,
1717*0Sstevel@tonic-gate 	    gen)) != REP_PROTOCOL_SUCCESS) {
1718*0Sstevel@tonic-gate 		rc_node_destroy(np);
1719*0Sstevel@tonic-gate 		goto fail;
1720*0Sstevel@tonic-gate 	}
1721*0Sstevel@tonic-gate 
1722*0Sstevel@tonic-gate 	rc = backend_tx_commit(tx_wr);
1723*0Sstevel@tonic-gate 	if (rc != REP_PROTOCOL_SUCCESS) {
1724*0Sstevel@tonic-gate 		rc_node_destroy(np);
1725*0Sstevel@tonic-gate 		return (rc);
1726*0Sstevel@tonic-gate 	}
1727*0Sstevel@tonic-gate 
1728*0Sstevel@tonic-gate 	*cpp = rc_node_setup_pg(np, lp, name, pgtype, flags, gen, ci.ci_parent);
1729*0Sstevel@tonic-gate 
1730*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
1731*0Sstevel@tonic-gate 
1732*0Sstevel@tonic-gate fail:
1733*0Sstevel@tonic-gate 	if (tx_ro != NULL)
1734*0Sstevel@tonic-gate 		backend_tx_end_ro(tx_ro);
1735*0Sstevel@tonic-gate 	if (tx_wr != NULL)
1736*0Sstevel@tonic-gate 		backend_tx_rollback(tx_wr);
1737*0Sstevel@tonic-gate 	return (rc);
1738*0Sstevel@tonic-gate }
1739*0Sstevel@tonic-gate 
1740*0Sstevel@tonic-gate /*
1741*0Sstevel@tonic-gate  * Given a row of snaplevel number, snaplevel id, service id, service name,
1742*0Sstevel@tonic-gate  * instance id, & instance name, create a rc_snaplevel_t & prepend it onto the
1743*0Sstevel@tonic-gate  * rs_levels list of the rc_snapshot_t passed in as data.
1744*0Sstevel@tonic-gate  * Returns _CONTINUE on success or _ABORT if any allocations fail.
1745*0Sstevel@tonic-gate  */
1746*0Sstevel@tonic-gate /*ARGSUSED*/
1747*0Sstevel@tonic-gate static int
1748*0Sstevel@tonic-gate fill_snapshot_cb(void *data, int columns, char **vals, char **names)
1749*0Sstevel@tonic-gate {
1750*0Sstevel@tonic-gate 	rc_snapshot_t *sp = data;
1751*0Sstevel@tonic-gate 	rc_snaplevel_t *lvl;
1752*0Sstevel@tonic-gate 	char *num = vals[0];
1753*0Sstevel@tonic-gate 	char *id = vals[1];
1754*0Sstevel@tonic-gate 	char *service_id = vals[2];
1755*0Sstevel@tonic-gate 	char *service = vals[3];
1756*0Sstevel@tonic-gate 	char *instance_id = vals[4];
1757*0Sstevel@tonic-gate 	char *instance = vals[5];
1758*0Sstevel@tonic-gate 	assert(columns == 6);
1759*0Sstevel@tonic-gate 
1760*0Sstevel@tonic-gate 	lvl = uu_zalloc(sizeof (*lvl));
1761*0Sstevel@tonic-gate 	if (lvl == NULL)
1762*0Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
1763*0Sstevel@tonic-gate 	lvl->rsl_parent = sp;
1764*0Sstevel@tonic-gate 	lvl->rsl_next = sp->rs_levels;
1765*0Sstevel@tonic-gate 	sp->rs_levels = lvl;
1766*0Sstevel@tonic-gate 
1767*0Sstevel@tonic-gate 	if (uu_strtouint(num, &lvl->rsl_level_num,
1768*0Sstevel@tonic-gate 	    sizeof (lvl->rsl_level_num), 0, 0, 0) == -1 ||
1769*0Sstevel@tonic-gate 	    uu_strtouint(id, &lvl->rsl_level_id,
1770*0Sstevel@tonic-gate 	    sizeof (lvl->rsl_level_id), 0, 0, 0) == -1 ||
1771*0Sstevel@tonic-gate 	    uu_strtouint(service_id, &lvl->rsl_service_id,
1772*0Sstevel@tonic-gate 	    sizeof (lvl->rsl_level_num), 0, 0, 0) == -1 ||
1773*0Sstevel@tonic-gate 	    (instance_id != NULL &&
1774*0Sstevel@tonic-gate 	    uu_strtouint(instance_id, &lvl->rsl_instance_id,
1775*0Sstevel@tonic-gate 	    sizeof (lvl->rsl_instance_id), 0, 0, 0) == -1)) {
1776*0Sstevel@tonic-gate 		backend_panic("invalid integer in database");
1777*0Sstevel@tonic-gate 	}
1778*0Sstevel@tonic-gate 
1779*0Sstevel@tonic-gate 	lvl->rsl_scope = (const char *)"localhost";
1780*0Sstevel@tonic-gate 	lvl->rsl_service = strdup(service);
1781*0Sstevel@tonic-gate 	if (lvl->rsl_service == NULL) {
1782*0Sstevel@tonic-gate 		uu_free(lvl);
1783*0Sstevel@tonic-gate 		return (BACKEND_CALLBACK_ABORT);
1784*0Sstevel@tonic-gate 	}
1785*0Sstevel@tonic-gate 	if (instance) {
1786*0Sstevel@tonic-gate 		assert(lvl->rsl_instance_id != 0);
1787*0Sstevel@tonic-gate 		lvl->rsl_instance = strdup(instance);
1788*0Sstevel@tonic-gate 		if (lvl->rsl_instance == NULL) {
1789*0Sstevel@tonic-gate 			free((void *)lvl->rsl_instance);
1790*0Sstevel@tonic-gate 			uu_free(lvl);
1791*0Sstevel@tonic-gate 			return (BACKEND_CALLBACK_ABORT);
1792*0Sstevel@tonic-gate 		}
1793*0Sstevel@tonic-gate 	} else {
1794*0Sstevel@tonic-gate 		assert(lvl->rsl_instance_id == 0);
1795*0Sstevel@tonic-gate 	}
1796*0Sstevel@tonic-gate 
1797*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
1798*0Sstevel@tonic-gate }
1799*0Sstevel@tonic-gate 
1800*0Sstevel@tonic-gate /*
1801*0Sstevel@tonic-gate  * Populate sp's rs_levels list from the snaplevel_tbl table.
1802*0Sstevel@tonic-gate  * Fails with
1803*0Sstevel@tonic-gate  *   _NO_RESOURCES
1804*0Sstevel@tonic-gate  */
1805*0Sstevel@tonic-gate int
1806*0Sstevel@tonic-gate object_fill_snapshot(rc_snapshot_t *sp)
1807*0Sstevel@tonic-gate {
1808*0Sstevel@tonic-gate 	backend_query_t *q;
1809*0Sstevel@tonic-gate 	rc_snaplevel_t *sl;
1810*0Sstevel@tonic-gate 	int result;
1811*0Sstevel@tonic-gate 	int i;
1812*0Sstevel@tonic-gate 
1813*0Sstevel@tonic-gate 	q = backend_query_alloc();
1814*0Sstevel@tonic-gate 	backend_query_add(q,
1815*0Sstevel@tonic-gate 	    "SELECT snap_level_num, snap_level_id, "
1816*0Sstevel@tonic-gate 	    "    snap_level_service_id, snap_level_service, "
1817*0Sstevel@tonic-gate 	    "    snap_level_instance_id, snap_level_instance "
1818*0Sstevel@tonic-gate 	    "FROM snaplevel_tbl "
1819*0Sstevel@tonic-gate 	    "WHERE snap_id = %d "
1820*0Sstevel@tonic-gate 	    "ORDER BY snap_level_id DESC",
1821*0Sstevel@tonic-gate 	    sp->rs_snap_id);
1822*0Sstevel@tonic-gate 
1823*0Sstevel@tonic-gate 	result = backend_run(BACKEND_TYPE_NORMAL, q, fill_snapshot_cb, sp);
1824*0Sstevel@tonic-gate 	if (result == REP_PROTOCOL_DONE)
1825*0Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_NO_RESOURCES;
1826*0Sstevel@tonic-gate 	backend_query_free(q);
1827*0Sstevel@tonic-gate 
1828*0Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS) {
1829*0Sstevel@tonic-gate 		i = 0;
1830*0Sstevel@tonic-gate 		for (sl = sp->rs_levels; sl != NULL; sl = sl->rsl_next) {
1831*0Sstevel@tonic-gate 			if (sl->rsl_level_num != ++i) {
1832*0Sstevel@tonic-gate 				backend_panic("snaplevels corrupt; expected "
1833*0Sstevel@tonic-gate 				    "level %d, got %d", i, sl->rsl_level_num);
1834*0Sstevel@tonic-gate 			}
1835*0Sstevel@tonic-gate 		}
1836*0Sstevel@tonic-gate 	}
1837*0Sstevel@tonic-gate 	return (result);
1838*0Sstevel@tonic-gate }
1839*0Sstevel@tonic-gate 
1840*0Sstevel@tonic-gate /*ARGSUSED*/
1841*0Sstevel@tonic-gate static int
1842*0Sstevel@tonic-gate object_copy_string(void *data_arg, int columns, char **vals, char **names)
1843*0Sstevel@tonic-gate {
1844*0Sstevel@tonic-gate 	char **data = data_arg;
1845*0Sstevel@tonic-gate 
1846*0Sstevel@tonic-gate 	assert(columns == 1);
1847*0Sstevel@tonic-gate 
1848*0Sstevel@tonic-gate 	if (*data != NULL)
1849*0Sstevel@tonic-gate 		free(*data);
1850*0Sstevel@tonic-gate 	*data = NULL;
1851*0Sstevel@tonic-gate 
1852*0Sstevel@tonic-gate 	if (vals[0] != NULL) {
1853*0Sstevel@tonic-gate 		if ((*data = strdup(vals[0])) == NULL)
1854*0Sstevel@tonic-gate 			return (BACKEND_CALLBACK_ABORT);
1855*0Sstevel@tonic-gate 	}
1856*0Sstevel@tonic-gate 
1857*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
1858*0Sstevel@tonic-gate }
1859*0Sstevel@tonic-gate 
1860*0Sstevel@tonic-gate struct snaplevel_add_info {
1861*0Sstevel@tonic-gate 	backend_query_t *sai_q;
1862*0Sstevel@tonic-gate 	uint32_t	sai_level_id;
1863*0Sstevel@tonic-gate 	int		sai_used;		/* sai_q has been used */
1864*0Sstevel@tonic-gate };
1865*0Sstevel@tonic-gate 
1866*0Sstevel@tonic-gate /*ARGSUSED*/
1867*0Sstevel@tonic-gate static int
1868*0Sstevel@tonic-gate object_snaplevel_process_pg(void *data_arg, int columns, char **vals,
1869*0Sstevel@tonic-gate     char **names)
1870*0Sstevel@tonic-gate {
1871*0Sstevel@tonic-gate 	struct snaplevel_add_info *data = data_arg;
1872*0Sstevel@tonic-gate 
1873*0Sstevel@tonic-gate 	assert(columns == 5);
1874*0Sstevel@tonic-gate 
1875*0Sstevel@tonic-gate 	backend_query_add(data->sai_q,
1876*0Sstevel@tonic-gate 	    "INSERT INTO snaplevel_lnk_tbl "
1877*0Sstevel@tonic-gate 	    "    (snaplvl_level_id, snaplvl_pg_id, snaplvl_pg_name, "
1878*0Sstevel@tonic-gate 	    "    snaplvl_pg_type, snaplvl_pg_flags, snaplvl_gen_id)"
1879*0Sstevel@tonic-gate 	    "VALUES (%d, %s, '%q', '%q', %s, %s);",
1880*0Sstevel@tonic-gate 	    data->sai_level_id, vals[0], vals[1], vals[2], vals[3], vals[4]);
1881*0Sstevel@tonic-gate 
1882*0Sstevel@tonic-gate 	data->sai_used = 1;
1883*0Sstevel@tonic-gate 
1884*0Sstevel@tonic-gate 	return (BACKEND_CALLBACK_CONTINUE);
1885*0Sstevel@tonic-gate }
1886*0Sstevel@tonic-gate 
1887*0Sstevel@tonic-gate /*ARGSUSED*/
1888*0Sstevel@tonic-gate static int
1889*0Sstevel@tonic-gate object_snapshot_add_level(backend_tx_t *tx, uint32_t snap_id,
1890*0Sstevel@tonic-gate     uint32_t snap_level_num, uint32_t svc_id, const char *svc_name,
1891*0Sstevel@tonic-gate     uint32_t inst_id, const char *inst_name)
1892*0Sstevel@tonic-gate {
1893*0Sstevel@tonic-gate 	struct snaplevel_add_info data;
1894*0Sstevel@tonic-gate 	backend_query_t *q;
1895*0Sstevel@tonic-gate 	int result;
1896*0Sstevel@tonic-gate 
1897*0Sstevel@tonic-gate 	assert((snap_level_num == 1 && inst_name != NULL) ||
1898*0Sstevel@tonic-gate 	    snap_level_num == 2 && inst_name == NULL);
1899*0Sstevel@tonic-gate 
1900*0Sstevel@tonic-gate 	data.sai_level_id = backend_new_id(tx, BACKEND_ID_SNAPLEVEL);
1901*0Sstevel@tonic-gate 	if (data.sai_level_id == 0) {
1902*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1903*0Sstevel@tonic-gate 	}
1904*0Sstevel@tonic-gate 
1905*0Sstevel@tonic-gate 	result = backend_tx_run_update(tx,
1906*0Sstevel@tonic-gate 	    "INSERT INTO snaplevel_tbl "
1907*0Sstevel@tonic-gate 	    "    (snap_id, snap_level_num, snap_level_id, "
1908*0Sstevel@tonic-gate 	    "    snap_level_service_id, snap_level_service, "
1909*0Sstevel@tonic-gate 	    "    snap_level_instance_id, snap_level_instance) "
1910*0Sstevel@tonic-gate 	    "VALUES (%d, %d, %d, %d, %Q, %d, %Q);",
1911*0Sstevel@tonic-gate 	    snap_id, snap_level_num, data.sai_level_id, svc_id, svc_name,
1912*0Sstevel@tonic-gate 	    inst_id, inst_name);
1913*0Sstevel@tonic-gate 
1914*0Sstevel@tonic-gate 	q = backend_query_alloc();
1915*0Sstevel@tonic-gate 	backend_query_add(q,
1916*0Sstevel@tonic-gate 	    "SELECT pg_id, pg_name, pg_type, pg_flags, pg_gen_id FROM pg_tbl "
1917*0Sstevel@tonic-gate 	    "WHERE (pg_parent_id = %d);",
1918*0Sstevel@tonic-gate 	    (inst_name != NULL)? inst_id : svc_id);
1919*0Sstevel@tonic-gate 
1920*0Sstevel@tonic-gate 	data.sai_q = backend_query_alloc();
1921*0Sstevel@tonic-gate 	data.sai_used = 0;
1922*0Sstevel@tonic-gate 	result = backend_tx_run(tx, q, object_snaplevel_process_pg,
1923*0Sstevel@tonic-gate 	    &data);
1924*0Sstevel@tonic-gate 	backend_query_free(q);
1925*0Sstevel@tonic-gate 
1926*0Sstevel@tonic-gate 	if (result == REP_PROTOCOL_SUCCESS && data.sai_used != 0)
1927*0Sstevel@tonic-gate 		result = backend_tx_run(tx, data.sai_q, NULL, NULL);
1928*0Sstevel@tonic-gate 	backend_query_free(data.sai_q);
1929*0Sstevel@tonic-gate 
1930*0Sstevel@tonic-gate 	return (result);
1931*0Sstevel@tonic-gate }
1932*0Sstevel@tonic-gate 
1933*0Sstevel@tonic-gate /*
1934*0Sstevel@tonic-gate  * Fails with:
1935*0Sstevel@tonic-gate  *	_NO_RESOURCES - no new id or out of disk space
1936*0Sstevel@tonic-gate  *	_BACKEND_READONLY - persistent backend is read-only
1937*0Sstevel@tonic-gate  */
1938*0Sstevel@tonic-gate static int
1939*0Sstevel@tonic-gate object_snapshot_do_take(uint32_t instid, const char *inst_name,
1940*0Sstevel@tonic-gate     uint32_t svcid, const char *svc_name,
1941*0Sstevel@tonic-gate     backend_tx_t **tx_out, uint32_t *snapid_out)
1942*0Sstevel@tonic-gate {
1943*0Sstevel@tonic-gate 	backend_tx_t *tx;
1944*0Sstevel@tonic-gate 	backend_query_t *q;
1945*0Sstevel@tonic-gate 	int result;
1946*0Sstevel@tonic-gate 
1947*0Sstevel@tonic-gate 	char *svc_name_alloc = NULL;
1948*0Sstevel@tonic-gate 	char *inst_name_alloc = NULL;
1949*0Sstevel@tonic-gate 	uint32_t snapid;
1950*0Sstevel@tonic-gate 
1951*0Sstevel@tonic-gate 	result = backend_tx_begin(BACKEND_TYPE_NORMAL, &tx);
1952*0Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
1953*0Sstevel@tonic-gate 		return (result);
1954*0Sstevel@tonic-gate 
1955*0Sstevel@tonic-gate 	snapid = backend_new_id(tx, BACKEND_ID_SNAPSHOT);
1956*0Sstevel@tonic-gate 	if (snapid == 0) {
1957*0Sstevel@tonic-gate 		result = REP_PROTOCOL_FAIL_NO_RESOURCES;
1958*0Sstevel@tonic-gate 		goto fail;
1959*0Sstevel@tonic-gate 	}
1960*0Sstevel@tonic-gate 
1961*0Sstevel@tonic-gate 	if (svc_name == NULL) {
1962*0Sstevel@tonic-gate 		q = backend_query_alloc();
1963*0Sstevel@tonic-gate 		backend_query_add(q,
1964*0Sstevel@tonic-gate 		    "SELECT svc_name FROM service_tbl "
1965*0Sstevel@tonic-gate 		    "WHERE (svc_id = %d)", svcid);
1966*0Sstevel@tonic-gate 		result = backend_tx_run(tx, q, object_copy_string,
1967*0Sstevel@tonic-gate 		    &svc_name_alloc);
1968*0Sstevel@tonic-gate 		backend_query_free(q);
1969*0Sstevel@tonic-gate 
1970*0Sstevel@tonic-gate 		svc_name = svc_name_alloc;
1971*0Sstevel@tonic-gate 
1972*0Sstevel@tonic-gate 		if (result == REP_PROTOCOL_DONE) {
1973*0Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_NO_RESOURCES;
1974*0Sstevel@tonic-gate 			goto fail;
1975*0Sstevel@tonic-gate 		}
1976*0Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS && svc_name == NULL)
1977*0Sstevel@tonic-gate 			backend_panic("unable to find name for svc id %d\n",
1978*0Sstevel@tonic-gate 			    svcid);
1979*0Sstevel@tonic-gate 
1980*0Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
1981*0Sstevel@tonic-gate 			goto fail;
1982*0Sstevel@tonic-gate 	}
1983*0Sstevel@tonic-gate 
1984*0Sstevel@tonic-gate 	if (inst_name == NULL) {
1985*0Sstevel@tonic-gate 		q = backend_query_alloc();
1986*0Sstevel@tonic-gate 		backend_query_add(q,
1987*0Sstevel@tonic-gate 		    "SELECT instance_name FROM instance_tbl "
1988*0Sstevel@tonic-gate 		    "WHERE (instance_id = %d)", instid);
1989*0Sstevel@tonic-gate 		result = backend_tx_run(tx, q, object_copy_string,
1990*0Sstevel@tonic-gate 		    &inst_name_alloc);
1991*0Sstevel@tonic-gate 		backend_query_free(q);
1992*0Sstevel@tonic-gate 
1993*0Sstevel@tonic-gate 		inst_name = inst_name_alloc;
1994*0Sstevel@tonic-gate 
1995*0Sstevel@tonic-gate 		if (result == REP_PROTOCOL_DONE) {
1996*0Sstevel@tonic-gate 			result = REP_PROTOCOL_FAIL_NO_RESOURCES;
1997*0Sstevel@tonic-gate 			goto fail;
1998*0Sstevel@tonic-gate 		}
1999*0Sstevel@tonic-gate 
2000*0Sstevel@tonic-gate 		if (result == REP_PROTOCOL_SUCCESS && inst_name == NULL)
2001*0Sstevel@tonic-gate 			backend_panic(
2002*0Sstevel@tonic-gate 			    "unable to find name for instance id %d\n", instid);
2003*0Sstevel@tonic-gate 
2004*0Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
2005*0Sstevel@tonic-gate 			goto fail;
2006*0Sstevel@tonic-gate 	}
2007*0Sstevel@tonic-gate 
2008*0Sstevel@tonic-gate 	result = object_snapshot_add_level(tx, snapid, 1,
2009*0Sstevel@tonic-gate 	    svcid, svc_name, instid, inst_name);
2010*0Sstevel@tonic-gate 
2011*0Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
2012*0Sstevel@tonic-gate 		goto fail;
2013*0Sstevel@tonic-gate 
2014*0Sstevel@tonic-gate 	result = object_snapshot_add_level(tx, snapid, 2,
2015*0Sstevel@tonic-gate 	    svcid, svc_name, 0, NULL);
2016*0Sstevel@tonic-gate 
2017*0Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
2018*0Sstevel@tonic-gate 		goto fail;
2019*0Sstevel@tonic-gate 
2020*0Sstevel@tonic-gate 	*snapid_out = snapid;
2021*0Sstevel@tonic-gate 	*tx_out = tx;
2022*0Sstevel@tonic-gate 
2023*0Sstevel@tonic-gate 	free(svc_name_alloc);
2024*0Sstevel@tonic-gate 	free(inst_name_alloc);
2025*0Sstevel@tonic-gate 
2026*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
2027*0Sstevel@tonic-gate 
2028*0Sstevel@tonic-gate fail:
2029*0Sstevel@tonic-gate 	backend_tx_rollback(tx);
2030*0Sstevel@tonic-gate 	free(svc_name_alloc);
2031*0Sstevel@tonic-gate 	free(inst_name_alloc);
2032*0Sstevel@tonic-gate 	return (result);
2033*0Sstevel@tonic-gate }
2034*0Sstevel@tonic-gate 
2035*0Sstevel@tonic-gate /*
2036*0Sstevel@tonic-gate  * Fails with:
2037*0Sstevel@tonic-gate  *	_TYPE_MISMATCH - pp is not an instance
2038*0Sstevel@tonic-gate  *	_NO_RESOURCES - no new id or out of disk space
2039*0Sstevel@tonic-gate  *	_BACKEND_READONLY - persistent backend is read-only
2040*0Sstevel@tonic-gate  */
2041*0Sstevel@tonic-gate int
2042*0Sstevel@tonic-gate object_snapshot_take_new(rc_node_t *pp,
2043*0Sstevel@tonic-gate     const char *svc_name, const char *inst_name,
2044*0Sstevel@tonic-gate     const char *name, rc_node_t **outp)
2045*0Sstevel@tonic-gate {
2046*0Sstevel@tonic-gate 	rc_node_lookup_t *insti = &pp->rn_id;
2047*0Sstevel@tonic-gate 
2048*0Sstevel@tonic-gate 	uint32_t instid = insti->rl_main_id;
2049*0Sstevel@tonic-gate 	uint32_t svcid = insti->rl_ids[ID_SERVICE];
2050*0Sstevel@tonic-gate 	uint32_t snapid = 0;
2051*0Sstevel@tonic-gate 	backend_tx_t *tx = NULL;
2052*0Sstevel@tonic-gate 	child_info_t ci;
2053*0Sstevel@tonic-gate 	rc_node_t *np;
2054*0Sstevel@tonic-gate 	int result;
2055*0Sstevel@tonic-gate 
2056*0Sstevel@tonic-gate 	if (insti->rl_type != REP_PROTOCOL_ENTITY_INSTANCE)
2057*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
2058*0Sstevel@tonic-gate 
2059*0Sstevel@tonic-gate 	result = object_snapshot_do_take(instid, inst_name, svcid, svc_name,
2060*0Sstevel@tonic-gate 	    &tx, &snapid);
2061*0Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
2062*0Sstevel@tonic-gate 		return (result);
2063*0Sstevel@tonic-gate 
2064*0Sstevel@tonic-gate 	if ((result = object_do_create(tx, &ci, pp,
2065*0Sstevel@tonic-gate 	    REP_PROTOCOL_ENTITY_SNAPSHOT, name, &np)) != REP_PROTOCOL_SUCCESS) {
2066*0Sstevel@tonic-gate 		backend_tx_rollback(tx);
2067*0Sstevel@tonic-gate 		return (result);
2068*0Sstevel@tonic-gate 	}
2069*0Sstevel@tonic-gate 
2070*0Sstevel@tonic-gate 	/*
2071*0Sstevel@tonic-gate 	 * link the new object to the new snapshot.
2072*0Sstevel@tonic-gate 	 */
2073*0Sstevel@tonic-gate 	np->rn_snapshot_id = snapid;
2074*0Sstevel@tonic-gate 
2075*0Sstevel@tonic-gate 	result = backend_tx_run_update(tx,
2076*0Sstevel@tonic-gate 	    "UPDATE snapshot_lnk_tbl SET lnk_snap_id = %d WHERE lnk_id = %d;",
2077*0Sstevel@tonic-gate 	    snapid, ci.ci_base_nl.rl_main_id);
2078*0Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS) {
2079*0Sstevel@tonic-gate 		backend_tx_rollback(tx);
2080*0Sstevel@tonic-gate 		rc_node_destroy(np);
2081*0Sstevel@tonic-gate 		return (result);
2082*0Sstevel@tonic-gate 	}
2083*0Sstevel@tonic-gate 	result = backend_tx_commit(tx);
2084*0Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS) {
2085*0Sstevel@tonic-gate 		rc_node_destroy(np);
2086*0Sstevel@tonic-gate 		return (result);
2087*0Sstevel@tonic-gate 	}
2088*0Sstevel@tonic-gate 
2089*0Sstevel@tonic-gate 	*outp = rc_node_setup(np, &ci.ci_base_nl, name, ci.ci_parent);
2090*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
2091*0Sstevel@tonic-gate }
2092*0Sstevel@tonic-gate 
2093*0Sstevel@tonic-gate /*
2094*0Sstevel@tonic-gate  * Fails with:
2095*0Sstevel@tonic-gate  *	_TYPE_MISMATCH - pp is not an instance
2096*0Sstevel@tonic-gate  *	_NO_RESOURCES - no new id or out of disk space
2097*0Sstevel@tonic-gate  *	_BACKEND_READONLY - persistent backend is read-only
2098*0Sstevel@tonic-gate  */
2099*0Sstevel@tonic-gate int
2100*0Sstevel@tonic-gate object_snapshot_attach(rc_node_lookup_t *snapi, uint32_t *snapid_ptr,
2101*0Sstevel@tonic-gate     int takesnap)
2102*0Sstevel@tonic-gate {
2103*0Sstevel@tonic-gate 	uint32_t svcid = snapi->rl_ids[ID_SERVICE];
2104*0Sstevel@tonic-gate 	uint32_t instid = snapi->rl_ids[ID_INSTANCE];
2105*0Sstevel@tonic-gate 	uint32_t snapid = *snapid_ptr;
2106*0Sstevel@tonic-gate 	uint32_t oldsnapid = 0;
2107*0Sstevel@tonic-gate 	backend_tx_t *tx = NULL;
2108*0Sstevel@tonic-gate 	backend_query_t *q;
2109*0Sstevel@tonic-gate 	int result;
2110*0Sstevel@tonic-gate 
2111*0Sstevel@tonic-gate 	delete_info_t dip;
2112*0Sstevel@tonic-gate 	delete_ent_t de;
2113*0Sstevel@tonic-gate 
2114*0Sstevel@tonic-gate 	if (snapi->rl_type != REP_PROTOCOL_ENTITY_SNAPSHOT)
2115*0Sstevel@tonic-gate 		return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
2116*0Sstevel@tonic-gate 
2117*0Sstevel@tonic-gate 	if (takesnap) {
2118*0Sstevel@tonic-gate 		result = object_snapshot_do_take(instid, NULL,
2119*0Sstevel@tonic-gate 		    svcid, NULL, &tx, &snapid);
2120*0Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
2121*0Sstevel@tonic-gate 			return (result);
2122*0Sstevel@tonic-gate 	} else {
2123*0Sstevel@tonic-gate 		result = backend_tx_begin(BACKEND_TYPE_NORMAL, &tx);
2124*0Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
2125*0Sstevel@tonic-gate 			return (result);
2126*0Sstevel@tonic-gate 	}
2127*0Sstevel@tonic-gate 
2128*0Sstevel@tonic-gate 	q = backend_query_alloc();
2129*0Sstevel@tonic-gate 	backend_query_add(q,
2130*0Sstevel@tonic-gate 	    "SELECT lnk_snap_id FROM snapshot_lnk_tbl WHERE lnk_id = %d; "
2131*0Sstevel@tonic-gate 	    "UPDATE snapshot_lnk_tbl SET lnk_snap_id = %d WHERE lnk_id = %d;",
2132*0Sstevel@tonic-gate 	    snapi->rl_main_id, snapid, snapi->rl_main_id);
2133*0Sstevel@tonic-gate 	result = backend_tx_run_single_int(tx, q, &oldsnapid);
2134*0Sstevel@tonic-gate 	backend_query_free(q);
2135*0Sstevel@tonic-gate 
2136*0Sstevel@tonic-gate 	if (result == REP_PROTOCOL_FAIL_NOT_FOUND) {
2137*0Sstevel@tonic-gate 		backend_tx_rollback(tx);
2138*0Sstevel@tonic-gate 		backend_panic("unable to find snapshot id %d",
2139*0Sstevel@tonic-gate 		    snapi->rl_main_id);
2140*0Sstevel@tonic-gate 	}
2141*0Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
2142*0Sstevel@tonic-gate 		goto fail;
2143*0Sstevel@tonic-gate 
2144*0Sstevel@tonic-gate 	/*
2145*0Sstevel@tonic-gate 	 * Now we use the delete stack to handle the possible unreferencing
2146*0Sstevel@tonic-gate 	 * of oldsnapid.
2147*0Sstevel@tonic-gate 	 */
2148*0Sstevel@tonic-gate 	(void) memset(&dip, 0, sizeof (dip));
2149*0Sstevel@tonic-gate 	dip.di_tx = tx;
2150*0Sstevel@tonic-gate 	dip.di_np_tx = NULL;	/* no need for non-persistant backend */
2151*0Sstevel@tonic-gate 
2152*0Sstevel@tonic-gate 	if ((result = delete_stack_push(&dip, BACKEND_TYPE_NORMAL,
2153*0Sstevel@tonic-gate 	    &snaplevel_tbl_delete, oldsnapid, 0)) != REP_PROTOCOL_SUCCESS)
2154*0Sstevel@tonic-gate 		goto fail;
2155*0Sstevel@tonic-gate 
2156*0Sstevel@tonic-gate 	while (delete_stack_pop(&dip, &de)) {
2157*0Sstevel@tonic-gate 		result = (*de.de_cb)(&dip, &de);
2158*0Sstevel@tonic-gate 		if (result != REP_PROTOCOL_SUCCESS)
2159*0Sstevel@tonic-gate 			goto fail;
2160*0Sstevel@tonic-gate 	}
2161*0Sstevel@tonic-gate 
2162*0Sstevel@tonic-gate 	result = backend_tx_commit(tx);
2163*0Sstevel@tonic-gate 	if (result != REP_PROTOCOL_SUCCESS)
2164*0Sstevel@tonic-gate 		goto fail;
2165*0Sstevel@tonic-gate 
2166*0Sstevel@tonic-gate 	delete_stack_cleanup(&dip);
2167*0Sstevel@tonic-gate 	*snapid_ptr = snapid;
2168*0Sstevel@tonic-gate 	return (REP_PROTOCOL_SUCCESS);
2169*0Sstevel@tonic-gate 
2170*0Sstevel@tonic-gate fail:
2171*0Sstevel@tonic-gate 	backend_tx_rollback(tx);
2172*0Sstevel@tonic-gate 	delete_stack_cleanup(&dip);
2173*0Sstevel@tonic-gate 	return (result);
2174*0Sstevel@tonic-gate }
2175