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 /* 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 27 #include <alloca.h> 28 #include <assert.h> 29 #include <ctype.h> 30 #include <door.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <fnmatch.h> 34 #include <inttypes.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 <locale.h> 42 #include <stdarg.h> 43 #include <string.h> 44 #include <strings.h> 45 #include <unistd.h> 46 #include <wait.h> 47 #include <poll.h> 48 49 #include <libxml/tree.h> 50 51 #include <sys/param.h> 52 53 #include <sys/stat.h> 54 #include <sys/mman.h> 55 56 #include "svccfg.h" 57 #include "manifest_hash.h" 58 #include "manifest_find.h" 59 60 /* The colon namespaces in each entity (each followed by a newline). */ 61 #define COLON_NAMESPACES ":properties\n" 62 63 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 64 65 /* These are characters which the lexer requires to be in double-quotes. */ 66 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 67 68 #define HASH_SIZE 16 69 #define HASH_PG_TYPE "framework" 70 #define HASH_PG_FLAGS 0 71 #define HASH_PROP "md5sum" 72 73 /* 74 * Indentation used in the output of the describe subcommand. 75 */ 76 #define TMPL_VALUE_INDENT " " 77 #define TMPL_INDENT " " 78 #define TMPL_INDENT_2X " " 79 #define TMPL_CHOICE_INDENT " " 80 81 /* 82 * Directory locations for manifests 83 */ 84 #define VARSVC_DIR "/var/svc/manifest" 85 #define LIBSVC_DIR "/lib/svc/manifest" 86 #define VARSVC_PR "var_svc_manifest" 87 #define LIBSVC_PR "lib_svc_manifest" 88 #define MFSTFILEPR "manifestfile" 89 90 #define SUPPORTPROP "support" 91 92 #define MFSTHISTFILE "/lib/svc/share/mfsthistory" 93 94 #define MFSTFILE_MAX 16 95 96 /* 97 * These are the classes of elements which may appear as children of service 98 * or instance elements in XML manifests. 99 */ 100 struct entity_elts { 101 xmlNodePtr create_default_instance; 102 xmlNodePtr single_instance; 103 xmlNodePtr restarter; 104 xmlNodePtr dependencies; 105 xmlNodePtr dependents; 106 xmlNodePtr method_context; 107 xmlNodePtr exec_methods; 108 xmlNodePtr property_groups; 109 xmlNodePtr instances; 110 xmlNodePtr stability; 111 xmlNodePtr template; 112 }; 113 114 /* 115 * Likewise for property_group elements. 116 */ 117 struct pg_elts { 118 xmlNodePtr stability; 119 xmlNodePtr propvals; 120 xmlNodePtr properties; 121 }; 122 123 /* 124 * Likewise for template elements. 125 */ 126 struct template_elts { 127 xmlNodePtr common_name; 128 xmlNodePtr description; 129 xmlNodePtr documentation; 130 }; 131 132 /* 133 * This structure is for snaplevel lists. They are convenient because libscf 134 * only allows traversing snaplevels in one direction. 135 */ 136 struct snaplevel { 137 uu_list_node_t list_node; 138 scf_snaplevel_t *sl; 139 }; 140 141 /* 142 * This is used for communication between lscf_service_export and 143 * export_callback. 144 */ 145 struct export_args { 146 const char *filename; 147 int flags; 148 }; 149 150 /* 151 * The service_manifest structure is used by the upgrade process 152 * to create a list of service to manifest linkages from the manifests 153 * in a set of given directories. 154 */ 155 typedef struct service_manifest { 156 const char *servicename; 157 uu_list_t *mfstlist; 158 size_t mfstlist_sz; 159 160 uu_avl_node_t svcmfst_node; 161 } service_manifest_t; 162 163 /* 164 * Structure to track the manifest file property group 165 * and the manifest file associated with that property 166 * group. Also, a flag to keep the access once it has 167 * been checked. 168 */ 169 struct mpg_mfile { 170 char *mpg; 171 char *mfile; 172 int access; 173 }; 174 175 const char * const scf_pg_general = SCF_PG_GENERAL; 176 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 177 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 178 const char * const scf_property_external = "external"; 179 180 const char * const snap_initial = "initial"; 181 const char * const snap_lastimport = "last-import"; 182 const char * const snap_previous = "previous"; 183 const char * const snap_running = "running"; 184 185 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 186 187 ssize_t max_scf_fmri_len; 188 ssize_t max_scf_name_len; 189 ssize_t max_scf_pg_type_len; 190 ssize_t max_scf_value_len; 191 static size_t max_scf_len; 192 193 static scf_scope_t *cur_scope; 194 static scf_service_t *cur_svc = NULL; 195 static scf_instance_t *cur_inst = NULL; 196 static scf_snapshot_t *cur_snap = NULL; 197 static scf_snaplevel_t *cur_level = NULL; 198 199 static uu_list_pool_t *snaplevel_pool; 200 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 201 static uu_list_t *cur_levels; 202 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 203 204 static FILE *tempfile = NULL; 205 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 206 207 static const char *emsg_entity_not_selected; 208 static const char *emsg_permission_denied; 209 static const char *emsg_create_xml; 210 static const char *emsg_cant_modify_snapshots; 211 static const char *emsg_read_only; 212 static const char *emsg_deleted; 213 static const char *emsg_invalid_pg_name; 214 static const char *emsg_invalid_prop_name; 215 static const char *emsg_no_such_pg; 216 static const char *emsg_fmri_invalid_pg_name; 217 static const char *emsg_fmri_invalid_pg_name_type; 218 static const char *emsg_pg_added; 219 static const char *emsg_pg_changed; 220 static const char *emsg_pg_deleted; 221 static const char *emsg_pg_mod_perm; 222 static const char *emsg_pg_add_perm; 223 static const char *emsg_pg_del_perm; 224 static const char *emsg_snap_perm; 225 static const char *emsg_dpt_dangling; 226 static const char *emsg_dpt_no_dep; 227 228 static int li_only = 0; 229 static int no_refresh = 0; 230 231 /* import globals, to minimize allocations */ 232 static scf_scope_t *imp_scope = NULL; 233 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 234 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 235 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 236 static scf_snapshot_t *imp_rsnap = NULL; 237 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 238 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 239 static scf_property_t *imp_prop = NULL; 240 static scf_iter_t *imp_iter = NULL; 241 static scf_iter_t *imp_rpg_iter = NULL; 242 static scf_iter_t *imp_up_iter = NULL; 243 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 244 static char *imp_str = NULL; 245 static size_t imp_str_sz; 246 static char *imp_tsname = NULL; 247 static char *imp_fe1 = NULL; /* for fmri_equal() */ 248 static char *imp_fe2 = NULL; 249 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 250 251 /* upgrade_dependents() globals */ 252 static scf_instance_t *ud_inst = NULL; 253 static scf_snaplevel_t *ud_snpl = NULL; 254 static scf_propertygroup_t *ud_pg = NULL; 255 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 256 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 257 static int ud_run_dpts_pg_set = 0; 258 static scf_property_t *ud_prop = NULL; 259 static scf_property_t *ud_dpt_prop = NULL; 260 static scf_value_t *ud_val = NULL; 261 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 262 static scf_transaction_t *ud_tx = NULL; 263 static char *ud_ctarg = NULL; 264 static char *ud_oldtarg = NULL; 265 static char *ud_name = NULL; 266 267 /* export globals */ 268 static scf_instance_t *exp_inst; 269 static scf_propertygroup_t *exp_pg; 270 static scf_property_t *exp_prop; 271 static scf_value_t *exp_val; 272 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 273 static char *exp_str; 274 static size_t exp_str_sz; 275 276 /* cleanup globals */ 277 static uu_avl_pool_t *service_manifest_pool = NULL; 278 static uu_avl_t *service_manifest_tree = NULL; 279 280 static void scfdie_lineno(int lineno) __NORETURN; 281 282 static char *start_method_names[] = { 283 "start", 284 "inetd_start", 285 NULL 286 }; 287 288 static void 289 safe_printf(const char *fmt, ...) 290 { 291 va_list va; 292 293 va_start(va, fmt); 294 if (vprintf(fmt, va) < 0) 295 uu_die(gettext("Error writing to stdout")); 296 va_end(va); 297 } 298 299 /* 300 * For unexpected libscf errors. 301 */ 302 #ifdef NDEBUG 303 304 static void scfdie(void) __NORETURN; 305 306 static void 307 scfdie(void) 308 { 309 scf_error_t err = scf_error(); 310 311 if (err == SCF_ERROR_CONNECTION_BROKEN) 312 uu_die(gettext("Repository connection broken. Exiting.\n")); 313 314 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 315 scf_strerror(err)); 316 } 317 318 #else 319 320 #define scfdie() scfdie_lineno(__LINE__) 321 322 static void 323 scfdie_lineno(int lineno) 324 { 325 scf_error_t err = scf_error(); 326 327 if (err == SCF_ERROR_CONNECTION_BROKEN) 328 uu_die(gettext("Repository connection broken. Exiting.\n")); 329 330 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 331 ": %s.\n"), lineno, scf_strerror(err)); 332 } 333 334 #endif 335 336 static void 337 scfwarn(void) 338 { 339 warn(gettext("Unexpected libscf error: %s.\n"), 340 scf_strerror(scf_error())); 341 } 342 343 /* 344 * Clear a field of a structure. 345 */ 346 static int 347 clear_int(void *a, void *b) 348 { 349 /* LINTED */ 350 *(int *)((char *)a + (size_t)b) = 0; 351 352 return (UU_WALK_NEXT); 353 } 354 355 static int 356 scferror2errno(scf_error_t err) 357 { 358 switch (err) { 359 case SCF_ERROR_BACKEND_ACCESS: 360 return (EACCES); 361 362 case SCF_ERROR_BACKEND_READONLY: 363 return (EROFS); 364 365 case SCF_ERROR_CONNECTION_BROKEN: 366 return (ECONNABORTED); 367 368 case SCF_ERROR_CONSTRAINT_VIOLATED: 369 case SCF_ERROR_INVALID_ARGUMENT: 370 return (EINVAL); 371 372 case SCF_ERROR_DELETED: 373 return (ECANCELED); 374 375 case SCF_ERROR_EXISTS: 376 return (EEXIST); 377 378 case SCF_ERROR_NO_MEMORY: 379 return (ENOMEM); 380 381 case SCF_ERROR_NO_RESOURCES: 382 return (ENOSPC); 383 384 case SCF_ERROR_NOT_FOUND: 385 return (ENOENT); 386 387 case SCF_ERROR_PERMISSION_DENIED: 388 return (EPERM); 389 390 default: 391 #ifndef NDEBUG 392 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 393 __FILE__, __LINE__, err); 394 #else 395 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 396 #endif 397 abort(); 398 /* NOTREACHED */ 399 } 400 } 401 402 static int 403 entity_get_pg(void *ent, int issvc, const char *name, 404 scf_propertygroup_t *pg) 405 { 406 if (issvc) 407 return (scf_service_get_pg(ent, name, pg)); 408 else 409 return (scf_instance_get_pg(ent, name, pg)); 410 } 411 412 static void 413 entity_destroy(void *ent, int issvc) 414 { 415 if (issvc) 416 scf_service_destroy(ent); 417 else 418 scf_instance_destroy(ent); 419 } 420 421 static int 422 get_pg(const char *pg_name, scf_propertygroup_t *pg) 423 { 424 int ret; 425 426 if (cur_level != NULL) 427 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 428 else if (cur_inst != NULL) 429 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 430 else 431 ret = scf_service_get_pg(cur_svc, pg_name, pg); 432 433 return (ret); 434 } 435 436 /* 437 * Find a snaplevel in a snapshot. If get_svc is true, find the service 438 * snaplevel. Otherwise find the instance snaplevel. 439 * 440 * Returns 441 * 0 - success 442 * ECONNABORTED - repository connection broken 443 * ECANCELED - instance containing snap was deleted 444 * ENOENT - snap has no snaplevels 445 * - requested snaplevel not found 446 */ 447 static int 448 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 449 { 450 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 451 switch (scf_error()) { 452 case SCF_ERROR_CONNECTION_BROKEN: 453 case SCF_ERROR_DELETED: 454 case SCF_ERROR_NOT_FOUND: 455 return (scferror2errno(scf_error())); 456 457 case SCF_ERROR_HANDLE_MISMATCH: 458 case SCF_ERROR_NOT_BOUND: 459 case SCF_ERROR_NOT_SET: 460 default: 461 bad_error("scf_snapshot_get_base_snaplevel", 462 scf_error()); 463 } 464 } 465 466 for (;;) { 467 ssize_t ssz; 468 469 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 470 if (ssz >= 0) { 471 if (!get_svc) 472 return (0); 473 } else { 474 switch (scf_error()) { 475 case SCF_ERROR_CONSTRAINT_VIOLATED: 476 if (get_svc) 477 return (0); 478 break; 479 480 case SCF_ERROR_DELETED: 481 case SCF_ERROR_CONNECTION_BROKEN: 482 return (scferror2errno(scf_error())); 483 484 case SCF_ERROR_NOT_SET: 485 case SCF_ERROR_NOT_BOUND: 486 default: 487 bad_error("scf_snaplevel_get_instance_name", 488 scf_error()); 489 } 490 } 491 492 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 493 switch (scf_error()) { 494 case SCF_ERROR_NOT_FOUND: 495 case SCF_ERROR_CONNECTION_BROKEN: 496 case SCF_ERROR_DELETED: 497 return (scferror2errno(scf_error())); 498 499 case SCF_ERROR_HANDLE_MISMATCH: 500 case SCF_ERROR_NOT_BOUND: 501 case SCF_ERROR_NOT_SET: 502 case SCF_ERROR_INVALID_ARGUMENT: 503 default: 504 bad_error("scf_snaplevel_get_next_snaplevel", 505 scf_error()); 506 } 507 } 508 } 509 } 510 511 /* 512 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 513 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 514 * the property group named name in it. If it doesn't have a running 515 * snapshot, set pg to the instance's current property group named name. 516 * 517 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 518 * its instances. If one has a running snapshot with a service snaplevel, set 519 * pg to the property group named name in it. If no such snaplevel could be 520 * found, set pg to the service's current property group named name. 521 * 522 * iter, inst, snap, and snpl are required scratch objects. 523 * 524 * Returns 525 * 0 - success 526 * ECONNABORTED - repository connection broken 527 * ECANCELED - ent was deleted 528 * ENOENT - no such property group 529 * EINVAL - name is an invalid property group name 530 * EBADF - found running snapshot is missing a snaplevel 531 */ 532 static int 533 entity_get_running_pg(void *ent, int issvc, const char *name, 534 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 535 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 536 { 537 int r; 538 539 if (issvc) { 540 /* Search for an instance with a running snapshot. */ 541 if (scf_iter_service_instances(iter, ent) != 0) { 542 switch (scf_error()) { 543 case SCF_ERROR_DELETED: 544 case SCF_ERROR_CONNECTION_BROKEN: 545 return (scferror2errno(scf_error())); 546 547 case SCF_ERROR_NOT_SET: 548 case SCF_ERROR_NOT_BOUND: 549 case SCF_ERROR_HANDLE_MISMATCH: 550 default: 551 bad_error("scf_iter_service_instances", 552 scf_error()); 553 } 554 } 555 556 for (;;) { 557 r = scf_iter_next_instance(iter, inst); 558 if (r == 0) { 559 if (scf_service_get_pg(ent, name, pg) == 0) 560 return (0); 561 562 switch (scf_error()) { 563 case SCF_ERROR_DELETED: 564 case SCF_ERROR_NOT_FOUND: 565 case SCF_ERROR_INVALID_ARGUMENT: 566 case SCF_ERROR_CONNECTION_BROKEN: 567 return (scferror2errno(scf_error())); 568 569 case SCF_ERROR_NOT_BOUND: 570 case SCF_ERROR_HANDLE_MISMATCH: 571 case SCF_ERROR_NOT_SET: 572 default: 573 bad_error("scf_service_get_pg", 574 scf_error()); 575 } 576 } 577 if (r != 1) { 578 switch (scf_error()) { 579 case SCF_ERROR_DELETED: 580 case SCF_ERROR_CONNECTION_BROKEN: 581 return (scferror2errno(scf_error())); 582 583 case SCF_ERROR_INVALID_ARGUMENT: 584 case SCF_ERROR_NOT_SET: 585 case SCF_ERROR_NOT_BOUND: 586 case SCF_ERROR_HANDLE_MISMATCH: 587 default: 588 bad_error("scf_iter_next_instance", 589 scf_error()); 590 } 591 } 592 593 if (scf_instance_get_snapshot(inst, snap_running, 594 snap) == 0) 595 break; 596 597 switch (scf_error()) { 598 case SCF_ERROR_NOT_FOUND: 599 case SCF_ERROR_DELETED: 600 continue; 601 602 case SCF_ERROR_CONNECTION_BROKEN: 603 return (ECONNABORTED); 604 605 case SCF_ERROR_HANDLE_MISMATCH: 606 case SCF_ERROR_INVALID_ARGUMENT: 607 case SCF_ERROR_NOT_SET: 608 case SCF_ERROR_NOT_BOUND: 609 default: 610 bad_error("scf_instance_get_snapshot", 611 scf_error()); 612 } 613 } 614 } else { 615 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 616 switch (scf_error()) { 617 case SCF_ERROR_NOT_FOUND: 618 break; 619 620 case SCF_ERROR_DELETED: 621 case SCF_ERROR_CONNECTION_BROKEN: 622 return (scferror2errno(scf_error())); 623 624 case SCF_ERROR_NOT_BOUND: 625 case SCF_ERROR_HANDLE_MISMATCH: 626 case SCF_ERROR_INVALID_ARGUMENT: 627 case SCF_ERROR_NOT_SET: 628 default: 629 bad_error("scf_instance_get_snapshot", 630 scf_error()); 631 } 632 633 if (scf_instance_get_pg(ent, name, pg) == 0) 634 return (0); 635 636 switch (scf_error()) { 637 case SCF_ERROR_DELETED: 638 case SCF_ERROR_NOT_FOUND: 639 case SCF_ERROR_INVALID_ARGUMENT: 640 case SCF_ERROR_CONNECTION_BROKEN: 641 return (scferror2errno(scf_error())); 642 643 case SCF_ERROR_NOT_BOUND: 644 case SCF_ERROR_HANDLE_MISMATCH: 645 case SCF_ERROR_NOT_SET: 646 default: 647 bad_error("scf_instance_get_pg", scf_error()); 648 } 649 } 650 } 651 652 r = get_snaplevel(snap, issvc, snpl); 653 switch (r) { 654 case 0: 655 break; 656 657 case ECONNABORTED: 658 case ECANCELED: 659 return (r); 660 661 case ENOENT: 662 return (EBADF); 663 664 default: 665 bad_error("get_snaplevel", r); 666 } 667 668 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 669 return (0); 670 671 switch (scf_error()) { 672 case SCF_ERROR_DELETED: 673 case SCF_ERROR_INVALID_ARGUMENT: 674 case SCF_ERROR_CONNECTION_BROKEN: 675 case SCF_ERROR_NOT_FOUND: 676 return (scferror2errno(scf_error())); 677 678 case SCF_ERROR_NOT_BOUND: 679 case SCF_ERROR_HANDLE_MISMATCH: 680 case SCF_ERROR_NOT_SET: 681 default: 682 bad_error("scf_snaplevel_get_pg", scf_error()); 683 /* NOTREACHED */ 684 } 685 } 686 687 /* 688 * To be registered with atexit(). 689 */ 690 static void 691 remove_tempfile(void) 692 { 693 int ret; 694 695 if (tempfile != NULL) { 696 if (fclose(tempfile) == EOF) 697 (void) warn(gettext("Could not close temporary file")); 698 tempfile = NULL; 699 } 700 701 if (tempfilename[0] != '\0') { 702 do { 703 ret = remove(tempfilename); 704 } while (ret == -1 && errno == EINTR); 705 if (ret == -1) 706 warn(gettext("Could not remove temporary file")); 707 tempfilename[0] = '\0'; 708 } 709 } 710 711 /* 712 * Launch private svc.configd(1M) for manipulating alternate repositories. 713 */ 714 static void 715 start_private_repository(engine_state_t *est) 716 { 717 int fd, stat; 718 struct door_info info; 719 pid_t pid; 720 721 /* 722 * 1. Create a temporary file for the door. 723 */ 724 if (est->sc_repo_doorname != NULL) 725 free((void *)est->sc_repo_doorname); 726 727 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 728 if (est->sc_repo_doorname == NULL) 729 uu_die(gettext("Could not acquire temporary filename")); 730 731 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 732 if (fd < 0) 733 uu_die(gettext("Could not create temporary file for " 734 "repository server")); 735 736 (void) close(fd); 737 738 /* 739 * 2. Launch a configd with that door, using the specified 740 * repository. 741 */ 742 if ((est->sc_repo_pid = fork()) == 0) { 743 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 744 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 745 NULL); 746 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 747 } else if (est->sc_repo_pid == -1) 748 uu_die(gettext("Attempt to fork failed")); 749 750 do { 751 pid = waitpid(est->sc_repo_pid, &stat, 0); 752 } while (pid == -1 && errno == EINTR); 753 754 if (pid == -1) 755 uu_die(gettext("Could not waitpid() for repository server")); 756 757 if (!WIFEXITED(stat)) { 758 uu_die(gettext("Repository server failed (status %d).\n"), 759 stat); 760 } else if (WEXITSTATUS(stat) != 0) { 761 uu_die(gettext("Repository server failed (exit %d).\n"), 762 WEXITSTATUS(stat)); 763 } 764 765 /* 766 * See if it was successful by checking if the door is a door. 767 */ 768 769 fd = open(est->sc_repo_doorname, O_RDWR); 770 if (fd < 0) 771 uu_die(gettext("Could not open door \"%s\""), 772 est->sc_repo_doorname); 773 774 if (door_info(fd, &info) < 0) 775 uu_die(gettext("Unexpected door_info() error")); 776 777 if (close(fd) == -1) 778 warn(gettext("Could not close repository door"), 779 strerror(errno)); 780 781 est->sc_repo_pid = info.di_target; 782 } 783 784 void 785 lscf_cleanup(void) 786 { 787 /* 788 * In the case where we've launched a private svc.configd(1M) 789 * instance, we must terminate our child and remove the temporary 790 * rendezvous point. 791 */ 792 if (est->sc_repo_pid > 0) { 793 (void) kill(est->sc_repo_pid, SIGTERM); 794 (void) waitpid(est->sc_repo_pid, NULL, 0); 795 (void) unlink(est->sc_repo_doorname); 796 797 est->sc_repo_pid = 0; 798 } 799 } 800 801 void 802 unselect_cursnap(void) 803 { 804 void *cookie; 805 806 cur_level = NULL; 807 808 cookie = NULL; 809 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 810 scf_snaplevel_destroy(cur_elt->sl); 811 free(cur_elt); 812 } 813 814 scf_snapshot_destroy(cur_snap); 815 cur_snap = NULL; 816 } 817 818 void 819 lscf_prep_hndl(void) 820 { 821 if (g_hndl != NULL) 822 return; 823 824 g_hndl = scf_handle_create(SCF_VERSION); 825 if (g_hndl == NULL) 826 scfdie(); 827 828 if (est->sc_repo_filename != NULL) 829 start_private_repository(est); 830 831 if (est->sc_repo_doorname != NULL) { 832 scf_value_t *repo_value; 833 int ret; 834 835 repo_value = scf_value_create(g_hndl); 836 if (repo_value == NULL) 837 scfdie(); 838 839 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 840 assert(ret == SCF_SUCCESS); 841 842 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 843 SCF_SUCCESS) 844 scfdie(); 845 846 scf_value_destroy(repo_value); 847 } 848 849 if (scf_handle_bind(g_hndl) != 0) 850 uu_die(gettext("Could not connect to repository server: %s.\n"), 851 scf_strerror(scf_error())); 852 853 cur_scope = scf_scope_create(g_hndl); 854 if (cur_scope == NULL) 855 scfdie(); 856 857 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 858 scfdie(); 859 } 860 861 static void 862 repository_teardown(void) 863 { 864 if (g_hndl != NULL) { 865 if (cur_snap != NULL) 866 unselect_cursnap(); 867 scf_instance_destroy(cur_inst); 868 scf_service_destroy(cur_svc); 869 scf_scope_destroy(cur_scope); 870 scf_handle_destroy(g_hndl); 871 cur_inst = NULL; 872 cur_svc = NULL; 873 cur_scope = NULL; 874 g_hndl = NULL; 875 lscf_cleanup(); 876 } 877 } 878 879 void 880 lscf_set_repository(const char *repfile, int force) 881 { 882 repository_teardown(); 883 884 if (est->sc_repo_filename != NULL) { 885 free((void *)est->sc_repo_filename); 886 est->sc_repo_filename = NULL; 887 } 888 889 if ((force == 0) && (access(repfile, R_OK) != 0)) { 890 /* 891 * Repository file does not exist 892 * or has no read permission. 893 */ 894 warn(gettext("Cannot access \"%s\": %s\n"), 895 repfile, strerror(errno)); 896 } else { 897 est->sc_repo_filename = safe_strdup(repfile); 898 } 899 900 lscf_prep_hndl(); 901 } 902 903 void 904 lscf_init() 905 { 906 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 907 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 908 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 909 0 || 910 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 911 scfdie(); 912 913 max_scf_len = max_scf_fmri_len; 914 if (max_scf_name_len > max_scf_len) 915 max_scf_len = max_scf_name_len; 916 if (max_scf_pg_type_len > max_scf_len) 917 max_scf_len = max_scf_pg_type_len; 918 if (max_scf_value_len > max_scf_len) 919 max_scf_len = max_scf_value_len; 920 921 if (atexit(remove_tempfile) != 0) 922 uu_die(gettext("Could not register atexit() function")); 923 924 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 925 emsg_permission_denied = gettext("Permission denied.\n"); 926 emsg_create_xml = gettext("Could not create XML node.\n"); 927 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 928 emsg_read_only = gettext("Backend read-only.\n"); 929 emsg_deleted = gettext("Current selection has been deleted.\n"); 930 emsg_invalid_pg_name = 931 gettext("Invalid property group name \"%s\".\n"); 932 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 933 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 934 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 935 "with invalid name \"%s\".\n"); 936 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 937 "group with invalid name \"%s\" or type \"%s\".\n"); 938 emsg_pg_added = gettext("%s changed unexpectedly " 939 "(property group \"%s\" added).\n"); 940 emsg_pg_changed = gettext("%s changed unexpectedly " 941 "(property group \"%s\" changed).\n"); 942 emsg_pg_deleted = gettext("%s changed unexpectedly " 943 "(property group \"%s\" or an ancestor was deleted).\n"); 944 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 945 "in %s (permission denied).\n"); 946 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 947 "in %s (permission denied).\n"); 948 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 949 "in %s (permission denied).\n"); 950 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 951 "(permission denied).\n"); 952 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 953 "new dependent \"%s\" because it already exists). Warning: The " 954 "current dependent's target (%s) does not exist.\n"); 955 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 956 "dependent \"%s\" because it already exists). Warning: The " 957 "current dependent's target (%s) does not have a dependency named " 958 "\"%s\" as expected.\n"); 959 960 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 961 offsetof(string_list_t, node), NULL, 0); 962 snaplevel_pool = uu_list_pool_create("snaplevels", 963 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 964 NULL, 0); 965 } 966 967 968 static const char * 969 prop_to_typestr(const scf_property_t *prop) 970 { 971 scf_type_t ty; 972 973 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 974 scfdie(); 975 976 return (scf_type_to_string(ty)); 977 } 978 979 static scf_type_t 980 string_to_type(const char *type) 981 { 982 size_t len = strlen(type); 983 char *buf; 984 985 if (len == 0 || type[len - 1] != ':') 986 return (SCF_TYPE_INVALID); 987 988 buf = (char *)alloca(len + 1); 989 (void) strlcpy(buf, type, len + 1); 990 buf[len - 1] = 0; 991 992 return (scf_string_to_type(buf)); 993 } 994 995 static scf_value_t * 996 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 997 { 998 scf_value_t *v; 999 char *dup, *nstr; 1000 size_t len; 1001 1002 v = scf_value_create(g_hndl); 1003 if (v == NULL) 1004 scfdie(); 1005 1006 len = strlen(str); 1007 if (require_quotes && 1008 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1009 semerr(gettext("Multiple string values or string values " 1010 "with spaces must be quoted with '\"'.\n")); 1011 scf_value_destroy(v); 1012 return (NULL); 1013 } 1014 1015 nstr = dup = safe_strdup(str); 1016 if (dup[0] == '\"') { 1017 /* 1018 * Strip out the first and the last quote. 1019 */ 1020 dup[len - 1] = '\0'; 1021 nstr = dup + 1; 1022 } 1023 1024 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1025 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1026 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1027 scf_type_to_string(ty), nstr); 1028 scf_value_destroy(v); 1029 v = NULL; 1030 } 1031 free(dup); 1032 return (v); 1033 } 1034 1035 /* 1036 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1037 * Optionally append a comment prefix ('#') to newlines ('\n'). 1038 */ 1039 static int 1040 quote_and_print(const char *str, FILE *strm, int commentnl) 1041 { 1042 const char *cp; 1043 1044 for (cp = str; *cp != '\0'; ++cp) { 1045 if (*cp == '"' || *cp == '\\') 1046 (void) putc('\\', strm); 1047 1048 (void) putc(*cp, strm); 1049 1050 if (commentnl && *cp == '\n') { 1051 (void) putc('#', strm); 1052 } 1053 } 1054 1055 return (ferror(strm)); 1056 } 1057 1058 /* 1059 * These wrappers around lowlevel functions provide consistent error checking 1060 * and warnings. 1061 */ 1062 static int 1063 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1064 { 1065 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1066 return (0); 1067 1068 if (scf_error() != SCF_ERROR_NOT_FOUND) 1069 scfdie(); 1070 1071 if (g_verbose) { 1072 ssize_t len; 1073 char *fmri; 1074 1075 len = scf_pg_to_fmri(pg, NULL, 0); 1076 if (len < 0) 1077 scfdie(); 1078 1079 fmri = safe_malloc(len + 1); 1080 1081 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1082 scfdie(); 1083 1084 warn(gettext("Expected property %s of property group %s is " 1085 "missing.\n"), propname, fmri); 1086 1087 free(fmri); 1088 } 1089 1090 return (-1); 1091 } 1092 1093 static int 1094 prop_check_type(scf_property_t *prop, scf_type_t ty) 1095 { 1096 scf_type_t pty; 1097 1098 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1099 scfdie(); 1100 1101 if (ty == pty) 1102 return (0); 1103 1104 if (g_verbose) { 1105 ssize_t len; 1106 char *fmri; 1107 const char *tystr; 1108 1109 len = scf_property_to_fmri(prop, NULL, 0); 1110 if (len < 0) 1111 scfdie(); 1112 1113 fmri = safe_malloc(len + 1); 1114 1115 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1116 scfdie(); 1117 1118 tystr = scf_type_to_string(ty); 1119 if (tystr == NULL) 1120 tystr = "?"; 1121 1122 warn(gettext("Property %s is not of expected type %s.\n"), 1123 fmri, tystr); 1124 1125 free(fmri); 1126 } 1127 1128 return (-1); 1129 } 1130 1131 static int 1132 prop_get_val(scf_property_t *prop, scf_value_t *val) 1133 { 1134 scf_error_t err; 1135 1136 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1137 return (0); 1138 1139 err = scf_error(); 1140 1141 if (err != SCF_ERROR_NOT_FOUND && 1142 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1143 err != SCF_ERROR_PERMISSION_DENIED) 1144 scfdie(); 1145 1146 if (g_verbose) { 1147 ssize_t len; 1148 char *fmri, *emsg; 1149 1150 len = scf_property_to_fmri(prop, NULL, 0); 1151 if (len < 0) 1152 scfdie(); 1153 1154 fmri = safe_malloc(len + 1); 1155 1156 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1157 scfdie(); 1158 1159 if (err == SCF_ERROR_NOT_FOUND) 1160 emsg = gettext("Property %s has no values; expected " 1161 "one.\n"); 1162 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1163 emsg = gettext("Property %s has multiple values; " 1164 "expected one.\n"); 1165 else 1166 emsg = gettext("No permission to read property %s.\n"); 1167 1168 warn(emsg, fmri); 1169 1170 free(fmri); 1171 } 1172 1173 return (-1); 1174 } 1175 1176 1177 static boolean_t 1178 snaplevel_is_instance(const scf_snaplevel_t *level) 1179 { 1180 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1181 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1182 scfdie(); 1183 return (0); 1184 } else { 1185 return (1); 1186 } 1187 } 1188 1189 /* 1190 * Decode FMRI into a service or instance, and put the result in *ep. If 1191 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1192 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1193 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1194 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1195 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1196 * whether *ep is a service. 1197 */ 1198 static scf_error_t 1199 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1200 { 1201 char *fmri_copy; 1202 const char *sstr, *istr, *pgstr; 1203 scf_service_t *svc; 1204 scf_instance_t *inst; 1205 1206 fmri_copy = strdup(fmri); 1207 if (fmri_copy == NULL) 1208 return (SCF_ERROR_NO_MEMORY); 1209 1210 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1211 SCF_SUCCESS) { 1212 free(fmri_copy); 1213 return (SCF_ERROR_INVALID_ARGUMENT); 1214 } 1215 1216 free(fmri_copy); 1217 1218 if (sstr == NULL || pgstr != NULL) 1219 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1220 1221 if (istr == NULL) { 1222 svc = scf_service_create(h); 1223 if (svc == NULL) 1224 return (SCF_ERROR_NO_MEMORY); 1225 1226 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1227 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1228 if (scf_error() != SCF_ERROR_NOT_FOUND) 1229 scfdie(); 1230 1231 return (SCF_ERROR_NOT_FOUND); 1232 } 1233 1234 *ep = svc; 1235 *isservice = 1; 1236 } else { 1237 inst = scf_instance_create(h); 1238 if (inst == NULL) 1239 return (SCF_ERROR_NO_MEMORY); 1240 1241 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1242 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1243 if (scf_error() != SCF_ERROR_NOT_FOUND) 1244 scfdie(); 1245 1246 return (SCF_ERROR_NOT_FOUND); 1247 } 1248 1249 *ep = inst; 1250 *isservice = 0; 1251 } 1252 1253 return (SCF_ERROR_NONE); 1254 } 1255 1256 /* 1257 * Create the entity named by fmri. Place a pointer to its libscf handle in 1258 * *ep, and set or clear *isservicep if it is a service or an instance. 1259 * Returns 1260 * SCF_ERROR_NONE - success 1261 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1262 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1263 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1264 * SCF_ERROR_NOT_FOUND - no such scope 1265 * SCF_ERROR_PERMISSION_DENIED 1266 * SCF_ERROR_BACKEND_READONLY 1267 * SCF_ERROR_BACKEND_ACCESS 1268 */ 1269 static scf_error_t 1270 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1271 { 1272 char *fmri_copy; 1273 const char *scstr, *sstr, *istr, *pgstr; 1274 scf_scope_t *scope = NULL; 1275 scf_service_t *svc = NULL; 1276 scf_instance_t *inst = NULL; 1277 scf_error_t scfe; 1278 1279 fmri_copy = safe_strdup(fmri); 1280 1281 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1282 0) { 1283 free(fmri_copy); 1284 return (SCF_ERROR_INVALID_ARGUMENT); 1285 } 1286 1287 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1288 free(fmri_copy); 1289 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1290 } 1291 1292 *ep = NULL; 1293 1294 if ((scope = scf_scope_create(h)) == NULL || 1295 (svc = scf_service_create(h)) == NULL || 1296 (inst = scf_instance_create(h)) == NULL) { 1297 scfe = SCF_ERROR_NO_MEMORY; 1298 goto out; 1299 } 1300 1301 get_scope: 1302 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1303 switch (scf_error()) { 1304 case SCF_ERROR_CONNECTION_BROKEN: 1305 scfdie(); 1306 /* NOTREACHED */ 1307 1308 case SCF_ERROR_NOT_FOUND: 1309 scfe = SCF_ERROR_NOT_FOUND; 1310 goto out; 1311 1312 case SCF_ERROR_HANDLE_MISMATCH: 1313 case SCF_ERROR_NOT_BOUND: 1314 case SCF_ERROR_INVALID_ARGUMENT: 1315 default: 1316 bad_error("scf_handle_get_scope", scf_error()); 1317 } 1318 } 1319 1320 get_svc: 1321 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1322 switch (scf_error()) { 1323 case SCF_ERROR_CONNECTION_BROKEN: 1324 scfdie(); 1325 /* NOTREACHED */ 1326 1327 case SCF_ERROR_DELETED: 1328 goto get_scope; 1329 1330 case SCF_ERROR_NOT_FOUND: 1331 break; 1332 1333 case SCF_ERROR_HANDLE_MISMATCH: 1334 case SCF_ERROR_INVALID_ARGUMENT: 1335 case SCF_ERROR_NOT_BOUND: 1336 case SCF_ERROR_NOT_SET: 1337 default: 1338 bad_error("scf_scope_get_service", scf_error()); 1339 } 1340 1341 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1342 switch (scf_error()) { 1343 case SCF_ERROR_CONNECTION_BROKEN: 1344 scfdie(); 1345 /* NOTREACHED */ 1346 1347 case SCF_ERROR_DELETED: 1348 goto get_scope; 1349 1350 case SCF_ERROR_PERMISSION_DENIED: 1351 case SCF_ERROR_BACKEND_READONLY: 1352 case SCF_ERROR_BACKEND_ACCESS: 1353 scfe = scf_error(); 1354 goto out; 1355 1356 case SCF_ERROR_HANDLE_MISMATCH: 1357 case SCF_ERROR_INVALID_ARGUMENT: 1358 case SCF_ERROR_NOT_BOUND: 1359 case SCF_ERROR_NOT_SET: 1360 default: 1361 bad_error("scf_scope_get_service", scf_error()); 1362 } 1363 } 1364 } 1365 1366 if (istr == NULL) { 1367 scfe = SCF_ERROR_NONE; 1368 *ep = svc; 1369 *isservicep = 1; 1370 goto out; 1371 } 1372 1373 get_inst: 1374 if (scf_service_get_instance(svc, istr, inst) != 0) { 1375 switch (scf_error()) { 1376 case SCF_ERROR_CONNECTION_BROKEN: 1377 scfdie(); 1378 /* NOTREACHED */ 1379 1380 case SCF_ERROR_DELETED: 1381 goto get_svc; 1382 1383 case SCF_ERROR_NOT_FOUND: 1384 break; 1385 1386 case SCF_ERROR_HANDLE_MISMATCH: 1387 case SCF_ERROR_INVALID_ARGUMENT: 1388 case SCF_ERROR_NOT_BOUND: 1389 case SCF_ERROR_NOT_SET: 1390 default: 1391 bad_error("scf_service_get_instance", scf_error()); 1392 } 1393 1394 if (scf_service_add_instance(svc, istr, inst) != 0) { 1395 switch (scf_error()) { 1396 case SCF_ERROR_CONNECTION_BROKEN: 1397 scfdie(); 1398 /* NOTREACHED */ 1399 1400 case SCF_ERROR_DELETED: 1401 goto get_svc; 1402 1403 case SCF_ERROR_PERMISSION_DENIED: 1404 case SCF_ERROR_BACKEND_READONLY: 1405 case SCF_ERROR_BACKEND_ACCESS: 1406 scfe = scf_error(); 1407 goto out; 1408 1409 case SCF_ERROR_HANDLE_MISMATCH: 1410 case SCF_ERROR_INVALID_ARGUMENT: 1411 case SCF_ERROR_NOT_BOUND: 1412 case SCF_ERROR_NOT_SET: 1413 default: 1414 bad_error("scf_service_add_instance", 1415 scf_error()); 1416 } 1417 } 1418 } 1419 1420 scfe = SCF_ERROR_NONE; 1421 *ep = inst; 1422 *isservicep = 0; 1423 1424 out: 1425 if (*ep != inst) 1426 scf_instance_destroy(inst); 1427 if (*ep != svc) 1428 scf_service_destroy(svc); 1429 scf_scope_destroy(scope); 1430 free(fmri_copy); 1431 return (scfe); 1432 } 1433 1434 /* 1435 * Create or update a snapshot of inst. snap is a required scratch object. 1436 * 1437 * Returns 1438 * 0 - success 1439 * ECONNABORTED - repository connection broken 1440 * EPERM - permission denied 1441 * ENOSPC - configd is out of resources 1442 * ECANCELED - inst was deleted 1443 * -1 - unknown libscf error (message printed) 1444 */ 1445 static int 1446 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1447 { 1448 again: 1449 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1450 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1451 switch (scf_error()) { 1452 case SCF_ERROR_CONNECTION_BROKEN: 1453 case SCF_ERROR_PERMISSION_DENIED: 1454 case SCF_ERROR_NO_RESOURCES: 1455 return (scferror2errno(scf_error())); 1456 1457 case SCF_ERROR_NOT_SET: 1458 case SCF_ERROR_INVALID_ARGUMENT: 1459 default: 1460 bad_error("_scf_snapshot_take_attach", 1461 scf_error()); 1462 } 1463 } 1464 } else { 1465 switch (scf_error()) { 1466 case SCF_ERROR_NOT_FOUND: 1467 break; 1468 1469 case SCF_ERROR_DELETED: 1470 case SCF_ERROR_CONNECTION_BROKEN: 1471 return (scferror2errno(scf_error())); 1472 1473 case SCF_ERROR_HANDLE_MISMATCH: 1474 case SCF_ERROR_NOT_BOUND: 1475 case SCF_ERROR_INVALID_ARGUMENT: 1476 case SCF_ERROR_NOT_SET: 1477 default: 1478 bad_error("scf_instance_get_snapshot", scf_error()); 1479 } 1480 1481 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1482 switch (scf_error()) { 1483 case SCF_ERROR_EXISTS: 1484 goto again; 1485 1486 case SCF_ERROR_CONNECTION_BROKEN: 1487 case SCF_ERROR_NO_RESOURCES: 1488 case SCF_ERROR_PERMISSION_DENIED: 1489 return (scferror2errno(scf_error())); 1490 1491 default: 1492 scfwarn(); 1493 return (-1); 1494 1495 case SCF_ERROR_NOT_SET: 1496 case SCF_ERROR_INTERNAL: 1497 case SCF_ERROR_INVALID_ARGUMENT: 1498 case SCF_ERROR_HANDLE_MISMATCH: 1499 bad_error("_scf_snapshot_take_new", 1500 scf_error()); 1501 } 1502 } 1503 } 1504 1505 return (0); 1506 } 1507 1508 static int 1509 refresh_running_snapshot(void *entity) 1510 { 1511 scf_snapshot_t *snap; 1512 int r; 1513 1514 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1515 scfdie(); 1516 r = take_snap(entity, snap_running, snap); 1517 scf_snapshot_destroy(snap); 1518 1519 return (r); 1520 } 1521 1522 /* 1523 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1524 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1525 * instances. fmri is used for messages. inst, iter, and name_buf are used 1526 * for scratch space. Returns 1527 * 0 - success 1528 * ECONNABORTED - repository connection broken 1529 * ECANCELED - entity was deleted 1530 * EACCES - backend denied access 1531 * EPERM - permission denied 1532 * ENOSPC - repository server out of resources 1533 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1534 */ 1535 static int 1536 refresh_entity(int isservice, void *entity, const char *fmri, 1537 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1538 { 1539 scf_error_t scfe; 1540 int r; 1541 1542 if (!isservice) { 1543 /* 1544 * Let restarter handles refreshing and making new running 1545 * snapshot only if operating on a live repository and not 1546 * running in early import. 1547 */ 1548 if (est->sc_repo_filename == NULL && 1549 est->sc_repo_doorname == NULL && 1550 est->sc_in_emi == 0) { 1551 if (_smf_refresh_instance_i(entity) == 0) { 1552 if (g_verbose) 1553 warn(gettext("Refreshed %s.\n"), fmri); 1554 return (0); 1555 } 1556 1557 switch (scf_error()) { 1558 case SCF_ERROR_BACKEND_ACCESS: 1559 return (EACCES); 1560 1561 case SCF_ERROR_PERMISSION_DENIED: 1562 return (EPERM); 1563 1564 default: 1565 return (-1); 1566 } 1567 } else { 1568 r = refresh_running_snapshot(entity); 1569 switch (r) { 1570 case 0: 1571 break; 1572 1573 case ECONNABORTED: 1574 case ECANCELED: 1575 case EPERM: 1576 case ENOSPC: 1577 break; 1578 1579 default: 1580 bad_error("refresh_running_snapshot", 1581 scf_error()); 1582 } 1583 1584 return (r); 1585 } 1586 } 1587 1588 if (scf_iter_service_instances(iter, entity) != 0) { 1589 switch (scf_error()) { 1590 case SCF_ERROR_CONNECTION_BROKEN: 1591 return (ECONNABORTED); 1592 1593 case SCF_ERROR_DELETED: 1594 return (ECANCELED); 1595 1596 case SCF_ERROR_HANDLE_MISMATCH: 1597 case SCF_ERROR_NOT_BOUND: 1598 case SCF_ERROR_NOT_SET: 1599 default: 1600 bad_error("scf_iter_service_instances", scf_error()); 1601 } 1602 } 1603 1604 for (;;) { 1605 r = scf_iter_next_instance(iter, inst); 1606 if (r == 0) 1607 break; 1608 if (r != 1) { 1609 switch (scf_error()) { 1610 case SCF_ERROR_CONNECTION_BROKEN: 1611 return (ECONNABORTED); 1612 1613 case SCF_ERROR_DELETED: 1614 return (ECANCELED); 1615 1616 case SCF_ERROR_HANDLE_MISMATCH: 1617 case SCF_ERROR_NOT_BOUND: 1618 case SCF_ERROR_NOT_SET: 1619 case SCF_ERROR_INVALID_ARGUMENT: 1620 default: 1621 bad_error("scf_iter_next_instance", 1622 scf_error()); 1623 } 1624 } 1625 1626 /* 1627 * Similarly, just take a new running snapshot if operating on 1628 * a non-live repository or running during early import. 1629 */ 1630 if (est->sc_repo_filename != NULL || 1631 est->sc_repo_doorname != NULL || 1632 est->sc_in_emi == 1) { 1633 r = refresh_running_snapshot(inst); 1634 switch (r) { 1635 case 0: 1636 continue; 1637 1638 case ECONNABORTED: 1639 case ECANCELED: 1640 case EPERM: 1641 case ENOSPC: 1642 break; 1643 default: 1644 bad_error("refresh_running_snapshot", 1645 scf_error()); 1646 } 1647 1648 return (r); 1649 1650 } 1651 1652 if (_smf_refresh_instance_i(inst) == 0) { 1653 if (g_verbose) { 1654 if (scf_instance_get_name(inst, name_buf, 1655 max_scf_name_len + 1) < 0) 1656 (void) strcpy(name_buf, "?"); 1657 1658 warn(gettext("Refreshed %s:%s.\n"), 1659 fmri, name_buf); 1660 } 1661 } else { 1662 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1663 g_verbose) { 1664 scfe = scf_error(); 1665 1666 if (scf_instance_to_fmri(inst, name_buf, 1667 max_scf_name_len + 1) < 0) 1668 (void) strcpy(name_buf, "?"); 1669 1670 warn(gettext( 1671 "Refresh of %s:%s failed: %s.\n"), fmri, 1672 name_buf, scf_strerror(scfe)); 1673 } 1674 } 1675 } 1676 1677 return (0); 1678 } 1679 1680 static void 1681 private_refresh(void) 1682 { 1683 scf_instance_t *pinst = NULL; 1684 scf_iter_t *piter = NULL; 1685 ssize_t fmrilen; 1686 size_t bufsz; 1687 char *fmribuf; 1688 void *ent; 1689 int issvc; 1690 int r; 1691 1692 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1693 return; 1694 1695 assert(cur_svc != NULL); 1696 1697 bufsz = max_scf_fmri_len + 1; 1698 fmribuf = safe_malloc(bufsz); 1699 if (cur_inst) { 1700 issvc = 0; 1701 ent = cur_inst; 1702 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1703 } else { 1704 issvc = 1; 1705 ent = cur_svc; 1706 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1707 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1708 scfdie(); 1709 1710 if ((piter = scf_iter_create(g_hndl)) == NULL) 1711 scfdie(); 1712 } 1713 if (fmrilen < 0) { 1714 free(fmribuf); 1715 if (scf_error() != SCF_ERROR_DELETED) 1716 scfdie(); 1717 1718 warn(emsg_deleted); 1719 return; 1720 } 1721 assert(fmrilen < bufsz); 1722 1723 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1724 switch (r) { 1725 case 0: 1726 break; 1727 1728 case ECONNABORTED: 1729 warn(gettext("Could not refresh %s " 1730 "(repository connection broken).\n"), fmribuf); 1731 break; 1732 1733 case ECANCELED: 1734 warn(emsg_deleted); 1735 break; 1736 1737 case EPERM: 1738 warn(gettext("Could not refresh %s " 1739 "(permission denied).\n"), fmribuf); 1740 break; 1741 1742 case ENOSPC: 1743 warn(gettext("Could not refresh %s " 1744 "(repository server out of resources).\n"), 1745 fmribuf); 1746 break; 1747 1748 case EACCES: 1749 default: 1750 bad_error("refresh_entity", scf_error()); 1751 } 1752 1753 if (issvc) { 1754 scf_instance_destroy(pinst); 1755 scf_iter_destroy(piter); 1756 } 1757 1758 free(fmribuf); 1759 } 1760 1761 1762 static int 1763 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1764 { 1765 cbp->sc_err = scferror2errno(err); 1766 return (UU_WALK_ERROR); 1767 } 1768 1769 static int 1770 stash_scferror(scf_callback_t *cbp) 1771 { 1772 return (stash_scferror_err(cbp, scf_error())); 1773 } 1774 1775 /* 1776 * Import. These functions import a bundle into the repository. 1777 */ 1778 1779 /* 1780 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 1781 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 1782 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 1783 * lcbdata->sc_err to 1784 * ENOMEM - out of memory 1785 * ECONNABORTED - repository connection broken 1786 * ECANCELED - sc_trans's property group was deleted 1787 * EINVAL - p's name is invalid (error printed) 1788 * - p has an invalid value (error printed) 1789 */ 1790 static int 1791 lscf_property_import(void *v, void *pvt) 1792 { 1793 property_t *p = v; 1794 scf_callback_t *lcbdata = pvt; 1795 value_t *vp; 1796 scf_transaction_t *trans = lcbdata->sc_trans; 1797 scf_transaction_entry_t *entr; 1798 scf_value_t *val; 1799 scf_type_t tp; 1800 1801 if ((lcbdata->sc_flags & SCI_NOENABLED || 1802 lcbdata->sc_flags & SCI_DELAYENABLE) && 1803 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 1804 lcbdata->sc_enable = p; 1805 return (UU_WALK_NEXT); 1806 } 1807 1808 entr = scf_entry_create(lcbdata->sc_handle); 1809 if (entr == NULL) { 1810 switch (scf_error()) { 1811 case SCF_ERROR_NO_MEMORY: 1812 return (stash_scferror(lcbdata)); 1813 1814 case SCF_ERROR_INVALID_ARGUMENT: 1815 default: 1816 bad_error("scf_entry_create", scf_error()); 1817 } 1818 } 1819 1820 tp = p->sc_value_type; 1821 1822 if (scf_transaction_property_new(trans, entr, 1823 p->sc_property_name, tp) != 0) { 1824 switch (scf_error()) { 1825 case SCF_ERROR_INVALID_ARGUMENT: 1826 semerr(emsg_invalid_prop_name, p->sc_property_name); 1827 scf_entry_destroy(entr); 1828 return (stash_scferror(lcbdata)); 1829 1830 case SCF_ERROR_EXISTS: 1831 break; 1832 1833 case SCF_ERROR_DELETED: 1834 case SCF_ERROR_CONNECTION_BROKEN: 1835 scf_entry_destroy(entr); 1836 return (stash_scferror(lcbdata)); 1837 1838 case SCF_ERROR_NOT_BOUND: 1839 case SCF_ERROR_HANDLE_MISMATCH: 1840 case SCF_ERROR_NOT_SET: 1841 default: 1842 bad_error("scf_transaction_property_new", scf_error()); 1843 } 1844 1845 if (scf_transaction_property_change_type(trans, entr, 1846 p->sc_property_name, tp) != 0) { 1847 switch (scf_error()) { 1848 case SCF_ERROR_DELETED: 1849 case SCF_ERROR_CONNECTION_BROKEN: 1850 scf_entry_destroy(entr); 1851 return (stash_scferror(lcbdata)); 1852 1853 case SCF_ERROR_INVALID_ARGUMENT: 1854 semerr(emsg_invalid_prop_name, 1855 p->sc_property_name); 1856 scf_entry_destroy(entr); 1857 return (stash_scferror(lcbdata)); 1858 1859 case SCF_ERROR_NOT_FOUND: 1860 case SCF_ERROR_NOT_SET: 1861 case SCF_ERROR_HANDLE_MISMATCH: 1862 case SCF_ERROR_NOT_BOUND: 1863 default: 1864 bad_error( 1865 "scf_transaction_property_change_type", 1866 scf_error()); 1867 } 1868 } 1869 } 1870 1871 for (vp = uu_list_first(p->sc_property_values); 1872 vp != NULL; 1873 vp = uu_list_next(p->sc_property_values, vp)) { 1874 val = scf_value_create(g_hndl); 1875 if (val == NULL) { 1876 switch (scf_error()) { 1877 case SCF_ERROR_NO_MEMORY: 1878 return (stash_scferror(lcbdata)); 1879 1880 case SCF_ERROR_INVALID_ARGUMENT: 1881 default: 1882 bad_error("scf_value_create", scf_error()); 1883 } 1884 } 1885 1886 switch (tp) { 1887 case SCF_TYPE_BOOLEAN: 1888 scf_value_set_boolean(val, vp->sc_u.sc_count); 1889 break; 1890 case SCF_TYPE_COUNT: 1891 scf_value_set_count(val, vp->sc_u.sc_count); 1892 break; 1893 case SCF_TYPE_INTEGER: 1894 scf_value_set_integer(val, vp->sc_u.sc_integer); 1895 break; 1896 default: 1897 assert(vp->sc_u.sc_string != NULL); 1898 if (scf_value_set_from_string(val, tp, 1899 vp->sc_u.sc_string) != 0) { 1900 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 1901 bad_error("scf_value_set_from_string", 1902 scf_error()); 1903 1904 warn(gettext("Value \"%s\" is not a valid " 1905 "%s.\n"), vp->sc_u.sc_string, 1906 scf_type_to_string(tp)); 1907 scf_value_destroy(val); 1908 return (stash_scferror(lcbdata)); 1909 } 1910 break; 1911 } 1912 1913 if (scf_entry_add_value(entr, val) != 0) 1914 bad_error("scf_entry_add_value", scf_error()); 1915 } 1916 1917 return (UU_WALK_NEXT); 1918 } 1919 1920 /* 1921 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 1922 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 1923 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 1924 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 1925 * lcbdata->sc_err to 1926 * ECONNABORTED - repository connection broken 1927 * ENOMEM - out of memory 1928 * ENOSPC - svc.configd is out of resources 1929 * ECANCELED - sc_parent was deleted 1930 * EPERM - could not create property group (permission denied) (error printed) 1931 * - could not modify property group (permission denied) (error printed) 1932 * - could not delete property group (permission denied) (error printed) 1933 * EROFS - could not create property group (repository is read-only) 1934 * - could not delete property group (repository is read-only) 1935 * EACCES - could not create property group (backend access denied) 1936 * - could not delete property group (backend access denied) 1937 * EEXIST - could not create property group (already exists) 1938 * EINVAL - invalid property group name (error printed) 1939 * - invalid property name (error printed) 1940 * - invalid value (error printed) 1941 * EBUSY - new property group deleted (error printed) 1942 * - new property group changed (error printed) 1943 * - property group added (error printed) 1944 * - property group deleted (error printed) 1945 */ 1946 static int 1947 entity_pgroup_import(void *v, void *pvt) 1948 { 1949 pgroup_t *p = v; 1950 scf_callback_t cbdata; 1951 scf_callback_t *lcbdata = pvt; 1952 void *ent = lcbdata->sc_parent; 1953 int issvc = lcbdata->sc_service; 1954 int r; 1955 1956 const char * const pg_changed = gettext("%s changed unexpectedly " 1957 "(new property group \"%s\" changed).\n"); 1958 1959 /* Never import deleted property groups. */ 1960 if (p->sc_pgroup_delete) 1961 return (UU_WALK_NEXT); 1962 1963 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 1964 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 1965 lcbdata->sc_general = p; 1966 return (UU_WALK_NEXT); 1967 } 1968 1969 add_pg: 1970 if (issvc) 1971 r = scf_service_add_pg(ent, p->sc_pgroup_name, 1972 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 1973 else 1974 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 1975 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 1976 if (r != 0) { 1977 switch (scf_error()) { 1978 case SCF_ERROR_DELETED: 1979 case SCF_ERROR_CONNECTION_BROKEN: 1980 case SCF_ERROR_BACKEND_READONLY: 1981 case SCF_ERROR_BACKEND_ACCESS: 1982 case SCF_ERROR_NO_RESOURCES: 1983 return (stash_scferror(lcbdata)); 1984 1985 case SCF_ERROR_EXISTS: 1986 if (lcbdata->sc_flags & SCI_FORCE) 1987 break; 1988 return (stash_scferror(lcbdata)); 1989 1990 case SCF_ERROR_INVALID_ARGUMENT: 1991 warn(emsg_fmri_invalid_pg_name_type, 1992 lcbdata->sc_source_fmri, 1993 p->sc_pgroup_name, p->sc_pgroup_type); 1994 return (stash_scferror(lcbdata)); 1995 1996 case SCF_ERROR_PERMISSION_DENIED: 1997 warn(emsg_pg_add_perm, p->sc_pgroup_name, 1998 lcbdata->sc_target_fmri); 1999 return (stash_scferror(lcbdata)); 2000 2001 case SCF_ERROR_NOT_BOUND: 2002 case SCF_ERROR_HANDLE_MISMATCH: 2003 case SCF_ERROR_NOT_SET: 2004 default: 2005 bad_error("scf_service_add_pg", scf_error()); 2006 } 2007 2008 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2009 switch (scf_error()) { 2010 case SCF_ERROR_CONNECTION_BROKEN: 2011 case SCF_ERROR_DELETED: 2012 return (stash_scferror(lcbdata)); 2013 2014 case SCF_ERROR_INVALID_ARGUMENT: 2015 warn(emsg_fmri_invalid_pg_name, 2016 lcbdata->sc_source_fmri, 2017 p->sc_pgroup_name); 2018 return (stash_scferror(lcbdata)); 2019 2020 case SCF_ERROR_NOT_FOUND: 2021 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2022 p->sc_pgroup_name); 2023 lcbdata->sc_err = EBUSY; 2024 return (UU_WALK_ERROR); 2025 2026 case SCF_ERROR_NOT_BOUND: 2027 case SCF_ERROR_HANDLE_MISMATCH: 2028 case SCF_ERROR_NOT_SET: 2029 default: 2030 bad_error("entity_get_pg", scf_error()); 2031 } 2032 } 2033 2034 if (lcbdata->sc_flags & SCI_KEEP) 2035 goto props; 2036 2037 if (scf_pg_delete(imp_pg) != 0) { 2038 switch (scf_error()) { 2039 case SCF_ERROR_DELETED: 2040 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2041 p->sc_pgroup_name); 2042 lcbdata->sc_err = EBUSY; 2043 return (UU_WALK_ERROR); 2044 2045 case SCF_ERROR_PERMISSION_DENIED: 2046 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2047 lcbdata->sc_target_fmri); 2048 return (stash_scferror(lcbdata)); 2049 2050 case SCF_ERROR_BACKEND_READONLY: 2051 case SCF_ERROR_BACKEND_ACCESS: 2052 case SCF_ERROR_CONNECTION_BROKEN: 2053 return (stash_scferror(lcbdata)); 2054 2055 case SCF_ERROR_NOT_SET: 2056 default: 2057 bad_error("scf_pg_delete", scf_error()); 2058 } 2059 } 2060 2061 goto add_pg; 2062 } 2063 2064 props: 2065 2066 /* 2067 * Add properties to property group, if any. 2068 */ 2069 cbdata.sc_handle = lcbdata->sc_handle; 2070 cbdata.sc_parent = imp_pg; 2071 cbdata.sc_flags = lcbdata->sc_flags; 2072 cbdata.sc_trans = imp_tx; 2073 cbdata.sc_enable = NULL; 2074 2075 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2076 switch (scf_error()) { 2077 case SCF_ERROR_BACKEND_ACCESS: 2078 case SCF_ERROR_BACKEND_READONLY: 2079 case SCF_ERROR_CONNECTION_BROKEN: 2080 return (stash_scferror(lcbdata)); 2081 2082 case SCF_ERROR_DELETED: 2083 warn(pg_changed, lcbdata->sc_target_fmri, 2084 p->sc_pgroup_name); 2085 lcbdata->sc_err = EBUSY; 2086 return (UU_WALK_ERROR); 2087 2088 case SCF_ERROR_PERMISSION_DENIED: 2089 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2090 lcbdata->sc_target_fmri); 2091 return (stash_scferror(lcbdata)); 2092 2093 case SCF_ERROR_NOT_BOUND: 2094 case SCF_ERROR_NOT_SET: 2095 case SCF_ERROR_IN_USE: 2096 case SCF_ERROR_HANDLE_MISMATCH: 2097 default: 2098 bad_error("scf_transaction_start", scf_error()); 2099 } 2100 } 2101 2102 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2103 UU_DEFAULT) != 0) { 2104 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2105 bad_error("uu_list_walk", uu_error()); 2106 scf_transaction_reset(imp_tx); 2107 2108 lcbdata->sc_err = cbdata.sc_err; 2109 if (cbdata.sc_err == ECANCELED) { 2110 warn(pg_changed, lcbdata->sc_target_fmri, 2111 p->sc_pgroup_name); 2112 lcbdata->sc_err = EBUSY; 2113 } 2114 return (UU_WALK_ERROR); 2115 } 2116 2117 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2118 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2119 2120 /* 2121 * take the snapshot running snapshot then 2122 * import the stored general/enable property 2123 */ 2124 r = take_snap(ent, snap_running, imp_rsnap); 2125 switch (r) { 2126 case 0: 2127 break; 2128 2129 case ECONNABORTED: 2130 warn(gettext("Could not take %s snapshot on import " 2131 "(repository connection broken).\n"), 2132 snap_running); 2133 lcbdata->sc_err = r; 2134 return (UU_WALK_ERROR); 2135 case ECANCELED: 2136 warn(emsg_deleted); 2137 lcbdata->sc_err = r; 2138 return (UU_WALK_ERROR); 2139 2140 case EPERM: 2141 warn(gettext("Could not take %s snapshot " 2142 "(permission denied).\n"), snap_running); 2143 lcbdata->sc_err = r; 2144 return (UU_WALK_ERROR); 2145 2146 case ENOSPC: 2147 warn(gettext("Could not take %s snapshot" 2148 "(repository server out of resources).\n"), 2149 snap_running); 2150 lcbdata->sc_err = r; 2151 return (UU_WALK_ERROR); 2152 2153 default: 2154 bad_error("take_snap", r); 2155 } 2156 2157 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2158 if (r != UU_WALK_NEXT) { 2159 if (r != UU_WALK_ERROR) 2160 bad_error("lscf_property_import", r); 2161 return (EINVAL); 2162 } 2163 } 2164 2165 r = scf_transaction_commit(imp_tx); 2166 switch (r) { 2167 case 1: 2168 r = UU_WALK_NEXT; 2169 break; 2170 2171 case 0: 2172 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2173 lcbdata->sc_err = EBUSY; 2174 r = UU_WALK_ERROR; 2175 break; 2176 2177 case -1: 2178 switch (scf_error()) { 2179 case SCF_ERROR_BACKEND_READONLY: 2180 case SCF_ERROR_BACKEND_ACCESS: 2181 case SCF_ERROR_CONNECTION_BROKEN: 2182 case SCF_ERROR_NO_RESOURCES: 2183 r = stash_scferror(lcbdata); 2184 break; 2185 2186 case SCF_ERROR_DELETED: 2187 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2188 p->sc_pgroup_name); 2189 lcbdata->sc_err = EBUSY; 2190 r = UU_WALK_ERROR; 2191 break; 2192 2193 case SCF_ERROR_PERMISSION_DENIED: 2194 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2195 lcbdata->sc_target_fmri); 2196 r = stash_scferror(lcbdata); 2197 break; 2198 2199 case SCF_ERROR_NOT_SET: 2200 case SCF_ERROR_INVALID_ARGUMENT: 2201 case SCF_ERROR_NOT_BOUND: 2202 default: 2203 bad_error("scf_transaction_commit", scf_error()); 2204 } 2205 break; 2206 2207 default: 2208 bad_error("scf_transaction_commit", r); 2209 } 2210 2211 scf_transaction_destroy_children(imp_tx); 2212 2213 return (r); 2214 } 2215 2216 /* 2217 * Returns 2218 * 0 - success 2219 * ECONNABORTED - repository connection broken 2220 * ENOMEM - out of memory 2221 * ENOSPC - svc.configd is out of resources 2222 * ECANCELED - inst was deleted 2223 * EPERM - could not create property group (permission denied) (error printed) 2224 * - could not modify property group (permission denied) (error printed) 2225 * EROFS - could not create property group (repository is read-only) 2226 * EACCES - could not create property group (backend access denied) 2227 * EEXIST - could not create property group (already exists) 2228 * EINVAL - invalid property group name (error printed) 2229 * - invalid property name (error printed) 2230 * - invalid value (error printed) 2231 * EBUSY - new property group changed (error printed) 2232 */ 2233 static int 2234 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2235 const entity_t *isvc, int flags) 2236 { 2237 scf_callback_t cbdata; 2238 2239 cbdata.sc_handle = scf_service_handle(svc); 2240 cbdata.sc_parent = svc; 2241 cbdata.sc_service = 1; 2242 cbdata.sc_general = 0; 2243 cbdata.sc_enable = 0; 2244 cbdata.sc_flags = flags; 2245 cbdata.sc_source_fmri = isvc->sc_fmri; 2246 cbdata.sc_target_fmri = target_fmri; 2247 2248 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2249 UU_DEFAULT) != 0) { 2250 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2251 bad_error("uu_list_walk", uu_error()); 2252 2253 return (cbdata.sc_err); 2254 } 2255 2256 return (0); 2257 } 2258 2259 /* 2260 * Returns 2261 * 0 - success 2262 * ECONNABORTED - repository connection broken 2263 * ENOMEM - out of memory 2264 * ENOSPC - svc.configd is out of resources 2265 * ECANCELED - inst was deleted 2266 * EPERM - could not create property group (permission denied) (error printed) 2267 * - could not modify property group (permission denied) (error printed) 2268 * EROFS - could not create property group (repository is read-only) 2269 * EACCES - could not create property group (backend access denied) 2270 * EEXIST - could not create property group (already exists) 2271 * EINVAL - invalid property group name (error printed) 2272 * - invalid property name (error printed) 2273 * - invalid value (error printed) 2274 * EBUSY - new property group changed (error printed) 2275 */ 2276 static int 2277 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2278 const entity_t *iinst, int flags) 2279 { 2280 scf_callback_t cbdata; 2281 2282 cbdata.sc_handle = scf_instance_handle(inst); 2283 cbdata.sc_parent = inst; 2284 cbdata.sc_service = 0; 2285 cbdata.sc_general = NULL; 2286 cbdata.sc_enable = NULL; 2287 cbdata.sc_flags = flags; 2288 cbdata.sc_source_fmri = iinst->sc_fmri; 2289 cbdata.sc_target_fmri = target_fmri; 2290 2291 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2292 UU_DEFAULT) != 0) { 2293 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2294 bad_error("uu_list_walk", uu_error()); 2295 2296 return (cbdata.sc_err); 2297 } 2298 2299 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2300 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2301 /* 2302 * If importing with the SCI_NOENABLED flag then 2303 * skip the delay, but if not then add the delay 2304 * of the enable property. 2305 */ 2306 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2307 cbdata.sc_flags |= SCI_DELAYENABLE; 2308 } 2309 2310 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2311 != UU_WALK_NEXT) 2312 return (cbdata.sc_err); 2313 } 2314 2315 return (0); 2316 } 2317 2318 /* 2319 * Report the reasons why we can't upgrade pg2 to pg1. 2320 */ 2321 static void 2322 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2323 int new) 2324 { 2325 property_t *p1, *p2; 2326 2327 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2328 2329 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2330 return; 2331 2332 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2333 p1 != NULL; 2334 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2335 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2336 if (p2 != NULL) { 2337 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2338 new); 2339 continue; 2340 } 2341 2342 if (new) 2343 warn(gettext("Conflict upgrading %s (new property " 2344 "group \"%s\" is missing property \"%s\").\n"), 2345 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2346 else 2347 warn(gettext("Conflict upgrading %s (property " 2348 "\"%s/%s\" is missing).\n"), fmri, 2349 pg1->sc_pgroup_name, p1->sc_property_name); 2350 } 2351 2352 /* 2353 * Since pg1 should be from the manifest, any properties in pg2 which 2354 * aren't in pg1 shouldn't be reported as conflicts. 2355 */ 2356 } 2357 2358 /* 2359 * Add transaction entries to tx which will upgrade cur's pg according to old 2360 * & new. 2361 * 2362 * Returns 2363 * 0 - success 2364 * EINVAL - new has a property with an invalid name or value (message emitted) 2365 * ENOMEM - out of memory 2366 */ 2367 static int 2368 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2369 pgroup_t *cur, int speak, const char *fmri) 2370 { 2371 property_t *p, *new_p, *cur_p; 2372 scf_transaction_entry_t *e; 2373 int r; 2374 int is_general; 2375 int is_protected; 2376 2377 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2378 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2379 bad_error("uu_list_walk", uu_error()); 2380 2381 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2382 2383 for (p = uu_list_first(old->sc_pgroup_props); 2384 p != NULL; 2385 p = uu_list_next(old->sc_pgroup_props, p)) { 2386 /* p is a property in the old property group. */ 2387 2388 /* Protect live properties. */ 2389 is_protected = 0; 2390 if (is_general) { 2391 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2392 0 || 2393 strcmp(p->sc_property_name, 2394 SCF_PROPERTY_RESTARTER) == 0) 2395 is_protected = 1; 2396 } 2397 2398 /* Look for the same property in the new properties. */ 2399 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2400 if (new_p != NULL) { 2401 new_p->sc_seen = 1; 2402 2403 /* 2404 * If the new property is the same as the old, don't do 2405 * anything (leave any user customizations). 2406 */ 2407 if (prop_equal(p, new_p, NULL, NULL, 0)) 2408 continue; 2409 2410 if (new_p->sc_property_override) 2411 goto upgrade; 2412 } 2413 2414 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2415 if (cur_p == NULL) { 2416 /* 2417 * p has been deleted from the repository. If we were 2418 * going to delete it anyway, do nothing. Otherwise 2419 * report a conflict. 2420 */ 2421 if (new_p == NULL) 2422 continue; 2423 2424 if (is_protected) 2425 continue; 2426 2427 warn(gettext("Conflict upgrading %s " 2428 "(property \"%s/%s\" is missing).\n"), fmri, 2429 old->sc_pgroup_name, p->sc_property_name); 2430 continue; 2431 } 2432 2433 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2434 /* 2435 * Conflict. Don't warn if the property is already the 2436 * way we want it, though. 2437 */ 2438 if (is_protected) 2439 continue; 2440 2441 if (new_p == NULL) 2442 (void) prop_equal(p, cur_p, fmri, 2443 old->sc_pgroup_name, 0); 2444 else 2445 (void) prop_equal(cur_p, new_p, fmri, 2446 old->sc_pgroup_name, 0); 2447 continue; 2448 } 2449 2450 if (is_protected) { 2451 if (speak) 2452 warn(gettext("%s: Refusing to upgrade " 2453 "\"%s/%s\" (live property).\n"), fmri, 2454 old->sc_pgroup_name, p->sc_property_name); 2455 continue; 2456 } 2457 2458 upgrade: 2459 /* p hasn't been customized in the repository. Upgrade it. */ 2460 if (new_p == NULL) { 2461 /* p was deleted. Delete from cur if unchanged. */ 2462 if (speak) 2463 warn(gettext( 2464 "%s: Deleting property \"%s/%s\".\n"), 2465 fmri, old->sc_pgroup_name, 2466 p->sc_property_name); 2467 2468 e = scf_entry_create(g_hndl); 2469 if (e == NULL) 2470 return (ENOMEM); 2471 2472 if (scf_transaction_property_delete(tx, e, 2473 p->sc_property_name) != 0) { 2474 switch (scf_error()) { 2475 case SCF_ERROR_DELETED: 2476 scf_entry_destroy(e); 2477 return (ECANCELED); 2478 2479 case SCF_ERROR_CONNECTION_BROKEN: 2480 scf_entry_destroy(e); 2481 return (ECONNABORTED); 2482 2483 case SCF_ERROR_NOT_FOUND: 2484 /* 2485 * This can happen if cur is from the 2486 * running snapshot (and it differs 2487 * from the live properties). 2488 */ 2489 scf_entry_destroy(e); 2490 break; 2491 2492 case SCF_ERROR_HANDLE_MISMATCH: 2493 case SCF_ERROR_NOT_BOUND: 2494 case SCF_ERROR_NOT_SET: 2495 case SCF_ERROR_INVALID_ARGUMENT: 2496 default: 2497 bad_error( 2498 "scf_transaction_property_delete", 2499 scf_error()); 2500 } 2501 } 2502 } else { 2503 scf_callback_t ctx; 2504 2505 if (speak) 2506 warn(gettext( 2507 "%s: Upgrading property \"%s/%s\".\n"), 2508 fmri, old->sc_pgroup_name, 2509 p->sc_property_name); 2510 2511 ctx.sc_handle = g_hndl; 2512 ctx.sc_trans = tx; 2513 ctx.sc_flags = 0; 2514 2515 r = lscf_property_import(new_p, &ctx); 2516 if (r != UU_WALK_NEXT) { 2517 if (r != UU_WALK_ERROR) 2518 bad_error("lscf_property_import", r); 2519 return (EINVAL); 2520 } 2521 } 2522 } 2523 2524 /* Go over the properties which were added. */ 2525 for (new_p = uu_list_first(new->sc_pgroup_props); 2526 new_p != NULL; 2527 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 2528 if (new_p->sc_seen) 2529 continue; 2530 2531 /* This is a new property. */ 2532 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 2533 if (cur_p == NULL) { 2534 scf_callback_t ctx; 2535 2536 ctx.sc_handle = g_hndl; 2537 ctx.sc_trans = tx; 2538 ctx.sc_flags = 0; 2539 2540 r = lscf_property_import(new_p, &ctx); 2541 if (r != UU_WALK_NEXT) { 2542 if (r != UU_WALK_ERROR) 2543 bad_error("lscf_property_import", r); 2544 return (EINVAL); 2545 } 2546 continue; 2547 } 2548 2549 /* 2550 * Report a conflict if the new property differs from the 2551 * current one. Unless it's general/enabled, since that's 2552 * never in the last-import snapshot. 2553 */ 2554 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 2555 0 && 2556 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 2557 continue; 2558 2559 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 2560 } 2561 2562 return (0); 2563 } 2564 2565 /* 2566 * Upgrade pg according to old & new. 2567 * 2568 * Returns 2569 * 0 - success 2570 * ECONNABORTED - repository connection broken 2571 * ENOMEM - out of memory 2572 * ENOSPC - svc.configd is out of resources 2573 * ECANCELED - pg was deleted 2574 * EPERM - couldn't modify pg (permission denied) 2575 * EROFS - couldn't modify pg (backend read-only) 2576 * EACCES - couldn't modify pg (backend access denied) 2577 * EINVAL - new has a property with invalid name or value (error printed) 2578 * EBUSY - pg changed unexpectedly 2579 */ 2580 static int 2581 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 2582 pgroup_t *new, int speak, const char *fmri) 2583 { 2584 int r; 2585 2586 if (scf_transaction_start(imp_tx, pg) != 0) { 2587 switch (scf_error()) { 2588 case SCF_ERROR_CONNECTION_BROKEN: 2589 case SCF_ERROR_DELETED: 2590 case SCF_ERROR_PERMISSION_DENIED: 2591 case SCF_ERROR_BACKEND_READONLY: 2592 case SCF_ERROR_BACKEND_ACCESS: 2593 return (scferror2errno(scf_error())); 2594 2595 case SCF_ERROR_HANDLE_MISMATCH: 2596 case SCF_ERROR_IN_USE: 2597 case SCF_ERROR_NOT_BOUND: 2598 case SCF_ERROR_NOT_SET: 2599 default: 2600 bad_error("scf_transaction_start", scf_error()); 2601 } 2602 } 2603 2604 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 2605 switch (r) { 2606 case 0: 2607 break; 2608 2609 case EINVAL: 2610 case ENOMEM: 2611 scf_transaction_destroy_children(imp_tx); 2612 return (r); 2613 2614 default: 2615 bad_error("add_upgrade_entries", r); 2616 } 2617 2618 r = scf_transaction_commit(imp_tx); 2619 2620 scf_transaction_destroy_children(imp_tx); 2621 2622 switch (r) { 2623 case 1: 2624 break; 2625 2626 case 0: 2627 return (EBUSY); 2628 2629 case -1: 2630 switch (scf_error()) { 2631 case SCF_ERROR_CONNECTION_BROKEN: 2632 case SCF_ERROR_NO_RESOURCES: 2633 case SCF_ERROR_PERMISSION_DENIED: 2634 case SCF_ERROR_BACKEND_READONLY: 2635 case SCF_ERROR_BACKEND_ACCESS: 2636 case SCF_ERROR_DELETED: 2637 return (scferror2errno(scf_error())); 2638 2639 case SCF_ERROR_NOT_BOUND: 2640 case SCF_ERROR_INVALID_ARGUMENT: 2641 case SCF_ERROR_NOT_SET: 2642 default: 2643 bad_error("scf_transaction_commit", scf_error()); 2644 } 2645 2646 default: 2647 bad_error("scf_transaction_commit", r); 2648 } 2649 2650 return (0); 2651 } 2652 2653 /* 2654 * Compares two entity FMRIs. Returns 2655 * 2656 * 1 - equal 2657 * 0 - not equal 2658 * -1 - f1 is invalid or not an entity 2659 * -2 - f2 is invalid or not an entity 2660 */ 2661 static int 2662 fmri_equal(const char *f1, const char *f2) 2663 { 2664 int r; 2665 const char *s1, *i1, *pg1; 2666 const char *s2, *i2, *pg2; 2667 2668 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 2669 return (-1); 2670 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 2671 return (-1); 2672 2673 if (s1 == NULL || pg1 != NULL) 2674 return (-1); 2675 2676 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 2677 return (-2); 2678 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 2679 return (-2); 2680 2681 if (s2 == NULL || pg2 != NULL) 2682 return (-2); 2683 2684 r = strcmp(s1, s2); 2685 if (r != 0) 2686 return (0); 2687 2688 if (i1 == NULL && i2 == NULL) 2689 return (1); 2690 2691 if (i1 == NULL || i2 == NULL) 2692 return (0); 2693 2694 return (strcmp(i1, i2) == 0); 2695 } 2696 2697 /* 2698 * Import a dependent by creating a dependency property group in the dependent 2699 * entity. If lcbdata->sc_trans is set, assume it's been started on the 2700 * dependents pg, and add an entry to create a new property for this 2701 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 2702 * 2703 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 2704 * lcbdata->sc_err to 2705 * ECONNABORTED - repository connection broken 2706 * ENOMEM - out of memory 2707 * ENOSPC - configd is out of resources 2708 * EINVAL - target is invalid (error printed) 2709 * - target is not an entity (error printed) 2710 * - dependent has invalid name (error printed) 2711 * - invalid property name (error printed) 2712 * - invalid value (error printed) 2713 * - scope of target does not exist (error printed) 2714 * EPERM - couldn't create target (permission denied) (error printed) 2715 * - couldn't create dependency pg (permission denied) (error printed) 2716 * - couldn't modify dependency pg (permission denied) (error printed) 2717 * EROFS - couldn't create target (repository read-only) 2718 * - couldn't create dependency pg (repository read-only) 2719 * EACCES - couldn't create target (backend access denied) 2720 * - couldn't create dependency pg (backend access denied) 2721 * ECANCELED - sc_trans's pg was deleted 2722 * EALREADY - property for dependent already exists in sc_trans's pg 2723 * EEXIST - dependency pg already exists in target (error printed) 2724 * EBUSY - target deleted (error printed) 2725 * - property group changed during import (error printed) 2726 */ 2727 static int 2728 lscf_dependent_import(void *a1, void *pvt) 2729 { 2730 pgroup_t *pgrp = a1; 2731 scf_callback_t *lcbdata = pvt; 2732 2733 int isservice; 2734 int ret; 2735 scf_transaction_entry_t *e; 2736 scf_value_t *val; 2737 scf_callback_t dependent_cbdata; 2738 scf_error_t scfe; 2739 2740 /* 2741 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 2742 * it's invalid, we fail before modifying the repository. 2743 */ 2744 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 2745 &dependent_cbdata.sc_parent, &isservice); 2746 switch (scfe) { 2747 case SCF_ERROR_NONE: 2748 break; 2749 2750 case SCF_ERROR_NO_MEMORY: 2751 return (stash_scferror_err(lcbdata, scfe)); 2752 2753 case SCF_ERROR_INVALID_ARGUMENT: 2754 semerr(gettext("The FMRI for the \"%s\" dependent is " 2755 "invalid.\n"), pgrp->sc_pgroup_name); 2756 return (stash_scferror_err(lcbdata, scfe)); 2757 2758 case SCF_ERROR_CONSTRAINT_VIOLATED: 2759 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 2760 "specifies neither a service nor an instance.\n"), 2761 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 2762 return (stash_scferror_err(lcbdata, scfe)); 2763 2764 case SCF_ERROR_NOT_FOUND: 2765 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 2766 &dependent_cbdata.sc_parent, &isservice); 2767 switch (scfe) { 2768 case SCF_ERROR_NONE: 2769 break; 2770 2771 case SCF_ERROR_NO_MEMORY: 2772 case SCF_ERROR_BACKEND_READONLY: 2773 case SCF_ERROR_BACKEND_ACCESS: 2774 return (stash_scferror_err(lcbdata, scfe)); 2775 2776 case SCF_ERROR_NOT_FOUND: 2777 semerr(gettext("The scope in FMRI \"%s\" for the " 2778 "\"%s\" dependent does not exist.\n"), 2779 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 2780 lcbdata->sc_err = EINVAL; 2781 return (UU_WALK_ERROR); 2782 2783 case SCF_ERROR_PERMISSION_DENIED: 2784 warn(gettext( 2785 "Could not create %s (permission denied).\n"), 2786 pgrp->sc_pgroup_fmri); 2787 return (stash_scferror_err(lcbdata, scfe)); 2788 2789 case SCF_ERROR_INVALID_ARGUMENT: 2790 case SCF_ERROR_CONSTRAINT_VIOLATED: 2791 default: 2792 bad_error("create_entity", scfe); 2793 } 2794 break; 2795 2796 default: 2797 bad_error("fmri_to_entity", scfe); 2798 } 2799 2800 if (lcbdata->sc_trans != NULL) { 2801 e = scf_entry_create(lcbdata->sc_handle); 2802 if (e == NULL) { 2803 if (scf_error() != SCF_ERROR_NO_MEMORY) 2804 bad_error("scf_entry_create", scf_error()); 2805 2806 entity_destroy(dependent_cbdata.sc_parent, isservice); 2807 return (stash_scferror(lcbdata)); 2808 } 2809 2810 if (scf_transaction_property_new(lcbdata->sc_trans, e, 2811 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 2812 switch (scf_error()) { 2813 case SCF_ERROR_INVALID_ARGUMENT: 2814 warn(gettext("Dependent of %s has invalid name " 2815 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 2816 pgrp->sc_pgroup_name); 2817 /* FALLTHROUGH */ 2818 2819 case SCF_ERROR_DELETED: 2820 case SCF_ERROR_CONNECTION_BROKEN: 2821 scf_entry_destroy(e); 2822 entity_destroy(dependent_cbdata.sc_parent, 2823 isservice); 2824 return (stash_scferror(lcbdata)); 2825 2826 case SCF_ERROR_EXISTS: 2827 scf_entry_destroy(e); 2828 entity_destroy(dependent_cbdata.sc_parent, 2829 isservice); 2830 lcbdata->sc_err = EALREADY; 2831 return (UU_WALK_ERROR); 2832 2833 case SCF_ERROR_NOT_BOUND: 2834 case SCF_ERROR_HANDLE_MISMATCH: 2835 case SCF_ERROR_NOT_SET: 2836 default: 2837 bad_error("scf_transaction_property_new", 2838 scf_error()); 2839 } 2840 } 2841 2842 val = scf_value_create(lcbdata->sc_handle); 2843 if (val == NULL) { 2844 if (scf_error() != SCF_ERROR_NO_MEMORY) 2845 bad_error("scf_value_create", scf_error()); 2846 2847 entity_destroy(dependent_cbdata.sc_parent, isservice); 2848 return (stash_scferror(lcbdata)); 2849 } 2850 2851 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 2852 pgrp->sc_pgroup_fmri) != 0) 2853 /* invalid should have been caught above */ 2854 bad_error("scf_value_set_from_string", scf_error()); 2855 2856 if (scf_entry_add_value(e, val) != 0) 2857 bad_error("scf_entry_add_value", scf_error()); 2858 } 2859 2860 /* Add the property group to the target entity. */ 2861 2862 dependent_cbdata.sc_handle = lcbdata->sc_handle; 2863 dependent_cbdata.sc_flags = 0; 2864 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 2865 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 2866 2867 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 2868 2869 entity_destroy(dependent_cbdata.sc_parent, isservice); 2870 2871 if (ret == UU_WALK_NEXT) 2872 return (ret); 2873 2874 if (ret != UU_WALK_ERROR) 2875 bad_error("entity_pgroup_import", ret); 2876 2877 switch (dependent_cbdata.sc_err) { 2878 case ECANCELED: 2879 warn(gettext("%s deleted unexpectedly.\n"), 2880 pgrp->sc_pgroup_fmri); 2881 lcbdata->sc_err = EBUSY; 2882 break; 2883 2884 case EEXIST: 2885 warn(gettext("Could not create \"%s\" dependency in %s " 2886 "(already exists).\n"), pgrp->sc_pgroup_name, 2887 pgrp->sc_pgroup_fmri); 2888 /* FALLTHROUGH */ 2889 2890 default: 2891 lcbdata->sc_err = dependent_cbdata.sc_err; 2892 } 2893 2894 return (UU_WALK_ERROR); 2895 } 2896 2897 static int upgrade_dependent(const scf_property_t *, const entity_t *, 2898 const scf_snaplevel_t *, scf_transaction_t *); 2899 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 2900 const pgroup_t *); 2901 2902 /* 2903 * Upgrade uncustomized dependents of ent to those specified in ient. Read 2904 * the current dependent targets from running (the snaplevel of a running 2905 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 2906 * scf_instance_t * according to ient, otherwise). Draw the ancestral 2907 * dependent targets and dependency properties from li_dpts_pg (the 2908 * "dependents" property group in snpl) and snpl (the snaplevel which 2909 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 2910 * snpl doesn't have a "dependents" property group, and any dependents in ient 2911 * are new. 2912 * 2913 * Returns 2914 * 0 - success 2915 * ECONNABORTED - repository connection broken 2916 * ENOMEM - out of memory 2917 * ENOSPC - configd is out of resources 2918 * ECANCELED - ent was deleted 2919 * ENODEV - the entity containing li_dpts_pg was deleted 2920 * EPERM - could not modify dependents pg (permission denied) (error printed) 2921 * - couldn't upgrade dependent (permission denied) (error printed) 2922 * - couldn't create dependent (permission denied) (error printed) 2923 * EROFS - could not modify dependents pg (repository read-only) 2924 * - couldn't upgrade dependent (repository read-only) 2925 * - couldn't create dependent (repository read-only) 2926 * EACCES - could not modify dependents pg (backend access denied) 2927 * - could not upgrade dependent (backend access denied) 2928 * - could not create dependent (backend access denied) 2929 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 2930 * - dependent target deleted (error printed) 2931 * - dependent pg changed (error printed) 2932 * EINVAL - new dependent is invalid (error printed) 2933 * EBADF - snpl is corrupt (error printed) 2934 * - snpl has corrupt pg (error printed) 2935 * - dependency pg in target is corrupt (error printed) 2936 * - target has corrupt snapshot (error printed) 2937 * EEXIST - dependency pg already existed in target service (error printed) 2938 */ 2939 static int 2940 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 2941 const scf_snaplevel_t *snpl, const entity_t *ient, 2942 const scf_snaplevel_t *running, void *ent) 2943 { 2944 pgroup_t *new_dpt_pgroup; 2945 scf_callback_t cbdata; 2946 int r, unseen, tx_started = 0; 2947 int have_cur_depts; 2948 2949 const char * const dependents = "dependents"; 2950 2951 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 2952 2953 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 2954 /* Nothing to do. */ 2955 return (0); 2956 2957 /* Fetch the current version of the "dependents" property group. */ 2958 have_cur_depts = 1; 2959 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 2960 switch (scf_error()) { 2961 case SCF_ERROR_NOT_FOUND: 2962 break; 2963 2964 case SCF_ERROR_DELETED: 2965 case SCF_ERROR_CONNECTION_BROKEN: 2966 return (scferror2errno(scf_error())); 2967 2968 case SCF_ERROR_NOT_SET: 2969 case SCF_ERROR_INVALID_ARGUMENT: 2970 case SCF_ERROR_HANDLE_MISMATCH: 2971 case SCF_ERROR_NOT_BOUND: 2972 default: 2973 bad_error("entity_get_pg", scf_error()); 2974 } 2975 2976 have_cur_depts = 0; 2977 } 2978 2979 /* Fetch the running version of the "dependents" property group. */ 2980 ud_run_dpts_pg_set = 0; 2981 if (running != NULL) 2982 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 2983 else 2984 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 2985 if (r == 0) { 2986 ud_run_dpts_pg_set = 1; 2987 } else { 2988 switch (scf_error()) { 2989 case SCF_ERROR_NOT_FOUND: 2990 break; 2991 2992 case SCF_ERROR_DELETED: 2993 case SCF_ERROR_CONNECTION_BROKEN: 2994 return (scferror2errno(scf_error())); 2995 2996 case SCF_ERROR_NOT_SET: 2997 case SCF_ERROR_INVALID_ARGUMENT: 2998 case SCF_ERROR_HANDLE_MISMATCH: 2999 case SCF_ERROR_NOT_BOUND: 3000 default: 3001 bad_error(running ? "scf_snaplevel_get_pg" : 3002 "entity_get_pg", scf_error()); 3003 } 3004 } 3005 3006 /* 3007 * Clear the seen fields of the dependents, so we can tell which ones 3008 * are new. 3009 */ 3010 if (uu_list_walk(ient->sc_dependents, clear_int, 3011 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3012 bad_error("uu_list_walk", uu_error()); 3013 3014 if (li_dpts_pg != NULL) { 3015 /* 3016 * Each property in li_dpts_pg represents a dependent tag in 3017 * the old manifest. For each, call upgrade_dependent(), 3018 * which will change ud_cur_depts_pg or dependencies in other 3019 * services as appropriate. Note (a) that changes to 3020 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3021 * made en masse, and (b) it's ok if the entity doesn't have 3022 * a current version of the "dependents" property group, 3023 * because we'll just consider all dependents as customized 3024 * (by being deleted). 3025 */ 3026 3027 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3028 switch (scf_error()) { 3029 case SCF_ERROR_DELETED: 3030 return (ENODEV); 3031 3032 case SCF_ERROR_CONNECTION_BROKEN: 3033 return (ECONNABORTED); 3034 3035 case SCF_ERROR_HANDLE_MISMATCH: 3036 case SCF_ERROR_NOT_BOUND: 3037 case SCF_ERROR_NOT_SET: 3038 default: 3039 bad_error("scf_iter_pg_properties", 3040 scf_error()); 3041 } 3042 } 3043 3044 if (have_cur_depts && 3045 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3046 switch (scf_error()) { 3047 case SCF_ERROR_BACKEND_ACCESS: 3048 case SCF_ERROR_BACKEND_READONLY: 3049 case SCF_ERROR_CONNECTION_BROKEN: 3050 return (scferror2errno(scf_error())); 3051 3052 case SCF_ERROR_DELETED: 3053 warn(emsg_pg_deleted, ient->sc_fmri, 3054 dependents); 3055 return (EBUSY); 3056 3057 case SCF_ERROR_PERMISSION_DENIED: 3058 warn(emsg_pg_mod_perm, dependents, 3059 ient->sc_fmri); 3060 return (scferror2errno(scf_error())); 3061 3062 case SCF_ERROR_HANDLE_MISMATCH: 3063 case SCF_ERROR_IN_USE: 3064 case SCF_ERROR_NOT_BOUND: 3065 case SCF_ERROR_NOT_SET: 3066 default: 3067 bad_error("scf_transaction_start", scf_error()); 3068 } 3069 } 3070 tx_started = have_cur_depts; 3071 3072 for (;;) { 3073 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3074 if (r == 0) 3075 break; 3076 if (r == 1) { 3077 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3078 tx_started ? ud_tx : NULL); 3079 switch (r) { 3080 case 0: 3081 continue; 3082 3083 case ECONNABORTED: 3084 case ENOMEM: 3085 case ENOSPC: 3086 case EBADF: 3087 case EBUSY: 3088 case EINVAL: 3089 case EPERM: 3090 case EROFS: 3091 case EACCES: 3092 case EEXIST: 3093 break; 3094 3095 case ECANCELED: 3096 r = ENODEV; 3097 break; 3098 3099 default: 3100 bad_error("upgrade_dependent", r); 3101 } 3102 3103 if (tx_started) 3104 scf_transaction_destroy_children(ud_tx); 3105 return (r); 3106 } 3107 if (r != -1) 3108 bad_error("scf_iter_next_property", r); 3109 3110 switch (scf_error()) { 3111 case SCF_ERROR_DELETED: 3112 r = ENODEV; 3113 break; 3114 3115 case SCF_ERROR_CONNECTION_BROKEN: 3116 r = ECONNABORTED; 3117 break; 3118 3119 case SCF_ERROR_NOT_SET: 3120 case SCF_ERROR_INVALID_ARGUMENT: 3121 case SCF_ERROR_NOT_BOUND: 3122 case SCF_ERROR_HANDLE_MISMATCH: 3123 default: 3124 bad_error("scf_iter_next_property", 3125 scf_error()); 3126 } 3127 3128 if (tx_started) 3129 scf_transaction_destroy_children(ud_tx); 3130 return (r); 3131 } 3132 } 3133 3134 /* import unseen dependents */ 3135 unseen = 0; 3136 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3137 new_dpt_pgroup != NULL; 3138 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3139 new_dpt_pgroup)) { 3140 if (!new_dpt_pgroup->sc_pgroup_seen) { 3141 unseen = 1; 3142 break; 3143 } 3144 } 3145 3146 /* If there are none, exit early. */ 3147 if (unseen == 0) 3148 goto commit; 3149 3150 /* Set up for lscf_dependent_import() */ 3151 cbdata.sc_handle = g_hndl; 3152 cbdata.sc_parent = ent; 3153 cbdata.sc_service = issvc; 3154 cbdata.sc_flags = 0; 3155 3156 if (!have_cur_depts) { 3157 /* 3158 * We have new dependents to import, so we need a "dependents" 3159 * property group. 3160 */ 3161 if (issvc) 3162 r = scf_service_add_pg(ent, dependents, 3163 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3164 else 3165 r = scf_instance_add_pg(ent, dependents, 3166 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3167 if (r != 0) { 3168 switch (scf_error()) { 3169 case SCF_ERROR_DELETED: 3170 case SCF_ERROR_CONNECTION_BROKEN: 3171 case SCF_ERROR_BACKEND_READONLY: 3172 case SCF_ERROR_BACKEND_ACCESS: 3173 case SCF_ERROR_NO_RESOURCES: 3174 return (scferror2errno(scf_error())); 3175 3176 case SCF_ERROR_EXISTS: 3177 warn(emsg_pg_added, ient->sc_fmri, dependents); 3178 return (EBUSY); 3179 3180 case SCF_ERROR_PERMISSION_DENIED: 3181 warn(emsg_pg_add_perm, dependents, 3182 ient->sc_fmri); 3183 return (scferror2errno(scf_error())); 3184 3185 case SCF_ERROR_NOT_BOUND: 3186 case SCF_ERROR_HANDLE_MISMATCH: 3187 case SCF_ERROR_INVALID_ARGUMENT: 3188 case SCF_ERROR_NOT_SET: 3189 default: 3190 bad_error("scf_service_add_pg", scf_error()); 3191 } 3192 } 3193 } 3194 3195 cbdata.sc_trans = ud_tx; 3196 3197 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3198 switch (scf_error()) { 3199 case SCF_ERROR_CONNECTION_BROKEN: 3200 case SCF_ERROR_BACKEND_ACCESS: 3201 case SCF_ERROR_BACKEND_READONLY: 3202 return (scferror2errno(scf_error())); 3203 3204 case SCF_ERROR_DELETED: 3205 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3206 return (EBUSY); 3207 3208 case SCF_ERROR_PERMISSION_DENIED: 3209 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3210 return (scferror2errno(scf_error())); 3211 3212 case SCF_ERROR_HANDLE_MISMATCH: 3213 case SCF_ERROR_IN_USE: 3214 case SCF_ERROR_NOT_BOUND: 3215 case SCF_ERROR_NOT_SET: 3216 default: 3217 bad_error("scf_transaction_start", scf_error()); 3218 } 3219 } 3220 tx_started = 1; 3221 3222 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3223 new_dpt_pgroup != NULL; 3224 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3225 new_dpt_pgroup)) { 3226 if (new_dpt_pgroup->sc_pgroup_seen) 3227 continue; 3228 3229 if (ud_run_dpts_pg_set) { 3230 /* 3231 * If the dependent is already there, then we have 3232 * a conflict. 3233 */ 3234 if (scf_pg_get_property(ud_run_dpts_pg, 3235 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3236 r = handle_dependent_conflict(ient, ud_prop, 3237 new_dpt_pgroup); 3238 switch (r) { 3239 case 0: 3240 continue; 3241 3242 case ECONNABORTED: 3243 case ENOMEM: 3244 case EBUSY: 3245 case EBADF: 3246 case EINVAL: 3247 scf_transaction_destroy_children(ud_tx); 3248 return (r); 3249 3250 default: 3251 bad_error("handle_dependent_conflict", 3252 r); 3253 } 3254 } else { 3255 switch (scf_error()) { 3256 case SCF_ERROR_NOT_FOUND: 3257 break; 3258 3259 case SCF_ERROR_INVALID_ARGUMENT: 3260 warn(emsg_fmri_invalid_pg_name, 3261 ient->sc_fmri, 3262 new_dpt_pgroup->sc_pgroup_name); 3263 scf_transaction_destroy_children(ud_tx); 3264 return (EINVAL); 3265 3266 case SCF_ERROR_DELETED: 3267 warn(emsg_pg_deleted, ient->sc_fmri, 3268 new_dpt_pgroup->sc_pgroup_name); 3269 scf_transaction_destroy_children(ud_tx); 3270 return (EBUSY); 3271 3272 case SCF_ERROR_CONNECTION_BROKEN: 3273 scf_transaction_destroy_children(ud_tx); 3274 return (ECONNABORTED); 3275 3276 case SCF_ERROR_NOT_BOUND: 3277 case SCF_ERROR_HANDLE_MISMATCH: 3278 case SCF_ERROR_NOT_SET: 3279 default: 3280 bad_error("scf_pg_get_property", 3281 scf_error()); 3282 } 3283 } 3284 } 3285 3286 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3287 if (r != UU_WALK_NEXT) { 3288 if (r != UU_WALK_ERROR) 3289 bad_error("lscf_dependent_import", r); 3290 3291 if (cbdata.sc_err == EALREADY) { 3292 /* Collisions were handled preemptively. */ 3293 bad_error("lscf_dependent_import", 3294 cbdata.sc_err); 3295 } 3296 3297 scf_transaction_destroy_children(ud_tx); 3298 return (cbdata.sc_err); 3299 } 3300 } 3301 3302 commit: 3303 if (!tx_started) 3304 return (0); 3305 3306 r = scf_transaction_commit(ud_tx); 3307 3308 scf_transaction_destroy_children(ud_tx); 3309 3310 switch (r) { 3311 case 1: 3312 return (0); 3313 3314 case 0: 3315 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3316 return (EBUSY); 3317 3318 case -1: 3319 break; 3320 3321 default: 3322 bad_error("scf_transaction_commit", r); 3323 } 3324 3325 switch (scf_error()) { 3326 case SCF_ERROR_CONNECTION_BROKEN: 3327 case SCF_ERROR_BACKEND_READONLY: 3328 case SCF_ERROR_BACKEND_ACCESS: 3329 case SCF_ERROR_NO_RESOURCES: 3330 return (scferror2errno(scf_error())); 3331 3332 case SCF_ERROR_DELETED: 3333 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3334 return (EBUSY); 3335 3336 case SCF_ERROR_PERMISSION_DENIED: 3337 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3338 return (scferror2errno(scf_error())); 3339 3340 case SCF_ERROR_NOT_BOUND: 3341 case SCF_ERROR_INVALID_ARGUMENT: 3342 case SCF_ERROR_NOT_SET: 3343 default: 3344 bad_error("scf_transaction_destroy", scf_error()); 3345 /* NOTREACHED */ 3346 } 3347 } 3348 3349 /* 3350 * Used to add the manifests to the list of currently supported manifests. 3351 * We can modify the existing manifest list removing entries if the files 3352 * don't exist. 3353 * 3354 * Get the old list and the new file name 3355 * If the new file name is in the list return 3356 * If not then add the file to the list. 3357 * As we process the list check to see if the files in the old list exist 3358 * if not then remove the file from the list. 3359 * Commit the list of manifest file names. 3360 * 3361 */ 3362 static int 3363 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient, 3364 const scf_snaplevel_t *running, void *ent) 3365 { 3366 scf_propertygroup_t *ud_mfsts_pg = NULL; 3367 scf_property_t *ud_prop = NULL; 3368 scf_iter_t *ud_prop_iter; 3369 scf_value_t *fname_value; 3370 scf_callback_t cbdata; 3371 pgroup_t *mfst_pgroup; 3372 property_t *mfst_prop; 3373 property_t *old_prop; 3374 char *pname = malloc(MAXPATHLEN); 3375 char *fval = NULL; 3376 char *old_pname; 3377 char *old_fval; 3378 int no_upgrade_pg; 3379 int mfst_seen; 3380 int r; 3381 3382 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3383 3384 /* 3385 * This should always be the service base on the code 3386 * path, and the fact that the manifests pg is a service 3387 * level property group only. 3388 */ 3389 ud_mfsts_pg = scf_pg_create(g_hndl); 3390 ud_prop = scf_property_create(g_hndl); 3391 ud_prop_iter = scf_iter_create(g_hndl); 3392 fname_value = scf_value_create(g_hndl); 3393 3394 /* Fetch the "manifests" property group */ 3395 no_upgrade_pg = 0; 3396 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3397 ud_mfsts_pg); 3398 if (r != 0) { 3399 switch (scf_error()) { 3400 case SCF_ERROR_NOT_FOUND: 3401 no_upgrade_pg = 1; 3402 break; 3403 3404 case SCF_ERROR_DELETED: 3405 case SCF_ERROR_CONNECTION_BROKEN: 3406 return (scferror2errno(scf_error())); 3407 3408 case SCF_ERROR_NOT_SET: 3409 case SCF_ERROR_INVALID_ARGUMENT: 3410 case SCF_ERROR_HANDLE_MISMATCH: 3411 case SCF_ERROR_NOT_BOUND: 3412 default: 3413 bad_error(running ? "scf_snaplevel_get_pg" : 3414 "entity_get_pg", scf_error()); 3415 } 3416 } 3417 3418 if (no_upgrade_pg) { 3419 cbdata.sc_handle = g_hndl; 3420 cbdata.sc_parent = ent; 3421 cbdata.sc_service = issvc; 3422 cbdata.sc_flags = SCI_FORCE; 3423 cbdata.sc_source_fmri = ient->sc_fmri; 3424 cbdata.sc_target_fmri = ient->sc_fmri; 3425 3426 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3427 return (cbdata.sc_err); 3428 3429 return (0); 3430 } 3431 3432 /* Fetch the new manifests property group */ 3433 for (mfst_pgroup = uu_list_first(ient->sc_pgroups); 3434 mfst_pgroup != NULL; 3435 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) { 3436 if (strcmp(mfst_pgroup->sc_pgroup_name, 3437 SCF_PG_MANIFESTFILES) == 0) 3438 break; 3439 } 3440 3441 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3442 SCF_SUCCESS) 3443 return (-1); 3444 3445 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 3446 mfst_seen = 0; 3447 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 3448 continue; 3449 3450 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3451 mfst_prop != NULL; 3452 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3453 mfst_prop)) { 3454 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3455 mfst_seen = 1; 3456 } 3457 } 3458 3459 /* 3460 * If the manifest is not seen then add it to the new mfst 3461 * property list to get proccessed into the repo. 3462 */ 3463 if (mfst_seen == 0) { 3464 if (fval == NULL) 3465 fval = malloc(MAXPATHLEN); 3466 3467 /* 3468 * If we cannot get the value then there is no 3469 * reason to attempt to attach the value to 3470 * the property group 3471 */ 3472 if (fval != NULL && 3473 prop_get_val(ud_prop, fname_value) == 0 && 3474 scf_value_get_astring(fname_value, fval, 3475 MAXPATHLEN) != -1) { 3476 /* 3477 * If the filesystem/minimal service is 3478 * online check to see if the manifest is 3479 * there. If not then there is no need to 3480 * add it. 3481 * 3482 * If filesystem/minimal service is not 3483 * online, we go ahead and record the 3484 * manifest file name. We don't check for 3485 * its existence because it may be on a 3486 * file system that is not yet mounted. 3487 */ 3488 if ((est->sc_fs_minimal) && 3489 (access(fval, F_OK) == -1)) { 3490 continue; 3491 } 3492 3493 old_pname = safe_strdup(pname); 3494 old_fval = safe_strdup(fval); 3495 old_prop = internal_property_create(old_pname, 3496 SCF_TYPE_ASTRING, 1, old_fval); 3497 3498 /* 3499 * Already checked to see if the property exists 3500 * in the group, and it does not. 3501 */ 3502 (void) internal_attach_property(mfst_pgroup, 3503 old_prop); 3504 } 3505 } 3506 } 3507 free(fval); 3508 3509 cbdata.sc_handle = g_hndl; 3510 cbdata.sc_parent = ent; 3511 cbdata.sc_service = issvc; 3512 cbdata.sc_flags = SCI_FORCE; 3513 cbdata.sc_source_fmri = ient->sc_fmri; 3514 cbdata.sc_target_fmri = ient->sc_fmri; 3515 3516 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 3517 return (cbdata.sc_err); 3518 3519 return (r); 3520 } 3521 3522 /* 3523 * prop is taken to be a property in the "dependents" property group of snpl, 3524 * which is taken to be the snaplevel of a last-import snapshot corresponding 3525 * to ient. If prop is a valid dependents property, upgrade the dependent it 3526 * represents according to the repository & ient. If ud_run_dpts_pg_set is 3527 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 3528 * of the entity ient represents (possibly in the running snapshot). If it 3529 * needs to be changed, an entry will be added to tx, if not NULL. 3530 * 3531 * Returns 3532 * 0 - success 3533 * ECONNABORTED - repository connection broken 3534 * ENOMEM - out of memory 3535 * ENOSPC - configd was out of resources 3536 * ECANCELED - snpl's entity was deleted 3537 * EINVAL - dependent target is invalid (error printed) 3538 * - dependent is invalid (error printed) 3539 * EBADF - snpl is corrupt (error printed) 3540 * - snpl has corrupt pg (error printed) 3541 * - dependency pg in target is corrupt (error printed) 3542 * - running snapshot in dependent is missing snaplevel (error printed) 3543 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 3544 * - couldn't create dependent (permission denied) (error printed) 3545 * - couldn't modify dependent pg (permission denied) (error printed) 3546 * EROFS - couldn't delete dependency pg (repository read-only) 3547 * - couldn't create dependent (repository read-only) 3548 * EACCES - couldn't delete dependency pg (backend access denied) 3549 * - couldn't create dependent (backend access denied) 3550 * EBUSY - ud_run_dpts_pg was deleted (error printed) 3551 * - tx's pg was deleted (error printed) 3552 * - dependent pg was changed or deleted (error printed) 3553 * EEXIST - dependency pg already exists in new target (error printed) 3554 */ 3555 static int 3556 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 3557 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 3558 { 3559 pgroup_t pgrp; 3560 scf_type_t ty; 3561 pgroup_t *new_dpt_pgroup; 3562 pgroup_t *old_dpt_pgroup = NULL; 3563 pgroup_t *current_pg; 3564 scf_callback_t cbdata; 3565 int tissvc; 3566 void *target_ent; 3567 scf_error_t serr; 3568 int r; 3569 scf_transaction_entry_t *ent; 3570 3571 const char * const cf_inval = gettext("Conflict upgrading %s " 3572 "(dependent \"%s\" has invalid dependents property).\n"); 3573 const char * const cf_missing = gettext("Conflict upgrading %s " 3574 "(dependent \"%s\" is missing).\n"); 3575 const char * const cf_newdpg = gettext("Conflict upgrading %s " 3576 "(dependent \"%s\" has new dependency property group).\n"); 3577 const char * const cf_newtarg = gettext("Conflict upgrading %s " 3578 "(dependent \"%s\" has new target).\n"); 3579 const char * const li_corrupt = 3580 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 3581 const char * const upgrading = 3582 gettext("%s: Upgrading dependent \"%s\".\n"); 3583 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 3584 "corrupt (missing snaplevel).\n"); 3585 3586 if (scf_property_type(prop, &ty) != 0) { 3587 switch (scf_error()) { 3588 case SCF_ERROR_DELETED: 3589 case SCF_ERROR_CONNECTION_BROKEN: 3590 return (scferror2errno(scf_error())); 3591 3592 case SCF_ERROR_NOT_BOUND: 3593 case SCF_ERROR_NOT_SET: 3594 default: 3595 bad_error("scf_property_type", scf_error()); 3596 } 3597 } 3598 3599 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3600 warn(li_corrupt, ient->sc_fmri); 3601 return (EBADF); 3602 } 3603 3604 /* 3605 * prop represents a dependent in the old manifest. It is named after 3606 * the dependent. 3607 */ 3608 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 3609 switch (scf_error()) { 3610 case SCF_ERROR_DELETED: 3611 case SCF_ERROR_CONNECTION_BROKEN: 3612 return (scferror2errno(scf_error())); 3613 3614 case SCF_ERROR_NOT_BOUND: 3615 case SCF_ERROR_NOT_SET: 3616 default: 3617 bad_error("scf_property_get_name", scf_error()); 3618 } 3619 } 3620 3621 /* See if it's in the new manifest. */ 3622 pgrp.sc_pgroup_name = ud_name; 3623 new_dpt_pgroup = 3624 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 3625 3626 /* If it's not, delete it... if it hasn't been customized. */ 3627 if (new_dpt_pgroup == NULL) { 3628 pgroup_t *dpt; 3629 3630 if (!ud_run_dpts_pg_set) 3631 return (0); 3632 3633 if (scf_property_get_value(prop, ud_val) != 0) { 3634 switch (scf_error()) { 3635 case SCF_ERROR_NOT_FOUND: 3636 case SCF_ERROR_CONSTRAINT_VIOLATED: 3637 warn(li_corrupt, ient->sc_fmri); 3638 return (EBADF); 3639 3640 case SCF_ERROR_DELETED: 3641 case SCF_ERROR_CONNECTION_BROKEN: 3642 return (scferror2errno(scf_error())); 3643 3644 case SCF_ERROR_HANDLE_MISMATCH: 3645 case SCF_ERROR_NOT_BOUND: 3646 case SCF_ERROR_NOT_SET: 3647 case SCF_ERROR_PERMISSION_DENIED: 3648 default: 3649 bad_error("scf_property_get_value", 3650 scf_error()); 3651 } 3652 } 3653 3654 if (scf_value_get_as_string(ud_val, ud_oldtarg, 3655 max_scf_value_len + 1) < 0) 3656 bad_error("scf_value_get_as_string", scf_error()); 3657 3658 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 3659 0) { 3660 switch (scf_error()) { 3661 case SCF_ERROR_NOT_FOUND: 3662 return (0); 3663 3664 case SCF_ERROR_CONNECTION_BROKEN: 3665 return (scferror2errno(scf_error())); 3666 3667 case SCF_ERROR_DELETED: 3668 warn(emsg_pg_deleted, ient->sc_fmri, 3669 "dependents"); 3670 return (EBUSY); 3671 3672 case SCF_ERROR_INVALID_ARGUMENT: 3673 case SCF_ERROR_NOT_BOUND: 3674 case SCF_ERROR_HANDLE_MISMATCH: 3675 case SCF_ERROR_NOT_SET: 3676 default: 3677 bad_error("scf_pg_get_property", scf_error()); 3678 } 3679 } 3680 if (scf_property_get_value(ud_prop, ud_val) != 0) { 3681 switch (scf_error()) { 3682 case SCF_ERROR_NOT_FOUND: 3683 case SCF_ERROR_CONSTRAINT_VIOLATED: 3684 warn(cf_inval, ient->sc_fmri, ud_name); 3685 return (0); 3686 3687 case SCF_ERROR_DELETED: 3688 case SCF_ERROR_CONNECTION_BROKEN: 3689 return (scferror2errno(scf_error())); 3690 3691 case SCF_ERROR_HANDLE_MISMATCH: 3692 case SCF_ERROR_NOT_BOUND: 3693 case SCF_ERROR_NOT_SET: 3694 case SCF_ERROR_PERMISSION_DENIED: 3695 default: 3696 bad_error("scf_property_get_value", 3697 scf_error()); 3698 } 3699 } 3700 3701 ty = scf_value_type(ud_val); 3702 assert(ty != SCF_TYPE_INVALID); 3703 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3704 warn(cf_inval, ient->sc_fmri, ud_name); 3705 return (0); 3706 } 3707 3708 if (scf_value_get_as_string(ud_val, ud_ctarg, 3709 max_scf_value_len + 1) < 0) 3710 bad_error("scf_value_get_as_string", scf_error()); 3711 3712 r = fmri_equal(ud_ctarg, ud_oldtarg); 3713 switch (r) { 3714 case 1: 3715 break; 3716 3717 case 0: 3718 case -1: /* warn? */ 3719 warn(cf_newtarg, ient->sc_fmri, ud_name); 3720 return (0); 3721 3722 case -2: 3723 warn(li_corrupt, ient->sc_fmri); 3724 return (EBADF); 3725 3726 default: 3727 bad_error("fmri_equal", r); 3728 } 3729 3730 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3731 switch (scf_error()) { 3732 case SCF_ERROR_NOT_FOUND: 3733 warn(li_corrupt, ient->sc_fmri); 3734 return (EBADF); 3735 3736 case SCF_ERROR_DELETED: 3737 case SCF_ERROR_CONNECTION_BROKEN: 3738 return (scferror2errno(scf_error())); 3739 3740 case SCF_ERROR_NOT_BOUND: 3741 case SCF_ERROR_HANDLE_MISMATCH: 3742 case SCF_ERROR_INVALID_ARGUMENT: 3743 case SCF_ERROR_NOT_SET: 3744 default: 3745 bad_error("scf_snaplevel_get_pg", scf_error()); 3746 } 3747 } 3748 3749 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3750 snap_lastimport); 3751 switch (r) { 3752 case 0: 3753 break; 3754 3755 case ECANCELED: 3756 case ECONNABORTED: 3757 case ENOMEM: 3758 case EBADF: 3759 return (r); 3760 3761 case EACCES: 3762 default: 3763 bad_error("load_pg", r); 3764 } 3765 3766 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 3767 switch (serr) { 3768 case SCF_ERROR_NONE: 3769 break; 3770 3771 case SCF_ERROR_NO_MEMORY: 3772 internal_pgroup_free(old_dpt_pgroup); 3773 return (ENOMEM); 3774 3775 case SCF_ERROR_NOT_FOUND: 3776 internal_pgroup_free(old_dpt_pgroup); 3777 goto delprop; 3778 3779 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 3780 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 3781 default: 3782 bad_error("fmri_to_entity", serr); 3783 } 3784 3785 r = entity_get_running_pg(target_ent, tissvc, ud_name, 3786 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 3787 switch (r) { 3788 case 0: 3789 break; 3790 3791 case ECONNABORTED: 3792 internal_pgroup_free(old_dpt_pgroup); 3793 return (r); 3794 3795 case ECANCELED: 3796 case ENOENT: 3797 internal_pgroup_free(old_dpt_pgroup); 3798 goto delprop; 3799 3800 case EBADF: 3801 warn(r_no_lvl, ud_ctarg); 3802 internal_pgroup_free(old_dpt_pgroup); 3803 return (r); 3804 3805 case EINVAL: 3806 default: 3807 bad_error("entity_get_running_pg", r); 3808 } 3809 3810 /* load it */ 3811 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 3812 switch (r) { 3813 case 0: 3814 break; 3815 3816 case ECANCELED: 3817 internal_pgroup_free(old_dpt_pgroup); 3818 goto delprop; 3819 3820 case ECONNABORTED: 3821 case ENOMEM: 3822 case EBADF: 3823 internal_pgroup_free(old_dpt_pgroup); 3824 return (r); 3825 3826 case EACCES: 3827 default: 3828 bad_error("load_pg", r); 3829 } 3830 3831 /* compare property groups */ 3832 if (!pg_equal(old_dpt_pgroup, current_pg)) { 3833 warn(cf_newdpg, ient->sc_fmri, ud_name); 3834 internal_pgroup_free(old_dpt_pgroup); 3835 internal_pgroup_free(current_pg); 3836 return (0); 3837 } 3838 3839 internal_pgroup_free(old_dpt_pgroup); 3840 internal_pgroup_free(current_pg); 3841 3842 if (g_verbose) 3843 warn(gettext("%s: Deleting dependent \"%s\".\n"), 3844 ient->sc_fmri, ud_name); 3845 3846 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 3847 switch (scf_error()) { 3848 case SCF_ERROR_NOT_FOUND: 3849 case SCF_ERROR_DELETED: 3850 internal_pgroup_free(old_dpt_pgroup); 3851 goto delprop; 3852 3853 case SCF_ERROR_CONNECTION_BROKEN: 3854 internal_pgroup_free(old_dpt_pgroup); 3855 return (ECONNABORTED); 3856 3857 case SCF_ERROR_NOT_SET: 3858 case SCF_ERROR_INVALID_ARGUMENT: 3859 case SCF_ERROR_HANDLE_MISMATCH: 3860 case SCF_ERROR_NOT_BOUND: 3861 default: 3862 bad_error("entity_get_pg", scf_error()); 3863 } 3864 } 3865 3866 if (scf_pg_delete(ud_pg) != 0) { 3867 switch (scf_error()) { 3868 case SCF_ERROR_DELETED: 3869 break; 3870 3871 case SCF_ERROR_CONNECTION_BROKEN: 3872 case SCF_ERROR_BACKEND_READONLY: 3873 case SCF_ERROR_BACKEND_ACCESS: 3874 return (scferror2errno(scf_error())); 3875 3876 case SCF_ERROR_PERMISSION_DENIED: 3877 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 3878 return (scferror2errno(scf_error())); 3879 3880 case SCF_ERROR_NOT_SET: 3881 default: 3882 bad_error("scf_pg_delete", scf_error()); 3883 } 3884 } 3885 3886 /* 3887 * This service was changed, so it must be refreshed. But 3888 * since it's not mentioned in the new manifest, we have to 3889 * record its FMRI here for use later. We record the name 3890 * & the entity (via sc_parent) in case we need to print error 3891 * messages during the refresh. 3892 */ 3893 dpt = internal_pgroup_new(); 3894 if (dpt == NULL) 3895 return (ENOMEM); 3896 dpt->sc_pgroup_name = strdup(ud_name); 3897 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 3898 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 3899 return (ENOMEM); 3900 dpt->sc_parent = (entity_t *)ient; 3901 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 3902 uu_die(gettext("libuutil error: %s\n"), 3903 uu_strerror(uu_error())); 3904 3905 delprop: 3906 if (tx == NULL) 3907 return (0); 3908 3909 ent = scf_entry_create(g_hndl); 3910 if (ent == NULL) 3911 return (ENOMEM); 3912 3913 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 3914 scf_entry_destroy(ent); 3915 switch (scf_error()) { 3916 case SCF_ERROR_DELETED: 3917 warn(emsg_pg_deleted, ient->sc_fmri, 3918 "dependents"); 3919 return (EBUSY); 3920 3921 case SCF_ERROR_CONNECTION_BROKEN: 3922 return (scferror2errno(scf_error())); 3923 3924 case SCF_ERROR_NOT_FOUND: 3925 break; 3926 3927 case SCF_ERROR_HANDLE_MISMATCH: 3928 case SCF_ERROR_NOT_BOUND: 3929 case SCF_ERROR_INVALID_ARGUMENT: 3930 case SCF_ERROR_NOT_SET: 3931 default: 3932 bad_error("scf_transaction_property_delete", 3933 scf_error()); 3934 } 3935 } 3936 3937 return (0); 3938 } 3939 3940 new_dpt_pgroup->sc_pgroup_seen = 1; 3941 3942 /* 3943 * Decide whether the dependent has changed in the manifest. 3944 */ 3945 /* Compare the target. */ 3946 if (scf_property_get_value(prop, ud_val) != 0) { 3947 switch (scf_error()) { 3948 case SCF_ERROR_NOT_FOUND: 3949 case SCF_ERROR_CONSTRAINT_VIOLATED: 3950 warn(li_corrupt, ient->sc_fmri); 3951 return (EBADF); 3952 3953 case SCF_ERROR_DELETED: 3954 case SCF_ERROR_CONNECTION_BROKEN: 3955 return (scferror2errno(scf_error())); 3956 3957 case SCF_ERROR_HANDLE_MISMATCH: 3958 case SCF_ERROR_NOT_BOUND: 3959 case SCF_ERROR_NOT_SET: 3960 case SCF_ERROR_PERMISSION_DENIED: 3961 default: 3962 bad_error("scf_property_get_value", scf_error()); 3963 } 3964 } 3965 3966 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 3967 0) 3968 bad_error("scf_value_get_as_string", scf_error()); 3969 3970 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 3971 switch (r) { 3972 case 0: 3973 break; 3974 3975 case 1: 3976 /* Compare the dependency pgs. */ 3977 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3978 switch (scf_error()) { 3979 case SCF_ERROR_NOT_FOUND: 3980 warn(li_corrupt, ient->sc_fmri); 3981 return (EBADF); 3982 3983 case SCF_ERROR_DELETED: 3984 case SCF_ERROR_CONNECTION_BROKEN: 3985 return (scferror2errno(scf_error())); 3986 3987 case SCF_ERROR_NOT_BOUND: 3988 case SCF_ERROR_HANDLE_MISMATCH: 3989 case SCF_ERROR_INVALID_ARGUMENT: 3990 case SCF_ERROR_NOT_SET: 3991 default: 3992 bad_error("scf_snaplevel_get_pg", scf_error()); 3993 } 3994 } 3995 3996 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3997 snap_lastimport); 3998 switch (r) { 3999 case 0: 4000 break; 4001 4002 case ECANCELED: 4003 case ECONNABORTED: 4004 case ENOMEM: 4005 case EBADF: 4006 return (r); 4007 4008 case EACCES: 4009 default: 4010 bad_error("load_pg", r); 4011 } 4012 4013 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4014 /* no change, leave customizations */ 4015 internal_pgroup_free(old_dpt_pgroup); 4016 return (0); 4017 } 4018 break; 4019 4020 case -1: 4021 warn(li_corrupt, ient->sc_fmri); 4022 return (EBADF); 4023 4024 case -2: 4025 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4026 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4027 return (EINVAL); 4028 4029 default: 4030 bad_error("fmri_equal", r); 4031 } 4032 4033 /* 4034 * The dependent has changed in the manifest. Upgrade the current 4035 * properties if they haven't been customized. 4036 */ 4037 4038 /* 4039 * If new_dpt_pgroup->sc_override, then act as though the property 4040 * group hasn't been customized. 4041 */ 4042 if (new_dpt_pgroup->sc_pgroup_override) 4043 goto nocust; 4044 4045 if (!ud_run_dpts_pg_set) { 4046 warn(cf_missing, ient->sc_fmri, ud_name); 4047 r = 0; 4048 goto out; 4049 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4050 switch (scf_error()) { 4051 case SCF_ERROR_NOT_FOUND: 4052 warn(cf_missing, ient->sc_fmri, ud_name); 4053 r = 0; 4054 goto out; 4055 4056 case SCF_ERROR_CONNECTION_BROKEN: 4057 r = scferror2errno(scf_error()); 4058 goto out; 4059 4060 case SCF_ERROR_DELETED: 4061 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4062 r = EBUSY; 4063 goto out; 4064 4065 case SCF_ERROR_INVALID_ARGUMENT: 4066 case SCF_ERROR_NOT_BOUND: 4067 case SCF_ERROR_HANDLE_MISMATCH: 4068 case SCF_ERROR_NOT_SET: 4069 default: 4070 bad_error("scf_pg_get_property", scf_error()); 4071 } 4072 } 4073 4074 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4075 switch (scf_error()) { 4076 case SCF_ERROR_NOT_FOUND: 4077 case SCF_ERROR_CONSTRAINT_VIOLATED: 4078 warn(cf_inval, ient->sc_fmri, ud_name); 4079 r = 0; 4080 goto out; 4081 4082 case SCF_ERROR_DELETED: 4083 case SCF_ERROR_CONNECTION_BROKEN: 4084 r = scferror2errno(scf_error()); 4085 goto out; 4086 4087 case SCF_ERROR_HANDLE_MISMATCH: 4088 case SCF_ERROR_NOT_BOUND: 4089 case SCF_ERROR_NOT_SET: 4090 case SCF_ERROR_PERMISSION_DENIED: 4091 default: 4092 bad_error("scf_property_get_value", scf_error()); 4093 } 4094 } 4095 4096 ty = scf_value_type(ud_val); 4097 assert(ty != SCF_TYPE_INVALID); 4098 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4099 warn(cf_inval, ient->sc_fmri, ud_name); 4100 r = 0; 4101 goto out; 4102 } 4103 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4104 0) 4105 bad_error("scf_value_get_as_string", scf_error()); 4106 4107 r = fmri_equal(ud_ctarg, ud_oldtarg); 4108 if (r == -1) { 4109 warn(cf_inval, ient->sc_fmri, ud_name); 4110 r = 0; 4111 goto out; 4112 } else if (r == -2) { 4113 warn(li_corrupt, ient->sc_fmri); 4114 r = EBADF; 4115 goto out; 4116 } else if (r == 0) { 4117 /* 4118 * Target has been changed. Only abort now if it's been 4119 * changed to something other than what's in the manifest. 4120 */ 4121 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4122 if (r == -1) { 4123 warn(cf_inval, ient->sc_fmri, ud_name); 4124 r = 0; 4125 goto out; 4126 } else if (r == 0) { 4127 warn(cf_newtarg, ient->sc_fmri, ud_name); 4128 r = 0; 4129 goto out; 4130 } else if (r != 1) { 4131 /* invalid sc_pgroup_fmri caught above */ 4132 bad_error("fmri_equal", r); 4133 } 4134 4135 /* 4136 * Fetch the current dependency pg. If it's what the manifest 4137 * says, then no problem. 4138 */ 4139 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4140 switch (serr) { 4141 case SCF_ERROR_NONE: 4142 break; 4143 4144 case SCF_ERROR_NOT_FOUND: 4145 warn(cf_missing, ient->sc_fmri, ud_name); 4146 r = 0; 4147 goto out; 4148 4149 case SCF_ERROR_NO_MEMORY: 4150 r = ENOMEM; 4151 goto out; 4152 4153 case SCF_ERROR_CONSTRAINT_VIOLATED: 4154 case SCF_ERROR_INVALID_ARGUMENT: 4155 default: 4156 bad_error("fmri_to_entity", serr); 4157 } 4158 4159 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4160 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4161 switch (r) { 4162 case 0: 4163 break; 4164 4165 case ECONNABORTED: 4166 goto out; 4167 4168 case ECANCELED: 4169 case ENOENT: 4170 warn(cf_missing, ient->sc_fmri, ud_name); 4171 r = 0; 4172 goto out; 4173 4174 case EBADF: 4175 warn(r_no_lvl, ud_ctarg); 4176 goto out; 4177 4178 case EINVAL: 4179 default: 4180 bad_error("entity_get_running_pg", r); 4181 } 4182 4183 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4184 switch (r) { 4185 case 0: 4186 break; 4187 4188 case ECANCELED: 4189 warn(cf_missing, ient->sc_fmri, ud_name); 4190 r = 0; 4191 goto out; 4192 4193 case ECONNABORTED: 4194 case ENOMEM: 4195 case EBADF: 4196 goto out; 4197 4198 case EACCES: 4199 default: 4200 bad_error("load_pg", r); 4201 } 4202 4203 if (!pg_equal(current_pg, new_dpt_pgroup)) 4204 warn(cf_newdpg, ient->sc_fmri, ud_name); 4205 internal_pgroup_free(current_pg); 4206 r = 0; 4207 goto out; 4208 } else if (r != 1) { 4209 bad_error("fmri_equal", r); 4210 } 4211 4212 nocust: 4213 /* 4214 * Target has not been customized. Check the dependency property 4215 * group. 4216 */ 4217 4218 if (old_dpt_pgroup == NULL) { 4219 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4220 ud_pg) != 0) { 4221 switch (scf_error()) { 4222 case SCF_ERROR_NOT_FOUND: 4223 warn(li_corrupt, ient->sc_fmri); 4224 return (EBADF); 4225 4226 case SCF_ERROR_DELETED: 4227 case SCF_ERROR_CONNECTION_BROKEN: 4228 return (scferror2errno(scf_error())); 4229 4230 case SCF_ERROR_NOT_BOUND: 4231 case SCF_ERROR_HANDLE_MISMATCH: 4232 case SCF_ERROR_INVALID_ARGUMENT: 4233 case SCF_ERROR_NOT_SET: 4234 default: 4235 bad_error("scf_snaplevel_get_pg", scf_error()); 4236 } 4237 } 4238 4239 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4240 snap_lastimport); 4241 switch (r) { 4242 case 0: 4243 break; 4244 4245 case ECANCELED: 4246 case ECONNABORTED: 4247 case ENOMEM: 4248 case EBADF: 4249 return (r); 4250 4251 case EACCES: 4252 default: 4253 bad_error("load_pg", r); 4254 } 4255 } 4256 4257 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4258 switch (serr) { 4259 case SCF_ERROR_NONE: 4260 break; 4261 4262 case SCF_ERROR_NOT_FOUND: 4263 warn(cf_missing, ient->sc_fmri, ud_name); 4264 r = 0; 4265 goto out; 4266 4267 case SCF_ERROR_NO_MEMORY: 4268 r = ENOMEM; 4269 goto out; 4270 4271 case SCF_ERROR_CONSTRAINT_VIOLATED: 4272 case SCF_ERROR_INVALID_ARGUMENT: 4273 default: 4274 bad_error("fmri_to_entity", serr); 4275 } 4276 4277 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4278 ud_iter2, ud_inst, imp_snap, ud_snpl); 4279 switch (r) { 4280 case 0: 4281 break; 4282 4283 case ECONNABORTED: 4284 goto out; 4285 4286 case ECANCELED: 4287 case ENOENT: 4288 warn(cf_missing, ient->sc_fmri, ud_name); 4289 r = 0; 4290 goto out; 4291 4292 case EBADF: 4293 warn(r_no_lvl, ud_ctarg); 4294 goto out; 4295 4296 case EINVAL: 4297 default: 4298 bad_error("entity_get_running_pg", r); 4299 } 4300 4301 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4302 switch (r) { 4303 case 0: 4304 break; 4305 4306 case ECANCELED: 4307 warn(cf_missing, ient->sc_fmri, ud_name); 4308 goto out; 4309 4310 case ECONNABORTED: 4311 case ENOMEM: 4312 case EBADF: 4313 goto out; 4314 4315 case EACCES: 4316 default: 4317 bad_error("load_pg", r); 4318 } 4319 4320 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4321 if (!pg_equal(current_pg, new_dpt_pgroup)) 4322 warn(cf_newdpg, ient->sc_fmri, ud_name); 4323 internal_pgroup_free(current_pg); 4324 r = 0; 4325 goto out; 4326 } 4327 4328 /* Uncustomized. Upgrade. */ 4329 4330 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4331 switch (r) { 4332 case 1: 4333 if (pg_equal(current_pg, new_dpt_pgroup)) { 4334 /* Already upgraded. */ 4335 internal_pgroup_free(current_pg); 4336 r = 0; 4337 goto out; 4338 } 4339 4340 internal_pgroup_free(current_pg); 4341 4342 /* upgrade current_pg */ 4343 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4344 switch (scf_error()) { 4345 case SCF_ERROR_CONNECTION_BROKEN: 4346 r = scferror2errno(scf_error()); 4347 goto out; 4348 4349 case SCF_ERROR_DELETED: 4350 warn(cf_missing, ient->sc_fmri, ud_name); 4351 r = 0; 4352 goto out; 4353 4354 case SCF_ERROR_NOT_FOUND: 4355 break; 4356 4357 case SCF_ERROR_INVALID_ARGUMENT: 4358 case SCF_ERROR_NOT_BOUND: 4359 case SCF_ERROR_NOT_SET: 4360 case SCF_ERROR_HANDLE_MISMATCH: 4361 default: 4362 bad_error("entity_get_pg", scf_error()); 4363 } 4364 4365 if (tissvc) 4366 r = scf_service_add_pg(target_ent, ud_name, 4367 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4368 else 4369 r = scf_instance_add_pg(target_ent, ud_name, 4370 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4371 if (r != 0) { 4372 switch (scf_error()) { 4373 case SCF_ERROR_CONNECTION_BROKEN: 4374 case SCF_ERROR_NO_RESOURCES: 4375 case SCF_ERROR_BACKEND_READONLY: 4376 case SCF_ERROR_BACKEND_ACCESS: 4377 r = scferror2errno(scf_error()); 4378 goto out; 4379 4380 case SCF_ERROR_DELETED: 4381 warn(cf_missing, ient->sc_fmri, 4382 ud_name); 4383 r = 0; 4384 goto out; 4385 4386 case SCF_ERROR_PERMISSION_DENIED: 4387 warn(emsg_pg_deleted, ud_ctarg, 4388 ud_name); 4389 r = EPERM; 4390 goto out; 4391 4392 case SCF_ERROR_EXISTS: 4393 warn(emsg_pg_added, ud_ctarg, ud_name); 4394 r = EBUSY; 4395 goto out; 4396 4397 case SCF_ERROR_NOT_BOUND: 4398 case SCF_ERROR_HANDLE_MISMATCH: 4399 case SCF_ERROR_INVALID_ARGUMENT: 4400 case SCF_ERROR_NOT_SET: 4401 default: 4402 bad_error("entity_add_pg", scf_error()); 4403 } 4404 } 4405 } 4406 4407 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4408 switch (r) { 4409 case 0: 4410 break; 4411 4412 case ECANCELED: 4413 warn(cf_missing, ient->sc_fmri, ud_name); 4414 goto out; 4415 4416 case ECONNABORTED: 4417 case ENOMEM: 4418 case EBADF: 4419 goto out; 4420 4421 case EACCES: 4422 default: 4423 bad_error("load_pg", r); 4424 } 4425 4426 if (g_verbose) 4427 warn(upgrading, ient->sc_fmri, ud_name); 4428 4429 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4430 new_dpt_pgroup, 0, ient->sc_fmri); 4431 switch (r) { 4432 case 0: 4433 break; 4434 4435 case ECANCELED: 4436 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4437 r = EBUSY; 4438 goto out; 4439 4440 case EPERM: 4441 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4442 goto out; 4443 4444 case EBUSY: 4445 warn(emsg_pg_changed, ud_ctarg, ud_name); 4446 goto out; 4447 4448 case ECONNABORTED: 4449 case ENOMEM: 4450 case ENOSPC: 4451 case EROFS: 4452 case EACCES: 4453 case EINVAL: 4454 goto out; 4455 4456 default: 4457 bad_error("upgrade_pg", r); 4458 } 4459 break; 4460 4461 case 0: { 4462 scf_transaction_entry_t *ent; 4463 scf_value_t *val; 4464 4465 internal_pgroup_free(current_pg); 4466 4467 /* delete old pg */ 4468 if (g_verbose) 4469 warn(upgrading, ient->sc_fmri, ud_name); 4470 4471 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4472 switch (scf_error()) { 4473 case SCF_ERROR_CONNECTION_BROKEN: 4474 r = scferror2errno(scf_error()); 4475 goto out; 4476 4477 case SCF_ERROR_DELETED: 4478 warn(cf_missing, ient->sc_fmri, ud_name); 4479 r = 0; 4480 goto out; 4481 4482 case SCF_ERROR_NOT_FOUND: 4483 break; 4484 4485 case SCF_ERROR_INVALID_ARGUMENT: 4486 case SCF_ERROR_NOT_BOUND: 4487 case SCF_ERROR_NOT_SET: 4488 case SCF_ERROR_HANDLE_MISMATCH: 4489 default: 4490 bad_error("entity_get_pg", scf_error()); 4491 } 4492 } else if (scf_pg_delete(ud_pg) != 0) { 4493 switch (scf_error()) { 4494 case SCF_ERROR_DELETED: 4495 break; 4496 4497 case SCF_ERROR_CONNECTION_BROKEN: 4498 case SCF_ERROR_BACKEND_READONLY: 4499 case SCF_ERROR_BACKEND_ACCESS: 4500 r = scferror2errno(scf_error()); 4501 goto out; 4502 4503 case SCF_ERROR_PERMISSION_DENIED: 4504 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4505 r = scferror2errno(scf_error()); 4506 goto out; 4507 4508 case SCF_ERROR_NOT_SET: 4509 default: 4510 bad_error("scf_pg_delete", scf_error()); 4511 } 4512 } 4513 4514 /* import new one */ 4515 cbdata.sc_handle = g_hndl; 4516 cbdata.sc_trans = NULL; /* handled below */ 4517 4518 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 4519 if (r != UU_WALK_NEXT) { 4520 if (r != UU_WALK_ERROR) 4521 bad_error("lscf_dependent_import", r); 4522 4523 r = cbdata.sc_err; 4524 goto out; 4525 } 4526 4527 if (tx == NULL) 4528 break; 4529 4530 if ((ent = scf_entry_create(g_hndl)) == NULL || 4531 (val = scf_value_create(g_hndl)) == NULL) { 4532 if (scf_error() == SCF_ERROR_NO_MEMORY) 4533 return (ENOMEM); 4534 4535 bad_error("scf_entry_create", scf_error()); 4536 } 4537 4538 if (scf_transaction_property_change_type(tx, ent, ud_name, 4539 SCF_TYPE_FMRI) != 0) { 4540 switch (scf_error()) { 4541 case SCF_ERROR_CONNECTION_BROKEN: 4542 r = scferror2errno(scf_error()); 4543 goto out; 4544 4545 case SCF_ERROR_DELETED: 4546 warn(emsg_pg_deleted, ient->sc_fmri, 4547 "dependents"); 4548 r = EBUSY; 4549 goto out; 4550 4551 case SCF_ERROR_NOT_FOUND: 4552 break; 4553 4554 case SCF_ERROR_NOT_BOUND: 4555 case SCF_ERROR_HANDLE_MISMATCH: 4556 case SCF_ERROR_INVALID_ARGUMENT: 4557 case SCF_ERROR_NOT_SET: 4558 default: 4559 bad_error("scf_transaction_property_" 4560 "change_type", scf_error()); 4561 } 4562 4563 if (scf_transaction_property_new(tx, ent, ud_name, 4564 SCF_TYPE_FMRI) != 0) { 4565 switch (scf_error()) { 4566 case SCF_ERROR_CONNECTION_BROKEN: 4567 r = scferror2errno(scf_error()); 4568 goto out; 4569 4570 case SCF_ERROR_DELETED: 4571 warn(emsg_pg_deleted, ient->sc_fmri, 4572 "dependents"); 4573 r = EBUSY; 4574 goto out; 4575 4576 case SCF_ERROR_EXISTS: 4577 warn(emsg_pg_changed, ient->sc_fmri, 4578 "dependents"); 4579 r = EBUSY; 4580 goto out; 4581 4582 case SCF_ERROR_INVALID_ARGUMENT: 4583 case SCF_ERROR_HANDLE_MISMATCH: 4584 case SCF_ERROR_NOT_BOUND: 4585 case SCF_ERROR_NOT_SET: 4586 default: 4587 bad_error("scf_transaction_property_" 4588 "new", scf_error()); 4589 } 4590 } 4591 } 4592 4593 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 4594 new_dpt_pgroup->sc_pgroup_fmri) != 0) 4595 /* invalid sc_pgroup_fmri caught above */ 4596 bad_error("scf_value_set_from_string", 4597 scf_error()); 4598 4599 if (scf_entry_add_value(ent, val) != 0) 4600 bad_error("scf_entry_add_value", scf_error()); 4601 break; 4602 } 4603 4604 case -2: 4605 warn(li_corrupt, ient->sc_fmri); 4606 internal_pgroup_free(current_pg); 4607 r = EBADF; 4608 goto out; 4609 4610 case -1: 4611 default: 4612 /* invalid sc_pgroup_fmri caught above */ 4613 bad_error("fmri_equal", r); 4614 } 4615 4616 r = 0; 4617 4618 out: 4619 if (old_dpt_pgroup != NULL) 4620 internal_pgroup_free(old_dpt_pgroup); 4621 4622 return (r); 4623 } 4624 4625 /* 4626 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 4627 * would import it, except it seems to exist in the service anyway. Compare 4628 * the existent dependent with the one we would import, and report any 4629 * differences (if there are none, be silent). prop is the property which 4630 * represents the existent dependent (in the dependents property group) in the 4631 * entity corresponding to ient. 4632 * 4633 * Returns 4634 * 0 - success (Sort of. At least, we can continue importing.) 4635 * ECONNABORTED - repository connection broken 4636 * EBUSY - ancestor of prop was deleted (error printed) 4637 * ENOMEM - out of memory 4638 * EBADF - corrupt property group (error printed) 4639 * EINVAL - new_dpt_pgroup has invalid target (error printed) 4640 */ 4641 static int 4642 handle_dependent_conflict(const entity_t * const ient, 4643 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 4644 { 4645 int r; 4646 scf_type_t ty; 4647 scf_error_t scfe; 4648 void *tptr; 4649 int tissvc; 4650 pgroup_t *pgroup; 4651 4652 if (scf_property_get_value(prop, ud_val) != 0) { 4653 switch (scf_error()) { 4654 case SCF_ERROR_CONNECTION_BROKEN: 4655 return (scferror2errno(scf_error())); 4656 4657 case SCF_ERROR_DELETED: 4658 warn(emsg_pg_deleted, ient->sc_fmri, 4659 new_dpt_pgroup->sc_pgroup_name); 4660 return (EBUSY); 4661 4662 case SCF_ERROR_CONSTRAINT_VIOLATED: 4663 case SCF_ERROR_NOT_FOUND: 4664 warn(gettext("Conflict upgrading %s (not importing " 4665 "dependent \"%s\" because it already exists.) " 4666 "Warning: The \"%s/%2$s\" property has more or " 4667 "fewer than one value)).\n"), ient->sc_fmri, 4668 new_dpt_pgroup->sc_pgroup_name, "dependents"); 4669 return (0); 4670 4671 case SCF_ERROR_HANDLE_MISMATCH: 4672 case SCF_ERROR_NOT_BOUND: 4673 case SCF_ERROR_NOT_SET: 4674 case SCF_ERROR_PERMISSION_DENIED: 4675 default: 4676 bad_error("scf_property_get_value", 4677 scf_error()); 4678 } 4679 } 4680 4681 ty = scf_value_type(ud_val); 4682 assert(ty != SCF_TYPE_INVALID); 4683 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4684 warn(gettext("Conflict upgrading %s (not importing dependent " 4685 "\"%s\" because it already exists). Warning: The " 4686 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 4687 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 4688 scf_type_to_string(ty), "dependents"); 4689 return (0); 4690 } 4691 4692 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4693 0) 4694 bad_error("scf_value_get_as_string", scf_error()); 4695 4696 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4697 switch (r) { 4698 case 0: 4699 warn(gettext("Conflict upgrading %s (not importing dependent " 4700 "\"%s\" (target \"%s\") because it already exists with " 4701 "target \"%s\").\n"), ient->sc_fmri, 4702 new_dpt_pgroup->sc_pgroup_name, 4703 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 4704 return (0); 4705 4706 case 1: 4707 break; 4708 4709 case -1: 4710 warn(gettext("Conflict upgrading %s (not importing dependent " 4711 "\"%s\" because it already exists). Warning: The current " 4712 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 4713 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4714 return (0); 4715 4716 case -2: 4717 warn(gettext("Dependent \"%s\" of %s has invalid target " 4718 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 4719 new_dpt_pgroup->sc_pgroup_fmri); 4720 return (EINVAL); 4721 4722 default: 4723 bad_error("fmri_equal", r); 4724 } 4725 4726 /* compare dependency pgs in target */ 4727 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 4728 switch (scfe) { 4729 case SCF_ERROR_NONE: 4730 break; 4731 4732 case SCF_ERROR_NO_MEMORY: 4733 return (ENOMEM); 4734 4735 case SCF_ERROR_NOT_FOUND: 4736 warn(emsg_dpt_dangling, ient->sc_fmri, 4737 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4738 return (0); 4739 4740 case SCF_ERROR_CONSTRAINT_VIOLATED: 4741 case SCF_ERROR_INVALID_ARGUMENT: 4742 default: 4743 bad_error("fmri_to_entity", scfe); 4744 } 4745 4746 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 4747 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 4748 switch (r) { 4749 case 0: 4750 break; 4751 4752 case ECONNABORTED: 4753 return (r); 4754 4755 case ECANCELED: 4756 warn(emsg_dpt_dangling, ient->sc_fmri, 4757 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4758 return (0); 4759 4760 case EBADF: 4761 if (tissvc) 4762 warn(gettext("%s has an instance with a \"%s\" " 4763 "snapshot which is missing a snaplevel.\n"), 4764 ud_ctarg, "running"); 4765 else 4766 warn(gettext("%s has a \"%s\" snapshot which is " 4767 "missing a snaplevel.\n"), ud_ctarg, "running"); 4768 /* FALLTHROUGH */ 4769 4770 case ENOENT: 4771 warn(emsg_dpt_no_dep, ient->sc_fmri, 4772 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4773 new_dpt_pgroup->sc_pgroup_name); 4774 return (0); 4775 4776 case EINVAL: 4777 default: 4778 bad_error("entity_get_running_pg", r); 4779 } 4780 4781 pgroup = internal_pgroup_new(); 4782 if (pgroup == NULL) 4783 return (ENOMEM); 4784 4785 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 4786 switch (r) { 4787 case 0: 4788 break; 4789 4790 case ECONNABORTED: 4791 case EBADF: 4792 case ENOMEM: 4793 internal_pgroup_free(pgroup); 4794 return (r); 4795 4796 case ECANCELED: 4797 warn(emsg_dpt_no_dep, ient->sc_fmri, 4798 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4799 new_dpt_pgroup->sc_pgroup_name); 4800 internal_pgroup_free(pgroup); 4801 return (0); 4802 4803 case EACCES: 4804 default: 4805 bad_error("load_pg", r); 4806 } 4807 4808 /* report differences */ 4809 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 4810 internal_pgroup_free(pgroup); 4811 return (0); 4812 } 4813 4814 /* 4815 * lipg is a property group in the last-import snapshot of ent, which is an 4816 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 4817 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 4818 * in ents's property groups, compare and upgrade ent appropriately. 4819 * 4820 * Returns 4821 * 0 - success 4822 * ECONNABORTED - repository connection broken 4823 * ENOMEM - out of memory 4824 * ENOSPC - configd is out of resources 4825 * EINVAL - ient has invalid dependent (error printed) 4826 * - ient has invalid pgroup_t (error printed) 4827 * ECANCELED - ent has been deleted 4828 * ENODEV - entity containing lipg has been deleted 4829 * - entity containing running has been deleted 4830 * EPERM - could not delete pg (permission denied) (error printed) 4831 * - couldn't upgrade dependents (permission denied) (error printed) 4832 * - couldn't import pg (permission denied) (error printed) 4833 * - couldn't upgrade pg (permission denied) (error printed) 4834 * EROFS - could not delete pg (repository read-only) 4835 * - couldn't upgrade dependents (repository read-only) 4836 * - couldn't import pg (repository read-only) 4837 * - couldn't upgrade pg (repository read-only) 4838 * EACCES - could not delete pg (backend access denied) 4839 * - couldn't upgrade dependents (backend access denied) 4840 * - couldn't import pg (backend access denied) 4841 * - couldn't upgrade pg (backend access denied) 4842 * - couldn't read property (backend access denied) 4843 * EBUSY - property group was added (error printed) 4844 * - property group was deleted (error printed) 4845 * - property group changed (error printed) 4846 * - "dependents" pg was added, changed, or deleted (error printed) 4847 * - dependent target deleted (error printed) 4848 * - dependent pg changed (error printed) 4849 * EBADF - imp_snpl is corrupt (error printed) 4850 * - ent has bad pg (error printed) 4851 * EEXIST - dependent collision in target service (error printed) 4852 */ 4853 static int 4854 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 4855 const scf_snaplevel_t *running) 4856 { 4857 int r; 4858 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 4859 scf_callback_t cbdata; 4860 4861 const char * const cf_pg_missing = 4862 gettext("Conflict upgrading %s (property group %s is missing)\n"); 4863 const char * const deleting = 4864 gettext("%s: Deleting property group \"%s\".\n"); 4865 4866 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 4867 4868 /* Skip dependent property groups. */ 4869 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 4870 switch (scf_error()) { 4871 case SCF_ERROR_DELETED: 4872 return (ENODEV); 4873 4874 case SCF_ERROR_CONNECTION_BROKEN: 4875 return (ECONNABORTED); 4876 4877 case SCF_ERROR_NOT_SET: 4878 case SCF_ERROR_NOT_BOUND: 4879 default: 4880 bad_error("scf_pg_get_type", scf_error()); 4881 } 4882 } 4883 4884 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 4885 if (scf_pg_get_property(lipg, "external", NULL) == 0) 4886 return (0); 4887 4888 switch (scf_error()) { 4889 case SCF_ERROR_NOT_FOUND: 4890 break; 4891 4892 case SCF_ERROR_CONNECTION_BROKEN: 4893 return (ECONNABORTED); 4894 4895 case SCF_ERROR_DELETED: 4896 return (ENODEV); 4897 4898 case SCF_ERROR_INVALID_ARGUMENT: 4899 case SCF_ERROR_NOT_BOUND: 4900 case SCF_ERROR_HANDLE_MISMATCH: 4901 case SCF_ERROR_NOT_SET: 4902 default: 4903 bad_error("scf_pg_get_property", scf_error()); 4904 } 4905 } 4906 4907 /* lookup pg in new properties */ 4908 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 4909 switch (scf_error()) { 4910 case SCF_ERROR_DELETED: 4911 return (ENODEV); 4912 4913 case SCF_ERROR_CONNECTION_BROKEN: 4914 return (ECONNABORTED); 4915 4916 case SCF_ERROR_NOT_SET: 4917 case SCF_ERROR_NOT_BOUND: 4918 default: 4919 bad_error("scf_pg_get_name", scf_error()); 4920 } 4921 } 4922 4923 pgrp.sc_pgroup_name = imp_str; 4924 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 4925 4926 if (mpg != NULL) 4927 mpg->sc_pgroup_seen = 1; 4928 4929 /* Special handling for dependents */ 4930 if (strcmp(imp_str, "dependents") == 0) 4931 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 4932 4933 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 4934 return (upgrade_manifestfiles(NULL, ient, running, ent)); 4935 4936 if (mpg == NULL || mpg->sc_pgroup_delete) { 4937 /* property group was deleted from manifest */ 4938 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 4939 switch (scf_error()) { 4940 case SCF_ERROR_NOT_FOUND: 4941 return (0); 4942 4943 case SCF_ERROR_DELETED: 4944 case SCF_ERROR_CONNECTION_BROKEN: 4945 return (scferror2errno(scf_error())); 4946 4947 case SCF_ERROR_INVALID_ARGUMENT: 4948 case SCF_ERROR_HANDLE_MISMATCH: 4949 case SCF_ERROR_NOT_BOUND: 4950 case SCF_ERROR_NOT_SET: 4951 default: 4952 bad_error("entity_get_pg", scf_error()); 4953 } 4954 } 4955 4956 if (mpg != NULL && mpg->sc_pgroup_delete) { 4957 if (g_verbose) 4958 warn(deleting, ient->sc_fmri, imp_str); 4959 if (scf_pg_delete(imp_pg2) == 0) 4960 return (0); 4961 4962 switch (scf_error()) { 4963 case SCF_ERROR_DELETED: 4964 return (0); 4965 4966 case SCF_ERROR_CONNECTION_BROKEN: 4967 case SCF_ERROR_BACKEND_READONLY: 4968 case SCF_ERROR_BACKEND_ACCESS: 4969 return (scferror2errno(scf_error())); 4970 4971 case SCF_ERROR_PERMISSION_DENIED: 4972 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 4973 return (scferror2errno(scf_error())); 4974 4975 case SCF_ERROR_NOT_SET: 4976 default: 4977 bad_error("scf_pg_delete", scf_error()); 4978 } 4979 } 4980 4981 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 4982 switch (r) { 4983 case 0: 4984 break; 4985 4986 case ECANCELED: 4987 return (ENODEV); 4988 4989 case ECONNABORTED: 4990 case ENOMEM: 4991 case EBADF: 4992 case EACCES: 4993 return (r); 4994 4995 default: 4996 bad_error("load_pg", r); 4997 } 4998 4999 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5000 switch (r) { 5001 case 0: 5002 break; 5003 5004 case ECANCELED: 5005 case ECONNABORTED: 5006 case ENOMEM: 5007 case EBADF: 5008 case EACCES: 5009 internal_pgroup_free(lipg_i); 5010 return (r); 5011 5012 default: 5013 bad_error("load_pg", r); 5014 } 5015 5016 if (pg_equal(lipg_i, curpg_i)) { 5017 if (g_verbose) 5018 warn(deleting, ient->sc_fmri, imp_str); 5019 if (scf_pg_delete(imp_pg2) != 0) { 5020 switch (scf_error()) { 5021 case SCF_ERROR_DELETED: 5022 break; 5023 5024 case SCF_ERROR_CONNECTION_BROKEN: 5025 internal_pgroup_free(lipg_i); 5026 internal_pgroup_free(curpg_i); 5027 return (ECONNABORTED); 5028 5029 case SCF_ERROR_NOT_SET: 5030 case SCF_ERROR_NOT_BOUND: 5031 default: 5032 bad_error("scf_pg_delete", scf_error()); 5033 } 5034 } 5035 } else { 5036 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5037 } 5038 5039 internal_pgroup_free(lipg_i); 5040 internal_pgroup_free(curpg_i); 5041 5042 return (0); 5043 } 5044 5045 /* 5046 * Only dependent pgs can have override set, and we skipped those 5047 * above. 5048 */ 5049 assert(!mpg->sc_pgroup_override); 5050 5051 /* compare */ 5052 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5053 switch (r) { 5054 case 0: 5055 break; 5056 5057 case ECANCELED: 5058 return (ENODEV); 5059 5060 case ECONNABORTED: 5061 case EBADF: 5062 case ENOMEM: 5063 case EACCES: 5064 return (r); 5065 5066 default: 5067 bad_error("load_pg", r); 5068 } 5069 5070 if (pg_equal(mpg, lipg_i)) { 5071 /* The manifest pg has not changed. Move on. */ 5072 r = 0; 5073 goto out; 5074 } 5075 5076 /* upgrade current properties according to lipg & mpg */ 5077 if (running != NULL) 5078 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5079 else 5080 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5081 if (r != 0) { 5082 switch (scf_error()) { 5083 case SCF_ERROR_CONNECTION_BROKEN: 5084 r = scferror2errno(scf_error()); 5085 goto out; 5086 5087 case SCF_ERROR_DELETED: 5088 if (running != NULL) 5089 r = ENODEV; 5090 else 5091 r = ECANCELED; 5092 goto out; 5093 5094 case SCF_ERROR_NOT_FOUND: 5095 break; 5096 5097 case SCF_ERROR_INVALID_ARGUMENT: 5098 case SCF_ERROR_HANDLE_MISMATCH: 5099 case SCF_ERROR_NOT_BOUND: 5100 case SCF_ERROR_NOT_SET: 5101 default: 5102 bad_error("entity_get_pg", scf_error()); 5103 } 5104 5105 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5106 5107 r = 0; 5108 goto out; 5109 } 5110 5111 r = load_pg_attrs(imp_pg2, &curpg_i); 5112 switch (r) { 5113 case 0: 5114 break; 5115 5116 case ECANCELED: 5117 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5118 r = 0; 5119 goto out; 5120 5121 case ECONNABORTED: 5122 case ENOMEM: 5123 goto out; 5124 5125 default: 5126 bad_error("load_pg_attrs", r); 5127 } 5128 5129 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5130 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5131 internal_pgroup_free(curpg_i); 5132 r = 0; 5133 goto out; 5134 } 5135 5136 internal_pgroup_free(curpg_i); 5137 5138 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5139 switch (r) { 5140 case 0: 5141 break; 5142 5143 case ECANCELED: 5144 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5145 r = 0; 5146 goto out; 5147 5148 case ECONNABORTED: 5149 case EBADF: 5150 case ENOMEM: 5151 case EACCES: 5152 goto out; 5153 5154 default: 5155 bad_error("load_pg", r); 5156 } 5157 5158 if (pg_equal(lipg_i, curpg_i) && 5159 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5160 int do_delete = 1; 5161 5162 if (g_verbose) 5163 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5164 ient->sc_fmri, mpg->sc_pgroup_name); 5165 5166 internal_pgroup_free(curpg_i); 5167 5168 if (running != NULL && 5169 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5170 switch (scf_error()) { 5171 case SCF_ERROR_DELETED: 5172 r = ECANCELED; 5173 goto out; 5174 5175 case SCF_ERROR_NOT_FOUND: 5176 do_delete = 0; 5177 break; 5178 5179 case SCF_ERROR_CONNECTION_BROKEN: 5180 r = scferror2errno(scf_error()); 5181 goto out; 5182 5183 case SCF_ERROR_HANDLE_MISMATCH: 5184 case SCF_ERROR_INVALID_ARGUMENT: 5185 case SCF_ERROR_NOT_SET: 5186 case SCF_ERROR_NOT_BOUND: 5187 default: 5188 bad_error("entity_get_pg", scf_error()); 5189 } 5190 } 5191 5192 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5193 switch (scf_error()) { 5194 case SCF_ERROR_DELETED: 5195 break; 5196 5197 case SCF_ERROR_CONNECTION_BROKEN: 5198 case SCF_ERROR_BACKEND_READONLY: 5199 case SCF_ERROR_BACKEND_ACCESS: 5200 r = scferror2errno(scf_error()); 5201 goto out; 5202 5203 case SCF_ERROR_PERMISSION_DENIED: 5204 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5205 ient->sc_fmri); 5206 r = scferror2errno(scf_error()); 5207 goto out; 5208 5209 case SCF_ERROR_NOT_SET: 5210 case SCF_ERROR_NOT_BOUND: 5211 default: 5212 bad_error("scf_pg_delete", scf_error()); 5213 } 5214 } 5215 5216 cbdata.sc_handle = g_hndl; 5217 cbdata.sc_parent = ent; 5218 cbdata.sc_service = issvc; 5219 cbdata.sc_flags = 0; 5220 cbdata.sc_source_fmri = ient->sc_fmri; 5221 cbdata.sc_target_fmri = ient->sc_fmri; 5222 5223 r = entity_pgroup_import(mpg, &cbdata); 5224 switch (r) { 5225 case UU_WALK_NEXT: 5226 r = 0; 5227 goto out; 5228 5229 case UU_WALK_ERROR: 5230 if (cbdata.sc_err == EEXIST) { 5231 warn(emsg_pg_added, ient->sc_fmri, 5232 mpg->sc_pgroup_name); 5233 r = EBUSY; 5234 } else { 5235 r = cbdata.sc_err; 5236 } 5237 goto out; 5238 5239 default: 5240 bad_error("entity_pgroup_import", r); 5241 } 5242 } 5243 5244 if (running != NULL && 5245 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5246 switch (scf_error()) { 5247 case SCF_ERROR_CONNECTION_BROKEN: 5248 case SCF_ERROR_DELETED: 5249 r = scferror2errno(scf_error()); 5250 goto out; 5251 5252 case SCF_ERROR_NOT_FOUND: 5253 break; 5254 5255 case SCF_ERROR_HANDLE_MISMATCH: 5256 case SCF_ERROR_INVALID_ARGUMENT: 5257 case SCF_ERROR_NOT_SET: 5258 case SCF_ERROR_NOT_BOUND: 5259 default: 5260 bad_error("entity_get_pg", scf_error()); 5261 } 5262 5263 cbdata.sc_handle = g_hndl; 5264 cbdata.sc_parent = ent; 5265 cbdata.sc_service = issvc; 5266 cbdata.sc_flags = SCI_FORCE; 5267 cbdata.sc_source_fmri = ient->sc_fmri; 5268 cbdata.sc_target_fmri = ient->sc_fmri; 5269 5270 r = entity_pgroup_import(mpg, &cbdata); 5271 switch (r) { 5272 case UU_WALK_NEXT: 5273 r = 0; 5274 goto out; 5275 5276 case UU_WALK_ERROR: 5277 if (cbdata.sc_err == EEXIST) { 5278 warn(emsg_pg_added, ient->sc_fmri, 5279 mpg->sc_pgroup_name); 5280 r = EBUSY; 5281 } else { 5282 r = cbdata.sc_err; 5283 } 5284 goto out; 5285 5286 default: 5287 bad_error("entity_pgroup_import", r); 5288 } 5289 } 5290 5291 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5292 internal_pgroup_free(curpg_i); 5293 switch (r) { 5294 case 0: 5295 ient->sc_import_state = IMPORT_PROP_BEGUN; 5296 break; 5297 5298 case ECANCELED: 5299 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5300 r = EBUSY; 5301 break; 5302 5303 case EPERM: 5304 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5305 break; 5306 5307 case EBUSY: 5308 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5309 break; 5310 5311 case ECONNABORTED: 5312 case ENOMEM: 5313 case ENOSPC: 5314 case EROFS: 5315 case EACCES: 5316 case EINVAL: 5317 break; 5318 5319 default: 5320 bad_error("upgrade_pg", r); 5321 } 5322 5323 out: 5324 internal_pgroup_free(lipg_i); 5325 return (r); 5326 } 5327 5328 /* 5329 * Upgrade the properties of ent according to snpl & ient. 5330 * 5331 * Returns 5332 * 0 - success 5333 * ECONNABORTED - repository connection broken 5334 * ENOMEM - out of memory 5335 * ENOSPC - configd is out of resources 5336 * ECANCELED - ent was deleted 5337 * ENODEV - entity containing snpl was deleted 5338 * - entity containing running was deleted 5339 * EBADF - imp_snpl is corrupt (error printed) 5340 * - ent has corrupt pg (error printed) 5341 * - dependent has corrupt pg (error printed) 5342 * - dependent target has a corrupt snapshot (error printed) 5343 * EBUSY - pg was added, changed, or deleted (error printed) 5344 * - dependent target was deleted (error printed) 5345 * - dependent pg changed (error printed) 5346 * EINVAL - invalid property group name (error printed) 5347 * - invalid property name (error printed) 5348 * - invalid value (error printed) 5349 * - ient has invalid pgroup or dependent (error printed) 5350 * EPERM - could not create property group (permission denied) (error printed) 5351 * - could not modify property group (permission denied) (error printed) 5352 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5353 * EROFS - could not create property group (repository read-only) 5354 * - couldn't delete, upgrade, or import pg or dependent 5355 * EACCES - could not create property group (backend access denied) 5356 * - couldn't delete, upgrade, or import pg or dependent 5357 * EEXIST - dependent collision in target service (error printed) 5358 */ 5359 static int 5360 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5361 entity_t *ient) 5362 { 5363 pgroup_t *pg, *rpg; 5364 int r; 5365 uu_list_t *pgs = ient->sc_pgroups; 5366 5367 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5368 5369 /* clear sc_sceen for pgs */ 5370 if (uu_list_walk(pgs, clear_int, 5371 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5372 bad_error("uu_list_walk", uu_error()); 5373 5374 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5375 switch (scf_error()) { 5376 case SCF_ERROR_DELETED: 5377 return (ENODEV); 5378 5379 case SCF_ERROR_CONNECTION_BROKEN: 5380 return (ECONNABORTED); 5381 5382 case SCF_ERROR_NOT_SET: 5383 case SCF_ERROR_NOT_BOUND: 5384 case SCF_ERROR_HANDLE_MISMATCH: 5385 default: 5386 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5387 } 5388 } 5389 5390 for (;;) { 5391 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5392 if (r == 0) 5393 break; 5394 if (r == 1) { 5395 r = process_old_pg(imp_pg, ient, ent, running); 5396 switch (r) { 5397 case 0: 5398 break; 5399 5400 case ECONNABORTED: 5401 case ENOMEM: 5402 case ENOSPC: 5403 case ECANCELED: 5404 case ENODEV: 5405 case EPERM: 5406 case EROFS: 5407 case EACCES: 5408 case EBADF: 5409 case EBUSY: 5410 case EINVAL: 5411 case EEXIST: 5412 return (r); 5413 5414 default: 5415 bad_error("process_old_pg", r); 5416 } 5417 continue; 5418 } 5419 if (r != -1) 5420 bad_error("scf_iter_next_pg", r); 5421 5422 switch (scf_error()) { 5423 case SCF_ERROR_DELETED: 5424 return (ENODEV); 5425 5426 case SCF_ERROR_CONNECTION_BROKEN: 5427 return (ECONNABORTED); 5428 5429 case SCF_ERROR_HANDLE_MISMATCH: 5430 case SCF_ERROR_NOT_BOUND: 5431 case SCF_ERROR_NOT_SET: 5432 case SCF_ERROR_INVALID_ARGUMENT: 5433 default: 5434 bad_error("scf_iter_next_pg", scf_error()); 5435 } 5436 } 5437 5438 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5439 if (pg->sc_pgroup_seen) 5440 continue; 5441 5442 /* pg is new */ 5443 5444 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5445 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5446 ent); 5447 switch (r) { 5448 case 0: 5449 break; 5450 5451 case ECONNABORTED: 5452 case ENOMEM: 5453 case ENOSPC: 5454 case ECANCELED: 5455 case ENODEV: 5456 case EBADF: 5457 case EBUSY: 5458 case EINVAL: 5459 case EPERM: 5460 case EROFS: 5461 case EACCES: 5462 case EEXIST: 5463 return (r); 5464 5465 default: 5466 bad_error("upgrade_dependents", r); 5467 } 5468 continue; 5469 } 5470 5471 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 5472 r = upgrade_manifestfiles(pg, ient, running, ent); 5473 switch (r) { 5474 case 0: 5475 break; 5476 5477 case ECONNABORTED: 5478 case ENOMEM: 5479 case ENOSPC: 5480 case ECANCELED: 5481 case ENODEV: 5482 case EBADF: 5483 case EBUSY: 5484 case EINVAL: 5485 case EPERM: 5486 case EROFS: 5487 case EACCES: 5488 case EEXIST: 5489 return (r); 5490 5491 default: 5492 bad_error("upgrade_manifestfiles", r); 5493 } 5494 continue; 5495 } 5496 5497 if (running != NULL) { 5498 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 5499 imp_pg); 5500 } else { 5501 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 5502 imp_pg); 5503 } 5504 if (r != 0) { 5505 scf_callback_t cbdata; 5506 5507 switch (scf_error()) { 5508 case SCF_ERROR_NOT_FOUND: 5509 break; 5510 5511 case SCF_ERROR_CONNECTION_BROKEN: 5512 return (scferror2errno(scf_error())); 5513 5514 case SCF_ERROR_DELETED: 5515 if (running != NULL) 5516 return (ENODEV); 5517 else 5518 return (scferror2errno(scf_error())); 5519 5520 case SCF_ERROR_INVALID_ARGUMENT: 5521 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 5522 pg->sc_pgroup_name); 5523 return (EINVAL); 5524 5525 case SCF_ERROR_NOT_SET: 5526 case SCF_ERROR_HANDLE_MISMATCH: 5527 case SCF_ERROR_NOT_BOUND: 5528 default: 5529 bad_error("entity_get_pg", scf_error()); 5530 } 5531 5532 /* User doesn't have pg, so import it. */ 5533 5534 cbdata.sc_handle = g_hndl; 5535 cbdata.sc_parent = ent; 5536 cbdata.sc_service = issvc; 5537 cbdata.sc_flags = SCI_FORCE; 5538 cbdata.sc_source_fmri = ient->sc_fmri; 5539 cbdata.sc_target_fmri = ient->sc_fmri; 5540 5541 r = entity_pgroup_import(pg, &cbdata); 5542 switch (r) { 5543 case UU_WALK_NEXT: 5544 ient->sc_import_state = IMPORT_PROP_BEGUN; 5545 continue; 5546 5547 case UU_WALK_ERROR: 5548 if (cbdata.sc_err == EEXIST) { 5549 warn(emsg_pg_added, ient->sc_fmri, 5550 pg->sc_pgroup_name); 5551 return (EBUSY); 5552 } 5553 return (cbdata.sc_err); 5554 5555 default: 5556 bad_error("entity_pgroup_import", r); 5557 } 5558 } 5559 5560 /* report differences between pg & current */ 5561 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 5562 switch (r) { 5563 case 0: 5564 break; 5565 5566 case ECANCELED: 5567 warn(emsg_pg_deleted, ient->sc_fmri, 5568 pg->sc_pgroup_name); 5569 return (EBUSY); 5570 5571 case ECONNABORTED: 5572 case EBADF: 5573 case ENOMEM: 5574 case EACCES: 5575 return (r); 5576 5577 default: 5578 bad_error("load_pg", r); 5579 } 5580 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 5581 internal_pgroup_free(rpg); 5582 rpg = NULL; 5583 } 5584 5585 return (0); 5586 } 5587 5588 /* 5589 * Import an instance. If it doesn't exist, create it. If it has 5590 * a last-import snapshot, upgrade its properties. Finish by updating its 5591 * last-import snapshot. If it doesn't have a last-import snapshot then it 5592 * could have been created for a dependent tag in another manifest. Import the 5593 * new properties. If there's a conflict, don't override, like now? 5594 * 5595 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 5596 * lcbdata->sc_err to 5597 * ECONNABORTED - repository connection broken 5598 * ENOMEM - out of memory 5599 * ENOSPC - svc.configd is out of resources 5600 * EEXIST - dependency collision in dependent service (error printed) 5601 * EPERM - couldn't create temporary instance (permission denied) 5602 * - couldn't import into temporary instance (permission denied) 5603 * - couldn't take snapshot (permission denied) 5604 * - couldn't upgrade properties (permission denied) 5605 * - couldn't import properties (permission denied) 5606 * - couldn't import dependents (permission denied) 5607 * EROFS - couldn't create temporary instance (repository read-only) 5608 * - couldn't import into temporary instance (repository read-only) 5609 * - couldn't upgrade properties (repository read-only) 5610 * - couldn't import properties (repository read-only) 5611 * - couldn't import dependents (repository read-only) 5612 * EACCES - couldn't create temporary instance (backend access denied) 5613 * - couldn't import into temporary instance (backend access denied) 5614 * - couldn't upgrade properties (backend access denied) 5615 * - couldn't import properties (backend access denied) 5616 * - couldn't import dependents (backend access denied) 5617 * EINVAL - invalid instance name (error printed) 5618 * - invalid pgroup_t's (error printed) 5619 * - invalid dependents (error printed) 5620 * EBUSY - temporary service deleted (error printed) 5621 * - temporary instance deleted (error printed) 5622 * - temporary instance changed (error printed) 5623 * - temporary instance already exists (error printed) 5624 * - instance deleted (error printed) 5625 * EBADF - instance has corrupt last-import snapshot (error printed) 5626 * - instance is corrupt (error printed) 5627 * - dependent has corrupt pg (error printed) 5628 * - dependent target has a corrupt snapshot (error printed) 5629 * -1 - unknown libscf error (error printed) 5630 */ 5631 static int 5632 lscf_instance_import(void *v, void *pvt) 5633 { 5634 entity_t *inst = v; 5635 scf_callback_t ctx; 5636 scf_callback_t *lcbdata = pvt; 5637 scf_service_t *rsvc = lcbdata->sc_parent; 5638 int r; 5639 scf_snaplevel_t *running; 5640 int flags = lcbdata->sc_flags; 5641 5642 const char * const emsg_tdel = 5643 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 5644 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 5645 "changed unexpectedly.\n"); 5646 const char * const emsg_del = gettext("%s changed unexpectedly " 5647 "(instance \"%s\" was deleted.)\n"); 5648 const char * const emsg_badsnap = gettext( 5649 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 5650 5651 /* 5652 * prepare last-import snapshot: 5653 * create temporary instance (service was precreated) 5654 * populate with properties from bundle 5655 * take snapshot 5656 */ 5657 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 5658 switch (scf_error()) { 5659 case SCF_ERROR_CONNECTION_BROKEN: 5660 case SCF_ERROR_NO_RESOURCES: 5661 case SCF_ERROR_BACKEND_READONLY: 5662 case SCF_ERROR_BACKEND_ACCESS: 5663 return (stash_scferror(lcbdata)); 5664 5665 case SCF_ERROR_EXISTS: 5666 warn(gettext("Temporary service svc:/%s " 5667 "changed unexpectedly (instance \"%s\" added).\n"), 5668 imp_tsname, inst->sc_name); 5669 lcbdata->sc_err = EBUSY; 5670 return (UU_WALK_ERROR); 5671 5672 case SCF_ERROR_DELETED: 5673 warn(gettext("Temporary service svc:/%s " 5674 "was deleted unexpectedly.\n"), imp_tsname); 5675 lcbdata->sc_err = EBUSY; 5676 return (UU_WALK_ERROR); 5677 5678 case SCF_ERROR_INVALID_ARGUMENT: 5679 warn(gettext("Invalid instance name \"%s\".\n"), 5680 inst->sc_name); 5681 return (stash_scferror(lcbdata)); 5682 5683 case SCF_ERROR_PERMISSION_DENIED: 5684 warn(gettext("Could not create temporary instance " 5685 "\"%s\" in svc:/%s (permission denied).\n"), 5686 inst->sc_name, imp_tsname); 5687 return (stash_scferror(lcbdata)); 5688 5689 case SCF_ERROR_HANDLE_MISMATCH: 5690 case SCF_ERROR_NOT_BOUND: 5691 case SCF_ERROR_NOT_SET: 5692 default: 5693 bad_error("scf_service_add_instance", scf_error()); 5694 } 5695 } 5696 5697 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5698 inst->sc_name); 5699 if (r < 0) 5700 bad_error("snprintf", errno); 5701 5702 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 5703 lcbdata->sc_flags | SCI_NOENABLED); 5704 switch (r) { 5705 case 0: 5706 break; 5707 5708 case ECANCELED: 5709 warn(emsg_tdel, imp_tsname, inst->sc_name); 5710 lcbdata->sc_err = EBUSY; 5711 r = UU_WALK_ERROR; 5712 goto deltemp; 5713 5714 case EEXIST: 5715 warn(emsg_tchg, imp_tsname, inst->sc_name); 5716 lcbdata->sc_err = EBUSY; 5717 r = UU_WALK_ERROR; 5718 goto deltemp; 5719 5720 case ECONNABORTED: 5721 goto connaborted; 5722 5723 case ENOMEM: 5724 case ENOSPC: 5725 case EPERM: 5726 case EROFS: 5727 case EACCES: 5728 case EINVAL: 5729 case EBUSY: 5730 lcbdata->sc_err = r; 5731 r = UU_WALK_ERROR; 5732 goto deltemp; 5733 5734 default: 5735 bad_error("lscf_import_instance_pgs", r); 5736 } 5737 5738 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5739 inst->sc_name); 5740 if (r < 0) 5741 bad_error("snprintf", errno); 5742 5743 ctx.sc_handle = lcbdata->sc_handle; 5744 ctx.sc_parent = imp_tinst; 5745 ctx.sc_service = 0; 5746 ctx.sc_source_fmri = inst->sc_fmri; 5747 ctx.sc_target_fmri = imp_str; 5748 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 5749 UU_DEFAULT) != 0) { 5750 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5751 bad_error("uu_list_walk", uu_error()); 5752 5753 switch (ctx.sc_err) { 5754 case ECONNABORTED: 5755 goto connaborted; 5756 5757 case ECANCELED: 5758 warn(emsg_tdel, imp_tsname, inst->sc_name); 5759 lcbdata->sc_err = EBUSY; 5760 break; 5761 5762 case EEXIST: 5763 warn(emsg_tchg, imp_tsname, inst->sc_name); 5764 lcbdata->sc_err = EBUSY; 5765 break; 5766 5767 default: 5768 lcbdata->sc_err = ctx.sc_err; 5769 } 5770 r = UU_WALK_ERROR; 5771 goto deltemp; 5772 } 5773 5774 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 5775 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 5776 switch (scf_error()) { 5777 case SCF_ERROR_CONNECTION_BROKEN: 5778 goto connaborted; 5779 5780 case SCF_ERROR_NO_RESOURCES: 5781 r = stash_scferror(lcbdata); 5782 goto deltemp; 5783 5784 case SCF_ERROR_EXISTS: 5785 warn(emsg_tchg, imp_tsname, inst->sc_name); 5786 lcbdata->sc_err = EBUSY; 5787 r = UU_WALK_ERROR; 5788 goto deltemp; 5789 5790 case SCF_ERROR_PERMISSION_DENIED: 5791 warn(gettext("Could not take \"%s\" snapshot of %s " 5792 "(permission denied).\n"), snap_lastimport, 5793 imp_str); 5794 r = stash_scferror(lcbdata); 5795 goto deltemp; 5796 5797 default: 5798 scfwarn(); 5799 lcbdata->sc_err = -1; 5800 r = UU_WALK_ERROR; 5801 goto deltemp; 5802 5803 case SCF_ERROR_HANDLE_MISMATCH: 5804 case SCF_ERROR_INVALID_ARGUMENT: 5805 case SCF_ERROR_NOT_SET: 5806 bad_error("_scf_snapshot_take_new_named", scf_error()); 5807 } 5808 } 5809 5810 if (lcbdata->sc_flags & SCI_FRESH) 5811 goto fresh; 5812 5813 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 5814 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 5815 imp_lisnap) != 0) { 5816 switch (scf_error()) { 5817 case SCF_ERROR_DELETED: 5818 warn(emsg_del, inst->sc_parent->sc_fmri, 5819 inst->sc_name); 5820 lcbdata->sc_err = EBUSY; 5821 r = UU_WALK_ERROR; 5822 goto deltemp; 5823 5824 case SCF_ERROR_NOT_FOUND: 5825 flags |= SCI_FORCE; 5826 goto nosnap; 5827 5828 case SCF_ERROR_CONNECTION_BROKEN: 5829 goto connaborted; 5830 5831 case SCF_ERROR_INVALID_ARGUMENT: 5832 case SCF_ERROR_HANDLE_MISMATCH: 5833 case SCF_ERROR_NOT_BOUND: 5834 case SCF_ERROR_NOT_SET: 5835 default: 5836 bad_error("scf_instance_get_snapshot", 5837 scf_error()); 5838 } 5839 } 5840 5841 /* upgrade */ 5842 5843 /* 5844 * compare new properties with last-import properties 5845 * upgrade current properties 5846 */ 5847 /* clear sc_sceen for pgs */ 5848 if (uu_list_walk(inst->sc_pgroups, clear_int, 5849 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 5850 0) 5851 bad_error("uu_list_walk", uu_error()); 5852 5853 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 5854 switch (r) { 5855 case 0: 5856 break; 5857 5858 case ECONNABORTED: 5859 goto connaborted; 5860 5861 case ECANCELED: 5862 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5863 lcbdata->sc_err = EBUSY; 5864 r = UU_WALK_ERROR; 5865 goto deltemp; 5866 5867 case ENOENT: 5868 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 5869 lcbdata->sc_err = EBADF; 5870 r = UU_WALK_ERROR; 5871 goto deltemp; 5872 5873 default: 5874 bad_error("get_snaplevel", r); 5875 } 5876 5877 if (scf_instance_get_snapshot(imp_inst, snap_running, 5878 imp_rsnap) != 0) { 5879 switch (scf_error()) { 5880 case SCF_ERROR_DELETED: 5881 warn(emsg_del, inst->sc_parent->sc_fmri, 5882 inst->sc_name); 5883 lcbdata->sc_err = EBUSY; 5884 r = UU_WALK_ERROR; 5885 goto deltemp; 5886 5887 case SCF_ERROR_NOT_FOUND: 5888 break; 5889 5890 case SCF_ERROR_CONNECTION_BROKEN: 5891 goto connaborted; 5892 5893 case SCF_ERROR_INVALID_ARGUMENT: 5894 case SCF_ERROR_HANDLE_MISMATCH: 5895 case SCF_ERROR_NOT_BOUND: 5896 case SCF_ERROR_NOT_SET: 5897 default: 5898 bad_error("scf_instance_get_snapshot", 5899 scf_error()); 5900 } 5901 5902 running = NULL; 5903 } else { 5904 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 5905 switch (r) { 5906 case 0: 5907 running = imp_rsnpl; 5908 break; 5909 5910 case ECONNABORTED: 5911 goto connaborted; 5912 5913 case ECANCELED: 5914 warn(emsg_del, inst->sc_parent->sc_fmri, 5915 inst->sc_name); 5916 lcbdata->sc_err = EBUSY; 5917 r = UU_WALK_ERROR; 5918 goto deltemp; 5919 5920 case ENOENT: 5921 warn(emsg_badsnap, snap_running, inst->sc_fmri); 5922 lcbdata->sc_err = EBADF; 5923 r = UU_WALK_ERROR; 5924 goto deltemp; 5925 5926 default: 5927 bad_error("get_snaplevel", r); 5928 } 5929 } 5930 5931 r = upgrade_props(imp_inst, running, imp_snpl, inst); 5932 switch (r) { 5933 case 0: 5934 break; 5935 5936 case ECANCELED: 5937 case ENODEV: 5938 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5939 lcbdata->sc_err = EBUSY; 5940 r = UU_WALK_ERROR; 5941 goto deltemp; 5942 5943 case ECONNABORTED: 5944 goto connaborted; 5945 5946 case ENOMEM: 5947 case ENOSPC: 5948 case EBADF: 5949 case EBUSY: 5950 case EINVAL: 5951 case EPERM: 5952 case EROFS: 5953 case EACCES: 5954 case EEXIST: 5955 lcbdata->sc_err = r; 5956 r = UU_WALK_ERROR; 5957 goto deltemp; 5958 5959 default: 5960 bad_error("upgrade_props", r); 5961 } 5962 5963 inst->sc_import_state = IMPORT_PROP_DONE; 5964 } else { 5965 switch (scf_error()) { 5966 case SCF_ERROR_CONNECTION_BROKEN: 5967 goto connaborted; 5968 5969 case SCF_ERROR_NOT_FOUND: 5970 break; 5971 5972 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5973 case SCF_ERROR_HANDLE_MISMATCH: 5974 case SCF_ERROR_NOT_BOUND: 5975 case SCF_ERROR_NOT_SET: 5976 default: 5977 bad_error("scf_service_get_instance", scf_error()); 5978 } 5979 5980 fresh: 5981 /* create instance */ 5982 if (scf_service_add_instance(rsvc, inst->sc_name, 5983 imp_inst) != 0) { 5984 switch (scf_error()) { 5985 case SCF_ERROR_CONNECTION_BROKEN: 5986 goto connaborted; 5987 5988 case SCF_ERROR_NO_RESOURCES: 5989 case SCF_ERROR_BACKEND_READONLY: 5990 case SCF_ERROR_BACKEND_ACCESS: 5991 r = stash_scferror(lcbdata); 5992 goto deltemp; 5993 5994 case SCF_ERROR_EXISTS: 5995 warn(gettext("%s changed unexpectedly " 5996 "(instance \"%s\" added).\n"), 5997 inst->sc_parent->sc_fmri, inst->sc_name); 5998 lcbdata->sc_err = EBUSY; 5999 r = UU_WALK_ERROR; 6000 goto deltemp; 6001 6002 case SCF_ERROR_PERMISSION_DENIED: 6003 warn(gettext("Could not create \"%s\" instance " 6004 "in %s (permission denied).\n"), 6005 inst->sc_name, inst->sc_parent->sc_fmri); 6006 r = stash_scferror(lcbdata); 6007 goto deltemp; 6008 6009 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6010 case SCF_ERROR_HANDLE_MISMATCH: 6011 case SCF_ERROR_NOT_BOUND: 6012 case SCF_ERROR_NOT_SET: 6013 default: 6014 bad_error("scf_service_add_instance", 6015 scf_error()); 6016 } 6017 } 6018 6019 nosnap: 6020 /* 6021 * Create a last-import snapshot to serve as an attachment 6022 * point for the real one from the temporary instance. Since 6023 * the contents is irrelevant, take it now, while the instance 6024 * is empty, to minimize svc.configd's work. 6025 */ 6026 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6027 imp_lisnap) != 0) { 6028 switch (scf_error()) { 6029 case SCF_ERROR_CONNECTION_BROKEN: 6030 goto connaborted; 6031 6032 case SCF_ERROR_NO_RESOURCES: 6033 r = stash_scferror(lcbdata); 6034 goto deltemp; 6035 6036 case SCF_ERROR_EXISTS: 6037 warn(gettext("%s changed unexpectedly " 6038 "(snapshot \"%s\" added).\n"), 6039 inst->sc_fmri, snap_lastimport); 6040 lcbdata->sc_err = EBUSY; 6041 r = UU_WALK_ERROR; 6042 goto deltemp; 6043 6044 case SCF_ERROR_PERMISSION_DENIED: 6045 warn(gettext("Could not take \"%s\" snapshot " 6046 "of %s (permission denied).\n"), 6047 snap_lastimport, inst->sc_fmri); 6048 r = stash_scferror(lcbdata); 6049 goto deltemp; 6050 6051 default: 6052 scfwarn(); 6053 lcbdata->sc_err = -1; 6054 r = UU_WALK_ERROR; 6055 goto deltemp; 6056 6057 case SCF_ERROR_NOT_SET: 6058 case SCF_ERROR_INTERNAL: 6059 case SCF_ERROR_INVALID_ARGUMENT: 6060 case SCF_ERROR_HANDLE_MISMATCH: 6061 bad_error("_scf_snapshot_take_new", 6062 scf_error()); 6063 } 6064 } 6065 6066 if (li_only) 6067 goto lionly; 6068 6069 inst->sc_import_state = IMPORT_PROP_BEGUN; 6070 6071 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6072 flags); 6073 switch (r) { 6074 case 0: 6075 break; 6076 6077 case ECONNABORTED: 6078 goto connaborted; 6079 6080 case ECANCELED: 6081 warn(gettext("%s changed unexpectedly " 6082 "(instance \"%s\" deleted).\n"), 6083 inst->sc_parent->sc_fmri, inst->sc_name); 6084 lcbdata->sc_err = EBUSY; 6085 r = UU_WALK_ERROR; 6086 goto deltemp; 6087 6088 case EEXIST: 6089 warn(gettext("%s changed unexpectedly " 6090 "(property group added).\n"), inst->sc_fmri); 6091 lcbdata->sc_err = EBUSY; 6092 r = UU_WALK_ERROR; 6093 goto deltemp; 6094 6095 default: 6096 lcbdata->sc_err = r; 6097 r = UU_WALK_ERROR; 6098 goto deltemp; 6099 6100 case EINVAL: /* caught above */ 6101 bad_error("lscf_import_instance_pgs", r); 6102 } 6103 6104 ctx.sc_parent = imp_inst; 6105 ctx.sc_service = 0; 6106 ctx.sc_trans = NULL; 6107 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6108 &ctx, UU_DEFAULT) != 0) { 6109 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6110 bad_error("uu_list_walk", uu_error()); 6111 6112 if (ctx.sc_err == ECONNABORTED) 6113 goto connaborted; 6114 lcbdata->sc_err = ctx.sc_err; 6115 r = UU_WALK_ERROR; 6116 goto deltemp; 6117 } 6118 6119 inst->sc_import_state = IMPORT_PROP_DONE; 6120 6121 if (g_verbose) 6122 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6123 snap_initial, inst->sc_fmri); 6124 r = take_snap(imp_inst, snap_initial, imp_snap); 6125 switch (r) { 6126 case 0: 6127 break; 6128 6129 case ECONNABORTED: 6130 goto connaborted; 6131 6132 case ENOSPC: 6133 case -1: 6134 lcbdata->sc_err = r; 6135 r = UU_WALK_ERROR; 6136 goto deltemp; 6137 6138 case ECANCELED: 6139 warn(gettext("%s changed unexpectedly " 6140 "(instance %s deleted).\n"), 6141 inst->sc_parent->sc_fmri, inst->sc_name); 6142 lcbdata->sc_err = r; 6143 r = UU_WALK_ERROR; 6144 goto deltemp; 6145 6146 case EPERM: 6147 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6148 lcbdata->sc_err = r; 6149 r = UU_WALK_ERROR; 6150 goto deltemp; 6151 6152 default: 6153 bad_error("take_snap", r); 6154 } 6155 } 6156 6157 lionly: 6158 if (lcbdata->sc_flags & SCI_NOSNAP) 6159 goto deltemp; 6160 6161 /* transfer snapshot from temporary instance */ 6162 if (g_verbose) 6163 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6164 snap_lastimport, inst->sc_fmri); 6165 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6166 switch (scf_error()) { 6167 case SCF_ERROR_CONNECTION_BROKEN: 6168 goto connaborted; 6169 6170 case SCF_ERROR_NO_RESOURCES: 6171 r = stash_scferror(lcbdata); 6172 goto deltemp; 6173 6174 case SCF_ERROR_PERMISSION_DENIED: 6175 warn(gettext("Could not take \"%s\" snapshot for %s " 6176 "(permission denied).\n"), snap_lastimport, 6177 inst->sc_fmri); 6178 r = stash_scferror(lcbdata); 6179 goto deltemp; 6180 6181 case SCF_ERROR_NOT_SET: 6182 case SCF_ERROR_HANDLE_MISMATCH: 6183 default: 6184 bad_error("_scf_snapshot_attach", scf_error()); 6185 } 6186 } 6187 6188 inst->sc_import_state = IMPORT_COMPLETE; 6189 6190 r = UU_WALK_NEXT; 6191 6192 deltemp: 6193 /* delete temporary instance */ 6194 if (scf_instance_delete(imp_tinst) != 0) { 6195 switch (scf_error()) { 6196 case SCF_ERROR_DELETED: 6197 break; 6198 6199 case SCF_ERROR_CONNECTION_BROKEN: 6200 goto connaborted; 6201 6202 case SCF_ERROR_NOT_SET: 6203 case SCF_ERROR_NOT_BOUND: 6204 default: 6205 bad_error("scf_instance_delete", scf_error()); 6206 } 6207 } 6208 6209 return (r); 6210 6211 connaborted: 6212 warn(gettext("Could not delete svc:/%s:%s " 6213 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6214 lcbdata->sc_err = ECONNABORTED; 6215 return (UU_WALK_ERROR); 6216 } 6217 6218 /* 6219 * If the service is missing, create it, import its properties, and import the 6220 * instances. Since the service is brand new, it should be empty, and if we 6221 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6222 * 6223 * If the service exists, we want to upgrade its properties and import the 6224 * instances. Upgrade requires a last-import snapshot, though, which are 6225 * children of instances, so first we'll have to go through the instances 6226 * looking for a last-import snapshot. If we don't find one then we'll just 6227 * override-import the service properties (but don't delete existing 6228 * properties: another service might have declared us as a dependent). Before 6229 * we change anything, though, we want to take the previous snapshots. We 6230 * also give lscf_instance_import() a leg up on taking last-import snapshots 6231 * by importing the manifest's service properties into a temporary service. 6232 * 6233 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6234 * sets lcbdata->sc_err to 6235 * ECONNABORTED - repository connection broken 6236 * ENOMEM - out of memory 6237 * ENOSPC - svc.configd is out of resources 6238 * EPERM - couldn't create temporary service (error printed) 6239 * - couldn't import into temp service (error printed) 6240 * - couldn't create service (error printed) 6241 * - couldn't import dependent (error printed) 6242 * - couldn't take snapshot (error printed) 6243 * - couldn't create instance (error printed) 6244 * - couldn't create, modify, or delete pg (error printed) 6245 * - couldn't create, modify, or delete dependent (error printed) 6246 * - couldn't import instance (error printed) 6247 * EROFS - couldn't create temporary service (repository read-only) 6248 * - couldn't import into temporary service (repository read-only) 6249 * - couldn't create service (repository read-only) 6250 * - couldn't import dependent (repository read-only) 6251 * - couldn't create instance (repository read-only) 6252 * - couldn't create, modify, or delete pg or dependent 6253 * - couldn't import instance (repository read-only) 6254 * EACCES - couldn't create temporary service (backend access denied) 6255 * - couldn't import into temporary service (backend access denied) 6256 * - couldn't create service (backend access denied) 6257 * - couldn't import dependent (backend access denied) 6258 * - couldn't create instance (backend access denied) 6259 * - couldn't create, modify, or delete pg or dependent 6260 * - couldn't import instance (backend access denied) 6261 * EINVAL - service name is invalid (error printed) 6262 * - service name is too long (error printed) 6263 * - s has invalid pgroup (error printed) 6264 * - s has invalid dependent (error printed) 6265 * - instance name is invalid (error printed) 6266 * - instance entity_t is invalid (error printed) 6267 * EEXIST - couldn't create temporary service (already exists) (error printed) 6268 * - couldn't import dependent (dependency pg already exists) (printed) 6269 * - dependency collision in dependent service (error printed) 6270 * EBUSY - temporary service deleted (error printed) 6271 * - property group added to temporary service (error printed) 6272 * - new property group changed or was deleted (error printed) 6273 * - service was added unexpectedly (error printed) 6274 * - service was deleted unexpectedly (error printed) 6275 * - property group added to new service (error printed) 6276 * - instance added unexpectedly (error printed) 6277 * - instance deleted unexpectedly (error printed) 6278 * - dependent service deleted unexpectedly (error printed) 6279 * - pg was added, changed, or deleted (error printed) 6280 * - dependent pg changed (error printed) 6281 * - temporary instance added, changed, or deleted (error printed) 6282 * EBADF - a last-import snapshot is corrupt (error printed) 6283 * - the service is corrupt (error printed) 6284 * - a dependent is corrupt (error printed) 6285 * - an instance is corrupt (error printed) 6286 * - an instance has a corrupt last-import snapshot (error printed) 6287 * - dependent target has a corrupt snapshot (error printed) 6288 * -1 - unknown libscf error (error printed) 6289 */ 6290 static int 6291 lscf_service_import(void *v, void *pvt) 6292 { 6293 entity_t *s = v; 6294 scf_callback_t cbdata; 6295 scf_callback_t *lcbdata = pvt; 6296 scf_scope_t *scope = lcbdata->sc_parent; 6297 entity_t *inst, linst; 6298 int r; 6299 int fresh = 0; 6300 scf_snaplevel_t *running; 6301 int have_ge = 0; 6302 6303 const char * const ts_deleted = gettext("Temporary service svc:/%s " 6304 "was deleted unexpectedly.\n"); 6305 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 6306 "changed unexpectedly (property group added).\n"); 6307 const char * const s_deleted = 6308 gettext("%s was deleted unexpectedly.\n"); 6309 const char * const i_deleted = 6310 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 6311 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 6312 "is corrupt (missing service snaplevel).\n"); 6313 const char * const s_mfile_upd = 6314 gettext("Unable to update the manifest file connection " 6315 "for %s\n"); 6316 6317 li_only = 0; 6318 /* Validate the service name */ 6319 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6320 switch (scf_error()) { 6321 case SCF_ERROR_CONNECTION_BROKEN: 6322 return (stash_scferror(lcbdata)); 6323 6324 case SCF_ERROR_INVALID_ARGUMENT: 6325 warn(gettext("\"%s\" is an invalid service name. " 6326 "Cannot import.\n"), s->sc_name); 6327 return (stash_scferror(lcbdata)); 6328 6329 case SCF_ERROR_NOT_FOUND: 6330 break; 6331 6332 case SCF_ERROR_HANDLE_MISMATCH: 6333 case SCF_ERROR_NOT_BOUND: 6334 case SCF_ERROR_NOT_SET: 6335 default: 6336 bad_error("scf_scope_get_service", scf_error()); 6337 } 6338 } 6339 6340 /* create temporary service */ 6341 /* 6342 * the size of the buffer was reduced to max_scf_name_len to prevent 6343 * hitting bug 6681151. After the bug fix, the size of the buffer 6344 * should be restored to its original value (max_scf_name_len +1) 6345 */ 6346 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 6347 if (r < 0) 6348 bad_error("snprintf", errno); 6349 if (r > max_scf_name_len) { 6350 warn(gettext( 6351 "Service name \"%s\" is too long. Cannot import.\n"), 6352 s->sc_name); 6353 lcbdata->sc_err = EINVAL; 6354 return (UU_WALK_ERROR); 6355 } 6356 6357 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 6358 switch (scf_error()) { 6359 case SCF_ERROR_CONNECTION_BROKEN: 6360 case SCF_ERROR_NO_RESOURCES: 6361 case SCF_ERROR_BACKEND_READONLY: 6362 case SCF_ERROR_BACKEND_ACCESS: 6363 return (stash_scferror(lcbdata)); 6364 6365 case SCF_ERROR_EXISTS: 6366 warn(gettext( 6367 "Temporary service \"%s\" must be deleted before " 6368 "this manifest can be imported.\n"), imp_tsname); 6369 return (stash_scferror(lcbdata)); 6370 6371 case SCF_ERROR_PERMISSION_DENIED: 6372 warn(gettext("Could not create temporary service " 6373 "\"%s\" (permission denied).\n"), imp_tsname); 6374 return (stash_scferror(lcbdata)); 6375 6376 case SCF_ERROR_INVALID_ARGUMENT: 6377 case SCF_ERROR_HANDLE_MISMATCH: 6378 case SCF_ERROR_NOT_BOUND: 6379 case SCF_ERROR_NOT_SET: 6380 default: 6381 bad_error("scf_scope_add_service", scf_error()); 6382 } 6383 } 6384 6385 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 6386 if (r < 0) 6387 bad_error("snprintf", errno); 6388 6389 cbdata.sc_handle = lcbdata->sc_handle; 6390 cbdata.sc_parent = imp_tsvc; 6391 cbdata.sc_service = 1; 6392 cbdata.sc_source_fmri = s->sc_fmri; 6393 cbdata.sc_target_fmri = imp_str; 6394 cbdata.sc_flags = 0; 6395 6396 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 6397 UU_DEFAULT) != 0) { 6398 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6399 bad_error("uu_list_walk", uu_error()); 6400 6401 lcbdata->sc_err = cbdata.sc_err; 6402 switch (cbdata.sc_err) { 6403 case ECONNABORTED: 6404 goto connaborted; 6405 6406 case ECANCELED: 6407 warn(ts_deleted, imp_tsname); 6408 lcbdata->sc_err = EBUSY; 6409 return (UU_WALK_ERROR); 6410 6411 case EEXIST: 6412 warn(ts_pg_added, imp_tsname); 6413 lcbdata->sc_err = EBUSY; 6414 return (UU_WALK_ERROR); 6415 } 6416 6417 r = UU_WALK_ERROR; 6418 goto deltemp; 6419 } 6420 6421 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 6422 UU_DEFAULT) != 0) { 6423 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6424 bad_error("uu_list_walk", uu_error()); 6425 6426 lcbdata->sc_err = cbdata.sc_err; 6427 switch (cbdata.sc_err) { 6428 case ECONNABORTED: 6429 goto connaborted; 6430 6431 case ECANCELED: 6432 warn(ts_deleted, imp_tsname); 6433 lcbdata->sc_err = EBUSY; 6434 return (UU_WALK_ERROR); 6435 6436 case EEXIST: 6437 warn(ts_pg_added, imp_tsname); 6438 lcbdata->sc_err = EBUSY; 6439 return (UU_WALK_ERROR); 6440 } 6441 6442 r = UU_WALK_ERROR; 6443 goto deltemp; 6444 } 6445 6446 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6447 switch (scf_error()) { 6448 case SCF_ERROR_NOT_FOUND: 6449 break; 6450 6451 case SCF_ERROR_CONNECTION_BROKEN: 6452 goto connaborted; 6453 6454 case SCF_ERROR_INVALID_ARGUMENT: 6455 case SCF_ERROR_HANDLE_MISMATCH: 6456 case SCF_ERROR_NOT_BOUND: 6457 case SCF_ERROR_NOT_SET: 6458 default: 6459 bad_error("scf_scope_get_service", scf_error()); 6460 } 6461 6462 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 6463 switch (scf_error()) { 6464 case SCF_ERROR_CONNECTION_BROKEN: 6465 goto connaborted; 6466 6467 case SCF_ERROR_NO_RESOURCES: 6468 case SCF_ERROR_BACKEND_READONLY: 6469 case SCF_ERROR_BACKEND_ACCESS: 6470 r = stash_scferror(lcbdata); 6471 goto deltemp; 6472 6473 case SCF_ERROR_EXISTS: 6474 warn(gettext("Scope \"%s\" changed unexpectedly" 6475 " (service \"%s\" added).\n"), 6476 SCF_SCOPE_LOCAL, s->sc_name); 6477 lcbdata->sc_err = EBUSY; 6478 goto deltemp; 6479 6480 case SCF_ERROR_PERMISSION_DENIED: 6481 warn(gettext("Could not create service \"%s\" " 6482 "(permission denied).\n"), s->sc_name); 6483 goto deltemp; 6484 6485 case SCF_ERROR_INVALID_ARGUMENT: 6486 case SCF_ERROR_HANDLE_MISMATCH: 6487 case SCF_ERROR_NOT_BOUND: 6488 case SCF_ERROR_NOT_SET: 6489 default: 6490 bad_error("scf_scope_add_service", scf_error()); 6491 } 6492 } 6493 6494 s->sc_import_state = IMPORT_PROP_BEGUN; 6495 6496 /* import service properties */ 6497 cbdata.sc_handle = lcbdata->sc_handle; 6498 cbdata.sc_parent = imp_svc; 6499 cbdata.sc_service = 1; 6500 cbdata.sc_flags = lcbdata->sc_flags; 6501 cbdata.sc_source_fmri = s->sc_fmri; 6502 cbdata.sc_target_fmri = s->sc_fmri; 6503 6504 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6505 &cbdata, UU_DEFAULT) != 0) { 6506 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6507 bad_error("uu_list_walk", uu_error()); 6508 6509 lcbdata->sc_err = cbdata.sc_err; 6510 switch (cbdata.sc_err) { 6511 case ECONNABORTED: 6512 goto connaborted; 6513 6514 case ECANCELED: 6515 warn(s_deleted, s->sc_fmri); 6516 lcbdata->sc_err = EBUSY; 6517 return (UU_WALK_ERROR); 6518 6519 case EEXIST: 6520 warn(gettext("%s changed unexpectedly " 6521 "(property group added).\n"), s->sc_fmri); 6522 lcbdata->sc_err = EBUSY; 6523 return (UU_WALK_ERROR); 6524 6525 case EINVAL: 6526 /* caught above */ 6527 bad_error("entity_pgroup_import", 6528 cbdata.sc_err); 6529 } 6530 6531 r = UU_WALK_ERROR; 6532 goto deltemp; 6533 } 6534 6535 cbdata.sc_trans = NULL; 6536 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 6537 &cbdata, UU_DEFAULT) != 0) { 6538 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6539 bad_error("uu_list_walk", uu_error()); 6540 6541 lcbdata->sc_err = cbdata.sc_err; 6542 if (cbdata.sc_err == ECONNABORTED) 6543 goto connaborted; 6544 r = UU_WALK_ERROR; 6545 goto deltemp; 6546 } 6547 6548 s->sc_import_state = IMPORT_PROP_DONE; 6549 6550 /* 6551 * This is a new service, so we can't take previous snapshots 6552 * or upgrade service properties. 6553 */ 6554 fresh = 1; 6555 goto instances; 6556 } 6557 6558 /* Clear sc_seen for the instances. */ 6559 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 6560 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 6561 bad_error("uu_list_walk", uu_error()); 6562 6563 /* 6564 * Take previous snapshots for all instances. Even for ones not 6565 * mentioned in the bundle, since we might change their service 6566 * properties. 6567 */ 6568 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6569 switch (scf_error()) { 6570 case SCF_ERROR_CONNECTION_BROKEN: 6571 goto connaborted; 6572 6573 case SCF_ERROR_DELETED: 6574 warn(s_deleted, s->sc_fmri); 6575 lcbdata->sc_err = EBUSY; 6576 r = UU_WALK_ERROR; 6577 goto deltemp; 6578 6579 case SCF_ERROR_HANDLE_MISMATCH: 6580 case SCF_ERROR_NOT_BOUND: 6581 case SCF_ERROR_NOT_SET: 6582 default: 6583 bad_error("scf_iter_service_instances", scf_error()); 6584 } 6585 } 6586 6587 for (;;) { 6588 r = scf_iter_next_instance(imp_iter, imp_inst); 6589 if (r == 0) 6590 break; 6591 if (r != 1) { 6592 switch (scf_error()) { 6593 case SCF_ERROR_DELETED: 6594 warn(s_deleted, s->sc_fmri); 6595 lcbdata->sc_err = EBUSY; 6596 r = UU_WALK_ERROR; 6597 goto deltemp; 6598 6599 case SCF_ERROR_CONNECTION_BROKEN: 6600 goto connaborted; 6601 6602 case SCF_ERROR_NOT_BOUND: 6603 case SCF_ERROR_HANDLE_MISMATCH: 6604 case SCF_ERROR_INVALID_ARGUMENT: 6605 case SCF_ERROR_NOT_SET: 6606 default: 6607 bad_error("scf_iter_next_instance", 6608 scf_error()); 6609 } 6610 } 6611 6612 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 6613 switch (scf_error()) { 6614 case SCF_ERROR_DELETED: 6615 continue; 6616 6617 case SCF_ERROR_CONNECTION_BROKEN: 6618 goto connaborted; 6619 6620 case SCF_ERROR_NOT_SET: 6621 case SCF_ERROR_NOT_BOUND: 6622 default: 6623 bad_error("scf_instance_get_name", scf_error()); 6624 } 6625 } 6626 6627 if (g_verbose) 6628 warn(gettext( 6629 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 6630 snap_previous, s->sc_name, imp_str); 6631 6632 r = take_snap(imp_inst, snap_previous, imp_snap); 6633 switch (r) { 6634 case 0: 6635 break; 6636 6637 case ECANCELED: 6638 continue; 6639 6640 case ECONNABORTED: 6641 goto connaborted; 6642 6643 case EPERM: 6644 warn(gettext("Could not take \"%s\" snapshot of " 6645 "svc:/%s:%s (permission denied).\n"), 6646 snap_previous, s->sc_name, imp_str); 6647 lcbdata->sc_err = r; 6648 return (UU_WALK_ERROR); 6649 6650 case ENOSPC: 6651 case -1: 6652 lcbdata->sc_err = r; 6653 r = UU_WALK_ERROR; 6654 goto deltemp; 6655 6656 default: 6657 bad_error("take_snap", r); 6658 } 6659 6660 linst.sc_name = imp_str; 6661 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 6662 &linst, NULL, NULL); 6663 if (inst != NULL) { 6664 inst->sc_import_state = IMPORT_PREVIOUS; 6665 inst->sc_seen = 1; 6666 } 6667 } 6668 6669 /* 6670 * Create the new instances and take previous snapshots of 6671 * them. This is not necessary, but it maximizes data preservation. 6672 */ 6673 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 6674 inst != NULL; 6675 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 6676 inst)) { 6677 if (inst->sc_seen) 6678 continue; 6679 6680 if (scf_service_add_instance(imp_svc, inst->sc_name, 6681 imp_inst) != 0) { 6682 switch (scf_error()) { 6683 case SCF_ERROR_CONNECTION_BROKEN: 6684 goto connaborted; 6685 6686 case SCF_ERROR_BACKEND_READONLY: 6687 case SCF_ERROR_BACKEND_ACCESS: 6688 case SCF_ERROR_NO_RESOURCES: 6689 r = stash_scferror(lcbdata); 6690 goto deltemp; 6691 6692 case SCF_ERROR_EXISTS: 6693 warn(gettext("%s changed unexpectedly " 6694 "(instance \"%s\" added).\n"), s->sc_fmri, 6695 inst->sc_name); 6696 lcbdata->sc_err = EBUSY; 6697 r = UU_WALK_ERROR; 6698 goto deltemp; 6699 6700 case SCF_ERROR_INVALID_ARGUMENT: 6701 warn(gettext("Service \"%s\" has instance with " 6702 "invalid name \"%s\".\n"), s->sc_name, 6703 inst->sc_name); 6704 r = stash_scferror(lcbdata); 6705 goto deltemp; 6706 6707 case SCF_ERROR_PERMISSION_DENIED: 6708 warn(gettext("Could not create instance \"%s\" " 6709 "in %s (permission denied).\n"), 6710 inst->sc_name, s->sc_fmri); 6711 r = stash_scferror(lcbdata); 6712 goto deltemp; 6713 6714 case SCF_ERROR_HANDLE_MISMATCH: 6715 case SCF_ERROR_NOT_BOUND: 6716 case SCF_ERROR_NOT_SET: 6717 default: 6718 bad_error("scf_service_add_instance", 6719 scf_error()); 6720 } 6721 } 6722 6723 if (g_verbose) 6724 warn(gettext("Taking \"%s\" snapshot for " 6725 "new service %s.\n"), snap_previous, inst->sc_fmri); 6726 r = take_snap(imp_inst, snap_previous, imp_snap); 6727 switch (r) { 6728 case 0: 6729 break; 6730 6731 case ECANCELED: 6732 warn(i_deleted, s->sc_fmri, inst->sc_name); 6733 lcbdata->sc_err = EBUSY; 6734 r = UU_WALK_ERROR; 6735 goto deltemp; 6736 6737 case ECONNABORTED: 6738 goto connaborted; 6739 6740 case EPERM: 6741 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 6742 lcbdata->sc_err = r; 6743 r = UU_WALK_ERROR; 6744 goto deltemp; 6745 6746 case ENOSPC: 6747 case -1: 6748 r = UU_WALK_ERROR; 6749 goto deltemp; 6750 6751 default: 6752 bad_error("take_snap", r); 6753 } 6754 } 6755 6756 s->sc_import_state = IMPORT_PREVIOUS; 6757 6758 /* 6759 * Upgrade service properties, if we can find a last-import snapshot. 6760 * Any will do because we don't support different service properties 6761 * in different manifests, so all snaplevels of the service in all of 6762 * the last-import snapshots of the instances should be the same. 6763 */ 6764 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6765 switch (scf_error()) { 6766 case SCF_ERROR_CONNECTION_BROKEN: 6767 goto connaborted; 6768 6769 case SCF_ERROR_DELETED: 6770 warn(s_deleted, s->sc_fmri); 6771 lcbdata->sc_err = EBUSY; 6772 r = UU_WALK_ERROR; 6773 goto deltemp; 6774 6775 case SCF_ERROR_HANDLE_MISMATCH: 6776 case SCF_ERROR_NOT_BOUND: 6777 case SCF_ERROR_NOT_SET: 6778 default: 6779 bad_error("scf_iter_service_instances", scf_error()); 6780 } 6781 } 6782 6783 for (;;) { 6784 r = scf_iter_next_instance(imp_iter, imp_inst); 6785 if (r == -1) { 6786 switch (scf_error()) { 6787 case SCF_ERROR_DELETED: 6788 warn(s_deleted, s->sc_fmri); 6789 lcbdata->sc_err = EBUSY; 6790 r = UU_WALK_ERROR; 6791 goto deltemp; 6792 6793 case SCF_ERROR_CONNECTION_BROKEN: 6794 goto connaborted; 6795 6796 case SCF_ERROR_NOT_BOUND: 6797 case SCF_ERROR_HANDLE_MISMATCH: 6798 case SCF_ERROR_INVALID_ARGUMENT: 6799 case SCF_ERROR_NOT_SET: 6800 default: 6801 bad_error("scf_iter_next_instance", 6802 scf_error()); 6803 } 6804 } 6805 6806 if (r == 0) { 6807 /* 6808 * Didn't find any last-import snapshots. Override- 6809 * import the properties. Unless one of the instances 6810 * has a general/enabled property, in which case we're 6811 * probably running a last-import-capable svccfg for 6812 * the first time, and we should only take the 6813 * last-import snapshot. 6814 */ 6815 if (have_ge) { 6816 pgroup_t *mfpg; 6817 scf_callback_t mfcbdata; 6818 6819 li_only = 1; 6820 no_refresh = 1; 6821 /* 6822 * Need to go ahead and import the manifestfiles 6823 * pg if it exists. If the last-import snapshot 6824 * upgrade code is ever removed this code can 6825 * be removed as well. 6826 */ 6827 mfpg = internal_pgroup_find(s, 6828 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 6829 6830 if (mfpg) { 6831 mfcbdata.sc_handle = g_hndl; 6832 mfcbdata.sc_parent = imp_svc; 6833 mfcbdata.sc_service = 1; 6834 mfcbdata.sc_flags = SCI_FORCE; 6835 mfcbdata.sc_source_fmri = s->sc_fmri; 6836 mfcbdata.sc_target_fmri = s->sc_fmri; 6837 if (entity_pgroup_import(mfpg, 6838 &mfcbdata) != UU_WALK_NEXT) { 6839 warn(s_mfile_upd, s->sc_fmri); 6840 r = UU_WALK_ERROR; 6841 goto deltemp; 6842 } 6843 } 6844 break; 6845 } 6846 6847 s->sc_import_state = IMPORT_PROP_BEGUN; 6848 6849 cbdata.sc_handle = g_hndl; 6850 cbdata.sc_parent = imp_svc; 6851 cbdata.sc_service = 1; 6852 cbdata.sc_flags = SCI_FORCE; 6853 cbdata.sc_source_fmri = s->sc_fmri; 6854 cbdata.sc_target_fmri = s->sc_fmri; 6855 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6856 &cbdata, UU_DEFAULT) != 0) { 6857 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6858 bad_error("uu_list_walk", uu_error()); 6859 lcbdata->sc_err = cbdata.sc_err; 6860 switch (cbdata.sc_err) { 6861 case ECONNABORTED: 6862 goto connaborted; 6863 6864 case ECANCELED: 6865 warn(s_deleted, s->sc_fmri); 6866 lcbdata->sc_err = EBUSY; 6867 break; 6868 6869 case EINVAL: /* caught above */ 6870 case EEXIST: 6871 bad_error("entity_pgroup_import", 6872 cbdata.sc_err); 6873 } 6874 6875 r = UU_WALK_ERROR; 6876 goto deltemp; 6877 } 6878 6879 cbdata.sc_trans = NULL; 6880 if (uu_list_walk(s->sc_dependents, 6881 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 6882 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6883 bad_error("uu_list_walk", uu_error()); 6884 lcbdata->sc_err = cbdata.sc_err; 6885 if (cbdata.sc_err == ECONNABORTED) 6886 goto connaborted; 6887 r = UU_WALK_ERROR; 6888 goto deltemp; 6889 } 6890 break; 6891 } 6892 6893 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6894 imp_snap) != 0) { 6895 switch (scf_error()) { 6896 case SCF_ERROR_DELETED: 6897 continue; 6898 6899 case SCF_ERROR_NOT_FOUND: 6900 break; 6901 6902 case SCF_ERROR_CONNECTION_BROKEN: 6903 goto connaborted; 6904 6905 case SCF_ERROR_HANDLE_MISMATCH: 6906 case SCF_ERROR_NOT_BOUND: 6907 case SCF_ERROR_INVALID_ARGUMENT: 6908 case SCF_ERROR_NOT_SET: 6909 default: 6910 bad_error("scf_instance_get_snapshot", 6911 scf_error()); 6912 } 6913 6914 if (have_ge) 6915 continue; 6916 6917 /* 6918 * Check for a general/enabled property. This is how 6919 * we tell whether to import if there turn out to be 6920 * no last-import snapshots. 6921 */ 6922 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 6923 imp_pg) == 0) { 6924 if (scf_pg_get_property(imp_pg, 6925 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 6926 have_ge = 1; 6927 } else { 6928 switch (scf_error()) { 6929 case SCF_ERROR_DELETED: 6930 case SCF_ERROR_NOT_FOUND: 6931 continue; 6932 6933 case SCF_ERROR_INVALID_ARGUMENT: 6934 case SCF_ERROR_HANDLE_MISMATCH: 6935 case SCF_ERROR_CONNECTION_BROKEN: 6936 case SCF_ERROR_NOT_BOUND: 6937 case SCF_ERROR_NOT_SET: 6938 default: 6939 bad_error("scf_pg_get_property", 6940 scf_error()); 6941 } 6942 } 6943 } else { 6944 switch (scf_error()) { 6945 case SCF_ERROR_DELETED: 6946 case SCF_ERROR_NOT_FOUND: 6947 continue; 6948 6949 case SCF_ERROR_CONNECTION_BROKEN: 6950 goto connaborted; 6951 6952 case SCF_ERROR_NOT_BOUND: 6953 case SCF_ERROR_NOT_SET: 6954 case SCF_ERROR_INVALID_ARGUMENT: 6955 case SCF_ERROR_HANDLE_MISMATCH: 6956 default: 6957 bad_error("scf_instance_get_pg", 6958 scf_error()); 6959 } 6960 } 6961 continue; 6962 } 6963 6964 /* find service snaplevel */ 6965 r = get_snaplevel(imp_snap, 1, imp_snpl); 6966 switch (r) { 6967 case 0: 6968 break; 6969 6970 case ECONNABORTED: 6971 goto connaborted; 6972 6973 case ECANCELED: 6974 continue; 6975 6976 case ENOENT: 6977 if (scf_instance_get_name(imp_inst, imp_str, 6978 imp_str_sz) < 0) 6979 (void) strcpy(imp_str, "?"); 6980 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 6981 lcbdata->sc_err = EBADF; 6982 r = UU_WALK_ERROR; 6983 goto deltemp; 6984 6985 default: 6986 bad_error("get_snaplevel", r); 6987 } 6988 6989 if (scf_instance_get_snapshot(imp_inst, snap_running, 6990 imp_rsnap) != 0) { 6991 switch (scf_error()) { 6992 case SCF_ERROR_DELETED: 6993 continue; 6994 6995 case SCF_ERROR_NOT_FOUND: 6996 break; 6997 6998 case SCF_ERROR_CONNECTION_BROKEN: 6999 goto connaborted; 7000 7001 case SCF_ERROR_INVALID_ARGUMENT: 7002 case SCF_ERROR_HANDLE_MISMATCH: 7003 case SCF_ERROR_NOT_BOUND: 7004 case SCF_ERROR_NOT_SET: 7005 default: 7006 bad_error("scf_instance_get_snapshot", 7007 scf_error()); 7008 } 7009 running = NULL; 7010 } else { 7011 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7012 switch (r) { 7013 case 0: 7014 running = imp_rsnpl; 7015 break; 7016 7017 case ECONNABORTED: 7018 goto connaborted; 7019 7020 case ECANCELED: 7021 continue; 7022 7023 case ENOENT: 7024 if (scf_instance_get_name(imp_inst, imp_str, 7025 imp_str_sz) < 0) 7026 (void) strcpy(imp_str, "?"); 7027 warn(badsnap, snap_running, s->sc_name, 7028 imp_str); 7029 lcbdata->sc_err = EBADF; 7030 r = UU_WALK_ERROR; 7031 goto deltemp; 7032 7033 default: 7034 bad_error("get_snaplevel", r); 7035 } 7036 } 7037 7038 if (g_verbose) { 7039 if (scf_instance_get_name(imp_inst, imp_str, 7040 imp_str_sz) < 0) 7041 (void) strcpy(imp_str, "?"); 7042 warn(gettext("Upgrading properties of %s according to " 7043 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7044 } 7045 7046 /* upgrade service properties */ 7047 r = upgrade_props(imp_svc, running, imp_snpl, s); 7048 if (r == 0) 7049 break; 7050 7051 switch (r) { 7052 case ECONNABORTED: 7053 goto connaborted; 7054 7055 case ECANCELED: 7056 warn(s_deleted, s->sc_fmri); 7057 lcbdata->sc_err = EBUSY; 7058 break; 7059 7060 case ENODEV: 7061 if (scf_instance_get_name(imp_inst, imp_str, 7062 imp_str_sz) < 0) 7063 (void) strcpy(imp_str, "?"); 7064 warn(i_deleted, s->sc_fmri, imp_str); 7065 lcbdata->sc_err = EBUSY; 7066 break; 7067 7068 default: 7069 lcbdata->sc_err = r; 7070 } 7071 7072 r = UU_WALK_ERROR; 7073 goto deltemp; 7074 } 7075 7076 s->sc_import_state = IMPORT_PROP_DONE; 7077 7078 instances: 7079 /* import instances */ 7080 cbdata.sc_handle = lcbdata->sc_handle; 7081 cbdata.sc_parent = imp_svc; 7082 cbdata.sc_service = 1; 7083 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7084 cbdata.sc_general = NULL; 7085 7086 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7087 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7088 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7089 bad_error("uu_list_walk", uu_error()); 7090 7091 lcbdata->sc_err = cbdata.sc_err; 7092 if (cbdata.sc_err == ECONNABORTED) 7093 goto connaborted; 7094 r = UU_WALK_ERROR; 7095 goto deltemp; 7096 } 7097 7098 s->sc_import_state = IMPORT_COMPLETE; 7099 r = UU_WALK_NEXT; 7100 7101 deltemp: 7102 /* delete temporary service */ 7103 if (scf_service_delete(imp_tsvc) != 0) { 7104 switch (scf_error()) { 7105 case SCF_ERROR_DELETED: 7106 break; 7107 7108 case SCF_ERROR_CONNECTION_BROKEN: 7109 goto connaborted; 7110 7111 case SCF_ERROR_EXISTS: 7112 warn(gettext( 7113 "Could not delete svc:/%s (instances exist).\n"), 7114 imp_tsname); 7115 break; 7116 7117 case SCF_ERROR_NOT_SET: 7118 case SCF_ERROR_NOT_BOUND: 7119 default: 7120 bad_error("scf_service_delete", scf_error()); 7121 } 7122 } 7123 7124 return (r); 7125 7126 connaborted: 7127 warn(gettext("Could not delete svc:/%s " 7128 "(repository connection broken).\n"), imp_tsname); 7129 lcbdata->sc_err = ECONNABORTED; 7130 return (UU_WALK_ERROR); 7131 } 7132 7133 static const char * 7134 import_progress(int st) 7135 { 7136 switch (st) { 7137 case 0: 7138 return (gettext("not reached.")); 7139 7140 case IMPORT_PREVIOUS: 7141 return (gettext("previous snapshot taken.")); 7142 7143 case IMPORT_PROP_BEGUN: 7144 return (gettext("some properties imported.")); 7145 7146 case IMPORT_PROP_DONE: 7147 return (gettext("properties imported.")); 7148 7149 case IMPORT_COMPLETE: 7150 return (gettext("imported.")); 7151 7152 case IMPORT_REFRESHED: 7153 return (gettext("refresh requested.")); 7154 7155 default: 7156 #ifndef NDEBUG 7157 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7158 __FILE__, __LINE__, st); 7159 #endif 7160 abort(); 7161 /* NOTREACHED */ 7162 } 7163 } 7164 7165 /* 7166 * Returns 7167 * 0 - success 7168 * - fmri wasn't found (error printed) 7169 * - entity was deleted (error printed) 7170 * - backend denied access (error printed) 7171 * ENOMEM - out of memory (error printed) 7172 * ECONNABORTED - repository connection broken (error printed) 7173 * EPERM - permission denied (error printed) 7174 * -1 - unknown libscf error (error printed) 7175 */ 7176 static int 7177 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7178 { 7179 scf_error_t serr; 7180 void *ent; 7181 int issvc; 7182 int r; 7183 7184 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7185 const char *dpt_deleted = gettext("Could not refresh %s " 7186 "(dependent \"%s\" of %s) (deleted).\n"); 7187 7188 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7189 switch (serr) { 7190 case SCF_ERROR_NONE: 7191 break; 7192 7193 case SCF_ERROR_NO_MEMORY: 7194 if (name == NULL) 7195 warn(gettext("Could not refresh %s (out of memory).\n"), 7196 fmri); 7197 else 7198 warn(gettext("Could not refresh %s " 7199 "(dependent \"%s\" of %s) (out of memory).\n"), 7200 fmri, name, d_fmri); 7201 return (ENOMEM); 7202 7203 case SCF_ERROR_NOT_FOUND: 7204 if (name == NULL) 7205 warn(deleted, fmri); 7206 else 7207 warn(dpt_deleted, fmri, name, d_fmri); 7208 return (0); 7209 7210 case SCF_ERROR_INVALID_ARGUMENT: 7211 case SCF_ERROR_CONSTRAINT_VIOLATED: 7212 default: 7213 bad_error("fmri_to_entity", serr); 7214 } 7215 7216 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7217 switch (r) { 7218 case 0: 7219 break; 7220 7221 case ECONNABORTED: 7222 if (name != NULL) 7223 warn(gettext("Could not refresh %s " 7224 "(dependent \"%s\" of %s) " 7225 "(repository connection broken).\n"), fmri, name, 7226 d_fmri); 7227 return (r); 7228 7229 case ECANCELED: 7230 if (name == NULL) 7231 warn(deleted, fmri); 7232 else 7233 warn(dpt_deleted, fmri, name, d_fmri); 7234 return (0); 7235 7236 case EACCES: 7237 if (!g_verbose) 7238 return (0); 7239 if (name == NULL) 7240 warn(gettext("Could not refresh %s " 7241 "(backend access denied).\n"), fmri); 7242 else 7243 warn(gettext("Could not refresh %s " 7244 "(dependent \"%s\" of %s) " 7245 "(backend access denied).\n"), fmri, name, d_fmri); 7246 return (0); 7247 7248 case EPERM: 7249 if (name == NULL) 7250 warn(gettext("Could not refresh %s " 7251 "(permission denied).\n"), fmri); 7252 else 7253 warn(gettext("Could not refresh %s " 7254 "(dependent \"%s\" of %s) " 7255 "(permission denied).\n"), fmri, name, d_fmri); 7256 return (r); 7257 7258 case ENOSPC: 7259 if (name == NULL) 7260 warn(gettext("Could not refresh %s " 7261 "(repository server out of resources).\n"), 7262 fmri); 7263 else 7264 warn(gettext("Could not refresh %s " 7265 "(dependent \"%s\" of %s) " 7266 "(repository server out of resources).\n"), 7267 fmri, name, d_fmri); 7268 return (r); 7269 7270 case -1: 7271 scfwarn(); 7272 return (r); 7273 7274 default: 7275 bad_error("refresh_entity", r); 7276 } 7277 7278 if (issvc) 7279 scf_service_destroy(ent); 7280 else 7281 scf_instance_destroy(ent); 7282 7283 return (0); 7284 } 7285 7286 int 7287 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 7288 { 7289 scf_callback_t cbdata; 7290 int result = 0; 7291 entity_t *svc, *inst; 7292 uu_list_t *insts; 7293 int r; 7294 pgroup_t *old_dpt; 7295 void *cookie; 7296 int annotation_set = 0; 7297 7298 const char * const emsg_nomem = gettext("Out of memory.\n"); 7299 const char * const emsg_nores = 7300 gettext("svc.configd is out of resources.\n"); 7301 7302 lscf_prep_hndl(); 7303 7304 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 7305 max_scf_name_len : max_scf_fmri_len) + 1; 7306 7307 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 7308 (imp_svc = scf_service_create(g_hndl)) == NULL || 7309 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 7310 (imp_inst = scf_instance_create(g_hndl)) == NULL || 7311 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 7312 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 7313 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 7314 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 7315 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 7316 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7317 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 7318 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7319 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 7320 (imp_prop = scf_property_create(g_hndl)) == NULL || 7321 (imp_iter = scf_iter_create(g_hndl)) == NULL || 7322 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 7323 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 7324 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 7325 (imp_str = malloc(imp_str_sz)) == NULL || 7326 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 7327 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 7328 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 7329 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 7330 (ud_inst = scf_instance_create(g_hndl)) == NULL || 7331 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7332 (ud_pg = scf_pg_create(g_hndl)) == NULL || 7333 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 7334 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 7335 (ud_prop = scf_property_create(g_hndl)) == NULL || 7336 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 7337 (ud_val = scf_value_create(g_hndl)) == NULL || 7338 (ud_iter = scf_iter_create(g_hndl)) == NULL || 7339 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 7340 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 7341 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 7342 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 7343 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 7344 if (scf_error() == SCF_ERROR_NO_RESOURCES) 7345 warn(emsg_nores); 7346 else 7347 warn(emsg_nomem); 7348 result = -1; 7349 goto out; 7350 } 7351 7352 r = load_init(); 7353 switch (r) { 7354 case 0: 7355 break; 7356 7357 case ENOMEM: 7358 warn(emsg_nomem); 7359 result = -1; 7360 goto out; 7361 7362 default: 7363 bad_error("load_init", r); 7364 } 7365 7366 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 7367 switch (scf_error()) { 7368 case SCF_ERROR_CONNECTION_BROKEN: 7369 warn(gettext("Repository connection broken.\n")); 7370 repository_teardown(); 7371 result = -1; 7372 goto out; 7373 7374 case SCF_ERROR_NOT_FOUND: 7375 case SCF_ERROR_INVALID_ARGUMENT: 7376 case SCF_ERROR_NOT_BOUND: 7377 case SCF_ERROR_HANDLE_MISMATCH: 7378 default: 7379 bad_error("scf_handle_get_scope", scf_error()); 7380 } 7381 } 7382 7383 /* Set up the auditing annotation. */ 7384 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 7385 annotation_set = 1; 7386 } else { 7387 switch (scf_error()) { 7388 case SCF_ERROR_CONNECTION_BROKEN: 7389 warn(gettext("Repository connection broken.\n")); 7390 repository_teardown(); 7391 result = -1; 7392 goto out; 7393 7394 case SCF_ERROR_INVALID_ARGUMENT: 7395 case SCF_ERROR_NOT_BOUND: 7396 case SCF_ERROR_NO_RESOURCES: 7397 case SCF_ERROR_INTERNAL: 7398 bad_error("_scf_set_annotation", scf_error()); 7399 /* NOTREACHED */ 7400 7401 default: 7402 /* 7403 * Do not terminate import because of inability to 7404 * generate annotation audit event. 7405 */ 7406 warn(gettext("_scf_set_annotation() unexpectedly " 7407 "failed with return code of %d\n"), scf_error()); 7408 break; 7409 } 7410 } 7411 7412 /* 7413 * Clear the sc_import_state's of all services & instances so we can 7414 * report how far we got if we fail. 7415 */ 7416 for (svc = uu_list_first(bndl->sc_bundle_services); 7417 svc != NULL; 7418 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7419 svc->sc_import_state = 0; 7420 7421 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 7422 clear_int, (void *)offsetof(entity_t, sc_import_state), 7423 UU_DEFAULT) != 0) 7424 bad_error("uu_list_walk", uu_error()); 7425 } 7426 7427 cbdata.sc_handle = g_hndl; 7428 cbdata.sc_parent = imp_scope; 7429 cbdata.sc_flags = flags; 7430 cbdata.sc_general = NULL; 7431 7432 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 7433 &cbdata, UU_DEFAULT) == 0) { 7434 /* Success. Refresh everything. */ 7435 7436 if (flags & SCI_NOREFRESH || no_refresh) { 7437 no_refresh = 0; 7438 result = 0; 7439 goto out; 7440 } 7441 7442 for (svc = uu_list_first(bndl->sc_bundle_services); 7443 svc != NULL; 7444 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7445 pgroup_t *dpt; 7446 7447 insts = svc->sc_u.sc_service.sc_service_instances; 7448 7449 for (inst = uu_list_first(insts); 7450 inst != NULL; 7451 inst = uu_list_next(insts, inst)) { 7452 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 7453 switch (r) { 7454 case 0: 7455 break; 7456 7457 case ENOMEM: 7458 case ECONNABORTED: 7459 case EPERM: 7460 case -1: 7461 goto progress; 7462 7463 default: 7464 bad_error("imp_refresh_fmri", r); 7465 } 7466 7467 inst->sc_import_state = IMPORT_REFRESHED; 7468 7469 for (dpt = uu_list_first(inst->sc_dependents); 7470 dpt != NULL; 7471 dpt = uu_list_next(inst->sc_dependents, 7472 dpt)) 7473 if (imp_refresh_fmri( 7474 dpt->sc_pgroup_fmri, 7475 dpt->sc_pgroup_name, 7476 inst->sc_fmri) != 0) 7477 goto progress; 7478 } 7479 7480 for (dpt = uu_list_first(svc->sc_dependents); 7481 dpt != NULL; 7482 dpt = uu_list_next(svc->sc_dependents, dpt)) 7483 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 7484 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 7485 goto progress; 7486 } 7487 7488 for (old_dpt = uu_list_first(imp_deleted_dpts); 7489 old_dpt != NULL; 7490 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 7491 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 7492 old_dpt->sc_pgroup_name, 7493 old_dpt->sc_parent->sc_fmri) != 0) 7494 goto progress; 7495 7496 result = 0; 7497 goto out; 7498 } 7499 7500 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7501 bad_error("uu_list_walk", uu_error()); 7502 7503 printerr: 7504 /* If the error hasn't been printed yet, do so here. */ 7505 switch (cbdata.sc_err) { 7506 case ECONNABORTED: 7507 warn(gettext("Repository connection broken.\n")); 7508 break; 7509 7510 case ENOMEM: 7511 warn(emsg_nomem); 7512 break; 7513 7514 case ENOSPC: 7515 warn(emsg_nores); 7516 break; 7517 7518 case EROFS: 7519 warn(gettext("Repository is read-only.\n")); 7520 break; 7521 7522 case EACCES: 7523 warn(gettext("Repository backend denied access.\n")); 7524 break; 7525 7526 case EPERM: 7527 case EINVAL: 7528 case EEXIST: 7529 case EBUSY: 7530 case EBADF: 7531 case -1: 7532 break; 7533 7534 default: 7535 bad_error("lscf_service_import", cbdata.sc_err); 7536 } 7537 7538 progress: 7539 warn(gettext("Import of %s failed. Progress:\n"), filename); 7540 7541 for (svc = uu_list_first(bndl->sc_bundle_services); 7542 svc != NULL; 7543 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7544 insts = svc->sc_u.sc_service.sc_service_instances; 7545 7546 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 7547 import_progress(svc->sc_import_state)); 7548 7549 for (inst = uu_list_first(insts); 7550 inst != NULL; 7551 inst = uu_list_next(insts, inst)) 7552 warn(gettext(" Instance \"%s\": %s\n"), 7553 inst->sc_name, 7554 import_progress(inst->sc_import_state)); 7555 } 7556 7557 if (cbdata.sc_err == ECONNABORTED) 7558 repository_teardown(); 7559 7560 7561 result = -1; 7562 7563 out: 7564 if (annotation_set != 0) { 7565 /* Turn off annotation. It is no longer needed. */ 7566 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7567 } 7568 load_fini(); 7569 7570 free(ud_ctarg); 7571 free(ud_oldtarg); 7572 free(ud_name); 7573 ud_ctarg = ud_oldtarg = ud_name = NULL; 7574 7575 scf_transaction_destroy(ud_tx); 7576 ud_tx = NULL; 7577 scf_iter_destroy(ud_iter); 7578 scf_iter_destroy(ud_iter2); 7579 ud_iter = ud_iter2 = NULL; 7580 scf_value_destroy(ud_val); 7581 ud_val = NULL; 7582 scf_property_destroy(ud_prop); 7583 scf_property_destroy(ud_dpt_prop); 7584 ud_prop = ud_dpt_prop = NULL; 7585 scf_pg_destroy(ud_pg); 7586 scf_pg_destroy(ud_cur_depts_pg); 7587 scf_pg_destroy(ud_run_dpts_pg); 7588 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7589 scf_snaplevel_destroy(ud_snpl); 7590 ud_snpl = NULL; 7591 scf_instance_destroy(ud_inst); 7592 ud_inst = NULL; 7593 7594 free(imp_str); 7595 free(imp_tsname); 7596 free(imp_fe1); 7597 free(imp_fe2); 7598 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7599 7600 cookie = NULL; 7601 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7602 NULL) { 7603 free((char *)old_dpt->sc_pgroup_name); 7604 free((char *)old_dpt->sc_pgroup_fmri); 7605 internal_pgroup_free(old_dpt); 7606 } 7607 uu_list_destroy(imp_deleted_dpts); 7608 7609 scf_transaction_destroy(imp_tx); 7610 imp_tx = NULL; 7611 scf_iter_destroy(imp_iter); 7612 scf_iter_destroy(imp_rpg_iter); 7613 scf_iter_destroy(imp_up_iter); 7614 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7615 scf_property_destroy(imp_prop); 7616 imp_prop = NULL; 7617 scf_pg_destroy(imp_pg); 7618 scf_pg_destroy(imp_pg2); 7619 imp_pg = imp_pg2 = NULL; 7620 scf_snaplevel_destroy(imp_snpl); 7621 scf_snaplevel_destroy(imp_rsnpl); 7622 imp_snpl = imp_rsnpl = NULL; 7623 scf_snapshot_destroy(imp_snap); 7624 scf_snapshot_destroy(imp_lisnap); 7625 scf_snapshot_destroy(imp_tlisnap); 7626 scf_snapshot_destroy(imp_rsnap); 7627 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7628 scf_instance_destroy(imp_inst); 7629 scf_instance_destroy(imp_tinst); 7630 imp_inst = imp_tinst = NULL; 7631 scf_service_destroy(imp_svc); 7632 scf_service_destroy(imp_tsvc); 7633 imp_svc = imp_tsvc = NULL; 7634 scf_scope_destroy(imp_scope); 7635 imp_scope = NULL; 7636 7637 return (result); 7638 } 7639 7640 /* 7641 * _lscf_import_err() summarize the error handling returned by 7642 * lscf_import_{instance | service}_pgs 7643 * Return values are: 7644 * IMPORT_NEXT 7645 * IMPORT_OUT 7646 * IMPORT_BAD 7647 */ 7648 7649 #define IMPORT_BAD -1 7650 #define IMPORT_NEXT 0 7651 #define IMPORT_OUT 1 7652 7653 static int 7654 _lscf_import_err(int err, const char *fmri) 7655 { 7656 switch (err) { 7657 case 0: 7658 if (g_verbose) 7659 warn(gettext("%s updated.\n"), fmri); 7660 return (IMPORT_NEXT); 7661 7662 case ECONNABORTED: 7663 warn(gettext("Could not update %s " 7664 "(repository connection broken).\n"), fmri); 7665 return (IMPORT_OUT); 7666 7667 case ENOMEM: 7668 warn(gettext("Could not update %s (out of memory).\n"), fmri); 7669 return (IMPORT_OUT); 7670 7671 case ENOSPC: 7672 warn(gettext("Could not update %s " 7673 "(repository server out of resources).\n"), fmri); 7674 return (IMPORT_OUT); 7675 7676 case ECANCELED: 7677 warn(gettext( 7678 "Could not update %s (deleted).\n"), fmri); 7679 return (IMPORT_NEXT); 7680 7681 case EPERM: 7682 case EINVAL: 7683 case EBUSY: 7684 return (IMPORT_NEXT); 7685 7686 case EROFS: 7687 warn(gettext("Could not update %s (repository read-only).\n"), 7688 fmri); 7689 return (IMPORT_OUT); 7690 7691 case EACCES: 7692 warn(gettext("Could not update %s " 7693 "(backend access denied).\n"), fmri); 7694 return (IMPORT_NEXT); 7695 7696 case EEXIST: 7697 default: 7698 return (IMPORT_BAD); 7699 } 7700 7701 /*NOTREACHED*/ 7702 } 7703 7704 /* 7705 * Returns 7706 * 0 - success 7707 * -1 - lscf_import_instance_pgs() failed. 7708 */ 7709 int 7710 lscf_bundle_apply(bundle_t *bndl, const char *file) 7711 { 7712 entity_t *svc, *inst; 7713 scf_scope_t *rscope; 7714 scf_service_t *rsvc; 7715 scf_instance_t *rinst; 7716 scf_snapshot_t *rsnap; 7717 scf_iter_t *iter; 7718 int annotation_set = 0; 7719 int r; 7720 7721 lscf_prep_hndl(); 7722 7723 if ((rscope = scf_scope_create(g_hndl)) == NULL || 7724 (rsvc = scf_service_create(g_hndl)) == NULL || 7725 (rinst = scf_instance_create(g_hndl)) == NULL || 7726 (rsnap = scf_snapshot_create(g_hndl)) == NULL || 7727 (iter = scf_iter_create(g_hndl)) == NULL || 7728 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7729 (imp_prop = scf_property_create(g_hndl)) == NULL || 7730 (imp_tx = scf_transaction_create(g_hndl)) == NULL) 7731 scfdie(); 7732 7733 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0) 7734 scfdie(); 7735 7736 /* 7737 * Set the strings to be used for the security audit annotation 7738 * event. 7739 */ 7740 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 7741 annotation_set = 1; 7742 } else { 7743 switch (scf_error()) { 7744 case SCF_ERROR_CONNECTION_BROKEN: 7745 warn(gettext("Repository connection broken.\n")); 7746 goto out; 7747 7748 case SCF_ERROR_INVALID_ARGUMENT: 7749 case SCF_ERROR_NOT_BOUND: 7750 case SCF_ERROR_NO_RESOURCES: 7751 case SCF_ERROR_INTERNAL: 7752 bad_error("_scf_set_annotation", scf_error()); 7753 /* NOTREACHED */ 7754 7755 default: 7756 /* 7757 * Do not abort apply operation because of 7758 * inability to create annotation audit event. 7759 */ 7760 warn(gettext("_scf_set_annotation() unexpectedly " 7761 "failed with return code of %d\n"), scf_error()); 7762 break; 7763 } 7764 } 7765 7766 for (svc = uu_list_first(bndl->sc_bundle_services); 7767 svc != NULL; 7768 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7769 int refresh = 0; 7770 7771 if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) { 7772 switch (scf_error()) { 7773 case SCF_ERROR_NOT_FOUND: 7774 if (g_verbose) 7775 warn(gettext("Ignoring nonexistent " 7776 "service %s.\n"), svc->sc_name); 7777 continue; 7778 7779 default: 7780 scfdie(); 7781 } 7782 } 7783 7784 /* 7785 * if we have pgs in the profile, we need to refresh ALL 7786 * instances of the service 7787 */ 7788 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 7789 refresh = 1; 7790 r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc, 7791 SCI_FORCE | SCI_KEEP); 7792 switch (_lscf_import_err(r, svc->sc_fmri)) { 7793 case IMPORT_NEXT: 7794 break; 7795 7796 case IMPORT_OUT: 7797 goto out; 7798 7799 case IMPORT_BAD: 7800 default: 7801 bad_error("lscf_import_service_pgs", r); 7802 } 7803 } 7804 7805 for (inst = uu_list_first( 7806 svc->sc_u.sc_service.sc_service_instances); 7807 inst != NULL; 7808 inst = uu_list_next( 7809 svc->sc_u.sc_service.sc_service_instances, inst)) { 7810 if (scf_service_get_instance(rsvc, inst->sc_name, 7811 rinst) != 0) { 7812 switch (scf_error()) { 7813 case SCF_ERROR_NOT_FOUND: 7814 if (g_verbose) 7815 warn(gettext("Ignoring " 7816 "nonexistant instance " 7817 "%s:%s.\n"), 7818 inst->sc_parent->sc_name, 7819 inst->sc_name); 7820 continue; 7821 7822 default: 7823 scfdie(); 7824 } 7825 } 7826 7827 /* 7828 * If the instance does not have a general/enabled 7829 * property and no last-import snapshot then the 7830 * instance is not a fully installed instance and 7831 * should not have a profile applied to it. 7832 * 7833 * This could happen if a service/instance declares 7834 * a dependent on behalf of another service/instance. 7835 */ 7836 if (scf_instance_get_snapshot(rinst, snap_lastimport, 7837 rsnap) != 0) { 7838 if (scf_instance_get_pg(rinst, SCF_PG_GENERAL, 7839 imp_pg) != 0 || scf_pg_get_property(imp_pg, 7840 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 7841 if (g_verbose) 7842 warn(gettext("Ignoreing " 7843 "partial instance " 7844 "%s:%s.\n"), 7845 inst->sc_parent->sc_name, 7846 inst->sc_name); 7847 continue; 7848 } 7849 } 7850 7851 r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst, 7852 SCI_FORCE | SCI_KEEP); 7853 switch (_lscf_import_err(r, inst->sc_fmri)) { 7854 case IMPORT_NEXT: 7855 break; 7856 7857 case IMPORT_OUT: 7858 goto out; 7859 7860 case IMPORT_BAD: 7861 default: 7862 bad_error("lscf_import_instance_pgs", r); 7863 } 7864 7865 /* refresh only if there is no pgs in the service */ 7866 if (refresh == 0) 7867 (void) refresh_entity(0, rinst, inst->sc_fmri, 7868 NULL, NULL, NULL); 7869 } 7870 7871 if (refresh == 1) { 7872 char *name_buf = safe_malloc(max_scf_name_len + 1); 7873 7874 (void) refresh_entity(1, rsvc, svc->sc_name, rinst, 7875 iter, name_buf); 7876 free(name_buf); 7877 } 7878 } 7879 7880 out: 7881 if (annotation_set) { 7882 /* Remove security audit annotation strings. */ 7883 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7884 } 7885 7886 scf_transaction_destroy(imp_tx); 7887 imp_tx = NULL; 7888 scf_pg_destroy(imp_pg); 7889 imp_pg = NULL; 7890 scf_property_destroy(imp_prop); 7891 imp_prop = NULL; 7892 7893 scf_snapshot_destroy(rsnap); 7894 scf_iter_destroy(iter); 7895 scf_instance_destroy(rinst); 7896 scf_service_destroy(rsvc); 7897 scf_scope_destroy(rscope); 7898 return (0); 7899 } 7900 7901 7902 /* 7903 * Export. These functions create and output an XML tree of a service 7904 * description from the repository. This is largely the inverse of 7905 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 7906 * 7907 * - We must include any properties which are not represented specifically by 7908 * a service manifest, e.g., properties created by an admin post-import. To 7909 * do so we'll iterate through all properties and deal with each 7910 * apropriately. 7911 * 7912 * - Children of services and instances must must be in the order set by the 7913 * DTD, but we iterate over the properties in undefined order. The elements 7914 * are not easily (or efficiently) sortable by name. Since there's a fixed 7915 * number of classes of them, however, we'll keep the classes separate and 7916 * assemble them in order. 7917 */ 7918 7919 /* 7920 * Convenience function to handle xmlSetProp errors (and type casting). 7921 */ 7922 static void 7923 safe_setprop(xmlNodePtr n, const char *name, const char *val) 7924 { 7925 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 7926 uu_die(gettext("Could not set XML property.\n")); 7927 } 7928 7929 /* 7930 * Convenience function to set an XML attribute to the single value of an 7931 * astring property. If the value happens to be the default, don't set the 7932 * attribute. "dval" should be the default value supplied by the DTD, or 7933 * NULL for no default. 7934 */ 7935 static int 7936 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 7937 const char *name, const char *dval) 7938 { 7939 scf_value_t *val; 7940 ssize_t len; 7941 char *str; 7942 7943 val = scf_value_create(g_hndl); 7944 if (val == NULL) 7945 scfdie(); 7946 7947 if (prop_get_val(prop, val) != 0) { 7948 scf_value_destroy(val); 7949 return (-1); 7950 } 7951 7952 len = scf_value_get_as_string(val, NULL, 0); 7953 if (len < 0) 7954 scfdie(); 7955 7956 str = safe_malloc(len + 1); 7957 7958 if (scf_value_get_as_string(val, str, len + 1) < 0) 7959 scfdie(); 7960 7961 scf_value_destroy(val); 7962 7963 if (dval == NULL || strcmp(str, dval) != 0) 7964 safe_setprop(n, name, str); 7965 7966 free(str); 7967 7968 return (0); 7969 } 7970 7971 /* 7972 * As above, but the attribute is always set. 7973 */ 7974 static int 7975 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 7976 { 7977 return (set_attr_from_prop_default(prop, n, name, NULL)); 7978 } 7979 7980 /* 7981 * Dump the given document onto f, with "'s replaced by ''s. 7982 */ 7983 static int 7984 write_service_bundle(xmlDocPtr doc, FILE *f) 7985 { 7986 xmlChar *mem; 7987 int sz, i; 7988 7989 mem = NULL; 7990 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 7991 7992 if (mem == NULL) { 7993 semerr(gettext("Could not dump XML tree.\n")); 7994 return (-1); 7995 } 7996 7997 /* 7998 * Fortunately libxml produces " instead of ", so we can blindly 7999 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 8000 * ' code?! 8001 */ 8002 for (i = 0; i < sz; ++i) { 8003 char c = (char)mem[i]; 8004 8005 if (c == '"') 8006 (void) fputc('\'', f); 8007 else if (c == '\'') 8008 (void) fwrite("'", sizeof ("'") - 1, 1, f); 8009 else 8010 (void) fputc(c, f); 8011 } 8012 8013 return (0); 8014 } 8015 8016 /* 8017 * Create the DOM elements in elts necessary to (generically) represent prop 8018 * (i.e., a property or propval element). If the name of the property is 8019 * known, it should be passed as name_arg. Otherwise, pass NULL. 8020 */ 8021 static void 8022 export_property(scf_property_t *prop, const char *name_arg, 8023 struct pg_elts *elts, int flags) 8024 { 8025 const char *type; 8026 scf_error_t err = 0; 8027 xmlNodePtr pnode, lnode; 8028 char *lnname; 8029 int ret; 8030 8031 /* name */ 8032 if (name_arg != NULL) { 8033 (void) strcpy(exp_str, name_arg); 8034 } else { 8035 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 8036 scfdie(); 8037 } 8038 8039 /* type */ 8040 type = prop_to_typestr(prop); 8041 if (type == NULL) 8042 uu_die(gettext("Can't export property %s: unknown type.\n"), 8043 exp_str); 8044 8045 /* If we're exporting values, and there's just one, export it here. */ 8046 if (!(flags & SCE_ALL_VALUES)) 8047 goto empty; 8048 8049 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 8050 xmlNodePtr n; 8051 8052 /* Single value, so use propval */ 8053 n = xmlNewNode(NULL, (xmlChar *)"propval"); 8054 if (n == NULL) 8055 uu_die(emsg_create_xml); 8056 8057 safe_setprop(n, name_attr, exp_str); 8058 safe_setprop(n, type_attr, type); 8059 8060 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8061 scfdie(); 8062 safe_setprop(n, value_attr, exp_str); 8063 8064 if (elts->propvals == NULL) 8065 elts->propvals = n; 8066 else 8067 (void) xmlAddSibling(elts->propvals, n); 8068 8069 return; 8070 } 8071 8072 err = scf_error(); 8073 8074 if (err == SCF_ERROR_PERMISSION_DENIED) { 8075 semerr(emsg_permission_denied); 8076 return; 8077 } 8078 8079 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 8080 err != SCF_ERROR_NOT_FOUND && 8081 err != SCF_ERROR_PERMISSION_DENIED) 8082 scfdie(); 8083 8084 empty: 8085 /* Multiple (or no) values, so use property */ 8086 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 8087 if (pnode == NULL) 8088 uu_die(emsg_create_xml); 8089 8090 safe_setprop(pnode, name_attr, exp_str); 8091 safe_setprop(pnode, type_attr, type); 8092 8093 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 8094 lnname = uu_msprintf("%s_list", type); 8095 if (lnname == NULL) 8096 uu_die(gettext("Could not create string")); 8097 8098 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 8099 if (lnode == NULL) 8100 uu_die(emsg_create_xml); 8101 8102 uu_free(lnname); 8103 8104 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 8105 scfdie(); 8106 8107 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 8108 1) { 8109 xmlNodePtr vn; 8110 8111 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 8112 NULL); 8113 if (vn == NULL) 8114 uu_die(emsg_create_xml); 8115 8116 if (scf_value_get_as_string(exp_val, exp_str, 8117 exp_str_sz) < 0) 8118 scfdie(); 8119 safe_setprop(vn, value_attr, exp_str); 8120 } 8121 if (ret != 0) 8122 scfdie(); 8123 } 8124 8125 if (elts->properties == NULL) 8126 elts->properties = pnode; 8127 else 8128 (void) xmlAddSibling(elts->properties, pnode); 8129 } 8130 8131 /* 8132 * Add a property_group element for this property group to elts. 8133 */ 8134 static void 8135 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 8136 { 8137 xmlNodePtr n; 8138 struct pg_elts elts; 8139 int ret; 8140 boolean_t read_protected; 8141 8142 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 8143 8144 /* name */ 8145 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8146 scfdie(); 8147 safe_setprop(n, name_attr, exp_str); 8148 8149 /* type */ 8150 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 8151 scfdie(); 8152 safe_setprop(n, type_attr, exp_str); 8153 8154 /* properties */ 8155 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8156 scfdie(); 8157 8158 (void) memset(&elts, 0, sizeof (elts)); 8159 8160 /* 8161 * If this property group is not read protected, we always want to 8162 * output all the values. Otherwise, we only output the values if the 8163 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 8164 */ 8165 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 8166 scfdie(); 8167 8168 if (!read_protected) 8169 flags |= SCE_ALL_VALUES; 8170 8171 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8172 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8173 scfdie(); 8174 8175 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8176 xmlNodePtr m; 8177 8178 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8179 if (m == NULL) 8180 uu_die(emsg_create_xml); 8181 8182 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8183 elts.stability = m; 8184 continue; 8185 } 8186 8187 xmlFreeNode(m); 8188 } 8189 8190 export_property(exp_prop, NULL, &elts, flags); 8191 } 8192 if (ret == -1) 8193 scfdie(); 8194 8195 (void) xmlAddChild(n, elts.stability); 8196 (void) xmlAddChildList(n, elts.propvals); 8197 (void) xmlAddChildList(n, elts.properties); 8198 8199 if (eelts->property_groups == NULL) 8200 eelts->property_groups = n; 8201 else 8202 (void) xmlAddSibling(eelts->property_groups, n); 8203 } 8204 8205 /* 8206 * Create an XML node representing the dependency described by the given 8207 * property group and put it in eelts. Unless the dependency is not valid, in 8208 * which case create a generic property_group element which represents it and 8209 * put it in eelts. 8210 */ 8211 static void 8212 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 8213 { 8214 xmlNodePtr n; 8215 int err = 0, ret; 8216 struct pg_elts elts; 8217 8218 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 8219 if (n == NULL) 8220 uu_die(emsg_create_xml); 8221 8222 /* 8223 * If the external flag is present, skip this dependency because it 8224 * should have been created by another manifest. 8225 */ 8226 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 8227 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8228 prop_get_val(exp_prop, exp_val) == 0) { 8229 uint8_t b; 8230 8231 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 8232 scfdie(); 8233 8234 if (b) 8235 return; 8236 } 8237 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 8238 scfdie(); 8239 8240 /* Get the required attributes. */ 8241 8242 /* name */ 8243 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8244 scfdie(); 8245 safe_setprop(n, name_attr, exp_str); 8246 8247 /* grouping */ 8248 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8249 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8250 err = 1; 8251 8252 /* restart_on */ 8253 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8254 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8255 err = 1; 8256 8257 /* type */ 8258 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8259 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8260 err = 1; 8261 8262 /* 8263 * entities: Not required, but if we create no children, it will be 8264 * created as empty on import, so fail if it's missing. 8265 */ 8266 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8267 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 8268 scf_iter_t *eiter; 8269 int ret2; 8270 8271 eiter = scf_iter_create(g_hndl); 8272 if (eiter == NULL) 8273 scfdie(); 8274 8275 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 8276 scfdie(); 8277 8278 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 8279 xmlNodePtr ch; 8280 8281 if (scf_value_get_astring(exp_val, exp_str, 8282 exp_str_sz) < 0) 8283 scfdie(); 8284 8285 /* 8286 * service_fmri's must be first, so we can add them 8287 * here. 8288 */ 8289 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 8290 NULL); 8291 if (ch == NULL) 8292 uu_die(emsg_create_xml); 8293 8294 safe_setprop(ch, value_attr, exp_str); 8295 } 8296 if (ret2 == -1) 8297 scfdie(); 8298 8299 scf_iter_destroy(eiter); 8300 } else 8301 err = 1; 8302 8303 if (err) { 8304 xmlFreeNode(n); 8305 8306 export_pg(pg, eelts, 0); 8307 8308 return; 8309 } 8310 8311 /* Iterate through the properties & handle each. */ 8312 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8313 scfdie(); 8314 8315 (void) memset(&elts, 0, sizeof (elts)); 8316 8317 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8318 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8319 scfdie(); 8320 8321 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8322 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8323 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 8324 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8325 continue; 8326 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8327 xmlNodePtr m; 8328 8329 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8330 if (m == NULL) 8331 uu_die(emsg_create_xml); 8332 8333 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8334 elts.stability = m; 8335 continue; 8336 } 8337 8338 xmlFreeNode(m); 8339 } 8340 8341 export_property(exp_prop, exp_str, &elts, 0); 8342 } 8343 if (ret == -1) 8344 scfdie(); 8345 8346 (void) xmlAddChild(n, elts.stability); 8347 (void) xmlAddChildList(n, elts.propvals); 8348 (void) xmlAddChildList(n, elts.properties); 8349 8350 if (eelts->dependencies == NULL) 8351 eelts->dependencies = n; 8352 else 8353 (void) xmlAddSibling(eelts->dependencies, n); 8354 } 8355 8356 static xmlNodePtr 8357 export_method_environment(scf_propertygroup_t *pg) 8358 { 8359 xmlNodePtr env; 8360 int ret; 8361 int children = 0; 8362 8363 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 8364 return (NULL); 8365 8366 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 8367 if (env == NULL) 8368 uu_die(emsg_create_xml); 8369 8370 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 8371 scfdie(); 8372 8373 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 8374 scfdie(); 8375 8376 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 8377 xmlNodePtr ev; 8378 char *cp; 8379 8380 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8381 scfdie(); 8382 8383 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 8384 warn(gettext("Invalid environment variable \"%s\".\n"), 8385 exp_str); 8386 continue; 8387 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 8388 warn(gettext("Invalid environment variable \"%s\"; " 8389 "\"SMF_\" prefix is reserved.\n"), exp_str); 8390 continue; 8391 } 8392 8393 *cp = '\0'; 8394 cp++; 8395 8396 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 8397 if (ev == NULL) 8398 uu_die(emsg_create_xml); 8399 8400 safe_setprop(ev, name_attr, exp_str); 8401 safe_setprop(ev, value_attr, cp); 8402 children++; 8403 } 8404 8405 if (ret != 0) 8406 scfdie(); 8407 8408 if (children == 0) { 8409 xmlFreeNode(env); 8410 return (NULL); 8411 } 8412 8413 return (env); 8414 } 8415 8416 /* 8417 * As above, but for a method property group. 8418 */ 8419 static void 8420 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 8421 { 8422 xmlNodePtr n, env; 8423 char *str; 8424 int err = 0, nonenv, ret; 8425 uint8_t use_profile; 8426 struct pg_elts elts; 8427 xmlNodePtr ctxt = NULL; 8428 8429 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 8430 8431 /* Get the required attributes. */ 8432 8433 /* name */ 8434 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8435 scfdie(); 8436 safe_setprop(n, name_attr, exp_str); 8437 8438 /* type */ 8439 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8440 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8441 err = 1; 8442 8443 /* exec */ 8444 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 8445 set_attr_from_prop(exp_prop, n, "exec") != 0) 8446 err = 1; 8447 8448 /* timeout */ 8449 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 8450 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 8451 prop_get_val(exp_prop, exp_val) == 0) { 8452 uint64_t c; 8453 8454 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 8455 scfdie(); 8456 8457 str = uu_msprintf("%llu", c); 8458 if (str == NULL) 8459 uu_die(gettext("Could not create string")); 8460 8461 safe_setprop(n, "timeout_seconds", str); 8462 free(str); 8463 } else 8464 err = 1; 8465 8466 if (err) { 8467 xmlFreeNode(n); 8468 8469 export_pg(pg, eelts, 0); 8470 8471 return; 8472 } 8473 8474 8475 /* 8476 * If we're going to have a method_context child, we need to know 8477 * before we iterate through the properties. Since method_context's 8478 * are optional, we don't want to complain about any properties 8479 * missing if none of them are there. Thus we can't use the 8480 * convenience functions. 8481 */ 8482 nonenv = 8483 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 8484 SCF_SUCCESS || 8485 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 8486 SCF_SUCCESS || 8487 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 8488 SCF_SUCCESS || 8489 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 8490 SCF_SUCCESS; 8491 8492 if (nonenv) { 8493 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 8494 if (ctxt == NULL) 8495 uu_die(emsg_create_xml); 8496 8497 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 8498 0 && 8499 set_attr_from_prop_default(exp_prop, ctxt, 8500 "working_directory", ":default") != 0) 8501 err = 1; 8502 8503 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 8504 set_attr_from_prop_default(exp_prop, ctxt, "project", 8505 ":default") != 0) 8506 err = 1; 8507 8508 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 8509 0 && 8510 set_attr_from_prop_default(exp_prop, ctxt, 8511 "resource_pool", ":default") != 0) 8512 err = 1; 8513 /* 8514 * We only want to complain about profile or credential 8515 * properties if we will use them. To determine that we must 8516 * examine USE_PROFILE. 8517 */ 8518 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 8519 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8520 prop_get_val(exp_prop, exp_val) == 0) { 8521 if (scf_value_get_boolean(exp_val, &use_profile) != 8522 SCF_SUCCESS) { 8523 scfdie(); 8524 } 8525 8526 if (use_profile) { 8527 xmlNodePtr prof; 8528 8529 prof = xmlNewChild(ctxt, NULL, 8530 (xmlChar *)"method_profile", NULL); 8531 if (prof == NULL) 8532 uu_die(emsg_create_xml); 8533 8534 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 8535 exp_prop) != 0 || 8536 set_attr_from_prop(exp_prop, prof, 8537 name_attr) != 0) 8538 err = 1; 8539 } else { 8540 xmlNodePtr cred; 8541 8542 cred = xmlNewChild(ctxt, NULL, 8543 (xmlChar *)"method_credential", NULL); 8544 if (cred == NULL) 8545 uu_die(emsg_create_xml); 8546 8547 if (pg_get_prop(pg, SCF_PROPERTY_USER, 8548 exp_prop) != 0 || 8549 set_attr_from_prop(exp_prop, cred, 8550 "user") != 0) { 8551 err = 1; 8552 } 8553 8554 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 8555 exp_prop) == 0 && 8556 set_attr_from_prop_default(exp_prop, cred, 8557 "group", ":default") != 0) 8558 err = 1; 8559 8560 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 8561 exp_prop) == 0 && 8562 set_attr_from_prop_default(exp_prop, cred, 8563 "supp_groups", ":default") != 0) 8564 err = 1; 8565 8566 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 8567 exp_prop) == 0 && 8568 set_attr_from_prop_default(exp_prop, cred, 8569 "privileges", ":default") != 0) 8570 err = 1; 8571 8572 if (pg_get_prop(pg, 8573 SCF_PROPERTY_LIMIT_PRIVILEGES, 8574 exp_prop) == 0 && 8575 set_attr_from_prop_default(exp_prop, cred, 8576 "limit_privileges", ":default") != 0) 8577 err = 1; 8578 } 8579 } 8580 } 8581 8582 if ((env = export_method_environment(pg)) != NULL) { 8583 if (ctxt == NULL) { 8584 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 8585 if (ctxt == NULL) 8586 uu_die(emsg_create_xml); 8587 } 8588 (void) xmlAddChild(ctxt, env); 8589 } 8590 8591 if (env != NULL || (nonenv && err == 0)) 8592 (void) xmlAddChild(n, ctxt); 8593 else 8594 xmlFreeNode(ctxt); 8595 8596 nonenv = (err == 0); 8597 8598 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8599 scfdie(); 8600 8601 (void) memset(&elts, 0, sizeof (elts)); 8602 8603 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8604 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8605 scfdie(); 8606 8607 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 8608 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 8609 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 8610 continue; 8611 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8612 xmlNodePtr m; 8613 8614 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8615 if (m == NULL) 8616 uu_die(emsg_create_xml); 8617 8618 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8619 elts.stability = m; 8620 continue; 8621 } 8622 8623 xmlFreeNode(m); 8624 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 8625 0 || 8626 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 8627 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 8628 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8629 if (nonenv) 8630 continue; 8631 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 8632 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 8633 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 8634 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 8635 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 8636 if (nonenv && !use_profile) 8637 continue; 8638 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8639 if (nonenv && use_profile) 8640 continue; 8641 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 8642 if (env != NULL) 8643 continue; 8644 } 8645 8646 export_property(exp_prop, exp_str, &elts, 0); 8647 } 8648 if (ret == -1) 8649 scfdie(); 8650 8651 (void) xmlAddChild(n, elts.stability); 8652 (void) xmlAddChildList(n, elts.propvals); 8653 (void) xmlAddChildList(n, elts.properties); 8654 8655 if (eelts->exec_methods == NULL) 8656 eelts->exec_methods = n; 8657 else 8658 (void) xmlAddSibling(eelts->exec_methods, n); 8659 } 8660 8661 static void 8662 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 8663 struct entity_elts *eelts) 8664 { 8665 xmlNodePtr pgnode; 8666 8667 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 8668 if (pgnode == NULL) 8669 uu_die(emsg_create_xml); 8670 8671 safe_setprop(pgnode, name_attr, name); 8672 safe_setprop(pgnode, type_attr, type); 8673 8674 (void) xmlAddChildList(pgnode, elts->propvals); 8675 (void) xmlAddChildList(pgnode, elts->properties); 8676 8677 if (eelts->property_groups == NULL) 8678 eelts->property_groups = pgnode; 8679 else 8680 (void) xmlAddSibling(eelts->property_groups, pgnode); 8681 } 8682 8683 /* 8684 * Process the general property group for a service. This is the one with the 8685 * goodies. 8686 */ 8687 static void 8688 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 8689 { 8690 struct pg_elts elts; 8691 int ret; 8692 8693 /* 8694 * In case there are properties which don't correspond to child 8695 * entities of the service entity, we'll set up a pg_elts structure to 8696 * put them in. 8697 */ 8698 (void) memset(&elts, 0, sizeof (elts)); 8699 8700 /* Walk the properties, looking for special ones. */ 8701 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8702 scfdie(); 8703 8704 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8705 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8706 scfdie(); 8707 8708 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 8709 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8710 prop_get_val(exp_prop, exp_val) == 0) { 8711 uint8_t b; 8712 8713 if (scf_value_get_boolean(exp_val, &b) != 8714 SCF_SUCCESS) 8715 scfdie(); 8716 8717 if (b) { 8718 selts->single_instance = 8719 xmlNewNode(NULL, 8720 (xmlChar *)"single_instance"); 8721 if (selts->single_instance == NULL) 8722 uu_die(emsg_create_xml); 8723 } 8724 8725 continue; 8726 } 8727 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8728 xmlNodePtr rnode, sfnode; 8729 8730 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8731 if (rnode == NULL) 8732 uu_die(emsg_create_xml); 8733 8734 sfnode = xmlNewChild(rnode, NULL, 8735 (xmlChar *)"service_fmri", NULL); 8736 if (sfnode == NULL) 8737 uu_die(emsg_create_xml); 8738 8739 if (set_attr_from_prop(exp_prop, sfnode, 8740 value_attr) == 0) { 8741 selts->restarter = rnode; 8742 continue; 8743 } 8744 8745 xmlFreeNode(rnode); 8746 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 8747 0) { 8748 xmlNodePtr s; 8749 8750 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8751 if (s == NULL) 8752 uu_die(emsg_create_xml); 8753 8754 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8755 selts->stability = s; 8756 continue; 8757 } 8758 8759 xmlFreeNode(s); 8760 } 8761 8762 export_property(exp_prop, exp_str, &elts, 0); 8763 } 8764 if (ret == -1) 8765 scfdie(); 8766 8767 if (elts.propvals != NULL || elts.properties != NULL) 8768 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 8769 selts); 8770 } 8771 8772 static void 8773 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 8774 { 8775 xmlNodePtr n, prof, cred, env; 8776 uint8_t use_profile; 8777 int ret, err = 0; 8778 8779 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 8780 8781 env = export_method_environment(pg); 8782 8783 /* Need to know whether we'll use a profile or not. */ 8784 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 8785 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8786 prop_get_val(exp_prop, exp_val) == 0) { 8787 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 8788 scfdie(); 8789 8790 if (use_profile) 8791 prof = 8792 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 8793 NULL); 8794 else 8795 cred = 8796 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 8797 NULL); 8798 } 8799 8800 if (env != NULL) 8801 (void) xmlAddChild(n, env); 8802 8803 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8804 scfdie(); 8805 8806 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8807 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8808 scfdie(); 8809 8810 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 8811 if (set_attr_from_prop(exp_prop, n, 8812 "working_directory") != 0) 8813 err = 1; 8814 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 8815 if (set_attr_from_prop(exp_prop, n, "project") != 0) 8816 err = 1; 8817 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 8818 if (set_attr_from_prop(exp_prop, n, 8819 "resource_pool") != 0) 8820 err = 1; 8821 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8822 /* EMPTY */ 8823 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 8824 if (use_profile || 8825 set_attr_from_prop(exp_prop, cred, "user") != 0) 8826 err = 1; 8827 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 8828 if (use_profile || 8829 set_attr_from_prop(exp_prop, cred, "group") != 0) 8830 err = 1; 8831 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 8832 if (use_profile || set_attr_from_prop(exp_prop, cred, 8833 "supp_groups") != 0) 8834 err = 1; 8835 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 8836 if (use_profile || set_attr_from_prop(exp_prop, cred, 8837 "privileges") != 0) 8838 err = 1; 8839 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 8840 0) { 8841 if (use_profile || set_attr_from_prop(exp_prop, cred, 8842 "limit_privileges") != 0) 8843 err = 1; 8844 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8845 if (!use_profile || set_attr_from_prop(exp_prop, 8846 prof, name_attr) != 0) 8847 err = 1; 8848 } else { 8849 /* Can't have generic properties in method_context's */ 8850 err = 1; 8851 } 8852 } 8853 if (ret == -1) 8854 scfdie(); 8855 8856 if (err && env == NULL) { 8857 xmlFreeNode(n); 8858 export_pg(pg, elts, 0); 8859 return; 8860 } 8861 8862 elts->method_context = n; 8863 } 8864 8865 /* 8866 * Given a dependency property group in the tfmri entity (target fmri), return 8867 * a dependent element which represents it. 8868 */ 8869 static xmlNodePtr 8870 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 8871 { 8872 uint8_t b; 8873 xmlNodePtr n, sf; 8874 int err = 0, ret; 8875 struct pg_elts pgelts; 8876 8877 /* 8878 * If external isn't set to true then exporting the service will 8879 * export this as a normal dependency, so we should stop to avoid 8880 * duplication. 8881 */ 8882 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 8883 scf_property_get_value(exp_prop, exp_val) != 0 || 8884 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 8885 if (g_verbose) { 8886 warn(gettext("Dependent \"%s\" cannot be exported " 8887 "properly because the \"%s\" property of the " 8888 "\"%s\" dependency of %s is not set to true.\n"), 8889 name, scf_property_external, name, tfmri); 8890 } 8891 8892 return (NULL); 8893 } 8894 8895 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 8896 if (n == NULL) 8897 uu_die(emsg_create_xml); 8898 8899 safe_setprop(n, name_attr, name); 8900 8901 /* Get the required attributes */ 8902 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8903 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8904 err = 1; 8905 8906 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8907 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8908 err = 1; 8909 8910 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8911 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 8912 prop_get_val(exp_prop, exp_val) == 0) { 8913 /* EMPTY */ 8914 } else 8915 err = 1; 8916 8917 if (err) { 8918 xmlFreeNode(n); 8919 return (NULL); 8920 } 8921 8922 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 8923 if (sf == NULL) 8924 uu_die(emsg_create_xml); 8925 8926 safe_setprop(sf, value_attr, tfmri); 8927 8928 /* 8929 * Now add elements for the other properties. 8930 */ 8931 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8932 scfdie(); 8933 8934 (void) memset(&pgelts, 0, sizeof (pgelts)); 8935 8936 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8937 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8938 scfdie(); 8939 8940 if (strcmp(exp_str, scf_property_external) == 0 || 8941 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8942 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8943 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8944 continue; 8945 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 8946 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 8947 prop_get_val(exp_prop, exp_val) == 0) { 8948 char type[sizeof ("service") + 1]; 8949 8950 if (scf_value_get_astring(exp_val, type, 8951 sizeof (type)) < 0) 8952 scfdie(); 8953 8954 if (strcmp(type, "service") == 0) 8955 continue; 8956 } 8957 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8958 xmlNodePtr s; 8959 8960 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8961 if (s == NULL) 8962 uu_die(emsg_create_xml); 8963 8964 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8965 pgelts.stability = s; 8966 continue; 8967 } 8968 8969 xmlFreeNode(s); 8970 } 8971 8972 export_property(exp_prop, exp_str, &pgelts, 0); 8973 } 8974 if (ret == -1) 8975 scfdie(); 8976 8977 (void) xmlAddChild(n, pgelts.stability); 8978 (void) xmlAddChildList(n, pgelts.propvals); 8979 (void) xmlAddChildList(n, pgelts.properties); 8980 8981 return (n); 8982 } 8983 8984 static void 8985 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 8986 { 8987 scf_propertygroup_t *opg; 8988 scf_iter_t *iter; 8989 char *type, *fmri; 8990 int ret; 8991 struct pg_elts pgelts; 8992 xmlNodePtr n; 8993 scf_error_t serr; 8994 8995 if ((opg = scf_pg_create(g_hndl)) == NULL || 8996 (iter = scf_iter_create(g_hndl)) == NULL) 8997 scfdie(); 8998 8999 /* Can't use exp_prop_iter due to export_dependent(). */ 9000 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 9001 scfdie(); 9002 9003 type = safe_malloc(max_scf_pg_type_len + 1); 9004 9005 /* Get an extra byte so we can tell if values are too long. */ 9006 fmri = safe_malloc(max_scf_fmri_len + 2); 9007 9008 (void) memset(&pgelts, 0, sizeof (pgelts)); 9009 9010 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 9011 void *entity; 9012 int isservice; 9013 scf_type_t ty; 9014 9015 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 9016 scfdie(); 9017 9018 if ((ty != SCF_TYPE_ASTRING && 9019 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 9020 prop_get_val(exp_prop, exp_val) != 0) { 9021 export_property(exp_prop, NULL, &pgelts, 0); 9022 continue; 9023 } 9024 9025 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9026 scfdie(); 9027 9028 if (scf_value_get_astring(exp_val, fmri, 9029 max_scf_fmri_len + 2) < 0) 9030 scfdie(); 9031 9032 /* Look for a dependency group in the target fmri. */ 9033 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 9034 switch (serr) { 9035 case SCF_ERROR_NONE: 9036 break; 9037 9038 case SCF_ERROR_NO_MEMORY: 9039 uu_die(gettext("Out of memory.\n")); 9040 /* NOTREACHED */ 9041 9042 case SCF_ERROR_INVALID_ARGUMENT: 9043 if (g_verbose) { 9044 if (scf_property_to_fmri(exp_prop, fmri, 9045 max_scf_fmri_len + 2) < 0) 9046 scfdie(); 9047 9048 warn(gettext("The value of %s is not a valid " 9049 "FMRI.\n"), fmri); 9050 } 9051 9052 export_property(exp_prop, exp_str, &pgelts, 0); 9053 continue; 9054 9055 case SCF_ERROR_CONSTRAINT_VIOLATED: 9056 if (g_verbose) { 9057 if (scf_property_to_fmri(exp_prop, fmri, 9058 max_scf_fmri_len + 2) < 0) 9059 scfdie(); 9060 9061 warn(gettext("The value of %s does not specify " 9062 "a service or an instance.\n"), fmri); 9063 } 9064 9065 export_property(exp_prop, exp_str, &pgelts, 0); 9066 continue; 9067 9068 case SCF_ERROR_NOT_FOUND: 9069 if (g_verbose) { 9070 if (scf_property_to_fmri(exp_prop, fmri, 9071 max_scf_fmri_len + 2) < 0) 9072 scfdie(); 9073 9074 warn(gettext("The entity specified by %s does " 9075 "not exist.\n"), fmri); 9076 } 9077 9078 export_property(exp_prop, exp_str, &pgelts, 0); 9079 continue; 9080 9081 default: 9082 #ifndef NDEBUG 9083 (void) fprintf(stderr, "%s:%d: %s() failed with " 9084 "unexpected error %d.\n", __FILE__, __LINE__, 9085 "fmri_to_entity", serr); 9086 #endif 9087 abort(); 9088 } 9089 9090 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 9091 if (scf_error() != SCF_ERROR_NOT_FOUND) 9092 scfdie(); 9093 9094 warn(gettext("Entity %s is missing dependency property " 9095 "group %s.\n"), fmri, exp_str); 9096 9097 export_property(exp_prop, NULL, &pgelts, 0); 9098 continue; 9099 } 9100 9101 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 9102 scfdie(); 9103 9104 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 9105 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 9106 scfdie(); 9107 9108 warn(gettext("Property group %s is not of " 9109 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 9110 9111 export_property(exp_prop, NULL, &pgelts, 0); 9112 continue; 9113 } 9114 9115 n = export_dependent(opg, exp_str, fmri); 9116 if (n == NULL) 9117 export_property(exp_prop, exp_str, &pgelts, 0); 9118 else { 9119 if (eelts->dependents == NULL) 9120 eelts->dependents = n; 9121 else 9122 (void) xmlAddSibling(eelts->dependents, 9123 n); 9124 } 9125 } 9126 if (ret == -1) 9127 scfdie(); 9128 9129 free(fmri); 9130 free(type); 9131 9132 scf_iter_destroy(iter); 9133 scf_pg_destroy(opg); 9134 9135 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9136 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 9137 eelts); 9138 } 9139 9140 static void 9141 make_node(xmlNodePtr *nodep, const char *name) 9142 { 9143 if (*nodep == NULL) { 9144 *nodep = xmlNewNode(NULL, (xmlChar *)name); 9145 if (*nodep == NULL) 9146 uu_die(emsg_create_xml); 9147 } 9148 } 9149 9150 static xmlNodePtr 9151 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 9152 { 9153 int ret; 9154 xmlNodePtr parent = NULL; 9155 xmlNodePtr loctext = NULL; 9156 9157 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9158 scfdie(); 9159 9160 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9161 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 9162 prop_get_val(exp_prop, exp_val) != 0) 9163 continue; 9164 9165 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 9166 scfdie(); 9167 9168 make_node(&parent, parname); 9169 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 9170 (xmlChar *)exp_str); 9171 if (loctext == NULL) 9172 uu_die(emsg_create_xml); 9173 9174 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9175 scfdie(); 9176 9177 safe_setprop(loctext, "xml:lang", exp_str); 9178 } 9179 9180 if (ret == -1) 9181 scfdie(); 9182 9183 return (parent); 9184 } 9185 9186 static xmlNodePtr 9187 export_tm_manpage(scf_propertygroup_t *pg) 9188 { 9189 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 9190 if (manpage == NULL) 9191 uu_die(emsg_create_xml); 9192 9193 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 9194 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 9195 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 9196 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 9197 xmlFreeNode(manpage); 9198 return (NULL); 9199 } 9200 9201 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 9202 (void) set_attr_from_prop_default(exp_prop, 9203 manpage, "manpath", ":default"); 9204 9205 return (manpage); 9206 } 9207 9208 static xmlNodePtr 9209 export_tm_doc_link(scf_propertygroup_t *pg) 9210 { 9211 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 9212 if (doc_link == NULL) 9213 uu_die(emsg_create_xml); 9214 9215 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 9216 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 9217 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 9218 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 9219 xmlFreeNode(doc_link); 9220 return (NULL); 9221 } 9222 return (doc_link); 9223 } 9224 9225 /* 9226 * Process template information for a service or instances. 9227 */ 9228 static void 9229 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 9230 struct template_elts *telts) 9231 { 9232 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 9233 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 9234 xmlNodePtr child = NULL; 9235 9236 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 9237 scfdie(); 9238 9239 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 9240 telts->common_name = export_tm_loctext(pg, "common_name"); 9241 if (telts->common_name == NULL) 9242 export_pg(pg, elts, 0); 9243 return; 9244 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 9245 telts->description = export_tm_loctext(pg, "description"); 9246 if (telts->description == NULL) 9247 export_pg(pg, elts, 0); 9248 return; 9249 } 9250 9251 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 9252 child = export_tm_manpage(pg); 9253 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 9254 child = export_tm_doc_link(pg); 9255 } 9256 9257 if (child != NULL) { 9258 make_node(&telts->documentation, "documentation"); 9259 (void) xmlAddChild(telts->documentation, child); 9260 } else { 9261 export_pg(pg, elts, 0); 9262 } 9263 } 9264 9265 /* 9266 * Process the general property group for an instance. 9267 */ 9268 static void 9269 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 9270 struct entity_elts *elts) 9271 { 9272 uint8_t enabled; 9273 struct pg_elts pgelts; 9274 int ret; 9275 9276 /* enabled */ 9277 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 9278 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9279 prop_get_val(exp_prop, exp_val) == 0) { 9280 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 9281 scfdie(); 9282 } else { 9283 enabled = 0; 9284 } 9285 9286 safe_setprop(inode, enabled_attr, enabled ? true : false); 9287 9288 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9289 scfdie(); 9290 9291 (void) memset(&pgelts, 0, sizeof (pgelts)); 9292 9293 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9294 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9295 scfdie(); 9296 9297 if (strcmp(exp_str, scf_property_enabled) == 0) { 9298 continue; 9299 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9300 xmlNodePtr rnode, sfnode; 9301 9302 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9303 if (rnode == NULL) 9304 uu_die(emsg_create_xml); 9305 9306 sfnode = xmlNewChild(rnode, NULL, 9307 (xmlChar *)"service_fmri", NULL); 9308 if (sfnode == NULL) 9309 uu_die(emsg_create_xml); 9310 9311 if (set_attr_from_prop(exp_prop, sfnode, 9312 value_attr) == 0) { 9313 elts->restarter = rnode; 9314 continue; 9315 } 9316 9317 xmlFreeNode(rnode); 9318 } 9319 9320 export_property(exp_prop, exp_str, &pgelts, 0); 9321 } 9322 if (ret == -1) 9323 scfdie(); 9324 9325 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9326 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 9327 elts); 9328 } 9329 9330 /* 9331 * Put an instance element for the given instance into selts. 9332 */ 9333 static void 9334 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 9335 { 9336 xmlNodePtr n; 9337 boolean_t isdefault; 9338 struct entity_elts elts; 9339 struct template_elts template_elts; 9340 int ret; 9341 9342 n = xmlNewNode(NULL, (xmlChar *)"instance"); 9343 if (n == NULL) 9344 uu_die(emsg_create_xml); 9345 9346 /* name */ 9347 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 9348 scfdie(); 9349 safe_setprop(n, name_attr, exp_str); 9350 isdefault = strcmp(exp_str, "default") == 0; 9351 9352 /* check existance of general pg (since general/enabled is required) */ 9353 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 9354 if (scf_error() != SCF_ERROR_NOT_FOUND) 9355 scfdie(); 9356 9357 if (g_verbose) { 9358 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 9359 scfdie(); 9360 9361 warn(gettext("Instance %s has no general property " 9362 "group; it will be marked disabled.\n"), exp_str); 9363 } 9364 9365 safe_setprop(n, enabled_attr, false); 9366 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 9367 strcmp(exp_str, scf_group_framework) != 0) { 9368 if (g_verbose) { 9369 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 9370 scfdie(); 9371 9372 warn(gettext("Property group %s is not of type " 9373 "framework; the instance will be marked " 9374 "disabled.\n"), exp_str); 9375 } 9376 9377 safe_setprop(n, enabled_attr, false); 9378 } 9379 9380 /* property groups */ 9381 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 9382 scfdie(); 9383 9384 (void) memset(&elts, 0, sizeof (elts)); 9385 (void) memset(&template_elts, 0, sizeof (template_elts)); 9386 9387 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 9388 uint32_t pgflags; 9389 9390 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 9391 scfdie(); 9392 9393 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 9394 continue; 9395 9396 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 9397 scfdie(); 9398 9399 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 9400 export_dependency(exp_pg, &elts); 9401 continue; 9402 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 9403 export_method(exp_pg, &elts); 9404 continue; 9405 } else if (strcmp(exp_str, scf_group_framework) == 0) { 9406 if (scf_pg_get_name(exp_pg, exp_str, 9407 max_scf_name_len + 1) < 0) 9408 scfdie(); 9409 9410 if (strcmp(exp_str, scf_pg_general) == 0) { 9411 export_inst_general(exp_pg, n, &elts); 9412 continue; 9413 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 9414 0) { 9415 export_method_context(exp_pg, &elts); 9416 continue; 9417 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 9418 export_dependents(exp_pg, &elts); 9419 continue; 9420 } 9421 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 9422 export_template(exp_pg, &elts, &template_elts); 9423 continue; 9424 } 9425 9426 /* Ordinary pg. */ 9427 export_pg(exp_pg, &elts, flags); 9428 } 9429 if (ret == -1) 9430 scfdie(); 9431 9432 if (template_elts.common_name != NULL) { 9433 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9434 (void) xmlAddChild(elts.template, template_elts.common_name); 9435 (void) xmlAddChild(elts.template, template_elts.description); 9436 (void) xmlAddChild(elts.template, template_elts.documentation); 9437 } else { 9438 xmlFreeNode(template_elts.description); 9439 xmlFreeNode(template_elts.documentation); 9440 } 9441 9442 if (isdefault && elts.restarter == NULL && 9443 elts.dependencies == NULL && elts.method_context == NULL && 9444 elts.exec_methods == NULL && elts.property_groups == NULL && 9445 elts.template == NULL) { 9446 xmlChar *eval; 9447 9448 /* This is a default instance */ 9449 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 9450 9451 xmlFreeNode(n); 9452 9453 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 9454 if (n == NULL) 9455 uu_die(emsg_create_xml); 9456 9457 safe_setprop(n, enabled_attr, (char *)eval); 9458 xmlFree(eval); 9459 9460 selts->create_default_instance = n; 9461 } else { 9462 /* Assemble the children in order. */ 9463 (void) xmlAddChild(n, elts.restarter); 9464 (void) xmlAddChildList(n, elts.dependencies); 9465 (void) xmlAddChildList(n, elts.dependents); 9466 (void) xmlAddChild(n, elts.method_context); 9467 (void) xmlAddChildList(n, elts.exec_methods); 9468 (void) xmlAddChildList(n, elts.property_groups); 9469 (void) xmlAddChild(n, elts.template); 9470 9471 if (selts->instances == NULL) 9472 selts->instances = n; 9473 else 9474 (void) xmlAddSibling(selts->instances, n); 9475 } 9476 } 9477 9478 /* 9479 * Return a service element for the given service. 9480 */ 9481 static xmlNodePtr 9482 export_service(scf_service_t *svc, int flags) 9483 { 9484 xmlNodePtr snode; 9485 struct entity_elts elts; 9486 struct template_elts template_elts; 9487 int ret; 9488 9489 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9490 if (snode == NULL) 9491 uu_die(emsg_create_xml); 9492 9493 /* Get & set name attribute */ 9494 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 9495 scfdie(); 9496 safe_setprop(snode, name_attr, exp_str); 9497 9498 safe_setprop(snode, type_attr, "service"); 9499 safe_setprop(snode, "version", "0"); 9500 9501 /* Acquire child elements. */ 9502 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 9503 scfdie(); 9504 9505 (void) memset(&elts, 0, sizeof (elts)); 9506 (void) memset(&template_elts, 0, sizeof (template_elts)); 9507 9508 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 9509 uint32_t pgflags; 9510 9511 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 9512 scfdie(); 9513 9514 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 9515 continue; 9516 9517 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 9518 scfdie(); 9519 9520 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 9521 export_dependency(exp_pg, &elts); 9522 continue; 9523 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 9524 export_method(exp_pg, &elts); 9525 continue; 9526 } else if (strcmp(exp_str, scf_group_framework) == 0) { 9527 if (scf_pg_get_name(exp_pg, exp_str, 9528 max_scf_name_len + 1) < 0) 9529 scfdie(); 9530 9531 if (strcmp(exp_str, scf_pg_general) == 0) { 9532 export_svc_general(exp_pg, &elts); 9533 continue; 9534 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 9535 0) { 9536 export_method_context(exp_pg, &elts); 9537 continue; 9538 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 9539 export_dependents(exp_pg, &elts); 9540 continue; 9541 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 9542 continue; 9543 } 9544 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 9545 export_template(exp_pg, &elts, &template_elts); 9546 continue; 9547 } 9548 9549 export_pg(exp_pg, &elts, flags); 9550 } 9551 if (ret == -1) 9552 scfdie(); 9553 9554 if (template_elts.common_name != NULL) { 9555 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9556 (void) xmlAddChild(elts.template, template_elts.common_name); 9557 (void) xmlAddChild(elts.template, template_elts.description); 9558 (void) xmlAddChild(elts.template, template_elts.documentation); 9559 } else { 9560 xmlFreeNode(template_elts.description); 9561 xmlFreeNode(template_elts.documentation); 9562 } 9563 9564 /* Iterate instances */ 9565 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 9566 scfdie(); 9567 9568 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 9569 export_instance(exp_inst, &elts, flags); 9570 if (ret == -1) 9571 scfdie(); 9572 9573 /* Now add all of the accumulated elements in order. */ 9574 (void) xmlAddChild(snode, elts.create_default_instance); 9575 (void) xmlAddChild(snode, elts.single_instance); 9576 (void) xmlAddChild(snode, elts.restarter); 9577 (void) xmlAddChildList(snode, elts.dependencies); 9578 (void) xmlAddChildList(snode, elts.dependents); 9579 (void) xmlAddChild(snode, elts.method_context); 9580 (void) xmlAddChildList(snode, elts.exec_methods); 9581 (void) xmlAddChildList(snode, elts.property_groups); 9582 (void) xmlAddChildList(snode, elts.instances); 9583 (void) xmlAddChild(snode, elts.stability); 9584 (void) xmlAddChild(snode, elts.template); 9585 9586 return (snode); 9587 } 9588 9589 static int 9590 export_callback(void *data, scf_walkinfo_t *wip) 9591 { 9592 FILE *f; 9593 xmlDocPtr doc; 9594 xmlNodePtr sb; 9595 int result; 9596 struct export_args *argsp = (struct export_args *)data; 9597 9598 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 9599 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9600 (exp_prop = scf_property_create(g_hndl)) == NULL || 9601 (exp_val = scf_value_create(g_hndl)) == NULL || 9602 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9603 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9604 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9605 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9606 scfdie(); 9607 9608 exp_str_sz = max_scf_len + 1; 9609 exp_str = safe_malloc(exp_str_sz); 9610 9611 if (argsp->filename != NULL) { 9612 errno = 0; 9613 f = fopen(argsp->filename, "wb"); 9614 if (f == NULL) { 9615 if (errno == 0) 9616 uu_die(gettext("Could not open \"%s\": no free " 9617 "stdio streams.\n"), argsp->filename); 9618 else 9619 uu_die(gettext("Could not open \"%s\""), 9620 argsp->filename); 9621 } 9622 } else 9623 f = stdout; 9624 9625 doc = xmlNewDoc((xmlChar *)"1.0"); 9626 if (doc == NULL) 9627 uu_die(gettext("Could not create XML document.\n")); 9628 9629 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9630 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9631 uu_die(emsg_create_xml); 9632 9633 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9634 if (sb == NULL) 9635 uu_die(emsg_create_xml); 9636 safe_setprop(sb, type_attr, "manifest"); 9637 safe_setprop(sb, name_attr, "export"); 9638 (void) xmlAddSibling(doc->children, sb); 9639 9640 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 9641 9642 result = write_service_bundle(doc, f); 9643 9644 free(exp_str); 9645 scf_iter_destroy(exp_val_iter); 9646 scf_iter_destroy(exp_prop_iter); 9647 scf_iter_destroy(exp_pg_iter); 9648 scf_iter_destroy(exp_inst_iter); 9649 scf_value_destroy(exp_val); 9650 scf_property_destroy(exp_prop); 9651 scf_pg_destroy(exp_pg); 9652 scf_instance_destroy(exp_inst); 9653 9654 xmlFreeDoc(doc); 9655 9656 if (f != stdout) 9657 (void) fclose(f); 9658 9659 return (result); 9660 } 9661 9662 /* 9663 * Get the service named by fmri, build an XML tree which represents it, and 9664 * dump it into filename (or stdout if filename is NULL). 9665 */ 9666 int 9667 lscf_service_export(char *fmri, const char *filename, int flags) 9668 { 9669 struct export_args args; 9670 int ret, err; 9671 9672 lscf_prep_hndl(); 9673 9674 bzero(&args, sizeof (args)); 9675 args.filename = filename; 9676 args.flags = flags; 9677 9678 err = 0; 9679 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 9680 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 9681 &args, &err, semerr)) != 0) { 9682 if (ret != -1) 9683 semerr(gettext("Failed to walk instances: %s\n"), 9684 scf_strerror(ret)); 9685 return (-1); 9686 } 9687 9688 /* 9689 * Error message has already been printed. 9690 */ 9691 if (err != 0) 9692 return (-1); 9693 9694 return (0); 9695 } 9696 9697 9698 /* 9699 * Archive 9700 */ 9701 9702 static xmlNodePtr 9703 make_archive(int flags) 9704 { 9705 xmlNodePtr sb; 9706 scf_scope_t *scope; 9707 scf_service_t *svc; 9708 scf_iter_t *iter; 9709 int r; 9710 9711 if ((scope = scf_scope_create(g_hndl)) == NULL || 9712 (svc = scf_service_create(g_hndl)) == NULL || 9713 (iter = scf_iter_create(g_hndl)) == NULL || 9714 (exp_inst = scf_instance_create(g_hndl)) == NULL || 9715 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9716 (exp_prop = scf_property_create(g_hndl)) == NULL || 9717 (exp_val = scf_value_create(g_hndl)) == NULL || 9718 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9719 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9720 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9721 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9722 scfdie(); 9723 9724 exp_str_sz = max_scf_len + 1; 9725 exp_str = safe_malloc(exp_str_sz); 9726 9727 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9728 if (sb == NULL) 9729 uu_die(emsg_create_xml); 9730 safe_setprop(sb, type_attr, "archive"); 9731 safe_setprop(sb, name_attr, "none"); 9732 9733 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 9734 scfdie(); 9735 if (scf_iter_scope_services(iter, scope) != 0) 9736 scfdie(); 9737 9738 for (;;) { 9739 r = scf_iter_next_service(iter, svc); 9740 if (r == 0) 9741 break; 9742 if (r != 1) 9743 scfdie(); 9744 9745 if (scf_service_get_name(svc, exp_str, 9746 max_scf_name_len + 1) < 0) 9747 scfdie(); 9748 9749 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 9750 continue; 9751 9752 (void) xmlAddChild(sb, export_service(svc, flags)); 9753 } 9754 9755 free(exp_str); 9756 9757 scf_iter_destroy(exp_val_iter); 9758 scf_iter_destroy(exp_prop_iter); 9759 scf_iter_destroy(exp_pg_iter); 9760 scf_iter_destroy(exp_inst_iter); 9761 scf_value_destroy(exp_val); 9762 scf_property_destroy(exp_prop); 9763 scf_pg_destroy(exp_pg); 9764 scf_instance_destroy(exp_inst); 9765 scf_iter_destroy(iter); 9766 scf_service_destroy(svc); 9767 scf_scope_destroy(scope); 9768 9769 return (sb); 9770 } 9771 9772 int 9773 lscf_archive(const char *filename, int flags) 9774 { 9775 FILE *f; 9776 xmlDocPtr doc; 9777 int result; 9778 9779 lscf_prep_hndl(); 9780 9781 if (filename != NULL) { 9782 errno = 0; 9783 f = fopen(filename, "wb"); 9784 if (f == NULL) { 9785 if (errno == 0) 9786 uu_die(gettext("Could not open \"%s\": no free " 9787 "stdio streams.\n"), filename); 9788 else 9789 uu_die(gettext("Could not open \"%s\""), 9790 filename); 9791 } 9792 } else 9793 f = stdout; 9794 9795 doc = xmlNewDoc((xmlChar *)"1.0"); 9796 if (doc == NULL) 9797 uu_die(gettext("Could not create XML document.\n")); 9798 9799 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9800 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9801 uu_die(emsg_create_xml); 9802 9803 (void) xmlAddSibling(doc->children, make_archive(flags)); 9804 9805 result = write_service_bundle(doc, f); 9806 9807 xmlFreeDoc(doc); 9808 9809 if (f != stdout) 9810 (void) fclose(f); 9811 9812 return (result); 9813 } 9814 9815 9816 /* 9817 * "Extract" a profile. 9818 */ 9819 int 9820 lscf_profile_extract(const char *filename) 9821 { 9822 FILE *f; 9823 xmlDocPtr doc; 9824 xmlNodePtr sb, snode, inode; 9825 scf_scope_t *scope; 9826 scf_service_t *svc; 9827 scf_instance_t *inst; 9828 scf_propertygroup_t *pg; 9829 scf_property_t *prop; 9830 scf_value_t *val; 9831 scf_iter_t *siter, *iiter; 9832 int r, s; 9833 char *namebuf; 9834 uint8_t b; 9835 int result; 9836 9837 lscf_prep_hndl(); 9838 9839 if (filename != NULL) { 9840 errno = 0; 9841 f = fopen(filename, "wb"); 9842 if (f == NULL) { 9843 if (errno == 0) 9844 uu_die(gettext("Could not open \"%s\": no " 9845 "free stdio streams.\n"), filename); 9846 else 9847 uu_die(gettext("Could not open \"%s\""), 9848 filename); 9849 } 9850 } else 9851 f = stdout; 9852 9853 doc = xmlNewDoc((xmlChar *)"1.0"); 9854 if (doc == NULL) 9855 uu_die(gettext("Could not create XML document.\n")); 9856 9857 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9858 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9859 uu_die(emsg_create_xml); 9860 9861 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9862 if (sb == NULL) 9863 uu_die(emsg_create_xml); 9864 safe_setprop(sb, type_attr, "profile"); 9865 safe_setprop(sb, name_attr, "extract"); 9866 (void) xmlAddSibling(doc->children, sb); 9867 9868 if ((scope = scf_scope_create(g_hndl)) == NULL || 9869 (svc = scf_service_create(g_hndl)) == NULL || 9870 (inst = scf_instance_create(g_hndl)) == NULL || 9871 (pg = scf_pg_create(g_hndl)) == NULL || 9872 (prop = scf_property_create(g_hndl)) == NULL || 9873 (val = scf_value_create(g_hndl)) == NULL || 9874 (siter = scf_iter_create(g_hndl)) == NULL || 9875 (iiter = scf_iter_create(g_hndl)) == NULL) 9876 scfdie(); 9877 9878 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 9879 scfdie(); 9880 9881 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 9882 scfdie(); 9883 9884 namebuf = safe_malloc(max_scf_name_len + 1); 9885 9886 while ((r = scf_iter_next_service(siter, svc)) == 1) { 9887 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 9888 scfdie(); 9889 9890 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9891 if (snode == NULL) 9892 uu_die(emsg_create_xml); 9893 9894 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 9895 0) 9896 scfdie(); 9897 9898 safe_setprop(snode, name_attr, namebuf); 9899 9900 safe_setprop(snode, type_attr, "service"); 9901 safe_setprop(snode, "version", "0"); 9902 9903 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 9904 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 9905 SCF_SUCCESS) { 9906 if (scf_error() != SCF_ERROR_NOT_FOUND) 9907 scfdie(); 9908 9909 if (g_verbose) { 9910 ssize_t len; 9911 char *fmri; 9912 9913 len = 9914 scf_instance_to_fmri(inst, NULL, 0); 9915 if (len < 0) 9916 scfdie(); 9917 9918 fmri = safe_malloc(len + 1); 9919 9920 if (scf_instance_to_fmri(inst, fmri, 9921 len + 1) < 0) 9922 scfdie(); 9923 9924 warn("Instance %s has no \"%s\" " 9925 "property group.\n", fmri, 9926 scf_pg_general); 9927 9928 free(fmri); 9929 } 9930 9931 continue; 9932 } 9933 9934 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 9935 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 9936 prop_get_val(prop, val) != 0) 9937 continue; 9938 9939 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 9940 NULL); 9941 if (inode == NULL) 9942 uu_die(emsg_create_xml); 9943 9944 if (scf_instance_get_name(inst, namebuf, 9945 max_scf_name_len + 1) < 0) 9946 scfdie(); 9947 9948 safe_setprop(inode, name_attr, namebuf); 9949 9950 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 9951 scfdie(); 9952 9953 safe_setprop(inode, enabled_attr, b ? true : false); 9954 } 9955 if (s < 0) 9956 scfdie(); 9957 9958 if (snode->children != NULL) 9959 (void) xmlAddChild(sb, snode); 9960 else 9961 xmlFreeNode(snode); 9962 } 9963 if (r < 0) 9964 scfdie(); 9965 9966 free(namebuf); 9967 9968 result = write_service_bundle(doc, f); 9969 9970 xmlFreeDoc(doc); 9971 9972 if (f != stdout) 9973 (void) fclose(f); 9974 9975 return (result); 9976 } 9977 9978 9979 /* 9980 * Entity manipulation commands 9981 */ 9982 9983 /* 9984 * Entity selection. If no entity is selected, then the current scope is in 9985 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 9986 * only cur_inst is NULL, and when an instance is selected, none are NULL. 9987 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 9988 * cur_inst will be non-NULL. 9989 */ 9990 9991 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 9992 static int 9993 select_inst(const char *name) 9994 { 9995 scf_instance_t *inst; 9996 scf_error_t err; 9997 9998 assert(cur_svc != NULL); 9999 10000 inst = scf_instance_create(g_hndl); 10001 if (inst == NULL) 10002 scfdie(); 10003 10004 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 10005 cur_inst = inst; 10006 return (0); 10007 } 10008 10009 err = scf_error(); 10010 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10011 scfdie(); 10012 10013 scf_instance_destroy(inst); 10014 return (1); 10015 } 10016 10017 /* Returns as above. */ 10018 static int 10019 select_svc(const char *name) 10020 { 10021 scf_service_t *svc; 10022 scf_error_t err; 10023 10024 assert(cur_scope != NULL); 10025 10026 svc = scf_service_create(g_hndl); 10027 if (svc == NULL) 10028 scfdie(); 10029 10030 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 10031 cur_svc = svc; 10032 return (0); 10033 } 10034 10035 err = scf_error(); 10036 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10037 scfdie(); 10038 10039 scf_service_destroy(svc); 10040 return (1); 10041 } 10042 10043 /* ARGSUSED */ 10044 static int 10045 select_callback(void *unused, scf_walkinfo_t *wip) 10046 { 10047 scf_instance_t *inst; 10048 scf_service_t *svc; 10049 scf_scope_t *scope; 10050 10051 if (wip->inst != NULL) { 10052 if ((scope = scf_scope_create(g_hndl)) == NULL || 10053 (svc = scf_service_create(g_hndl)) == NULL || 10054 (inst = scf_instance_create(g_hndl)) == NULL) 10055 scfdie(); 10056 10057 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 10058 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 10059 scfdie(); 10060 } else { 10061 assert(wip->svc != NULL); 10062 10063 if ((scope = scf_scope_create(g_hndl)) == NULL || 10064 (svc = scf_service_create(g_hndl)) == NULL) 10065 scfdie(); 10066 10067 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 10068 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 10069 scfdie(); 10070 10071 inst = NULL; 10072 } 10073 10074 /* Clear out the current selection */ 10075 assert(cur_scope != NULL); 10076 scf_scope_destroy(cur_scope); 10077 scf_service_destroy(cur_svc); 10078 scf_instance_destroy(cur_inst); 10079 10080 cur_scope = scope; 10081 cur_svc = svc; 10082 cur_inst = inst; 10083 10084 return (0); 10085 } 10086 10087 static int 10088 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 10089 { 10090 char **fmri = fmri_p; 10091 10092 *fmri = strdup(wip->fmri); 10093 if (*fmri == NULL) 10094 uu_die(gettext("Out of memory.\n")); 10095 10096 return (0); 10097 } 10098 10099 /* 10100 * validate [fmri] 10101 * Perform the validation of an FMRI instance. 10102 */ 10103 void 10104 lscf_validate_fmri(const char *fmri) 10105 { 10106 int ret = 0; 10107 size_t inst_sz; 10108 char *inst_fmri = NULL; 10109 scf_tmpl_errors_t *errs = NULL; 10110 char *snapbuf = NULL; 10111 10112 lscf_prep_hndl(); 10113 10114 if (fmri == NULL) { 10115 inst_sz = max_scf_fmri_len + 1; 10116 inst_fmri = safe_malloc(inst_sz); 10117 10118 if (cur_snap != NULL) { 10119 snapbuf = safe_malloc(max_scf_name_len + 1); 10120 if (scf_snapshot_get_name(cur_snap, snapbuf, 10121 max_scf_name_len + 1) < 0) 10122 scfdie(); 10123 } 10124 if (cur_inst == NULL) { 10125 semerr(gettext("No instance selected\n")); 10126 goto cleanup; 10127 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 10128 inst_sz) >= inst_sz) { 10129 /* sanity check. Should never get here */ 10130 uu_die(gettext("Unexpected error! file %s, line %d\n"), 10131 __FILE__, __LINE__); 10132 } 10133 } else { 10134 scf_error_t scf_err; 10135 int err = 0; 10136 10137 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 10138 validate_callback, &inst_fmri, &err, semerr)) != 0) { 10139 uu_warn("Failed to walk instances: %s\n", 10140 scf_strerror(scf_err)); 10141 goto cleanup; 10142 } 10143 if (err != 0) { 10144 /* error message displayed by scf_walk_fmri */ 10145 goto cleanup; 10146 } 10147 } 10148 10149 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 10150 SCF_TMPL_VALIDATE_FLAG_CURRENT); 10151 if (ret == -1) { 10152 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 10153 warn(gettext("Template data for %s is invalid. " 10154 "Consider reverting to a previous snapshot or " 10155 "restoring original configuration.\n"), inst_fmri); 10156 } else { 10157 uu_warn("%s: %s\n", 10158 gettext("Error validating the instance"), 10159 scf_strerror(scf_error())); 10160 } 10161 } else if (ret == 1 && errs != NULL) { 10162 scf_tmpl_error_t *err = NULL; 10163 char *msg; 10164 size_t len = 256; /* initial error buffer size */ 10165 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 10166 SCF_TMPL_STRERROR_HUMAN : 0; 10167 10168 msg = safe_malloc(len); 10169 10170 while ((err = scf_tmpl_next_error(errs)) != NULL) { 10171 int ret; 10172 10173 if ((ret = scf_tmpl_strerror(err, msg, len, 10174 flag)) >= len) { 10175 len = ret + 1; 10176 msg = realloc(msg, len); 10177 if (msg == NULL) 10178 uu_die(gettext( 10179 "Out of memory.\n")); 10180 (void) scf_tmpl_strerror(err, msg, len, 10181 flag); 10182 } 10183 (void) fprintf(stderr, "%s\n", msg); 10184 } 10185 if (msg != NULL) 10186 free(msg); 10187 } 10188 if (errs != NULL) 10189 scf_tmpl_errors_destroy(errs); 10190 10191 cleanup: 10192 free(inst_fmri); 10193 free(snapbuf); 10194 } 10195 10196 static void 10197 lscf_validate_file(const char *filename) 10198 { 10199 tmpl_errors_t *errs; 10200 10201 bundle_t *b = internal_bundle_new(); 10202 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 10203 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 10204 tmpl_errors_print(stderr, errs, ""); 10205 semerr(gettext("Validation failed.\n")); 10206 } 10207 tmpl_errors_destroy(errs); 10208 } 10209 (void) internal_bundle_free(b); 10210 } 10211 10212 /* 10213 * validate [fmri|file] 10214 */ 10215 void 10216 lscf_validate(const char *arg) 10217 { 10218 const char *str; 10219 10220 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 10221 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 10222 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 10223 lscf_validate_file(str); 10224 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 10225 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 10226 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 10227 lscf_validate_fmri(str); 10228 } else if (access(arg, R_OK | F_OK) == 0) { 10229 lscf_validate_file(arg); 10230 } else { 10231 lscf_validate_fmri(arg); 10232 } 10233 } 10234 10235 void 10236 lscf_select(const char *fmri) 10237 { 10238 int ret, err; 10239 10240 lscf_prep_hndl(); 10241 10242 if (cur_snap != NULL) { 10243 struct snaplevel *elt; 10244 char *buf; 10245 10246 /* Error unless name is that of the next level. */ 10247 elt = uu_list_next(cur_levels, cur_elt); 10248 if (elt == NULL) { 10249 semerr(gettext("No children.\n")); 10250 return; 10251 } 10252 10253 buf = safe_malloc(max_scf_name_len + 1); 10254 10255 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10256 max_scf_name_len + 1) < 0) 10257 scfdie(); 10258 10259 if (strcmp(buf, fmri) != 0) { 10260 semerr(gettext("No such child.\n")); 10261 free(buf); 10262 return; 10263 } 10264 10265 free(buf); 10266 10267 cur_elt = elt; 10268 cur_level = elt->sl; 10269 return; 10270 } 10271 10272 /* 10273 * Special case for 'svc:', which takes the user to the scope level. 10274 */ 10275 if (strcmp(fmri, "svc:") == 0) { 10276 scf_instance_destroy(cur_inst); 10277 scf_service_destroy(cur_svc); 10278 cur_inst = NULL; 10279 cur_svc = NULL; 10280 return; 10281 } 10282 10283 /* 10284 * Special case for ':properties'. This appears as part of 'list' but 10285 * can't be selected. Give a more helpful error message in this case. 10286 */ 10287 if (strcmp(fmri, ":properties") == 0) { 10288 semerr(gettext(":properties is not an entity. Try 'listprop' " 10289 "to list properties.\n")); 10290 return; 10291 } 10292 10293 /* 10294 * First try the argument as relative to the current selection. 10295 */ 10296 if (cur_inst != NULL) { 10297 /* EMPTY */; 10298 } else if (cur_svc != NULL) { 10299 if (select_inst(fmri) != 1) 10300 return; 10301 } else { 10302 if (select_svc(fmri) != 1) 10303 return; 10304 } 10305 10306 err = 0; 10307 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 10308 select_callback, NULL, &err, semerr)) != 0) { 10309 semerr(gettext("Failed to walk instances: %s\n"), 10310 scf_strerror(ret)); 10311 } 10312 } 10313 10314 void 10315 lscf_unselect(void) 10316 { 10317 lscf_prep_hndl(); 10318 10319 if (cur_snap != NULL) { 10320 struct snaplevel *elt; 10321 10322 elt = uu_list_prev(cur_levels, cur_elt); 10323 if (elt == NULL) { 10324 semerr(gettext("No parent levels.\n")); 10325 } else { 10326 cur_elt = elt; 10327 cur_level = elt->sl; 10328 } 10329 } else if (cur_inst != NULL) { 10330 scf_instance_destroy(cur_inst); 10331 cur_inst = NULL; 10332 } else if (cur_svc != NULL) { 10333 scf_service_destroy(cur_svc); 10334 cur_svc = NULL; 10335 } else { 10336 semerr(gettext("Cannot unselect at scope level.\n")); 10337 } 10338 } 10339 10340 /* 10341 * Return the FMRI of the current selection, for the prompt. 10342 */ 10343 void 10344 lscf_get_selection_str(char *buf, size_t bufsz) 10345 { 10346 char *cp; 10347 ssize_t fmrilen, szret; 10348 boolean_t deleted = B_FALSE; 10349 10350 if (g_hndl == NULL) { 10351 (void) strlcpy(buf, "svc:", bufsz); 10352 return; 10353 } 10354 10355 if (cur_level != NULL) { 10356 assert(cur_snap != NULL); 10357 10358 /* [ snapshot ] FMRI [: instance ] */ 10359 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 10360 + 2 + max_scf_name_len + 1 + 1); 10361 10362 buf[0] = '['; 10363 10364 szret = scf_snapshot_get_name(cur_snap, buf + 1, 10365 max_scf_name_len + 1); 10366 if (szret < 0) { 10367 if (scf_error() != SCF_ERROR_DELETED) 10368 scfdie(); 10369 10370 goto snap_deleted; 10371 } 10372 10373 (void) strcat(buf, "]svc:/"); 10374 10375 cp = strchr(buf, '\0'); 10376 10377 szret = scf_snaplevel_get_service_name(cur_level, cp, 10378 max_scf_name_len + 1); 10379 if (szret < 0) { 10380 if (scf_error() != SCF_ERROR_DELETED) 10381 scfdie(); 10382 10383 goto snap_deleted; 10384 } 10385 10386 cp = strchr(cp, '\0'); 10387 10388 if (snaplevel_is_instance(cur_level)) { 10389 *cp++ = ':'; 10390 10391 if (scf_snaplevel_get_instance_name(cur_level, cp, 10392 max_scf_name_len + 1) < 0) { 10393 if (scf_error() != SCF_ERROR_DELETED) 10394 scfdie(); 10395 10396 goto snap_deleted; 10397 } 10398 } else { 10399 *cp++ = '['; 10400 *cp++ = ':'; 10401 10402 if (scf_instance_get_name(cur_inst, cp, 10403 max_scf_name_len + 1) < 0) { 10404 if (scf_error() != SCF_ERROR_DELETED) 10405 scfdie(); 10406 10407 goto snap_deleted; 10408 } 10409 10410 (void) strcat(buf, "]"); 10411 } 10412 10413 return; 10414 10415 snap_deleted: 10416 deleted = B_TRUE; 10417 free(buf); 10418 unselect_cursnap(); 10419 } 10420 10421 assert(cur_snap == NULL); 10422 10423 if (cur_inst != NULL) { 10424 assert(cur_svc != NULL); 10425 assert(cur_scope != NULL); 10426 10427 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 10428 if (fmrilen >= 0) { 10429 assert(fmrilen < bufsz); 10430 if (deleted) 10431 warn(emsg_deleted); 10432 return; 10433 } 10434 10435 if (scf_error() != SCF_ERROR_DELETED) 10436 scfdie(); 10437 10438 deleted = B_TRUE; 10439 10440 scf_instance_destroy(cur_inst); 10441 cur_inst = NULL; 10442 } 10443 10444 if (cur_svc != NULL) { 10445 assert(cur_scope != NULL); 10446 10447 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 10448 if (szret >= 0) { 10449 assert(szret < bufsz); 10450 if (deleted) 10451 warn(emsg_deleted); 10452 return; 10453 } 10454 10455 if (scf_error() != SCF_ERROR_DELETED) 10456 scfdie(); 10457 10458 deleted = B_TRUE; 10459 scf_service_destroy(cur_svc); 10460 cur_svc = NULL; 10461 } 10462 10463 assert(cur_scope != NULL); 10464 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 10465 10466 if (fmrilen < 0) 10467 scfdie(); 10468 10469 assert(fmrilen < bufsz); 10470 if (deleted) 10471 warn(emsg_deleted); 10472 } 10473 10474 /* 10475 * Entity listing. Entities and colon namespaces (e.g., :properties and 10476 * :statistics) are listed for the current selection. 10477 */ 10478 void 10479 lscf_list(const char *pattern) 10480 { 10481 scf_iter_t *iter; 10482 char *buf; 10483 int ret; 10484 10485 lscf_prep_hndl(); 10486 10487 if (cur_level != NULL) { 10488 struct snaplevel *elt; 10489 10490 (void) fputs(COLON_NAMESPACES, stdout); 10491 10492 elt = uu_list_next(cur_levels, cur_elt); 10493 if (elt == NULL) 10494 return; 10495 10496 /* 10497 * For now, we know that the next level is an instance. But 10498 * if we ever have multiple scopes, this could be complicated. 10499 */ 10500 buf = safe_malloc(max_scf_name_len + 1); 10501 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10502 max_scf_name_len + 1) >= 0) { 10503 (void) puts(buf); 10504 } else { 10505 if (scf_error() != SCF_ERROR_DELETED) 10506 scfdie(); 10507 } 10508 10509 free(buf); 10510 10511 return; 10512 } 10513 10514 if (cur_inst != NULL) { 10515 (void) fputs(COLON_NAMESPACES, stdout); 10516 return; 10517 } 10518 10519 iter = scf_iter_create(g_hndl); 10520 if (iter == NULL) 10521 scfdie(); 10522 10523 buf = safe_malloc(max_scf_name_len + 1); 10524 10525 if (cur_svc != NULL) { 10526 /* List the instances in this service. */ 10527 scf_instance_t *inst; 10528 10529 inst = scf_instance_create(g_hndl); 10530 if (inst == NULL) 10531 scfdie(); 10532 10533 if (scf_iter_service_instances(iter, cur_svc) == 0) { 10534 safe_printf(COLON_NAMESPACES); 10535 10536 for (;;) { 10537 ret = scf_iter_next_instance(iter, inst); 10538 if (ret == 0) 10539 break; 10540 if (ret != 1) { 10541 if (scf_error() != SCF_ERROR_DELETED) 10542 scfdie(); 10543 10544 break; 10545 } 10546 10547 if (scf_instance_get_name(inst, buf, 10548 max_scf_name_len + 1) >= 0) { 10549 if (pattern == NULL || 10550 fnmatch(pattern, buf, 0) == 0) 10551 (void) puts(buf); 10552 } else { 10553 if (scf_error() != SCF_ERROR_DELETED) 10554 scfdie(); 10555 } 10556 } 10557 } else { 10558 if (scf_error() != SCF_ERROR_DELETED) 10559 scfdie(); 10560 } 10561 10562 scf_instance_destroy(inst); 10563 } else { 10564 /* List the services in this scope. */ 10565 scf_service_t *svc; 10566 10567 assert(cur_scope != NULL); 10568 10569 svc = scf_service_create(g_hndl); 10570 if (svc == NULL) 10571 scfdie(); 10572 10573 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 10574 scfdie(); 10575 10576 for (;;) { 10577 ret = scf_iter_next_service(iter, svc); 10578 if (ret == 0) 10579 break; 10580 if (ret != 1) 10581 scfdie(); 10582 10583 if (scf_service_get_name(svc, buf, 10584 max_scf_name_len + 1) >= 0) { 10585 if (pattern == NULL || 10586 fnmatch(pattern, buf, 0) == 0) 10587 safe_printf("%s\n", buf); 10588 } else { 10589 if (scf_error() != SCF_ERROR_DELETED) 10590 scfdie(); 10591 } 10592 } 10593 10594 scf_service_destroy(svc); 10595 } 10596 10597 free(buf); 10598 scf_iter_destroy(iter); 10599 } 10600 10601 /* 10602 * Entity addition. Creates an empty entity in the current selection. 10603 */ 10604 void 10605 lscf_add(const char *name) 10606 { 10607 lscf_prep_hndl(); 10608 10609 if (cur_snap != NULL) { 10610 semerr(emsg_cant_modify_snapshots); 10611 } else if (cur_inst != NULL) { 10612 semerr(gettext("Cannot add entities to an instance.\n")); 10613 } else if (cur_svc != NULL) { 10614 10615 if (scf_service_add_instance(cur_svc, name, NULL) != 10616 SCF_SUCCESS) { 10617 switch (scf_error()) { 10618 case SCF_ERROR_INVALID_ARGUMENT: 10619 semerr(gettext("Invalid name.\n")); 10620 break; 10621 10622 case SCF_ERROR_EXISTS: 10623 semerr(gettext("Instance already exists.\n")); 10624 break; 10625 10626 case SCF_ERROR_PERMISSION_DENIED: 10627 semerr(emsg_permission_denied); 10628 break; 10629 10630 default: 10631 scfdie(); 10632 } 10633 } 10634 } else { 10635 assert(cur_scope != NULL); 10636 10637 if (scf_scope_add_service(cur_scope, name, NULL) != 10638 SCF_SUCCESS) { 10639 switch (scf_error()) { 10640 case SCF_ERROR_INVALID_ARGUMENT: 10641 semerr(gettext("Invalid name.\n")); 10642 break; 10643 10644 case SCF_ERROR_EXISTS: 10645 semerr(gettext("Service already exists.\n")); 10646 break; 10647 10648 case SCF_ERROR_PERMISSION_DENIED: 10649 semerr(emsg_permission_denied); 10650 break; 10651 10652 case SCF_ERROR_BACKEND_READONLY: 10653 semerr(emsg_read_only); 10654 break; 10655 10656 default: 10657 scfdie(); 10658 } 10659 } 10660 } 10661 } 10662 10663 /* return 1 if the entity has no persistent pgs, else return 0 */ 10664 static int 10665 entity_has_no_pgs(void *ent, int isservice) 10666 { 10667 scf_iter_t *iter = NULL; 10668 scf_propertygroup_t *pg = NULL; 10669 uint32_t flags; 10670 int err; 10671 int ret = 1; 10672 10673 if ((iter = scf_iter_create(g_hndl)) == NULL || 10674 (pg = scf_pg_create(g_hndl)) == NULL) 10675 scfdie(); 10676 10677 if (isservice) { 10678 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 10679 scfdie(); 10680 } else { 10681 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 10682 scfdie(); 10683 } 10684 10685 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 10686 if (scf_pg_get_flags(pg, &flags) != 0) 10687 scfdie(); 10688 10689 /* skip nonpersistent pgs */ 10690 if (flags & SCF_PG_FLAG_NONPERSISTENT) 10691 continue; 10692 10693 ret = 0; 10694 break; 10695 } 10696 10697 if (err == -1) 10698 scfdie(); 10699 10700 scf_pg_destroy(pg); 10701 scf_iter_destroy(iter); 10702 10703 return (ret); 10704 } 10705 10706 /* return 1 if the service has no instances, else return 0 */ 10707 static int 10708 svc_has_no_insts(scf_service_t *svc) 10709 { 10710 scf_instance_t *inst; 10711 scf_iter_t *iter; 10712 int r; 10713 int ret = 1; 10714 10715 if ((inst = scf_instance_create(g_hndl)) == NULL || 10716 (iter = scf_iter_create(g_hndl)) == NULL) 10717 scfdie(); 10718 10719 if (scf_iter_service_instances(iter, svc) != 0) 10720 scfdie(); 10721 10722 r = scf_iter_next_instance(iter, inst); 10723 if (r == 1) { 10724 ret = 0; 10725 } else if (r == 0) { 10726 ret = 1; 10727 } else if (r == -1) { 10728 scfdie(); 10729 } else { 10730 bad_error("scf_iter_next_instance", r); 10731 } 10732 10733 scf_iter_destroy(iter); 10734 scf_instance_destroy(inst); 10735 10736 return (ret); 10737 } 10738 10739 /* 10740 * Entity deletion. 10741 */ 10742 10743 /* 10744 * Delete the property group <fmri>/:properties/<name>. Returns 10745 * SCF_ERROR_NONE on success (or if the entity is not found), 10746 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 10747 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 10748 * denied. 10749 */ 10750 static scf_error_t 10751 delete_dependency_pg(const char *fmri, const char *name) 10752 { 10753 void *entity = NULL; 10754 int isservice; 10755 scf_propertygroup_t *pg = NULL; 10756 scf_error_t result; 10757 char *pgty; 10758 scf_service_t *svc = NULL; 10759 scf_instance_t *inst = NULL; 10760 scf_iter_t *iter = NULL; 10761 char *name_buf = NULL; 10762 10763 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10764 switch (result) { 10765 case SCF_ERROR_NONE: 10766 break; 10767 10768 case SCF_ERROR_NO_MEMORY: 10769 uu_die(gettext("Out of memory.\n")); 10770 /* NOTREACHED */ 10771 10772 case SCF_ERROR_INVALID_ARGUMENT: 10773 case SCF_ERROR_CONSTRAINT_VIOLATED: 10774 return (SCF_ERROR_INVALID_ARGUMENT); 10775 10776 case SCF_ERROR_NOT_FOUND: 10777 result = SCF_ERROR_NONE; 10778 goto out; 10779 10780 default: 10781 bad_error("fmri_to_entity", result); 10782 } 10783 10784 pg = scf_pg_create(g_hndl); 10785 if (pg == NULL) 10786 scfdie(); 10787 10788 if (entity_get_pg(entity, isservice, name, pg) != 0) { 10789 if (scf_error() != SCF_ERROR_NOT_FOUND) 10790 scfdie(); 10791 10792 result = SCF_ERROR_NONE; 10793 goto out; 10794 } 10795 10796 pgty = safe_malloc(max_scf_pg_type_len + 1); 10797 10798 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10799 scfdie(); 10800 10801 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 10802 result = SCF_ERROR_TYPE_MISMATCH; 10803 free(pgty); 10804 goto out; 10805 } 10806 10807 free(pgty); 10808 10809 if (scf_pg_delete(pg) != 0) { 10810 result = scf_error(); 10811 if (result != SCF_ERROR_PERMISSION_DENIED) 10812 scfdie(); 10813 goto out; 10814 } 10815 10816 /* 10817 * We have to handle the case where we've just deleted the last 10818 * property group of a "dummy" entity (instance or service). 10819 * A "dummy" entity is an entity only present to hold an 10820 * external dependency. 10821 * So, in the case we deleted the last property group then we 10822 * can also delete the entity. If the entity is an instance then 10823 * we must verify if this was the last instance for the service 10824 * and if it is, we can also delete the service if it doesn't 10825 * have any property group either. 10826 */ 10827 10828 result = SCF_ERROR_NONE; 10829 10830 if (isservice) { 10831 svc = (scf_service_t *)entity; 10832 10833 if ((inst = scf_instance_create(g_hndl)) == NULL || 10834 (iter = scf_iter_create(g_hndl)) == NULL) 10835 scfdie(); 10836 10837 name_buf = safe_malloc(max_scf_name_len + 1); 10838 } else { 10839 inst = (scf_instance_t *)entity; 10840 } 10841 10842 /* 10843 * If the entity is an instance and we've just deleted its last 10844 * property group then we should delete it. 10845 */ 10846 if (!isservice && entity_has_no_pgs(entity, isservice)) { 10847 /* find the service before deleting the inst. - needed later */ 10848 if ((svc = scf_service_create(g_hndl)) == NULL) 10849 scfdie(); 10850 10851 if (scf_instance_get_parent(inst, svc) != 0) 10852 scfdie(); 10853 10854 /* delete the instance */ 10855 if (scf_instance_delete(inst) != 0) { 10856 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10857 scfdie(); 10858 10859 result = SCF_ERROR_PERMISSION_DENIED; 10860 goto out; 10861 } 10862 /* no need to refresh the instance */ 10863 inst = NULL; 10864 } 10865 10866 /* 10867 * If the service has no more instances and pgs or we just deleted the 10868 * last instance and the service doesn't have anymore propery groups 10869 * then the service should be deleted. 10870 */ 10871 if (svc != NULL && 10872 svc_has_no_insts(svc) && 10873 entity_has_no_pgs((void *)svc, 1)) { 10874 if (scf_service_delete(svc) == 0) { 10875 if (isservice) { 10876 /* no need to refresh the service */ 10877 svc = NULL; 10878 } 10879 10880 goto out; 10881 } 10882 10883 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10884 scfdie(); 10885 10886 result = SCF_ERROR_PERMISSION_DENIED; 10887 } 10888 10889 /* if the entity has not been deleted, refresh it */ 10890 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 10891 (void) refresh_entity(isservice, entity, fmri, inst, iter, 10892 name_buf); 10893 } 10894 10895 out: 10896 if (isservice && (inst != NULL && iter != NULL)) { 10897 free(name_buf); 10898 scf_iter_destroy(iter); 10899 scf_instance_destroy(inst); 10900 } 10901 10902 if (!isservice && svc != NULL) { 10903 scf_service_destroy(svc); 10904 } 10905 10906 scf_pg_destroy(pg); 10907 if (entity != NULL) 10908 entity_destroy(entity, isservice); 10909 10910 return (result); 10911 } 10912 10913 static int 10914 delete_dependents(scf_propertygroup_t *pg) 10915 { 10916 char *pgty, *name, *fmri; 10917 scf_property_t *prop; 10918 scf_value_t *val; 10919 scf_iter_t *iter; 10920 int r; 10921 scf_error_t err; 10922 10923 /* Verify that the pg has the correct type. */ 10924 pgty = safe_malloc(max_scf_pg_type_len + 1); 10925 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10926 scfdie(); 10927 10928 if (strcmp(pgty, scf_group_framework) != 0) { 10929 if (g_verbose) { 10930 fmri = safe_malloc(max_scf_fmri_len + 1); 10931 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 10932 scfdie(); 10933 10934 warn(gettext("Property group %s is not of expected " 10935 "type %s.\n"), fmri, scf_group_framework); 10936 10937 free(fmri); 10938 } 10939 10940 free(pgty); 10941 return (-1); 10942 } 10943 10944 free(pgty); 10945 10946 /* map delete_dependency_pg onto the properties. */ 10947 if ((prop = scf_property_create(g_hndl)) == NULL || 10948 (val = scf_value_create(g_hndl)) == NULL || 10949 (iter = scf_iter_create(g_hndl)) == NULL) 10950 scfdie(); 10951 10952 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10953 scfdie(); 10954 10955 name = safe_malloc(max_scf_name_len + 1); 10956 fmri = safe_malloc(max_scf_fmri_len + 2); 10957 10958 while ((r = scf_iter_next_property(iter, prop)) == 1) { 10959 scf_type_t ty; 10960 10961 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 10962 scfdie(); 10963 10964 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 10965 scfdie(); 10966 10967 if ((ty != SCF_TYPE_ASTRING && 10968 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 10969 prop_get_val(prop, val) != 0) 10970 continue; 10971 10972 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 10973 scfdie(); 10974 10975 err = delete_dependency_pg(fmri, name); 10976 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 10977 if (scf_property_to_fmri(prop, fmri, 10978 max_scf_fmri_len + 2) < 0) 10979 scfdie(); 10980 10981 warn(gettext("Value of %s is not a valid FMRI.\n"), 10982 fmri); 10983 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 10984 warn(gettext("Property group \"%s\" of entity \"%s\" " 10985 "does not have dependency type.\n"), name, fmri); 10986 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 10987 warn(gettext("Could not delete property group \"%s\" " 10988 "of entity \"%s\" (permission denied).\n"), name, 10989 fmri); 10990 } 10991 } 10992 if (r == -1) 10993 scfdie(); 10994 10995 scf_value_destroy(val); 10996 scf_property_destroy(prop); 10997 10998 return (0); 10999 } 11000 11001 /* 11002 * Returns 1 if the instance may be running, and 0 otherwise. 11003 */ 11004 static int 11005 inst_is_running(scf_instance_t *inst) 11006 { 11007 scf_propertygroup_t *pg; 11008 scf_property_t *prop; 11009 scf_value_t *val; 11010 char buf[MAX_SCF_STATE_STRING_SZ]; 11011 int ret = 0; 11012 ssize_t szret; 11013 11014 if ((pg = scf_pg_create(g_hndl)) == NULL || 11015 (prop = scf_property_create(g_hndl)) == NULL || 11016 (val = scf_value_create(g_hndl)) == NULL) 11017 scfdie(); 11018 11019 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 11020 if (scf_error() != SCF_ERROR_NOT_FOUND) 11021 scfdie(); 11022 goto out; 11023 } 11024 11025 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 11026 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 11027 prop_get_val(prop, val) != 0) 11028 goto out; 11029 11030 szret = scf_value_get_astring(val, buf, sizeof (buf)); 11031 assert(szret >= 0); 11032 11033 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 11034 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 11035 11036 out: 11037 scf_value_destroy(val); 11038 scf_property_destroy(prop); 11039 scf_pg_destroy(pg); 11040 return (ret); 11041 } 11042 11043 static uint8_t 11044 pg_is_external_dependency(scf_propertygroup_t *pg) 11045 { 11046 char *type; 11047 scf_value_t *val; 11048 scf_property_t *prop; 11049 uint8_t b = B_FALSE; 11050 11051 type = safe_malloc(max_scf_pg_type_len + 1); 11052 11053 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 11054 scfdie(); 11055 11056 if ((prop = scf_property_create(g_hndl)) == NULL || 11057 (val = scf_value_create(g_hndl)) == NULL) 11058 scfdie(); 11059 11060 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 11061 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 11062 if (scf_property_get_value(prop, val) != 0) 11063 scfdie(); 11064 if (scf_value_get_boolean(val, &b) != 0) 11065 scfdie(); 11066 } 11067 } 11068 11069 free(type); 11070 (void) scf_value_destroy(val); 11071 (void) scf_property_destroy(prop); 11072 11073 return (b); 11074 } 11075 11076 #define DELETE_FAILURE -1 11077 #define DELETE_SUCCESS_NOEXTDEPS 0 11078 #define DELETE_SUCCESS_EXTDEPS 1 11079 11080 /* 11081 * lscf_instance_delete() deletes an instance. Before calling 11082 * scf_instance_delete(), though, we make sure the instance isn't 11083 * running and delete dependencies in other entities which the instance 11084 * declared as "dependents". If there are dependencies which were 11085 * created for other entities, then instead of deleting the instance we 11086 * make it "empty" by deleting all other property groups and all 11087 * snapshots. 11088 * 11089 * lscf_instance_delete() verifies that there is no external dependency pgs 11090 * before suppressing the instance. If there is, then we must not remove them 11091 * now in case the instance is re-created otherwise the dependencies would be 11092 * lost. The external dependency pgs will be removed if the dependencies are 11093 * removed. 11094 * 11095 * Returns: 11096 * DELETE_FAILURE on failure 11097 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 11098 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 11099 */ 11100 static int 11101 lscf_instance_delete(scf_instance_t *inst, int force) 11102 { 11103 scf_propertygroup_t *pg; 11104 scf_snapshot_t *snap; 11105 scf_iter_t *iter; 11106 int err; 11107 int external = 0; 11108 11109 /* If we're not forcing and the instance is running, refuse. */ 11110 if (!force && inst_is_running(inst)) { 11111 char *fmri; 11112 11113 fmri = safe_malloc(max_scf_fmri_len + 1); 11114 11115 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 11116 scfdie(); 11117 11118 semerr(gettext("Instance %s may be running. " 11119 "Use delete -f if it is not.\n"), fmri); 11120 11121 free(fmri); 11122 return (DELETE_FAILURE); 11123 } 11124 11125 pg = scf_pg_create(g_hndl); 11126 if (pg == NULL) 11127 scfdie(); 11128 11129 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 11130 (void) delete_dependents(pg); 11131 else if (scf_error() != SCF_ERROR_NOT_FOUND) 11132 scfdie(); 11133 11134 scf_pg_destroy(pg); 11135 11136 /* 11137 * If the instance has some external dependencies then we must 11138 * keep them in case the instance is reimported otherwise the 11139 * dependencies would be lost on reimport. 11140 */ 11141 if ((iter = scf_iter_create(g_hndl)) == NULL || 11142 (pg = scf_pg_create(g_hndl)) == NULL) 11143 scfdie(); 11144 11145 if (scf_iter_instance_pgs(iter, inst) < 0) 11146 scfdie(); 11147 11148 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11149 if (pg_is_external_dependency(pg)) { 11150 external = 1; 11151 continue; 11152 } 11153 11154 if (scf_pg_delete(pg) != 0) { 11155 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11156 scfdie(); 11157 else { 11158 semerr(emsg_permission_denied); 11159 11160 (void) scf_iter_destroy(iter); 11161 (void) scf_pg_destroy(pg); 11162 return (DELETE_FAILURE); 11163 } 11164 } 11165 } 11166 11167 if (err == -1) 11168 scfdie(); 11169 11170 (void) scf_iter_destroy(iter); 11171 (void) scf_pg_destroy(pg); 11172 11173 if (external) { 11174 /* 11175 * All the pgs have been deleted for the instance except 11176 * the ones holding the external dependencies. 11177 * For the job to be complete, we must also delete the 11178 * snapshots associated with the instance. 11179 */ 11180 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 11181 NULL) 11182 scfdie(); 11183 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 11184 scfdie(); 11185 11186 if (scf_iter_instance_snapshots(iter, inst) == -1) 11187 scfdie(); 11188 11189 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 11190 if (_scf_snapshot_delete(snap) != 0) { 11191 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11192 scfdie(); 11193 11194 semerr(emsg_permission_denied); 11195 11196 (void) scf_iter_destroy(iter); 11197 (void) scf_snapshot_destroy(snap); 11198 return (DELETE_FAILURE); 11199 } 11200 } 11201 11202 if (err == -1) 11203 scfdie(); 11204 11205 (void) scf_iter_destroy(iter); 11206 (void) scf_snapshot_destroy(snap); 11207 return (DELETE_SUCCESS_EXTDEPS); 11208 } 11209 11210 if (scf_instance_delete(inst) != 0) { 11211 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11212 scfdie(); 11213 11214 semerr(emsg_permission_denied); 11215 11216 return (DELETE_FAILURE); 11217 } 11218 11219 return (DELETE_SUCCESS_NOEXTDEPS); 11220 } 11221 11222 /* 11223 * lscf_service_delete() deletes a service. Before calling 11224 * scf_service_delete(), though, we call lscf_instance_delete() for 11225 * each of the instances and delete dependencies in other entities 11226 * which were created as "dependents" of this service. If there are 11227 * dependencies which were created for other entities, then we delete 11228 * all other property groups in the service and leave it as "empty". 11229 * 11230 * lscf_service_delete() verifies that there is no external dependency 11231 * pgs at the instance & service level before suppressing the service. 11232 * If there is, then we must not remove them now in case the service 11233 * is re-imported otherwise the dependencies would be lost. The external 11234 * dependency pgs will be removed if the dependencies are removed. 11235 * 11236 * Returns: 11237 * DELETE_FAILURE on failure 11238 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 11239 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 11240 */ 11241 static int 11242 lscf_service_delete(scf_service_t *svc, int force) 11243 { 11244 int r; 11245 scf_instance_t *inst; 11246 scf_propertygroup_t *pg; 11247 scf_iter_t *iter; 11248 int ret; 11249 int external = 0; 11250 11251 if ((inst = scf_instance_create(g_hndl)) == NULL || 11252 (pg = scf_pg_create(g_hndl)) == NULL || 11253 (iter = scf_iter_create(g_hndl)) == NULL) 11254 scfdie(); 11255 11256 if (scf_iter_service_instances(iter, svc) != 0) 11257 scfdie(); 11258 11259 for (r = scf_iter_next_instance(iter, inst); 11260 r == 1; 11261 r = scf_iter_next_instance(iter, inst)) { 11262 11263 ret = lscf_instance_delete(inst, force); 11264 if (ret == DELETE_FAILURE) { 11265 scf_iter_destroy(iter); 11266 scf_pg_destroy(pg); 11267 scf_instance_destroy(inst); 11268 return (DELETE_FAILURE); 11269 } 11270 11271 /* 11272 * Record the fact that there is some external dependencies 11273 * at the instance level. 11274 */ 11275 if (ret == DELETE_SUCCESS_EXTDEPS) 11276 external |= 1; 11277 } 11278 11279 if (r != 0) 11280 scfdie(); 11281 11282 /* Delete dependency property groups in dependent services. */ 11283 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 11284 (void) delete_dependents(pg); 11285 else if (scf_error() != SCF_ERROR_NOT_FOUND) 11286 scfdie(); 11287 11288 scf_iter_destroy(iter); 11289 scf_pg_destroy(pg); 11290 scf_instance_destroy(inst); 11291 11292 /* 11293 * If the service has some external dependencies then we don't 11294 * want to remove them in case the service is re-imported. 11295 */ 11296 if ((pg = scf_pg_create(g_hndl)) == NULL || 11297 (iter = scf_iter_create(g_hndl)) == NULL) 11298 scfdie(); 11299 11300 if (scf_iter_service_pgs(iter, svc) < 0) 11301 scfdie(); 11302 11303 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 11304 if (pg_is_external_dependency(pg)) { 11305 external |= 2; 11306 continue; 11307 } 11308 11309 if (scf_pg_delete(pg) != 0) { 11310 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11311 scfdie(); 11312 else { 11313 semerr(emsg_permission_denied); 11314 11315 (void) scf_iter_destroy(iter); 11316 (void) scf_pg_destroy(pg); 11317 return (DELETE_FAILURE); 11318 } 11319 } 11320 } 11321 11322 if (r == -1) 11323 scfdie(); 11324 11325 (void) scf_iter_destroy(iter); 11326 (void) scf_pg_destroy(pg); 11327 11328 if (external != 0) 11329 return (DELETE_SUCCESS_EXTDEPS); 11330 11331 if (scf_service_delete(svc) == 0) 11332 return (DELETE_SUCCESS_NOEXTDEPS); 11333 11334 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11335 scfdie(); 11336 11337 semerr(emsg_permission_denied); 11338 return (DELETE_FAILURE); 11339 } 11340 11341 static int 11342 delete_callback(void *data, scf_walkinfo_t *wip) 11343 { 11344 int force = (int)data; 11345 11346 if (wip->inst != NULL) 11347 (void) lscf_instance_delete(wip->inst, force); 11348 else 11349 (void) lscf_service_delete(wip->svc, force); 11350 11351 return (0); 11352 } 11353 11354 void 11355 lscf_delete(const char *fmri, int force) 11356 { 11357 scf_service_t *svc; 11358 scf_instance_t *inst; 11359 int ret; 11360 11361 lscf_prep_hndl(); 11362 11363 if (cur_snap != NULL) { 11364 if (!snaplevel_is_instance(cur_level)) { 11365 char *buf; 11366 11367 buf = safe_malloc(max_scf_name_len + 1); 11368 if (scf_instance_get_name(cur_inst, buf, 11369 max_scf_name_len + 1) >= 0) { 11370 if (strcmp(buf, fmri) == 0) { 11371 semerr(emsg_cant_modify_snapshots); 11372 free(buf); 11373 return; 11374 } 11375 } else if (scf_error() != SCF_ERROR_DELETED) { 11376 scfdie(); 11377 } 11378 free(buf); 11379 } 11380 } else if (cur_inst != NULL) { 11381 /* EMPTY */; 11382 } else if (cur_svc != NULL) { 11383 inst = scf_instance_create(g_hndl); 11384 if (inst == NULL) 11385 scfdie(); 11386 11387 if (scf_service_get_instance(cur_svc, fmri, inst) == 11388 SCF_SUCCESS) { 11389 (void) lscf_instance_delete(inst, force); 11390 scf_instance_destroy(inst); 11391 return; 11392 } 11393 11394 if (scf_error() != SCF_ERROR_NOT_FOUND && 11395 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 11396 scfdie(); 11397 11398 scf_instance_destroy(inst); 11399 } else { 11400 assert(cur_scope != NULL); 11401 11402 svc = scf_service_create(g_hndl); 11403 if (svc == NULL) 11404 scfdie(); 11405 11406 if (scf_scope_get_service(cur_scope, fmri, svc) == 11407 SCF_SUCCESS) { 11408 (void) lscf_service_delete(svc, force); 11409 scf_service_destroy(svc); 11410 return; 11411 } 11412 11413 if (scf_error() != SCF_ERROR_NOT_FOUND && 11414 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 11415 scfdie(); 11416 11417 scf_service_destroy(svc); 11418 } 11419 11420 /* 11421 * Match FMRI to entity. 11422 */ 11423 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11424 delete_callback, (void *)force, NULL, semerr)) != 0) { 11425 semerr(gettext("Failed to walk instances: %s\n"), 11426 scf_strerror(ret)); 11427 } 11428 } 11429 11430 11431 11432 /* 11433 * :properties commands. These all end with "pg" or "prop" and generally 11434 * operate on the currently selected entity. 11435 */ 11436 11437 /* 11438 * Property listing. List the property groups, properties, their types and 11439 * their values for the currently selected entity. 11440 */ 11441 static void 11442 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 11443 { 11444 char *buf; 11445 uint32_t flags; 11446 11447 buf = safe_malloc(max_scf_pg_type_len + 1); 11448 11449 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 11450 scfdie(); 11451 11452 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 11453 scfdie(); 11454 11455 safe_printf("%-*s %s", namewidth, name, buf); 11456 11457 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11458 safe_printf("\tNONPERSISTENT"); 11459 11460 safe_printf("\n"); 11461 11462 free(buf); 11463 } 11464 11465 static boolean_t 11466 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 11467 { 11468 if (scf_property_get_value(prop, val) == 0) { 11469 return (B_FALSE); 11470 } else { 11471 switch (scf_error()) { 11472 case SCF_ERROR_NOT_FOUND: 11473 return (B_FALSE); 11474 case SCF_ERROR_PERMISSION_DENIED: 11475 case SCF_ERROR_CONSTRAINT_VIOLATED: 11476 return (B_TRUE); 11477 default: 11478 scfdie(); 11479 /*NOTREACHED*/ 11480 } 11481 } 11482 } 11483 11484 static void 11485 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 11486 { 11487 scf_iter_t *iter; 11488 scf_value_t *val; 11489 const char *type; 11490 int multiple_strings = 0; 11491 int ret; 11492 11493 if ((iter = scf_iter_create(g_hndl)) == NULL || 11494 (val = scf_value_create(g_hndl)) == NULL) 11495 scfdie(); 11496 11497 type = prop_to_typestr(prop); 11498 assert(type != NULL); 11499 11500 safe_printf("%-*s %-7s ", len, name, type); 11501 11502 if (prop_has_multiple_values(prop, val) && 11503 (scf_value_type(val) == SCF_TYPE_ASTRING || 11504 scf_value_type(val) == SCF_TYPE_USTRING)) 11505 multiple_strings = 1; 11506 11507 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11508 scfdie(); 11509 11510 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11511 char *buf; 11512 ssize_t vlen, szret; 11513 11514 vlen = scf_value_get_as_string(val, NULL, 0); 11515 if (vlen < 0) 11516 scfdie(); 11517 11518 buf = safe_malloc(vlen + 1); 11519 11520 szret = scf_value_get_as_string(val, buf, vlen + 1); 11521 if (szret < 0) 11522 scfdie(); 11523 assert(szret <= vlen); 11524 11525 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11526 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 11527 safe_printf(" \""); 11528 (void) quote_and_print(buf, stdout, 0); 11529 (void) putchar('"'); 11530 if (ferror(stdout)) { 11531 (void) putchar('\n'); 11532 uu_die(gettext("Error writing to stdout.\n")); 11533 } 11534 } else { 11535 safe_printf(" %s", buf); 11536 } 11537 11538 free(buf); 11539 } 11540 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11541 scfdie(); 11542 11543 if (putchar('\n') != '\n') 11544 uu_die(gettext("Could not output newline")); 11545 } 11546 11547 /* 11548 * Outputs template property group info for the describe subcommand. 11549 * If 'templates' == 2, verbose output is printed in the format expected 11550 * for describe -v, which includes all templates fields. If pg is 11551 * not NULL, we're describing the template data, not an existing property 11552 * group, and formatting should be appropriate for describe -t. 11553 */ 11554 static void 11555 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 11556 { 11557 char *buf; 11558 uint8_t required; 11559 scf_property_t *stability_prop; 11560 scf_value_t *stability_val; 11561 11562 if (templates == 0) 11563 return; 11564 11565 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 11566 (stability_val = scf_value_create(g_hndl)) == NULL) 11567 scfdie(); 11568 11569 if (templates == 2 && pg != NULL) { 11570 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 11571 stability_prop) == 0) { 11572 if (prop_check_type(stability_prop, 11573 SCF_TYPE_ASTRING) == 0 && 11574 prop_get_val(stability_prop, stability_val) == 0) { 11575 char *stability; 11576 11577 stability = safe_malloc(max_scf_value_len + 1); 11578 11579 if (scf_value_get_astring(stability_val, 11580 stability, max_scf_value_len + 1) == -1 && 11581 scf_error() != SCF_ERROR_NOT_FOUND) 11582 scfdie(); 11583 11584 safe_printf("%s%s: %s\n", TMPL_INDENT, 11585 gettext("stability"), stability); 11586 11587 free(stability); 11588 } 11589 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 11590 scfdie(); 11591 } 11592 11593 scf_property_destroy(stability_prop); 11594 scf_value_destroy(stability_val); 11595 11596 if (pgt == NULL) 11597 return; 11598 11599 if (pg == NULL || templates == 2) { 11600 /* print type info only if scf_tmpl_pg_name succeeds */ 11601 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 11602 if (pg != NULL) 11603 safe_printf("%s", TMPL_INDENT); 11604 safe_printf("%s: ", gettext("name")); 11605 safe_printf("%s\n", buf); 11606 free(buf); 11607 } 11608 11609 /* print type info only if scf_tmpl_pg_type succeeds */ 11610 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 11611 if (pg != NULL) 11612 safe_printf("%s", TMPL_INDENT); 11613 safe_printf("%s: ", gettext("type")); 11614 safe_printf("%s\n", buf); 11615 free(buf); 11616 } 11617 } 11618 11619 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 11620 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11621 required ? "true" : "false"); 11622 11623 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 11624 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 11625 buf); 11626 free(buf); 11627 } 11628 11629 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 11630 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11631 buf); 11632 free(buf); 11633 } 11634 11635 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 11636 if (templates == 2) 11637 safe_printf("%s%s: %s\n", TMPL_INDENT, 11638 gettext("description"), buf); 11639 else 11640 safe_printf("%s%s\n", TMPL_INDENT, buf); 11641 free(buf); 11642 } 11643 11644 } 11645 11646 /* 11647 * With as_value set to true, indent as appropriate for the value level. 11648 * If false, indent to appropriate level for inclusion in constraint 11649 * or choice printout. 11650 */ 11651 static void 11652 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 11653 int as_value) 11654 { 11655 char *buf; 11656 11657 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 11658 if (as_value == 0) 11659 safe_printf("%s", TMPL_CHOICE_INDENT); 11660 else 11661 safe_printf("%s", TMPL_INDENT); 11662 safe_printf("%s: %s\n", gettext("value common name"), buf); 11663 free(buf); 11664 } 11665 11666 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 11667 if (as_value == 0) 11668 safe_printf("%s", TMPL_CHOICE_INDENT); 11669 else 11670 safe_printf("%s", TMPL_INDENT); 11671 safe_printf("%s: %s\n", gettext("value description"), buf); 11672 free(buf); 11673 } 11674 } 11675 11676 static void 11677 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 11678 { 11679 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 11680 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11681 safe_printf("%s\n", val_buf); 11682 11683 print_template_value_details(prt, val_buf, 1); 11684 } 11685 11686 static void 11687 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 11688 { 11689 int i, printed = 0; 11690 scf_values_t values; 11691 scf_count_ranges_t c_ranges; 11692 scf_int_ranges_t i_ranges; 11693 11694 printed = 0; 11695 i = 0; 11696 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 11697 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11698 gettext("value constraints")); 11699 printed++; 11700 for (i = 0; i < values.value_count; ++i) { 11701 safe_printf("%s%s: %s\n", TMPL_INDENT, 11702 gettext("value name"), values.values_as_strings[i]); 11703 if (verbose == 1) 11704 print_template_value_details(prt, 11705 values.values_as_strings[i], 0); 11706 } 11707 11708 scf_values_destroy(&values); 11709 } 11710 11711 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 11712 if (printed++ == 0) 11713 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11714 gettext("value constraints")); 11715 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11716 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11717 gettext("range"), c_ranges.scr_min[i], 11718 c_ranges.scr_max[i]); 11719 } 11720 scf_count_ranges_destroy(&c_ranges); 11721 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11722 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 11723 if (printed++ == 0) 11724 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11725 gettext("value constraints")); 11726 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11727 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11728 gettext("range"), i_ranges.sir_min[i], 11729 i_ranges.sir_max[i]); 11730 } 11731 scf_int_ranges_destroy(&i_ranges); 11732 } 11733 } 11734 11735 static void 11736 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 11737 { 11738 int i = 0, printed = 0; 11739 scf_values_t values; 11740 scf_count_ranges_t c_ranges; 11741 scf_int_ranges_t i_ranges; 11742 11743 printed = 0; 11744 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 11745 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11746 gettext("value constraints")); 11747 printed++; 11748 for (i = 0; i < values.value_count; i++) { 11749 safe_printf("%s%s: %s\n", TMPL_INDENT, 11750 gettext("value name"), values.values_as_strings[i]); 11751 if (verbose == 1) 11752 print_template_value_details(prt, 11753 values.values_as_strings[i], 0); 11754 } 11755 11756 scf_values_destroy(&values); 11757 } 11758 11759 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 11760 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11761 if (printed++ == 0) 11762 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11763 gettext("value choices")); 11764 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11765 gettext("range"), c_ranges.scr_min[i], 11766 c_ranges.scr_max[i]); 11767 } 11768 scf_count_ranges_destroy(&c_ranges); 11769 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11770 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 11771 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11772 if (printed++ == 0) 11773 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11774 gettext("value choices")); 11775 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11776 gettext("range"), i_ranges.sir_min[i], 11777 i_ranges.sir_max[i]); 11778 } 11779 scf_int_ranges_destroy(&i_ranges); 11780 } 11781 } 11782 11783 static void 11784 list_values_by_template(scf_prop_tmpl_t *prt) 11785 { 11786 print_template_constraints(prt, 1); 11787 print_template_choices(prt, 1); 11788 } 11789 11790 static void 11791 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 11792 { 11793 char *val_buf; 11794 scf_iter_t *iter; 11795 scf_value_t *val; 11796 int ret; 11797 11798 if ((iter = scf_iter_create(g_hndl)) == NULL || 11799 (val = scf_value_create(g_hndl)) == NULL) 11800 scfdie(); 11801 11802 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11803 scfdie(); 11804 11805 val_buf = safe_malloc(max_scf_value_len + 1); 11806 11807 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11808 if (scf_value_get_as_string(val, val_buf, 11809 max_scf_value_len + 1) < 0) 11810 scfdie(); 11811 11812 print_template_value(prt, val_buf); 11813 } 11814 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11815 scfdie(); 11816 free(val_buf); 11817 11818 print_template_constraints(prt, 0); 11819 print_template_choices(prt, 0); 11820 11821 } 11822 11823 /* 11824 * Outputs property info for the describe subcommand 11825 * Verbose output if templates == 2, -v option of svccfg describe 11826 * Displays template data if prop is not NULL, -t option of svccfg describe 11827 */ 11828 static void 11829 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 11830 { 11831 char *buf; 11832 uint8_t u_buf; 11833 int i; 11834 uint64_t min, max; 11835 scf_values_t values; 11836 11837 if (prt == NULL || templates == 0) 11838 return; 11839 11840 if (prop == NULL) { 11841 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 11842 if (scf_tmpl_prop_name(prt, &buf) > 0) { 11843 safe_printf("%s\n", buf); 11844 free(buf); 11845 } else 11846 safe_printf("(%s)\n", gettext("any")); 11847 } 11848 11849 if (prop == NULL || templates == 2) { 11850 if (prop != NULL) 11851 safe_printf("%s", TMPL_INDENT); 11852 else 11853 safe_printf("%s", TMPL_VALUE_INDENT); 11854 safe_printf("%s: ", gettext("type")); 11855 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 11856 safe_printf("%s\n", buf); 11857 free(buf); 11858 } else 11859 safe_printf("(%s)\n", gettext("any")); 11860 } 11861 11862 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 11863 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11864 u_buf ? "true" : "false"); 11865 11866 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 11867 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11868 buf); 11869 free(buf); 11870 } 11871 11872 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 11873 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 11874 buf); 11875 free(buf); 11876 } 11877 11878 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 11879 safe_printf("%s%s\n", TMPL_INDENT, buf); 11880 free(buf); 11881 } 11882 11883 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 11884 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 11885 scf_tmpl_visibility_to_string(u_buf)); 11886 11887 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 11888 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11889 gettext("minimum number of values"), min); 11890 if (max == ULLONG_MAX) { 11891 safe_printf("%s%s: %s\n", TMPL_INDENT, 11892 gettext("maximum number of values"), 11893 gettext("unlimited")); 11894 } else { 11895 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11896 gettext("maximum number of values"), max); 11897 } 11898 } 11899 11900 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 11901 for (i = 0; i < values.value_count; i++) { 11902 if (i == 0) { 11903 safe_printf("%s%s:", TMPL_INDENT, 11904 gettext("internal separators")); 11905 } 11906 safe_printf(" \"%s\"", values.values_as_strings[i]); 11907 } 11908 safe_printf("\n"); 11909 } 11910 11911 if (templates != 2) 11912 return; 11913 11914 if (prop != NULL) 11915 list_values_tmpl(prt, prop); 11916 else 11917 list_values_by_template(prt); 11918 } 11919 11920 static char * 11921 read_astring(scf_propertygroup_t *pg, const char *prop_name) 11922 { 11923 char *rv; 11924 11925 rv = _scf_read_single_astring_from_pg(pg, prop_name); 11926 if (rv == NULL) { 11927 switch (scf_error()) { 11928 case SCF_ERROR_NOT_FOUND: 11929 break; 11930 default: 11931 scfdie(); 11932 } 11933 } 11934 return (rv); 11935 } 11936 11937 static void 11938 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 11939 { 11940 size_t doc_len; 11941 size_t man_len; 11942 char *pg_name; 11943 char *text = NULL; 11944 int rv; 11945 11946 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 11947 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 11948 pg_name = safe_malloc(max_scf_name_len + 1); 11949 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 11950 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 11951 scfdie(); 11952 } 11953 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 11954 /* Display doc_link and and uri */ 11955 safe_printf("%s%s:\n", TMPL_INDENT, 11956 gettext("doc_link")); 11957 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 11958 if (text != NULL) { 11959 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11960 TMPL_INDENT, gettext("name"), text); 11961 uu_free(text); 11962 } 11963 text = read_astring(pg, SCF_PROPERTY_TM_URI); 11964 if (text != NULL) { 11965 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 11966 gettext("uri"), text); 11967 uu_free(text); 11968 } 11969 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 11970 man_len) == 0) { 11971 /* Display manpage title, section and path */ 11972 safe_printf("%s%s:\n", TMPL_INDENT, 11973 gettext("manpage")); 11974 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 11975 if (text != NULL) { 11976 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11977 TMPL_INDENT, gettext("title"), text); 11978 uu_free(text); 11979 } 11980 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 11981 if (text != NULL) { 11982 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11983 TMPL_INDENT, gettext("section"), text); 11984 uu_free(text); 11985 } 11986 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 11987 if (text != NULL) { 11988 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11989 TMPL_INDENT, gettext("manpath"), text); 11990 uu_free(text); 11991 } 11992 } 11993 } 11994 if (rv == -1) 11995 scfdie(); 11996 11997 done: 11998 free(pg_name); 11999 } 12000 12001 static void 12002 list_entity_tmpl(int templates) 12003 { 12004 char *common_name = NULL; 12005 char *description = NULL; 12006 char *locale = NULL; 12007 scf_iter_t *iter; 12008 scf_propertygroup_t *pg; 12009 scf_property_t *prop; 12010 int r; 12011 scf_value_t *val; 12012 12013 if ((pg = scf_pg_create(g_hndl)) == NULL || 12014 (prop = scf_property_create(g_hndl)) == NULL || 12015 (val = scf_value_create(g_hndl)) == NULL || 12016 (iter = scf_iter_create(g_hndl)) == NULL) 12017 scfdie(); 12018 12019 locale = setlocale(LC_MESSAGES, NULL); 12020 12021 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 12022 common_name = safe_malloc(max_scf_value_len + 1); 12023 12024 /* Try both the current locale and the "C" locale. */ 12025 if (scf_pg_get_property(pg, locale, prop) == 0 || 12026 (scf_error() == SCF_ERROR_NOT_FOUND && 12027 scf_pg_get_property(pg, "C", prop) == 0)) { 12028 if (prop_get_val(prop, val) == 0 && 12029 scf_value_get_ustring(val, common_name, 12030 max_scf_value_len + 1) != -1) { 12031 safe_printf("%s%s: %s\n", TMPL_INDENT, 12032 gettext("common name"), common_name); 12033 } 12034 } 12035 } 12036 12037 /* 12038 * Do description, manpages, and doc links if templates == 2. 12039 */ 12040 if (templates == 2) { 12041 /* Get the description. */ 12042 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 12043 description = safe_malloc(max_scf_value_len + 1); 12044 12045 /* Try both the current locale and the "C" locale. */ 12046 if (scf_pg_get_property(pg, locale, prop) == 0 || 12047 (scf_error() == SCF_ERROR_NOT_FOUND && 12048 scf_pg_get_property(pg, "C", prop) == 0)) { 12049 if (prop_get_val(prop, val) == 0 && 12050 scf_value_get_ustring(val, description, 12051 max_scf_value_len + 1) != -1) { 12052 safe_printf("%s%s: %s\n", TMPL_INDENT, 12053 gettext("description"), 12054 description); 12055 } 12056 } 12057 } 12058 12059 /* Process doc_link & manpage elements. */ 12060 if (cur_level != NULL) { 12061 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 12062 SCF_GROUP_TEMPLATE); 12063 } else if (cur_inst != NULL) { 12064 r = scf_iter_instance_pgs_typed(iter, cur_inst, 12065 SCF_GROUP_TEMPLATE); 12066 } else { 12067 r = scf_iter_service_pgs_typed(iter, cur_svc, 12068 SCF_GROUP_TEMPLATE); 12069 } 12070 if (r == 0) { 12071 display_documentation(iter, pg); 12072 } 12073 } 12074 12075 free(common_name); 12076 free(description); 12077 scf_pg_destroy(pg); 12078 scf_property_destroy(prop); 12079 scf_value_destroy(val); 12080 scf_iter_destroy(iter); 12081 } 12082 12083 static void 12084 listtmpl(const char *pattern, int templates) 12085 { 12086 scf_pg_tmpl_t *pgt; 12087 scf_prop_tmpl_t *prt; 12088 char *snapbuf = NULL; 12089 char *fmribuf; 12090 char *pg_name = NULL, *prop_name = NULL; 12091 ssize_t prop_name_size; 12092 char *qual_prop_name; 12093 char *search_name; 12094 int listed = 0; 12095 12096 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 12097 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 12098 scfdie(); 12099 12100 fmribuf = safe_malloc(max_scf_name_len + 1); 12101 qual_prop_name = safe_malloc(max_scf_name_len + 1); 12102 12103 if (cur_snap != NULL) { 12104 snapbuf = safe_malloc(max_scf_name_len + 1); 12105 if (scf_snapshot_get_name(cur_snap, snapbuf, 12106 max_scf_name_len + 1) < 0) 12107 scfdie(); 12108 } 12109 12110 if (cur_inst != NULL) { 12111 if (scf_instance_to_fmri(cur_inst, fmribuf, 12112 max_scf_name_len + 1) < 0) 12113 scfdie(); 12114 } else if (cur_svc != NULL) { 12115 if (scf_service_to_fmri(cur_svc, fmribuf, 12116 max_scf_name_len + 1) < 0) 12117 scfdie(); 12118 } else 12119 abort(); 12120 12121 /* If pattern is specified, we want to list only those items. */ 12122 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) { 12123 listed = 0; 12124 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 12125 fnmatch(pattern, pg_name, 0) == 0)) { 12126 list_pg_tmpl(pgt, NULL, templates); 12127 listed++; 12128 } 12129 12130 scf_tmpl_prop_reset(prt); 12131 12132 while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) { 12133 search_name = NULL; 12134 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 12135 if ((prop_name_size > 0) && (pg_name != NULL)) { 12136 if (snprintf(qual_prop_name, 12137 max_scf_name_len + 1, "%s/%s", 12138 pg_name, prop_name) >= 12139 max_scf_name_len + 1) { 12140 prop_name_size = -1; 12141 } else { 12142 search_name = qual_prop_name; 12143 } 12144 } 12145 if (listed > 0 || pattern == NULL || 12146 (prop_name_size > 0 && 12147 fnmatch(pattern, search_name, 12148 FNM_PATHNAME) == 0)) 12149 list_prop_tmpl(prt, NULL, templates); 12150 if (prop_name != NULL) { 12151 free(prop_name); 12152 prop_name = NULL; 12153 } 12154 } 12155 if (pg_name != NULL) { 12156 free(pg_name); 12157 pg_name = NULL; 12158 } 12159 } 12160 12161 scf_tmpl_prop_destroy(prt); 12162 scf_tmpl_pg_destroy(pgt); 12163 free(snapbuf); 12164 free(fmribuf); 12165 free(qual_prop_name); 12166 } 12167 12168 static void 12169 listprop(const char *pattern, int only_pgs, int templates) 12170 { 12171 scf_propertygroup_t *pg; 12172 scf_property_t *prop; 12173 scf_iter_t *iter, *piter; 12174 char *pgnbuf, *prnbuf, *ppnbuf; 12175 scf_pg_tmpl_t *pgt, *pgtp; 12176 scf_prop_tmpl_t *prt; 12177 12178 void **objects; 12179 char **names; 12180 void **tmpls; 12181 int allocd, i; 12182 12183 int ret; 12184 ssize_t pgnlen, prnlen, szret; 12185 size_t max_len = 0; 12186 12187 if (cur_svc == NULL && cur_inst == NULL) { 12188 semerr(emsg_entity_not_selected); 12189 return; 12190 } 12191 12192 if ((pg = scf_pg_create(g_hndl)) == NULL || 12193 (prop = scf_property_create(g_hndl)) == NULL || 12194 (iter = scf_iter_create(g_hndl)) == NULL || 12195 (piter = scf_iter_create(g_hndl)) == NULL || 12196 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12197 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 12198 scfdie(); 12199 12200 prnbuf = safe_malloc(max_scf_name_len + 1); 12201 12202 if (cur_level != NULL) 12203 ret = scf_iter_snaplevel_pgs(iter, cur_level); 12204 else if (cur_inst != NULL) 12205 ret = scf_iter_instance_pgs(iter, cur_inst); 12206 else 12207 ret = scf_iter_service_pgs(iter, cur_svc); 12208 if (ret != 0) { 12209 return; 12210 } 12211 12212 /* 12213 * We want to only list items which match pattern, and we want the 12214 * second column to line up, so during the first pass we'll save 12215 * matching items, their names, and their templates in objects, 12216 * names, and tmpls, computing the maximum name length as we go, 12217 * and then we'll print them out. 12218 * 12219 * Note: We always keep an extra slot available so the array can be 12220 * NULL-terminated. 12221 */ 12222 i = 0; 12223 allocd = 1; 12224 objects = safe_malloc(sizeof (*objects)); 12225 names = safe_malloc(sizeof (*names)); 12226 tmpls = safe_malloc(sizeof (*tmpls)); 12227 12228 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12229 int new_pg = 0; 12230 int print_props = 0; 12231 pgtp = NULL; 12232 12233 pgnlen = scf_pg_get_name(pg, NULL, 0); 12234 if (pgnlen < 0) 12235 scfdie(); 12236 12237 pgnbuf = safe_malloc(pgnlen + 1); 12238 12239 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 12240 if (szret < 0) 12241 scfdie(); 12242 assert(szret <= pgnlen); 12243 12244 if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) { 12245 if (scf_error() != SCF_ERROR_NOT_FOUND) 12246 scfdie(); 12247 pgtp = NULL; 12248 } else { 12249 pgtp = pgt; 12250 } 12251 12252 if (pattern == NULL || 12253 fnmatch(pattern, pgnbuf, 0) == 0) { 12254 if (i+1 >= allocd) { 12255 allocd *= 2; 12256 objects = realloc(objects, 12257 sizeof (*objects) * allocd); 12258 names = 12259 realloc(names, sizeof (*names) * allocd); 12260 tmpls = realloc(tmpls, 12261 sizeof (*tmpls) * allocd); 12262 if (objects == NULL || names == NULL || 12263 tmpls == NULL) 12264 uu_die(gettext("Out of memory")); 12265 } 12266 objects[i] = pg; 12267 names[i] = pgnbuf; 12268 12269 if (pgtp == NULL) 12270 tmpls[i] = NULL; 12271 else 12272 tmpls[i] = pgt; 12273 12274 ++i; 12275 12276 if (pgnlen > max_len) 12277 max_len = pgnlen; 12278 12279 new_pg = 1; 12280 print_props = 1; 12281 } 12282 12283 if (only_pgs) { 12284 if (new_pg) { 12285 pg = scf_pg_create(g_hndl); 12286 if (pg == NULL) 12287 scfdie(); 12288 pgt = scf_tmpl_pg_create(g_hndl); 12289 if (pgt == NULL) 12290 scfdie(); 12291 } else 12292 free(pgnbuf); 12293 12294 continue; 12295 } 12296 12297 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 12298 scfdie(); 12299 12300 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 12301 prnlen = scf_property_get_name(prop, prnbuf, 12302 max_scf_name_len + 1); 12303 if (prnlen < 0) 12304 scfdie(); 12305 12306 /* Will prepend the property group name and a slash. */ 12307 prnlen += pgnlen + 1; 12308 12309 ppnbuf = safe_malloc(prnlen + 1); 12310 12311 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 12312 prnbuf) < 0) 12313 uu_die("snprintf"); 12314 12315 if (pattern == NULL || print_props == 1 || 12316 fnmatch(pattern, ppnbuf, 0) == 0) { 12317 if (i+1 >= allocd) { 12318 allocd *= 2; 12319 objects = realloc(objects, 12320 sizeof (*objects) * allocd); 12321 names = realloc(names, 12322 sizeof (*names) * allocd); 12323 tmpls = realloc(tmpls, 12324 sizeof (*tmpls) * allocd); 12325 if (objects == NULL || names == NULL || 12326 tmpls == NULL) 12327 uu_die(gettext( 12328 "Out of memory")); 12329 } 12330 12331 objects[i] = prop; 12332 names[i] = ppnbuf; 12333 12334 if (pgtp != NULL) { 12335 if (scf_tmpl_get_by_prop(pgt, prnbuf, 12336 prt, NULL) < 0) { 12337 if (scf_error() != 12338 SCF_ERROR_NOT_FOUND) 12339 scfdie(); 12340 tmpls[i] = NULL; 12341 } else { 12342 tmpls[i] = prt; 12343 } 12344 } else { 12345 tmpls[i] = NULL; 12346 } 12347 12348 ++i; 12349 12350 if (prnlen > max_len) 12351 max_len = prnlen; 12352 12353 prop = scf_property_create(g_hndl); 12354 prt = scf_tmpl_prop_create(g_hndl); 12355 } else { 12356 free(ppnbuf); 12357 } 12358 } 12359 12360 if (new_pg) { 12361 pg = scf_pg_create(g_hndl); 12362 if (pg == NULL) 12363 scfdie(); 12364 pgt = scf_tmpl_pg_create(g_hndl); 12365 if (pgt == NULL) 12366 scfdie(); 12367 } else 12368 free(pgnbuf); 12369 } 12370 if (ret != 0) 12371 scfdie(); 12372 12373 objects[i] = NULL; 12374 12375 scf_pg_destroy(pg); 12376 scf_tmpl_pg_destroy(pgt); 12377 scf_property_destroy(prop); 12378 scf_tmpl_prop_destroy(prt); 12379 12380 for (i = 0; objects[i] != NULL; ++i) { 12381 if (strchr(names[i], '/') == NULL) { 12382 /* property group */ 12383 pg = (scf_propertygroup_t *)objects[i]; 12384 pgt = (scf_pg_tmpl_t *)tmpls[i]; 12385 list_pg_info(pg, names[i], max_len); 12386 list_pg_tmpl(pgt, pg, templates); 12387 free(names[i]); 12388 scf_pg_destroy(pg); 12389 if (pgt != NULL) 12390 scf_tmpl_pg_destroy(pgt); 12391 } else { 12392 /* property */ 12393 prop = (scf_property_t *)objects[i]; 12394 prt = (scf_prop_tmpl_t *)tmpls[i]; 12395 list_prop_info(prop, names[i], max_len); 12396 list_prop_tmpl(prt, prop, templates); 12397 free(names[i]); 12398 scf_property_destroy(prop); 12399 if (prt != NULL) 12400 scf_tmpl_prop_destroy(prt); 12401 } 12402 } 12403 12404 free(names); 12405 free(objects); 12406 free(tmpls); 12407 } 12408 12409 void 12410 lscf_listpg(const char *pattern) 12411 { 12412 lscf_prep_hndl(); 12413 12414 listprop(pattern, 1, 0); 12415 } 12416 12417 /* 12418 * Property group and property creation, setting, and deletion. setprop (and 12419 * its alias, addprop) can either create a property group of a given type, or 12420 * it can create or set a property to a given type and list of values. 12421 */ 12422 void 12423 lscf_addpg(const char *name, const char *type, const char *flags) 12424 { 12425 scf_propertygroup_t *pg; 12426 int ret; 12427 uint32_t flgs = 0; 12428 const char *cp; 12429 12430 12431 lscf_prep_hndl(); 12432 12433 if (cur_snap != NULL) { 12434 semerr(emsg_cant_modify_snapshots); 12435 return; 12436 } 12437 12438 if (cur_inst == NULL && cur_svc == NULL) { 12439 semerr(emsg_entity_not_selected); 12440 return; 12441 } 12442 12443 if (flags != NULL) { 12444 for (cp = flags; *cp != '\0'; ++cp) { 12445 switch (*cp) { 12446 case 'P': 12447 flgs |= SCF_PG_FLAG_NONPERSISTENT; 12448 break; 12449 12450 case 'p': 12451 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 12452 break; 12453 12454 default: 12455 semerr(gettext("Invalid property group flag " 12456 "%c."), *cp); 12457 return; 12458 } 12459 } 12460 } 12461 12462 pg = scf_pg_create(g_hndl); 12463 if (pg == NULL) 12464 scfdie(); 12465 12466 if (cur_inst != NULL) 12467 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 12468 else 12469 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 12470 12471 if (ret != SCF_SUCCESS) { 12472 switch (scf_error()) { 12473 case SCF_ERROR_INVALID_ARGUMENT: 12474 semerr(gettext("Name, type, or flags are invalid.\n")); 12475 break; 12476 12477 case SCF_ERROR_EXISTS: 12478 semerr(gettext("Property group already exists.\n")); 12479 break; 12480 12481 case SCF_ERROR_PERMISSION_DENIED: 12482 semerr(emsg_permission_denied); 12483 break; 12484 12485 case SCF_ERROR_BACKEND_ACCESS: 12486 semerr(gettext("Backend refused access.\n")); 12487 break; 12488 12489 default: 12490 scfdie(); 12491 } 12492 } 12493 12494 scf_pg_destroy(pg); 12495 12496 private_refresh(); 12497 } 12498 12499 void 12500 lscf_delpg(char *name) 12501 { 12502 lscf_prep_hndl(); 12503 12504 if (cur_snap != NULL) { 12505 semerr(emsg_cant_modify_snapshots); 12506 return; 12507 } 12508 12509 if (cur_inst == NULL && cur_svc == NULL) { 12510 semerr(emsg_entity_not_selected); 12511 return; 12512 } 12513 12514 if (strchr(name, '/') != NULL) { 12515 semerr(emsg_invalid_pg_name, name); 12516 return; 12517 } 12518 12519 lscf_delprop(name); 12520 } 12521 12522 /* 12523 * scf_delhash() is used to remove the property group related to the 12524 * hash entry for a specific manifest in the repository. pgname will be 12525 * constructed from the location of the manifest file. If deathrow isn't 0, 12526 * manifest file doesn't need to exist (manifest string will be used as 12527 * an absolute path). 12528 */ 12529 void 12530 lscf_delhash(char *manifest, int deathrow) 12531 { 12532 char *pgname; 12533 12534 if (cur_snap != NULL || 12535 cur_inst != NULL || cur_svc != NULL) { 12536 warn(gettext("error, an entity is selected\n")); 12537 return; 12538 } 12539 12540 /* select smf/manifest */ 12541 lscf_select(HASH_SVC); 12542 /* 12543 * Translate the manifest file name to property name. In the deathrow 12544 * case, the manifest file does not need to exist. 12545 */ 12546 pgname = mhash_filename_to_propname(manifest, 12547 deathrow ? B_TRUE : B_FALSE); 12548 if (pgname == NULL) { 12549 warn(gettext("cannot resolve pathname for %s\n"), manifest); 12550 return; 12551 } 12552 /* delete the hash property name */ 12553 lscf_delpg(pgname); 12554 } 12555 12556 void 12557 lscf_listprop(const char *pattern) 12558 { 12559 lscf_prep_hndl(); 12560 12561 listprop(pattern, 0, 0); 12562 } 12563 12564 int 12565 lscf_setprop(const char *pgname, const char *type, const char *value, 12566 const uu_list_t *values) 12567 { 12568 scf_type_t ty, current_ty; 12569 scf_service_t *svc; 12570 scf_propertygroup_t *pg, *parent_pg; 12571 scf_property_t *prop, *parent_prop; 12572 scf_pg_tmpl_t *pgt; 12573 scf_prop_tmpl_t *prt; 12574 int ret, result = 0; 12575 scf_transaction_t *tx; 12576 scf_transaction_entry_t *e; 12577 scf_value_t *v; 12578 uu_list_walk_t *walk; 12579 string_list_t *sp; 12580 char *propname; 12581 int req_quotes = 0; 12582 12583 lscf_prep_hndl(); 12584 12585 if ((e = scf_entry_create(g_hndl)) == NULL || 12586 (svc = scf_service_create(g_hndl)) == NULL || 12587 (parent_pg = scf_pg_create(g_hndl)) == NULL || 12588 (pg = scf_pg_create(g_hndl)) == NULL || 12589 (parent_prop = scf_property_create(g_hndl)) == NULL || 12590 (prop = scf_property_create(g_hndl)) == NULL || 12591 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 12592 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12593 (tx = scf_transaction_create(g_hndl)) == NULL) 12594 scfdie(); 12595 12596 if (cur_snap != NULL) { 12597 semerr(emsg_cant_modify_snapshots); 12598 goto fail; 12599 } 12600 12601 if (cur_inst == NULL && cur_svc == NULL) { 12602 semerr(emsg_entity_not_selected); 12603 goto fail; 12604 } 12605 12606 propname = strchr(pgname, '/'); 12607 if (propname == NULL) { 12608 semerr(gettext("Property names must contain a `/'.\n")); 12609 goto fail; 12610 } 12611 12612 *propname = '\0'; 12613 ++propname; 12614 12615 if (type != NULL) { 12616 ty = string_to_type(type); 12617 if (ty == SCF_TYPE_INVALID) { 12618 semerr(gettext("Unknown type \"%s\".\n"), type); 12619 goto fail; 12620 } 12621 } 12622 12623 if (cur_inst != NULL) 12624 ret = scf_instance_get_pg(cur_inst, pgname, pg); 12625 else 12626 ret = scf_service_get_pg(cur_svc, pgname, pg); 12627 if (ret != SCF_SUCCESS) { 12628 switch (scf_error()) { 12629 case SCF_ERROR_NOT_FOUND: 12630 semerr(emsg_no_such_pg, pgname); 12631 goto fail; 12632 12633 case SCF_ERROR_INVALID_ARGUMENT: 12634 semerr(emsg_invalid_pg_name, pgname); 12635 goto fail; 12636 12637 default: 12638 scfdie(); 12639 break; 12640 } 12641 } 12642 12643 do { 12644 if (scf_pg_update(pg) == -1) 12645 scfdie(); 12646 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12647 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12648 scfdie(); 12649 12650 semerr(emsg_permission_denied); 12651 goto fail; 12652 } 12653 12654 ret = scf_pg_get_property(pg, propname, prop); 12655 if (ret == SCF_SUCCESS) { 12656 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 12657 scfdie(); 12658 12659 if (type == NULL) 12660 ty = current_ty; 12661 if (scf_transaction_property_change_type(tx, e, 12662 propname, ty) == -1) 12663 scfdie(); 12664 12665 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 12666 /* Infer the type, if possible. */ 12667 if (type == NULL) { 12668 /* 12669 * First check if we're an instance and the 12670 * property is set on the service. 12671 */ 12672 if (cur_inst != NULL && 12673 scf_instance_get_parent(cur_inst, 12674 svc) == 0 && 12675 scf_service_get_pg(cur_svc, pgname, 12676 parent_pg) == 0 && 12677 scf_pg_get_property(parent_pg, propname, 12678 parent_prop) == 0 && 12679 scf_property_type(parent_prop, 12680 ¤t_ty) == 0) { 12681 ty = current_ty; 12682 12683 /* Then check for a type set in a template. */ 12684 } else if (scf_tmpl_get_by_pg(pg, pgt, 12685 NULL) == 0 && 12686 scf_tmpl_get_by_prop(pgt, propname, prt, 12687 NULL) == 0 && 12688 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 12689 ty = current_ty; 12690 12691 /* If type can't be inferred, fail. */ 12692 } else { 12693 semerr(gettext("Type required for new " 12694 "properties.\n")); 12695 goto fail; 12696 } 12697 } 12698 if (scf_transaction_property_new(tx, e, propname, 12699 ty) == -1) 12700 scfdie(); 12701 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12702 semerr(emsg_invalid_prop_name, propname); 12703 goto fail; 12704 } else { 12705 scfdie(); 12706 } 12707 12708 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 12709 req_quotes = 1; 12710 12711 if (value != NULL) { 12712 v = string_to_value(value, ty, 0); 12713 12714 if (v == NULL) 12715 goto fail; 12716 12717 ret = scf_entry_add_value(e, v); 12718 assert(ret == SCF_SUCCESS); 12719 } else { 12720 assert(values != NULL); 12721 12722 walk = uu_list_walk_start((uu_list_t *)values, 12723 UU_DEFAULT); 12724 if (walk == NULL) 12725 uu_die(gettext("Could not walk list")); 12726 12727 for (sp = uu_list_walk_next(walk); sp != NULL; 12728 sp = uu_list_walk_next(walk)) { 12729 v = string_to_value(sp->str, ty, req_quotes); 12730 12731 if (v == NULL) { 12732 scf_entry_destroy_children(e); 12733 goto fail; 12734 } 12735 12736 ret = scf_entry_add_value(e, v); 12737 assert(ret == SCF_SUCCESS); 12738 } 12739 uu_list_walk_end(walk); 12740 } 12741 result = scf_transaction_commit(tx); 12742 12743 scf_transaction_reset(tx); 12744 scf_entry_destroy_children(e); 12745 } while (result == 0); 12746 12747 if (result < 0) { 12748 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12749 scfdie(); 12750 12751 semerr(emsg_permission_denied); 12752 goto fail; 12753 } 12754 12755 ret = 0; 12756 12757 private_refresh(); 12758 12759 goto cleanup; 12760 12761 fail: 12762 ret = -1; 12763 12764 cleanup: 12765 scf_transaction_destroy(tx); 12766 scf_entry_destroy(e); 12767 scf_service_destroy(svc); 12768 scf_pg_destroy(parent_pg); 12769 scf_pg_destroy(pg); 12770 scf_property_destroy(parent_prop); 12771 scf_property_destroy(prop); 12772 scf_tmpl_pg_destroy(pgt); 12773 scf_tmpl_prop_destroy(prt); 12774 12775 return (ret); 12776 } 12777 12778 void 12779 lscf_delprop(char *pgn) 12780 { 12781 char *slash, *pn; 12782 scf_propertygroup_t *pg; 12783 scf_transaction_t *tx; 12784 scf_transaction_entry_t *e; 12785 int ret; 12786 12787 12788 lscf_prep_hndl(); 12789 12790 if (cur_snap != NULL) { 12791 semerr(emsg_cant_modify_snapshots); 12792 return; 12793 } 12794 12795 if (cur_inst == NULL && cur_svc == NULL) { 12796 semerr(emsg_entity_not_selected); 12797 return; 12798 } 12799 12800 pg = scf_pg_create(g_hndl); 12801 if (pg == NULL) 12802 scfdie(); 12803 12804 slash = strchr(pgn, '/'); 12805 if (slash == NULL) { 12806 pn = NULL; 12807 } else { 12808 *slash = '\0'; 12809 pn = slash + 1; 12810 } 12811 12812 if (cur_inst != NULL) 12813 ret = scf_instance_get_pg(cur_inst, pgn, pg); 12814 else 12815 ret = scf_service_get_pg(cur_svc, pgn, pg); 12816 if (ret != SCF_SUCCESS) { 12817 switch (scf_error()) { 12818 case SCF_ERROR_NOT_FOUND: 12819 semerr(emsg_no_such_pg, pgn); 12820 break; 12821 12822 case SCF_ERROR_INVALID_ARGUMENT: 12823 semerr(emsg_invalid_pg_name, pgn); 12824 break; 12825 12826 default: 12827 scfdie(); 12828 } 12829 12830 scf_pg_destroy(pg); 12831 12832 return; 12833 } 12834 12835 if (pn == NULL) { 12836 /* Try to delete the property group. */ 12837 if (scf_pg_delete(pg) != SCF_SUCCESS) { 12838 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12839 scfdie(); 12840 12841 semerr(emsg_permission_denied); 12842 } else { 12843 private_refresh(); 12844 } 12845 12846 scf_pg_destroy(pg); 12847 return; 12848 } 12849 12850 e = scf_entry_create(g_hndl); 12851 tx = scf_transaction_create(g_hndl); 12852 12853 do { 12854 if (scf_pg_update(pg) == -1) 12855 scfdie(); 12856 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12857 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12858 scfdie(); 12859 12860 semerr(emsg_permission_denied); 12861 break; 12862 } 12863 12864 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 12865 if (scf_error() == SCF_ERROR_NOT_FOUND) { 12866 semerr(gettext("No such property %s/%s.\n"), 12867 pgn, pn); 12868 break; 12869 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12870 semerr(emsg_invalid_prop_name, pn); 12871 break; 12872 } else { 12873 scfdie(); 12874 } 12875 } 12876 12877 ret = scf_transaction_commit(tx); 12878 12879 if (ret == 0) 12880 scf_transaction_reset(tx); 12881 } while (ret == 0); 12882 12883 if (ret < 0) { 12884 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12885 scfdie(); 12886 12887 semerr(emsg_permission_denied); 12888 } else { 12889 private_refresh(); 12890 } 12891 12892 scf_transaction_destroy(tx); 12893 scf_entry_destroy(e); 12894 scf_pg_destroy(pg); 12895 } 12896 12897 /* 12898 * Property editing. 12899 */ 12900 12901 static int 12902 write_edit_script(FILE *strm) 12903 { 12904 char *fmribuf; 12905 ssize_t fmrilen; 12906 12907 scf_propertygroup_t *pg; 12908 scf_property_t *prop; 12909 scf_value_t *val; 12910 scf_type_t ty; 12911 int ret, result = 0; 12912 scf_iter_t *iter, *piter, *viter; 12913 char *buf, *tybuf, *pname; 12914 const char *emsg_write_error; 12915 12916 12917 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 12918 12919 12920 /* select fmri */ 12921 if (cur_inst != NULL) { 12922 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 12923 if (fmrilen < 0) 12924 scfdie(); 12925 fmribuf = safe_malloc(fmrilen + 1); 12926 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 12927 scfdie(); 12928 } else { 12929 assert(cur_svc != NULL); 12930 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 12931 if (fmrilen < 0) 12932 scfdie(); 12933 fmribuf = safe_malloc(fmrilen + 1); 12934 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 12935 scfdie(); 12936 } 12937 12938 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 12939 warn(emsg_write_error, strerror(errno)); 12940 free(fmribuf); 12941 return (-1); 12942 } 12943 12944 free(fmribuf); 12945 12946 12947 if ((pg = scf_pg_create(g_hndl)) == NULL || 12948 (prop = scf_property_create(g_hndl)) == NULL || 12949 (val = scf_value_create(g_hndl)) == NULL || 12950 (iter = scf_iter_create(g_hndl)) == NULL || 12951 (piter = scf_iter_create(g_hndl)) == NULL || 12952 (viter = scf_iter_create(g_hndl)) == NULL) 12953 scfdie(); 12954 12955 buf = safe_malloc(max_scf_name_len + 1); 12956 tybuf = safe_malloc(max_scf_pg_type_len + 1); 12957 pname = safe_malloc(max_scf_name_len + 1); 12958 12959 if (cur_inst != NULL) 12960 ret = scf_iter_instance_pgs(iter, cur_inst); 12961 else 12962 ret = scf_iter_service_pgs(iter, cur_svc); 12963 if (ret != SCF_SUCCESS) 12964 scfdie(); 12965 12966 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12967 int ret2; 12968 12969 /* 12970 * # delprop pg 12971 * # addpg pg type 12972 */ 12973 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 12974 scfdie(); 12975 12976 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 12977 scfdie(); 12978 12979 if (fprintf(strm, "# Property group \"%s\"\n" 12980 "# delprop %s\n" 12981 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 12982 warn(emsg_write_error, strerror(errno)); 12983 result = -1; 12984 goto out; 12985 } 12986 12987 /* # setprop pg/prop = (values) */ 12988 12989 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 12990 scfdie(); 12991 12992 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 12993 int first = 1; 12994 int ret3; 12995 int multiple; 12996 int is_str; 12997 scf_type_t bty; 12998 12999 if (scf_property_get_name(prop, pname, 13000 max_scf_name_len + 1) < 0) 13001 scfdie(); 13002 13003 if (scf_property_type(prop, &ty) != 0) 13004 scfdie(); 13005 13006 multiple = prop_has_multiple_values(prop, val); 13007 13008 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 13009 pname, scf_type_to_string(ty), multiple ? "(" : "") 13010 < 0) { 13011 warn(emsg_write_error, strerror(errno)); 13012 result = -1; 13013 goto out; 13014 } 13015 13016 (void) scf_type_base_type(ty, &bty); 13017 is_str = (bty == SCF_TYPE_ASTRING); 13018 13019 if (scf_iter_property_values(viter, prop) != 13020 SCF_SUCCESS) 13021 scfdie(); 13022 13023 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 13024 char *buf; 13025 ssize_t buflen; 13026 13027 buflen = scf_value_get_as_string(val, NULL, 0); 13028 if (buflen < 0) 13029 scfdie(); 13030 13031 buf = safe_malloc(buflen + 1); 13032 13033 if (scf_value_get_as_string(val, buf, 13034 buflen + 1) < 0) 13035 scfdie(); 13036 13037 if (first) 13038 first = 0; 13039 else { 13040 if (putc(' ', strm) != ' ') { 13041 warn(emsg_write_error, 13042 strerror(errno)); 13043 result = -1; 13044 goto out; 13045 } 13046 } 13047 13048 if ((is_str && multiple) || 13049 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 13050 (void) putc('"', strm); 13051 (void) quote_and_print(buf, strm, 1); 13052 (void) putc('"', strm); 13053 13054 if (ferror(strm)) { 13055 warn(emsg_write_error, 13056 strerror(errno)); 13057 result = -1; 13058 goto out; 13059 } 13060 } else { 13061 if (fprintf(strm, "%s", buf) < 0) { 13062 warn(emsg_write_error, 13063 strerror(errno)); 13064 result = -1; 13065 goto out; 13066 } 13067 } 13068 13069 free(buf); 13070 } 13071 if (ret3 < 0 && 13072 scf_error() != SCF_ERROR_PERMISSION_DENIED) 13073 scfdie(); 13074 13075 /* Write closing paren if mult-value property */ 13076 if ((multiple && putc(')', strm) == EOF) || 13077 13078 /* Write final newline */ 13079 fputc('\n', strm) == EOF) { 13080 warn(emsg_write_error, strerror(errno)); 13081 result = -1; 13082 goto out; 13083 } 13084 } 13085 if (ret2 < 0) 13086 scfdie(); 13087 13088 if (fputc('\n', strm) == EOF) { 13089 warn(emsg_write_error, strerror(errno)); 13090 result = -1; 13091 goto out; 13092 } 13093 } 13094 if (ret < 0) 13095 scfdie(); 13096 13097 out: 13098 free(pname); 13099 free(tybuf); 13100 free(buf); 13101 scf_iter_destroy(viter); 13102 scf_iter_destroy(piter); 13103 scf_iter_destroy(iter); 13104 scf_value_destroy(val); 13105 scf_property_destroy(prop); 13106 scf_pg_destroy(pg); 13107 13108 if (result == 0) { 13109 if (fflush(strm) != 0) { 13110 warn(emsg_write_error, strerror(errno)); 13111 return (-1); 13112 } 13113 } 13114 13115 return (result); 13116 } 13117 13118 int 13119 lscf_editprop() 13120 { 13121 char *buf, *editor; 13122 size_t bufsz; 13123 int tmpfd; 13124 char tempname[] = TEMP_FILE_PATTERN; 13125 13126 lscf_prep_hndl(); 13127 13128 if (cur_snap != NULL) { 13129 semerr(emsg_cant_modify_snapshots); 13130 return (-1); 13131 } 13132 13133 if (cur_svc == NULL && cur_inst == NULL) { 13134 semerr(emsg_entity_not_selected); 13135 return (-1); 13136 } 13137 13138 tmpfd = mkstemp(tempname); 13139 if (tmpfd == -1) { 13140 semerr(gettext("Could not create temporary file.\n")); 13141 return (-1); 13142 } 13143 13144 (void) strcpy(tempfilename, tempname); 13145 13146 tempfile = fdopen(tmpfd, "r+"); 13147 if (tempfile == NULL) { 13148 warn(gettext("Could not create temporary file.\n")); 13149 if (close(tmpfd) == -1) 13150 warn(gettext("Could not close temporary file: %s.\n"), 13151 strerror(errno)); 13152 13153 remove_tempfile(); 13154 13155 return (-1); 13156 } 13157 13158 if (write_edit_script(tempfile) == -1) { 13159 remove_tempfile(); 13160 return (-1); 13161 } 13162 13163 editor = getenv("EDITOR"); 13164 if (editor == NULL) 13165 editor = "vi"; 13166 13167 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 13168 buf = safe_malloc(bufsz); 13169 13170 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 13171 uu_die(gettext("Error creating editor command")); 13172 13173 if (system(buf) == -1) { 13174 semerr(gettext("Could not launch editor %s: %s\n"), editor, 13175 strerror(errno)); 13176 free(buf); 13177 remove_tempfile(); 13178 return (-1); 13179 } 13180 13181 free(buf); 13182 13183 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 13184 13185 remove_tempfile(); 13186 13187 return (0); 13188 } 13189 13190 static void 13191 add_string(uu_list_t *strlist, const char *str) 13192 { 13193 string_list_t *elem; 13194 elem = safe_malloc(sizeof (*elem)); 13195 uu_list_node_init(elem, &elem->node, string_pool); 13196 elem->str = safe_strdup(str); 13197 if (uu_list_append(strlist, elem) != 0) 13198 uu_die(gettext("libuutil error: %s\n"), 13199 uu_strerror(uu_error())); 13200 } 13201 13202 static int 13203 remove_string(uu_list_t *strlist, const char *str) 13204 { 13205 uu_list_walk_t *elems; 13206 string_list_t *sp; 13207 13208 /* 13209 * Find the element that needs to be removed. 13210 */ 13211 elems = uu_list_walk_start(strlist, UU_DEFAULT); 13212 while ((sp = uu_list_walk_next(elems)) != NULL) { 13213 if (strcmp(sp->str, str) == 0) 13214 break; 13215 } 13216 uu_list_walk_end(elems); 13217 13218 /* 13219 * Returning 1 here as the value was not found, this 13220 * might not be an error. Leave it to the caller to 13221 * decide. 13222 */ 13223 if (sp == NULL) { 13224 return (1); 13225 } 13226 13227 uu_list_remove(strlist, sp); 13228 13229 free(sp->str); 13230 free(sp); 13231 13232 return (0); 13233 } 13234 13235 /* 13236 * Get all property values that don't match the given glob pattern, 13237 * if a pattern is specified. 13238 */ 13239 static void 13240 get_prop_values(scf_property_t *prop, uu_list_t *values, 13241 const char *pattern) 13242 { 13243 scf_iter_t *iter; 13244 scf_value_t *val; 13245 int ret; 13246 13247 if ((iter = scf_iter_create(g_hndl)) == NULL || 13248 (val = scf_value_create(g_hndl)) == NULL) 13249 scfdie(); 13250 13251 if (scf_iter_property_values(iter, prop) != 0) 13252 scfdie(); 13253 13254 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13255 char *buf; 13256 ssize_t vlen, szret; 13257 13258 vlen = scf_value_get_as_string(val, NULL, 0); 13259 if (vlen < 0) 13260 scfdie(); 13261 13262 buf = safe_malloc(vlen + 1); 13263 13264 szret = scf_value_get_as_string(val, buf, vlen + 1); 13265 if (szret < 0) 13266 scfdie(); 13267 assert(szret <= vlen); 13268 13269 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 13270 add_string(values, buf); 13271 13272 free(buf); 13273 } 13274 13275 if (ret == -1) 13276 scfdie(); 13277 13278 scf_value_destroy(val); 13279 scf_iter_destroy(iter); 13280 } 13281 13282 static int 13283 lscf_setpropvalue(const char *pgname, const char *type, 13284 const char *arg, int isadd, int isnotfoundok) 13285 { 13286 scf_type_t ty; 13287 scf_propertygroup_t *pg; 13288 scf_property_t *prop; 13289 int ret, result = 0; 13290 scf_transaction_t *tx; 13291 scf_transaction_entry_t *e; 13292 scf_value_t *v; 13293 string_list_t *sp; 13294 char *propname; 13295 uu_list_t *values; 13296 uu_list_walk_t *walk; 13297 void *cookie = NULL; 13298 char *pattern = NULL; 13299 13300 lscf_prep_hndl(); 13301 13302 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 13303 uu_die(gettext("Could not create property list: %s\n"), 13304 uu_strerror(uu_error())); 13305 13306 if (!isadd) 13307 pattern = safe_strdup(arg); 13308 13309 if ((e = scf_entry_create(g_hndl)) == NULL || 13310 (pg = scf_pg_create(g_hndl)) == NULL || 13311 (prop = scf_property_create(g_hndl)) == NULL || 13312 (tx = scf_transaction_create(g_hndl)) == NULL) 13313 scfdie(); 13314 13315 if (cur_snap != NULL) { 13316 semerr(emsg_cant_modify_snapshots); 13317 goto fail; 13318 } 13319 13320 if (cur_inst == NULL && cur_svc == NULL) { 13321 semerr(emsg_entity_not_selected); 13322 goto fail; 13323 } 13324 13325 propname = strchr(pgname, '/'); 13326 if (propname == NULL) { 13327 semerr(gettext("Property names must contain a `/'.\n")); 13328 goto fail; 13329 } 13330 13331 *propname = '\0'; 13332 ++propname; 13333 13334 if (type != NULL) { 13335 ty = string_to_type(type); 13336 if (ty == SCF_TYPE_INVALID) { 13337 semerr(gettext("Unknown type \"%s\".\n"), type); 13338 goto fail; 13339 } 13340 } 13341 13342 if (cur_inst != NULL) 13343 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13344 else 13345 ret = scf_service_get_pg(cur_svc, pgname, pg); 13346 if (ret != 0) { 13347 switch (scf_error()) { 13348 case SCF_ERROR_NOT_FOUND: 13349 if (isnotfoundok) { 13350 result = 0; 13351 } else { 13352 semerr(emsg_no_such_pg, pgname); 13353 result = -1; 13354 } 13355 goto out; 13356 13357 case SCF_ERROR_INVALID_ARGUMENT: 13358 semerr(emsg_invalid_pg_name, pgname); 13359 goto fail; 13360 13361 default: 13362 scfdie(); 13363 } 13364 } 13365 13366 do { 13367 if (scf_pg_update(pg) == -1) 13368 scfdie(); 13369 if (scf_transaction_start(tx, pg) != 0) { 13370 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13371 scfdie(); 13372 13373 semerr(emsg_permission_denied); 13374 goto fail; 13375 } 13376 13377 ret = scf_pg_get_property(pg, propname, prop); 13378 if (ret == 0) { 13379 scf_type_t ptype; 13380 char *pat = pattern; 13381 13382 if (scf_property_type(prop, &ptype) != 0) 13383 scfdie(); 13384 13385 if (isadd) { 13386 if (type != NULL && ptype != ty) { 13387 semerr(gettext("Property \"%s\" is not " 13388 "of type \"%s\".\n"), propname, 13389 type); 13390 goto fail; 13391 } 13392 13393 pat = NULL; 13394 } else { 13395 size_t len = strlen(pat); 13396 if (len > 0 && pat[len - 1] == '\"') 13397 pat[len - 1] = '\0'; 13398 if (len > 0 && pat[0] == '\"') 13399 pat++; 13400 } 13401 13402 ty = ptype; 13403 13404 get_prop_values(prop, values, pat); 13405 13406 if (isadd) 13407 add_string(values, arg); 13408 13409 if (scf_transaction_property_change(tx, e, 13410 propname, ty) == -1) 13411 scfdie(); 13412 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13413 if (isadd) { 13414 if (type == NULL) { 13415 semerr(gettext("Type required " 13416 "for new properties.\n")); 13417 goto fail; 13418 } 13419 13420 add_string(values, arg); 13421 13422 if (scf_transaction_property_new(tx, e, 13423 propname, ty) == -1) 13424 scfdie(); 13425 } else if (isnotfoundok) { 13426 result = 0; 13427 goto out; 13428 } else { 13429 semerr(gettext("No such property %s/%s.\n"), 13430 pgname, propname); 13431 result = -1; 13432 goto out; 13433 } 13434 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13435 semerr(emsg_invalid_prop_name, propname); 13436 goto fail; 13437 } else { 13438 scfdie(); 13439 } 13440 13441 walk = uu_list_walk_start(values, UU_DEFAULT); 13442 if (walk == NULL) 13443 uu_die(gettext("Could not walk property list.\n")); 13444 13445 for (sp = uu_list_walk_next(walk); sp != NULL; 13446 sp = uu_list_walk_next(walk)) { 13447 v = string_to_value(sp->str, ty, 0); 13448 13449 if (v == NULL) { 13450 scf_entry_destroy_children(e); 13451 goto fail; 13452 } 13453 ret = scf_entry_add_value(e, v); 13454 assert(ret == 0); 13455 } 13456 uu_list_walk_end(walk); 13457 13458 result = scf_transaction_commit(tx); 13459 13460 scf_transaction_reset(tx); 13461 scf_entry_destroy_children(e); 13462 } while (result == 0); 13463 13464 if (result < 0) { 13465 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13466 scfdie(); 13467 13468 semerr(emsg_permission_denied); 13469 goto fail; 13470 } 13471 13472 result = 0; 13473 13474 private_refresh(); 13475 13476 out: 13477 scf_transaction_destroy(tx); 13478 scf_entry_destroy(e); 13479 scf_pg_destroy(pg); 13480 scf_property_destroy(prop); 13481 free(pattern); 13482 13483 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 13484 free(sp->str); 13485 free(sp); 13486 } 13487 13488 uu_list_destroy(values); 13489 13490 return (result); 13491 13492 fail: 13493 result = -1; 13494 goto out; 13495 } 13496 13497 int 13498 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 13499 { 13500 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 13501 } 13502 13503 int 13504 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 13505 { 13506 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 13507 } 13508 13509 /* 13510 * Look for a standard start method, first in the instance (if any), 13511 * then the service. 13512 */ 13513 static const char * 13514 start_method_name(int *in_instance) 13515 { 13516 scf_propertygroup_t *pg; 13517 char **p; 13518 int ret; 13519 scf_instance_t *inst = cur_inst; 13520 13521 if ((pg = scf_pg_create(g_hndl)) == NULL) 13522 scfdie(); 13523 13524 again: 13525 for (p = start_method_names; *p != NULL; p++) { 13526 if (inst != NULL) 13527 ret = scf_instance_get_pg(inst, *p, pg); 13528 else 13529 ret = scf_service_get_pg(cur_svc, *p, pg); 13530 13531 if (ret == 0) { 13532 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 13533 char *buf = safe_malloc(bufsz); 13534 13535 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 13536 free(buf); 13537 continue; 13538 } 13539 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 13540 free(buf); 13541 continue; 13542 } 13543 13544 free(buf); 13545 *in_instance = (inst != NULL); 13546 scf_pg_destroy(pg); 13547 return (*p); 13548 } 13549 13550 if (scf_error() == SCF_ERROR_NOT_FOUND) 13551 continue; 13552 13553 scfdie(); 13554 } 13555 13556 if (inst != NULL) { 13557 inst = NULL; 13558 goto again; 13559 } 13560 13561 scf_pg_destroy(pg); 13562 return (NULL); 13563 } 13564 13565 static int 13566 addpg(const char *name, const char *type) 13567 { 13568 scf_propertygroup_t *pg; 13569 int ret; 13570 13571 pg = scf_pg_create(g_hndl); 13572 if (pg == NULL) 13573 scfdie(); 13574 13575 if (cur_inst != NULL) 13576 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 13577 else 13578 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 13579 13580 if (ret != 0) { 13581 switch (scf_error()) { 13582 case SCF_ERROR_EXISTS: 13583 ret = 0; 13584 break; 13585 13586 case SCF_ERROR_PERMISSION_DENIED: 13587 semerr(emsg_permission_denied); 13588 break; 13589 13590 default: 13591 scfdie(); 13592 } 13593 } 13594 13595 scf_pg_destroy(pg); 13596 return (ret); 13597 } 13598 13599 int 13600 lscf_setenv(uu_list_t *args, int isunset) 13601 { 13602 int ret = 0; 13603 size_t i; 13604 int argc; 13605 char **argv = NULL; 13606 string_list_t *slp; 13607 char *pattern; 13608 char *prop; 13609 int do_service = 0; 13610 int do_instance = 0; 13611 const char *method = NULL; 13612 const char *name = NULL; 13613 const char *value = NULL; 13614 scf_instance_t *saved_cur_inst = cur_inst; 13615 13616 lscf_prep_hndl(); 13617 13618 argc = uu_list_numnodes(args); 13619 if (argc < 1) 13620 goto usage; 13621 13622 argv = calloc(argc + 1, sizeof (char *)); 13623 if (argv == NULL) 13624 uu_die(gettext("Out of memory.\n")); 13625 13626 for (slp = uu_list_first(args), i = 0; 13627 slp != NULL; 13628 slp = uu_list_next(args, slp), ++i) 13629 argv[i] = slp->str; 13630 13631 argv[i] = NULL; 13632 13633 opterr = 0; 13634 optind = 0; 13635 for (;;) { 13636 ret = getopt(argc, argv, "sim:"); 13637 if (ret == -1) 13638 break; 13639 13640 switch (ret) { 13641 case 's': 13642 do_service = 1; 13643 cur_inst = NULL; 13644 break; 13645 13646 case 'i': 13647 do_instance = 1; 13648 break; 13649 13650 case 'm': 13651 method = optarg; 13652 break; 13653 13654 case '?': 13655 goto usage; 13656 13657 default: 13658 bad_error("getopt", ret); 13659 } 13660 } 13661 13662 argc -= optind; 13663 if ((do_service && do_instance) || 13664 (isunset && argc != 1) || 13665 (!isunset && argc != 2)) 13666 goto usage; 13667 13668 name = argv[optind]; 13669 if (!isunset) 13670 value = argv[optind + 1]; 13671 13672 if (cur_snap != NULL) { 13673 semerr(emsg_cant_modify_snapshots); 13674 ret = -1; 13675 goto out; 13676 } 13677 13678 if (cur_inst == NULL && cur_svc == NULL) { 13679 semerr(emsg_entity_not_selected); 13680 ret = -1; 13681 goto out; 13682 } 13683 13684 if (do_instance && cur_inst == NULL) { 13685 semerr(gettext("No instance is selected.\n")); 13686 ret = -1; 13687 goto out; 13688 } 13689 13690 if (do_service && cur_svc == NULL) { 13691 semerr(gettext("No service is selected.\n")); 13692 ret = -1; 13693 goto out; 13694 } 13695 13696 if (method == NULL) { 13697 if (do_instance || do_service) { 13698 method = "method_context"; 13699 if (!isunset) { 13700 ret = addpg("method_context", 13701 SCF_GROUP_FRAMEWORK); 13702 if (ret != 0) 13703 goto out; 13704 } 13705 } else { 13706 int in_instance; 13707 method = start_method_name(&in_instance); 13708 if (method == NULL) { 13709 semerr(gettext( 13710 "Couldn't find start method; please " 13711 "specify a method with '-m'.\n")); 13712 ret = -1; 13713 goto out; 13714 } 13715 if (!in_instance) 13716 cur_inst = NULL; 13717 } 13718 } else { 13719 scf_propertygroup_t *pg; 13720 size_t bufsz; 13721 char *buf; 13722 int ret; 13723 13724 if ((pg = scf_pg_create(g_hndl)) == NULL) 13725 scfdie(); 13726 13727 if (cur_inst != NULL) 13728 ret = scf_instance_get_pg(cur_inst, method, pg); 13729 else 13730 ret = scf_service_get_pg(cur_svc, method, pg); 13731 13732 if (ret != 0) { 13733 scf_pg_destroy(pg); 13734 switch (scf_error()) { 13735 case SCF_ERROR_NOT_FOUND: 13736 semerr(gettext("Couldn't find the method " 13737 "\"%s\".\n"), method); 13738 goto out; 13739 13740 case SCF_ERROR_INVALID_ARGUMENT: 13741 semerr(gettext("Invalid method name \"%s\".\n"), 13742 method); 13743 goto out; 13744 13745 default: 13746 scfdie(); 13747 } 13748 } 13749 13750 bufsz = strlen(SCF_GROUP_METHOD) + 1; 13751 buf = safe_malloc(bufsz); 13752 13753 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 13754 strcmp(buf, SCF_GROUP_METHOD) != 0) { 13755 semerr(gettext("Property group \"%s\" is not of type " 13756 "\"method\".\n"), method); 13757 ret = -1; 13758 free(buf); 13759 scf_pg_destroy(pg); 13760 goto out; 13761 } 13762 13763 free(buf); 13764 scf_pg_destroy(pg); 13765 } 13766 13767 prop = uu_msprintf("%s/environment", method); 13768 pattern = uu_msprintf("%s=*", name); 13769 13770 if (prop == NULL || pattern == NULL) 13771 uu_die(gettext("Out of memory.\n")); 13772 13773 ret = lscf_delpropvalue(prop, pattern, !isunset); 13774 13775 if (ret == 0 && !isunset) { 13776 uu_free(pattern); 13777 uu_free(prop); 13778 prop = uu_msprintf("%s/environment", method); 13779 pattern = uu_msprintf("%s=%s", name, value); 13780 if (prop == NULL || pattern == NULL) 13781 uu_die(gettext("Out of memory.\n")); 13782 ret = lscf_addpropvalue(prop, "astring:", pattern); 13783 } 13784 uu_free(pattern); 13785 uu_free(prop); 13786 13787 out: 13788 cur_inst = saved_cur_inst; 13789 13790 free(argv); 13791 return (ret); 13792 usage: 13793 ret = -2; 13794 goto out; 13795 } 13796 13797 /* 13798 * Snapshot commands 13799 */ 13800 13801 void 13802 lscf_listsnap() 13803 { 13804 scf_snapshot_t *snap; 13805 scf_iter_t *iter; 13806 char *nb; 13807 int r; 13808 13809 lscf_prep_hndl(); 13810 13811 if (cur_inst == NULL) { 13812 semerr(gettext("Instance not selected.\n")); 13813 return; 13814 } 13815 13816 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13817 (iter = scf_iter_create(g_hndl)) == NULL) 13818 scfdie(); 13819 13820 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 13821 scfdie(); 13822 13823 nb = safe_malloc(max_scf_name_len + 1); 13824 13825 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 13826 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 13827 scfdie(); 13828 13829 (void) puts(nb); 13830 } 13831 if (r < 0) 13832 scfdie(); 13833 13834 free(nb); 13835 scf_iter_destroy(iter); 13836 scf_snapshot_destroy(snap); 13837 } 13838 13839 void 13840 lscf_selectsnap(const char *name) 13841 { 13842 scf_snapshot_t *snap; 13843 scf_snaplevel_t *level; 13844 13845 lscf_prep_hndl(); 13846 13847 if (cur_inst == NULL) { 13848 semerr(gettext("Instance not selected.\n")); 13849 return; 13850 } 13851 13852 if (cur_snap != NULL) { 13853 if (name != NULL) { 13854 char *cur_snap_name; 13855 boolean_t nochange; 13856 13857 cur_snap_name = safe_malloc(max_scf_name_len + 1); 13858 13859 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 13860 max_scf_name_len + 1) < 0) 13861 scfdie(); 13862 13863 nochange = strcmp(name, cur_snap_name) == 0; 13864 13865 free(cur_snap_name); 13866 13867 if (nochange) 13868 return; 13869 } 13870 13871 unselect_cursnap(); 13872 } 13873 13874 if (name == NULL) 13875 return; 13876 13877 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13878 (level = scf_snaplevel_create(g_hndl)) == NULL) 13879 scfdie(); 13880 13881 if (scf_instance_get_snapshot(cur_inst, name, snap) != 13882 SCF_SUCCESS) { 13883 switch (scf_error()) { 13884 case SCF_ERROR_INVALID_ARGUMENT: 13885 semerr(gettext("Invalid name \"%s\".\n"), name); 13886 break; 13887 13888 case SCF_ERROR_NOT_FOUND: 13889 semerr(gettext("No such snapshot \"%s\".\n"), name); 13890 break; 13891 13892 default: 13893 scfdie(); 13894 } 13895 13896 scf_snaplevel_destroy(level); 13897 scf_snapshot_destroy(snap); 13898 return; 13899 } 13900 13901 /* Load the snaplevels into our list. */ 13902 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 13903 if (cur_levels == NULL) 13904 uu_die(gettext("Could not create list: %s\n"), 13905 uu_strerror(uu_error())); 13906 13907 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 13908 if (scf_error() != SCF_ERROR_NOT_FOUND) 13909 scfdie(); 13910 13911 semerr(gettext("Snapshot has no snaplevels.\n")); 13912 13913 scf_snaplevel_destroy(level); 13914 scf_snapshot_destroy(snap); 13915 return; 13916 } 13917 13918 cur_snap = snap; 13919 13920 for (;;) { 13921 cur_elt = safe_malloc(sizeof (*cur_elt)); 13922 uu_list_node_init(cur_elt, &cur_elt->list_node, 13923 snaplevel_pool); 13924 cur_elt->sl = level; 13925 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 13926 uu_die(gettext("libuutil error: %s\n"), 13927 uu_strerror(uu_error())); 13928 13929 level = scf_snaplevel_create(g_hndl); 13930 if (level == NULL) 13931 scfdie(); 13932 13933 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 13934 level) != SCF_SUCCESS) { 13935 if (scf_error() != SCF_ERROR_NOT_FOUND) 13936 scfdie(); 13937 13938 scf_snaplevel_destroy(level); 13939 break; 13940 } 13941 } 13942 13943 cur_elt = uu_list_last(cur_levels); 13944 cur_level = cur_elt->sl; 13945 } 13946 13947 /* 13948 * Copies the properties & values in src to dst. Assumes src won't change. 13949 * Returns -1 if permission is denied, -2 if another transaction interrupts, 13950 * and 0 on success. 13951 * 13952 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 13953 * property, if it is copied and has type boolean. (See comment in 13954 * lscf_revert()). 13955 */ 13956 static int 13957 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 13958 uint8_t enabled) 13959 { 13960 scf_transaction_t *tx; 13961 scf_iter_t *iter, *viter; 13962 scf_property_t *prop; 13963 scf_value_t *v; 13964 char *nbuf; 13965 int r; 13966 13967 tx = scf_transaction_create(g_hndl); 13968 if (tx == NULL) 13969 scfdie(); 13970 13971 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 13972 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13973 scfdie(); 13974 13975 scf_transaction_destroy(tx); 13976 13977 return (-1); 13978 } 13979 13980 if ((iter = scf_iter_create(g_hndl)) == NULL || 13981 (prop = scf_property_create(g_hndl)) == NULL || 13982 (viter = scf_iter_create(g_hndl)) == NULL) 13983 scfdie(); 13984 13985 nbuf = safe_malloc(max_scf_name_len + 1); 13986 13987 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 13988 scfdie(); 13989 13990 for (;;) { 13991 scf_transaction_entry_t *e; 13992 scf_type_t ty; 13993 13994 r = scf_iter_next_property(iter, prop); 13995 if (r == -1) 13996 scfdie(); 13997 if (r == 0) 13998 break; 13999 14000 e = scf_entry_create(g_hndl); 14001 if (e == NULL) 14002 scfdie(); 14003 14004 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 14005 scfdie(); 14006 14007 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 14008 scfdie(); 14009 14010 if (scf_transaction_property_new(tx, e, nbuf, 14011 ty) != SCF_SUCCESS) 14012 scfdie(); 14013 14014 if ((enabled == 0 || enabled == 1) && 14015 strcmp(nbuf, scf_property_enabled) == 0 && 14016 ty == SCF_TYPE_BOOLEAN) { 14017 v = scf_value_create(g_hndl); 14018 if (v == NULL) 14019 scfdie(); 14020 14021 scf_value_set_boolean(v, enabled); 14022 14023 if (scf_entry_add_value(e, v) != 0) 14024 scfdie(); 14025 } else { 14026 if (scf_iter_property_values(viter, prop) != 0) 14027 scfdie(); 14028 14029 for (;;) { 14030 v = scf_value_create(g_hndl); 14031 if (v == NULL) 14032 scfdie(); 14033 14034 r = scf_iter_next_value(viter, v); 14035 if (r == -1) 14036 scfdie(); 14037 if (r == 0) { 14038 scf_value_destroy(v); 14039 break; 14040 } 14041 14042 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 14043 scfdie(); 14044 } 14045 } 14046 } 14047 14048 free(nbuf); 14049 scf_iter_destroy(viter); 14050 scf_property_destroy(prop); 14051 scf_iter_destroy(iter); 14052 14053 r = scf_transaction_commit(tx); 14054 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 14055 scfdie(); 14056 14057 scf_transaction_destroy_children(tx); 14058 scf_transaction_destroy(tx); 14059 14060 switch (r) { 14061 case 1: return (0); 14062 case 0: return (-2); 14063 case -1: return (-1); 14064 14065 default: 14066 abort(); 14067 } 14068 14069 /* NOTREACHED */ 14070 } 14071 14072 void 14073 lscf_revert(const char *snapname) 14074 { 14075 scf_snapshot_t *snap, *prev; 14076 scf_snaplevel_t *level, *nlevel; 14077 scf_iter_t *iter; 14078 scf_propertygroup_t *pg, *npg; 14079 scf_property_t *prop; 14080 scf_value_t *val; 14081 char *nbuf, *tbuf; 14082 uint8_t enabled; 14083 14084 lscf_prep_hndl(); 14085 14086 if (cur_inst == NULL) { 14087 semerr(gettext("Instance not selected.\n")); 14088 return; 14089 } 14090 14091 if (snapname != NULL) { 14092 snap = scf_snapshot_create(g_hndl); 14093 if (snap == NULL) 14094 scfdie(); 14095 14096 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 14097 SCF_SUCCESS) { 14098 switch (scf_error()) { 14099 case SCF_ERROR_INVALID_ARGUMENT: 14100 semerr(gettext("Invalid snapshot name " 14101 "\"%s\".\n"), snapname); 14102 break; 14103 14104 case SCF_ERROR_NOT_FOUND: 14105 semerr(gettext("No such snapshot.\n")); 14106 break; 14107 14108 default: 14109 scfdie(); 14110 } 14111 14112 scf_snapshot_destroy(snap); 14113 return; 14114 } 14115 } else { 14116 if (cur_snap != NULL) { 14117 snap = cur_snap; 14118 } else { 14119 semerr(gettext("No snapshot selected.\n")); 14120 return; 14121 } 14122 } 14123 14124 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 14125 (level = scf_snaplevel_create(g_hndl)) == NULL || 14126 (iter = scf_iter_create(g_hndl)) == NULL || 14127 (pg = scf_pg_create(g_hndl)) == NULL || 14128 (npg = scf_pg_create(g_hndl)) == NULL || 14129 (prop = scf_property_create(g_hndl)) == NULL || 14130 (val = scf_value_create(g_hndl)) == NULL) 14131 scfdie(); 14132 14133 nbuf = safe_malloc(max_scf_name_len + 1); 14134 tbuf = safe_malloc(max_scf_pg_type_len + 1); 14135 14136 /* Take the "previous" snapshot before we blow away the properties. */ 14137 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 14138 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 14139 scfdie(); 14140 } else { 14141 if (scf_error() != SCF_ERROR_NOT_FOUND) 14142 scfdie(); 14143 14144 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 14145 scfdie(); 14146 } 14147 14148 /* Save general/enabled, since we're probably going to replace it. */ 14149 enabled = 2; 14150 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 14151 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 14152 scf_property_get_value(prop, val) == 0) 14153 (void) scf_value_get_boolean(val, &enabled); 14154 14155 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 14156 if (scf_error() != SCF_ERROR_NOT_FOUND) 14157 scfdie(); 14158 14159 goto out; 14160 } 14161 14162 for (;;) { 14163 boolean_t isinst; 14164 uint32_t flags; 14165 int r; 14166 14167 /* Clear the properties from the corresponding entity. */ 14168 isinst = snaplevel_is_instance(level); 14169 14170 if (!isinst) 14171 r = scf_iter_service_pgs(iter, cur_svc); 14172 else 14173 r = scf_iter_instance_pgs(iter, cur_inst); 14174 if (r != SCF_SUCCESS) 14175 scfdie(); 14176 14177 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 14178 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 14179 scfdie(); 14180 14181 /* Skip nonpersistent pgs. */ 14182 if (flags & SCF_PG_FLAG_NONPERSISTENT) 14183 continue; 14184 14185 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14186 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14187 scfdie(); 14188 14189 semerr(emsg_permission_denied); 14190 goto out; 14191 } 14192 } 14193 if (r == -1) 14194 scfdie(); 14195 14196 /* Copy the properties to the corresponding entity. */ 14197 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 14198 scfdie(); 14199 14200 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 14201 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 14202 scfdie(); 14203 14204 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 14205 0) 14206 scfdie(); 14207 14208 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 14209 scfdie(); 14210 14211 if (!isinst) 14212 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 14213 flags, npg); 14214 else 14215 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 14216 flags, npg); 14217 if (r != SCF_SUCCESS) { 14218 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14219 scfdie(); 14220 14221 semerr(emsg_permission_denied); 14222 goto out; 14223 } 14224 14225 if ((enabled == 0 || enabled == 1) && 14226 strcmp(nbuf, scf_pg_general) == 0) 14227 r = pg_copy(pg, npg, enabled); 14228 else 14229 r = pg_copy(pg, npg, 2); 14230 14231 switch (r) { 14232 case 0: 14233 break; 14234 14235 case -1: 14236 semerr(emsg_permission_denied); 14237 goto out; 14238 14239 case -2: 14240 semerr(gettext( 14241 "Interrupted by another change.\n")); 14242 goto out; 14243 14244 default: 14245 abort(); 14246 } 14247 } 14248 if (r == -1) 14249 scfdie(); 14250 14251 /* Get next level. */ 14252 nlevel = scf_snaplevel_create(g_hndl); 14253 if (nlevel == NULL) 14254 scfdie(); 14255 14256 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 14257 SCF_SUCCESS) { 14258 if (scf_error() != SCF_ERROR_NOT_FOUND) 14259 scfdie(); 14260 14261 scf_snaplevel_destroy(nlevel); 14262 break; 14263 } 14264 14265 scf_snaplevel_destroy(level); 14266 level = nlevel; 14267 } 14268 14269 if (snapname == NULL) { 14270 lscf_selectsnap(NULL); 14271 snap = NULL; /* cur_snap has been destroyed */ 14272 } 14273 14274 out: 14275 free(tbuf); 14276 free(nbuf); 14277 scf_value_destroy(val); 14278 scf_property_destroy(prop); 14279 scf_pg_destroy(npg); 14280 scf_pg_destroy(pg); 14281 scf_iter_destroy(iter); 14282 scf_snaplevel_destroy(level); 14283 scf_snapshot_destroy(prev); 14284 if (snap != cur_snap) 14285 scf_snapshot_destroy(snap); 14286 } 14287 14288 void 14289 lscf_refresh(void) 14290 { 14291 ssize_t fmrilen; 14292 size_t bufsz; 14293 char *fmribuf; 14294 int r; 14295 14296 lscf_prep_hndl(); 14297 14298 if (cur_inst == NULL) { 14299 semerr(gettext("Instance not selected.\n")); 14300 return; 14301 } 14302 14303 bufsz = max_scf_fmri_len + 1; 14304 fmribuf = safe_malloc(bufsz); 14305 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 14306 if (fmrilen < 0) { 14307 free(fmribuf); 14308 if (scf_error() != SCF_ERROR_DELETED) 14309 scfdie(); 14310 scf_instance_destroy(cur_inst); 14311 cur_inst = NULL; 14312 warn(emsg_deleted); 14313 return; 14314 } 14315 assert(fmrilen < bufsz); 14316 14317 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 14318 switch (r) { 14319 case 0: 14320 break; 14321 14322 case ECONNABORTED: 14323 warn(gettext("Could not refresh %s " 14324 "(repository connection broken).\n"), fmribuf); 14325 break; 14326 14327 case ECANCELED: 14328 warn(emsg_deleted); 14329 break; 14330 14331 case EPERM: 14332 warn(gettext("Could not refresh %s " 14333 "(permission denied).\n"), fmribuf); 14334 break; 14335 14336 case ENOSPC: 14337 warn(gettext("Could not refresh %s " 14338 "(repository server out of resources).\n"), 14339 fmribuf); 14340 break; 14341 14342 case EACCES: 14343 default: 14344 bad_error("refresh_entity", scf_error()); 14345 } 14346 14347 free(fmribuf); 14348 } 14349 14350 /* 14351 * describe [-v] [-t] [pg/prop] 14352 */ 14353 int 14354 lscf_describe(uu_list_t *args, int hasargs) 14355 { 14356 int ret = 0; 14357 size_t i; 14358 int argc; 14359 char **argv = NULL; 14360 string_list_t *slp; 14361 int do_verbose = 0; 14362 int do_templates = 0; 14363 char *pattern = NULL; 14364 14365 lscf_prep_hndl(); 14366 14367 if (hasargs != 0) { 14368 argc = uu_list_numnodes(args); 14369 if (argc < 1) 14370 goto usage; 14371 14372 argv = calloc(argc + 1, sizeof (char *)); 14373 if (argv == NULL) 14374 uu_die(gettext("Out of memory.\n")); 14375 14376 for (slp = uu_list_first(args), i = 0; 14377 slp != NULL; 14378 slp = uu_list_next(args, slp), ++i) 14379 argv[i] = slp->str; 14380 14381 argv[i] = NULL; 14382 14383 /* 14384 * We start optind = 0 because our list of arguments 14385 * starts at argv[0] 14386 */ 14387 optind = 0; 14388 opterr = 0; 14389 for (;;) { 14390 ret = getopt(argc, argv, "vt"); 14391 if (ret == -1) 14392 break; 14393 14394 switch (ret) { 14395 case 'v': 14396 do_verbose = 1; 14397 break; 14398 14399 case 't': 14400 do_templates = 1; 14401 break; 14402 14403 case '?': 14404 goto usage; 14405 14406 default: 14407 bad_error("getopt", ret); 14408 } 14409 } 14410 14411 pattern = argv[optind]; 14412 } 14413 14414 if (cur_inst == NULL && cur_svc == NULL) { 14415 semerr(emsg_entity_not_selected); 14416 ret = -1; 14417 goto out; 14418 } 14419 14420 /* 14421 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 14422 * output if their last parameter is set to 2. Less information is 14423 * produced if the parameter is set to 1. 14424 */ 14425 if (pattern == NULL) { 14426 if (do_verbose == 1) 14427 list_entity_tmpl(2); 14428 else 14429 list_entity_tmpl(1); 14430 } 14431 14432 if (do_templates == 0) { 14433 if (do_verbose == 1) 14434 listprop(pattern, 0, 2); 14435 else 14436 listprop(pattern, 0, 1); 14437 } else { 14438 if (do_verbose == 1) 14439 listtmpl(pattern, 2); 14440 else 14441 listtmpl(pattern, 1); 14442 } 14443 14444 ret = 0; 14445 out: 14446 if (argv != NULL) 14447 free(argv); 14448 return (ret); 14449 usage: 14450 ret = -2; 14451 goto out; 14452 } 14453 14454 /* 14455 * Creates a list of instance name strings associated with a service. If 14456 * wohandcrafted flag is set, get only instances that have a last-import 14457 * snapshot, instances that were imported via svccfg. 14458 */ 14459 static uu_list_t * 14460 create_instance_list(scf_service_t *svc, int wohandcrafted) 14461 { 14462 scf_snapshot_t *snap = NULL; 14463 scf_instance_t *inst; 14464 scf_iter_t *inst_iter; 14465 uu_list_t *instances; 14466 char *instname; 14467 int r; 14468 14469 inst_iter = scf_iter_create(g_hndl); 14470 inst = scf_instance_create(g_hndl); 14471 if (inst_iter == NULL || inst == NULL) { 14472 uu_warn(gettext("Could not create instance or iterator\n")); 14473 scfdie(); 14474 } 14475 14476 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 14477 return (instances); 14478 14479 if (scf_iter_service_instances(inst_iter, svc) != 0) { 14480 switch (scf_error()) { 14481 case SCF_ERROR_CONNECTION_BROKEN: 14482 case SCF_ERROR_DELETED: 14483 uu_list_destroy(instances); 14484 instances = NULL; 14485 goto out; 14486 14487 case SCF_ERROR_HANDLE_MISMATCH: 14488 case SCF_ERROR_NOT_BOUND: 14489 case SCF_ERROR_NOT_SET: 14490 default: 14491 bad_error("scf_iter_service_instances", scf_error()); 14492 } 14493 } 14494 14495 instname = safe_malloc(max_scf_name_len + 1); 14496 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 14497 if (r == -1) { 14498 (void) uu_warn(gettext("Unable to iterate through " 14499 "instances to create instance list : %s\n"), 14500 scf_strerror(scf_error())); 14501 14502 uu_list_destroy(instances); 14503 instances = NULL; 14504 goto out; 14505 } 14506 14507 /* 14508 * If the instance does not have a last-import snapshot 14509 * then do not add it to the list as it is a hand-crafted 14510 * instance that should not be managed. 14511 */ 14512 if (wohandcrafted) { 14513 if (snap == NULL && 14514 (snap = scf_snapshot_create(g_hndl)) == NULL) { 14515 uu_warn(gettext("Unable to create snapshot " 14516 "entity\n")); 14517 scfdie(); 14518 } 14519 14520 if (scf_instance_get_snapshot(inst, 14521 snap_lastimport, snap) != 0) { 14522 switch (scf_error()) { 14523 case SCF_ERROR_NOT_FOUND : 14524 case SCF_ERROR_DELETED: 14525 continue; 14526 14527 case SCF_ERROR_CONNECTION_BROKEN: 14528 uu_list_destroy(instances); 14529 instances = NULL; 14530 goto out; 14531 14532 case SCF_ERROR_HANDLE_MISMATCH: 14533 case SCF_ERROR_NOT_BOUND: 14534 case SCF_ERROR_NOT_SET: 14535 default: 14536 bad_error("scf_iter_service_instances", 14537 scf_error()); 14538 } 14539 } 14540 } 14541 14542 if (scf_instance_get_name(inst, instname, 14543 max_scf_name_len + 1) < 0) { 14544 switch (scf_error()) { 14545 case SCF_ERROR_NOT_FOUND : 14546 continue; 14547 14548 case SCF_ERROR_CONNECTION_BROKEN: 14549 case SCF_ERROR_DELETED: 14550 uu_list_destroy(instances); 14551 instances = NULL; 14552 goto out; 14553 14554 case SCF_ERROR_HANDLE_MISMATCH: 14555 case SCF_ERROR_NOT_BOUND: 14556 case SCF_ERROR_NOT_SET: 14557 default: 14558 bad_error("scf_iter_service_instances", 14559 scf_error()); 14560 } 14561 } 14562 14563 add_string(instances, instname); 14564 } 14565 14566 out: 14567 if (snap) 14568 scf_snapshot_destroy(snap); 14569 14570 scf_instance_destroy(inst); 14571 scf_iter_destroy(inst_iter); 14572 free(instname); 14573 return (instances); 14574 } 14575 14576 /* 14577 * disable an instance but wait for the instance to 14578 * move out of the running state. 14579 * 14580 * Returns 0 : if the instance did not disable 14581 * Returns non-zero : if the instance disabled. 14582 * 14583 */ 14584 static int 14585 disable_instance(scf_instance_t *instance) 14586 { 14587 char *fmribuf; 14588 int enabled = 10000; 14589 14590 if (inst_is_running(instance)) { 14591 fmribuf = safe_malloc(max_scf_name_len + 1); 14592 if (scf_instance_to_fmri(instance, fmribuf, 14593 max_scf_name_len + 1) < 0) { 14594 free(fmribuf); 14595 return (0); 14596 } 14597 14598 /* 14599 * If the instance cannot be disabled then return 14600 * failure to disable and let the caller decide 14601 * if that is of importance. 14602 */ 14603 if (smf_disable_instance(fmribuf, 0) != 0) { 14604 free(fmribuf); 14605 return (0); 14606 } 14607 14608 while (enabled) { 14609 if (!inst_is_running(instance)) 14610 break; 14611 14612 (void) poll(NULL, 0, 5); 14613 enabled = enabled - 5; 14614 } 14615 14616 free(fmribuf); 14617 } 14618 14619 return (enabled); 14620 } 14621 14622 /* 14623 * Function to compare two service_manifest structures. 14624 */ 14625 /* ARGSUSED2 */ 14626 static int 14627 service_manifest_compare(const void *left, const void *right, void *unused) 14628 { 14629 service_manifest_t *l = (service_manifest_t *)left; 14630 service_manifest_t *r = (service_manifest_t *)right; 14631 int rc; 14632 14633 rc = strcmp(l->servicename, r->servicename); 14634 14635 return (rc); 14636 } 14637 14638 /* 14639 * Look for the provided service in the service to manifest 14640 * tree. If the service exists, and a manifest was provided 14641 * then add the manifest to that service. If the service 14642 * does not exist, then add the service and manifest to the 14643 * list. 14644 * 14645 * If the manifest is NULL, return the element if found. If 14646 * the service is not found return NULL. 14647 */ 14648 service_manifest_t * 14649 find_add_svc_mfst(const char *svnbuf, const char *mfst) 14650 { 14651 service_manifest_t elem; 14652 service_manifest_t *fnelem; 14653 uu_avl_index_t marker; 14654 14655 elem.servicename = svnbuf; 14656 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 14657 14658 if (mfst) { 14659 if (fnelem) { 14660 add_string(fnelem->mfstlist, strdup(mfst)); 14661 } else { 14662 fnelem = safe_malloc(sizeof (*fnelem)); 14663 fnelem->servicename = safe_strdup(svnbuf); 14664 if ((fnelem->mfstlist = 14665 uu_list_create(string_pool, NULL, 0)) == NULL) 14666 uu_die(gettext("Could not create property " 14667 "list: %s\n"), uu_strerror(uu_error())); 14668 14669 add_string(fnelem->mfstlist, safe_strdup(mfst)); 14670 14671 uu_avl_insert(service_manifest_tree, fnelem, marker); 14672 } 14673 } 14674 14675 return (fnelem); 14676 } 14677 14678 /* 14679 * Create the service to manifest avl tree. 14680 * 14681 * Walk each of the manifests currently installed in the supported 14682 * directories, /lib/svc/manifests and /var/svc/manifests. For 14683 * each of the manifests, inventory the services and add them to 14684 * the tree. 14685 * 14686 * Code that calls this function should make sure fileystem/minimal is online, 14687 * /var is available, since this function walks the /var/svc/manifest directory. 14688 */ 14689 static void 14690 create_manifest_tree(void) 14691 { 14692 manifest_info_t **entry; 14693 manifest_info_t **manifests; 14694 uu_list_walk_t *svcs; 14695 bundle_t *b; 14696 entity_t *mfsvc; 14697 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 14698 int c, status; 14699 14700 if (service_manifest_pool) 14701 return; 14702 14703 /* 14704 * Create the list pool for the service manifest list 14705 */ 14706 service_manifest_pool = uu_avl_pool_create("service_manifest", 14707 sizeof (service_manifest_t), 14708 offsetof(service_manifest_t, svcmfst_node), 14709 service_manifest_compare, UU_DEFAULT); 14710 if (service_manifest_pool == NULL) 14711 uu_die(gettext("service_manifest pool creation failed: %s\n"), 14712 uu_strerror(uu_error())); 14713 14714 /* 14715 * Create the list 14716 */ 14717 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 14718 UU_DEFAULT); 14719 if (service_manifest_tree == NULL) 14720 uu_die(gettext("service_manifest tree creation failed: %s\n"), 14721 uu_strerror(uu_error())); 14722 14723 /* 14724 * Walk the manifests adding the service(s) from each manifest. 14725 * 14726 * If a service already exists add the manifest to the manifest 14727 * list for that service. This covers the case of a service that 14728 * is supported by multiple manifest files. 14729 */ 14730 for (c = 0; dirs[c]; c++) { 14731 status = find_manifests(dirs[c], &manifests, CHECKEXT); 14732 if (status < 0) { 14733 uu_warn(gettext("file tree walk of %s encountered " 14734 "error %s\n"), dirs[c], strerror(errno)); 14735 14736 uu_avl_destroy(service_manifest_tree); 14737 service_manifest_tree = NULL; 14738 return; 14739 } 14740 14741 /* 14742 * If a manifest that was in the list is not found 14743 * then skip and go to the next manifest file. 14744 */ 14745 if (manifests != NULL) { 14746 for (entry = manifests; *entry != NULL; entry++) { 14747 b = internal_bundle_new(); 14748 if (lxml_get_bundle_file(b, (*entry)->mi_path, 14749 SVCCFG_OP_IMPORT) != 0) { 14750 internal_bundle_free(b); 14751 continue; 14752 } 14753 14754 svcs = uu_list_walk_start(b->sc_bundle_services, 14755 0); 14756 if (svcs == NULL) { 14757 internal_bundle_free(b); 14758 continue; 14759 } 14760 14761 while ((mfsvc = uu_list_walk_next(svcs)) != 14762 NULL) { 14763 /* Add manifest to service */ 14764 (void) find_add_svc_mfst(mfsvc->sc_name, 14765 (*entry)->mi_path); 14766 } 14767 14768 uu_list_walk_end(svcs); 14769 internal_bundle_free(b); 14770 } 14771 14772 free_manifest_array(manifests); 14773 } 14774 } 14775 } 14776 14777 /* 14778 * Check the manifest history file to see 14779 * if the service was ever installed from 14780 * one of the supported directories. 14781 * 14782 * Return Values : 14783 * -1 - if there's error reading manifest history file 14784 * 1 - if the service is not found 14785 * 0 - if the service is found 14786 */ 14787 static int 14788 check_mfst_history(const char *svcname) 14789 { 14790 struct stat st; 14791 caddr_t mfsthist_start; 14792 char *svnbuf; 14793 int fd; 14794 int r = 1; 14795 14796 fd = open(MFSTHISTFILE, O_RDONLY); 14797 if (fd == -1) { 14798 uu_warn(gettext("Unable to open the history file\n")); 14799 return (-1); 14800 } 14801 14802 if (fstat(fd, &st) == -1) { 14803 uu_warn(gettext("Unable to stat the history file\n")); 14804 return (-1); 14805 } 14806 14807 mfsthist_start = mmap(0, st.st_size, PROT_READ, 14808 MAP_PRIVATE, fd, 0); 14809 14810 (void) close(fd); 14811 if (mfsthist_start == MAP_FAILED || 14812 *(mfsthist_start + st.st_size) != '\0') { 14813 (void) munmap(mfsthist_start, st.st_size); 14814 return (-1); 14815 } 14816 14817 /* 14818 * The manifest history file is a space delimited list 14819 * of service and instance to manifest linkage. Adding 14820 * a space to the end of the service name so to get only 14821 * the service that is being searched for. 14822 */ 14823 svnbuf = uu_msprintf("%s ", svcname); 14824 if (svnbuf == NULL) 14825 uu_die(gettext("Out of memory")); 14826 14827 if (strstr(mfsthist_start, svnbuf) != NULL) 14828 r = 0; 14829 14830 (void) munmap(mfsthist_start, st.st_size); 14831 uu_free(svnbuf); 14832 return (r); 14833 } 14834 14835 /* 14836 * Take down each of the instances in the service 14837 * and remove them, then delete the service. 14838 */ 14839 static void 14840 teardown_service(scf_service_t *svc, const char *svnbuf) 14841 { 14842 scf_instance_t *instance; 14843 scf_iter_t *iter; 14844 int r; 14845 14846 safe_printf(gettext("Delete service %s as there are no " 14847 "supporting manifests\n"), svnbuf); 14848 14849 instance = scf_instance_create(g_hndl); 14850 iter = scf_iter_create(g_hndl); 14851 if (iter == NULL || instance == NULL) { 14852 uu_warn(gettext("Unable to create supporting entities to " 14853 "teardown the service\n")); 14854 uu_warn(gettext("scf error is : %s\n"), 14855 scf_strerror(scf_error())); 14856 scfdie(); 14857 } 14858 14859 if (scf_iter_service_instances(iter, svc) != 0) { 14860 switch (scf_error()) { 14861 case SCF_ERROR_CONNECTION_BROKEN: 14862 case SCF_ERROR_DELETED: 14863 goto out; 14864 14865 case SCF_ERROR_HANDLE_MISMATCH: 14866 case SCF_ERROR_NOT_BOUND: 14867 case SCF_ERROR_NOT_SET: 14868 default: 14869 bad_error("scf_iter_service_instances", 14870 scf_error()); 14871 } 14872 } 14873 14874 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 14875 if (r == -1) { 14876 uu_warn(gettext("Error - %s\n"), 14877 scf_strerror(scf_error())); 14878 goto out; 14879 } 14880 14881 (void) disable_instance(instance); 14882 } 14883 14884 /* 14885 * Delete the service... forcing the deletion in case 14886 * any of the instances did not disable. 14887 */ 14888 (void) lscf_service_delete(svc, 1); 14889 out: 14890 scf_instance_destroy(instance); 14891 scf_iter_destroy(iter); 14892 } 14893 14894 /* 14895 * Get the list of instances supported by the manifest 14896 * file. 14897 * 14898 * Return 0 if there are no instances. 14899 * 14900 * Return -1 if there are errors attempting to collect instances. 14901 * 14902 * Return the count of instances found if there are no errors. 14903 * 14904 */ 14905 static int 14906 check_instance_support(char *mfstfile, const char *svcname, 14907 uu_list_t *instances) 14908 { 14909 uu_list_walk_t *svcs, *insts; 14910 uu_list_t *ilist; 14911 bundle_t *b; 14912 entity_t *mfsvc, *mfinst; 14913 const char *svcn; 14914 int rminstcnt = 0; 14915 14916 14917 b = internal_bundle_new(); 14918 14919 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 14920 /* 14921 * Unable to process the manifest file for 14922 * instance support, so just return as 14923 * don't want to remove instances that could 14924 * not be accounted for that might exist here. 14925 */ 14926 internal_bundle_free(b); 14927 return (0); 14928 } 14929 14930 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 14931 if (svcs == NULL) { 14932 internal_bundle_free(b); 14933 return (0); 14934 } 14935 14936 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 14937 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 14938 14939 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 14940 if (strcmp(mfsvc->sc_name, svcn) == 0) 14941 break; 14942 } 14943 uu_list_walk_end(svcs); 14944 14945 if (mfsvc == NULL) { 14946 internal_bundle_free(b); 14947 return (-1); 14948 } 14949 14950 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 14951 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 14952 internal_bundle_free(b); 14953 return (0); 14954 } 14955 14956 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 14957 /* 14958 * Remove the instance from the instances list. 14959 * The unaccounted for instances will be removed 14960 * from the service once all manifests are 14961 * processed. 14962 */ 14963 (void) remove_string(instances, 14964 mfinst->sc_name); 14965 rminstcnt++; 14966 } 14967 14968 uu_list_walk_end(insts); 14969 internal_bundle_free(b); 14970 14971 return (rminstcnt); 14972 } 14973 14974 /* 14975 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 14976 * 'false' to indicate there's no manifest file(s) found for the service. 14977 */ 14978 static void 14979 svc_add_no_support(scf_service_t *svc) 14980 { 14981 char *pname; 14982 14983 /* Add no support */ 14984 cur_svc = svc; 14985 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 14986 return; 14987 14988 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 14989 if (pname == NULL) 14990 uu_die(gettext("Out of memory.\n")); 14991 14992 (void) lscf_addpropvalue(pname, "boolean:", "0"); 14993 14994 uu_free(pname); 14995 cur_svc = NULL; 14996 } 14997 14998 /* 14999 * This function handles all upgrade scenarios for a service that doesn't have 15000 * SCF_PG_MANIFESTFILES pg. The function creates and populates 15001 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 15002 * manifest(s) mapping. Manifests under supported directories are inventoried 15003 * and a property is added for each file that delivers configuration to the 15004 * service. A service that has no corresponding manifest files (deleted) are 15005 * removed from repository. 15006 * 15007 * Unsupported services: 15008 * 15009 * A service is considered unsupported if there is no corresponding manifest 15010 * in the supported directories for that service and the service isn't in the 15011 * history file list. The history file, MFSTHISTFILE, contains a list of all 15012 * services and instances that were delivered by Solaris before the introduction 15013 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 15014 * the path to the manifest file that defined the service or instance. 15015 * 15016 * Another type of unsupported services is 'handcrafted' services, 15017 * programmatically created services or services created by dependent entries 15018 * in other manifests. A handcrafted service is identified by its lack of any 15019 * instance containing last-import snapshot which is created during svccfg 15020 * import. 15021 * 15022 * This function sets a flag for unsupported services by setting services' 15023 * SCF_PG_MANIFESTFILES/support property to false. 15024 */ 15025 static void 15026 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 15027 { 15028 service_manifest_t *elem; 15029 uu_list_walk_t *mfwalk; 15030 string_list_t *mfile; 15031 uu_list_t *instances; 15032 const char *sname; 15033 char *pname; 15034 int r; 15035 15036 /* 15037 * Since there's no guarantee manifests under /var are available during 15038 * early import, don't perform any upgrade during early import. 15039 */ 15040 if (IGNORE_VAR) 15041 return; 15042 15043 if (service_manifest_tree == NULL) { 15044 create_manifest_tree(); 15045 } 15046 15047 /* 15048 * Find service's supporting manifest(s) after 15049 * stripping off the svc:/ prefix that is part 15050 * of the fmri that is not used in the service 15051 * manifest bundle list. 15052 */ 15053 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 15054 strlen(SCF_FMRI_SERVICE_PREFIX); 15055 elem = find_add_svc_mfst(sname, NULL); 15056 if (elem == NULL) { 15057 15058 /* 15059 * A handcrafted service, one that has no instance containing 15060 * last-import snapshot, should get unsupported flag. 15061 */ 15062 instances = create_instance_list(svc, 1); 15063 if (instances == NULL) { 15064 uu_warn(gettext("Unable to create instance list %s\n"), 15065 svcname); 15066 return; 15067 } 15068 15069 if (uu_list_numnodes(instances) == 0) { 15070 svc_add_no_support(svc); 15071 return; 15072 } 15073 15074 /* 15075 * If the service is in the history file, and its supporting 15076 * manifests are not found, we can safely delete the service 15077 * because its manifests are removed from the system. 15078 * 15079 * Services not found in the history file are not delivered by 15080 * Solaris and/or delivered outside supported directories, set 15081 * unsupported flag for these services. 15082 */ 15083 r = check_mfst_history(svcname); 15084 if (r == -1) 15085 return; 15086 15087 if (r) { 15088 /* Set unsupported flag for service */ 15089 svc_add_no_support(svc); 15090 } else { 15091 /* Delete the service */ 15092 teardown_service(svc, svcname); 15093 } 15094 15095 return; 15096 } 15097 15098 /* 15099 * Walk through the list of manifests and add them 15100 * to the service. 15101 * 15102 * Create a manifestfiles pg and add the property. 15103 */ 15104 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 15105 if (mfwalk == NULL) 15106 return; 15107 15108 cur_svc = svc; 15109 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 15110 if (r != 0) { 15111 cur_svc = NULL; 15112 return; 15113 } 15114 15115 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 15116 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 15117 mhash_filename_to_propname(mfile->str, 0)); 15118 if (pname == NULL) 15119 uu_die(gettext("Out of memory.\n")); 15120 15121 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 15122 uu_free(pname); 15123 } 15124 uu_list_walk_end(mfwalk); 15125 15126 cur_svc = NULL; 15127 } 15128 15129 /* 15130 * Take a service and process the manifest file entires to see if 15131 * there is continued support for the service and instances. If 15132 * not cleanup as appropriate. 15133 * 15134 * If a service does not have a manifest files entry flag it for 15135 * upgrade and return. 15136 * 15137 * For each manifestfiles property check if the manifest file is 15138 * under the supported /lib/svc/manifest or /var/svc/manifest path 15139 * and if not then return immediately as this service is not supported 15140 * by the cleanup mechanism and should be ignored. 15141 * 15142 * For each manifest file that is supported, check to see if the 15143 * file exists. If not then remove the manifest file property 15144 * from the service and the smf/manifest hash table. If the manifest 15145 * file exists then verify that it supports the instances that are 15146 * part of the service. 15147 * 15148 * Once all manifest files have been accounted for remove any instances 15149 * that are no longer supported in the service. 15150 * 15151 * Return values : 15152 * 0 - Successfully processed the service 15153 * non-zero - failed to process the service 15154 * 15155 * On most errors, will just return to wait and get the next service, 15156 * unless in case of unable to create the needed structures which is 15157 * most likely a fatal error that is not going to be recoverable. 15158 */ 15159 int 15160 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 15161 { 15162 struct mpg_mfile *mpntov; 15163 struct mpg_mfile **mpvarry = NULL; 15164 scf_service_t *svc; 15165 scf_propertygroup_t *mpg; 15166 scf_property_t *mp; 15167 scf_value_t *mv; 15168 scf_iter_t *mi; 15169 scf_instance_t *instance; 15170 uu_list_walk_t *insts; 15171 uu_list_t *instances = NULL; 15172 boolean_t activity = (boolean_t)act; 15173 char *mpnbuf; 15174 char *mpvbuf; 15175 char *pgpropbuf; 15176 int mfstcnt, rminstct, instct, mfstmax; 15177 int index; 15178 int r = 0; 15179 15180 assert(g_hndl != NULL); 15181 assert(wip->svc != NULL); 15182 assert(wip->fmri != NULL); 15183 15184 svc = wip->svc; 15185 15186 mpg = scf_pg_create(g_hndl); 15187 mp = scf_property_create(g_hndl); 15188 mi = scf_iter_create(g_hndl); 15189 mv = scf_value_create(g_hndl); 15190 instance = scf_instance_create(g_hndl); 15191 15192 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 15193 instance == NULL) { 15194 uu_warn(gettext("Unable to create the supporting entities\n")); 15195 uu_warn(gettext("scf error is : %s\n"), 15196 scf_strerror(scf_error())); 15197 scfdie(); 15198 } 15199 15200 /* 15201 * Get the manifestfiles property group to be parsed for 15202 * files existence. 15203 */ 15204 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 15205 switch (scf_error()) { 15206 case SCF_ERROR_NOT_FOUND: 15207 upgrade_svc_mfst_connection(svc, wip->fmri); 15208 break; 15209 case SCF_ERROR_DELETED: 15210 case SCF_ERROR_CONNECTION_BROKEN: 15211 goto out; 15212 15213 case SCF_ERROR_HANDLE_MISMATCH: 15214 case SCF_ERROR_NOT_BOUND: 15215 case SCF_ERROR_NOT_SET: 15216 default: 15217 bad_error("scf_iter_pg_properties", 15218 scf_error()); 15219 } 15220 15221 goto out; 15222 } 15223 15224 /* 15225 * Iterate through each of the manifestfiles properties 15226 * to determine what manifestfiles are available. 15227 * 15228 * If a manifest file is supported then increment the 15229 * count and therefore the service is safe. 15230 */ 15231 if (scf_iter_pg_properties(mi, mpg) != 0) { 15232 switch (scf_error()) { 15233 case SCF_ERROR_DELETED: 15234 case SCF_ERROR_CONNECTION_BROKEN: 15235 goto out; 15236 15237 case SCF_ERROR_HANDLE_MISMATCH: 15238 case SCF_ERROR_NOT_BOUND: 15239 case SCF_ERROR_NOT_SET: 15240 default: 15241 bad_error("scf_iter_pg_properties", 15242 scf_error()); 15243 } 15244 } 15245 15246 mfstcnt = 0; 15247 mfstmax = MFSTFILE_MAX; 15248 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 15249 while ((r = scf_iter_next_property(mi, mp)) != 0) { 15250 if (r == -1) 15251 bad_error(gettext("Unable to iterate through " 15252 "manifestfiles properties : %s"), 15253 scf_error()); 15254 15255 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 15256 mpnbuf = safe_malloc(max_scf_name_len + 1); 15257 mpvbuf = safe_malloc(max_scf_value_len + 1); 15258 mpntov->mpg = mpnbuf; 15259 mpntov->mfile = mpvbuf; 15260 mpntov->access = 1; 15261 if (scf_property_get_name(mp, mpnbuf, 15262 max_scf_name_len + 1) < 0) { 15263 uu_warn(gettext("Unable to get manifest file " 15264 "property : %s\n"), 15265 scf_strerror(scf_error())); 15266 15267 switch (scf_error()) { 15268 case SCF_ERROR_DELETED: 15269 case SCF_ERROR_CONNECTION_BROKEN: 15270 r = scferror2errno(scf_error()); 15271 goto out_free; 15272 15273 case SCF_ERROR_HANDLE_MISMATCH: 15274 case SCF_ERROR_NOT_BOUND: 15275 case SCF_ERROR_NOT_SET: 15276 default: 15277 bad_error("scf_iter_pg_properties", 15278 scf_error()); 15279 } 15280 } 15281 15282 /* 15283 * The support property is a boolean value that indicates 15284 * if the service is supported for manifest file deletion. 15285 * Currently at this time there is no code that sets this 15286 * value to true. So while we could just let this be caught 15287 * by the support check below, in the future this by be set 15288 * to true and require processing. So for that, go ahead 15289 * and check here, and just return if false. Otherwise, 15290 * fall through expecting that other support checks will 15291 * handle the entries. 15292 */ 15293 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 15294 uint8_t support; 15295 15296 if (scf_property_get_value(mp, mv) != 0 || 15297 scf_value_get_boolean(mv, &support) != 0) { 15298 uu_warn(gettext("Unable to get the manifest " 15299 "support value: %s\n"), 15300 scf_strerror(scf_error())); 15301 15302 switch (scf_error()) { 15303 case SCF_ERROR_DELETED: 15304 case SCF_ERROR_CONNECTION_BROKEN: 15305 r = scferror2errno(scf_error()); 15306 goto out_free; 15307 15308 case SCF_ERROR_HANDLE_MISMATCH: 15309 case SCF_ERROR_NOT_BOUND: 15310 case SCF_ERROR_NOT_SET: 15311 default: 15312 bad_error("scf_iter_pg_properties", 15313 scf_error()); 15314 } 15315 } 15316 15317 if (support == B_FALSE) 15318 goto out_free; 15319 } 15320 15321 /* 15322 * Anything with a manifest outside of the supported 15323 * directories, immediately bail out because that makes 15324 * this service non-supported. We don't even want 15325 * to do instance processing in this case because the 15326 * instances could be part of the non-supported manifest. 15327 */ 15328 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 15329 /* 15330 * Manifest is not in /lib/svc, so we need to 15331 * consider the /var/svc case. 15332 */ 15333 if (strncmp(mpnbuf, VARSVC_PR, 15334 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 15335 /* 15336 * Either the manifest is not in /var/svc or 15337 * /var is not yet mounted. We ignore the 15338 * manifest either because it is not in a 15339 * standard location or because we cannot 15340 * currently access the manifest. 15341 */ 15342 goto out_free; 15343 } 15344 } 15345 15346 /* 15347 * Get the value to of the manifest file for this entry 15348 * for access verification and instance support 15349 * verification if it still exists. 15350 * 15351 * During Early Manifest Import if the manifest is in 15352 * /var/svc then it may not yet be available for checking 15353 * so we must determine if /var/svc is available. If not 15354 * then defer until Late Manifest Import to cleanup. 15355 */ 15356 if (scf_property_get_value(mp, mv) != 0) { 15357 uu_warn(gettext("Unable to get the manifest file " 15358 "value: %s\n"), 15359 scf_strerror(scf_error())); 15360 15361 switch (scf_error()) { 15362 case SCF_ERROR_DELETED: 15363 case SCF_ERROR_CONNECTION_BROKEN: 15364 r = scferror2errno(scf_error()); 15365 goto out_free; 15366 15367 case SCF_ERROR_HANDLE_MISMATCH: 15368 case SCF_ERROR_NOT_BOUND: 15369 case SCF_ERROR_NOT_SET: 15370 default: 15371 bad_error("scf_property_get_value", 15372 scf_error()); 15373 } 15374 } 15375 15376 if (scf_value_get_astring(mv, mpvbuf, 15377 max_scf_value_len + 1) < 0) { 15378 uu_warn(gettext("Unable to get the manifest " 15379 "file : %s\n"), 15380 scf_strerror(scf_error())); 15381 15382 switch (scf_error()) { 15383 case SCF_ERROR_DELETED: 15384 case SCF_ERROR_CONNECTION_BROKEN: 15385 r = scferror2errno(scf_error()); 15386 goto out_free; 15387 15388 case SCF_ERROR_HANDLE_MISMATCH: 15389 case SCF_ERROR_NOT_BOUND: 15390 case SCF_ERROR_NOT_SET: 15391 default: 15392 bad_error("scf_value_get_astring", 15393 scf_error()); 15394 } 15395 } 15396 15397 mpvarry[mfstcnt] = mpntov; 15398 mfstcnt++; 15399 15400 /* 15401 * Check for the need to reallocate array 15402 */ 15403 if (mfstcnt >= (mfstmax - 1)) { 15404 struct mpg_mfile **newmpvarry; 15405 15406 mfstmax = mfstmax * 2; 15407 newmpvarry = realloc(mpvarry, 15408 sizeof (struct mpg_mfile *) * mfstmax); 15409 15410 if (newmpvarry == NULL) 15411 goto out_free; 15412 15413 mpvarry = newmpvarry; 15414 } 15415 15416 mpvarry[mfstcnt] = NULL; 15417 } 15418 15419 for (index = 0; mpvarry[index]; index++) { 15420 mpntov = mpvarry[index]; 15421 15422 /* 15423 * Check to see if the manifestfile is accessable, if so hand 15424 * this service and manifestfile off to be processed for 15425 * instance support. 15426 */ 15427 mpnbuf = mpntov->mpg; 15428 mpvbuf = mpntov->mfile; 15429 if (access(mpvbuf, F_OK) != 0) { 15430 mpntov->access = 0; 15431 activity++; 15432 mfstcnt--; 15433 /* Remove the entry from the service */ 15434 cur_svc = svc; 15435 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 15436 mpnbuf); 15437 if (pgpropbuf == NULL) 15438 uu_die(gettext("Out of memory.\n")); 15439 15440 lscf_delprop(pgpropbuf); 15441 cur_svc = NULL; 15442 15443 uu_free(pgpropbuf); 15444 } 15445 } 15446 15447 /* 15448 * If mfstcnt is 0, none of the manifests that supported the service 15449 * existed so remove the service. 15450 */ 15451 if (mfstcnt == 0) { 15452 teardown_service(svc, wip->fmri); 15453 15454 goto out_free; 15455 } 15456 15457 if (activity) { 15458 int nosvcsupport = 0; 15459 15460 /* 15461 * If the list of service instances is NULL then 15462 * create the list. 15463 */ 15464 instances = create_instance_list(svc, 1); 15465 if (instances == NULL) { 15466 uu_warn(gettext("Unable to create instance list %s\n"), 15467 wip->fmri); 15468 goto out_free; 15469 } 15470 15471 rminstct = uu_list_numnodes(instances); 15472 instct = rminstct; 15473 15474 for (index = 0; mpvarry[index]; index++) { 15475 mpntov = mpvarry[index]; 15476 if (mpntov->access == 0) 15477 continue; 15478 15479 mpnbuf = mpntov->mpg; 15480 mpvbuf = mpntov->mfile; 15481 r = check_instance_support(mpvbuf, wip->fmri, 15482 instances); 15483 if (r == -1) { 15484 nosvcsupport++; 15485 } else { 15486 rminstct -= r; 15487 } 15488 } 15489 15490 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 15491 teardown_service(svc, wip->fmri); 15492 15493 goto out_free; 15494 } 15495 } 15496 15497 /* 15498 * If there are instances left on the instance list, then 15499 * we must remove them. 15500 */ 15501 if (instances != NULL && uu_list_numnodes(instances)) { 15502 string_list_t *sp; 15503 15504 insts = uu_list_walk_start(instances, 0); 15505 while ((sp = uu_list_walk_next(insts)) != NULL) { 15506 /* 15507 * Remove the instance from the instances list. 15508 */ 15509 safe_printf(gettext("Delete instance %s from " 15510 "service %s\n"), sp->str, wip->fmri); 15511 if (scf_service_get_instance(svc, sp->str, 15512 instance) != SCF_SUCCESS) { 15513 (void) uu_warn("scf_error - %s\n", 15514 scf_strerror(scf_error())); 15515 15516 continue; 15517 } 15518 15519 (void) disable_instance(instance); 15520 15521 (void) lscf_instance_delete(instance, 1); 15522 } 15523 scf_instance_destroy(instance); 15524 uu_list_walk_end(insts); 15525 } 15526 15527 out_free: 15528 if (mpvarry) { 15529 struct mpg_mfile *fmpntov; 15530 15531 for (index = 0; mpvarry[index]; index++) { 15532 fmpntov = mpvarry[index]; 15533 if (fmpntov->mpg == mpnbuf) 15534 mpnbuf = NULL; 15535 free(fmpntov->mpg); 15536 15537 if (fmpntov->mfile == mpvbuf) 15538 mpvbuf = NULL; 15539 free(fmpntov->mfile); 15540 15541 if (fmpntov == mpntov) 15542 mpntov = NULL; 15543 free(fmpntov); 15544 } 15545 if (mpnbuf) 15546 free(mpnbuf); 15547 if (mpvbuf) 15548 free(mpvbuf); 15549 if (mpntov) 15550 free(mpntov); 15551 15552 free(mpvarry); 15553 } 15554 out: 15555 scf_pg_destroy(mpg); 15556 scf_property_destroy(mp); 15557 scf_iter_destroy(mi); 15558 scf_value_destroy(mv); 15559 15560 return (0); 15561 } 15562 15563 /* 15564 * Take the service and search for the manifestfiles property 15565 * in each of the property groups. If the manifest file 15566 * associated with the property does not exist then remove 15567 * the property group. 15568 */ 15569 int 15570 lscf_hash_cleanup() 15571 { 15572 scf_service_t *svc; 15573 scf_scope_t *scope; 15574 scf_propertygroup_t *pg; 15575 scf_property_t *prop; 15576 scf_value_t *val; 15577 scf_iter_t *iter; 15578 char *pgname; 15579 char *mfile; 15580 int r; 15581 15582 svc = scf_service_create(g_hndl); 15583 scope = scf_scope_create(g_hndl); 15584 pg = scf_pg_create(g_hndl); 15585 prop = scf_property_create(g_hndl); 15586 val = scf_value_create(g_hndl); 15587 iter = scf_iter_create(g_hndl); 15588 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 15589 svc == NULL || scope == NULL) { 15590 uu_warn(gettext("Unable to create a property group, or " 15591 "property\n")); 15592 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 15593 "pg is not NULL"); 15594 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 15595 "prop is not NULL"); 15596 uu_warn("%s\n", val == NULL ? "val is NULL" : 15597 "val is not NULL"); 15598 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 15599 "iter is not NULL"); 15600 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 15601 "svc is not NULL"); 15602 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 15603 "scope is not NULL"); 15604 uu_warn(gettext("scf error is : %s\n"), 15605 scf_strerror(scf_error())); 15606 scfdie(); 15607 } 15608 15609 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 15610 switch (scf_error()) { 15611 case SCF_ERROR_CONNECTION_BROKEN: 15612 case SCF_ERROR_NOT_FOUND: 15613 goto out; 15614 15615 case SCF_ERROR_HANDLE_MISMATCH: 15616 case SCF_ERROR_NOT_BOUND: 15617 case SCF_ERROR_INVALID_ARGUMENT: 15618 default: 15619 bad_error("scf_handle_get_scope", scf_error()); 15620 } 15621 } 15622 15623 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 15624 uu_warn(gettext("Unable to process the hash service, %s\n"), 15625 HASH_SVC); 15626 goto out; 15627 } 15628 15629 pgname = safe_malloc(max_scf_name_len + 1); 15630 mfile = safe_malloc(max_scf_value_len + 1); 15631 15632 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 15633 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 15634 scf_strerror(scf_error())); 15635 goto out; 15636 } 15637 15638 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 15639 if (r == -1) 15640 goto out; 15641 15642 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 15643 switch (scf_error()) { 15644 case SCF_ERROR_DELETED: 15645 return (ENODEV); 15646 15647 case SCF_ERROR_CONNECTION_BROKEN: 15648 return (ECONNABORTED); 15649 15650 case SCF_ERROR_NOT_SET: 15651 case SCF_ERROR_NOT_BOUND: 15652 default: 15653 bad_error("scf_pg_get_name", scf_error()); 15654 } 15655 } 15656 if (IGNORE_VAR) { 15657 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 15658 continue; 15659 } 15660 15661 /* 15662 * If unable to get the property continue as this is an 15663 * entry that has no location to check against. 15664 */ 15665 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 15666 continue; 15667 } 15668 15669 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 15670 uu_warn(gettext("Unable to get value from %s\n"), 15671 pgname); 15672 goto error_handle; 15673 } 15674 15675 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) == 15676 -1) { 15677 uu_warn(gettext("Unable to get astring from %s : %s\n"), 15678 pgname, scf_strerror(scf_error())); 15679 goto error_handle; 15680 } 15681 15682 if (access(mfile, F_OK) == 0) 15683 continue; 15684 15685 (void) scf_pg_delete(pg); 15686 15687 error_handle: 15688 switch (scf_error()) { 15689 case SCF_ERROR_DELETED: 15690 case SCF_ERROR_CONSTRAINT_VIOLATED: 15691 case SCF_ERROR_NOT_FOUND: 15692 case SCF_ERROR_NOT_SET: 15693 continue; 15694 15695 case SCF_ERROR_CONNECTION_BROKEN: 15696 r = scferror2errno(scf_error()); 15697 goto out; 15698 15699 case SCF_ERROR_HANDLE_MISMATCH: 15700 case SCF_ERROR_NOT_BOUND: 15701 default: 15702 bad_error("scf_value_get_astring", 15703 scf_error()); 15704 } 15705 } 15706 15707 out: 15708 scf_scope_destroy(scope); 15709 scf_service_destroy(svc); 15710 scf_pg_destroy(pg); 15711 scf_property_destroy(prop); 15712 scf_value_destroy(val); 15713 scf_iter_destroy(iter); 15714 free(pgname); 15715 free(mfile); 15716 15717 return (0); 15718 } 15719 15720 #ifndef NATIVE_BUILD 15721 /* ARGSUSED */ 15722 CPL_MATCH_FN(complete_select) 15723 { 15724 const char *arg0, *arg1, *arg1end; 15725 int word_start, err = 0, r; 15726 size_t len; 15727 char *buf; 15728 15729 lscf_prep_hndl(); 15730 15731 arg0 = line + strspn(line, " \t"); 15732 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 15733 15734 arg1 = arg0 + sizeof ("select") - 1; 15735 arg1 += strspn(arg1, " \t"); 15736 word_start = arg1 - line; 15737 15738 arg1end = arg1 + strcspn(arg1, " \t"); 15739 if (arg1end < line + word_end) 15740 return (0); 15741 15742 len = line + word_end - arg1; 15743 15744 buf = safe_malloc(max_scf_name_len + 1); 15745 15746 if (cur_snap != NULL) { 15747 return (0); 15748 } else if (cur_inst != NULL) { 15749 return (0); 15750 } else if (cur_svc != NULL) { 15751 scf_instance_t *inst; 15752 scf_iter_t *iter; 15753 15754 if ((inst = scf_instance_create(g_hndl)) == NULL || 15755 (iter = scf_iter_create(g_hndl)) == NULL) 15756 scfdie(); 15757 15758 if (scf_iter_service_instances(iter, cur_svc) != 0) 15759 scfdie(); 15760 15761 for (;;) { 15762 r = scf_iter_next_instance(iter, inst); 15763 if (r == 0) 15764 break; 15765 if (r != 1) 15766 scfdie(); 15767 15768 if (scf_instance_get_name(inst, buf, 15769 max_scf_name_len + 1) < 0) 15770 scfdie(); 15771 15772 if (strncmp(buf, arg1, len) == 0) { 15773 err = cpl_add_completion(cpl, line, word_start, 15774 word_end, buf + len, "", " "); 15775 if (err != 0) 15776 break; 15777 } 15778 } 15779 15780 scf_iter_destroy(iter); 15781 scf_instance_destroy(inst); 15782 15783 return (err); 15784 } else { 15785 scf_service_t *svc; 15786 scf_iter_t *iter; 15787 15788 assert(cur_scope != NULL); 15789 15790 if ((svc = scf_service_create(g_hndl)) == NULL || 15791 (iter = scf_iter_create(g_hndl)) == NULL) 15792 scfdie(); 15793 15794 if (scf_iter_scope_services(iter, cur_scope) != 0) 15795 scfdie(); 15796 15797 for (;;) { 15798 r = scf_iter_next_service(iter, svc); 15799 if (r == 0) 15800 break; 15801 if (r != 1) 15802 scfdie(); 15803 15804 if (scf_service_get_name(svc, buf, 15805 max_scf_name_len + 1) < 0) 15806 scfdie(); 15807 15808 if (strncmp(buf, arg1, len) == 0) { 15809 err = cpl_add_completion(cpl, line, word_start, 15810 word_end, buf + len, "", " "); 15811 if (err != 0) 15812 break; 15813 } 15814 } 15815 15816 scf_iter_destroy(iter); 15817 scf_service_destroy(svc); 15818 15819 return (err); 15820 } 15821 } 15822 15823 /* ARGSUSED */ 15824 CPL_MATCH_FN(complete_command) 15825 { 15826 uint32_t scope = 0; 15827 15828 if (cur_snap != NULL) 15829 scope = CS_SNAP; 15830 else if (cur_inst != NULL) 15831 scope = CS_INST; 15832 else if (cur_svc != NULL) 15833 scope = CS_SVC; 15834 else 15835 scope = CS_SCOPE; 15836 15837 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 15838 } 15839 #endif /* NATIVE_BUILD */ 15840