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