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