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