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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <alloca.h> 29 #include <assert.h> 30 #include <ctype.h> 31 #include <door.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <fnmatch.h> 35 #include <libintl.h> 36 #include <libscf.h> 37 #include <libscf_priv.h> 38 #include <libtecla.h> 39 #include <libuutil.h> 40 #include <limits.h> 41 #include <stdarg.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <wait.h> 45 46 #include <libxml/tree.h> 47 48 #include "svccfg.h" 49 50 /* The colon namespaces in each entity (each followed by a newline). */ 51 #define COLON_NAMESPACES ":properties\n" 52 53 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 54 55 /* These are characters which the lexer requires to be in double-quotes. */ 56 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 57 58 #define HASH_SIZE 16 59 #define HASH_SVC "smf/manifest" 60 #define HASH_PG_TYPE "framework" 61 #define HASH_PG_FLAGS 0 62 #define HASH_PROP "md5sum" 63 64 65 /* 66 * These are the classes of elements which may appear as children of service 67 * or instance elements in XML manifests. 68 */ 69 struct entity_elts { 70 xmlNodePtr create_default_instance; 71 xmlNodePtr single_instance; 72 xmlNodePtr restarter; 73 xmlNodePtr dependencies; 74 xmlNodePtr dependents; 75 xmlNodePtr method_context; 76 xmlNodePtr exec_methods; 77 xmlNodePtr property_groups; 78 xmlNodePtr instances; 79 xmlNodePtr stability; 80 xmlNodePtr template; 81 }; 82 83 /* 84 * Likewise for property_group elements. 85 */ 86 struct pg_elts { 87 xmlNodePtr stability; 88 xmlNodePtr propvals; 89 xmlNodePtr properties; 90 }; 91 92 /* 93 * Likewise for template elements. 94 */ 95 struct template_elts { 96 xmlNodePtr common_name; 97 xmlNodePtr description; 98 xmlNodePtr documentation; 99 }; 100 101 /* 102 * This structure is for snaplevel lists. They are convenient because libscf 103 * only allows traversing snaplevels in one direction. 104 */ 105 struct snaplevel { 106 uu_list_node_t list_node; 107 scf_snaplevel_t *sl; 108 }; 109 110 111 const char * const scf_pg_general = SCF_PG_GENERAL; 112 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 113 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 114 const char * const scf_property_external = "external"; 115 116 const char * const snap_initial = "initial"; 117 const char * const snap_lastimport = "last-import"; 118 const char * const snap_previous = "previous"; 119 const char * const snap_running = "running"; 120 121 122 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 123 124 ssize_t max_scf_fmri_len; 125 ssize_t max_scf_name_len; 126 ssize_t max_scf_pg_type_len; 127 ssize_t max_scf_value_len; 128 static size_t max_scf_len; 129 130 static scf_scope_t *cur_scope; 131 static scf_service_t *cur_svc = NULL; 132 static scf_instance_t *cur_inst = NULL; 133 static scf_snapshot_t *cur_snap = NULL; 134 static scf_snaplevel_t *cur_level = NULL; 135 136 static uu_list_pool_t *snaplevel_pool; 137 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 138 static uu_list_t *cur_levels; 139 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 140 141 static FILE *tempfile = NULL; 142 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 143 144 static const char *emsg_entity_not_selected; 145 static const char *emsg_permission_denied; 146 static const char *emsg_create_xml; 147 static const char *emsg_cant_modify_snapshots; 148 static const char *emsg_read_only; 149 static const char *emsg_deleted; 150 static const char *emsg_invalid_pg_name; 151 static const char *emsg_invalid_prop_name; 152 static const char *emsg_no_such_pg; 153 static const char *emsg_fmri_invalid_pg_name; 154 static const char *emsg_fmri_invalid_pg_name_type; 155 static const char *emsg_pg_added; 156 static const char *emsg_pg_changed; 157 static const char *emsg_pg_deleted; 158 static const char *emsg_pg_mod_perm; 159 static const char *emsg_pg_add_perm; 160 static const char *emsg_pg_del_perm; 161 static const char *emsg_snap_perm; 162 static const char *emsg_dpt_dangling; 163 static const char *emsg_dpt_no_dep; 164 165 static int li_only; 166 static int no_refresh = 0; 167 168 /* import globals, to minimize allocations */ 169 static scf_scope_t *imp_scope = NULL; 170 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 171 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 172 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 173 static scf_snapshot_t *imp_rsnap = NULL; 174 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 175 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 176 static scf_property_t *imp_prop = NULL; 177 static scf_iter_t *imp_iter = NULL; 178 static scf_iter_t *imp_rpg_iter = NULL; 179 static scf_iter_t *imp_up_iter = NULL; 180 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 181 static char *imp_str = NULL; 182 static size_t imp_str_sz; 183 static char *imp_tsname = NULL; 184 static char *imp_fe1 = NULL; /* for fmri_equal() */ 185 static char *imp_fe2 = NULL; 186 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 187 188 /* upgrade_dependents() globals */ 189 static scf_instance_t *ud_inst = NULL; 190 static scf_snaplevel_t *ud_snpl = NULL; 191 static scf_propertygroup_t *ud_pg = NULL; 192 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 193 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 194 static int ud_run_dpts_pg_set = 0; 195 static scf_property_t *ud_prop = NULL; 196 static scf_property_t *ud_dpt_prop = NULL; 197 static scf_value_t *ud_val = NULL; 198 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 199 static scf_transaction_t *ud_tx = NULL; 200 static char *ud_ctarg = NULL; 201 static char *ud_oldtarg = NULL; 202 static char *ud_name = NULL; 203 204 /* export globals */ 205 static scf_instance_t *exp_inst; 206 static scf_propertygroup_t *exp_pg; 207 static scf_property_t *exp_prop; 208 static scf_value_t *exp_val; 209 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 210 static char *exp_str; 211 static size_t exp_str_sz; 212 213 static void scfdie_lineno(int lineno) __NORETURN; 214 215 static char *start_method_names[] = { 216 "start", 217 "inetd_start", 218 NULL 219 }; 220 221 static void 222 safe_printf(const char *fmt, ...) 223 { 224 va_list va; 225 226 va_start(va, fmt); 227 if (vprintf(fmt, va) < 0) 228 uu_die(gettext("Error writing to stdout")); 229 va_end(va); 230 } 231 232 /* 233 * For unexpected libscf errors. 234 */ 235 #ifdef NDEBUG 236 237 static void scfdie(void) __NORETURN; 238 239 static void 240 scfdie(void) 241 { 242 scf_error_t err = scf_error(); 243 244 if (err == SCF_ERROR_CONNECTION_BROKEN) 245 uu_die(gettext("Repository connection broken. Exiting.\n")); 246 247 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 248 scf_strerror(err)); 249 } 250 251 #else 252 253 #define scfdie() scfdie_lineno(__LINE__) 254 255 static void 256 scfdie_lineno(int lineno) 257 { 258 scf_error_t err = scf_error(); 259 260 if (err == SCF_ERROR_CONNECTION_BROKEN) 261 uu_die(gettext("Repository connection broken. Exiting.\n")); 262 263 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 264 ": %s.\n"), lineno, scf_strerror(err)); 265 } 266 267 #endif 268 269 static void 270 scfwarn(void) 271 { 272 warn(gettext("Unexpected libscf error: %s.\n"), 273 scf_strerror(scf_error())); 274 } 275 276 /* 277 * Clear a field of a structure. 278 */ 279 static int 280 clear_int(void *a, void *b) 281 { 282 /* LINTED */ 283 *(int *)((char *)a + (size_t)b) = 0; 284 285 return (UU_WALK_NEXT); 286 } 287 288 static int 289 scferror2errno(scf_error_t err) 290 { 291 switch (err) { 292 case SCF_ERROR_BACKEND_ACCESS: 293 return (EACCES); 294 295 case SCF_ERROR_BACKEND_READONLY: 296 return (EROFS); 297 298 case SCF_ERROR_CONNECTION_BROKEN: 299 return (ECONNABORTED); 300 301 case SCF_ERROR_CONSTRAINT_VIOLATED: 302 case SCF_ERROR_INVALID_ARGUMENT: 303 return (EINVAL); 304 305 case SCF_ERROR_DELETED: 306 return (ECANCELED); 307 308 case SCF_ERROR_EXISTS: 309 return (EEXIST); 310 311 case SCF_ERROR_NO_MEMORY: 312 return (ENOMEM); 313 314 case SCF_ERROR_NO_RESOURCES: 315 return (ENOSPC); 316 317 case SCF_ERROR_NOT_FOUND: 318 return (ENOENT); 319 320 case SCF_ERROR_PERMISSION_DENIED: 321 return (EPERM); 322 323 default: 324 #ifndef NDEBUG 325 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 326 __FILE__, __LINE__, err); 327 #else 328 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 329 #endif 330 abort(); 331 /* NOTREACHED */ 332 } 333 } 334 335 static int 336 entity_get_pg(void *ent, int issvc, const char *name, 337 scf_propertygroup_t *pg) 338 { 339 if (issvc) 340 return (scf_service_get_pg(ent, name, pg)); 341 else 342 return (scf_instance_get_pg(ent, name, pg)); 343 } 344 345 static void 346 entity_destroy(void *ent, int issvc) 347 { 348 if (issvc) 349 scf_service_destroy(ent); 350 else 351 scf_instance_destroy(ent); 352 } 353 354 /* 355 * Find a snaplevel in a snapshot. If get_svc is true, find the service 356 * snaplevel. Otherwise find the instance snaplevel. 357 * 358 * Returns 359 * 0 - success 360 * ECONNABORTED - repository connection broken 361 * ECANCELED - instance containing snap was deleted 362 * ENOENT - snap has no snaplevels 363 * - requested snaplevel not found 364 */ 365 static int 366 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 367 { 368 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 369 switch (scf_error()) { 370 case SCF_ERROR_CONNECTION_BROKEN: 371 case SCF_ERROR_DELETED: 372 case SCF_ERROR_NOT_FOUND: 373 return (scferror2errno(scf_error())); 374 375 case SCF_ERROR_HANDLE_MISMATCH: 376 case SCF_ERROR_NOT_BOUND: 377 case SCF_ERROR_NOT_SET: 378 default: 379 bad_error("scf_snapshot_get_base_snaplevel", 380 scf_error()); 381 } 382 } 383 384 for (;;) { 385 ssize_t ssz; 386 387 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 388 if (ssz >= 0) { 389 if (!get_svc) 390 return (0); 391 } else { 392 switch (scf_error()) { 393 case SCF_ERROR_CONSTRAINT_VIOLATED: 394 if (get_svc) 395 return (0); 396 break; 397 398 case SCF_ERROR_DELETED: 399 case SCF_ERROR_CONNECTION_BROKEN: 400 return (scferror2errno(scf_error())); 401 402 case SCF_ERROR_NOT_SET: 403 case SCF_ERROR_NOT_BOUND: 404 default: 405 bad_error("scf_snaplevel_get_instance_name", 406 scf_error()); 407 } 408 } 409 410 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 411 switch (scf_error()) { 412 case SCF_ERROR_NOT_FOUND: 413 case SCF_ERROR_CONNECTION_BROKEN: 414 case SCF_ERROR_DELETED: 415 return (scferror2errno(scf_error())); 416 417 case SCF_ERROR_HANDLE_MISMATCH: 418 case SCF_ERROR_NOT_BOUND: 419 case SCF_ERROR_NOT_SET: 420 case SCF_ERROR_INVALID_ARGUMENT: 421 default: 422 bad_error("scf_snaplevel_get_next_snaplevel", 423 scf_error()); 424 } 425 } 426 } 427 } 428 429 /* 430 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 431 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 432 * the property group named name in it. If it doesn't have a running 433 * snapshot, set pg to the instance's current property group named name. 434 * 435 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 436 * its instances. If one has a running snapshot with a service snaplevel, set 437 * pg to the property group named name in it. If no such snaplevel could be 438 * found, set pg to the service's current property group named name. 439 * 440 * iter, inst, snap, and snpl are required scratch objects. 441 * 442 * Returns 443 * 0 - success 444 * ECONNABORTED - repository connection broken 445 * ECANCELED - ent was deleted 446 * ENOENT - no such property group 447 * EINVAL - name is an invalid property group name 448 * EBADF - found running snapshot is missing a snaplevel 449 */ 450 static int 451 entity_get_running_pg(void *ent, int issvc, const char *name, 452 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 453 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 454 { 455 int r; 456 457 if (issvc) { 458 /* Search for an instance with a running snapshot. */ 459 if (scf_iter_service_instances(iter, ent) != 0) { 460 switch (scf_error()) { 461 case SCF_ERROR_DELETED: 462 case SCF_ERROR_CONNECTION_BROKEN: 463 return (scferror2errno(scf_error())); 464 465 case SCF_ERROR_NOT_SET: 466 case SCF_ERROR_NOT_BOUND: 467 case SCF_ERROR_HANDLE_MISMATCH: 468 default: 469 bad_error("scf_iter_service_instances", 470 scf_error()); 471 } 472 } 473 474 for (;;) { 475 r = scf_iter_next_instance(iter, inst); 476 if (r == 0) { 477 if (scf_service_get_pg(ent, name, pg) == 0) 478 return (0); 479 480 switch (scf_error()) { 481 case SCF_ERROR_DELETED: 482 case SCF_ERROR_NOT_FOUND: 483 case SCF_ERROR_INVALID_ARGUMENT: 484 case SCF_ERROR_CONNECTION_BROKEN: 485 return (scferror2errno(scf_error())); 486 487 case SCF_ERROR_NOT_BOUND: 488 case SCF_ERROR_HANDLE_MISMATCH: 489 case SCF_ERROR_NOT_SET: 490 default: 491 bad_error("scf_service_get_pg", 492 scf_error()); 493 } 494 } 495 if (r != 1) { 496 switch (scf_error()) { 497 case SCF_ERROR_DELETED: 498 case SCF_ERROR_CONNECTION_BROKEN: 499 return (scferror2errno(scf_error())); 500 501 case SCF_ERROR_INVALID_ARGUMENT: 502 case SCF_ERROR_NOT_SET: 503 case SCF_ERROR_NOT_BOUND: 504 case SCF_ERROR_HANDLE_MISMATCH: 505 default: 506 bad_error("scf_iter_next_instance", 507 scf_error()); 508 } 509 } 510 511 if (scf_instance_get_snapshot(inst, snap_running, 512 snap) == 0) 513 break; 514 515 switch (scf_error()) { 516 case SCF_ERROR_NOT_FOUND: 517 case SCF_ERROR_DELETED: 518 continue; 519 520 case SCF_ERROR_CONNECTION_BROKEN: 521 return (ECONNABORTED); 522 523 case SCF_ERROR_HANDLE_MISMATCH: 524 case SCF_ERROR_INVALID_ARGUMENT: 525 case SCF_ERROR_NOT_SET: 526 case SCF_ERROR_NOT_BOUND: 527 default: 528 bad_error("scf_instance_get_snapshot", 529 scf_error()); 530 } 531 } 532 } else { 533 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 534 switch (scf_error()) { 535 case SCF_ERROR_NOT_FOUND: 536 break; 537 538 case SCF_ERROR_DELETED: 539 case SCF_ERROR_CONNECTION_BROKEN: 540 return (scferror2errno(scf_error())); 541 542 case SCF_ERROR_NOT_BOUND: 543 case SCF_ERROR_HANDLE_MISMATCH: 544 case SCF_ERROR_INVALID_ARGUMENT: 545 case SCF_ERROR_NOT_SET: 546 default: 547 bad_error("scf_instance_get_snapshot", 548 scf_error()); 549 } 550 551 if (scf_instance_get_pg(ent, name, pg) == 0) 552 return (0); 553 554 switch (scf_error()) { 555 case SCF_ERROR_DELETED: 556 case SCF_ERROR_NOT_FOUND: 557 case SCF_ERROR_INVALID_ARGUMENT: 558 case SCF_ERROR_CONNECTION_BROKEN: 559 return (scferror2errno(scf_error())); 560 561 case SCF_ERROR_NOT_BOUND: 562 case SCF_ERROR_HANDLE_MISMATCH: 563 case SCF_ERROR_NOT_SET: 564 default: 565 bad_error("scf_instance_get_pg", scf_error()); 566 } 567 } 568 } 569 570 r = get_snaplevel(snap, issvc, snpl); 571 switch (r) { 572 case 0: 573 break; 574 575 case ECONNABORTED: 576 case ECANCELED: 577 return (r); 578 579 case ENOENT: 580 return (EBADF); 581 582 default: 583 bad_error("get_snaplevel", r); 584 } 585 586 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 587 return (0); 588 589 switch (scf_error()) { 590 case SCF_ERROR_DELETED: 591 case SCF_ERROR_INVALID_ARGUMENT: 592 case SCF_ERROR_CONNECTION_BROKEN: 593 case SCF_ERROR_NOT_FOUND: 594 return (scferror2errno(scf_error())); 595 596 case SCF_ERROR_NOT_BOUND: 597 case SCF_ERROR_HANDLE_MISMATCH: 598 case SCF_ERROR_NOT_SET: 599 default: 600 bad_error("scf_snaplevel_get_pg", scf_error()); 601 /* NOTREACHED */ 602 } 603 } 604 605 606 /* 607 * To be registered with atexit(). 608 */ 609 static void 610 remove_tempfile(void) 611 { 612 int ret; 613 614 if (tempfile != NULL) { 615 if (fclose(tempfile) == EOF) 616 warn(gettext("Could not close temporary file")); 617 tempfile = NULL; 618 } 619 620 if (tempfilename[0] != '\0') { 621 do 622 ret = remove(tempfilename); 623 while (ret == -1 && errno == EINTR); 624 if (ret == -1) 625 warn(gettext("Could not remove temporary file")); 626 tempfilename[0] = '\0'; 627 } 628 } 629 630 /* 631 * Launch private svc.configd(1M) for manipulating alternate repositories. 632 */ 633 static void 634 start_private_repository(engine_state_t *est) 635 { 636 int fd, stat; 637 struct door_info info; 638 pid_t pid; 639 640 /* 641 * 1. Create a temporary file for the door. 642 */ 643 if (est->sc_repo_doorname != NULL) 644 free((void *)est->sc_repo_doorname); 645 646 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 647 if (est->sc_repo_doorname == NULL) 648 uu_die(gettext("Could not acquire temporary filename")); 649 650 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 651 if (fd < 0) 652 uu_die(gettext("Could not create temporary file for " 653 "repository server")); 654 655 (void) close(fd); 656 657 /* 658 * 2. Launch a configd with that door, using the specified 659 * repository. 660 */ 661 if ((est->sc_repo_pid = fork()) == 0) { 662 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 663 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 664 NULL); 665 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 666 } else if (est->sc_repo_pid == -1) 667 uu_die(gettext("Attempt to fork failed")); 668 669 do 670 pid = waitpid(est->sc_repo_pid, &stat, 0); 671 while (pid == -1 && errno == EINTR); 672 673 if (pid == -1) 674 uu_die(gettext("Could not waitpid() for repository server")); 675 676 if (!WIFEXITED(stat)) { 677 uu_die(gettext("Repository server failed (status %d).\n"), 678 stat); 679 } else if (WEXITSTATUS(stat) != 0) { 680 uu_die(gettext("Repository server failed (exit %d).\n"), 681 WEXITSTATUS(stat)); 682 } 683 684 /* 685 * See if it was successful by checking if the door is a door. 686 */ 687 688 fd = open(est->sc_repo_doorname, O_RDWR); 689 if (fd < 0) 690 uu_die(gettext("Could not open door \"%s\""), 691 est->sc_repo_doorname); 692 693 if (door_info(fd, &info) < 0) 694 uu_die(gettext("Unexpected door_info() error")); 695 696 if (close(fd) == -1) 697 warn(gettext("Could not close repository door"), 698 strerror(errno)); 699 700 est->sc_repo_pid = info.di_target; 701 } 702 703 void 704 lscf_cleanup(void) 705 { 706 /* 707 * In the case where we've launched a private svc.configd(1M) 708 * instance, we must terminate our child and remove the temporary 709 * rendezvous point. 710 */ 711 if (est->sc_repo_pid > 0) { 712 (void) kill(est->sc_repo_pid, SIGTERM); 713 (void) waitpid(est->sc_repo_pid, NULL, 0); 714 (void) unlink(est->sc_repo_doorname); 715 716 est->sc_repo_pid = 0; 717 } 718 } 719 720 void 721 unselect_cursnap(void) 722 { 723 void *cookie; 724 725 cur_level = NULL; 726 727 cookie = NULL; 728 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 729 scf_snaplevel_destroy(cur_elt->sl); 730 free(cur_elt); 731 } 732 733 scf_snapshot_destroy(cur_snap); 734 cur_snap = NULL; 735 } 736 737 void 738 lscf_prep_hndl(void) 739 { 740 if (g_hndl != NULL) 741 return; 742 743 g_hndl = scf_handle_create(SCF_VERSION); 744 if (g_hndl == NULL) 745 scfdie(); 746 747 if (est->sc_repo_filename != NULL) 748 start_private_repository(est); 749 750 if (est->sc_repo_doorname != NULL) { 751 scf_value_t *repo_value; 752 int ret; 753 754 repo_value = scf_value_create(g_hndl); 755 if (repo_value == NULL) 756 scfdie(); 757 758 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 759 assert(ret == SCF_SUCCESS); 760 761 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 762 SCF_SUCCESS) 763 scfdie(); 764 765 scf_value_destroy(repo_value); 766 } 767 768 if (scf_handle_bind(g_hndl) != 0) 769 uu_die(gettext("Could not connect to repository server: %s.\n"), 770 scf_strerror(scf_error())); 771 772 cur_scope = scf_scope_create(g_hndl); 773 if (cur_scope == NULL) 774 scfdie(); 775 776 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 777 scfdie(); 778 } 779 780 static void 781 repository_teardown(void) 782 { 783 if (g_hndl != NULL) { 784 if (cur_snap != NULL) 785 unselect_cursnap(); 786 scf_instance_destroy(cur_inst); 787 scf_service_destroy(cur_svc); 788 scf_scope_destroy(cur_scope); 789 scf_handle_destroy(g_hndl); 790 g_hndl = NULL; 791 792 lscf_cleanup(); 793 } 794 } 795 796 void 797 lscf_set_repository(const char *repfile) 798 { 799 repository_teardown(); 800 801 if (est->sc_repo_filename != NULL) 802 free((void *)est->sc_repo_filename); 803 804 est->sc_repo_filename = safe_strdup(repfile); 805 806 lscf_prep_hndl(); 807 } 808 809 void 810 lscf_init() 811 { 812 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 813 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 814 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 815 0 || 816 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 817 scfdie(); 818 819 max_scf_len = max_scf_fmri_len; 820 if (max_scf_name_len > max_scf_len) 821 max_scf_len = max_scf_name_len; 822 if (max_scf_pg_type_len > max_scf_len) 823 max_scf_len = max_scf_pg_type_len; 824 if (max_scf_value_len > max_scf_len) 825 max_scf_len = max_scf_value_len; 826 827 if (atexit(remove_tempfile) != 0) 828 uu_die(gettext("Could not register atexit() function")); 829 830 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 831 emsg_permission_denied = gettext("Permission denied.\n"); 832 emsg_create_xml = gettext("Could not create XML node.\n"); 833 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 834 emsg_read_only = gettext("Backend read-only.\n"); 835 emsg_deleted = gettext("Current selection has been deleted.\n"); 836 emsg_invalid_pg_name = 837 gettext("Invalid property group name \"%s\".\n"); 838 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 839 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 840 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 841 "with invalid name \"%s\".\n"); 842 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 843 "group with invalid name \"%s\" or type \"%s\".\n"); 844 emsg_pg_added = gettext("%s changed unexpectedly " 845 "(property group \"%s\" added).\n"); 846 emsg_pg_changed = gettext("%s changed unexpectedly " 847 "(property group \"%s\" changed).\n"); 848 emsg_pg_deleted = gettext("%s changed unexpectedly " 849 "(property group \"%s\" or an ancestor was deleted).\n"); 850 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 851 "in %s (permission denied).\n"); 852 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 853 "in %s (permission denied).\n"); 854 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 855 "in %s (permission denied).\n"); 856 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 857 "(permission denied).\n"); 858 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 859 "new dependent \"%s\" because it already exists). Warning: The " 860 "current dependent's target (%s) does not exist.\n"); 861 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 862 "dependent \"%s\" because it already exists). Warning: The " 863 "current dependent's target (%s) does not have a dependency named " 864 "\"%s\" as expected.\n"); 865 866 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 867 offsetof(string_list_t, node), NULL, 0); 868 snaplevel_pool = uu_list_pool_create("snaplevels", 869 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 870 NULL, 0); 871 } 872 873 874 static const char * 875 prop_to_typestr(const scf_property_t *prop) 876 { 877 scf_type_t ty; 878 879 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 880 scfdie(); 881 882 return (scf_type_to_string(ty)); 883 } 884 885 static scf_type_t 886 string_to_type(const char *type) 887 { 888 size_t len = strlen(type); 889 char *buf; 890 891 if (len == 0 || type[len - 1] != ':') 892 return (SCF_TYPE_INVALID); 893 894 buf = (char *)alloca(len + 1); 895 (void) strlcpy(buf, type, len + 1); 896 buf[len - 1] = 0; 897 898 return (scf_string_to_type(buf)); 899 } 900 901 static scf_value_t * 902 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 903 { 904 scf_value_t *v; 905 char *dup, *nstr; 906 size_t len; 907 908 v = scf_value_create(g_hndl); 909 if (v == NULL) 910 scfdie(); 911 912 len = strlen(str); 913 if (require_quotes && 914 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 915 semerr(gettext("Multiple string values or string values " 916 "with spaces must be quoted with '\"'.\n")); 917 scf_value_destroy(v); 918 return (NULL); 919 } 920 921 nstr = dup = safe_strdup(str); 922 if (dup[0] == '\"') { 923 /* 924 * Strip out the first and the last quote. 925 */ 926 dup[len - 1] = '\0'; 927 nstr = dup + 1; 928 } 929 930 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 931 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 932 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 933 scf_type_to_string(ty), nstr); 934 scf_value_destroy(v); 935 v = NULL; 936 } 937 free(dup); 938 return (v); 939 } 940 941 /* 942 * Print str to strm, quoting double-quotes and backslashes with backslashes. 943 * Optionally append a comment prefix ('#') to newlines ('\n'). 944 */ 945 static int 946 quote_and_print(const char *str, FILE *strm, int commentnl) 947 { 948 const char *cp; 949 950 for (cp = str; *cp != '\0'; ++cp) { 951 if (*cp == '"' || *cp == '\\') 952 (void) putc('\\', strm); 953 954 (void) putc(*cp, strm); 955 956 if (commentnl && *cp == '\n') { 957 (void) putc('#', strm); 958 } 959 } 960 961 return (ferror(strm)); 962 } 963 964 /* 965 * These wrappers around lowlevel functions provide consistent error checking 966 * and warnings. 967 */ 968 static int 969 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 970 { 971 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 972 return (0); 973 974 if (scf_error() != SCF_ERROR_NOT_FOUND) 975 scfdie(); 976 977 if (g_verbose) { 978 ssize_t len; 979 char *fmri; 980 981 len = scf_pg_to_fmri(pg, NULL, 0); 982 if (len < 0) 983 scfdie(); 984 985 fmri = safe_malloc(len + 1); 986 987 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 988 scfdie(); 989 990 warn(gettext("Expected property %s of property group %s is " 991 "missing.\n"), propname, fmri); 992 993 free(fmri); 994 } 995 996 return (-1); 997 } 998 999 static int 1000 prop_check_type(scf_property_t *prop, scf_type_t ty) 1001 { 1002 scf_type_t pty; 1003 1004 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1005 scfdie(); 1006 1007 if (ty == pty) 1008 return (0); 1009 1010 if (g_verbose) { 1011 ssize_t len; 1012 char *fmri; 1013 const char *tystr; 1014 1015 len = scf_property_to_fmri(prop, NULL, 0); 1016 if (len < 0) 1017 scfdie(); 1018 1019 fmri = safe_malloc(len + 1); 1020 1021 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1022 scfdie(); 1023 1024 tystr = scf_type_to_string(ty); 1025 if (tystr == NULL) 1026 tystr = "?"; 1027 1028 warn(gettext("Property %s is not of expected type %s.\n"), 1029 fmri, tystr); 1030 1031 free(fmri); 1032 } 1033 1034 return (-1); 1035 } 1036 1037 static int 1038 prop_get_val(scf_property_t *prop, scf_value_t *val) 1039 { 1040 scf_error_t err; 1041 1042 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1043 return (0); 1044 1045 err = scf_error(); 1046 1047 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_CONSTRAINT_VIOLATED) 1048 scfdie(); 1049 1050 if (g_verbose) { 1051 ssize_t len; 1052 char *fmri, *emsg; 1053 1054 len = scf_property_to_fmri(prop, NULL, 0); 1055 if (len < 0) 1056 scfdie(); 1057 1058 fmri = safe_malloc(len + 1); 1059 1060 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1061 scfdie(); 1062 1063 if (err == SCF_ERROR_NOT_FOUND) 1064 emsg = gettext("Property %s has no values; expected " 1065 "one.\n"); 1066 else 1067 emsg = gettext("Property %s has multiple values; " 1068 "expected one.\n"); 1069 1070 warn(emsg, fmri); 1071 1072 free(fmri); 1073 } 1074 1075 return (-1); 1076 } 1077 1078 1079 static boolean_t 1080 snaplevel_is_instance(const scf_snaplevel_t *level) 1081 { 1082 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1083 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1084 scfdie(); 1085 return (0); 1086 } else { 1087 return (1); 1088 } 1089 } 1090 1091 /* 1092 * Decode FMRI into a service or instance, and put the result in *ep. If 1093 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1094 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1095 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1096 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1097 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1098 * whether *ep is a service. 1099 */ 1100 static scf_error_t 1101 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1102 { 1103 char *fmri_copy; 1104 const char *sstr, *istr, *pgstr; 1105 scf_service_t *svc; 1106 scf_instance_t *inst; 1107 1108 fmri_copy = strdup(fmri); 1109 if (fmri_copy == NULL) 1110 return (SCF_ERROR_NO_MEMORY); 1111 1112 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1113 SCF_SUCCESS) { 1114 free(fmri_copy); 1115 return (SCF_ERROR_INVALID_ARGUMENT); 1116 } 1117 1118 free(fmri_copy); 1119 1120 if (sstr == NULL || pgstr != NULL) 1121 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1122 1123 if (istr == NULL) { 1124 svc = scf_service_create(h); 1125 if (svc == NULL) 1126 return (SCF_ERROR_NO_MEMORY); 1127 1128 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1129 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1130 if (scf_error() != SCF_ERROR_NOT_FOUND) 1131 scfdie(); 1132 1133 return (SCF_ERROR_NOT_FOUND); 1134 } 1135 1136 *ep = svc; 1137 *isservice = 1; 1138 } else { 1139 inst = scf_instance_create(h); 1140 if (inst == NULL) 1141 return (SCF_ERROR_NO_MEMORY); 1142 1143 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1144 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1145 if (scf_error() != SCF_ERROR_NOT_FOUND) 1146 scfdie(); 1147 1148 return (SCF_ERROR_NOT_FOUND); 1149 } 1150 1151 *ep = inst; 1152 *isservice = 0; 1153 } 1154 1155 return (SCF_ERROR_NONE); 1156 } 1157 1158 /* 1159 * Create the entity named by fmri. Place a pointer to its libscf handle in 1160 * *ep, and set or clear *isservicep if it is a service or an instance. 1161 * Returns 1162 * SCF_ERROR_NONE - success 1163 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1164 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1165 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1166 * SCF_ERROR_NOT_FOUND - no such scope 1167 * SCF_ERROR_PERMISSION_DENIED 1168 * SCF_ERROR_BACKEND_READONLY 1169 * SCF_ERROR_BACKEND_ACCESS 1170 */ 1171 static scf_error_t 1172 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1173 { 1174 char *fmri_copy; 1175 const char *scstr, *sstr, *istr, *pgstr; 1176 scf_scope_t *scope = NULL; 1177 scf_service_t *svc = NULL; 1178 scf_instance_t *inst = NULL; 1179 scf_error_t scfe; 1180 1181 fmri_copy = safe_strdup(fmri); 1182 1183 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1184 0) { 1185 free(fmri_copy); 1186 return (SCF_ERROR_INVALID_ARGUMENT); 1187 } 1188 1189 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1190 free(fmri_copy); 1191 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1192 } 1193 1194 *ep = NULL; 1195 1196 if ((scope = scf_scope_create(h)) == NULL || 1197 (svc = scf_service_create(h)) == NULL || 1198 (inst = scf_instance_create(h)) == NULL) { 1199 scfe = SCF_ERROR_NO_MEMORY; 1200 goto out; 1201 } 1202 1203 get_scope: 1204 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1205 switch (scf_error()) { 1206 case SCF_ERROR_CONNECTION_BROKEN: 1207 scfdie(); 1208 /* NOTREACHED */ 1209 1210 case SCF_ERROR_NOT_FOUND: 1211 scfe = SCF_ERROR_NOT_FOUND; 1212 goto out; 1213 1214 case SCF_ERROR_HANDLE_MISMATCH: 1215 case SCF_ERROR_NOT_BOUND: 1216 case SCF_ERROR_INVALID_ARGUMENT: 1217 default: 1218 bad_error("scf_handle_get_scope", scf_error()); 1219 } 1220 } 1221 1222 get_svc: 1223 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1224 switch (scf_error()) { 1225 case SCF_ERROR_CONNECTION_BROKEN: 1226 scfdie(); 1227 /* NOTREACHED */ 1228 1229 case SCF_ERROR_DELETED: 1230 goto get_scope; 1231 1232 case SCF_ERROR_NOT_FOUND: 1233 break; 1234 1235 case SCF_ERROR_HANDLE_MISMATCH: 1236 case SCF_ERROR_INVALID_ARGUMENT: 1237 case SCF_ERROR_NOT_BOUND: 1238 case SCF_ERROR_NOT_SET: 1239 default: 1240 bad_error("scf_scope_get_service", scf_error()); 1241 } 1242 1243 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1244 switch (scf_error()) { 1245 case SCF_ERROR_CONNECTION_BROKEN: 1246 scfdie(); 1247 /* NOTREACHED */ 1248 1249 case SCF_ERROR_DELETED: 1250 goto get_scope; 1251 1252 case SCF_ERROR_PERMISSION_DENIED: 1253 case SCF_ERROR_BACKEND_READONLY: 1254 case SCF_ERROR_BACKEND_ACCESS: 1255 scfe = scf_error(); 1256 goto out; 1257 1258 case SCF_ERROR_HANDLE_MISMATCH: 1259 case SCF_ERROR_INVALID_ARGUMENT: 1260 case SCF_ERROR_NOT_BOUND: 1261 case SCF_ERROR_NOT_SET: 1262 default: 1263 bad_error("scf_scope_get_service", scf_error()); 1264 } 1265 } 1266 } 1267 1268 if (istr == NULL) { 1269 scfe = SCF_ERROR_NONE; 1270 *ep = svc; 1271 *isservicep = 1; 1272 goto out; 1273 } 1274 1275 get_inst: 1276 if (scf_service_get_instance(svc, istr, inst) != 0) { 1277 switch (scf_error()) { 1278 case SCF_ERROR_CONNECTION_BROKEN: 1279 scfdie(); 1280 /* NOTREACHED */ 1281 1282 case SCF_ERROR_DELETED: 1283 goto get_svc; 1284 1285 case SCF_ERROR_NOT_FOUND: 1286 break; 1287 1288 case SCF_ERROR_HANDLE_MISMATCH: 1289 case SCF_ERROR_INVALID_ARGUMENT: 1290 case SCF_ERROR_NOT_BOUND: 1291 case SCF_ERROR_NOT_SET: 1292 default: 1293 bad_error("scf_service_get_instance", scf_error()); 1294 } 1295 1296 if (scf_service_add_instance(svc, istr, inst) != 0) { 1297 switch (scf_error()) { 1298 case SCF_ERROR_CONNECTION_BROKEN: 1299 scfdie(); 1300 /* NOTREACHED */ 1301 1302 case SCF_ERROR_DELETED: 1303 goto get_svc; 1304 1305 case SCF_ERROR_PERMISSION_DENIED: 1306 case SCF_ERROR_BACKEND_READONLY: 1307 case SCF_ERROR_BACKEND_ACCESS: 1308 scfe = scf_error(); 1309 goto out; 1310 1311 case SCF_ERROR_HANDLE_MISMATCH: 1312 case SCF_ERROR_INVALID_ARGUMENT: 1313 case SCF_ERROR_NOT_BOUND: 1314 case SCF_ERROR_NOT_SET: 1315 default: 1316 bad_error("scf_service_add_instance", 1317 scf_error()); 1318 } 1319 } 1320 } 1321 1322 scfe = SCF_ERROR_NONE; 1323 *ep = inst; 1324 *isservicep = 0; 1325 1326 out: 1327 if (*ep != inst) 1328 scf_instance_destroy(inst); 1329 if (*ep != svc) 1330 scf_service_destroy(svc); 1331 scf_scope_destroy(scope); 1332 free(fmri_copy); 1333 return (scfe); 1334 } 1335 1336 /* 1337 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1338 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1339 * instances. fmri is used for messages. inst, iter, and name_buf are used 1340 * for scratch space. Returns 1341 * 0 - success 1342 * ECONNABORTED - repository connection broken 1343 * ECANCELED - entity was deleted 1344 * EACCES - backend denied access 1345 * EPERM - permission denied 1346 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1347 */ 1348 static int 1349 refresh_entity(int isservice, void *entity, const char *fmri, 1350 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1351 { 1352 scf_error_t scfe; 1353 int r; 1354 1355 if (!isservice) { 1356 if (_smf_refresh_instance_i(entity) == 0) { 1357 if (g_verbose) 1358 warn(gettext("Refreshed %s.\n"), fmri); 1359 return (0); 1360 } 1361 1362 switch (scf_error()) { 1363 case SCF_ERROR_BACKEND_ACCESS: 1364 return (EACCES); 1365 1366 case SCF_ERROR_PERMISSION_DENIED: 1367 return (EPERM); 1368 1369 default: 1370 return (-1); 1371 } 1372 } 1373 1374 if (scf_iter_service_instances(iter, entity) != 0) { 1375 switch (scf_error()) { 1376 case SCF_ERROR_CONNECTION_BROKEN: 1377 return (ECONNABORTED); 1378 1379 case SCF_ERROR_DELETED: 1380 return (ECANCELED); 1381 1382 case SCF_ERROR_HANDLE_MISMATCH: 1383 case SCF_ERROR_NOT_BOUND: 1384 case SCF_ERROR_NOT_SET: 1385 default: 1386 bad_error("scf_iter_service_instances", scf_error()); 1387 } 1388 } 1389 1390 for (;;) { 1391 r = scf_iter_next_instance(iter, inst); 1392 if (r == 0) 1393 break; 1394 if (r != 1) { 1395 switch (scf_error()) { 1396 case SCF_ERROR_CONNECTION_BROKEN: 1397 return (ECONNABORTED); 1398 1399 case SCF_ERROR_DELETED: 1400 return (ECANCELED); 1401 1402 case SCF_ERROR_HANDLE_MISMATCH: 1403 case SCF_ERROR_NOT_BOUND: 1404 case SCF_ERROR_NOT_SET: 1405 case SCF_ERROR_INVALID_ARGUMENT: 1406 default: 1407 bad_error("scf_iter_next_instance", 1408 scf_error()); 1409 } 1410 } 1411 1412 if (_smf_refresh_instance_i(inst) == 0) { 1413 if (g_verbose) { 1414 if (scf_instance_get_name(inst, name_buf, 1415 max_scf_name_len + 1) < 0) 1416 (void) strcpy(name_buf, "?"); 1417 1418 warn(gettext("Refreshed %s:%s.\n"), 1419 fmri, name_buf); 1420 } 1421 } else { 1422 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1423 g_verbose) { 1424 scfe = scf_error(); 1425 1426 if (scf_instance_to_fmri(inst, name_buf, 1427 max_scf_name_len + 1) < 0) 1428 (void) strcpy(name_buf, "?"); 1429 1430 warn(gettext( 1431 "Refresh of %s:%s failed: %s.\n"), fmri, 1432 name_buf, scf_strerror(scfe)); 1433 } 1434 } 1435 } 1436 1437 return (0); 1438 } 1439 1440 static int 1441 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1442 { 1443 cbp->sc_err = scferror2errno(err); 1444 return (UU_WALK_ERROR); 1445 } 1446 1447 static int 1448 stash_scferror(scf_callback_t *cbp) 1449 { 1450 return (stash_scferror_err(cbp, scf_error())); 1451 } 1452 1453 1454 /* 1455 * Import. These functions import a bundle into the repository. 1456 */ 1457 1458 /* 1459 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 1460 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 1461 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 1462 * lcbdata->sc_err to 1463 * ENOMEM - out of memory 1464 * ECONNABORTED - repository connection broken 1465 * ECANCELED - sc_trans's property group was deleted 1466 * EINVAL - p's name is invalid (error printed) 1467 * - p has an invalid value (error printed) 1468 */ 1469 static int 1470 lscf_property_import(void *v, void *pvt) 1471 { 1472 property_t *p = v; 1473 scf_callback_t *lcbdata = pvt; 1474 value_t *vp; 1475 scf_transaction_t *trans = lcbdata->sc_trans; 1476 scf_transaction_entry_t *entr; 1477 scf_value_t *val; 1478 scf_type_t tp; 1479 1480 if (lcbdata->sc_flags & SCI_NOENABLED && 1481 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) 1482 return (UU_WALK_NEXT); 1483 1484 entr = scf_entry_create(lcbdata->sc_handle); 1485 if (entr == NULL) { 1486 switch (scf_error()) { 1487 case SCF_ERROR_NO_MEMORY: 1488 return (stash_scferror(lcbdata)); 1489 1490 case SCF_ERROR_INVALID_ARGUMENT: 1491 default: 1492 bad_error("scf_entry_create", scf_error()); 1493 } 1494 } 1495 1496 tp = p->sc_value_type; 1497 1498 if (scf_transaction_property_new(trans, entr, 1499 p->sc_property_name, tp) != 0) { 1500 switch (scf_error()) { 1501 case SCF_ERROR_INVALID_ARGUMENT: 1502 semerr(emsg_invalid_prop_name, p->sc_property_name); 1503 scf_entry_destroy(entr); 1504 return (stash_scferror(lcbdata)); 1505 1506 case SCF_ERROR_EXISTS: 1507 break; 1508 1509 case SCF_ERROR_DELETED: 1510 case SCF_ERROR_CONNECTION_BROKEN: 1511 scf_entry_destroy(entr); 1512 return (stash_scferror(lcbdata)); 1513 1514 case SCF_ERROR_NOT_BOUND: 1515 case SCF_ERROR_HANDLE_MISMATCH: 1516 case SCF_ERROR_NOT_SET: 1517 default: 1518 bad_error("scf_transaction_property_new", scf_error()); 1519 } 1520 1521 if (scf_transaction_property_change_type(trans, entr, 1522 p->sc_property_name, tp) != 0) { 1523 switch (scf_error()) { 1524 case SCF_ERROR_DELETED: 1525 case SCF_ERROR_CONNECTION_BROKEN: 1526 scf_entry_destroy(entr); 1527 return (stash_scferror(lcbdata)); 1528 1529 case SCF_ERROR_INVALID_ARGUMENT: 1530 semerr(emsg_invalid_prop_name, 1531 p->sc_property_name); 1532 scf_entry_destroy(entr); 1533 return (stash_scferror(lcbdata)); 1534 1535 case SCF_ERROR_NOT_FOUND: 1536 case SCF_ERROR_NOT_SET: 1537 case SCF_ERROR_HANDLE_MISMATCH: 1538 case SCF_ERROR_NOT_BOUND: 1539 default: 1540 bad_error( 1541 "scf_transaction_property_change_type", 1542 scf_error()); 1543 } 1544 } 1545 } 1546 1547 for (vp = uu_list_first(p->sc_property_values); 1548 vp != NULL; 1549 vp = uu_list_next(p->sc_property_values, vp)) { 1550 val = scf_value_create(g_hndl); 1551 if (val == NULL) { 1552 switch (scf_error()) { 1553 case SCF_ERROR_NO_MEMORY: 1554 return (stash_scferror(lcbdata)); 1555 1556 case SCF_ERROR_INVALID_ARGUMENT: 1557 default: 1558 bad_error("scf_value_create", scf_error()); 1559 } 1560 } 1561 1562 switch (tp) { 1563 case SCF_TYPE_BOOLEAN: 1564 scf_value_set_boolean(val, vp->sc_u.sc_count); 1565 break; 1566 case SCF_TYPE_COUNT: 1567 scf_value_set_count(val, vp->sc_u.sc_count); 1568 break; 1569 case SCF_TYPE_INTEGER: 1570 scf_value_set_integer(val, vp->sc_u.sc_integer); 1571 break; 1572 default: 1573 assert(vp->sc_u.sc_string != NULL); 1574 if (scf_value_set_from_string(val, tp, 1575 vp->sc_u.sc_string) != 0) { 1576 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 1577 bad_error("scf_value_set_from_string", 1578 scf_error()); 1579 1580 warn(gettext("Value \"%s\" is not a valid " 1581 "%s.\n"), vp->sc_u.sc_string, 1582 scf_type_to_string(tp)); 1583 scf_value_destroy(val); 1584 return (stash_scferror(lcbdata)); 1585 } 1586 break; 1587 } 1588 1589 if (scf_entry_add_value(entr, val) != 0) 1590 bad_error("scf_entry_add_value", scf_error()); 1591 } 1592 1593 return (UU_WALK_NEXT); 1594 } 1595 1596 /* 1597 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 1598 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 1599 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 1600 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 1601 * lcbdata->sc_err to 1602 * ECONNABORTED - repository connection broken 1603 * ENOMEM - out of memory 1604 * ENOSPC - svc.configd is out of resources 1605 * ECANCELED - sc_parent was deleted 1606 * EPERM - could not create property group (permission denied) (error printed) 1607 * - could not modify property group (permission denied) (error printed) 1608 * - could not delete property group (permission denied) (error printed) 1609 * EROFS - could not create property group (repository is read-only) 1610 * - could not delete property group (repository is read-only) 1611 * EACCES - could not create property group (backend access denied) 1612 * - could not delete property group (backend access denied) 1613 * EEXIST - could not create property group (already exists) 1614 * EINVAL - invalid property group name (error printed) 1615 * - invalid property name (error printed) 1616 * - invalid value (error printed) 1617 * EBUSY - new property group deleted (error printed) 1618 * - new property group changed (error printed) 1619 * - property group added (error printed) 1620 * - property group deleted (error printed) 1621 */ 1622 static int 1623 entity_pgroup_import(void *v, void *pvt) 1624 { 1625 pgroup_t *p = v; 1626 scf_callback_t cbdata; 1627 scf_callback_t *lcbdata = pvt; 1628 void *ent = lcbdata->sc_parent; 1629 int issvc = lcbdata->sc_service; 1630 int r; 1631 1632 const char * const pg_changed = gettext("%s changed unexpectedly " 1633 "(new property group \"%s\" changed).\n"); 1634 1635 /* Never import deleted property groups. */ 1636 if (p->sc_pgroup_delete) 1637 return (UU_WALK_NEXT); 1638 1639 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 1640 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 1641 lcbdata->sc_general = p; 1642 return (UU_WALK_NEXT); 1643 } 1644 1645 add_pg: 1646 if (issvc) 1647 r = scf_service_add_pg(ent, p->sc_pgroup_name, 1648 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 1649 else 1650 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 1651 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 1652 if (r != 0) { 1653 switch (scf_error()) { 1654 case SCF_ERROR_DELETED: 1655 case SCF_ERROR_CONNECTION_BROKEN: 1656 case SCF_ERROR_BACKEND_READONLY: 1657 case SCF_ERROR_BACKEND_ACCESS: 1658 case SCF_ERROR_NO_RESOURCES: 1659 return (stash_scferror(lcbdata)); 1660 1661 case SCF_ERROR_EXISTS: 1662 if (lcbdata->sc_flags & SCI_FORCE) 1663 break; 1664 return (stash_scferror(lcbdata)); 1665 1666 case SCF_ERROR_INVALID_ARGUMENT: 1667 warn(emsg_fmri_invalid_pg_name_type, 1668 lcbdata->sc_source_fmri, 1669 p->sc_pgroup_name, p->sc_pgroup_type); 1670 return (stash_scferror(lcbdata)); 1671 1672 case SCF_ERROR_PERMISSION_DENIED: 1673 warn(emsg_pg_add_perm, p->sc_pgroup_name, 1674 lcbdata->sc_target_fmri); 1675 return (stash_scferror(lcbdata)); 1676 1677 case SCF_ERROR_NOT_BOUND: 1678 case SCF_ERROR_HANDLE_MISMATCH: 1679 case SCF_ERROR_NOT_SET: 1680 default: 1681 bad_error("scf_service_add_pg", scf_error()); 1682 } 1683 1684 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 1685 switch (scf_error()) { 1686 case SCF_ERROR_CONNECTION_BROKEN: 1687 case SCF_ERROR_DELETED: 1688 return (stash_scferror(lcbdata)); 1689 1690 case SCF_ERROR_INVALID_ARGUMENT: 1691 warn(emsg_fmri_invalid_pg_name, 1692 lcbdata->sc_source_fmri, 1693 p->sc_pgroup_name); 1694 return (stash_scferror(lcbdata)); 1695 1696 case SCF_ERROR_NOT_FOUND: 1697 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 1698 p->sc_pgroup_name); 1699 lcbdata->sc_err = EBUSY; 1700 return (UU_WALK_ERROR); 1701 1702 case SCF_ERROR_NOT_BOUND: 1703 case SCF_ERROR_HANDLE_MISMATCH: 1704 case SCF_ERROR_NOT_SET: 1705 default: 1706 bad_error("entity_get_pg", scf_error()); 1707 } 1708 } 1709 1710 if (lcbdata->sc_flags & SCI_KEEP) 1711 goto props; 1712 1713 if (scf_pg_delete(imp_pg) != 0) { 1714 switch (scf_error()) { 1715 case SCF_ERROR_DELETED: 1716 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 1717 p->sc_pgroup_name); 1718 lcbdata->sc_err = EBUSY; 1719 return (UU_WALK_ERROR); 1720 1721 case SCF_ERROR_PERMISSION_DENIED: 1722 warn(emsg_pg_del_perm, p->sc_pgroup_name, 1723 lcbdata->sc_target_fmri); 1724 return (stash_scferror(lcbdata)); 1725 1726 case SCF_ERROR_BACKEND_READONLY: 1727 case SCF_ERROR_BACKEND_ACCESS: 1728 case SCF_ERROR_CONNECTION_BROKEN: 1729 return (stash_scferror(lcbdata)); 1730 1731 case SCF_ERROR_NOT_SET: 1732 default: 1733 bad_error("scf_pg_delete", scf_error()); 1734 } 1735 } 1736 1737 goto add_pg; 1738 } 1739 1740 props: 1741 1742 /* 1743 * Add properties to property group, if any. 1744 */ 1745 cbdata.sc_handle = lcbdata->sc_handle; 1746 cbdata.sc_parent = imp_pg; 1747 cbdata.sc_flags = lcbdata->sc_flags; 1748 cbdata.sc_trans = imp_tx; 1749 1750 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 1751 switch (scf_error()) { 1752 case SCF_ERROR_BACKEND_ACCESS: 1753 case SCF_ERROR_BACKEND_READONLY: 1754 case SCF_ERROR_CONNECTION_BROKEN: 1755 return (stash_scferror(lcbdata)); 1756 1757 case SCF_ERROR_DELETED: 1758 warn(pg_changed, lcbdata->sc_target_fmri, 1759 p->sc_pgroup_name); 1760 lcbdata->sc_err = EBUSY; 1761 return (UU_WALK_ERROR); 1762 1763 case SCF_ERROR_PERMISSION_DENIED: 1764 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 1765 lcbdata->sc_target_fmri); 1766 return (stash_scferror(lcbdata)); 1767 1768 case SCF_ERROR_NOT_BOUND: 1769 case SCF_ERROR_NOT_SET: 1770 case SCF_ERROR_IN_USE: 1771 case SCF_ERROR_HANDLE_MISMATCH: 1772 default: 1773 bad_error("scf_transaction_start", scf_error()); 1774 } 1775 } 1776 1777 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 1778 UU_DEFAULT) != 0) { 1779 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 1780 bad_error("uu_list_walk", uu_error()); 1781 scf_transaction_reset(imp_tx); 1782 1783 lcbdata->sc_err = cbdata.sc_err; 1784 if (cbdata.sc_err == ECANCELED) { 1785 warn(pg_changed, lcbdata->sc_target_fmri, 1786 p->sc_pgroup_name); 1787 lcbdata->sc_err = EBUSY; 1788 } 1789 return (UU_WALK_ERROR); 1790 } 1791 1792 r = scf_transaction_commit(imp_tx); 1793 switch (r) { 1794 case 1: 1795 r = UU_WALK_NEXT; 1796 break; 1797 1798 case 0: 1799 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 1800 lcbdata->sc_err = EBUSY; 1801 r = UU_WALK_ERROR; 1802 break; 1803 1804 case -1: 1805 switch (scf_error()) { 1806 case SCF_ERROR_BACKEND_READONLY: 1807 case SCF_ERROR_BACKEND_ACCESS: 1808 case SCF_ERROR_CONNECTION_BROKEN: 1809 case SCF_ERROR_NO_RESOURCES: 1810 r = stash_scferror(lcbdata); 1811 break; 1812 1813 case SCF_ERROR_DELETED: 1814 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 1815 p->sc_pgroup_name); 1816 lcbdata->sc_err = EBUSY; 1817 r = UU_WALK_ERROR; 1818 break; 1819 1820 case SCF_ERROR_PERMISSION_DENIED: 1821 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 1822 lcbdata->sc_target_fmri); 1823 r = stash_scferror(lcbdata); 1824 break; 1825 1826 case SCF_ERROR_NOT_SET: 1827 case SCF_ERROR_INVALID_ARGUMENT: 1828 case SCF_ERROR_NOT_BOUND: 1829 default: 1830 bad_error("scf_transaction_commit", scf_error()); 1831 } 1832 1833 default: 1834 bad_error("scf_transaction_commit", r); 1835 } 1836 1837 scf_transaction_destroy_children(imp_tx); 1838 1839 return (r); 1840 } 1841 1842 /* 1843 * Returns 1844 * 0 - success 1845 * ECONNABORTED - repository connection broken 1846 * ENOMEM - out of memory 1847 * ENOSPC - svc.configd is out of resources 1848 * ECANCELED - inst was deleted 1849 * EPERM - could not create property group (permission denied) (error printed) 1850 * - could not modify property group (permission denied) (error printed) 1851 * EROFS - could not create property group (repository is read-only) 1852 * EACCES - could not create property group (backend access denied) 1853 * EEXIST - could not create property group (already exists) 1854 * EINVAL - invalid property group name (error printed) 1855 * - invalid property name (error printed) 1856 * - invalid value (error printed) 1857 * EBUSY - new property group changed (error printed) 1858 */ 1859 static int 1860 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 1861 const entity_t *iinst, int flags) 1862 { 1863 scf_callback_t cbdata; 1864 1865 cbdata.sc_handle = scf_instance_handle(inst); 1866 cbdata.sc_parent = inst; 1867 cbdata.sc_service = 0; 1868 cbdata.sc_general = 0; 1869 cbdata.sc_flags = flags; 1870 cbdata.sc_source_fmri = iinst->sc_fmri; 1871 cbdata.sc_target_fmri = target_fmri; 1872 1873 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 1874 UU_DEFAULT) != 0) { 1875 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 1876 bad_error("uu_list_walk", uu_error()); 1877 1878 return (cbdata.sc_err); 1879 } 1880 1881 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 1882 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 1883 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 1884 != UU_WALK_NEXT) 1885 return (cbdata.sc_err); 1886 } 1887 1888 return (0); 1889 } 1890 1891 /* 1892 * Report the reasons why we can't upgrade pg2 to pg1. 1893 */ 1894 static void 1895 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 1896 int new) 1897 { 1898 property_t *p1, *p2; 1899 1900 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 1901 1902 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 1903 return; 1904 1905 for (p1 = uu_list_first(pg1->sc_pgroup_props); 1906 p1 != NULL; 1907 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 1908 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 1909 if (p2 != NULL) { 1910 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 1911 new); 1912 continue; 1913 } 1914 1915 if (new) 1916 warn(gettext("Conflict upgrading %s (new property " 1917 "group \"%s\" is missing property \"%s\").\n"), 1918 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 1919 else 1920 warn(gettext("Conflict upgrading %s (property " 1921 "\"%s/%s\" is missing).\n"), fmri, 1922 pg1->sc_pgroup_name, p1->sc_property_name); 1923 } 1924 1925 /* 1926 * Since pg1 should be from the manifest, any properties in pg2 which 1927 * aren't in pg1 shouldn't be reported as conflicts. 1928 */ 1929 } 1930 1931 /* 1932 * Add transaction entries to tx which will upgrade cur's pg according to old 1933 * & new. 1934 * 1935 * Returns 1936 * 0 - success 1937 * EINVAL - new has a property with an invalid name or value (message emitted) 1938 * ENOMEM - out of memory 1939 */ 1940 static int 1941 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 1942 pgroup_t *cur, int speak, const char *fmri) 1943 { 1944 property_t *p, *new_p, *cur_p; 1945 scf_transaction_entry_t *e; 1946 int r; 1947 int is_general; 1948 int is_protected; 1949 1950 if (uu_list_walk(new->sc_pgroup_props, clear_int, 1951 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 1952 bad_error("uu_list_walk", uu_error()); 1953 1954 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 1955 1956 for (p = uu_list_first(old->sc_pgroup_props); 1957 p != NULL; 1958 p = uu_list_next(old->sc_pgroup_props, p)) { 1959 /* p is a property in the old property group. */ 1960 1961 /* Protect live properties. */ 1962 is_protected = 0; 1963 if (is_general) { 1964 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 1965 0 || 1966 strcmp(p->sc_property_name, 1967 SCF_PROPERTY_RESTARTER) == 0) 1968 is_protected = 1; 1969 } 1970 1971 /* Look for the same property in the new properties. */ 1972 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 1973 if (new_p != NULL) { 1974 new_p->sc_seen = 1; 1975 1976 /* 1977 * If the new property is the same as the old, don't do 1978 * anything (leave any user customizations). 1979 */ 1980 if (prop_equal(p, new_p, NULL, NULL, 0)) 1981 continue; 1982 1983 if (new_p->sc_property_override) 1984 goto upgrade; 1985 } 1986 1987 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 1988 if (cur_p == NULL) { 1989 /* 1990 * p has been deleted from the repository. If we were 1991 * going to delete it anyway, do nothing. Otherwise 1992 * report a conflict. 1993 */ 1994 if (new_p == NULL) 1995 continue; 1996 1997 if (is_protected) 1998 continue; 1999 2000 warn(gettext("Conflict upgrading %s " 2001 "(property \"%s/%s\" is missing).\n"), fmri, 2002 old->sc_pgroup_name, p->sc_property_name); 2003 continue; 2004 } 2005 2006 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2007 /* 2008 * Conflict. Don't warn if the property is already the 2009 * way we want it, though. 2010 */ 2011 if (is_protected) 2012 continue; 2013 2014 if (new_p == NULL) 2015 (void) prop_equal(p, cur_p, fmri, 2016 old->sc_pgroup_name, 0); 2017 else 2018 (void) prop_equal(cur_p, new_p, fmri, 2019 old->sc_pgroup_name, 0); 2020 continue; 2021 } 2022 2023 if (is_protected) { 2024 if (speak) 2025 warn(gettext("%s: Refusing to upgrade " 2026 "\"%s/%s\" (live property).\n"), fmri, 2027 old->sc_pgroup_name, p->sc_property_name); 2028 continue; 2029 } 2030 2031 upgrade: 2032 /* p hasn't been customized in the repository. Upgrade it. */ 2033 if (new_p == NULL) { 2034 /* p was deleted. Delete from cur if unchanged. */ 2035 if (speak) 2036 warn(gettext( 2037 "%s: Deleting property \"%s/%s\".\n"), 2038 fmri, old->sc_pgroup_name, 2039 p->sc_property_name); 2040 2041 e = scf_entry_create(g_hndl); 2042 if (e == NULL) 2043 return (ENOMEM); 2044 2045 if (scf_transaction_property_delete(tx, e, 2046 p->sc_property_name) != 0) { 2047 switch (scf_error()) { 2048 case SCF_ERROR_DELETED: 2049 scf_entry_destroy(e); 2050 return (ECANCELED); 2051 2052 case SCF_ERROR_CONNECTION_BROKEN: 2053 scf_entry_destroy(e); 2054 return (ECONNABORTED); 2055 2056 case SCF_ERROR_NOT_FOUND: 2057 /* 2058 * This can happen if cur is from the 2059 * running snapshot (and it differs 2060 * from the live properties). 2061 */ 2062 scf_entry_destroy(e); 2063 break; 2064 2065 case SCF_ERROR_HANDLE_MISMATCH: 2066 case SCF_ERROR_NOT_BOUND: 2067 case SCF_ERROR_NOT_SET: 2068 case SCF_ERROR_INVALID_ARGUMENT: 2069 default: 2070 bad_error( 2071 "scf_transaction_property_delete", 2072 scf_error()); 2073 } 2074 } 2075 } else { 2076 scf_callback_t ctx; 2077 2078 if (speak) 2079 warn(gettext( 2080 "%s: Upgrading property \"%s/%s\".\n"), 2081 fmri, old->sc_pgroup_name, 2082 p->sc_property_name); 2083 2084 ctx.sc_handle = g_hndl; 2085 ctx.sc_trans = tx; 2086 ctx.sc_flags = 0; 2087 2088 r = lscf_property_import(new_p, &ctx); 2089 if (r != UU_WALK_NEXT) { 2090 if (r != UU_WALK_ERROR) 2091 bad_error("lscf_property_import", r); 2092 return (EINVAL); 2093 } 2094 } 2095 } 2096 2097 /* Go over the properties which were added. */ 2098 for (new_p = uu_list_first(new->sc_pgroup_props); 2099 new_p != NULL; 2100 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 2101 if (new_p->sc_seen) 2102 continue; 2103 2104 /* This is a new property. */ 2105 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 2106 if (cur_p == NULL) { 2107 scf_callback_t ctx; 2108 2109 ctx.sc_handle = g_hndl; 2110 ctx.sc_trans = tx; 2111 ctx.sc_flags = 0; 2112 2113 r = lscf_property_import(new_p, &ctx); 2114 if (r != UU_WALK_NEXT) { 2115 if (r != UU_WALK_ERROR) 2116 bad_error("lscf_property_import", r); 2117 return (EINVAL); 2118 } 2119 continue; 2120 } 2121 2122 /* 2123 * Report a conflict if the new property differs from the 2124 * current one. Unless it's general/enabled, since that's 2125 * never in the last-import snapshot. 2126 */ 2127 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 2128 0 && 2129 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 2130 continue; 2131 2132 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 2133 } 2134 2135 return (0); 2136 } 2137 2138 /* 2139 * Upgrade pg according to old & new. 2140 * 2141 * Returns 2142 * 0 - success 2143 * ECONNABORTED - repository connection broken 2144 * ENOMEM - out of memory 2145 * ENOSPC - svc.configd is out of resources 2146 * ECANCELED - pg was deleted 2147 * EPERM - couldn't modify pg (permission denied) 2148 * EROFS - couldn't modify pg (backend read-only) 2149 * EACCES - couldn't modify pg (backend access denied) 2150 * EINVAL - new has a property with invalid name or value (error printed) 2151 * EBUSY - pg changed unexpectedly 2152 */ 2153 static int 2154 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 2155 pgroup_t *new, int speak, const char *fmri) 2156 { 2157 int r; 2158 2159 if (scf_transaction_start(imp_tx, pg) != 0) { 2160 switch (scf_error()) { 2161 case SCF_ERROR_CONNECTION_BROKEN: 2162 case SCF_ERROR_DELETED: 2163 case SCF_ERROR_PERMISSION_DENIED: 2164 case SCF_ERROR_BACKEND_READONLY: 2165 case SCF_ERROR_BACKEND_ACCESS: 2166 return (scferror2errno(scf_error())); 2167 2168 case SCF_ERROR_HANDLE_MISMATCH: 2169 case SCF_ERROR_IN_USE: 2170 case SCF_ERROR_NOT_BOUND: 2171 case SCF_ERROR_NOT_SET: 2172 default: 2173 bad_error("scf_transaction_start", scf_error()); 2174 } 2175 } 2176 2177 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 2178 switch (r) { 2179 case 0: 2180 break; 2181 2182 case EINVAL: 2183 case ENOMEM: 2184 scf_transaction_destroy_children(imp_tx); 2185 return (r); 2186 2187 default: 2188 bad_error("add_upgrade_entries", r); 2189 } 2190 2191 r = scf_transaction_commit(imp_tx); 2192 2193 scf_transaction_destroy_children(imp_tx); 2194 2195 switch (r) { 2196 case 1: 2197 break; 2198 2199 case 0: 2200 return (EBUSY); 2201 2202 case -1: 2203 switch (scf_error()) { 2204 case SCF_ERROR_CONNECTION_BROKEN: 2205 case SCF_ERROR_NO_RESOURCES: 2206 case SCF_ERROR_PERMISSION_DENIED: 2207 case SCF_ERROR_BACKEND_READONLY: 2208 case SCF_ERROR_BACKEND_ACCESS: 2209 case SCF_ERROR_DELETED: 2210 return (scferror2errno(scf_error())); 2211 2212 case SCF_ERROR_NOT_BOUND: 2213 case SCF_ERROR_INVALID_ARGUMENT: 2214 case SCF_ERROR_NOT_SET: 2215 default: 2216 bad_error("scf_transaction_commit", scf_error()); 2217 } 2218 2219 default: 2220 bad_error("scf_transaction_commit", r); 2221 } 2222 2223 return (0); 2224 } 2225 2226 /* 2227 * Compares two entity FMRIs. Returns 2228 * 2229 * 1 - equal 2230 * 0 - not equal 2231 * -1 - f1 is invalid or not an entity 2232 * -2 - f2 is invalid or not an entity 2233 */ 2234 static int 2235 fmri_equal(const char *f1, const char *f2) 2236 { 2237 int r; 2238 const char *s1, *i1, *pg1; 2239 const char *s2, *i2, *pg2; 2240 2241 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 2242 return (-1); 2243 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 2244 return (-1); 2245 2246 if (s1 == NULL || pg1 != NULL) 2247 return (-1); 2248 2249 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 2250 return (-2); 2251 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 2252 return (-2); 2253 2254 if (s2 == NULL || pg2 != NULL) 2255 return (-2); 2256 2257 r = strcmp(s1, s2); 2258 if (r != 0) 2259 return (0); 2260 2261 if (i1 == NULL && i2 == NULL) 2262 return (1); 2263 2264 if (i1 == NULL || i2 == NULL) 2265 return (0); 2266 2267 return (strcmp(i1, i2) == 0); 2268 } 2269 2270 /* 2271 * Import a dependent by creating a dependency property group in the dependent 2272 * entity. If lcbdata->sc_trans is set, assume it's been started on the 2273 * dependents pg, and add an entry to create a new property for this 2274 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 2275 * 2276 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 2277 * lcbdata->sc_err to 2278 * ECONNABORTED - repository connection broken 2279 * ENOMEM - out of memory 2280 * ENOSPC - configd is out of resources 2281 * EINVAL - target is invalid (error printed) 2282 * - target is not an entity (error printed) 2283 * - dependent has invalid name (error printed) 2284 * - invalid property name (error printed) 2285 * - invalid value (error printed) 2286 * - scope of target does not exist (error printed) 2287 * EPERM - couldn't create target (permission denied) (error printed) 2288 * - couldn't create dependency pg (permission denied) (error printed) 2289 * - couldn't modify dependency pg (permission denied) (error printed) 2290 * EROFS - couldn't create target (repository read-only) 2291 * - couldn't create dependency pg (repository read-only) 2292 * EACCES - couldn't create target (backend access denied) 2293 * - couldn't create dependency pg (backend access denied) 2294 * ECANCELED - sc_trans's pg was deleted 2295 * EALREADY - property for dependent already exists in sc_trans's pg 2296 * EEXIST - dependency pg already exists in target (error printed) 2297 * EBUSY - target deleted (error printed) 2298 * - property group changed during import (error printed) 2299 */ 2300 static int 2301 lscf_dependent_import(void *a1, void *pvt) 2302 { 2303 pgroup_t *pgrp = a1; 2304 scf_callback_t *lcbdata = pvt; 2305 2306 int isservice; 2307 int ret; 2308 scf_transaction_entry_t *e; 2309 scf_value_t *val; 2310 scf_callback_t dependent_cbdata; 2311 scf_error_t scfe; 2312 2313 /* 2314 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 2315 * it's invalid, we fail before modifying the repository. 2316 */ 2317 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 2318 &dependent_cbdata.sc_parent, &isservice); 2319 switch (scfe) { 2320 case SCF_ERROR_NONE: 2321 break; 2322 2323 case SCF_ERROR_NO_MEMORY: 2324 return (stash_scferror_err(lcbdata, scfe)); 2325 2326 case SCF_ERROR_INVALID_ARGUMENT: 2327 semerr(gettext("The FMRI for the \"%s\" dependent is " 2328 "invalid.\n"), pgrp->sc_pgroup_name); 2329 return (stash_scferror_err(lcbdata, scfe)); 2330 2331 case SCF_ERROR_CONSTRAINT_VIOLATED: 2332 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 2333 "specifies neither a service nor an instance.\n"), 2334 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 2335 return (stash_scferror_err(lcbdata, scfe)); 2336 2337 case SCF_ERROR_NOT_FOUND: 2338 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 2339 &dependent_cbdata.sc_parent, &isservice); 2340 switch (scfe) { 2341 case SCF_ERROR_NONE: 2342 break; 2343 2344 case SCF_ERROR_NO_MEMORY: 2345 case SCF_ERROR_BACKEND_READONLY: 2346 case SCF_ERROR_BACKEND_ACCESS: 2347 return (stash_scferror_err(lcbdata, scfe)); 2348 2349 case SCF_ERROR_NOT_FOUND: 2350 semerr(gettext("The scope in FMRI \"%s\" for the " 2351 "\"%s\" dependent does not exist.\n"), 2352 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 2353 lcbdata->sc_err = EINVAL; 2354 return (UU_WALK_ERROR); 2355 2356 case SCF_ERROR_PERMISSION_DENIED: 2357 warn(gettext( 2358 "Could not create %s (permission denied).\n"), 2359 pgrp->sc_pgroup_fmri); 2360 return (stash_scferror_err(lcbdata, scfe)); 2361 2362 case SCF_ERROR_INVALID_ARGUMENT: 2363 case SCF_ERROR_CONSTRAINT_VIOLATED: 2364 default: 2365 bad_error("create_entity", scfe); 2366 } 2367 break; 2368 2369 default: 2370 bad_error("fmri_to_entity", scfe); 2371 } 2372 2373 if (lcbdata->sc_trans != NULL) { 2374 e = scf_entry_create(lcbdata->sc_handle); 2375 if (e == NULL) { 2376 if (scf_error() != SCF_ERROR_NO_MEMORY) 2377 bad_error("scf_entry_create", scf_error()); 2378 2379 entity_destroy(dependent_cbdata.sc_parent, isservice); 2380 return (stash_scferror(lcbdata)); 2381 } 2382 2383 if (scf_transaction_property_new(lcbdata->sc_trans, e, 2384 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 2385 switch (scf_error()) { 2386 case SCF_ERROR_INVALID_ARGUMENT: 2387 warn(gettext("Dependent of %s has invalid name " 2388 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 2389 pgrp->sc_pgroup_name); 2390 /* FALLTHROUGH */ 2391 2392 case SCF_ERROR_DELETED: 2393 case SCF_ERROR_CONNECTION_BROKEN: 2394 scf_entry_destroy(e); 2395 entity_destroy(dependent_cbdata.sc_parent, 2396 isservice); 2397 return (stash_scferror(lcbdata)); 2398 2399 case SCF_ERROR_EXISTS: 2400 scf_entry_destroy(e); 2401 entity_destroy(dependent_cbdata.sc_parent, 2402 isservice); 2403 lcbdata->sc_err = EALREADY; 2404 return (UU_WALK_ERROR); 2405 2406 case SCF_ERROR_NOT_BOUND: 2407 case SCF_ERROR_HANDLE_MISMATCH: 2408 case SCF_ERROR_NOT_SET: 2409 default: 2410 bad_error("scf_transaction_property_new", 2411 scf_error()); 2412 } 2413 } 2414 2415 val = scf_value_create(lcbdata->sc_handle); 2416 if (val == NULL) { 2417 if (scf_error() != SCF_ERROR_NO_MEMORY) 2418 bad_error("scf_value_create", scf_error()); 2419 2420 entity_destroy(dependent_cbdata.sc_parent, isservice); 2421 return (stash_scferror(lcbdata)); 2422 } 2423 2424 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 2425 pgrp->sc_pgroup_fmri) != 0) 2426 /* invalid should have been caught above */ 2427 bad_error("scf_value_set_from_string", scf_error()); 2428 2429 if (scf_entry_add_value(e, val) != 0) 2430 bad_error("scf_entry_add_value", scf_error()); 2431 } 2432 2433 /* Add the property group to the target entity. */ 2434 2435 dependent_cbdata.sc_handle = lcbdata->sc_handle; 2436 dependent_cbdata.sc_flags = 0; 2437 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 2438 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 2439 2440 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 2441 2442 entity_destroy(dependent_cbdata.sc_parent, isservice); 2443 2444 if (ret == UU_WALK_NEXT) 2445 return (ret); 2446 2447 if (ret != UU_WALK_ERROR) 2448 bad_error("entity_pgroup_import", ret); 2449 2450 switch (dependent_cbdata.sc_err) { 2451 case ECANCELED: 2452 warn(gettext("%s deleted unexpectedly.\n"), 2453 pgrp->sc_pgroup_fmri); 2454 lcbdata->sc_err = EBUSY; 2455 break; 2456 2457 case EEXIST: 2458 warn(gettext("Could not create \"%s\" dependency in %s " 2459 "(already exists).\n"), pgrp->sc_pgroup_name, 2460 pgrp->sc_pgroup_fmri); 2461 /* FALLTHROUGH */ 2462 2463 default: 2464 lcbdata->sc_err = dependent_cbdata.sc_err; 2465 } 2466 2467 return (UU_WALK_ERROR); 2468 } 2469 2470 static int upgrade_dependent(const scf_property_t *, const entity_t *, 2471 const scf_snaplevel_t *, scf_transaction_t *); 2472 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 2473 const pgroup_t *); 2474 2475 /* 2476 * Upgrade uncustomized dependents of ent to those specified in ient. Read 2477 * the current dependent targets from running (the snaplevel of a running 2478 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 2479 * scf_instance_t * according to ient, otherwise). Draw the ancestral 2480 * dependent targets and dependency properties from li_dpts_pg (the 2481 * "dependents" property group in snpl) and snpl (the snaplevel which 2482 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 2483 * snpl doesn't have a "dependents" property group, and any dependents in ient 2484 * are new. 2485 * 2486 * Returns 2487 * 0 - success 2488 * ECONNABORTED - repository connection broken 2489 * ENOMEM - out of memory 2490 * ENOSPC - configd is out of resources 2491 * ECANCELED - ent was deleted 2492 * ENODEV - the entity containing li_dpts_pg was deleted 2493 * EPERM - could not modify dependents pg (permission denied) (error printed) 2494 * - couldn't upgrade dependent (permission denied) (error printed) 2495 * - couldn't create dependent (permission denied) (error printed) 2496 * EROFS - could not modify dependents pg (repository read-only) 2497 * - couldn't upgrade dependent (repository read-only) 2498 * - couldn't create dependent (repository read-only) 2499 * EACCES - could not modify dependents pg (backend access denied) 2500 * - could not upgrade dependent (backend access denied) 2501 * - could not create dependent (backend access denied) 2502 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 2503 * - dependent target deleted (error printed) 2504 * - dependent pg changed (error printed) 2505 * EINVAL - new dependent is invalid (error printed) 2506 * EBADF - snpl is corrupt (error printed) 2507 * - snpl has corrupt pg (error printed) 2508 * - dependency pg in target is corrupt (error printed) 2509 * - target has corrupt snapshot (error printed) 2510 * EEXIST - dependency pg already existed in target service (error printed) 2511 */ 2512 static int 2513 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 2514 const scf_snaplevel_t *snpl, const entity_t *ient, 2515 const scf_snaplevel_t *running, void *ent) 2516 { 2517 pgroup_t *new_dpt_pgroup; 2518 scf_callback_t cbdata; 2519 int r, unseen, tx_started = 0; 2520 int have_cur_depts; 2521 2522 const char * const dependents = "dependents"; 2523 2524 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 2525 2526 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 2527 /* Nothing to do. */ 2528 return (0); 2529 2530 /* Fetch the current version of the "dependents" property group. */ 2531 have_cur_depts = 1; 2532 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 2533 switch (scf_error()) { 2534 case SCF_ERROR_NOT_FOUND: 2535 break; 2536 2537 case SCF_ERROR_DELETED: 2538 case SCF_ERROR_CONNECTION_BROKEN: 2539 return (scferror2errno(scf_error())); 2540 2541 case SCF_ERROR_NOT_SET: 2542 case SCF_ERROR_INVALID_ARGUMENT: 2543 case SCF_ERROR_HANDLE_MISMATCH: 2544 case SCF_ERROR_NOT_BOUND: 2545 default: 2546 bad_error("entity_get_pg", scf_error()); 2547 } 2548 2549 have_cur_depts = 0; 2550 } 2551 2552 /* Fetch the running version of the "dependents" property group. */ 2553 ud_run_dpts_pg_set = 0; 2554 if (running != NULL) 2555 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 2556 else 2557 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 2558 if (r == 0) { 2559 ud_run_dpts_pg_set = 1; 2560 } else { 2561 switch (scf_error()) { 2562 case SCF_ERROR_NOT_FOUND: 2563 break; 2564 2565 case SCF_ERROR_DELETED: 2566 case SCF_ERROR_CONNECTION_BROKEN: 2567 return (scferror2errno(scf_error())); 2568 2569 case SCF_ERROR_NOT_SET: 2570 case SCF_ERROR_INVALID_ARGUMENT: 2571 case SCF_ERROR_HANDLE_MISMATCH: 2572 case SCF_ERROR_NOT_BOUND: 2573 default: 2574 bad_error(running ? "scf_snaplevel_get_pg" : 2575 "entity_get_pg", scf_error()); 2576 } 2577 } 2578 2579 /* 2580 * Clear the seen fields of the dependents, so we can tell which ones 2581 * are new. 2582 */ 2583 if (uu_list_walk(ient->sc_dependents, clear_int, 2584 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 2585 bad_error("uu_list_walk", uu_error()); 2586 2587 if (li_dpts_pg != NULL) { 2588 /* 2589 * Each property in li_dpts_pg represents a dependent tag in 2590 * the old manifest. For each, call upgrade_dependent(), 2591 * which will change ud_cur_depts_pg or dependencies in other 2592 * services as appropriate. Note (a) that changes to 2593 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 2594 * made en masse, and (b) it's ok if the entity doesn't have 2595 * a current version of the "dependents" property group, 2596 * because we'll just consider all dependents as customized 2597 * (by being deleted). 2598 */ 2599 2600 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 2601 switch (scf_error()) { 2602 case SCF_ERROR_DELETED: 2603 return (ENODEV); 2604 2605 case SCF_ERROR_CONNECTION_BROKEN: 2606 return (ECONNABORTED); 2607 2608 case SCF_ERROR_HANDLE_MISMATCH: 2609 case SCF_ERROR_NOT_BOUND: 2610 case SCF_ERROR_NOT_SET: 2611 default: 2612 bad_error("scf_iter_pg_properties", 2613 scf_error()); 2614 } 2615 } 2616 2617 if (have_cur_depts && 2618 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 2619 switch (scf_error()) { 2620 case SCF_ERROR_BACKEND_ACCESS: 2621 case SCF_ERROR_BACKEND_READONLY: 2622 case SCF_ERROR_CONNECTION_BROKEN: 2623 return (scferror2errno(scf_error())); 2624 2625 case SCF_ERROR_DELETED: 2626 warn(emsg_pg_deleted, ient->sc_fmri, 2627 dependents); 2628 return (EBUSY); 2629 2630 case SCF_ERROR_PERMISSION_DENIED: 2631 warn(emsg_pg_mod_perm, dependents, 2632 ient->sc_fmri); 2633 return (scferror2errno(scf_error())); 2634 2635 case SCF_ERROR_HANDLE_MISMATCH: 2636 case SCF_ERROR_IN_USE: 2637 case SCF_ERROR_NOT_BOUND: 2638 case SCF_ERROR_NOT_SET: 2639 default: 2640 bad_error("scf_transaction_start", scf_error()); 2641 } 2642 } 2643 tx_started = have_cur_depts; 2644 2645 for (;;) { 2646 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 2647 if (r == 0) 2648 break; 2649 if (r == 1) { 2650 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 2651 tx_started ? ud_tx : NULL); 2652 switch (r) { 2653 case 0: 2654 continue; 2655 2656 case ECONNABORTED: 2657 case ENOMEM: 2658 case ENOSPC: 2659 case EBADF: 2660 case EBUSY: 2661 case EINVAL: 2662 case EPERM: 2663 case EROFS: 2664 case EACCES: 2665 case EEXIST: 2666 break; 2667 2668 case ECANCELED: 2669 r = ENODEV; 2670 break; 2671 2672 default: 2673 bad_error("upgrade_dependent", r); 2674 } 2675 2676 if (tx_started) 2677 scf_transaction_destroy_children(ud_tx); 2678 return (r); 2679 } 2680 if (r != -1) 2681 bad_error("scf_iter_next_property", r); 2682 2683 switch (scf_error()) { 2684 case SCF_ERROR_DELETED: 2685 r = ENODEV; 2686 break; 2687 2688 case SCF_ERROR_CONNECTION_BROKEN: 2689 r = ECONNABORTED; 2690 break; 2691 2692 case SCF_ERROR_NOT_SET: 2693 case SCF_ERROR_INVALID_ARGUMENT: 2694 case SCF_ERROR_NOT_BOUND: 2695 case SCF_ERROR_HANDLE_MISMATCH: 2696 default: 2697 bad_error("scf_iter_next_property", 2698 scf_error()); 2699 } 2700 2701 if (tx_started) 2702 scf_transaction_destroy_children(ud_tx); 2703 return (r); 2704 } 2705 } 2706 2707 /* import unseen dependents */ 2708 unseen = 0; 2709 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 2710 new_dpt_pgroup != NULL; 2711 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 2712 new_dpt_pgroup)) { 2713 if (!new_dpt_pgroup->sc_pgroup_seen) { 2714 unseen = 1; 2715 break; 2716 } 2717 } 2718 2719 /* If there are none, exit early. */ 2720 if (unseen == 0) 2721 goto commit; 2722 2723 /* Set up for lscf_dependent_import() */ 2724 cbdata.sc_handle = g_hndl; 2725 cbdata.sc_parent = ent; 2726 cbdata.sc_service = issvc; 2727 cbdata.sc_flags = 0; 2728 2729 if (!have_cur_depts) { 2730 /* 2731 * We have new dependents to import, so we need a "dependents" 2732 * property group. 2733 */ 2734 if (issvc) 2735 r = scf_service_add_pg(ent, dependents, 2736 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 2737 else 2738 r = scf_instance_add_pg(ent, dependents, 2739 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 2740 if (r != 0) { 2741 switch (scf_error()) { 2742 case SCF_ERROR_DELETED: 2743 case SCF_ERROR_CONNECTION_BROKEN: 2744 case SCF_ERROR_BACKEND_READONLY: 2745 case SCF_ERROR_BACKEND_ACCESS: 2746 case SCF_ERROR_NO_RESOURCES: 2747 return (scferror2errno(scf_error())); 2748 2749 case SCF_ERROR_EXISTS: 2750 warn(emsg_pg_added, ient->sc_fmri, dependents); 2751 return (EBUSY); 2752 2753 case SCF_ERROR_PERMISSION_DENIED: 2754 warn(emsg_pg_add_perm, dependents, 2755 ient->sc_fmri); 2756 return (scferror2errno(scf_error())); 2757 2758 case SCF_ERROR_NOT_BOUND: 2759 case SCF_ERROR_HANDLE_MISMATCH: 2760 case SCF_ERROR_INVALID_ARGUMENT: 2761 case SCF_ERROR_NOT_SET: 2762 default: 2763 bad_error("scf_service_add_pg", scf_error()); 2764 } 2765 } 2766 } 2767 2768 cbdata.sc_trans = ud_tx; 2769 2770 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 2771 switch (scf_error()) { 2772 case SCF_ERROR_CONNECTION_BROKEN: 2773 case SCF_ERROR_BACKEND_ACCESS: 2774 case SCF_ERROR_BACKEND_READONLY: 2775 return (scferror2errno(scf_error())); 2776 2777 case SCF_ERROR_DELETED: 2778 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 2779 return (EBUSY); 2780 2781 case SCF_ERROR_PERMISSION_DENIED: 2782 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 2783 return (scferror2errno(scf_error())); 2784 2785 case SCF_ERROR_HANDLE_MISMATCH: 2786 case SCF_ERROR_IN_USE: 2787 case SCF_ERROR_NOT_BOUND: 2788 case SCF_ERROR_NOT_SET: 2789 default: 2790 bad_error("scf_transaction_start", scf_error()); 2791 } 2792 } 2793 tx_started = 1; 2794 2795 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 2796 new_dpt_pgroup != NULL; 2797 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 2798 new_dpt_pgroup)) { 2799 if (new_dpt_pgroup->sc_pgroup_seen) 2800 continue; 2801 2802 if (ud_run_dpts_pg_set) { 2803 /* 2804 * If the dependent is already there, then we have 2805 * a conflict. 2806 */ 2807 if (scf_pg_get_property(ud_run_dpts_pg, 2808 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 2809 r = handle_dependent_conflict(ient, ud_prop, 2810 new_dpt_pgroup); 2811 switch (r) { 2812 case 0: 2813 continue; 2814 2815 case ECONNABORTED: 2816 case ENOMEM: 2817 case EBUSY: 2818 case EBADF: 2819 case EINVAL: 2820 scf_transaction_destroy_children(ud_tx); 2821 return (r); 2822 2823 default: 2824 bad_error("handle_dependent_conflict", 2825 r); 2826 } 2827 } else { 2828 switch (scf_error()) { 2829 case SCF_ERROR_NOT_FOUND: 2830 break; 2831 2832 case SCF_ERROR_INVALID_ARGUMENT: 2833 warn(emsg_fmri_invalid_pg_name, 2834 ient->sc_fmri, 2835 new_dpt_pgroup->sc_pgroup_name); 2836 scf_transaction_destroy_children(ud_tx); 2837 return (EINVAL); 2838 2839 case SCF_ERROR_DELETED: 2840 warn(emsg_pg_deleted, ient->sc_fmri, 2841 new_dpt_pgroup->sc_pgroup_name); 2842 scf_transaction_destroy_children(ud_tx); 2843 return (EBUSY); 2844 2845 case SCF_ERROR_CONNECTION_BROKEN: 2846 scf_transaction_destroy_children(ud_tx); 2847 return (ECONNABORTED); 2848 2849 case SCF_ERROR_NOT_BOUND: 2850 case SCF_ERROR_HANDLE_MISMATCH: 2851 case SCF_ERROR_NOT_SET: 2852 default: 2853 bad_error("scf_pg_get_property", 2854 scf_error()); 2855 } 2856 } 2857 } 2858 2859 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 2860 if (r != UU_WALK_NEXT) { 2861 if (r != UU_WALK_ERROR) 2862 bad_error("lscf_dependent_import", r); 2863 2864 if (cbdata.sc_err == EALREADY) { 2865 /* Collisions were handled preemptively. */ 2866 bad_error("lscf_dependent_import", 2867 cbdata.sc_err); 2868 } 2869 2870 scf_transaction_destroy_children(ud_tx); 2871 return (cbdata.sc_err); 2872 } 2873 } 2874 2875 commit: 2876 if (!tx_started) 2877 return (0); 2878 2879 r = scf_transaction_commit(ud_tx); 2880 2881 scf_transaction_destroy_children(ud_tx); 2882 2883 switch (r) { 2884 case 1: 2885 return (0); 2886 2887 case 0: 2888 warn(emsg_pg_changed, ient->sc_fmri, dependents); 2889 return (EBUSY); 2890 2891 case -1: 2892 break; 2893 2894 default: 2895 bad_error("scf_transaction_commit", r); 2896 } 2897 2898 switch (scf_error()) { 2899 case SCF_ERROR_CONNECTION_BROKEN: 2900 case SCF_ERROR_BACKEND_READONLY: 2901 case SCF_ERROR_BACKEND_ACCESS: 2902 case SCF_ERROR_NO_RESOURCES: 2903 return (scferror2errno(scf_error())); 2904 2905 case SCF_ERROR_DELETED: 2906 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 2907 return (EBUSY); 2908 2909 case SCF_ERROR_PERMISSION_DENIED: 2910 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 2911 return (scferror2errno(scf_error())); 2912 2913 case SCF_ERROR_NOT_BOUND: 2914 case SCF_ERROR_INVALID_ARGUMENT: 2915 case SCF_ERROR_NOT_SET: 2916 default: 2917 bad_error("scf_transaction_destroy", scf_error()); 2918 /* NOTREACHED */ 2919 } 2920 } 2921 2922 /* 2923 * prop is taken to be a property in the "dependents" property group of snpl, 2924 * which is taken to be the snaplevel of a last-import snapshot corresponding 2925 * to ient. If prop is a valid dependents property, upgrade the dependent it 2926 * represents according to the repository & ient. If ud_run_dpts_pg_set is 2927 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 2928 * of the entity ient represents (possibly in the running snapshot). If it 2929 * needs to be changed, an entry will be added to tx, if not NULL. 2930 * 2931 * Returns 2932 * 0 - success 2933 * ECONNABORTED - repository connection broken 2934 * ENOMEM - out of memory 2935 * ENOSPC - configd was out of resources 2936 * ECANCELED - snpl's entity was deleted 2937 * EINVAL - dependent target is invalid (error printed) 2938 * - dependent is invalid (error printed) 2939 * EBADF - snpl is corrupt (error printed) 2940 * - snpl has corrupt pg (error printed) 2941 * - dependency pg in target is corrupt (error printed) 2942 * - running snapshot in dependent is missing snaplevel (error printed) 2943 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 2944 * - couldn't create dependent (permission denied) (error printed) 2945 * - couldn't modify dependent pg (permission denied) (error printed) 2946 * EROFS - couldn't delete dependency pg (repository read-only) 2947 * - couldn't create dependent (repository read-only) 2948 * EACCES - couldn't delete dependency pg (backend access denied) 2949 * - couldn't create dependent (backend access denied) 2950 * EBUSY - ud_run_dpts_pg was deleted (error printed) 2951 * - tx's pg was deleted (error printed) 2952 * - dependent pg was changed or deleted (error printed) 2953 * EEXIST - dependency pg already exists in new target (error printed) 2954 */ 2955 static int 2956 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 2957 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 2958 { 2959 pgroup_t pgrp; 2960 scf_type_t ty; 2961 pgroup_t *new_dpt_pgroup; 2962 pgroup_t *old_dpt_pgroup = NULL; 2963 pgroup_t *current_pg; 2964 scf_callback_t cbdata; 2965 int tissvc; 2966 void *target_ent; 2967 scf_error_t serr; 2968 int r; 2969 scf_transaction_entry_t *ent; 2970 2971 const char * const cf_inval = gettext("Conflict upgrading %s " 2972 "(dependent \"%s\" has invalid dependents property).\n"); 2973 const char * const cf_missing = gettext("Conflict upgrading %s " 2974 "(dependent \"%s\" is missing).\n"); 2975 const char * const cf_newdpg = gettext("Conflict upgrading %s " 2976 "(dependent \"%s\" has new dependency property group).\n"); 2977 const char * const cf_newtarg = gettext("Conflict upgrading %s " 2978 "(dependent \"%s\" has new target).\n"); 2979 const char * const li_corrupt = 2980 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 2981 const char * const upgrading = 2982 gettext("%s: Upgrading dependent \"%s\".\n"); 2983 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 2984 "corrupt (missing snaplevel).\n"); 2985 2986 if (scf_property_type(prop, &ty) != 0) { 2987 switch (scf_error()) { 2988 case SCF_ERROR_DELETED: 2989 case SCF_ERROR_CONNECTION_BROKEN: 2990 return (scferror2errno(scf_error())); 2991 2992 case SCF_ERROR_NOT_BOUND: 2993 case SCF_ERROR_NOT_SET: 2994 default: 2995 bad_error("scf_property_type", scf_error()); 2996 } 2997 } 2998 2999 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3000 warn(li_corrupt, ient->sc_fmri); 3001 return (EBADF); 3002 } 3003 3004 /* 3005 * prop represents a dependent in the old manifest. It is named after 3006 * the dependent. 3007 */ 3008 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 3009 switch (scf_error()) { 3010 case SCF_ERROR_DELETED: 3011 case SCF_ERROR_CONNECTION_BROKEN: 3012 return (scferror2errno(scf_error())); 3013 3014 case SCF_ERROR_NOT_BOUND: 3015 case SCF_ERROR_NOT_SET: 3016 default: 3017 bad_error("scf_property_get_name", scf_error()); 3018 } 3019 } 3020 3021 /* See if it's in the new manifest. */ 3022 pgrp.sc_pgroup_name = ud_name; 3023 new_dpt_pgroup = 3024 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 3025 3026 /* If it's not, delete it... if it hasn't been customized. */ 3027 if (new_dpt_pgroup == NULL) { 3028 pgroup_t *dpt; 3029 3030 if (!ud_run_dpts_pg_set) 3031 return (0); 3032 3033 if (scf_property_get_value(prop, ud_val) != 0) { 3034 switch (scf_error()) { 3035 case SCF_ERROR_NOT_FOUND: 3036 case SCF_ERROR_CONSTRAINT_VIOLATED: 3037 warn(li_corrupt, ient->sc_fmri); 3038 return (EBADF); 3039 3040 case SCF_ERROR_DELETED: 3041 case SCF_ERROR_CONNECTION_BROKEN: 3042 return (scferror2errno(scf_error())); 3043 3044 case SCF_ERROR_HANDLE_MISMATCH: 3045 case SCF_ERROR_NOT_BOUND: 3046 case SCF_ERROR_NOT_SET: 3047 default: 3048 bad_error("scf_property_get_value", 3049 scf_error()); 3050 } 3051 } 3052 3053 if (scf_value_get_as_string(ud_val, ud_oldtarg, 3054 max_scf_value_len + 1) < 0) 3055 bad_error("scf_value_get_as_string", scf_error()); 3056 3057 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 3058 0) { 3059 switch (scf_error()) { 3060 case SCF_ERROR_NOT_FOUND: 3061 return (0); 3062 3063 case SCF_ERROR_CONNECTION_BROKEN: 3064 return (scferror2errno(scf_error())); 3065 3066 case SCF_ERROR_DELETED: 3067 warn(emsg_pg_deleted, ient->sc_fmri, 3068 "dependents"); 3069 return (EBUSY); 3070 3071 case SCF_ERROR_INVALID_ARGUMENT: 3072 case SCF_ERROR_NOT_BOUND: 3073 case SCF_ERROR_HANDLE_MISMATCH: 3074 case SCF_ERROR_NOT_SET: 3075 default: 3076 bad_error("scf_pg_get_property", scf_error()); 3077 } 3078 } 3079 if (scf_property_get_value(ud_prop, ud_val) != 0) { 3080 switch (scf_error()) { 3081 case SCF_ERROR_NOT_FOUND: 3082 case SCF_ERROR_CONSTRAINT_VIOLATED: 3083 warn(cf_inval, ient->sc_fmri, ud_name); 3084 return (0); 3085 3086 case SCF_ERROR_DELETED: 3087 case SCF_ERROR_CONNECTION_BROKEN: 3088 return (scferror2errno(scf_error())); 3089 3090 case SCF_ERROR_HANDLE_MISMATCH: 3091 case SCF_ERROR_NOT_BOUND: 3092 case SCF_ERROR_NOT_SET: 3093 default: 3094 bad_error("scf_property_get_value", 3095 scf_error()); 3096 } 3097 } 3098 3099 ty = scf_value_type(ud_val); 3100 assert(ty != SCF_TYPE_INVALID); 3101 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3102 warn(cf_inval, ient->sc_fmri, ud_name); 3103 return (0); 3104 } 3105 3106 if (scf_value_get_as_string(ud_val, ud_ctarg, 3107 max_scf_value_len + 1) < 0) 3108 bad_error("scf_value_get_as_string", scf_error()); 3109 3110 r = fmri_equal(ud_ctarg, ud_oldtarg); 3111 switch (r) { 3112 case 1: 3113 break; 3114 3115 case 0: 3116 case -1: /* warn? */ 3117 warn(cf_newtarg, ient->sc_fmri, ud_name); 3118 return (0); 3119 3120 case -2: 3121 warn(li_corrupt, ient->sc_fmri); 3122 return (EBADF); 3123 3124 default: 3125 bad_error("fmri_equal", r); 3126 } 3127 3128 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3129 switch (scf_error()) { 3130 case SCF_ERROR_NOT_FOUND: 3131 warn(li_corrupt, ient->sc_fmri); 3132 return (EBADF); 3133 3134 case SCF_ERROR_DELETED: 3135 case SCF_ERROR_CONNECTION_BROKEN: 3136 return (scferror2errno(scf_error())); 3137 3138 case SCF_ERROR_NOT_BOUND: 3139 case SCF_ERROR_HANDLE_MISMATCH: 3140 case SCF_ERROR_INVALID_ARGUMENT: 3141 case SCF_ERROR_NOT_SET: 3142 default: 3143 bad_error("scf_snaplevel_get_pg", scf_error()); 3144 } 3145 } 3146 3147 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3148 snap_lastimport); 3149 switch (r) { 3150 case 0: 3151 break; 3152 3153 case ECANCELED: 3154 case ECONNABORTED: 3155 case ENOMEM: 3156 case EBADF: 3157 return (r); 3158 3159 default: 3160 bad_error("load_pg", r); 3161 } 3162 3163 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 3164 switch (serr) { 3165 case SCF_ERROR_NONE: 3166 break; 3167 3168 case SCF_ERROR_NO_MEMORY: 3169 internal_pgroup_free(old_dpt_pgroup); 3170 return (ENOMEM); 3171 3172 case SCF_ERROR_NOT_FOUND: 3173 internal_pgroup_free(old_dpt_pgroup); 3174 goto delprop; 3175 3176 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 3177 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 3178 default: 3179 bad_error("fmri_to_entity", serr); 3180 } 3181 3182 r = entity_get_running_pg(target_ent, tissvc, ud_name, 3183 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 3184 switch (r) { 3185 case 0: 3186 break; 3187 3188 case ECONNABORTED: 3189 internal_pgroup_free(old_dpt_pgroup); 3190 return (r); 3191 3192 case ECANCELED: 3193 case ENOENT: 3194 internal_pgroup_free(old_dpt_pgroup); 3195 goto delprop; 3196 3197 case EBADF: 3198 warn(r_no_lvl, ud_ctarg); 3199 internal_pgroup_free(old_dpt_pgroup); 3200 return (r); 3201 3202 case EINVAL: 3203 default: 3204 bad_error("entity_get_running_pg", r); 3205 } 3206 3207 /* load it */ 3208 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 3209 switch (r) { 3210 case 0: 3211 break; 3212 3213 case ECANCELED: 3214 internal_pgroup_free(old_dpt_pgroup); 3215 goto delprop; 3216 3217 case ECONNABORTED: 3218 case ENOMEM: 3219 case EBADF: 3220 internal_pgroup_free(old_dpt_pgroup); 3221 return (r); 3222 3223 default: 3224 bad_error("load_pg", r); 3225 } 3226 3227 /* compare property groups */ 3228 if (!pg_equal(old_dpt_pgroup, current_pg)) { 3229 warn(cf_newdpg, ient->sc_fmri, ud_name); 3230 internal_pgroup_free(old_dpt_pgroup); 3231 internal_pgroup_free(current_pg); 3232 return (0); 3233 } 3234 3235 internal_pgroup_free(old_dpt_pgroup); 3236 internal_pgroup_free(current_pg); 3237 3238 if (g_verbose) 3239 warn(gettext("%s: Deleting dependent \"%s\".\n"), 3240 ient->sc_fmri, ud_name); 3241 3242 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 3243 switch (scf_error()) { 3244 case SCF_ERROR_NOT_FOUND: 3245 case SCF_ERROR_DELETED: 3246 internal_pgroup_free(old_dpt_pgroup); 3247 goto delprop; 3248 3249 case SCF_ERROR_CONNECTION_BROKEN: 3250 internal_pgroup_free(old_dpt_pgroup); 3251 return (ECONNABORTED); 3252 3253 case SCF_ERROR_NOT_SET: 3254 case SCF_ERROR_INVALID_ARGUMENT: 3255 case SCF_ERROR_HANDLE_MISMATCH: 3256 case SCF_ERROR_NOT_BOUND: 3257 default: 3258 bad_error("entity_get_pg", scf_error()); 3259 } 3260 } 3261 3262 if (scf_pg_delete(ud_pg) != 0) { 3263 switch (scf_error()) { 3264 case SCF_ERROR_DELETED: 3265 break; 3266 3267 case SCF_ERROR_CONNECTION_BROKEN: 3268 case SCF_ERROR_BACKEND_READONLY: 3269 case SCF_ERROR_BACKEND_ACCESS: 3270 return (scferror2errno(scf_error())); 3271 3272 case SCF_ERROR_PERMISSION_DENIED: 3273 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 3274 return (scferror2errno(scf_error())); 3275 3276 case SCF_ERROR_NOT_SET: 3277 default: 3278 bad_error("scf_pg_delete", scf_error()); 3279 } 3280 } 3281 3282 /* 3283 * This service was changed, so it must be refreshed. But 3284 * since it's not mentioned in the new manifest, we have to 3285 * record its FMRI here for use later. We record the name 3286 * & the entity (via sc_parent) in case we need to print error 3287 * messages during the refresh. 3288 */ 3289 dpt = internal_pgroup_new(); 3290 if (dpt == NULL) 3291 return (ENOMEM); 3292 dpt->sc_pgroup_name = strdup(ud_name); 3293 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 3294 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 3295 return (ENOMEM); 3296 dpt->sc_parent = (entity_t *)ient; 3297 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 3298 uu_die(gettext("libuutil error: %s\n"), 3299 uu_strerror(uu_error())); 3300 3301 delprop: 3302 if (tx == NULL) 3303 return (0); 3304 3305 ent = scf_entry_create(g_hndl); 3306 if (ent == NULL) 3307 return (ENOMEM); 3308 3309 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 3310 scf_entry_destroy(ent); 3311 switch (scf_error()) { 3312 case SCF_ERROR_DELETED: 3313 warn(emsg_pg_deleted, ient->sc_fmri, 3314 "dependents"); 3315 return (EBUSY); 3316 3317 case SCF_ERROR_CONNECTION_BROKEN: 3318 return (scferror2errno(scf_error())); 3319 3320 case SCF_ERROR_NOT_FOUND: 3321 break; 3322 3323 case SCF_ERROR_HANDLE_MISMATCH: 3324 case SCF_ERROR_NOT_BOUND: 3325 case SCF_ERROR_INVALID_ARGUMENT: 3326 case SCF_ERROR_NOT_SET: 3327 default: 3328 bad_error("scf_transaction_property_delete", 3329 scf_error()); 3330 } 3331 } 3332 3333 return (0); 3334 } 3335 3336 new_dpt_pgroup->sc_pgroup_seen = 1; 3337 3338 /* 3339 * Decide whether the dependent has changed in the manifest. 3340 */ 3341 /* Compare the target. */ 3342 if (scf_property_get_value(prop, ud_val) != 0) { 3343 switch (scf_error()) { 3344 case SCF_ERROR_NOT_FOUND: 3345 case SCF_ERROR_CONSTRAINT_VIOLATED: 3346 warn(li_corrupt, ient->sc_fmri); 3347 return (EBADF); 3348 3349 case SCF_ERROR_DELETED: 3350 case SCF_ERROR_CONNECTION_BROKEN: 3351 return (scferror2errno(scf_error())); 3352 3353 case SCF_ERROR_HANDLE_MISMATCH: 3354 case SCF_ERROR_NOT_BOUND: 3355 case SCF_ERROR_NOT_SET: 3356 default: 3357 bad_error("scf_property_get_value", scf_error()); 3358 } 3359 } 3360 3361 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 3362 0) 3363 bad_error("scf_value_get_as_string", scf_error()); 3364 3365 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 3366 switch (r) { 3367 case 0: 3368 break; 3369 3370 case 1: 3371 /* Compare the dependency pgs. */ 3372 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3373 switch (scf_error()) { 3374 case SCF_ERROR_NOT_FOUND: 3375 warn(li_corrupt, ient->sc_fmri); 3376 return (EBADF); 3377 3378 case SCF_ERROR_DELETED: 3379 case SCF_ERROR_CONNECTION_BROKEN: 3380 return (scferror2errno(scf_error())); 3381 3382 case SCF_ERROR_NOT_BOUND: 3383 case SCF_ERROR_HANDLE_MISMATCH: 3384 case SCF_ERROR_INVALID_ARGUMENT: 3385 case SCF_ERROR_NOT_SET: 3386 default: 3387 bad_error("scf_snaplevel_get_pg", scf_error()); 3388 } 3389 } 3390 3391 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3392 snap_lastimport); 3393 switch (r) { 3394 case 0: 3395 break; 3396 3397 case ECANCELED: 3398 case ECONNABORTED: 3399 case ENOMEM: 3400 case EBADF: 3401 return (r); 3402 3403 default: 3404 bad_error("load_pg", r); 3405 } 3406 3407 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 3408 /* no change, leave customizations */ 3409 internal_pgroup_free(old_dpt_pgroup); 3410 return (0); 3411 } 3412 break; 3413 3414 case -1: 3415 warn(li_corrupt, ient->sc_fmri); 3416 return (EBADF); 3417 3418 case -2: 3419 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 3420 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 3421 return (EINVAL); 3422 3423 default: 3424 bad_error("fmri_equal", r); 3425 } 3426 3427 /* 3428 * The dependent has changed in the manifest. Upgrade the current 3429 * properties if they haven't been customized. 3430 */ 3431 3432 /* 3433 * If new_dpt_pgroup->sc_override, then act as though the property 3434 * group hasn't been customized. 3435 */ 3436 if (new_dpt_pgroup->sc_pgroup_override) 3437 goto nocust; 3438 3439 if (!ud_run_dpts_pg_set) { 3440 warn(cf_missing, ient->sc_fmri, ud_name); 3441 r = 0; 3442 goto out; 3443 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 3444 switch (scf_error()) { 3445 case SCF_ERROR_NOT_FOUND: 3446 warn(cf_missing, ient->sc_fmri, ud_name); 3447 r = 0; 3448 goto out; 3449 3450 case SCF_ERROR_CONNECTION_BROKEN: 3451 r = scferror2errno(scf_error()); 3452 goto out; 3453 3454 case SCF_ERROR_DELETED: 3455 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 3456 r = EBUSY; 3457 goto out; 3458 3459 case SCF_ERROR_INVALID_ARGUMENT: 3460 case SCF_ERROR_NOT_BOUND: 3461 case SCF_ERROR_HANDLE_MISMATCH: 3462 case SCF_ERROR_NOT_SET: 3463 default: 3464 bad_error("scf_pg_get_property", scf_error()); 3465 } 3466 } 3467 3468 if (scf_property_get_value(ud_prop, ud_val) != 0) { 3469 switch (scf_error()) { 3470 case SCF_ERROR_NOT_FOUND: 3471 case SCF_ERROR_CONSTRAINT_VIOLATED: 3472 warn(cf_inval, ient->sc_fmri, ud_name); 3473 r = 0; 3474 goto out; 3475 3476 case SCF_ERROR_DELETED: 3477 case SCF_ERROR_CONNECTION_BROKEN: 3478 r = scferror2errno(scf_error()); 3479 goto out; 3480 3481 case SCF_ERROR_HANDLE_MISMATCH: 3482 case SCF_ERROR_NOT_BOUND: 3483 case SCF_ERROR_NOT_SET: 3484 default: 3485 bad_error("scf_property_get_value", scf_error()); 3486 } 3487 } 3488 3489 ty = scf_value_type(ud_val); 3490 assert(ty != SCF_TYPE_INVALID); 3491 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3492 warn(cf_inval, ient->sc_fmri, ud_name); 3493 r = 0; 3494 goto out; 3495 } 3496 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 3497 0) 3498 bad_error("scf_value_get_as_string", scf_error()); 3499 3500 r = fmri_equal(ud_ctarg, ud_oldtarg); 3501 if (r == -1) { 3502 warn(cf_inval, ient->sc_fmri, ud_name); 3503 r = 0; 3504 goto out; 3505 } else if (r == -2) { 3506 warn(li_corrupt, ient->sc_fmri); 3507 r = EBADF; 3508 goto out; 3509 } else if (r == 0) { 3510 /* 3511 * Target has been changed. Only abort now if it's been 3512 * changed to something other than what's in the manifest. 3513 */ 3514 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 3515 if (r == -1) { 3516 warn(cf_inval, ient->sc_fmri, ud_name); 3517 r = 0; 3518 goto out; 3519 } else if (r == 0) { 3520 warn(cf_newtarg, ient->sc_fmri, ud_name); 3521 r = 0; 3522 goto out; 3523 } else if (r != 1) { 3524 /* invalid sc_pgroup_fmri caught above */ 3525 bad_error("fmri_equal", r); 3526 } 3527 3528 /* 3529 * Fetch the current dependency pg. If it's what the manifest 3530 * says, then no problem. 3531 */ 3532 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 3533 switch (serr) { 3534 case SCF_ERROR_NONE: 3535 break; 3536 3537 case SCF_ERROR_NOT_FOUND: 3538 warn(cf_missing, ient->sc_fmri, ud_name); 3539 r = 0; 3540 goto out; 3541 3542 case SCF_ERROR_NO_MEMORY: 3543 r = ENOMEM; 3544 goto out; 3545 3546 case SCF_ERROR_CONSTRAINT_VIOLATED: 3547 case SCF_ERROR_INVALID_ARGUMENT: 3548 default: 3549 bad_error("fmri_to_entity", serr); 3550 } 3551 3552 r = entity_get_running_pg(target_ent, tissvc, ud_name, 3553 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 3554 switch (r) { 3555 case 0: 3556 break; 3557 3558 case ECONNABORTED: 3559 goto out; 3560 3561 case ECANCELED: 3562 case ENOENT: 3563 warn(cf_missing, ient->sc_fmri, ud_name); 3564 r = 0; 3565 goto out; 3566 3567 case EBADF: 3568 warn(r_no_lvl, ud_ctarg); 3569 goto out; 3570 3571 case EINVAL: 3572 default: 3573 bad_error("entity_get_running_pg", r); 3574 } 3575 3576 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 3577 switch (r) { 3578 case 0: 3579 break; 3580 3581 case ECANCELED: 3582 warn(cf_missing, ient->sc_fmri, ud_name); 3583 r = 0; 3584 goto out; 3585 3586 case ECONNABORTED: 3587 case ENOMEM: 3588 case EBADF: 3589 goto out; 3590 3591 default: 3592 bad_error("load_pg", r); 3593 } 3594 3595 if (!pg_equal(current_pg, new_dpt_pgroup)) 3596 warn(cf_newdpg, ient->sc_fmri, ud_name); 3597 internal_pgroup_free(current_pg); 3598 r = 0; 3599 goto out; 3600 } else if (r != 1) { 3601 bad_error("fmri_equal", r); 3602 } 3603 3604 nocust: 3605 /* 3606 * Target has not been customized. Check the dependency property 3607 * group. 3608 */ 3609 3610 if (old_dpt_pgroup == NULL) { 3611 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 3612 ud_pg) != 0) { 3613 switch (scf_error()) { 3614 case SCF_ERROR_NOT_FOUND: 3615 warn(li_corrupt, ient->sc_fmri); 3616 return (EBADF); 3617 3618 case SCF_ERROR_DELETED: 3619 case SCF_ERROR_CONNECTION_BROKEN: 3620 return (scferror2errno(scf_error())); 3621 3622 case SCF_ERROR_NOT_BOUND: 3623 case SCF_ERROR_HANDLE_MISMATCH: 3624 case SCF_ERROR_INVALID_ARGUMENT: 3625 case SCF_ERROR_NOT_SET: 3626 default: 3627 bad_error("scf_snaplevel_get_pg", scf_error()); 3628 } 3629 } 3630 3631 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3632 snap_lastimport); 3633 switch (r) { 3634 case 0: 3635 break; 3636 3637 case ECANCELED: 3638 case ECONNABORTED: 3639 case ENOMEM: 3640 case EBADF: 3641 return (r); 3642 3643 default: 3644 bad_error("load_pg", r); 3645 } 3646 } 3647 3648 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 3649 switch (serr) { 3650 case SCF_ERROR_NONE: 3651 break; 3652 3653 case SCF_ERROR_NOT_FOUND: 3654 warn(cf_missing, ient->sc_fmri, ud_name); 3655 r = 0; 3656 goto out; 3657 3658 case SCF_ERROR_NO_MEMORY: 3659 r = ENOMEM; 3660 goto out; 3661 3662 case SCF_ERROR_CONSTRAINT_VIOLATED: 3663 case SCF_ERROR_INVALID_ARGUMENT: 3664 default: 3665 bad_error("fmri_to_entity", serr); 3666 } 3667 3668 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 3669 ud_iter2, ud_inst, imp_snap, ud_snpl); 3670 switch (r) { 3671 case 0: 3672 break; 3673 3674 case ECONNABORTED: 3675 goto out; 3676 3677 case ECANCELED: 3678 case ENOENT: 3679 warn(cf_missing, ient->sc_fmri, ud_name); 3680 r = 0; 3681 goto out; 3682 3683 case EBADF: 3684 warn(r_no_lvl, ud_ctarg); 3685 goto out; 3686 3687 case EINVAL: 3688 default: 3689 bad_error("entity_get_running_pg", r); 3690 } 3691 3692 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 3693 switch (r) { 3694 case 0: 3695 break; 3696 3697 case ECANCELED: 3698 warn(cf_missing, ient->sc_fmri, ud_name); 3699 goto out; 3700 3701 case ECONNABORTED: 3702 case ENOMEM: 3703 case EBADF: 3704 goto out; 3705 3706 default: 3707 bad_error("load_pg", r); 3708 } 3709 3710 if (!pg_equal(current_pg, old_dpt_pgroup)) { 3711 if (!pg_equal(current_pg, new_dpt_pgroup)) 3712 warn(cf_newdpg, ient->sc_fmri, ud_name); 3713 internal_pgroup_free(current_pg); 3714 r = 0; 3715 goto out; 3716 } 3717 3718 /* Uncustomized. Upgrade. */ 3719 3720 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 3721 switch (r) { 3722 case 1: 3723 if (pg_equal(current_pg, new_dpt_pgroup)) { 3724 /* Already upgraded. */ 3725 internal_pgroup_free(current_pg); 3726 r = 0; 3727 goto out; 3728 } 3729 3730 internal_pgroup_free(current_pg); 3731 3732 /* upgrade current_pg */ 3733 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 3734 switch (scf_error()) { 3735 case SCF_ERROR_CONNECTION_BROKEN: 3736 r = scferror2errno(scf_error()); 3737 goto out; 3738 3739 case SCF_ERROR_DELETED: 3740 warn(cf_missing, ient->sc_fmri, ud_name); 3741 r = 0; 3742 goto out; 3743 3744 case SCF_ERROR_NOT_FOUND: 3745 break; 3746 3747 case SCF_ERROR_INVALID_ARGUMENT: 3748 case SCF_ERROR_NOT_BOUND: 3749 case SCF_ERROR_NOT_SET: 3750 case SCF_ERROR_HANDLE_MISMATCH: 3751 default: 3752 bad_error("entity_get_pg", scf_error()); 3753 } 3754 3755 if (tissvc) 3756 r = scf_service_add_pg(target_ent, ud_name, 3757 SCF_GROUP_DEPENDENCY, 0, ud_pg); 3758 else 3759 r = scf_instance_add_pg(target_ent, ud_name, 3760 SCF_GROUP_DEPENDENCY, 0, ud_pg); 3761 if (r != 0) { 3762 switch (scf_error()) { 3763 case SCF_ERROR_CONNECTION_BROKEN: 3764 case SCF_ERROR_NO_RESOURCES: 3765 case SCF_ERROR_BACKEND_READONLY: 3766 case SCF_ERROR_BACKEND_ACCESS: 3767 r = scferror2errno(scf_error()); 3768 goto out; 3769 3770 case SCF_ERROR_DELETED: 3771 warn(cf_missing, ient->sc_fmri, 3772 ud_name); 3773 r = 0; 3774 goto out; 3775 3776 case SCF_ERROR_PERMISSION_DENIED: 3777 warn(emsg_pg_deleted, ud_ctarg, 3778 ud_name); 3779 r = EPERM; 3780 goto out; 3781 3782 case SCF_ERROR_EXISTS: 3783 warn(emsg_pg_added, ud_ctarg, ud_name); 3784 r = EBUSY; 3785 goto out; 3786 3787 case SCF_ERROR_NOT_BOUND: 3788 case SCF_ERROR_HANDLE_MISMATCH: 3789 case SCF_ERROR_INVALID_ARGUMENT: 3790 case SCF_ERROR_NOT_SET: 3791 default: 3792 bad_error("entity_add_pg", scf_error()); 3793 } 3794 } 3795 } 3796 3797 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 3798 switch (r) { 3799 case 0: 3800 break; 3801 3802 case ECANCELED: 3803 warn(cf_missing, ient->sc_fmri, ud_name); 3804 goto out; 3805 3806 case ECONNABORTED: 3807 case ENOMEM: 3808 case EBADF: 3809 goto out; 3810 3811 default: 3812 bad_error("load_pg", r); 3813 } 3814 3815 if (g_verbose) 3816 warn(upgrading, ient->sc_fmri, ud_name); 3817 3818 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 3819 new_dpt_pgroup, 0, ient->sc_fmri); 3820 switch (r) { 3821 case 0: 3822 break; 3823 3824 case ECANCELED: 3825 warn(emsg_pg_deleted, ud_ctarg, ud_name); 3826 r = EBUSY; 3827 goto out; 3828 3829 case EPERM: 3830 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 3831 goto out; 3832 3833 case EBUSY: 3834 warn(emsg_pg_changed, ud_ctarg, ud_name); 3835 goto out; 3836 3837 case ECONNABORTED: 3838 case ENOMEM: 3839 case ENOSPC: 3840 case EROFS: 3841 case EACCES: 3842 case EINVAL: 3843 goto out; 3844 3845 default: 3846 bad_error("upgrade_pg", r); 3847 } 3848 break; 3849 3850 case 0: { 3851 scf_transaction_entry_t *ent; 3852 scf_value_t *val; 3853 3854 internal_pgroup_free(current_pg); 3855 3856 /* delete old pg */ 3857 if (g_verbose) 3858 warn(upgrading, ient->sc_fmri, ud_name); 3859 3860 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 3861 switch (scf_error()) { 3862 case SCF_ERROR_CONNECTION_BROKEN: 3863 r = scferror2errno(scf_error()); 3864 goto out; 3865 3866 case SCF_ERROR_DELETED: 3867 warn(cf_missing, ient->sc_fmri, ud_name); 3868 r = 0; 3869 goto out; 3870 3871 case SCF_ERROR_NOT_FOUND: 3872 break; 3873 3874 case SCF_ERROR_INVALID_ARGUMENT: 3875 case SCF_ERROR_NOT_BOUND: 3876 case SCF_ERROR_NOT_SET: 3877 case SCF_ERROR_HANDLE_MISMATCH: 3878 default: 3879 bad_error("entity_get_pg", scf_error()); 3880 } 3881 } else if (scf_pg_delete(ud_pg) != 0) { 3882 switch (scf_error()) { 3883 case SCF_ERROR_DELETED: 3884 break; 3885 3886 case SCF_ERROR_CONNECTION_BROKEN: 3887 case SCF_ERROR_BACKEND_READONLY: 3888 case SCF_ERROR_BACKEND_ACCESS: 3889 r = scferror2errno(scf_error()); 3890 goto out; 3891 3892 case SCF_ERROR_PERMISSION_DENIED: 3893 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 3894 r = scferror2errno(scf_error()); 3895 goto out; 3896 3897 case SCF_ERROR_NOT_SET: 3898 default: 3899 bad_error("scf_pg_delete", scf_error()); 3900 } 3901 } 3902 3903 /* import new one */ 3904 cbdata.sc_handle = g_hndl; 3905 cbdata.sc_trans = NULL; /* handled below */ 3906 3907 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3908 if (r != UU_WALK_NEXT) { 3909 if (r != UU_WALK_ERROR) 3910 bad_error("lscf_dependent_import", r); 3911 3912 r = cbdata.sc_err; 3913 goto out; 3914 } 3915 3916 if (tx == NULL) 3917 break; 3918 3919 if ((ent = scf_entry_create(g_hndl)) == NULL || 3920 (val = scf_value_create(g_hndl)) == NULL) { 3921 if (scf_error() == SCF_ERROR_NO_MEMORY) 3922 return (ENOMEM); 3923 3924 bad_error("scf_entry_create", scf_error()); 3925 } 3926 3927 if (scf_transaction_property_change_type(tx, ent, ud_name, 3928 SCF_TYPE_FMRI) != 0) { 3929 switch (scf_error()) { 3930 case SCF_ERROR_CONNECTION_BROKEN: 3931 r = scferror2errno(scf_error()); 3932 goto out; 3933 3934 case SCF_ERROR_DELETED: 3935 warn(emsg_pg_deleted, ient->sc_fmri, 3936 "dependents"); 3937 r = EBUSY; 3938 goto out; 3939 3940 case SCF_ERROR_NOT_FOUND: 3941 break; 3942 3943 case SCF_ERROR_NOT_BOUND: 3944 case SCF_ERROR_HANDLE_MISMATCH: 3945 case SCF_ERROR_INVALID_ARGUMENT: 3946 case SCF_ERROR_NOT_SET: 3947 default: 3948 bad_error("scf_transaction_property_" 3949 "change_type", scf_error()); 3950 } 3951 3952 if (scf_transaction_property_new(tx, ent, ud_name, 3953 SCF_TYPE_FMRI) != 0) { 3954 switch (scf_error()) { 3955 case SCF_ERROR_CONNECTION_BROKEN: 3956 r = scferror2errno(scf_error()); 3957 goto out; 3958 3959 case SCF_ERROR_DELETED: 3960 warn(emsg_pg_deleted, ient->sc_fmri, 3961 "dependents"); 3962 r = EBUSY; 3963 goto out; 3964 3965 case SCF_ERROR_EXISTS: 3966 warn(emsg_pg_changed, ient->sc_fmri, 3967 "dependents"); 3968 r = EBUSY; 3969 goto out; 3970 3971 case SCF_ERROR_INVALID_ARGUMENT: 3972 case SCF_ERROR_HANDLE_MISMATCH: 3973 case SCF_ERROR_NOT_BOUND: 3974 case SCF_ERROR_NOT_SET: 3975 default: 3976 bad_error("scf_transaction_property_" 3977 "new", scf_error()); 3978 } 3979 } 3980 } 3981 3982 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3983 new_dpt_pgroup->sc_pgroup_fmri) != 0) 3984 /* invalid sc_pgroup_fmri caught above */ 3985 bad_error("scf_value_set_from_string", 3986 scf_error()); 3987 3988 if (scf_entry_add_value(ent, val) != 0) 3989 bad_error("scf_entry_add_value", scf_error()); 3990 break; 3991 } 3992 3993 case -2: 3994 warn(li_corrupt, ient->sc_fmri); 3995 internal_pgroup_free(current_pg); 3996 r = EBADF; 3997 goto out; 3998 3999 case -1: 4000 default: 4001 /* invalid sc_pgroup_fmri caught above */ 4002 bad_error("fmri_equal", r); 4003 } 4004 4005 r = 0; 4006 4007 out: 4008 if (old_dpt_pgroup != NULL) 4009 internal_pgroup_free(old_dpt_pgroup); 4010 4011 return (r); 4012 } 4013 4014 /* 4015 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 4016 * would import it, except it seems to exist in the service anyway. Compare 4017 * the existent dependent with the one we would import, and report any 4018 * differences (if there are none, be silent). prop is the property which 4019 * represents the existent dependent (in the dependents property group) in the 4020 * entity corresponding to ient. 4021 * 4022 * Returns 4023 * 0 - success (Sort of. At least, we can continue importing.) 4024 * ECONNABORTED - repository connection broken 4025 * EBUSY - ancestor of prop was deleted (error printed) 4026 * ENOMEM - out of memory 4027 * EBADF - corrupt property group (error printed) 4028 * EINVAL - new_dpt_pgroup has invalid target (error printed) 4029 */ 4030 static int 4031 handle_dependent_conflict(const entity_t * const ient, 4032 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 4033 { 4034 int r; 4035 scf_type_t ty; 4036 scf_error_t scfe; 4037 void *tptr; 4038 int tissvc; 4039 pgroup_t *pgroup; 4040 4041 if (scf_property_get_value(prop, ud_val) != 0) { 4042 switch (scf_error()) { 4043 case SCF_ERROR_CONNECTION_BROKEN: 4044 return (scferror2errno(scf_error())); 4045 4046 case SCF_ERROR_DELETED: 4047 warn(emsg_pg_deleted, ient->sc_fmri, 4048 new_dpt_pgroup->sc_pgroup_name); 4049 return (EBUSY); 4050 4051 case SCF_ERROR_CONSTRAINT_VIOLATED: 4052 case SCF_ERROR_NOT_FOUND: 4053 warn(gettext("Conflict upgrading %s (not importing " 4054 "dependent \"%s\" because it already exists.) " 4055 "Warning: The \"%s/%2$s\" property has more or " 4056 "fewer than one value)).\n"), ient->sc_fmri, 4057 new_dpt_pgroup->sc_pgroup_name, "dependents"); 4058 return (0); 4059 4060 case SCF_ERROR_HANDLE_MISMATCH: 4061 case SCF_ERROR_NOT_BOUND: 4062 case SCF_ERROR_NOT_SET: 4063 default: 4064 bad_error("scf_property_get_value", 4065 scf_error()); 4066 } 4067 } 4068 4069 ty = scf_value_type(ud_val); 4070 assert(ty != SCF_TYPE_INVALID); 4071 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4072 warn(gettext("Conflict upgrading %s (not importing dependent " 4073 "\"%s\" because it already exists). Warning: The " 4074 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 4075 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 4076 scf_type_to_string(ty), "dependents"); 4077 return (0); 4078 } 4079 4080 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4081 0) 4082 bad_error("scf_value_get_as_string", scf_error()); 4083 4084 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4085 switch (r) { 4086 case 0: 4087 warn(gettext("Conflict upgrading %s (not importing dependent " 4088 "\"%s\" (target \"%s\") because it already exists with " 4089 "target \"%s\").\n"), ient->sc_fmri, 4090 new_dpt_pgroup->sc_pgroup_name, 4091 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 4092 return (0); 4093 4094 case 1: 4095 break; 4096 4097 case -1: 4098 warn(gettext("Conflict upgrading %s (not importing dependent " 4099 "\"%s\" because it already exists). Warning: The current " 4100 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 4101 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4102 return (0); 4103 4104 case -2: 4105 warn(gettext("Dependent \"%s\" of %s has invalid target " 4106 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 4107 new_dpt_pgroup->sc_pgroup_fmri); 4108 return (EINVAL); 4109 4110 default: 4111 bad_error("fmri_equal", r); 4112 } 4113 4114 /* compare dependency pgs in target */ 4115 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 4116 switch (scfe) { 4117 case SCF_ERROR_NONE: 4118 break; 4119 4120 case SCF_ERROR_NO_MEMORY: 4121 return (ENOMEM); 4122 4123 case SCF_ERROR_NOT_FOUND: 4124 warn(emsg_dpt_dangling, ient->sc_fmri, 4125 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4126 return (0); 4127 4128 case SCF_ERROR_CONSTRAINT_VIOLATED: 4129 case SCF_ERROR_INVALID_ARGUMENT: 4130 default: 4131 bad_error("fmri_to_entity", scfe); 4132 } 4133 4134 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 4135 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 4136 switch (r) { 4137 case 0: 4138 break; 4139 4140 case ECONNABORTED: 4141 return (r); 4142 4143 case ECANCELED: 4144 warn(emsg_dpt_dangling, ient->sc_fmri, 4145 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4146 return (0); 4147 4148 case EBADF: 4149 if (tissvc) 4150 warn(gettext("%s has an instance with a \"%s\" " 4151 "snapshot which is missing a snaplevel.\n"), 4152 ud_ctarg, "running"); 4153 else 4154 warn(gettext("%s has a \"%s\" snapshot which is " 4155 "missing a snaplevel.\n"), ud_ctarg, "running"); 4156 /* FALLTHROUGH */ 4157 4158 case ENOENT: 4159 warn(emsg_dpt_no_dep, ient->sc_fmri, 4160 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4161 new_dpt_pgroup->sc_pgroup_name); 4162 return (0); 4163 4164 case EINVAL: 4165 default: 4166 bad_error("entity_get_running_pg", r); 4167 } 4168 4169 pgroup = internal_pgroup_new(); 4170 if (pgroup == NULL) 4171 return (ENOMEM); 4172 4173 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 4174 switch (r) { 4175 case 0: 4176 break; 4177 4178 case ECONNABORTED: 4179 case EBADF: 4180 case ENOMEM: 4181 internal_pgroup_free(pgroup); 4182 return (r); 4183 4184 case ECANCELED: 4185 warn(emsg_dpt_no_dep, ient->sc_fmri, 4186 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4187 new_dpt_pgroup->sc_pgroup_name); 4188 internal_pgroup_free(pgroup); 4189 return (0); 4190 4191 default: 4192 bad_error("load_pg", r); 4193 } 4194 4195 /* report differences */ 4196 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 4197 internal_pgroup_free(pgroup); 4198 return (0); 4199 } 4200 4201 /* 4202 * lipg is a property group in the last-import snapshot of ent, which is an 4203 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 4204 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 4205 * in ents's property groups, compare and upgrade ent appropriately. 4206 * 4207 * Returns 4208 * 0 - success 4209 * ECONNABORTED - repository connection broken 4210 * ENOMEM - out of memory 4211 * ENOSPC - configd is out of resources 4212 * EINVAL - ient has invalid dependent (error printed) 4213 * - ient has invalid pgroup_t (error printed) 4214 * ECANCELED - ent has been deleted 4215 * ENODEV - entity containing lipg has been deleted 4216 * - entity containing running has been deleted 4217 * EPERM - could not delete pg (permission denied) (error printed) 4218 * - couldn't upgrade dependents (permission denied) (error printed) 4219 * - couldn't import pg (permission denied) (error printed) 4220 * - couldn't upgrade pg (permission denied) (error printed) 4221 * EROFS - could not delete pg (repository read-only) 4222 * - couldn't upgrade dependents (repository read-only) 4223 * - couldn't import pg (repository read-only) 4224 * - couldn't upgrade pg (repository read-only) 4225 * EACCES - could not delete pg (backend access denied) 4226 * - couldn't upgrade dependents (backend access denied) 4227 * - couldn't import pg (backend access denied) 4228 * - couldn't upgrade pg (backend access denied) 4229 * EBUSY - property group was added (error printed) 4230 * - property group was deleted (error printed) 4231 * - property group changed (error printed) 4232 * - "dependents" pg was added, changed, or deleted (error printed) 4233 * - dependent target deleted (error printed) 4234 * - dependent pg changed (error printed) 4235 * EBADF - imp_snpl is corrupt (error printed) 4236 * - ent has bad pg (error printed) 4237 * EEXIST - dependent collision in target service (error printed) 4238 */ 4239 static int 4240 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 4241 const scf_snaplevel_t *running) 4242 { 4243 int r; 4244 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 4245 scf_callback_t cbdata; 4246 4247 const char * const cf_pg_missing = 4248 gettext("Conflict upgrading %s (property group %s is missing)\n"); 4249 const char * const deleting = 4250 gettext("%s: Deleting property group \"%s\".\n"); 4251 4252 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 4253 4254 /* Skip dependent property groups. */ 4255 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 4256 switch (scf_error()) { 4257 case SCF_ERROR_DELETED: 4258 return (ENODEV); 4259 4260 case SCF_ERROR_CONNECTION_BROKEN: 4261 return (ECONNABORTED); 4262 4263 case SCF_ERROR_NOT_SET: 4264 case SCF_ERROR_NOT_BOUND: 4265 default: 4266 bad_error("scf_pg_get_type", scf_error()); 4267 } 4268 } 4269 4270 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 4271 if (scf_pg_get_property(lipg, "external", NULL) == 0) 4272 return (0); 4273 4274 switch (scf_error()) { 4275 case SCF_ERROR_NOT_FOUND: 4276 break; 4277 4278 case SCF_ERROR_CONNECTION_BROKEN: 4279 return (ECONNABORTED); 4280 4281 case SCF_ERROR_DELETED: 4282 return (ENODEV); 4283 4284 case SCF_ERROR_INVALID_ARGUMENT: 4285 case SCF_ERROR_NOT_BOUND: 4286 case SCF_ERROR_HANDLE_MISMATCH: 4287 case SCF_ERROR_NOT_SET: 4288 default: 4289 bad_error("scf_pg_get_property", scf_error()); 4290 } 4291 } 4292 4293 /* lookup pg in new properties */ 4294 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 4295 switch (scf_error()) { 4296 case SCF_ERROR_DELETED: 4297 return (ENODEV); 4298 4299 case SCF_ERROR_CONNECTION_BROKEN: 4300 return (ECONNABORTED); 4301 4302 case SCF_ERROR_NOT_SET: 4303 case SCF_ERROR_NOT_BOUND: 4304 default: 4305 bad_error("scf_pg_get_name", scf_error()); 4306 } 4307 } 4308 4309 pgrp.sc_pgroup_name = imp_str; 4310 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 4311 4312 if (mpg != NULL) 4313 mpg->sc_pgroup_seen = 1; 4314 4315 /* Special handling for dependents */ 4316 if (strcmp(imp_str, "dependents") == 0) 4317 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 4318 4319 if (mpg == NULL || mpg->sc_pgroup_delete) { 4320 /* property group was deleted from manifest */ 4321 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 4322 switch (scf_error()) { 4323 case SCF_ERROR_NOT_FOUND: 4324 return (0); 4325 4326 case SCF_ERROR_DELETED: 4327 case SCF_ERROR_CONNECTION_BROKEN: 4328 return (scferror2errno(scf_error())); 4329 4330 case SCF_ERROR_INVALID_ARGUMENT: 4331 case SCF_ERROR_HANDLE_MISMATCH: 4332 case SCF_ERROR_NOT_BOUND: 4333 case SCF_ERROR_NOT_SET: 4334 default: 4335 bad_error("entity_get_pg", scf_error()); 4336 } 4337 } 4338 4339 if (mpg != NULL && mpg->sc_pgroup_delete) { 4340 if (g_verbose) 4341 warn(deleting, ient->sc_fmri, imp_str); 4342 if (scf_pg_delete(imp_pg2) == 0) 4343 return (0); 4344 4345 switch (scf_error()) { 4346 case SCF_ERROR_DELETED: 4347 return (0); 4348 4349 case SCF_ERROR_CONNECTION_BROKEN: 4350 case SCF_ERROR_BACKEND_READONLY: 4351 case SCF_ERROR_BACKEND_ACCESS: 4352 return (scferror2errno(scf_error())); 4353 4354 case SCF_ERROR_PERMISSION_DENIED: 4355 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 4356 return (scferror2errno(scf_error())); 4357 4358 case SCF_ERROR_NOT_SET: 4359 default: 4360 bad_error("scf_pg_delete", scf_error()); 4361 } 4362 } 4363 4364 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 4365 switch (r) { 4366 case 0: 4367 break; 4368 4369 case ECANCELED: 4370 return (ENODEV); 4371 4372 case ECONNABORTED: 4373 case ENOMEM: 4374 case EBADF: 4375 return (r); 4376 4377 default: 4378 bad_error("load_pg", r); 4379 } 4380 4381 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 4382 switch (r) { 4383 case 0: 4384 break; 4385 4386 case ECANCELED: 4387 case ECONNABORTED: 4388 case ENOMEM: 4389 case EBADF: 4390 internal_pgroup_free(lipg_i); 4391 return (r); 4392 4393 default: 4394 bad_error("load_pg", r); 4395 } 4396 4397 if (pg_equal(lipg_i, curpg_i)) { 4398 if (g_verbose) 4399 warn(deleting, ient->sc_fmri, imp_str); 4400 if (scf_pg_delete(imp_pg2) != 0) { 4401 switch (scf_error()) { 4402 case SCF_ERROR_DELETED: 4403 break; 4404 4405 case SCF_ERROR_CONNECTION_BROKEN: 4406 internal_pgroup_free(lipg_i); 4407 internal_pgroup_free(curpg_i); 4408 return (ECONNABORTED); 4409 4410 case SCF_ERROR_NOT_SET: 4411 case SCF_ERROR_NOT_BOUND: 4412 default: 4413 bad_error("scf_pg_delete", scf_error()); 4414 } 4415 } 4416 } else { 4417 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 4418 } 4419 4420 internal_pgroup_free(lipg_i); 4421 internal_pgroup_free(curpg_i); 4422 4423 return (0); 4424 } 4425 4426 /* 4427 * Only dependent pgs can have override set, and we skipped those 4428 * above. 4429 */ 4430 assert(!mpg->sc_pgroup_override); 4431 4432 /* compare */ 4433 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 4434 switch (r) { 4435 case 0: 4436 break; 4437 4438 case ECANCELED: 4439 return (ENODEV); 4440 4441 case ECONNABORTED: 4442 case EBADF: 4443 case ENOMEM: 4444 return (r); 4445 4446 default: 4447 bad_error("load_pg", r); 4448 } 4449 4450 if (pg_equal(mpg, lipg_i)) { 4451 /* The manifest pg has not changed. Move on. */ 4452 r = 0; 4453 goto out; 4454 } 4455 4456 /* upgrade current properties according to lipg & mpg */ 4457 if (running != NULL) 4458 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 4459 else 4460 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 4461 if (r != 0) { 4462 switch (scf_error()) { 4463 case SCF_ERROR_CONNECTION_BROKEN: 4464 r = scferror2errno(scf_error()); 4465 goto out; 4466 4467 case SCF_ERROR_DELETED: 4468 if (running != NULL) 4469 r = ENODEV; 4470 else 4471 r = ECANCELED; 4472 goto out; 4473 4474 case SCF_ERROR_NOT_FOUND: 4475 break; 4476 4477 case SCF_ERROR_INVALID_ARGUMENT: 4478 case SCF_ERROR_HANDLE_MISMATCH: 4479 case SCF_ERROR_NOT_BOUND: 4480 case SCF_ERROR_NOT_SET: 4481 default: 4482 bad_error("entity_get_pg", scf_error()); 4483 } 4484 4485 warn(cf_pg_missing, ient->sc_fmri, imp_str); 4486 4487 r = 0; 4488 goto out; 4489 } 4490 4491 r = load_pg_attrs(imp_pg2, &curpg_i); 4492 switch (r) { 4493 case 0: 4494 break; 4495 4496 case ECANCELED: 4497 warn(cf_pg_missing, ient->sc_fmri, imp_str); 4498 r = 0; 4499 goto out; 4500 4501 case ECONNABORTED: 4502 case ENOMEM: 4503 goto out; 4504 4505 default: 4506 bad_error("load_pg_attrs", r); 4507 } 4508 4509 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 4510 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 4511 internal_pgroup_free(curpg_i); 4512 r = 0; 4513 goto out; 4514 } 4515 4516 internal_pgroup_free(curpg_i); 4517 4518 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 4519 switch (r) { 4520 case 0: 4521 break; 4522 4523 case ECANCELED: 4524 warn(cf_pg_missing, ient->sc_fmri, imp_str); 4525 r = 0; 4526 goto out; 4527 4528 case ECONNABORTED: 4529 case EBADF: 4530 case ENOMEM: 4531 goto out; 4532 4533 default: 4534 bad_error("load_pg", r); 4535 } 4536 4537 if (pg_equal(lipg_i, curpg_i) && 4538 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 4539 int do_delete = 1; 4540 4541 if (g_verbose) 4542 warn(gettext("%s: Upgrading property group \"%s\".\n"), 4543 ient->sc_fmri, mpg->sc_pgroup_name); 4544 4545 internal_pgroup_free(curpg_i); 4546 4547 if (running != NULL && 4548 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 4549 switch (scf_error()) { 4550 case SCF_ERROR_DELETED: 4551 r = ECANCELED; 4552 goto out; 4553 4554 case SCF_ERROR_NOT_FOUND: 4555 do_delete = 0; 4556 break; 4557 4558 case SCF_ERROR_CONNECTION_BROKEN: 4559 r = scferror2errno(scf_error()); 4560 goto out; 4561 4562 case SCF_ERROR_HANDLE_MISMATCH: 4563 case SCF_ERROR_INVALID_ARGUMENT: 4564 case SCF_ERROR_NOT_SET: 4565 case SCF_ERROR_NOT_BOUND: 4566 default: 4567 bad_error("entity_get_pg", scf_error()); 4568 } 4569 } 4570 4571 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 4572 switch (scf_error()) { 4573 case SCF_ERROR_DELETED: 4574 break; 4575 4576 case SCF_ERROR_CONNECTION_BROKEN: 4577 case SCF_ERROR_BACKEND_READONLY: 4578 case SCF_ERROR_BACKEND_ACCESS: 4579 r = scferror2errno(scf_error()); 4580 goto out; 4581 4582 case SCF_ERROR_PERMISSION_DENIED: 4583 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 4584 ient->sc_fmri); 4585 r = scferror2errno(scf_error()); 4586 goto out; 4587 4588 case SCF_ERROR_NOT_SET: 4589 case SCF_ERROR_NOT_BOUND: 4590 default: 4591 bad_error("scf_pg_delete", scf_error()); 4592 } 4593 } 4594 4595 cbdata.sc_handle = g_hndl; 4596 cbdata.sc_parent = ent; 4597 cbdata.sc_service = issvc; 4598 cbdata.sc_flags = 0; 4599 cbdata.sc_source_fmri = ient->sc_fmri; 4600 cbdata.sc_target_fmri = ient->sc_fmri; 4601 4602 r = entity_pgroup_import(mpg, &cbdata); 4603 switch (r) { 4604 case UU_WALK_NEXT: 4605 r = 0; 4606 goto out; 4607 4608 case UU_WALK_ERROR: 4609 if (cbdata.sc_err == EEXIST) { 4610 warn(emsg_pg_added, ient->sc_fmri, 4611 mpg->sc_pgroup_name); 4612 r = EBUSY; 4613 } else { 4614 r = cbdata.sc_err; 4615 } 4616 goto out; 4617 4618 default: 4619 bad_error("entity_pgroup_import", r); 4620 } 4621 } 4622 4623 if (running != NULL && 4624 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 4625 switch (scf_error()) { 4626 case SCF_ERROR_CONNECTION_BROKEN: 4627 case SCF_ERROR_DELETED: 4628 r = scferror2errno(scf_error()); 4629 goto out; 4630 4631 case SCF_ERROR_NOT_FOUND: 4632 break; 4633 4634 case SCF_ERROR_HANDLE_MISMATCH: 4635 case SCF_ERROR_INVALID_ARGUMENT: 4636 case SCF_ERROR_NOT_SET: 4637 case SCF_ERROR_NOT_BOUND: 4638 default: 4639 bad_error("entity_get_pg", scf_error()); 4640 } 4641 4642 cbdata.sc_handle = g_hndl; 4643 cbdata.sc_parent = ent; 4644 cbdata.sc_service = issvc; 4645 cbdata.sc_flags = SCI_FORCE; 4646 cbdata.sc_source_fmri = ient->sc_fmri; 4647 cbdata.sc_target_fmri = ient->sc_fmri; 4648 4649 r = entity_pgroup_import(mpg, &cbdata); 4650 switch (r) { 4651 case UU_WALK_NEXT: 4652 r = 0; 4653 goto out; 4654 4655 case UU_WALK_ERROR: 4656 if (cbdata.sc_err == EEXIST) { 4657 warn(emsg_pg_added, ient->sc_fmri, 4658 mpg->sc_pgroup_name); 4659 r = EBUSY; 4660 } else { 4661 r = cbdata.sc_err; 4662 } 4663 goto out; 4664 4665 default: 4666 bad_error("entity_pgroup_import", r); 4667 } 4668 } 4669 4670 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 4671 internal_pgroup_free(curpg_i); 4672 switch (r) { 4673 case 0: 4674 ient->sc_import_state = IMPORT_PROP_BEGUN; 4675 break; 4676 4677 case ECANCELED: 4678 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 4679 r = EBUSY; 4680 break; 4681 4682 case EPERM: 4683 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 4684 break; 4685 4686 case EBUSY: 4687 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 4688 break; 4689 4690 case ECONNABORTED: 4691 case ENOMEM: 4692 case ENOSPC: 4693 case EROFS: 4694 case EACCES: 4695 case EINVAL: 4696 break; 4697 4698 default: 4699 bad_error("upgrade_pg", r); 4700 } 4701 4702 out: 4703 internal_pgroup_free(lipg_i); 4704 return (r); 4705 } 4706 4707 /* 4708 * Upgrade the properties of ent according to snpl & ient. 4709 * 4710 * Returns 4711 * 0 - success 4712 * ECONNABORTED - repository connection broken 4713 * ENOMEM - out of memory 4714 * ENOSPC - configd is out of resources 4715 * ECANCELED - ent was deleted 4716 * ENODEV - entity containing snpl was deleted 4717 * - entity containing running was deleted 4718 * EBADF - imp_snpl is corrupt (error printed) 4719 * - ent has corrupt pg (error printed) 4720 * - dependent has corrupt pg (error printed) 4721 * - dependent target has a corrupt snapshot (error printed) 4722 * EBUSY - pg was added, changed, or deleted (error printed) 4723 * - dependent target was deleted (error printed) 4724 * - dependent pg changed (error printed) 4725 * EINVAL - invalid property group name (error printed) 4726 * - invalid property name (error printed) 4727 * - invalid value (error printed) 4728 * - ient has invalid pgroup or dependent (error printed) 4729 * EPERM - could not create property group (permission denied) (error printed) 4730 * - could not modify property group (permission denied) (error printed) 4731 * - couldn't delete, upgrade, or import pg or dependent (error printed) 4732 * EROFS - could not create property group (repository read-only) 4733 * - couldn't delete, upgrade, or import pg or dependent 4734 * EACCES - could not create property group (backend access denied) 4735 * - couldn't delete, upgrade, or import pg or dependent 4736 * EEXIST - dependent collision in target service (error printed) 4737 */ 4738 static int 4739 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 4740 entity_t *ient) 4741 { 4742 pgroup_t *pg, *rpg; 4743 int r; 4744 uu_list_t *pgs = ient->sc_pgroups; 4745 4746 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 4747 4748 /* clear sc_sceen for pgs */ 4749 if (uu_list_walk(pgs, clear_int, 4750 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 4751 bad_error("uu_list_walk", uu_error()); 4752 4753 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 4754 switch (scf_error()) { 4755 case SCF_ERROR_DELETED: 4756 return (ENODEV); 4757 4758 case SCF_ERROR_CONNECTION_BROKEN: 4759 return (ECONNABORTED); 4760 4761 case SCF_ERROR_NOT_SET: 4762 case SCF_ERROR_NOT_BOUND: 4763 case SCF_ERROR_HANDLE_MISMATCH: 4764 default: 4765 bad_error("scf_iter_snaplevel_pgs", scf_error()); 4766 } 4767 } 4768 4769 for (;;) { 4770 r = scf_iter_next_pg(imp_up_iter, imp_pg); 4771 if (r == 0) 4772 break; 4773 if (r == 1) { 4774 r = process_old_pg(imp_pg, ient, ent, running); 4775 switch (r) { 4776 case 0: 4777 break; 4778 4779 case ECONNABORTED: 4780 case ENOMEM: 4781 case ENOSPC: 4782 case ECANCELED: 4783 case ENODEV: 4784 case EPERM: 4785 case EROFS: 4786 case EACCES: 4787 case EBADF: 4788 case EBUSY: 4789 case EINVAL: 4790 case EEXIST: 4791 return (r); 4792 4793 default: 4794 bad_error("process_old_pg", r); 4795 } 4796 continue; 4797 } 4798 if (r != -1) 4799 bad_error("scf_iter_next_pg", r); 4800 4801 switch (scf_error()) { 4802 case SCF_ERROR_DELETED: 4803 return (ENODEV); 4804 4805 case SCF_ERROR_CONNECTION_BROKEN: 4806 return (ECONNABORTED); 4807 4808 case SCF_ERROR_HANDLE_MISMATCH: 4809 case SCF_ERROR_NOT_BOUND: 4810 case SCF_ERROR_NOT_SET: 4811 case SCF_ERROR_INVALID_ARGUMENT: 4812 default: 4813 bad_error("scf_iter_next_pg", scf_error()); 4814 } 4815 } 4816 4817 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 4818 if (pg->sc_pgroup_seen) 4819 continue; 4820 4821 /* pg is new */ 4822 4823 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 4824 r = upgrade_dependents(NULL, imp_snpl, ient, running, 4825 ent); 4826 switch (r) { 4827 case 0: 4828 break; 4829 4830 case ECONNABORTED: 4831 case ENOMEM: 4832 case ENOSPC: 4833 case ECANCELED: 4834 case ENODEV: 4835 case EBADF: 4836 case EBUSY: 4837 case EINVAL: 4838 case EPERM: 4839 case EROFS: 4840 case EACCES: 4841 case EEXIST: 4842 return (r); 4843 4844 default: 4845 bad_error("upgrade_dependents", r); 4846 } 4847 continue; 4848 } 4849 4850 if (running != NULL) 4851 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 4852 imp_pg); 4853 else 4854 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 4855 imp_pg); 4856 if (r != 0) { 4857 scf_callback_t cbdata; 4858 4859 switch (scf_error()) { 4860 case SCF_ERROR_NOT_FOUND: 4861 break; 4862 4863 case SCF_ERROR_CONNECTION_BROKEN: 4864 return (scferror2errno(scf_error())); 4865 4866 case SCF_ERROR_DELETED: 4867 if (running != NULL) 4868 return (ENODEV); 4869 else 4870 return (scferror2errno(scf_error())); 4871 4872 case SCF_ERROR_INVALID_ARGUMENT: 4873 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 4874 pg->sc_pgroup_name); 4875 return (EINVAL); 4876 4877 case SCF_ERROR_NOT_SET: 4878 case SCF_ERROR_HANDLE_MISMATCH: 4879 case SCF_ERROR_NOT_BOUND: 4880 default: 4881 bad_error("entity_get_pg", scf_error()); 4882 } 4883 4884 /* User doesn't have pg, so import it. */ 4885 4886 cbdata.sc_handle = g_hndl; 4887 cbdata.sc_parent = ent; 4888 cbdata.sc_service = issvc; 4889 cbdata.sc_flags = SCI_FORCE; 4890 cbdata.sc_source_fmri = ient->sc_fmri; 4891 cbdata.sc_target_fmri = ient->sc_fmri; 4892 4893 r = entity_pgroup_import(pg, &cbdata); 4894 switch (r) { 4895 case UU_WALK_NEXT: 4896 ient->sc_import_state = IMPORT_PROP_BEGUN; 4897 continue; 4898 4899 case UU_WALK_ERROR: 4900 if (cbdata.sc_err == EEXIST) { 4901 warn(emsg_pg_added, ient->sc_fmri, 4902 pg->sc_pgroup_name); 4903 return (EBUSY); 4904 } 4905 return (cbdata.sc_err); 4906 4907 default: 4908 bad_error("entity_pgroup_import", r); 4909 } 4910 } 4911 4912 /* report differences between pg & current */ 4913 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 4914 switch (r) { 4915 case 0: 4916 break; 4917 4918 case ECANCELED: 4919 warn(emsg_pg_deleted, ient->sc_fmri, 4920 pg->sc_pgroup_name); 4921 return (EBUSY); 4922 4923 case ECONNABORTED: 4924 case EBADF: 4925 case ENOMEM: 4926 return (r); 4927 4928 default: 4929 bad_error("load_pg", r); 4930 } 4931 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 4932 internal_pgroup_free(rpg); 4933 rpg = NULL; 4934 } 4935 4936 return (0); 4937 } 4938 4939 /* 4940 * Create or update a snapshot of inst. Uses imp_snap. 4941 * 4942 * Returns 4943 * 0 - success 4944 * ECONNABORTED - repository connection broken 4945 * EPERM - permission denied 4946 * ENOSPC - configd is out of resources 4947 * ECANCELED - inst was deleted 4948 * -1 - unknown libscf error (message printed) 4949 */ 4950 static int 4951 take_snap(scf_instance_t *inst, const char *name) 4952 { 4953 again: 4954 if (scf_instance_get_snapshot(inst, name, imp_snap) == 0) { 4955 if (_scf_snapshot_take_attach(inst, imp_snap) != 0) { 4956 switch (scf_error()) { 4957 case SCF_ERROR_CONNECTION_BROKEN: 4958 case SCF_ERROR_PERMISSION_DENIED: 4959 case SCF_ERROR_NO_RESOURCES: 4960 return (scferror2errno(scf_error())); 4961 4962 case SCF_ERROR_NOT_SET: 4963 case SCF_ERROR_INVALID_ARGUMENT: 4964 default: 4965 bad_error("_scf_snapshot_take_attach", 4966 scf_error()); 4967 } 4968 } 4969 } else { 4970 switch (scf_error()) { 4971 case SCF_ERROR_NOT_FOUND: 4972 break; 4973 4974 case SCF_ERROR_DELETED: 4975 case SCF_ERROR_CONNECTION_BROKEN: 4976 return (scferror2errno(scf_error())); 4977 4978 case SCF_ERROR_HANDLE_MISMATCH: 4979 case SCF_ERROR_NOT_BOUND: 4980 case SCF_ERROR_INVALID_ARGUMENT: 4981 case SCF_ERROR_NOT_SET: 4982 default: 4983 bad_error("scf_instance_get_snapshot", scf_error()); 4984 } 4985 4986 if (_scf_snapshot_take_new(inst, name, imp_snap) != 0) { 4987 switch (scf_error()) { 4988 case SCF_ERROR_EXISTS: 4989 goto again; 4990 4991 case SCF_ERROR_CONNECTION_BROKEN: 4992 case SCF_ERROR_NO_RESOURCES: 4993 case SCF_ERROR_PERMISSION_DENIED: 4994 return (scferror2errno(scf_error())); 4995 4996 default: 4997 scfwarn(); 4998 return (-1); 4999 5000 case SCF_ERROR_NOT_SET: 5001 case SCF_ERROR_INVALID_ARGUMENT: 5002 case SCF_ERROR_HANDLE_MISMATCH: 5003 bad_error("_scf_snapshot_take_new", 5004 scf_error()); 5005 } 5006 } 5007 } 5008 5009 return (0); 5010 } 5011 5012 /* 5013 * Import an instance. If it doesn't exist, create it. If it has 5014 * a last-import snapshot, upgrade its properties. Finish by updating its 5015 * last-import snapshot. If it doesn't have a last-import snapshot then it 5016 * could have been created for a dependent tag in another manifest. Import the 5017 * new properties. If there's a conflict, don't override, like now? 5018 * 5019 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 5020 * lcbdata->sc_err to 5021 * ECONNABORTED - repository connection broken 5022 * ENOMEM - out of memory 5023 * ENOSPC - svc.configd is out of resources 5024 * EEXIST - dependency collision in dependent service (error printed) 5025 * EPERM - couldn't create temporary instance (permission denied) 5026 * - couldn't import into temporary instance (permission denied) 5027 * - couldn't take snapshot (permission denied) 5028 * - couldn't upgrade properties (permission denied) 5029 * - couldn't import properties (permission denied) 5030 * - couldn't import dependents (permission denied) 5031 * EROFS - couldn't create temporary instance (repository read-only) 5032 * - couldn't import into temporary instance (repository read-only) 5033 * - couldn't upgrade properties (repository read-only) 5034 * - couldn't import properties (repository read-only) 5035 * - couldn't import dependents (repository read-only) 5036 * EACCES - couldn't create temporary instance (backend access denied) 5037 * - couldn't import into temporary instance (backend access denied) 5038 * - couldn't upgrade properties (backend access denied) 5039 * - couldn't import properties (backend access denied) 5040 * - couldn't import dependents (backend access denied) 5041 * EINVAL - invalid instance name (error printed) 5042 * - invalid pgroup_t's (error printed) 5043 * - invalid dependents (error printed) 5044 * EBUSY - temporary service deleted (error printed) 5045 * - temporary instance deleted (error printed) 5046 * - temporary instance changed (error printed) 5047 * - temporary instance already exists (error printed) 5048 * - instance deleted (error printed) 5049 * EBADF - instance has corrupt last-import snapshot (error printed) 5050 * - instance is corrupt (error printed) 5051 * - dependent has corrupt pg (error printed) 5052 * - dependent target has a corrupt snapshot (error printed) 5053 * -1 - unknown libscf error (error printed) 5054 */ 5055 static int 5056 lscf_instance_import(void *v, void *pvt) 5057 { 5058 entity_t *inst = v; 5059 scf_callback_t ctx; 5060 scf_callback_t *lcbdata = pvt; 5061 scf_service_t *rsvc = lcbdata->sc_parent; 5062 int r; 5063 scf_snaplevel_t *running; 5064 int flags = lcbdata->sc_flags; 5065 5066 const char * const emsg_tdel = 5067 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 5068 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 5069 "changed unexpectedly.\n"); 5070 const char * const emsg_del = gettext("%s changed unexpectedly " 5071 "(instance \"%s\" was deleted.)\n"); 5072 const char * const emsg_badsnap = gettext( 5073 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 5074 5075 /* 5076 * prepare last-import snapshot: 5077 * create temporary instance (service was precreated) 5078 * populate with properties from bundle 5079 * take snapshot 5080 */ 5081 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 5082 switch (scf_error()) { 5083 case SCF_ERROR_CONNECTION_BROKEN: 5084 case SCF_ERROR_NO_RESOURCES: 5085 case SCF_ERROR_BACKEND_READONLY: 5086 case SCF_ERROR_BACKEND_ACCESS: 5087 return (stash_scferror(lcbdata)); 5088 5089 case SCF_ERROR_EXISTS: 5090 warn(gettext("Temporary service svc:/%s " 5091 "changed unexpectedly (instance \"%s\" added).\n"), 5092 imp_tsname, inst->sc_name); 5093 lcbdata->sc_err = EBUSY; 5094 return (UU_WALK_ERROR); 5095 5096 case SCF_ERROR_DELETED: 5097 warn(gettext("Temporary service svc:/%s " 5098 "was deleted unexpectedly.\n"), imp_tsname); 5099 lcbdata->sc_err = EBUSY; 5100 return (UU_WALK_ERROR); 5101 5102 case SCF_ERROR_INVALID_ARGUMENT: 5103 warn(gettext("Invalid instance name \"%s\".\n"), 5104 inst->sc_name); 5105 return (stash_scferror(lcbdata)); 5106 5107 case SCF_ERROR_PERMISSION_DENIED: 5108 warn(gettext("Could not create temporary instance " 5109 "\"%s\" in svc:/%s (permission denied).\n"), 5110 inst->sc_name, imp_tsname); 5111 return (stash_scferror(lcbdata)); 5112 5113 case SCF_ERROR_HANDLE_MISMATCH: 5114 case SCF_ERROR_NOT_BOUND: 5115 case SCF_ERROR_NOT_SET: 5116 default: 5117 bad_error("scf_service_add_instance", scf_error()); 5118 } 5119 } 5120 5121 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5122 inst->sc_name); 5123 if (r < 0) 5124 bad_error("snprintf", errno); 5125 5126 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 5127 lcbdata->sc_flags | SCI_NOENABLED); 5128 switch (r) { 5129 case 0: 5130 break; 5131 5132 case ECANCELED: 5133 warn(emsg_tdel, imp_tsname, inst->sc_name); 5134 lcbdata->sc_err = EBUSY; 5135 r = UU_WALK_ERROR; 5136 goto deltemp; 5137 5138 case EEXIST: 5139 warn(emsg_tchg, imp_tsname, inst->sc_name); 5140 lcbdata->sc_err = EBUSY; 5141 r = UU_WALK_ERROR; 5142 goto deltemp; 5143 5144 case ECONNABORTED: 5145 goto connaborted; 5146 5147 case ENOMEM: 5148 case ENOSPC: 5149 case EPERM: 5150 case EROFS: 5151 case EACCES: 5152 case EINVAL: 5153 case EBUSY: 5154 lcbdata->sc_err = r; 5155 r = UU_WALK_ERROR; 5156 goto deltemp; 5157 5158 default: 5159 bad_error("lscf_import_instance_pgs", r); 5160 } 5161 5162 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5163 inst->sc_name); 5164 if (r < 0) 5165 bad_error("snprintf", errno); 5166 5167 ctx.sc_handle = lcbdata->sc_handle; 5168 ctx.sc_parent = imp_tinst; 5169 ctx.sc_service = 0; 5170 ctx.sc_source_fmri = inst->sc_fmri; 5171 ctx.sc_target_fmri = imp_str; 5172 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 5173 UU_DEFAULT) != 0) { 5174 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5175 bad_error("uu_list_walk", uu_error()); 5176 5177 switch (ctx.sc_err) { 5178 case ECONNABORTED: 5179 goto connaborted; 5180 5181 case ECANCELED: 5182 warn(emsg_tdel, imp_tsname, inst->sc_name); 5183 lcbdata->sc_err = EBUSY; 5184 break; 5185 5186 case EEXIST: 5187 warn(emsg_tchg, imp_tsname, inst->sc_name); 5188 lcbdata->sc_err = EBUSY; 5189 break; 5190 5191 default: 5192 lcbdata->sc_err = ctx.sc_err; 5193 } 5194 r = UU_WALK_ERROR; 5195 goto deltemp; 5196 } 5197 5198 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 5199 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 5200 switch (scf_error()) { 5201 case SCF_ERROR_CONNECTION_BROKEN: 5202 goto connaborted; 5203 5204 case SCF_ERROR_NO_RESOURCES: 5205 r = stash_scferror(lcbdata); 5206 goto deltemp; 5207 5208 case SCF_ERROR_EXISTS: 5209 warn(emsg_tchg, imp_tsname, inst->sc_name); 5210 lcbdata->sc_err = EBUSY; 5211 r = UU_WALK_ERROR; 5212 goto deltemp; 5213 5214 case SCF_ERROR_PERMISSION_DENIED: 5215 warn(gettext("Could not take \"%s\" snapshot of %s " 5216 "(permission denied).\n"), snap_lastimport, 5217 imp_str); 5218 r = stash_scferror(lcbdata); 5219 goto deltemp; 5220 5221 default: 5222 scfwarn(); 5223 lcbdata->sc_err = -1; 5224 r = UU_WALK_ERROR; 5225 goto deltemp; 5226 5227 case SCF_ERROR_HANDLE_MISMATCH: 5228 case SCF_ERROR_INVALID_ARGUMENT: 5229 case SCF_ERROR_NOT_SET: 5230 bad_error("_scf_snapshot_take_new_named", scf_error()); 5231 } 5232 } 5233 5234 if (lcbdata->sc_flags & SCI_FRESH) 5235 goto fresh; 5236 5237 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 5238 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 5239 imp_lisnap) != 0) { 5240 switch (scf_error()) { 5241 case SCF_ERROR_DELETED: 5242 warn(emsg_del, inst->sc_parent->sc_fmri, 5243 inst->sc_name); 5244 lcbdata->sc_err = EBUSY; 5245 r = UU_WALK_ERROR; 5246 goto deltemp; 5247 5248 case SCF_ERROR_NOT_FOUND: 5249 flags |= SCI_FORCE; 5250 goto nosnap; 5251 5252 case SCF_ERROR_CONNECTION_BROKEN: 5253 goto connaborted; 5254 5255 case SCF_ERROR_INVALID_ARGUMENT: 5256 case SCF_ERROR_HANDLE_MISMATCH: 5257 case SCF_ERROR_NOT_BOUND: 5258 case SCF_ERROR_NOT_SET: 5259 default: 5260 bad_error("scf_instance_get_snapshot", 5261 scf_error()); 5262 } 5263 } 5264 5265 /* upgrade */ 5266 5267 /* 5268 * compare new properties with last-import properties 5269 * upgrade current properties 5270 */ 5271 /* clear sc_sceen for pgs */ 5272 if (uu_list_walk(inst->sc_pgroups, clear_int, 5273 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 5274 0) 5275 bad_error("uu_list_walk", uu_error()); 5276 5277 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 5278 switch (r) { 5279 case 0: 5280 break; 5281 5282 case ECONNABORTED: 5283 goto connaborted; 5284 5285 case ECANCELED: 5286 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5287 lcbdata->sc_err = EBUSY; 5288 r = UU_WALK_ERROR; 5289 goto deltemp; 5290 5291 case ENOENT: 5292 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 5293 lcbdata->sc_err = EBADF; 5294 r = UU_WALK_ERROR; 5295 goto deltemp; 5296 5297 default: 5298 bad_error("get_snaplevel", r); 5299 } 5300 5301 if (scf_instance_get_snapshot(imp_inst, snap_running, 5302 imp_rsnap) != 0) { 5303 switch (scf_error()) { 5304 case SCF_ERROR_DELETED: 5305 warn(emsg_del, inst->sc_parent->sc_fmri, 5306 inst->sc_name); 5307 lcbdata->sc_err = EBUSY; 5308 r = UU_WALK_ERROR; 5309 goto deltemp; 5310 5311 case SCF_ERROR_NOT_FOUND: 5312 break; 5313 5314 case SCF_ERROR_CONNECTION_BROKEN: 5315 goto connaborted; 5316 5317 case SCF_ERROR_INVALID_ARGUMENT: 5318 case SCF_ERROR_HANDLE_MISMATCH: 5319 case SCF_ERROR_NOT_BOUND: 5320 case SCF_ERROR_NOT_SET: 5321 default: 5322 bad_error("scf_instance_get_snapshot", 5323 scf_error()); 5324 } 5325 5326 running = NULL; 5327 } else { 5328 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 5329 switch (r) { 5330 case 0: 5331 running = imp_rsnpl; 5332 break; 5333 5334 case ECONNABORTED: 5335 goto connaborted; 5336 5337 case ECANCELED: 5338 warn(emsg_del, inst->sc_parent->sc_fmri, 5339 inst->sc_name); 5340 lcbdata->sc_err = EBUSY; 5341 r = UU_WALK_ERROR; 5342 goto deltemp; 5343 5344 case ENOENT: 5345 warn(emsg_badsnap, snap_running, inst->sc_fmri); 5346 lcbdata->sc_err = EBADF; 5347 r = UU_WALK_ERROR; 5348 goto deltemp; 5349 5350 default: 5351 bad_error("get_snaplevel", r); 5352 } 5353 } 5354 5355 r = upgrade_props(imp_inst, running, imp_snpl, inst); 5356 switch (r) { 5357 case 0: 5358 break; 5359 5360 case ECANCELED: 5361 case ENODEV: 5362 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5363 lcbdata->sc_err = EBUSY; 5364 r = UU_WALK_ERROR; 5365 goto deltemp; 5366 5367 case ECONNABORTED: 5368 goto connaborted; 5369 5370 case ENOMEM: 5371 case ENOSPC: 5372 case EBADF: 5373 case EBUSY: 5374 case EINVAL: 5375 case EPERM: 5376 case EROFS: 5377 case EACCES: 5378 case EEXIST: 5379 lcbdata->sc_err = r; 5380 r = UU_WALK_ERROR; 5381 goto deltemp; 5382 5383 default: 5384 bad_error("upgrade_props", r); 5385 } 5386 5387 inst->sc_import_state = IMPORT_PROP_DONE; 5388 } else { 5389 switch (scf_error()) { 5390 case SCF_ERROR_CONNECTION_BROKEN: 5391 goto connaborted; 5392 5393 case SCF_ERROR_NOT_FOUND: 5394 break; 5395 5396 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5397 case SCF_ERROR_HANDLE_MISMATCH: 5398 case SCF_ERROR_NOT_BOUND: 5399 case SCF_ERROR_NOT_SET: 5400 default: 5401 bad_error("scf_service_get_instance", scf_error()); 5402 } 5403 5404 fresh: 5405 /* create instance */ 5406 if (scf_service_add_instance(rsvc, inst->sc_name, 5407 imp_inst) != 0) { 5408 switch (scf_error()) { 5409 case SCF_ERROR_CONNECTION_BROKEN: 5410 goto connaborted; 5411 5412 case SCF_ERROR_NO_RESOURCES: 5413 case SCF_ERROR_BACKEND_READONLY: 5414 case SCF_ERROR_BACKEND_ACCESS: 5415 r = stash_scferror(lcbdata); 5416 goto deltemp; 5417 5418 case SCF_ERROR_EXISTS: 5419 warn(gettext("%s changed unexpectedly " 5420 "(instance \"%s\" added).\n"), 5421 inst->sc_parent->sc_fmri, inst->sc_name); 5422 lcbdata->sc_err = EBUSY; 5423 r = UU_WALK_ERROR; 5424 goto deltemp; 5425 5426 case SCF_ERROR_PERMISSION_DENIED: 5427 warn(gettext("Could not create \"%s\" instance " 5428 "in %s (permission denied).\n"), 5429 inst->sc_name, inst->sc_parent->sc_fmri); 5430 r = stash_scferror(lcbdata); 5431 goto deltemp; 5432 5433 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5434 case SCF_ERROR_HANDLE_MISMATCH: 5435 case SCF_ERROR_NOT_BOUND: 5436 case SCF_ERROR_NOT_SET: 5437 default: 5438 bad_error("scf_service_add_instance", 5439 scf_error()); 5440 } 5441 } 5442 5443 nosnap: 5444 /* 5445 * Create a last-import snapshot to serve as an attachment 5446 * point for the real one from the temporary instance. Since 5447 * the contents is irrelevant, take it now, while the instance 5448 * is empty, to minimize svc.configd's work. 5449 */ 5450 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 5451 imp_lisnap) != 0) { 5452 switch (scf_error()) { 5453 case SCF_ERROR_CONNECTION_BROKEN: 5454 goto connaborted; 5455 5456 case SCF_ERROR_NO_RESOURCES: 5457 r = stash_scferror(lcbdata); 5458 goto deltemp; 5459 5460 case SCF_ERROR_EXISTS: 5461 warn(gettext("%s changed unexpectedly " 5462 "(snapshot \"%s\" added).\n"), 5463 inst->sc_fmri, snap_lastimport); 5464 lcbdata->sc_err = EBUSY; 5465 r = UU_WALK_ERROR; 5466 goto deltemp; 5467 5468 case SCF_ERROR_PERMISSION_DENIED: 5469 warn(gettext("Could not take \"%s\" snapshot " 5470 "of %s (permission denied).\n"), 5471 snap_lastimport, inst->sc_fmri); 5472 r = stash_scferror(lcbdata); 5473 goto deltemp; 5474 5475 default: 5476 scfwarn(); 5477 lcbdata->sc_err = -1; 5478 r = UU_WALK_ERROR; 5479 goto deltemp; 5480 5481 case SCF_ERROR_NOT_SET: 5482 case SCF_ERROR_INVALID_ARGUMENT: 5483 case SCF_ERROR_HANDLE_MISMATCH: 5484 bad_error("_scf_snapshot_take_new", 5485 scf_error()); 5486 } 5487 } 5488 5489 if (li_only) 5490 goto lionly; 5491 5492 inst->sc_import_state = IMPORT_PROP_BEGUN; 5493 5494 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 5495 flags); 5496 switch (r) { 5497 case 0: 5498 break; 5499 5500 case ECONNABORTED: 5501 goto connaborted; 5502 5503 case ECANCELED: 5504 warn(gettext("%s changed unexpectedly " 5505 "(instance \"%s\" deleted).\n"), 5506 inst->sc_parent->sc_fmri, inst->sc_name); 5507 lcbdata->sc_err = EBUSY; 5508 r = UU_WALK_ERROR; 5509 goto deltemp; 5510 5511 case EEXIST: 5512 warn(gettext("%s changed unexpectedly " 5513 "(property group added).\n"), inst->sc_fmri); 5514 lcbdata->sc_err = EBUSY; 5515 r = UU_WALK_ERROR; 5516 goto deltemp; 5517 5518 default: 5519 lcbdata->sc_err = r; 5520 r = UU_WALK_ERROR; 5521 goto deltemp; 5522 5523 case EINVAL: /* caught above */ 5524 bad_error("lscf_import_instance_pgs", r); 5525 } 5526 5527 ctx.sc_parent = imp_inst; 5528 ctx.sc_service = 0; 5529 ctx.sc_trans = NULL; 5530 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 5531 &ctx, UU_DEFAULT) != 0) { 5532 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5533 bad_error("uu_list_walk", uu_error()); 5534 5535 if (ctx.sc_err == ECONNABORTED) 5536 goto connaborted; 5537 lcbdata->sc_err = ctx.sc_err; 5538 r = UU_WALK_ERROR; 5539 goto deltemp; 5540 } 5541 5542 inst->sc_import_state = IMPORT_PROP_DONE; 5543 5544 if (g_verbose) 5545 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 5546 snap_initial, inst->sc_fmri); 5547 r = take_snap(imp_inst, snap_initial); 5548 switch (r) { 5549 case 0: 5550 break; 5551 5552 case ECONNABORTED: 5553 goto connaborted; 5554 5555 case ENOSPC: 5556 case -1: 5557 lcbdata->sc_err = r; 5558 r = UU_WALK_ERROR; 5559 goto deltemp; 5560 5561 case ECANCELED: 5562 warn(gettext("%s changed unexpectedly " 5563 "(instance %s deleted).\n"), 5564 inst->sc_parent->sc_fmri, inst->sc_name); 5565 lcbdata->sc_err = r; 5566 r = UU_WALK_ERROR; 5567 goto deltemp; 5568 5569 case EPERM: 5570 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 5571 lcbdata->sc_err = r; 5572 r = UU_WALK_ERROR; 5573 goto deltemp; 5574 5575 default: 5576 bad_error("take_snap", r); 5577 } 5578 } 5579 5580 lionly: 5581 /* transfer snapshot from temporary instance */ 5582 if (g_verbose) 5583 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 5584 snap_lastimport, inst->sc_fmri); 5585 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 5586 switch (scf_error()) { 5587 case SCF_ERROR_CONNECTION_BROKEN: 5588 goto connaborted; 5589 5590 case SCF_ERROR_NO_RESOURCES: 5591 r = stash_scferror(lcbdata); 5592 goto deltemp; 5593 5594 case SCF_ERROR_PERMISSION_DENIED: 5595 warn(gettext("Could not take \"%s\" snapshot for %s " 5596 "(permission denied).\n"), snap_lastimport, 5597 inst->sc_fmri); 5598 r = stash_scferror(lcbdata); 5599 goto deltemp; 5600 5601 case SCF_ERROR_NOT_SET: 5602 case SCF_ERROR_HANDLE_MISMATCH: 5603 default: 5604 bad_error("_scf_snapshot_attach", scf_error()); 5605 } 5606 } 5607 5608 inst->sc_import_state = IMPORT_COMPLETE; 5609 5610 r = UU_WALK_NEXT; 5611 5612 deltemp: 5613 /* delete temporary instance */ 5614 if (scf_instance_delete(imp_tinst) != 0) { 5615 switch (scf_error()) { 5616 case SCF_ERROR_DELETED: 5617 break; 5618 5619 case SCF_ERROR_CONNECTION_BROKEN: 5620 goto connaborted; 5621 5622 case SCF_ERROR_NOT_SET: 5623 case SCF_ERROR_NOT_BOUND: 5624 default: 5625 bad_error("scf_instance_delete", scf_error()); 5626 } 5627 } 5628 5629 return (r); 5630 5631 connaborted: 5632 warn(gettext("Could not delete svc:/%s:%s " 5633 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 5634 lcbdata->sc_err = ECONNABORTED; 5635 return (UU_WALK_ERROR); 5636 } 5637 5638 /* 5639 * If the service is missing, create it, import its properties, and import the 5640 * instances. Since the service is brand new, it should be empty, and if we 5641 * run into any existing entities (SCF_ERROR_EXISTS), abort. 5642 * 5643 * If the service exists, we want to upgrade its properties and import the 5644 * instances. Upgrade requires a last-import snapshot, though, which are 5645 * children of instances, so first we'll have to go through the instances 5646 * looking for a last-import snapshot. If we don't find one then we'll just 5647 * override-import the service properties (but don't delete existing 5648 * properties: another service might have declared us as a dependent). Before 5649 * we change anything, though, we want to take the previous snapshots. We 5650 * also give lscf_instance_import() a leg up on taking last-import snapshots 5651 * by importing the manifest's service properties into a temporary service. 5652 * 5653 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 5654 * sets lcbdata->sc_err to 5655 * ECONNABORTED - repository connection broken 5656 * ENOMEM - out of memory 5657 * ENOSPC - svc.configd is out of resources 5658 * EPERM - couldn't create temporary service (error printed) 5659 * - couldn't import into temp service (error printed) 5660 * - couldn't create service (error printed) 5661 * - couldn't import dependent (error printed) 5662 * - couldn't take snapshot (error printed) 5663 * - couldn't create instance (error printed) 5664 * - couldn't create, modify, or delete pg (error printed) 5665 * - couldn't create, modify, or delete dependent (error printed) 5666 * - couldn't import instance (error printed) 5667 * EROFS - couldn't create temporary service (repository read-only) 5668 * - couldn't import into temporary service (repository read-only) 5669 * - couldn't create service (repository read-only) 5670 * - couldn't import dependent (repository read-only) 5671 * - couldn't create instance (repository read-only) 5672 * - couldn't create, modify, or delete pg or dependent 5673 * - couldn't import instance (repository read-only) 5674 * EACCES - couldn't create temporary service (backend access denied) 5675 * - couldn't import into temporary service (backend access denied) 5676 * - couldn't create service (backend access denied) 5677 * - couldn't import dependent (backend access denied) 5678 * - couldn't create instance (backend access denied) 5679 * - couldn't create, modify, or delete pg or dependent 5680 * - couldn't import instance (backend access denied) 5681 * EINVAL - service name is invalid (error printed) 5682 * - service name is too long (error printed) 5683 * - s has invalid pgroup (error printed) 5684 * - s has invalid dependent (error printed) 5685 * - instance name is invalid (error printed) 5686 * - instance entity_t is invalid (error printed) 5687 * EEXIST - couldn't create temporary service (already exists) (error printed) 5688 * - couldn't import dependent (dependency pg already exists) (printed) 5689 * - dependency collision in dependent service (error printed) 5690 * EBUSY - temporary service deleted (error printed) 5691 * - property group added to temporary service (error printed) 5692 * - new property group changed or was deleted (error printed) 5693 * - service was added unexpectedly (error printed) 5694 * - service was deleted unexpectedly (error printed) 5695 * - property group added to new service (error printed) 5696 * - instance added unexpectedly (error printed) 5697 * - instance deleted unexpectedly (error printed) 5698 * - dependent service deleted unexpectedly (error printed) 5699 * - pg was added, changed, or deleted (error printed) 5700 * - dependent pg changed (error printed) 5701 * - temporary instance added, changed, or deleted (error printed) 5702 * EBADF - a last-import snapshot is corrupt (error printed) 5703 * - the service is corrupt (error printed) 5704 * - a dependent is corrupt (error printed) 5705 * - an instance is corrupt (error printed) 5706 * - an instance has a corrupt last-import snapshot (error printed) 5707 * - dependent target has a corrupt snapshot (error printed) 5708 * -1 - unknown libscf error (error printed) 5709 */ 5710 static int 5711 lscf_service_import(void *v, void *pvt) 5712 { 5713 entity_t *s = v; 5714 scf_callback_t cbdata; 5715 scf_callback_t *lcbdata = pvt; 5716 scf_scope_t *scope = lcbdata->sc_parent; 5717 entity_t *inst, linst; 5718 int r; 5719 int fresh = 0; 5720 scf_snaplevel_t *running; 5721 int have_ge; 5722 5723 const char * const ts_deleted = gettext("Temporary service svc:/%s " 5724 "was deleted unexpectedly.\n"); 5725 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 5726 "changed unexpectedly (property group added).\n"); 5727 const char * const s_deleted = 5728 gettext("%s was deleted unexpectedly.\n"); 5729 const char * const i_deleted = 5730 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 5731 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 5732 "is corrupt (missing service snaplevel).\n"); 5733 5734 /* Validate the service name */ 5735 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 5736 switch (scf_error()) { 5737 case SCF_ERROR_CONNECTION_BROKEN: 5738 return (stash_scferror(lcbdata)); 5739 5740 case SCF_ERROR_INVALID_ARGUMENT: 5741 warn(gettext("\"%s\" is an invalid service name. " 5742 "Cannot import.\n"), s->sc_name); 5743 return (stash_scferror(lcbdata)); 5744 5745 case SCF_ERROR_NOT_FOUND: 5746 break; 5747 5748 case SCF_ERROR_HANDLE_MISMATCH: 5749 case SCF_ERROR_NOT_BOUND: 5750 case SCF_ERROR_NOT_SET: 5751 default: 5752 bad_error("scf_scope_get_service", scf_error()); 5753 } 5754 } 5755 5756 /* create temporary service */ 5757 r = snprintf(imp_tsname, max_scf_name_len + 1, "TEMP/%s", s->sc_name); 5758 if (r < 0) 5759 bad_error("snprintf", errno); 5760 if (r > max_scf_name_len) { 5761 warn(gettext( 5762 "Service name \"%s\" is too long. Cannot import.\n"), 5763 s->sc_name); 5764 lcbdata->sc_err = EINVAL; 5765 return (UU_WALK_ERROR); 5766 } 5767 5768 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 5769 switch (scf_error()) { 5770 case SCF_ERROR_CONNECTION_BROKEN: 5771 case SCF_ERROR_NO_RESOURCES: 5772 case SCF_ERROR_BACKEND_READONLY: 5773 case SCF_ERROR_BACKEND_ACCESS: 5774 return (stash_scferror(lcbdata)); 5775 5776 case SCF_ERROR_EXISTS: 5777 warn(gettext( 5778 "Temporary service \"%s\" must be deleted before " 5779 "this manifest can be imported.\n"), imp_tsname); 5780 return (stash_scferror(lcbdata)); 5781 5782 case SCF_ERROR_PERMISSION_DENIED: 5783 warn(gettext("Could not create temporary service " 5784 "\"%s\" (permission denied).\n"), imp_tsname); 5785 return (stash_scferror(lcbdata)); 5786 5787 case SCF_ERROR_INVALID_ARGUMENT: 5788 case SCF_ERROR_HANDLE_MISMATCH: 5789 case SCF_ERROR_NOT_BOUND: 5790 case SCF_ERROR_NOT_SET: 5791 default: 5792 bad_error("scf_scope_add_service", scf_error()); 5793 } 5794 } 5795 5796 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 5797 if (r < 0) 5798 bad_error("snprintf", errno); 5799 5800 cbdata.sc_handle = lcbdata->sc_handle; 5801 cbdata.sc_parent = imp_tsvc; 5802 cbdata.sc_service = 1; 5803 cbdata.sc_source_fmri = s->sc_fmri; 5804 cbdata.sc_target_fmri = imp_str; 5805 5806 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 5807 UU_DEFAULT) != 0) { 5808 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5809 bad_error("uu_list_walk", uu_error()); 5810 5811 lcbdata->sc_err = cbdata.sc_err; 5812 switch (cbdata.sc_err) { 5813 case ECONNABORTED: 5814 goto connaborted; 5815 5816 case ECANCELED: 5817 warn(ts_deleted, imp_tsname); 5818 lcbdata->sc_err = EBUSY; 5819 return (UU_WALK_ERROR); 5820 5821 case EEXIST: 5822 warn(ts_pg_added, imp_tsname); 5823 lcbdata->sc_err = EBUSY; 5824 return (UU_WALK_ERROR); 5825 } 5826 5827 r = UU_WALK_ERROR; 5828 goto deltemp; 5829 } 5830 5831 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 5832 UU_DEFAULT) != 0) { 5833 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5834 bad_error("uu_list_walk", uu_error()); 5835 5836 lcbdata->sc_err = cbdata.sc_err; 5837 switch (cbdata.sc_err) { 5838 case ECONNABORTED: 5839 goto connaborted; 5840 5841 case ECANCELED: 5842 warn(ts_deleted, imp_tsname); 5843 lcbdata->sc_err = EBUSY; 5844 return (UU_WALK_ERROR); 5845 5846 case EEXIST: 5847 warn(ts_pg_added, imp_tsname); 5848 lcbdata->sc_err = EBUSY; 5849 return (UU_WALK_ERROR); 5850 } 5851 5852 r = UU_WALK_ERROR; 5853 goto deltemp; 5854 } 5855 5856 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 5857 switch (scf_error()) { 5858 case SCF_ERROR_NOT_FOUND: 5859 break; 5860 5861 case SCF_ERROR_CONNECTION_BROKEN: 5862 goto connaborted; 5863 5864 case SCF_ERROR_INVALID_ARGUMENT: 5865 case SCF_ERROR_HANDLE_MISMATCH: 5866 case SCF_ERROR_NOT_BOUND: 5867 case SCF_ERROR_NOT_SET: 5868 default: 5869 bad_error("scf_scope_get_service", scf_error()); 5870 } 5871 5872 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 5873 switch (scf_error()) { 5874 case SCF_ERROR_CONNECTION_BROKEN: 5875 goto connaborted; 5876 5877 case SCF_ERROR_NO_RESOURCES: 5878 case SCF_ERROR_BACKEND_READONLY: 5879 case SCF_ERROR_BACKEND_ACCESS: 5880 r = stash_scferror(lcbdata); 5881 goto deltemp; 5882 5883 case SCF_ERROR_EXISTS: 5884 warn(gettext("Scope \"%s\" changed unexpectedly" 5885 " (service \"%s\" added).\n"), 5886 SCF_SCOPE_LOCAL, s->sc_name); 5887 lcbdata->sc_err = EBUSY; 5888 goto deltemp; 5889 5890 case SCF_ERROR_PERMISSION_DENIED: 5891 warn(gettext("Could not create service \"%s\" " 5892 "(permission denied).\n"), s->sc_name); 5893 goto deltemp; 5894 5895 case SCF_ERROR_INVALID_ARGUMENT: 5896 case SCF_ERROR_HANDLE_MISMATCH: 5897 case SCF_ERROR_NOT_BOUND: 5898 case SCF_ERROR_NOT_SET: 5899 default: 5900 bad_error("scf_scope_add_service", scf_error()); 5901 } 5902 } 5903 5904 s->sc_import_state = IMPORT_PROP_BEGUN; 5905 5906 /* import service properties */ 5907 cbdata.sc_handle = lcbdata->sc_handle; 5908 cbdata.sc_parent = imp_svc; 5909 cbdata.sc_service = 1; 5910 cbdata.sc_flags = lcbdata->sc_flags; 5911 cbdata.sc_source_fmri = s->sc_fmri; 5912 cbdata.sc_target_fmri = s->sc_fmri; 5913 5914 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 5915 &cbdata, UU_DEFAULT) != 0) { 5916 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5917 bad_error("uu_list_walk", uu_error()); 5918 5919 lcbdata->sc_err = cbdata.sc_err; 5920 switch (cbdata.sc_err) { 5921 case ECONNABORTED: 5922 goto connaborted; 5923 5924 case ECANCELED: 5925 warn(s_deleted, s->sc_fmri); 5926 lcbdata->sc_err = EBUSY; 5927 return (UU_WALK_ERROR); 5928 5929 case EEXIST: 5930 warn(gettext("%s changed unexpectedly " 5931 "(property group added).\n"), s->sc_fmri); 5932 lcbdata->sc_err = EBUSY; 5933 return (UU_WALK_ERROR); 5934 5935 case EINVAL: 5936 /* caught above */ 5937 bad_error("entity_pgroup_import", 5938 cbdata.sc_err); 5939 } 5940 5941 r = UU_WALK_ERROR; 5942 goto deltemp; 5943 } 5944 5945 cbdata.sc_trans = NULL; 5946 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 5947 &cbdata, UU_DEFAULT) != 0) { 5948 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5949 bad_error("uu_list_walk", uu_error()); 5950 5951 lcbdata->sc_err = cbdata.sc_err; 5952 if (cbdata.sc_err == ECONNABORTED) 5953 goto connaborted; 5954 r = UU_WALK_ERROR; 5955 goto deltemp; 5956 } 5957 5958 s->sc_import_state = IMPORT_PROP_DONE; 5959 5960 /* 5961 * This is a new service, so we can't take previous snapshots 5962 * or upgrade service properties. 5963 */ 5964 fresh = 1; 5965 goto instances; 5966 } 5967 5968 /* Clear sc_seen for the instances. */ 5969 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 5970 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 5971 bad_error("uu_list_walk", uu_error()); 5972 5973 /* 5974 * Take previous snapshots for all instances. Even for ones not 5975 * mentioned in the bundle, since we might change their service 5976 * properties. 5977 */ 5978 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 5979 switch (scf_error()) { 5980 case SCF_ERROR_CONNECTION_BROKEN: 5981 goto connaborted; 5982 5983 case SCF_ERROR_DELETED: 5984 warn(s_deleted, s->sc_fmri); 5985 lcbdata->sc_err = EBUSY; 5986 r = UU_WALK_ERROR; 5987 goto deltemp; 5988 5989 case SCF_ERROR_HANDLE_MISMATCH: 5990 case SCF_ERROR_NOT_BOUND: 5991 case SCF_ERROR_NOT_SET: 5992 default: 5993 bad_error("scf_iter_service_instances", scf_error()); 5994 } 5995 } 5996 5997 for (;;) { 5998 r = scf_iter_next_instance(imp_iter, imp_inst); 5999 if (r == 0) 6000 break; 6001 if (r != 1) { 6002 switch (scf_error()) { 6003 case SCF_ERROR_DELETED: 6004 warn(s_deleted, s->sc_fmri); 6005 lcbdata->sc_err = EBUSY; 6006 r = UU_WALK_ERROR; 6007 goto deltemp; 6008 6009 case SCF_ERROR_CONNECTION_BROKEN: 6010 goto connaborted; 6011 6012 case SCF_ERROR_NOT_BOUND: 6013 case SCF_ERROR_HANDLE_MISMATCH: 6014 case SCF_ERROR_INVALID_ARGUMENT: 6015 case SCF_ERROR_NOT_SET: 6016 default: 6017 bad_error("scf_iter_next_instance", 6018 scf_error()); 6019 } 6020 } 6021 6022 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 6023 switch (scf_error()) { 6024 case SCF_ERROR_DELETED: 6025 continue; 6026 6027 case SCF_ERROR_CONNECTION_BROKEN: 6028 goto connaborted; 6029 6030 case SCF_ERROR_NOT_SET: 6031 case SCF_ERROR_NOT_BOUND: 6032 default: 6033 bad_error("scf_instance_get_name", scf_error()); 6034 } 6035 } 6036 6037 if (g_verbose) 6038 warn(gettext( 6039 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 6040 snap_previous, s->sc_name, imp_str); 6041 6042 r = take_snap(imp_inst, snap_previous); 6043 switch (r) { 6044 case 0: 6045 break; 6046 6047 case ECANCELED: 6048 continue; 6049 6050 case ECONNABORTED: 6051 goto connaborted; 6052 6053 case EPERM: 6054 warn(gettext("Could not take \"%s\" snapshot of " 6055 "svc:/%s:%s (permission denied).\n"), 6056 snap_previous, s->sc_name, imp_str); 6057 lcbdata->sc_err = r; 6058 return (UU_WALK_ERROR); 6059 6060 case ENOSPC: 6061 case -1: 6062 lcbdata->sc_err = r; 6063 r = UU_WALK_ERROR; 6064 goto deltemp; 6065 6066 default: 6067 bad_error("take_snap", r); 6068 } 6069 6070 linst.sc_name = imp_str; 6071 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 6072 &linst, NULL, NULL); 6073 if (inst != NULL) { 6074 inst->sc_import_state = IMPORT_PREVIOUS; 6075 inst->sc_seen = 1; 6076 } 6077 } 6078 6079 /* 6080 * Create the new instances and take previous snapshots of 6081 * them. This is not necessary, but it maximizes data preservation. 6082 */ 6083 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 6084 inst != NULL; 6085 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 6086 inst)) { 6087 if (inst->sc_seen) 6088 continue; 6089 6090 if (scf_service_add_instance(imp_svc, inst->sc_name, 6091 imp_inst) != 0) { 6092 switch (scf_error()) { 6093 case SCF_ERROR_CONNECTION_BROKEN: 6094 goto connaborted; 6095 6096 case SCF_ERROR_BACKEND_READONLY: 6097 case SCF_ERROR_BACKEND_ACCESS: 6098 case SCF_ERROR_NO_RESOURCES: 6099 r = stash_scferror(lcbdata); 6100 goto deltemp; 6101 6102 case SCF_ERROR_EXISTS: 6103 warn(gettext("%s changed unexpectedly " 6104 "(instance \"%s\" added).\n"), s->sc_fmri, 6105 inst->sc_name); 6106 lcbdata->sc_err = EBUSY; 6107 r = UU_WALK_ERROR; 6108 goto deltemp; 6109 6110 case SCF_ERROR_INVALID_ARGUMENT: 6111 warn(gettext("Service \"%s\" has instance with " 6112 "invalid name \"%s\".\n"), s->sc_name, 6113 inst->sc_name); 6114 r = stash_scferror(lcbdata); 6115 goto deltemp; 6116 6117 case SCF_ERROR_PERMISSION_DENIED: 6118 warn(gettext("Could not create instance \"%s\" " 6119 "in %s (permission denied).\n"), 6120 inst->sc_name, s->sc_fmri); 6121 r = stash_scferror(lcbdata); 6122 goto deltemp; 6123 6124 case SCF_ERROR_HANDLE_MISMATCH: 6125 case SCF_ERROR_NOT_BOUND: 6126 case SCF_ERROR_NOT_SET: 6127 default: 6128 bad_error("scf_service_add_instance", 6129 scf_error()); 6130 } 6131 } 6132 6133 if (g_verbose) 6134 warn(gettext("Taking \"%s\" snapshot for " 6135 "new service %s.\n"), snap_previous, inst->sc_fmri); 6136 r = take_snap(imp_inst, snap_previous); 6137 switch (r) { 6138 case 0: 6139 break; 6140 6141 case ECANCELED: 6142 warn(i_deleted, s->sc_fmri, inst->sc_name); 6143 lcbdata->sc_err = EBUSY; 6144 r = UU_WALK_ERROR; 6145 goto deltemp; 6146 6147 case ECONNABORTED: 6148 goto connaborted; 6149 6150 case EPERM: 6151 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 6152 lcbdata->sc_err = r; 6153 r = UU_WALK_ERROR; 6154 goto deltemp; 6155 6156 case ENOSPC: 6157 case -1: 6158 r = UU_WALK_ERROR; 6159 goto deltemp; 6160 6161 default: 6162 bad_error("take_snap", r); 6163 } 6164 } 6165 6166 s->sc_import_state = IMPORT_PREVIOUS; 6167 6168 /* 6169 * Upgrade service properties, if we can find a last-import snapshot. 6170 * Any will do because we don't support different service properties 6171 * in different manifests, so all snaplevels of the service in all of 6172 * the last-import snapshots of the instances should be the same. 6173 */ 6174 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6175 switch (scf_error()) { 6176 case SCF_ERROR_CONNECTION_BROKEN: 6177 goto connaborted; 6178 6179 case SCF_ERROR_DELETED: 6180 warn(s_deleted, s->sc_fmri); 6181 lcbdata->sc_err = EBUSY; 6182 r = UU_WALK_ERROR; 6183 goto deltemp; 6184 6185 case SCF_ERROR_HANDLE_MISMATCH: 6186 case SCF_ERROR_NOT_BOUND: 6187 case SCF_ERROR_NOT_SET: 6188 default: 6189 bad_error("scf_iter_service_instances", scf_error()); 6190 } 6191 } 6192 6193 have_ge = 0; 6194 li_only = 0; 6195 6196 for (;;) { 6197 r = scf_iter_next_instance(imp_iter, imp_inst); 6198 if (r == -1) { 6199 switch (scf_error()) { 6200 case SCF_ERROR_DELETED: 6201 warn(s_deleted, s->sc_fmri); 6202 lcbdata->sc_err = EBUSY; 6203 r = UU_WALK_ERROR; 6204 goto deltemp; 6205 6206 case SCF_ERROR_CONNECTION_BROKEN: 6207 goto connaborted; 6208 6209 case SCF_ERROR_NOT_BOUND: 6210 case SCF_ERROR_HANDLE_MISMATCH: 6211 case SCF_ERROR_INVALID_ARGUMENT: 6212 case SCF_ERROR_NOT_SET: 6213 default: 6214 bad_error("scf_iter_next_instance", 6215 scf_error()); 6216 } 6217 } 6218 6219 if (r == 0) { 6220 /* 6221 * Didn't find any last-import snapshots. Override- 6222 * import the properties. Unless one of the instances 6223 * has a general/enabled property, in which case we're 6224 * probably running a last-import-capable svccfg for 6225 * the first time, and we should only take the 6226 * last-import snapshot. 6227 */ 6228 if (have_ge) { 6229 li_only = 1; 6230 no_refresh = 1; 6231 break; 6232 } 6233 6234 s->sc_import_state = IMPORT_PROP_BEGUN; 6235 6236 cbdata.sc_handle = g_hndl; 6237 cbdata.sc_parent = imp_svc; 6238 cbdata.sc_service = 1; 6239 cbdata.sc_flags = SCI_FORCE; 6240 cbdata.sc_source_fmri = s->sc_fmri; 6241 cbdata.sc_target_fmri = s->sc_fmri; 6242 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6243 &cbdata, UU_DEFAULT) != 0) { 6244 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6245 bad_error("uu_list_walk", uu_error()); 6246 lcbdata->sc_err = cbdata.sc_err; 6247 switch (cbdata.sc_err) { 6248 case ECONNABORTED: 6249 goto connaborted; 6250 6251 case ECANCELED: 6252 warn(s_deleted, s->sc_fmri); 6253 lcbdata->sc_err = EBUSY; 6254 break; 6255 6256 case EINVAL: /* caught above */ 6257 case EEXIST: 6258 bad_error("entity_pgroup_import", 6259 cbdata.sc_err); 6260 } 6261 6262 r = UU_WALK_ERROR; 6263 goto deltemp; 6264 } 6265 6266 cbdata.sc_trans = NULL; 6267 if (uu_list_walk(s->sc_dependents, 6268 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 6269 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6270 bad_error("uu_list_walk", uu_error()); 6271 lcbdata->sc_err = cbdata.sc_err; 6272 if (cbdata.sc_err == ECONNABORTED) 6273 goto connaborted; 6274 r = UU_WALK_ERROR; 6275 goto deltemp; 6276 } 6277 break; 6278 } 6279 6280 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6281 imp_snap) != 0) { 6282 switch (scf_error()) { 6283 case SCF_ERROR_DELETED: 6284 continue; 6285 6286 case SCF_ERROR_NOT_FOUND: 6287 break; 6288 6289 case SCF_ERROR_CONNECTION_BROKEN: 6290 goto connaborted; 6291 6292 case SCF_ERROR_HANDLE_MISMATCH: 6293 case SCF_ERROR_NOT_BOUND: 6294 case SCF_ERROR_INVALID_ARGUMENT: 6295 case SCF_ERROR_NOT_SET: 6296 default: 6297 bad_error("scf_instance_get_snapshot", 6298 scf_error()); 6299 } 6300 6301 if (have_ge) 6302 continue; 6303 6304 /* 6305 * Check for a general/enabled property. This is how 6306 * we tell whether to import if there turn out to be 6307 * no last-import snapshots. 6308 */ 6309 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 6310 imp_pg) == 0) { 6311 if (scf_pg_get_property(imp_pg, 6312 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 6313 have_ge = 1; 6314 } else { 6315 switch (scf_error()) { 6316 case SCF_ERROR_DELETED: 6317 case SCF_ERROR_NOT_FOUND: 6318 continue; 6319 6320 case SCF_ERROR_INVALID_ARGUMENT: 6321 case SCF_ERROR_HANDLE_MISMATCH: 6322 case SCF_ERROR_CONNECTION_BROKEN: 6323 case SCF_ERROR_NOT_BOUND: 6324 case SCF_ERROR_NOT_SET: 6325 default: 6326 bad_error("scf_pg_get_property", 6327 scf_error()); 6328 } 6329 } 6330 } else { 6331 switch (scf_error()) { 6332 case SCF_ERROR_DELETED: 6333 case SCF_ERROR_NOT_FOUND: 6334 continue; 6335 6336 case SCF_ERROR_CONNECTION_BROKEN: 6337 goto connaborted; 6338 6339 case SCF_ERROR_NOT_BOUND: 6340 case SCF_ERROR_NOT_SET: 6341 case SCF_ERROR_INVALID_ARGUMENT: 6342 case SCF_ERROR_HANDLE_MISMATCH: 6343 default: 6344 bad_error("scf_instance_get_pg", 6345 scf_error()); 6346 } 6347 } 6348 continue; 6349 } 6350 6351 /* find service snaplevel */ 6352 r = get_snaplevel(imp_snap, 1, imp_snpl); 6353 switch (r) { 6354 case 0: 6355 break; 6356 6357 case ECONNABORTED: 6358 goto connaborted; 6359 6360 case ECANCELED: 6361 continue; 6362 6363 case ENOENT: 6364 if (scf_instance_get_name(imp_inst, imp_str, 6365 imp_str_sz) < 0) 6366 (void) strcpy(imp_str, "?"); 6367 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 6368 lcbdata->sc_err = EBADF; 6369 r = UU_WALK_ERROR; 6370 goto deltemp; 6371 6372 default: 6373 bad_error("get_snaplevel", r); 6374 } 6375 6376 if (scf_instance_get_snapshot(imp_inst, snap_running, 6377 imp_rsnap) != 0) { 6378 switch (scf_error()) { 6379 case SCF_ERROR_DELETED: 6380 continue; 6381 6382 case SCF_ERROR_NOT_FOUND: 6383 break; 6384 6385 case SCF_ERROR_CONNECTION_BROKEN: 6386 goto connaborted; 6387 6388 case SCF_ERROR_INVALID_ARGUMENT: 6389 case SCF_ERROR_HANDLE_MISMATCH: 6390 case SCF_ERROR_NOT_BOUND: 6391 case SCF_ERROR_NOT_SET: 6392 default: 6393 bad_error("scf_instance_get_snapshot", 6394 scf_error()); 6395 } 6396 running = NULL; 6397 } else { 6398 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 6399 switch (r) { 6400 case 0: 6401 running = imp_rsnpl; 6402 break; 6403 6404 case ECONNABORTED: 6405 goto connaborted; 6406 6407 case ECANCELED: 6408 continue; 6409 6410 case ENOENT: 6411 if (scf_instance_get_name(imp_inst, imp_str, 6412 imp_str_sz) < 0) 6413 (void) strcpy(imp_str, "?"); 6414 warn(badsnap, snap_running, s->sc_name, 6415 imp_str); 6416 lcbdata->sc_err = EBADF; 6417 r = UU_WALK_ERROR; 6418 goto deltemp; 6419 6420 default: 6421 bad_error("get_snaplevel", r); 6422 } 6423 } 6424 6425 if (g_verbose) { 6426 if (scf_instance_get_name(imp_inst, imp_str, 6427 imp_str_sz) < 0) 6428 (void) strcpy(imp_str, "?"); 6429 warn(gettext("Upgrading properties of %s according to " 6430 "instance \"%s\".\n"), s->sc_fmri, imp_str); 6431 } 6432 6433 /* upgrade service properties */ 6434 r = upgrade_props(imp_svc, running, imp_snpl, s); 6435 if (r == 0) 6436 break; 6437 6438 switch (r) { 6439 case ECONNABORTED: 6440 goto connaborted; 6441 6442 case ECANCELED: 6443 warn(s_deleted, s->sc_fmri); 6444 lcbdata->sc_err = EBUSY; 6445 break; 6446 6447 case ENODEV: 6448 if (scf_instance_get_name(imp_inst, imp_str, 6449 imp_str_sz) < 0) 6450 (void) strcpy(imp_str, "?"); 6451 warn(i_deleted, s->sc_fmri, imp_str); 6452 lcbdata->sc_err = EBUSY; 6453 break; 6454 6455 default: 6456 lcbdata->sc_err = r; 6457 } 6458 6459 r = UU_WALK_ERROR; 6460 goto deltemp; 6461 } 6462 6463 s->sc_import_state = IMPORT_PROP_DONE; 6464 6465 instances: 6466 /* import instances */ 6467 cbdata.sc_handle = lcbdata->sc_handle; 6468 cbdata.sc_parent = imp_svc; 6469 cbdata.sc_service = 1; 6470 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 6471 cbdata.sc_general = NULL; 6472 6473 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 6474 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 6475 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6476 bad_error("uu_list_walk", uu_error()); 6477 6478 lcbdata->sc_err = cbdata.sc_err; 6479 if (cbdata.sc_err == ECONNABORTED) 6480 goto connaborted; 6481 r = UU_WALK_ERROR; 6482 goto deltemp; 6483 } 6484 6485 s->sc_import_state = IMPORT_COMPLETE; 6486 r = UU_WALK_NEXT; 6487 6488 deltemp: 6489 /* delete temporary service */ 6490 if (scf_service_delete(imp_tsvc) != 0) { 6491 switch (scf_error()) { 6492 case SCF_ERROR_DELETED: 6493 break; 6494 6495 case SCF_ERROR_CONNECTION_BROKEN: 6496 goto connaborted; 6497 6498 case SCF_ERROR_EXISTS: 6499 warn(gettext( 6500 "Could not delete svc:/%s (instances exist).\n"), 6501 imp_tsname); 6502 break; 6503 6504 case SCF_ERROR_NOT_SET: 6505 case SCF_ERROR_NOT_BOUND: 6506 default: 6507 bad_error("scf_service_delete", scf_error()); 6508 } 6509 } 6510 6511 return (r); 6512 6513 connaborted: 6514 warn(gettext("Could not delete svc:/%s " 6515 "(repository connection broken).\n"), imp_tsname); 6516 lcbdata->sc_err = ECONNABORTED; 6517 return (UU_WALK_ERROR); 6518 } 6519 6520 static const char * 6521 import_progress(int st) 6522 { 6523 switch (st) { 6524 case 0: 6525 return (gettext("not reached.")); 6526 6527 case IMPORT_PREVIOUS: 6528 return (gettext("previous snapshot taken.")); 6529 6530 case IMPORT_PROP_BEGUN: 6531 return (gettext("some properties imported.")); 6532 6533 case IMPORT_PROP_DONE: 6534 return (gettext("properties imported.")); 6535 6536 case IMPORT_COMPLETE: 6537 return (gettext("imported.")); 6538 6539 case IMPORT_REFRESHED: 6540 return (gettext("refresh requested.")); 6541 6542 default: 6543 #ifndef NDEBUG 6544 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 6545 __FILE__, __LINE__, st); 6546 #endif 6547 abort(); 6548 /* NOTREACHED */ 6549 } 6550 } 6551 6552 /* 6553 * Returns 6554 * 0 - success 6555 * - fmri wasn't found (error printed) 6556 * - entity was deleted (error printed) 6557 * - backend denied access (error printed) 6558 * ENOMEM - out of memory (error printed) 6559 * ECONNABORTED - repository connection broken (error printed) 6560 * EPERM - permission denied (error printed) 6561 * -1 - unknown libscf error (error printed) 6562 */ 6563 static int 6564 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 6565 { 6566 scf_error_t serr; 6567 void *ent; 6568 int issvc; 6569 int r; 6570 6571 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 6572 const char *dpt_deleted = gettext("Could not refresh %s " 6573 "(dependent \"%s\" of %s) (deleted).\n"); 6574 6575 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 6576 switch (serr) { 6577 case SCF_ERROR_NONE: 6578 break; 6579 6580 case SCF_ERROR_NO_MEMORY: 6581 if (name == NULL) 6582 warn(gettext("Could not refresh %s (out of memory).\n"), 6583 fmri); 6584 else 6585 warn(gettext("Could not refresh %s " 6586 "(dependent \"%s\" of %s) (out of memory).\n"), 6587 fmri, name, d_fmri); 6588 return (ENOMEM); 6589 6590 case SCF_ERROR_NOT_FOUND: 6591 if (name == NULL) 6592 warn(deleted, fmri); 6593 else 6594 warn(dpt_deleted, fmri, name, d_fmri); 6595 return (0); 6596 6597 case SCF_ERROR_INVALID_ARGUMENT: 6598 case SCF_ERROR_CONSTRAINT_VIOLATED: 6599 default: 6600 bad_error("fmri_to_entity", serr); 6601 } 6602 6603 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 6604 switch (r) { 6605 case 0: 6606 break; 6607 6608 case ECONNABORTED: 6609 if (name != NULL) 6610 warn(gettext("Could not refresh %s " 6611 "(dependent \"%s\" of %s) " 6612 "(repository connection broken).\n"), fmri, name, 6613 d_fmri); 6614 return (r); 6615 6616 case ECANCELED: 6617 if (name == NULL) 6618 warn(deleted, fmri); 6619 else 6620 warn(dpt_deleted, fmri, name, d_fmri); 6621 return (0); 6622 6623 case EACCES: 6624 if (!g_verbose) 6625 return (0); 6626 if (name == NULL) 6627 warn(gettext("Could not refresh %s " 6628 "(backend access denied).\n"), fmri); 6629 else 6630 warn(gettext("Could not refresh %s " 6631 "(dependent \"%s\" of %s) " 6632 "(backend access denied).\n"), fmri, name, d_fmri); 6633 return (0); 6634 6635 case EPERM: 6636 if (name == NULL) 6637 warn(gettext("Could not refresh %s " 6638 "(permission denied).\n"), fmri); 6639 else 6640 warn(gettext("Could not refresh %s " 6641 "(dependent \"%s\" of %s) " 6642 "(permission denied).\n"), fmri, name, d_fmri); 6643 return (r); 6644 6645 case -1: 6646 scfwarn(); 6647 return (r); 6648 6649 default: 6650 bad_error("refresh_entity", r); 6651 } 6652 6653 if (issvc) 6654 scf_service_destroy(ent); 6655 else 6656 scf_instance_destroy(ent); 6657 6658 return (0); 6659 } 6660 6661 int 6662 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 6663 { 6664 scf_callback_t cbdata; 6665 int result = 0; 6666 entity_t *svc, *inst; 6667 uu_list_t *insts; 6668 int r; 6669 pgroup_t *old_dpt; 6670 void *cookie; 6671 6672 const char * const emsg_nomem = gettext("Out of memory.\n"); 6673 const char * const emsg_nores = 6674 gettext("svc.configd is out of resources.\n"); 6675 6676 lscf_prep_hndl(); 6677 6678 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 6679 max_scf_name_len : max_scf_fmri_len) + 1; 6680 6681 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 6682 (imp_svc = scf_service_create(g_hndl)) == NULL || 6683 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 6684 (imp_inst = scf_instance_create(g_hndl)) == NULL || 6685 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 6686 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 6687 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 6688 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 6689 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 6690 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 6691 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 6692 (imp_pg = scf_pg_create(g_hndl)) == NULL || 6693 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 6694 (imp_prop = scf_property_create(g_hndl)) == NULL || 6695 (imp_iter = scf_iter_create(g_hndl)) == NULL || 6696 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 6697 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 6698 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 6699 (imp_str = malloc(imp_str_sz)) == NULL || 6700 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 6701 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 6702 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 6703 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 6704 (ud_inst = scf_instance_create(g_hndl)) == NULL || 6705 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 6706 (ud_pg = scf_pg_create(g_hndl)) == NULL || 6707 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 6708 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 6709 (ud_prop = scf_property_create(g_hndl)) == NULL || 6710 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 6711 (ud_val = scf_value_create(g_hndl)) == NULL || 6712 (ud_iter = scf_iter_create(g_hndl)) == NULL || 6713 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 6714 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 6715 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 6716 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 6717 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 6718 if (scf_error() == SCF_ERROR_NO_RESOURCES) 6719 warn(emsg_nores); 6720 else 6721 warn(emsg_nomem); 6722 result = -1; 6723 goto out; 6724 } 6725 6726 r = load_init(); 6727 switch (r) { 6728 case 0: 6729 break; 6730 6731 case ENOMEM: 6732 warn(emsg_nomem); 6733 result = -1; 6734 goto out; 6735 6736 default: 6737 bad_error("load_init", r); 6738 } 6739 6740 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 6741 switch (scf_error()) { 6742 case SCF_ERROR_CONNECTION_BROKEN: 6743 warn(gettext("Repository connection broken.\n")); 6744 repository_teardown(); 6745 result = -1; 6746 goto out; 6747 6748 case SCF_ERROR_NOT_FOUND: 6749 case SCF_ERROR_INVALID_ARGUMENT: 6750 case SCF_ERROR_NOT_BOUND: 6751 case SCF_ERROR_HANDLE_MISMATCH: 6752 default: 6753 bad_error("scf_handle_get_scope", scf_error()); 6754 } 6755 } 6756 6757 /* 6758 * Clear the sc_import_state's of all services & instances so we can 6759 * report how far we got if we fail. 6760 */ 6761 for (svc = uu_list_first(bndl->sc_bundle_services); 6762 svc != NULL; 6763 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 6764 svc->sc_import_state = 0; 6765 6766 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 6767 clear_int, (void *)offsetof(entity_t, sc_import_state), 6768 UU_DEFAULT) != 0) 6769 bad_error("uu_list_walk", uu_error()); 6770 } 6771 6772 cbdata.sc_handle = g_hndl; 6773 cbdata.sc_parent = imp_scope; 6774 cbdata.sc_flags = flags; 6775 cbdata.sc_general = NULL; 6776 6777 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 6778 &cbdata, UU_DEFAULT) == 0) { 6779 /* Success. Refresh everything. */ 6780 6781 if (flags & SCI_NOREFRESH || no_refresh) { 6782 result = 0; 6783 goto out; 6784 } 6785 6786 for (svc = uu_list_first(bndl->sc_bundle_services); 6787 svc != NULL; 6788 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 6789 pgroup_t *dpt; 6790 6791 insts = svc->sc_u.sc_service.sc_service_instances; 6792 6793 for (inst = uu_list_first(insts); 6794 inst != NULL; 6795 inst = uu_list_next(insts, inst)) { 6796 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 6797 switch (r) { 6798 case 0: 6799 break; 6800 6801 case ENOMEM: 6802 case ECONNABORTED: 6803 case EPERM: 6804 case -1: 6805 goto progress; 6806 6807 default: 6808 bad_error("imp_refresh_fmri", r); 6809 } 6810 6811 inst->sc_import_state = IMPORT_REFRESHED; 6812 6813 for (dpt = uu_list_first(inst->sc_dependents); 6814 dpt != NULL; 6815 dpt = uu_list_next(inst->sc_dependents, 6816 dpt)) 6817 if (imp_refresh_fmri( 6818 dpt->sc_pgroup_fmri, 6819 dpt->sc_pgroup_name, 6820 inst->sc_fmri) != 0) 6821 goto progress; 6822 } 6823 6824 for (dpt = uu_list_first(svc->sc_dependents); 6825 dpt != NULL; 6826 dpt = uu_list_next(svc->sc_dependents, dpt)) 6827 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 6828 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 6829 goto progress; 6830 } 6831 6832 for (old_dpt = uu_list_first(imp_deleted_dpts); 6833 old_dpt != NULL; 6834 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 6835 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 6836 old_dpt->sc_pgroup_name, 6837 old_dpt->sc_parent->sc_fmri) != 0) 6838 goto progress; 6839 6840 result = 0; 6841 goto out; 6842 } 6843 6844 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6845 bad_error("uu_list_walk", uu_error()); 6846 6847 printerr: 6848 /* If the error hasn't been printed yet, do so here. */ 6849 switch (cbdata.sc_err) { 6850 case ECONNABORTED: 6851 warn(gettext("Repository connection broken.\n")); 6852 break; 6853 6854 case ENOMEM: 6855 warn(emsg_nomem); 6856 break; 6857 6858 case ENOSPC: 6859 warn(emsg_nores); 6860 break; 6861 6862 case EROFS: 6863 warn(gettext("Repository is read-only.\n")); 6864 break; 6865 6866 case EACCES: 6867 warn(gettext("Repository backend denied access.\n")); 6868 break; 6869 6870 case EPERM: 6871 case EINVAL: 6872 case EEXIST: 6873 case EBUSY: 6874 case EBADF: 6875 case -1: 6876 break; 6877 6878 default: 6879 bad_error("lscf_service_import", cbdata.sc_err); 6880 } 6881 6882 progress: 6883 warn(gettext("Import of %s failed. Progress:\n"), filename); 6884 6885 for (svc = uu_list_first(bndl->sc_bundle_services); 6886 svc != NULL; 6887 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 6888 insts = svc->sc_u.sc_service.sc_service_instances; 6889 6890 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 6891 import_progress(svc->sc_import_state)); 6892 6893 for (inst = uu_list_first(insts); 6894 inst != NULL; 6895 inst = uu_list_next(insts, inst)) 6896 warn(gettext(" Instance \"%s\": %s\n"), 6897 inst->sc_name, 6898 import_progress(inst->sc_import_state)); 6899 } 6900 6901 if (cbdata.sc_err == ECONNABORTED) 6902 repository_teardown(); 6903 6904 6905 result = -1; 6906 6907 out: 6908 load_fini(); 6909 6910 free(ud_ctarg); 6911 free(ud_oldtarg); 6912 free(ud_name); 6913 ud_ctarg = ud_oldtarg = ud_name = NULL; 6914 6915 scf_transaction_destroy(ud_tx); 6916 ud_tx = NULL; 6917 scf_iter_destroy(ud_iter); 6918 scf_iter_destroy(ud_iter2); 6919 ud_iter = ud_iter2 = NULL; 6920 scf_value_destroy(ud_val); 6921 ud_val = NULL; 6922 scf_property_destroy(ud_prop); 6923 scf_property_destroy(ud_dpt_prop); 6924 ud_prop = ud_dpt_prop = NULL; 6925 scf_pg_destroy(ud_pg); 6926 scf_pg_destroy(ud_cur_depts_pg); 6927 scf_pg_destroy(ud_run_dpts_pg); 6928 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 6929 scf_snaplevel_destroy(ud_snpl); 6930 ud_snpl = NULL; 6931 scf_instance_destroy(ud_inst); 6932 ud_inst = NULL; 6933 6934 free(imp_str); 6935 free(imp_tsname); 6936 free(imp_fe1); 6937 free(imp_fe2); 6938 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 6939 6940 cookie = NULL; 6941 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 6942 NULL) { 6943 free((char *)old_dpt->sc_pgroup_name); 6944 free((char *)old_dpt->sc_pgroup_fmri); 6945 internal_pgroup_free(old_dpt); 6946 } 6947 uu_list_destroy(imp_deleted_dpts); 6948 6949 scf_transaction_destroy(imp_tx); 6950 imp_tx = NULL; 6951 scf_iter_destroy(imp_iter); 6952 scf_iter_destroy(imp_rpg_iter); 6953 scf_iter_destroy(imp_up_iter); 6954 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 6955 scf_property_destroy(imp_prop); 6956 imp_prop = NULL; 6957 scf_pg_destroy(imp_pg); 6958 scf_pg_destroy(imp_pg2); 6959 imp_pg = imp_pg2 = NULL; 6960 scf_snaplevel_destroy(imp_snpl); 6961 scf_snaplevel_destroy(imp_rsnpl); 6962 imp_snpl = imp_rsnpl = NULL; 6963 scf_snapshot_destroy(imp_snap); 6964 scf_snapshot_destroy(imp_lisnap); 6965 scf_snapshot_destroy(imp_tlisnap); 6966 scf_snapshot_destroy(imp_rsnap); 6967 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 6968 scf_instance_destroy(imp_inst); 6969 scf_instance_destroy(imp_tinst); 6970 imp_inst = imp_tinst = NULL; 6971 scf_service_destroy(imp_svc); 6972 scf_service_destroy(imp_tsvc); 6973 imp_svc = imp_tsvc = NULL; 6974 scf_scope_destroy(imp_scope); 6975 imp_scope = NULL; 6976 6977 return (result); 6978 } 6979 6980 6981 /* 6982 * Returns 6983 * 0 - success 6984 * -1 - lscf_import_instance_pgs() failed. 6985 */ 6986 int 6987 lscf_bundle_apply(bundle_t *bndl) 6988 { 6989 entity_t *svc, *inst; 6990 scf_scope_t *rscope; 6991 scf_service_t *rsvc; 6992 scf_instance_t *rinst; 6993 int r; 6994 6995 lscf_prep_hndl(); 6996 6997 if ((rscope = scf_scope_create(g_hndl)) == NULL || 6998 (rsvc = scf_service_create(g_hndl)) == NULL || 6999 (rinst = scf_instance_create(g_hndl)) == NULL || 7000 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7001 (imp_tx = scf_transaction_create(g_hndl)) == NULL) 7002 scfdie(); 7003 7004 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0) 7005 scfdie(); 7006 7007 for (svc = uu_list_first(bndl->sc_bundle_services); 7008 svc != NULL; 7009 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7010 if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) { 7011 switch (scf_error()) { 7012 case SCF_ERROR_NOT_FOUND: 7013 if (g_verbose) 7014 warn(gettext("Ignoring nonexistent " 7015 "service %s.\n"), svc->sc_name); 7016 continue; 7017 7018 default: 7019 scfdie(); 7020 } 7021 } 7022 7023 for (inst = uu_list_first( 7024 svc->sc_u.sc_service.sc_service_instances); 7025 inst != NULL; 7026 inst = uu_list_next( 7027 svc->sc_u.sc_service.sc_service_instances, inst)) { 7028 if (scf_service_get_instance(rsvc, inst->sc_name, 7029 rinst) != 0) { 7030 switch (scf_error()) { 7031 case SCF_ERROR_NOT_FOUND: 7032 if (g_verbose) 7033 warn(gettext("Ignoring " 7034 "nonexistant instance " 7035 "%s:%s.\n"), 7036 inst->sc_parent->sc_name, 7037 inst->sc_name); 7038 continue; 7039 7040 default: 7041 scfdie(); 7042 } 7043 } 7044 7045 r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst, 7046 SCI_FORCE | SCI_KEEP); 7047 switch (r) { 7048 case 0: 7049 if (g_verbose) 7050 warn(gettext("%s updated.\n"), 7051 inst->sc_fmri); 7052 break; 7053 7054 case ECONNABORTED: 7055 warn(gettext("Could not update %s " 7056 "(repository connection broken).\n"), 7057 inst->sc_fmri); 7058 goto out; 7059 7060 case ENOMEM: 7061 warn(gettext("Could not update %s " 7062 "(out of memory).\n"), inst->sc_fmri); 7063 goto out; 7064 7065 case ENOSPC: 7066 warn(gettext("Could not update %s " 7067 "(repository server out of resources).\n"), 7068 inst->sc_fmri); 7069 goto out; 7070 7071 case ECANCELED: 7072 warn(gettext( 7073 "Could not update %s (deleted).\n"), 7074 inst->sc_fmri); 7075 break; 7076 7077 case EPERM: 7078 case EINVAL: 7079 case EBUSY: 7080 break; 7081 7082 case EROFS: 7083 warn(gettext("Could not update %s " 7084 "(repository read-only).\n"), 7085 inst->sc_fmri); 7086 goto out; 7087 7088 case EACCES: 7089 warn(gettext("Could not update %s " 7090 "(backend access denied).\n"), 7091 inst->sc_fmri); 7092 break; 7093 7094 case EEXIST: 7095 default: 7096 bad_error("lscf_import_instance_pgs", r); 7097 } 7098 } 7099 } 7100 7101 out: 7102 scf_transaction_destroy(imp_tx); 7103 imp_tx = NULL; 7104 scf_pg_destroy(imp_pg); 7105 imp_pg = NULL; 7106 7107 scf_instance_destroy(rinst); 7108 scf_service_destroy(rsvc); 7109 scf_scope_destroy(rscope); 7110 return (0); 7111 } 7112 7113 7114 /* 7115 * Export. These functions create and output an XML tree of a service 7116 * description from the repository. This is largely the inverse of 7117 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 7118 * 7119 * - We must include any properties which are not represented specifically by 7120 * a service manifest, e.g., properties created by an admin post-import. To 7121 * do so we'll iterate through all properties and deal with each 7122 * apropriately. 7123 * 7124 * - Children of services and instances must must be in the order set by the 7125 * DTD, but we iterate over the properties in undefined order. The elements 7126 * are not easily (or efficiently) sortable by name. Since there's a fixed 7127 * number of classes of them, however, we'll keep the classes separate and 7128 * assemble them in order. 7129 */ 7130 7131 /* 7132 * Convenience function to handle xmlSetProp errors (and type casting). 7133 */ 7134 static void 7135 safe_setprop(xmlNodePtr n, const char *name, const char *val) 7136 { 7137 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 7138 uu_die(gettext("Could not set XML property.\n")); 7139 } 7140 7141 /* 7142 * Convenience function to set an XML attribute to the single value of an 7143 * astring property. If the value happens to be the default, don't set the 7144 * attribute. "dval" should be the default value supplied by the DTD, or 7145 * NULL for no default. 7146 */ 7147 static int 7148 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 7149 const char *name, const char *dval) 7150 { 7151 scf_value_t *val; 7152 ssize_t len; 7153 char *str; 7154 7155 val = scf_value_create(g_hndl); 7156 if (val == NULL) 7157 scfdie(); 7158 7159 if (prop_get_val(prop, val) != 0) { 7160 scf_value_destroy(val); 7161 return (-1); 7162 } 7163 7164 len = scf_value_get_as_string(val, NULL, 0); 7165 if (len < 0) 7166 scfdie(); 7167 7168 str = safe_malloc(len + 1); 7169 7170 if (scf_value_get_as_string(val, str, len + 1) < 0) 7171 scfdie(); 7172 7173 scf_value_destroy(val); 7174 7175 if (dval == NULL || strcmp(str, dval) != 0) 7176 safe_setprop(n, name, str); 7177 7178 free(str); 7179 7180 return (0); 7181 } 7182 7183 /* 7184 * As above, but the attribute is always set. 7185 */ 7186 static int 7187 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 7188 { 7189 return (set_attr_from_prop_default(prop, n, name, NULL)); 7190 } 7191 7192 /* 7193 * Dump the given document onto f, with "'s replaced by ''s. 7194 */ 7195 static int 7196 write_service_bundle(xmlDocPtr doc, FILE *f) 7197 { 7198 xmlChar *mem; 7199 int sz, i; 7200 7201 mem = NULL; 7202 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 7203 7204 if (mem == NULL) { 7205 semerr(gettext("Could not dump XML tree.\n")); 7206 return (-1); 7207 } 7208 7209 /* 7210 * Fortunately libxml produces " instead of ", so we can blindly 7211 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 7212 * ' code?! 7213 */ 7214 for (i = 0; i < sz; ++i) { 7215 char c = (char)mem[i]; 7216 7217 if (c == '"') 7218 (void) fputc('\'', f); 7219 else if (c == '\'') 7220 (void) fwrite("'", sizeof ("'") - 1, 1, f); 7221 else 7222 (void) fputc(c, f); 7223 } 7224 7225 return (0); 7226 } 7227 7228 /* 7229 * Create the DOM elements in elts necessary to (generically) represent prop 7230 * (i.e., a property or propval element). If the name of the property is 7231 * known, it should be passed as name_arg. Otherwise, pass NULL. 7232 */ 7233 static void 7234 export_property(scf_property_t *prop, const char *name_arg, 7235 struct pg_elts *elts) 7236 { 7237 const char *type; 7238 scf_error_t err; 7239 xmlNodePtr pnode, lnode; 7240 char *lnname; 7241 int ret; 7242 7243 /* name */ 7244 if (name_arg != NULL) { 7245 (void) strcpy(exp_str, name_arg); 7246 } else { 7247 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 7248 scfdie(); 7249 } 7250 7251 /* type */ 7252 type = prop_to_typestr(prop); 7253 if (type == NULL) 7254 uu_die(gettext("Can't export property %s: unknown type.\n"), 7255 exp_str); 7256 7257 /* Is there a single value? */ 7258 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 7259 xmlNodePtr n; 7260 7261 /* Single value, so use propval */ 7262 n = xmlNewNode(NULL, (xmlChar *)"propval"); 7263 if (n == NULL) 7264 uu_die(emsg_create_xml); 7265 7266 safe_setprop(n, name_attr, exp_str); 7267 safe_setprop(n, type_attr, type); 7268 7269 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 7270 scfdie(); 7271 safe_setprop(n, value_attr, exp_str); 7272 7273 if (elts->propvals == NULL) 7274 elts->propvals = n; 7275 else 7276 (void) xmlAddSibling(elts->propvals, n); 7277 7278 return; 7279 } 7280 7281 err = scf_error(); 7282 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && err != SCF_ERROR_NOT_FOUND) 7283 scfdie(); 7284 7285 /* Multiple (or no) values, so use property */ 7286 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 7287 if (pnode == NULL) 7288 uu_die(emsg_create_xml); 7289 7290 safe_setprop(pnode, name_attr, exp_str); 7291 safe_setprop(pnode, type_attr, type); 7292 7293 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 7294 lnname = uu_msprintf("%s_list", type); 7295 if (lnname == NULL) 7296 uu_die(gettext("Could not create string")); 7297 7298 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 7299 if (lnode == NULL) 7300 uu_die(emsg_create_xml); 7301 7302 uu_free(lnname); 7303 7304 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 7305 scfdie(); 7306 7307 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 7308 1) { 7309 xmlNodePtr vn; 7310 7311 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 7312 NULL); 7313 if (vn == NULL) 7314 uu_die(emsg_create_xml); 7315 7316 if (scf_value_get_as_string(exp_val, exp_str, 7317 exp_str_sz) < 0) 7318 scfdie(); 7319 safe_setprop(vn, value_attr, exp_str); 7320 } 7321 if (ret != 0) 7322 scfdie(); 7323 } 7324 7325 if (elts->properties == NULL) 7326 elts->properties = pnode; 7327 else 7328 (void) xmlAddSibling(elts->properties, pnode); 7329 } 7330 7331 /* 7332 * Add a property_group element for this property group to elts. 7333 */ 7334 static void 7335 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts) 7336 { 7337 xmlNodePtr n; 7338 struct pg_elts elts; 7339 int ret; 7340 7341 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 7342 7343 /* name */ 7344 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7345 scfdie(); 7346 safe_setprop(n, name_attr, exp_str); 7347 7348 /* type */ 7349 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 7350 scfdie(); 7351 safe_setprop(n, type_attr, exp_str); 7352 7353 /* properties */ 7354 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7355 scfdie(); 7356 7357 (void) memset(&elts, 0, sizeof (elts)); 7358 7359 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7360 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7361 scfdie(); 7362 7363 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 7364 xmlNodePtr m; 7365 7366 m = xmlNewNode(NULL, (xmlChar *)"stability"); 7367 if (m == NULL) 7368 uu_die(emsg_create_xml); 7369 7370 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 7371 elts.stability = m; 7372 continue; 7373 } 7374 7375 xmlFreeNode(m); 7376 } 7377 7378 export_property(exp_prop, NULL, &elts); 7379 } 7380 if (ret == -1) 7381 scfdie(); 7382 7383 (void) xmlAddChild(n, elts.stability); 7384 (void) xmlAddChildList(n, elts.propvals); 7385 (void) xmlAddChildList(n, elts.properties); 7386 7387 if (eelts->property_groups == NULL) 7388 eelts->property_groups = n; 7389 else 7390 (void) xmlAddSibling(eelts->property_groups, n); 7391 } 7392 7393 /* 7394 * Create an XML node representing the dependency described by the given 7395 * property group and put it in eelts. Unless the dependency is not valid, in 7396 * which case create a generic property_group element which represents it and 7397 * put it in eelts. 7398 */ 7399 static void 7400 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 7401 { 7402 xmlNodePtr n; 7403 int err = 0, ret; 7404 struct pg_elts elts; 7405 7406 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 7407 if (n == NULL) 7408 uu_die(emsg_create_xml); 7409 7410 /* 7411 * If the external flag is present, skip this dependency because it 7412 * should have been created by another manifest. 7413 */ 7414 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 7415 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 7416 prop_get_val(exp_prop, exp_val) == 0) { 7417 uint8_t b; 7418 7419 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 7420 scfdie(); 7421 7422 if (b) 7423 return; 7424 } 7425 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 7426 scfdie(); 7427 7428 /* Get the required attributes. */ 7429 7430 /* name */ 7431 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7432 scfdie(); 7433 safe_setprop(n, name_attr, exp_str); 7434 7435 /* grouping */ 7436 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 7437 set_attr_from_prop(exp_prop, n, "grouping") != 0) 7438 err = 1; 7439 7440 /* restart_on */ 7441 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 7442 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 7443 err = 1; 7444 7445 /* type */ 7446 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 7447 set_attr_from_prop(exp_prop, n, type_attr) != 0) 7448 err = 1; 7449 7450 /* 7451 * entities: Not required, but if we create no children, it will be 7452 * created as empty on import, so fail if it's missing. 7453 */ 7454 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 7455 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 7456 scf_iter_t *eiter; 7457 int ret2; 7458 7459 eiter = scf_iter_create(g_hndl); 7460 if (eiter == NULL) 7461 scfdie(); 7462 7463 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 7464 scfdie(); 7465 7466 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 7467 xmlNodePtr ch; 7468 7469 if (scf_value_get_astring(exp_val, exp_str, 7470 exp_str_sz) < 0) 7471 scfdie(); 7472 7473 /* 7474 * service_fmri's must be first, so we can add them 7475 * here. 7476 */ 7477 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 7478 NULL); 7479 if (ch == NULL) 7480 uu_die(emsg_create_xml); 7481 7482 safe_setprop(ch, value_attr, exp_str); 7483 } 7484 if (ret2 == -1) 7485 scfdie(); 7486 7487 scf_iter_destroy(eiter); 7488 } else 7489 err = 1; 7490 7491 if (err) { 7492 xmlFreeNode(n); 7493 7494 export_pg(pg, eelts); 7495 7496 return; 7497 } 7498 7499 /* Iterate through the properties & handle each. */ 7500 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7501 scfdie(); 7502 7503 (void) memset(&elts, 0, sizeof (elts)); 7504 7505 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7506 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7507 scfdie(); 7508 7509 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 7510 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 7511 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 7512 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 7513 continue; 7514 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 7515 xmlNodePtr m; 7516 7517 m = xmlNewNode(NULL, (xmlChar *)"stability"); 7518 if (m == NULL) 7519 uu_die(emsg_create_xml); 7520 7521 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 7522 elts.stability = m; 7523 continue; 7524 } 7525 7526 xmlFreeNode(m); 7527 } 7528 7529 export_property(exp_prop, exp_str, &elts); 7530 } 7531 if (ret == -1) 7532 scfdie(); 7533 7534 (void) xmlAddChild(n, elts.stability); 7535 (void) xmlAddChildList(n, elts.propvals); 7536 (void) xmlAddChildList(n, elts.properties); 7537 7538 if (eelts->dependencies == NULL) 7539 eelts->dependencies = n; 7540 else 7541 (void) xmlAddSibling(eelts->dependencies, n); 7542 } 7543 7544 static xmlNodePtr 7545 export_method_environment(scf_propertygroup_t *pg) 7546 { 7547 xmlNodePtr env; 7548 int ret; 7549 int children = 0; 7550 7551 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 7552 return (NULL); 7553 7554 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 7555 if (env == NULL) 7556 uu_die(emsg_create_xml); 7557 7558 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 7559 scfdie(); 7560 7561 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 7562 scfdie(); 7563 7564 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 7565 xmlNodePtr ev; 7566 char *cp; 7567 7568 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 7569 scfdie(); 7570 7571 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 7572 warn(gettext("Invalid environment variable \"%s\".\n"), 7573 exp_str); 7574 continue; 7575 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 7576 warn(gettext("Invalid environment variable \"%s\"; " 7577 "\"SMF_\" prefix is reserved.\n"), exp_str); 7578 continue; 7579 } 7580 7581 *cp = '\0'; 7582 cp++; 7583 7584 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 7585 if (ev == NULL) 7586 uu_die(emsg_create_xml); 7587 7588 safe_setprop(ev, name_attr, exp_str); 7589 safe_setprop(ev, value_attr, cp); 7590 children++; 7591 } 7592 7593 if (ret != 0) 7594 scfdie(); 7595 7596 if (children == 0) { 7597 xmlFreeNode(env); 7598 return (NULL); 7599 } 7600 7601 return (env); 7602 } 7603 7604 /* 7605 * As above, but for a method property group. 7606 */ 7607 static void 7608 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 7609 { 7610 xmlNodePtr n, env; 7611 char *str; 7612 int err = 0, nonenv, ret; 7613 uint8_t use_profile; 7614 struct pg_elts elts; 7615 xmlNodePtr ctxt; 7616 7617 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 7618 7619 /* Get the required attributes. */ 7620 7621 /* name */ 7622 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7623 scfdie(); 7624 safe_setprop(n, name_attr, exp_str); 7625 7626 /* type */ 7627 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 7628 set_attr_from_prop(exp_prop, n, type_attr) != 0) 7629 err = 1; 7630 7631 /* exec */ 7632 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 7633 set_attr_from_prop(exp_prop, n, "exec") != 0) 7634 err = 1; 7635 7636 /* timeout */ 7637 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 7638 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 7639 prop_get_val(exp_prop, exp_val) == 0) { 7640 uint64_t c; 7641 7642 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 7643 scfdie(); 7644 7645 str = uu_msprintf("%llu", c); 7646 if (str == NULL) 7647 uu_die(gettext("Could not create string")); 7648 7649 safe_setprop(n, "timeout_seconds", str); 7650 free(str); 7651 } else 7652 err = 1; 7653 7654 if (err) { 7655 xmlFreeNode(n); 7656 7657 export_pg(pg, eelts); 7658 7659 return; 7660 } 7661 7662 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 7663 if (ctxt == NULL) 7664 uu_die(emsg_create_xml); 7665 7666 /* 7667 * If we're going to have a method_context child, we need to know 7668 * before we iterate through the properties. Since method_context's 7669 * are optional, we don't want to complain about any properties 7670 * missing if none of them are there. Thus we can't use the 7671 * convenience functions. 7672 */ 7673 nonenv = 7674 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 7675 SCF_SUCCESS || 7676 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 7677 SCF_SUCCESS || 7678 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 7679 SCF_SUCCESS || 7680 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 7681 SCF_SUCCESS; 7682 7683 if (nonenv) { 7684 /* 7685 * We only want to complain about profile or credential 7686 * properties if we will use them. To determine that we must 7687 * examine USE_PROFILE. 7688 */ 7689 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 7690 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 7691 prop_get_val(exp_prop, exp_val) == 0) { 7692 if (scf_value_get_boolean(exp_val, &use_profile) != 7693 SCF_SUCCESS) 7694 scfdie(); 7695 } else 7696 /* 7697 * USE_PROFILE is misconfigured. Since we should have 7698 * complained just now, we don't want to complain 7699 * about any of the other properties, so don't look 7700 * for them. 7701 */ 7702 nonenv = 0; 7703 } 7704 7705 if (nonenv) { 7706 7707 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) != 7708 0 || 7709 set_attr_from_prop_default(exp_prop, ctxt, 7710 "working_directory", ":default") != 0) 7711 err = 1; 7712 7713 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) != 0 || 7714 set_attr_from_prop_default(exp_prop, ctxt, "project", 7715 ":default") != 0) 7716 err = 1; 7717 7718 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) != 7719 0 || 7720 set_attr_from_prop_default(exp_prop, ctxt, 7721 "resource_pool", ":default") != 0) 7722 err = 1; 7723 7724 if (use_profile) { 7725 xmlNodePtr prof; 7726 7727 prof = xmlNewChild(ctxt, NULL, 7728 (xmlChar *)"method_profile", NULL); 7729 if (prof == NULL) 7730 uu_die(emsg_create_xml); 7731 7732 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, exp_prop) != 7733 0 || set_attr_from_prop(exp_prop, prof, 7734 name_attr) != 0) 7735 err = 1; 7736 } else { 7737 xmlNodePtr cred; 7738 7739 cred = xmlNewChild(ctxt, NULL, 7740 (xmlChar *)"method_credential", NULL); 7741 if (cred == NULL) 7742 uu_die(emsg_create_xml); 7743 7744 if (pg_get_prop(pg, SCF_PROPERTY_USER, exp_prop) != 0 || 7745 set_attr_from_prop(exp_prop, cred, "user") != 0) 7746 err = 1; 7747 7748 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, exp_prop) != 7749 0 || 7750 set_attr_from_prop_default(exp_prop, cred, 7751 "group", ":default") != 0) 7752 err = 1; 7753 7754 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 7755 exp_prop) != 0 || 7756 set_attr_from_prop_default(exp_prop, cred, 7757 "supp_groups", ":default") != 0) 7758 err = 1; 7759 7760 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 7761 exp_prop) != 0 || 7762 set_attr_from_prop_default(exp_prop, cred, 7763 "privileges", ":default") != 0) 7764 err = 1; 7765 7766 if (pg_get_prop(pg, SCF_PROPERTY_LIMIT_PRIVILEGES, 7767 exp_prop) != 0 || 7768 set_attr_from_prop_default(exp_prop, cred, 7769 "limit_privileges", ":default") != 0) 7770 err = 1; 7771 } 7772 } 7773 7774 if ((env = export_method_environment(pg)) != NULL) 7775 (void) xmlAddChild(ctxt, env); 7776 7777 if (env != NULL || err == 0) 7778 (void) xmlAddChild(n, ctxt); 7779 else 7780 xmlFreeNode(ctxt); 7781 7782 nonenv = (err == 0); 7783 7784 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7785 scfdie(); 7786 7787 (void) memset(&elts, 0, sizeof (elts)); 7788 7789 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7790 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7791 scfdie(); 7792 7793 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 7794 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 7795 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 7796 continue; 7797 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 7798 xmlNodePtr m; 7799 7800 m = xmlNewNode(NULL, (xmlChar *)"stability"); 7801 if (m == NULL) 7802 uu_die(emsg_create_xml); 7803 7804 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 7805 elts.stability = m; 7806 continue; 7807 } 7808 7809 xmlFreeNode(m); 7810 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 7811 0 || 7812 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 7813 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 7814 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 7815 if (nonenv) 7816 continue; 7817 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 7818 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 7819 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 7820 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 7821 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 7822 if (nonenv && !use_profile) 7823 continue; 7824 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 7825 if (nonenv && use_profile) 7826 continue; 7827 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 7828 if (env != NULL) 7829 continue; 7830 } 7831 7832 export_property(exp_prop, exp_str, &elts); 7833 } 7834 if (ret == -1) 7835 scfdie(); 7836 7837 (void) xmlAddChild(n, elts.stability); 7838 (void) xmlAddChildList(n, elts.propvals); 7839 (void) xmlAddChildList(n, elts.properties); 7840 7841 if (eelts->exec_methods == NULL) 7842 eelts->exec_methods = n; 7843 else 7844 (void) xmlAddSibling(eelts->exec_methods, n); 7845 } 7846 7847 static void 7848 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 7849 struct entity_elts *eelts) 7850 { 7851 xmlNodePtr pgnode; 7852 7853 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 7854 if (pgnode == NULL) 7855 uu_die(emsg_create_xml); 7856 7857 safe_setprop(pgnode, name_attr, name); 7858 safe_setprop(pgnode, type_attr, type); 7859 7860 (void) xmlAddChildList(pgnode, elts->propvals); 7861 (void) xmlAddChildList(pgnode, elts->properties); 7862 7863 if (eelts->property_groups == NULL) 7864 eelts->property_groups = pgnode; 7865 else 7866 (void) xmlAddSibling(eelts->property_groups, pgnode); 7867 } 7868 7869 /* 7870 * Process the general property group for a service. This is the one with the 7871 * goodies. 7872 */ 7873 static void 7874 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 7875 { 7876 struct pg_elts elts; 7877 int ret; 7878 7879 /* 7880 * In case there are properties which don't correspond to child 7881 * entities of the service entity, we'll set up a pg_elts structure to 7882 * put them in. 7883 */ 7884 (void) memset(&elts, 0, sizeof (elts)); 7885 7886 /* Walk the properties, looking for special ones. */ 7887 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7888 scfdie(); 7889 7890 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7891 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7892 scfdie(); 7893 7894 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 7895 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 7896 prop_get_val(exp_prop, exp_val) == 0) { 7897 uint8_t b; 7898 7899 if (scf_value_get_boolean(exp_val, &b) != 7900 SCF_SUCCESS) 7901 scfdie(); 7902 7903 if (b) { 7904 selts->single_instance = 7905 xmlNewNode(NULL, 7906 (xmlChar *)"single_instance"); 7907 if (selts->single_instance == NULL) 7908 uu_die(emsg_create_xml); 7909 } 7910 7911 continue; 7912 } 7913 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 7914 xmlNodePtr rnode, sfnode; 7915 7916 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 7917 if (rnode == NULL) 7918 uu_die(emsg_create_xml); 7919 7920 sfnode = xmlNewChild(rnode, NULL, 7921 (xmlChar *)"service_fmri", NULL); 7922 if (sfnode == NULL) 7923 uu_die(emsg_create_xml); 7924 7925 if (set_attr_from_prop(exp_prop, sfnode, 7926 value_attr) == 0) { 7927 selts->restarter = rnode; 7928 continue; 7929 } 7930 7931 xmlFreeNode(rnode); 7932 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 7933 0) { 7934 xmlNodePtr s; 7935 7936 s = xmlNewNode(NULL, (xmlChar *)"stability"); 7937 if (s == NULL) 7938 uu_die(emsg_create_xml); 7939 7940 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 7941 selts->stability = s; 7942 continue; 7943 } 7944 7945 xmlFreeNode(s); 7946 } 7947 7948 export_property(exp_prop, exp_str, &elts); 7949 } 7950 if (ret == -1) 7951 scfdie(); 7952 7953 if (elts.propvals != NULL || elts.properties != NULL) 7954 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 7955 selts); 7956 } 7957 7958 static void 7959 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 7960 { 7961 xmlNodePtr n, prof, cred, env; 7962 uint8_t use_profile; 7963 int ret, err = 0; 7964 7965 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 7966 7967 env = export_method_environment(pg); 7968 7969 /* Need to know whether we'll use a profile or not. */ 7970 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) != 0 || 7971 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) != 0 || 7972 prop_get_val(exp_prop, exp_val) != 0) { 7973 if (env != NULL) { 7974 (void) xmlAddChild(n, env); 7975 elts->method_context = n; 7976 } else { 7977 xmlFreeNode(n); 7978 export_pg(pg, elts); 7979 } 7980 return; 7981 } 7982 7983 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 7984 scfdie(); 7985 7986 if (use_profile) 7987 prof = xmlNewChild(n, NULL, (xmlChar *)"method_profile", NULL); 7988 else 7989 cred = 7990 xmlNewChild(n, NULL, (xmlChar *)"method_credential", NULL); 7991 7992 if (env != NULL) 7993 (void) xmlAddChild(n, env); 7994 7995 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7996 scfdie(); 7997 7998 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7999 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8000 scfdie(); 8001 8002 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 8003 if (set_attr_from_prop(exp_prop, n, 8004 "working_directory") != 0) 8005 err = 1; 8006 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 8007 if (set_attr_from_prop(exp_prop, n, "project") != 0) 8008 err = 1; 8009 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 8010 if (set_attr_from_prop(exp_prop, n, 8011 "resource_pool") != 0) 8012 err = 1; 8013 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8014 /* EMPTY */ 8015 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 8016 if (use_profile || 8017 set_attr_from_prop(exp_prop, cred, "user") != 0) 8018 err = 1; 8019 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 8020 if (use_profile || 8021 set_attr_from_prop(exp_prop, cred, "group") != 0) 8022 err = 1; 8023 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 8024 if (use_profile || set_attr_from_prop(exp_prop, cred, 8025 "supp_groups") != 0) 8026 err = 1; 8027 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 8028 if (use_profile || set_attr_from_prop(exp_prop, cred, 8029 "privileges") != 0) 8030 err = 1; 8031 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 8032 0) { 8033 if (use_profile || set_attr_from_prop(exp_prop, cred, 8034 "limit_privileges") != 0) 8035 err = 1; 8036 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8037 if (!use_profile || set_attr_from_prop(exp_prop, 8038 prof, name_attr) != 0) 8039 err = 1; 8040 } else { 8041 /* Can't have generic properties in method_context's */ 8042 err = 1; 8043 } 8044 } 8045 if (ret == -1) 8046 scfdie(); 8047 8048 if (err && env == NULL) { 8049 xmlFreeNode(n); 8050 export_pg(pg, elts); 8051 return; 8052 } 8053 8054 elts->method_context = n; 8055 } 8056 8057 /* 8058 * Given a dependency property group in the tfmri entity (target fmri), return 8059 * a dependent element which represents it. 8060 */ 8061 static xmlNodePtr 8062 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 8063 { 8064 uint8_t b; 8065 xmlNodePtr n, sf; 8066 int err = 0, ret; 8067 struct pg_elts pgelts; 8068 8069 /* 8070 * If external isn't set to true then exporting the service will 8071 * export this as a normal dependency, so we should stop to avoid 8072 * duplication. 8073 */ 8074 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 8075 scf_property_get_value(exp_prop, exp_val) != 0 || 8076 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 8077 if (g_verbose) { 8078 warn(gettext("Dependent \"%s\" cannot be exported " 8079 "properly because the \"%s\" property of the " 8080 "\"%s\" dependency of %s is not set to true.\n"), 8081 name, scf_property_external, name, tfmri); 8082 } 8083 8084 return (NULL); 8085 } 8086 8087 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 8088 if (n == NULL) 8089 uu_die(emsg_create_xml); 8090 8091 safe_setprop(n, name_attr, name); 8092 8093 /* Get the required attributes */ 8094 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8095 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8096 err = 1; 8097 8098 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8099 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8100 err = 1; 8101 8102 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8103 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 8104 prop_get_val(exp_prop, exp_val) == 0) { 8105 /* EMPTY */ 8106 } else 8107 err = 1; 8108 8109 if (err) { 8110 xmlFreeNode(n); 8111 return (NULL); 8112 } 8113 8114 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 8115 if (sf == NULL) 8116 uu_die(emsg_create_xml); 8117 8118 safe_setprop(sf, value_attr, tfmri); 8119 8120 /* 8121 * Now add elements for the other properties. 8122 */ 8123 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8124 scfdie(); 8125 8126 (void) memset(&pgelts, 0, sizeof (pgelts)); 8127 8128 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8129 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8130 scfdie(); 8131 8132 if (strcmp(exp_str, scf_property_external) == 0 || 8133 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8134 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8135 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8136 continue; 8137 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 8138 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 8139 prop_get_val(exp_prop, exp_val) == 0) { 8140 char type[sizeof ("service") + 1]; 8141 8142 if (scf_value_get_astring(exp_val, type, 8143 sizeof (type)) < 0) 8144 scfdie(); 8145 8146 if (strcmp(type, "service") == 0) 8147 continue; 8148 } 8149 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8150 xmlNodePtr s; 8151 8152 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8153 if (s == NULL) 8154 uu_die(emsg_create_xml); 8155 8156 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8157 pgelts.stability = s; 8158 continue; 8159 } 8160 8161 xmlFreeNode(s); 8162 } 8163 8164 export_property(exp_prop, exp_str, &pgelts); 8165 } 8166 if (ret == -1) 8167 scfdie(); 8168 8169 (void) xmlAddChild(n, pgelts.stability); 8170 (void) xmlAddChildList(n, pgelts.propvals); 8171 (void) xmlAddChildList(n, pgelts.properties); 8172 8173 return (n); 8174 } 8175 8176 static void 8177 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 8178 { 8179 scf_propertygroup_t *opg; 8180 scf_iter_t *iter; 8181 char *type, *fmri; 8182 int ret; 8183 struct pg_elts pgelts; 8184 xmlNodePtr n; 8185 scf_error_t serr; 8186 8187 if ((opg = scf_pg_create(g_hndl)) == NULL || 8188 (iter = scf_iter_create(g_hndl)) == NULL) 8189 scfdie(); 8190 8191 /* Can't use exp_prop_iter due to export_dependent(). */ 8192 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 8193 scfdie(); 8194 8195 type = safe_malloc(max_scf_pg_type_len + 1); 8196 8197 /* Get an extra byte so we can tell if values are too long. */ 8198 fmri = safe_malloc(max_scf_fmri_len + 2); 8199 8200 (void) memset(&pgelts, 0, sizeof (pgelts)); 8201 8202 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 8203 void *entity; 8204 int isservice; 8205 scf_type_t ty; 8206 8207 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 8208 scfdie(); 8209 8210 if ((ty != SCF_TYPE_ASTRING && 8211 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 8212 prop_get_val(exp_prop, exp_val) != 0) { 8213 export_property(exp_prop, NULL, &pgelts); 8214 continue; 8215 } 8216 8217 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8218 scfdie(); 8219 8220 if (scf_value_get_astring(exp_val, fmri, 8221 max_scf_fmri_len + 2) < 0) 8222 scfdie(); 8223 8224 /* Look for a dependency group in the target fmri. */ 8225 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 8226 switch (serr) { 8227 case SCF_ERROR_NONE: 8228 break; 8229 8230 case SCF_ERROR_NO_MEMORY: 8231 uu_die(gettext("Out of memory.\n")); 8232 /* NOTREACHED */ 8233 8234 case SCF_ERROR_INVALID_ARGUMENT: 8235 if (g_verbose) { 8236 if (scf_property_to_fmri(exp_prop, fmri, 8237 max_scf_fmri_len + 2) < 0) 8238 scfdie(); 8239 8240 warn(gettext("The value of %s is not a valid " 8241 "FMRI.\n"), fmri); 8242 } 8243 8244 export_property(exp_prop, exp_str, &pgelts); 8245 continue; 8246 8247 case SCF_ERROR_CONSTRAINT_VIOLATED: 8248 if (g_verbose) { 8249 if (scf_property_to_fmri(exp_prop, fmri, 8250 max_scf_fmri_len + 2) < 0) 8251 scfdie(); 8252 8253 warn(gettext("The value of %s does not specify " 8254 "a service or an instance.\n"), fmri); 8255 } 8256 8257 export_property(exp_prop, exp_str, &pgelts); 8258 continue; 8259 8260 case SCF_ERROR_NOT_FOUND: 8261 if (g_verbose) { 8262 if (scf_property_to_fmri(exp_prop, fmri, 8263 max_scf_fmri_len + 2) < 0) 8264 scfdie(); 8265 8266 warn(gettext("The entity specified by %s does " 8267 "not exist.\n"), fmri); 8268 } 8269 8270 export_property(exp_prop, exp_str, &pgelts); 8271 continue; 8272 8273 default: 8274 #ifndef NDEBUG 8275 (void) fprintf(stderr, "%s:%d: %s() failed with " 8276 "unexpected error %d.\n", __FILE__, __LINE__, 8277 "fmri_to_entity", serr); 8278 #endif 8279 abort(); 8280 } 8281 8282 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 8283 if (scf_error() != SCF_ERROR_NOT_FOUND) 8284 scfdie(); 8285 8286 warn(gettext("Entity %s is missing dependency property " 8287 "group %s.\n"), fmri, exp_str); 8288 8289 export_property(exp_prop, NULL, &pgelts); 8290 continue; 8291 } 8292 8293 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 8294 scfdie(); 8295 8296 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 8297 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 8298 scfdie(); 8299 8300 warn(gettext("Property group %s is not of " 8301 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 8302 8303 export_property(exp_prop, NULL, &pgelts); 8304 continue; 8305 } 8306 8307 n = export_dependent(opg, exp_str, fmri); 8308 if (n == NULL) 8309 export_property(exp_prop, exp_str, &pgelts); 8310 else { 8311 if (eelts->dependents == NULL) 8312 eelts->dependents = n; 8313 else 8314 (void) xmlAddSibling(eelts->dependents, 8315 n); 8316 } 8317 } 8318 if (ret == -1) 8319 scfdie(); 8320 8321 free(fmri); 8322 free(type); 8323 8324 scf_iter_destroy(iter); 8325 scf_pg_destroy(opg); 8326 8327 if (pgelts.propvals != NULL || pgelts.properties != NULL) 8328 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 8329 eelts); 8330 } 8331 8332 static void 8333 make_node(xmlNodePtr *nodep, const char *name) 8334 { 8335 if (*nodep == NULL) { 8336 *nodep = xmlNewNode(NULL, (xmlChar *)name); 8337 if (*nodep == NULL) 8338 uu_die(emsg_create_xml); 8339 } 8340 } 8341 8342 static xmlNodePtr 8343 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 8344 { 8345 int ret; 8346 xmlNodePtr parent = NULL; 8347 xmlNodePtr loctext = NULL; 8348 8349 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8350 scfdie(); 8351 8352 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8353 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 8354 prop_get_val(exp_prop, exp_val) != 0) 8355 continue; 8356 8357 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 8358 scfdie(); 8359 8360 make_node(&parent, parname); 8361 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 8362 (xmlChar *)exp_str); 8363 if (loctext == NULL) 8364 uu_die(emsg_create_xml); 8365 8366 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8367 scfdie(); 8368 8369 safe_setprop(loctext, "xml:lang", exp_str); 8370 } 8371 8372 if (ret == -1) 8373 scfdie(); 8374 8375 return (parent); 8376 } 8377 8378 static xmlNodePtr 8379 export_tm_manpage(scf_propertygroup_t *pg) 8380 { 8381 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 8382 if (manpage == NULL) 8383 uu_die(emsg_create_xml); 8384 8385 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 8386 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 8387 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 8388 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 8389 xmlFreeNode(manpage); 8390 return (NULL); 8391 } 8392 8393 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 8394 (void) set_attr_from_prop_default(exp_prop, 8395 manpage, "manpath", ":default"); 8396 8397 return (manpage); 8398 } 8399 8400 static xmlNodePtr 8401 export_tm_doc_link(scf_propertygroup_t *pg) 8402 { 8403 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 8404 if (doc_link == NULL) 8405 uu_die(emsg_create_xml); 8406 8407 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 8408 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 8409 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 8410 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 8411 xmlFreeNode(doc_link); 8412 return (NULL); 8413 } 8414 return (doc_link); 8415 } 8416 8417 /* 8418 * Process template information for a service or instances. 8419 */ 8420 static void 8421 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 8422 struct template_elts *telts) 8423 { 8424 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 8425 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 8426 xmlNodePtr child = NULL; 8427 8428 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 8429 scfdie(); 8430 8431 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 8432 telts->common_name = export_tm_loctext(pg, "common_name"); 8433 if (telts->common_name == NULL) 8434 export_pg(pg, elts); 8435 return; 8436 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 8437 telts->description = export_tm_loctext(pg, "description"); 8438 if (telts->description == NULL) 8439 export_pg(pg, elts); 8440 return; 8441 } 8442 8443 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 8444 child = export_tm_manpage(pg); 8445 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 8446 child = export_tm_doc_link(pg); 8447 } 8448 8449 if (child != NULL) { 8450 make_node(&telts->documentation, "documentation"); 8451 (void) xmlAddChild(telts->documentation, child); 8452 } else { 8453 export_pg(pg, elts); 8454 } 8455 } 8456 8457 /* 8458 * Process the general property group for an instance. 8459 */ 8460 static void 8461 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 8462 struct entity_elts *elts) 8463 { 8464 uint8_t enabled; 8465 struct pg_elts pgelts; 8466 int ret; 8467 8468 /* enabled */ 8469 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 8470 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8471 prop_get_val(exp_prop, exp_val) == 0) { 8472 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 8473 scfdie(); 8474 } else { 8475 enabled = 0; 8476 } 8477 8478 safe_setprop(inode, enabled_attr, enabled ? true : false); 8479 8480 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8481 scfdie(); 8482 8483 (void) memset(&pgelts, 0, sizeof (pgelts)); 8484 8485 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8486 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8487 scfdie(); 8488 8489 if (strcmp(exp_str, scf_property_enabled) == 0) { 8490 continue; 8491 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8492 xmlNodePtr rnode, sfnode; 8493 8494 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8495 if (rnode == NULL) 8496 uu_die(emsg_create_xml); 8497 8498 sfnode = xmlNewChild(rnode, NULL, 8499 (xmlChar *)"service_fmri", NULL); 8500 if (sfnode == NULL) 8501 uu_die(emsg_create_xml); 8502 8503 if (set_attr_from_prop(exp_prop, sfnode, 8504 value_attr) == 0) { 8505 elts->restarter = rnode; 8506 continue; 8507 } 8508 8509 xmlFreeNode(rnode); 8510 } 8511 8512 export_property(exp_prop, exp_str, &pgelts); 8513 } 8514 if (ret == -1) 8515 scfdie(); 8516 8517 if (pgelts.propvals != NULL || pgelts.properties != NULL) 8518 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 8519 elts); 8520 } 8521 8522 /* 8523 * Put an instance element for the given instance into selts. 8524 */ 8525 static void 8526 export_instance(scf_instance_t *inst, struct entity_elts *selts) 8527 { 8528 xmlNodePtr n; 8529 boolean_t isdefault; 8530 struct entity_elts elts; 8531 struct template_elts template_elts; 8532 int ret; 8533 8534 n = xmlNewNode(NULL, (xmlChar *)"instance"); 8535 if (n == NULL) 8536 uu_die(emsg_create_xml); 8537 8538 /* name */ 8539 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 8540 scfdie(); 8541 safe_setprop(n, name_attr, exp_str); 8542 isdefault = strcmp(exp_str, "default") == 0; 8543 8544 /* check existance of general pg (since general/enabled is required) */ 8545 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 8546 if (scf_error() != SCF_ERROR_NOT_FOUND) 8547 scfdie(); 8548 8549 if (g_verbose) { 8550 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 8551 scfdie(); 8552 8553 warn(gettext("Instance %s has no general property " 8554 "group; it will be marked disabled.\n"), exp_str); 8555 } 8556 8557 safe_setprop(n, enabled_attr, false); 8558 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 8559 strcmp(exp_str, scf_group_framework) != 0) { 8560 if (g_verbose) { 8561 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 8562 scfdie(); 8563 8564 warn(gettext("Property group %s is not of type " 8565 "framework; the instance will be marked " 8566 "disabled.\n"), exp_str); 8567 } 8568 8569 safe_setprop(n, enabled_attr, false); 8570 } 8571 8572 /* property groups */ 8573 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 8574 scfdie(); 8575 8576 (void) memset(&elts, 0, sizeof (elts)); 8577 (void) memset(&template_elts, 0, sizeof (template_elts)); 8578 8579 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 8580 uint32_t flags; 8581 8582 if (scf_pg_get_flags(exp_pg, &flags) != 0) 8583 scfdie(); 8584 8585 if (flags & SCF_PG_FLAG_NONPERSISTENT) 8586 continue; 8587 8588 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 8589 scfdie(); 8590 8591 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 8592 export_dependency(exp_pg, &elts); 8593 continue; 8594 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 8595 export_method(exp_pg, &elts); 8596 continue; 8597 } else if (strcmp(exp_str, scf_group_framework) == 0) { 8598 if (scf_pg_get_name(exp_pg, exp_str, 8599 max_scf_name_len + 1) < 0) 8600 scfdie(); 8601 8602 if (strcmp(exp_str, scf_pg_general) == 0) { 8603 export_inst_general(exp_pg, n, &elts); 8604 continue; 8605 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 8606 0) { 8607 export_method_context(exp_pg, &elts); 8608 continue; 8609 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 8610 export_dependents(exp_pg, &elts); 8611 continue; 8612 } 8613 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 8614 export_template(exp_pg, &elts, &template_elts); 8615 continue; 8616 } 8617 8618 /* Ordinary pg. */ 8619 export_pg(exp_pg, &elts); 8620 } 8621 if (ret == -1) 8622 scfdie(); 8623 8624 if (template_elts.common_name != NULL) { 8625 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 8626 (void) xmlAddChild(elts.template, template_elts.common_name); 8627 (void) xmlAddChild(elts.template, template_elts.description); 8628 (void) xmlAddChild(elts.template, template_elts.documentation); 8629 } else { 8630 xmlFreeNode(template_elts.description); 8631 xmlFreeNode(template_elts.documentation); 8632 } 8633 8634 if (isdefault && elts.restarter == NULL && 8635 elts.dependencies == NULL && elts.method_context == NULL && 8636 elts.exec_methods == NULL && elts.property_groups == NULL && 8637 elts.template == NULL) { 8638 xmlChar *eval; 8639 8640 /* This is a default instance */ 8641 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 8642 8643 xmlFreeNode(n); 8644 8645 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 8646 if (n == NULL) 8647 uu_die(emsg_create_xml); 8648 8649 safe_setprop(n, enabled_attr, (char *)eval); 8650 xmlFree(eval); 8651 8652 selts->create_default_instance = n; 8653 } else { 8654 /* Assemble the children in order. */ 8655 (void) xmlAddChild(n, elts.restarter); 8656 (void) xmlAddChildList(n, elts.dependencies); 8657 (void) xmlAddChildList(n, elts.dependents); 8658 (void) xmlAddChild(n, elts.method_context); 8659 (void) xmlAddChildList(n, elts.exec_methods); 8660 (void) xmlAddChildList(n, elts.property_groups); 8661 (void) xmlAddChild(n, elts.template); 8662 8663 if (selts->instances == NULL) 8664 selts->instances = n; 8665 else 8666 (void) xmlAddSibling(selts->instances, n); 8667 } 8668 } 8669 8670 /* 8671 * Return a service element for the given service. 8672 */ 8673 static xmlNodePtr 8674 export_service(scf_service_t *svc) 8675 { 8676 xmlNodePtr snode; 8677 struct entity_elts elts; 8678 struct template_elts template_elts; 8679 int ret; 8680 8681 snode = xmlNewNode(NULL, (xmlChar *)"service"); 8682 if (snode == NULL) 8683 uu_die(emsg_create_xml); 8684 8685 /* Get & set name attribute */ 8686 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 8687 scfdie(); 8688 safe_setprop(snode, name_attr, exp_str); 8689 8690 safe_setprop(snode, type_attr, "service"); 8691 safe_setprop(snode, "version", "0"); 8692 8693 /* Acquire child elements. */ 8694 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 8695 scfdie(); 8696 8697 (void) memset(&elts, 0, sizeof (elts)); 8698 (void) memset(&template_elts, 0, sizeof (template_elts)); 8699 8700 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 8701 uint32_t flags; 8702 8703 if (scf_pg_get_flags(exp_pg, &flags) != 0) 8704 scfdie(); 8705 8706 if (flags & SCF_PG_FLAG_NONPERSISTENT) 8707 continue; 8708 8709 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 8710 scfdie(); 8711 8712 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 8713 export_dependency(exp_pg, &elts); 8714 continue; 8715 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 8716 export_method(exp_pg, &elts); 8717 continue; 8718 } else if (strcmp(exp_str, scf_group_framework) == 0) { 8719 if (scf_pg_get_name(exp_pg, exp_str, 8720 max_scf_name_len + 1) < 0) 8721 scfdie(); 8722 8723 if (strcmp(exp_str, scf_pg_general) == 0) { 8724 export_svc_general(exp_pg, &elts); 8725 continue; 8726 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 8727 0) { 8728 export_method_context(exp_pg, &elts); 8729 continue; 8730 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 8731 export_dependents(exp_pg, &elts); 8732 continue; 8733 } 8734 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 8735 export_template(exp_pg, &elts, &template_elts); 8736 continue; 8737 } 8738 8739 export_pg(exp_pg, &elts); 8740 } 8741 if (ret == -1) 8742 scfdie(); 8743 8744 if (template_elts.common_name != NULL) { 8745 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 8746 (void) xmlAddChild(elts.template, template_elts.common_name); 8747 (void) xmlAddChild(elts.template, template_elts.description); 8748 (void) xmlAddChild(elts.template, template_elts.documentation); 8749 } else { 8750 xmlFreeNode(template_elts.description); 8751 xmlFreeNode(template_elts.documentation); 8752 } 8753 8754 /* Iterate instances */ 8755 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 8756 scfdie(); 8757 8758 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 8759 export_instance(exp_inst, &elts); 8760 if (ret == -1) 8761 scfdie(); 8762 8763 /* Now add all of the accumulated elements in order. */ 8764 (void) xmlAddChild(snode, elts.create_default_instance); 8765 (void) xmlAddChild(snode, elts.single_instance); 8766 (void) xmlAddChild(snode, elts.restarter); 8767 (void) xmlAddChildList(snode, elts.dependencies); 8768 (void) xmlAddChildList(snode, elts.dependents); 8769 (void) xmlAddChild(snode, elts.method_context); 8770 (void) xmlAddChildList(snode, elts.exec_methods); 8771 (void) xmlAddChildList(snode, elts.property_groups); 8772 (void) xmlAddChildList(snode, elts.instances); 8773 (void) xmlAddChild(snode, elts.stability); 8774 (void) xmlAddChild(snode, elts.template); 8775 8776 return (snode); 8777 } 8778 8779 static int 8780 export_callback(void *data, scf_walkinfo_t *wip) 8781 { 8782 FILE *f; 8783 xmlDocPtr doc; 8784 xmlNodePtr sb; 8785 int result; 8786 char *filename = data; 8787 8788 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 8789 (exp_pg = scf_pg_create(g_hndl)) == NULL || 8790 (exp_prop = scf_property_create(g_hndl)) == NULL || 8791 (exp_val = scf_value_create(g_hndl)) == NULL || 8792 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 8793 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 8794 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 8795 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 8796 scfdie(); 8797 8798 exp_str_sz = max_scf_len + 1; 8799 exp_str = safe_malloc(exp_str_sz); 8800 8801 if (filename != NULL) { 8802 errno = 0; 8803 f = fopen(filename, "wb"); 8804 if (f == NULL) { 8805 if (errno == 0) 8806 uu_die(gettext("Could not open \"%s\": no free " 8807 "stdio streams.\n"), filename); 8808 else 8809 uu_die(gettext("Could not open \"%s\""), 8810 filename); 8811 } 8812 } else 8813 f = stdout; 8814 8815 doc = xmlNewDoc((xmlChar *)"1.0"); 8816 if (doc == NULL) 8817 uu_die(gettext("Could not create XML document.\n")); 8818 8819 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 8820 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 8821 uu_die(emsg_create_xml); 8822 8823 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 8824 if (sb == NULL) 8825 uu_die(emsg_create_xml); 8826 safe_setprop(sb, type_attr, "manifest"); 8827 safe_setprop(sb, name_attr, "export"); 8828 (void) xmlAddSibling(doc->children, sb); 8829 8830 (void) xmlAddChild(sb, export_service(wip->svc)); 8831 8832 result = write_service_bundle(doc, f); 8833 8834 free(exp_str); 8835 scf_iter_destroy(exp_val_iter); 8836 scf_iter_destroy(exp_prop_iter); 8837 scf_iter_destroy(exp_pg_iter); 8838 scf_iter_destroy(exp_inst_iter); 8839 scf_value_destroy(exp_val); 8840 scf_property_destroy(exp_prop); 8841 scf_pg_destroy(exp_pg); 8842 scf_instance_destroy(exp_inst); 8843 8844 xmlFreeDoc(doc); 8845 8846 if (f != stdout) 8847 (void) fclose(f); 8848 8849 return (result); 8850 } 8851 8852 /* 8853 * Get the service named by fmri, build an XML tree which represents it, and 8854 * dump it into filename (or stdout if filename is NULL). 8855 */ 8856 int 8857 lscf_service_export(char *fmri, const char *filename) 8858 { 8859 int ret, err; 8860 8861 lscf_prep_hndl(); 8862 8863 err = 0; 8864 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 8865 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 8866 (void *)filename, &err, semerr)) != 0) { 8867 if (ret != -1) 8868 semerr(gettext("Failed to walk instances: %s\n"), 8869 scf_strerror(ret)); 8870 return (-1); 8871 } 8872 8873 /* 8874 * Error message has already been printed. 8875 */ 8876 if (err != 0) 8877 return (-1); 8878 8879 return (0); 8880 } 8881 8882 8883 /* 8884 * Archive 8885 */ 8886 8887 static xmlNodePtr 8888 make_archive() 8889 { 8890 xmlNodePtr sb; 8891 scf_scope_t *scope; 8892 scf_service_t *svc; 8893 scf_iter_t *iter; 8894 int r; 8895 8896 if ((scope = scf_scope_create(g_hndl)) == NULL || 8897 (svc = scf_service_create(g_hndl)) == NULL || 8898 (iter = scf_iter_create(g_hndl)) == NULL || 8899 (exp_inst = scf_instance_create(g_hndl)) == NULL || 8900 (exp_pg = scf_pg_create(g_hndl)) == NULL || 8901 (exp_prop = scf_property_create(g_hndl)) == NULL || 8902 (exp_val = scf_value_create(g_hndl)) == NULL || 8903 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 8904 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 8905 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 8906 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 8907 scfdie(); 8908 8909 exp_str_sz = max_scf_len + 1; 8910 exp_str = safe_malloc(exp_str_sz); 8911 8912 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 8913 if (sb == NULL) 8914 uu_die(emsg_create_xml); 8915 safe_setprop(sb, type_attr, "archive"); 8916 safe_setprop(sb, name_attr, "none"); 8917 8918 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 8919 scfdie(); 8920 if (scf_iter_scope_services(iter, scope) != 0) 8921 scfdie(); 8922 8923 for (;;) { 8924 r = scf_iter_next_service(iter, svc); 8925 if (r == 0) 8926 break; 8927 if (r != 1) 8928 scfdie(); 8929 8930 if (scf_service_get_name(svc, exp_str, 8931 max_scf_name_len + 1) < 0) 8932 scfdie(); 8933 8934 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 8935 continue; 8936 8937 xmlAddChild(sb, export_service(svc)); 8938 } 8939 8940 free(exp_str); 8941 8942 scf_iter_destroy(exp_val_iter); 8943 scf_iter_destroy(exp_prop_iter); 8944 scf_iter_destroy(exp_pg_iter); 8945 scf_iter_destroy(exp_inst_iter); 8946 scf_value_destroy(exp_val); 8947 scf_property_destroy(exp_prop); 8948 scf_pg_destroy(exp_pg); 8949 scf_instance_destroy(exp_inst); 8950 scf_iter_destroy(iter); 8951 scf_service_destroy(svc); 8952 scf_scope_destroy(scope); 8953 8954 return (sb); 8955 } 8956 8957 int 8958 lscf_archive(const char *filename) 8959 { 8960 FILE *f; 8961 xmlDocPtr doc; 8962 int result; 8963 8964 lscf_prep_hndl(); 8965 8966 if (filename != NULL) { 8967 errno = 0; 8968 f = fopen(filename, "wb"); 8969 if (f == NULL) { 8970 if (errno == 0) 8971 uu_die(gettext("Could not open \"%s\": no free " 8972 "stdio streams.\n"), filename); 8973 else 8974 uu_die(gettext("Could not open \"%s\""), 8975 filename); 8976 } 8977 } else 8978 f = stdout; 8979 8980 doc = xmlNewDoc((xmlChar *)"1.0"); 8981 if (doc == NULL) 8982 uu_die(gettext("Could not create XML document.\n")); 8983 8984 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 8985 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 8986 uu_die(emsg_create_xml); 8987 8988 (void) xmlAddSibling(doc->children, make_archive()); 8989 8990 result = write_service_bundle(doc, f); 8991 8992 xmlFreeDoc(doc); 8993 8994 if (f != stdout) 8995 (void) fclose(f); 8996 8997 return (result); 8998 } 8999 9000 9001 /* 9002 * "Extract" a profile. 9003 */ 9004 int 9005 lscf_profile_extract(const char *filename) 9006 { 9007 FILE *f; 9008 xmlDocPtr doc; 9009 xmlNodePtr sb, snode, inode; 9010 scf_scope_t *scope; 9011 scf_service_t *svc; 9012 scf_instance_t *inst; 9013 scf_propertygroup_t *pg; 9014 scf_property_t *prop; 9015 scf_value_t *val; 9016 scf_iter_t *siter, *iiter; 9017 int r, s; 9018 char *namebuf; 9019 uint8_t b; 9020 int result; 9021 9022 lscf_prep_hndl(); 9023 9024 if (filename != NULL) { 9025 errno = 0; 9026 f = fopen(filename, "wb"); 9027 if (f == NULL) { 9028 if (errno == 0) 9029 uu_die(gettext("Could not open \"%s\": no " 9030 "free stdio streams.\n"), filename); 9031 else 9032 uu_die(gettext("Could not open \"%s\""), 9033 filename); 9034 } 9035 } else 9036 f = stdout; 9037 9038 doc = xmlNewDoc((xmlChar *)"1.0"); 9039 if (doc == NULL) 9040 uu_die(gettext("Could not create XML document.\n")); 9041 9042 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9043 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9044 uu_die(emsg_create_xml); 9045 9046 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9047 if (sb == NULL) 9048 uu_die(emsg_create_xml); 9049 safe_setprop(sb, type_attr, "profile"); 9050 safe_setprop(sb, name_attr, "extract"); 9051 (void) xmlAddSibling(doc->children, sb); 9052 9053 if ((scope = scf_scope_create(g_hndl)) == NULL || 9054 (svc = scf_service_create(g_hndl)) == NULL || 9055 (inst = scf_instance_create(g_hndl)) == NULL || 9056 (pg = scf_pg_create(g_hndl)) == NULL || 9057 (prop = scf_property_create(g_hndl)) == NULL || 9058 (val = scf_value_create(g_hndl)) == NULL || 9059 (siter = scf_iter_create(g_hndl)) == NULL || 9060 (iiter = scf_iter_create(g_hndl)) == NULL) 9061 scfdie(); 9062 9063 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 9064 scfdie(); 9065 9066 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 9067 scfdie(); 9068 9069 namebuf = safe_malloc(max_scf_name_len + 1); 9070 9071 while ((r = scf_iter_next_service(siter, svc)) == 1) { 9072 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 9073 scfdie(); 9074 9075 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9076 if (snode == NULL) 9077 uu_die(emsg_create_xml); 9078 9079 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 9080 0) 9081 scfdie(); 9082 9083 safe_setprop(snode, name_attr, namebuf); 9084 9085 safe_setprop(snode, type_attr, "service"); 9086 safe_setprop(snode, "version", "0"); 9087 9088 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 9089 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 9090 SCF_SUCCESS) { 9091 if (scf_error() != SCF_ERROR_NOT_FOUND) 9092 scfdie(); 9093 9094 if (g_verbose) { 9095 ssize_t len; 9096 char *fmri; 9097 9098 len = 9099 scf_instance_to_fmri(inst, NULL, 0); 9100 if (len < 0) 9101 scfdie(); 9102 9103 fmri = safe_malloc(len + 1); 9104 9105 if (scf_instance_to_fmri(inst, fmri, 9106 len + 1) < 0) 9107 scfdie(); 9108 9109 warn("Instance %s has no \"%s\" " 9110 "property group.\n", fmri, 9111 scf_pg_general); 9112 9113 free(fmri); 9114 } 9115 9116 continue; 9117 } 9118 9119 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 9120 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 9121 prop_get_val(prop, val) != 0) 9122 continue; 9123 9124 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 9125 NULL); 9126 if (inode == NULL) 9127 uu_die(emsg_create_xml); 9128 9129 if (scf_instance_get_name(inst, namebuf, 9130 max_scf_name_len + 1) < 0) 9131 scfdie(); 9132 9133 safe_setprop(inode, name_attr, namebuf); 9134 9135 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 9136 scfdie(); 9137 9138 safe_setprop(inode, enabled_attr, b ? true : false); 9139 } 9140 if (s < 0) 9141 scfdie(); 9142 9143 if (snode->children != NULL) 9144 xmlAddChild(sb, snode); 9145 else 9146 xmlFreeNode(snode); 9147 } 9148 if (r < 0) 9149 scfdie(); 9150 9151 free(namebuf); 9152 9153 result = write_service_bundle(doc, f); 9154 9155 xmlFreeDoc(doc); 9156 9157 if (f != stdout) 9158 (void) fclose(f); 9159 9160 return (result); 9161 } 9162 9163 9164 /* 9165 * Entity manipulation commands 9166 */ 9167 9168 /* 9169 * Entity selection. If no entity is selected, then the current scope is in 9170 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 9171 * only cur_inst is NULL, and when an instance is selected, none are NULL. 9172 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 9173 * cur_inst will be non-NULL. 9174 */ 9175 9176 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 9177 static int 9178 select_inst(const char *name) 9179 { 9180 scf_instance_t *inst; 9181 scf_error_t err; 9182 9183 assert(cur_svc != NULL); 9184 9185 inst = scf_instance_create(g_hndl); 9186 if (inst == NULL) 9187 scfdie(); 9188 9189 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 9190 cur_inst = inst; 9191 return (0); 9192 } 9193 9194 err = scf_error(); 9195 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9196 scfdie(); 9197 9198 scf_instance_destroy(inst); 9199 return (1); 9200 } 9201 9202 /* Returns as above. */ 9203 static int 9204 select_svc(const char *name) 9205 { 9206 scf_service_t *svc; 9207 scf_error_t err; 9208 9209 assert(cur_scope != NULL); 9210 9211 svc = scf_service_create(g_hndl); 9212 if (svc == NULL) 9213 scfdie(); 9214 9215 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 9216 cur_svc = svc; 9217 return (0); 9218 } 9219 9220 err = scf_error(); 9221 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9222 scfdie(); 9223 9224 scf_service_destroy(svc); 9225 return (1); 9226 } 9227 9228 /* ARGSUSED */ 9229 static int 9230 select_callback(void *unused, scf_walkinfo_t *wip) 9231 { 9232 scf_instance_t *inst; 9233 scf_service_t *svc; 9234 scf_scope_t *scope; 9235 9236 if (wip->inst != NULL) { 9237 if ((scope = scf_scope_create(g_hndl)) == NULL || 9238 (svc = scf_service_create(g_hndl)) == NULL || 9239 (inst = scf_instance_create(g_hndl)) == NULL) 9240 scfdie(); 9241 9242 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9243 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9244 scfdie(); 9245 } else { 9246 assert(wip->svc != NULL); 9247 9248 if ((scope = scf_scope_create(g_hndl)) == NULL || 9249 (svc = scf_service_create(g_hndl)) == NULL) 9250 scfdie(); 9251 9252 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9253 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9254 scfdie(); 9255 9256 inst = NULL; 9257 } 9258 9259 /* Clear out the current selection */ 9260 assert(cur_scope != NULL); 9261 scf_scope_destroy(cur_scope); 9262 scf_service_destroy(cur_svc); 9263 scf_instance_destroy(cur_inst); 9264 9265 cur_scope = scope; 9266 cur_svc = svc; 9267 cur_inst = inst; 9268 9269 return (0); 9270 } 9271 9272 void 9273 lscf_select(const char *fmri) 9274 { 9275 int ret, err; 9276 9277 lscf_prep_hndl(); 9278 9279 if (cur_snap != NULL) { 9280 struct snaplevel *elt; 9281 char *buf; 9282 9283 /* Error unless name is that of the next level. */ 9284 elt = uu_list_next(cur_levels, cur_elt); 9285 if (elt == NULL) { 9286 semerr(gettext("No children.\n")); 9287 return; 9288 } 9289 9290 buf = safe_malloc(max_scf_name_len + 1); 9291 9292 if (scf_snaplevel_get_instance_name(elt->sl, buf, 9293 max_scf_name_len + 1) < 0) 9294 scfdie(); 9295 9296 if (strcmp(buf, fmri) != 0) { 9297 semerr(gettext("No such child.\n")); 9298 free(buf); 9299 return; 9300 } 9301 9302 free(buf); 9303 9304 cur_elt = elt; 9305 cur_level = elt->sl; 9306 return; 9307 } 9308 9309 /* 9310 * Special case for 'svc:', which takes the user to the scope level. 9311 */ 9312 if (strcmp(fmri, "svc:") == 0) { 9313 scf_instance_destroy(cur_inst); 9314 scf_service_destroy(cur_svc); 9315 cur_inst = NULL; 9316 cur_svc = NULL; 9317 return; 9318 } 9319 9320 /* 9321 * Special case for ':properties'. This appears as part of 'list' but 9322 * can't be selected. Give a more helpful error message in this case. 9323 */ 9324 if (strcmp(fmri, ":properties") == 0) { 9325 semerr(gettext(":properties is not an entity. Try 'listprop' " 9326 "to list properties.\n")); 9327 return; 9328 } 9329 9330 /* 9331 * First try the argument as relative to the current selection. 9332 */ 9333 if (cur_inst != NULL) { 9334 /* EMPTY */; 9335 } else if (cur_svc != NULL) { 9336 if (select_inst(fmri) != 1) 9337 return; 9338 } else { 9339 if (select_svc(fmri) != 1) 9340 return; 9341 } 9342 9343 err = 0; 9344 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 9345 select_callback, NULL, &err, semerr)) != 0) { 9346 semerr(gettext("Failed to walk instances: %s\n"), 9347 scf_strerror(ret)); 9348 } 9349 } 9350 9351 void 9352 lscf_unselect(void) 9353 { 9354 lscf_prep_hndl(); 9355 9356 if (cur_snap != NULL) { 9357 struct snaplevel *elt; 9358 9359 elt = uu_list_prev(cur_levels, cur_elt); 9360 if (elt == NULL) { 9361 semerr(gettext("No parent levels.\n")); 9362 } else { 9363 cur_elt = elt; 9364 cur_level = elt->sl; 9365 } 9366 } else if (cur_inst != NULL) { 9367 scf_instance_destroy(cur_inst); 9368 cur_inst = NULL; 9369 } else if (cur_svc != NULL) { 9370 scf_service_destroy(cur_svc); 9371 cur_svc = NULL; 9372 } else { 9373 semerr(gettext("Cannot unselect at scope level.\n")); 9374 } 9375 } 9376 9377 /* 9378 * Return the FMRI of the current selection, for the prompt. 9379 */ 9380 void 9381 lscf_get_selection_str(char *buf, size_t bufsz) 9382 { 9383 char *cp; 9384 ssize_t fmrilen, szret; 9385 boolean_t deleted = B_FALSE; 9386 9387 if (g_hndl == NULL) { 9388 (void) strlcpy(buf, "svc:", bufsz); 9389 return; 9390 } 9391 9392 if (cur_level != NULL) { 9393 assert(cur_snap != NULL); 9394 9395 /* [ snapshot ] FMRI [: instance ] */ 9396 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 9397 + 2 + max_scf_name_len + 1 + 1); 9398 9399 buf[0] = '['; 9400 9401 szret = scf_snapshot_get_name(cur_snap, buf + 1, 9402 max_scf_name_len + 1); 9403 if (szret < 0) { 9404 if (scf_error() != SCF_ERROR_DELETED) 9405 scfdie(); 9406 9407 goto snap_deleted; 9408 } 9409 9410 (void) strcat(buf, "]svc:/"); 9411 9412 cp = strchr(buf, '\0'); 9413 9414 szret = scf_snaplevel_get_service_name(cur_level, cp, 9415 max_scf_name_len + 1); 9416 if (szret < 0) { 9417 if (scf_error() != SCF_ERROR_DELETED) 9418 scfdie(); 9419 9420 goto snap_deleted; 9421 } 9422 9423 cp = strchr(cp, '\0'); 9424 9425 if (snaplevel_is_instance(cur_level)) { 9426 *cp++ = ':'; 9427 9428 if (scf_snaplevel_get_instance_name(cur_level, cp, 9429 max_scf_name_len + 1) < 0) { 9430 if (scf_error() != SCF_ERROR_DELETED) 9431 scfdie(); 9432 9433 goto snap_deleted; 9434 } 9435 } else { 9436 *cp++ = '['; 9437 *cp++ = ':'; 9438 9439 if (scf_instance_get_name(cur_inst, cp, 9440 max_scf_name_len + 1) < 0) { 9441 if (scf_error() != SCF_ERROR_DELETED) 9442 scfdie(); 9443 9444 goto snap_deleted; 9445 } 9446 9447 (void) strcat(buf, "]"); 9448 } 9449 9450 return; 9451 9452 snap_deleted: 9453 deleted = B_TRUE; 9454 free(buf); 9455 unselect_cursnap(); 9456 } 9457 9458 assert(cur_snap == NULL); 9459 9460 if (cur_inst != NULL) { 9461 assert(cur_svc != NULL); 9462 assert(cur_scope != NULL); 9463 9464 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 9465 if (fmrilen >= 0) { 9466 assert(fmrilen < bufsz); 9467 if (deleted) 9468 warn(emsg_deleted); 9469 return; 9470 } 9471 9472 if (scf_error() != SCF_ERROR_DELETED) 9473 scfdie(); 9474 9475 deleted = B_TRUE; 9476 9477 scf_instance_destroy(cur_inst); 9478 cur_inst = NULL; 9479 } 9480 9481 if (cur_svc != NULL) { 9482 assert(cur_scope != NULL); 9483 9484 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 9485 if (szret >= 0) { 9486 assert(szret < bufsz); 9487 if (deleted) 9488 warn(emsg_deleted); 9489 return; 9490 } 9491 9492 if (scf_error() != SCF_ERROR_DELETED) 9493 scfdie(); 9494 9495 deleted = B_TRUE; 9496 scf_service_destroy(cur_svc); 9497 cur_svc = NULL; 9498 } 9499 9500 assert(cur_scope != NULL); 9501 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 9502 9503 if (fmrilen < 0) 9504 scfdie(); 9505 9506 assert(fmrilen < bufsz); 9507 if (deleted) 9508 warn(emsg_deleted); 9509 } 9510 9511 /* 9512 * Entity listing. Entities and colon namespaces (e.g., :properties and 9513 * :statistics) are listed for the current selection. 9514 */ 9515 void 9516 lscf_list(const char *pattern) 9517 { 9518 scf_iter_t *iter; 9519 char *buf; 9520 int ret; 9521 9522 lscf_prep_hndl(); 9523 9524 if (cur_level != NULL) { 9525 struct snaplevel *elt; 9526 9527 (void) fputs(COLON_NAMESPACES, stdout); 9528 9529 elt = uu_list_next(cur_levels, cur_elt); 9530 if (elt == NULL) 9531 return; 9532 9533 /* 9534 * For now, we know that the next level is an instance. But 9535 * if we ever have multiple scopes, this could be complicated. 9536 */ 9537 buf = safe_malloc(max_scf_name_len + 1); 9538 if (scf_snaplevel_get_instance_name(elt->sl, buf, 9539 max_scf_name_len + 1) >= 0) { 9540 (void) puts(buf); 9541 } else { 9542 if (scf_error() != SCF_ERROR_DELETED) 9543 scfdie(); 9544 } 9545 9546 free(buf); 9547 9548 return; 9549 } 9550 9551 if (cur_inst != NULL) { 9552 (void) fputs(COLON_NAMESPACES, stdout); 9553 return; 9554 } 9555 9556 iter = scf_iter_create(g_hndl); 9557 if (iter == NULL) 9558 scfdie(); 9559 9560 buf = safe_malloc(max_scf_name_len + 1); 9561 9562 if (cur_svc != NULL) { 9563 /* List the instances in this service. */ 9564 scf_instance_t *inst; 9565 9566 inst = scf_instance_create(g_hndl); 9567 if (inst == NULL) 9568 scfdie(); 9569 9570 if (scf_iter_service_instances(iter, cur_svc) == 0) { 9571 safe_printf(COLON_NAMESPACES); 9572 9573 for (;;) { 9574 ret = scf_iter_next_instance(iter, inst); 9575 if (ret == 0) 9576 break; 9577 if (ret != 1) { 9578 if (scf_error() != SCF_ERROR_DELETED) 9579 scfdie(); 9580 9581 break; 9582 } 9583 9584 if (scf_instance_get_name(inst, buf, 9585 max_scf_name_len + 1) >= 0) { 9586 if (pattern == NULL || 9587 fnmatch(pattern, buf, 0) == 0) 9588 (void) puts(buf); 9589 } else { 9590 if (scf_error() != SCF_ERROR_DELETED) 9591 scfdie(); 9592 } 9593 } 9594 } else { 9595 if (scf_error() != SCF_ERROR_DELETED) 9596 scfdie(); 9597 } 9598 9599 scf_instance_destroy(inst); 9600 } else { 9601 /* List the services in this scope. */ 9602 scf_service_t *svc; 9603 9604 assert(cur_scope != NULL); 9605 9606 svc = scf_service_create(g_hndl); 9607 if (svc == NULL) 9608 scfdie(); 9609 9610 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 9611 scfdie(); 9612 9613 for (;;) { 9614 ret = scf_iter_next_service(iter, svc); 9615 if (ret == 0) 9616 break; 9617 if (ret != 1) 9618 scfdie(); 9619 9620 if (scf_service_get_name(svc, buf, 9621 max_scf_name_len + 1) >= 0) { 9622 if (pattern == NULL || 9623 fnmatch(pattern, buf, 0) == 0) 9624 safe_printf("%s\n", buf); 9625 } else { 9626 if (scf_error() != SCF_ERROR_DELETED) 9627 scfdie(); 9628 } 9629 } 9630 9631 scf_service_destroy(svc); 9632 } 9633 9634 free(buf); 9635 scf_iter_destroy(iter); 9636 } 9637 9638 /* 9639 * Entity addition. Creates an empty entity in the current selection. 9640 */ 9641 void 9642 lscf_add(const char *name) 9643 { 9644 lscf_prep_hndl(); 9645 9646 if (cur_snap != NULL) { 9647 semerr(emsg_cant_modify_snapshots); 9648 } else if (cur_inst != NULL) { 9649 semerr(gettext("Cannot add entities to an instance.\n")); 9650 } else if (cur_svc != NULL) { 9651 9652 if (scf_service_add_instance(cur_svc, name, NULL) != 9653 SCF_SUCCESS) { 9654 switch (scf_error()) { 9655 case SCF_ERROR_INVALID_ARGUMENT: 9656 semerr(gettext("Invalid name.\n")); 9657 break; 9658 9659 case SCF_ERROR_EXISTS: 9660 semerr(gettext("Instance already exists.\n")); 9661 break; 9662 9663 case SCF_ERROR_PERMISSION_DENIED: 9664 semerr(emsg_permission_denied); 9665 break; 9666 9667 default: 9668 scfdie(); 9669 } 9670 } 9671 } else { 9672 assert(cur_scope != NULL); 9673 9674 if (scf_scope_add_service(cur_scope, name, NULL) != 9675 SCF_SUCCESS) { 9676 switch (scf_error()) { 9677 case SCF_ERROR_INVALID_ARGUMENT: 9678 semerr(gettext("Invalid name.\n")); 9679 break; 9680 9681 case SCF_ERROR_EXISTS: 9682 semerr(gettext("Service already exists.\n")); 9683 break; 9684 9685 case SCF_ERROR_PERMISSION_DENIED: 9686 semerr(emsg_permission_denied); 9687 break; 9688 9689 case SCF_ERROR_BACKEND_READONLY: 9690 semerr(emsg_read_only); 9691 break; 9692 9693 default: 9694 scfdie(); 9695 } 9696 } 9697 } 9698 } 9699 9700 /* 9701 * Entity deletion. 9702 */ 9703 9704 /* 9705 * Delete the property group <fmri>/:properties/<name>. Returns 9706 * SCF_ERROR_NONE on success (or if the entity is not found), 9707 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 9708 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 9709 * denied. 9710 */ 9711 static scf_error_t 9712 delete_dependency_pg(const char *fmri, const char *name) 9713 { 9714 void *entity = NULL; 9715 int isservice; 9716 scf_propertygroup_t *pg = NULL; 9717 scf_error_t result; 9718 char *pgty; 9719 9720 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 9721 switch (result) { 9722 case SCF_ERROR_NONE: 9723 break; 9724 9725 case SCF_ERROR_NO_MEMORY: 9726 uu_die(gettext("Out of memory.\n")); 9727 /* NOTREACHED */ 9728 9729 case SCF_ERROR_INVALID_ARGUMENT: 9730 case SCF_ERROR_CONSTRAINT_VIOLATED: 9731 return (SCF_ERROR_INVALID_ARGUMENT); 9732 9733 case SCF_ERROR_NOT_FOUND: 9734 result = SCF_ERROR_NONE; 9735 goto out; 9736 9737 default: 9738 bad_error("fmri_to_entity", result); 9739 } 9740 9741 pg = scf_pg_create(g_hndl); 9742 if (pg == NULL) 9743 scfdie(); 9744 9745 if (entity_get_pg(entity, isservice, name, pg) != 0) { 9746 if (scf_error() != SCF_ERROR_NOT_FOUND) 9747 scfdie(); 9748 9749 result = SCF_ERROR_NONE; 9750 goto out; 9751 } 9752 9753 pgty = safe_malloc(max_scf_pg_type_len + 1); 9754 9755 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 9756 scfdie(); 9757 9758 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 9759 result = SCF_ERROR_TYPE_MISMATCH; 9760 free(pgty); 9761 goto out; 9762 } 9763 9764 free(pgty); 9765 9766 if (scf_pg_delete(pg) == 0) { 9767 scf_instance_t *inst = NULL; 9768 scf_iter_t *iter = NULL; 9769 char *name_buf = NULL; 9770 9771 result = SCF_ERROR_NONE; 9772 9773 if (isservice) { 9774 if ((inst = scf_instance_create(g_hndl)) == NULL || 9775 (iter = scf_iter_create(g_hndl)) == NULL) 9776 scfdie(); 9777 9778 name_buf = safe_malloc(max_scf_name_len + 1); 9779 } 9780 (void) refresh_entity(isservice, entity, fmri, inst, iter, 9781 name_buf); 9782 9783 free(name_buf); 9784 scf_iter_destroy(iter); 9785 scf_instance_destroy(inst); 9786 } else if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 9787 scfdie(); 9788 else 9789 result = SCF_ERROR_PERMISSION_DENIED; 9790 9791 out: 9792 scf_pg_destroy(pg); 9793 if (entity != NULL) 9794 entity_destroy(entity, isservice); 9795 9796 return (result); 9797 } 9798 9799 static int 9800 delete_dependents(scf_propertygroup_t *pg) 9801 { 9802 char *pgty, *name, *fmri; 9803 scf_property_t *prop; 9804 scf_value_t *val; 9805 scf_iter_t *iter; 9806 int r; 9807 scf_error_t err; 9808 9809 /* Verify that the pg has the correct type. */ 9810 pgty = safe_malloc(max_scf_pg_type_len + 1); 9811 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 9812 scfdie(); 9813 9814 if (strcmp(pgty, scf_group_framework) != 0) { 9815 if (g_verbose) { 9816 fmri = safe_malloc(max_scf_fmri_len + 1); 9817 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 9818 scfdie(); 9819 9820 warn(gettext("Property group %s is not of expected " 9821 "type %s.\n"), fmri, scf_group_framework); 9822 9823 free(fmri); 9824 } 9825 9826 free(pgty); 9827 return (-1); 9828 } 9829 9830 free(pgty); 9831 9832 /* map delete_dependency_pg onto the properties. */ 9833 if ((prop = scf_property_create(g_hndl)) == NULL || 9834 (val = scf_value_create(g_hndl)) == NULL || 9835 (iter = scf_iter_create(g_hndl)) == NULL) 9836 scfdie(); 9837 9838 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 9839 scfdie(); 9840 9841 name = safe_malloc(max_scf_name_len + 1); 9842 fmri = safe_malloc(max_scf_fmri_len + 2); 9843 9844 while ((r = scf_iter_next_property(iter, prop)) == 1) { 9845 scf_type_t ty; 9846 9847 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 9848 scfdie(); 9849 9850 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 9851 scfdie(); 9852 9853 if ((ty != SCF_TYPE_ASTRING && 9854 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 9855 prop_get_val(prop, val) != 0) 9856 continue; 9857 9858 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 9859 scfdie(); 9860 9861 err = delete_dependency_pg(fmri, name); 9862 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 9863 if (scf_property_to_fmri(prop, fmri, 9864 max_scf_fmri_len + 2) < 0) 9865 scfdie(); 9866 9867 warn(gettext("Value of %s is not a valid FMRI.\n"), 9868 fmri); 9869 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 9870 warn(gettext("Property group \"%s\" of entity \"%s\" " 9871 "does not have dependency type.\n"), name, fmri); 9872 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 9873 warn(gettext("Could not delete property group \"%s\" " 9874 "of entity \"%s\" (permission denied).\n"), name, 9875 fmri); 9876 } 9877 } 9878 if (r == -1) 9879 scfdie(); 9880 9881 scf_value_destroy(val); 9882 scf_property_destroy(prop); 9883 9884 return (0); 9885 } 9886 9887 /* 9888 * Returns 1 if the instance may be running, and 0 otherwise. 9889 */ 9890 static int 9891 inst_is_running(scf_instance_t *inst) 9892 { 9893 scf_propertygroup_t *pg; 9894 scf_property_t *prop; 9895 scf_value_t *val; 9896 char buf[MAX_SCF_STATE_STRING_SZ]; 9897 int ret = 0; 9898 ssize_t szret; 9899 9900 if ((pg = scf_pg_create(g_hndl)) == NULL || 9901 (prop = scf_property_create(g_hndl)) == NULL || 9902 (val = scf_value_create(g_hndl)) == NULL) 9903 scfdie(); 9904 9905 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 9906 if (scf_error() != SCF_ERROR_NOT_FOUND) 9907 scfdie(); 9908 goto out; 9909 } 9910 9911 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 9912 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 9913 prop_get_val(prop, val) != 0) 9914 goto out; 9915 9916 szret = scf_value_get_astring(val, buf, sizeof (buf)); 9917 assert(szret >= 0); 9918 9919 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 9920 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 9921 9922 out: 9923 scf_value_destroy(val); 9924 scf_property_destroy(prop); 9925 scf_pg_destroy(pg); 9926 return (ret); 9927 } 9928 9929 static int 9930 lscf_instance_delete(scf_instance_t *inst, int force) 9931 { 9932 scf_propertygroup_t *pg; 9933 9934 /* If we're not forcing and the instance is running, refuse. */ 9935 if (!force && inst_is_running(inst)) { 9936 char *fmri; 9937 9938 fmri = safe_malloc(max_scf_fmri_len + 1); 9939 9940 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 9941 scfdie(); 9942 9943 semerr(gettext("Instance %s may be running. " 9944 "Use delete -f if it is not.\n"), fmri); 9945 9946 free(fmri); 9947 return (-1); 9948 } 9949 9950 pg = scf_pg_create(g_hndl); 9951 if (pg == NULL) 9952 scfdie(); 9953 9954 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == SCF_SUCCESS) 9955 (void) delete_dependents(pg); 9956 else if (scf_error() != SCF_ERROR_NOT_FOUND) 9957 scfdie(); 9958 9959 scf_pg_destroy(pg); 9960 9961 if (scf_instance_delete(inst) != SCF_SUCCESS) { 9962 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 9963 scfdie(); 9964 9965 semerr(emsg_permission_denied); 9966 9967 return (-1); 9968 } 9969 9970 return (0); 9971 } 9972 9973 static int 9974 lscf_service_delete(scf_service_t *svc, int force) 9975 { 9976 int r; 9977 scf_instance_t *inst; 9978 scf_propertygroup_t *pg; 9979 scf_iter_t *iter; 9980 9981 if ((inst = scf_instance_create(g_hndl)) == NULL || 9982 (pg = scf_pg_create(g_hndl)) == NULL || 9983 (iter = scf_iter_create(g_hndl)) == NULL) 9984 scfdie(); 9985 9986 if (scf_iter_service_instances(iter, svc) != SCF_SUCCESS) 9987 scfdie(); 9988 9989 for (r = scf_iter_next_instance(iter, inst); 9990 r == 1; 9991 r = scf_iter_next_instance(iter, inst)) { 9992 if (lscf_instance_delete(inst, force) == -1) { 9993 scf_iter_destroy(iter); 9994 scf_pg_destroy(pg); 9995 scf_instance_destroy(inst); 9996 return (-1); 9997 } 9998 } 9999 10000 if (r != 0) 10001 scfdie(); 10002 10003 /* Delete dependency property groups in dependent services. */ 10004 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == SCF_SUCCESS) 10005 (void) delete_dependents(pg); 10006 else if (scf_error() != SCF_ERROR_NOT_FOUND) 10007 scfdie(); 10008 10009 scf_iter_destroy(iter); 10010 scf_pg_destroy(pg); 10011 scf_instance_destroy(inst); 10012 10013 if (r != 0) 10014 return (-1); 10015 10016 if (scf_service_delete(svc) == SCF_SUCCESS) 10017 return (0); 10018 10019 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10020 scfdie(); 10021 10022 semerr(emsg_permission_denied); 10023 return (-1); 10024 } 10025 10026 static int 10027 delete_callback(void *data, scf_walkinfo_t *wip) 10028 { 10029 int force = (int)data; 10030 10031 if (wip->inst != NULL) 10032 (void) lscf_instance_delete(wip->inst, force); 10033 else 10034 (void) lscf_service_delete(wip->svc, force); 10035 10036 return (0); 10037 } 10038 10039 void 10040 lscf_delete(const char *fmri, int force) 10041 { 10042 scf_service_t *svc; 10043 scf_instance_t *inst; 10044 int ret; 10045 10046 lscf_prep_hndl(); 10047 10048 if (cur_snap != NULL) { 10049 if (!snaplevel_is_instance(cur_level)) { 10050 char *buf; 10051 10052 buf = safe_malloc(max_scf_name_len + 1); 10053 if (scf_instance_get_name(cur_inst, buf, 10054 max_scf_name_len + 1) >= 0) { 10055 if (strcmp(buf, fmri) == 0) { 10056 semerr(emsg_cant_modify_snapshots); 10057 free(buf); 10058 return; 10059 } 10060 } else if (scf_error() != SCF_ERROR_DELETED) { 10061 scfdie(); 10062 } 10063 free(buf); 10064 } 10065 } else if (cur_inst != NULL) { 10066 /* EMPTY */; 10067 } else if (cur_svc != NULL) { 10068 inst = scf_instance_create(g_hndl); 10069 if (inst == NULL) 10070 scfdie(); 10071 10072 if (scf_service_get_instance(cur_svc, fmri, inst) == 10073 SCF_SUCCESS) { 10074 (void) lscf_instance_delete(inst, force); 10075 scf_instance_destroy(inst); 10076 return; 10077 } 10078 10079 if (scf_error() != SCF_ERROR_NOT_FOUND && 10080 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 10081 scfdie(); 10082 10083 scf_instance_destroy(inst); 10084 } else { 10085 assert(cur_scope != NULL); 10086 10087 svc = scf_service_create(g_hndl); 10088 if (svc == NULL) 10089 scfdie(); 10090 10091 if (scf_scope_get_service(cur_scope, fmri, svc) == 10092 SCF_SUCCESS) { 10093 (void) lscf_service_delete(svc, force); 10094 scf_service_destroy(svc); 10095 return; 10096 } 10097 10098 if (scf_error() != SCF_ERROR_NOT_FOUND && 10099 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 10100 scfdie(); 10101 10102 scf_service_destroy(svc); 10103 } 10104 10105 /* 10106 * Match FMRI to entity. 10107 */ 10108 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 10109 delete_callback, (void *)force, NULL, semerr)) != 0) { 10110 semerr(gettext("Failed to walk instances: %s\n"), 10111 scf_strerror(ret)); 10112 } 10113 } 10114 10115 10116 10117 /* 10118 * :properties commands. These all end with "pg" or "prop" and generally 10119 * operate on the currently selected entity. 10120 */ 10121 10122 /* 10123 * Property listing. List the property groups, properties, their types and 10124 * their values for the currently selected entity. 10125 */ 10126 static void 10127 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 10128 { 10129 char *buf; 10130 uint32_t flags; 10131 10132 buf = safe_malloc(max_scf_pg_type_len + 1); 10133 10134 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 10135 scfdie(); 10136 10137 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 10138 scfdie(); 10139 10140 safe_printf("%-*s %s", namewidth, name, buf); 10141 10142 if (flags & SCF_PG_FLAG_NONPERSISTENT) 10143 safe_printf("\tNONPERSISTENT"); 10144 10145 safe_printf("\n"); 10146 10147 free(buf); 10148 } 10149 10150 static boolean_t 10151 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 10152 { 10153 if (scf_property_get_value(prop, val) == 0) { 10154 return (B_FALSE); 10155 } else { 10156 switch (scf_error()) { 10157 case SCF_ERROR_NOT_FOUND: 10158 return (B_FALSE); 10159 case SCF_ERROR_CONSTRAINT_VIOLATED: 10160 return (B_TRUE); 10161 default: 10162 scfdie(); 10163 /*NOTREACHED*/ 10164 } 10165 } 10166 } 10167 10168 static void 10169 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 10170 { 10171 scf_iter_t *iter; 10172 scf_value_t *val; 10173 const char *type; 10174 int multiple_strings = 0; 10175 int ret; 10176 10177 if ((iter = scf_iter_create(g_hndl)) == NULL || 10178 (val = scf_value_create(g_hndl)) == NULL) 10179 scfdie(); 10180 10181 type = prop_to_typestr(prop); 10182 assert(type != NULL); 10183 10184 safe_printf("%-*s %-7s ", len, name, type); 10185 10186 if (prop_has_multiple_values(prop, val) && 10187 (scf_value_type(val) == SCF_TYPE_ASTRING || 10188 scf_value_type(val) == SCF_TYPE_USTRING)) 10189 multiple_strings = 1; 10190 10191 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 10192 scfdie(); 10193 10194 while ((ret = scf_iter_next_value(iter, val)) == 1) { 10195 char *buf; 10196 ssize_t vlen, szret; 10197 10198 vlen = scf_value_get_as_string(val, NULL, 0); 10199 if (vlen < 0) 10200 scfdie(); 10201 10202 buf = safe_malloc(vlen + 1); 10203 10204 szret = scf_value_get_as_string(val, buf, vlen + 1); 10205 if (szret < 0) 10206 scfdie(); 10207 assert(szret <= vlen); 10208 10209 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 10210 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 10211 safe_printf(" \""); 10212 (void) quote_and_print(buf, stdout, 0); 10213 (void) putchar('"'); 10214 if (ferror(stdout)) { 10215 (void) putchar('\n'); 10216 uu_die(gettext("Error writing to stdout.\n")); 10217 } 10218 } else { 10219 safe_printf(" %s", buf); 10220 } 10221 10222 free(buf); 10223 } 10224 if (ret != 0) 10225 scfdie(); 10226 10227 if (putchar('\n') != '\n') 10228 uu_die(gettext("Could not output newline")); 10229 } 10230 10231 static void 10232 listprop(const char *pattern, int only_pgs) 10233 { 10234 scf_propertygroup_t *pg; 10235 scf_property_t *prop; 10236 scf_iter_t *iter, *piter; 10237 char *pgnbuf, *prnbuf, *ppnbuf; 10238 10239 void **objects; 10240 char **names; 10241 int allocd, i; 10242 10243 int ret; 10244 ssize_t pgnlen, prnlen, szret; 10245 size_t max_len = 0; 10246 10247 if (cur_svc == NULL && cur_inst == NULL) { 10248 semerr(emsg_entity_not_selected); 10249 return; 10250 } 10251 10252 if ((pg = scf_pg_create(g_hndl)) == NULL || 10253 (prop = scf_property_create(g_hndl)) == NULL || 10254 (iter = scf_iter_create(g_hndl)) == NULL || 10255 (piter = scf_iter_create(g_hndl)) == NULL) 10256 scfdie(); 10257 10258 prnbuf = safe_malloc(max_scf_name_len + 1); 10259 10260 if (cur_level != NULL) 10261 ret = scf_iter_snaplevel_pgs(iter, cur_level); 10262 else if (cur_inst != NULL) 10263 ret = scf_iter_instance_pgs(iter, cur_inst); 10264 else 10265 ret = scf_iter_service_pgs(iter, cur_svc); 10266 if (ret != 0) { 10267 if (scf_error() == SCF_ERROR_DELETED) 10268 scfdie(); 10269 return; 10270 } 10271 10272 /* 10273 * We want to only list items which match pattern, and we want the 10274 * second column to line up, so during the first pass we'll save 10275 * matching items & their names in objects and names, computing the 10276 * maximum name length as we go, and then we'll print them out. 10277 * 10278 * Note: We always keep an extra slot available so the array can be 10279 * NULL-terminated. 10280 */ 10281 i = 0; 10282 allocd = 1; 10283 objects = safe_malloc(sizeof (*objects)); 10284 names = safe_malloc(sizeof (*names)); 10285 10286 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 10287 int new_pg = 0; 10288 10289 pgnlen = scf_pg_get_name(pg, NULL, 0); 10290 if (pgnlen < 0) 10291 scfdie(); 10292 10293 pgnbuf = safe_malloc(pgnlen + 1); 10294 10295 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 10296 if (szret < 0) 10297 scfdie(); 10298 assert(szret <= pgnlen); 10299 10300 if (pattern == NULL || 10301 fnmatch(pattern, pgnbuf, 0) == 0) { 10302 if (i+1 >= allocd) { 10303 allocd *= 2; 10304 objects = realloc(objects, 10305 sizeof (*objects) * allocd); 10306 names = 10307 realloc(names, sizeof (*names) * allocd); 10308 if (objects == NULL || names == NULL) 10309 uu_die(gettext("Out of memory")); 10310 } 10311 objects[i] = pg; 10312 names[i] = pgnbuf; 10313 ++i; 10314 10315 if (pgnlen > max_len) 10316 max_len = pgnlen; 10317 10318 new_pg = 1; 10319 } 10320 10321 if (only_pgs) { 10322 if (new_pg) { 10323 pg = scf_pg_create(g_hndl); 10324 if (pg == NULL) 10325 scfdie(); 10326 } else 10327 free(pgnbuf); 10328 10329 continue; 10330 } 10331 10332 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 10333 scfdie(); 10334 10335 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 10336 prnlen = scf_property_get_name(prop, prnbuf, 10337 max_scf_name_len + 1); 10338 if (prnlen < 0) 10339 scfdie(); 10340 10341 /* Will prepend the property group name and a slash. */ 10342 prnlen += pgnlen + 1; 10343 10344 ppnbuf = safe_malloc(prnlen + 1); 10345 10346 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 10347 prnbuf) < 0) 10348 uu_die("snprintf"); 10349 10350 if (pattern == NULL || 10351 fnmatch(pattern, ppnbuf, 0) == 0) { 10352 if (i+1 >= allocd) { 10353 allocd *= 2; 10354 objects = realloc(objects, 10355 sizeof (*objects) * allocd); 10356 names = realloc(names, 10357 sizeof (*names) * allocd); 10358 if (objects == NULL || names == NULL) 10359 uu_die(gettext("Out of " 10360 "memory")); 10361 } 10362 10363 objects[i] = prop; 10364 names[i] = ppnbuf; 10365 ++i; 10366 10367 if (prnlen > max_len) 10368 max_len = prnlen; 10369 10370 prop = scf_property_create(g_hndl); 10371 } else { 10372 free(ppnbuf); 10373 } 10374 } 10375 10376 if (new_pg) { 10377 pg = scf_pg_create(g_hndl); 10378 if (pg == NULL) 10379 scfdie(); 10380 } else 10381 free(pgnbuf); 10382 } 10383 if (ret != 0) 10384 scfdie(); 10385 10386 objects[i] = NULL; 10387 10388 scf_pg_destroy(pg); 10389 scf_property_destroy(prop); 10390 10391 for (i = 0; objects[i] != NULL; ++i) { 10392 if (strchr(names[i], '/') == NULL) { 10393 /* property group */ 10394 pg = (scf_propertygroup_t *)objects[i]; 10395 list_pg_info(pg, names[i], max_len); 10396 free(names[i]); 10397 scf_pg_destroy(pg); 10398 } else { 10399 /* property */ 10400 prop = (scf_property_t *)objects[i]; 10401 list_prop_info(prop, names[i], max_len); 10402 free(names[i]); 10403 scf_property_destroy(prop); 10404 } 10405 } 10406 10407 free(names); 10408 free(objects); 10409 } 10410 10411 void 10412 lscf_listpg(const char *pattern) 10413 { 10414 lscf_prep_hndl(); 10415 10416 listprop(pattern, 1); 10417 } 10418 10419 /* 10420 * Property group and property creation, setting, and deletion. setprop (and 10421 * its alias, addprop) can either create a property group of a given type, or 10422 * it can create or set a property to a given type and list of values. 10423 */ 10424 void 10425 lscf_addpg(const char *name, const char *type, const char *flags) 10426 { 10427 scf_propertygroup_t *pg; 10428 int ret; 10429 uint32_t flgs = 0; 10430 const char *cp; 10431 10432 10433 lscf_prep_hndl(); 10434 10435 if (cur_snap != NULL) { 10436 semerr(emsg_cant_modify_snapshots); 10437 return; 10438 } 10439 10440 if (cur_inst == NULL && cur_svc == NULL) { 10441 semerr(emsg_entity_not_selected); 10442 return; 10443 } 10444 10445 if (flags != NULL) { 10446 for (cp = flags; *cp != '\0'; ++cp) { 10447 switch (*cp) { 10448 case 'P': 10449 flgs |= SCF_PG_FLAG_NONPERSISTENT; 10450 break; 10451 10452 case 'p': 10453 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 10454 break; 10455 10456 default: 10457 semerr(gettext("Invalid property group flag " 10458 "%c."), *cp); 10459 return; 10460 } 10461 } 10462 } 10463 10464 pg = scf_pg_create(g_hndl); 10465 if (pg == NULL) 10466 scfdie(); 10467 10468 if (cur_inst != NULL) 10469 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 10470 else 10471 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 10472 10473 if (ret != SCF_SUCCESS) { 10474 switch (scf_error()) { 10475 case SCF_ERROR_INVALID_ARGUMENT: 10476 semerr(gettext("Name, type, or flags are invalid.\n")); 10477 break; 10478 10479 case SCF_ERROR_EXISTS: 10480 semerr(gettext("Property group already exists.\n")); 10481 break; 10482 10483 case SCF_ERROR_PERMISSION_DENIED: 10484 semerr(emsg_permission_denied); 10485 break; 10486 10487 case SCF_ERROR_BACKEND_ACCESS: 10488 semerr(gettext("Backend refused access.\n")); 10489 break; 10490 10491 default: 10492 scfdie(); 10493 } 10494 } 10495 10496 scf_pg_destroy(pg); 10497 } 10498 10499 void 10500 lscf_delpg(char *name) 10501 { 10502 lscf_prep_hndl(); 10503 10504 if (cur_snap != NULL) { 10505 semerr(emsg_cant_modify_snapshots); 10506 return; 10507 } 10508 10509 if (cur_inst == NULL && cur_svc == NULL) { 10510 semerr(emsg_entity_not_selected); 10511 return; 10512 } 10513 10514 if (strchr(name, '/') != NULL) { 10515 semerr(emsg_invalid_pg_name, name); 10516 return; 10517 } 10518 10519 lscf_delprop(name); 10520 } 10521 10522 void 10523 lscf_listprop(const char *pattern) 10524 { 10525 lscf_prep_hndl(); 10526 10527 listprop(pattern, 0); 10528 } 10529 10530 int 10531 lscf_setprop(const char *pgname, const char *type, const char *value, 10532 const uu_list_t *values) 10533 { 10534 scf_type_t ty; 10535 scf_propertygroup_t *pg; 10536 scf_property_t *prop; 10537 int ret, result = 0; 10538 scf_transaction_t *tx; 10539 scf_transaction_entry_t *e; 10540 scf_value_t *v; 10541 uu_list_walk_t *walk; 10542 string_list_t *sp; 10543 char *propname; 10544 int req_quotes = 0; 10545 10546 lscf_prep_hndl(); 10547 10548 if ((e = scf_entry_create(g_hndl)) == NULL || 10549 (pg = scf_pg_create(g_hndl)) == NULL || 10550 (prop = scf_property_create(g_hndl)) == NULL || 10551 (tx = scf_transaction_create(g_hndl)) == NULL) 10552 scfdie(); 10553 10554 if (cur_snap != NULL) { 10555 semerr(emsg_cant_modify_snapshots); 10556 goto fail; 10557 } 10558 10559 if (cur_inst == NULL && cur_svc == NULL) { 10560 semerr(emsg_entity_not_selected); 10561 goto fail; 10562 } 10563 10564 propname = strchr(pgname, '/'); 10565 if (propname == NULL) { 10566 semerr(gettext("Property names must contain a `/'.\n")); 10567 goto fail; 10568 } 10569 10570 *propname = '\0'; 10571 ++propname; 10572 10573 if (type != NULL) { 10574 ty = string_to_type(type); 10575 if (ty == SCF_TYPE_INVALID) { 10576 semerr(gettext("Unknown type \"%s\".\n"), type); 10577 goto fail; 10578 } 10579 } 10580 10581 if (cur_inst != NULL) 10582 ret = scf_instance_get_pg(cur_inst, pgname, pg); 10583 else 10584 ret = scf_service_get_pg(cur_svc, pgname, pg); 10585 if (ret != SCF_SUCCESS) { 10586 switch (scf_error()) { 10587 case SCF_ERROR_NOT_FOUND: 10588 semerr(emsg_no_such_pg, pgname); 10589 goto fail; 10590 10591 case SCF_ERROR_INVALID_ARGUMENT: 10592 semerr(emsg_invalid_pg_name, pgname); 10593 goto fail; 10594 10595 default: 10596 scfdie(); 10597 break; 10598 } 10599 } 10600 10601 do { 10602 if (scf_pg_update(pg) == -1) 10603 scfdie(); 10604 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 10605 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10606 scfdie(); 10607 10608 semerr(emsg_permission_denied); 10609 goto fail; 10610 } 10611 10612 ret = scf_pg_get_property(pg, propname, prop); 10613 if (ret == SCF_SUCCESS) { 10614 scf_type_t current_ty; 10615 10616 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 10617 scfdie(); 10618 10619 if (type == NULL) 10620 ty = current_ty; 10621 if (scf_transaction_property_change_type(tx, e, 10622 propname, ty) == -1) 10623 scfdie(); 10624 10625 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 10626 if (type == NULL) { 10627 semerr( 10628 gettext("Type required for new properties.\n")); 10629 goto fail; 10630 } 10631 if (scf_transaction_property_new(tx, e, propname, 10632 ty) == -1) 10633 scfdie(); 10634 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 10635 semerr(emsg_invalid_prop_name, propname); 10636 goto fail; 10637 } else { 10638 scfdie(); 10639 } 10640 10641 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 10642 req_quotes = 1; 10643 10644 if (value != NULL) { 10645 v = string_to_value(value, ty, 0); 10646 10647 if (v == NULL) 10648 goto fail; 10649 10650 ret = scf_entry_add_value(e, v); 10651 assert(ret == SCF_SUCCESS); 10652 } else { 10653 assert(values != NULL); 10654 10655 walk = uu_list_walk_start((uu_list_t *)values, 10656 UU_WALK_REVERSE); 10657 if (walk == NULL) 10658 uu_die(gettext("Could not walk list")); 10659 10660 for (sp = uu_list_walk_next(walk); sp != NULL; 10661 sp = uu_list_walk_next(walk)) { 10662 v = string_to_value(sp->str, ty, req_quotes); 10663 10664 if (v == NULL) { 10665 scf_entry_destroy_children(e); 10666 goto fail; 10667 } 10668 10669 ret = scf_entry_add_value(e, v); 10670 assert(ret == SCF_SUCCESS); 10671 } 10672 uu_list_walk_end(walk); 10673 } 10674 result = scf_transaction_commit(tx); 10675 10676 scf_transaction_reset(tx); 10677 scf_entry_destroy_children(e); 10678 } while (result == 0); 10679 10680 if (result < 0) { 10681 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10682 scfdie(); 10683 10684 semerr(emsg_permission_denied); 10685 goto fail; 10686 } 10687 10688 scf_transaction_destroy(tx); 10689 scf_entry_destroy(e); 10690 scf_pg_destroy(pg); 10691 scf_property_destroy(prop); 10692 10693 return (0); 10694 10695 fail: 10696 scf_transaction_destroy(tx); 10697 scf_entry_destroy(e); 10698 scf_pg_destroy(pg); 10699 scf_property_destroy(prop); 10700 10701 return (-1); 10702 } 10703 10704 void 10705 lscf_delprop(char *pgn) 10706 { 10707 char *slash, *pn; 10708 scf_propertygroup_t *pg; 10709 scf_transaction_t *tx; 10710 scf_transaction_entry_t *e; 10711 int ret; 10712 10713 10714 lscf_prep_hndl(); 10715 10716 if (cur_snap != NULL) { 10717 semerr(emsg_cant_modify_snapshots); 10718 return; 10719 } 10720 10721 if (cur_inst == NULL && cur_svc == NULL) { 10722 semerr(emsg_entity_not_selected); 10723 return; 10724 } 10725 10726 pg = scf_pg_create(g_hndl); 10727 if (pg == NULL) 10728 scfdie(); 10729 10730 slash = strchr(pgn, '/'); 10731 if (slash == NULL) { 10732 pn = NULL; 10733 } else { 10734 *slash = '\0'; 10735 pn = slash + 1; 10736 } 10737 10738 if (cur_inst != NULL) 10739 ret = scf_instance_get_pg(cur_inst, pgn, pg); 10740 else 10741 ret = scf_service_get_pg(cur_svc, pgn, pg); 10742 if (ret != SCF_SUCCESS) { 10743 switch (scf_error()) { 10744 case SCF_ERROR_NOT_FOUND: 10745 semerr(emsg_no_such_pg, pgn); 10746 break; 10747 10748 case SCF_ERROR_INVALID_ARGUMENT: 10749 semerr(emsg_invalid_pg_name, pgn); 10750 break; 10751 10752 default: 10753 scfdie(); 10754 } 10755 10756 scf_pg_destroy(pg); 10757 10758 return; 10759 } 10760 10761 if (pn == NULL) { 10762 /* Try to delete the property group. */ 10763 if (scf_pg_delete(pg) != SCF_SUCCESS) { 10764 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10765 scfdie(); 10766 10767 semerr(emsg_permission_denied); 10768 } 10769 10770 scf_pg_destroy(pg); 10771 return; 10772 } 10773 10774 e = scf_entry_create(g_hndl); 10775 tx = scf_transaction_create(g_hndl); 10776 10777 do { 10778 if (scf_pg_update(pg) == -1) 10779 scfdie(); 10780 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 10781 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10782 scfdie(); 10783 10784 semerr(emsg_permission_denied); 10785 break; 10786 } 10787 10788 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 10789 if (scf_error() == SCF_ERROR_NOT_FOUND) { 10790 semerr(gettext("No such property %s/%s.\n"), 10791 pgn, pn); 10792 break; 10793 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 10794 semerr(emsg_invalid_prop_name, pn); 10795 break; 10796 } else { 10797 scfdie(); 10798 } 10799 } 10800 10801 ret = scf_transaction_commit(tx); 10802 10803 if (ret == 0) 10804 scf_transaction_reset(tx); 10805 } while (ret == 0); 10806 10807 if (ret < 0) { 10808 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10809 scfdie(); 10810 10811 semerr(emsg_permission_denied); 10812 } 10813 10814 scf_transaction_destroy(tx); 10815 scf_entry_destroy(e); 10816 scf_pg_destroy(pg); 10817 } 10818 10819 /* 10820 * Property editing. 10821 */ 10822 10823 static int 10824 write_edit_script(FILE *strm) 10825 { 10826 char *fmribuf; 10827 ssize_t fmrilen; 10828 10829 scf_propertygroup_t *pg; 10830 scf_property_t *prop; 10831 scf_value_t *val; 10832 scf_type_t ty; 10833 int ret, result = 0; 10834 scf_iter_t *iter, *piter, *viter; 10835 char *buf, *tybuf, *pname; 10836 const char *emsg_write_error; 10837 10838 10839 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 10840 10841 10842 /* select fmri */ 10843 if (cur_inst != NULL) { 10844 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 10845 if (fmrilen < 0) 10846 scfdie(); 10847 fmribuf = safe_malloc(fmrilen + 1); 10848 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 10849 scfdie(); 10850 } else { 10851 assert(cur_svc != NULL); 10852 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 10853 if (fmrilen < 0) 10854 scfdie(); 10855 fmribuf = safe_malloc(fmrilen + 1); 10856 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 10857 scfdie(); 10858 } 10859 10860 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 10861 warn(emsg_write_error, strerror(errno)); 10862 free(fmribuf); 10863 return (-1); 10864 } 10865 10866 free(fmribuf); 10867 10868 10869 if ((pg = scf_pg_create(g_hndl)) == NULL || 10870 (prop = scf_property_create(g_hndl)) == NULL || 10871 (val = scf_value_create(g_hndl)) == NULL || 10872 (iter = scf_iter_create(g_hndl)) == NULL || 10873 (piter = scf_iter_create(g_hndl)) == NULL || 10874 (viter = scf_iter_create(g_hndl)) == NULL) 10875 scfdie(); 10876 10877 buf = safe_malloc(max_scf_name_len + 1); 10878 tybuf = safe_malloc(max_scf_pg_type_len + 1); 10879 pname = safe_malloc(max_scf_name_len + 1); 10880 10881 if (cur_inst != NULL) 10882 ret = scf_iter_instance_pgs(iter, cur_inst); 10883 else 10884 ret = scf_iter_service_pgs(iter, cur_svc); 10885 if (ret != SCF_SUCCESS) 10886 scfdie(); 10887 10888 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 10889 int ret2; 10890 10891 /* 10892 * # delprop pg 10893 * # addpg pg type 10894 */ 10895 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 10896 scfdie(); 10897 10898 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 10899 scfdie(); 10900 10901 if (fprintf(strm, "# Property group \"%s\"\n" 10902 "# delprop %s\n" 10903 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 10904 warn(emsg_write_error, strerror(errno)); 10905 result = -1; 10906 goto out; 10907 } 10908 10909 /* # setprop pg/prop = (values) */ 10910 10911 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 10912 scfdie(); 10913 10914 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 10915 int first = 1; 10916 int ret3; 10917 int multiple; 10918 int is_str; 10919 scf_type_t bty; 10920 10921 if (scf_property_get_name(prop, pname, 10922 max_scf_name_len + 1) < 0) 10923 scfdie(); 10924 10925 if (scf_property_type(prop, &ty) != 0) 10926 scfdie(); 10927 10928 multiple = prop_has_multiple_values(prop, val); 10929 10930 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 10931 pname, scf_type_to_string(ty), multiple ? "(" : "") 10932 < 0) { 10933 warn(emsg_write_error, strerror(errno)); 10934 result = -1; 10935 goto out; 10936 } 10937 10938 (void) scf_type_base_type(ty, &bty); 10939 is_str = (bty == SCF_TYPE_ASTRING); 10940 10941 if (scf_iter_property_values(viter, prop) != 10942 SCF_SUCCESS) 10943 scfdie(); 10944 10945 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 10946 char *buf; 10947 ssize_t buflen; 10948 10949 buflen = scf_value_get_as_string(val, NULL, 0); 10950 if (buflen < 0) 10951 scfdie(); 10952 10953 buf = safe_malloc(buflen + 1); 10954 10955 if (scf_value_get_as_string(val, buf, 10956 buflen + 1) < 0) 10957 scfdie(); 10958 10959 if (first) 10960 first = 0; 10961 else { 10962 if (putc(' ', strm) != ' ') { 10963 warn(emsg_write_error, 10964 strerror(errno)); 10965 result = -1; 10966 goto out; 10967 } 10968 } 10969 10970 if ((is_str && multiple) || 10971 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 10972 (void) putc('"', strm); 10973 (void) quote_and_print(buf, strm, 1); 10974 (void) putc('"', strm); 10975 10976 if (ferror(strm)) { 10977 warn(emsg_write_error, 10978 strerror(errno)); 10979 result = -1; 10980 goto out; 10981 } 10982 } else { 10983 if (fprintf(strm, "%s", buf) < 0) { 10984 warn(emsg_write_error, 10985 strerror(errno)); 10986 result = -1; 10987 goto out; 10988 } 10989 } 10990 10991 free(buf); 10992 } 10993 if (ret3 < 0) 10994 scfdie(); 10995 10996 /* Write closing paren if mult-value property */ 10997 if ((multiple && putc(')', strm) == EOF) || 10998 10999 /* Write final newline */ 11000 fputc('\n', strm) == EOF) { 11001 warn(emsg_write_error, strerror(errno)); 11002 result = -1; 11003 goto out; 11004 } 11005 } 11006 if (ret2 < 0) 11007 scfdie(); 11008 11009 if (fputc('\n', strm) == EOF) { 11010 warn(emsg_write_error, strerror(errno)); 11011 result = -1; 11012 goto out; 11013 } 11014 } 11015 if (ret < 0) 11016 scfdie(); 11017 11018 out: 11019 free(pname); 11020 free(tybuf); 11021 free(buf); 11022 scf_iter_destroy(viter); 11023 scf_iter_destroy(piter); 11024 scf_iter_destroy(iter); 11025 scf_value_destroy(val); 11026 scf_property_destroy(prop); 11027 scf_pg_destroy(pg); 11028 11029 if (result == 0) { 11030 if (fflush(strm) != 0) { 11031 warn(emsg_write_error, strerror(errno)); 11032 return (-1); 11033 } 11034 } 11035 11036 return (result); 11037 } 11038 11039 int 11040 lscf_editprop() 11041 { 11042 char *buf, *editor; 11043 size_t bufsz; 11044 int tmpfd; 11045 char tempname[] = TEMP_FILE_PATTERN; 11046 11047 lscf_prep_hndl(); 11048 11049 if (cur_snap != NULL) { 11050 semerr(emsg_cant_modify_snapshots); 11051 return (-1); 11052 } 11053 11054 if (cur_svc == NULL && cur_inst == NULL) { 11055 semerr(emsg_entity_not_selected); 11056 return (-1); 11057 } 11058 11059 tmpfd = mkstemp(tempname); 11060 if (tmpfd == -1) { 11061 semerr(gettext("Could not create temporary file.\n")); 11062 return (-1); 11063 } 11064 11065 (void) strcpy(tempfilename, tempname); 11066 11067 tempfile = fdopen(tmpfd, "r+"); 11068 if (tempfile == NULL) { 11069 warn(gettext("Could not create temporary file.\n")); 11070 if (close(tmpfd) == -1) 11071 warn(gettext("Could not close temporary file: %s.\n"), 11072 strerror(errno)); 11073 11074 remove_tempfile(); 11075 11076 return (-1); 11077 } 11078 11079 if (write_edit_script(tempfile) == -1) { 11080 remove_tempfile(); 11081 return (-1); 11082 } 11083 11084 editor = getenv("EDITOR"); 11085 if (editor == NULL) 11086 editor = "vi"; 11087 11088 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 11089 buf = safe_malloc(bufsz); 11090 11091 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 11092 uu_die(gettext("Error creating editor command")); 11093 11094 if (system(buf) == -1) { 11095 semerr(gettext("Could not launch editor %s: %s\n"), editor, 11096 strerror(errno)); 11097 free(buf); 11098 remove_tempfile(); 11099 return (-1); 11100 } 11101 11102 free(buf); 11103 11104 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 11105 11106 remove_tempfile(); 11107 11108 return (0); 11109 } 11110 11111 static void 11112 add_string(uu_list_t *strlist, const char *str) 11113 { 11114 string_list_t *elem; 11115 elem = safe_malloc(sizeof (*elem)); 11116 uu_list_node_init(elem, &elem->node, string_pool); 11117 elem->str = safe_strdup(str); 11118 if (uu_list_prepend(strlist, elem) != 0) 11119 uu_die(gettext("libuutil error: %s\n"), 11120 uu_strerror(uu_error())); 11121 } 11122 11123 /* 11124 * Get all property values that don't match the given glob pattern, 11125 * if a pattern is specified. 11126 */ 11127 static void 11128 get_prop_values(scf_property_t *prop, uu_list_t *values, 11129 const char *pattern) 11130 { 11131 scf_iter_t *iter; 11132 scf_value_t *val; 11133 int ret; 11134 11135 if ((iter = scf_iter_create(g_hndl)) == NULL || 11136 (val = scf_value_create(g_hndl)) == NULL) 11137 scfdie(); 11138 11139 if (scf_iter_property_values(iter, prop) != 0) 11140 scfdie(); 11141 11142 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11143 char *buf; 11144 ssize_t vlen, szret; 11145 11146 vlen = scf_value_get_as_string(val, NULL, 0); 11147 if (vlen < 0) 11148 scfdie(); 11149 11150 buf = safe_malloc(vlen + 1); 11151 11152 szret = scf_value_get_as_string(val, buf, vlen + 1); 11153 if (szret < 0) 11154 scfdie(); 11155 assert(szret <= vlen); 11156 11157 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 11158 add_string(values, buf); 11159 11160 free(buf); 11161 } 11162 11163 if (ret == -1) 11164 scfdie(); 11165 11166 scf_value_destroy(val); 11167 scf_iter_destroy(iter); 11168 } 11169 11170 static int 11171 lscf_setpropvalue(const char *pgname, const char *type, 11172 const char *arg, int isadd, int isnotfoundok) 11173 { 11174 scf_type_t ty; 11175 scf_propertygroup_t *pg; 11176 scf_property_t *prop; 11177 int ret, result = 0; 11178 scf_transaction_t *tx; 11179 scf_transaction_entry_t *e; 11180 scf_value_t *v; 11181 string_list_t *sp; 11182 char *propname; 11183 uu_list_t *values; 11184 uu_list_walk_t *walk; 11185 void *cookie = NULL; 11186 char *pattern = NULL; 11187 11188 lscf_prep_hndl(); 11189 11190 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 11191 uu_die(gettext("Could not create property list: %s\n"), 11192 uu_strerror(uu_error())); 11193 11194 if (!isadd) 11195 pattern = safe_strdup(arg); 11196 11197 if ((e = scf_entry_create(g_hndl)) == NULL || 11198 (pg = scf_pg_create(g_hndl)) == NULL || 11199 (prop = scf_property_create(g_hndl)) == NULL || 11200 (tx = scf_transaction_create(g_hndl)) == NULL) 11201 scfdie(); 11202 11203 if (cur_snap != NULL) { 11204 semerr(emsg_cant_modify_snapshots); 11205 goto fail; 11206 } 11207 11208 if (cur_inst == NULL && cur_svc == NULL) { 11209 semerr(emsg_entity_not_selected); 11210 goto fail; 11211 } 11212 11213 propname = strchr(pgname, '/'); 11214 if (propname == NULL) { 11215 semerr(gettext("Property names must contain a `/'.\n")); 11216 goto fail; 11217 } 11218 11219 *propname = '\0'; 11220 ++propname; 11221 11222 if (type != NULL) { 11223 ty = string_to_type(type); 11224 if (ty == SCF_TYPE_INVALID) { 11225 semerr(gettext("Unknown type \"%s\".\n"), type); 11226 goto fail; 11227 } 11228 } 11229 11230 if (cur_inst != NULL) 11231 ret = scf_instance_get_pg(cur_inst, pgname, pg); 11232 else 11233 ret = scf_service_get_pg(cur_svc, pgname, pg); 11234 if (ret != 0) { 11235 switch (scf_error()) { 11236 case SCF_ERROR_NOT_FOUND: 11237 if (isnotfoundok) { 11238 result = 0; 11239 } else { 11240 semerr(emsg_no_such_pg, pgname); 11241 result = -1; 11242 } 11243 goto out; 11244 11245 case SCF_ERROR_INVALID_ARGUMENT: 11246 semerr(emsg_invalid_pg_name, pgname); 11247 goto fail; 11248 11249 default: 11250 scfdie(); 11251 } 11252 } 11253 11254 do { 11255 if (scf_pg_update(pg) == -1) 11256 scfdie(); 11257 if (scf_transaction_start(tx, pg) != 0) { 11258 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11259 scfdie(); 11260 11261 semerr(emsg_permission_denied); 11262 goto fail; 11263 } 11264 11265 ret = scf_pg_get_property(pg, propname, prop); 11266 if (ret == 0) { 11267 scf_type_t ptype; 11268 char *pat = pattern; 11269 11270 if (scf_property_type(prop, &ptype) != 0) 11271 scfdie(); 11272 11273 if (isadd) { 11274 if (type != NULL && ptype != ty) { 11275 semerr(gettext("Property \"%s\" is not " 11276 "of type \"%s\".\n"), propname, 11277 type); 11278 goto fail; 11279 } 11280 11281 pat = NULL; 11282 } else { 11283 size_t len = strlen(pat); 11284 if (len > 0 && pat[len - 1] == '\"') 11285 pat[len - 1] = '\0'; 11286 if (len > 0 && pat[0] == '\"') 11287 pat++; 11288 } 11289 11290 ty = ptype; 11291 11292 get_prop_values(prop, values, pat); 11293 11294 if (isadd) 11295 add_string(values, arg); 11296 11297 if (scf_transaction_property_change(tx, e, 11298 propname, ty) == -1) 11299 scfdie(); 11300 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 11301 if (isadd) { 11302 if (type == NULL) { 11303 semerr(gettext("Type required " 11304 "for new properties.\n")); 11305 goto fail; 11306 } 11307 11308 add_string(values, arg); 11309 11310 if (scf_transaction_property_new(tx, e, 11311 propname, ty) == -1) 11312 scfdie(); 11313 } else if (isnotfoundok) { 11314 result = 0; 11315 goto out; 11316 } else { 11317 semerr(gettext("No such property %s/%s.\n"), 11318 pgname, propname); 11319 result = -1; 11320 goto out; 11321 } 11322 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 11323 semerr(emsg_invalid_prop_name, propname); 11324 goto fail; 11325 } else { 11326 scfdie(); 11327 } 11328 11329 walk = uu_list_walk_start(values, UU_DEFAULT); 11330 if (walk == NULL) 11331 uu_die(gettext("Could not walk property list.\n")); 11332 11333 for (sp = uu_list_walk_next(walk); sp != NULL; 11334 sp = uu_list_walk_next(walk)) { 11335 v = string_to_value(sp->str, ty, 0); 11336 11337 if (v == NULL) { 11338 scf_entry_destroy_children(e); 11339 goto fail; 11340 } 11341 ret = scf_entry_add_value(e, v); 11342 assert(ret == 0); 11343 } 11344 uu_list_walk_end(walk); 11345 11346 result = scf_transaction_commit(tx); 11347 11348 scf_transaction_reset(tx); 11349 scf_entry_destroy_children(e); 11350 } while (result == 0); 11351 11352 if (result < 0) { 11353 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11354 scfdie(); 11355 11356 semerr(emsg_permission_denied); 11357 goto fail; 11358 } 11359 11360 result = 0; 11361 11362 out: 11363 scf_transaction_destroy(tx); 11364 scf_entry_destroy(e); 11365 scf_pg_destroy(pg); 11366 scf_property_destroy(prop); 11367 free(pattern); 11368 11369 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 11370 free(sp->str); 11371 free(sp); 11372 } 11373 11374 uu_list_destroy(values); 11375 11376 return (result); 11377 11378 fail: 11379 result = -1; 11380 goto out; 11381 } 11382 11383 int 11384 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 11385 { 11386 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 11387 } 11388 11389 int 11390 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 11391 { 11392 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 11393 } 11394 11395 /* 11396 * Look for a standard start method, first in the instance (if any), 11397 * then the service. 11398 */ 11399 static const char * 11400 start_method_name(int *in_instance) 11401 { 11402 scf_propertygroup_t *pg; 11403 char **p; 11404 int ret; 11405 scf_instance_t *inst = cur_inst; 11406 11407 if ((pg = scf_pg_create(g_hndl)) == NULL) 11408 scfdie(); 11409 11410 again: 11411 for (p = start_method_names; *p != NULL; p++) { 11412 if (inst != NULL) 11413 ret = scf_instance_get_pg(inst, *p, pg); 11414 else 11415 ret = scf_service_get_pg(cur_svc, *p, pg); 11416 11417 if (ret == 0) { 11418 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 11419 char *buf = safe_malloc(bufsz); 11420 11421 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 11422 free(buf); 11423 continue; 11424 } 11425 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 11426 free(buf); 11427 continue; 11428 } 11429 11430 free(buf); 11431 *in_instance = (inst != NULL); 11432 scf_pg_destroy(pg); 11433 return (*p); 11434 } 11435 11436 if (scf_error() == SCF_ERROR_NOT_FOUND) 11437 continue; 11438 11439 scfdie(); 11440 } 11441 11442 if (inst != NULL) { 11443 inst = NULL; 11444 goto again; 11445 } 11446 11447 scf_pg_destroy(pg); 11448 return (NULL); 11449 } 11450 11451 static int 11452 addpg(const char *name, const char *type) 11453 { 11454 scf_propertygroup_t *pg; 11455 int ret; 11456 11457 pg = scf_pg_create(g_hndl); 11458 if (pg == NULL) 11459 scfdie(); 11460 11461 if (cur_inst != NULL) 11462 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 11463 else 11464 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 11465 11466 if (ret != 0) { 11467 switch (scf_error()) { 11468 case SCF_ERROR_EXISTS: 11469 ret = 0; 11470 break; 11471 11472 case SCF_ERROR_PERMISSION_DENIED: 11473 semerr(emsg_permission_denied); 11474 break; 11475 11476 default: 11477 scfdie(); 11478 } 11479 } 11480 11481 scf_pg_destroy(pg); 11482 return (ret); 11483 } 11484 11485 int 11486 lscf_setenv(uu_list_t *args, int isunset) 11487 { 11488 int ret = 0; 11489 size_t i; 11490 int argc; 11491 char **argv = NULL; 11492 string_list_t *slp; 11493 char *pattern; 11494 char *prop; 11495 int do_service = 0; 11496 int do_instance = 0; 11497 const char *method = NULL; 11498 const char *name = NULL; 11499 const char *value = NULL; 11500 scf_instance_t *saved_cur_inst = cur_inst; 11501 11502 lscf_prep_hndl(); 11503 11504 argc = uu_list_numnodes(args); 11505 if (argc < 1) 11506 goto usage; 11507 11508 argv = calloc(argc + 1, sizeof (char *)); 11509 if (argv == NULL) 11510 uu_die(gettext("Out of memory.\n")); 11511 11512 for (slp = uu_list_first(args), i = 0; 11513 slp != NULL; 11514 slp = uu_list_next(args, slp), ++i) 11515 argv[i] = slp->str; 11516 11517 argv[i] = NULL; 11518 11519 opterr = 0; 11520 optind = 0; 11521 for (;;) { 11522 ret = getopt(argc, argv, "sim:"); 11523 if (ret == -1) 11524 break; 11525 11526 switch (ret) { 11527 case 's': 11528 do_service = 1; 11529 cur_inst = NULL; 11530 break; 11531 11532 case 'i': 11533 do_instance = 1; 11534 break; 11535 11536 case 'm': 11537 method = optarg; 11538 break; 11539 11540 case '?': 11541 goto usage; 11542 11543 default: 11544 bad_error("getopt", ret); 11545 } 11546 } 11547 11548 argc -= optind; 11549 if ((do_service && do_instance) || 11550 (isunset && argc != 1) || 11551 (!isunset && argc != 2)) 11552 goto usage; 11553 11554 name = argv[optind]; 11555 if (!isunset) 11556 value = argv[optind + 1]; 11557 11558 if (cur_snap != NULL) { 11559 semerr(emsg_cant_modify_snapshots); 11560 ret = -1; 11561 goto out; 11562 } 11563 11564 if (cur_inst == NULL && cur_svc == NULL) { 11565 semerr(emsg_entity_not_selected); 11566 ret = -1; 11567 goto out; 11568 } 11569 11570 if (do_instance && cur_inst == NULL) { 11571 semerr(gettext("No instance is selected.\n")); 11572 ret = -1; 11573 goto out; 11574 } 11575 11576 if (do_service && cur_svc == NULL) { 11577 semerr(gettext("No service is selected.\n")); 11578 ret = -1; 11579 goto out; 11580 } 11581 11582 if (method == NULL) { 11583 if (do_instance || do_service) { 11584 method = "method_context"; 11585 if (!isunset) { 11586 ret = addpg("method_context", 11587 SCF_GROUP_FRAMEWORK); 11588 if (ret != 0) 11589 goto out; 11590 } 11591 } else { 11592 int in_instance; 11593 method = start_method_name(&in_instance); 11594 if (method == NULL) { 11595 semerr(gettext( 11596 "Couldn't find start method; please " 11597 "specify a method with '-m'.\n")); 11598 ret = -1; 11599 goto out; 11600 } 11601 if (!in_instance) 11602 cur_inst = NULL; 11603 } 11604 } else { 11605 scf_propertygroup_t *pg; 11606 size_t bufsz; 11607 char *buf; 11608 int ret; 11609 11610 if ((pg = scf_pg_create(g_hndl)) == NULL) 11611 scfdie(); 11612 11613 if (cur_inst != NULL) 11614 ret = scf_instance_get_pg(cur_inst, method, pg); 11615 else 11616 ret = scf_service_get_pg(cur_svc, method, pg); 11617 11618 if (ret != 0) { 11619 scf_pg_destroy(pg); 11620 switch (scf_error()) { 11621 case SCF_ERROR_NOT_FOUND: 11622 semerr(gettext("Couldn't find the method " 11623 "\"%s\".\n"), method); 11624 goto out; 11625 11626 case SCF_ERROR_INVALID_ARGUMENT: 11627 semerr(gettext("Invalid method name \"%s\".\n"), 11628 method); 11629 goto out; 11630 11631 default: 11632 scfdie(); 11633 } 11634 } 11635 11636 bufsz = strlen(SCF_GROUP_METHOD) + 1; 11637 buf = safe_malloc(bufsz); 11638 11639 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 11640 strcmp(buf, SCF_GROUP_METHOD) != 0) { 11641 semerr(gettext("Property group \"%s\" is not of type " 11642 "\"method\".\n"), method); 11643 ret = -1; 11644 free(buf); 11645 scf_pg_destroy(pg); 11646 goto out; 11647 } 11648 11649 free(buf); 11650 scf_pg_destroy(pg); 11651 } 11652 11653 prop = uu_msprintf("%s/environment", method); 11654 pattern = uu_msprintf("%s=*", name); 11655 11656 if (prop == NULL || pattern == NULL) 11657 uu_die(gettext("Out of memory.\n")); 11658 11659 ret = lscf_delpropvalue(prop, pattern, !isunset); 11660 11661 if (ret == 0 && !isunset) { 11662 uu_free(pattern); 11663 uu_free(prop); 11664 prop = uu_msprintf("%s/environment", method); 11665 pattern = uu_msprintf("%s=%s", name, value); 11666 if (prop == NULL || pattern == NULL) 11667 uu_die(gettext("Out of memory.\n")); 11668 ret = lscf_addpropvalue(prop, "astring:", pattern); 11669 } 11670 uu_free(pattern); 11671 uu_free(prop); 11672 11673 out: 11674 cur_inst = saved_cur_inst; 11675 11676 free(argv); 11677 return (ret); 11678 usage: 11679 ret = -2; 11680 goto out; 11681 } 11682 11683 /* 11684 * Snapshot commands 11685 */ 11686 11687 void 11688 lscf_listsnap() 11689 { 11690 scf_snapshot_t *snap; 11691 scf_iter_t *iter; 11692 char *nb; 11693 int r; 11694 11695 lscf_prep_hndl(); 11696 11697 if (cur_inst == NULL) { 11698 semerr(gettext("Instance not selected.\n")); 11699 return; 11700 } 11701 11702 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 11703 (iter = scf_iter_create(g_hndl)) == NULL) 11704 scfdie(); 11705 11706 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 11707 scfdie(); 11708 11709 nb = safe_malloc(max_scf_name_len + 1); 11710 11711 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 11712 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 11713 scfdie(); 11714 11715 (void) puts(nb); 11716 } 11717 if (r < 0) 11718 scfdie(); 11719 11720 free(nb); 11721 scf_iter_destroy(iter); 11722 scf_snapshot_destroy(snap); 11723 } 11724 11725 void 11726 lscf_selectsnap(const char *name) 11727 { 11728 scf_snapshot_t *snap; 11729 scf_snaplevel_t *level; 11730 11731 lscf_prep_hndl(); 11732 11733 if (cur_inst == NULL) { 11734 semerr(gettext("Instance not selected.\n")); 11735 return; 11736 } 11737 11738 if (cur_snap != NULL) { 11739 if (name != NULL) { 11740 char *cur_snap_name; 11741 boolean_t nochange; 11742 11743 cur_snap_name = safe_malloc(max_scf_name_len + 1); 11744 11745 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 11746 max_scf_name_len + 1) < 0) 11747 scfdie(); 11748 11749 nochange = strcmp(name, cur_snap_name) == 0; 11750 11751 free(cur_snap_name); 11752 11753 if (nochange) 11754 return; 11755 } 11756 11757 unselect_cursnap(); 11758 } 11759 11760 if (name == NULL) 11761 return; 11762 11763 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 11764 (level = scf_snaplevel_create(g_hndl)) == NULL) 11765 scfdie(); 11766 11767 if (scf_instance_get_snapshot(cur_inst, name, snap) != 11768 SCF_SUCCESS) { 11769 switch (scf_error()) { 11770 case SCF_ERROR_INVALID_ARGUMENT: 11771 semerr(gettext("Invalid name \"%s\".\n"), name); 11772 break; 11773 11774 case SCF_ERROR_NOT_FOUND: 11775 semerr(gettext("No such snapshot \"%s\".\n"), name); 11776 break; 11777 11778 default: 11779 scfdie(); 11780 } 11781 11782 scf_snaplevel_destroy(level); 11783 scf_snapshot_destroy(snap); 11784 return; 11785 } 11786 11787 /* Load the snaplevels into our list. */ 11788 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 11789 if (cur_levels == NULL) 11790 uu_die(gettext("Could not create list: %s\n"), 11791 uu_strerror(uu_error())); 11792 11793 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 11794 if (scf_error() != SCF_ERROR_NOT_FOUND) 11795 scfdie(); 11796 11797 semerr(gettext("Snapshot has no snaplevels.\n")); 11798 11799 scf_snaplevel_destroy(level); 11800 scf_snapshot_destroy(snap); 11801 return; 11802 } 11803 11804 cur_snap = snap; 11805 11806 for (;;) { 11807 cur_elt = safe_malloc(sizeof (*cur_elt)); 11808 uu_list_node_init(cur_elt, &cur_elt->list_node, 11809 snaplevel_pool); 11810 cur_elt->sl = level; 11811 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 11812 uu_die(gettext("libuutil error: %s\n"), 11813 uu_strerror(uu_error())); 11814 11815 level = scf_snaplevel_create(g_hndl); 11816 if (level == NULL) 11817 scfdie(); 11818 11819 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 11820 level) != SCF_SUCCESS) { 11821 if (scf_error() != SCF_ERROR_NOT_FOUND) 11822 scfdie(); 11823 11824 scf_snaplevel_destroy(level); 11825 break; 11826 } 11827 } 11828 11829 cur_elt = uu_list_last(cur_levels); 11830 cur_level = cur_elt->sl; 11831 } 11832 11833 /* 11834 * Copies the properties & values in src to dst. Assumes src won't change. 11835 * Returns -1 if permission is denied, -2 if another transaction interrupts, 11836 * and 0 on success. 11837 * 11838 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 11839 * property, if it is copied and has type boolean. (See comment in 11840 * lscf_revert()). 11841 */ 11842 static int 11843 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 11844 uint8_t enabled) 11845 { 11846 scf_transaction_t *tx; 11847 scf_iter_t *iter, *viter; 11848 scf_property_t *prop; 11849 scf_value_t *v; 11850 char *nbuf; 11851 int r; 11852 11853 tx = scf_transaction_create(g_hndl); 11854 if (tx == NULL) 11855 scfdie(); 11856 11857 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 11858 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11859 scfdie(); 11860 11861 scf_transaction_destroy(tx); 11862 11863 return (-1); 11864 } 11865 11866 if ((iter = scf_iter_create(g_hndl)) == NULL || 11867 (prop = scf_property_create(g_hndl)) == NULL || 11868 (viter = scf_iter_create(g_hndl)) == NULL) 11869 scfdie(); 11870 11871 nbuf = safe_malloc(max_scf_name_len + 1); 11872 11873 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 11874 scfdie(); 11875 11876 for (;;) { 11877 scf_transaction_entry_t *e; 11878 scf_type_t ty; 11879 11880 r = scf_iter_next_property(iter, prop); 11881 if (r == -1) 11882 scfdie(); 11883 if (r == 0) 11884 break; 11885 11886 e = scf_entry_create(g_hndl); 11887 if (e == NULL) 11888 scfdie(); 11889 11890 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 11891 scfdie(); 11892 11893 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 11894 scfdie(); 11895 11896 if (scf_transaction_property_new(tx, e, nbuf, 11897 ty) != SCF_SUCCESS) 11898 scfdie(); 11899 11900 if ((enabled == 0 || enabled == 1) && 11901 strcmp(nbuf, scf_property_enabled) == 0 && 11902 ty == SCF_TYPE_BOOLEAN) { 11903 v = scf_value_create(g_hndl); 11904 if (v == NULL) 11905 scfdie(); 11906 11907 scf_value_set_boolean(v, enabled); 11908 11909 if (scf_entry_add_value(e, v) != 0) 11910 scfdie(); 11911 } else { 11912 if (scf_iter_property_values(viter, prop) != 0) 11913 scfdie(); 11914 11915 for (;;) { 11916 v = scf_value_create(g_hndl); 11917 if (v == NULL) 11918 scfdie(); 11919 11920 r = scf_iter_next_value(viter, v); 11921 if (r == -1) 11922 scfdie(); 11923 if (r == 0) { 11924 scf_value_destroy(v); 11925 break; 11926 } 11927 11928 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 11929 scfdie(); 11930 } 11931 } 11932 } 11933 11934 free(nbuf); 11935 scf_iter_destroy(viter); 11936 scf_property_destroy(prop); 11937 scf_iter_destroy(iter); 11938 11939 r = scf_transaction_commit(tx); 11940 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11941 scfdie(); 11942 11943 scf_transaction_destroy_children(tx); 11944 scf_transaction_destroy(tx); 11945 11946 switch (r) { 11947 case 1: return (0); 11948 case 0: return (-2); 11949 case -1: return (-1); 11950 11951 default: 11952 abort(); 11953 } 11954 11955 /* NOTREACHED */ 11956 } 11957 11958 void 11959 lscf_revert(const char *snapname) 11960 { 11961 scf_snapshot_t *snap, *prev; 11962 scf_snaplevel_t *level, *nlevel; 11963 scf_iter_t *iter; 11964 scf_propertygroup_t *pg, *npg; 11965 scf_property_t *prop; 11966 scf_value_t *val; 11967 char *nbuf, *tbuf; 11968 uint8_t enabled; 11969 11970 lscf_prep_hndl(); 11971 11972 if (cur_inst == NULL) { 11973 semerr(gettext("Instance not selected.\n")); 11974 return; 11975 } 11976 11977 if (snapname != NULL) { 11978 snap = scf_snapshot_create(g_hndl); 11979 if (snap == NULL) 11980 scfdie(); 11981 11982 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 11983 SCF_SUCCESS) { 11984 switch (scf_error()) { 11985 case SCF_ERROR_INVALID_ARGUMENT: 11986 semerr(gettext("Invalid snapshot name " 11987 "\"%s\".\n"), snapname); 11988 break; 11989 11990 case SCF_ERROR_NOT_FOUND: 11991 semerr(gettext("No such snapshot.\n")); 11992 break; 11993 11994 default: 11995 scfdie(); 11996 } 11997 11998 scf_snapshot_destroy(snap); 11999 return; 12000 } 12001 } else { 12002 if (cur_snap != NULL) { 12003 snap = cur_snap; 12004 } else { 12005 semerr(gettext("No snapshot selected.\n")); 12006 return; 12007 } 12008 } 12009 12010 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 12011 (level = scf_snaplevel_create(g_hndl)) == NULL || 12012 (iter = scf_iter_create(g_hndl)) == NULL || 12013 (pg = scf_pg_create(g_hndl)) == NULL || 12014 (npg = scf_pg_create(g_hndl)) == NULL || 12015 (prop = scf_property_create(g_hndl)) == NULL || 12016 (val = scf_value_create(g_hndl)) == NULL) 12017 scfdie(); 12018 12019 nbuf = safe_malloc(max_scf_name_len + 1); 12020 tbuf = safe_malloc(max_scf_pg_type_len + 1); 12021 12022 /* Take the "previous" snapshot before we blow away the properties. */ 12023 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 12024 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 12025 scfdie(); 12026 } else { 12027 if (scf_error() != SCF_ERROR_NOT_FOUND) 12028 scfdie(); 12029 12030 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 12031 scfdie(); 12032 } 12033 12034 /* Save general/enabled, since we're probably going to replace it. */ 12035 enabled = 2; 12036 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 12037 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 12038 scf_property_get_value(prop, val) == 0) 12039 (void) scf_value_get_boolean(val, &enabled); 12040 12041 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 12042 if (scf_error() != SCF_ERROR_NOT_FOUND) 12043 scfdie(); 12044 12045 goto out; 12046 } 12047 12048 for (;;) { 12049 boolean_t isinst; 12050 uint32_t flags; 12051 int r; 12052 12053 /* Clear the properties from the corresponding entity. */ 12054 isinst = snaplevel_is_instance(level); 12055 12056 if (!isinst) 12057 r = scf_iter_service_pgs(iter, cur_svc); 12058 else 12059 r = scf_iter_instance_pgs(iter, cur_inst); 12060 if (r != SCF_SUCCESS) 12061 scfdie(); 12062 12063 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12064 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12065 scfdie(); 12066 12067 /* Skip nonpersistent pgs. */ 12068 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12069 continue; 12070 12071 if (scf_pg_delete(pg) != SCF_SUCCESS) { 12072 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12073 scfdie(); 12074 12075 semerr(emsg_permission_denied); 12076 goto out; 12077 } 12078 } 12079 if (r == -1) 12080 scfdie(); 12081 12082 /* Copy the properties to the corresponding entity. */ 12083 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 12084 scfdie(); 12085 12086 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12087 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 12088 scfdie(); 12089 12090 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 12091 0) 12092 scfdie(); 12093 12094 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12095 scfdie(); 12096 12097 if (!isinst) 12098 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 12099 flags, npg); 12100 else 12101 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 12102 flags, npg); 12103 if (r != SCF_SUCCESS) { 12104 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12105 scfdie(); 12106 12107 semerr(emsg_permission_denied); 12108 goto out; 12109 } 12110 12111 if ((enabled == 0 || enabled == 1) && 12112 strcmp(nbuf, scf_pg_general) == 0) 12113 r = pg_copy(pg, npg, enabled); 12114 else 12115 r = pg_copy(pg, npg, 2); 12116 12117 switch (r) { 12118 case 0: 12119 break; 12120 12121 case -1: 12122 semerr(emsg_permission_denied); 12123 goto out; 12124 12125 case -2: 12126 semerr(gettext( 12127 "Interrupted by another change.\n")); 12128 goto out; 12129 12130 default: 12131 abort(); 12132 } 12133 } 12134 if (r == -1) 12135 scfdie(); 12136 12137 /* Get next level. */ 12138 nlevel = scf_snaplevel_create(g_hndl); 12139 if (nlevel == NULL) 12140 scfdie(); 12141 12142 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 12143 SCF_SUCCESS) { 12144 if (scf_error() != SCF_ERROR_NOT_FOUND) 12145 scfdie(); 12146 12147 scf_snaplevel_destroy(nlevel); 12148 break; 12149 } 12150 12151 scf_snaplevel_destroy(level); 12152 level = nlevel; 12153 } 12154 12155 if (snapname == NULL) { 12156 lscf_selectsnap(NULL); 12157 snap = NULL; /* cur_snap has been destroyed */ 12158 } 12159 12160 out: 12161 free(tbuf); 12162 free(nbuf); 12163 scf_value_destroy(val); 12164 scf_property_destroy(prop); 12165 scf_pg_destroy(npg); 12166 scf_pg_destroy(pg); 12167 scf_iter_destroy(iter); 12168 scf_snaplevel_destroy(level); 12169 scf_snapshot_destroy(prev); 12170 if (snap != cur_snap) 12171 scf_snapshot_destroy(snap); 12172 } 12173 12174 #ifndef NATIVE_BUILD 12175 /* ARGSUSED */ 12176 CPL_MATCH_FN(complete_select) 12177 { 12178 const char *arg0, *arg1, *arg1end; 12179 int word_start, err = 0, r; 12180 size_t len; 12181 char *buf; 12182 12183 lscf_prep_hndl(); 12184 12185 arg0 = line + strspn(line, " \t"); 12186 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 12187 12188 arg1 = arg0 + sizeof ("select") - 1; 12189 arg1 += strspn(arg1, " \t"); 12190 word_start = arg1 - line; 12191 12192 arg1end = arg1 + strcspn(arg1, " \t"); 12193 if (arg1end < line + word_end) 12194 return (0); 12195 12196 len = line + word_end - arg1; 12197 12198 buf = safe_malloc(max_scf_name_len + 1); 12199 12200 if (cur_snap != NULL) { 12201 return (0); 12202 } else if (cur_inst != NULL) { 12203 return (0); 12204 } else if (cur_svc != NULL) { 12205 scf_instance_t *inst; 12206 scf_iter_t *iter; 12207 12208 if ((inst = scf_instance_create(g_hndl)) == NULL || 12209 (iter = scf_iter_create(g_hndl)) == NULL) 12210 scfdie(); 12211 12212 if (scf_iter_service_instances(iter, cur_svc) != 0) 12213 scfdie(); 12214 12215 for (;;) { 12216 r = scf_iter_next_instance(iter, inst); 12217 if (r == 0) 12218 break; 12219 if (r != 1) 12220 scfdie(); 12221 12222 if (scf_instance_get_name(inst, buf, 12223 max_scf_name_len + 1) < 0) 12224 scfdie(); 12225 12226 if (strncmp(buf, arg1, len) == 0) { 12227 err = cpl_add_completion(cpl, line, word_start, 12228 word_end, buf + len, "", " "); 12229 if (err != 0) 12230 break; 12231 } 12232 } 12233 12234 scf_iter_destroy(iter); 12235 scf_instance_destroy(inst); 12236 12237 return (err); 12238 } else { 12239 scf_service_t *svc; 12240 scf_iter_t *iter; 12241 12242 assert(cur_scope != NULL); 12243 12244 if ((svc = scf_service_create(g_hndl)) == NULL || 12245 (iter = scf_iter_create(g_hndl)) == NULL) 12246 scfdie(); 12247 12248 if (scf_iter_scope_services(iter, cur_scope) != 0) 12249 scfdie(); 12250 12251 for (;;) { 12252 r = scf_iter_next_service(iter, svc); 12253 if (r == 0) 12254 break; 12255 if (r != 1) 12256 scfdie(); 12257 12258 if (scf_service_get_name(svc, buf, 12259 max_scf_name_len + 1) < 0) 12260 scfdie(); 12261 12262 if (strncmp(buf, arg1, len) == 0) { 12263 err = cpl_add_completion(cpl, line, word_start, 12264 word_end, buf + len, "", " "); 12265 if (err != 0) 12266 break; 12267 } 12268 } 12269 12270 scf_iter_destroy(iter); 12271 scf_service_destroy(svc); 12272 12273 return (err); 12274 } 12275 } 12276 12277 /* ARGSUSED */ 12278 CPL_MATCH_FN(complete_command) 12279 { 12280 uint32_t scope = 0; 12281 12282 if (cur_snap != NULL) 12283 scope = CS_SNAP; 12284 else if (cur_inst != NULL) 12285 scope = CS_INST; 12286 else if (cur_svc != NULL) 12287 scope = CS_SVC; 12288 else 12289 scope = CS_SCOPE; 12290 12291 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 12292 } 12293 #endif /* NATIVE_BUILD */ 12294