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 if (scf_service_get_instance(svc, istr, inst) != 0) { 1445 switch (scf_error()) { 1446 case SCF_ERROR_CONNECTION_BROKEN: 1447 scfdie(); 1448 /* NOTREACHED */ 1449 1450 case SCF_ERROR_DELETED: 1451 goto get_svc; 1452 1453 case SCF_ERROR_NOT_FOUND: 1454 break; 1455 1456 case SCF_ERROR_HANDLE_MISMATCH: 1457 case SCF_ERROR_INVALID_ARGUMENT: 1458 case SCF_ERROR_NOT_BOUND: 1459 case SCF_ERROR_NOT_SET: 1460 default: 1461 bad_error("scf_service_get_instance", scf_error()); 1462 } 1463 1464 if (scf_service_add_instance(svc, istr, inst) != 0) { 1465 switch (scf_error()) { 1466 case SCF_ERROR_CONNECTION_BROKEN: 1467 scfdie(); 1468 /* NOTREACHED */ 1469 1470 case SCF_ERROR_DELETED: 1471 goto get_svc; 1472 1473 case SCF_ERROR_PERMISSION_DENIED: 1474 case SCF_ERROR_BACKEND_READONLY: 1475 case SCF_ERROR_BACKEND_ACCESS: 1476 scfe = scf_error(); 1477 goto out; 1478 1479 case SCF_ERROR_HANDLE_MISMATCH: 1480 case SCF_ERROR_INVALID_ARGUMENT: 1481 case SCF_ERROR_NOT_BOUND: 1482 case SCF_ERROR_NOT_SET: 1483 default: 1484 bad_error("scf_service_add_instance", 1485 scf_error()); 1486 } 1487 } 1488 } 1489 1490 scfe = SCF_ERROR_NONE; 1491 *ep = inst; 1492 *isservicep = 0; 1493 1494 out: 1495 if (*ep != inst) 1496 scf_instance_destroy(inst); 1497 if (*ep != svc) 1498 scf_service_destroy(svc); 1499 scf_scope_destroy(scope); 1500 free(fmri_copy); 1501 return (scfe); 1502 } 1503 1504 /* 1505 * Create or update a snapshot of inst. snap is a required scratch object. 1506 * 1507 * Returns 1508 * 0 - success 1509 * ECONNABORTED - repository connection broken 1510 * EPERM - permission denied 1511 * ENOSPC - configd is out of resources 1512 * ECANCELED - inst was deleted 1513 * -1 - unknown libscf error (message printed) 1514 */ 1515 static int 1516 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1517 { 1518 again: 1519 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1520 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1521 switch (scf_error()) { 1522 case SCF_ERROR_CONNECTION_BROKEN: 1523 case SCF_ERROR_PERMISSION_DENIED: 1524 case SCF_ERROR_NO_RESOURCES: 1525 return (scferror2errno(scf_error())); 1526 1527 case SCF_ERROR_NOT_SET: 1528 case SCF_ERROR_INVALID_ARGUMENT: 1529 default: 1530 bad_error("_scf_snapshot_take_attach", 1531 scf_error()); 1532 } 1533 } 1534 } else { 1535 switch (scf_error()) { 1536 case SCF_ERROR_NOT_FOUND: 1537 break; 1538 1539 case SCF_ERROR_DELETED: 1540 case SCF_ERROR_CONNECTION_BROKEN: 1541 return (scferror2errno(scf_error())); 1542 1543 case SCF_ERROR_HANDLE_MISMATCH: 1544 case SCF_ERROR_NOT_BOUND: 1545 case SCF_ERROR_INVALID_ARGUMENT: 1546 case SCF_ERROR_NOT_SET: 1547 default: 1548 bad_error("scf_instance_get_snapshot", scf_error()); 1549 } 1550 1551 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1552 switch (scf_error()) { 1553 case SCF_ERROR_EXISTS: 1554 goto again; 1555 1556 case SCF_ERROR_CONNECTION_BROKEN: 1557 case SCF_ERROR_NO_RESOURCES: 1558 case SCF_ERROR_PERMISSION_DENIED: 1559 return (scferror2errno(scf_error())); 1560 1561 default: 1562 scfwarn(); 1563 return (-1); 1564 1565 case SCF_ERROR_NOT_SET: 1566 case SCF_ERROR_INTERNAL: 1567 case SCF_ERROR_INVALID_ARGUMENT: 1568 case SCF_ERROR_HANDLE_MISMATCH: 1569 bad_error("_scf_snapshot_take_new", 1570 scf_error()); 1571 } 1572 } 1573 } 1574 1575 return (0); 1576 } 1577 1578 static int 1579 refresh_running_snapshot(void *entity) 1580 { 1581 scf_snapshot_t *snap; 1582 int r; 1583 1584 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1585 scfdie(); 1586 r = take_snap(entity, snap_running, snap); 1587 scf_snapshot_destroy(snap); 1588 1589 return (r); 1590 } 1591 1592 /* 1593 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1594 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1595 * instances. fmri is used for messages. inst, iter, and name_buf are used 1596 * for scratch space. Returns 1597 * 0 - success 1598 * ECONNABORTED - repository connection broken 1599 * ECANCELED - entity was deleted 1600 * EACCES - backend denied access 1601 * EPERM - permission denied 1602 * ENOSPC - repository server out of resources 1603 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1604 */ 1605 static int 1606 refresh_entity(int isservice, void *entity, const char *fmri, 1607 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1608 { 1609 scf_error_t scfe; 1610 int r; 1611 1612 if (!isservice) { 1613 /* 1614 * Let restarter handles refreshing and making new running 1615 * snapshot only if operating on a live repository and not 1616 * running in early import. 1617 */ 1618 if (est->sc_repo_filename == NULL && 1619 est->sc_repo_doorname == NULL && 1620 est->sc_in_emi == 0) { 1621 if (_smf_refresh_instance_i(entity) == 0) { 1622 if (g_verbose) 1623 warn(gettext("Refreshed %s.\n"), fmri); 1624 return (0); 1625 } 1626 1627 switch (scf_error()) { 1628 case SCF_ERROR_BACKEND_ACCESS: 1629 return (EACCES); 1630 1631 case SCF_ERROR_PERMISSION_DENIED: 1632 return (EPERM); 1633 1634 default: 1635 return (-1); 1636 } 1637 } else { 1638 r = refresh_running_snapshot(entity); 1639 switch (r) { 1640 case 0: 1641 break; 1642 1643 case ECONNABORTED: 1644 case ECANCELED: 1645 case EPERM: 1646 case ENOSPC: 1647 break; 1648 1649 default: 1650 bad_error("refresh_running_snapshot", 1651 scf_error()); 1652 } 1653 1654 return (r); 1655 } 1656 } 1657 1658 if (scf_iter_service_instances(iter, entity) != 0) { 1659 switch (scf_error()) { 1660 case SCF_ERROR_CONNECTION_BROKEN: 1661 return (ECONNABORTED); 1662 1663 case SCF_ERROR_DELETED: 1664 return (ECANCELED); 1665 1666 case SCF_ERROR_HANDLE_MISMATCH: 1667 case SCF_ERROR_NOT_BOUND: 1668 case SCF_ERROR_NOT_SET: 1669 default: 1670 bad_error("scf_iter_service_instances", scf_error()); 1671 } 1672 } 1673 1674 for (;;) { 1675 r = scf_iter_next_instance(iter, inst); 1676 if (r == 0) 1677 break; 1678 if (r != 1) { 1679 switch (scf_error()) { 1680 case SCF_ERROR_CONNECTION_BROKEN: 1681 return (ECONNABORTED); 1682 1683 case SCF_ERROR_DELETED: 1684 return (ECANCELED); 1685 1686 case SCF_ERROR_HANDLE_MISMATCH: 1687 case SCF_ERROR_NOT_BOUND: 1688 case SCF_ERROR_NOT_SET: 1689 case SCF_ERROR_INVALID_ARGUMENT: 1690 default: 1691 bad_error("scf_iter_next_instance", 1692 scf_error()); 1693 } 1694 } 1695 1696 /* 1697 * Similarly, just take a new running snapshot if operating on 1698 * a non-live repository or running during early import. 1699 */ 1700 if (est->sc_repo_filename != NULL || 1701 est->sc_repo_doorname != NULL || 1702 est->sc_in_emi == 1) { 1703 r = refresh_running_snapshot(inst); 1704 switch (r) { 1705 case 0: 1706 continue; 1707 1708 case ECONNABORTED: 1709 case ECANCELED: 1710 case EPERM: 1711 case ENOSPC: 1712 break; 1713 default: 1714 bad_error("refresh_running_snapshot", 1715 scf_error()); 1716 } 1717 1718 return (r); 1719 1720 } 1721 1722 if (_smf_refresh_instance_i(inst) == 0) { 1723 if (g_verbose) { 1724 if (scf_instance_get_name(inst, name_buf, 1725 max_scf_name_len + 1) < 0) 1726 (void) strcpy(name_buf, "?"); 1727 1728 warn(gettext("Refreshed %s:%s.\n"), 1729 fmri, name_buf); 1730 } 1731 } else { 1732 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1733 g_verbose) { 1734 scfe = scf_error(); 1735 1736 if (scf_instance_to_fmri(inst, name_buf, 1737 max_scf_name_len + 1) < 0) 1738 (void) strcpy(name_buf, "?"); 1739 1740 warn(gettext( 1741 "Refresh of %s:%s failed: %s.\n"), fmri, 1742 name_buf, scf_strerror(scfe)); 1743 } 1744 } 1745 } 1746 1747 return (0); 1748 } 1749 1750 static void 1751 private_refresh(void) 1752 { 1753 scf_instance_t *pinst = NULL; 1754 scf_iter_t *piter = NULL; 1755 ssize_t fmrilen; 1756 size_t bufsz; 1757 char *fmribuf; 1758 void *ent; 1759 int issvc; 1760 int r; 1761 1762 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1763 return; 1764 1765 assert(cur_svc != NULL); 1766 1767 bufsz = max_scf_fmri_len + 1; 1768 fmribuf = safe_malloc(bufsz); 1769 if (cur_inst) { 1770 issvc = 0; 1771 ent = cur_inst; 1772 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1773 } else { 1774 issvc = 1; 1775 ent = cur_svc; 1776 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1777 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1778 scfdie(); 1779 1780 if ((piter = scf_iter_create(g_hndl)) == NULL) 1781 scfdie(); 1782 } 1783 if (fmrilen < 0) { 1784 free(fmribuf); 1785 if (scf_error() != SCF_ERROR_DELETED) 1786 scfdie(); 1787 1788 warn(emsg_deleted); 1789 return; 1790 } 1791 assert(fmrilen < bufsz); 1792 1793 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1794 switch (r) { 1795 case 0: 1796 break; 1797 1798 case ECONNABORTED: 1799 warn(gettext("Could not refresh %s " 1800 "(repository connection broken).\n"), fmribuf); 1801 break; 1802 1803 case ECANCELED: 1804 warn(emsg_deleted); 1805 break; 1806 1807 case EPERM: 1808 warn(gettext("Could not refresh %s " 1809 "(permission denied).\n"), fmribuf); 1810 break; 1811 1812 case ENOSPC: 1813 warn(gettext("Could not refresh %s " 1814 "(repository server out of resources).\n"), 1815 fmribuf); 1816 break; 1817 1818 case EACCES: 1819 default: 1820 bad_error("refresh_entity", scf_error()); 1821 } 1822 1823 if (issvc) { 1824 scf_instance_destroy(pinst); 1825 scf_iter_destroy(piter); 1826 } 1827 1828 free(fmribuf); 1829 } 1830 1831 1832 static int 1833 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1834 { 1835 cbp->sc_err = scferror2errno(err); 1836 return (UU_WALK_ERROR); 1837 } 1838 1839 static int 1840 stash_scferror(scf_callback_t *cbp) 1841 { 1842 return (stash_scferror_err(cbp, scf_error())); 1843 } 1844 1845 static int select_inst(const char *); 1846 static int select_svc(const char *); 1847 1848 /* 1849 * Take a property that does not have a type and check to see if a type 1850 * exists or can be gleened from the current data. Set the type. 1851 * 1852 * Check the current level (instance) and then check the higher level 1853 * (service). This could be the case for adding a new property to 1854 * the instance that's going to "override" a service level property. 1855 * 1856 * For a property : 1857 * 1. Take the type from an existing property 1858 * 2. Take the type from a template entry 1859 * 1860 * If the type can not be found, then leave the type as is, and let the import 1861 * report the problem of the missing type. 1862 */ 1863 static int 1864 find_current_prop_type(void *p, void *g) 1865 { 1866 property_t *prop = p; 1867 scf_callback_t *lcb = g; 1868 pgroup_t *pg = NULL; 1869 1870 const char *fmri = NULL; 1871 char *lfmri = NULL; 1872 char *cur_selection = NULL; 1873 1874 scf_propertygroup_t *sc_pg = NULL; 1875 scf_property_t *sc_prop = NULL; 1876 scf_pg_tmpl_t *t_pg = NULL; 1877 scf_prop_tmpl_t *t_prop = NULL; 1878 scf_type_t prop_type; 1879 1880 value_t *vp; 1881 int issvc = lcb->sc_service; 1882 int r = UU_WALK_ERROR; 1883 1884 if (prop->sc_value_type != SCF_TYPE_INVALID) 1885 return (UU_WALK_NEXT); 1886 1887 t_prop = scf_tmpl_prop_create(g_hndl); 1888 sc_prop = scf_property_create(g_hndl); 1889 if (sc_prop == NULL || t_prop == NULL) { 1890 warn(gettext("Unable to create the property to attempt and " 1891 "find a missing type.\n")); 1892 1893 scf_property_destroy(sc_prop); 1894 scf_tmpl_prop_destroy(t_prop); 1895 1896 return (UU_WALK_ERROR); 1897 } 1898 1899 if (lcb->sc_flags == 1) { 1900 pg = lcb->sc_parent; 1901 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT); 1902 fmri = pg->sc_parent->sc_fmri; 1903 retry_pg: 1904 if (cur_svc && cur_selection == NULL) { 1905 cur_selection = safe_malloc(max_scf_fmri_len + 1); 1906 lscf_get_selection_str(cur_selection, 1907 max_scf_fmri_len + 1); 1908 1909 if (strcmp(cur_selection, fmri) != 0) { 1910 lscf_select(fmri); 1911 } else { 1912 free(cur_selection); 1913 cur_selection = NULL; 1914 } 1915 } else { 1916 lscf_select(fmri); 1917 } 1918 1919 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) { 1920 warn(gettext("Unable to create property group to " 1921 "find a missing property type.\n")); 1922 1923 goto out; 1924 } 1925 1926 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) { 1927 /* 1928 * If this is the sc_pg from the parent 1929 * let the caller clean up the sc_pg, 1930 * and just throw it away in this case. 1931 */ 1932 if (sc_pg != lcb->sc_parent) 1933 scf_pg_destroy(sc_pg); 1934 1935 sc_pg = NULL; 1936 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1937 warn(gettext("Unable to create template " 1938 "property group to find a property " 1939 "type.\n")); 1940 1941 goto out; 1942 } 1943 1944 if (scf_tmpl_get_by_pg_name(fmri, NULL, 1945 pg->sc_pgroup_name, NULL, t_pg, 1946 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) { 1947 /* 1948 * if instance get service and jump back 1949 */ 1950 scf_tmpl_pg_destroy(t_pg); 1951 t_pg = NULL; 1952 if (issvc == 0) { 1953 entity_t *e = pg->sc_parent->sc_parent; 1954 1955 fmri = e->sc_fmri; 1956 issvc = 1; 1957 goto retry_pg; 1958 } else { 1959 goto out; 1960 } 1961 } 1962 } 1963 } else { 1964 sc_pg = lcb->sc_parent; 1965 } 1966 1967 /* 1968 * Attempt to get the type from an existing property. If the property 1969 * cannot be found then attempt to get the type from a template entry 1970 * for the property. 1971 * 1972 * Finally, if at the instance level look at the service level. 1973 */ 1974 if (sc_pg != NULL && 1975 pg_get_prop(sc_pg, prop->sc_property_name, 1976 sc_prop) == SCF_SUCCESS && 1977 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) { 1978 prop->sc_value_type = prop_type; 1979 1980 /* 1981 * Found a type, update the value types and validate 1982 * the actual value against this type. 1983 */ 1984 for (vp = uu_list_first(prop->sc_property_values); 1985 vp != NULL; 1986 vp = uu_list_next(prop->sc_property_values, vp)) { 1987 vp->sc_type = prop->sc_value_type; 1988 lxml_store_value(vp, 0, NULL); 1989 } 1990 1991 r = UU_WALK_NEXT; 1992 goto out; 1993 } 1994 1995 /* 1996 * If we get here with t_pg set to NULL then we had to have 1997 * gotten an sc_pg but that sc_pg did not have the property 1998 * we are looking for. So if the t_pg is not null look up 1999 * the template entry for the property. 2000 * 2001 * If the t_pg is null then need to attempt to get a matching 2002 * template entry for the sc_pg, and see if there is a property 2003 * entry for that template entry. 2004 */ 2005 do_tmpl : 2006 if (t_pg != NULL && 2007 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name, 2008 t_prop, 0) == SCF_SUCCESS) { 2009 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) { 2010 prop->sc_value_type = prop_type; 2011 2012 /* 2013 * Found a type, update the value types and validate 2014 * the actual value against this type. 2015 */ 2016 for (vp = uu_list_first(prop->sc_property_values); 2017 vp != NULL; 2018 vp = uu_list_next(prop->sc_property_values, vp)) { 2019 vp->sc_type = prop->sc_value_type; 2020 lxml_store_value(vp, 0, NULL); 2021 } 2022 2023 r = UU_WALK_NEXT; 2024 goto out; 2025 } 2026 } else { 2027 if (t_pg == NULL && sc_pg) { 2028 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 2029 warn(gettext("Unable to create template " 2030 "property group to find a property " 2031 "type.\n")); 2032 2033 goto out; 2034 } 2035 2036 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) { 2037 scf_tmpl_pg_destroy(t_pg); 2038 t_pg = NULL; 2039 } else { 2040 goto do_tmpl; 2041 } 2042 } 2043 } 2044 2045 if (issvc == 0) { 2046 scf_instance_t *i; 2047 scf_service_t *s; 2048 2049 issvc = 1; 2050 if (lcb->sc_flags == 1) { 2051 entity_t *e = pg->sc_parent->sc_parent; 2052 2053 fmri = e->sc_fmri; 2054 goto retry_pg; 2055 } 2056 2057 /* 2058 * because lcb->sc_flags was not set then this means 2059 * the pg was not used and can be used here. 2060 */ 2061 if ((pg = internal_pgroup_new()) == NULL) { 2062 warn(gettext("Could not create internal property group " 2063 "to find a missing type.")); 2064 2065 goto out; 2066 } 2067 2068 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1); 2069 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name, 2070 max_scf_name_len + 1) < 0) 2071 goto out; 2072 2073 i = scf_instance_create(g_hndl); 2074 s = scf_service_create(g_hndl); 2075 if (i == NULL || s == NULL || 2076 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) { 2077 warn(gettext("Could not get a service for the instance " 2078 "to find a missing type.")); 2079 2080 goto out; 2081 } 2082 2083 /* 2084 * Check to see truly at the instance level. 2085 */ 2086 lfmri = safe_malloc(max_scf_fmri_len + 1); 2087 if (scf_instance_get_parent(i, s) == SCF_SUCCESS && 2088 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0) 2089 goto out; 2090 else 2091 fmri = (const char *)lfmri; 2092 2093 goto retry_pg; 2094 } 2095 2096 out : 2097 if (sc_pg != lcb->sc_parent) { 2098 scf_pg_destroy(sc_pg); 2099 } 2100 2101 /* 2102 * If this is true then the pg was allocated 2103 * here, and the name was set so need to free 2104 * the name and the pg. 2105 */ 2106 if (pg != NULL && pg != lcb->sc_parent) { 2107 free((char *)pg->sc_pgroup_name); 2108 internal_pgroup_free(pg); 2109 } 2110 2111 if (cur_selection) { 2112 lscf_select(cur_selection); 2113 free(cur_selection); 2114 } 2115 2116 scf_tmpl_pg_destroy(t_pg); 2117 scf_tmpl_prop_destroy(t_prop); 2118 scf_property_destroy(sc_prop); 2119 2120 if (r != UU_WALK_NEXT) 2121 warn(gettext("Could not find property type for \"%s\" " 2122 "from \"%s\"\n"), prop->sc_property_name, 2123 fmri != NULL ? fmri : lcb->sc_source_fmri); 2124 2125 free(lfmri); 2126 2127 return (r); 2128 } 2129 2130 /* 2131 * Take a property group that does not have a type and check to see if a type 2132 * exists or can be gleened from the current data. Set the type. 2133 * 2134 * Check the current level (instance) and then check the higher level 2135 * (service). This could be the case for adding a new property to 2136 * the instance that's going to "override" a service level property. 2137 * 2138 * For a property group 2139 * 1. Take the type from an existing property group 2140 * 2. Take the type from a template entry 2141 * 2142 * If the type can not be found, then leave the type as is, and let the import 2143 * report the problem of the missing type. 2144 */ 2145 static int 2146 find_current_pg_type(void *p, void *sori) 2147 { 2148 entity_t *si = sori; 2149 pgroup_t *pg = p; 2150 2151 const char *ofmri, *fmri; 2152 char *cur_selection = NULL; 2153 char *pg_type = NULL; 2154 2155 scf_propertygroup_t *sc_pg = NULL; 2156 scf_pg_tmpl_t *t_pg = NULL; 2157 2158 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2159 int r = UU_WALK_ERROR; 2160 2161 ofmri = fmri = si->sc_fmri; 2162 if (pg->sc_pgroup_type != NULL) { 2163 r = UU_WALK_NEXT; 2164 2165 goto out; 2166 } 2167 2168 sc_pg = scf_pg_create(g_hndl); 2169 if (sc_pg == NULL) { 2170 warn(gettext("Unable to create property group to attempt " 2171 "and find a missing type.\n")); 2172 2173 return (UU_WALK_ERROR); 2174 } 2175 2176 /* 2177 * Using get_pg() requires that the cur_svc/cur_inst be 2178 * via lscf_select. Need to preserve the current selection 2179 * if going to use lscf_select() to set up the cur_svc/cur_inst 2180 */ 2181 if (cur_svc) { 2182 cur_selection = safe_malloc(max_scf_fmri_len + 1); 2183 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1); 2184 } 2185 2186 /* 2187 * If the property group exists get the type, and set 2188 * the pgroup_t type of that type. 2189 * 2190 * If not the check for a template pg_pattern entry 2191 * and take the type from that. 2192 */ 2193 retry_svc: 2194 lscf_select(fmri); 2195 2196 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) { 2197 pg_type = safe_malloc(max_scf_pg_type_len + 1); 2198 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type, 2199 max_scf_pg_type_len + 1) != -1) { 2200 pg->sc_pgroup_type = pg_type; 2201 2202 r = UU_WALK_NEXT; 2203 goto out; 2204 } else { 2205 free(pg_type); 2206 } 2207 } else { 2208 if ((t_pg == NULL) && 2209 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) 2210 goto out; 2211 2212 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name, 2213 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS && 2214 scf_tmpl_pg_type(t_pg, &pg_type) != -1) { 2215 pg->sc_pgroup_type = pg_type; 2216 2217 r = UU_WALK_NEXT; 2218 goto out; 2219 } 2220 } 2221 2222 /* 2223 * If type is not found at the instance level then attempt to 2224 * find the type at the service level. 2225 */ 2226 if (!issvc) { 2227 si = si->sc_parent; 2228 fmri = si->sc_fmri; 2229 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2230 goto retry_svc; 2231 } 2232 2233 out : 2234 if (cur_selection) { 2235 lscf_select(cur_selection); 2236 free(cur_selection); 2237 } 2238 2239 /* 2240 * Now walk the properties of the property group to make sure that 2241 * all properties have the correct type and values are valid for 2242 * those types. 2243 */ 2244 if (r == UU_WALK_NEXT) { 2245 scf_callback_t cb; 2246 2247 cb.sc_service = issvc; 2248 cb.sc_source_fmri = ofmri; 2249 if (sc_pg != NULL) { 2250 cb.sc_parent = sc_pg; 2251 cb.sc_flags = 0; 2252 } else { 2253 cb.sc_parent = pg; 2254 cb.sc_flags = 1; 2255 } 2256 2257 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type, 2258 &cb, UU_DEFAULT) != 0) { 2259 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2260 bad_error("uu_list_walk", uu_error()); 2261 2262 r = UU_WALK_ERROR; 2263 } 2264 } else { 2265 warn(gettext("Could not find property group type for " 2266 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri); 2267 } 2268 2269 scf_tmpl_pg_destroy(t_pg); 2270 scf_pg_destroy(sc_pg); 2271 2272 return (r); 2273 } 2274 2275 /* 2276 * Import. These functions import a bundle into the repository. 2277 */ 2278 2279 /* 2280 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 2281 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 2282 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2283 * lcbdata->sc_err to 2284 * ENOMEM - out of memory 2285 * ECONNABORTED - repository connection broken 2286 * ECANCELED - sc_trans's property group was deleted 2287 * EINVAL - p's name is invalid (error printed) 2288 * - p has an invalid value (error printed) 2289 */ 2290 static int 2291 lscf_property_import(void *v, void *pvt) 2292 { 2293 property_t *p = v; 2294 scf_callback_t *lcbdata = pvt; 2295 value_t *vp; 2296 scf_transaction_t *trans = lcbdata->sc_trans; 2297 scf_transaction_entry_t *entr; 2298 scf_value_t *val; 2299 scf_type_t tp; 2300 2301 if ((lcbdata->sc_flags & SCI_NOENABLED || 2302 lcbdata->sc_flags & SCI_DELAYENABLE) && 2303 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 2304 lcbdata->sc_enable = p; 2305 return (UU_WALK_NEXT); 2306 } 2307 2308 entr = scf_entry_create(lcbdata->sc_handle); 2309 if (entr == NULL) { 2310 switch (scf_error()) { 2311 case SCF_ERROR_NO_MEMORY: 2312 return (stash_scferror(lcbdata)); 2313 2314 case SCF_ERROR_INVALID_ARGUMENT: 2315 default: 2316 bad_error("scf_entry_create", scf_error()); 2317 } 2318 } 2319 2320 tp = p->sc_value_type; 2321 2322 if (scf_transaction_property_new(trans, entr, 2323 p->sc_property_name, tp) != 0) { 2324 switch (scf_error()) { 2325 case SCF_ERROR_INVALID_ARGUMENT: 2326 semerr(emsg_invalid_prop_name, p->sc_property_name); 2327 scf_entry_destroy(entr); 2328 return (stash_scferror(lcbdata)); 2329 2330 case SCF_ERROR_EXISTS: 2331 break; 2332 2333 case SCF_ERROR_DELETED: 2334 case SCF_ERROR_CONNECTION_BROKEN: 2335 scf_entry_destroy(entr); 2336 return (stash_scferror(lcbdata)); 2337 2338 case SCF_ERROR_NOT_BOUND: 2339 case SCF_ERROR_HANDLE_MISMATCH: 2340 case SCF_ERROR_NOT_SET: 2341 default: 2342 bad_error("scf_transaction_property_new", scf_error()); 2343 } 2344 2345 if (scf_transaction_property_change_type(trans, entr, 2346 p->sc_property_name, tp) != 0) { 2347 switch (scf_error()) { 2348 case SCF_ERROR_DELETED: 2349 case SCF_ERROR_CONNECTION_BROKEN: 2350 scf_entry_destroy(entr); 2351 return (stash_scferror(lcbdata)); 2352 2353 case SCF_ERROR_INVALID_ARGUMENT: 2354 semerr(emsg_invalid_prop_name, 2355 p->sc_property_name); 2356 scf_entry_destroy(entr); 2357 return (stash_scferror(lcbdata)); 2358 2359 case SCF_ERROR_NOT_FOUND: 2360 case SCF_ERROR_NOT_SET: 2361 case SCF_ERROR_HANDLE_MISMATCH: 2362 case SCF_ERROR_NOT_BOUND: 2363 default: 2364 bad_error( 2365 "scf_transaction_property_change_type", 2366 scf_error()); 2367 } 2368 } 2369 } 2370 2371 for (vp = uu_list_first(p->sc_property_values); 2372 vp != NULL; 2373 vp = uu_list_next(p->sc_property_values, vp)) { 2374 val = scf_value_create(g_hndl); 2375 if (val == NULL) { 2376 switch (scf_error()) { 2377 case SCF_ERROR_NO_MEMORY: 2378 return (stash_scferror(lcbdata)); 2379 2380 case SCF_ERROR_INVALID_ARGUMENT: 2381 default: 2382 bad_error("scf_value_create", scf_error()); 2383 } 2384 } 2385 2386 switch (tp) { 2387 case SCF_TYPE_BOOLEAN: 2388 scf_value_set_boolean(val, vp->sc_u.sc_count); 2389 break; 2390 case SCF_TYPE_COUNT: 2391 scf_value_set_count(val, vp->sc_u.sc_count); 2392 break; 2393 case SCF_TYPE_INTEGER: 2394 scf_value_set_integer(val, vp->sc_u.sc_integer); 2395 break; 2396 default: 2397 assert(vp->sc_u.sc_string != NULL); 2398 if (scf_value_set_from_string(val, tp, 2399 vp->sc_u.sc_string) != 0) { 2400 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 2401 bad_error("scf_value_set_from_string", 2402 scf_error()); 2403 2404 warn(gettext("Value \"%s\" is not a valid " 2405 "%s.\n"), vp->sc_u.sc_string, 2406 scf_type_to_string(tp)); 2407 scf_value_destroy(val); 2408 return (stash_scferror(lcbdata)); 2409 } 2410 break; 2411 } 2412 2413 if (scf_entry_add_value(entr, val) != 0) 2414 bad_error("scf_entry_add_value", scf_error()); 2415 } 2416 2417 return (UU_WALK_NEXT); 2418 } 2419 2420 /* 2421 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 2422 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 2423 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 2424 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2425 * lcbdata->sc_err to 2426 * ECONNABORTED - repository connection broken 2427 * ENOMEM - out of memory 2428 * ENOSPC - svc.configd is out of resources 2429 * ECANCELED - sc_parent was deleted 2430 * EPERM - could not create property group (permission denied) (error printed) 2431 * - could not modify property group (permission denied) (error printed) 2432 * - could not delete property group (permission denied) (error printed) 2433 * EROFS - could not create property group (repository is read-only) 2434 * - could not delete property group (repository is read-only) 2435 * EACCES - could not create property group (backend access denied) 2436 * - could not delete property group (backend access denied) 2437 * EEXIST - could not create property group (already exists) 2438 * EINVAL - invalid property group name (error printed) 2439 * - invalid property name (error printed) 2440 * - invalid value (error printed) 2441 * EBUSY - new property group deleted (error printed) 2442 * - new property group changed (error printed) 2443 * - property group added (error printed) 2444 * - property group deleted (error printed) 2445 */ 2446 static int 2447 entity_pgroup_import(void *v, void *pvt) 2448 { 2449 pgroup_t *p = v; 2450 scf_callback_t cbdata; 2451 scf_callback_t *lcbdata = pvt; 2452 void *ent = lcbdata->sc_parent; 2453 int issvc = lcbdata->sc_service; 2454 int r; 2455 2456 const char * const pg_changed = gettext("%s changed unexpectedly " 2457 "(new property group \"%s\" changed).\n"); 2458 2459 /* Never import deleted property groups. */ 2460 if (p->sc_pgroup_delete) { 2461 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY && 2462 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) { 2463 goto delete_pg; 2464 } 2465 return (UU_WALK_NEXT); 2466 } 2467 2468 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 2469 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 2470 lcbdata->sc_general = p; 2471 return (UU_WALK_NEXT); 2472 } 2473 2474 add_pg: 2475 if (issvc) 2476 r = scf_service_add_pg(ent, p->sc_pgroup_name, 2477 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2478 else 2479 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 2480 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2481 if (r != 0) { 2482 switch (scf_error()) { 2483 case SCF_ERROR_DELETED: 2484 case SCF_ERROR_CONNECTION_BROKEN: 2485 case SCF_ERROR_BACKEND_READONLY: 2486 case SCF_ERROR_BACKEND_ACCESS: 2487 case SCF_ERROR_NO_RESOURCES: 2488 return (stash_scferror(lcbdata)); 2489 2490 case SCF_ERROR_EXISTS: 2491 if (lcbdata->sc_flags & SCI_FORCE) 2492 break; 2493 return (stash_scferror(lcbdata)); 2494 2495 case SCF_ERROR_INVALID_ARGUMENT: 2496 warn(emsg_fmri_invalid_pg_name_type, 2497 lcbdata->sc_source_fmri, 2498 p->sc_pgroup_name, p->sc_pgroup_type); 2499 return (stash_scferror(lcbdata)); 2500 2501 case SCF_ERROR_PERMISSION_DENIED: 2502 warn(emsg_pg_add_perm, p->sc_pgroup_name, 2503 lcbdata->sc_target_fmri); 2504 return (stash_scferror(lcbdata)); 2505 2506 case SCF_ERROR_NOT_BOUND: 2507 case SCF_ERROR_HANDLE_MISMATCH: 2508 case SCF_ERROR_NOT_SET: 2509 default: 2510 bad_error("scf_service_add_pg", scf_error()); 2511 } 2512 2513 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2514 switch (scf_error()) { 2515 case SCF_ERROR_CONNECTION_BROKEN: 2516 case SCF_ERROR_DELETED: 2517 return (stash_scferror(lcbdata)); 2518 2519 case SCF_ERROR_INVALID_ARGUMENT: 2520 warn(emsg_fmri_invalid_pg_name, 2521 lcbdata->sc_source_fmri, 2522 p->sc_pgroup_name); 2523 return (stash_scferror(lcbdata)); 2524 2525 case SCF_ERROR_NOT_FOUND: 2526 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2527 p->sc_pgroup_name); 2528 lcbdata->sc_err = EBUSY; 2529 return (UU_WALK_ERROR); 2530 2531 case SCF_ERROR_NOT_BOUND: 2532 case SCF_ERROR_HANDLE_MISMATCH: 2533 case SCF_ERROR_NOT_SET: 2534 default: 2535 bad_error("entity_get_pg", scf_error()); 2536 } 2537 } 2538 2539 if (lcbdata->sc_flags & SCI_KEEP) 2540 goto props; 2541 2542 delete_pg: 2543 if (scf_pg_delete(imp_pg) != 0) { 2544 switch (scf_error()) { 2545 case SCF_ERROR_DELETED: 2546 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2547 p->sc_pgroup_name); 2548 lcbdata->sc_err = EBUSY; 2549 return (UU_WALK_ERROR); 2550 2551 case SCF_ERROR_PERMISSION_DENIED: 2552 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2553 lcbdata->sc_target_fmri); 2554 return (stash_scferror(lcbdata)); 2555 2556 case SCF_ERROR_BACKEND_READONLY: 2557 case SCF_ERROR_BACKEND_ACCESS: 2558 case SCF_ERROR_CONNECTION_BROKEN: 2559 return (stash_scferror(lcbdata)); 2560 2561 case SCF_ERROR_NOT_SET: 2562 default: 2563 bad_error("scf_pg_delete", scf_error()); 2564 } 2565 } 2566 2567 if (p->sc_pgroup_delete) 2568 return (UU_WALK_NEXT); 2569 2570 goto add_pg; 2571 } 2572 2573 props: 2574 2575 /* 2576 * Add properties to property group, if any. 2577 */ 2578 cbdata.sc_handle = lcbdata->sc_handle; 2579 cbdata.sc_parent = imp_pg; 2580 cbdata.sc_flags = lcbdata->sc_flags; 2581 cbdata.sc_trans = imp_tx; 2582 cbdata.sc_enable = NULL; 2583 2584 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2585 switch (scf_error()) { 2586 case SCF_ERROR_BACKEND_ACCESS: 2587 case SCF_ERROR_BACKEND_READONLY: 2588 case SCF_ERROR_CONNECTION_BROKEN: 2589 return (stash_scferror(lcbdata)); 2590 2591 case SCF_ERROR_DELETED: 2592 warn(pg_changed, lcbdata->sc_target_fmri, 2593 p->sc_pgroup_name); 2594 lcbdata->sc_err = EBUSY; 2595 return (UU_WALK_ERROR); 2596 2597 case SCF_ERROR_PERMISSION_DENIED: 2598 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2599 lcbdata->sc_target_fmri); 2600 return (stash_scferror(lcbdata)); 2601 2602 case SCF_ERROR_NOT_BOUND: 2603 case SCF_ERROR_NOT_SET: 2604 case SCF_ERROR_IN_USE: 2605 case SCF_ERROR_HANDLE_MISMATCH: 2606 default: 2607 bad_error("scf_transaction_start", scf_error()); 2608 } 2609 } 2610 2611 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2612 UU_DEFAULT) != 0) { 2613 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2614 bad_error("uu_list_walk", uu_error()); 2615 scf_transaction_reset(imp_tx); 2616 2617 lcbdata->sc_err = cbdata.sc_err; 2618 if (cbdata.sc_err == ECANCELED) { 2619 warn(pg_changed, lcbdata->sc_target_fmri, 2620 p->sc_pgroup_name); 2621 lcbdata->sc_err = EBUSY; 2622 } 2623 return (UU_WALK_ERROR); 2624 } 2625 2626 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2627 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2628 2629 /* 2630 * take the snapshot running snapshot then 2631 * import the stored general/enable property 2632 */ 2633 r = take_snap(ent, snap_running, imp_rsnap); 2634 switch (r) { 2635 case 0: 2636 break; 2637 2638 case ECONNABORTED: 2639 warn(gettext("Could not take %s snapshot on import " 2640 "(repository connection broken).\n"), 2641 snap_running); 2642 lcbdata->sc_err = r; 2643 return (UU_WALK_ERROR); 2644 case ECANCELED: 2645 warn(emsg_deleted); 2646 lcbdata->sc_err = r; 2647 return (UU_WALK_ERROR); 2648 2649 case EPERM: 2650 warn(gettext("Could not take %s snapshot " 2651 "(permission denied).\n"), snap_running); 2652 lcbdata->sc_err = r; 2653 return (UU_WALK_ERROR); 2654 2655 case ENOSPC: 2656 warn(gettext("Could not take %s snapshot" 2657 "(repository server out of resources).\n"), 2658 snap_running); 2659 lcbdata->sc_err = r; 2660 return (UU_WALK_ERROR); 2661 2662 default: 2663 bad_error("take_snap", r); 2664 } 2665 2666 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2667 if (r != UU_WALK_NEXT) { 2668 if (r != UU_WALK_ERROR) 2669 bad_error("lscf_property_import", r); 2670 return (EINVAL); 2671 } 2672 } 2673 2674 r = scf_transaction_commit(imp_tx); 2675 switch (r) { 2676 case 1: 2677 r = UU_WALK_NEXT; 2678 break; 2679 2680 case 0: 2681 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2682 lcbdata->sc_err = EBUSY; 2683 r = UU_WALK_ERROR; 2684 break; 2685 2686 case -1: 2687 switch (scf_error()) { 2688 case SCF_ERROR_BACKEND_READONLY: 2689 case SCF_ERROR_BACKEND_ACCESS: 2690 case SCF_ERROR_CONNECTION_BROKEN: 2691 case SCF_ERROR_NO_RESOURCES: 2692 r = stash_scferror(lcbdata); 2693 break; 2694 2695 case SCF_ERROR_DELETED: 2696 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2697 p->sc_pgroup_name); 2698 lcbdata->sc_err = EBUSY; 2699 r = UU_WALK_ERROR; 2700 break; 2701 2702 case SCF_ERROR_PERMISSION_DENIED: 2703 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2704 lcbdata->sc_target_fmri); 2705 r = stash_scferror(lcbdata); 2706 break; 2707 2708 case SCF_ERROR_NOT_SET: 2709 case SCF_ERROR_INVALID_ARGUMENT: 2710 case SCF_ERROR_NOT_BOUND: 2711 default: 2712 bad_error("scf_transaction_commit", scf_error()); 2713 } 2714 break; 2715 2716 default: 2717 bad_error("scf_transaction_commit", r); 2718 } 2719 2720 scf_transaction_destroy_children(imp_tx); 2721 2722 return (r); 2723 } 2724 2725 /* 2726 * Returns 2727 * 0 - success 2728 * ECONNABORTED - repository connection broken 2729 * ENOMEM - out of memory 2730 * ENOSPC - svc.configd is out of resources 2731 * ECANCELED - inst was deleted 2732 * EPERM - could not create property group (permission denied) (error printed) 2733 * - could not modify property group (permission denied) (error printed) 2734 * EROFS - could not create property group (repository is read-only) 2735 * EACCES - could not create property group (backend access denied) 2736 * EEXIST - could not create property group (already exists) 2737 * EINVAL - invalid property group name (error printed) 2738 * - invalid property name (error printed) 2739 * - invalid value (error printed) 2740 * EBUSY - new property group changed (error printed) 2741 */ 2742 static int 2743 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2744 const entity_t *isvc, int flags) 2745 { 2746 scf_callback_t cbdata; 2747 2748 cbdata.sc_handle = scf_service_handle(svc); 2749 cbdata.sc_parent = svc; 2750 cbdata.sc_service = 1; 2751 cbdata.sc_general = 0; 2752 cbdata.sc_enable = 0; 2753 cbdata.sc_flags = flags; 2754 cbdata.sc_source_fmri = isvc->sc_fmri; 2755 cbdata.sc_target_fmri = target_fmri; 2756 2757 /* 2758 * If the op is set, then add the flag to the callback 2759 * flags for later use. 2760 */ 2761 if (isvc->sc_op != SVCCFG_OP_NONE) { 2762 switch (isvc->sc_op) { 2763 case SVCCFG_OP_IMPORT : 2764 cbdata.sc_flags |= SCI_OP_IMPORT; 2765 break; 2766 case SVCCFG_OP_APPLY : 2767 cbdata.sc_flags |= SCI_OP_APPLY; 2768 break; 2769 case SVCCFG_OP_RESTORE : 2770 cbdata.sc_flags |= SCI_OP_RESTORE; 2771 break; 2772 default : 2773 uu_die(gettext("lscf_import_service_pgs : " 2774 "Unknown op stored in the service entity\n")); 2775 2776 } 2777 } 2778 2779 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2780 UU_DEFAULT) != 0) { 2781 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2782 bad_error("uu_list_walk", uu_error()); 2783 2784 return (cbdata.sc_err); 2785 } 2786 2787 return (0); 2788 } 2789 2790 /* 2791 * Returns 2792 * 0 - success 2793 * ECONNABORTED - repository connection broken 2794 * ENOMEM - out of memory 2795 * ENOSPC - svc.configd is out of resources 2796 * ECANCELED - inst was deleted 2797 * EPERM - could not create property group (permission denied) (error printed) 2798 * - could not modify property group (permission denied) (error printed) 2799 * EROFS - could not create property group (repository is read-only) 2800 * EACCES - could not create property group (backend access denied) 2801 * EEXIST - could not create property group (already exists) 2802 * EINVAL - invalid property group name (error printed) 2803 * - invalid property name (error printed) 2804 * - invalid value (error printed) 2805 * EBUSY - new property group changed (error printed) 2806 */ 2807 static int 2808 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2809 const entity_t *iinst, int flags) 2810 { 2811 scf_callback_t cbdata; 2812 2813 cbdata.sc_handle = scf_instance_handle(inst); 2814 cbdata.sc_parent = inst; 2815 cbdata.sc_service = 0; 2816 cbdata.sc_general = NULL; 2817 cbdata.sc_enable = NULL; 2818 cbdata.sc_flags = flags; 2819 cbdata.sc_source_fmri = iinst->sc_fmri; 2820 cbdata.sc_target_fmri = target_fmri; 2821 2822 /* 2823 * If the op is set, then add the flag to the callback 2824 * flags for later use. 2825 */ 2826 if (iinst->sc_op != SVCCFG_OP_NONE) { 2827 switch (iinst->sc_op) { 2828 case SVCCFG_OP_IMPORT : 2829 cbdata.sc_flags |= SCI_OP_IMPORT; 2830 break; 2831 case SVCCFG_OP_APPLY : 2832 cbdata.sc_flags |= SCI_OP_APPLY; 2833 break; 2834 case SVCCFG_OP_RESTORE : 2835 cbdata.sc_flags |= SCI_OP_RESTORE; 2836 break; 2837 default : 2838 uu_die(gettext("lscf_import_instance_pgs : " 2839 "Unknown op stored in the instance entity\n")); 2840 } 2841 } 2842 2843 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2844 UU_DEFAULT) != 0) { 2845 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2846 bad_error("uu_list_walk", uu_error()); 2847 2848 return (cbdata.sc_err); 2849 } 2850 2851 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2852 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2853 /* 2854 * If importing with the SCI_NOENABLED flag then 2855 * skip the delay, but if not then add the delay 2856 * of the enable property. 2857 */ 2858 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2859 cbdata.sc_flags |= SCI_DELAYENABLE; 2860 } 2861 2862 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2863 != UU_WALK_NEXT) 2864 return (cbdata.sc_err); 2865 } 2866 2867 return (0); 2868 } 2869 2870 /* 2871 * Report the reasons why we can't upgrade pg2 to pg1. 2872 */ 2873 static void 2874 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2875 int new) 2876 { 2877 property_t *p1, *p2; 2878 2879 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2880 2881 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2882 return; 2883 2884 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2885 p1 != NULL; 2886 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2887 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2888 if (p2 != NULL) { 2889 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2890 new); 2891 continue; 2892 } 2893 2894 if (new) 2895 warn(gettext("Conflict upgrading %s (new property " 2896 "group \"%s\" is missing property \"%s\").\n"), 2897 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2898 else 2899 warn(gettext("Conflict upgrading %s (property " 2900 "\"%s/%s\" is missing).\n"), fmri, 2901 pg1->sc_pgroup_name, p1->sc_property_name); 2902 } 2903 2904 /* 2905 * Since pg1 should be from the manifest, any properties in pg2 which 2906 * aren't in pg1 shouldn't be reported as conflicts. 2907 */ 2908 } 2909 2910 /* 2911 * Add transaction entries to tx which will upgrade cur's pg according to old 2912 * & new. 2913 * 2914 * Returns 2915 * 0 - success 2916 * EINVAL - new has a property with an invalid name or value (message emitted) 2917 * ENOMEM - out of memory 2918 */ 2919 static int 2920 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2921 pgroup_t *cur, int speak, const char *fmri) 2922 { 2923 property_t *p, *new_p, *cur_p; 2924 scf_transaction_entry_t *e; 2925 int r; 2926 int is_general; 2927 int is_protected; 2928 2929 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2930 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2931 bad_error("uu_list_walk", uu_error()); 2932 2933 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2934 2935 for (p = uu_list_first(old->sc_pgroup_props); 2936 p != NULL; 2937 p = uu_list_next(old->sc_pgroup_props, p)) { 2938 /* p is a property in the old property group. */ 2939 2940 /* Protect live properties. */ 2941 is_protected = 0; 2942 if (is_general) { 2943 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2944 0 || 2945 strcmp(p->sc_property_name, 2946 SCF_PROPERTY_RESTARTER) == 0) 2947 is_protected = 1; 2948 } 2949 2950 /* Look for the same property in the new properties. */ 2951 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2952 if (new_p != NULL) { 2953 new_p->sc_seen = 1; 2954 2955 /* 2956 * If the new property is the same as the old, don't do 2957 * anything (leave any user customizations). 2958 */ 2959 if (prop_equal(p, new_p, NULL, NULL, 0)) 2960 continue; 2961 2962 if (new_p->sc_property_override) 2963 goto upgrade; 2964 } 2965 2966 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2967 if (cur_p == NULL) { 2968 /* 2969 * p has been deleted from the repository. If we were 2970 * going to delete it anyway, do nothing. Otherwise 2971 * report a conflict. 2972 */ 2973 if (new_p == NULL) 2974 continue; 2975 2976 if (is_protected) 2977 continue; 2978 2979 warn(gettext("Conflict upgrading %s " 2980 "(property \"%s/%s\" is missing).\n"), fmri, 2981 old->sc_pgroup_name, p->sc_property_name); 2982 continue; 2983 } 2984 2985 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2986 /* 2987 * Conflict. Don't warn if the property is already the 2988 * way we want it, though. 2989 */ 2990 if (is_protected) 2991 continue; 2992 2993 if (new_p == NULL) 2994 (void) prop_equal(p, cur_p, fmri, 2995 old->sc_pgroup_name, 0); 2996 else 2997 (void) prop_equal(cur_p, new_p, fmri, 2998 old->sc_pgroup_name, 0); 2999 continue; 3000 } 3001 3002 if (is_protected) { 3003 if (speak) 3004 warn(gettext("%s: Refusing to upgrade " 3005 "\"%s/%s\" (live property).\n"), fmri, 3006 old->sc_pgroup_name, p->sc_property_name); 3007 continue; 3008 } 3009 3010 upgrade: 3011 /* p hasn't been customized in the repository. Upgrade it. */ 3012 if (new_p == NULL) { 3013 /* p was deleted. Delete from cur if unchanged. */ 3014 if (speak) 3015 warn(gettext( 3016 "%s: Deleting property \"%s/%s\".\n"), 3017 fmri, old->sc_pgroup_name, 3018 p->sc_property_name); 3019 3020 e = scf_entry_create(g_hndl); 3021 if (e == NULL) 3022 return (ENOMEM); 3023 3024 if (scf_transaction_property_delete(tx, e, 3025 p->sc_property_name) != 0) { 3026 switch (scf_error()) { 3027 case SCF_ERROR_DELETED: 3028 scf_entry_destroy(e); 3029 return (ECANCELED); 3030 3031 case SCF_ERROR_CONNECTION_BROKEN: 3032 scf_entry_destroy(e); 3033 return (ECONNABORTED); 3034 3035 case SCF_ERROR_NOT_FOUND: 3036 /* 3037 * This can happen if cur is from the 3038 * running snapshot (and it differs 3039 * from the live properties). 3040 */ 3041 scf_entry_destroy(e); 3042 break; 3043 3044 case SCF_ERROR_HANDLE_MISMATCH: 3045 case SCF_ERROR_NOT_BOUND: 3046 case SCF_ERROR_NOT_SET: 3047 case SCF_ERROR_INVALID_ARGUMENT: 3048 default: 3049 bad_error( 3050 "scf_transaction_property_delete", 3051 scf_error()); 3052 } 3053 } 3054 } else { 3055 scf_callback_t ctx; 3056 3057 if (speak) 3058 warn(gettext( 3059 "%s: Upgrading property \"%s/%s\".\n"), 3060 fmri, old->sc_pgroup_name, 3061 p->sc_property_name); 3062 3063 ctx.sc_handle = g_hndl; 3064 ctx.sc_trans = tx; 3065 ctx.sc_flags = 0; 3066 3067 r = lscf_property_import(new_p, &ctx); 3068 if (r != UU_WALK_NEXT) { 3069 if (r != UU_WALK_ERROR) 3070 bad_error("lscf_property_import", r); 3071 return (EINVAL); 3072 } 3073 } 3074 } 3075 3076 /* Go over the properties which were added. */ 3077 for (new_p = uu_list_first(new->sc_pgroup_props); 3078 new_p != NULL; 3079 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 3080 if (new_p->sc_seen) 3081 continue; 3082 3083 /* This is a new property. */ 3084 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 3085 if (cur_p == NULL) { 3086 scf_callback_t ctx; 3087 3088 ctx.sc_handle = g_hndl; 3089 ctx.sc_trans = tx; 3090 ctx.sc_flags = 0; 3091 3092 r = lscf_property_import(new_p, &ctx); 3093 if (r != UU_WALK_NEXT) { 3094 if (r != UU_WALK_ERROR) 3095 bad_error("lscf_property_import", r); 3096 return (EINVAL); 3097 } 3098 continue; 3099 } 3100 3101 /* 3102 * Report a conflict if the new property differs from the 3103 * current one. Unless it's general/enabled, since that's 3104 * never in the last-import snapshot. 3105 */ 3106 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 3107 0 && 3108 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 3109 continue; 3110 3111 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 3112 } 3113 3114 return (0); 3115 } 3116 3117 /* 3118 * Upgrade pg according to old & new. 3119 * 3120 * Returns 3121 * 0 - success 3122 * ECONNABORTED - repository connection broken 3123 * ENOMEM - out of memory 3124 * ENOSPC - svc.configd is out of resources 3125 * ECANCELED - pg was deleted 3126 * EPERM - couldn't modify pg (permission denied) 3127 * EROFS - couldn't modify pg (backend read-only) 3128 * EACCES - couldn't modify pg (backend access denied) 3129 * EINVAL - new has a property with invalid name or value (error printed) 3130 * EBUSY - pg changed unexpectedly 3131 */ 3132 static int 3133 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 3134 pgroup_t *new, int speak, const char *fmri) 3135 { 3136 int r; 3137 3138 if (scf_transaction_start(imp_tx, pg) != 0) { 3139 switch (scf_error()) { 3140 case SCF_ERROR_CONNECTION_BROKEN: 3141 case SCF_ERROR_DELETED: 3142 case SCF_ERROR_PERMISSION_DENIED: 3143 case SCF_ERROR_BACKEND_READONLY: 3144 case SCF_ERROR_BACKEND_ACCESS: 3145 return (scferror2errno(scf_error())); 3146 3147 case SCF_ERROR_HANDLE_MISMATCH: 3148 case SCF_ERROR_IN_USE: 3149 case SCF_ERROR_NOT_BOUND: 3150 case SCF_ERROR_NOT_SET: 3151 default: 3152 bad_error("scf_transaction_start", scf_error()); 3153 } 3154 } 3155 3156 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 3157 switch (r) { 3158 case 0: 3159 break; 3160 3161 case EINVAL: 3162 case ENOMEM: 3163 scf_transaction_destroy_children(imp_tx); 3164 return (r); 3165 3166 default: 3167 bad_error("add_upgrade_entries", r); 3168 } 3169 3170 r = scf_transaction_commit(imp_tx); 3171 3172 scf_transaction_destroy_children(imp_tx); 3173 3174 switch (r) { 3175 case 1: 3176 break; 3177 3178 case 0: 3179 return (EBUSY); 3180 3181 case -1: 3182 switch (scf_error()) { 3183 case SCF_ERROR_CONNECTION_BROKEN: 3184 case SCF_ERROR_NO_RESOURCES: 3185 case SCF_ERROR_PERMISSION_DENIED: 3186 case SCF_ERROR_BACKEND_READONLY: 3187 case SCF_ERROR_BACKEND_ACCESS: 3188 case SCF_ERROR_DELETED: 3189 return (scferror2errno(scf_error())); 3190 3191 case SCF_ERROR_NOT_BOUND: 3192 case SCF_ERROR_INVALID_ARGUMENT: 3193 case SCF_ERROR_NOT_SET: 3194 default: 3195 bad_error("scf_transaction_commit", scf_error()); 3196 } 3197 3198 default: 3199 bad_error("scf_transaction_commit", r); 3200 } 3201 3202 return (0); 3203 } 3204 3205 /* 3206 * Compares two entity FMRIs. Returns 3207 * 3208 * 1 - equal 3209 * 0 - not equal 3210 * -1 - f1 is invalid or not an entity 3211 * -2 - f2 is invalid or not an entity 3212 */ 3213 static int 3214 fmri_equal(const char *f1, const char *f2) 3215 { 3216 int r; 3217 const char *s1, *i1, *pg1; 3218 const char *s2, *i2, *pg2; 3219 3220 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3221 return (-1); 3222 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 3223 return (-1); 3224 3225 if (s1 == NULL || pg1 != NULL) 3226 return (-1); 3227 3228 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3229 return (-2); 3230 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 3231 return (-2); 3232 3233 if (s2 == NULL || pg2 != NULL) 3234 return (-2); 3235 3236 r = strcmp(s1, s2); 3237 if (r != 0) 3238 return (0); 3239 3240 if (i1 == NULL && i2 == NULL) 3241 return (1); 3242 3243 if (i1 == NULL || i2 == NULL) 3244 return (0); 3245 3246 return (strcmp(i1, i2) == 0); 3247 } 3248 3249 /* 3250 * Import a dependent by creating a dependency property group in the dependent 3251 * entity. If lcbdata->sc_trans is set, assume it's been started on the 3252 * dependents pg, and add an entry to create a new property for this 3253 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 3254 * 3255 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 3256 * lcbdata->sc_err to 3257 * ECONNABORTED - repository connection broken 3258 * ENOMEM - out of memory 3259 * ENOSPC - configd is out of resources 3260 * EINVAL - target is invalid (error printed) 3261 * - target is not an entity (error printed) 3262 * - dependent has invalid name (error printed) 3263 * - invalid property name (error printed) 3264 * - invalid value (error printed) 3265 * - scope of target does not exist (error printed) 3266 * EPERM - couldn't create target (permission denied) (error printed) 3267 * - couldn't create dependency pg (permission denied) (error printed) 3268 * - couldn't modify dependency pg (permission denied) (error printed) 3269 * EROFS - couldn't create target (repository read-only) 3270 * - couldn't create dependency pg (repository read-only) 3271 * EACCES - couldn't create target (backend access denied) 3272 * - couldn't create dependency pg (backend access denied) 3273 * ECANCELED - sc_trans's pg was deleted 3274 * EALREADY - property for dependent already exists in sc_trans's pg 3275 * EEXIST - dependency pg already exists in target (error printed) 3276 * EBUSY - target deleted (error printed) 3277 * - property group changed during import (error printed) 3278 */ 3279 static int 3280 lscf_dependent_import(void *a1, void *pvt) 3281 { 3282 pgroup_t *pgrp = a1; 3283 scf_callback_t *lcbdata = pvt; 3284 3285 int isservice; 3286 int ret; 3287 scf_transaction_entry_t *e; 3288 scf_value_t *val; 3289 scf_callback_t dependent_cbdata; 3290 scf_error_t scfe; 3291 3292 /* 3293 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 3294 * it's invalid, we fail before modifying the repository. 3295 */ 3296 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3297 &dependent_cbdata.sc_parent, &isservice); 3298 switch (scfe) { 3299 case SCF_ERROR_NONE: 3300 break; 3301 3302 case SCF_ERROR_NO_MEMORY: 3303 return (stash_scferror_err(lcbdata, scfe)); 3304 3305 case SCF_ERROR_INVALID_ARGUMENT: 3306 semerr(gettext("The FMRI for the \"%s\" dependent is " 3307 "invalid.\n"), pgrp->sc_pgroup_name); 3308 return (stash_scferror_err(lcbdata, scfe)); 3309 3310 case SCF_ERROR_CONSTRAINT_VIOLATED: 3311 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 3312 "specifies neither a service nor an instance.\n"), 3313 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3314 return (stash_scferror_err(lcbdata, scfe)); 3315 3316 case SCF_ERROR_NOT_FOUND: 3317 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3318 &dependent_cbdata.sc_parent, &isservice); 3319 switch (scfe) { 3320 case SCF_ERROR_NONE: 3321 break; 3322 3323 case SCF_ERROR_NO_MEMORY: 3324 case SCF_ERROR_BACKEND_READONLY: 3325 case SCF_ERROR_BACKEND_ACCESS: 3326 return (stash_scferror_err(lcbdata, scfe)); 3327 3328 case SCF_ERROR_NOT_FOUND: 3329 semerr(gettext("The scope in FMRI \"%s\" for the " 3330 "\"%s\" dependent does not exist.\n"), 3331 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3332 lcbdata->sc_err = EINVAL; 3333 return (UU_WALK_ERROR); 3334 3335 case SCF_ERROR_PERMISSION_DENIED: 3336 warn(gettext( 3337 "Could not create %s (permission denied).\n"), 3338 pgrp->sc_pgroup_fmri); 3339 return (stash_scferror_err(lcbdata, scfe)); 3340 3341 case SCF_ERROR_INVALID_ARGUMENT: 3342 case SCF_ERROR_CONSTRAINT_VIOLATED: 3343 default: 3344 bad_error("create_entity", scfe); 3345 } 3346 break; 3347 3348 default: 3349 bad_error("fmri_to_entity", scfe); 3350 } 3351 3352 if (lcbdata->sc_trans != NULL) { 3353 e = scf_entry_create(lcbdata->sc_handle); 3354 if (e == NULL) { 3355 if (scf_error() != SCF_ERROR_NO_MEMORY) 3356 bad_error("scf_entry_create", scf_error()); 3357 3358 entity_destroy(dependent_cbdata.sc_parent, isservice); 3359 return (stash_scferror(lcbdata)); 3360 } 3361 3362 if (scf_transaction_property_new(lcbdata->sc_trans, e, 3363 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 3364 switch (scf_error()) { 3365 case SCF_ERROR_INVALID_ARGUMENT: 3366 warn(gettext("Dependent of %s has invalid name " 3367 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 3368 pgrp->sc_pgroup_name); 3369 /* FALLTHROUGH */ 3370 3371 case SCF_ERROR_DELETED: 3372 case SCF_ERROR_CONNECTION_BROKEN: 3373 scf_entry_destroy(e); 3374 entity_destroy(dependent_cbdata.sc_parent, 3375 isservice); 3376 return (stash_scferror(lcbdata)); 3377 3378 case SCF_ERROR_EXISTS: 3379 scf_entry_destroy(e); 3380 entity_destroy(dependent_cbdata.sc_parent, 3381 isservice); 3382 lcbdata->sc_err = EALREADY; 3383 return (UU_WALK_ERROR); 3384 3385 case SCF_ERROR_NOT_BOUND: 3386 case SCF_ERROR_HANDLE_MISMATCH: 3387 case SCF_ERROR_NOT_SET: 3388 default: 3389 bad_error("scf_transaction_property_new", 3390 scf_error()); 3391 } 3392 } 3393 3394 val = scf_value_create(lcbdata->sc_handle); 3395 if (val == NULL) { 3396 if (scf_error() != SCF_ERROR_NO_MEMORY) 3397 bad_error("scf_value_create", scf_error()); 3398 3399 entity_destroy(dependent_cbdata.sc_parent, isservice); 3400 return (stash_scferror(lcbdata)); 3401 } 3402 3403 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3404 pgrp->sc_pgroup_fmri) != 0) 3405 /* invalid should have been caught above */ 3406 bad_error("scf_value_set_from_string", scf_error()); 3407 3408 if (scf_entry_add_value(e, val) != 0) 3409 bad_error("scf_entry_add_value", scf_error()); 3410 } 3411 3412 /* Add the property group to the target entity. */ 3413 3414 dependent_cbdata.sc_handle = lcbdata->sc_handle; 3415 dependent_cbdata.sc_flags = lcbdata->sc_flags; 3416 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 3417 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 3418 3419 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 3420 3421 entity_destroy(dependent_cbdata.sc_parent, isservice); 3422 3423 if (ret == UU_WALK_NEXT) 3424 return (ret); 3425 3426 if (ret != UU_WALK_ERROR) 3427 bad_error("entity_pgroup_import", ret); 3428 3429 switch (dependent_cbdata.sc_err) { 3430 case ECANCELED: 3431 warn(gettext("%s deleted unexpectedly.\n"), 3432 pgrp->sc_pgroup_fmri); 3433 lcbdata->sc_err = EBUSY; 3434 break; 3435 3436 case EEXIST: 3437 warn(gettext("Could not create \"%s\" dependency in %s " 3438 "(already exists).\n"), pgrp->sc_pgroup_name, 3439 pgrp->sc_pgroup_fmri); 3440 /* FALLTHROUGH */ 3441 3442 default: 3443 lcbdata->sc_err = dependent_cbdata.sc_err; 3444 } 3445 3446 return (UU_WALK_ERROR); 3447 } 3448 3449 static int upgrade_dependent(const scf_property_t *, const entity_t *, 3450 const scf_snaplevel_t *, scf_transaction_t *); 3451 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 3452 const pgroup_t *); 3453 3454 /* 3455 * Upgrade uncustomized dependents of ent to those specified in ient. Read 3456 * the current dependent targets from running (the snaplevel of a running 3457 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 3458 * scf_instance_t * according to ient, otherwise). Draw the ancestral 3459 * dependent targets and dependency properties from li_dpts_pg (the 3460 * "dependents" property group in snpl) and snpl (the snaplevel which 3461 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 3462 * snpl doesn't have a "dependents" property group, and any dependents in ient 3463 * are new. 3464 * 3465 * Returns 3466 * 0 - success 3467 * ECONNABORTED - repository connection broken 3468 * ENOMEM - out of memory 3469 * ENOSPC - configd is out of resources 3470 * ECANCELED - ent was deleted 3471 * ENODEV - the entity containing li_dpts_pg was deleted 3472 * EPERM - could not modify dependents pg (permission denied) (error printed) 3473 * - couldn't upgrade dependent (permission denied) (error printed) 3474 * - couldn't create dependent (permission denied) (error printed) 3475 * EROFS - could not modify dependents pg (repository read-only) 3476 * - couldn't upgrade dependent (repository read-only) 3477 * - couldn't create dependent (repository read-only) 3478 * EACCES - could not modify dependents pg (backend access denied) 3479 * - could not upgrade dependent (backend access denied) 3480 * - could not create dependent (backend access denied) 3481 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 3482 * - dependent target deleted (error printed) 3483 * - dependent pg changed (error printed) 3484 * EINVAL - new dependent is invalid (error printed) 3485 * EBADF - snpl is corrupt (error printed) 3486 * - snpl has corrupt pg (error printed) 3487 * - dependency pg in target is corrupt (error printed) 3488 * - target has corrupt snapshot (error printed) 3489 * EEXIST - dependency pg already existed in target service (error printed) 3490 */ 3491 static int 3492 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 3493 const scf_snaplevel_t *snpl, const entity_t *ient, 3494 const scf_snaplevel_t *running, void *ent) 3495 { 3496 pgroup_t *new_dpt_pgroup; 3497 scf_callback_t cbdata; 3498 int r, unseen, tx_started = 0; 3499 int have_cur_depts; 3500 3501 const char * const dependents = "dependents"; 3502 3503 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3504 3505 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 3506 /* Nothing to do. */ 3507 return (0); 3508 3509 /* Fetch the current version of the "dependents" property group. */ 3510 have_cur_depts = 1; 3511 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 3512 switch (scf_error()) { 3513 case SCF_ERROR_NOT_FOUND: 3514 break; 3515 3516 case SCF_ERROR_DELETED: 3517 case SCF_ERROR_CONNECTION_BROKEN: 3518 return (scferror2errno(scf_error())); 3519 3520 case SCF_ERROR_NOT_SET: 3521 case SCF_ERROR_INVALID_ARGUMENT: 3522 case SCF_ERROR_HANDLE_MISMATCH: 3523 case SCF_ERROR_NOT_BOUND: 3524 default: 3525 bad_error("entity_get_pg", scf_error()); 3526 } 3527 3528 have_cur_depts = 0; 3529 } 3530 3531 /* Fetch the running version of the "dependents" property group. */ 3532 ud_run_dpts_pg_set = 0; 3533 if (running != NULL) 3534 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 3535 else 3536 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 3537 if (r == 0) { 3538 ud_run_dpts_pg_set = 1; 3539 } else { 3540 switch (scf_error()) { 3541 case SCF_ERROR_NOT_FOUND: 3542 break; 3543 3544 case SCF_ERROR_DELETED: 3545 case SCF_ERROR_CONNECTION_BROKEN: 3546 return (scferror2errno(scf_error())); 3547 3548 case SCF_ERROR_NOT_SET: 3549 case SCF_ERROR_INVALID_ARGUMENT: 3550 case SCF_ERROR_HANDLE_MISMATCH: 3551 case SCF_ERROR_NOT_BOUND: 3552 default: 3553 bad_error(running ? "scf_snaplevel_get_pg" : 3554 "entity_get_pg", scf_error()); 3555 } 3556 } 3557 3558 /* 3559 * Clear the seen fields of the dependents, so we can tell which ones 3560 * are new. 3561 */ 3562 if (uu_list_walk(ient->sc_dependents, clear_int, 3563 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3564 bad_error("uu_list_walk", uu_error()); 3565 3566 if (li_dpts_pg != NULL) { 3567 /* 3568 * Each property in li_dpts_pg represents a dependent tag in 3569 * the old manifest. For each, call upgrade_dependent(), 3570 * which will change ud_cur_depts_pg or dependencies in other 3571 * services as appropriate. Note (a) that changes to 3572 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3573 * made en masse, and (b) it's ok if the entity doesn't have 3574 * a current version of the "dependents" property group, 3575 * because we'll just consider all dependents as customized 3576 * (by being deleted). 3577 */ 3578 3579 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3580 switch (scf_error()) { 3581 case SCF_ERROR_DELETED: 3582 return (ENODEV); 3583 3584 case SCF_ERROR_CONNECTION_BROKEN: 3585 return (ECONNABORTED); 3586 3587 case SCF_ERROR_HANDLE_MISMATCH: 3588 case SCF_ERROR_NOT_BOUND: 3589 case SCF_ERROR_NOT_SET: 3590 default: 3591 bad_error("scf_iter_pg_properties", 3592 scf_error()); 3593 } 3594 } 3595 3596 if (have_cur_depts && 3597 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3598 switch (scf_error()) { 3599 case SCF_ERROR_BACKEND_ACCESS: 3600 case SCF_ERROR_BACKEND_READONLY: 3601 case SCF_ERROR_CONNECTION_BROKEN: 3602 return (scferror2errno(scf_error())); 3603 3604 case SCF_ERROR_DELETED: 3605 warn(emsg_pg_deleted, ient->sc_fmri, 3606 dependents); 3607 return (EBUSY); 3608 3609 case SCF_ERROR_PERMISSION_DENIED: 3610 warn(emsg_pg_mod_perm, dependents, 3611 ient->sc_fmri); 3612 return (scferror2errno(scf_error())); 3613 3614 case SCF_ERROR_HANDLE_MISMATCH: 3615 case SCF_ERROR_IN_USE: 3616 case SCF_ERROR_NOT_BOUND: 3617 case SCF_ERROR_NOT_SET: 3618 default: 3619 bad_error("scf_transaction_start", scf_error()); 3620 } 3621 } 3622 tx_started = have_cur_depts; 3623 3624 for (;;) { 3625 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3626 if (r == 0) 3627 break; 3628 if (r == 1) { 3629 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3630 tx_started ? ud_tx : NULL); 3631 switch (r) { 3632 case 0: 3633 continue; 3634 3635 case ECONNABORTED: 3636 case ENOMEM: 3637 case ENOSPC: 3638 case EBADF: 3639 case EBUSY: 3640 case EINVAL: 3641 case EPERM: 3642 case EROFS: 3643 case EACCES: 3644 case EEXIST: 3645 break; 3646 3647 case ECANCELED: 3648 r = ENODEV; 3649 break; 3650 3651 default: 3652 bad_error("upgrade_dependent", r); 3653 } 3654 3655 if (tx_started) 3656 scf_transaction_destroy_children(ud_tx); 3657 return (r); 3658 } 3659 if (r != -1) 3660 bad_error("scf_iter_next_property", r); 3661 3662 switch (scf_error()) { 3663 case SCF_ERROR_DELETED: 3664 r = ENODEV; 3665 break; 3666 3667 case SCF_ERROR_CONNECTION_BROKEN: 3668 r = ECONNABORTED; 3669 break; 3670 3671 case SCF_ERROR_NOT_SET: 3672 case SCF_ERROR_INVALID_ARGUMENT: 3673 case SCF_ERROR_NOT_BOUND: 3674 case SCF_ERROR_HANDLE_MISMATCH: 3675 default: 3676 bad_error("scf_iter_next_property", 3677 scf_error()); 3678 } 3679 3680 if (tx_started) 3681 scf_transaction_destroy_children(ud_tx); 3682 return (r); 3683 } 3684 } 3685 3686 /* import unseen dependents */ 3687 unseen = 0; 3688 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3689 new_dpt_pgroup != NULL; 3690 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3691 new_dpt_pgroup)) { 3692 if (!new_dpt_pgroup->sc_pgroup_seen) { 3693 unseen = 1; 3694 break; 3695 } 3696 } 3697 3698 /* If there are none, exit early. */ 3699 if (unseen == 0) 3700 goto commit; 3701 3702 /* Set up for lscf_dependent_import() */ 3703 cbdata.sc_handle = g_hndl; 3704 cbdata.sc_parent = ent; 3705 cbdata.sc_service = issvc; 3706 cbdata.sc_flags = 0; 3707 3708 if (!have_cur_depts) { 3709 /* 3710 * We have new dependents to import, so we need a "dependents" 3711 * property group. 3712 */ 3713 if (issvc) 3714 r = scf_service_add_pg(ent, dependents, 3715 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3716 else 3717 r = scf_instance_add_pg(ent, dependents, 3718 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3719 if (r != 0) { 3720 switch (scf_error()) { 3721 case SCF_ERROR_DELETED: 3722 case SCF_ERROR_CONNECTION_BROKEN: 3723 case SCF_ERROR_BACKEND_READONLY: 3724 case SCF_ERROR_BACKEND_ACCESS: 3725 case SCF_ERROR_NO_RESOURCES: 3726 return (scferror2errno(scf_error())); 3727 3728 case SCF_ERROR_EXISTS: 3729 warn(emsg_pg_added, ient->sc_fmri, dependents); 3730 return (EBUSY); 3731 3732 case SCF_ERROR_PERMISSION_DENIED: 3733 warn(emsg_pg_add_perm, dependents, 3734 ient->sc_fmri); 3735 return (scferror2errno(scf_error())); 3736 3737 case SCF_ERROR_NOT_BOUND: 3738 case SCF_ERROR_HANDLE_MISMATCH: 3739 case SCF_ERROR_INVALID_ARGUMENT: 3740 case SCF_ERROR_NOT_SET: 3741 default: 3742 bad_error("scf_service_add_pg", scf_error()); 3743 } 3744 } 3745 } 3746 3747 cbdata.sc_trans = ud_tx; 3748 3749 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3750 switch (scf_error()) { 3751 case SCF_ERROR_CONNECTION_BROKEN: 3752 case SCF_ERROR_BACKEND_ACCESS: 3753 case SCF_ERROR_BACKEND_READONLY: 3754 return (scferror2errno(scf_error())); 3755 3756 case SCF_ERROR_DELETED: 3757 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3758 return (EBUSY); 3759 3760 case SCF_ERROR_PERMISSION_DENIED: 3761 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3762 return (scferror2errno(scf_error())); 3763 3764 case SCF_ERROR_HANDLE_MISMATCH: 3765 case SCF_ERROR_IN_USE: 3766 case SCF_ERROR_NOT_BOUND: 3767 case SCF_ERROR_NOT_SET: 3768 default: 3769 bad_error("scf_transaction_start", scf_error()); 3770 } 3771 } 3772 tx_started = 1; 3773 3774 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3775 new_dpt_pgroup != NULL; 3776 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3777 new_dpt_pgroup)) { 3778 if (new_dpt_pgroup->sc_pgroup_seen) 3779 continue; 3780 3781 if (ud_run_dpts_pg_set) { 3782 /* 3783 * If the dependent is already there, then we have 3784 * a conflict. 3785 */ 3786 if (scf_pg_get_property(ud_run_dpts_pg, 3787 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3788 r = handle_dependent_conflict(ient, ud_prop, 3789 new_dpt_pgroup); 3790 switch (r) { 3791 case 0: 3792 continue; 3793 3794 case ECONNABORTED: 3795 case ENOMEM: 3796 case EBUSY: 3797 case EBADF: 3798 case EINVAL: 3799 scf_transaction_destroy_children(ud_tx); 3800 return (r); 3801 3802 default: 3803 bad_error("handle_dependent_conflict", 3804 r); 3805 } 3806 } else { 3807 switch (scf_error()) { 3808 case SCF_ERROR_NOT_FOUND: 3809 break; 3810 3811 case SCF_ERROR_INVALID_ARGUMENT: 3812 warn(emsg_fmri_invalid_pg_name, 3813 ient->sc_fmri, 3814 new_dpt_pgroup->sc_pgroup_name); 3815 scf_transaction_destroy_children(ud_tx); 3816 return (EINVAL); 3817 3818 case SCF_ERROR_DELETED: 3819 warn(emsg_pg_deleted, ient->sc_fmri, 3820 new_dpt_pgroup->sc_pgroup_name); 3821 scf_transaction_destroy_children(ud_tx); 3822 return (EBUSY); 3823 3824 case SCF_ERROR_CONNECTION_BROKEN: 3825 scf_transaction_destroy_children(ud_tx); 3826 return (ECONNABORTED); 3827 3828 case SCF_ERROR_NOT_BOUND: 3829 case SCF_ERROR_HANDLE_MISMATCH: 3830 case SCF_ERROR_NOT_SET: 3831 default: 3832 bad_error("scf_pg_get_property", 3833 scf_error()); 3834 } 3835 } 3836 } 3837 3838 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3839 if (r != UU_WALK_NEXT) { 3840 if (r != UU_WALK_ERROR) 3841 bad_error("lscf_dependent_import", r); 3842 3843 if (cbdata.sc_err == EALREADY) { 3844 /* Collisions were handled preemptively. */ 3845 bad_error("lscf_dependent_import", 3846 cbdata.sc_err); 3847 } 3848 3849 scf_transaction_destroy_children(ud_tx); 3850 return (cbdata.sc_err); 3851 } 3852 } 3853 3854 commit: 3855 if (!tx_started) 3856 return (0); 3857 3858 r = scf_transaction_commit(ud_tx); 3859 3860 scf_transaction_destroy_children(ud_tx); 3861 3862 switch (r) { 3863 case 1: 3864 return (0); 3865 3866 case 0: 3867 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3868 return (EBUSY); 3869 3870 case -1: 3871 break; 3872 3873 default: 3874 bad_error("scf_transaction_commit", r); 3875 } 3876 3877 switch (scf_error()) { 3878 case SCF_ERROR_CONNECTION_BROKEN: 3879 case SCF_ERROR_BACKEND_READONLY: 3880 case SCF_ERROR_BACKEND_ACCESS: 3881 case SCF_ERROR_NO_RESOURCES: 3882 return (scferror2errno(scf_error())); 3883 3884 case SCF_ERROR_DELETED: 3885 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3886 return (EBUSY); 3887 3888 case SCF_ERROR_PERMISSION_DENIED: 3889 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3890 return (scferror2errno(scf_error())); 3891 3892 case SCF_ERROR_NOT_BOUND: 3893 case SCF_ERROR_INVALID_ARGUMENT: 3894 case SCF_ERROR_NOT_SET: 3895 default: 3896 bad_error("scf_transaction_destroy", scf_error()); 3897 /* NOTREACHED */ 3898 } 3899 } 3900 3901 /* 3902 * Used to add the manifests to the list of currently supported manifests. 3903 * We can modify the existing manifest list removing entries if the files 3904 * don't exist. 3905 * 3906 * Get the old list and the new file name 3907 * If the new file name is in the list return 3908 * If not then add the file to the list. 3909 * As we process the list check to see if the files in the old list exist 3910 * if not then remove the file from the list. 3911 * Commit the list of manifest file names. 3912 * 3913 */ 3914 static int 3915 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient, 3916 const scf_snaplevel_t *running, void *ent) 3917 { 3918 scf_propertygroup_t *ud_mfsts_pg = NULL; 3919 scf_property_t *ud_prop = NULL; 3920 scf_iter_t *ud_prop_iter; 3921 scf_value_t *fname_value; 3922 scf_callback_t cbdata; 3923 pgroup_t *mfst_pgroup; 3924 property_t *mfst_prop; 3925 property_t *old_prop; 3926 char *pname; 3927 char *fval; 3928 char *old_pname; 3929 char *old_fval; 3930 int no_upgrade_pg; 3931 int mfst_seen; 3932 int r; 3933 3934 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3935 3936 /* 3937 * This should always be the service base on the code 3938 * path, and the fact that the manifests pg is a service 3939 * level property group only. 3940 */ 3941 ud_mfsts_pg = scf_pg_create(g_hndl); 3942 ud_prop = scf_property_create(g_hndl); 3943 ud_prop_iter = scf_iter_create(g_hndl); 3944 fname_value = scf_value_create(g_hndl); 3945 3946 /* Fetch the "manifests" property group */ 3947 no_upgrade_pg = 0; 3948 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3949 ud_mfsts_pg); 3950 if (r != 0) { 3951 switch (scf_error()) { 3952 case SCF_ERROR_NOT_FOUND: 3953 no_upgrade_pg = 1; 3954 break; 3955 3956 case SCF_ERROR_DELETED: 3957 case SCF_ERROR_CONNECTION_BROKEN: 3958 return (scferror2errno(scf_error())); 3959 3960 case SCF_ERROR_NOT_SET: 3961 case SCF_ERROR_INVALID_ARGUMENT: 3962 case SCF_ERROR_HANDLE_MISMATCH: 3963 case SCF_ERROR_NOT_BOUND: 3964 default: 3965 bad_error(running ? "scf_snaplevel_get_pg" : 3966 "entity_get_pg", scf_error()); 3967 } 3968 } 3969 3970 if (no_upgrade_pg) { 3971 cbdata.sc_handle = g_hndl; 3972 cbdata.sc_parent = ent; 3973 cbdata.sc_service = issvc; 3974 cbdata.sc_flags = SCI_FORCE; 3975 cbdata.sc_source_fmri = ient->sc_fmri; 3976 cbdata.sc_target_fmri = ient->sc_fmri; 3977 3978 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3979 return (cbdata.sc_err); 3980 3981 return (0); 3982 } 3983 3984 /* Fetch the new manifests property group */ 3985 mfst_pgroup = internal_pgroup_find_or_create(ient, 3986 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 3987 assert(mfst_pgroup != NULL); 3988 3989 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3990 SCF_SUCCESS) 3991 return (-1); 3992 3993 if ((pname = malloc(MAXPATHLEN)) == NULL) 3994 return (ENOMEM); 3995 if ((fval = malloc(MAXPATHLEN)) == NULL) { 3996 free(pname); 3997 return (ENOMEM); 3998 } 3999 4000 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 4001 mfst_seen = 0; 4002 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 4003 continue; 4004 4005 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 4006 mfst_prop != NULL; 4007 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 4008 mfst_prop)) { 4009 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 4010 mfst_seen = 1; 4011 } 4012 } 4013 4014 /* 4015 * If the manifest is not seen then add it to the new mfst 4016 * property list to get proccessed into the repo. 4017 */ 4018 if (mfst_seen == 0) { 4019 /* 4020 * If we cannot get the value then there is no 4021 * reason to attempt to attach the value to 4022 * the property group 4023 */ 4024 if (prop_get_val(ud_prop, fname_value) == 0 && 4025 scf_value_get_astring(fname_value, fval, 4026 MAXPATHLEN) != -1) { 4027 old_pname = safe_strdup(pname); 4028 old_fval = safe_strdup(fval); 4029 old_prop = internal_property_create(old_pname, 4030 SCF_TYPE_ASTRING, 1, old_fval); 4031 4032 /* 4033 * Already checked to see if the property exists 4034 * in the group, and it does not. 4035 */ 4036 (void) internal_attach_property(mfst_pgroup, 4037 old_prop); 4038 } 4039 } 4040 } 4041 free(pname); 4042 free(fval); 4043 4044 cbdata.sc_handle = g_hndl; 4045 cbdata.sc_parent = ent; 4046 cbdata.sc_service = issvc; 4047 cbdata.sc_flags = SCI_FORCE; 4048 cbdata.sc_source_fmri = ient->sc_fmri; 4049 cbdata.sc_target_fmri = ient->sc_fmri; 4050 4051 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 4052 return (cbdata.sc_err); 4053 4054 return (r); 4055 } 4056 4057 /* 4058 * prop is taken to be a property in the "dependents" property group of snpl, 4059 * which is taken to be the snaplevel of a last-import snapshot corresponding 4060 * to ient. If prop is a valid dependents property, upgrade the dependent it 4061 * represents according to the repository & ient. If ud_run_dpts_pg_set is 4062 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 4063 * of the entity ient represents (possibly in the running snapshot). If it 4064 * needs to be changed, an entry will be added to tx, if not NULL. 4065 * 4066 * Returns 4067 * 0 - success 4068 * ECONNABORTED - repository connection broken 4069 * ENOMEM - out of memory 4070 * ENOSPC - configd was out of resources 4071 * ECANCELED - snpl's entity was deleted 4072 * EINVAL - dependent target is invalid (error printed) 4073 * - dependent is invalid (error printed) 4074 * EBADF - snpl is corrupt (error printed) 4075 * - snpl has corrupt pg (error printed) 4076 * - dependency pg in target is corrupt (error printed) 4077 * - running snapshot in dependent is missing snaplevel (error printed) 4078 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 4079 * - couldn't create dependent (permission denied) (error printed) 4080 * - couldn't modify dependent pg (permission denied) (error printed) 4081 * EROFS - couldn't delete dependency pg (repository read-only) 4082 * - couldn't create dependent (repository read-only) 4083 * EACCES - couldn't delete dependency pg (backend access denied) 4084 * - couldn't create dependent (backend access denied) 4085 * EBUSY - ud_run_dpts_pg was deleted (error printed) 4086 * - tx's pg was deleted (error printed) 4087 * - dependent pg was changed or deleted (error printed) 4088 * EEXIST - dependency pg already exists in new target (error printed) 4089 */ 4090 static int 4091 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 4092 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 4093 { 4094 pgroup_t pgrp; 4095 scf_type_t ty; 4096 pgroup_t *new_dpt_pgroup; 4097 pgroup_t *old_dpt_pgroup = NULL; 4098 pgroup_t *current_pg; 4099 pgroup_t *dpt; 4100 scf_callback_t cbdata; 4101 int tissvc; 4102 void *target_ent; 4103 scf_error_t serr; 4104 int r; 4105 scf_transaction_entry_t *ent; 4106 4107 const char * const cf_inval = gettext("Conflict upgrading %s " 4108 "(dependent \"%s\" has invalid dependents property).\n"); 4109 const char * const cf_missing = gettext("Conflict upgrading %s " 4110 "(dependent \"%s\" is missing).\n"); 4111 const char * const cf_newdpg = gettext("Conflict upgrading %s " 4112 "(dependent \"%s\" has new dependency property group).\n"); 4113 const char * const cf_newtarg = gettext("Conflict upgrading %s " 4114 "(dependent \"%s\" has new target).\n"); 4115 const char * const li_corrupt = 4116 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 4117 const char * const upgrading = 4118 gettext("%s: Upgrading dependent \"%s\".\n"); 4119 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 4120 "corrupt (missing snaplevel).\n"); 4121 4122 if (scf_property_type(prop, &ty) != 0) { 4123 switch (scf_error()) { 4124 case SCF_ERROR_DELETED: 4125 case SCF_ERROR_CONNECTION_BROKEN: 4126 return (scferror2errno(scf_error())); 4127 4128 case SCF_ERROR_NOT_BOUND: 4129 case SCF_ERROR_NOT_SET: 4130 default: 4131 bad_error("scf_property_type", scf_error()); 4132 } 4133 } 4134 4135 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4136 warn(li_corrupt, ient->sc_fmri); 4137 return (EBADF); 4138 } 4139 4140 /* 4141 * prop represents a dependent in the old manifest. It is named after 4142 * the dependent. 4143 */ 4144 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 4145 switch (scf_error()) { 4146 case SCF_ERROR_DELETED: 4147 case SCF_ERROR_CONNECTION_BROKEN: 4148 return (scferror2errno(scf_error())); 4149 4150 case SCF_ERROR_NOT_BOUND: 4151 case SCF_ERROR_NOT_SET: 4152 default: 4153 bad_error("scf_property_get_name", scf_error()); 4154 } 4155 } 4156 4157 /* See if it's in the new manifest. */ 4158 pgrp.sc_pgroup_name = ud_name; 4159 new_dpt_pgroup = 4160 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 4161 4162 /* If it's not, delete it... if it hasn't been customized. */ 4163 if (new_dpt_pgroup == NULL) { 4164 if (!ud_run_dpts_pg_set) 4165 return (0); 4166 4167 if (scf_property_get_value(prop, ud_val) != 0) { 4168 switch (scf_error()) { 4169 case SCF_ERROR_NOT_FOUND: 4170 case SCF_ERROR_CONSTRAINT_VIOLATED: 4171 warn(li_corrupt, ient->sc_fmri); 4172 return (EBADF); 4173 4174 case SCF_ERROR_DELETED: 4175 case SCF_ERROR_CONNECTION_BROKEN: 4176 return (scferror2errno(scf_error())); 4177 4178 case SCF_ERROR_HANDLE_MISMATCH: 4179 case SCF_ERROR_NOT_BOUND: 4180 case SCF_ERROR_NOT_SET: 4181 case SCF_ERROR_PERMISSION_DENIED: 4182 default: 4183 bad_error("scf_property_get_value", 4184 scf_error()); 4185 } 4186 } 4187 4188 if (scf_value_get_as_string(ud_val, ud_oldtarg, 4189 max_scf_value_len + 1) < 0) 4190 bad_error("scf_value_get_as_string", scf_error()); 4191 4192 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 4193 0) { 4194 switch (scf_error()) { 4195 case SCF_ERROR_NOT_FOUND: 4196 return (0); 4197 4198 case SCF_ERROR_CONNECTION_BROKEN: 4199 return (scferror2errno(scf_error())); 4200 4201 case SCF_ERROR_DELETED: 4202 warn(emsg_pg_deleted, ient->sc_fmri, 4203 "dependents"); 4204 return (EBUSY); 4205 4206 case SCF_ERROR_INVALID_ARGUMENT: 4207 case SCF_ERROR_NOT_BOUND: 4208 case SCF_ERROR_HANDLE_MISMATCH: 4209 case SCF_ERROR_NOT_SET: 4210 default: 4211 bad_error("scf_pg_get_property", scf_error()); 4212 } 4213 } 4214 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4215 switch (scf_error()) { 4216 case SCF_ERROR_NOT_FOUND: 4217 case SCF_ERROR_CONSTRAINT_VIOLATED: 4218 warn(cf_inval, ient->sc_fmri, ud_name); 4219 return (0); 4220 4221 case SCF_ERROR_DELETED: 4222 case SCF_ERROR_CONNECTION_BROKEN: 4223 return (scferror2errno(scf_error())); 4224 4225 case SCF_ERROR_HANDLE_MISMATCH: 4226 case SCF_ERROR_NOT_BOUND: 4227 case SCF_ERROR_NOT_SET: 4228 case SCF_ERROR_PERMISSION_DENIED: 4229 default: 4230 bad_error("scf_property_get_value", 4231 scf_error()); 4232 } 4233 } 4234 4235 ty = scf_value_type(ud_val); 4236 assert(ty != SCF_TYPE_INVALID); 4237 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4238 warn(cf_inval, ient->sc_fmri, ud_name); 4239 return (0); 4240 } 4241 4242 if (scf_value_get_as_string(ud_val, ud_ctarg, 4243 max_scf_value_len + 1) < 0) 4244 bad_error("scf_value_get_as_string", scf_error()); 4245 4246 r = fmri_equal(ud_ctarg, ud_oldtarg); 4247 switch (r) { 4248 case 1: 4249 break; 4250 4251 case 0: 4252 case -1: /* warn? */ 4253 warn(cf_newtarg, ient->sc_fmri, ud_name); 4254 return (0); 4255 4256 case -2: 4257 warn(li_corrupt, ient->sc_fmri); 4258 return (EBADF); 4259 4260 default: 4261 bad_error("fmri_equal", r); 4262 } 4263 4264 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4265 switch (scf_error()) { 4266 case SCF_ERROR_NOT_FOUND: 4267 warn(li_corrupt, ient->sc_fmri); 4268 return (EBADF); 4269 4270 case SCF_ERROR_DELETED: 4271 case SCF_ERROR_CONNECTION_BROKEN: 4272 return (scferror2errno(scf_error())); 4273 4274 case SCF_ERROR_NOT_BOUND: 4275 case SCF_ERROR_HANDLE_MISMATCH: 4276 case SCF_ERROR_INVALID_ARGUMENT: 4277 case SCF_ERROR_NOT_SET: 4278 default: 4279 bad_error("scf_snaplevel_get_pg", scf_error()); 4280 } 4281 } 4282 4283 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4284 snap_lastimport); 4285 switch (r) { 4286 case 0: 4287 break; 4288 4289 case ECANCELED: 4290 case ECONNABORTED: 4291 case ENOMEM: 4292 case EBADF: 4293 return (r); 4294 4295 case EACCES: 4296 default: 4297 bad_error("load_pg", r); 4298 } 4299 4300 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4301 switch (serr) { 4302 case SCF_ERROR_NONE: 4303 break; 4304 4305 case SCF_ERROR_NO_MEMORY: 4306 internal_pgroup_free(old_dpt_pgroup); 4307 return (ENOMEM); 4308 4309 case SCF_ERROR_NOT_FOUND: 4310 internal_pgroup_free(old_dpt_pgroup); 4311 goto delprop; 4312 4313 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 4314 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 4315 default: 4316 bad_error("fmri_to_entity", serr); 4317 } 4318 4319 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4320 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4321 switch (r) { 4322 case 0: 4323 break; 4324 4325 case ECONNABORTED: 4326 internal_pgroup_free(old_dpt_pgroup); 4327 return (r); 4328 4329 case ECANCELED: 4330 case ENOENT: 4331 internal_pgroup_free(old_dpt_pgroup); 4332 goto delprop; 4333 4334 case EBADF: 4335 warn(r_no_lvl, ud_ctarg); 4336 internal_pgroup_free(old_dpt_pgroup); 4337 return (r); 4338 4339 case EINVAL: 4340 default: 4341 bad_error("entity_get_running_pg", r); 4342 } 4343 4344 /* load it */ 4345 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4346 switch (r) { 4347 case 0: 4348 break; 4349 4350 case ECANCELED: 4351 internal_pgroup_free(old_dpt_pgroup); 4352 goto delprop; 4353 4354 case ECONNABORTED: 4355 case ENOMEM: 4356 case EBADF: 4357 internal_pgroup_free(old_dpt_pgroup); 4358 return (r); 4359 4360 case EACCES: 4361 default: 4362 bad_error("load_pg", r); 4363 } 4364 4365 /* compare property groups */ 4366 if (!pg_equal(old_dpt_pgroup, current_pg)) { 4367 warn(cf_newdpg, ient->sc_fmri, ud_name); 4368 internal_pgroup_free(old_dpt_pgroup); 4369 internal_pgroup_free(current_pg); 4370 return (0); 4371 } 4372 4373 internal_pgroup_free(old_dpt_pgroup); 4374 internal_pgroup_free(current_pg); 4375 4376 if (g_verbose) 4377 warn(gettext("%s: Deleting dependent \"%s\".\n"), 4378 ient->sc_fmri, ud_name); 4379 4380 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4381 switch (scf_error()) { 4382 case SCF_ERROR_NOT_FOUND: 4383 case SCF_ERROR_DELETED: 4384 internal_pgroup_free(old_dpt_pgroup); 4385 goto delprop; 4386 4387 case SCF_ERROR_CONNECTION_BROKEN: 4388 internal_pgroup_free(old_dpt_pgroup); 4389 return (ECONNABORTED); 4390 4391 case SCF_ERROR_NOT_SET: 4392 case SCF_ERROR_INVALID_ARGUMENT: 4393 case SCF_ERROR_HANDLE_MISMATCH: 4394 case SCF_ERROR_NOT_BOUND: 4395 default: 4396 bad_error("entity_get_pg", scf_error()); 4397 } 4398 } 4399 4400 if (scf_pg_delete(ud_pg) != 0) { 4401 switch (scf_error()) { 4402 case SCF_ERROR_DELETED: 4403 break; 4404 4405 case SCF_ERROR_CONNECTION_BROKEN: 4406 case SCF_ERROR_BACKEND_READONLY: 4407 case SCF_ERROR_BACKEND_ACCESS: 4408 return (scferror2errno(scf_error())); 4409 4410 case SCF_ERROR_PERMISSION_DENIED: 4411 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4412 return (scferror2errno(scf_error())); 4413 4414 case SCF_ERROR_NOT_SET: 4415 default: 4416 bad_error("scf_pg_delete", scf_error()); 4417 } 4418 } 4419 4420 /* 4421 * This service was changed, so it must be refreshed. But 4422 * since it's not mentioned in the new manifest, we have to 4423 * record its FMRI here for use later. We record the name 4424 * & the entity (via sc_parent) in case we need to print error 4425 * messages during the refresh. 4426 */ 4427 dpt = internal_pgroup_new(); 4428 if (dpt == NULL) 4429 return (ENOMEM); 4430 dpt->sc_pgroup_name = strdup(ud_name); 4431 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 4432 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4433 return (ENOMEM); 4434 dpt->sc_parent = (entity_t *)ient; 4435 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4436 uu_die(gettext("libuutil error: %s\n"), 4437 uu_strerror(uu_error())); 4438 4439 delprop: 4440 if (tx == NULL) 4441 return (0); 4442 4443 ent = scf_entry_create(g_hndl); 4444 if (ent == NULL) 4445 return (ENOMEM); 4446 4447 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 4448 scf_entry_destroy(ent); 4449 switch (scf_error()) { 4450 case SCF_ERROR_DELETED: 4451 warn(emsg_pg_deleted, ient->sc_fmri, 4452 "dependents"); 4453 return (EBUSY); 4454 4455 case SCF_ERROR_CONNECTION_BROKEN: 4456 return (scferror2errno(scf_error())); 4457 4458 case SCF_ERROR_NOT_FOUND: 4459 break; 4460 4461 case SCF_ERROR_HANDLE_MISMATCH: 4462 case SCF_ERROR_NOT_BOUND: 4463 case SCF_ERROR_INVALID_ARGUMENT: 4464 case SCF_ERROR_NOT_SET: 4465 default: 4466 bad_error("scf_transaction_property_delete", 4467 scf_error()); 4468 } 4469 } 4470 4471 return (0); 4472 } 4473 4474 new_dpt_pgroup->sc_pgroup_seen = 1; 4475 4476 /* 4477 * Decide whether the dependent has changed in the manifest. 4478 */ 4479 /* Compare the target. */ 4480 if (scf_property_get_value(prop, ud_val) != 0) { 4481 switch (scf_error()) { 4482 case SCF_ERROR_NOT_FOUND: 4483 case SCF_ERROR_CONSTRAINT_VIOLATED: 4484 warn(li_corrupt, ient->sc_fmri); 4485 return (EBADF); 4486 4487 case SCF_ERROR_DELETED: 4488 case SCF_ERROR_CONNECTION_BROKEN: 4489 return (scferror2errno(scf_error())); 4490 4491 case SCF_ERROR_HANDLE_MISMATCH: 4492 case SCF_ERROR_NOT_BOUND: 4493 case SCF_ERROR_NOT_SET: 4494 case SCF_ERROR_PERMISSION_DENIED: 4495 default: 4496 bad_error("scf_property_get_value", scf_error()); 4497 } 4498 } 4499 4500 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 4501 0) 4502 bad_error("scf_value_get_as_string", scf_error()); 4503 4504 /* 4505 * If the fmri's are not equal then the old fmri will need to 4506 * be refreshed to ensure that the changes are properly updated 4507 * in that service. 4508 */ 4509 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 4510 switch (r) { 4511 case 0: 4512 dpt = internal_pgroup_new(); 4513 if (dpt == NULL) 4514 return (ENOMEM); 4515 dpt->sc_pgroup_name = strdup(ud_name); 4516 dpt->sc_pgroup_fmri = strdup(ud_oldtarg); 4517 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4518 return (ENOMEM); 4519 dpt->sc_parent = (entity_t *)ient; 4520 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4521 uu_die(gettext("libuutil error: %s\n"), 4522 uu_strerror(uu_error())); 4523 break; 4524 4525 case 1: 4526 /* Compare the dependency pgs. */ 4527 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4528 switch (scf_error()) { 4529 case SCF_ERROR_NOT_FOUND: 4530 warn(li_corrupt, ient->sc_fmri); 4531 return (EBADF); 4532 4533 case SCF_ERROR_DELETED: 4534 case SCF_ERROR_CONNECTION_BROKEN: 4535 return (scferror2errno(scf_error())); 4536 4537 case SCF_ERROR_NOT_BOUND: 4538 case SCF_ERROR_HANDLE_MISMATCH: 4539 case SCF_ERROR_INVALID_ARGUMENT: 4540 case SCF_ERROR_NOT_SET: 4541 default: 4542 bad_error("scf_snaplevel_get_pg", scf_error()); 4543 } 4544 } 4545 4546 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4547 snap_lastimport); 4548 switch (r) { 4549 case 0: 4550 break; 4551 4552 case ECANCELED: 4553 case ECONNABORTED: 4554 case ENOMEM: 4555 case EBADF: 4556 return (r); 4557 4558 case EACCES: 4559 default: 4560 bad_error("load_pg", r); 4561 } 4562 4563 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4564 /* no change, leave customizations */ 4565 internal_pgroup_free(old_dpt_pgroup); 4566 return (0); 4567 } 4568 break; 4569 4570 case -1: 4571 warn(li_corrupt, ient->sc_fmri); 4572 return (EBADF); 4573 4574 case -2: 4575 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4576 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4577 return (EINVAL); 4578 4579 default: 4580 bad_error("fmri_equal", r); 4581 } 4582 4583 /* 4584 * The dependent has changed in the manifest. Upgrade the current 4585 * properties if they haven't been customized. 4586 */ 4587 4588 /* 4589 * If new_dpt_pgroup->sc_override, then act as though the property 4590 * group hasn't been customized. 4591 */ 4592 if (new_dpt_pgroup->sc_pgroup_override) { 4593 (void) strcpy(ud_ctarg, ud_oldtarg); 4594 goto nocust; 4595 } 4596 4597 if (!ud_run_dpts_pg_set) { 4598 warn(cf_missing, ient->sc_fmri, ud_name); 4599 r = 0; 4600 goto out; 4601 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4602 switch (scf_error()) { 4603 case SCF_ERROR_NOT_FOUND: 4604 warn(cf_missing, ient->sc_fmri, ud_name); 4605 r = 0; 4606 goto out; 4607 4608 case SCF_ERROR_CONNECTION_BROKEN: 4609 r = scferror2errno(scf_error()); 4610 goto out; 4611 4612 case SCF_ERROR_DELETED: 4613 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4614 r = EBUSY; 4615 goto out; 4616 4617 case SCF_ERROR_INVALID_ARGUMENT: 4618 case SCF_ERROR_NOT_BOUND: 4619 case SCF_ERROR_HANDLE_MISMATCH: 4620 case SCF_ERROR_NOT_SET: 4621 default: 4622 bad_error("scf_pg_get_property", scf_error()); 4623 } 4624 } 4625 4626 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4627 switch (scf_error()) { 4628 case SCF_ERROR_NOT_FOUND: 4629 case SCF_ERROR_CONSTRAINT_VIOLATED: 4630 warn(cf_inval, ient->sc_fmri, ud_name); 4631 r = 0; 4632 goto out; 4633 4634 case SCF_ERROR_DELETED: 4635 case SCF_ERROR_CONNECTION_BROKEN: 4636 r = scferror2errno(scf_error()); 4637 goto out; 4638 4639 case SCF_ERROR_HANDLE_MISMATCH: 4640 case SCF_ERROR_NOT_BOUND: 4641 case SCF_ERROR_NOT_SET: 4642 case SCF_ERROR_PERMISSION_DENIED: 4643 default: 4644 bad_error("scf_property_get_value", scf_error()); 4645 } 4646 } 4647 4648 ty = scf_value_type(ud_val); 4649 assert(ty != SCF_TYPE_INVALID); 4650 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4651 warn(cf_inval, ient->sc_fmri, ud_name); 4652 r = 0; 4653 goto out; 4654 } 4655 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4656 0) 4657 bad_error("scf_value_get_as_string", scf_error()); 4658 4659 r = fmri_equal(ud_ctarg, ud_oldtarg); 4660 if (r == -1) { 4661 warn(cf_inval, ient->sc_fmri, ud_name); 4662 r = 0; 4663 goto out; 4664 } else if (r == -2) { 4665 warn(li_corrupt, ient->sc_fmri); 4666 r = EBADF; 4667 goto out; 4668 } else if (r == 0) { 4669 /* 4670 * Target has been changed. Only abort now if it's been 4671 * changed to something other than what's in the manifest. 4672 */ 4673 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4674 if (r == -1) { 4675 warn(cf_inval, ient->sc_fmri, ud_name); 4676 r = 0; 4677 goto out; 4678 } else if (r == 0) { 4679 warn(cf_newtarg, ient->sc_fmri, ud_name); 4680 r = 0; 4681 goto out; 4682 } else if (r != 1) { 4683 /* invalid sc_pgroup_fmri caught above */ 4684 bad_error("fmri_equal", r); 4685 } 4686 4687 /* 4688 * Fetch the current dependency pg. If it's what the manifest 4689 * says, then no problem. 4690 */ 4691 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4692 switch (serr) { 4693 case SCF_ERROR_NONE: 4694 break; 4695 4696 case SCF_ERROR_NOT_FOUND: 4697 warn(cf_missing, ient->sc_fmri, ud_name); 4698 r = 0; 4699 goto out; 4700 4701 case SCF_ERROR_NO_MEMORY: 4702 r = ENOMEM; 4703 goto out; 4704 4705 case SCF_ERROR_CONSTRAINT_VIOLATED: 4706 case SCF_ERROR_INVALID_ARGUMENT: 4707 default: 4708 bad_error("fmri_to_entity", serr); 4709 } 4710 4711 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4712 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4713 switch (r) { 4714 case 0: 4715 break; 4716 4717 case ECONNABORTED: 4718 goto out; 4719 4720 case ECANCELED: 4721 case ENOENT: 4722 warn(cf_missing, ient->sc_fmri, ud_name); 4723 r = 0; 4724 goto out; 4725 4726 case EBADF: 4727 warn(r_no_lvl, ud_ctarg); 4728 goto out; 4729 4730 case EINVAL: 4731 default: 4732 bad_error("entity_get_running_pg", r); 4733 } 4734 4735 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4736 switch (r) { 4737 case 0: 4738 break; 4739 4740 case ECANCELED: 4741 warn(cf_missing, ient->sc_fmri, ud_name); 4742 r = 0; 4743 goto out; 4744 4745 case ECONNABORTED: 4746 case ENOMEM: 4747 case EBADF: 4748 goto out; 4749 4750 case EACCES: 4751 default: 4752 bad_error("load_pg", r); 4753 } 4754 4755 if (!pg_equal(current_pg, new_dpt_pgroup)) 4756 warn(cf_newdpg, ient->sc_fmri, ud_name); 4757 internal_pgroup_free(current_pg); 4758 r = 0; 4759 goto out; 4760 } else if (r != 1) { 4761 bad_error("fmri_equal", r); 4762 } 4763 4764 nocust: 4765 /* 4766 * Target has not been customized. Check the dependency property 4767 * group. 4768 */ 4769 4770 if (old_dpt_pgroup == NULL) { 4771 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4772 ud_pg) != 0) { 4773 switch (scf_error()) { 4774 case SCF_ERROR_NOT_FOUND: 4775 warn(li_corrupt, ient->sc_fmri); 4776 return (EBADF); 4777 4778 case SCF_ERROR_DELETED: 4779 case SCF_ERROR_CONNECTION_BROKEN: 4780 return (scferror2errno(scf_error())); 4781 4782 case SCF_ERROR_NOT_BOUND: 4783 case SCF_ERROR_HANDLE_MISMATCH: 4784 case SCF_ERROR_INVALID_ARGUMENT: 4785 case SCF_ERROR_NOT_SET: 4786 default: 4787 bad_error("scf_snaplevel_get_pg", scf_error()); 4788 } 4789 } 4790 4791 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4792 snap_lastimport); 4793 switch (r) { 4794 case 0: 4795 break; 4796 4797 case ECANCELED: 4798 case ECONNABORTED: 4799 case ENOMEM: 4800 case EBADF: 4801 return (r); 4802 4803 case EACCES: 4804 default: 4805 bad_error("load_pg", r); 4806 } 4807 } 4808 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4809 switch (serr) { 4810 case SCF_ERROR_NONE: 4811 break; 4812 4813 case SCF_ERROR_NOT_FOUND: 4814 warn(cf_missing, ient->sc_fmri, ud_name); 4815 r = 0; 4816 goto out; 4817 4818 case SCF_ERROR_NO_MEMORY: 4819 r = ENOMEM; 4820 goto out; 4821 4822 case SCF_ERROR_CONSTRAINT_VIOLATED: 4823 case SCF_ERROR_INVALID_ARGUMENT: 4824 default: 4825 bad_error("fmri_to_entity", serr); 4826 } 4827 4828 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4829 ud_iter2, ud_inst, imp_snap, ud_snpl); 4830 switch (r) { 4831 case 0: 4832 break; 4833 4834 case ECONNABORTED: 4835 goto out; 4836 4837 case ECANCELED: 4838 case ENOENT: 4839 warn(cf_missing, ient->sc_fmri, ud_name); 4840 r = 0; 4841 goto out; 4842 4843 case EBADF: 4844 warn(r_no_lvl, ud_ctarg); 4845 goto out; 4846 4847 case EINVAL: 4848 default: 4849 bad_error("entity_get_running_pg", r); 4850 } 4851 4852 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4853 switch (r) { 4854 case 0: 4855 break; 4856 4857 case ECANCELED: 4858 warn(cf_missing, ient->sc_fmri, ud_name); 4859 goto out; 4860 4861 case ECONNABORTED: 4862 case ENOMEM: 4863 case EBADF: 4864 goto out; 4865 4866 case EACCES: 4867 default: 4868 bad_error("load_pg", r); 4869 } 4870 4871 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4872 if (!pg_equal(current_pg, new_dpt_pgroup)) 4873 warn(cf_newdpg, ient->sc_fmri, ud_name); 4874 internal_pgroup_free(current_pg); 4875 r = 0; 4876 goto out; 4877 } 4878 4879 /* Uncustomized. Upgrade. */ 4880 4881 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4882 switch (r) { 4883 case 1: 4884 if (pg_equal(current_pg, new_dpt_pgroup)) { 4885 /* Already upgraded. */ 4886 internal_pgroup_free(current_pg); 4887 r = 0; 4888 goto out; 4889 } 4890 4891 internal_pgroup_free(current_pg); 4892 4893 /* upgrade current_pg */ 4894 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4895 switch (scf_error()) { 4896 case SCF_ERROR_CONNECTION_BROKEN: 4897 r = scferror2errno(scf_error()); 4898 goto out; 4899 4900 case SCF_ERROR_DELETED: 4901 warn(cf_missing, ient->sc_fmri, ud_name); 4902 r = 0; 4903 goto out; 4904 4905 case SCF_ERROR_NOT_FOUND: 4906 break; 4907 4908 case SCF_ERROR_INVALID_ARGUMENT: 4909 case SCF_ERROR_NOT_BOUND: 4910 case SCF_ERROR_NOT_SET: 4911 case SCF_ERROR_HANDLE_MISMATCH: 4912 default: 4913 bad_error("entity_get_pg", scf_error()); 4914 } 4915 4916 if (tissvc) 4917 r = scf_service_add_pg(target_ent, ud_name, 4918 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4919 else 4920 r = scf_instance_add_pg(target_ent, ud_name, 4921 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4922 if (r != 0) { 4923 switch (scf_error()) { 4924 case SCF_ERROR_CONNECTION_BROKEN: 4925 case SCF_ERROR_NO_RESOURCES: 4926 case SCF_ERROR_BACKEND_READONLY: 4927 case SCF_ERROR_BACKEND_ACCESS: 4928 r = scferror2errno(scf_error()); 4929 goto out; 4930 4931 case SCF_ERROR_DELETED: 4932 warn(cf_missing, ient->sc_fmri, 4933 ud_name); 4934 r = 0; 4935 goto out; 4936 4937 case SCF_ERROR_PERMISSION_DENIED: 4938 warn(emsg_pg_deleted, ud_ctarg, 4939 ud_name); 4940 r = EPERM; 4941 goto out; 4942 4943 case SCF_ERROR_EXISTS: 4944 warn(emsg_pg_added, ud_ctarg, ud_name); 4945 r = EBUSY; 4946 goto out; 4947 4948 case SCF_ERROR_NOT_BOUND: 4949 case SCF_ERROR_HANDLE_MISMATCH: 4950 case SCF_ERROR_INVALID_ARGUMENT: 4951 case SCF_ERROR_NOT_SET: 4952 default: 4953 bad_error("entity_add_pg", scf_error()); 4954 } 4955 } 4956 } 4957 4958 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4959 switch (r) { 4960 case 0: 4961 break; 4962 4963 case ECANCELED: 4964 warn(cf_missing, ient->sc_fmri, ud_name); 4965 goto out; 4966 4967 case ECONNABORTED: 4968 case ENOMEM: 4969 case EBADF: 4970 goto out; 4971 4972 case EACCES: 4973 default: 4974 bad_error("load_pg", r); 4975 } 4976 4977 if (g_verbose) 4978 warn(upgrading, ient->sc_fmri, ud_name); 4979 4980 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4981 new_dpt_pgroup, 0, ient->sc_fmri); 4982 switch (r) { 4983 case 0: 4984 break; 4985 4986 case ECANCELED: 4987 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4988 r = EBUSY; 4989 goto out; 4990 4991 case EPERM: 4992 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4993 goto out; 4994 4995 case EBUSY: 4996 warn(emsg_pg_changed, ud_ctarg, ud_name); 4997 goto out; 4998 4999 case ECONNABORTED: 5000 case ENOMEM: 5001 case ENOSPC: 5002 case EROFS: 5003 case EACCES: 5004 case EINVAL: 5005 goto out; 5006 5007 default: 5008 bad_error("upgrade_pg", r); 5009 } 5010 break; 5011 5012 case 0: { 5013 scf_transaction_entry_t *ent; 5014 scf_value_t *val; 5015 5016 internal_pgroup_free(current_pg); 5017 5018 /* delete old pg */ 5019 if (g_verbose) 5020 warn(upgrading, ient->sc_fmri, ud_name); 5021 5022 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 5023 switch (scf_error()) { 5024 case SCF_ERROR_CONNECTION_BROKEN: 5025 r = scferror2errno(scf_error()); 5026 goto out; 5027 5028 case SCF_ERROR_DELETED: 5029 warn(cf_missing, ient->sc_fmri, ud_name); 5030 r = 0; 5031 goto out; 5032 5033 case SCF_ERROR_NOT_FOUND: 5034 break; 5035 5036 case SCF_ERROR_INVALID_ARGUMENT: 5037 case SCF_ERROR_NOT_BOUND: 5038 case SCF_ERROR_NOT_SET: 5039 case SCF_ERROR_HANDLE_MISMATCH: 5040 default: 5041 bad_error("entity_get_pg", scf_error()); 5042 } 5043 } else if (scf_pg_delete(ud_pg) != 0) { 5044 switch (scf_error()) { 5045 case SCF_ERROR_DELETED: 5046 break; 5047 5048 case SCF_ERROR_CONNECTION_BROKEN: 5049 case SCF_ERROR_BACKEND_READONLY: 5050 case SCF_ERROR_BACKEND_ACCESS: 5051 r = scferror2errno(scf_error()); 5052 goto out; 5053 5054 case SCF_ERROR_PERMISSION_DENIED: 5055 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 5056 r = scferror2errno(scf_error()); 5057 goto out; 5058 5059 case SCF_ERROR_NOT_SET: 5060 default: 5061 bad_error("scf_pg_delete", scf_error()); 5062 } 5063 } 5064 5065 /* import new one */ 5066 cbdata.sc_handle = g_hndl; 5067 cbdata.sc_trans = NULL; /* handled below */ 5068 cbdata.sc_flags = 0; 5069 5070 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 5071 if (r != UU_WALK_NEXT) { 5072 if (r != UU_WALK_ERROR) 5073 bad_error("lscf_dependent_import", r); 5074 5075 r = cbdata.sc_err; 5076 goto out; 5077 } 5078 5079 if (tx == NULL) 5080 break; 5081 5082 if ((ent = scf_entry_create(g_hndl)) == NULL || 5083 (val = scf_value_create(g_hndl)) == NULL) { 5084 if (scf_error() == SCF_ERROR_NO_MEMORY) 5085 return (ENOMEM); 5086 5087 bad_error("scf_entry_create", scf_error()); 5088 } 5089 5090 if (scf_transaction_property_change_type(tx, ent, ud_name, 5091 SCF_TYPE_FMRI) != 0) { 5092 switch (scf_error()) { 5093 case SCF_ERROR_CONNECTION_BROKEN: 5094 r = scferror2errno(scf_error()); 5095 goto out; 5096 5097 case SCF_ERROR_DELETED: 5098 warn(emsg_pg_deleted, ient->sc_fmri, 5099 "dependents"); 5100 r = EBUSY; 5101 goto out; 5102 5103 case SCF_ERROR_NOT_FOUND: 5104 break; 5105 5106 case SCF_ERROR_NOT_BOUND: 5107 case SCF_ERROR_HANDLE_MISMATCH: 5108 case SCF_ERROR_INVALID_ARGUMENT: 5109 case SCF_ERROR_NOT_SET: 5110 default: 5111 bad_error("scf_transaction_property_" 5112 "change_type", scf_error()); 5113 } 5114 5115 if (scf_transaction_property_new(tx, ent, ud_name, 5116 SCF_TYPE_FMRI) != 0) { 5117 switch (scf_error()) { 5118 case SCF_ERROR_CONNECTION_BROKEN: 5119 r = scferror2errno(scf_error()); 5120 goto out; 5121 5122 case SCF_ERROR_DELETED: 5123 warn(emsg_pg_deleted, ient->sc_fmri, 5124 "dependents"); 5125 r = EBUSY; 5126 goto out; 5127 5128 case SCF_ERROR_EXISTS: 5129 warn(emsg_pg_changed, ient->sc_fmri, 5130 "dependents"); 5131 r = EBUSY; 5132 goto out; 5133 5134 case SCF_ERROR_INVALID_ARGUMENT: 5135 case SCF_ERROR_HANDLE_MISMATCH: 5136 case SCF_ERROR_NOT_BOUND: 5137 case SCF_ERROR_NOT_SET: 5138 default: 5139 bad_error("scf_transaction_property_" 5140 "new", scf_error()); 5141 } 5142 } 5143 } 5144 5145 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 5146 new_dpt_pgroup->sc_pgroup_fmri) != 0) 5147 /* invalid sc_pgroup_fmri caught above */ 5148 bad_error("scf_value_set_from_string", 5149 scf_error()); 5150 5151 if (scf_entry_add_value(ent, val) != 0) 5152 bad_error("scf_entry_add_value", scf_error()); 5153 break; 5154 } 5155 5156 case -2: 5157 warn(li_corrupt, ient->sc_fmri); 5158 internal_pgroup_free(current_pg); 5159 r = EBADF; 5160 goto out; 5161 5162 case -1: 5163 default: 5164 /* invalid sc_pgroup_fmri caught above */ 5165 bad_error("fmri_equal", r); 5166 } 5167 5168 r = 0; 5169 5170 out: 5171 if (old_dpt_pgroup != NULL) 5172 internal_pgroup_free(old_dpt_pgroup); 5173 5174 return (r); 5175 } 5176 5177 /* 5178 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 5179 * would import it, except it seems to exist in the service anyway. Compare 5180 * the existent dependent with the one we would import, and report any 5181 * differences (if there are none, be silent). prop is the property which 5182 * represents the existent dependent (in the dependents property group) in the 5183 * entity corresponding to ient. 5184 * 5185 * Returns 5186 * 0 - success (Sort of. At least, we can continue importing.) 5187 * ECONNABORTED - repository connection broken 5188 * EBUSY - ancestor of prop was deleted (error printed) 5189 * ENOMEM - out of memory 5190 * EBADF - corrupt property group (error printed) 5191 * EINVAL - new_dpt_pgroup has invalid target (error printed) 5192 */ 5193 static int 5194 handle_dependent_conflict(const entity_t * const ient, 5195 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 5196 { 5197 int r; 5198 scf_type_t ty; 5199 scf_error_t scfe; 5200 void *tptr; 5201 int tissvc; 5202 pgroup_t *pgroup; 5203 5204 if (scf_property_get_value(prop, ud_val) != 0) { 5205 switch (scf_error()) { 5206 case SCF_ERROR_CONNECTION_BROKEN: 5207 return (scferror2errno(scf_error())); 5208 5209 case SCF_ERROR_DELETED: 5210 warn(emsg_pg_deleted, ient->sc_fmri, 5211 new_dpt_pgroup->sc_pgroup_name); 5212 return (EBUSY); 5213 5214 case SCF_ERROR_CONSTRAINT_VIOLATED: 5215 case SCF_ERROR_NOT_FOUND: 5216 warn(gettext("Conflict upgrading %s (not importing " 5217 "dependent \"%s\" because it already exists.) " 5218 "Warning: The \"%s/%2$s\" property has more or " 5219 "fewer than one value)).\n"), ient->sc_fmri, 5220 new_dpt_pgroup->sc_pgroup_name, "dependents"); 5221 return (0); 5222 5223 case SCF_ERROR_HANDLE_MISMATCH: 5224 case SCF_ERROR_NOT_BOUND: 5225 case SCF_ERROR_NOT_SET: 5226 case SCF_ERROR_PERMISSION_DENIED: 5227 default: 5228 bad_error("scf_property_get_value", 5229 scf_error()); 5230 } 5231 } 5232 5233 ty = scf_value_type(ud_val); 5234 assert(ty != SCF_TYPE_INVALID); 5235 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 5236 warn(gettext("Conflict upgrading %s (not importing dependent " 5237 "\"%s\" because it already exists). Warning: The " 5238 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 5239 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 5240 scf_type_to_string(ty), "dependents"); 5241 return (0); 5242 } 5243 5244 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 5245 0) 5246 bad_error("scf_value_get_as_string", scf_error()); 5247 5248 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 5249 switch (r) { 5250 case 0: 5251 warn(gettext("Conflict upgrading %s (not importing dependent " 5252 "\"%s\" (target \"%s\") because it already exists with " 5253 "target \"%s\").\n"), ient->sc_fmri, 5254 new_dpt_pgroup->sc_pgroup_name, 5255 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 5256 return (0); 5257 5258 case 1: 5259 break; 5260 5261 case -1: 5262 warn(gettext("Conflict upgrading %s (not importing dependent " 5263 "\"%s\" because it already exists). Warning: The current " 5264 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 5265 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5266 return (0); 5267 5268 case -2: 5269 warn(gettext("Dependent \"%s\" of %s has invalid target " 5270 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 5271 new_dpt_pgroup->sc_pgroup_fmri); 5272 return (EINVAL); 5273 5274 default: 5275 bad_error("fmri_equal", r); 5276 } 5277 5278 /* compare dependency pgs in target */ 5279 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 5280 switch (scfe) { 5281 case SCF_ERROR_NONE: 5282 break; 5283 5284 case SCF_ERROR_NO_MEMORY: 5285 return (ENOMEM); 5286 5287 case SCF_ERROR_NOT_FOUND: 5288 warn(emsg_dpt_dangling, ient->sc_fmri, 5289 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5290 return (0); 5291 5292 case SCF_ERROR_CONSTRAINT_VIOLATED: 5293 case SCF_ERROR_INVALID_ARGUMENT: 5294 default: 5295 bad_error("fmri_to_entity", scfe); 5296 } 5297 5298 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 5299 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 5300 switch (r) { 5301 case 0: 5302 break; 5303 5304 case ECONNABORTED: 5305 return (r); 5306 5307 case ECANCELED: 5308 warn(emsg_dpt_dangling, ient->sc_fmri, 5309 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5310 return (0); 5311 5312 case EBADF: 5313 if (tissvc) 5314 warn(gettext("%s has an instance with a \"%s\" " 5315 "snapshot which is missing a snaplevel.\n"), 5316 ud_ctarg, "running"); 5317 else 5318 warn(gettext("%s has a \"%s\" snapshot which is " 5319 "missing a snaplevel.\n"), ud_ctarg, "running"); 5320 /* FALLTHROUGH */ 5321 5322 case ENOENT: 5323 warn(emsg_dpt_no_dep, ient->sc_fmri, 5324 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5325 new_dpt_pgroup->sc_pgroup_name); 5326 return (0); 5327 5328 case EINVAL: 5329 default: 5330 bad_error("entity_get_running_pg", r); 5331 } 5332 5333 pgroup = internal_pgroup_new(); 5334 if (pgroup == NULL) 5335 return (ENOMEM); 5336 5337 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 5338 switch (r) { 5339 case 0: 5340 break; 5341 5342 case ECONNABORTED: 5343 case EBADF: 5344 case ENOMEM: 5345 internal_pgroup_free(pgroup); 5346 return (r); 5347 5348 case ECANCELED: 5349 warn(emsg_dpt_no_dep, ient->sc_fmri, 5350 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5351 new_dpt_pgroup->sc_pgroup_name); 5352 internal_pgroup_free(pgroup); 5353 return (0); 5354 5355 case EACCES: 5356 default: 5357 bad_error("load_pg", r); 5358 } 5359 5360 /* report differences */ 5361 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 5362 internal_pgroup_free(pgroup); 5363 return (0); 5364 } 5365 5366 /* 5367 * lipg is a property group in the last-import snapshot of ent, which is an 5368 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 5369 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 5370 * in ents's property groups, compare and upgrade ent appropriately. 5371 * 5372 * Returns 5373 * 0 - success 5374 * ECONNABORTED - repository connection broken 5375 * ENOMEM - out of memory 5376 * ENOSPC - configd is out of resources 5377 * EINVAL - ient has invalid dependent (error printed) 5378 * - ient has invalid pgroup_t (error printed) 5379 * ECANCELED - ent has been deleted 5380 * ENODEV - entity containing lipg has been deleted 5381 * - entity containing running has been deleted 5382 * EPERM - could not delete pg (permission denied) (error printed) 5383 * - couldn't upgrade dependents (permission denied) (error printed) 5384 * - couldn't import pg (permission denied) (error printed) 5385 * - couldn't upgrade pg (permission denied) (error printed) 5386 * EROFS - could not delete pg (repository read-only) 5387 * - couldn't upgrade dependents (repository read-only) 5388 * - couldn't import pg (repository read-only) 5389 * - couldn't upgrade pg (repository read-only) 5390 * EACCES - could not delete pg (backend access denied) 5391 * - couldn't upgrade dependents (backend access denied) 5392 * - couldn't import pg (backend access denied) 5393 * - couldn't upgrade pg (backend access denied) 5394 * - couldn't read property (backend access denied) 5395 * EBUSY - property group was added (error printed) 5396 * - property group was deleted (error printed) 5397 * - property group changed (error printed) 5398 * - "dependents" pg was added, changed, or deleted (error printed) 5399 * - dependent target deleted (error printed) 5400 * - dependent pg changed (error printed) 5401 * EBADF - imp_snpl is corrupt (error printed) 5402 * - ent has bad pg (error printed) 5403 * EEXIST - dependent collision in target service (error printed) 5404 */ 5405 static int 5406 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 5407 const scf_snaplevel_t *running) 5408 { 5409 int r; 5410 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 5411 scf_callback_t cbdata; 5412 5413 const char * const cf_pg_missing = 5414 gettext("Conflict upgrading %s (property group %s is missing)\n"); 5415 const char * const deleting = 5416 gettext("%s: Deleting property group \"%s\".\n"); 5417 5418 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5419 5420 /* Skip dependent property groups. */ 5421 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 5422 switch (scf_error()) { 5423 case SCF_ERROR_DELETED: 5424 return (ENODEV); 5425 5426 case SCF_ERROR_CONNECTION_BROKEN: 5427 return (ECONNABORTED); 5428 5429 case SCF_ERROR_NOT_SET: 5430 case SCF_ERROR_NOT_BOUND: 5431 default: 5432 bad_error("scf_pg_get_type", scf_error()); 5433 } 5434 } 5435 5436 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 5437 if (scf_pg_get_property(lipg, "external", NULL) == 0) 5438 return (0); 5439 5440 switch (scf_error()) { 5441 case SCF_ERROR_NOT_FOUND: 5442 break; 5443 5444 case SCF_ERROR_CONNECTION_BROKEN: 5445 return (ECONNABORTED); 5446 5447 case SCF_ERROR_DELETED: 5448 return (ENODEV); 5449 5450 case SCF_ERROR_INVALID_ARGUMENT: 5451 case SCF_ERROR_NOT_BOUND: 5452 case SCF_ERROR_HANDLE_MISMATCH: 5453 case SCF_ERROR_NOT_SET: 5454 default: 5455 bad_error("scf_pg_get_property", scf_error()); 5456 } 5457 } 5458 5459 /* lookup pg in new properties */ 5460 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 5461 switch (scf_error()) { 5462 case SCF_ERROR_DELETED: 5463 return (ENODEV); 5464 5465 case SCF_ERROR_CONNECTION_BROKEN: 5466 return (ECONNABORTED); 5467 5468 case SCF_ERROR_NOT_SET: 5469 case SCF_ERROR_NOT_BOUND: 5470 default: 5471 bad_error("scf_pg_get_name", scf_error()); 5472 } 5473 } 5474 5475 pgrp.sc_pgroup_name = imp_str; 5476 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 5477 5478 if (mpg != NULL) 5479 mpg->sc_pgroup_seen = 1; 5480 5481 /* Special handling for dependents */ 5482 if (strcmp(imp_str, "dependents") == 0) 5483 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 5484 5485 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 5486 return (upgrade_manifestfiles(NULL, ient, running, ent)); 5487 5488 if (mpg == NULL || mpg->sc_pgroup_delete) { 5489 /* property group was deleted from manifest */ 5490 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5491 switch (scf_error()) { 5492 case SCF_ERROR_NOT_FOUND: 5493 return (0); 5494 5495 case SCF_ERROR_DELETED: 5496 case SCF_ERROR_CONNECTION_BROKEN: 5497 return (scferror2errno(scf_error())); 5498 5499 case SCF_ERROR_INVALID_ARGUMENT: 5500 case SCF_ERROR_HANDLE_MISMATCH: 5501 case SCF_ERROR_NOT_BOUND: 5502 case SCF_ERROR_NOT_SET: 5503 default: 5504 bad_error("entity_get_pg", scf_error()); 5505 } 5506 } 5507 5508 if (mpg != NULL && mpg->sc_pgroup_delete) { 5509 if (g_verbose) 5510 warn(deleting, ient->sc_fmri, imp_str); 5511 if (scf_pg_delete(imp_pg2) == 0) 5512 return (0); 5513 5514 switch (scf_error()) { 5515 case SCF_ERROR_DELETED: 5516 return (0); 5517 5518 case SCF_ERROR_CONNECTION_BROKEN: 5519 case SCF_ERROR_BACKEND_READONLY: 5520 case SCF_ERROR_BACKEND_ACCESS: 5521 return (scferror2errno(scf_error())); 5522 5523 case SCF_ERROR_PERMISSION_DENIED: 5524 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 5525 return (scferror2errno(scf_error())); 5526 5527 case SCF_ERROR_NOT_SET: 5528 default: 5529 bad_error("scf_pg_delete", scf_error()); 5530 } 5531 } 5532 5533 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5534 switch (r) { 5535 case 0: 5536 break; 5537 5538 case ECANCELED: 5539 return (ENODEV); 5540 5541 case ECONNABORTED: 5542 case ENOMEM: 5543 case EBADF: 5544 case EACCES: 5545 return (r); 5546 5547 default: 5548 bad_error("load_pg", r); 5549 } 5550 5551 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5552 switch (r) { 5553 case 0: 5554 break; 5555 5556 case ECANCELED: 5557 case ECONNABORTED: 5558 case ENOMEM: 5559 case EBADF: 5560 case EACCES: 5561 internal_pgroup_free(lipg_i); 5562 return (r); 5563 5564 default: 5565 bad_error("load_pg", r); 5566 } 5567 5568 if (pg_equal(lipg_i, curpg_i)) { 5569 if (g_verbose) 5570 warn(deleting, ient->sc_fmri, imp_str); 5571 if (scf_pg_delete(imp_pg2) != 0) { 5572 switch (scf_error()) { 5573 case SCF_ERROR_DELETED: 5574 break; 5575 5576 case SCF_ERROR_CONNECTION_BROKEN: 5577 internal_pgroup_free(lipg_i); 5578 internal_pgroup_free(curpg_i); 5579 return (ECONNABORTED); 5580 5581 case SCF_ERROR_NOT_SET: 5582 case SCF_ERROR_NOT_BOUND: 5583 default: 5584 bad_error("scf_pg_delete", scf_error()); 5585 } 5586 } 5587 } else { 5588 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5589 } 5590 5591 internal_pgroup_free(lipg_i); 5592 internal_pgroup_free(curpg_i); 5593 5594 return (0); 5595 } 5596 5597 /* 5598 * Only dependent pgs can have override set, and we skipped those 5599 * above. 5600 */ 5601 assert(!mpg->sc_pgroup_override); 5602 5603 /* compare */ 5604 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5605 switch (r) { 5606 case 0: 5607 break; 5608 5609 case ECANCELED: 5610 return (ENODEV); 5611 5612 case ECONNABORTED: 5613 case EBADF: 5614 case ENOMEM: 5615 case EACCES: 5616 return (r); 5617 5618 default: 5619 bad_error("load_pg", r); 5620 } 5621 5622 if (pg_equal(mpg, lipg_i)) { 5623 /* The manifest pg has not changed. Move on. */ 5624 r = 0; 5625 goto out; 5626 } 5627 5628 /* upgrade current properties according to lipg & mpg */ 5629 if (running != NULL) 5630 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5631 else 5632 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5633 if (r != 0) { 5634 switch (scf_error()) { 5635 case SCF_ERROR_CONNECTION_BROKEN: 5636 r = scferror2errno(scf_error()); 5637 goto out; 5638 5639 case SCF_ERROR_DELETED: 5640 if (running != NULL) 5641 r = ENODEV; 5642 else 5643 r = ECANCELED; 5644 goto out; 5645 5646 case SCF_ERROR_NOT_FOUND: 5647 break; 5648 5649 case SCF_ERROR_INVALID_ARGUMENT: 5650 case SCF_ERROR_HANDLE_MISMATCH: 5651 case SCF_ERROR_NOT_BOUND: 5652 case SCF_ERROR_NOT_SET: 5653 default: 5654 bad_error("entity_get_pg", scf_error()); 5655 } 5656 5657 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5658 5659 r = 0; 5660 goto out; 5661 } 5662 5663 r = load_pg_attrs(imp_pg2, &curpg_i); 5664 switch (r) { 5665 case 0: 5666 break; 5667 5668 case ECANCELED: 5669 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5670 r = 0; 5671 goto out; 5672 5673 case ECONNABORTED: 5674 case ENOMEM: 5675 goto out; 5676 5677 default: 5678 bad_error("load_pg_attrs", r); 5679 } 5680 5681 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5682 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5683 internal_pgroup_free(curpg_i); 5684 r = 0; 5685 goto out; 5686 } 5687 5688 internal_pgroup_free(curpg_i); 5689 5690 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5691 switch (r) { 5692 case 0: 5693 break; 5694 5695 case ECANCELED: 5696 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5697 r = 0; 5698 goto out; 5699 5700 case ECONNABORTED: 5701 case EBADF: 5702 case ENOMEM: 5703 case EACCES: 5704 goto out; 5705 5706 default: 5707 bad_error("load_pg", r); 5708 } 5709 5710 if (pg_equal(lipg_i, curpg_i) && 5711 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5712 int do_delete = 1; 5713 5714 if (g_verbose) 5715 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5716 ient->sc_fmri, mpg->sc_pgroup_name); 5717 5718 internal_pgroup_free(curpg_i); 5719 5720 if (running != NULL && 5721 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5722 switch (scf_error()) { 5723 case SCF_ERROR_DELETED: 5724 r = ECANCELED; 5725 goto out; 5726 5727 case SCF_ERROR_NOT_FOUND: 5728 do_delete = 0; 5729 break; 5730 5731 case SCF_ERROR_CONNECTION_BROKEN: 5732 r = scferror2errno(scf_error()); 5733 goto out; 5734 5735 case SCF_ERROR_HANDLE_MISMATCH: 5736 case SCF_ERROR_INVALID_ARGUMENT: 5737 case SCF_ERROR_NOT_SET: 5738 case SCF_ERROR_NOT_BOUND: 5739 default: 5740 bad_error("entity_get_pg", scf_error()); 5741 } 5742 } 5743 5744 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5745 switch (scf_error()) { 5746 case SCF_ERROR_DELETED: 5747 break; 5748 5749 case SCF_ERROR_CONNECTION_BROKEN: 5750 case SCF_ERROR_BACKEND_READONLY: 5751 case SCF_ERROR_BACKEND_ACCESS: 5752 r = scferror2errno(scf_error()); 5753 goto out; 5754 5755 case SCF_ERROR_PERMISSION_DENIED: 5756 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5757 ient->sc_fmri); 5758 r = scferror2errno(scf_error()); 5759 goto out; 5760 5761 case SCF_ERROR_NOT_SET: 5762 case SCF_ERROR_NOT_BOUND: 5763 default: 5764 bad_error("scf_pg_delete", scf_error()); 5765 } 5766 } 5767 5768 cbdata.sc_handle = g_hndl; 5769 cbdata.sc_parent = ent; 5770 cbdata.sc_service = issvc; 5771 cbdata.sc_flags = 0; 5772 cbdata.sc_source_fmri = ient->sc_fmri; 5773 cbdata.sc_target_fmri = ient->sc_fmri; 5774 5775 r = entity_pgroup_import(mpg, &cbdata); 5776 switch (r) { 5777 case UU_WALK_NEXT: 5778 r = 0; 5779 goto out; 5780 5781 case UU_WALK_ERROR: 5782 if (cbdata.sc_err == EEXIST) { 5783 warn(emsg_pg_added, ient->sc_fmri, 5784 mpg->sc_pgroup_name); 5785 r = EBUSY; 5786 } else { 5787 r = cbdata.sc_err; 5788 } 5789 goto out; 5790 5791 default: 5792 bad_error("entity_pgroup_import", r); 5793 } 5794 } 5795 5796 if (running != NULL && 5797 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5798 switch (scf_error()) { 5799 case SCF_ERROR_CONNECTION_BROKEN: 5800 case SCF_ERROR_DELETED: 5801 r = scferror2errno(scf_error()); 5802 goto out; 5803 5804 case SCF_ERROR_NOT_FOUND: 5805 break; 5806 5807 case SCF_ERROR_HANDLE_MISMATCH: 5808 case SCF_ERROR_INVALID_ARGUMENT: 5809 case SCF_ERROR_NOT_SET: 5810 case SCF_ERROR_NOT_BOUND: 5811 default: 5812 bad_error("entity_get_pg", scf_error()); 5813 } 5814 5815 cbdata.sc_handle = g_hndl; 5816 cbdata.sc_parent = ent; 5817 cbdata.sc_service = issvc; 5818 cbdata.sc_flags = SCI_FORCE; 5819 cbdata.sc_source_fmri = ient->sc_fmri; 5820 cbdata.sc_target_fmri = ient->sc_fmri; 5821 5822 r = entity_pgroup_import(mpg, &cbdata); 5823 switch (r) { 5824 case UU_WALK_NEXT: 5825 r = 0; 5826 goto out; 5827 5828 case UU_WALK_ERROR: 5829 if (cbdata.sc_err == EEXIST) { 5830 warn(emsg_pg_added, ient->sc_fmri, 5831 mpg->sc_pgroup_name); 5832 r = EBUSY; 5833 } else { 5834 r = cbdata.sc_err; 5835 } 5836 goto out; 5837 5838 default: 5839 bad_error("entity_pgroup_import", r); 5840 } 5841 } 5842 5843 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5844 internal_pgroup_free(curpg_i); 5845 switch (r) { 5846 case 0: 5847 ient->sc_import_state = IMPORT_PROP_BEGUN; 5848 break; 5849 5850 case ECANCELED: 5851 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5852 r = EBUSY; 5853 break; 5854 5855 case EPERM: 5856 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5857 break; 5858 5859 case EBUSY: 5860 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5861 break; 5862 5863 case ECONNABORTED: 5864 case ENOMEM: 5865 case ENOSPC: 5866 case EROFS: 5867 case EACCES: 5868 case EINVAL: 5869 break; 5870 5871 default: 5872 bad_error("upgrade_pg", r); 5873 } 5874 5875 out: 5876 internal_pgroup_free(lipg_i); 5877 return (r); 5878 } 5879 5880 /* 5881 * Upgrade the properties of ent according to snpl & ient. 5882 * 5883 * Returns 5884 * 0 - success 5885 * ECONNABORTED - repository connection broken 5886 * ENOMEM - out of memory 5887 * ENOSPC - configd is out of resources 5888 * ECANCELED - ent was deleted 5889 * ENODEV - entity containing snpl was deleted 5890 * - entity containing running was deleted 5891 * EBADF - imp_snpl is corrupt (error printed) 5892 * - ent has corrupt pg (error printed) 5893 * - dependent has corrupt pg (error printed) 5894 * - dependent target has a corrupt snapshot (error printed) 5895 * EBUSY - pg was added, changed, or deleted (error printed) 5896 * - dependent target was deleted (error printed) 5897 * - dependent pg changed (error printed) 5898 * EINVAL - invalid property group name (error printed) 5899 * - invalid property name (error printed) 5900 * - invalid value (error printed) 5901 * - ient has invalid pgroup or dependent (error printed) 5902 * EPERM - could not create property group (permission denied) (error printed) 5903 * - could not modify property group (permission denied) (error printed) 5904 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5905 * EROFS - could not create property group (repository read-only) 5906 * - couldn't delete, upgrade, or import pg or dependent 5907 * EACCES - could not create property group (backend access denied) 5908 * - couldn't delete, upgrade, or import pg or dependent 5909 * EEXIST - dependent collision in target service (error printed) 5910 */ 5911 static int 5912 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5913 entity_t *ient) 5914 { 5915 pgroup_t *pg, *rpg; 5916 int r; 5917 uu_list_t *pgs = ient->sc_pgroups; 5918 5919 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5920 5921 /* clear sc_sceen for pgs */ 5922 if (uu_list_walk(pgs, clear_int, 5923 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5924 bad_error("uu_list_walk", uu_error()); 5925 5926 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5927 switch (scf_error()) { 5928 case SCF_ERROR_DELETED: 5929 return (ENODEV); 5930 5931 case SCF_ERROR_CONNECTION_BROKEN: 5932 return (ECONNABORTED); 5933 5934 case SCF_ERROR_NOT_SET: 5935 case SCF_ERROR_NOT_BOUND: 5936 case SCF_ERROR_HANDLE_MISMATCH: 5937 default: 5938 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5939 } 5940 } 5941 5942 for (;;) { 5943 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5944 if (r == 0) 5945 break; 5946 if (r == 1) { 5947 r = process_old_pg(imp_pg, ient, ent, running); 5948 switch (r) { 5949 case 0: 5950 break; 5951 5952 case ECONNABORTED: 5953 case ENOMEM: 5954 case ENOSPC: 5955 case ECANCELED: 5956 case ENODEV: 5957 case EPERM: 5958 case EROFS: 5959 case EACCES: 5960 case EBADF: 5961 case EBUSY: 5962 case EINVAL: 5963 case EEXIST: 5964 return (r); 5965 5966 default: 5967 bad_error("process_old_pg", r); 5968 } 5969 continue; 5970 } 5971 if (r != -1) 5972 bad_error("scf_iter_next_pg", r); 5973 5974 switch (scf_error()) { 5975 case SCF_ERROR_DELETED: 5976 return (ENODEV); 5977 5978 case SCF_ERROR_CONNECTION_BROKEN: 5979 return (ECONNABORTED); 5980 5981 case SCF_ERROR_HANDLE_MISMATCH: 5982 case SCF_ERROR_NOT_BOUND: 5983 case SCF_ERROR_NOT_SET: 5984 case SCF_ERROR_INVALID_ARGUMENT: 5985 default: 5986 bad_error("scf_iter_next_pg", scf_error()); 5987 } 5988 } 5989 5990 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5991 if (pg->sc_pgroup_seen) 5992 continue; 5993 5994 /* pg is new */ 5995 5996 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5997 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5998 ent); 5999 switch (r) { 6000 case 0: 6001 break; 6002 6003 case ECONNABORTED: 6004 case ENOMEM: 6005 case ENOSPC: 6006 case ECANCELED: 6007 case ENODEV: 6008 case EBADF: 6009 case EBUSY: 6010 case EINVAL: 6011 case EPERM: 6012 case EROFS: 6013 case EACCES: 6014 case EEXIST: 6015 return (r); 6016 6017 default: 6018 bad_error("upgrade_dependents", r); 6019 } 6020 continue; 6021 } 6022 6023 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 6024 r = upgrade_manifestfiles(pg, ient, running, ent); 6025 switch (r) { 6026 case 0: 6027 break; 6028 6029 case ECONNABORTED: 6030 case ENOMEM: 6031 case ENOSPC: 6032 case ECANCELED: 6033 case ENODEV: 6034 case EBADF: 6035 case EBUSY: 6036 case EINVAL: 6037 case EPERM: 6038 case EROFS: 6039 case EACCES: 6040 case EEXIST: 6041 return (r); 6042 6043 default: 6044 bad_error("upgrade_manifestfiles", r); 6045 } 6046 continue; 6047 } 6048 6049 if (running != NULL) { 6050 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 6051 imp_pg); 6052 } else { 6053 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 6054 imp_pg); 6055 } 6056 if (r != 0) { 6057 scf_callback_t cbdata; 6058 6059 switch (scf_error()) { 6060 case SCF_ERROR_NOT_FOUND: 6061 break; 6062 6063 case SCF_ERROR_CONNECTION_BROKEN: 6064 return (scferror2errno(scf_error())); 6065 6066 case SCF_ERROR_DELETED: 6067 if (running != NULL) 6068 return (ENODEV); 6069 else 6070 return (scferror2errno(scf_error())); 6071 6072 case SCF_ERROR_INVALID_ARGUMENT: 6073 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 6074 pg->sc_pgroup_name); 6075 return (EINVAL); 6076 6077 case SCF_ERROR_NOT_SET: 6078 case SCF_ERROR_HANDLE_MISMATCH: 6079 case SCF_ERROR_NOT_BOUND: 6080 default: 6081 bad_error("entity_get_pg", scf_error()); 6082 } 6083 6084 /* User doesn't have pg, so import it. */ 6085 6086 cbdata.sc_handle = g_hndl; 6087 cbdata.sc_parent = ent; 6088 cbdata.sc_service = issvc; 6089 cbdata.sc_flags = SCI_FORCE; 6090 cbdata.sc_source_fmri = ient->sc_fmri; 6091 cbdata.sc_target_fmri = ient->sc_fmri; 6092 6093 r = entity_pgroup_import(pg, &cbdata); 6094 switch (r) { 6095 case UU_WALK_NEXT: 6096 ient->sc_import_state = IMPORT_PROP_BEGUN; 6097 continue; 6098 6099 case UU_WALK_ERROR: 6100 if (cbdata.sc_err == EEXIST) { 6101 warn(emsg_pg_added, ient->sc_fmri, 6102 pg->sc_pgroup_name); 6103 return (EBUSY); 6104 } 6105 return (cbdata.sc_err); 6106 6107 default: 6108 bad_error("entity_pgroup_import", r); 6109 } 6110 } 6111 6112 /* report differences between pg & current */ 6113 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 6114 switch (r) { 6115 case 0: 6116 break; 6117 6118 case ECANCELED: 6119 warn(emsg_pg_deleted, ient->sc_fmri, 6120 pg->sc_pgroup_name); 6121 return (EBUSY); 6122 6123 case ECONNABORTED: 6124 case EBADF: 6125 case ENOMEM: 6126 case EACCES: 6127 return (r); 6128 6129 default: 6130 bad_error("load_pg", r); 6131 } 6132 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 6133 internal_pgroup_free(rpg); 6134 rpg = NULL; 6135 } 6136 6137 return (0); 6138 } 6139 6140 /* 6141 * Import an instance. If it doesn't exist, create it. If it has 6142 * a last-import snapshot, upgrade its properties. Finish by updating its 6143 * last-import snapshot. If it doesn't have a last-import snapshot then it 6144 * could have been created for a dependent tag in another manifest. Import the 6145 * new properties. If there's a conflict, don't override, like now? 6146 * 6147 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 6148 * lcbdata->sc_err to 6149 * ECONNABORTED - repository connection broken 6150 * ENOMEM - out of memory 6151 * ENOSPC - svc.configd is out of resources 6152 * EEXIST - dependency collision in dependent service (error printed) 6153 * EPERM - couldn't create temporary instance (permission denied) 6154 * - couldn't import into temporary instance (permission denied) 6155 * - couldn't take snapshot (permission denied) 6156 * - couldn't upgrade properties (permission denied) 6157 * - couldn't import properties (permission denied) 6158 * - couldn't import dependents (permission denied) 6159 * EROFS - couldn't create temporary instance (repository read-only) 6160 * - couldn't import into temporary instance (repository read-only) 6161 * - couldn't upgrade properties (repository read-only) 6162 * - couldn't import properties (repository read-only) 6163 * - couldn't import dependents (repository read-only) 6164 * EACCES - couldn't create temporary instance (backend access denied) 6165 * - couldn't import into temporary instance (backend access denied) 6166 * - couldn't upgrade properties (backend access denied) 6167 * - couldn't import properties (backend access denied) 6168 * - couldn't import dependents (backend access denied) 6169 * EINVAL - invalid instance name (error printed) 6170 * - invalid pgroup_t's (error printed) 6171 * - invalid dependents (error printed) 6172 * EBUSY - temporary service deleted (error printed) 6173 * - temporary instance deleted (error printed) 6174 * - temporary instance changed (error printed) 6175 * - temporary instance already exists (error printed) 6176 * - instance deleted (error printed) 6177 * EBADF - instance has corrupt last-import snapshot (error printed) 6178 * - instance is corrupt (error printed) 6179 * - dependent has corrupt pg (error printed) 6180 * - dependent target has a corrupt snapshot (error printed) 6181 * -1 - unknown libscf error (error printed) 6182 */ 6183 static int 6184 lscf_instance_import(void *v, void *pvt) 6185 { 6186 entity_t *inst = v; 6187 scf_callback_t ctx; 6188 scf_callback_t *lcbdata = pvt; 6189 scf_service_t *rsvc = lcbdata->sc_parent; 6190 int r; 6191 scf_snaplevel_t *running; 6192 int flags = lcbdata->sc_flags; 6193 6194 const char * const emsg_tdel = 6195 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 6196 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 6197 "changed unexpectedly.\n"); 6198 const char * const emsg_del = gettext("%s changed unexpectedly " 6199 "(instance \"%s\" was deleted.)\n"); 6200 const char * const emsg_badsnap = gettext( 6201 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 6202 6203 /* 6204 * prepare last-import snapshot: 6205 * create temporary instance (service was precreated) 6206 * populate with properties from bundle 6207 * take snapshot 6208 */ 6209 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 6210 switch (scf_error()) { 6211 case SCF_ERROR_CONNECTION_BROKEN: 6212 case SCF_ERROR_NO_RESOURCES: 6213 case SCF_ERROR_BACKEND_READONLY: 6214 case SCF_ERROR_BACKEND_ACCESS: 6215 return (stash_scferror(lcbdata)); 6216 6217 case SCF_ERROR_EXISTS: 6218 warn(gettext("Temporary service svc:/%s " 6219 "changed unexpectedly (instance \"%s\" added).\n"), 6220 imp_tsname, inst->sc_name); 6221 lcbdata->sc_err = EBUSY; 6222 return (UU_WALK_ERROR); 6223 6224 case SCF_ERROR_DELETED: 6225 warn(gettext("Temporary service svc:/%s " 6226 "was deleted unexpectedly.\n"), imp_tsname); 6227 lcbdata->sc_err = EBUSY; 6228 return (UU_WALK_ERROR); 6229 6230 case SCF_ERROR_INVALID_ARGUMENT: 6231 warn(gettext("Invalid instance name \"%s\".\n"), 6232 inst->sc_name); 6233 return (stash_scferror(lcbdata)); 6234 6235 case SCF_ERROR_PERMISSION_DENIED: 6236 warn(gettext("Could not create temporary instance " 6237 "\"%s\" in svc:/%s (permission denied).\n"), 6238 inst->sc_name, imp_tsname); 6239 return (stash_scferror(lcbdata)); 6240 6241 case SCF_ERROR_HANDLE_MISMATCH: 6242 case SCF_ERROR_NOT_BOUND: 6243 case SCF_ERROR_NOT_SET: 6244 default: 6245 bad_error("scf_service_add_instance", scf_error()); 6246 } 6247 } 6248 6249 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6250 inst->sc_name); 6251 if (r < 0) 6252 bad_error("snprintf", errno); 6253 6254 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 6255 lcbdata->sc_flags | SCI_NOENABLED); 6256 switch (r) { 6257 case 0: 6258 break; 6259 6260 case ECANCELED: 6261 warn(emsg_tdel, imp_tsname, inst->sc_name); 6262 lcbdata->sc_err = EBUSY; 6263 r = UU_WALK_ERROR; 6264 goto deltemp; 6265 6266 case EEXIST: 6267 warn(emsg_tchg, imp_tsname, inst->sc_name); 6268 lcbdata->sc_err = EBUSY; 6269 r = UU_WALK_ERROR; 6270 goto deltemp; 6271 6272 case ECONNABORTED: 6273 goto connaborted; 6274 6275 case ENOMEM: 6276 case ENOSPC: 6277 case EPERM: 6278 case EROFS: 6279 case EACCES: 6280 case EINVAL: 6281 case EBUSY: 6282 lcbdata->sc_err = r; 6283 r = UU_WALK_ERROR; 6284 goto deltemp; 6285 6286 default: 6287 bad_error("lscf_import_instance_pgs", r); 6288 } 6289 6290 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6291 inst->sc_name); 6292 if (r < 0) 6293 bad_error("snprintf", errno); 6294 6295 ctx.sc_handle = lcbdata->sc_handle; 6296 ctx.sc_parent = imp_tinst; 6297 ctx.sc_service = 0; 6298 ctx.sc_source_fmri = inst->sc_fmri; 6299 ctx.sc_target_fmri = imp_str; 6300 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 6301 UU_DEFAULT) != 0) { 6302 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6303 bad_error("uu_list_walk", uu_error()); 6304 6305 switch (ctx.sc_err) { 6306 case ECONNABORTED: 6307 goto connaborted; 6308 6309 case ECANCELED: 6310 warn(emsg_tdel, imp_tsname, inst->sc_name); 6311 lcbdata->sc_err = EBUSY; 6312 break; 6313 6314 case EEXIST: 6315 warn(emsg_tchg, imp_tsname, inst->sc_name); 6316 lcbdata->sc_err = EBUSY; 6317 break; 6318 6319 default: 6320 lcbdata->sc_err = ctx.sc_err; 6321 } 6322 r = UU_WALK_ERROR; 6323 goto deltemp; 6324 } 6325 6326 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 6327 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 6328 switch (scf_error()) { 6329 case SCF_ERROR_CONNECTION_BROKEN: 6330 goto connaborted; 6331 6332 case SCF_ERROR_NO_RESOURCES: 6333 r = stash_scferror(lcbdata); 6334 goto deltemp; 6335 6336 case SCF_ERROR_EXISTS: 6337 warn(emsg_tchg, imp_tsname, inst->sc_name); 6338 lcbdata->sc_err = EBUSY; 6339 r = UU_WALK_ERROR; 6340 goto deltemp; 6341 6342 case SCF_ERROR_PERMISSION_DENIED: 6343 warn(gettext("Could not take \"%s\" snapshot of %s " 6344 "(permission denied).\n"), snap_lastimport, 6345 imp_str); 6346 r = stash_scferror(lcbdata); 6347 goto deltemp; 6348 6349 default: 6350 scfwarn(); 6351 lcbdata->sc_err = -1; 6352 r = UU_WALK_ERROR; 6353 goto deltemp; 6354 6355 case SCF_ERROR_HANDLE_MISMATCH: 6356 case SCF_ERROR_INVALID_ARGUMENT: 6357 case SCF_ERROR_NOT_SET: 6358 bad_error("_scf_snapshot_take_new_named", scf_error()); 6359 } 6360 } 6361 6362 if (lcbdata->sc_flags & SCI_FRESH) 6363 goto fresh; 6364 6365 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 6366 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6367 imp_lisnap) != 0) { 6368 switch (scf_error()) { 6369 case SCF_ERROR_DELETED: 6370 warn(emsg_del, inst->sc_parent->sc_fmri, 6371 inst->sc_name); 6372 lcbdata->sc_err = EBUSY; 6373 r = UU_WALK_ERROR; 6374 goto deltemp; 6375 6376 case SCF_ERROR_NOT_FOUND: 6377 flags |= SCI_FORCE; 6378 goto nosnap; 6379 6380 case SCF_ERROR_CONNECTION_BROKEN: 6381 goto connaborted; 6382 6383 case SCF_ERROR_INVALID_ARGUMENT: 6384 case SCF_ERROR_HANDLE_MISMATCH: 6385 case SCF_ERROR_NOT_BOUND: 6386 case SCF_ERROR_NOT_SET: 6387 default: 6388 bad_error("scf_instance_get_snapshot", 6389 scf_error()); 6390 } 6391 } 6392 6393 /* upgrade */ 6394 6395 /* 6396 * compare new properties with last-import properties 6397 * upgrade current properties 6398 */ 6399 /* clear sc_sceen for pgs */ 6400 if (uu_list_walk(inst->sc_pgroups, clear_int, 6401 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 6402 0) 6403 bad_error("uu_list_walk", uu_error()); 6404 6405 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 6406 switch (r) { 6407 case 0: 6408 break; 6409 6410 case ECONNABORTED: 6411 goto connaborted; 6412 6413 case ECANCELED: 6414 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6415 lcbdata->sc_err = EBUSY; 6416 r = UU_WALK_ERROR; 6417 goto deltemp; 6418 6419 case ENOENT: 6420 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 6421 lcbdata->sc_err = EBADF; 6422 r = UU_WALK_ERROR; 6423 goto deltemp; 6424 6425 default: 6426 bad_error("get_snaplevel", r); 6427 } 6428 6429 if (scf_instance_get_snapshot(imp_inst, snap_running, 6430 imp_rsnap) != 0) { 6431 switch (scf_error()) { 6432 case SCF_ERROR_DELETED: 6433 warn(emsg_del, inst->sc_parent->sc_fmri, 6434 inst->sc_name); 6435 lcbdata->sc_err = EBUSY; 6436 r = UU_WALK_ERROR; 6437 goto deltemp; 6438 6439 case SCF_ERROR_NOT_FOUND: 6440 break; 6441 6442 case SCF_ERROR_CONNECTION_BROKEN: 6443 goto connaborted; 6444 6445 case SCF_ERROR_INVALID_ARGUMENT: 6446 case SCF_ERROR_HANDLE_MISMATCH: 6447 case SCF_ERROR_NOT_BOUND: 6448 case SCF_ERROR_NOT_SET: 6449 default: 6450 bad_error("scf_instance_get_snapshot", 6451 scf_error()); 6452 } 6453 6454 running = NULL; 6455 } else { 6456 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 6457 switch (r) { 6458 case 0: 6459 running = imp_rsnpl; 6460 break; 6461 6462 case ECONNABORTED: 6463 goto connaborted; 6464 6465 case ECANCELED: 6466 warn(emsg_del, inst->sc_parent->sc_fmri, 6467 inst->sc_name); 6468 lcbdata->sc_err = EBUSY; 6469 r = UU_WALK_ERROR; 6470 goto deltemp; 6471 6472 case ENOENT: 6473 warn(emsg_badsnap, snap_running, inst->sc_fmri); 6474 lcbdata->sc_err = EBADF; 6475 r = UU_WALK_ERROR; 6476 goto deltemp; 6477 6478 default: 6479 bad_error("get_snaplevel", r); 6480 } 6481 } 6482 6483 r = upgrade_props(imp_inst, running, imp_snpl, inst); 6484 switch (r) { 6485 case 0: 6486 break; 6487 6488 case ECANCELED: 6489 case ENODEV: 6490 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6491 lcbdata->sc_err = EBUSY; 6492 r = UU_WALK_ERROR; 6493 goto deltemp; 6494 6495 case ECONNABORTED: 6496 goto connaborted; 6497 6498 case ENOMEM: 6499 case ENOSPC: 6500 case EBADF: 6501 case EBUSY: 6502 case EINVAL: 6503 case EPERM: 6504 case EROFS: 6505 case EACCES: 6506 case EEXIST: 6507 lcbdata->sc_err = r; 6508 r = UU_WALK_ERROR; 6509 goto deltemp; 6510 6511 default: 6512 bad_error("upgrade_props", r); 6513 } 6514 6515 inst->sc_import_state = IMPORT_PROP_DONE; 6516 } else { 6517 switch (scf_error()) { 6518 case SCF_ERROR_CONNECTION_BROKEN: 6519 goto connaborted; 6520 6521 case SCF_ERROR_NOT_FOUND: 6522 break; 6523 6524 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6525 case SCF_ERROR_HANDLE_MISMATCH: 6526 case SCF_ERROR_NOT_BOUND: 6527 case SCF_ERROR_NOT_SET: 6528 default: 6529 bad_error("scf_service_get_instance", scf_error()); 6530 } 6531 6532 fresh: 6533 /* create instance */ 6534 if (scf_service_add_instance(rsvc, inst->sc_name, 6535 imp_inst) != 0) { 6536 switch (scf_error()) { 6537 case SCF_ERROR_CONNECTION_BROKEN: 6538 goto connaborted; 6539 6540 case SCF_ERROR_NO_RESOURCES: 6541 case SCF_ERROR_BACKEND_READONLY: 6542 case SCF_ERROR_BACKEND_ACCESS: 6543 r = stash_scferror(lcbdata); 6544 goto deltemp; 6545 6546 case SCF_ERROR_EXISTS: 6547 warn(gettext("%s changed unexpectedly " 6548 "(instance \"%s\" added).\n"), 6549 inst->sc_parent->sc_fmri, inst->sc_name); 6550 lcbdata->sc_err = EBUSY; 6551 r = UU_WALK_ERROR; 6552 goto deltemp; 6553 6554 case SCF_ERROR_PERMISSION_DENIED: 6555 warn(gettext("Could not create \"%s\" instance " 6556 "in %s (permission denied).\n"), 6557 inst->sc_name, inst->sc_parent->sc_fmri); 6558 r = stash_scferror(lcbdata); 6559 goto deltemp; 6560 6561 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6562 case SCF_ERROR_HANDLE_MISMATCH: 6563 case SCF_ERROR_NOT_BOUND: 6564 case SCF_ERROR_NOT_SET: 6565 default: 6566 bad_error("scf_service_add_instance", 6567 scf_error()); 6568 } 6569 } 6570 6571 nosnap: 6572 /* 6573 * Create a last-import snapshot to serve as an attachment 6574 * point for the real one from the temporary instance. Since 6575 * the contents is irrelevant, take it now, while the instance 6576 * is empty, to minimize svc.configd's work. 6577 */ 6578 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6579 imp_lisnap) != 0) { 6580 switch (scf_error()) { 6581 case SCF_ERROR_CONNECTION_BROKEN: 6582 goto connaborted; 6583 6584 case SCF_ERROR_NO_RESOURCES: 6585 r = stash_scferror(lcbdata); 6586 goto deltemp; 6587 6588 case SCF_ERROR_EXISTS: 6589 warn(gettext("%s changed unexpectedly " 6590 "(snapshot \"%s\" added).\n"), 6591 inst->sc_fmri, snap_lastimport); 6592 lcbdata->sc_err = EBUSY; 6593 r = UU_WALK_ERROR; 6594 goto deltemp; 6595 6596 case SCF_ERROR_PERMISSION_DENIED: 6597 warn(gettext("Could not take \"%s\" snapshot " 6598 "of %s (permission denied).\n"), 6599 snap_lastimport, inst->sc_fmri); 6600 r = stash_scferror(lcbdata); 6601 goto deltemp; 6602 6603 default: 6604 scfwarn(); 6605 lcbdata->sc_err = -1; 6606 r = UU_WALK_ERROR; 6607 goto deltemp; 6608 6609 case SCF_ERROR_NOT_SET: 6610 case SCF_ERROR_INTERNAL: 6611 case SCF_ERROR_INVALID_ARGUMENT: 6612 case SCF_ERROR_HANDLE_MISMATCH: 6613 bad_error("_scf_snapshot_take_new", 6614 scf_error()); 6615 } 6616 } 6617 6618 if (li_only) 6619 goto lionly; 6620 6621 inst->sc_import_state = IMPORT_PROP_BEGUN; 6622 6623 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6624 flags); 6625 switch (r) { 6626 case 0: 6627 break; 6628 6629 case ECONNABORTED: 6630 goto connaborted; 6631 6632 case ECANCELED: 6633 warn(gettext("%s changed unexpectedly " 6634 "(instance \"%s\" deleted).\n"), 6635 inst->sc_parent->sc_fmri, inst->sc_name); 6636 lcbdata->sc_err = EBUSY; 6637 r = UU_WALK_ERROR; 6638 goto deltemp; 6639 6640 case EEXIST: 6641 warn(gettext("%s changed unexpectedly " 6642 "(property group added).\n"), inst->sc_fmri); 6643 lcbdata->sc_err = EBUSY; 6644 r = UU_WALK_ERROR; 6645 goto deltemp; 6646 6647 default: 6648 lcbdata->sc_err = r; 6649 r = UU_WALK_ERROR; 6650 goto deltemp; 6651 6652 case EINVAL: /* caught above */ 6653 bad_error("lscf_import_instance_pgs", r); 6654 } 6655 6656 ctx.sc_parent = imp_inst; 6657 ctx.sc_service = 0; 6658 ctx.sc_trans = NULL; 6659 ctx.sc_flags = 0; 6660 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6661 &ctx, UU_DEFAULT) != 0) { 6662 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6663 bad_error("uu_list_walk", uu_error()); 6664 6665 if (ctx.sc_err == ECONNABORTED) 6666 goto connaborted; 6667 lcbdata->sc_err = ctx.sc_err; 6668 r = UU_WALK_ERROR; 6669 goto deltemp; 6670 } 6671 6672 inst->sc_import_state = IMPORT_PROP_DONE; 6673 6674 if (g_verbose) 6675 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6676 snap_initial, inst->sc_fmri); 6677 r = take_snap(imp_inst, snap_initial, imp_snap); 6678 switch (r) { 6679 case 0: 6680 break; 6681 6682 case ECONNABORTED: 6683 goto connaborted; 6684 6685 case ENOSPC: 6686 case -1: 6687 lcbdata->sc_err = r; 6688 r = UU_WALK_ERROR; 6689 goto deltemp; 6690 6691 case ECANCELED: 6692 warn(gettext("%s changed unexpectedly " 6693 "(instance %s deleted).\n"), 6694 inst->sc_parent->sc_fmri, inst->sc_name); 6695 lcbdata->sc_err = r; 6696 r = UU_WALK_ERROR; 6697 goto deltemp; 6698 6699 case EPERM: 6700 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6701 lcbdata->sc_err = r; 6702 r = UU_WALK_ERROR; 6703 goto deltemp; 6704 6705 default: 6706 bad_error("take_snap", r); 6707 } 6708 } 6709 6710 lionly: 6711 if (lcbdata->sc_flags & SCI_NOSNAP) 6712 goto deltemp; 6713 6714 /* transfer snapshot from temporary instance */ 6715 if (g_verbose) 6716 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6717 snap_lastimport, inst->sc_fmri); 6718 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6719 switch (scf_error()) { 6720 case SCF_ERROR_CONNECTION_BROKEN: 6721 goto connaborted; 6722 6723 case SCF_ERROR_NO_RESOURCES: 6724 r = stash_scferror(lcbdata); 6725 goto deltemp; 6726 6727 case SCF_ERROR_PERMISSION_DENIED: 6728 warn(gettext("Could not take \"%s\" snapshot for %s " 6729 "(permission denied).\n"), snap_lastimport, 6730 inst->sc_fmri); 6731 r = stash_scferror(lcbdata); 6732 goto deltemp; 6733 6734 case SCF_ERROR_NOT_SET: 6735 case SCF_ERROR_HANDLE_MISMATCH: 6736 default: 6737 bad_error("_scf_snapshot_attach", scf_error()); 6738 } 6739 } 6740 6741 inst->sc_import_state = IMPORT_COMPLETE; 6742 6743 r = UU_WALK_NEXT; 6744 6745 deltemp: 6746 /* delete temporary instance */ 6747 if (scf_instance_delete(imp_tinst) != 0) { 6748 switch (scf_error()) { 6749 case SCF_ERROR_DELETED: 6750 break; 6751 6752 case SCF_ERROR_CONNECTION_BROKEN: 6753 goto connaborted; 6754 6755 case SCF_ERROR_NOT_SET: 6756 case SCF_ERROR_NOT_BOUND: 6757 default: 6758 bad_error("scf_instance_delete", scf_error()); 6759 } 6760 } 6761 6762 return (r); 6763 6764 connaborted: 6765 warn(gettext("Could not delete svc:/%s:%s " 6766 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6767 lcbdata->sc_err = ECONNABORTED; 6768 return (UU_WALK_ERROR); 6769 } 6770 6771 /* 6772 * When an instance is imported we end up telling configd about it. Once we tell 6773 * configd about these changes, startd eventually notices. If this is a new 6774 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter) 6775 * property group. However, many of the other tools expect that this property 6776 * group exists and has certain values. 6777 * 6778 * These values are added asynchronously by startd. We should not return from 6779 * this routine until we can verify that the property group we need is there. 6780 * 6781 * Before we go ahead and verify this, we have to ask ourselves an important 6782 * question: Is the early manifest service currently running? Because if it is 6783 * running and it has invoked us, then the service will never get a restarter 6784 * property because svc.startd is blocked on EMI finishing before it lets itself 6785 * fully connect to svc.configd. Of course, this means that this race condition 6786 * is in fact impossible to 100% eliminate. 6787 * 6788 * svc.startd makes sure that EMI only runs once and has succeeded by checking 6789 * the state of the EMI instance. If it is online it bails out and makes sure 6790 * that it doesn't run again. In this case, we're going to do something similar, 6791 * only if the state is online, then we're going to actually verify. EMI always 6792 * has to be present, but it can be explicitly disabled to reduce the amount of 6793 * damage it can cause. If EMI has been disabled then we no longer have to worry 6794 * about the implicit race condition and can go ahead and check things. If EMI 6795 * is in some state that isn't online or disabled and isn't runinng, then we 6796 * assume that things are rather bad and we're not going to get in your way, 6797 * even if the rest of SMF does. 6798 * 6799 * Returns 0 on success or returns an errno. 6800 */ 6801 #ifndef NATIVE_BUILD 6802 static int 6803 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst) 6804 { 6805 int ret, err; 6806 struct timespec ts; 6807 char *emi_state; 6808 6809 /* 6810 * smf_get_state does not distinguish between its different failure 6811 * modes: memory allocation failures, SMF internal failures, and a lack 6812 * of EMI entirely because it's been removed. In these cases, we're 6813 * going to be conservative and opt to say that if we don't know, better 6814 * to not block import or falsely warn to the user. 6815 */ 6816 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) { 6817 return (0); 6818 } 6819 6820 /* 6821 * As per the block comment for this function check the state of EMI 6822 */ 6823 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 && 6824 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) { 6825 warn(gettext("Not validating instance %s:%s because EMI's " 6826 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state); 6827 free(emi_state); 6828 return (0); 6829 } 6830 6831 free(emi_state); 6832 6833 /* 6834 * First we have to get the property. 6835 */ 6836 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) { 6837 ret = scf_error(); 6838 warn(gettext("Failed to look up service: %s\n"), svc->sc_name); 6839 return (ret); 6840 } 6841 6842 /* 6843 * We should always be able to get the instance. It should already 6844 * exist because we just created it or got it. There probably is a 6845 * slim chance that someone may have come in and deleted it though from 6846 * under us. 6847 */ 6848 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst)) 6849 != 0) { 6850 ret = scf_error(); 6851 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name); 6852 switch (ret) { 6853 case SCF_ERROR_DELETED: 6854 err = ENODEV; 6855 break; 6856 case SCF_ERROR_CONNECTION_BROKEN: 6857 warn(gettext("Lost repository connection\n")); 6858 err = ECONNABORTED; 6859 break; 6860 case SCF_ERROR_NOT_FOUND: 6861 warn(gettext("Instance \"%s\" disappeared out from " 6862 "under us.\n"), inst->sc_name); 6863 err = ENOENT; 6864 break; 6865 default: 6866 bad_error("scf_service_get_instance", ret); 6867 } 6868 6869 return (err); 6870 } 6871 6872 /* 6873 * An astute observer may want to use _scf_wait_pg which would notify us 6874 * of a property group change, unfortunately that does not work if the 6875 * property group in question does not exist. So instead we have to 6876 * manually poll and ask smf the best way to get to it. 6877 */ 6878 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg)) 6879 != SCF_SUCCESS) { 6880 ret = scf_error(); 6881 if (ret != SCF_ERROR_NOT_FOUND) { 6882 warn(gettext("Failed to get restarter property " 6883 "group for instance: %s\n"), inst->sc_name); 6884 switch (ret) { 6885 case SCF_ERROR_DELETED: 6886 err = ENODEV; 6887 break; 6888 case SCF_ERROR_CONNECTION_BROKEN: 6889 warn(gettext("Lost repository connection\n")); 6890 err = ECONNABORTED; 6891 break; 6892 default: 6893 bad_error("scf_service_get_instance", ret); 6894 } 6895 6896 return (err); 6897 } 6898 6899 ts.tv_sec = pg_timeout / NANOSEC; 6900 ts.tv_nsec = pg_timeout % NANOSEC; 6901 6902 (void) nanosleep(&ts, NULL); 6903 } 6904 6905 /* 6906 * svcadm also expects that the SCF_PROPERTY_STATE property is present. 6907 * So in addition to the property group being present, we need to wait 6908 * for the property to be there in some form. 6909 * 6910 * Note that a property group is a frozen snapshot in time. To properly 6911 * get beyond this, you have to refresh the property group each time. 6912 */ 6913 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE, 6914 imp_prop)) != 0) { 6915 6916 ret = scf_error(); 6917 if (ret != SCF_ERROR_NOT_FOUND) { 6918 warn(gettext("Failed to get property %s from the " 6919 "restarter property group of instance %s\n"), 6920 SCF_PROPERTY_STATE, inst->sc_name); 6921 switch (ret) { 6922 case SCF_ERROR_CONNECTION_BROKEN: 6923 warn(gettext("Lost repository connection\n")); 6924 err = ECONNABORTED; 6925 break; 6926 case SCF_ERROR_DELETED: 6927 err = ENODEV; 6928 break; 6929 default: 6930 bad_error("scf_pg_get_property", ret); 6931 } 6932 6933 return (err); 6934 } 6935 6936 ts.tv_sec = pg_timeout / NANOSEC; 6937 ts.tv_nsec = pg_timeout % NANOSEC; 6938 6939 (void) nanosleep(&ts, NULL); 6940 6941 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg); 6942 if (ret != SCF_SUCCESS) { 6943 warn(gettext("Failed to get restarter property " 6944 "group for instance: %s\n"), inst->sc_name); 6945 switch (ret) { 6946 case SCF_ERROR_DELETED: 6947 err = ENODEV; 6948 break; 6949 case SCF_ERROR_CONNECTION_BROKEN: 6950 warn(gettext("Lost repository connection\n")); 6951 err = ECONNABORTED; 6952 break; 6953 default: 6954 bad_error("scf_service_get_instance", ret); 6955 } 6956 6957 return (err); 6958 } 6959 } 6960 6961 /* 6962 * We don't have to free the property groups or other values that we got 6963 * because we stored them in global variables that are allocated and 6964 * freed by the routines that call into these functions. Unless of 6965 * course the rest of the code here that we are basing this on is 6966 * mistaken. 6967 */ 6968 return (0); 6969 } 6970 #endif 6971 6972 /* 6973 * If the service is missing, create it, import its properties, and import the 6974 * instances. Since the service is brand new, it should be empty, and if we 6975 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6976 * 6977 * If the service exists, we want to upgrade its properties and import the 6978 * instances. Upgrade requires a last-import snapshot, though, which are 6979 * children of instances, so first we'll have to go through the instances 6980 * looking for a last-import snapshot. If we don't find one then we'll just 6981 * override-import the service properties (but don't delete existing 6982 * properties: another service might have declared us as a dependent). Before 6983 * we change anything, though, we want to take the previous snapshots. We 6984 * also give lscf_instance_import() a leg up on taking last-import snapshots 6985 * by importing the manifest's service properties into a temporary service. 6986 * 6987 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6988 * sets lcbdata->sc_err to 6989 * ECONNABORTED - repository connection broken 6990 * ENOMEM - out of memory 6991 * ENOSPC - svc.configd is out of resources 6992 * EPERM - couldn't create temporary service (error printed) 6993 * - couldn't import into temp service (error printed) 6994 * - couldn't create service (error printed) 6995 * - couldn't import dependent (error printed) 6996 * - couldn't take snapshot (error printed) 6997 * - couldn't create instance (error printed) 6998 * - couldn't create, modify, or delete pg (error printed) 6999 * - couldn't create, modify, or delete dependent (error printed) 7000 * - couldn't import instance (error printed) 7001 * EROFS - couldn't create temporary service (repository read-only) 7002 * - couldn't import into temporary service (repository read-only) 7003 * - couldn't create service (repository read-only) 7004 * - couldn't import dependent (repository read-only) 7005 * - couldn't create instance (repository read-only) 7006 * - couldn't create, modify, or delete pg or dependent 7007 * - couldn't import instance (repository read-only) 7008 * EACCES - couldn't create temporary service (backend access denied) 7009 * - couldn't import into temporary service (backend access denied) 7010 * - couldn't create service (backend access denied) 7011 * - couldn't import dependent (backend access denied) 7012 * - couldn't create instance (backend access denied) 7013 * - couldn't create, modify, or delete pg or dependent 7014 * - couldn't import instance (backend access denied) 7015 * EINVAL - service name is invalid (error printed) 7016 * - service name is too long (error printed) 7017 * - s has invalid pgroup (error printed) 7018 * - s has invalid dependent (error printed) 7019 * - instance name is invalid (error printed) 7020 * - instance entity_t is invalid (error printed) 7021 * EEXIST - couldn't create temporary service (already exists) (error printed) 7022 * - couldn't import dependent (dependency pg already exists) (printed) 7023 * - dependency collision in dependent service (error printed) 7024 * EBUSY - temporary service deleted (error printed) 7025 * - property group added to temporary service (error printed) 7026 * - new property group changed or was deleted (error printed) 7027 * - service was added unexpectedly (error printed) 7028 * - service was deleted unexpectedly (error printed) 7029 * - property group added to new service (error printed) 7030 * - instance added unexpectedly (error printed) 7031 * - instance deleted unexpectedly (error printed) 7032 * - dependent service deleted unexpectedly (error printed) 7033 * - pg was added, changed, or deleted (error printed) 7034 * - dependent pg changed (error printed) 7035 * - temporary instance added, changed, or deleted (error printed) 7036 * EBADF - a last-import snapshot is corrupt (error printed) 7037 * - the service is corrupt (error printed) 7038 * - a dependent is corrupt (error printed) 7039 * - an instance is corrupt (error printed) 7040 * - an instance has a corrupt last-import snapshot (error printed) 7041 * - dependent target has a corrupt snapshot (error printed) 7042 * -1 - unknown libscf error (error printed) 7043 */ 7044 static int 7045 lscf_service_import(void *v, void *pvt) 7046 { 7047 entity_t *s = v; 7048 scf_callback_t cbdata; 7049 scf_callback_t *lcbdata = pvt; 7050 scf_scope_t *scope = lcbdata->sc_parent; 7051 entity_t *inst, linst; 7052 int r; 7053 int fresh = 0; 7054 scf_snaplevel_t *running; 7055 int have_ge = 0; 7056 boolean_t retried = B_FALSE; 7057 7058 const char * const ts_deleted = gettext("Temporary service svc:/%s " 7059 "was deleted unexpectedly.\n"); 7060 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 7061 "changed unexpectedly (property group added).\n"); 7062 const char * const s_deleted = 7063 gettext("%s was deleted unexpectedly.\n"); 7064 const char * const i_deleted = 7065 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 7066 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 7067 "is corrupt (missing service snaplevel).\n"); 7068 const char * const s_mfile_upd = 7069 gettext("Unable to update the manifest file connection " 7070 "for %s\n"); 7071 7072 li_only = 0; 7073 /* Validate the service name */ 7074 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7075 switch (scf_error()) { 7076 case SCF_ERROR_CONNECTION_BROKEN: 7077 return (stash_scferror(lcbdata)); 7078 7079 case SCF_ERROR_INVALID_ARGUMENT: 7080 warn(gettext("\"%s\" is an invalid service name. " 7081 "Cannot import.\n"), s->sc_name); 7082 return (stash_scferror(lcbdata)); 7083 7084 case SCF_ERROR_NOT_FOUND: 7085 break; 7086 7087 case SCF_ERROR_HANDLE_MISMATCH: 7088 case SCF_ERROR_NOT_BOUND: 7089 case SCF_ERROR_NOT_SET: 7090 default: 7091 bad_error("scf_scope_get_service", scf_error()); 7092 } 7093 } 7094 7095 /* create temporary service */ 7096 /* 7097 * the size of the buffer was reduced to max_scf_name_len to prevent 7098 * hitting bug 6681151. After the bug fix, the size of the buffer 7099 * should be restored to its original value (max_scf_name_len +1) 7100 */ 7101 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 7102 if (r < 0) 7103 bad_error("snprintf", errno); 7104 if (r > max_scf_name_len) { 7105 warn(gettext( 7106 "Service name \"%s\" is too long. Cannot import.\n"), 7107 s->sc_name); 7108 lcbdata->sc_err = EINVAL; 7109 return (UU_WALK_ERROR); 7110 } 7111 7112 retry: 7113 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 7114 switch (scf_error()) { 7115 case SCF_ERROR_CONNECTION_BROKEN: 7116 case SCF_ERROR_NO_RESOURCES: 7117 case SCF_ERROR_BACKEND_READONLY: 7118 case SCF_ERROR_BACKEND_ACCESS: 7119 return (stash_scferror(lcbdata)); 7120 7121 case SCF_ERROR_EXISTS: 7122 if (!retried) { 7123 lscf_delete(imp_tsname, 0); 7124 retried = B_TRUE; 7125 goto retry; 7126 } 7127 warn(gettext( 7128 "Temporary service \"%s\" must be deleted before " 7129 "this manifest can be imported.\n"), imp_tsname); 7130 return (stash_scferror(lcbdata)); 7131 7132 case SCF_ERROR_PERMISSION_DENIED: 7133 warn(gettext("Could not create temporary service " 7134 "\"%s\" (permission denied).\n"), imp_tsname); 7135 return (stash_scferror(lcbdata)); 7136 7137 case SCF_ERROR_INVALID_ARGUMENT: 7138 case SCF_ERROR_HANDLE_MISMATCH: 7139 case SCF_ERROR_NOT_BOUND: 7140 case SCF_ERROR_NOT_SET: 7141 default: 7142 bad_error("scf_scope_add_service", scf_error()); 7143 } 7144 } 7145 7146 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 7147 if (r < 0) 7148 bad_error("snprintf", errno); 7149 7150 cbdata.sc_handle = lcbdata->sc_handle; 7151 cbdata.sc_parent = imp_tsvc; 7152 cbdata.sc_service = 1; 7153 cbdata.sc_source_fmri = s->sc_fmri; 7154 cbdata.sc_target_fmri = imp_str; 7155 cbdata.sc_flags = 0; 7156 7157 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 7158 UU_DEFAULT) != 0) { 7159 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7160 bad_error("uu_list_walk", uu_error()); 7161 7162 lcbdata->sc_err = cbdata.sc_err; 7163 switch (cbdata.sc_err) { 7164 case ECONNABORTED: 7165 goto connaborted; 7166 7167 case ECANCELED: 7168 warn(ts_deleted, imp_tsname); 7169 lcbdata->sc_err = EBUSY; 7170 return (UU_WALK_ERROR); 7171 7172 case EEXIST: 7173 warn(ts_pg_added, imp_tsname); 7174 lcbdata->sc_err = EBUSY; 7175 return (UU_WALK_ERROR); 7176 } 7177 7178 r = UU_WALK_ERROR; 7179 goto deltemp; 7180 } 7181 7182 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 7183 UU_DEFAULT) != 0) { 7184 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7185 bad_error("uu_list_walk", uu_error()); 7186 7187 lcbdata->sc_err = cbdata.sc_err; 7188 switch (cbdata.sc_err) { 7189 case ECONNABORTED: 7190 goto connaborted; 7191 7192 case ECANCELED: 7193 warn(ts_deleted, imp_tsname); 7194 lcbdata->sc_err = EBUSY; 7195 return (UU_WALK_ERROR); 7196 7197 case EEXIST: 7198 warn(ts_pg_added, imp_tsname); 7199 lcbdata->sc_err = EBUSY; 7200 return (UU_WALK_ERROR); 7201 } 7202 7203 r = UU_WALK_ERROR; 7204 goto deltemp; 7205 } 7206 7207 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7208 switch (scf_error()) { 7209 case SCF_ERROR_NOT_FOUND: 7210 break; 7211 7212 case SCF_ERROR_CONNECTION_BROKEN: 7213 goto connaborted; 7214 7215 case SCF_ERROR_INVALID_ARGUMENT: 7216 case SCF_ERROR_HANDLE_MISMATCH: 7217 case SCF_ERROR_NOT_BOUND: 7218 case SCF_ERROR_NOT_SET: 7219 default: 7220 bad_error("scf_scope_get_service", scf_error()); 7221 } 7222 7223 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 7224 switch (scf_error()) { 7225 case SCF_ERROR_CONNECTION_BROKEN: 7226 goto connaborted; 7227 7228 case SCF_ERROR_NO_RESOURCES: 7229 case SCF_ERROR_BACKEND_READONLY: 7230 case SCF_ERROR_BACKEND_ACCESS: 7231 r = stash_scferror(lcbdata); 7232 goto deltemp; 7233 7234 case SCF_ERROR_EXISTS: 7235 warn(gettext("Scope \"%s\" changed unexpectedly" 7236 " (service \"%s\" added).\n"), 7237 SCF_SCOPE_LOCAL, s->sc_name); 7238 lcbdata->sc_err = EBUSY; 7239 goto deltemp; 7240 7241 case SCF_ERROR_PERMISSION_DENIED: 7242 warn(gettext("Could not create service \"%s\" " 7243 "(permission denied).\n"), s->sc_name); 7244 goto deltemp; 7245 7246 case SCF_ERROR_INVALID_ARGUMENT: 7247 case SCF_ERROR_HANDLE_MISMATCH: 7248 case SCF_ERROR_NOT_BOUND: 7249 case SCF_ERROR_NOT_SET: 7250 default: 7251 bad_error("scf_scope_add_service", scf_error()); 7252 } 7253 } 7254 7255 s->sc_import_state = IMPORT_PROP_BEGUN; 7256 7257 /* import service properties */ 7258 cbdata.sc_handle = lcbdata->sc_handle; 7259 cbdata.sc_parent = imp_svc; 7260 cbdata.sc_service = 1; 7261 cbdata.sc_flags = lcbdata->sc_flags; 7262 cbdata.sc_source_fmri = s->sc_fmri; 7263 cbdata.sc_target_fmri = s->sc_fmri; 7264 7265 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7266 &cbdata, UU_DEFAULT) != 0) { 7267 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7268 bad_error("uu_list_walk", uu_error()); 7269 7270 lcbdata->sc_err = cbdata.sc_err; 7271 switch (cbdata.sc_err) { 7272 case ECONNABORTED: 7273 goto connaborted; 7274 7275 case ECANCELED: 7276 warn(s_deleted, s->sc_fmri); 7277 lcbdata->sc_err = EBUSY; 7278 return (UU_WALK_ERROR); 7279 7280 case EEXIST: 7281 warn(gettext("%s changed unexpectedly " 7282 "(property group added).\n"), s->sc_fmri); 7283 lcbdata->sc_err = EBUSY; 7284 return (UU_WALK_ERROR); 7285 7286 case EINVAL: 7287 /* caught above */ 7288 bad_error("entity_pgroup_import", 7289 cbdata.sc_err); 7290 } 7291 7292 r = UU_WALK_ERROR; 7293 goto deltemp; 7294 } 7295 7296 cbdata.sc_trans = NULL; 7297 cbdata.sc_flags = 0; 7298 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 7299 &cbdata, UU_DEFAULT) != 0) { 7300 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7301 bad_error("uu_list_walk", uu_error()); 7302 7303 lcbdata->sc_err = cbdata.sc_err; 7304 if (cbdata.sc_err == ECONNABORTED) 7305 goto connaborted; 7306 r = UU_WALK_ERROR; 7307 goto deltemp; 7308 } 7309 7310 s->sc_import_state = IMPORT_PROP_DONE; 7311 7312 /* 7313 * This is a new service, so we can't take previous snapshots 7314 * or upgrade service properties. 7315 */ 7316 fresh = 1; 7317 goto instances; 7318 } 7319 7320 /* Clear sc_seen for the instances. */ 7321 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 7322 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 7323 bad_error("uu_list_walk", uu_error()); 7324 7325 /* 7326 * Take previous snapshots for all instances. Even for ones not 7327 * mentioned in the bundle, since we might change their service 7328 * properties. 7329 */ 7330 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7331 switch (scf_error()) { 7332 case SCF_ERROR_CONNECTION_BROKEN: 7333 goto connaborted; 7334 7335 case SCF_ERROR_DELETED: 7336 warn(s_deleted, s->sc_fmri); 7337 lcbdata->sc_err = EBUSY; 7338 r = UU_WALK_ERROR; 7339 goto deltemp; 7340 7341 case SCF_ERROR_HANDLE_MISMATCH: 7342 case SCF_ERROR_NOT_BOUND: 7343 case SCF_ERROR_NOT_SET: 7344 default: 7345 bad_error("scf_iter_service_instances", scf_error()); 7346 } 7347 } 7348 7349 for (;;) { 7350 r = scf_iter_next_instance(imp_iter, imp_inst); 7351 if (r == 0) 7352 break; 7353 if (r != 1) { 7354 switch (scf_error()) { 7355 case SCF_ERROR_DELETED: 7356 warn(s_deleted, s->sc_fmri); 7357 lcbdata->sc_err = EBUSY; 7358 r = UU_WALK_ERROR; 7359 goto deltemp; 7360 7361 case SCF_ERROR_CONNECTION_BROKEN: 7362 goto connaborted; 7363 7364 case SCF_ERROR_NOT_BOUND: 7365 case SCF_ERROR_HANDLE_MISMATCH: 7366 case SCF_ERROR_INVALID_ARGUMENT: 7367 case SCF_ERROR_NOT_SET: 7368 default: 7369 bad_error("scf_iter_next_instance", 7370 scf_error()); 7371 } 7372 } 7373 7374 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 7375 switch (scf_error()) { 7376 case SCF_ERROR_DELETED: 7377 continue; 7378 7379 case SCF_ERROR_CONNECTION_BROKEN: 7380 goto connaborted; 7381 7382 case SCF_ERROR_NOT_SET: 7383 case SCF_ERROR_NOT_BOUND: 7384 default: 7385 bad_error("scf_instance_get_name", scf_error()); 7386 } 7387 } 7388 7389 if (g_verbose) 7390 warn(gettext( 7391 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 7392 snap_previous, s->sc_name, imp_str); 7393 7394 r = take_snap(imp_inst, snap_previous, imp_snap); 7395 switch (r) { 7396 case 0: 7397 break; 7398 7399 case ECANCELED: 7400 continue; 7401 7402 case ECONNABORTED: 7403 goto connaborted; 7404 7405 case EPERM: 7406 warn(gettext("Could not take \"%s\" snapshot of " 7407 "svc:/%s:%s (permission denied).\n"), 7408 snap_previous, s->sc_name, imp_str); 7409 lcbdata->sc_err = r; 7410 return (UU_WALK_ERROR); 7411 7412 case ENOSPC: 7413 case -1: 7414 lcbdata->sc_err = r; 7415 r = UU_WALK_ERROR; 7416 goto deltemp; 7417 7418 default: 7419 bad_error("take_snap", r); 7420 } 7421 7422 linst.sc_name = imp_str; 7423 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 7424 &linst, NULL, NULL); 7425 if (inst != NULL) { 7426 inst->sc_import_state = IMPORT_PREVIOUS; 7427 inst->sc_seen = 1; 7428 } 7429 } 7430 7431 /* 7432 * Create the new instances and take previous snapshots of 7433 * them. This is not necessary, but it maximizes data preservation. 7434 */ 7435 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 7436 inst != NULL; 7437 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 7438 inst)) { 7439 if (inst->sc_seen) 7440 continue; 7441 7442 if (scf_service_add_instance(imp_svc, inst->sc_name, 7443 imp_inst) != 0) { 7444 switch (scf_error()) { 7445 case SCF_ERROR_CONNECTION_BROKEN: 7446 goto connaborted; 7447 7448 case SCF_ERROR_BACKEND_READONLY: 7449 case SCF_ERROR_BACKEND_ACCESS: 7450 case SCF_ERROR_NO_RESOURCES: 7451 r = stash_scferror(lcbdata); 7452 goto deltemp; 7453 7454 case SCF_ERROR_EXISTS: 7455 warn(gettext("%s changed unexpectedly " 7456 "(instance \"%s\" added).\n"), s->sc_fmri, 7457 inst->sc_name); 7458 lcbdata->sc_err = EBUSY; 7459 r = UU_WALK_ERROR; 7460 goto deltemp; 7461 7462 case SCF_ERROR_INVALID_ARGUMENT: 7463 warn(gettext("Service \"%s\" has instance with " 7464 "invalid name \"%s\".\n"), s->sc_name, 7465 inst->sc_name); 7466 r = stash_scferror(lcbdata); 7467 goto deltemp; 7468 7469 case SCF_ERROR_PERMISSION_DENIED: 7470 warn(gettext("Could not create instance \"%s\" " 7471 "in %s (permission denied).\n"), 7472 inst->sc_name, s->sc_fmri); 7473 r = stash_scferror(lcbdata); 7474 goto deltemp; 7475 7476 case SCF_ERROR_HANDLE_MISMATCH: 7477 case SCF_ERROR_NOT_BOUND: 7478 case SCF_ERROR_NOT_SET: 7479 default: 7480 bad_error("scf_service_add_instance", 7481 scf_error()); 7482 } 7483 } 7484 7485 if (g_verbose) 7486 warn(gettext("Taking \"%s\" snapshot for " 7487 "new service %s.\n"), snap_previous, inst->sc_fmri); 7488 r = take_snap(imp_inst, snap_previous, imp_snap); 7489 switch (r) { 7490 case 0: 7491 break; 7492 7493 case ECANCELED: 7494 warn(i_deleted, s->sc_fmri, inst->sc_name); 7495 lcbdata->sc_err = EBUSY; 7496 r = UU_WALK_ERROR; 7497 goto deltemp; 7498 7499 case ECONNABORTED: 7500 goto connaborted; 7501 7502 case EPERM: 7503 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 7504 lcbdata->sc_err = r; 7505 r = UU_WALK_ERROR; 7506 goto deltemp; 7507 7508 case ENOSPC: 7509 case -1: 7510 r = UU_WALK_ERROR; 7511 goto deltemp; 7512 7513 default: 7514 bad_error("take_snap", r); 7515 } 7516 } 7517 7518 s->sc_import_state = IMPORT_PREVIOUS; 7519 7520 /* 7521 * Upgrade service properties, if we can find a last-import snapshot. 7522 * Any will do because we don't support different service properties 7523 * in different manifests, so all snaplevels of the service in all of 7524 * the last-import snapshots of the instances should be the same. 7525 */ 7526 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7527 switch (scf_error()) { 7528 case SCF_ERROR_CONNECTION_BROKEN: 7529 goto connaborted; 7530 7531 case SCF_ERROR_DELETED: 7532 warn(s_deleted, s->sc_fmri); 7533 lcbdata->sc_err = EBUSY; 7534 r = UU_WALK_ERROR; 7535 goto deltemp; 7536 7537 case SCF_ERROR_HANDLE_MISMATCH: 7538 case SCF_ERROR_NOT_BOUND: 7539 case SCF_ERROR_NOT_SET: 7540 default: 7541 bad_error("scf_iter_service_instances", scf_error()); 7542 } 7543 } 7544 7545 for (;;) { 7546 r = scf_iter_next_instance(imp_iter, imp_inst); 7547 if (r == -1) { 7548 switch (scf_error()) { 7549 case SCF_ERROR_DELETED: 7550 warn(s_deleted, s->sc_fmri); 7551 lcbdata->sc_err = EBUSY; 7552 r = UU_WALK_ERROR; 7553 goto deltemp; 7554 7555 case SCF_ERROR_CONNECTION_BROKEN: 7556 goto connaborted; 7557 7558 case SCF_ERROR_NOT_BOUND: 7559 case SCF_ERROR_HANDLE_MISMATCH: 7560 case SCF_ERROR_INVALID_ARGUMENT: 7561 case SCF_ERROR_NOT_SET: 7562 default: 7563 bad_error("scf_iter_next_instance", 7564 scf_error()); 7565 } 7566 } 7567 7568 if (r == 0) { 7569 /* 7570 * Didn't find any last-import snapshots. Override- 7571 * import the properties. Unless one of the instances 7572 * has a general/enabled property, in which case we're 7573 * probably running a last-import-capable svccfg for 7574 * the first time, and we should only take the 7575 * last-import snapshot. 7576 */ 7577 if (have_ge) { 7578 pgroup_t *mfpg; 7579 scf_callback_t mfcbdata; 7580 7581 li_only = 1; 7582 no_refresh = 1; 7583 /* 7584 * Need to go ahead and import the manifestfiles 7585 * pg if it exists. If the last-import snapshot 7586 * upgrade code is ever removed this code can 7587 * be removed as well. 7588 */ 7589 mfpg = internal_pgroup_find(s, 7590 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 7591 7592 if (mfpg) { 7593 mfcbdata.sc_handle = g_hndl; 7594 mfcbdata.sc_parent = imp_svc; 7595 mfcbdata.sc_service = 1; 7596 mfcbdata.sc_flags = SCI_FORCE; 7597 mfcbdata.sc_source_fmri = s->sc_fmri; 7598 mfcbdata.sc_target_fmri = s->sc_fmri; 7599 if (entity_pgroup_import(mfpg, 7600 &mfcbdata) != UU_WALK_NEXT) { 7601 warn(s_mfile_upd, s->sc_fmri); 7602 r = UU_WALK_ERROR; 7603 goto deltemp; 7604 } 7605 } 7606 break; 7607 } 7608 7609 s->sc_import_state = IMPORT_PROP_BEGUN; 7610 7611 cbdata.sc_handle = g_hndl; 7612 cbdata.sc_parent = imp_svc; 7613 cbdata.sc_service = 1; 7614 cbdata.sc_flags = SCI_FORCE; 7615 cbdata.sc_source_fmri = s->sc_fmri; 7616 cbdata.sc_target_fmri = s->sc_fmri; 7617 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7618 &cbdata, UU_DEFAULT) != 0) { 7619 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7620 bad_error("uu_list_walk", uu_error()); 7621 lcbdata->sc_err = cbdata.sc_err; 7622 switch (cbdata.sc_err) { 7623 case ECONNABORTED: 7624 goto connaborted; 7625 7626 case ECANCELED: 7627 warn(s_deleted, s->sc_fmri); 7628 lcbdata->sc_err = EBUSY; 7629 break; 7630 7631 case EINVAL: /* caught above */ 7632 case EEXIST: 7633 bad_error("entity_pgroup_import", 7634 cbdata.sc_err); 7635 } 7636 7637 r = UU_WALK_ERROR; 7638 goto deltemp; 7639 } 7640 7641 cbdata.sc_trans = NULL; 7642 cbdata.sc_flags = 0; 7643 if (uu_list_walk(s->sc_dependents, 7644 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 7645 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7646 bad_error("uu_list_walk", uu_error()); 7647 lcbdata->sc_err = cbdata.sc_err; 7648 if (cbdata.sc_err == ECONNABORTED) 7649 goto connaborted; 7650 r = UU_WALK_ERROR; 7651 goto deltemp; 7652 } 7653 break; 7654 } 7655 7656 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 7657 imp_snap) != 0) { 7658 switch (scf_error()) { 7659 case SCF_ERROR_DELETED: 7660 continue; 7661 7662 case SCF_ERROR_NOT_FOUND: 7663 break; 7664 7665 case SCF_ERROR_CONNECTION_BROKEN: 7666 goto connaborted; 7667 7668 case SCF_ERROR_HANDLE_MISMATCH: 7669 case SCF_ERROR_NOT_BOUND: 7670 case SCF_ERROR_INVALID_ARGUMENT: 7671 case SCF_ERROR_NOT_SET: 7672 default: 7673 bad_error("scf_instance_get_snapshot", 7674 scf_error()); 7675 } 7676 7677 if (have_ge) 7678 continue; 7679 7680 /* 7681 * Check for a general/enabled property. This is how 7682 * we tell whether to import if there turn out to be 7683 * no last-import snapshots. 7684 */ 7685 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 7686 imp_pg) == 0) { 7687 if (scf_pg_get_property(imp_pg, 7688 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 7689 have_ge = 1; 7690 } else { 7691 switch (scf_error()) { 7692 case SCF_ERROR_DELETED: 7693 case SCF_ERROR_NOT_FOUND: 7694 continue; 7695 7696 case SCF_ERROR_INVALID_ARGUMENT: 7697 case SCF_ERROR_HANDLE_MISMATCH: 7698 case SCF_ERROR_CONNECTION_BROKEN: 7699 case SCF_ERROR_NOT_BOUND: 7700 case SCF_ERROR_NOT_SET: 7701 default: 7702 bad_error("scf_pg_get_property", 7703 scf_error()); 7704 } 7705 } 7706 } else { 7707 switch (scf_error()) { 7708 case SCF_ERROR_DELETED: 7709 case SCF_ERROR_NOT_FOUND: 7710 continue; 7711 7712 case SCF_ERROR_CONNECTION_BROKEN: 7713 goto connaborted; 7714 7715 case SCF_ERROR_NOT_BOUND: 7716 case SCF_ERROR_NOT_SET: 7717 case SCF_ERROR_INVALID_ARGUMENT: 7718 case SCF_ERROR_HANDLE_MISMATCH: 7719 default: 7720 bad_error("scf_instance_get_pg", 7721 scf_error()); 7722 } 7723 } 7724 continue; 7725 } 7726 7727 /* find service snaplevel */ 7728 r = get_snaplevel(imp_snap, 1, imp_snpl); 7729 switch (r) { 7730 case 0: 7731 break; 7732 7733 case ECONNABORTED: 7734 goto connaborted; 7735 7736 case ECANCELED: 7737 continue; 7738 7739 case ENOENT: 7740 if (scf_instance_get_name(imp_inst, imp_str, 7741 imp_str_sz) < 0) 7742 (void) strcpy(imp_str, "?"); 7743 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 7744 lcbdata->sc_err = EBADF; 7745 r = UU_WALK_ERROR; 7746 goto deltemp; 7747 7748 default: 7749 bad_error("get_snaplevel", r); 7750 } 7751 7752 if (scf_instance_get_snapshot(imp_inst, snap_running, 7753 imp_rsnap) != 0) { 7754 switch (scf_error()) { 7755 case SCF_ERROR_DELETED: 7756 continue; 7757 7758 case SCF_ERROR_NOT_FOUND: 7759 break; 7760 7761 case SCF_ERROR_CONNECTION_BROKEN: 7762 goto connaborted; 7763 7764 case SCF_ERROR_INVALID_ARGUMENT: 7765 case SCF_ERROR_HANDLE_MISMATCH: 7766 case SCF_ERROR_NOT_BOUND: 7767 case SCF_ERROR_NOT_SET: 7768 default: 7769 bad_error("scf_instance_get_snapshot", 7770 scf_error()); 7771 } 7772 running = NULL; 7773 } else { 7774 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7775 switch (r) { 7776 case 0: 7777 running = imp_rsnpl; 7778 break; 7779 7780 case ECONNABORTED: 7781 goto connaborted; 7782 7783 case ECANCELED: 7784 continue; 7785 7786 case ENOENT: 7787 if (scf_instance_get_name(imp_inst, imp_str, 7788 imp_str_sz) < 0) 7789 (void) strcpy(imp_str, "?"); 7790 warn(badsnap, snap_running, s->sc_name, 7791 imp_str); 7792 lcbdata->sc_err = EBADF; 7793 r = UU_WALK_ERROR; 7794 goto deltemp; 7795 7796 default: 7797 bad_error("get_snaplevel", r); 7798 } 7799 } 7800 7801 if (g_verbose) { 7802 if (scf_instance_get_name(imp_inst, imp_str, 7803 imp_str_sz) < 0) 7804 (void) strcpy(imp_str, "?"); 7805 warn(gettext("Upgrading properties of %s according to " 7806 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7807 } 7808 7809 /* upgrade service properties */ 7810 r = upgrade_props(imp_svc, running, imp_snpl, s); 7811 if (r == 0) 7812 break; 7813 7814 switch (r) { 7815 case ECONNABORTED: 7816 goto connaborted; 7817 7818 case ECANCELED: 7819 warn(s_deleted, s->sc_fmri); 7820 lcbdata->sc_err = EBUSY; 7821 break; 7822 7823 case ENODEV: 7824 if (scf_instance_get_name(imp_inst, imp_str, 7825 imp_str_sz) < 0) 7826 (void) strcpy(imp_str, "?"); 7827 warn(i_deleted, s->sc_fmri, imp_str); 7828 lcbdata->sc_err = EBUSY; 7829 break; 7830 7831 default: 7832 lcbdata->sc_err = r; 7833 } 7834 7835 r = UU_WALK_ERROR; 7836 goto deltemp; 7837 } 7838 7839 s->sc_import_state = IMPORT_PROP_DONE; 7840 7841 instances: 7842 /* import instances */ 7843 cbdata.sc_handle = lcbdata->sc_handle; 7844 cbdata.sc_parent = imp_svc; 7845 cbdata.sc_service = 1; 7846 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7847 cbdata.sc_general = NULL; 7848 7849 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7850 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7851 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7852 bad_error("uu_list_walk", uu_error()); 7853 7854 lcbdata->sc_err = cbdata.sc_err; 7855 if (cbdata.sc_err == ECONNABORTED) 7856 goto connaborted; 7857 r = UU_WALK_ERROR; 7858 goto deltemp; 7859 } 7860 7861 s->sc_import_state = IMPORT_COMPLETE; 7862 r = UU_WALK_NEXT; 7863 7864 deltemp: 7865 /* delete temporary service */ 7866 if (scf_service_delete(imp_tsvc) != 0) { 7867 switch (scf_error()) { 7868 case SCF_ERROR_DELETED: 7869 break; 7870 7871 case SCF_ERROR_CONNECTION_BROKEN: 7872 goto connaborted; 7873 7874 case SCF_ERROR_EXISTS: 7875 warn(gettext( 7876 "Could not delete svc:/%s (instances exist).\n"), 7877 imp_tsname); 7878 break; 7879 7880 case SCF_ERROR_NOT_SET: 7881 case SCF_ERROR_NOT_BOUND: 7882 default: 7883 bad_error("scf_service_delete", scf_error()); 7884 } 7885 } 7886 7887 return (r); 7888 7889 connaborted: 7890 warn(gettext("Could not delete svc:/%s " 7891 "(repository connection broken).\n"), imp_tsname); 7892 lcbdata->sc_err = ECONNABORTED; 7893 return (UU_WALK_ERROR); 7894 } 7895 7896 static const char * 7897 import_progress(int st) 7898 { 7899 switch (st) { 7900 case 0: 7901 return (gettext("not reached.")); 7902 7903 case IMPORT_PREVIOUS: 7904 return (gettext("previous snapshot taken.")); 7905 7906 case IMPORT_PROP_BEGUN: 7907 return (gettext("some properties imported.")); 7908 7909 case IMPORT_PROP_DONE: 7910 return (gettext("properties imported.")); 7911 7912 case IMPORT_COMPLETE: 7913 return (gettext("imported.")); 7914 7915 case IMPORT_REFRESHED: 7916 return (gettext("refresh requested.")); 7917 7918 default: 7919 #ifndef NDEBUG 7920 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7921 __FILE__, __LINE__, st); 7922 #endif 7923 abort(); 7924 /* NOTREACHED */ 7925 } 7926 } 7927 7928 /* 7929 * Returns 7930 * 0 - success 7931 * - fmri wasn't found (error printed) 7932 * - entity was deleted (error printed) 7933 * - backend denied access (error printed) 7934 * ENOMEM - out of memory (error printed) 7935 * ECONNABORTED - repository connection broken (error printed) 7936 * EPERM - permission denied (error printed) 7937 * -1 - unknown libscf error (error printed) 7938 */ 7939 static int 7940 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7941 { 7942 scf_error_t serr; 7943 void *ent; 7944 int issvc; 7945 int r; 7946 7947 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7948 const char *dpt_deleted = gettext("Could not refresh %s " 7949 "(dependent \"%s\" of %s) (deleted).\n"); 7950 7951 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7952 switch (serr) { 7953 case SCF_ERROR_NONE: 7954 break; 7955 7956 case SCF_ERROR_NO_MEMORY: 7957 if (name == NULL) 7958 warn(gettext("Could not refresh %s (out of memory).\n"), 7959 fmri); 7960 else 7961 warn(gettext("Could not refresh %s " 7962 "(dependent \"%s\" of %s) (out of memory).\n"), 7963 fmri, name, d_fmri); 7964 return (ENOMEM); 7965 7966 case SCF_ERROR_NOT_FOUND: 7967 if (name == NULL) 7968 warn(deleted, fmri); 7969 else 7970 warn(dpt_deleted, fmri, name, d_fmri); 7971 return (0); 7972 7973 case SCF_ERROR_INVALID_ARGUMENT: 7974 case SCF_ERROR_CONSTRAINT_VIOLATED: 7975 default: 7976 bad_error("fmri_to_entity", serr); 7977 } 7978 7979 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7980 switch (r) { 7981 case 0: 7982 break; 7983 7984 case ECONNABORTED: 7985 if (name != NULL) 7986 warn(gettext("Could not refresh %s " 7987 "(dependent \"%s\" of %s) " 7988 "(repository connection broken).\n"), fmri, name, 7989 d_fmri); 7990 return (r); 7991 7992 case ECANCELED: 7993 if (name == NULL) 7994 warn(deleted, fmri); 7995 else 7996 warn(dpt_deleted, fmri, name, d_fmri); 7997 return (0); 7998 7999 case EACCES: 8000 if (!g_verbose) 8001 return (0); 8002 if (name == NULL) 8003 warn(gettext("Could not refresh %s " 8004 "(backend access denied).\n"), fmri); 8005 else 8006 warn(gettext("Could not refresh %s " 8007 "(dependent \"%s\" of %s) " 8008 "(backend access denied).\n"), fmri, name, d_fmri); 8009 return (0); 8010 8011 case EPERM: 8012 if (name == NULL) 8013 warn(gettext("Could not refresh %s " 8014 "(permission denied).\n"), fmri); 8015 else 8016 warn(gettext("Could not refresh %s " 8017 "(dependent \"%s\" of %s) " 8018 "(permission denied).\n"), fmri, name, d_fmri); 8019 return (r); 8020 8021 case ENOSPC: 8022 if (name == NULL) 8023 warn(gettext("Could not refresh %s " 8024 "(repository server out of resources).\n"), 8025 fmri); 8026 else 8027 warn(gettext("Could not refresh %s " 8028 "(dependent \"%s\" of %s) " 8029 "(repository server out of resources).\n"), 8030 fmri, name, d_fmri); 8031 return (r); 8032 8033 case -1: 8034 scfwarn(); 8035 return (r); 8036 8037 default: 8038 bad_error("refresh_entity", r); 8039 } 8040 8041 if (issvc) 8042 scf_service_destroy(ent); 8043 else 8044 scf_instance_destroy(ent); 8045 8046 return (0); 8047 } 8048 8049 static int 8050 alloc_imp_globals() 8051 { 8052 int r; 8053 8054 const char * const emsg_nomem = gettext("Out of memory.\n"); 8055 const char * const emsg_nores = 8056 gettext("svc.configd is out of resources.\n"); 8057 8058 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 8059 max_scf_name_len : max_scf_fmri_len) + 1; 8060 8061 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 8062 (imp_svc = scf_service_create(g_hndl)) == NULL || 8063 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 8064 (imp_inst = scf_instance_create(g_hndl)) == NULL || 8065 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 8066 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 8067 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 8068 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 8069 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 8070 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8071 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 8072 (imp_pg = scf_pg_create(g_hndl)) == NULL || 8073 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 8074 (imp_prop = scf_property_create(g_hndl)) == NULL || 8075 (imp_iter = scf_iter_create(g_hndl)) == NULL || 8076 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 8077 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 8078 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 8079 (imp_str = malloc(imp_str_sz)) == NULL || 8080 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 8081 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 8082 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 8083 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 8084 (ud_inst = scf_instance_create(g_hndl)) == NULL || 8085 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8086 (ud_pg = scf_pg_create(g_hndl)) == NULL || 8087 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 8088 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 8089 (ud_prop = scf_property_create(g_hndl)) == NULL || 8090 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 8091 (ud_val = scf_value_create(g_hndl)) == NULL || 8092 (ud_iter = scf_iter_create(g_hndl)) == NULL || 8093 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 8094 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 8095 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 8096 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 8097 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 8098 if (scf_error() == SCF_ERROR_NO_RESOURCES) 8099 warn(emsg_nores); 8100 else 8101 warn(emsg_nomem); 8102 8103 return (-1); 8104 } 8105 8106 r = load_init(); 8107 switch (r) { 8108 case 0: 8109 break; 8110 8111 case ENOMEM: 8112 warn(emsg_nomem); 8113 return (-1); 8114 8115 default: 8116 bad_error("load_init", r); 8117 } 8118 8119 return (0); 8120 } 8121 8122 static void 8123 free_imp_globals() 8124 { 8125 pgroup_t *old_dpt; 8126 void *cookie; 8127 8128 load_fini(); 8129 8130 free(ud_ctarg); 8131 free(ud_oldtarg); 8132 free(ud_name); 8133 ud_ctarg = ud_oldtarg = ud_name = NULL; 8134 8135 scf_transaction_destroy(ud_tx); 8136 ud_tx = NULL; 8137 scf_iter_destroy(ud_iter); 8138 scf_iter_destroy(ud_iter2); 8139 ud_iter = ud_iter2 = NULL; 8140 scf_value_destroy(ud_val); 8141 ud_val = NULL; 8142 scf_property_destroy(ud_prop); 8143 scf_property_destroy(ud_dpt_prop); 8144 ud_prop = ud_dpt_prop = NULL; 8145 scf_pg_destroy(ud_pg); 8146 scf_pg_destroy(ud_cur_depts_pg); 8147 scf_pg_destroy(ud_run_dpts_pg); 8148 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 8149 scf_snaplevel_destroy(ud_snpl); 8150 ud_snpl = NULL; 8151 scf_instance_destroy(ud_inst); 8152 ud_inst = NULL; 8153 8154 free(imp_str); 8155 free(imp_tsname); 8156 free(imp_fe1); 8157 free(imp_fe2); 8158 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 8159 8160 cookie = NULL; 8161 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 8162 NULL) { 8163 free((char *)old_dpt->sc_pgroup_name); 8164 free((char *)old_dpt->sc_pgroup_fmri); 8165 internal_pgroup_free(old_dpt); 8166 } 8167 uu_list_destroy(imp_deleted_dpts); 8168 8169 scf_transaction_destroy(imp_tx); 8170 imp_tx = NULL; 8171 scf_iter_destroy(imp_iter); 8172 scf_iter_destroy(imp_rpg_iter); 8173 scf_iter_destroy(imp_up_iter); 8174 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 8175 scf_property_destroy(imp_prop); 8176 imp_prop = NULL; 8177 scf_pg_destroy(imp_pg); 8178 scf_pg_destroy(imp_pg2); 8179 imp_pg = imp_pg2 = NULL; 8180 scf_snaplevel_destroy(imp_snpl); 8181 scf_snaplevel_destroy(imp_rsnpl); 8182 imp_snpl = imp_rsnpl = NULL; 8183 scf_snapshot_destroy(imp_snap); 8184 scf_snapshot_destroy(imp_lisnap); 8185 scf_snapshot_destroy(imp_tlisnap); 8186 scf_snapshot_destroy(imp_rsnap); 8187 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 8188 scf_instance_destroy(imp_inst); 8189 scf_instance_destroy(imp_tinst); 8190 imp_inst = imp_tinst = NULL; 8191 scf_service_destroy(imp_svc); 8192 scf_service_destroy(imp_tsvc); 8193 imp_svc = imp_tsvc = NULL; 8194 scf_scope_destroy(imp_scope); 8195 imp_scope = NULL; 8196 8197 load_fini(); 8198 } 8199 8200 int 8201 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 8202 { 8203 scf_callback_t cbdata; 8204 int result = 0; 8205 entity_t *svc, *inst; 8206 uu_list_t *insts; 8207 int r; 8208 pgroup_t *old_dpt; 8209 int annotation_set = 0; 8210 8211 const char * const emsg_nomem = gettext("Out of memory.\n"); 8212 const char * const emsg_nores = 8213 gettext("svc.configd is out of resources.\n"); 8214 8215 lscf_prep_hndl(); 8216 8217 if (alloc_imp_globals()) 8218 goto out; 8219 8220 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 8221 switch (scf_error()) { 8222 case SCF_ERROR_CONNECTION_BROKEN: 8223 warn(gettext("Repository connection broken.\n")); 8224 repository_teardown(); 8225 result = -1; 8226 goto out; 8227 8228 case SCF_ERROR_NOT_FOUND: 8229 case SCF_ERROR_INVALID_ARGUMENT: 8230 case SCF_ERROR_NOT_BOUND: 8231 case SCF_ERROR_HANDLE_MISMATCH: 8232 default: 8233 bad_error("scf_handle_get_scope", scf_error()); 8234 } 8235 } 8236 8237 /* Set up the auditing annotation. */ 8238 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 8239 annotation_set = 1; 8240 } else { 8241 switch (scf_error()) { 8242 case SCF_ERROR_CONNECTION_BROKEN: 8243 warn(gettext("Repository connection broken.\n")); 8244 repository_teardown(); 8245 result = -1; 8246 goto out; 8247 8248 case SCF_ERROR_INVALID_ARGUMENT: 8249 case SCF_ERROR_NOT_BOUND: 8250 case SCF_ERROR_NO_RESOURCES: 8251 case SCF_ERROR_INTERNAL: 8252 bad_error("_scf_set_annotation", scf_error()); 8253 /* NOTREACHED */ 8254 8255 default: 8256 /* 8257 * Do not terminate import because of inability to 8258 * generate annotation audit event. 8259 */ 8260 warn(gettext("_scf_set_annotation() unexpectedly " 8261 "failed with return code of %d\n"), scf_error()); 8262 break; 8263 } 8264 } 8265 8266 /* 8267 * Clear the sc_import_state's of all services & instances so we can 8268 * report how far we got if we fail. 8269 */ 8270 for (svc = uu_list_first(bndl->sc_bundle_services); 8271 svc != NULL; 8272 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8273 svc->sc_import_state = 0; 8274 8275 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 8276 clear_int, (void *)offsetof(entity_t, sc_import_state), 8277 UU_DEFAULT) != 0) 8278 bad_error("uu_list_walk", uu_error()); 8279 } 8280 8281 cbdata.sc_handle = g_hndl; 8282 cbdata.sc_parent = imp_scope; 8283 cbdata.sc_flags = flags; 8284 cbdata.sc_general = NULL; 8285 8286 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 8287 &cbdata, UU_DEFAULT) == 0) { 8288 char *eptr; 8289 /* Success. Refresh everything. */ 8290 8291 if (flags & SCI_NOREFRESH || no_refresh) { 8292 no_refresh = 0; 8293 result = 0; 8294 goto out; 8295 } 8296 8297 for (svc = uu_list_first(bndl->sc_bundle_services); 8298 svc != NULL; 8299 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8300 pgroup_t *dpt; 8301 8302 insts = svc->sc_u.sc_service.sc_service_instances; 8303 8304 for (inst = uu_list_first(insts); 8305 inst != NULL; 8306 inst = uu_list_next(insts, inst)) { 8307 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 8308 switch (r) { 8309 case 0: 8310 break; 8311 8312 case ENOMEM: 8313 case ECONNABORTED: 8314 case EPERM: 8315 case -1: 8316 goto progress; 8317 8318 default: 8319 bad_error("imp_refresh_fmri", r); 8320 } 8321 8322 inst->sc_import_state = IMPORT_REFRESHED; 8323 8324 for (dpt = uu_list_first(inst->sc_dependents); 8325 dpt != NULL; 8326 dpt = uu_list_next(inst->sc_dependents, 8327 dpt)) 8328 if (imp_refresh_fmri( 8329 dpt->sc_pgroup_fmri, 8330 dpt->sc_pgroup_name, 8331 inst->sc_fmri) != 0) 8332 goto progress; 8333 } 8334 8335 for (dpt = uu_list_first(svc->sc_dependents); 8336 dpt != NULL; 8337 dpt = uu_list_next(svc->sc_dependents, dpt)) 8338 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 8339 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 8340 goto progress; 8341 } 8342 8343 for (old_dpt = uu_list_first(imp_deleted_dpts); 8344 old_dpt != NULL; 8345 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 8346 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8347 old_dpt->sc_pgroup_name, 8348 old_dpt->sc_parent->sc_fmri) != 0) 8349 goto progress; 8350 8351 result = 0; 8352 8353 /* 8354 * This snippet of code assumes that we are running svccfg as we 8355 * normally do -- witih svc.startd running. Of course, that is 8356 * not actually the case all the time because we also use a 8357 * varient of svc.configd and svccfg which are only meant to 8358 * run during the build process. During this time we have no 8359 * svc.startd, so this check would hang the build process. 8360 * 8361 * However, we've also given other consolidations, a bit of a 8362 * means to tie themselves into a knot. They're not properly 8363 * using the native build equivalents, but they've been getting 8364 * away with it anyways. Therefore, if we've found that 8365 * SVCCFG_REPOSITORY is set indicating that a separate configd 8366 * should be spun up, then we have to assume it's not using a 8367 * startd and we should not do this check. 8368 */ 8369 #ifndef NATIVE_BUILD 8370 /* 8371 * Verify that the restarter group is preset 8372 */ 8373 eptr = getenv("SVCCFG_REPOSITORY"); 8374 for (svc = uu_list_first(bndl->sc_bundle_services); 8375 svc != NULL && eptr == NULL; 8376 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8377 8378 insts = svc->sc_u.sc_service.sc_service_instances; 8379 8380 for (inst = uu_list_first(insts); 8381 inst != NULL; 8382 inst = uu_list_next(insts, inst)) { 8383 if (lscf_instance_verify(imp_scope, svc, 8384 inst) != 0) 8385 goto progress; 8386 } 8387 } 8388 #endif 8389 goto out; 8390 8391 } 8392 8393 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8394 bad_error("uu_list_walk", uu_error()); 8395 8396 /* If the error hasn't been printed yet, do so here. */ 8397 switch (cbdata.sc_err) { 8398 case ECONNABORTED: 8399 warn(gettext("Repository connection broken.\n")); 8400 break; 8401 8402 case ENOMEM: 8403 warn(emsg_nomem); 8404 break; 8405 8406 case ENOSPC: 8407 warn(emsg_nores); 8408 break; 8409 8410 case EROFS: 8411 warn(gettext("Repository is read-only.\n")); 8412 break; 8413 8414 case EACCES: 8415 warn(gettext("Repository backend denied access.\n")); 8416 break; 8417 8418 case EPERM: 8419 case EINVAL: 8420 case EEXIST: 8421 case EBUSY: 8422 case EBADF: 8423 case -1: 8424 break; 8425 8426 default: 8427 bad_error("lscf_service_import", cbdata.sc_err); 8428 } 8429 8430 progress: 8431 warn(gettext("Import of %s failed. Progress:\n"), filename); 8432 8433 for (svc = uu_list_first(bndl->sc_bundle_services); 8434 svc != NULL; 8435 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8436 insts = svc->sc_u.sc_service.sc_service_instances; 8437 8438 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 8439 import_progress(svc->sc_import_state)); 8440 8441 for (inst = uu_list_first(insts); 8442 inst != NULL; 8443 inst = uu_list_next(insts, inst)) 8444 warn(gettext(" Instance \"%s\": %s\n"), 8445 inst->sc_name, 8446 import_progress(inst->sc_import_state)); 8447 } 8448 8449 if (cbdata.sc_err == ECONNABORTED) 8450 repository_teardown(); 8451 8452 8453 result = -1; 8454 8455 out: 8456 if (annotation_set != 0) { 8457 /* Turn off annotation. It is no longer needed. */ 8458 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8459 } 8460 8461 free_imp_globals(); 8462 8463 return (result); 8464 } 8465 8466 /* 8467 * _lscf_import_err() summarize the error handling returned by 8468 * lscf_import_{instance | service}_pgs 8469 * Return values are: 8470 * IMPORT_NEXT 8471 * IMPORT_OUT 8472 * IMPORT_BAD 8473 */ 8474 8475 #define IMPORT_BAD -1 8476 #define IMPORT_NEXT 0 8477 #define IMPORT_OUT 1 8478 8479 static int 8480 _lscf_import_err(int err, const char *fmri) 8481 { 8482 switch (err) { 8483 case 0: 8484 if (g_verbose) 8485 warn(gettext("%s updated.\n"), fmri); 8486 return (IMPORT_NEXT); 8487 8488 case ECONNABORTED: 8489 warn(gettext("Could not update %s " 8490 "(repository connection broken).\n"), fmri); 8491 return (IMPORT_OUT); 8492 8493 case ENOMEM: 8494 warn(gettext("Could not update %s (out of memory).\n"), fmri); 8495 return (IMPORT_OUT); 8496 8497 case ENOSPC: 8498 warn(gettext("Could not update %s " 8499 "(repository server out of resources).\n"), fmri); 8500 return (IMPORT_OUT); 8501 8502 case ECANCELED: 8503 warn(gettext( 8504 "Could not update %s (deleted).\n"), fmri); 8505 return (IMPORT_NEXT); 8506 8507 case EPERM: 8508 case EINVAL: 8509 case EBUSY: 8510 return (IMPORT_NEXT); 8511 8512 case EROFS: 8513 warn(gettext("Could not update %s (repository read-only).\n"), 8514 fmri); 8515 return (IMPORT_OUT); 8516 8517 case EACCES: 8518 warn(gettext("Could not update %s " 8519 "(backend access denied).\n"), fmri); 8520 return (IMPORT_NEXT); 8521 8522 case EEXIST: 8523 default: 8524 return (IMPORT_BAD); 8525 } 8526 8527 /*NOTREACHED*/ 8528 } 8529 8530 /* 8531 * The global imp_svc and imp_inst should be set by the caller in the 8532 * check to make sure the service and instance exist that the apply is 8533 * working on. 8534 */ 8535 static int 8536 lscf_dependent_apply(void *dpg, void *e) 8537 { 8538 scf_callback_t cb; 8539 pgroup_t *dpt_pgroup = dpg; 8540 pgroup_t *deldpt; 8541 entity_t *ent = e; 8542 int tissvc; 8543 void *sc_ent, *tent; 8544 scf_error_t serr; 8545 int r; 8546 8547 const char * const dependents = "dependents"; 8548 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT); 8549 8550 if (issvc) 8551 sc_ent = imp_svc; 8552 else 8553 sc_ent = imp_inst; 8554 8555 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg, 8556 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 || 8557 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name, 8558 imp_prop) != 0) { 8559 switch (scf_error()) { 8560 case SCF_ERROR_NOT_FOUND: 8561 case SCF_ERROR_DELETED: 8562 break; 8563 8564 case SCF_ERROR_CONNECTION_BROKEN: 8565 case SCF_ERROR_NOT_SET: 8566 case SCF_ERROR_INVALID_ARGUMENT: 8567 case SCF_ERROR_HANDLE_MISMATCH: 8568 case SCF_ERROR_NOT_BOUND: 8569 default: 8570 bad_error("entity_get_pg", scf_error()); 8571 } 8572 } else { 8573 /* 8574 * Found the dependents/<wip dep> so check to 8575 * see if the service is different. If so 8576 * store the service for later refresh, and 8577 * delete the wip dependency from the service 8578 */ 8579 if (scf_property_get_value(imp_prop, ud_val) != 0) { 8580 switch (scf_error()) { 8581 case SCF_ERROR_DELETED: 8582 break; 8583 8584 case SCF_ERROR_CONNECTION_BROKEN: 8585 case SCF_ERROR_NOT_SET: 8586 case SCF_ERROR_INVALID_ARGUMENT: 8587 case SCF_ERROR_HANDLE_MISMATCH: 8588 case SCF_ERROR_NOT_BOUND: 8589 default: 8590 bad_error("scf_property_get_value", 8591 scf_error()); 8592 } 8593 } 8594 8595 if (scf_value_get_as_string(ud_val, ud_oldtarg, 8596 max_scf_value_len + 1) < 0) 8597 bad_error("scf_value_get_as_string", scf_error()); 8598 8599 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 8600 switch (r) { 8601 case 1: 8602 break; 8603 case 0: 8604 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent, 8605 &tissvc)) != SCF_ERROR_NONE) { 8606 if (serr == SCF_ERROR_NOT_FOUND) { 8607 break; 8608 } else { 8609 bad_error("fmri_to_entity", serr); 8610 } 8611 } 8612 8613 if (entity_get_pg(tent, tissvc, 8614 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) { 8615 serr = scf_error(); 8616 if (serr == SCF_ERROR_NOT_FOUND || 8617 serr == SCF_ERROR_DELETED) { 8618 break; 8619 } else { 8620 bad_error("entity_get_pg", scf_error()); 8621 } 8622 } 8623 8624 if (scf_pg_delete(imp_pg) != 0) { 8625 serr = scf_error(); 8626 if (serr == SCF_ERROR_NOT_FOUND || 8627 serr == SCF_ERROR_DELETED) { 8628 break; 8629 } else { 8630 bad_error("scf_pg_delete", scf_error()); 8631 } 8632 } 8633 8634 deldpt = internal_pgroup_new(); 8635 if (deldpt == NULL) 8636 return (ENOMEM); 8637 deldpt->sc_pgroup_name = 8638 strdup(dpt_pgroup->sc_pgroup_name); 8639 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg); 8640 if (deldpt->sc_pgroup_name == NULL || 8641 deldpt->sc_pgroup_fmri == NULL) 8642 return (ENOMEM); 8643 deldpt->sc_parent = (entity_t *)ent; 8644 if (uu_list_insert_after(imp_deleted_dpts, NULL, 8645 deldpt) != 0) 8646 uu_die(gettext("libuutil error: %s\n"), 8647 uu_strerror(uu_error())); 8648 8649 break; 8650 default: 8651 bad_error("fmri_equal", r); 8652 } 8653 } 8654 8655 cb.sc_handle = g_hndl; 8656 cb.sc_parent = ent; 8657 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT; 8658 cb.sc_source_fmri = ent->sc_fmri; 8659 cb.sc_target_fmri = ent->sc_fmri; 8660 cb.sc_trans = NULL; 8661 cb.sc_flags = SCI_FORCE; 8662 8663 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT) 8664 return (UU_WALK_ERROR); 8665 8666 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL); 8667 switch (r) { 8668 case 0: 8669 break; 8670 8671 case ENOMEM: 8672 case ECONNABORTED: 8673 case EPERM: 8674 case -1: 8675 warn(gettext("Unable to refresh \"%s\"\n"), 8676 dpt_pgroup->sc_pgroup_fmri); 8677 return (UU_WALK_ERROR); 8678 8679 default: 8680 bad_error("imp_refresh_fmri", r); 8681 } 8682 8683 return (UU_WALK_NEXT); 8684 } 8685 8686 /* 8687 * Returns 8688 * 0 - success 8689 * -1 - lscf_import_instance_pgs() failed. 8690 */ 8691 int 8692 lscf_bundle_apply(bundle_t *bndl, const char *file) 8693 { 8694 pgroup_t *old_dpt; 8695 entity_t *svc, *inst; 8696 int annotation_set = 0; 8697 int ret = 0; 8698 int r = 0; 8699 8700 lscf_prep_hndl(); 8701 8702 if ((ret = alloc_imp_globals())) 8703 goto out; 8704 8705 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) 8706 scfdie(); 8707 8708 /* 8709 * Set the strings to be used for the security audit annotation 8710 * event. 8711 */ 8712 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 8713 annotation_set = 1; 8714 } else { 8715 switch (scf_error()) { 8716 case SCF_ERROR_CONNECTION_BROKEN: 8717 warn(gettext("Repository connection broken.\n")); 8718 goto out; 8719 8720 case SCF_ERROR_INVALID_ARGUMENT: 8721 case SCF_ERROR_NOT_BOUND: 8722 case SCF_ERROR_NO_RESOURCES: 8723 case SCF_ERROR_INTERNAL: 8724 bad_error("_scf_set_annotation", scf_error()); 8725 /* NOTREACHED */ 8726 8727 default: 8728 /* 8729 * Do not abort apply operation because of 8730 * inability to create annotation audit event. 8731 */ 8732 warn(gettext("_scf_set_annotation() unexpectedly " 8733 "failed with return code of %d\n"), scf_error()); 8734 break; 8735 } 8736 } 8737 8738 for (svc = uu_list_first(bndl->sc_bundle_services); 8739 svc != NULL; 8740 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8741 int refresh = 0; 8742 8743 if (scf_scope_get_service(imp_scope, svc->sc_name, 8744 imp_svc) != 0) { 8745 switch (scf_error()) { 8746 case SCF_ERROR_NOT_FOUND: 8747 if (g_verbose) 8748 warn(gettext("Ignoring nonexistent " 8749 "service %s.\n"), svc->sc_name); 8750 continue; 8751 8752 default: 8753 scfdie(); 8754 } 8755 } 8756 8757 /* 8758 * If there were missing types in the profile, then need to 8759 * attempt to find the types. 8760 */ 8761 if (svc->sc_miss_type) { 8762 if (uu_list_numnodes(svc->sc_pgroups) && 8763 uu_list_walk(svc->sc_pgroups, find_current_pg_type, 8764 svc, UU_DEFAULT) != 0) { 8765 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8766 bad_error("uu_list_walk", uu_error()); 8767 8768 ret = -1; 8769 continue; 8770 } 8771 8772 for (inst = uu_list_first( 8773 svc->sc_u.sc_service.sc_service_instances); 8774 inst != NULL; 8775 inst = uu_list_next( 8776 svc->sc_u.sc_service.sc_service_instances, inst)) { 8777 /* 8778 * If the instance doesn't exist just 8779 * skip to the next instance and let the 8780 * import note the missing instance. 8781 */ 8782 if (scf_service_get_instance(imp_svc, 8783 inst->sc_name, imp_inst) != 0) 8784 continue; 8785 8786 if (uu_list_walk(inst->sc_pgroups, 8787 find_current_pg_type, inst, 8788 UU_DEFAULT) != 0) { 8789 if (uu_error() != 8790 UU_ERROR_CALLBACK_FAILED) 8791 bad_error("uu_list_walk", 8792 uu_error()); 8793 8794 ret = -1; 8795 inst->sc_miss_type = B_TRUE; 8796 } 8797 } 8798 } 8799 8800 /* 8801 * if we have pgs in the profile, we need to refresh ALL 8802 * instances of the service 8803 */ 8804 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 8805 refresh = 1; 8806 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc, 8807 SCI_FORCE | SCI_KEEP); 8808 switch (_lscf_import_err(r, svc->sc_fmri)) { 8809 case IMPORT_NEXT: 8810 break; 8811 8812 case IMPORT_OUT: 8813 goto out; 8814 8815 case IMPORT_BAD: 8816 default: 8817 bad_error("lscf_import_service_pgs", r); 8818 } 8819 } 8820 8821 if (uu_list_numnodes(svc->sc_dependents) != 0) { 8822 uu_list_walk(svc->sc_dependents, 8823 lscf_dependent_apply, svc, UU_DEFAULT); 8824 } 8825 8826 for (inst = uu_list_first( 8827 svc->sc_u.sc_service.sc_service_instances); 8828 inst != NULL; 8829 inst = uu_list_next( 8830 svc->sc_u.sc_service.sc_service_instances, inst)) { 8831 /* 8832 * This instance still has missing types 8833 * so skip it. 8834 */ 8835 if (inst->sc_miss_type) { 8836 if (g_verbose) 8837 warn(gettext("Ignoring instance " 8838 "%s:%s with missing types\n"), 8839 inst->sc_parent->sc_name, 8840 inst->sc_name); 8841 8842 continue; 8843 } 8844 8845 if (scf_service_get_instance(imp_svc, inst->sc_name, 8846 imp_inst) != 0) { 8847 switch (scf_error()) { 8848 case SCF_ERROR_NOT_FOUND: 8849 if (g_verbose) 8850 warn(gettext("Ignoring " 8851 "nonexistant instance " 8852 "%s:%s.\n"), 8853 inst->sc_parent->sc_name, 8854 inst->sc_name); 8855 continue; 8856 8857 default: 8858 scfdie(); 8859 } 8860 } 8861 8862 /* 8863 * If the instance does not have a general/enabled 8864 * property and no last-import snapshot then the 8865 * instance is not a fully installed instance and 8866 * should not have a profile applied to it. 8867 * 8868 * This could happen if a service/instance declares 8869 * a dependent on behalf of another service/instance. 8870 * 8871 */ 8872 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 8873 imp_snap) != 0) { 8874 if (scf_instance_get_pg(imp_inst, 8875 SCF_PG_GENERAL, imp_pg) != 0 || 8876 scf_pg_get_property(imp_pg, 8877 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 8878 if (g_verbose) 8879 warn(gettext("Ignoreing " 8880 "partial instance " 8881 "%s:%s.\n"), 8882 inst->sc_parent->sc_name, 8883 inst->sc_name); 8884 continue; 8885 } 8886 } 8887 8888 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, 8889 inst, SCI_FORCE | SCI_KEEP); 8890 switch (_lscf_import_err(r, inst->sc_fmri)) { 8891 case IMPORT_NEXT: 8892 break; 8893 8894 case IMPORT_OUT: 8895 goto out; 8896 8897 case IMPORT_BAD: 8898 default: 8899 bad_error("lscf_import_instance_pgs", r); 8900 } 8901 8902 if (uu_list_numnodes(inst->sc_dependents) != 0) { 8903 uu_list_walk(inst->sc_dependents, 8904 lscf_dependent_apply, inst, UU_DEFAULT); 8905 } 8906 8907 /* refresh only if there is no pgs in the service */ 8908 if (refresh == 0) 8909 (void) refresh_entity(0, imp_inst, 8910 inst->sc_fmri, NULL, NULL, NULL); 8911 } 8912 8913 if (refresh == 1) { 8914 char *name_buf = safe_malloc(max_scf_name_len + 1); 8915 8916 (void) refresh_entity(1, imp_svc, svc->sc_name, 8917 imp_inst, imp_iter, name_buf); 8918 free(name_buf); 8919 } 8920 8921 for (old_dpt = uu_list_first(imp_deleted_dpts); 8922 old_dpt != NULL; 8923 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) { 8924 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8925 old_dpt->sc_pgroup_name, 8926 old_dpt->sc_parent->sc_fmri) != 0) { 8927 warn(gettext("Unable to refresh \"%s\"\n"), 8928 old_dpt->sc_pgroup_fmri); 8929 } 8930 } 8931 } 8932 8933 out: 8934 if (annotation_set) { 8935 /* Remove security audit annotation strings. */ 8936 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8937 } 8938 8939 free_imp_globals(); 8940 return (ret); 8941 } 8942 8943 8944 /* 8945 * Export. These functions create and output an XML tree of a service 8946 * description from the repository. This is largely the inverse of 8947 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 8948 * 8949 * - We must include any properties which are not represented specifically by 8950 * a service manifest, e.g., properties created by an admin post-import. To 8951 * do so we'll iterate through all properties and deal with each 8952 * apropriately. 8953 * 8954 * - Children of services and instances must must be in the order set by the 8955 * DTD, but we iterate over the properties in undefined order. The elements 8956 * are not easily (or efficiently) sortable by name. Since there's a fixed 8957 * number of classes of them, however, we'll keep the classes separate and 8958 * assemble them in order. 8959 */ 8960 8961 /* 8962 * Convenience function to handle xmlSetProp errors (and type casting). 8963 */ 8964 static void 8965 safe_setprop(xmlNodePtr n, const char *name, const char *val) 8966 { 8967 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 8968 uu_die(gettext("Could not set XML property.\n")); 8969 } 8970 8971 /* 8972 * Convenience function to set an XML attribute to the single value of an 8973 * astring property. If the value happens to be the default, don't set the 8974 * attribute. "dval" should be the default value supplied by the DTD, or 8975 * NULL for no default. 8976 */ 8977 static int 8978 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 8979 const char *name, const char *dval) 8980 { 8981 scf_value_t *val; 8982 ssize_t len; 8983 char *str; 8984 8985 val = scf_value_create(g_hndl); 8986 if (val == NULL) 8987 scfdie(); 8988 8989 if (prop_get_val(prop, val) != 0) { 8990 scf_value_destroy(val); 8991 return (-1); 8992 } 8993 8994 len = scf_value_get_as_string(val, NULL, 0); 8995 if (len < 0) 8996 scfdie(); 8997 8998 str = safe_malloc(len + 1); 8999 9000 if (scf_value_get_as_string(val, str, len + 1) < 0) 9001 scfdie(); 9002 9003 scf_value_destroy(val); 9004 9005 if (dval == NULL || strcmp(str, dval) != 0) 9006 safe_setprop(n, name, str); 9007 9008 free(str); 9009 9010 return (0); 9011 } 9012 9013 /* 9014 * As above, but the attribute is always set. 9015 */ 9016 static int 9017 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 9018 { 9019 return (set_attr_from_prop_default(prop, n, name, NULL)); 9020 } 9021 9022 /* 9023 * Dump the given document onto f, with "'s replaced by ''s. 9024 */ 9025 static int 9026 write_service_bundle(xmlDocPtr doc, FILE *f) 9027 { 9028 xmlChar *mem; 9029 int sz, i; 9030 9031 mem = NULL; 9032 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 9033 9034 if (mem == NULL) { 9035 semerr(gettext("Could not dump XML tree.\n")); 9036 return (-1); 9037 } 9038 9039 /* 9040 * Fortunately libxml produces " instead of ", so we can blindly 9041 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 9042 * ' code?! 9043 */ 9044 for (i = 0; i < sz; ++i) { 9045 char c = (char)mem[i]; 9046 9047 if (c == '"') 9048 (void) fputc('\'', f); 9049 else if (c == '\'') 9050 (void) fwrite("'", sizeof ("'") - 1, 1, f); 9051 else 9052 (void) fputc(c, f); 9053 } 9054 9055 return (0); 9056 } 9057 9058 /* 9059 * Create the DOM elements in elts necessary to (generically) represent prop 9060 * (i.e., a property or propval element). If the name of the property is 9061 * known, it should be passed as name_arg. Otherwise, pass NULL. 9062 */ 9063 static void 9064 export_property(scf_property_t *prop, const char *name_arg, 9065 struct pg_elts *elts, int flags) 9066 { 9067 const char *type; 9068 scf_error_t err = 0; 9069 xmlNodePtr pnode, lnode; 9070 char *lnname; 9071 int ret; 9072 9073 /* name */ 9074 if (name_arg != NULL) { 9075 (void) strcpy(exp_str, name_arg); 9076 } else { 9077 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 9078 scfdie(); 9079 } 9080 9081 /* type */ 9082 type = prop_to_typestr(prop); 9083 if (type == NULL) 9084 uu_die(gettext("Can't export property %s: unknown type.\n"), 9085 exp_str); 9086 9087 /* If we're exporting values, and there's just one, export it here. */ 9088 if (!(flags & SCE_ALL_VALUES)) 9089 goto empty; 9090 9091 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 9092 xmlNodePtr n; 9093 9094 /* Single value, so use propval */ 9095 n = xmlNewNode(NULL, (xmlChar *)"propval"); 9096 if (n == NULL) 9097 uu_die(emsg_create_xml); 9098 9099 safe_setprop(n, name_attr, exp_str); 9100 safe_setprop(n, type_attr, type); 9101 9102 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9103 scfdie(); 9104 safe_setprop(n, value_attr, exp_str); 9105 9106 if (elts->propvals == NULL) 9107 elts->propvals = n; 9108 else 9109 (void) xmlAddSibling(elts->propvals, n); 9110 9111 return; 9112 } 9113 9114 err = scf_error(); 9115 9116 if (err == SCF_ERROR_PERMISSION_DENIED) { 9117 semerr(emsg_permission_denied); 9118 return; 9119 } 9120 9121 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 9122 err != SCF_ERROR_NOT_FOUND && 9123 err != SCF_ERROR_PERMISSION_DENIED) 9124 scfdie(); 9125 9126 empty: 9127 /* Multiple (or no) values, so use property */ 9128 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 9129 if (pnode == NULL) 9130 uu_die(emsg_create_xml); 9131 9132 safe_setprop(pnode, name_attr, exp_str); 9133 safe_setprop(pnode, type_attr, type); 9134 9135 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 9136 lnname = uu_msprintf("%s_list", type); 9137 if (lnname == NULL) 9138 uu_die(gettext("Could not create string")); 9139 9140 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 9141 if (lnode == NULL) 9142 uu_die(emsg_create_xml); 9143 9144 uu_free(lnname); 9145 9146 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 9147 scfdie(); 9148 9149 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 9150 1) { 9151 xmlNodePtr vn; 9152 9153 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 9154 NULL); 9155 if (vn == NULL) 9156 uu_die(emsg_create_xml); 9157 9158 if (scf_value_get_as_string(exp_val, exp_str, 9159 exp_str_sz) < 0) 9160 scfdie(); 9161 safe_setprop(vn, value_attr, exp_str); 9162 } 9163 if (ret != 0) 9164 scfdie(); 9165 } 9166 9167 if (elts->properties == NULL) 9168 elts->properties = pnode; 9169 else 9170 (void) xmlAddSibling(elts->properties, pnode); 9171 } 9172 9173 /* 9174 * Add a property_group element for this property group to elts. 9175 */ 9176 static void 9177 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 9178 { 9179 xmlNodePtr n; 9180 struct pg_elts elts; 9181 int ret; 9182 boolean_t read_protected; 9183 9184 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 9185 9186 /* name */ 9187 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9188 scfdie(); 9189 safe_setprop(n, name_attr, exp_str); 9190 9191 /* type */ 9192 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 9193 scfdie(); 9194 safe_setprop(n, type_attr, exp_str); 9195 9196 /* properties */ 9197 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9198 scfdie(); 9199 9200 (void) memset(&elts, 0, sizeof (elts)); 9201 9202 /* 9203 * If this property group is not read protected, we always want to 9204 * output all the values. Otherwise, we only output the values if the 9205 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 9206 */ 9207 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 9208 scfdie(); 9209 9210 if (!read_protected) 9211 flags |= SCE_ALL_VALUES; 9212 9213 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9214 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9215 scfdie(); 9216 9217 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9218 xmlNodePtr m; 9219 9220 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9221 if (m == NULL) 9222 uu_die(emsg_create_xml); 9223 9224 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9225 elts.stability = m; 9226 continue; 9227 } 9228 9229 xmlFreeNode(m); 9230 } 9231 9232 export_property(exp_prop, NULL, &elts, flags); 9233 } 9234 if (ret == -1) 9235 scfdie(); 9236 9237 (void) xmlAddChild(n, elts.stability); 9238 (void) xmlAddChildList(n, elts.propvals); 9239 (void) xmlAddChildList(n, elts.properties); 9240 9241 if (eelts->property_groups == NULL) 9242 eelts->property_groups = n; 9243 else 9244 (void) xmlAddSibling(eelts->property_groups, n); 9245 } 9246 9247 /* 9248 * Create an XML node representing the dependency described by the given 9249 * property group and put it in eelts. Unless the dependency is not valid, in 9250 * which case create a generic property_group element which represents it and 9251 * put it in eelts. 9252 */ 9253 static void 9254 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 9255 { 9256 xmlNodePtr n; 9257 int err = 0, ret; 9258 struct pg_elts elts; 9259 9260 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 9261 if (n == NULL) 9262 uu_die(emsg_create_xml); 9263 9264 /* 9265 * If the external flag is present, skip this dependency because it 9266 * should have been created by another manifest. 9267 */ 9268 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 9269 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9270 prop_get_val(exp_prop, exp_val) == 0) { 9271 uint8_t b; 9272 9273 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 9274 scfdie(); 9275 9276 if (b) 9277 return; 9278 } 9279 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 9280 scfdie(); 9281 9282 /* Get the required attributes. */ 9283 9284 /* name */ 9285 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9286 scfdie(); 9287 safe_setprop(n, name_attr, exp_str); 9288 9289 /* grouping */ 9290 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9291 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9292 err = 1; 9293 9294 /* restart_on */ 9295 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9296 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9297 err = 1; 9298 9299 /* type */ 9300 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9301 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9302 err = 1; 9303 9304 /* 9305 * entities: Not required, but if we create no children, it will be 9306 * created as empty on import, so fail if it's missing. 9307 */ 9308 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9309 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 9310 scf_iter_t *eiter; 9311 int ret2; 9312 9313 eiter = scf_iter_create(g_hndl); 9314 if (eiter == NULL) 9315 scfdie(); 9316 9317 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 9318 scfdie(); 9319 9320 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 9321 xmlNodePtr ch; 9322 9323 if (scf_value_get_astring(exp_val, exp_str, 9324 exp_str_sz) < 0) 9325 scfdie(); 9326 9327 /* 9328 * service_fmri's must be first, so we can add them 9329 * here. 9330 */ 9331 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 9332 NULL); 9333 if (ch == NULL) 9334 uu_die(emsg_create_xml); 9335 9336 safe_setprop(ch, value_attr, exp_str); 9337 } 9338 if (ret2 == -1) 9339 scfdie(); 9340 9341 scf_iter_destroy(eiter); 9342 } else 9343 err = 1; 9344 9345 if (err) { 9346 xmlFreeNode(n); 9347 9348 export_pg(pg, eelts, SCE_ALL_VALUES); 9349 9350 return; 9351 } 9352 9353 /* Iterate through the properties & handle each. */ 9354 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9355 scfdie(); 9356 9357 (void) memset(&elts, 0, sizeof (elts)); 9358 9359 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9360 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9361 scfdie(); 9362 9363 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9364 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9365 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9366 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9367 continue; 9368 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9369 xmlNodePtr m; 9370 9371 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9372 if (m == NULL) 9373 uu_die(emsg_create_xml); 9374 9375 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9376 elts.stability = m; 9377 continue; 9378 } 9379 9380 xmlFreeNode(m); 9381 } 9382 9383 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9384 } 9385 if (ret == -1) 9386 scfdie(); 9387 9388 (void) xmlAddChild(n, elts.stability); 9389 (void) xmlAddChildList(n, elts.propvals); 9390 (void) xmlAddChildList(n, elts.properties); 9391 9392 if (eelts->dependencies == NULL) 9393 eelts->dependencies = n; 9394 else 9395 (void) xmlAddSibling(eelts->dependencies, n); 9396 } 9397 9398 static xmlNodePtr 9399 export_method_environment(scf_propertygroup_t *pg) 9400 { 9401 xmlNodePtr env; 9402 int ret; 9403 int children = 0; 9404 9405 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 9406 return (NULL); 9407 9408 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 9409 if (env == NULL) 9410 uu_die(emsg_create_xml); 9411 9412 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 9413 scfdie(); 9414 9415 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 9416 scfdie(); 9417 9418 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 9419 xmlNodePtr ev; 9420 char *cp; 9421 9422 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9423 scfdie(); 9424 9425 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 9426 warn(gettext("Invalid environment variable \"%s\".\n"), 9427 exp_str); 9428 continue; 9429 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 9430 warn(gettext("Invalid environment variable \"%s\"; " 9431 "\"SMF_\" prefix is reserved.\n"), exp_str); 9432 continue; 9433 } 9434 9435 *cp = '\0'; 9436 cp++; 9437 9438 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 9439 if (ev == NULL) 9440 uu_die(emsg_create_xml); 9441 9442 safe_setprop(ev, name_attr, exp_str); 9443 safe_setprop(ev, value_attr, cp); 9444 children++; 9445 } 9446 9447 if (ret != 0) 9448 scfdie(); 9449 9450 if (children == 0) { 9451 xmlFreeNode(env); 9452 return (NULL); 9453 } 9454 9455 return (env); 9456 } 9457 9458 /* 9459 * As above, but for a method property group. 9460 */ 9461 static void 9462 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 9463 { 9464 xmlNodePtr n, env; 9465 char *str; 9466 int err = 0, nonenv, ret; 9467 uint8_t use_profile; 9468 struct pg_elts elts; 9469 xmlNodePtr ctxt = NULL; 9470 9471 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 9472 9473 /* Get the required attributes. */ 9474 9475 /* name */ 9476 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9477 scfdie(); 9478 safe_setprop(n, name_attr, exp_str); 9479 9480 /* type */ 9481 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9482 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9483 err = 1; 9484 9485 /* exec */ 9486 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 9487 set_attr_from_prop(exp_prop, n, "exec") != 0) 9488 err = 1; 9489 9490 /* timeout */ 9491 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 9492 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 9493 prop_get_val(exp_prop, exp_val) == 0) { 9494 uint64_t c; 9495 9496 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 9497 scfdie(); 9498 9499 str = uu_msprintf("%llu", c); 9500 if (str == NULL) 9501 uu_die(gettext("Could not create string")); 9502 9503 safe_setprop(n, "timeout_seconds", str); 9504 free(str); 9505 } else 9506 err = 1; 9507 9508 if (err) { 9509 xmlFreeNode(n); 9510 9511 export_pg(pg, eelts, SCE_ALL_VALUES); 9512 9513 return; 9514 } 9515 9516 9517 /* 9518 * If we're going to have a method_context child, we need to know 9519 * before we iterate through the properties. Since method_context's 9520 * are optional, we don't want to complain about any properties 9521 * missing if none of them are there. Thus we can't use the 9522 * convenience functions. 9523 */ 9524 nonenv = 9525 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 9526 SCF_SUCCESS || 9527 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 9528 SCF_SUCCESS || 9529 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 9530 SCF_SUCCESS || 9531 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) == 9532 SCF_SUCCESS || 9533 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 9534 SCF_SUCCESS; 9535 9536 if (nonenv) { 9537 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9538 if (ctxt == NULL) 9539 uu_die(emsg_create_xml); 9540 9541 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 9542 0 && 9543 set_attr_from_prop_default(exp_prop, ctxt, 9544 "working_directory", ":default") != 0) 9545 err = 1; 9546 9547 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 9548 set_attr_from_prop_default(exp_prop, ctxt, "project", 9549 ":default") != 0) 9550 err = 1; 9551 9552 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 9553 0 && 9554 set_attr_from_prop_default(exp_prop, ctxt, 9555 "resource_pool", ":default") != 0) 9556 err = 1; 9557 9558 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 && 9559 set_attr_from_prop_default(exp_prop, ctxt, 9560 "security_flags", ":default") != 0) 9561 err = 1; 9562 9563 /* 9564 * We only want to complain about profile or credential 9565 * properties if we will use them. To determine that we must 9566 * examine USE_PROFILE. 9567 */ 9568 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9569 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9570 prop_get_val(exp_prop, exp_val) == 0) { 9571 if (scf_value_get_boolean(exp_val, &use_profile) != 9572 SCF_SUCCESS) { 9573 scfdie(); 9574 } 9575 9576 if (use_profile) { 9577 xmlNodePtr prof; 9578 9579 prof = xmlNewChild(ctxt, NULL, 9580 (xmlChar *)"method_profile", NULL); 9581 if (prof == NULL) 9582 uu_die(emsg_create_xml); 9583 9584 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 9585 exp_prop) != 0 || 9586 set_attr_from_prop(exp_prop, prof, 9587 name_attr) != 0) 9588 err = 1; 9589 } else { 9590 xmlNodePtr cred; 9591 9592 cred = xmlNewChild(ctxt, NULL, 9593 (xmlChar *)"method_credential", NULL); 9594 if (cred == NULL) 9595 uu_die(emsg_create_xml); 9596 9597 if (pg_get_prop(pg, SCF_PROPERTY_USER, 9598 exp_prop) != 0 || 9599 set_attr_from_prop(exp_prop, cred, 9600 "user") != 0) { 9601 err = 1; 9602 } 9603 9604 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 9605 exp_prop) == 0 && 9606 set_attr_from_prop_default(exp_prop, cred, 9607 "group", ":default") != 0) 9608 err = 1; 9609 9610 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 9611 exp_prop) == 0 && 9612 set_attr_from_prop_default(exp_prop, cred, 9613 "supp_groups", ":default") != 0) 9614 err = 1; 9615 9616 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 9617 exp_prop) == 0 && 9618 set_attr_from_prop_default(exp_prop, cred, 9619 "privileges", ":default") != 0) 9620 err = 1; 9621 9622 if (pg_get_prop(pg, 9623 SCF_PROPERTY_LIMIT_PRIVILEGES, 9624 exp_prop) == 0 && 9625 set_attr_from_prop_default(exp_prop, cred, 9626 "limit_privileges", ":default") != 0) 9627 err = 1; 9628 } 9629 } 9630 } 9631 9632 if ((env = export_method_environment(pg)) != NULL) { 9633 if (ctxt == NULL) { 9634 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9635 if (ctxt == NULL) 9636 uu_die(emsg_create_xml); 9637 } 9638 (void) xmlAddChild(ctxt, env); 9639 } 9640 9641 if (env != NULL || (nonenv && err == 0)) 9642 (void) xmlAddChild(n, ctxt); 9643 else 9644 xmlFreeNode(ctxt); 9645 9646 nonenv = (err == 0); 9647 9648 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9649 scfdie(); 9650 9651 (void) memset(&elts, 0, sizeof (elts)); 9652 9653 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9654 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9655 scfdie(); 9656 9657 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9658 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 9659 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 9660 continue; 9661 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9662 xmlNodePtr m; 9663 9664 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9665 if (m == NULL) 9666 uu_die(emsg_create_xml); 9667 9668 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9669 elts.stability = m; 9670 continue; 9671 } 9672 9673 xmlFreeNode(m); 9674 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 9675 0 || 9676 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 9677 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 9678 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9679 if (nonenv) 9680 continue; 9681 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 9682 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 9683 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 9684 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 9685 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 || 9686 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9687 if (nonenv && !use_profile) 9688 continue; 9689 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9690 if (nonenv && use_profile) 9691 continue; 9692 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 9693 if (env != NULL) 9694 continue; 9695 } 9696 9697 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9698 } 9699 if (ret == -1) 9700 scfdie(); 9701 9702 (void) xmlAddChild(n, elts.stability); 9703 (void) xmlAddChildList(n, elts.propvals); 9704 (void) xmlAddChildList(n, elts.properties); 9705 9706 if (eelts->exec_methods == NULL) 9707 eelts->exec_methods = n; 9708 else 9709 (void) xmlAddSibling(eelts->exec_methods, n); 9710 } 9711 9712 static void 9713 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 9714 struct entity_elts *eelts) 9715 { 9716 xmlNodePtr pgnode; 9717 9718 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 9719 if (pgnode == NULL) 9720 uu_die(emsg_create_xml); 9721 9722 safe_setprop(pgnode, name_attr, name); 9723 safe_setprop(pgnode, type_attr, type); 9724 9725 (void) xmlAddChildList(pgnode, elts->propvals); 9726 (void) xmlAddChildList(pgnode, elts->properties); 9727 9728 if (eelts->property_groups == NULL) 9729 eelts->property_groups = pgnode; 9730 else 9731 (void) xmlAddSibling(eelts->property_groups, pgnode); 9732 } 9733 9734 /* 9735 * Process the general property group for a service. This is the one with the 9736 * goodies. 9737 */ 9738 static void 9739 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 9740 { 9741 struct pg_elts elts; 9742 int ret; 9743 9744 /* 9745 * In case there are properties which don't correspond to child 9746 * entities of the service entity, we'll set up a pg_elts structure to 9747 * put them in. 9748 */ 9749 (void) memset(&elts, 0, sizeof (elts)); 9750 9751 /* Walk the properties, looking for special ones. */ 9752 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9753 scfdie(); 9754 9755 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9756 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9757 scfdie(); 9758 9759 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 9760 /* 9761 * Unimplemented and obsolete, but we still process it 9762 * for compatibility purposes. 9763 */ 9764 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9765 prop_get_val(exp_prop, exp_val) == 0) { 9766 uint8_t b; 9767 9768 if (scf_value_get_boolean(exp_val, &b) != 9769 SCF_SUCCESS) 9770 scfdie(); 9771 9772 if (b) { 9773 selts->single_instance = 9774 xmlNewNode(NULL, 9775 (xmlChar *)"single_instance"); 9776 if (selts->single_instance == NULL) 9777 uu_die(emsg_create_xml); 9778 } 9779 9780 continue; 9781 } 9782 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9783 xmlNodePtr rnode, sfnode; 9784 9785 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9786 if (rnode == NULL) 9787 uu_die(emsg_create_xml); 9788 9789 sfnode = xmlNewChild(rnode, NULL, 9790 (xmlChar *)"service_fmri", NULL); 9791 if (sfnode == NULL) 9792 uu_die(emsg_create_xml); 9793 9794 if (set_attr_from_prop(exp_prop, sfnode, 9795 value_attr) == 0) { 9796 selts->restarter = rnode; 9797 continue; 9798 } 9799 9800 xmlFreeNode(rnode); 9801 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 9802 0) { 9803 xmlNodePtr s; 9804 9805 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9806 if (s == NULL) 9807 uu_die(emsg_create_xml); 9808 9809 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9810 selts->stability = s; 9811 continue; 9812 } 9813 9814 xmlFreeNode(s); 9815 } 9816 9817 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9818 } 9819 if (ret == -1) 9820 scfdie(); 9821 9822 if (elts.propvals != NULL || elts.properties != NULL) 9823 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 9824 selts); 9825 } 9826 9827 static void 9828 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 9829 { 9830 xmlNodePtr n, prof, cred, env; 9831 uint8_t use_profile; 9832 int ret, err = 0; 9833 9834 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 9835 9836 env = export_method_environment(pg); 9837 9838 /* Need to know whether we'll use a profile or not. */ 9839 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9840 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9841 prop_get_val(exp_prop, exp_val) == 0) { 9842 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 9843 scfdie(); 9844 9845 if (use_profile) 9846 prof = 9847 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 9848 NULL); 9849 else 9850 cred = 9851 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 9852 NULL); 9853 } 9854 9855 if (env != NULL) 9856 (void) xmlAddChild(n, env); 9857 9858 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9859 scfdie(); 9860 9861 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9862 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9863 scfdie(); 9864 9865 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 9866 if (set_attr_from_prop(exp_prop, n, 9867 "working_directory") != 0) 9868 err = 1; 9869 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 9870 if (set_attr_from_prop(exp_prop, n, "project") != 0) 9871 err = 1; 9872 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 9873 if (set_attr_from_prop(exp_prop, n, 9874 "resource_pool") != 0) 9875 err = 1; 9876 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9877 if (set_attr_from_prop(exp_prop, n, 9878 "security_flags") != 0) 9879 err = 1; 9880 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9881 /* EMPTY */ 9882 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 9883 if (use_profile || 9884 set_attr_from_prop(exp_prop, cred, "user") != 0) 9885 err = 1; 9886 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 9887 if (use_profile || 9888 set_attr_from_prop(exp_prop, cred, "group") != 0) 9889 err = 1; 9890 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 9891 if (use_profile || set_attr_from_prop(exp_prop, cred, 9892 "supp_groups") != 0) 9893 err = 1; 9894 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 9895 if (use_profile || set_attr_from_prop(exp_prop, cred, 9896 "privileges") != 0) 9897 err = 1; 9898 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 9899 0) { 9900 if (use_profile || set_attr_from_prop(exp_prop, cred, 9901 "limit_privileges") != 0) 9902 err = 1; 9903 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9904 if (!use_profile || set_attr_from_prop(exp_prop, 9905 prof, name_attr) != 0) 9906 err = 1; 9907 } else { 9908 /* Can't have generic properties in method_context's */ 9909 err = 1; 9910 } 9911 } 9912 if (ret == -1) 9913 scfdie(); 9914 9915 if (err && env == NULL) { 9916 xmlFreeNode(n); 9917 export_pg(pg, elts, SCE_ALL_VALUES); 9918 return; 9919 } 9920 9921 elts->method_context = n; 9922 } 9923 9924 /* 9925 * Given a dependency property group in the tfmri entity (target fmri), return 9926 * a dependent element which represents it. 9927 */ 9928 static xmlNodePtr 9929 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 9930 { 9931 uint8_t b; 9932 xmlNodePtr n, sf; 9933 int err = 0, ret; 9934 struct pg_elts pgelts; 9935 9936 /* 9937 * If external isn't set to true then exporting the service will 9938 * export this as a normal dependency, so we should stop to avoid 9939 * duplication. 9940 */ 9941 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 9942 scf_property_get_value(exp_prop, exp_val) != 0 || 9943 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 9944 if (g_verbose) { 9945 warn(gettext("Dependent \"%s\" cannot be exported " 9946 "properly because the \"%s\" property of the " 9947 "\"%s\" dependency of %s is not set to true.\n"), 9948 name, scf_property_external, name, tfmri); 9949 } 9950 9951 return (NULL); 9952 } 9953 9954 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 9955 if (n == NULL) 9956 uu_die(emsg_create_xml); 9957 9958 safe_setprop(n, name_attr, name); 9959 9960 /* Get the required attributes */ 9961 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9962 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9963 err = 1; 9964 9965 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9966 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9967 err = 1; 9968 9969 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9970 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 9971 prop_get_val(exp_prop, exp_val) == 0) { 9972 /* EMPTY */ 9973 } else 9974 err = 1; 9975 9976 if (err) { 9977 xmlFreeNode(n); 9978 return (NULL); 9979 } 9980 9981 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 9982 if (sf == NULL) 9983 uu_die(emsg_create_xml); 9984 9985 safe_setprop(sf, value_attr, tfmri); 9986 9987 /* 9988 * Now add elements for the other properties. 9989 */ 9990 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9991 scfdie(); 9992 9993 (void) memset(&pgelts, 0, sizeof (pgelts)); 9994 9995 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9996 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9997 scfdie(); 9998 9999 if (strcmp(exp_str, scf_property_external) == 0 || 10000 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 10001 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 10002 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 10003 continue; 10004 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 10005 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 10006 prop_get_val(exp_prop, exp_val) == 0) { 10007 char type[sizeof ("service") + 1]; 10008 10009 if (scf_value_get_astring(exp_val, type, 10010 sizeof (type)) < 0) 10011 scfdie(); 10012 10013 if (strcmp(type, "service") == 0) 10014 continue; 10015 } 10016 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 10017 xmlNodePtr s; 10018 10019 s = xmlNewNode(NULL, (xmlChar *)"stability"); 10020 if (s == NULL) 10021 uu_die(emsg_create_xml); 10022 10023 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 10024 pgelts.stability = s; 10025 continue; 10026 } 10027 10028 xmlFreeNode(s); 10029 } 10030 10031 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10032 } 10033 if (ret == -1) 10034 scfdie(); 10035 10036 (void) xmlAddChild(n, pgelts.stability); 10037 (void) xmlAddChildList(n, pgelts.propvals); 10038 (void) xmlAddChildList(n, pgelts.properties); 10039 10040 return (n); 10041 } 10042 10043 static void 10044 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 10045 { 10046 scf_propertygroup_t *opg; 10047 scf_iter_t *iter; 10048 char *type, *fmri; 10049 int ret; 10050 struct pg_elts pgelts; 10051 xmlNodePtr n; 10052 scf_error_t serr; 10053 10054 if ((opg = scf_pg_create(g_hndl)) == NULL || 10055 (iter = scf_iter_create(g_hndl)) == NULL) 10056 scfdie(); 10057 10058 /* Can't use exp_prop_iter due to export_dependent(). */ 10059 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10060 scfdie(); 10061 10062 type = safe_malloc(max_scf_pg_type_len + 1); 10063 10064 /* Get an extra byte so we can tell if values are too long. */ 10065 fmri = safe_malloc(max_scf_fmri_len + 2); 10066 10067 (void) memset(&pgelts, 0, sizeof (pgelts)); 10068 10069 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 10070 void *entity; 10071 int isservice; 10072 scf_type_t ty; 10073 10074 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 10075 scfdie(); 10076 10077 if ((ty != SCF_TYPE_ASTRING && 10078 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 10079 prop_get_val(exp_prop, exp_val) != 0) { 10080 export_property(exp_prop, NULL, &pgelts, 10081 SCE_ALL_VALUES); 10082 continue; 10083 } 10084 10085 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10086 scfdie(); 10087 10088 if (scf_value_get_astring(exp_val, fmri, 10089 max_scf_fmri_len + 2) < 0) 10090 scfdie(); 10091 10092 /* Look for a dependency group in the target fmri. */ 10093 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10094 switch (serr) { 10095 case SCF_ERROR_NONE: 10096 break; 10097 10098 case SCF_ERROR_NO_MEMORY: 10099 uu_die(gettext("Out of memory.\n")); 10100 /* NOTREACHED */ 10101 10102 case SCF_ERROR_INVALID_ARGUMENT: 10103 if (g_verbose) { 10104 if (scf_property_to_fmri(exp_prop, fmri, 10105 max_scf_fmri_len + 2) < 0) 10106 scfdie(); 10107 10108 warn(gettext("The value of %s is not a valid " 10109 "FMRI.\n"), fmri); 10110 } 10111 10112 export_property(exp_prop, exp_str, &pgelts, 10113 SCE_ALL_VALUES); 10114 continue; 10115 10116 case SCF_ERROR_CONSTRAINT_VIOLATED: 10117 if (g_verbose) { 10118 if (scf_property_to_fmri(exp_prop, fmri, 10119 max_scf_fmri_len + 2) < 0) 10120 scfdie(); 10121 10122 warn(gettext("The value of %s does not specify " 10123 "a service or an instance.\n"), fmri); 10124 } 10125 10126 export_property(exp_prop, exp_str, &pgelts, 10127 SCE_ALL_VALUES); 10128 continue; 10129 10130 case SCF_ERROR_NOT_FOUND: 10131 if (g_verbose) { 10132 if (scf_property_to_fmri(exp_prop, fmri, 10133 max_scf_fmri_len + 2) < 0) 10134 scfdie(); 10135 10136 warn(gettext("The entity specified by %s does " 10137 "not exist.\n"), fmri); 10138 } 10139 10140 export_property(exp_prop, exp_str, &pgelts, 10141 SCE_ALL_VALUES); 10142 continue; 10143 10144 default: 10145 #ifndef NDEBUG 10146 (void) fprintf(stderr, "%s:%d: %s() failed with " 10147 "unexpected error %d.\n", __FILE__, __LINE__, 10148 "fmri_to_entity", serr); 10149 #endif 10150 abort(); 10151 } 10152 10153 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 10154 if (scf_error() != SCF_ERROR_NOT_FOUND) 10155 scfdie(); 10156 10157 warn(gettext("Entity %s is missing dependency property " 10158 "group %s.\n"), fmri, exp_str); 10159 10160 export_property(exp_prop, NULL, &pgelts, 10161 SCE_ALL_VALUES); 10162 continue; 10163 } 10164 10165 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 10166 scfdie(); 10167 10168 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 10169 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 10170 scfdie(); 10171 10172 warn(gettext("Property group %s is not of " 10173 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 10174 10175 export_property(exp_prop, NULL, &pgelts, 10176 SCE_ALL_VALUES); 10177 continue; 10178 } 10179 10180 n = export_dependent(opg, exp_str, fmri); 10181 if (n == NULL) { 10182 export_property(exp_prop, exp_str, &pgelts, 10183 SCE_ALL_VALUES); 10184 } else { 10185 if (eelts->dependents == NULL) 10186 eelts->dependents = n; 10187 else 10188 (void) xmlAddSibling(eelts->dependents, 10189 n); 10190 } 10191 } 10192 if (ret == -1) 10193 scfdie(); 10194 10195 free(fmri); 10196 free(type); 10197 10198 scf_iter_destroy(iter); 10199 scf_pg_destroy(opg); 10200 10201 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10202 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 10203 eelts); 10204 } 10205 10206 static void 10207 make_node(xmlNodePtr *nodep, const char *name) 10208 { 10209 if (*nodep == NULL) { 10210 *nodep = xmlNewNode(NULL, (xmlChar *)name); 10211 if (*nodep == NULL) 10212 uu_die(emsg_create_xml); 10213 } 10214 } 10215 10216 static xmlNodePtr 10217 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 10218 { 10219 int ret; 10220 xmlNodePtr parent = NULL; 10221 xmlNodePtr loctext = NULL; 10222 10223 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10224 scfdie(); 10225 10226 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10227 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 10228 prop_get_val(exp_prop, exp_val) != 0) 10229 continue; 10230 10231 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 10232 scfdie(); 10233 10234 make_node(&parent, parname); 10235 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 10236 (xmlChar *)exp_str); 10237 if (loctext == NULL) 10238 uu_die(emsg_create_xml); 10239 10240 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10241 scfdie(); 10242 10243 safe_setprop(loctext, "xml:lang", exp_str); 10244 } 10245 10246 if (ret == -1) 10247 scfdie(); 10248 10249 return (parent); 10250 } 10251 10252 static xmlNodePtr 10253 export_tm_manpage(scf_propertygroup_t *pg) 10254 { 10255 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 10256 if (manpage == NULL) 10257 uu_die(emsg_create_xml); 10258 10259 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 10260 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 10261 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 10262 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 10263 xmlFreeNode(manpage); 10264 return (NULL); 10265 } 10266 10267 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 10268 (void) set_attr_from_prop_default(exp_prop, 10269 manpage, "manpath", ":default"); 10270 10271 return (manpage); 10272 } 10273 10274 static xmlNodePtr 10275 export_tm_doc_link(scf_propertygroup_t *pg) 10276 { 10277 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 10278 if (doc_link == NULL) 10279 uu_die(emsg_create_xml); 10280 10281 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 10282 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 10283 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 10284 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 10285 xmlFreeNode(doc_link); 10286 return (NULL); 10287 } 10288 return (doc_link); 10289 } 10290 10291 /* 10292 * Process template information for a service or instances. 10293 */ 10294 static void 10295 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 10296 struct template_elts *telts) 10297 { 10298 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 10299 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 10300 xmlNodePtr child = NULL; 10301 10302 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 10303 scfdie(); 10304 10305 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 10306 telts->common_name = export_tm_loctext(pg, "common_name"); 10307 if (telts->common_name == NULL) 10308 export_pg(pg, elts, SCE_ALL_VALUES); 10309 return; 10310 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 10311 telts->description = export_tm_loctext(pg, "description"); 10312 if (telts->description == NULL) 10313 export_pg(pg, elts, SCE_ALL_VALUES); 10314 return; 10315 } 10316 10317 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 10318 child = export_tm_manpage(pg); 10319 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 10320 child = export_tm_doc_link(pg); 10321 } 10322 10323 if (child != NULL) { 10324 make_node(&telts->documentation, "documentation"); 10325 (void) xmlAddChild(telts->documentation, child); 10326 } else { 10327 export_pg(pg, elts, SCE_ALL_VALUES); 10328 } 10329 } 10330 10331 /* 10332 * Process parameter and paramval elements 10333 */ 10334 static void 10335 export_parameter(scf_property_t *prop, const char *name, 10336 struct params_elts *elts) 10337 { 10338 xmlNodePtr param; 10339 scf_error_t err = 0; 10340 int ret; 10341 10342 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 10343 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL) 10344 uu_die(emsg_create_xml); 10345 10346 safe_setprop(param, name_attr, name); 10347 10348 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 10349 scfdie(); 10350 safe_setprop(param, value_attr, exp_str); 10351 10352 if (elts->paramval == NULL) 10353 elts->paramval = param; 10354 else 10355 (void) xmlAddSibling(elts->paramval, param); 10356 10357 return; 10358 } 10359 10360 err = scf_error(); 10361 10362 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 10363 err != SCF_ERROR_NOT_FOUND) 10364 scfdie(); 10365 10366 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL) 10367 uu_die(emsg_create_xml); 10368 10369 safe_setprop(param, name_attr, name); 10370 10371 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 10372 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 10373 scfdie(); 10374 10375 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 10376 1) { 10377 xmlNodePtr vn; 10378 10379 if ((vn = xmlNewChild(param, NULL, 10380 (xmlChar *)"value_node", NULL)) == NULL) 10381 uu_die(emsg_create_xml); 10382 10383 if (scf_value_get_as_string(exp_val, exp_str, 10384 exp_str_sz) < 0) 10385 scfdie(); 10386 10387 safe_setprop(vn, value_attr, exp_str); 10388 } 10389 if (ret != 0) 10390 scfdie(); 10391 } 10392 10393 if (elts->parameter == NULL) 10394 elts->parameter = param; 10395 else 10396 (void) xmlAddSibling(elts->parameter, param); 10397 } 10398 10399 /* 10400 * Process notification parameters for a service or instance 10401 */ 10402 static void 10403 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts) 10404 { 10405 xmlNodePtr n, event, *type; 10406 struct params_elts *eelts; 10407 int ret, err, i; 10408 char *s; 10409 10410 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters"); 10411 event = xmlNewNode(NULL, (xmlChar *)"event"); 10412 if (n == NULL || event == NULL) 10413 uu_die(emsg_create_xml); 10414 10415 /* event value */ 10416 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 10417 scfdie(); 10418 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */ 10419 if ((s = strchr(exp_str, ',')) != NULL) 10420 *s = '\0'; 10421 safe_setprop(event, value_attr, exp_str); 10422 10423 (void) xmlAddChild(n, event); 10424 10425 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL || 10426 (eelts = calloc(URI_SCHEME_NUM, 10427 sizeof (struct params_elts))) == NULL) 10428 uu_die(gettext("Out of memory.\n")); 10429 10430 err = 0; 10431 10432 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10433 scfdie(); 10434 10435 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10436 char *t, *p; 10437 10438 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10439 scfdie(); 10440 10441 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) { 10442 /* 10443 * this is not a well formed notification parameters 10444 * element, we should export as regular pg 10445 */ 10446 err = 1; 10447 break; 10448 } 10449 10450 if ((i = check_uri_protocol(t)) < 0) { 10451 err = 1; 10452 break; 10453 } 10454 10455 if (type[i] == NULL) { 10456 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) == 10457 NULL) 10458 uu_die(emsg_create_xml); 10459 10460 safe_setprop(type[i], name_attr, t); 10461 } 10462 if (strcmp(p, active_attr) == 0) { 10463 if (set_attr_from_prop(exp_prop, type[i], 10464 active_attr) != 0) { 10465 err = 1; 10466 break; 10467 } 10468 continue; 10469 } 10470 /* 10471 * We export the parameter 10472 */ 10473 export_parameter(exp_prop, p, &eelts[i]); 10474 } 10475 10476 if (ret == -1) 10477 scfdie(); 10478 10479 if (err == 1) { 10480 for (i = 0; i < URI_SCHEME_NUM; ++i) 10481 xmlFree(type[i]); 10482 free(type); 10483 10484 export_pg(pg, elts, SCE_ALL_VALUES); 10485 10486 return; 10487 } else { 10488 for (i = 0; i < URI_SCHEME_NUM; ++i) 10489 if (type[i] != NULL) { 10490 (void) xmlAddChildList(type[i], 10491 eelts[i].paramval); 10492 (void) xmlAddChildList(type[i], 10493 eelts[i].parameter); 10494 (void) xmlAddSibling(event, type[i]); 10495 } 10496 } 10497 free(type); 10498 10499 if (elts->notify_params == NULL) 10500 elts->notify_params = n; 10501 else 10502 (void) xmlAddSibling(elts->notify_params, n); 10503 } 10504 10505 /* 10506 * Process the general property group for an instance. 10507 */ 10508 static void 10509 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 10510 struct entity_elts *elts) 10511 { 10512 uint8_t enabled; 10513 struct pg_elts pgelts; 10514 int ret; 10515 10516 /* enabled */ 10517 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10518 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10519 prop_get_val(exp_prop, exp_val) == 0) { 10520 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10521 scfdie(); 10522 } else { 10523 enabled = 0; 10524 } 10525 10526 safe_setprop(inode, enabled_attr, enabled ? true : false); 10527 10528 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10529 scfdie(); 10530 10531 (void) memset(&pgelts, 0, sizeof (pgelts)); 10532 10533 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10534 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10535 scfdie(); 10536 10537 if (strcmp(exp_str, scf_property_enabled) == 0) { 10538 continue; 10539 } else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) { 10540 continue; 10541 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10542 xmlNodePtr rnode, sfnode; 10543 10544 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10545 if (rnode == NULL) 10546 uu_die(emsg_create_xml); 10547 10548 sfnode = xmlNewChild(rnode, NULL, 10549 (xmlChar *)"service_fmri", NULL); 10550 if (sfnode == NULL) 10551 uu_die(emsg_create_xml); 10552 10553 if (set_attr_from_prop(exp_prop, sfnode, 10554 value_attr) == 0) { 10555 elts->restarter = rnode; 10556 continue; 10557 } 10558 10559 xmlFreeNode(rnode); 10560 } 10561 10562 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10563 } 10564 if (ret == -1) 10565 scfdie(); 10566 10567 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10568 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10569 elts); 10570 } 10571 10572 /* 10573 * Put an instance element for the given instance into selts. 10574 */ 10575 static void 10576 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10577 { 10578 xmlNodePtr n; 10579 boolean_t isdefault; 10580 struct entity_elts elts; 10581 struct template_elts template_elts; 10582 int ret; 10583 10584 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10585 if (n == NULL) 10586 uu_die(emsg_create_xml); 10587 10588 /* name */ 10589 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10590 scfdie(); 10591 safe_setprop(n, name_attr, exp_str); 10592 isdefault = strcmp(exp_str, "default") == 0; 10593 10594 /* check existance of general pg (since general/enabled is required) */ 10595 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10596 if (scf_error() != SCF_ERROR_NOT_FOUND) 10597 scfdie(); 10598 10599 if (g_verbose) { 10600 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10601 scfdie(); 10602 10603 warn(gettext("Instance %s has no general property " 10604 "group; it will be marked disabled.\n"), exp_str); 10605 } 10606 10607 safe_setprop(n, enabled_attr, false); 10608 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10609 strcmp(exp_str, scf_group_framework) != 0) { 10610 if (g_verbose) { 10611 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10612 scfdie(); 10613 10614 warn(gettext("Property group %s is not of type " 10615 "framework; the instance will be marked " 10616 "disabled.\n"), exp_str); 10617 } 10618 10619 safe_setprop(n, enabled_attr, false); 10620 } 10621 10622 /* property groups */ 10623 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10624 scfdie(); 10625 10626 (void) memset(&elts, 0, sizeof (elts)); 10627 (void) memset(&template_elts, 0, sizeof (template_elts)); 10628 10629 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10630 uint32_t pgflags; 10631 10632 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10633 scfdie(); 10634 10635 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10636 continue; 10637 10638 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10639 scfdie(); 10640 10641 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10642 export_dependency(exp_pg, &elts); 10643 continue; 10644 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10645 export_method(exp_pg, &elts); 10646 continue; 10647 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10648 if (scf_pg_get_name(exp_pg, exp_str, 10649 max_scf_name_len + 1) < 0) 10650 scfdie(); 10651 10652 if (strcmp(exp_str, scf_pg_general) == 0) { 10653 export_inst_general(exp_pg, n, &elts); 10654 continue; 10655 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10656 0) { 10657 export_method_context(exp_pg, &elts); 10658 continue; 10659 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10660 export_dependents(exp_pg, &elts); 10661 continue; 10662 } 10663 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10664 export_template(exp_pg, &elts, &template_elts); 10665 continue; 10666 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10667 export_notify_params(exp_pg, &elts); 10668 continue; 10669 } 10670 10671 /* Ordinary pg. */ 10672 export_pg(exp_pg, &elts, flags); 10673 } 10674 if (ret == -1) 10675 scfdie(); 10676 10677 if (template_elts.common_name != NULL) { 10678 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10679 (void) xmlAddChild(elts.template, template_elts.common_name); 10680 (void) xmlAddChild(elts.template, template_elts.description); 10681 (void) xmlAddChild(elts.template, template_elts.documentation); 10682 } else { 10683 xmlFreeNode(template_elts.description); 10684 xmlFreeNode(template_elts.documentation); 10685 } 10686 10687 if (isdefault && elts.restarter == NULL && 10688 elts.dependencies == NULL && elts.method_context == NULL && 10689 elts.exec_methods == NULL && elts.notify_params == NULL && 10690 elts.property_groups == NULL && elts.template == NULL) { 10691 xmlChar *eval; 10692 10693 /* This is a default instance */ 10694 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10695 10696 xmlFreeNode(n); 10697 10698 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10699 if (n == NULL) 10700 uu_die(emsg_create_xml); 10701 10702 safe_setprop(n, enabled_attr, (char *)eval); 10703 xmlFree(eval); 10704 10705 selts->create_default_instance = n; 10706 } else { 10707 /* Assemble the children in order. */ 10708 (void) xmlAddChild(n, elts.restarter); 10709 (void) xmlAddChildList(n, elts.dependencies); 10710 (void) xmlAddChildList(n, elts.dependents); 10711 (void) xmlAddChild(n, elts.method_context); 10712 (void) xmlAddChildList(n, elts.exec_methods); 10713 (void) xmlAddChildList(n, elts.notify_params); 10714 (void) xmlAddChildList(n, elts.property_groups); 10715 (void) xmlAddChild(n, elts.template); 10716 10717 if (selts->instances == NULL) 10718 selts->instances = n; 10719 else 10720 (void) xmlAddSibling(selts->instances, n); 10721 } 10722 } 10723 10724 /* 10725 * Return a service element for the given service. 10726 */ 10727 static xmlNodePtr 10728 export_service(scf_service_t *svc, int flags) 10729 { 10730 xmlNodePtr snode; 10731 struct entity_elts elts; 10732 struct template_elts template_elts; 10733 int ret; 10734 10735 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10736 if (snode == NULL) 10737 uu_die(emsg_create_xml); 10738 10739 /* Get & set name attribute */ 10740 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10741 scfdie(); 10742 safe_setprop(snode, name_attr, exp_str); 10743 10744 safe_setprop(snode, type_attr, "service"); 10745 safe_setprop(snode, "version", "0"); 10746 10747 /* Acquire child elements. */ 10748 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10749 scfdie(); 10750 10751 (void) memset(&elts, 0, sizeof (elts)); 10752 (void) memset(&template_elts, 0, sizeof (template_elts)); 10753 10754 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10755 uint32_t pgflags; 10756 10757 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10758 scfdie(); 10759 10760 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10761 continue; 10762 10763 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10764 scfdie(); 10765 10766 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10767 export_dependency(exp_pg, &elts); 10768 continue; 10769 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10770 export_method(exp_pg, &elts); 10771 continue; 10772 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10773 if (scf_pg_get_name(exp_pg, exp_str, 10774 max_scf_name_len + 1) < 0) 10775 scfdie(); 10776 10777 if (strcmp(exp_str, scf_pg_general) == 0) { 10778 export_svc_general(exp_pg, &elts); 10779 continue; 10780 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10781 0) { 10782 export_method_context(exp_pg, &elts); 10783 continue; 10784 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10785 export_dependents(exp_pg, &elts); 10786 continue; 10787 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10788 continue; 10789 } 10790 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10791 export_template(exp_pg, &elts, &template_elts); 10792 continue; 10793 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10794 export_notify_params(exp_pg, &elts); 10795 continue; 10796 } 10797 10798 export_pg(exp_pg, &elts, flags); 10799 } 10800 if (ret == -1) 10801 scfdie(); 10802 10803 if (template_elts.common_name != NULL) { 10804 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10805 (void) xmlAddChild(elts.template, template_elts.common_name); 10806 (void) xmlAddChild(elts.template, template_elts.description); 10807 (void) xmlAddChild(elts.template, template_elts.documentation); 10808 } else { 10809 xmlFreeNode(template_elts.description); 10810 xmlFreeNode(template_elts.documentation); 10811 } 10812 10813 /* Iterate instances */ 10814 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10815 scfdie(); 10816 10817 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10818 export_instance(exp_inst, &elts, flags); 10819 if (ret == -1) 10820 scfdie(); 10821 10822 /* Now add all of the accumulated elements in order. */ 10823 (void) xmlAddChild(snode, elts.create_default_instance); 10824 (void) xmlAddChild(snode, elts.single_instance); 10825 (void) xmlAddChild(snode, elts.restarter); 10826 (void) xmlAddChildList(snode, elts.dependencies); 10827 (void) xmlAddChildList(snode, elts.dependents); 10828 (void) xmlAddChild(snode, elts.method_context); 10829 (void) xmlAddChildList(snode, elts.exec_methods); 10830 (void) xmlAddChildList(snode, elts.notify_params); 10831 (void) xmlAddChildList(snode, elts.property_groups); 10832 (void) xmlAddChildList(snode, elts.instances); 10833 (void) xmlAddChild(snode, elts.stability); 10834 (void) xmlAddChild(snode, elts.template); 10835 10836 return (snode); 10837 } 10838 10839 static int 10840 export_callback(void *data, scf_walkinfo_t *wip) 10841 { 10842 FILE *f; 10843 xmlDocPtr doc; 10844 xmlNodePtr sb; 10845 int result; 10846 struct export_args *argsp = (struct export_args *)data; 10847 10848 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10849 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10850 (exp_prop = scf_property_create(g_hndl)) == NULL || 10851 (exp_val = scf_value_create(g_hndl)) == NULL || 10852 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10853 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10854 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10855 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10856 scfdie(); 10857 10858 exp_str_sz = max_scf_len + 1; 10859 exp_str = safe_malloc(exp_str_sz); 10860 10861 if (argsp->filename != NULL) { 10862 errno = 0; 10863 f = fopen(argsp->filename, "wb"); 10864 if (f == NULL) { 10865 if (errno == 0) 10866 uu_die(gettext("Could not open \"%s\": no free " 10867 "stdio streams.\n"), argsp->filename); 10868 else 10869 uu_die(gettext("Could not open \"%s\""), 10870 argsp->filename); 10871 } 10872 } else 10873 f = stdout; 10874 10875 doc = xmlNewDoc((xmlChar *)"1.0"); 10876 if (doc == NULL) 10877 uu_die(gettext("Could not create XML document.\n")); 10878 10879 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10880 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10881 uu_die(emsg_create_xml); 10882 10883 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10884 if (sb == NULL) 10885 uu_die(emsg_create_xml); 10886 safe_setprop(sb, type_attr, "manifest"); 10887 safe_setprop(sb, name_attr, "export"); 10888 (void) xmlAddSibling(doc->children, sb); 10889 10890 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10891 10892 result = write_service_bundle(doc, f); 10893 10894 free(exp_str); 10895 scf_iter_destroy(exp_val_iter); 10896 scf_iter_destroy(exp_prop_iter); 10897 scf_iter_destroy(exp_pg_iter); 10898 scf_iter_destroy(exp_inst_iter); 10899 scf_value_destroy(exp_val); 10900 scf_property_destroy(exp_prop); 10901 scf_pg_destroy(exp_pg); 10902 scf_instance_destroy(exp_inst); 10903 10904 xmlFreeDoc(doc); 10905 10906 if (f != stdout) 10907 (void) fclose(f); 10908 10909 return (result); 10910 } 10911 10912 /* 10913 * Get the service named by fmri, build an XML tree which represents it, and 10914 * dump it into filename (or stdout if filename is NULL). 10915 */ 10916 int 10917 lscf_service_export(char *fmri, const char *filename, int flags) 10918 { 10919 struct export_args args; 10920 char *fmridup; 10921 const char *scope, *svc, *inst; 10922 size_t cblen = 3 * max_scf_name_len; 10923 char *canonbuf = alloca(cblen); 10924 int ret, err; 10925 10926 lscf_prep_hndl(); 10927 10928 bzero(&args, sizeof (args)); 10929 args.filename = filename; 10930 args.flags = flags; 10931 10932 /* 10933 * If some poor user has passed an exact instance FMRI, of the sort 10934 * one might cut and paste from svcs(1) or an error message, warn 10935 * and chop off the instance instead of failing. 10936 */ 10937 fmridup = alloca(strlen(fmri) + 1); 10938 (void) strcpy(fmridup, fmri); 10939 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX, 10940 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 && 10941 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 && 10942 inst != NULL) { 10943 (void) strlcpy(canonbuf, "svc:/", cblen); 10944 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 10945 (void) strlcat(canonbuf, "/", cblen); 10946 (void) strlcat(canonbuf, scope, cblen); 10947 } 10948 (void) strlcat(canonbuf, svc, cblen); 10949 fmri = canonbuf; 10950 10951 warn(gettext("Only services may be exported; ignoring " 10952 "instance portion of argument.\n")); 10953 } 10954 10955 err = 0; 10956 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10957 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10958 &args, &err, semerr)) != 0) { 10959 if (ret != -1) 10960 semerr(gettext("Failed to walk instances: %s\n"), 10961 scf_strerror(ret)); 10962 return (-1); 10963 } 10964 10965 /* 10966 * Error message has already been printed. 10967 */ 10968 if (err != 0) 10969 return (-1); 10970 10971 return (0); 10972 } 10973 10974 10975 /* 10976 * Archive 10977 */ 10978 10979 static xmlNodePtr 10980 make_archive(int flags) 10981 { 10982 xmlNodePtr sb; 10983 scf_scope_t *scope; 10984 scf_service_t *svc; 10985 scf_iter_t *iter; 10986 int r; 10987 10988 if ((scope = scf_scope_create(g_hndl)) == NULL || 10989 (svc = scf_service_create(g_hndl)) == NULL || 10990 (iter = scf_iter_create(g_hndl)) == NULL || 10991 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10992 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10993 (exp_prop = scf_property_create(g_hndl)) == NULL || 10994 (exp_val = scf_value_create(g_hndl)) == NULL || 10995 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10996 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10997 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10998 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10999 scfdie(); 11000 11001 exp_str_sz = max_scf_len + 1; 11002 exp_str = safe_malloc(exp_str_sz); 11003 11004 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 11005 if (sb == NULL) 11006 uu_die(emsg_create_xml); 11007 safe_setprop(sb, type_attr, "archive"); 11008 safe_setprop(sb, name_attr, "none"); 11009 11010 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 11011 scfdie(); 11012 if (scf_iter_scope_services(iter, scope) != 0) 11013 scfdie(); 11014 11015 for (;;) { 11016 r = scf_iter_next_service(iter, svc); 11017 if (r == 0) 11018 break; 11019 if (r != 1) 11020 scfdie(); 11021 11022 if (scf_service_get_name(svc, exp_str, 11023 max_scf_name_len + 1) < 0) 11024 scfdie(); 11025 11026 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 11027 continue; 11028 11029 (void) xmlAddChild(sb, export_service(svc, flags)); 11030 } 11031 11032 free(exp_str); 11033 11034 scf_iter_destroy(exp_val_iter); 11035 scf_iter_destroy(exp_prop_iter); 11036 scf_iter_destroy(exp_pg_iter); 11037 scf_iter_destroy(exp_inst_iter); 11038 scf_value_destroy(exp_val); 11039 scf_property_destroy(exp_prop); 11040 scf_pg_destroy(exp_pg); 11041 scf_instance_destroy(exp_inst); 11042 scf_iter_destroy(iter); 11043 scf_service_destroy(svc); 11044 scf_scope_destroy(scope); 11045 11046 return (sb); 11047 } 11048 11049 int 11050 lscf_archive(const char *filename, int flags) 11051 { 11052 FILE *f; 11053 xmlDocPtr doc; 11054 int result; 11055 11056 lscf_prep_hndl(); 11057 11058 if (filename != NULL) { 11059 errno = 0; 11060 f = fopen(filename, "wb"); 11061 if (f == NULL) { 11062 if (errno == 0) 11063 uu_die(gettext("Could not open \"%s\": no free " 11064 "stdio streams.\n"), filename); 11065 else 11066 uu_die(gettext("Could not open \"%s\""), 11067 filename); 11068 } 11069 } else 11070 f = stdout; 11071 11072 doc = xmlNewDoc((xmlChar *)"1.0"); 11073 if (doc == NULL) 11074 uu_die(gettext("Could not create XML document.\n")); 11075 11076 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11077 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11078 uu_die(emsg_create_xml); 11079 11080 (void) xmlAddSibling(doc->children, make_archive(flags)); 11081 11082 result = write_service_bundle(doc, f); 11083 11084 xmlFreeDoc(doc); 11085 11086 if (f != stdout) 11087 (void) fclose(f); 11088 11089 return (result); 11090 } 11091 11092 11093 /* 11094 * "Extract" a profile. 11095 */ 11096 int 11097 lscf_profile_extract(const char *filename) 11098 { 11099 FILE *f; 11100 xmlDocPtr doc; 11101 xmlNodePtr sb, snode, inode; 11102 scf_scope_t *scope; 11103 scf_service_t *svc; 11104 scf_instance_t *inst; 11105 scf_propertygroup_t *pg; 11106 scf_property_t *prop; 11107 scf_value_t *val; 11108 scf_iter_t *siter, *iiter; 11109 int r, s; 11110 char *namebuf; 11111 uint8_t b; 11112 int result; 11113 11114 lscf_prep_hndl(); 11115 11116 if (filename != NULL) { 11117 errno = 0; 11118 f = fopen(filename, "wb"); 11119 if (f == NULL) { 11120 if (errno == 0) 11121 uu_die(gettext("Could not open \"%s\": no " 11122 "free stdio streams.\n"), filename); 11123 else 11124 uu_die(gettext("Could not open \"%s\""), 11125 filename); 11126 } 11127 } else 11128 f = stdout; 11129 11130 doc = xmlNewDoc((xmlChar *)"1.0"); 11131 if (doc == NULL) 11132 uu_die(gettext("Could not create XML document.\n")); 11133 11134 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11135 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11136 uu_die(emsg_create_xml); 11137 11138 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 11139 if (sb == NULL) 11140 uu_die(emsg_create_xml); 11141 safe_setprop(sb, type_attr, "profile"); 11142 safe_setprop(sb, name_attr, "extract"); 11143 (void) xmlAddSibling(doc->children, sb); 11144 11145 if ((scope = scf_scope_create(g_hndl)) == NULL || 11146 (svc = scf_service_create(g_hndl)) == NULL || 11147 (inst = scf_instance_create(g_hndl)) == NULL || 11148 (pg = scf_pg_create(g_hndl)) == NULL || 11149 (prop = scf_property_create(g_hndl)) == NULL || 11150 (val = scf_value_create(g_hndl)) == NULL || 11151 (siter = scf_iter_create(g_hndl)) == NULL || 11152 (iiter = scf_iter_create(g_hndl)) == NULL) 11153 scfdie(); 11154 11155 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 11156 scfdie(); 11157 11158 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 11159 scfdie(); 11160 11161 namebuf = safe_malloc(max_scf_name_len + 1); 11162 11163 while ((r = scf_iter_next_service(siter, svc)) == 1) { 11164 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 11165 scfdie(); 11166 11167 snode = xmlNewNode(NULL, (xmlChar *)"service"); 11168 if (snode == NULL) 11169 uu_die(emsg_create_xml); 11170 11171 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 11172 0) 11173 scfdie(); 11174 11175 safe_setprop(snode, name_attr, namebuf); 11176 11177 safe_setprop(snode, type_attr, "service"); 11178 safe_setprop(snode, "version", "0"); 11179 11180 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 11181 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 11182 SCF_SUCCESS) { 11183 if (scf_error() != SCF_ERROR_NOT_FOUND) 11184 scfdie(); 11185 11186 if (g_verbose) { 11187 ssize_t len; 11188 char *fmri; 11189 11190 len = 11191 scf_instance_to_fmri(inst, NULL, 0); 11192 if (len < 0) 11193 scfdie(); 11194 11195 fmri = safe_malloc(len + 1); 11196 11197 if (scf_instance_to_fmri(inst, fmri, 11198 len + 1) < 0) 11199 scfdie(); 11200 11201 warn("Instance %s has no \"%s\" " 11202 "property group.\n", fmri, 11203 scf_pg_general); 11204 11205 free(fmri); 11206 } 11207 11208 continue; 11209 } 11210 11211 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 11212 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 11213 prop_get_val(prop, val) != 0) 11214 continue; 11215 11216 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 11217 NULL); 11218 if (inode == NULL) 11219 uu_die(emsg_create_xml); 11220 11221 if (scf_instance_get_name(inst, namebuf, 11222 max_scf_name_len + 1) < 0) 11223 scfdie(); 11224 11225 safe_setprop(inode, name_attr, namebuf); 11226 11227 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 11228 scfdie(); 11229 11230 safe_setprop(inode, enabled_attr, b ? true : false); 11231 } 11232 if (s < 0) 11233 scfdie(); 11234 11235 if (snode->children != NULL) 11236 (void) xmlAddChild(sb, snode); 11237 else 11238 xmlFreeNode(snode); 11239 } 11240 if (r < 0) 11241 scfdie(); 11242 11243 free(namebuf); 11244 11245 result = write_service_bundle(doc, f); 11246 11247 xmlFreeDoc(doc); 11248 11249 if (f != stdout) 11250 (void) fclose(f); 11251 11252 return (result); 11253 } 11254 11255 11256 /* 11257 * Entity manipulation commands 11258 */ 11259 11260 /* 11261 * Entity selection. If no entity is selected, then the current scope is in 11262 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 11263 * only cur_inst is NULL, and when an instance is selected, none are NULL. 11264 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 11265 * cur_inst will be non-NULL. 11266 */ 11267 11268 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 11269 static int 11270 select_inst(const char *name) 11271 { 11272 scf_instance_t *inst; 11273 scf_error_t err; 11274 11275 assert(cur_svc != NULL); 11276 11277 inst = scf_instance_create(g_hndl); 11278 if (inst == NULL) 11279 scfdie(); 11280 11281 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 11282 cur_inst = inst; 11283 return (0); 11284 } 11285 11286 err = scf_error(); 11287 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11288 scfdie(); 11289 11290 scf_instance_destroy(inst); 11291 return (1); 11292 } 11293 11294 /* Returns as above. */ 11295 static int 11296 select_svc(const char *name) 11297 { 11298 scf_service_t *svc; 11299 scf_error_t err; 11300 11301 assert(cur_scope != NULL); 11302 11303 svc = scf_service_create(g_hndl); 11304 if (svc == NULL) 11305 scfdie(); 11306 11307 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 11308 cur_svc = svc; 11309 return (0); 11310 } 11311 11312 err = scf_error(); 11313 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11314 scfdie(); 11315 11316 scf_service_destroy(svc); 11317 return (1); 11318 } 11319 11320 /* ARGSUSED */ 11321 static int 11322 select_callback(void *unused, scf_walkinfo_t *wip) 11323 { 11324 scf_instance_t *inst; 11325 scf_service_t *svc; 11326 scf_scope_t *scope; 11327 11328 if (wip->inst != NULL) { 11329 if ((scope = scf_scope_create(g_hndl)) == NULL || 11330 (svc = scf_service_create(g_hndl)) == NULL || 11331 (inst = scf_instance_create(g_hndl)) == NULL) 11332 scfdie(); 11333 11334 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11335 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11336 scfdie(); 11337 } else { 11338 assert(wip->svc != NULL); 11339 11340 if ((scope = scf_scope_create(g_hndl)) == NULL || 11341 (svc = scf_service_create(g_hndl)) == NULL) 11342 scfdie(); 11343 11344 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11345 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11346 scfdie(); 11347 11348 inst = NULL; 11349 } 11350 11351 /* Clear out the current selection */ 11352 assert(cur_scope != NULL); 11353 scf_scope_destroy(cur_scope); 11354 scf_service_destroy(cur_svc); 11355 scf_instance_destroy(cur_inst); 11356 11357 cur_scope = scope; 11358 cur_svc = svc; 11359 cur_inst = inst; 11360 11361 return (0); 11362 } 11363 11364 static int 11365 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 11366 { 11367 char **fmri = fmri_p; 11368 11369 *fmri = strdup(wip->fmri); 11370 if (*fmri == NULL) 11371 uu_die(gettext("Out of memory.\n")); 11372 11373 return (0); 11374 } 11375 11376 /* 11377 * validate [fmri] 11378 * Perform the validation of an FMRI instance. 11379 */ 11380 void 11381 lscf_validate_fmri(const char *fmri) 11382 { 11383 int ret = 0; 11384 size_t inst_sz; 11385 char *inst_fmri = NULL; 11386 scf_tmpl_errors_t *errs = NULL; 11387 char *snapbuf = NULL; 11388 11389 lscf_prep_hndl(); 11390 11391 if (fmri == NULL) { 11392 inst_sz = max_scf_fmri_len + 1; 11393 inst_fmri = safe_malloc(inst_sz); 11394 11395 if (cur_snap != NULL) { 11396 snapbuf = safe_malloc(max_scf_name_len + 1); 11397 if (scf_snapshot_get_name(cur_snap, snapbuf, 11398 max_scf_name_len + 1) < 0) 11399 scfdie(); 11400 } 11401 if (cur_inst == NULL) { 11402 semerr(gettext("No instance selected\n")); 11403 goto cleanup; 11404 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 11405 inst_sz) >= inst_sz) { 11406 /* sanity check. Should never get here */ 11407 uu_die(gettext("Unexpected error! file %s, line %d\n"), 11408 __FILE__, __LINE__); 11409 } 11410 } else { 11411 scf_error_t scf_err; 11412 int err = 0; 11413 11414 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 11415 validate_callback, &inst_fmri, &err, semerr)) != 0) { 11416 uu_warn("Failed to walk instances: %s\n", 11417 scf_strerror(scf_err)); 11418 goto cleanup; 11419 } 11420 if (err != 0) { 11421 /* error message displayed by scf_walk_fmri */ 11422 goto cleanup; 11423 } 11424 } 11425 11426 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 11427 SCF_TMPL_VALIDATE_FLAG_CURRENT); 11428 if (ret == -1) { 11429 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 11430 warn(gettext("Template data for %s is invalid. " 11431 "Consider reverting to a previous snapshot or " 11432 "restoring original configuration.\n"), inst_fmri); 11433 } else { 11434 uu_warn("%s: %s\n", 11435 gettext("Error validating the instance"), 11436 scf_strerror(scf_error())); 11437 } 11438 } else if (ret == 1 && errs != NULL) { 11439 scf_tmpl_error_t *err = NULL; 11440 char *msg; 11441 size_t len = 256; /* initial error buffer size */ 11442 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 11443 SCF_TMPL_STRERROR_HUMAN : 0; 11444 11445 msg = safe_malloc(len); 11446 11447 while ((err = scf_tmpl_next_error(errs)) != NULL) { 11448 int ret; 11449 11450 if ((ret = scf_tmpl_strerror(err, msg, len, 11451 flag)) >= len) { 11452 len = ret + 1; 11453 msg = realloc(msg, len); 11454 if (msg == NULL) 11455 uu_die(gettext( 11456 "Out of memory.\n")); 11457 (void) scf_tmpl_strerror(err, msg, len, 11458 flag); 11459 } 11460 (void) fprintf(stderr, "%s\n", msg); 11461 } 11462 if (msg != NULL) 11463 free(msg); 11464 } 11465 if (errs != NULL) 11466 scf_tmpl_errors_destroy(errs); 11467 11468 cleanup: 11469 free(inst_fmri); 11470 free(snapbuf); 11471 } 11472 11473 static void 11474 lscf_validate_file(const char *filename) 11475 { 11476 tmpl_errors_t *errs; 11477 11478 bundle_t *b = internal_bundle_new(); 11479 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 11480 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 11481 tmpl_errors_print(stderr, errs, ""); 11482 semerr(gettext("Validation failed.\n")); 11483 } 11484 tmpl_errors_destroy(errs); 11485 } 11486 (void) internal_bundle_free(b); 11487 } 11488 11489 /* 11490 * validate [fmri|file] 11491 */ 11492 void 11493 lscf_validate(const char *arg) 11494 { 11495 const char *str; 11496 11497 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 11498 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 11499 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 11500 lscf_validate_file(str); 11501 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 11502 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 11503 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 11504 lscf_validate_fmri(str); 11505 } else if (access(arg, R_OK | F_OK) == 0) { 11506 lscf_validate_file(arg); 11507 } else { 11508 lscf_validate_fmri(arg); 11509 } 11510 } 11511 11512 void 11513 lscf_select(const char *fmri) 11514 { 11515 int ret, err; 11516 11517 lscf_prep_hndl(); 11518 11519 if (cur_snap != NULL) { 11520 struct snaplevel *elt; 11521 char *buf; 11522 11523 /* Error unless name is that of the next level. */ 11524 elt = uu_list_next(cur_levels, cur_elt); 11525 if (elt == NULL) { 11526 semerr(gettext("No children.\n")); 11527 return; 11528 } 11529 11530 buf = safe_malloc(max_scf_name_len + 1); 11531 11532 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11533 max_scf_name_len + 1) < 0) 11534 scfdie(); 11535 11536 if (strcmp(buf, fmri) != 0) { 11537 semerr(gettext("No such child.\n")); 11538 free(buf); 11539 return; 11540 } 11541 11542 free(buf); 11543 11544 cur_elt = elt; 11545 cur_level = elt->sl; 11546 return; 11547 } 11548 11549 /* 11550 * Special case for 'svc:', which takes the user to the scope level. 11551 */ 11552 if (strcmp(fmri, "svc:") == 0) { 11553 scf_instance_destroy(cur_inst); 11554 scf_service_destroy(cur_svc); 11555 cur_inst = NULL; 11556 cur_svc = NULL; 11557 return; 11558 } 11559 11560 /* 11561 * Special case for ':properties'. This appears as part of 'list' but 11562 * can't be selected. Give a more helpful error message in this case. 11563 */ 11564 if (strcmp(fmri, ":properties") == 0) { 11565 semerr(gettext(":properties is not an entity. Try 'listprop' " 11566 "to list properties.\n")); 11567 return; 11568 } 11569 11570 /* 11571 * First try the argument as relative to the current selection. 11572 */ 11573 if (cur_inst != NULL) { 11574 /* EMPTY */; 11575 } else if (cur_svc != NULL) { 11576 if (select_inst(fmri) != 1) 11577 return; 11578 } else { 11579 if (select_svc(fmri) != 1) 11580 return; 11581 } 11582 11583 err = 0; 11584 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11585 select_callback, NULL, &err, semerr)) != 0) { 11586 semerr(gettext("Failed to walk instances: %s\n"), 11587 scf_strerror(ret)); 11588 } 11589 } 11590 11591 void 11592 lscf_unselect(void) 11593 { 11594 lscf_prep_hndl(); 11595 11596 if (cur_snap != NULL) { 11597 struct snaplevel *elt; 11598 11599 elt = uu_list_prev(cur_levels, cur_elt); 11600 if (elt == NULL) { 11601 semerr(gettext("No parent levels.\n")); 11602 } else { 11603 cur_elt = elt; 11604 cur_level = elt->sl; 11605 } 11606 } else if (cur_inst != NULL) { 11607 scf_instance_destroy(cur_inst); 11608 cur_inst = NULL; 11609 } else if (cur_svc != NULL) { 11610 scf_service_destroy(cur_svc); 11611 cur_svc = NULL; 11612 } else { 11613 semerr(gettext("Cannot unselect at scope level.\n")); 11614 } 11615 } 11616 11617 /* 11618 * Return the FMRI of the current selection, for the prompt. 11619 */ 11620 void 11621 lscf_get_selection_str(char *buf, size_t bufsz) 11622 { 11623 char *cp; 11624 ssize_t fmrilen, szret; 11625 boolean_t deleted = B_FALSE; 11626 11627 if (g_hndl == NULL) { 11628 (void) strlcpy(buf, "svc:", bufsz); 11629 return; 11630 } 11631 11632 if (cur_level != NULL) { 11633 assert(cur_snap != NULL); 11634 11635 /* [ snapshot ] FMRI [: instance ] */ 11636 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11637 + 2 + max_scf_name_len + 1 + 1); 11638 11639 buf[0] = '['; 11640 11641 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11642 max_scf_name_len + 1); 11643 if (szret < 0) { 11644 if (scf_error() != SCF_ERROR_DELETED) 11645 scfdie(); 11646 11647 goto snap_deleted; 11648 } 11649 11650 (void) strcat(buf, "]svc:/"); 11651 11652 cp = strchr(buf, '\0'); 11653 11654 szret = scf_snaplevel_get_service_name(cur_level, cp, 11655 max_scf_name_len + 1); 11656 if (szret < 0) { 11657 if (scf_error() != SCF_ERROR_DELETED) 11658 scfdie(); 11659 11660 goto snap_deleted; 11661 } 11662 11663 cp = strchr(cp, '\0'); 11664 11665 if (snaplevel_is_instance(cur_level)) { 11666 *cp++ = ':'; 11667 11668 if (scf_snaplevel_get_instance_name(cur_level, cp, 11669 max_scf_name_len + 1) < 0) { 11670 if (scf_error() != SCF_ERROR_DELETED) 11671 scfdie(); 11672 11673 goto snap_deleted; 11674 } 11675 } else { 11676 *cp++ = '['; 11677 *cp++ = ':'; 11678 11679 if (scf_instance_get_name(cur_inst, cp, 11680 max_scf_name_len + 1) < 0) { 11681 if (scf_error() != SCF_ERROR_DELETED) 11682 scfdie(); 11683 11684 goto snap_deleted; 11685 } 11686 11687 (void) strcat(buf, "]"); 11688 } 11689 11690 return; 11691 11692 snap_deleted: 11693 deleted = B_TRUE; 11694 free(buf); 11695 unselect_cursnap(); 11696 } 11697 11698 assert(cur_snap == NULL); 11699 11700 if (cur_inst != NULL) { 11701 assert(cur_svc != NULL); 11702 assert(cur_scope != NULL); 11703 11704 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11705 if (fmrilen >= 0) { 11706 assert(fmrilen < bufsz); 11707 if (deleted) 11708 warn(emsg_deleted); 11709 return; 11710 } 11711 11712 if (scf_error() != SCF_ERROR_DELETED) 11713 scfdie(); 11714 11715 deleted = B_TRUE; 11716 11717 scf_instance_destroy(cur_inst); 11718 cur_inst = NULL; 11719 } 11720 11721 if (cur_svc != NULL) { 11722 assert(cur_scope != NULL); 11723 11724 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11725 if (szret >= 0) { 11726 assert(szret < bufsz); 11727 if (deleted) 11728 warn(emsg_deleted); 11729 return; 11730 } 11731 11732 if (scf_error() != SCF_ERROR_DELETED) 11733 scfdie(); 11734 11735 deleted = B_TRUE; 11736 scf_service_destroy(cur_svc); 11737 cur_svc = NULL; 11738 } 11739 11740 assert(cur_scope != NULL); 11741 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11742 11743 if (fmrilen < 0) 11744 scfdie(); 11745 11746 assert(fmrilen < bufsz); 11747 if (deleted) 11748 warn(emsg_deleted); 11749 } 11750 11751 /* 11752 * Entity listing. Entities and colon namespaces (e.g., :properties and 11753 * :statistics) are listed for the current selection. 11754 */ 11755 void 11756 lscf_list(const char *pattern) 11757 { 11758 scf_iter_t *iter; 11759 char *buf; 11760 int ret; 11761 11762 lscf_prep_hndl(); 11763 11764 if (cur_level != NULL) { 11765 struct snaplevel *elt; 11766 11767 (void) fputs(COLON_NAMESPACES, stdout); 11768 11769 elt = uu_list_next(cur_levels, cur_elt); 11770 if (elt == NULL) 11771 return; 11772 11773 /* 11774 * For now, we know that the next level is an instance. But 11775 * if we ever have multiple scopes, this could be complicated. 11776 */ 11777 buf = safe_malloc(max_scf_name_len + 1); 11778 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11779 max_scf_name_len + 1) >= 0) { 11780 (void) puts(buf); 11781 } else { 11782 if (scf_error() != SCF_ERROR_DELETED) 11783 scfdie(); 11784 } 11785 11786 free(buf); 11787 11788 return; 11789 } 11790 11791 if (cur_inst != NULL) { 11792 (void) fputs(COLON_NAMESPACES, stdout); 11793 return; 11794 } 11795 11796 iter = scf_iter_create(g_hndl); 11797 if (iter == NULL) 11798 scfdie(); 11799 11800 buf = safe_malloc(max_scf_name_len + 1); 11801 11802 if (cur_svc != NULL) { 11803 /* List the instances in this service. */ 11804 scf_instance_t *inst; 11805 11806 inst = scf_instance_create(g_hndl); 11807 if (inst == NULL) 11808 scfdie(); 11809 11810 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11811 safe_printf(COLON_NAMESPACES); 11812 11813 for (;;) { 11814 ret = scf_iter_next_instance(iter, inst); 11815 if (ret == 0) 11816 break; 11817 if (ret != 1) { 11818 if (scf_error() != SCF_ERROR_DELETED) 11819 scfdie(); 11820 11821 break; 11822 } 11823 11824 if (scf_instance_get_name(inst, buf, 11825 max_scf_name_len + 1) >= 0) { 11826 if (pattern == NULL || 11827 fnmatch(pattern, buf, 0) == 0) 11828 (void) puts(buf); 11829 } else { 11830 if (scf_error() != SCF_ERROR_DELETED) 11831 scfdie(); 11832 } 11833 } 11834 } else { 11835 if (scf_error() != SCF_ERROR_DELETED) 11836 scfdie(); 11837 } 11838 11839 scf_instance_destroy(inst); 11840 } else { 11841 /* List the services in this scope. */ 11842 scf_service_t *svc; 11843 11844 assert(cur_scope != NULL); 11845 11846 svc = scf_service_create(g_hndl); 11847 if (svc == NULL) 11848 scfdie(); 11849 11850 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11851 scfdie(); 11852 11853 for (;;) { 11854 ret = scf_iter_next_service(iter, svc); 11855 if (ret == 0) 11856 break; 11857 if (ret != 1) 11858 scfdie(); 11859 11860 if (scf_service_get_name(svc, buf, 11861 max_scf_name_len + 1) >= 0) { 11862 if (pattern == NULL || 11863 fnmatch(pattern, buf, 0) == 0) 11864 safe_printf("%s\n", buf); 11865 } else { 11866 if (scf_error() != SCF_ERROR_DELETED) 11867 scfdie(); 11868 } 11869 } 11870 11871 scf_service_destroy(svc); 11872 } 11873 11874 free(buf); 11875 scf_iter_destroy(iter); 11876 } 11877 11878 /* 11879 * Entity addition. Creates an empty entity in the current selection. 11880 */ 11881 void 11882 lscf_add(const char *name) 11883 { 11884 lscf_prep_hndl(); 11885 11886 if (cur_snap != NULL) { 11887 semerr(emsg_cant_modify_snapshots); 11888 } else if (cur_inst != NULL) { 11889 semerr(gettext("Cannot add entities to an instance.\n")); 11890 } else if (cur_svc != NULL) { 11891 11892 if (scf_service_add_instance(cur_svc, name, NULL) != 11893 SCF_SUCCESS) { 11894 switch (scf_error()) { 11895 case SCF_ERROR_INVALID_ARGUMENT: 11896 semerr(gettext("Invalid name.\n")); 11897 break; 11898 11899 case SCF_ERROR_EXISTS: 11900 semerr(gettext("Instance already exists.\n")); 11901 break; 11902 11903 case SCF_ERROR_PERMISSION_DENIED: 11904 semerr(emsg_permission_denied); 11905 break; 11906 11907 default: 11908 scfdie(); 11909 } 11910 } 11911 } else { 11912 assert(cur_scope != NULL); 11913 11914 if (scf_scope_add_service(cur_scope, name, NULL) != 11915 SCF_SUCCESS) { 11916 switch (scf_error()) { 11917 case SCF_ERROR_INVALID_ARGUMENT: 11918 semerr(gettext("Invalid name.\n")); 11919 break; 11920 11921 case SCF_ERROR_EXISTS: 11922 semerr(gettext("Service already exists.\n")); 11923 break; 11924 11925 case SCF_ERROR_PERMISSION_DENIED: 11926 semerr(emsg_permission_denied); 11927 break; 11928 11929 case SCF_ERROR_BACKEND_READONLY: 11930 semerr(emsg_read_only); 11931 break; 11932 11933 default: 11934 scfdie(); 11935 } 11936 } 11937 } 11938 } 11939 11940 /* return 1 if the entity has no persistent pgs, else return 0 */ 11941 static int 11942 entity_has_no_pgs(void *ent, int isservice) 11943 { 11944 scf_iter_t *iter = NULL; 11945 scf_propertygroup_t *pg = NULL; 11946 uint32_t flags; 11947 int err; 11948 int ret = 1; 11949 11950 if ((iter = scf_iter_create(g_hndl)) == NULL || 11951 (pg = scf_pg_create(g_hndl)) == NULL) 11952 scfdie(); 11953 11954 if (isservice) { 11955 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11956 scfdie(); 11957 } else { 11958 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11959 scfdie(); 11960 } 11961 11962 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11963 if (scf_pg_get_flags(pg, &flags) != 0) 11964 scfdie(); 11965 11966 /* skip nonpersistent pgs */ 11967 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11968 continue; 11969 11970 ret = 0; 11971 break; 11972 } 11973 11974 if (err == -1) 11975 scfdie(); 11976 11977 scf_pg_destroy(pg); 11978 scf_iter_destroy(iter); 11979 11980 return (ret); 11981 } 11982 11983 /* return 1 if the service has no instances, else return 0 */ 11984 static int 11985 svc_has_no_insts(scf_service_t *svc) 11986 { 11987 scf_instance_t *inst; 11988 scf_iter_t *iter; 11989 int r; 11990 int ret = 1; 11991 11992 if ((inst = scf_instance_create(g_hndl)) == NULL || 11993 (iter = scf_iter_create(g_hndl)) == NULL) 11994 scfdie(); 11995 11996 if (scf_iter_service_instances(iter, svc) != 0) 11997 scfdie(); 11998 11999 r = scf_iter_next_instance(iter, inst); 12000 if (r == 1) { 12001 ret = 0; 12002 } else if (r == 0) { 12003 ret = 1; 12004 } else if (r == -1) { 12005 scfdie(); 12006 } else { 12007 bad_error("scf_iter_next_instance", r); 12008 } 12009 12010 scf_iter_destroy(iter); 12011 scf_instance_destroy(inst); 12012 12013 return (ret); 12014 } 12015 12016 /* 12017 * Entity deletion. 12018 */ 12019 12020 /* 12021 * Delete the property group <fmri>/:properties/<name>. Returns 12022 * SCF_ERROR_NONE on success (or if the entity is not found), 12023 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 12024 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 12025 * denied. 12026 */ 12027 static scf_error_t 12028 delete_dependency_pg(const char *fmri, const char *name) 12029 { 12030 void *entity = NULL; 12031 int isservice; 12032 scf_propertygroup_t *pg = NULL; 12033 scf_error_t result; 12034 char *pgty; 12035 scf_service_t *svc = NULL; 12036 scf_instance_t *inst = NULL; 12037 scf_iter_t *iter = NULL; 12038 char *name_buf = NULL; 12039 12040 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 12041 switch (result) { 12042 case SCF_ERROR_NONE: 12043 break; 12044 12045 case SCF_ERROR_NO_MEMORY: 12046 uu_die(gettext("Out of memory.\n")); 12047 /* NOTREACHED */ 12048 12049 case SCF_ERROR_INVALID_ARGUMENT: 12050 case SCF_ERROR_CONSTRAINT_VIOLATED: 12051 return (SCF_ERROR_INVALID_ARGUMENT); 12052 12053 case SCF_ERROR_NOT_FOUND: 12054 result = SCF_ERROR_NONE; 12055 goto out; 12056 12057 default: 12058 bad_error("fmri_to_entity", result); 12059 } 12060 12061 pg = scf_pg_create(g_hndl); 12062 if (pg == NULL) 12063 scfdie(); 12064 12065 if (entity_get_pg(entity, isservice, name, pg) != 0) { 12066 if (scf_error() != SCF_ERROR_NOT_FOUND) 12067 scfdie(); 12068 12069 result = SCF_ERROR_NONE; 12070 goto out; 12071 } 12072 12073 pgty = safe_malloc(max_scf_pg_type_len + 1); 12074 12075 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12076 scfdie(); 12077 12078 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 12079 result = SCF_ERROR_TYPE_MISMATCH; 12080 free(pgty); 12081 goto out; 12082 } 12083 12084 free(pgty); 12085 12086 if (scf_pg_delete(pg) != 0) { 12087 result = scf_error(); 12088 if (result != SCF_ERROR_PERMISSION_DENIED) 12089 scfdie(); 12090 goto out; 12091 } 12092 12093 /* 12094 * We have to handle the case where we've just deleted the last 12095 * property group of a "dummy" entity (instance or service). 12096 * A "dummy" entity is an entity only present to hold an 12097 * external dependency. 12098 * So, in the case we deleted the last property group then we 12099 * can also delete the entity. If the entity is an instance then 12100 * we must verify if this was the last instance for the service 12101 * and if it is, we can also delete the service if it doesn't 12102 * have any property group either. 12103 */ 12104 12105 result = SCF_ERROR_NONE; 12106 12107 if (isservice) { 12108 svc = (scf_service_t *)entity; 12109 12110 if ((inst = scf_instance_create(g_hndl)) == NULL || 12111 (iter = scf_iter_create(g_hndl)) == NULL) 12112 scfdie(); 12113 12114 name_buf = safe_malloc(max_scf_name_len + 1); 12115 } else { 12116 inst = (scf_instance_t *)entity; 12117 } 12118 12119 /* 12120 * If the entity is an instance and we've just deleted its last 12121 * property group then we should delete it. 12122 */ 12123 if (!isservice && entity_has_no_pgs(entity, isservice)) { 12124 /* find the service before deleting the inst. - needed later */ 12125 if ((svc = scf_service_create(g_hndl)) == NULL) 12126 scfdie(); 12127 12128 if (scf_instance_get_parent(inst, svc) != 0) 12129 scfdie(); 12130 12131 /* delete the instance */ 12132 if (scf_instance_delete(inst) != 0) { 12133 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12134 scfdie(); 12135 12136 result = SCF_ERROR_PERMISSION_DENIED; 12137 goto out; 12138 } 12139 /* no need to refresh the instance */ 12140 inst = NULL; 12141 } 12142 12143 /* 12144 * If the service has no more instances and pgs or we just deleted the 12145 * last instance and the service doesn't have anymore propery groups 12146 * then the service should be deleted. 12147 */ 12148 if (svc != NULL && 12149 svc_has_no_insts(svc) && 12150 entity_has_no_pgs((void *)svc, 1)) { 12151 if (scf_service_delete(svc) == 0) { 12152 if (isservice) { 12153 /* no need to refresh the service */ 12154 svc = NULL; 12155 } 12156 12157 goto out; 12158 } 12159 12160 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12161 scfdie(); 12162 12163 result = SCF_ERROR_PERMISSION_DENIED; 12164 } 12165 12166 /* if the entity has not been deleted, refresh it */ 12167 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 12168 (void) refresh_entity(isservice, entity, fmri, inst, iter, 12169 name_buf); 12170 } 12171 12172 out: 12173 if (isservice && (inst != NULL && iter != NULL)) { 12174 free(name_buf); 12175 scf_iter_destroy(iter); 12176 scf_instance_destroy(inst); 12177 } 12178 12179 if (!isservice && svc != NULL) { 12180 scf_service_destroy(svc); 12181 } 12182 12183 scf_pg_destroy(pg); 12184 if (entity != NULL) 12185 entity_destroy(entity, isservice); 12186 12187 return (result); 12188 } 12189 12190 static int 12191 delete_dependents(scf_propertygroup_t *pg) 12192 { 12193 char *pgty, *name, *fmri; 12194 scf_property_t *prop; 12195 scf_value_t *val; 12196 scf_iter_t *iter; 12197 int r; 12198 scf_error_t err; 12199 12200 /* Verify that the pg has the correct type. */ 12201 pgty = safe_malloc(max_scf_pg_type_len + 1); 12202 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12203 scfdie(); 12204 12205 if (strcmp(pgty, scf_group_framework) != 0) { 12206 if (g_verbose) { 12207 fmri = safe_malloc(max_scf_fmri_len + 1); 12208 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 12209 scfdie(); 12210 12211 warn(gettext("Property group %s is not of expected " 12212 "type %s.\n"), fmri, scf_group_framework); 12213 12214 free(fmri); 12215 } 12216 12217 free(pgty); 12218 return (-1); 12219 } 12220 12221 free(pgty); 12222 12223 /* map delete_dependency_pg onto the properties. */ 12224 if ((prop = scf_property_create(g_hndl)) == NULL || 12225 (val = scf_value_create(g_hndl)) == NULL || 12226 (iter = scf_iter_create(g_hndl)) == NULL) 12227 scfdie(); 12228 12229 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 12230 scfdie(); 12231 12232 name = safe_malloc(max_scf_name_len + 1); 12233 fmri = safe_malloc(max_scf_fmri_len + 2); 12234 12235 while ((r = scf_iter_next_property(iter, prop)) == 1) { 12236 scf_type_t ty; 12237 12238 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 12239 scfdie(); 12240 12241 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 12242 scfdie(); 12243 12244 if ((ty != SCF_TYPE_ASTRING && 12245 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 12246 prop_get_val(prop, val) != 0) 12247 continue; 12248 12249 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 12250 scfdie(); 12251 12252 err = delete_dependency_pg(fmri, name); 12253 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 12254 if (scf_property_to_fmri(prop, fmri, 12255 max_scf_fmri_len + 2) < 0) 12256 scfdie(); 12257 12258 warn(gettext("Value of %s is not a valid FMRI.\n"), 12259 fmri); 12260 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 12261 warn(gettext("Property group \"%s\" of entity \"%s\" " 12262 "does not have dependency type.\n"), name, fmri); 12263 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 12264 warn(gettext("Could not delete property group \"%s\" " 12265 "of entity \"%s\" (permission denied).\n"), name, 12266 fmri); 12267 } 12268 } 12269 if (r == -1) 12270 scfdie(); 12271 12272 scf_value_destroy(val); 12273 scf_property_destroy(prop); 12274 12275 return (0); 12276 } 12277 12278 /* 12279 * Returns 1 if the instance may be running, and 0 otherwise. 12280 */ 12281 static int 12282 inst_is_running(scf_instance_t *inst) 12283 { 12284 scf_propertygroup_t *pg; 12285 scf_property_t *prop; 12286 scf_value_t *val; 12287 char buf[MAX_SCF_STATE_STRING_SZ]; 12288 int ret = 0; 12289 ssize_t szret; 12290 12291 if ((pg = scf_pg_create(g_hndl)) == NULL || 12292 (prop = scf_property_create(g_hndl)) == NULL || 12293 (val = scf_value_create(g_hndl)) == NULL) 12294 scfdie(); 12295 12296 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 12297 if (scf_error() != SCF_ERROR_NOT_FOUND) 12298 scfdie(); 12299 goto out; 12300 } 12301 12302 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 12303 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 12304 prop_get_val(prop, val) != 0) 12305 goto out; 12306 12307 szret = scf_value_get_astring(val, buf, sizeof (buf)); 12308 assert(szret >= 0); 12309 12310 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 12311 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 12312 12313 out: 12314 scf_value_destroy(val); 12315 scf_property_destroy(prop); 12316 scf_pg_destroy(pg); 12317 return (ret); 12318 } 12319 12320 static uint8_t 12321 pg_is_external_dependency(scf_propertygroup_t *pg) 12322 { 12323 char *type; 12324 scf_value_t *val; 12325 scf_property_t *prop; 12326 uint8_t b = B_FALSE; 12327 12328 type = safe_malloc(max_scf_pg_type_len + 1); 12329 12330 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 12331 scfdie(); 12332 12333 if ((prop = scf_property_create(g_hndl)) == NULL || 12334 (val = scf_value_create(g_hndl)) == NULL) 12335 scfdie(); 12336 12337 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 12338 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 12339 if (scf_property_get_value(prop, val) != 0) 12340 scfdie(); 12341 if (scf_value_get_boolean(val, &b) != 0) 12342 scfdie(); 12343 } 12344 } 12345 12346 free(type); 12347 (void) scf_value_destroy(val); 12348 (void) scf_property_destroy(prop); 12349 12350 return (b); 12351 } 12352 12353 #define DELETE_FAILURE -1 12354 #define DELETE_SUCCESS_NOEXTDEPS 0 12355 #define DELETE_SUCCESS_EXTDEPS 1 12356 12357 /* 12358 * lscf_instance_delete() deletes an instance. Before calling 12359 * scf_instance_delete(), though, we make sure the instance isn't 12360 * running and delete dependencies in other entities which the instance 12361 * declared as "dependents". If there are dependencies which were 12362 * created for other entities, then instead of deleting the instance we 12363 * make it "empty" by deleting all other property groups and all 12364 * snapshots. 12365 * 12366 * lscf_instance_delete() verifies that there is no external dependency pgs 12367 * before suppressing the instance. If there is, then we must not remove them 12368 * now in case the instance is re-created otherwise the dependencies would be 12369 * lost. The external dependency pgs will be removed if the dependencies are 12370 * removed. 12371 * 12372 * Returns: 12373 * DELETE_FAILURE on failure 12374 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12375 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12376 */ 12377 static int 12378 lscf_instance_delete(scf_instance_t *inst, int force) 12379 { 12380 scf_propertygroup_t *pg; 12381 scf_snapshot_t *snap; 12382 scf_iter_t *iter; 12383 int err; 12384 int external = 0; 12385 12386 /* If we're not forcing and the instance is running, refuse. */ 12387 if (!force && inst_is_running(inst)) { 12388 char *fmri; 12389 12390 fmri = safe_malloc(max_scf_fmri_len + 1); 12391 12392 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 12393 scfdie(); 12394 12395 semerr(gettext("Instance %s may be running. " 12396 "Use delete -f if it is not.\n"), fmri); 12397 12398 free(fmri); 12399 return (DELETE_FAILURE); 12400 } 12401 12402 pg = scf_pg_create(g_hndl); 12403 if (pg == NULL) 12404 scfdie(); 12405 12406 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 12407 (void) delete_dependents(pg); 12408 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12409 scfdie(); 12410 12411 scf_pg_destroy(pg); 12412 12413 /* 12414 * If the instance has some external dependencies then we must 12415 * keep them in case the instance is reimported otherwise the 12416 * dependencies would be lost on reimport. 12417 */ 12418 if ((iter = scf_iter_create(g_hndl)) == NULL || 12419 (pg = scf_pg_create(g_hndl)) == NULL) 12420 scfdie(); 12421 12422 if (scf_iter_instance_pgs(iter, inst) < 0) 12423 scfdie(); 12424 12425 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 12426 if (pg_is_external_dependency(pg)) { 12427 external = 1; 12428 continue; 12429 } 12430 12431 if (scf_pg_delete(pg) != 0) { 12432 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12433 scfdie(); 12434 else { 12435 semerr(emsg_permission_denied); 12436 12437 (void) scf_iter_destroy(iter); 12438 (void) scf_pg_destroy(pg); 12439 return (DELETE_FAILURE); 12440 } 12441 } 12442 } 12443 12444 if (err == -1) 12445 scfdie(); 12446 12447 (void) scf_iter_destroy(iter); 12448 (void) scf_pg_destroy(pg); 12449 12450 if (external) { 12451 /* 12452 * All the pgs have been deleted for the instance except 12453 * the ones holding the external dependencies. 12454 * For the job to be complete, we must also delete the 12455 * snapshots associated with the instance. 12456 */ 12457 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 12458 NULL) 12459 scfdie(); 12460 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 12461 scfdie(); 12462 12463 if (scf_iter_instance_snapshots(iter, inst) == -1) 12464 scfdie(); 12465 12466 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 12467 if (_scf_snapshot_delete(snap) != 0) { 12468 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12469 scfdie(); 12470 12471 semerr(emsg_permission_denied); 12472 12473 (void) scf_iter_destroy(iter); 12474 (void) scf_snapshot_destroy(snap); 12475 return (DELETE_FAILURE); 12476 } 12477 } 12478 12479 if (err == -1) 12480 scfdie(); 12481 12482 (void) scf_iter_destroy(iter); 12483 (void) scf_snapshot_destroy(snap); 12484 return (DELETE_SUCCESS_EXTDEPS); 12485 } 12486 12487 if (scf_instance_delete(inst) != 0) { 12488 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12489 scfdie(); 12490 12491 semerr(emsg_permission_denied); 12492 12493 return (DELETE_FAILURE); 12494 } 12495 12496 return (DELETE_SUCCESS_NOEXTDEPS); 12497 } 12498 12499 /* 12500 * lscf_service_delete() deletes a service. Before calling 12501 * scf_service_delete(), though, we call lscf_instance_delete() for 12502 * each of the instances and delete dependencies in other entities 12503 * which were created as "dependents" of this service. If there are 12504 * dependencies which were created for other entities, then we delete 12505 * all other property groups in the service and leave it as "empty". 12506 * 12507 * lscf_service_delete() verifies that there is no external dependency 12508 * pgs at the instance & service level before suppressing the service. 12509 * If there is, then we must not remove them now in case the service 12510 * is re-imported otherwise the dependencies would be lost. The external 12511 * dependency pgs will be removed if the dependencies are removed. 12512 * 12513 * Returns: 12514 * DELETE_FAILURE on failure 12515 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12516 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12517 */ 12518 static int 12519 lscf_service_delete(scf_service_t *svc, int force) 12520 { 12521 int r; 12522 scf_instance_t *inst; 12523 scf_propertygroup_t *pg; 12524 scf_iter_t *iter; 12525 int ret; 12526 int external = 0; 12527 12528 if ((inst = scf_instance_create(g_hndl)) == NULL || 12529 (pg = scf_pg_create(g_hndl)) == NULL || 12530 (iter = scf_iter_create(g_hndl)) == NULL) 12531 scfdie(); 12532 12533 if (scf_iter_service_instances(iter, svc) != 0) 12534 scfdie(); 12535 12536 for (r = scf_iter_next_instance(iter, inst); 12537 r == 1; 12538 r = scf_iter_next_instance(iter, inst)) { 12539 12540 ret = lscf_instance_delete(inst, force); 12541 if (ret == DELETE_FAILURE) { 12542 scf_iter_destroy(iter); 12543 scf_pg_destroy(pg); 12544 scf_instance_destroy(inst); 12545 return (DELETE_FAILURE); 12546 } 12547 12548 /* 12549 * Record the fact that there is some external dependencies 12550 * at the instance level. 12551 */ 12552 if (ret == DELETE_SUCCESS_EXTDEPS) 12553 external |= 1; 12554 } 12555 12556 if (r != 0) 12557 scfdie(); 12558 12559 /* Delete dependency property groups in dependent services. */ 12560 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12561 (void) delete_dependents(pg); 12562 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12563 scfdie(); 12564 12565 scf_iter_destroy(iter); 12566 scf_pg_destroy(pg); 12567 scf_instance_destroy(inst); 12568 12569 /* 12570 * If the service has some external dependencies then we don't 12571 * want to remove them in case the service is re-imported. 12572 */ 12573 if ((pg = scf_pg_create(g_hndl)) == NULL || 12574 (iter = scf_iter_create(g_hndl)) == NULL) 12575 scfdie(); 12576 12577 if (scf_iter_service_pgs(iter, svc) < 0) 12578 scfdie(); 12579 12580 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12581 if (pg_is_external_dependency(pg)) { 12582 external |= 2; 12583 continue; 12584 } 12585 12586 if (scf_pg_delete(pg) != 0) { 12587 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12588 scfdie(); 12589 else { 12590 semerr(emsg_permission_denied); 12591 12592 (void) scf_iter_destroy(iter); 12593 (void) scf_pg_destroy(pg); 12594 return (DELETE_FAILURE); 12595 } 12596 } 12597 } 12598 12599 if (r == -1) 12600 scfdie(); 12601 12602 (void) scf_iter_destroy(iter); 12603 (void) scf_pg_destroy(pg); 12604 12605 if (external != 0) 12606 return (DELETE_SUCCESS_EXTDEPS); 12607 12608 if (scf_service_delete(svc) == 0) 12609 return (DELETE_SUCCESS_NOEXTDEPS); 12610 12611 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12612 scfdie(); 12613 12614 semerr(emsg_permission_denied); 12615 return (DELETE_FAILURE); 12616 } 12617 12618 static int 12619 delete_callback(void *data, scf_walkinfo_t *wip) 12620 { 12621 int force = (int)data; 12622 12623 if (wip->inst != NULL) 12624 (void) lscf_instance_delete(wip->inst, force); 12625 else 12626 (void) lscf_service_delete(wip->svc, force); 12627 12628 return (0); 12629 } 12630 12631 void 12632 lscf_delete(const char *fmri, int force) 12633 { 12634 scf_service_t *svc; 12635 scf_instance_t *inst; 12636 int ret; 12637 12638 lscf_prep_hndl(); 12639 12640 if (cur_snap != NULL) { 12641 if (!snaplevel_is_instance(cur_level)) { 12642 char *buf; 12643 12644 buf = safe_malloc(max_scf_name_len + 1); 12645 if (scf_instance_get_name(cur_inst, buf, 12646 max_scf_name_len + 1) >= 0) { 12647 if (strcmp(buf, fmri) == 0) { 12648 semerr(emsg_cant_modify_snapshots); 12649 free(buf); 12650 return; 12651 } 12652 } else if (scf_error() != SCF_ERROR_DELETED) { 12653 scfdie(); 12654 } 12655 free(buf); 12656 } 12657 } else if (cur_inst != NULL) { 12658 /* EMPTY */; 12659 } else if (cur_svc != NULL) { 12660 inst = scf_instance_create(g_hndl); 12661 if (inst == NULL) 12662 scfdie(); 12663 12664 if (scf_service_get_instance(cur_svc, fmri, inst) == 12665 SCF_SUCCESS) { 12666 (void) lscf_instance_delete(inst, force); 12667 scf_instance_destroy(inst); 12668 return; 12669 } 12670 12671 if (scf_error() != SCF_ERROR_NOT_FOUND && 12672 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12673 scfdie(); 12674 12675 scf_instance_destroy(inst); 12676 } else { 12677 assert(cur_scope != NULL); 12678 12679 svc = scf_service_create(g_hndl); 12680 if (svc == NULL) 12681 scfdie(); 12682 12683 if (scf_scope_get_service(cur_scope, fmri, svc) == 12684 SCF_SUCCESS) { 12685 (void) lscf_service_delete(svc, force); 12686 scf_service_destroy(svc); 12687 return; 12688 } 12689 12690 if (scf_error() != SCF_ERROR_NOT_FOUND && 12691 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12692 scfdie(); 12693 12694 scf_service_destroy(svc); 12695 } 12696 12697 /* 12698 * Match FMRI to entity. 12699 */ 12700 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12701 delete_callback, (void *)force, NULL, semerr)) != 0) { 12702 semerr(gettext("Failed to walk instances: %s\n"), 12703 scf_strerror(ret)); 12704 } 12705 } 12706 12707 12708 12709 /* 12710 * :properties commands. These all end with "pg" or "prop" and generally 12711 * operate on the currently selected entity. 12712 */ 12713 12714 /* 12715 * Property listing. List the property groups, properties, their types and 12716 * their values for the currently selected entity. 12717 */ 12718 static void 12719 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12720 { 12721 char *buf; 12722 uint32_t flags; 12723 12724 buf = safe_malloc(max_scf_pg_type_len + 1); 12725 12726 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12727 scfdie(); 12728 12729 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12730 scfdie(); 12731 12732 safe_printf("%-*s %s", namewidth, name, buf); 12733 12734 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12735 safe_printf("\tNONPERSISTENT"); 12736 12737 safe_printf("\n"); 12738 12739 free(buf); 12740 } 12741 12742 static boolean_t 12743 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12744 { 12745 if (scf_property_get_value(prop, val) == 0) { 12746 return (B_FALSE); 12747 } else { 12748 switch (scf_error()) { 12749 case SCF_ERROR_NOT_FOUND: 12750 return (B_FALSE); 12751 case SCF_ERROR_PERMISSION_DENIED: 12752 case SCF_ERROR_CONSTRAINT_VIOLATED: 12753 return (B_TRUE); 12754 default: 12755 scfdie(); 12756 /*NOTREACHED*/ 12757 } 12758 } 12759 } 12760 12761 static void 12762 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12763 { 12764 scf_iter_t *iter; 12765 scf_value_t *val; 12766 const char *type; 12767 int multiple_strings = 0; 12768 int ret; 12769 12770 if ((iter = scf_iter_create(g_hndl)) == NULL || 12771 (val = scf_value_create(g_hndl)) == NULL) 12772 scfdie(); 12773 12774 type = prop_to_typestr(prop); 12775 assert(type != NULL); 12776 12777 safe_printf("%-*s %-7s ", len, name, type); 12778 12779 if (prop_has_multiple_values(prop, val) && 12780 (scf_value_type(val) == SCF_TYPE_ASTRING || 12781 scf_value_type(val) == SCF_TYPE_USTRING)) 12782 multiple_strings = 1; 12783 12784 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12785 scfdie(); 12786 12787 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12788 char *buf; 12789 ssize_t vlen, szret; 12790 12791 vlen = scf_value_get_as_string(val, NULL, 0); 12792 if (vlen < 0) 12793 scfdie(); 12794 12795 buf = safe_malloc(vlen + 1); 12796 12797 szret = scf_value_get_as_string(val, buf, vlen + 1); 12798 if (szret < 0) 12799 scfdie(); 12800 assert(szret <= vlen); 12801 12802 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12803 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12804 safe_printf(" \""); 12805 (void) quote_and_print(buf, stdout, 0); 12806 (void) putchar('"'); 12807 if (ferror(stdout)) { 12808 (void) putchar('\n'); 12809 uu_die(gettext("Error writing to stdout.\n")); 12810 } 12811 } else { 12812 safe_printf(" %s", buf); 12813 } 12814 12815 free(buf); 12816 } 12817 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12818 scfdie(); 12819 12820 if (putchar('\n') != '\n') 12821 uu_die(gettext("Could not output newline")); 12822 } 12823 12824 /* 12825 * Outputs template property group info for the describe subcommand. 12826 * If 'templates' == 2, verbose output is printed in the format expected 12827 * for describe -v, which includes all templates fields. If pg is 12828 * not NULL, we're describing the template data, not an existing property 12829 * group, and formatting should be appropriate for describe -t. 12830 */ 12831 static void 12832 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12833 { 12834 char *buf; 12835 uint8_t required; 12836 scf_property_t *stability_prop; 12837 scf_value_t *stability_val; 12838 12839 if (templates == 0) 12840 return; 12841 12842 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12843 (stability_val = scf_value_create(g_hndl)) == NULL) 12844 scfdie(); 12845 12846 if (templates == 2 && pg != NULL) { 12847 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12848 stability_prop) == 0) { 12849 if (prop_check_type(stability_prop, 12850 SCF_TYPE_ASTRING) == 0 && 12851 prop_get_val(stability_prop, stability_val) == 0) { 12852 char *stability; 12853 12854 stability = safe_malloc(max_scf_value_len + 1); 12855 12856 if (scf_value_get_astring(stability_val, 12857 stability, max_scf_value_len + 1) == -1 && 12858 scf_error() != SCF_ERROR_NOT_FOUND) 12859 scfdie(); 12860 12861 safe_printf("%s%s: %s\n", TMPL_INDENT, 12862 gettext("stability"), stability); 12863 12864 free(stability); 12865 } 12866 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12867 scfdie(); 12868 } 12869 12870 scf_property_destroy(stability_prop); 12871 scf_value_destroy(stability_val); 12872 12873 if (pgt == NULL) 12874 return; 12875 12876 if (pg == NULL || templates == 2) { 12877 /* print type info only if scf_tmpl_pg_name succeeds */ 12878 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12879 if (pg != NULL) 12880 safe_printf("%s", TMPL_INDENT); 12881 safe_printf("%s: ", gettext("name")); 12882 safe_printf("%s\n", buf); 12883 free(buf); 12884 } 12885 12886 /* print type info only if scf_tmpl_pg_type succeeds */ 12887 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12888 if (pg != NULL) 12889 safe_printf("%s", TMPL_INDENT); 12890 safe_printf("%s: ", gettext("type")); 12891 safe_printf("%s\n", buf); 12892 free(buf); 12893 } 12894 } 12895 12896 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12897 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12898 required ? "true" : "false"); 12899 12900 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12901 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12902 buf); 12903 free(buf); 12904 } 12905 12906 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12907 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12908 buf); 12909 free(buf); 12910 } 12911 12912 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12913 if (templates == 2) 12914 safe_printf("%s%s: %s\n", TMPL_INDENT, 12915 gettext("description"), buf); 12916 else 12917 safe_printf("%s%s\n", TMPL_INDENT, buf); 12918 free(buf); 12919 } 12920 12921 } 12922 12923 /* 12924 * With as_value set to true, indent as appropriate for the value level. 12925 * If false, indent to appropriate level for inclusion in constraint 12926 * or choice printout. 12927 */ 12928 static void 12929 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12930 int as_value) 12931 { 12932 char *buf; 12933 12934 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12935 if (as_value == 0) 12936 safe_printf("%s", TMPL_CHOICE_INDENT); 12937 else 12938 safe_printf("%s", TMPL_INDENT); 12939 safe_printf("%s: %s\n", gettext("value common name"), buf); 12940 free(buf); 12941 } 12942 12943 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12944 if (as_value == 0) 12945 safe_printf("%s", TMPL_CHOICE_INDENT); 12946 else 12947 safe_printf("%s", TMPL_INDENT); 12948 safe_printf("%s: %s\n", gettext("value description"), buf); 12949 free(buf); 12950 } 12951 } 12952 12953 static void 12954 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12955 { 12956 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12957 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12958 safe_printf("%s\n", val_buf); 12959 12960 print_template_value_details(prt, val_buf, 1); 12961 } 12962 12963 static void 12964 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12965 { 12966 int i, printed = 0; 12967 scf_values_t values; 12968 scf_count_ranges_t c_ranges; 12969 scf_int_ranges_t i_ranges; 12970 12971 printed = 0; 12972 i = 0; 12973 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12974 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12975 gettext("value constraints")); 12976 printed++; 12977 for (i = 0; i < values.value_count; ++i) { 12978 safe_printf("%s%s: %s\n", TMPL_INDENT, 12979 gettext("value name"), values.values_as_strings[i]); 12980 if (verbose == 1) 12981 print_template_value_details(prt, 12982 values.values_as_strings[i], 0); 12983 } 12984 12985 scf_values_destroy(&values); 12986 } 12987 12988 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12989 if (printed++ == 0) 12990 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12991 gettext("value constraints")); 12992 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12993 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12994 gettext("range"), c_ranges.scr_min[i], 12995 c_ranges.scr_max[i]); 12996 } 12997 scf_count_ranges_destroy(&c_ranges); 12998 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12999 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 13000 if (printed++ == 0) 13001 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13002 gettext("value constraints")); 13003 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 13004 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 13005 gettext("range"), i_ranges.sir_min[i], 13006 i_ranges.sir_max[i]); 13007 } 13008 scf_int_ranges_destroy(&i_ranges); 13009 } 13010 } 13011 13012 static void 13013 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 13014 { 13015 int i = 0, printed = 0; 13016 scf_values_t values; 13017 scf_count_ranges_t c_ranges; 13018 scf_int_ranges_t i_ranges; 13019 13020 printed = 0; 13021 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 13022 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13023 gettext("value constraints")); 13024 printed++; 13025 for (i = 0; i < values.value_count; i++) { 13026 safe_printf("%s%s: %s\n", TMPL_INDENT, 13027 gettext("value name"), values.values_as_strings[i]); 13028 if (verbose == 1) 13029 print_template_value_details(prt, 13030 values.values_as_strings[i], 0); 13031 } 13032 13033 scf_values_destroy(&values); 13034 } 13035 13036 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 13037 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 13038 if (printed++ == 0) 13039 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13040 gettext("value choices")); 13041 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 13042 gettext("range"), c_ranges.scr_min[i], 13043 c_ranges.scr_max[i]); 13044 } 13045 scf_count_ranges_destroy(&c_ranges); 13046 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 13047 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 13048 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 13049 if (printed++ == 0) 13050 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13051 gettext("value choices")); 13052 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 13053 gettext("range"), i_ranges.sir_min[i], 13054 i_ranges.sir_max[i]); 13055 } 13056 scf_int_ranges_destroy(&i_ranges); 13057 } 13058 } 13059 13060 static void 13061 list_values_by_template(scf_prop_tmpl_t *prt) 13062 { 13063 print_template_constraints(prt, 1); 13064 print_template_choices(prt, 1); 13065 } 13066 13067 static void 13068 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 13069 { 13070 char *val_buf; 13071 scf_iter_t *iter; 13072 scf_value_t *val; 13073 int ret; 13074 13075 if ((iter = scf_iter_create(g_hndl)) == NULL || 13076 (val = scf_value_create(g_hndl)) == NULL) 13077 scfdie(); 13078 13079 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 13080 scfdie(); 13081 13082 val_buf = safe_malloc(max_scf_value_len + 1); 13083 13084 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13085 if (scf_value_get_as_string(val, val_buf, 13086 max_scf_value_len + 1) < 0) 13087 scfdie(); 13088 13089 print_template_value(prt, val_buf); 13090 } 13091 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 13092 scfdie(); 13093 free(val_buf); 13094 13095 print_template_constraints(prt, 0); 13096 print_template_choices(prt, 0); 13097 13098 } 13099 13100 /* 13101 * Outputs property info for the describe subcommand 13102 * Verbose output if templates == 2, -v option of svccfg describe 13103 * Displays template data if prop is not NULL, -t option of svccfg describe 13104 */ 13105 static void 13106 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 13107 { 13108 char *buf; 13109 uint8_t u_buf; 13110 int i; 13111 uint64_t min, max; 13112 scf_values_t values; 13113 13114 if (prt == NULL || templates == 0) 13115 return; 13116 13117 if (prop == NULL) { 13118 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 13119 if (scf_tmpl_prop_name(prt, &buf) > 0) { 13120 safe_printf("%s\n", buf); 13121 free(buf); 13122 } else 13123 safe_printf("(%s)\n", gettext("any")); 13124 } 13125 13126 if (prop == NULL || templates == 2) { 13127 if (prop != NULL) 13128 safe_printf("%s", TMPL_INDENT); 13129 else 13130 safe_printf("%s", TMPL_VALUE_INDENT); 13131 safe_printf("%s: ", gettext("type")); 13132 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 13133 safe_printf("%s\n", buf); 13134 free(buf); 13135 } else 13136 safe_printf("(%s)\n", gettext("any")); 13137 } 13138 13139 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 13140 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 13141 u_buf ? "true" : "false"); 13142 13143 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 13144 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 13145 buf); 13146 free(buf); 13147 } 13148 13149 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 13150 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 13151 buf); 13152 free(buf); 13153 } 13154 13155 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 13156 safe_printf("%s%s\n", TMPL_INDENT, buf); 13157 free(buf); 13158 } 13159 13160 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 13161 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 13162 scf_tmpl_visibility_to_string(u_buf)); 13163 13164 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 13165 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13166 gettext("minimum number of values"), min); 13167 if (max == ULLONG_MAX) { 13168 safe_printf("%s%s: %s\n", TMPL_INDENT, 13169 gettext("maximum number of values"), 13170 gettext("unlimited")); 13171 } else { 13172 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13173 gettext("maximum number of values"), max); 13174 } 13175 } 13176 13177 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 13178 for (i = 0; i < values.value_count; i++) { 13179 if (i == 0) { 13180 safe_printf("%s%s:", TMPL_INDENT, 13181 gettext("internal separators")); 13182 } 13183 safe_printf(" \"%s\"", values.values_as_strings[i]); 13184 } 13185 safe_printf("\n"); 13186 } 13187 13188 if (templates != 2) 13189 return; 13190 13191 if (prop != NULL) 13192 list_values_tmpl(prt, prop); 13193 else 13194 list_values_by_template(prt); 13195 } 13196 13197 static char * 13198 read_astring(scf_propertygroup_t *pg, const char *prop_name) 13199 { 13200 char *rv; 13201 13202 rv = _scf_read_single_astring_from_pg(pg, prop_name); 13203 if (rv == NULL) { 13204 switch (scf_error()) { 13205 case SCF_ERROR_NOT_FOUND: 13206 break; 13207 default: 13208 scfdie(); 13209 } 13210 } 13211 return (rv); 13212 } 13213 13214 static void 13215 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 13216 { 13217 size_t doc_len; 13218 size_t man_len; 13219 char *pg_name; 13220 char *text = NULL; 13221 int rv; 13222 13223 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 13224 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 13225 pg_name = safe_malloc(max_scf_name_len + 1); 13226 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 13227 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 13228 scfdie(); 13229 } 13230 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 13231 /* Display doc_link and and uri */ 13232 safe_printf("%s%s:\n", TMPL_INDENT, 13233 gettext("doc_link")); 13234 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 13235 if (text != NULL) { 13236 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13237 TMPL_INDENT, gettext("name"), text); 13238 uu_free(text); 13239 } 13240 text = read_astring(pg, SCF_PROPERTY_TM_URI); 13241 if (text != NULL) { 13242 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 13243 gettext("uri"), text); 13244 uu_free(text); 13245 } 13246 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 13247 man_len) == 0) { 13248 /* Display manpage title, section and path */ 13249 safe_printf("%s%s:\n", TMPL_INDENT, 13250 gettext("manpage")); 13251 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 13252 if (text != NULL) { 13253 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13254 TMPL_INDENT, gettext("title"), text); 13255 uu_free(text); 13256 } 13257 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 13258 if (text != NULL) { 13259 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13260 TMPL_INDENT, gettext("section"), text); 13261 uu_free(text); 13262 } 13263 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 13264 if (text != NULL) { 13265 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13266 TMPL_INDENT, gettext("manpath"), text); 13267 uu_free(text); 13268 } 13269 } 13270 } 13271 if (rv == -1) 13272 scfdie(); 13273 13274 free(pg_name); 13275 } 13276 13277 static void 13278 list_entity_tmpl(int templates) 13279 { 13280 char *common_name = NULL; 13281 char *description = NULL; 13282 char *locale = NULL; 13283 scf_iter_t *iter; 13284 scf_propertygroup_t *pg; 13285 scf_property_t *prop; 13286 int r; 13287 scf_value_t *val; 13288 13289 if ((pg = scf_pg_create(g_hndl)) == NULL || 13290 (prop = scf_property_create(g_hndl)) == NULL || 13291 (val = scf_value_create(g_hndl)) == NULL || 13292 (iter = scf_iter_create(g_hndl)) == NULL) 13293 scfdie(); 13294 13295 locale = setlocale(LC_MESSAGES, NULL); 13296 13297 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 13298 common_name = safe_malloc(max_scf_value_len + 1); 13299 13300 /* Try both the current locale and the "C" locale. */ 13301 if (scf_pg_get_property(pg, locale, prop) == 0 || 13302 (scf_error() == SCF_ERROR_NOT_FOUND && 13303 scf_pg_get_property(pg, "C", prop) == 0)) { 13304 if (prop_get_val(prop, val) == 0 && 13305 scf_value_get_ustring(val, common_name, 13306 max_scf_value_len + 1) != -1) { 13307 safe_printf("%s%s: %s\n", TMPL_INDENT, 13308 gettext("common name"), common_name); 13309 } 13310 } 13311 } 13312 13313 /* 13314 * Do description, manpages, and doc links if templates == 2. 13315 */ 13316 if (templates == 2) { 13317 /* Get the description. */ 13318 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 13319 description = safe_malloc(max_scf_value_len + 1); 13320 13321 /* Try both the current locale and the "C" locale. */ 13322 if (scf_pg_get_property(pg, locale, prop) == 0 || 13323 (scf_error() == SCF_ERROR_NOT_FOUND && 13324 scf_pg_get_property(pg, "C", prop) == 0)) { 13325 if (prop_get_val(prop, val) == 0 && 13326 scf_value_get_ustring(val, description, 13327 max_scf_value_len + 1) != -1) { 13328 safe_printf("%s%s: %s\n", TMPL_INDENT, 13329 gettext("description"), 13330 description); 13331 } 13332 } 13333 } 13334 13335 /* Process doc_link & manpage elements. */ 13336 if (cur_level != NULL) { 13337 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 13338 SCF_GROUP_TEMPLATE); 13339 } else if (cur_inst != NULL) { 13340 r = scf_iter_instance_pgs_typed(iter, cur_inst, 13341 SCF_GROUP_TEMPLATE); 13342 } else { 13343 r = scf_iter_service_pgs_typed(iter, cur_svc, 13344 SCF_GROUP_TEMPLATE); 13345 } 13346 if (r == 0) { 13347 display_documentation(iter, pg); 13348 } 13349 } 13350 13351 free(common_name); 13352 free(description); 13353 scf_pg_destroy(pg); 13354 scf_property_destroy(prop); 13355 scf_value_destroy(val); 13356 scf_iter_destroy(iter); 13357 } 13358 13359 static void 13360 listtmpl(const char *pattern, int templates) 13361 { 13362 scf_pg_tmpl_t *pgt; 13363 scf_prop_tmpl_t *prt; 13364 char *snapbuf = NULL; 13365 char *fmribuf; 13366 char *pg_name = NULL, *prop_name = NULL; 13367 ssize_t prop_name_size; 13368 char *qual_prop_name; 13369 char *search_name; 13370 int listed = 0; 13371 13372 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13373 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 13374 scfdie(); 13375 13376 fmribuf = safe_malloc(max_scf_name_len + 1); 13377 qual_prop_name = safe_malloc(max_scf_name_len + 1); 13378 13379 if (cur_snap != NULL) { 13380 snapbuf = safe_malloc(max_scf_name_len + 1); 13381 if (scf_snapshot_get_name(cur_snap, snapbuf, 13382 max_scf_name_len + 1) < 0) 13383 scfdie(); 13384 } 13385 13386 if (cur_inst != NULL) { 13387 if (scf_instance_to_fmri(cur_inst, fmribuf, 13388 max_scf_name_len + 1) < 0) 13389 scfdie(); 13390 } else if (cur_svc != NULL) { 13391 if (scf_service_to_fmri(cur_svc, fmribuf, 13392 max_scf_name_len + 1) < 0) 13393 scfdie(); 13394 } else 13395 abort(); 13396 13397 /* If pattern is specified, we want to list only those items. */ 13398 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) { 13399 listed = 0; 13400 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 13401 fnmatch(pattern, pg_name, 0) == 0)) { 13402 list_pg_tmpl(pgt, NULL, templates); 13403 listed++; 13404 } 13405 13406 scf_tmpl_prop_reset(prt); 13407 13408 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) { 13409 search_name = NULL; 13410 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 13411 if ((prop_name_size > 0) && (pg_name != NULL)) { 13412 if (snprintf(qual_prop_name, 13413 max_scf_name_len + 1, "%s/%s", 13414 pg_name, prop_name) >= 13415 max_scf_name_len + 1) { 13416 prop_name_size = -1; 13417 } else { 13418 search_name = qual_prop_name; 13419 } 13420 } 13421 if (listed > 0 || pattern == NULL || 13422 (prop_name_size > 0 && 13423 fnmatch(pattern, search_name, 13424 FNM_PATHNAME) == 0)) 13425 list_prop_tmpl(prt, NULL, templates); 13426 if (prop_name != NULL) { 13427 free(prop_name); 13428 prop_name = NULL; 13429 } 13430 } 13431 if (pg_name != NULL) { 13432 free(pg_name); 13433 pg_name = NULL; 13434 } 13435 } 13436 13437 scf_tmpl_prop_destroy(prt); 13438 scf_tmpl_pg_destroy(pgt); 13439 free(snapbuf); 13440 free(fmribuf); 13441 free(qual_prop_name); 13442 } 13443 13444 static void 13445 listprop(const char *pattern, int only_pgs, int templates) 13446 { 13447 scf_propertygroup_t *pg; 13448 scf_property_t *prop; 13449 scf_iter_t *iter, *piter; 13450 char *pgnbuf, *prnbuf, *ppnbuf; 13451 scf_pg_tmpl_t *pgt, *pgtp; 13452 scf_prop_tmpl_t *prt; 13453 13454 void **objects; 13455 char **names; 13456 void **tmpls; 13457 int allocd, i; 13458 13459 int ret; 13460 ssize_t pgnlen, prnlen, szret; 13461 size_t max_len = 0; 13462 13463 if (cur_svc == NULL && cur_inst == NULL) { 13464 semerr(emsg_entity_not_selected); 13465 return; 13466 } 13467 13468 if ((pg = scf_pg_create(g_hndl)) == NULL || 13469 (prop = scf_property_create(g_hndl)) == NULL || 13470 (iter = scf_iter_create(g_hndl)) == NULL || 13471 (piter = scf_iter_create(g_hndl)) == NULL || 13472 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13473 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 13474 scfdie(); 13475 13476 prnbuf = safe_malloc(max_scf_name_len + 1); 13477 13478 if (cur_level != NULL) 13479 ret = scf_iter_snaplevel_pgs(iter, cur_level); 13480 else if (cur_inst != NULL) 13481 ret = scf_iter_instance_pgs(iter, cur_inst); 13482 else 13483 ret = scf_iter_service_pgs(iter, cur_svc); 13484 if (ret != 0) { 13485 return; 13486 } 13487 13488 /* 13489 * We want to only list items which match pattern, and we want the 13490 * second column to line up, so during the first pass we'll save 13491 * matching items, their names, and their templates in objects, 13492 * names, and tmpls, computing the maximum name length as we go, 13493 * and then we'll print them out. 13494 * 13495 * Note: We always keep an extra slot available so the array can be 13496 * NULL-terminated. 13497 */ 13498 i = 0; 13499 allocd = 1; 13500 objects = safe_malloc(sizeof (*objects)); 13501 names = safe_malloc(sizeof (*names)); 13502 tmpls = safe_malloc(sizeof (*tmpls)); 13503 13504 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13505 int new_pg = 0; 13506 int print_props = 0; 13507 pgtp = NULL; 13508 13509 pgnlen = scf_pg_get_name(pg, NULL, 0); 13510 if (pgnlen < 0) 13511 scfdie(); 13512 13513 pgnbuf = safe_malloc(pgnlen + 1); 13514 13515 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 13516 if (szret < 0) 13517 scfdie(); 13518 assert(szret <= pgnlen); 13519 13520 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) { 13521 if (scf_error() != SCF_ERROR_NOT_FOUND) 13522 scfdie(); 13523 pgtp = NULL; 13524 } else { 13525 pgtp = pgt; 13526 } 13527 13528 if (pattern == NULL || 13529 fnmatch(pattern, pgnbuf, 0) == 0) { 13530 if (i+1 >= allocd) { 13531 allocd *= 2; 13532 objects = realloc(objects, 13533 sizeof (*objects) * allocd); 13534 names = 13535 realloc(names, sizeof (*names) * allocd); 13536 tmpls = realloc(tmpls, 13537 sizeof (*tmpls) * allocd); 13538 if (objects == NULL || names == NULL || 13539 tmpls == NULL) 13540 uu_die(gettext("Out of memory")); 13541 } 13542 objects[i] = pg; 13543 names[i] = pgnbuf; 13544 13545 if (pgtp == NULL) 13546 tmpls[i] = NULL; 13547 else 13548 tmpls[i] = pgt; 13549 13550 ++i; 13551 13552 if (pgnlen > max_len) 13553 max_len = pgnlen; 13554 13555 new_pg = 1; 13556 print_props = 1; 13557 } 13558 13559 if (only_pgs) { 13560 if (new_pg) { 13561 pg = scf_pg_create(g_hndl); 13562 if (pg == NULL) 13563 scfdie(); 13564 pgt = scf_tmpl_pg_create(g_hndl); 13565 if (pgt == NULL) 13566 scfdie(); 13567 } else 13568 free(pgnbuf); 13569 13570 continue; 13571 } 13572 13573 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13574 scfdie(); 13575 13576 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13577 prnlen = scf_property_get_name(prop, prnbuf, 13578 max_scf_name_len + 1); 13579 if (prnlen < 0) 13580 scfdie(); 13581 13582 /* Will prepend the property group name and a slash. */ 13583 prnlen += pgnlen + 1; 13584 13585 ppnbuf = safe_malloc(prnlen + 1); 13586 13587 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13588 prnbuf) < 0) 13589 uu_die("snprintf"); 13590 13591 if (pattern == NULL || print_props == 1 || 13592 fnmatch(pattern, ppnbuf, 0) == 0) { 13593 if (i+1 >= allocd) { 13594 allocd *= 2; 13595 objects = realloc(objects, 13596 sizeof (*objects) * allocd); 13597 names = realloc(names, 13598 sizeof (*names) * allocd); 13599 tmpls = realloc(tmpls, 13600 sizeof (*tmpls) * allocd); 13601 if (objects == NULL || names == NULL || 13602 tmpls == NULL) 13603 uu_die(gettext( 13604 "Out of memory")); 13605 } 13606 13607 objects[i] = prop; 13608 names[i] = ppnbuf; 13609 13610 if (pgtp != NULL) { 13611 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13612 prt, 0) < 0) { 13613 if (scf_error() != 13614 SCF_ERROR_NOT_FOUND) 13615 scfdie(); 13616 tmpls[i] = NULL; 13617 } else { 13618 tmpls[i] = prt; 13619 } 13620 } else { 13621 tmpls[i] = NULL; 13622 } 13623 13624 ++i; 13625 13626 if (prnlen > max_len) 13627 max_len = prnlen; 13628 13629 prop = scf_property_create(g_hndl); 13630 prt = scf_tmpl_prop_create(g_hndl); 13631 } else { 13632 free(ppnbuf); 13633 } 13634 } 13635 13636 if (new_pg) { 13637 pg = scf_pg_create(g_hndl); 13638 if (pg == NULL) 13639 scfdie(); 13640 pgt = scf_tmpl_pg_create(g_hndl); 13641 if (pgt == NULL) 13642 scfdie(); 13643 } else 13644 free(pgnbuf); 13645 } 13646 if (ret != 0) 13647 scfdie(); 13648 13649 objects[i] = NULL; 13650 13651 scf_pg_destroy(pg); 13652 scf_tmpl_pg_destroy(pgt); 13653 scf_property_destroy(prop); 13654 scf_tmpl_prop_destroy(prt); 13655 13656 for (i = 0; objects[i] != NULL; ++i) { 13657 if (strchr(names[i], '/') == NULL) { 13658 /* property group */ 13659 pg = (scf_propertygroup_t *)objects[i]; 13660 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13661 list_pg_info(pg, names[i], max_len); 13662 list_pg_tmpl(pgt, pg, templates); 13663 free(names[i]); 13664 scf_pg_destroy(pg); 13665 if (pgt != NULL) 13666 scf_tmpl_pg_destroy(pgt); 13667 } else { 13668 /* property */ 13669 prop = (scf_property_t *)objects[i]; 13670 prt = (scf_prop_tmpl_t *)tmpls[i]; 13671 list_prop_info(prop, names[i], max_len); 13672 list_prop_tmpl(prt, prop, templates); 13673 free(names[i]); 13674 scf_property_destroy(prop); 13675 if (prt != NULL) 13676 scf_tmpl_prop_destroy(prt); 13677 } 13678 } 13679 13680 free(names); 13681 free(objects); 13682 free(tmpls); 13683 } 13684 13685 void 13686 lscf_listpg(const char *pattern) 13687 { 13688 lscf_prep_hndl(); 13689 13690 listprop(pattern, 1, 0); 13691 } 13692 13693 /* 13694 * Property group and property creation, setting, and deletion. setprop (and 13695 * its alias, addprop) can either create a property group of a given type, or 13696 * it can create or set a property to a given type and list of values. 13697 */ 13698 void 13699 lscf_addpg(const char *name, const char *type, const char *flags) 13700 { 13701 scf_propertygroup_t *pg; 13702 int ret; 13703 uint32_t flgs = 0; 13704 const char *cp; 13705 13706 13707 lscf_prep_hndl(); 13708 13709 if (cur_snap != NULL) { 13710 semerr(emsg_cant_modify_snapshots); 13711 return; 13712 } 13713 13714 if (cur_inst == NULL && cur_svc == NULL) { 13715 semerr(emsg_entity_not_selected); 13716 return; 13717 } 13718 13719 if (flags != NULL) { 13720 for (cp = flags; *cp != '\0'; ++cp) { 13721 switch (*cp) { 13722 case 'P': 13723 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13724 break; 13725 13726 case 'p': 13727 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13728 break; 13729 13730 default: 13731 semerr(gettext("Invalid property group flag " 13732 "%c."), *cp); 13733 return; 13734 } 13735 } 13736 } 13737 13738 pg = scf_pg_create(g_hndl); 13739 if (pg == NULL) 13740 scfdie(); 13741 13742 if (cur_inst != NULL) 13743 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13744 else 13745 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13746 13747 if (ret != SCF_SUCCESS) { 13748 switch (scf_error()) { 13749 case SCF_ERROR_INVALID_ARGUMENT: 13750 semerr(gettext("Name, type, or flags are invalid.\n")); 13751 break; 13752 13753 case SCF_ERROR_EXISTS: 13754 semerr(gettext("Property group already exists.\n")); 13755 break; 13756 13757 case SCF_ERROR_PERMISSION_DENIED: 13758 semerr(emsg_permission_denied); 13759 break; 13760 13761 case SCF_ERROR_BACKEND_ACCESS: 13762 semerr(gettext("Backend refused access.\n")); 13763 break; 13764 13765 default: 13766 scfdie(); 13767 } 13768 } 13769 13770 scf_pg_destroy(pg); 13771 13772 private_refresh(); 13773 } 13774 13775 void 13776 lscf_delpg(char *name) 13777 { 13778 lscf_prep_hndl(); 13779 13780 if (cur_snap != NULL) { 13781 semerr(emsg_cant_modify_snapshots); 13782 return; 13783 } 13784 13785 if (cur_inst == NULL && cur_svc == NULL) { 13786 semerr(emsg_entity_not_selected); 13787 return; 13788 } 13789 13790 if (strchr(name, '/') != NULL) { 13791 semerr(emsg_invalid_pg_name, name); 13792 return; 13793 } 13794 13795 lscf_delprop(name); 13796 } 13797 13798 /* 13799 * scf_delhash() is used to remove the property group related to the 13800 * hash entry for a specific manifest in the repository. pgname will be 13801 * constructed from the location of the manifest file. If deathrow isn't 0, 13802 * manifest file doesn't need to exist (manifest string will be used as 13803 * an absolute path). 13804 */ 13805 void 13806 lscf_delhash(char *manifest, int deathrow) 13807 { 13808 char *pgname; 13809 13810 if (cur_snap != NULL || 13811 cur_inst != NULL || cur_svc != NULL) { 13812 warn(gettext("error, an entity is selected\n")); 13813 return; 13814 } 13815 13816 /* select smf/manifest */ 13817 lscf_select(HASH_SVC); 13818 /* 13819 * Translate the manifest file name to property name. In the deathrow 13820 * case, the manifest file does not need to exist. 13821 */ 13822 pgname = mhash_filename_to_propname(manifest, 13823 deathrow ? B_TRUE : B_FALSE); 13824 if (pgname == NULL) { 13825 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13826 return; 13827 } 13828 /* delete the hash property name */ 13829 lscf_delpg(pgname); 13830 } 13831 13832 void 13833 lscf_listprop(const char *pattern) 13834 { 13835 lscf_prep_hndl(); 13836 13837 listprop(pattern, 0, 0); 13838 } 13839 13840 int 13841 lscf_setprop(const char *pgname, const char *type, const char *value, 13842 const uu_list_t *values) 13843 { 13844 scf_type_t ty, current_ty; 13845 scf_service_t *svc; 13846 scf_propertygroup_t *pg, *parent_pg; 13847 scf_property_t *prop, *parent_prop; 13848 scf_pg_tmpl_t *pgt; 13849 scf_prop_tmpl_t *prt; 13850 int ret, result = 0; 13851 scf_transaction_t *tx; 13852 scf_transaction_entry_t *e; 13853 scf_value_t *v; 13854 uu_list_walk_t *walk; 13855 string_list_t *sp; 13856 char *propname; 13857 int req_quotes = 0; 13858 13859 lscf_prep_hndl(); 13860 13861 if ((e = scf_entry_create(g_hndl)) == NULL || 13862 (svc = scf_service_create(g_hndl)) == NULL || 13863 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13864 (pg = scf_pg_create(g_hndl)) == NULL || 13865 (parent_prop = scf_property_create(g_hndl)) == NULL || 13866 (prop = scf_property_create(g_hndl)) == NULL || 13867 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13868 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13869 (tx = scf_transaction_create(g_hndl)) == NULL) 13870 scfdie(); 13871 13872 if (cur_snap != NULL) { 13873 semerr(emsg_cant_modify_snapshots); 13874 goto fail; 13875 } 13876 13877 if (cur_inst == NULL && cur_svc == NULL) { 13878 semerr(emsg_entity_not_selected); 13879 goto fail; 13880 } 13881 13882 propname = strchr(pgname, '/'); 13883 if (propname == NULL) { 13884 semerr(gettext("Property names must contain a `/'.\n")); 13885 goto fail; 13886 } 13887 13888 *propname = '\0'; 13889 ++propname; 13890 13891 if (type != NULL) { 13892 ty = string_to_type(type); 13893 if (ty == SCF_TYPE_INVALID) { 13894 semerr(gettext("Unknown type \"%s\".\n"), type); 13895 goto fail; 13896 } 13897 } 13898 13899 if (cur_inst != NULL) 13900 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13901 else 13902 ret = scf_service_get_pg(cur_svc, pgname, pg); 13903 if (ret != SCF_SUCCESS) { 13904 switch (scf_error()) { 13905 case SCF_ERROR_NOT_FOUND: 13906 semerr(emsg_no_such_pg, pgname); 13907 goto fail; 13908 13909 case SCF_ERROR_INVALID_ARGUMENT: 13910 semerr(emsg_invalid_pg_name, pgname); 13911 goto fail; 13912 13913 default: 13914 scfdie(); 13915 break; 13916 } 13917 } 13918 13919 do { 13920 if (scf_pg_update(pg) == -1) 13921 scfdie(); 13922 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13923 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13924 scfdie(); 13925 13926 semerr(emsg_permission_denied); 13927 goto fail; 13928 } 13929 13930 ret = scf_pg_get_property(pg, propname, prop); 13931 if (ret == SCF_SUCCESS) { 13932 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13933 scfdie(); 13934 13935 if (type == NULL) 13936 ty = current_ty; 13937 if (scf_transaction_property_change_type(tx, e, 13938 propname, ty) == -1) 13939 scfdie(); 13940 13941 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13942 /* Infer the type, if possible. */ 13943 if (type == NULL) { 13944 /* 13945 * First check if we're an instance and the 13946 * property is set on the service. 13947 */ 13948 if (cur_inst != NULL && 13949 scf_instance_get_parent(cur_inst, 13950 svc) == 0 && 13951 scf_service_get_pg(cur_svc, pgname, 13952 parent_pg) == 0 && 13953 scf_pg_get_property(parent_pg, propname, 13954 parent_prop) == 0 && 13955 scf_property_type(parent_prop, 13956 ¤t_ty) == 0) { 13957 ty = current_ty; 13958 13959 /* Then check for a type set in a template. */ 13960 } else if (scf_tmpl_get_by_pg(pg, pgt, 13961 0) == 0 && 13962 scf_tmpl_get_by_prop(pgt, propname, prt, 13963 0) == 0 && 13964 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13965 ty = current_ty; 13966 13967 /* If type can't be inferred, fail. */ 13968 } else { 13969 semerr(gettext("Type required for new " 13970 "properties.\n")); 13971 goto fail; 13972 } 13973 } 13974 if (scf_transaction_property_new(tx, e, propname, 13975 ty) == -1) 13976 scfdie(); 13977 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13978 semerr(emsg_invalid_prop_name, propname); 13979 goto fail; 13980 } else { 13981 scfdie(); 13982 } 13983 13984 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13985 req_quotes = 1; 13986 13987 if (value != NULL) { 13988 v = string_to_value(value, ty, 0); 13989 13990 if (v == NULL) 13991 goto fail; 13992 13993 ret = scf_entry_add_value(e, v); 13994 assert(ret == SCF_SUCCESS); 13995 } else { 13996 assert(values != NULL); 13997 13998 walk = uu_list_walk_start((uu_list_t *)values, 13999 UU_DEFAULT); 14000 if (walk == NULL) 14001 uu_die(gettext("Could not walk list")); 14002 14003 for (sp = uu_list_walk_next(walk); sp != NULL; 14004 sp = uu_list_walk_next(walk)) { 14005 v = string_to_value(sp->str, ty, req_quotes); 14006 14007 if (v == NULL) { 14008 scf_entry_destroy_children(e); 14009 goto fail; 14010 } 14011 14012 ret = scf_entry_add_value(e, v); 14013 assert(ret == SCF_SUCCESS); 14014 } 14015 uu_list_walk_end(walk); 14016 } 14017 result = scf_transaction_commit(tx); 14018 14019 scf_transaction_reset(tx); 14020 scf_entry_destroy_children(e); 14021 } while (result == 0); 14022 14023 if (result < 0) { 14024 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14025 scfdie(); 14026 14027 semerr(emsg_permission_denied); 14028 goto fail; 14029 } 14030 14031 ret = 0; 14032 14033 private_refresh(); 14034 14035 goto cleanup; 14036 14037 fail: 14038 ret = -1; 14039 14040 cleanup: 14041 scf_transaction_destroy(tx); 14042 scf_entry_destroy(e); 14043 scf_service_destroy(svc); 14044 scf_pg_destroy(parent_pg); 14045 scf_pg_destroy(pg); 14046 scf_property_destroy(parent_prop); 14047 scf_property_destroy(prop); 14048 scf_tmpl_pg_destroy(pgt); 14049 scf_tmpl_prop_destroy(prt); 14050 14051 return (ret); 14052 } 14053 14054 void 14055 lscf_delprop(char *pgn) 14056 { 14057 char *slash, *pn; 14058 scf_propertygroup_t *pg; 14059 scf_transaction_t *tx; 14060 scf_transaction_entry_t *e; 14061 int ret; 14062 14063 14064 lscf_prep_hndl(); 14065 14066 if (cur_snap != NULL) { 14067 semerr(emsg_cant_modify_snapshots); 14068 return; 14069 } 14070 14071 if (cur_inst == NULL && cur_svc == NULL) { 14072 semerr(emsg_entity_not_selected); 14073 return; 14074 } 14075 14076 pg = scf_pg_create(g_hndl); 14077 if (pg == NULL) 14078 scfdie(); 14079 14080 slash = strchr(pgn, '/'); 14081 if (slash == NULL) { 14082 pn = NULL; 14083 } else { 14084 *slash = '\0'; 14085 pn = slash + 1; 14086 } 14087 14088 if (cur_inst != NULL) 14089 ret = scf_instance_get_pg(cur_inst, pgn, pg); 14090 else 14091 ret = scf_service_get_pg(cur_svc, pgn, pg); 14092 if (ret != SCF_SUCCESS) { 14093 switch (scf_error()) { 14094 case SCF_ERROR_NOT_FOUND: 14095 semerr(emsg_no_such_pg, pgn); 14096 break; 14097 14098 case SCF_ERROR_INVALID_ARGUMENT: 14099 semerr(emsg_invalid_pg_name, pgn); 14100 break; 14101 14102 default: 14103 scfdie(); 14104 } 14105 14106 scf_pg_destroy(pg); 14107 14108 return; 14109 } 14110 14111 if (pn == NULL) { 14112 /* Try to delete the property group. */ 14113 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14114 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14115 scfdie(); 14116 14117 semerr(emsg_permission_denied); 14118 } else { 14119 private_refresh(); 14120 } 14121 14122 scf_pg_destroy(pg); 14123 return; 14124 } 14125 14126 e = scf_entry_create(g_hndl); 14127 tx = scf_transaction_create(g_hndl); 14128 14129 do { 14130 if (scf_pg_update(pg) == -1) 14131 scfdie(); 14132 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 14133 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14134 scfdie(); 14135 14136 semerr(emsg_permission_denied); 14137 break; 14138 } 14139 14140 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 14141 if (scf_error() == SCF_ERROR_NOT_FOUND) { 14142 semerr(gettext("No such property %s/%s.\n"), 14143 pgn, pn); 14144 break; 14145 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14146 semerr(emsg_invalid_prop_name, pn); 14147 break; 14148 } else { 14149 scfdie(); 14150 } 14151 } 14152 14153 ret = scf_transaction_commit(tx); 14154 14155 if (ret == 0) 14156 scf_transaction_reset(tx); 14157 } while (ret == 0); 14158 14159 if (ret < 0) { 14160 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14161 scfdie(); 14162 14163 semerr(emsg_permission_denied); 14164 } else { 14165 private_refresh(); 14166 } 14167 14168 scf_transaction_destroy(tx); 14169 scf_entry_destroy(e); 14170 scf_pg_destroy(pg); 14171 } 14172 14173 /* 14174 * Property editing. 14175 */ 14176 14177 static int 14178 write_edit_script(FILE *strm) 14179 { 14180 char *fmribuf; 14181 ssize_t fmrilen; 14182 14183 scf_propertygroup_t *pg; 14184 scf_property_t *prop; 14185 scf_value_t *val; 14186 scf_type_t ty; 14187 int ret, result = 0; 14188 scf_iter_t *iter, *piter, *viter; 14189 char *buf, *tybuf, *pname; 14190 const char *emsg_write_error; 14191 14192 14193 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 14194 14195 14196 /* select fmri */ 14197 if (cur_inst != NULL) { 14198 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 14199 if (fmrilen < 0) 14200 scfdie(); 14201 fmribuf = safe_malloc(fmrilen + 1); 14202 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 14203 scfdie(); 14204 } else { 14205 assert(cur_svc != NULL); 14206 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 14207 if (fmrilen < 0) 14208 scfdie(); 14209 fmribuf = safe_malloc(fmrilen + 1); 14210 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 14211 scfdie(); 14212 } 14213 14214 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 14215 warn(emsg_write_error, strerror(errno)); 14216 free(fmribuf); 14217 return (-1); 14218 } 14219 14220 free(fmribuf); 14221 14222 14223 if ((pg = scf_pg_create(g_hndl)) == NULL || 14224 (prop = scf_property_create(g_hndl)) == NULL || 14225 (val = scf_value_create(g_hndl)) == NULL || 14226 (iter = scf_iter_create(g_hndl)) == NULL || 14227 (piter = scf_iter_create(g_hndl)) == NULL || 14228 (viter = scf_iter_create(g_hndl)) == NULL) 14229 scfdie(); 14230 14231 buf = safe_malloc(max_scf_name_len + 1); 14232 tybuf = safe_malloc(max_scf_pg_type_len + 1); 14233 pname = safe_malloc(max_scf_name_len + 1); 14234 14235 if (cur_inst != NULL) 14236 ret = scf_iter_instance_pgs(iter, cur_inst); 14237 else 14238 ret = scf_iter_service_pgs(iter, cur_svc); 14239 if (ret != SCF_SUCCESS) 14240 scfdie(); 14241 14242 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 14243 int ret2; 14244 14245 /* 14246 * # delprop pg 14247 * # addpg pg type 14248 */ 14249 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 14250 scfdie(); 14251 14252 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 14253 scfdie(); 14254 14255 if (fprintf(strm, "# Property group \"%s\"\n" 14256 "# delprop %s\n" 14257 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 14258 warn(emsg_write_error, strerror(errno)); 14259 result = -1; 14260 goto out; 14261 } 14262 14263 /* # setprop pg/prop = (values) */ 14264 14265 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 14266 scfdie(); 14267 14268 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 14269 int first = 1; 14270 int ret3; 14271 int multiple; 14272 int is_str; 14273 scf_type_t bty; 14274 14275 if (scf_property_get_name(prop, pname, 14276 max_scf_name_len + 1) < 0) 14277 scfdie(); 14278 14279 if (scf_property_type(prop, &ty) != 0) 14280 scfdie(); 14281 14282 multiple = prop_has_multiple_values(prop, val); 14283 14284 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 14285 pname, scf_type_to_string(ty), multiple ? "(" : "") 14286 < 0) { 14287 warn(emsg_write_error, strerror(errno)); 14288 result = -1; 14289 goto out; 14290 } 14291 14292 (void) scf_type_base_type(ty, &bty); 14293 is_str = (bty == SCF_TYPE_ASTRING); 14294 14295 if (scf_iter_property_values(viter, prop) != 14296 SCF_SUCCESS) 14297 scfdie(); 14298 14299 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 14300 char *buf; 14301 ssize_t buflen; 14302 14303 buflen = scf_value_get_as_string(val, NULL, 0); 14304 if (buflen < 0) 14305 scfdie(); 14306 14307 buf = safe_malloc(buflen + 1); 14308 14309 if (scf_value_get_as_string(val, buf, 14310 buflen + 1) < 0) 14311 scfdie(); 14312 14313 if (first) 14314 first = 0; 14315 else { 14316 if (putc(' ', strm) != ' ') { 14317 warn(emsg_write_error, 14318 strerror(errno)); 14319 result = -1; 14320 goto out; 14321 } 14322 } 14323 14324 if ((is_str && multiple) || 14325 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 14326 (void) putc('"', strm); 14327 (void) quote_and_print(buf, strm, 1); 14328 (void) putc('"', strm); 14329 14330 if (ferror(strm)) { 14331 warn(emsg_write_error, 14332 strerror(errno)); 14333 result = -1; 14334 goto out; 14335 } 14336 } else { 14337 if (fprintf(strm, "%s", buf) < 0) { 14338 warn(emsg_write_error, 14339 strerror(errno)); 14340 result = -1; 14341 goto out; 14342 } 14343 } 14344 14345 free(buf); 14346 } 14347 if (ret3 < 0 && 14348 scf_error() != SCF_ERROR_PERMISSION_DENIED) 14349 scfdie(); 14350 14351 /* Write closing paren if mult-value property */ 14352 if ((multiple && putc(')', strm) == EOF) || 14353 14354 /* Write final newline */ 14355 fputc('\n', strm) == EOF) { 14356 warn(emsg_write_error, strerror(errno)); 14357 result = -1; 14358 goto out; 14359 } 14360 } 14361 if (ret2 < 0) 14362 scfdie(); 14363 14364 if (fputc('\n', strm) == EOF) { 14365 warn(emsg_write_error, strerror(errno)); 14366 result = -1; 14367 goto out; 14368 } 14369 } 14370 if (ret < 0) 14371 scfdie(); 14372 14373 out: 14374 free(pname); 14375 free(tybuf); 14376 free(buf); 14377 scf_iter_destroy(viter); 14378 scf_iter_destroy(piter); 14379 scf_iter_destroy(iter); 14380 scf_value_destroy(val); 14381 scf_property_destroy(prop); 14382 scf_pg_destroy(pg); 14383 14384 if (result == 0) { 14385 if (fflush(strm) != 0) { 14386 warn(emsg_write_error, strerror(errno)); 14387 return (-1); 14388 } 14389 } 14390 14391 return (result); 14392 } 14393 14394 int 14395 lscf_editprop(void) 14396 { 14397 char *buf, *editor; 14398 size_t bufsz; 14399 int tmpfd; 14400 char tempname[] = TEMP_FILE_PATTERN; 14401 14402 lscf_prep_hndl(); 14403 14404 if (cur_snap != NULL) { 14405 semerr(emsg_cant_modify_snapshots); 14406 return (-1); 14407 } 14408 14409 if (cur_svc == NULL && cur_inst == NULL) { 14410 semerr(emsg_entity_not_selected); 14411 return (-1); 14412 } 14413 14414 tmpfd = mkstemp(tempname); 14415 if (tmpfd == -1) { 14416 semerr(gettext("Could not create temporary file.\n")); 14417 return (-1); 14418 } 14419 14420 (void) strcpy(tempfilename, tempname); 14421 14422 tempfile = fdopen(tmpfd, "r+"); 14423 if (tempfile == NULL) { 14424 warn(gettext("Could not create temporary file.\n")); 14425 if (close(tmpfd) == -1) 14426 warn(gettext("Could not close temporary file: %s.\n"), 14427 strerror(errno)); 14428 14429 remove_tempfile(); 14430 14431 return (-1); 14432 } 14433 14434 if (write_edit_script(tempfile) == -1) { 14435 remove_tempfile(); 14436 return (-1); 14437 } 14438 14439 editor = getenv("EDITOR"); 14440 if (editor == NULL) 14441 editor = "vi"; 14442 14443 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 14444 buf = safe_malloc(bufsz); 14445 14446 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 14447 uu_die(gettext("Error creating editor command")); 14448 14449 if (system(buf) == -1) { 14450 semerr(gettext("Could not launch editor %s: %s\n"), editor, 14451 strerror(errno)); 14452 free(buf); 14453 remove_tempfile(); 14454 return (-1); 14455 } 14456 14457 free(buf); 14458 14459 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 14460 14461 remove_tempfile(); 14462 14463 return (0); 14464 } 14465 14466 static void 14467 add_string(uu_list_t *strlist, const char *str) 14468 { 14469 string_list_t *elem; 14470 elem = safe_malloc(sizeof (*elem)); 14471 uu_list_node_init(elem, &elem->node, string_pool); 14472 elem->str = safe_strdup(str); 14473 if (uu_list_append(strlist, elem) != 0) 14474 uu_die(gettext("libuutil error: %s\n"), 14475 uu_strerror(uu_error())); 14476 } 14477 14478 static int 14479 remove_string(uu_list_t *strlist, const char *str) 14480 { 14481 uu_list_walk_t *elems; 14482 string_list_t *sp; 14483 14484 /* 14485 * Find the element that needs to be removed. 14486 */ 14487 elems = uu_list_walk_start(strlist, UU_DEFAULT); 14488 while ((sp = uu_list_walk_next(elems)) != NULL) { 14489 if (strcmp(sp->str, str) == 0) 14490 break; 14491 } 14492 uu_list_walk_end(elems); 14493 14494 /* 14495 * Returning 1 here as the value was not found, this 14496 * might not be an error. Leave it to the caller to 14497 * decide. 14498 */ 14499 if (sp == NULL) { 14500 return (1); 14501 } 14502 14503 uu_list_remove(strlist, sp); 14504 14505 free(sp->str); 14506 free(sp); 14507 14508 return (0); 14509 } 14510 14511 /* 14512 * Get all property values that don't match the given glob pattern, 14513 * if a pattern is specified. 14514 */ 14515 static void 14516 get_prop_values(scf_property_t *prop, uu_list_t *values, 14517 const char *pattern) 14518 { 14519 scf_iter_t *iter; 14520 scf_value_t *val; 14521 int ret; 14522 14523 if ((iter = scf_iter_create(g_hndl)) == NULL || 14524 (val = scf_value_create(g_hndl)) == NULL) 14525 scfdie(); 14526 14527 if (scf_iter_property_values(iter, prop) != 0) 14528 scfdie(); 14529 14530 while ((ret = scf_iter_next_value(iter, val)) == 1) { 14531 char *buf; 14532 ssize_t vlen, szret; 14533 14534 vlen = scf_value_get_as_string(val, NULL, 0); 14535 if (vlen < 0) 14536 scfdie(); 14537 14538 buf = safe_malloc(vlen + 1); 14539 14540 szret = scf_value_get_as_string(val, buf, vlen + 1); 14541 if (szret < 0) 14542 scfdie(); 14543 assert(szret <= vlen); 14544 14545 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 14546 add_string(values, buf); 14547 14548 free(buf); 14549 } 14550 14551 if (ret == -1) 14552 scfdie(); 14553 14554 scf_value_destroy(val); 14555 scf_iter_destroy(iter); 14556 } 14557 14558 static int 14559 lscf_setpropvalue(const char *pgname, const char *type, 14560 const char *arg, int isadd, int isnotfoundok) 14561 { 14562 scf_type_t ty; 14563 scf_propertygroup_t *pg; 14564 scf_property_t *prop; 14565 int ret, result = 0; 14566 scf_transaction_t *tx; 14567 scf_transaction_entry_t *e; 14568 scf_value_t *v; 14569 string_list_t *sp; 14570 char *propname; 14571 uu_list_t *values; 14572 uu_list_walk_t *walk; 14573 void *cookie = NULL; 14574 char *pattern = NULL; 14575 14576 lscf_prep_hndl(); 14577 14578 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14579 uu_die(gettext("Could not create property list: %s\n"), 14580 uu_strerror(uu_error())); 14581 14582 if (!isadd) 14583 pattern = safe_strdup(arg); 14584 14585 if ((e = scf_entry_create(g_hndl)) == NULL || 14586 (pg = scf_pg_create(g_hndl)) == NULL || 14587 (prop = scf_property_create(g_hndl)) == NULL || 14588 (tx = scf_transaction_create(g_hndl)) == NULL) 14589 scfdie(); 14590 14591 if (cur_snap != NULL) { 14592 semerr(emsg_cant_modify_snapshots); 14593 goto fail; 14594 } 14595 14596 if (cur_inst == NULL && cur_svc == NULL) { 14597 semerr(emsg_entity_not_selected); 14598 goto fail; 14599 } 14600 14601 propname = strchr(pgname, '/'); 14602 if (propname == NULL) { 14603 semerr(gettext("Property names must contain a `/'.\n")); 14604 goto fail; 14605 } 14606 14607 *propname = '\0'; 14608 ++propname; 14609 14610 if (type != NULL) { 14611 ty = string_to_type(type); 14612 if (ty == SCF_TYPE_INVALID) { 14613 semerr(gettext("Unknown type \"%s\".\n"), type); 14614 goto fail; 14615 } 14616 } 14617 14618 if (cur_inst != NULL) 14619 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14620 else 14621 ret = scf_service_get_pg(cur_svc, pgname, pg); 14622 if (ret != 0) { 14623 switch (scf_error()) { 14624 case SCF_ERROR_NOT_FOUND: 14625 if (isnotfoundok) { 14626 result = 0; 14627 } else { 14628 semerr(emsg_no_such_pg, pgname); 14629 result = -1; 14630 } 14631 goto out; 14632 14633 case SCF_ERROR_INVALID_ARGUMENT: 14634 semerr(emsg_invalid_pg_name, pgname); 14635 goto fail; 14636 14637 default: 14638 scfdie(); 14639 } 14640 } 14641 14642 do { 14643 if (scf_pg_update(pg) == -1) 14644 scfdie(); 14645 if (scf_transaction_start(tx, pg) != 0) { 14646 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14647 scfdie(); 14648 14649 semerr(emsg_permission_denied); 14650 goto fail; 14651 } 14652 14653 ret = scf_pg_get_property(pg, propname, prop); 14654 if (ret == 0) { 14655 scf_type_t ptype; 14656 char *pat = pattern; 14657 14658 if (scf_property_type(prop, &ptype) != 0) 14659 scfdie(); 14660 14661 if (isadd) { 14662 if (type != NULL && ptype != ty) { 14663 semerr(gettext("Property \"%s\" is not " 14664 "of type \"%s\".\n"), propname, 14665 type); 14666 goto fail; 14667 } 14668 14669 pat = NULL; 14670 } else { 14671 size_t len = strlen(pat); 14672 if (len > 0 && pat[len - 1] == '\"') 14673 pat[len - 1] = '\0'; 14674 if (len > 0 && pat[0] == '\"') 14675 pat++; 14676 } 14677 14678 ty = ptype; 14679 14680 get_prop_values(prop, values, pat); 14681 14682 if (isadd) 14683 add_string(values, arg); 14684 14685 if (scf_transaction_property_change(tx, e, 14686 propname, ty) == -1) 14687 scfdie(); 14688 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14689 if (isadd) { 14690 if (type == NULL) { 14691 semerr(gettext("Type required " 14692 "for new properties.\n")); 14693 goto fail; 14694 } 14695 14696 add_string(values, arg); 14697 14698 if (scf_transaction_property_new(tx, e, 14699 propname, ty) == -1) 14700 scfdie(); 14701 } else if (isnotfoundok) { 14702 result = 0; 14703 goto out; 14704 } else { 14705 semerr(gettext("No such property %s/%s.\n"), 14706 pgname, propname); 14707 result = -1; 14708 goto out; 14709 } 14710 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14711 semerr(emsg_invalid_prop_name, propname); 14712 goto fail; 14713 } else { 14714 scfdie(); 14715 } 14716 14717 walk = uu_list_walk_start(values, UU_DEFAULT); 14718 if (walk == NULL) 14719 uu_die(gettext("Could not walk property list.\n")); 14720 14721 for (sp = uu_list_walk_next(walk); sp != NULL; 14722 sp = uu_list_walk_next(walk)) { 14723 v = string_to_value(sp->str, ty, 0); 14724 14725 if (v == NULL) { 14726 scf_entry_destroy_children(e); 14727 goto fail; 14728 } 14729 ret = scf_entry_add_value(e, v); 14730 assert(ret == 0); 14731 } 14732 uu_list_walk_end(walk); 14733 14734 result = scf_transaction_commit(tx); 14735 14736 scf_transaction_reset(tx); 14737 scf_entry_destroy_children(e); 14738 } while (result == 0); 14739 14740 if (result < 0) { 14741 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14742 scfdie(); 14743 14744 semerr(emsg_permission_denied); 14745 goto fail; 14746 } 14747 14748 result = 0; 14749 14750 private_refresh(); 14751 14752 out: 14753 scf_transaction_destroy(tx); 14754 scf_entry_destroy(e); 14755 scf_pg_destroy(pg); 14756 scf_property_destroy(prop); 14757 free(pattern); 14758 14759 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14760 free(sp->str); 14761 free(sp); 14762 } 14763 14764 uu_list_destroy(values); 14765 14766 return (result); 14767 14768 fail: 14769 result = -1; 14770 goto out; 14771 } 14772 14773 int 14774 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14775 { 14776 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14777 } 14778 14779 int 14780 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14781 { 14782 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14783 } 14784 14785 /* 14786 * Look for a standard start method, first in the instance (if any), 14787 * then the service. 14788 */ 14789 static const char * 14790 start_method_name(int *in_instance) 14791 { 14792 scf_propertygroup_t *pg; 14793 char **p; 14794 int ret; 14795 scf_instance_t *inst = cur_inst; 14796 14797 if ((pg = scf_pg_create(g_hndl)) == NULL) 14798 scfdie(); 14799 14800 again: 14801 for (p = start_method_names; *p != NULL; p++) { 14802 if (inst != NULL) 14803 ret = scf_instance_get_pg(inst, *p, pg); 14804 else 14805 ret = scf_service_get_pg(cur_svc, *p, pg); 14806 14807 if (ret == 0) { 14808 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14809 char *buf = safe_malloc(bufsz); 14810 14811 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14812 free(buf); 14813 continue; 14814 } 14815 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14816 free(buf); 14817 continue; 14818 } 14819 14820 free(buf); 14821 *in_instance = (inst != NULL); 14822 scf_pg_destroy(pg); 14823 return (*p); 14824 } 14825 14826 if (scf_error() == SCF_ERROR_NOT_FOUND) 14827 continue; 14828 14829 scfdie(); 14830 } 14831 14832 if (inst != NULL) { 14833 inst = NULL; 14834 goto again; 14835 } 14836 14837 scf_pg_destroy(pg); 14838 return (NULL); 14839 } 14840 14841 static int 14842 addpg(const char *name, const char *type) 14843 { 14844 scf_propertygroup_t *pg; 14845 int ret; 14846 14847 pg = scf_pg_create(g_hndl); 14848 if (pg == NULL) 14849 scfdie(); 14850 14851 if (cur_inst != NULL) 14852 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14853 else 14854 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14855 14856 if (ret != 0) { 14857 switch (scf_error()) { 14858 case SCF_ERROR_EXISTS: 14859 ret = 0; 14860 break; 14861 14862 case SCF_ERROR_PERMISSION_DENIED: 14863 semerr(emsg_permission_denied); 14864 break; 14865 14866 default: 14867 scfdie(); 14868 } 14869 } 14870 14871 scf_pg_destroy(pg); 14872 return (ret); 14873 } 14874 14875 int 14876 lscf_setenv(uu_list_t *args, int isunset) 14877 { 14878 int ret = 0; 14879 size_t i; 14880 int argc; 14881 char **argv = NULL; 14882 string_list_t *slp; 14883 char *pattern; 14884 char *prop; 14885 int do_service = 0; 14886 int do_instance = 0; 14887 const char *method = NULL; 14888 const char *name = NULL; 14889 const char *value = NULL; 14890 scf_instance_t *saved_cur_inst = cur_inst; 14891 14892 lscf_prep_hndl(); 14893 14894 argc = uu_list_numnodes(args); 14895 if (argc < 1) 14896 goto usage; 14897 14898 argv = calloc(argc + 1, sizeof (char *)); 14899 if (argv == NULL) 14900 uu_die(gettext("Out of memory.\n")); 14901 14902 for (slp = uu_list_first(args), i = 0; 14903 slp != NULL; 14904 slp = uu_list_next(args, slp), ++i) 14905 argv[i] = slp->str; 14906 14907 argv[i] = NULL; 14908 14909 opterr = 0; 14910 optind = 0; 14911 for (;;) { 14912 ret = getopt(argc, argv, "sim:"); 14913 if (ret == -1) 14914 break; 14915 14916 switch (ret) { 14917 case 's': 14918 do_service = 1; 14919 cur_inst = NULL; 14920 break; 14921 14922 case 'i': 14923 do_instance = 1; 14924 break; 14925 14926 case 'm': 14927 method = optarg; 14928 break; 14929 14930 case '?': 14931 goto usage; 14932 14933 default: 14934 bad_error("getopt", ret); 14935 } 14936 } 14937 14938 argc -= optind; 14939 if ((do_service && do_instance) || 14940 (isunset && argc != 1) || 14941 (!isunset && argc != 2)) 14942 goto usage; 14943 14944 name = argv[optind]; 14945 if (!isunset) 14946 value = argv[optind + 1]; 14947 14948 if (cur_snap != NULL) { 14949 semerr(emsg_cant_modify_snapshots); 14950 ret = -1; 14951 goto out; 14952 } 14953 14954 if (cur_inst == NULL && cur_svc == NULL) { 14955 semerr(emsg_entity_not_selected); 14956 ret = -1; 14957 goto out; 14958 } 14959 14960 if (do_instance && cur_inst == NULL) { 14961 semerr(gettext("No instance is selected.\n")); 14962 ret = -1; 14963 goto out; 14964 } 14965 14966 if (do_service && cur_svc == NULL) { 14967 semerr(gettext("No service is selected.\n")); 14968 ret = -1; 14969 goto out; 14970 } 14971 14972 if (method == NULL) { 14973 if (do_instance || do_service) { 14974 method = "method_context"; 14975 if (!isunset) { 14976 ret = addpg("method_context", 14977 SCF_GROUP_FRAMEWORK); 14978 if (ret != 0) 14979 goto out; 14980 } 14981 } else { 14982 int in_instance; 14983 method = start_method_name(&in_instance); 14984 if (method == NULL) { 14985 semerr(gettext( 14986 "Couldn't find start method; please " 14987 "specify a method with '-m'.\n")); 14988 ret = -1; 14989 goto out; 14990 } 14991 if (!in_instance) 14992 cur_inst = NULL; 14993 } 14994 } else { 14995 scf_propertygroup_t *pg; 14996 size_t bufsz; 14997 char *buf; 14998 int ret; 14999 15000 if ((pg = scf_pg_create(g_hndl)) == NULL) 15001 scfdie(); 15002 15003 if (cur_inst != NULL) 15004 ret = scf_instance_get_pg(cur_inst, method, pg); 15005 else 15006 ret = scf_service_get_pg(cur_svc, method, pg); 15007 15008 if (ret != 0) { 15009 scf_pg_destroy(pg); 15010 switch (scf_error()) { 15011 case SCF_ERROR_NOT_FOUND: 15012 semerr(gettext("Couldn't find the method " 15013 "\"%s\".\n"), method); 15014 goto out; 15015 15016 case SCF_ERROR_INVALID_ARGUMENT: 15017 semerr(gettext("Invalid method name \"%s\".\n"), 15018 method); 15019 goto out; 15020 15021 default: 15022 scfdie(); 15023 } 15024 } 15025 15026 bufsz = strlen(SCF_GROUP_METHOD) + 1; 15027 buf = safe_malloc(bufsz); 15028 15029 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 15030 strcmp(buf, SCF_GROUP_METHOD) != 0) { 15031 semerr(gettext("Property group \"%s\" is not of type " 15032 "\"method\".\n"), method); 15033 ret = -1; 15034 free(buf); 15035 scf_pg_destroy(pg); 15036 goto out; 15037 } 15038 15039 free(buf); 15040 scf_pg_destroy(pg); 15041 } 15042 15043 prop = uu_msprintf("%s/environment", method); 15044 pattern = uu_msprintf("%s=*", name); 15045 15046 if (prop == NULL || pattern == NULL) 15047 uu_die(gettext("Out of memory.\n")); 15048 15049 ret = lscf_delpropvalue(prop, pattern, !isunset); 15050 15051 if (ret == 0 && !isunset) { 15052 uu_free(pattern); 15053 uu_free(prop); 15054 prop = uu_msprintf("%s/environment", method); 15055 pattern = uu_msprintf("%s=%s", name, value); 15056 if (prop == NULL || pattern == NULL) 15057 uu_die(gettext("Out of memory.\n")); 15058 ret = lscf_addpropvalue(prop, "astring:", pattern); 15059 } 15060 uu_free(pattern); 15061 uu_free(prop); 15062 15063 out: 15064 cur_inst = saved_cur_inst; 15065 15066 free(argv); 15067 return (ret); 15068 usage: 15069 ret = -2; 15070 goto out; 15071 } 15072 15073 /* 15074 * Snapshot commands 15075 */ 15076 15077 void 15078 lscf_listsnap() 15079 { 15080 scf_snapshot_t *snap; 15081 scf_iter_t *iter; 15082 char *nb; 15083 int r; 15084 15085 lscf_prep_hndl(); 15086 15087 if (cur_inst == NULL) { 15088 semerr(gettext("Instance not selected.\n")); 15089 return; 15090 } 15091 15092 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15093 (iter = scf_iter_create(g_hndl)) == NULL) 15094 scfdie(); 15095 15096 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 15097 scfdie(); 15098 15099 nb = safe_malloc(max_scf_name_len + 1); 15100 15101 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 15102 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 15103 scfdie(); 15104 15105 (void) puts(nb); 15106 } 15107 if (r < 0) 15108 scfdie(); 15109 15110 free(nb); 15111 scf_iter_destroy(iter); 15112 scf_snapshot_destroy(snap); 15113 } 15114 15115 void 15116 lscf_selectsnap(const char *name) 15117 { 15118 scf_snapshot_t *snap; 15119 scf_snaplevel_t *level; 15120 15121 lscf_prep_hndl(); 15122 15123 if (cur_inst == NULL) { 15124 semerr(gettext("Instance not selected.\n")); 15125 return; 15126 } 15127 15128 if (cur_snap != NULL) { 15129 if (name != NULL) { 15130 char *cur_snap_name; 15131 boolean_t nochange; 15132 15133 cur_snap_name = safe_malloc(max_scf_name_len + 1); 15134 15135 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 15136 max_scf_name_len + 1) < 0) 15137 scfdie(); 15138 15139 nochange = strcmp(name, cur_snap_name) == 0; 15140 15141 free(cur_snap_name); 15142 15143 if (nochange) 15144 return; 15145 } 15146 15147 unselect_cursnap(); 15148 } 15149 15150 if (name == NULL) 15151 return; 15152 15153 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15154 (level = scf_snaplevel_create(g_hndl)) == NULL) 15155 scfdie(); 15156 15157 if (scf_instance_get_snapshot(cur_inst, name, snap) != 15158 SCF_SUCCESS) { 15159 switch (scf_error()) { 15160 case SCF_ERROR_INVALID_ARGUMENT: 15161 semerr(gettext("Invalid name \"%s\".\n"), name); 15162 break; 15163 15164 case SCF_ERROR_NOT_FOUND: 15165 semerr(gettext("No such snapshot \"%s\".\n"), name); 15166 break; 15167 15168 default: 15169 scfdie(); 15170 } 15171 15172 scf_snaplevel_destroy(level); 15173 scf_snapshot_destroy(snap); 15174 return; 15175 } 15176 15177 /* Load the snaplevels into our list. */ 15178 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 15179 if (cur_levels == NULL) 15180 uu_die(gettext("Could not create list: %s\n"), 15181 uu_strerror(uu_error())); 15182 15183 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15184 if (scf_error() != SCF_ERROR_NOT_FOUND) 15185 scfdie(); 15186 15187 semerr(gettext("Snapshot has no snaplevels.\n")); 15188 15189 scf_snaplevel_destroy(level); 15190 scf_snapshot_destroy(snap); 15191 return; 15192 } 15193 15194 cur_snap = snap; 15195 15196 for (;;) { 15197 cur_elt = safe_malloc(sizeof (*cur_elt)); 15198 uu_list_node_init(cur_elt, &cur_elt->list_node, 15199 snaplevel_pool); 15200 cur_elt->sl = level; 15201 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 15202 uu_die(gettext("libuutil error: %s\n"), 15203 uu_strerror(uu_error())); 15204 15205 level = scf_snaplevel_create(g_hndl); 15206 if (level == NULL) 15207 scfdie(); 15208 15209 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 15210 level) != SCF_SUCCESS) { 15211 if (scf_error() != SCF_ERROR_NOT_FOUND) 15212 scfdie(); 15213 15214 scf_snaplevel_destroy(level); 15215 break; 15216 } 15217 } 15218 15219 cur_elt = uu_list_last(cur_levels); 15220 cur_level = cur_elt->sl; 15221 } 15222 15223 /* 15224 * Copies the properties & values in src to dst. Assumes src won't change. 15225 * Returns -1 if permission is denied, -2 if another transaction interrupts, 15226 * and 0 on success. 15227 * 15228 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 15229 * property, if it is copied and has type boolean. (See comment in 15230 * lscf_revert()). 15231 */ 15232 static int 15233 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 15234 uint8_t enabled) 15235 { 15236 scf_transaction_t *tx; 15237 scf_iter_t *iter, *viter; 15238 scf_property_t *prop; 15239 scf_value_t *v; 15240 char *nbuf; 15241 int r; 15242 15243 tx = scf_transaction_create(g_hndl); 15244 if (tx == NULL) 15245 scfdie(); 15246 15247 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 15248 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15249 scfdie(); 15250 15251 scf_transaction_destroy(tx); 15252 15253 return (-1); 15254 } 15255 15256 if ((iter = scf_iter_create(g_hndl)) == NULL || 15257 (prop = scf_property_create(g_hndl)) == NULL || 15258 (viter = scf_iter_create(g_hndl)) == NULL) 15259 scfdie(); 15260 15261 nbuf = safe_malloc(max_scf_name_len + 1); 15262 15263 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 15264 scfdie(); 15265 15266 for (;;) { 15267 scf_transaction_entry_t *e; 15268 scf_type_t ty; 15269 15270 r = scf_iter_next_property(iter, prop); 15271 if (r == -1) 15272 scfdie(); 15273 if (r == 0) 15274 break; 15275 15276 e = scf_entry_create(g_hndl); 15277 if (e == NULL) 15278 scfdie(); 15279 15280 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 15281 scfdie(); 15282 15283 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 15284 scfdie(); 15285 15286 if (scf_transaction_property_new(tx, e, nbuf, 15287 ty) != SCF_SUCCESS) 15288 scfdie(); 15289 15290 if ((enabled == 0 || enabled == 1) && 15291 strcmp(nbuf, scf_property_enabled) == 0 && 15292 ty == SCF_TYPE_BOOLEAN) { 15293 v = scf_value_create(g_hndl); 15294 if (v == NULL) 15295 scfdie(); 15296 15297 scf_value_set_boolean(v, enabled); 15298 15299 if (scf_entry_add_value(e, v) != 0) 15300 scfdie(); 15301 } else { 15302 if (scf_iter_property_values(viter, prop) != 0) 15303 scfdie(); 15304 15305 for (;;) { 15306 v = scf_value_create(g_hndl); 15307 if (v == NULL) 15308 scfdie(); 15309 15310 r = scf_iter_next_value(viter, v); 15311 if (r == -1) 15312 scfdie(); 15313 if (r == 0) { 15314 scf_value_destroy(v); 15315 break; 15316 } 15317 15318 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 15319 scfdie(); 15320 } 15321 } 15322 } 15323 15324 free(nbuf); 15325 scf_iter_destroy(viter); 15326 scf_property_destroy(prop); 15327 scf_iter_destroy(iter); 15328 15329 r = scf_transaction_commit(tx); 15330 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 15331 scfdie(); 15332 15333 scf_transaction_destroy_children(tx); 15334 scf_transaction_destroy(tx); 15335 15336 switch (r) { 15337 case 1: return (0); 15338 case 0: return (-2); 15339 case -1: return (-1); 15340 15341 default: 15342 abort(); 15343 } 15344 15345 /* NOTREACHED */ 15346 } 15347 15348 void 15349 lscf_revert(const char *snapname) 15350 { 15351 scf_snapshot_t *snap, *prev; 15352 scf_snaplevel_t *level, *nlevel; 15353 scf_iter_t *iter; 15354 scf_propertygroup_t *pg, *npg; 15355 scf_property_t *prop; 15356 scf_value_t *val; 15357 char *nbuf, *tbuf; 15358 uint8_t enabled; 15359 15360 lscf_prep_hndl(); 15361 15362 if (cur_inst == NULL) { 15363 semerr(gettext("Instance not selected.\n")); 15364 return; 15365 } 15366 15367 if (snapname != NULL) { 15368 snap = scf_snapshot_create(g_hndl); 15369 if (snap == NULL) 15370 scfdie(); 15371 15372 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 15373 SCF_SUCCESS) { 15374 switch (scf_error()) { 15375 case SCF_ERROR_INVALID_ARGUMENT: 15376 semerr(gettext("Invalid snapshot name " 15377 "\"%s\".\n"), snapname); 15378 break; 15379 15380 case SCF_ERROR_NOT_FOUND: 15381 semerr(gettext("No such snapshot.\n")); 15382 break; 15383 15384 default: 15385 scfdie(); 15386 } 15387 15388 scf_snapshot_destroy(snap); 15389 return; 15390 } 15391 } else { 15392 if (cur_snap != NULL) { 15393 snap = cur_snap; 15394 } else { 15395 semerr(gettext("No snapshot selected.\n")); 15396 return; 15397 } 15398 } 15399 15400 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 15401 (level = scf_snaplevel_create(g_hndl)) == NULL || 15402 (iter = scf_iter_create(g_hndl)) == NULL || 15403 (pg = scf_pg_create(g_hndl)) == NULL || 15404 (npg = scf_pg_create(g_hndl)) == NULL || 15405 (prop = scf_property_create(g_hndl)) == NULL || 15406 (val = scf_value_create(g_hndl)) == NULL) 15407 scfdie(); 15408 15409 nbuf = safe_malloc(max_scf_name_len + 1); 15410 tbuf = safe_malloc(max_scf_pg_type_len + 1); 15411 15412 /* Take the "previous" snapshot before we blow away the properties. */ 15413 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 15414 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 15415 scfdie(); 15416 } else { 15417 if (scf_error() != SCF_ERROR_NOT_FOUND) 15418 scfdie(); 15419 15420 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 15421 scfdie(); 15422 } 15423 15424 /* Save general/enabled, since we're probably going to replace it. */ 15425 enabled = 2; 15426 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 15427 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 15428 scf_property_get_value(prop, val) == 0) 15429 (void) scf_value_get_boolean(val, &enabled); 15430 15431 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15432 if (scf_error() != SCF_ERROR_NOT_FOUND) 15433 scfdie(); 15434 15435 goto out; 15436 } 15437 15438 for (;;) { 15439 boolean_t isinst; 15440 uint32_t flags; 15441 int r; 15442 15443 /* Clear the properties from the corresponding entity. */ 15444 isinst = snaplevel_is_instance(level); 15445 15446 if (!isinst) 15447 r = scf_iter_service_pgs(iter, cur_svc); 15448 else 15449 r = scf_iter_instance_pgs(iter, cur_inst); 15450 if (r != SCF_SUCCESS) 15451 scfdie(); 15452 15453 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15454 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15455 scfdie(); 15456 15457 /* Skip nonpersistent pgs. */ 15458 if (flags & SCF_PG_FLAG_NONPERSISTENT) 15459 continue; 15460 15461 if (scf_pg_delete(pg) != SCF_SUCCESS) { 15462 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15463 scfdie(); 15464 15465 semerr(emsg_permission_denied); 15466 goto out; 15467 } 15468 } 15469 if (r == -1) 15470 scfdie(); 15471 15472 /* Copy the properties to the corresponding entity. */ 15473 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 15474 scfdie(); 15475 15476 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15477 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 15478 scfdie(); 15479 15480 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 15481 0) 15482 scfdie(); 15483 15484 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15485 scfdie(); 15486 15487 if (!isinst) 15488 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 15489 flags, npg); 15490 else 15491 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 15492 flags, npg); 15493 if (r != SCF_SUCCESS) { 15494 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15495 scfdie(); 15496 15497 semerr(emsg_permission_denied); 15498 goto out; 15499 } 15500 15501 if ((enabled == 0 || enabled == 1) && 15502 strcmp(nbuf, scf_pg_general) == 0) 15503 r = pg_copy(pg, npg, enabled); 15504 else 15505 r = pg_copy(pg, npg, 2); 15506 15507 switch (r) { 15508 case 0: 15509 break; 15510 15511 case -1: 15512 semerr(emsg_permission_denied); 15513 goto out; 15514 15515 case -2: 15516 semerr(gettext( 15517 "Interrupted by another change.\n")); 15518 goto out; 15519 15520 default: 15521 abort(); 15522 } 15523 } 15524 if (r == -1) 15525 scfdie(); 15526 15527 /* Get next level. */ 15528 nlevel = scf_snaplevel_create(g_hndl); 15529 if (nlevel == NULL) 15530 scfdie(); 15531 15532 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 15533 SCF_SUCCESS) { 15534 if (scf_error() != SCF_ERROR_NOT_FOUND) 15535 scfdie(); 15536 15537 scf_snaplevel_destroy(nlevel); 15538 break; 15539 } 15540 15541 scf_snaplevel_destroy(level); 15542 level = nlevel; 15543 } 15544 15545 if (snapname == NULL) { 15546 lscf_selectsnap(NULL); 15547 snap = NULL; /* cur_snap has been destroyed */ 15548 } 15549 15550 out: 15551 free(tbuf); 15552 free(nbuf); 15553 scf_value_destroy(val); 15554 scf_property_destroy(prop); 15555 scf_pg_destroy(npg); 15556 scf_pg_destroy(pg); 15557 scf_iter_destroy(iter); 15558 scf_snaplevel_destroy(level); 15559 scf_snapshot_destroy(prev); 15560 if (snap != cur_snap) 15561 scf_snapshot_destroy(snap); 15562 } 15563 15564 void 15565 lscf_refresh(void) 15566 { 15567 ssize_t fmrilen; 15568 size_t bufsz; 15569 char *fmribuf; 15570 int r; 15571 15572 lscf_prep_hndl(); 15573 15574 if (cur_inst == NULL) { 15575 semerr(gettext("Instance not selected.\n")); 15576 return; 15577 } 15578 15579 bufsz = max_scf_fmri_len + 1; 15580 fmribuf = safe_malloc(bufsz); 15581 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15582 if (fmrilen < 0) { 15583 free(fmribuf); 15584 if (scf_error() != SCF_ERROR_DELETED) 15585 scfdie(); 15586 scf_instance_destroy(cur_inst); 15587 cur_inst = NULL; 15588 warn(emsg_deleted); 15589 return; 15590 } 15591 assert(fmrilen < bufsz); 15592 15593 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15594 switch (r) { 15595 case 0: 15596 break; 15597 15598 case ECONNABORTED: 15599 warn(gettext("Could not refresh %s " 15600 "(repository connection broken).\n"), fmribuf); 15601 break; 15602 15603 case ECANCELED: 15604 warn(emsg_deleted); 15605 break; 15606 15607 case EPERM: 15608 warn(gettext("Could not refresh %s " 15609 "(permission denied).\n"), fmribuf); 15610 break; 15611 15612 case ENOSPC: 15613 warn(gettext("Could not refresh %s " 15614 "(repository server out of resources).\n"), 15615 fmribuf); 15616 break; 15617 15618 case EACCES: 15619 default: 15620 bad_error("refresh_entity", scf_error()); 15621 } 15622 15623 free(fmribuf); 15624 } 15625 15626 /* 15627 * describe [-v] [-t] [pg/prop] 15628 */ 15629 int 15630 lscf_describe(uu_list_t *args, int hasargs) 15631 { 15632 int ret = 0; 15633 size_t i; 15634 int argc; 15635 char **argv = NULL; 15636 string_list_t *slp; 15637 int do_verbose = 0; 15638 int do_templates = 0; 15639 char *pattern = NULL; 15640 15641 lscf_prep_hndl(); 15642 15643 if (hasargs != 0) { 15644 argc = uu_list_numnodes(args); 15645 if (argc < 1) 15646 goto usage; 15647 15648 argv = calloc(argc + 1, sizeof (char *)); 15649 if (argv == NULL) 15650 uu_die(gettext("Out of memory.\n")); 15651 15652 for (slp = uu_list_first(args), i = 0; 15653 slp != NULL; 15654 slp = uu_list_next(args, slp), ++i) 15655 argv[i] = slp->str; 15656 15657 argv[i] = NULL; 15658 15659 /* 15660 * We start optind = 0 because our list of arguments 15661 * starts at argv[0] 15662 */ 15663 optind = 0; 15664 opterr = 0; 15665 for (;;) { 15666 ret = getopt(argc, argv, "vt"); 15667 if (ret == -1) 15668 break; 15669 15670 switch (ret) { 15671 case 'v': 15672 do_verbose = 1; 15673 break; 15674 15675 case 't': 15676 do_templates = 1; 15677 break; 15678 15679 case '?': 15680 goto usage; 15681 15682 default: 15683 bad_error("getopt", ret); 15684 } 15685 } 15686 15687 pattern = argv[optind]; 15688 } 15689 15690 if (cur_inst == NULL && cur_svc == NULL) { 15691 semerr(emsg_entity_not_selected); 15692 ret = -1; 15693 goto out; 15694 } 15695 15696 /* 15697 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15698 * output if their last parameter is set to 2. Less information is 15699 * produced if the parameter is set to 1. 15700 */ 15701 if (pattern == NULL) { 15702 if (do_verbose == 1) 15703 list_entity_tmpl(2); 15704 else 15705 list_entity_tmpl(1); 15706 } 15707 15708 if (do_templates == 0) { 15709 if (do_verbose == 1) 15710 listprop(pattern, 0, 2); 15711 else 15712 listprop(pattern, 0, 1); 15713 } else { 15714 if (do_verbose == 1) 15715 listtmpl(pattern, 2); 15716 else 15717 listtmpl(pattern, 1); 15718 } 15719 15720 ret = 0; 15721 out: 15722 if (argv != NULL) 15723 free(argv); 15724 return (ret); 15725 usage: 15726 ret = -2; 15727 goto out; 15728 } 15729 15730 #define PARAM_ACTIVE ((const char *) "active") 15731 #define PARAM_INACTIVE ((const char *) "inactive") 15732 #define PARAM_SMTP_TO ((const char *) "to") 15733 15734 /* 15735 * tokenize() 15736 * Breaks down the string according to the tokens passed. 15737 * Caller is responsible for freeing array of pointers returned. 15738 * Returns NULL on failure 15739 */ 15740 char ** 15741 tokenize(char *str, const char *sep) 15742 { 15743 char *token, *lasts; 15744 char **buf; 15745 int n = 0; /* number of elements */ 15746 int size = 8; /* size of the array (initial) */ 15747 15748 buf = safe_malloc(size * sizeof (char *)); 15749 15750 for (token = strtok_r(str, sep, &lasts); token != NULL; 15751 token = strtok_r(NULL, sep, &lasts), ++n) { 15752 if (n + 1 >= size) { 15753 size *= 2; 15754 if ((buf = realloc(buf, size * sizeof (char *))) == 15755 NULL) { 15756 uu_die(gettext("Out of memory")); 15757 } 15758 } 15759 buf[n] = token; 15760 } 15761 /* NULL terminate the pointer array */ 15762 buf[n] = NULL; 15763 15764 return (buf); 15765 } 15766 15767 int32_t 15768 check_tokens(char **p) 15769 { 15770 int32_t smf = 0; 15771 int32_t fma = 0; 15772 15773 while (*p) { 15774 int32_t t = string_to_tset(*p); 15775 15776 if (t == 0) { 15777 if (is_fma_token(*p) == 0) 15778 return (INVALID_TOKENS); 15779 fma = 1; /* this token is an fma event */ 15780 } else { 15781 smf |= t; 15782 } 15783 15784 if (smf != 0 && fma == 1) 15785 return (MIXED_TOKENS); 15786 ++p; 15787 } 15788 15789 if (smf > 0) 15790 return (smf); 15791 else if (fma == 1) 15792 return (FMA_TOKENS); 15793 15794 return (INVALID_TOKENS); 15795 } 15796 15797 static int 15798 get_selection_str(char *fmri, size_t sz) 15799 { 15800 if (g_hndl == NULL) { 15801 semerr(emsg_entity_not_selected); 15802 return (-1); 15803 } else if (cur_level != NULL) { 15804 semerr(emsg_invalid_for_snapshot); 15805 return (-1); 15806 } else { 15807 lscf_get_selection_str(fmri, sz); 15808 } 15809 15810 return (0); 15811 } 15812 15813 void 15814 lscf_delnotify(const char *set, int global) 15815 { 15816 char *str = strdup(set); 15817 char **pgs; 15818 char **p; 15819 int32_t tset; 15820 char *fmri = NULL; 15821 15822 if (str == NULL) 15823 uu_die(gettext("Out of memory.\n")); 15824 15825 pgs = tokenize(str, ","); 15826 15827 if ((tset = check_tokens(pgs)) > 0) { 15828 size_t sz = max_scf_fmri_len + 1; 15829 15830 fmri = safe_malloc(sz); 15831 if (global) { 15832 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15833 } else if (get_selection_str(fmri, sz) != 0) { 15834 goto out; 15835 } 15836 15837 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri, 15838 tset) != SCF_SUCCESS) { 15839 uu_warn(gettext("Failed smf_notify_del_params: %s\n"), 15840 scf_strerror(scf_error())); 15841 } 15842 } else if (tset == FMA_TOKENS) { 15843 if (global) { 15844 semerr(gettext("Can't use option '-g' with FMA event " 15845 "definitions\n")); 15846 goto out; 15847 } 15848 15849 for (p = pgs; *p; ++p) { 15850 if (smf_notify_del_params(de_tag(*p), NULL, 0) != 15851 SCF_SUCCESS) { 15852 uu_warn(gettext("Failed for \"%s\": %s\n"), *p, 15853 scf_strerror(scf_error())); 15854 goto out; 15855 } 15856 } 15857 } else if (tset == MIXED_TOKENS) { 15858 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15859 goto out; 15860 } else { 15861 uu_die(gettext("Invalid input.\n")); 15862 } 15863 15864 out: 15865 free(fmri); 15866 free(pgs); 15867 free(str); 15868 } 15869 15870 void 15871 lscf_listnotify(const char *set, int global) 15872 { 15873 char *str = safe_strdup(set); 15874 char **pgs; 15875 char **p; 15876 int32_t tset; 15877 nvlist_t *nvl; 15878 char *fmri = NULL; 15879 15880 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 15881 uu_die(gettext("Out of memory.\n")); 15882 15883 pgs = tokenize(str, ","); 15884 15885 if ((tset = check_tokens(pgs)) > 0) { 15886 size_t sz = max_scf_fmri_len + 1; 15887 15888 fmri = safe_malloc(sz); 15889 if (global) { 15890 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15891 } else if (get_selection_str(fmri, sz) != 0) { 15892 goto out; 15893 } 15894 15895 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) != 15896 SCF_SUCCESS) { 15897 if (scf_error() != SCF_ERROR_NOT_FOUND && 15898 scf_error() != SCF_ERROR_DELETED) 15899 uu_warn(gettext( 15900 "Failed listnotify: %s\n"), 15901 scf_strerror(scf_error())); 15902 goto out; 15903 } 15904 15905 listnotify_print(nvl, NULL); 15906 } else if (tset == FMA_TOKENS) { 15907 if (global) { 15908 semerr(gettext("Can't use option '-g' with FMA event " 15909 "definitions\n")); 15910 goto out; 15911 } 15912 15913 for (p = pgs; *p; ++p) { 15914 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) != 15915 SCF_SUCCESS) { 15916 /* 15917 * if the preferences have just been deleted 15918 * or does not exist, just skip. 15919 */ 15920 if (scf_error() == SCF_ERROR_NOT_FOUND || 15921 scf_error() == SCF_ERROR_DELETED) 15922 continue; 15923 uu_warn(gettext( 15924 "Failed listnotify: %s\n"), 15925 scf_strerror(scf_error())); 15926 goto out; 15927 } 15928 listnotify_print(nvl, re_tag(*p)); 15929 } 15930 } else if (tset == MIXED_TOKENS) { 15931 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15932 goto out; 15933 } else { 15934 semerr(gettext("Invalid input.\n")); 15935 } 15936 15937 out: 15938 nvlist_free(nvl); 15939 free(fmri); 15940 free(pgs); 15941 free(str); 15942 } 15943 15944 static char * 15945 strip_quotes_and_blanks(char *s) 15946 { 15947 char *start = s; 15948 char *end = strrchr(s, '\"'); 15949 15950 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') { 15951 start = s + 1; 15952 while (isblank(*start)) 15953 start++; 15954 while (isblank(*(end - 1)) && end > start) { 15955 end--; 15956 } 15957 *end = '\0'; 15958 } 15959 15960 return (start); 15961 } 15962 15963 static int 15964 set_active(nvlist_t *mech, const char *hier_part) 15965 { 15966 boolean_t b; 15967 15968 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) { 15969 b = B_TRUE; 15970 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) { 15971 b = B_FALSE; 15972 } else { 15973 return (-1); 15974 } 15975 15976 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0) 15977 uu_die(gettext("Out of memory.\n")); 15978 15979 return (0); 15980 } 15981 15982 static int 15983 add_snmp_params(nvlist_t *mech, char *hier_part) 15984 { 15985 return (set_active(mech, hier_part)); 15986 } 15987 15988 static int 15989 add_syslog_params(nvlist_t *mech, char *hier_part) 15990 { 15991 return (set_active(mech, hier_part)); 15992 } 15993 15994 /* 15995 * add_mailto_paramas() 15996 * parse the hier_part of mailto URI 15997 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]] 15998 * or mailto:{[active]|inactive} 15999 */ 16000 static int 16001 add_mailto_params(nvlist_t *mech, char *hier_part) 16002 { 16003 const char *tok = "?&"; 16004 char *p; 16005 char *lasts; 16006 char *param; 16007 char *val; 16008 16009 /* 16010 * If the notification parametes are in the form of 16011 * 16012 * malito:{[active]|inactive} 16013 * 16014 * we set the property accordingly and return. 16015 * Otherwise, we make the notification type active and 16016 * process the hier_part. 16017 */ 16018 if (set_active(mech, hier_part) == 0) 16019 return (0); 16020 else if (set_active(mech, PARAM_ACTIVE) != 0) 16021 return (-1); 16022 16023 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) { 16024 /* 16025 * sanity check: we only get here if hier_part = "", but 16026 * that's handled by set_active 16027 */ 16028 uu_die("strtok_r"); 16029 } 16030 16031 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0) 16032 uu_die(gettext("Out of memory.\n")); 16033 16034 while ((p = strtok_r(NULL, tok, &lasts)) != NULL) 16035 if ((param = strtok_r(p, "=", &val)) != NULL) 16036 if (nvlist_add_string(mech, param, val) != 0) 16037 uu_die(gettext("Out of memory.\n")); 16038 16039 return (0); 16040 } 16041 16042 static int 16043 uri_split(char *uri, char **scheme, char **hier_part) 16044 { 16045 int r = -1; 16046 16047 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL || 16048 *hier_part == NULL) { 16049 semerr(gettext("'%s' is not an URI\n"), uri); 16050 return (r); 16051 } 16052 16053 if ((r = check_uri_scheme(*scheme)) < 0) { 16054 semerr(gettext("Unkown URI scheme: %s\n"), *scheme); 16055 return (r); 16056 } 16057 16058 return (r); 16059 } 16060 16061 static int 16062 process_uri(nvlist_t *params, char *uri) 16063 { 16064 char *scheme; 16065 char *hier_part; 16066 nvlist_t *mech; 16067 int index; 16068 int r; 16069 16070 if ((index = uri_split(uri, &scheme, &hier_part)) < 0) 16071 return (-1); 16072 16073 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0) 16074 uu_die(gettext("Out of memory.\n")); 16075 16076 switch (index) { 16077 case 0: 16078 /* error messages displayed by called function */ 16079 r = add_mailto_params(mech, hier_part); 16080 break; 16081 16082 case 1: 16083 if ((r = add_snmp_params(mech, hier_part)) != 0) 16084 semerr(gettext("Not valid parameters: '%s'\n"), 16085 hier_part); 16086 break; 16087 16088 case 2: 16089 if ((r = add_syslog_params(mech, hier_part)) != 0) 16090 semerr(gettext("Not valid parameters: '%s'\n"), 16091 hier_part); 16092 break; 16093 16094 default: 16095 r = -1; 16096 } 16097 16098 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol, 16099 mech) != 0) 16100 uu_die(gettext("Out of memory.\n")); 16101 16102 nvlist_free(mech); 16103 return (r); 16104 } 16105 16106 static int 16107 set_params(nvlist_t *params, char **p) 16108 { 16109 char *uri; 16110 16111 if (p == NULL) 16112 /* sanity check */ 16113 uu_die("set_params"); 16114 16115 while (*p) { 16116 uri = strip_quotes_and_blanks(*p); 16117 if (process_uri(params, uri) != 0) 16118 return (-1); 16119 16120 ++p; 16121 } 16122 16123 return (0); 16124 } 16125 16126 static int 16127 setnotify(const char *e, char **p, int global) 16128 { 16129 char *str = safe_strdup(e); 16130 char **events; 16131 int32_t tset; 16132 int r = -1; 16133 nvlist_t *nvl, *params; 16134 char *fmri = NULL; 16135 16136 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 16137 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 || 16138 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 16139 SCF_NOTIFY_PARAMS_VERSION) != 0) 16140 uu_die(gettext("Out of memory.\n")); 16141 16142 events = tokenize(str, ","); 16143 16144 if ((tset = check_tokens(events)) > 0) { 16145 /* SMF state transitions parameters */ 16146 size_t sz = max_scf_fmri_len + 1; 16147 16148 fmri = safe_malloc(sz); 16149 if (global) { 16150 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 16151 } else if (get_selection_str(fmri, sz) != 0) { 16152 goto out; 16153 } 16154 16155 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 || 16156 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0) 16157 uu_die(gettext("Out of memory.\n")); 16158 16159 if ((r = set_params(params, p)) == 0) { 16160 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, 16161 params) != 0) 16162 uu_die(gettext("Out of memory.\n")); 16163 16164 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS, 16165 nvl) != SCF_SUCCESS) { 16166 r = -1; 16167 uu_warn(gettext( 16168 "Failed smf_notify_set_params(3SCF): %s\n"), 16169 scf_strerror(scf_error())); 16170 } 16171 } 16172 } else if (tset == FMA_TOKENS) { 16173 /* FMA event parameters */ 16174 if (global) { 16175 semerr(gettext("Can't use option '-g' with FMA event " 16176 "definitions\n")); 16177 goto out; 16178 } 16179 16180 if ((r = set_params(params, p)) != 0) 16181 goto out; 16182 16183 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0) 16184 uu_die(gettext("Out of memory.\n")); 16185 16186 while (*events) { 16187 if (smf_notify_set_params(de_tag(*events), nvl) != 16188 SCF_SUCCESS) 16189 uu_warn(gettext( 16190 "Failed smf_notify_set_params(3SCF) for " 16191 "event %s: %s\n"), *events, 16192 scf_strerror(scf_error())); 16193 events++; 16194 } 16195 } else if (tset == MIXED_TOKENS) { 16196 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 16197 } else { 16198 /* Sanity check */ 16199 uu_die(gettext("Invalid input.\n")); 16200 } 16201 16202 out: 16203 nvlist_free(nvl); 16204 nvlist_free(params); 16205 free(fmri); 16206 free(str); 16207 16208 return (r); 16209 } 16210 16211 int 16212 lscf_setnotify(uu_list_t *args) 16213 { 16214 int argc; 16215 char **argv = NULL; 16216 string_list_t *slp; 16217 int global; 16218 char *events; 16219 char **p; 16220 int i; 16221 int ret; 16222 16223 if ((argc = uu_list_numnodes(args)) < 2) 16224 goto usage; 16225 16226 argv = calloc(argc + 1, sizeof (char *)); 16227 if (argv == NULL) 16228 uu_die(gettext("Out of memory.\n")); 16229 16230 for (slp = uu_list_first(args), i = 0; 16231 slp != NULL; 16232 slp = uu_list_next(args, slp), ++i) 16233 argv[i] = slp->str; 16234 16235 argv[i] = NULL; 16236 16237 if (strcmp(argv[0], "-g") == 0) { 16238 global = 1; 16239 events = argv[1]; 16240 p = argv + 2; 16241 } else { 16242 global = 0; 16243 events = argv[0]; 16244 p = argv + 1; 16245 } 16246 16247 ret = setnotify(events, p, global); 16248 16249 out: 16250 free(argv); 16251 return (ret); 16252 16253 usage: 16254 ret = -2; 16255 goto out; 16256 } 16257 16258 /* 16259 * Creates a list of instance name strings associated with a service. If 16260 * wohandcrafted flag is set, get only instances that have a last-import 16261 * snapshot, instances that were imported via svccfg. 16262 */ 16263 static uu_list_t * 16264 create_instance_list(scf_service_t *svc, int wohandcrafted) 16265 { 16266 scf_snapshot_t *snap = NULL; 16267 scf_instance_t *inst; 16268 scf_iter_t *inst_iter; 16269 uu_list_t *instances; 16270 char *instname = NULL; 16271 int r; 16272 16273 inst_iter = scf_iter_create(g_hndl); 16274 inst = scf_instance_create(g_hndl); 16275 if (inst_iter == NULL || inst == NULL) { 16276 uu_warn(gettext("Could not create instance or iterator\n")); 16277 scfdie(); 16278 } 16279 16280 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 16281 return (instances); 16282 16283 if (scf_iter_service_instances(inst_iter, svc) != 0) { 16284 switch (scf_error()) { 16285 case SCF_ERROR_CONNECTION_BROKEN: 16286 case SCF_ERROR_DELETED: 16287 uu_list_destroy(instances); 16288 instances = NULL; 16289 goto out; 16290 16291 case SCF_ERROR_HANDLE_MISMATCH: 16292 case SCF_ERROR_NOT_BOUND: 16293 case SCF_ERROR_NOT_SET: 16294 default: 16295 bad_error("scf_iter_service_instances", scf_error()); 16296 } 16297 } 16298 16299 instname = safe_malloc(max_scf_name_len + 1); 16300 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 16301 if (r == -1) { 16302 (void) uu_warn(gettext("Unable to iterate through " 16303 "instances to create instance list : %s\n"), 16304 scf_strerror(scf_error())); 16305 16306 uu_list_destroy(instances); 16307 instances = NULL; 16308 goto out; 16309 } 16310 16311 /* 16312 * If the instance does not have a last-import snapshot 16313 * then do not add it to the list as it is a hand-crafted 16314 * instance that should not be managed. 16315 */ 16316 if (wohandcrafted) { 16317 if (snap == NULL && 16318 (snap = scf_snapshot_create(g_hndl)) == NULL) { 16319 uu_warn(gettext("Unable to create snapshot " 16320 "entity\n")); 16321 scfdie(); 16322 } 16323 16324 if (scf_instance_get_snapshot(inst, 16325 snap_lastimport, snap) != 0) { 16326 switch (scf_error()) { 16327 case SCF_ERROR_NOT_FOUND : 16328 case SCF_ERROR_DELETED: 16329 continue; 16330 16331 case SCF_ERROR_CONNECTION_BROKEN: 16332 uu_list_destroy(instances); 16333 instances = NULL; 16334 goto out; 16335 16336 case SCF_ERROR_HANDLE_MISMATCH: 16337 case SCF_ERROR_NOT_BOUND: 16338 case SCF_ERROR_NOT_SET: 16339 default: 16340 bad_error("scf_iter_service_instances", 16341 scf_error()); 16342 } 16343 } 16344 } 16345 16346 if (scf_instance_get_name(inst, instname, 16347 max_scf_name_len + 1) < 0) { 16348 switch (scf_error()) { 16349 case SCF_ERROR_NOT_FOUND : 16350 continue; 16351 16352 case SCF_ERROR_CONNECTION_BROKEN: 16353 case SCF_ERROR_DELETED: 16354 uu_list_destroy(instances); 16355 instances = NULL; 16356 goto out; 16357 16358 case SCF_ERROR_HANDLE_MISMATCH: 16359 case SCF_ERROR_NOT_BOUND: 16360 case SCF_ERROR_NOT_SET: 16361 default: 16362 bad_error("scf_iter_service_instances", 16363 scf_error()); 16364 } 16365 } 16366 16367 add_string(instances, instname); 16368 } 16369 16370 out: 16371 if (snap) 16372 scf_snapshot_destroy(snap); 16373 16374 scf_instance_destroy(inst); 16375 scf_iter_destroy(inst_iter); 16376 free(instname); 16377 return (instances); 16378 } 16379 16380 /* 16381 * disable an instance but wait for the instance to 16382 * move out of the running state. 16383 * 16384 * Returns 0 : if the instance did not disable 16385 * Returns non-zero : if the instance disabled. 16386 * 16387 */ 16388 static int 16389 disable_instance(scf_instance_t *instance) 16390 { 16391 char *fmribuf; 16392 int enabled = 10000; 16393 16394 if (inst_is_running(instance)) { 16395 fmribuf = safe_malloc(max_scf_name_len + 1); 16396 if (scf_instance_to_fmri(instance, fmribuf, 16397 max_scf_name_len + 1) < 0) { 16398 free(fmribuf); 16399 return (0); 16400 } 16401 16402 /* 16403 * If the instance cannot be disabled then return 16404 * failure to disable and let the caller decide 16405 * if that is of importance. 16406 */ 16407 if (smf_disable_instance(fmribuf, 0) != 0) { 16408 free(fmribuf); 16409 return (0); 16410 } 16411 16412 while (enabled) { 16413 if (!inst_is_running(instance)) 16414 break; 16415 16416 (void) poll(NULL, 0, 5); 16417 enabled = enabled - 5; 16418 } 16419 16420 free(fmribuf); 16421 } 16422 16423 return (enabled); 16424 } 16425 16426 /* 16427 * Function to compare two service_manifest structures. 16428 */ 16429 /* ARGSUSED2 */ 16430 static int 16431 service_manifest_compare(const void *left, const void *right, void *unused) 16432 { 16433 service_manifest_t *l = (service_manifest_t *)left; 16434 service_manifest_t *r = (service_manifest_t *)right; 16435 int rc; 16436 16437 rc = strcmp(l->servicename, r->servicename); 16438 16439 return (rc); 16440 } 16441 16442 /* 16443 * Look for the provided service in the service to manifest 16444 * tree. If the service exists, and a manifest was provided 16445 * then add the manifest to that service. If the service 16446 * does not exist, then add the service and manifest to the 16447 * list. 16448 * 16449 * If the manifest is NULL, return the element if found. If 16450 * the service is not found return NULL. 16451 */ 16452 service_manifest_t * 16453 find_add_svc_mfst(const char *svnbuf, const char *mfst) 16454 { 16455 service_manifest_t elem; 16456 service_manifest_t *fnelem; 16457 uu_avl_index_t marker; 16458 16459 elem.servicename = svnbuf; 16460 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 16461 16462 if (mfst) { 16463 if (fnelem) { 16464 add_string(fnelem->mfstlist, strdup(mfst)); 16465 } else { 16466 fnelem = safe_malloc(sizeof (*fnelem)); 16467 fnelem->servicename = safe_strdup(svnbuf); 16468 if ((fnelem->mfstlist = 16469 uu_list_create(string_pool, NULL, 0)) == NULL) 16470 uu_die(gettext("Could not create property " 16471 "list: %s\n"), uu_strerror(uu_error())); 16472 16473 add_string(fnelem->mfstlist, safe_strdup(mfst)); 16474 16475 uu_avl_insert(service_manifest_tree, fnelem, marker); 16476 } 16477 } 16478 16479 return (fnelem); 16480 } 16481 16482 /* 16483 * Create the service to manifest avl tree. 16484 * 16485 * Walk each of the manifests currently installed in the supported 16486 * directories, /lib/svc/manifest and /var/svc/manifest. For 16487 * each of the manifests, inventory the services and add them to 16488 * the tree. 16489 * 16490 * Code that calls this function should make sure fileystem/minimal is online, 16491 * /var is available, since this function walks the /var/svc/manifest directory. 16492 */ 16493 static void 16494 create_manifest_tree(void) 16495 { 16496 manifest_info_t **entry; 16497 manifest_info_t **manifests; 16498 uu_list_walk_t *svcs; 16499 bundle_t *b; 16500 entity_t *mfsvc; 16501 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 16502 int c, status; 16503 16504 if (service_manifest_pool) 16505 return; 16506 16507 /* 16508 * Create the list pool for the service manifest list 16509 */ 16510 service_manifest_pool = uu_avl_pool_create("service_manifest", 16511 sizeof (service_manifest_t), 16512 offsetof(service_manifest_t, svcmfst_node), 16513 service_manifest_compare, UU_DEFAULT); 16514 if (service_manifest_pool == NULL) 16515 uu_die(gettext("service_manifest pool creation failed: %s\n"), 16516 uu_strerror(uu_error())); 16517 16518 /* 16519 * Create the list 16520 */ 16521 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 16522 UU_DEFAULT); 16523 if (service_manifest_tree == NULL) 16524 uu_die(gettext("service_manifest tree creation failed: %s\n"), 16525 uu_strerror(uu_error())); 16526 16527 /* 16528 * Walk the manifests adding the service(s) from each manifest. 16529 * 16530 * If a service already exists add the manifest to the manifest 16531 * list for that service. This covers the case of a service that 16532 * is supported by multiple manifest files. 16533 */ 16534 for (c = 0; dirs[c]; c++) { 16535 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT); 16536 if (status < 0) { 16537 uu_warn(gettext("file tree walk of %s encountered " 16538 "error %s\n"), dirs[c], strerror(errno)); 16539 16540 uu_avl_destroy(service_manifest_tree); 16541 service_manifest_tree = NULL; 16542 return; 16543 } 16544 16545 /* 16546 * If a manifest that was in the list is not found 16547 * then skip and go to the next manifest file. 16548 */ 16549 if (manifests != NULL) { 16550 for (entry = manifests; *entry != NULL; entry++) { 16551 b = internal_bundle_new(); 16552 if (lxml_get_bundle_file(b, (*entry)->mi_path, 16553 SVCCFG_OP_IMPORT) != 0) { 16554 internal_bundle_free(b); 16555 continue; 16556 } 16557 16558 svcs = uu_list_walk_start(b->sc_bundle_services, 16559 0); 16560 if (svcs == NULL) { 16561 internal_bundle_free(b); 16562 continue; 16563 } 16564 16565 while ((mfsvc = uu_list_walk_next(svcs)) != 16566 NULL) { 16567 /* Add manifest to service */ 16568 (void) find_add_svc_mfst(mfsvc->sc_name, 16569 (*entry)->mi_path); 16570 } 16571 16572 uu_list_walk_end(svcs); 16573 internal_bundle_free(b); 16574 } 16575 16576 free_manifest_array(manifests); 16577 } 16578 } 16579 } 16580 16581 /* 16582 * Check the manifest history file to see 16583 * if the service was ever installed from 16584 * one of the supported directories. 16585 * 16586 * Return Values : 16587 * -1 - if there's error reading manifest history file 16588 * 1 - if the service is not found 16589 * 0 - if the service is found 16590 */ 16591 static int 16592 check_mfst_history(const char *svcname) 16593 { 16594 struct stat st; 16595 caddr_t mfsthist_start; 16596 char *svnbuf; 16597 int fd; 16598 int r = 1; 16599 16600 fd = open(MFSTHISTFILE, O_RDONLY); 16601 if (fd == -1) { 16602 uu_warn(gettext("Unable to open the history file\n")); 16603 return (-1); 16604 } 16605 16606 if (fstat(fd, &st) == -1) { 16607 uu_warn(gettext("Unable to stat the history file\n")); 16608 return (-1); 16609 } 16610 16611 mfsthist_start = mmap(0, st.st_size, PROT_READ, 16612 MAP_PRIVATE, fd, 0); 16613 16614 (void) close(fd); 16615 if (mfsthist_start == MAP_FAILED || 16616 *(mfsthist_start + st.st_size) != '\0') { 16617 (void) munmap(mfsthist_start, st.st_size); 16618 return (-1); 16619 } 16620 16621 /* 16622 * The manifest history file is a space delimited list 16623 * of service and instance to manifest linkage. Adding 16624 * a space to the end of the service name so to get only 16625 * the service that is being searched for. 16626 */ 16627 svnbuf = uu_msprintf("%s ", svcname); 16628 if (svnbuf == NULL) 16629 uu_die(gettext("Out of memory")); 16630 16631 if (strstr(mfsthist_start, svnbuf) != NULL) 16632 r = 0; 16633 16634 (void) munmap(mfsthist_start, st.st_size); 16635 uu_free(svnbuf); 16636 return (r); 16637 } 16638 16639 /* 16640 * Take down each of the instances in the service 16641 * and remove them, then delete the service. 16642 */ 16643 static void 16644 teardown_service(scf_service_t *svc, const char *svnbuf) 16645 { 16646 scf_instance_t *instance; 16647 scf_iter_t *iter; 16648 int r; 16649 16650 safe_printf(gettext("Delete service %s as there are no " 16651 "supporting manifests\n"), svnbuf); 16652 16653 instance = scf_instance_create(g_hndl); 16654 iter = scf_iter_create(g_hndl); 16655 if (iter == NULL || instance == NULL) { 16656 uu_warn(gettext("Unable to create supporting entities to " 16657 "teardown the service\n")); 16658 uu_warn(gettext("scf error is : %s\n"), 16659 scf_strerror(scf_error())); 16660 scfdie(); 16661 } 16662 16663 if (scf_iter_service_instances(iter, svc) != 0) { 16664 switch (scf_error()) { 16665 case SCF_ERROR_CONNECTION_BROKEN: 16666 case SCF_ERROR_DELETED: 16667 goto out; 16668 16669 case SCF_ERROR_HANDLE_MISMATCH: 16670 case SCF_ERROR_NOT_BOUND: 16671 case SCF_ERROR_NOT_SET: 16672 default: 16673 bad_error("scf_iter_service_instances", 16674 scf_error()); 16675 } 16676 } 16677 16678 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 16679 if (r == -1) { 16680 uu_warn(gettext("Error - %s\n"), 16681 scf_strerror(scf_error())); 16682 goto out; 16683 } 16684 16685 (void) disable_instance(instance); 16686 } 16687 16688 /* 16689 * Delete the service... forcing the deletion in case 16690 * any of the instances did not disable. 16691 */ 16692 (void) lscf_service_delete(svc, 1); 16693 out: 16694 scf_instance_destroy(instance); 16695 scf_iter_destroy(iter); 16696 } 16697 16698 /* 16699 * Get the list of instances supported by the manifest 16700 * file. 16701 * 16702 * Return 0 if there are no instances. 16703 * 16704 * Return -1 if there are errors attempting to collect instances. 16705 * 16706 * Return the count of instances found if there are no errors. 16707 * 16708 */ 16709 static int 16710 check_instance_support(char *mfstfile, const char *svcname, 16711 uu_list_t *instances) 16712 { 16713 uu_list_walk_t *svcs, *insts; 16714 uu_list_t *ilist; 16715 bundle_t *b; 16716 entity_t *mfsvc, *mfinst; 16717 const char *svcn; 16718 int rminstcnt = 0; 16719 16720 16721 b = internal_bundle_new(); 16722 16723 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 16724 /* 16725 * Unable to process the manifest file for 16726 * instance support, so just return as 16727 * don't want to remove instances that could 16728 * not be accounted for that might exist here. 16729 */ 16730 internal_bundle_free(b); 16731 return (0); 16732 } 16733 16734 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 16735 if (svcs == NULL) { 16736 internal_bundle_free(b); 16737 return (0); 16738 } 16739 16740 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 16741 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 16742 16743 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 16744 if (strcmp(mfsvc->sc_name, svcn) == 0) 16745 break; 16746 } 16747 uu_list_walk_end(svcs); 16748 16749 if (mfsvc == NULL) { 16750 internal_bundle_free(b); 16751 return (-1); 16752 } 16753 16754 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 16755 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 16756 internal_bundle_free(b); 16757 return (0); 16758 } 16759 16760 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 16761 /* 16762 * Remove the instance from the instances list. 16763 * The unaccounted for instances will be removed 16764 * from the service once all manifests are 16765 * processed. 16766 */ 16767 (void) remove_string(instances, 16768 mfinst->sc_name); 16769 rminstcnt++; 16770 } 16771 16772 uu_list_walk_end(insts); 16773 internal_bundle_free(b); 16774 16775 return (rminstcnt); 16776 } 16777 16778 /* 16779 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 16780 * 'false' to indicate there's no manifest file(s) found for the service. 16781 */ 16782 static void 16783 svc_add_no_support(scf_service_t *svc) 16784 { 16785 char *pname; 16786 16787 /* Add no support */ 16788 cur_svc = svc; 16789 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 16790 return; 16791 16792 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 16793 if (pname == NULL) 16794 uu_die(gettext("Out of memory.\n")); 16795 16796 (void) lscf_addpropvalue(pname, "boolean:", "0"); 16797 16798 uu_free(pname); 16799 cur_svc = NULL; 16800 } 16801 16802 /* 16803 * This function handles all upgrade scenarios for a service that doesn't have 16804 * SCF_PG_MANIFESTFILES pg. The function creates and populates 16805 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 16806 * manifest(s) mapping. Manifests under supported directories are inventoried 16807 * and a property is added for each file that delivers configuration to the 16808 * service. A service that has no corresponding manifest files (deleted) are 16809 * removed from repository. 16810 * 16811 * Unsupported services: 16812 * 16813 * A service is considered unsupported if there is no corresponding manifest 16814 * in the supported directories for that service and the service isn't in the 16815 * history file list. The history file, MFSTHISTFILE, contains a list of all 16816 * services and instances that were delivered by Solaris before the introduction 16817 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 16818 * the path to the manifest file that defined the service or instance. 16819 * 16820 * Another type of unsupported services is 'handcrafted' services, 16821 * programmatically created services or services created by dependent entries 16822 * in other manifests. A handcrafted service is identified by its lack of any 16823 * instance containing last-import snapshot which is created during svccfg 16824 * import. 16825 * 16826 * This function sets a flag for unsupported services by setting services' 16827 * SCF_PG_MANIFESTFILES/support property to false. 16828 */ 16829 static void 16830 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 16831 { 16832 service_manifest_t *elem; 16833 uu_list_walk_t *mfwalk; 16834 string_list_t *mfile; 16835 uu_list_t *instances; 16836 const char *sname; 16837 char *pname; 16838 int r; 16839 16840 /* 16841 * Since there's no guarantee manifests under /var are available during 16842 * early import, don't perform any upgrade during early import. 16843 */ 16844 if (IGNORE_VAR) 16845 return; 16846 16847 if (service_manifest_tree == NULL) { 16848 create_manifest_tree(); 16849 } 16850 16851 /* 16852 * Find service's supporting manifest(s) after 16853 * stripping off the svc:/ prefix that is part 16854 * of the fmri that is not used in the service 16855 * manifest bundle list. 16856 */ 16857 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 16858 strlen(SCF_FMRI_SERVICE_PREFIX); 16859 elem = find_add_svc_mfst(sname, NULL); 16860 if (elem == NULL) { 16861 16862 /* 16863 * A handcrafted service, one that has no instance containing 16864 * last-import snapshot, should get unsupported flag. 16865 */ 16866 instances = create_instance_list(svc, 1); 16867 if (instances == NULL) { 16868 uu_warn(gettext("Unable to create instance list %s\n"), 16869 svcname); 16870 return; 16871 } 16872 16873 if (uu_list_numnodes(instances) == 0) { 16874 svc_add_no_support(svc); 16875 return; 16876 } 16877 16878 /* 16879 * If the service is in the history file, and its supporting 16880 * manifests are not found, we can safely delete the service 16881 * because its manifests are removed from the system. 16882 * 16883 * Services not found in the history file are not delivered by 16884 * Solaris and/or delivered outside supported directories, set 16885 * unsupported flag for these services. 16886 */ 16887 r = check_mfst_history(svcname); 16888 if (r == -1) 16889 return; 16890 16891 if (r) { 16892 /* Set unsupported flag for service */ 16893 svc_add_no_support(svc); 16894 } else { 16895 /* Delete the service */ 16896 teardown_service(svc, svcname); 16897 } 16898 16899 return; 16900 } 16901 16902 /* 16903 * Walk through the list of manifests and add them 16904 * to the service. 16905 * 16906 * Create a manifestfiles pg and add the property. 16907 */ 16908 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 16909 if (mfwalk == NULL) 16910 return; 16911 16912 cur_svc = svc; 16913 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 16914 if (r != 0) { 16915 cur_svc = NULL; 16916 return; 16917 } 16918 16919 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 16920 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16921 mhash_filename_to_propname(mfile->str, 0)); 16922 if (pname == NULL) 16923 uu_die(gettext("Out of memory.\n")); 16924 16925 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 16926 uu_free(pname); 16927 } 16928 uu_list_walk_end(mfwalk); 16929 16930 cur_svc = NULL; 16931 } 16932 16933 /* 16934 * Take a service and process the manifest file entires to see if 16935 * there is continued support for the service and instances. If 16936 * not cleanup as appropriate. 16937 * 16938 * If a service does not have a manifest files entry flag it for 16939 * upgrade and return. 16940 * 16941 * For each manifestfiles property check if the manifest file is 16942 * under the supported /lib/svc/manifest or /var/svc/manifest path 16943 * and if not then return immediately as this service is not supported 16944 * by the cleanup mechanism and should be ignored. 16945 * 16946 * For each manifest file that is supported, check to see if the 16947 * file exists. If not then remove the manifest file property 16948 * from the service and the smf/manifest hash table. If the manifest 16949 * file exists then verify that it supports the instances that are 16950 * part of the service. 16951 * 16952 * Once all manifest files have been accounted for remove any instances 16953 * that are no longer supported in the service. 16954 * 16955 * Return values : 16956 * 0 - Successfully processed the service 16957 * non-zero - failed to process the service 16958 * 16959 * On most errors, will just return to wait and get the next service, 16960 * unless in case of unable to create the needed structures which is 16961 * most likely a fatal error that is not going to be recoverable. 16962 */ 16963 int 16964 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 16965 { 16966 struct mpg_mfile *mpntov = NULL; 16967 struct mpg_mfile **mpvarry = NULL; 16968 scf_service_t *svc; 16969 scf_propertygroup_t *mpg; 16970 scf_property_t *mp; 16971 scf_value_t *mv; 16972 scf_iter_t *mi; 16973 scf_instance_t *instance; 16974 uu_list_walk_t *insts; 16975 uu_list_t *instances = NULL; 16976 boolean_t activity = (boolean_t)act; 16977 char *mpnbuf = NULL; 16978 char *mpvbuf = NULL; 16979 char *pgpropbuf; 16980 int mfstcnt, rminstct, instct, mfstmax; 16981 int index; 16982 int r = 0; 16983 16984 assert(g_hndl != NULL); 16985 assert(wip->svc != NULL); 16986 assert(wip->fmri != NULL); 16987 16988 svc = wip->svc; 16989 16990 mpg = scf_pg_create(g_hndl); 16991 mp = scf_property_create(g_hndl); 16992 mi = scf_iter_create(g_hndl); 16993 mv = scf_value_create(g_hndl); 16994 instance = scf_instance_create(g_hndl); 16995 16996 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 16997 instance == NULL) { 16998 uu_warn(gettext("Unable to create the supporting entities\n")); 16999 uu_warn(gettext("scf error is : %s\n"), 17000 scf_strerror(scf_error())); 17001 scfdie(); 17002 } 17003 17004 /* 17005 * Get the manifestfiles property group to be parsed for 17006 * files existence. 17007 */ 17008 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 17009 switch (scf_error()) { 17010 case SCF_ERROR_NOT_FOUND: 17011 upgrade_svc_mfst_connection(svc, wip->fmri); 17012 break; 17013 case SCF_ERROR_DELETED: 17014 case SCF_ERROR_CONNECTION_BROKEN: 17015 goto out; 17016 17017 case SCF_ERROR_HANDLE_MISMATCH: 17018 case SCF_ERROR_NOT_BOUND: 17019 case SCF_ERROR_NOT_SET: 17020 default: 17021 bad_error("scf_iter_pg_properties", 17022 scf_error()); 17023 } 17024 17025 goto out; 17026 } 17027 17028 /* 17029 * Iterate through each of the manifestfiles properties 17030 * to determine what manifestfiles are available. 17031 * 17032 * If a manifest file is supported then increment the 17033 * count and therefore the service is safe. 17034 */ 17035 if (scf_iter_pg_properties(mi, mpg) != 0) { 17036 switch (scf_error()) { 17037 case SCF_ERROR_DELETED: 17038 case SCF_ERROR_CONNECTION_BROKEN: 17039 goto out; 17040 17041 case SCF_ERROR_HANDLE_MISMATCH: 17042 case SCF_ERROR_NOT_BOUND: 17043 case SCF_ERROR_NOT_SET: 17044 default: 17045 bad_error("scf_iter_pg_properties", 17046 scf_error()); 17047 } 17048 } 17049 17050 mfstcnt = 0; 17051 mfstmax = MFSTFILE_MAX; 17052 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 17053 while ((r = scf_iter_next_property(mi, mp)) != 0) { 17054 if (r == -1) 17055 bad_error(gettext("Unable to iterate through " 17056 "manifestfiles properties : %s"), 17057 scf_error()); 17058 17059 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 17060 mpnbuf = safe_malloc(max_scf_name_len + 1); 17061 mpvbuf = safe_malloc(max_scf_value_len + 1); 17062 mpntov->mpg = mpnbuf; 17063 mpntov->mfile = mpvbuf; 17064 mpntov->access = 1; 17065 if (scf_property_get_name(mp, mpnbuf, 17066 max_scf_name_len + 1) < 0) { 17067 uu_warn(gettext("Unable to get manifest file " 17068 "property : %s\n"), 17069 scf_strerror(scf_error())); 17070 17071 switch (scf_error()) { 17072 case SCF_ERROR_DELETED: 17073 case SCF_ERROR_CONNECTION_BROKEN: 17074 r = scferror2errno(scf_error()); 17075 goto out_free; 17076 17077 case SCF_ERROR_HANDLE_MISMATCH: 17078 case SCF_ERROR_NOT_BOUND: 17079 case SCF_ERROR_NOT_SET: 17080 default: 17081 bad_error("scf_iter_pg_properties", 17082 scf_error()); 17083 } 17084 } 17085 17086 /* 17087 * The support property is a boolean value that indicates 17088 * if the service is supported for manifest file deletion. 17089 * Currently at this time there is no code that sets this 17090 * value to true. So while we could just let this be caught 17091 * by the support check below, in the future this by be set 17092 * to true and require processing. So for that, go ahead 17093 * and check here, and just return if false. Otherwise, 17094 * fall through expecting that other support checks will 17095 * handle the entries. 17096 */ 17097 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 17098 uint8_t support; 17099 17100 if (scf_property_get_value(mp, mv) != 0 || 17101 scf_value_get_boolean(mv, &support) != 0) { 17102 uu_warn(gettext("Unable to get the manifest " 17103 "support value: %s\n"), 17104 scf_strerror(scf_error())); 17105 17106 switch (scf_error()) { 17107 case SCF_ERROR_DELETED: 17108 case SCF_ERROR_CONNECTION_BROKEN: 17109 r = scferror2errno(scf_error()); 17110 goto out_free; 17111 17112 case SCF_ERROR_HANDLE_MISMATCH: 17113 case SCF_ERROR_NOT_BOUND: 17114 case SCF_ERROR_NOT_SET: 17115 default: 17116 bad_error("scf_iter_pg_properties", 17117 scf_error()); 17118 } 17119 } 17120 17121 if (support == B_FALSE) 17122 goto out_free; 17123 } 17124 17125 /* 17126 * Anything with a manifest outside of the supported 17127 * directories, immediately bail out because that makes 17128 * this service non-supported. We don't even want 17129 * to do instance processing in this case because the 17130 * instances could be part of the non-supported manifest. 17131 */ 17132 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 17133 /* 17134 * Manifest is not in /lib/svc, so we need to 17135 * consider the /var/svc case. 17136 */ 17137 if (strncmp(mpnbuf, VARSVC_PR, 17138 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 17139 /* 17140 * Either the manifest is not in /var/svc or 17141 * /var is not yet mounted. We ignore the 17142 * manifest either because it is not in a 17143 * standard location or because we cannot 17144 * currently access the manifest. 17145 */ 17146 goto out_free; 17147 } 17148 } 17149 17150 /* 17151 * Get the value to of the manifest file for this entry 17152 * for access verification and instance support 17153 * verification if it still exists. 17154 * 17155 * During Early Manifest Import if the manifest is in 17156 * /var/svc then it may not yet be available for checking 17157 * so we must determine if /var/svc is available. If not 17158 * then defer until Late Manifest Import to cleanup. 17159 */ 17160 if (scf_property_get_value(mp, mv) != 0) { 17161 uu_warn(gettext("Unable to get the manifest file " 17162 "value: %s\n"), 17163 scf_strerror(scf_error())); 17164 17165 switch (scf_error()) { 17166 case SCF_ERROR_DELETED: 17167 case SCF_ERROR_CONNECTION_BROKEN: 17168 r = scferror2errno(scf_error()); 17169 goto out_free; 17170 17171 case SCF_ERROR_HANDLE_MISMATCH: 17172 case SCF_ERROR_NOT_BOUND: 17173 case SCF_ERROR_NOT_SET: 17174 default: 17175 bad_error("scf_property_get_value", 17176 scf_error()); 17177 } 17178 } 17179 17180 if (scf_value_get_astring(mv, mpvbuf, 17181 max_scf_value_len + 1) < 0) { 17182 uu_warn(gettext("Unable to get the manifest " 17183 "file : %s\n"), 17184 scf_strerror(scf_error())); 17185 17186 switch (scf_error()) { 17187 case SCF_ERROR_DELETED: 17188 case SCF_ERROR_CONNECTION_BROKEN: 17189 r = scferror2errno(scf_error()); 17190 goto out_free; 17191 17192 case SCF_ERROR_HANDLE_MISMATCH: 17193 case SCF_ERROR_NOT_BOUND: 17194 case SCF_ERROR_NOT_SET: 17195 default: 17196 bad_error("scf_value_get_astring", 17197 scf_error()); 17198 } 17199 } 17200 17201 mpvarry[mfstcnt] = mpntov; 17202 mfstcnt++; 17203 17204 /* 17205 * Check for the need to reallocate array 17206 */ 17207 if (mfstcnt >= (mfstmax - 1)) { 17208 struct mpg_mfile **newmpvarry; 17209 17210 mfstmax = mfstmax * 2; 17211 newmpvarry = realloc(mpvarry, 17212 sizeof (struct mpg_mfile *) * mfstmax); 17213 17214 if (newmpvarry == NULL) 17215 goto out_free; 17216 17217 mpvarry = newmpvarry; 17218 } 17219 17220 mpvarry[mfstcnt] = NULL; 17221 } 17222 17223 for (index = 0; mpvarry[index]; index++) { 17224 mpntov = mpvarry[index]; 17225 17226 /* 17227 * Check to see if the manifestfile is accessable, if so hand 17228 * this service and manifestfile off to be processed for 17229 * instance support. 17230 */ 17231 mpnbuf = mpntov->mpg; 17232 mpvbuf = mpntov->mfile; 17233 if (access(mpvbuf, F_OK) != 0) { 17234 mpntov->access = 0; 17235 activity++; 17236 mfstcnt--; 17237 /* Remove the entry from the service */ 17238 cur_svc = svc; 17239 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 17240 mpnbuf); 17241 if (pgpropbuf == NULL) 17242 uu_die(gettext("Out of memory.\n")); 17243 17244 lscf_delprop(pgpropbuf); 17245 cur_svc = NULL; 17246 17247 uu_free(pgpropbuf); 17248 } 17249 } 17250 17251 /* 17252 * If mfstcnt is 0, none of the manifests that supported the service 17253 * existed so remove the service. 17254 */ 17255 if (mfstcnt == 0) { 17256 teardown_service(svc, wip->fmri); 17257 17258 goto out_free; 17259 } 17260 17261 if (activity) { 17262 int nosvcsupport = 0; 17263 17264 /* 17265 * If the list of service instances is NULL then 17266 * create the list. 17267 */ 17268 instances = create_instance_list(svc, 1); 17269 if (instances == NULL) { 17270 uu_warn(gettext("Unable to create instance list %s\n"), 17271 wip->fmri); 17272 goto out_free; 17273 } 17274 17275 rminstct = uu_list_numnodes(instances); 17276 instct = rminstct; 17277 17278 for (index = 0; mpvarry[index]; index++) { 17279 mpntov = mpvarry[index]; 17280 if (mpntov->access == 0) 17281 continue; 17282 17283 mpnbuf = mpntov->mpg; 17284 mpvbuf = mpntov->mfile; 17285 r = check_instance_support(mpvbuf, wip->fmri, 17286 instances); 17287 if (r == -1) { 17288 nosvcsupport++; 17289 } else { 17290 rminstct -= r; 17291 } 17292 } 17293 17294 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 17295 teardown_service(svc, wip->fmri); 17296 17297 goto out_free; 17298 } 17299 } 17300 17301 /* 17302 * If there are instances left on the instance list, then 17303 * we must remove them. 17304 */ 17305 if (instances != NULL && uu_list_numnodes(instances)) { 17306 string_list_t *sp; 17307 17308 insts = uu_list_walk_start(instances, 0); 17309 while ((sp = uu_list_walk_next(insts)) != NULL) { 17310 /* 17311 * Remove the instance from the instances list. 17312 */ 17313 safe_printf(gettext("Delete instance %s from " 17314 "service %s\n"), sp->str, wip->fmri); 17315 if (scf_service_get_instance(svc, sp->str, 17316 instance) != SCF_SUCCESS) { 17317 (void) uu_warn("scf_error - %s\n", 17318 scf_strerror(scf_error())); 17319 17320 continue; 17321 } 17322 17323 (void) disable_instance(instance); 17324 17325 (void) lscf_instance_delete(instance, 1); 17326 } 17327 scf_instance_destroy(instance); 17328 uu_list_walk_end(insts); 17329 } 17330 17331 out_free: 17332 if (mpvarry) { 17333 struct mpg_mfile *fmpntov; 17334 17335 for (index = 0; mpvarry[index]; index++) { 17336 fmpntov = mpvarry[index]; 17337 if (fmpntov->mpg == mpnbuf) 17338 mpnbuf = NULL; 17339 free(fmpntov->mpg); 17340 17341 if (fmpntov->mfile == mpvbuf) 17342 mpvbuf = NULL; 17343 free(fmpntov->mfile); 17344 17345 if (fmpntov == mpntov) 17346 mpntov = NULL; 17347 free(fmpntov); 17348 } 17349 if (mpnbuf) 17350 free(mpnbuf); 17351 if (mpvbuf) 17352 free(mpvbuf); 17353 if (mpntov) 17354 free(mpntov); 17355 17356 free(mpvarry); 17357 } 17358 out: 17359 scf_pg_destroy(mpg); 17360 scf_property_destroy(mp); 17361 scf_iter_destroy(mi); 17362 scf_value_destroy(mv); 17363 17364 return (0); 17365 } 17366 17367 /* 17368 * Take the service and search for the manifestfiles property 17369 * in each of the property groups. If the manifest file 17370 * associated with the property does not exist then remove 17371 * the property group. 17372 */ 17373 int 17374 lscf_hash_cleanup() 17375 { 17376 scf_service_t *svc; 17377 scf_scope_t *scope; 17378 scf_propertygroup_t *pg; 17379 scf_property_t *prop; 17380 scf_value_t *val; 17381 scf_iter_t *iter; 17382 char *pgname = NULL; 17383 char *mfile = NULL; 17384 int r; 17385 17386 svc = scf_service_create(g_hndl); 17387 scope = scf_scope_create(g_hndl); 17388 pg = scf_pg_create(g_hndl); 17389 prop = scf_property_create(g_hndl); 17390 val = scf_value_create(g_hndl); 17391 iter = scf_iter_create(g_hndl); 17392 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 17393 svc == NULL || scope == NULL) { 17394 uu_warn(gettext("Unable to create a property group, or " 17395 "property\n")); 17396 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 17397 "pg is not NULL"); 17398 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 17399 "prop is not NULL"); 17400 uu_warn("%s\n", val == NULL ? "val is NULL" : 17401 "val is not NULL"); 17402 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 17403 "iter is not NULL"); 17404 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 17405 "svc is not NULL"); 17406 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 17407 "scope is not NULL"); 17408 uu_warn(gettext("scf error is : %s\n"), 17409 scf_strerror(scf_error())); 17410 scfdie(); 17411 } 17412 17413 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 17414 switch (scf_error()) { 17415 case SCF_ERROR_CONNECTION_BROKEN: 17416 case SCF_ERROR_NOT_FOUND: 17417 goto out; 17418 17419 case SCF_ERROR_HANDLE_MISMATCH: 17420 case SCF_ERROR_NOT_BOUND: 17421 case SCF_ERROR_INVALID_ARGUMENT: 17422 default: 17423 bad_error("scf_handle_get_scope", scf_error()); 17424 } 17425 } 17426 17427 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 17428 uu_warn(gettext("Unable to process the hash service, %s\n"), 17429 HASH_SVC); 17430 goto out; 17431 } 17432 17433 pgname = safe_malloc(max_scf_name_len + 1); 17434 mfile = safe_malloc(max_scf_value_len + 1); 17435 17436 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 17437 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 17438 scf_strerror(scf_error())); 17439 goto out; 17440 } 17441 17442 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 17443 if (r == -1) 17444 goto out; 17445 17446 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 17447 switch (scf_error()) { 17448 case SCF_ERROR_DELETED: 17449 return (ENODEV); 17450 17451 case SCF_ERROR_CONNECTION_BROKEN: 17452 return (ECONNABORTED); 17453 17454 case SCF_ERROR_NOT_SET: 17455 case SCF_ERROR_NOT_BOUND: 17456 default: 17457 bad_error("scf_pg_get_name", scf_error()); 17458 } 17459 } 17460 if (IGNORE_VAR) { 17461 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 17462 continue; 17463 } 17464 17465 /* 17466 * If unable to get the property continue as this is an 17467 * entry that has no location to check against. 17468 */ 17469 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 17470 continue; 17471 } 17472 17473 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 17474 uu_warn(gettext("Unable to get value from %s\n"), 17475 pgname); 17476 17477 switch (scf_error()) { 17478 case SCF_ERROR_DELETED: 17479 case SCF_ERROR_CONSTRAINT_VIOLATED: 17480 case SCF_ERROR_NOT_FOUND: 17481 case SCF_ERROR_NOT_SET: 17482 continue; 17483 17484 case SCF_ERROR_CONNECTION_BROKEN: 17485 r = scferror2errno(scf_error()); 17486 goto out; 17487 17488 case SCF_ERROR_HANDLE_MISMATCH: 17489 case SCF_ERROR_NOT_BOUND: 17490 default: 17491 bad_error("scf_property_get_value", 17492 scf_error()); 17493 } 17494 } 17495 17496 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) 17497 == -1) { 17498 uu_warn(gettext("Unable to get astring from %s : %s\n"), 17499 pgname, scf_strerror(scf_error())); 17500 17501 switch (scf_error()) { 17502 case SCF_ERROR_NOT_SET: 17503 case SCF_ERROR_TYPE_MISMATCH: 17504 continue; 17505 17506 default: 17507 bad_error("scf_value_get_astring", scf_error()); 17508 } 17509 } 17510 17511 if (access(mfile, F_OK) == 0) 17512 continue; 17513 17514 (void) scf_pg_delete(pg); 17515 } 17516 17517 out: 17518 scf_scope_destroy(scope); 17519 scf_service_destroy(svc); 17520 scf_pg_destroy(pg); 17521 scf_property_destroy(prop); 17522 scf_value_destroy(val); 17523 scf_iter_destroy(iter); 17524 free(pgname); 17525 free(mfile); 17526 17527 return (0); 17528 } 17529 17530 #ifndef NATIVE_BUILD 17531 /* ARGSUSED */ 17532 CPL_MATCH_FN(complete_select) 17533 { 17534 const char *arg0, *arg1, *arg1end; 17535 int word_start, err = 0, r; 17536 size_t len; 17537 char *buf; 17538 17539 lscf_prep_hndl(); 17540 17541 arg0 = line + strspn(line, " \t"); 17542 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 17543 17544 arg1 = arg0 + sizeof ("select") - 1; 17545 arg1 += strspn(arg1, " \t"); 17546 word_start = arg1 - line; 17547 17548 arg1end = arg1 + strcspn(arg1, " \t"); 17549 if (arg1end < line + word_end) 17550 return (0); 17551 17552 len = line + word_end - arg1; 17553 17554 buf = safe_malloc(max_scf_name_len + 1); 17555 17556 if (cur_snap != NULL) { 17557 return (0); 17558 } else if (cur_inst != NULL) { 17559 return (0); 17560 } else if (cur_svc != NULL) { 17561 scf_instance_t *inst; 17562 scf_iter_t *iter; 17563 17564 if ((inst = scf_instance_create(g_hndl)) == NULL || 17565 (iter = scf_iter_create(g_hndl)) == NULL) 17566 scfdie(); 17567 17568 if (scf_iter_service_instances(iter, cur_svc) != 0) 17569 scfdie(); 17570 17571 for (;;) { 17572 r = scf_iter_next_instance(iter, inst); 17573 if (r == 0) 17574 break; 17575 if (r != 1) 17576 scfdie(); 17577 17578 if (scf_instance_get_name(inst, buf, 17579 max_scf_name_len + 1) < 0) 17580 scfdie(); 17581 17582 if (strncmp(buf, arg1, len) == 0) { 17583 err = cpl_add_completion(cpl, line, word_start, 17584 word_end, buf + len, "", " "); 17585 if (err != 0) 17586 break; 17587 } 17588 } 17589 17590 scf_iter_destroy(iter); 17591 scf_instance_destroy(inst); 17592 17593 return (err); 17594 } else { 17595 scf_service_t *svc; 17596 scf_iter_t *iter; 17597 17598 assert(cur_scope != NULL); 17599 17600 if ((svc = scf_service_create(g_hndl)) == NULL || 17601 (iter = scf_iter_create(g_hndl)) == NULL) 17602 scfdie(); 17603 17604 if (scf_iter_scope_services(iter, cur_scope) != 0) 17605 scfdie(); 17606 17607 for (;;) { 17608 r = scf_iter_next_service(iter, svc); 17609 if (r == 0) 17610 break; 17611 if (r != 1) 17612 scfdie(); 17613 17614 if (scf_service_get_name(svc, buf, 17615 max_scf_name_len + 1) < 0) 17616 scfdie(); 17617 17618 if (strncmp(buf, arg1, len) == 0) { 17619 err = cpl_add_completion(cpl, line, word_start, 17620 word_end, buf + len, "", " "); 17621 if (err != 0) 17622 break; 17623 } 17624 } 17625 17626 scf_iter_destroy(iter); 17627 scf_service_destroy(svc); 17628 17629 return (err); 17630 } 17631 } 17632 17633 /* ARGSUSED */ 17634 CPL_MATCH_FN(complete_command) 17635 { 17636 uint32_t scope = 0; 17637 17638 if (cur_snap != NULL) 17639 scope = CS_SNAP; 17640 else if (cur_inst != NULL) 17641 scope = CS_INST; 17642 else if (cur_svc != NULL) 17643 scope = CS_SVC; 17644 else 17645 scope = CS_SCOPE; 17646 17647 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 17648 } 17649 #endif /* NATIVE_BUILD */ 17650