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 * Copyright 2020 Joyent, Inc. 25 * Copyright 2012 Milan Jurik. All rights reserved. 26 * Copyright 2017 RackTop Systems. 27 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 28 * Copyright 2023 Oxide Computer Company 29 */ 30 31 32 #include <alloca.h> 33 #include <assert.h> 34 #include <ctype.h> 35 #include <door.h> 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <fnmatch.h> 39 #include <inttypes.h> 40 #include <libintl.h> 41 #include <libnvpair.h> 42 #include <libscf.h> 43 #include <libscf_priv.h> 44 #include <libtecla.h> 45 #include <libuutil.h> 46 #include <limits.h> 47 #include <locale.h> 48 #include <stdarg.h> 49 #include <string.h> 50 #include <strings.h> 51 #include <time.h> 52 #include <unistd.h> 53 #include <wait.h> 54 #include <poll.h> 55 56 #include <libxml/tree.h> 57 58 #include <sys/param.h> 59 60 #include <sys/stat.h> 61 #include <sys/mman.h> 62 63 #include "svccfg.h" 64 #include "notify_params.h" 65 #include "manifest_hash.h" 66 #include "manifest_find.h" 67 68 /* The colon namespaces in each entity (each followed by a newline). */ 69 #define COLON_NAMESPACES ":properties\n" 70 71 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 72 73 /* These are characters which the lexer requires to be in double-quotes. */ 74 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 75 76 #define HASH_SIZE 16 77 #define HASH_PG_TYPE "framework" 78 #define HASH_PG_FLAGS 0 79 #define HASH_PROP "md5sum" 80 81 /* 82 * Indentation used in the output of the describe subcommand. 83 */ 84 #define TMPL_VALUE_INDENT " " 85 #define TMPL_INDENT " " 86 #define TMPL_INDENT_2X " " 87 #define TMPL_CHOICE_INDENT " " 88 89 /* 90 * Directory locations for manifests 91 */ 92 #define VARSVC_DIR "/var/svc/manifest" 93 #define LIBSVC_DIR "/lib/svc/manifest" 94 #define VARSVC_PR "var_svc_manifest" 95 #define LIBSVC_PR "lib_svc_manifest" 96 #define MFSTFILEPR "manifestfile" 97 98 #define SUPPORTPROP "support" 99 100 #define MFSTHISTFILE "/lib/svc/share/mfsthistory" 101 102 #define MFSTFILE_MAX 16 103 104 /* 105 * These are the classes of elements which may appear as children of service 106 * or instance elements in XML manifests. 107 */ 108 struct entity_elts { 109 xmlNodePtr create_default_instance; 110 xmlNodePtr single_instance; 111 xmlNodePtr restarter; 112 xmlNodePtr dependencies; 113 xmlNodePtr dependents; 114 xmlNodePtr method_context; 115 xmlNodePtr exec_methods; 116 xmlNodePtr notify_params; 117 xmlNodePtr property_groups; 118 xmlNodePtr instances; 119 xmlNodePtr stability; 120 xmlNodePtr template; 121 }; 122 123 /* 124 * Likewise for property_group elements. 125 */ 126 struct pg_elts { 127 xmlNodePtr stability; 128 xmlNodePtr propvals; 129 xmlNodePtr properties; 130 }; 131 132 /* 133 * Likewise for template elements. 134 */ 135 struct template_elts { 136 xmlNodePtr common_name; 137 xmlNodePtr description; 138 xmlNodePtr documentation; 139 }; 140 141 /* 142 * Likewise for type (for notification parameters) elements. 143 */ 144 struct params_elts { 145 xmlNodePtr paramval; 146 xmlNodePtr parameter; 147 }; 148 149 /* 150 * This structure is for snaplevel lists. They are convenient because libscf 151 * only allows traversing snaplevels in one direction. 152 */ 153 struct snaplevel { 154 uu_list_node_t list_node; 155 scf_snaplevel_t *sl; 156 }; 157 158 /* 159 * This is used for communication between lscf_service_export and 160 * export_callback. 161 */ 162 struct export_args { 163 const char *filename; 164 int flags; 165 }; 166 167 /* 168 * The service_manifest structure is used by the upgrade process 169 * to create a list of service to manifest linkages from the manifests 170 * in a set of given directories. 171 */ 172 typedef struct service_manifest { 173 const char *servicename; 174 uu_list_t *mfstlist; 175 size_t mfstlist_sz; 176 177 uu_avl_node_t svcmfst_node; 178 } service_manifest_t; 179 180 /* 181 * Structure to track the manifest file property group 182 * and the manifest file associated with that property 183 * group. Also, a flag to keep the access once it has 184 * been checked. 185 */ 186 struct mpg_mfile { 187 char *mpg; 188 char *mfile; 189 int access; 190 }; 191 192 const char * const scf_pg_general = SCF_PG_GENERAL; 193 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 194 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 195 const char * const scf_property_external = "external"; 196 197 const char * const snap_initial = "initial"; 198 const char * const snap_lastimport = "last-import"; 199 const char * const snap_previous = "previous"; 200 const char * const snap_running = "running"; 201 202 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 203 204 ssize_t max_scf_fmri_len; 205 ssize_t max_scf_name_len; 206 ssize_t max_scf_pg_type_len; 207 ssize_t max_scf_value_len; 208 static size_t max_scf_len; 209 210 static scf_scope_t *cur_scope; 211 static scf_service_t *cur_svc = NULL; 212 static scf_instance_t *cur_inst = NULL; 213 static scf_snapshot_t *cur_snap = NULL; 214 static scf_snaplevel_t *cur_level = NULL; 215 216 static uu_list_pool_t *snaplevel_pool; 217 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 218 static uu_list_t *cur_levels; 219 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 220 221 static FILE *tempfile = NULL; 222 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 223 224 static const char *emsg_entity_not_selected; 225 static const char *emsg_permission_denied; 226 static const char *emsg_create_xml; 227 static const char *emsg_cant_modify_snapshots; 228 static const char *emsg_invalid_for_snapshot; 229 static const char *emsg_read_only; 230 static const char *emsg_deleted; 231 static const char *emsg_invalid_pg_name; 232 static const char *emsg_invalid_prop_name; 233 static const char *emsg_no_such_pg; 234 static const char *emsg_fmri_invalid_pg_name; 235 static const char *emsg_fmri_invalid_pg_name_type; 236 static const char *emsg_pg_added; 237 static const char *emsg_pg_changed; 238 static const char *emsg_pg_deleted; 239 static const char *emsg_pg_mod_perm; 240 static const char *emsg_pg_add_perm; 241 static const char *emsg_pg_del_perm; 242 static const char *emsg_snap_perm; 243 static const char *emsg_dpt_dangling; 244 static const char *emsg_dpt_no_dep; 245 246 static int li_only = 0; 247 static int no_refresh = 0; 248 249 /* how long in ns we should wait between checks for a pg */ 250 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC); 251 252 /* import globals, to minimize allocations */ 253 static scf_scope_t *imp_scope = NULL; 254 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 255 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 256 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 257 static scf_snapshot_t *imp_rsnap = NULL; 258 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 259 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 260 static scf_property_t *imp_prop = NULL; 261 static scf_iter_t *imp_iter = NULL; 262 static scf_iter_t *imp_rpg_iter = NULL; 263 static scf_iter_t *imp_up_iter = NULL; 264 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 265 static char *imp_str = NULL; 266 static size_t imp_str_sz; 267 static char *imp_tsname = NULL; 268 static char *imp_fe1 = NULL; /* for fmri_equal() */ 269 static char *imp_fe2 = NULL; 270 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 271 272 /* upgrade_dependents() globals */ 273 static scf_instance_t *ud_inst = NULL; 274 static scf_snaplevel_t *ud_snpl = NULL; 275 static scf_propertygroup_t *ud_pg = NULL; 276 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 277 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 278 static int ud_run_dpts_pg_set = 0; 279 static scf_property_t *ud_prop = NULL; 280 static scf_property_t *ud_dpt_prop = NULL; 281 static scf_value_t *ud_val = NULL; 282 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 283 static scf_transaction_t *ud_tx = NULL; 284 static char *ud_ctarg = NULL; 285 static char *ud_oldtarg = NULL; 286 static char *ud_name = NULL; 287 288 /* export globals */ 289 static scf_instance_t *exp_inst; 290 static scf_propertygroup_t *exp_pg; 291 static scf_property_t *exp_prop; 292 static scf_value_t *exp_val; 293 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 294 static char *exp_str; 295 static size_t exp_str_sz; 296 297 /* cleanup globals */ 298 static uu_avl_pool_t *service_manifest_pool = NULL; 299 static uu_avl_t *service_manifest_tree = NULL; 300 301 static void scfdie_lineno(int lineno) __NORETURN; 302 303 static char *start_method_names[] = { 304 "start", 305 "inetd_start", 306 NULL 307 }; 308 309 static struct uri_scheme { 310 const char *scheme; 311 const char *protocol; 312 } uri_scheme[] = { 313 { "mailto", "smtp" }, 314 { "snmp", "snmp" }, 315 { "syslog", "syslog" }, 316 { NULL, NULL } 317 }; 318 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \ 319 sizeof (struct uri_scheme)) - 1) 320 321 static int 322 check_uri_scheme(const char *scheme) 323 { 324 int i; 325 326 for (i = 0; uri_scheme[i].scheme != NULL; ++i) { 327 if (strcmp(scheme, uri_scheme[i].scheme) == 0) 328 return (i); 329 } 330 331 return (-1); 332 } 333 334 static int 335 check_uri_protocol(const char *p) 336 { 337 int i; 338 339 for (i = 0; uri_scheme[i].protocol != NULL; ++i) { 340 if (strcmp(p, uri_scheme[i].protocol) == 0) 341 return (i); 342 } 343 344 return (-1); 345 } 346 347 /* 348 * For unexpected libscf errors. 349 */ 350 #ifdef NDEBUG 351 352 static void scfdie(void) __NORETURN; 353 354 static void 355 scfdie(void) 356 { 357 scf_error_t err = scf_error(); 358 359 if (err == SCF_ERROR_CONNECTION_BROKEN) 360 uu_die(gettext("Repository connection broken. Exiting.\n")); 361 362 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 363 scf_strerror(err)); 364 } 365 366 #else 367 368 #define scfdie() scfdie_lineno(__LINE__) 369 370 static void 371 scfdie_lineno(int lineno) 372 { 373 scf_error_t err = scf_error(); 374 375 if (err == SCF_ERROR_CONNECTION_BROKEN) 376 uu_die(gettext("Repository connection broken. Exiting.\n")); 377 378 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 379 ": %s.\n"), lineno, scf_strerror(err)); 380 } 381 382 #endif 383 384 static void 385 scfwarn(void) 386 { 387 warn(gettext("Unexpected libscf error: %s.\n"), 388 scf_strerror(scf_error())); 389 } 390 391 /* 392 * Clear a field of a structure. 393 */ 394 static int 395 clear_int(void *a, void *b) 396 { 397 /* LINTED */ 398 *(int *)((char *)a + (size_t)b) = 0; 399 400 return (UU_WALK_NEXT); 401 } 402 403 static int 404 scferror2errno(scf_error_t err) 405 { 406 switch (err) { 407 case SCF_ERROR_BACKEND_ACCESS: 408 return (EACCES); 409 410 case SCF_ERROR_BACKEND_READONLY: 411 return (EROFS); 412 413 case SCF_ERROR_CONNECTION_BROKEN: 414 return (ECONNABORTED); 415 416 case SCF_ERROR_CONSTRAINT_VIOLATED: 417 case SCF_ERROR_INVALID_ARGUMENT: 418 return (EINVAL); 419 420 case SCF_ERROR_DELETED: 421 return (ECANCELED); 422 423 case SCF_ERROR_EXISTS: 424 return (EEXIST); 425 426 case SCF_ERROR_NO_MEMORY: 427 return (ENOMEM); 428 429 case SCF_ERROR_NO_RESOURCES: 430 return (ENOSPC); 431 432 case SCF_ERROR_NOT_FOUND: 433 return (ENOENT); 434 435 case SCF_ERROR_PERMISSION_DENIED: 436 return (EPERM); 437 438 default: 439 #ifndef NDEBUG 440 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 441 __FILE__, __LINE__, err); 442 #else 443 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 444 #endif 445 abort(); 446 /* NOTREACHED */ 447 } 448 } 449 450 static int 451 entity_get_pg(void *ent, int issvc, const char *name, 452 scf_propertygroup_t *pg) 453 { 454 if (issvc) 455 return (scf_service_get_pg(ent, name, pg)); 456 else 457 return (scf_instance_get_pg(ent, name, pg)); 458 } 459 460 static void 461 entity_destroy(void *ent, int issvc) 462 { 463 if (issvc) 464 scf_service_destroy(ent); 465 else 466 scf_instance_destroy(ent); 467 } 468 469 static int 470 get_pg(const char *pg_name, scf_propertygroup_t *pg) 471 { 472 int ret; 473 474 if (cur_level != NULL) 475 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 476 else if (cur_inst != NULL) 477 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 478 else 479 ret = scf_service_get_pg(cur_svc, pg_name, pg); 480 481 return (ret); 482 } 483 484 /* 485 * Find a snaplevel in a snapshot. If get_svc is true, find the service 486 * snaplevel. Otherwise find the instance snaplevel. 487 * 488 * Returns 489 * 0 - success 490 * ECONNABORTED - repository connection broken 491 * ECANCELED - instance containing snap was deleted 492 * ENOENT - snap has no snaplevels 493 * - requested snaplevel not found 494 */ 495 static int 496 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 497 { 498 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 499 switch (scf_error()) { 500 case SCF_ERROR_CONNECTION_BROKEN: 501 case SCF_ERROR_DELETED: 502 case SCF_ERROR_NOT_FOUND: 503 return (scferror2errno(scf_error())); 504 505 case SCF_ERROR_HANDLE_MISMATCH: 506 case SCF_ERROR_NOT_BOUND: 507 case SCF_ERROR_NOT_SET: 508 default: 509 bad_error("scf_snapshot_get_base_snaplevel", 510 scf_error()); 511 } 512 } 513 514 for (;;) { 515 ssize_t ssz; 516 517 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 518 if (ssz >= 0) { 519 if (!get_svc) 520 return (0); 521 } else { 522 switch (scf_error()) { 523 case SCF_ERROR_CONSTRAINT_VIOLATED: 524 if (get_svc) 525 return (0); 526 break; 527 528 case SCF_ERROR_DELETED: 529 case SCF_ERROR_CONNECTION_BROKEN: 530 return (scferror2errno(scf_error())); 531 532 case SCF_ERROR_NOT_SET: 533 case SCF_ERROR_NOT_BOUND: 534 default: 535 bad_error("scf_snaplevel_get_instance_name", 536 scf_error()); 537 } 538 } 539 540 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 541 switch (scf_error()) { 542 case SCF_ERROR_NOT_FOUND: 543 case SCF_ERROR_CONNECTION_BROKEN: 544 case SCF_ERROR_DELETED: 545 return (scferror2errno(scf_error())); 546 547 case SCF_ERROR_HANDLE_MISMATCH: 548 case SCF_ERROR_NOT_BOUND: 549 case SCF_ERROR_NOT_SET: 550 case SCF_ERROR_INVALID_ARGUMENT: 551 default: 552 bad_error("scf_snaplevel_get_next_snaplevel", 553 scf_error()); 554 } 555 } 556 } 557 } 558 559 /* 560 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 561 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 562 * the property group named name in it. If it doesn't have a running 563 * snapshot, set pg to the instance's current property group named name. 564 * 565 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 566 * its instances. If one has a running snapshot with a service snaplevel, set 567 * pg to the property group named name in it. If no such snaplevel could be 568 * found, set pg to the service's current property group named name. 569 * 570 * iter, inst, snap, and snpl are required scratch objects. 571 * 572 * Returns 573 * 0 - success 574 * ECONNABORTED - repository connection broken 575 * ECANCELED - ent was deleted 576 * ENOENT - no such property group 577 * EINVAL - name is an invalid property group name 578 * EBADF - found running snapshot is missing a snaplevel 579 */ 580 static int 581 entity_get_running_pg(void *ent, int issvc, const char *name, 582 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 583 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 584 { 585 int r; 586 587 if (issvc) { 588 /* Search for an instance with a running snapshot. */ 589 if (scf_iter_service_instances(iter, ent) != 0) { 590 switch (scf_error()) { 591 case SCF_ERROR_DELETED: 592 case SCF_ERROR_CONNECTION_BROKEN: 593 return (scferror2errno(scf_error())); 594 595 case SCF_ERROR_NOT_SET: 596 case SCF_ERROR_NOT_BOUND: 597 case SCF_ERROR_HANDLE_MISMATCH: 598 default: 599 bad_error("scf_iter_service_instances", 600 scf_error()); 601 } 602 } 603 604 for (;;) { 605 r = scf_iter_next_instance(iter, inst); 606 if (r == 0) { 607 if (scf_service_get_pg(ent, name, pg) == 0) 608 return (0); 609 610 switch (scf_error()) { 611 case SCF_ERROR_DELETED: 612 case SCF_ERROR_NOT_FOUND: 613 case SCF_ERROR_INVALID_ARGUMENT: 614 case SCF_ERROR_CONNECTION_BROKEN: 615 return (scferror2errno(scf_error())); 616 617 case SCF_ERROR_NOT_BOUND: 618 case SCF_ERROR_HANDLE_MISMATCH: 619 case SCF_ERROR_NOT_SET: 620 default: 621 bad_error("scf_service_get_pg", 622 scf_error()); 623 } 624 } 625 if (r != 1) { 626 switch (scf_error()) { 627 case SCF_ERROR_DELETED: 628 case SCF_ERROR_CONNECTION_BROKEN: 629 return (scferror2errno(scf_error())); 630 631 case SCF_ERROR_INVALID_ARGUMENT: 632 case SCF_ERROR_NOT_SET: 633 case SCF_ERROR_NOT_BOUND: 634 case SCF_ERROR_HANDLE_MISMATCH: 635 default: 636 bad_error("scf_iter_next_instance", 637 scf_error()); 638 } 639 } 640 641 if (scf_instance_get_snapshot(inst, snap_running, 642 snap) == 0) 643 break; 644 645 switch (scf_error()) { 646 case SCF_ERROR_NOT_FOUND: 647 case SCF_ERROR_DELETED: 648 continue; 649 650 case SCF_ERROR_CONNECTION_BROKEN: 651 return (ECONNABORTED); 652 653 case SCF_ERROR_HANDLE_MISMATCH: 654 case SCF_ERROR_INVALID_ARGUMENT: 655 case SCF_ERROR_NOT_SET: 656 case SCF_ERROR_NOT_BOUND: 657 default: 658 bad_error("scf_instance_get_snapshot", 659 scf_error()); 660 } 661 } 662 } else { 663 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 664 switch (scf_error()) { 665 case SCF_ERROR_NOT_FOUND: 666 break; 667 668 case SCF_ERROR_DELETED: 669 case SCF_ERROR_CONNECTION_BROKEN: 670 return (scferror2errno(scf_error())); 671 672 case SCF_ERROR_NOT_BOUND: 673 case SCF_ERROR_HANDLE_MISMATCH: 674 case SCF_ERROR_INVALID_ARGUMENT: 675 case SCF_ERROR_NOT_SET: 676 default: 677 bad_error("scf_instance_get_snapshot", 678 scf_error()); 679 } 680 681 if (scf_instance_get_pg(ent, name, pg) == 0) 682 return (0); 683 684 switch (scf_error()) { 685 case SCF_ERROR_DELETED: 686 case SCF_ERROR_NOT_FOUND: 687 case SCF_ERROR_INVALID_ARGUMENT: 688 case SCF_ERROR_CONNECTION_BROKEN: 689 return (scferror2errno(scf_error())); 690 691 case SCF_ERROR_NOT_BOUND: 692 case SCF_ERROR_HANDLE_MISMATCH: 693 case SCF_ERROR_NOT_SET: 694 default: 695 bad_error("scf_instance_get_pg", scf_error()); 696 } 697 } 698 } 699 700 r = get_snaplevel(snap, issvc, snpl); 701 switch (r) { 702 case 0: 703 break; 704 705 case ECONNABORTED: 706 case ECANCELED: 707 return (r); 708 709 case ENOENT: 710 return (EBADF); 711 712 default: 713 bad_error("get_snaplevel", r); 714 } 715 716 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 717 return (0); 718 719 switch (scf_error()) { 720 case SCF_ERROR_DELETED: 721 case SCF_ERROR_INVALID_ARGUMENT: 722 case SCF_ERROR_CONNECTION_BROKEN: 723 case SCF_ERROR_NOT_FOUND: 724 return (scferror2errno(scf_error())); 725 726 case SCF_ERROR_NOT_BOUND: 727 case SCF_ERROR_HANDLE_MISMATCH: 728 case SCF_ERROR_NOT_SET: 729 default: 730 bad_error("scf_snaplevel_get_pg", scf_error()); 731 /* NOTREACHED */ 732 } 733 } 734 735 /* 736 * To be registered with atexit(). 737 */ 738 static void 739 remove_tempfile(void) 740 { 741 int ret; 742 743 if (tempfile != NULL) { 744 if (fclose(tempfile) == EOF) 745 (void) warn(gettext("Could not close temporary file")); 746 tempfile = NULL; 747 } 748 749 if (tempfilename[0] != '\0') { 750 do { 751 ret = remove(tempfilename); 752 } while (ret == -1 && errno == EINTR); 753 if (ret == -1) 754 warn(gettext("Could not remove temporary file")); 755 tempfilename[0] = '\0'; 756 } 757 } 758 759 /* 760 * Launch private svc.configd(8) for manipulating alternate repositories. 761 */ 762 static void 763 start_private_repository(engine_state_t *est) 764 { 765 int fd, stat; 766 struct door_info info; 767 pid_t pid; 768 769 /* 770 * 1. Create a temporary file for the door. 771 */ 772 if (est->sc_repo_doorname != NULL) 773 free((void *)est->sc_repo_doorname); 774 775 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 776 if (est->sc_repo_doorname == NULL) 777 uu_die(gettext("Could not acquire temporary filename")); 778 779 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 780 if (fd < 0) 781 uu_die(gettext("Could not create temporary file for " 782 "repository server")); 783 784 (void) close(fd); 785 786 /* 787 * 2. Launch a configd with that door, using the specified 788 * repository. 789 */ 790 if ((est->sc_repo_pid = fork()) == 0) { 791 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 792 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 793 NULL); 794 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 795 } else if (est->sc_repo_pid == -1) 796 uu_die(gettext("Attempt to fork failed")); 797 798 do { 799 pid = waitpid(est->sc_repo_pid, &stat, 0); 800 } while (pid == -1 && errno == EINTR); 801 802 if (pid == -1) 803 uu_die(gettext("Could not waitpid() for repository server")); 804 805 if (!WIFEXITED(stat)) { 806 uu_die(gettext("Repository server failed (status %d).\n"), 807 stat); 808 } else if (WEXITSTATUS(stat) != 0) { 809 uu_die(gettext("Repository server failed (exit %d).\n"), 810 WEXITSTATUS(stat)); 811 } 812 813 /* 814 * See if it was successful by checking if the door is a door. 815 */ 816 817 fd = open(est->sc_repo_doorname, O_RDWR); 818 if (fd < 0) 819 uu_die(gettext("Could not open door \"%s\""), 820 est->sc_repo_doorname); 821 822 if (door_info(fd, &info) < 0) 823 uu_die(gettext("Unexpected door_info() error")); 824 825 if (close(fd) == -1) 826 warn(gettext("Could not close repository door"), 827 strerror(errno)); 828 829 est->sc_repo_pid = info.di_target; 830 } 831 832 void 833 lscf_cleanup(void) 834 { 835 /* 836 * In the case where we've launched a private svc.configd(8) 837 * instance, we must terminate our child and remove the temporary 838 * rendezvous point. 839 */ 840 if (est->sc_repo_pid > 0) { 841 (void) kill(est->sc_repo_pid, SIGTERM); 842 (void) waitpid(est->sc_repo_pid, NULL, 0); 843 (void) unlink(est->sc_repo_doorname); 844 845 est->sc_repo_pid = 0; 846 } 847 } 848 849 void 850 unselect_cursnap(void) 851 { 852 void *cookie; 853 854 cur_level = NULL; 855 856 cookie = NULL; 857 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 858 scf_snaplevel_destroy(cur_elt->sl); 859 free(cur_elt); 860 } 861 862 scf_snapshot_destroy(cur_snap); 863 cur_snap = NULL; 864 } 865 866 void 867 lscf_prep_hndl(void) 868 { 869 if (g_hndl != NULL) 870 return; 871 872 g_hndl = scf_handle_create(SCF_VERSION); 873 if (g_hndl == NULL) 874 scfdie(); 875 876 if (est->sc_repo_filename != NULL) 877 start_private_repository(est); 878 879 if (est->sc_repo_doorname != NULL) { 880 scf_value_t *repo_value; 881 int ret; 882 883 repo_value = scf_value_create(g_hndl); 884 if (repo_value == NULL) 885 scfdie(); 886 887 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 888 assert(ret == SCF_SUCCESS); 889 890 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 891 SCF_SUCCESS) 892 scfdie(); 893 894 scf_value_destroy(repo_value); 895 } else if (g_do_zone != 0) { 896 scf_value_t *zone; 897 898 if ((zone = scf_value_create(g_hndl)) == NULL) 899 scfdie(); 900 901 if (scf_value_set_astring(zone, g_zonename) != SCF_SUCCESS) 902 scfdie(); 903 904 if (scf_handle_decorate(g_hndl, "zone", zone) != SCF_SUCCESS) { 905 uu_die(gettext("zone '%s': %s\n"), 906 g_zonename, scf_strerror(scf_error())); 907 } 908 909 scf_value_destroy(zone); 910 } 911 912 if (scf_handle_bind(g_hndl) != 0) 913 uu_die(gettext("Could not connect to repository server: %s.\n"), 914 scf_strerror(scf_error())); 915 916 cur_scope = scf_scope_create(g_hndl); 917 if (cur_scope == NULL) 918 scfdie(); 919 920 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 921 scfdie(); 922 } 923 924 static void 925 repository_teardown(void) 926 { 927 if (g_hndl != NULL) { 928 if (cur_snap != NULL) 929 unselect_cursnap(); 930 scf_instance_destroy(cur_inst); 931 scf_service_destroy(cur_svc); 932 scf_scope_destroy(cur_scope); 933 scf_handle_destroy(g_hndl); 934 cur_inst = NULL; 935 cur_svc = NULL; 936 cur_scope = NULL; 937 g_hndl = NULL; 938 lscf_cleanup(); 939 } 940 } 941 942 void 943 lscf_set_repository(const char *repfile, int force) 944 { 945 repository_teardown(); 946 947 if (est->sc_repo_filename != NULL) { 948 free((void *)est->sc_repo_filename); 949 est->sc_repo_filename = NULL; 950 } 951 952 if ((force == 0) && (access(repfile, R_OK) != 0)) { 953 /* 954 * Repository file does not exist 955 * or has no read permission. 956 */ 957 warn(gettext("Cannot access \"%s\": %s\n"), 958 repfile, strerror(errno)); 959 } else { 960 est->sc_repo_filename = safe_strdup(repfile); 961 } 962 963 lscf_prep_hndl(); 964 } 965 966 void 967 lscf_init() 968 { 969 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 970 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 971 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 972 0 || 973 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 974 scfdie(); 975 976 max_scf_len = max_scf_fmri_len; 977 if (max_scf_name_len > max_scf_len) 978 max_scf_len = max_scf_name_len; 979 if (max_scf_pg_type_len > max_scf_len) 980 max_scf_len = max_scf_pg_type_len; 981 /* 982 * When a value of type opaque is represented as a string, the 983 * string contains 2 characters for every byte of data. That is 984 * because the string contains the hex representation of the opaque 985 * value. 986 */ 987 if (2 * max_scf_value_len > max_scf_len) 988 max_scf_len = 2 * max_scf_value_len; 989 990 if (atexit(remove_tempfile) != 0) 991 uu_die(gettext("Could not register atexit() function")); 992 993 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 994 emsg_permission_denied = gettext("Permission denied.\n"); 995 emsg_create_xml = gettext("Could not create XML node.\n"); 996 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 997 emsg_invalid_for_snapshot = 998 gettext("Invalid operation on a snapshot.\n"); 999 emsg_read_only = gettext("Backend read-only.\n"); 1000 emsg_deleted = gettext("Current selection has been deleted.\n"); 1001 emsg_invalid_pg_name = 1002 gettext("Invalid property group name \"%s\".\n"); 1003 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 1004 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 1005 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 1006 "with invalid name \"%s\".\n"); 1007 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 1008 "group with invalid name \"%s\" or type \"%s\".\n"); 1009 emsg_pg_added = gettext("%s changed unexpectedly " 1010 "(property group \"%s\" added).\n"); 1011 emsg_pg_changed = gettext("%s changed unexpectedly " 1012 "(property group \"%s\" changed).\n"); 1013 emsg_pg_deleted = gettext("%s changed unexpectedly " 1014 "(property group \"%s\" or an ancestor was deleted).\n"); 1015 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 1016 "in %s (permission denied).\n"); 1017 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 1018 "in %s (permission denied).\n"); 1019 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 1020 "in %s (permission denied).\n"); 1021 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 1022 "(permission denied).\n"); 1023 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 1024 "new dependent \"%s\" because it already exists). Warning: The " 1025 "current dependent's target (%s) does not exist.\n"); 1026 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 1027 "dependent \"%s\" because it already exists). Warning: The " 1028 "current dependent's target (%s) does not have a dependency named " 1029 "\"%s\" as expected.\n"); 1030 1031 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 1032 offsetof(string_list_t, node), NULL, 0); 1033 snaplevel_pool = uu_list_pool_create("snaplevels", 1034 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 1035 NULL, 0); 1036 } 1037 1038 1039 static const char * 1040 prop_to_typestr(const scf_property_t *prop) 1041 { 1042 scf_type_t ty; 1043 1044 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 1045 scfdie(); 1046 1047 return (scf_type_to_string(ty)); 1048 } 1049 1050 static scf_type_t 1051 string_to_type(const char *type) 1052 { 1053 size_t len = strlen(type); 1054 char *buf; 1055 1056 if (len == 0 || type[len - 1] != ':') 1057 return (SCF_TYPE_INVALID); 1058 1059 buf = (char *)alloca(len + 1); 1060 (void) strlcpy(buf, type, len + 1); 1061 buf[len - 1] = 0; 1062 1063 return (scf_string_to_type(buf)); 1064 } 1065 1066 static scf_value_t * 1067 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 1068 { 1069 scf_value_t *v; 1070 char *dup, *nstr; 1071 size_t len; 1072 1073 v = scf_value_create(g_hndl); 1074 if (v == NULL) 1075 scfdie(); 1076 1077 len = strlen(str); 1078 if (require_quotes && 1079 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1080 semerr(gettext("Multiple string values or string values " 1081 "with spaces must be quoted with '\"'.\n")); 1082 scf_value_destroy(v); 1083 return (NULL); 1084 } 1085 1086 nstr = dup = safe_strdup(str); 1087 if (dup[0] == '\"') { 1088 /* 1089 * Strip out the first and the last quote. 1090 */ 1091 dup[len - 1] = '\0'; 1092 nstr = dup + 1; 1093 } 1094 1095 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1096 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1097 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1098 scf_type_to_string(ty), nstr); 1099 scf_value_destroy(v); 1100 v = NULL; 1101 } 1102 free(dup); 1103 return (v); 1104 } 1105 1106 /* 1107 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1108 * Optionally append a comment prefix ('#') to newlines ('\n'). 1109 */ 1110 static int 1111 quote_and_print(const char *str, FILE *strm, int commentnl) 1112 { 1113 const char *cp; 1114 1115 for (cp = str; *cp != '\0'; ++cp) { 1116 if (*cp == '"' || *cp == '\\') 1117 (void) putc('\\', strm); 1118 1119 (void) putc(*cp, strm); 1120 1121 if (commentnl && *cp == '\n') { 1122 (void) putc('#', strm); 1123 } 1124 } 1125 1126 return (ferror(strm)); 1127 } 1128 1129 /* 1130 * These wrappers around lowlevel functions provide consistent error checking 1131 * and warnings. 1132 */ 1133 static int 1134 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1135 { 1136 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1137 return (0); 1138 1139 if (scf_error() != SCF_ERROR_NOT_FOUND) 1140 scfdie(); 1141 1142 if (g_verbose) { 1143 ssize_t len; 1144 char *fmri; 1145 1146 len = scf_pg_to_fmri(pg, NULL, 0); 1147 if (len < 0) 1148 scfdie(); 1149 1150 fmri = safe_malloc(len + 1); 1151 1152 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1153 scfdie(); 1154 1155 warn(gettext("Expected property %s of property group %s is " 1156 "missing.\n"), propname, fmri); 1157 1158 free(fmri); 1159 } 1160 1161 return (-1); 1162 } 1163 1164 static int 1165 prop_check_type(scf_property_t *prop, scf_type_t ty) 1166 { 1167 scf_type_t pty; 1168 1169 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1170 scfdie(); 1171 1172 if (ty == pty) 1173 return (0); 1174 1175 if (g_verbose) { 1176 ssize_t len; 1177 char *fmri; 1178 const char *tystr; 1179 1180 len = scf_property_to_fmri(prop, NULL, 0); 1181 if (len < 0) 1182 scfdie(); 1183 1184 fmri = safe_malloc(len + 1); 1185 1186 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1187 scfdie(); 1188 1189 tystr = scf_type_to_string(ty); 1190 if (tystr == NULL) 1191 tystr = "?"; 1192 1193 warn(gettext("Property %s is not of expected type %s.\n"), 1194 fmri, tystr); 1195 1196 free(fmri); 1197 } 1198 1199 return (-1); 1200 } 1201 1202 static int 1203 prop_get_val(scf_property_t *prop, scf_value_t *val) 1204 { 1205 scf_error_t err; 1206 1207 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1208 return (0); 1209 1210 err = scf_error(); 1211 1212 if (err != SCF_ERROR_NOT_FOUND && 1213 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1214 err != SCF_ERROR_PERMISSION_DENIED) 1215 scfdie(); 1216 1217 if (g_verbose) { 1218 ssize_t len; 1219 char *fmri, *emsg; 1220 1221 len = scf_property_to_fmri(prop, NULL, 0); 1222 if (len < 0) 1223 scfdie(); 1224 1225 fmri = safe_malloc(len + 1); 1226 1227 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1228 scfdie(); 1229 1230 if (err == SCF_ERROR_NOT_FOUND) 1231 emsg = gettext("Property %s has no values; expected " 1232 "one.\n"); 1233 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1234 emsg = gettext("Property %s has multiple values; " 1235 "expected one.\n"); 1236 else 1237 emsg = gettext("No permission to read property %s.\n"); 1238 1239 warn(emsg, fmri); 1240 1241 free(fmri); 1242 } 1243 1244 return (-1); 1245 } 1246 1247 1248 static boolean_t 1249 snaplevel_is_instance(const scf_snaplevel_t *level) 1250 { 1251 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1252 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1253 scfdie(); 1254 return (0); 1255 } else { 1256 return (1); 1257 } 1258 } 1259 1260 /* 1261 * Decode FMRI into a service or instance, and put the result in *ep. If 1262 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1263 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1264 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1265 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1266 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1267 * whether *ep is a service. 1268 */ 1269 static scf_error_t 1270 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1271 { 1272 char *fmri_copy; 1273 const char *sstr, *istr, *pgstr; 1274 scf_service_t *svc; 1275 scf_instance_t *inst; 1276 1277 fmri_copy = strdup(fmri); 1278 if (fmri_copy == NULL) 1279 return (SCF_ERROR_NO_MEMORY); 1280 1281 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1282 SCF_SUCCESS) { 1283 free(fmri_copy); 1284 return (SCF_ERROR_INVALID_ARGUMENT); 1285 } 1286 1287 free(fmri_copy); 1288 1289 if (sstr == NULL || pgstr != NULL) 1290 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1291 1292 if (istr == NULL) { 1293 svc = scf_service_create(h); 1294 if (svc == NULL) 1295 return (SCF_ERROR_NO_MEMORY); 1296 1297 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1298 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1299 if (scf_error() != SCF_ERROR_NOT_FOUND) 1300 scfdie(); 1301 1302 return (SCF_ERROR_NOT_FOUND); 1303 } 1304 1305 *ep = svc; 1306 *isservice = 1; 1307 } else { 1308 inst = scf_instance_create(h); 1309 if (inst == NULL) 1310 return (SCF_ERROR_NO_MEMORY); 1311 1312 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1313 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1314 if (scf_error() != SCF_ERROR_NOT_FOUND) 1315 scfdie(); 1316 1317 return (SCF_ERROR_NOT_FOUND); 1318 } 1319 1320 *ep = inst; 1321 *isservice = 0; 1322 } 1323 1324 return (SCF_ERROR_NONE); 1325 } 1326 1327 /* 1328 * Create the entity named by fmri. Place a pointer to its libscf handle in 1329 * *ep, and set or clear *isservicep if it is a service or an instance. 1330 * Returns 1331 * SCF_ERROR_NONE - success 1332 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1333 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1334 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1335 * SCF_ERROR_NOT_FOUND - no such scope 1336 * SCF_ERROR_PERMISSION_DENIED 1337 * SCF_ERROR_BACKEND_READONLY 1338 * SCF_ERROR_BACKEND_ACCESS 1339 */ 1340 static scf_error_t 1341 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1342 { 1343 char *fmri_copy; 1344 const char *scstr, *sstr, *istr, *pgstr; 1345 scf_scope_t *scope = NULL; 1346 scf_service_t *svc = NULL; 1347 scf_instance_t *inst = NULL; 1348 scf_error_t scfe; 1349 1350 fmri_copy = safe_strdup(fmri); 1351 1352 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1353 0) { 1354 free(fmri_copy); 1355 return (SCF_ERROR_INVALID_ARGUMENT); 1356 } 1357 1358 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1359 free(fmri_copy); 1360 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1361 } 1362 1363 *ep = NULL; 1364 1365 if ((scope = scf_scope_create(h)) == NULL || 1366 (svc = scf_service_create(h)) == NULL || 1367 (inst = scf_instance_create(h)) == NULL) { 1368 scfe = SCF_ERROR_NO_MEMORY; 1369 goto out; 1370 } 1371 1372 get_scope: 1373 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1374 switch (scf_error()) { 1375 case SCF_ERROR_CONNECTION_BROKEN: 1376 scfdie(); 1377 /* NOTREACHED */ 1378 1379 case SCF_ERROR_NOT_FOUND: 1380 scfe = SCF_ERROR_NOT_FOUND; 1381 goto out; 1382 1383 case SCF_ERROR_HANDLE_MISMATCH: 1384 case SCF_ERROR_NOT_BOUND: 1385 case SCF_ERROR_INVALID_ARGUMENT: 1386 default: 1387 bad_error("scf_handle_get_scope", scf_error()); 1388 } 1389 } 1390 1391 get_svc: 1392 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1393 switch (scf_error()) { 1394 case SCF_ERROR_CONNECTION_BROKEN: 1395 scfdie(); 1396 /* NOTREACHED */ 1397 1398 case SCF_ERROR_DELETED: 1399 goto get_scope; 1400 1401 case SCF_ERROR_NOT_FOUND: 1402 break; 1403 1404 case SCF_ERROR_HANDLE_MISMATCH: 1405 case SCF_ERROR_INVALID_ARGUMENT: 1406 case SCF_ERROR_NOT_BOUND: 1407 case SCF_ERROR_NOT_SET: 1408 default: 1409 bad_error("scf_scope_get_service", scf_error()); 1410 } 1411 1412 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1413 switch (scf_error()) { 1414 case SCF_ERROR_CONNECTION_BROKEN: 1415 scfdie(); 1416 /* NOTREACHED */ 1417 1418 case SCF_ERROR_DELETED: 1419 goto get_scope; 1420 1421 case SCF_ERROR_PERMISSION_DENIED: 1422 case SCF_ERROR_BACKEND_READONLY: 1423 case SCF_ERROR_BACKEND_ACCESS: 1424 scfe = scf_error(); 1425 goto out; 1426 1427 case SCF_ERROR_HANDLE_MISMATCH: 1428 case SCF_ERROR_INVALID_ARGUMENT: 1429 case SCF_ERROR_NOT_BOUND: 1430 case SCF_ERROR_NOT_SET: 1431 default: 1432 bad_error("scf_scope_get_service", scf_error()); 1433 } 1434 } 1435 } 1436 1437 if (istr == NULL) { 1438 scfe = SCF_ERROR_NONE; 1439 *ep = svc; 1440 *isservicep = 1; 1441 goto out; 1442 } 1443 1444 get_inst: 1445 if (scf_service_get_instance(svc, istr, inst) != 0) { 1446 switch (scf_error()) { 1447 case SCF_ERROR_CONNECTION_BROKEN: 1448 scfdie(); 1449 /* NOTREACHED */ 1450 1451 case SCF_ERROR_DELETED: 1452 goto get_svc; 1453 1454 case SCF_ERROR_NOT_FOUND: 1455 break; 1456 1457 case SCF_ERROR_HANDLE_MISMATCH: 1458 case SCF_ERROR_INVALID_ARGUMENT: 1459 case SCF_ERROR_NOT_BOUND: 1460 case SCF_ERROR_NOT_SET: 1461 default: 1462 bad_error("scf_service_get_instance", scf_error()); 1463 } 1464 1465 if (scf_service_add_instance(svc, istr, inst) != 0) { 1466 switch (scf_error()) { 1467 case SCF_ERROR_CONNECTION_BROKEN: 1468 scfdie(); 1469 /* NOTREACHED */ 1470 1471 case SCF_ERROR_DELETED: 1472 goto get_svc; 1473 1474 case SCF_ERROR_PERMISSION_DENIED: 1475 case SCF_ERROR_BACKEND_READONLY: 1476 case SCF_ERROR_BACKEND_ACCESS: 1477 scfe = scf_error(); 1478 goto out; 1479 1480 case SCF_ERROR_HANDLE_MISMATCH: 1481 case SCF_ERROR_INVALID_ARGUMENT: 1482 case SCF_ERROR_NOT_BOUND: 1483 case SCF_ERROR_NOT_SET: 1484 default: 1485 bad_error("scf_service_add_instance", 1486 scf_error()); 1487 } 1488 } 1489 } 1490 1491 scfe = SCF_ERROR_NONE; 1492 *ep = inst; 1493 *isservicep = 0; 1494 1495 out: 1496 if (*ep != inst) 1497 scf_instance_destroy(inst); 1498 if (*ep != svc) 1499 scf_service_destroy(svc); 1500 scf_scope_destroy(scope); 1501 free(fmri_copy); 1502 return (scfe); 1503 } 1504 1505 /* 1506 * Create or update a snapshot of inst. snap is a required scratch object. 1507 * 1508 * Returns 1509 * 0 - success 1510 * ECONNABORTED - repository connection broken 1511 * EPERM - permission denied 1512 * ENOSPC - configd is out of resources 1513 * ECANCELED - inst was deleted 1514 * -1 - unknown libscf error (message printed) 1515 */ 1516 static int 1517 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1518 { 1519 again: 1520 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1521 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1522 switch (scf_error()) { 1523 case SCF_ERROR_CONNECTION_BROKEN: 1524 case SCF_ERROR_PERMISSION_DENIED: 1525 case SCF_ERROR_NO_RESOURCES: 1526 return (scferror2errno(scf_error())); 1527 1528 case SCF_ERROR_NOT_SET: 1529 case SCF_ERROR_INVALID_ARGUMENT: 1530 default: 1531 bad_error("_scf_snapshot_take_attach", 1532 scf_error()); 1533 } 1534 } 1535 } else { 1536 switch (scf_error()) { 1537 case SCF_ERROR_NOT_FOUND: 1538 break; 1539 1540 case SCF_ERROR_DELETED: 1541 case SCF_ERROR_CONNECTION_BROKEN: 1542 return (scferror2errno(scf_error())); 1543 1544 case SCF_ERROR_HANDLE_MISMATCH: 1545 case SCF_ERROR_NOT_BOUND: 1546 case SCF_ERROR_INVALID_ARGUMENT: 1547 case SCF_ERROR_NOT_SET: 1548 default: 1549 bad_error("scf_instance_get_snapshot", scf_error()); 1550 } 1551 1552 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1553 switch (scf_error()) { 1554 case SCF_ERROR_EXISTS: 1555 goto again; 1556 1557 case SCF_ERROR_CONNECTION_BROKEN: 1558 case SCF_ERROR_NO_RESOURCES: 1559 case SCF_ERROR_PERMISSION_DENIED: 1560 return (scferror2errno(scf_error())); 1561 1562 default: 1563 scfwarn(); 1564 return (-1); 1565 1566 case SCF_ERROR_NOT_SET: 1567 case SCF_ERROR_INTERNAL: 1568 case SCF_ERROR_INVALID_ARGUMENT: 1569 case SCF_ERROR_HANDLE_MISMATCH: 1570 bad_error("_scf_snapshot_take_new", 1571 scf_error()); 1572 } 1573 } 1574 } 1575 1576 return (0); 1577 } 1578 1579 static int 1580 refresh_running_snapshot(void *entity) 1581 { 1582 scf_snapshot_t *snap; 1583 int r; 1584 1585 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1586 scfdie(); 1587 r = take_snap(entity, snap_running, snap); 1588 scf_snapshot_destroy(snap); 1589 1590 return (r); 1591 } 1592 1593 /* 1594 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1595 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1596 * instances. fmri is used for messages. inst, iter, and name_buf are used 1597 * for scratch space. Returns 1598 * 0 - success 1599 * ECONNABORTED - repository connection broken 1600 * ECANCELED - entity was deleted 1601 * EACCES - backend denied access 1602 * EPERM - permission denied 1603 * ENOSPC - repository server out of resources 1604 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1605 */ 1606 static int 1607 refresh_entity(int isservice, void *entity, const char *fmri, 1608 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1609 { 1610 scf_error_t scfe; 1611 int r; 1612 1613 if (!isservice) { 1614 /* 1615 * Let restarter handles refreshing and making new running 1616 * snapshot only if operating on a live repository and not 1617 * running in early import. 1618 */ 1619 if (est->sc_repo_filename == NULL && 1620 est->sc_repo_doorname == NULL && 1621 est->sc_in_emi == 0) { 1622 if (_smf_refresh_instance_i(entity) == 0) { 1623 if (g_verbose) 1624 warn(gettext("Refreshed %s.\n"), fmri); 1625 return (0); 1626 } 1627 1628 switch (scf_error()) { 1629 case SCF_ERROR_BACKEND_ACCESS: 1630 return (EACCES); 1631 1632 case SCF_ERROR_PERMISSION_DENIED: 1633 return (EPERM); 1634 1635 default: 1636 return (-1); 1637 } 1638 } else { 1639 r = refresh_running_snapshot(entity); 1640 switch (r) { 1641 case 0: 1642 break; 1643 1644 case ECONNABORTED: 1645 case ECANCELED: 1646 case EPERM: 1647 case ENOSPC: 1648 break; 1649 1650 default: 1651 bad_error("refresh_running_snapshot", 1652 scf_error()); 1653 } 1654 1655 return (r); 1656 } 1657 } 1658 1659 if (scf_iter_service_instances(iter, entity) != 0) { 1660 switch (scf_error()) { 1661 case SCF_ERROR_CONNECTION_BROKEN: 1662 return (ECONNABORTED); 1663 1664 case SCF_ERROR_DELETED: 1665 return (ECANCELED); 1666 1667 case SCF_ERROR_HANDLE_MISMATCH: 1668 case SCF_ERROR_NOT_BOUND: 1669 case SCF_ERROR_NOT_SET: 1670 default: 1671 bad_error("scf_iter_service_instances", scf_error()); 1672 } 1673 } 1674 1675 for (;;) { 1676 r = scf_iter_next_instance(iter, inst); 1677 if (r == 0) 1678 break; 1679 if (r != 1) { 1680 switch (scf_error()) { 1681 case SCF_ERROR_CONNECTION_BROKEN: 1682 return (ECONNABORTED); 1683 1684 case SCF_ERROR_DELETED: 1685 return (ECANCELED); 1686 1687 case SCF_ERROR_HANDLE_MISMATCH: 1688 case SCF_ERROR_NOT_BOUND: 1689 case SCF_ERROR_NOT_SET: 1690 case SCF_ERROR_INVALID_ARGUMENT: 1691 default: 1692 bad_error("scf_iter_next_instance", 1693 scf_error()); 1694 } 1695 } 1696 1697 /* 1698 * Similarly, just take a new running snapshot if operating on 1699 * a non-live repository or running during early import. 1700 */ 1701 if (est->sc_repo_filename != NULL || 1702 est->sc_repo_doorname != NULL || 1703 est->sc_in_emi == 1) { 1704 r = refresh_running_snapshot(inst); 1705 switch (r) { 1706 case 0: 1707 continue; 1708 1709 case ECONNABORTED: 1710 case ECANCELED: 1711 case EPERM: 1712 case ENOSPC: 1713 break; 1714 default: 1715 bad_error("refresh_running_snapshot", 1716 scf_error()); 1717 } 1718 1719 return (r); 1720 1721 } 1722 1723 if (_smf_refresh_instance_i(inst) == 0) { 1724 if (g_verbose) { 1725 if (scf_instance_get_name(inst, name_buf, 1726 max_scf_name_len + 1) < 0) 1727 (void) strcpy(name_buf, "?"); 1728 1729 warn(gettext("Refreshed %s:%s.\n"), 1730 fmri, name_buf); 1731 } 1732 } else { 1733 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1734 g_verbose) { 1735 scfe = scf_error(); 1736 1737 if (scf_instance_to_fmri(inst, name_buf, 1738 max_scf_name_len + 1) < 0) 1739 (void) strcpy(name_buf, "?"); 1740 1741 warn(gettext( 1742 "Refresh of %s:%s failed: %s.\n"), fmri, 1743 name_buf, scf_strerror(scfe)); 1744 } 1745 } 1746 } 1747 1748 return (0); 1749 } 1750 1751 static void 1752 private_refresh(void) 1753 { 1754 scf_instance_t *pinst = NULL; 1755 scf_iter_t *piter = NULL; 1756 ssize_t fmrilen; 1757 size_t bufsz; 1758 char *fmribuf; 1759 void *ent; 1760 int issvc; 1761 int r; 1762 1763 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1764 return; 1765 1766 assert(cur_svc != NULL); 1767 1768 bufsz = max_scf_fmri_len + 1; 1769 fmribuf = safe_malloc(bufsz); 1770 if (cur_inst) { 1771 issvc = 0; 1772 ent = cur_inst; 1773 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1774 } else { 1775 issvc = 1; 1776 ent = cur_svc; 1777 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1778 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1779 scfdie(); 1780 1781 if ((piter = scf_iter_create(g_hndl)) == NULL) 1782 scfdie(); 1783 } 1784 if (fmrilen < 0) { 1785 free(fmribuf); 1786 if (scf_error() != SCF_ERROR_DELETED) 1787 scfdie(); 1788 1789 warn(emsg_deleted); 1790 return; 1791 } 1792 assert(fmrilen < bufsz); 1793 1794 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1795 switch (r) { 1796 case 0: 1797 break; 1798 1799 case ECONNABORTED: 1800 warn(gettext("Could not refresh %s " 1801 "(repository connection broken).\n"), fmribuf); 1802 break; 1803 1804 case ECANCELED: 1805 warn(emsg_deleted); 1806 break; 1807 1808 case EPERM: 1809 warn(gettext("Could not refresh %s " 1810 "(permission denied).\n"), fmribuf); 1811 break; 1812 1813 case ENOSPC: 1814 warn(gettext("Could not refresh %s " 1815 "(repository server out of resources).\n"), 1816 fmribuf); 1817 break; 1818 1819 case EACCES: 1820 default: 1821 bad_error("refresh_entity", scf_error()); 1822 } 1823 1824 if (issvc) { 1825 scf_instance_destroy(pinst); 1826 scf_iter_destroy(piter); 1827 } 1828 1829 free(fmribuf); 1830 } 1831 1832 1833 static int 1834 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1835 { 1836 cbp->sc_err = scferror2errno(err); 1837 return (UU_WALK_ERROR); 1838 } 1839 1840 static int 1841 stash_scferror(scf_callback_t *cbp) 1842 { 1843 return (stash_scferror_err(cbp, scf_error())); 1844 } 1845 1846 static int select_inst(const char *); 1847 static int select_svc(const char *); 1848 1849 /* 1850 * Take a property that does not have a type and check to see if a type 1851 * exists or can be gleened from the current data. Set the type. 1852 * 1853 * Check the current level (instance) and then check the higher level 1854 * (service). This could be the case for adding a new property to 1855 * the instance that's going to "override" a service level property. 1856 * 1857 * For a property : 1858 * 1. Take the type from an existing property 1859 * 2. Take the type from a template entry 1860 * 1861 * If the type can not be found, then leave the type as is, and let the import 1862 * report the problem of the missing type. 1863 */ 1864 static int 1865 find_current_prop_type(void *p, void *g) 1866 { 1867 property_t *prop = p; 1868 scf_callback_t *lcb = g; 1869 pgroup_t *pg = NULL; 1870 1871 const char *fmri = NULL; 1872 char *lfmri = NULL; 1873 char *cur_selection = NULL; 1874 1875 scf_propertygroup_t *sc_pg = NULL; 1876 scf_property_t *sc_prop = NULL; 1877 scf_pg_tmpl_t *t_pg = NULL; 1878 scf_prop_tmpl_t *t_prop = NULL; 1879 scf_type_t prop_type; 1880 1881 value_t *vp; 1882 int issvc = lcb->sc_service; 1883 int r = UU_WALK_ERROR; 1884 1885 if (prop->sc_value_type != SCF_TYPE_INVALID) 1886 return (UU_WALK_NEXT); 1887 1888 t_prop = scf_tmpl_prop_create(g_hndl); 1889 sc_prop = scf_property_create(g_hndl); 1890 if (sc_prop == NULL || t_prop == NULL) { 1891 warn(gettext("Unable to create the property to attempt and " 1892 "find a missing type.\n")); 1893 1894 scf_property_destroy(sc_prop); 1895 scf_tmpl_prop_destroy(t_prop); 1896 1897 return (UU_WALK_ERROR); 1898 } 1899 1900 if (lcb->sc_flags == 1) { 1901 pg = lcb->sc_parent; 1902 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT); 1903 fmri = pg->sc_parent->sc_fmri; 1904 retry_pg: 1905 if (cur_svc && cur_selection == NULL) { 1906 cur_selection = safe_malloc(max_scf_fmri_len + 1); 1907 lscf_get_selection_str(cur_selection, 1908 max_scf_fmri_len + 1); 1909 1910 if (strcmp(cur_selection, fmri) != 0) { 1911 lscf_select(fmri); 1912 } else { 1913 free(cur_selection); 1914 cur_selection = NULL; 1915 } 1916 } else { 1917 lscf_select(fmri); 1918 } 1919 1920 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) { 1921 warn(gettext("Unable to create property group to " 1922 "find a missing property type.\n")); 1923 1924 goto out; 1925 } 1926 1927 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) { 1928 /* 1929 * If this is the sc_pg from the parent 1930 * let the caller clean up the sc_pg, 1931 * and just throw it away in this case. 1932 */ 1933 if (sc_pg != lcb->sc_parent) 1934 scf_pg_destroy(sc_pg); 1935 1936 sc_pg = NULL; 1937 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1938 warn(gettext("Unable to create template " 1939 "property group to find a property " 1940 "type.\n")); 1941 1942 goto out; 1943 } 1944 1945 if (scf_tmpl_get_by_pg_name(fmri, NULL, 1946 pg->sc_pgroup_name, NULL, t_pg, 1947 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) { 1948 /* 1949 * if instance get service and jump back 1950 */ 1951 scf_tmpl_pg_destroy(t_pg); 1952 t_pg = NULL; 1953 if (issvc == 0) { 1954 entity_t *e = pg->sc_parent->sc_parent; 1955 1956 fmri = e->sc_fmri; 1957 issvc = 1; 1958 goto retry_pg; 1959 } else { 1960 goto out; 1961 } 1962 } 1963 } 1964 } else { 1965 sc_pg = lcb->sc_parent; 1966 } 1967 1968 /* 1969 * Attempt to get the type from an existing property. If the property 1970 * cannot be found then attempt to get the type from a template entry 1971 * for the property. 1972 * 1973 * Finally, if at the instance level look at the service level. 1974 */ 1975 if (sc_pg != NULL && 1976 pg_get_prop(sc_pg, prop->sc_property_name, 1977 sc_prop) == SCF_SUCCESS && 1978 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) { 1979 prop->sc_value_type = prop_type; 1980 1981 /* 1982 * Found a type, update the value types and validate 1983 * the actual value against this type. 1984 */ 1985 for (vp = uu_list_first(prop->sc_property_values); 1986 vp != NULL; 1987 vp = uu_list_next(prop->sc_property_values, vp)) { 1988 vp->sc_type = prop->sc_value_type; 1989 lxml_store_value(vp, 0, NULL); 1990 } 1991 1992 r = UU_WALK_NEXT; 1993 goto out; 1994 } 1995 1996 /* 1997 * If we get here with t_pg set to NULL then we had to have 1998 * gotten an sc_pg but that sc_pg did not have the property 1999 * we are looking for. So if the t_pg is not null look up 2000 * the template entry for the property. 2001 * 2002 * If the t_pg is null then need to attempt to get a matching 2003 * template entry for the sc_pg, and see if there is a property 2004 * entry for that template entry. 2005 */ 2006 do_tmpl : 2007 if (t_pg != NULL && 2008 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name, 2009 t_prop, 0) == SCF_SUCCESS) { 2010 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) { 2011 prop->sc_value_type = prop_type; 2012 2013 /* 2014 * Found a type, update the value types and validate 2015 * the actual value against this type. 2016 */ 2017 for (vp = uu_list_first(prop->sc_property_values); 2018 vp != NULL; 2019 vp = uu_list_next(prop->sc_property_values, vp)) { 2020 vp->sc_type = prop->sc_value_type; 2021 lxml_store_value(vp, 0, NULL); 2022 } 2023 2024 r = UU_WALK_NEXT; 2025 goto out; 2026 } 2027 } else { 2028 if (t_pg == NULL && sc_pg) { 2029 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 2030 warn(gettext("Unable to create template " 2031 "property group to find a property " 2032 "type.\n")); 2033 2034 goto out; 2035 } 2036 2037 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) { 2038 scf_tmpl_pg_destroy(t_pg); 2039 t_pg = NULL; 2040 } else { 2041 goto do_tmpl; 2042 } 2043 } 2044 } 2045 2046 if (issvc == 0) { 2047 scf_instance_t *i; 2048 scf_service_t *s; 2049 2050 issvc = 1; 2051 if (lcb->sc_flags == 1) { 2052 entity_t *e = pg->sc_parent->sc_parent; 2053 2054 fmri = e->sc_fmri; 2055 goto retry_pg; 2056 } 2057 2058 /* 2059 * because lcb->sc_flags was not set then this means 2060 * the pg was not used and can be used here. 2061 */ 2062 if ((pg = internal_pgroup_new()) == NULL) { 2063 warn(gettext("Could not create internal property group " 2064 "to find a missing type.")); 2065 2066 goto out; 2067 } 2068 2069 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1); 2070 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name, 2071 max_scf_name_len + 1) < 0) 2072 goto out; 2073 2074 i = scf_instance_create(g_hndl); 2075 s = scf_service_create(g_hndl); 2076 if (i == NULL || s == NULL || 2077 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) { 2078 warn(gettext("Could not get a service for the instance " 2079 "to find a missing type.")); 2080 2081 goto out; 2082 } 2083 2084 /* 2085 * Check to see truly at the instance level. 2086 */ 2087 lfmri = safe_malloc(max_scf_fmri_len + 1); 2088 if (scf_instance_get_parent(i, s) == SCF_SUCCESS && 2089 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0) 2090 goto out; 2091 else 2092 fmri = (const char *)lfmri; 2093 2094 goto retry_pg; 2095 } 2096 2097 out : 2098 if (sc_pg != lcb->sc_parent) { 2099 scf_pg_destroy(sc_pg); 2100 } 2101 2102 /* 2103 * If this is true then the pg was allocated 2104 * here, and the name was set so need to free 2105 * the name and the pg. 2106 */ 2107 if (pg != NULL && pg != lcb->sc_parent) { 2108 free((char *)pg->sc_pgroup_name); 2109 internal_pgroup_free(pg); 2110 } 2111 2112 if (cur_selection) { 2113 lscf_select(cur_selection); 2114 free(cur_selection); 2115 } 2116 2117 scf_tmpl_pg_destroy(t_pg); 2118 scf_tmpl_prop_destroy(t_prop); 2119 scf_property_destroy(sc_prop); 2120 2121 if (r != UU_WALK_NEXT) 2122 warn(gettext("Could not find property type for \"%s\" " 2123 "from \"%s\"\n"), prop->sc_property_name, 2124 fmri != NULL ? fmri : lcb->sc_source_fmri); 2125 2126 free(lfmri); 2127 2128 return (r); 2129 } 2130 2131 /* 2132 * Take a property group that does not have a type and check to see if a type 2133 * exists or can be gleened from the current data. Set the type. 2134 * 2135 * Check the current level (instance) and then check the higher level 2136 * (service). This could be the case for adding a new property to 2137 * the instance that's going to "override" a service level property. 2138 * 2139 * For a property group 2140 * 1. Take the type from an existing property group 2141 * 2. Take the type from a template entry 2142 * 2143 * If the type can not be found, then leave the type as is, and let the import 2144 * report the problem of the missing type. 2145 */ 2146 static int 2147 find_current_pg_type(void *p, void *sori) 2148 { 2149 entity_t *si = sori; 2150 pgroup_t *pg = p; 2151 2152 const char *ofmri, *fmri; 2153 char *cur_selection = NULL; 2154 char *pg_type = NULL; 2155 2156 scf_propertygroup_t *sc_pg = NULL; 2157 scf_pg_tmpl_t *t_pg = NULL; 2158 2159 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2160 int r = UU_WALK_ERROR; 2161 2162 ofmri = fmri = si->sc_fmri; 2163 if (pg->sc_pgroup_type != NULL) { 2164 r = UU_WALK_NEXT; 2165 2166 goto out; 2167 } 2168 2169 sc_pg = scf_pg_create(g_hndl); 2170 if (sc_pg == NULL) { 2171 warn(gettext("Unable to create property group to attempt " 2172 "and find a missing type.\n")); 2173 2174 return (UU_WALK_ERROR); 2175 } 2176 2177 /* 2178 * Using get_pg() requires that the cur_svc/cur_inst be 2179 * via lscf_select. Need to preserve the current selection 2180 * if going to use lscf_select() to set up the cur_svc/cur_inst 2181 */ 2182 if (cur_svc) { 2183 cur_selection = safe_malloc(max_scf_fmri_len + 1); 2184 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1); 2185 } 2186 2187 /* 2188 * If the property group exists get the type, and set 2189 * the pgroup_t type of that type. 2190 * 2191 * If not the check for a template pg_pattern entry 2192 * and take the type from that. 2193 */ 2194 retry_svc: 2195 lscf_select(fmri); 2196 2197 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) { 2198 pg_type = safe_malloc(max_scf_pg_type_len + 1); 2199 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type, 2200 max_scf_pg_type_len + 1) != -1) { 2201 pg->sc_pgroup_type = pg_type; 2202 2203 r = UU_WALK_NEXT; 2204 goto out; 2205 } else { 2206 free(pg_type); 2207 } 2208 } else { 2209 if ((t_pg == NULL) && 2210 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) 2211 goto out; 2212 2213 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name, 2214 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS && 2215 scf_tmpl_pg_type(t_pg, &pg_type) != -1) { 2216 pg->sc_pgroup_type = pg_type; 2217 2218 r = UU_WALK_NEXT; 2219 goto out; 2220 } 2221 } 2222 2223 /* 2224 * If type is not found at the instance level then attempt to 2225 * find the type at the service level. 2226 */ 2227 if (!issvc) { 2228 si = si->sc_parent; 2229 fmri = si->sc_fmri; 2230 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2231 goto retry_svc; 2232 } 2233 2234 out : 2235 if (cur_selection) { 2236 lscf_select(cur_selection); 2237 free(cur_selection); 2238 } 2239 2240 /* 2241 * Now walk the properties of the property group to make sure that 2242 * all properties have the correct type and values are valid for 2243 * those types. 2244 */ 2245 if (r == UU_WALK_NEXT) { 2246 scf_callback_t cb; 2247 2248 cb.sc_service = issvc; 2249 cb.sc_source_fmri = ofmri; 2250 if (sc_pg != NULL) { 2251 cb.sc_parent = sc_pg; 2252 cb.sc_flags = 0; 2253 } else { 2254 cb.sc_parent = pg; 2255 cb.sc_flags = 1; 2256 } 2257 2258 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type, 2259 &cb, UU_DEFAULT) != 0) { 2260 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2261 bad_error("uu_list_walk", uu_error()); 2262 2263 r = UU_WALK_ERROR; 2264 } 2265 } else { 2266 warn(gettext("Could not find property group type for " 2267 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri); 2268 } 2269 2270 scf_tmpl_pg_destroy(t_pg); 2271 scf_pg_destroy(sc_pg); 2272 2273 return (r); 2274 } 2275 2276 /* 2277 * Import. These functions import a bundle into the repository. 2278 */ 2279 2280 /* 2281 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 2282 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 2283 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2284 * lcbdata->sc_err to 2285 * ENOMEM - out of memory 2286 * ECONNABORTED - repository connection broken 2287 * ECANCELED - sc_trans's property group was deleted 2288 * EINVAL - p's name is invalid (error printed) 2289 * - p has an invalid value (error printed) 2290 */ 2291 static int 2292 lscf_property_import(void *v, void *pvt) 2293 { 2294 property_t *p = v; 2295 scf_callback_t *lcbdata = pvt; 2296 value_t *vp; 2297 scf_transaction_t *trans = lcbdata->sc_trans; 2298 scf_transaction_entry_t *entr; 2299 scf_value_t *val; 2300 scf_type_t tp; 2301 2302 if ((lcbdata->sc_flags & SCI_NOENABLED || 2303 lcbdata->sc_flags & SCI_DELAYENABLE) && 2304 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 2305 lcbdata->sc_enable = p; 2306 return (UU_WALK_NEXT); 2307 } 2308 2309 entr = scf_entry_create(lcbdata->sc_handle); 2310 if (entr == NULL) { 2311 switch (scf_error()) { 2312 case SCF_ERROR_NO_MEMORY: 2313 return (stash_scferror(lcbdata)); 2314 2315 case SCF_ERROR_INVALID_ARGUMENT: 2316 default: 2317 bad_error("scf_entry_create", scf_error()); 2318 } 2319 } 2320 2321 tp = p->sc_value_type; 2322 2323 if (scf_transaction_property_new(trans, entr, 2324 p->sc_property_name, tp) != 0) { 2325 switch (scf_error()) { 2326 case SCF_ERROR_INVALID_ARGUMENT: 2327 semerr(emsg_invalid_prop_name, p->sc_property_name); 2328 scf_entry_destroy(entr); 2329 return (stash_scferror(lcbdata)); 2330 2331 case SCF_ERROR_EXISTS: 2332 break; 2333 2334 case SCF_ERROR_DELETED: 2335 case SCF_ERROR_CONNECTION_BROKEN: 2336 scf_entry_destroy(entr); 2337 return (stash_scferror(lcbdata)); 2338 2339 case SCF_ERROR_NOT_BOUND: 2340 case SCF_ERROR_HANDLE_MISMATCH: 2341 case SCF_ERROR_NOT_SET: 2342 default: 2343 bad_error("scf_transaction_property_new", scf_error()); 2344 } 2345 2346 if (scf_transaction_property_change_type(trans, entr, 2347 p->sc_property_name, tp) != 0) { 2348 switch (scf_error()) { 2349 case SCF_ERROR_DELETED: 2350 case SCF_ERROR_CONNECTION_BROKEN: 2351 scf_entry_destroy(entr); 2352 return (stash_scferror(lcbdata)); 2353 2354 case SCF_ERROR_INVALID_ARGUMENT: 2355 semerr(emsg_invalid_prop_name, 2356 p->sc_property_name); 2357 scf_entry_destroy(entr); 2358 return (stash_scferror(lcbdata)); 2359 2360 case SCF_ERROR_NOT_FOUND: 2361 case SCF_ERROR_NOT_SET: 2362 case SCF_ERROR_HANDLE_MISMATCH: 2363 case SCF_ERROR_NOT_BOUND: 2364 default: 2365 bad_error( 2366 "scf_transaction_property_change_type", 2367 scf_error()); 2368 } 2369 } 2370 } 2371 2372 for (vp = uu_list_first(p->sc_property_values); 2373 vp != NULL; 2374 vp = uu_list_next(p->sc_property_values, vp)) { 2375 val = scf_value_create(g_hndl); 2376 if (val == NULL) { 2377 switch (scf_error()) { 2378 case SCF_ERROR_NO_MEMORY: 2379 return (stash_scferror(lcbdata)); 2380 2381 case SCF_ERROR_INVALID_ARGUMENT: 2382 default: 2383 bad_error("scf_value_create", scf_error()); 2384 } 2385 } 2386 2387 switch (tp) { 2388 case SCF_TYPE_BOOLEAN: 2389 scf_value_set_boolean(val, vp->sc_u.sc_count); 2390 break; 2391 case SCF_TYPE_COUNT: 2392 scf_value_set_count(val, vp->sc_u.sc_count); 2393 break; 2394 case SCF_TYPE_INTEGER: 2395 scf_value_set_integer(val, vp->sc_u.sc_integer); 2396 break; 2397 default: 2398 assert(vp->sc_u.sc_string != NULL); 2399 if (scf_value_set_from_string(val, tp, 2400 vp->sc_u.sc_string) != 0) { 2401 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 2402 bad_error("scf_value_set_from_string", 2403 scf_error()); 2404 2405 warn(gettext("Value \"%s\" is not a valid " 2406 "%s.\n"), vp->sc_u.sc_string, 2407 scf_type_to_string(tp)); 2408 scf_value_destroy(val); 2409 return (stash_scferror(lcbdata)); 2410 } 2411 break; 2412 } 2413 2414 if (scf_entry_add_value(entr, val) != 0) 2415 bad_error("scf_entry_add_value", scf_error()); 2416 } 2417 2418 return (UU_WALK_NEXT); 2419 } 2420 2421 /* 2422 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 2423 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 2424 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 2425 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2426 * lcbdata->sc_err to 2427 * ECONNABORTED - repository connection broken 2428 * ENOMEM - out of memory 2429 * ENOSPC - svc.configd is out of resources 2430 * ECANCELED - sc_parent was deleted 2431 * EPERM - could not create property group (permission denied) (error printed) 2432 * - could not modify property group (permission denied) (error printed) 2433 * - could not delete property group (permission denied) (error printed) 2434 * EROFS - could not create property group (repository is read-only) 2435 * - could not delete property group (repository is read-only) 2436 * EACCES - could not create property group (backend access denied) 2437 * - could not delete property group (backend access denied) 2438 * EEXIST - could not create property group (already exists) 2439 * EINVAL - invalid property group name (error printed) 2440 * - invalid property name (error printed) 2441 * - invalid value (error printed) 2442 * EBUSY - new property group deleted (error printed) 2443 * - new property group changed (error printed) 2444 * - property group added (error printed) 2445 * - property group deleted (error printed) 2446 */ 2447 static int 2448 entity_pgroup_import(void *v, void *pvt) 2449 { 2450 pgroup_t *p = v; 2451 scf_callback_t cbdata; 2452 scf_callback_t *lcbdata = pvt; 2453 void *ent = lcbdata->sc_parent; 2454 int issvc = lcbdata->sc_service; 2455 int r; 2456 2457 const char * const pg_changed = gettext("%s changed unexpectedly " 2458 "(new property group \"%s\" changed).\n"); 2459 2460 /* Never import deleted property groups. */ 2461 if (p->sc_pgroup_delete) { 2462 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY && 2463 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) { 2464 goto delete_pg; 2465 } 2466 return (UU_WALK_NEXT); 2467 } 2468 2469 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 2470 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 2471 lcbdata->sc_general = p; 2472 return (UU_WALK_NEXT); 2473 } 2474 2475 add_pg: 2476 if (issvc) 2477 r = scf_service_add_pg(ent, p->sc_pgroup_name, 2478 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2479 else 2480 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 2481 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2482 if (r != 0) { 2483 switch (scf_error()) { 2484 case SCF_ERROR_DELETED: 2485 case SCF_ERROR_CONNECTION_BROKEN: 2486 case SCF_ERROR_BACKEND_READONLY: 2487 case SCF_ERROR_BACKEND_ACCESS: 2488 case SCF_ERROR_NO_RESOURCES: 2489 return (stash_scferror(lcbdata)); 2490 2491 case SCF_ERROR_EXISTS: 2492 if (lcbdata->sc_flags & SCI_FORCE) 2493 break; 2494 return (stash_scferror(lcbdata)); 2495 2496 case SCF_ERROR_INVALID_ARGUMENT: 2497 warn(emsg_fmri_invalid_pg_name_type, 2498 lcbdata->sc_source_fmri, 2499 p->sc_pgroup_name, p->sc_pgroup_type); 2500 return (stash_scferror(lcbdata)); 2501 2502 case SCF_ERROR_PERMISSION_DENIED: 2503 warn(emsg_pg_add_perm, p->sc_pgroup_name, 2504 lcbdata->sc_target_fmri); 2505 return (stash_scferror(lcbdata)); 2506 2507 case SCF_ERROR_NOT_BOUND: 2508 case SCF_ERROR_HANDLE_MISMATCH: 2509 case SCF_ERROR_NOT_SET: 2510 default: 2511 bad_error("scf_service_add_pg", scf_error()); 2512 } 2513 2514 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2515 switch (scf_error()) { 2516 case SCF_ERROR_CONNECTION_BROKEN: 2517 case SCF_ERROR_DELETED: 2518 return (stash_scferror(lcbdata)); 2519 2520 case SCF_ERROR_INVALID_ARGUMENT: 2521 warn(emsg_fmri_invalid_pg_name, 2522 lcbdata->sc_source_fmri, 2523 p->sc_pgroup_name); 2524 return (stash_scferror(lcbdata)); 2525 2526 case SCF_ERROR_NOT_FOUND: 2527 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2528 p->sc_pgroup_name); 2529 lcbdata->sc_err = EBUSY; 2530 return (UU_WALK_ERROR); 2531 2532 case SCF_ERROR_NOT_BOUND: 2533 case SCF_ERROR_HANDLE_MISMATCH: 2534 case SCF_ERROR_NOT_SET: 2535 default: 2536 bad_error("entity_get_pg", scf_error()); 2537 } 2538 } 2539 2540 if (lcbdata->sc_flags & SCI_KEEP) 2541 goto props; 2542 2543 delete_pg: 2544 if (scf_pg_delete(imp_pg) != 0) { 2545 switch (scf_error()) { 2546 case SCF_ERROR_DELETED: 2547 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2548 p->sc_pgroup_name); 2549 lcbdata->sc_err = EBUSY; 2550 return (UU_WALK_ERROR); 2551 2552 case SCF_ERROR_PERMISSION_DENIED: 2553 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2554 lcbdata->sc_target_fmri); 2555 return (stash_scferror(lcbdata)); 2556 2557 case SCF_ERROR_BACKEND_READONLY: 2558 case SCF_ERROR_BACKEND_ACCESS: 2559 case SCF_ERROR_CONNECTION_BROKEN: 2560 return (stash_scferror(lcbdata)); 2561 2562 case SCF_ERROR_NOT_SET: 2563 default: 2564 bad_error("scf_pg_delete", scf_error()); 2565 } 2566 } 2567 2568 if (p->sc_pgroup_delete) 2569 return (UU_WALK_NEXT); 2570 2571 goto add_pg; 2572 } 2573 2574 props: 2575 2576 /* 2577 * Add properties to property group, if any. 2578 */ 2579 cbdata.sc_handle = lcbdata->sc_handle; 2580 cbdata.sc_parent = imp_pg; 2581 cbdata.sc_flags = lcbdata->sc_flags; 2582 cbdata.sc_trans = imp_tx; 2583 cbdata.sc_enable = NULL; 2584 2585 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2586 switch (scf_error()) { 2587 case SCF_ERROR_BACKEND_ACCESS: 2588 case SCF_ERROR_BACKEND_READONLY: 2589 case SCF_ERROR_CONNECTION_BROKEN: 2590 return (stash_scferror(lcbdata)); 2591 2592 case SCF_ERROR_DELETED: 2593 warn(pg_changed, lcbdata->sc_target_fmri, 2594 p->sc_pgroup_name); 2595 lcbdata->sc_err = EBUSY; 2596 return (UU_WALK_ERROR); 2597 2598 case SCF_ERROR_PERMISSION_DENIED: 2599 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2600 lcbdata->sc_target_fmri); 2601 return (stash_scferror(lcbdata)); 2602 2603 case SCF_ERROR_NOT_BOUND: 2604 case SCF_ERROR_NOT_SET: 2605 case SCF_ERROR_IN_USE: 2606 case SCF_ERROR_HANDLE_MISMATCH: 2607 default: 2608 bad_error("scf_transaction_start", scf_error()); 2609 } 2610 } 2611 2612 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2613 UU_DEFAULT) != 0) { 2614 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2615 bad_error("uu_list_walk", uu_error()); 2616 scf_transaction_reset(imp_tx); 2617 2618 lcbdata->sc_err = cbdata.sc_err; 2619 if (cbdata.sc_err == ECANCELED) { 2620 warn(pg_changed, lcbdata->sc_target_fmri, 2621 p->sc_pgroup_name); 2622 lcbdata->sc_err = EBUSY; 2623 } 2624 return (UU_WALK_ERROR); 2625 } 2626 2627 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2628 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2629 2630 /* 2631 * take the snapshot running snapshot then 2632 * import the stored general/enable property 2633 */ 2634 r = take_snap(ent, snap_running, imp_rsnap); 2635 switch (r) { 2636 case 0: 2637 break; 2638 2639 case ECONNABORTED: 2640 warn(gettext("Could not take %s snapshot on import " 2641 "(repository connection broken).\n"), 2642 snap_running); 2643 lcbdata->sc_err = r; 2644 return (UU_WALK_ERROR); 2645 case ECANCELED: 2646 warn(emsg_deleted); 2647 lcbdata->sc_err = r; 2648 return (UU_WALK_ERROR); 2649 2650 case EPERM: 2651 warn(gettext("Could not take %s snapshot " 2652 "(permission denied).\n"), snap_running); 2653 lcbdata->sc_err = r; 2654 return (UU_WALK_ERROR); 2655 2656 case ENOSPC: 2657 warn(gettext("Could not take %s snapshot" 2658 "(repository server out of resources).\n"), 2659 snap_running); 2660 lcbdata->sc_err = r; 2661 return (UU_WALK_ERROR); 2662 2663 default: 2664 bad_error("take_snap", r); 2665 } 2666 2667 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2668 if (r != UU_WALK_NEXT) { 2669 if (r != UU_WALK_ERROR) 2670 bad_error("lscf_property_import", r); 2671 return (EINVAL); 2672 } 2673 } 2674 2675 r = scf_transaction_commit(imp_tx); 2676 switch (r) { 2677 case 1: 2678 r = UU_WALK_NEXT; 2679 break; 2680 2681 case 0: 2682 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2683 lcbdata->sc_err = EBUSY; 2684 r = UU_WALK_ERROR; 2685 break; 2686 2687 case -1: 2688 switch (scf_error()) { 2689 case SCF_ERROR_BACKEND_READONLY: 2690 case SCF_ERROR_BACKEND_ACCESS: 2691 case SCF_ERROR_CONNECTION_BROKEN: 2692 case SCF_ERROR_NO_RESOURCES: 2693 r = stash_scferror(lcbdata); 2694 break; 2695 2696 case SCF_ERROR_DELETED: 2697 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2698 p->sc_pgroup_name); 2699 lcbdata->sc_err = EBUSY; 2700 r = UU_WALK_ERROR; 2701 break; 2702 2703 case SCF_ERROR_PERMISSION_DENIED: 2704 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2705 lcbdata->sc_target_fmri); 2706 r = stash_scferror(lcbdata); 2707 break; 2708 2709 case SCF_ERROR_NOT_SET: 2710 case SCF_ERROR_INVALID_ARGUMENT: 2711 case SCF_ERROR_NOT_BOUND: 2712 default: 2713 bad_error("scf_transaction_commit", scf_error()); 2714 } 2715 break; 2716 2717 default: 2718 bad_error("scf_transaction_commit", r); 2719 } 2720 2721 scf_transaction_destroy_children(imp_tx); 2722 2723 return (r); 2724 } 2725 2726 /* 2727 * Returns 2728 * 0 - success 2729 * ECONNABORTED - repository connection broken 2730 * ENOMEM - out of memory 2731 * ENOSPC - svc.configd is out of resources 2732 * ECANCELED - inst was deleted 2733 * EPERM - could not create property group (permission denied) (error printed) 2734 * - could not modify property group (permission denied) (error printed) 2735 * EROFS - could not create property group (repository is read-only) 2736 * EACCES - could not create property group (backend access denied) 2737 * EEXIST - could not create property group (already exists) 2738 * EINVAL - invalid property group name (error printed) 2739 * - invalid property name (error printed) 2740 * - invalid value (error printed) 2741 * EBUSY - new property group changed (error printed) 2742 */ 2743 static int 2744 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2745 const entity_t *isvc, int flags) 2746 { 2747 scf_callback_t cbdata; 2748 2749 cbdata.sc_handle = scf_service_handle(svc); 2750 cbdata.sc_parent = svc; 2751 cbdata.sc_service = 1; 2752 cbdata.sc_general = 0; 2753 cbdata.sc_enable = 0; 2754 cbdata.sc_flags = flags; 2755 cbdata.sc_source_fmri = isvc->sc_fmri; 2756 cbdata.sc_target_fmri = target_fmri; 2757 2758 /* 2759 * If the op is set, then add the flag to the callback 2760 * flags for later use. 2761 */ 2762 if (isvc->sc_op != SVCCFG_OP_NONE) { 2763 switch (isvc->sc_op) { 2764 case SVCCFG_OP_IMPORT : 2765 cbdata.sc_flags |= SCI_OP_IMPORT; 2766 break; 2767 case SVCCFG_OP_APPLY : 2768 cbdata.sc_flags |= SCI_OP_APPLY; 2769 break; 2770 case SVCCFG_OP_RESTORE : 2771 cbdata.sc_flags |= SCI_OP_RESTORE; 2772 break; 2773 default : 2774 uu_die(gettext("lscf_import_service_pgs : " 2775 "Unknown op stored in the service entity\n")); 2776 2777 } 2778 } 2779 2780 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2781 UU_DEFAULT) != 0) { 2782 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2783 bad_error("uu_list_walk", uu_error()); 2784 2785 return (cbdata.sc_err); 2786 } 2787 2788 return (0); 2789 } 2790 2791 /* 2792 * Returns 2793 * 0 - success 2794 * ECONNABORTED - repository connection broken 2795 * ENOMEM - out of memory 2796 * ENOSPC - svc.configd is out of resources 2797 * ECANCELED - inst was deleted 2798 * EPERM - could not create property group (permission denied) (error printed) 2799 * - could not modify property group (permission denied) (error printed) 2800 * EROFS - could not create property group (repository is read-only) 2801 * EACCES - could not create property group (backend access denied) 2802 * EEXIST - could not create property group (already exists) 2803 * EINVAL - invalid property group name (error printed) 2804 * - invalid property name (error printed) 2805 * - invalid value (error printed) 2806 * EBUSY - new property group changed (error printed) 2807 */ 2808 static int 2809 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2810 const entity_t *iinst, int flags) 2811 { 2812 scf_callback_t cbdata; 2813 2814 cbdata.sc_handle = scf_instance_handle(inst); 2815 cbdata.sc_parent = inst; 2816 cbdata.sc_service = 0; 2817 cbdata.sc_general = NULL; 2818 cbdata.sc_enable = NULL; 2819 cbdata.sc_flags = flags; 2820 cbdata.sc_source_fmri = iinst->sc_fmri; 2821 cbdata.sc_target_fmri = target_fmri; 2822 2823 /* 2824 * If the op is set, then add the flag to the callback 2825 * flags for later use. 2826 */ 2827 if (iinst->sc_op != SVCCFG_OP_NONE) { 2828 switch (iinst->sc_op) { 2829 case SVCCFG_OP_IMPORT : 2830 cbdata.sc_flags |= SCI_OP_IMPORT; 2831 break; 2832 case SVCCFG_OP_APPLY : 2833 cbdata.sc_flags |= SCI_OP_APPLY; 2834 break; 2835 case SVCCFG_OP_RESTORE : 2836 cbdata.sc_flags |= SCI_OP_RESTORE; 2837 break; 2838 default : 2839 uu_die(gettext("lscf_import_instance_pgs : " 2840 "Unknown op stored in the instance entity\n")); 2841 } 2842 } 2843 2844 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2845 UU_DEFAULT) != 0) { 2846 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2847 bad_error("uu_list_walk", uu_error()); 2848 2849 return (cbdata.sc_err); 2850 } 2851 2852 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2853 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2854 /* 2855 * If importing with the SCI_NOENABLED flag then 2856 * skip the delay, but if not then add the delay 2857 * of the enable property. 2858 */ 2859 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2860 cbdata.sc_flags |= SCI_DELAYENABLE; 2861 } 2862 2863 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2864 != UU_WALK_NEXT) 2865 return (cbdata.sc_err); 2866 } 2867 2868 return (0); 2869 } 2870 2871 /* 2872 * Report the reasons why we can't upgrade pg2 to pg1. 2873 */ 2874 static void 2875 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2876 int new) 2877 { 2878 property_t *p1, *p2; 2879 2880 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2881 2882 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2883 return; 2884 2885 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2886 p1 != NULL; 2887 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2888 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2889 if (p2 != NULL) { 2890 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2891 new); 2892 continue; 2893 } 2894 2895 if (new) 2896 warn(gettext("Conflict upgrading %s (new property " 2897 "group \"%s\" is missing property \"%s\").\n"), 2898 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2899 else 2900 warn(gettext("Conflict upgrading %s (property " 2901 "\"%s/%s\" is missing).\n"), fmri, 2902 pg1->sc_pgroup_name, p1->sc_property_name); 2903 } 2904 2905 /* 2906 * Since pg1 should be from the manifest, any properties in pg2 which 2907 * aren't in pg1 shouldn't be reported as conflicts. 2908 */ 2909 } 2910 2911 /* 2912 * Add transaction entries to tx which will upgrade cur's pg according to old 2913 * & new. 2914 * 2915 * Returns 2916 * 0 - success 2917 * EINVAL - new has a property with an invalid name or value (message emitted) 2918 * ENOMEM - out of memory 2919 */ 2920 static int 2921 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2922 pgroup_t *cur, int speak, const char *fmri) 2923 { 2924 property_t *p, *new_p, *cur_p; 2925 scf_transaction_entry_t *e; 2926 int r; 2927 int is_general; 2928 int is_protected; 2929 2930 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2931 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2932 bad_error("uu_list_walk", uu_error()); 2933 2934 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2935 2936 for (p = uu_list_first(old->sc_pgroup_props); 2937 p != NULL; 2938 p = uu_list_next(old->sc_pgroup_props, p)) { 2939 /* p is a property in the old property group. */ 2940 2941 /* Protect live properties. */ 2942 is_protected = 0; 2943 if (is_general) { 2944 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2945 0 || 2946 strcmp(p->sc_property_name, 2947 SCF_PROPERTY_RESTARTER) == 0) 2948 is_protected = 1; 2949 } 2950 2951 /* Look for the same property in the new properties. */ 2952 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2953 if (new_p != NULL) { 2954 new_p->sc_seen = 1; 2955 2956 /* 2957 * If the new property is the same as the old, don't do 2958 * anything (leave any user customizations). 2959 */ 2960 if (prop_equal(p, new_p, NULL, NULL, 0)) 2961 continue; 2962 2963 if (new_p->sc_property_override) 2964 goto upgrade; 2965 } 2966 2967 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2968 if (cur_p == NULL) { 2969 /* 2970 * p has been deleted from the repository. If we were 2971 * going to delete it anyway, do nothing. Otherwise 2972 * report a conflict. 2973 */ 2974 if (new_p == NULL) 2975 continue; 2976 2977 if (is_protected) 2978 continue; 2979 2980 warn(gettext("Conflict upgrading %s " 2981 "(property \"%s/%s\" is missing).\n"), fmri, 2982 old->sc_pgroup_name, p->sc_property_name); 2983 continue; 2984 } 2985 2986 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2987 /* 2988 * Conflict. Don't warn if the property is already the 2989 * way we want it, though. 2990 */ 2991 if (is_protected) 2992 continue; 2993 2994 if (new_p == NULL) 2995 (void) prop_equal(p, cur_p, fmri, 2996 old->sc_pgroup_name, 0); 2997 else 2998 (void) prop_equal(cur_p, new_p, fmri, 2999 old->sc_pgroup_name, 0); 3000 continue; 3001 } 3002 3003 if (is_protected) { 3004 if (speak) 3005 warn(gettext("%s: Refusing to upgrade " 3006 "\"%s/%s\" (live property).\n"), fmri, 3007 old->sc_pgroup_name, p->sc_property_name); 3008 continue; 3009 } 3010 3011 upgrade: 3012 /* p hasn't been customized in the repository. Upgrade it. */ 3013 if (new_p == NULL) { 3014 /* p was deleted. Delete from cur if unchanged. */ 3015 if (speak) 3016 warn(gettext( 3017 "%s: Deleting property \"%s/%s\".\n"), 3018 fmri, old->sc_pgroup_name, 3019 p->sc_property_name); 3020 3021 e = scf_entry_create(g_hndl); 3022 if (e == NULL) 3023 return (ENOMEM); 3024 3025 if (scf_transaction_property_delete(tx, e, 3026 p->sc_property_name) != 0) { 3027 switch (scf_error()) { 3028 case SCF_ERROR_DELETED: 3029 scf_entry_destroy(e); 3030 return (ECANCELED); 3031 3032 case SCF_ERROR_CONNECTION_BROKEN: 3033 scf_entry_destroy(e); 3034 return (ECONNABORTED); 3035 3036 case SCF_ERROR_NOT_FOUND: 3037 /* 3038 * This can happen if cur is from the 3039 * running snapshot (and it differs 3040 * from the live properties). 3041 */ 3042 scf_entry_destroy(e); 3043 break; 3044 3045 case SCF_ERROR_HANDLE_MISMATCH: 3046 case SCF_ERROR_NOT_BOUND: 3047 case SCF_ERROR_NOT_SET: 3048 case SCF_ERROR_INVALID_ARGUMENT: 3049 default: 3050 bad_error( 3051 "scf_transaction_property_delete", 3052 scf_error()); 3053 } 3054 } 3055 } else { 3056 scf_callback_t ctx; 3057 3058 if (speak) 3059 warn(gettext( 3060 "%s: Upgrading property \"%s/%s\".\n"), 3061 fmri, old->sc_pgroup_name, 3062 p->sc_property_name); 3063 3064 ctx.sc_handle = g_hndl; 3065 ctx.sc_trans = tx; 3066 ctx.sc_flags = 0; 3067 3068 r = lscf_property_import(new_p, &ctx); 3069 if (r != UU_WALK_NEXT) { 3070 if (r != UU_WALK_ERROR) 3071 bad_error("lscf_property_import", r); 3072 return (EINVAL); 3073 } 3074 } 3075 } 3076 3077 /* Go over the properties which were added. */ 3078 for (new_p = uu_list_first(new->sc_pgroup_props); 3079 new_p != NULL; 3080 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 3081 if (new_p->sc_seen) 3082 continue; 3083 3084 /* This is a new property. */ 3085 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 3086 if (cur_p == NULL) { 3087 scf_callback_t ctx; 3088 3089 ctx.sc_handle = g_hndl; 3090 ctx.sc_trans = tx; 3091 ctx.sc_flags = 0; 3092 3093 r = lscf_property_import(new_p, &ctx); 3094 if (r != UU_WALK_NEXT) { 3095 if (r != UU_WALK_ERROR) 3096 bad_error("lscf_property_import", r); 3097 return (EINVAL); 3098 } 3099 continue; 3100 } 3101 3102 /* 3103 * Report a conflict if the new property differs from the 3104 * current one. Unless it's general/enabled, since that's 3105 * never in the last-import snapshot. 3106 */ 3107 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 3108 0 && 3109 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 3110 continue; 3111 3112 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 3113 } 3114 3115 return (0); 3116 } 3117 3118 /* 3119 * Upgrade pg according to old & new. 3120 * 3121 * Returns 3122 * 0 - success 3123 * ECONNABORTED - repository connection broken 3124 * ENOMEM - out of memory 3125 * ENOSPC - svc.configd is out of resources 3126 * ECANCELED - pg was deleted 3127 * EPERM - couldn't modify pg (permission denied) 3128 * EROFS - couldn't modify pg (backend read-only) 3129 * EACCES - couldn't modify pg (backend access denied) 3130 * EINVAL - new has a property with invalid name or value (error printed) 3131 * EBUSY - pg changed unexpectedly 3132 */ 3133 static int 3134 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 3135 pgroup_t *new, int speak, const char *fmri) 3136 { 3137 int r; 3138 3139 if (scf_transaction_start(imp_tx, pg) != 0) { 3140 switch (scf_error()) { 3141 case SCF_ERROR_CONNECTION_BROKEN: 3142 case SCF_ERROR_DELETED: 3143 case SCF_ERROR_PERMISSION_DENIED: 3144 case SCF_ERROR_BACKEND_READONLY: 3145 case SCF_ERROR_BACKEND_ACCESS: 3146 return (scferror2errno(scf_error())); 3147 3148 case SCF_ERROR_HANDLE_MISMATCH: 3149 case SCF_ERROR_IN_USE: 3150 case SCF_ERROR_NOT_BOUND: 3151 case SCF_ERROR_NOT_SET: 3152 default: 3153 bad_error("scf_transaction_start", scf_error()); 3154 } 3155 } 3156 3157 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 3158 switch (r) { 3159 case 0: 3160 break; 3161 3162 case EINVAL: 3163 case ENOMEM: 3164 scf_transaction_destroy_children(imp_tx); 3165 return (r); 3166 3167 default: 3168 bad_error("add_upgrade_entries", r); 3169 } 3170 3171 r = scf_transaction_commit(imp_tx); 3172 3173 scf_transaction_destroy_children(imp_tx); 3174 3175 switch (r) { 3176 case 1: 3177 break; 3178 3179 case 0: 3180 return (EBUSY); 3181 3182 case -1: 3183 switch (scf_error()) { 3184 case SCF_ERROR_CONNECTION_BROKEN: 3185 case SCF_ERROR_NO_RESOURCES: 3186 case SCF_ERROR_PERMISSION_DENIED: 3187 case SCF_ERROR_BACKEND_READONLY: 3188 case SCF_ERROR_BACKEND_ACCESS: 3189 case SCF_ERROR_DELETED: 3190 return (scferror2errno(scf_error())); 3191 3192 case SCF_ERROR_NOT_BOUND: 3193 case SCF_ERROR_INVALID_ARGUMENT: 3194 case SCF_ERROR_NOT_SET: 3195 default: 3196 bad_error("scf_transaction_commit", scf_error()); 3197 } 3198 3199 default: 3200 bad_error("scf_transaction_commit", r); 3201 } 3202 3203 return (0); 3204 } 3205 3206 /* 3207 * Compares two entity FMRIs. Returns 3208 * 3209 * 1 - equal 3210 * 0 - not equal 3211 * -1 - f1 is invalid or not an entity 3212 * -2 - f2 is invalid or not an entity 3213 */ 3214 static int 3215 fmri_equal(const char *f1, const char *f2) 3216 { 3217 int r; 3218 const char *s1, *i1, *pg1; 3219 const char *s2, *i2, *pg2; 3220 3221 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3222 return (-1); 3223 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 3224 return (-1); 3225 3226 if (s1 == NULL || pg1 != NULL) 3227 return (-1); 3228 3229 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3230 return (-2); 3231 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 3232 return (-2); 3233 3234 if (s2 == NULL || pg2 != NULL) 3235 return (-2); 3236 3237 r = strcmp(s1, s2); 3238 if (r != 0) 3239 return (0); 3240 3241 if (i1 == NULL && i2 == NULL) 3242 return (1); 3243 3244 if (i1 == NULL || i2 == NULL) 3245 return (0); 3246 3247 return (strcmp(i1, i2) == 0); 3248 } 3249 3250 /* 3251 * Import a dependent by creating a dependency property group in the dependent 3252 * entity. If lcbdata->sc_trans is set, assume it's been started on the 3253 * dependents pg, and add an entry to create a new property for this 3254 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 3255 * 3256 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 3257 * lcbdata->sc_err to 3258 * ECONNABORTED - repository connection broken 3259 * ENOMEM - out of memory 3260 * ENOSPC - configd is out of resources 3261 * EINVAL - target is invalid (error printed) 3262 * - target is not an entity (error printed) 3263 * - dependent has invalid name (error printed) 3264 * - invalid property name (error printed) 3265 * - invalid value (error printed) 3266 * - scope of target does not exist (error printed) 3267 * EPERM - couldn't create target (permission denied) (error printed) 3268 * - couldn't create dependency pg (permission denied) (error printed) 3269 * - couldn't modify dependency pg (permission denied) (error printed) 3270 * EROFS - couldn't create target (repository read-only) 3271 * - couldn't create dependency pg (repository read-only) 3272 * EACCES - couldn't create target (backend access denied) 3273 * - couldn't create dependency pg (backend access denied) 3274 * ECANCELED - sc_trans's pg was deleted 3275 * EALREADY - property for dependent already exists in sc_trans's pg 3276 * EEXIST - dependency pg already exists in target (error printed) 3277 * EBUSY - target deleted (error printed) 3278 * - property group changed during import (error printed) 3279 */ 3280 static int 3281 lscf_dependent_import(void *a1, void *pvt) 3282 { 3283 pgroup_t *pgrp = a1; 3284 scf_callback_t *lcbdata = pvt; 3285 3286 int isservice; 3287 int ret; 3288 scf_transaction_entry_t *e; 3289 scf_value_t *val; 3290 scf_callback_t dependent_cbdata; 3291 scf_error_t scfe; 3292 3293 /* 3294 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 3295 * it's invalid, we fail before modifying the repository. 3296 */ 3297 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3298 &dependent_cbdata.sc_parent, &isservice); 3299 switch (scfe) { 3300 case SCF_ERROR_NONE: 3301 break; 3302 3303 case SCF_ERROR_NO_MEMORY: 3304 return (stash_scferror_err(lcbdata, scfe)); 3305 3306 case SCF_ERROR_INVALID_ARGUMENT: 3307 semerr(gettext("The FMRI for the \"%s\" dependent is " 3308 "invalid.\n"), pgrp->sc_pgroup_name); 3309 return (stash_scferror_err(lcbdata, scfe)); 3310 3311 case SCF_ERROR_CONSTRAINT_VIOLATED: 3312 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 3313 "specifies neither a service nor an instance.\n"), 3314 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3315 return (stash_scferror_err(lcbdata, scfe)); 3316 3317 case SCF_ERROR_NOT_FOUND: 3318 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3319 &dependent_cbdata.sc_parent, &isservice); 3320 switch (scfe) { 3321 case SCF_ERROR_NONE: 3322 break; 3323 3324 case SCF_ERROR_NO_MEMORY: 3325 case SCF_ERROR_BACKEND_READONLY: 3326 case SCF_ERROR_BACKEND_ACCESS: 3327 return (stash_scferror_err(lcbdata, scfe)); 3328 3329 case SCF_ERROR_NOT_FOUND: 3330 semerr(gettext("The scope in FMRI \"%s\" for the " 3331 "\"%s\" dependent does not exist.\n"), 3332 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3333 lcbdata->sc_err = EINVAL; 3334 return (UU_WALK_ERROR); 3335 3336 case SCF_ERROR_PERMISSION_DENIED: 3337 warn(gettext( 3338 "Could not create %s (permission denied).\n"), 3339 pgrp->sc_pgroup_fmri); 3340 return (stash_scferror_err(lcbdata, scfe)); 3341 3342 case SCF_ERROR_INVALID_ARGUMENT: 3343 case SCF_ERROR_CONSTRAINT_VIOLATED: 3344 default: 3345 bad_error("create_entity", scfe); 3346 } 3347 break; 3348 3349 default: 3350 bad_error("fmri_to_entity", scfe); 3351 } 3352 3353 if (lcbdata->sc_trans != NULL) { 3354 e = scf_entry_create(lcbdata->sc_handle); 3355 if (e == NULL) { 3356 if (scf_error() != SCF_ERROR_NO_MEMORY) 3357 bad_error("scf_entry_create", scf_error()); 3358 3359 entity_destroy(dependent_cbdata.sc_parent, isservice); 3360 return (stash_scferror(lcbdata)); 3361 } 3362 3363 if (scf_transaction_property_new(lcbdata->sc_trans, e, 3364 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 3365 switch (scf_error()) { 3366 case SCF_ERROR_INVALID_ARGUMENT: 3367 warn(gettext("Dependent of %s has invalid name " 3368 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 3369 pgrp->sc_pgroup_name); 3370 /* FALLTHROUGH */ 3371 3372 case SCF_ERROR_DELETED: 3373 case SCF_ERROR_CONNECTION_BROKEN: 3374 scf_entry_destroy(e); 3375 entity_destroy(dependent_cbdata.sc_parent, 3376 isservice); 3377 return (stash_scferror(lcbdata)); 3378 3379 case SCF_ERROR_EXISTS: 3380 scf_entry_destroy(e); 3381 entity_destroy(dependent_cbdata.sc_parent, 3382 isservice); 3383 lcbdata->sc_err = EALREADY; 3384 return (UU_WALK_ERROR); 3385 3386 case SCF_ERROR_NOT_BOUND: 3387 case SCF_ERROR_HANDLE_MISMATCH: 3388 case SCF_ERROR_NOT_SET: 3389 default: 3390 bad_error("scf_transaction_property_new", 3391 scf_error()); 3392 } 3393 } 3394 3395 val = scf_value_create(lcbdata->sc_handle); 3396 if (val == NULL) { 3397 if (scf_error() != SCF_ERROR_NO_MEMORY) 3398 bad_error("scf_value_create", scf_error()); 3399 3400 entity_destroy(dependent_cbdata.sc_parent, isservice); 3401 return (stash_scferror(lcbdata)); 3402 } 3403 3404 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3405 pgrp->sc_pgroup_fmri) != 0) 3406 /* invalid should have been caught above */ 3407 bad_error("scf_value_set_from_string", scf_error()); 3408 3409 if (scf_entry_add_value(e, val) != 0) 3410 bad_error("scf_entry_add_value", scf_error()); 3411 } 3412 3413 /* Add the property group to the target entity. */ 3414 3415 dependent_cbdata.sc_handle = lcbdata->sc_handle; 3416 dependent_cbdata.sc_flags = lcbdata->sc_flags; 3417 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 3418 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 3419 3420 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 3421 3422 entity_destroy(dependent_cbdata.sc_parent, isservice); 3423 3424 if (ret == UU_WALK_NEXT) 3425 return (ret); 3426 3427 if (ret != UU_WALK_ERROR) 3428 bad_error("entity_pgroup_import", ret); 3429 3430 switch (dependent_cbdata.sc_err) { 3431 case ECANCELED: 3432 warn(gettext("%s deleted unexpectedly.\n"), 3433 pgrp->sc_pgroup_fmri); 3434 lcbdata->sc_err = EBUSY; 3435 break; 3436 3437 case EEXIST: 3438 warn(gettext("Could not create \"%s\" dependency in %s " 3439 "(already exists).\n"), pgrp->sc_pgroup_name, 3440 pgrp->sc_pgroup_fmri); 3441 /* FALLTHROUGH */ 3442 3443 default: 3444 lcbdata->sc_err = dependent_cbdata.sc_err; 3445 } 3446 3447 return (UU_WALK_ERROR); 3448 } 3449 3450 static int upgrade_dependent(const scf_property_t *, const entity_t *, 3451 const scf_snaplevel_t *, scf_transaction_t *); 3452 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 3453 const pgroup_t *); 3454 3455 /* 3456 * Upgrade uncustomized dependents of ent to those specified in ient. Read 3457 * the current dependent targets from running (the snaplevel of a running 3458 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 3459 * scf_instance_t * according to ient, otherwise). Draw the ancestral 3460 * dependent targets and dependency properties from li_dpts_pg (the 3461 * "dependents" property group in snpl) and snpl (the snaplevel which 3462 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 3463 * snpl doesn't have a "dependents" property group, and any dependents in ient 3464 * are new. 3465 * 3466 * Returns 3467 * 0 - success 3468 * ECONNABORTED - repository connection broken 3469 * ENOMEM - out of memory 3470 * ENOSPC - configd is out of resources 3471 * ECANCELED - ent was deleted 3472 * ENODEV - the entity containing li_dpts_pg was deleted 3473 * EPERM - could not modify dependents pg (permission denied) (error printed) 3474 * - couldn't upgrade dependent (permission denied) (error printed) 3475 * - couldn't create dependent (permission denied) (error printed) 3476 * EROFS - could not modify dependents pg (repository read-only) 3477 * - couldn't upgrade dependent (repository read-only) 3478 * - couldn't create dependent (repository read-only) 3479 * EACCES - could not modify dependents pg (backend access denied) 3480 * - could not upgrade dependent (backend access denied) 3481 * - could not create dependent (backend access denied) 3482 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 3483 * - dependent target deleted (error printed) 3484 * - dependent pg changed (error printed) 3485 * EINVAL - new dependent is invalid (error printed) 3486 * EBADF - snpl is corrupt (error printed) 3487 * - snpl has corrupt pg (error printed) 3488 * - dependency pg in target is corrupt (error printed) 3489 * - target has corrupt snapshot (error printed) 3490 * EEXIST - dependency pg already existed in target service (error printed) 3491 */ 3492 static int 3493 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 3494 const scf_snaplevel_t *snpl, const entity_t *ient, 3495 const scf_snaplevel_t *running, void *ent) 3496 { 3497 pgroup_t *new_dpt_pgroup; 3498 scf_callback_t cbdata; 3499 int r, unseen, tx_started = 0; 3500 int have_cur_depts; 3501 3502 const char * const dependents = "dependents"; 3503 3504 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3505 3506 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 3507 /* Nothing to do. */ 3508 return (0); 3509 3510 /* Fetch the current version of the "dependents" property group. */ 3511 have_cur_depts = 1; 3512 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 3513 switch (scf_error()) { 3514 case SCF_ERROR_NOT_FOUND: 3515 break; 3516 3517 case SCF_ERROR_DELETED: 3518 case SCF_ERROR_CONNECTION_BROKEN: 3519 return (scferror2errno(scf_error())); 3520 3521 case SCF_ERROR_NOT_SET: 3522 case SCF_ERROR_INVALID_ARGUMENT: 3523 case SCF_ERROR_HANDLE_MISMATCH: 3524 case SCF_ERROR_NOT_BOUND: 3525 default: 3526 bad_error("entity_get_pg", scf_error()); 3527 } 3528 3529 have_cur_depts = 0; 3530 } 3531 3532 /* Fetch the running version of the "dependents" property group. */ 3533 ud_run_dpts_pg_set = 0; 3534 if (running != NULL) 3535 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 3536 else 3537 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 3538 if (r == 0) { 3539 ud_run_dpts_pg_set = 1; 3540 } else { 3541 switch (scf_error()) { 3542 case SCF_ERROR_NOT_FOUND: 3543 break; 3544 3545 case SCF_ERROR_DELETED: 3546 case SCF_ERROR_CONNECTION_BROKEN: 3547 return (scferror2errno(scf_error())); 3548 3549 case SCF_ERROR_NOT_SET: 3550 case SCF_ERROR_INVALID_ARGUMENT: 3551 case SCF_ERROR_HANDLE_MISMATCH: 3552 case SCF_ERROR_NOT_BOUND: 3553 default: 3554 bad_error(running ? "scf_snaplevel_get_pg" : 3555 "entity_get_pg", scf_error()); 3556 } 3557 } 3558 3559 /* 3560 * Clear the seen fields of the dependents, so we can tell which ones 3561 * are new. 3562 */ 3563 if (uu_list_walk(ient->sc_dependents, clear_int, 3564 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3565 bad_error("uu_list_walk", uu_error()); 3566 3567 if (li_dpts_pg != NULL) { 3568 /* 3569 * Each property in li_dpts_pg represents a dependent tag in 3570 * the old manifest. For each, call upgrade_dependent(), 3571 * which will change ud_cur_depts_pg or dependencies in other 3572 * services as appropriate. Note (a) that changes to 3573 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3574 * made en masse, and (b) it's ok if the entity doesn't have 3575 * a current version of the "dependents" property group, 3576 * because we'll just consider all dependents as customized 3577 * (by being deleted). 3578 */ 3579 3580 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3581 switch (scf_error()) { 3582 case SCF_ERROR_DELETED: 3583 return (ENODEV); 3584 3585 case SCF_ERROR_CONNECTION_BROKEN: 3586 return (ECONNABORTED); 3587 3588 case SCF_ERROR_HANDLE_MISMATCH: 3589 case SCF_ERROR_NOT_BOUND: 3590 case SCF_ERROR_NOT_SET: 3591 default: 3592 bad_error("scf_iter_pg_properties", 3593 scf_error()); 3594 } 3595 } 3596 3597 if (have_cur_depts && 3598 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3599 switch (scf_error()) { 3600 case SCF_ERROR_BACKEND_ACCESS: 3601 case SCF_ERROR_BACKEND_READONLY: 3602 case SCF_ERROR_CONNECTION_BROKEN: 3603 return (scferror2errno(scf_error())); 3604 3605 case SCF_ERROR_DELETED: 3606 warn(emsg_pg_deleted, ient->sc_fmri, 3607 dependents); 3608 return (EBUSY); 3609 3610 case SCF_ERROR_PERMISSION_DENIED: 3611 warn(emsg_pg_mod_perm, dependents, 3612 ient->sc_fmri); 3613 return (scferror2errno(scf_error())); 3614 3615 case SCF_ERROR_HANDLE_MISMATCH: 3616 case SCF_ERROR_IN_USE: 3617 case SCF_ERROR_NOT_BOUND: 3618 case SCF_ERROR_NOT_SET: 3619 default: 3620 bad_error("scf_transaction_start", scf_error()); 3621 } 3622 } 3623 tx_started = have_cur_depts; 3624 3625 for (;;) { 3626 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3627 if (r == 0) 3628 break; 3629 if (r == 1) { 3630 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3631 tx_started ? ud_tx : NULL); 3632 switch (r) { 3633 case 0: 3634 continue; 3635 3636 case ECONNABORTED: 3637 case ENOMEM: 3638 case ENOSPC: 3639 case EBADF: 3640 case EBUSY: 3641 case EINVAL: 3642 case EPERM: 3643 case EROFS: 3644 case EACCES: 3645 case EEXIST: 3646 break; 3647 3648 case ECANCELED: 3649 r = ENODEV; 3650 break; 3651 3652 default: 3653 bad_error("upgrade_dependent", r); 3654 } 3655 3656 if (tx_started) 3657 scf_transaction_destroy_children(ud_tx); 3658 return (r); 3659 } 3660 if (r != -1) 3661 bad_error("scf_iter_next_property", r); 3662 3663 switch (scf_error()) { 3664 case SCF_ERROR_DELETED: 3665 r = ENODEV; 3666 break; 3667 3668 case SCF_ERROR_CONNECTION_BROKEN: 3669 r = ECONNABORTED; 3670 break; 3671 3672 case SCF_ERROR_NOT_SET: 3673 case SCF_ERROR_INVALID_ARGUMENT: 3674 case SCF_ERROR_NOT_BOUND: 3675 case SCF_ERROR_HANDLE_MISMATCH: 3676 default: 3677 bad_error("scf_iter_next_property", 3678 scf_error()); 3679 } 3680 3681 if (tx_started) 3682 scf_transaction_destroy_children(ud_tx); 3683 return (r); 3684 } 3685 } 3686 3687 /* import unseen dependents */ 3688 unseen = 0; 3689 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3690 new_dpt_pgroup != NULL; 3691 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3692 new_dpt_pgroup)) { 3693 if (!new_dpt_pgroup->sc_pgroup_seen) { 3694 unseen = 1; 3695 break; 3696 } 3697 } 3698 3699 /* If there are none, exit early. */ 3700 if (unseen == 0) 3701 goto commit; 3702 3703 /* Set up for lscf_dependent_import() */ 3704 cbdata.sc_handle = g_hndl; 3705 cbdata.sc_parent = ent; 3706 cbdata.sc_service = issvc; 3707 cbdata.sc_flags = 0; 3708 3709 if (!have_cur_depts) { 3710 /* 3711 * We have new dependents to import, so we need a "dependents" 3712 * property group. 3713 */ 3714 if (issvc) 3715 r = scf_service_add_pg(ent, dependents, 3716 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3717 else 3718 r = scf_instance_add_pg(ent, dependents, 3719 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3720 if (r != 0) { 3721 switch (scf_error()) { 3722 case SCF_ERROR_DELETED: 3723 case SCF_ERROR_CONNECTION_BROKEN: 3724 case SCF_ERROR_BACKEND_READONLY: 3725 case SCF_ERROR_BACKEND_ACCESS: 3726 case SCF_ERROR_NO_RESOURCES: 3727 return (scferror2errno(scf_error())); 3728 3729 case SCF_ERROR_EXISTS: 3730 warn(emsg_pg_added, ient->sc_fmri, dependents); 3731 return (EBUSY); 3732 3733 case SCF_ERROR_PERMISSION_DENIED: 3734 warn(emsg_pg_add_perm, dependents, 3735 ient->sc_fmri); 3736 return (scferror2errno(scf_error())); 3737 3738 case SCF_ERROR_NOT_BOUND: 3739 case SCF_ERROR_HANDLE_MISMATCH: 3740 case SCF_ERROR_INVALID_ARGUMENT: 3741 case SCF_ERROR_NOT_SET: 3742 default: 3743 bad_error("scf_service_add_pg", scf_error()); 3744 } 3745 } 3746 } 3747 3748 cbdata.sc_trans = ud_tx; 3749 3750 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3751 switch (scf_error()) { 3752 case SCF_ERROR_CONNECTION_BROKEN: 3753 case SCF_ERROR_BACKEND_ACCESS: 3754 case SCF_ERROR_BACKEND_READONLY: 3755 return (scferror2errno(scf_error())); 3756 3757 case SCF_ERROR_DELETED: 3758 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3759 return (EBUSY); 3760 3761 case SCF_ERROR_PERMISSION_DENIED: 3762 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3763 return (scferror2errno(scf_error())); 3764 3765 case SCF_ERROR_HANDLE_MISMATCH: 3766 case SCF_ERROR_IN_USE: 3767 case SCF_ERROR_NOT_BOUND: 3768 case SCF_ERROR_NOT_SET: 3769 default: 3770 bad_error("scf_transaction_start", scf_error()); 3771 } 3772 } 3773 tx_started = 1; 3774 3775 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3776 new_dpt_pgroup != NULL; 3777 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3778 new_dpt_pgroup)) { 3779 if (new_dpt_pgroup->sc_pgroup_seen) 3780 continue; 3781 3782 if (ud_run_dpts_pg_set) { 3783 /* 3784 * If the dependent is already there, then we have 3785 * a conflict. 3786 */ 3787 if (scf_pg_get_property(ud_run_dpts_pg, 3788 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3789 r = handle_dependent_conflict(ient, ud_prop, 3790 new_dpt_pgroup); 3791 switch (r) { 3792 case 0: 3793 continue; 3794 3795 case ECONNABORTED: 3796 case ENOMEM: 3797 case EBUSY: 3798 case EBADF: 3799 case EINVAL: 3800 scf_transaction_destroy_children(ud_tx); 3801 return (r); 3802 3803 default: 3804 bad_error("handle_dependent_conflict", 3805 r); 3806 } 3807 } else { 3808 switch (scf_error()) { 3809 case SCF_ERROR_NOT_FOUND: 3810 break; 3811 3812 case SCF_ERROR_INVALID_ARGUMENT: 3813 warn(emsg_fmri_invalid_pg_name, 3814 ient->sc_fmri, 3815 new_dpt_pgroup->sc_pgroup_name); 3816 scf_transaction_destroy_children(ud_tx); 3817 return (EINVAL); 3818 3819 case SCF_ERROR_DELETED: 3820 warn(emsg_pg_deleted, ient->sc_fmri, 3821 new_dpt_pgroup->sc_pgroup_name); 3822 scf_transaction_destroy_children(ud_tx); 3823 return (EBUSY); 3824 3825 case SCF_ERROR_CONNECTION_BROKEN: 3826 scf_transaction_destroy_children(ud_tx); 3827 return (ECONNABORTED); 3828 3829 case SCF_ERROR_NOT_BOUND: 3830 case SCF_ERROR_HANDLE_MISMATCH: 3831 case SCF_ERROR_NOT_SET: 3832 default: 3833 bad_error("scf_pg_get_property", 3834 scf_error()); 3835 } 3836 } 3837 } 3838 3839 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3840 if (r != UU_WALK_NEXT) { 3841 if (r != UU_WALK_ERROR) 3842 bad_error("lscf_dependent_import", r); 3843 3844 if (cbdata.sc_err == EALREADY) { 3845 /* Collisions were handled preemptively. */ 3846 bad_error("lscf_dependent_import", 3847 cbdata.sc_err); 3848 } 3849 3850 scf_transaction_destroy_children(ud_tx); 3851 return (cbdata.sc_err); 3852 } 3853 } 3854 3855 commit: 3856 if (!tx_started) 3857 return (0); 3858 3859 r = scf_transaction_commit(ud_tx); 3860 3861 scf_transaction_destroy_children(ud_tx); 3862 3863 switch (r) { 3864 case 1: 3865 return (0); 3866 3867 case 0: 3868 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3869 return (EBUSY); 3870 3871 case -1: 3872 break; 3873 3874 default: 3875 bad_error("scf_transaction_commit", r); 3876 } 3877 3878 switch (scf_error()) { 3879 case SCF_ERROR_CONNECTION_BROKEN: 3880 case SCF_ERROR_BACKEND_READONLY: 3881 case SCF_ERROR_BACKEND_ACCESS: 3882 case SCF_ERROR_NO_RESOURCES: 3883 return (scferror2errno(scf_error())); 3884 3885 case SCF_ERROR_DELETED: 3886 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3887 return (EBUSY); 3888 3889 case SCF_ERROR_PERMISSION_DENIED: 3890 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3891 return (scferror2errno(scf_error())); 3892 3893 case SCF_ERROR_NOT_BOUND: 3894 case SCF_ERROR_INVALID_ARGUMENT: 3895 case SCF_ERROR_NOT_SET: 3896 default: 3897 bad_error("scf_transaction_destroy", scf_error()); 3898 /* NOTREACHED */ 3899 } 3900 } 3901 3902 /* 3903 * Used to add the manifests to the list of currently supported manifests. 3904 * We can modify the existing manifest list removing entries if the files 3905 * don't exist. 3906 * 3907 * Get the old list and the new file name 3908 * If the new file name is in the list return 3909 * If not then add the file to the list. 3910 * As we process the list check to see if the files in the old list exist 3911 * if not then remove the file from the list. 3912 * Commit the list of manifest file names. 3913 * 3914 */ 3915 static int 3916 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient, 3917 const scf_snaplevel_t *running, void *ent) 3918 { 3919 scf_propertygroup_t *ud_mfsts_pg = NULL; 3920 scf_property_t *ud_prop = NULL; 3921 scf_iter_t *ud_prop_iter; 3922 scf_value_t *fname_value; 3923 scf_callback_t cbdata; 3924 pgroup_t *mfst_pgroup; 3925 property_t *mfst_prop; 3926 property_t *old_prop; 3927 char *pname; 3928 char *fval; 3929 char *old_pname; 3930 char *old_fval; 3931 int no_upgrade_pg; 3932 int mfst_seen; 3933 int r; 3934 3935 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3936 3937 /* 3938 * This should always be the service base on the code 3939 * path, and the fact that the manifests pg is a service 3940 * level property group only. 3941 */ 3942 ud_mfsts_pg = scf_pg_create(g_hndl); 3943 ud_prop = scf_property_create(g_hndl); 3944 ud_prop_iter = scf_iter_create(g_hndl); 3945 fname_value = scf_value_create(g_hndl); 3946 3947 /* Fetch the "manifests" property group */ 3948 no_upgrade_pg = 0; 3949 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3950 ud_mfsts_pg); 3951 if (r != 0) { 3952 switch (scf_error()) { 3953 case SCF_ERROR_NOT_FOUND: 3954 no_upgrade_pg = 1; 3955 break; 3956 3957 case SCF_ERROR_DELETED: 3958 case SCF_ERROR_CONNECTION_BROKEN: 3959 return (scferror2errno(scf_error())); 3960 3961 case SCF_ERROR_NOT_SET: 3962 case SCF_ERROR_INVALID_ARGUMENT: 3963 case SCF_ERROR_HANDLE_MISMATCH: 3964 case SCF_ERROR_NOT_BOUND: 3965 default: 3966 bad_error(running ? "scf_snaplevel_get_pg" : 3967 "entity_get_pg", scf_error()); 3968 } 3969 } 3970 3971 if (no_upgrade_pg) { 3972 cbdata.sc_handle = g_hndl; 3973 cbdata.sc_parent = ent; 3974 cbdata.sc_service = issvc; 3975 cbdata.sc_flags = SCI_FORCE; 3976 cbdata.sc_source_fmri = ient->sc_fmri; 3977 cbdata.sc_target_fmri = ient->sc_fmri; 3978 3979 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3980 return (cbdata.sc_err); 3981 3982 return (0); 3983 } 3984 3985 /* Fetch the new manifests property group */ 3986 mfst_pgroup = internal_pgroup_find_or_create(ient, 3987 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 3988 assert(mfst_pgroup != NULL); 3989 3990 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3991 SCF_SUCCESS) 3992 return (-1); 3993 3994 if ((pname = malloc(MAXPATHLEN)) == NULL) 3995 return (ENOMEM); 3996 if ((fval = malloc(MAXPATHLEN)) == NULL) { 3997 free(pname); 3998 return (ENOMEM); 3999 } 4000 4001 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 4002 mfst_seen = 0; 4003 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 4004 continue; 4005 4006 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 4007 mfst_prop != NULL; 4008 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 4009 mfst_prop)) { 4010 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 4011 mfst_seen = 1; 4012 } 4013 } 4014 4015 /* 4016 * If the manifest is not seen then add it to the new mfst 4017 * property list to get proccessed into the repo. 4018 */ 4019 if (mfst_seen == 0) { 4020 /* 4021 * If we cannot get the value then there is no 4022 * reason to attempt to attach the value to 4023 * the property group 4024 */ 4025 if (prop_get_val(ud_prop, fname_value) == 0 && 4026 scf_value_get_astring(fname_value, fval, 4027 MAXPATHLEN) != -1) { 4028 old_pname = safe_strdup(pname); 4029 old_fval = safe_strdup(fval); 4030 old_prop = internal_property_create(old_pname, 4031 SCF_TYPE_ASTRING, 1, old_fval); 4032 4033 /* 4034 * Already checked to see if the property exists 4035 * in the group, and it does not. 4036 */ 4037 (void) internal_attach_property(mfst_pgroup, 4038 old_prop); 4039 } 4040 } 4041 } 4042 free(pname); 4043 free(fval); 4044 4045 cbdata.sc_handle = g_hndl; 4046 cbdata.sc_parent = ent; 4047 cbdata.sc_service = issvc; 4048 cbdata.sc_flags = SCI_FORCE; 4049 cbdata.sc_source_fmri = ient->sc_fmri; 4050 cbdata.sc_target_fmri = ient->sc_fmri; 4051 4052 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 4053 return (cbdata.sc_err); 4054 4055 return (r); 4056 } 4057 4058 /* 4059 * prop is taken to be a property in the "dependents" property group of snpl, 4060 * which is taken to be the snaplevel of a last-import snapshot corresponding 4061 * to ient. If prop is a valid dependents property, upgrade the dependent it 4062 * represents according to the repository & ient. If ud_run_dpts_pg_set is 4063 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 4064 * of the entity ient represents (possibly in the running snapshot). If it 4065 * needs to be changed, an entry will be added to tx, if not NULL. 4066 * 4067 * Returns 4068 * 0 - success 4069 * ECONNABORTED - repository connection broken 4070 * ENOMEM - out of memory 4071 * ENOSPC - configd was out of resources 4072 * ECANCELED - snpl's entity was deleted 4073 * EINVAL - dependent target is invalid (error printed) 4074 * - dependent is invalid (error printed) 4075 * EBADF - snpl is corrupt (error printed) 4076 * - snpl has corrupt pg (error printed) 4077 * - dependency pg in target is corrupt (error printed) 4078 * - running snapshot in dependent is missing snaplevel (error printed) 4079 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 4080 * - couldn't create dependent (permission denied) (error printed) 4081 * - couldn't modify dependent pg (permission denied) (error printed) 4082 * EROFS - couldn't delete dependency pg (repository read-only) 4083 * - couldn't create dependent (repository read-only) 4084 * EACCES - couldn't delete dependency pg (backend access denied) 4085 * - couldn't create dependent (backend access denied) 4086 * EBUSY - ud_run_dpts_pg was deleted (error printed) 4087 * - tx's pg was deleted (error printed) 4088 * - dependent pg was changed or deleted (error printed) 4089 * EEXIST - dependency pg already exists in new target (error printed) 4090 */ 4091 static int 4092 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 4093 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 4094 { 4095 pgroup_t pgrp; 4096 scf_type_t ty; 4097 pgroup_t *new_dpt_pgroup; 4098 pgroup_t *old_dpt_pgroup = NULL; 4099 pgroup_t *current_pg; 4100 pgroup_t *dpt; 4101 scf_callback_t cbdata; 4102 int tissvc; 4103 void *target_ent; 4104 scf_error_t serr; 4105 int r; 4106 scf_transaction_entry_t *ent; 4107 4108 const char * const cf_inval = gettext("Conflict upgrading %s " 4109 "(dependent \"%s\" has invalid dependents property).\n"); 4110 const char * const cf_missing = gettext("Conflict upgrading %s " 4111 "(dependent \"%s\" is missing).\n"); 4112 const char * const cf_newdpg = gettext("Conflict upgrading %s " 4113 "(dependent \"%s\" has new dependency property group).\n"); 4114 const char * const cf_newtarg = gettext("Conflict upgrading %s " 4115 "(dependent \"%s\" has new target).\n"); 4116 const char * const li_corrupt = 4117 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 4118 const char * const upgrading = 4119 gettext("%s: Upgrading dependent \"%s\".\n"); 4120 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 4121 "corrupt (missing snaplevel).\n"); 4122 4123 if (scf_property_type(prop, &ty) != 0) { 4124 switch (scf_error()) { 4125 case SCF_ERROR_DELETED: 4126 case SCF_ERROR_CONNECTION_BROKEN: 4127 return (scferror2errno(scf_error())); 4128 4129 case SCF_ERROR_NOT_BOUND: 4130 case SCF_ERROR_NOT_SET: 4131 default: 4132 bad_error("scf_property_type", scf_error()); 4133 } 4134 } 4135 4136 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4137 warn(li_corrupt, ient->sc_fmri); 4138 return (EBADF); 4139 } 4140 4141 /* 4142 * prop represents a dependent in the old manifest. It is named after 4143 * the dependent. 4144 */ 4145 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 4146 switch (scf_error()) { 4147 case SCF_ERROR_DELETED: 4148 case SCF_ERROR_CONNECTION_BROKEN: 4149 return (scferror2errno(scf_error())); 4150 4151 case SCF_ERROR_NOT_BOUND: 4152 case SCF_ERROR_NOT_SET: 4153 default: 4154 bad_error("scf_property_get_name", scf_error()); 4155 } 4156 } 4157 4158 /* See if it's in the new manifest. */ 4159 pgrp.sc_pgroup_name = ud_name; 4160 new_dpt_pgroup = 4161 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 4162 4163 /* If it's not, delete it... if it hasn't been customized. */ 4164 if (new_dpt_pgroup == NULL) { 4165 if (!ud_run_dpts_pg_set) 4166 return (0); 4167 4168 if (scf_property_get_value(prop, ud_val) != 0) { 4169 switch (scf_error()) { 4170 case SCF_ERROR_NOT_FOUND: 4171 case SCF_ERROR_CONSTRAINT_VIOLATED: 4172 warn(li_corrupt, ient->sc_fmri); 4173 return (EBADF); 4174 4175 case SCF_ERROR_DELETED: 4176 case SCF_ERROR_CONNECTION_BROKEN: 4177 return (scferror2errno(scf_error())); 4178 4179 case SCF_ERROR_HANDLE_MISMATCH: 4180 case SCF_ERROR_NOT_BOUND: 4181 case SCF_ERROR_NOT_SET: 4182 case SCF_ERROR_PERMISSION_DENIED: 4183 default: 4184 bad_error("scf_property_get_value", 4185 scf_error()); 4186 } 4187 } 4188 4189 if (scf_value_get_as_string(ud_val, ud_oldtarg, 4190 max_scf_value_len + 1) < 0) 4191 bad_error("scf_value_get_as_string", scf_error()); 4192 4193 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 4194 0) { 4195 switch (scf_error()) { 4196 case SCF_ERROR_NOT_FOUND: 4197 return (0); 4198 4199 case SCF_ERROR_CONNECTION_BROKEN: 4200 return (scferror2errno(scf_error())); 4201 4202 case SCF_ERROR_DELETED: 4203 warn(emsg_pg_deleted, ient->sc_fmri, 4204 "dependents"); 4205 return (EBUSY); 4206 4207 case SCF_ERROR_INVALID_ARGUMENT: 4208 case SCF_ERROR_NOT_BOUND: 4209 case SCF_ERROR_HANDLE_MISMATCH: 4210 case SCF_ERROR_NOT_SET: 4211 default: 4212 bad_error("scf_pg_get_property", scf_error()); 4213 } 4214 } 4215 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4216 switch (scf_error()) { 4217 case SCF_ERROR_NOT_FOUND: 4218 case SCF_ERROR_CONSTRAINT_VIOLATED: 4219 warn(cf_inval, ient->sc_fmri, ud_name); 4220 return (0); 4221 4222 case SCF_ERROR_DELETED: 4223 case SCF_ERROR_CONNECTION_BROKEN: 4224 return (scferror2errno(scf_error())); 4225 4226 case SCF_ERROR_HANDLE_MISMATCH: 4227 case SCF_ERROR_NOT_BOUND: 4228 case SCF_ERROR_NOT_SET: 4229 case SCF_ERROR_PERMISSION_DENIED: 4230 default: 4231 bad_error("scf_property_get_value", 4232 scf_error()); 4233 } 4234 } 4235 4236 ty = scf_value_type(ud_val); 4237 assert(ty != SCF_TYPE_INVALID); 4238 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4239 warn(cf_inval, ient->sc_fmri, ud_name); 4240 return (0); 4241 } 4242 4243 if (scf_value_get_as_string(ud_val, ud_ctarg, 4244 max_scf_value_len + 1) < 0) 4245 bad_error("scf_value_get_as_string", scf_error()); 4246 4247 r = fmri_equal(ud_ctarg, ud_oldtarg); 4248 switch (r) { 4249 case 1: 4250 break; 4251 4252 case 0: 4253 case -1: /* warn? */ 4254 warn(cf_newtarg, ient->sc_fmri, ud_name); 4255 return (0); 4256 4257 case -2: 4258 warn(li_corrupt, ient->sc_fmri); 4259 return (EBADF); 4260 4261 default: 4262 bad_error("fmri_equal", r); 4263 } 4264 4265 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4266 switch (scf_error()) { 4267 case SCF_ERROR_NOT_FOUND: 4268 warn(li_corrupt, ient->sc_fmri); 4269 return (EBADF); 4270 4271 case SCF_ERROR_DELETED: 4272 case SCF_ERROR_CONNECTION_BROKEN: 4273 return (scferror2errno(scf_error())); 4274 4275 case SCF_ERROR_NOT_BOUND: 4276 case SCF_ERROR_HANDLE_MISMATCH: 4277 case SCF_ERROR_INVALID_ARGUMENT: 4278 case SCF_ERROR_NOT_SET: 4279 default: 4280 bad_error("scf_snaplevel_get_pg", scf_error()); 4281 } 4282 } 4283 4284 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4285 snap_lastimport); 4286 switch (r) { 4287 case 0: 4288 break; 4289 4290 case ECANCELED: 4291 case ECONNABORTED: 4292 case ENOMEM: 4293 case EBADF: 4294 return (r); 4295 4296 case EACCES: 4297 default: 4298 bad_error("load_pg", r); 4299 } 4300 4301 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4302 switch (serr) { 4303 case SCF_ERROR_NONE: 4304 break; 4305 4306 case SCF_ERROR_NO_MEMORY: 4307 internal_pgroup_free(old_dpt_pgroup); 4308 return (ENOMEM); 4309 4310 case SCF_ERROR_NOT_FOUND: 4311 internal_pgroup_free(old_dpt_pgroup); 4312 goto delprop; 4313 4314 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 4315 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 4316 default: 4317 bad_error("fmri_to_entity", serr); 4318 } 4319 4320 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4321 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4322 switch (r) { 4323 case 0: 4324 break; 4325 4326 case ECONNABORTED: 4327 internal_pgroup_free(old_dpt_pgroup); 4328 return (r); 4329 4330 case ECANCELED: 4331 case ENOENT: 4332 internal_pgroup_free(old_dpt_pgroup); 4333 goto delprop; 4334 4335 case EBADF: 4336 warn(r_no_lvl, ud_ctarg); 4337 internal_pgroup_free(old_dpt_pgroup); 4338 return (r); 4339 4340 case EINVAL: 4341 default: 4342 bad_error("entity_get_running_pg", r); 4343 } 4344 4345 /* load it */ 4346 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4347 switch (r) { 4348 case 0: 4349 break; 4350 4351 case ECANCELED: 4352 internal_pgroup_free(old_dpt_pgroup); 4353 goto delprop; 4354 4355 case ECONNABORTED: 4356 case ENOMEM: 4357 case EBADF: 4358 internal_pgroup_free(old_dpt_pgroup); 4359 return (r); 4360 4361 case EACCES: 4362 default: 4363 bad_error("load_pg", r); 4364 } 4365 4366 /* compare property groups */ 4367 if (!pg_equal(old_dpt_pgroup, current_pg)) { 4368 warn(cf_newdpg, ient->sc_fmri, ud_name); 4369 internal_pgroup_free(old_dpt_pgroup); 4370 internal_pgroup_free(current_pg); 4371 return (0); 4372 } 4373 4374 internal_pgroup_free(old_dpt_pgroup); 4375 internal_pgroup_free(current_pg); 4376 4377 if (g_verbose) 4378 warn(gettext("%s: Deleting dependent \"%s\".\n"), 4379 ient->sc_fmri, ud_name); 4380 4381 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4382 switch (scf_error()) { 4383 case SCF_ERROR_NOT_FOUND: 4384 case SCF_ERROR_DELETED: 4385 internal_pgroup_free(old_dpt_pgroup); 4386 goto delprop; 4387 4388 case SCF_ERROR_CONNECTION_BROKEN: 4389 internal_pgroup_free(old_dpt_pgroup); 4390 return (ECONNABORTED); 4391 4392 case SCF_ERROR_NOT_SET: 4393 case SCF_ERROR_INVALID_ARGUMENT: 4394 case SCF_ERROR_HANDLE_MISMATCH: 4395 case SCF_ERROR_NOT_BOUND: 4396 default: 4397 bad_error("entity_get_pg", scf_error()); 4398 } 4399 } 4400 4401 if (scf_pg_delete(ud_pg) != 0) { 4402 switch (scf_error()) { 4403 case SCF_ERROR_DELETED: 4404 break; 4405 4406 case SCF_ERROR_CONNECTION_BROKEN: 4407 case SCF_ERROR_BACKEND_READONLY: 4408 case SCF_ERROR_BACKEND_ACCESS: 4409 return (scferror2errno(scf_error())); 4410 4411 case SCF_ERROR_PERMISSION_DENIED: 4412 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4413 return (scferror2errno(scf_error())); 4414 4415 case SCF_ERROR_NOT_SET: 4416 default: 4417 bad_error("scf_pg_delete", scf_error()); 4418 } 4419 } 4420 4421 /* 4422 * This service was changed, so it must be refreshed. But 4423 * since it's not mentioned in the new manifest, we have to 4424 * record its FMRI here for use later. We record the name 4425 * & the entity (via sc_parent) in case we need to print error 4426 * messages during the refresh. 4427 */ 4428 dpt = internal_pgroup_new(); 4429 if (dpt == NULL) 4430 return (ENOMEM); 4431 dpt->sc_pgroup_name = strdup(ud_name); 4432 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 4433 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4434 return (ENOMEM); 4435 dpt->sc_parent = (entity_t *)ient; 4436 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4437 uu_die(gettext("libuutil error: %s\n"), 4438 uu_strerror(uu_error())); 4439 4440 delprop: 4441 if (tx == NULL) 4442 return (0); 4443 4444 ent = scf_entry_create(g_hndl); 4445 if (ent == NULL) 4446 return (ENOMEM); 4447 4448 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 4449 scf_entry_destroy(ent); 4450 switch (scf_error()) { 4451 case SCF_ERROR_DELETED: 4452 warn(emsg_pg_deleted, ient->sc_fmri, 4453 "dependents"); 4454 return (EBUSY); 4455 4456 case SCF_ERROR_CONNECTION_BROKEN: 4457 return (scferror2errno(scf_error())); 4458 4459 case SCF_ERROR_NOT_FOUND: 4460 break; 4461 4462 case SCF_ERROR_HANDLE_MISMATCH: 4463 case SCF_ERROR_NOT_BOUND: 4464 case SCF_ERROR_INVALID_ARGUMENT: 4465 case SCF_ERROR_NOT_SET: 4466 default: 4467 bad_error("scf_transaction_property_delete", 4468 scf_error()); 4469 } 4470 } 4471 4472 return (0); 4473 } 4474 4475 new_dpt_pgroup->sc_pgroup_seen = 1; 4476 4477 /* 4478 * Decide whether the dependent has changed in the manifest. 4479 */ 4480 /* Compare the target. */ 4481 if (scf_property_get_value(prop, ud_val) != 0) { 4482 switch (scf_error()) { 4483 case SCF_ERROR_NOT_FOUND: 4484 case SCF_ERROR_CONSTRAINT_VIOLATED: 4485 warn(li_corrupt, ient->sc_fmri); 4486 return (EBADF); 4487 4488 case SCF_ERROR_DELETED: 4489 case SCF_ERROR_CONNECTION_BROKEN: 4490 return (scferror2errno(scf_error())); 4491 4492 case SCF_ERROR_HANDLE_MISMATCH: 4493 case SCF_ERROR_NOT_BOUND: 4494 case SCF_ERROR_NOT_SET: 4495 case SCF_ERROR_PERMISSION_DENIED: 4496 default: 4497 bad_error("scf_property_get_value", scf_error()); 4498 } 4499 } 4500 4501 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 4502 0) 4503 bad_error("scf_value_get_as_string", scf_error()); 4504 4505 /* 4506 * If the fmri's are not equal then the old fmri will need to 4507 * be refreshed to ensure that the changes are properly updated 4508 * in that service. 4509 */ 4510 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 4511 switch (r) { 4512 case 0: 4513 dpt = internal_pgroup_new(); 4514 if (dpt == NULL) 4515 return (ENOMEM); 4516 dpt->sc_pgroup_name = strdup(ud_name); 4517 dpt->sc_pgroup_fmri = strdup(ud_oldtarg); 4518 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4519 return (ENOMEM); 4520 dpt->sc_parent = (entity_t *)ient; 4521 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4522 uu_die(gettext("libuutil error: %s\n"), 4523 uu_strerror(uu_error())); 4524 break; 4525 4526 case 1: 4527 /* Compare the dependency pgs. */ 4528 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4529 switch (scf_error()) { 4530 case SCF_ERROR_NOT_FOUND: 4531 warn(li_corrupt, ient->sc_fmri); 4532 return (EBADF); 4533 4534 case SCF_ERROR_DELETED: 4535 case SCF_ERROR_CONNECTION_BROKEN: 4536 return (scferror2errno(scf_error())); 4537 4538 case SCF_ERROR_NOT_BOUND: 4539 case SCF_ERROR_HANDLE_MISMATCH: 4540 case SCF_ERROR_INVALID_ARGUMENT: 4541 case SCF_ERROR_NOT_SET: 4542 default: 4543 bad_error("scf_snaplevel_get_pg", scf_error()); 4544 } 4545 } 4546 4547 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4548 snap_lastimport); 4549 switch (r) { 4550 case 0: 4551 break; 4552 4553 case ECANCELED: 4554 case ECONNABORTED: 4555 case ENOMEM: 4556 case EBADF: 4557 return (r); 4558 4559 case EACCES: 4560 default: 4561 bad_error("load_pg", r); 4562 } 4563 4564 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4565 /* no change, leave customizations */ 4566 internal_pgroup_free(old_dpt_pgroup); 4567 return (0); 4568 } 4569 break; 4570 4571 case -1: 4572 warn(li_corrupt, ient->sc_fmri); 4573 return (EBADF); 4574 4575 case -2: 4576 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4577 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4578 return (EINVAL); 4579 4580 default: 4581 bad_error("fmri_equal", r); 4582 } 4583 4584 /* 4585 * The dependent has changed in the manifest. Upgrade the current 4586 * properties if they haven't been customized. 4587 */ 4588 4589 /* 4590 * If new_dpt_pgroup->sc_override, then act as though the property 4591 * group hasn't been customized. 4592 */ 4593 if (new_dpt_pgroup->sc_pgroup_override) { 4594 (void) strcpy(ud_ctarg, ud_oldtarg); 4595 goto nocust; 4596 } 4597 4598 if (!ud_run_dpts_pg_set) { 4599 warn(cf_missing, ient->sc_fmri, ud_name); 4600 r = 0; 4601 goto out; 4602 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4603 switch (scf_error()) { 4604 case SCF_ERROR_NOT_FOUND: 4605 warn(cf_missing, ient->sc_fmri, ud_name); 4606 r = 0; 4607 goto out; 4608 4609 case SCF_ERROR_CONNECTION_BROKEN: 4610 r = scferror2errno(scf_error()); 4611 goto out; 4612 4613 case SCF_ERROR_DELETED: 4614 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4615 r = EBUSY; 4616 goto out; 4617 4618 case SCF_ERROR_INVALID_ARGUMENT: 4619 case SCF_ERROR_NOT_BOUND: 4620 case SCF_ERROR_HANDLE_MISMATCH: 4621 case SCF_ERROR_NOT_SET: 4622 default: 4623 bad_error("scf_pg_get_property", scf_error()); 4624 } 4625 } 4626 4627 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4628 switch (scf_error()) { 4629 case SCF_ERROR_NOT_FOUND: 4630 case SCF_ERROR_CONSTRAINT_VIOLATED: 4631 warn(cf_inval, ient->sc_fmri, ud_name); 4632 r = 0; 4633 goto out; 4634 4635 case SCF_ERROR_DELETED: 4636 case SCF_ERROR_CONNECTION_BROKEN: 4637 r = scferror2errno(scf_error()); 4638 goto out; 4639 4640 case SCF_ERROR_HANDLE_MISMATCH: 4641 case SCF_ERROR_NOT_BOUND: 4642 case SCF_ERROR_NOT_SET: 4643 case SCF_ERROR_PERMISSION_DENIED: 4644 default: 4645 bad_error("scf_property_get_value", scf_error()); 4646 } 4647 } 4648 4649 ty = scf_value_type(ud_val); 4650 assert(ty != SCF_TYPE_INVALID); 4651 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4652 warn(cf_inval, ient->sc_fmri, ud_name); 4653 r = 0; 4654 goto out; 4655 } 4656 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4657 0) 4658 bad_error("scf_value_get_as_string", scf_error()); 4659 4660 r = fmri_equal(ud_ctarg, ud_oldtarg); 4661 if (r == -1) { 4662 warn(cf_inval, ient->sc_fmri, ud_name); 4663 r = 0; 4664 goto out; 4665 } else if (r == -2) { 4666 warn(li_corrupt, ient->sc_fmri); 4667 r = EBADF; 4668 goto out; 4669 } else if (r == 0) { 4670 /* 4671 * Target has been changed. Only abort now if it's been 4672 * changed to something other than what's in the manifest. 4673 */ 4674 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4675 if (r == -1) { 4676 warn(cf_inval, ient->sc_fmri, ud_name); 4677 r = 0; 4678 goto out; 4679 } else if (r == 0) { 4680 warn(cf_newtarg, ient->sc_fmri, ud_name); 4681 r = 0; 4682 goto out; 4683 } else if (r != 1) { 4684 /* invalid sc_pgroup_fmri caught above */ 4685 bad_error("fmri_equal", r); 4686 } 4687 4688 /* 4689 * Fetch the current dependency pg. If it's what the manifest 4690 * says, then no problem. 4691 */ 4692 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4693 switch (serr) { 4694 case SCF_ERROR_NONE: 4695 break; 4696 4697 case SCF_ERROR_NOT_FOUND: 4698 warn(cf_missing, ient->sc_fmri, ud_name); 4699 r = 0; 4700 goto out; 4701 4702 case SCF_ERROR_NO_MEMORY: 4703 r = ENOMEM; 4704 goto out; 4705 4706 case SCF_ERROR_CONSTRAINT_VIOLATED: 4707 case SCF_ERROR_INVALID_ARGUMENT: 4708 default: 4709 bad_error("fmri_to_entity", serr); 4710 } 4711 4712 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4713 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4714 switch (r) { 4715 case 0: 4716 break; 4717 4718 case ECONNABORTED: 4719 goto out; 4720 4721 case ECANCELED: 4722 case ENOENT: 4723 warn(cf_missing, ient->sc_fmri, ud_name); 4724 r = 0; 4725 goto out; 4726 4727 case EBADF: 4728 warn(r_no_lvl, ud_ctarg); 4729 goto out; 4730 4731 case EINVAL: 4732 default: 4733 bad_error("entity_get_running_pg", r); 4734 } 4735 4736 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4737 switch (r) { 4738 case 0: 4739 break; 4740 4741 case ECANCELED: 4742 warn(cf_missing, ient->sc_fmri, ud_name); 4743 r = 0; 4744 goto out; 4745 4746 case ECONNABORTED: 4747 case ENOMEM: 4748 case EBADF: 4749 goto out; 4750 4751 case EACCES: 4752 default: 4753 bad_error("load_pg", r); 4754 } 4755 4756 if (!pg_equal(current_pg, new_dpt_pgroup)) 4757 warn(cf_newdpg, ient->sc_fmri, ud_name); 4758 internal_pgroup_free(current_pg); 4759 r = 0; 4760 goto out; 4761 } else if (r != 1) { 4762 bad_error("fmri_equal", r); 4763 } 4764 4765 nocust: 4766 /* 4767 * Target has not been customized. Check the dependency property 4768 * group. 4769 */ 4770 4771 if (old_dpt_pgroup == NULL) { 4772 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4773 ud_pg) != 0) { 4774 switch (scf_error()) { 4775 case SCF_ERROR_NOT_FOUND: 4776 warn(li_corrupt, ient->sc_fmri); 4777 return (EBADF); 4778 4779 case SCF_ERROR_DELETED: 4780 case SCF_ERROR_CONNECTION_BROKEN: 4781 return (scferror2errno(scf_error())); 4782 4783 case SCF_ERROR_NOT_BOUND: 4784 case SCF_ERROR_HANDLE_MISMATCH: 4785 case SCF_ERROR_INVALID_ARGUMENT: 4786 case SCF_ERROR_NOT_SET: 4787 default: 4788 bad_error("scf_snaplevel_get_pg", scf_error()); 4789 } 4790 } 4791 4792 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4793 snap_lastimport); 4794 switch (r) { 4795 case 0: 4796 break; 4797 4798 case ECANCELED: 4799 case ECONNABORTED: 4800 case ENOMEM: 4801 case EBADF: 4802 return (r); 4803 4804 case EACCES: 4805 default: 4806 bad_error("load_pg", r); 4807 } 4808 } 4809 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4810 switch (serr) { 4811 case SCF_ERROR_NONE: 4812 break; 4813 4814 case SCF_ERROR_NOT_FOUND: 4815 warn(cf_missing, ient->sc_fmri, ud_name); 4816 r = 0; 4817 goto out; 4818 4819 case SCF_ERROR_NO_MEMORY: 4820 r = ENOMEM; 4821 goto out; 4822 4823 case SCF_ERROR_CONSTRAINT_VIOLATED: 4824 case SCF_ERROR_INVALID_ARGUMENT: 4825 default: 4826 bad_error("fmri_to_entity", serr); 4827 } 4828 4829 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4830 ud_iter2, ud_inst, imp_snap, ud_snpl); 4831 switch (r) { 4832 case 0: 4833 break; 4834 4835 case ECONNABORTED: 4836 goto out; 4837 4838 case ECANCELED: 4839 case ENOENT: 4840 warn(cf_missing, ient->sc_fmri, ud_name); 4841 r = 0; 4842 goto out; 4843 4844 case EBADF: 4845 warn(r_no_lvl, ud_ctarg); 4846 goto out; 4847 4848 case EINVAL: 4849 default: 4850 bad_error("entity_get_running_pg", r); 4851 } 4852 4853 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4854 switch (r) { 4855 case 0: 4856 break; 4857 4858 case ECANCELED: 4859 warn(cf_missing, ient->sc_fmri, ud_name); 4860 goto out; 4861 4862 case ECONNABORTED: 4863 case ENOMEM: 4864 case EBADF: 4865 goto out; 4866 4867 case EACCES: 4868 default: 4869 bad_error("load_pg", r); 4870 } 4871 4872 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4873 if (!pg_equal(current_pg, new_dpt_pgroup)) 4874 warn(cf_newdpg, ient->sc_fmri, ud_name); 4875 internal_pgroup_free(current_pg); 4876 r = 0; 4877 goto out; 4878 } 4879 4880 /* Uncustomized. Upgrade. */ 4881 4882 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4883 switch (r) { 4884 case 1: 4885 if (pg_equal(current_pg, new_dpt_pgroup)) { 4886 /* Already upgraded. */ 4887 internal_pgroup_free(current_pg); 4888 r = 0; 4889 goto out; 4890 } 4891 4892 internal_pgroup_free(current_pg); 4893 4894 /* upgrade current_pg */ 4895 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4896 switch (scf_error()) { 4897 case SCF_ERROR_CONNECTION_BROKEN: 4898 r = scferror2errno(scf_error()); 4899 goto out; 4900 4901 case SCF_ERROR_DELETED: 4902 warn(cf_missing, ient->sc_fmri, ud_name); 4903 r = 0; 4904 goto out; 4905 4906 case SCF_ERROR_NOT_FOUND: 4907 break; 4908 4909 case SCF_ERROR_INVALID_ARGUMENT: 4910 case SCF_ERROR_NOT_BOUND: 4911 case SCF_ERROR_NOT_SET: 4912 case SCF_ERROR_HANDLE_MISMATCH: 4913 default: 4914 bad_error("entity_get_pg", scf_error()); 4915 } 4916 4917 if (tissvc) 4918 r = scf_service_add_pg(target_ent, ud_name, 4919 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4920 else 4921 r = scf_instance_add_pg(target_ent, ud_name, 4922 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4923 if (r != 0) { 4924 switch (scf_error()) { 4925 case SCF_ERROR_CONNECTION_BROKEN: 4926 case SCF_ERROR_NO_RESOURCES: 4927 case SCF_ERROR_BACKEND_READONLY: 4928 case SCF_ERROR_BACKEND_ACCESS: 4929 r = scferror2errno(scf_error()); 4930 goto out; 4931 4932 case SCF_ERROR_DELETED: 4933 warn(cf_missing, ient->sc_fmri, 4934 ud_name); 4935 r = 0; 4936 goto out; 4937 4938 case SCF_ERROR_PERMISSION_DENIED: 4939 warn(emsg_pg_deleted, ud_ctarg, 4940 ud_name); 4941 r = EPERM; 4942 goto out; 4943 4944 case SCF_ERROR_EXISTS: 4945 warn(emsg_pg_added, ud_ctarg, ud_name); 4946 r = EBUSY; 4947 goto out; 4948 4949 case SCF_ERROR_NOT_BOUND: 4950 case SCF_ERROR_HANDLE_MISMATCH: 4951 case SCF_ERROR_INVALID_ARGUMENT: 4952 case SCF_ERROR_NOT_SET: 4953 default: 4954 bad_error("entity_add_pg", scf_error()); 4955 } 4956 } 4957 } 4958 4959 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4960 switch (r) { 4961 case 0: 4962 break; 4963 4964 case ECANCELED: 4965 warn(cf_missing, ient->sc_fmri, ud_name); 4966 goto out; 4967 4968 case ECONNABORTED: 4969 case ENOMEM: 4970 case EBADF: 4971 goto out; 4972 4973 case EACCES: 4974 default: 4975 bad_error("load_pg", r); 4976 } 4977 4978 if (g_verbose) 4979 warn(upgrading, ient->sc_fmri, ud_name); 4980 4981 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4982 new_dpt_pgroup, 0, ient->sc_fmri); 4983 switch (r) { 4984 case 0: 4985 break; 4986 4987 case ECANCELED: 4988 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4989 r = EBUSY; 4990 goto out; 4991 4992 case EPERM: 4993 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4994 goto out; 4995 4996 case EBUSY: 4997 warn(emsg_pg_changed, ud_ctarg, ud_name); 4998 goto out; 4999 5000 case ECONNABORTED: 5001 case ENOMEM: 5002 case ENOSPC: 5003 case EROFS: 5004 case EACCES: 5005 case EINVAL: 5006 goto out; 5007 5008 default: 5009 bad_error("upgrade_pg", r); 5010 } 5011 break; 5012 5013 case 0: { 5014 scf_transaction_entry_t *ent; 5015 scf_value_t *val; 5016 5017 internal_pgroup_free(current_pg); 5018 5019 /* delete old pg */ 5020 if (g_verbose) 5021 warn(upgrading, ient->sc_fmri, ud_name); 5022 5023 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 5024 switch (scf_error()) { 5025 case SCF_ERROR_CONNECTION_BROKEN: 5026 r = scferror2errno(scf_error()); 5027 goto out; 5028 5029 case SCF_ERROR_DELETED: 5030 warn(cf_missing, ient->sc_fmri, ud_name); 5031 r = 0; 5032 goto out; 5033 5034 case SCF_ERROR_NOT_FOUND: 5035 break; 5036 5037 case SCF_ERROR_INVALID_ARGUMENT: 5038 case SCF_ERROR_NOT_BOUND: 5039 case SCF_ERROR_NOT_SET: 5040 case SCF_ERROR_HANDLE_MISMATCH: 5041 default: 5042 bad_error("entity_get_pg", scf_error()); 5043 } 5044 } else if (scf_pg_delete(ud_pg) != 0) { 5045 switch (scf_error()) { 5046 case SCF_ERROR_DELETED: 5047 break; 5048 5049 case SCF_ERROR_CONNECTION_BROKEN: 5050 case SCF_ERROR_BACKEND_READONLY: 5051 case SCF_ERROR_BACKEND_ACCESS: 5052 r = scferror2errno(scf_error()); 5053 goto out; 5054 5055 case SCF_ERROR_PERMISSION_DENIED: 5056 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 5057 r = scferror2errno(scf_error()); 5058 goto out; 5059 5060 case SCF_ERROR_NOT_SET: 5061 default: 5062 bad_error("scf_pg_delete", scf_error()); 5063 } 5064 } 5065 5066 /* import new one */ 5067 cbdata.sc_handle = g_hndl; 5068 cbdata.sc_trans = NULL; /* handled below */ 5069 cbdata.sc_flags = 0; 5070 5071 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 5072 if (r != UU_WALK_NEXT) { 5073 if (r != UU_WALK_ERROR) 5074 bad_error("lscf_dependent_import", r); 5075 5076 r = cbdata.sc_err; 5077 goto out; 5078 } 5079 5080 if (tx == NULL) 5081 break; 5082 5083 if ((ent = scf_entry_create(g_hndl)) == NULL || 5084 (val = scf_value_create(g_hndl)) == NULL) { 5085 if (scf_error() == SCF_ERROR_NO_MEMORY) 5086 return (ENOMEM); 5087 5088 bad_error("scf_entry_create", scf_error()); 5089 } 5090 5091 if (scf_transaction_property_change_type(tx, ent, ud_name, 5092 SCF_TYPE_FMRI) != 0) { 5093 switch (scf_error()) { 5094 case SCF_ERROR_CONNECTION_BROKEN: 5095 r = scferror2errno(scf_error()); 5096 goto out; 5097 5098 case SCF_ERROR_DELETED: 5099 warn(emsg_pg_deleted, ient->sc_fmri, 5100 "dependents"); 5101 r = EBUSY; 5102 goto out; 5103 5104 case SCF_ERROR_NOT_FOUND: 5105 break; 5106 5107 case SCF_ERROR_NOT_BOUND: 5108 case SCF_ERROR_HANDLE_MISMATCH: 5109 case SCF_ERROR_INVALID_ARGUMENT: 5110 case SCF_ERROR_NOT_SET: 5111 default: 5112 bad_error("scf_transaction_property_" 5113 "change_type", scf_error()); 5114 } 5115 5116 if (scf_transaction_property_new(tx, ent, ud_name, 5117 SCF_TYPE_FMRI) != 0) { 5118 switch (scf_error()) { 5119 case SCF_ERROR_CONNECTION_BROKEN: 5120 r = scferror2errno(scf_error()); 5121 goto out; 5122 5123 case SCF_ERROR_DELETED: 5124 warn(emsg_pg_deleted, ient->sc_fmri, 5125 "dependents"); 5126 r = EBUSY; 5127 goto out; 5128 5129 case SCF_ERROR_EXISTS: 5130 warn(emsg_pg_changed, ient->sc_fmri, 5131 "dependents"); 5132 r = EBUSY; 5133 goto out; 5134 5135 case SCF_ERROR_INVALID_ARGUMENT: 5136 case SCF_ERROR_HANDLE_MISMATCH: 5137 case SCF_ERROR_NOT_BOUND: 5138 case SCF_ERROR_NOT_SET: 5139 default: 5140 bad_error("scf_transaction_property_" 5141 "new", scf_error()); 5142 } 5143 } 5144 } 5145 5146 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 5147 new_dpt_pgroup->sc_pgroup_fmri) != 0) 5148 /* invalid sc_pgroup_fmri caught above */ 5149 bad_error("scf_value_set_from_string", 5150 scf_error()); 5151 5152 if (scf_entry_add_value(ent, val) != 0) 5153 bad_error("scf_entry_add_value", scf_error()); 5154 break; 5155 } 5156 5157 case -2: 5158 warn(li_corrupt, ient->sc_fmri); 5159 internal_pgroup_free(current_pg); 5160 r = EBADF; 5161 goto out; 5162 5163 case -1: 5164 default: 5165 /* invalid sc_pgroup_fmri caught above */ 5166 bad_error("fmri_equal", r); 5167 } 5168 5169 r = 0; 5170 5171 out: 5172 if (old_dpt_pgroup != NULL) 5173 internal_pgroup_free(old_dpt_pgroup); 5174 5175 return (r); 5176 } 5177 5178 /* 5179 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 5180 * would import it, except it seems to exist in the service anyway. Compare 5181 * the existent dependent with the one we would import, and report any 5182 * differences (if there are none, be silent). prop is the property which 5183 * represents the existent dependent (in the dependents property group) in the 5184 * entity corresponding to ient. 5185 * 5186 * Returns 5187 * 0 - success (Sort of. At least, we can continue importing.) 5188 * ECONNABORTED - repository connection broken 5189 * EBUSY - ancestor of prop was deleted (error printed) 5190 * ENOMEM - out of memory 5191 * EBADF - corrupt property group (error printed) 5192 * EINVAL - new_dpt_pgroup has invalid target (error printed) 5193 */ 5194 static int 5195 handle_dependent_conflict(const entity_t * const ient, 5196 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 5197 { 5198 int r; 5199 scf_type_t ty; 5200 scf_error_t scfe; 5201 void *tptr; 5202 int tissvc; 5203 pgroup_t *pgroup; 5204 5205 if (scf_property_get_value(prop, ud_val) != 0) { 5206 switch (scf_error()) { 5207 case SCF_ERROR_CONNECTION_BROKEN: 5208 return (scferror2errno(scf_error())); 5209 5210 case SCF_ERROR_DELETED: 5211 warn(emsg_pg_deleted, ient->sc_fmri, 5212 new_dpt_pgroup->sc_pgroup_name); 5213 return (EBUSY); 5214 5215 case SCF_ERROR_CONSTRAINT_VIOLATED: 5216 case SCF_ERROR_NOT_FOUND: 5217 warn(gettext("Conflict upgrading %s (not importing " 5218 "dependent \"%s\" because it already exists.) " 5219 "Warning: The \"%s/%2$s\" property has more or " 5220 "fewer than one value)).\n"), ient->sc_fmri, 5221 new_dpt_pgroup->sc_pgroup_name, "dependents"); 5222 return (0); 5223 5224 case SCF_ERROR_HANDLE_MISMATCH: 5225 case SCF_ERROR_NOT_BOUND: 5226 case SCF_ERROR_NOT_SET: 5227 case SCF_ERROR_PERMISSION_DENIED: 5228 default: 5229 bad_error("scf_property_get_value", 5230 scf_error()); 5231 } 5232 } 5233 5234 ty = scf_value_type(ud_val); 5235 assert(ty != SCF_TYPE_INVALID); 5236 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 5237 warn(gettext("Conflict upgrading %s (not importing dependent " 5238 "\"%s\" because it already exists). Warning: The " 5239 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 5240 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 5241 scf_type_to_string(ty), "dependents"); 5242 return (0); 5243 } 5244 5245 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 5246 0) 5247 bad_error("scf_value_get_as_string", scf_error()); 5248 5249 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 5250 switch (r) { 5251 case 0: 5252 warn(gettext("Conflict upgrading %s (not importing dependent " 5253 "\"%s\" (target \"%s\") because it already exists with " 5254 "target \"%s\").\n"), ient->sc_fmri, 5255 new_dpt_pgroup->sc_pgroup_name, 5256 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 5257 return (0); 5258 5259 case 1: 5260 break; 5261 5262 case -1: 5263 warn(gettext("Conflict upgrading %s (not importing dependent " 5264 "\"%s\" because it already exists). Warning: The current " 5265 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 5266 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5267 return (0); 5268 5269 case -2: 5270 warn(gettext("Dependent \"%s\" of %s has invalid target " 5271 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 5272 new_dpt_pgroup->sc_pgroup_fmri); 5273 return (EINVAL); 5274 5275 default: 5276 bad_error("fmri_equal", r); 5277 } 5278 5279 /* compare dependency pgs in target */ 5280 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 5281 switch (scfe) { 5282 case SCF_ERROR_NONE: 5283 break; 5284 5285 case SCF_ERROR_NO_MEMORY: 5286 return (ENOMEM); 5287 5288 case SCF_ERROR_NOT_FOUND: 5289 warn(emsg_dpt_dangling, ient->sc_fmri, 5290 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5291 return (0); 5292 5293 case SCF_ERROR_CONSTRAINT_VIOLATED: 5294 case SCF_ERROR_INVALID_ARGUMENT: 5295 default: 5296 bad_error("fmri_to_entity", scfe); 5297 } 5298 5299 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 5300 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 5301 switch (r) { 5302 case 0: 5303 break; 5304 5305 case ECONNABORTED: 5306 return (r); 5307 5308 case ECANCELED: 5309 warn(emsg_dpt_dangling, ient->sc_fmri, 5310 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5311 return (0); 5312 5313 case EBADF: 5314 if (tissvc) 5315 warn(gettext("%s has an instance with a \"%s\" " 5316 "snapshot which is missing a snaplevel.\n"), 5317 ud_ctarg, "running"); 5318 else 5319 warn(gettext("%s has a \"%s\" snapshot which is " 5320 "missing a snaplevel.\n"), ud_ctarg, "running"); 5321 /* FALLTHROUGH */ 5322 5323 case ENOENT: 5324 warn(emsg_dpt_no_dep, ient->sc_fmri, 5325 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5326 new_dpt_pgroup->sc_pgroup_name); 5327 return (0); 5328 5329 case EINVAL: 5330 default: 5331 bad_error("entity_get_running_pg", r); 5332 } 5333 5334 pgroup = internal_pgroup_new(); 5335 if (pgroup == NULL) 5336 return (ENOMEM); 5337 5338 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 5339 switch (r) { 5340 case 0: 5341 break; 5342 5343 case ECONNABORTED: 5344 case EBADF: 5345 case ENOMEM: 5346 internal_pgroup_free(pgroup); 5347 return (r); 5348 5349 case ECANCELED: 5350 warn(emsg_dpt_no_dep, ient->sc_fmri, 5351 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5352 new_dpt_pgroup->sc_pgroup_name); 5353 internal_pgroup_free(pgroup); 5354 return (0); 5355 5356 case EACCES: 5357 default: 5358 bad_error("load_pg", r); 5359 } 5360 5361 /* report differences */ 5362 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 5363 internal_pgroup_free(pgroup); 5364 return (0); 5365 } 5366 5367 /* 5368 * lipg is a property group in the last-import snapshot of ent, which is an 5369 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 5370 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 5371 * in ents's property groups, compare and upgrade ent appropriately. 5372 * 5373 * Returns 5374 * 0 - success 5375 * ECONNABORTED - repository connection broken 5376 * ENOMEM - out of memory 5377 * ENOSPC - configd is out of resources 5378 * EINVAL - ient has invalid dependent (error printed) 5379 * - ient has invalid pgroup_t (error printed) 5380 * ECANCELED - ent has been deleted 5381 * ENODEV - entity containing lipg has been deleted 5382 * - entity containing running has been deleted 5383 * EPERM - could not delete pg (permission denied) (error printed) 5384 * - couldn't upgrade dependents (permission denied) (error printed) 5385 * - couldn't import pg (permission denied) (error printed) 5386 * - couldn't upgrade pg (permission denied) (error printed) 5387 * EROFS - could not delete pg (repository read-only) 5388 * - couldn't upgrade dependents (repository read-only) 5389 * - couldn't import pg (repository read-only) 5390 * - couldn't upgrade pg (repository read-only) 5391 * EACCES - could not delete pg (backend access denied) 5392 * - couldn't upgrade dependents (backend access denied) 5393 * - couldn't import pg (backend access denied) 5394 * - couldn't upgrade pg (backend access denied) 5395 * - couldn't read property (backend access denied) 5396 * EBUSY - property group was added (error printed) 5397 * - property group was deleted (error printed) 5398 * - property group changed (error printed) 5399 * - "dependents" pg was added, changed, or deleted (error printed) 5400 * - dependent target deleted (error printed) 5401 * - dependent pg changed (error printed) 5402 * EBADF - imp_snpl is corrupt (error printed) 5403 * - ent has bad pg (error printed) 5404 * EEXIST - dependent collision in target service (error printed) 5405 */ 5406 static int 5407 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 5408 const scf_snaplevel_t *running) 5409 { 5410 int r; 5411 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 5412 scf_callback_t cbdata; 5413 5414 const char * const cf_pg_missing = 5415 gettext("Conflict upgrading %s (property group %s is missing)\n"); 5416 const char * const deleting = 5417 gettext("%s: Deleting property group \"%s\".\n"); 5418 5419 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5420 5421 /* Skip dependent property groups. */ 5422 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 5423 switch (scf_error()) { 5424 case SCF_ERROR_DELETED: 5425 return (ENODEV); 5426 5427 case SCF_ERROR_CONNECTION_BROKEN: 5428 return (ECONNABORTED); 5429 5430 case SCF_ERROR_NOT_SET: 5431 case SCF_ERROR_NOT_BOUND: 5432 default: 5433 bad_error("scf_pg_get_type", scf_error()); 5434 } 5435 } 5436 5437 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 5438 if (scf_pg_get_property(lipg, "external", NULL) == 0) 5439 return (0); 5440 5441 switch (scf_error()) { 5442 case SCF_ERROR_NOT_FOUND: 5443 break; 5444 5445 case SCF_ERROR_CONNECTION_BROKEN: 5446 return (ECONNABORTED); 5447 5448 case SCF_ERROR_DELETED: 5449 return (ENODEV); 5450 5451 case SCF_ERROR_INVALID_ARGUMENT: 5452 case SCF_ERROR_NOT_BOUND: 5453 case SCF_ERROR_HANDLE_MISMATCH: 5454 case SCF_ERROR_NOT_SET: 5455 default: 5456 bad_error("scf_pg_get_property", scf_error()); 5457 } 5458 } 5459 5460 /* lookup pg in new properties */ 5461 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 5462 switch (scf_error()) { 5463 case SCF_ERROR_DELETED: 5464 return (ENODEV); 5465 5466 case SCF_ERROR_CONNECTION_BROKEN: 5467 return (ECONNABORTED); 5468 5469 case SCF_ERROR_NOT_SET: 5470 case SCF_ERROR_NOT_BOUND: 5471 default: 5472 bad_error("scf_pg_get_name", scf_error()); 5473 } 5474 } 5475 5476 pgrp.sc_pgroup_name = imp_str; 5477 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 5478 5479 if (mpg != NULL) 5480 mpg->sc_pgroup_seen = 1; 5481 5482 /* Special handling for dependents */ 5483 if (strcmp(imp_str, "dependents") == 0) 5484 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 5485 5486 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 5487 return (upgrade_manifestfiles(NULL, ient, running, ent)); 5488 5489 if (mpg == NULL || mpg->sc_pgroup_delete) { 5490 /* property group was deleted from manifest */ 5491 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5492 switch (scf_error()) { 5493 case SCF_ERROR_NOT_FOUND: 5494 return (0); 5495 5496 case SCF_ERROR_DELETED: 5497 case SCF_ERROR_CONNECTION_BROKEN: 5498 return (scferror2errno(scf_error())); 5499 5500 case SCF_ERROR_INVALID_ARGUMENT: 5501 case SCF_ERROR_HANDLE_MISMATCH: 5502 case SCF_ERROR_NOT_BOUND: 5503 case SCF_ERROR_NOT_SET: 5504 default: 5505 bad_error("entity_get_pg", scf_error()); 5506 } 5507 } 5508 5509 if (mpg != NULL && mpg->sc_pgroup_delete) { 5510 if (g_verbose) 5511 warn(deleting, ient->sc_fmri, imp_str); 5512 if (scf_pg_delete(imp_pg2) == 0) 5513 return (0); 5514 5515 switch (scf_error()) { 5516 case SCF_ERROR_DELETED: 5517 return (0); 5518 5519 case SCF_ERROR_CONNECTION_BROKEN: 5520 case SCF_ERROR_BACKEND_READONLY: 5521 case SCF_ERROR_BACKEND_ACCESS: 5522 return (scferror2errno(scf_error())); 5523 5524 case SCF_ERROR_PERMISSION_DENIED: 5525 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 5526 return (scferror2errno(scf_error())); 5527 5528 case SCF_ERROR_NOT_SET: 5529 default: 5530 bad_error("scf_pg_delete", scf_error()); 5531 } 5532 } 5533 5534 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5535 switch (r) { 5536 case 0: 5537 break; 5538 5539 case ECANCELED: 5540 return (ENODEV); 5541 5542 case ECONNABORTED: 5543 case ENOMEM: 5544 case EBADF: 5545 case EACCES: 5546 return (r); 5547 5548 default: 5549 bad_error("load_pg", r); 5550 } 5551 5552 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5553 switch (r) { 5554 case 0: 5555 break; 5556 5557 case ECANCELED: 5558 case ECONNABORTED: 5559 case ENOMEM: 5560 case EBADF: 5561 case EACCES: 5562 internal_pgroup_free(lipg_i); 5563 return (r); 5564 5565 default: 5566 bad_error("load_pg", r); 5567 } 5568 5569 if (pg_equal(lipg_i, curpg_i)) { 5570 if (g_verbose) 5571 warn(deleting, ient->sc_fmri, imp_str); 5572 if (scf_pg_delete(imp_pg2) != 0) { 5573 switch (scf_error()) { 5574 case SCF_ERROR_DELETED: 5575 break; 5576 5577 case SCF_ERROR_CONNECTION_BROKEN: 5578 internal_pgroup_free(lipg_i); 5579 internal_pgroup_free(curpg_i); 5580 return (ECONNABORTED); 5581 5582 case SCF_ERROR_NOT_SET: 5583 case SCF_ERROR_NOT_BOUND: 5584 default: 5585 bad_error("scf_pg_delete", scf_error()); 5586 } 5587 } 5588 } else { 5589 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5590 } 5591 5592 internal_pgroup_free(lipg_i); 5593 internal_pgroup_free(curpg_i); 5594 5595 return (0); 5596 } 5597 5598 /* 5599 * Only dependent pgs can have override set, and we skipped those 5600 * above. 5601 */ 5602 assert(!mpg->sc_pgroup_override); 5603 5604 /* compare */ 5605 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5606 switch (r) { 5607 case 0: 5608 break; 5609 5610 case ECANCELED: 5611 return (ENODEV); 5612 5613 case ECONNABORTED: 5614 case EBADF: 5615 case ENOMEM: 5616 case EACCES: 5617 return (r); 5618 5619 default: 5620 bad_error("load_pg", r); 5621 } 5622 5623 if (pg_equal(mpg, lipg_i)) { 5624 /* The manifest pg has not changed. Move on. */ 5625 r = 0; 5626 goto out; 5627 } 5628 5629 /* upgrade current properties according to lipg & mpg */ 5630 if (running != NULL) 5631 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5632 else 5633 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5634 if (r != 0) { 5635 switch (scf_error()) { 5636 case SCF_ERROR_CONNECTION_BROKEN: 5637 r = scferror2errno(scf_error()); 5638 goto out; 5639 5640 case SCF_ERROR_DELETED: 5641 if (running != NULL) 5642 r = ENODEV; 5643 else 5644 r = ECANCELED; 5645 goto out; 5646 5647 case SCF_ERROR_NOT_FOUND: 5648 break; 5649 5650 case SCF_ERROR_INVALID_ARGUMENT: 5651 case SCF_ERROR_HANDLE_MISMATCH: 5652 case SCF_ERROR_NOT_BOUND: 5653 case SCF_ERROR_NOT_SET: 5654 default: 5655 bad_error("entity_get_pg", scf_error()); 5656 } 5657 5658 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5659 5660 r = 0; 5661 goto out; 5662 } 5663 5664 r = load_pg_attrs(imp_pg2, &curpg_i); 5665 switch (r) { 5666 case 0: 5667 break; 5668 5669 case ECANCELED: 5670 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5671 r = 0; 5672 goto out; 5673 5674 case ECONNABORTED: 5675 case ENOMEM: 5676 goto out; 5677 5678 default: 5679 bad_error("load_pg_attrs", r); 5680 } 5681 5682 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5683 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5684 internal_pgroup_free(curpg_i); 5685 r = 0; 5686 goto out; 5687 } 5688 5689 internal_pgroup_free(curpg_i); 5690 5691 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5692 switch (r) { 5693 case 0: 5694 break; 5695 5696 case ECANCELED: 5697 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5698 r = 0; 5699 goto out; 5700 5701 case ECONNABORTED: 5702 case EBADF: 5703 case ENOMEM: 5704 case EACCES: 5705 goto out; 5706 5707 default: 5708 bad_error("load_pg", r); 5709 } 5710 5711 if (pg_equal(lipg_i, curpg_i) && 5712 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5713 int do_delete = 1; 5714 5715 if (g_verbose) 5716 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5717 ient->sc_fmri, mpg->sc_pgroup_name); 5718 5719 internal_pgroup_free(curpg_i); 5720 5721 if (running != NULL && 5722 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5723 switch (scf_error()) { 5724 case SCF_ERROR_DELETED: 5725 r = ECANCELED; 5726 goto out; 5727 5728 case SCF_ERROR_NOT_FOUND: 5729 do_delete = 0; 5730 break; 5731 5732 case SCF_ERROR_CONNECTION_BROKEN: 5733 r = scferror2errno(scf_error()); 5734 goto out; 5735 5736 case SCF_ERROR_HANDLE_MISMATCH: 5737 case SCF_ERROR_INVALID_ARGUMENT: 5738 case SCF_ERROR_NOT_SET: 5739 case SCF_ERROR_NOT_BOUND: 5740 default: 5741 bad_error("entity_get_pg", scf_error()); 5742 } 5743 } 5744 5745 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5746 switch (scf_error()) { 5747 case SCF_ERROR_DELETED: 5748 break; 5749 5750 case SCF_ERROR_CONNECTION_BROKEN: 5751 case SCF_ERROR_BACKEND_READONLY: 5752 case SCF_ERROR_BACKEND_ACCESS: 5753 r = scferror2errno(scf_error()); 5754 goto out; 5755 5756 case SCF_ERROR_PERMISSION_DENIED: 5757 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5758 ient->sc_fmri); 5759 r = scferror2errno(scf_error()); 5760 goto out; 5761 5762 case SCF_ERROR_NOT_SET: 5763 case SCF_ERROR_NOT_BOUND: 5764 default: 5765 bad_error("scf_pg_delete", scf_error()); 5766 } 5767 } 5768 5769 cbdata.sc_handle = g_hndl; 5770 cbdata.sc_parent = ent; 5771 cbdata.sc_service = issvc; 5772 cbdata.sc_flags = 0; 5773 cbdata.sc_source_fmri = ient->sc_fmri; 5774 cbdata.sc_target_fmri = ient->sc_fmri; 5775 5776 r = entity_pgroup_import(mpg, &cbdata); 5777 switch (r) { 5778 case UU_WALK_NEXT: 5779 r = 0; 5780 goto out; 5781 5782 case UU_WALK_ERROR: 5783 if (cbdata.sc_err == EEXIST) { 5784 warn(emsg_pg_added, ient->sc_fmri, 5785 mpg->sc_pgroup_name); 5786 r = EBUSY; 5787 } else { 5788 r = cbdata.sc_err; 5789 } 5790 goto out; 5791 5792 default: 5793 bad_error("entity_pgroup_import", r); 5794 } 5795 } 5796 5797 if (running != NULL && 5798 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5799 switch (scf_error()) { 5800 case SCF_ERROR_CONNECTION_BROKEN: 5801 case SCF_ERROR_DELETED: 5802 r = scferror2errno(scf_error()); 5803 goto out; 5804 5805 case SCF_ERROR_NOT_FOUND: 5806 break; 5807 5808 case SCF_ERROR_HANDLE_MISMATCH: 5809 case SCF_ERROR_INVALID_ARGUMENT: 5810 case SCF_ERROR_NOT_SET: 5811 case SCF_ERROR_NOT_BOUND: 5812 default: 5813 bad_error("entity_get_pg", scf_error()); 5814 } 5815 5816 cbdata.sc_handle = g_hndl; 5817 cbdata.sc_parent = ent; 5818 cbdata.sc_service = issvc; 5819 cbdata.sc_flags = SCI_FORCE; 5820 cbdata.sc_source_fmri = ient->sc_fmri; 5821 cbdata.sc_target_fmri = ient->sc_fmri; 5822 5823 r = entity_pgroup_import(mpg, &cbdata); 5824 switch (r) { 5825 case UU_WALK_NEXT: 5826 r = 0; 5827 goto out; 5828 5829 case UU_WALK_ERROR: 5830 if (cbdata.sc_err == EEXIST) { 5831 warn(emsg_pg_added, ient->sc_fmri, 5832 mpg->sc_pgroup_name); 5833 r = EBUSY; 5834 } else { 5835 r = cbdata.sc_err; 5836 } 5837 goto out; 5838 5839 default: 5840 bad_error("entity_pgroup_import", r); 5841 } 5842 } 5843 5844 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5845 internal_pgroup_free(curpg_i); 5846 switch (r) { 5847 case 0: 5848 ient->sc_import_state = IMPORT_PROP_BEGUN; 5849 break; 5850 5851 case ECANCELED: 5852 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5853 r = EBUSY; 5854 break; 5855 5856 case EPERM: 5857 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5858 break; 5859 5860 case EBUSY: 5861 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5862 break; 5863 5864 case ECONNABORTED: 5865 case ENOMEM: 5866 case ENOSPC: 5867 case EROFS: 5868 case EACCES: 5869 case EINVAL: 5870 break; 5871 5872 default: 5873 bad_error("upgrade_pg", r); 5874 } 5875 5876 out: 5877 internal_pgroup_free(lipg_i); 5878 return (r); 5879 } 5880 5881 /* 5882 * Upgrade the properties of ent according to snpl & ient. 5883 * 5884 * Returns 5885 * 0 - success 5886 * ECONNABORTED - repository connection broken 5887 * ENOMEM - out of memory 5888 * ENOSPC - configd is out of resources 5889 * ECANCELED - ent was deleted 5890 * ENODEV - entity containing snpl was deleted 5891 * - entity containing running was deleted 5892 * EBADF - imp_snpl is corrupt (error printed) 5893 * - ent has corrupt pg (error printed) 5894 * - dependent has corrupt pg (error printed) 5895 * - dependent target has a corrupt snapshot (error printed) 5896 * EBUSY - pg was added, changed, or deleted (error printed) 5897 * - dependent target was deleted (error printed) 5898 * - dependent pg changed (error printed) 5899 * EINVAL - invalid property group name (error printed) 5900 * - invalid property name (error printed) 5901 * - invalid value (error printed) 5902 * - ient has invalid pgroup or dependent (error printed) 5903 * EPERM - could not create property group (permission denied) (error printed) 5904 * - could not modify property group (permission denied) (error printed) 5905 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5906 * EROFS - could not create property group (repository read-only) 5907 * - couldn't delete, upgrade, or import pg or dependent 5908 * EACCES - could not create property group (backend access denied) 5909 * - couldn't delete, upgrade, or import pg or dependent 5910 * EEXIST - dependent collision in target service (error printed) 5911 */ 5912 static int 5913 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5914 entity_t *ient) 5915 { 5916 pgroup_t *pg, *rpg; 5917 int r; 5918 uu_list_t *pgs = ient->sc_pgroups; 5919 5920 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5921 5922 /* clear sc_sceen for pgs */ 5923 if (uu_list_walk(pgs, clear_int, 5924 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5925 bad_error("uu_list_walk", uu_error()); 5926 5927 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5928 switch (scf_error()) { 5929 case SCF_ERROR_DELETED: 5930 return (ENODEV); 5931 5932 case SCF_ERROR_CONNECTION_BROKEN: 5933 return (ECONNABORTED); 5934 5935 case SCF_ERROR_NOT_SET: 5936 case SCF_ERROR_NOT_BOUND: 5937 case SCF_ERROR_HANDLE_MISMATCH: 5938 default: 5939 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5940 } 5941 } 5942 5943 for (;;) { 5944 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5945 if (r == 0) 5946 break; 5947 if (r == 1) { 5948 r = process_old_pg(imp_pg, ient, ent, running); 5949 switch (r) { 5950 case 0: 5951 break; 5952 5953 case ECONNABORTED: 5954 case ENOMEM: 5955 case ENOSPC: 5956 case ECANCELED: 5957 case ENODEV: 5958 case EPERM: 5959 case EROFS: 5960 case EACCES: 5961 case EBADF: 5962 case EBUSY: 5963 case EINVAL: 5964 case EEXIST: 5965 return (r); 5966 5967 default: 5968 bad_error("process_old_pg", r); 5969 } 5970 continue; 5971 } 5972 if (r != -1) 5973 bad_error("scf_iter_next_pg", r); 5974 5975 switch (scf_error()) { 5976 case SCF_ERROR_DELETED: 5977 return (ENODEV); 5978 5979 case SCF_ERROR_CONNECTION_BROKEN: 5980 return (ECONNABORTED); 5981 5982 case SCF_ERROR_HANDLE_MISMATCH: 5983 case SCF_ERROR_NOT_BOUND: 5984 case SCF_ERROR_NOT_SET: 5985 case SCF_ERROR_INVALID_ARGUMENT: 5986 default: 5987 bad_error("scf_iter_next_pg", scf_error()); 5988 } 5989 } 5990 5991 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5992 if (pg->sc_pgroup_seen) 5993 continue; 5994 5995 /* pg is new */ 5996 5997 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5998 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5999 ent); 6000 switch (r) { 6001 case 0: 6002 break; 6003 6004 case ECONNABORTED: 6005 case ENOMEM: 6006 case ENOSPC: 6007 case ECANCELED: 6008 case ENODEV: 6009 case EBADF: 6010 case EBUSY: 6011 case EINVAL: 6012 case EPERM: 6013 case EROFS: 6014 case EACCES: 6015 case EEXIST: 6016 return (r); 6017 6018 default: 6019 bad_error("upgrade_dependents", r); 6020 } 6021 continue; 6022 } 6023 6024 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 6025 r = upgrade_manifestfiles(pg, ient, running, ent); 6026 switch (r) { 6027 case 0: 6028 break; 6029 6030 case ECONNABORTED: 6031 case ENOMEM: 6032 case ENOSPC: 6033 case ECANCELED: 6034 case ENODEV: 6035 case EBADF: 6036 case EBUSY: 6037 case EINVAL: 6038 case EPERM: 6039 case EROFS: 6040 case EACCES: 6041 case EEXIST: 6042 return (r); 6043 6044 default: 6045 bad_error("upgrade_manifestfiles", r); 6046 } 6047 continue; 6048 } 6049 6050 if (running != NULL) { 6051 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 6052 imp_pg); 6053 } else { 6054 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 6055 imp_pg); 6056 } 6057 if (r != 0) { 6058 scf_callback_t cbdata; 6059 6060 switch (scf_error()) { 6061 case SCF_ERROR_NOT_FOUND: 6062 break; 6063 6064 case SCF_ERROR_CONNECTION_BROKEN: 6065 return (scferror2errno(scf_error())); 6066 6067 case SCF_ERROR_DELETED: 6068 if (running != NULL) 6069 return (ENODEV); 6070 else 6071 return (scferror2errno(scf_error())); 6072 6073 case SCF_ERROR_INVALID_ARGUMENT: 6074 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 6075 pg->sc_pgroup_name); 6076 return (EINVAL); 6077 6078 case SCF_ERROR_NOT_SET: 6079 case SCF_ERROR_HANDLE_MISMATCH: 6080 case SCF_ERROR_NOT_BOUND: 6081 default: 6082 bad_error("entity_get_pg", scf_error()); 6083 } 6084 6085 /* User doesn't have pg, so import it. */ 6086 6087 cbdata.sc_handle = g_hndl; 6088 cbdata.sc_parent = ent; 6089 cbdata.sc_service = issvc; 6090 cbdata.sc_flags = SCI_FORCE; 6091 cbdata.sc_source_fmri = ient->sc_fmri; 6092 cbdata.sc_target_fmri = ient->sc_fmri; 6093 6094 r = entity_pgroup_import(pg, &cbdata); 6095 switch (r) { 6096 case UU_WALK_NEXT: 6097 ient->sc_import_state = IMPORT_PROP_BEGUN; 6098 continue; 6099 6100 case UU_WALK_ERROR: 6101 if (cbdata.sc_err == EEXIST) { 6102 warn(emsg_pg_added, ient->sc_fmri, 6103 pg->sc_pgroup_name); 6104 return (EBUSY); 6105 } 6106 return (cbdata.sc_err); 6107 6108 default: 6109 bad_error("entity_pgroup_import", r); 6110 } 6111 } 6112 6113 /* report differences between pg & current */ 6114 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 6115 switch (r) { 6116 case 0: 6117 break; 6118 6119 case ECANCELED: 6120 warn(emsg_pg_deleted, ient->sc_fmri, 6121 pg->sc_pgroup_name); 6122 return (EBUSY); 6123 6124 case ECONNABORTED: 6125 case EBADF: 6126 case ENOMEM: 6127 case EACCES: 6128 return (r); 6129 6130 default: 6131 bad_error("load_pg", r); 6132 } 6133 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 6134 internal_pgroup_free(rpg); 6135 rpg = NULL; 6136 } 6137 6138 return (0); 6139 } 6140 6141 /* 6142 * Import an instance. If it doesn't exist, create it. If it has 6143 * a last-import snapshot, upgrade its properties. Finish by updating its 6144 * last-import snapshot. If it doesn't have a last-import snapshot then it 6145 * could have been created for a dependent tag in another manifest. Import the 6146 * new properties. If there's a conflict, don't override, like now? 6147 * 6148 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 6149 * lcbdata->sc_err to 6150 * ECONNABORTED - repository connection broken 6151 * ENOMEM - out of memory 6152 * ENOSPC - svc.configd is out of resources 6153 * EEXIST - dependency collision in dependent service (error printed) 6154 * EPERM - couldn't create temporary instance (permission denied) 6155 * - couldn't import into temporary instance (permission denied) 6156 * - couldn't take snapshot (permission denied) 6157 * - couldn't upgrade properties (permission denied) 6158 * - couldn't import properties (permission denied) 6159 * - couldn't import dependents (permission denied) 6160 * EROFS - couldn't create temporary instance (repository read-only) 6161 * - couldn't import into temporary instance (repository read-only) 6162 * - couldn't upgrade properties (repository read-only) 6163 * - couldn't import properties (repository read-only) 6164 * - couldn't import dependents (repository read-only) 6165 * EACCES - couldn't create temporary instance (backend access denied) 6166 * - couldn't import into temporary instance (backend access denied) 6167 * - couldn't upgrade properties (backend access denied) 6168 * - couldn't import properties (backend access denied) 6169 * - couldn't import dependents (backend access denied) 6170 * EINVAL - invalid instance name (error printed) 6171 * - invalid pgroup_t's (error printed) 6172 * - invalid dependents (error printed) 6173 * EBUSY - temporary service deleted (error printed) 6174 * - temporary instance deleted (error printed) 6175 * - temporary instance changed (error printed) 6176 * - temporary instance already exists (error printed) 6177 * - instance deleted (error printed) 6178 * EBADF - instance has corrupt last-import snapshot (error printed) 6179 * - instance is corrupt (error printed) 6180 * - dependent has corrupt pg (error printed) 6181 * - dependent target has a corrupt snapshot (error printed) 6182 * -1 - unknown libscf error (error printed) 6183 */ 6184 static int 6185 lscf_instance_import(void *v, void *pvt) 6186 { 6187 entity_t *inst = v; 6188 scf_callback_t ctx; 6189 scf_callback_t *lcbdata = pvt; 6190 scf_service_t *rsvc = lcbdata->sc_parent; 6191 int r; 6192 scf_snaplevel_t *running; 6193 int flags = lcbdata->sc_flags; 6194 6195 const char * const emsg_tdel = 6196 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 6197 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 6198 "changed unexpectedly.\n"); 6199 const char * const emsg_del = gettext("%s changed unexpectedly " 6200 "(instance \"%s\" was deleted.)\n"); 6201 const char * const emsg_badsnap = gettext( 6202 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 6203 6204 /* 6205 * prepare last-import snapshot: 6206 * create temporary instance (service was precreated) 6207 * populate with properties from bundle 6208 * take snapshot 6209 */ 6210 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 6211 switch (scf_error()) { 6212 case SCF_ERROR_CONNECTION_BROKEN: 6213 case SCF_ERROR_NO_RESOURCES: 6214 case SCF_ERROR_BACKEND_READONLY: 6215 case SCF_ERROR_BACKEND_ACCESS: 6216 return (stash_scferror(lcbdata)); 6217 6218 case SCF_ERROR_EXISTS: 6219 warn(gettext("Temporary service svc:/%s " 6220 "changed unexpectedly (instance \"%s\" added).\n"), 6221 imp_tsname, inst->sc_name); 6222 lcbdata->sc_err = EBUSY; 6223 return (UU_WALK_ERROR); 6224 6225 case SCF_ERROR_DELETED: 6226 warn(gettext("Temporary service svc:/%s " 6227 "was deleted unexpectedly.\n"), imp_tsname); 6228 lcbdata->sc_err = EBUSY; 6229 return (UU_WALK_ERROR); 6230 6231 case SCF_ERROR_INVALID_ARGUMENT: 6232 warn(gettext("Invalid instance name \"%s\".\n"), 6233 inst->sc_name); 6234 return (stash_scferror(lcbdata)); 6235 6236 case SCF_ERROR_PERMISSION_DENIED: 6237 warn(gettext("Could not create temporary instance " 6238 "\"%s\" in svc:/%s (permission denied).\n"), 6239 inst->sc_name, imp_tsname); 6240 return (stash_scferror(lcbdata)); 6241 6242 case SCF_ERROR_HANDLE_MISMATCH: 6243 case SCF_ERROR_NOT_BOUND: 6244 case SCF_ERROR_NOT_SET: 6245 default: 6246 bad_error("scf_service_add_instance", scf_error()); 6247 } 6248 } 6249 6250 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6251 inst->sc_name); 6252 if (r < 0) 6253 bad_error("snprintf", errno); 6254 6255 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 6256 lcbdata->sc_flags | SCI_NOENABLED); 6257 switch (r) { 6258 case 0: 6259 break; 6260 6261 case ECANCELED: 6262 warn(emsg_tdel, imp_tsname, inst->sc_name); 6263 lcbdata->sc_err = EBUSY; 6264 r = UU_WALK_ERROR; 6265 goto deltemp; 6266 6267 case EEXIST: 6268 warn(emsg_tchg, imp_tsname, inst->sc_name); 6269 lcbdata->sc_err = EBUSY; 6270 r = UU_WALK_ERROR; 6271 goto deltemp; 6272 6273 case ECONNABORTED: 6274 goto connaborted; 6275 6276 case ENOMEM: 6277 case ENOSPC: 6278 case EPERM: 6279 case EROFS: 6280 case EACCES: 6281 case EINVAL: 6282 case EBUSY: 6283 lcbdata->sc_err = r; 6284 r = UU_WALK_ERROR; 6285 goto deltemp; 6286 6287 default: 6288 bad_error("lscf_import_instance_pgs", r); 6289 } 6290 6291 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6292 inst->sc_name); 6293 if (r < 0) 6294 bad_error("snprintf", errno); 6295 6296 ctx.sc_handle = lcbdata->sc_handle; 6297 ctx.sc_parent = imp_tinst; 6298 ctx.sc_service = 0; 6299 ctx.sc_source_fmri = inst->sc_fmri; 6300 ctx.sc_target_fmri = imp_str; 6301 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 6302 UU_DEFAULT) != 0) { 6303 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6304 bad_error("uu_list_walk", uu_error()); 6305 6306 switch (ctx.sc_err) { 6307 case ECONNABORTED: 6308 goto connaborted; 6309 6310 case ECANCELED: 6311 warn(emsg_tdel, imp_tsname, inst->sc_name); 6312 lcbdata->sc_err = EBUSY; 6313 break; 6314 6315 case EEXIST: 6316 warn(emsg_tchg, imp_tsname, inst->sc_name); 6317 lcbdata->sc_err = EBUSY; 6318 break; 6319 6320 default: 6321 lcbdata->sc_err = ctx.sc_err; 6322 } 6323 r = UU_WALK_ERROR; 6324 goto deltemp; 6325 } 6326 6327 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 6328 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 6329 switch (scf_error()) { 6330 case SCF_ERROR_CONNECTION_BROKEN: 6331 goto connaborted; 6332 6333 case SCF_ERROR_NO_RESOURCES: 6334 r = stash_scferror(lcbdata); 6335 goto deltemp; 6336 6337 case SCF_ERROR_EXISTS: 6338 warn(emsg_tchg, imp_tsname, inst->sc_name); 6339 lcbdata->sc_err = EBUSY; 6340 r = UU_WALK_ERROR; 6341 goto deltemp; 6342 6343 case SCF_ERROR_PERMISSION_DENIED: 6344 warn(gettext("Could not take \"%s\" snapshot of %s " 6345 "(permission denied).\n"), snap_lastimport, 6346 imp_str); 6347 r = stash_scferror(lcbdata); 6348 goto deltemp; 6349 6350 default: 6351 scfwarn(); 6352 lcbdata->sc_err = -1; 6353 r = UU_WALK_ERROR; 6354 goto deltemp; 6355 6356 case SCF_ERROR_HANDLE_MISMATCH: 6357 case SCF_ERROR_INVALID_ARGUMENT: 6358 case SCF_ERROR_NOT_SET: 6359 bad_error("_scf_snapshot_take_new_named", scf_error()); 6360 } 6361 } 6362 6363 if (lcbdata->sc_flags & SCI_FRESH) 6364 goto fresh; 6365 6366 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 6367 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6368 imp_lisnap) != 0) { 6369 switch (scf_error()) { 6370 case SCF_ERROR_DELETED: 6371 warn(emsg_del, inst->sc_parent->sc_fmri, 6372 inst->sc_name); 6373 lcbdata->sc_err = EBUSY; 6374 r = UU_WALK_ERROR; 6375 goto deltemp; 6376 6377 case SCF_ERROR_NOT_FOUND: 6378 flags |= SCI_FORCE; 6379 goto nosnap; 6380 6381 case SCF_ERROR_CONNECTION_BROKEN: 6382 goto connaborted; 6383 6384 case SCF_ERROR_INVALID_ARGUMENT: 6385 case SCF_ERROR_HANDLE_MISMATCH: 6386 case SCF_ERROR_NOT_BOUND: 6387 case SCF_ERROR_NOT_SET: 6388 default: 6389 bad_error("scf_instance_get_snapshot", 6390 scf_error()); 6391 } 6392 } 6393 6394 /* upgrade */ 6395 6396 /* 6397 * compare new properties with last-import properties 6398 * upgrade current properties 6399 */ 6400 /* clear sc_sceen for pgs */ 6401 if (uu_list_walk(inst->sc_pgroups, clear_int, 6402 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 6403 0) 6404 bad_error("uu_list_walk", uu_error()); 6405 6406 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 6407 switch (r) { 6408 case 0: 6409 break; 6410 6411 case ECONNABORTED: 6412 goto connaborted; 6413 6414 case ECANCELED: 6415 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6416 lcbdata->sc_err = EBUSY; 6417 r = UU_WALK_ERROR; 6418 goto deltemp; 6419 6420 case ENOENT: 6421 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 6422 lcbdata->sc_err = EBADF; 6423 r = UU_WALK_ERROR; 6424 goto deltemp; 6425 6426 default: 6427 bad_error("get_snaplevel", r); 6428 } 6429 6430 if (scf_instance_get_snapshot(imp_inst, snap_running, 6431 imp_rsnap) != 0) { 6432 switch (scf_error()) { 6433 case SCF_ERROR_DELETED: 6434 warn(emsg_del, inst->sc_parent->sc_fmri, 6435 inst->sc_name); 6436 lcbdata->sc_err = EBUSY; 6437 r = UU_WALK_ERROR; 6438 goto deltemp; 6439 6440 case SCF_ERROR_NOT_FOUND: 6441 break; 6442 6443 case SCF_ERROR_CONNECTION_BROKEN: 6444 goto connaborted; 6445 6446 case SCF_ERROR_INVALID_ARGUMENT: 6447 case SCF_ERROR_HANDLE_MISMATCH: 6448 case SCF_ERROR_NOT_BOUND: 6449 case SCF_ERROR_NOT_SET: 6450 default: 6451 bad_error("scf_instance_get_snapshot", 6452 scf_error()); 6453 } 6454 6455 running = NULL; 6456 } else { 6457 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 6458 switch (r) { 6459 case 0: 6460 running = imp_rsnpl; 6461 break; 6462 6463 case ECONNABORTED: 6464 goto connaborted; 6465 6466 case ECANCELED: 6467 warn(emsg_del, inst->sc_parent->sc_fmri, 6468 inst->sc_name); 6469 lcbdata->sc_err = EBUSY; 6470 r = UU_WALK_ERROR; 6471 goto deltemp; 6472 6473 case ENOENT: 6474 warn(emsg_badsnap, snap_running, inst->sc_fmri); 6475 lcbdata->sc_err = EBADF; 6476 r = UU_WALK_ERROR; 6477 goto deltemp; 6478 6479 default: 6480 bad_error("get_snaplevel", r); 6481 } 6482 } 6483 6484 r = upgrade_props(imp_inst, running, imp_snpl, inst); 6485 switch (r) { 6486 case 0: 6487 break; 6488 6489 case ECANCELED: 6490 case ENODEV: 6491 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6492 lcbdata->sc_err = EBUSY; 6493 r = UU_WALK_ERROR; 6494 goto deltemp; 6495 6496 case ECONNABORTED: 6497 goto connaborted; 6498 6499 case ENOMEM: 6500 case ENOSPC: 6501 case EBADF: 6502 case EBUSY: 6503 case EINVAL: 6504 case EPERM: 6505 case EROFS: 6506 case EACCES: 6507 case EEXIST: 6508 lcbdata->sc_err = r; 6509 r = UU_WALK_ERROR; 6510 goto deltemp; 6511 6512 default: 6513 bad_error("upgrade_props", r); 6514 } 6515 6516 inst->sc_import_state = IMPORT_PROP_DONE; 6517 } else { 6518 switch (scf_error()) { 6519 case SCF_ERROR_CONNECTION_BROKEN: 6520 goto connaborted; 6521 6522 case SCF_ERROR_NOT_FOUND: 6523 break; 6524 6525 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6526 case SCF_ERROR_HANDLE_MISMATCH: 6527 case SCF_ERROR_NOT_BOUND: 6528 case SCF_ERROR_NOT_SET: 6529 default: 6530 bad_error("scf_service_get_instance", scf_error()); 6531 } 6532 6533 fresh: 6534 /* create instance */ 6535 if (scf_service_add_instance(rsvc, inst->sc_name, 6536 imp_inst) != 0) { 6537 switch (scf_error()) { 6538 case SCF_ERROR_CONNECTION_BROKEN: 6539 goto connaborted; 6540 6541 case SCF_ERROR_NO_RESOURCES: 6542 case SCF_ERROR_BACKEND_READONLY: 6543 case SCF_ERROR_BACKEND_ACCESS: 6544 r = stash_scferror(lcbdata); 6545 goto deltemp; 6546 6547 case SCF_ERROR_EXISTS: 6548 warn(gettext("%s changed unexpectedly " 6549 "(instance \"%s\" added).\n"), 6550 inst->sc_parent->sc_fmri, inst->sc_name); 6551 lcbdata->sc_err = EBUSY; 6552 r = UU_WALK_ERROR; 6553 goto deltemp; 6554 6555 case SCF_ERROR_PERMISSION_DENIED: 6556 warn(gettext("Could not create \"%s\" instance " 6557 "in %s (permission denied).\n"), 6558 inst->sc_name, inst->sc_parent->sc_fmri); 6559 r = stash_scferror(lcbdata); 6560 goto deltemp; 6561 6562 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6563 case SCF_ERROR_HANDLE_MISMATCH: 6564 case SCF_ERROR_NOT_BOUND: 6565 case SCF_ERROR_NOT_SET: 6566 default: 6567 bad_error("scf_service_add_instance", 6568 scf_error()); 6569 } 6570 } 6571 6572 nosnap: 6573 /* 6574 * Create a last-import snapshot to serve as an attachment 6575 * point for the real one from the temporary instance. Since 6576 * the contents is irrelevant, take it now, while the instance 6577 * is empty, to minimize svc.configd's work. 6578 */ 6579 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6580 imp_lisnap) != 0) { 6581 switch (scf_error()) { 6582 case SCF_ERROR_CONNECTION_BROKEN: 6583 goto connaborted; 6584 6585 case SCF_ERROR_NO_RESOURCES: 6586 r = stash_scferror(lcbdata); 6587 goto deltemp; 6588 6589 case SCF_ERROR_EXISTS: 6590 warn(gettext("%s changed unexpectedly " 6591 "(snapshot \"%s\" added).\n"), 6592 inst->sc_fmri, snap_lastimport); 6593 lcbdata->sc_err = EBUSY; 6594 r = UU_WALK_ERROR; 6595 goto deltemp; 6596 6597 case SCF_ERROR_PERMISSION_DENIED: 6598 warn(gettext("Could not take \"%s\" snapshot " 6599 "of %s (permission denied).\n"), 6600 snap_lastimport, inst->sc_fmri); 6601 r = stash_scferror(lcbdata); 6602 goto deltemp; 6603 6604 default: 6605 scfwarn(); 6606 lcbdata->sc_err = -1; 6607 r = UU_WALK_ERROR; 6608 goto deltemp; 6609 6610 case SCF_ERROR_NOT_SET: 6611 case SCF_ERROR_INTERNAL: 6612 case SCF_ERROR_INVALID_ARGUMENT: 6613 case SCF_ERROR_HANDLE_MISMATCH: 6614 bad_error("_scf_snapshot_take_new", 6615 scf_error()); 6616 } 6617 } 6618 6619 if (li_only) 6620 goto lionly; 6621 6622 inst->sc_import_state = IMPORT_PROP_BEGUN; 6623 6624 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6625 flags); 6626 switch (r) { 6627 case 0: 6628 break; 6629 6630 case ECONNABORTED: 6631 goto connaborted; 6632 6633 case ECANCELED: 6634 warn(gettext("%s changed unexpectedly " 6635 "(instance \"%s\" deleted).\n"), 6636 inst->sc_parent->sc_fmri, inst->sc_name); 6637 lcbdata->sc_err = EBUSY; 6638 r = UU_WALK_ERROR; 6639 goto deltemp; 6640 6641 case EEXIST: 6642 warn(gettext("%s changed unexpectedly " 6643 "(property group added).\n"), inst->sc_fmri); 6644 lcbdata->sc_err = EBUSY; 6645 r = UU_WALK_ERROR; 6646 goto deltemp; 6647 6648 default: 6649 lcbdata->sc_err = r; 6650 r = UU_WALK_ERROR; 6651 goto deltemp; 6652 6653 case EINVAL: /* caught above */ 6654 bad_error("lscf_import_instance_pgs", r); 6655 } 6656 6657 ctx.sc_parent = imp_inst; 6658 ctx.sc_service = 0; 6659 ctx.sc_trans = NULL; 6660 ctx.sc_flags = 0; 6661 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6662 &ctx, UU_DEFAULT) != 0) { 6663 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6664 bad_error("uu_list_walk", uu_error()); 6665 6666 if (ctx.sc_err == ECONNABORTED) 6667 goto connaborted; 6668 lcbdata->sc_err = ctx.sc_err; 6669 r = UU_WALK_ERROR; 6670 goto deltemp; 6671 } 6672 6673 inst->sc_import_state = IMPORT_PROP_DONE; 6674 6675 if (g_verbose) 6676 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6677 snap_initial, inst->sc_fmri); 6678 r = take_snap(imp_inst, snap_initial, imp_snap); 6679 switch (r) { 6680 case 0: 6681 break; 6682 6683 case ECONNABORTED: 6684 goto connaborted; 6685 6686 case ENOSPC: 6687 case -1: 6688 lcbdata->sc_err = r; 6689 r = UU_WALK_ERROR; 6690 goto deltemp; 6691 6692 case ECANCELED: 6693 warn(gettext("%s changed unexpectedly " 6694 "(instance %s deleted).\n"), 6695 inst->sc_parent->sc_fmri, inst->sc_name); 6696 lcbdata->sc_err = r; 6697 r = UU_WALK_ERROR; 6698 goto deltemp; 6699 6700 case EPERM: 6701 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6702 lcbdata->sc_err = r; 6703 r = UU_WALK_ERROR; 6704 goto deltemp; 6705 6706 default: 6707 bad_error("take_snap", r); 6708 } 6709 } 6710 6711 lionly: 6712 if (lcbdata->sc_flags & SCI_NOSNAP) 6713 goto deltemp; 6714 6715 /* transfer snapshot from temporary instance */ 6716 if (g_verbose) 6717 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6718 snap_lastimport, inst->sc_fmri); 6719 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6720 switch (scf_error()) { 6721 case SCF_ERROR_CONNECTION_BROKEN: 6722 goto connaborted; 6723 6724 case SCF_ERROR_NO_RESOURCES: 6725 r = stash_scferror(lcbdata); 6726 goto deltemp; 6727 6728 case SCF_ERROR_PERMISSION_DENIED: 6729 warn(gettext("Could not take \"%s\" snapshot for %s " 6730 "(permission denied).\n"), snap_lastimport, 6731 inst->sc_fmri); 6732 r = stash_scferror(lcbdata); 6733 goto deltemp; 6734 6735 case SCF_ERROR_NOT_SET: 6736 case SCF_ERROR_HANDLE_MISMATCH: 6737 default: 6738 bad_error("_scf_snapshot_attach", scf_error()); 6739 } 6740 } 6741 6742 inst->sc_import_state = IMPORT_COMPLETE; 6743 6744 r = UU_WALK_NEXT; 6745 6746 deltemp: 6747 /* delete temporary instance */ 6748 if (scf_instance_delete(imp_tinst) != 0) { 6749 switch (scf_error()) { 6750 case SCF_ERROR_DELETED: 6751 break; 6752 6753 case SCF_ERROR_CONNECTION_BROKEN: 6754 goto connaborted; 6755 6756 case SCF_ERROR_NOT_SET: 6757 case SCF_ERROR_NOT_BOUND: 6758 default: 6759 bad_error("scf_instance_delete", scf_error()); 6760 } 6761 } 6762 6763 return (r); 6764 6765 connaborted: 6766 warn(gettext("Could not delete svc:/%s:%s " 6767 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6768 lcbdata->sc_err = ECONNABORTED; 6769 return (UU_WALK_ERROR); 6770 } 6771 6772 /* 6773 * When an instance is imported we end up telling configd about it. Once we tell 6774 * configd about these changes, startd eventually notices. If this is a new 6775 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter) 6776 * property group. However, many of the other tools expect that this property 6777 * group exists and has certain values. 6778 * 6779 * These values are added asynchronously by startd. We should not return from 6780 * this routine until we can verify that the property group we need is there. 6781 * 6782 * Before we go ahead and verify this, we have to ask ourselves an important 6783 * question: Is the early manifest service currently running? Because if it is 6784 * running and it has invoked us, then the service will never get a restarter 6785 * property because svc.startd is blocked on EMI finishing before it lets itself 6786 * fully connect to svc.configd. Of course, this means that this race condition 6787 * is in fact impossible to 100% eliminate. 6788 * 6789 * svc.startd makes sure that EMI only runs once and has succeeded by checking 6790 * the state of the EMI instance. If it is online it bails out and makes sure 6791 * that it doesn't run again. In this case, we're going to do something similar, 6792 * only if the state is online, then we're going to actually verify. EMI always 6793 * has to be present, but it can be explicitly disabled to reduce the amount of 6794 * damage it can cause. If EMI has been disabled then we no longer have to worry 6795 * about the implicit race condition and can go ahead and check things. If EMI 6796 * is in some state that isn't online or disabled and isn't runinng, then we 6797 * assume that things are rather bad and we're not going to get in your way, 6798 * even if the rest of SMF does. 6799 * 6800 * Returns 0 on success or returns an errno. 6801 */ 6802 #ifndef NATIVE_BUILD 6803 static int 6804 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst) 6805 { 6806 int ret, err; 6807 struct timespec ts; 6808 char *emi_state; 6809 6810 /* 6811 * smf_get_state does not distinguish between its different failure 6812 * modes: memory allocation failures, SMF internal failures, and a lack 6813 * of EMI entirely because it's been removed. In these cases, we're 6814 * going to be conservative and opt to say that if we don't know, better 6815 * to not block import or falsely warn to the user. 6816 */ 6817 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) { 6818 return (0); 6819 } 6820 6821 /* 6822 * As per the block comment for this function check the state of EMI 6823 */ 6824 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 && 6825 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) { 6826 warn(gettext("Not validating instance %s:%s because EMI's " 6827 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state); 6828 free(emi_state); 6829 return (0); 6830 } 6831 6832 free(emi_state); 6833 6834 /* 6835 * First we have to get the property. 6836 */ 6837 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) { 6838 ret = scf_error(); 6839 warn(gettext("Failed to look up service: %s\n"), svc->sc_name); 6840 return (ret); 6841 } 6842 6843 /* 6844 * We should always be able to get the instance. It should already 6845 * exist because we just created it or got it. There probably is a 6846 * slim chance that someone may have come in and deleted it though from 6847 * under us. 6848 */ 6849 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst)) 6850 != 0) { 6851 ret = scf_error(); 6852 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name); 6853 switch (ret) { 6854 case SCF_ERROR_DELETED: 6855 err = ENODEV; 6856 break; 6857 case SCF_ERROR_CONNECTION_BROKEN: 6858 warn(gettext("Lost repository connection\n")); 6859 err = ECONNABORTED; 6860 break; 6861 case SCF_ERROR_NOT_FOUND: 6862 warn(gettext("Instance \"%s\" disappeared out from " 6863 "under us.\n"), inst->sc_name); 6864 err = ENOENT; 6865 break; 6866 default: 6867 bad_error("scf_service_get_instance", ret); 6868 } 6869 6870 return (err); 6871 } 6872 6873 /* 6874 * An astute observer may want to use _scf_wait_pg which would notify us 6875 * of a property group change, unfortunately that does not work if the 6876 * property group in question does not exist. So instead we have to 6877 * manually poll and ask smf the best way to get to it. 6878 */ 6879 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg)) 6880 != SCF_SUCCESS) { 6881 ret = scf_error(); 6882 if (ret != SCF_ERROR_NOT_FOUND) { 6883 warn(gettext("Failed to get restarter property " 6884 "group for instance: %s\n"), inst->sc_name); 6885 switch (ret) { 6886 case SCF_ERROR_DELETED: 6887 err = ENODEV; 6888 break; 6889 case SCF_ERROR_CONNECTION_BROKEN: 6890 warn(gettext("Lost repository connection\n")); 6891 err = ECONNABORTED; 6892 break; 6893 default: 6894 bad_error("scf_service_get_instance", ret); 6895 } 6896 6897 return (err); 6898 } 6899 6900 ts.tv_sec = pg_timeout / NANOSEC; 6901 ts.tv_nsec = pg_timeout % NANOSEC; 6902 6903 (void) nanosleep(&ts, NULL); 6904 } 6905 6906 /* 6907 * svcadm also expects that the SCF_PROPERTY_STATE property is present. 6908 * So in addition to the property group being present, we need to wait 6909 * for the property to be there in some form. 6910 * 6911 * Note that a property group is a frozen snapshot in time. To properly 6912 * get beyond this, you have to refresh the property group each time. 6913 */ 6914 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE, 6915 imp_prop)) != 0) { 6916 6917 ret = scf_error(); 6918 if (ret != SCF_ERROR_NOT_FOUND) { 6919 warn(gettext("Failed to get property %s from the " 6920 "restarter property group of instance %s\n"), 6921 SCF_PROPERTY_STATE, inst->sc_name); 6922 switch (ret) { 6923 case SCF_ERROR_CONNECTION_BROKEN: 6924 warn(gettext("Lost repository connection\n")); 6925 err = ECONNABORTED; 6926 break; 6927 case SCF_ERROR_DELETED: 6928 err = ENODEV; 6929 break; 6930 default: 6931 bad_error("scf_pg_get_property", ret); 6932 } 6933 6934 return (err); 6935 } 6936 6937 ts.tv_sec = pg_timeout / NANOSEC; 6938 ts.tv_nsec = pg_timeout % NANOSEC; 6939 6940 (void) nanosleep(&ts, NULL); 6941 6942 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg); 6943 if (ret != SCF_SUCCESS) { 6944 warn(gettext("Failed to get restarter property " 6945 "group for instance: %s\n"), inst->sc_name); 6946 switch (ret) { 6947 case SCF_ERROR_DELETED: 6948 err = ENODEV; 6949 break; 6950 case SCF_ERROR_CONNECTION_BROKEN: 6951 warn(gettext("Lost repository connection\n")); 6952 err = ECONNABORTED; 6953 break; 6954 default: 6955 bad_error("scf_service_get_instance", ret); 6956 } 6957 6958 return (err); 6959 } 6960 } 6961 6962 /* 6963 * We don't have to free the property groups or other values that we got 6964 * because we stored them in global variables that are allocated and 6965 * freed by the routines that call into these functions. Unless of 6966 * course the rest of the code here that we are basing this on is 6967 * mistaken. 6968 */ 6969 return (0); 6970 } 6971 #endif 6972 6973 /* 6974 * If the service is missing, create it, import its properties, and import the 6975 * instances. Since the service is brand new, it should be empty, and if we 6976 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6977 * 6978 * If the service exists, we want to upgrade its properties and import the 6979 * instances. Upgrade requires a last-import snapshot, though, which are 6980 * children of instances, so first we'll have to go through the instances 6981 * looking for a last-import snapshot. If we don't find one then we'll just 6982 * override-import the service properties (but don't delete existing 6983 * properties: another service might have declared us as a dependent). Before 6984 * we change anything, though, we want to take the previous snapshots. We 6985 * also give lscf_instance_import() a leg up on taking last-import snapshots 6986 * by importing the manifest's service properties into a temporary service. 6987 * 6988 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6989 * sets lcbdata->sc_err to 6990 * ECONNABORTED - repository connection broken 6991 * ENOMEM - out of memory 6992 * ENOSPC - svc.configd is out of resources 6993 * EPERM - couldn't create temporary service (error printed) 6994 * - couldn't import into temp service (error printed) 6995 * - couldn't create service (error printed) 6996 * - couldn't import dependent (error printed) 6997 * - couldn't take snapshot (error printed) 6998 * - couldn't create instance (error printed) 6999 * - couldn't create, modify, or delete pg (error printed) 7000 * - couldn't create, modify, or delete dependent (error printed) 7001 * - couldn't import instance (error printed) 7002 * EROFS - couldn't create temporary service (repository read-only) 7003 * - couldn't import into temporary service (repository read-only) 7004 * - couldn't create service (repository read-only) 7005 * - couldn't import dependent (repository read-only) 7006 * - couldn't create instance (repository read-only) 7007 * - couldn't create, modify, or delete pg or dependent 7008 * - couldn't import instance (repository read-only) 7009 * EACCES - couldn't create temporary service (backend access denied) 7010 * - couldn't import into temporary service (backend access denied) 7011 * - couldn't create service (backend access denied) 7012 * - couldn't import dependent (backend access denied) 7013 * - couldn't create instance (backend access denied) 7014 * - couldn't create, modify, or delete pg or dependent 7015 * - couldn't import instance (backend access denied) 7016 * EINVAL - service name is invalid (error printed) 7017 * - service name is too long (error printed) 7018 * - s has invalid pgroup (error printed) 7019 * - s has invalid dependent (error printed) 7020 * - instance name is invalid (error printed) 7021 * - instance entity_t is invalid (error printed) 7022 * EEXIST - couldn't create temporary service (already exists) (error printed) 7023 * - couldn't import dependent (dependency pg already exists) (printed) 7024 * - dependency collision in dependent service (error printed) 7025 * EBUSY - temporary service deleted (error printed) 7026 * - property group added to temporary service (error printed) 7027 * - new property group changed or was deleted (error printed) 7028 * - service was added unexpectedly (error printed) 7029 * - service was deleted unexpectedly (error printed) 7030 * - property group added to new service (error printed) 7031 * - instance added unexpectedly (error printed) 7032 * - instance deleted unexpectedly (error printed) 7033 * - dependent service deleted unexpectedly (error printed) 7034 * - pg was added, changed, or deleted (error printed) 7035 * - dependent pg changed (error printed) 7036 * - temporary instance added, changed, or deleted (error printed) 7037 * EBADF - a last-import snapshot is corrupt (error printed) 7038 * - the service is corrupt (error printed) 7039 * - a dependent is corrupt (error printed) 7040 * - an instance is corrupt (error printed) 7041 * - an instance has a corrupt last-import snapshot (error printed) 7042 * - dependent target has a corrupt snapshot (error printed) 7043 * -1 - unknown libscf error (error printed) 7044 */ 7045 static int 7046 lscf_service_import(void *v, void *pvt) 7047 { 7048 entity_t *s = v; 7049 scf_callback_t cbdata; 7050 scf_callback_t *lcbdata = pvt; 7051 scf_scope_t *scope = lcbdata->sc_parent; 7052 entity_t *inst, linst; 7053 int r; 7054 int fresh = 0; 7055 scf_snaplevel_t *running; 7056 int have_ge = 0; 7057 boolean_t retried = B_FALSE; 7058 7059 const char * const ts_deleted = gettext("Temporary service svc:/%s " 7060 "was deleted unexpectedly.\n"); 7061 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 7062 "changed unexpectedly (property group added).\n"); 7063 const char * const s_deleted = 7064 gettext("%s was deleted unexpectedly.\n"); 7065 const char * const i_deleted = 7066 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 7067 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 7068 "is corrupt (missing service snaplevel).\n"); 7069 const char * const s_mfile_upd = 7070 gettext("Unable to update the manifest file connection " 7071 "for %s\n"); 7072 7073 li_only = 0; 7074 /* Validate the service name */ 7075 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7076 switch (scf_error()) { 7077 case SCF_ERROR_CONNECTION_BROKEN: 7078 return (stash_scferror(lcbdata)); 7079 7080 case SCF_ERROR_INVALID_ARGUMENT: 7081 warn(gettext("\"%s\" is an invalid service name. " 7082 "Cannot import.\n"), s->sc_name); 7083 return (stash_scferror(lcbdata)); 7084 7085 case SCF_ERROR_NOT_FOUND: 7086 break; 7087 7088 case SCF_ERROR_HANDLE_MISMATCH: 7089 case SCF_ERROR_NOT_BOUND: 7090 case SCF_ERROR_NOT_SET: 7091 default: 7092 bad_error("scf_scope_get_service", scf_error()); 7093 } 7094 } 7095 7096 /* create temporary service */ 7097 /* 7098 * the size of the buffer was reduced to max_scf_name_len to prevent 7099 * hitting bug 6681151. After the bug fix, the size of the buffer 7100 * should be restored to its original value (max_scf_name_len +1) 7101 */ 7102 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 7103 if (r < 0) 7104 bad_error("snprintf", errno); 7105 if (r > max_scf_name_len) { 7106 warn(gettext( 7107 "Service name \"%s\" is too long. Cannot import.\n"), 7108 s->sc_name); 7109 lcbdata->sc_err = EINVAL; 7110 return (UU_WALK_ERROR); 7111 } 7112 7113 retry: 7114 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 7115 switch (scf_error()) { 7116 case SCF_ERROR_CONNECTION_BROKEN: 7117 case SCF_ERROR_NO_RESOURCES: 7118 case SCF_ERROR_BACKEND_READONLY: 7119 case SCF_ERROR_BACKEND_ACCESS: 7120 return (stash_scferror(lcbdata)); 7121 7122 case SCF_ERROR_EXISTS: 7123 if (!retried) { 7124 lscf_delete(imp_tsname, 0); 7125 retried = B_TRUE; 7126 goto retry; 7127 } 7128 warn(gettext( 7129 "Temporary service \"%s\" must be deleted before " 7130 "this manifest can be imported.\n"), imp_tsname); 7131 return (stash_scferror(lcbdata)); 7132 7133 case SCF_ERROR_PERMISSION_DENIED: 7134 warn(gettext("Could not create temporary service " 7135 "\"%s\" (permission denied).\n"), imp_tsname); 7136 return (stash_scferror(lcbdata)); 7137 7138 case SCF_ERROR_INVALID_ARGUMENT: 7139 case SCF_ERROR_HANDLE_MISMATCH: 7140 case SCF_ERROR_NOT_BOUND: 7141 case SCF_ERROR_NOT_SET: 7142 default: 7143 bad_error("scf_scope_add_service", scf_error()); 7144 } 7145 } 7146 7147 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 7148 if (r < 0) 7149 bad_error("snprintf", errno); 7150 7151 cbdata.sc_handle = lcbdata->sc_handle; 7152 cbdata.sc_parent = imp_tsvc; 7153 cbdata.sc_service = 1; 7154 cbdata.sc_source_fmri = s->sc_fmri; 7155 cbdata.sc_target_fmri = imp_str; 7156 cbdata.sc_flags = 0; 7157 7158 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 7159 UU_DEFAULT) != 0) { 7160 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7161 bad_error("uu_list_walk", uu_error()); 7162 7163 lcbdata->sc_err = cbdata.sc_err; 7164 switch (cbdata.sc_err) { 7165 case ECONNABORTED: 7166 goto connaborted; 7167 7168 case ECANCELED: 7169 warn(ts_deleted, imp_tsname); 7170 lcbdata->sc_err = EBUSY; 7171 return (UU_WALK_ERROR); 7172 7173 case EEXIST: 7174 warn(ts_pg_added, imp_tsname); 7175 lcbdata->sc_err = EBUSY; 7176 return (UU_WALK_ERROR); 7177 } 7178 7179 r = UU_WALK_ERROR; 7180 goto deltemp; 7181 } 7182 7183 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 7184 UU_DEFAULT) != 0) { 7185 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7186 bad_error("uu_list_walk", uu_error()); 7187 7188 lcbdata->sc_err = cbdata.sc_err; 7189 switch (cbdata.sc_err) { 7190 case ECONNABORTED: 7191 goto connaborted; 7192 7193 case ECANCELED: 7194 warn(ts_deleted, imp_tsname); 7195 lcbdata->sc_err = EBUSY; 7196 return (UU_WALK_ERROR); 7197 7198 case EEXIST: 7199 warn(ts_pg_added, imp_tsname); 7200 lcbdata->sc_err = EBUSY; 7201 return (UU_WALK_ERROR); 7202 } 7203 7204 r = UU_WALK_ERROR; 7205 goto deltemp; 7206 } 7207 7208 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7209 switch (scf_error()) { 7210 case SCF_ERROR_NOT_FOUND: 7211 break; 7212 7213 case SCF_ERROR_CONNECTION_BROKEN: 7214 goto connaborted; 7215 7216 case SCF_ERROR_INVALID_ARGUMENT: 7217 case SCF_ERROR_HANDLE_MISMATCH: 7218 case SCF_ERROR_NOT_BOUND: 7219 case SCF_ERROR_NOT_SET: 7220 default: 7221 bad_error("scf_scope_get_service", scf_error()); 7222 } 7223 7224 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 7225 switch (scf_error()) { 7226 case SCF_ERROR_CONNECTION_BROKEN: 7227 goto connaborted; 7228 7229 case SCF_ERROR_NO_RESOURCES: 7230 case SCF_ERROR_BACKEND_READONLY: 7231 case SCF_ERROR_BACKEND_ACCESS: 7232 r = stash_scferror(lcbdata); 7233 goto deltemp; 7234 7235 case SCF_ERROR_EXISTS: 7236 warn(gettext("Scope \"%s\" changed unexpectedly" 7237 " (service \"%s\" added).\n"), 7238 SCF_SCOPE_LOCAL, s->sc_name); 7239 lcbdata->sc_err = EBUSY; 7240 goto deltemp; 7241 7242 case SCF_ERROR_PERMISSION_DENIED: 7243 warn(gettext("Could not create service \"%s\" " 7244 "(permission denied).\n"), s->sc_name); 7245 goto deltemp; 7246 7247 case SCF_ERROR_INVALID_ARGUMENT: 7248 case SCF_ERROR_HANDLE_MISMATCH: 7249 case SCF_ERROR_NOT_BOUND: 7250 case SCF_ERROR_NOT_SET: 7251 default: 7252 bad_error("scf_scope_add_service", scf_error()); 7253 } 7254 } 7255 7256 s->sc_import_state = IMPORT_PROP_BEGUN; 7257 7258 /* import service properties */ 7259 cbdata.sc_handle = lcbdata->sc_handle; 7260 cbdata.sc_parent = imp_svc; 7261 cbdata.sc_service = 1; 7262 cbdata.sc_flags = lcbdata->sc_flags; 7263 cbdata.sc_source_fmri = s->sc_fmri; 7264 cbdata.sc_target_fmri = s->sc_fmri; 7265 7266 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7267 &cbdata, UU_DEFAULT) != 0) { 7268 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7269 bad_error("uu_list_walk", uu_error()); 7270 7271 lcbdata->sc_err = cbdata.sc_err; 7272 switch (cbdata.sc_err) { 7273 case ECONNABORTED: 7274 goto connaborted; 7275 7276 case ECANCELED: 7277 warn(s_deleted, s->sc_fmri); 7278 lcbdata->sc_err = EBUSY; 7279 return (UU_WALK_ERROR); 7280 7281 case EEXIST: 7282 warn(gettext("%s changed unexpectedly " 7283 "(property group added).\n"), s->sc_fmri); 7284 lcbdata->sc_err = EBUSY; 7285 return (UU_WALK_ERROR); 7286 7287 case EINVAL: 7288 /* caught above */ 7289 bad_error("entity_pgroup_import", 7290 cbdata.sc_err); 7291 } 7292 7293 r = UU_WALK_ERROR; 7294 goto deltemp; 7295 } 7296 7297 cbdata.sc_trans = NULL; 7298 cbdata.sc_flags = 0; 7299 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 7300 &cbdata, UU_DEFAULT) != 0) { 7301 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7302 bad_error("uu_list_walk", uu_error()); 7303 7304 lcbdata->sc_err = cbdata.sc_err; 7305 if (cbdata.sc_err == ECONNABORTED) 7306 goto connaborted; 7307 r = UU_WALK_ERROR; 7308 goto deltemp; 7309 } 7310 7311 s->sc_import_state = IMPORT_PROP_DONE; 7312 7313 /* 7314 * This is a new service, so we can't take previous snapshots 7315 * or upgrade service properties. 7316 */ 7317 fresh = 1; 7318 goto instances; 7319 } 7320 7321 /* Clear sc_seen for the instances. */ 7322 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 7323 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 7324 bad_error("uu_list_walk", uu_error()); 7325 7326 /* 7327 * Take previous snapshots for all instances. Even for ones not 7328 * mentioned in the bundle, since we might change their service 7329 * properties. 7330 */ 7331 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7332 switch (scf_error()) { 7333 case SCF_ERROR_CONNECTION_BROKEN: 7334 goto connaborted; 7335 7336 case SCF_ERROR_DELETED: 7337 warn(s_deleted, s->sc_fmri); 7338 lcbdata->sc_err = EBUSY; 7339 r = UU_WALK_ERROR; 7340 goto deltemp; 7341 7342 case SCF_ERROR_HANDLE_MISMATCH: 7343 case SCF_ERROR_NOT_BOUND: 7344 case SCF_ERROR_NOT_SET: 7345 default: 7346 bad_error("scf_iter_service_instances", scf_error()); 7347 } 7348 } 7349 7350 for (;;) { 7351 r = scf_iter_next_instance(imp_iter, imp_inst); 7352 if (r == 0) 7353 break; 7354 if (r != 1) { 7355 switch (scf_error()) { 7356 case SCF_ERROR_DELETED: 7357 warn(s_deleted, s->sc_fmri); 7358 lcbdata->sc_err = EBUSY; 7359 r = UU_WALK_ERROR; 7360 goto deltemp; 7361 7362 case SCF_ERROR_CONNECTION_BROKEN: 7363 goto connaborted; 7364 7365 case SCF_ERROR_NOT_BOUND: 7366 case SCF_ERROR_HANDLE_MISMATCH: 7367 case SCF_ERROR_INVALID_ARGUMENT: 7368 case SCF_ERROR_NOT_SET: 7369 default: 7370 bad_error("scf_iter_next_instance", 7371 scf_error()); 7372 } 7373 } 7374 7375 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 7376 switch (scf_error()) { 7377 case SCF_ERROR_DELETED: 7378 continue; 7379 7380 case SCF_ERROR_CONNECTION_BROKEN: 7381 goto connaborted; 7382 7383 case SCF_ERROR_NOT_SET: 7384 case SCF_ERROR_NOT_BOUND: 7385 default: 7386 bad_error("scf_instance_get_name", scf_error()); 7387 } 7388 } 7389 7390 if (g_verbose) 7391 warn(gettext( 7392 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 7393 snap_previous, s->sc_name, imp_str); 7394 7395 r = take_snap(imp_inst, snap_previous, imp_snap); 7396 switch (r) { 7397 case 0: 7398 break; 7399 7400 case ECANCELED: 7401 continue; 7402 7403 case ECONNABORTED: 7404 goto connaborted; 7405 7406 case EPERM: 7407 warn(gettext("Could not take \"%s\" snapshot of " 7408 "svc:/%s:%s (permission denied).\n"), 7409 snap_previous, s->sc_name, imp_str); 7410 lcbdata->sc_err = r; 7411 return (UU_WALK_ERROR); 7412 7413 case ENOSPC: 7414 case -1: 7415 lcbdata->sc_err = r; 7416 r = UU_WALK_ERROR; 7417 goto deltemp; 7418 7419 default: 7420 bad_error("take_snap", r); 7421 } 7422 7423 linst.sc_name = imp_str; 7424 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 7425 &linst, NULL, NULL); 7426 if (inst != NULL) { 7427 inst->sc_import_state = IMPORT_PREVIOUS; 7428 inst->sc_seen = 1; 7429 } 7430 } 7431 7432 /* 7433 * Create the new instances and take previous snapshots of 7434 * them. This is not necessary, but it maximizes data preservation. 7435 */ 7436 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 7437 inst != NULL; 7438 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 7439 inst)) { 7440 if (inst->sc_seen) 7441 continue; 7442 7443 if (scf_service_add_instance(imp_svc, inst->sc_name, 7444 imp_inst) != 0) { 7445 switch (scf_error()) { 7446 case SCF_ERROR_CONNECTION_BROKEN: 7447 goto connaborted; 7448 7449 case SCF_ERROR_BACKEND_READONLY: 7450 case SCF_ERROR_BACKEND_ACCESS: 7451 case SCF_ERROR_NO_RESOURCES: 7452 r = stash_scferror(lcbdata); 7453 goto deltemp; 7454 7455 case SCF_ERROR_EXISTS: 7456 warn(gettext("%s changed unexpectedly " 7457 "(instance \"%s\" added).\n"), s->sc_fmri, 7458 inst->sc_name); 7459 lcbdata->sc_err = EBUSY; 7460 r = UU_WALK_ERROR; 7461 goto deltemp; 7462 7463 case SCF_ERROR_INVALID_ARGUMENT: 7464 warn(gettext("Service \"%s\" has instance with " 7465 "invalid name \"%s\".\n"), s->sc_name, 7466 inst->sc_name); 7467 r = stash_scferror(lcbdata); 7468 goto deltemp; 7469 7470 case SCF_ERROR_PERMISSION_DENIED: 7471 warn(gettext("Could not create instance \"%s\" " 7472 "in %s (permission denied).\n"), 7473 inst->sc_name, s->sc_fmri); 7474 r = stash_scferror(lcbdata); 7475 goto deltemp; 7476 7477 case SCF_ERROR_HANDLE_MISMATCH: 7478 case SCF_ERROR_NOT_BOUND: 7479 case SCF_ERROR_NOT_SET: 7480 default: 7481 bad_error("scf_service_add_instance", 7482 scf_error()); 7483 } 7484 } 7485 7486 if (g_verbose) 7487 warn(gettext("Taking \"%s\" snapshot for " 7488 "new service %s.\n"), snap_previous, inst->sc_fmri); 7489 r = take_snap(imp_inst, snap_previous, imp_snap); 7490 switch (r) { 7491 case 0: 7492 break; 7493 7494 case ECANCELED: 7495 warn(i_deleted, s->sc_fmri, inst->sc_name); 7496 lcbdata->sc_err = EBUSY; 7497 r = UU_WALK_ERROR; 7498 goto deltemp; 7499 7500 case ECONNABORTED: 7501 goto connaborted; 7502 7503 case EPERM: 7504 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 7505 lcbdata->sc_err = r; 7506 r = UU_WALK_ERROR; 7507 goto deltemp; 7508 7509 case ENOSPC: 7510 case -1: 7511 r = UU_WALK_ERROR; 7512 goto deltemp; 7513 7514 default: 7515 bad_error("take_snap", r); 7516 } 7517 } 7518 7519 s->sc_import_state = IMPORT_PREVIOUS; 7520 7521 /* 7522 * Upgrade service properties, if we can find a last-import snapshot. 7523 * Any will do because we don't support different service properties 7524 * in different manifests, so all snaplevels of the service in all of 7525 * the last-import snapshots of the instances should be the same. 7526 */ 7527 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7528 switch (scf_error()) { 7529 case SCF_ERROR_CONNECTION_BROKEN: 7530 goto connaborted; 7531 7532 case SCF_ERROR_DELETED: 7533 warn(s_deleted, s->sc_fmri); 7534 lcbdata->sc_err = EBUSY; 7535 r = UU_WALK_ERROR; 7536 goto deltemp; 7537 7538 case SCF_ERROR_HANDLE_MISMATCH: 7539 case SCF_ERROR_NOT_BOUND: 7540 case SCF_ERROR_NOT_SET: 7541 default: 7542 bad_error("scf_iter_service_instances", scf_error()); 7543 } 7544 } 7545 7546 for (;;) { 7547 r = scf_iter_next_instance(imp_iter, imp_inst); 7548 if (r == -1) { 7549 switch (scf_error()) { 7550 case SCF_ERROR_DELETED: 7551 warn(s_deleted, s->sc_fmri); 7552 lcbdata->sc_err = EBUSY; 7553 r = UU_WALK_ERROR; 7554 goto deltemp; 7555 7556 case SCF_ERROR_CONNECTION_BROKEN: 7557 goto connaborted; 7558 7559 case SCF_ERROR_NOT_BOUND: 7560 case SCF_ERROR_HANDLE_MISMATCH: 7561 case SCF_ERROR_INVALID_ARGUMENT: 7562 case SCF_ERROR_NOT_SET: 7563 default: 7564 bad_error("scf_iter_next_instance", 7565 scf_error()); 7566 } 7567 } 7568 7569 if (r == 0) { 7570 /* 7571 * Didn't find any last-import snapshots. Override- 7572 * import the properties. Unless one of the instances 7573 * has a general/enabled property, in which case we're 7574 * probably running a last-import-capable svccfg for 7575 * the first time, and we should only take the 7576 * last-import snapshot. 7577 */ 7578 if (have_ge) { 7579 pgroup_t *mfpg; 7580 scf_callback_t mfcbdata; 7581 7582 li_only = 1; 7583 no_refresh = 1; 7584 /* 7585 * Need to go ahead and import the manifestfiles 7586 * pg if it exists. If the last-import snapshot 7587 * upgrade code is ever removed this code can 7588 * be removed as well. 7589 */ 7590 mfpg = internal_pgroup_find(s, 7591 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 7592 7593 if (mfpg) { 7594 mfcbdata.sc_handle = g_hndl; 7595 mfcbdata.sc_parent = imp_svc; 7596 mfcbdata.sc_service = 1; 7597 mfcbdata.sc_flags = SCI_FORCE; 7598 mfcbdata.sc_source_fmri = s->sc_fmri; 7599 mfcbdata.sc_target_fmri = s->sc_fmri; 7600 if (entity_pgroup_import(mfpg, 7601 &mfcbdata) != UU_WALK_NEXT) { 7602 warn(s_mfile_upd, s->sc_fmri); 7603 r = UU_WALK_ERROR; 7604 goto deltemp; 7605 } 7606 } 7607 break; 7608 } 7609 7610 s->sc_import_state = IMPORT_PROP_BEGUN; 7611 7612 cbdata.sc_handle = g_hndl; 7613 cbdata.sc_parent = imp_svc; 7614 cbdata.sc_service = 1; 7615 cbdata.sc_flags = SCI_FORCE; 7616 cbdata.sc_source_fmri = s->sc_fmri; 7617 cbdata.sc_target_fmri = s->sc_fmri; 7618 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7619 &cbdata, UU_DEFAULT) != 0) { 7620 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7621 bad_error("uu_list_walk", uu_error()); 7622 lcbdata->sc_err = cbdata.sc_err; 7623 switch (cbdata.sc_err) { 7624 case ECONNABORTED: 7625 goto connaborted; 7626 7627 case ECANCELED: 7628 warn(s_deleted, s->sc_fmri); 7629 lcbdata->sc_err = EBUSY; 7630 break; 7631 7632 case EINVAL: /* caught above */ 7633 case EEXIST: 7634 bad_error("entity_pgroup_import", 7635 cbdata.sc_err); 7636 } 7637 7638 r = UU_WALK_ERROR; 7639 goto deltemp; 7640 } 7641 7642 cbdata.sc_trans = NULL; 7643 cbdata.sc_flags = 0; 7644 if (uu_list_walk(s->sc_dependents, 7645 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 7646 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7647 bad_error("uu_list_walk", uu_error()); 7648 lcbdata->sc_err = cbdata.sc_err; 7649 if (cbdata.sc_err == ECONNABORTED) 7650 goto connaborted; 7651 r = UU_WALK_ERROR; 7652 goto deltemp; 7653 } 7654 break; 7655 } 7656 7657 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 7658 imp_snap) != 0) { 7659 switch (scf_error()) { 7660 case SCF_ERROR_DELETED: 7661 continue; 7662 7663 case SCF_ERROR_NOT_FOUND: 7664 break; 7665 7666 case SCF_ERROR_CONNECTION_BROKEN: 7667 goto connaborted; 7668 7669 case SCF_ERROR_HANDLE_MISMATCH: 7670 case SCF_ERROR_NOT_BOUND: 7671 case SCF_ERROR_INVALID_ARGUMENT: 7672 case SCF_ERROR_NOT_SET: 7673 default: 7674 bad_error("scf_instance_get_snapshot", 7675 scf_error()); 7676 } 7677 7678 if (have_ge) 7679 continue; 7680 7681 /* 7682 * Check for a general/enabled property. This is how 7683 * we tell whether to import if there turn out to be 7684 * no last-import snapshots. 7685 */ 7686 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 7687 imp_pg) == 0) { 7688 if (scf_pg_get_property(imp_pg, 7689 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 7690 have_ge = 1; 7691 } else { 7692 switch (scf_error()) { 7693 case SCF_ERROR_DELETED: 7694 case SCF_ERROR_NOT_FOUND: 7695 continue; 7696 7697 case SCF_ERROR_INVALID_ARGUMENT: 7698 case SCF_ERROR_HANDLE_MISMATCH: 7699 case SCF_ERROR_CONNECTION_BROKEN: 7700 case SCF_ERROR_NOT_BOUND: 7701 case SCF_ERROR_NOT_SET: 7702 default: 7703 bad_error("scf_pg_get_property", 7704 scf_error()); 7705 } 7706 } 7707 } else { 7708 switch (scf_error()) { 7709 case SCF_ERROR_DELETED: 7710 case SCF_ERROR_NOT_FOUND: 7711 continue; 7712 7713 case SCF_ERROR_CONNECTION_BROKEN: 7714 goto connaborted; 7715 7716 case SCF_ERROR_NOT_BOUND: 7717 case SCF_ERROR_NOT_SET: 7718 case SCF_ERROR_INVALID_ARGUMENT: 7719 case SCF_ERROR_HANDLE_MISMATCH: 7720 default: 7721 bad_error("scf_instance_get_pg", 7722 scf_error()); 7723 } 7724 } 7725 continue; 7726 } 7727 7728 /* find service snaplevel */ 7729 r = get_snaplevel(imp_snap, 1, imp_snpl); 7730 switch (r) { 7731 case 0: 7732 break; 7733 7734 case ECONNABORTED: 7735 goto connaborted; 7736 7737 case ECANCELED: 7738 continue; 7739 7740 case ENOENT: 7741 if (scf_instance_get_name(imp_inst, imp_str, 7742 imp_str_sz) < 0) 7743 (void) strcpy(imp_str, "?"); 7744 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 7745 lcbdata->sc_err = EBADF; 7746 r = UU_WALK_ERROR; 7747 goto deltemp; 7748 7749 default: 7750 bad_error("get_snaplevel", r); 7751 } 7752 7753 if (scf_instance_get_snapshot(imp_inst, snap_running, 7754 imp_rsnap) != 0) { 7755 switch (scf_error()) { 7756 case SCF_ERROR_DELETED: 7757 continue; 7758 7759 case SCF_ERROR_NOT_FOUND: 7760 break; 7761 7762 case SCF_ERROR_CONNECTION_BROKEN: 7763 goto connaborted; 7764 7765 case SCF_ERROR_INVALID_ARGUMENT: 7766 case SCF_ERROR_HANDLE_MISMATCH: 7767 case SCF_ERROR_NOT_BOUND: 7768 case SCF_ERROR_NOT_SET: 7769 default: 7770 bad_error("scf_instance_get_snapshot", 7771 scf_error()); 7772 } 7773 running = NULL; 7774 } else { 7775 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7776 switch (r) { 7777 case 0: 7778 running = imp_rsnpl; 7779 break; 7780 7781 case ECONNABORTED: 7782 goto connaborted; 7783 7784 case ECANCELED: 7785 continue; 7786 7787 case ENOENT: 7788 if (scf_instance_get_name(imp_inst, imp_str, 7789 imp_str_sz) < 0) 7790 (void) strcpy(imp_str, "?"); 7791 warn(badsnap, snap_running, s->sc_name, 7792 imp_str); 7793 lcbdata->sc_err = EBADF; 7794 r = UU_WALK_ERROR; 7795 goto deltemp; 7796 7797 default: 7798 bad_error("get_snaplevel", r); 7799 } 7800 } 7801 7802 if (g_verbose) { 7803 if (scf_instance_get_name(imp_inst, imp_str, 7804 imp_str_sz) < 0) 7805 (void) strcpy(imp_str, "?"); 7806 warn(gettext("Upgrading properties of %s according to " 7807 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7808 } 7809 7810 /* upgrade service properties */ 7811 r = upgrade_props(imp_svc, running, imp_snpl, s); 7812 if (r == 0) 7813 break; 7814 7815 switch (r) { 7816 case ECONNABORTED: 7817 goto connaborted; 7818 7819 case ECANCELED: 7820 warn(s_deleted, s->sc_fmri); 7821 lcbdata->sc_err = EBUSY; 7822 break; 7823 7824 case ENODEV: 7825 if (scf_instance_get_name(imp_inst, imp_str, 7826 imp_str_sz) < 0) 7827 (void) strcpy(imp_str, "?"); 7828 warn(i_deleted, s->sc_fmri, imp_str); 7829 lcbdata->sc_err = EBUSY; 7830 break; 7831 7832 default: 7833 lcbdata->sc_err = r; 7834 } 7835 7836 r = UU_WALK_ERROR; 7837 goto deltemp; 7838 } 7839 7840 s->sc_import_state = IMPORT_PROP_DONE; 7841 7842 instances: 7843 /* import instances */ 7844 cbdata.sc_handle = lcbdata->sc_handle; 7845 cbdata.sc_parent = imp_svc; 7846 cbdata.sc_service = 1; 7847 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7848 cbdata.sc_general = NULL; 7849 7850 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7851 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7852 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7853 bad_error("uu_list_walk", uu_error()); 7854 7855 lcbdata->sc_err = cbdata.sc_err; 7856 if (cbdata.sc_err == ECONNABORTED) 7857 goto connaborted; 7858 r = UU_WALK_ERROR; 7859 goto deltemp; 7860 } 7861 7862 s->sc_import_state = IMPORT_COMPLETE; 7863 r = UU_WALK_NEXT; 7864 7865 deltemp: 7866 /* delete temporary service */ 7867 if (scf_service_delete(imp_tsvc) != 0) { 7868 switch (scf_error()) { 7869 case SCF_ERROR_DELETED: 7870 break; 7871 7872 case SCF_ERROR_CONNECTION_BROKEN: 7873 goto connaborted; 7874 7875 case SCF_ERROR_EXISTS: 7876 warn(gettext( 7877 "Could not delete svc:/%s (instances exist).\n"), 7878 imp_tsname); 7879 break; 7880 7881 case SCF_ERROR_NOT_SET: 7882 case SCF_ERROR_NOT_BOUND: 7883 default: 7884 bad_error("scf_service_delete", scf_error()); 7885 } 7886 } 7887 7888 return (r); 7889 7890 connaborted: 7891 warn(gettext("Could not delete svc:/%s " 7892 "(repository connection broken).\n"), imp_tsname); 7893 lcbdata->sc_err = ECONNABORTED; 7894 return (UU_WALK_ERROR); 7895 } 7896 7897 static const char * 7898 import_progress(int st) 7899 { 7900 switch (st) { 7901 case 0: 7902 return (gettext("not reached.")); 7903 7904 case IMPORT_PREVIOUS: 7905 return (gettext("previous snapshot taken.")); 7906 7907 case IMPORT_PROP_BEGUN: 7908 return (gettext("some properties imported.")); 7909 7910 case IMPORT_PROP_DONE: 7911 return (gettext("properties imported.")); 7912 7913 case IMPORT_COMPLETE: 7914 return (gettext("imported.")); 7915 7916 case IMPORT_REFRESHED: 7917 return (gettext("refresh requested.")); 7918 7919 default: 7920 #ifndef NDEBUG 7921 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7922 __FILE__, __LINE__, st); 7923 #endif 7924 abort(); 7925 /* NOTREACHED */ 7926 } 7927 } 7928 7929 /* 7930 * Returns 7931 * 0 - success 7932 * - fmri wasn't found (error printed) 7933 * - entity was deleted (error printed) 7934 * - backend denied access (error printed) 7935 * ENOMEM - out of memory (error printed) 7936 * ECONNABORTED - repository connection broken (error printed) 7937 * EPERM - permission denied (error printed) 7938 * -1 - unknown libscf error (error printed) 7939 */ 7940 static int 7941 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7942 { 7943 scf_error_t serr; 7944 void *ent; 7945 int issvc; 7946 int r; 7947 7948 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7949 const char *dpt_deleted = gettext("Could not refresh %s " 7950 "(dependent \"%s\" of %s) (deleted).\n"); 7951 7952 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7953 switch (serr) { 7954 case SCF_ERROR_NONE: 7955 break; 7956 7957 case SCF_ERROR_NO_MEMORY: 7958 if (name == NULL) 7959 warn(gettext("Could not refresh %s (out of memory).\n"), 7960 fmri); 7961 else 7962 warn(gettext("Could not refresh %s " 7963 "(dependent \"%s\" of %s) (out of memory).\n"), 7964 fmri, name, d_fmri); 7965 return (ENOMEM); 7966 7967 case SCF_ERROR_NOT_FOUND: 7968 if (name == NULL) 7969 warn(deleted, fmri); 7970 else 7971 warn(dpt_deleted, fmri, name, d_fmri); 7972 return (0); 7973 7974 case SCF_ERROR_INVALID_ARGUMENT: 7975 case SCF_ERROR_CONSTRAINT_VIOLATED: 7976 default: 7977 bad_error("fmri_to_entity", serr); 7978 } 7979 7980 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7981 switch (r) { 7982 case 0: 7983 break; 7984 7985 case ECONNABORTED: 7986 if (name != NULL) 7987 warn(gettext("Could not refresh %s " 7988 "(dependent \"%s\" of %s) " 7989 "(repository connection broken).\n"), fmri, name, 7990 d_fmri); 7991 return (r); 7992 7993 case ECANCELED: 7994 if (name == NULL) 7995 warn(deleted, fmri); 7996 else 7997 warn(dpt_deleted, fmri, name, d_fmri); 7998 return (0); 7999 8000 case EACCES: 8001 if (!g_verbose) 8002 return (0); 8003 if (name == NULL) 8004 warn(gettext("Could not refresh %s " 8005 "(backend access denied).\n"), fmri); 8006 else 8007 warn(gettext("Could not refresh %s " 8008 "(dependent \"%s\" of %s) " 8009 "(backend access denied).\n"), fmri, name, d_fmri); 8010 return (0); 8011 8012 case EPERM: 8013 if (name == NULL) 8014 warn(gettext("Could not refresh %s " 8015 "(permission denied).\n"), fmri); 8016 else 8017 warn(gettext("Could not refresh %s " 8018 "(dependent \"%s\" of %s) " 8019 "(permission denied).\n"), fmri, name, d_fmri); 8020 return (r); 8021 8022 case ENOSPC: 8023 if (name == NULL) 8024 warn(gettext("Could not refresh %s " 8025 "(repository server out of resources).\n"), 8026 fmri); 8027 else 8028 warn(gettext("Could not refresh %s " 8029 "(dependent \"%s\" of %s) " 8030 "(repository server out of resources).\n"), 8031 fmri, name, d_fmri); 8032 return (r); 8033 8034 case -1: 8035 scfwarn(); 8036 return (r); 8037 8038 default: 8039 bad_error("refresh_entity", r); 8040 } 8041 8042 if (issvc) 8043 scf_service_destroy(ent); 8044 else 8045 scf_instance_destroy(ent); 8046 8047 return (0); 8048 } 8049 8050 static int 8051 alloc_imp_globals() 8052 { 8053 int r; 8054 8055 const char * const emsg_nomem = gettext("Out of memory.\n"); 8056 const char * const emsg_nores = 8057 gettext("svc.configd is out of resources.\n"); 8058 8059 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 8060 max_scf_name_len : max_scf_fmri_len) + 1; 8061 8062 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 8063 (imp_svc = scf_service_create(g_hndl)) == NULL || 8064 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 8065 (imp_inst = scf_instance_create(g_hndl)) == NULL || 8066 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 8067 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 8068 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 8069 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 8070 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 8071 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8072 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 8073 (imp_pg = scf_pg_create(g_hndl)) == NULL || 8074 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 8075 (imp_prop = scf_property_create(g_hndl)) == NULL || 8076 (imp_iter = scf_iter_create(g_hndl)) == NULL || 8077 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 8078 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 8079 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 8080 (imp_str = malloc(imp_str_sz)) == NULL || 8081 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 8082 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 8083 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 8084 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 8085 (ud_inst = scf_instance_create(g_hndl)) == NULL || 8086 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8087 (ud_pg = scf_pg_create(g_hndl)) == NULL || 8088 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 8089 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 8090 (ud_prop = scf_property_create(g_hndl)) == NULL || 8091 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 8092 (ud_val = scf_value_create(g_hndl)) == NULL || 8093 (ud_iter = scf_iter_create(g_hndl)) == NULL || 8094 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 8095 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 8096 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 8097 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 8098 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 8099 if (scf_error() == SCF_ERROR_NO_RESOURCES) 8100 warn(emsg_nores); 8101 else 8102 warn(emsg_nomem); 8103 8104 return (-1); 8105 } 8106 8107 r = load_init(); 8108 switch (r) { 8109 case 0: 8110 break; 8111 8112 case ENOMEM: 8113 warn(emsg_nomem); 8114 return (-1); 8115 8116 default: 8117 bad_error("load_init", r); 8118 } 8119 8120 return (0); 8121 } 8122 8123 static void 8124 free_imp_globals() 8125 { 8126 pgroup_t *old_dpt; 8127 void *cookie; 8128 8129 load_fini(); 8130 8131 free(ud_ctarg); 8132 free(ud_oldtarg); 8133 free(ud_name); 8134 ud_ctarg = ud_oldtarg = ud_name = NULL; 8135 8136 scf_transaction_destroy(ud_tx); 8137 ud_tx = NULL; 8138 scf_iter_destroy(ud_iter); 8139 scf_iter_destroy(ud_iter2); 8140 ud_iter = ud_iter2 = NULL; 8141 scf_value_destroy(ud_val); 8142 ud_val = NULL; 8143 scf_property_destroy(ud_prop); 8144 scf_property_destroy(ud_dpt_prop); 8145 ud_prop = ud_dpt_prop = NULL; 8146 scf_pg_destroy(ud_pg); 8147 scf_pg_destroy(ud_cur_depts_pg); 8148 scf_pg_destroy(ud_run_dpts_pg); 8149 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 8150 scf_snaplevel_destroy(ud_snpl); 8151 ud_snpl = NULL; 8152 scf_instance_destroy(ud_inst); 8153 ud_inst = NULL; 8154 8155 free(imp_str); 8156 free(imp_tsname); 8157 free(imp_fe1); 8158 free(imp_fe2); 8159 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 8160 8161 cookie = NULL; 8162 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 8163 NULL) { 8164 free((char *)old_dpt->sc_pgroup_name); 8165 free((char *)old_dpt->sc_pgroup_fmri); 8166 internal_pgroup_free(old_dpt); 8167 } 8168 uu_list_destroy(imp_deleted_dpts); 8169 8170 scf_transaction_destroy(imp_tx); 8171 imp_tx = NULL; 8172 scf_iter_destroy(imp_iter); 8173 scf_iter_destroy(imp_rpg_iter); 8174 scf_iter_destroy(imp_up_iter); 8175 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 8176 scf_property_destroy(imp_prop); 8177 imp_prop = NULL; 8178 scf_pg_destroy(imp_pg); 8179 scf_pg_destroy(imp_pg2); 8180 imp_pg = imp_pg2 = NULL; 8181 scf_snaplevel_destroy(imp_snpl); 8182 scf_snaplevel_destroy(imp_rsnpl); 8183 imp_snpl = imp_rsnpl = NULL; 8184 scf_snapshot_destroy(imp_snap); 8185 scf_snapshot_destroy(imp_lisnap); 8186 scf_snapshot_destroy(imp_tlisnap); 8187 scf_snapshot_destroy(imp_rsnap); 8188 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 8189 scf_instance_destroy(imp_inst); 8190 scf_instance_destroy(imp_tinst); 8191 imp_inst = imp_tinst = NULL; 8192 scf_service_destroy(imp_svc); 8193 scf_service_destroy(imp_tsvc); 8194 imp_svc = imp_tsvc = NULL; 8195 scf_scope_destroy(imp_scope); 8196 imp_scope = NULL; 8197 8198 load_fini(); 8199 } 8200 8201 int 8202 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 8203 { 8204 scf_callback_t cbdata; 8205 int result = 0; 8206 entity_t *svc, *inst; 8207 uu_list_t *insts; 8208 int r; 8209 pgroup_t *old_dpt; 8210 int annotation_set = 0; 8211 8212 const char * const emsg_nomem = gettext("Out of memory.\n"); 8213 const char * const emsg_nores = 8214 gettext("svc.configd is out of resources.\n"); 8215 8216 lscf_prep_hndl(); 8217 8218 if (alloc_imp_globals()) 8219 goto out; 8220 8221 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 8222 switch (scf_error()) { 8223 case SCF_ERROR_CONNECTION_BROKEN: 8224 warn(gettext("Repository connection broken.\n")); 8225 repository_teardown(); 8226 result = -1; 8227 goto out; 8228 8229 case SCF_ERROR_NOT_FOUND: 8230 case SCF_ERROR_INVALID_ARGUMENT: 8231 case SCF_ERROR_NOT_BOUND: 8232 case SCF_ERROR_HANDLE_MISMATCH: 8233 default: 8234 bad_error("scf_handle_get_scope", scf_error()); 8235 } 8236 } 8237 8238 /* Set up the auditing annotation. */ 8239 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 8240 annotation_set = 1; 8241 } else { 8242 switch (scf_error()) { 8243 case SCF_ERROR_CONNECTION_BROKEN: 8244 warn(gettext("Repository connection broken.\n")); 8245 repository_teardown(); 8246 result = -1; 8247 goto out; 8248 8249 case SCF_ERROR_INVALID_ARGUMENT: 8250 case SCF_ERROR_NOT_BOUND: 8251 case SCF_ERROR_NO_RESOURCES: 8252 case SCF_ERROR_INTERNAL: 8253 bad_error("_scf_set_annotation", scf_error()); 8254 /* NOTREACHED */ 8255 8256 default: 8257 /* 8258 * Do not terminate import because of inability to 8259 * generate annotation audit event. 8260 */ 8261 warn(gettext("_scf_set_annotation() unexpectedly " 8262 "failed with return code of %d\n"), scf_error()); 8263 break; 8264 } 8265 } 8266 8267 /* 8268 * Clear the sc_import_state's of all services & instances so we can 8269 * report how far we got if we fail. 8270 */ 8271 for (svc = uu_list_first(bndl->sc_bundle_services); 8272 svc != NULL; 8273 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8274 svc->sc_import_state = 0; 8275 8276 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 8277 clear_int, (void *)offsetof(entity_t, sc_import_state), 8278 UU_DEFAULT) != 0) 8279 bad_error("uu_list_walk", uu_error()); 8280 } 8281 8282 cbdata.sc_handle = g_hndl; 8283 cbdata.sc_parent = imp_scope; 8284 cbdata.sc_flags = flags; 8285 cbdata.sc_general = NULL; 8286 8287 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 8288 &cbdata, UU_DEFAULT) == 0) { 8289 char *eptr; 8290 /* Success. Refresh everything. */ 8291 8292 if (flags & SCI_NOREFRESH || no_refresh) { 8293 no_refresh = 0; 8294 result = 0; 8295 goto out; 8296 } 8297 8298 for (svc = uu_list_first(bndl->sc_bundle_services); 8299 svc != NULL; 8300 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8301 pgroup_t *dpt; 8302 8303 insts = svc->sc_u.sc_service.sc_service_instances; 8304 8305 for (inst = uu_list_first(insts); 8306 inst != NULL; 8307 inst = uu_list_next(insts, inst)) { 8308 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 8309 switch (r) { 8310 case 0: 8311 break; 8312 8313 case ENOMEM: 8314 case ECONNABORTED: 8315 case EPERM: 8316 case -1: 8317 goto progress; 8318 8319 default: 8320 bad_error("imp_refresh_fmri", r); 8321 } 8322 8323 inst->sc_import_state = IMPORT_REFRESHED; 8324 8325 for (dpt = uu_list_first(inst->sc_dependents); 8326 dpt != NULL; 8327 dpt = uu_list_next(inst->sc_dependents, 8328 dpt)) 8329 if (imp_refresh_fmri( 8330 dpt->sc_pgroup_fmri, 8331 dpt->sc_pgroup_name, 8332 inst->sc_fmri) != 0) 8333 goto progress; 8334 } 8335 8336 for (dpt = uu_list_first(svc->sc_dependents); 8337 dpt != NULL; 8338 dpt = uu_list_next(svc->sc_dependents, dpt)) 8339 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 8340 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 8341 goto progress; 8342 } 8343 8344 for (old_dpt = uu_list_first(imp_deleted_dpts); 8345 old_dpt != NULL; 8346 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 8347 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8348 old_dpt->sc_pgroup_name, 8349 old_dpt->sc_parent->sc_fmri) != 0) 8350 goto progress; 8351 8352 result = 0; 8353 8354 /* 8355 * This snippet of code assumes that we are running svccfg as we 8356 * normally do -- witih svc.startd running. Of course, that is 8357 * not actually the case all the time because we also use a 8358 * varient of svc.configd and svccfg which are only meant to 8359 * run during the build process. During this time we have no 8360 * svc.startd, so this check would hang the build process. 8361 * 8362 * However, we've also given other consolidations, a bit of a 8363 * means to tie themselves into a knot. They're not properly 8364 * using the native build equivalents, but they've been getting 8365 * away with it anyways. Therefore, if we've found that 8366 * SVCCFG_REPOSITORY is set indicating that a separate configd 8367 * should be spun up, then we have to assume it's not using a 8368 * startd and we should not do this check. 8369 */ 8370 #ifndef NATIVE_BUILD 8371 /* 8372 * Verify that the restarter group is preset 8373 */ 8374 eptr = getenv("SVCCFG_REPOSITORY"); 8375 for (svc = uu_list_first(bndl->sc_bundle_services); 8376 svc != NULL && eptr == NULL; 8377 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8378 8379 insts = svc->sc_u.sc_service.sc_service_instances; 8380 8381 for (inst = uu_list_first(insts); 8382 inst != NULL; 8383 inst = uu_list_next(insts, inst)) { 8384 if (lscf_instance_verify(imp_scope, svc, 8385 inst) != 0) 8386 goto progress; 8387 } 8388 } 8389 #endif 8390 goto out; 8391 8392 } 8393 8394 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8395 bad_error("uu_list_walk", uu_error()); 8396 8397 printerr: 8398 /* If the error hasn't been printed yet, do so here. */ 8399 switch (cbdata.sc_err) { 8400 case ECONNABORTED: 8401 warn(gettext("Repository connection broken.\n")); 8402 break; 8403 8404 case ENOMEM: 8405 warn(emsg_nomem); 8406 break; 8407 8408 case ENOSPC: 8409 warn(emsg_nores); 8410 break; 8411 8412 case EROFS: 8413 warn(gettext("Repository is read-only.\n")); 8414 break; 8415 8416 case EACCES: 8417 warn(gettext("Repository backend denied access.\n")); 8418 break; 8419 8420 case EPERM: 8421 case EINVAL: 8422 case EEXIST: 8423 case EBUSY: 8424 case EBADF: 8425 case -1: 8426 break; 8427 8428 default: 8429 bad_error("lscf_service_import", cbdata.sc_err); 8430 } 8431 8432 progress: 8433 warn(gettext("Import of %s failed. Progress:\n"), filename); 8434 8435 for (svc = uu_list_first(bndl->sc_bundle_services); 8436 svc != NULL; 8437 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8438 insts = svc->sc_u.sc_service.sc_service_instances; 8439 8440 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 8441 import_progress(svc->sc_import_state)); 8442 8443 for (inst = uu_list_first(insts); 8444 inst != NULL; 8445 inst = uu_list_next(insts, inst)) 8446 warn(gettext(" Instance \"%s\": %s\n"), 8447 inst->sc_name, 8448 import_progress(inst->sc_import_state)); 8449 } 8450 8451 if (cbdata.sc_err == ECONNABORTED) 8452 repository_teardown(); 8453 8454 8455 result = -1; 8456 8457 out: 8458 if (annotation_set != 0) { 8459 /* Turn off annotation. It is no longer needed. */ 8460 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8461 } 8462 8463 free_imp_globals(); 8464 8465 return (result); 8466 } 8467 8468 /* 8469 * _lscf_import_err() summarize the error handling returned by 8470 * lscf_import_{instance | service}_pgs 8471 * Return values are: 8472 * IMPORT_NEXT 8473 * IMPORT_OUT 8474 * IMPORT_BAD 8475 */ 8476 8477 #define IMPORT_BAD -1 8478 #define IMPORT_NEXT 0 8479 #define IMPORT_OUT 1 8480 8481 static int 8482 _lscf_import_err(int err, const char *fmri) 8483 { 8484 switch (err) { 8485 case 0: 8486 if (g_verbose) 8487 warn(gettext("%s updated.\n"), fmri); 8488 return (IMPORT_NEXT); 8489 8490 case ECONNABORTED: 8491 warn(gettext("Could not update %s " 8492 "(repository connection broken).\n"), fmri); 8493 return (IMPORT_OUT); 8494 8495 case ENOMEM: 8496 warn(gettext("Could not update %s (out of memory).\n"), fmri); 8497 return (IMPORT_OUT); 8498 8499 case ENOSPC: 8500 warn(gettext("Could not update %s " 8501 "(repository server out of resources).\n"), fmri); 8502 return (IMPORT_OUT); 8503 8504 case ECANCELED: 8505 warn(gettext( 8506 "Could not update %s (deleted).\n"), fmri); 8507 return (IMPORT_NEXT); 8508 8509 case EPERM: 8510 case EINVAL: 8511 case EBUSY: 8512 return (IMPORT_NEXT); 8513 8514 case EROFS: 8515 warn(gettext("Could not update %s (repository read-only).\n"), 8516 fmri); 8517 return (IMPORT_OUT); 8518 8519 case EACCES: 8520 warn(gettext("Could not update %s " 8521 "(backend access denied).\n"), fmri); 8522 return (IMPORT_NEXT); 8523 8524 case EEXIST: 8525 default: 8526 return (IMPORT_BAD); 8527 } 8528 8529 /*NOTREACHED*/ 8530 } 8531 8532 /* 8533 * The global imp_svc and imp_inst should be set by the caller in the 8534 * check to make sure the service and instance exist that the apply is 8535 * working on. 8536 */ 8537 static int 8538 lscf_dependent_apply(void *dpg, void *e) 8539 { 8540 scf_callback_t cb; 8541 pgroup_t *dpt_pgroup = dpg; 8542 pgroup_t *deldpt; 8543 entity_t *ent = e; 8544 int tissvc; 8545 void *sc_ent, *tent; 8546 scf_error_t serr; 8547 int r; 8548 8549 const char * const dependents = "dependents"; 8550 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT); 8551 8552 if (issvc) 8553 sc_ent = imp_svc; 8554 else 8555 sc_ent = imp_inst; 8556 8557 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg, 8558 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 || 8559 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name, 8560 imp_prop) != 0) { 8561 switch (scf_error()) { 8562 case SCF_ERROR_NOT_FOUND: 8563 case SCF_ERROR_DELETED: 8564 break; 8565 8566 case SCF_ERROR_CONNECTION_BROKEN: 8567 case SCF_ERROR_NOT_SET: 8568 case SCF_ERROR_INVALID_ARGUMENT: 8569 case SCF_ERROR_HANDLE_MISMATCH: 8570 case SCF_ERROR_NOT_BOUND: 8571 default: 8572 bad_error("entity_get_pg", scf_error()); 8573 } 8574 } else { 8575 /* 8576 * Found the dependents/<wip dep> so check to 8577 * see if the service is different. If so 8578 * store the service for later refresh, and 8579 * delete the wip dependency from the service 8580 */ 8581 if (scf_property_get_value(imp_prop, ud_val) != 0) { 8582 switch (scf_error()) { 8583 case SCF_ERROR_DELETED: 8584 break; 8585 8586 case SCF_ERROR_CONNECTION_BROKEN: 8587 case SCF_ERROR_NOT_SET: 8588 case SCF_ERROR_INVALID_ARGUMENT: 8589 case SCF_ERROR_HANDLE_MISMATCH: 8590 case SCF_ERROR_NOT_BOUND: 8591 default: 8592 bad_error("scf_property_get_value", 8593 scf_error()); 8594 } 8595 } 8596 8597 if (scf_value_get_as_string(ud_val, ud_oldtarg, 8598 max_scf_value_len + 1) < 0) 8599 bad_error("scf_value_get_as_string", scf_error()); 8600 8601 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 8602 switch (r) { 8603 case 1: 8604 break; 8605 case 0: 8606 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent, 8607 &tissvc)) != SCF_ERROR_NONE) { 8608 if (serr == SCF_ERROR_NOT_FOUND) { 8609 break; 8610 } else { 8611 bad_error("fmri_to_entity", serr); 8612 } 8613 } 8614 8615 if (entity_get_pg(tent, tissvc, 8616 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) { 8617 serr = scf_error(); 8618 if (serr == SCF_ERROR_NOT_FOUND || 8619 serr == SCF_ERROR_DELETED) { 8620 break; 8621 } else { 8622 bad_error("entity_get_pg", scf_error()); 8623 } 8624 } 8625 8626 if (scf_pg_delete(imp_pg) != 0) { 8627 serr = scf_error(); 8628 if (serr == SCF_ERROR_NOT_FOUND || 8629 serr == SCF_ERROR_DELETED) { 8630 break; 8631 } else { 8632 bad_error("scf_pg_delete", scf_error()); 8633 } 8634 } 8635 8636 deldpt = internal_pgroup_new(); 8637 if (deldpt == NULL) 8638 return (ENOMEM); 8639 deldpt->sc_pgroup_name = 8640 strdup(dpt_pgroup->sc_pgroup_name); 8641 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg); 8642 if (deldpt->sc_pgroup_name == NULL || 8643 deldpt->sc_pgroup_fmri == NULL) 8644 return (ENOMEM); 8645 deldpt->sc_parent = (entity_t *)ent; 8646 if (uu_list_insert_after(imp_deleted_dpts, NULL, 8647 deldpt) != 0) 8648 uu_die(gettext("libuutil error: %s\n"), 8649 uu_strerror(uu_error())); 8650 8651 break; 8652 default: 8653 bad_error("fmri_equal", r); 8654 } 8655 } 8656 8657 cb.sc_handle = g_hndl; 8658 cb.sc_parent = ent; 8659 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT; 8660 cb.sc_source_fmri = ent->sc_fmri; 8661 cb.sc_target_fmri = ent->sc_fmri; 8662 cb.sc_trans = NULL; 8663 cb.sc_flags = SCI_FORCE; 8664 8665 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT) 8666 return (UU_WALK_ERROR); 8667 8668 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL); 8669 switch (r) { 8670 case 0: 8671 break; 8672 8673 case ENOMEM: 8674 case ECONNABORTED: 8675 case EPERM: 8676 case -1: 8677 warn(gettext("Unable to refresh \"%s\"\n"), 8678 dpt_pgroup->sc_pgroup_fmri); 8679 return (UU_WALK_ERROR); 8680 8681 default: 8682 bad_error("imp_refresh_fmri", r); 8683 } 8684 8685 return (UU_WALK_NEXT); 8686 } 8687 8688 /* 8689 * Returns 8690 * 0 - success 8691 * -1 - lscf_import_instance_pgs() failed. 8692 */ 8693 int 8694 lscf_bundle_apply(bundle_t *bndl, const char *file) 8695 { 8696 pgroup_t *old_dpt; 8697 entity_t *svc, *inst; 8698 int annotation_set = 0; 8699 int ret = 0; 8700 int r = 0; 8701 8702 lscf_prep_hndl(); 8703 8704 if ((ret = alloc_imp_globals())) 8705 goto out; 8706 8707 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) 8708 scfdie(); 8709 8710 /* 8711 * Set the strings to be used for the security audit annotation 8712 * event. 8713 */ 8714 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 8715 annotation_set = 1; 8716 } else { 8717 switch (scf_error()) { 8718 case SCF_ERROR_CONNECTION_BROKEN: 8719 warn(gettext("Repository connection broken.\n")); 8720 goto out; 8721 8722 case SCF_ERROR_INVALID_ARGUMENT: 8723 case SCF_ERROR_NOT_BOUND: 8724 case SCF_ERROR_NO_RESOURCES: 8725 case SCF_ERROR_INTERNAL: 8726 bad_error("_scf_set_annotation", scf_error()); 8727 /* NOTREACHED */ 8728 8729 default: 8730 /* 8731 * Do not abort apply operation because of 8732 * inability to create annotation audit event. 8733 */ 8734 warn(gettext("_scf_set_annotation() unexpectedly " 8735 "failed with return code of %d\n"), scf_error()); 8736 break; 8737 } 8738 } 8739 8740 for (svc = uu_list_first(bndl->sc_bundle_services); 8741 svc != NULL; 8742 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8743 int refresh = 0; 8744 8745 if (scf_scope_get_service(imp_scope, svc->sc_name, 8746 imp_svc) != 0) { 8747 switch (scf_error()) { 8748 case SCF_ERROR_NOT_FOUND: 8749 if (g_verbose) 8750 warn(gettext("Ignoring nonexistent " 8751 "service %s.\n"), svc->sc_name); 8752 continue; 8753 8754 default: 8755 scfdie(); 8756 } 8757 } 8758 8759 /* 8760 * If there were missing types in the profile, then need to 8761 * attempt to find the types. 8762 */ 8763 if (svc->sc_miss_type) { 8764 if (uu_list_numnodes(svc->sc_pgroups) && 8765 uu_list_walk(svc->sc_pgroups, find_current_pg_type, 8766 svc, UU_DEFAULT) != 0) { 8767 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8768 bad_error("uu_list_walk", uu_error()); 8769 8770 ret = -1; 8771 continue; 8772 } 8773 8774 for (inst = uu_list_first( 8775 svc->sc_u.sc_service.sc_service_instances); 8776 inst != NULL; 8777 inst = uu_list_next( 8778 svc->sc_u.sc_service.sc_service_instances, inst)) { 8779 /* 8780 * If the instance doesn't exist just 8781 * skip to the next instance and let the 8782 * import note the missing instance. 8783 */ 8784 if (scf_service_get_instance(imp_svc, 8785 inst->sc_name, imp_inst) != 0) 8786 continue; 8787 8788 if (uu_list_walk(inst->sc_pgroups, 8789 find_current_pg_type, inst, 8790 UU_DEFAULT) != 0) { 8791 if (uu_error() != 8792 UU_ERROR_CALLBACK_FAILED) 8793 bad_error("uu_list_walk", 8794 uu_error()); 8795 8796 ret = -1; 8797 inst->sc_miss_type = B_TRUE; 8798 } 8799 } 8800 } 8801 8802 /* 8803 * if we have pgs in the profile, we need to refresh ALL 8804 * instances of the service 8805 */ 8806 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 8807 refresh = 1; 8808 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc, 8809 SCI_FORCE | SCI_KEEP); 8810 switch (_lscf_import_err(r, svc->sc_fmri)) { 8811 case IMPORT_NEXT: 8812 break; 8813 8814 case IMPORT_OUT: 8815 goto out; 8816 8817 case IMPORT_BAD: 8818 default: 8819 bad_error("lscf_import_service_pgs", r); 8820 } 8821 } 8822 8823 if (uu_list_numnodes(svc->sc_dependents) != 0) { 8824 uu_list_walk(svc->sc_dependents, 8825 lscf_dependent_apply, svc, UU_DEFAULT); 8826 } 8827 8828 for (inst = uu_list_first( 8829 svc->sc_u.sc_service.sc_service_instances); 8830 inst != NULL; 8831 inst = uu_list_next( 8832 svc->sc_u.sc_service.sc_service_instances, inst)) { 8833 /* 8834 * This instance still has missing types 8835 * so skip it. 8836 */ 8837 if (inst->sc_miss_type) { 8838 if (g_verbose) 8839 warn(gettext("Ignoring instance " 8840 "%s:%s with missing types\n"), 8841 inst->sc_parent->sc_name, 8842 inst->sc_name); 8843 8844 continue; 8845 } 8846 8847 if (scf_service_get_instance(imp_svc, inst->sc_name, 8848 imp_inst) != 0) { 8849 switch (scf_error()) { 8850 case SCF_ERROR_NOT_FOUND: 8851 if (g_verbose) 8852 warn(gettext("Ignoring " 8853 "nonexistant instance " 8854 "%s:%s.\n"), 8855 inst->sc_parent->sc_name, 8856 inst->sc_name); 8857 continue; 8858 8859 default: 8860 scfdie(); 8861 } 8862 } 8863 8864 /* 8865 * If the instance does not have a general/enabled 8866 * property and no last-import snapshot then the 8867 * instance is not a fully installed instance and 8868 * should not have a profile applied to it. 8869 * 8870 * This could happen if a service/instance declares 8871 * a dependent on behalf of another service/instance. 8872 * 8873 */ 8874 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 8875 imp_snap) != 0) { 8876 if (scf_instance_get_pg(imp_inst, 8877 SCF_PG_GENERAL, imp_pg) != 0 || 8878 scf_pg_get_property(imp_pg, 8879 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 8880 if (g_verbose) 8881 warn(gettext("Ignoreing " 8882 "partial instance " 8883 "%s:%s.\n"), 8884 inst->sc_parent->sc_name, 8885 inst->sc_name); 8886 continue; 8887 } 8888 } 8889 8890 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, 8891 inst, SCI_FORCE | SCI_KEEP); 8892 switch (_lscf_import_err(r, inst->sc_fmri)) { 8893 case IMPORT_NEXT: 8894 break; 8895 8896 case IMPORT_OUT: 8897 goto out; 8898 8899 case IMPORT_BAD: 8900 default: 8901 bad_error("lscf_import_instance_pgs", r); 8902 } 8903 8904 if (uu_list_numnodes(inst->sc_dependents) != 0) { 8905 uu_list_walk(inst->sc_dependents, 8906 lscf_dependent_apply, inst, UU_DEFAULT); 8907 } 8908 8909 /* refresh only if there is no pgs in the service */ 8910 if (refresh == 0) 8911 (void) refresh_entity(0, imp_inst, 8912 inst->sc_fmri, NULL, NULL, NULL); 8913 } 8914 8915 if (refresh == 1) { 8916 char *name_buf = safe_malloc(max_scf_name_len + 1); 8917 8918 (void) refresh_entity(1, imp_svc, svc->sc_name, 8919 imp_inst, imp_iter, name_buf); 8920 free(name_buf); 8921 } 8922 8923 for (old_dpt = uu_list_first(imp_deleted_dpts); 8924 old_dpt != NULL; 8925 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) { 8926 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8927 old_dpt->sc_pgroup_name, 8928 old_dpt->sc_parent->sc_fmri) != 0) { 8929 warn(gettext("Unable to refresh \"%s\"\n"), 8930 old_dpt->sc_pgroup_fmri); 8931 } 8932 } 8933 } 8934 8935 out: 8936 if (annotation_set) { 8937 /* Remove security audit annotation strings. */ 8938 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8939 } 8940 8941 free_imp_globals(); 8942 return (ret); 8943 } 8944 8945 8946 /* 8947 * Export. These functions create and output an XML tree of a service 8948 * description from the repository. This is largely the inverse of 8949 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 8950 * 8951 * - We must include any properties which are not represented specifically by 8952 * a service manifest, e.g., properties created by an admin post-import. To 8953 * do so we'll iterate through all properties and deal with each 8954 * apropriately. 8955 * 8956 * - Children of services and instances must must be in the order set by the 8957 * DTD, but we iterate over the properties in undefined order. The elements 8958 * are not easily (or efficiently) sortable by name. Since there's a fixed 8959 * number of classes of them, however, we'll keep the classes separate and 8960 * assemble them in order. 8961 */ 8962 8963 /* 8964 * Convenience function to handle xmlSetProp errors (and type casting). 8965 */ 8966 static void 8967 safe_setprop(xmlNodePtr n, const char *name, const char *val) 8968 { 8969 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 8970 uu_die(gettext("Could not set XML property.\n")); 8971 } 8972 8973 /* 8974 * Convenience function to set an XML attribute to the single value of an 8975 * astring property. If the value happens to be the default, don't set the 8976 * attribute. "dval" should be the default value supplied by the DTD, or 8977 * NULL for no default. 8978 */ 8979 static int 8980 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 8981 const char *name, const char *dval) 8982 { 8983 scf_value_t *val; 8984 ssize_t len; 8985 char *str; 8986 8987 val = scf_value_create(g_hndl); 8988 if (val == NULL) 8989 scfdie(); 8990 8991 if (prop_get_val(prop, val) != 0) { 8992 scf_value_destroy(val); 8993 return (-1); 8994 } 8995 8996 len = scf_value_get_as_string(val, NULL, 0); 8997 if (len < 0) 8998 scfdie(); 8999 9000 str = safe_malloc(len + 1); 9001 9002 if (scf_value_get_as_string(val, str, len + 1) < 0) 9003 scfdie(); 9004 9005 scf_value_destroy(val); 9006 9007 if (dval == NULL || strcmp(str, dval) != 0) 9008 safe_setprop(n, name, str); 9009 9010 free(str); 9011 9012 return (0); 9013 } 9014 9015 /* 9016 * As above, but the attribute is always set. 9017 */ 9018 static int 9019 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 9020 { 9021 return (set_attr_from_prop_default(prop, n, name, NULL)); 9022 } 9023 9024 /* 9025 * Dump the given document onto f, with "'s replaced by ''s. 9026 */ 9027 static int 9028 write_service_bundle(xmlDocPtr doc, FILE *f) 9029 { 9030 xmlChar *mem; 9031 int sz, i; 9032 9033 mem = NULL; 9034 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 9035 9036 if (mem == NULL) { 9037 semerr(gettext("Could not dump XML tree.\n")); 9038 return (-1); 9039 } 9040 9041 /* 9042 * Fortunately libxml produces " instead of ", so we can blindly 9043 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 9044 * ' code?! 9045 */ 9046 for (i = 0; i < sz; ++i) { 9047 char c = (char)mem[i]; 9048 9049 if (c == '"') 9050 (void) fputc('\'', f); 9051 else if (c == '\'') 9052 (void) fwrite("'", sizeof ("'") - 1, 1, f); 9053 else 9054 (void) fputc(c, f); 9055 } 9056 9057 return (0); 9058 } 9059 9060 /* 9061 * Create the DOM elements in elts necessary to (generically) represent prop 9062 * (i.e., a property or propval element). If the name of the property is 9063 * known, it should be passed as name_arg. Otherwise, pass NULL. 9064 */ 9065 static void 9066 export_property(scf_property_t *prop, const char *name_arg, 9067 struct pg_elts *elts, int flags) 9068 { 9069 const char *type; 9070 scf_error_t err = 0; 9071 xmlNodePtr pnode, lnode; 9072 char *lnname; 9073 int ret; 9074 9075 /* name */ 9076 if (name_arg != NULL) { 9077 (void) strcpy(exp_str, name_arg); 9078 } else { 9079 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 9080 scfdie(); 9081 } 9082 9083 /* type */ 9084 type = prop_to_typestr(prop); 9085 if (type == NULL) 9086 uu_die(gettext("Can't export property %s: unknown type.\n"), 9087 exp_str); 9088 9089 /* If we're exporting values, and there's just one, export it here. */ 9090 if (!(flags & SCE_ALL_VALUES)) 9091 goto empty; 9092 9093 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 9094 xmlNodePtr n; 9095 9096 /* Single value, so use propval */ 9097 n = xmlNewNode(NULL, (xmlChar *)"propval"); 9098 if (n == NULL) 9099 uu_die(emsg_create_xml); 9100 9101 safe_setprop(n, name_attr, exp_str); 9102 safe_setprop(n, type_attr, type); 9103 9104 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9105 scfdie(); 9106 safe_setprop(n, value_attr, exp_str); 9107 9108 if (elts->propvals == NULL) 9109 elts->propvals = n; 9110 else 9111 (void) xmlAddSibling(elts->propvals, n); 9112 9113 return; 9114 } 9115 9116 err = scf_error(); 9117 9118 if (err == SCF_ERROR_PERMISSION_DENIED) { 9119 semerr(emsg_permission_denied); 9120 return; 9121 } 9122 9123 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 9124 err != SCF_ERROR_NOT_FOUND && 9125 err != SCF_ERROR_PERMISSION_DENIED) 9126 scfdie(); 9127 9128 empty: 9129 /* Multiple (or no) values, so use property */ 9130 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 9131 if (pnode == NULL) 9132 uu_die(emsg_create_xml); 9133 9134 safe_setprop(pnode, name_attr, exp_str); 9135 safe_setprop(pnode, type_attr, type); 9136 9137 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 9138 lnname = uu_msprintf("%s_list", type); 9139 if (lnname == NULL) 9140 uu_die(gettext("Could not create string")); 9141 9142 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 9143 if (lnode == NULL) 9144 uu_die(emsg_create_xml); 9145 9146 uu_free(lnname); 9147 9148 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 9149 scfdie(); 9150 9151 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 9152 1) { 9153 xmlNodePtr vn; 9154 9155 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 9156 NULL); 9157 if (vn == NULL) 9158 uu_die(emsg_create_xml); 9159 9160 if (scf_value_get_as_string(exp_val, exp_str, 9161 exp_str_sz) < 0) 9162 scfdie(); 9163 safe_setprop(vn, value_attr, exp_str); 9164 } 9165 if (ret != 0) 9166 scfdie(); 9167 } 9168 9169 if (elts->properties == NULL) 9170 elts->properties = pnode; 9171 else 9172 (void) xmlAddSibling(elts->properties, pnode); 9173 } 9174 9175 /* 9176 * Add a property_group element for this property group to elts. 9177 */ 9178 static void 9179 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 9180 { 9181 xmlNodePtr n; 9182 struct pg_elts elts; 9183 int ret; 9184 boolean_t read_protected; 9185 9186 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 9187 9188 /* name */ 9189 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9190 scfdie(); 9191 safe_setprop(n, name_attr, exp_str); 9192 9193 /* type */ 9194 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 9195 scfdie(); 9196 safe_setprop(n, type_attr, exp_str); 9197 9198 /* properties */ 9199 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9200 scfdie(); 9201 9202 (void) memset(&elts, 0, sizeof (elts)); 9203 9204 /* 9205 * If this property group is not read protected, we always want to 9206 * output all the values. Otherwise, we only output the values if the 9207 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 9208 */ 9209 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 9210 scfdie(); 9211 9212 if (!read_protected) 9213 flags |= SCE_ALL_VALUES; 9214 9215 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9216 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9217 scfdie(); 9218 9219 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9220 xmlNodePtr m; 9221 9222 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9223 if (m == NULL) 9224 uu_die(emsg_create_xml); 9225 9226 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9227 elts.stability = m; 9228 continue; 9229 } 9230 9231 xmlFreeNode(m); 9232 } 9233 9234 export_property(exp_prop, NULL, &elts, flags); 9235 } 9236 if (ret == -1) 9237 scfdie(); 9238 9239 (void) xmlAddChild(n, elts.stability); 9240 (void) xmlAddChildList(n, elts.propvals); 9241 (void) xmlAddChildList(n, elts.properties); 9242 9243 if (eelts->property_groups == NULL) 9244 eelts->property_groups = n; 9245 else 9246 (void) xmlAddSibling(eelts->property_groups, n); 9247 } 9248 9249 /* 9250 * Create an XML node representing the dependency described by the given 9251 * property group and put it in eelts. Unless the dependency is not valid, in 9252 * which case create a generic property_group element which represents it and 9253 * put it in eelts. 9254 */ 9255 static void 9256 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 9257 { 9258 xmlNodePtr n; 9259 int err = 0, ret; 9260 struct pg_elts elts; 9261 9262 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 9263 if (n == NULL) 9264 uu_die(emsg_create_xml); 9265 9266 /* 9267 * If the external flag is present, skip this dependency because it 9268 * should have been created by another manifest. 9269 */ 9270 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 9271 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9272 prop_get_val(exp_prop, exp_val) == 0) { 9273 uint8_t b; 9274 9275 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 9276 scfdie(); 9277 9278 if (b) 9279 return; 9280 } 9281 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 9282 scfdie(); 9283 9284 /* Get the required attributes. */ 9285 9286 /* name */ 9287 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9288 scfdie(); 9289 safe_setprop(n, name_attr, exp_str); 9290 9291 /* grouping */ 9292 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9293 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9294 err = 1; 9295 9296 /* restart_on */ 9297 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9298 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9299 err = 1; 9300 9301 /* type */ 9302 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9303 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9304 err = 1; 9305 9306 /* 9307 * entities: Not required, but if we create no children, it will be 9308 * created as empty on import, so fail if it's missing. 9309 */ 9310 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9311 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 9312 scf_iter_t *eiter; 9313 int ret2; 9314 9315 eiter = scf_iter_create(g_hndl); 9316 if (eiter == NULL) 9317 scfdie(); 9318 9319 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 9320 scfdie(); 9321 9322 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 9323 xmlNodePtr ch; 9324 9325 if (scf_value_get_astring(exp_val, exp_str, 9326 exp_str_sz) < 0) 9327 scfdie(); 9328 9329 /* 9330 * service_fmri's must be first, so we can add them 9331 * here. 9332 */ 9333 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 9334 NULL); 9335 if (ch == NULL) 9336 uu_die(emsg_create_xml); 9337 9338 safe_setprop(ch, value_attr, exp_str); 9339 } 9340 if (ret2 == -1) 9341 scfdie(); 9342 9343 scf_iter_destroy(eiter); 9344 } else 9345 err = 1; 9346 9347 if (err) { 9348 xmlFreeNode(n); 9349 9350 export_pg(pg, eelts, SCE_ALL_VALUES); 9351 9352 return; 9353 } 9354 9355 /* Iterate through the properties & handle each. */ 9356 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9357 scfdie(); 9358 9359 (void) memset(&elts, 0, sizeof (elts)); 9360 9361 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9362 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9363 scfdie(); 9364 9365 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9366 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9367 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9368 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9369 continue; 9370 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9371 xmlNodePtr m; 9372 9373 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9374 if (m == NULL) 9375 uu_die(emsg_create_xml); 9376 9377 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9378 elts.stability = m; 9379 continue; 9380 } 9381 9382 xmlFreeNode(m); 9383 } 9384 9385 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9386 } 9387 if (ret == -1) 9388 scfdie(); 9389 9390 (void) xmlAddChild(n, elts.stability); 9391 (void) xmlAddChildList(n, elts.propvals); 9392 (void) xmlAddChildList(n, elts.properties); 9393 9394 if (eelts->dependencies == NULL) 9395 eelts->dependencies = n; 9396 else 9397 (void) xmlAddSibling(eelts->dependencies, n); 9398 } 9399 9400 static xmlNodePtr 9401 export_method_environment(scf_propertygroup_t *pg) 9402 { 9403 xmlNodePtr env; 9404 int ret; 9405 int children = 0; 9406 9407 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 9408 return (NULL); 9409 9410 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 9411 if (env == NULL) 9412 uu_die(emsg_create_xml); 9413 9414 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 9415 scfdie(); 9416 9417 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 9418 scfdie(); 9419 9420 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 9421 xmlNodePtr ev; 9422 char *cp; 9423 9424 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9425 scfdie(); 9426 9427 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 9428 warn(gettext("Invalid environment variable \"%s\".\n"), 9429 exp_str); 9430 continue; 9431 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 9432 warn(gettext("Invalid environment variable \"%s\"; " 9433 "\"SMF_\" prefix is reserved.\n"), exp_str); 9434 continue; 9435 } 9436 9437 *cp = '\0'; 9438 cp++; 9439 9440 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 9441 if (ev == NULL) 9442 uu_die(emsg_create_xml); 9443 9444 safe_setprop(ev, name_attr, exp_str); 9445 safe_setprop(ev, value_attr, cp); 9446 children++; 9447 } 9448 9449 if (ret != 0) 9450 scfdie(); 9451 9452 if (children == 0) { 9453 xmlFreeNode(env); 9454 return (NULL); 9455 } 9456 9457 return (env); 9458 } 9459 9460 /* 9461 * As above, but for a method property group. 9462 */ 9463 static void 9464 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 9465 { 9466 xmlNodePtr n, env; 9467 char *str; 9468 int err = 0, nonenv, ret; 9469 uint8_t use_profile; 9470 struct pg_elts elts; 9471 xmlNodePtr ctxt = NULL; 9472 9473 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 9474 9475 /* Get the required attributes. */ 9476 9477 /* name */ 9478 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9479 scfdie(); 9480 safe_setprop(n, name_attr, exp_str); 9481 9482 /* type */ 9483 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9484 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9485 err = 1; 9486 9487 /* exec */ 9488 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 9489 set_attr_from_prop(exp_prop, n, "exec") != 0) 9490 err = 1; 9491 9492 /* timeout */ 9493 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 9494 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 9495 prop_get_val(exp_prop, exp_val) == 0) { 9496 uint64_t c; 9497 9498 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 9499 scfdie(); 9500 9501 str = uu_msprintf("%llu", c); 9502 if (str == NULL) 9503 uu_die(gettext("Could not create string")); 9504 9505 safe_setprop(n, "timeout_seconds", str); 9506 free(str); 9507 } else 9508 err = 1; 9509 9510 if (err) { 9511 xmlFreeNode(n); 9512 9513 export_pg(pg, eelts, SCE_ALL_VALUES); 9514 9515 return; 9516 } 9517 9518 9519 /* 9520 * If we're going to have a method_context child, we need to know 9521 * before we iterate through the properties. Since method_context's 9522 * are optional, we don't want to complain about any properties 9523 * missing if none of them are there. Thus we can't use the 9524 * convenience functions. 9525 */ 9526 nonenv = 9527 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 9528 SCF_SUCCESS || 9529 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 9530 SCF_SUCCESS || 9531 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 9532 SCF_SUCCESS || 9533 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) == 9534 SCF_SUCCESS || 9535 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 9536 SCF_SUCCESS; 9537 9538 if (nonenv) { 9539 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9540 if (ctxt == NULL) 9541 uu_die(emsg_create_xml); 9542 9543 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 9544 0 && 9545 set_attr_from_prop_default(exp_prop, ctxt, 9546 "working_directory", ":default") != 0) 9547 err = 1; 9548 9549 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 9550 set_attr_from_prop_default(exp_prop, ctxt, "project", 9551 ":default") != 0) 9552 err = 1; 9553 9554 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 9555 0 && 9556 set_attr_from_prop_default(exp_prop, ctxt, 9557 "resource_pool", ":default") != 0) 9558 err = 1; 9559 9560 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 && 9561 set_attr_from_prop_default(exp_prop, ctxt, 9562 "security_flags", ":default") != 0) 9563 err = 1; 9564 9565 /* 9566 * We only want to complain about profile or credential 9567 * properties if we will use them. To determine that we must 9568 * examine USE_PROFILE. 9569 */ 9570 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9571 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9572 prop_get_val(exp_prop, exp_val) == 0) { 9573 if (scf_value_get_boolean(exp_val, &use_profile) != 9574 SCF_SUCCESS) { 9575 scfdie(); 9576 } 9577 9578 if (use_profile) { 9579 xmlNodePtr prof; 9580 9581 prof = xmlNewChild(ctxt, NULL, 9582 (xmlChar *)"method_profile", NULL); 9583 if (prof == NULL) 9584 uu_die(emsg_create_xml); 9585 9586 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 9587 exp_prop) != 0 || 9588 set_attr_from_prop(exp_prop, prof, 9589 name_attr) != 0) 9590 err = 1; 9591 } else { 9592 xmlNodePtr cred; 9593 9594 cred = xmlNewChild(ctxt, NULL, 9595 (xmlChar *)"method_credential", NULL); 9596 if (cred == NULL) 9597 uu_die(emsg_create_xml); 9598 9599 if (pg_get_prop(pg, SCF_PROPERTY_USER, 9600 exp_prop) != 0 || 9601 set_attr_from_prop(exp_prop, cred, 9602 "user") != 0) { 9603 err = 1; 9604 } 9605 9606 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 9607 exp_prop) == 0 && 9608 set_attr_from_prop_default(exp_prop, cred, 9609 "group", ":default") != 0) 9610 err = 1; 9611 9612 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 9613 exp_prop) == 0 && 9614 set_attr_from_prop_default(exp_prop, cred, 9615 "supp_groups", ":default") != 0) 9616 err = 1; 9617 9618 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 9619 exp_prop) == 0 && 9620 set_attr_from_prop_default(exp_prop, cred, 9621 "privileges", ":default") != 0) 9622 err = 1; 9623 9624 if (pg_get_prop(pg, 9625 SCF_PROPERTY_LIMIT_PRIVILEGES, 9626 exp_prop) == 0 && 9627 set_attr_from_prop_default(exp_prop, cred, 9628 "limit_privileges", ":default") != 0) 9629 err = 1; 9630 } 9631 } 9632 } 9633 9634 if ((env = export_method_environment(pg)) != NULL) { 9635 if (ctxt == NULL) { 9636 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9637 if (ctxt == NULL) 9638 uu_die(emsg_create_xml); 9639 } 9640 (void) xmlAddChild(ctxt, env); 9641 } 9642 9643 if (env != NULL || (nonenv && err == 0)) 9644 (void) xmlAddChild(n, ctxt); 9645 else 9646 xmlFreeNode(ctxt); 9647 9648 nonenv = (err == 0); 9649 9650 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9651 scfdie(); 9652 9653 (void) memset(&elts, 0, sizeof (elts)); 9654 9655 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9656 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9657 scfdie(); 9658 9659 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9660 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 9661 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 9662 continue; 9663 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9664 xmlNodePtr m; 9665 9666 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9667 if (m == NULL) 9668 uu_die(emsg_create_xml); 9669 9670 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9671 elts.stability = m; 9672 continue; 9673 } 9674 9675 xmlFreeNode(m); 9676 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 9677 0 || 9678 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 9679 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 9680 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9681 if (nonenv) 9682 continue; 9683 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 9684 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 9685 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 9686 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 9687 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 || 9688 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9689 if (nonenv && !use_profile) 9690 continue; 9691 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9692 if (nonenv && use_profile) 9693 continue; 9694 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 9695 if (env != NULL) 9696 continue; 9697 } 9698 9699 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9700 } 9701 if (ret == -1) 9702 scfdie(); 9703 9704 (void) xmlAddChild(n, elts.stability); 9705 (void) xmlAddChildList(n, elts.propvals); 9706 (void) xmlAddChildList(n, elts.properties); 9707 9708 if (eelts->exec_methods == NULL) 9709 eelts->exec_methods = n; 9710 else 9711 (void) xmlAddSibling(eelts->exec_methods, n); 9712 } 9713 9714 static void 9715 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 9716 struct entity_elts *eelts) 9717 { 9718 xmlNodePtr pgnode; 9719 9720 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 9721 if (pgnode == NULL) 9722 uu_die(emsg_create_xml); 9723 9724 safe_setprop(pgnode, name_attr, name); 9725 safe_setprop(pgnode, type_attr, type); 9726 9727 (void) xmlAddChildList(pgnode, elts->propvals); 9728 (void) xmlAddChildList(pgnode, elts->properties); 9729 9730 if (eelts->property_groups == NULL) 9731 eelts->property_groups = pgnode; 9732 else 9733 (void) xmlAddSibling(eelts->property_groups, pgnode); 9734 } 9735 9736 /* 9737 * Process the general property group for a service. This is the one with the 9738 * goodies. 9739 */ 9740 static void 9741 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 9742 { 9743 struct pg_elts elts; 9744 int ret; 9745 9746 /* 9747 * In case there are properties which don't correspond to child 9748 * entities of the service entity, we'll set up a pg_elts structure to 9749 * put them in. 9750 */ 9751 (void) memset(&elts, 0, sizeof (elts)); 9752 9753 /* Walk the properties, looking for special ones. */ 9754 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9755 scfdie(); 9756 9757 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9758 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9759 scfdie(); 9760 9761 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 9762 /* 9763 * Unimplemented and obsolete, but we still process it 9764 * for compatibility purposes. 9765 */ 9766 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9767 prop_get_val(exp_prop, exp_val) == 0) { 9768 uint8_t b; 9769 9770 if (scf_value_get_boolean(exp_val, &b) != 9771 SCF_SUCCESS) 9772 scfdie(); 9773 9774 if (b) { 9775 selts->single_instance = 9776 xmlNewNode(NULL, 9777 (xmlChar *)"single_instance"); 9778 if (selts->single_instance == NULL) 9779 uu_die(emsg_create_xml); 9780 } 9781 9782 continue; 9783 } 9784 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9785 xmlNodePtr rnode, sfnode; 9786 9787 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9788 if (rnode == NULL) 9789 uu_die(emsg_create_xml); 9790 9791 sfnode = xmlNewChild(rnode, NULL, 9792 (xmlChar *)"service_fmri", NULL); 9793 if (sfnode == NULL) 9794 uu_die(emsg_create_xml); 9795 9796 if (set_attr_from_prop(exp_prop, sfnode, 9797 value_attr) == 0) { 9798 selts->restarter = rnode; 9799 continue; 9800 } 9801 9802 xmlFreeNode(rnode); 9803 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 9804 0) { 9805 xmlNodePtr s; 9806 9807 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9808 if (s == NULL) 9809 uu_die(emsg_create_xml); 9810 9811 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9812 selts->stability = s; 9813 continue; 9814 } 9815 9816 xmlFreeNode(s); 9817 } 9818 9819 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9820 } 9821 if (ret == -1) 9822 scfdie(); 9823 9824 if (elts.propvals != NULL || elts.properties != NULL) 9825 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 9826 selts); 9827 } 9828 9829 static void 9830 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 9831 { 9832 xmlNodePtr n, prof, cred, env; 9833 uint8_t use_profile; 9834 int ret, err = 0; 9835 9836 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 9837 9838 env = export_method_environment(pg); 9839 9840 /* Need to know whether we'll use a profile or not. */ 9841 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9842 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9843 prop_get_val(exp_prop, exp_val) == 0) { 9844 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 9845 scfdie(); 9846 9847 if (use_profile) 9848 prof = 9849 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 9850 NULL); 9851 else 9852 cred = 9853 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 9854 NULL); 9855 } 9856 9857 if (env != NULL) 9858 (void) xmlAddChild(n, env); 9859 9860 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9861 scfdie(); 9862 9863 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9864 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9865 scfdie(); 9866 9867 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 9868 if (set_attr_from_prop(exp_prop, n, 9869 "working_directory") != 0) 9870 err = 1; 9871 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 9872 if (set_attr_from_prop(exp_prop, n, "project") != 0) 9873 err = 1; 9874 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 9875 if (set_attr_from_prop(exp_prop, n, 9876 "resource_pool") != 0) 9877 err = 1; 9878 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9879 if (set_attr_from_prop(exp_prop, n, 9880 "security_flags") != 0) 9881 err = 1; 9882 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9883 /* EMPTY */ 9884 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 9885 if (use_profile || 9886 set_attr_from_prop(exp_prop, cred, "user") != 0) 9887 err = 1; 9888 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 9889 if (use_profile || 9890 set_attr_from_prop(exp_prop, cred, "group") != 0) 9891 err = 1; 9892 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 9893 if (use_profile || set_attr_from_prop(exp_prop, cred, 9894 "supp_groups") != 0) 9895 err = 1; 9896 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 9897 if (use_profile || set_attr_from_prop(exp_prop, cred, 9898 "privileges") != 0) 9899 err = 1; 9900 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 9901 0) { 9902 if (use_profile || set_attr_from_prop(exp_prop, cred, 9903 "limit_privileges") != 0) 9904 err = 1; 9905 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9906 if (!use_profile || set_attr_from_prop(exp_prop, 9907 prof, name_attr) != 0) 9908 err = 1; 9909 } else { 9910 /* Can't have generic properties in method_context's */ 9911 err = 1; 9912 } 9913 } 9914 if (ret == -1) 9915 scfdie(); 9916 9917 if (err && env == NULL) { 9918 xmlFreeNode(n); 9919 export_pg(pg, elts, SCE_ALL_VALUES); 9920 return; 9921 } 9922 9923 elts->method_context = n; 9924 } 9925 9926 /* 9927 * Given a dependency property group in the tfmri entity (target fmri), return 9928 * a dependent element which represents it. 9929 */ 9930 static xmlNodePtr 9931 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 9932 { 9933 uint8_t b; 9934 xmlNodePtr n, sf; 9935 int err = 0, ret; 9936 struct pg_elts pgelts; 9937 9938 /* 9939 * If external isn't set to true then exporting the service will 9940 * export this as a normal dependency, so we should stop to avoid 9941 * duplication. 9942 */ 9943 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 9944 scf_property_get_value(exp_prop, exp_val) != 0 || 9945 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 9946 if (g_verbose) { 9947 warn(gettext("Dependent \"%s\" cannot be exported " 9948 "properly because the \"%s\" property of the " 9949 "\"%s\" dependency of %s is not set to true.\n"), 9950 name, scf_property_external, name, tfmri); 9951 } 9952 9953 return (NULL); 9954 } 9955 9956 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 9957 if (n == NULL) 9958 uu_die(emsg_create_xml); 9959 9960 safe_setprop(n, name_attr, name); 9961 9962 /* Get the required attributes */ 9963 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9964 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9965 err = 1; 9966 9967 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9968 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9969 err = 1; 9970 9971 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9972 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 9973 prop_get_val(exp_prop, exp_val) == 0) { 9974 /* EMPTY */ 9975 } else 9976 err = 1; 9977 9978 if (err) { 9979 xmlFreeNode(n); 9980 return (NULL); 9981 } 9982 9983 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 9984 if (sf == NULL) 9985 uu_die(emsg_create_xml); 9986 9987 safe_setprop(sf, value_attr, tfmri); 9988 9989 /* 9990 * Now add elements for the other properties. 9991 */ 9992 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9993 scfdie(); 9994 9995 (void) memset(&pgelts, 0, sizeof (pgelts)); 9996 9997 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9998 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9999 scfdie(); 10000 10001 if (strcmp(exp_str, scf_property_external) == 0 || 10002 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 10003 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 10004 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 10005 continue; 10006 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 10007 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 10008 prop_get_val(exp_prop, exp_val) == 0) { 10009 char type[sizeof ("service") + 1]; 10010 10011 if (scf_value_get_astring(exp_val, type, 10012 sizeof (type)) < 0) 10013 scfdie(); 10014 10015 if (strcmp(type, "service") == 0) 10016 continue; 10017 } 10018 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 10019 xmlNodePtr s; 10020 10021 s = xmlNewNode(NULL, (xmlChar *)"stability"); 10022 if (s == NULL) 10023 uu_die(emsg_create_xml); 10024 10025 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 10026 pgelts.stability = s; 10027 continue; 10028 } 10029 10030 xmlFreeNode(s); 10031 } 10032 10033 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10034 } 10035 if (ret == -1) 10036 scfdie(); 10037 10038 (void) xmlAddChild(n, pgelts.stability); 10039 (void) xmlAddChildList(n, pgelts.propvals); 10040 (void) xmlAddChildList(n, pgelts.properties); 10041 10042 return (n); 10043 } 10044 10045 static void 10046 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 10047 { 10048 scf_propertygroup_t *opg; 10049 scf_iter_t *iter; 10050 char *type, *fmri; 10051 int ret; 10052 struct pg_elts pgelts; 10053 xmlNodePtr n; 10054 scf_error_t serr; 10055 10056 if ((opg = scf_pg_create(g_hndl)) == NULL || 10057 (iter = scf_iter_create(g_hndl)) == NULL) 10058 scfdie(); 10059 10060 /* Can't use exp_prop_iter due to export_dependent(). */ 10061 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10062 scfdie(); 10063 10064 type = safe_malloc(max_scf_pg_type_len + 1); 10065 10066 /* Get an extra byte so we can tell if values are too long. */ 10067 fmri = safe_malloc(max_scf_fmri_len + 2); 10068 10069 (void) memset(&pgelts, 0, sizeof (pgelts)); 10070 10071 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 10072 void *entity; 10073 int isservice; 10074 scf_type_t ty; 10075 10076 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 10077 scfdie(); 10078 10079 if ((ty != SCF_TYPE_ASTRING && 10080 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 10081 prop_get_val(exp_prop, exp_val) != 0) { 10082 export_property(exp_prop, NULL, &pgelts, 10083 SCE_ALL_VALUES); 10084 continue; 10085 } 10086 10087 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10088 scfdie(); 10089 10090 if (scf_value_get_astring(exp_val, fmri, 10091 max_scf_fmri_len + 2) < 0) 10092 scfdie(); 10093 10094 /* Look for a dependency group in the target fmri. */ 10095 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10096 switch (serr) { 10097 case SCF_ERROR_NONE: 10098 break; 10099 10100 case SCF_ERROR_NO_MEMORY: 10101 uu_die(gettext("Out of memory.\n")); 10102 /* NOTREACHED */ 10103 10104 case SCF_ERROR_INVALID_ARGUMENT: 10105 if (g_verbose) { 10106 if (scf_property_to_fmri(exp_prop, fmri, 10107 max_scf_fmri_len + 2) < 0) 10108 scfdie(); 10109 10110 warn(gettext("The value of %s is not a valid " 10111 "FMRI.\n"), fmri); 10112 } 10113 10114 export_property(exp_prop, exp_str, &pgelts, 10115 SCE_ALL_VALUES); 10116 continue; 10117 10118 case SCF_ERROR_CONSTRAINT_VIOLATED: 10119 if (g_verbose) { 10120 if (scf_property_to_fmri(exp_prop, fmri, 10121 max_scf_fmri_len + 2) < 0) 10122 scfdie(); 10123 10124 warn(gettext("The value of %s does not specify " 10125 "a service or an instance.\n"), fmri); 10126 } 10127 10128 export_property(exp_prop, exp_str, &pgelts, 10129 SCE_ALL_VALUES); 10130 continue; 10131 10132 case SCF_ERROR_NOT_FOUND: 10133 if (g_verbose) { 10134 if (scf_property_to_fmri(exp_prop, fmri, 10135 max_scf_fmri_len + 2) < 0) 10136 scfdie(); 10137 10138 warn(gettext("The entity specified by %s does " 10139 "not exist.\n"), fmri); 10140 } 10141 10142 export_property(exp_prop, exp_str, &pgelts, 10143 SCE_ALL_VALUES); 10144 continue; 10145 10146 default: 10147 #ifndef NDEBUG 10148 (void) fprintf(stderr, "%s:%d: %s() failed with " 10149 "unexpected error %d.\n", __FILE__, __LINE__, 10150 "fmri_to_entity", serr); 10151 #endif 10152 abort(); 10153 } 10154 10155 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 10156 if (scf_error() != SCF_ERROR_NOT_FOUND) 10157 scfdie(); 10158 10159 warn(gettext("Entity %s is missing dependency property " 10160 "group %s.\n"), fmri, exp_str); 10161 10162 export_property(exp_prop, NULL, &pgelts, 10163 SCE_ALL_VALUES); 10164 continue; 10165 } 10166 10167 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 10168 scfdie(); 10169 10170 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 10171 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 10172 scfdie(); 10173 10174 warn(gettext("Property group %s is not of " 10175 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 10176 10177 export_property(exp_prop, NULL, &pgelts, 10178 SCE_ALL_VALUES); 10179 continue; 10180 } 10181 10182 n = export_dependent(opg, exp_str, fmri); 10183 if (n == NULL) { 10184 export_property(exp_prop, exp_str, &pgelts, 10185 SCE_ALL_VALUES); 10186 } else { 10187 if (eelts->dependents == NULL) 10188 eelts->dependents = n; 10189 else 10190 (void) xmlAddSibling(eelts->dependents, 10191 n); 10192 } 10193 } 10194 if (ret == -1) 10195 scfdie(); 10196 10197 free(fmri); 10198 free(type); 10199 10200 scf_iter_destroy(iter); 10201 scf_pg_destroy(opg); 10202 10203 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10204 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 10205 eelts); 10206 } 10207 10208 static void 10209 make_node(xmlNodePtr *nodep, const char *name) 10210 { 10211 if (*nodep == NULL) { 10212 *nodep = xmlNewNode(NULL, (xmlChar *)name); 10213 if (*nodep == NULL) 10214 uu_die(emsg_create_xml); 10215 } 10216 } 10217 10218 static xmlNodePtr 10219 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 10220 { 10221 int ret; 10222 xmlNodePtr parent = NULL; 10223 xmlNodePtr loctext = NULL; 10224 10225 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10226 scfdie(); 10227 10228 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10229 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 10230 prop_get_val(exp_prop, exp_val) != 0) 10231 continue; 10232 10233 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 10234 scfdie(); 10235 10236 make_node(&parent, parname); 10237 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 10238 (xmlChar *)exp_str); 10239 if (loctext == NULL) 10240 uu_die(emsg_create_xml); 10241 10242 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10243 scfdie(); 10244 10245 safe_setprop(loctext, "xml:lang", exp_str); 10246 } 10247 10248 if (ret == -1) 10249 scfdie(); 10250 10251 return (parent); 10252 } 10253 10254 static xmlNodePtr 10255 export_tm_manpage(scf_propertygroup_t *pg) 10256 { 10257 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 10258 if (manpage == NULL) 10259 uu_die(emsg_create_xml); 10260 10261 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 10262 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 10263 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 10264 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 10265 xmlFreeNode(manpage); 10266 return (NULL); 10267 } 10268 10269 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 10270 (void) set_attr_from_prop_default(exp_prop, 10271 manpage, "manpath", ":default"); 10272 10273 return (manpage); 10274 } 10275 10276 static xmlNodePtr 10277 export_tm_doc_link(scf_propertygroup_t *pg) 10278 { 10279 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 10280 if (doc_link == NULL) 10281 uu_die(emsg_create_xml); 10282 10283 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 10284 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 10285 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 10286 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 10287 xmlFreeNode(doc_link); 10288 return (NULL); 10289 } 10290 return (doc_link); 10291 } 10292 10293 /* 10294 * Process template information for a service or instances. 10295 */ 10296 static void 10297 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 10298 struct template_elts *telts) 10299 { 10300 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 10301 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 10302 xmlNodePtr child = NULL; 10303 10304 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 10305 scfdie(); 10306 10307 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 10308 telts->common_name = export_tm_loctext(pg, "common_name"); 10309 if (telts->common_name == NULL) 10310 export_pg(pg, elts, SCE_ALL_VALUES); 10311 return; 10312 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 10313 telts->description = export_tm_loctext(pg, "description"); 10314 if (telts->description == NULL) 10315 export_pg(pg, elts, SCE_ALL_VALUES); 10316 return; 10317 } 10318 10319 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 10320 child = export_tm_manpage(pg); 10321 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 10322 child = export_tm_doc_link(pg); 10323 } 10324 10325 if (child != NULL) { 10326 make_node(&telts->documentation, "documentation"); 10327 (void) xmlAddChild(telts->documentation, child); 10328 } else { 10329 export_pg(pg, elts, SCE_ALL_VALUES); 10330 } 10331 } 10332 10333 /* 10334 * Process parameter and paramval elements 10335 */ 10336 static void 10337 export_parameter(scf_property_t *prop, const char *name, 10338 struct params_elts *elts) 10339 { 10340 xmlNodePtr param; 10341 scf_error_t err = 0; 10342 int ret; 10343 10344 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 10345 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL) 10346 uu_die(emsg_create_xml); 10347 10348 safe_setprop(param, name_attr, name); 10349 10350 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 10351 scfdie(); 10352 safe_setprop(param, value_attr, exp_str); 10353 10354 if (elts->paramval == NULL) 10355 elts->paramval = param; 10356 else 10357 (void) xmlAddSibling(elts->paramval, param); 10358 10359 return; 10360 } 10361 10362 err = scf_error(); 10363 10364 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 10365 err != SCF_ERROR_NOT_FOUND) 10366 scfdie(); 10367 10368 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL) 10369 uu_die(emsg_create_xml); 10370 10371 safe_setprop(param, name_attr, name); 10372 10373 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 10374 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 10375 scfdie(); 10376 10377 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 10378 1) { 10379 xmlNodePtr vn; 10380 10381 if ((vn = xmlNewChild(param, NULL, 10382 (xmlChar *)"value_node", NULL)) == NULL) 10383 uu_die(emsg_create_xml); 10384 10385 if (scf_value_get_as_string(exp_val, exp_str, 10386 exp_str_sz) < 0) 10387 scfdie(); 10388 10389 safe_setprop(vn, value_attr, exp_str); 10390 } 10391 if (ret != 0) 10392 scfdie(); 10393 } 10394 10395 if (elts->parameter == NULL) 10396 elts->parameter = param; 10397 else 10398 (void) xmlAddSibling(elts->parameter, param); 10399 } 10400 10401 /* 10402 * Process notification parameters for a service or instance 10403 */ 10404 static void 10405 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts) 10406 { 10407 xmlNodePtr n, event, *type; 10408 struct params_elts *eelts; 10409 int ret, err, i; 10410 char *s; 10411 10412 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters"); 10413 event = xmlNewNode(NULL, (xmlChar *)"event"); 10414 if (n == NULL || event == NULL) 10415 uu_die(emsg_create_xml); 10416 10417 /* event value */ 10418 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 10419 scfdie(); 10420 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */ 10421 if ((s = strchr(exp_str, ',')) != NULL) 10422 *s = '\0'; 10423 safe_setprop(event, value_attr, exp_str); 10424 10425 (void) xmlAddChild(n, event); 10426 10427 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL || 10428 (eelts = calloc(URI_SCHEME_NUM, 10429 sizeof (struct params_elts))) == NULL) 10430 uu_die(gettext("Out of memory.\n")); 10431 10432 err = 0; 10433 10434 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10435 scfdie(); 10436 10437 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10438 char *t, *p; 10439 10440 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10441 scfdie(); 10442 10443 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) { 10444 /* 10445 * this is not a well formed notification parameters 10446 * element, we should export as regular pg 10447 */ 10448 err = 1; 10449 break; 10450 } 10451 10452 if ((i = check_uri_protocol(t)) < 0) { 10453 err = 1; 10454 break; 10455 } 10456 10457 if (type[i] == NULL) { 10458 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) == 10459 NULL) 10460 uu_die(emsg_create_xml); 10461 10462 safe_setprop(type[i], name_attr, t); 10463 } 10464 if (strcmp(p, active_attr) == 0) { 10465 if (set_attr_from_prop(exp_prop, type[i], 10466 active_attr) != 0) { 10467 err = 1; 10468 break; 10469 } 10470 continue; 10471 } 10472 /* 10473 * We export the parameter 10474 */ 10475 export_parameter(exp_prop, p, &eelts[i]); 10476 } 10477 10478 if (ret == -1) 10479 scfdie(); 10480 10481 if (err == 1) { 10482 for (i = 0; i < URI_SCHEME_NUM; ++i) 10483 xmlFree(type[i]); 10484 free(type); 10485 10486 export_pg(pg, elts, SCE_ALL_VALUES); 10487 10488 return; 10489 } else { 10490 for (i = 0; i < URI_SCHEME_NUM; ++i) 10491 if (type[i] != NULL) { 10492 (void) xmlAddChildList(type[i], 10493 eelts[i].paramval); 10494 (void) xmlAddChildList(type[i], 10495 eelts[i].parameter); 10496 (void) xmlAddSibling(event, type[i]); 10497 } 10498 } 10499 free(type); 10500 10501 if (elts->notify_params == NULL) 10502 elts->notify_params = n; 10503 else 10504 (void) xmlAddSibling(elts->notify_params, n); 10505 } 10506 10507 /* 10508 * Process the general property group for an instance. 10509 */ 10510 static void 10511 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 10512 struct entity_elts *elts) 10513 { 10514 uint8_t enabled; 10515 struct pg_elts pgelts; 10516 int ret; 10517 10518 /* enabled */ 10519 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10520 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10521 prop_get_val(exp_prop, exp_val) == 0) { 10522 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10523 scfdie(); 10524 } else { 10525 enabled = 0; 10526 } 10527 10528 safe_setprop(inode, enabled_attr, enabled ? true : false); 10529 10530 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10531 scfdie(); 10532 10533 (void) memset(&pgelts, 0, sizeof (pgelts)); 10534 10535 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10536 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10537 scfdie(); 10538 10539 if (strcmp(exp_str, scf_property_enabled) == 0) { 10540 continue; 10541 } else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) { 10542 continue; 10543 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10544 xmlNodePtr rnode, sfnode; 10545 10546 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10547 if (rnode == NULL) 10548 uu_die(emsg_create_xml); 10549 10550 sfnode = xmlNewChild(rnode, NULL, 10551 (xmlChar *)"service_fmri", NULL); 10552 if (sfnode == NULL) 10553 uu_die(emsg_create_xml); 10554 10555 if (set_attr_from_prop(exp_prop, sfnode, 10556 value_attr) == 0) { 10557 elts->restarter = rnode; 10558 continue; 10559 } 10560 10561 xmlFreeNode(rnode); 10562 } 10563 10564 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10565 } 10566 if (ret == -1) 10567 scfdie(); 10568 10569 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10570 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10571 elts); 10572 } 10573 10574 /* 10575 * Put an instance element for the given instance into selts. 10576 */ 10577 static void 10578 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10579 { 10580 xmlNodePtr n; 10581 boolean_t isdefault; 10582 struct entity_elts elts; 10583 struct template_elts template_elts; 10584 int ret; 10585 10586 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10587 if (n == NULL) 10588 uu_die(emsg_create_xml); 10589 10590 /* name */ 10591 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10592 scfdie(); 10593 safe_setprop(n, name_attr, exp_str); 10594 isdefault = strcmp(exp_str, "default") == 0; 10595 10596 /* check existance of general pg (since general/enabled is required) */ 10597 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10598 if (scf_error() != SCF_ERROR_NOT_FOUND) 10599 scfdie(); 10600 10601 if (g_verbose) { 10602 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10603 scfdie(); 10604 10605 warn(gettext("Instance %s has no general property " 10606 "group; it will be marked disabled.\n"), exp_str); 10607 } 10608 10609 safe_setprop(n, enabled_attr, false); 10610 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10611 strcmp(exp_str, scf_group_framework) != 0) { 10612 if (g_verbose) { 10613 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10614 scfdie(); 10615 10616 warn(gettext("Property group %s is not of type " 10617 "framework; the instance will be marked " 10618 "disabled.\n"), exp_str); 10619 } 10620 10621 safe_setprop(n, enabled_attr, false); 10622 } 10623 10624 /* property groups */ 10625 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10626 scfdie(); 10627 10628 (void) memset(&elts, 0, sizeof (elts)); 10629 (void) memset(&template_elts, 0, sizeof (template_elts)); 10630 10631 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10632 uint32_t pgflags; 10633 10634 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10635 scfdie(); 10636 10637 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10638 continue; 10639 10640 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10641 scfdie(); 10642 10643 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10644 export_dependency(exp_pg, &elts); 10645 continue; 10646 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10647 export_method(exp_pg, &elts); 10648 continue; 10649 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10650 if (scf_pg_get_name(exp_pg, exp_str, 10651 max_scf_name_len + 1) < 0) 10652 scfdie(); 10653 10654 if (strcmp(exp_str, scf_pg_general) == 0) { 10655 export_inst_general(exp_pg, n, &elts); 10656 continue; 10657 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10658 0) { 10659 export_method_context(exp_pg, &elts); 10660 continue; 10661 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10662 export_dependents(exp_pg, &elts); 10663 continue; 10664 } 10665 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10666 export_template(exp_pg, &elts, &template_elts); 10667 continue; 10668 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10669 export_notify_params(exp_pg, &elts); 10670 continue; 10671 } 10672 10673 /* Ordinary pg. */ 10674 export_pg(exp_pg, &elts, flags); 10675 } 10676 if (ret == -1) 10677 scfdie(); 10678 10679 if (template_elts.common_name != NULL) { 10680 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10681 (void) xmlAddChild(elts.template, template_elts.common_name); 10682 (void) xmlAddChild(elts.template, template_elts.description); 10683 (void) xmlAddChild(elts.template, template_elts.documentation); 10684 } else { 10685 xmlFreeNode(template_elts.description); 10686 xmlFreeNode(template_elts.documentation); 10687 } 10688 10689 if (isdefault && elts.restarter == NULL && 10690 elts.dependencies == NULL && elts.method_context == NULL && 10691 elts.exec_methods == NULL && elts.notify_params == NULL && 10692 elts.property_groups == NULL && elts.template == NULL) { 10693 xmlChar *eval; 10694 10695 /* This is a default instance */ 10696 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10697 10698 xmlFreeNode(n); 10699 10700 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10701 if (n == NULL) 10702 uu_die(emsg_create_xml); 10703 10704 safe_setprop(n, enabled_attr, (char *)eval); 10705 xmlFree(eval); 10706 10707 selts->create_default_instance = n; 10708 } else { 10709 /* Assemble the children in order. */ 10710 (void) xmlAddChild(n, elts.restarter); 10711 (void) xmlAddChildList(n, elts.dependencies); 10712 (void) xmlAddChildList(n, elts.dependents); 10713 (void) xmlAddChild(n, elts.method_context); 10714 (void) xmlAddChildList(n, elts.exec_methods); 10715 (void) xmlAddChildList(n, elts.notify_params); 10716 (void) xmlAddChildList(n, elts.property_groups); 10717 (void) xmlAddChild(n, elts.template); 10718 10719 if (selts->instances == NULL) 10720 selts->instances = n; 10721 else 10722 (void) xmlAddSibling(selts->instances, n); 10723 } 10724 } 10725 10726 /* 10727 * Return a service element for the given service. 10728 */ 10729 static xmlNodePtr 10730 export_service(scf_service_t *svc, int flags) 10731 { 10732 xmlNodePtr snode; 10733 struct entity_elts elts; 10734 struct template_elts template_elts; 10735 int ret; 10736 10737 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10738 if (snode == NULL) 10739 uu_die(emsg_create_xml); 10740 10741 /* Get & set name attribute */ 10742 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10743 scfdie(); 10744 safe_setprop(snode, name_attr, exp_str); 10745 10746 safe_setprop(snode, type_attr, "service"); 10747 safe_setprop(snode, "version", "0"); 10748 10749 /* Acquire child elements. */ 10750 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10751 scfdie(); 10752 10753 (void) memset(&elts, 0, sizeof (elts)); 10754 (void) memset(&template_elts, 0, sizeof (template_elts)); 10755 10756 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10757 uint32_t pgflags; 10758 10759 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10760 scfdie(); 10761 10762 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10763 continue; 10764 10765 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10766 scfdie(); 10767 10768 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10769 export_dependency(exp_pg, &elts); 10770 continue; 10771 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10772 export_method(exp_pg, &elts); 10773 continue; 10774 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10775 if (scf_pg_get_name(exp_pg, exp_str, 10776 max_scf_name_len + 1) < 0) 10777 scfdie(); 10778 10779 if (strcmp(exp_str, scf_pg_general) == 0) { 10780 export_svc_general(exp_pg, &elts); 10781 continue; 10782 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10783 0) { 10784 export_method_context(exp_pg, &elts); 10785 continue; 10786 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10787 export_dependents(exp_pg, &elts); 10788 continue; 10789 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10790 continue; 10791 } 10792 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10793 export_template(exp_pg, &elts, &template_elts); 10794 continue; 10795 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10796 export_notify_params(exp_pg, &elts); 10797 continue; 10798 } 10799 10800 export_pg(exp_pg, &elts, flags); 10801 } 10802 if (ret == -1) 10803 scfdie(); 10804 10805 if (template_elts.common_name != NULL) { 10806 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10807 (void) xmlAddChild(elts.template, template_elts.common_name); 10808 (void) xmlAddChild(elts.template, template_elts.description); 10809 (void) xmlAddChild(elts.template, template_elts.documentation); 10810 } else { 10811 xmlFreeNode(template_elts.description); 10812 xmlFreeNode(template_elts.documentation); 10813 } 10814 10815 /* Iterate instances */ 10816 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10817 scfdie(); 10818 10819 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10820 export_instance(exp_inst, &elts, flags); 10821 if (ret == -1) 10822 scfdie(); 10823 10824 /* Now add all of the accumulated elements in order. */ 10825 (void) xmlAddChild(snode, elts.create_default_instance); 10826 (void) xmlAddChild(snode, elts.single_instance); 10827 (void) xmlAddChild(snode, elts.restarter); 10828 (void) xmlAddChildList(snode, elts.dependencies); 10829 (void) xmlAddChildList(snode, elts.dependents); 10830 (void) xmlAddChild(snode, elts.method_context); 10831 (void) xmlAddChildList(snode, elts.exec_methods); 10832 (void) xmlAddChildList(snode, elts.notify_params); 10833 (void) xmlAddChildList(snode, elts.property_groups); 10834 (void) xmlAddChildList(snode, elts.instances); 10835 (void) xmlAddChild(snode, elts.stability); 10836 (void) xmlAddChild(snode, elts.template); 10837 10838 return (snode); 10839 } 10840 10841 static int 10842 export_callback(void *data, scf_walkinfo_t *wip) 10843 { 10844 FILE *f; 10845 xmlDocPtr doc; 10846 xmlNodePtr sb; 10847 int result; 10848 struct export_args *argsp = (struct export_args *)data; 10849 10850 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10851 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10852 (exp_prop = scf_property_create(g_hndl)) == NULL || 10853 (exp_val = scf_value_create(g_hndl)) == NULL || 10854 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10855 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10856 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10857 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10858 scfdie(); 10859 10860 exp_str_sz = max_scf_len + 1; 10861 exp_str = safe_malloc(exp_str_sz); 10862 10863 if (argsp->filename != NULL) { 10864 errno = 0; 10865 f = fopen(argsp->filename, "wb"); 10866 if (f == NULL) { 10867 if (errno == 0) 10868 uu_die(gettext("Could not open \"%s\": no free " 10869 "stdio streams.\n"), argsp->filename); 10870 else 10871 uu_die(gettext("Could not open \"%s\""), 10872 argsp->filename); 10873 } 10874 } else 10875 f = stdout; 10876 10877 doc = xmlNewDoc((xmlChar *)"1.0"); 10878 if (doc == NULL) 10879 uu_die(gettext("Could not create XML document.\n")); 10880 10881 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10882 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10883 uu_die(emsg_create_xml); 10884 10885 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10886 if (sb == NULL) 10887 uu_die(emsg_create_xml); 10888 safe_setprop(sb, type_attr, "manifest"); 10889 safe_setprop(sb, name_attr, "export"); 10890 (void) xmlAddSibling(doc->children, sb); 10891 10892 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10893 10894 result = write_service_bundle(doc, f); 10895 10896 free(exp_str); 10897 scf_iter_destroy(exp_val_iter); 10898 scf_iter_destroy(exp_prop_iter); 10899 scf_iter_destroy(exp_pg_iter); 10900 scf_iter_destroy(exp_inst_iter); 10901 scf_value_destroy(exp_val); 10902 scf_property_destroy(exp_prop); 10903 scf_pg_destroy(exp_pg); 10904 scf_instance_destroy(exp_inst); 10905 10906 xmlFreeDoc(doc); 10907 10908 if (f != stdout) 10909 (void) fclose(f); 10910 10911 return (result); 10912 } 10913 10914 /* 10915 * Get the service named by fmri, build an XML tree which represents it, and 10916 * dump it into filename (or stdout if filename is NULL). 10917 */ 10918 int 10919 lscf_service_export(char *fmri, const char *filename, int flags) 10920 { 10921 struct export_args args; 10922 char *fmridup; 10923 const char *scope, *svc, *inst; 10924 size_t cblen = 3 * max_scf_name_len; 10925 char *canonbuf = alloca(cblen); 10926 int ret, err; 10927 10928 lscf_prep_hndl(); 10929 10930 bzero(&args, sizeof (args)); 10931 args.filename = filename; 10932 args.flags = flags; 10933 10934 /* 10935 * If some poor user has passed an exact instance FMRI, of the sort 10936 * one might cut and paste from svcs(1) or an error message, warn 10937 * and chop off the instance instead of failing. 10938 */ 10939 fmridup = alloca(strlen(fmri) + 1); 10940 (void) strcpy(fmridup, fmri); 10941 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX, 10942 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 && 10943 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 && 10944 inst != NULL) { 10945 (void) strlcpy(canonbuf, "svc:/", cblen); 10946 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 10947 (void) strlcat(canonbuf, "/", cblen); 10948 (void) strlcat(canonbuf, scope, cblen); 10949 } 10950 (void) strlcat(canonbuf, svc, cblen); 10951 fmri = canonbuf; 10952 10953 warn(gettext("Only services may be exported; ignoring " 10954 "instance portion of argument.\n")); 10955 } 10956 10957 err = 0; 10958 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10959 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10960 &args, &err, semerr)) != 0) { 10961 if (ret != -1) 10962 semerr(gettext("Failed to walk instances: %s\n"), 10963 scf_strerror(ret)); 10964 return (-1); 10965 } 10966 10967 /* 10968 * Error message has already been printed. 10969 */ 10970 if (err != 0) 10971 return (-1); 10972 10973 return (0); 10974 } 10975 10976 10977 /* 10978 * Archive 10979 */ 10980 10981 static xmlNodePtr 10982 make_archive(int flags) 10983 { 10984 xmlNodePtr sb; 10985 scf_scope_t *scope; 10986 scf_service_t *svc; 10987 scf_iter_t *iter; 10988 int r; 10989 10990 if ((scope = scf_scope_create(g_hndl)) == NULL || 10991 (svc = scf_service_create(g_hndl)) == NULL || 10992 (iter = scf_iter_create(g_hndl)) == NULL || 10993 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10994 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10995 (exp_prop = scf_property_create(g_hndl)) == NULL || 10996 (exp_val = scf_value_create(g_hndl)) == NULL || 10997 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10998 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10999 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 11000 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 11001 scfdie(); 11002 11003 exp_str_sz = max_scf_len + 1; 11004 exp_str = safe_malloc(exp_str_sz); 11005 11006 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 11007 if (sb == NULL) 11008 uu_die(emsg_create_xml); 11009 safe_setprop(sb, type_attr, "archive"); 11010 safe_setprop(sb, name_attr, "none"); 11011 11012 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 11013 scfdie(); 11014 if (scf_iter_scope_services(iter, scope) != 0) 11015 scfdie(); 11016 11017 for (;;) { 11018 r = scf_iter_next_service(iter, svc); 11019 if (r == 0) 11020 break; 11021 if (r != 1) 11022 scfdie(); 11023 11024 if (scf_service_get_name(svc, exp_str, 11025 max_scf_name_len + 1) < 0) 11026 scfdie(); 11027 11028 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 11029 continue; 11030 11031 (void) xmlAddChild(sb, export_service(svc, flags)); 11032 } 11033 11034 free(exp_str); 11035 11036 scf_iter_destroy(exp_val_iter); 11037 scf_iter_destroy(exp_prop_iter); 11038 scf_iter_destroy(exp_pg_iter); 11039 scf_iter_destroy(exp_inst_iter); 11040 scf_value_destroy(exp_val); 11041 scf_property_destroy(exp_prop); 11042 scf_pg_destroy(exp_pg); 11043 scf_instance_destroy(exp_inst); 11044 scf_iter_destroy(iter); 11045 scf_service_destroy(svc); 11046 scf_scope_destroy(scope); 11047 11048 return (sb); 11049 } 11050 11051 int 11052 lscf_archive(const char *filename, int flags) 11053 { 11054 FILE *f; 11055 xmlDocPtr doc; 11056 int result; 11057 11058 lscf_prep_hndl(); 11059 11060 if (filename != NULL) { 11061 errno = 0; 11062 f = fopen(filename, "wb"); 11063 if (f == NULL) { 11064 if (errno == 0) 11065 uu_die(gettext("Could not open \"%s\": no free " 11066 "stdio streams.\n"), filename); 11067 else 11068 uu_die(gettext("Could not open \"%s\""), 11069 filename); 11070 } 11071 } else 11072 f = stdout; 11073 11074 doc = xmlNewDoc((xmlChar *)"1.0"); 11075 if (doc == NULL) 11076 uu_die(gettext("Could not create XML document.\n")); 11077 11078 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11079 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11080 uu_die(emsg_create_xml); 11081 11082 (void) xmlAddSibling(doc->children, make_archive(flags)); 11083 11084 result = write_service_bundle(doc, f); 11085 11086 xmlFreeDoc(doc); 11087 11088 if (f != stdout) 11089 (void) fclose(f); 11090 11091 return (result); 11092 } 11093 11094 11095 /* 11096 * "Extract" a profile. 11097 */ 11098 int 11099 lscf_profile_extract(const char *filename) 11100 { 11101 FILE *f; 11102 xmlDocPtr doc; 11103 xmlNodePtr sb, snode, inode; 11104 scf_scope_t *scope; 11105 scf_service_t *svc; 11106 scf_instance_t *inst; 11107 scf_propertygroup_t *pg; 11108 scf_property_t *prop; 11109 scf_value_t *val; 11110 scf_iter_t *siter, *iiter; 11111 int r, s; 11112 char *namebuf; 11113 uint8_t b; 11114 int result; 11115 11116 lscf_prep_hndl(); 11117 11118 if (filename != NULL) { 11119 errno = 0; 11120 f = fopen(filename, "wb"); 11121 if (f == NULL) { 11122 if (errno == 0) 11123 uu_die(gettext("Could not open \"%s\": no " 11124 "free stdio streams.\n"), filename); 11125 else 11126 uu_die(gettext("Could not open \"%s\""), 11127 filename); 11128 } 11129 } else 11130 f = stdout; 11131 11132 doc = xmlNewDoc((xmlChar *)"1.0"); 11133 if (doc == NULL) 11134 uu_die(gettext("Could not create XML document.\n")); 11135 11136 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11137 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11138 uu_die(emsg_create_xml); 11139 11140 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 11141 if (sb == NULL) 11142 uu_die(emsg_create_xml); 11143 safe_setprop(sb, type_attr, "profile"); 11144 safe_setprop(sb, name_attr, "extract"); 11145 (void) xmlAddSibling(doc->children, sb); 11146 11147 if ((scope = scf_scope_create(g_hndl)) == NULL || 11148 (svc = scf_service_create(g_hndl)) == NULL || 11149 (inst = scf_instance_create(g_hndl)) == NULL || 11150 (pg = scf_pg_create(g_hndl)) == NULL || 11151 (prop = scf_property_create(g_hndl)) == NULL || 11152 (val = scf_value_create(g_hndl)) == NULL || 11153 (siter = scf_iter_create(g_hndl)) == NULL || 11154 (iiter = scf_iter_create(g_hndl)) == NULL) 11155 scfdie(); 11156 11157 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 11158 scfdie(); 11159 11160 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 11161 scfdie(); 11162 11163 namebuf = safe_malloc(max_scf_name_len + 1); 11164 11165 while ((r = scf_iter_next_service(siter, svc)) == 1) { 11166 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 11167 scfdie(); 11168 11169 snode = xmlNewNode(NULL, (xmlChar *)"service"); 11170 if (snode == NULL) 11171 uu_die(emsg_create_xml); 11172 11173 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 11174 0) 11175 scfdie(); 11176 11177 safe_setprop(snode, name_attr, namebuf); 11178 11179 safe_setprop(snode, type_attr, "service"); 11180 safe_setprop(snode, "version", "0"); 11181 11182 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 11183 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 11184 SCF_SUCCESS) { 11185 if (scf_error() != SCF_ERROR_NOT_FOUND) 11186 scfdie(); 11187 11188 if (g_verbose) { 11189 ssize_t len; 11190 char *fmri; 11191 11192 len = 11193 scf_instance_to_fmri(inst, NULL, 0); 11194 if (len < 0) 11195 scfdie(); 11196 11197 fmri = safe_malloc(len + 1); 11198 11199 if (scf_instance_to_fmri(inst, fmri, 11200 len + 1) < 0) 11201 scfdie(); 11202 11203 warn("Instance %s has no \"%s\" " 11204 "property group.\n", fmri, 11205 scf_pg_general); 11206 11207 free(fmri); 11208 } 11209 11210 continue; 11211 } 11212 11213 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 11214 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 11215 prop_get_val(prop, val) != 0) 11216 continue; 11217 11218 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 11219 NULL); 11220 if (inode == NULL) 11221 uu_die(emsg_create_xml); 11222 11223 if (scf_instance_get_name(inst, namebuf, 11224 max_scf_name_len + 1) < 0) 11225 scfdie(); 11226 11227 safe_setprop(inode, name_attr, namebuf); 11228 11229 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 11230 scfdie(); 11231 11232 safe_setprop(inode, enabled_attr, b ? true : false); 11233 } 11234 if (s < 0) 11235 scfdie(); 11236 11237 if (snode->children != NULL) 11238 (void) xmlAddChild(sb, snode); 11239 else 11240 xmlFreeNode(snode); 11241 } 11242 if (r < 0) 11243 scfdie(); 11244 11245 free(namebuf); 11246 11247 result = write_service_bundle(doc, f); 11248 11249 xmlFreeDoc(doc); 11250 11251 if (f != stdout) 11252 (void) fclose(f); 11253 11254 return (result); 11255 } 11256 11257 11258 /* 11259 * Entity manipulation commands 11260 */ 11261 11262 /* 11263 * Entity selection. If no entity is selected, then the current scope is in 11264 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 11265 * only cur_inst is NULL, and when an instance is selected, none are NULL. 11266 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 11267 * cur_inst will be non-NULL. 11268 */ 11269 11270 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 11271 static int 11272 select_inst(const char *name) 11273 { 11274 scf_instance_t *inst; 11275 scf_error_t err; 11276 11277 assert(cur_svc != NULL); 11278 11279 inst = scf_instance_create(g_hndl); 11280 if (inst == NULL) 11281 scfdie(); 11282 11283 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 11284 cur_inst = inst; 11285 return (0); 11286 } 11287 11288 err = scf_error(); 11289 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11290 scfdie(); 11291 11292 scf_instance_destroy(inst); 11293 return (1); 11294 } 11295 11296 /* Returns as above. */ 11297 static int 11298 select_svc(const char *name) 11299 { 11300 scf_service_t *svc; 11301 scf_error_t err; 11302 11303 assert(cur_scope != NULL); 11304 11305 svc = scf_service_create(g_hndl); 11306 if (svc == NULL) 11307 scfdie(); 11308 11309 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 11310 cur_svc = svc; 11311 return (0); 11312 } 11313 11314 err = scf_error(); 11315 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11316 scfdie(); 11317 11318 scf_service_destroy(svc); 11319 return (1); 11320 } 11321 11322 /* ARGSUSED */ 11323 static int 11324 select_callback(void *unused, scf_walkinfo_t *wip) 11325 { 11326 scf_instance_t *inst; 11327 scf_service_t *svc; 11328 scf_scope_t *scope; 11329 11330 if (wip->inst != NULL) { 11331 if ((scope = scf_scope_create(g_hndl)) == NULL || 11332 (svc = scf_service_create(g_hndl)) == NULL || 11333 (inst = scf_instance_create(g_hndl)) == NULL) 11334 scfdie(); 11335 11336 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11337 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11338 scfdie(); 11339 } else { 11340 assert(wip->svc != NULL); 11341 11342 if ((scope = scf_scope_create(g_hndl)) == NULL || 11343 (svc = scf_service_create(g_hndl)) == NULL) 11344 scfdie(); 11345 11346 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11347 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11348 scfdie(); 11349 11350 inst = NULL; 11351 } 11352 11353 /* Clear out the current selection */ 11354 assert(cur_scope != NULL); 11355 scf_scope_destroy(cur_scope); 11356 scf_service_destroy(cur_svc); 11357 scf_instance_destroy(cur_inst); 11358 11359 cur_scope = scope; 11360 cur_svc = svc; 11361 cur_inst = inst; 11362 11363 return (0); 11364 } 11365 11366 static int 11367 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 11368 { 11369 char **fmri = fmri_p; 11370 11371 *fmri = strdup(wip->fmri); 11372 if (*fmri == NULL) 11373 uu_die(gettext("Out of memory.\n")); 11374 11375 return (0); 11376 } 11377 11378 /* 11379 * validate [fmri] 11380 * Perform the validation of an FMRI instance. 11381 */ 11382 void 11383 lscf_validate_fmri(const char *fmri) 11384 { 11385 int ret = 0; 11386 size_t inst_sz; 11387 char *inst_fmri = NULL; 11388 scf_tmpl_errors_t *errs = NULL; 11389 char *snapbuf = NULL; 11390 11391 lscf_prep_hndl(); 11392 11393 if (fmri == NULL) { 11394 inst_sz = max_scf_fmri_len + 1; 11395 inst_fmri = safe_malloc(inst_sz); 11396 11397 if (cur_snap != NULL) { 11398 snapbuf = safe_malloc(max_scf_name_len + 1); 11399 if (scf_snapshot_get_name(cur_snap, snapbuf, 11400 max_scf_name_len + 1) < 0) 11401 scfdie(); 11402 } 11403 if (cur_inst == NULL) { 11404 semerr(gettext("No instance selected\n")); 11405 goto cleanup; 11406 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 11407 inst_sz) >= inst_sz) { 11408 /* sanity check. Should never get here */ 11409 uu_die(gettext("Unexpected error! file %s, line %d\n"), 11410 __FILE__, __LINE__); 11411 } 11412 } else { 11413 scf_error_t scf_err; 11414 int err = 0; 11415 11416 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 11417 validate_callback, &inst_fmri, &err, semerr)) != 0) { 11418 uu_warn("Failed to walk instances: %s\n", 11419 scf_strerror(scf_err)); 11420 goto cleanup; 11421 } 11422 if (err != 0) { 11423 /* error message displayed by scf_walk_fmri */ 11424 goto cleanup; 11425 } 11426 } 11427 11428 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 11429 SCF_TMPL_VALIDATE_FLAG_CURRENT); 11430 if (ret == -1) { 11431 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 11432 warn(gettext("Template data for %s is invalid. " 11433 "Consider reverting to a previous snapshot or " 11434 "restoring original configuration.\n"), inst_fmri); 11435 } else { 11436 uu_warn("%s: %s\n", 11437 gettext("Error validating the instance"), 11438 scf_strerror(scf_error())); 11439 } 11440 } else if (ret == 1 && errs != NULL) { 11441 scf_tmpl_error_t *err = NULL; 11442 char *msg; 11443 size_t len = 256; /* initial error buffer size */ 11444 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 11445 SCF_TMPL_STRERROR_HUMAN : 0; 11446 11447 msg = safe_malloc(len); 11448 11449 while ((err = scf_tmpl_next_error(errs)) != NULL) { 11450 int ret; 11451 11452 if ((ret = scf_tmpl_strerror(err, msg, len, 11453 flag)) >= len) { 11454 len = ret + 1; 11455 msg = realloc(msg, len); 11456 if (msg == NULL) 11457 uu_die(gettext( 11458 "Out of memory.\n")); 11459 (void) scf_tmpl_strerror(err, msg, len, 11460 flag); 11461 } 11462 (void) fprintf(stderr, "%s\n", msg); 11463 } 11464 if (msg != NULL) 11465 free(msg); 11466 } 11467 if (errs != NULL) 11468 scf_tmpl_errors_destroy(errs); 11469 11470 cleanup: 11471 free(inst_fmri); 11472 free(snapbuf); 11473 } 11474 11475 static void 11476 lscf_validate_file(const char *filename) 11477 { 11478 tmpl_errors_t *errs; 11479 11480 bundle_t *b = internal_bundle_new(); 11481 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 11482 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 11483 tmpl_errors_print(stderr, errs, ""); 11484 semerr(gettext("Validation failed.\n")); 11485 } 11486 tmpl_errors_destroy(errs); 11487 } 11488 (void) internal_bundle_free(b); 11489 } 11490 11491 /* 11492 * validate [fmri|file] 11493 */ 11494 void 11495 lscf_validate(const char *arg) 11496 { 11497 const char *str; 11498 11499 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 11500 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 11501 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 11502 lscf_validate_file(str); 11503 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 11504 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 11505 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 11506 lscf_validate_fmri(str); 11507 } else if (access(arg, R_OK | F_OK) == 0) { 11508 lscf_validate_file(arg); 11509 } else { 11510 lscf_validate_fmri(arg); 11511 } 11512 } 11513 11514 void 11515 lscf_select(const char *fmri) 11516 { 11517 int ret, err; 11518 11519 lscf_prep_hndl(); 11520 11521 if (cur_snap != NULL) { 11522 struct snaplevel *elt; 11523 char *buf; 11524 11525 /* Error unless name is that of the next level. */ 11526 elt = uu_list_next(cur_levels, cur_elt); 11527 if (elt == NULL) { 11528 semerr(gettext("No children.\n")); 11529 return; 11530 } 11531 11532 buf = safe_malloc(max_scf_name_len + 1); 11533 11534 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11535 max_scf_name_len + 1) < 0) 11536 scfdie(); 11537 11538 if (strcmp(buf, fmri) != 0) { 11539 semerr(gettext("No such child.\n")); 11540 free(buf); 11541 return; 11542 } 11543 11544 free(buf); 11545 11546 cur_elt = elt; 11547 cur_level = elt->sl; 11548 return; 11549 } 11550 11551 /* 11552 * Special case for 'svc:', which takes the user to the scope level. 11553 */ 11554 if (strcmp(fmri, "svc:") == 0) { 11555 scf_instance_destroy(cur_inst); 11556 scf_service_destroy(cur_svc); 11557 cur_inst = NULL; 11558 cur_svc = NULL; 11559 return; 11560 } 11561 11562 /* 11563 * Special case for ':properties'. This appears as part of 'list' but 11564 * can't be selected. Give a more helpful error message in this case. 11565 */ 11566 if (strcmp(fmri, ":properties") == 0) { 11567 semerr(gettext(":properties is not an entity. Try 'listprop' " 11568 "to list properties.\n")); 11569 return; 11570 } 11571 11572 /* 11573 * First try the argument as relative to the current selection. 11574 */ 11575 if (cur_inst != NULL) { 11576 /* EMPTY */; 11577 } else if (cur_svc != NULL) { 11578 if (select_inst(fmri) != 1) 11579 return; 11580 } else { 11581 if (select_svc(fmri) != 1) 11582 return; 11583 } 11584 11585 err = 0; 11586 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11587 select_callback, NULL, &err, semerr)) != 0) { 11588 semerr(gettext("Failed to walk instances: %s\n"), 11589 scf_strerror(ret)); 11590 } 11591 } 11592 11593 void 11594 lscf_unselect(void) 11595 { 11596 lscf_prep_hndl(); 11597 11598 if (cur_snap != NULL) { 11599 struct snaplevel *elt; 11600 11601 elt = uu_list_prev(cur_levels, cur_elt); 11602 if (elt == NULL) { 11603 semerr(gettext("No parent levels.\n")); 11604 } else { 11605 cur_elt = elt; 11606 cur_level = elt->sl; 11607 } 11608 } else if (cur_inst != NULL) { 11609 scf_instance_destroy(cur_inst); 11610 cur_inst = NULL; 11611 } else if (cur_svc != NULL) { 11612 scf_service_destroy(cur_svc); 11613 cur_svc = NULL; 11614 } else { 11615 semerr(gettext("Cannot unselect at scope level.\n")); 11616 } 11617 } 11618 11619 /* 11620 * Return the FMRI of the current selection, for the prompt. 11621 */ 11622 void 11623 lscf_get_selection_str(char *buf, size_t bufsz) 11624 { 11625 char *cp; 11626 ssize_t fmrilen, szret; 11627 boolean_t deleted = B_FALSE; 11628 11629 if (g_hndl == NULL) { 11630 (void) strlcpy(buf, "svc:", bufsz); 11631 return; 11632 } 11633 11634 if (cur_level != NULL) { 11635 assert(cur_snap != NULL); 11636 11637 /* [ snapshot ] FMRI [: instance ] */ 11638 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11639 + 2 + max_scf_name_len + 1 + 1); 11640 11641 buf[0] = '['; 11642 11643 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11644 max_scf_name_len + 1); 11645 if (szret < 0) { 11646 if (scf_error() != SCF_ERROR_DELETED) 11647 scfdie(); 11648 11649 goto snap_deleted; 11650 } 11651 11652 (void) strcat(buf, "]svc:/"); 11653 11654 cp = strchr(buf, '\0'); 11655 11656 szret = scf_snaplevel_get_service_name(cur_level, cp, 11657 max_scf_name_len + 1); 11658 if (szret < 0) { 11659 if (scf_error() != SCF_ERROR_DELETED) 11660 scfdie(); 11661 11662 goto snap_deleted; 11663 } 11664 11665 cp = strchr(cp, '\0'); 11666 11667 if (snaplevel_is_instance(cur_level)) { 11668 *cp++ = ':'; 11669 11670 if (scf_snaplevel_get_instance_name(cur_level, cp, 11671 max_scf_name_len + 1) < 0) { 11672 if (scf_error() != SCF_ERROR_DELETED) 11673 scfdie(); 11674 11675 goto snap_deleted; 11676 } 11677 } else { 11678 *cp++ = '['; 11679 *cp++ = ':'; 11680 11681 if (scf_instance_get_name(cur_inst, cp, 11682 max_scf_name_len + 1) < 0) { 11683 if (scf_error() != SCF_ERROR_DELETED) 11684 scfdie(); 11685 11686 goto snap_deleted; 11687 } 11688 11689 (void) strcat(buf, "]"); 11690 } 11691 11692 return; 11693 11694 snap_deleted: 11695 deleted = B_TRUE; 11696 free(buf); 11697 unselect_cursnap(); 11698 } 11699 11700 assert(cur_snap == NULL); 11701 11702 if (cur_inst != NULL) { 11703 assert(cur_svc != NULL); 11704 assert(cur_scope != NULL); 11705 11706 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11707 if (fmrilen >= 0) { 11708 assert(fmrilen < bufsz); 11709 if (deleted) 11710 warn(emsg_deleted); 11711 return; 11712 } 11713 11714 if (scf_error() != SCF_ERROR_DELETED) 11715 scfdie(); 11716 11717 deleted = B_TRUE; 11718 11719 scf_instance_destroy(cur_inst); 11720 cur_inst = NULL; 11721 } 11722 11723 if (cur_svc != NULL) { 11724 assert(cur_scope != NULL); 11725 11726 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11727 if (szret >= 0) { 11728 assert(szret < bufsz); 11729 if (deleted) 11730 warn(emsg_deleted); 11731 return; 11732 } 11733 11734 if (scf_error() != SCF_ERROR_DELETED) 11735 scfdie(); 11736 11737 deleted = B_TRUE; 11738 scf_service_destroy(cur_svc); 11739 cur_svc = NULL; 11740 } 11741 11742 assert(cur_scope != NULL); 11743 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11744 11745 if (fmrilen < 0) 11746 scfdie(); 11747 11748 assert(fmrilen < bufsz); 11749 if (deleted) 11750 warn(emsg_deleted); 11751 } 11752 11753 /* 11754 * Entity listing. Entities and colon namespaces (e.g., :properties and 11755 * :statistics) are listed for the current selection. 11756 */ 11757 void 11758 lscf_list(const char *pattern) 11759 { 11760 scf_iter_t *iter; 11761 char *buf; 11762 int ret; 11763 11764 lscf_prep_hndl(); 11765 11766 if (cur_level != NULL) { 11767 struct snaplevel *elt; 11768 11769 (void) fputs(COLON_NAMESPACES, stdout); 11770 11771 elt = uu_list_next(cur_levels, cur_elt); 11772 if (elt == NULL) 11773 return; 11774 11775 /* 11776 * For now, we know that the next level is an instance. But 11777 * if we ever have multiple scopes, this could be complicated. 11778 */ 11779 buf = safe_malloc(max_scf_name_len + 1); 11780 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11781 max_scf_name_len + 1) >= 0) { 11782 (void) puts(buf); 11783 } else { 11784 if (scf_error() != SCF_ERROR_DELETED) 11785 scfdie(); 11786 } 11787 11788 free(buf); 11789 11790 return; 11791 } 11792 11793 if (cur_inst != NULL) { 11794 (void) fputs(COLON_NAMESPACES, stdout); 11795 return; 11796 } 11797 11798 iter = scf_iter_create(g_hndl); 11799 if (iter == NULL) 11800 scfdie(); 11801 11802 buf = safe_malloc(max_scf_name_len + 1); 11803 11804 if (cur_svc != NULL) { 11805 /* List the instances in this service. */ 11806 scf_instance_t *inst; 11807 11808 inst = scf_instance_create(g_hndl); 11809 if (inst == NULL) 11810 scfdie(); 11811 11812 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11813 safe_printf(COLON_NAMESPACES); 11814 11815 for (;;) { 11816 ret = scf_iter_next_instance(iter, inst); 11817 if (ret == 0) 11818 break; 11819 if (ret != 1) { 11820 if (scf_error() != SCF_ERROR_DELETED) 11821 scfdie(); 11822 11823 break; 11824 } 11825 11826 if (scf_instance_get_name(inst, buf, 11827 max_scf_name_len + 1) >= 0) { 11828 if (pattern == NULL || 11829 fnmatch(pattern, buf, 0) == 0) 11830 (void) puts(buf); 11831 } else { 11832 if (scf_error() != SCF_ERROR_DELETED) 11833 scfdie(); 11834 } 11835 } 11836 } else { 11837 if (scf_error() != SCF_ERROR_DELETED) 11838 scfdie(); 11839 } 11840 11841 scf_instance_destroy(inst); 11842 } else { 11843 /* List the services in this scope. */ 11844 scf_service_t *svc; 11845 11846 assert(cur_scope != NULL); 11847 11848 svc = scf_service_create(g_hndl); 11849 if (svc == NULL) 11850 scfdie(); 11851 11852 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11853 scfdie(); 11854 11855 for (;;) { 11856 ret = scf_iter_next_service(iter, svc); 11857 if (ret == 0) 11858 break; 11859 if (ret != 1) 11860 scfdie(); 11861 11862 if (scf_service_get_name(svc, buf, 11863 max_scf_name_len + 1) >= 0) { 11864 if (pattern == NULL || 11865 fnmatch(pattern, buf, 0) == 0) 11866 safe_printf("%s\n", buf); 11867 } else { 11868 if (scf_error() != SCF_ERROR_DELETED) 11869 scfdie(); 11870 } 11871 } 11872 11873 scf_service_destroy(svc); 11874 } 11875 11876 free(buf); 11877 scf_iter_destroy(iter); 11878 } 11879 11880 /* 11881 * Entity addition. Creates an empty entity in the current selection. 11882 */ 11883 void 11884 lscf_add(const char *name) 11885 { 11886 lscf_prep_hndl(); 11887 11888 if (cur_snap != NULL) { 11889 semerr(emsg_cant_modify_snapshots); 11890 } else if (cur_inst != NULL) { 11891 semerr(gettext("Cannot add entities to an instance.\n")); 11892 } else if (cur_svc != NULL) { 11893 11894 if (scf_service_add_instance(cur_svc, name, NULL) != 11895 SCF_SUCCESS) { 11896 switch (scf_error()) { 11897 case SCF_ERROR_INVALID_ARGUMENT: 11898 semerr(gettext("Invalid name.\n")); 11899 break; 11900 11901 case SCF_ERROR_EXISTS: 11902 semerr(gettext("Instance already exists.\n")); 11903 break; 11904 11905 case SCF_ERROR_PERMISSION_DENIED: 11906 semerr(emsg_permission_denied); 11907 break; 11908 11909 default: 11910 scfdie(); 11911 } 11912 } 11913 } else { 11914 assert(cur_scope != NULL); 11915 11916 if (scf_scope_add_service(cur_scope, name, NULL) != 11917 SCF_SUCCESS) { 11918 switch (scf_error()) { 11919 case SCF_ERROR_INVALID_ARGUMENT: 11920 semerr(gettext("Invalid name.\n")); 11921 break; 11922 11923 case SCF_ERROR_EXISTS: 11924 semerr(gettext("Service already exists.\n")); 11925 break; 11926 11927 case SCF_ERROR_PERMISSION_DENIED: 11928 semerr(emsg_permission_denied); 11929 break; 11930 11931 case SCF_ERROR_BACKEND_READONLY: 11932 semerr(emsg_read_only); 11933 break; 11934 11935 default: 11936 scfdie(); 11937 } 11938 } 11939 } 11940 } 11941 11942 /* return 1 if the entity has no persistent pgs, else return 0 */ 11943 static int 11944 entity_has_no_pgs(void *ent, int isservice) 11945 { 11946 scf_iter_t *iter = NULL; 11947 scf_propertygroup_t *pg = NULL; 11948 uint32_t flags; 11949 int err; 11950 int ret = 1; 11951 11952 if ((iter = scf_iter_create(g_hndl)) == NULL || 11953 (pg = scf_pg_create(g_hndl)) == NULL) 11954 scfdie(); 11955 11956 if (isservice) { 11957 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11958 scfdie(); 11959 } else { 11960 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11961 scfdie(); 11962 } 11963 11964 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11965 if (scf_pg_get_flags(pg, &flags) != 0) 11966 scfdie(); 11967 11968 /* skip nonpersistent pgs */ 11969 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11970 continue; 11971 11972 ret = 0; 11973 break; 11974 } 11975 11976 if (err == -1) 11977 scfdie(); 11978 11979 scf_pg_destroy(pg); 11980 scf_iter_destroy(iter); 11981 11982 return (ret); 11983 } 11984 11985 /* return 1 if the service has no instances, else return 0 */ 11986 static int 11987 svc_has_no_insts(scf_service_t *svc) 11988 { 11989 scf_instance_t *inst; 11990 scf_iter_t *iter; 11991 int r; 11992 int ret = 1; 11993 11994 if ((inst = scf_instance_create(g_hndl)) == NULL || 11995 (iter = scf_iter_create(g_hndl)) == NULL) 11996 scfdie(); 11997 11998 if (scf_iter_service_instances(iter, svc) != 0) 11999 scfdie(); 12000 12001 r = scf_iter_next_instance(iter, inst); 12002 if (r == 1) { 12003 ret = 0; 12004 } else if (r == 0) { 12005 ret = 1; 12006 } else if (r == -1) { 12007 scfdie(); 12008 } else { 12009 bad_error("scf_iter_next_instance", r); 12010 } 12011 12012 scf_iter_destroy(iter); 12013 scf_instance_destroy(inst); 12014 12015 return (ret); 12016 } 12017 12018 /* 12019 * Entity deletion. 12020 */ 12021 12022 /* 12023 * Delete the property group <fmri>/:properties/<name>. Returns 12024 * SCF_ERROR_NONE on success (or if the entity is not found), 12025 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 12026 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 12027 * denied. 12028 */ 12029 static scf_error_t 12030 delete_dependency_pg(const char *fmri, const char *name) 12031 { 12032 void *entity = NULL; 12033 int isservice; 12034 scf_propertygroup_t *pg = NULL; 12035 scf_error_t result; 12036 char *pgty; 12037 scf_service_t *svc = NULL; 12038 scf_instance_t *inst = NULL; 12039 scf_iter_t *iter = NULL; 12040 char *name_buf = NULL; 12041 12042 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 12043 switch (result) { 12044 case SCF_ERROR_NONE: 12045 break; 12046 12047 case SCF_ERROR_NO_MEMORY: 12048 uu_die(gettext("Out of memory.\n")); 12049 /* NOTREACHED */ 12050 12051 case SCF_ERROR_INVALID_ARGUMENT: 12052 case SCF_ERROR_CONSTRAINT_VIOLATED: 12053 return (SCF_ERROR_INVALID_ARGUMENT); 12054 12055 case SCF_ERROR_NOT_FOUND: 12056 result = SCF_ERROR_NONE; 12057 goto out; 12058 12059 default: 12060 bad_error("fmri_to_entity", result); 12061 } 12062 12063 pg = scf_pg_create(g_hndl); 12064 if (pg == NULL) 12065 scfdie(); 12066 12067 if (entity_get_pg(entity, isservice, name, pg) != 0) { 12068 if (scf_error() != SCF_ERROR_NOT_FOUND) 12069 scfdie(); 12070 12071 result = SCF_ERROR_NONE; 12072 goto out; 12073 } 12074 12075 pgty = safe_malloc(max_scf_pg_type_len + 1); 12076 12077 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12078 scfdie(); 12079 12080 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 12081 result = SCF_ERROR_TYPE_MISMATCH; 12082 free(pgty); 12083 goto out; 12084 } 12085 12086 free(pgty); 12087 12088 if (scf_pg_delete(pg) != 0) { 12089 result = scf_error(); 12090 if (result != SCF_ERROR_PERMISSION_DENIED) 12091 scfdie(); 12092 goto out; 12093 } 12094 12095 /* 12096 * We have to handle the case where we've just deleted the last 12097 * property group of a "dummy" entity (instance or service). 12098 * A "dummy" entity is an entity only present to hold an 12099 * external dependency. 12100 * So, in the case we deleted the last property group then we 12101 * can also delete the entity. If the entity is an instance then 12102 * we must verify if this was the last instance for the service 12103 * and if it is, we can also delete the service if it doesn't 12104 * have any property group either. 12105 */ 12106 12107 result = SCF_ERROR_NONE; 12108 12109 if (isservice) { 12110 svc = (scf_service_t *)entity; 12111 12112 if ((inst = scf_instance_create(g_hndl)) == NULL || 12113 (iter = scf_iter_create(g_hndl)) == NULL) 12114 scfdie(); 12115 12116 name_buf = safe_malloc(max_scf_name_len + 1); 12117 } else { 12118 inst = (scf_instance_t *)entity; 12119 } 12120 12121 /* 12122 * If the entity is an instance and we've just deleted its last 12123 * property group then we should delete it. 12124 */ 12125 if (!isservice && entity_has_no_pgs(entity, isservice)) { 12126 /* find the service before deleting the inst. - needed later */ 12127 if ((svc = scf_service_create(g_hndl)) == NULL) 12128 scfdie(); 12129 12130 if (scf_instance_get_parent(inst, svc) != 0) 12131 scfdie(); 12132 12133 /* delete the instance */ 12134 if (scf_instance_delete(inst) != 0) { 12135 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12136 scfdie(); 12137 12138 result = SCF_ERROR_PERMISSION_DENIED; 12139 goto out; 12140 } 12141 /* no need to refresh the instance */ 12142 inst = NULL; 12143 } 12144 12145 /* 12146 * If the service has no more instances and pgs or we just deleted the 12147 * last instance and the service doesn't have anymore propery groups 12148 * then the service should be deleted. 12149 */ 12150 if (svc != NULL && 12151 svc_has_no_insts(svc) && 12152 entity_has_no_pgs((void *)svc, 1)) { 12153 if (scf_service_delete(svc) == 0) { 12154 if (isservice) { 12155 /* no need to refresh the service */ 12156 svc = NULL; 12157 } 12158 12159 goto out; 12160 } 12161 12162 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12163 scfdie(); 12164 12165 result = SCF_ERROR_PERMISSION_DENIED; 12166 } 12167 12168 /* if the entity has not been deleted, refresh it */ 12169 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 12170 (void) refresh_entity(isservice, entity, fmri, inst, iter, 12171 name_buf); 12172 } 12173 12174 out: 12175 if (isservice && (inst != NULL && iter != NULL)) { 12176 free(name_buf); 12177 scf_iter_destroy(iter); 12178 scf_instance_destroy(inst); 12179 } 12180 12181 if (!isservice && svc != NULL) { 12182 scf_service_destroy(svc); 12183 } 12184 12185 scf_pg_destroy(pg); 12186 if (entity != NULL) 12187 entity_destroy(entity, isservice); 12188 12189 return (result); 12190 } 12191 12192 static int 12193 delete_dependents(scf_propertygroup_t *pg) 12194 { 12195 char *pgty, *name, *fmri; 12196 scf_property_t *prop; 12197 scf_value_t *val; 12198 scf_iter_t *iter; 12199 int r; 12200 scf_error_t err; 12201 12202 /* Verify that the pg has the correct type. */ 12203 pgty = safe_malloc(max_scf_pg_type_len + 1); 12204 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12205 scfdie(); 12206 12207 if (strcmp(pgty, scf_group_framework) != 0) { 12208 if (g_verbose) { 12209 fmri = safe_malloc(max_scf_fmri_len + 1); 12210 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 12211 scfdie(); 12212 12213 warn(gettext("Property group %s is not of expected " 12214 "type %s.\n"), fmri, scf_group_framework); 12215 12216 free(fmri); 12217 } 12218 12219 free(pgty); 12220 return (-1); 12221 } 12222 12223 free(pgty); 12224 12225 /* map delete_dependency_pg onto the properties. */ 12226 if ((prop = scf_property_create(g_hndl)) == NULL || 12227 (val = scf_value_create(g_hndl)) == NULL || 12228 (iter = scf_iter_create(g_hndl)) == NULL) 12229 scfdie(); 12230 12231 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 12232 scfdie(); 12233 12234 name = safe_malloc(max_scf_name_len + 1); 12235 fmri = safe_malloc(max_scf_fmri_len + 2); 12236 12237 while ((r = scf_iter_next_property(iter, prop)) == 1) { 12238 scf_type_t ty; 12239 12240 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 12241 scfdie(); 12242 12243 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 12244 scfdie(); 12245 12246 if ((ty != SCF_TYPE_ASTRING && 12247 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 12248 prop_get_val(prop, val) != 0) 12249 continue; 12250 12251 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 12252 scfdie(); 12253 12254 err = delete_dependency_pg(fmri, name); 12255 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 12256 if (scf_property_to_fmri(prop, fmri, 12257 max_scf_fmri_len + 2) < 0) 12258 scfdie(); 12259 12260 warn(gettext("Value of %s is not a valid FMRI.\n"), 12261 fmri); 12262 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 12263 warn(gettext("Property group \"%s\" of entity \"%s\" " 12264 "does not have dependency type.\n"), name, fmri); 12265 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 12266 warn(gettext("Could not delete property group \"%s\" " 12267 "of entity \"%s\" (permission denied).\n"), name, 12268 fmri); 12269 } 12270 } 12271 if (r == -1) 12272 scfdie(); 12273 12274 scf_value_destroy(val); 12275 scf_property_destroy(prop); 12276 12277 return (0); 12278 } 12279 12280 /* 12281 * Returns 1 if the instance may be running, and 0 otherwise. 12282 */ 12283 static int 12284 inst_is_running(scf_instance_t *inst) 12285 { 12286 scf_propertygroup_t *pg; 12287 scf_property_t *prop; 12288 scf_value_t *val; 12289 char buf[MAX_SCF_STATE_STRING_SZ]; 12290 int ret = 0; 12291 ssize_t szret; 12292 12293 if ((pg = scf_pg_create(g_hndl)) == NULL || 12294 (prop = scf_property_create(g_hndl)) == NULL || 12295 (val = scf_value_create(g_hndl)) == NULL) 12296 scfdie(); 12297 12298 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 12299 if (scf_error() != SCF_ERROR_NOT_FOUND) 12300 scfdie(); 12301 goto out; 12302 } 12303 12304 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 12305 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 12306 prop_get_val(prop, val) != 0) 12307 goto out; 12308 12309 szret = scf_value_get_astring(val, buf, sizeof (buf)); 12310 assert(szret >= 0); 12311 12312 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 12313 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 12314 12315 out: 12316 scf_value_destroy(val); 12317 scf_property_destroy(prop); 12318 scf_pg_destroy(pg); 12319 return (ret); 12320 } 12321 12322 static uint8_t 12323 pg_is_external_dependency(scf_propertygroup_t *pg) 12324 { 12325 char *type; 12326 scf_value_t *val; 12327 scf_property_t *prop; 12328 uint8_t b = B_FALSE; 12329 12330 type = safe_malloc(max_scf_pg_type_len + 1); 12331 12332 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 12333 scfdie(); 12334 12335 if ((prop = scf_property_create(g_hndl)) == NULL || 12336 (val = scf_value_create(g_hndl)) == NULL) 12337 scfdie(); 12338 12339 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 12340 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 12341 if (scf_property_get_value(prop, val) != 0) 12342 scfdie(); 12343 if (scf_value_get_boolean(val, &b) != 0) 12344 scfdie(); 12345 } 12346 } 12347 12348 free(type); 12349 (void) scf_value_destroy(val); 12350 (void) scf_property_destroy(prop); 12351 12352 return (b); 12353 } 12354 12355 #define DELETE_FAILURE -1 12356 #define DELETE_SUCCESS_NOEXTDEPS 0 12357 #define DELETE_SUCCESS_EXTDEPS 1 12358 12359 /* 12360 * lscf_instance_delete() deletes an instance. Before calling 12361 * scf_instance_delete(), though, we make sure the instance isn't 12362 * running and delete dependencies in other entities which the instance 12363 * declared as "dependents". If there are dependencies which were 12364 * created for other entities, then instead of deleting the instance we 12365 * make it "empty" by deleting all other property groups and all 12366 * snapshots. 12367 * 12368 * lscf_instance_delete() verifies that there is no external dependency pgs 12369 * before suppressing the instance. If there is, then we must not remove them 12370 * now in case the instance is re-created otherwise the dependencies would be 12371 * lost. The external dependency pgs will be removed if the dependencies are 12372 * removed. 12373 * 12374 * Returns: 12375 * DELETE_FAILURE on failure 12376 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12377 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12378 */ 12379 static int 12380 lscf_instance_delete(scf_instance_t *inst, int force) 12381 { 12382 scf_propertygroup_t *pg; 12383 scf_snapshot_t *snap; 12384 scf_iter_t *iter; 12385 int err; 12386 int external = 0; 12387 12388 /* If we're not forcing and the instance is running, refuse. */ 12389 if (!force && inst_is_running(inst)) { 12390 char *fmri; 12391 12392 fmri = safe_malloc(max_scf_fmri_len + 1); 12393 12394 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 12395 scfdie(); 12396 12397 semerr(gettext("Instance %s may be running. " 12398 "Use delete -f if it is not.\n"), fmri); 12399 12400 free(fmri); 12401 return (DELETE_FAILURE); 12402 } 12403 12404 pg = scf_pg_create(g_hndl); 12405 if (pg == NULL) 12406 scfdie(); 12407 12408 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 12409 (void) delete_dependents(pg); 12410 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12411 scfdie(); 12412 12413 scf_pg_destroy(pg); 12414 12415 /* 12416 * If the instance has some external dependencies then we must 12417 * keep them in case the instance is reimported otherwise the 12418 * dependencies would be lost on reimport. 12419 */ 12420 if ((iter = scf_iter_create(g_hndl)) == NULL || 12421 (pg = scf_pg_create(g_hndl)) == NULL) 12422 scfdie(); 12423 12424 if (scf_iter_instance_pgs(iter, inst) < 0) 12425 scfdie(); 12426 12427 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 12428 if (pg_is_external_dependency(pg)) { 12429 external = 1; 12430 continue; 12431 } 12432 12433 if (scf_pg_delete(pg) != 0) { 12434 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12435 scfdie(); 12436 else { 12437 semerr(emsg_permission_denied); 12438 12439 (void) scf_iter_destroy(iter); 12440 (void) scf_pg_destroy(pg); 12441 return (DELETE_FAILURE); 12442 } 12443 } 12444 } 12445 12446 if (err == -1) 12447 scfdie(); 12448 12449 (void) scf_iter_destroy(iter); 12450 (void) scf_pg_destroy(pg); 12451 12452 if (external) { 12453 /* 12454 * All the pgs have been deleted for the instance except 12455 * the ones holding the external dependencies. 12456 * For the job to be complete, we must also delete the 12457 * snapshots associated with the instance. 12458 */ 12459 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 12460 NULL) 12461 scfdie(); 12462 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 12463 scfdie(); 12464 12465 if (scf_iter_instance_snapshots(iter, inst) == -1) 12466 scfdie(); 12467 12468 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 12469 if (_scf_snapshot_delete(snap) != 0) { 12470 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12471 scfdie(); 12472 12473 semerr(emsg_permission_denied); 12474 12475 (void) scf_iter_destroy(iter); 12476 (void) scf_snapshot_destroy(snap); 12477 return (DELETE_FAILURE); 12478 } 12479 } 12480 12481 if (err == -1) 12482 scfdie(); 12483 12484 (void) scf_iter_destroy(iter); 12485 (void) scf_snapshot_destroy(snap); 12486 return (DELETE_SUCCESS_EXTDEPS); 12487 } 12488 12489 if (scf_instance_delete(inst) != 0) { 12490 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12491 scfdie(); 12492 12493 semerr(emsg_permission_denied); 12494 12495 return (DELETE_FAILURE); 12496 } 12497 12498 return (DELETE_SUCCESS_NOEXTDEPS); 12499 } 12500 12501 /* 12502 * lscf_service_delete() deletes a service. Before calling 12503 * scf_service_delete(), though, we call lscf_instance_delete() for 12504 * each of the instances and delete dependencies in other entities 12505 * which were created as "dependents" of this service. If there are 12506 * dependencies which were created for other entities, then we delete 12507 * all other property groups in the service and leave it as "empty". 12508 * 12509 * lscf_service_delete() verifies that there is no external dependency 12510 * pgs at the instance & service level before suppressing the service. 12511 * If there is, then we must not remove them now in case the service 12512 * is re-imported otherwise the dependencies would be lost. The external 12513 * dependency pgs will be removed if the dependencies are removed. 12514 * 12515 * Returns: 12516 * DELETE_FAILURE on failure 12517 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12518 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12519 */ 12520 static int 12521 lscf_service_delete(scf_service_t *svc, int force) 12522 { 12523 int r; 12524 scf_instance_t *inst; 12525 scf_propertygroup_t *pg; 12526 scf_iter_t *iter; 12527 int ret; 12528 int external = 0; 12529 12530 if ((inst = scf_instance_create(g_hndl)) == NULL || 12531 (pg = scf_pg_create(g_hndl)) == NULL || 12532 (iter = scf_iter_create(g_hndl)) == NULL) 12533 scfdie(); 12534 12535 if (scf_iter_service_instances(iter, svc) != 0) 12536 scfdie(); 12537 12538 for (r = scf_iter_next_instance(iter, inst); 12539 r == 1; 12540 r = scf_iter_next_instance(iter, inst)) { 12541 12542 ret = lscf_instance_delete(inst, force); 12543 if (ret == DELETE_FAILURE) { 12544 scf_iter_destroy(iter); 12545 scf_pg_destroy(pg); 12546 scf_instance_destroy(inst); 12547 return (DELETE_FAILURE); 12548 } 12549 12550 /* 12551 * Record the fact that there is some external dependencies 12552 * at the instance level. 12553 */ 12554 if (ret == DELETE_SUCCESS_EXTDEPS) 12555 external |= 1; 12556 } 12557 12558 if (r != 0) 12559 scfdie(); 12560 12561 /* Delete dependency property groups in dependent services. */ 12562 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12563 (void) delete_dependents(pg); 12564 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12565 scfdie(); 12566 12567 scf_iter_destroy(iter); 12568 scf_pg_destroy(pg); 12569 scf_instance_destroy(inst); 12570 12571 /* 12572 * If the service has some external dependencies then we don't 12573 * want to remove them in case the service is re-imported. 12574 */ 12575 if ((pg = scf_pg_create(g_hndl)) == NULL || 12576 (iter = scf_iter_create(g_hndl)) == NULL) 12577 scfdie(); 12578 12579 if (scf_iter_service_pgs(iter, svc) < 0) 12580 scfdie(); 12581 12582 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12583 if (pg_is_external_dependency(pg)) { 12584 external |= 2; 12585 continue; 12586 } 12587 12588 if (scf_pg_delete(pg) != 0) { 12589 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12590 scfdie(); 12591 else { 12592 semerr(emsg_permission_denied); 12593 12594 (void) scf_iter_destroy(iter); 12595 (void) scf_pg_destroy(pg); 12596 return (DELETE_FAILURE); 12597 } 12598 } 12599 } 12600 12601 if (r == -1) 12602 scfdie(); 12603 12604 (void) scf_iter_destroy(iter); 12605 (void) scf_pg_destroy(pg); 12606 12607 if (external != 0) 12608 return (DELETE_SUCCESS_EXTDEPS); 12609 12610 if (scf_service_delete(svc) == 0) 12611 return (DELETE_SUCCESS_NOEXTDEPS); 12612 12613 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12614 scfdie(); 12615 12616 semerr(emsg_permission_denied); 12617 return (DELETE_FAILURE); 12618 } 12619 12620 static int 12621 delete_callback(void *data, scf_walkinfo_t *wip) 12622 { 12623 int force = (int)data; 12624 12625 if (wip->inst != NULL) 12626 (void) lscf_instance_delete(wip->inst, force); 12627 else 12628 (void) lscf_service_delete(wip->svc, force); 12629 12630 return (0); 12631 } 12632 12633 void 12634 lscf_delete(const char *fmri, int force) 12635 { 12636 scf_service_t *svc; 12637 scf_instance_t *inst; 12638 int ret; 12639 12640 lscf_prep_hndl(); 12641 12642 if (cur_snap != NULL) { 12643 if (!snaplevel_is_instance(cur_level)) { 12644 char *buf; 12645 12646 buf = safe_malloc(max_scf_name_len + 1); 12647 if (scf_instance_get_name(cur_inst, buf, 12648 max_scf_name_len + 1) >= 0) { 12649 if (strcmp(buf, fmri) == 0) { 12650 semerr(emsg_cant_modify_snapshots); 12651 free(buf); 12652 return; 12653 } 12654 } else if (scf_error() != SCF_ERROR_DELETED) { 12655 scfdie(); 12656 } 12657 free(buf); 12658 } 12659 } else if (cur_inst != NULL) { 12660 /* EMPTY */; 12661 } else if (cur_svc != NULL) { 12662 inst = scf_instance_create(g_hndl); 12663 if (inst == NULL) 12664 scfdie(); 12665 12666 if (scf_service_get_instance(cur_svc, fmri, inst) == 12667 SCF_SUCCESS) { 12668 (void) lscf_instance_delete(inst, force); 12669 scf_instance_destroy(inst); 12670 return; 12671 } 12672 12673 if (scf_error() != SCF_ERROR_NOT_FOUND && 12674 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12675 scfdie(); 12676 12677 scf_instance_destroy(inst); 12678 } else { 12679 assert(cur_scope != NULL); 12680 12681 svc = scf_service_create(g_hndl); 12682 if (svc == NULL) 12683 scfdie(); 12684 12685 if (scf_scope_get_service(cur_scope, fmri, svc) == 12686 SCF_SUCCESS) { 12687 (void) lscf_service_delete(svc, force); 12688 scf_service_destroy(svc); 12689 return; 12690 } 12691 12692 if (scf_error() != SCF_ERROR_NOT_FOUND && 12693 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12694 scfdie(); 12695 12696 scf_service_destroy(svc); 12697 } 12698 12699 /* 12700 * Match FMRI to entity. 12701 */ 12702 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12703 delete_callback, (void *)force, NULL, semerr)) != 0) { 12704 semerr(gettext("Failed to walk instances: %s\n"), 12705 scf_strerror(ret)); 12706 } 12707 } 12708 12709 12710 12711 /* 12712 * :properties commands. These all end with "pg" or "prop" and generally 12713 * operate on the currently selected entity. 12714 */ 12715 12716 /* 12717 * Property listing. List the property groups, properties, their types and 12718 * their values for the currently selected entity. 12719 */ 12720 static void 12721 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12722 { 12723 char *buf; 12724 uint32_t flags; 12725 12726 buf = safe_malloc(max_scf_pg_type_len + 1); 12727 12728 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12729 scfdie(); 12730 12731 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12732 scfdie(); 12733 12734 safe_printf("%-*s %s", namewidth, name, buf); 12735 12736 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12737 safe_printf("\tNONPERSISTENT"); 12738 12739 safe_printf("\n"); 12740 12741 free(buf); 12742 } 12743 12744 static boolean_t 12745 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12746 { 12747 if (scf_property_get_value(prop, val) == 0) { 12748 return (B_FALSE); 12749 } else { 12750 switch (scf_error()) { 12751 case SCF_ERROR_NOT_FOUND: 12752 return (B_FALSE); 12753 case SCF_ERROR_PERMISSION_DENIED: 12754 case SCF_ERROR_CONSTRAINT_VIOLATED: 12755 return (B_TRUE); 12756 default: 12757 scfdie(); 12758 /*NOTREACHED*/ 12759 } 12760 } 12761 } 12762 12763 static void 12764 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12765 { 12766 scf_iter_t *iter; 12767 scf_value_t *val; 12768 const char *type; 12769 int multiple_strings = 0; 12770 int ret; 12771 12772 if ((iter = scf_iter_create(g_hndl)) == NULL || 12773 (val = scf_value_create(g_hndl)) == NULL) 12774 scfdie(); 12775 12776 type = prop_to_typestr(prop); 12777 assert(type != NULL); 12778 12779 safe_printf("%-*s %-7s ", len, name, type); 12780 12781 if (prop_has_multiple_values(prop, val) && 12782 (scf_value_type(val) == SCF_TYPE_ASTRING || 12783 scf_value_type(val) == SCF_TYPE_USTRING)) 12784 multiple_strings = 1; 12785 12786 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12787 scfdie(); 12788 12789 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12790 char *buf; 12791 ssize_t vlen, szret; 12792 12793 vlen = scf_value_get_as_string(val, NULL, 0); 12794 if (vlen < 0) 12795 scfdie(); 12796 12797 buf = safe_malloc(vlen + 1); 12798 12799 szret = scf_value_get_as_string(val, buf, vlen + 1); 12800 if (szret < 0) 12801 scfdie(); 12802 assert(szret <= vlen); 12803 12804 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12805 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12806 safe_printf(" \""); 12807 (void) quote_and_print(buf, stdout, 0); 12808 (void) putchar('"'); 12809 if (ferror(stdout)) { 12810 (void) putchar('\n'); 12811 uu_die(gettext("Error writing to stdout.\n")); 12812 } 12813 } else { 12814 safe_printf(" %s", buf); 12815 } 12816 12817 free(buf); 12818 } 12819 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12820 scfdie(); 12821 12822 if (putchar('\n') != '\n') 12823 uu_die(gettext("Could not output newline")); 12824 } 12825 12826 /* 12827 * Outputs template property group info for the describe subcommand. 12828 * If 'templates' == 2, verbose output is printed in the format expected 12829 * for describe -v, which includes all templates fields. If pg is 12830 * not NULL, we're describing the template data, not an existing property 12831 * group, and formatting should be appropriate for describe -t. 12832 */ 12833 static void 12834 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12835 { 12836 char *buf; 12837 uint8_t required; 12838 scf_property_t *stability_prop; 12839 scf_value_t *stability_val; 12840 12841 if (templates == 0) 12842 return; 12843 12844 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12845 (stability_val = scf_value_create(g_hndl)) == NULL) 12846 scfdie(); 12847 12848 if (templates == 2 && pg != NULL) { 12849 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12850 stability_prop) == 0) { 12851 if (prop_check_type(stability_prop, 12852 SCF_TYPE_ASTRING) == 0 && 12853 prop_get_val(stability_prop, stability_val) == 0) { 12854 char *stability; 12855 12856 stability = safe_malloc(max_scf_value_len + 1); 12857 12858 if (scf_value_get_astring(stability_val, 12859 stability, max_scf_value_len + 1) == -1 && 12860 scf_error() != SCF_ERROR_NOT_FOUND) 12861 scfdie(); 12862 12863 safe_printf("%s%s: %s\n", TMPL_INDENT, 12864 gettext("stability"), stability); 12865 12866 free(stability); 12867 } 12868 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12869 scfdie(); 12870 } 12871 12872 scf_property_destroy(stability_prop); 12873 scf_value_destroy(stability_val); 12874 12875 if (pgt == NULL) 12876 return; 12877 12878 if (pg == NULL || templates == 2) { 12879 /* print type info only if scf_tmpl_pg_name succeeds */ 12880 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12881 if (pg != NULL) 12882 safe_printf("%s", TMPL_INDENT); 12883 safe_printf("%s: ", gettext("name")); 12884 safe_printf("%s\n", buf); 12885 free(buf); 12886 } 12887 12888 /* print type info only if scf_tmpl_pg_type succeeds */ 12889 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12890 if (pg != NULL) 12891 safe_printf("%s", TMPL_INDENT); 12892 safe_printf("%s: ", gettext("type")); 12893 safe_printf("%s\n", buf); 12894 free(buf); 12895 } 12896 } 12897 12898 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12899 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12900 required ? "true" : "false"); 12901 12902 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12903 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12904 buf); 12905 free(buf); 12906 } 12907 12908 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12909 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12910 buf); 12911 free(buf); 12912 } 12913 12914 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12915 if (templates == 2) 12916 safe_printf("%s%s: %s\n", TMPL_INDENT, 12917 gettext("description"), buf); 12918 else 12919 safe_printf("%s%s\n", TMPL_INDENT, buf); 12920 free(buf); 12921 } 12922 12923 } 12924 12925 /* 12926 * With as_value set to true, indent as appropriate for the value level. 12927 * If false, indent to appropriate level for inclusion in constraint 12928 * or choice printout. 12929 */ 12930 static void 12931 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12932 int as_value) 12933 { 12934 char *buf; 12935 12936 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12937 if (as_value == 0) 12938 safe_printf("%s", TMPL_CHOICE_INDENT); 12939 else 12940 safe_printf("%s", TMPL_INDENT); 12941 safe_printf("%s: %s\n", gettext("value common name"), buf); 12942 free(buf); 12943 } 12944 12945 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12946 if (as_value == 0) 12947 safe_printf("%s", TMPL_CHOICE_INDENT); 12948 else 12949 safe_printf("%s", TMPL_INDENT); 12950 safe_printf("%s: %s\n", gettext("value description"), buf); 12951 free(buf); 12952 } 12953 } 12954 12955 static void 12956 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12957 { 12958 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12959 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12960 safe_printf("%s\n", val_buf); 12961 12962 print_template_value_details(prt, val_buf, 1); 12963 } 12964 12965 static void 12966 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12967 { 12968 int i, printed = 0; 12969 scf_values_t values; 12970 scf_count_ranges_t c_ranges; 12971 scf_int_ranges_t i_ranges; 12972 12973 printed = 0; 12974 i = 0; 12975 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12976 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12977 gettext("value constraints")); 12978 printed++; 12979 for (i = 0; i < values.value_count; ++i) { 12980 safe_printf("%s%s: %s\n", TMPL_INDENT, 12981 gettext("value name"), values.values_as_strings[i]); 12982 if (verbose == 1) 12983 print_template_value_details(prt, 12984 values.values_as_strings[i], 0); 12985 } 12986 12987 scf_values_destroy(&values); 12988 } 12989 12990 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12991 if (printed++ == 0) 12992 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12993 gettext("value constraints")); 12994 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12995 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12996 gettext("range"), c_ranges.scr_min[i], 12997 c_ranges.scr_max[i]); 12998 } 12999 scf_count_ranges_destroy(&c_ranges); 13000 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 13001 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 13002 if (printed++ == 0) 13003 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13004 gettext("value constraints")); 13005 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 13006 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 13007 gettext("range"), i_ranges.sir_min[i], 13008 i_ranges.sir_max[i]); 13009 } 13010 scf_int_ranges_destroy(&i_ranges); 13011 } 13012 } 13013 13014 static void 13015 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 13016 { 13017 int i = 0, printed = 0; 13018 scf_values_t values; 13019 scf_count_ranges_t c_ranges; 13020 scf_int_ranges_t i_ranges; 13021 13022 printed = 0; 13023 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 13024 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13025 gettext("value constraints")); 13026 printed++; 13027 for (i = 0; i < values.value_count; i++) { 13028 safe_printf("%s%s: %s\n", TMPL_INDENT, 13029 gettext("value name"), values.values_as_strings[i]); 13030 if (verbose == 1) 13031 print_template_value_details(prt, 13032 values.values_as_strings[i], 0); 13033 } 13034 13035 scf_values_destroy(&values); 13036 } 13037 13038 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 13039 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 13040 if (printed++ == 0) 13041 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13042 gettext("value choices")); 13043 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 13044 gettext("range"), c_ranges.scr_min[i], 13045 c_ranges.scr_max[i]); 13046 } 13047 scf_count_ranges_destroy(&c_ranges); 13048 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 13049 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 13050 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 13051 if (printed++ == 0) 13052 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13053 gettext("value choices")); 13054 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 13055 gettext("range"), i_ranges.sir_min[i], 13056 i_ranges.sir_max[i]); 13057 } 13058 scf_int_ranges_destroy(&i_ranges); 13059 } 13060 } 13061 13062 static void 13063 list_values_by_template(scf_prop_tmpl_t *prt) 13064 { 13065 print_template_constraints(prt, 1); 13066 print_template_choices(prt, 1); 13067 } 13068 13069 static void 13070 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 13071 { 13072 char *val_buf; 13073 scf_iter_t *iter; 13074 scf_value_t *val; 13075 int ret; 13076 13077 if ((iter = scf_iter_create(g_hndl)) == NULL || 13078 (val = scf_value_create(g_hndl)) == NULL) 13079 scfdie(); 13080 13081 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 13082 scfdie(); 13083 13084 val_buf = safe_malloc(max_scf_value_len + 1); 13085 13086 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13087 if (scf_value_get_as_string(val, val_buf, 13088 max_scf_value_len + 1) < 0) 13089 scfdie(); 13090 13091 print_template_value(prt, val_buf); 13092 } 13093 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 13094 scfdie(); 13095 free(val_buf); 13096 13097 print_template_constraints(prt, 0); 13098 print_template_choices(prt, 0); 13099 13100 } 13101 13102 /* 13103 * Outputs property info for the describe subcommand 13104 * Verbose output if templates == 2, -v option of svccfg describe 13105 * Displays template data if prop is not NULL, -t option of svccfg describe 13106 */ 13107 static void 13108 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 13109 { 13110 char *buf; 13111 uint8_t u_buf; 13112 int i; 13113 uint64_t min, max; 13114 scf_values_t values; 13115 13116 if (prt == NULL || templates == 0) 13117 return; 13118 13119 if (prop == NULL) { 13120 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 13121 if (scf_tmpl_prop_name(prt, &buf) > 0) { 13122 safe_printf("%s\n", buf); 13123 free(buf); 13124 } else 13125 safe_printf("(%s)\n", gettext("any")); 13126 } 13127 13128 if (prop == NULL || templates == 2) { 13129 if (prop != NULL) 13130 safe_printf("%s", TMPL_INDENT); 13131 else 13132 safe_printf("%s", TMPL_VALUE_INDENT); 13133 safe_printf("%s: ", gettext("type")); 13134 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 13135 safe_printf("%s\n", buf); 13136 free(buf); 13137 } else 13138 safe_printf("(%s)\n", gettext("any")); 13139 } 13140 13141 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 13142 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 13143 u_buf ? "true" : "false"); 13144 13145 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 13146 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 13147 buf); 13148 free(buf); 13149 } 13150 13151 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 13152 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 13153 buf); 13154 free(buf); 13155 } 13156 13157 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 13158 safe_printf("%s%s\n", TMPL_INDENT, buf); 13159 free(buf); 13160 } 13161 13162 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 13163 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 13164 scf_tmpl_visibility_to_string(u_buf)); 13165 13166 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 13167 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13168 gettext("minimum number of values"), min); 13169 if (max == ULLONG_MAX) { 13170 safe_printf("%s%s: %s\n", TMPL_INDENT, 13171 gettext("maximum number of values"), 13172 gettext("unlimited")); 13173 } else { 13174 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13175 gettext("maximum number of values"), max); 13176 } 13177 } 13178 13179 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 13180 for (i = 0; i < values.value_count; i++) { 13181 if (i == 0) { 13182 safe_printf("%s%s:", TMPL_INDENT, 13183 gettext("internal separators")); 13184 } 13185 safe_printf(" \"%s\"", values.values_as_strings[i]); 13186 } 13187 safe_printf("\n"); 13188 } 13189 13190 if (templates != 2) 13191 return; 13192 13193 if (prop != NULL) 13194 list_values_tmpl(prt, prop); 13195 else 13196 list_values_by_template(prt); 13197 } 13198 13199 static char * 13200 read_astring(scf_propertygroup_t *pg, const char *prop_name) 13201 { 13202 char *rv; 13203 13204 rv = _scf_read_single_astring_from_pg(pg, prop_name); 13205 if (rv == NULL) { 13206 switch (scf_error()) { 13207 case SCF_ERROR_NOT_FOUND: 13208 break; 13209 default: 13210 scfdie(); 13211 } 13212 } 13213 return (rv); 13214 } 13215 13216 static void 13217 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 13218 { 13219 size_t doc_len; 13220 size_t man_len; 13221 char *pg_name; 13222 char *text = NULL; 13223 int rv; 13224 13225 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 13226 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 13227 pg_name = safe_malloc(max_scf_name_len + 1); 13228 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 13229 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 13230 scfdie(); 13231 } 13232 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 13233 /* Display doc_link and and uri */ 13234 safe_printf("%s%s:\n", TMPL_INDENT, 13235 gettext("doc_link")); 13236 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 13237 if (text != NULL) { 13238 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13239 TMPL_INDENT, gettext("name"), text); 13240 uu_free(text); 13241 } 13242 text = read_astring(pg, SCF_PROPERTY_TM_URI); 13243 if (text != NULL) { 13244 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 13245 gettext("uri"), text); 13246 uu_free(text); 13247 } 13248 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 13249 man_len) == 0) { 13250 /* Display manpage title, section and path */ 13251 safe_printf("%s%s:\n", TMPL_INDENT, 13252 gettext("manpage")); 13253 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 13254 if (text != NULL) { 13255 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13256 TMPL_INDENT, gettext("title"), text); 13257 uu_free(text); 13258 } 13259 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 13260 if (text != NULL) { 13261 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13262 TMPL_INDENT, gettext("section"), text); 13263 uu_free(text); 13264 } 13265 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 13266 if (text != NULL) { 13267 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13268 TMPL_INDENT, gettext("manpath"), text); 13269 uu_free(text); 13270 } 13271 } 13272 } 13273 if (rv == -1) 13274 scfdie(); 13275 13276 done: 13277 free(pg_name); 13278 } 13279 13280 static void 13281 list_entity_tmpl(int templates) 13282 { 13283 char *common_name = NULL; 13284 char *description = NULL; 13285 char *locale = NULL; 13286 scf_iter_t *iter; 13287 scf_propertygroup_t *pg; 13288 scf_property_t *prop; 13289 int r; 13290 scf_value_t *val; 13291 13292 if ((pg = scf_pg_create(g_hndl)) == NULL || 13293 (prop = scf_property_create(g_hndl)) == NULL || 13294 (val = scf_value_create(g_hndl)) == NULL || 13295 (iter = scf_iter_create(g_hndl)) == NULL) 13296 scfdie(); 13297 13298 locale = setlocale(LC_MESSAGES, NULL); 13299 13300 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 13301 common_name = safe_malloc(max_scf_value_len + 1); 13302 13303 /* Try both the current locale and the "C" locale. */ 13304 if (scf_pg_get_property(pg, locale, prop) == 0 || 13305 (scf_error() == SCF_ERROR_NOT_FOUND && 13306 scf_pg_get_property(pg, "C", prop) == 0)) { 13307 if (prop_get_val(prop, val) == 0 && 13308 scf_value_get_ustring(val, common_name, 13309 max_scf_value_len + 1) != -1) { 13310 safe_printf("%s%s: %s\n", TMPL_INDENT, 13311 gettext("common name"), common_name); 13312 } 13313 } 13314 } 13315 13316 /* 13317 * Do description, manpages, and doc links if templates == 2. 13318 */ 13319 if (templates == 2) { 13320 /* Get the description. */ 13321 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 13322 description = safe_malloc(max_scf_value_len + 1); 13323 13324 /* Try both the current locale and the "C" locale. */ 13325 if (scf_pg_get_property(pg, locale, prop) == 0 || 13326 (scf_error() == SCF_ERROR_NOT_FOUND && 13327 scf_pg_get_property(pg, "C", prop) == 0)) { 13328 if (prop_get_val(prop, val) == 0 && 13329 scf_value_get_ustring(val, description, 13330 max_scf_value_len + 1) != -1) { 13331 safe_printf("%s%s: %s\n", TMPL_INDENT, 13332 gettext("description"), 13333 description); 13334 } 13335 } 13336 } 13337 13338 /* Process doc_link & manpage elements. */ 13339 if (cur_level != NULL) { 13340 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 13341 SCF_GROUP_TEMPLATE); 13342 } else if (cur_inst != NULL) { 13343 r = scf_iter_instance_pgs_typed(iter, cur_inst, 13344 SCF_GROUP_TEMPLATE); 13345 } else { 13346 r = scf_iter_service_pgs_typed(iter, cur_svc, 13347 SCF_GROUP_TEMPLATE); 13348 } 13349 if (r == 0) { 13350 display_documentation(iter, pg); 13351 } 13352 } 13353 13354 free(common_name); 13355 free(description); 13356 scf_pg_destroy(pg); 13357 scf_property_destroy(prop); 13358 scf_value_destroy(val); 13359 scf_iter_destroy(iter); 13360 } 13361 13362 static void 13363 listtmpl(const char *pattern, int templates) 13364 { 13365 scf_pg_tmpl_t *pgt; 13366 scf_prop_tmpl_t *prt; 13367 char *snapbuf = NULL; 13368 char *fmribuf; 13369 char *pg_name = NULL, *prop_name = NULL; 13370 ssize_t prop_name_size; 13371 char *qual_prop_name; 13372 char *search_name; 13373 int listed = 0; 13374 13375 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13376 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 13377 scfdie(); 13378 13379 fmribuf = safe_malloc(max_scf_name_len + 1); 13380 qual_prop_name = safe_malloc(max_scf_name_len + 1); 13381 13382 if (cur_snap != NULL) { 13383 snapbuf = safe_malloc(max_scf_name_len + 1); 13384 if (scf_snapshot_get_name(cur_snap, snapbuf, 13385 max_scf_name_len + 1) < 0) 13386 scfdie(); 13387 } 13388 13389 if (cur_inst != NULL) { 13390 if (scf_instance_to_fmri(cur_inst, fmribuf, 13391 max_scf_name_len + 1) < 0) 13392 scfdie(); 13393 } else if (cur_svc != NULL) { 13394 if (scf_service_to_fmri(cur_svc, fmribuf, 13395 max_scf_name_len + 1) < 0) 13396 scfdie(); 13397 } else 13398 abort(); 13399 13400 /* If pattern is specified, we want to list only those items. */ 13401 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) { 13402 listed = 0; 13403 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 13404 fnmatch(pattern, pg_name, 0) == 0)) { 13405 list_pg_tmpl(pgt, NULL, templates); 13406 listed++; 13407 } 13408 13409 scf_tmpl_prop_reset(prt); 13410 13411 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) { 13412 search_name = NULL; 13413 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 13414 if ((prop_name_size > 0) && (pg_name != NULL)) { 13415 if (snprintf(qual_prop_name, 13416 max_scf_name_len + 1, "%s/%s", 13417 pg_name, prop_name) >= 13418 max_scf_name_len + 1) { 13419 prop_name_size = -1; 13420 } else { 13421 search_name = qual_prop_name; 13422 } 13423 } 13424 if (listed > 0 || pattern == NULL || 13425 (prop_name_size > 0 && 13426 fnmatch(pattern, search_name, 13427 FNM_PATHNAME) == 0)) 13428 list_prop_tmpl(prt, NULL, templates); 13429 if (prop_name != NULL) { 13430 free(prop_name); 13431 prop_name = NULL; 13432 } 13433 } 13434 if (pg_name != NULL) { 13435 free(pg_name); 13436 pg_name = NULL; 13437 } 13438 } 13439 13440 scf_tmpl_prop_destroy(prt); 13441 scf_tmpl_pg_destroy(pgt); 13442 free(snapbuf); 13443 free(fmribuf); 13444 free(qual_prop_name); 13445 } 13446 13447 static void 13448 listprop(const char *pattern, int only_pgs, int templates) 13449 { 13450 scf_propertygroup_t *pg; 13451 scf_property_t *prop; 13452 scf_iter_t *iter, *piter; 13453 char *pgnbuf, *prnbuf, *ppnbuf; 13454 scf_pg_tmpl_t *pgt, *pgtp; 13455 scf_prop_tmpl_t *prt; 13456 13457 void **objects; 13458 char **names; 13459 void **tmpls; 13460 int allocd, i; 13461 13462 int ret; 13463 ssize_t pgnlen, prnlen, szret; 13464 size_t max_len = 0; 13465 13466 if (cur_svc == NULL && cur_inst == NULL) { 13467 semerr(emsg_entity_not_selected); 13468 return; 13469 } 13470 13471 if ((pg = scf_pg_create(g_hndl)) == NULL || 13472 (prop = scf_property_create(g_hndl)) == NULL || 13473 (iter = scf_iter_create(g_hndl)) == NULL || 13474 (piter = scf_iter_create(g_hndl)) == NULL || 13475 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13476 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 13477 scfdie(); 13478 13479 prnbuf = safe_malloc(max_scf_name_len + 1); 13480 13481 if (cur_level != NULL) 13482 ret = scf_iter_snaplevel_pgs(iter, cur_level); 13483 else if (cur_inst != NULL) 13484 ret = scf_iter_instance_pgs(iter, cur_inst); 13485 else 13486 ret = scf_iter_service_pgs(iter, cur_svc); 13487 if (ret != 0) { 13488 return; 13489 } 13490 13491 /* 13492 * We want to only list items which match pattern, and we want the 13493 * second column to line up, so during the first pass we'll save 13494 * matching items, their names, and their templates in objects, 13495 * names, and tmpls, computing the maximum name length as we go, 13496 * and then we'll print them out. 13497 * 13498 * Note: We always keep an extra slot available so the array can be 13499 * NULL-terminated. 13500 */ 13501 i = 0; 13502 allocd = 1; 13503 objects = safe_malloc(sizeof (*objects)); 13504 names = safe_malloc(sizeof (*names)); 13505 tmpls = safe_malloc(sizeof (*tmpls)); 13506 13507 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13508 int new_pg = 0; 13509 int print_props = 0; 13510 pgtp = NULL; 13511 13512 pgnlen = scf_pg_get_name(pg, NULL, 0); 13513 if (pgnlen < 0) 13514 scfdie(); 13515 13516 pgnbuf = safe_malloc(pgnlen + 1); 13517 13518 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 13519 if (szret < 0) 13520 scfdie(); 13521 assert(szret <= pgnlen); 13522 13523 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) { 13524 if (scf_error() != SCF_ERROR_NOT_FOUND) 13525 scfdie(); 13526 pgtp = NULL; 13527 } else { 13528 pgtp = pgt; 13529 } 13530 13531 if (pattern == NULL || 13532 fnmatch(pattern, pgnbuf, 0) == 0) { 13533 if (i+1 >= allocd) { 13534 allocd *= 2; 13535 objects = realloc(objects, 13536 sizeof (*objects) * allocd); 13537 names = 13538 realloc(names, sizeof (*names) * allocd); 13539 tmpls = realloc(tmpls, 13540 sizeof (*tmpls) * allocd); 13541 if (objects == NULL || names == NULL || 13542 tmpls == NULL) 13543 uu_die(gettext("Out of memory")); 13544 } 13545 objects[i] = pg; 13546 names[i] = pgnbuf; 13547 13548 if (pgtp == NULL) 13549 tmpls[i] = NULL; 13550 else 13551 tmpls[i] = pgt; 13552 13553 ++i; 13554 13555 if (pgnlen > max_len) 13556 max_len = pgnlen; 13557 13558 new_pg = 1; 13559 print_props = 1; 13560 } 13561 13562 if (only_pgs) { 13563 if (new_pg) { 13564 pg = scf_pg_create(g_hndl); 13565 if (pg == NULL) 13566 scfdie(); 13567 pgt = scf_tmpl_pg_create(g_hndl); 13568 if (pgt == NULL) 13569 scfdie(); 13570 } else 13571 free(pgnbuf); 13572 13573 continue; 13574 } 13575 13576 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13577 scfdie(); 13578 13579 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13580 prnlen = scf_property_get_name(prop, prnbuf, 13581 max_scf_name_len + 1); 13582 if (prnlen < 0) 13583 scfdie(); 13584 13585 /* Will prepend the property group name and a slash. */ 13586 prnlen += pgnlen + 1; 13587 13588 ppnbuf = safe_malloc(prnlen + 1); 13589 13590 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13591 prnbuf) < 0) 13592 uu_die("snprintf"); 13593 13594 if (pattern == NULL || print_props == 1 || 13595 fnmatch(pattern, ppnbuf, 0) == 0) { 13596 if (i+1 >= allocd) { 13597 allocd *= 2; 13598 objects = realloc(objects, 13599 sizeof (*objects) * allocd); 13600 names = realloc(names, 13601 sizeof (*names) * allocd); 13602 tmpls = realloc(tmpls, 13603 sizeof (*tmpls) * allocd); 13604 if (objects == NULL || names == NULL || 13605 tmpls == NULL) 13606 uu_die(gettext( 13607 "Out of memory")); 13608 } 13609 13610 objects[i] = prop; 13611 names[i] = ppnbuf; 13612 13613 if (pgtp != NULL) { 13614 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13615 prt, 0) < 0) { 13616 if (scf_error() != 13617 SCF_ERROR_NOT_FOUND) 13618 scfdie(); 13619 tmpls[i] = NULL; 13620 } else { 13621 tmpls[i] = prt; 13622 } 13623 } else { 13624 tmpls[i] = NULL; 13625 } 13626 13627 ++i; 13628 13629 if (prnlen > max_len) 13630 max_len = prnlen; 13631 13632 prop = scf_property_create(g_hndl); 13633 prt = scf_tmpl_prop_create(g_hndl); 13634 } else { 13635 free(ppnbuf); 13636 } 13637 } 13638 13639 if (new_pg) { 13640 pg = scf_pg_create(g_hndl); 13641 if (pg == NULL) 13642 scfdie(); 13643 pgt = scf_tmpl_pg_create(g_hndl); 13644 if (pgt == NULL) 13645 scfdie(); 13646 } else 13647 free(pgnbuf); 13648 } 13649 if (ret != 0) 13650 scfdie(); 13651 13652 objects[i] = NULL; 13653 13654 scf_pg_destroy(pg); 13655 scf_tmpl_pg_destroy(pgt); 13656 scf_property_destroy(prop); 13657 scf_tmpl_prop_destroy(prt); 13658 13659 for (i = 0; objects[i] != NULL; ++i) { 13660 if (strchr(names[i], '/') == NULL) { 13661 /* property group */ 13662 pg = (scf_propertygroup_t *)objects[i]; 13663 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13664 list_pg_info(pg, names[i], max_len); 13665 list_pg_tmpl(pgt, pg, templates); 13666 free(names[i]); 13667 scf_pg_destroy(pg); 13668 if (pgt != NULL) 13669 scf_tmpl_pg_destroy(pgt); 13670 } else { 13671 /* property */ 13672 prop = (scf_property_t *)objects[i]; 13673 prt = (scf_prop_tmpl_t *)tmpls[i]; 13674 list_prop_info(prop, names[i], max_len); 13675 list_prop_tmpl(prt, prop, templates); 13676 free(names[i]); 13677 scf_property_destroy(prop); 13678 if (prt != NULL) 13679 scf_tmpl_prop_destroy(prt); 13680 } 13681 } 13682 13683 free(names); 13684 free(objects); 13685 free(tmpls); 13686 } 13687 13688 void 13689 lscf_listpg(const char *pattern) 13690 { 13691 lscf_prep_hndl(); 13692 13693 listprop(pattern, 1, 0); 13694 } 13695 13696 /* 13697 * Property group and property creation, setting, and deletion. setprop (and 13698 * its alias, addprop) can either create a property group of a given type, or 13699 * it can create or set a property to a given type and list of values. 13700 */ 13701 void 13702 lscf_addpg(const char *name, const char *type, const char *flags) 13703 { 13704 scf_propertygroup_t *pg; 13705 int ret; 13706 uint32_t flgs = 0; 13707 const char *cp; 13708 13709 13710 lscf_prep_hndl(); 13711 13712 if (cur_snap != NULL) { 13713 semerr(emsg_cant_modify_snapshots); 13714 return; 13715 } 13716 13717 if (cur_inst == NULL && cur_svc == NULL) { 13718 semerr(emsg_entity_not_selected); 13719 return; 13720 } 13721 13722 if (flags != NULL) { 13723 for (cp = flags; *cp != '\0'; ++cp) { 13724 switch (*cp) { 13725 case 'P': 13726 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13727 break; 13728 13729 case 'p': 13730 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13731 break; 13732 13733 default: 13734 semerr(gettext("Invalid property group flag " 13735 "%c."), *cp); 13736 return; 13737 } 13738 } 13739 } 13740 13741 pg = scf_pg_create(g_hndl); 13742 if (pg == NULL) 13743 scfdie(); 13744 13745 if (cur_inst != NULL) 13746 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13747 else 13748 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13749 13750 if (ret != SCF_SUCCESS) { 13751 switch (scf_error()) { 13752 case SCF_ERROR_INVALID_ARGUMENT: 13753 semerr(gettext("Name, type, or flags are invalid.\n")); 13754 break; 13755 13756 case SCF_ERROR_EXISTS: 13757 semerr(gettext("Property group already exists.\n")); 13758 break; 13759 13760 case SCF_ERROR_PERMISSION_DENIED: 13761 semerr(emsg_permission_denied); 13762 break; 13763 13764 case SCF_ERROR_BACKEND_ACCESS: 13765 semerr(gettext("Backend refused access.\n")); 13766 break; 13767 13768 default: 13769 scfdie(); 13770 } 13771 } 13772 13773 scf_pg_destroy(pg); 13774 13775 private_refresh(); 13776 } 13777 13778 void 13779 lscf_delpg(char *name) 13780 { 13781 lscf_prep_hndl(); 13782 13783 if (cur_snap != NULL) { 13784 semerr(emsg_cant_modify_snapshots); 13785 return; 13786 } 13787 13788 if (cur_inst == NULL && cur_svc == NULL) { 13789 semerr(emsg_entity_not_selected); 13790 return; 13791 } 13792 13793 if (strchr(name, '/') != NULL) { 13794 semerr(emsg_invalid_pg_name, name); 13795 return; 13796 } 13797 13798 lscf_delprop(name); 13799 } 13800 13801 /* 13802 * scf_delhash() is used to remove the property group related to the 13803 * hash entry for a specific manifest in the repository. pgname will be 13804 * constructed from the location of the manifest file. If deathrow isn't 0, 13805 * manifest file doesn't need to exist (manifest string will be used as 13806 * an absolute path). 13807 */ 13808 void 13809 lscf_delhash(char *manifest, int deathrow) 13810 { 13811 char *pgname; 13812 13813 if (cur_snap != NULL || 13814 cur_inst != NULL || cur_svc != NULL) { 13815 warn(gettext("error, an entity is selected\n")); 13816 return; 13817 } 13818 13819 /* select smf/manifest */ 13820 lscf_select(HASH_SVC); 13821 /* 13822 * Translate the manifest file name to property name. In the deathrow 13823 * case, the manifest file does not need to exist. 13824 */ 13825 pgname = mhash_filename_to_propname(manifest, 13826 deathrow ? B_TRUE : B_FALSE); 13827 if (pgname == NULL) { 13828 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13829 return; 13830 } 13831 /* delete the hash property name */ 13832 lscf_delpg(pgname); 13833 } 13834 13835 void 13836 lscf_listprop(const char *pattern) 13837 { 13838 lscf_prep_hndl(); 13839 13840 listprop(pattern, 0, 0); 13841 } 13842 13843 int 13844 lscf_setprop(const char *pgname, const char *type, const char *value, 13845 const uu_list_t *values) 13846 { 13847 scf_type_t ty, current_ty; 13848 scf_service_t *svc; 13849 scf_propertygroup_t *pg, *parent_pg; 13850 scf_property_t *prop, *parent_prop; 13851 scf_pg_tmpl_t *pgt; 13852 scf_prop_tmpl_t *prt; 13853 int ret, result = 0; 13854 scf_transaction_t *tx; 13855 scf_transaction_entry_t *e; 13856 scf_value_t *v; 13857 uu_list_walk_t *walk; 13858 string_list_t *sp; 13859 char *propname; 13860 int req_quotes = 0; 13861 13862 lscf_prep_hndl(); 13863 13864 if ((e = scf_entry_create(g_hndl)) == NULL || 13865 (svc = scf_service_create(g_hndl)) == NULL || 13866 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13867 (pg = scf_pg_create(g_hndl)) == NULL || 13868 (parent_prop = scf_property_create(g_hndl)) == NULL || 13869 (prop = scf_property_create(g_hndl)) == NULL || 13870 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13871 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13872 (tx = scf_transaction_create(g_hndl)) == NULL) 13873 scfdie(); 13874 13875 if (cur_snap != NULL) { 13876 semerr(emsg_cant_modify_snapshots); 13877 goto fail; 13878 } 13879 13880 if (cur_inst == NULL && cur_svc == NULL) { 13881 semerr(emsg_entity_not_selected); 13882 goto fail; 13883 } 13884 13885 propname = strchr(pgname, '/'); 13886 if (propname == NULL) { 13887 semerr(gettext("Property names must contain a `/'.\n")); 13888 goto fail; 13889 } 13890 13891 *propname = '\0'; 13892 ++propname; 13893 13894 if (type != NULL) { 13895 ty = string_to_type(type); 13896 if (ty == SCF_TYPE_INVALID) { 13897 semerr(gettext("Unknown type \"%s\".\n"), type); 13898 goto fail; 13899 } 13900 } 13901 13902 if (cur_inst != NULL) 13903 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13904 else 13905 ret = scf_service_get_pg(cur_svc, pgname, pg); 13906 if (ret != SCF_SUCCESS) { 13907 switch (scf_error()) { 13908 case SCF_ERROR_NOT_FOUND: 13909 semerr(emsg_no_such_pg, pgname); 13910 goto fail; 13911 13912 case SCF_ERROR_INVALID_ARGUMENT: 13913 semerr(emsg_invalid_pg_name, pgname); 13914 goto fail; 13915 13916 default: 13917 scfdie(); 13918 break; 13919 } 13920 } 13921 13922 do { 13923 if (scf_pg_update(pg) == -1) 13924 scfdie(); 13925 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13926 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13927 scfdie(); 13928 13929 semerr(emsg_permission_denied); 13930 goto fail; 13931 } 13932 13933 ret = scf_pg_get_property(pg, propname, prop); 13934 if (ret == SCF_SUCCESS) { 13935 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13936 scfdie(); 13937 13938 if (type == NULL) 13939 ty = current_ty; 13940 if (scf_transaction_property_change_type(tx, e, 13941 propname, ty) == -1) 13942 scfdie(); 13943 13944 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13945 /* Infer the type, if possible. */ 13946 if (type == NULL) { 13947 /* 13948 * First check if we're an instance and the 13949 * property is set on the service. 13950 */ 13951 if (cur_inst != NULL && 13952 scf_instance_get_parent(cur_inst, 13953 svc) == 0 && 13954 scf_service_get_pg(cur_svc, pgname, 13955 parent_pg) == 0 && 13956 scf_pg_get_property(parent_pg, propname, 13957 parent_prop) == 0 && 13958 scf_property_type(parent_prop, 13959 ¤t_ty) == 0) { 13960 ty = current_ty; 13961 13962 /* Then check for a type set in a template. */ 13963 } else if (scf_tmpl_get_by_pg(pg, pgt, 13964 0) == 0 && 13965 scf_tmpl_get_by_prop(pgt, propname, prt, 13966 0) == 0 && 13967 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13968 ty = current_ty; 13969 13970 /* If type can't be inferred, fail. */ 13971 } else { 13972 semerr(gettext("Type required for new " 13973 "properties.\n")); 13974 goto fail; 13975 } 13976 } 13977 if (scf_transaction_property_new(tx, e, propname, 13978 ty) == -1) 13979 scfdie(); 13980 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13981 semerr(emsg_invalid_prop_name, propname); 13982 goto fail; 13983 } else { 13984 scfdie(); 13985 } 13986 13987 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13988 req_quotes = 1; 13989 13990 if (value != NULL) { 13991 v = string_to_value(value, ty, 0); 13992 13993 if (v == NULL) 13994 goto fail; 13995 13996 ret = scf_entry_add_value(e, v); 13997 assert(ret == SCF_SUCCESS); 13998 } else { 13999 assert(values != NULL); 14000 14001 walk = uu_list_walk_start((uu_list_t *)values, 14002 UU_DEFAULT); 14003 if (walk == NULL) 14004 uu_die(gettext("Could not walk list")); 14005 14006 for (sp = uu_list_walk_next(walk); sp != NULL; 14007 sp = uu_list_walk_next(walk)) { 14008 v = string_to_value(sp->str, ty, req_quotes); 14009 14010 if (v == NULL) { 14011 scf_entry_destroy_children(e); 14012 goto fail; 14013 } 14014 14015 ret = scf_entry_add_value(e, v); 14016 assert(ret == SCF_SUCCESS); 14017 } 14018 uu_list_walk_end(walk); 14019 } 14020 result = scf_transaction_commit(tx); 14021 14022 scf_transaction_reset(tx); 14023 scf_entry_destroy_children(e); 14024 } while (result == 0); 14025 14026 if (result < 0) { 14027 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14028 scfdie(); 14029 14030 semerr(emsg_permission_denied); 14031 goto fail; 14032 } 14033 14034 ret = 0; 14035 14036 private_refresh(); 14037 14038 goto cleanup; 14039 14040 fail: 14041 ret = -1; 14042 14043 cleanup: 14044 scf_transaction_destroy(tx); 14045 scf_entry_destroy(e); 14046 scf_service_destroy(svc); 14047 scf_pg_destroy(parent_pg); 14048 scf_pg_destroy(pg); 14049 scf_property_destroy(parent_prop); 14050 scf_property_destroy(prop); 14051 scf_tmpl_pg_destroy(pgt); 14052 scf_tmpl_prop_destroy(prt); 14053 14054 return (ret); 14055 } 14056 14057 void 14058 lscf_delprop(char *pgn) 14059 { 14060 char *slash, *pn; 14061 scf_propertygroup_t *pg; 14062 scf_transaction_t *tx; 14063 scf_transaction_entry_t *e; 14064 int ret; 14065 14066 14067 lscf_prep_hndl(); 14068 14069 if (cur_snap != NULL) { 14070 semerr(emsg_cant_modify_snapshots); 14071 return; 14072 } 14073 14074 if (cur_inst == NULL && cur_svc == NULL) { 14075 semerr(emsg_entity_not_selected); 14076 return; 14077 } 14078 14079 pg = scf_pg_create(g_hndl); 14080 if (pg == NULL) 14081 scfdie(); 14082 14083 slash = strchr(pgn, '/'); 14084 if (slash == NULL) { 14085 pn = NULL; 14086 } else { 14087 *slash = '\0'; 14088 pn = slash + 1; 14089 } 14090 14091 if (cur_inst != NULL) 14092 ret = scf_instance_get_pg(cur_inst, pgn, pg); 14093 else 14094 ret = scf_service_get_pg(cur_svc, pgn, pg); 14095 if (ret != SCF_SUCCESS) { 14096 switch (scf_error()) { 14097 case SCF_ERROR_NOT_FOUND: 14098 semerr(emsg_no_such_pg, pgn); 14099 break; 14100 14101 case SCF_ERROR_INVALID_ARGUMENT: 14102 semerr(emsg_invalid_pg_name, pgn); 14103 break; 14104 14105 default: 14106 scfdie(); 14107 } 14108 14109 scf_pg_destroy(pg); 14110 14111 return; 14112 } 14113 14114 if (pn == NULL) { 14115 /* Try to delete the property group. */ 14116 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14117 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14118 scfdie(); 14119 14120 semerr(emsg_permission_denied); 14121 } else { 14122 private_refresh(); 14123 } 14124 14125 scf_pg_destroy(pg); 14126 return; 14127 } 14128 14129 e = scf_entry_create(g_hndl); 14130 tx = scf_transaction_create(g_hndl); 14131 14132 do { 14133 if (scf_pg_update(pg) == -1) 14134 scfdie(); 14135 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 14136 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14137 scfdie(); 14138 14139 semerr(emsg_permission_denied); 14140 break; 14141 } 14142 14143 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 14144 if (scf_error() == SCF_ERROR_NOT_FOUND) { 14145 semerr(gettext("No such property %s/%s.\n"), 14146 pgn, pn); 14147 break; 14148 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14149 semerr(emsg_invalid_prop_name, pn); 14150 break; 14151 } else { 14152 scfdie(); 14153 } 14154 } 14155 14156 ret = scf_transaction_commit(tx); 14157 14158 if (ret == 0) 14159 scf_transaction_reset(tx); 14160 } while (ret == 0); 14161 14162 if (ret < 0) { 14163 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14164 scfdie(); 14165 14166 semerr(emsg_permission_denied); 14167 } else { 14168 private_refresh(); 14169 } 14170 14171 scf_transaction_destroy(tx); 14172 scf_entry_destroy(e); 14173 scf_pg_destroy(pg); 14174 } 14175 14176 /* 14177 * Property editing. 14178 */ 14179 14180 static int 14181 write_edit_script(FILE *strm) 14182 { 14183 char *fmribuf; 14184 ssize_t fmrilen; 14185 14186 scf_propertygroup_t *pg; 14187 scf_property_t *prop; 14188 scf_value_t *val; 14189 scf_type_t ty; 14190 int ret, result = 0; 14191 scf_iter_t *iter, *piter, *viter; 14192 char *buf, *tybuf, *pname; 14193 const char *emsg_write_error; 14194 14195 14196 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 14197 14198 14199 /* select fmri */ 14200 if (cur_inst != NULL) { 14201 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 14202 if (fmrilen < 0) 14203 scfdie(); 14204 fmribuf = safe_malloc(fmrilen + 1); 14205 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 14206 scfdie(); 14207 } else { 14208 assert(cur_svc != NULL); 14209 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 14210 if (fmrilen < 0) 14211 scfdie(); 14212 fmribuf = safe_malloc(fmrilen + 1); 14213 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 14214 scfdie(); 14215 } 14216 14217 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 14218 warn(emsg_write_error, strerror(errno)); 14219 free(fmribuf); 14220 return (-1); 14221 } 14222 14223 free(fmribuf); 14224 14225 14226 if ((pg = scf_pg_create(g_hndl)) == NULL || 14227 (prop = scf_property_create(g_hndl)) == NULL || 14228 (val = scf_value_create(g_hndl)) == NULL || 14229 (iter = scf_iter_create(g_hndl)) == NULL || 14230 (piter = scf_iter_create(g_hndl)) == NULL || 14231 (viter = scf_iter_create(g_hndl)) == NULL) 14232 scfdie(); 14233 14234 buf = safe_malloc(max_scf_name_len + 1); 14235 tybuf = safe_malloc(max_scf_pg_type_len + 1); 14236 pname = safe_malloc(max_scf_name_len + 1); 14237 14238 if (cur_inst != NULL) 14239 ret = scf_iter_instance_pgs(iter, cur_inst); 14240 else 14241 ret = scf_iter_service_pgs(iter, cur_svc); 14242 if (ret != SCF_SUCCESS) 14243 scfdie(); 14244 14245 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 14246 int ret2; 14247 14248 /* 14249 * # delprop pg 14250 * # addpg pg type 14251 */ 14252 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 14253 scfdie(); 14254 14255 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 14256 scfdie(); 14257 14258 if (fprintf(strm, "# Property group \"%s\"\n" 14259 "# delprop %s\n" 14260 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 14261 warn(emsg_write_error, strerror(errno)); 14262 result = -1; 14263 goto out; 14264 } 14265 14266 /* # setprop pg/prop = (values) */ 14267 14268 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 14269 scfdie(); 14270 14271 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 14272 int first = 1; 14273 int ret3; 14274 int multiple; 14275 int is_str; 14276 scf_type_t bty; 14277 14278 if (scf_property_get_name(prop, pname, 14279 max_scf_name_len + 1) < 0) 14280 scfdie(); 14281 14282 if (scf_property_type(prop, &ty) != 0) 14283 scfdie(); 14284 14285 multiple = prop_has_multiple_values(prop, val); 14286 14287 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 14288 pname, scf_type_to_string(ty), multiple ? "(" : "") 14289 < 0) { 14290 warn(emsg_write_error, strerror(errno)); 14291 result = -1; 14292 goto out; 14293 } 14294 14295 (void) scf_type_base_type(ty, &bty); 14296 is_str = (bty == SCF_TYPE_ASTRING); 14297 14298 if (scf_iter_property_values(viter, prop) != 14299 SCF_SUCCESS) 14300 scfdie(); 14301 14302 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 14303 char *buf; 14304 ssize_t buflen; 14305 14306 buflen = scf_value_get_as_string(val, NULL, 0); 14307 if (buflen < 0) 14308 scfdie(); 14309 14310 buf = safe_malloc(buflen + 1); 14311 14312 if (scf_value_get_as_string(val, buf, 14313 buflen + 1) < 0) 14314 scfdie(); 14315 14316 if (first) 14317 first = 0; 14318 else { 14319 if (putc(' ', strm) != ' ') { 14320 warn(emsg_write_error, 14321 strerror(errno)); 14322 result = -1; 14323 goto out; 14324 } 14325 } 14326 14327 if ((is_str && multiple) || 14328 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 14329 (void) putc('"', strm); 14330 (void) quote_and_print(buf, strm, 1); 14331 (void) putc('"', strm); 14332 14333 if (ferror(strm)) { 14334 warn(emsg_write_error, 14335 strerror(errno)); 14336 result = -1; 14337 goto out; 14338 } 14339 } else { 14340 if (fprintf(strm, "%s", buf) < 0) { 14341 warn(emsg_write_error, 14342 strerror(errno)); 14343 result = -1; 14344 goto out; 14345 } 14346 } 14347 14348 free(buf); 14349 } 14350 if (ret3 < 0 && 14351 scf_error() != SCF_ERROR_PERMISSION_DENIED) 14352 scfdie(); 14353 14354 /* Write closing paren if mult-value property */ 14355 if ((multiple && putc(')', strm) == EOF) || 14356 14357 /* Write final newline */ 14358 fputc('\n', strm) == EOF) { 14359 warn(emsg_write_error, strerror(errno)); 14360 result = -1; 14361 goto out; 14362 } 14363 } 14364 if (ret2 < 0) 14365 scfdie(); 14366 14367 if (fputc('\n', strm) == EOF) { 14368 warn(emsg_write_error, strerror(errno)); 14369 result = -1; 14370 goto out; 14371 } 14372 } 14373 if (ret < 0) 14374 scfdie(); 14375 14376 out: 14377 free(pname); 14378 free(tybuf); 14379 free(buf); 14380 scf_iter_destroy(viter); 14381 scf_iter_destroy(piter); 14382 scf_iter_destroy(iter); 14383 scf_value_destroy(val); 14384 scf_property_destroy(prop); 14385 scf_pg_destroy(pg); 14386 14387 if (result == 0) { 14388 if (fflush(strm) != 0) { 14389 warn(emsg_write_error, strerror(errno)); 14390 return (-1); 14391 } 14392 } 14393 14394 return (result); 14395 } 14396 14397 int 14398 lscf_editprop(void) 14399 { 14400 char *buf, *editor; 14401 size_t bufsz; 14402 int tmpfd; 14403 char tempname[] = TEMP_FILE_PATTERN; 14404 14405 lscf_prep_hndl(); 14406 14407 if (cur_snap != NULL) { 14408 semerr(emsg_cant_modify_snapshots); 14409 return (-1); 14410 } 14411 14412 if (cur_svc == NULL && cur_inst == NULL) { 14413 semerr(emsg_entity_not_selected); 14414 return (-1); 14415 } 14416 14417 tmpfd = mkstemp(tempname); 14418 if (tmpfd == -1) { 14419 semerr(gettext("Could not create temporary file.\n")); 14420 return (-1); 14421 } 14422 14423 (void) strcpy(tempfilename, tempname); 14424 14425 tempfile = fdopen(tmpfd, "r+"); 14426 if (tempfile == NULL) { 14427 warn(gettext("Could not create temporary file.\n")); 14428 if (close(tmpfd) == -1) 14429 warn(gettext("Could not close temporary file: %s.\n"), 14430 strerror(errno)); 14431 14432 remove_tempfile(); 14433 14434 return (-1); 14435 } 14436 14437 if (write_edit_script(tempfile) == -1) { 14438 remove_tempfile(); 14439 return (-1); 14440 } 14441 14442 editor = getenv("EDITOR"); 14443 if (editor == NULL) 14444 editor = "vi"; 14445 14446 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 14447 buf = safe_malloc(bufsz); 14448 14449 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 14450 uu_die(gettext("Error creating editor command")); 14451 14452 if (system(buf) == -1) { 14453 semerr(gettext("Could not launch editor %s: %s\n"), editor, 14454 strerror(errno)); 14455 free(buf); 14456 remove_tempfile(); 14457 return (-1); 14458 } 14459 14460 free(buf); 14461 14462 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 14463 14464 remove_tempfile(); 14465 14466 return (0); 14467 } 14468 14469 static void 14470 add_string(uu_list_t *strlist, const char *str) 14471 { 14472 string_list_t *elem; 14473 elem = safe_malloc(sizeof (*elem)); 14474 uu_list_node_init(elem, &elem->node, string_pool); 14475 elem->str = safe_strdup(str); 14476 if (uu_list_append(strlist, elem) != 0) 14477 uu_die(gettext("libuutil error: %s\n"), 14478 uu_strerror(uu_error())); 14479 } 14480 14481 static int 14482 remove_string(uu_list_t *strlist, const char *str) 14483 { 14484 uu_list_walk_t *elems; 14485 string_list_t *sp; 14486 14487 /* 14488 * Find the element that needs to be removed. 14489 */ 14490 elems = uu_list_walk_start(strlist, UU_DEFAULT); 14491 while ((sp = uu_list_walk_next(elems)) != NULL) { 14492 if (strcmp(sp->str, str) == 0) 14493 break; 14494 } 14495 uu_list_walk_end(elems); 14496 14497 /* 14498 * Returning 1 here as the value was not found, this 14499 * might not be an error. Leave it to the caller to 14500 * decide. 14501 */ 14502 if (sp == NULL) { 14503 return (1); 14504 } 14505 14506 uu_list_remove(strlist, sp); 14507 14508 free(sp->str); 14509 free(sp); 14510 14511 return (0); 14512 } 14513 14514 /* 14515 * Get all property values that don't match the given glob pattern, 14516 * if a pattern is specified. 14517 */ 14518 static void 14519 get_prop_values(scf_property_t *prop, uu_list_t *values, 14520 const char *pattern) 14521 { 14522 scf_iter_t *iter; 14523 scf_value_t *val; 14524 int ret; 14525 14526 if ((iter = scf_iter_create(g_hndl)) == NULL || 14527 (val = scf_value_create(g_hndl)) == NULL) 14528 scfdie(); 14529 14530 if (scf_iter_property_values(iter, prop) != 0) 14531 scfdie(); 14532 14533 while ((ret = scf_iter_next_value(iter, val)) == 1) { 14534 char *buf; 14535 ssize_t vlen, szret; 14536 14537 vlen = scf_value_get_as_string(val, NULL, 0); 14538 if (vlen < 0) 14539 scfdie(); 14540 14541 buf = safe_malloc(vlen + 1); 14542 14543 szret = scf_value_get_as_string(val, buf, vlen + 1); 14544 if (szret < 0) 14545 scfdie(); 14546 assert(szret <= vlen); 14547 14548 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 14549 add_string(values, buf); 14550 14551 free(buf); 14552 } 14553 14554 if (ret == -1) 14555 scfdie(); 14556 14557 scf_value_destroy(val); 14558 scf_iter_destroy(iter); 14559 } 14560 14561 static int 14562 lscf_setpropvalue(const char *pgname, const char *type, 14563 const char *arg, int isadd, int isnotfoundok) 14564 { 14565 scf_type_t ty; 14566 scf_propertygroup_t *pg; 14567 scf_property_t *prop; 14568 int ret, result = 0; 14569 scf_transaction_t *tx; 14570 scf_transaction_entry_t *e; 14571 scf_value_t *v; 14572 string_list_t *sp; 14573 char *propname; 14574 uu_list_t *values; 14575 uu_list_walk_t *walk; 14576 void *cookie = NULL; 14577 char *pattern = NULL; 14578 14579 lscf_prep_hndl(); 14580 14581 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14582 uu_die(gettext("Could not create property list: %s\n"), 14583 uu_strerror(uu_error())); 14584 14585 if (!isadd) 14586 pattern = safe_strdup(arg); 14587 14588 if ((e = scf_entry_create(g_hndl)) == NULL || 14589 (pg = scf_pg_create(g_hndl)) == NULL || 14590 (prop = scf_property_create(g_hndl)) == NULL || 14591 (tx = scf_transaction_create(g_hndl)) == NULL) 14592 scfdie(); 14593 14594 if (cur_snap != NULL) { 14595 semerr(emsg_cant_modify_snapshots); 14596 goto fail; 14597 } 14598 14599 if (cur_inst == NULL && cur_svc == NULL) { 14600 semerr(emsg_entity_not_selected); 14601 goto fail; 14602 } 14603 14604 propname = strchr(pgname, '/'); 14605 if (propname == NULL) { 14606 semerr(gettext("Property names must contain a `/'.\n")); 14607 goto fail; 14608 } 14609 14610 *propname = '\0'; 14611 ++propname; 14612 14613 if (type != NULL) { 14614 ty = string_to_type(type); 14615 if (ty == SCF_TYPE_INVALID) { 14616 semerr(gettext("Unknown type \"%s\".\n"), type); 14617 goto fail; 14618 } 14619 } 14620 14621 if (cur_inst != NULL) 14622 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14623 else 14624 ret = scf_service_get_pg(cur_svc, pgname, pg); 14625 if (ret != 0) { 14626 switch (scf_error()) { 14627 case SCF_ERROR_NOT_FOUND: 14628 if (isnotfoundok) { 14629 result = 0; 14630 } else { 14631 semerr(emsg_no_such_pg, pgname); 14632 result = -1; 14633 } 14634 goto out; 14635 14636 case SCF_ERROR_INVALID_ARGUMENT: 14637 semerr(emsg_invalid_pg_name, pgname); 14638 goto fail; 14639 14640 default: 14641 scfdie(); 14642 } 14643 } 14644 14645 do { 14646 if (scf_pg_update(pg) == -1) 14647 scfdie(); 14648 if (scf_transaction_start(tx, pg) != 0) { 14649 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14650 scfdie(); 14651 14652 semerr(emsg_permission_denied); 14653 goto fail; 14654 } 14655 14656 ret = scf_pg_get_property(pg, propname, prop); 14657 if (ret == 0) { 14658 scf_type_t ptype; 14659 char *pat = pattern; 14660 14661 if (scf_property_type(prop, &ptype) != 0) 14662 scfdie(); 14663 14664 if (isadd) { 14665 if (type != NULL && ptype != ty) { 14666 semerr(gettext("Property \"%s\" is not " 14667 "of type \"%s\".\n"), propname, 14668 type); 14669 goto fail; 14670 } 14671 14672 pat = NULL; 14673 } else { 14674 size_t len = strlen(pat); 14675 if (len > 0 && pat[len - 1] == '\"') 14676 pat[len - 1] = '\0'; 14677 if (len > 0 && pat[0] == '\"') 14678 pat++; 14679 } 14680 14681 ty = ptype; 14682 14683 get_prop_values(prop, values, pat); 14684 14685 if (isadd) 14686 add_string(values, arg); 14687 14688 if (scf_transaction_property_change(tx, e, 14689 propname, ty) == -1) 14690 scfdie(); 14691 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14692 if (isadd) { 14693 if (type == NULL) { 14694 semerr(gettext("Type required " 14695 "for new properties.\n")); 14696 goto fail; 14697 } 14698 14699 add_string(values, arg); 14700 14701 if (scf_transaction_property_new(tx, e, 14702 propname, ty) == -1) 14703 scfdie(); 14704 } else if (isnotfoundok) { 14705 result = 0; 14706 goto out; 14707 } else { 14708 semerr(gettext("No such property %s/%s.\n"), 14709 pgname, propname); 14710 result = -1; 14711 goto out; 14712 } 14713 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14714 semerr(emsg_invalid_prop_name, propname); 14715 goto fail; 14716 } else { 14717 scfdie(); 14718 } 14719 14720 walk = uu_list_walk_start(values, UU_DEFAULT); 14721 if (walk == NULL) 14722 uu_die(gettext("Could not walk property list.\n")); 14723 14724 for (sp = uu_list_walk_next(walk); sp != NULL; 14725 sp = uu_list_walk_next(walk)) { 14726 v = string_to_value(sp->str, ty, 0); 14727 14728 if (v == NULL) { 14729 scf_entry_destroy_children(e); 14730 goto fail; 14731 } 14732 ret = scf_entry_add_value(e, v); 14733 assert(ret == 0); 14734 } 14735 uu_list_walk_end(walk); 14736 14737 result = scf_transaction_commit(tx); 14738 14739 scf_transaction_reset(tx); 14740 scf_entry_destroy_children(e); 14741 } while (result == 0); 14742 14743 if (result < 0) { 14744 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14745 scfdie(); 14746 14747 semerr(emsg_permission_denied); 14748 goto fail; 14749 } 14750 14751 result = 0; 14752 14753 private_refresh(); 14754 14755 out: 14756 scf_transaction_destroy(tx); 14757 scf_entry_destroy(e); 14758 scf_pg_destroy(pg); 14759 scf_property_destroy(prop); 14760 free(pattern); 14761 14762 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14763 free(sp->str); 14764 free(sp); 14765 } 14766 14767 uu_list_destroy(values); 14768 14769 return (result); 14770 14771 fail: 14772 result = -1; 14773 goto out; 14774 } 14775 14776 int 14777 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14778 { 14779 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14780 } 14781 14782 int 14783 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14784 { 14785 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14786 } 14787 14788 /* 14789 * Look for a standard start method, first in the instance (if any), 14790 * then the service. 14791 */ 14792 static const char * 14793 start_method_name(int *in_instance) 14794 { 14795 scf_propertygroup_t *pg; 14796 char **p; 14797 int ret; 14798 scf_instance_t *inst = cur_inst; 14799 14800 if ((pg = scf_pg_create(g_hndl)) == NULL) 14801 scfdie(); 14802 14803 again: 14804 for (p = start_method_names; *p != NULL; p++) { 14805 if (inst != NULL) 14806 ret = scf_instance_get_pg(inst, *p, pg); 14807 else 14808 ret = scf_service_get_pg(cur_svc, *p, pg); 14809 14810 if (ret == 0) { 14811 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14812 char *buf = safe_malloc(bufsz); 14813 14814 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14815 free(buf); 14816 continue; 14817 } 14818 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14819 free(buf); 14820 continue; 14821 } 14822 14823 free(buf); 14824 *in_instance = (inst != NULL); 14825 scf_pg_destroy(pg); 14826 return (*p); 14827 } 14828 14829 if (scf_error() == SCF_ERROR_NOT_FOUND) 14830 continue; 14831 14832 scfdie(); 14833 } 14834 14835 if (inst != NULL) { 14836 inst = NULL; 14837 goto again; 14838 } 14839 14840 scf_pg_destroy(pg); 14841 return (NULL); 14842 } 14843 14844 static int 14845 addpg(const char *name, const char *type) 14846 { 14847 scf_propertygroup_t *pg; 14848 int ret; 14849 14850 pg = scf_pg_create(g_hndl); 14851 if (pg == NULL) 14852 scfdie(); 14853 14854 if (cur_inst != NULL) 14855 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14856 else 14857 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14858 14859 if (ret != 0) { 14860 switch (scf_error()) { 14861 case SCF_ERROR_EXISTS: 14862 ret = 0; 14863 break; 14864 14865 case SCF_ERROR_PERMISSION_DENIED: 14866 semerr(emsg_permission_denied); 14867 break; 14868 14869 default: 14870 scfdie(); 14871 } 14872 } 14873 14874 scf_pg_destroy(pg); 14875 return (ret); 14876 } 14877 14878 int 14879 lscf_setenv(uu_list_t *args, int isunset) 14880 { 14881 int ret = 0; 14882 size_t i; 14883 int argc; 14884 char **argv = NULL; 14885 string_list_t *slp; 14886 char *pattern; 14887 char *prop; 14888 int do_service = 0; 14889 int do_instance = 0; 14890 const char *method = NULL; 14891 const char *name = NULL; 14892 const char *value = NULL; 14893 scf_instance_t *saved_cur_inst = cur_inst; 14894 14895 lscf_prep_hndl(); 14896 14897 argc = uu_list_numnodes(args); 14898 if (argc < 1) 14899 goto usage; 14900 14901 argv = calloc(argc + 1, sizeof (char *)); 14902 if (argv == NULL) 14903 uu_die(gettext("Out of memory.\n")); 14904 14905 for (slp = uu_list_first(args), i = 0; 14906 slp != NULL; 14907 slp = uu_list_next(args, slp), ++i) 14908 argv[i] = slp->str; 14909 14910 argv[i] = NULL; 14911 14912 opterr = 0; 14913 optind = 0; 14914 for (;;) { 14915 ret = getopt(argc, argv, "sim:"); 14916 if (ret == -1) 14917 break; 14918 14919 switch (ret) { 14920 case 's': 14921 do_service = 1; 14922 cur_inst = NULL; 14923 break; 14924 14925 case 'i': 14926 do_instance = 1; 14927 break; 14928 14929 case 'm': 14930 method = optarg; 14931 break; 14932 14933 case '?': 14934 goto usage; 14935 14936 default: 14937 bad_error("getopt", ret); 14938 } 14939 } 14940 14941 argc -= optind; 14942 if ((do_service && do_instance) || 14943 (isunset && argc != 1) || 14944 (!isunset && argc != 2)) 14945 goto usage; 14946 14947 name = argv[optind]; 14948 if (!isunset) 14949 value = argv[optind + 1]; 14950 14951 if (cur_snap != NULL) { 14952 semerr(emsg_cant_modify_snapshots); 14953 ret = -1; 14954 goto out; 14955 } 14956 14957 if (cur_inst == NULL && cur_svc == NULL) { 14958 semerr(emsg_entity_not_selected); 14959 ret = -1; 14960 goto out; 14961 } 14962 14963 if (do_instance && cur_inst == NULL) { 14964 semerr(gettext("No instance is selected.\n")); 14965 ret = -1; 14966 goto out; 14967 } 14968 14969 if (do_service && cur_svc == NULL) { 14970 semerr(gettext("No service is selected.\n")); 14971 ret = -1; 14972 goto out; 14973 } 14974 14975 if (method == NULL) { 14976 if (do_instance || do_service) { 14977 method = "method_context"; 14978 if (!isunset) { 14979 ret = addpg("method_context", 14980 SCF_GROUP_FRAMEWORK); 14981 if (ret != 0) 14982 goto out; 14983 } 14984 } else { 14985 int in_instance; 14986 method = start_method_name(&in_instance); 14987 if (method == NULL) { 14988 semerr(gettext( 14989 "Couldn't find start method; please " 14990 "specify a method with '-m'.\n")); 14991 ret = -1; 14992 goto out; 14993 } 14994 if (!in_instance) 14995 cur_inst = NULL; 14996 } 14997 } else { 14998 scf_propertygroup_t *pg; 14999 size_t bufsz; 15000 char *buf; 15001 int ret; 15002 15003 if ((pg = scf_pg_create(g_hndl)) == NULL) 15004 scfdie(); 15005 15006 if (cur_inst != NULL) 15007 ret = scf_instance_get_pg(cur_inst, method, pg); 15008 else 15009 ret = scf_service_get_pg(cur_svc, method, pg); 15010 15011 if (ret != 0) { 15012 scf_pg_destroy(pg); 15013 switch (scf_error()) { 15014 case SCF_ERROR_NOT_FOUND: 15015 semerr(gettext("Couldn't find the method " 15016 "\"%s\".\n"), method); 15017 goto out; 15018 15019 case SCF_ERROR_INVALID_ARGUMENT: 15020 semerr(gettext("Invalid method name \"%s\".\n"), 15021 method); 15022 goto out; 15023 15024 default: 15025 scfdie(); 15026 } 15027 } 15028 15029 bufsz = strlen(SCF_GROUP_METHOD) + 1; 15030 buf = safe_malloc(bufsz); 15031 15032 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 15033 strcmp(buf, SCF_GROUP_METHOD) != 0) { 15034 semerr(gettext("Property group \"%s\" is not of type " 15035 "\"method\".\n"), method); 15036 ret = -1; 15037 free(buf); 15038 scf_pg_destroy(pg); 15039 goto out; 15040 } 15041 15042 free(buf); 15043 scf_pg_destroy(pg); 15044 } 15045 15046 prop = uu_msprintf("%s/environment", method); 15047 pattern = uu_msprintf("%s=*", name); 15048 15049 if (prop == NULL || pattern == NULL) 15050 uu_die(gettext("Out of memory.\n")); 15051 15052 ret = lscf_delpropvalue(prop, pattern, !isunset); 15053 15054 if (ret == 0 && !isunset) { 15055 uu_free(pattern); 15056 uu_free(prop); 15057 prop = uu_msprintf("%s/environment", method); 15058 pattern = uu_msprintf("%s=%s", name, value); 15059 if (prop == NULL || pattern == NULL) 15060 uu_die(gettext("Out of memory.\n")); 15061 ret = lscf_addpropvalue(prop, "astring:", pattern); 15062 } 15063 uu_free(pattern); 15064 uu_free(prop); 15065 15066 out: 15067 cur_inst = saved_cur_inst; 15068 15069 free(argv); 15070 return (ret); 15071 usage: 15072 ret = -2; 15073 goto out; 15074 } 15075 15076 /* 15077 * Snapshot commands 15078 */ 15079 15080 void 15081 lscf_listsnap() 15082 { 15083 scf_snapshot_t *snap; 15084 scf_iter_t *iter; 15085 char *nb; 15086 int r; 15087 15088 lscf_prep_hndl(); 15089 15090 if (cur_inst == NULL) { 15091 semerr(gettext("Instance not selected.\n")); 15092 return; 15093 } 15094 15095 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15096 (iter = scf_iter_create(g_hndl)) == NULL) 15097 scfdie(); 15098 15099 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 15100 scfdie(); 15101 15102 nb = safe_malloc(max_scf_name_len + 1); 15103 15104 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 15105 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 15106 scfdie(); 15107 15108 (void) puts(nb); 15109 } 15110 if (r < 0) 15111 scfdie(); 15112 15113 free(nb); 15114 scf_iter_destroy(iter); 15115 scf_snapshot_destroy(snap); 15116 } 15117 15118 void 15119 lscf_selectsnap(const char *name) 15120 { 15121 scf_snapshot_t *snap; 15122 scf_snaplevel_t *level; 15123 15124 lscf_prep_hndl(); 15125 15126 if (cur_inst == NULL) { 15127 semerr(gettext("Instance not selected.\n")); 15128 return; 15129 } 15130 15131 if (cur_snap != NULL) { 15132 if (name != NULL) { 15133 char *cur_snap_name; 15134 boolean_t nochange; 15135 15136 cur_snap_name = safe_malloc(max_scf_name_len + 1); 15137 15138 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 15139 max_scf_name_len + 1) < 0) 15140 scfdie(); 15141 15142 nochange = strcmp(name, cur_snap_name) == 0; 15143 15144 free(cur_snap_name); 15145 15146 if (nochange) 15147 return; 15148 } 15149 15150 unselect_cursnap(); 15151 } 15152 15153 if (name == NULL) 15154 return; 15155 15156 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15157 (level = scf_snaplevel_create(g_hndl)) == NULL) 15158 scfdie(); 15159 15160 if (scf_instance_get_snapshot(cur_inst, name, snap) != 15161 SCF_SUCCESS) { 15162 switch (scf_error()) { 15163 case SCF_ERROR_INVALID_ARGUMENT: 15164 semerr(gettext("Invalid name \"%s\".\n"), name); 15165 break; 15166 15167 case SCF_ERROR_NOT_FOUND: 15168 semerr(gettext("No such snapshot \"%s\".\n"), name); 15169 break; 15170 15171 default: 15172 scfdie(); 15173 } 15174 15175 scf_snaplevel_destroy(level); 15176 scf_snapshot_destroy(snap); 15177 return; 15178 } 15179 15180 /* Load the snaplevels into our list. */ 15181 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 15182 if (cur_levels == NULL) 15183 uu_die(gettext("Could not create list: %s\n"), 15184 uu_strerror(uu_error())); 15185 15186 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15187 if (scf_error() != SCF_ERROR_NOT_FOUND) 15188 scfdie(); 15189 15190 semerr(gettext("Snapshot has no snaplevels.\n")); 15191 15192 scf_snaplevel_destroy(level); 15193 scf_snapshot_destroy(snap); 15194 return; 15195 } 15196 15197 cur_snap = snap; 15198 15199 for (;;) { 15200 cur_elt = safe_malloc(sizeof (*cur_elt)); 15201 uu_list_node_init(cur_elt, &cur_elt->list_node, 15202 snaplevel_pool); 15203 cur_elt->sl = level; 15204 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 15205 uu_die(gettext("libuutil error: %s\n"), 15206 uu_strerror(uu_error())); 15207 15208 level = scf_snaplevel_create(g_hndl); 15209 if (level == NULL) 15210 scfdie(); 15211 15212 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 15213 level) != SCF_SUCCESS) { 15214 if (scf_error() != SCF_ERROR_NOT_FOUND) 15215 scfdie(); 15216 15217 scf_snaplevel_destroy(level); 15218 break; 15219 } 15220 } 15221 15222 cur_elt = uu_list_last(cur_levels); 15223 cur_level = cur_elt->sl; 15224 } 15225 15226 /* 15227 * Copies the properties & values in src to dst. Assumes src won't change. 15228 * Returns -1 if permission is denied, -2 if another transaction interrupts, 15229 * and 0 on success. 15230 * 15231 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 15232 * property, if it is copied and has type boolean. (See comment in 15233 * lscf_revert()). 15234 */ 15235 static int 15236 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 15237 uint8_t enabled) 15238 { 15239 scf_transaction_t *tx; 15240 scf_iter_t *iter, *viter; 15241 scf_property_t *prop; 15242 scf_value_t *v; 15243 char *nbuf; 15244 int r; 15245 15246 tx = scf_transaction_create(g_hndl); 15247 if (tx == NULL) 15248 scfdie(); 15249 15250 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 15251 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15252 scfdie(); 15253 15254 scf_transaction_destroy(tx); 15255 15256 return (-1); 15257 } 15258 15259 if ((iter = scf_iter_create(g_hndl)) == NULL || 15260 (prop = scf_property_create(g_hndl)) == NULL || 15261 (viter = scf_iter_create(g_hndl)) == NULL) 15262 scfdie(); 15263 15264 nbuf = safe_malloc(max_scf_name_len + 1); 15265 15266 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 15267 scfdie(); 15268 15269 for (;;) { 15270 scf_transaction_entry_t *e; 15271 scf_type_t ty; 15272 15273 r = scf_iter_next_property(iter, prop); 15274 if (r == -1) 15275 scfdie(); 15276 if (r == 0) 15277 break; 15278 15279 e = scf_entry_create(g_hndl); 15280 if (e == NULL) 15281 scfdie(); 15282 15283 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 15284 scfdie(); 15285 15286 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 15287 scfdie(); 15288 15289 if (scf_transaction_property_new(tx, e, nbuf, 15290 ty) != SCF_SUCCESS) 15291 scfdie(); 15292 15293 if ((enabled == 0 || enabled == 1) && 15294 strcmp(nbuf, scf_property_enabled) == 0 && 15295 ty == SCF_TYPE_BOOLEAN) { 15296 v = scf_value_create(g_hndl); 15297 if (v == NULL) 15298 scfdie(); 15299 15300 scf_value_set_boolean(v, enabled); 15301 15302 if (scf_entry_add_value(e, v) != 0) 15303 scfdie(); 15304 } else { 15305 if (scf_iter_property_values(viter, prop) != 0) 15306 scfdie(); 15307 15308 for (;;) { 15309 v = scf_value_create(g_hndl); 15310 if (v == NULL) 15311 scfdie(); 15312 15313 r = scf_iter_next_value(viter, v); 15314 if (r == -1) 15315 scfdie(); 15316 if (r == 0) { 15317 scf_value_destroy(v); 15318 break; 15319 } 15320 15321 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 15322 scfdie(); 15323 } 15324 } 15325 } 15326 15327 free(nbuf); 15328 scf_iter_destroy(viter); 15329 scf_property_destroy(prop); 15330 scf_iter_destroy(iter); 15331 15332 r = scf_transaction_commit(tx); 15333 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 15334 scfdie(); 15335 15336 scf_transaction_destroy_children(tx); 15337 scf_transaction_destroy(tx); 15338 15339 switch (r) { 15340 case 1: return (0); 15341 case 0: return (-2); 15342 case -1: return (-1); 15343 15344 default: 15345 abort(); 15346 } 15347 15348 /* NOTREACHED */ 15349 } 15350 15351 void 15352 lscf_revert(const char *snapname) 15353 { 15354 scf_snapshot_t *snap, *prev; 15355 scf_snaplevel_t *level, *nlevel; 15356 scf_iter_t *iter; 15357 scf_propertygroup_t *pg, *npg; 15358 scf_property_t *prop; 15359 scf_value_t *val; 15360 char *nbuf, *tbuf; 15361 uint8_t enabled; 15362 15363 lscf_prep_hndl(); 15364 15365 if (cur_inst == NULL) { 15366 semerr(gettext("Instance not selected.\n")); 15367 return; 15368 } 15369 15370 if (snapname != NULL) { 15371 snap = scf_snapshot_create(g_hndl); 15372 if (snap == NULL) 15373 scfdie(); 15374 15375 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 15376 SCF_SUCCESS) { 15377 switch (scf_error()) { 15378 case SCF_ERROR_INVALID_ARGUMENT: 15379 semerr(gettext("Invalid snapshot name " 15380 "\"%s\".\n"), snapname); 15381 break; 15382 15383 case SCF_ERROR_NOT_FOUND: 15384 semerr(gettext("No such snapshot.\n")); 15385 break; 15386 15387 default: 15388 scfdie(); 15389 } 15390 15391 scf_snapshot_destroy(snap); 15392 return; 15393 } 15394 } else { 15395 if (cur_snap != NULL) { 15396 snap = cur_snap; 15397 } else { 15398 semerr(gettext("No snapshot selected.\n")); 15399 return; 15400 } 15401 } 15402 15403 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 15404 (level = scf_snaplevel_create(g_hndl)) == NULL || 15405 (iter = scf_iter_create(g_hndl)) == NULL || 15406 (pg = scf_pg_create(g_hndl)) == NULL || 15407 (npg = scf_pg_create(g_hndl)) == NULL || 15408 (prop = scf_property_create(g_hndl)) == NULL || 15409 (val = scf_value_create(g_hndl)) == NULL) 15410 scfdie(); 15411 15412 nbuf = safe_malloc(max_scf_name_len + 1); 15413 tbuf = safe_malloc(max_scf_pg_type_len + 1); 15414 15415 /* Take the "previous" snapshot before we blow away the properties. */ 15416 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 15417 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 15418 scfdie(); 15419 } else { 15420 if (scf_error() != SCF_ERROR_NOT_FOUND) 15421 scfdie(); 15422 15423 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 15424 scfdie(); 15425 } 15426 15427 /* Save general/enabled, since we're probably going to replace it. */ 15428 enabled = 2; 15429 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 15430 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 15431 scf_property_get_value(prop, val) == 0) 15432 (void) scf_value_get_boolean(val, &enabled); 15433 15434 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15435 if (scf_error() != SCF_ERROR_NOT_FOUND) 15436 scfdie(); 15437 15438 goto out; 15439 } 15440 15441 for (;;) { 15442 boolean_t isinst; 15443 uint32_t flags; 15444 int r; 15445 15446 /* Clear the properties from the corresponding entity. */ 15447 isinst = snaplevel_is_instance(level); 15448 15449 if (!isinst) 15450 r = scf_iter_service_pgs(iter, cur_svc); 15451 else 15452 r = scf_iter_instance_pgs(iter, cur_inst); 15453 if (r != SCF_SUCCESS) 15454 scfdie(); 15455 15456 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15457 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15458 scfdie(); 15459 15460 /* Skip nonpersistent pgs. */ 15461 if (flags & SCF_PG_FLAG_NONPERSISTENT) 15462 continue; 15463 15464 if (scf_pg_delete(pg) != SCF_SUCCESS) { 15465 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15466 scfdie(); 15467 15468 semerr(emsg_permission_denied); 15469 goto out; 15470 } 15471 } 15472 if (r == -1) 15473 scfdie(); 15474 15475 /* Copy the properties to the corresponding entity. */ 15476 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 15477 scfdie(); 15478 15479 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15480 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 15481 scfdie(); 15482 15483 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 15484 0) 15485 scfdie(); 15486 15487 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15488 scfdie(); 15489 15490 if (!isinst) 15491 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 15492 flags, npg); 15493 else 15494 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 15495 flags, npg); 15496 if (r != SCF_SUCCESS) { 15497 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15498 scfdie(); 15499 15500 semerr(emsg_permission_denied); 15501 goto out; 15502 } 15503 15504 if ((enabled == 0 || enabled == 1) && 15505 strcmp(nbuf, scf_pg_general) == 0) 15506 r = pg_copy(pg, npg, enabled); 15507 else 15508 r = pg_copy(pg, npg, 2); 15509 15510 switch (r) { 15511 case 0: 15512 break; 15513 15514 case -1: 15515 semerr(emsg_permission_denied); 15516 goto out; 15517 15518 case -2: 15519 semerr(gettext( 15520 "Interrupted by another change.\n")); 15521 goto out; 15522 15523 default: 15524 abort(); 15525 } 15526 } 15527 if (r == -1) 15528 scfdie(); 15529 15530 /* Get next level. */ 15531 nlevel = scf_snaplevel_create(g_hndl); 15532 if (nlevel == NULL) 15533 scfdie(); 15534 15535 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 15536 SCF_SUCCESS) { 15537 if (scf_error() != SCF_ERROR_NOT_FOUND) 15538 scfdie(); 15539 15540 scf_snaplevel_destroy(nlevel); 15541 break; 15542 } 15543 15544 scf_snaplevel_destroy(level); 15545 level = nlevel; 15546 } 15547 15548 if (snapname == NULL) { 15549 lscf_selectsnap(NULL); 15550 snap = NULL; /* cur_snap has been destroyed */ 15551 } 15552 15553 out: 15554 free(tbuf); 15555 free(nbuf); 15556 scf_value_destroy(val); 15557 scf_property_destroy(prop); 15558 scf_pg_destroy(npg); 15559 scf_pg_destroy(pg); 15560 scf_iter_destroy(iter); 15561 scf_snaplevel_destroy(level); 15562 scf_snapshot_destroy(prev); 15563 if (snap != cur_snap) 15564 scf_snapshot_destroy(snap); 15565 } 15566 15567 void 15568 lscf_refresh(void) 15569 { 15570 ssize_t fmrilen; 15571 size_t bufsz; 15572 char *fmribuf; 15573 int r; 15574 15575 lscf_prep_hndl(); 15576 15577 if (cur_inst == NULL) { 15578 semerr(gettext("Instance not selected.\n")); 15579 return; 15580 } 15581 15582 bufsz = max_scf_fmri_len + 1; 15583 fmribuf = safe_malloc(bufsz); 15584 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15585 if (fmrilen < 0) { 15586 free(fmribuf); 15587 if (scf_error() != SCF_ERROR_DELETED) 15588 scfdie(); 15589 scf_instance_destroy(cur_inst); 15590 cur_inst = NULL; 15591 warn(emsg_deleted); 15592 return; 15593 } 15594 assert(fmrilen < bufsz); 15595 15596 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15597 switch (r) { 15598 case 0: 15599 break; 15600 15601 case ECONNABORTED: 15602 warn(gettext("Could not refresh %s " 15603 "(repository connection broken).\n"), fmribuf); 15604 break; 15605 15606 case ECANCELED: 15607 warn(emsg_deleted); 15608 break; 15609 15610 case EPERM: 15611 warn(gettext("Could not refresh %s " 15612 "(permission denied).\n"), fmribuf); 15613 break; 15614 15615 case ENOSPC: 15616 warn(gettext("Could not refresh %s " 15617 "(repository server out of resources).\n"), 15618 fmribuf); 15619 break; 15620 15621 case EACCES: 15622 default: 15623 bad_error("refresh_entity", scf_error()); 15624 } 15625 15626 free(fmribuf); 15627 } 15628 15629 /* 15630 * describe [-v] [-t] [pg/prop] 15631 */ 15632 int 15633 lscf_describe(uu_list_t *args, int hasargs) 15634 { 15635 int ret = 0; 15636 size_t i; 15637 int argc; 15638 char **argv = NULL; 15639 string_list_t *slp; 15640 int do_verbose = 0; 15641 int do_templates = 0; 15642 char *pattern = NULL; 15643 15644 lscf_prep_hndl(); 15645 15646 if (hasargs != 0) { 15647 argc = uu_list_numnodes(args); 15648 if (argc < 1) 15649 goto usage; 15650 15651 argv = calloc(argc + 1, sizeof (char *)); 15652 if (argv == NULL) 15653 uu_die(gettext("Out of memory.\n")); 15654 15655 for (slp = uu_list_first(args), i = 0; 15656 slp != NULL; 15657 slp = uu_list_next(args, slp), ++i) 15658 argv[i] = slp->str; 15659 15660 argv[i] = NULL; 15661 15662 /* 15663 * We start optind = 0 because our list of arguments 15664 * starts at argv[0] 15665 */ 15666 optind = 0; 15667 opterr = 0; 15668 for (;;) { 15669 ret = getopt(argc, argv, "vt"); 15670 if (ret == -1) 15671 break; 15672 15673 switch (ret) { 15674 case 'v': 15675 do_verbose = 1; 15676 break; 15677 15678 case 't': 15679 do_templates = 1; 15680 break; 15681 15682 case '?': 15683 goto usage; 15684 15685 default: 15686 bad_error("getopt", ret); 15687 } 15688 } 15689 15690 pattern = argv[optind]; 15691 } 15692 15693 if (cur_inst == NULL && cur_svc == NULL) { 15694 semerr(emsg_entity_not_selected); 15695 ret = -1; 15696 goto out; 15697 } 15698 15699 /* 15700 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15701 * output if their last parameter is set to 2. Less information is 15702 * produced if the parameter is set to 1. 15703 */ 15704 if (pattern == NULL) { 15705 if (do_verbose == 1) 15706 list_entity_tmpl(2); 15707 else 15708 list_entity_tmpl(1); 15709 } 15710 15711 if (do_templates == 0) { 15712 if (do_verbose == 1) 15713 listprop(pattern, 0, 2); 15714 else 15715 listprop(pattern, 0, 1); 15716 } else { 15717 if (do_verbose == 1) 15718 listtmpl(pattern, 2); 15719 else 15720 listtmpl(pattern, 1); 15721 } 15722 15723 ret = 0; 15724 out: 15725 if (argv != NULL) 15726 free(argv); 15727 return (ret); 15728 usage: 15729 ret = -2; 15730 goto out; 15731 } 15732 15733 #define PARAM_ACTIVE ((const char *) "active") 15734 #define PARAM_INACTIVE ((const char *) "inactive") 15735 #define PARAM_SMTP_TO ((const char *) "to") 15736 15737 /* 15738 * tokenize() 15739 * Breaks down the string according to the tokens passed. 15740 * Caller is responsible for freeing array of pointers returned. 15741 * Returns NULL on failure 15742 */ 15743 char ** 15744 tokenize(char *str, const char *sep) 15745 { 15746 char *token, *lasts; 15747 char **buf; 15748 int n = 0; /* number of elements */ 15749 int size = 8; /* size of the array (initial) */ 15750 15751 buf = safe_malloc(size * sizeof (char *)); 15752 15753 for (token = strtok_r(str, sep, &lasts); token != NULL; 15754 token = strtok_r(NULL, sep, &lasts), ++n) { 15755 if (n + 1 >= size) { 15756 size *= 2; 15757 if ((buf = realloc(buf, size * sizeof (char *))) == 15758 NULL) { 15759 uu_die(gettext("Out of memory")); 15760 } 15761 } 15762 buf[n] = token; 15763 } 15764 /* NULL terminate the pointer array */ 15765 buf[n] = NULL; 15766 15767 return (buf); 15768 } 15769 15770 int32_t 15771 check_tokens(char **p) 15772 { 15773 int32_t smf = 0; 15774 int32_t fma = 0; 15775 15776 while (*p) { 15777 int32_t t = string_to_tset(*p); 15778 15779 if (t == 0) { 15780 if (is_fma_token(*p) == 0) 15781 return (INVALID_TOKENS); 15782 fma = 1; /* this token is an fma event */ 15783 } else { 15784 smf |= t; 15785 } 15786 15787 if (smf != 0 && fma == 1) 15788 return (MIXED_TOKENS); 15789 ++p; 15790 } 15791 15792 if (smf > 0) 15793 return (smf); 15794 else if (fma == 1) 15795 return (FMA_TOKENS); 15796 15797 return (INVALID_TOKENS); 15798 } 15799 15800 static int 15801 get_selection_str(char *fmri, size_t sz) 15802 { 15803 if (g_hndl == NULL) { 15804 semerr(emsg_entity_not_selected); 15805 return (-1); 15806 } else if (cur_level != NULL) { 15807 semerr(emsg_invalid_for_snapshot); 15808 return (-1); 15809 } else { 15810 lscf_get_selection_str(fmri, sz); 15811 } 15812 15813 return (0); 15814 } 15815 15816 void 15817 lscf_delnotify(const char *set, int global) 15818 { 15819 char *str = strdup(set); 15820 char **pgs; 15821 char **p; 15822 int32_t tset; 15823 char *fmri = NULL; 15824 15825 if (str == NULL) 15826 uu_die(gettext("Out of memory.\n")); 15827 15828 pgs = tokenize(str, ","); 15829 15830 if ((tset = check_tokens(pgs)) > 0) { 15831 size_t sz = max_scf_fmri_len + 1; 15832 15833 fmri = safe_malloc(sz); 15834 if (global) { 15835 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15836 } else if (get_selection_str(fmri, sz) != 0) { 15837 goto out; 15838 } 15839 15840 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri, 15841 tset) != SCF_SUCCESS) { 15842 uu_warn(gettext("Failed smf_notify_del_params: %s\n"), 15843 scf_strerror(scf_error())); 15844 } 15845 } else if (tset == FMA_TOKENS) { 15846 if (global) { 15847 semerr(gettext("Can't use option '-g' with FMA event " 15848 "definitions\n")); 15849 goto out; 15850 } 15851 15852 for (p = pgs; *p; ++p) { 15853 if (smf_notify_del_params(de_tag(*p), NULL, 0) != 15854 SCF_SUCCESS) { 15855 uu_warn(gettext("Failed for \"%s\": %s\n"), *p, 15856 scf_strerror(scf_error())); 15857 goto out; 15858 } 15859 } 15860 } else if (tset == MIXED_TOKENS) { 15861 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15862 goto out; 15863 } else { 15864 uu_die(gettext("Invalid input.\n")); 15865 } 15866 15867 out: 15868 free(fmri); 15869 free(pgs); 15870 free(str); 15871 } 15872 15873 void 15874 lscf_listnotify(const char *set, int global) 15875 { 15876 char *str = safe_strdup(set); 15877 char **pgs; 15878 char **p; 15879 int32_t tset; 15880 nvlist_t *nvl; 15881 char *fmri = NULL; 15882 15883 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 15884 uu_die(gettext("Out of memory.\n")); 15885 15886 pgs = tokenize(str, ","); 15887 15888 if ((tset = check_tokens(pgs)) > 0) { 15889 size_t sz = max_scf_fmri_len + 1; 15890 15891 fmri = safe_malloc(sz); 15892 if (global) { 15893 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15894 } else if (get_selection_str(fmri, sz) != 0) { 15895 goto out; 15896 } 15897 15898 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) != 15899 SCF_SUCCESS) { 15900 if (scf_error() != SCF_ERROR_NOT_FOUND && 15901 scf_error() != SCF_ERROR_DELETED) 15902 uu_warn(gettext( 15903 "Failed listnotify: %s\n"), 15904 scf_strerror(scf_error())); 15905 goto out; 15906 } 15907 15908 listnotify_print(nvl, NULL); 15909 } else if (tset == FMA_TOKENS) { 15910 if (global) { 15911 semerr(gettext("Can't use option '-g' with FMA event " 15912 "definitions\n")); 15913 goto out; 15914 } 15915 15916 for (p = pgs; *p; ++p) { 15917 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) != 15918 SCF_SUCCESS) { 15919 /* 15920 * if the preferences have just been deleted 15921 * or does not exist, just skip. 15922 */ 15923 if (scf_error() == SCF_ERROR_NOT_FOUND || 15924 scf_error() == SCF_ERROR_DELETED) 15925 continue; 15926 uu_warn(gettext( 15927 "Failed listnotify: %s\n"), 15928 scf_strerror(scf_error())); 15929 goto out; 15930 } 15931 listnotify_print(nvl, re_tag(*p)); 15932 } 15933 } else if (tset == MIXED_TOKENS) { 15934 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15935 goto out; 15936 } else { 15937 semerr(gettext("Invalid input.\n")); 15938 } 15939 15940 out: 15941 nvlist_free(nvl); 15942 free(fmri); 15943 free(pgs); 15944 free(str); 15945 } 15946 15947 static char * 15948 strip_quotes_and_blanks(char *s) 15949 { 15950 char *start = s; 15951 char *end = strrchr(s, '\"'); 15952 15953 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') { 15954 start = s + 1; 15955 while (isblank(*start)) 15956 start++; 15957 while (isblank(*(end - 1)) && end > start) { 15958 end--; 15959 } 15960 *end = '\0'; 15961 } 15962 15963 return (start); 15964 } 15965 15966 static int 15967 set_active(nvlist_t *mech, const char *hier_part) 15968 { 15969 boolean_t b; 15970 15971 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) { 15972 b = B_TRUE; 15973 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) { 15974 b = B_FALSE; 15975 } else { 15976 return (-1); 15977 } 15978 15979 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0) 15980 uu_die(gettext("Out of memory.\n")); 15981 15982 return (0); 15983 } 15984 15985 static int 15986 add_snmp_params(nvlist_t *mech, char *hier_part) 15987 { 15988 return (set_active(mech, hier_part)); 15989 } 15990 15991 static int 15992 add_syslog_params(nvlist_t *mech, char *hier_part) 15993 { 15994 return (set_active(mech, hier_part)); 15995 } 15996 15997 /* 15998 * add_mailto_paramas() 15999 * parse the hier_part of mailto URI 16000 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]] 16001 * or mailto:{[active]|inactive} 16002 */ 16003 static int 16004 add_mailto_params(nvlist_t *mech, char *hier_part) 16005 { 16006 const char *tok = "?&"; 16007 char *p; 16008 char *lasts; 16009 char *param; 16010 char *val; 16011 16012 /* 16013 * If the notification parametes are in the form of 16014 * 16015 * malito:{[active]|inactive} 16016 * 16017 * we set the property accordingly and return. 16018 * Otherwise, we make the notification type active and 16019 * process the hier_part. 16020 */ 16021 if (set_active(mech, hier_part) == 0) 16022 return (0); 16023 else if (set_active(mech, PARAM_ACTIVE) != 0) 16024 return (-1); 16025 16026 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) { 16027 /* 16028 * sanity check: we only get here if hier_part = "", but 16029 * that's handled by set_active 16030 */ 16031 uu_die("strtok_r"); 16032 } 16033 16034 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0) 16035 uu_die(gettext("Out of memory.\n")); 16036 16037 while ((p = strtok_r(NULL, tok, &lasts)) != NULL) 16038 if ((param = strtok_r(p, "=", &val)) != NULL) 16039 if (nvlist_add_string(mech, param, val) != 0) 16040 uu_die(gettext("Out of memory.\n")); 16041 16042 return (0); 16043 } 16044 16045 static int 16046 uri_split(char *uri, char **scheme, char **hier_part) 16047 { 16048 int r = -1; 16049 16050 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL || 16051 *hier_part == NULL) { 16052 semerr(gettext("'%s' is not an URI\n"), uri); 16053 return (r); 16054 } 16055 16056 if ((r = check_uri_scheme(*scheme)) < 0) { 16057 semerr(gettext("Unkown URI scheme: %s\n"), *scheme); 16058 return (r); 16059 } 16060 16061 return (r); 16062 } 16063 16064 static int 16065 process_uri(nvlist_t *params, char *uri) 16066 { 16067 char *scheme; 16068 char *hier_part; 16069 nvlist_t *mech; 16070 int index; 16071 int r; 16072 16073 if ((index = uri_split(uri, &scheme, &hier_part)) < 0) 16074 return (-1); 16075 16076 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0) 16077 uu_die(gettext("Out of memory.\n")); 16078 16079 switch (index) { 16080 case 0: 16081 /* error messages displayed by called function */ 16082 r = add_mailto_params(mech, hier_part); 16083 break; 16084 16085 case 1: 16086 if ((r = add_snmp_params(mech, hier_part)) != 0) 16087 semerr(gettext("Not valid parameters: '%s'\n"), 16088 hier_part); 16089 break; 16090 16091 case 2: 16092 if ((r = add_syslog_params(mech, hier_part)) != 0) 16093 semerr(gettext("Not valid parameters: '%s'\n"), 16094 hier_part); 16095 break; 16096 16097 default: 16098 r = -1; 16099 } 16100 16101 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol, 16102 mech) != 0) 16103 uu_die(gettext("Out of memory.\n")); 16104 16105 nvlist_free(mech); 16106 return (r); 16107 } 16108 16109 static int 16110 set_params(nvlist_t *params, char **p) 16111 { 16112 char *uri; 16113 16114 if (p == NULL) 16115 /* sanity check */ 16116 uu_die("set_params"); 16117 16118 while (*p) { 16119 uri = strip_quotes_and_blanks(*p); 16120 if (process_uri(params, uri) != 0) 16121 return (-1); 16122 16123 ++p; 16124 } 16125 16126 return (0); 16127 } 16128 16129 static int 16130 setnotify(const char *e, char **p, int global) 16131 { 16132 char *str = safe_strdup(e); 16133 char **events; 16134 int32_t tset; 16135 int r = -1; 16136 nvlist_t *nvl, *params; 16137 char *fmri = NULL; 16138 16139 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 16140 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 || 16141 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 16142 SCF_NOTIFY_PARAMS_VERSION) != 0) 16143 uu_die(gettext("Out of memory.\n")); 16144 16145 events = tokenize(str, ","); 16146 16147 if ((tset = check_tokens(events)) > 0) { 16148 /* SMF state transitions parameters */ 16149 size_t sz = max_scf_fmri_len + 1; 16150 16151 fmri = safe_malloc(sz); 16152 if (global) { 16153 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 16154 } else if (get_selection_str(fmri, sz) != 0) { 16155 goto out; 16156 } 16157 16158 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 || 16159 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0) 16160 uu_die(gettext("Out of memory.\n")); 16161 16162 if ((r = set_params(params, p)) == 0) { 16163 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, 16164 params) != 0) 16165 uu_die(gettext("Out of memory.\n")); 16166 16167 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS, 16168 nvl) != SCF_SUCCESS) { 16169 r = -1; 16170 uu_warn(gettext( 16171 "Failed smf_notify_set_params(3SCF): %s\n"), 16172 scf_strerror(scf_error())); 16173 } 16174 } 16175 } else if (tset == FMA_TOKENS) { 16176 /* FMA event parameters */ 16177 if (global) { 16178 semerr(gettext("Can't use option '-g' with FMA event " 16179 "definitions\n")); 16180 goto out; 16181 } 16182 16183 if ((r = set_params(params, p)) != 0) 16184 goto out; 16185 16186 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0) 16187 uu_die(gettext("Out of memory.\n")); 16188 16189 while (*events) { 16190 if (smf_notify_set_params(de_tag(*events), nvl) != 16191 SCF_SUCCESS) 16192 uu_warn(gettext( 16193 "Failed smf_notify_set_params(3SCF) for " 16194 "event %s: %s\n"), *events, 16195 scf_strerror(scf_error())); 16196 events++; 16197 } 16198 } else if (tset == MIXED_TOKENS) { 16199 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 16200 } else { 16201 /* Sanity check */ 16202 uu_die(gettext("Invalid input.\n")); 16203 } 16204 16205 out: 16206 nvlist_free(nvl); 16207 nvlist_free(params); 16208 free(fmri); 16209 free(str); 16210 16211 return (r); 16212 } 16213 16214 int 16215 lscf_setnotify(uu_list_t *args) 16216 { 16217 int argc; 16218 char **argv = NULL; 16219 string_list_t *slp; 16220 int global; 16221 char *events; 16222 char **p; 16223 int i; 16224 int ret; 16225 16226 if ((argc = uu_list_numnodes(args)) < 2) 16227 goto usage; 16228 16229 argv = calloc(argc + 1, sizeof (char *)); 16230 if (argv == NULL) 16231 uu_die(gettext("Out of memory.\n")); 16232 16233 for (slp = uu_list_first(args), i = 0; 16234 slp != NULL; 16235 slp = uu_list_next(args, slp), ++i) 16236 argv[i] = slp->str; 16237 16238 argv[i] = NULL; 16239 16240 if (strcmp(argv[0], "-g") == 0) { 16241 global = 1; 16242 events = argv[1]; 16243 p = argv + 2; 16244 } else { 16245 global = 0; 16246 events = argv[0]; 16247 p = argv + 1; 16248 } 16249 16250 ret = setnotify(events, p, global); 16251 16252 out: 16253 free(argv); 16254 return (ret); 16255 16256 usage: 16257 ret = -2; 16258 goto out; 16259 } 16260 16261 /* 16262 * Creates a list of instance name strings associated with a service. If 16263 * wohandcrafted flag is set, get only instances that have a last-import 16264 * snapshot, instances that were imported via svccfg. 16265 */ 16266 static uu_list_t * 16267 create_instance_list(scf_service_t *svc, int wohandcrafted) 16268 { 16269 scf_snapshot_t *snap = NULL; 16270 scf_instance_t *inst; 16271 scf_iter_t *inst_iter; 16272 uu_list_t *instances; 16273 char *instname = NULL; 16274 int r; 16275 16276 inst_iter = scf_iter_create(g_hndl); 16277 inst = scf_instance_create(g_hndl); 16278 if (inst_iter == NULL || inst == NULL) { 16279 uu_warn(gettext("Could not create instance or iterator\n")); 16280 scfdie(); 16281 } 16282 16283 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 16284 return (instances); 16285 16286 if (scf_iter_service_instances(inst_iter, svc) != 0) { 16287 switch (scf_error()) { 16288 case SCF_ERROR_CONNECTION_BROKEN: 16289 case SCF_ERROR_DELETED: 16290 uu_list_destroy(instances); 16291 instances = NULL; 16292 goto out; 16293 16294 case SCF_ERROR_HANDLE_MISMATCH: 16295 case SCF_ERROR_NOT_BOUND: 16296 case SCF_ERROR_NOT_SET: 16297 default: 16298 bad_error("scf_iter_service_instances", scf_error()); 16299 } 16300 } 16301 16302 instname = safe_malloc(max_scf_name_len + 1); 16303 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 16304 if (r == -1) { 16305 (void) uu_warn(gettext("Unable to iterate through " 16306 "instances to create instance list : %s\n"), 16307 scf_strerror(scf_error())); 16308 16309 uu_list_destroy(instances); 16310 instances = NULL; 16311 goto out; 16312 } 16313 16314 /* 16315 * If the instance does not have a last-import snapshot 16316 * then do not add it to the list as it is a hand-crafted 16317 * instance that should not be managed. 16318 */ 16319 if (wohandcrafted) { 16320 if (snap == NULL && 16321 (snap = scf_snapshot_create(g_hndl)) == NULL) { 16322 uu_warn(gettext("Unable to create snapshot " 16323 "entity\n")); 16324 scfdie(); 16325 } 16326 16327 if (scf_instance_get_snapshot(inst, 16328 snap_lastimport, snap) != 0) { 16329 switch (scf_error()) { 16330 case SCF_ERROR_NOT_FOUND : 16331 case SCF_ERROR_DELETED: 16332 continue; 16333 16334 case SCF_ERROR_CONNECTION_BROKEN: 16335 uu_list_destroy(instances); 16336 instances = NULL; 16337 goto out; 16338 16339 case SCF_ERROR_HANDLE_MISMATCH: 16340 case SCF_ERROR_NOT_BOUND: 16341 case SCF_ERROR_NOT_SET: 16342 default: 16343 bad_error("scf_iter_service_instances", 16344 scf_error()); 16345 } 16346 } 16347 } 16348 16349 if (scf_instance_get_name(inst, instname, 16350 max_scf_name_len + 1) < 0) { 16351 switch (scf_error()) { 16352 case SCF_ERROR_NOT_FOUND : 16353 continue; 16354 16355 case SCF_ERROR_CONNECTION_BROKEN: 16356 case SCF_ERROR_DELETED: 16357 uu_list_destroy(instances); 16358 instances = NULL; 16359 goto out; 16360 16361 case SCF_ERROR_HANDLE_MISMATCH: 16362 case SCF_ERROR_NOT_BOUND: 16363 case SCF_ERROR_NOT_SET: 16364 default: 16365 bad_error("scf_iter_service_instances", 16366 scf_error()); 16367 } 16368 } 16369 16370 add_string(instances, instname); 16371 } 16372 16373 out: 16374 if (snap) 16375 scf_snapshot_destroy(snap); 16376 16377 scf_instance_destroy(inst); 16378 scf_iter_destroy(inst_iter); 16379 free(instname); 16380 return (instances); 16381 } 16382 16383 /* 16384 * disable an instance but wait for the instance to 16385 * move out of the running state. 16386 * 16387 * Returns 0 : if the instance did not disable 16388 * Returns non-zero : if the instance disabled. 16389 * 16390 */ 16391 static int 16392 disable_instance(scf_instance_t *instance) 16393 { 16394 char *fmribuf; 16395 int enabled = 10000; 16396 16397 if (inst_is_running(instance)) { 16398 fmribuf = safe_malloc(max_scf_name_len + 1); 16399 if (scf_instance_to_fmri(instance, fmribuf, 16400 max_scf_name_len + 1) < 0) { 16401 free(fmribuf); 16402 return (0); 16403 } 16404 16405 /* 16406 * If the instance cannot be disabled then return 16407 * failure to disable and let the caller decide 16408 * if that is of importance. 16409 */ 16410 if (smf_disable_instance(fmribuf, 0) != 0) { 16411 free(fmribuf); 16412 return (0); 16413 } 16414 16415 while (enabled) { 16416 if (!inst_is_running(instance)) 16417 break; 16418 16419 (void) poll(NULL, 0, 5); 16420 enabled = enabled - 5; 16421 } 16422 16423 free(fmribuf); 16424 } 16425 16426 return (enabled); 16427 } 16428 16429 /* 16430 * Function to compare two service_manifest structures. 16431 */ 16432 /* ARGSUSED2 */ 16433 static int 16434 service_manifest_compare(const void *left, const void *right, void *unused) 16435 { 16436 service_manifest_t *l = (service_manifest_t *)left; 16437 service_manifest_t *r = (service_manifest_t *)right; 16438 int rc; 16439 16440 rc = strcmp(l->servicename, r->servicename); 16441 16442 return (rc); 16443 } 16444 16445 /* 16446 * Look for the provided service in the service to manifest 16447 * tree. If the service exists, and a manifest was provided 16448 * then add the manifest to that service. If the service 16449 * does not exist, then add the service and manifest to the 16450 * list. 16451 * 16452 * If the manifest is NULL, return the element if found. If 16453 * the service is not found return NULL. 16454 */ 16455 service_manifest_t * 16456 find_add_svc_mfst(const char *svnbuf, const char *mfst) 16457 { 16458 service_manifest_t elem; 16459 service_manifest_t *fnelem; 16460 uu_avl_index_t marker; 16461 16462 elem.servicename = svnbuf; 16463 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 16464 16465 if (mfst) { 16466 if (fnelem) { 16467 add_string(fnelem->mfstlist, strdup(mfst)); 16468 } else { 16469 fnelem = safe_malloc(sizeof (*fnelem)); 16470 fnelem->servicename = safe_strdup(svnbuf); 16471 if ((fnelem->mfstlist = 16472 uu_list_create(string_pool, NULL, 0)) == NULL) 16473 uu_die(gettext("Could not create property " 16474 "list: %s\n"), uu_strerror(uu_error())); 16475 16476 add_string(fnelem->mfstlist, safe_strdup(mfst)); 16477 16478 uu_avl_insert(service_manifest_tree, fnelem, marker); 16479 } 16480 } 16481 16482 return (fnelem); 16483 } 16484 16485 /* 16486 * Create the service to manifest avl tree. 16487 * 16488 * Walk each of the manifests currently installed in the supported 16489 * directories, /lib/svc/manifest and /var/svc/manifest. For 16490 * each of the manifests, inventory the services and add them to 16491 * the tree. 16492 * 16493 * Code that calls this function should make sure fileystem/minimal is online, 16494 * /var is available, since this function walks the /var/svc/manifest directory. 16495 */ 16496 static void 16497 create_manifest_tree(void) 16498 { 16499 manifest_info_t **entry; 16500 manifest_info_t **manifests; 16501 uu_list_walk_t *svcs; 16502 bundle_t *b; 16503 entity_t *mfsvc; 16504 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 16505 int c, status; 16506 16507 if (service_manifest_pool) 16508 return; 16509 16510 /* 16511 * Create the list pool for the service manifest list 16512 */ 16513 service_manifest_pool = uu_avl_pool_create("service_manifest", 16514 sizeof (service_manifest_t), 16515 offsetof(service_manifest_t, svcmfst_node), 16516 service_manifest_compare, UU_DEFAULT); 16517 if (service_manifest_pool == NULL) 16518 uu_die(gettext("service_manifest pool creation failed: %s\n"), 16519 uu_strerror(uu_error())); 16520 16521 /* 16522 * Create the list 16523 */ 16524 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 16525 UU_DEFAULT); 16526 if (service_manifest_tree == NULL) 16527 uu_die(gettext("service_manifest tree creation failed: %s\n"), 16528 uu_strerror(uu_error())); 16529 16530 /* 16531 * Walk the manifests adding the service(s) from each manifest. 16532 * 16533 * If a service already exists add the manifest to the manifest 16534 * list for that service. This covers the case of a service that 16535 * is supported by multiple manifest files. 16536 */ 16537 for (c = 0; dirs[c]; c++) { 16538 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT); 16539 if (status < 0) { 16540 uu_warn(gettext("file tree walk of %s encountered " 16541 "error %s\n"), dirs[c], strerror(errno)); 16542 16543 uu_avl_destroy(service_manifest_tree); 16544 service_manifest_tree = NULL; 16545 return; 16546 } 16547 16548 /* 16549 * If a manifest that was in the list is not found 16550 * then skip and go to the next manifest file. 16551 */ 16552 if (manifests != NULL) { 16553 for (entry = manifests; *entry != NULL; entry++) { 16554 b = internal_bundle_new(); 16555 if (lxml_get_bundle_file(b, (*entry)->mi_path, 16556 SVCCFG_OP_IMPORT) != 0) { 16557 internal_bundle_free(b); 16558 continue; 16559 } 16560 16561 svcs = uu_list_walk_start(b->sc_bundle_services, 16562 0); 16563 if (svcs == NULL) { 16564 internal_bundle_free(b); 16565 continue; 16566 } 16567 16568 while ((mfsvc = uu_list_walk_next(svcs)) != 16569 NULL) { 16570 /* Add manifest to service */ 16571 (void) find_add_svc_mfst(mfsvc->sc_name, 16572 (*entry)->mi_path); 16573 } 16574 16575 uu_list_walk_end(svcs); 16576 internal_bundle_free(b); 16577 } 16578 16579 free_manifest_array(manifests); 16580 } 16581 } 16582 } 16583 16584 /* 16585 * Check the manifest history file to see 16586 * if the service was ever installed from 16587 * one of the supported directories. 16588 * 16589 * Return Values : 16590 * -1 - if there's error reading manifest history file 16591 * 1 - if the service is not found 16592 * 0 - if the service is found 16593 */ 16594 static int 16595 check_mfst_history(const char *svcname) 16596 { 16597 struct stat st; 16598 caddr_t mfsthist_start; 16599 char *svnbuf; 16600 int fd; 16601 int r = 1; 16602 16603 fd = open(MFSTHISTFILE, O_RDONLY); 16604 if (fd == -1) { 16605 uu_warn(gettext("Unable to open the history file\n")); 16606 return (-1); 16607 } 16608 16609 if (fstat(fd, &st) == -1) { 16610 uu_warn(gettext("Unable to stat the history file\n")); 16611 return (-1); 16612 } 16613 16614 mfsthist_start = mmap(0, st.st_size, PROT_READ, 16615 MAP_PRIVATE, fd, 0); 16616 16617 (void) close(fd); 16618 if (mfsthist_start == MAP_FAILED || 16619 *(mfsthist_start + st.st_size) != '\0') { 16620 (void) munmap(mfsthist_start, st.st_size); 16621 return (-1); 16622 } 16623 16624 /* 16625 * The manifest history file is a space delimited list 16626 * of service and instance to manifest linkage. Adding 16627 * a space to the end of the service name so to get only 16628 * the service that is being searched for. 16629 */ 16630 svnbuf = uu_msprintf("%s ", svcname); 16631 if (svnbuf == NULL) 16632 uu_die(gettext("Out of memory")); 16633 16634 if (strstr(mfsthist_start, svnbuf) != NULL) 16635 r = 0; 16636 16637 (void) munmap(mfsthist_start, st.st_size); 16638 uu_free(svnbuf); 16639 return (r); 16640 } 16641 16642 /* 16643 * Take down each of the instances in the service 16644 * and remove them, then delete the service. 16645 */ 16646 static void 16647 teardown_service(scf_service_t *svc, const char *svnbuf) 16648 { 16649 scf_instance_t *instance; 16650 scf_iter_t *iter; 16651 int r; 16652 16653 safe_printf(gettext("Delete service %s as there are no " 16654 "supporting manifests\n"), svnbuf); 16655 16656 instance = scf_instance_create(g_hndl); 16657 iter = scf_iter_create(g_hndl); 16658 if (iter == NULL || instance == NULL) { 16659 uu_warn(gettext("Unable to create supporting entities to " 16660 "teardown the service\n")); 16661 uu_warn(gettext("scf error is : %s\n"), 16662 scf_strerror(scf_error())); 16663 scfdie(); 16664 } 16665 16666 if (scf_iter_service_instances(iter, svc) != 0) { 16667 switch (scf_error()) { 16668 case SCF_ERROR_CONNECTION_BROKEN: 16669 case SCF_ERROR_DELETED: 16670 goto out; 16671 16672 case SCF_ERROR_HANDLE_MISMATCH: 16673 case SCF_ERROR_NOT_BOUND: 16674 case SCF_ERROR_NOT_SET: 16675 default: 16676 bad_error("scf_iter_service_instances", 16677 scf_error()); 16678 } 16679 } 16680 16681 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 16682 if (r == -1) { 16683 uu_warn(gettext("Error - %s\n"), 16684 scf_strerror(scf_error())); 16685 goto out; 16686 } 16687 16688 (void) disable_instance(instance); 16689 } 16690 16691 /* 16692 * Delete the service... forcing the deletion in case 16693 * any of the instances did not disable. 16694 */ 16695 (void) lscf_service_delete(svc, 1); 16696 out: 16697 scf_instance_destroy(instance); 16698 scf_iter_destroy(iter); 16699 } 16700 16701 /* 16702 * Get the list of instances supported by the manifest 16703 * file. 16704 * 16705 * Return 0 if there are no instances. 16706 * 16707 * Return -1 if there are errors attempting to collect instances. 16708 * 16709 * Return the count of instances found if there are no errors. 16710 * 16711 */ 16712 static int 16713 check_instance_support(char *mfstfile, const char *svcname, 16714 uu_list_t *instances) 16715 { 16716 uu_list_walk_t *svcs, *insts; 16717 uu_list_t *ilist; 16718 bundle_t *b; 16719 entity_t *mfsvc, *mfinst; 16720 const char *svcn; 16721 int rminstcnt = 0; 16722 16723 16724 b = internal_bundle_new(); 16725 16726 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 16727 /* 16728 * Unable to process the manifest file for 16729 * instance support, so just return as 16730 * don't want to remove instances that could 16731 * not be accounted for that might exist here. 16732 */ 16733 internal_bundle_free(b); 16734 return (0); 16735 } 16736 16737 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 16738 if (svcs == NULL) { 16739 internal_bundle_free(b); 16740 return (0); 16741 } 16742 16743 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 16744 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 16745 16746 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 16747 if (strcmp(mfsvc->sc_name, svcn) == 0) 16748 break; 16749 } 16750 uu_list_walk_end(svcs); 16751 16752 if (mfsvc == NULL) { 16753 internal_bundle_free(b); 16754 return (-1); 16755 } 16756 16757 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 16758 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 16759 internal_bundle_free(b); 16760 return (0); 16761 } 16762 16763 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 16764 /* 16765 * Remove the instance from the instances list. 16766 * The unaccounted for instances will be removed 16767 * from the service once all manifests are 16768 * processed. 16769 */ 16770 (void) remove_string(instances, 16771 mfinst->sc_name); 16772 rminstcnt++; 16773 } 16774 16775 uu_list_walk_end(insts); 16776 internal_bundle_free(b); 16777 16778 return (rminstcnt); 16779 } 16780 16781 /* 16782 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 16783 * 'false' to indicate there's no manifest file(s) found for the service. 16784 */ 16785 static void 16786 svc_add_no_support(scf_service_t *svc) 16787 { 16788 char *pname; 16789 16790 /* Add no support */ 16791 cur_svc = svc; 16792 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 16793 return; 16794 16795 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 16796 if (pname == NULL) 16797 uu_die(gettext("Out of memory.\n")); 16798 16799 (void) lscf_addpropvalue(pname, "boolean:", "0"); 16800 16801 uu_free(pname); 16802 cur_svc = NULL; 16803 } 16804 16805 /* 16806 * This function handles all upgrade scenarios for a service that doesn't have 16807 * SCF_PG_MANIFESTFILES pg. The function creates and populates 16808 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 16809 * manifest(s) mapping. Manifests under supported directories are inventoried 16810 * and a property is added for each file that delivers configuration to the 16811 * service. A service that has no corresponding manifest files (deleted) are 16812 * removed from repository. 16813 * 16814 * Unsupported services: 16815 * 16816 * A service is considered unsupported if there is no corresponding manifest 16817 * in the supported directories for that service and the service isn't in the 16818 * history file list. The history file, MFSTHISTFILE, contains a list of all 16819 * services and instances that were delivered by Solaris before the introduction 16820 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 16821 * the path to the manifest file that defined the service or instance. 16822 * 16823 * Another type of unsupported services is 'handcrafted' services, 16824 * programmatically created services or services created by dependent entries 16825 * in other manifests. A handcrafted service is identified by its lack of any 16826 * instance containing last-import snapshot which is created during svccfg 16827 * import. 16828 * 16829 * This function sets a flag for unsupported services by setting services' 16830 * SCF_PG_MANIFESTFILES/support property to false. 16831 */ 16832 static void 16833 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 16834 { 16835 service_manifest_t *elem; 16836 uu_list_walk_t *mfwalk; 16837 string_list_t *mfile; 16838 uu_list_t *instances; 16839 const char *sname; 16840 char *pname; 16841 int r; 16842 16843 /* 16844 * Since there's no guarantee manifests under /var are available during 16845 * early import, don't perform any upgrade during early import. 16846 */ 16847 if (IGNORE_VAR) 16848 return; 16849 16850 if (service_manifest_tree == NULL) { 16851 create_manifest_tree(); 16852 } 16853 16854 /* 16855 * Find service's supporting manifest(s) after 16856 * stripping off the svc:/ prefix that is part 16857 * of the fmri that is not used in the service 16858 * manifest bundle list. 16859 */ 16860 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 16861 strlen(SCF_FMRI_SERVICE_PREFIX); 16862 elem = find_add_svc_mfst(sname, NULL); 16863 if (elem == NULL) { 16864 16865 /* 16866 * A handcrafted service, one that has no instance containing 16867 * last-import snapshot, should get unsupported flag. 16868 */ 16869 instances = create_instance_list(svc, 1); 16870 if (instances == NULL) { 16871 uu_warn(gettext("Unable to create instance list %s\n"), 16872 svcname); 16873 return; 16874 } 16875 16876 if (uu_list_numnodes(instances) == 0) { 16877 svc_add_no_support(svc); 16878 return; 16879 } 16880 16881 /* 16882 * If the service is in the history file, and its supporting 16883 * manifests are not found, we can safely delete the service 16884 * because its manifests are removed from the system. 16885 * 16886 * Services not found in the history file are not delivered by 16887 * Solaris and/or delivered outside supported directories, set 16888 * unsupported flag for these services. 16889 */ 16890 r = check_mfst_history(svcname); 16891 if (r == -1) 16892 return; 16893 16894 if (r) { 16895 /* Set unsupported flag for service */ 16896 svc_add_no_support(svc); 16897 } else { 16898 /* Delete the service */ 16899 teardown_service(svc, svcname); 16900 } 16901 16902 return; 16903 } 16904 16905 /* 16906 * Walk through the list of manifests and add them 16907 * to the service. 16908 * 16909 * Create a manifestfiles pg and add the property. 16910 */ 16911 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 16912 if (mfwalk == NULL) 16913 return; 16914 16915 cur_svc = svc; 16916 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 16917 if (r != 0) { 16918 cur_svc = NULL; 16919 return; 16920 } 16921 16922 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 16923 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16924 mhash_filename_to_propname(mfile->str, 0)); 16925 if (pname == NULL) 16926 uu_die(gettext("Out of memory.\n")); 16927 16928 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 16929 uu_free(pname); 16930 } 16931 uu_list_walk_end(mfwalk); 16932 16933 cur_svc = NULL; 16934 } 16935 16936 /* 16937 * Take a service and process the manifest file entires to see if 16938 * there is continued support for the service and instances. If 16939 * not cleanup as appropriate. 16940 * 16941 * If a service does not have a manifest files entry flag it for 16942 * upgrade and return. 16943 * 16944 * For each manifestfiles property check if the manifest file is 16945 * under the supported /lib/svc/manifest or /var/svc/manifest path 16946 * and if not then return immediately as this service is not supported 16947 * by the cleanup mechanism and should be ignored. 16948 * 16949 * For each manifest file that is supported, check to see if the 16950 * file exists. If not then remove the manifest file property 16951 * from the service and the smf/manifest hash table. If the manifest 16952 * file exists then verify that it supports the instances that are 16953 * part of the service. 16954 * 16955 * Once all manifest files have been accounted for remove any instances 16956 * that are no longer supported in the service. 16957 * 16958 * Return values : 16959 * 0 - Successfully processed the service 16960 * non-zero - failed to process the service 16961 * 16962 * On most errors, will just return to wait and get the next service, 16963 * unless in case of unable to create the needed structures which is 16964 * most likely a fatal error that is not going to be recoverable. 16965 */ 16966 int 16967 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 16968 { 16969 struct mpg_mfile *mpntov = NULL; 16970 struct mpg_mfile **mpvarry = NULL; 16971 scf_service_t *svc; 16972 scf_propertygroup_t *mpg; 16973 scf_property_t *mp; 16974 scf_value_t *mv; 16975 scf_iter_t *mi; 16976 scf_instance_t *instance; 16977 uu_list_walk_t *insts; 16978 uu_list_t *instances = NULL; 16979 boolean_t activity = (boolean_t)act; 16980 char *mpnbuf = NULL; 16981 char *mpvbuf = NULL; 16982 char *pgpropbuf; 16983 int mfstcnt, rminstct, instct, mfstmax; 16984 int index; 16985 int r = 0; 16986 16987 assert(g_hndl != NULL); 16988 assert(wip->svc != NULL); 16989 assert(wip->fmri != NULL); 16990 16991 svc = wip->svc; 16992 16993 mpg = scf_pg_create(g_hndl); 16994 mp = scf_property_create(g_hndl); 16995 mi = scf_iter_create(g_hndl); 16996 mv = scf_value_create(g_hndl); 16997 instance = scf_instance_create(g_hndl); 16998 16999 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 17000 instance == NULL) { 17001 uu_warn(gettext("Unable to create the supporting entities\n")); 17002 uu_warn(gettext("scf error is : %s\n"), 17003 scf_strerror(scf_error())); 17004 scfdie(); 17005 } 17006 17007 /* 17008 * Get the manifestfiles property group to be parsed for 17009 * files existence. 17010 */ 17011 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 17012 switch (scf_error()) { 17013 case SCF_ERROR_NOT_FOUND: 17014 upgrade_svc_mfst_connection(svc, wip->fmri); 17015 break; 17016 case SCF_ERROR_DELETED: 17017 case SCF_ERROR_CONNECTION_BROKEN: 17018 goto out; 17019 17020 case SCF_ERROR_HANDLE_MISMATCH: 17021 case SCF_ERROR_NOT_BOUND: 17022 case SCF_ERROR_NOT_SET: 17023 default: 17024 bad_error("scf_iter_pg_properties", 17025 scf_error()); 17026 } 17027 17028 goto out; 17029 } 17030 17031 /* 17032 * Iterate through each of the manifestfiles properties 17033 * to determine what manifestfiles are available. 17034 * 17035 * If a manifest file is supported then increment the 17036 * count and therefore the service is safe. 17037 */ 17038 if (scf_iter_pg_properties(mi, mpg) != 0) { 17039 switch (scf_error()) { 17040 case SCF_ERROR_DELETED: 17041 case SCF_ERROR_CONNECTION_BROKEN: 17042 goto out; 17043 17044 case SCF_ERROR_HANDLE_MISMATCH: 17045 case SCF_ERROR_NOT_BOUND: 17046 case SCF_ERROR_NOT_SET: 17047 default: 17048 bad_error("scf_iter_pg_properties", 17049 scf_error()); 17050 } 17051 } 17052 17053 mfstcnt = 0; 17054 mfstmax = MFSTFILE_MAX; 17055 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 17056 while ((r = scf_iter_next_property(mi, mp)) != 0) { 17057 if (r == -1) 17058 bad_error(gettext("Unable to iterate through " 17059 "manifestfiles properties : %s"), 17060 scf_error()); 17061 17062 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 17063 mpnbuf = safe_malloc(max_scf_name_len + 1); 17064 mpvbuf = safe_malloc(max_scf_value_len + 1); 17065 mpntov->mpg = mpnbuf; 17066 mpntov->mfile = mpvbuf; 17067 mpntov->access = 1; 17068 if (scf_property_get_name(mp, mpnbuf, 17069 max_scf_name_len + 1) < 0) { 17070 uu_warn(gettext("Unable to get manifest file " 17071 "property : %s\n"), 17072 scf_strerror(scf_error())); 17073 17074 switch (scf_error()) { 17075 case SCF_ERROR_DELETED: 17076 case SCF_ERROR_CONNECTION_BROKEN: 17077 r = scferror2errno(scf_error()); 17078 goto out_free; 17079 17080 case SCF_ERROR_HANDLE_MISMATCH: 17081 case SCF_ERROR_NOT_BOUND: 17082 case SCF_ERROR_NOT_SET: 17083 default: 17084 bad_error("scf_iter_pg_properties", 17085 scf_error()); 17086 } 17087 } 17088 17089 /* 17090 * The support property is a boolean value that indicates 17091 * if the service is supported for manifest file deletion. 17092 * Currently at this time there is no code that sets this 17093 * value to true. So while we could just let this be caught 17094 * by the support check below, in the future this by be set 17095 * to true and require processing. So for that, go ahead 17096 * and check here, and just return if false. Otherwise, 17097 * fall through expecting that other support checks will 17098 * handle the entries. 17099 */ 17100 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 17101 uint8_t support; 17102 17103 if (scf_property_get_value(mp, mv) != 0 || 17104 scf_value_get_boolean(mv, &support) != 0) { 17105 uu_warn(gettext("Unable to get the manifest " 17106 "support value: %s\n"), 17107 scf_strerror(scf_error())); 17108 17109 switch (scf_error()) { 17110 case SCF_ERROR_DELETED: 17111 case SCF_ERROR_CONNECTION_BROKEN: 17112 r = scferror2errno(scf_error()); 17113 goto out_free; 17114 17115 case SCF_ERROR_HANDLE_MISMATCH: 17116 case SCF_ERROR_NOT_BOUND: 17117 case SCF_ERROR_NOT_SET: 17118 default: 17119 bad_error("scf_iter_pg_properties", 17120 scf_error()); 17121 } 17122 } 17123 17124 if (support == B_FALSE) 17125 goto out_free; 17126 } 17127 17128 /* 17129 * Anything with a manifest outside of the supported 17130 * directories, immediately bail out because that makes 17131 * this service non-supported. We don't even want 17132 * to do instance processing in this case because the 17133 * instances could be part of the non-supported manifest. 17134 */ 17135 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 17136 /* 17137 * Manifest is not in /lib/svc, so we need to 17138 * consider the /var/svc case. 17139 */ 17140 if (strncmp(mpnbuf, VARSVC_PR, 17141 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 17142 /* 17143 * Either the manifest is not in /var/svc or 17144 * /var is not yet mounted. We ignore the 17145 * manifest either because it is not in a 17146 * standard location or because we cannot 17147 * currently access the manifest. 17148 */ 17149 goto out_free; 17150 } 17151 } 17152 17153 /* 17154 * Get the value to of the manifest file for this entry 17155 * for access verification and instance support 17156 * verification if it still exists. 17157 * 17158 * During Early Manifest Import if the manifest is in 17159 * /var/svc then it may not yet be available for checking 17160 * so we must determine if /var/svc is available. If not 17161 * then defer until Late Manifest Import to cleanup. 17162 */ 17163 if (scf_property_get_value(mp, mv) != 0) { 17164 uu_warn(gettext("Unable to get the manifest file " 17165 "value: %s\n"), 17166 scf_strerror(scf_error())); 17167 17168 switch (scf_error()) { 17169 case SCF_ERROR_DELETED: 17170 case SCF_ERROR_CONNECTION_BROKEN: 17171 r = scferror2errno(scf_error()); 17172 goto out_free; 17173 17174 case SCF_ERROR_HANDLE_MISMATCH: 17175 case SCF_ERROR_NOT_BOUND: 17176 case SCF_ERROR_NOT_SET: 17177 default: 17178 bad_error("scf_property_get_value", 17179 scf_error()); 17180 } 17181 } 17182 17183 if (scf_value_get_astring(mv, mpvbuf, 17184 max_scf_value_len + 1) < 0) { 17185 uu_warn(gettext("Unable to get the manifest " 17186 "file : %s\n"), 17187 scf_strerror(scf_error())); 17188 17189 switch (scf_error()) { 17190 case SCF_ERROR_DELETED: 17191 case SCF_ERROR_CONNECTION_BROKEN: 17192 r = scferror2errno(scf_error()); 17193 goto out_free; 17194 17195 case SCF_ERROR_HANDLE_MISMATCH: 17196 case SCF_ERROR_NOT_BOUND: 17197 case SCF_ERROR_NOT_SET: 17198 default: 17199 bad_error("scf_value_get_astring", 17200 scf_error()); 17201 } 17202 } 17203 17204 mpvarry[mfstcnt] = mpntov; 17205 mfstcnt++; 17206 17207 /* 17208 * Check for the need to reallocate array 17209 */ 17210 if (mfstcnt >= (mfstmax - 1)) { 17211 struct mpg_mfile **newmpvarry; 17212 17213 mfstmax = mfstmax * 2; 17214 newmpvarry = realloc(mpvarry, 17215 sizeof (struct mpg_mfile *) * mfstmax); 17216 17217 if (newmpvarry == NULL) 17218 goto out_free; 17219 17220 mpvarry = newmpvarry; 17221 } 17222 17223 mpvarry[mfstcnt] = NULL; 17224 } 17225 17226 for (index = 0; mpvarry[index]; index++) { 17227 mpntov = mpvarry[index]; 17228 17229 /* 17230 * Check to see if the manifestfile is accessable, if so hand 17231 * this service and manifestfile off to be processed for 17232 * instance support. 17233 */ 17234 mpnbuf = mpntov->mpg; 17235 mpvbuf = mpntov->mfile; 17236 if (access(mpvbuf, F_OK) != 0) { 17237 mpntov->access = 0; 17238 activity++; 17239 mfstcnt--; 17240 /* Remove the entry from the service */ 17241 cur_svc = svc; 17242 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 17243 mpnbuf); 17244 if (pgpropbuf == NULL) 17245 uu_die(gettext("Out of memory.\n")); 17246 17247 lscf_delprop(pgpropbuf); 17248 cur_svc = NULL; 17249 17250 uu_free(pgpropbuf); 17251 } 17252 } 17253 17254 /* 17255 * If mfstcnt is 0, none of the manifests that supported the service 17256 * existed so remove the service. 17257 */ 17258 if (mfstcnt == 0) { 17259 teardown_service(svc, wip->fmri); 17260 17261 goto out_free; 17262 } 17263 17264 if (activity) { 17265 int nosvcsupport = 0; 17266 17267 /* 17268 * If the list of service instances is NULL then 17269 * create the list. 17270 */ 17271 instances = create_instance_list(svc, 1); 17272 if (instances == NULL) { 17273 uu_warn(gettext("Unable to create instance list %s\n"), 17274 wip->fmri); 17275 goto out_free; 17276 } 17277 17278 rminstct = uu_list_numnodes(instances); 17279 instct = rminstct; 17280 17281 for (index = 0; mpvarry[index]; index++) { 17282 mpntov = mpvarry[index]; 17283 if (mpntov->access == 0) 17284 continue; 17285 17286 mpnbuf = mpntov->mpg; 17287 mpvbuf = mpntov->mfile; 17288 r = check_instance_support(mpvbuf, wip->fmri, 17289 instances); 17290 if (r == -1) { 17291 nosvcsupport++; 17292 } else { 17293 rminstct -= r; 17294 } 17295 } 17296 17297 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 17298 teardown_service(svc, wip->fmri); 17299 17300 goto out_free; 17301 } 17302 } 17303 17304 /* 17305 * If there are instances left on the instance list, then 17306 * we must remove them. 17307 */ 17308 if (instances != NULL && uu_list_numnodes(instances)) { 17309 string_list_t *sp; 17310 17311 insts = uu_list_walk_start(instances, 0); 17312 while ((sp = uu_list_walk_next(insts)) != NULL) { 17313 /* 17314 * Remove the instance from the instances list. 17315 */ 17316 safe_printf(gettext("Delete instance %s from " 17317 "service %s\n"), sp->str, wip->fmri); 17318 if (scf_service_get_instance(svc, sp->str, 17319 instance) != SCF_SUCCESS) { 17320 (void) uu_warn("scf_error - %s\n", 17321 scf_strerror(scf_error())); 17322 17323 continue; 17324 } 17325 17326 (void) disable_instance(instance); 17327 17328 (void) lscf_instance_delete(instance, 1); 17329 } 17330 scf_instance_destroy(instance); 17331 uu_list_walk_end(insts); 17332 } 17333 17334 out_free: 17335 if (mpvarry) { 17336 struct mpg_mfile *fmpntov; 17337 17338 for (index = 0; mpvarry[index]; index++) { 17339 fmpntov = mpvarry[index]; 17340 if (fmpntov->mpg == mpnbuf) 17341 mpnbuf = NULL; 17342 free(fmpntov->mpg); 17343 17344 if (fmpntov->mfile == mpvbuf) 17345 mpvbuf = NULL; 17346 free(fmpntov->mfile); 17347 17348 if (fmpntov == mpntov) 17349 mpntov = NULL; 17350 free(fmpntov); 17351 } 17352 if (mpnbuf) 17353 free(mpnbuf); 17354 if (mpvbuf) 17355 free(mpvbuf); 17356 if (mpntov) 17357 free(mpntov); 17358 17359 free(mpvarry); 17360 } 17361 out: 17362 scf_pg_destroy(mpg); 17363 scf_property_destroy(mp); 17364 scf_iter_destroy(mi); 17365 scf_value_destroy(mv); 17366 17367 return (0); 17368 } 17369 17370 /* 17371 * Take the service and search for the manifestfiles property 17372 * in each of the property groups. If the manifest file 17373 * associated with the property does not exist then remove 17374 * the property group. 17375 */ 17376 int 17377 lscf_hash_cleanup() 17378 { 17379 scf_service_t *svc; 17380 scf_scope_t *scope; 17381 scf_propertygroup_t *pg; 17382 scf_property_t *prop; 17383 scf_value_t *val; 17384 scf_iter_t *iter; 17385 char *pgname = NULL; 17386 char *mfile = NULL; 17387 int r; 17388 17389 svc = scf_service_create(g_hndl); 17390 scope = scf_scope_create(g_hndl); 17391 pg = scf_pg_create(g_hndl); 17392 prop = scf_property_create(g_hndl); 17393 val = scf_value_create(g_hndl); 17394 iter = scf_iter_create(g_hndl); 17395 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 17396 svc == NULL || scope == NULL) { 17397 uu_warn(gettext("Unable to create a property group, or " 17398 "property\n")); 17399 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 17400 "pg is not NULL"); 17401 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 17402 "prop is not NULL"); 17403 uu_warn("%s\n", val == NULL ? "val is NULL" : 17404 "val is not NULL"); 17405 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 17406 "iter is not NULL"); 17407 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 17408 "svc is not NULL"); 17409 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 17410 "scope is not NULL"); 17411 uu_warn(gettext("scf error is : %s\n"), 17412 scf_strerror(scf_error())); 17413 scfdie(); 17414 } 17415 17416 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 17417 switch (scf_error()) { 17418 case SCF_ERROR_CONNECTION_BROKEN: 17419 case SCF_ERROR_NOT_FOUND: 17420 goto out; 17421 17422 case SCF_ERROR_HANDLE_MISMATCH: 17423 case SCF_ERROR_NOT_BOUND: 17424 case SCF_ERROR_INVALID_ARGUMENT: 17425 default: 17426 bad_error("scf_handle_get_scope", scf_error()); 17427 } 17428 } 17429 17430 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 17431 uu_warn(gettext("Unable to process the hash service, %s\n"), 17432 HASH_SVC); 17433 goto out; 17434 } 17435 17436 pgname = safe_malloc(max_scf_name_len + 1); 17437 mfile = safe_malloc(max_scf_value_len + 1); 17438 17439 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 17440 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 17441 scf_strerror(scf_error())); 17442 goto out; 17443 } 17444 17445 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 17446 if (r == -1) 17447 goto out; 17448 17449 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 17450 switch (scf_error()) { 17451 case SCF_ERROR_DELETED: 17452 return (ENODEV); 17453 17454 case SCF_ERROR_CONNECTION_BROKEN: 17455 return (ECONNABORTED); 17456 17457 case SCF_ERROR_NOT_SET: 17458 case SCF_ERROR_NOT_BOUND: 17459 default: 17460 bad_error("scf_pg_get_name", scf_error()); 17461 } 17462 } 17463 if (IGNORE_VAR) { 17464 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 17465 continue; 17466 } 17467 17468 /* 17469 * If unable to get the property continue as this is an 17470 * entry that has no location to check against. 17471 */ 17472 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 17473 continue; 17474 } 17475 17476 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 17477 uu_warn(gettext("Unable to get value from %s\n"), 17478 pgname); 17479 17480 switch (scf_error()) { 17481 case SCF_ERROR_DELETED: 17482 case SCF_ERROR_CONSTRAINT_VIOLATED: 17483 case SCF_ERROR_NOT_FOUND: 17484 case SCF_ERROR_NOT_SET: 17485 continue; 17486 17487 case SCF_ERROR_CONNECTION_BROKEN: 17488 r = scferror2errno(scf_error()); 17489 goto out; 17490 17491 case SCF_ERROR_HANDLE_MISMATCH: 17492 case SCF_ERROR_NOT_BOUND: 17493 default: 17494 bad_error("scf_property_get_value", 17495 scf_error()); 17496 } 17497 } 17498 17499 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) 17500 == -1) { 17501 uu_warn(gettext("Unable to get astring from %s : %s\n"), 17502 pgname, scf_strerror(scf_error())); 17503 17504 switch (scf_error()) { 17505 case SCF_ERROR_NOT_SET: 17506 case SCF_ERROR_TYPE_MISMATCH: 17507 continue; 17508 17509 default: 17510 bad_error("scf_value_get_astring", scf_error()); 17511 } 17512 } 17513 17514 if (access(mfile, F_OK) == 0) 17515 continue; 17516 17517 (void) scf_pg_delete(pg); 17518 } 17519 17520 out: 17521 scf_scope_destroy(scope); 17522 scf_service_destroy(svc); 17523 scf_pg_destroy(pg); 17524 scf_property_destroy(prop); 17525 scf_value_destroy(val); 17526 scf_iter_destroy(iter); 17527 free(pgname); 17528 free(mfile); 17529 17530 return (0); 17531 } 17532 17533 #ifndef NATIVE_BUILD 17534 /* ARGSUSED */ 17535 CPL_MATCH_FN(complete_select) 17536 { 17537 const char *arg0, *arg1, *arg1end; 17538 int word_start, err = 0, r; 17539 size_t len; 17540 char *buf; 17541 17542 lscf_prep_hndl(); 17543 17544 arg0 = line + strspn(line, " \t"); 17545 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 17546 17547 arg1 = arg0 + sizeof ("select") - 1; 17548 arg1 += strspn(arg1, " \t"); 17549 word_start = arg1 - line; 17550 17551 arg1end = arg1 + strcspn(arg1, " \t"); 17552 if (arg1end < line + word_end) 17553 return (0); 17554 17555 len = line + word_end - arg1; 17556 17557 buf = safe_malloc(max_scf_name_len + 1); 17558 17559 if (cur_snap != NULL) { 17560 return (0); 17561 } else if (cur_inst != NULL) { 17562 return (0); 17563 } else if (cur_svc != NULL) { 17564 scf_instance_t *inst; 17565 scf_iter_t *iter; 17566 17567 if ((inst = scf_instance_create(g_hndl)) == NULL || 17568 (iter = scf_iter_create(g_hndl)) == NULL) 17569 scfdie(); 17570 17571 if (scf_iter_service_instances(iter, cur_svc) != 0) 17572 scfdie(); 17573 17574 for (;;) { 17575 r = scf_iter_next_instance(iter, inst); 17576 if (r == 0) 17577 break; 17578 if (r != 1) 17579 scfdie(); 17580 17581 if (scf_instance_get_name(inst, buf, 17582 max_scf_name_len + 1) < 0) 17583 scfdie(); 17584 17585 if (strncmp(buf, arg1, len) == 0) { 17586 err = cpl_add_completion(cpl, line, word_start, 17587 word_end, buf + len, "", " "); 17588 if (err != 0) 17589 break; 17590 } 17591 } 17592 17593 scf_iter_destroy(iter); 17594 scf_instance_destroy(inst); 17595 17596 return (err); 17597 } else { 17598 scf_service_t *svc; 17599 scf_iter_t *iter; 17600 17601 assert(cur_scope != NULL); 17602 17603 if ((svc = scf_service_create(g_hndl)) == NULL || 17604 (iter = scf_iter_create(g_hndl)) == NULL) 17605 scfdie(); 17606 17607 if (scf_iter_scope_services(iter, cur_scope) != 0) 17608 scfdie(); 17609 17610 for (;;) { 17611 r = scf_iter_next_service(iter, svc); 17612 if (r == 0) 17613 break; 17614 if (r != 1) 17615 scfdie(); 17616 17617 if (scf_service_get_name(svc, buf, 17618 max_scf_name_len + 1) < 0) 17619 scfdie(); 17620 17621 if (strncmp(buf, arg1, len) == 0) { 17622 err = cpl_add_completion(cpl, line, word_start, 17623 word_end, buf + len, "", " "); 17624 if (err != 0) 17625 break; 17626 } 17627 } 17628 17629 scf_iter_destroy(iter); 17630 scf_service_destroy(svc); 17631 17632 return (err); 17633 } 17634 } 17635 17636 /* ARGSUSED */ 17637 CPL_MATCH_FN(complete_command) 17638 { 17639 uint32_t scope = 0; 17640 17641 if (cur_snap != NULL) 17642 scope = CS_SNAP; 17643 else if (cur_inst != NULL) 17644 scope = CS_INST; 17645 else if (cur_svc != NULL) 17646 scope = CS_SVC; 17647 else 17648 scope = CS_SCOPE; 17649 17650 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 17651 } 17652 #endif /* NATIVE_BUILD */ 17653