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 <libnvpair.h> 37 #include <libscf.h> 38 #include <libscf_priv.h> 39 #include <libtecla.h> 40 #include <libuutil.h> 41 #include <limits.h> 42 #include <locale.h> 43 #include <stdarg.h> 44 #include <string.h> 45 #include <strings.h> 46 #include <unistd.h> 47 #include <wait.h> 48 #include <poll.h> 49 50 #include <libxml/tree.h> 51 52 #include <sys/param.h> 53 54 #include <sys/stat.h> 55 #include <sys/mman.h> 56 57 #include "svccfg.h" 58 #include "notify_params.h" 59 #include "manifest_hash.h" 60 #include "manifest_find.h" 61 62 /* The colon namespaces in each entity (each followed by a newline). */ 63 #define COLON_NAMESPACES ":properties\n" 64 65 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 66 67 /* These are characters which the lexer requires to be in double-quotes. */ 68 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 69 70 #define HASH_SIZE 16 71 #define HASH_PG_TYPE "framework" 72 #define HASH_PG_FLAGS 0 73 #define HASH_PROP "md5sum" 74 75 /* 76 * Indentation used in the output of the describe subcommand. 77 */ 78 #define TMPL_VALUE_INDENT " " 79 #define TMPL_INDENT " " 80 #define TMPL_INDENT_2X " " 81 #define TMPL_CHOICE_INDENT " " 82 83 /* 84 * Directory locations for manifests 85 */ 86 #define VARSVC_DIR "/var/svc/manifest" 87 #define LIBSVC_DIR "/lib/svc/manifest" 88 #define VARSVC_PR "var_svc_manifest" 89 #define LIBSVC_PR "lib_svc_manifest" 90 #define MFSTFILEPR "manifestfile" 91 92 #define SUPPORTPROP "support" 93 94 #define MFSTHISTFILE "/lib/svc/share/mfsthistory" 95 96 #define MFSTFILE_MAX 16 97 98 /* 99 * These are the classes of elements which may appear as children of service 100 * or instance elements in XML manifests. 101 */ 102 struct entity_elts { 103 xmlNodePtr create_default_instance; 104 xmlNodePtr single_instance; 105 xmlNodePtr restarter; 106 xmlNodePtr dependencies; 107 xmlNodePtr dependents; 108 xmlNodePtr method_context; 109 xmlNodePtr exec_methods; 110 xmlNodePtr notify_params; 111 xmlNodePtr property_groups; 112 xmlNodePtr instances; 113 xmlNodePtr stability; 114 xmlNodePtr template; 115 }; 116 117 /* 118 * Likewise for property_group elements. 119 */ 120 struct pg_elts { 121 xmlNodePtr stability; 122 xmlNodePtr propvals; 123 xmlNodePtr properties; 124 }; 125 126 /* 127 * Likewise for template elements. 128 */ 129 struct template_elts { 130 xmlNodePtr common_name; 131 xmlNodePtr description; 132 xmlNodePtr documentation; 133 }; 134 135 /* 136 * Likewise for type (for notification parameters) elements. 137 */ 138 struct params_elts { 139 xmlNodePtr paramval; 140 xmlNodePtr parameter; 141 }; 142 143 /* 144 * This structure is for snaplevel lists. They are convenient because libscf 145 * only allows traversing snaplevels in one direction. 146 */ 147 struct snaplevel { 148 uu_list_node_t list_node; 149 scf_snaplevel_t *sl; 150 }; 151 152 /* 153 * This is used for communication between lscf_service_export and 154 * export_callback. 155 */ 156 struct export_args { 157 const char *filename; 158 int flags; 159 }; 160 161 /* 162 * The service_manifest structure is used by the upgrade process 163 * to create a list of service to manifest linkages from the manifests 164 * in a set of given directories. 165 */ 166 typedef struct service_manifest { 167 const char *servicename; 168 uu_list_t *mfstlist; 169 size_t mfstlist_sz; 170 171 uu_avl_node_t svcmfst_node; 172 } service_manifest_t; 173 174 /* 175 * Structure to track the manifest file property group 176 * and the manifest file associated with that property 177 * group. Also, a flag to keep the access once it has 178 * been checked. 179 */ 180 struct mpg_mfile { 181 char *mpg; 182 char *mfile; 183 int access; 184 }; 185 186 const char * const scf_pg_general = SCF_PG_GENERAL; 187 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 188 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 189 const char * const scf_property_external = "external"; 190 191 const char * const snap_initial = "initial"; 192 const char * const snap_lastimport = "last-import"; 193 const char * const snap_previous = "previous"; 194 const char * const snap_running = "running"; 195 196 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 197 198 ssize_t max_scf_fmri_len; 199 ssize_t max_scf_name_len; 200 ssize_t max_scf_pg_type_len; 201 ssize_t max_scf_value_len; 202 static size_t max_scf_len; 203 204 static scf_scope_t *cur_scope; 205 static scf_service_t *cur_svc = NULL; 206 static scf_instance_t *cur_inst = NULL; 207 static scf_snapshot_t *cur_snap = NULL; 208 static scf_snaplevel_t *cur_level = NULL; 209 210 static uu_list_pool_t *snaplevel_pool; 211 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 212 static uu_list_t *cur_levels; 213 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 214 215 static FILE *tempfile = NULL; 216 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 217 218 static const char *emsg_entity_not_selected; 219 static const char *emsg_permission_denied; 220 static const char *emsg_create_xml; 221 static const char *emsg_cant_modify_snapshots; 222 static const char *emsg_invalid_for_snapshot; 223 static const char *emsg_read_only; 224 static const char *emsg_deleted; 225 static const char *emsg_invalid_pg_name; 226 static const char *emsg_invalid_prop_name; 227 static const char *emsg_no_such_pg; 228 static const char *emsg_fmri_invalid_pg_name; 229 static const char *emsg_fmri_invalid_pg_name_type; 230 static const char *emsg_pg_added; 231 static const char *emsg_pg_changed; 232 static const char *emsg_pg_deleted; 233 static const char *emsg_pg_mod_perm; 234 static const char *emsg_pg_add_perm; 235 static const char *emsg_pg_del_perm; 236 static const char *emsg_snap_perm; 237 static const char *emsg_dpt_dangling; 238 static const char *emsg_dpt_no_dep; 239 240 static int li_only = 0; 241 static int no_refresh = 0; 242 243 /* import globals, to minimize allocations */ 244 static scf_scope_t *imp_scope = NULL; 245 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 246 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 247 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 248 static scf_snapshot_t *imp_rsnap = NULL; 249 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 250 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 251 static scf_property_t *imp_prop = NULL; 252 static scf_iter_t *imp_iter = NULL; 253 static scf_iter_t *imp_rpg_iter = NULL; 254 static scf_iter_t *imp_up_iter = NULL; 255 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 256 static char *imp_str = NULL; 257 static size_t imp_str_sz; 258 static char *imp_tsname = NULL; 259 static char *imp_fe1 = NULL; /* for fmri_equal() */ 260 static char *imp_fe2 = NULL; 261 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 262 263 /* upgrade_dependents() globals */ 264 static scf_instance_t *ud_inst = NULL; 265 static scf_snaplevel_t *ud_snpl = NULL; 266 static scf_propertygroup_t *ud_pg = NULL; 267 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 268 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 269 static int ud_run_dpts_pg_set = 0; 270 static scf_property_t *ud_prop = NULL; 271 static scf_property_t *ud_dpt_prop = NULL; 272 static scf_value_t *ud_val = NULL; 273 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 274 static scf_transaction_t *ud_tx = NULL; 275 static char *ud_ctarg = NULL; 276 static char *ud_oldtarg = NULL; 277 static char *ud_name = NULL; 278 279 /* export globals */ 280 static scf_instance_t *exp_inst; 281 static scf_propertygroup_t *exp_pg; 282 static scf_property_t *exp_prop; 283 static scf_value_t *exp_val; 284 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 285 static char *exp_str; 286 static size_t exp_str_sz; 287 288 /* cleanup globals */ 289 static uu_avl_pool_t *service_manifest_pool = NULL; 290 static uu_avl_t *service_manifest_tree = NULL; 291 292 static void scfdie_lineno(int lineno) __NORETURN; 293 294 static char *start_method_names[] = { 295 "start", 296 "inetd_start", 297 NULL 298 }; 299 300 static struct uri_scheme { 301 const char *scheme; 302 const char *protocol; 303 } uri_scheme[] = { 304 { "mailto", "smtp" }, 305 { "snmp", "snmp" }, 306 { "syslog", "syslog" }, 307 { NULL, NULL } 308 }; 309 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \ 310 sizeof (struct uri_scheme)) - 1) 311 312 static int 313 check_uri_scheme(const char *scheme) 314 { 315 int i; 316 317 for (i = 0; uri_scheme[i].scheme != NULL; ++i) { 318 if (strcmp(scheme, uri_scheme[i].scheme) == 0) 319 return (i); 320 } 321 322 return (-1); 323 } 324 325 static int 326 check_uri_protocol(const char *p) 327 { 328 int i; 329 330 for (i = 0; uri_scheme[i].protocol != NULL; ++i) { 331 if (strcmp(p, uri_scheme[i].protocol) == 0) 332 return (i); 333 } 334 335 return (-1); 336 } 337 338 /* 339 * For unexpected libscf errors. 340 */ 341 #ifdef NDEBUG 342 343 static void scfdie(void) __NORETURN; 344 345 static void 346 scfdie(void) 347 { 348 scf_error_t err = scf_error(); 349 350 if (err == SCF_ERROR_CONNECTION_BROKEN) 351 uu_die(gettext("Repository connection broken. Exiting.\n")); 352 353 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 354 scf_strerror(err)); 355 } 356 357 #else 358 359 #define scfdie() scfdie_lineno(__LINE__) 360 361 static void 362 scfdie_lineno(int lineno) 363 { 364 scf_error_t err = scf_error(); 365 366 if (err == SCF_ERROR_CONNECTION_BROKEN) 367 uu_die(gettext("Repository connection broken. Exiting.\n")); 368 369 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 370 ": %s.\n"), lineno, scf_strerror(err)); 371 } 372 373 #endif 374 375 static void 376 scfwarn(void) 377 { 378 warn(gettext("Unexpected libscf error: %s.\n"), 379 scf_strerror(scf_error())); 380 } 381 382 /* 383 * Clear a field of a structure. 384 */ 385 static int 386 clear_int(void *a, void *b) 387 { 388 /* LINTED */ 389 *(int *)((char *)a + (size_t)b) = 0; 390 391 return (UU_WALK_NEXT); 392 } 393 394 static int 395 scferror2errno(scf_error_t err) 396 { 397 switch (err) { 398 case SCF_ERROR_BACKEND_ACCESS: 399 return (EACCES); 400 401 case SCF_ERROR_BACKEND_READONLY: 402 return (EROFS); 403 404 case SCF_ERROR_CONNECTION_BROKEN: 405 return (ECONNABORTED); 406 407 case SCF_ERROR_CONSTRAINT_VIOLATED: 408 case SCF_ERROR_INVALID_ARGUMENT: 409 return (EINVAL); 410 411 case SCF_ERROR_DELETED: 412 return (ECANCELED); 413 414 case SCF_ERROR_EXISTS: 415 return (EEXIST); 416 417 case SCF_ERROR_NO_MEMORY: 418 return (ENOMEM); 419 420 case SCF_ERROR_NO_RESOURCES: 421 return (ENOSPC); 422 423 case SCF_ERROR_NOT_FOUND: 424 return (ENOENT); 425 426 case SCF_ERROR_PERMISSION_DENIED: 427 return (EPERM); 428 429 default: 430 #ifndef NDEBUG 431 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 432 __FILE__, __LINE__, err); 433 #else 434 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 435 #endif 436 abort(); 437 /* NOTREACHED */ 438 } 439 } 440 441 static int 442 entity_get_pg(void *ent, int issvc, const char *name, 443 scf_propertygroup_t *pg) 444 { 445 if (issvc) 446 return (scf_service_get_pg(ent, name, pg)); 447 else 448 return (scf_instance_get_pg(ent, name, pg)); 449 } 450 451 static void 452 entity_destroy(void *ent, int issvc) 453 { 454 if (issvc) 455 scf_service_destroy(ent); 456 else 457 scf_instance_destroy(ent); 458 } 459 460 static int 461 get_pg(const char *pg_name, scf_propertygroup_t *pg) 462 { 463 int ret; 464 465 if (cur_level != NULL) 466 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 467 else if (cur_inst != NULL) 468 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 469 else 470 ret = scf_service_get_pg(cur_svc, pg_name, pg); 471 472 return (ret); 473 } 474 475 /* 476 * Find a snaplevel in a snapshot. If get_svc is true, find the service 477 * snaplevel. Otherwise find the instance snaplevel. 478 * 479 * Returns 480 * 0 - success 481 * ECONNABORTED - repository connection broken 482 * ECANCELED - instance containing snap was deleted 483 * ENOENT - snap has no snaplevels 484 * - requested snaplevel not found 485 */ 486 static int 487 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 488 { 489 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 490 switch (scf_error()) { 491 case SCF_ERROR_CONNECTION_BROKEN: 492 case SCF_ERROR_DELETED: 493 case SCF_ERROR_NOT_FOUND: 494 return (scferror2errno(scf_error())); 495 496 case SCF_ERROR_HANDLE_MISMATCH: 497 case SCF_ERROR_NOT_BOUND: 498 case SCF_ERROR_NOT_SET: 499 default: 500 bad_error("scf_snapshot_get_base_snaplevel", 501 scf_error()); 502 } 503 } 504 505 for (;;) { 506 ssize_t ssz; 507 508 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 509 if (ssz >= 0) { 510 if (!get_svc) 511 return (0); 512 } else { 513 switch (scf_error()) { 514 case SCF_ERROR_CONSTRAINT_VIOLATED: 515 if (get_svc) 516 return (0); 517 break; 518 519 case SCF_ERROR_DELETED: 520 case SCF_ERROR_CONNECTION_BROKEN: 521 return (scferror2errno(scf_error())); 522 523 case SCF_ERROR_NOT_SET: 524 case SCF_ERROR_NOT_BOUND: 525 default: 526 bad_error("scf_snaplevel_get_instance_name", 527 scf_error()); 528 } 529 } 530 531 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 532 switch (scf_error()) { 533 case SCF_ERROR_NOT_FOUND: 534 case SCF_ERROR_CONNECTION_BROKEN: 535 case SCF_ERROR_DELETED: 536 return (scferror2errno(scf_error())); 537 538 case SCF_ERROR_HANDLE_MISMATCH: 539 case SCF_ERROR_NOT_BOUND: 540 case SCF_ERROR_NOT_SET: 541 case SCF_ERROR_INVALID_ARGUMENT: 542 default: 543 bad_error("scf_snaplevel_get_next_snaplevel", 544 scf_error()); 545 } 546 } 547 } 548 } 549 550 /* 551 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 552 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 553 * the property group named name in it. If it doesn't have a running 554 * snapshot, set pg to the instance's current property group named name. 555 * 556 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 557 * its instances. If one has a running snapshot with a service snaplevel, set 558 * pg to the property group named name in it. If no such snaplevel could be 559 * found, set pg to the service's current property group named name. 560 * 561 * iter, inst, snap, and snpl are required scratch objects. 562 * 563 * Returns 564 * 0 - success 565 * ECONNABORTED - repository connection broken 566 * ECANCELED - ent was deleted 567 * ENOENT - no such property group 568 * EINVAL - name is an invalid property group name 569 * EBADF - found running snapshot is missing a snaplevel 570 */ 571 static int 572 entity_get_running_pg(void *ent, int issvc, const char *name, 573 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 574 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 575 { 576 int r; 577 578 if (issvc) { 579 /* Search for an instance with a running snapshot. */ 580 if (scf_iter_service_instances(iter, ent) != 0) { 581 switch (scf_error()) { 582 case SCF_ERROR_DELETED: 583 case SCF_ERROR_CONNECTION_BROKEN: 584 return (scferror2errno(scf_error())); 585 586 case SCF_ERROR_NOT_SET: 587 case SCF_ERROR_NOT_BOUND: 588 case SCF_ERROR_HANDLE_MISMATCH: 589 default: 590 bad_error("scf_iter_service_instances", 591 scf_error()); 592 } 593 } 594 595 for (;;) { 596 r = scf_iter_next_instance(iter, inst); 597 if (r == 0) { 598 if (scf_service_get_pg(ent, name, pg) == 0) 599 return (0); 600 601 switch (scf_error()) { 602 case SCF_ERROR_DELETED: 603 case SCF_ERROR_NOT_FOUND: 604 case SCF_ERROR_INVALID_ARGUMENT: 605 case SCF_ERROR_CONNECTION_BROKEN: 606 return (scferror2errno(scf_error())); 607 608 case SCF_ERROR_NOT_BOUND: 609 case SCF_ERROR_HANDLE_MISMATCH: 610 case SCF_ERROR_NOT_SET: 611 default: 612 bad_error("scf_service_get_pg", 613 scf_error()); 614 } 615 } 616 if (r != 1) { 617 switch (scf_error()) { 618 case SCF_ERROR_DELETED: 619 case SCF_ERROR_CONNECTION_BROKEN: 620 return (scferror2errno(scf_error())); 621 622 case SCF_ERROR_INVALID_ARGUMENT: 623 case SCF_ERROR_NOT_SET: 624 case SCF_ERROR_NOT_BOUND: 625 case SCF_ERROR_HANDLE_MISMATCH: 626 default: 627 bad_error("scf_iter_next_instance", 628 scf_error()); 629 } 630 } 631 632 if (scf_instance_get_snapshot(inst, snap_running, 633 snap) == 0) 634 break; 635 636 switch (scf_error()) { 637 case SCF_ERROR_NOT_FOUND: 638 case SCF_ERROR_DELETED: 639 continue; 640 641 case SCF_ERROR_CONNECTION_BROKEN: 642 return (ECONNABORTED); 643 644 case SCF_ERROR_HANDLE_MISMATCH: 645 case SCF_ERROR_INVALID_ARGUMENT: 646 case SCF_ERROR_NOT_SET: 647 case SCF_ERROR_NOT_BOUND: 648 default: 649 bad_error("scf_instance_get_snapshot", 650 scf_error()); 651 } 652 } 653 } else { 654 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 655 switch (scf_error()) { 656 case SCF_ERROR_NOT_FOUND: 657 break; 658 659 case SCF_ERROR_DELETED: 660 case SCF_ERROR_CONNECTION_BROKEN: 661 return (scferror2errno(scf_error())); 662 663 case SCF_ERROR_NOT_BOUND: 664 case SCF_ERROR_HANDLE_MISMATCH: 665 case SCF_ERROR_INVALID_ARGUMENT: 666 case SCF_ERROR_NOT_SET: 667 default: 668 bad_error("scf_instance_get_snapshot", 669 scf_error()); 670 } 671 672 if (scf_instance_get_pg(ent, name, pg) == 0) 673 return (0); 674 675 switch (scf_error()) { 676 case SCF_ERROR_DELETED: 677 case SCF_ERROR_NOT_FOUND: 678 case SCF_ERROR_INVALID_ARGUMENT: 679 case SCF_ERROR_CONNECTION_BROKEN: 680 return (scferror2errno(scf_error())); 681 682 case SCF_ERROR_NOT_BOUND: 683 case SCF_ERROR_HANDLE_MISMATCH: 684 case SCF_ERROR_NOT_SET: 685 default: 686 bad_error("scf_instance_get_pg", scf_error()); 687 } 688 } 689 } 690 691 r = get_snaplevel(snap, issvc, snpl); 692 switch (r) { 693 case 0: 694 break; 695 696 case ECONNABORTED: 697 case ECANCELED: 698 return (r); 699 700 case ENOENT: 701 return (EBADF); 702 703 default: 704 bad_error("get_snaplevel", r); 705 } 706 707 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 708 return (0); 709 710 switch (scf_error()) { 711 case SCF_ERROR_DELETED: 712 case SCF_ERROR_INVALID_ARGUMENT: 713 case SCF_ERROR_CONNECTION_BROKEN: 714 case SCF_ERROR_NOT_FOUND: 715 return (scferror2errno(scf_error())); 716 717 case SCF_ERROR_NOT_BOUND: 718 case SCF_ERROR_HANDLE_MISMATCH: 719 case SCF_ERROR_NOT_SET: 720 default: 721 bad_error("scf_snaplevel_get_pg", scf_error()); 722 /* NOTREACHED */ 723 } 724 } 725 726 /* 727 * To be registered with atexit(). 728 */ 729 static void 730 remove_tempfile(void) 731 { 732 int ret; 733 734 if (tempfile != NULL) { 735 if (fclose(tempfile) == EOF) 736 (void) warn(gettext("Could not close temporary file")); 737 tempfile = NULL; 738 } 739 740 if (tempfilename[0] != '\0') { 741 do { 742 ret = remove(tempfilename); 743 } while (ret == -1 && errno == EINTR); 744 if (ret == -1) 745 warn(gettext("Could not remove temporary file")); 746 tempfilename[0] = '\0'; 747 } 748 } 749 750 /* 751 * Launch private svc.configd(1M) for manipulating alternate repositories. 752 */ 753 static void 754 start_private_repository(engine_state_t *est) 755 { 756 int fd, stat; 757 struct door_info info; 758 pid_t pid; 759 760 /* 761 * 1. Create a temporary file for the door. 762 */ 763 if (est->sc_repo_doorname != NULL) 764 free((void *)est->sc_repo_doorname); 765 766 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 767 if (est->sc_repo_doorname == NULL) 768 uu_die(gettext("Could not acquire temporary filename")); 769 770 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 771 if (fd < 0) 772 uu_die(gettext("Could not create temporary file for " 773 "repository server")); 774 775 (void) close(fd); 776 777 /* 778 * 2. Launch a configd with that door, using the specified 779 * repository. 780 */ 781 if ((est->sc_repo_pid = fork()) == 0) { 782 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 783 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 784 NULL); 785 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 786 } else if (est->sc_repo_pid == -1) 787 uu_die(gettext("Attempt to fork failed")); 788 789 do { 790 pid = waitpid(est->sc_repo_pid, &stat, 0); 791 } while (pid == -1 && errno == EINTR); 792 793 if (pid == -1) 794 uu_die(gettext("Could not waitpid() for repository server")); 795 796 if (!WIFEXITED(stat)) { 797 uu_die(gettext("Repository server failed (status %d).\n"), 798 stat); 799 } else if (WEXITSTATUS(stat) != 0) { 800 uu_die(gettext("Repository server failed (exit %d).\n"), 801 WEXITSTATUS(stat)); 802 } 803 804 /* 805 * See if it was successful by checking if the door is a door. 806 */ 807 808 fd = open(est->sc_repo_doorname, O_RDWR); 809 if (fd < 0) 810 uu_die(gettext("Could not open door \"%s\""), 811 est->sc_repo_doorname); 812 813 if (door_info(fd, &info) < 0) 814 uu_die(gettext("Unexpected door_info() error")); 815 816 if (close(fd) == -1) 817 warn(gettext("Could not close repository door"), 818 strerror(errno)); 819 820 est->sc_repo_pid = info.di_target; 821 } 822 823 void 824 lscf_cleanup(void) 825 { 826 /* 827 * In the case where we've launched a private svc.configd(1M) 828 * instance, we must terminate our child and remove the temporary 829 * rendezvous point. 830 */ 831 if (est->sc_repo_pid > 0) { 832 (void) kill(est->sc_repo_pid, SIGTERM); 833 (void) waitpid(est->sc_repo_pid, NULL, 0); 834 (void) unlink(est->sc_repo_doorname); 835 836 est->sc_repo_pid = 0; 837 } 838 } 839 840 void 841 unselect_cursnap(void) 842 { 843 void *cookie; 844 845 cur_level = NULL; 846 847 cookie = NULL; 848 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 849 scf_snaplevel_destroy(cur_elt->sl); 850 free(cur_elt); 851 } 852 853 scf_snapshot_destroy(cur_snap); 854 cur_snap = NULL; 855 } 856 857 void 858 lscf_prep_hndl(void) 859 { 860 if (g_hndl != NULL) 861 return; 862 863 g_hndl = scf_handle_create(SCF_VERSION); 864 if (g_hndl == NULL) 865 scfdie(); 866 867 if (est->sc_repo_filename != NULL) 868 start_private_repository(est); 869 870 if (est->sc_repo_doorname != NULL) { 871 scf_value_t *repo_value; 872 int ret; 873 874 repo_value = scf_value_create(g_hndl); 875 if (repo_value == NULL) 876 scfdie(); 877 878 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 879 assert(ret == SCF_SUCCESS); 880 881 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 882 SCF_SUCCESS) 883 scfdie(); 884 885 scf_value_destroy(repo_value); 886 } 887 888 if (scf_handle_bind(g_hndl) != 0) 889 uu_die(gettext("Could not connect to repository server: %s.\n"), 890 scf_strerror(scf_error())); 891 892 cur_scope = scf_scope_create(g_hndl); 893 if (cur_scope == NULL) 894 scfdie(); 895 896 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 897 scfdie(); 898 } 899 900 static void 901 repository_teardown(void) 902 { 903 if (g_hndl != NULL) { 904 if (cur_snap != NULL) 905 unselect_cursnap(); 906 scf_instance_destroy(cur_inst); 907 scf_service_destroy(cur_svc); 908 scf_scope_destroy(cur_scope); 909 scf_handle_destroy(g_hndl); 910 cur_inst = NULL; 911 cur_svc = NULL; 912 cur_scope = NULL; 913 g_hndl = NULL; 914 lscf_cleanup(); 915 } 916 } 917 918 void 919 lscf_set_repository(const char *repfile, int force) 920 { 921 repository_teardown(); 922 923 if (est->sc_repo_filename != NULL) { 924 free((void *)est->sc_repo_filename); 925 est->sc_repo_filename = NULL; 926 } 927 928 if ((force == 0) && (access(repfile, R_OK) != 0)) { 929 /* 930 * Repository file does not exist 931 * or has no read permission. 932 */ 933 warn(gettext("Cannot access \"%s\": %s\n"), 934 repfile, strerror(errno)); 935 } else { 936 est->sc_repo_filename = safe_strdup(repfile); 937 } 938 939 lscf_prep_hndl(); 940 } 941 942 void 943 lscf_init() 944 { 945 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 946 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 947 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 948 0 || 949 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 950 scfdie(); 951 952 max_scf_len = max_scf_fmri_len; 953 if (max_scf_name_len > max_scf_len) 954 max_scf_len = max_scf_name_len; 955 if (max_scf_pg_type_len > max_scf_len) 956 max_scf_len = max_scf_pg_type_len; 957 /* 958 * When a value of type opaque is represented as a string, the 959 * string contains 2 characters for every byte of data. That is 960 * because the string contains the hex representation of the opaque 961 * value. 962 */ 963 if (2 * max_scf_value_len > max_scf_len) 964 max_scf_len = 2 * max_scf_value_len; 965 966 if (atexit(remove_tempfile) != 0) 967 uu_die(gettext("Could not register atexit() function")); 968 969 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 970 emsg_permission_denied = gettext("Permission denied.\n"); 971 emsg_create_xml = gettext("Could not create XML node.\n"); 972 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 973 emsg_invalid_for_snapshot = 974 gettext("Invalid operation on a snapshot.\n"); 975 emsg_read_only = gettext("Backend read-only.\n"); 976 emsg_deleted = gettext("Current selection has been deleted.\n"); 977 emsg_invalid_pg_name = 978 gettext("Invalid property group name \"%s\".\n"); 979 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 980 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 981 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 982 "with invalid name \"%s\".\n"); 983 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 984 "group with invalid name \"%s\" or type \"%s\".\n"); 985 emsg_pg_added = gettext("%s changed unexpectedly " 986 "(property group \"%s\" added).\n"); 987 emsg_pg_changed = gettext("%s changed unexpectedly " 988 "(property group \"%s\" changed).\n"); 989 emsg_pg_deleted = gettext("%s changed unexpectedly " 990 "(property group \"%s\" or an ancestor was deleted).\n"); 991 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 992 "in %s (permission denied).\n"); 993 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 994 "in %s (permission denied).\n"); 995 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 996 "in %s (permission denied).\n"); 997 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 998 "(permission denied).\n"); 999 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 1000 "new dependent \"%s\" because it already exists). Warning: The " 1001 "current dependent's target (%s) does not exist.\n"); 1002 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 1003 "dependent \"%s\" because it already exists). Warning: The " 1004 "current dependent's target (%s) does not have a dependency named " 1005 "\"%s\" as expected.\n"); 1006 1007 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 1008 offsetof(string_list_t, node), NULL, 0); 1009 snaplevel_pool = uu_list_pool_create("snaplevels", 1010 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 1011 NULL, 0); 1012 } 1013 1014 1015 static const char * 1016 prop_to_typestr(const scf_property_t *prop) 1017 { 1018 scf_type_t ty; 1019 1020 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 1021 scfdie(); 1022 1023 return (scf_type_to_string(ty)); 1024 } 1025 1026 static scf_type_t 1027 string_to_type(const char *type) 1028 { 1029 size_t len = strlen(type); 1030 char *buf; 1031 1032 if (len == 0 || type[len - 1] != ':') 1033 return (SCF_TYPE_INVALID); 1034 1035 buf = (char *)alloca(len + 1); 1036 (void) strlcpy(buf, type, len + 1); 1037 buf[len - 1] = 0; 1038 1039 return (scf_string_to_type(buf)); 1040 } 1041 1042 static scf_value_t * 1043 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 1044 { 1045 scf_value_t *v; 1046 char *dup, *nstr; 1047 size_t len; 1048 1049 v = scf_value_create(g_hndl); 1050 if (v == NULL) 1051 scfdie(); 1052 1053 len = strlen(str); 1054 if (require_quotes && 1055 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1056 semerr(gettext("Multiple string values or string values " 1057 "with spaces must be quoted with '\"'.\n")); 1058 scf_value_destroy(v); 1059 return (NULL); 1060 } 1061 1062 nstr = dup = safe_strdup(str); 1063 if (dup[0] == '\"') { 1064 /* 1065 * Strip out the first and the last quote. 1066 */ 1067 dup[len - 1] = '\0'; 1068 nstr = dup + 1; 1069 } 1070 1071 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1072 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1073 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1074 scf_type_to_string(ty), nstr); 1075 scf_value_destroy(v); 1076 v = NULL; 1077 } 1078 free(dup); 1079 return (v); 1080 } 1081 1082 /* 1083 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1084 * Optionally append a comment prefix ('#') to newlines ('\n'). 1085 */ 1086 static int 1087 quote_and_print(const char *str, FILE *strm, int commentnl) 1088 { 1089 const char *cp; 1090 1091 for (cp = str; *cp != '\0'; ++cp) { 1092 if (*cp == '"' || *cp == '\\') 1093 (void) putc('\\', strm); 1094 1095 (void) putc(*cp, strm); 1096 1097 if (commentnl && *cp == '\n') { 1098 (void) putc('#', strm); 1099 } 1100 } 1101 1102 return (ferror(strm)); 1103 } 1104 1105 /* 1106 * These wrappers around lowlevel functions provide consistent error checking 1107 * and warnings. 1108 */ 1109 static int 1110 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1111 { 1112 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1113 return (0); 1114 1115 if (scf_error() != SCF_ERROR_NOT_FOUND) 1116 scfdie(); 1117 1118 if (g_verbose) { 1119 ssize_t len; 1120 char *fmri; 1121 1122 len = scf_pg_to_fmri(pg, NULL, 0); 1123 if (len < 0) 1124 scfdie(); 1125 1126 fmri = safe_malloc(len + 1); 1127 1128 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1129 scfdie(); 1130 1131 warn(gettext("Expected property %s of property group %s is " 1132 "missing.\n"), propname, fmri); 1133 1134 free(fmri); 1135 } 1136 1137 return (-1); 1138 } 1139 1140 static int 1141 prop_check_type(scf_property_t *prop, scf_type_t ty) 1142 { 1143 scf_type_t pty; 1144 1145 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1146 scfdie(); 1147 1148 if (ty == pty) 1149 return (0); 1150 1151 if (g_verbose) { 1152 ssize_t len; 1153 char *fmri; 1154 const char *tystr; 1155 1156 len = scf_property_to_fmri(prop, NULL, 0); 1157 if (len < 0) 1158 scfdie(); 1159 1160 fmri = safe_malloc(len + 1); 1161 1162 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1163 scfdie(); 1164 1165 tystr = scf_type_to_string(ty); 1166 if (tystr == NULL) 1167 tystr = "?"; 1168 1169 warn(gettext("Property %s is not of expected type %s.\n"), 1170 fmri, tystr); 1171 1172 free(fmri); 1173 } 1174 1175 return (-1); 1176 } 1177 1178 static int 1179 prop_get_val(scf_property_t *prop, scf_value_t *val) 1180 { 1181 scf_error_t err; 1182 1183 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1184 return (0); 1185 1186 err = scf_error(); 1187 1188 if (err != SCF_ERROR_NOT_FOUND && 1189 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1190 err != SCF_ERROR_PERMISSION_DENIED) 1191 scfdie(); 1192 1193 if (g_verbose) { 1194 ssize_t len; 1195 char *fmri, *emsg; 1196 1197 len = scf_property_to_fmri(prop, NULL, 0); 1198 if (len < 0) 1199 scfdie(); 1200 1201 fmri = safe_malloc(len + 1); 1202 1203 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1204 scfdie(); 1205 1206 if (err == SCF_ERROR_NOT_FOUND) 1207 emsg = gettext("Property %s has no values; expected " 1208 "one.\n"); 1209 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1210 emsg = gettext("Property %s has multiple values; " 1211 "expected one.\n"); 1212 else 1213 emsg = gettext("No permission to read property %s.\n"); 1214 1215 warn(emsg, fmri); 1216 1217 free(fmri); 1218 } 1219 1220 return (-1); 1221 } 1222 1223 1224 static boolean_t 1225 snaplevel_is_instance(const scf_snaplevel_t *level) 1226 { 1227 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1228 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1229 scfdie(); 1230 return (0); 1231 } else { 1232 return (1); 1233 } 1234 } 1235 1236 /* 1237 * Decode FMRI into a service or instance, and put the result in *ep. If 1238 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1239 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1240 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1241 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1242 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1243 * whether *ep is a service. 1244 */ 1245 static scf_error_t 1246 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1247 { 1248 char *fmri_copy; 1249 const char *sstr, *istr, *pgstr; 1250 scf_service_t *svc; 1251 scf_instance_t *inst; 1252 1253 fmri_copy = strdup(fmri); 1254 if (fmri_copy == NULL) 1255 return (SCF_ERROR_NO_MEMORY); 1256 1257 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1258 SCF_SUCCESS) { 1259 free(fmri_copy); 1260 return (SCF_ERROR_INVALID_ARGUMENT); 1261 } 1262 1263 free(fmri_copy); 1264 1265 if (sstr == NULL || pgstr != NULL) 1266 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1267 1268 if (istr == NULL) { 1269 svc = scf_service_create(h); 1270 if (svc == NULL) 1271 return (SCF_ERROR_NO_MEMORY); 1272 1273 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1274 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1275 if (scf_error() != SCF_ERROR_NOT_FOUND) 1276 scfdie(); 1277 1278 return (SCF_ERROR_NOT_FOUND); 1279 } 1280 1281 *ep = svc; 1282 *isservice = 1; 1283 } else { 1284 inst = scf_instance_create(h); 1285 if (inst == NULL) 1286 return (SCF_ERROR_NO_MEMORY); 1287 1288 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1289 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1290 if (scf_error() != SCF_ERROR_NOT_FOUND) 1291 scfdie(); 1292 1293 return (SCF_ERROR_NOT_FOUND); 1294 } 1295 1296 *ep = inst; 1297 *isservice = 0; 1298 } 1299 1300 return (SCF_ERROR_NONE); 1301 } 1302 1303 /* 1304 * Create the entity named by fmri. Place a pointer to its libscf handle in 1305 * *ep, and set or clear *isservicep if it is a service or an instance. 1306 * Returns 1307 * SCF_ERROR_NONE - success 1308 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1309 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1310 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1311 * SCF_ERROR_NOT_FOUND - no such scope 1312 * SCF_ERROR_PERMISSION_DENIED 1313 * SCF_ERROR_BACKEND_READONLY 1314 * SCF_ERROR_BACKEND_ACCESS 1315 */ 1316 static scf_error_t 1317 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1318 { 1319 char *fmri_copy; 1320 const char *scstr, *sstr, *istr, *pgstr; 1321 scf_scope_t *scope = NULL; 1322 scf_service_t *svc = NULL; 1323 scf_instance_t *inst = NULL; 1324 scf_error_t scfe; 1325 1326 fmri_copy = safe_strdup(fmri); 1327 1328 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1329 0) { 1330 free(fmri_copy); 1331 return (SCF_ERROR_INVALID_ARGUMENT); 1332 } 1333 1334 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1335 free(fmri_copy); 1336 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1337 } 1338 1339 *ep = NULL; 1340 1341 if ((scope = scf_scope_create(h)) == NULL || 1342 (svc = scf_service_create(h)) == NULL || 1343 (inst = scf_instance_create(h)) == NULL) { 1344 scfe = SCF_ERROR_NO_MEMORY; 1345 goto out; 1346 } 1347 1348 get_scope: 1349 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1350 switch (scf_error()) { 1351 case SCF_ERROR_CONNECTION_BROKEN: 1352 scfdie(); 1353 /* NOTREACHED */ 1354 1355 case SCF_ERROR_NOT_FOUND: 1356 scfe = SCF_ERROR_NOT_FOUND; 1357 goto out; 1358 1359 case SCF_ERROR_HANDLE_MISMATCH: 1360 case SCF_ERROR_NOT_BOUND: 1361 case SCF_ERROR_INVALID_ARGUMENT: 1362 default: 1363 bad_error("scf_handle_get_scope", scf_error()); 1364 } 1365 } 1366 1367 get_svc: 1368 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1369 switch (scf_error()) { 1370 case SCF_ERROR_CONNECTION_BROKEN: 1371 scfdie(); 1372 /* NOTREACHED */ 1373 1374 case SCF_ERROR_DELETED: 1375 goto get_scope; 1376 1377 case SCF_ERROR_NOT_FOUND: 1378 break; 1379 1380 case SCF_ERROR_HANDLE_MISMATCH: 1381 case SCF_ERROR_INVALID_ARGUMENT: 1382 case SCF_ERROR_NOT_BOUND: 1383 case SCF_ERROR_NOT_SET: 1384 default: 1385 bad_error("scf_scope_get_service", scf_error()); 1386 } 1387 1388 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1389 switch (scf_error()) { 1390 case SCF_ERROR_CONNECTION_BROKEN: 1391 scfdie(); 1392 /* NOTREACHED */ 1393 1394 case SCF_ERROR_DELETED: 1395 goto get_scope; 1396 1397 case SCF_ERROR_PERMISSION_DENIED: 1398 case SCF_ERROR_BACKEND_READONLY: 1399 case SCF_ERROR_BACKEND_ACCESS: 1400 scfe = scf_error(); 1401 goto out; 1402 1403 case SCF_ERROR_HANDLE_MISMATCH: 1404 case SCF_ERROR_INVALID_ARGUMENT: 1405 case SCF_ERROR_NOT_BOUND: 1406 case SCF_ERROR_NOT_SET: 1407 default: 1408 bad_error("scf_scope_get_service", scf_error()); 1409 } 1410 } 1411 } 1412 1413 if (istr == NULL) { 1414 scfe = SCF_ERROR_NONE; 1415 *ep = svc; 1416 *isservicep = 1; 1417 goto out; 1418 } 1419 1420 get_inst: 1421 if (scf_service_get_instance(svc, istr, inst) != 0) { 1422 switch (scf_error()) { 1423 case SCF_ERROR_CONNECTION_BROKEN: 1424 scfdie(); 1425 /* NOTREACHED */ 1426 1427 case SCF_ERROR_DELETED: 1428 goto get_svc; 1429 1430 case SCF_ERROR_NOT_FOUND: 1431 break; 1432 1433 case SCF_ERROR_HANDLE_MISMATCH: 1434 case SCF_ERROR_INVALID_ARGUMENT: 1435 case SCF_ERROR_NOT_BOUND: 1436 case SCF_ERROR_NOT_SET: 1437 default: 1438 bad_error("scf_service_get_instance", scf_error()); 1439 } 1440 1441 if (scf_service_add_instance(svc, istr, inst) != 0) { 1442 switch (scf_error()) { 1443 case SCF_ERROR_CONNECTION_BROKEN: 1444 scfdie(); 1445 /* NOTREACHED */ 1446 1447 case SCF_ERROR_DELETED: 1448 goto get_svc; 1449 1450 case SCF_ERROR_PERMISSION_DENIED: 1451 case SCF_ERROR_BACKEND_READONLY: 1452 case SCF_ERROR_BACKEND_ACCESS: 1453 scfe = scf_error(); 1454 goto out; 1455 1456 case SCF_ERROR_HANDLE_MISMATCH: 1457 case SCF_ERROR_INVALID_ARGUMENT: 1458 case SCF_ERROR_NOT_BOUND: 1459 case SCF_ERROR_NOT_SET: 1460 default: 1461 bad_error("scf_service_add_instance", 1462 scf_error()); 1463 } 1464 } 1465 } 1466 1467 scfe = SCF_ERROR_NONE; 1468 *ep = inst; 1469 *isservicep = 0; 1470 1471 out: 1472 if (*ep != inst) 1473 scf_instance_destroy(inst); 1474 if (*ep != svc) 1475 scf_service_destroy(svc); 1476 scf_scope_destroy(scope); 1477 free(fmri_copy); 1478 return (scfe); 1479 } 1480 1481 /* 1482 * Create or update a snapshot of inst. snap is a required scratch object. 1483 * 1484 * Returns 1485 * 0 - success 1486 * ECONNABORTED - repository connection broken 1487 * EPERM - permission denied 1488 * ENOSPC - configd is out of resources 1489 * ECANCELED - inst was deleted 1490 * -1 - unknown libscf error (message printed) 1491 */ 1492 static int 1493 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1494 { 1495 again: 1496 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1497 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1498 switch (scf_error()) { 1499 case SCF_ERROR_CONNECTION_BROKEN: 1500 case SCF_ERROR_PERMISSION_DENIED: 1501 case SCF_ERROR_NO_RESOURCES: 1502 return (scferror2errno(scf_error())); 1503 1504 case SCF_ERROR_NOT_SET: 1505 case SCF_ERROR_INVALID_ARGUMENT: 1506 default: 1507 bad_error("_scf_snapshot_take_attach", 1508 scf_error()); 1509 } 1510 } 1511 } else { 1512 switch (scf_error()) { 1513 case SCF_ERROR_NOT_FOUND: 1514 break; 1515 1516 case SCF_ERROR_DELETED: 1517 case SCF_ERROR_CONNECTION_BROKEN: 1518 return (scferror2errno(scf_error())); 1519 1520 case SCF_ERROR_HANDLE_MISMATCH: 1521 case SCF_ERROR_NOT_BOUND: 1522 case SCF_ERROR_INVALID_ARGUMENT: 1523 case SCF_ERROR_NOT_SET: 1524 default: 1525 bad_error("scf_instance_get_snapshot", scf_error()); 1526 } 1527 1528 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1529 switch (scf_error()) { 1530 case SCF_ERROR_EXISTS: 1531 goto again; 1532 1533 case SCF_ERROR_CONNECTION_BROKEN: 1534 case SCF_ERROR_NO_RESOURCES: 1535 case SCF_ERROR_PERMISSION_DENIED: 1536 return (scferror2errno(scf_error())); 1537 1538 default: 1539 scfwarn(); 1540 return (-1); 1541 1542 case SCF_ERROR_NOT_SET: 1543 case SCF_ERROR_INTERNAL: 1544 case SCF_ERROR_INVALID_ARGUMENT: 1545 case SCF_ERROR_HANDLE_MISMATCH: 1546 bad_error("_scf_snapshot_take_new", 1547 scf_error()); 1548 } 1549 } 1550 } 1551 1552 return (0); 1553 } 1554 1555 static int 1556 refresh_running_snapshot(void *entity) 1557 { 1558 scf_snapshot_t *snap; 1559 int r; 1560 1561 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1562 scfdie(); 1563 r = take_snap(entity, snap_running, snap); 1564 scf_snapshot_destroy(snap); 1565 1566 return (r); 1567 } 1568 1569 /* 1570 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1571 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1572 * instances. fmri is used for messages. inst, iter, and name_buf are used 1573 * for scratch space. Returns 1574 * 0 - success 1575 * ECONNABORTED - repository connection broken 1576 * ECANCELED - entity was deleted 1577 * EACCES - backend denied access 1578 * EPERM - permission denied 1579 * ENOSPC - repository server out of resources 1580 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1581 */ 1582 static int 1583 refresh_entity(int isservice, void *entity, const char *fmri, 1584 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1585 { 1586 scf_error_t scfe; 1587 int r; 1588 1589 if (!isservice) { 1590 /* 1591 * Let restarter handles refreshing and making new running 1592 * snapshot only if operating on a live repository and not 1593 * running in early import. 1594 */ 1595 if (est->sc_repo_filename == NULL && 1596 est->sc_repo_doorname == NULL && 1597 est->sc_in_emi == 0) { 1598 if (_smf_refresh_instance_i(entity) == 0) { 1599 if (g_verbose) 1600 warn(gettext("Refreshed %s.\n"), fmri); 1601 return (0); 1602 } 1603 1604 switch (scf_error()) { 1605 case SCF_ERROR_BACKEND_ACCESS: 1606 return (EACCES); 1607 1608 case SCF_ERROR_PERMISSION_DENIED: 1609 return (EPERM); 1610 1611 default: 1612 return (-1); 1613 } 1614 } else { 1615 r = refresh_running_snapshot(entity); 1616 switch (r) { 1617 case 0: 1618 break; 1619 1620 case ECONNABORTED: 1621 case ECANCELED: 1622 case EPERM: 1623 case ENOSPC: 1624 break; 1625 1626 default: 1627 bad_error("refresh_running_snapshot", 1628 scf_error()); 1629 } 1630 1631 return (r); 1632 } 1633 } 1634 1635 if (scf_iter_service_instances(iter, entity) != 0) { 1636 switch (scf_error()) { 1637 case SCF_ERROR_CONNECTION_BROKEN: 1638 return (ECONNABORTED); 1639 1640 case SCF_ERROR_DELETED: 1641 return (ECANCELED); 1642 1643 case SCF_ERROR_HANDLE_MISMATCH: 1644 case SCF_ERROR_NOT_BOUND: 1645 case SCF_ERROR_NOT_SET: 1646 default: 1647 bad_error("scf_iter_service_instances", scf_error()); 1648 } 1649 } 1650 1651 for (;;) { 1652 r = scf_iter_next_instance(iter, inst); 1653 if (r == 0) 1654 break; 1655 if (r != 1) { 1656 switch (scf_error()) { 1657 case SCF_ERROR_CONNECTION_BROKEN: 1658 return (ECONNABORTED); 1659 1660 case SCF_ERROR_DELETED: 1661 return (ECANCELED); 1662 1663 case SCF_ERROR_HANDLE_MISMATCH: 1664 case SCF_ERROR_NOT_BOUND: 1665 case SCF_ERROR_NOT_SET: 1666 case SCF_ERROR_INVALID_ARGUMENT: 1667 default: 1668 bad_error("scf_iter_next_instance", 1669 scf_error()); 1670 } 1671 } 1672 1673 /* 1674 * Similarly, just take a new running snapshot if operating on 1675 * a non-live repository or running during early import. 1676 */ 1677 if (est->sc_repo_filename != NULL || 1678 est->sc_repo_doorname != NULL || 1679 est->sc_in_emi == 1) { 1680 r = refresh_running_snapshot(inst); 1681 switch (r) { 1682 case 0: 1683 continue; 1684 1685 case ECONNABORTED: 1686 case ECANCELED: 1687 case EPERM: 1688 case ENOSPC: 1689 break; 1690 default: 1691 bad_error("refresh_running_snapshot", 1692 scf_error()); 1693 } 1694 1695 return (r); 1696 1697 } 1698 1699 if (_smf_refresh_instance_i(inst) == 0) { 1700 if (g_verbose) { 1701 if (scf_instance_get_name(inst, name_buf, 1702 max_scf_name_len + 1) < 0) 1703 (void) strcpy(name_buf, "?"); 1704 1705 warn(gettext("Refreshed %s:%s.\n"), 1706 fmri, name_buf); 1707 } 1708 } else { 1709 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1710 g_verbose) { 1711 scfe = scf_error(); 1712 1713 if (scf_instance_to_fmri(inst, name_buf, 1714 max_scf_name_len + 1) < 0) 1715 (void) strcpy(name_buf, "?"); 1716 1717 warn(gettext( 1718 "Refresh of %s:%s failed: %s.\n"), fmri, 1719 name_buf, scf_strerror(scfe)); 1720 } 1721 } 1722 } 1723 1724 return (0); 1725 } 1726 1727 static void 1728 private_refresh(void) 1729 { 1730 scf_instance_t *pinst = NULL; 1731 scf_iter_t *piter = NULL; 1732 ssize_t fmrilen; 1733 size_t bufsz; 1734 char *fmribuf; 1735 void *ent; 1736 int issvc; 1737 int r; 1738 1739 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1740 return; 1741 1742 assert(cur_svc != NULL); 1743 1744 bufsz = max_scf_fmri_len + 1; 1745 fmribuf = safe_malloc(bufsz); 1746 if (cur_inst) { 1747 issvc = 0; 1748 ent = cur_inst; 1749 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1750 } else { 1751 issvc = 1; 1752 ent = cur_svc; 1753 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1754 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1755 scfdie(); 1756 1757 if ((piter = scf_iter_create(g_hndl)) == NULL) 1758 scfdie(); 1759 } 1760 if (fmrilen < 0) { 1761 free(fmribuf); 1762 if (scf_error() != SCF_ERROR_DELETED) 1763 scfdie(); 1764 1765 warn(emsg_deleted); 1766 return; 1767 } 1768 assert(fmrilen < bufsz); 1769 1770 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1771 switch (r) { 1772 case 0: 1773 break; 1774 1775 case ECONNABORTED: 1776 warn(gettext("Could not refresh %s " 1777 "(repository connection broken).\n"), fmribuf); 1778 break; 1779 1780 case ECANCELED: 1781 warn(emsg_deleted); 1782 break; 1783 1784 case EPERM: 1785 warn(gettext("Could not refresh %s " 1786 "(permission denied).\n"), fmribuf); 1787 break; 1788 1789 case ENOSPC: 1790 warn(gettext("Could not refresh %s " 1791 "(repository server out of resources).\n"), 1792 fmribuf); 1793 break; 1794 1795 case EACCES: 1796 default: 1797 bad_error("refresh_entity", scf_error()); 1798 } 1799 1800 if (issvc) { 1801 scf_instance_destroy(pinst); 1802 scf_iter_destroy(piter); 1803 } 1804 1805 free(fmribuf); 1806 } 1807 1808 1809 static int 1810 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1811 { 1812 cbp->sc_err = scferror2errno(err); 1813 return (UU_WALK_ERROR); 1814 } 1815 1816 static int 1817 stash_scferror(scf_callback_t *cbp) 1818 { 1819 return (stash_scferror_err(cbp, scf_error())); 1820 } 1821 1822 static int select_inst(const char *); 1823 static int select_svc(const char *); 1824 1825 /* 1826 * Take a property that does not have a type and check to see if a type 1827 * exists or can be gleened from the current data. Set the type. 1828 * 1829 * Check the current level (instance) and then check the higher level 1830 * (service). This could be the case for adding a new property to 1831 * the instance that's going to "override" a service level property. 1832 * 1833 * For a property : 1834 * 1. Take the type from an existing property 1835 * 2. Take the type from a template entry 1836 * 1837 * If the type can not be found, then leave the type as is, and let the import 1838 * report the problem of the missing type. 1839 */ 1840 static int 1841 find_current_prop_type(void *p, void *g) 1842 { 1843 property_t *prop = p; 1844 scf_callback_t *lcb = g; 1845 pgroup_t *pg = NULL; 1846 1847 const char *fmri = NULL; 1848 char *lfmri = NULL; 1849 char *cur_selection = NULL; 1850 1851 scf_propertygroup_t *sc_pg = NULL; 1852 scf_property_t *sc_prop = NULL; 1853 scf_pg_tmpl_t *t_pg = NULL; 1854 scf_prop_tmpl_t *t_prop = NULL; 1855 scf_type_t prop_type; 1856 1857 value_t *vp; 1858 int issvc = lcb->sc_service; 1859 int r = UU_WALK_ERROR; 1860 1861 if (prop->sc_value_type != SCF_TYPE_INVALID) 1862 return (UU_WALK_NEXT); 1863 1864 t_prop = scf_tmpl_prop_create(g_hndl); 1865 sc_prop = scf_property_create(g_hndl); 1866 if (sc_prop == NULL || t_prop == NULL) { 1867 warn(gettext("Unable to create the property to attempt and " 1868 "find a missing type.\n")); 1869 1870 scf_property_destroy(sc_prop); 1871 scf_tmpl_prop_destroy(t_prop); 1872 1873 return (UU_WALK_ERROR); 1874 } 1875 1876 if (lcb->sc_flags == 1) { 1877 pg = lcb->sc_parent; 1878 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT); 1879 fmri = pg->sc_parent->sc_fmri; 1880 retry_pg: 1881 if (cur_svc && cur_selection == NULL) { 1882 cur_selection = safe_malloc(max_scf_fmri_len + 1); 1883 lscf_get_selection_str(cur_selection, 1884 max_scf_fmri_len + 1); 1885 1886 if (strcmp(cur_selection, fmri) != 0) { 1887 lscf_select(fmri); 1888 } else { 1889 free(cur_selection); 1890 cur_selection = NULL; 1891 } 1892 } else { 1893 lscf_select(fmri); 1894 } 1895 1896 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) { 1897 warn(gettext("Unable to create property group to " 1898 "find a missing property type.\n")); 1899 1900 goto out; 1901 } 1902 1903 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) { 1904 /* 1905 * If this is the sc_pg from the parent 1906 * let the caller clean up the sc_pg, 1907 * and just throw it away in this case. 1908 */ 1909 if (sc_pg != lcb->sc_parent) 1910 scf_pg_destroy(sc_pg); 1911 1912 sc_pg = NULL; 1913 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1914 warn(gettext("Unable to create template " 1915 "property group to find a property " 1916 "type.\n")); 1917 1918 goto out; 1919 } 1920 1921 if (scf_tmpl_get_by_pg_name(fmri, NULL, 1922 pg->sc_pgroup_name, NULL, t_pg, 1923 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) { 1924 /* 1925 * if instance get service and jump back 1926 */ 1927 scf_tmpl_pg_destroy(t_pg); 1928 t_pg = NULL; 1929 if (issvc == 0) { 1930 entity_t *e = pg->sc_parent->sc_parent; 1931 1932 fmri = e->sc_fmri; 1933 issvc = 1; 1934 goto retry_pg; 1935 } else { 1936 goto out; 1937 } 1938 } 1939 } 1940 } else { 1941 sc_pg = lcb->sc_parent; 1942 } 1943 1944 /* 1945 * Attempt to get the type from an existing property. If the property 1946 * cannot be found then attempt to get the type from a template entry 1947 * for the property. 1948 * 1949 * Finally, if at the instance level look at the service level. 1950 */ 1951 if (sc_pg != NULL && 1952 pg_get_prop(sc_pg, prop->sc_property_name, 1953 sc_prop) == SCF_SUCCESS && 1954 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) { 1955 prop->sc_value_type = prop_type; 1956 1957 /* 1958 * Found a type, update the value types and validate 1959 * the actual value against this type. 1960 */ 1961 for (vp = uu_list_first(prop->sc_property_values); 1962 vp != NULL; 1963 vp = uu_list_next(prop->sc_property_values, vp)) { 1964 vp->sc_type = prop->sc_value_type; 1965 lxml_store_value(vp, 0, NULL); 1966 } 1967 1968 r = UU_WALK_NEXT; 1969 goto out; 1970 } 1971 1972 /* 1973 * If we get here with t_pg set to NULL then we had to have 1974 * gotten an sc_pg but that sc_pg did not have the property 1975 * we are looking for. So if the t_pg is not null look up 1976 * the template entry for the property. 1977 * 1978 * If the t_pg is null then need to attempt to get a matching 1979 * template entry for the sc_pg, and see if there is a property 1980 * entry for that template entry. 1981 */ 1982 do_tmpl : 1983 if (t_pg != NULL && 1984 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name, 1985 t_prop, 0) == SCF_SUCCESS) { 1986 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) { 1987 prop->sc_value_type = prop_type; 1988 1989 /* 1990 * Found a type, update the value types and validate 1991 * the actual value against this type. 1992 */ 1993 for (vp = uu_list_first(prop->sc_property_values); 1994 vp != NULL; 1995 vp = uu_list_next(prop->sc_property_values, vp)) { 1996 vp->sc_type = prop->sc_value_type; 1997 lxml_store_value(vp, 0, NULL); 1998 } 1999 2000 r = UU_WALK_NEXT; 2001 goto out; 2002 } 2003 } else { 2004 if (t_pg == NULL && sc_pg) { 2005 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 2006 warn(gettext("Unable to create template " 2007 "property group to find a property " 2008 "type.\n")); 2009 2010 goto out; 2011 } 2012 2013 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) { 2014 scf_tmpl_pg_destroy(t_pg); 2015 t_pg = NULL; 2016 } else { 2017 goto do_tmpl; 2018 } 2019 } 2020 } 2021 2022 if (issvc == 0) { 2023 scf_instance_t *i; 2024 scf_service_t *s; 2025 2026 issvc = 1; 2027 if (lcb->sc_flags == 1) { 2028 entity_t *e = pg->sc_parent->sc_parent; 2029 2030 fmri = e->sc_fmri; 2031 goto retry_pg; 2032 } 2033 2034 /* 2035 * because lcb->sc_flags was not set then this means 2036 * the pg was not used and can be used here. 2037 */ 2038 if ((pg = internal_pgroup_new()) == NULL) { 2039 warn(gettext("Could not create internal property group " 2040 "to find a missing type.")); 2041 2042 goto out; 2043 } 2044 2045 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1); 2046 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name, 2047 max_scf_name_len + 1) < 0) 2048 goto out; 2049 2050 i = scf_instance_create(g_hndl); 2051 s = scf_service_create(g_hndl); 2052 if (i == NULL || s == NULL || 2053 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) { 2054 warn(gettext("Could not get a service for the instance " 2055 "to find a missing type.")); 2056 2057 goto out; 2058 } 2059 2060 /* 2061 * Check to see truly at the instance level. 2062 */ 2063 lfmri = safe_malloc(max_scf_fmri_len + 1); 2064 if (scf_instance_get_parent(i, s) == SCF_SUCCESS && 2065 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0) 2066 goto out; 2067 else 2068 fmri = (const char *)lfmri; 2069 2070 goto retry_pg; 2071 } 2072 2073 out : 2074 if (sc_pg != lcb->sc_parent) { 2075 scf_pg_destroy(sc_pg); 2076 } 2077 2078 /* 2079 * If this is true then the pg was allocated 2080 * here, and the name was set so need to free 2081 * the name and the pg. 2082 */ 2083 if (pg != NULL && pg != lcb->sc_parent) { 2084 free((char *)pg->sc_pgroup_name); 2085 internal_pgroup_free(pg); 2086 } 2087 2088 if (cur_selection) { 2089 lscf_select(cur_selection); 2090 free(cur_selection); 2091 } 2092 2093 scf_tmpl_pg_destroy(t_pg); 2094 scf_tmpl_prop_destroy(t_prop); 2095 scf_property_destroy(sc_prop); 2096 2097 if (r != UU_WALK_NEXT) 2098 warn(gettext("Could not find property type for \"%s\" " 2099 "from \"%s\"\n"), prop->sc_property_name, 2100 fmri != NULL ? fmri : lcb->sc_source_fmri); 2101 2102 free(lfmri); 2103 2104 return (r); 2105 } 2106 2107 /* 2108 * Take a property group that does not have a type and check to see if a type 2109 * exists or can be gleened from the current data. Set the type. 2110 * 2111 * Check the current level (instance) and then check the higher level 2112 * (service). This could be the case for adding a new property to 2113 * the instance that's going to "override" a service level property. 2114 * 2115 * For a property group 2116 * 1. Take the type from an existing property group 2117 * 2. Take the type from a template entry 2118 * 2119 * If the type can not be found, then leave the type as is, and let the import 2120 * report the problem of the missing type. 2121 */ 2122 static int 2123 find_current_pg_type(void *p, void *sori) 2124 { 2125 entity_t *si = sori; 2126 pgroup_t *pg = p; 2127 2128 const char *ofmri, *fmri; 2129 char *cur_selection = NULL; 2130 char *pg_type = NULL; 2131 2132 scf_propertygroup_t *sc_pg = NULL; 2133 scf_pg_tmpl_t *t_pg = NULL; 2134 2135 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2136 int r = UU_WALK_ERROR; 2137 2138 ofmri = fmri = si->sc_fmri; 2139 if (pg->sc_pgroup_type != NULL) { 2140 r = UU_WALK_NEXT; 2141 2142 goto out; 2143 } 2144 2145 sc_pg = scf_pg_create(g_hndl); 2146 if (sc_pg == NULL) { 2147 warn(gettext("Unable to create property group to attempt " 2148 "and find a missing type.\n")); 2149 2150 return (UU_WALK_ERROR); 2151 } 2152 2153 /* 2154 * Using get_pg() requires that the cur_svc/cur_inst be 2155 * via lscf_select. Need to preserve the current selection 2156 * if going to use lscf_select() to set up the cur_svc/cur_inst 2157 */ 2158 if (cur_svc) { 2159 cur_selection = safe_malloc(max_scf_fmri_len + 1); 2160 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1); 2161 } 2162 2163 /* 2164 * If the property group exists get the type, and set 2165 * the pgroup_t type of that type. 2166 * 2167 * If not the check for a template pg_pattern entry 2168 * and take the type from that. 2169 */ 2170 retry_svc: 2171 lscf_select(fmri); 2172 2173 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) { 2174 pg_type = safe_malloc(max_scf_pg_type_len + 1); 2175 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type, 2176 max_scf_pg_type_len + 1) != -1) { 2177 pg->sc_pgroup_type = pg_type; 2178 2179 r = UU_WALK_NEXT; 2180 goto out; 2181 } else { 2182 free(pg_type); 2183 } 2184 } else { 2185 if ((t_pg == NULL) && 2186 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) 2187 goto out; 2188 2189 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name, 2190 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS && 2191 scf_tmpl_pg_type(t_pg, &pg_type) != -1) { 2192 pg->sc_pgroup_type = pg_type; 2193 2194 r = UU_WALK_NEXT; 2195 goto out; 2196 } 2197 } 2198 2199 /* 2200 * If type is not found at the instance level then attempt to 2201 * find the type at the service level. 2202 */ 2203 if (!issvc) { 2204 si = si->sc_parent; 2205 fmri = si->sc_fmri; 2206 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2207 goto retry_svc; 2208 } 2209 2210 out : 2211 if (cur_selection) { 2212 lscf_select(cur_selection); 2213 free(cur_selection); 2214 } 2215 2216 /* 2217 * Now walk the properties of the property group to make sure that 2218 * all properties have the correct type and values are valid for 2219 * those types. 2220 */ 2221 if (r == UU_WALK_NEXT) { 2222 scf_callback_t cb; 2223 2224 cb.sc_service = issvc; 2225 cb.sc_source_fmri = ofmri; 2226 if (sc_pg != NULL) { 2227 cb.sc_parent = sc_pg; 2228 cb.sc_flags = 0; 2229 } else { 2230 cb.sc_parent = pg; 2231 cb.sc_flags = 1; 2232 } 2233 2234 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type, 2235 &cb, UU_DEFAULT) != 0) { 2236 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2237 bad_error("uu_list_walk", uu_error()); 2238 2239 r = UU_WALK_ERROR; 2240 } 2241 } else { 2242 warn(gettext("Could not find property group type for " 2243 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri); 2244 } 2245 2246 scf_tmpl_pg_destroy(t_pg); 2247 scf_pg_destroy(sc_pg); 2248 2249 return (r); 2250 } 2251 2252 /* 2253 * Import. These functions import a bundle into the repository. 2254 */ 2255 2256 /* 2257 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 2258 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 2259 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2260 * lcbdata->sc_err to 2261 * ENOMEM - out of memory 2262 * ECONNABORTED - repository connection broken 2263 * ECANCELED - sc_trans's property group was deleted 2264 * EINVAL - p's name is invalid (error printed) 2265 * - p has an invalid value (error printed) 2266 */ 2267 static int 2268 lscf_property_import(void *v, void *pvt) 2269 { 2270 property_t *p = v; 2271 scf_callback_t *lcbdata = pvt; 2272 value_t *vp; 2273 scf_transaction_t *trans = lcbdata->sc_trans; 2274 scf_transaction_entry_t *entr; 2275 scf_value_t *val; 2276 scf_type_t tp; 2277 2278 if ((lcbdata->sc_flags & SCI_NOENABLED || 2279 lcbdata->sc_flags & SCI_DELAYENABLE) && 2280 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 2281 lcbdata->sc_enable = p; 2282 return (UU_WALK_NEXT); 2283 } 2284 2285 entr = scf_entry_create(lcbdata->sc_handle); 2286 if (entr == NULL) { 2287 switch (scf_error()) { 2288 case SCF_ERROR_NO_MEMORY: 2289 return (stash_scferror(lcbdata)); 2290 2291 case SCF_ERROR_INVALID_ARGUMENT: 2292 default: 2293 bad_error("scf_entry_create", scf_error()); 2294 } 2295 } 2296 2297 tp = p->sc_value_type; 2298 2299 if (scf_transaction_property_new(trans, entr, 2300 p->sc_property_name, tp) != 0) { 2301 switch (scf_error()) { 2302 case SCF_ERROR_INVALID_ARGUMENT: 2303 semerr(emsg_invalid_prop_name, p->sc_property_name); 2304 scf_entry_destroy(entr); 2305 return (stash_scferror(lcbdata)); 2306 2307 case SCF_ERROR_EXISTS: 2308 break; 2309 2310 case SCF_ERROR_DELETED: 2311 case SCF_ERROR_CONNECTION_BROKEN: 2312 scf_entry_destroy(entr); 2313 return (stash_scferror(lcbdata)); 2314 2315 case SCF_ERROR_NOT_BOUND: 2316 case SCF_ERROR_HANDLE_MISMATCH: 2317 case SCF_ERROR_NOT_SET: 2318 default: 2319 bad_error("scf_transaction_property_new", scf_error()); 2320 } 2321 2322 if (scf_transaction_property_change_type(trans, entr, 2323 p->sc_property_name, tp) != 0) { 2324 switch (scf_error()) { 2325 case SCF_ERROR_DELETED: 2326 case SCF_ERROR_CONNECTION_BROKEN: 2327 scf_entry_destroy(entr); 2328 return (stash_scferror(lcbdata)); 2329 2330 case SCF_ERROR_INVALID_ARGUMENT: 2331 semerr(emsg_invalid_prop_name, 2332 p->sc_property_name); 2333 scf_entry_destroy(entr); 2334 return (stash_scferror(lcbdata)); 2335 2336 case SCF_ERROR_NOT_FOUND: 2337 case SCF_ERROR_NOT_SET: 2338 case SCF_ERROR_HANDLE_MISMATCH: 2339 case SCF_ERROR_NOT_BOUND: 2340 default: 2341 bad_error( 2342 "scf_transaction_property_change_type", 2343 scf_error()); 2344 } 2345 } 2346 } 2347 2348 for (vp = uu_list_first(p->sc_property_values); 2349 vp != NULL; 2350 vp = uu_list_next(p->sc_property_values, vp)) { 2351 val = scf_value_create(g_hndl); 2352 if (val == NULL) { 2353 switch (scf_error()) { 2354 case SCF_ERROR_NO_MEMORY: 2355 return (stash_scferror(lcbdata)); 2356 2357 case SCF_ERROR_INVALID_ARGUMENT: 2358 default: 2359 bad_error("scf_value_create", scf_error()); 2360 } 2361 } 2362 2363 switch (tp) { 2364 case SCF_TYPE_BOOLEAN: 2365 scf_value_set_boolean(val, vp->sc_u.sc_count); 2366 break; 2367 case SCF_TYPE_COUNT: 2368 scf_value_set_count(val, vp->sc_u.sc_count); 2369 break; 2370 case SCF_TYPE_INTEGER: 2371 scf_value_set_integer(val, vp->sc_u.sc_integer); 2372 break; 2373 default: 2374 assert(vp->sc_u.sc_string != NULL); 2375 if (scf_value_set_from_string(val, tp, 2376 vp->sc_u.sc_string) != 0) { 2377 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 2378 bad_error("scf_value_set_from_string", 2379 scf_error()); 2380 2381 warn(gettext("Value \"%s\" is not a valid " 2382 "%s.\n"), vp->sc_u.sc_string, 2383 scf_type_to_string(tp)); 2384 scf_value_destroy(val); 2385 return (stash_scferror(lcbdata)); 2386 } 2387 break; 2388 } 2389 2390 if (scf_entry_add_value(entr, val) != 0) 2391 bad_error("scf_entry_add_value", scf_error()); 2392 } 2393 2394 return (UU_WALK_NEXT); 2395 } 2396 2397 /* 2398 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 2399 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 2400 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 2401 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2402 * lcbdata->sc_err to 2403 * ECONNABORTED - repository connection broken 2404 * ENOMEM - out of memory 2405 * ENOSPC - svc.configd is out of resources 2406 * ECANCELED - sc_parent was deleted 2407 * EPERM - could not create property group (permission denied) (error printed) 2408 * - could not modify property group (permission denied) (error printed) 2409 * - could not delete property group (permission denied) (error printed) 2410 * EROFS - could not create property group (repository is read-only) 2411 * - could not delete property group (repository is read-only) 2412 * EACCES - could not create property group (backend access denied) 2413 * - could not delete property group (backend access denied) 2414 * EEXIST - could not create property group (already exists) 2415 * EINVAL - invalid property group name (error printed) 2416 * - invalid property name (error printed) 2417 * - invalid value (error printed) 2418 * EBUSY - new property group deleted (error printed) 2419 * - new property group changed (error printed) 2420 * - property group added (error printed) 2421 * - property group deleted (error printed) 2422 */ 2423 static int 2424 entity_pgroup_import(void *v, void *pvt) 2425 { 2426 pgroup_t *p = v; 2427 scf_callback_t cbdata; 2428 scf_callback_t *lcbdata = pvt; 2429 void *ent = lcbdata->sc_parent; 2430 int issvc = lcbdata->sc_service; 2431 int r; 2432 2433 const char * const pg_changed = gettext("%s changed unexpectedly " 2434 "(new property group \"%s\" changed).\n"); 2435 2436 /* Never import deleted property groups. */ 2437 if (p->sc_pgroup_delete) { 2438 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY && 2439 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) { 2440 goto delete_pg; 2441 } 2442 return (UU_WALK_NEXT); 2443 } 2444 2445 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 2446 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 2447 lcbdata->sc_general = p; 2448 return (UU_WALK_NEXT); 2449 } 2450 2451 add_pg: 2452 if (issvc) 2453 r = scf_service_add_pg(ent, p->sc_pgroup_name, 2454 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2455 else 2456 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 2457 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2458 if (r != 0) { 2459 switch (scf_error()) { 2460 case SCF_ERROR_DELETED: 2461 case SCF_ERROR_CONNECTION_BROKEN: 2462 case SCF_ERROR_BACKEND_READONLY: 2463 case SCF_ERROR_BACKEND_ACCESS: 2464 case SCF_ERROR_NO_RESOURCES: 2465 return (stash_scferror(lcbdata)); 2466 2467 case SCF_ERROR_EXISTS: 2468 if (lcbdata->sc_flags & SCI_FORCE) 2469 break; 2470 return (stash_scferror(lcbdata)); 2471 2472 case SCF_ERROR_INVALID_ARGUMENT: 2473 warn(emsg_fmri_invalid_pg_name_type, 2474 lcbdata->sc_source_fmri, 2475 p->sc_pgroup_name, p->sc_pgroup_type); 2476 return (stash_scferror(lcbdata)); 2477 2478 case SCF_ERROR_PERMISSION_DENIED: 2479 warn(emsg_pg_add_perm, p->sc_pgroup_name, 2480 lcbdata->sc_target_fmri); 2481 return (stash_scferror(lcbdata)); 2482 2483 case SCF_ERROR_NOT_BOUND: 2484 case SCF_ERROR_HANDLE_MISMATCH: 2485 case SCF_ERROR_NOT_SET: 2486 default: 2487 bad_error("scf_service_add_pg", scf_error()); 2488 } 2489 2490 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2491 switch (scf_error()) { 2492 case SCF_ERROR_CONNECTION_BROKEN: 2493 case SCF_ERROR_DELETED: 2494 return (stash_scferror(lcbdata)); 2495 2496 case SCF_ERROR_INVALID_ARGUMENT: 2497 warn(emsg_fmri_invalid_pg_name, 2498 lcbdata->sc_source_fmri, 2499 p->sc_pgroup_name); 2500 return (stash_scferror(lcbdata)); 2501 2502 case SCF_ERROR_NOT_FOUND: 2503 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2504 p->sc_pgroup_name); 2505 lcbdata->sc_err = EBUSY; 2506 return (UU_WALK_ERROR); 2507 2508 case SCF_ERROR_NOT_BOUND: 2509 case SCF_ERROR_HANDLE_MISMATCH: 2510 case SCF_ERROR_NOT_SET: 2511 default: 2512 bad_error("entity_get_pg", scf_error()); 2513 } 2514 } 2515 2516 if (lcbdata->sc_flags & SCI_KEEP) 2517 goto props; 2518 2519 delete_pg: 2520 if (scf_pg_delete(imp_pg) != 0) { 2521 switch (scf_error()) { 2522 case SCF_ERROR_DELETED: 2523 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2524 p->sc_pgroup_name); 2525 lcbdata->sc_err = EBUSY; 2526 return (UU_WALK_ERROR); 2527 2528 case SCF_ERROR_PERMISSION_DENIED: 2529 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2530 lcbdata->sc_target_fmri); 2531 return (stash_scferror(lcbdata)); 2532 2533 case SCF_ERROR_BACKEND_READONLY: 2534 case SCF_ERROR_BACKEND_ACCESS: 2535 case SCF_ERROR_CONNECTION_BROKEN: 2536 return (stash_scferror(lcbdata)); 2537 2538 case SCF_ERROR_NOT_SET: 2539 default: 2540 bad_error("scf_pg_delete", scf_error()); 2541 } 2542 } 2543 2544 if (p->sc_pgroup_delete) 2545 return (UU_WALK_NEXT); 2546 2547 goto add_pg; 2548 } 2549 2550 props: 2551 2552 /* 2553 * Add properties to property group, if any. 2554 */ 2555 cbdata.sc_handle = lcbdata->sc_handle; 2556 cbdata.sc_parent = imp_pg; 2557 cbdata.sc_flags = lcbdata->sc_flags; 2558 cbdata.sc_trans = imp_tx; 2559 cbdata.sc_enable = NULL; 2560 2561 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2562 switch (scf_error()) { 2563 case SCF_ERROR_BACKEND_ACCESS: 2564 case SCF_ERROR_BACKEND_READONLY: 2565 case SCF_ERROR_CONNECTION_BROKEN: 2566 return (stash_scferror(lcbdata)); 2567 2568 case SCF_ERROR_DELETED: 2569 warn(pg_changed, lcbdata->sc_target_fmri, 2570 p->sc_pgroup_name); 2571 lcbdata->sc_err = EBUSY; 2572 return (UU_WALK_ERROR); 2573 2574 case SCF_ERROR_PERMISSION_DENIED: 2575 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2576 lcbdata->sc_target_fmri); 2577 return (stash_scferror(lcbdata)); 2578 2579 case SCF_ERROR_NOT_BOUND: 2580 case SCF_ERROR_NOT_SET: 2581 case SCF_ERROR_IN_USE: 2582 case SCF_ERROR_HANDLE_MISMATCH: 2583 default: 2584 bad_error("scf_transaction_start", scf_error()); 2585 } 2586 } 2587 2588 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2589 UU_DEFAULT) != 0) { 2590 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2591 bad_error("uu_list_walk", uu_error()); 2592 scf_transaction_reset(imp_tx); 2593 2594 lcbdata->sc_err = cbdata.sc_err; 2595 if (cbdata.sc_err == ECANCELED) { 2596 warn(pg_changed, lcbdata->sc_target_fmri, 2597 p->sc_pgroup_name); 2598 lcbdata->sc_err = EBUSY; 2599 } 2600 return (UU_WALK_ERROR); 2601 } 2602 2603 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2604 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2605 2606 /* 2607 * take the snapshot running snapshot then 2608 * import the stored general/enable property 2609 */ 2610 r = take_snap(ent, snap_running, imp_rsnap); 2611 switch (r) { 2612 case 0: 2613 break; 2614 2615 case ECONNABORTED: 2616 warn(gettext("Could not take %s snapshot on import " 2617 "(repository connection broken).\n"), 2618 snap_running); 2619 lcbdata->sc_err = r; 2620 return (UU_WALK_ERROR); 2621 case ECANCELED: 2622 warn(emsg_deleted); 2623 lcbdata->sc_err = r; 2624 return (UU_WALK_ERROR); 2625 2626 case EPERM: 2627 warn(gettext("Could not take %s snapshot " 2628 "(permission denied).\n"), snap_running); 2629 lcbdata->sc_err = r; 2630 return (UU_WALK_ERROR); 2631 2632 case ENOSPC: 2633 warn(gettext("Could not take %s snapshot" 2634 "(repository server out of resources).\n"), 2635 snap_running); 2636 lcbdata->sc_err = r; 2637 return (UU_WALK_ERROR); 2638 2639 default: 2640 bad_error("take_snap", r); 2641 } 2642 2643 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2644 if (r != UU_WALK_NEXT) { 2645 if (r != UU_WALK_ERROR) 2646 bad_error("lscf_property_import", r); 2647 return (EINVAL); 2648 } 2649 } 2650 2651 r = scf_transaction_commit(imp_tx); 2652 switch (r) { 2653 case 1: 2654 r = UU_WALK_NEXT; 2655 break; 2656 2657 case 0: 2658 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2659 lcbdata->sc_err = EBUSY; 2660 r = UU_WALK_ERROR; 2661 break; 2662 2663 case -1: 2664 switch (scf_error()) { 2665 case SCF_ERROR_BACKEND_READONLY: 2666 case SCF_ERROR_BACKEND_ACCESS: 2667 case SCF_ERROR_CONNECTION_BROKEN: 2668 case SCF_ERROR_NO_RESOURCES: 2669 r = stash_scferror(lcbdata); 2670 break; 2671 2672 case SCF_ERROR_DELETED: 2673 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2674 p->sc_pgroup_name); 2675 lcbdata->sc_err = EBUSY; 2676 r = UU_WALK_ERROR; 2677 break; 2678 2679 case SCF_ERROR_PERMISSION_DENIED: 2680 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2681 lcbdata->sc_target_fmri); 2682 r = stash_scferror(lcbdata); 2683 break; 2684 2685 case SCF_ERROR_NOT_SET: 2686 case SCF_ERROR_INVALID_ARGUMENT: 2687 case SCF_ERROR_NOT_BOUND: 2688 default: 2689 bad_error("scf_transaction_commit", scf_error()); 2690 } 2691 break; 2692 2693 default: 2694 bad_error("scf_transaction_commit", r); 2695 } 2696 2697 scf_transaction_destroy_children(imp_tx); 2698 2699 return (r); 2700 } 2701 2702 /* 2703 * Returns 2704 * 0 - success 2705 * ECONNABORTED - repository connection broken 2706 * ENOMEM - out of memory 2707 * ENOSPC - svc.configd is out of resources 2708 * ECANCELED - inst was deleted 2709 * EPERM - could not create property group (permission denied) (error printed) 2710 * - could not modify property group (permission denied) (error printed) 2711 * EROFS - could not create property group (repository is read-only) 2712 * EACCES - could not create property group (backend access denied) 2713 * EEXIST - could not create property group (already exists) 2714 * EINVAL - invalid property group name (error printed) 2715 * - invalid property name (error printed) 2716 * - invalid value (error printed) 2717 * EBUSY - new property group changed (error printed) 2718 */ 2719 static int 2720 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2721 const entity_t *isvc, int flags) 2722 { 2723 scf_callback_t cbdata; 2724 2725 cbdata.sc_handle = scf_service_handle(svc); 2726 cbdata.sc_parent = svc; 2727 cbdata.sc_service = 1; 2728 cbdata.sc_general = 0; 2729 cbdata.sc_enable = 0; 2730 cbdata.sc_flags = flags; 2731 cbdata.sc_source_fmri = isvc->sc_fmri; 2732 cbdata.sc_target_fmri = target_fmri; 2733 2734 /* 2735 * If the op is set, then add the flag to the callback 2736 * flags for later use. 2737 */ 2738 if (isvc->sc_op != SVCCFG_OP_NONE) { 2739 switch (isvc->sc_op) { 2740 case SVCCFG_OP_IMPORT : 2741 cbdata.sc_flags |= SCI_OP_IMPORT; 2742 break; 2743 case SVCCFG_OP_APPLY : 2744 cbdata.sc_flags |= SCI_OP_APPLY; 2745 break; 2746 case SVCCFG_OP_RESTORE : 2747 cbdata.sc_flags |= SCI_OP_RESTORE; 2748 break; 2749 default : 2750 uu_die(gettext("lscf_import_service_pgs : " 2751 "Unknown op stored in the service entity\n")); 2752 2753 } 2754 } 2755 2756 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2757 UU_DEFAULT) != 0) { 2758 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2759 bad_error("uu_list_walk", uu_error()); 2760 2761 return (cbdata.sc_err); 2762 } 2763 2764 return (0); 2765 } 2766 2767 /* 2768 * Returns 2769 * 0 - success 2770 * ECONNABORTED - repository connection broken 2771 * ENOMEM - out of memory 2772 * ENOSPC - svc.configd is out of resources 2773 * ECANCELED - inst was deleted 2774 * EPERM - could not create property group (permission denied) (error printed) 2775 * - could not modify property group (permission denied) (error printed) 2776 * EROFS - could not create property group (repository is read-only) 2777 * EACCES - could not create property group (backend access denied) 2778 * EEXIST - could not create property group (already exists) 2779 * EINVAL - invalid property group name (error printed) 2780 * - invalid property name (error printed) 2781 * - invalid value (error printed) 2782 * EBUSY - new property group changed (error printed) 2783 */ 2784 static int 2785 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2786 const entity_t *iinst, int flags) 2787 { 2788 scf_callback_t cbdata; 2789 2790 cbdata.sc_handle = scf_instance_handle(inst); 2791 cbdata.sc_parent = inst; 2792 cbdata.sc_service = 0; 2793 cbdata.sc_general = NULL; 2794 cbdata.sc_enable = NULL; 2795 cbdata.sc_flags = flags; 2796 cbdata.sc_source_fmri = iinst->sc_fmri; 2797 cbdata.sc_target_fmri = target_fmri; 2798 2799 /* 2800 * If the op is set, then add the flag to the callback 2801 * flags for later use. 2802 */ 2803 if (iinst->sc_op != SVCCFG_OP_NONE) { 2804 switch (iinst->sc_op) { 2805 case SVCCFG_OP_IMPORT : 2806 cbdata.sc_flags |= SCI_OP_IMPORT; 2807 break; 2808 case SVCCFG_OP_APPLY : 2809 cbdata.sc_flags |= SCI_OP_APPLY; 2810 break; 2811 case SVCCFG_OP_RESTORE : 2812 cbdata.sc_flags |= SCI_OP_RESTORE; 2813 break; 2814 default : 2815 uu_die(gettext("lscf_import_instance_pgs : " 2816 "Unknown op stored in the instance entity\n")); 2817 } 2818 } 2819 2820 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2821 UU_DEFAULT) != 0) { 2822 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2823 bad_error("uu_list_walk", uu_error()); 2824 2825 return (cbdata.sc_err); 2826 } 2827 2828 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2829 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2830 /* 2831 * If importing with the SCI_NOENABLED flag then 2832 * skip the delay, but if not then add the delay 2833 * of the enable property. 2834 */ 2835 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2836 cbdata.sc_flags |= SCI_DELAYENABLE; 2837 } 2838 2839 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2840 != UU_WALK_NEXT) 2841 return (cbdata.sc_err); 2842 } 2843 2844 return (0); 2845 } 2846 2847 /* 2848 * Report the reasons why we can't upgrade pg2 to pg1. 2849 */ 2850 static void 2851 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2852 int new) 2853 { 2854 property_t *p1, *p2; 2855 2856 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2857 2858 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2859 return; 2860 2861 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2862 p1 != NULL; 2863 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2864 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2865 if (p2 != NULL) { 2866 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2867 new); 2868 continue; 2869 } 2870 2871 if (new) 2872 warn(gettext("Conflict upgrading %s (new property " 2873 "group \"%s\" is missing property \"%s\").\n"), 2874 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2875 else 2876 warn(gettext("Conflict upgrading %s (property " 2877 "\"%s/%s\" is missing).\n"), fmri, 2878 pg1->sc_pgroup_name, p1->sc_property_name); 2879 } 2880 2881 /* 2882 * Since pg1 should be from the manifest, any properties in pg2 which 2883 * aren't in pg1 shouldn't be reported as conflicts. 2884 */ 2885 } 2886 2887 /* 2888 * Add transaction entries to tx which will upgrade cur's pg according to old 2889 * & new. 2890 * 2891 * Returns 2892 * 0 - success 2893 * EINVAL - new has a property with an invalid name or value (message emitted) 2894 * ENOMEM - out of memory 2895 */ 2896 static int 2897 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2898 pgroup_t *cur, int speak, const char *fmri) 2899 { 2900 property_t *p, *new_p, *cur_p; 2901 scf_transaction_entry_t *e; 2902 int r; 2903 int is_general; 2904 int is_protected; 2905 2906 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2907 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2908 bad_error("uu_list_walk", uu_error()); 2909 2910 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2911 2912 for (p = uu_list_first(old->sc_pgroup_props); 2913 p != NULL; 2914 p = uu_list_next(old->sc_pgroup_props, p)) { 2915 /* p is a property in the old property group. */ 2916 2917 /* Protect live properties. */ 2918 is_protected = 0; 2919 if (is_general) { 2920 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2921 0 || 2922 strcmp(p->sc_property_name, 2923 SCF_PROPERTY_RESTARTER) == 0) 2924 is_protected = 1; 2925 } 2926 2927 /* Look for the same property in the new properties. */ 2928 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2929 if (new_p != NULL) { 2930 new_p->sc_seen = 1; 2931 2932 /* 2933 * If the new property is the same as the old, don't do 2934 * anything (leave any user customizations). 2935 */ 2936 if (prop_equal(p, new_p, NULL, NULL, 0)) 2937 continue; 2938 2939 if (new_p->sc_property_override) 2940 goto upgrade; 2941 } 2942 2943 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2944 if (cur_p == NULL) { 2945 /* 2946 * p has been deleted from the repository. If we were 2947 * going to delete it anyway, do nothing. Otherwise 2948 * report a conflict. 2949 */ 2950 if (new_p == NULL) 2951 continue; 2952 2953 if (is_protected) 2954 continue; 2955 2956 warn(gettext("Conflict upgrading %s " 2957 "(property \"%s/%s\" is missing).\n"), fmri, 2958 old->sc_pgroup_name, p->sc_property_name); 2959 continue; 2960 } 2961 2962 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2963 /* 2964 * Conflict. Don't warn if the property is already the 2965 * way we want it, though. 2966 */ 2967 if (is_protected) 2968 continue; 2969 2970 if (new_p == NULL) 2971 (void) prop_equal(p, cur_p, fmri, 2972 old->sc_pgroup_name, 0); 2973 else 2974 (void) prop_equal(cur_p, new_p, fmri, 2975 old->sc_pgroup_name, 0); 2976 continue; 2977 } 2978 2979 if (is_protected) { 2980 if (speak) 2981 warn(gettext("%s: Refusing to upgrade " 2982 "\"%s/%s\" (live property).\n"), fmri, 2983 old->sc_pgroup_name, p->sc_property_name); 2984 continue; 2985 } 2986 2987 upgrade: 2988 /* p hasn't been customized in the repository. Upgrade it. */ 2989 if (new_p == NULL) { 2990 /* p was deleted. Delete from cur if unchanged. */ 2991 if (speak) 2992 warn(gettext( 2993 "%s: Deleting property \"%s/%s\".\n"), 2994 fmri, old->sc_pgroup_name, 2995 p->sc_property_name); 2996 2997 e = scf_entry_create(g_hndl); 2998 if (e == NULL) 2999 return (ENOMEM); 3000 3001 if (scf_transaction_property_delete(tx, e, 3002 p->sc_property_name) != 0) { 3003 switch (scf_error()) { 3004 case SCF_ERROR_DELETED: 3005 scf_entry_destroy(e); 3006 return (ECANCELED); 3007 3008 case SCF_ERROR_CONNECTION_BROKEN: 3009 scf_entry_destroy(e); 3010 return (ECONNABORTED); 3011 3012 case SCF_ERROR_NOT_FOUND: 3013 /* 3014 * This can happen if cur is from the 3015 * running snapshot (and it differs 3016 * from the live properties). 3017 */ 3018 scf_entry_destroy(e); 3019 break; 3020 3021 case SCF_ERROR_HANDLE_MISMATCH: 3022 case SCF_ERROR_NOT_BOUND: 3023 case SCF_ERROR_NOT_SET: 3024 case SCF_ERROR_INVALID_ARGUMENT: 3025 default: 3026 bad_error( 3027 "scf_transaction_property_delete", 3028 scf_error()); 3029 } 3030 } 3031 } else { 3032 scf_callback_t ctx; 3033 3034 if (speak) 3035 warn(gettext( 3036 "%s: Upgrading property \"%s/%s\".\n"), 3037 fmri, old->sc_pgroup_name, 3038 p->sc_property_name); 3039 3040 ctx.sc_handle = g_hndl; 3041 ctx.sc_trans = tx; 3042 ctx.sc_flags = 0; 3043 3044 r = lscf_property_import(new_p, &ctx); 3045 if (r != UU_WALK_NEXT) { 3046 if (r != UU_WALK_ERROR) 3047 bad_error("lscf_property_import", r); 3048 return (EINVAL); 3049 } 3050 } 3051 } 3052 3053 /* Go over the properties which were added. */ 3054 for (new_p = uu_list_first(new->sc_pgroup_props); 3055 new_p != NULL; 3056 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 3057 if (new_p->sc_seen) 3058 continue; 3059 3060 /* This is a new property. */ 3061 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 3062 if (cur_p == NULL) { 3063 scf_callback_t ctx; 3064 3065 ctx.sc_handle = g_hndl; 3066 ctx.sc_trans = tx; 3067 ctx.sc_flags = 0; 3068 3069 r = lscf_property_import(new_p, &ctx); 3070 if (r != UU_WALK_NEXT) { 3071 if (r != UU_WALK_ERROR) 3072 bad_error("lscf_property_import", r); 3073 return (EINVAL); 3074 } 3075 continue; 3076 } 3077 3078 /* 3079 * Report a conflict if the new property differs from the 3080 * current one. Unless it's general/enabled, since that's 3081 * never in the last-import snapshot. 3082 */ 3083 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 3084 0 && 3085 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 3086 continue; 3087 3088 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 3089 } 3090 3091 return (0); 3092 } 3093 3094 /* 3095 * Upgrade pg according to old & new. 3096 * 3097 * Returns 3098 * 0 - success 3099 * ECONNABORTED - repository connection broken 3100 * ENOMEM - out of memory 3101 * ENOSPC - svc.configd is out of resources 3102 * ECANCELED - pg was deleted 3103 * EPERM - couldn't modify pg (permission denied) 3104 * EROFS - couldn't modify pg (backend read-only) 3105 * EACCES - couldn't modify pg (backend access denied) 3106 * EINVAL - new has a property with invalid name or value (error printed) 3107 * EBUSY - pg changed unexpectedly 3108 */ 3109 static int 3110 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 3111 pgroup_t *new, int speak, const char *fmri) 3112 { 3113 int r; 3114 3115 if (scf_transaction_start(imp_tx, pg) != 0) { 3116 switch (scf_error()) { 3117 case SCF_ERROR_CONNECTION_BROKEN: 3118 case SCF_ERROR_DELETED: 3119 case SCF_ERROR_PERMISSION_DENIED: 3120 case SCF_ERROR_BACKEND_READONLY: 3121 case SCF_ERROR_BACKEND_ACCESS: 3122 return (scferror2errno(scf_error())); 3123 3124 case SCF_ERROR_HANDLE_MISMATCH: 3125 case SCF_ERROR_IN_USE: 3126 case SCF_ERROR_NOT_BOUND: 3127 case SCF_ERROR_NOT_SET: 3128 default: 3129 bad_error("scf_transaction_start", scf_error()); 3130 } 3131 } 3132 3133 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 3134 switch (r) { 3135 case 0: 3136 break; 3137 3138 case EINVAL: 3139 case ENOMEM: 3140 scf_transaction_destroy_children(imp_tx); 3141 return (r); 3142 3143 default: 3144 bad_error("add_upgrade_entries", r); 3145 } 3146 3147 r = scf_transaction_commit(imp_tx); 3148 3149 scf_transaction_destroy_children(imp_tx); 3150 3151 switch (r) { 3152 case 1: 3153 break; 3154 3155 case 0: 3156 return (EBUSY); 3157 3158 case -1: 3159 switch (scf_error()) { 3160 case SCF_ERROR_CONNECTION_BROKEN: 3161 case SCF_ERROR_NO_RESOURCES: 3162 case SCF_ERROR_PERMISSION_DENIED: 3163 case SCF_ERROR_BACKEND_READONLY: 3164 case SCF_ERROR_BACKEND_ACCESS: 3165 case SCF_ERROR_DELETED: 3166 return (scferror2errno(scf_error())); 3167 3168 case SCF_ERROR_NOT_BOUND: 3169 case SCF_ERROR_INVALID_ARGUMENT: 3170 case SCF_ERROR_NOT_SET: 3171 default: 3172 bad_error("scf_transaction_commit", scf_error()); 3173 } 3174 3175 default: 3176 bad_error("scf_transaction_commit", r); 3177 } 3178 3179 return (0); 3180 } 3181 3182 /* 3183 * Compares two entity FMRIs. Returns 3184 * 3185 * 1 - equal 3186 * 0 - not equal 3187 * -1 - f1 is invalid or not an entity 3188 * -2 - f2 is invalid or not an entity 3189 */ 3190 static int 3191 fmri_equal(const char *f1, const char *f2) 3192 { 3193 int r; 3194 const char *s1, *i1, *pg1; 3195 const char *s2, *i2, *pg2; 3196 3197 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3198 return (-1); 3199 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 3200 return (-1); 3201 3202 if (s1 == NULL || pg1 != NULL) 3203 return (-1); 3204 3205 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3206 return (-2); 3207 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 3208 return (-2); 3209 3210 if (s2 == NULL || pg2 != NULL) 3211 return (-2); 3212 3213 r = strcmp(s1, s2); 3214 if (r != 0) 3215 return (0); 3216 3217 if (i1 == NULL && i2 == NULL) 3218 return (1); 3219 3220 if (i1 == NULL || i2 == NULL) 3221 return (0); 3222 3223 return (strcmp(i1, i2) == 0); 3224 } 3225 3226 /* 3227 * Import a dependent by creating a dependency property group in the dependent 3228 * entity. If lcbdata->sc_trans is set, assume it's been started on the 3229 * dependents pg, and add an entry to create a new property for this 3230 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 3231 * 3232 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 3233 * lcbdata->sc_err to 3234 * ECONNABORTED - repository connection broken 3235 * ENOMEM - out of memory 3236 * ENOSPC - configd is out of resources 3237 * EINVAL - target is invalid (error printed) 3238 * - target is not an entity (error printed) 3239 * - dependent has invalid name (error printed) 3240 * - invalid property name (error printed) 3241 * - invalid value (error printed) 3242 * - scope of target does not exist (error printed) 3243 * EPERM - couldn't create target (permission denied) (error printed) 3244 * - couldn't create dependency pg (permission denied) (error printed) 3245 * - couldn't modify dependency pg (permission denied) (error printed) 3246 * EROFS - couldn't create target (repository read-only) 3247 * - couldn't create dependency pg (repository read-only) 3248 * EACCES - couldn't create target (backend access denied) 3249 * - couldn't create dependency pg (backend access denied) 3250 * ECANCELED - sc_trans's pg was deleted 3251 * EALREADY - property for dependent already exists in sc_trans's pg 3252 * EEXIST - dependency pg already exists in target (error printed) 3253 * EBUSY - target deleted (error printed) 3254 * - property group changed during import (error printed) 3255 */ 3256 static int 3257 lscf_dependent_import(void *a1, void *pvt) 3258 { 3259 pgroup_t *pgrp = a1; 3260 scf_callback_t *lcbdata = pvt; 3261 3262 int isservice; 3263 int ret; 3264 scf_transaction_entry_t *e; 3265 scf_value_t *val; 3266 scf_callback_t dependent_cbdata; 3267 scf_error_t scfe; 3268 3269 /* 3270 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 3271 * it's invalid, we fail before modifying the repository. 3272 */ 3273 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3274 &dependent_cbdata.sc_parent, &isservice); 3275 switch (scfe) { 3276 case SCF_ERROR_NONE: 3277 break; 3278 3279 case SCF_ERROR_NO_MEMORY: 3280 return (stash_scferror_err(lcbdata, scfe)); 3281 3282 case SCF_ERROR_INVALID_ARGUMENT: 3283 semerr(gettext("The FMRI for the \"%s\" dependent is " 3284 "invalid.\n"), pgrp->sc_pgroup_name); 3285 return (stash_scferror_err(lcbdata, scfe)); 3286 3287 case SCF_ERROR_CONSTRAINT_VIOLATED: 3288 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 3289 "specifies neither a service nor an instance.\n"), 3290 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3291 return (stash_scferror_err(lcbdata, scfe)); 3292 3293 case SCF_ERROR_NOT_FOUND: 3294 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3295 &dependent_cbdata.sc_parent, &isservice); 3296 switch (scfe) { 3297 case SCF_ERROR_NONE: 3298 break; 3299 3300 case SCF_ERROR_NO_MEMORY: 3301 case SCF_ERROR_BACKEND_READONLY: 3302 case SCF_ERROR_BACKEND_ACCESS: 3303 return (stash_scferror_err(lcbdata, scfe)); 3304 3305 case SCF_ERROR_NOT_FOUND: 3306 semerr(gettext("The scope in FMRI \"%s\" for the " 3307 "\"%s\" dependent does not exist.\n"), 3308 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3309 lcbdata->sc_err = EINVAL; 3310 return (UU_WALK_ERROR); 3311 3312 case SCF_ERROR_PERMISSION_DENIED: 3313 warn(gettext( 3314 "Could not create %s (permission denied).\n"), 3315 pgrp->sc_pgroup_fmri); 3316 return (stash_scferror_err(lcbdata, scfe)); 3317 3318 case SCF_ERROR_INVALID_ARGUMENT: 3319 case SCF_ERROR_CONSTRAINT_VIOLATED: 3320 default: 3321 bad_error("create_entity", scfe); 3322 } 3323 break; 3324 3325 default: 3326 bad_error("fmri_to_entity", scfe); 3327 } 3328 3329 if (lcbdata->sc_trans != NULL) { 3330 e = scf_entry_create(lcbdata->sc_handle); 3331 if (e == NULL) { 3332 if (scf_error() != SCF_ERROR_NO_MEMORY) 3333 bad_error("scf_entry_create", scf_error()); 3334 3335 entity_destroy(dependent_cbdata.sc_parent, isservice); 3336 return (stash_scferror(lcbdata)); 3337 } 3338 3339 if (scf_transaction_property_new(lcbdata->sc_trans, e, 3340 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 3341 switch (scf_error()) { 3342 case SCF_ERROR_INVALID_ARGUMENT: 3343 warn(gettext("Dependent of %s has invalid name " 3344 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 3345 pgrp->sc_pgroup_name); 3346 /* FALLTHROUGH */ 3347 3348 case SCF_ERROR_DELETED: 3349 case SCF_ERROR_CONNECTION_BROKEN: 3350 scf_entry_destroy(e); 3351 entity_destroy(dependent_cbdata.sc_parent, 3352 isservice); 3353 return (stash_scferror(lcbdata)); 3354 3355 case SCF_ERROR_EXISTS: 3356 scf_entry_destroy(e); 3357 entity_destroy(dependent_cbdata.sc_parent, 3358 isservice); 3359 lcbdata->sc_err = EALREADY; 3360 return (UU_WALK_ERROR); 3361 3362 case SCF_ERROR_NOT_BOUND: 3363 case SCF_ERROR_HANDLE_MISMATCH: 3364 case SCF_ERROR_NOT_SET: 3365 default: 3366 bad_error("scf_transaction_property_new", 3367 scf_error()); 3368 } 3369 } 3370 3371 val = scf_value_create(lcbdata->sc_handle); 3372 if (val == NULL) { 3373 if (scf_error() != SCF_ERROR_NO_MEMORY) 3374 bad_error("scf_value_create", scf_error()); 3375 3376 entity_destroy(dependent_cbdata.sc_parent, isservice); 3377 return (stash_scferror(lcbdata)); 3378 } 3379 3380 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3381 pgrp->sc_pgroup_fmri) != 0) 3382 /* invalid should have been caught above */ 3383 bad_error("scf_value_set_from_string", scf_error()); 3384 3385 if (scf_entry_add_value(e, val) != 0) 3386 bad_error("scf_entry_add_value", scf_error()); 3387 } 3388 3389 /* Add the property group to the target entity. */ 3390 3391 dependent_cbdata.sc_handle = lcbdata->sc_handle; 3392 dependent_cbdata.sc_flags = lcbdata->sc_flags; 3393 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 3394 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 3395 3396 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 3397 3398 entity_destroy(dependent_cbdata.sc_parent, isservice); 3399 3400 if (ret == UU_WALK_NEXT) 3401 return (ret); 3402 3403 if (ret != UU_WALK_ERROR) 3404 bad_error("entity_pgroup_import", ret); 3405 3406 switch (dependent_cbdata.sc_err) { 3407 case ECANCELED: 3408 warn(gettext("%s deleted unexpectedly.\n"), 3409 pgrp->sc_pgroup_fmri); 3410 lcbdata->sc_err = EBUSY; 3411 break; 3412 3413 case EEXIST: 3414 warn(gettext("Could not create \"%s\" dependency in %s " 3415 "(already exists).\n"), pgrp->sc_pgroup_name, 3416 pgrp->sc_pgroup_fmri); 3417 /* FALLTHROUGH */ 3418 3419 default: 3420 lcbdata->sc_err = dependent_cbdata.sc_err; 3421 } 3422 3423 return (UU_WALK_ERROR); 3424 } 3425 3426 static int upgrade_dependent(const scf_property_t *, const entity_t *, 3427 const scf_snaplevel_t *, scf_transaction_t *); 3428 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 3429 const pgroup_t *); 3430 3431 /* 3432 * Upgrade uncustomized dependents of ent to those specified in ient. Read 3433 * the current dependent targets from running (the snaplevel of a running 3434 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 3435 * scf_instance_t * according to ient, otherwise). Draw the ancestral 3436 * dependent targets and dependency properties from li_dpts_pg (the 3437 * "dependents" property group in snpl) and snpl (the snaplevel which 3438 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 3439 * snpl doesn't have a "dependents" property group, and any dependents in ient 3440 * are new. 3441 * 3442 * Returns 3443 * 0 - success 3444 * ECONNABORTED - repository connection broken 3445 * ENOMEM - out of memory 3446 * ENOSPC - configd is out of resources 3447 * ECANCELED - ent was deleted 3448 * ENODEV - the entity containing li_dpts_pg was deleted 3449 * EPERM - could not modify dependents pg (permission denied) (error printed) 3450 * - couldn't upgrade dependent (permission denied) (error printed) 3451 * - couldn't create dependent (permission denied) (error printed) 3452 * EROFS - could not modify dependents pg (repository read-only) 3453 * - couldn't upgrade dependent (repository read-only) 3454 * - couldn't create dependent (repository read-only) 3455 * EACCES - could not modify dependents pg (backend access denied) 3456 * - could not upgrade dependent (backend access denied) 3457 * - could not create dependent (backend access denied) 3458 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 3459 * - dependent target deleted (error printed) 3460 * - dependent pg changed (error printed) 3461 * EINVAL - new dependent is invalid (error printed) 3462 * EBADF - snpl is corrupt (error printed) 3463 * - snpl has corrupt pg (error printed) 3464 * - dependency pg in target is corrupt (error printed) 3465 * - target has corrupt snapshot (error printed) 3466 * EEXIST - dependency pg already existed in target service (error printed) 3467 */ 3468 static int 3469 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 3470 const scf_snaplevel_t *snpl, const entity_t *ient, 3471 const scf_snaplevel_t *running, void *ent) 3472 { 3473 pgroup_t *new_dpt_pgroup; 3474 scf_callback_t cbdata; 3475 int r, unseen, tx_started = 0; 3476 int have_cur_depts; 3477 3478 const char * const dependents = "dependents"; 3479 3480 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3481 3482 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 3483 /* Nothing to do. */ 3484 return (0); 3485 3486 /* Fetch the current version of the "dependents" property group. */ 3487 have_cur_depts = 1; 3488 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 3489 switch (scf_error()) { 3490 case SCF_ERROR_NOT_FOUND: 3491 break; 3492 3493 case SCF_ERROR_DELETED: 3494 case SCF_ERROR_CONNECTION_BROKEN: 3495 return (scferror2errno(scf_error())); 3496 3497 case SCF_ERROR_NOT_SET: 3498 case SCF_ERROR_INVALID_ARGUMENT: 3499 case SCF_ERROR_HANDLE_MISMATCH: 3500 case SCF_ERROR_NOT_BOUND: 3501 default: 3502 bad_error("entity_get_pg", scf_error()); 3503 } 3504 3505 have_cur_depts = 0; 3506 } 3507 3508 /* Fetch the running version of the "dependents" property group. */ 3509 ud_run_dpts_pg_set = 0; 3510 if (running != NULL) 3511 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 3512 else 3513 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 3514 if (r == 0) { 3515 ud_run_dpts_pg_set = 1; 3516 } else { 3517 switch (scf_error()) { 3518 case SCF_ERROR_NOT_FOUND: 3519 break; 3520 3521 case SCF_ERROR_DELETED: 3522 case SCF_ERROR_CONNECTION_BROKEN: 3523 return (scferror2errno(scf_error())); 3524 3525 case SCF_ERROR_NOT_SET: 3526 case SCF_ERROR_INVALID_ARGUMENT: 3527 case SCF_ERROR_HANDLE_MISMATCH: 3528 case SCF_ERROR_NOT_BOUND: 3529 default: 3530 bad_error(running ? "scf_snaplevel_get_pg" : 3531 "entity_get_pg", scf_error()); 3532 } 3533 } 3534 3535 /* 3536 * Clear the seen fields of the dependents, so we can tell which ones 3537 * are new. 3538 */ 3539 if (uu_list_walk(ient->sc_dependents, clear_int, 3540 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3541 bad_error("uu_list_walk", uu_error()); 3542 3543 if (li_dpts_pg != NULL) { 3544 /* 3545 * Each property in li_dpts_pg represents a dependent tag in 3546 * the old manifest. For each, call upgrade_dependent(), 3547 * which will change ud_cur_depts_pg or dependencies in other 3548 * services as appropriate. Note (a) that changes to 3549 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3550 * made en masse, and (b) it's ok if the entity doesn't have 3551 * a current version of the "dependents" property group, 3552 * because we'll just consider all dependents as customized 3553 * (by being deleted). 3554 */ 3555 3556 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3557 switch (scf_error()) { 3558 case SCF_ERROR_DELETED: 3559 return (ENODEV); 3560 3561 case SCF_ERROR_CONNECTION_BROKEN: 3562 return (ECONNABORTED); 3563 3564 case SCF_ERROR_HANDLE_MISMATCH: 3565 case SCF_ERROR_NOT_BOUND: 3566 case SCF_ERROR_NOT_SET: 3567 default: 3568 bad_error("scf_iter_pg_properties", 3569 scf_error()); 3570 } 3571 } 3572 3573 if (have_cur_depts && 3574 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3575 switch (scf_error()) { 3576 case SCF_ERROR_BACKEND_ACCESS: 3577 case SCF_ERROR_BACKEND_READONLY: 3578 case SCF_ERROR_CONNECTION_BROKEN: 3579 return (scferror2errno(scf_error())); 3580 3581 case SCF_ERROR_DELETED: 3582 warn(emsg_pg_deleted, ient->sc_fmri, 3583 dependents); 3584 return (EBUSY); 3585 3586 case SCF_ERROR_PERMISSION_DENIED: 3587 warn(emsg_pg_mod_perm, dependents, 3588 ient->sc_fmri); 3589 return (scferror2errno(scf_error())); 3590 3591 case SCF_ERROR_HANDLE_MISMATCH: 3592 case SCF_ERROR_IN_USE: 3593 case SCF_ERROR_NOT_BOUND: 3594 case SCF_ERROR_NOT_SET: 3595 default: 3596 bad_error("scf_transaction_start", scf_error()); 3597 } 3598 } 3599 tx_started = have_cur_depts; 3600 3601 for (;;) { 3602 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3603 if (r == 0) 3604 break; 3605 if (r == 1) { 3606 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3607 tx_started ? ud_tx : NULL); 3608 switch (r) { 3609 case 0: 3610 continue; 3611 3612 case ECONNABORTED: 3613 case ENOMEM: 3614 case ENOSPC: 3615 case EBADF: 3616 case EBUSY: 3617 case EINVAL: 3618 case EPERM: 3619 case EROFS: 3620 case EACCES: 3621 case EEXIST: 3622 break; 3623 3624 case ECANCELED: 3625 r = ENODEV; 3626 break; 3627 3628 default: 3629 bad_error("upgrade_dependent", r); 3630 } 3631 3632 if (tx_started) 3633 scf_transaction_destroy_children(ud_tx); 3634 return (r); 3635 } 3636 if (r != -1) 3637 bad_error("scf_iter_next_property", r); 3638 3639 switch (scf_error()) { 3640 case SCF_ERROR_DELETED: 3641 r = ENODEV; 3642 break; 3643 3644 case SCF_ERROR_CONNECTION_BROKEN: 3645 r = ECONNABORTED; 3646 break; 3647 3648 case SCF_ERROR_NOT_SET: 3649 case SCF_ERROR_INVALID_ARGUMENT: 3650 case SCF_ERROR_NOT_BOUND: 3651 case SCF_ERROR_HANDLE_MISMATCH: 3652 default: 3653 bad_error("scf_iter_next_property", 3654 scf_error()); 3655 } 3656 3657 if (tx_started) 3658 scf_transaction_destroy_children(ud_tx); 3659 return (r); 3660 } 3661 } 3662 3663 /* import unseen dependents */ 3664 unseen = 0; 3665 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3666 new_dpt_pgroup != NULL; 3667 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3668 new_dpt_pgroup)) { 3669 if (!new_dpt_pgroup->sc_pgroup_seen) { 3670 unseen = 1; 3671 break; 3672 } 3673 } 3674 3675 /* If there are none, exit early. */ 3676 if (unseen == 0) 3677 goto commit; 3678 3679 /* Set up for lscf_dependent_import() */ 3680 cbdata.sc_handle = g_hndl; 3681 cbdata.sc_parent = ent; 3682 cbdata.sc_service = issvc; 3683 cbdata.sc_flags = 0; 3684 3685 if (!have_cur_depts) { 3686 /* 3687 * We have new dependents to import, so we need a "dependents" 3688 * property group. 3689 */ 3690 if (issvc) 3691 r = scf_service_add_pg(ent, dependents, 3692 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3693 else 3694 r = scf_instance_add_pg(ent, dependents, 3695 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3696 if (r != 0) { 3697 switch (scf_error()) { 3698 case SCF_ERROR_DELETED: 3699 case SCF_ERROR_CONNECTION_BROKEN: 3700 case SCF_ERROR_BACKEND_READONLY: 3701 case SCF_ERROR_BACKEND_ACCESS: 3702 case SCF_ERROR_NO_RESOURCES: 3703 return (scferror2errno(scf_error())); 3704 3705 case SCF_ERROR_EXISTS: 3706 warn(emsg_pg_added, ient->sc_fmri, dependents); 3707 return (EBUSY); 3708 3709 case SCF_ERROR_PERMISSION_DENIED: 3710 warn(emsg_pg_add_perm, dependents, 3711 ient->sc_fmri); 3712 return (scferror2errno(scf_error())); 3713 3714 case SCF_ERROR_NOT_BOUND: 3715 case SCF_ERROR_HANDLE_MISMATCH: 3716 case SCF_ERROR_INVALID_ARGUMENT: 3717 case SCF_ERROR_NOT_SET: 3718 default: 3719 bad_error("scf_service_add_pg", scf_error()); 3720 } 3721 } 3722 } 3723 3724 cbdata.sc_trans = ud_tx; 3725 3726 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3727 switch (scf_error()) { 3728 case SCF_ERROR_CONNECTION_BROKEN: 3729 case SCF_ERROR_BACKEND_ACCESS: 3730 case SCF_ERROR_BACKEND_READONLY: 3731 return (scferror2errno(scf_error())); 3732 3733 case SCF_ERROR_DELETED: 3734 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3735 return (EBUSY); 3736 3737 case SCF_ERROR_PERMISSION_DENIED: 3738 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3739 return (scferror2errno(scf_error())); 3740 3741 case SCF_ERROR_HANDLE_MISMATCH: 3742 case SCF_ERROR_IN_USE: 3743 case SCF_ERROR_NOT_BOUND: 3744 case SCF_ERROR_NOT_SET: 3745 default: 3746 bad_error("scf_transaction_start", scf_error()); 3747 } 3748 } 3749 tx_started = 1; 3750 3751 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3752 new_dpt_pgroup != NULL; 3753 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3754 new_dpt_pgroup)) { 3755 if (new_dpt_pgroup->sc_pgroup_seen) 3756 continue; 3757 3758 if (ud_run_dpts_pg_set) { 3759 /* 3760 * If the dependent is already there, then we have 3761 * a conflict. 3762 */ 3763 if (scf_pg_get_property(ud_run_dpts_pg, 3764 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3765 r = handle_dependent_conflict(ient, ud_prop, 3766 new_dpt_pgroup); 3767 switch (r) { 3768 case 0: 3769 continue; 3770 3771 case ECONNABORTED: 3772 case ENOMEM: 3773 case EBUSY: 3774 case EBADF: 3775 case EINVAL: 3776 scf_transaction_destroy_children(ud_tx); 3777 return (r); 3778 3779 default: 3780 bad_error("handle_dependent_conflict", 3781 r); 3782 } 3783 } else { 3784 switch (scf_error()) { 3785 case SCF_ERROR_NOT_FOUND: 3786 break; 3787 3788 case SCF_ERROR_INVALID_ARGUMENT: 3789 warn(emsg_fmri_invalid_pg_name, 3790 ient->sc_fmri, 3791 new_dpt_pgroup->sc_pgroup_name); 3792 scf_transaction_destroy_children(ud_tx); 3793 return (EINVAL); 3794 3795 case SCF_ERROR_DELETED: 3796 warn(emsg_pg_deleted, ient->sc_fmri, 3797 new_dpt_pgroup->sc_pgroup_name); 3798 scf_transaction_destroy_children(ud_tx); 3799 return (EBUSY); 3800 3801 case SCF_ERROR_CONNECTION_BROKEN: 3802 scf_transaction_destroy_children(ud_tx); 3803 return (ECONNABORTED); 3804 3805 case SCF_ERROR_NOT_BOUND: 3806 case SCF_ERROR_HANDLE_MISMATCH: 3807 case SCF_ERROR_NOT_SET: 3808 default: 3809 bad_error("scf_pg_get_property", 3810 scf_error()); 3811 } 3812 } 3813 } 3814 3815 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3816 if (r != UU_WALK_NEXT) { 3817 if (r != UU_WALK_ERROR) 3818 bad_error("lscf_dependent_import", r); 3819 3820 if (cbdata.sc_err == EALREADY) { 3821 /* Collisions were handled preemptively. */ 3822 bad_error("lscf_dependent_import", 3823 cbdata.sc_err); 3824 } 3825 3826 scf_transaction_destroy_children(ud_tx); 3827 return (cbdata.sc_err); 3828 } 3829 } 3830 3831 commit: 3832 if (!tx_started) 3833 return (0); 3834 3835 r = scf_transaction_commit(ud_tx); 3836 3837 scf_transaction_destroy_children(ud_tx); 3838 3839 switch (r) { 3840 case 1: 3841 return (0); 3842 3843 case 0: 3844 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3845 return (EBUSY); 3846 3847 case -1: 3848 break; 3849 3850 default: 3851 bad_error("scf_transaction_commit", r); 3852 } 3853 3854 switch (scf_error()) { 3855 case SCF_ERROR_CONNECTION_BROKEN: 3856 case SCF_ERROR_BACKEND_READONLY: 3857 case SCF_ERROR_BACKEND_ACCESS: 3858 case SCF_ERROR_NO_RESOURCES: 3859 return (scferror2errno(scf_error())); 3860 3861 case SCF_ERROR_DELETED: 3862 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3863 return (EBUSY); 3864 3865 case SCF_ERROR_PERMISSION_DENIED: 3866 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3867 return (scferror2errno(scf_error())); 3868 3869 case SCF_ERROR_NOT_BOUND: 3870 case SCF_ERROR_INVALID_ARGUMENT: 3871 case SCF_ERROR_NOT_SET: 3872 default: 3873 bad_error("scf_transaction_destroy", scf_error()); 3874 /* NOTREACHED */ 3875 } 3876 } 3877 3878 /* 3879 * Used to add the manifests to the list of currently supported manifests. 3880 * We can modify the existing manifest list removing entries if the files 3881 * don't exist. 3882 * 3883 * Get the old list and the new file name 3884 * If the new file name is in the list return 3885 * If not then add the file to the list. 3886 * As we process the list check to see if the files in the old list exist 3887 * if not then remove the file from the list. 3888 * Commit the list of manifest file names. 3889 * 3890 */ 3891 static int 3892 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient, 3893 const scf_snaplevel_t *running, void *ent) 3894 { 3895 scf_propertygroup_t *ud_mfsts_pg = NULL; 3896 scf_property_t *ud_prop = NULL; 3897 scf_iter_t *ud_prop_iter; 3898 scf_value_t *fname_value; 3899 scf_callback_t cbdata; 3900 pgroup_t *mfst_pgroup; 3901 property_t *mfst_prop; 3902 property_t *old_prop; 3903 char *pname = malloc(MAXPATHLEN); 3904 char *fval = NULL; 3905 char *old_pname; 3906 char *old_fval; 3907 int no_upgrade_pg; 3908 int mfst_seen; 3909 int r; 3910 3911 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3912 3913 /* 3914 * This should always be the service base on the code 3915 * path, and the fact that the manifests pg is a service 3916 * level property group only. 3917 */ 3918 ud_mfsts_pg = scf_pg_create(g_hndl); 3919 ud_prop = scf_property_create(g_hndl); 3920 ud_prop_iter = scf_iter_create(g_hndl); 3921 fname_value = scf_value_create(g_hndl); 3922 3923 /* Fetch the "manifests" property group */ 3924 no_upgrade_pg = 0; 3925 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3926 ud_mfsts_pg); 3927 if (r != 0) { 3928 switch (scf_error()) { 3929 case SCF_ERROR_NOT_FOUND: 3930 no_upgrade_pg = 1; 3931 break; 3932 3933 case SCF_ERROR_DELETED: 3934 case SCF_ERROR_CONNECTION_BROKEN: 3935 return (scferror2errno(scf_error())); 3936 3937 case SCF_ERROR_NOT_SET: 3938 case SCF_ERROR_INVALID_ARGUMENT: 3939 case SCF_ERROR_HANDLE_MISMATCH: 3940 case SCF_ERROR_NOT_BOUND: 3941 default: 3942 bad_error(running ? "scf_snaplevel_get_pg" : 3943 "entity_get_pg", scf_error()); 3944 } 3945 } 3946 3947 if (no_upgrade_pg) { 3948 cbdata.sc_handle = g_hndl; 3949 cbdata.sc_parent = ent; 3950 cbdata.sc_service = issvc; 3951 cbdata.sc_flags = SCI_FORCE; 3952 cbdata.sc_source_fmri = ient->sc_fmri; 3953 cbdata.sc_target_fmri = ient->sc_fmri; 3954 3955 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3956 return (cbdata.sc_err); 3957 3958 return (0); 3959 } 3960 3961 /* Fetch the new manifests property group */ 3962 for (mfst_pgroup = uu_list_first(ient->sc_pgroups); 3963 mfst_pgroup != NULL; 3964 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) { 3965 if (strcmp(mfst_pgroup->sc_pgroup_name, 3966 SCF_PG_MANIFESTFILES) == 0) 3967 break; 3968 } 3969 3970 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3971 SCF_SUCCESS) 3972 return (-1); 3973 3974 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 3975 mfst_seen = 0; 3976 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 3977 continue; 3978 3979 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3980 mfst_prop != NULL; 3981 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3982 mfst_prop)) { 3983 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3984 mfst_seen = 1; 3985 } 3986 } 3987 3988 /* 3989 * If the manifest is not seen then add it to the new mfst 3990 * property list to get proccessed into the repo. 3991 */ 3992 if (mfst_seen == 0) { 3993 if (fval == NULL) 3994 fval = malloc(MAXPATHLEN); 3995 3996 /* 3997 * If we cannot get the value then there is no 3998 * reason to attempt to attach the value to 3999 * the property group 4000 */ 4001 if (fval != NULL && 4002 prop_get_val(ud_prop, fname_value) == 0 && 4003 scf_value_get_astring(fname_value, fval, 4004 MAXPATHLEN) != -1) { 4005 old_pname = safe_strdup(pname); 4006 old_fval = safe_strdup(fval); 4007 old_prop = internal_property_create(old_pname, 4008 SCF_TYPE_ASTRING, 1, old_fval); 4009 4010 /* 4011 * Already checked to see if the property exists 4012 * in the group, and it does not. 4013 */ 4014 (void) internal_attach_property(mfst_pgroup, 4015 old_prop); 4016 } 4017 } 4018 } 4019 free(fval); 4020 4021 cbdata.sc_handle = g_hndl; 4022 cbdata.sc_parent = ent; 4023 cbdata.sc_service = issvc; 4024 cbdata.sc_flags = SCI_FORCE; 4025 cbdata.sc_source_fmri = ient->sc_fmri; 4026 cbdata.sc_target_fmri = ient->sc_fmri; 4027 4028 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 4029 return (cbdata.sc_err); 4030 4031 return (r); 4032 } 4033 4034 /* 4035 * prop is taken to be a property in the "dependents" property group of snpl, 4036 * which is taken to be the snaplevel of a last-import snapshot corresponding 4037 * to ient. If prop is a valid dependents property, upgrade the dependent it 4038 * represents according to the repository & ient. If ud_run_dpts_pg_set is 4039 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 4040 * of the entity ient represents (possibly in the running snapshot). If it 4041 * needs to be changed, an entry will be added to tx, if not NULL. 4042 * 4043 * Returns 4044 * 0 - success 4045 * ECONNABORTED - repository connection broken 4046 * ENOMEM - out of memory 4047 * ENOSPC - configd was out of resources 4048 * ECANCELED - snpl's entity was deleted 4049 * EINVAL - dependent target is invalid (error printed) 4050 * - dependent is invalid (error printed) 4051 * EBADF - snpl is corrupt (error printed) 4052 * - snpl has corrupt pg (error printed) 4053 * - dependency pg in target is corrupt (error printed) 4054 * - running snapshot in dependent is missing snaplevel (error printed) 4055 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 4056 * - couldn't create dependent (permission denied) (error printed) 4057 * - couldn't modify dependent pg (permission denied) (error printed) 4058 * EROFS - couldn't delete dependency pg (repository read-only) 4059 * - couldn't create dependent (repository read-only) 4060 * EACCES - couldn't delete dependency pg (backend access denied) 4061 * - couldn't create dependent (backend access denied) 4062 * EBUSY - ud_run_dpts_pg was deleted (error printed) 4063 * - tx's pg was deleted (error printed) 4064 * - dependent pg was changed or deleted (error printed) 4065 * EEXIST - dependency pg already exists in new target (error printed) 4066 */ 4067 static int 4068 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 4069 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 4070 { 4071 pgroup_t pgrp; 4072 scf_type_t ty; 4073 pgroup_t *new_dpt_pgroup; 4074 pgroup_t *old_dpt_pgroup = NULL; 4075 pgroup_t *current_pg; 4076 pgroup_t *dpt; 4077 scf_callback_t cbdata; 4078 int tissvc; 4079 void *target_ent; 4080 scf_error_t serr; 4081 int r; 4082 scf_transaction_entry_t *ent; 4083 4084 const char * const cf_inval = gettext("Conflict upgrading %s " 4085 "(dependent \"%s\" has invalid dependents property).\n"); 4086 const char * const cf_missing = gettext("Conflict upgrading %s " 4087 "(dependent \"%s\" is missing).\n"); 4088 const char * const cf_newdpg = gettext("Conflict upgrading %s " 4089 "(dependent \"%s\" has new dependency property group).\n"); 4090 const char * const cf_newtarg = gettext("Conflict upgrading %s " 4091 "(dependent \"%s\" has new target).\n"); 4092 const char * const li_corrupt = 4093 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 4094 const char * const upgrading = 4095 gettext("%s: Upgrading dependent \"%s\".\n"); 4096 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 4097 "corrupt (missing snaplevel).\n"); 4098 4099 if (scf_property_type(prop, &ty) != 0) { 4100 switch (scf_error()) { 4101 case SCF_ERROR_DELETED: 4102 case SCF_ERROR_CONNECTION_BROKEN: 4103 return (scferror2errno(scf_error())); 4104 4105 case SCF_ERROR_NOT_BOUND: 4106 case SCF_ERROR_NOT_SET: 4107 default: 4108 bad_error("scf_property_type", scf_error()); 4109 } 4110 } 4111 4112 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4113 warn(li_corrupt, ient->sc_fmri); 4114 return (EBADF); 4115 } 4116 4117 /* 4118 * prop represents a dependent in the old manifest. It is named after 4119 * the dependent. 4120 */ 4121 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 4122 switch (scf_error()) { 4123 case SCF_ERROR_DELETED: 4124 case SCF_ERROR_CONNECTION_BROKEN: 4125 return (scferror2errno(scf_error())); 4126 4127 case SCF_ERROR_NOT_BOUND: 4128 case SCF_ERROR_NOT_SET: 4129 default: 4130 bad_error("scf_property_get_name", scf_error()); 4131 } 4132 } 4133 4134 /* See if it's in the new manifest. */ 4135 pgrp.sc_pgroup_name = ud_name; 4136 new_dpt_pgroup = 4137 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 4138 4139 /* If it's not, delete it... if it hasn't been customized. */ 4140 if (new_dpt_pgroup == NULL) { 4141 if (!ud_run_dpts_pg_set) 4142 return (0); 4143 4144 if (scf_property_get_value(prop, ud_val) != 0) { 4145 switch (scf_error()) { 4146 case SCF_ERROR_NOT_FOUND: 4147 case SCF_ERROR_CONSTRAINT_VIOLATED: 4148 warn(li_corrupt, ient->sc_fmri); 4149 return (EBADF); 4150 4151 case SCF_ERROR_DELETED: 4152 case SCF_ERROR_CONNECTION_BROKEN: 4153 return (scferror2errno(scf_error())); 4154 4155 case SCF_ERROR_HANDLE_MISMATCH: 4156 case SCF_ERROR_NOT_BOUND: 4157 case SCF_ERROR_NOT_SET: 4158 case SCF_ERROR_PERMISSION_DENIED: 4159 default: 4160 bad_error("scf_property_get_value", 4161 scf_error()); 4162 } 4163 } 4164 4165 if (scf_value_get_as_string(ud_val, ud_oldtarg, 4166 max_scf_value_len + 1) < 0) 4167 bad_error("scf_value_get_as_string", scf_error()); 4168 4169 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 4170 0) { 4171 switch (scf_error()) { 4172 case SCF_ERROR_NOT_FOUND: 4173 return (0); 4174 4175 case SCF_ERROR_CONNECTION_BROKEN: 4176 return (scferror2errno(scf_error())); 4177 4178 case SCF_ERROR_DELETED: 4179 warn(emsg_pg_deleted, ient->sc_fmri, 4180 "dependents"); 4181 return (EBUSY); 4182 4183 case SCF_ERROR_INVALID_ARGUMENT: 4184 case SCF_ERROR_NOT_BOUND: 4185 case SCF_ERROR_HANDLE_MISMATCH: 4186 case SCF_ERROR_NOT_SET: 4187 default: 4188 bad_error("scf_pg_get_property", scf_error()); 4189 } 4190 } 4191 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4192 switch (scf_error()) { 4193 case SCF_ERROR_NOT_FOUND: 4194 case SCF_ERROR_CONSTRAINT_VIOLATED: 4195 warn(cf_inval, ient->sc_fmri, ud_name); 4196 return (0); 4197 4198 case SCF_ERROR_DELETED: 4199 case SCF_ERROR_CONNECTION_BROKEN: 4200 return (scferror2errno(scf_error())); 4201 4202 case SCF_ERROR_HANDLE_MISMATCH: 4203 case SCF_ERROR_NOT_BOUND: 4204 case SCF_ERROR_NOT_SET: 4205 case SCF_ERROR_PERMISSION_DENIED: 4206 default: 4207 bad_error("scf_property_get_value", 4208 scf_error()); 4209 } 4210 } 4211 4212 ty = scf_value_type(ud_val); 4213 assert(ty != SCF_TYPE_INVALID); 4214 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4215 warn(cf_inval, ient->sc_fmri, ud_name); 4216 return (0); 4217 } 4218 4219 if (scf_value_get_as_string(ud_val, ud_ctarg, 4220 max_scf_value_len + 1) < 0) 4221 bad_error("scf_value_get_as_string", scf_error()); 4222 4223 r = fmri_equal(ud_ctarg, ud_oldtarg); 4224 switch (r) { 4225 case 1: 4226 break; 4227 4228 case 0: 4229 case -1: /* warn? */ 4230 warn(cf_newtarg, ient->sc_fmri, ud_name); 4231 return (0); 4232 4233 case -2: 4234 warn(li_corrupt, ient->sc_fmri); 4235 return (EBADF); 4236 4237 default: 4238 bad_error("fmri_equal", r); 4239 } 4240 4241 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4242 switch (scf_error()) { 4243 case SCF_ERROR_NOT_FOUND: 4244 warn(li_corrupt, ient->sc_fmri); 4245 return (EBADF); 4246 4247 case SCF_ERROR_DELETED: 4248 case SCF_ERROR_CONNECTION_BROKEN: 4249 return (scferror2errno(scf_error())); 4250 4251 case SCF_ERROR_NOT_BOUND: 4252 case SCF_ERROR_HANDLE_MISMATCH: 4253 case SCF_ERROR_INVALID_ARGUMENT: 4254 case SCF_ERROR_NOT_SET: 4255 default: 4256 bad_error("scf_snaplevel_get_pg", scf_error()); 4257 } 4258 } 4259 4260 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4261 snap_lastimport); 4262 switch (r) { 4263 case 0: 4264 break; 4265 4266 case ECANCELED: 4267 case ECONNABORTED: 4268 case ENOMEM: 4269 case EBADF: 4270 return (r); 4271 4272 case EACCES: 4273 default: 4274 bad_error("load_pg", r); 4275 } 4276 4277 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4278 switch (serr) { 4279 case SCF_ERROR_NONE: 4280 break; 4281 4282 case SCF_ERROR_NO_MEMORY: 4283 internal_pgroup_free(old_dpt_pgroup); 4284 return (ENOMEM); 4285 4286 case SCF_ERROR_NOT_FOUND: 4287 internal_pgroup_free(old_dpt_pgroup); 4288 goto delprop; 4289 4290 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 4291 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 4292 default: 4293 bad_error("fmri_to_entity", serr); 4294 } 4295 4296 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4297 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4298 switch (r) { 4299 case 0: 4300 break; 4301 4302 case ECONNABORTED: 4303 internal_pgroup_free(old_dpt_pgroup); 4304 return (r); 4305 4306 case ECANCELED: 4307 case ENOENT: 4308 internal_pgroup_free(old_dpt_pgroup); 4309 goto delprop; 4310 4311 case EBADF: 4312 warn(r_no_lvl, ud_ctarg); 4313 internal_pgroup_free(old_dpt_pgroup); 4314 return (r); 4315 4316 case EINVAL: 4317 default: 4318 bad_error("entity_get_running_pg", r); 4319 } 4320 4321 /* load it */ 4322 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4323 switch (r) { 4324 case 0: 4325 break; 4326 4327 case ECANCELED: 4328 internal_pgroup_free(old_dpt_pgroup); 4329 goto delprop; 4330 4331 case ECONNABORTED: 4332 case ENOMEM: 4333 case EBADF: 4334 internal_pgroup_free(old_dpt_pgroup); 4335 return (r); 4336 4337 case EACCES: 4338 default: 4339 bad_error("load_pg", r); 4340 } 4341 4342 /* compare property groups */ 4343 if (!pg_equal(old_dpt_pgroup, current_pg)) { 4344 warn(cf_newdpg, ient->sc_fmri, ud_name); 4345 internal_pgroup_free(old_dpt_pgroup); 4346 internal_pgroup_free(current_pg); 4347 return (0); 4348 } 4349 4350 internal_pgroup_free(old_dpt_pgroup); 4351 internal_pgroup_free(current_pg); 4352 4353 if (g_verbose) 4354 warn(gettext("%s: Deleting dependent \"%s\".\n"), 4355 ient->sc_fmri, ud_name); 4356 4357 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4358 switch (scf_error()) { 4359 case SCF_ERROR_NOT_FOUND: 4360 case SCF_ERROR_DELETED: 4361 internal_pgroup_free(old_dpt_pgroup); 4362 goto delprop; 4363 4364 case SCF_ERROR_CONNECTION_BROKEN: 4365 internal_pgroup_free(old_dpt_pgroup); 4366 return (ECONNABORTED); 4367 4368 case SCF_ERROR_NOT_SET: 4369 case SCF_ERROR_INVALID_ARGUMENT: 4370 case SCF_ERROR_HANDLE_MISMATCH: 4371 case SCF_ERROR_NOT_BOUND: 4372 default: 4373 bad_error("entity_get_pg", scf_error()); 4374 } 4375 } 4376 4377 if (scf_pg_delete(ud_pg) != 0) { 4378 switch (scf_error()) { 4379 case SCF_ERROR_DELETED: 4380 break; 4381 4382 case SCF_ERROR_CONNECTION_BROKEN: 4383 case SCF_ERROR_BACKEND_READONLY: 4384 case SCF_ERROR_BACKEND_ACCESS: 4385 return (scferror2errno(scf_error())); 4386 4387 case SCF_ERROR_PERMISSION_DENIED: 4388 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4389 return (scferror2errno(scf_error())); 4390 4391 case SCF_ERROR_NOT_SET: 4392 default: 4393 bad_error("scf_pg_delete", scf_error()); 4394 } 4395 } 4396 4397 /* 4398 * This service was changed, so it must be refreshed. But 4399 * since it's not mentioned in the new manifest, we have to 4400 * record its FMRI here for use later. We record the name 4401 * & the entity (via sc_parent) in case we need to print error 4402 * messages during the refresh. 4403 */ 4404 dpt = internal_pgroup_new(); 4405 if (dpt == NULL) 4406 return (ENOMEM); 4407 dpt->sc_pgroup_name = strdup(ud_name); 4408 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 4409 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4410 return (ENOMEM); 4411 dpt->sc_parent = (entity_t *)ient; 4412 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4413 uu_die(gettext("libuutil error: %s\n"), 4414 uu_strerror(uu_error())); 4415 4416 delprop: 4417 if (tx == NULL) 4418 return (0); 4419 4420 ent = scf_entry_create(g_hndl); 4421 if (ent == NULL) 4422 return (ENOMEM); 4423 4424 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 4425 scf_entry_destroy(ent); 4426 switch (scf_error()) { 4427 case SCF_ERROR_DELETED: 4428 warn(emsg_pg_deleted, ient->sc_fmri, 4429 "dependents"); 4430 return (EBUSY); 4431 4432 case SCF_ERROR_CONNECTION_BROKEN: 4433 return (scferror2errno(scf_error())); 4434 4435 case SCF_ERROR_NOT_FOUND: 4436 break; 4437 4438 case SCF_ERROR_HANDLE_MISMATCH: 4439 case SCF_ERROR_NOT_BOUND: 4440 case SCF_ERROR_INVALID_ARGUMENT: 4441 case SCF_ERROR_NOT_SET: 4442 default: 4443 bad_error("scf_transaction_property_delete", 4444 scf_error()); 4445 } 4446 } 4447 4448 return (0); 4449 } 4450 4451 new_dpt_pgroup->sc_pgroup_seen = 1; 4452 4453 /* 4454 * Decide whether the dependent has changed in the manifest. 4455 */ 4456 /* Compare the target. */ 4457 if (scf_property_get_value(prop, ud_val) != 0) { 4458 switch (scf_error()) { 4459 case SCF_ERROR_NOT_FOUND: 4460 case SCF_ERROR_CONSTRAINT_VIOLATED: 4461 warn(li_corrupt, ient->sc_fmri); 4462 return (EBADF); 4463 4464 case SCF_ERROR_DELETED: 4465 case SCF_ERROR_CONNECTION_BROKEN: 4466 return (scferror2errno(scf_error())); 4467 4468 case SCF_ERROR_HANDLE_MISMATCH: 4469 case SCF_ERROR_NOT_BOUND: 4470 case SCF_ERROR_NOT_SET: 4471 case SCF_ERROR_PERMISSION_DENIED: 4472 default: 4473 bad_error("scf_property_get_value", scf_error()); 4474 } 4475 } 4476 4477 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 4478 0) 4479 bad_error("scf_value_get_as_string", scf_error()); 4480 4481 /* 4482 * If the fmri's are not equal then the old fmri will need to 4483 * be refreshed to ensure that the changes are properly updated 4484 * in that service. 4485 */ 4486 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 4487 switch (r) { 4488 case 0: 4489 dpt = internal_pgroup_new(); 4490 if (dpt == NULL) 4491 return (ENOMEM); 4492 dpt->sc_pgroup_name = strdup(ud_name); 4493 dpt->sc_pgroup_fmri = strdup(ud_oldtarg); 4494 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4495 return (ENOMEM); 4496 dpt->sc_parent = (entity_t *)ient; 4497 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4498 uu_die(gettext("libuutil error: %s\n"), 4499 uu_strerror(uu_error())); 4500 break; 4501 4502 case 1: 4503 /* Compare the dependency pgs. */ 4504 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4505 switch (scf_error()) { 4506 case SCF_ERROR_NOT_FOUND: 4507 warn(li_corrupt, ient->sc_fmri); 4508 return (EBADF); 4509 4510 case SCF_ERROR_DELETED: 4511 case SCF_ERROR_CONNECTION_BROKEN: 4512 return (scferror2errno(scf_error())); 4513 4514 case SCF_ERROR_NOT_BOUND: 4515 case SCF_ERROR_HANDLE_MISMATCH: 4516 case SCF_ERROR_INVALID_ARGUMENT: 4517 case SCF_ERROR_NOT_SET: 4518 default: 4519 bad_error("scf_snaplevel_get_pg", scf_error()); 4520 } 4521 } 4522 4523 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4524 snap_lastimport); 4525 switch (r) { 4526 case 0: 4527 break; 4528 4529 case ECANCELED: 4530 case ECONNABORTED: 4531 case ENOMEM: 4532 case EBADF: 4533 return (r); 4534 4535 case EACCES: 4536 default: 4537 bad_error("load_pg", r); 4538 } 4539 4540 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4541 /* no change, leave customizations */ 4542 internal_pgroup_free(old_dpt_pgroup); 4543 return (0); 4544 } 4545 break; 4546 4547 case -1: 4548 warn(li_corrupt, ient->sc_fmri); 4549 return (EBADF); 4550 4551 case -2: 4552 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4553 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4554 return (EINVAL); 4555 4556 default: 4557 bad_error("fmri_equal", r); 4558 } 4559 4560 /* 4561 * The dependent has changed in the manifest. Upgrade the current 4562 * properties if they haven't been customized. 4563 */ 4564 4565 /* 4566 * If new_dpt_pgroup->sc_override, then act as though the property 4567 * group hasn't been customized. 4568 */ 4569 if (new_dpt_pgroup->sc_pgroup_override) { 4570 (void) strcpy(ud_ctarg, ud_oldtarg); 4571 goto nocust; 4572 } 4573 4574 if (!ud_run_dpts_pg_set) { 4575 warn(cf_missing, ient->sc_fmri, ud_name); 4576 r = 0; 4577 goto out; 4578 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4579 switch (scf_error()) { 4580 case SCF_ERROR_NOT_FOUND: 4581 warn(cf_missing, ient->sc_fmri, ud_name); 4582 r = 0; 4583 goto out; 4584 4585 case SCF_ERROR_CONNECTION_BROKEN: 4586 r = scferror2errno(scf_error()); 4587 goto out; 4588 4589 case SCF_ERROR_DELETED: 4590 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4591 r = EBUSY; 4592 goto out; 4593 4594 case SCF_ERROR_INVALID_ARGUMENT: 4595 case SCF_ERROR_NOT_BOUND: 4596 case SCF_ERROR_HANDLE_MISMATCH: 4597 case SCF_ERROR_NOT_SET: 4598 default: 4599 bad_error("scf_pg_get_property", scf_error()); 4600 } 4601 } 4602 4603 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4604 switch (scf_error()) { 4605 case SCF_ERROR_NOT_FOUND: 4606 case SCF_ERROR_CONSTRAINT_VIOLATED: 4607 warn(cf_inval, ient->sc_fmri, ud_name); 4608 r = 0; 4609 goto out; 4610 4611 case SCF_ERROR_DELETED: 4612 case SCF_ERROR_CONNECTION_BROKEN: 4613 r = scferror2errno(scf_error()); 4614 goto out; 4615 4616 case SCF_ERROR_HANDLE_MISMATCH: 4617 case SCF_ERROR_NOT_BOUND: 4618 case SCF_ERROR_NOT_SET: 4619 case SCF_ERROR_PERMISSION_DENIED: 4620 default: 4621 bad_error("scf_property_get_value", scf_error()); 4622 } 4623 } 4624 4625 ty = scf_value_type(ud_val); 4626 assert(ty != SCF_TYPE_INVALID); 4627 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4628 warn(cf_inval, ient->sc_fmri, ud_name); 4629 r = 0; 4630 goto out; 4631 } 4632 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4633 0) 4634 bad_error("scf_value_get_as_string", scf_error()); 4635 4636 r = fmri_equal(ud_ctarg, ud_oldtarg); 4637 if (r == -1) { 4638 warn(cf_inval, ient->sc_fmri, ud_name); 4639 r = 0; 4640 goto out; 4641 } else if (r == -2) { 4642 warn(li_corrupt, ient->sc_fmri); 4643 r = EBADF; 4644 goto out; 4645 } else if (r == 0) { 4646 /* 4647 * Target has been changed. Only abort now if it's been 4648 * changed to something other than what's in the manifest. 4649 */ 4650 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4651 if (r == -1) { 4652 warn(cf_inval, ient->sc_fmri, ud_name); 4653 r = 0; 4654 goto out; 4655 } else if (r == 0) { 4656 warn(cf_newtarg, ient->sc_fmri, ud_name); 4657 r = 0; 4658 goto out; 4659 } else if (r != 1) { 4660 /* invalid sc_pgroup_fmri caught above */ 4661 bad_error("fmri_equal", r); 4662 } 4663 4664 /* 4665 * Fetch the current dependency pg. If it's what the manifest 4666 * says, then no problem. 4667 */ 4668 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4669 switch (serr) { 4670 case SCF_ERROR_NONE: 4671 break; 4672 4673 case SCF_ERROR_NOT_FOUND: 4674 warn(cf_missing, ient->sc_fmri, ud_name); 4675 r = 0; 4676 goto out; 4677 4678 case SCF_ERROR_NO_MEMORY: 4679 r = ENOMEM; 4680 goto out; 4681 4682 case SCF_ERROR_CONSTRAINT_VIOLATED: 4683 case SCF_ERROR_INVALID_ARGUMENT: 4684 default: 4685 bad_error("fmri_to_entity", serr); 4686 } 4687 4688 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4689 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4690 switch (r) { 4691 case 0: 4692 break; 4693 4694 case ECONNABORTED: 4695 goto out; 4696 4697 case ECANCELED: 4698 case ENOENT: 4699 warn(cf_missing, ient->sc_fmri, ud_name); 4700 r = 0; 4701 goto out; 4702 4703 case EBADF: 4704 warn(r_no_lvl, ud_ctarg); 4705 goto out; 4706 4707 case EINVAL: 4708 default: 4709 bad_error("entity_get_running_pg", r); 4710 } 4711 4712 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4713 switch (r) { 4714 case 0: 4715 break; 4716 4717 case ECANCELED: 4718 warn(cf_missing, ient->sc_fmri, ud_name); 4719 r = 0; 4720 goto out; 4721 4722 case ECONNABORTED: 4723 case ENOMEM: 4724 case EBADF: 4725 goto out; 4726 4727 case EACCES: 4728 default: 4729 bad_error("load_pg", r); 4730 } 4731 4732 if (!pg_equal(current_pg, new_dpt_pgroup)) 4733 warn(cf_newdpg, ient->sc_fmri, ud_name); 4734 internal_pgroup_free(current_pg); 4735 r = 0; 4736 goto out; 4737 } else if (r != 1) { 4738 bad_error("fmri_equal", r); 4739 } 4740 4741 nocust: 4742 /* 4743 * Target has not been customized. Check the dependency property 4744 * group. 4745 */ 4746 4747 if (old_dpt_pgroup == NULL) { 4748 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4749 ud_pg) != 0) { 4750 switch (scf_error()) { 4751 case SCF_ERROR_NOT_FOUND: 4752 warn(li_corrupt, ient->sc_fmri); 4753 return (EBADF); 4754 4755 case SCF_ERROR_DELETED: 4756 case SCF_ERROR_CONNECTION_BROKEN: 4757 return (scferror2errno(scf_error())); 4758 4759 case SCF_ERROR_NOT_BOUND: 4760 case SCF_ERROR_HANDLE_MISMATCH: 4761 case SCF_ERROR_INVALID_ARGUMENT: 4762 case SCF_ERROR_NOT_SET: 4763 default: 4764 bad_error("scf_snaplevel_get_pg", scf_error()); 4765 } 4766 } 4767 4768 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4769 snap_lastimport); 4770 switch (r) { 4771 case 0: 4772 break; 4773 4774 case ECANCELED: 4775 case ECONNABORTED: 4776 case ENOMEM: 4777 case EBADF: 4778 return (r); 4779 4780 case EACCES: 4781 default: 4782 bad_error("load_pg", r); 4783 } 4784 } 4785 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4786 switch (serr) { 4787 case SCF_ERROR_NONE: 4788 break; 4789 4790 case SCF_ERROR_NOT_FOUND: 4791 warn(cf_missing, ient->sc_fmri, ud_name); 4792 r = 0; 4793 goto out; 4794 4795 case SCF_ERROR_NO_MEMORY: 4796 r = ENOMEM; 4797 goto out; 4798 4799 case SCF_ERROR_CONSTRAINT_VIOLATED: 4800 case SCF_ERROR_INVALID_ARGUMENT: 4801 default: 4802 bad_error("fmri_to_entity", serr); 4803 } 4804 4805 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4806 ud_iter2, ud_inst, imp_snap, ud_snpl); 4807 switch (r) { 4808 case 0: 4809 break; 4810 4811 case ECONNABORTED: 4812 goto out; 4813 4814 case ECANCELED: 4815 case ENOENT: 4816 warn(cf_missing, ient->sc_fmri, ud_name); 4817 r = 0; 4818 goto out; 4819 4820 case EBADF: 4821 warn(r_no_lvl, ud_ctarg); 4822 goto out; 4823 4824 case EINVAL: 4825 default: 4826 bad_error("entity_get_running_pg", r); 4827 } 4828 4829 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4830 switch (r) { 4831 case 0: 4832 break; 4833 4834 case ECANCELED: 4835 warn(cf_missing, ient->sc_fmri, ud_name); 4836 goto out; 4837 4838 case ECONNABORTED: 4839 case ENOMEM: 4840 case EBADF: 4841 goto out; 4842 4843 case EACCES: 4844 default: 4845 bad_error("load_pg", r); 4846 } 4847 4848 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4849 if (!pg_equal(current_pg, new_dpt_pgroup)) 4850 warn(cf_newdpg, ient->sc_fmri, ud_name); 4851 internal_pgroup_free(current_pg); 4852 r = 0; 4853 goto out; 4854 } 4855 4856 /* Uncustomized. Upgrade. */ 4857 4858 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4859 switch (r) { 4860 case 1: 4861 if (pg_equal(current_pg, new_dpt_pgroup)) { 4862 /* Already upgraded. */ 4863 internal_pgroup_free(current_pg); 4864 r = 0; 4865 goto out; 4866 } 4867 4868 internal_pgroup_free(current_pg); 4869 4870 /* upgrade current_pg */ 4871 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4872 switch (scf_error()) { 4873 case SCF_ERROR_CONNECTION_BROKEN: 4874 r = scferror2errno(scf_error()); 4875 goto out; 4876 4877 case SCF_ERROR_DELETED: 4878 warn(cf_missing, ient->sc_fmri, ud_name); 4879 r = 0; 4880 goto out; 4881 4882 case SCF_ERROR_NOT_FOUND: 4883 break; 4884 4885 case SCF_ERROR_INVALID_ARGUMENT: 4886 case SCF_ERROR_NOT_BOUND: 4887 case SCF_ERROR_NOT_SET: 4888 case SCF_ERROR_HANDLE_MISMATCH: 4889 default: 4890 bad_error("entity_get_pg", scf_error()); 4891 } 4892 4893 if (tissvc) 4894 r = scf_service_add_pg(target_ent, ud_name, 4895 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4896 else 4897 r = scf_instance_add_pg(target_ent, ud_name, 4898 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4899 if (r != 0) { 4900 switch (scf_error()) { 4901 case SCF_ERROR_CONNECTION_BROKEN: 4902 case SCF_ERROR_NO_RESOURCES: 4903 case SCF_ERROR_BACKEND_READONLY: 4904 case SCF_ERROR_BACKEND_ACCESS: 4905 r = scferror2errno(scf_error()); 4906 goto out; 4907 4908 case SCF_ERROR_DELETED: 4909 warn(cf_missing, ient->sc_fmri, 4910 ud_name); 4911 r = 0; 4912 goto out; 4913 4914 case SCF_ERROR_PERMISSION_DENIED: 4915 warn(emsg_pg_deleted, ud_ctarg, 4916 ud_name); 4917 r = EPERM; 4918 goto out; 4919 4920 case SCF_ERROR_EXISTS: 4921 warn(emsg_pg_added, ud_ctarg, ud_name); 4922 r = EBUSY; 4923 goto out; 4924 4925 case SCF_ERROR_NOT_BOUND: 4926 case SCF_ERROR_HANDLE_MISMATCH: 4927 case SCF_ERROR_INVALID_ARGUMENT: 4928 case SCF_ERROR_NOT_SET: 4929 default: 4930 bad_error("entity_add_pg", scf_error()); 4931 } 4932 } 4933 } 4934 4935 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4936 switch (r) { 4937 case 0: 4938 break; 4939 4940 case ECANCELED: 4941 warn(cf_missing, ient->sc_fmri, ud_name); 4942 goto out; 4943 4944 case ECONNABORTED: 4945 case ENOMEM: 4946 case EBADF: 4947 goto out; 4948 4949 case EACCES: 4950 default: 4951 bad_error("load_pg", r); 4952 } 4953 4954 if (g_verbose) 4955 warn(upgrading, ient->sc_fmri, ud_name); 4956 4957 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4958 new_dpt_pgroup, 0, ient->sc_fmri); 4959 switch (r) { 4960 case 0: 4961 break; 4962 4963 case ECANCELED: 4964 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4965 r = EBUSY; 4966 goto out; 4967 4968 case EPERM: 4969 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4970 goto out; 4971 4972 case EBUSY: 4973 warn(emsg_pg_changed, ud_ctarg, ud_name); 4974 goto out; 4975 4976 case ECONNABORTED: 4977 case ENOMEM: 4978 case ENOSPC: 4979 case EROFS: 4980 case EACCES: 4981 case EINVAL: 4982 goto out; 4983 4984 default: 4985 bad_error("upgrade_pg", r); 4986 } 4987 break; 4988 4989 case 0: { 4990 scf_transaction_entry_t *ent; 4991 scf_value_t *val; 4992 4993 internal_pgroup_free(current_pg); 4994 4995 /* delete old pg */ 4996 if (g_verbose) 4997 warn(upgrading, ient->sc_fmri, ud_name); 4998 4999 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 5000 switch (scf_error()) { 5001 case SCF_ERROR_CONNECTION_BROKEN: 5002 r = scferror2errno(scf_error()); 5003 goto out; 5004 5005 case SCF_ERROR_DELETED: 5006 warn(cf_missing, ient->sc_fmri, ud_name); 5007 r = 0; 5008 goto out; 5009 5010 case SCF_ERROR_NOT_FOUND: 5011 break; 5012 5013 case SCF_ERROR_INVALID_ARGUMENT: 5014 case SCF_ERROR_NOT_BOUND: 5015 case SCF_ERROR_NOT_SET: 5016 case SCF_ERROR_HANDLE_MISMATCH: 5017 default: 5018 bad_error("entity_get_pg", scf_error()); 5019 } 5020 } else if (scf_pg_delete(ud_pg) != 0) { 5021 switch (scf_error()) { 5022 case SCF_ERROR_DELETED: 5023 break; 5024 5025 case SCF_ERROR_CONNECTION_BROKEN: 5026 case SCF_ERROR_BACKEND_READONLY: 5027 case SCF_ERROR_BACKEND_ACCESS: 5028 r = scferror2errno(scf_error()); 5029 goto out; 5030 5031 case SCF_ERROR_PERMISSION_DENIED: 5032 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 5033 r = scferror2errno(scf_error()); 5034 goto out; 5035 5036 case SCF_ERROR_NOT_SET: 5037 default: 5038 bad_error("scf_pg_delete", scf_error()); 5039 } 5040 } 5041 5042 /* import new one */ 5043 cbdata.sc_handle = g_hndl; 5044 cbdata.sc_trans = NULL; /* handled below */ 5045 cbdata.sc_flags = 0; 5046 5047 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 5048 if (r != UU_WALK_NEXT) { 5049 if (r != UU_WALK_ERROR) 5050 bad_error("lscf_dependent_import", r); 5051 5052 r = cbdata.sc_err; 5053 goto out; 5054 } 5055 5056 if (tx == NULL) 5057 break; 5058 5059 if ((ent = scf_entry_create(g_hndl)) == NULL || 5060 (val = scf_value_create(g_hndl)) == NULL) { 5061 if (scf_error() == SCF_ERROR_NO_MEMORY) 5062 return (ENOMEM); 5063 5064 bad_error("scf_entry_create", scf_error()); 5065 } 5066 5067 if (scf_transaction_property_change_type(tx, ent, ud_name, 5068 SCF_TYPE_FMRI) != 0) { 5069 switch (scf_error()) { 5070 case SCF_ERROR_CONNECTION_BROKEN: 5071 r = scferror2errno(scf_error()); 5072 goto out; 5073 5074 case SCF_ERROR_DELETED: 5075 warn(emsg_pg_deleted, ient->sc_fmri, 5076 "dependents"); 5077 r = EBUSY; 5078 goto out; 5079 5080 case SCF_ERROR_NOT_FOUND: 5081 break; 5082 5083 case SCF_ERROR_NOT_BOUND: 5084 case SCF_ERROR_HANDLE_MISMATCH: 5085 case SCF_ERROR_INVALID_ARGUMENT: 5086 case SCF_ERROR_NOT_SET: 5087 default: 5088 bad_error("scf_transaction_property_" 5089 "change_type", scf_error()); 5090 } 5091 5092 if (scf_transaction_property_new(tx, ent, ud_name, 5093 SCF_TYPE_FMRI) != 0) { 5094 switch (scf_error()) { 5095 case SCF_ERROR_CONNECTION_BROKEN: 5096 r = scferror2errno(scf_error()); 5097 goto out; 5098 5099 case SCF_ERROR_DELETED: 5100 warn(emsg_pg_deleted, ient->sc_fmri, 5101 "dependents"); 5102 r = EBUSY; 5103 goto out; 5104 5105 case SCF_ERROR_EXISTS: 5106 warn(emsg_pg_changed, ient->sc_fmri, 5107 "dependents"); 5108 r = EBUSY; 5109 goto out; 5110 5111 case SCF_ERROR_INVALID_ARGUMENT: 5112 case SCF_ERROR_HANDLE_MISMATCH: 5113 case SCF_ERROR_NOT_BOUND: 5114 case SCF_ERROR_NOT_SET: 5115 default: 5116 bad_error("scf_transaction_property_" 5117 "new", scf_error()); 5118 } 5119 } 5120 } 5121 5122 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 5123 new_dpt_pgroup->sc_pgroup_fmri) != 0) 5124 /* invalid sc_pgroup_fmri caught above */ 5125 bad_error("scf_value_set_from_string", 5126 scf_error()); 5127 5128 if (scf_entry_add_value(ent, val) != 0) 5129 bad_error("scf_entry_add_value", scf_error()); 5130 break; 5131 } 5132 5133 case -2: 5134 warn(li_corrupt, ient->sc_fmri); 5135 internal_pgroup_free(current_pg); 5136 r = EBADF; 5137 goto out; 5138 5139 case -1: 5140 default: 5141 /* invalid sc_pgroup_fmri caught above */ 5142 bad_error("fmri_equal", r); 5143 } 5144 5145 r = 0; 5146 5147 out: 5148 if (old_dpt_pgroup != NULL) 5149 internal_pgroup_free(old_dpt_pgroup); 5150 5151 return (r); 5152 } 5153 5154 /* 5155 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 5156 * would import it, except it seems to exist in the service anyway. Compare 5157 * the existent dependent with the one we would import, and report any 5158 * differences (if there are none, be silent). prop is the property which 5159 * represents the existent dependent (in the dependents property group) in the 5160 * entity corresponding to ient. 5161 * 5162 * Returns 5163 * 0 - success (Sort of. At least, we can continue importing.) 5164 * ECONNABORTED - repository connection broken 5165 * EBUSY - ancestor of prop was deleted (error printed) 5166 * ENOMEM - out of memory 5167 * EBADF - corrupt property group (error printed) 5168 * EINVAL - new_dpt_pgroup has invalid target (error printed) 5169 */ 5170 static int 5171 handle_dependent_conflict(const entity_t * const ient, 5172 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 5173 { 5174 int r; 5175 scf_type_t ty; 5176 scf_error_t scfe; 5177 void *tptr; 5178 int tissvc; 5179 pgroup_t *pgroup; 5180 5181 if (scf_property_get_value(prop, ud_val) != 0) { 5182 switch (scf_error()) { 5183 case SCF_ERROR_CONNECTION_BROKEN: 5184 return (scferror2errno(scf_error())); 5185 5186 case SCF_ERROR_DELETED: 5187 warn(emsg_pg_deleted, ient->sc_fmri, 5188 new_dpt_pgroup->sc_pgroup_name); 5189 return (EBUSY); 5190 5191 case SCF_ERROR_CONSTRAINT_VIOLATED: 5192 case SCF_ERROR_NOT_FOUND: 5193 warn(gettext("Conflict upgrading %s (not importing " 5194 "dependent \"%s\" because it already exists.) " 5195 "Warning: The \"%s/%2$s\" property has more or " 5196 "fewer than one value)).\n"), ient->sc_fmri, 5197 new_dpt_pgroup->sc_pgroup_name, "dependents"); 5198 return (0); 5199 5200 case SCF_ERROR_HANDLE_MISMATCH: 5201 case SCF_ERROR_NOT_BOUND: 5202 case SCF_ERROR_NOT_SET: 5203 case SCF_ERROR_PERMISSION_DENIED: 5204 default: 5205 bad_error("scf_property_get_value", 5206 scf_error()); 5207 } 5208 } 5209 5210 ty = scf_value_type(ud_val); 5211 assert(ty != SCF_TYPE_INVALID); 5212 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 5213 warn(gettext("Conflict upgrading %s (not importing dependent " 5214 "\"%s\" because it already exists). Warning: The " 5215 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 5216 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 5217 scf_type_to_string(ty), "dependents"); 5218 return (0); 5219 } 5220 5221 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 5222 0) 5223 bad_error("scf_value_get_as_string", scf_error()); 5224 5225 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 5226 switch (r) { 5227 case 0: 5228 warn(gettext("Conflict upgrading %s (not importing dependent " 5229 "\"%s\" (target \"%s\") because it already exists with " 5230 "target \"%s\").\n"), ient->sc_fmri, 5231 new_dpt_pgroup->sc_pgroup_name, 5232 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 5233 return (0); 5234 5235 case 1: 5236 break; 5237 5238 case -1: 5239 warn(gettext("Conflict upgrading %s (not importing dependent " 5240 "\"%s\" because it already exists). Warning: The current " 5241 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 5242 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5243 return (0); 5244 5245 case -2: 5246 warn(gettext("Dependent \"%s\" of %s has invalid target " 5247 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 5248 new_dpt_pgroup->sc_pgroup_fmri); 5249 return (EINVAL); 5250 5251 default: 5252 bad_error("fmri_equal", r); 5253 } 5254 5255 /* compare dependency pgs in target */ 5256 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 5257 switch (scfe) { 5258 case SCF_ERROR_NONE: 5259 break; 5260 5261 case SCF_ERROR_NO_MEMORY: 5262 return (ENOMEM); 5263 5264 case SCF_ERROR_NOT_FOUND: 5265 warn(emsg_dpt_dangling, ient->sc_fmri, 5266 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5267 return (0); 5268 5269 case SCF_ERROR_CONSTRAINT_VIOLATED: 5270 case SCF_ERROR_INVALID_ARGUMENT: 5271 default: 5272 bad_error("fmri_to_entity", scfe); 5273 } 5274 5275 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 5276 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 5277 switch (r) { 5278 case 0: 5279 break; 5280 5281 case ECONNABORTED: 5282 return (r); 5283 5284 case ECANCELED: 5285 warn(emsg_dpt_dangling, ient->sc_fmri, 5286 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5287 return (0); 5288 5289 case EBADF: 5290 if (tissvc) 5291 warn(gettext("%s has an instance with a \"%s\" " 5292 "snapshot which is missing a snaplevel.\n"), 5293 ud_ctarg, "running"); 5294 else 5295 warn(gettext("%s has a \"%s\" snapshot which is " 5296 "missing a snaplevel.\n"), ud_ctarg, "running"); 5297 /* FALLTHROUGH */ 5298 5299 case ENOENT: 5300 warn(emsg_dpt_no_dep, ient->sc_fmri, 5301 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5302 new_dpt_pgroup->sc_pgroup_name); 5303 return (0); 5304 5305 case EINVAL: 5306 default: 5307 bad_error("entity_get_running_pg", r); 5308 } 5309 5310 pgroup = internal_pgroup_new(); 5311 if (pgroup == NULL) 5312 return (ENOMEM); 5313 5314 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 5315 switch (r) { 5316 case 0: 5317 break; 5318 5319 case ECONNABORTED: 5320 case EBADF: 5321 case ENOMEM: 5322 internal_pgroup_free(pgroup); 5323 return (r); 5324 5325 case ECANCELED: 5326 warn(emsg_dpt_no_dep, ient->sc_fmri, 5327 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5328 new_dpt_pgroup->sc_pgroup_name); 5329 internal_pgroup_free(pgroup); 5330 return (0); 5331 5332 case EACCES: 5333 default: 5334 bad_error("load_pg", r); 5335 } 5336 5337 /* report differences */ 5338 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 5339 internal_pgroup_free(pgroup); 5340 return (0); 5341 } 5342 5343 /* 5344 * lipg is a property group in the last-import snapshot of ent, which is an 5345 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 5346 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 5347 * in ents's property groups, compare and upgrade ent appropriately. 5348 * 5349 * Returns 5350 * 0 - success 5351 * ECONNABORTED - repository connection broken 5352 * ENOMEM - out of memory 5353 * ENOSPC - configd is out of resources 5354 * EINVAL - ient has invalid dependent (error printed) 5355 * - ient has invalid pgroup_t (error printed) 5356 * ECANCELED - ent has been deleted 5357 * ENODEV - entity containing lipg has been deleted 5358 * - entity containing running has been deleted 5359 * EPERM - could not delete pg (permission denied) (error printed) 5360 * - couldn't upgrade dependents (permission denied) (error printed) 5361 * - couldn't import pg (permission denied) (error printed) 5362 * - couldn't upgrade pg (permission denied) (error printed) 5363 * EROFS - could not delete pg (repository read-only) 5364 * - couldn't upgrade dependents (repository read-only) 5365 * - couldn't import pg (repository read-only) 5366 * - couldn't upgrade pg (repository read-only) 5367 * EACCES - could not delete pg (backend access denied) 5368 * - couldn't upgrade dependents (backend access denied) 5369 * - couldn't import pg (backend access denied) 5370 * - couldn't upgrade pg (backend access denied) 5371 * - couldn't read property (backend access denied) 5372 * EBUSY - property group was added (error printed) 5373 * - property group was deleted (error printed) 5374 * - property group changed (error printed) 5375 * - "dependents" pg was added, changed, or deleted (error printed) 5376 * - dependent target deleted (error printed) 5377 * - dependent pg changed (error printed) 5378 * EBADF - imp_snpl is corrupt (error printed) 5379 * - ent has bad pg (error printed) 5380 * EEXIST - dependent collision in target service (error printed) 5381 */ 5382 static int 5383 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 5384 const scf_snaplevel_t *running) 5385 { 5386 int r; 5387 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 5388 scf_callback_t cbdata; 5389 5390 const char * const cf_pg_missing = 5391 gettext("Conflict upgrading %s (property group %s is missing)\n"); 5392 const char * const deleting = 5393 gettext("%s: Deleting property group \"%s\".\n"); 5394 5395 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5396 5397 /* Skip dependent property groups. */ 5398 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 5399 switch (scf_error()) { 5400 case SCF_ERROR_DELETED: 5401 return (ENODEV); 5402 5403 case SCF_ERROR_CONNECTION_BROKEN: 5404 return (ECONNABORTED); 5405 5406 case SCF_ERROR_NOT_SET: 5407 case SCF_ERROR_NOT_BOUND: 5408 default: 5409 bad_error("scf_pg_get_type", scf_error()); 5410 } 5411 } 5412 5413 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 5414 if (scf_pg_get_property(lipg, "external", NULL) == 0) 5415 return (0); 5416 5417 switch (scf_error()) { 5418 case SCF_ERROR_NOT_FOUND: 5419 break; 5420 5421 case SCF_ERROR_CONNECTION_BROKEN: 5422 return (ECONNABORTED); 5423 5424 case SCF_ERROR_DELETED: 5425 return (ENODEV); 5426 5427 case SCF_ERROR_INVALID_ARGUMENT: 5428 case SCF_ERROR_NOT_BOUND: 5429 case SCF_ERROR_HANDLE_MISMATCH: 5430 case SCF_ERROR_NOT_SET: 5431 default: 5432 bad_error("scf_pg_get_property", scf_error()); 5433 } 5434 } 5435 5436 /* lookup pg in new properties */ 5437 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 5438 switch (scf_error()) { 5439 case SCF_ERROR_DELETED: 5440 return (ENODEV); 5441 5442 case SCF_ERROR_CONNECTION_BROKEN: 5443 return (ECONNABORTED); 5444 5445 case SCF_ERROR_NOT_SET: 5446 case SCF_ERROR_NOT_BOUND: 5447 default: 5448 bad_error("scf_pg_get_name", scf_error()); 5449 } 5450 } 5451 5452 pgrp.sc_pgroup_name = imp_str; 5453 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 5454 5455 if (mpg != NULL) 5456 mpg->sc_pgroup_seen = 1; 5457 5458 /* Special handling for dependents */ 5459 if (strcmp(imp_str, "dependents") == 0) 5460 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 5461 5462 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 5463 return (upgrade_manifestfiles(NULL, ient, running, ent)); 5464 5465 if (mpg == NULL || mpg->sc_pgroup_delete) { 5466 /* property group was deleted from manifest */ 5467 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5468 switch (scf_error()) { 5469 case SCF_ERROR_NOT_FOUND: 5470 return (0); 5471 5472 case SCF_ERROR_DELETED: 5473 case SCF_ERROR_CONNECTION_BROKEN: 5474 return (scferror2errno(scf_error())); 5475 5476 case SCF_ERROR_INVALID_ARGUMENT: 5477 case SCF_ERROR_HANDLE_MISMATCH: 5478 case SCF_ERROR_NOT_BOUND: 5479 case SCF_ERROR_NOT_SET: 5480 default: 5481 bad_error("entity_get_pg", scf_error()); 5482 } 5483 } 5484 5485 if (mpg != NULL && mpg->sc_pgroup_delete) { 5486 if (g_verbose) 5487 warn(deleting, ient->sc_fmri, imp_str); 5488 if (scf_pg_delete(imp_pg2) == 0) 5489 return (0); 5490 5491 switch (scf_error()) { 5492 case SCF_ERROR_DELETED: 5493 return (0); 5494 5495 case SCF_ERROR_CONNECTION_BROKEN: 5496 case SCF_ERROR_BACKEND_READONLY: 5497 case SCF_ERROR_BACKEND_ACCESS: 5498 return (scferror2errno(scf_error())); 5499 5500 case SCF_ERROR_PERMISSION_DENIED: 5501 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 5502 return (scferror2errno(scf_error())); 5503 5504 case SCF_ERROR_NOT_SET: 5505 default: 5506 bad_error("scf_pg_delete", scf_error()); 5507 } 5508 } 5509 5510 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5511 switch (r) { 5512 case 0: 5513 break; 5514 5515 case ECANCELED: 5516 return (ENODEV); 5517 5518 case ECONNABORTED: 5519 case ENOMEM: 5520 case EBADF: 5521 case EACCES: 5522 return (r); 5523 5524 default: 5525 bad_error("load_pg", r); 5526 } 5527 5528 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5529 switch (r) { 5530 case 0: 5531 break; 5532 5533 case ECANCELED: 5534 case ECONNABORTED: 5535 case ENOMEM: 5536 case EBADF: 5537 case EACCES: 5538 internal_pgroup_free(lipg_i); 5539 return (r); 5540 5541 default: 5542 bad_error("load_pg", r); 5543 } 5544 5545 if (pg_equal(lipg_i, curpg_i)) { 5546 if (g_verbose) 5547 warn(deleting, ient->sc_fmri, imp_str); 5548 if (scf_pg_delete(imp_pg2) != 0) { 5549 switch (scf_error()) { 5550 case SCF_ERROR_DELETED: 5551 break; 5552 5553 case SCF_ERROR_CONNECTION_BROKEN: 5554 internal_pgroup_free(lipg_i); 5555 internal_pgroup_free(curpg_i); 5556 return (ECONNABORTED); 5557 5558 case SCF_ERROR_NOT_SET: 5559 case SCF_ERROR_NOT_BOUND: 5560 default: 5561 bad_error("scf_pg_delete", scf_error()); 5562 } 5563 } 5564 } else { 5565 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5566 } 5567 5568 internal_pgroup_free(lipg_i); 5569 internal_pgroup_free(curpg_i); 5570 5571 return (0); 5572 } 5573 5574 /* 5575 * Only dependent pgs can have override set, and we skipped those 5576 * above. 5577 */ 5578 assert(!mpg->sc_pgroup_override); 5579 5580 /* compare */ 5581 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5582 switch (r) { 5583 case 0: 5584 break; 5585 5586 case ECANCELED: 5587 return (ENODEV); 5588 5589 case ECONNABORTED: 5590 case EBADF: 5591 case ENOMEM: 5592 case EACCES: 5593 return (r); 5594 5595 default: 5596 bad_error("load_pg", r); 5597 } 5598 5599 if (pg_equal(mpg, lipg_i)) { 5600 /* The manifest pg has not changed. Move on. */ 5601 r = 0; 5602 goto out; 5603 } 5604 5605 /* upgrade current properties according to lipg & mpg */ 5606 if (running != NULL) 5607 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5608 else 5609 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5610 if (r != 0) { 5611 switch (scf_error()) { 5612 case SCF_ERROR_CONNECTION_BROKEN: 5613 r = scferror2errno(scf_error()); 5614 goto out; 5615 5616 case SCF_ERROR_DELETED: 5617 if (running != NULL) 5618 r = ENODEV; 5619 else 5620 r = ECANCELED; 5621 goto out; 5622 5623 case SCF_ERROR_NOT_FOUND: 5624 break; 5625 5626 case SCF_ERROR_INVALID_ARGUMENT: 5627 case SCF_ERROR_HANDLE_MISMATCH: 5628 case SCF_ERROR_NOT_BOUND: 5629 case SCF_ERROR_NOT_SET: 5630 default: 5631 bad_error("entity_get_pg", scf_error()); 5632 } 5633 5634 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5635 5636 r = 0; 5637 goto out; 5638 } 5639 5640 r = load_pg_attrs(imp_pg2, &curpg_i); 5641 switch (r) { 5642 case 0: 5643 break; 5644 5645 case ECANCELED: 5646 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5647 r = 0; 5648 goto out; 5649 5650 case ECONNABORTED: 5651 case ENOMEM: 5652 goto out; 5653 5654 default: 5655 bad_error("load_pg_attrs", r); 5656 } 5657 5658 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5659 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5660 internal_pgroup_free(curpg_i); 5661 r = 0; 5662 goto out; 5663 } 5664 5665 internal_pgroup_free(curpg_i); 5666 5667 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5668 switch (r) { 5669 case 0: 5670 break; 5671 5672 case ECANCELED: 5673 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5674 r = 0; 5675 goto out; 5676 5677 case ECONNABORTED: 5678 case EBADF: 5679 case ENOMEM: 5680 case EACCES: 5681 goto out; 5682 5683 default: 5684 bad_error("load_pg", r); 5685 } 5686 5687 if (pg_equal(lipg_i, curpg_i) && 5688 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5689 int do_delete = 1; 5690 5691 if (g_verbose) 5692 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5693 ient->sc_fmri, mpg->sc_pgroup_name); 5694 5695 internal_pgroup_free(curpg_i); 5696 5697 if (running != NULL && 5698 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5699 switch (scf_error()) { 5700 case SCF_ERROR_DELETED: 5701 r = ECANCELED; 5702 goto out; 5703 5704 case SCF_ERROR_NOT_FOUND: 5705 do_delete = 0; 5706 break; 5707 5708 case SCF_ERROR_CONNECTION_BROKEN: 5709 r = scferror2errno(scf_error()); 5710 goto out; 5711 5712 case SCF_ERROR_HANDLE_MISMATCH: 5713 case SCF_ERROR_INVALID_ARGUMENT: 5714 case SCF_ERROR_NOT_SET: 5715 case SCF_ERROR_NOT_BOUND: 5716 default: 5717 bad_error("entity_get_pg", scf_error()); 5718 } 5719 } 5720 5721 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5722 switch (scf_error()) { 5723 case SCF_ERROR_DELETED: 5724 break; 5725 5726 case SCF_ERROR_CONNECTION_BROKEN: 5727 case SCF_ERROR_BACKEND_READONLY: 5728 case SCF_ERROR_BACKEND_ACCESS: 5729 r = scferror2errno(scf_error()); 5730 goto out; 5731 5732 case SCF_ERROR_PERMISSION_DENIED: 5733 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5734 ient->sc_fmri); 5735 r = scferror2errno(scf_error()); 5736 goto out; 5737 5738 case SCF_ERROR_NOT_SET: 5739 case SCF_ERROR_NOT_BOUND: 5740 default: 5741 bad_error("scf_pg_delete", scf_error()); 5742 } 5743 } 5744 5745 cbdata.sc_handle = g_hndl; 5746 cbdata.sc_parent = ent; 5747 cbdata.sc_service = issvc; 5748 cbdata.sc_flags = 0; 5749 cbdata.sc_source_fmri = ient->sc_fmri; 5750 cbdata.sc_target_fmri = ient->sc_fmri; 5751 5752 r = entity_pgroup_import(mpg, &cbdata); 5753 switch (r) { 5754 case UU_WALK_NEXT: 5755 r = 0; 5756 goto out; 5757 5758 case UU_WALK_ERROR: 5759 if (cbdata.sc_err == EEXIST) { 5760 warn(emsg_pg_added, ient->sc_fmri, 5761 mpg->sc_pgroup_name); 5762 r = EBUSY; 5763 } else { 5764 r = cbdata.sc_err; 5765 } 5766 goto out; 5767 5768 default: 5769 bad_error("entity_pgroup_import", r); 5770 } 5771 } 5772 5773 if (running != NULL && 5774 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5775 switch (scf_error()) { 5776 case SCF_ERROR_CONNECTION_BROKEN: 5777 case SCF_ERROR_DELETED: 5778 r = scferror2errno(scf_error()); 5779 goto out; 5780 5781 case SCF_ERROR_NOT_FOUND: 5782 break; 5783 5784 case SCF_ERROR_HANDLE_MISMATCH: 5785 case SCF_ERROR_INVALID_ARGUMENT: 5786 case SCF_ERROR_NOT_SET: 5787 case SCF_ERROR_NOT_BOUND: 5788 default: 5789 bad_error("entity_get_pg", scf_error()); 5790 } 5791 5792 cbdata.sc_handle = g_hndl; 5793 cbdata.sc_parent = ent; 5794 cbdata.sc_service = issvc; 5795 cbdata.sc_flags = SCI_FORCE; 5796 cbdata.sc_source_fmri = ient->sc_fmri; 5797 cbdata.sc_target_fmri = ient->sc_fmri; 5798 5799 r = entity_pgroup_import(mpg, &cbdata); 5800 switch (r) { 5801 case UU_WALK_NEXT: 5802 r = 0; 5803 goto out; 5804 5805 case UU_WALK_ERROR: 5806 if (cbdata.sc_err == EEXIST) { 5807 warn(emsg_pg_added, ient->sc_fmri, 5808 mpg->sc_pgroup_name); 5809 r = EBUSY; 5810 } else { 5811 r = cbdata.sc_err; 5812 } 5813 goto out; 5814 5815 default: 5816 bad_error("entity_pgroup_import", r); 5817 } 5818 } 5819 5820 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5821 internal_pgroup_free(curpg_i); 5822 switch (r) { 5823 case 0: 5824 ient->sc_import_state = IMPORT_PROP_BEGUN; 5825 break; 5826 5827 case ECANCELED: 5828 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5829 r = EBUSY; 5830 break; 5831 5832 case EPERM: 5833 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5834 break; 5835 5836 case EBUSY: 5837 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5838 break; 5839 5840 case ECONNABORTED: 5841 case ENOMEM: 5842 case ENOSPC: 5843 case EROFS: 5844 case EACCES: 5845 case EINVAL: 5846 break; 5847 5848 default: 5849 bad_error("upgrade_pg", r); 5850 } 5851 5852 out: 5853 internal_pgroup_free(lipg_i); 5854 return (r); 5855 } 5856 5857 /* 5858 * Upgrade the properties of ent according to snpl & ient. 5859 * 5860 * Returns 5861 * 0 - success 5862 * ECONNABORTED - repository connection broken 5863 * ENOMEM - out of memory 5864 * ENOSPC - configd is out of resources 5865 * ECANCELED - ent was deleted 5866 * ENODEV - entity containing snpl was deleted 5867 * - entity containing running was deleted 5868 * EBADF - imp_snpl is corrupt (error printed) 5869 * - ent has corrupt pg (error printed) 5870 * - dependent has corrupt pg (error printed) 5871 * - dependent target has a corrupt snapshot (error printed) 5872 * EBUSY - pg was added, changed, or deleted (error printed) 5873 * - dependent target was deleted (error printed) 5874 * - dependent pg changed (error printed) 5875 * EINVAL - invalid property group name (error printed) 5876 * - invalid property name (error printed) 5877 * - invalid value (error printed) 5878 * - ient has invalid pgroup or dependent (error printed) 5879 * EPERM - could not create property group (permission denied) (error printed) 5880 * - could not modify property group (permission denied) (error printed) 5881 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5882 * EROFS - could not create property group (repository read-only) 5883 * - couldn't delete, upgrade, or import pg or dependent 5884 * EACCES - could not create property group (backend access denied) 5885 * - couldn't delete, upgrade, or import pg or dependent 5886 * EEXIST - dependent collision in target service (error printed) 5887 */ 5888 static int 5889 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5890 entity_t *ient) 5891 { 5892 pgroup_t *pg, *rpg; 5893 int r; 5894 uu_list_t *pgs = ient->sc_pgroups; 5895 5896 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5897 5898 /* clear sc_sceen for pgs */ 5899 if (uu_list_walk(pgs, clear_int, 5900 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5901 bad_error("uu_list_walk", uu_error()); 5902 5903 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5904 switch (scf_error()) { 5905 case SCF_ERROR_DELETED: 5906 return (ENODEV); 5907 5908 case SCF_ERROR_CONNECTION_BROKEN: 5909 return (ECONNABORTED); 5910 5911 case SCF_ERROR_NOT_SET: 5912 case SCF_ERROR_NOT_BOUND: 5913 case SCF_ERROR_HANDLE_MISMATCH: 5914 default: 5915 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5916 } 5917 } 5918 5919 for (;;) { 5920 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5921 if (r == 0) 5922 break; 5923 if (r == 1) { 5924 r = process_old_pg(imp_pg, ient, ent, running); 5925 switch (r) { 5926 case 0: 5927 break; 5928 5929 case ECONNABORTED: 5930 case ENOMEM: 5931 case ENOSPC: 5932 case ECANCELED: 5933 case ENODEV: 5934 case EPERM: 5935 case EROFS: 5936 case EACCES: 5937 case EBADF: 5938 case EBUSY: 5939 case EINVAL: 5940 case EEXIST: 5941 return (r); 5942 5943 default: 5944 bad_error("process_old_pg", r); 5945 } 5946 continue; 5947 } 5948 if (r != -1) 5949 bad_error("scf_iter_next_pg", r); 5950 5951 switch (scf_error()) { 5952 case SCF_ERROR_DELETED: 5953 return (ENODEV); 5954 5955 case SCF_ERROR_CONNECTION_BROKEN: 5956 return (ECONNABORTED); 5957 5958 case SCF_ERROR_HANDLE_MISMATCH: 5959 case SCF_ERROR_NOT_BOUND: 5960 case SCF_ERROR_NOT_SET: 5961 case SCF_ERROR_INVALID_ARGUMENT: 5962 default: 5963 bad_error("scf_iter_next_pg", scf_error()); 5964 } 5965 } 5966 5967 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5968 if (pg->sc_pgroup_seen) 5969 continue; 5970 5971 /* pg is new */ 5972 5973 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5974 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5975 ent); 5976 switch (r) { 5977 case 0: 5978 break; 5979 5980 case ECONNABORTED: 5981 case ENOMEM: 5982 case ENOSPC: 5983 case ECANCELED: 5984 case ENODEV: 5985 case EBADF: 5986 case EBUSY: 5987 case EINVAL: 5988 case EPERM: 5989 case EROFS: 5990 case EACCES: 5991 case EEXIST: 5992 return (r); 5993 5994 default: 5995 bad_error("upgrade_dependents", r); 5996 } 5997 continue; 5998 } 5999 6000 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 6001 r = upgrade_manifestfiles(pg, ient, running, ent); 6002 switch (r) { 6003 case 0: 6004 break; 6005 6006 case ECONNABORTED: 6007 case ENOMEM: 6008 case ENOSPC: 6009 case ECANCELED: 6010 case ENODEV: 6011 case EBADF: 6012 case EBUSY: 6013 case EINVAL: 6014 case EPERM: 6015 case EROFS: 6016 case EACCES: 6017 case EEXIST: 6018 return (r); 6019 6020 default: 6021 bad_error("upgrade_manifestfiles", r); 6022 } 6023 continue; 6024 } 6025 6026 if (running != NULL) { 6027 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 6028 imp_pg); 6029 } else { 6030 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 6031 imp_pg); 6032 } 6033 if (r != 0) { 6034 scf_callback_t cbdata; 6035 6036 switch (scf_error()) { 6037 case SCF_ERROR_NOT_FOUND: 6038 break; 6039 6040 case SCF_ERROR_CONNECTION_BROKEN: 6041 return (scferror2errno(scf_error())); 6042 6043 case SCF_ERROR_DELETED: 6044 if (running != NULL) 6045 return (ENODEV); 6046 else 6047 return (scferror2errno(scf_error())); 6048 6049 case SCF_ERROR_INVALID_ARGUMENT: 6050 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 6051 pg->sc_pgroup_name); 6052 return (EINVAL); 6053 6054 case SCF_ERROR_NOT_SET: 6055 case SCF_ERROR_HANDLE_MISMATCH: 6056 case SCF_ERROR_NOT_BOUND: 6057 default: 6058 bad_error("entity_get_pg", scf_error()); 6059 } 6060 6061 /* User doesn't have pg, so import it. */ 6062 6063 cbdata.sc_handle = g_hndl; 6064 cbdata.sc_parent = ent; 6065 cbdata.sc_service = issvc; 6066 cbdata.sc_flags = SCI_FORCE; 6067 cbdata.sc_source_fmri = ient->sc_fmri; 6068 cbdata.sc_target_fmri = ient->sc_fmri; 6069 6070 r = entity_pgroup_import(pg, &cbdata); 6071 switch (r) { 6072 case UU_WALK_NEXT: 6073 ient->sc_import_state = IMPORT_PROP_BEGUN; 6074 continue; 6075 6076 case UU_WALK_ERROR: 6077 if (cbdata.sc_err == EEXIST) { 6078 warn(emsg_pg_added, ient->sc_fmri, 6079 pg->sc_pgroup_name); 6080 return (EBUSY); 6081 } 6082 return (cbdata.sc_err); 6083 6084 default: 6085 bad_error("entity_pgroup_import", r); 6086 } 6087 } 6088 6089 /* report differences between pg & current */ 6090 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 6091 switch (r) { 6092 case 0: 6093 break; 6094 6095 case ECANCELED: 6096 warn(emsg_pg_deleted, ient->sc_fmri, 6097 pg->sc_pgroup_name); 6098 return (EBUSY); 6099 6100 case ECONNABORTED: 6101 case EBADF: 6102 case ENOMEM: 6103 case EACCES: 6104 return (r); 6105 6106 default: 6107 bad_error("load_pg", r); 6108 } 6109 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 6110 internal_pgroup_free(rpg); 6111 rpg = NULL; 6112 } 6113 6114 return (0); 6115 } 6116 6117 /* 6118 * Import an instance. If it doesn't exist, create it. If it has 6119 * a last-import snapshot, upgrade its properties. Finish by updating its 6120 * last-import snapshot. If it doesn't have a last-import snapshot then it 6121 * could have been created for a dependent tag in another manifest. Import the 6122 * new properties. If there's a conflict, don't override, like now? 6123 * 6124 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 6125 * lcbdata->sc_err to 6126 * ECONNABORTED - repository connection broken 6127 * ENOMEM - out of memory 6128 * ENOSPC - svc.configd is out of resources 6129 * EEXIST - dependency collision in dependent service (error printed) 6130 * EPERM - couldn't create temporary instance (permission denied) 6131 * - couldn't import into temporary instance (permission denied) 6132 * - couldn't take snapshot (permission denied) 6133 * - couldn't upgrade properties (permission denied) 6134 * - couldn't import properties (permission denied) 6135 * - couldn't import dependents (permission denied) 6136 * EROFS - couldn't create temporary instance (repository read-only) 6137 * - couldn't import into temporary instance (repository read-only) 6138 * - couldn't upgrade properties (repository read-only) 6139 * - couldn't import properties (repository read-only) 6140 * - couldn't import dependents (repository read-only) 6141 * EACCES - couldn't create temporary instance (backend access denied) 6142 * - couldn't import into temporary instance (backend access denied) 6143 * - couldn't upgrade properties (backend access denied) 6144 * - couldn't import properties (backend access denied) 6145 * - couldn't import dependents (backend access denied) 6146 * EINVAL - invalid instance name (error printed) 6147 * - invalid pgroup_t's (error printed) 6148 * - invalid dependents (error printed) 6149 * EBUSY - temporary service deleted (error printed) 6150 * - temporary instance deleted (error printed) 6151 * - temporary instance changed (error printed) 6152 * - temporary instance already exists (error printed) 6153 * - instance deleted (error printed) 6154 * EBADF - instance has corrupt last-import snapshot (error printed) 6155 * - instance is corrupt (error printed) 6156 * - dependent has corrupt pg (error printed) 6157 * - dependent target has a corrupt snapshot (error printed) 6158 * -1 - unknown libscf error (error printed) 6159 */ 6160 static int 6161 lscf_instance_import(void *v, void *pvt) 6162 { 6163 entity_t *inst = v; 6164 scf_callback_t ctx; 6165 scf_callback_t *lcbdata = pvt; 6166 scf_service_t *rsvc = lcbdata->sc_parent; 6167 int r; 6168 scf_snaplevel_t *running; 6169 int flags = lcbdata->sc_flags; 6170 6171 const char * const emsg_tdel = 6172 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 6173 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 6174 "changed unexpectedly.\n"); 6175 const char * const emsg_del = gettext("%s changed unexpectedly " 6176 "(instance \"%s\" was deleted.)\n"); 6177 const char * const emsg_badsnap = gettext( 6178 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 6179 6180 /* 6181 * prepare last-import snapshot: 6182 * create temporary instance (service was precreated) 6183 * populate with properties from bundle 6184 * take snapshot 6185 */ 6186 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 6187 switch (scf_error()) { 6188 case SCF_ERROR_CONNECTION_BROKEN: 6189 case SCF_ERROR_NO_RESOURCES: 6190 case SCF_ERROR_BACKEND_READONLY: 6191 case SCF_ERROR_BACKEND_ACCESS: 6192 return (stash_scferror(lcbdata)); 6193 6194 case SCF_ERROR_EXISTS: 6195 warn(gettext("Temporary service svc:/%s " 6196 "changed unexpectedly (instance \"%s\" added).\n"), 6197 imp_tsname, inst->sc_name); 6198 lcbdata->sc_err = EBUSY; 6199 return (UU_WALK_ERROR); 6200 6201 case SCF_ERROR_DELETED: 6202 warn(gettext("Temporary service svc:/%s " 6203 "was deleted unexpectedly.\n"), imp_tsname); 6204 lcbdata->sc_err = EBUSY; 6205 return (UU_WALK_ERROR); 6206 6207 case SCF_ERROR_INVALID_ARGUMENT: 6208 warn(gettext("Invalid instance name \"%s\".\n"), 6209 inst->sc_name); 6210 return (stash_scferror(lcbdata)); 6211 6212 case SCF_ERROR_PERMISSION_DENIED: 6213 warn(gettext("Could not create temporary instance " 6214 "\"%s\" in svc:/%s (permission denied).\n"), 6215 inst->sc_name, imp_tsname); 6216 return (stash_scferror(lcbdata)); 6217 6218 case SCF_ERROR_HANDLE_MISMATCH: 6219 case SCF_ERROR_NOT_BOUND: 6220 case SCF_ERROR_NOT_SET: 6221 default: 6222 bad_error("scf_service_add_instance", scf_error()); 6223 } 6224 } 6225 6226 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6227 inst->sc_name); 6228 if (r < 0) 6229 bad_error("snprintf", errno); 6230 6231 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 6232 lcbdata->sc_flags | SCI_NOENABLED); 6233 switch (r) { 6234 case 0: 6235 break; 6236 6237 case ECANCELED: 6238 warn(emsg_tdel, imp_tsname, inst->sc_name); 6239 lcbdata->sc_err = EBUSY; 6240 r = UU_WALK_ERROR; 6241 goto deltemp; 6242 6243 case EEXIST: 6244 warn(emsg_tchg, imp_tsname, inst->sc_name); 6245 lcbdata->sc_err = EBUSY; 6246 r = UU_WALK_ERROR; 6247 goto deltemp; 6248 6249 case ECONNABORTED: 6250 goto connaborted; 6251 6252 case ENOMEM: 6253 case ENOSPC: 6254 case EPERM: 6255 case EROFS: 6256 case EACCES: 6257 case EINVAL: 6258 case EBUSY: 6259 lcbdata->sc_err = r; 6260 r = UU_WALK_ERROR; 6261 goto deltemp; 6262 6263 default: 6264 bad_error("lscf_import_instance_pgs", r); 6265 } 6266 6267 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6268 inst->sc_name); 6269 if (r < 0) 6270 bad_error("snprintf", errno); 6271 6272 ctx.sc_handle = lcbdata->sc_handle; 6273 ctx.sc_parent = imp_tinst; 6274 ctx.sc_service = 0; 6275 ctx.sc_source_fmri = inst->sc_fmri; 6276 ctx.sc_target_fmri = imp_str; 6277 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 6278 UU_DEFAULT) != 0) { 6279 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6280 bad_error("uu_list_walk", uu_error()); 6281 6282 switch (ctx.sc_err) { 6283 case ECONNABORTED: 6284 goto connaborted; 6285 6286 case ECANCELED: 6287 warn(emsg_tdel, imp_tsname, inst->sc_name); 6288 lcbdata->sc_err = EBUSY; 6289 break; 6290 6291 case EEXIST: 6292 warn(emsg_tchg, imp_tsname, inst->sc_name); 6293 lcbdata->sc_err = EBUSY; 6294 break; 6295 6296 default: 6297 lcbdata->sc_err = ctx.sc_err; 6298 } 6299 r = UU_WALK_ERROR; 6300 goto deltemp; 6301 } 6302 6303 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 6304 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 6305 switch (scf_error()) { 6306 case SCF_ERROR_CONNECTION_BROKEN: 6307 goto connaborted; 6308 6309 case SCF_ERROR_NO_RESOURCES: 6310 r = stash_scferror(lcbdata); 6311 goto deltemp; 6312 6313 case SCF_ERROR_EXISTS: 6314 warn(emsg_tchg, imp_tsname, inst->sc_name); 6315 lcbdata->sc_err = EBUSY; 6316 r = UU_WALK_ERROR; 6317 goto deltemp; 6318 6319 case SCF_ERROR_PERMISSION_DENIED: 6320 warn(gettext("Could not take \"%s\" snapshot of %s " 6321 "(permission denied).\n"), snap_lastimport, 6322 imp_str); 6323 r = stash_scferror(lcbdata); 6324 goto deltemp; 6325 6326 default: 6327 scfwarn(); 6328 lcbdata->sc_err = -1; 6329 r = UU_WALK_ERROR; 6330 goto deltemp; 6331 6332 case SCF_ERROR_HANDLE_MISMATCH: 6333 case SCF_ERROR_INVALID_ARGUMENT: 6334 case SCF_ERROR_NOT_SET: 6335 bad_error("_scf_snapshot_take_new_named", scf_error()); 6336 } 6337 } 6338 6339 if (lcbdata->sc_flags & SCI_FRESH) 6340 goto fresh; 6341 6342 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 6343 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6344 imp_lisnap) != 0) { 6345 switch (scf_error()) { 6346 case SCF_ERROR_DELETED: 6347 warn(emsg_del, inst->sc_parent->sc_fmri, 6348 inst->sc_name); 6349 lcbdata->sc_err = EBUSY; 6350 r = UU_WALK_ERROR; 6351 goto deltemp; 6352 6353 case SCF_ERROR_NOT_FOUND: 6354 flags |= SCI_FORCE; 6355 goto nosnap; 6356 6357 case SCF_ERROR_CONNECTION_BROKEN: 6358 goto connaborted; 6359 6360 case SCF_ERROR_INVALID_ARGUMENT: 6361 case SCF_ERROR_HANDLE_MISMATCH: 6362 case SCF_ERROR_NOT_BOUND: 6363 case SCF_ERROR_NOT_SET: 6364 default: 6365 bad_error("scf_instance_get_snapshot", 6366 scf_error()); 6367 } 6368 } 6369 6370 /* upgrade */ 6371 6372 /* 6373 * compare new properties with last-import properties 6374 * upgrade current properties 6375 */ 6376 /* clear sc_sceen for pgs */ 6377 if (uu_list_walk(inst->sc_pgroups, clear_int, 6378 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 6379 0) 6380 bad_error("uu_list_walk", uu_error()); 6381 6382 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 6383 switch (r) { 6384 case 0: 6385 break; 6386 6387 case ECONNABORTED: 6388 goto connaborted; 6389 6390 case ECANCELED: 6391 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6392 lcbdata->sc_err = EBUSY; 6393 r = UU_WALK_ERROR; 6394 goto deltemp; 6395 6396 case ENOENT: 6397 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 6398 lcbdata->sc_err = EBADF; 6399 r = UU_WALK_ERROR; 6400 goto deltemp; 6401 6402 default: 6403 bad_error("get_snaplevel", r); 6404 } 6405 6406 if (scf_instance_get_snapshot(imp_inst, snap_running, 6407 imp_rsnap) != 0) { 6408 switch (scf_error()) { 6409 case SCF_ERROR_DELETED: 6410 warn(emsg_del, inst->sc_parent->sc_fmri, 6411 inst->sc_name); 6412 lcbdata->sc_err = EBUSY; 6413 r = UU_WALK_ERROR; 6414 goto deltemp; 6415 6416 case SCF_ERROR_NOT_FOUND: 6417 break; 6418 6419 case SCF_ERROR_CONNECTION_BROKEN: 6420 goto connaborted; 6421 6422 case SCF_ERROR_INVALID_ARGUMENT: 6423 case SCF_ERROR_HANDLE_MISMATCH: 6424 case SCF_ERROR_NOT_BOUND: 6425 case SCF_ERROR_NOT_SET: 6426 default: 6427 bad_error("scf_instance_get_snapshot", 6428 scf_error()); 6429 } 6430 6431 running = NULL; 6432 } else { 6433 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 6434 switch (r) { 6435 case 0: 6436 running = imp_rsnpl; 6437 break; 6438 6439 case ECONNABORTED: 6440 goto connaborted; 6441 6442 case ECANCELED: 6443 warn(emsg_del, inst->sc_parent->sc_fmri, 6444 inst->sc_name); 6445 lcbdata->sc_err = EBUSY; 6446 r = UU_WALK_ERROR; 6447 goto deltemp; 6448 6449 case ENOENT: 6450 warn(emsg_badsnap, snap_running, inst->sc_fmri); 6451 lcbdata->sc_err = EBADF; 6452 r = UU_WALK_ERROR; 6453 goto deltemp; 6454 6455 default: 6456 bad_error("get_snaplevel", r); 6457 } 6458 } 6459 6460 r = upgrade_props(imp_inst, running, imp_snpl, inst); 6461 switch (r) { 6462 case 0: 6463 break; 6464 6465 case ECANCELED: 6466 case ENODEV: 6467 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6468 lcbdata->sc_err = EBUSY; 6469 r = UU_WALK_ERROR; 6470 goto deltemp; 6471 6472 case ECONNABORTED: 6473 goto connaborted; 6474 6475 case ENOMEM: 6476 case ENOSPC: 6477 case EBADF: 6478 case EBUSY: 6479 case EINVAL: 6480 case EPERM: 6481 case EROFS: 6482 case EACCES: 6483 case EEXIST: 6484 lcbdata->sc_err = r; 6485 r = UU_WALK_ERROR; 6486 goto deltemp; 6487 6488 default: 6489 bad_error("upgrade_props", r); 6490 } 6491 6492 inst->sc_import_state = IMPORT_PROP_DONE; 6493 } else { 6494 switch (scf_error()) { 6495 case SCF_ERROR_CONNECTION_BROKEN: 6496 goto connaborted; 6497 6498 case SCF_ERROR_NOT_FOUND: 6499 break; 6500 6501 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6502 case SCF_ERROR_HANDLE_MISMATCH: 6503 case SCF_ERROR_NOT_BOUND: 6504 case SCF_ERROR_NOT_SET: 6505 default: 6506 bad_error("scf_service_get_instance", scf_error()); 6507 } 6508 6509 fresh: 6510 /* create instance */ 6511 if (scf_service_add_instance(rsvc, inst->sc_name, 6512 imp_inst) != 0) { 6513 switch (scf_error()) { 6514 case SCF_ERROR_CONNECTION_BROKEN: 6515 goto connaborted; 6516 6517 case SCF_ERROR_NO_RESOURCES: 6518 case SCF_ERROR_BACKEND_READONLY: 6519 case SCF_ERROR_BACKEND_ACCESS: 6520 r = stash_scferror(lcbdata); 6521 goto deltemp; 6522 6523 case SCF_ERROR_EXISTS: 6524 warn(gettext("%s changed unexpectedly " 6525 "(instance \"%s\" added).\n"), 6526 inst->sc_parent->sc_fmri, inst->sc_name); 6527 lcbdata->sc_err = EBUSY; 6528 r = UU_WALK_ERROR; 6529 goto deltemp; 6530 6531 case SCF_ERROR_PERMISSION_DENIED: 6532 warn(gettext("Could not create \"%s\" instance " 6533 "in %s (permission denied).\n"), 6534 inst->sc_name, inst->sc_parent->sc_fmri); 6535 r = stash_scferror(lcbdata); 6536 goto deltemp; 6537 6538 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6539 case SCF_ERROR_HANDLE_MISMATCH: 6540 case SCF_ERROR_NOT_BOUND: 6541 case SCF_ERROR_NOT_SET: 6542 default: 6543 bad_error("scf_service_add_instance", 6544 scf_error()); 6545 } 6546 } 6547 6548 nosnap: 6549 /* 6550 * Create a last-import snapshot to serve as an attachment 6551 * point for the real one from the temporary instance. Since 6552 * the contents is irrelevant, take it now, while the instance 6553 * is empty, to minimize svc.configd's work. 6554 */ 6555 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6556 imp_lisnap) != 0) { 6557 switch (scf_error()) { 6558 case SCF_ERROR_CONNECTION_BROKEN: 6559 goto connaborted; 6560 6561 case SCF_ERROR_NO_RESOURCES: 6562 r = stash_scferror(lcbdata); 6563 goto deltemp; 6564 6565 case SCF_ERROR_EXISTS: 6566 warn(gettext("%s changed unexpectedly " 6567 "(snapshot \"%s\" added).\n"), 6568 inst->sc_fmri, snap_lastimport); 6569 lcbdata->sc_err = EBUSY; 6570 r = UU_WALK_ERROR; 6571 goto deltemp; 6572 6573 case SCF_ERROR_PERMISSION_DENIED: 6574 warn(gettext("Could not take \"%s\" snapshot " 6575 "of %s (permission denied).\n"), 6576 snap_lastimport, inst->sc_fmri); 6577 r = stash_scferror(lcbdata); 6578 goto deltemp; 6579 6580 default: 6581 scfwarn(); 6582 lcbdata->sc_err = -1; 6583 r = UU_WALK_ERROR; 6584 goto deltemp; 6585 6586 case SCF_ERROR_NOT_SET: 6587 case SCF_ERROR_INTERNAL: 6588 case SCF_ERROR_INVALID_ARGUMENT: 6589 case SCF_ERROR_HANDLE_MISMATCH: 6590 bad_error("_scf_snapshot_take_new", 6591 scf_error()); 6592 } 6593 } 6594 6595 if (li_only) 6596 goto lionly; 6597 6598 inst->sc_import_state = IMPORT_PROP_BEGUN; 6599 6600 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6601 flags); 6602 switch (r) { 6603 case 0: 6604 break; 6605 6606 case ECONNABORTED: 6607 goto connaborted; 6608 6609 case ECANCELED: 6610 warn(gettext("%s changed unexpectedly " 6611 "(instance \"%s\" deleted).\n"), 6612 inst->sc_parent->sc_fmri, inst->sc_name); 6613 lcbdata->sc_err = EBUSY; 6614 r = UU_WALK_ERROR; 6615 goto deltemp; 6616 6617 case EEXIST: 6618 warn(gettext("%s changed unexpectedly " 6619 "(property group added).\n"), inst->sc_fmri); 6620 lcbdata->sc_err = EBUSY; 6621 r = UU_WALK_ERROR; 6622 goto deltemp; 6623 6624 default: 6625 lcbdata->sc_err = r; 6626 r = UU_WALK_ERROR; 6627 goto deltemp; 6628 6629 case EINVAL: /* caught above */ 6630 bad_error("lscf_import_instance_pgs", r); 6631 } 6632 6633 ctx.sc_parent = imp_inst; 6634 ctx.sc_service = 0; 6635 ctx.sc_trans = NULL; 6636 ctx.sc_flags = 0; 6637 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6638 &ctx, UU_DEFAULT) != 0) { 6639 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6640 bad_error("uu_list_walk", uu_error()); 6641 6642 if (ctx.sc_err == ECONNABORTED) 6643 goto connaborted; 6644 lcbdata->sc_err = ctx.sc_err; 6645 r = UU_WALK_ERROR; 6646 goto deltemp; 6647 } 6648 6649 inst->sc_import_state = IMPORT_PROP_DONE; 6650 6651 if (g_verbose) 6652 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6653 snap_initial, inst->sc_fmri); 6654 r = take_snap(imp_inst, snap_initial, imp_snap); 6655 switch (r) { 6656 case 0: 6657 break; 6658 6659 case ECONNABORTED: 6660 goto connaborted; 6661 6662 case ENOSPC: 6663 case -1: 6664 lcbdata->sc_err = r; 6665 r = UU_WALK_ERROR; 6666 goto deltemp; 6667 6668 case ECANCELED: 6669 warn(gettext("%s changed unexpectedly " 6670 "(instance %s deleted).\n"), 6671 inst->sc_parent->sc_fmri, inst->sc_name); 6672 lcbdata->sc_err = r; 6673 r = UU_WALK_ERROR; 6674 goto deltemp; 6675 6676 case EPERM: 6677 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6678 lcbdata->sc_err = r; 6679 r = UU_WALK_ERROR; 6680 goto deltemp; 6681 6682 default: 6683 bad_error("take_snap", r); 6684 } 6685 } 6686 6687 lionly: 6688 if (lcbdata->sc_flags & SCI_NOSNAP) 6689 goto deltemp; 6690 6691 /* transfer snapshot from temporary instance */ 6692 if (g_verbose) 6693 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6694 snap_lastimport, inst->sc_fmri); 6695 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6696 switch (scf_error()) { 6697 case SCF_ERROR_CONNECTION_BROKEN: 6698 goto connaborted; 6699 6700 case SCF_ERROR_NO_RESOURCES: 6701 r = stash_scferror(lcbdata); 6702 goto deltemp; 6703 6704 case SCF_ERROR_PERMISSION_DENIED: 6705 warn(gettext("Could not take \"%s\" snapshot for %s " 6706 "(permission denied).\n"), snap_lastimport, 6707 inst->sc_fmri); 6708 r = stash_scferror(lcbdata); 6709 goto deltemp; 6710 6711 case SCF_ERROR_NOT_SET: 6712 case SCF_ERROR_HANDLE_MISMATCH: 6713 default: 6714 bad_error("_scf_snapshot_attach", scf_error()); 6715 } 6716 } 6717 6718 inst->sc_import_state = IMPORT_COMPLETE; 6719 6720 r = UU_WALK_NEXT; 6721 6722 deltemp: 6723 /* delete temporary instance */ 6724 if (scf_instance_delete(imp_tinst) != 0) { 6725 switch (scf_error()) { 6726 case SCF_ERROR_DELETED: 6727 break; 6728 6729 case SCF_ERROR_CONNECTION_BROKEN: 6730 goto connaborted; 6731 6732 case SCF_ERROR_NOT_SET: 6733 case SCF_ERROR_NOT_BOUND: 6734 default: 6735 bad_error("scf_instance_delete", scf_error()); 6736 } 6737 } 6738 6739 return (r); 6740 6741 connaborted: 6742 warn(gettext("Could not delete svc:/%s:%s " 6743 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6744 lcbdata->sc_err = ECONNABORTED; 6745 return (UU_WALK_ERROR); 6746 } 6747 6748 /* 6749 * If the service is missing, create it, import its properties, and import the 6750 * instances. Since the service is brand new, it should be empty, and if we 6751 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6752 * 6753 * If the service exists, we want to upgrade its properties and import the 6754 * instances. Upgrade requires a last-import snapshot, though, which are 6755 * children of instances, so first we'll have to go through the instances 6756 * looking for a last-import snapshot. If we don't find one then we'll just 6757 * override-import the service properties (but don't delete existing 6758 * properties: another service might have declared us as a dependent). Before 6759 * we change anything, though, we want to take the previous snapshots. We 6760 * also give lscf_instance_import() a leg up on taking last-import snapshots 6761 * by importing the manifest's service properties into a temporary service. 6762 * 6763 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6764 * sets lcbdata->sc_err to 6765 * ECONNABORTED - repository connection broken 6766 * ENOMEM - out of memory 6767 * ENOSPC - svc.configd is out of resources 6768 * EPERM - couldn't create temporary service (error printed) 6769 * - couldn't import into temp service (error printed) 6770 * - couldn't create service (error printed) 6771 * - couldn't import dependent (error printed) 6772 * - couldn't take snapshot (error printed) 6773 * - couldn't create instance (error printed) 6774 * - couldn't create, modify, or delete pg (error printed) 6775 * - couldn't create, modify, or delete dependent (error printed) 6776 * - couldn't import instance (error printed) 6777 * EROFS - couldn't create temporary service (repository read-only) 6778 * - couldn't import into temporary service (repository read-only) 6779 * - couldn't create service (repository read-only) 6780 * - couldn't import dependent (repository read-only) 6781 * - couldn't create instance (repository read-only) 6782 * - couldn't create, modify, or delete pg or dependent 6783 * - couldn't import instance (repository read-only) 6784 * EACCES - couldn't create temporary service (backend access denied) 6785 * - couldn't import into temporary service (backend access denied) 6786 * - couldn't create service (backend access denied) 6787 * - couldn't import dependent (backend access denied) 6788 * - couldn't create instance (backend access denied) 6789 * - couldn't create, modify, or delete pg or dependent 6790 * - couldn't import instance (backend access denied) 6791 * EINVAL - service name is invalid (error printed) 6792 * - service name is too long (error printed) 6793 * - s has invalid pgroup (error printed) 6794 * - s has invalid dependent (error printed) 6795 * - instance name is invalid (error printed) 6796 * - instance entity_t is invalid (error printed) 6797 * EEXIST - couldn't create temporary service (already exists) (error printed) 6798 * - couldn't import dependent (dependency pg already exists) (printed) 6799 * - dependency collision in dependent service (error printed) 6800 * EBUSY - temporary service deleted (error printed) 6801 * - property group added to temporary service (error printed) 6802 * - new property group changed or was deleted (error printed) 6803 * - service was added unexpectedly (error printed) 6804 * - service was deleted unexpectedly (error printed) 6805 * - property group added to new service (error printed) 6806 * - instance added unexpectedly (error printed) 6807 * - instance deleted unexpectedly (error printed) 6808 * - dependent service deleted unexpectedly (error printed) 6809 * - pg was added, changed, or deleted (error printed) 6810 * - dependent pg changed (error printed) 6811 * - temporary instance added, changed, or deleted (error printed) 6812 * EBADF - a last-import snapshot is corrupt (error printed) 6813 * - the service is corrupt (error printed) 6814 * - a dependent is corrupt (error printed) 6815 * - an instance is corrupt (error printed) 6816 * - an instance has a corrupt last-import snapshot (error printed) 6817 * - dependent target has a corrupt snapshot (error printed) 6818 * -1 - unknown libscf error (error printed) 6819 */ 6820 static int 6821 lscf_service_import(void *v, void *pvt) 6822 { 6823 entity_t *s = v; 6824 scf_callback_t cbdata; 6825 scf_callback_t *lcbdata = pvt; 6826 scf_scope_t *scope = lcbdata->sc_parent; 6827 entity_t *inst, linst; 6828 int r; 6829 int fresh = 0; 6830 scf_snaplevel_t *running; 6831 int have_ge = 0; 6832 6833 const char * const ts_deleted = gettext("Temporary service svc:/%s " 6834 "was deleted unexpectedly.\n"); 6835 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 6836 "changed unexpectedly (property group added).\n"); 6837 const char * const s_deleted = 6838 gettext("%s was deleted unexpectedly.\n"); 6839 const char * const i_deleted = 6840 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 6841 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 6842 "is corrupt (missing service snaplevel).\n"); 6843 const char * const s_mfile_upd = 6844 gettext("Unable to update the manifest file connection " 6845 "for %s\n"); 6846 6847 li_only = 0; 6848 /* Validate the service name */ 6849 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6850 switch (scf_error()) { 6851 case SCF_ERROR_CONNECTION_BROKEN: 6852 return (stash_scferror(lcbdata)); 6853 6854 case SCF_ERROR_INVALID_ARGUMENT: 6855 warn(gettext("\"%s\" is an invalid service name. " 6856 "Cannot import.\n"), s->sc_name); 6857 return (stash_scferror(lcbdata)); 6858 6859 case SCF_ERROR_NOT_FOUND: 6860 break; 6861 6862 case SCF_ERROR_HANDLE_MISMATCH: 6863 case SCF_ERROR_NOT_BOUND: 6864 case SCF_ERROR_NOT_SET: 6865 default: 6866 bad_error("scf_scope_get_service", scf_error()); 6867 } 6868 } 6869 6870 /* create temporary service */ 6871 /* 6872 * the size of the buffer was reduced to max_scf_name_len to prevent 6873 * hitting bug 6681151. After the bug fix, the size of the buffer 6874 * should be restored to its original value (max_scf_name_len +1) 6875 */ 6876 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 6877 if (r < 0) 6878 bad_error("snprintf", errno); 6879 if (r > max_scf_name_len) { 6880 warn(gettext( 6881 "Service name \"%s\" is too long. Cannot import.\n"), 6882 s->sc_name); 6883 lcbdata->sc_err = EINVAL; 6884 return (UU_WALK_ERROR); 6885 } 6886 6887 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 6888 switch (scf_error()) { 6889 case SCF_ERROR_CONNECTION_BROKEN: 6890 case SCF_ERROR_NO_RESOURCES: 6891 case SCF_ERROR_BACKEND_READONLY: 6892 case SCF_ERROR_BACKEND_ACCESS: 6893 return (stash_scferror(lcbdata)); 6894 6895 case SCF_ERROR_EXISTS: 6896 warn(gettext( 6897 "Temporary service \"%s\" must be deleted before " 6898 "this manifest can be imported.\n"), imp_tsname); 6899 return (stash_scferror(lcbdata)); 6900 6901 case SCF_ERROR_PERMISSION_DENIED: 6902 warn(gettext("Could not create temporary service " 6903 "\"%s\" (permission denied).\n"), imp_tsname); 6904 return (stash_scferror(lcbdata)); 6905 6906 case SCF_ERROR_INVALID_ARGUMENT: 6907 case SCF_ERROR_HANDLE_MISMATCH: 6908 case SCF_ERROR_NOT_BOUND: 6909 case SCF_ERROR_NOT_SET: 6910 default: 6911 bad_error("scf_scope_add_service", scf_error()); 6912 } 6913 } 6914 6915 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 6916 if (r < 0) 6917 bad_error("snprintf", errno); 6918 6919 cbdata.sc_handle = lcbdata->sc_handle; 6920 cbdata.sc_parent = imp_tsvc; 6921 cbdata.sc_service = 1; 6922 cbdata.sc_source_fmri = s->sc_fmri; 6923 cbdata.sc_target_fmri = imp_str; 6924 cbdata.sc_flags = 0; 6925 6926 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 6927 UU_DEFAULT) != 0) { 6928 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6929 bad_error("uu_list_walk", uu_error()); 6930 6931 lcbdata->sc_err = cbdata.sc_err; 6932 switch (cbdata.sc_err) { 6933 case ECONNABORTED: 6934 goto connaborted; 6935 6936 case ECANCELED: 6937 warn(ts_deleted, imp_tsname); 6938 lcbdata->sc_err = EBUSY; 6939 return (UU_WALK_ERROR); 6940 6941 case EEXIST: 6942 warn(ts_pg_added, imp_tsname); 6943 lcbdata->sc_err = EBUSY; 6944 return (UU_WALK_ERROR); 6945 } 6946 6947 r = UU_WALK_ERROR; 6948 goto deltemp; 6949 } 6950 6951 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 6952 UU_DEFAULT) != 0) { 6953 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6954 bad_error("uu_list_walk", uu_error()); 6955 6956 lcbdata->sc_err = cbdata.sc_err; 6957 switch (cbdata.sc_err) { 6958 case ECONNABORTED: 6959 goto connaborted; 6960 6961 case ECANCELED: 6962 warn(ts_deleted, imp_tsname); 6963 lcbdata->sc_err = EBUSY; 6964 return (UU_WALK_ERROR); 6965 6966 case EEXIST: 6967 warn(ts_pg_added, imp_tsname); 6968 lcbdata->sc_err = EBUSY; 6969 return (UU_WALK_ERROR); 6970 } 6971 6972 r = UU_WALK_ERROR; 6973 goto deltemp; 6974 } 6975 6976 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6977 switch (scf_error()) { 6978 case SCF_ERROR_NOT_FOUND: 6979 break; 6980 6981 case SCF_ERROR_CONNECTION_BROKEN: 6982 goto connaborted; 6983 6984 case SCF_ERROR_INVALID_ARGUMENT: 6985 case SCF_ERROR_HANDLE_MISMATCH: 6986 case SCF_ERROR_NOT_BOUND: 6987 case SCF_ERROR_NOT_SET: 6988 default: 6989 bad_error("scf_scope_get_service", scf_error()); 6990 } 6991 6992 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 6993 switch (scf_error()) { 6994 case SCF_ERROR_CONNECTION_BROKEN: 6995 goto connaborted; 6996 6997 case SCF_ERROR_NO_RESOURCES: 6998 case SCF_ERROR_BACKEND_READONLY: 6999 case SCF_ERROR_BACKEND_ACCESS: 7000 r = stash_scferror(lcbdata); 7001 goto deltemp; 7002 7003 case SCF_ERROR_EXISTS: 7004 warn(gettext("Scope \"%s\" changed unexpectedly" 7005 " (service \"%s\" added).\n"), 7006 SCF_SCOPE_LOCAL, s->sc_name); 7007 lcbdata->sc_err = EBUSY; 7008 goto deltemp; 7009 7010 case SCF_ERROR_PERMISSION_DENIED: 7011 warn(gettext("Could not create service \"%s\" " 7012 "(permission denied).\n"), s->sc_name); 7013 goto deltemp; 7014 7015 case SCF_ERROR_INVALID_ARGUMENT: 7016 case SCF_ERROR_HANDLE_MISMATCH: 7017 case SCF_ERROR_NOT_BOUND: 7018 case SCF_ERROR_NOT_SET: 7019 default: 7020 bad_error("scf_scope_add_service", scf_error()); 7021 } 7022 } 7023 7024 s->sc_import_state = IMPORT_PROP_BEGUN; 7025 7026 /* import service properties */ 7027 cbdata.sc_handle = lcbdata->sc_handle; 7028 cbdata.sc_parent = imp_svc; 7029 cbdata.sc_service = 1; 7030 cbdata.sc_flags = lcbdata->sc_flags; 7031 cbdata.sc_source_fmri = s->sc_fmri; 7032 cbdata.sc_target_fmri = s->sc_fmri; 7033 7034 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7035 &cbdata, UU_DEFAULT) != 0) { 7036 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7037 bad_error("uu_list_walk", uu_error()); 7038 7039 lcbdata->sc_err = cbdata.sc_err; 7040 switch (cbdata.sc_err) { 7041 case ECONNABORTED: 7042 goto connaborted; 7043 7044 case ECANCELED: 7045 warn(s_deleted, s->sc_fmri); 7046 lcbdata->sc_err = EBUSY; 7047 return (UU_WALK_ERROR); 7048 7049 case EEXIST: 7050 warn(gettext("%s changed unexpectedly " 7051 "(property group added).\n"), s->sc_fmri); 7052 lcbdata->sc_err = EBUSY; 7053 return (UU_WALK_ERROR); 7054 7055 case EINVAL: 7056 /* caught above */ 7057 bad_error("entity_pgroup_import", 7058 cbdata.sc_err); 7059 } 7060 7061 r = UU_WALK_ERROR; 7062 goto deltemp; 7063 } 7064 7065 cbdata.sc_trans = NULL; 7066 cbdata.sc_flags = 0; 7067 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 7068 &cbdata, UU_DEFAULT) != 0) { 7069 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7070 bad_error("uu_list_walk", uu_error()); 7071 7072 lcbdata->sc_err = cbdata.sc_err; 7073 if (cbdata.sc_err == ECONNABORTED) 7074 goto connaborted; 7075 r = UU_WALK_ERROR; 7076 goto deltemp; 7077 } 7078 7079 s->sc_import_state = IMPORT_PROP_DONE; 7080 7081 /* 7082 * This is a new service, so we can't take previous snapshots 7083 * or upgrade service properties. 7084 */ 7085 fresh = 1; 7086 goto instances; 7087 } 7088 7089 /* Clear sc_seen for the instances. */ 7090 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 7091 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 7092 bad_error("uu_list_walk", uu_error()); 7093 7094 /* 7095 * Take previous snapshots for all instances. Even for ones not 7096 * mentioned in the bundle, since we might change their service 7097 * properties. 7098 */ 7099 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7100 switch (scf_error()) { 7101 case SCF_ERROR_CONNECTION_BROKEN: 7102 goto connaborted; 7103 7104 case SCF_ERROR_DELETED: 7105 warn(s_deleted, s->sc_fmri); 7106 lcbdata->sc_err = EBUSY; 7107 r = UU_WALK_ERROR; 7108 goto deltemp; 7109 7110 case SCF_ERROR_HANDLE_MISMATCH: 7111 case SCF_ERROR_NOT_BOUND: 7112 case SCF_ERROR_NOT_SET: 7113 default: 7114 bad_error("scf_iter_service_instances", scf_error()); 7115 } 7116 } 7117 7118 for (;;) { 7119 r = scf_iter_next_instance(imp_iter, imp_inst); 7120 if (r == 0) 7121 break; 7122 if (r != 1) { 7123 switch (scf_error()) { 7124 case SCF_ERROR_DELETED: 7125 warn(s_deleted, s->sc_fmri); 7126 lcbdata->sc_err = EBUSY; 7127 r = UU_WALK_ERROR; 7128 goto deltemp; 7129 7130 case SCF_ERROR_CONNECTION_BROKEN: 7131 goto connaborted; 7132 7133 case SCF_ERROR_NOT_BOUND: 7134 case SCF_ERROR_HANDLE_MISMATCH: 7135 case SCF_ERROR_INVALID_ARGUMENT: 7136 case SCF_ERROR_NOT_SET: 7137 default: 7138 bad_error("scf_iter_next_instance", 7139 scf_error()); 7140 } 7141 } 7142 7143 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 7144 switch (scf_error()) { 7145 case SCF_ERROR_DELETED: 7146 continue; 7147 7148 case SCF_ERROR_CONNECTION_BROKEN: 7149 goto connaborted; 7150 7151 case SCF_ERROR_NOT_SET: 7152 case SCF_ERROR_NOT_BOUND: 7153 default: 7154 bad_error("scf_instance_get_name", scf_error()); 7155 } 7156 } 7157 7158 if (g_verbose) 7159 warn(gettext( 7160 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 7161 snap_previous, s->sc_name, imp_str); 7162 7163 r = take_snap(imp_inst, snap_previous, imp_snap); 7164 switch (r) { 7165 case 0: 7166 break; 7167 7168 case ECANCELED: 7169 continue; 7170 7171 case ECONNABORTED: 7172 goto connaborted; 7173 7174 case EPERM: 7175 warn(gettext("Could not take \"%s\" snapshot of " 7176 "svc:/%s:%s (permission denied).\n"), 7177 snap_previous, s->sc_name, imp_str); 7178 lcbdata->sc_err = r; 7179 return (UU_WALK_ERROR); 7180 7181 case ENOSPC: 7182 case -1: 7183 lcbdata->sc_err = r; 7184 r = UU_WALK_ERROR; 7185 goto deltemp; 7186 7187 default: 7188 bad_error("take_snap", r); 7189 } 7190 7191 linst.sc_name = imp_str; 7192 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 7193 &linst, NULL, NULL); 7194 if (inst != NULL) { 7195 inst->sc_import_state = IMPORT_PREVIOUS; 7196 inst->sc_seen = 1; 7197 } 7198 } 7199 7200 /* 7201 * Create the new instances and take previous snapshots of 7202 * them. This is not necessary, but it maximizes data preservation. 7203 */ 7204 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 7205 inst != NULL; 7206 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 7207 inst)) { 7208 if (inst->sc_seen) 7209 continue; 7210 7211 if (scf_service_add_instance(imp_svc, inst->sc_name, 7212 imp_inst) != 0) { 7213 switch (scf_error()) { 7214 case SCF_ERROR_CONNECTION_BROKEN: 7215 goto connaborted; 7216 7217 case SCF_ERROR_BACKEND_READONLY: 7218 case SCF_ERROR_BACKEND_ACCESS: 7219 case SCF_ERROR_NO_RESOURCES: 7220 r = stash_scferror(lcbdata); 7221 goto deltemp; 7222 7223 case SCF_ERROR_EXISTS: 7224 warn(gettext("%s changed unexpectedly " 7225 "(instance \"%s\" added).\n"), s->sc_fmri, 7226 inst->sc_name); 7227 lcbdata->sc_err = EBUSY; 7228 r = UU_WALK_ERROR; 7229 goto deltemp; 7230 7231 case SCF_ERROR_INVALID_ARGUMENT: 7232 warn(gettext("Service \"%s\" has instance with " 7233 "invalid name \"%s\".\n"), s->sc_name, 7234 inst->sc_name); 7235 r = stash_scferror(lcbdata); 7236 goto deltemp; 7237 7238 case SCF_ERROR_PERMISSION_DENIED: 7239 warn(gettext("Could not create instance \"%s\" " 7240 "in %s (permission denied).\n"), 7241 inst->sc_name, s->sc_fmri); 7242 r = stash_scferror(lcbdata); 7243 goto deltemp; 7244 7245 case SCF_ERROR_HANDLE_MISMATCH: 7246 case SCF_ERROR_NOT_BOUND: 7247 case SCF_ERROR_NOT_SET: 7248 default: 7249 bad_error("scf_service_add_instance", 7250 scf_error()); 7251 } 7252 } 7253 7254 if (g_verbose) 7255 warn(gettext("Taking \"%s\" snapshot for " 7256 "new service %s.\n"), snap_previous, inst->sc_fmri); 7257 r = take_snap(imp_inst, snap_previous, imp_snap); 7258 switch (r) { 7259 case 0: 7260 break; 7261 7262 case ECANCELED: 7263 warn(i_deleted, s->sc_fmri, inst->sc_name); 7264 lcbdata->sc_err = EBUSY; 7265 r = UU_WALK_ERROR; 7266 goto deltemp; 7267 7268 case ECONNABORTED: 7269 goto connaborted; 7270 7271 case EPERM: 7272 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 7273 lcbdata->sc_err = r; 7274 r = UU_WALK_ERROR; 7275 goto deltemp; 7276 7277 case ENOSPC: 7278 case -1: 7279 r = UU_WALK_ERROR; 7280 goto deltemp; 7281 7282 default: 7283 bad_error("take_snap", r); 7284 } 7285 } 7286 7287 s->sc_import_state = IMPORT_PREVIOUS; 7288 7289 /* 7290 * Upgrade service properties, if we can find a last-import snapshot. 7291 * Any will do because we don't support different service properties 7292 * in different manifests, so all snaplevels of the service in all of 7293 * the last-import snapshots of the instances should be the same. 7294 */ 7295 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7296 switch (scf_error()) { 7297 case SCF_ERROR_CONNECTION_BROKEN: 7298 goto connaborted; 7299 7300 case SCF_ERROR_DELETED: 7301 warn(s_deleted, s->sc_fmri); 7302 lcbdata->sc_err = EBUSY; 7303 r = UU_WALK_ERROR; 7304 goto deltemp; 7305 7306 case SCF_ERROR_HANDLE_MISMATCH: 7307 case SCF_ERROR_NOT_BOUND: 7308 case SCF_ERROR_NOT_SET: 7309 default: 7310 bad_error("scf_iter_service_instances", scf_error()); 7311 } 7312 } 7313 7314 for (;;) { 7315 r = scf_iter_next_instance(imp_iter, imp_inst); 7316 if (r == -1) { 7317 switch (scf_error()) { 7318 case SCF_ERROR_DELETED: 7319 warn(s_deleted, s->sc_fmri); 7320 lcbdata->sc_err = EBUSY; 7321 r = UU_WALK_ERROR; 7322 goto deltemp; 7323 7324 case SCF_ERROR_CONNECTION_BROKEN: 7325 goto connaborted; 7326 7327 case SCF_ERROR_NOT_BOUND: 7328 case SCF_ERROR_HANDLE_MISMATCH: 7329 case SCF_ERROR_INVALID_ARGUMENT: 7330 case SCF_ERROR_NOT_SET: 7331 default: 7332 bad_error("scf_iter_next_instance", 7333 scf_error()); 7334 } 7335 } 7336 7337 if (r == 0) { 7338 /* 7339 * Didn't find any last-import snapshots. Override- 7340 * import the properties. Unless one of the instances 7341 * has a general/enabled property, in which case we're 7342 * probably running a last-import-capable svccfg for 7343 * the first time, and we should only take the 7344 * last-import snapshot. 7345 */ 7346 if (have_ge) { 7347 pgroup_t *mfpg; 7348 scf_callback_t mfcbdata; 7349 7350 li_only = 1; 7351 no_refresh = 1; 7352 /* 7353 * Need to go ahead and import the manifestfiles 7354 * pg if it exists. If the last-import snapshot 7355 * upgrade code is ever removed this code can 7356 * be removed as well. 7357 */ 7358 mfpg = internal_pgroup_find(s, 7359 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 7360 7361 if (mfpg) { 7362 mfcbdata.sc_handle = g_hndl; 7363 mfcbdata.sc_parent = imp_svc; 7364 mfcbdata.sc_service = 1; 7365 mfcbdata.sc_flags = SCI_FORCE; 7366 mfcbdata.sc_source_fmri = s->sc_fmri; 7367 mfcbdata.sc_target_fmri = s->sc_fmri; 7368 if (entity_pgroup_import(mfpg, 7369 &mfcbdata) != UU_WALK_NEXT) { 7370 warn(s_mfile_upd, s->sc_fmri); 7371 r = UU_WALK_ERROR; 7372 goto deltemp; 7373 } 7374 } 7375 break; 7376 } 7377 7378 s->sc_import_state = IMPORT_PROP_BEGUN; 7379 7380 cbdata.sc_handle = g_hndl; 7381 cbdata.sc_parent = imp_svc; 7382 cbdata.sc_service = 1; 7383 cbdata.sc_flags = SCI_FORCE; 7384 cbdata.sc_source_fmri = s->sc_fmri; 7385 cbdata.sc_target_fmri = s->sc_fmri; 7386 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7387 &cbdata, UU_DEFAULT) != 0) { 7388 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7389 bad_error("uu_list_walk", uu_error()); 7390 lcbdata->sc_err = cbdata.sc_err; 7391 switch (cbdata.sc_err) { 7392 case ECONNABORTED: 7393 goto connaborted; 7394 7395 case ECANCELED: 7396 warn(s_deleted, s->sc_fmri); 7397 lcbdata->sc_err = EBUSY; 7398 break; 7399 7400 case EINVAL: /* caught above */ 7401 case EEXIST: 7402 bad_error("entity_pgroup_import", 7403 cbdata.sc_err); 7404 } 7405 7406 r = UU_WALK_ERROR; 7407 goto deltemp; 7408 } 7409 7410 cbdata.sc_trans = NULL; 7411 cbdata.sc_flags = 0; 7412 if (uu_list_walk(s->sc_dependents, 7413 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 7414 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7415 bad_error("uu_list_walk", uu_error()); 7416 lcbdata->sc_err = cbdata.sc_err; 7417 if (cbdata.sc_err == ECONNABORTED) 7418 goto connaborted; 7419 r = UU_WALK_ERROR; 7420 goto deltemp; 7421 } 7422 break; 7423 } 7424 7425 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 7426 imp_snap) != 0) { 7427 switch (scf_error()) { 7428 case SCF_ERROR_DELETED: 7429 continue; 7430 7431 case SCF_ERROR_NOT_FOUND: 7432 break; 7433 7434 case SCF_ERROR_CONNECTION_BROKEN: 7435 goto connaborted; 7436 7437 case SCF_ERROR_HANDLE_MISMATCH: 7438 case SCF_ERROR_NOT_BOUND: 7439 case SCF_ERROR_INVALID_ARGUMENT: 7440 case SCF_ERROR_NOT_SET: 7441 default: 7442 bad_error("scf_instance_get_snapshot", 7443 scf_error()); 7444 } 7445 7446 if (have_ge) 7447 continue; 7448 7449 /* 7450 * Check for a general/enabled property. This is how 7451 * we tell whether to import if there turn out to be 7452 * no last-import snapshots. 7453 */ 7454 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 7455 imp_pg) == 0) { 7456 if (scf_pg_get_property(imp_pg, 7457 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 7458 have_ge = 1; 7459 } else { 7460 switch (scf_error()) { 7461 case SCF_ERROR_DELETED: 7462 case SCF_ERROR_NOT_FOUND: 7463 continue; 7464 7465 case SCF_ERROR_INVALID_ARGUMENT: 7466 case SCF_ERROR_HANDLE_MISMATCH: 7467 case SCF_ERROR_CONNECTION_BROKEN: 7468 case SCF_ERROR_NOT_BOUND: 7469 case SCF_ERROR_NOT_SET: 7470 default: 7471 bad_error("scf_pg_get_property", 7472 scf_error()); 7473 } 7474 } 7475 } else { 7476 switch (scf_error()) { 7477 case SCF_ERROR_DELETED: 7478 case SCF_ERROR_NOT_FOUND: 7479 continue; 7480 7481 case SCF_ERROR_CONNECTION_BROKEN: 7482 goto connaborted; 7483 7484 case SCF_ERROR_NOT_BOUND: 7485 case SCF_ERROR_NOT_SET: 7486 case SCF_ERROR_INVALID_ARGUMENT: 7487 case SCF_ERROR_HANDLE_MISMATCH: 7488 default: 7489 bad_error("scf_instance_get_pg", 7490 scf_error()); 7491 } 7492 } 7493 continue; 7494 } 7495 7496 /* find service snaplevel */ 7497 r = get_snaplevel(imp_snap, 1, imp_snpl); 7498 switch (r) { 7499 case 0: 7500 break; 7501 7502 case ECONNABORTED: 7503 goto connaborted; 7504 7505 case ECANCELED: 7506 continue; 7507 7508 case ENOENT: 7509 if (scf_instance_get_name(imp_inst, imp_str, 7510 imp_str_sz) < 0) 7511 (void) strcpy(imp_str, "?"); 7512 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 7513 lcbdata->sc_err = EBADF; 7514 r = UU_WALK_ERROR; 7515 goto deltemp; 7516 7517 default: 7518 bad_error("get_snaplevel", r); 7519 } 7520 7521 if (scf_instance_get_snapshot(imp_inst, snap_running, 7522 imp_rsnap) != 0) { 7523 switch (scf_error()) { 7524 case SCF_ERROR_DELETED: 7525 continue; 7526 7527 case SCF_ERROR_NOT_FOUND: 7528 break; 7529 7530 case SCF_ERROR_CONNECTION_BROKEN: 7531 goto connaborted; 7532 7533 case SCF_ERROR_INVALID_ARGUMENT: 7534 case SCF_ERROR_HANDLE_MISMATCH: 7535 case SCF_ERROR_NOT_BOUND: 7536 case SCF_ERROR_NOT_SET: 7537 default: 7538 bad_error("scf_instance_get_snapshot", 7539 scf_error()); 7540 } 7541 running = NULL; 7542 } else { 7543 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7544 switch (r) { 7545 case 0: 7546 running = imp_rsnpl; 7547 break; 7548 7549 case ECONNABORTED: 7550 goto connaborted; 7551 7552 case ECANCELED: 7553 continue; 7554 7555 case ENOENT: 7556 if (scf_instance_get_name(imp_inst, imp_str, 7557 imp_str_sz) < 0) 7558 (void) strcpy(imp_str, "?"); 7559 warn(badsnap, snap_running, s->sc_name, 7560 imp_str); 7561 lcbdata->sc_err = EBADF; 7562 r = UU_WALK_ERROR; 7563 goto deltemp; 7564 7565 default: 7566 bad_error("get_snaplevel", r); 7567 } 7568 } 7569 7570 if (g_verbose) { 7571 if (scf_instance_get_name(imp_inst, imp_str, 7572 imp_str_sz) < 0) 7573 (void) strcpy(imp_str, "?"); 7574 warn(gettext("Upgrading properties of %s according to " 7575 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7576 } 7577 7578 /* upgrade service properties */ 7579 r = upgrade_props(imp_svc, running, imp_snpl, s); 7580 if (r == 0) 7581 break; 7582 7583 switch (r) { 7584 case ECONNABORTED: 7585 goto connaborted; 7586 7587 case ECANCELED: 7588 warn(s_deleted, s->sc_fmri); 7589 lcbdata->sc_err = EBUSY; 7590 break; 7591 7592 case ENODEV: 7593 if (scf_instance_get_name(imp_inst, imp_str, 7594 imp_str_sz) < 0) 7595 (void) strcpy(imp_str, "?"); 7596 warn(i_deleted, s->sc_fmri, imp_str); 7597 lcbdata->sc_err = EBUSY; 7598 break; 7599 7600 default: 7601 lcbdata->sc_err = r; 7602 } 7603 7604 r = UU_WALK_ERROR; 7605 goto deltemp; 7606 } 7607 7608 s->sc_import_state = IMPORT_PROP_DONE; 7609 7610 instances: 7611 /* import instances */ 7612 cbdata.sc_handle = lcbdata->sc_handle; 7613 cbdata.sc_parent = imp_svc; 7614 cbdata.sc_service = 1; 7615 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7616 cbdata.sc_general = NULL; 7617 7618 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7619 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7620 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7621 bad_error("uu_list_walk", uu_error()); 7622 7623 lcbdata->sc_err = cbdata.sc_err; 7624 if (cbdata.sc_err == ECONNABORTED) 7625 goto connaborted; 7626 r = UU_WALK_ERROR; 7627 goto deltemp; 7628 } 7629 7630 s->sc_import_state = IMPORT_COMPLETE; 7631 r = UU_WALK_NEXT; 7632 7633 deltemp: 7634 /* delete temporary service */ 7635 if (scf_service_delete(imp_tsvc) != 0) { 7636 switch (scf_error()) { 7637 case SCF_ERROR_DELETED: 7638 break; 7639 7640 case SCF_ERROR_CONNECTION_BROKEN: 7641 goto connaborted; 7642 7643 case SCF_ERROR_EXISTS: 7644 warn(gettext( 7645 "Could not delete svc:/%s (instances exist).\n"), 7646 imp_tsname); 7647 break; 7648 7649 case SCF_ERROR_NOT_SET: 7650 case SCF_ERROR_NOT_BOUND: 7651 default: 7652 bad_error("scf_service_delete", scf_error()); 7653 } 7654 } 7655 7656 return (r); 7657 7658 connaborted: 7659 warn(gettext("Could not delete svc:/%s " 7660 "(repository connection broken).\n"), imp_tsname); 7661 lcbdata->sc_err = ECONNABORTED; 7662 return (UU_WALK_ERROR); 7663 } 7664 7665 static const char * 7666 import_progress(int st) 7667 { 7668 switch (st) { 7669 case 0: 7670 return (gettext("not reached.")); 7671 7672 case IMPORT_PREVIOUS: 7673 return (gettext("previous snapshot taken.")); 7674 7675 case IMPORT_PROP_BEGUN: 7676 return (gettext("some properties imported.")); 7677 7678 case IMPORT_PROP_DONE: 7679 return (gettext("properties imported.")); 7680 7681 case IMPORT_COMPLETE: 7682 return (gettext("imported.")); 7683 7684 case IMPORT_REFRESHED: 7685 return (gettext("refresh requested.")); 7686 7687 default: 7688 #ifndef NDEBUG 7689 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7690 __FILE__, __LINE__, st); 7691 #endif 7692 abort(); 7693 /* NOTREACHED */ 7694 } 7695 } 7696 7697 /* 7698 * Returns 7699 * 0 - success 7700 * - fmri wasn't found (error printed) 7701 * - entity was deleted (error printed) 7702 * - backend denied access (error printed) 7703 * ENOMEM - out of memory (error printed) 7704 * ECONNABORTED - repository connection broken (error printed) 7705 * EPERM - permission denied (error printed) 7706 * -1 - unknown libscf error (error printed) 7707 */ 7708 static int 7709 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7710 { 7711 scf_error_t serr; 7712 void *ent; 7713 int issvc; 7714 int r; 7715 7716 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7717 const char *dpt_deleted = gettext("Could not refresh %s " 7718 "(dependent \"%s\" of %s) (deleted).\n"); 7719 7720 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7721 switch (serr) { 7722 case SCF_ERROR_NONE: 7723 break; 7724 7725 case SCF_ERROR_NO_MEMORY: 7726 if (name == NULL) 7727 warn(gettext("Could not refresh %s (out of memory).\n"), 7728 fmri); 7729 else 7730 warn(gettext("Could not refresh %s " 7731 "(dependent \"%s\" of %s) (out of memory).\n"), 7732 fmri, name, d_fmri); 7733 return (ENOMEM); 7734 7735 case SCF_ERROR_NOT_FOUND: 7736 if (name == NULL) 7737 warn(deleted, fmri); 7738 else 7739 warn(dpt_deleted, fmri, name, d_fmri); 7740 return (0); 7741 7742 case SCF_ERROR_INVALID_ARGUMENT: 7743 case SCF_ERROR_CONSTRAINT_VIOLATED: 7744 default: 7745 bad_error("fmri_to_entity", serr); 7746 } 7747 7748 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7749 switch (r) { 7750 case 0: 7751 break; 7752 7753 case ECONNABORTED: 7754 if (name != NULL) 7755 warn(gettext("Could not refresh %s " 7756 "(dependent \"%s\" of %s) " 7757 "(repository connection broken).\n"), fmri, name, 7758 d_fmri); 7759 return (r); 7760 7761 case ECANCELED: 7762 if (name == NULL) 7763 warn(deleted, fmri); 7764 else 7765 warn(dpt_deleted, fmri, name, d_fmri); 7766 return (0); 7767 7768 case EACCES: 7769 if (!g_verbose) 7770 return (0); 7771 if (name == NULL) 7772 warn(gettext("Could not refresh %s " 7773 "(backend access denied).\n"), fmri); 7774 else 7775 warn(gettext("Could not refresh %s " 7776 "(dependent \"%s\" of %s) " 7777 "(backend access denied).\n"), fmri, name, d_fmri); 7778 return (0); 7779 7780 case EPERM: 7781 if (name == NULL) 7782 warn(gettext("Could not refresh %s " 7783 "(permission denied).\n"), fmri); 7784 else 7785 warn(gettext("Could not refresh %s " 7786 "(dependent \"%s\" of %s) " 7787 "(permission denied).\n"), fmri, name, d_fmri); 7788 return (r); 7789 7790 case ENOSPC: 7791 if (name == NULL) 7792 warn(gettext("Could not refresh %s " 7793 "(repository server out of resources).\n"), 7794 fmri); 7795 else 7796 warn(gettext("Could not refresh %s " 7797 "(dependent \"%s\" of %s) " 7798 "(repository server out of resources).\n"), 7799 fmri, name, d_fmri); 7800 return (r); 7801 7802 case -1: 7803 scfwarn(); 7804 return (r); 7805 7806 default: 7807 bad_error("refresh_entity", r); 7808 } 7809 7810 if (issvc) 7811 scf_service_destroy(ent); 7812 else 7813 scf_instance_destroy(ent); 7814 7815 return (0); 7816 } 7817 7818 static int 7819 alloc_imp_globals() 7820 { 7821 int r; 7822 7823 const char * const emsg_nomem = gettext("Out of memory.\n"); 7824 const char * const emsg_nores = 7825 gettext("svc.configd is out of resources.\n"); 7826 7827 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 7828 max_scf_name_len : max_scf_fmri_len) + 1; 7829 7830 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 7831 (imp_svc = scf_service_create(g_hndl)) == NULL || 7832 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 7833 (imp_inst = scf_instance_create(g_hndl)) == NULL || 7834 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 7835 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 7836 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 7837 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 7838 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 7839 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7840 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 7841 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7842 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 7843 (imp_prop = scf_property_create(g_hndl)) == NULL || 7844 (imp_iter = scf_iter_create(g_hndl)) == NULL || 7845 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 7846 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 7847 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 7848 (imp_str = malloc(imp_str_sz)) == NULL || 7849 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 7850 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 7851 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 7852 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 7853 (ud_inst = scf_instance_create(g_hndl)) == NULL || 7854 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7855 (ud_pg = scf_pg_create(g_hndl)) == NULL || 7856 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 7857 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 7858 (ud_prop = scf_property_create(g_hndl)) == NULL || 7859 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 7860 (ud_val = scf_value_create(g_hndl)) == NULL || 7861 (ud_iter = scf_iter_create(g_hndl)) == NULL || 7862 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 7863 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 7864 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 7865 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 7866 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 7867 if (scf_error() == SCF_ERROR_NO_RESOURCES) 7868 warn(emsg_nores); 7869 else 7870 warn(emsg_nomem); 7871 7872 return (-1); 7873 } 7874 7875 r = load_init(); 7876 switch (r) { 7877 case 0: 7878 break; 7879 7880 case ENOMEM: 7881 warn(emsg_nomem); 7882 return (-1); 7883 7884 default: 7885 bad_error("load_init", r); 7886 } 7887 7888 return (0); 7889 } 7890 7891 static void 7892 free_imp_globals() 7893 { 7894 pgroup_t *old_dpt; 7895 void *cookie; 7896 7897 load_fini(); 7898 7899 free(ud_ctarg); 7900 free(ud_oldtarg); 7901 free(ud_name); 7902 ud_ctarg = ud_oldtarg = ud_name = NULL; 7903 7904 scf_transaction_destroy(ud_tx); 7905 ud_tx = NULL; 7906 scf_iter_destroy(ud_iter); 7907 scf_iter_destroy(ud_iter2); 7908 ud_iter = ud_iter2 = NULL; 7909 scf_value_destroy(ud_val); 7910 ud_val = NULL; 7911 scf_property_destroy(ud_prop); 7912 scf_property_destroy(ud_dpt_prop); 7913 ud_prop = ud_dpt_prop = NULL; 7914 scf_pg_destroy(ud_pg); 7915 scf_pg_destroy(ud_cur_depts_pg); 7916 scf_pg_destroy(ud_run_dpts_pg); 7917 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7918 scf_snaplevel_destroy(ud_snpl); 7919 ud_snpl = NULL; 7920 scf_instance_destroy(ud_inst); 7921 ud_inst = NULL; 7922 7923 free(imp_str); 7924 free(imp_tsname); 7925 free(imp_fe1); 7926 free(imp_fe2); 7927 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7928 7929 cookie = NULL; 7930 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7931 NULL) { 7932 free((char *)old_dpt->sc_pgroup_name); 7933 free((char *)old_dpt->sc_pgroup_fmri); 7934 internal_pgroup_free(old_dpt); 7935 } 7936 uu_list_destroy(imp_deleted_dpts); 7937 7938 scf_transaction_destroy(imp_tx); 7939 imp_tx = NULL; 7940 scf_iter_destroy(imp_iter); 7941 scf_iter_destroy(imp_rpg_iter); 7942 scf_iter_destroy(imp_up_iter); 7943 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7944 scf_property_destroy(imp_prop); 7945 imp_prop = NULL; 7946 scf_pg_destroy(imp_pg); 7947 scf_pg_destroy(imp_pg2); 7948 imp_pg = imp_pg2 = NULL; 7949 scf_snaplevel_destroy(imp_snpl); 7950 scf_snaplevel_destroy(imp_rsnpl); 7951 imp_snpl = imp_rsnpl = NULL; 7952 scf_snapshot_destroy(imp_snap); 7953 scf_snapshot_destroy(imp_lisnap); 7954 scf_snapshot_destroy(imp_tlisnap); 7955 scf_snapshot_destroy(imp_rsnap); 7956 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7957 scf_instance_destroy(imp_inst); 7958 scf_instance_destroy(imp_tinst); 7959 imp_inst = imp_tinst = NULL; 7960 scf_service_destroy(imp_svc); 7961 scf_service_destroy(imp_tsvc); 7962 imp_svc = imp_tsvc = NULL; 7963 scf_scope_destroy(imp_scope); 7964 imp_scope = NULL; 7965 7966 load_fini(); 7967 } 7968 7969 int 7970 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 7971 { 7972 scf_callback_t cbdata; 7973 int result = 0; 7974 entity_t *svc, *inst; 7975 uu_list_t *insts; 7976 int r; 7977 pgroup_t *old_dpt; 7978 int annotation_set = 0; 7979 7980 const char * const emsg_nomem = gettext("Out of memory.\n"); 7981 const char * const emsg_nores = 7982 gettext("svc.configd is out of resources.\n"); 7983 7984 lscf_prep_hndl(); 7985 7986 if (alloc_imp_globals()) 7987 goto out; 7988 7989 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 7990 switch (scf_error()) { 7991 case SCF_ERROR_CONNECTION_BROKEN: 7992 warn(gettext("Repository connection broken.\n")); 7993 repository_teardown(); 7994 result = -1; 7995 goto out; 7996 7997 case SCF_ERROR_NOT_FOUND: 7998 case SCF_ERROR_INVALID_ARGUMENT: 7999 case SCF_ERROR_NOT_BOUND: 8000 case SCF_ERROR_HANDLE_MISMATCH: 8001 default: 8002 bad_error("scf_handle_get_scope", scf_error()); 8003 } 8004 } 8005 8006 /* Set up the auditing annotation. */ 8007 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 8008 annotation_set = 1; 8009 } else { 8010 switch (scf_error()) { 8011 case SCF_ERROR_CONNECTION_BROKEN: 8012 warn(gettext("Repository connection broken.\n")); 8013 repository_teardown(); 8014 result = -1; 8015 goto out; 8016 8017 case SCF_ERROR_INVALID_ARGUMENT: 8018 case SCF_ERROR_NOT_BOUND: 8019 case SCF_ERROR_NO_RESOURCES: 8020 case SCF_ERROR_INTERNAL: 8021 bad_error("_scf_set_annotation", scf_error()); 8022 /* NOTREACHED */ 8023 8024 default: 8025 /* 8026 * Do not terminate import because of inability to 8027 * generate annotation audit event. 8028 */ 8029 warn(gettext("_scf_set_annotation() unexpectedly " 8030 "failed with return code of %d\n"), scf_error()); 8031 break; 8032 } 8033 } 8034 8035 /* 8036 * Clear the sc_import_state's of all services & instances so we can 8037 * report how far we got if we fail. 8038 */ 8039 for (svc = uu_list_first(bndl->sc_bundle_services); 8040 svc != NULL; 8041 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8042 svc->sc_import_state = 0; 8043 8044 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 8045 clear_int, (void *)offsetof(entity_t, sc_import_state), 8046 UU_DEFAULT) != 0) 8047 bad_error("uu_list_walk", uu_error()); 8048 } 8049 8050 cbdata.sc_handle = g_hndl; 8051 cbdata.sc_parent = imp_scope; 8052 cbdata.sc_flags = flags; 8053 cbdata.sc_general = NULL; 8054 8055 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 8056 &cbdata, UU_DEFAULT) == 0) { 8057 /* Success. Refresh everything. */ 8058 8059 if (flags & SCI_NOREFRESH || no_refresh) { 8060 no_refresh = 0; 8061 result = 0; 8062 goto out; 8063 } 8064 8065 for (svc = uu_list_first(bndl->sc_bundle_services); 8066 svc != NULL; 8067 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8068 pgroup_t *dpt; 8069 8070 insts = svc->sc_u.sc_service.sc_service_instances; 8071 8072 for (inst = uu_list_first(insts); 8073 inst != NULL; 8074 inst = uu_list_next(insts, inst)) { 8075 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 8076 switch (r) { 8077 case 0: 8078 break; 8079 8080 case ENOMEM: 8081 case ECONNABORTED: 8082 case EPERM: 8083 case -1: 8084 goto progress; 8085 8086 default: 8087 bad_error("imp_refresh_fmri", r); 8088 } 8089 8090 inst->sc_import_state = IMPORT_REFRESHED; 8091 8092 for (dpt = uu_list_first(inst->sc_dependents); 8093 dpt != NULL; 8094 dpt = uu_list_next(inst->sc_dependents, 8095 dpt)) 8096 if (imp_refresh_fmri( 8097 dpt->sc_pgroup_fmri, 8098 dpt->sc_pgroup_name, 8099 inst->sc_fmri) != 0) 8100 goto progress; 8101 } 8102 8103 for (dpt = uu_list_first(svc->sc_dependents); 8104 dpt != NULL; 8105 dpt = uu_list_next(svc->sc_dependents, dpt)) 8106 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 8107 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 8108 goto progress; 8109 } 8110 8111 for (old_dpt = uu_list_first(imp_deleted_dpts); 8112 old_dpt != NULL; 8113 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 8114 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8115 old_dpt->sc_pgroup_name, 8116 old_dpt->sc_parent->sc_fmri) != 0) 8117 goto progress; 8118 8119 result = 0; 8120 goto out; 8121 } 8122 8123 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8124 bad_error("uu_list_walk", uu_error()); 8125 8126 printerr: 8127 /* If the error hasn't been printed yet, do so here. */ 8128 switch (cbdata.sc_err) { 8129 case ECONNABORTED: 8130 warn(gettext("Repository connection broken.\n")); 8131 break; 8132 8133 case ENOMEM: 8134 warn(emsg_nomem); 8135 break; 8136 8137 case ENOSPC: 8138 warn(emsg_nores); 8139 break; 8140 8141 case EROFS: 8142 warn(gettext("Repository is read-only.\n")); 8143 break; 8144 8145 case EACCES: 8146 warn(gettext("Repository backend denied access.\n")); 8147 break; 8148 8149 case EPERM: 8150 case EINVAL: 8151 case EEXIST: 8152 case EBUSY: 8153 case EBADF: 8154 case -1: 8155 break; 8156 8157 default: 8158 bad_error("lscf_service_import", cbdata.sc_err); 8159 } 8160 8161 progress: 8162 warn(gettext("Import of %s failed. Progress:\n"), filename); 8163 8164 for (svc = uu_list_first(bndl->sc_bundle_services); 8165 svc != NULL; 8166 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8167 insts = svc->sc_u.sc_service.sc_service_instances; 8168 8169 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 8170 import_progress(svc->sc_import_state)); 8171 8172 for (inst = uu_list_first(insts); 8173 inst != NULL; 8174 inst = uu_list_next(insts, inst)) 8175 warn(gettext(" Instance \"%s\": %s\n"), 8176 inst->sc_name, 8177 import_progress(inst->sc_import_state)); 8178 } 8179 8180 if (cbdata.sc_err == ECONNABORTED) 8181 repository_teardown(); 8182 8183 8184 result = -1; 8185 8186 out: 8187 if (annotation_set != 0) { 8188 /* Turn off annotation. It is no longer needed. */ 8189 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8190 } 8191 8192 free_imp_globals(); 8193 8194 return (result); 8195 } 8196 8197 /* 8198 * _lscf_import_err() summarize the error handling returned by 8199 * lscf_import_{instance | service}_pgs 8200 * Return values are: 8201 * IMPORT_NEXT 8202 * IMPORT_OUT 8203 * IMPORT_BAD 8204 */ 8205 8206 #define IMPORT_BAD -1 8207 #define IMPORT_NEXT 0 8208 #define IMPORT_OUT 1 8209 8210 static int 8211 _lscf_import_err(int err, const char *fmri) 8212 { 8213 switch (err) { 8214 case 0: 8215 if (g_verbose) 8216 warn(gettext("%s updated.\n"), fmri); 8217 return (IMPORT_NEXT); 8218 8219 case ECONNABORTED: 8220 warn(gettext("Could not update %s " 8221 "(repository connection broken).\n"), fmri); 8222 return (IMPORT_OUT); 8223 8224 case ENOMEM: 8225 warn(gettext("Could not update %s (out of memory).\n"), fmri); 8226 return (IMPORT_OUT); 8227 8228 case ENOSPC: 8229 warn(gettext("Could not update %s " 8230 "(repository server out of resources).\n"), fmri); 8231 return (IMPORT_OUT); 8232 8233 case ECANCELED: 8234 warn(gettext( 8235 "Could not update %s (deleted).\n"), fmri); 8236 return (IMPORT_NEXT); 8237 8238 case EPERM: 8239 case EINVAL: 8240 case EBUSY: 8241 return (IMPORT_NEXT); 8242 8243 case EROFS: 8244 warn(gettext("Could not update %s (repository read-only).\n"), 8245 fmri); 8246 return (IMPORT_OUT); 8247 8248 case EACCES: 8249 warn(gettext("Could not update %s " 8250 "(backend access denied).\n"), fmri); 8251 return (IMPORT_NEXT); 8252 8253 case EEXIST: 8254 default: 8255 return (IMPORT_BAD); 8256 } 8257 8258 /*NOTREACHED*/ 8259 } 8260 8261 /* 8262 * The global imp_svc and imp_inst should be set by the caller in the 8263 * check to make sure the service and instance exist that the apply is 8264 * working on. 8265 */ 8266 static int 8267 lscf_dependent_apply(void *dpg, void *e) 8268 { 8269 scf_callback_t cb; 8270 pgroup_t *dpt_pgroup = dpg; 8271 pgroup_t *deldpt; 8272 entity_t *ent = e; 8273 int tissvc; 8274 void *sc_ent, *tent; 8275 scf_error_t serr; 8276 int r; 8277 8278 const char * const dependents = "dependents"; 8279 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT); 8280 8281 if (issvc) 8282 sc_ent = imp_svc; 8283 else 8284 sc_ent = imp_inst; 8285 8286 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg, 8287 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 || 8288 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name, 8289 imp_prop) != 0) { 8290 switch (scf_error()) { 8291 case SCF_ERROR_NOT_FOUND: 8292 case SCF_ERROR_DELETED: 8293 break; 8294 8295 case SCF_ERROR_CONNECTION_BROKEN: 8296 case SCF_ERROR_NOT_SET: 8297 case SCF_ERROR_INVALID_ARGUMENT: 8298 case SCF_ERROR_HANDLE_MISMATCH: 8299 case SCF_ERROR_NOT_BOUND: 8300 default: 8301 bad_error("entity_get_pg", scf_error()); 8302 } 8303 } else { 8304 /* 8305 * Found the dependents/<wip dep> so check to 8306 * see if the service is different. If so 8307 * store the service for later refresh, and 8308 * delete the wip dependency from the service 8309 */ 8310 if (scf_property_get_value(imp_prop, ud_val) != 0) { 8311 switch (scf_error()) { 8312 case SCF_ERROR_DELETED: 8313 break; 8314 8315 case SCF_ERROR_CONNECTION_BROKEN: 8316 case SCF_ERROR_NOT_SET: 8317 case SCF_ERROR_INVALID_ARGUMENT: 8318 case SCF_ERROR_HANDLE_MISMATCH: 8319 case SCF_ERROR_NOT_BOUND: 8320 default: 8321 bad_error("scf_property_get_value", 8322 scf_error()); 8323 } 8324 } 8325 8326 if (scf_value_get_as_string(ud_val, ud_oldtarg, 8327 max_scf_value_len + 1) < 0) 8328 bad_error("scf_value_get_as_string", scf_error()); 8329 8330 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 8331 switch (r) { 8332 case 1: 8333 break; 8334 case 0: 8335 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent, 8336 &tissvc)) != SCF_ERROR_NONE) { 8337 if (serr == SCF_ERROR_NOT_FOUND) { 8338 break; 8339 } else { 8340 bad_error("fmri_to_entity", serr); 8341 } 8342 } 8343 8344 if (entity_get_pg(tent, tissvc, 8345 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) { 8346 serr = scf_error(); 8347 if (serr == SCF_ERROR_NOT_FOUND || 8348 serr == SCF_ERROR_DELETED) { 8349 break; 8350 } else { 8351 bad_error("entity_get_pg", scf_error()); 8352 } 8353 } 8354 8355 if (scf_pg_delete(imp_pg) != 0) { 8356 serr = scf_error(); 8357 if (serr == SCF_ERROR_NOT_FOUND || 8358 serr == SCF_ERROR_DELETED) { 8359 break; 8360 } else { 8361 bad_error("scf_pg_delete", scf_error()); 8362 } 8363 } 8364 8365 deldpt = internal_pgroup_new(); 8366 if (deldpt == NULL) 8367 return (ENOMEM); 8368 deldpt->sc_pgroup_name = 8369 strdup(dpt_pgroup->sc_pgroup_name); 8370 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg); 8371 if (deldpt->sc_pgroup_name == NULL || 8372 deldpt->sc_pgroup_fmri == NULL) 8373 return (ENOMEM); 8374 deldpt->sc_parent = (entity_t *)ent; 8375 if (uu_list_insert_after(imp_deleted_dpts, NULL, 8376 deldpt) != 0) 8377 uu_die(gettext("libuutil error: %s\n"), 8378 uu_strerror(uu_error())); 8379 8380 break; 8381 default: 8382 bad_error("fmri_equal", r); 8383 } 8384 } 8385 8386 cb.sc_handle = g_hndl; 8387 cb.sc_parent = ent; 8388 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT; 8389 cb.sc_source_fmri = ent->sc_fmri; 8390 cb.sc_target_fmri = ent->sc_fmri; 8391 cb.sc_trans = NULL; 8392 cb.sc_flags = SCI_FORCE; 8393 8394 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT) 8395 return (UU_WALK_ERROR); 8396 8397 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL); 8398 switch (r) { 8399 case 0: 8400 break; 8401 8402 case ENOMEM: 8403 case ECONNABORTED: 8404 case EPERM: 8405 case -1: 8406 warn(gettext("Unable to refresh \"%s\"\n"), 8407 dpt_pgroup->sc_pgroup_fmri); 8408 return (UU_WALK_ERROR); 8409 8410 default: 8411 bad_error("imp_refresh_fmri", r); 8412 } 8413 8414 return (UU_WALK_NEXT); 8415 } 8416 8417 /* 8418 * Returns 8419 * 0 - success 8420 * -1 - lscf_import_instance_pgs() failed. 8421 */ 8422 int 8423 lscf_bundle_apply(bundle_t *bndl, const char *file) 8424 { 8425 pgroup_t *old_dpt; 8426 entity_t *svc, *inst; 8427 int annotation_set = 0; 8428 int ret = 0; 8429 int r = 0; 8430 8431 lscf_prep_hndl(); 8432 8433 if ((ret = alloc_imp_globals())) 8434 goto out; 8435 8436 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) 8437 scfdie(); 8438 8439 /* 8440 * Set the strings to be used for the security audit annotation 8441 * event. 8442 */ 8443 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 8444 annotation_set = 1; 8445 } else { 8446 switch (scf_error()) { 8447 case SCF_ERROR_CONNECTION_BROKEN: 8448 warn(gettext("Repository connection broken.\n")); 8449 goto out; 8450 8451 case SCF_ERROR_INVALID_ARGUMENT: 8452 case SCF_ERROR_NOT_BOUND: 8453 case SCF_ERROR_NO_RESOURCES: 8454 case SCF_ERROR_INTERNAL: 8455 bad_error("_scf_set_annotation", scf_error()); 8456 /* NOTREACHED */ 8457 8458 default: 8459 /* 8460 * Do not abort apply operation because of 8461 * inability to create annotation audit event. 8462 */ 8463 warn(gettext("_scf_set_annotation() unexpectedly " 8464 "failed with return code of %d\n"), scf_error()); 8465 break; 8466 } 8467 } 8468 8469 for (svc = uu_list_first(bndl->sc_bundle_services); 8470 svc != NULL; 8471 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8472 int refresh = 0; 8473 8474 if (scf_scope_get_service(imp_scope, svc->sc_name, 8475 imp_svc) != 0) { 8476 switch (scf_error()) { 8477 case SCF_ERROR_NOT_FOUND: 8478 if (g_verbose) 8479 warn(gettext("Ignoring nonexistent " 8480 "service %s.\n"), svc->sc_name); 8481 continue; 8482 8483 default: 8484 scfdie(); 8485 } 8486 } 8487 8488 /* 8489 * If there were missing types in the profile, then need to 8490 * attempt to find the types. 8491 */ 8492 if (svc->sc_miss_type) { 8493 if (uu_list_numnodes(svc->sc_pgroups) && 8494 uu_list_walk(svc->sc_pgroups, find_current_pg_type, 8495 svc, UU_DEFAULT) != 0) { 8496 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8497 bad_error("uu_list_walk", uu_error()); 8498 8499 ret = -1; 8500 continue; 8501 } 8502 8503 for (inst = uu_list_first( 8504 svc->sc_u.sc_service.sc_service_instances); 8505 inst != NULL; 8506 inst = uu_list_next( 8507 svc->sc_u.sc_service.sc_service_instances, inst)) { 8508 /* 8509 * If the instance doesn't exist just 8510 * skip to the next instance and let the 8511 * import note the missing instance. 8512 */ 8513 if (scf_service_get_instance(imp_svc, 8514 inst->sc_name, imp_inst) != 0) 8515 continue; 8516 8517 if (uu_list_walk(inst->sc_pgroups, 8518 find_current_pg_type, inst, 8519 UU_DEFAULT) != 0) { 8520 if (uu_error() != 8521 UU_ERROR_CALLBACK_FAILED) 8522 bad_error("uu_list_walk", 8523 uu_error()); 8524 8525 ret = -1; 8526 inst->sc_miss_type = B_TRUE; 8527 } 8528 } 8529 } 8530 8531 /* 8532 * if we have pgs in the profile, we need to refresh ALL 8533 * instances of the service 8534 */ 8535 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 8536 refresh = 1; 8537 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc, 8538 SCI_FORCE | SCI_KEEP); 8539 switch (_lscf_import_err(r, svc->sc_fmri)) { 8540 case IMPORT_NEXT: 8541 break; 8542 8543 case IMPORT_OUT: 8544 goto out; 8545 8546 case IMPORT_BAD: 8547 default: 8548 bad_error("lscf_import_service_pgs", r); 8549 } 8550 } 8551 8552 if (uu_list_numnodes(svc->sc_dependents) != 0) { 8553 uu_list_walk(svc->sc_dependents, 8554 lscf_dependent_apply, svc, UU_DEFAULT); 8555 } 8556 8557 for (inst = uu_list_first( 8558 svc->sc_u.sc_service.sc_service_instances); 8559 inst != NULL; 8560 inst = uu_list_next( 8561 svc->sc_u.sc_service.sc_service_instances, inst)) { 8562 /* 8563 * This instance still has missing types 8564 * so skip it. 8565 */ 8566 if (inst->sc_miss_type) { 8567 if (g_verbose) 8568 warn(gettext("Ignoring instance " 8569 "%s:%s with missing types\n"), 8570 inst->sc_parent->sc_name, 8571 inst->sc_name); 8572 8573 continue; 8574 } 8575 8576 if (scf_service_get_instance(imp_svc, inst->sc_name, 8577 imp_inst) != 0) { 8578 switch (scf_error()) { 8579 case SCF_ERROR_NOT_FOUND: 8580 if (g_verbose) 8581 warn(gettext("Ignoring " 8582 "nonexistant instance " 8583 "%s:%s.\n"), 8584 inst->sc_parent->sc_name, 8585 inst->sc_name); 8586 continue; 8587 8588 default: 8589 scfdie(); 8590 } 8591 } 8592 8593 /* 8594 * If the instance does not have a general/enabled 8595 * property and no last-import snapshot then the 8596 * instance is not a fully installed instance and 8597 * should not have a profile applied to it. 8598 * 8599 * This could happen if a service/instance declares 8600 * a dependent on behalf of another service/instance. 8601 * 8602 */ 8603 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 8604 imp_snap) != 0) { 8605 if (scf_instance_get_pg(imp_inst, 8606 SCF_PG_GENERAL, imp_pg) != 0 || 8607 scf_pg_get_property(imp_pg, 8608 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 8609 if (g_verbose) 8610 warn(gettext("Ignoreing " 8611 "partial instance " 8612 "%s:%s.\n"), 8613 inst->sc_parent->sc_name, 8614 inst->sc_name); 8615 continue; 8616 } 8617 } 8618 8619 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, 8620 inst, SCI_FORCE | SCI_KEEP); 8621 switch (_lscf_import_err(r, inst->sc_fmri)) { 8622 case IMPORT_NEXT: 8623 break; 8624 8625 case IMPORT_OUT: 8626 goto out; 8627 8628 case IMPORT_BAD: 8629 default: 8630 bad_error("lscf_import_instance_pgs", r); 8631 } 8632 8633 if (uu_list_numnodes(inst->sc_dependents) != 0) { 8634 uu_list_walk(inst->sc_dependents, 8635 lscf_dependent_apply, inst, UU_DEFAULT); 8636 } 8637 8638 /* refresh only if there is no pgs in the service */ 8639 if (refresh == 0) 8640 (void) refresh_entity(0, imp_inst, 8641 inst->sc_fmri, NULL, NULL, NULL); 8642 } 8643 8644 if (refresh == 1) { 8645 char *name_buf = safe_malloc(max_scf_name_len + 1); 8646 8647 (void) refresh_entity(1, imp_svc, svc->sc_name, 8648 imp_inst, imp_iter, name_buf); 8649 free(name_buf); 8650 } 8651 8652 for (old_dpt = uu_list_first(imp_deleted_dpts); 8653 old_dpt != NULL; 8654 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) { 8655 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8656 old_dpt->sc_pgroup_name, 8657 old_dpt->sc_parent->sc_fmri) != 0) { 8658 warn(gettext("Unable to refresh \"%s\"\n"), 8659 old_dpt->sc_pgroup_fmri); 8660 } 8661 } 8662 } 8663 8664 out: 8665 if (annotation_set) { 8666 /* Remove security audit annotation strings. */ 8667 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8668 } 8669 8670 free_imp_globals(); 8671 return (ret); 8672 } 8673 8674 8675 /* 8676 * Export. These functions create and output an XML tree of a service 8677 * description from the repository. This is largely the inverse of 8678 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 8679 * 8680 * - We must include any properties which are not represented specifically by 8681 * a service manifest, e.g., properties created by an admin post-import. To 8682 * do so we'll iterate through all properties and deal with each 8683 * apropriately. 8684 * 8685 * - Children of services and instances must must be in the order set by the 8686 * DTD, but we iterate over the properties in undefined order. The elements 8687 * are not easily (or efficiently) sortable by name. Since there's a fixed 8688 * number of classes of them, however, we'll keep the classes separate and 8689 * assemble them in order. 8690 */ 8691 8692 /* 8693 * Convenience function to handle xmlSetProp errors (and type casting). 8694 */ 8695 static void 8696 safe_setprop(xmlNodePtr n, const char *name, const char *val) 8697 { 8698 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 8699 uu_die(gettext("Could not set XML property.\n")); 8700 } 8701 8702 /* 8703 * Convenience function to set an XML attribute to the single value of an 8704 * astring property. If the value happens to be the default, don't set the 8705 * attribute. "dval" should be the default value supplied by the DTD, or 8706 * NULL for no default. 8707 */ 8708 static int 8709 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 8710 const char *name, const char *dval) 8711 { 8712 scf_value_t *val; 8713 ssize_t len; 8714 char *str; 8715 8716 val = scf_value_create(g_hndl); 8717 if (val == NULL) 8718 scfdie(); 8719 8720 if (prop_get_val(prop, val) != 0) { 8721 scf_value_destroy(val); 8722 return (-1); 8723 } 8724 8725 len = scf_value_get_as_string(val, NULL, 0); 8726 if (len < 0) 8727 scfdie(); 8728 8729 str = safe_malloc(len + 1); 8730 8731 if (scf_value_get_as_string(val, str, len + 1) < 0) 8732 scfdie(); 8733 8734 scf_value_destroy(val); 8735 8736 if (dval == NULL || strcmp(str, dval) != 0) 8737 safe_setprop(n, name, str); 8738 8739 free(str); 8740 8741 return (0); 8742 } 8743 8744 /* 8745 * As above, but the attribute is always set. 8746 */ 8747 static int 8748 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 8749 { 8750 return (set_attr_from_prop_default(prop, n, name, NULL)); 8751 } 8752 8753 /* 8754 * Dump the given document onto f, with "'s replaced by ''s. 8755 */ 8756 static int 8757 write_service_bundle(xmlDocPtr doc, FILE *f) 8758 { 8759 xmlChar *mem; 8760 int sz, i; 8761 8762 mem = NULL; 8763 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 8764 8765 if (mem == NULL) { 8766 semerr(gettext("Could not dump XML tree.\n")); 8767 return (-1); 8768 } 8769 8770 /* 8771 * Fortunately libxml produces " instead of ", so we can blindly 8772 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 8773 * ' code?! 8774 */ 8775 for (i = 0; i < sz; ++i) { 8776 char c = (char)mem[i]; 8777 8778 if (c == '"') 8779 (void) fputc('\'', f); 8780 else if (c == '\'') 8781 (void) fwrite("'", sizeof ("'") - 1, 1, f); 8782 else 8783 (void) fputc(c, f); 8784 } 8785 8786 return (0); 8787 } 8788 8789 /* 8790 * Create the DOM elements in elts necessary to (generically) represent prop 8791 * (i.e., a property or propval element). If the name of the property is 8792 * known, it should be passed as name_arg. Otherwise, pass NULL. 8793 */ 8794 static void 8795 export_property(scf_property_t *prop, const char *name_arg, 8796 struct pg_elts *elts, int flags) 8797 { 8798 const char *type; 8799 scf_error_t err = 0; 8800 xmlNodePtr pnode, lnode; 8801 char *lnname; 8802 int ret; 8803 8804 /* name */ 8805 if (name_arg != NULL) { 8806 (void) strcpy(exp_str, name_arg); 8807 } else { 8808 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 8809 scfdie(); 8810 } 8811 8812 /* type */ 8813 type = prop_to_typestr(prop); 8814 if (type == NULL) 8815 uu_die(gettext("Can't export property %s: unknown type.\n"), 8816 exp_str); 8817 8818 /* If we're exporting values, and there's just one, export it here. */ 8819 if (!(flags & SCE_ALL_VALUES)) 8820 goto empty; 8821 8822 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 8823 xmlNodePtr n; 8824 8825 /* Single value, so use propval */ 8826 n = xmlNewNode(NULL, (xmlChar *)"propval"); 8827 if (n == NULL) 8828 uu_die(emsg_create_xml); 8829 8830 safe_setprop(n, name_attr, exp_str); 8831 safe_setprop(n, type_attr, type); 8832 8833 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8834 scfdie(); 8835 safe_setprop(n, value_attr, exp_str); 8836 8837 if (elts->propvals == NULL) 8838 elts->propvals = n; 8839 else 8840 (void) xmlAddSibling(elts->propvals, n); 8841 8842 return; 8843 } 8844 8845 err = scf_error(); 8846 8847 if (err == SCF_ERROR_PERMISSION_DENIED) { 8848 semerr(emsg_permission_denied); 8849 return; 8850 } 8851 8852 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 8853 err != SCF_ERROR_NOT_FOUND && 8854 err != SCF_ERROR_PERMISSION_DENIED) 8855 scfdie(); 8856 8857 empty: 8858 /* Multiple (or no) values, so use property */ 8859 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 8860 if (pnode == NULL) 8861 uu_die(emsg_create_xml); 8862 8863 safe_setprop(pnode, name_attr, exp_str); 8864 safe_setprop(pnode, type_attr, type); 8865 8866 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 8867 lnname = uu_msprintf("%s_list", type); 8868 if (lnname == NULL) 8869 uu_die(gettext("Could not create string")); 8870 8871 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 8872 if (lnode == NULL) 8873 uu_die(emsg_create_xml); 8874 8875 uu_free(lnname); 8876 8877 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 8878 scfdie(); 8879 8880 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 8881 1) { 8882 xmlNodePtr vn; 8883 8884 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 8885 NULL); 8886 if (vn == NULL) 8887 uu_die(emsg_create_xml); 8888 8889 if (scf_value_get_as_string(exp_val, exp_str, 8890 exp_str_sz) < 0) 8891 scfdie(); 8892 safe_setprop(vn, value_attr, exp_str); 8893 } 8894 if (ret != 0) 8895 scfdie(); 8896 } 8897 8898 if (elts->properties == NULL) 8899 elts->properties = pnode; 8900 else 8901 (void) xmlAddSibling(elts->properties, pnode); 8902 } 8903 8904 /* 8905 * Add a property_group element for this property group to elts. 8906 */ 8907 static void 8908 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 8909 { 8910 xmlNodePtr n; 8911 struct pg_elts elts; 8912 int ret; 8913 boolean_t read_protected; 8914 8915 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 8916 8917 /* name */ 8918 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8919 scfdie(); 8920 safe_setprop(n, name_attr, exp_str); 8921 8922 /* type */ 8923 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 8924 scfdie(); 8925 safe_setprop(n, type_attr, exp_str); 8926 8927 /* properties */ 8928 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8929 scfdie(); 8930 8931 (void) memset(&elts, 0, sizeof (elts)); 8932 8933 /* 8934 * If this property group is not read protected, we always want to 8935 * output all the values. Otherwise, we only output the values if the 8936 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 8937 */ 8938 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 8939 scfdie(); 8940 8941 if (!read_protected) 8942 flags |= SCE_ALL_VALUES; 8943 8944 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8945 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8946 scfdie(); 8947 8948 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8949 xmlNodePtr m; 8950 8951 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8952 if (m == NULL) 8953 uu_die(emsg_create_xml); 8954 8955 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8956 elts.stability = m; 8957 continue; 8958 } 8959 8960 xmlFreeNode(m); 8961 } 8962 8963 export_property(exp_prop, NULL, &elts, flags); 8964 } 8965 if (ret == -1) 8966 scfdie(); 8967 8968 (void) xmlAddChild(n, elts.stability); 8969 (void) xmlAddChildList(n, elts.propvals); 8970 (void) xmlAddChildList(n, elts.properties); 8971 8972 if (eelts->property_groups == NULL) 8973 eelts->property_groups = n; 8974 else 8975 (void) xmlAddSibling(eelts->property_groups, n); 8976 } 8977 8978 /* 8979 * Create an XML node representing the dependency described by the given 8980 * property group and put it in eelts. Unless the dependency is not valid, in 8981 * which case create a generic property_group element which represents it and 8982 * put it in eelts. 8983 */ 8984 static void 8985 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 8986 { 8987 xmlNodePtr n; 8988 int err = 0, ret; 8989 struct pg_elts elts; 8990 8991 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 8992 if (n == NULL) 8993 uu_die(emsg_create_xml); 8994 8995 /* 8996 * If the external flag is present, skip this dependency because it 8997 * should have been created by another manifest. 8998 */ 8999 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 9000 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9001 prop_get_val(exp_prop, exp_val) == 0) { 9002 uint8_t b; 9003 9004 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 9005 scfdie(); 9006 9007 if (b) 9008 return; 9009 } 9010 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 9011 scfdie(); 9012 9013 /* Get the required attributes. */ 9014 9015 /* name */ 9016 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9017 scfdie(); 9018 safe_setprop(n, name_attr, exp_str); 9019 9020 /* grouping */ 9021 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9022 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9023 err = 1; 9024 9025 /* restart_on */ 9026 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9027 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9028 err = 1; 9029 9030 /* type */ 9031 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9032 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9033 err = 1; 9034 9035 /* 9036 * entities: Not required, but if we create no children, it will be 9037 * created as empty on import, so fail if it's missing. 9038 */ 9039 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9040 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 9041 scf_iter_t *eiter; 9042 int ret2; 9043 9044 eiter = scf_iter_create(g_hndl); 9045 if (eiter == NULL) 9046 scfdie(); 9047 9048 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 9049 scfdie(); 9050 9051 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 9052 xmlNodePtr ch; 9053 9054 if (scf_value_get_astring(exp_val, exp_str, 9055 exp_str_sz) < 0) 9056 scfdie(); 9057 9058 /* 9059 * service_fmri's must be first, so we can add them 9060 * here. 9061 */ 9062 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 9063 NULL); 9064 if (ch == NULL) 9065 uu_die(emsg_create_xml); 9066 9067 safe_setprop(ch, value_attr, exp_str); 9068 } 9069 if (ret2 == -1) 9070 scfdie(); 9071 9072 scf_iter_destroy(eiter); 9073 } else 9074 err = 1; 9075 9076 if (err) { 9077 xmlFreeNode(n); 9078 9079 export_pg(pg, eelts, 0); 9080 9081 return; 9082 } 9083 9084 /* Iterate through the properties & handle each. */ 9085 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9086 scfdie(); 9087 9088 (void) memset(&elts, 0, sizeof (elts)); 9089 9090 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9091 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9092 scfdie(); 9093 9094 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9095 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9096 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9097 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9098 continue; 9099 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9100 xmlNodePtr m; 9101 9102 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9103 if (m == NULL) 9104 uu_die(emsg_create_xml); 9105 9106 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9107 elts.stability = m; 9108 continue; 9109 } 9110 9111 xmlFreeNode(m); 9112 } 9113 9114 export_property(exp_prop, exp_str, &elts, 0); 9115 } 9116 if (ret == -1) 9117 scfdie(); 9118 9119 (void) xmlAddChild(n, elts.stability); 9120 (void) xmlAddChildList(n, elts.propvals); 9121 (void) xmlAddChildList(n, elts.properties); 9122 9123 if (eelts->dependencies == NULL) 9124 eelts->dependencies = n; 9125 else 9126 (void) xmlAddSibling(eelts->dependencies, n); 9127 } 9128 9129 static xmlNodePtr 9130 export_method_environment(scf_propertygroup_t *pg) 9131 { 9132 xmlNodePtr env; 9133 int ret; 9134 int children = 0; 9135 9136 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 9137 return (NULL); 9138 9139 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 9140 if (env == NULL) 9141 uu_die(emsg_create_xml); 9142 9143 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 9144 scfdie(); 9145 9146 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 9147 scfdie(); 9148 9149 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 9150 xmlNodePtr ev; 9151 char *cp; 9152 9153 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9154 scfdie(); 9155 9156 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 9157 warn(gettext("Invalid environment variable \"%s\".\n"), 9158 exp_str); 9159 continue; 9160 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 9161 warn(gettext("Invalid environment variable \"%s\"; " 9162 "\"SMF_\" prefix is reserved.\n"), exp_str); 9163 continue; 9164 } 9165 9166 *cp = '\0'; 9167 cp++; 9168 9169 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 9170 if (ev == NULL) 9171 uu_die(emsg_create_xml); 9172 9173 safe_setprop(ev, name_attr, exp_str); 9174 safe_setprop(ev, value_attr, cp); 9175 children++; 9176 } 9177 9178 if (ret != 0) 9179 scfdie(); 9180 9181 if (children == 0) { 9182 xmlFreeNode(env); 9183 return (NULL); 9184 } 9185 9186 return (env); 9187 } 9188 9189 /* 9190 * As above, but for a method property group. 9191 */ 9192 static void 9193 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 9194 { 9195 xmlNodePtr n, env; 9196 char *str; 9197 int err = 0, nonenv, ret; 9198 uint8_t use_profile; 9199 struct pg_elts elts; 9200 xmlNodePtr ctxt = NULL; 9201 9202 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 9203 9204 /* Get the required attributes. */ 9205 9206 /* name */ 9207 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9208 scfdie(); 9209 safe_setprop(n, name_attr, exp_str); 9210 9211 /* type */ 9212 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9213 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9214 err = 1; 9215 9216 /* exec */ 9217 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 9218 set_attr_from_prop(exp_prop, n, "exec") != 0) 9219 err = 1; 9220 9221 /* timeout */ 9222 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 9223 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 9224 prop_get_val(exp_prop, exp_val) == 0) { 9225 uint64_t c; 9226 9227 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 9228 scfdie(); 9229 9230 str = uu_msprintf("%llu", c); 9231 if (str == NULL) 9232 uu_die(gettext("Could not create string")); 9233 9234 safe_setprop(n, "timeout_seconds", str); 9235 free(str); 9236 } else 9237 err = 1; 9238 9239 if (err) { 9240 xmlFreeNode(n); 9241 9242 export_pg(pg, eelts, 0); 9243 9244 return; 9245 } 9246 9247 9248 /* 9249 * If we're going to have a method_context child, we need to know 9250 * before we iterate through the properties. Since method_context's 9251 * are optional, we don't want to complain about any properties 9252 * missing if none of them are there. Thus we can't use the 9253 * convenience functions. 9254 */ 9255 nonenv = 9256 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 9257 SCF_SUCCESS || 9258 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 9259 SCF_SUCCESS || 9260 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 9261 SCF_SUCCESS || 9262 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 9263 SCF_SUCCESS; 9264 9265 if (nonenv) { 9266 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9267 if (ctxt == NULL) 9268 uu_die(emsg_create_xml); 9269 9270 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 9271 0 && 9272 set_attr_from_prop_default(exp_prop, ctxt, 9273 "working_directory", ":default") != 0) 9274 err = 1; 9275 9276 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 9277 set_attr_from_prop_default(exp_prop, ctxt, "project", 9278 ":default") != 0) 9279 err = 1; 9280 9281 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 9282 0 && 9283 set_attr_from_prop_default(exp_prop, ctxt, 9284 "resource_pool", ":default") != 0) 9285 err = 1; 9286 /* 9287 * We only want to complain about profile or credential 9288 * properties if we will use them. To determine that we must 9289 * examine USE_PROFILE. 9290 */ 9291 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9292 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9293 prop_get_val(exp_prop, exp_val) == 0) { 9294 if (scf_value_get_boolean(exp_val, &use_profile) != 9295 SCF_SUCCESS) { 9296 scfdie(); 9297 } 9298 9299 if (use_profile) { 9300 xmlNodePtr prof; 9301 9302 prof = xmlNewChild(ctxt, NULL, 9303 (xmlChar *)"method_profile", NULL); 9304 if (prof == NULL) 9305 uu_die(emsg_create_xml); 9306 9307 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 9308 exp_prop) != 0 || 9309 set_attr_from_prop(exp_prop, prof, 9310 name_attr) != 0) 9311 err = 1; 9312 } else { 9313 xmlNodePtr cred; 9314 9315 cred = xmlNewChild(ctxt, NULL, 9316 (xmlChar *)"method_credential", NULL); 9317 if (cred == NULL) 9318 uu_die(emsg_create_xml); 9319 9320 if (pg_get_prop(pg, SCF_PROPERTY_USER, 9321 exp_prop) != 0 || 9322 set_attr_from_prop(exp_prop, cred, 9323 "user") != 0) { 9324 err = 1; 9325 } 9326 9327 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 9328 exp_prop) == 0 && 9329 set_attr_from_prop_default(exp_prop, cred, 9330 "group", ":default") != 0) 9331 err = 1; 9332 9333 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 9334 exp_prop) == 0 && 9335 set_attr_from_prop_default(exp_prop, cred, 9336 "supp_groups", ":default") != 0) 9337 err = 1; 9338 9339 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 9340 exp_prop) == 0 && 9341 set_attr_from_prop_default(exp_prop, cred, 9342 "privileges", ":default") != 0) 9343 err = 1; 9344 9345 if (pg_get_prop(pg, 9346 SCF_PROPERTY_LIMIT_PRIVILEGES, 9347 exp_prop) == 0 && 9348 set_attr_from_prop_default(exp_prop, cred, 9349 "limit_privileges", ":default") != 0) 9350 err = 1; 9351 } 9352 } 9353 } 9354 9355 if ((env = export_method_environment(pg)) != NULL) { 9356 if (ctxt == NULL) { 9357 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9358 if (ctxt == NULL) 9359 uu_die(emsg_create_xml); 9360 } 9361 (void) xmlAddChild(ctxt, env); 9362 } 9363 9364 if (env != NULL || (nonenv && err == 0)) 9365 (void) xmlAddChild(n, ctxt); 9366 else 9367 xmlFreeNode(ctxt); 9368 9369 nonenv = (err == 0); 9370 9371 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9372 scfdie(); 9373 9374 (void) memset(&elts, 0, sizeof (elts)); 9375 9376 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9377 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9378 scfdie(); 9379 9380 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9381 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 9382 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 9383 continue; 9384 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9385 xmlNodePtr m; 9386 9387 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9388 if (m == NULL) 9389 uu_die(emsg_create_xml); 9390 9391 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9392 elts.stability = m; 9393 continue; 9394 } 9395 9396 xmlFreeNode(m); 9397 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 9398 0 || 9399 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 9400 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 9401 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9402 if (nonenv) 9403 continue; 9404 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 9405 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 9406 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 9407 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 9408 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 9409 if (nonenv && !use_profile) 9410 continue; 9411 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9412 if (nonenv && use_profile) 9413 continue; 9414 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 9415 if (env != NULL) 9416 continue; 9417 } 9418 9419 export_property(exp_prop, exp_str, &elts, 0); 9420 } 9421 if (ret == -1) 9422 scfdie(); 9423 9424 (void) xmlAddChild(n, elts.stability); 9425 (void) xmlAddChildList(n, elts.propvals); 9426 (void) xmlAddChildList(n, elts.properties); 9427 9428 if (eelts->exec_methods == NULL) 9429 eelts->exec_methods = n; 9430 else 9431 (void) xmlAddSibling(eelts->exec_methods, n); 9432 } 9433 9434 static void 9435 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 9436 struct entity_elts *eelts) 9437 { 9438 xmlNodePtr pgnode; 9439 9440 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 9441 if (pgnode == NULL) 9442 uu_die(emsg_create_xml); 9443 9444 safe_setprop(pgnode, name_attr, name); 9445 safe_setprop(pgnode, type_attr, type); 9446 9447 (void) xmlAddChildList(pgnode, elts->propvals); 9448 (void) xmlAddChildList(pgnode, elts->properties); 9449 9450 if (eelts->property_groups == NULL) 9451 eelts->property_groups = pgnode; 9452 else 9453 (void) xmlAddSibling(eelts->property_groups, pgnode); 9454 } 9455 9456 /* 9457 * Process the general property group for a service. This is the one with the 9458 * goodies. 9459 */ 9460 static void 9461 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 9462 { 9463 struct pg_elts elts; 9464 int ret; 9465 9466 /* 9467 * In case there are properties which don't correspond to child 9468 * entities of the service entity, we'll set up a pg_elts structure to 9469 * put them in. 9470 */ 9471 (void) memset(&elts, 0, sizeof (elts)); 9472 9473 /* Walk the properties, looking for special ones. */ 9474 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9475 scfdie(); 9476 9477 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9478 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9479 scfdie(); 9480 9481 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 9482 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9483 prop_get_val(exp_prop, exp_val) == 0) { 9484 uint8_t b; 9485 9486 if (scf_value_get_boolean(exp_val, &b) != 9487 SCF_SUCCESS) 9488 scfdie(); 9489 9490 if (b) { 9491 selts->single_instance = 9492 xmlNewNode(NULL, 9493 (xmlChar *)"single_instance"); 9494 if (selts->single_instance == NULL) 9495 uu_die(emsg_create_xml); 9496 } 9497 9498 continue; 9499 } 9500 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9501 xmlNodePtr rnode, sfnode; 9502 9503 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9504 if (rnode == NULL) 9505 uu_die(emsg_create_xml); 9506 9507 sfnode = xmlNewChild(rnode, NULL, 9508 (xmlChar *)"service_fmri", NULL); 9509 if (sfnode == NULL) 9510 uu_die(emsg_create_xml); 9511 9512 if (set_attr_from_prop(exp_prop, sfnode, 9513 value_attr) == 0) { 9514 selts->restarter = rnode; 9515 continue; 9516 } 9517 9518 xmlFreeNode(rnode); 9519 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 9520 0) { 9521 xmlNodePtr s; 9522 9523 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9524 if (s == NULL) 9525 uu_die(emsg_create_xml); 9526 9527 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9528 selts->stability = s; 9529 continue; 9530 } 9531 9532 xmlFreeNode(s); 9533 } 9534 9535 export_property(exp_prop, exp_str, &elts, 0); 9536 } 9537 if (ret == -1) 9538 scfdie(); 9539 9540 if (elts.propvals != NULL || elts.properties != NULL) 9541 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 9542 selts); 9543 } 9544 9545 static void 9546 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 9547 { 9548 xmlNodePtr n, prof, cred, env; 9549 uint8_t use_profile; 9550 int ret, err = 0; 9551 9552 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 9553 9554 env = export_method_environment(pg); 9555 9556 /* Need to know whether we'll use a profile or not. */ 9557 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9558 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9559 prop_get_val(exp_prop, exp_val) == 0) { 9560 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 9561 scfdie(); 9562 9563 if (use_profile) 9564 prof = 9565 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 9566 NULL); 9567 else 9568 cred = 9569 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 9570 NULL); 9571 } 9572 9573 if (env != NULL) 9574 (void) xmlAddChild(n, env); 9575 9576 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9577 scfdie(); 9578 9579 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9580 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9581 scfdie(); 9582 9583 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 9584 if (set_attr_from_prop(exp_prop, n, 9585 "working_directory") != 0) 9586 err = 1; 9587 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 9588 if (set_attr_from_prop(exp_prop, n, "project") != 0) 9589 err = 1; 9590 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 9591 if (set_attr_from_prop(exp_prop, n, 9592 "resource_pool") != 0) 9593 err = 1; 9594 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9595 /* EMPTY */ 9596 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 9597 if (use_profile || 9598 set_attr_from_prop(exp_prop, cred, "user") != 0) 9599 err = 1; 9600 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 9601 if (use_profile || 9602 set_attr_from_prop(exp_prop, cred, "group") != 0) 9603 err = 1; 9604 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 9605 if (use_profile || set_attr_from_prop(exp_prop, cred, 9606 "supp_groups") != 0) 9607 err = 1; 9608 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 9609 if (use_profile || set_attr_from_prop(exp_prop, cred, 9610 "privileges") != 0) 9611 err = 1; 9612 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 9613 0) { 9614 if (use_profile || set_attr_from_prop(exp_prop, cred, 9615 "limit_privileges") != 0) 9616 err = 1; 9617 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9618 if (!use_profile || set_attr_from_prop(exp_prop, 9619 prof, name_attr) != 0) 9620 err = 1; 9621 } else { 9622 /* Can't have generic properties in method_context's */ 9623 err = 1; 9624 } 9625 } 9626 if (ret == -1) 9627 scfdie(); 9628 9629 if (err && env == NULL) { 9630 xmlFreeNode(n); 9631 export_pg(pg, elts, 0); 9632 return; 9633 } 9634 9635 elts->method_context = n; 9636 } 9637 9638 /* 9639 * Given a dependency property group in the tfmri entity (target fmri), return 9640 * a dependent element which represents it. 9641 */ 9642 static xmlNodePtr 9643 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 9644 { 9645 uint8_t b; 9646 xmlNodePtr n, sf; 9647 int err = 0, ret; 9648 struct pg_elts pgelts; 9649 9650 /* 9651 * If external isn't set to true then exporting the service will 9652 * export this as a normal dependency, so we should stop to avoid 9653 * duplication. 9654 */ 9655 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 9656 scf_property_get_value(exp_prop, exp_val) != 0 || 9657 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 9658 if (g_verbose) { 9659 warn(gettext("Dependent \"%s\" cannot be exported " 9660 "properly because the \"%s\" property of the " 9661 "\"%s\" dependency of %s is not set to true.\n"), 9662 name, scf_property_external, name, tfmri); 9663 } 9664 9665 return (NULL); 9666 } 9667 9668 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 9669 if (n == NULL) 9670 uu_die(emsg_create_xml); 9671 9672 safe_setprop(n, name_attr, name); 9673 9674 /* Get the required attributes */ 9675 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9676 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9677 err = 1; 9678 9679 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9680 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9681 err = 1; 9682 9683 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9684 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 9685 prop_get_val(exp_prop, exp_val) == 0) { 9686 /* EMPTY */ 9687 } else 9688 err = 1; 9689 9690 if (err) { 9691 xmlFreeNode(n); 9692 return (NULL); 9693 } 9694 9695 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 9696 if (sf == NULL) 9697 uu_die(emsg_create_xml); 9698 9699 safe_setprop(sf, value_attr, tfmri); 9700 9701 /* 9702 * Now add elements for the other properties. 9703 */ 9704 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9705 scfdie(); 9706 9707 (void) memset(&pgelts, 0, sizeof (pgelts)); 9708 9709 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9710 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9711 scfdie(); 9712 9713 if (strcmp(exp_str, scf_property_external) == 0 || 9714 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9715 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9716 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9717 continue; 9718 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 9719 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 9720 prop_get_val(exp_prop, exp_val) == 0) { 9721 char type[sizeof ("service") + 1]; 9722 9723 if (scf_value_get_astring(exp_val, type, 9724 sizeof (type)) < 0) 9725 scfdie(); 9726 9727 if (strcmp(type, "service") == 0) 9728 continue; 9729 } 9730 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9731 xmlNodePtr s; 9732 9733 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9734 if (s == NULL) 9735 uu_die(emsg_create_xml); 9736 9737 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9738 pgelts.stability = s; 9739 continue; 9740 } 9741 9742 xmlFreeNode(s); 9743 } 9744 9745 export_property(exp_prop, exp_str, &pgelts, 0); 9746 } 9747 if (ret == -1) 9748 scfdie(); 9749 9750 (void) xmlAddChild(n, pgelts.stability); 9751 (void) xmlAddChildList(n, pgelts.propvals); 9752 (void) xmlAddChildList(n, pgelts.properties); 9753 9754 return (n); 9755 } 9756 9757 static void 9758 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 9759 { 9760 scf_propertygroup_t *opg; 9761 scf_iter_t *iter; 9762 char *type, *fmri; 9763 int ret; 9764 struct pg_elts pgelts; 9765 xmlNodePtr n; 9766 scf_error_t serr; 9767 9768 if ((opg = scf_pg_create(g_hndl)) == NULL || 9769 (iter = scf_iter_create(g_hndl)) == NULL) 9770 scfdie(); 9771 9772 /* Can't use exp_prop_iter due to export_dependent(). */ 9773 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 9774 scfdie(); 9775 9776 type = safe_malloc(max_scf_pg_type_len + 1); 9777 9778 /* Get an extra byte so we can tell if values are too long. */ 9779 fmri = safe_malloc(max_scf_fmri_len + 2); 9780 9781 (void) memset(&pgelts, 0, sizeof (pgelts)); 9782 9783 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 9784 void *entity; 9785 int isservice; 9786 scf_type_t ty; 9787 9788 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 9789 scfdie(); 9790 9791 if ((ty != SCF_TYPE_ASTRING && 9792 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 9793 prop_get_val(exp_prop, exp_val) != 0) { 9794 export_property(exp_prop, NULL, &pgelts, 0); 9795 continue; 9796 } 9797 9798 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9799 scfdie(); 9800 9801 if (scf_value_get_astring(exp_val, fmri, 9802 max_scf_fmri_len + 2) < 0) 9803 scfdie(); 9804 9805 /* Look for a dependency group in the target fmri. */ 9806 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 9807 switch (serr) { 9808 case SCF_ERROR_NONE: 9809 break; 9810 9811 case SCF_ERROR_NO_MEMORY: 9812 uu_die(gettext("Out of memory.\n")); 9813 /* NOTREACHED */ 9814 9815 case SCF_ERROR_INVALID_ARGUMENT: 9816 if (g_verbose) { 9817 if (scf_property_to_fmri(exp_prop, fmri, 9818 max_scf_fmri_len + 2) < 0) 9819 scfdie(); 9820 9821 warn(gettext("The value of %s is not a valid " 9822 "FMRI.\n"), fmri); 9823 } 9824 9825 export_property(exp_prop, exp_str, &pgelts, 0); 9826 continue; 9827 9828 case SCF_ERROR_CONSTRAINT_VIOLATED: 9829 if (g_verbose) { 9830 if (scf_property_to_fmri(exp_prop, fmri, 9831 max_scf_fmri_len + 2) < 0) 9832 scfdie(); 9833 9834 warn(gettext("The value of %s does not specify " 9835 "a service or an instance.\n"), fmri); 9836 } 9837 9838 export_property(exp_prop, exp_str, &pgelts, 0); 9839 continue; 9840 9841 case SCF_ERROR_NOT_FOUND: 9842 if (g_verbose) { 9843 if (scf_property_to_fmri(exp_prop, fmri, 9844 max_scf_fmri_len + 2) < 0) 9845 scfdie(); 9846 9847 warn(gettext("The entity specified by %s does " 9848 "not exist.\n"), fmri); 9849 } 9850 9851 export_property(exp_prop, exp_str, &pgelts, 0); 9852 continue; 9853 9854 default: 9855 #ifndef NDEBUG 9856 (void) fprintf(stderr, "%s:%d: %s() failed with " 9857 "unexpected error %d.\n", __FILE__, __LINE__, 9858 "fmri_to_entity", serr); 9859 #endif 9860 abort(); 9861 } 9862 9863 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 9864 if (scf_error() != SCF_ERROR_NOT_FOUND) 9865 scfdie(); 9866 9867 warn(gettext("Entity %s is missing dependency property " 9868 "group %s.\n"), fmri, exp_str); 9869 9870 export_property(exp_prop, NULL, &pgelts, 0); 9871 continue; 9872 } 9873 9874 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 9875 scfdie(); 9876 9877 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 9878 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 9879 scfdie(); 9880 9881 warn(gettext("Property group %s is not of " 9882 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 9883 9884 export_property(exp_prop, NULL, &pgelts, 0); 9885 continue; 9886 } 9887 9888 n = export_dependent(opg, exp_str, fmri); 9889 if (n == NULL) 9890 export_property(exp_prop, exp_str, &pgelts, 0); 9891 else { 9892 if (eelts->dependents == NULL) 9893 eelts->dependents = n; 9894 else 9895 (void) xmlAddSibling(eelts->dependents, 9896 n); 9897 } 9898 } 9899 if (ret == -1) 9900 scfdie(); 9901 9902 free(fmri); 9903 free(type); 9904 9905 scf_iter_destroy(iter); 9906 scf_pg_destroy(opg); 9907 9908 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9909 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 9910 eelts); 9911 } 9912 9913 static void 9914 make_node(xmlNodePtr *nodep, const char *name) 9915 { 9916 if (*nodep == NULL) { 9917 *nodep = xmlNewNode(NULL, (xmlChar *)name); 9918 if (*nodep == NULL) 9919 uu_die(emsg_create_xml); 9920 } 9921 } 9922 9923 static xmlNodePtr 9924 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 9925 { 9926 int ret; 9927 xmlNodePtr parent = NULL; 9928 xmlNodePtr loctext = NULL; 9929 9930 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9931 scfdie(); 9932 9933 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9934 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 9935 prop_get_val(exp_prop, exp_val) != 0) 9936 continue; 9937 9938 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 9939 scfdie(); 9940 9941 make_node(&parent, parname); 9942 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 9943 (xmlChar *)exp_str); 9944 if (loctext == NULL) 9945 uu_die(emsg_create_xml); 9946 9947 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9948 scfdie(); 9949 9950 safe_setprop(loctext, "xml:lang", exp_str); 9951 } 9952 9953 if (ret == -1) 9954 scfdie(); 9955 9956 return (parent); 9957 } 9958 9959 static xmlNodePtr 9960 export_tm_manpage(scf_propertygroup_t *pg) 9961 { 9962 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 9963 if (manpage == NULL) 9964 uu_die(emsg_create_xml); 9965 9966 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 9967 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 9968 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 9969 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 9970 xmlFreeNode(manpage); 9971 return (NULL); 9972 } 9973 9974 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 9975 (void) set_attr_from_prop_default(exp_prop, 9976 manpage, "manpath", ":default"); 9977 9978 return (manpage); 9979 } 9980 9981 static xmlNodePtr 9982 export_tm_doc_link(scf_propertygroup_t *pg) 9983 { 9984 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 9985 if (doc_link == NULL) 9986 uu_die(emsg_create_xml); 9987 9988 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 9989 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 9990 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 9991 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 9992 xmlFreeNode(doc_link); 9993 return (NULL); 9994 } 9995 return (doc_link); 9996 } 9997 9998 /* 9999 * Process template information for a service or instances. 10000 */ 10001 static void 10002 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 10003 struct template_elts *telts) 10004 { 10005 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 10006 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 10007 xmlNodePtr child = NULL; 10008 10009 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 10010 scfdie(); 10011 10012 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 10013 telts->common_name = export_tm_loctext(pg, "common_name"); 10014 if (telts->common_name == NULL) 10015 export_pg(pg, elts, 0); 10016 return; 10017 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 10018 telts->description = export_tm_loctext(pg, "description"); 10019 if (telts->description == NULL) 10020 export_pg(pg, elts, 0); 10021 return; 10022 } 10023 10024 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 10025 child = export_tm_manpage(pg); 10026 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 10027 child = export_tm_doc_link(pg); 10028 } 10029 10030 if (child != NULL) { 10031 make_node(&telts->documentation, "documentation"); 10032 (void) xmlAddChild(telts->documentation, child); 10033 } else { 10034 export_pg(pg, elts, 0); 10035 } 10036 } 10037 10038 /* 10039 * Process parameter and paramval elements 10040 */ 10041 static void 10042 export_parameter(scf_property_t *prop, const char *name, 10043 struct params_elts *elts) 10044 { 10045 xmlNodePtr param; 10046 scf_error_t err = 0; 10047 int ret; 10048 10049 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 10050 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL) 10051 uu_die(emsg_create_xml); 10052 10053 safe_setprop(param, name_attr, name); 10054 10055 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 10056 scfdie(); 10057 safe_setprop(param, value_attr, exp_str); 10058 10059 if (elts->paramval == NULL) 10060 elts->paramval = param; 10061 else 10062 (void) xmlAddSibling(elts->paramval, param); 10063 10064 return; 10065 } 10066 10067 err = scf_error(); 10068 10069 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 10070 err != SCF_ERROR_NOT_FOUND) 10071 scfdie(); 10072 10073 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL) 10074 uu_die(emsg_create_xml); 10075 10076 safe_setprop(param, name_attr, name); 10077 10078 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 10079 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 10080 scfdie(); 10081 10082 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 10083 1) { 10084 xmlNodePtr vn; 10085 10086 if ((vn = xmlNewChild(param, NULL, 10087 (xmlChar *)"value_node", NULL)) == NULL) 10088 uu_die(emsg_create_xml); 10089 10090 if (scf_value_get_as_string(exp_val, exp_str, 10091 exp_str_sz) < 0) 10092 scfdie(); 10093 10094 safe_setprop(vn, value_attr, exp_str); 10095 } 10096 if (ret != 0) 10097 scfdie(); 10098 } 10099 10100 if (elts->parameter == NULL) 10101 elts->parameter = param; 10102 else 10103 (void) xmlAddSibling(elts->parameter, param); 10104 } 10105 10106 /* 10107 * Process notification parameters for a service or instance 10108 */ 10109 static void 10110 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts) 10111 { 10112 xmlNodePtr n, event, *type; 10113 struct params_elts *eelts; 10114 int ret, err, i; 10115 10116 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters"); 10117 event = xmlNewNode(NULL, (xmlChar *)"event"); 10118 if (n == NULL || event == NULL) 10119 uu_die(emsg_create_xml); 10120 10121 /* event value */ 10122 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 10123 scfdie(); 10124 safe_setprop(event, value_attr, exp_str); 10125 10126 (void) xmlAddChild(n, event); 10127 10128 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL || 10129 (eelts = calloc(URI_SCHEME_NUM, 10130 sizeof (struct params_elts))) == NULL) 10131 uu_die(gettext("Out of memory.\n")); 10132 10133 err = 0; 10134 10135 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10136 scfdie(); 10137 10138 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10139 char *t, *p; 10140 10141 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10142 scfdie(); 10143 10144 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) { 10145 /* 10146 * this is not a well formed notification parameters 10147 * element, we should export as regular pg 10148 */ 10149 err = 1; 10150 break; 10151 } 10152 10153 if ((i = check_uri_protocol(t)) < 0) { 10154 err = 1; 10155 break; 10156 } 10157 10158 if (type[i] == NULL) { 10159 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) == 10160 NULL) 10161 uu_die(emsg_create_xml); 10162 10163 safe_setprop(type[i], name_attr, t); 10164 } 10165 if (strcmp(p, active_attr) == 0) { 10166 if (set_attr_from_prop(exp_prop, type[i], 10167 active_attr) != 0) { 10168 err = 1; 10169 break; 10170 } 10171 continue; 10172 } 10173 /* 10174 * We export the parameter 10175 */ 10176 export_parameter(exp_prop, p, &eelts[i]); 10177 } 10178 10179 if (ret == -1) 10180 scfdie(); 10181 10182 if (err == 1) { 10183 for (i = 0; i < URI_SCHEME_NUM; ++i) 10184 xmlFree(type[i]); 10185 free(type); 10186 10187 export_pg(pg, elts, 0); 10188 10189 return; 10190 } else { 10191 for (i = 0; i < URI_SCHEME_NUM; ++i) 10192 if (type[i] != NULL) { 10193 (void) xmlAddChildList(type[i], 10194 eelts[i].paramval); 10195 (void) xmlAddChildList(type[i], 10196 eelts[i].parameter); 10197 (void) xmlAddSibling(event, type[i]); 10198 } 10199 } 10200 free(type); 10201 10202 if (elts->notify_params == NULL) 10203 elts->notify_params = n; 10204 else 10205 (void) xmlAddSibling(elts->notify_params, n); 10206 } 10207 10208 /* 10209 * Process the general property group for an instance. 10210 */ 10211 static void 10212 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 10213 struct entity_elts *elts) 10214 { 10215 uint8_t enabled; 10216 struct pg_elts pgelts; 10217 int ret; 10218 10219 /* enabled */ 10220 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10221 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10222 prop_get_val(exp_prop, exp_val) == 0) { 10223 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10224 scfdie(); 10225 } else { 10226 enabled = 0; 10227 } 10228 10229 safe_setprop(inode, enabled_attr, enabled ? true : false); 10230 10231 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10232 scfdie(); 10233 10234 (void) memset(&pgelts, 0, sizeof (pgelts)); 10235 10236 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10237 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10238 scfdie(); 10239 10240 if (strcmp(exp_str, scf_property_enabled) == 0) { 10241 continue; 10242 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10243 xmlNodePtr rnode, sfnode; 10244 10245 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10246 if (rnode == NULL) 10247 uu_die(emsg_create_xml); 10248 10249 sfnode = xmlNewChild(rnode, NULL, 10250 (xmlChar *)"service_fmri", NULL); 10251 if (sfnode == NULL) 10252 uu_die(emsg_create_xml); 10253 10254 if (set_attr_from_prop(exp_prop, sfnode, 10255 value_attr) == 0) { 10256 elts->restarter = rnode; 10257 continue; 10258 } 10259 10260 xmlFreeNode(rnode); 10261 } 10262 10263 export_property(exp_prop, exp_str, &pgelts, 0); 10264 } 10265 if (ret == -1) 10266 scfdie(); 10267 10268 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10269 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10270 elts); 10271 } 10272 10273 /* 10274 * Put an instance element for the given instance into selts. 10275 */ 10276 static void 10277 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10278 { 10279 xmlNodePtr n; 10280 boolean_t isdefault; 10281 struct entity_elts elts; 10282 struct template_elts template_elts; 10283 int ret; 10284 10285 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10286 if (n == NULL) 10287 uu_die(emsg_create_xml); 10288 10289 /* name */ 10290 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10291 scfdie(); 10292 safe_setprop(n, name_attr, exp_str); 10293 isdefault = strcmp(exp_str, "default") == 0; 10294 10295 /* check existance of general pg (since general/enabled is required) */ 10296 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10297 if (scf_error() != SCF_ERROR_NOT_FOUND) 10298 scfdie(); 10299 10300 if (g_verbose) { 10301 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10302 scfdie(); 10303 10304 warn(gettext("Instance %s has no general property " 10305 "group; it will be marked disabled.\n"), exp_str); 10306 } 10307 10308 safe_setprop(n, enabled_attr, false); 10309 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10310 strcmp(exp_str, scf_group_framework) != 0) { 10311 if (g_verbose) { 10312 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10313 scfdie(); 10314 10315 warn(gettext("Property group %s is not of type " 10316 "framework; the instance will be marked " 10317 "disabled.\n"), exp_str); 10318 } 10319 10320 safe_setprop(n, enabled_attr, false); 10321 } 10322 10323 /* property groups */ 10324 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10325 scfdie(); 10326 10327 (void) memset(&elts, 0, sizeof (elts)); 10328 (void) memset(&template_elts, 0, sizeof (template_elts)); 10329 10330 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10331 uint32_t pgflags; 10332 10333 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10334 scfdie(); 10335 10336 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10337 continue; 10338 10339 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10340 scfdie(); 10341 10342 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10343 export_dependency(exp_pg, &elts); 10344 continue; 10345 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10346 export_method(exp_pg, &elts); 10347 continue; 10348 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10349 if (scf_pg_get_name(exp_pg, exp_str, 10350 max_scf_name_len + 1) < 0) 10351 scfdie(); 10352 10353 if (strcmp(exp_str, scf_pg_general) == 0) { 10354 export_inst_general(exp_pg, n, &elts); 10355 continue; 10356 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10357 0) { 10358 export_method_context(exp_pg, &elts); 10359 continue; 10360 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10361 export_dependents(exp_pg, &elts); 10362 continue; 10363 } 10364 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10365 export_template(exp_pg, &elts, &template_elts); 10366 continue; 10367 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10368 export_notify_params(exp_pg, &elts); 10369 continue; 10370 } 10371 10372 /* Ordinary pg. */ 10373 export_pg(exp_pg, &elts, flags); 10374 } 10375 if (ret == -1) 10376 scfdie(); 10377 10378 if (template_elts.common_name != NULL) { 10379 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10380 (void) xmlAddChild(elts.template, template_elts.common_name); 10381 (void) xmlAddChild(elts.template, template_elts.description); 10382 (void) xmlAddChild(elts.template, template_elts.documentation); 10383 } else { 10384 xmlFreeNode(template_elts.description); 10385 xmlFreeNode(template_elts.documentation); 10386 } 10387 10388 if (isdefault && elts.restarter == NULL && 10389 elts.dependencies == NULL && elts.method_context == NULL && 10390 elts.exec_methods == NULL && elts.notify_params == NULL && 10391 elts.property_groups == NULL && elts.template == NULL) { 10392 xmlChar *eval; 10393 10394 /* This is a default instance */ 10395 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10396 10397 xmlFreeNode(n); 10398 10399 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10400 if (n == NULL) 10401 uu_die(emsg_create_xml); 10402 10403 safe_setprop(n, enabled_attr, (char *)eval); 10404 xmlFree(eval); 10405 10406 selts->create_default_instance = n; 10407 } else { 10408 /* Assemble the children in order. */ 10409 (void) xmlAddChild(n, elts.restarter); 10410 (void) xmlAddChildList(n, elts.dependencies); 10411 (void) xmlAddChildList(n, elts.dependents); 10412 (void) xmlAddChild(n, elts.method_context); 10413 (void) xmlAddChildList(n, elts.exec_methods); 10414 (void) xmlAddChildList(n, elts.notify_params); 10415 (void) xmlAddChildList(n, elts.property_groups); 10416 (void) xmlAddChild(n, elts.template); 10417 10418 if (selts->instances == NULL) 10419 selts->instances = n; 10420 else 10421 (void) xmlAddSibling(selts->instances, n); 10422 } 10423 } 10424 10425 /* 10426 * Return a service element for the given service. 10427 */ 10428 static xmlNodePtr 10429 export_service(scf_service_t *svc, int flags) 10430 { 10431 xmlNodePtr snode; 10432 struct entity_elts elts; 10433 struct template_elts template_elts; 10434 int ret; 10435 10436 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10437 if (snode == NULL) 10438 uu_die(emsg_create_xml); 10439 10440 /* Get & set name attribute */ 10441 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10442 scfdie(); 10443 safe_setprop(snode, name_attr, exp_str); 10444 10445 safe_setprop(snode, type_attr, "service"); 10446 safe_setprop(snode, "version", "0"); 10447 10448 /* Acquire child elements. */ 10449 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10450 scfdie(); 10451 10452 (void) memset(&elts, 0, sizeof (elts)); 10453 (void) memset(&template_elts, 0, sizeof (template_elts)); 10454 10455 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10456 uint32_t pgflags; 10457 10458 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10459 scfdie(); 10460 10461 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10462 continue; 10463 10464 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10465 scfdie(); 10466 10467 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10468 export_dependency(exp_pg, &elts); 10469 continue; 10470 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10471 export_method(exp_pg, &elts); 10472 continue; 10473 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10474 if (scf_pg_get_name(exp_pg, exp_str, 10475 max_scf_name_len + 1) < 0) 10476 scfdie(); 10477 10478 if (strcmp(exp_str, scf_pg_general) == 0) { 10479 export_svc_general(exp_pg, &elts); 10480 continue; 10481 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10482 0) { 10483 export_method_context(exp_pg, &elts); 10484 continue; 10485 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10486 export_dependents(exp_pg, &elts); 10487 continue; 10488 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10489 continue; 10490 } 10491 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10492 export_template(exp_pg, &elts, &template_elts); 10493 continue; 10494 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10495 export_notify_params(exp_pg, &elts); 10496 continue; 10497 } 10498 10499 export_pg(exp_pg, &elts, flags); 10500 } 10501 if (ret == -1) 10502 scfdie(); 10503 10504 if (template_elts.common_name != NULL) { 10505 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10506 (void) xmlAddChild(elts.template, template_elts.common_name); 10507 (void) xmlAddChild(elts.template, template_elts.description); 10508 (void) xmlAddChild(elts.template, template_elts.documentation); 10509 } else { 10510 xmlFreeNode(template_elts.description); 10511 xmlFreeNode(template_elts.documentation); 10512 } 10513 10514 /* Iterate instances */ 10515 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10516 scfdie(); 10517 10518 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10519 export_instance(exp_inst, &elts, flags); 10520 if (ret == -1) 10521 scfdie(); 10522 10523 /* Now add all of the accumulated elements in order. */ 10524 (void) xmlAddChild(snode, elts.create_default_instance); 10525 (void) xmlAddChild(snode, elts.single_instance); 10526 (void) xmlAddChild(snode, elts.restarter); 10527 (void) xmlAddChildList(snode, elts.dependencies); 10528 (void) xmlAddChildList(snode, elts.dependents); 10529 (void) xmlAddChild(snode, elts.method_context); 10530 (void) xmlAddChildList(snode, elts.exec_methods); 10531 (void) xmlAddChildList(snode, elts.notify_params); 10532 (void) xmlAddChildList(snode, elts.property_groups); 10533 (void) xmlAddChildList(snode, elts.instances); 10534 (void) xmlAddChild(snode, elts.stability); 10535 (void) xmlAddChild(snode, elts.template); 10536 10537 return (snode); 10538 } 10539 10540 static int 10541 export_callback(void *data, scf_walkinfo_t *wip) 10542 { 10543 FILE *f; 10544 xmlDocPtr doc; 10545 xmlNodePtr sb; 10546 int result; 10547 struct export_args *argsp = (struct export_args *)data; 10548 10549 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10550 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10551 (exp_prop = scf_property_create(g_hndl)) == NULL || 10552 (exp_val = scf_value_create(g_hndl)) == NULL || 10553 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10554 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10555 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10556 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10557 scfdie(); 10558 10559 exp_str_sz = max_scf_len + 1; 10560 exp_str = safe_malloc(exp_str_sz); 10561 10562 if (argsp->filename != NULL) { 10563 errno = 0; 10564 f = fopen(argsp->filename, "wb"); 10565 if (f == NULL) { 10566 if (errno == 0) 10567 uu_die(gettext("Could not open \"%s\": no free " 10568 "stdio streams.\n"), argsp->filename); 10569 else 10570 uu_die(gettext("Could not open \"%s\""), 10571 argsp->filename); 10572 } 10573 } else 10574 f = stdout; 10575 10576 doc = xmlNewDoc((xmlChar *)"1.0"); 10577 if (doc == NULL) 10578 uu_die(gettext("Could not create XML document.\n")); 10579 10580 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10581 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10582 uu_die(emsg_create_xml); 10583 10584 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10585 if (sb == NULL) 10586 uu_die(emsg_create_xml); 10587 safe_setprop(sb, type_attr, "manifest"); 10588 safe_setprop(sb, name_attr, "export"); 10589 (void) xmlAddSibling(doc->children, sb); 10590 10591 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10592 10593 result = write_service_bundle(doc, f); 10594 10595 free(exp_str); 10596 scf_iter_destroy(exp_val_iter); 10597 scf_iter_destroy(exp_prop_iter); 10598 scf_iter_destroy(exp_pg_iter); 10599 scf_iter_destroy(exp_inst_iter); 10600 scf_value_destroy(exp_val); 10601 scf_property_destroy(exp_prop); 10602 scf_pg_destroy(exp_pg); 10603 scf_instance_destroy(exp_inst); 10604 10605 xmlFreeDoc(doc); 10606 10607 if (f != stdout) 10608 (void) fclose(f); 10609 10610 return (result); 10611 } 10612 10613 /* 10614 * Get the service named by fmri, build an XML tree which represents it, and 10615 * dump it into filename (or stdout if filename is NULL). 10616 */ 10617 int 10618 lscf_service_export(char *fmri, const char *filename, int flags) 10619 { 10620 struct export_args args; 10621 int ret, err; 10622 10623 lscf_prep_hndl(); 10624 10625 bzero(&args, sizeof (args)); 10626 args.filename = filename; 10627 args.flags = flags; 10628 10629 err = 0; 10630 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10631 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10632 &args, &err, semerr)) != 0) { 10633 if (ret != -1) 10634 semerr(gettext("Failed to walk instances: %s\n"), 10635 scf_strerror(ret)); 10636 return (-1); 10637 } 10638 10639 /* 10640 * Error message has already been printed. 10641 */ 10642 if (err != 0) 10643 return (-1); 10644 10645 return (0); 10646 } 10647 10648 10649 /* 10650 * Archive 10651 */ 10652 10653 static xmlNodePtr 10654 make_archive(int flags) 10655 { 10656 xmlNodePtr sb; 10657 scf_scope_t *scope; 10658 scf_service_t *svc; 10659 scf_iter_t *iter; 10660 int r; 10661 10662 if ((scope = scf_scope_create(g_hndl)) == NULL || 10663 (svc = scf_service_create(g_hndl)) == NULL || 10664 (iter = scf_iter_create(g_hndl)) == NULL || 10665 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10666 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10667 (exp_prop = scf_property_create(g_hndl)) == NULL || 10668 (exp_val = scf_value_create(g_hndl)) == NULL || 10669 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10670 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10671 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10672 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10673 scfdie(); 10674 10675 exp_str_sz = max_scf_len + 1; 10676 exp_str = safe_malloc(exp_str_sz); 10677 10678 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10679 if (sb == NULL) 10680 uu_die(emsg_create_xml); 10681 safe_setprop(sb, type_attr, "archive"); 10682 safe_setprop(sb, name_attr, "none"); 10683 10684 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 10685 scfdie(); 10686 if (scf_iter_scope_services(iter, scope) != 0) 10687 scfdie(); 10688 10689 for (;;) { 10690 r = scf_iter_next_service(iter, svc); 10691 if (r == 0) 10692 break; 10693 if (r != 1) 10694 scfdie(); 10695 10696 if (scf_service_get_name(svc, exp_str, 10697 max_scf_name_len + 1) < 0) 10698 scfdie(); 10699 10700 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 10701 continue; 10702 10703 (void) xmlAddChild(sb, export_service(svc, flags)); 10704 } 10705 10706 free(exp_str); 10707 10708 scf_iter_destroy(exp_val_iter); 10709 scf_iter_destroy(exp_prop_iter); 10710 scf_iter_destroy(exp_pg_iter); 10711 scf_iter_destroy(exp_inst_iter); 10712 scf_value_destroy(exp_val); 10713 scf_property_destroy(exp_prop); 10714 scf_pg_destroy(exp_pg); 10715 scf_instance_destroy(exp_inst); 10716 scf_iter_destroy(iter); 10717 scf_service_destroy(svc); 10718 scf_scope_destroy(scope); 10719 10720 return (sb); 10721 } 10722 10723 int 10724 lscf_archive(const char *filename, int flags) 10725 { 10726 FILE *f; 10727 xmlDocPtr doc; 10728 int result; 10729 10730 lscf_prep_hndl(); 10731 10732 if (filename != NULL) { 10733 errno = 0; 10734 f = fopen(filename, "wb"); 10735 if (f == NULL) { 10736 if (errno == 0) 10737 uu_die(gettext("Could not open \"%s\": no free " 10738 "stdio streams.\n"), filename); 10739 else 10740 uu_die(gettext("Could not open \"%s\""), 10741 filename); 10742 } 10743 } else 10744 f = stdout; 10745 10746 doc = xmlNewDoc((xmlChar *)"1.0"); 10747 if (doc == NULL) 10748 uu_die(gettext("Could not create XML document.\n")); 10749 10750 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10751 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10752 uu_die(emsg_create_xml); 10753 10754 (void) xmlAddSibling(doc->children, make_archive(flags)); 10755 10756 result = write_service_bundle(doc, f); 10757 10758 xmlFreeDoc(doc); 10759 10760 if (f != stdout) 10761 (void) fclose(f); 10762 10763 return (result); 10764 } 10765 10766 10767 /* 10768 * "Extract" a profile. 10769 */ 10770 int 10771 lscf_profile_extract(const char *filename) 10772 { 10773 FILE *f; 10774 xmlDocPtr doc; 10775 xmlNodePtr sb, snode, inode; 10776 scf_scope_t *scope; 10777 scf_service_t *svc; 10778 scf_instance_t *inst; 10779 scf_propertygroup_t *pg; 10780 scf_property_t *prop; 10781 scf_value_t *val; 10782 scf_iter_t *siter, *iiter; 10783 int r, s; 10784 char *namebuf; 10785 uint8_t b; 10786 int result; 10787 10788 lscf_prep_hndl(); 10789 10790 if (filename != NULL) { 10791 errno = 0; 10792 f = fopen(filename, "wb"); 10793 if (f == NULL) { 10794 if (errno == 0) 10795 uu_die(gettext("Could not open \"%s\": no " 10796 "free stdio streams.\n"), filename); 10797 else 10798 uu_die(gettext("Could not open \"%s\""), 10799 filename); 10800 } 10801 } else 10802 f = stdout; 10803 10804 doc = xmlNewDoc((xmlChar *)"1.0"); 10805 if (doc == NULL) 10806 uu_die(gettext("Could not create XML document.\n")); 10807 10808 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10809 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10810 uu_die(emsg_create_xml); 10811 10812 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10813 if (sb == NULL) 10814 uu_die(emsg_create_xml); 10815 safe_setprop(sb, type_attr, "profile"); 10816 safe_setprop(sb, name_attr, "extract"); 10817 (void) xmlAddSibling(doc->children, sb); 10818 10819 if ((scope = scf_scope_create(g_hndl)) == NULL || 10820 (svc = scf_service_create(g_hndl)) == NULL || 10821 (inst = scf_instance_create(g_hndl)) == NULL || 10822 (pg = scf_pg_create(g_hndl)) == NULL || 10823 (prop = scf_property_create(g_hndl)) == NULL || 10824 (val = scf_value_create(g_hndl)) == NULL || 10825 (siter = scf_iter_create(g_hndl)) == NULL || 10826 (iiter = scf_iter_create(g_hndl)) == NULL) 10827 scfdie(); 10828 10829 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 10830 scfdie(); 10831 10832 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 10833 scfdie(); 10834 10835 namebuf = safe_malloc(max_scf_name_len + 1); 10836 10837 while ((r = scf_iter_next_service(siter, svc)) == 1) { 10838 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 10839 scfdie(); 10840 10841 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10842 if (snode == NULL) 10843 uu_die(emsg_create_xml); 10844 10845 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 10846 0) 10847 scfdie(); 10848 10849 safe_setprop(snode, name_attr, namebuf); 10850 10851 safe_setprop(snode, type_attr, "service"); 10852 safe_setprop(snode, "version", "0"); 10853 10854 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 10855 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 10856 SCF_SUCCESS) { 10857 if (scf_error() != SCF_ERROR_NOT_FOUND) 10858 scfdie(); 10859 10860 if (g_verbose) { 10861 ssize_t len; 10862 char *fmri; 10863 10864 len = 10865 scf_instance_to_fmri(inst, NULL, 0); 10866 if (len < 0) 10867 scfdie(); 10868 10869 fmri = safe_malloc(len + 1); 10870 10871 if (scf_instance_to_fmri(inst, fmri, 10872 len + 1) < 0) 10873 scfdie(); 10874 10875 warn("Instance %s has no \"%s\" " 10876 "property group.\n", fmri, 10877 scf_pg_general); 10878 10879 free(fmri); 10880 } 10881 10882 continue; 10883 } 10884 10885 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 10886 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 10887 prop_get_val(prop, val) != 0) 10888 continue; 10889 10890 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 10891 NULL); 10892 if (inode == NULL) 10893 uu_die(emsg_create_xml); 10894 10895 if (scf_instance_get_name(inst, namebuf, 10896 max_scf_name_len + 1) < 0) 10897 scfdie(); 10898 10899 safe_setprop(inode, name_attr, namebuf); 10900 10901 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 10902 scfdie(); 10903 10904 safe_setprop(inode, enabled_attr, b ? true : false); 10905 } 10906 if (s < 0) 10907 scfdie(); 10908 10909 if (snode->children != NULL) 10910 (void) xmlAddChild(sb, snode); 10911 else 10912 xmlFreeNode(snode); 10913 } 10914 if (r < 0) 10915 scfdie(); 10916 10917 free(namebuf); 10918 10919 result = write_service_bundle(doc, f); 10920 10921 xmlFreeDoc(doc); 10922 10923 if (f != stdout) 10924 (void) fclose(f); 10925 10926 return (result); 10927 } 10928 10929 10930 /* 10931 * Entity manipulation commands 10932 */ 10933 10934 /* 10935 * Entity selection. If no entity is selected, then the current scope is in 10936 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 10937 * only cur_inst is NULL, and when an instance is selected, none are NULL. 10938 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 10939 * cur_inst will be non-NULL. 10940 */ 10941 10942 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 10943 static int 10944 select_inst(const char *name) 10945 { 10946 scf_instance_t *inst; 10947 scf_error_t err; 10948 10949 assert(cur_svc != NULL); 10950 10951 inst = scf_instance_create(g_hndl); 10952 if (inst == NULL) 10953 scfdie(); 10954 10955 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 10956 cur_inst = inst; 10957 return (0); 10958 } 10959 10960 err = scf_error(); 10961 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10962 scfdie(); 10963 10964 scf_instance_destroy(inst); 10965 return (1); 10966 } 10967 10968 /* Returns as above. */ 10969 static int 10970 select_svc(const char *name) 10971 { 10972 scf_service_t *svc; 10973 scf_error_t err; 10974 10975 assert(cur_scope != NULL); 10976 10977 svc = scf_service_create(g_hndl); 10978 if (svc == NULL) 10979 scfdie(); 10980 10981 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 10982 cur_svc = svc; 10983 return (0); 10984 } 10985 10986 err = scf_error(); 10987 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10988 scfdie(); 10989 10990 scf_service_destroy(svc); 10991 return (1); 10992 } 10993 10994 /* ARGSUSED */ 10995 static int 10996 select_callback(void *unused, scf_walkinfo_t *wip) 10997 { 10998 scf_instance_t *inst; 10999 scf_service_t *svc; 11000 scf_scope_t *scope; 11001 11002 if (wip->inst != NULL) { 11003 if ((scope = scf_scope_create(g_hndl)) == NULL || 11004 (svc = scf_service_create(g_hndl)) == NULL || 11005 (inst = scf_instance_create(g_hndl)) == NULL) 11006 scfdie(); 11007 11008 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11009 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11010 scfdie(); 11011 } else { 11012 assert(wip->svc != NULL); 11013 11014 if ((scope = scf_scope_create(g_hndl)) == NULL || 11015 (svc = scf_service_create(g_hndl)) == NULL) 11016 scfdie(); 11017 11018 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11019 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11020 scfdie(); 11021 11022 inst = NULL; 11023 } 11024 11025 /* Clear out the current selection */ 11026 assert(cur_scope != NULL); 11027 scf_scope_destroy(cur_scope); 11028 scf_service_destroy(cur_svc); 11029 scf_instance_destroy(cur_inst); 11030 11031 cur_scope = scope; 11032 cur_svc = svc; 11033 cur_inst = inst; 11034 11035 return (0); 11036 } 11037 11038 static int 11039 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 11040 { 11041 char **fmri = fmri_p; 11042 11043 *fmri = strdup(wip->fmri); 11044 if (*fmri == NULL) 11045 uu_die(gettext("Out of memory.\n")); 11046 11047 return (0); 11048 } 11049 11050 /* 11051 * validate [fmri] 11052 * Perform the validation of an FMRI instance. 11053 */ 11054 void 11055 lscf_validate_fmri(const char *fmri) 11056 { 11057 int ret = 0; 11058 size_t inst_sz; 11059 char *inst_fmri = NULL; 11060 scf_tmpl_errors_t *errs = NULL; 11061 char *snapbuf = NULL; 11062 11063 lscf_prep_hndl(); 11064 11065 if (fmri == NULL) { 11066 inst_sz = max_scf_fmri_len + 1; 11067 inst_fmri = safe_malloc(inst_sz); 11068 11069 if (cur_snap != NULL) { 11070 snapbuf = safe_malloc(max_scf_name_len + 1); 11071 if (scf_snapshot_get_name(cur_snap, snapbuf, 11072 max_scf_name_len + 1) < 0) 11073 scfdie(); 11074 } 11075 if (cur_inst == NULL) { 11076 semerr(gettext("No instance selected\n")); 11077 goto cleanup; 11078 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 11079 inst_sz) >= inst_sz) { 11080 /* sanity check. Should never get here */ 11081 uu_die(gettext("Unexpected error! file %s, line %d\n"), 11082 __FILE__, __LINE__); 11083 } 11084 } else { 11085 scf_error_t scf_err; 11086 int err = 0; 11087 11088 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 11089 validate_callback, &inst_fmri, &err, semerr)) != 0) { 11090 uu_warn("Failed to walk instances: %s\n", 11091 scf_strerror(scf_err)); 11092 goto cleanup; 11093 } 11094 if (err != 0) { 11095 /* error message displayed by scf_walk_fmri */ 11096 goto cleanup; 11097 } 11098 } 11099 11100 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 11101 SCF_TMPL_VALIDATE_FLAG_CURRENT); 11102 if (ret == -1) { 11103 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 11104 warn(gettext("Template data for %s is invalid. " 11105 "Consider reverting to a previous snapshot or " 11106 "restoring original configuration.\n"), inst_fmri); 11107 } else { 11108 uu_warn("%s: %s\n", 11109 gettext("Error validating the instance"), 11110 scf_strerror(scf_error())); 11111 } 11112 } else if (ret == 1 && errs != NULL) { 11113 scf_tmpl_error_t *err = NULL; 11114 char *msg; 11115 size_t len = 256; /* initial error buffer size */ 11116 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 11117 SCF_TMPL_STRERROR_HUMAN : 0; 11118 11119 msg = safe_malloc(len); 11120 11121 while ((err = scf_tmpl_next_error(errs)) != NULL) { 11122 int ret; 11123 11124 if ((ret = scf_tmpl_strerror(err, msg, len, 11125 flag)) >= len) { 11126 len = ret + 1; 11127 msg = realloc(msg, len); 11128 if (msg == NULL) 11129 uu_die(gettext( 11130 "Out of memory.\n")); 11131 (void) scf_tmpl_strerror(err, msg, len, 11132 flag); 11133 } 11134 (void) fprintf(stderr, "%s\n", msg); 11135 } 11136 if (msg != NULL) 11137 free(msg); 11138 } 11139 if (errs != NULL) 11140 scf_tmpl_errors_destroy(errs); 11141 11142 cleanup: 11143 free(inst_fmri); 11144 free(snapbuf); 11145 } 11146 11147 static void 11148 lscf_validate_file(const char *filename) 11149 { 11150 tmpl_errors_t *errs; 11151 11152 bundle_t *b = internal_bundle_new(); 11153 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 11154 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 11155 tmpl_errors_print(stderr, errs, ""); 11156 semerr(gettext("Validation failed.\n")); 11157 } 11158 tmpl_errors_destroy(errs); 11159 } 11160 (void) internal_bundle_free(b); 11161 } 11162 11163 /* 11164 * validate [fmri|file] 11165 */ 11166 void 11167 lscf_validate(const char *arg) 11168 { 11169 const char *str; 11170 11171 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 11172 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 11173 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 11174 lscf_validate_file(str); 11175 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 11176 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 11177 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 11178 lscf_validate_fmri(str); 11179 } else if (access(arg, R_OK | F_OK) == 0) { 11180 lscf_validate_file(arg); 11181 } else { 11182 lscf_validate_fmri(arg); 11183 } 11184 } 11185 11186 void 11187 lscf_select(const char *fmri) 11188 { 11189 int ret, err; 11190 11191 lscf_prep_hndl(); 11192 11193 if (cur_snap != NULL) { 11194 struct snaplevel *elt; 11195 char *buf; 11196 11197 /* Error unless name is that of the next level. */ 11198 elt = uu_list_next(cur_levels, cur_elt); 11199 if (elt == NULL) { 11200 semerr(gettext("No children.\n")); 11201 return; 11202 } 11203 11204 buf = safe_malloc(max_scf_name_len + 1); 11205 11206 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11207 max_scf_name_len + 1) < 0) 11208 scfdie(); 11209 11210 if (strcmp(buf, fmri) != 0) { 11211 semerr(gettext("No such child.\n")); 11212 free(buf); 11213 return; 11214 } 11215 11216 free(buf); 11217 11218 cur_elt = elt; 11219 cur_level = elt->sl; 11220 return; 11221 } 11222 11223 /* 11224 * Special case for 'svc:', which takes the user to the scope level. 11225 */ 11226 if (strcmp(fmri, "svc:") == 0) { 11227 scf_instance_destroy(cur_inst); 11228 scf_service_destroy(cur_svc); 11229 cur_inst = NULL; 11230 cur_svc = NULL; 11231 return; 11232 } 11233 11234 /* 11235 * Special case for ':properties'. This appears as part of 'list' but 11236 * can't be selected. Give a more helpful error message in this case. 11237 */ 11238 if (strcmp(fmri, ":properties") == 0) { 11239 semerr(gettext(":properties is not an entity. Try 'listprop' " 11240 "to list properties.\n")); 11241 return; 11242 } 11243 11244 /* 11245 * First try the argument as relative to the current selection. 11246 */ 11247 if (cur_inst != NULL) { 11248 /* EMPTY */; 11249 } else if (cur_svc != NULL) { 11250 if (select_inst(fmri) != 1) 11251 return; 11252 } else { 11253 if (select_svc(fmri) != 1) 11254 return; 11255 } 11256 11257 err = 0; 11258 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11259 select_callback, NULL, &err, semerr)) != 0) { 11260 semerr(gettext("Failed to walk instances: %s\n"), 11261 scf_strerror(ret)); 11262 } 11263 } 11264 11265 void 11266 lscf_unselect(void) 11267 { 11268 lscf_prep_hndl(); 11269 11270 if (cur_snap != NULL) { 11271 struct snaplevel *elt; 11272 11273 elt = uu_list_prev(cur_levels, cur_elt); 11274 if (elt == NULL) { 11275 semerr(gettext("No parent levels.\n")); 11276 } else { 11277 cur_elt = elt; 11278 cur_level = elt->sl; 11279 } 11280 } else if (cur_inst != NULL) { 11281 scf_instance_destroy(cur_inst); 11282 cur_inst = NULL; 11283 } else if (cur_svc != NULL) { 11284 scf_service_destroy(cur_svc); 11285 cur_svc = NULL; 11286 } else { 11287 semerr(gettext("Cannot unselect at scope level.\n")); 11288 } 11289 } 11290 11291 /* 11292 * Return the FMRI of the current selection, for the prompt. 11293 */ 11294 void 11295 lscf_get_selection_str(char *buf, size_t bufsz) 11296 { 11297 char *cp; 11298 ssize_t fmrilen, szret; 11299 boolean_t deleted = B_FALSE; 11300 11301 if (g_hndl == NULL) { 11302 (void) strlcpy(buf, "svc:", bufsz); 11303 return; 11304 } 11305 11306 if (cur_level != NULL) { 11307 assert(cur_snap != NULL); 11308 11309 /* [ snapshot ] FMRI [: instance ] */ 11310 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11311 + 2 + max_scf_name_len + 1 + 1); 11312 11313 buf[0] = '['; 11314 11315 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11316 max_scf_name_len + 1); 11317 if (szret < 0) { 11318 if (scf_error() != SCF_ERROR_DELETED) 11319 scfdie(); 11320 11321 goto snap_deleted; 11322 } 11323 11324 (void) strcat(buf, "]svc:/"); 11325 11326 cp = strchr(buf, '\0'); 11327 11328 szret = scf_snaplevel_get_service_name(cur_level, cp, 11329 max_scf_name_len + 1); 11330 if (szret < 0) { 11331 if (scf_error() != SCF_ERROR_DELETED) 11332 scfdie(); 11333 11334 goto snap_deleted; 11335 } 11336 11337 cp = strchr(cp, '\0'); 11338 11339 if (snaplevel_is_instance(cur_level)) { 11340 *cp++ = ':'; 11341 11342 if (scf_snaplevel_get_instance_name(cur_level, cp, 11343 max_scf_name_len + 1) < 0) { 11344 if (scf_error() != SCF_ERROR_DELETED) 11345 scfdie(); 11346 11347 goto snap_deleted; 11348 } 11349 } else { 11350 *cp++ = '['; 11351 *cp++ = ':'; 11352 11353 if (scf_instance_get_name(cur_inst, cp, 11354 max_scf_name_len + 1) < 0) { 11355 if (scf_error() != SCF_ERROR_DELETED) 11356 scfdie(); 11357 11358 goto snap_deleted; 11359 } 11360 11361 (void) strcat(buf, "]"); 11362 } 11363 11364 return; 11365 11366 snap_deleted: 11367 deleted = B_TRUE; 11368 free(buf); 11369 unselect_cursnap(); 11370 } 11371 11372 assert(cur_snap == NULL); 11373 11374 if (cur_inst != NULL) { 11375 assert(cur_svc != NULL); 11376 assert(cur_scope != NULL); 11377 11378 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11379 if (fmrilen >= 0) { 11380 assert(fmrilen < bufsz); 11381 if (deleted) 11382 warn(emsg_deleted); 11383 return; 11384 } 11385 11386 if (scf_error() != SCF_ERROR_DELETED) 11387 scfdie(); 11388 11389 deleted = B_TRUE; 11390 11391 scf_instance_destroy(cur_inst); 11392 cur_inst = NULL; 11393 } 11394 11395 if (cur_svc != NULL) { 11396 assert(cur_scope != NULL); 11397 11398 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11399 if (szret >= 0) { 11400 assert(szret < bufsz); 11401 if (deleted) 11402 warn(emsg_deleted); 11403 return; 11404 } 11405 11406 if (scf_error() != SCF_ERROR_DELETED) 11407 scfdie(); 11408 11409 deleted = B_TRUE; 11410 scf_service_destroy(cur_svc); 11411 cur_svc = NULL; 11412 } 11413 11414 assert(cur_scope != NULL); 11415 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11416 11417 if (fmrilen < 0) 11418 scfdie(); 11419 11420 assert(fmrilen < bufsz); 11421 if (deleted) 11422 warn(emsg_deleted); 11423 } 11424 11425 /* 11426 * Entity listing. Entities and colon namespaces (e.g., :properties and 11427 * :statistics) are listed for the current selection. 11428 */ 11429 void 11430 lscf_list(const char *pattern) 11431 { 11432 scf_iter_t *iter; 11433 char *buf; 11434 int ret; 11435 11436 lscf_prep_hndl(); 11437 11438 if (cur_level != NULL) { 11439 struct snaplevel *elt; 11440 11441 (void) fputs(COLON_NAMESPACES, stdout); 11442 11443 elt = uu_list_next(cur_levels, cur_elt); 11444 if (elt == NULL) 11445 return; 11446 11447 /* 11448 * For now, we know that the next level is an instance. But 11449 * if we ever have multiple scopes, this could be complicated. 11450 */ 11451 buf = safe_malloc(max_scf_name_len + 1); 11452 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11453 max_scf_name_len + 1) >= 0) { 11454 (void) puts(buf); 11455 } else { 11456 if (scf_error() != SCF_ERROR_DELETED) 11457 scfdie(); 11458 } 11459 11460 free(buf); 11461 11462 return; 11463 } 11464 11465 if (cur_inst != NULL) { 11466 (void) fputs(COLON_NAMESPACES, stdout); 11467 return; 11468 } 11469 11470 iter = scf_iter_create(g_hndl); 11471 if (iter == NULL) 11472 scfdie(); 11473 11474 buf = safe_malloc(max_scf_name_len + 1); 11475 11476 if (cur_svc != NULL) { 11477 /* List the instances in this service. */ 11478 scf_instance_t *inst; 11479 11480 inst = scf_instance_create(g_hndl); 11481 if (inst == NULL) 11482 scfdie(); 11483 11484 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11485 safe_printf(COLON_NAMESPACES); 11486 11487 for (;;) { 11488 ret = scf_iter_next_instance(iter, inst); 11489 if (ret == 0) 11490 break; 11491 if (ret != 1) { 11492 if (scf_error() != SCF_ERROR_DELETED) 11493 scfdie(); 11494 11495 break; 11496 } 11497 11498 if (scf_instance_get_name(inst, buf, 11499 max_scf_name_len + 1) >= 0) { 11500 if (pattern == NULL || 11501 fnmatch(pattern, buf, 0) == 0) 11502 (void) puts(buf); 11503 } else { 11504 if (scf_error() != SCF_ERROR_DELETED) 11505 scfdie(); 11506 } 11507 } 11508 } else { 11509 if (scf_error() != SCF_ERROR_DELETED) 11510 scfdie(); 11511 } 11512 11513 scf_instance_destroy(inst); 11514 } else { 11515 /* List the services in this scope. */ 11516 scf_service_t *svc; 11517 11518 assert(cur_scope != NULL); 11519 11520 svc = scf_service_create(g_hndl); 11521 if (svc == NULL) 11522 scfdie(); 11523 11524 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11525 scfdie(); 11526 11527 for (;;) { 11528 ret = scf_iter_next_service(iter, svc); 11529 if (ret == 0) 11530 break; 11531 if (ret != 1) 11532 scfdie(); 11533 11534 if (scf_service_get_name(svc, buf, 11535 max_scf_name_len + 1) >= 0) { 11536 if (pattern == NULL || 11537 fnmatch(pattern, buf, 0) == 0) 11538 safe_printf("%s\n", buf); 11539 } else { 11540 if (scf_error() != SCF_ERROR_DELETED) 11541 scfdie(); 11542 } 11543 } 11544 11545 scf_service_destroy(svc); 11546 } 11547 11548 free(buf); 11549 scf_iter_destroy(iter); 11550 } 11551 11552 /* 11553 * Entity addition. Creates an empty entity in the current selection. 11554 */ 11555 void 11556 lscf_add(const char *name) 11557 { 11558 lscf_prep_hndl(); 11559 11560 if (cur_snap != NULL) { 11561 semerr(emsg_cant_modify_snapshots); 11562 } else if (cur_inst != NULL) { 11563 semerr(gettext("Cannot add entities to an instance.\n")); 11564 } else if (cur_svc != NULL) { 11565 11566 if (scf_service_add_instance(cur_svc, name, NULL) != 11567 SCF_SUCCESS) { 11568 switch (scf_error()) { 11569 case SCF_ERROR_INVALID_ARGUMENT: 11570 semerr(gettext("Invalid name.\n")); 11571 break; 11572 11573 case SCF_ERROR_EXISTS: 11574 semerr(gettext("Instance already exists.\n")); 11575 break; 11576 11577 case SCF_ERROR_PERMISSION_DENIED: 11578 semerr(emsg_permission_denied); 11579 break; 11580 11581 default: 11582 scfdie(); 11583 } 11584 } 11585 } else { 11586 assert(cur_scope != NULL); 11587 11588 if (scf_scope_add_service(cur_scope, name, NULL) != 11589 SCF_SUCCESS) { 11590 switch (scf_error()) { 11591 case SCF_ERROR_INVALID_ARGUMENT: 11592 semerr(gettext("Invalid name.\n")); 11593 break; 11594 11595 case SCF_ERROR_EXISTS: 11596 semerr(gettext("Service already exists.\n")); 11597 break; 11598 11599 case SCF_ERROR_PERMISSION_DENIED: 11600 semerr(emsg_permission_denied); 11601 break; 11602 11603 case SCF_ERROR_BACKEND_READONLY: 11604 semerr(emsg_read_only); 11605 break; 11606 11607 default: 11608 scfdie(); 11609 } 11610 } 11611 } 11612 } 11613 11614 /* return 1 if the entity has no persistent pgs, else return 0 */ 11615 static int 11616 entity_has_no_pgs(void *ent, int isservice) 11617 { 11618 scf_iter_t *iter = NULL; 11619 scf_propertygroup_t *pg = NULL; 11620 uint32_t flags; 11621 int err; 11622 int ret = 1; 11623 11624 if ((iter = scf_iter_create(g_hndl)) == NULL || 11625 (pg = scf_pg_create(g_hndl)) == NULL) 11626 scfdie(); 11627 11628 if (isservice) { 11629 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11630 scfdie(); 11631 } else { 11632 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11633 scfdie(); 11634 } 11635 11636 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11637 if (scf_pg_get_flags(pg, &flags) != 0) 11638 scfdie(); 11639 11640 /* skip nonpersistent pgs */ 11641 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11642 continue; 11643 11644 ret = 0; 11645 break; 11646 } 11647 11648 if (err == -1) 11649 scfdie(); 11650 11651 scf_pg_destroy(pg); 11652 scf_iter_destroy(iter); 11653 11654 return (ret); 11655 } 11656 11657 /* return 1 if the service has no instances, else return 0 */ 11658 static int 11659 svc_has_no_insts(scf_service_t *svc) 11660 { 11661 scf_instance_t *inst; 11662 scf_iter_t *iter; 11663 int r; 11664 int ret = 1; 11665 11666 if ((inst = scf_instance_create(g_hndl)) == NULL || 11667 (iter = scf_iter_create(g_hndl)) == NULL) 11668 scfdie(); 11669 11670 if (scf_iter_service_instances(iter, svc) != 0) 11671 scfdie(); 11672 11673 r = scf_iter_next_instance(iter, inst); 11674 if (r == 1) { 11675 ret = 0; 11676 } else if (r == 0) { 11677 ret = 1; 11678 } else if (r == -1) { 11679 scfdie(); 11680 } else { 11681 bad_error("scf_iter_next_instance", r); 11682 } 11683 11684 scf_iter_destroy(iter); 11685 scf_instance_destroy(inst); 11686 11687 return (ret); 11688 } 11689 11690 /* 11691 * Entity deletion. 11692 */ 11693 11694 /* 11695 * Delete the property group <fmri>/:properties/<name>. Returns 11696 * SCF_ERROR_NONE on success (or if the entity is not found), 11697 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 11698 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 11699 * denied. 11700 */ 11701 static scf_error_t 11702 delete_dependency_pg(const char *fmri, const char *name) 11703 { 11704 void *entity = NULL; 11705 int isservice; 11706 scf_propertygroup_t *pg = NULL; 11707 scf_error_t result; 11708 char *pgty; 11709 scf_service_t *svc = NULL; 11710 scf_instance_t *inst = NULL; 11711 scf_iter_t *iter = NULL; 11712 char *name_buf = NULL; 11713 11714 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 11715 switch (result) { 11716 case SCF_ERROR_NONE: 11717 break; 11718 11719 case SCF_ERROR_NO_MEMORY: 11720 uu_die(gettext("Out of memory.\n")); 11721 /* NOTREACHED */ 11722 11723 case SCF_ERROR_INVALID_ARGUMENT: 11724 case SCF_ERROR_CONSTRAINT_VIOLATED: 11725 return (SCF_ERROR_INVALID_ARGUMENT); 11726 11727 case SCF_ERROR_NOT_FOUND: 11728 result = SCF_ERROR_NONE; 11729 goto out; 11730 11731 default: 11732 bad_error("fmri_to_entity", result); 11733 } 11734 11735 pg = scf_pg_create(g_hndl); 11736 if (pg == NULL) 11737 scfdie(); 11738 11739 if (entity_get_pg(entity, isservice, name, pg) != 0) { 11740 if (scf_error() != SCF_ERROR_NOT_FOUND) 11741 scfdie(); 11742 11743 result = SCF_ERROR_NONE; 11744 goto out; 11745 } 11746 11747 pgty = safe_malloc(max_scf_pg_type_len + 1); 11748 11749 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 11750 scfdie(); 11751 11752 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 11753 result = SCF_ERROR_TYPE_MISMATCH; 11754 free(pgty); 11755 goto out; 11756 } 11757 11758 free(pgty); 11759 11760 if (scf_pg_delete(pg) != 0) { 11761 result = scf_error(); 11762 if (result != SCF_ERROR_PERMISSION_DENIED) 11763 scfdie(); 11764 goto out; 11765 } 11766 11767 /* 11768 * We have to handle the case where we've just deleted the last 11769 * property group of a "dummy" entity (instance or service). 11770 * A "dummy" entity is an entity only present to hold an 11771 * external dependency. 11772 * So, in the case we deleted the last property group then we 11773 * can also delete the entity. If the entity is an instance then 11774 * we must verify if this was the last instance for the service 11775 * and if it is, we can also delete the service if it doesn't 11776 * have any property group either. 11777 */ 11778 11779 result = SCF_ERROR_NONE; 11780 11781 if (isservice) { 11782 svc = (scf_service_t *)entity; 11783 11784 if ((inst = scf_instance_create(g_hndl)) == NULL || 11785 (iter = scf_iter_create(g_hndl)) == NULL) 11786 scfdie(); 11787 11788 name_buf = safe_malloc(max_scf_name_len + 1); 11789 } else { 11790 inst = (scf_instance_t *)entity; 11791 } 11792 11793 /* 11794 * If the entity is an instance and we've just deleted its last 11795 * property group then we should delete it. 11796 */ 11797 if (!isservice && entity_has_no_pgs(entity, isservice)) { 11798 /* find the service before deleting the inst. - needed later */ 11799 if ((svc = scf_service_create(g_hndl)) == NULL) 11800 scfdie(); 11801 11802 if (scf_instance_get_parent(inst, svc) != 0) 11803 scfdie(); 11804 11805 /* delete the instance */ 11806 if (scf_instance_delete(inst) != 0) { 11807 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11808 scfdie(); 11809 11810 result = SCF_ERROR_PERMISSION_DENIED; 11811 goto out; 11812 } 11813 /* no need to refresh the instance */ 11814 inst = NULL; 11815 } 11816 11817 /* 11818 * If the service has no more instances and pgs or we just deleted the 11819 * last instance and the service doesn't have anymore propery groups 11820 * then the service should be deleted. 11821 */ 11822 if (svc != NULL && 11823 svc_has_no_insts(svc) && 11824 entity_has_no_pgs((void *)svc, 1)) { 11825 if (scf_service_delete(svc) == 0) { 11826 if (isservice) { 11827 /* no need to refresh the service */ 11828 svc = NULL; 11829 } 11830 11831 goto out; 11832 } 11833 11834 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11835 scfdie(); 11836 11837 result = SCF_ERROR_PERMISSION_DENIED; 11838 } 11839 11840 /* if the entity has not been deleted, refresh it */ 11841 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 11842 (void) refresh_entity(isservice, entity, fmri, inst, iter, 11843 name_buf); 11844 } 11845 11846 out: 11847 if (isservice && (inst != NULL && iter != NULL)) { 11848 free(name_buf); 11849 scf_iter_destroy(iter); 11850 scf_instance_destroy(inst); 11851 } 11852 11853 if (!isservice && svc != NULL) { 11854 scf_service_destroy(svc); 11855 } 11856 11857 scf_pg_destroy(pg); 11858 if (entity != NULL) 11859 entity_destroy(entity, isservice); 11860 11861 return (result); 11862 } 11863 11864 static int 11865 delete_dependents(scf_propertygroup_t *pg) 11866 { 11867 char *pgty, *name, *fmri; 11868 scf_property_t *prop; 11869 scf_value_t *val; 11870 scf_iter_t *iter; 11871 int r; 11872 scf_error_t err; 11873 11874 /* Verify that the pg has the correct type. */ 11875 pgty = safe_malloc(max_scf_pg_type_len + 1); 11876 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 11877 scfdie(); 11878 11879 if (strcmp(pgty, scf_group_framework) != 0) { 11880 if (g_verbose) { 11881 fmri = safe_malloc(max_scf_fmri_len + 1); 11882 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 11883 scfdie(); 11884 11885 warn(gettext("Property group %s is not of expected " 11886 "type %s.\n"), fmri, scf_group_framework); 11887 11888 free(fmri); 11889 } 11890 11891 free(pgty); 11892 return (-1); 11893 } 11894 11895 free(pgty); 11896 11897 /* map delete_dependency_pg onto the properties. */ 11898 if ((prop = scf_property_create(g_hndl)) == NULL || 11899 (val = scf_value_create(g_hndl)) == NULL || 11900 (iter = scf_iter_create(g_hndl)) == NULL) 11901 scfdie(); 11902 11903 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 11904 scfdie(); 11905 11906 name = safe_malloc(max_scf_name_len + 1); 11907 fmri = safe_malloc(max_scf_fmri_len + 2); 11908 11909 while ((r = scf_iter_next_property(iter, prop)) == 1) { 11910 scf_type_t ty; 11911 11912 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 11913 scfdie(); 11914 11915 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 11916 scfdie(); 11917 11918 if ((ty != SCF_TYPE_ASTRING && 11919 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 11920 prop_get_val(prop, val) != 0) 11921 continue; 11922 11923 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 11924 scfdie(); 11925 11926 err = delete_dependency_pg(fmri, name); 11927 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 11928 if (scf_property_to_fmri(prop, fmri, 11929 max_scf_fmri_len + 2) < 0) 11930 scfdie(); 11931 11932 warn(gettext("Value of %s is not a valid FMRI.\n"), 11933 fmri); 11934 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 11935 warn(gettext("Property group \"%s\" of entity \"%s\" " 11936 "does not have dependency type.\n"), name, fmri); 11937 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 11938 warn(gettext("Could not delete property group \"%s\" " 11939 "of entity \"%s\" (permission denied).\n"), name, 11940 fmri); 11941 } 11942 } 11943 if (r == -1) 11944 scfdie(); 11945 11946 scf_value_destroy(val); 11947 scf_property_destroy(prop); 11948 11949 return (0); 11950 } 11951 11952 /* 11953 * Returns 1 if the instance may be running, and 0 otherwise. 11954 */ 11955 static int 11956 inst_is_running(scf_instance_t *inst) 11957 { 11958 scf_propertygroup_t *pg; 11959 scf_property_t *prop; 11960 scf_value_t *val; 11961 char buf[MAX_SCF_STATE_STRING_SZ]; 11962 int ret = 0; 11963 ssize_t szret; 11964 11965 if ((pg = scf_pg_create(g_hndl)) == NULL || 11966 (prop = scf_property_create(g_hndl)) == NULL || 11967 (val = scf_value_create(g_hndl)) == NULL) 11968 scfdie(); 11969 11970 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 11971 if (scf_error() != SCF_ERROR_NOT_FOUND) 11972 scfdie(); 11973 goto out; 11974 } 11975 11976 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 11977 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 11978 prop_get_val(prop, val) != 0) 11979 goto out; 11980 11981 szret = scf_value_get_astring(val, buf, sizeof (buf)); 11982 assert(szret >= 0); 11983 11984 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 11985 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 11986 11987 out: 11988 scf_value_destroy(val); 11989 scf_property_destroy(prop); 11990 scf_pg_destroy(pg); 11991 return (ret); 11992 } 11993 11994 static uint8_t 11995 pg_is_external_dependency(scf_propertygroup_t *pg) 11996 { 11997 char *type; 11998 scf_value_t *val; 11999 scf_property_t *prop; 12000 uint8_t b = B_FALSE; 12001 12002 type = safe_malloc(max_scf_pg_type_len + 1); 12003 12004 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 12005 scfdie(); 12006 12007 if ((prop = scf_property_create(g_hndl)) == NULL || 12008 (val = scf_value_create(g_hndl)) == NULL) 12009 scfdie(); 12010 12011 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 12012 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 12013 if (scf_property_get_value(prop, val) != 0) 12014 scfdie(); 12015 if (scf_value_get_boolean(val, &b) != 0) 12016 scfdie(); 12017 } 12018 } 12019 12020 free(type); 12021 (void) scf_value_destroy(val); 12022 (void) scf_property_destroy(prop); 12023 12024 return (b); 12025 } 12026 12027 #define DELETE_FAILURE -1 12028 #define DELETE_SUCCESS_NOEXTDEPS 0 12029 #define DELETE_SUCCESS_EXTDEPS 1 12030 12031 /* 12032 * lscf_instance_delete() deletes an instance. Before calling 12033 * scf_instance_delete(), though, we make sure the instance isn't 12034 * running and delete dependencies in other entities which the instance 12035 * declared as "dependents". If there are dependencies which were 12036 * created for other entities, then instead of deleting the instance we 12037 * make it "empty" by deleting all other property groups and all 12038 * snapshots. 12039 * 12040 * lscf_instance_delete() verifies that there is no external dependency pgs 12041 * before suppressing the instance. If there is, then we must not remove them 12042 * now in case the instance is re-created otherwise the dependencies would be 12043 * lost. The external dependency pgs will be removed if the dependencies are 12044 * removed. 12045 * 12046 * Returns: 12047 * DELETE_FAILURE on failure 12048 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12049 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12050 */ 12051 static int 12052 lscf_instance_delete(scf_instance_t *inst, int force) 12053 { 12054 scf_propertygroup_t *pg; 12055 scf_snapshot_t *snap; 12056 scf_iter_t *iter; 12057 int err; 12058 int external = 0; 12059 12060 /* If we're not forcing and the instance is running, refuse. */ 12061 if (!force && inst_is_running(inst)) { 12062 char *fmri; 12063 12064 fmri = safe_malloc(max_scf_fmri_len + 1); 12065 12066 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 12067 scfdie(); 12068 12069 semerr(gettext("Instance %s may be running. " 12070 "Use delete -f if it is not.\n"), fmri); 12071 12072 free(fmri); 12073 return (DELETE_FAILURE); 12074 } 12075 12076 pg = scf_pg_create(g_hndl); 12077 if (pg == NULL) 12078 scfdie(); 12079 12080 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 12081 (void) delete_dependents(pg); 12082 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12083 scfdie(); 12084 12085 scf_pg_destroy(pg); 12086 12087 /* 12088 * If the instance has some external dependencies then we must 12089 * keep them in case the instance is reimported otherwise the 12090 * dependencies would be lost on reimport. 12091 */ 12092 if ((iter = scf_iter_create(g_hndl)) == NULL || 12093 (pg = scf_pg_create(g_hndl)) == NULL) 12094 scfdie(); 12095 12096 if (scf_iter_instance_pgs(iter, inst) < 0) 12097 scfdie(); 12098 12099 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 12100 if (pg_is_external_dependency(pg)) { 12101 external = 1; 12102 continue; 12103 } 12104 12105 if (scf_pg_delete(pg) != 0) { 12106 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12107 scfdie(); 12108 else { 12109 semerr(emsg_permission_denied); 12110 12111 (void) scf_iter_destroy(iter); 12112 (void) scf_pg_destroy(pg); 12113 return (DELETE_FAILURE); 12114 } 12115 } 12116 } 12117 12118 if (err == -1) 12119 scfdie(); 12120 12121 (void) scf_iter_destroy(iter); 12122 (void) scf_pg_destroy(pg); 12123 12124 if (external) { 12125 /* 12126 * All the pgs have been deleted for the instance except 12127 * the ones holding the external dependencies. 12128 * For the job to be complete, we must also delete the 12129 * snapshots associated with the instance. 12130 */ 12131 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 12132 NULL) 12133 scfdie(); 12134 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 12135 scfdie(); 12136 12137 if (scf_iter_instance_snapshots(iter, inst) == -1) 12138 scfdie(); 12139 12140 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 12141 if (_scf_snapshot_delete(snap) != 0) { 12142 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12143 scfdie(); 12144 12145 semerr(emsg_permission_denied); 12146 12147 (void) scf_iter_destroy(iter); 12148 (void) scf_snapshot_destroy(snap); 12149 return (DELETE_FAILURE); 12150 } 12151 } 12152 12153 if (err == -1) 12154 scfdie(); 12155 12156 (void) scf_iter_destroy(iter); 12157 (void) scf_snapshot_destroy(snap); 12158 return (DELETE_SUCCESS_EXTDEPS); 12159 } 12160 12161 if (scf_instance_delete(inst) != 0) { 12162 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12163 scfdie(); 12164 12165 semerr(emsg_permission_denied); 12166 12167 return (DELETE_FAILURE); 12168 } 12169 12170 return (DELETE_SUCCESS_NOEXTDEPS); 12171 } 12172 12173 /* 12174 * lscf_service_delete() deletes a service. Before calling 12175 * scf_service_delete(), though, we call lscf_instance_delete() for 12176 * each of the instances and delete dependencies in other entities 12177 * which were created as "dependents" of this service. If there are 12178 * dependencies which were created for other entities, then we delete 12179 * all other property groups in the service and leave it as "empty". 12180 * 12181 * lscf_service_delete() verifies that there is no external dependency 12182 * pgs at the instance & service level before suppressing the service. 12183 * If there is, then we must not remove them now in case the service 12184 * is re-imported otherwise the dependencies would be lost. The external 12185 * dependency pgs will be removed if the dependencies are removed. 12186 * 12187 * Returns: 12188 * DELETE_FAILURE on failure 12189 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12190 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12191 */ 12192 static int 12193 lscf_service_delete(scf_service_t *svc, int force) 12194 { 12195 int r; 12196 scf_instance_t *inst; 12197 scf_propertygroup_t *pg; 12198 scf_iter_t *iter; 12199 int ret; 12200 int external = 0; 12201 12202 if ((inst = scf_instance_create(g_hndl)) == NULL || 12203 (pg = scf_pg_create(g_hndl)) == NULL || 12204 (iter = scf_iter_create(g_hndl)) == NULL) 12205 scfdie(); 12206 12207 if (scf_iter_service_instances(iter, svc) != 0) 12208 scfdie(); 12209 12210 for (r = scf_iter_next_instance(iter, inst); 12211 r == 1; 12212 r = scf_iter_next_instance(iter, inst)) { 12213 12214 ret = lscf_instance_delete(inst, force); 12215 if (ret == DELETE_FAILURE) { 12216 scf_iter_destroy(iter); 12217 scf_pg_destroy(pg); 12218 scf_instance_destroy(inst); 12219 return (DELETE_FAILURE); 12220 } 12221 12222 /* 12223 * Record the fact that there is some external dependencies 12224 * at the instance level. 12225 */ 12226 if (ret == DELETE_SUCCESS_EXTDEPS) 12227 external |= 1; 12228 } 12229 12230 if (r != 0) 12231 scfdie(); 12232 12233 /* Delete dependency property groups in dependent services. */ 12234 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12235 (void) delete_dependents(pg); 12236 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12237 scfdie(); 12238 12239 scf_iter_destroy(iter); 12240 scf_pg_destroy(pg); 12241 scf_instance_destroy(inst); 12242 12243 /* 12244 * If the service has some external dependencies then we don't 12245 * want to remove them in case the service is re-imported. 12246 */ 12247 if ((pg = scf_pg_create(g_hndl)) == NULL || 12248 (iter = scf_iter_create(g_hndl)) == NULL) 12249 scfdie(); 12250 12251 if (scf_iter_service_pgs(iter, svc) < 0) 12252 scfdie(); 12253 12254 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12255 if (pg_is_external_dependency(pg)) { 12256 external |= 2; 12257 continue; 12258 } 12259 12260 if (scf_pg_delete(pg) != 0) { 12261 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12262 scfdie(); 12263 else { 12264 semerr(emsg_permission_denied); 12265 12266 (void) scf_iter_destroy(iter); 12267 (void) scf_pg_destroy(pg); 12268 return (DELETE_FAILURE); 12269 } 12270 } 12271 } 12272 12273 if (r == -1) 12274 scfdie(); 12275 12276 (void) scf_iter_destroy(iter); 12277 (void) scf_pg_destroy(pg); 12278 12279 if (external != 0) 12280 return (DELETE_SUCCESS_EXTDEPS); 12281 12282 if (scf_service_delete(svc) == 0) 12283 return (DELETE_SUCCESS_NOEXTDEPS); 12284 12285 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12286 scfdie(); 12287 12288 semerr(emsg_permission_denied); 12289 return (DELETE_FAILURE); 12290 } 12291 12292 static int 12293 delete_callback(void *data, scf_walkinfo_t *wip) 12294 { 12295 int force = (int)data; 12296 12297 if (wip->inst != NULL) 12298 (void) lscf_instance_delete(wip->inst, force); 12299 else 12300 (void) lscf_service_delete(wip->svc, force); 12301 12302 return (0); 12303 } 12304 12305 void 12306 lscf_delete(const char *fmri, int force) 12307 { 12308 scf_service_t *svc; 12309 scf_instance_t *inst; 12310 int ret; 12311 12312 lscf_prep_hndl(); 12313 12314 if (cur_snap != NULL) { 12315 if (!snaplevel_is_instance(cur_level)) { 12316 char *buf; 12317 12318 buf = safe_malloc(max_scf_name_len + 1); 12319 if (scf_instance_get_name(cur_inst, buf, 12320 max_scf_name_len + 1) >= 0) { 12321 if (strcmp(buf, fmri) == 0) { 12322 semerr(emsg_cant_modify_snapshots); 12323 free(buf); 12324 return; 12325 } 12326 } else if (scf_error() != SCF_ERROR_DELETED) { 12327 scfdie(); 12328 } 12329 free(buf); 12330 } 12331 } else if (cur_inst != NULL) { 12332 /* EMPTY */; 12333 } else if (cur_svc != NULL) { 12334 inst = scf_instance_create(g_hndl); 12335 if (inst == NULL) 12336 scfdie(); 12337 12338 if (scf_service_get_instance(cur_svc, fmri, inst) == 12339 SCF_SUCCESS) { 12340 (void) lscf_instance_delete(inst, force); 12341 scf_instance_destroy(inst); 12342 return; 12343 } 12344 12345 if (scf_error() != SCF_ERROR_NOT_FOUND && 12346 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12347 scfdie(); 12348 12349 scf_instance_destroy(inst); 12350 } else { 12351 assert(cur_scope != NULL); 12352 12353 svc = scf_service_create(g_hndl); 12354 if (svc == NULL) 12355 scfdie(); 12356 12357 if (scf_scope_get_service(cur_scope, fmri, svc) == 12358 SCF_SUCCESS) { 12359 (void) lscf_service_delete(svc, force); 12360 scf_service_destroy(svc); 12361 return; 12362 } 12363 12364 if (scf_error() != SCF_ERROR_NOT_FOUND && 12365 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12366 scfdie(); 12367 12368 scf_service_destroy(svc); 12369 } 12370 12371 /* 12372 * Match FMRI to entity. 12373 */ 12374 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12375 delete_callback, (void *)force, NULL, semerr)) != 0) { 12376 semerr(gettext("Failed to walk instances: %s\n"), 12377 scf_strerror(ret)); 12378 } 12379 } 12380 12381 12382 12383 /* 12384 * :properties commands. These all end with "pg" or "prop" and generally 12385 * operate on the currently selected entity. 12386 */ 12387 12388 /* 12389 * Property listing. List the property groups, properties, their types and 12390 * their values for the currently selected entity. 12391 */ 12392 static void 12393 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12394 { 12395 char *buf; 12396 uint32_t flags; 12397 12398 buf = safe_malloc(max_scf_pg_type_len + 1); 12399 12400 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12401 scfdie(); 12402 12403 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12404 scfdie(); 12405 12406 safe_printf("%-*s %s", namewidth, name, buf); 12407 12408 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12409 safe_printf("\tNONPERSISTENT"); 12410 12411 safe_printf("\n"); 12412 12413 free(buf); 12414 } 12415 12416 static boolean_t 12417 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12418 { 12419 if (scf_property_get_value(prop, val) == 0) { 12420 return (B_FALSE); 12421 } else { 12422 switch (scf_error()) { 12423 case SCF_ERROR_NOT_FOUND: 12424 return (B_FALSE); 12425 case SCF_ERROR_PERMISSION_DENIED: 12426 case SCF_ERROR_CONSTRAINT_VIOLATED: 12427 return (B_TRUE); 12428 default: 12429 scfdie(); 12430 /*NOTREACHED*/ 12431 } 12432 } 12433 } 12434 12435 static void 12436 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12437 { 12438 scf_iter_t *iter; 12439 scf_value_t *val; 12440 const char *type; 12441 int multiple_strings = 0; 12442 int ret; 12443 12444 if ((iter = scf_iter_create(g_hndl)) == NULL || 12445 (val = scf_value_create(g_hndl)) == NULL) 12446 scfdie(); 12447 12448 type = prop_to_typestr(prop); 12449 assert(type != NULL); 12450 12451 safe_printf("%-*s %-7s ", len, name, type); 12452 12453 if (prop_has_multiple_values(prop, val) && 12454 (scf_value_type(val) == SCF_TYPE_ASTRING || 12455 scf_value_type(val) == SCF_TYPE_USTRING)) 12456 multiple_strings = 1; 12457 12458 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12459 scfdie(); 12460 12461 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12462 char *buf; 12463 ssize_t vlen, szret; 12464 12465 vlen = scf_value_get_as_string(val, NULL, 0); 12466 if (vlen < 0) 12467 scfdie(); 12468 12469 buf = safe_malloc(vlen + 1); 12470 12471 szret = scf_value_get_as_string(val, buf, vlen + 1); 12472 if (szret < 0) 12473 scfdie(); 12474 assert(szret <= vlen); 12475 12476 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12477 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12478 safe_printf(" \""); 12479 (void) quote_and_print(buf, stdout, 0); 12480 (void) putchar('"'); 12481 if (ferror(stdout)) { 12482 (void) putchar('\n'); 12483 uu_die(gettext("Error writing to stdout.\n")); 12484 } 12485 } else { 12486 safe_printf(" %s", buf); 12487 } 12488 12489 free(buf); 12490 } 12491 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12492 scfdie(); 12493 12494 if (putchar('\n') != '\n') 12495 uu_die(gettext("Could not output newline")); 12496 } 12497 12498 /* 12499 * Outputs template property group info for the describe subcommand. 12500 * If 'templates' == 2, verbose output is printed in the format expected 12501 * for describe -v, which includes all templates fields. If pg is 12502 * not NULL, we're describing the template data, not an existing property 12503 * group, and formatting should be appropriate for describe -t. 12504 */ 12505 static void 12506 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12507 { 12508 char *buf; 12509 uint8_t required; 12510 scf_property_t *stability_prop; 12511 scf_value_t *stability_val; 12512 12513 if (templates == 0) 12514 return; 12515 12516 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12517 (stability_val = scf_value_create(g_hndl)) == NULL) 12518 scfdie(); 12519 12520 if (templates == 2 && pg != NULL) { 12521 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12522 stability_prop) == 0) { 12523 if (prop_check_type(stability_prop, 12524 SCF_TYPE_ASTRING) == 0 && 12525 prop_get_val(stability_prop, stability_val) == 0) { 12526 char *stability; 12527 12528 stability = safe_malloc(max_scf_value_len + 1); 12529 12530 if (scf_value_get_astring(stability_val, 12531 stability, max_scf_value_len + 1) == -1 && 12532 scf_error() != SCF_ERROR_NOT_FOUND) 12533 scfdie(); 12534 12535 safe_printf("%s%s: %s\n", TMPL_INDENT, 12536 gettext("stability"), stability); 12537 12538 free(stability); 12539 } 12540 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12541 scfdie(); 12542 } 12543 12544 scf_property_destroy(stability_prop); 12545 scf_value_destroy(stability_val); 12546 12547 if (pgt == NULL) 12548 return; 12549 12550 if (pg == NULL || templates == 2) { 12551 /* print type info only if scf_tmpl_pg_name succeeds */ 12552 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12553 if (pg != NULL) 12554 safe_printf("%s", TMPL_INDENT); 12555 safe_printf("%s: ", gettext("name")); 12556 safe_printf("%s\n", buf); 12557 free(buf); 12558 } 12559 12560 /* print type info only if scf_tmpl_pg_type succeeds */ 12561 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12562 if (pg != NULL) 12563 safe_printf("%s", TMPL_INDENT); 12564 safe_printf("%s: ", gettext("type")); 12565 safe_printf("%s\n", buf); 12566 free(buf); 12567 } 12568 } 12569 12570 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12571 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12572 required ? "true" : "false"); 12573 12574 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12575 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12576 buf); 12577 free(buf); 12578 } 12579 12580 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12581 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12582 buf); 12583 free(buf); 12584 } 12585 12586 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12587 if (templates == 2) 12588 safe_printf("%s%s: %s\n", TMPL_INDENT, 12589 gettext("description"), buf); 12590 else 12591 safe_printf("%s%s\n", TMPL_INDENT, buf); 12592 free(buf); 12593 } 12594 12595 } 12596 12597 /* 12598 * With as_value set to true, indent as appropriate for the value level. 12599 * If false, indent to appropriate level for inclusion in constraint 12600 * or choice printout. 12601 */ 12602 static void 12603 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12604 int as_value) 12605 { 12606 char *buf; 12607 12608 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12609 if (as_value == 0) 12610 safe_printf("%s", TMPL_CHOICE_INDENT); 12611 else 12612 safe_printf("%s", TMPL_INDENT); 12613 safe_printf("%s: %s\n", gettext("value common name"), buf); 12614 free(buf); 12615 } 12616 12617 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12618 if (as_value == 0) 12619 safe_printf("%s", TMPL_CHOICE_INDENT); 12620 else 12621 safe_printf("%s", TMPL_INDENT); 12622 safe_printf("%s: %s\n", gettext("value description"), buf); 12623 free(buf); 12624 } 12625 } 12626 12627 static void 12628 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12629 { 12630 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12631 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12632 safe_printf("%s\n", val_buf); 12633 12634 print_template_value_details(prt, val_buf, 1); 12635 } 12636 12637 static void 12638 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12639 { 12640 int i, printed = 0; 12641 scf_values_t values; 12642 scf_count_ranges_t c_ranges; 12643 scf_int_ranges_t i_ranges; 12644 12645 printed = 0; 12646 i = 0; 12647 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12648 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12649 gettext("value constraints")); 12650 printed++; 12651 for (i = 0; i < values.value_count; ++i) { 12652 safe_printf("%s%s: %s\n", TMPL_INDENT, 12653 gettext("value name"), values.values_as_strings[i]); 12654 if (verbose == 1) 12655 print_template_value_details(prt, 12656 values.values_as_strings[i], 0); 12657 } 12658 12659 scf_values_destroy(&values); 12660 } 12661 12662 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12663 if (printed++ == 0) 12664 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12665 gettext("value constraints")); 12666 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12667 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12668 gettext("range"), c_ranges.scr_min[i], 12669 c_ranges.scr_max[i]); 12670 } 12671 scf_count_ranges_destroy(&c_ranges); 12672 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12673 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 12674 if (printed++ == 0) 12675 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12676 gettext("value constraints")); 12677 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12678 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12679 gettext("range"), i_ranges.sir_min[i], 12680 i_ranges.sir_max[i]); 12681 } 12682 scf_int_ranges_destroy(&i_ranges); 12683 } 12684 } 12685 12686 static void 12687 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 12688 { 12689 int i = 0, printed = 0; 12690 scf_values_t values; 12691 scf_count_ranges_t c_ranges; 12692 scf_int_ranges_t i_ranges; 12693 12694 printed = 0; 12695 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 12696 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12697 gettext("value constraints")); 12698 printed++; 12699 for (i = 0; i < values.value_count; i++) { 12700 safe_printf("%s%s: %s\n", TMPL_INDENT, 12701 gettext("value name"), values.values_as_strings[i]); 12702 if (verbose == 1) 12703 print_template_value_details(prt, 12704 values.values_as_strings[i], 0); 12705 } 12706 12707 scf_values_destroy(&values); 12708 } 12709 12710 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 12711 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12712 if (printed++ == 0) 12713 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12714 gettext("value choices")); 12715 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12716 gettext("range"), c_ranges.scr_min[i], 12717 c_ranges.scr_max[i]); 12718 } 12719 scf_count_ranges_destroy(&c_ranges); 12720 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12721 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 12722 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12723 if (printed++ == 0) 12724 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12725 gettext("value choices")); 12726 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12727 gettext("range"), i_ranges.sir_min[i], 12728 i_ranges.sir_max[i]); 12729 } 12730 scf_int_ranges_destroy(&i_ranges); 12731 } 12732 } 12733 12734 static void 12735 list_values_by_template(scf_prop_tmpl_t *prt) 12736 { 12737 print_template_constraints(prt, 1); 12738 print_template_choices(prt, 1); 12739 } 12740 12741 static void 12742 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 12743 { 12744 char *val_buf; 12745 scf_iter_t *iter; 12746 scf_value_t *val; 12747 int ret; 12748 12749 if ((iter = scf_iter_create(g_hndl)) == NULL || 12750 (val = scf_value_create(g_hndl)) == NULL) 12751 scfdie(); 12752 12753 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12754 scfdie(); 12755 12756 val_buf = safe_malloc(max_scf_value_len + 1); 12757 12758 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12759 if (scf_value_get_as_string(val, val_buf, 12760 max_scf_value_len + 1) < 0) 12761 scfdie(); 12762 12763 print_template_value(prt, val_buf); 12764 } 12765 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12766 scfdie(); 12767 free(val_buf); 12768 12769 print_template_constraints(prt, 0); 12770 print_template_choices(prt, 0); 12771 12772 } 12773 12774 /* 12775 * Outputs property info for the describe subcommand 12776 * Verbose output if templates == 2, -v option of svccfg describe 12777 * Displays template data if prop is not NULL, -t option of svccfg describe 12778 */ 12779 static void 12780 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 12781 { 12782 char *buf; 12783 uint8_t u_buf; 12784 int i; 12785 uint64_t min, max; 12786 scf_values_t values; 12787 12788 if (prt == NULL || templates == 0) 12789 return; 12790 12791 if (prop == NULL) { 12792 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 12793 if (scf_tmpl_prop_name(prt, &buf) > 0) { 12794 safe_printf("%s\n", buf); 12795 free(buf); 12796 } else 12797 safe_printf("(%s)\n", gettext("any")); 12798 } 12799 12800 if (prop == NULL || templates == 2) { 12801 if (prop != NULL) 12802 safe_printf("%s", TMPL_INDENT); 12803 else 12804 safe_printf("%s", TMPL_VALUE_INDENT); 12805 safe_printf("%s: ", gettext("type")); 12806 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 12807 safe_printf("%s\n", buf); 12808 free(buf); 12809 } else 12810 safe_printf("(%s)\n", gettext("any")); 12811 } 12812 12813 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 12814 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12815 u_buf ? "true" : "false"); 12816 12817 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 12818 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12819 buf); 12820 free(buf); 12821 } 12822 12823 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 12824 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 12825 buf); 12826 free(buf); 12827 } 12828 12829 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 12830 safe_printf("%s%s\n", TMPL_INDENT, buf); 12831 free(buf); 12832 } 12833 12834 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 12835 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 12836 scf_tmpl_visibility_to_string(u_buf)); 12837 12838 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 12839 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 12840 gettext("minimum number of values"), min); 12841 if (max == ULLONG_MAX) { 12842 safe_printf("%s%s: %s\n", TMPL_INDENT, 12843 gettext("maximum number of values"), 12844 gettext("unlimited")); 12845 } else { 12846 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 12847 gettext("maximum number of values"), max); 12848 } 12849 } 12850 12851 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 12852 for (i = 0; i < values.value_count; i++) { 12853 if (i == 0) { 12854 safe_printf("%s%s:", TMPL_INDENT, 12855 gettext("internal separators")); 12856 } 12857 safe_printf(" \"%s\"", values.values_as_strings[i]); 12858 } 12859 safe_printf("\n"); 12860 } 12861 12862 if (templates != 2) 12863 return; 12864 12865 if (prop != NULL) 12866 list_values_tmpl(prt, prop); 12867 else 12868 list_values_by_template(prt); 12869 } 12870 12871 static char * 12872 read_astring(scf_propertygroup_t *pg, const char *prop_name) 12873 { 12874 char *rv; 12875 12876 rv = _scf_read_single_astring_from_pg(pg, prop_name); 12877 if (rv == NULL) { 12878 switch (scf_error()) { 12879 case SCF_ERROR_NOT_FOUND: 12880 break; 12881 default: 12882 scfdie(); 12883 } 12884 } 12885 return (rv); 12886 } 12887 12888 static void 12889 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 12890 { 12891 size_t doc_len; 12892 size_t man_len; 12893 char *pg_name; 12894 char *text = NULL; 12895 int rv; 12896 12897 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 12898 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 12899 pg_name = safe_malloc(max_scf_name_len + 1); 12900 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 12901 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 12902 scfdie(); 12903 } 12904 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 12905 /* Display doc_link and and uri */ 12906 safe_printf("%s%s:\n", TMPL_INDENT, 12907 gettext("doc_link")); 12908 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 12909 if (text != NULL) { 12910 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12911 TMPL_INDENT, gettext("name"), text); 12912 uu_free(text); 12913 } 12914 text = read_astring(pg, SCF_PROPERTY_TM_URI); 12915 if (text != NULL) { 12916 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 12917 gettext("uri"), text); 12918 uu_free(text); 12919 } 12920 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 12921 man_len) == 0) { 12922 /* Display manpage title, section and path */ 12923 safe_printf("%s%s:\n", TMPL_INDENT, 12924 gettext("manpage")); 12925 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 12926 if (text != NULL) { 12927 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12928 TMPL_INDENT, gettext("title"), text); 12929 uu_free(text); 12930 } 12931 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 12932 if (text != NULL) { 12933 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12934 TMPL_INDENT, gettext("section"), text); 12935 uu_free(text); 12936 } 12937 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 12938 if (text != NULL) { 12939 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12940 TMPL_INDENT, gettext("manpath"), text); 12941 uu_free(text); 12942 } 12943 } 12944 } 12945 if (rv == -1) 12946 scfdie(); 12947 12948 done: 12949 free(pg_name); 12950 } 12951 12952 static void 12953 list_entity_tmpl(int templates) 12954 { 12955 char *common_name = NULL; 12956 char *description = NULL; 12957 char *locale = NULL; 12958 scf_iter_t *iter; 12959 scf_propertygroup_t *pg; 12960 scf_property_t *prop; 12961 int r; 12962 scf_value_t *val; 12963 12964 if ((pg = scf_pg_create(g_hndl)) == NULL || 12965 (prop = scf_property_create(g_hndl)) == NULL || 12966 (val = scf_value_create(g_hndl)) == NULL || 12967 (iter = scf_iter_create(g_hndl)) == NULL) 12968 scfdie(); 12969 12970 locale = setlocale(LC_MESSAGES, NULL); 12971 12972 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 12973 common_name = safe_malloc(max_scf_value_len + 1); 12974 12975 /* Try both the current locale and the "C" locale. */ 12976 if (scf_pg_get_property(pg, locale, prop) == 0 || 12977 (scf_error() == SCF_ERROR_NOT_FOUND && 12978 scf_pg_get_property(pg, "C", prop) == 0)) { 12979 if (prop_get_val(prop, val) == 0 && 12980 scf_value_get_ustring(val, common_name, 12981 max_scf_value_len + 1) != -1) { 12982 safe_printf("%s%s: %s\n", TMPL_INDENT, 12983 gettext("common name"), common_name); 12984 } 12985 } 12986 } 12987 12988 /* 12989 * Do description, manpages, and doc links if templates == 2. 12990 */ 12991 if (templates == 2) { 12992 /* Get the description. */ 12993 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 12994 description = safe_malloc(max_scf_value_len + 1); 12995 12996 /* Try both the current locale and the "C" locale. */ 12997 if (scf_pg_get_property(pg, locale, prop) == 0 || 12998 (scf_error() == SCF_ERROR_NOT_FOUND && 12999 scf_pg_get_property(pg, "C", prop) == 0)) { 13000 if (prop_get_val(prop, val) == 0 && 13001 scf_value_get_ustring(val, description, 13002 max_scf_value_len + 1) != -1) { 13003 safe_printf("%s%s: %s\n", TMPL_INDENT, 13004 gettext("description"), 13005 description); 13006 } 13007 } 13008 } 13009 13010 /* Process doc_link & manpage elements. */ 13011 if (cur_level != NULL) { 13012 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 13013 SCF_GROUP_TEMPLATE); 13014 } else if (cur_inst != NULL) { 13015 r = scf_iter_instance_pgs_typed(iter, cur_inst, 13016 SCF_GROUP_TEMPLATE); 13017 } else { 13018 r = scf_iter_service_pgs_typed(iter, cur_svc, 13019 SCF_GROUP_TEMPLATE); 13020 } 13021 if (r == 0) { 13022 display_documentation(iter, pg); 13023 } 13024 } 13025 13026 free(common_name); 13027 free(description); 13028 scf_pg_destroy(pg); 13029 scf_property_destroy(prop); 13030 scf_value_destroy(val); 13031 scf_iter_destroy(iter); 13032 } 13033 13034 static void 13035 listtmpl(const char *pattern, int templates) 13036 { 13037 scf_pg_tmpl_t *pgt; 13038 scf_prop_tmpl_t *prt; 13039 char *snapbuf = NULL; 13040 char *fmribuf; 13041 char *pg_name = NULL, *prop_name = NULL; 13042 ssize_t prop_name_size; 13043 char *qual_prop_name; 13044 char *search_name; 13045 int listed = 0; 13046 13047 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13048 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 13049 scfdie(); 13050 13051 fmribuf = safe_malloc(max_scf_name_len + 1); 13052 qual_prop_name = safe_malloc(max_scf_name_len + 1); 13053 13054 if (cur_snap != NULL) { 13055 snapbuf = safe_malloc(max_scf_name_len + 1); 13056 if (scf_snapshot_get_name(cur_snap, snapbuf, 13057 max_scf_name_len + 1) < 0) 13058 scfdie(); 13059 } 13060 13061 if (cur_inst != NULL) { 13062 if (scf_instance_to_fmri(cur_inst, fmribuf, 13063 max_scf_name_len + 1) < 0) 13064 scfdie(); 13065 } else if (cur_svc != NULL) { 13066 if (scf_service_to_fmri(cur_svc, fmribuf, 13067 max_scf_name_len + 1) < 0) 13068 scfdie(); 13069 } else 13070 abort(); 13071 13072 /* If pattern is specified, we want to list only those items. */ 13073 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) { 13074 listed = 0; 13075 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 13076 fnmatch(pattern, pg_name, 0) == 0)) { 13077 list_pg_tmpl(pgt, NULL, templates); 13078 listed++; 13079 } 13080 13081 scf_tmpl_prop_reset(prt); 13082 13083 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) { 13084 search_name = NULL; 13085 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 13086 if ((prop_name_size > 0) && (pg_name != NULL)) { 13087 if (snprintf(qual_prop_name, 13088 max_scf_name_len + 1, "%s/%s", 13089 pg_name, prop_name) >= 13090 max_scf_name_len + 1) { 13091 prop_name_size = -1; 13092 } else { 13093 search_name = qual_prop_name; 13094 } 13095 } 13096 if (listed > 0 || pattern == NULL || 13097 (prop_name_size > 0 && 13098 fnmatch(pattern, search_name, 13099 FNM_PATHNAME) == 0)) 13100 list_prop_tmpl(prt, NULL, templates); 13101 if (prop_name != NULL) { 13102 free(prop_name); 13103 prop_name = NULL; 13104 } 13105 } 13106 if (pg_name != NULL) { 13107 free(pg_name); 13108 pg_name = NULL; 13109 } 13110 } 13111 13112 scf_tmpl_prop_destroy(prt); 13113 scf_tmpl_pg_destroy(pgt); 13114 free(snapbuf); 13115 free(fmribuf); 13116 free(qual_prop_name); 13117 } 13118 13119 static void 13120 listprop(const char *pattern, int only_pgs, int templates) 13121 { 13122 scf_propertygroup_t *pg; 13123 scf_property_t *prop; 13124 scf_iter_t *iter, *piter; 13125 char *pgnbuf, *prnbuf, *ppnbuf; 13126 scf_pg_tmpl_t *pgt, *pgtp; 13127 scf_prop_tmpl_t *prt; 13128 13129 void **objects; 13130 char **names; 13131 void **tmpls; 13132 int allocd, i; 13133 13134 int ret; 13135 ssize_t pgnlen, prnlen, szret; 13136 size_t max_len = 0; 13137 13138 if (cur_svc == NULL && cur_inst == NULL) { 13139 semerr(emsg_entity_not_selected); 13140 return; 13141 } 13142 13143 if ((pg = scf_pg_create(g_hndl)) == NULL || 13144 (prop = scf_property_create(g_hndl)) == NULL || 13145 (iter = scf_iter_create(g_hndl)) == NULL || 13146 (piter = scf_iter_create(g_hndl)) == NULL || 13147 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13148 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 13149 scfdie(); 13150 13151 prnbuf = safe_malloc(max_scf_name_len + 1); 13152 13153 if (cur_level != NULL) 13154 ret = scf_iter_snaplevel_pgs(iter, cur_level); 13155 else if (cur_inst != NULL) 13156 ret = scf_iter_instance_pgs(iter, cur_inst); 13157 else 13158 ret = scf_iter_service_pgs(iter, cur_svc); 13159 if (ret != 0) { 13160 return; 13161 } 13162 13163 /* 13164 * We want to only list items which match pattern, and we want the 13165 * second column to line up, so during the first pass we'll save 13166 * matching items, their names, and their templates in objects, 13167 * names, and tmpls, computing the maximum name length as we go, 13168 * and then we'll print them out. 13169 * 13170 * Note: We always keep an extra slot available so the array can be 13171 * NULL-terminated. 13172 */ 13173 i = 0; 13174 allocd = 1; 13175 objects = safe_malloc(sizeof (*objects)); 13176 names = safe_malloc(sizeof (*names)); 13177 tmpls = safe_malloc(sizeof (*tmpls)); 13178 13179 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13180 int new_pg = 0; 13181 int print_props = 0; 13182 pgtp = NULL; 13183 13184 pgnlen = scf_pg_get_name(pg, NULL, 0); 13185 if (pgnlen < 0) 13186 scfdie(); 13187 13188 pgnbuf = safe_malloc(pgnlen + 1); 13189 13190 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 13191 if (szret < 0) 13192 scfdie(); 13193 assert(szret <= pgnlen); 13194 13195 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) { 13196 if (scf_error() != SCF_ERROR_NOT_FOUND) 13197 scfdie(); 13198 pgtp = NULL; 13199 } else { 13200 pgtp = pgt; 13201 } 13202 13203 if (pattern == NULL || 13204 fnmatch(pattern, pgnbuf, 0) == 0) { 13205 if (i+1 >= allocd) { 13206 allocd *= 2; 13207 objects = realloc(objects, 13208 sizeof (*objects) * allocd); 13209 names = 13210 realloc(names, sizeof (*names) * allocd); 13211 tmpls = realloc(tmpls, 13212 sizeof (*tmpls) * allocd); 13213 if (objects == NULL || names == NULL || 13214 tmpls == NULL) 13215 uu_die(gettext("Out of memory")); 13216 } 13217 objects[i] = pg; 13218 names[i] = pgnbuf; 13219 13220 if (pgtp == NULL) 13221 tmpls[i] = NULL; 13222 else 13223 tmpls[i] = pgt; 13224 13225 ++i; 13226 13227 if (pgnlen > max_len) 13228 max_len = pgnlen; 13229 13230 new_pg = 1; 13231 print_props = 1; 13232 } 13233 13234 if (only_pgs) { 13235 if (new_pg) { 13236 pg = scf_pg_create(g_hndl); 13237 if (pg == NULL) 13238 scfdie(); 13239 pgt = scf_tmpl_pg_create(g_hndl); 13240 if (pgt == NULL) 13241 scfdie(); 13242 } else 13243 free(pgnbuf); 13244 13245 continue; 13246 } 13247 13248 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13249 scfdie(); 13250 13251 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13252 prnlen = scf_property_get_name(prop, prnbuf, 13253 max_scf_name_len + 1); 13254 if (prnlen < 0) 13255 scfdie(); 13256 13257 /* Will prepend the property group name and a slash. */ 13258 prnlen += pgnlen + 1; 13259 13260 ppnbuf = safe_malloc(prnlen + 1); 13261 13262 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13263 prnbuf) < 0) 13264 uu_die("snprintf"); 13265 13266 if (pattern == NULL || print_props == 1 || 13267 fnmatch(pattern, ppnbuf, 0) == 0) { 13268 if (i+1 >= allocd) { 13269 allocd *= 2; 13270 objects = realloc(objects, 13271 sizeof (*objects) * allocd); 13272 names = realloc(names, 13273 sizeof (*names) * allocd); 13274 tmpls = realloc(tmpls, 13275 sizeof (*tmpls) * allocd); 13276 if (objects == NULL || names == NULL || 13277 tmpls == NULL) 13278 uu_die(gettext( 13279 "Out of memory")); 13280 } 13281 13282 objects[i] = prop; 13283 names[i] = ppnbuf; 13284 13285 if (pgtp != NULL) { 13286 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13287 prt, 0) < 0) { 13288 if (scf_error() != 13289 SCF_ERROR_NOT_FOUND) 13290 scfdie(); 13291 tmpls[i] = NULL; 13292 } else { 13293 tmpls[i] = prt; 13294 } 13295 } else { 13296 tmpls[i] = NULL; 13297 } 13298 13299 ++i; 13300 13301 if (prnlen > max_len) 13302 max_len = prnlen; 13303 13304 prop = scf_property_create(g_hndl); 13305 prt = scf_tmpl_prop_create(g_hndl); 13306 } else { 13307 free(ppnbuf); 13308 } 13309 } 13310 13311 if (new_pg) { 13312 pg = scf_pg_create(g_hndl); 13313 if (pg == NULL) 13314 scfdie(); 13315 pgt = scf_tmpl_pg_create(g_hndl); 13316 if (pgt == NULL) 13317 scfdie(); 13318 } else 13319 free(pgnbuf); 13320 } 13321 if (ret != 0) 13322 scfdie(); 13323 13324 objects[i] = NULL; 13325 13326 scf_pg_destroy(pg); 13327 scf_tmpl_pg_destroy(pgt); 13328 scf_property_destroy(prop); 13329 scf_tmpl_prop_destroy(prt); 13330 13331 for (i = 0; objects[i] != NULL; ++i) { 13332 if (strchr(names[i], '/') == NULL) { 13333 /* property group */ 13334 pg = (scf_propertygroup_t *)objects[i]; 13335 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13336 list_pg_info(pg, names[i], max_len); 13337 list_pg_tmpl(pgt, pg, templates); 13338 free(names[i]); 13339 scf_pg_destroy(pg); 13340 if (pgt != NULL) 13341 scf_tmpl_pg_destroy(pgt); 13342 } else { 13343 /* property */ 13344 prop = (scf_property_t *)objects[i]; 13345 prt = (scf_prop_tmpl_t *)tmpls[i]; 13346 list_prop_info(prop, names[i], max_len); 13347 list_prop_tmpl(prt, prop, templates); 13348 free(names[i]); 13349 scf_property_destroy(prop); 13350 if (prt != NULL) 13351 scf_tmpl_prop_destroy(prt); 13352 } 13353 } 13354 13355 free(names); 13356 free(objects); 13357 free(tmpls); 13358 } 13359 13360 void 13361 lscf_listpg(const char *pattern) 13362 { 13363 lscf_prep_hndl(); 13364 13365 listprop(pattern, 1, 0); 13366 } 13367 13368 /* 13369 * Property group and property creation, setting, and deletion. setprop (and 13370 * its alias, addprop) can either create a property group of a given type, or 13371 * it can create or set a property to a given type and list of values. 13372 */ 13373 void 13374 lscf_addpg(const char *name, const char *type, const char *flags) 13375 { 13376 scf_propertygroup_t *pg; 13377 int ret; 13378 uint32_t flgs = 0; 13379 const char *cp; 13380 13381 13382 lscf_prep_hndl(); 13383 13384 if (cur_snap != NULL) { 13385 semerr(emsg_cant_modify_snapshots); 13386 return; 13387 } 13388 13389 if (cur_inst == NULL && cur_svc == NULL) { 13390 semerr(emsg_entity_not_selected); 13391 return; 13392 } 13393 13394 if (flags != NULL) { 13395 for (cp = flags; *cp != '\0'; ++cp) { 13396 switch (*cp) { 13397 case 'P': 13398 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13399 break; 13400 13401 case 'p': 13402 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13403 break; 13404 13405 default: 13406 semerr(gettext("Invalid property group flag " 13407 "%c."), *cp); 13408 return; 13409 } 13410 } 13411 } 13412 13413 pg = scf_pg_create(g_hndl); 13414 if (pg == NULL) 13415 scfdie(); 13416 13417 if (cur_inst != NULL) 13418 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13419 else 13420 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13421 13422 if (ret != SCF_SUCCESS) { 13423 switch (scf_error()) { 13424 case SCF_ERROR_INVALID_ARGUMENT: 13425 semerr(gettext("Name, type, or flags are invalid.\n")); 13426 break; 13427 13428 case SCF_ERROR_EXISTS: 13429 semerr(gettext("Property group already exists.\n")); 13430 break; 13431 13432 case SCF_ERROR_PERMISSION_DENIED: 13433 semerr(emsg_permission_denied); 13434 break; 13435 13436 case SCF_ERROR_BACKEND_ACCESS: 13437 semerr(gettext("Backend refused access.\n")); 13438 break; 13439 13440 default: 13441 scfdie(); 13442 } 13443 } 13444 13445 scf_pg_destroy(pg); 13446 13447 private_refresh(); 13448 } 13449 13450 void 13451 lscf_delpg(char *name) 13452 { 13453 lscf_prep_hndl(); 13454 13455 if (cur_snap != NULL) { 13456 semerr(emsg_cant_modify_snapshots); 13457 return; 13458 } 13459 13460 if (cur_inst == NULL && cur_svc == NULL) { 13461 semerr(emsg_entity_not_selected); 13462 return; 13463 } 13464 13465 if (strchr(name, '/') != NULL) { 13466 semerr(emsg_invalid_pg_name, name); 13467 return; 13468 } 13469 13470 lscf_delprop(name); 13471 } 13472 13473 /* 13474 * scf_delhash() is used to remove the property group related to the 13475 * hash entry for a specific manifest in the repository. pgname will be 13476 * constructed from the location of the manifest file. If deathrow isn't 0, 13477 * manifest file doesn't need to exist (manifest string will be used as 13478 * an absolute path). 13479 */ 13480 void 13481 lscf_delhash(char *manifest, int deathrow) 13482 { 13483 char *pgname; 13484 13485 if (cur_snap != NULL || 13486 cur_inst != NULL || cur_svc != NULL) { 13487 warn(gettext("error, an entity is selected\n")); 13488 return; 13489 } 13490 13491 /* select smf/manifest */ 13492 lscf_select(HASH_SVC); 13493 /* 13494 * Translate the manifest file name to property name. In the deathrow 13495 * case, the manifest file does not need to exist. 13496 */ 13497 pgname = mhash_filename_to_propname(manifest, 13498 deathrow ? B_TRUE : B_FALSE); 13499 if (pgname == NULL) { 13500 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13501 return; 13502 } 13503 /* delete the hash property name */ 13504 lscf_delpg(pgname); 13505 } 13506 13507 void 13508 lscf_listprop(const char *pattern) 13509 { 13510 lscf_prep_hndl(); 13511 13512 listprop(pattern, 0, 0); 13513 } 13514 13515 int 13516 lscf_setprop(const char *pgname, const char *type, const char *value, 13517 const uu_list_t *values) 13518 { 13519 scf_type_t ty, current_ty; 13520 scf_service_t *svc; 13521 scf_propertygroup_t *pg, *parent_pg; 13522 scf_property_t *prop, *parent_prop; 13523 scf_pg_tmpl_t *pgt; 13524 scf_prop_tmpl_t *prt; 13525 int ret, result = 0; 13526 scf_transaction_t *tx; 13527 scf_transaction_entry_t *e; 13528 scf_value_t *v; 13529 uu_list_walk_t *walk; 13530 string_list_t *sp; 13531 char *propname; 13532 int req_quotes = 0; 13533 13534 lscf_prep_hndl(); 13535 13536 if ((e = scf_entry_create(g_hndl)) == NULL || 13537 (svc = scf_service_create(g_hndl)) == NULL || 13538 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13539 (pg = scf_pg_create(g_hndl)) == NULL || 13540 (parent_prop = scf_property_create(g_hndl)) == NULL || 13541 (prop = scf_property_create(g_hndl)) == NULL || 13542 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13543 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13544 (tx = scf_transaction_create(g_hndl)) == NULL) 13545 scfdie(); 13546 13547 if (cur_snap != NULL) { 13548 semerr(emsg_cant_modify_snapshots); 13549 goto fail; 13550 } 13551 13552 if (cur_inst == NULL && cur_svc == NULL) { 13553 semerr(emsg_entity_not_selected); 13554 goto fail; 13555 } 13556 13557 propname = strchr(pgname, '/'); 13558 if (propname == NULL) { 13559 semerr(gettext("Property names must contain a `/'.\n")); 13560 goto fail; 13561 } 13562 13563 *propname = '\0'; 13564 ++propname; 13565 13566 if (type != NULL) { 13567 ty = string_to_type(type); 13568 if (ty == SCF_TYPE_INVALID) { 13569 semerr(gettext("Unknown type \"%s\".\n"), type); 13570 goto fail; 13571 } 13572 } 13573 13574 if (cur_inst != NULL) 13575 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13576 else 13577 ret = scf_service_get_pg(cur_svc, pgname, pg); 13578 if (ret != SCF_SUCCESS) { 13579 switch (scf_error()) { 13580 case SCF_ERROR_NOT_FOUND: 13581 semerr(emsg_no_such_pg, pgname); 13582 goto fail; 13583 13584 case SCF_ERROR_INVALID_ARGUMENT: 13585 semerr(emsg_invalid_pg_name, pgname); 13586 goto fail; 13587 13588 default: 13589 scfdie(); 13590 break; 13591 } 13592 } 13593 13594 do { 13595 if (scf_pg_update(pg) == -1) 13596 scfdie(); 13597 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13598 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13599 scfdie(); 13600 13601 semerr(emsg_permission_denied); 13602 goto fail; 13603 } 13604 13605 ret = scf_pg_get_property(pg, propname, prop); 13606 if (ret == SCF_SUCCESS) { 13607 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13608 scfdie(); 13609 13610 if (type == NULL) 13611 ty = current_ty; 13612 if (scf_transaction_property_change_type(tx, e, 13613 propname, ty) == -1) 13614 scfdie(); 13615 13616 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13617 /* Infer the type, if possible. */ 13618 if (type == NULL) { 13619 /* 13620 * First check if we're an instance and the 13621 * property is set on the service. 13622 */ 13623 if (cur_inst != NULL && 13624 scf_instance_get_parent(cur_inst, 13625 svc) == 0 && 13626 scf_service_get_pg(cur_svc, pgname, 13627 parent_pg) == 0 && 13628 scf_pg_get_property(parent_pg, propname, 13629 parent_prop) == 0 && 13630 scf_property_type(parent_prop, 13631 ¤t_ty) == 0) { 13632 ty = current_ty; 13633 13634 /* Then check for a type set in a template. */ 13635 } else if (scf_tmpl_get_by_pg(pg, pgt, 13636 0) == 0 && 13637 scf_tmpl_get_by_prop(pgt, propname, prt, 13638 0) == 0 && 13639 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13640 ty = current_ty; 13641 13642 /* If type can't be inferred, fail. */ 13643 } else { 13644 semerr(gettext("Type required for new " 13645 "properties.\n")); 13646 goto fail; 13647 } 13648 } 13649 if (scf_transaction_property_new(tx, e, propname, 13650 ty) == -1) 13651 scfdie(); 13652 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13653 semerr(emsg_invalid_prop_name, propname); 13654 goto fail; 13655 } else { 13656 scfdie(); 13657 } 13658 13659 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13660 req_quotes = 1; 13661 13662 if (value != NULL) { 13663 v = string_to_value(value, ty, 0); 13664 13665 if (v == NULL) 13666 goto fail; 13667 13668 ret = scf_entry_add_value(e, v); 13669 assert(ret == SCF_SUCCESS); 13670 } else { 13671 assert(values != NULL); 13672 13673 walk = uu_list_walk_start((uu_list_t *)values, 13674 UU_DEFAULT); 13675 if (walk == NULL) 13676 uu_die(gettext("Could not walk list")); 13677 13678 for (sp = uu_list_walk_next(walk); sp != NULL; 13679 sp = uu_list_walk_next(walk)) { 13680 v = string_to_value(sp->str, ty, req_quotes); 13681 13682 if (v == NULL) { 13683 scf_entry_destroy_children(e); 13684 goto fail; 13685 } 13686 13687 ret = scf_entry_add_value(e, v); 13688 assert(ret == SCF_SUCCESS); 13689 } 13690 uu_list_walk_end(walk); 13691 } 13692 result = scf_transaction_commit(tx); 13693 13694 scf_transaction_reset(tx); 13695 scf_entry_destroy_children(e); 13696 } while (result == 0); 13697 13698 if (result < 0) { 13699 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13700 scfdie(); 13701 13702 semerr(emsg_permission_denied); 13703 goto fail; 13704 } 13705 13706 ret = 0; 13707 13708 private_refresh(); 13709 13710 goto cleanup; 13711 13712 fail: 13713 ret = -1; 13714 13715 cleanup: 13716 scf_transaction_destroy(tx); 13717 scf_entry_destroy(e); 13718 scf_service_destroy(svc); 13719 scf_pg_destroy(parent_pg); 13720 scf_pg_destroy(pg); 13721 scf_property_destroy(parent_prop); 13722 scf_property_destroy(prop); 13723 scf_tmpl_pg_destroy(pgt); 13724 scf_tmpl_prop_destroy(prt); 13725 13726 return (ret); 13727 } 13728 13729 void 13730 lscf_delprop(char *pgn) 13731 { 13732 char *slash, *pn; 13733 scf_propertygroup_t *pg; 13734 scf_transaction_t *tx; 13735 scf_transaction_entry_t *e; 13736 int ret; 13737 13738 13739 lscf_prep_hndl(); 13740 13741 if (cur_snap != NULL) { 13742 semerr(emsg_cant_modify_snapshots); 13743 return; 13744 } 13745 13746 if (cur_inst == NULL && cur_svc == NULL) { 13747 semerr(emsg_entity_not_selected); 13748 return; 13749 } 13750 13751 pg = scf_pg_create(g_hndl); 13752 if (pg == NULL) 13753 scfdie(); 13754 13755 slash = strchr(pgn, '/'); 13756 if (slash == NULL) { 13757 pn = NULL; 13758 } else { 13759 *slash = '\0'; 13760 pn = slash + 1; 13761 } 13762 13763 if (cur_inst != NULL) 13764 ret = scf_instance_get_pg(cur_inst, pgn, pg); 13765 else 13766 ret = scf_service_get_pg(cur_svc, pgn, pg); 13767 if (ret != SCF_SUCCESS) { 13768 switch (scf_error()) { 13769 case SCF_ERROR_NOT_FOUND: 13770 semerr(emsg_no_such_pg, pgn); 13771 break; 13772 13773 case SCF_ERROR_INVALID_ARGUMENT: 13774 semerr(emsg_invalid_pg_name, pgn); 13775 break; 13776 13777 default: 13778 scfdie(); 13779 } 13780 13781 scf_pg_destroy(pg); 13782 13783 return; 13784 } 13785 13786 if (pn == NULL) { 13787 /* Try to delete the property group. */ 13788 if (scf_pg_delete(pg) != SCF_SUCCESS) { 13789 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13790 scfdie(); 13791 13792 semerr(emsg_permission_denied); 13793 } else { 13794 private_refresh(); 13795 } 13796 13797 scf_pg_destroy(pg); 13798 return; 13799 } 13800 13801 e = scf_entry_create(g_hndl); 13802 tx = scf_transaction_create(g_hndl); 13803 13804 do { 13805 if (scf_pg_update(pg) == -1) 13806 scfdie(); 13807 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13808 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13809 scfdie(); 13810 13811 semerr(emsg_permission_denied); 13812 break; 13813 } 13814 13815 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 13816 if (scf_error() == SCF_ERROR_NOT_FOUND) { 13817 semerr(gettext("No such property %s/%s.\n"), 13818 pgn, pn); 13819 break; 13820 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13821 semerr(emsg_invalid_prop_name, pn); 13822 break; 13823 } else { 13824 scfdie(); 13825 } 13826 } 13827 13828 ret = scf_transaction_commit(tx); 13829 13830 if (ret == 0) 13831 scf_transaction_reset(tx); 13832 } while (ret == 0); 13833 13834 if (ret < 0) { 13835 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13836 scfdie(); 13837 13838 semerr(emsg_permission_denied); 13839 } else { 13840 private_refresh(); 13841 } 13842 13843 scf_transaction_destroy(tx); 13844 scf_entry_destroy(e); 13845 scf_pg_destroy(pg); 13846 } 13847 13848 /* 13849 * Property editing. 13850 */ 13851 13852 static int 13853 write_edit_script(FILE *strm) 13854 { 13855 char *fmribuf; 13856 ssize_t fmrilen; 13857 13858 scf_propertygroup_t *pg; 13859 scf_property_t *prop; 13860 scf_value_t *val; 13861 scf_type_t ty; 13862 int ret, result = 0; 13863 scf_iter_t *iter, *piter, *viter; 13864 char *buf, *tybuf, *pname; 13865 const char *emsg_write_error; 13866 13867 13868 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 13869 13870 13871 /* select fmri */ 13872 if (cur_inst != NULL) { 13873 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 13874 if (fmrilen < 0) 13875 scfdie(); 13876 fmribuf = safe_malloc(fmrilen + 1); 13877 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 13878 scfdie(); 13879 } else { 13880 assert(cur_svc != NULL); 13881 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 13882 if (fmrilen < 0) 13883 scfdie(); 13884 fmribuf = safe_malloc(fmrilen + 1); 13885 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 13886 scfdie(); 13887 } 13888 13889 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 13890 warn(emsg_write_error, strerror(errno)); 13891 free(fmribuf); 13892 return (-1); 13893 } 13894 13895 free(fmribuf); 13896 13897 13898 if ((pg = scf_pg_create(g_hndl)) == NULL || 13899 (prop = scf_property_create(g_hndl)) == NULL || 13900 (val = scf_value_create(g_hndl)) == NULL || 13901 (iter = scf_iter_create(g_hndl)) == NULL || 13902 (piter = scf_iter_create(g_hndl)) == NULL || 13903 (viter = scf_iter_create(g_hndl)) == NULL) 13904 scfdie(); 13905 13906 buf = safe_malloc(max_scf_name_len + 1); 13907 tybuf = safe_malloc(max_scf_pg_type_len + 1); 13908 pname = safe_malloc(max_scf_name_len + 1); 13909 13910 if (cur_inst != NULL) 13911 ret = scf_iter_instance_pgs(iter, cur_inst); 13912 else 13913 ret = scf_iter_service_pgs(iter, cur_svc); 13914 if (ret != SCF_SUCCESS) 13915 scfdie(); 13916 13917 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13918 int ret2; 13919 13920 /* 13921 * # delprop pg 13922 * # addpg pg type 13923 */ 13924 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 13925 scfdie(); 13926 13927 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 13928 scfdie(); 13929 13930 if (fprintf(strm, "# Property group \"%s\"\n" 13931 "# delprop %s\n" 13932 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 13933 warn(emsg_write_error, strerror(errno)); 13934 result = -1; 13935 goto out; 13936 } 13937 13938 /* # setprop pg/prop = (values) */ 13939 13940 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13941 scfdie(); 13942 13943 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 13944 int first = 1; 13945 int ret3; 13946 int multiple; 13947 int is_str; 13948 scf_type_t bty; 13949 13950 if (scf_property_get_name(prop, pname, 13951 max_scf_name_len + 1) < 0) 13952 scfdie(); 13953 13954 if (scf_property_type(prop, &ty) != 0) 13955 scfdie(); 13956 13957 multiple = prop_has_multiple_values(prop, val); 13958 13959 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 13960 pname, scf_type_to_string(ty), multiple ? "(" : "") 13961 < 0) { 13962 warn(emsg_write_error, strerror(errno)); 13963 result = -1; 13964 goto out; 13965 } 13966 13967 (void) scf_type_base_type(ty, &bty); 13968 is_str = (bty == SCF_TYPE_ASTRING); 13969 13970 if (scf_iter_property_values(viter, prop) != 13971 SCF_SUCCESS) 13972 scfdie(); 13973 13974 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 13975 char *buf; 13976 ssize_t buflen; 13977 13978 buflen = scf_value_get_as_string(val, NULL, 0); 13979 if (buflen < 0) 13980 scfdie(); 13981 13982 buf = safe_malloc(buflen + 1); 13983 13984 if (scf_value_get_as_string(val, buf, 13985 buflen + 1) < 0) 13986 scfdie(); 13987 13988 if (first) 13989 first = 0; 13990 else { 13991 if (putc(' ', strm) != ' ') { 13992 warn(emsg_write_error, 13993 strerror(errno)); 13994 result = -1; 13995 goto out; 13996 } 13997 } 13998 13999 if ((is_str && multiple) || 14000 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 14001 (void) putc('"', strm); 14002 (void) quote_and_print(buf, strm, 1); 14003 (void) putc('"', strm); 14004 14005 if (ferror(strm)) { 14006 warn(emsg_write_error, 14007 strerror(errno)); 14008 result = -1; 14009 goto out; 14010 } 14011 } else { 14012 if (fprintf(strm, "%s", buf) < 0) { 14013 warn(emsg_write_error, 14014 strerror(errno)); 14015 result = -1; 14016 goto out; 14017 } 14018 } 14019 14020 free(buf); 14021 } 14022 if (ret3 < 0 && 14023 scf_error() != SCF_ERROR_PERMISSION_DENIED) 14024 scfdie(); 14025 14026 /* Write closing paren if mult-value property */ 14027 if ((multiple && putc(')', strm) == EOF) || 14028 14029 /* Write final newline */ 14030 fputc('\n', strm) == EOF) { 14031 warn(emsg_write_error, strerror(errno)); 14032 result = -1; 14033 goto out; 14034 } 14035 } 14036 if (ret2 < 0) 14037 scfdie(); 14038 14039 if (fputc('\n', strm) == EOF) { 14040 warn(emsg_write_error, strerror(errno)); 14041 result = -1; 14042 goto out; 14043 } 14044 } 14045 if (ret < 0) 14046 scfdie(); 14047 14048 out: 14049 free(pname); 14050 free(tybuf); 14051 free(buf); 14052 scf_iter_destroy(viter); 14053 scf_iter_destroy(piter); 14054 scf_iter_destroy(iter); 14055 scf_value_destroy(val); 14056 scf_property_destroy(prop); 14057 scf_pg_destroy(pg); 14058 14059 if (result == 0) { 14060 if (fflush(strm) != 0) { 14061 warn(emsg_write_error, strerror(errno)); 14062 return (-1); 14063 } 14064 } 14065 14066 return (result); 14067 } 14068 14069 int 14070 lscf_editprop() 14071 { 14072 char *buf, *editor; 14073 size_t bufsz; 14074 int tmpfd; 14075 char tempname[] = TEMP_FILE_PATTERN; 14076 14077 lscf_prep_hndl(); 14078 14079 if (cur_snap != NULL) { 14080 semerr(emsg_cant_modify_snapshots); 14081 return (-1); 14082 } 14083 14084 if (cur_svc == NULL && cur_inst == NULL) { 14085 semerr(emsg_entity_not_selected); 14086 return (-1); 14087 } 14088 14089 tmpfd = mkstemp(tempname); 14090 if (tmpfd == -1) { 14091 semerr(gettext("Could not create temporary file.\n")); 14092 return (-1); 14093 } 14094 14095 (void) strcpy(tempfilename, tempname); 14096 14097 tempfile = fdopen(tmpfd, "r+"); 14098 if (tempfile == NULL) { 14099 warn(gettext("Could not create temporary file.\n")); 14100 if (close(tmpfd) == -1) 14101 warn(gettext("Could not close temporary file: %s.\n"), 14102 strerror(errno)); 14103 14104 remove_tempfile(); 14105 14106 return (-1); 14107 } 14108 14109 if (write_edit_script(tempfile) == -1) { 14110 remove_tempfile(); 14111 return (-1); 14112 } 14113 14114 editor = getenv("EDITOR"); 14115 if (editor == NULL) 14116 editor = "vi"; 14117 14118 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 14119 buf = safe_malloc(bufsz); 14120 14121 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 14122 uu_die(gettext("Error creating editor command")); 14123 14124 if (system(buf) == -1) { 14125 semerr(gettext("Could not launch editor %s: %s\n"), editor, 14126 strerror(errno)); 14127 free(buf); 14128 remove_tempfile(); 14129 return (-1); 14130 } 14131 14132 free(buf); 14133 14134 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 14135 14136 remove_tempfile(); 14137 14138 return (0); 14139 } 14140 14141 static void 14142 add_string(uu_list_t *strlist, const char *str) 14143 { 14144 string_list_t *elem; 14145 elem = safe_malloc(sizeof (*elem)); 14146 uu_list_node_init(elem, &elem->node, string_pool); 14147 elem->str = safe_strdup(str); 14148 if (uu_list_append(strlist, elem) != 0) 14149 uu_die(gettext("libuutil error: %s\n"), 14150 uu_strerror(uu_error())); 14151 } 14152 14153 static int 14154 remove_string(uu_list_t *strlist, const char *str) 14155 { 14156 uu_list_walk_t *elems; 14157 string_list_t *sp; 14158 14159 /* 14160 * Find the element that needs to be removed. 14161 */ 14162 elems = uu_list_walk_start(strlist, UU_DEFAULT); 14163 while ((sp = uu_list_walk_next(elems)) != NULL) { 14164 if (strcmp(sp->str, str) == 0) 14165 break; 14166 } 14167 uu_list_walk_end(elems); 14168 14169 /* 14170 * Returning 1 here as the value was not found, this 14171 * might not be an error. Leave it to the caller to 14172 * decide. 14173 */ 14174 if (sp == NULL) { 14175 return (1); 14176 } 14177 14178 uu_list_remove(strlist, sp); 14179 14180 free(sp->str); 14181 free(sp); 14182 14183 return (0); 14184 } 14185 14186 /* 14187 * Get all property values that don't match the given glob pattern, 14188 * if a pattern is specified. 14189 */ 14190 static void 14191 get_prop_values(scf_property_t *prop, uu_list_t *values, 14192 const char *pattern) 14193 { 14194 scf_iter_t *iter; 14195 scf_value_t *val; 14196 int ret; 14197 14198 if ((iter = scf_iter_create(g_hndl)) == NULL || 14199 (val = scf_value_create(g_hndl)) == NULL) 14200 scfdie(); 14201 14202 if (scf_iter_property_values(iter, prop) != 0) 14203 scfdie(); 14204 14205 while ((ret = scf_iter_next_value(iter, val)) == 1) { 14206 char *buf; 14207 ssize_t vlen, szret; 14208 14209 vlen = scf_value_get_as_string(val, NULL, 0); 14210 if (vlen < 0) 14211 scfdie(); 14212 14213 buf = safe_malloc(vlen + 1); 14214 14215 szret = scf_value_get_as_string(val, buf, vlen + 1); 14216 if (szret < 0) 14217 scfdie(); 14218 assert(szret <= vlen); 14219 14220 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 14221 add_string(values, buf); 14222 14223 free(buf); 14224 } 14225 14226 if (ret == -1) 14227 scfdie(); 14228 14229 scf_value_destroy(val); 14230 scf_iter_destroy(iter); 14231 } 14232 14233 static int 14234 lscf_setpropvalue(const char *pgname, const char *type, 14235 const char *arg, int isadd, int isnotfoundok) 14236 { 14237 scf_type_t ty; 14238 scf_propertygroup_t *pg; 14239 scf_property_t *prop; 14240 int ret, result = 0; 14241 scf_transaction_t *tx; 14242 scf_transaction_entry_t *e; 14243 scf_value_t *v; 14244 string_list_t *sp; 14245 char *propname; 14246 uu_list_t *values; 14247 uu_list_walk_t *walk; 14248 void *cookie = NULL; 14249 char *pattern = NULL; 14250 14251 lscf_prep_hndl(); 14252 14253 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14254 uu_die(gettext("Could not create property list: %s\n"), 14255 uu_strerror(uu_error())); 14256 14257 if (!isadd) 14258 pattern = safe_strdup(arg); 14259 14260 if ((e = scf_entry_create(g_hndl)) == NULL || 14261 (pg = scf_pg_create(g_hndl)) == NULL || 14262 (prop = scf_property_create(g_hndl)) == NULL || 14263 (tx = scf_transaction_create(g_hndl)) == NULL) 14264 scfdie(); 14265 14266 if (cur_snap != NULL) { 14267 semerr(emsg_cant_modify_snapshots); 14268 goto fail; 14269 } 14270 14271 if (cur_inst == NULL && cur_svc == NULL) { 14272 semerr(emsg_entity_not_selected); 14273 goto fail; 14274 } 14275 14276 propname = strchr(pgname, '/'); 14277 if (propname == NULL) { 14278 semerr(gettext("Property names must contain a `/'.\n")); 14279 goto fail; 14280 } 14281 14282 *propname = '\0'; 14283 ++propname; 14284 14285 if (type != NULL) { 14286 ty = string_to_type(type); 14287 if (ty == SCF_TYPE_INVALID) { 14288 semerr(gettext("Unknown type \"%s\".\n"), type); 14289 goto fail; 14290 } 14291 } 14292 14293 if (cur_inst != NULL) 14294 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14295 else 14296 ret = scf_service_get_pg(cur_svc, pgname, pg); 14297 if (ret != 0) { 14298 switch (scf_error()) { 14299 case SCF_ERROR_NOT_FOUND: 14300 if (isnotfoundok) { 14301 result = 0; 14302 } else { 14303 semerr(emsg_no_such_pg, pgname); 14304 result = -1; 14305 } 14306 goto out; 14307 14308 case SCF_ERROR_INVALID_ARGUMENT: 14309 semerr(emsg_invalid_pg_name, pgname); 14310 goto fail; 14311 14312 default: 14313 scfdie(); 14314 } 14315 } 14316 14317 do { 14318 if (scf_pg_update(pg) == -1) 14319 scfdie(); 14320 if (scf_transaction_start(tx, pg) != 0) { 14321 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14322 scfdie(); 14323 14324 semerr(emsg_permission_denied); 14325 goto fail; 14326 } 14327 14328 ret = scf_pg_get_property(pg, propname, prop); 14329 if (ret == 0) { 14330 scf_type_t ptype; 14331 char *pat = pattern; 14332 14333 if (scf_property_type(prop, &ptype) != 0) 14334 scfdie(); 14335 14336 if (isadd) { 14337 if (type != NULL && ptype != ty) { 14338 semerr(gettext("Property \"%s\" is not " 14339 "of type \"%s\".\n"), propname, 14340 type); 14341 goto fail; 14342 } 14343 14344 pat = NULL; 14345 } else { 14346 size_t len = strlen(pat); 14347 if (len > 0 && pat[len - 1] == '\"') 14348 pat[len - 1] = '\0'; 14349 if (len > 0 && pat[0] == '\"') 14350 pat++; 14351 } 14352 14353 ty = ptype; 14354 14355 get_prop_values(prop, values, pat); 14356 14357 if (isadd) 14358 add_string(values, arg); 14359 14360 if (scf_transaction_property_change(tx, e, 14361 propname, ty) == -1) 14362 scfdie(); 14363 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14364 if (isadd) { 14365 if (type == NULL) { 14366 semerr(gettext("Type required " 14367 "for new properties.\n")); 14368 goto fail; 14369 } 14370 14371 add_string(values, arg); 14372 14373 if (scf_transaction_property_new(tx, e, 14374 propname, ty) == -1) 14375 scfdie(); 14376 } else if (isnotfoundok) { 14377 result = 0; 14378 goto out; 14379 } else { 14380 semerr(gettext("No such property %s/%s.\n"), 14381 pgname, propname); 14382 result = -1; 14383 goto out; 14384 } 14385 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14386 semerr(emsg_invalid_prop_name, propname); 14387 goto fail; 14388 } else { 14389 scfdie(); 14390 } 14391 14392 walk = uu_list_walk_start(values, UU_DEFAULT); 14393 if (walk == NULL) 14394 uu_die(gettext("Could not walk property list.\n")); 14395 14396 for (sp = uu_list_walk_next(walk); sp != NULL; 14397 sp = uu_list_walk_next(walk)) { 14398 v = string_to_value(sp->str, ty, 0); 14399 14400 if (v == NULL) { 14401 scf_entry_destroy_children(e); 14402 goto fail; 14403 } 14404 ret = scf_entry_add_value(e, v); 14405 assert(ret == 0); 14406 } 14407 uu_list_walk_end(walk); 14408 14409 result = scf_transaction_commit(tx); 14410 14411 scf_transaction_reset(tx); 14412 scf_entry_destroy_children(e); 14413 } while (result == 0); 14414 14415 if (result < 0) { 14416 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14417 scfdie(); 14418 14419 semerr(emsg_permission_denied); 14420 goto fail; 14421 } 14422 14423 result = 0; 14424 14425 private_refresh(); 14426 14427 out: 14428 scf_transaction_destroy(tx); 14429 scf_entry_destroy(e); 14430 scf_pg_destroy(pg); 14431 scf_property_destroy(prop); 14432 free(pattern); 14433 14434 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14435 free(sp->str); 14436 free(sp); 14437 } 14438 14439 uu_list_destroy(values); 14440 14441 return (result); 14442 14443 fail: 14444 result = -1; 14445 goto out; 14446 } 14447 14448 int 14449 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14450 { 14451 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14452 } 14453 14454 int 14455 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14456 { 14457 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14458 } 14459 14460 /* 14461 * Look for a standard start method, first in the instance (if any), 14462 * then the service. 14463 */ 14464 static const char * 14465 start_method_name(int *in_instance) 14466 { 14467 scf_propertygroup_t *pg; 14468 char **p; 14469 int ret; 14470 scf_instance_t *inst = cur_inst; 14471 14472 if ((pg = scf_pg_create(g_hndl)) == NULL) 14473 scfdie(); 14474 14475 again: 14476 for (p = start_method_names; *p != NULL; p++) { 14477 if (inst != NULL) 14478 ret = scf_instance_get_pg(inst, *p, pg); 14479 else 14480 ret = scf_service_get_pg(cur_svc, *p, pg); 14481 14482 if (ret == 0) { 14483 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14484 char *buf = safe_malloc(bufsz); 14485 14486 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14487 free(buf); 14488 continue; 14489 } 14490 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14491 free(buf); 14492 continue; 14493 } 14494 14495 free(buf); 14496 *in_instance = (inst != NULL); 14497 scf_pg_destroy(pg); 14498 return (*p); 14499 } 14500 14501 if (scf_error() == SCF_ERROR_NOT_FOUND) 14502 continue; 14503 14504 scfdie(); 14505 } 14506 14507 if (inst != NULL) { 14508 inst = NULL; 14509 goto again; 14510 } 14511 14512 scf_pg_destroy(pg); 14513 return (NULL); 14514 } 14515 14516 static int 14517 addpg(const char *name, const char *type) 14518 { 14519 scf_propertygroup_t *pg; 14520 int ret; 14521 14522 pg = scf_pg_create(g_hndl); 14523 if (pg == NULL) 14524 scfdie(); 14525 14526 if (cur_inst != NULL) 14527 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14528 else 14529 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14530 14531 if (ret != 0) { 14532 switch (scf_error()) { 14533 case SCF_ERROR_EXISTS: 14534 ret = 0; 14535 break; 14536 14537 case SCF_ERROR_PERMISSION_DENIED: 14538 semerr(emsg_permission_denied); 14539 break; 14540 14541 default: 14542 scfdie(); 14543 } 14544 } 14545 14546 scf_pg_destroy(pg); 14547 return (ret); 14548 } 14549 14550 int 14551 lscf_setenv(uu_list_t *args, int isunset) 14552 { 14553 int ret = 0; 14554 size_t i; 14555 int argc; 14556 char **argv = NULL; 14557 string_list_t *slp; 14558 char *pattern; 14559 char *prop; 14560 int do_service = 0; 14561 int do_instance = 0; 14562 const char *method = NULL; 14563 const char *name = NULL; 14564 const char *value = NULL; 14565 scf_instance_t *saved_cur_inst = cur_inst; 14566 14567 lscf_prep_hndl(); 14568 14569 argc = uu_list_numnodes(args); 14570 if (argc < 1) 14571 goto usage; 14572 14573 argv = calloc(argc + 1, sizeof (char *)); 14574 if (argv == NULL) 14575 uu_die(gettext("Out of memory.\n")); 14576 14577 for (slp = uu_list_first(args), i = 0; 14578 slp != NULL; 14579 slp = uu_list_next(args, slp), ++i) 14580 argv[i] = slp->str; 14581 14582 argv[i] = NULL; 14583 14584 opterr = 0; 14585 optind = 0; 14586 for (;;) { 14587 ret = getopt(argc, argv, "sim:"); 14588 if (ret == -1) 14589 break; 14590 14591 switch (ret) { 14592 case 's': 14593 do_service = 1; 14594 cur_inst = NULL; 14595 break; 14596 14597 case 'i': 14598 do_instance = 1; 14599 break; 14600 14601 case 'm': 14602 method = optarg; 14603 break; 14604 14605 case '?': 14606 goto usage; 14607 14608 default: 14609 bad_error("getopt", ret); 14610 } 14611 } 14612 14613 argc -= optind; 14614 if ((do_service && do_instance) || 14615 (isunset && argc != 1) || 14616 (!isunset && argc != 2)) 14617 goto usage; 14618 14619 name = argv[optind]; 14620 if (!isunset) 14621 value = argv[optind + 1]; 14622 14623 if (cur_snap != NULL) { 14624 semerr(emsg_cant_modify_snapshots); 14625 ret = -1; 14626 goto out; 14627 } 14628 14629 if (cur_inst == NULL && cur_svc == NULL) { 14630 semerr(emsg_entity_not_selected); 14631 ret = -1; 14632 goto out; 14633 } 14634 14635 if (do_instance && cur_inst == NULL) { 14636 semerr(gettext("No instance is selected.\n")); 14637 ret = -1; 14638 goto out; 14639 } 14640 14641 if (do_service && cur_svc == NULL) { 14642 semerr(gettext("No service is selected.\n")); 14643 ret = -1; 14644 goto out; 14645 } 14646 14647 if (method == NULL) { 14648 if (do_instance || do_service) { 14649 method = "method_context"; 14650 if (!isunset) { 14651 ret = addpg("method_context", 14652 SCF_GROUP_FRAMEWORK); 14653 if (ret != 0) 14654 goto out; 14655 } 14656 } else { 14657 int in_instance; 14658 method = start_method_name(&in_instance); 14659 if (method == NULL) { 14660 semerr(gettext( 14661 "Couldn't find start method; please " 14662 "specify a method with '-m'.\n")); 14663 ret = -1; 14664 goto out; 14665 } 14666 if (!in_instance) 14667 cur_inst = NULL; 14668 } 14669 } else { 14670 scf_propertygroup_t *pg; 14671 size_t bufsz; 14672 char *buf; 14673 int ret; 14674 14675 if ((pg = scf_pg_create(g_hndl)) == NULL) 14676 scfdie(); 14677 14678 if (cur_inst != NULL) 14679 ret = scf_instance_get_pg(cur_inst, method, pg); 14680 else 14681 ret = scf_service_get_pg(cur_svc, method, pg); 14682 14683 if (ret != 0) { 14684 scf_pg_destroy(pg); 14685 switch (scf_error()) { 14686 case SCF_ERROR_NOT_FOUND: 14687 semerr(gettext("Couldn't find the method " 14688 "\"%s\".\n"), method); 14689 goto out; 14690 14691 case SCF_ERROR_INVALID_ARGUMENT: 14692 semerr(gettext("Invalid method name \"%s\".\n"), 14693 method); 14694 goto out; 14695 14696 default: 14697 scfdie(); 14698 } 14699 } 14700 14701 bufsz = strlen(SCF_GROUP_METHOD) + 1; 14702 buf = safe_malloc(bufsz); 14703 14704 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 14705 strcmp(buf, SCF_GROUP_METHOD) != 0) { 14706 semerr(gettext("Property group \"%s\" is not of type " 14707 "\"method\".\n"), method); 14708 ret = -1; 14709 free(buf); 14710 scf_pg_destroy(pg); 14711 goto out; 14712 } 14713 14714 free(buf); 14715 scf_pg_destroy(pg); 14716 } 14717 14718 prop = uu_msprintf("%s/environment", method); 14719 pattern = uu_msprintf("%s=*", name); 14720 14721 if (prop == NULL || pattern == NULL) 14722 uu_die(gettext("Out of memory.\n")); 14723 14724 ret = lscf_delpropvalue(prop, pattern, !isunset); 14725 14726 if (ret == 0 && !isunset) { 14727 uu_free(pattern); 14728 uu_free(prop); 14729 prop = uu_msprintf("%s/environment", method); 14730 pattern = uu_msprintf("%s=%s", name, value); 14731 if (prop == NULL || pattern == NULL) 14732 uu_die(gettext("Out of memory.\n")); 14733 ret = lscf_addpropvalue(prop, "astring:", pattern); 14734 } 14735 uu_free(pattern); 14736 uu_free(prop); 14737 14738 out: 14739 cur_inst = saved_cur_inst; 14740 14741 free(argv); 14742 return (ret); 14743 usage: 14744 ret = -2; 14745 goto out; 14746 } 14747 14748 /* 14749 * Snapshot commands 14750 */ 14751 14752 void 14753 lscf_listsnap() 14754 { 14755 scf_snapshot_t *snap; 14756 scf_iter_t *iter; 14757 char *nb; 14758 int r; 14759 14760 lscf_prep_hndl(); 14761 14762 if (cur_inst == NULL) { 14763 semerr(gettext("Instance not selected.\n")); 14764 return; 14765 } 14766 14767 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 14768 (iter = scf_iter_create(g_hndl)) == NULL) 14769 scfdie(); 14770 14771 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 14772 scfdie(); 14773 14774 nb = safe_malloc(max_scf_name_len + 1); 14775 14776 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 14777 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 14778 scfdie(); 14779 14780 (void) puts(nb); 14781 } 14782 if (r < 0) 14783 scfdie(); 14784 14785 free(nb); 14786 scf_iter_destroy(iter); 14787 scf_snapshot_destroy(snap); 14788 } 14789 14790 void 14791 lscf_selectsnap(const char *name) 14792 { 14793 scf_snapshot_t *snap; 14794 scf_snaplevel_t *level; 14795 14796 lscf_prep_hndl(); 14797 14798 if (cur_inst == NULL) { 14799 semerr(gettext("Instance not selected.\n")); 14800 return; 14801 } 14802 14803 if (cur_snap != NULL) { 14804 if (name != NULL) { 14805 char *cur_snap_name; 14806 boolean_t nochange; 14807 14808 cur_snap_name = safe_malloc(max_scf_name_len + 1); 14809 14810 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 14811 max_scf_name_len + 1) < 0) 14812 scfdie(); 14813 14814 nochange = strcmp(name, cur_snap_name) == 0; 14815 14816 free(cur_snap_name); 14817 14818 if (nochange) 14819 return; 14820 } 14821 14822 unselect_cursnap(); 14823 } 14824 14825 if (name == NULL) 14826 return; 14827 14828 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 14829 (level = scf_snaplevel_create(g_hndl)) == NULL) 14830 scfdie(); 14831 14832 if (scf_instance_get_snapshot(cur_inst, name, snap) != 14833 SCF_SUCCESS) { 14834 switch (scf_error()) { 14835 case SCF_ERROR_INVALID_ARGUMENT: 14836 semerr(gettext("Invalid name \"%s\".\n"), name); 14837 break; 14838 14839 case SCF_ERROR_NOT_FOUND: 14840 semerr(gettext("No such snapshot \"%s\".\n"), name); 14841 break; 14842 14843 default: 14844 scfdie(); 14845 } 14846 14847 scf_snaplevel_destroy(level); 14848 scf_snapshot_destroy(snap); 14849 return; 14850 } 14851 14852 /* Load the snaplevels into our list. */ 14853 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 14854 if (cur_levels == NULL) 14855 uu_die(gettext("Could not create list: %s\n"), 14856 uu_strerror(uu_error())); 14857 14858 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 14859 if (scf_error() != SCF_ERROR_NOT_FOUND) 14860 scfdie(); 14861 14862 semerr(gettext("Snapshot has no snaplevels.\n")); 14863 14864 scf_snaplevel_destroy(level); 14865 scf_snapshot_destroy(snap); 14866 return; 14867 } 14868 14869 cur_snap = snap; 14870 14871 for (;;) { 14872 cur_elt = safe_malloc(sizeof (*cur_elt)); 14873 uu_list_node_init(cur_elt, &cur_elt->list_node, 14874 snaplevel_pool); 14875 cur_elt->sl = level; 14876 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 14877 uu_die(gettext("libuutil error: %s\n"), 14878 uu_strerror(uu_error())); 14879 14880 level = scf_snaplevel_create(g_hndl); 14881 if (level == NULL) 14882 scfdie(); 14883 14884 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 14885 level) != SCF_SUCCESS) { 14886 if (scf_error() != SCF_ERROR_NOT_FOUND) 14887 scfdie(); 14888 14889 scf_snaplevel_destroy(level); 14890 break; 14891 } 14892 } 14893 14894 cur_elt = uu_list_last(cur_levels); 14895 cur_level = cur_elt->sl; 14896 } 14897 14898 /* 14899 * Copies the properties & values in src to dst. Assumes src won't change. 14900 * Returns -1 if permission is denied, -2 if another transaction interrupts, 14901 * and 0 on success. 14902 * 14903 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 14904 * property, if it is copied and has type boolean. (See comment in 14905 * lscf_revert()). 14906 */ 14907 static int 14908 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 14909 uint8_t enabled) 14910 { 14911 scf_transaction_t *tx; 14912 scf_iter_t *iter, *viter; 14913 scf_property_t *prop; 14914 scf_value_t *v; 14915 char *nbuf; 14916 int r; 14917 14918 tx = scf_transaction_create(g_hndl); 14919 if (tx == NULL) 14920 scfdie(); 14921 14922 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 14923 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14924 scfdie(); 14925 14926 scf_transaction_destroy(tx); 14927 14928 return (-1); 14929 } 14930 14931 if ((iter = scf_iter_create(g_hndl)) == NULL || 14932 (prop = scf_property_create(g_hndl)) == NULL || 14933 (viter = scf_iter_create(g_hndl)) == NULL) 14934 scfdie(); 14935 14936 nbuf = safe_malloc(max_scf_name_len + 1); 14937 14938 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 14939 scfdie(); 14940 14941 for (;;) { 14942 scf_transaction_entry_t *e; 14943 scf_type_t ty; 14944 14945 r = scf_iter_next_property(iter, prop); 14946 if (r == -1) 14947 scfdie(); 14948 if (r == 0) 14949 break; 14950 14951 e = scf_entry_create(g_hndl); 14952 if (e == NULL) 14953 scfdie(); 14954 14955 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 14956 scfdie(); 14957 14958 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 14959 scfdie(); 14960 14961 if (scf_transaction_property_new(tx, e, nbuf, 14962 ty) != SCF_SUCCESS) 14963 scfdie(); 14964 14965 if ((enabled == 0 || enabled == 1) && 14966 strcmp(nbuf, scf_property_enabled) == 0 && 14967 ty == SCF_TYPE_BOOLEAN) { 14968 v = scf_value_create(g_hndl); 14969 if (v == NULL) 14970 scfdie(); 14971 14972 scf_value_set_boolean(v, enabled); 14973 14974 if (scf_entry_add_value(e, v) != 0) 14975 scfdie(); 14976 } else { 14977 if (scf_iter_property_values(viter, prop) != 0) 14978 scfdie(); 14979 14980 for (;;) { 14981 v = scf_value_create(g_hndl); 14982 if (v == NULL) 14983 scfdie(); 14984 14985 r = scf_iter_next_value(viter, v); 14986 if (r == -1) 14987 scfdie(); 14988 if (r == 0) { 14989 scf_value_destroy(v); 14990 break; 14991 } 14992 14993 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 14994 scfdie(); 14995 } 14996 } 14997 } 14998 14999 free(nbuf); 15000 scf_iter_destroy(viter); 15001 scf_property_destroy(prop); 15002 scf_iter_destroy(iter); 15003 15004 r = scf_transaction_commit(tx); 15005 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 15006 scfdie(); 15007 15008 scf_transaction_destroy_children(tx); 15009 scf_transaction_destroy(tx); 15010 15011 switch (r) { 15012 case 1: return (0); 15013 case 0: return (-2); 15014 case -1: return (-1); 15015 15016 default: 15017 abort(); 15018 } 15019 15020 /* NOTREACHED */ 15021 } 15022 15023 void 15024 lscf_revert(const char *snapname) 15025 { 15026 scf_snapshot_t *snap, *prev; 15027 scf_snaplevel_t *level, *nlevel; 15028 scf_iter_t *iter; 15029 scf_propertygroup_t *pg, *npg; 15030 scf_property_t *prop; 15031 scf_value_t *val; 15032 char *nbuf, *tbuf; 15033 uint8_t enabled; 15034 15035 lscf_prep_hndl(); 15036 15037 if (cur_inst == NULL) { 15038 semerr(gettext("Instance not selected.\n")); 15039 return; 15040 } 15041 15042 if (snapname != NULL) { 15043 snap = scf_snapshot_create(g_hndl); 15044 if (snap == NULL) 15045 scfdie(); 15046 15047 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 15048 SCF_SUCCESS) { 15049 switch (scf_error()) { 15050 case SCF_ERROR_INVALID_ARGUMENT: 15051 semerr(gettext("Invalid snapshot name " 15052 "\"%s\".\n"), snapname); 15053 break; 15054 15055 case SCF_ERROR_NOT_FOUND: 15056 semerr(gettext("No such snapshot.\n")); 15057 break; 15058 15059 default: 15060 scfdie(); 15061 } 15062 15063 scf_snapshot_destroy(snap); 15064 return; 15065 } 15066 } else { 15067 if (cur_snap != NULL) { 15068 snap = cur_snap; 15069 } else { 15070 semerr(gettext("No snapshot selected.\n")); 15071 return; 15072 } 15073 } 15074 15075 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 15076 (level = scf_snaplevel_create(g_hndl)) == NULL || 15077 (iter = scf_iter_create(g_hndl)) == NULL || 15078 (pg = scf_pg_create(g_hndl)) == NULL || 15079 (npg = scf_pg_create(g_hndl)) == NULL || 15080 (prop = scf_property_create(g_hndl)) == NULL || 15081 (val = scf_value_create(g_hndl)) == NULL) 15082 scfdie(); 15083 15084 nbuf = safe_malloc(max_scf_name_len + 1); 15085 tbuf = safe_malloc(max_scf_pg_type_len + 1); 15086 15087 /* Take the "previous" snapshot before we blow away the properties. */ 15088 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 15089 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 15090 scfdie(); 15091 } else { 15092 if (scf_error() != SCF_ERROR_NOT_FOUND) 15093 scfdie(); 15094 15095 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 15096 scfdie(); 15097 } 15098 15099 /* Save general/enabled, since we're probably going to replace it. */ 15100 enabled = 2; 15101 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 15102 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 15103 scf_property_get_value(prop, val) == 0) 15104 (void) scf_value_get_boolean(val, &enabled); 15105 15106 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15107 if (scf_error() != SCF_ERROR_NOT_FOUND) 15108 scfdie(); 15109 15110 goto out; 15111 } 15112 15113 for (;;) { 15114 boolean_t isinst; 15115 uint32_t flags; 15116 int r; 15117 15118 /* Clear the properties from the corresponding entity. */ 15119 isinst = snaplevel_is_instance(level); 15120 15121 if (!isinst) 15122 r = scf_iter_service_pgs(iter, cur_svc); 15123 else 15124 r = scf_iter_instance_pgs(iter, cur_inst); 15125 if (r != SCF_SUCCESS) 15126 scfdie(); 15127 15128 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15129 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15130 scfdie(); 15131 15132 /* Skip nonpersistent pgs. */ 15133 if (flags & SCF_PG_FLAG_NONPERSISTENT) 15134 continue; 15135 15136 if (scf_pg_delete(pg) != SCF_SUCCESS) { 15137 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15138 scfdie(); 15139 15140 semerr(emsg_permission_denied); 15141 goto out; 15142 } 15143 } 15144 if (r == -1) 15145 scfdie(); 15146 15147 /* Copy the properties to the corresponding entity. */ 15148 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 15149 scfdie(); 15150 15151 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15152 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 15153 scfdie(); 15154 15155 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 15156 0) 15157 scfdie(); 15158 15159 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15160 scfdie(); 15161 15162 if (!isinst) 15163 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 15164 flags, npg); 15165 else 15166 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 15167 flags, npg); 15168 if (r != SCF_SUCCESS) { 15169 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15170 scfdie(); 15171 15172 semerr(emsg_permission_denied); 15173 goto out; 15174 } 15175 15176 if ((enabled == 0 || enabled == 1) && 15177 strcmp(nbuf, scf_pg_general) == 0) 15178 r = pg_copy(pg, npg, enabled); 15179 else 15180 r = pg_copy(pg, npg, 2); 15181 15182 switch (r) { 15183 case 0: 15184 break; 15185 15186 case -1: 15187 semerr(emsg_permission_denied); 15188 goto out; 15189 15190 case -2: 15191 semerr(gettext( 15192 "Interrupted by another change.\n")); 15193 goto out; 15194 15195 default: 15196 abort(); 15197 } 15198 } 15199 if (r == -1) 15200 scfdie(); 15201 15202 /* Get next level. */ 15203 nlevel = scf_snaplevel_create(g_hndl); 15204 if (nlevel == NULL) 15205 scfdie(); 15206 15207 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 15208 SCF_SUCCESS) { 15209 if (scf_error() != SCF_ERROR_NOT_FOUND) 15210 scfdie(); 15211 15212 scf_snaplevel_destroy(nlevel); 15213 break; 15214 } 15215 15216 scf_snaplevel_destroy(level); 15217 level = nlevel; 15218 } 15219 15220 if (snapname == NULL) { 15221 lscf_selectsnap(NULL); 15222 snap = NULL; /* cur_snap has been destroyed */ 15223 } 15224 15225 out: 15226 free(tbuf); 15227 free(nbuf); 15228 scf_value_destroy(val); 15229 scf_property_destroy(prop); 15230 scf_pg_destroy(npg); 15231 scf_pg_destroy(pg); 15232 scf_iter_destroy(iter); 15233 scf_snaplevel_destroy(level); 15234 scf_snapshot_destroy(prev); 15235 if (snap != cur_snap) 15236 scf_snapshot_destroy(snap); 15237 } 15238 15239 void 15240 lscf_refresh(void) 15241 { 15242 ssize_t fmrilen; 15243 size_t bufsz; 15244 char *fmribuf; 15245 int r; 15246 15247 lscf_prep_hndl(); 15248 15249 if (cur_inst == NULL) { 15250 semerr(gettext("Instance not selected.\n")); 15251 return; 15252 } 15253 15254 bufsz = max_scf_fmri_len + 1; 15255 fmribuf = safe_malloc(bufsz); 15256 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15257 if (fmrilen < 0) { 15258 free(fmribuf); 15259 if (scf_error() != SCF_ERROR_DELETED) 15260 scfdie(); 15261 scf_instance_destroy(cur_inst); 15262 cur_inst = NULL; 15263 warn(emsg_deleted); 15264 return; 15265 } 15266 assert(fmrilen < bufsz); 15267 15268 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15269 switch (r) { 15270 case 0: 15271 break; 15272 15273 case ECONNABORTED: 15274 warn(gettext("Could not refresh %s " 15275 "(repository connection broken).\n"), fmribuf); 15276 break; 15277 15278 case ECANCELED: 15279 warn(emsg_deleted); 15280 break; 15281 15282 case EPERM: 15283 warn(gettext("Could not refresh %s " 15284 "(permission denied).\n"), fmribuf); 15285 break; 15286 15287 case ENOSPC: 15288 warn(gettext("Could not refresh %s " 15289 "(repository server out of resources).\n"), 15290 fmribuf); 15291 break; 15292 15293 case EACCES: 15294 default: 15295 bad_error("refresh_entity", scf_error()); 15296 } 15297 15298 free(fmribuf); 15299 } 15300 15301 /* 15302 * describe [-v] [-t] [pg/prop] 15303 */ 15304 int 15305 lscf_describe(uu_list_t *args, int hasargs) 15306 { 15307 int ret = 0; 15308 size_t i; 15309 int argc; 15310 char **argv = NULL; 15311 string_list_t *slp; 15312 int do_verbose = 0; 15313 int do_templates = 0; 15314 char *pattern = NULL; 15315 15316 lscf_prep_hndl(); 15317 15318 if (hasargs != 0) { 15319 argc = uu_list_numnodes(args); 15320 if (argc < 1) 15321 goto usage; 15322 15323 argv = calloc(argc + 1, sizeof (char *)); 15324 if (argv == NULL) 15325 uu_die(gettext("Out of memory.\n")); 15326 15327 for (slp = uu_list_first(args), i = 0; 15328 slp != NULL; 15329 slp = uu_list_next(args, slp), ++i) 15330 argv[i] = slp->str; 15331 15332 argv[i] = NULL; 15333 15334 /* 15335 * We start optind = 0 because our list of arguments 15336 * starts at argv[0] 15337 */ 15338 optind = 0; 15339 opterr = 0; 15340 for (;;) { 15341 ret = getopt(argc, argv, "vt"); 15342 if (ret == -1) 15343 break; 15344 15345 switch (ret) { 15346 case 'v': 15347 do_verbose = 1; 15348 break; 15349 15350 case 't': 15351 do_templates = 1; 15352 break; 15353 15354 case '?': 15355 goto usage; 15356 15357 default: 15358 bad_error("getopt", ret); 15359 } 15360 } 15361 15362 pattern = argv[optind]; 15363 } 15364 15365 if (cur_inst == NULL && cur_svc == NULL) { 15366 semerr(emsg_entity_not_selected); 15367 ret = -1; 15368 goto out; 15369 } 15370 15371 /* 15372 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15373 * output if their last parameter is set to 2. Less information is 15374 * produced if the parameter is set to 1. 15375 */ 15376 if (pattern == NULL) { 15377 if (do_verbose == 1) 15378 list_entity_tmpl(2); 15379 else 15380 list_entity_tmpl(1); 15381 } 15382 15383 if (do_templates == 0) { 15384 if (do_verbose == 1) 15385 listprop(pattern, 0, 2); 15386 else 15387 listprop(pattern, 0, 1); 15388 } else { 15389 if (do_verbose == 1) 15390 listtmpl(pattern, 2); 15391 else 15392 listtmpl(pattern, 1); 15393 } 15394 15395 ret = 0; 15396 out: 15397 if (argv != NULL) 15398 free(argv); 15399 return (ret); 15400 usage: 15401 ret = -2; 15402 goto out; 15403 } 15404 15405 #define PARAM_ACTIVE ((const char *) "active") 15406 #define PARAM_INACTIVE ((const char *) "inactive") 15407 #define PARAM_SMTP_TO ((const char *) "to") 15408 15409 /* 15410 * tokenize() 15411 * Breaks down the string according to the tokens passed. 15412 * Caller is responsible for freeing array of pointers returned. 15413 * Returns NULL on failure 15414 */ 15415 char ** 15416 tokenize(char *str, const char *sep) 15417 { 15418 char *token, *lasts; 15419 char **buf; 15420 int n = 0; /* number of elements */ 15421 int size = 8; /* size of the array (initial) */ 15422 15423 buf = safe_malloc(size * sizeof (char *)); 15424 15425 for (token = strtok_r(str, sep, &lasts); token != NULL; 15426 token = strtok_r(NULL, sep, &lasts), ++n) { 15427 if (n + 1 >= size) { 15428 size *= 2; 15429 if ((buf = realloc(buf, size * sizeof (char *))) == 15430 NULL) { 15431 uu_die(gettext("Out of memory")); 15432 } 15433 } 15434 buf[n] = token; 15435 } 15436 /* NULL terminate the pointer array */ 15437 buf[n] = NULL; 15438 15439 return (buf); 15440 } 15441 15442 int32_t 15443 check_tokens(char **p) 15444 { 15445 int32_t smf = 0; 15446 int32_t fma = 0; 15447 15448 while (*p) { 15449 int32_t t = string_to_tset(*p); 15450 15451 if (t == 0) { 15452 if (is_fma_token(*p) == 0) 15453 return (INVALID_TOKENS); 15454 fma = 1; /* this token is an fma event */ 15455 } else { 15456 smf |= t; 15457 } 15458 15459 if (smf != 0 && fma == 1) 15460 return (MIXED_TOKENS); 15461 ++p; 15462 } 15463 15464 if (smf > 0) 15465 return (smf); 15466 else if (fma == 1) 15467 return (FMA_TOKENS); 15468 15469 return (INVALID_TOKENS); 15470 } 15471 15472 static int 15473 get_selection_str(char *fmri, size_t sz) 15474 { 15475 if (g_hndl == NULL) { 15476 semerr(emsg_entity_not_selected); 15477 return (-1); 15478 } else if (cur_level != NULL) { 15479 semerr(emsg_invalid_for_snapshot); 15480 return (-1); 15481 } else { 15482 lscf_get_selection_str(fmri, sz); 15483 } 15484 15485 return (0); 15486 } 15487 15488 void 15489 lscf_delnotify(const char *set, int global) 15490 { 15491 char *str = strdup(set); 15492 char **pgs; 15493 char **p; 15494 int32_t tset; 15495 char *fmri = NULL; 15496 15497 if (str == NULL) 15498 uu_die(gettext("Out of memory.\n")); 15499 15500 pgs = tokenize(str, ","); 15501 15502 if ((tset = check_tokens(pgs)) > 0) { 15503 size_t sz = max_scf_fmri_len + 1; 15504 15505 fmri = safe_malloc(sz); 15506 if (global) { 15507 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15508 } else if (get_selection_str(fmri, sz) != 0) { 15509 goto out; 15510 } 15511 15512 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri, 15513 tset) != SCF_SUCCESS) { 15514 uu_warn(gettext("Failed smf_notify_del_params: %s\n"), 15515 scf_strerror(scf_error())); 15516 } 15517 } else if (tset == FMA_TOKENS) { 15518 if (global) { 15519 semerr(gettext("Can't use option '-g' with FMA event " 15520 "definitions\n")); 15521 goto out; 15522 } 15523 15524 for (p = pgs; *p; ++p) { 15525 if (smf_notify_del_params(de_tag(*p), NULL, 0) != 15526 SCF_SUCCESS) { 15527 uu_warn(gettext("Failed for \"%s\": %s\n"), *p, 15528 scf_strerror(scf_error())); 15529 goto out; 15530 } 15531 } 15532 } else if (tset == MIXED_TOKENS) { 15533 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15534 goto out; 15535 } else { 15536 uu_die(gettext("Invalid input.\n")); 15537 } 15538 15539 out: 15540 free(fmri); 15541 free(pgs); 15542 free(str); 15543 } 15544 15545 void 15546 lscf_listnotify(const char *set, int global) 15547 { 15548 char *str = safe_strdup(set); 15549 char **pgs; 15550 char **p; 15551 int32_t tset; 15552 nvlist_t *nvl; 15553 char *fmri = NULL; 15554 15555 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 15556 uu_die(gettext("Out of memory.\n")); 15557 15558 pgs = tokenize(str, ","); 15559 15560 if ((tset = check_tokens(pgs)) > 0) { 15561 size_t sz = max_scf_fmri_len + 1; 15562 15563 fmri = safe_malloc(sz); 15564 if (global) { 15565 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15566 } else if (get_selection_str(fmri, sz) != 0) { 15567 goto out; 15568 } 15569 15570 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) != 15571 SCF_SUCCESS) { 15572 if (scf_error() != SCF_ERROR_NOT_FOUND && 15573 scf_error() != SCF_ERROR_DELETED) 15574 uu_warn(gettext( 15575 "Failed listnotify: %s\n"), 15576 scf_strerror(scf_error())); 15577 goto out; 15578 } 15579 15580 listnotify_print(nvl, NULL); 15581 } else if (tset == FMA_TOKENS) { 15582 if (global) { 15583 semerr(gettext("Can't use option '-g' with FMA event " 15584 "definitions\n")); 15585 goto out; 15586 } 15587 15588 for (p = pgs; *p; ++p) { 15589 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) != 15590 SCF_SUCCESS) { 15591 /* 15592 * if the preferences have just been deleted 15593 * or does not exist, just skip. 15594 */ 15595 if (scf_error() == SCF_ERROR_NOT_FOUND || 15596 scf_error() == SCF_ERROR_DELETED) 15597 continue; 15598 uu_warn(gettext( 15599 "Failed listnotify: %s\n"), 15600 scf_strerror(scf_error())); 15601 goto out; 15602 } 15603 listnotify_print(nvl, re_tag(*p)); 15604 } 15605 } else if (tset == MIXED_TOKENS) { 15606 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15607 goto out; 15608 } else { 15609 semerr(gettext("Invalid input.\n")); 15610 } 15611 15612 out: 15613 nvlist_free(nvl); 15614 free(fmri); 15615 free(pgs); 15616 free(str); 15617 } 15618 15619 static char * 15620 strip_quotes_and_blanks(char *s) 15621 { 15622 char *start = s; 15623 char *end = strrchr(s, '\"'); 15624 15625 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') { 15626 start = s + 1; 15627 while (isblank(*start)) 15628 start++; 15629 while (isblank(*(end - 1)) && end > start) { 15630 end--; 15631 } 15632 *end = '\0'; 15633 } 15634 15635 return (start); 15636 } 15637 15638 static int 15639 set_active(nvlist_t *mech, const char *hier_part) 15640 { 15641 boolean_t b; 15642 15643 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) { 15644 b = B_TRUE; 15645 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) { 15646 b = B_FALSE; 15647 } else { 15648 return (-1); 15649 } 15650 15651 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0) 15652 uu_die(gettext("Out of memory.\n")); 15653 15654 return (0); 15655 } 15656 15657 static int 15658 add_snmp_params(nvlist_t *mech, char *hier_part) 15659 { 15660 return (set_active(mech, hier_part)); 15661 } 15662 15663 static int 15664 add_syslog_params(nvlist_t *mech, char *hier_part) 15665 { 15666 return (set_active(mech, hier_part)); 15667 } 15668 15669 /* 15670 * add_mailto_paramas() 15671 * parse the hier_part of mailto URI 15672 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]] 15673 * or mailto:{[active]|inactive} 15674 */ 15675 static int 15676 add_mailto_params(nvlist_t *mech, char *hier_part) 15677 { 15678 const char *tok = "?&"; 15679 char *p; 15680 char *lasts; 15681 char *param; 15682 char *val; 15683 15684 /* 15685 * If the notification parametes are in the form of 15686 * 15687 * malito:{[active]|inactive} 15688 * 15689 * we set the property accordingly and return. 15690 * Otherwise, we make the notification type active and 15691 * process the hier_part. 15692 */ 15693 if (set_active(mech, hier_part) == 0) 15694 return (0); 15695 else if (set_active(mech, PARAM_ACTIVE) != 0) 15696 return (-1); 15697 15698 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) { 15699 /* 15700 * sanity check: we only get here if hier_part = "", but 15701 * that's handled by set_active 15702 */ 15703 uu_die("strtok_r"); 15704 } 15705 15706 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0) 15707 uu_die(gettext("Out of memory.\n")); 15708 15709 while ((p = strtok_r(NULL, tok, &lasts)) != NULL) 15710 if ((param = strtok_r(p, "=", &val)) != NULL) 15711 if (nvlist_add_string(mech, param, val) != 0) 15712 uu_die(gettext("Out of memory.\n")); 15713 15714 return (0); 15715 } 15716 15717 static int 15718 uri_split(char *uri, char **scheme, char **hier_part) 15719 { 15720 int r = -1; 15721 15722 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL || 15723 *hier_part == NULL) { 15724 semerr(gettext("'%s' is not an URI\n"), uri); 15725 return (r); 15726 } 15727 15728 if ((r = check_uri_scheme(*scheme)) < 0) { 15729 semerr(gettext("Unkown URI scheme: %s\n"), *scheme); 15730 return (r); 15731 } 15732 15733 return (r); 15734 } 15735 15736 static int 15737 process_uri(nvlist_t *params, char *uri) 15738 { 15739 char *scheme; 15740 char *hier_part; 15741 nvlist_t *mech; 15742 int index; 15743 int r; 15744 15745 if ((index = uri_split(uri, &scheme, &hier_part)) < 0) 15746 return (-1); 15747 15748 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0) 15749 uu_die(gettext("Out of memory.\n")); 15750 15751 switch (index) { 15752 case 0: 15753 /* error messages displayed by called function */ 15754 r = add_mailto_params(mech, hier_part); 15755 break; 15756 15757 case 1: 15758 if ((r = add_snmp_params(mech, hier_part)) != 0) 15759 semerr(gettext("Not valid parameters: '%s'\n"), 15760 hier_part); 15761 break; 15762 15763 case 2: 15764 if ((r = add_syslog_params(mech, hier_part)) != 0) 15765 semerr(gettext("Not valid parameters: '%s'\n"), 15766 hier_part); 15767 break; 15768 15769 default: 15770 r = -1; 15771 } 15772 15773 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol, 15774 mech) != 0) 15775 uu_die(gettext("Out of memory.\n")); 15776 15777 nvlist_free(mech); 15778 return (r); 15779 } 15780 15781 static int 15782 set_params(nvlist_t *params, char **p) 15783 { 15784 char *uri; 15785 15786 if (p == NULL) 15787 /* sanity check */ 15788 uu_die("set_params"); 15789 15790 while (*p) { 15791 uri = strip_quotes_and_blanks(*p); 15792 if (process_uri(params, uri) != 0) 15793 return (-1); 15794 15795 ++p; 15796 } 15797 15798 return (0); 15799 } 15800 15801 static int 15802 setnotify(const char *e, char **p, int global) 15803 { 15804 char *str = safe_strdup(e); 15805 char **events; 15806 int32_t tset; 15807 int r = -1; 15808 nvlist_t *nvl, *params; 15809 char *fmri = NULL; 15810 15811 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 15812 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 || 15813 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 15814 SCF_NOTIFY_PARAMS_VERSION) != 0) 15815 uu_die(gettext("Out of memory.\n")); 15816 15817 events = tokenize(str, ","); 15818 15819 if ((tset = check_tokens(events)) > 0) { 15820 /* SMF state transitions parameters */ 15821 size_t sz = max_scf_fmri_len + 1; 15822 15823 fmri = safe_malloc(sz); 15824 if (global) { 15825 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15826 } else if (get_selection_str(fmri, sz) != 0) { 15827 goto out; 15828 } 15829 15830 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 || 15831 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0) 15832 uu_die(gettext("Out of memory.\n")); 15833 15834 if ((r = set_params(params, p)) == 0) { 15835 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, 15836 params) != 0) 15837 uu_die(gettext("Out of memory.\n")); 15838 15839 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS, 15840 nvl) != SCF_SUCCESS) { 15841 r = -1; 15842 uu_warn(gettext( 15843 "Failed smf_notify_set_params(3SCF): %s\n"), 15844 scf_strerror(scf_error())); 15845 } 15846 } 15847 } else if (tset == FMA_TOKENS) { 15848 /* FMA event parameters */ 15849 if (global) { 15850 semerr(gettext("Can't use option '-g' with FMA event " 15851 "definitions\n")); 15852 goto out; 15853 } 15854 15855 if ((r = set_params(params, p)) != 0) 15856 goto out; 15857 15858 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0) 15859 uu_die(gettext("Out of memory.\n")); 15860 15861 while (*events) { 15862 if (smf_notify_set_params(de_tag(*events), nvl) != 15863 SCF_SUCCESS) 15864 uu_warn(gettext( 15865 "Failed smf_notify_set_params(3SCF) for " 15866 "event %s: %s\n"), *events, 15867 scf_strerror(scf_error())); 15868 events++; 15869 } 15870 } else if (tset == MIXED_TOKENS) { 15871 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15872 } else { 15873 /* Sanity check */ 15874 uu_die(gettext("Invalid input.\n")); 15875 } 15876 15877 out: 15878 nvlist_free(nvl); 15879 nvlist_free(params); 15880 free(fmri); 15881 free(str); 15882 15883 return (r); 15884 } 15885 15886 int 15887 lscf_setnotify(uu_list_t *args) 15888 { 15889 int argc; 15890 char **argv = NULL; 15891 string_list_t *slp; 15892 int global; 15893 char *events; 15894 char **p; 15895 int i; 15896 int ret; 15897 15898 if ((argc = uu_list_numnodes(args)) < 2) 15899 goto usage; 15900 15901 argv = calloc(argc + 1, sizeof (char *)); 15902 if (argv == NULL) 15903 uu_die(gettext("Out of memory.\n")); 15904 15905 for (slp = uu_list_first(args), i = 0; 15906 slp != NULL; 15907 slp = uu_list_next(args, slp), ++i) 15908 argv[i] = slp->str; 15909 15910 argv[i] = NULL; 15911 15912 if (strcmp(argv[0], "-g") == 0) { 15913 global = 1; 15914 events = argv[1]; 15915 p = argv + 2; 15916 } else { 15917 global = 0; 15918 events = argv[0]; 15919 p = argv + 1; 15920 } 15921 15922 ret = setnotify(events, p, global); 15923 15924 out: 15925 free(argv); 15926 return (ret); 15927 15928 usage: 15929 ret = -2; 15930 goto out; 15931 } 15932 15933 /* 15934 * Creates a list of instance name strings associated with a service. If 15935 * wohandcrafted flag is set, get only instances that have a last-import 15936 * snapshot, instances that were imported via svccfg. 15937 */ 15938 static uu_list_t * 15939 create_instance_list(scf_service_t *svc, int wohandcrafted) 15940 { 15941 scf_snapshot_t *snap = NULL; 15942 scf_instance_t *inst; 15943 scf_iter_t *inst_iter; 15944 uu_list_t *instances; 15945 char *instname; 15946 int r; 15947 15948 inst_iter = scf_iter_create(g_hndl); 15949 inst = scf_instance_create(g_hndl); 15950 if (inst_iter == NULL || inst == NULL) { 15951 uu_warn(gettext("Could not create instance or iterator\n")); 15952 scfdie(); 15953 } 15954 15955 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 15956 return (instances); 15957 15958 if (scf_iter_service_instances(inst_iter, svc) != 0) { 15959 switch (scf_error()) { 15960 case SCF_ERROR_CONNECTION_BROKEN: 15961 case SCF_ERROR_DELETED: 15962 uu_list_destroy(instances); 15963 instances = NULL; 15964 goto out; 15965 15966 case SCF_ERROR_HANDLE_MISMATCH: 15967 case SCF_ERROR_NOT_BOUND: 15968 case SCF_ERROR_NOT_SET: 15969 default: 15970 bad_error("scf_iter_service_instances", scf_error()); 15971 } 15972 } 15973 15974 instname = safe_malloc(max_scf_name_len + 1); 15975 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 15976 if (r == -1) { 15977 (void) uu_warn(gettext("Unable to iterate through " 15978 "instances to create instance list : %s\n"), 15979 scf_strerror(scf_error())); 15980 15981 uu_list_destroy(instances); 15982 instances = NULL; 15983 goto out; 15984 } 15985 15986 /* 15987 * If the instance does not have a last-import snapshot 15988 * then do not add it to the list as it is a hand-crafted 15989 * instance that should not be managed. 15990 */ 15991 if (wohandcrafted) { 15992 if (snap == NULL && 15993 (snap = scf_snapshot_create(g_hndl)) == NULL) { 15994 uu_warn(gettext("Unable to create snapshot " 15995 "entity\n")); 15996 scfdie(); 15997 } 15998 15999 if (scf_instance_get_snapshot(inst, 16000 snap_lastimport, snap) != 0) { 16001 switch (scf_error()) { 16002 case SCF_ERROR_NOT_FOUND : 16003 case SCF_ERROR_DELETED: 16004 continue; 16005 16006 case SCF_ERROR_CONNECTION_BROKEN: 16007 uu_list_destroy(instances); 16008 instances = NULL; 16009 goto out; 16010 16011 case SCF_ERROR_HANDLE_MISMATCH: 16012 case SCF_ERROR_NOT_BOUND: 16013 case SCF_ERROR_NOT_SET: 16014 default: 16015 bad_error("scf_iter_service_instances", 16016 scf_error()); 16017 } 16018 } 16019 } 16020 16021 if (scf_instance_get_name(inst, instname, 16022 max_scf_name_len + 1) < 0) { 16023 switch (scf_error()) { 16024 case SCF_ERROR_NOT_FOUND : 16025 continue; 16026 16027 case SCF_ERROR_CONNECTION_BROKEN: 16028 case SCF_ERROR_DELETED: 16029 uu_list_destroy(instances); 16030 instances = NULL; 16031 goto out; 16032 16033 case SCF_ERROR_HANDLE_MISMATCH: 16034 case SCF_ERROR_NOT_BOUND: 16035 case SCF_ERROR_NOT_SET: 16036 default: 16037 bad_error("scf_iter_service_instances", 16038 scf_error()); 16039 } 16040 } 16041 16042 add_string(instances, instname); 16043 } 16044 16045 out: 16046 if (snap) 16047 scf_snapshot_destroy(snap); 16048 16049 scf_instance_destroy(inst); 16050 scf_iter_destroy(inst_iter); 16051 free(instname); 16052 return (instances); 16053 } 16054 16055 /* 16056 * disable an instance but wait for the instance to 16057 * move out of the running state. 16058 * 16059 * Returns 0 : if the instance did not disable 16060 * Returns non-zero : if the instance disabled. 16061 * 16062 */ 16063 static int 16064 disable_instance(scf_instance_t *instance) 16065 { 16066 char *fmribuf; 16067 int enabled = 10000; 16068 16069 if (inst_is_running(instance)) { 16070 fmribuf = safe_malloc(max_scf_name_len + 1); 16071 if (scf_instance_to_fmri(instance, fmribuf, 16072 max_scf_name_len + 1) < 0) { 16073 free(fmribuf); 16074 return (0); 16075 } 16076 16077 /* 16078 * If the instance cannot be disabled then return 16079 * failure to disable and let the caller decide 16080 * if that is of importance. 16081 */ 16082 if (smf_disable_instance(fmribuf, 0) != 0) { 16083 free(fmribuf); 16084 return (0); 16085 } 16086 16087 while (enabled) { 16088 if (!inst_is_running(instance)) 16089 break; 16090 16091 (void) poll(NULL, 0, 5); 16092 enabled = enabled - 5; 16093 } 16094 16095 free(fmribuf); 16096 } 16097 16098 return (enabled); 16099 } 16100 16101 /* 16102 * Function to compare two service_manifest structures. 16103 */ 16104 /* ARGSUSED2 */ 16105 static int 16106 service_manifest_compare(const void *left, const void *right, void *unused) 16107 { 16108 service_manifest_t *l = (service_manifest_t *)left; 16109 service_manifest_t *r = (service_manifest_t *)right; 16110 int rc; 16111 16112 rc = strcmp(l->servicename, r->servicename); 16113 16114 return (rc); 16115 } 16116 16117 /* 16118 * Look for the provided service in the service to manifest 16119 * tree. If the service exists, and a manifest was provided 16120 * then add the manifest to that service. If the service 16121 * does not exist, then add the service and manifest to the 16122 * list. 16123 * 16124 * If the manifest is NULL, return the element if found. If 16125 * the service is not found return NULL. 16126 */ 16127 service_manifest_t * 16128 find_add_svc_mfst(const char *svnbuf, const char *mfst) 16129 { 16130 service_manifest_t elem; 16131 service_manifest_t *fnelem; 16132 uu_avl_index_t marker; 16133 16134 elem.servicename = svnbuf; 16135 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 16136 16137 if (mfst) { 16138 if (fnelem) { 16139 add_string(fnelem->mfstlist, strdup(mfst)); 16140 } else { 16141 fnelem = safe_malloc(sizeof (*fnelem)); 16142 fnelem->servicename = safe_strdup(svnbuf); 16143 if ((fnelem->mfstlist = 16144 uu_list_create(string_pool, NULL, 0)) == NULL) 16145 uu_die(gettext("Could not create property " 16146 "list: %s\n"), uu_strerror(uu_error())); 16147 16148 add_string(fnelem->mfstlist, safe_strdup(mfst)); 16149 16150 uu_avl_insert(service_manifest_tree, fnelem, marker); 16151 } 16152 } 16153 16154 return (fnelem); 16155 } 16156 16157 /* 16158 * Create the service to manifest avl tree. 16159 * 16160 * Walk each of the manifests currently installed in the supported 16161 * directories, /lib/svc/manifests and /var/svc/manifests. For 16162 * each of the manifests, inventory the services and add them to 16163 * the tree. 16164 * 16165 * Code that calls this function should make sure fileystem/minimal is online, 16166 * /var is available, since this function walks the /var/svc/manifest directory. 16167 */ 16168 static void 16169 create_manifest_tree(void) 16170 { 16171 manifest_info_t **entry; 16172 manifest_info_t **manifests; 16173 uu_list_walk_t *svcs; 16174 bundle_t *b; 16175 entity_t *mfsvc; 16176 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 16177 int c, status; 16178 16179 if (service_manifest_pool) 16180 return; 16181 16182 /* 16183 * Create the list pool for the service manifest list 16184 */ 16185 service_manifest_pool = uu_avl_pool_create("service_manifest", 16186 sizeof (service_manifest_t), 16187 offsetof(service_manifest_t, svcmfst_node), 16188 service_manifest_compare, UU_DEFAULT); 16189 if (service_manifest_pool == NULL) 16190 uu_die(gettext("service_manifest pool creation failed: %s\n"), 16191 uu_strerror(uu_error())); 16192 16193 /* 16194 * Create the list 16195 */ 16196 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 16197 UU_DEFAULT); 16198 if (service_manifest_tree == NULL) 16199 uu_die(gettext("service_manifest tree creation failed: %s\n"), 16200 uu_strerror(uu_error())); 16201 16202 /* 16203 * Walk the manifests adding the service(s) from each manifest. 16204 * 16205 * If a service already exists add the manifest to the manifest 16206 * list for that service. This covers the case of a service that 16207 * is supported by multiple manifest files. 16208 */ 16209 for (c = 0; dirs[c]; c++) { 16210 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT); 16211 if (status < 0) { 16212 uu_warn(gettext("file tree walk of %s encountered " 16213 "error %s\n"), dirs[c], strerror(errno)); 16214 16215 uu_avl_destroy(service_manifest_tree); 16216 service_manifest_tree = NULL; 16217 return; 16218 } 16219 16220 /* 16221 * If a manifest that was in the list is not found 16222 * then skip and go to the next manifest file. 16223 */ 16224 if (manifests != NULL) { 16225 for (entry = manifests; *entry != NULL; entry++) { 16226 b = internal_bundle_new(); 16227 if (lxml_get_bundle_file(b, (*entry)->mi_path, 16228 SVCCFG_OP_IMPORT) != 0) { 16229 internal_bundle_free(b); 16230 continue; 16231 } 16232 16233 svcs = uu_list_walk_start(b->sc_bundle_services, 16234 0); 16235 if (svcs == NULL) { 16236 internal_bundle_free(b); 16237 continue; 16238 } 16239 16240 while ((mfsvc = uu_list_walk_next(svcs)) != 16241 NULL) { 16242 /* Add manifest to service */ 16243 (void) find_add_svc_mfst(mfsvc->sc_name, 16244 (*entry)->mi_path); 16245 } 16246 16247 uu_list_walk_end(svcs); 16248 internal_bundle_free(b); 16249 } 16250 16251 free_manifest_array(manifests); 16252 } 16253 } 16254 } 16255 16256 /* 16257 * Check the manifest history file to see 16258 * if the service was ever installed from 16259 * one of the supported directories. 16260 * 16261 * Return Values : 16262 * -1 - if there's error reading manifest history file 16263 * 1 - if the service is not found 16264 * 0 - if the service is found 16265 */ 16266 static int 16267 check_mfst_history(const char *svcname) 16268 { 16269 struct stat st; 16270 caddr_t mfsthist_start; 16271 char *svnbuf; 16272 int fd; 16273 int r = 1; 16274 16275 fd = open(MFSTHISTFILE, O_RDONLY); 16276 if (fd == -1) { 16277 uu_warn(gettext("Unable to open the history file\n")); 16278 return (-1); 16279 } 16280 16281 if (fstat(fd, &st) == -1) { 16282 uu_warn(gettext("Unable to stat the history file\n")); 16283 return (-1); 16284 } 16285 16286 mfsthist_start = mmap(0, st.st_size, PROT_READ, 16287 MAP_PRIVATE, fd, 0); 16288 16289 (void) close(fd); 16290 if (mfsthist_start == MAP_FAILED || 16291 *(mfsthist_start + st.st_size) != '\0') { 16292 (void) munmap(mfsthist_start, st.st_size); 16293 return (-1); 16294 } 16295 16296 /* 16297 * The manifest history file is a space delimited list 16298 * of service and instance to manifest linkage. Adding 16299 * a space to the end of the service name so to get only 16300 * the service that is being searched for. 16301 */ 16302 svnbuf = uu_msprintf("%s ", svcname); 16303 if (svnbuf == NULL) 16304 uu_die(gettext("Out of memory")); 16305 16306 if (strstr(mfsthist_start, svnbuf) != NULL) 16307 r = 0; 16308 16309 (void) munmap(mfsthist_start, st.st_size); 16310 uu_free(svnbuf); 16311 return (r); 16312 } 16313 16314 /* 16315 * Take down each of the instances in the service 16316 * and remove them, then delete the service. 16317 */ 16318 static void 16319 teardown_service(scf_service_t *svc, const char *svnbuf) 16320 { 16321 scf_instance_t *instance; 16322 scf_iter_t *iter; 16323 int r; 16324 16325 safe_printf(gettext("Delete service %s as there are no " 16326 "supporting manifests\n"), svnbuf); 16327 16328 instance = scf_instance_create(g_hndl); 16329 iter = scf_iter_create(g_hndl); 16330 if (iter == NULL || instance == NULL) { 16331 uu_warn(gettext("Unable to create supporting entities to " 16332 "teardown the service\n")); 16333 uu_warn(gettext("scf error is : %s\n"), 16334 scf_strerror(scf_error())); 16335 scfdie(); 16336 } 16337 16338 if (scf_iter_service_instances(iter, svc) != 0) { 16339 switch (scf_error()) { 16340 case SCF_ERROR_CONNECTION_BROKEN: 16341 case SCF_ERROR_DELETED: 16342 goto out; 16343 16344 case SCF_ERROR_HANDLE_MISMATCH: 16345 case SCF_ERROR_NOT_BOUND: 16346 case SCF_ERROR_NOT_SET: 16347 default: 16348 bad_error("scf_iter_service_instances", 16349 scf_error()); 16350 } 16351 } 16352 16353 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 16354 if (r == -1) { 16355 uu_warn(gettext("Error - %s\n"), 16356 scf_strerror(scf_error())); 16357 goto out; 16358 } 16359 16360 (void) disable_instance(instance); 16361 } 16362 16363 /* 16364 * Delete the service... forcing the deletion in case 16365 * any of the instances did not disable. 16366 */ 16367 (void) lscf_service_delete(svc, 1); 16368 out: 16369 scf_instance_destroy(instance); 16370 scf_iter_destroy(iter); 16371 } 16372 16373 /* 16374 * Get the list of instances supported by the manifest 16375 * file. 16376 * 16377 * Return 0 if there are no instances. 16378 * 16379 * Return -1 if there are errors attempting to collect instances. 16380 * 16381 * Return the count of instances found if there are no errors. 16382 * 16383 */ 16384 static int 16385 check_instance_support(char *mfstfile, const char *svcname, 16386 uu_list_t *instances) 16387 { 16388 uu_list_walk_t *svcs, *insts; 16389 uu_list_t *ilist; 16390 bundle_t *b; 16391 entity_t *mfsvc, *mfinst; 16392 const char *svcn; 16393 int rminstcnt = 0; 16394 16395 16396 b = internal_bundle_new(); 16397 16398 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 16399 /* 16400 * Unable to process the manifest file for 16401 * instance support, so just return as 16402 * don't want to remove instances that could 16403 * not be accounted for that might exist here. 16404 */ 16405 internal_bundle_free(b); 16406 return (0); 16407 } 16408 16409 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 16410 if (svcs == NULL) { 16411 internal_bundle_free(b); 16412 return (0); 16413 } 16414 16415 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 16416 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 16417 16418 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 16419 if (strcmp(mfsvc->sc_name, svcn) == 0) 16420 break; 16421 } 16422 uu_list_walk_end(svcs); 16423 16424 if (mfsvc == NULL) { 16425 internal_bundle_free(b); 16426 return (-1); 16427 } 16428 16429 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 16430 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 16431 internal_bundle_free(b); 16432 return (0); 16433 } 16434 16435 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 16436 /* 16437 * Remove the instance from the instances list. 16438 * The unaccounted for instances will be removed 16439 * from the service once all manifests are 16440 * processed. 16441 */ 16442 (void) remove_string(instances, 16443 mfinst->sc_name); 16444 rminstcnt++; 16445 } 16446 16447 uu_list_walk_end(insts); 16448 internal_bundle_free(b); 16449 16450 return (rminstcnt); 16451 } 16452 16453 /* 16454 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 16455 * 'false' to indicate there's no manifest file(s) found for the service. 16456 */ 16457 static void 16458 svc_add_no_support(scf_service_t *svc) 16459 { 16460 char *pname; 16461 16462 /* Add no support */ 16463 cur_svc = svc; 16464 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 16465 return; 16466 16467 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 16468 if (pname == NULL) 16469 uu_die(gettext("Out of memory.\n")); 16470 16471 (void) lscf_addpropvalue(pname, "boolean:", "0"); 16472 16473 uu_free(pname); 16474 cur_svc = NULL; 16475 } 16476 16477 /* 16478 * This function handles all upgrade scenarios for a service that doesn't have 16479 * SCF_PG_MANIFESTFILES pg. The function creates and populates 16480 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 16481 * manifest(s) mapping. Manifests under supported directories are inventoried 16482 * and a property is added for each file that delivers configuration to the 16483 * service. A service that has no corresponding manifest files (deleted) are 16484 * removed from repository. 16485 * 16486 * Unsupported services: 16487 * 16488 * A service is considered unsupported if there is no corresponding manifest 16489 * in the supported directories for that service and the service isn't in the 16490 * history file list. The history file, MFSTHISTFILE, contains a list of all 16491 * services and instances that were delivered by Solaris before the introduction 16492 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 16493 * the path to the manifest file that defined the service or instance. 16494 * 16495 * Another type of unsupported services is 'handcrafted' services, 16496 * programmatically created services or services created by dependent entries 16497 * in other manifests. A handcrafted service is identified by its lack of any 16498 * instance containing last-import snapshot which is created during svccfg 16499 * import. 16500 * 16501 * This function sets a flag for unsupported services by setting services' 16502 * SCF_PG_MANIFESTFILES/support property to false. 16503 */ 16504 static void 16505 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 16506 { 16507 service_manifest_t *elem; 16508 uu_list_walk_t *mfwalk; 16509 string_list_t *mfile; 16510 uu_list_t *instances; 16511 const char *sname; 16512 char *pname; 16513 int r; 16514 16515 /* 16516 * Since there's no guarantee manifests under /var are available during 16517 * early import, don't perform any upgrade during early import. 16518 */ 16519 if (IGNORE_VAR) 16520 return; 16521 16522 if (service_manifest_tree == NULL) { 16523 create_manifest_tree(); 16524 } 16525 16526 /* 16527 * Find service's supporting manifest(s) after 16528 * stripping off the svc:/ prefix that is part 16529 * of the fmri that is not used in the service 16530 * manifest bundle list. 16531 */ 16532 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 16533 strlen(SCF_FMRI_SERVICE_PREFIX); 16534 elem = find_add_svc_mfst(sname, NULL); 16535 if (elem == NULL) { 16536 16537 /* 16538 * A handcrafted service, one that has no instance containing 16539 * last-import snapshot, should get unsupported flag. 16540 */ 16541 instances = create_instance_list(svc, 1); 16542 if (instances == NULL) { 16543 uu_warn(gettext("Unable to create instance list %s\n"), 16544 svcname); 16545 return; 16546 } 16547 16548 if (uu_list_numnodes(instances) == 0) { 16549 svc_add_no_support(svc); 16550 return; 16551 } 16552 16553 /* 16554 * If the service is in the history file, and its supporting 16555 * manifests are not found, we can safely delete the service 16556 * because its manifests are removed from the system. 16557 * 16558 * Services not found in the history file are not delivered by 16559 * Solaris and/or delivered outside supported directories, set 16560 * unsupported flag for these services. 16561 */ 16562 r = check_mfst_history(svcname); 16563 if (r == -1) 16564 return; 16565 16566 if (r) { 16567 /* Set unsupported flag for service */ 16568 svc_add_no_support(svc); 16569 } else { 16570 /* Delete the service */ 16571 teardown_service(svc, svcname); 16572 } 16573 16574 return; 16575 } 16576 16577 /* 16578 * Walk through the list of manifests and add them 16579 * to the service. 16580 * 16581 * Create a manifestfiles pg and add the property. 16582 */ 16583 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 16584 if (mfwalk == NULL) 16585 return; 16586 16587 cur_svc = svc; 16588 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 16589 if (r != 0) { 16590 cur_svc = NULL; 16591 return; 16592 } 16593 16594 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 16595 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16596 mhash_filename_to_propname(mfile->str, 0)); 16597 if (pname == NULL) 16598 uu_die(gettext("Out of memory.\n")); 16599 16600 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 16601 uu_free(pname); 16602 } 16603 uu_list_walk_end(mfwalk); 16604 16605 cur_svc = NULL; 16606 } 16607 16608 /* 16609 * Take a service and process the manifest file entires to see if 16610 * there is continued support for the service and instances. If 16611 * not cleanup as appropriate. 16612 * 16613 * If a service does not have a manifest files entry flag it for 16614 * upgrade and return. 16615 * 16616 * For each manifestfiles property check if the manifest file is 16617 * under the supported /lib/svc/manifest or /var/svc/manifest path 16618 * and if not then return immediately as this service is not supported 16619 * by the cleanup mechanism and should be ignored. 16620 * 16621 * For each manifest file that is supported, check to see if the 16622 * file exists. If not then remove the manifest file property 16623 * from the service and the smf/manifest hash table. If the manifest 16624 * file exists then verify that it supports the instances that are 16625 * part of the service. 16626 * 16627 * Once all manifest files have been accounted for remove any instances 16628 * that are no longer supported in the service. 16629 * 16630 * Return values : 16631 * 0 - Successfully processed the service 16632 * non-zero - failed to process the service 16633 * 16634 * On most errors, will just return to wait and get the next service, 16635 * unless in case of unable to create the needed structures which is 16636 * most likely a fatal error that is not going to be recoverable. 16637 */ 16638 int 16639 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 16640 { 16641 struct mpg_mfile *mpntov; 16642 struct mpg_mfile **mpvarry = NULL; 16643 scf_service_t *svc; 16644 scf_propertygroup_t *mpg; 16645 scf_property_t *mp; 16646 scf_value_t *mv; 16647 scf_iter_t *mi; 16648 scf_instance_t *instance; 16649 uu_list_walk_t *insts; 16650 uu_list_t *instances = NULL; 16651 boolean_t activity = (boolean_t)act; 16652 char *mpnbuf; 16653 char *mpvbuf; 16654 char *pgpropbuf; 16655 int mfstcnt, rminstct, instct, mfstmax; 16656 int index; 16657 int r = 0; 16658 16659 assert(g_hndl != NULL); 16660 assert(wip->svc != NULL); 16661 assert(wip->fmri != NULL); 16662 16663 svc = wip->svc; 16664 16665 mpg = scf_pg_create(g_hndl); 16666 mp = scf_property_create(g_hndl); 16667 mi = scf_iter_create(g_hndl); 16668 mv = scf_value_create(g_hndl); 16669 instance = scf_instance_create(g_hndl); 16670 16671 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 16672 instance == NULL) { 16673 uu_warn(gettext("Unable to create the supporting entities\n")); 16674 uu_warn(gettext("scf error is : %s\n"), 16675 scf_strerror(scf_error())); 16676 scfdie(); 16677 } 16678 16679 /* 16680 * Get the manifestfiles property group to be parsed for 16681 * files existence. 16682 */ 16683 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 16684 switch (scf_error()) { 16685 case SCF_ERROR_NOT_FOUND: 16686 upgrade_svc_mfst_connection(svc, wip->fmri); 16687 break; 16688 case SCF_ERROR_DELETED: 16689 case SCF_ERROR_CONNECTION_BROKEN: 16690 goto out; 16691 16692 case SCF_ERROR_HANDLE_MISMATCH: 16693 case SCF_ERROR_NOT_BOUND: 16694 case SCF_ERROR_NOT_SET: 16695 default: 16696 bad_error("scf_iter_pg_properties", 16697 scf_error()); 16698 } 16699 16700 goto out; 16701 } 16702 16703 /* 16704 * Iterate through each of the manifestfiles properties 16705 * to determine what manifestfiles are available. 16706 * 16707 * If a manifest file is supported then increment the 16708 * count and therefore the service is safe. 16709 */ 16710 if (scf_iter_pg_properties(mi, mpg) != 0) { 16711 switch (scf_error()) { 16712 case SCF_ERROR_DELETED: 16713 case SCF_ERROR_CONNECTION_BROKEN: 16714 goto out; 16715 16716 case SCF_ERROR_HANDLE_MISMATCH: 16717 case SCF_ERROR_NOT_BOUND: 16718 case SCF_ERROR_NOT_SET: 16719 default: 16720 bad_error("scf_iter_pg_properties", 16721 scf_error()); 16722 } 16723 } 16724 16725 mfstcnt = 0; 16726 mfstmax = MFSTFILE_MAX; 16727 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 16728 while ((r = scf_iter_next_property(mi, mp)) != 0) { 16729 if (r == -1) 16730 bad_error(gettext("Unable to iterate through " 16731 "manifestfiles properties : %s"), 16732 scf_error()); 16733 16734 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 16735 mpnbuf = safe_malloc(max_scf_name_len + 1); 16736 mpvbuf = safe_malloc(max_scf_value_len + 1); 16737 mpntov->mpg = mpnbuf; 16738 mpntov->mfile = mpvbuf; 16739 mpntov->access = 1; 16740 if (scf_property_get_name(mp, mpnbuf, 16741 max_scf_name_len + 1) < 0) { 16742 uu_warn(gettext("Unable to get manifest file " 16743 "property : %s\n"), 16744 scf_strerror(scf_error())); 16745 16746 switch (scf_error()) { 16747 case SCF_ERROR_DELETED: 16748 case SCF_ERROR_CONNECTION_BROKEN: 16749 r = scferror2errno(scf_error()); 16750 goto out_free; 16751 16752 case SCF_ERROR_HANDLE_MISMATCH: 16753 case SCF_ERROR_NOT_BOUND: 16754 case SCF_ERROR_NOT_SET: 16755 default: 16756 bad_error("scf_iter_pg_properties", 16757 scf_error()); 16758 } 16759 } 16760 16761 /* 16762 * The support property is a boolean value that indicates 16763 * if the service is supported for manifest file deletion. 16764 * Currently at this time there is no code that sets this 16765 * value to true. So while we could just let this be caught 16766 * by the support check below, in the future this by be set 16767 * to true and require processing. So for that, go ahead 16768 * and check here, and just return if false. Otherwise, 16769 * fall through expecting that other support checks will 16770 * handle the entries. 16771 */ 16772 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 16773 uint8_t support; 16774 16775 if (scf_property_get_value(mp, mv) != 0 || 16776 scf_value_get_boolean(mv, &support) != 0) { 16777 uu_warn(gettext("Unable to get the manifest " 16778 "support value: %s\n"), 16779 scf_strerror(scf_error())); 16780 16781 switch (scf_error()) { 16782 case SCF_ERROR_DELETED: 16783 case SCF_ERROR_CONNECTION_BROKEN: 16784 r = scferror2errno(scf_error()); 16785 goto out_free; 16786 16787 case SCF_ERROR_HANDLE_MISMATCH: 16788 case SCF_ERROR_NOT_BOUND: 16789 case SCF_ERROR_NOT_SET: 16790 default: 16791 bad_error("scf_iter_pg_properties", 16792 scf_error()); 16793 } 16794 } 16795 16796 if (support == B_FALSE) 16797 goto out_free; 16798 } 16799 16800 /* 16801 * Anything with a manifest outside of the supported 16802 * directories, immediately bail out because that makes 16803 * this service non-supported. We don't even want 16804 * to do instance processing in this case because the 16805 * instances could be part of the non-supported manifest. 16806 */ 16807 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 16808 /* 16809 * Manifest is not in /lib/svc, so we need to 16810 * consider the /var/svc case. 16811 */ 16812 if (strncmp(mpnbuf, VARSVC_PR, 16813 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 16814 /* 16815 * Either the manifest is not in /var/svc or 16816 * /var is not yet mounted. We ignore the 16817 * manifest either because it is not in a 16818 * standard location or because we cannot 16819 * currently access the manifest. 16820 */ 16821 goto out_free; 16822 } 16823 } 16824 16825 /* 16826 * Get the value to of the manifest file for this entry 16827 * for access verification and instance support 16828 * verification if it still exists. 16829 * 16830 * During Early Manifest Import if the manifest is in 16831 * /var/svc then it may not yet be available for checking 16832 * so we must determine if /var/svc is available. If not 16833 * then defer until Late Manifest Import to cleanup. 16834 */ 16835 if (scf_property_get_value(mp, mv) != 0) { 16836 uu_warn(gettext("Unable to get the manifest file " 16837 "value: %s\n"), 16838 scf_strerror(scf_error())); 16839 16840 switch (scf_error()) { 16841 case SCF_ERROR_DELETED: 16842 case SCF_ERROR_CONNECTION_BROKEN: 16843 r = scferror2errno(scf_error()); 16844 goto out_free; 16845 16846 case SCF_ERROR_HANDLE_MISMATCH: 16847 case SCF_ERROR_NOT_BOUND: 16848 case SCF_ERROR_NOT_SET: 16849 default: 16850 bad_error("scf_property_get_value", 16851 scf_error()); 16852 } 16853 } 16854 16855 if (scf_value_get_astring(mv, mpvbuf, 16856 max_scf_value_len + 1) < 0) { 16857 uu_warn(gettext("Unable to get the manifest " 16858 "file : %s\n"), 16859 scf_strerror(scf_error())); 16860 16861 switch (scf_error()) { 16862 case SCF_ERROR_DELETED: 16863 case SCF_ERROR_CONNECTION_BROKEN: 16864 r = scferror2errno(scf_error()); 16865 goto out_free; 16866 16867 case SCF_ERROR_HANDLE_MISMATCH: 16868 case SCF_ERROR_NOT_BOUND: 16869 case SCF_ERROR_NOT_SET: 16870 default: 16871 bad_error("scf_value_get_astring", 16872 scf_error()); 16873 } 16874 } 16875 16876 mpvarry[mfstcnt] = mpntov; 16877 mfstcnt++; 16878 16879 /* 16880 * Check for the need to reallocate array 16881 */ 16882 if (mfstcnt >= (mfstmax - 1)) { 16883 struct mpg_mfile **newmpvarry; 16884 16885 mfstmax = mfstmax * 2; 16886 newmpvarry = realloc(mpvarry, 16887 sizeof (struct mpg_mfile *) * mfstmax); 16888 16889 if (newmpvarry == NULL) 16890 goto out_free; 16891 16892 mpvarry = newmpvarry; 16893 } 16894 16895 mpvarry[mfstcnt] = NULL; 16896 } 16897 16898 for (index = 0; mpvarry[index]; index++) { 16899 mpntov = mpvarry[index]; 16900 16901 /* 16902 * Check to see if the manifestfile is accessable, if so hand 16903 * this service and manifestfile off to be processed for 16904 * instance support. 16905 */ 16906 mpnbuf = mpntov->mpg; 16907 mpvbuf = mpntov->mfile; 16908 if (access(mpvbuf, F_OK) != 0) { 16909 mpntov->access = 0; 16910 activity++; 16911 mfstcnt--; 16912 /* Remove the entry from the service */ 16913 cur_svc = svc; 16914 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16915 mpnbuf); 16916 if (pgpropbuf == NULL) 16917 uu_die(gettext("Out of memory.\n")); 16918 16919 lscf_delprop(pgpropbuf); 16920 cur_svc = NULL; 16921 16922 uu_free(pgpropbuf); 16923 } 16924 } 16925 16926 /* 16927 * If mfstcnt is 0, none of the manifests that supported the service 16928 * existed so remove the service. 16929 */ 16930 if (mfstcnt == 0) { 16931 teardown_service(svc, wip->fmri); 16932 16933 goto out_free; 16934 } 16935 16936 if (activity) { 16937 int nosvcsupport = 0; 16938 16939 /* 16940 * If the list of service instances is NULL then 16941 * create the list. 16942 */ 16943 instances = create_instance_list(svc, 1); 16944 if (instances == NULL) { 16945 uu_warn(gettext("Unable to create instance list %s\n"), 16946 wip->fmri); 16947 goto out_free; 16948 } 16949 16950 rminstct = uu_list_numnodes(instances); 16951 instct = rminstct; 16952 16953 for (index = 0; mpvarry[index]; index++) { 16954 mpntov = mpvarry[index]; 16955 if (mpntov->access == 0) 16956 continue; 16957 16958 mpnbuf = mpntov->mpg; 16959 mpvbuf = mpntov->mfile; 16960 r = check_instance_support(mpvbuf, wip->fmri, 16961 instances); 16962 if (r == -1) { 16963 nosvcsupport++; 16964 } else { 16965 rminstct -= r; 16966 } 16967 } 16968 16969 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 16970 teardown_service(svc, wip->fmri); 16971 16972 goto out_free; 16973 } 16974 } 16975 16976 /* 16977 * If there are instances left on the instance list, then 16978 * we must remove them. 16979 */ 16980 if (instances != NULL && uu_list_numnodes(instances)) { 16981 string_list_t *sp; 16982 16983 insts = uu_list_walk_start(instances, 0); 16984 while ((sp = uu_list_walk_next(insts)) != NULL) { 16985 /* 16986 * Remove the instance from the instances list. 16987 */ 16988 safe_printf(gettext("Delete instance %s from " 16989 "service %s\n"), sp->str, wip->fmri); 16990 if (scf_service_get_instance(svc, sp->str, 16991 instance) != SCF_SUCCESS) { 16992 (void) uu_warn("scf_error - %s\n", 16993 scf_strerror(scf_error())); 16994 16995 continue; 16996 } 16997 16998 (void) disable_instance(instance); 16999 17000 (void) lscf_instance_delete(instance, 1); 17001 } 17002 scf_instance_destroy(instance); 17003 uu_list_walk_end(insts); 17004 } 17005 17006 out_free: 17007 if (mpvarry) { 17008 struct mpg_mfile *fmpntov; 17009 17010 for (index = 0; mpvarry[index]; index++) { 17011 fmpntov = mpvarry[index]; 17012 if (fmpntov->mpg == mpnbuf) 17013 mpnbuf = NULL; 17014 free(fmpntov->mpg); 17015 17016 if (fmpntov->mfile == mpvbuf) 17017 mpvbuf = NULL; 17018 free(fmpntov->mfile); 17019 17020 if (fmpntov == mpntov) 17021 mpntov = NULL; 17022 free(fmpntov); 17023 } 17024 if (mpnbuf) 17025 free(mpnbuf); 17026 if (mpvbuf) 17027 free(mpvbuf); 17028 if (mpntov) 17029 free(mpntov); 17030 17031 free(mpvarry); 17032 } 17033 out: 17034 scf_pg_destroy(mpg); 17035 scf_property_destroy(mp); 17036 scf_iter_destroy(mi); 17037 scf_value_destroy(mv); 17038 17039 return (0); 17040 } 17041 17042 /* 17043 * Take the service and search for the manifestfiles property 17044 * in each of the property groups. If the manifest file 17045 * associated with the property does not exist then remove 17046 * the property group. 17047 */ 17048 int 17049 lscf_hash_cleanup() 17050 { 17051 scf_service_t *svc; 17052 scf_scope_t *scope; 17053 scf_propertygroup_t *pg; 17054 scf_property_t *prop; 17055 scf_value_t *val; 17056 scf_iter_t *iter; 17057 char *pgname = NULL; 17058 char *mfile = NULL; 17059 int r; 17060 17061 svc = scf_service_create(g_hndl); 17062 scope = scf_scope_create(g_hndl); 17063 pg = scf_pg_create(g_hndl); 17064 prop = scf_property_create(g_hndl); 17065 val = scf_value_create(g_hndl); 17066 iter = scf_iter_create(g_hndl); 17067 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 17068 svc == NULL || scope == NULL) { 17069 uu_warn(gettext("Unable to create a property group, or " 17070 "property\n")); 17071 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 17072 "pg is not NULL"); 17073 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 17074 "prop is not NULL"); 17075 uu_warn("%s\n", val == NULL ? "val is NULL" : 17076 "val is not NULL"); 17077 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 17078 "iter is not NULL"); 17079 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 17080 "svc is not NULL"); 17081 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 17082 "scope is not NULL"); 17083 uu_warn(gettext("scf error is : %s\n"), 17084 scf_strerror(scf_error())); 17085 scfdie(); 17086 } 17087 17088 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 17089 switch (scf_error()) { 17090 case SCF_ERROR_CONNECTION_BROKEN: 17091 case SCF_ERROR_NOT_FOUND: 17092 goto out; 17093 17094 case SCF_ERROR_HANDLE_MISMATCH: 17095 case SCF_ERROR_NOT_BOUND: 17096 case SCF_ERROR_INVALID_ARGUMENT: 17097 default: 17098 bad_error("scf_handle_get_scope", scf_error()); 17099 } 17100 } 17101 17102 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 17103 uu_warn(gettext("Unable to process the hash service, %s\n"), 17104 HASH_SVC); 17105 goto out; 17106 } 17107 17108 pgname = safe_malloc(max_scf_name_len + 1); 17109 mfile = safe_malloc(max_scf_value_len + 1); 17110 17111 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 17112 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 17113 scf_strerror(scf_error())); 17114 goto out; 17115 } 17116 17117 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 17118 if (r == -1) 17119 goto out; 17120 17121 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 17122 switch (scf_error()) { 17123 case SCF_ERROR_DELETED: 17124 return (ENODEV); 17125 17126 case SCF_ERROR_CONNECTION_BROKEN: 17127 return (ECONNABORTED); 17128 17129 case SCF_ERROR_NOT_SET: 17130 case SCF_ERROR_NOT_BOUND: 17131 default: 17132 bad_error("scf_pg_get_name", scf_error()); 17133 } 17134 } 17135 if (IGNORE_VAR) { 17136 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 17137 continue; 17138 } 17139 17140 /* 17141 * If unable to get the property continue as this is an 17142 * entry that has no location to check against. 17143 */ 17144 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 17145 continue; 17146 } 17147 17148 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 17149 uu_warn(gettext("Unable to get value from %s\n"), 17150 pgname); 17151 17152 switch (scf_error()) { 17153 case SCF_ERROR_DELETED: 17154 case SCF_ERROR_CONSTRAINT_VIOLATED: 17155 case SCF_ERROR_NOT_FOUND: 17156 case SCF_ERROR_NOT_SET: 17157 continue; 17158 17159 case SCF_ERROR_CONNECTION_BROKEN: 17160 r = scferror2errno(scf_error()); 17161 goto out; 17162 17163 case SCF_ERROR_HANDLE_MISMATCH: 17164 case SCF_ERROR_NOT_BOUND: 17165 default: 17166 bad_error("scf_property_get_value", 17167 scf_error()); 17168 } 17169 } 17170 17171 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) 17172 == -1) { 17173 uu_warn(gettext("Unable to get astring from %s : %s\n"), 17174 pgname, scf_strerror(scf_error())); 17175 17176 switch (scf_error()) { 17177 case SCF_ERROR_NOT_SET: 17178 case SCF_ERROR_TYPE_MISMATCH: 17179 continue; 17180 17181 default: 17182 bad_error("scf_value_get_astring", scf_error()); 17183 } 17184 } 17185 17186 if (access(mfile, F_OK) == 0) 17187 continue; 17188 17189 (void) scf_pg_delete(pg); 17190 } 17191 17192 out: 17193 scf_scope_destroy(scope); 17194 scf_service_destroy(svc); 17195 scf_pg_destroy(pg); 17196 scf_property_destroy(prop); 17197 scf_value_destroy(val); 17198 scf_iter_destroy(iter); 17199 free(pgname); 17200 free(mfile); 17201 17202 return (0); 17203 } 17204 17205 #ifndef NATIVE_BUILD 17206 /* ARGSUSED */ 17207 CPL_MATCH_FN(complete_select) 17208 { 17209 const char *arg0, *arg1, *arg1end; 17210 int word_start, err = 0, r; 17211 size_t len; 17212 char *buf; 17213 17214 lscf_prep_hndl(); 17215 17216 arg0 = line + strspn(line, " \t"); 17217 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 17218 17219 arg1 = arg0 + sizeof ("select") - 1; 17220 arg1 += strspn(arg1, " \t"); 17221 word_start = arg1 - line; 17222 17223 arg1end = arg1 + strcspn(arg1, " \t"); 17224 if (arg1end < line + word_end) 17225 return (0); 17226 17227 len = line + word_end - arg1; 17228 17229 buf = safe_malloc(max_scf_name_len + 1); 17230 17231 if (cur_snap != NULL) { 17232 return (0); 17233 } else if (cur_inst != NULL) { 17234 return (0); 17235 } else if (cur_svc != NULL) { 17236 scf_instance_t *inst; 17237 scf_iter_t *iter; 17238 17239 if ((inst = scf_instance_create(g_hndl)) == NULL || 17240 (iter = scf_iter_create(g_hndl)) == NULL) 17241 scfdie(); 17242 17243 if (scf_iter_service_instances(iter, cur_svc) != 0) 17244 scfdie(); 17245 17246 for (;;) { 17247 r = scf_iter_next_instance(iter, inst); 17248 if (r == 0) 17249 break; 17250 if (r != 1) 17251 scfdie(); 17252 17253 if (scf_instance_get_name(inst, buf, 17254 max_scf_name_len + 1) < 0) 17255 scfdie(); 17256 17257 if (strncmp(buf, arg1, len) == 0) { 17258 err = cpl_add_completion(cpl, line, word_start, 17259 word_end, buf + len, "", " "); 17260 if (err != 0) 17261 break; 17262 } 17263 } 17264 17265 scf_iter_destroy(iter); 17266 scf_instance_destroy(inst); 17267 17268 return (err); 17269 } else { 17270 scf_service_t *svc; 17271 scf_iter_t *iter; 17272 17273 assert(cur_scope != NULL); 17274 17275 if ((svc = scf_service_create(g_hndl)) == NULL || 17276 (iter = scf_iter_create(g_hndl)) == NULL) 17277 scfdie(); 17278 17279 if (scf_iter_scope_services(iter, cur_scope) != 0) 17280 scfdie(); 17281 17282 for (;;) { 17283 r = scf_iter_next_service(iter, svc); 17284 if (r == 0) 17285 break; 17286 if (r != 1) 17287 scfdie(); 17288 17289 if (scf_service_get_name(svc, buf, 17290 max_scf_name_len + 1) < 0) 17291 scfdie(); 17292 17293 if (strncmp(buf, arg1, len) == 0) { 17294 err = cpl_add_completion(cpl, line, word_start, 17295 word_end, buf + len, "", " "); 17296 if (err != 0) 17297 break; 17298 } 17299 } 17300 17301 scf_iter_destroy(iter); 17302 scf_service_destroy(svc); 17303 17304 return (err); 17305 } 17306 } 17307 17308 /* ARGSUSED */ 17309 CPL_MATCH_FN(complete_command) 17310 { 17311 uint32_t scope = 0; 17312 17313 if (cur_snap != NULL) 17314 scope = CS_SNAP; 17315 else if (cur_inst != NULL) 17316 scope = CS_INST; 17317 else if (cur_svc != NULL) 17318 scope = CS_SVC; 17319 else 17320 scope = CS_SCOPE; 17321 17322 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 17323 } 17324 #endif /* NATIVE_BUILD */ 17325