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 2015 Joyent, Inc. 25 * Copyright 2012 Milan Jurik. All rights reserved. 26 */ 27 28 29 #include <alloca.h> 30 #include <assert.h> 31 #include <ctype.h> 32 #include <door.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <fnmatch.h> 36 #include <inttypes.h> 37 #include <libintl.h> 38 #include <libnvpair.h> 39 #include <libscf.h> 40 #include <libscf_priv.h> 41 #include <libtecla.h> 42 #include <libuutil.h> 43 #include <limits.h> 44 #include <locale.h> 45 #include <stdarg.h> 46 #include <string.h> 47 #include <strings.h> 48 #include <time.h> 49 #include <unistd.h> 50 #include <wait.h> 51 #include <poll.h> 52 53 #include <libxml/tree.h> 54 55 #include <sys/param.h> 56 57 #include <sys/stat.h> 58 #include <sys/mman.h> 59 60 #include "svccfg.h" 61 #include "notify_params.h" 62 #include "manifest_hash.h" 63 #include "manifest_find.h" 64 65 /* The colon namespaces in each entity (each followed by a newline). */ 66 #define COLON_NAMESPACES ":properties\n" 67 68 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 69 70 /* These are characters which the lexer requires to be in double-quotes. */ 71 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 72 73 #define HASH_SIZE 16 74 #define HASH_PG_TYPE "framework" 75 #define HASH_PG_FLAGS 0 76 #define HASH_PROP "md5sum" 77 78 /* 79 * Indentation used in the output of the describe subcommand. 80 */ 81 #define TMPL_VALUE_INDENT " " 82 #define TMPL_INDENT " " 83 #define TMPL_INDENT_2X " " 84 #define TMPL_CHOICE_INDENT " " 85 86 /* 87 * Directory locations for manifests 88 */ 89 #define VARSVC_DIR "/var/svc/manifest" 90 #define LIBSVC_DIR "/lib/svc/manifest" 91 #define VARSVC_PR "var_svc_manifest" 92 #define LIBSVC_PR "lib_svc_manifest" 93 #define MFSTFILEPR "manifestfile" 94 95 #define SUPPORTPROP "support" 96 97 #define MFSTHISTFILE "/lib/svc/share/mfsthistory" 98 99 #define MFSTFILE_MAX 16 100 101 /* 102 * These are the classes of elements which may appear as children of service 103 * or instance elements in XML manifests. 104 */ 105 struct entity_elts { 106 xmlNodePtr create_default_instance; 107 xmlNodePtr single_instance; 108 xmlNodePtr restarter; 109 xmlNodePtr dependencies; 110 xmlNodePtr dependents; 111 xmlNodePtr method_context; 112 xmlNodePtr exec_methods; 113 xmlNodePtr notify_params; 114 xmlNodePtr property_groups; 115 xmlNodePtr instances; 116 xmlNodePtr stability; 117 xmlNodePtr template; 118 }; 119 120 /* 121 * Likewise for property_group elements. 122 */ 123 struct pg_elts { 124 xmlNodePtr stability; 125 xmlNodePtr propvals; 126 xmlNodePtr properties; 127 }; 128 129 /* 130 * Likewise for template elements. 131 */ 132 struct template_elts { 133 xmlNodePtr common_name; 134 xmlNodePtr description; 135 xmlNodePtr documentation; 136 }; 137 138 /* 139 * Likewise for type (for notification parameters) elements. 140 */ 141 struct params_elts { 142 xmlNodePtr paramval; 143 xmlNodePtr parameter; 144 }; 145 146 /* 147 * This structure is for snaplevel lists. They are convenient because libscf 148 * only allows traversing snaplevels in one direction. 149 */ 150 struct snaplevel { 151 uu_list_node_t list_node; 152 scf_snaplevel_t *sl; 153 }; 154 155 /* 156 * This is used for communication between lscf_service_export and 157 * export_callback. 158 */ 159 struct export_args { 160 const char *filename; 161 int flags; 162 }; 163 164 /* 165 * The service_manifest structure is used by the upgrade process 166 * to create a list of service to manifest linkages from the manifests 167 * in a set of given directories. 168 */ 169 typedef struct service_manifest { 170 const char *servicename; 171 uu_list_t *mfstlist; 172 size_t mfstlist_sz; 173 174 uu_avl_node_t svcmfst_node; 175 } service_manifest_t; 176 177 /* 178 * Structure to track the manifest file property group 179 * and the manifest file associated with that property 180 * group. Also, a flag to keep the access once it has 181 * been checked. 182 */ 183 struct mpg_mfile { 184 char *mpg; 185 char *mfile; 186 int access; 187 }; 188 189 const char * const scf_pg_general = SCF_PG_GENERAL; 190 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 191 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 192 const char * const scf_property_external = "external"; 193 194 const char * const snap_initial = "initial"; 195 const char * const snap_lastimport = "last-import"; 196 const char * const snap_previous = "previous"; 197 const char * const snap_running = "running"; 198 199 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 200 201 ssize_t max_scf_fmri_len; 202 ssize_t max_scf_name_len; 203 ssize_t max_scf_pg_type_len; 204 ssize_t max_scf_value_len; 205 static size_t max_scf_len; 206 207 static scf_scope_t *cur_scope; 208 static scf_service_t *cur_svc = NULL; 209 static scf_instance_t *cur_inst = NULL; 210 static scf_snapshot_t *cur_snap = NULL; 211 static scf_snaplevel_t *cur_level = NULL; 212 213 static uu_list_pool_t *snaplevel_pool; 214 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 215 static uu_list_t *cur_levels; 216 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 217 218 static FILE *tempfile = NULL; 219 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 220 221 static const char *emsg_entity_not_selected; 222 static const char *emsg_permission_denied; 223 static const char *emsg_create_xml; 224 static const char *emsg_cant_modify_snapshots; 225 static const char *emsg_invalid_for_snapshot; 226 static const char *emsg_read_only; 227 static const char *emsg_deleted; 228 static const char *emsg_invalid_pg_name; 229 static const char *emsg_invalid_prop_name; 230 static const char *emsg_no_such_pg; 231 static const char *emsg_fmri_invalid_pg_name; 232 static const char *emsg_fmri_invalid_pg_name_type; 233 static const char *emsg_pg_added; 234 static const char *emsg_pg_changed; 235 static const char *emsg_pg_deleted; 236 static const char *emsg_pg_mod_perm; 237 static const char *emsg_pg_add_perm; 238 static const char *emsg_pg_del_perm; 239 static const char *emsg_snap_perm; 240 static const char *emsg_dpt_dangling; 241 static const char *emsg_dpt_no_dep; 242 243 static int li_only = 0; 244 static int no_refresh = 0; 245 246 /* how long in ns we should wait between checks for a pg */ 247 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC); 248 249 /* import globals, to minimize allocations */ 250 static scf_scope_t *imp_scope = NULL; 251 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 252 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 253 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 254 static scf_snapshot_t *imp_rsnap = NULL; 255 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 256 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 257 static scf_property_t *imp_prop = NULL; 258 static scf_iter_t *imp_iter = NULL; 259 static scf_iter_t *imp_rpg_iter = NULL; 260 static scf_iter_t *imp_up_iter = NULL; 261 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 262 static char *imp_str = NULL; 263 static size_t imp_str_sz; 264 static char *imp_tsname = NULL; 265 static char *imp_fe1 = NULL; /* for fmri_equal() */ 266 static char *imp_fe2 = NULL; 267 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 268 269 /* upgrade_dependents() globals */ 270 static scf_instance_t *ud_inst = NULL; 271 static scf_snaplevel_t *ud_snpl = NULL; 272 static scf_propertygroup_t *ud_pg = NULL; 273 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 274 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 275 static int ud_run_dpts_pg_set = 0; 276 static scf_property_t *ud_prop = NULL; 277 static scf_property_t *ud_dpt_prop = NULL; 278 static scf_value_t *ud_val = NULL; 279 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 280 static scf_transaction_t *ud_tx = NULL; 281 static char *ud_ctarg = NULL; 282 static char *ud_oldtarg = NULL; 283 static char *ud_name = NULL; 284 285 /* export globals */ 286 static scf_instance_t *exp_inst; 287 static scf_propertygroup_t *exp_pg; 288 static scf_property_t *exp_prop; 289 static scf_value_t *exp_val; 290 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 291 static char *exp_str; 292 static size_t exp_str_sz; 293 294 /* cleanup globals */ 295 static uu_avl_pool_t *service_manifest_pool = NULL; 296 static uu_avl_t *service_manifest_tree = NULL; 297 298 static void scfdie_lineno(int lineno) __NORETURN; 299 300 static char *start_method_names[] = { 301 "start", 302 "inetd_start", 303 NULL 304 }; 305 306 static struct uri_scheme { 307 const char *scheme; 308 const char *protocol; 309 } uri_scheme[] = { 310 { "mailto", "smtp" }, 311 { "snmp", "snmp" }, 312 { "syslog", "syslog" }, 313 { NULL, NULL } 314 }; 315 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \ 316 sizeof (struct uri_scheme)) - 1) 317 318 static int 319 check_uri_scheme(const char *scheme) 320 { 321 int i; 322 323 for (i = 0; uri_scheme[i].scheme != NULL; ++i) { 324 if (strcmp(scheme, uri_scheme[i].scheme) == 0) 325 return (i); 326 } 327 328 return (-1); 329 } 330 331 static int 332 check_uri_protocol(const char *p) 333 { 334 int i; 335 336 for (i = 0; uri_scheme[i].protocol != NULL; ++i) { 337 if (strcmp(p, uri_scheme[i].protocol) == 0) 338 return (i); 339 } 340 341 return (-1); 342 } 343 344 /* 345 * For unexpected libscf errors. 346 */ 347 #ifdef NDEBUG 348 349 static void scfdie(void) __NORETURN; 350 351 static void 352 scfdie(void) 353 { 354 scf_error_t err = scf_error(); 355 356 if (err == SCF_ERROR_CONNECTION_BROKEN) 357 uu_die(gettext("Repository connection broken. Exiting.\n")); 358 359 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 360 scf_strerror(err)); 361 } 362 363 #else 364 365 #define scfdie() scfdie_lineno(__LINE__) 366 367 static void 368 scfdie_lineno(int lineno) 369 { 370 scf_error_t err = scf_error(); 371 372 if (err == SCF_ERROR_CONNECTION_BROKEN) 373 uu_die(gettext("Repository connection broken. Exiting.\n")); 374 375 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 376 ": %s.\n"), lineno, scf_strerror(err)); 377 } 378 379 #endif 380 381 static void 382 scfwarn(void) 383 { 384 warn(gettext("Unexpected libscf error: %s.\n"), 385 scf_strerror(scf_error())); 386 } 387 388 /* 389 * Clear a field of a structure. 390 */ 391 static int 392 clear_int(void *a, void *b) 393 { 394 /* LINTED */ 395 *(int *)((char *)a + (size_t)b) = 0; 396 397 return (UU_WALK_NEXT); 398 } 399 400 static int 401 scferror2errno(scf_error_t err) 402 { 403 switch (err) { 404 case SCF_ERROR_BACKEND_ACCESS: 405 return (EACCES); 406 407 case SCF_ERROR_BACKEND_READONLY: 408 return (EROFS); 409 410 case SCF_ERROR_CONNECTION_BROKEN: 411 return (ECONNABORTED); 412 413 case SCF_ERROR_CONSTRAINT_VIOLATED: 414 case SCF_ERROR_INVALID_ARGUMENT: 415 return (EINVAL); 416 417 case SCF_ERROR_DELETED: 418 return (ECANCELED); 419 420 case SCF_ERROR_EXISTS: 421 return (EEXIST); 422 423 case SCF_ERROR_NO_MEMORY: 424 return (ENOMEM); 425 426 case SCF_ERROR_NO_RESOURCES: 427 return (ENOSPC); 428 429 case SCF_ERROR_NOT_FOUND: 430 return (ENOENT); 431 432 case SCF_ERROR_PERMISSION_DENIED: 433 return (EPERM); 434 435 default: 436 #ifndef NDEBUG 437 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 438 __FILE__, __LINE__, err); 439 #else 440 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 441 #endif 442 abort(); 443 /* NOTREACHED */ 444 } 445 } 446 447 static int 448 entity_get_pg(void *ent, int issvc, const char *name, 449 scf_propertygroup_t *pg) 450 { 451 if (issvc) 452 return (scf_service_get_pg(ent, name, pg)); 453 else 454 return (scf_instance_get_pg(ent, name, pg)); 455 } 456 457 static void 458 entity_destroy(void *ent, int issvc) 459 { 460 if (issvc) 461 scf_service_destroy(ent); 462 else 463 scf_instance_destroy(ent); 464 } 465 466 static int 467 get_pg(const char *pg_name, scf_propertygroup_t *pg) 468 { 469 int ret; 470 471 if (cur_level != NULL) 472 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 473 else if (cur_inst != NULL) 474 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 475 else 476 ret = scf_service_get_pg(cur_svc, pg_name, pg); 477 478 return (ret); 479 } 480 481 /* 482 * Find a snaplevel in a snapshot. If get_svc is true, find the service 483 * snaplevel. Otherwise find the instance snaplevel. 484 * 485 * Returns 486 * 0 - success 487 * ECONNABORTED - repository connection broken 488 * ECANCELED - instance containing snap was deleted 489 * ENOENT - snap has no snaplevels 490 * - requested snaplevel not found 491 */ 492 static int 493 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 494 { 495 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 496 switch (scf_error()) { 497 case SCF_ERROR_CONNECTION_BROKEN: 498 case SCF_ERROR_DELETED: 499 case SCF_ERROR_NOT_FOUND: 500 return (scferror2errno(scf_error())); 501 502 case SCF_ERROR_HANDLE_MISMATCH: 503 case SCF_ERROR_NOT_BOUND: 504 case SCF_ERROR_NOT_SET: 505 default: 506 bad_error("scf_snapshot_get_base_snaplevel", 507 scf_error()); 508 } 509 } 510 511 for (;;) { 512 ssize_t ssz; 513 514 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 515 if (ssz >= 0) { 516 if (!get_svc) 517 return (0); 518 } else { 519 switch (scf_error()) { 520 case SCF_ERROR_CONSTRAINT_VIOLATED: 521 if (get_svc) 522 return (0); 523 break; 524 525 case SCF_ERROR_DELETED: 526 case SCF_ERROR_CONNECTION_BROKEN: 527 return (scferror2errno(scf_error())); 528 529 case SCF_ERROR_NOT_SET: 530 case SCF_ERROR_NOT_BOUND: 531 default: 532 bad_error("scf_snaplevel_get_instance_name", 533 scf_error()); 534 } 535 } 536 537 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 538 switch (scf_error()) { 539 case SCF_ERROR_NOT_FOUND: 540 case SCF_ERROR_CONNECTION_BROKEN: 541 case SCF_ERROR_DELETED: 542 return (scferror2errno(scf_error())); 543 544 case SCF_ERROR_HANDLE_MISMATCH: 545 case SCF_ERROR_NOT_BOUND: 546 case SCF_ERROR_NOT_SET: 547 case SCF_ERROR_INVALID_ARGUMENT: 548 default: 549 bad_error("scf_snaplevel_get_next_snaplevel", 550 scf_error()); 551 } 552 } 553 } 554 } 555 556 /* 557 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 558 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 559 * the property group named name in it. If it doesn't have a running 560 * snapshot, set pg to the instance's current property group named name. 561 * 562 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 563 * its instances. If one has a running snapshot with a service snaplevel, set 564 * pg to the property group named name in it. If no such snaplevel could be 565 * found, set pg to the service's current property group named name. 566 * 567 * iter, inst, snap, and snpl are required scratch objects. 568 * 569 * Returns 570 * 0 - success 571 * ECONNABORTED - repository connection broken 572 * ECANCELED - ent was deleted 573 * ENOENT - no such property group 574 * EINVAL - name is an invalid property group name 575 * EBADF - found running snapshot is missing a snaplevel 576 */ 577 static int 578 entity_get_running_pg(void *ent, int issvc, const char *name, 579 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 580 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 581 { 582 int r; 583 584 if (issvc) { 585 /* Search for an instance with a running snapshot. */ 586 if (scf_iter_service_instances(iter, ent) != 0) { 587 switch (scf_error()) { 588 case SCF_ERROR_DELETED: 589 case SCF_ERROR_CONNECTION_BROKEN: 590 return (scferror2errno(scf_error())); 591 592 case SCF_ERROR_NOT_SET: 593 case SCF_ERROR_NOT_BOUND: 594 case SCF_ERROR_HANDLE_MISMATCH: 595 default: 596 bad_error("scf_iter_service_instances", 597 scf_error()); 598 } 599 } 600 601 for (;;) { 602 r = scf_iter_next_instance(iter, inst); 603 if (r == 0) { 604 if (scf_service_get_pg(ent, name, pg) == 0) 605 return (0); 606 607 switch (scf_error()) { 608 case SCF_ERROR_DELETED: 609 case SCF_ERROR_NOT_FOUND: 610 case SCF_ERROR_INVALID_ARGUMENT: 611 case SCF_ERROR_CONNECTION_BROKEN: 612 return (scferror2errno(scf_error())); 613 614 case SCF_ERROR_NOT_BOUND: 615 case SCF_ERROR_HANDLE_MISMATCH: 616 case SCF_ERROR_NOT_SET: 617 default: 618 bad_error("scf_service_get_pg", 619 scf_error()); 620 } 621 } 622 if (r != 1) { 623 switch (scf_error()) { 624 case SCF_ERROR_DELETED: 625 case SCF_ERROR_CONNECTION_BROKEN: 626 return (scferror2errno(scf_error())); 627 628 case SCF_ERROR_INVALID_ARGUMENT: 629 case SCF_ERROR_NOT_SET: 630 case SCF_ERROR_NOT_BOUND: 631 case SCF_ERROR_HANDLE_MISMATCH: 632 default: 633 bad_error("scf_iter_next_instance", 634 scf_error()); 635 } 636 } 637 638 if (scf_instance_get_snapshot(inst, snap_running, 639 snap) == 0) 640 break; 641 642 switch (scf_error()) { 643 case SCF_ERROR_NOT_FOUND: 644 case SCF_ERROR_DELETED: 645 continue; 646 647 case SCF_ERROR_CONNECTION_BROKEN: 648 return (ECONNABORTED); 649 650 case SCF_ERROR_HANDLE_MISMATCH: 651 case SCF_ERROR_INVALID_ARGUMENT: 652 case SCF_ERROR_NOT_SET: 653 case SCF_ERROR_NOT_BOUND: 654 default: 655 bad_error("scf_instance_get_snapshot", 656 scf_error()); 657 } 658 } 659 } else { 660 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 661 switch (scf_error()) { 662 case SCF_ERROR_NOT_FOUND: 663 break; 664 665 case SCF_ERROR_DELETED: 666 case SCF_ERROR_CONNECTION_BROKEN: 667 return (scferror2errno(scf_error())); 668 669 case SCF_ERROR_NOT_BOUND: 670 case SCF_ERROR_HANDLE_MISMATCH: 671 case SCF_ERROR_INVALID_ARGUMENT: 672 case SCF_ERROR_NOT_SET: 673 default: 674 bad_error("scf_instance_get_snapshot", 675 scf_error()); 676 } 677 678 if (scf_instance_get_pg(ent, name, pg) == 0) 679 return (0); 680 681 switch (scf_error()) { 682 case SCF_ERROR_DELETED: 683 case SCF_ERROR_NOT_FOUND: 684 case SCF_ERROR_INVALID_ARGUMENT: 685 case SCF_ERROR_CONNECTION_BROKEN: 686 return (scferror2errno(scf_error())); 687 688 case SCF_ERROR_NOT_BOUND: 689 case SCF_ERROR_HANDLE_MISMATCH: 690 case SCF_ERROR_NOT_SET: 691 default: 692 bad_error("scf_instance_get_pg", scf_error()); 693 } 694 } 695 } 696 697 r = get_snaplevel(snap, issvc, snpl); 698 switch (r) { 699 case 0: 700 break; 701 702 case ECONNABORTED: 703 case ECANCELED: 704 return (r); 705 706 case ENOENT: 707 return (EBADF); 708 709 default: 710 bad_error("get_snaplevel", r); 711 } 712 713 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 714 return (0); 715 716 switch (scf_error()) { 717 case SCF_ERROR_DELETED: 718 case SCF_ERROR_INVALID_ARGUMENT: 719 case SCF_ERROR_CONNECTION_BROKEN: 720 case SCF_ERROR_NOT_FOUND: 721 return (scferror2errno(scf_error())); 722 723 case SCF_ERROR_NOT_BOUND: 724 case SCF_ERROR_HANDLE_MISMATCH: 725 case SCF_ERROR_NOT_SET: 726 default: 727 bad_error("scf_snaplevel_get_pg", scf_error()); 728 /* NOTREACHED */ 729 } 730 } 731 732 /* 733 * To be registered with atexit(). 734 */ 735 static void 736 remove_tempfile(void) 737 { 738 int ret; 739 740 if (tempfile != NULL) { 741 if (fclose(tempfile) == EOF) 742 (void) warn(gettext("Could not close temporary file")); 743 tempfile = NULL; 744 } 745 746 if (tempfilename[0] != '\0') { 747 do { 748 ret = remove(tempfilename); 749 } while (ret == -1 && errno == EINTR); 750 if (ret == -1) 751 warn(gettext("Could not remove temporary file")); 752 tempfilename[0] = '\0'; 753 } 754 } 755 756 /* 757 * Launch private svc.configd(1M) for manipulating alternate repositories. 758 */ 759 static void 760 start_private_repository(engine_state_t *est) 761 { 762 int fd, stat; 763 struct door_info info; 764 pid_t pid; 765 766 /* 767 * 1. Create a temporary file for the door. 768 */ 769 if (est->sc_repo_doorname != NULL) 770 free((void *)est->sc_repo_doorname); 771 772 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 773 if (est->sc_repo_doorname == NULL) 774 uu_die(gettext("Could not acquire temporary filename")); 775 776 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 777 if (fd < 0) 778 uu_die(gettext("Could not create temporary file for " 779 "repository server")); 780 781 (void) close(fd); 782 783 /* 784 * 2. Launch a configd with that door, using the specified 785 * repository. 786 */ 787 if ((est->sc_repo_pid = fork()) == 0) { 788 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 789 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 790 NULL); 791 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 792 } else if (est->sc_repo_pid == -1) 793 uu_die(gettext("Attempt to fork failed")); 794 795 do { 796 pid = waitpid(est->sc_repo_pid, &stat, 0); 797 } while (pid == -1 && errno == EINTR); 798 799 if (pid == -1) 800 uu_die(gettext("Could not waitpid() for repository server")); 801 802 if (!WIFEXITED(stat)) { 803 uu_die(gettext("Repository server failed (status %d).\n"), 804 stat); 805 } else if (WEXITSTATUS(stat) != 0) { 806 uu_die(gettext("Repository server failed (exit %d).\n"), 807 WEXITSTATUS(stat)); 808 } 809 810 /* 811 * See if it was successful by checking if the door is a door. 812 */ 813 814 fd = open(est->sc_repo_doorname, O_RDWR); 815 if (fd < 0) 816 uu_die(gettext("Could not open door \"%s\""), 817 est->sc_repo_doorname); 818 819 if (door_info(fd, &info) < 0) 820 uu_die(gettext("Unexpected door_info() error")); 821 822 if (close(fd) == -1) 823 warn(gettext("Could not close repository door"), 824 strerror(errno)); 825 826 est->sc_repo_pid = info.di_target; 827 } 828 829 void 830 lscf_cleanup(void) 831 { 832 /* 833 * In the case where we've launched a private svc.configd(1M) 834 * instance, we must terminate our child and remove the temporary 835 * rendezvous point. 836 */ 837 if (est->sc_repo_pid > 0) { 838 (void) kill(est->sc_repo_pid, SIGTERM); 839 (void) waitpid(est->sc_repo_pid, NULL, 0); 840 (void) unlink(est->sc_repo_doorname); 841 842 est->sc_repo_pid = 0; 843 } 844 } 845 846 void 847 unselect_cursnap(void) 848 { 849 void *cookie; 850 851 cur_level = NULL; 852 853 cookie = NULL; 854 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 855 scf_snaplevel_destroy(cur_elt->sl); 856 free(cur_elt); 857 } 858 859 scf_snapshot_destroy(cur_snap); 860 cur_snap = NULL; 861 } 862 863 void 864 lscf_prep_hndl(void) 865 { 866 if (g_hndl != NULL) 867 return; 868 869 g_hndl = scf_handle_create(SCF_VERSION); 870 if (g_hndl == NULL) 871 scfdie(); 872 873 if (est->sc_repo_filename != NULL) 874 start_private_repository(est); 875 876 if (est->sc_repo_doorname != NULL) { 877 scf_value_t *repo_value; 878 int ret; 879 880 repo_value = scf_value_create(g_hndl); 881 if (repo_value == NULL) 882 scfdie(); 883 884 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 885 assert(ret == SCF_SUCCESS); 886 887 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 888 SCF_SUCCESS) 889 scfdie(); 890 891 scf_value_destroy(repo_value); 892 } 893 894 if (scf_handle_bind(g_hndl) != 0) 895 uu_die(gettext("Could not connect to repository server: %s.\n"), 896 scf_strerror(scf_error())); 897 898 cur_scope = scf_scope_create(g_hndl); 899 if (cur_scope == NULL) 900 scfdie(); 901 902 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 903 scfdie(); 904 } 905 906 static void 907 repository_teardown(void) 908 { 909 if (g_hndl != NULL) { 910 if (cur_snap != NULL) 911 unselect_cursnap(); 912 scf_instance_destroy(cur_inst); 913 scf_service_destroy(cur_svc); 914 scf_scope_destroy(cur_scope); 915 scf_handle_destroy(g_hndl); 916 cur_inst = NULL; 917 cur_svc = NULL; 918 cur_scope = NULL; 919 g_hndl = NULL; 920 lscf_cleanup(); 921 } 922 } 923 924 void 925 lscf_set_repository(const char *repfile, int force) 926 { 927 repository_teardown(); 928 929 if (est->sc_repo_filename != NULL) { 930 free((void *)est->sc_repo_filename); 931 est->sc_repo_filename = NULL; 932 } 933 934 if ((force == 0) && (access(repfile, R_OK) != 0)) { 935 /* 936 * Repository file does not exist 937 * or has no read permission. 938 */ 939 warn(gettext("Cannot access \"%s\": %s\n"), 940 repfile, strerror(errno)); 941 } else { 942 est->sc_repo_filename = safe_strdup(repfile); 943 } 944 945 lscf_prep_hndl(); 946 } 947 948 void 949 lscf_init() 950 { 951 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 952 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 953 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 954 0 || 955 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 956 scfdie(); 957 958 max_scf_len = max_scf_fmri_len; 959 if (max_scf_name_len > max_scf_len) 960 max_scf_len = max_scf_name_len; 961 if (max_scf_pg_type_len > max_scf_len) 962 max_scf_len = max_scf_pg_type_len; 963 /* 964 * When a value of type opaque is represented as a string, the 965 * string contains 2 characters for every byte of data. That is 966 * because the string contains the hex representation of the opaque 967 * value. 968 */ 969 if (2 * max_scf_value_len > max_scf_len) 970 max_scf_len = 2 * max_scf_value_len; 971 972 if (atexit(remove_tempfile) != 0) 973 uu_die(gettext("Could not register atexit() function")); 974 975 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 976 emsg_permission_denied = gettext("Permission denied.\n"); 977 emsg_create_xml = gettext("Could not create XML node.\n"); 978 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 979 emsg_invalid_for_snapshot = 980 gettext("Invalid operation on a snapshot.\n"); 981 emsg_read_only = gettext("Backend read-only.\n"); 982 emsg_deleted = gettext("Current selection has been deleted.\n"); 983 emsg_invalid_pg_name = 984 gettext("Invalid property group name \"%s\".\n"); 985 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 986 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 987 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 988 "with invalid name \"%s\".\n"); 989 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 990 "group with invalid name \"%s\" or type \"%s\".\n"); 991 emsg_pg_added = gettext("%s changed unexpectedly " 992 "(property group \"%s\" added).\n"); 993 emsg_pg_changed = gettext("%s changed unexpectedly " 994 "(property group \"%s\" changed).\n"); 995 emsg_pg_deleted = gettext("%s changed unexpectedly " 996 "(property group \"%s\" or an ancestor was deleted).\n"); 997 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 998 "in %s (permission denied).\n"); 999 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 1000 "in %s (permission denied).\n"); 1001 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 1002 "in %s (permission denied).\n"); 1003 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 1004 "(permission denied).\n"); 1005 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 1006 "new dependent \"%s\" because it already exists). Warning: The " 1007 "current dependent's target (%s) does not exist.\n"); 1008 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 1009 "dependent \"%s\" because it already exists). Warning: The " 1010 "current dependent's target (%s) does not have a dependency named " 1011 "\"%s\" as expected.\n"); 1012 1013 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 1014 offsetof(string_list_t, node), NULL, 0); 1015 snaplevel_pool = uu_list_pool_create("snaplevels", 1016 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 1017 NULL, 0); 1018 } 1019 1020 1021 static const char * 1022 prop_to_typestr(const scf_property_t *prop) 1023 { 1024 scf_type_t ty; 1025 1026 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 1027 scfdie(); 1028 1029 return (scf_type_to_string(ty)); 1030 } 1031 1032 static scf_type_t 1033 string_to_type(const char *type) 1034 { 1035 size_t len = strlen(type); 1036 char *buf; 1037 1038 if (len == 0 || type[len - 1] != ':') 1039 return (SCF_TYPE_INVALID); 1040 1041 buf = (char *)alloca(len + 1); 1042 (void) strlcpy(buf, type, len + 1); 1043 buf[len - 1] = 0; 1044 1045 return (scf_string_to_type(buf)); 1046 } 1047 1048 static scf_value_t * 1049 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 1050 { 1051 scf_value_t *v; 1052 char *dup, *nstr; 1053 size_t len; 1054 1055 v = scf_value_create(g_hndl); 1056 if (v == NULL) 1057 scfdie(); 1058 1059 len = strlen(str); 1060 if (require_quotes && 1061 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1062 semerr(gettext("Multiple string values or string values " 1063 "with spaces must be quoted with '\"'.\n")); 1064 scf_value_destroy(v); 1065 return (NULL); 1066 } 1067 1068 nstr = dup = safe_strdup(str); 1069 if (dup[0] == '\"') { 1070 /* 1071 * Strip out the first and the last quote. 1072 */ 1073 dup[len - 1] = '\0'; 1074 nstr = dup + 1; 1075 } 1076 1077 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1078 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1079 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1080 scf_type_to_string(ty), nstr); 1081 scf_value_destroy(v); 1082 v = NULL; 1083 } 1084 free(dup); 1085 return (v); 1086 } 1087 1088 /* 1089 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1090 * Optionally append a comment prefix ('#') to newlines ('\n'). 1091 */ 1092 static int 1093 quote_and_print(const char *str, FILE *strm, int commentnl) 1094 { 1095 const char *cp; 1096 1097 for (cp = str; *cp != '\0'; ++cp) { 1098 if (*cp == '"' || *cp == '\\') 1099 (void) putc('\\', strm); 1100 1101 (void) putc(*cp, strm); 1102 1103 if (commentnl && *cp == '\n') { 1104 (void) putc('#', strm); 1105 } 1106 } 1107 1108 return (ferror(strm)); 1109 } 1110 1111 /* 1112 * These wrappers around lowlevel functions provide consistent error checking 1113 * and warnings. 1114 */ 1115 static int 1116 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1117 { 1118 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1119 return (0); 1120 1121 if (scf_error() != SCF_ERROR_NOT_FOUND) 1122 scfdie(); 1123 1124 if (g_verbose) { 1125 ssize_t len; 1126 char *fmri; 1127 1128 len = scf_pg_to_fmri(pg, NULL, 0); 1129 if (len < 0) 1130 scfdie(); 1131 1132 fmri = safe_malloc(len + 1); 1133 1134 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1135 scfdie(); 1136 1137 warn(gettext("Expected property %s of property group %s is " 1138 "missing.\n"), propname, fmri); 1139 1140 free(fmri); 1141 } 1142 1143 return (-1); 1144 } 1145 1146 static int 1147 prop_check_type(scf_property_t *prop, scf_type_t ty) 1148 { 1149 scf_type_t pty; 1150 1151 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1152 scfdie(); 1153 1154 if (ty == pty) 1155 return (0); 1156 1157 if (g_verbose) { 1158 ssize_t len; 1159 char *fmri; 1160 const char *tystr; 1161 1162 len = scf_property_to_fmri(prop, NULL, 0); 1163 if (len < 0) 1164 scfdie(); 1165 1166 fmri = safe_malloc(len + 1); 1167 1168 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1169 scfdie(); 1170 1171 tystr = scf_type_to_string(ty); 1172 if (tystr == NULL) 1173 tystr = "?"; 1174 1175 warn(gettext("Property %s is not of expected type %s.\n"), 1176 fmri, tystr); 1177 1178 free(fmri); 1179 } 1180 1181 return (-1); 1182 } 1183 1184 static int 1185 prop_get_val(scf_property_t *prop, scf_value_t *val) 1186 { 1187 scf_error_t err; 1188 1189 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1190 return (0); 1191 1192 err = scf_error(); 1193 1194 if (err != SCF_ERROR_NOT_FOUND && 1195 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1196 err != SCF_ERROR_PERMISSION_DENIED) 1197 scfdie(); 1198 1199 if (g_verbose) { 1200 ssize_t len; 1201 char *fmri, *emsg; 1202 1203 len = scf_property_to_fmri(prop, NULL, 0); 1204 if (len < 0) 1205 scfdie(); 1206 1207 fmri = safe_malloc(len + 1); 1208 1209 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1210 scfdie(); 1211 1212 if (err == SCF_ERROR_NOT_FOUND) 1213 emsg = gettext("Property %s has no values; expected " 1214 "one.\n"); 1215 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1216 emsg = gettext("Property %s has multiple values; " 1217 "expected one.\n"); 1218 else 1219 emsg = gettext("No permission to read property %s.\n"); 1220 1221 warn(emsg, fmri); 1222 1223 free(fmri); 1224 } 1225 1226 return (-1); 1227 } 1228 1229 1230 static boolean_t 1231 snaplevel_is_instance(const scf_snaplevel_t *level) 1232 { 1233 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1234 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1235 scfdie(); 1236 return (0); 1237 } else { 1238 return (1); 1239 } 1240 } 1241 1242 /* 1243 * Decode FMRI into a service or instance, and put the result in *ep. If 1244 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1245 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1246 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1247 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1248 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1249 * whether *ep is a service. 1250 */ 1251 static scf_error_t 1252 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1253 { 1254 char *fmri_copy; 1255 const char *sstr, *istr, *pgstr; 1256 scf_service_t *svc; 1257 scf_instance_t *inst; 1258 1259 fmri_copy = strdup(fmri); 1260 if (fmri_copy == NULL) 1261 return (SCF_ERROR_NO_MEMORY); 1262 1263 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1264 SCF_SUCCESS) { 1265 free(fmri_copy); 1266 return (SCF_ERROR_INVALID_ARGUMENT); 1267 } 1268 1269 free(fmri_copy); 1270 1271 if (sstr == NULL || pgstr != NULL) 1272 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1273 1274 if (istr == NULL) { 1275 svc = scf_service_create(h); 1276 if (svc == NULL) 1277 return (SCF_ERROR_NO_MEMORY); 1278 1279 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1280 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1281 if (scf_error() != SCF_ERROR_NOT_FOUND) 1282 scfdie(); 1283 1284 return (SCF_ERROR_NOT_FOUND); 1285 } 1286 1287 *ep = svc; 1288 *isservice = 1; 1289 } else { 1290 inst = scf_instance_create(h); 1291 if (inst == NULL) 1292 return (SCF_ERROR_NO_MEMORY); 1293 1294 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1295 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1296 if (scf_error() != SCF_ERROR_NOT_FOUND) 1297 scfdie(); 1298 1299 return (SCF_ERROR_NOT_FOUND); 1300 } 1301 1302 *ep = inst; 1303 *isservice = 0; 1304 } 1305 1306 return (SCF_ERROR_NONE); 1307 } 1308 1309 /* 1310 * Create the entity named by fmri. Place a pointer to its libscf handle in 1311 * *ep, and set or clear *isservicep if it is a service or an instance. 1312 * Returns 1313 * SCF_ERROR_NONE - success 1314 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1315 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1316 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1317 * SCF_ERROR_NOT_FOUND - no such scope 1318 * SCF_ERROR_PERMISSION_DENIED 1319 * SCF_ERROR_BACKEND_READONLY 1320 * SCF_ERROR_BACKEND_ACCESS 1321 */ 1322 static scf_error_t 1323 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1324 { 1325 char *fmri_copy; 1326 const char *scstr, *sstr, *istr, *pgstr; 1327 scf_scope_t *scope = NULL; 1328 scf_service_t *svc = NULL; 1329 scf_instance_t *inst = NULL; 1330 scf_error_t scfe; 1331 1332 fmri_copy = safe_strdup(fmri); 1333 1334 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1335 0) { 1336 free(fmri_copy); 1337 return (SCF_ERROR_INVALID_ARGUMENT); 1338 } 1339 1340 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1341 free(fmri_copy); 1342 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1343 } 1344 1345 *ep = NULL; 1346 1347 if ((scope = scf_scope_create(h)) == NULL || 1348 (svc = scf_service_create(h)) == NULL || 1349 (inst = scf_instance_create(h)) == NULL) { 1350 scfe = SCF_ERROR_NO_MEMORY; 1351 goto out; 1352 } 1353 1354 get_scope: 1355 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1356 switch (scf_error()) { 1357 case SCF_ERROR_CONNECTION_BROKEN: 1358 scfdie(); 1359 /* NOTREACHED */ 1360 1361 case SCF_ERROR_NOT_FOUND: 1362 scfe = SCF_ERROR_NOT_FOUND; 1363 goto out; 1364 1365 case SCF_ERROR_HANDLE_MISMATCH: 1366 case SCF_ERROR_NOT_BOUND: 1367 case SCF_ERROR_INVALID_ARGUMENT: 1368 default: 1369 bad_error("scf_handle_get_scope", scf_error()); 1370 } 1371 } 1372 1373 get_svc: 1374 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1375 switch (scf_error()) { 1376 case SCF_ERROR_CONNECTION_BROKEN: 1377 scfdie(); 1378 /* NOTREACHED */ 1379 1380 case SCF_ERROR_DELETED: 1381 goto get_scope; 1382 1383 case SCF_ERROR_NOT_FOUND: 1384 break; 1385 1386 case SCF_ERROR_HANDLE_MISMATCH: 1387 case SCF_ERROR_INVALID_ARGUMENT: 1388 case SCF_ERROR_NOT_BOUND: 1389 case SCF_ERROR_NOT_SET: 1390 default: 1391 bad_error("scf_scope_get_service", scf_error()); 1392 } 1393 1394 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1395 switch (scf_error()) { 1396 case SCF_ERROR_CONNECTION_BROKEN: 1397 scfdie(); 1398 /* NOTREACHED */ 1399 1400 case SCF_ERROR_DELETED: 1401 goto get_scope; 1402 1403 case SCF_ERROR_PERMISSION_DENIED: 1404 case SCF_ERROR_BACKEND_READONLY: 1405 case SCF_ERROR_BACKEND_ACCESS: 1406 scfe = scf_error(); 1407 goto out; 1408 1409 case SCF_ERROR_HANDLE_MISMATCH: 1410 case SCF_ERROR_INVALID_ARGUMENT: 1411 case SCF_ERROR_NOT_BOUND: 1412 case SCF_ERROR_NOT_SET: 1413 default: 1414 bad_error("scf_scope_get_service", scf_error()); 1415 } 1416 } 1417 } 1418 1419 if (istr == NULL) { 1420 scfe = SCF_ERROR_NONE; 1421 *ep = svc; 1422 *isservicep = 1; 1423 goto out; 1424 } 1425 1426 get_inst: 1427 if (scf_service_get_instance(svc, istr, inst) != 0) { 1428 switch (scf_error()) { 1429 case SCF_ERROR_CONNECTION_BROKEN: 1430 scfdie(); 1431 /* NOTREACHED */ 1432 1433 case SCF_ERROR_DELETED: 1434 goto get_svc; 1435 1436 case SCF_ERROR_NOT_FOUND: 1437 break; 1438 1439 case SCF_ERROR_HANDLE_MISMATCH: 1440 case SCF_ERROR_INVALID_ARGUMENT: 1441 case SCF_ERROR_NOT_BOUND: 1442 case SCF_ERROR_NOT_SET: 1443 default: 1444 bad_error("scf_service_get_instance", scf_error()); 1445 } 1446 1447 if (scf_service_add_instance(svc, istr, inst) != 0) { 1448 switch (scf_error()) { 1449 case SCF_ERROR_CONNECTION_BROKEN: 1450 scfdie(); 1451 /* NOTREACHED */ 1452 1453 case SCF_ERROR_DELETED: 1454 goto get_svc; 1455 1456 case SCF_ERROR_PERMISSION_DENIED: 1457 case SCF_ERROR_BACKEND_READONLY: 1458 case SCF_ERROR_BACKEND_ACCESS: 1459 scfe = scf_error(); 1460 goto out; 1461 1462 case SCF_ERROR_HANDLE_MISMATCH: 1463 case SCF_ERROR_INVALID_ARGUMENT: 1464 case SCF_ERROR_NOT_BOUND: 1465 case SCF_ERROR_NOT_SET: 1466 default: 1467 bad_error("scf_service_add_instance", 1468 scf_error()); 1469 } 1470 } 1471 } 1472 1473 scfe = SCF_ERROR_NONE; 1474 *ep = inst; 1475 *isservicep = 0; 1476 1477 out: 1478 if (*ep != inst) 1479 scf_instance_destroy(inst); 1480 if (*ep != svc) 1481 scf_service_destroy(svc); 1482 scf_scope_destroy(scope); 1483 free(fmri_copy); 1484 return (scfe); 1485 } 1486 1487 /* 1488 * Create or update a snapshot of inst. snap is a required scratch object. 1489 * 1490 * Returns 1491 * 0 - success 1492 * ECONNABORTED - repository connection broken 1493 * EPERM - permission denied 1494 * ENOSPC - configd is out of resources 1495 * ECANCELED - inst was deleted 1496 * -1 - unknown libscf error (message printed) 1497 */ 1498 static int 1499 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1500 { 1501 again: 1502 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1503 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1504 switch (scf_error()) { 1505 case SCF_ERROR_CONNECTION_BROKEN: 1506 case SCF_ERROR_PERMISSION_DENIED: 1507 case SCF_ERROR_NO_RESOURCES: 1508 return (scferror2errno(scf_error())); 1509 1510 case SCF_ERROR_NOT_SET: 1511 case SCF_ERROR_INVALID_ARGUMENT: 1512 default: 1513 bad_error("_scf_snapshot_take_attach", 1514 scf_error()); 1515 } 1516 } 1517 } else { 1518 switch (scf_error()) { 1519 case SCF_ERROR_NOT_FOUND: 1520 break; 1521 1522 case SCF_ERROR_DELETED: 1523 case SCF_ERROR_CONNECTION_BROKEN: 1524 return (scferror2errno(scf_error())); 1525 1526 case SCF_ERROR_HANDLE_MISMATCH: 1527 case SCF_ERROR_NOT_BOUND: 1528 case SCF_ERROR_INVALID_ARGUMENT: 1529 case SCF_ERROR_NOT_SET: 1530 default: 1531 bad_error("scf_instance_get_snapshot", scf_error()); 1532 } 1533 1534 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1535 switch (scf_error()) { 1536 case SCF_ERROR_EXISTS: 1537 goto again; 1538 1539 case SCF_ERROR_CONNECTION_BROKEN: 1540 case SCF_ERROR_NO_RESOURCES: 1541 case SCF_ERROR_PERMISSION_DENIED: 1542 return (scferror2errno(scf_error())); 1543 1544 default: 1545 scfwarn(); 1546 return (-1); 1547 1548 case SCF_ERROR_NOT_SET: 1549 case SCF_ERROR_INTERNAL: 1550 case SCF_ERROR_INVALID_ARGUMENT: 1551 case SCF_ERROR_HANDLE_MISMATCH: 1552 bad_error("_scf_snapshot_take_new", 1553 scf_error()); 1554 } 1555 } 1556 } 1557 1558 return (0); 1559 } 1560 1561 static int 1562 refresh_running_snapshot(void *entity) 1563 { 1564 scf_snapshot_t *snap; 1565 int r; 1566 1567 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1568 scfdie(); 1569 r = take_snap(entity, snap_running, snap); 1570 scf_snapshot_destroy(snap); 1571 1572 return (r); 1573 } 1574 1575 /* 1576 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1577 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1578 * instances. fmri is used for messages. inst, iter, and name_buf are used 1579 * for scratch space. Returns 1580 * 0 - success 1581 * ECONNABORTED - repository connection broken 1582 * ECANCELED - entity was deleted 1583 * EACCES - backend denied access 1584 * EPERM - permission denied 1585 * ENOSPC - repository server out of resources 1586 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1587 */ 1588 static int 1589 refresh_entity(int isservice, void *entity, const char *fmri, 1590 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1591 { 1592 scf_error_t scfe; 1593 int r; 1594 1595 if (!isservice) { 1596 /* 1597 * Let restarter handles refreshing and making new running 1598 * snapshot only if operating on a live repository and not 1599 * running in early import. 1600 */ 1601 if (est->sc_repo_filename == NULL && 1602 est->sc_repo_doorname == NULL && 1603 est->sc_in_emi == 0) { 1604 if (_smf_refresh_instance_i(entity) == 0) { 1605 if (g_verbose) 1606 warn(gettext("Refreshed %s.\n"), fmri); 1607 return (0); 1608 } 1609 1610 switch (scf_error()) { 1611 case SCF_ERROR_BACKEND_ACCESS: 1612 return (EACCES); 1613 1614 case SCF_ERROR_PERMISSION_DENIED: 1615 return (EPERM); 1616 1617 default: 1618 return (-1); 1619 } 1620 } else { 1621 r = refresh_running_snapshot(entity); 1622 switch (r) { 1623 case 0: 1624 break; 1625 1626 case ECONNABORTED: 1627 case ECANCELED: 1628 case EPERM: 1629 case ENOSPC: 1630 break; 1631 1632 default: 1633 bad_error("refresh_running_snapshot", 1634 scf_error()); 1635 } 1636 1637 return (r); 1638 } 1639 } 1640 1641 if (scf_iter_service_instances(iter, entity) != 0) { 1642 switch (scf_error()) { 1643 case SCF_ERROR_CONNECTION_BROKEN: 1644 return (ECONNABORTED); 1645 1646 case SCF_ERROR_DELETED: 1647 return (ECANCELED); 1648 1649 case SCF_ERROR_HANDLE_MISMATCH: 1650 case SCF_ERROR_NOT_BOUND: 1651 case SCF_ERROR_NOT_SET: 1652 default: 1653 bad_error("scf_iter_service_instances", scf_error()); 1654 } 1655 } 1656 1657 for (;;) { 1658 r = scf_iter_next_instance(iter, inst); 1659 if (r == 0) 1660 break; 1661 if (r != 1) { 1662 switch (scf_error()) { 1663 case SCF_ERROR_CONNECTION_BROKEN: 1664 return (ECONNABORTED); 1665 1666 case SCF_ERROR_DELETED: 1667 return (ECANCELED); 1668 1669 case SCF_ERROR_HANDLE_MISMATCH: 1670 case SCF_ERROR_NOT_BOUND: 1671 case SCF_ERROR_NOT_SET: 1672 case SCF_ERROR_INVALID_ARGUMENT: 1673 default: 1674 bad_error("scf_iter_next_instance", 1675 scf_error()); 1676 } 1677 } 1678 1679 /* 1680 * Similarly, just take a new running snapshot if operating on 1681 * a non-live repository or running during early import. 1682 */ 1683 if (est->sc_repo_filename != NULL || 1684 est->sc_repo_doorname != NULL || 1685 est->sc_in_emi == 1) { 1686 r = refresh_running_snapshot(inst); 1687 switch (r) { 1688 case 0: 1689 continue; 1690 1691 case ECONNABORTED: 1692 case ECANCELED: 1693 case EPERM: 1694 case ENOSPC: 1695 break; 1696 default: 1697 bad_error("refresh_running_snapshot", 1698 scf_error()); 1699 } 1700 1701 return (r); 1702 1703 } 1704 1705 if (_smf_refresh_instance_i(inst) == 0) { 1706 if (g_verbose) { 1707 if (scf_instance_get_name(inst, name_buf, 1708 max_scf_name_len + 1) < 0) 1709 (void) strcpy(name_buf, "?"); 1710 1711 warn(gettext("Refreshed %s:%s.\n"), 1712 fmri, name_buf); 1713 } 1714 } else { 1715 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1716 g_verbose) { 1717 scfe = scf_error(); 1718 1719 if (scf_instance_to_fmri(inst, name_buf, 1720 max_scf_name_len + 1) < 0) 1721 (void) strcpy(name_buf, "?"); 1722 1723 warn(gettext( 1724 "Refresh of %s:%s failed: %s.\n"), fmri, 1725 name_buf, scf_strerror(scfe)); 1726 } 1727 } 1728 } 1729 1730 return (0); 1731 } 1732 1733 static void 1734 private_refresh(void) 1735 { 1736 scf_instance_t *pinst = NULL; 1737 scf_iter_t *piter = NULL; 1738 ssize_t fmrilen; 1739 size_t bufsz; 1740 char *fmribuf; 1741 void *ent; 1742 int issvc; 1743 int r; 1744 1745 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1746 return; 1747 1748 assert(cur_svc != NULL); 1749 1750 bufsz = max_scf_fmri_len + 1; 1751 fmribuf = safe_malloc(bufsz); 1752 if (cur_inst) { 1753 issvc = 0; 1754 ent = cur_inst; 1755 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1756 } else { 1757 issvc = 1; 1758 ent = cur_svc; 1759 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1760 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1761 scfdie(); 1762 1763 if ((piter = scf_iter_create(g_hndl)) == NULL) 1764 scfdie(); 1765 } 1766 if (fmrilen < 0) { 1767 free(fmribuf); 1768 if (scf_error() != SCF_ERROR_DELETED) 1769 scfdie(); 1770 1771 warn(emsg_deleted); 1772 return; 1773 } 1774 assert(fmrilen < bufsz); 1775 1776 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1777 switch (r) { 1778 case 0: 1779 break; 1780 1781 case ECONNABORTED: 1782 warn(gettext("Could not refresh %s " 1783 "(repository connection broken).\n"), fmribuf); 1784 break; 1785 1786 case ECANCELED: 1787 warn(emsg_deleted); 1788 break; 1789 1790 case EPERM: 1791 warn(gettext("Could not refresh %s " 1792 "(permission denied).\n"), fmribuf); 1793 break; 1794 1795 case ENOSPC: 1796 warn(gettext("Could not refresh %s " 1797 "(repository server out of resources).\n"), 1798 fmribuf); 1799 break; 1800 1801 case EACCES: 1802 default: 1803 bad_error("refresh_entity", scf_error()); 1804 } 1805 1806 if (issvc) { 1807 scf_instance_destroy(pinst); 1808 scf_iter_destroy(piter); 1809 } 1810 1811 free(fmribuf); 1812 } 1813 1814 1815 static int 1816 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1817 { 1818 cbp->sc_err = scferror2errno(err); 1819 return (UU_WALK_ERROR); 1820 } 1821 1822 static int 1823 stash_scferror(scf_callback_t *cbp) 1824 { 1825 return (stash_scferror_err(cbp, scf_error())); 1826 } 1827 1828 static int select_inst(const char *); 1829 static int select_svc(const char *); 1830 1831 /* 1832 * Take a property that does not have a type and check to see if a type 1833 * exists or can be gleened from the current data. Set the type. 1834 * 1835 * Check the current level (instance) and then check the higher level 1836 * (service). This could be the case for adding a new property to 1837 * the instance that's going to "override" a service level property. 1838 * 1839 * For a property : 1840 * 1. Take the type from an existing property 1841 * 2. Take the type from a template entry 1842 * 1843 * If the type can not be found, then leave the type as is, and let the import 1844 * report the problem of the missing type. 1845 */ 1846 static int 1847 find_current_prop_type(void *p, void *g) 1848 { 1849 property_t *prop = p; 1850 scf_callback_t *lcb = g; 1851 pgroup_t *pg = NULL; 1852 1853 const char *fmri = NULL; 1854 char *lfmri = NULL; 1855 char *cur_selection = NULL; 1856 1857 scf_propertygroup_t *sc_pg = NULL; 1858 scf_property_t *sc_prop = NULL; 1859 scf_pg_tmpl_t *t_pg = NULL; 1860 scf_prop_tmpl_t *t_prop = NULL; 1861 scf_type_t prop_type; 1862 1863 value_t *vp; 1864 int issvc = lcb->sc_service; 1865 int r = UU_WALK_ERROR; 1866 1867 if (prop->sc_value_type != SCF_TYPE_INVALID) 1868 return (UU_WALK_NEXT); 1869 1870 t_prop = scf_tmpl_prop_create(g_hndl); 1871 sc_prop = scf_property_create(g_hndl); 1872 if (sc_prop == NULL || t_prop == NULL) { 1873 warn(gettext("Unable to create the property to attempt and " 1874 "find a missing type.\n")); 1875 1876 scf_property_destroy(sc_prop); 1877 scf_tmpl_prop_destroy(t_prop); 1878 1879 return (UU_WALK_ERROR); 1880 } 1881 1882 if (lcb->sc_flags == 1) { 1883 pg = lcb->sc_parent; 1884 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT); 1885 fmri = pg->sc_parent->sc_fmri; 1886 retry_pg: 1887 if (cur_svc && cur_selection == NULL) { 1888 cur_selection = safe_malloc(max_scf_fmri_len + 1); 1889 lscf_get_selection_str(cur_selection, 1890 max_scf_fmri_len + 1); 1891 1892 if (strcmp(cur_selection, fmri) != 0) { 1893 lscf_select(fmri); 1894 } else { 1895 free(cur_selection); 1896 cur_selection = NULL; 1897 } 1898 } else { 1899 lscf_select(fmri); 1900 } 1901 1902 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) { 1903 warn(gettext("Unable to create property group to " 1904 "find a missing property type.\n")); 1905 1906 goto out; 1907 } 1908 1909 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) { 1910 /* 1911 * If this is the sc_pg from the parent 1912 * let the caller clean up the sc_pg, 1913 * and just throw it away in this case. 1914 */ 1915 if (sc_pg != lcb->sc_parent) 1916 scf_pg_destroy(sc_pg); 1917 1918 sc_pg = NULL; 1919 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1920 warn(gettext("Unable to create template " 1921 "property group to find a property " 1922 "type.\n")); 1923 1924 goto out; 1925 } 1926 1927 if (scf_tmpl_get_by_pg_name(fmri, NULL, 1928 pg->sc_pgroup_name, NULL, t_pg, 1929 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) { 1930 /* 1931 * if instance get service and jump back 1932 */ 1933 scf_tmpl_pg_destroy(t_pg); 1934 t_pg = NULL; 1935 if (issvc == 0) { 1936 entity_t *e = pg->sc_parent->sc_parent; 1937 1938 fmri = e->sc_fmri; 1939 issvc = 1; 1940 goto retry_pg; 1941 } else { 1942 goto out; 1943 } 1944 } 1945 } 1946 } else { 1947 sc_pg = lcb->sc_parent; 1948 } 1949 1950 /* 1951 * Attempt to get the type from an existing property. If the property 1952 * cannot be found then attempt to get the type from a template entry 1953 * for the property. 1954 * 1955 * Finally, if at the instance level look at the service level. 1956 */ 1957 if (sc_pg != NULL && 1958 pg_get_prop(sc_pg, prop->sc_property_name, 1959 sc_prop) == SCF_SUCCESS && 1960 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) { 1961 prop->sc_value_type = prop_type; 1962 1963 /* 1964 * Found a type, update the value types and validate 1965 * the actual value against this type. 1966 */ 1967 for (vp = uu_list_first(prop->sc_property_values); 1968 vp != NULL; 1969 vp = uu_list_next(prop->sc_property_values, vp)) { 1970 vp->sc_type = prop->sc_value_type; 1971 lxml_store_value(vp, 0, NULL); 1972 } 1973 1974 r = UU_WALK_NEXT; 1975 goto out; 1976 } 1977 1978 /* 1979 * If we get here with t_pg set to NULL then we had to have 1980 * gotten an sc_pg but that sc_pg did not have the property 1981 * we are looking for. So if the t_pg is not null look up 1982 * the template entry for the property. 1983 * 1984 * If the t_pg is null then need to attempt to get a matching 1985 * template entry for the sc_pg, and see if there is a property 1986 * entry for that template entry. 1987 */ 1988 do_tmpl : 1989 if (t_pg != NULL && 1990 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name, 1991 t_prop, 0) == SCF_SUCCESS) { 1992 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) { 1993 prop->sc_value_type = prop_type; 1994 1995 /* 1996 * Found a type, update the value types and validate 1997 * the actual value against this type. 1998 */ 1999 for (vp = uu_list_first(prop->sc_property_values); 2000 vp != NULL; 2001 vp = uu_list_next(prop->sc_property_values, vp)) { 2002 vp->sc_type = prop->sc_value_type; 2003 lxml_store_value(vp, 0, NULL); 2004 } 2005 2006 r = UU_WALK_NEXT; 2007 goto out; 2008 } 2009 } else { 2010 if (t_pg == NULL && sc_pg) { 2011 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 2012 warn(gettext("Unable to create template " 2013 "property group to find a property " 2014 "type.\n")); 2015 2016 goto out; 2017 } 2018 2019 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) { 2020 scf_tmpl_pg_destroy(t_pg); 2021 t_pg = NULL; 2022 } else { 2023 goto do_tmpl; 2024 } 2025 } 2026 } 2027 2028 if (issvc == 0) { 2029 scf_instance_t *i; 2030 scf_service_t *s; 2031 2032 issvc = 1; 2033 if (lcb->sc_flags == 1) { 2034 entity_t *e = pg->sc_parent->sc_parent; 2035 2036 fmri = e->sc_fmri; 2037 goto retry_pg; 2038 } 2039 2040 /* 2041 * because lcb->sc_flags was not set then this means 2042 * the pg was not used and can be used here. 2043 */ 2044 if ((pg = internal_pgroup_new()) == NULL) { 2045 warn(gettext("Could not create internal property group " 2046 "to find a missing type.")); 2047 2048 goto out; 2049 } 2050 2051 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1); 2052 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name, 2053 max_scf_name_len + 1) < 0) 2054 goto out; 2055 2056 i = scf_instance_create(g_hndl); 2057 s = scf_service_create(g_hndl); 2058 if (i == NULL || s == NULL || 2059 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) { 2060 warn(gettext("Could not get a service for the instance " 2061 "to find a missing type.")); 2062 2063 goto out; 2064 } 2065 2066 /* 2067 * Check to see truly at the instance level. 2068 */ 2069 lfmri = safe_malloc(max_scf_fmri_len + 1); 2070 if (scf_instance_get_parent(i, s) == SCF_SUCCESS && 2071 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0) 2072 goto out; 2073 else 2074 fmri = (const char *)lfmri; 2075 2076 goto retry_pg; 2077 } 2078 2079 out : 2080 if (sc_pg != lcb->sc_parent) { 2081 scf_pg_destroy(sc_pg); 2082 } 2083 2084 /* 2085 * If this is true then the pg was allocated 2086 * here, and the name was set so need to free 2087 * the name and the pg. 2088 */ 2089 if (pg != NULL && pg != lcb->sc_parent) { 2090 free((char *)pg->sc_pgroup_name); 2091 internal_pgroup_free(pg); 2092 } 2093 2094 if (cur_selection) { 2095 lscf_select(cur_selection); 2096 free(cur_selection); 2097 } 2098 2099 scf_tmpl_pg_destroy(t_pg); 2100 scf_tmpl_prop_destroy(t_prop); 2101 scf_property_destroy(sc_prop); 2102 2103 if (r != UU_WALK_NEXT) 2104 warn(gettext("Could not find property type for \"%s\" " 2105 "from \"%s\"\n"), prop->sc_property_name, 2106 fmri != NULL ? fmri : lcb->sc_source_fmri); 2107 2108 free(lfmri); 2109 2110 return (r); 2111 } 2112 2113 /* 2114 * Take a property group that does not have a type and check to see if a type 2115 * exists or can be gleened from the current data. Set the type. 2116 * 2117 * Check the current level (instance) and then check the higher level 2118 * (service). This could be the case for adding a new property to 2119 * the instance that's going to "override" a service level property. 2120 * 2121 * For a property group 2122 * 1. Take the type from an existing property group 2123 * 2. Take the type from a template entry 2124 * 2125 * If the type can not be found, then leave the type as is, and let the import 2126 * report the problem of the missing type. 2127 */ 2128 static int 2129 find_current_pg_type(void *p, void *sori) 2130 { 2131 entity_t *si = sori; 2132 pgroup_t *pg = p; 2133 2134 const char *ofmri, *fmri; 2135 char *cur_selection = NULL; 2136 char *pg_type = NULL; 2137 2138 scf_propertygroup_t *sc_pg = NULL; 2139 scf_pg_tmpl_t *t_pg = NULL; 2140 2141 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2142 int r = UU_WALK_ERROR; 2143 2144 ofmri = fmri = si->sc_fmri; 2145 if (pg->sc_pgroup_type != NULL) { 2146 r = UU_WALK_NEXT; 2147 2148 goto out; 2149 } 2150 2151 sc_pg = scf_pg_create(g_hndl); 2152 if (sc_pg == NULL) { 2153 warn(gettext("Unable to create property group to attempt " 2154 "and find a missing type.\n")); 2155 2156 return (UU_WALK_ERROR); 2157 } 2158 2159 /* 2160 * Using get_pg() requires that the cur_svc/cur_inst be 2161 * via lscf_select. Need to preserve the current selection 2162 * if going to use lscf_select() to set up the cur_svc/cur_inst 2163 */ 2164 if (cur_svc) { 2165 cur_selection = safe_malloc(max_scf_fmri_len + 1); 2166 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1); 2167 } 2168 2169 /* 2170 * If the property group exists get the type, and set 2171 * the pgroup_t type of that type. 2172 * 2173 * If not the check for a template pg_pattern entry 2174 * and take the type from that. 2175 */ 2176 retry_svc: 2177 lscf_select(fmri); 2178 2179 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) { 2180 pg_type = safe_malloc(max_scf_pg_type_len + 1); 2181 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type, 2182 max_scf_pg_type_len + 1) != -1) { 2183 pg->sc_pgroup_type = pg_type; 2184 2185 r = UU_WALK_NEXT; 2186 goto out; 2187 } else { 2188 free(pg_type); 2189 } 2190 } else { 2191 if ((t_pg == NULL) && 2192 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) 2193 goto out; 2194 2195 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name, 2196 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS && 2197 scf_tmpl_pg_type(t_pg, &pg_type) != -1) { 2198 pg->sc_pgroup_type = pg_type; 2199 2200 r = UU_WALK_NEXT; 2201 goto out; 2202 } 2203 } 2204 2205 /* 2206 * If type is not found at the instance level then attempt to 2207 * find the type at the service level. 2208 */ 2209 if (!issvc) { 2210 si = si->sc_parent; 2211 fmri = si->sc_fmri; 2212 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2213 goto retry_svc; 2214 } 2215 2216 out : 2217 if (cur_selection) { 2218 lscf_select(cur_selection); 2219 free(cur_selection); 2220 } 2221 2222 /* 2223 * Now walk the properties of the property group to make sure that 2224 * all properties have the correct type and values are valid for 2225 * those types. 2226 */ 2227 if (r == UU_WALK_NEXT) { 2228 scf_callback_t cb; 2229 2230 cb.sc_service = issvc; 2231 cb.sc_source_fmri = ofmri; 2232 if (sc_pg != NULL) { 2233 cb.sc_parent = sc_pg; 2234 cb.sc_flags = 0; 2235 } else { 2236 cb.sc_parent = pg; 2237 cb.sc_flags = 1; 2238 } 2239 2240 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type, 2241 &cb, UU_DEFAULT) != 0) { 2242 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2243 bad_error("uu_list_walk", uu_error()); 2244 2245 r = UU_WALK_ERROR; 2246 } 2247 } else { 2248 warn(gettext("Could not find property group type for " 2249 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri); 2250 } 2251 2252 scf_tmpl_pg_destroy(t_pg); 2253 scf_pg_destroy(sc_pg); 2254 2255 return (r); 2256 } 2257 2258 /* 2259 * Import. These functions import a bundle into the repository. 2260 */ 2261 2262 /* 2263 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 2264 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 2265 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2266 * lcbdata->sc_err to 2267 * ENOMEM - out of memory 2268 * ECONNABORTED - repository connection broken 2269 * ECANCELED - sc_trans's property group was deleted 2270 * EINVAL - p's name is invalid (error printed) 2271 * - p has an invalid value (error printed) 2272 */ 2273 static int 2274 lscf_property_import(void *v, void *pvt) 2275 { 2276 property_t *p = v; 2277 scf_callback_t *lcbdata = pvt; 2278 value_t *vp; 2279 scf_transaction_t *trans = lcbdata->sc_trans; 2280 scf_transaction_entry_t *entr; 2281 scf_value_t *val; 2282 scf_type_t tp; 2283 2284 if ((lcbdata->sc_flags & SCI_NOENABLED || 2285 lcbdata->sc_flags & SCI_DELAYENABLE) && 2286 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 2287 lcbdata->sc_enable = p; 2288 return (UU_WALK_NEXT); 2289 } 2290 2291 entr = scf_entry_create(lcbdata->sc_handle); 2292 if (entr == NULL) { 2293 switch (scf_error()) { 2294 case SCF_ERROR_NO_MEMORY: 2295 return (stash_scferror(lcbdata)); 2296 2297 case SCF_ERROR_INVALID_ARGUMENT: 2298 default: 2299 bad_error("scf_entry_create", scf_error()); 2300 } 2301 } 2302 2303 tp = p->sc_value_type; 2304 2305 if (scf_transaction_property_new(trans, entr, 2306 p->sc_property_name, tp) != 0) { 2307 switch (scf_error()) { 2308 case SCF_ERROR_INVALID_ARGUMENT: 2309 semerr(emsg_invalid_prop_name, p->sc_property_name); 2310 scf_entry_destroy(entr); 2311 return (stash_scferror(lcbdata)); 2312 2313 case SCF_ERROR_EXISTS: 2314 break; 2315 2316 case SCF_ERROR_DELETED: 2317 case SCF_ERROR_CONNECTION_BROKEN: 2318 scf_entry_destroy(entr); 2319 return (stash_scferror(lcbdata)); 2320 2321 case SCF_ERROR_NOT_BOUND: 2322 case SCF_ERROR_HANDLE_MISMATCH: 2323 case SCF_ERROR_NOT_SET: 2324 default: 2325 bad_error("scf_transaction_property_new", scf_error()); 2326 } 2327 2328 if (scf_transaction_property_change_type(trans, entr, 2329 p->sc_property_name, tp) != 0) { 2330 switch (scf_error()) { 2331 case SCF_ERROR_DELETED: 2332 case SCF_ERROR_CONNECTION_BROKEN: 2333 scf_entry_destroy(entr); 2334 return (stash_scferror(lcbdata)); 2335 2336 case SCF_ERROR_INVALID_ARGUMENT: 2337 semerr(emsg_invalid_prop_name, 2338 p->sc_property_name); 2339 scf_entry_destroy(entr); 2340 return (stash_scferror(lcbdata)); 2341 2342 case SCF_ERROR_NOT_FOUND: 2343 case SCF_ERROR_NOT_SET: 2344 case SCF_ERROR_HANDLE_MISMATCH: 2345 case SCF_ERROR_NOT_BOUND: 2346 default: 2347 bad_error( 2348 "scf_transaction_property_change_type", 2349 scf_error()); 2350 } 2351 } 2352 } 2353 2354 for (vp = uu_list_first(p->sc_property_values); 2355 vp != NULL; 2356 vp = uu_list_next(p->sc_property_values, vp)) { 2357 val = scf_value_create(g_hndl); 2358 if (val == NULL) { 2359 switch (scf_error()) { 2360 case SCF_ERROR_NO_MEMORY: 2361 return (stash_scferror(lcbdata)); 2362 2363 case SCF_ERROR_INVALID_ARGUMENT: 2364 default: 2365 bad_error("scf_value_create", scf_error()); 2366 } 2367 } 2368 2369 switch (tp) { 2370 case SCF_TYPE_BOOLEAN: 2371 scf_value_set_boolean(val, vp->sc_u.sc_count); 2372 break; 2373 case SCF_TYPE_COUNT: 2374 scf_value_set_count(val, vp->sc_u.sc_count); 2375 break; 2376 case SCF_TYPE_INTEGER: 2377 scf_value_set_integer(val, vp->sc_u.sc_integer); 2378 break; 2379 default: 2380 assert(vp->sc_u.sc_string != NULL); 2381 if (scf_value_set_from_string(val, tp, 2382 vp->sc_u.sc_string) != 0) { 2383 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 2384 bad_error("scf_value_set_from_string", 2385 scf_error()); 2386 2387 warn(gettext("Value \"%s\" is not a valid " 2388 "%s.\n"), vp->sc_u.sc_string, 2389 scf_type_to_string(tp)); 2390 scf_value_destroy(val); 2391 return (stash_scferror(lcbdata)); 2392 } 2393 break; 2394 } 2395 2396 if (scf_entry_add_value(entr, val) != 0) 2397 bad_error("scf_entry_add_value", scf_error()); 2398 } 2399 2400 return (UU_WALK_NEXT); 2401 } 2402 2403 /* 2404 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 2405 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 2406 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 2407 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2408 * lcbdata->sc_err to 2409 * ECONNABORTED - repository connection broken 2410 * ENOMEM - out of memory 2411 * ENOSPC - svc.configd is out of resources 2412 * ECANCELED - sc_parent was deleted 2413 * EPERM - could not create property group (permission denied) (error printed) 2414 * - could not modify property group (permission denied) (error printed) 2415 * - could not delete property group (permission denied) (error printed) 2416 * EROFS - could not create property group (repository is read-only) 2417 * - could not delete property group (repository is read-only) 2418 * EACCES - could not create property group (backend access denied) 2419 * - could not delete property group (backend access denied) 2420 * EEXIST - could not create property group (already exists) 2421 * EINVAL - invalid property group name (error printed) 2422 * - invalid property name (error printed) 2423 * - invalid value (error printed) 2424 * EBUSY - new property group deleted (error printed) 2425 * - new property group changed (error printed) 2426 * - property group added (error printed) 2427 * - property group deleted (error printed) 2428 */ 2429 static int 2430 entity_pgroup_import(void *v, void *pvt) 2431 { 2432 pgroup_t *p = v; 2433 scf_callback_t cbdata; 2434 scf_callback_t *lcbdata = pvt; 2435 void *ent = lcbdata->sc_parent; 2436 int issvc = lcbdata->sc_service; 2437 int r; 2438 2439 const char * const pg_changed = gettext("%s changed unexpectedly " 2440 "(new property group \"%s\" changed).\n"); 2441 2442 /* Never import deleted property groups. */ 2443 if (p->sc_pgroup_delete) { 2444 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY && 2445 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) { 2446 goto delete_pg; 2447 } 2448 return (UU_WALK_NEXT); 2449 } 2450 2451 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 2452 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 2453 lcbdata->sc_general = p; 2454 return (UU_WALK_NEXT); 2455 } 2456 2457 add_pg: 2458 if (issvc) 2459 r = scf_service_add_pg(ent, p->sc_pgroup_name, 2460 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2461 else 2462 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 2463 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2464 if (r != 0) { 2465 switch (scf_error()) { 2466 case SCF_ERROR_DELETED: 2467 case SCF_ERROR_CONNECTION_BROKEN: 2468 case SCF_ERROR_BACKEND_READONLY: 2469 case SCF_ERROR_BACKEND_ACCESS: 2470 case SCF_ERROR_NO_RESOURCES: 2471 return (stash_scferror(lcbdata)); 2472 2473 case SCF_ERROR_EXISTS: 2474 if (lcbdata->sc_flags & SCI_FORCE) 2475 break; 2476 return (stash_scferror(lcbdata)); 2477 2478 case SCF_ERROR_INVALID_ARGUMENT: 2479 warn(emsg_fmri_invalid_pg_name_type, 2480 lcbdata->sc_source_fmri, 2481 p->sc_pgroup_name, p->sc_pgroup_type); 2482 return (stash_scferror(lcbdata)); 2483 2484 case SCF_ERROR_PERMISSION_DENIED: 2485 warn(emsg_pg_add_perm, p->sc_pgroup_name, 2486 lcbdata->sc_target_fmri); 2487 return (stash_scferror(lcbdata)); 2488 2489 case SCF_ERROR_NOT_BOUND: 2490 case SCF_ERROR_HANDLE_MISMATCH: 2491 case SCF_ERROR_NOT_SET: 2492 default: 2493 bad_error("scf_service_add_pg", scf_error()); 2494 } 2495 2496 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2497 switch (scf_error()) { 2498 case SCF_ERROR_CONNECTION_BROKEN: 2499 case SCF_ERROR_DELETED: 2500 return (stash_scferror(lcbdata)); 2501 2502 case SCF_ERROR_INVALID_ARGUMENT: 2503 warn(emsg_fmri_invalid_pg_name, 2504 lcbdata->sc_source_fmri, 2505 p->sc_pgroup_name); 2506 return (stash_scferror(lcbdata)); 2507 2508 case SCF_ERROR_NOT_FOUND: 2509 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2510 p->sc_pgroup_name); 2511 lcbdata->sc_err = EBUSY; 2512 return (UU_WALK_ERROR); 2513 2514 case SCF_ERROR_NOT_BOUND: 2515 case SCF_ERROR_HANDLE_MISMATCH: 2516 case SCF_ERROR_NOT_SET: 2517 default: 2518 bad_error("entity_get_pg", scf_error()); 2519 } 2520 } 2521 2522 if (lcbdata->sc_flags & SCI_KEEP) 2523 goto props; 2524 2525 delete_pg: 2526 if (scf_pg_delete(imp_pg) != 0) { 2527 switch (scf_error()) { 2528 case SCF_ERROR_DELETED: 2529 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2530 p->sc_pgroup_name); 2531 lcbdata->sc_err = EBUSY; 2532 return (UU_WALK_ERROR); 2533 2534 case SCF_ERROR_PERMISSION_DENIED: 2535 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2536 lcbdata->sc_target_fmri); 2537 return (stash_scferror(lcbdata)); 2538 2539 case SCF_ERROR_BACKEND_READONLY: 2540 case SCF_ERROR_BACKEND_ACCESS: 2541 case SCF_ERROR_CONNECTION_BROKEN: 2542 return (stash_scferror(lcbdata)); 2543 2544 case SCF_ERROR_NOT_SET: 2545 default: 2546 bad_error("scf_pg_delete", scf_error()); 2547 } 2548 } 2549 2550 if (p->sc_pgroup_delete) 2551 return (UU_WALK_NEXT); 2552 2553 goto add_pg; 2554 } 2555 2556 props: 2557 2558 /* 2559 * Add properties to property group, if any. 2560 */ 2561 cbdata.sc_handle = lcbdata->sc_handle; 2562 cbdata.sc_parent = imp_pg; 2563 cbdata.sc_flags = lcbdata->sc_flags; 2564 cbdata.sc_trans = imp_tx; 2565 cbdata.sc_enable = NULL; 2566 2567 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2568 switch (scf_error()) { 2569 case SCF_ERROR_BACKEND_ACCESS: 2570 case SCF_ERROR_BACKEND_READONLY: 2571 case SCF_ERROR_CONNECTION_BROKEN: 2572 return (stash_scferror(lcbdata)); 2573 2574 case SCF_ERROR_DELETED: 2575 warn(pg_changed, lcbdata->sc_target_fmri, 2576 p->sc_pgroup_name); 2577 lcbdata->sc_err = EBUSY; 2578 return (UU_WALK_ERROR); 2579 2580 case SCF_ERROR_PERMISSION_DENIED: 2581 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2582 lcbdata->sc_target_fmri); 2583 return (stash_scferror(lcbdata)); 2584 2585 case SCF_ERROR_NOT_BOUND: 2586 case SCF_ERROR_NOT_SET: 2587 case SCF_ERROR_IN_USE: 2588 case SCF_ERROR_HANDLE_MISMATCH: 2589 default: 2590 bad_error("scf_transaction_start", scf_error()); 2591 } 2592 } 2593 2594 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2595 UU_DEFAULT) != 0) { 2596 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2597 bad_error("uu_list_walk", uu_error()); 2598 scf_transaction_reset(imp_tx); 2599 2600 lcbdata->sc_err = cbdata.sc_err; 2601 if (cbdata.sc_err == ECANCELED) { 2602 warn(pg_changed, lcbdata->sc_target_fmri, 2603 p->sc_pgroup_name); 2604 lcbdata->sc_err = EBUSY; 2605 } 2606 return (UU_WALK_ERROR); 2607 } 2608 2609 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2610 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2611 2612 /* 2613 * take the snapshot running snapshot then 2614 * import the stored general/enable property 2615 */ 2616 r = take_snap(ent, snap_running, imp_rsnap); 2617 switch (r) { 2618 case 0: 2619 break; 2620 2621 case ECONNABORTED: 2622 warn(gettext("Could not take %s snapshot on import " 2623 "(repository connection broken).\n"), 2624 snap_running); 2625 lcbdata->sc_err = r; 2626 return (UU_WALK_ERROR); 2627 case ECANCELED: 2628 warn(emsg_deleted); 2629 lcbdata->sc_err = r; 2630 return (UU_WALK_ERROR); 2631 2632 case EPERM: 2633 warn(gettext("Could not take %s snapshot " 2634 "(permission denied).\n"), snap_running); 2635 lcbdata->sc_err = r; 2636 return (UU_WALK_ERROR); 2637 2638 case ENOSPC: 2639 warn(gettext("Could not take %s snapshot" 2640 "(repository server out of resources).\n"), 2641 snap_running); 2642 lcbdata->sc_err = r; 2643 return (UU_WALK_ERROR); 2644 2645 default: 2646 bad_error("take_snap", r); 2647 } 2648 2649 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2650 if (r != UU_WALK_NEXT) { 2651 if (r != UU_WALK_ERROR) 2652 bad_error("lscf_property_import", r); 2653 return (EINVAL); 2654 } 2655 } 2656 2657 r = scf_transaction_commit(imp_tx); 2658 switch (r) { 2659 case 1: 2660 r = UU_WALK_NEXT; 2661 break; 2662 2663 case 0: 2664 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2665 lcbdata->sc_err = EBUSY; 2666 r = UU_WALK_ERROR; 2667 break; 2668 2669 case -1: 2670 switch (scf_error()) { 2671 case SCF_ERROR_BACKEND_READONLY: 2672 case SCF_ERROR_BACKEND_ACCESS: 2673 case SCF_ERROR_CONNECTION_BROKEN: 2674 case SCF_ERROR_NO_RESOURCES: 2675 r = stash_scferror(lcbdata); 2676 break; 2677 2678 case SCF_ERROR_DELETED: 2679 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2680 p->sc_pgroup_name); 2681 lcbdata->sc_err = EBUSY; 2682 r = UU_WALK_ERROR; 2683 break; 2684 2685 case SCF_ERROR_PERMISSION_DENIED: 2686 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2687 lcbdata->sc_target_fmri); 2688 r = stash_scferror(lcbdata); 2689 break; 2690 2691 case SCF_ERROR_NOT_SET: 2692 case SCF_ERROR_INVALID_ARGUMENT: 2693 case SCF_ERROR_NOT_BOUND: 2694 default: 2695 bad_error("scf_transaction_commit", scf_error()); 2696 } 2697 break; 2698 2699 default: 2700 bad_error("scf_transaction_commit", r); 2701 } 2702 2703 scf_transaction_destroy_children(imp_tx); 2704 2705 return (r); 2706 } 2707 2708 /* 2709 * Returns 2710 * 0 - success 2711 * ECONNABORTED - repository connection broken 2712 * ENOMEM - out of memory 2713 * ENOSPC - svc.configd is out of resources 2714 * ECANCELED - inst was deleted 2715 * EPERM - could not create property group (permission denied) (error printed) 2716 * - could not modify property group (permission denied) (error printed) 2717 * EROFS - could not create property group (repository is read-only) 2718 * EACCES - could not create property group (backend access denied) 2719 * EEXIST - could not create property group (already exists) 2720 * EINVAL - invalid property group name (error printed) 2721 * - invalid property name (error printed) 2722 * - invalid value (error printed) 2723 * EBUSY - new property group changed (error printed) 2724 */ 2725 static int 2726 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2727 const entity_t *isvc, int flags) 2728 { 2729 scf_callback_t cbdata; 2730 2731 cbdata.sc_handle = scf_service_handle(svc); 2732 cbdata.sc_parent = svc; 2733 cbdata.sc_service = 1; 2734 cbdata.sc_general = 0; 2735 cbdata.sc_enable = 0; 2736 cbdata.sc_flags = flags; 2737 cbdata.sc_source_fmri = isvc->sc_fmri; 2738 cbdata.sc_target_fmri = target_fmri; 2739 2740 /* 2741 * If the op is set, then add the flag to the callback 2742 * flags for later use. 2743 */ 2744 if (isvc->sc_op != SVCCFG_OP_NONE) { 2745 switch (isvc->sc_op) { 2746 case SVCCFG_OP_IMPORT : 2747 cbdata.sc_flags |= SCI_OP_IMPORT; 2748 break; 2749 case SVCCFG_OP_APPLY : 2750 cbdata.sc_flags |= SCI_OP_APPLY; 2751 break; 2752 case SVCCFG_OP_RESTORE : 2753 cbdata.sc_flags |= SCI_OP_RESTORE; 2754 break; 2755 default : 2756 uu_die(gettext("lscf_import_service_pgs : " 2757 "Unknown op stored in the service entity\n")); 2758 2759 } 2760 } 2761 2762 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2763 UU_DEFAULT) != 0) { 2764 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2765 bad_error("uu_list_walk", uu_error()); 2766 2767 return (cbdata.sc_err); 2768 } 2769 2770 return (0); 2771 } 2772 2773 /* 2774 * Returns 2775 * 0 - success 2776 * ECONNABORTED - repository connection broken 2777 * ENOMEM - out of memory 2778 * ENOSPC - svc.configd is out of resources 2779 * ECANCELED - inst was deleted 2780 * EPERM - could not create property group (permission denied) (error printed) 2781 * - could not modify property group (permission denied) (error printed) 2782 * EROFS - could not create property group (repository is read-only) 2783 * EACCES - could not create property group (backend access denied) 2784 * EEXIST - could not create property group (already exists) 2785 * EINVAL - invalid property group name (error printed) 2786 * - invalid property name (error printed) 2787 * - invalid value (error printed) 2788 * EBUSY - new property group changed (error printed) 2789 */ 2790 static int 2791 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2792 const entity_t *iinst, int flags) 2793 { 2794 scf_callback_t cbdata; 2795 2796 cbdata.sc_handle = scf_instance_handle(inst); 2797 cbdata.sc_parent = inst; 2798 cbdata.sc_service = 0; 2799 cbdata.sc_general = NULL; 2800 cbdata.sc_enable = NULL; 2801 cbdata.sc_flags = flags; 2802 cbdata.sc_source_fmri = iinst->sc_fmri; 2803 cbdata.sc_target_fmri = target_fmri; 2804 2805 /* 2806 * If the op is set, then add the flag to the callback 2807 * flags for later use. 2808 */ 2809 if (iinst->sc_op != SVCCFG_OP_NONE) { 2810 switch (iinst->sc_op) { 2811 case SVCCFG_OP_IMPORT : 2812 cbdata.sc_flags |= SCI_OP_IMPORT; 2813 break; 2814 case SVCCFG_OP_APPLY : 2815 cbdata.sc_flags |= SCI_OP_APPLY; 2816 break; 2817 case SVCCFG_OP_RESTORE : 2818 cbdata.sc_flags |= SCI_OP_RESTORE; 2819 break; 2820 default : 2821 uu_die(gettext("lscf_import_instance_pgs : " 2822 "Unknown op stored in the instance entity\n")); 2823 } 2824 } 2825 2826 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2827 UU_DEFAULT) != 0) { 2828 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2829 bad_error("uu_list_walk", uu_error()); 2830 2831 return (cbdata.sc_err); 2832 } 2833 2834 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2835 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2836 /* 2837 * If importing with the SCI_NOENABLED flag then 2838 * skip the delay, but if not then add the delay 2839 * of the enable property. 2840 */ 2841 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2842 cbdata.sc_flags |= SCI_DELAYENABLE; 2843 } 2844 2845 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2846 != UU_WALK_NEXT) 2847 return (cbdata.sc_err); 2848 } 2849 2850 return (0); 2851 } 2852 2853 /* 2854 * Report the reasons why we can't upgrade pg2 to pg1. 2855 */ 2856 static void 2857 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2858 int new) 2859 { 2860 property_t *p1, *p2; 2861 2862 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2863 2864 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2865 return; 2866 2867 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2868 p1 != NULL; 2869 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2870 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2871 if (p2 != NULL) { 2872 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2873 new); 2874 continue; 2875 } 2876 2877 if (new) 2878 warn(gettext("Conflict upgrading %s (new property " 2879 "group \"%s\" is missing property \"%s\").\n"), 2880 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2881 else 2882 warn(gettext("Conflict upgrading %s (property " 2883 "\"%s/%s\" is missing).\n"), fmri, 2884 pg1->sc_pgroup_name, p1->sc_property_name); 2885 } 2886 2887 /* 2888 * Since pg1 should be from the manifest, any properties in pg2 which 2889 * aren't in pg1 shouldn't be reported as conflicts. 2890 */ 2891 } 2892 2893 /* 2894 * Add transaction entries to tx which will upgrade cur's pg according to old 2895 * & new. 2896 * 2897 * Returns 2898 * 0 - success 2899 * EINVAL - new has a property with an invalid name or value (message emitted) 2900 * ENOMEM - out of memory 2901 */ 2902 static int 2903 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2904 pgroup_t *cur, int speak, const char *fmri) 2905 { 2906 property_t *p, *new_p, *cur_p; 2907 scf_transaction_entry_t *e; 2908 int r; 2909 int is_general; 2910 int is_protected; 2911 2912 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2913 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2914 bad_error("uu_list_walk", uu_error()); 2915 2916 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2917 2918 for (p = uu_list_first(old->sc_pgroup_props); 2919 p != NULL; 2920 p = uu_list_next(old->sc_pgroup_props, p)) { 2921 /* p is a property in the old property group. */ 2922 2923 /* Protect live properties. */ 2924 is_protected = 0; 2925 if (is_general) { 2926 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2927 0 || 2928 strcmp(p->sc_property_name, 2929 SCF_PROPERTY_RESTARTER) == 0) 2930 is_protected = 1; 2931 } 2932 2933 /* Look for the same property in the new properties. */ 2934 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2935 if (new_p != NULL) { 2936 new_p->sc_seen = 1; 2937 2938 /* 2939 * If the new property is the same as the old, don't do 2940 * anything (leave any user customizations). 2941 */ 2942 if (prop_equal(p, new_p, NULL, NULL, 0)) 2943 continue; 2944 2945 if (new_p->sc_property_override) 2946 goto upgrade; 2947 } 2948 2949 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2950 if (cur_p == NULL) { 2951 /* 2952 * p has been deleted from the repository. If we were 2953 * going to delete it anyway, do nothing. Otherwise 2954 * report a conflict. 2955 */ 2956 if (new_p == NULL) 2957 continue; 2958 2959 if (is_protected) 2960 continue; 2961 2962 warn(gettext("Conflict upgrading %s " 2963 "(property \"%s/%s\" is missing).\n"), fmri, 2964 old->sc_pgroup_name, p->sc_property_name); 2965 continue; 2966 } 2967 2968 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2969 /* 2970 * Conflict. Don't warn if the property is already the 2971 * way we want it, though. 2972 */ 2973 if (is_protected) 2974 continue; 2975 2976 if (new_p == NULL) 2977 (void) prop_equal(p, cur_p, fmri, 2978 old->sc_pgroup_name, 0); 2979 else 2980 (void) prop_equal(cur_p, new_p, fmri, 2981 old->sc_pgroup_name, 0); 2982 continue; 2983 } 2984 2985 if (is_protected) { 2986 if (speak) 2987 warn(gettext("%s: Refusing to upgrade " 2988 "\"%s/%s\" (live property).\n"), fmri, 2989 old->sc_pgroup_name, p->sc_property_name); 2990 continue; 2991 } 2992 2993 upgrade: 2994 /* p hasn't been customized in the repository. Upgrade it. */ 2995 if (new_p == NULL) { 2996 /* p was deleted. Delete from cur if unchanged. */ 2997 if (speak) 2998 warn(gettext( 2999 "%s: Deleting property \"%s/%s\".\n"), 3000 fmri, old->sc_pgroup_name, 3001 p->sc_property_name); 3002 3003 e = scf_entry_create(g_hndl); 3004 if (e == NULL) 3005 return (ENOMEM); 3006 3007 if (scf_transaction_property_delete(tx, e, 3008 p->sc_property_name) != 0) { 3009 switch (scf_error()) { 3010 case SCF_ERROR_DELETED: 3011 scf_entry_destroy(e); 3012 return (ECANCELED); 3013 3014 case SCF_ERROR_CONNECTION_BROKEN: 3015 scf_entry_destroy(e); 3016 return (ECONNABORTED); 3017 3018 case SCF_ERROR_NOT_FOUND: 3019 /* 3020 * This can happen if cur is from the 3021 * running snapshot (and it differs 3022 * from the live properties). 3023 */ 3024 scf_entry_destroy(e); 3025 break; 3026 3027 case SCF_ERROR_HANDLE_MISMATCH: 3028 case SCF_ERROR_NOT_BOUND: 3029 case SCF_ERROR_NOT_SET: 3030 case SCF_ERROR_INVALID_ARGUMENT: 3031 default: 3032 bad_error( 3033 "scf_transaction_property_delete", 3034 scf_error()); 3035 } 3036 } 3037 } else { 3038 scf_callback_t ctx; 3039 3040 if (speak) 3041 warn(gettext( 3042 "%s: Upgrading property \"%s/%s\".\n"), 3043 fmri, old->sc_pgroup_name, 3044 p->sc_property_name); 3045 3046 ctx.sc_handle = g_hndl; 3047 ctx.sc_trans = tx; 3048 ctx.sc_flags = 0; 3049 3050 r = lscf_property_import(new_p, &ctx); 3051 if (r != UU_WALK_NEXT) { 3052 if (r != UU_WALK_ERROR) 3053 bad_error("lscf_property_import", r); 3054 return (EINVAL); 3055 } 3056 } 3057 } 3058 3059 /* Go over the properties which were added. */ 3060 for (new_p = uu_list_first(new->sc_pgroup_props); 3061 new_p != NULL; 3062 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 3063 if (new_p->sc_seen) 3064 continue; 3065 3066 /* This is a new property. */ 3067 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 3068 if (cur_p == NULL) { 3069 scf_callback_t ctx; 3070 3071 ctx.sc_handle = g_hndl; 3072 ctx.sc_trans = tx; 3073 ctx.sc_flags = 0; 3074 3075 r = lscf_property_import(new_p, &ctx); 3076 if (r != UU_WALK_NEXT) { 3077 if (r != UU_WALK_ERROR) 3078 bad_error("lscf_property_import", r); 3079 return (EINVAL); 3080 } 3081 continue; 3082 } 3083 3084 /* 3085 * Report a conflict if the new property differs from the 3086 * current one. Unless it's general/enabled, since that's 3087 * never in the last-import snapshot. 3088 */ 3089 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 3090 0 && 3091 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 3092 continue; 3093 3094 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 3095 } 3096 3097 return (0); 3098 } 3099 3100 /* 3101 * Upgrade pg according to old & new. 3102 * 3103 * Returns 3104 * 0 - success 3105 * ECONNABORTED - repository connection broken 3106 * ENOMEM - out of memory 3107 * ENOSPC - svc.configd is out of resources 3108 * ECANCELED - pg was deleted 3109 * EPERM - couldn't modify pg (permission denied) 3110 * EROFS - couldn't modify pg (backend read-only) 3111 * EACCES - couldn't modify pg (backend access denied) 3112 * EINVAL - new has a property with invalid name or value (error printed) 3113 * EBUSY - pg changed unexpectedly 3114 */ 3115 static int 3116 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 3117 pgroup_t *new, int speak, const char *fmri) 3118 { 3119 int r; 3120 3121 if (scf_transaction_start(imp_tx, pg) != 0) { 3122 switch (scf_error()) { 3123 case SCF_ERROR_CONNECTION_BROKEN: 3124 case SCF_ERROR_DELETED: 3125 case SCF_ERROR_PERMISSION_DENIED: 3126 case SCF_ERROR_BACKEND_READONLY: 3127 case SCF_ERROR_BACKEND_ACCESS: 3128 return (scferror2errno(scf_error())); 3129 3130 case SCF_ERROR_HANDLE_MISMATCH: 3131 case SCF_ERROR_IN_USE: 3132 case SCF_ERROR_NOT_BOUND: 3133 case SCF_ERROR_NOT_SET: 3134 default: 3135 bad_error("scf_transaction_start", scf_error()); 3136 } 3137 } 3138 3139 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 3140 switch (r) { 3141 case 0: 3142 break; 3143 3144 case EINVAL: 3145 case ENOMEM: 3146 scf_transaction_destroy_children(imp_tx); 3147 return (r); 3148 3149 default: 3150 bad_error("add_upgrade_entries", r); 3151 } 3152 3153 r = scf_transaction_commit(imp_tx); 3154 3155 scf_transaction_destroy_children(imp_tx); 3156 3157 switch (r) { 3158 case 1: 3159 break; 3160 3161 case 0: 3162 return (EBUSY); 3163 3164 case -1: 3165 switch (scf_error()) { 3166 case SCF_ERROR_CONNECTION_BROKEN: 3167 case SCF_ERROR_NO_RESOURCES: 3168 case SCF_ERROR_PERMISSION_DENIED: 3169 case SCF_ERROR_BACKEND_READONLY: 3170 case SCF_ERROR_BACKEND_ACCESS: 3171 case SCF_ERROR_DELETED: 3172 return (scferror2errno(scf_error())); 3173 3174 case SCF_ERROR_NOT_BOUND: 3175 case SCF_ERROR_INVALID_ARGUMENT: 3176 case SCF_ERROR_NOT_SET: 3177 default: 3178 bad_error("scf_transaction_commit", scf_error()); 3179 } 3180 3181 default: 3182 bad_error("scf_transaction_commit", r); 3183 } 3184 3185 return (0); 3186 } 3187 3188 /* 3189 * Compares two entity FMRIs. Returns 3190 * 3191 * 1 - equal 3192 * 0 - not equal 3193 * -1 - f1 is invalid or not an entity 3194 * -2 - f2 is invalid or not an entity 3195 */ 3196 static int 3197 fmri_equal(const char *f1, const char *f2) 3198 { 3199 int r; 3200 const char *s1, *i1, *pg1; 3201 const char *s2, *i2, *pg2; 3202 3203 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3204 return (-1); 3205 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 3206 return (-1); 3207 3208 if (s1 == NULL || pg1 != NULL) 3209 return (-1); 3210 3211 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3212 return (-2); 3213 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 3214 return (-2); 3215 3216 if (s2 == NULL || pg2 != NULL) 3217 return (-2); 3218 3219 r = strcmp(s1, s2); 3220 if (r != 0) 3221 return (0); 3222 3223 if (i1 == NULL && i2 == NULL) 3224 return (1); 3225 3226 if (i1 == NULL || i2 == NULL) 3227 return (0); 3228 3229 return (strcmp(i1, i2) == 0); 3230 } 3231 3232 /* 3233 * Import a dependent by creating a dependency property group in the dependent 3234 * entity. If lcbdata->sc_trans is set, assume it's been started on the 3235 * dependents pg, and add an entry to create a new property for this 3236 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 3237 * 3238 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 3239 * lcbdata->sc_err to 3240 * ECONNABORTED - repository connection broken 3241 * ENOMEM - out of memory 3242 * ENOSPC - configd is out of resources 3243 * EINVAL - target is invalid (error printed) 3244 * - target is not an entity (error printed) 3245 * - dependent has invalid name (error printed) 3246 * - invalid property name (error printed) 3247 * - invalid value (error printed) 3248 * - scope of target does not exist (error printed) 3249 * EPERM - couldn't create target (permission denied) (error printed) 3250 * - couldn't create dependency pg (permission denied) (error printed) 3251 * - couldn't modify dependency pg (permission denied) (error printed) 3252 * EROFS - couldn't create target (repository read-only) 3253 * - couldn't create dependency pg (repository read-only) 3254 * EACCES - couldn't create target (backend access denied) 3255 * - couldn't create dependency pg (backend access denied) 3256 * ECANCELED - sc_trans's pg was deleted 3257 * EALREADY - property for dependent already exists in sc_trans's pg 3258 * EEXIST - dependency pg already exists in target (error printed) 3259 * EBUSY - target deleted (error printed) 3260 * - property group changed during import (error printed) 3261 */ 3262 static int 3263 lscf_dependent_import(void *a1, void *pvt) 3264 { 3265 pgroup_t *pgrp = a1; 3266 scf_callback_t *lcbdata = pvt; 3267 3268 int isservice; 3269 int ret; 3270 scf_transaction_entry_t *e; 3271 scf_value_t *val; 3272 scf_callback_t dependent_cbdata; 3273 scf_error_t scfe; 3274 3275 /* 3276 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 3277 * it's invalid, we fail before modifying the repository. 3278 */ 3279 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3280 &dependent_cbdata.sc_parent, &isservice); 3281 switch (scfe) { 3282 case SCF_ERROR_NONE: 3283 break; 3284 3285 case SCF_ERROR_NO_MEMORY: 3286 return (stash_scferror_err(lcbdata, scfe)); 3287 3288 case SCF_ERROR_INVALID_ARGUMENT: 3289 semerr(gettext("The FMRI for the \"%s\" dependent is " 3290 "invalid.\n"), pgrp->sc_pgroup_name); 3291 return (stash_scferror_err(lcbdata, scfe)); 3292 3293 case SCF_ERROR_CONSTRAINT_VIOLATED: 3294 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 3295 "specifies neither a service nor an instance.\n"), 3296 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3297 return (stash_scferror_err(lcbdata, scfe)); 3298 3299 case SCF_ERROR_NOT_FOUND: 3300 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3301 &dependent_cbdata.sc_parent, &isservice); 3302 switch (scfe) { 3303 case SCF_ERROR_NONE: 3304 break; 3305 3306 case SCF_ERROR_NO_MEMORY: 3307 case SCF_ERROR_BACKEND_READONLY: 3308 case SCF_ERROR_BACKEND_ACCESS: 3309 return (stash_scferror_err(lcbdata, scfe)); 3310 3311 case SCF_ERROR_NOT_FOUND: 3312 semerr(gettext("The scope in FMRI \"%s\" for the " 3313 "\"%s\" dependent does not exist.\n"), 3314 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3315 lcbdata->sc_err = EINVAL; 3316 return (UU_WALK_ERROR); 3317 3318 case SCF_ERROR_PERMISSION_DENIED: 3319 warn(gettext( 3320 "Could not create %s (permission denied).\n"), 3321 pgrp->sc_pgroup_fmri); 3322 return (stash_scferror_err(lcbdata, scfe)); 3323 3324 case SCF_ERROR_INVALID_ARGUMENT: 3325 case SCF_ERROR_CONSTRAINT_VIOLATED: 3326 default: 3327 bad_error("create_entity", scfe); 3328 } 3329 break; 3330 3331 default: 3332 bad_error("fmri_to_entity", scfe); 3333 } 3334 3335 if (lcbdata->sc_trans != NULL) { 3336 e = scf_entry_create(lcbdata->sc_handle); 3337 if (e == NULL) { 3338 if (scf_error() != SCF_ERROR_NO_MEMORY) 3339 bad_error("scf_entry_create", scf_error()); 3340 3341 entity_destroy(dependent_cbdata.sc_parent, isservice); 3342 return (stash_scferror(lcbdata)); 3343 } 3344 3345 if (scf_transaction_property_new(lcbdata->sc_trans, e, 3346 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 3347 switch (scf_error()) { 3348 case SCF_ERROR_INVALID_ARGUMENT: 3349 warn(gettext("Dependent of %s has invalid name " 3350 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 3351 pgrp->sc_pgroup_name); 3352 /* FALLTHROUGH */ 3353 3354 case SCF_ERROR_DELETED: 3355 case SCF_ERROR_CONNECTION_BROKEN: 3356 scf_entry_destroy(e); 3357 entity_destroy(dependent_cbdata.sc_parent, 3358 isservice); 3359 return (stash_scferror(lcbdata)); 3360 3361 case SCF_ERROR_EXISTS: 3362 scf_entry_destroy(e); 3363 entity_destroy(dependent_cbdata.sc_parent, 3364 isservice); 3365 lcbdata->sc_err = EALREADY; 3366 return (UU_WALK_ERROR); 3367 3368 case SCF_ERROR_NOT_BOUND: 3369 case SCF_ERROR_HANDLE_MISMATCH: 3370 case SCF_ERROR_NOT_SET: 3371 default: 3372 bad_error("scf_transaction_property_new", 3373 scf_error()); 3374 } 3375 } 3376 3377 val = scf_value_create(lcbdata->sc_handle); 3378 if (val == NULL) { 3379 if (scf_error() != SCF_ERROR_NO_MEMORY) 3380 bad_error("scf_value_create", scf_error()); 3381 3382 entity_destroy(dependent_cbdata.sc_parent, isservice); 3383 return (stash_scferror(lcbdata)); 3384 } 3385 3386 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3387 pgrp->sc_pgroup_fmri) != 0) 3388 /* invalid should have been caught above */ 3389 bad_error("scf_value_set_from_string", scf_error()); 3390 3391 if (scf_entry_add_value(e, val) != 0) 3392 bad_error("scf_entry_add_value", scf_error()); 3393 } 3394 3395 /* Add the property group to the target entity. */ 3396 3397 dependent_cbdata.sc_handle = lcbdata->sc_handle; 3398 dependent_cbdata.sc_flags = lcbdata->sc_flags; 3399 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 3400 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 3401 3402 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 3403 3404 entity_destroy(dependent_cbdata.sc_parent, isservice); 3405 3406 if (ret == UU_WALK_NEXT) 3407 return (ret); 3408 3409 if (ret != UU_WALK_ERROR) 3410 bad_error("entity_pgroup_import", ret); 3411 3412 switch (dependent_cbdata.sc_err) { 3413 case ECANCELED: 3414 warn(gettext("%s deleted unexpectedly.\n"), 3415 pgrp->sc_pgroup_fmri); 3416 lcbdata->sc_err = EBUSY; 3417 break; 3418 3419 case EEXIST: 3420 warn(gettext("Could not create \"%s\" dependency in %s " 3421 "(already exists).\n"), pgrp->sc_pgroup_name, 3422 pgrp->sc_pgroup_fmri); 3423 /* FALLTHROUGH */ 3424 3425 default: 3426 lcbdata->sc_err = dependent_cbdata.sc_err; 3427 } 3428 3429 return (UU_WALK_ERROR); 3430 } 3431 3432 static int upgrade_dependent(const scf_property_t *, const entity_t *, 3433 const scf_snaplevel_t *, scf_transaction_t *); 3434 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 3435 const pgroup_t *); 3436 3437 /* 3438 * Upgrade uncustomized dependents of ent to those specified in ient. Read 3439 * the current dependent targets from running (the snaplevel of a running 3440 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 3441 * scf_instance_t * according to ient, otherwise). Draw the ancestral 3442 * dependent targets and dependency properties from li_dpts_pg (the 3443 * "dependents" property group in snpl) and snpl (the snaplevel which 3444 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 3445 * snpl doesn't have a "dependents" property group, and any dependents in ient 3446 * are new. 3447 * 3448 * Returns 3449 * 0 - success 3450 * ECONNABORTED - repository connection broken 3451 * ENOMEM - out of memory 3452 * ENOSPC - configd is out of resources 3453 * ECANCELED - ent was deleted 3454 * ENODEV - the entity containing li_dpts_pg was deleted 3455 * EPERM - could not modify dependents pg (permission denied) (error printed) 3456 * - couldn't upgrade dependent (permission denied) (error printed) 3457 * - couldn't create dependent (permission denied) (error printed) 3458 * EROFS - could not modify dependents pg (repository read-only) 3459 * - couldn't upgrade dependent (repository read-only) 3460 * - couldn't create dependent (repository read-only) 3461 * EACCES - could not modify dependents pg (backend access denied) 3462 * - could not upgrade dependent (backend access denied) 3463 * - could not create dependent (backend access denied) 3464 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 3465 * - dependent target deleted (error printed) 3466 * - dependent pg changed (error printed) 3467 * EINVAL - new dependent is invalid (error printed) 3468 * EBADF - snpl is corrupt (error printed) 3469 * - snpl has corrupt pg (error printed) 3470 * - dependency pg in target is corrupt (error printed) 3471 * - target has corrupt snapshot (error printed) 3472 * EEXIST - dependency pg already existed in target service (error printed) 3473 */ 3474 static int 3475 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 3476 const scf_snaplevel_t *snpl, const entity_t *ient, 3477 const scf_snaplevel_t *running, void *ent) 3478 { 3479 pgroup_t *new_dpt_pgroup; 3480 scf_callback_t cbdata; 3481 int r, unseen, tx_started = 0; 3482 int have_cur_depts; 3483 3484 const char * const dependents = "dependents"; 3485 3486 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3487 3488 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 3489 /* Nothing to do. */ 3490 return (0); 3491 3492 /* Fetch the current version of the "dependents" property group. */ 3493 have_cur_depts = 1; 3494 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 3495 switch (scf_error()) { 3496 case SCF_ERROR_NOT_FOUND: 3497 break; 3498 3499 case SCF_ERROR_DELETED: 3500 case SCF_ERROR_CONNECTION_BROKEN: 3501 return (scferror2errno(scf_error())); 3502 3503 case SCF_ERROR_NOT_SET: 3504 case SCF_ERROR_INVALID_ARGUMENT: 3505 case SCF_ERROR_HANDLE_MISMATCH: 3506 case SCF_ERROR_NOT_BOUND: 3507 default: 3508 bad_error("entity_get_pg", scf_error()); 3509 } 3510 3511 have_cur_depts = 0; 3512 } 3513 3514 /* Fetch the running version of the "dependents" property group. */ 3515 ud_run_dpts_pg_set = 0; 3516 if (running != NULL) 3517 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 3518 else 3519 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 3520 if (r == 0) { 3521 ud_run_dpts_pg_set = 1; 3522 } else { 3523 switch (scf_error()) { 3524 case SCF_ERROR_NOT_FOUND: 3525 break; 3526 3527 case SCF_ERROR_DELETED: 3528 case SCF_ERROR_CONNECTION_BROKEN: 3529 return (scferror2errno(scf_error())); 3530 3531 case SCF_ERROR_NOT_SET: 3532 case SCF_ERROR_INVALID_ARGUMENT: 3533 case SCF_ERROR_HANDLE_MISMATCH: 3534 case SCF_ERROR_NOT_BOUND: 3535 default: 3536 bad_error(running ? "scf_snaplevel_get_pg" : 3537 "entity_get_pg", scf_error()); 3538 } 3539 } 3540 3541 /* 3542 * Clear the seen fields of the dependents, so we can tell which ones 3543 * are new. 3544 */ 3545 if (uu_list_walk(ient->sc_dependents, clear_int, 3546 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3547 bad_error("uu_list_walk", uu_error()); 3548 3549 if (li_dpts_pg != NULL) { 3550 /* 3551 * Each property in li_dpts_pg represents a dependent tag in 3552 * the old manifest. For each, call upgrade_dependent(), 3553 * which will change ud_cur_depts_pg or dependencies in other 3554 * services as appropriate. Note (a) that changes to 3555 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3556 * made en masse, and (b) it's ok if the entity doesn't have 3557 * a current version of the "dependents" property group, 3558 * because we'll just consider all dependents as customized 3559 * (by being deleted). 3560 */ 3561 3562 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3563 switch (scf_error()) { 3564 case SCF_ERROR_DELETED: 3565 return (ENODEV); 3566 3567 case SCF_ERROR_CONNECTION_BROKEN: 3568 return (ECONNABORTED); 3569 3570 case SCF_ERROR_HANDLE_MISMATCH: 3571 case SCF_ERROR_NOT_BOUND: 3572 case SCF_ERROR_NOT_SET: 3573 default: 3574 bad_error("scf_iter_pg_properties", 3575 scf_error()); 3576 } 3577 } 3578 3579 if (have_cur_depts && 3580 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3581 switch (scf_error()) { 3582 case SCF_ERROR_BACKEND_ACCESS: 3583 case SCF_ERROR_BACKEND_READONLY: 3584 case SCF_ERROR_CONNECTION_BROKEN: 3585 return (scferror2errno(scf_error())); 3586 3587 case SCF_ERROR_DELETED: 3588 warn(emsg_pg_deleted, ient->sc_fmri, 3589 dependents); 3590 return (EBUSY); 3591 3592 case SCF_ERROR_PERMISSION_DENIED: 3593 warn(emsg_pg_mod_perm, dependents, 3594 ient->sc_fmri); 3595 return (scferror2errno(scf_error())); 3596 3597 case SCF_ERROR_HANDLE_MISMATCH: 3598 case SCF_ERROR_IN_USE: 3599 case SCF_ERROR_NOT_BOUND: 3600 case SCF_ERROR_NOT_SET: 3601 default: 3602 bad_error("scf_transaction_start", scf_error()); 3603 } 3604 } 3605 tx_started = have_cur_depts; 3606 3607 for (;;) { 3608 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3609 if (r == 0) 3610 break; 3611 if (r == 1) { 3612 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3613 tx_started ? ud_tx : NULL); 3614 switch (r) { 3615 case 0: 3616 continue; 3617 3618 case ECONNABORTED: 3619 case ENOMEM: 3620 case ENOSPC: 3621 case EBADF: 3622 case EBUSY: 3623 case EINVAL: 3624 case EPERM: 3625 case EROFS: 3626 case EACCES: 3627 case EEXIST: 3628 break; 3629 3630 case ECANCELED: 3631 r = ENODEV; 3632 break; 3633 3634 default: 3635 bad_error("upgrade_dependent", r); 3636 } 3637 3638 if (tx_started) 3639 scf_transaction_destroy_children(ud_tx); 3640 return (r); 3641 } 3642 if (r != -1) 3643 bad_error("scf_iter_next_property", r); 3644 3645 switch (scf_error()) { 3646 case SCF_ERROR_DELETED: 3647 r = ENODEV; 3648 break; 3649 3650 case SCF_ERROR_CONNECTION_BROKEN: 3651 r = ECONNABORTED; 3652 break; 3653 3654 case SCF_ERROR_NOT_SET: 3655 case SCF_ERROR_INVALID_ARGUMENT: 3656 case SCF_ERROR_NOT_BOUND: 3657 case SCF_ERROR_HANDLE_MISMATCH: 3658 default: 3659 bad_error("scf_iter_next_property", 3660 scf_error()); 3661 } 3662 3663 if (tx_started) 3664 scf_transaction_destroy_children(ud_tx); 3665 return (r); 3666 } 3667 } 3668 3669 /* import unseen dependents */ 3670 unseen = 0; 3671 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3672 new_dpt_pgroup != NULL; 3673 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3674 new_dpt_pgroup)) { 3675 if (!new_dpt_pgroup->sc_pgroup_seen) { 3676 unseen = 1; 3677 break; 3678 } 3679 } 3680 3681 /* If there are none, exit early. */ 3682 if (unseen == 0) 3683 goto commit; 3684 3685 /* Set up for lscf_dependent_import() */ 3686 cbdata.sc_handle = g_hndl; 3687 cbdata.sc_parent = ent; 3688 cbdata.sc_service = issvc; 3689 cbdata.sc_flags = 0; 3690 3691 if (!have_cur_depts) { 3692 /* 3693 * We have new dependents to import, so we need a "dependents" 3694 * property group. 3695 */ 3696 if (issvc) 3697 r = scf_service_add_pg(ent, dependents, 3698 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3699 else 3700 r = scf_instance_add_pg(ent, dependents, 3701 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3702 if (r != 0) { 3703 switch (scf_error()) { 3704 case SCF_ERROR_DELETED: 3705 case SCF_ERROR_CONNECTION_BROKEN: 3706 case SCF_ERROR_BACKEND_READONLY: 3707 case SCF_ERROR_BACKEND_ACCESS: 3708 case SCF_ERROR_NO_RESOURCES: 3709 return (scferror2errno(scf_error())); 3710 3711 case SCF_ERROR_EXISTS: 3712 warn(emsg_pg_added, ient->sc_fmri, dependents); 3713 return (EBUSY); 3714 3715 case SCF_ERROR_PERMISSION_DENIED: 3716 warn(emsg_pg_add_perm, dependents, 3717 ient->sc_fmri); 3718 return (scferror2errno(scf_error())); 3719 3720 case SCF_ERROR_NOT_BOUND: 3721 case SCF_ERROR_HANDLE_MISMATCH: 3722 case SCF_ERROR_INVALID_ARGUMENT: 3723 case SCF_ERROR_NOT_SET: 3724 default: 3725 bad_error("scf_service_add_pg", scf_error()); 3726 } 3727 } 3728 } 3729 3730 cbdata.sc_trans = ud_tx; 3731 3732 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3733 switch (scf_error()) { 3734 case SCF_ERROR_CONNECTION_BROKEN: 3735 case SCF_ERROR_BACKEND_ACCESS: 3736 case SCF_ERROR_BACKEND_READONLY: 3737 return (scferror2errno(scf_error())); 3738 3739 case SCF_ERROR_DELETED: 3740 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3741 return (EBUSY); 3742 3743 case SCF_ERROR_PERMISSION_DENIED: 3744 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3745 return (scferror2errno(scf_error())); 3746 3747 case SCF_ERROR_HANDLE_MISMATCH: 3748 case SCF_ERROR_IN_USE: 3749 case SCF_ERROR_NOT_BOUND: 3750 case SCF_ERROR_NOT_SET: 3751 default: 3752 bad_error("scf_transaction_start", scf_error()); 3753 } 3754 } 3755 tx_started = 1; 3756 3757 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3758 new_dpt_pgroup != NULL; 3759 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3760 new_dpt_pgroup)) { 3761 if (new_dpt_pgroup->sc_pgroup_seen) 3762 continue; 3763 3764 if (ud_run_dpts_pg_set) { 3765 /* 3766 * If the dependent is already there, then we have 3767 * a conflict. 3768 */ 3769 if (scf_pg_get_property(ud_run_dpts_pg, 3770 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3771 r = handle_dependent_conflict(ient, ud_prop, 3772 new_dpt_pgroup); 3773 switch (r) { 3774 case 0: 3775 continue; 3776 3777 case ECONNABORTED: 3778 case ENOMEM: 3779 case EBUSY: 3780 case EBADF: 3781 case EINVAL: 3782 scf_transaction_destroy_children(ud_tx); 3783 return (r); 3784 3785 default: 3786 bad_error("handle_dependent_conflict", 3787 r); 3788 } 3789 } else { 3790 switch (scf_error()) { 3791 case SCF_ERROR_NOT_FOUND: 3792 break; 3793 3794 case SCF_ERROR_INVALID_ARGUMENT: 3795 warn(emsg_fmri_invalid_pg_name, 3796 ient->sc_fmri, 3797 new_dpt_pgroup->sc_pgroup_name); 3798 scf_transaction_destroy_children(ud_tx); 3799 return (EINVAL); 3800 3801 case SCF_ERROR_DELETED: 3802 warn(emsg_pg_deleted, ient->sc_fmri, 3803 new_dpt_pgroup->sc_pgroup_name); 3804 scf_transaction_destroy_children(ud_tx); 3805 return (EBUSY); 3806 3807 case SCF_ERROR_CONNECTION_BROKEN: 3808 scf_transaction_destroy_children(ud_tx); 3809 return (ECONNABORTED); 3810 3811 case SCF_ERROR_NOT_BOUND: 3812 case SCF_ERROR_HANDLE_MISMATCH: 3813 case SCF_ERROR_NOT_SET: 3814 default: 3815 bad_error("scf_pg_get_property", 3816 scf_error()); 3817 } 3818 } 3819 } 3820 3821 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3822 if (r != UU_WALK_NEXT) { 3823 if (r != UU_WALK_ERROR) 3824 bad_error("lscf_dependent_import", r); 3825 3826 if (cbdata.sc_err == EALREADY) { 3827 /* Collisions were handled preemptively. */ 3828 bad_error("lscf_dependent_import", 3829 cbdata.sc_err); 3830 } 3831 3832 scf_transaction_destroy_children(ud_tx); 3833 return (cbdata.sc_err); 3834 } 3835 } 3836 3837 commit: 3838 if (!tx_started) 3839 return (0); 3840 3841 r = scf_transaction_commit(ud_tx); 3842 3843 scf_transaction_destroy_children(ud_tx); 3844 3845 switch (r) { 3846 case 1: 3847 return (0); 3848 3849 case 0: 3850 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3851 return (EBUSY); 3852 3853 case -1: 3854 break; 3855 3856 default: 3857 bad_error("scf_transaction_commit", r); 3858 } 3859 3860 switch (scf_error()) { 3861 case SCF_ERROR_CONNECTION_BROKEN: 3862 case SCF_ERROR_BACKEND_READONLY: 3863 case SCF_ERROR_BACKEND_ACCESS: 3864 case SCF_ERROR_NO_RESOURCES: 3865 return (scferror2errno(scf_error())); 3866 3867 case SCF_ERROR_DELETED: 3868 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3869 return (EBUSY); 3870 3871 case SCF_ERROR_PERMISSION_DENIED: 3872 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3873 return (scferror2errno(scf_error())); 3874 3875 case SCF_ERROR_NOT_BOUND: 3876 case SCF_ERROR_INVALID_ARGUMENT: 3877 case SCF_ERROR_NOT_SET: 3878 default: 3879 bad_error("scf_transaction_destroy", scf_error()); 3880 /* NOTREACHED */ 3881 } 3882 } 3883 3884 /* 3885 * Used to add the manifests to the list of currently supported manifests. 3886 * We can modify the existing manifest list removing entries if the files 3887 * don't exist. 3888 * 3889 * Get the old list and the new file name 3890 * If the new file name is in the list return 3891 * If not then add the file to the list. 3892 * As we process the list check to see if the files in the old list exist 3893 * if not then remove the file from the list. 3894 * Commit the list of manifest file names. 3895 * 3896 */ 3897 static int 3898 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient, 3899 const scf_snaplevel_t *running, void *ent) 3900 { 3901 scf_propertygroup_t *ud_mfsts_pg = NULL; 3902 scf_property_t *ud_prop = NULL; 3903 scf_iter_t *ud_prop_iter; 3904 scf_value_t *fname_value; 3905 scf_callback_t cbdata; 3906 pgroup_t *mfst_pgroup; 3907 property_t *mfst_prop; 3908 property_t *old_prop; 3909 char *pname; 3910 char *fval; 3911 char *old_pname; 3912 char *old_fval; 3913 int no_upgrade_pg; 3914 int mfst_seen; 3915 int r; 3916 3917 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3918 3919 /* 3920 * This should always be the service base on the code 3921 * path, and the fact that the manifests pg is a service 3922 * level property group only. 3923 */ 3924 ud_mfsts_pg = scf_pg_create(g_hndl); 3925 ud_prop = scf_property_create(g_hndl); 3926 ud_prop_iter = scf_iter_create(g_hndl); 3927 fname_value = scf_value_create(g_hndl); 3928 3929 /* Fetch the "manifests" property group */ 3930 no_upgrade_pg = 0; 3931 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3932 ud_mfsts_pg); 3933 if (r != 0) { 3934 switch (scf_error()) { 3935 case SCF_ERROR_NOT_FOUND: 3936 no_upgrade_pg = 1; 3937 break; 3938 3939 case SCF_ERROR_DELETED: 3940 case SCF_ERROR_CONNECTION_BROKEN: 3941 return (scferror2errno(scf_error())); 3942 3943 case SCF_ERROR_NOT_SET: 3944 case SCF_ERROR_INVALID_ARGUMENT: 3945 case SCF_ERROR_HANDLE_MISMATCH: 3946 case SCF_ERROR_NOT_BOUND: 3947 default: 3948 bad_error(running ? "scf_snaplevel_get_pg" : 3949 "entity_get_pg", scf_error()); 3950 } 3951 } 3952 3953 if (no_upgrade_pg) { 3954 cbdata.sc_handle = g_hndl; 3955 cbdata.sc_parent = ent; 3956 cbdata.sc_service = issvc; 3957 cbdata.sc_flags = SCI_FORCE; 3958 cbdata.sc_source_fmri = ient->sc_fmri; 3959 cbdata.sc_target_fmri = ient->sc_fmri; 3960 3961 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3962 return (cbdata.sc_err); 3963 3964 return (0); 3965 } 3966 3967 /* Fetch the new manifests property group */ 3968 for (mfst_pgroup = uu_list_first(ient->sc_pgroups); 3969 mfst_pgroup != NULL; 3970 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) { 3971 if (strcmp(mfst_pgroup->sc_pgroup_name, 3972 SCF_PG_MANIFESTFILES) == 0) 3973 break; 3974 } 3975 3976 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3977 SCF_SUCCESS) 3978 return (-1); 3979 3980 if ((pname = malloc(MAXPATHLEN)) == NULL) 3981 return (ENOMEM); 3982 if ((fval = malloc(MAXPATHLEN)) == NULL) { 3983 free(pname); 3984 return (ENOMEM); 3985 } 3986 3987 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 3988 mfst_seen = 0; 3989 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 3990 continue; 3991 3992 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3993 mfst_prop != NULL; 3994 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3995 mfst_prop)) { 3996 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3997 mfst_seen = 1; 3998 } 3999 } 4000 4001 /* 4002 * If the manifest is not seen then add it to the new mfst 4003 * property list to get proccessed into the repo. 4004 */ 4005 if (mfst_seen == 0) { 4006 /* 4007 * If we cannot get the value then there is no 4008 * reason to attempt to attach the value to 4009 * the property group 4010 */ 4011 if (prop_get_val(ud_prop, fname_value) == 0 && 4012 scf_value_get_astring(fname_value, fval, 4013 MAXPATHLEN) != -1) { 4014 old_pname = safe_strdup(pname); 4015 old_fval = safe_strdup(fval); 4016 old_prop = internal_property_create(old_pname, 4017 SCF_TYPE_ASTRING, 1, old_fval); 4018 4019 /* 4020 * Already checked to see if the property exists 4021 * in the group, and it does not. 4022 */ 4023 (void) internal_attach_property(mfst_pgroup, 4024 old_prop); 4025 } 4026 } 4027 } 4028 free(pname); 4029 free(fval); 4030 4031 cbdata.sc_handle = g_hndl; 4032 cbdata.sc_parent = ent; 4033 cbdata.sc_service = issvc; 4034 cbdata.sc_flags = SCI_FORCE; 4035 cbdata.sc_source_fmri = ient->sc_fmri; 4036 cbdata.sc_target_fmri = ient->sc_fmri; 4037 4038 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 4039 return (cbdata.sc_err); 4040 4041 return (r); 4042 } 4043 4044 /* 4045 * prop is taken to be a property in the "dependents" property group of snpl, 4046 * which is taken to be the snaplevel of a last-import snapshot corresponding 4047 * to ient. If prop is a valid dependents property, upgrade the dependent it 4048 * represents according to the repository & ient. If ud_run_dpts_pg_set is 4049 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 4050 * of the entity ient represents (possibly in the running snapshot). If it 4051 * needs to be changed, an entry will be added to tx, if not NULL. 4052 * 4053 * Returns 4054 * 0 - success 4055 * ECONNABORTED - repository connection broken 4056 * ENOMEM - out of memory 4057 * ENOSPC - configd was out of resources 4058 * ECANCELED - snpl's entity was deleted 4059 * EINVAL - dependent target is invalid (error printed) 4060 * - dependent is invalid (error printed) 4061 * EBADF - snpl is corrupt (error printed) 4062 * - snpl has corrupt pg (error printed) 4063 * - dependency pg in target is corrupt (error printed) 4064 * - running snapshot in dependent is missing snaplevel (error printed) 4065 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 4066 * - couldn't create dependent (permission denied) (error printed) 4067 * - couldn't modify dependent pg (permission denied) (error printed) 4068 * EROFS - couldn't delete dependency pg (repository read-only) 4069 * - couldn't create dependent (repository read-only) 4070 * EACCES - couldn't delete dependency pg (backend access denied) 4071 * - couldn't create dependent (backend access denied) 4072 * EBUSY - ud_run_dpts_pg was deleted (error printed) 4073 * - tx's pg was deleted (error printed) 4074 * - dependent pg was changed or deleted (error printed) 4075 * EEXIST - dependency pg already exists in new target (error printed) 4076 */ 4077 static int 4078 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 4079 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 4080 { 4081 pgroup_t pgrp; 4082 scf_type_t ty; 4083 pgroup_t *new_dpt_pgroup; 4084 pgroup_t *old_dpt_pgroup = NULL; 4085 pgroup_t *current_pg; 4086 pgroup_t *dpt; 4087 scf_callback_t cbdata; 4088 int tissvc; 4089 void *target_ent; 4090 scf_error_t serr; 4091 int r; 4092 scf_transaction_entry_t *ent; 4093 4094 const char * const cf_inval = gettext("Conflict upgrading %s " 4095 "(dependent \"%s\" has invalid dependents property).\n"); 4096 const char * const cf_missing = gettext("Conflict upgrading %s " 4097 "(dependent \"%s\" is missing).\n"); 4098 const char * const cf_newdpg = gettext("Conflict upgrading %s " 4099 "(dependent \"%s\" has new dependency property group).\n"); 4100 const char * const cf_newtarg = gettext("Conflict upgrading %s " 4101 "(dependent \"%s\" has new target).\n"); 4102 const char * const li_corrupt = 4103 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 4104 const char * const upgrading = 4105 gettext("%s: Upgrading dependent \"%s\".\n"); 4106 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 4107 "corrupt (missing snaplevel).\n"); 4108 4109 if (scf_property_type(prop, &ty) != 0) { 4110 switch (scf_error()) { 4111 case SCF_ERROR_DELETED: 4112 case SCF_ERROR_CONNECTION_BROKEN: 4113 return (scferror2errno(scf_error())); 4114 4115 case SCF_ERROR_NOT_BOUND: 4116 case SCF_ERROR_NOT_SET: 4117 default: 4118 bad_error("scf_property_type", scf_error()); 4119 } 4120 } 4121 4122 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4123 warn(li_corrupt, ient->sc_fmri); 4124 return (EBADF); 4125 } 4126 4127 /* 4128 * prop represents a dependent in the old manifest. It is named after 4129 * the dependent. 4130 */ 4131 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 4132 switch (scf_error()) { 4133 case SCF_ERROR_DELETED: 4134 case SCF_ERROR_CONNECTION_BROKEN: 4135 return (scferror2errno(scf_error())); 4136 4137 case SCF_ERROR_NOT_BOUND: 4138 case SCF_ERROR_NOT_SET: 4139 default: 4140 bad_error("scf_property_get_name", scf_error()); 4141 } 4142 } 4143 4144 /* See if it's in the new manifest. */ 4145 pgrp.sc_pgroup_name = ud_name; 4146 new_dpt_pgroup = 4147 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 4148 4149 /* If it's not, delete it... if it hasn't been customized. */ 4150 if (new_dpt_pgroup == NULL) { 4151 if (!ud_run_dpts_pg_set) 4152 return (0); 4153 4154 if (scf_property_get_value(prop, ud_val) != 0) { 4155 switch (scf_error()) { 4156 case SCF_ERROR_NOT_FOUND: 4157 case SCF_ERROR_CONSTRAINT_VIOLATED: 4158 warn(li_corrupt, ient->sc_fmri); 4159 return (EBADF); 4160 4161 case SCF_ERROR_DELETED: 4162 case SCF_ERROR_CONNECTION_BROKEN: 4163 return (scferror2errno(scf_error())); 4164 4165 case SCF_ERROR_HANDLE_MISMATCH: 4166 case SCF_ERROR_NOT_BOUND: 4167 case SCF_ERROR_NOT_SET: 4168 case SCF_ERROR_PERMISSION_DENIED: 4169 default: 4170 bad_error("scf_property_get_value", 4171 scf_error()); 4172 } 4173 } 4174 4175 if (scf_value_get_as_string(ud_val, ud_oldtarg, 4176 max_scf_value_len + 1) < 0) 4177 bad_error("scf_value_get_as_string", scf_error()); 4178 4179 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 4180 0) { 4181 switch (scf_error()) { 4182 case SCF_ERROR_NOT_FOUND: 4183 return (0); 4184 4185 case SCF_ERROR_CONNECTION_BROKEN: 4186 return (scferror2errno(scf_error())); 4187 4188 case SCF_ERROR_DELETED: 4189 warn(emsg_pg_deleted, ient->sc_fmri, 4190 "dependents"); 4191 return (EBUSY); 4192 4193 case SCF_ERROR_INVALID_ARGUMENT: 4194 case SCF_ERROR_NOT_BOUND: 4195 case SCF_ERROR_HANDLE_MISMATCH: 4196 case SCF_ERROR_NOT_SET: 4197 default: 4198 bad_error("scf_pg_get_property", scf_error()); 4199 } 4200 } 4201 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4202 switch (scf_error()) { 4203 case SCF_ERROR_NOT_FOUND: 4204 case SCF_ERROR_CONSTRAINT_VIOLATED: 4205 warn(cf_inval, ient->sc_fmri, ud_name); 4206 return (0); 4207 4208 case SCF_ERROR_DELETED: 4209 case SCF_ERROR_CONNECTION_BROKEN: 4210 return (scferror2errno(scf_error())); 4211 4212 case SCF_ERROR_HANDLE_MISMATCH: 4213 case SCF_ERROR_NOT_BOUND: 4214 case SCF_ERROR_NOT_SET: 4215 case SCF_ERROR_PERMISSION_DENIED: 4216 default: 4217 bad_error("scf_property_get_value", 4218 scf_error()); 4219 } 4220 } 4221 4222 ty = scf_value_type(ud_val); 4223 assert(ty != SCF_TYPE_INVALID); 4224 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4225 warn(cf_inval, ient->sc_fmri, ud_name); 4226 return (0); 4227 } 4228 4229 if (scf_value_get_as_string(ud_val, ud_ctarg, 4230 max_scf_value_len + 1) < 0) 4231 bad_error("scf_value_get_as_string", scf_error()); 4232 4233 r = fmri_equal(ud_ctarg, ud_oldtarg); 4234 switch (r) { 4235 case 1: 4236 break; 4237 4238 case 0: 4239 case -1: /* warn? */ 4240 warn(cf_newtarg, ient->sc_fmri, ud_name); 4241 return (0); 4242 4243 case -2: 4244 warn(li_corrupt, ient->sc_fmri); 4245 return (EBADF); 4246 4247 default: 4248 bad_error("fmri_equal", r); 4249 } 4250 4251 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4252 switch (scf_error()) { 4253 case SCF_ERROR_NOT_FOUND: 4254 warn(li_corrupt, ient->sc_fmri); 4255 return (EBADF); 4256 4257 case SCF_ERROR_DELETED: 4258 case SCF_ERROR_CONNECTION_BROKEN: 4259 return (scferror2errno(scf_error())); 4260 4261 case SCF_ERROR_NOT_BOUND: 4262 case SCF_ERROR_HANDLE_MISMATCH: 4263 case SCF_ERROR_INVALID_ARGUMENT: 4264 case SCF_ERROR_NOT_SET: 4265 default: 4266 bad_error("scf_snaplevel_get_pg", scf_error()); 4267 } 4268 } 4269 4270 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4271 snap_lastimport); 4272 switch (r) { 4273 case 0: 4274 break; 4275 4276 case ECANCELED: 4277 case ECONNABORTED: 4278 case ENOMEM: 4279 case EBADF: 4280 return (r); 4281 4282 case EACCES: 4283 default: 4284 bad_error("load_pg", r); 4285 } 4286 4287 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4288 switch (serr) { 4289 case SCF_ERROR_NONE: 4290 break; 4291 4292 case SCF_ERROR_NO_MEMORY: 4293 internal_pgroup_free(old_dpt_pgroup); 4294 return (ENOMEM); 4295 4296 case SCF_ERROR_NOT_FOUND: 4297 internal_pgroup_free(old_dpt_pgroup); 4298 goto delprop; 4299 4300 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 4301 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 4302 default: 4303 bad_error("fmri_to_entity", serr); 4304 } 4305 4306 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4307 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4308 switch (r) { 4309 case 0: 4310 break; 4311 4312 case ECONNABORTED: 4313 internal_pgroup_free(old_dpt_pgroup); 4314 return (r); 4315 4316 case ECANCELED: 4317 case ENOENT: 4318 internal_pgroup_free(old_dpt_pgroup); 4319 goto delprop; 4320 4321 case EBADF: 4322 warn(r_no_lvl, ud_ctarg); 4323 internal_pgroup_free(old_dpt_pgroup); 4324 return (r); 4325 4326 case EINVAL: 4327 default: 4328 bad_error("entity_get_running_pg", r); 4329 } 4330 4331 /* load it */ 4332 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4333 switch (r) { 4334 case 0: 4335 break; 4336 4337 case ECANCELED: 4338 internal_pgroup_free(old_dpt_pgroup); 4339 goto delprop; 4340 4341 case ECONNABORTED: 4342 case ENOMEM: 4343 case EBADF: 4344 internal_pgroup_free(old_dpt_pgroup); 4345 return (r); 4346 4347 case EACCES: 4348 default: 4349 bad_error("load_pg", r); 4350 } 4351 4352 /* compare property groups */ 4353 if (!pg_equal(old_dpt_pgroup, current_pg)) { 4354 warn(cf_newdpg, ient->sc_fmri, ud_name); 4355 internal_pgroup_free(old_dpt_pgroup); 4356 internal_pgroup_free(current_pg); 4357 return (0); 4358 } 4359 4360 internal_pgroup_free(old_dpt_pgroup); 4361 internal_pgroup_free(current_pg); 4362 4363 if (g_verbose) 4364 warn(gettext("%s: Deleting dependent \"%s\".\n"), 4365 ient->sc_fmri, ud_name); 4366 4367 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4368 switch (scf_error()) { 4369 case SCF_ERROR_NOT_FOUND: 4370 case SCF_ERROR_DELETED: 4371 internal_pgroup_free(old_dpt_pgroup); 4372 goto delprop; 4373 4374 case SCF_ERROR_CONNECTION_BROKEN: 4375 internal_pgroup_free(old_dpt_pgroup); 4376 return (ECONNABORTED); 4377 4378 case SCF_ERROR_NOT_SET: 4379 case SCF_ERROR_INVALID_ARGUMENT: 4380 case SCF_ERROR_HANDLE_MISMATCH: 4381 case SCF_ERROR_NOT_BOUND: 4382 default: 4383 bad_error("entity_get_pg", scf_error()); 4384 } 4385 } 4386 4387 if (scf_pg_delete(ud_pg) != 0) { 4388 switch (scf_error()) { 4389 case SCF_ERROR_DELETED: 4390 break; 4391 4392 case SCF_ERROR_CONNECTION_BROKEN: 4393 case SCF_ERROR_BACKEND_READONLY: 4394 case SCF_ERROR_BACKEND_ACCESS: 4395 return (scferror2errno(scf_error())); 4396 4397 case SCF_ERROR_PERMISSION_DENIED: 4398 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4399 return (scferror2errno(scf_error())); 4400 4401 case SCF_ERROR_NOT_SET: 4402 default: 4403 bad_error("scf_pg_delete", scf_error()); 4404 } 4405 } 4406 4407 /* 4408 * This service was changed, so it must be refreshed. But 4409 * since it's not mentioned in the new manifest, we have to 4410 * record its FMRI here for use later. We record the name 4411 * & the entity (via sc_parent) in case we need to print error 4412 * messages during the refresh. 4413 */ 4414 dpt = internal_pgroup_new(); 4415 if (dpt == NULL) 4416 return (ENOMEM); 4417 dpt->sc_pgroup_name = strdup(ud_name); 4418 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 4419 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4420 return (ENOMEM); 4421 dpt->sc_parent = (entity_t *)ient; 4422 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4423 uu_die(gettext("libuutil error: %s\n"), 4424 uu_strerror(uu_error())); 4425 4426 delprop: 4427 if (tx == NULL) 4428 return (0); 4429 4430 ent = scf_entry_create(g_hndl); 4431 if (ent == NULL) 4432 return (ENOMEM); 4433 4434 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 4435 scf_entry_destroy(ent); 4436 switch (scf_error()) { 4437 case SCF_ERROR_DELETED: 4438 warn(emsg_pg_deleted, ient->sc_fmri, 4439 "dependents"); 4440 return (EBUSY); 4441 4442 case SCF_ERROR_CONNECTION_BROKEN: 4443 return (scferror2errno(scf_error())); 4444 4445 case SCF_ERROR_NOT_FOUND: 4446 break; 4447 4448 case SCF_ERROR_HANDLE_MISMATCH: 4449 case SCF_ERROR_NOT_BOUND: 4450 case SCF_ERROR_INVALID_ARGUMENT: 4451 case SCF_ERROR_NOT_SET: 4452 default: 4453 bad_error("scf_transaction_property_delete", 4454 scf_error()); 4455 } 4456 } 4457 4458 return (0); 4459 } 4460 4461 new_dpt_pgroup->sc_pgroup_seen = 1; 4462 4463 /* 4464 * Decide whether the dependent has changed in the manifest. 4465 */ 4466 /* Compare the target. */ 4467 if (scf_property_get_value(prop, ud_val) != 0) { 4468 switch (scf_error()) { 4469 case SCF_ERROR_NOT_FOUND: 4470 case SCF_ERROR_CONSTRAINT_VIOLATED: 4471 warn(li_corrupt, ient->sc_fmri); 4472 return (EBADF); 4473 4474 case SCF_ERROR_DELETED: 4475 case SCF_ERROR_CONNECTION_BROKEN: 4476 return (scferror2errno(scf_error())); 4477 4478 case SCF_ERROR_HANDLE_MISMATCH: 4479 case SCF_ERROR_NOT_BOUND: 4480 case SCF_ERROR_NOT_SET: 4481 case SCF_ERROR_PERMISSION_DENIED: 4482 default: 4483 bad_error("scf_property_get_value", scf_error()); 4484 } 4485 } 4486 4487 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 4488 0) 4489 bad_error("scf_value_get_as_string", scf_error()); 4490 4491 /* 4492 * If the fmri's are not equal then the old fmri will need to 4493 * be refreshed to ensure that the changes are properly updated 4494 * in that service. 4495 */ 4496 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 4497 switch (r) { 4498 case 0: 4499 dpt = internal_pgroup_new(); 4500 if (dpt == NULL) 4501 return (ENOMEM); 4502 dpt->sc_pgroup_name = strdup(ud_name); 4503 dpt->sc_pgroup_fmri = strdup(ud_oldtarg); 4504 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4505 return (ENOMEM); 4506 dpt->sc_parent = (entity_t *)ient; 4507 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4508 uu_die(gettext("libuutil error: %s\n"), 4509 uu_strerror(uu_error())); 4510 break; 4511 4512 case 1: 4513 /* Compare the dependency pgs. */ 4514 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4515 switch (scf_error()) { 4516 case SCF_ERROR_NOT_FOUND: 4517 warn(li_corrupt, ient->sc_fmri); 4518 return (EBADF); 4519 4520 case SCF_ERROR_DELETED: 4521 case SCF_ERROR_CONNECTION_BROKEN: 4522 return (scferror2errno(scf_error())); 4523 4524 case SCF_ERROR_NOT_BOUND: 4525 case SCF_ERROR_HANDLE_MISMATCH: 4526 case SCF_ERROR_INVALID_ARGUMENT: 4527 case SCF_ERROR_NOT_SET: 4528 default: 4529 bad_error("scf_snaplevel_get_pg", scf_error()); 4530 } 4531 } 4532 4533 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4534 snap_lastimport); 4535 switch (r) { 4536 case 0: 4537 break; 4538 4539 case ECANCELED: 4540 case ECONNABORTED: 4541 case ENOMEM: 4542 case EBADF: 4543 return (r); 4544 4545 case EACCES: 4546 default: 4547 bad_error("load_pg", r); 4548 } 4549 4550 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4551 /* no change, leave customizations */ 4552 internal_pgroup_free(old_dpt_pgroup); 4553 return (0); 4554 } 4555 break; 4556 4557 case -1: 4558 warn(li_corrupt, ient->sc_fmri); 4559 return (EBADF); 4560 4561 case -2: 4562 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4563 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4564 return (EINVAL); 4565 4566 default: 4567 bad_error("fmri_equal", r); 4568 } 4569 4570 /* 4571 * The dependent has changed in the manifest. Upgrade the current 4572 * properties if they haven't been customized. 4573 */ 4574 4575 /* 4576 * If new_dpt_pgroup->sc_override, then act as though the property 4577 * group hasn't been customized. 4578 */ 4579 if (new_dpt_pgroup->sc_pgroup_override) { 4580 (void) strcpy(ud_ctarg, ud_oldtarg); 4581 goto nocust; 4582 } 4583 4584 if (!ud_run_dpts_pg_set) { 4585 warn(cf_missing, ient->sc_fmri, ud_name); 4586 r = 0; 4587 goto out; 4588 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4589 switch (scf_error()) { 4590 case SCF_ERROR_NOT_FOUND: 4591 warn(cf_missing, ient->sc_fmri, ud_name); 4592 r = 0; 4593 goto out; 4594 4595 case SCF_ERROR_CONNECTION_BROKEN: 4596 r = scferror2errno(scf_error()); 4597 goto out; 4598 4599 case SCF_ERROR_DELETED: 4600 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4601 r = EBUSY; 4602 goto out; 4603 4604 case SCF_ERROR_INVALID_ARGUMENT: 4605 case SCF_ERROR_NOT_BOUND: 4606 case SCF_ERROR_HANDLE_MISMATCH: 4607 case SCF_ERROR_NOT_SET: 4608 default: 4609 bad_error("scf_pg_get_property", scf_error()); 4610 } 4611 } 4612 4613 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4614 switch (scf_error()) { 4615 case SCF_ERROR_NOT_FOUND: 4616 case SCF_ERROR_CONSTRAINT_VIOLATED: 4617 warn(cf_inval, ient->sc_fmri, ud_name); 4618 r = 0; 4619 goto out; 4620 4621 case SCF_ERROR_DELETED: 4622 case SCF_ERROR_CONNECTION_BROKEN: 4623 r = scferror2errno(scf_error()); 4624 goto out; 4625 4626 case SCF_ERROR_HANDLE_MISMATCH: 4627 case SCF_ERROR_NOT_BOUND: 4628 case SCF_ERROR_NOT_SET: 4629 case SCF_ERROR_PERMISSION_DENIED: 4630 default: 4631 bad_error("scf_property_get_value", scf_error()); 4632 } 4633 } 4634 4635 ty = scf_value_type(ud_val); 4636 assert(ty != SCF_TYPE_INVALID); 4637 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4638 warn(cf_inval, ient->sc_fmri, ud_name); 4639 r = 0; 4640 goto out; 4641 } 4642 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4643 0) 4644 bad_error("scf_value_get_as_string", scf_error()); 4645 4646 r = fmri_equal(ud_ctarg, ud_oldtarg); 4647 if (r == -1) { 4648 warn(cf_inval, ient->sc_fmri, ud_name); 4649 r = 0; 4650 goto out; 4651 } else if (r == -2) { 4652 warn(li_corrupt, ient->sc_fmri); 4653 r = EBADF; 4654 goto out; 4655 } else if (r == 0) { 4656 /* 4657 * Target has been changed. Only abort now if it's been 4658 * changed to something other than what's in the manifest. 4659 */ 4660 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4661 if (r == -1) { 4662 warn(cf_inval, ient->sc_fmri, ud_name); 4663 r = 0; 4664 goto out; 4665 } else if (r == 0) { 4666 warn(cf_newtarg, ient->sc_fmri, ud_name); 4667 r = 0; 4668 goto out; 4669 } else if (r != 1) { 4670 /* invalid sc_pgroup_fmri caught above */ 4671 bad_error("fmri_equal", r); 4672 } 4673 4674 /* 4675 * Fetch the current dependency pg. If it's what the manifest 4676 * says, then no problem. 4677 */ 4678 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4679 switch (serr) { 4680 case SCF_ERROR_NONE: 4681 break; 4682 4683 case SCF_ERROR_NOT_FOUND: 4684 warn(cf_missing, ient->sc_fmri, ud_name); 4685 r = 0; 4686 goto out; 4687 4688 case SCF_ERROR_NO_MEMORY: 4689 r = ENOMEM; 4690 goto out; 4691 4692 case SCF_ERROR_CONSTRAINT_VIOLATED: 4693 case SCF_ERROR_INVALID_ARGUMENT: 4694 default: 4695 bad_error("fmri_to_entity", serr); 4696 } 4697 4698 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4699 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4700 switch (r) { 4701 case 0: 4702 break; 4703 4704 case ECONNABORTED: 4705 goto out; 4706 4707 case ECANCELED: 4708 case ENOENT: 4709 warn(cf_missing, ient->sc_fmri, ud_name); 4710 r = 0; 4711 goto out; 4712 4713 case EBADF: 4714 warn(r_no_lvl, ud_ctarg); 4715 goto out; 4716 4717 case EINVAL: 4718 default: 4719 bad_error("entity_get_running_pg", r); 4720 } 4721 4722 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4723 switch (r) { 4724 case 0: 4725 break; 4726 4727 case ECANCELED: 4728 warn(cf_missing, ient->sc_fmri, ud_name); 4729 r = 0; 4730 goto out; 4731 4732 case ECONNABORTED: 4733 case ENOMEM: 4734 case EBADF: 4735 goto out; 4736 4737 case EACCES: 4738 default: 4739 bad_error("load_pg", r); 4740 } 4741 4742 if (!pg_equal(current_pg, new_dpt_pgroup)) 4743 warn(cf_newdpg, ient->sc_fmri, ud_name); 4744 internal_pgroup_free(current_pg); 4745 r = 0; 4746 goto out; 4747 } else if (r != 1) { 4748 bad_error("fmri_equal", r); 4749 } 4750 4751 nocust: 4752 /* 4753 * Target has not been customized. Check the dependency property 4754 * group. 4755 */ 4756 4757 if (old_dpt_pgroup == NULL) { 4758 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4759 ud_pg) != 0) { 4760 switch (scf_error()) { 4761 case SCF_ERROR_NOT_FOUND: 4762 warn(li_corrupt, ient->sc_fmri); 4763 return (EBADF); 4764 4765 case SCF_ERROR_DELETED: 4766 case SCF_ERROR_CONNECTION_BROKEN: 4767 return (scferror2errno(scf_error())); 4768 4769 case SCF_ERROR_NOT_BOUND: 4770 case SCF_ERROR_HANDLE_MISMATCH: 4771 case SCF_ERROR_INVALID_ARGUMENT: 4772 case SCF_ERROR_NOT_SET: 4773 default: 4774 bad_error("scf_snaplevel_get_pg", scf_error()); 4775 } 4776 } 4777 4778 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4779 snap_lastimport); 4780 switch (r) { 4781 case 0: 4782 break; 4783 4784 case ECANCELED: 4785 case ECONNABORTED: 4786 case ENOMEM: 4787 case EBADF: 4788 return (r); 4789 4790 case EACCES: 4791 default: 4792 bad_error("load_pg", r); 4793 } 4794 } 4795 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4796 switch (serr) { 4797 case SCF_ERROR_NONE: 4798 break; 4799 4800 case SCF_ERROR_NOT_FOUND: 4801 warn(cf_missing, ient->sc_fmri, ud_name); 4802 r = 0; 4803 goto out; 4804 4805 case SCF_ERROR_NO_MEMORY: 4806 r = ENOMEM; 4807 goto out; 4808 4809 case SCF_ERROR_CONSTRAINT_VIOLATED: 4810 case SCF_ERROR_INVALID_ARGUMENT: 4811 default: 4812 bad_error("fmri_to_entity", serr); 4813 } 4814 4815 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4816 ud_iter2, ud_inst, imp_snap, ud_snpl); 4817 switch (r) { 4818 case 0: 4819 break; 4820 4821 case ECONNABORTED: 4822 goto out; 4823 4824 case ECANCELED: 4825 case ENOENT: 4826 warn(cf_missing, ient->sc_fmri, ud_name); 4827 r = 0; 4828 goto out; 4829 4830 case EBADF: 4831 warn(r_no_lvl, ud_ctarg); 4832 goto out; 4833 4834 case EINVAL: 4835 default: 4836 bad_error("entity_get_running_pg", r); 4837 } 4838 4839 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4840 switch (r) { 4841 case 0: 4842 break; 4843 4844 case ECANCELED: 4845 warn(cf_missing, ient->sc_fmri, ud_name); 4846 goto out; 4847 4848 case ECONNABORTED: 4849 case ENOMEM: 4850 case EBADF: 4851 goto out; 4852 4853 case EACCES: 4854 default: 4855 bad_error("load_pg", r); 4856 } 4857 4858 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4859 if (!pg_equal(current_pg, new_dpt_pgroup)) 4860 warn(cf_newdpg, ient->sc_fmri, ud_name); 4861 internal_pgroup_free(current_pg); 4862 r = 0; 4863 goto out; 4864 } 4865 4866 /* Uncustomized. Upgrade. */ 4867 4868 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4869 switch (r) { 4870 case 1: 4871 if (pg_equal(current_pg, new_dpt_pgroup)) { 4872 /* Already upgraded. */ 4873 internal_pgroup_free(current_pg); 4874 r = 0; 4875 goto out; 4876 } 4877 4878 internal_pgroup_free(current_pg); 4879 4880 /* upgrade current_pg */ 4881 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4882 switch (scf_error()) { 4883 case SCF_ERROR_CONNECTION_BROKEN: 4884 r = scferror2errno(scf_error()); 4885 goto out; 4886 4887 case SCF_ERROR_DELETED: 4888 warn(cf_missing, ient->sc_fmri, ud_name); 4889 r = 0; 4890 goto out; 4891 4892 case SCF_ERROR_NOT_FOUND: 4893 break; 4894 4895 case SCF_ERROR_INVALID_ARGUMENT: 4896 case SCF_ERROR_NOT_BOUND: 4897 case SCF_ERROR_NOT_SET: 4898 case SCF_ERROR_HANDLE_MISMATCH: 4899 default: 4900 bad_error("entity_get_pg", scf_error()); 4901 } 4902 4903 if (tissvc) 4904 r = scf_service_add_pg(target_ent, ud_name, 4905 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4906 else 4907 r = scf_instance_add_pg(target_ent, ud_name, 4908 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4909 if (r != 0) { 4910 switch (scf_error()) { 4911 case SCF_ERROR_CONNECTION_BROKEN: 4912 case SCF_ERROR_NO_RESOURCES: 4913 case SCF_ERROR_BACKEND_READONLY: 4914 case SCF_ERROR_BACKEND_ACCESS: 4915 r = scferror2errno(scf_error()); 4916 goto out; 4917 4918 case SCF_ERROR_DELETED: 4919 warn(cf_missing, ient->sc_fmri, 4920 ud_name); 4921 r = 0; 4922 goto out; 4923 4924 case SCF_ERROR_PERMISSION_DENIED: 4925 warn(emsg_pg_deleted, ud_ctarg, 4926 ud_name); 4927 r = EPERM; 4928 goto out; 4929 4930 case SCF_ERROR_EXISTS: 4931 warn(emsg_pg_added, ud_ctarg, ud_name); 4932 r = EBUSY; 4933 goto out; 4934 4935 case SCF_ERROR_NOT_BOUND: 4936 case SCF_ERROR_HANDLE_MISMATCH: 4937 case SCF_ERROR_INVALID_ARGUMENT: 4938 case SCF_ERROR_NOT_SET: 4939 default: 4940 bad_error("entity_add_pg", scf_error()); 4941 } 4942 } 4943 } 4944 4945 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4946 switch (r) { 4947 case 0: 4948 break; 4949 4950 case ECANCELED: 4951 warn(cf_missing, ient->sc_fmri, ud_name); 4952 goto out; 4953 4954 case ECONNABORTED: 4955 case ENOMEM: 4956 case EBADF: 4957 goto out; 4958 4959 case EACCES: 4960 default: 4961 bad_error("load_pg", r); 4962 } 4963 4964 if (g_verbose) 4965 warn(upgrading, ient->sc_fmri, ud_name); 4966 4967 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4968 new_dpt_pgroup, 0, ient->sc_fmri); 4969 switch (r) { 4970 case 0: 4971 break; 4972 4973 case ECANCELED: 4974 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4975 r = EBUSY; 4976 goto out; 4977 4978 case EPERM: 4979 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4980 goto out; 4981 4982 case EBUSY: 4983 warn(emsg_pg_changed, ud_ctarg, ud_name); 4984 goto out; 4985 4986 case ECONNABORTED: 4987 case ENOMEM: 4988 case ENOSPC: 4989 case EROFS: 4990 case EACCES: 4991 case EINVAL: 4992 goto out; 4993 4994 default: 4995 bad_error("upgrade_pg", r); 4996 } 4997 break; 4998 4999 case 0: { 5000 scf_transaction_entry_t *ent; 5001 scf_value_t *val; 5002 5003 internal_pgroup_free(current_pg); 5004 5005 /* delete old pg */ 5006 if (g_verbose) 5007 warn(upgrading, ient->sc_fmri, ud_name); 5008 5009 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 5010 switch (scf_error()) { 5011 case SCF_ERROR_CONNECTION_BROKEN: 5012 r = scferror2errno(scf_error()); 5013 goto out; 5014 5015 case SCF_ERROR_DELETED: 5016 warn(cf_missing, ient->sc_fmri, ud_name); 5017 r = 0; 5018 goto out; 5019 5020 case SCF_ERROR_NOT_FOUND: 5021 break; 5022 5023 case SCF_ERROR_INVALID_ARGUMENT: 5024 case SCF_ERROR_NOT_BOUND: 5025 case SCF_ERROR_NOT_SET: 5026 case SCF_ERROR_HANDLE_MISMATCH: 5027 default: 5028 bad_error("entity_get_pg", scf_error()); 5029 } 5030 } else if (scf_pg_delete(ud_pg) != 0) { 5031 switch (scf_error()) { 5032 case SCF_ERROR_DELETED: 5033 break; 5034 5035 case SCF_ERROR_CONNECTION_BROKEN: 5036 case SCF_ERROR_BACKEND_READONLY: 5037 case SCF_ERROR_BACKEND_ACCESS: 5038 r = scferror2errno(scf_error()); 5039 goto out; 5040 5041 case SCF_ERROR_PERMISSION_DENIED: 5042 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 5043 r = scferror2errno(scf_error()); 5044 goto out; 5045 5046 case SCF_ERROR_NOT_SET: 5047 default: 5048 bad_error("scf_pg_delete", scf_error()); 5049 } 5050 } 5051 5052 /* import new one */ 5053 cbdata.sc_handle = g_hndl; 5054 cbdata.sc_trans = NULL; /* handled below */ 5055 cbdata.sc_flags = 0; 5056 5057 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 5058 if (r != UU_WALK_NEXT) { 5059 if (r != UU_WALK_ERROR) 5060 bad_error("lscf_dependent_import", r); 5061 5062 r = cbdata.sc_err; 5063 goto out; 5064 } 5065 5066 if (tx == NULL) 5067 break; 5068 5069 if ((ent = scf_entry_create(g_hndl)) == NULL || 5070 (val = scf_value_create(g_hndl)) == NULL) { 5071 if (scf_error() == SCF_ERROR_NO_MEMORY) 5072 return (ENOMEM); 5073 5074 bad_error("scf_entry_create", scf_error()); 5075 } 5076 5077 if (scf_transaction_property_change_type(tx, ent, ud_name, 5078 SCF_TYPE_FMRI) != 0) { 5079 switch (scf_error()) { 5080 case SCF_ERROR_CONNECTION_BROKEN: 5081 r = scferror2errno(scf_error()); 5082 goto out; 5083 5084 case SCF_ERROR_DELETED: 5085 warn(emsg_pg_deleted, ient->sc_fmri, 5086 "dependents"); 5087 r = EBUSY; 5088 goto out; 5089 5090 case SCF_ERROR_NOT_FOUND: 5091 break; 5092 5093 case SCF_ERROR_NOT_BOUND: 5094 case SCF_ERROR_HANDLE_MISMATCH: 5095 case SCF_ERROR_INVALID_ARGUMENT: 5096 case SCF_ERROR_NOT_SET: 5097 default: 5098 bad_error("scf_transaction_property_" 5099 "change_type", scf_error()); 5100 } 5101 5102 if (scf_transaction_property_new(tx, ent, ud_name, 5103 SCF_TYPE_FMRI) != 0) { 5104 switch (scf_error()) { 5105 case SCF_ERROR_CONNECTION_BROKEN: 5106 r = scferror2errno(scf_error()); 5107 goto out; 5108 5109 case SCF_ERROR_DELETED: 5110 warn(emsg_pg_deleted, ient->sc_fmri, 5111 "dependents"); 5112 r = EBUSY; 5113 goto out; 5114 5115 case SCF_ERROR_EXISTS: 5116 warn(emsg_pg_changed, ient->sc_fmri, 5117 "dependents"); 5118 r = EBUSY; 5119 goto out; 5120 5121 case SCF_ERROR_INVALID_ARGUMENT: 5122 case SCF_ERROR_HANDLE_MISMATCH: 5123 case SCF_ERROR_NOT_BOUND: 5124 case SCF_ERROR_NOT_SET: 5125 default: 5126 bad_error("scf_transaction_property_" 5127 "new", scf_error()); 5128 } 5129 } 5130 } 5131 5132 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 5133 new_dpt_pgroup->sc_pgroup_fmri) != 0) 5134 /* invalid sc_pgroup_fmri caught above */ 5135 bad_error("scf_value_set_from_string", 5136 scf_error()); 5137 5138 if (scf_entry_add_value(ent, val) != 0) 5139 bad_error("scf_entry_add_value", scf_error()); 5140 break; 5141 } 5142 5143 case -2: 5144 warn(li_corrupt, ient->sc_fmri); 5145 internal_pgroup_free(current_pg); 5146 r = EBADF; 5147 goto out; 5148 5149 case -1: 5150 default: 5151 /* invalid sc_pgroup_fmri caught above */ 5152 bad_error("fmri_equal", r); 5153 } 5154 5155 r = 0; 5156 5157 out: 5158 if (old_dpt_pgroup != NULL) 5159 internal_pgroup_free(old_dpt_pgroup); 5160 5161 return (r); 5162 } 5163 5164 /* 5165 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 5166 * would import it, except it seems to exist in the service anyway. Compare 5167 * the existent dependent with the one we would import, and report any 5168 * differences (if there are none, be silent). prop is the property which 5169 * represents the existent dependent (in the dependents property group) in the 5170 * entity corresponding to ient. 5171 * 5172 * Returns 5173 * 0 - success (Sort of. At least, we can continue importing.) 5174 * ECONNABORTED - repository connection broken 5175 * EBUSY - ancestor of prop was deleted (error printed) 5176 * ENOMEM - out of memory 5177 * EBADF - corrupt property group (error printed) 5178 * EINVAL - new_dpt_pgroup has invalid target (error printed) 5179 */ 5180 static int 5181 handle_dependent_conflict(const entity_t * const ient, 5182 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 5183 { 5184 int r; 5185 scf_type_t ty; 5186 scf_error_t scfe; 5187 void *tptr; 5188 int tissvc; 5189 pgroup_t *pgroup; 5190 5191 if (scf_property_get_value(prop, ud_val) != 0) { 5192 switch (scf_error()) { 5193 case SCF_ERROR_CONNECTION_BROKEN: 5194 return (scferror2errno(scf_error())); 5195 5196 case SCF_ERROR_DELETED: 5197 warn(emsg_pg_deleted, ient->sc_fmri, 5198 new_dpt_pgroup->sc_pgroup_name); 5199 return (EBUSY); 5200 5201 case SCF_ERROR_CONSTRAINT_VIOLATED: 5202 case SCF_ERROR_NOT_FOUND: 5203 warn(gettext("Conflict upgrading %s (not importing " 5204 "dependent \"%s\" because it already exists.) " 5205 "Warning: The \"%s/%2$s\" property has more or " 5206 "fewer than one value)).\n"), ient->sc_fmri, 5207 new_dpt_pgroup->sc_pgroup_name, "dependents"); 5208 return (0); 5209 5210 case SCF_ERROR_HANDLE_MISMATCH: 5211 case SCF_ERROR_NOT_BOUND: 5212 case SCF_ERROR_NOT_SET: 5213 case SCF_ERROR_PERMISSION_DENIED: 5214 default: 5215 bad_error("scf_property_get_value", 5216 scf_error()); 5217 } 5218 } 5219 5220 ty = scf_value_type(ud_val); 5221 assert(ty != SCF_TYPE_INVALID); 5222 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 5223 warn(gettext("Conflict upgrading %s (not importing dependent " 5224 "\"%s\" because it already exists). Warning: The " 5225 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 5226 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 5227 scf_type_to_string(ty), "dependents"); 5228 return (0); 5229 } 5230 5231 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 5232 0) 5233 bad_error("scf_value_get_as_string", scf_error()); 5234 5235 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 5236 switch (r) { 5237 case 0: 5238 warn(gettext("Conflict upgrading %s (not importing dependent " 5239 "\"%s\" (target \"%s\") because it already exists with " 5240 "target \"%s\").\n"), ient->sc_fmri, 5241 new_dpt_pgroup->sc_pgroup_name, 5242 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 5243 return (0); 5244 5245 case 1: 5246 break; 5247 5248 case -1: 5249 warn(gettext("Conflict upgrading %s (not importing dependent " 5250 "\"%s\" because it already exists). Warning: The current " 5251 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 5252 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5253 return (0); 5254 5255 case -2: 5256 warn(gettext("Dependent \"%s\" of %s has invalid target " 5257 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 5258 new_dpt_pgroup->sc_pgroup_fmri); 5259 return (EINVAL); 5260 5261 default: 5262 bad_error("fmri_equal", r); 5263 } 5264 5265 /* compare dependency pgs in target */ 5266 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 5267 switch (scfe) { 5268 case SCF_ERROR_NONE: 5269 break; 5270 5271 case SCF_ERROR_NO_MEMORY: 5272 return (ENOMEM); 5273 5274 case SCF_ERROR_NOT_FOUND: 5275 warn(emsg_dpt_dangling, ient->sc_fmri, 5276 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5277 return (0); 5278 5279 case SCF_ERROR_CONSTRAINT_VIOLATED: 5280 case SCF_ERROR_INVALID_ARGUMENT: 5281 default: 5282 bad_error("fmri_to_entity", scfe); 5283 } 5284 5285 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 5286 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 5287 switch (r) { 5288 case 0: 5289 break; 5290 5291 case ECONNABORTED: 5292 return (r); 5293 5294 case ECANCELED: 5295 warn(emsg_dpt_dangling, ient->sc_fmri, 5296 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5297 return (0); 5298 5299 case EBADF: 5300 if (tissvc) 5301 warn(gettext("%s has an instance with a \"%s\" " 5302 "snapshot which is missing a snaplevel.\n"), 5303 ud_ctarg, "running"); 5304 else 5305 warn(gettext("%s has a \"%s\" snapshot which is " 5306 "missing a snaplevel.\n"), ud_ctarg, "running"); 5307 /* FALLTHROUGH */ 5308 5309 case ENOENT: 5310 warn(emsg_dpt_no_dep, ient->sc_fmri, 5311 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5312 new_dpt_pgroup->sc_pgroup_name); 5313 return (0); 5314 5315 case EINVAL: 5316 default: 5317 bad_error("entity_get_running_pg", r); 5318 } 5319 5320 pgroup = internal_pgroup_new(); 5321 if (pgroup == NULL) 5322 return (ENOMEM); 5323 5324 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 5325 switch (r) { 5326 case 0: 5327 break; 5328 5329 case ECONNABORTED: 5330 case EBADF: 5331 case ENOMEM: 5332 internal_pgroup_free(pgroup); 5333 return (r); 5334 5335 case ECANCELED: 5336 warn(emsg_dpt_no_dep, ient->sc_fmri, 5337 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5338 new_dpt_pgroup->sc_pgroup_name); 5339 internal_pgroup_free(pgroup); 5340 return (0); 5341 5342 case EACCES: 5343 default: 5344 bad_error("load_pg", r); 5345 } 5346 5347 /* report differences */ 5348 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 5349 internal_pgroup_free(pgroup); 5350 return (0); 5351 } 5352 5353 /* 5354 * lipg is a property group in the last-import snapshot of ent, which is an 5355 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 5356 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 5357 * in ents's property groups, compare and upgrade ent appropriately. 5358 * 5359 * Returns 5360 * 0 - success 5361 * ECONNABORTED - repository connection broken 5362 * ENOMEM - out of memory 5363 * ENOSPC - configd is out of resources 5364 * EINVAL - ient has invalid dependent (error printed) 5365 * - ient has invalid pgroup_t (error printed) 5366 * ECANCELED - ent has been deleted 5367 * ENODEV - entity containing lipg has been deleted 5368 * - entity containing running has been deleted 5369 * EPERM - could not delete pg (permission denied) (error printed) 5370 * - couldn't upgrade dependents (permission denied) (error printed) 5371 * - couldn't import pg (permission denied) (error printed) 5372 * - couldn't upgrade pg (permission denied) (error printed) 5373 * EROFS - could not delete pg (repository read-only) 5374 * - couldn't upgrade dependents (repository read-only) 5375 * - couldn't import pg (repository read-only) 5376 * - couldn't upgrade pg (repository read-only) 5377 * EACCES - could not delete pg (backend access denied) 5378 * - couldn't upgrade dependents (backend access denied) 5379 * - couldn't import pg (backend access denied) 5380 * - couldn't upgrade pg (backend access denied) 5381 * - couldn't read property (backend access denied) 5382 * EBUSY - property group was added (error printed) 5383 * - property group was deleted (error printed) 5384 * - property group changed (error printed) 5385 * - "dependents" pg was added, changed, or deleted (error printed) 5386 * - dependent target deleted (error printed) 5387 * - dependent pg changed (error printed) 5388 * EBADF - imp_snpl is corrupt (error printed) 5389 * - ent has bad pg (error printed) 5390 * EEXIST - dependent collision in target service (error printed) 5391 */ 5392 static int 5393 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 5394 const scf_snaplevel_t *running) 5395 { 5396 int r; 5397 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 5398 scf_callback_t cbdata; 5399 5400 const char * const cf_pg_missing = 5401 gettext("Conflict upgrading %s (property group %s is missing)\n"); 5402 const char * const deleting = 5403 gettext("%s: Deleting property group \"%s\".\n"); 5404 5405 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5406 5407 /* Skip dependent property groups. */ 5408 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 5409 switch (scf_error()) { 5410 case SCF_ERROR_DELETED: 5411 return (ENODEV); 5412 5413 case SCF_ERROR_CONNECTION_BROKEN: 5414 return (ECONNABORTED); 5415 5416 case SCF_ERROR_NOT_SET: 5417 case SCF_ERROR_NOT_BOUND: 5418 default: 5419 bad_error("scf_pg_get_type", scf_error()); 5420 } 5421 } 5422 5423 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 5424 if (scf_pg_get_property(lipg, "external", NULL) == 0) 5425 return (0); 5426 5427 switch (scf_error()) { 5428 case SCF_ERROR_NOT_FOUND: 5429 break; 5430 5431 case SCF_ERROR_CONNECTION_BROKEN: 5432 return (ECONNABORTED); 5433 5434 case SCF_ERROR_DELETED: 5435 return (ENODEV); 5436 5437 case SCF_ERROR_INVALID_ARGUMENT: 5438 case SCF_ERROR_NOT_BOUND: 5439 case SCF_ERROR_HANDLE_MISMATCH: 5440 case SCF_ERROR_NOT_SET: 5441 default: 5442 bad_error("scf_pg_get_property", scf_error()); 5443 } 5444 } 5445 5446 /* lookup pg in new properties */ 5447 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 5448 switch (scf_error()) { 5449 case SCF_ERROR_DELETED: 5450 return (ENODEV); 5451 5452 case SCF_ERROR_CONNECTION_BROKEN: 5453 return (ECONNABORTED); 5454 5455 case SCF_ERROR_NOT_SET: 5456 case SCF_ERROR_NOT_BOUND: 5457 default: 5458 bad_error("scf_pg_get_name", scf_error()); 5459 } 5460 } 5461 5462 pgrp.sc_pgroup_name = imp_str; 5463 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 5464 5465 if (mpg != NULL) 5466 mpg->sc_pgroup_seen = 1; 5467 5468 /* Special handling for dependents */ 5469 if (strcmp(imp_str, "dependents") == 0) 5470 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 5471 5472 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 5473 return (upgrade_manifestfiles(NULL, ient, running, ent)); 5474 5475 if (mpg == NULL || mpg->sc_pgroup_delete) { 5476 /* property group was deleted from manifest */ 5477 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5478 switch (scf_error()) { 5479 case SCF_ERROR_NOT_FOUND: 5480 return (0); 5481 5482 case SCF_ERROR_DELETED: 5483 case SCF_ERROR_CONNECTION_BROKEN: 5484 return (scferror2errno(scf_error())); 5485 5486 case SCF_ERROR_INVALID_ARGUMENT: 5487 case SCF_ERROR_HANDLE_MISMATCH: 5488 case SCF_ERROR_NOT_BOUND: 5489 case SCF_ERROR_NOT_SET: 5490 default: 5491 bad_error("entity_get_pg", scf_error()); 5492 } 5493 } 5494 5495 if (mpg != NULL && mpg->sc_pgroup_delete) { 5496 if (g_verbose) 5497 warn(deleting, ient->sc_fmri, imp_str); 5498 if (scf_pg_delete(imp_pg2) == 0) 5499 return (0); 5500 5501 switch (scf_error()) { 5502 case SCF_ERROR_DELETED: 5503 return (0); 5504 5505 case SCF_ERROR_CONNECTION_BROKEN: 5506 case SCF_ERROR_BACKEND_READONLY: 5507 case SCF_ERROR_BACKEND_ACCESS: 5508 return (scferror2errno(scf_error())); 5509 5510 case SCF_ERROR_PERMISSION_DENIED: 5511 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 5512 return (scferror2errno(scf_error())); 5513 5514 case SCF_ERROR_NOT_SET: 5515 default: 5516 bad_error("scf_pg_delete", scf_error()); 5517 } 5518 } 5519 5520 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5521 switch (r) { 5522 case 0: 5523 break; 5524 5525 case ECANCELED: 5526 return (ENODEV); 5527 5528 case ECONNABORTED: 5529 case ENOMEM: 5530 case EBADF: 5531 case EACCES: 5532 return (r); 5533 5534 default: 5535 bad_error("load_pg", r); 5536 } 5537 5538 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5539 switch (r) { 5540 case 0: 5541 break; 5542 5543 case ECANCELED: 5544 case ECONNABORTED: 5545 case ENOMEM: 5546 case EBADF: 5547 case EACCES: 5548 internal_pgroup_free(lipg_i); 5549 return (r); 5550 5551 default: 5552 bad_error("load_pg", r); 5553 } 5554 5555 if (pg_equal(lipg_i, curpg_i)) { 5556 if (g_verbose) 5557 warn(deleting, ient->sc_fmri, imp_str); 5558 if (scf_pg_delete(imp_pg2) != 0) { 5559 switch (scf_error()) { 5560 case SCF_ERROR_DELETED: 5561 break; 5562 5563 case SCF_ERROR_CONNECTION_BROKEN: 5564 internal_pgroup_free(lipg_i); 5565 internal_pgroup_free(curpg_i); 5566 return (ECONNABORTED); 5567 5568 case SCF_ERROR_NOT_SET: 5569 case SCF_ERROR_NOT_BOUND: 5570 default: 5571 bad_error("scf_pg_delete", scf_error()); 5572 } 5573 } 5574 } else { 5575 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5576 } 5577 5578 internal_pgroup_free(lipg_i); 5579 internal_pgroup_free(curpg_i); 5580 5581 return (0); 5582 } 5583 5584 /* 5585 * Only dependent pgs can have override set, and we skipped those 5586 * above. 5587 */ 5588 assert(!mpg->sc_pgroup_override); 5589 5590 /* compare */ 5591 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5592 switch (r) { 5593 case 0: 5594 break; 5595 5596 case ECANCELED: 5597 return (ENODEV); 5598 5599 case ECONNABORTED: 5600 case EBADF: 5601 case ENOMEM: 5602 case EACCES: 5603 return (r); 5604 5605 default: 5606 bad_error("load_pg", r); 5607 } 5608 5609 if (pg_equal(mpg, lipg_i)) { 5610 /* The manifest pg has not changed. Move on. */ 5611 r = 0; 5612 goto out; 5613 } 5614 5615 /* upgrade current properties according to lipg & mpg */ 5616 if (running != NULL) 5617 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5618 else 5619 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5620 if (r != 0) { 5621 switch (scf_error()) { 5622 case SCF_ERROR_CONNECTION_BROKEN: 5623 r = scferror2errno(scf_error()); 5624 goto out; 5625 5626 case SCF_ERROR_DELETED: 5627 if (running != NULL) 5628 r = ENODEV; 5629 else 5630 r = ECANCELED; 5631 goto out; 5632 5633 case SCF_ERROR_NOT_FOUND: 5634 break; 5635 5636 case SCF_ERROR_INVALID_ARGUMENT: 5637 case SCF_ERROR_HANDLE_MISMATCH: 5638 case SCF_ERROR_NOT_BOUND: 5639 case SCF_ERROR_NOT_SET: 5640 default: 5641 bad_error("entity_get_pg", scf_error()); 5642 } 5643 5644 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5645 5646 r = 0; 5647 goto out; 5648 } 5649 5650 r = load_pg_attrs(imp_pg2, &curpg_i); 5651 switch (r) { 5652 case 0: 5653 break; 5654 5655 case ECANCELED: 5656 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5657 r = 0; 5658 goto out; 5659 5660 case ECONNABORTED: 5661 case ENOMEM: 5662 goto out; 5663 5664 default: 5665 bad_error("load_pg_attrs", r); 5666 } 5667 5668 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5669 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5670 internal_pgroup_free(curpg_i); 5671 r = 0; 5672 goto out; 5673 } 5674 5675 internal_pgroup_free(curpg_i); 5676 5677 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5678 switch (r) { 5679 case 0: 5680 break; 5681 5682 case ECANCELED: 5683 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5684 r = 0; 5685 goto out; 5686 5687 case ECONNABORTED: 5688 case EBADF: 5689 case ENOMEM: 5690 case EACCES: 5691 goto out; 5692 5693 default: 5694 bad_error("load_pg", r); 5695 } 5696 5697 if (pg_equal(lipg_i, curpg_i) && 5698 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5699 int do_delete = 1; 5700 5701 if (g_verbose) 5702 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5703 ient->sc_fmri, mpg->sc_pgroup_name); 5704 5705 internal_pgroup_free(curpg_i); 5706 5707 if (running != NULL && 5708 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5709 switch (scf_error()) { 5710 case SCF_ERROR_DELETED: 5711 r = ECANCELED; 5712 goto out; 5713 5714 case SCF_ERROR_NOT_FOUND: 5715 do_delete = 0; 5716 break; 5717 5718 case SCF_ERROR_CONNECTION_BROKEN: 5719 r = scferror2errno(scf_error()); 5720 goto out; 5721 5722 case SCF_ERROR_HANDLE_MISMATCH: 5723 case SCF_ERROR_INVALID_ARGUMENT: 5724 case SCF_ERROR_NOT_SET: 5725 case SCF_ERROR_NOT_BOUND: 5726 default: 5727 bad_error("entity_get_pg", scf_error()); 5728 } 5729 } 5730 5731 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5732 switch (scf_error()) { 5733 case SCF_ERROR_DELETED: 5734 break; 5735 5736 case SCF_ERROR_CONNECTION_BROKEN: 5737 case SCF_ERROR_BACKEND_READONLY: 5738 case SCF_ERROR_BACKEND_ACCESS: 5739 r = scferror2errno(scf_error()); 5740 goto out; 5741 5742 case SCF_ERROR_PERMISSION_DENIED: 5743 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5744 ient->sc_fmri); 5745 r = scferror2errno(scf_error()); 5746 goto out; 5747 5748 case SCF_ERROR_NOT_SET: 5749 case SCF_ERROR_NOT_BOUND: 5750 default: 5751 bad_error("scf_pg_delete", scf_error()); 5752 } 5753 } 5754 5755 cbdata.sc_handle = g_hndl; 5756 cbdata.sc_parent = ent; 5757 cbdata.sc_service = issvc; 5758 cbdata.sc_flags = 0; 5759 cbdata.sc_source_fmri = ient->sc_fmri; 5760 cbdata.sc_target_fmri = ient->sc_fmri; 5761 5762 r = entity_pgroup_import(mpg, &cbdata); 5763 switch (r) { 5764 case UU_WALK_NEXT: 5765 r = 0; 5766 goto out; 5767 5768 case UU_WALK_ERROR: 5769 if (cbdata.sc_err == EEXIST) { 5770 warn(emsg_pg_added, ient->sc_fmri, 5771 mpg->sc_pgroup_name); 5772 r = EBUSY; 5773 } else { 5774 r = cbdata.sc_err; 5775 } 5776 goto out; 5777 5778 default: 5779 bad_error("entity_pgroup_import", r); 5780 } 5781 } 5782 5783 if (running != NULL && 5784 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5785 switch (scf_error()) { 5786 case SCF_ERROR_CONNECTION_BROKEN: 5787 case SCF_ERROR_DELETED: 5788 r = scferror2errno(scf_error()); 5789 goto out; 5790 5791 case SCF_ERROR_NOT_FOUND: 5792 break; 5793 5794 case SCF_ERROR_HANDLE_MISMATCH: 5795 case SCF_ERROR_INVALID_ARGUMENT: 5796 case SCF_ERROR_NOT_SET: 5797 case SCF_ERROR_NOT_BOUND: 5798 default: 5799 bad_error("entity_get_pg", scf_error()); 5800 } 5801 5802 cbdata.sc_handle = g_hndl; 5803 cbdata.sc_parent = ent; 5804 cbdata.sc_service = issvc; 5805 cbdata.sc_flags = SCI_FORCE; 5806 cbdata.sc_source_fmri = ient->sc_fmri; 5807 cbdata.sc_target_fmri = ient->sc_fmri; 5808 5809 r = entity_pgroup_import(mpg, &cbdata); 5810 switch (r) { 5811 case UU_WALK_NEXT: 5812 r = 0; 5813 goto out; 5814 5815 case UU_WALK_ERROR: 5816 if (cbdata.sc_err == EEXIST) { 5817 warn(emsg_pg_added, ient->sc_fmri, 5818 mpg->sc_pgroup_name); 5819 r = EBUSY; 5820 } else { 5821 r = cbdata.sc_err; 5822 } 5823 goto out; 5824 5825 default: 5826 bad_error("entity_pgroup_import", r); 5827 } 5828 } 5829 5830 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5831 internal_pgroup_free(curpg_i); 5832 switch (r) { 5833 case 0: 5834 ient->sc_import_state = IMPORT_PROP_BEGUN; 5835 break; 5836 5837 case ECANCELED: 5838 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5839 r = EBUSY; 5840 break; 5841 5842 case EPERM: 5843 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5844 break; 5845 5846 case EBUSY: 5847 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5848 break; 5849 5850 case ECONNABORTED: 5851 case ENOMEM: 5852 case ENOSPC: 5853 case EROFS: 5854 case EACCES: 5855 case EINVAL: 5856 break; 5857 5858 default: 5859 bad_error("upgrade_pg", r); 5860 } 5861 5862 out: 5863 internal_pgroup_free(lipg_i); 5864 return (r); 5865 } 5866 5867 /* 5868 * Upgrade the properties of ent according to snpl & ient. 5869 * 5870 * Returns 5871 * 0 - success 5872 * ECONNABORTED - repository connection broken 5873 * ENOMEM - out of memory 5874 * ENOSPC - configd is out of resources 5875 * ECANCELED - ent was deleted 5876 * ENODEV - entity containing snpl was deleted 5877 * - entity containing running was deleted 5878 * EBADF - imp_snpl is corrupt (error printed) 5879 * - ent has corrupt pg (error printed) 5880 * - dependent has corrupt pg (error printed) 5881 * - dependent target has a corrupt snapshot (error printed) 5882 * EBUSY - pg was added, changed, or deleted (error printed) 5883 * - dependent target was deleted (error printed) 5884 * - dependent pg changed (error printed) 5885 * EINVAL - invalid property group name (error printed) 5886 * - invalid property name (error printed) 5887 * - invalid value (error printed) 5888 * - ient has invalid pgroup or dependent (error printed) 5889 * EPERM - could not create property group (permission denied) (error printed) 5890 * - could not modify property group (permission denied) (error printed) 5891 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5892 * EROFS - could not create property group (repository read-only) 5893 * - couldn't delete, upgrade, or import pg or dependent 5894 * EACCES - could not create property group (backend access denied) 5895 * - couldn't delete, upgrade, or import pg or dependent 5896 * EEXIST - dependent collision in target service (error printed) 5897 */ 5898 static int 5899 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5900 entity_t *ient) 5901 { 5902 pgroup_t *pg, *rpg; 5903 int r; 5904 uu_list_t *pgs = ient->sc_pgroups; 5905 5906 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5907 5908 /* clear sc_sceen for pgs */ 5909 if (uu_list_walk(pgs, clear_int, 5910 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5911 bad_error("uu_list_walk", uu_error()); 5912 5913 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5914 switch (scf_error()) { 5915 case SCF_ERROR_DELETED: 5916 return (ENODEV); 5917 5918 case SCF_ERROR_CONNECTION_BROKEN: 5919 return (ECONNABORTED); 5920 5921 case SCF_ERROR_NOT_SET: 5922 case SCF_ERROR_NOT_BOUND: 5923 case SCF_ERROR_HANDLE_MISMATCH: 5924 default: 5925 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5926 } 5927 } 5928 5929 for (;;) { 5930 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5931 if (r == 0) 5932 break; 5933 if (r == 1) { 5934 r = process_old_pg(imp_pg, ient, ent, running); 5935 switch (r) { 5936 case 0: 5937 break; 5938 5939 case ECONNABORTED: 5940 case ENOMEM: 5941 case ENOSPC: 5942 case ECANCELED: 5943 case ENODEV: 5944 case EPERM: 5945 case EROFS: 5946 case EACCES: 5947 case EBADF: 5948 case EBUSY: 5949 case EINVAL: 5950 case EEXIST: 5951 return (r); 5952 5953 default: 5954 bad_error("process_old_pg", r); 5955 } 5956 continue; 5957 } 5958 if (r != -1) 5959 bad_error("scf_iter_next_pg", r); 5960 5961 switch (scf_error()) { 5962 case SCF_ERROR_DELETED: 5963 return (ENODEV); 5964 5965 case SCF_ERROR_CONNECTION_BROKEN: 5966 return (ECONNABORTED); 5967 5968 case SCF_ERROR_HANDLE_MISMATCH: 5969 case SCF_ERROR_NOT_BOUND: 5970 case SCF_ERROR_NOT_SET: 5971 case SCF_ERROR_INVALID_ARGUMENT: 5972 default: 5973 bad_error("scf_iter_next_pg", scf_error()); 5974 } 5975 } 5976 5977 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5978 if (pg->sc_pgroup_seen) 5979 continue; 5980 5981 /* pg is new */ 5982 5983 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5984 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5985 ent); 5986 switch (r) { 5987 case 0: 5988 break; 5989 5990 case ECONNABORTED: 5991 case ENOMEM: 5992 case ENOSPC: 5993 case ECANCELED: 5994 case ENODEV: 5995 case EBADF: 5996 case EBUSY: 5997 case EINVAL: 5998 case EPERM: 5999 case EROFS: 6000 case EACCES: 6001 case EEXIST: 6002 return (r); 6003 6004 default: 6005 bad_error("upgrade_dependents", r); 6006 } 6007 continue; 6008 } 6009 6010 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 6011 r = upgrade_manifestfiles(pg, ient, running, ent); 6012 switch (r) { 6013 case 0: 6014 break; 6015 6016 case ECONNABORTED: 6017 case ENOMEM: 6018 case ENOSPC: 6019 case ECANCELED: 6020 case ENODEV: 6021 case EBADF: 6022 case EBUSY: 6023 case EINVAL: 6024 case EPERM: 6025 case EROFS: 6026 case EACCES: 6027 case EEXIST: 6028 return (r); 6029 6030 default: 6031 bad_error("upgrade_manifestfiles", r); 6032 } 6033 continue; 6034 } 6035 6036 if (running != NULL) { 6037 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 6038 imp_pg); 6039 } else { 6040 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 6041 imp_pg); 6042 } 6043 if (r != 0) { 6044 scf_callback_t cbdata; 6045 6046 switch (scf_error()) { 6047 case SCF_ERROR_NOT_FOUND: 6048 break; 6049 6050 case SCF_ERROR_CONNECTION_BROKEN: 6051 return (scferror2errno(scf_error())); 6052 6053 case SCF_ERROR_DELETED: 6054 if (running != NULL) 6055 return (ENODEV); 6056 else 6057 return (scferror2errno(scf_error())); 6058 6059 case SCF_ERROR_INVALID_ARGUMENT: 6060 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 6061 pg->sc_pgroup_name); 6062 return (EINVAL); 6063 6064 case SCF_ERROR_NOT_SET: 6065 case SCF_ERROR_HANDLE_MISMATCH: 6066 case SCF_ERROR_NOT_BOUND: 6067 default: 6068 bad_error("entity_get_pg", scf_error()); 6069 } 6070 6071 /* User doesn't have pg, so import it. */ 6072 6073 cbdata.sc_handle = g_hndl; 6074 cbdata.sc_parent = ent; 6075 cbdata.sc_service = issvc; 6076 cbdata.sc_flags = SCI_FORCE; 6077 cbdata.sc_source_fmri = ient->sc_fmri; 6078 cbdata.sc_target_fmri = ient->sc_fmri; 6079 6080 r = entity_pgroup_import(pg, &cbdata); 6081 switch (r) { 6082 case UU_WALK_NEXT: 6083 ient->sc_import_state = IMPORT_PROP_BEGUN; 6084 continue; 6085 6086 case UU_WALK_ERROR: 6087 if (cbdata.sc_err == EEXIST) { 6088 warn(emsg_pg_added, ient->sc_fmri, 6089 pg->sc_pgroup_name); 6090 return (EBUSY); 6091 } 6092 return (cbdata.sc_err); 6093 6094 default: 6095 bad_error("entity_pgroup_import", r); 6096 } 6097 } 6098 6099 /* report differences between pg & current */ 6100 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 6101 switch (r) { 6102 case 0: 6103 break; 6104 6105 case ECANCELED: 6106 warn(emsg_pg_deleted, ient->sc_fmri, 6107 pg->sc_pgroup_name); 6108 return (EBUSY); 6109 6110 case ECONNABORTED: 6111 case EBADF: 6112 case ENOMEM: 6113 case EACCES: 6114 return (r); 6115 6116 default: 6117 bad_error("load_pg", r); 6118 } 6119 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 6120 internal_pgroup_free(rpg); 6121 rpg = NULL; 6122 } 6123 6124 return (0); 6125 } 6126 6127 /* 6128 * Import an instance. If it doesn't exist, create it. If it has 6129 * a last-import snapshot, upgrade its properties. Finish by updating its 6130 * last-import snapshot. If it doesn't have a last-import snapshot then it 6131 * could have been created for a dependent tag in another manifest. Import the 6132 * new properties. If there's a conflict, don't override, like now? 6133 * 6134 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 6135 * lcbdata->sc_err to 6136 * ECONNABORTED - repository connection broken 6137 * ENOMEM - out of memory 6138 * ENOSPC - svc.configd is out of resources 6139 * EEXIST - dependency collision in dependent service (error printed) 6140 * EPERM - couldn't create temporary instance (permission denied) 6141 * - couldn't import into temporary instance (permission denied) 6142 * - couldn't take snapshot (permission denied) 6143 * - couldn't upgrade properties (permission denied) 6144 * - couldn't import properties (permission denied) 6145 * - couldn't import dependents (permission denied) 6146 * EROFS - couldn't create temporary instance (repository read-only) 6147 * - couldn't import into temporary instance (repository read-only) 6148 * - couldn't upgrade properties (repository read-only) 6149 * - couldn't import properties (repository read-only) 6150 * - couldn't import dependents (repository read-only) 6151 * EACCES - couldn't create temporary instance (backend access denied) 6152 * - couldn't import into temporary instance (backend access denied) 6153 * - couldn't upgrade properties (backend access denied) 6154 * - couldn't import properties (backend access denied) 6155 * - couldn't import dependents (backend access denied) 6156 * EINVAL - invalid instance name (error printed) 6157 * - invalid pgroup_t's (error printed) 6158 * - invalid dependents (error printed) 6159 * EBUSY - temporary service deleted (error printed) 6160 * - temporary instance deleted (error printed) 6161 * - temporary instance changed (error printed) 6162 * - temporary instance already exists (error printed) 6163 * - instance deleted (error printed) 6164 * EBADF - instance has corrupt last-import snapshot (error printed) 6165 * - instance is corrupt (error printed) 6166 * - dependent has corrupt pg (error printed) 6167 * - dependent target has a corrupt snapshot (error printed) 6168 * -1 - unknown libscf error (error printed) 6169 */ 6170 static int 6171 lscf_instance_import(void *v, void *pvt) 6172 { 6173 entity_t *inst = v; 6174 scf_callback_t ctx; 6175 scf_callback_t *lcbdata = pvt; 6176 scf_service_t *rsvc = lcbdata->sc_parent; 6177 int r; 6178 scf_snaplevel_t *running; 6179 int flags = lcbdata->sc_flags; 6180 6181 const char * const emsg_tdel = 6182 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 6183 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 6184 "changed unexpectedly.\n"); 6185 const char * const emsg_del = gettext("%s changed unexpectedly " 6186 "(instance \"%s\" was deleted.)\n"); 6187 const char * const emsg_badsnap = gettext( 6188 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 6189 6190 /* 6191 * prepare last-import snapshot: 6192 * create temporary instance (service was precreated) 6193 * populate with properties from bundle 6194 * take snapshot 6195 */ 6196 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 6197 switch (scf_error()) { 6198 case SCF_ERROR_CONNECTION_BROKEN: 6199 case SCF_ERROR_NO_RESOURCES: 6200 case SCF_ERROR_BACKEND_READONLY: 6201 case SCF_ERROR_BACKEND_ACCESS: 6202 return (stash_scferror(lcbdata)); 6203 6204 case SCF_ERROR_EXISTS: 6205 warn(gettext("Temporary service svc:/%s " 6206 "changed unexpectedly (instance \"%s\" added).\n"), 6207 imp_tsname, inst->sc_name); 6208 lcbdata->sc_err = EBUSY; 6209 return (UU_WALK_ERROR); 6210 6211 case SCF_ERROR_DELETED: 6212 warn(gettext("Temporary service svc:/%s " 6213 "was deleted unexpectedly.\n"), imp_tsname); 6214 lcbdata->sc_err = EBUSY; 6215 return (UU_WALK_ERROR); 6216 6217 case SCF_ERROR_INVALID_ARGUMENT: 6218 warn(gettext("Invalid instance name \"%s\".\n"), 6219 inst->sc_name); 6220 return (stash_scferror(lcbdata)); 6221 6222 case SCF_ERROR_PERMISSION_DENIED: 6223 warn(gettext("Could not create temporary instance " 6224 "\"%s\" in svc:/%s (permission denied).\n"), 6225 inst->sc_name, imp_tsname); 6226 return (stash_scferror(lcbdata)); 6227 6228 case SCF_ERROR_HANDLE_MISMATCH: 6229 case SCF_ERROR_NOT_BOUND: 6230 case SCF_ERROR_NOT_SET: 6231 default: 6232 bad_error("scf_service_add_instance", scf_error()); 6233 } 6234 } 6235 6236 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6237 inst->sc_name); 6238 if (r < 0) 6239 bad_error("snprintf", errno); 6240 6241 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 6242 lcbdata->sc_flags | SCI_NOENABLED); 6243 switch (r) { 6244 case 0: 6245 break; 6246 6247 case ECANCELED: 6248 warn(emsg_tdel, imp_tsname, inst->sc_name); 6249 lcbdata->sc_err = EBUSY; 6250 r = UU_WALK_ERROR; 6251 goto deltemp; 6252 6253 case EEXIST: 6254 warn(emsg_tchg, imp_tsname, inst->sc_name); 6255 lcbdata->sc_err = EBUSY; 6256 r = UU_WALK_ERROR; 6257 goto deltemp; 6258 6259 case ECONNABORTED: 6260 goto connaborted; 6261 6262 case ENOMEM: 6263 case ENOSPC: 6264 case EPERM: 6265 case EROFS: 6266 case EACCES: 6267 case EINVAL: 6268 case EBUSY: 6269 lcbdata->sc_err = r; 6270 r = UU_WALK_ERROR; 6271 goto deltemp; 6272 6273 default: 6274 bad_error("lscf_import_instance_pgs", r); 6275 } 6276 6277 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6278 inst->sc_name); 6279 if (r < 0) 6280 bad_error("snprintf", errno); 6281 6282 ctx.sc_handle = lcbdata->sc_handle; 6283 ctx.sc_parent = imp_tinst; 6284 ctx.sc_service = 0; 6285 ctx.sc_source_fmri = inst->sc_fmri; 6286 ctx.sc_target_fmri = imp_str; 6287 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 6288 UU_DEFAULT) != 0) { 6289 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6290 bad_error("uu_list_walk", uu_error()); 6291 6292 switch (ctx.sc_err) { 6293 case ECONNABORTED: 6294 goto connaborted; 6295 6296 case ECANCELED: 6297 warn(emsg_tdel, imp_tsname, inst->sc_name); 6298 lcbdata->sc_err = EBUSY; 6299 break; 6300 6301 case EEXIST: 6302 warn(emsg_tchg, imp_tsname, inst->sc_name); 6303 lcbdata->sc_err = EBUSY; 6304 break; 6305 6306 default: 6307 lcbdata->sc_err = ctx.sc_err; 6308 } 6309 r = UU_WALK_ERROR; 6310 goto deltemp; 6311 } 6312 6313 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 6314 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 6315 switch (scf_error()) { 6316 case SCF_ERROR_CONNECTION_BROKEN: 6317 goto connaborted; 6318 6319 case SCF_ERROR_NO_RESOURCES: 6320 r = stash_scferror(lcbdata); 6321 goto deltemp; 6322 6323 case SCF_ERROR_EXISTS: 6324 warn(emsg_tchg, imp_tsname, inst->sc_name); 6325 lcbdata->sc_err = EBUSY; 6326 r = UU_WALK_ERROR; 6327 goto deltemp; 6328 6329 case SCF_ERROR_PERMISSION_DENIED: 6330 warn(gettext("Could not take \"%s\" snapshot of %s " 6331 "(permission denied).\n"), snap_lastimport, 6332 imp_str); 6333 r = stash_scferror(lcbdata); 6334 goto deltemp; 6335 6336 default: 6337 scfwarn(); 6338 lcbdata->sc_err = -1; 6339 r = UU_WALK_ERROR; 6340 goto deltemp; 6341 6342 case SCF_ERROR_HANDLE_MISMATCH: 6343 case SCF_ERROR_INVALID_ARGUMENT: 6344 case SCF_ERROR_NOT_SET: 6345 bad_error("_scf_snapshot_take_new_named", scf_error()); 6346 } 6347 } 6348 6349 if (lcbdata->sc_flags & SCI_FRESH) 6350 goto fresh; 6351 6352 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 6353 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6354 imp_lisnap) != 0) { 6355 switch (scf_error()) { 6356 case SCF_ERROR_DELETED: 6357 warn(emsg_del, inst->sc_parent->sc_fmri, 6358 inst->sc_name); 6359 lcbdata->sc_err = EBUSY; 6360 r = UU_WALK_ERROR; 6361 goto deltemp; 6362 6363 case SCF_ERROR_NOT_FOUND: 6364 flags |= SCI_FORCE; 6365 goto nosnap; 6366 6367 case SCF_ERROR_CONNECTION_BROKEN: 6368 goto connaborted; 6369 6370 case SCF_ERROR_INVALID_ARGUMENT: 6371 case SCF_ERROR_HANDLE_MISMATCH: 6372 case SCF_ERROR_NOT_BOUND: 6373 case SCF_ERROR_NOT_SET: 6374 default: 6375 bad_error("scf_instance_get_snapshot", 6376 scf_error()); 6377 } 6378 } 6379 6380 /* upgrade */ 6381 6382 /* 6383 * compare new properties with last-import properties 6384 * upgrade current properties 6385 */ 6386 /* clear sc_sceen for pgs */ 6387 if (uu_list_walk(inst->sc_pgroups, clear_int, 6388 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 6389 0) 6390 bad_error("uu_list_walk", uu_error()); 6391 6392 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 6393 switch (r) { 6394 case 0: 6395 break; 6396 6397 case ECONNABORTED: 6398 goto connaborted; 6399 6400 case ECANCELED: 6401 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6402 lcbdata->sc_err = EBUSY; 6403 r = UU_WALK_ERROR; 6404 goto deltemp; 6405 6406 case ENOENT: 6407 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 6408 lcbdata->sc_err = EBADF; 6409 r = UU_WALK_ERROR; 6410 goto deltemp; 6411 6412 default: 6413 bad_error("get_snaplevel", r); 6414 } 6415 6416 if (scf_instance_get_snapshot(imp_inst, snap_running, 6417 imp_rsnap) != 0) { 6418 switch (scf_error()) { 6419 case SCF_ERROR_DELETED: 6420 warn(emsg_del, inst->sc_parent->sc_fmri, 6421 inst->sc_name); 6422 lcbdata->sc_err = EBUSY; 6423 r = UU_WALK_ERROR; 6424 goto deltemp; 6425 6426 case SCF_ERROR_NOT_FOUND: 6427 break; 6428 6429 case SCF_ERROR_CONNECTION_BROKEN: 6430 goto connaborted; 6431 6432 case SCF_ERROR_INVALID_ARGUMENT: 6433 case SCF_ERROR_HANDLE_MISMATCH: 6434 case SCF_ERROR_NOT_BOUND: 6435 case SCF_ERROR_NOT_SET: 6436 default: 6437 bad_error("scf_instance_get_snapshot", 6438 scf_error()); 6439 } 6440 6441 running = NULL; 6442 } else { 6443 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 6444 switch (r) { 6445 case 0: 6446 running = imp_rsnpl; 6447 break; 6448 6449 case ECONNABORTED: 6450 goto connaborted; 6451 6452 case ECANCELED: 6453 warn(emsg_del, inst->sc_parent->sc_fmri, 6454 inst->sc_name); 6455 lcbdata->sc_err = EBUSY; 6456 r = UU_WALK_ERROR; 6457 goto deltemp; 6458 6459 case ENOENT: 6460 warn(emsg_badsnap, snap_running, inst->sc_fmri); 6461 lcbdata->sc_err = EBADF; 6462 r = UU_WALK_ERROR; 6463 goto deltemp; 6464 6465 default: 6466 bad_error("get_snaplevel", r); 6467 } 6468 } 6469 6470 r = upgrade_props(imp_inst, running, imp_snpl, inst); 6471 switch (r) { 6472 case 0: 6473 break; 6474 6475 case ECANCELED: 6476 case ENODEV: 6477 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6478 lcbdata->sc_err = EBUSY; 6479 r = UU_WALK_ERROR; 6480 goto deltemp; 6481 6482 case ECONNABORTED: 6483 goto connaborted; 6484 6485 case ENOMEM: 6486 case ENOSPC: 6487 case EBADF: 6488 case EBUSY: 6489 case EINVAL: 6490 case EPERM: 6491 case EROFS: 6492 case EACCES: 6493 case EEXIST: 6494 lcbdata->sc_err = r; 6495 r = UU_WALK_ERROR; 6496 goto deltemp; 6497 6498 default: 6499 bad_error("upgrade_props", r); 6500 } 6501 6502 inst->sc_import_state = IMPORT_PROP_DONE; 6503 } else { 6504 switch (scf_error()) { 6505 case SCF_ERROR_CONNECTION_BROKEN: 6506 goto connaborted; 6507 6508 case SCF_ERROR_NOT_FOUND: 6509 break; 6510 6511 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6512 case SCF_ERROR_HANDLE_MISMATCH: 6513 case SCF_ERROR_NOT_BOUND: 6514 case SCF_ERROR_NOT_SET: 6515 default: 6516 bad_error("scf_service_get_instance", scf_error()); 6517 } 6518 6519 fresh: 6520 /* create instance */ 6521 if (scf_service_add_instance(rsvc, inst->sc_name, 6522 imp_inst) != 0) { 6523 switch (scf_error()) { 6524 case SCF_ERROR_CONNECTION_BROKEN: 6525 goto connaborted; 6526 6527 case SCF_ERROR_NO_RESOURCES: 6528 case SCF_ERROR_BACKEND_READONLY: 6529 case SCF_ERROR_BACKEND_ACCESS: 6530 r = stash_scferror(lcbdata); 6531 goto deltemp; 6532 6533 case SCF_ERROR_EXISTS: 6534 warn(gettext("%s changed unexpectedly " 6535 "(instance \"%s\" added).\n"), 6536 inst->sc_parent->sc_fmri, inst->sc_name); 6537 lcbdata->sc_err = EBUSY; 6538 r = UU_WALK_ERROR; 6539 goto deltemp; 6540 6541 case SCF_ERROR_PERMISSION_DENIED: 6542 warn(gettext("Could not create \"%s\" instance " 6543 "in %s (permission denied).\n"), 6544 inst->sc_name, inst->sc_parent->sc_fmri); 6545 r = stash_scferror(lcbdata); 6546 goto deltemp; 6547 6548 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6549 case SCF_ERROR_HANDLE_MISMATCH: 6550 case SCF_ERROR_NOT_BOUND: 6551 case SCF_ERROR_NOT_SET: 6552 default: 6553 bad_error("scf_service_add_instance", 6554 scf_error()); 6555 } 6556 } 6557 6558 nosnap: 6559 /* 6560 * Create a last-import snapshot to serve as an attachment 6561 * point for the real one from the temporary instance. Since 6562 * the contents is irrelevant, take it now, while the instance 6563 * is empty, to minimize svc.configd's work. 6564 */ 6565 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6566 imp_lisnap) != 0) { 6567 switch (scf_error()) { 6568 case SCF_ERROR_CONNECTION_BROKEN: 6569 goto connaborted; 6570 6571 case SCF_ERROR_NO_RESOURCES: 6572 r = stash_scferror(lcbdata); 6573 goto deltemp; 6574 6575 case SCF_ERROR_EXISTS: 6576 warn(gettext("%s changed unexpectedly " 6577 "(snapshot \"%s\" added).\n"), 6578 inst->sc_fmri, snap_lastimport); 6579 lcbdata->sc_err = EBUSY; 6580 r = UU_WALK_ERROR; 6581 goto deltemp; 6582 6583 case SCF_ERROR_PERMISSION_DENIED: 6584 warn(gettext("Could not take \"%s\" snapshot " 6585 "of %s (permission denied).\n"), 6586 snap_lastimport, inst->sc_fmri); 6587 r = stash_scferror(lcbdata); 6588 goto deltemp; 6589 6590 default: 6591 scfwarn(); 6592 lcbdata->sc_err = -1; 6593 r = UU_WALK_ERROR; 6594 goto deltemp; 6595 6596 case SCF_ERROR_NOT_SET: 6597 case SCF_ERROR_INTERNAL: 6598 case SCF_ERROR_INVALID_ARGUMENT: 6599 case SCF_ERROR_HANDLE_MISMATCH: 6600 bad_error("_scf_snapshot_take_new", 6601 scf_error()); 6602 } 6603 } 6604 6605 if (li_only) 6606 goto lionly; 6607 6608 inst->sc_import_state = IMPORT_PROP_BEGUN; 6609 6610 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6611 flags); 6612 switch (r) { 6613 case 0: 6614 break; 6615 6616 case ECONNABORTED: 6617 goto connaborted; 6618 6619 case ECANCELED: 6620 warn(gettext("%s changed unexpectedly " 6621 "(instance \"%s\" deleted).\n"), 6622 inst->sc_parent->sc_fmri, inst->sc_name); 6623 lcbdata->sc_err = EBUSY; 6624 r = UU_WALK_ERROR; 6625 goto deltemp; 6626 6627 case EEXIST: 6628 warn(gettext("%s changed unexpectedly " 6629 "(property group added).\n"), inst->sc_fmri); 6630 lcbdata->sc_err = EBUSY; 6631 r = UU_WALK_ERROR; 6632 goto deltemp; 6633 6634 default: 6635 lcbdata->sc_err = r; 6636 r = UU_WALK_ERROR; 6637 goto deltemp; 6638 6639 case EINVAL: /* caught above */ 6640 bad_error("lscf_import_instance_pgs", r); 6641 } 6642 6643 ctx.sc_parent = imp_inst; 6644 ctx.sc_service = 0; 6645 ctx.sc_trans = NULL; 6646 ctx.sc_flags = 0; 6647 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6648 &ctx, UU_DEFAULT) != 0) { 6649 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6650 bad_error("uu_list_walk", uu_error()); 6651 6652 if (ctx.sc_err == ECONNABORTED) 6653 goto connaborted; 6654 lcbdata->sc_err = ctx.sc_err; 6655 r = UU_WALK_ERROR; 6656 goto deltemp; 6657 } 6658 6659 inst->sc_import_state = IMPORT_PROP_DONE; 6660 6661 if (g_verbose) 6662 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6663 snap_initial, inst->sc_fmri); 6664 r = take_snap(imp_inst, snap_initial, imp_snap); 6665 switch (r) { 6666 case 0: 6667 break; 6668 6669 case ECONNABORTED: 6670 goto connaborted; 6671 6672 case ENOSPC: 6673 case -1: 6674 lcbdata->sc_err = r; 6675 r = UU_WALK_ERROR; 6676 goto deltemp; 6677 6678 case ECANCELED: 6679 warn(gettext("%s changed unexpectedly " 6680 "(instance %s deleted).\n"), 6681 inst->sc_parent->sc_fmri, inst->sc_name); 6682 lcbdata->sc_err = r; 6683 r = UU_WALK_ERROR; 6684 goto deltemp; 6685 6686 case EPERM: 6687 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6688 lcbdata->sc_err = r; 6689 r = UU_WALK_ERROR; 6690 goto deltemp; 6691 6692 default: 6693 bad_error("take_snap", r); 6694 } 6695 } 6696 6697 lionly: 6698 if (lcbdata->sc_flags & SCI_NOSNAP) 6699 goto deltemp; 6700 6701 /* transfer snapshot from temporary instance */ 6702 if (g_verbose) 6703 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6704 snap_lastimport, inst->sc_fmri); 6705 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6706 switch (scf_error()) { 6707 case SCF_ERROR_CONNECTION_BROKEN: 6708 goto connaborted; 6709 6710 case SCF_ERROR_NO_RESOURCES: 6711 r = stash_scferror(lcbdata); 6712 goto deltemp; 6713 6714 case SCF_ERROR_PERMISSION_DENIED: 6715 warn(gettext("Could not take \"%s\" snapshot for %s " 6716 "(permission denied).\n"), snap_lastimport, 6717 inst->sc_fmri); 6718 r = stash_scferror(lcbdata); 6719 goto deltemp; 6720 6721 case SCF_ERROR_NOT_SET: 6722 case SCF_ERROR_HANDLE_MISMATCH: 6723 default: 6724 bad_error("_scf_snapshot_attach", scf_error()); 6725 } 6726 } 6727 6728 inst->sc_import_state = IMPORT_COMPLETE; 6729 6730 r = UU_WALK_NEXT; 6731 6732 deltemp: 6733 /* delete temporary instance */ 6734 if (scf_instance_delete(imp_tinst) != 0) { 6735 switch (scf_error()) { 6736 case SCF_ERROR_DELETED: 6737 break; 6738 6739 case SCF_ERROR_CONNECTION_BROKEN: 6740 goto connaborted; 6741 6742 case SCF_ERROR_NOT_SET: 6743 case SCF_ERROR_NOT_BOUND: 6744 default: 6745 bad_error("scf_instance_delete", scf_error()); 6746 } 6747 } 6748 6749 return (r); 6750 6751 connaborted: 6752 warn(gettext("Could not delete svc:/%s:%s " 6753 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6754 lcbdata->sc_err = ECONNABORTED; 6755 return (UU_WALK_ERROR); 6756 } 6757 6758 /* 6759 * When an instance is imported we end up telling configd about it. Once we tell 6760 * configd about these changes, startd eventually notices. If this is a new 6761 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter) 6762 * property group. However, many of the other tools expect that this property 6763 * group exists and has certain values. 6764 * 6765 * These values are added asynchronously by startd. We should not return from 6766 * this routine until we can verify that the property group we need is there. 6767 * 6768 * Before we go ahead and verify this, we have to ask ourselves an important 6769 * question: Is the early manifest service currently running? Because if it is 6770 * running and it has invoked us, then the service will never get a restarter 6771 * property because svc.startd is blocked on EMI finishing before it lets itself 6772 * fully connect to svc.configd. Of course, this means that this race condition 6773 * is in fact impossible to 100% eliminate. 6774 * 6775 * svc.startd makes sure that EMI only runs once and has succeeded by checking 6776 * the state of the EMI instance. If it is online it bails out and makes sure 6777 * that it doesn't run again. In this case, we're going to do something similar, 6778 * only if the state is online, then we're going to actually verify. EMI always 6779 * has to be present, but it can be explicitly disabled to reduce the amount of 6780 * damage it can cause. If EMI has been disabled then we no longer have to worry 6781 * about the implicit race condition and can go ahead and check things. If EMI 6782 * is in some state that isn't online or disabled and isn't runinng, then we 6783 * assume that things are rather bad and we're not going to get in your way, 6784 * even if the rest of SMF does. 6785 * 6786 * Returns 0 on success or returns an errno. 6787 */ 6788 #ifndef NATIVE_BUILD 6789 static int 6790 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst) 6791 { 6792 int ret, err; 6793 struct timespec ts; 6794 char *emi_state; 6795 6796 /* 6797 * smf_get_state does not distinguish between its different failure 6798 * modes: memory allocation failures, SMF internal failures, and a lack 6799 * of EMI entirely because it's been removed. In these cases, we're 6800 * going to be conservative and opt to say that if we don't know, better 6801 * to not block import or falsely warn to the user. 6802 */ 6803 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) { 6804 return (0); 6805 } 6806 6807 /* 6808 * As per the block comment for this function check the state of EMI 6809 */ 6810 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 && 6811 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) { 6812 warn(gettext("Not validating instance %s:%s because EMI's " 6813 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state); 6814 free(emi_state); 6815 return (0); 6816 } 6817 6818 free(emi_state); 6819 6820 /* 6821 * First we have to get the property. 6822 */ 6823 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) { 6824 ret = scf_error(); 6825 warn(gettext("Failed to look up service: %s\n"), svc->sc_name); 6826 return (ret); 6827 } 6828 6829 /* 6830 * We should always be able to get the instance. It should already 6831 * exist because we just created it or got it. There probably is a 6832 * slim chance that someone may have come in and deleted it though from 6833 * under us. 6834 */ 6835 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst)) 6836 != 0) { 6837 ret = scf_error(); 6838 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name); 6839 switch (ret) { 6840 case SCF_ERROR_DELETED: 6841 err = ENODEV; 6842 break; 6843 case SCF_ERROR_CONNECTION_BROKEN: 6844 warn(gettext("Lost repository connection\n")); 6845 err = ECONNABORTED; 6846 break; 6847 case SCF_ERROR_NOT_FOUND: 6848 warn(gettext("Instance \"%s\" disappeared out from " 6849 "under us.\n"), inst->sc_name); 6850 err = ENOENT; 6851 break; 6852 default: 6853 bad_error("scf_service_get_instance", ret); 6854 } 6855 6856 return (err); 6857 } 6858 6859 /* 6860 * An astute observer may want to use _scf_wait_pg which would notify us 6861 * of a property group change, unfortunately that does not work if the 6862 * property group in question does not exist. So instead we have to 6863 * manually poll and ask smf the best way to get to it. 6864 */ 6865 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg)) 6866 != SCF_SUCCESS) { 6867 ret = scf_error(); 6868 if (ret != SCF_ERROR_NOT_FOUND) { 6869 warn(gettext("Failed to get restarter property " 6870 "group for instance: %s\n"), inst->sc_name); 6871 switch (ret) { 6872 case SCF_ERROR_DELETED: 6873 err = ENODEV; 6874 break; 6875 case SCF_ERROR_CONNECTION_BROKEN: 6876 warn(gettext("Lost repository connection\n")); 6877 err = ECONNABORTED; 6878 break; 6879 default: 6880 bad_error("scf_service_get_instance", ret); 6881 } 6882 6883 return (err); 6884 } 6885 6886 ts.tv_sec = pg_timeout / NANOSEC; 6887 ts.tv_nsec = pg_timeout % NANOSEC; 6888 6889 (void) nanosleep(&ts, NULL); 6890 } 6891 6892 /* 6893 * svcadm also expects that the SCF_PROPERTY_STATE property is present. 6894 * So in addition to the property group being present, we need to wait 6895 * for the property to be there in some form. 6896 * 6897 * Note that a property group is a frozen snapshot in time. To properly 6898 * get beyond this, you have to refresh the property group each time. 6899 */ 6900 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE, 6901 imp_prop)) != 0) { 6902 6903 ret = scf_error(); 6904 if (ret != SCF_ERROR_NOT_FOUND) { 6905 warn(gettext("Failed to get property %s from the " 6906 "restarter property group of instance %s\n"), 6907 SCF_PROPERTY_STATE, inst->sc_name); 6908 switch (ret) { 6909 case SCF_ERROR_CONNECTION_BROKEN: 6910 warn(gettext("Lost repository connection\n")); 6911 err = ECONNABORTED; 6912 break; 6913 case SCF_ERROR_DELETED: 6914 err = ENODEV; 6915 break; 6916 default: 6917 bad_error("scf_pg_get_property", ret); 6918 } 6919 6920 return (err); 6921 } 6922 6923 ts.tv_sec = pg_timeout / NANOSEC; 6924 ts.tv_nsec = pg_timeout % NANOSEC; 6925 6926 (void) nanosleep(&ts, NULL); 6927 6928 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg); 6929 if (ret != SCF_SUCCESS) { 6930 warn(gettext("Failed to get restarter property " 6931 "group for instance: %s\n"), inst->sc_name); 6932 switch (ret) { 6933 case SCF_ERROR_DELETED: 6934 err = ENODEV; 6935 break; 6936 case SCF_ERROR_CONNECTION_BROKEN: 6937 warn(gettext("Lost repository connection\n")); 6938 err = ECONNABORTED; 6939 break; 6940 default: 6941 bad_error("scf_service_get_instance", ret); 6942 } 6943 6944 return (err); 6945 } 6946 } 6947 6948 /* 6949 * We don't have to free the property groups or other values that we got 6950 * because we stored them in global variables that are allocated and 6951 * freed by the routines that call into these functions. Unless of 6952 * course the rest of the code here that we are basing this on is 6953 * mistaken. 6954 */ 6955 return (0); 6956 } 6957 #endif 6958 6959 /* 6960 * If the service is missing, create it, import its properties, and import the 6961 * instances. Since the service is brand new, it should be empty, and if we 6962 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6963 * 6964 * If the service exists, we want to upgrade its properties and import the 6965 * instances. Upgrade requires a last-import snapshot, though, which are 6966 * children of instances, so first we'll have to go through the instances 6967 * looking for a last-import snapshot. If we don't find one then we'll just 6968 * override-import the service properties (but don't delete existing 6969 * properties: another service might have declared us as a dependent). Before 6970 * we change anything, though, we want to take the previous snapshots. We 6971 * also give lscf_instance_import() a leg up on taking last-import snapshots 6972 * by importing the manifest's service properties into a temporary service. 6973 * 6974 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6975 * sets lcbdata->sc_err to 6976 * ECONNABORTED - repository connection broken 6977 * ENOMEM - out of memory 6978 * ENOSPC - svc.configd is out of resources 6979 * EPERM - couldn't create temporary service (error printed) 6980 * - couldn't import into temp service (error printed) 6981 * - couldn't create service (error printed) 6982 * - couldn't import dependent (error printed) 6983 * - couldn't take snapshot (error printed) 6984 * - couldn't create instance (error printed) 6985 * - couldn't create, modify, or delete pg (error printed) 6986 * - couldn't create, modify, or delete dependent (error printed) 6987 * - couldn't import instance (error printed) 6988 * EROFS - couldn't create temporary service (repository read-only) 6989 * - couldn't import into temporary service (repository read-only) 6990 * - couldn't create service (repository read-only) 6991 * - couldn't import dependent (repository read-only) 6992 * - couldn't create instance (repository read-only) 6993 * - couldn't create, modify, or delete pg or dependent 6994 * - couldn't import instance (repository read-only) 6995 * EACCES - couldn't create temporary service (backend access denied) 6996 * - couldn't import into temporary service (backend access denied) 6997 * - couldn't create service (backend access denied) 6998 * - couldn't import dependent (backend access denied) 6999 * - couldn't create instance (backend access denied) 7000 * - couldn't create, modify, or delete pg or dependent 7001 * - couldn't import instance (backend access denied) 7002 * EINVAL - service name is invalid (error printed) 7003 * - service name is too long (error printed) 7004 * - s has invalid pgroup (error printed) 7005 * - s has invalid dependent (error printed) 7006 * - instance name is invalid (error printed) 7007 * - instance entity_t is invalid (error printed) 7008 * EEXIST - couldn't create temporary service (already exists) (error printed) 7009 * - couldn't import dependent (dependency pg already exists) (printed) 7010 * - dependency collision in dependent service (error printed) 7011 * EBUSY - temporary service deleted (error printed) 7012 * - property group added to temporary service (error printed) 7013 * - new property group changed or was deleted (error printed) 7014 * - service was added unexpectedly (error printed) 7015 * - service was deleted unexpectedly (error printed) 7016 * - property group added to new service (error printed) 7017 * - instance added unexpectedly (error printed) 7018 * - instance deleted unexpectedly (error printed) 7019 * - dependent service deleted unexpectedly (error printed) 7020 * - pg was added, changed, or deleted (error printed) 7021 * - dependent pg changed (error printed) 7022 * - temporary instance added, changed, or deleted (error printed) 7023 * EBADF - a last-import snapshot is corrupt (error printed) 7024 * - the service is corrupt (error printed) 7025 * - a dependent is corrupt (error printed) 7026 * - an instance is corrupt (error printed) 7027 * - an instance has a corrupt last-import snapshot (error printed) 7028 * - dependent target has a corrupt snapshot (error printed) 7029 * -1 - unknown libscf error (error printed) 7030 */ 7031 static int 7032 lscf_service_import(void *v, void *pvt) 7033 { 7034 entity_t *s = v; 7035 scf_callback_t cbdata; 7036 scf_callback_t *lcbdata = pvt; 7037 scf_scope_t *scope = lcbdata->sc_parent; 7038 entity_t *inst, linst; 7039 int r; 7040 int fresh = 0; 7041 scf_snaplevel_t *running; 7042 int have_ge = 0; 7043 boolean_t retried = B_FALSE; 7044 7045 const char * const ts_deleted = gettext("Temporary service svc:/%s " 7046 "was deleted unexpectedly.\n"); 7047 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 7048 "changed unexpectedly (property group added).\n"); 7049 const char * const s_deleted = 7050 gettext("%s was deleted unexpectedly.\n"); 7051 const char * const i_deleted = 7052 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 7053 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 7054 "is corrupt (missing service snaplevel).\n"); 7055 const char * const s_mfile_upd = 7056 gettext("Unable to update the manifest file connection " 7057 "for %s\n"); 7058 7059 li_only = 0; 7060 /* Validate the service name */ 7061 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7062 switch (scf_error()) { 7063 case SCF_ERROR_CONNECTION_BROKEN: 7064 return (stash_scferror(lcbdata)); 7065 7066 case SCF_ERROR_INVALID_ARGUMENT: 7067 warn(gettext("\"%s\" is an invalid service name. " 7068 "Cannot import.\n"), s->sc_name); 7069 return (stash_scferror(lcbdata)); 7070 7071 case SCF_ERROR_NOT_FOUND: 7072 break; 7073 7074 case SCF_ERROR_HANDLE_MISMATCH: 7075 case SCF_ERROR_NOT_BOUND: 7076 case SCF_ERROR_NOT_SET: 7077 default: 7078 bad_error("scf_scope_get_service", scf_error()); 7079 } 7080 } 7081 7082 /* create temporary service */ 7083 /* 7084 * the size of the buffer was reduced to max_scf_name_len to prevent 7085 * hitting bug 6681151. After the bug fix, the size of the buffer 7086 * should be restored to its original value (max_scf_name_len +1) 7087 */ 7088 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 7089 if (r < 0) 7090 bad_error("snprintf", errno); 7091 if (r > max_scf_name_len) { 7092 warn(gettext( 7093 "Service name \"%s\" is too long. Cannot import.\n"), 7094 s->sc_name); 7095 lcbdata->sc_err = EINVAL; 7096 return (UU_WALK_ERROR); 7097 } 7098 7099 retry: 7100 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 7101 switch (scf_error()) { 7102 case SCF_ERROR_CONNECTION_BROKEN: 7103 case SCF_ERROR_NO_RESOURCES: 7104 case SCF_ERROR_BACKEND_READONLY: 7105 case SCF_ERROR_BACKEND_ACCESS: 7106 return (stash_scferror(lcbdata)); 7107 7108 case SCF_ERROR_EXISTS: 7109 if (!retried) { 7110 lscf_delete(imp_tsname, 0); 7111 retried = B_TRUE; 7112 goto retry; 7113 } 7114 warn(gettext( 7115 "Temporary service \"%s\" must be deleted before " 7116 "this manifest can be imported.\n"), imp_tsname); 7117 return (stash_scferror(lcbdata)); 7118 7119 case SCF_ERROR_PERMISSION_DENIED: 7120 warn(gettext("Could not create temporary service " 7121 "\"%s\" (permission denied).\n"), imp_tsname); 7122 return (stash_scferror(lcbdata)); 7123 7124 case SCF_ERROR_INVALID_ARGUMENT: 7125 case SCF_ERROR_HANDLE_MISMATCH: 7126 case SCF_ERROR_NOT_BOUND: 7127 case SCF_ERROR_NOT_SET: 7128 default: 7129 bad_error("scf_scope_add_service", scf_error()); 7130 } 7131 } 7132 7133 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 7134 if (r < 0) 7135 bad_error("snprintf", errno); 7136 7137 cbdata.sc_handle = lcbdata->sc_handle; 7138 cbdata.sc_parent = imp_tsvc; 7139 cbdata.sc_service = 1; 7140 cbdata.sc_source_fmri = s->sc_fmri; 7141 cbdata.sc_target_fmri = imp_str; 7142 cbdata.sc_flags = 0; 7143 7144 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 7145 UU_DEFAULT) != 0) { 7146 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7147 bad_error("uu_list_walk", uu_error()); 7148 7149 lcbdata->sc_err = cbdata.sc_err; 7150 switch (cbdata.sc_err) { 7151 case ECONNABORTED: 7152 goto connaborted; 7153 7154 case ECANCELED: 7155 warn(ts_deleted, imp_tsname); 7156 lcbdata->sc_err = EBUSY; 7157 return (UU_WALK_ERROR); 7158 7159 case EEXIST: 7160 warn(ts_pg_added, imp_tsname); 7161 lcbdata->sc_err = EBUSY; 7162 return (UU_WALK_ERROR); 7163 } 7164 7165 r = UU_WALK_ERROR; 7166 goto deltemp; 7167 } 7168 7169 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 7170 UU_DEFAULT) != 0) { 7171 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7172 bad_error("uu_list_walk", uu_error()); 7173 7174 lcbdata->sc_err = cbdata.sc_err; 7175 switch (cbdata.sc_err) { 7176 case ECONNABORTED: 7177 goto connaborted; 7178 7179 case ECANCELED: 7180 warn(ts_deleted, imp_tsname); 7181 lcbdata->sc_err = EBUSY; 7182 return (UU_WALK_ERROR); 7183 7184 case EEXIST: 7185 warn(ts_pg_added, imp_tsname); 7186 lcbdata->sc_err = EBUSY; 7187 return (UU_WALK_ERROR); 7188 } 7189 7190 r = UU_WALK_ERROR; 7191 goto deltemp; 7192 } 7193 7194 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7195 switch (scf_error()) { 7196 case SCF_ERROR_NOT_FOUND: 7197 break; 7198 7199 case SCF_ERROR_CONNECTION_BROKEN: 7200 goto connaborted; 7201 7202 case SCF_ERROR_INVALID_ARGUMENT: 7203 case SCF_ERROR_HANDLE_MISMATCH: 7204 case SCF_ERROR_NOT_BOUND: 7205 case SCF_ERROR_NOT_SET: 7206 default: 7207 bad_error("scf_scope_get_service", scf_error()); 7208 } 7209 7210 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 7211 switch (scf_error()) { 7212 case SCF_ERROR_CONNECTION_BROKEN: 7213 goto connaborted; 7214 7215 case SCF_ERROR_NO_RESOURCES: 7216 case SCF_ERROR_BACKEND_READONLY: 7217 case SCF_ERROR_BACKEND_ACCESS: 7218 r = stash_scferror(lcbdata); 7219 goto deltemp; 7220 7221 case SCF_ERROR_EXISTS: 7222 warn(gettext("Scope \"%s\" changed unexpectedly" 7223 " (service \"%s\" added).\n"), 7224 SCF_SCOPE_LOCAL, s->sc_name); 7225 lcbdata->sc_err = EBUSY; 7226 goto deltemp; 7227 7228 case SCF_ERROR_PERMISSION_DENIED: 7229 warn(gettext("Could not create service \"%s\" " 7230 "(permission denied).\n"), s->sc_name); 7231 goto deltemp; 7232 7233 case SCF_ERROR_INVALID_ARGUMENT: 7234 case SCF_ERROR_HANDLE_MISMATCH: 7235 case SCF_ERROR_NOT_BOUND: 7236 case SCF_ERROR_NOT_SET: 7237 default: 7238 bad_error("scf_scope_add_service", scf_error()); 7239 } 7240 } 7241 7242 s->sc_import_state = IMPORT_PROP_BEGUN; 7243 7244 /* import service properties */ 7245 cbdata.sc_handle = lcbdata->sc_handle; 7246 cbdata.sc_parent = imp_svc; 7247 cbdata.sc_service = 1; 7248 cbdata.sc_flags = lcbdata->sc_flags; 7249 cbdata.sc_source_fmri = s->sc_fmri; 7250 cbdata.sc_target_fmri = s->sc_fmri; 7251 7252 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7253 &cbdata, UU_DEFAULT) != 0) { 7254 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7255 bad_error("uu_list_walk", uu_error()); 7256 7257 lcbdata->sc_err = cbdata.sc_err; 7258 switch (cbdata.sc_err) { 7259 case ECONNABORTED: 7260 goto connaborted; 7261 7262 case ECANCELED: 7263 warn(s_deleted, s->sc_fmri); 7264 lcbdata->sc_err = EBUSY; 7265 return (UU_WALK_ERROR); 7266 7267 case EEXIST: 7268 warn(gettext("%s changed unexpectedly " 7269 "(property group added).\n"), s->sc_fmri); 7270 lcbdata->sc_err = EBUSY; 7271 return (UU_WALK_ERROR); 7272 7273 case EINVAL: 7274 /* caught above */ 7275 bad_error("entity_pgroup_import", 7276 cbdata.sc_err); 7277 } 7278 7279 r = UU_WALK_ERROR; 7280 goto deltemp; 7281 } 7282 7283 cbdata.sc_trans = NULL; 7284 cbdata.sc_flags = 0; 7285 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 7286 &cbdata, UU_DEFAULT) != 0) { 7287 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7288 bad_error("uu_list_walk", uu_error()); 7289 7290 lcbdata->sc_err = cbdata.sc_err; 7291 if (cbdata.sc_err == ECONNABORTED) 7292 goto connaborted; 7293 r = UU_WALK_ERROR; 7294 goto deltemp; 7295 } 7296 7297 s->sc_import_state = IMPORT_PROP_DONE; 7298 7299 /* 7300 * This is a new service, so we can't take previous snapshots 7301 * or upgrade service properties. 7302 */ 7303 fresh = 1; 7304 goto instances; 7305 } 7306 7307 /* Clear sc_seen for the instances. */ 7308 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 7309 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 7310 bad_error("uu_list_walk", uu_error()); 7311 7312 /* 7313 * Take previous snapshots for all instances. Even for ones not 7314 * mentioned in the bundle, since we might change their service 7315 * properties. 7316 */ 7317 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7318 switch (scf_error()) { 7319 case SCF_ERROR_CONNECTION_BROKEN: 7320 goto connaborted; 7321 7322 case SCF_ERROR_DELETED: 7323 warn(s_deleted, s->sc_fmri); 7324 lcbdata->sc_err = EBUSY; 7325 r = UU_WALK_ERROR; 7326 goto deltemp; 7327 7328 case SCF_ERROR_HANDLE_MISMATCH: 7329 case SCF_ERROR_NOT_BOUND: 7330 case SCF_ERROR_NOT_SET: 7331 default: 7332 bad_error("scf_iter_service_instances", scf_error()); 7333 } 7334 } 7335 7336 for (;;) { 7337 r = scf_iter_next_instance(imp_iter, imp_inst); 7338 if (r == 0) 7339 break; 7340 if (r != 1) { 7341 switch (scf_error()) { 7342 case SCF_ERROR_DELETED: 7343 warn(s_deleted, s->sc_fmri); 7344 lcbdata->sc_err = EBUSY; 7345 r = UU_WALK_ERROR; 7346 goto deltemp; 7347 7348 case SCF_ERROR_CONNECTION_BROKEN: 7349 goto connaborted; 7350 7351 case SCF_ERROR_NOT_BOUND: 7352 case SCF_ERROR_HANDLE_MISMATCH: 7353 case SCF_ERROR_INVALID_ARGUMENT: 7354 case SCF_ERROR_NOT_SET: 7355 default: 7356 bad_error("scf_iter_next_instance", 7357 scf_error()); 7358 } 7359 } 7360 7361 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 7362 switch (scf_error()) { 7363 case SCF_ERROR_DELETED: 7364 continue; 7365 7366 case SCF_ERROR_CONNECTION_BROKEN: 7367 goto connaborted; 7368 7369 case SCF_ERROR_NOT_SET: 7370 case SCF_ERROR_NOT_BOUND: 7371 default: 7372 bad_error("scf_instance_get_name", scf_error()); 7373 } 7374 } 7375 7376 if (g_verbose) 7377 warn(gettext( 7378 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 7379 snap_previous, s->sc_name, imp_str); 7380 7381 r = take_snap(imp_inst, snap_previous, imp_snap); 7382 switch (r) { 7383 case 0: 7384 break; 7385 7386 case ECANCELED: 7387 continue; 7388 7389 case ECONNABORTED: 7390 goto connaborted; 7391 7392 case EPERM: 7393 warn(gettext("Could not take \"%s\" snapshot of " 7394 "svc:/%s:%s (permission denied).\n"), 7395 snap_previous, s->sc_name, imp_str); 7396 lcbdata->sc_err = r; 7397 return (UU_WALK_ERROR); 7398 7399 case ENOSPC: 7400 case -1: 7401 lcbdata->sc_err = r; 7402 r = UU_WALK_ERROR; 7403 goto deltemp; 7404 7405 default: 7406 bad_error("take_snap", r); 7407 } 7408 7409 linst.sc_name = imp_str; 7410 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 7411 &linst, NULL, NULL); 7412 if (inst != NULL) { 7413 inst->sc_import_state = IMPORT_PREVIOUS; 7414 inst->sc_seen = 1; 7415 } 7416 } 7417 7418 /* 7419 * Create the new instances and take previous snapshots of 7420 * them. This is not necessary, but it maximizes data preservation. 7421 */ 7422 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 7423 inst != NULL; 7424 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 7425 inst)) { 7426 if (inst->sc_seen) 7427 continue; 7428 7429 if (scf_service_add_instance(imp_svc, inst->sc_name, 7430 imp_inst) != 0) { 7431 switch (scf_error()) { 7432 case SCF_ERROR_CONNECTION_BROKEN: 7433 goto connaborted; 7434 7435 case SCF_ERROR_BACKEND_READONLY: 7436 case SCF_ERROR_BACKEND_ACCESS: 7437 case SCF_ERROR_NO_RESOURCES: 7438 r = stash_scferror(lcbdata); 7439 goto deltemp; 7440 7441 case SCF_ERROR_EXISTS: 7442 warn(gettext("%s changed unexpectedly " 7443 "(instance \"%s\" added).\n"), s->sc_fmri, 7444 inst->sc_name); 7445 lcbdata->sc_err = EBUSY; 7446 r = UU_WALK_ERROR; 7447 goto deltemp; 7448 7449 case SCF_ERROR_INVALID_ARGUMENT: 7450 warn(gettext("Service \"%s\" has instance with " 7451 "invalid name \"%s\".\n"), s->sc_name, 7452 inst->sc_name); 7453 r = stash_scferror(lcbdata); 7454 goto deltemp; 7455 7456 case SCF_ERROR_PERMISSION_DENIED: 7457 warn(gettext("Could not create instance \"%s\" " 7458 "in %s (permission denied).\n"), 7459 inst->sc_name, s->sc_fmri); 7460 r = stash_scferror(lcbdata); 7461 goto deltemp; 7462 7463 case SCF_ERROR_HANDLE_MISMATCH: 7464 case SCF_ERROR_NOT_BOUND: 7465 case SCF_ERROR_NOT_SET: 7466 default: 7467 bad_error("scf_service_add_instance", 7468 scf_error()); 7469 } 7470 } 7471 7472 if (g_verbose) 7473 warn(gettext("Taking \"%s\" snapshot for " 7474 "new service %s.\n"), snap_previous, inst->sc_fmri); 7475 r = take_snap(imp_inst, snap_previous, imp_snap); 7476 switch (r) { 7477 case 0: 7478 break; 7479 7480 case ECANCELED: 7481 warn(i_deleted, s->sc_fmri, inst->sc_name); 7482 lcbdata->sc_err = EBUSY; 7483 r = UU_WALK_ERROR; 7484 goto deltemp; 7485 7486 case ECONNABORTED: 7487 goto connaborted; 7488 7489 case EPERM: 7490 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 7491 lcbdata->sc_err = r; 7492 r = UU_WALK_ERROR; 7493 goto deltemp; 7494 7495 case ENOSPC: 7496 case -1: 7497 r = UU_WALK_ERROR; 7498 goto deltemp; 7499 7500 default: 7501 bad_error("take_snap", r); 7502 } 7503 } 7504 7505 s->sc_import_state = IMPORT_PREVIOUS; 7506 7507 /* 7508 * Upgrade service properties, if we can find a last-import snapshot. 7509 * Any will do because we don't support different service properties 7510 * in different manifests, so all snaplevels of the service in all of 7511 * the last-import snapshots of the instances should be the same. 7512 */ 7513 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7514 switch (scf_error()) { 7515 case SCF_ERROR_CONNECTION_BROKEN: 7516 goto connaborted; 7517 7518 case SCF_ERROR_DELETED: 7519 warn(s_deleted, s->sc_fmri); 7520 lcbdata->sc_err = EBUSY; 7521 r = UU_WALK_ERROR; 7522 goto deltemp; 7523 7524 case SCF_ERROR_HANDLE_MISMATCH: 7525 case SCF_ERROR_NOT_BOUND: 7526 case SCF_ERROR_NOT_SET: 7527 default: 7528 bad_error("scf_iter_service_instances", scf_error()); 7529 } 7530 } 7531 7532 for (;;) { 7533 r = scf_iter_next_instance(imp_iter, imp_inst); 7534 if (r == -1) { 7535 switch (scf_error()) { 7536 case SCF_ERROR_DELETED: 7537 warn(s_deleted, s->sc_fmri); 7538 lcbdata->sc_err = EBUSY; 7539 r = UU_WALK_ERROR; 7540 goto deltemp; 7541 7542 case SCF_ERROR_CONNECTION_BROKEN: 7543 goto connaborted; 7544 7545 case SCF_ERROR_NOT_BOUND: 7546 case SCF_ERROR_HANDLE_MISMATCH: 7547 case SCF_ERROR_INVALID_ARGUMENT: 7548 case SCF_ERROR_NOT_SET: 7549 default: 7550 bad_error("scf_iter_next_instance", 7551 scf_error()); 7552 } 7553 } 7554 7555 if (r == 0) { 7556 /* 7557 * Didn't find any last-import snapshots. Override- 7558 * import the properties. Unless one of the instances 7559 * has a general/enabled property, in which case we're 7560 * probably running a last-import-capable svccfg for 7561 * the first time, and we should only take the 7562 * last-import snapshot. 7563 */ 7564 if (have_ge) { 7565 pgroup_t *mfpg; 7566 scf_callback_t mfcbdata; 7567 7568 li_only = 1; 7569 no_refresh = 1; 7570 /* 7571 * Need to go ahead and import the manifestfiles 7572 * pg if it exists. If the last-import snapshot 7573 * upgrade code is ever removed this code can 7574 * be removed as well. 7575 */ 7576 mfpg = internal_pgroup_find(s, 7577 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 7578 7579 if (mfpg) { 7580 mfcbdata.sc_handle = g_hndl; 7581 mfcbdata.sc_parent = imp_svc; 7582 mfcbdata.sc_service = 1; 7583 mfcbdata.sc_flags = SCI_FORCE; 7584 mfcbdata.sc_source_fmri = s->sc_fmri; 7585 mfcbdata.sc_target_fmri = s->sc_fmri; 7586 if (entity_pgroup_import(mfpg, 7587 &mfcbdata) != UU_WALK_NEXT) { 7588 warn(s_mfile_upd, s->sc_fmri); 7589 r = UU_WALK_ERROR; 7590 goto deltemp; 7591 } 7592 } 7593 break; 7594 } 7595 7596 s->sc_import_state = IMPORT_PROP_BEGUN; 7597 7598 cbdata.sc_handle = g_hndl; 7599 cbdata.sc_parent = imp_svc; 7600 cbdata.sc_service = 1; 7601 cbdata.sc_flags = SCI_FORCE; 7602 cbdata.sc_source_fmri = s->sc_fmri; 7603 cbdata.sc_target_fmri = s->sc_fmri; 7604 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7605 &cbdata, UU_DEFAULT) != 0) { 7606 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7607 bad_error("uu_list_walk", uu_error()); 7608 lcbdata->sc_err = cbdata.sc_err; 7609 switch (cbdata.sc_err) { 7610 case ECONNABORTED: 7611 goto connaborted; 7612 7613 case ECANCELED: 7614 warn(s_deleted, s->sc_fmri); 7615 lcbdata->sc_err = EBUSY; 7616 break; 7617 7618 case EINVAL: /* caught above */ 7619 case EEXIST: 7620 bad_error("entity_pgroup_import", 7621 cbdata.sc_err); 7622 } 7623 7624 r = UU_WALK_ERROR; 7625 goto deltemp; 7626 } 7627 7628 cbdata.sc_trans = NULL; 7629 cbdata.sc_flags = 0; 7630 if (uu_list_walk(s->sc_dependents, 7631 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 7632 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7633 bad_error("uu_list_walk", uu_error()); 7634 lcbdata->sc_err = cbdata.sc_err; 7635 if (cbdata.sc_err == ECONNABORTED) 7636 goto connaborted; 7637 r = UU_WALK_ERROR; 7638 goto deltemp; 7639 } 7640 break; 7641 } 7642 7643 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 7644 imp_snap) != 0) { 7645 switch (scf_error()) { 7646 case SCF_ERROR_DELETED: 7647 continue; 7648 7649 case SCF_ERROR_NOT_FOUND: 7650 break; 7651 7652 case SCF_ERROR_CONNECTION_BROKEN: 7653 goto connaborted; 7654 7655 case SCF_ERROR_HANDLE_MISMATCH: 7656 case SCF_ERROR_NOT_BOUND: 7657 case SCF_ERROR_INVALID_ARGUMENT: 7658 case SCF_ERROR_NOT_SET: 7659 default: 7660 bad_error("scf_instance_get_snapshot", 7661 scf_error()); 7662 } 7663 7664 if (have_ge) 7665 continue; 7666 7667 /* 7668 * Check for a general/enabled property. This is how 7669 * we tell whether to import if there turn out to be 7670 * no last-import snapshots. 7671 */ 7672 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 7673 imp_pg) == 0) { 7674 if (scf_pg_get_property(imp_pg, 7675 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 7676 have_ge = 1; 7677 } else { 7678 switch (scf_error()) { 7679 case SCF_ERROR_DELETED: 7680 case SCF_ERROR_NOT_FOUND: 7681 continue; 7682 7683 case SCF_ERROR_INVALID_ARGUMENT: 7684 case SCF_ERROR_HANDLE_MISMATCH: 7685 case SCF_ERROR_CONNECTION_BROKEN: 7686 case SCF_ERROR_NOT_BOUND: 7687 case SCF_ERROR_NOT_SET: 7688 default: 7689 bad_error("scf_pg_get_property", 7690 scf_error()); 7691 } 7692 } 7693 } else { 7694 switch (scf_error()) { 7695 case SCF_ERROR_DELETED: 7696 case SCF_ERROR_NOT_FOUND: 7697 continue; 7698 7699 case SCF_ERROR_CONNECTION_BROKEN: 7700 goto connaborted; 7701 7702 case SCF_ERROR_NOT_BOUND: 7703 case SCF_ERROR_NOT_SET: 7704 case SCF_ERROR_INVALID_ARGUMENT: 7705 case SCF_ERROR_HANDLE_MISMATCH: 7706 default: 7707 bad_error("scf_instance_get_pg", 7708 scf_error()); 7709 } 7710 } 7711 continue; 7712 } 7713 7714 /* find service snaplevel */ 7715 r = get_snaplevel(imp_snap, 1, imp_snpl); 7716 switch (r) { 7717 case 0: 7718 break; 7719 7720 case ECONNABORTED: 7721 goto connaborted; 7722 7723 case ECANCELED: 7724 continue; 7725 7726 case ENOENT: 7727 if (scf_instance_get_name(imp_inst, imp_str, 7728 imp_str_sz) < 0) 7729 (void) strcpy(imp_str, "?"); 7730 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 7731 lcbdata->sc_err = EBADF; 7732 r = UU_WALK_ERROR; 7733 goto deltemp; 7734 7735 default: 7736 bad_error("get_snaplevel", r); 7737 } 7738 7739 if (scf_instance_get_snapshot(imp_inst, snap_running, 7740 imp_rsnap) != 0) { 7741 switch (scf_error()) { 7742 case SCF_ERROR_DELETED: 7743 continue; 7744 7745 case SCF_ERROR_NOT_FOUND: 7746 break; 7747 7748 case SCF_ERROR_CONNECTION_BROKEN: 7749 goto connaborted; 7750 7751 case SCF_ERROR_INVALID_ARGUMENT: 7752 case SCF_ERROR_HANDLE_MISMATCH: 7753 case SCF_ERROR_NOT_BOUND: 7754 case SCF_ERROR_NOT_SET: 7755 default: 7756 bad_error("scf_instance_get_snapshot", 7757 scf_error()); 7758 } 7759 running = NULL; 7760 } else { 7761 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7762 switch (r) { 7763 case 0: 7764 running = imp_rsnpl; 7765 break; 7766 7767 case ECONNABORTED: 7768 goto connaborted; 7769 7770 case ECANCELED: 7771 continue; 7772 7773 case ENOENT: 7774 if (scf_instance_get_name(imp_inst, imp_str, 7775 imp_str_sz) < 0) 7776 (void) strcpy(imp_str, "?"); 7777 warn(badsnap, snap_running, s->sc_name, 7778 imp_str); 7779 lcbdata->sc_err = EBADF; 7780 r = UU_WALK_ERROR; 7781 goto deltemp; 7782 7783 default: 7784 bad_error("get_snaplevel", r); 7785 } 7786 } 7787 7788 if (g_verbose) { 7789 if (scf_instance_get_name(imp_inst, imp_str, 7790 imp_str_sz) < 0) 7791 (void) strcpy(imp_str, "?"); 7792 warn(gettext("Upgrading properties of %s according to " 7793 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7794 } 7795 7796 /* upgrade service properties */ 7797 r = upgrade_props(imp_svc, running, imp_snpl, s); 7798 if (r == 0) 7799 break; 7800 7801 switch (r) { 7802 case ECONNABORTED: 7803 goto connaborted; 7804 7805 case ECANCELED: 7806 warn(s_deleted, s->sc_fmri); 7807 lcbdata->sc_err = EBUSY; 7808 break; 7809 7810 case ENODEV: 7811 if (scf_instance_get_name(imp_inst, imp_str, 7812 imp_str_sz) < 0) 7813 (void) strcpy(imp_str, "?"); 7814 warn(i_deleted, s->sc_fmri, imp_str); 7815 lcbdata->sc_err = EBUSY; 7816 break; 7817 7818 default: 7819 lcbdata->sc_err = r; 7820 } 7821 7822 r = UU_WALK_ERROR; 7823 goto deltemp; 7824 } 7825 7826 s->sc_import_state = IMPORT_PROP_DONE; 7827 7828 instances: 7829 /* import instances */ 7830 cbdata.sc_handle = lcbdata->sc_handle; 7831 cbdata.sc_parent = imp_svc; 7832 cbdata.sc_service = 1; 7833 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7834 cbdata.sc_general = NULL; 7835 7836 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7837 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7838 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7839 bad_error("uu_list_walk", uu_error()); 7840 7841 lcbdata->sc_err = cbdata.sc_err; 7842 if (cbdata.sc_err == ECONNABORTED) 7843 goto connaborted; 7844 r = UU_WALK_ERROR; 7845 goto deltemp; 7846 } 7847 7848 s->sc_import_state = IMPORT_COMPLETE; 7849 r = UU_WALK_NEXT; 7850 7851 deltemp: 7852 /* delete temporary service */ 7853 if (scf_service_delete(imp_tsvc) != 0) { 7854 switch (scf_error()) { 7855 case SCF_ERROR_DELETED: 7856 break; 7857 7858 case SCF_ERROR_CONNECTION_BROKEN: 7859 goto connaborted; 7860 7861 case SCF_ERROR_EXISTS: 7862 warn(gettext( 7863 "Could not delete svc:/%s (instances exist).\n"), 7864 imp_tsname); 7865 break; 7866 7867 case SCF_ERROR_NOT_SET: 7868 case SCF_ERROR_NOT_BOUND: 7869 default: 7870 bad_error("scf_service_delete", scf_error()); 7871 } 7872 } 7873 7874 return (r); 7875 7876 connaborted: 7877 warn(gettext("Could not delete svc:/%s " 7878 "(repository connection broken).\n"), imp_tsname); 7879 lcbdata->sc_err = ECONNABORTED; 7880 return (UU_WALK_ERROR); 7881 } 7882 7883 static const char * 7884 import_progress(int st) 7885 { 7886 switch (st) { 7887 case 0: 7888 return (gettext("not reached.")); 7889 7890 case IMPORT_PREVIOUS: 7891 return (gettext("previous snapshot taken.")); 7892 7893 case IMPORT_PROP_BEGUN: 7894 return (gettext("some properties imported.")); 7895 7896 case IMPORT_PROP_DONE: 7897 return (gettext("properties imported.")); 7898 7899 case IMPORT_COMPLETE: 7900 return (gettext("imported.")); 7901 7902 case IMPORT_REFRESHED: 7903 return (gettext("refresh requested.")); 7904 7905 default: 7906 #ifndef NDEBUG 7907 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7908 __FILE__, __LINE__, st); 7909 #endif 7910 abort(); 7911 /* NOTREACHED */ 7912 } 7913 } 7914 7915 /* 7916 * Returns 7917 * 0 - success 7918 * - fmri wasn't found (error printed) 7919 * - entity was deleted (error printed) 7920 * - backend denied access (error printed) 7921 * ENOMEM - out of memory (error printed) 7922 * ECONNABORTED - repository connection broken (error printed) 7923 * EPERM - permission denied (error printed) 7924 * -1 - unknown libscf error (error printed) 7925 */ 7926 static int 7927 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7928 { 7929 scf_error_t serr; 7930 void *ent; 7931 int issvc; 7932 int r; 7933 7934 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7935 const char *dpt_deleted = gettext("Could not refresh %s " 7936 "(dependent \"%s\" of %s) (deleted).\n"); 7937 7938 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7939 switch (serr) { 7940 case SCF_ERROR_NONE: 7941 break; 7942 7943 case SCF_ERROR_NO_MEMORY: 7944 if (name == NULL) 7945 warn(gettext("Could not refresh %s (out of memory).\n"), 7946 fmri); 7947 else 7948 warn(gettext("Could not refresh %s " 7949 "(dependent \"%s\" of %s) (out of memory).\n"), 7950 fmri, name, d_fmri); 7951 return (ENOMEM); 7952 7953 case SCF_ERROR_NOT_FOUND: 7954 if (name == NULL) 7955 warn(deleted, fmri); 7956 else 7957 warn(dpt_deleted, fmri, name, d_fmri); 7958 return (0); 7959 7960 case SCF_ERROR_INVALID_ARGUMENT: 7961 case SCF_ERROR_CONSTRAINT_VIOLATED: 7962 default: 7963 bad_error("fmri_to_entity", serr); 7964 } 7965 7966 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7967 switch (r) { 7968 case 0: 7969 break; 7970 7971 case ECONNABORTED: 7972 if (name != NULL) 7973 warn(gettext("Could not refresh %s " 7974 "(dependent \"%s\" of %s) " 7975 "(repository connection broken).\n"), fmri, name, 7976 d_fmri); 7977 return (r); 7978 7979 case ECANCELED: 7980 if (name == NULL) 7981 warn(deleted, fmri); 7982 else 7983 warn(dpt_deleted, fmri, name, d_fmri); 7984 return (0); 7985 7986 case EACCES: 7987 if (!g_verbose) 7988 return (0); 7989 if (name == NULL) 7990 warn(gettext("Could not refresh %s " 7991 "(backend access denied).\n"), fmri); 7992 else 7993 warn(gettext("Could not refresh %s " 7994 "(dependent \"%s\" of %s) " 7995 "(backend access denied).\n"), fmri, name, d_fmri); 7996 return (0); 7997 7998 case EPERM: 7999 if (name == NULL) 8000 warn(gettext("Could not refresh %s " 8001 "(permission denied).\n"), fmri); 8002 else 8003 warn(gettext("Could not refresh %s " 8004 "(dependent \"%s\" of %s) " 8005 "(permission denied).\n"), fmri, name, d_fmri); 8006 return (r); 8007 8008 case ENOSPC: 8009 if (name == NULL) 8010 warn(gettext("Could not refresh %s " 8011 "(repository server out of resources).\n"), 8012 fmri); 8013 else 8014 warn(gettext("Could not refresh %s " 8015 "(dependent \"%s\" of %s) " 8016 "(repository server out of resources).\n"), 8017 fmri, name, d_fmri); 8018 return (r); 8019 8020 case -1: 8021 scfwarn(); 8022 return (r); 8023 8024 default: 8025 bad_error("refresh_entity", r); 8026 } 8027 8028 if (issvc) 8029 scf_service_destroy(ent); 8030 else 8031 scf_instance_destroy(ent); 8032 8033 return (0); 8034 } 8035 8036 static int 8037 alloc_imp_globals() 8038 { 8039 int r; 8040 8041 const char * const emsg_nomem = gettext("Out of memory.\n"); 8042 const char * const emsg_nores = 8043 gettext("svc.configd is out of resources.\n"); 8044 8045 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 8046 max_scf_name_len : max_scf_fmri_len) + 1; 8047 8048 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 8049 (imp_svc = scf_service_create(g_hndl)) == NULL || 8050 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 8051 (imp_inst = scf_instance_create(g_hndl)) == NULL || 8052 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 8053 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 8054 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 8055 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 8056 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 8057 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8058 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 8059 (imp_pg = scf_pg_create(g_hndl)) == NULL || 8060 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 8061 (imp_prop = scf_property_create(g_hndl)) == NULL || 8062 (imp_iter = scf_iter_create(g_hndl)) == NULL || 8063 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 8064 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 8065 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 8066 (imp_str = malloc(imp_str_sz)) == NULL || 8067 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 8068 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 8069 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 8070 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 8071 (ud_inst = scf_instance_create(g_hndl)) == NULL || 8072 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8073 (ud_pg = scf_pg_create(g_hndl)) == NULL || 8074 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 8075 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 8076 (ud_prop = scf_property_create(g_hndl)) == NULL || 8077 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 8078 (ud_val = scf_value_create(g_hndl)) == NULL || 8079 (ud_iter = scf_iter_create(g_hndl)) == NULL || 8080 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 8081 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 8082 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 8083 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 8084 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 8085 if (scf_error() == SCF_ERROR_NO_RESOURCES) 8086 warn(emsg_nores); 8087 else 8088 warn(emsg_nomem); 8089 8090 return (-1); 8091 } 8092 8093 r = load_init(); 8094 switch (r) { 8095 case 0: 8096 break; 8097 8098 case ENOMEM: 8099 warn(emsg_nomem); 8100 return (-1); 8101 8102 default: 8103 bad_error("load_init", r); 8104 } 8105 8106 return (0); 8107 } 8108 8109 static void 8110 free_imp_globals() 8111 { 8112 pgroup_t *old_dpt; 8113 void *cookie; 8114 8115 load_fini(); 8116 8117 free(ud_ctarg); 8118 free(ud_oldtarg); 8119 free(ud_name); 8120 ud_ctarg = ud_oldtarg = ud_name = NULL; 8121 8122 scf_transaction_destroy(ud_tx); 8123 ud_tx = NULL; 8124 scf_iter_destroy(ud_iter); 8125 scf_iter_destroy(ud_iter2); 8126 ud_iter = ud_iter2 = NULL; 8127 scf_value_destroy(ud_val); 8128 ud_val = NULL; 8129 scf_property_destroy(ud_prop); 8130 scf_property_destroy(ud_dpt_prop); 8131 ud_prop = ud_dpt_prop = NULL; 8132 scf_pg_destroy(ud_pg); 8133 scf_pg_destroy(ud_cur_depts_pg); 8134 scf_pg_destroy(ud_run_dpts_pg); 8135 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 8136 scf_snaplevel_destroy(ud_snpl); 8137 ud_snpl = NULL; 8138 scf_instance_destroy(ud_inst); 8139 ud_inst = NULL; 8140 8141 free(imp_str); 8142 free(imp_tsname); 8143 free(imp_fe1); 8144 free(imp_fe2); 8145 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 8146 8147 cookie = NULL; 8148 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 8149 NULL) { 8150 free((char *)old_dpt->sc_pgroup_name); 8151 free((char *)old_dpt->sc_pgroup_fmri); 8152 internal_pgroup_free(old_dpt); 8153 } 8154 uu_list_destroy(imp_deleted_dpts); 8155 8156 scf_transaction_destroy(imp_tx); 8157 imp_tx = NULL; 8158 scf_iter_destroy(imp_iter); 8159 scf_iter_destroy(imp_rpg_iter); 8160 scf_iter_destroy(imp_up_iter); 8161 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 8162 scf_property_destroy(imp_prop); 8163 imp_prop = NULL; 8164 scf_pg_destroy(imp_pg); 8165 scf_pg_destroy(imp_pg2); 8166 imp_pg = imp_pg2 = NULL; 8167 scf_snaplevel_destroy(imp_snpl); 8168 scf_snaplevel_destroy(imp_rsnpl); 8169 imp_snpl = imp_rsnpl = NULL; 8170 scf_snapshot_destroy(imp_snap); 8171 scf_snapshot_destroy(imp_lisnap); 8172 scf_snapshot_destroy(imp_tlisnap); 8173 scf_snapshot_destroy(imp_rsnap); 8174 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 8175 scf_instance_destroy(imp_inst); 8176 scf_instance_destroy(imp_tinst); 8177 imp_inst = imp_tinst = NULL; 8178 scf_service_destroy(imp_svc); 8179 scf_service_destroy(imp_tsvc); 8180 imp_svc = imp_tsvc = NULL; 8181 scf_scope_destroy(imp_scope); 8182 imp_scope = NULL; 8183 8184 load_fini(); 8185 } 8186 8187 int 8188 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 8189 { 8190 scf_callback_t cbdata; 8191 int result = 0; 8192 entity_t *svc, *inst; 8193 uu_list_t *insts; 8194 int r; 8195 pgroup_t *old_dpt; 8196 int annotation_set = 0; 8197 8198 const char * const emsg_nomem = gettext("Out of memory.\n"); 8199 const char * const emsg_nores = 8200 gettext("svc.configd is out of resources.\n"); 8201 8202 lscf_prep_hndl(); 8203 8204 if (alloc_imp_globals()) 8205 goto out; 8206 8207 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 8208 switch (scf_error()) { 8209 case SCF_ERROR_CONNECTION_BROKEN: 8210 warn(gettext("Repository connection broken.\n")); 8211 repository_teardown(); 8212 result = -1; 8213 goto out; 8214 8215 case SCF_ERROR_NOT_FOUND: 8216 case SCF_ERROR_INVALID_ARGUMENT: 8217 case SCF_ERROR_NOT_BOUND: 8218 case SCF_ERROR_HANDLE_MISMATCH: 8219 default: 8220 bad_error("scf_handle_get_scope", scf_error()); 8221 } 8222 } 8223 8224 /* Set up the auditing annotation. */ 8225 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 8226 annotation_set = 1; 8227 } else { 8228 switch (scf_error()) { 8229 case SCF_ERROR_CONNECTION_BROKEN: 8230 warn(gettext("Repository connection broken.\n")); 8231 repository_teardown(); 8232 result = -1; 8233 goto out; 8234 8235 case SCF_ERROR_INVALID_ARGUMENT: 8236 case SCF_ERROR_NOT_BOUND: 8237 case SCF_ERROR_NO_RESOURCES: 8238 case SCF_ERROR_INTERNAL: 8239 bad_error("_scf_set_annotation", scf_error()); 8240 /* NOTREACHED */ 8241 8242 default: 8243 /* 8244 * Do not terminate import because of inability to 8245 * generate annotation audit event. 8246 */ 8247 warn(gettext("_scf_set_annotation() unexpectedly " 8248 "failed with return code of %d\n"), scf_error()); 8249 break; 8250 } 8251 } 8252 8253 /* 8254 * Clear the sc_import_state's of all services & instances so we can 8255 * report how far we got if we fail. 8256 */ 8257 for (svc = uu_list_first(bndl->sc_bundle_services); 8258 svc != NULL; 8259 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8260 svc->sc_import_state = 0; 8261 8262 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 8263 clear_int, (void *)offsetof(entity_t, sc_import_state), 8264 UU_DEFAULT) != 0) 8265 bad_error("uu_list_walk", uu_error()); 8266 } 8267 8268 cbdata.sc_handle = g_hndl; 8269 cbdata.sc_parent = imp_scope; 8270 cbdata.sc_flags = flags; 8271 cbdata.sc_general = NULL; 8272 8273 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 8274 &cbdata, UU_DEFAULT) == 0) { 8275 char *eptr; 8276 /* Success. Refresh everything. */ 8277 8278 if (flags & SCI_NOREFRESH || no_refresh) { 8279 no_refresh = 0; 8280 result = 0; 8281 goto out; 8282 } 8283 8284 for (svc = uu_list_first(bndl->sc_bundle_services); 8285 svc != NULL; 8286 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8287 pgroup_t *dpt; 8288 8289 insts = svc->sc_u.sc_service.sc_service_instances; 8290 8291 for (inst = uu_list_first(insts); 8292 inst != NULL; 8293 inst = uu_list_next(insts, inst)) { 8294 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 8295 switch (r) { 8296 case 0: 8297 break; 8298 8299 case ENOMEM: 8300 case ECONNABORTED: 8301 case EPERM: 8302 case -1: 8303 goto progress; 8304 8305 default: 8306 bad_error("imp_refresh_fmri", r); 8307 } 8308 8309 inst->sc_import_state = IMPORT_REFRESHED; 8310 8311 for (dpt = uu_list_first(inst->sc_dependents); 8312 dpt != NULL; 8313 dpt = uu_list_next(inst->sc_dependents, 8314 dpt)) 8315 if (imp_refresh_fmri( 8316 dpt->sc_pgroup_fmri, 8317 dpt->sc_pgroup_name, 8318 inst->sc_fmri) != 0) 8319 goto progress; 8320 } 8321 8322 for (dpt = uu_list_first(svc->sc_dependents); 8323 dpt != NULL; 8324 dpt = uu_list_next(svc->sc_dependents, dpt)) 8325 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 8326 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 8327 goto progress; 8328 } 8329 8330 for (old_dpt = uu_list_first(imp_deleted_dpts); 8331 old_dpt != NULL; 8332 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 8333 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8334 old_dpt->sc_pgroup_name, 8335 old_dpt->sc_parent->sc_fmri) != 0) 8336 goto progress; 8337 8338 result = 0; 8339 8340 /* 8341 * This snippet of code assumes that we are running svccfg as we 8342 * normally do -- witih svc.startd running. Of course, that is 8343 * not actually the case all the time because we also use a 8344 * varient of svc.configd and svccfg which are only meant to 8345 * run during the build process. During this time we have no 8346 * svc.startd, so this check would hang the build process. 8347 * 8348 * However, we've also given other consolidations, a bit of a 8349 * means to tie themselves into a knot. They're not properly 8350 * using the native build equivalents, but they've been getting 8351 * away with it anyways. Therefore, if we've found that 8352 * SVCCFG_REPOSITORY is set indicating that a separate configd 8353 * should be spun up, then we have to assume it's not using a 8354 * startd and we should not do this check. 8355 */ 8356 #ifndef NATIVE_BUILD 8357 /* 8358 * Verify that the restarter group is preset 8359 */ 8360 eptr = getenv("SVCCFG_REPOSITORY"); 8361 for (svc = uu_list_first(bndl->sc_bundle_services); 8362 svc != NULL && eptr == NULL; 8363 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8364 8365 insts = svc->sc_u.sc_service.sc_service_instances; 8366 8367 for (inst = uu_list_first(insts); 8368 inst != NULL; 8369 inst = uu_list_next(insts, inst)) { 8370 if (lscf_instance_verify(imp_scope, svc, 8371 inst) != 0) 8372 goto progress; 8373 } 8374 } 8375 #endif 8376 goto out; 8377 8378 } 8379 8380 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8381 bad_error("uu_list_walk", uu_error()); 8382 8383 printerr: 8384 /* If the error hasn't been printed yet, do so here. */ 8385 switch (cbdata.sc_err) { 8386 case ECONNABORTED: 8387 warn(gettext("Repository connection broken.\n")); 8388 break; 8389 8390 case ENOMEM: 8391 warn(emsg_nomem); 8392 break; 8393 8394 case ENOSPC: 8395 warn(emsg_nores); 8396 break; 8397 8398 case EROFS: 8399 warn(gettext("Repository is read-only.\n")); 8400 break; 8401 8402 case EACCES: 8403 warn(gettext("Repository backend denied access.\n")); 8404 break; 8405 8406 case EPERM: 8407 case EINVAL: 8408 case EEXIST: 8409 case EBUSY: 8410 case EBADF: 8411 case -1: 8412 break; 8413 8414 default: 8415 bad_error("lscf_service_import", cbdata.sc_err); 8416 } 8417 8418 progress: 8419 warn(gettext("Import of %s failed. Progress:\n"), filename); 8420 8421 for (svc = uu_list_first(bndl->sc_bundle_services); 8422 svc != NULL; 8423 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8424 insts = svc->sc_u.sc_service.sc_service_instances; 8425 8426 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 8427 import_progress(svc->sc_import_state)); 8428 8429 for (inst = uu_list_first(insts); 8430 inst != NULL; 8431 inst = uu_list_next(insts, inst)) 8432 warn(gettext(" Instance \"%s\": %s\n"), 8433 inst->sc_name, 8434 import_progress(inst->sc_import_state)); 8435 } 8436 8437 if (cbdata.sc_err == ECONNABORTED) 8438 repository_teardown(); 8439 8440 8441 result = -1; 8442 8443 out: 8444 if (annotation_set != 0) { 8445 /* Turn off annotation. It is no longer needed. */ 8446 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8447 } 8448 8449 free_imp_globals(); 8450 8451 return (result); 8452 } 8453 8454 /* 8455 * _lscf_import_err() summarize the error handling returned by 8456 * lscf_import_{instance | service}_pgs 8457 * Return values are: 8458 * IMPORT_NEXT 8459 * IMPORT_OUT 8460 * IMPORT_BAD 8461 */ 8462 8463 #define IMPORT_BAD -1 8464 #define IMPORT_NEXT 0 8465 #define IMPORT_OUT 1 8466 8467 static int 8468 _lscf_import_err(int err, const char *fmri) 8469 { 8470 switch (err) { 8471 case 0: 8472 if (g_verbose) 8473 warn(gettext("%s updated.\n"), fmri); 8474 return (IMPORT_NEXT); 8475 8476 case ECONNABORTED: 8477 warn(gettext("Could not update %s " 8478 "(repository connection broken).\n"), fmri); 8479 return (IMPORT_OUT); 8480 8481 case ENOMEM: 8482 warn(gettext("Could not update %s (out of memory).\n"), fmri); 8483 return (IMPORT_OUT); 8484 8485 case ENOSPC: 8486 warn(gettext("Could not update %s " 8487 "(repository server out of resources).\n"), fmri); 8488 return (IMPORT_OUT); 8489 8490 case ECANCELED: 8491 warn(gettext( 8492 "Could not update %s (deleted).\n"), fmri); 8493 return (IMPORT_NEXT); 8494 8495 case EPERM: 8496 case EINVAL: 8497 case EBUSY: 8498 return (IMPORT_NEXT); 8499 8500 case EROFS: 8501 warn(gettext("Could not update %s (repository read-only).\n"), 8502 fmri); 8503 return (IMPORT_OUT); 8504 8505 case EACCES: 8506 warn(gettext("Could not update %s " 8507 "(backend access denied).\n"), fmri); 8508 return (IMPORT_NEXT); 8509 8510 case EEXIST: 8511 default: 8512 return (IMPORT_BAD); 8513 } 8514 8515 /*NOTREACHED*/ 8516 } 8517 8518 /* 8519 * The global imp_svc and imp_inst should be set by the caller in the 8520 * check to make sure the service and instance exist that the apply is 8521 * working on. 8522 */ 8523 static int 8524 lscf_dependent_apply(void *dpg, void *e) 8525 { 8526 scf_callback_t cb; 8527 pgroup_t *dpt_pgroup = dpg; 8528 pgroup_t *deldpt; 8529 entity_t *ent = e; 8530 int tissvc; 8531 void *sc_ent, *tent; 8532 scf_error_t serr; 8533 int r; 8534 8535 const char * const dependents = "dependents"; 8536 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT); 8537 8538 if (issvc) 8539 sc_ent = imp_svc; 8540 else 8541 sc_ent = imp_inst; 8542 8543 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg, 8544 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 || 8545 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name, 8546 imp_prop) != 0) { 8547 switch (scf_error()) { 8548 case SCF_ERROR_NOT_FOUND: 8549 case SCF_ERROR_DELETED: 8550 break; 8551 8552 case SCF_ERROR_CONNECTION_BROKEN: 8553 case SCF_ERROR_NOT_SET: 8554 case SCF_ERROR_INVALID_ARGUMENT: 8555 case SCF_ERROR_HANDLE_MISMATCH: 8556 case SCF_ERROR_NOT_BOUND: 8557 default: 8558 bad_error("entity_get_pg", scf_error()); 8559 } 8560 } else { 8561 /* 8562 * Found the dependents/<wip dep> so check to 8563 * see if the service is different. If so 8564 * store the service for later refresh, and 8565 * delete the wip dependency from the service 8566 */ 8567 if (scf_property_get_value(imp_prop, ud_val) != 0) { 8568 switch (scf_error()) { 8569 case SCF_ERROR_DELETED: 8570 break; 8571 8572 case SCF_ERROR_CONNECTION_BROKEN: 8573 case SCF_ERROR_NOT_SET: 8574 case SCF_ERROR_INVALID_ARGUMENT: 8575 case SCF_ERROR_HANDLE_MISMATCH: 8576 case SCF_ERROR_NOT_BOUND: 8577 default: 8578 bad_error("scf_property_get_value", 8579 scf_error()); 8580 } 8581 } 8582 8583 if (scf_value_get_as_string(ud_val, ud_oldtarg, 8584 max_scf_value_len + 1) < 0) 8585 bad_error("scf_value_get_as_string", scf_error()); 8586 8587 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 8588 switch (r) { 8589 case 1: 8590 break; 8591 case 0: 8592 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent, 8593 &tissvc)) != SCF_ERROR_NONE) { 8594 if (serr == SCF_ERROR_NOT_FOUND) { 8595 break; 8596 } else { 8597 bad_error("fmri_to_entity", serr); 8598 } 8599 } 8600 8601 if (entity_get_pg(tent, tissvc, 8602 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) { 8603 serr = scf_error(); 8604 if (serr == SCF_ERROR_NOT_FOUND || 8605 serr == SCF_ERROR_DELETED) { 8606 break; 8607 } else { 8608 bad_error("entity_get_pg", scf_error()); 8609 } 8610 } 8611 8612 if (scf_pg_delete(imp_pg) != 0) { 8613 serr = scf_error(); 8614 if (serr == SCF_ERROR_NOT_FOUND || 8615 serr == SCF_ERROR_DELETED) { 8616 break; 8617 } else { 8618 bad_error("scf_pg_delete", scf_error()); 8619 } 8620 } 8621 8622 deldpt = internal_pgroup_new(); 8623 if (deldpt == NULL) 8624 return (ENOMEM); 8625 deldpt->sc_pgroup_name = 8626 strdup(dpt_pgroup->sc_pgroup_name); 8627 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg); 8628 if (deldpt->sc_pgroup_name == NULL || 8629 deldpt->sc_pgroup_fmri == NULL) 8630 return (ENOMEM); 8631 deldpt->sc_parent = (entity_t *)ent; 8632 if (uu_list_insert_after(imp_deleted_dpts, NULL, 8633 deldpt) != 0) 8634 uu_die(gettext("libuutil error: %s\n"), 8635 uu_strerror(uu_error())); 8636 8637 break; 8638 default: 8639 bad_error("fmri_equal", r); 8640 } 8641 } 8642 8643 cb.sc_handle = g_hndl; 8644 cb.sc_parent = ent; 8645 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT; 8646 cb.sc_source_fmri = ent->sc_fmri; 8647 cb.sc_target_fmri = ent->sc_fmri; 8648 cb.sc_trans = NULL; 8649 cb.sc_flags = SCI_FORCE; 8650 8651 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT) 8652 return (UU_WALK_ERROR); 8653 8654 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL); 8655 switch (r) { 8656 case 0: 8657 break; 8658 8659 case ENOMEM: 8660 case ECONNABORTED: 8661 case EPERM: 8662 case -1: 8663 warn(gettext("Unable to refresh \"%s\"\n"), 8664 dpt_pgroup->sc_pgroup_fmri); 8665 return (UU_WALK_ERROR); 8666 8667 default: 8668 bad_error("imp_refresh_fmri", r); 8669 } 8670 8671 return (UU_WALK_NEXT); 8672 } 8673 8674 /* 8675 * Returns 8676 * 0 - success 8677 * -1 - lscf_import_instance_pgs() failed. 8678 */ 8679 int 8680 lscf_bundle_apply(bundle_t *bndl, const char *file) 8681 { 8682 pgroup_t *old_dpt; 8683 entity_t *svc, *inst; 8684 int annotation_set = 0; 8685 int ret = 0; 8686 int r = 0; 8687 8688 lscf_prep_hndl(); 8689 8690 if ((ret = alloc_imp_globals())) 8691 goto out; 8692 8693 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) 8694 scfdie(); 8695 8696 /* 8697 * Set the strings to be used for the security audit annotation 8698 * event. 8699 */ 8700 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 8701 annotation_set = 1; 8702 } else { 8703 switch (scf_error()) { 8704 case SCF_ERROR_CONNECTION_BROKEN: 8705 warn(gettext("Repository connection broken.\n")); 8706 goto out; 8707 8708 case SCF_ERROR_INVALID_ARGUMENT: 8709 case SCF_ERROR_NOT_BOUND: 8710 case SCF_ERROR_NO_RESOURCES: 8711 case SCF_ERROR_INTERNAL: 8712 bad_error("_scf_set_annotation", scf_error()); 8713 /* NOTREACHED */ 8714 8715 default: 8716 /* 8717 * Do not abort apply operation because of 8718 * inability to create annotation audit event. 8719 */ 8720 warn(gettext("_scf_set_annotation() unexpectedly " 8721 "failed with return code of %d\n"), scf_error()); 8722 break; 8723 } 8724 } 8725 8726 for (svc = uu_list_first(bndl->sc_bundle_services); 8727 svc != NULL; 8728 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8729 int refresh = 0; 8730 8731 if (scf_scope_get_service(imp_scope, svc->sc_name, 8732 imp_svc) != 0) { 8733 switch (scf_error()) { 8734 case SCF_ERROR_NOT_FOUND: 8735 if (g_verbose) 8736 warn(gettext("Ignoring nonexistent " 8737 "service %s.\n"), svc->sc_name); 8738 continue; 8739 8740 default: 8741 scfdie(); 8742 } 8743 } 8744 8745 /* 8746 * If there were missing types in the profile, then need to 8747 * attempt to find the types. 8748 */ 8749 if (svc->sc_miss_type) { 8750 if (uu_list_numnodes(svc->sc_pgroups) && 8751 uu_list_walk(svc->sc_pgroups, find_current_pg_type, 8752 svc, UU_DEFAULT) != 0) { 8753 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8754 bad_error("uu_list_walk", uu_error()); 8755 8756 ret = -1; 8757 continue; 8758 } 8759 8760 for (inst = uu_list_first( 8761 svc->sc_u.sc_service.sc_service_instances); 8762 inst != NULL; 8763 inst = uu_list_next( 8764 svc->sc_u.sc_service.sc_service_instances, inst)) { 8765 /* 8766 * If the instance doesn't exist just 8767 * skip to the next instance and let the 8768 * import note the missing instance. 8769 */ 8770 if (scf_service_get_instance(imp_svc, 8771 inst->sc_name, imp_inst) != 0) 8772 continue; 8773 8774 if (uu_list_walk(inst->sc_pgroups, 8775 find_current_pg_type, inst, 8776 UU_DEFAULT) != 0) { 8777 if (uu_error() != 8778 UU_ERROR_CALLBACK_FAILED) 8779 bad_error("uu_list_walk", 8780 uu_error()); 8781 8782 ret = -1; 8783 inst->sc_miss_type = B_TRUE; 8784 } 8785 } 8786 } 8787 8788 /* 8789 * if we have pgs in the profile, we need to refresh ALL 8790 * instances of the service 8791 */ 8792 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 8793 refresh = 1; 8794 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc, 8795 SCI_FORCE | SCI_KEEP); 8796 switch (_lscf_import_err(r, svc->sc_fmri)) { 8797 case IMPORT_NEXT: 8798 break; 8799 8800 case IMPORT_OUT: 8801 goto out; 8802 8803 case IMPORT_BAD: 8804 default: 8805 bad_error("lscf_import_service_pgs", r); 8806 } 8807 } 8808 8809 if (uu_list_numnodes(svc->sc_dependents) != 0) { 8810 uu_list_walk(svc->sc_dependents, 8811 lscf_dependent_apply, svc, UU_DEFAULT); 8812 } 8813 8814 for (inst = uu_list_first( 8815 svc->sc_u.sc_service.sc_service_instances); 8816 inst != NULL; 8817 inst = uu_list_next( 8818 svc->sc_u.sc_service.sc_service_instances, inst)) { 8819 /* 8820 * This instance still has missing types 8821 * so skip it. 8822 */ 8823 if (inst->sc_miss_type) { 8824 if (g_verbose) 8825 warn(gettext("Ignoring instance " 8826 "%s:%s with missing types\n"), 8827 inst->sc_parent->sc_name, 8828 inst->sc_name); 8829 8830 continue; 8831 } 8832 8833 if (scf_service_get_instance(imp_svc, inst->sc_name, 8834 imp_inst) != 0) { 8835 switch (scf_error()) { 8836 case SCF_ERROR_NOT_FOUND: 8837 if (g_verbose) 8838 warn(gettext("Ignoring " 8839 "nonexistant instance " 8840 "%s:%s.\n"), 8841 inst->sc_parent->sc_name, 8842 inst->sc_name); 8843 continue; 8844 8845 default: 8846 scfdie(); 8847 } 8848 } 8849 8850 /* 8851 * If the instance does not have a general/enabled 8852 * property and no last-import snapshot then the 8853 * instance is not a fully installed instance and 8854 * should not have a profile applied to it. 8855 * 8856 * This could happen if a service/instance declares 8857 * a dependent on behalf of another service/instance. 8858 * 8859 */ 8860 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 8861 imp_snap) != 0) { 8862 if (scf_instance_get_pg(imp_inst, 8863 SCF_PG_GENERAL, imp_pg) != 0 || 8864 scf_pg_get_property(imp_pg, 8865 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 8866 if (g_verbose) 8867 warn(gettext("Ignoreing " 8868 "partial instance " 8869 "%s:%s.\n"), 8870 inst->sc_parent->sc_name, 8871 inst->sc_name); 8872 continue; 8873 } 8874 } 8875 8876 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, 8877 inst, SCI_FORCE | SCI_KEEP); 8878 switch (_lscf_import_err(r, inst->sc_fmri)) { 8879 case IMPORT_NEXT: 8880 break; 8881 8882 case IMPORT_OUT: 8883 goto out; 8884 8885 case IMPORT_BAD: 8886 default: 8887 bad_error("lscf_import_instance_pgs", r); 8888 } 8889 8890 if (uu_list_numnodes(inst->sc_dependents) != 0) { 8891 uu_list_walk(inst->sc_dependents, 8892 lscf_dependent_apply, inst, UU_DEFAULT); 8893 } 8894 8895 /* refresh only if there is no pgs in the service */ 8896 if (refresh == 0) 8897 (void) refresh_entity(0, imp_inst, 8898 inst->sc_fmri, NULL, NULL, NULL); 8899 } 8900 8901 if (refresh == 1) { 8902 char *name_buf = safe_malloc(max_scf_name_len + 1); 8903 8904 (void) refresh_entity(1, imp_svc, svc->sc_name, 8905 imp_inst, imp_iter, name_buf); 8906 free(name_buf); 8907 } 8908 8909 for (old_dpt = uu_list_first(imp_deleted_dpts); 8910 old_dpt != NULL; 8911 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) { 8912 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8913 old_dpt->sc_pgroup_name, 8914 old_dpt->sc_parent->sc_fmri) != 0) { 8915 warn(gettext("Unable to refresh \"%s\"\n"), 8916 old_dpt->sc_pgroup_fmri); 8917 } 8918 } 8919 } 8920 8921 out: 8922 if (annotation_set) { 8923 /* Remove security audit annotation strings. */ 8924 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8925 } 8926 8927 free_imp_globals(); 8928 return (ret); 8929 } 8930 8931 8932 /* 8933 * Export. These functions create and output an XML tree of a service 8934 * description from the repository. This is largely the inverse of 8935 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 8936 * 8937 * - We must include any properties which are not represented specifically by 8938 * a service manifest, e.g., properties created by an admin post-import. To 8939 * do so we'll iterate through all properties and deal with each 8940 * apropriately. 8941 * 8942 * - Children of services and instances must must be in the order set by the 8943 * DTD, but we iterate over the properties in undefined order. The elements 8944 * are not easily (or efficiently) sortable by name. Since there's a fixed 8945 * number of classes of them, however, we'll keep the classes separate and 8946 * assemble them in order. 8947 */ 8948 8949 /* 8950 * Convenience function to handle xmlSetProp errors (and type casting). 8951 */ 8952 static void 8953 safe_setprop(xmlNodePtr n, const char *name, const char *val) 8954 { 8955 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 8956 uu_die(gettext("Could not set XML property.\n")); 8957 } 8958 8959 /* 8960 * Convenience function to set an XML attribute to the single value of an 8961 * astring property. If the value happens to be the default, don't set the 8962 * attribute. "dval" should be the default value supplied by the DTD, or 8963 * NULL for no default. 8964 */ 8965 static int 8966 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 8967 const char *name, const char *dval) 8968 { 8969 scf_value_t *val; 8970 ssize_t len; 8971 char *str; 8972 8973 val = scf_value_create(g_hndl); 8974 if (val == NULL) 8975 scfdie(); 8976 8977 if (prop_get_val(prop, val) != 0) { 8978 scf_value_destroy(val); 8979 return (-1); 8980 } 8981 8982 len = scf_value_get_as_string(val, NULL, 0); 8983 if (len < 0) 8984 scfdie(); 8985 8986 str = safe_malloc(len + 1); 8987 8988 if (scf_value_get_as_string(val, str, len + 1) < 0) 8989 scfdie(); 8990 8991 scf_value_destroy(val); 8992 8993 if (dval == NULL || strcmp(str, dval) != 0) 8994 safe_setprop(n, name, str); 8995 8996 free(str); 8997 8998 return (0); 8999 } 9000 9001 /* 9002 * As above, but the attribute is always set. 9003 */ 9004 static int 9005 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 9006 { 9007 return (set_attr_from_prop_default(prop, n, name, NULL)); 9008 } 9009 9010 /* 9011 * Dump the given document onto f, with "'s replaced by ''s. 9012 */ 9013 static int 9014 write_service_bundle(xmlDocPtr doc, FILE *f) 9015 { 9016 xmlChar *mem; 9017 int sz, i; 9018 9019 mem = NULL; 9020 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 9021 9022 if (mem == NULL) { 9023 semerr(gettext("Could not dump XML tree.\n")); 9024 return (-1); 9025 } 9026 9027 /* 9028 * Fortunately libxml produces " instead of ", so we can blindly 9029 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 9030 * ' code?! 9031 */ 9032 for (i = 0; i < sz; ++i) { 9033 char c = (char)mem[i]; 9034 9035 if (c == '"') 9036 (void) fputc('\'', f); 9037 else if (c == '\'') 9038 (void) fwrite("'", sizeof ("'") - 1, 1, f); 9039 else 9040 (void) fputc(c, f); 9041 } 9042 9043 return (0); 9044 } 9045 9046 /* 9047 * Create the DOM elements in elts necessary to (generically) represent prop 9048 * (i.e., a property or propval element). If the name of the property is 9049 * known, it should be passed as name_arg. Otherwise, pass NULL. 9050 */ 9051 static void 9052 export_property(scf_property_t *prop, const char *name_arg, 9053 struct pg_elts *elts, int flags) 9054 { 9055 const char *type; 9056 scf_error_t err = 0; 9057 xmlNodePtr pnode, lnode; 9058 char *lnname; 9059 int ret; 9060 9061 /* name */ 9062 if (name_arg != NULL) { 9063 (void) strcpy(exp_str, name_arg); 9064 } else { 9065 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 9066 scfdie(); 9067 } 9068 9069 /* type */ 9070 type = prop_to_typestr(prop); 9071 if (type == NULL) 9072 uu_die(gettext("Can't export property %s: unknown type.\n"), 9073 exp_str); 9074 9075 /* If we're exporting values, and there's just one, export it here. */ 9076 if (!(flags & SCE_ALL_VALUES)) 9077 goto empty; 9078 9079 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 9080 xmlNodePtr n; 9081 9082 /* Single value, so use propval */ 9083 n = xmlNewNode(NULL, (xmlChar *)"propval"); 9084 if (n == NULL) 9085 uu_die(emsg_create_xml); 9086 9087 safe_setprop(n, name_attr, exp_str); 9088 safe_setprop(n, type_attr, type); 9089 9090 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9091 scfdie(); 9092 safe_setprop(n, value_attr, exp_str); 9093 9094 if (elts->propvals == NULL) 9095 elts->propvals = n; 9096 else 9097 (void) xmlAddSibling(elts->propvals, n); 9098 9099 return; 9100 } 9101 9102 err = scf_error(); 9103 9104 if (err == SCF_ERROR_PERMISSION_DENIED) { 9105 semerr(emsg_permission_denied); 9106 return; 9107 } 9108 9109 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 9110 err != SCF_ERROR_NOT_FOUND && 9111 err != SCF_ERROR_PERMISSION_DENIED) 9112 scfdie(); 9113 9114 empty: 9115 /* Multiple (or no) values, so use property */ 9116 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 9117 if (pnode == NULL) 9118 uu_die(emsg_create_xml); 9119 9120 safe_setprop(pnode, name_attr, exp_str); 9121 safe_setprop(pnode, type_attr, type); 9122 9123 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 9124 lnname = uu_msprintf("%s_list", type); 9125 if (lnname == NULL) 9126 uu_die(gettext("Could not create string")); 9127 9128 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 9129 if (lnode == NULL) 9130 uu_die(emsg_create_xml); 9131 9132 uu_free(lnname); 9133 9134 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 9135 scfdie(); 9136 9137 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 9138 1) { 9139 xmlNodePtr vn; 9140 9141 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 9142 NULL); 9143 if (vn == NULL) 9144 uu_die(emsg_create_xml); 9145 9146 if (scf_value_get_as_string(exp_val, exp_str, 9147 exp_str_sz) < 0) 9148 scfdie(); 9149 safe_setprop(vn, value_attr, exp_str); 9150 } 9151 if (ret != 0) 9152 scfdie(); 9153 } 9154 9155 if (elts->properties == NULL) 9156 elts->properties = pnode; 9157 else 9158 (void) xmlAddSibling(elts->properties, pnode); 9159 } 9160 9161 /* 9162 * Add a property_group element for this property group to elts. 9163 */ 9164 static void 9165 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 9166 { 9167 xmlNodePtr n; 9168 struct pg_elts elts; 9169 int ret; 9170 boolean_t read_protected; 9171 9172 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 9173 9174 /* name */ 9175 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9176 scfdie(); 9177 safe_setprop(n, name_attr, exp_str); 9178 9179 /* type */ 9180 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 9181 scfdie(); 9182 safe_setprop(n, type_attr, exp_str); 9183 9184 /* properties */ 9185 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9186 scfdie(); 9187 9188 (void) memset(&elts, 0, sizeof (elts)); 9189 9190 /* 9191 * If this property group is not read protected, we always want to 9192 * output all the values. Otherwise, we only output the values if the 9193 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 9194 */ 9195 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 9196 scfdie(); 9197 9198 if (!read_protected) 9199 flags |= SCE_ALL_VALUES; 9200 9201 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9202 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9203 scfdie(); 9204 9205 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9206 xmlNodePtr m; 9207 9208 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9209 if (m == NULL) 9210 uu_die(emsg_create_xml); 9211 9212 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9213 elts.stability = m; 9214 continue; 9215 } 9216 9217 xmlFreeNode(m); 9218 } 9219 9220 export_property(exp_prop, NULL, &elts, flags); 9221 } 9222 if (ret == -1) 9223 scfdie(); 9224 9225 (void) xmlAddChild(n, elts.stability); 9226 (void) xmlAddChildList(n, elts.propvals); 9227 (void) xmlAddChildList(n, elts.properties); 9228 9229 if (eelts->property_groups == NULL) 9230 eelts->property_groups = n; 9231 else 9232 (void) xmlAddSibling(eelts->property_groups, n); 9233 } 9234 9235 /* 9236 * Create an XML node representing the dependency described by the given 9237 * property group and put it in eelts. Unless the dependency is not valid, in 9238 * which case create a generic property_group element which represents it and 9239 * put it in eelts. 9240 */ 9241 static void 9242 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 9243 { 9244 xmlNodePtr n; 9245 int err = 0, ret; 9246 struct pg_elts elts; 9247 9248 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 9249 if (n == NULL) 9250 uu_die(emsg_create_xml); 9251 9252 /* 9253 * If the external flag is present, skip this dependency because it 9254 * should have been created by another manifest. 9255 */ 9256 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 9257 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9258 prop_get_val(exp_prop, exp_val) == 0) { 9259 uint8_t b; 9260 9261 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 9262 scfdie(); 9263 9264 if (b) 9265 return; 9266 } 9267 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 9268 scfdie(); 9269 9270 /* Get the required attributes. */ 9271 9272 /* name */ 9273 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9274 scfdie(); 9275 safe_setprop(n, name_attr, exp_str); 9276 9277 /* grouping */ 9278 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9279 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9280 err = 1; 9281 9282 /* restart_on */ 9283 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9284 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9285 err = 1; 9286 9287 /* type */ 9288 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9289 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9290 err = 1; 9291 9292 /* 9293 * entities: Not required, but if we create no children, it will be 9294 * created as empty on import, so fail if it's missing. 9295 */ 9296 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9297 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 9298 scf_iter_t *eiter; 9299 int ret2; 9300 9301 eiter = scf_iter_create(g_hndl); 9302 if (eiter == NULL) 9303 scfdie(); 9304 9305 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 9306 scfdie(); 9307 9308 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 9309 xmlNodePtr ch; 9310 9311 if (scf_value_get_astring(exp_val, exp_str, 9312 exp_str_sz) < 0) 9313 scfdie(); 9314 9315 /* 9316 * service_fmri's must be first, so we can add them 9317 * here. 9318 */ 9319 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 9320 NULL); 9321 if (ch == NULL) 9322 uu_die(emsg_create_xml); 9323 9324 safe_setprop(ch, value_attr, exp_str); 9325 } 9326 if (ret2 == -1) 9327 scfdie(); 9328 9329 scf_iter_destroy(eiter); 9330 } else 9331 err = 1; 9332 9333 if (err) { 9334 xmlFreeNode(n); 9335 9336 export_pg(pg, eelts, SCE_ALL_VALUES); 9337 9338 return; 9339 } 9340 9341 /* Iterate through the properties & handle each. */ 9342 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9343 scfdie(); 9344 9345 (void) memset(&elts, 0, sizeof (elts)); 9346 9347 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9348 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9349 scfdie(); 9350 9351 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9352 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9353 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9354 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9355 continue; 9356 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9357 xmlNodePtr m; 9358 9359 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9360 if (m == NULL) 9361 uu_die(emsg_create_xml); 9362 9363 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9364 elts.stability = m; 9365 continue; 9366 } 9367 9368 xmlFreeNode(m); 9369 } 9370 9371 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9372 } 9373 if (ret == -1) 9374 scfdie(); 9375 9376 (void) xmlAddChild(n, elts.stability); 9377 (void) xmlAddChildList(n, elts.propvals); 9378 (void) xmlAddChildList(n, elts.properties); 9379 9380 if (eelts->dependencies == NULL) 9381 eelts->dependencies = n; 9382 else 9383 (void) xmlAddSibling(eelts->dependencies, n); 9384 } 9385 9386 static xmlNodePtr 9387 export_method_environment(scf_propertygroup_t *pg) 9388 { 9389 xmlNodePtr env; 9390 int ret; 9391 int children = 0; 9392 9393 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 9394 return (NULL); 9395 9396 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 9397 if (env == NULL) 9398 uu_die(emsg_create_xml); 9399 9400 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 9401 scfdie(); 9402 9403 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 9404 scfdie(); 9405 9406 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 9407 xmlNodePtr ev; 9408 char *cp; 9409 9410 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9411 scfdie(); 9412 9413 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 9414 warn(gettext("Invalid environment variable \"%s\".\n"), 9415 exp_str); 9416 continue; 9417 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 9418 warn(gettext("Invalid environment variable \"%s\"; " 9419 "\"SMF_\" prefix is reserved.\n"), exp_str); 9420 continue; 9421 } 9422 9423 *cp = '\0'; 9424 cp++; 9425 9426 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 9427 if (ev == NULL) 9428 uu_die(emsg_create_xml); 9429 9430 safe_setprop(ev, name_attr, exp_str); 9431 safe_setprop(ev, value_attr, cp); 9432 children++; 9433 } 9434 9435 if (ret != 0) 9436 scfdie(); 9437 9438 if (children == 0) { 9439 xmlFreeNode(env); 9440 return (NULL); 9441 } 9442 9443 return (env); 9444 } 9445 9446 /* 9447 * As above, but for a method property group. 9448 */ 9449 static void 9450 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 9451 { 9452 xmlNodePtr n, env; 9453 char *str; 9454 int err = 0, nonenv, ret; 9455 uint8_t use_profile; 9456 struct pg_elts elts; 9457 xmlNodePtr ctxt = NULL; 9458 9459 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 9460 9461 /* Get the required attributes. */ 9462 9463 /* name */ 9464 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9465 scfdie(); 9466 safe_setprop(n, name_attr, exp_str); 9467 9468 /* type */ 9469 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9470 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9471 err = 1; 9472 9473 /* exec */ 9474 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 9475 set_attr_from_prop(exp_prop, n, "exec") != 0) 9476 err = 1; 9477 9478 /* timeout */ 9479 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 9480 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 9481 prop_get_val(exp_prop, exp_val) == 0) { 9482 uint64_t c; 9483 9484 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 9485 scfdie(); 9486 9487 str = uu_msprintf("%llu", c); 9488 if (str == NULL) 9489 uu_die(gettext("Could not create string")); 9490 9491 safe_setprop(n, "timeout_seconds", str); 9492 free(str); 9493 } else 9494 err = 1; 9495 9496 if (err) { 9497 xmlFreeNode(n); 9498 9499 export_pg(pg, eelts, SCE_ALL_VALUES); 9500 9501 return; 9502 } 9503 9504 9505 /* 9506 * If we're going to have a method_context child, we need to know 9507 * before we iterate through the properties. Since method_context's 9508 * are optional, we don't want to complain about any properties 9509 * missing if none of them are there. Thus we can't use the 9510 * convenience functions. 9511 */ 9512 nonenv = 9513 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 9514 SCF_SUCCESS || 9515 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 9516 SCF_SUCCESS || 9517 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 9518 SCF_SUCCESS || 9519 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) == 9520 SCF_SUCCESS || 9521 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 9522 SCF_SUCCESS; 9523 9524 if (nonenv) { 9525 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9526 if (ctxt == NULL) 9527 uu_die(emsg_create_xml); 9528 9529 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 9530 0 && 9531 set_attr_from_prop_default(exp_prop, ctxt, 9532 "working_directory", ":default") != 0) 9533 err = 1; 9534 9535 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 9536 set_attr_from_prop_default(exp_prop, ctxt, "project", 9537 ":default") != 0) 9538 err = 1; 9539 9540 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 9541 0 && 9542 set_attr_from_prop_default(exp_prop, ctxt, 9543 "resource_pool", ":default") != 0) 9544 err = 1; 9545 9546 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 && 9547 set_attr_from_prop_default(exp_prop, ctxt, 9548 "security_flags", ":default") != 0) 9549 err = 1; 9550 9551 /* 9552 * We only want to complain about profile or credential 9553 * properties if we will use them. To determine that we must 9554 * examine USE_PROFILE. 9555 */ 9556 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9557 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9558 prop_get_val(exp_prop, exp_val) == 0) { 9559 if (scf_value_get_boolean(exp_val, &use_profile) != 9560 SCF_SUCCESS) { 9561 scfdie(); 9562 } 9563 9564 if (use_profile) { 9565 xmlNodePtr prof; 9566 9567 prof = xmlNewChild(ctxt, NULL, 9568 (xmlChar *)"method_profile", NULL); 9569 if (prof == NULL) 9570 uu_die(emsg_create_xml); 9571 9572 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 9573 exp_prop) != 0 || 9574 set_attr_from_prop(exp_prop, prof, 9575 name_attr) != 0) 9576 err = 1; 9577 } else { 9578 xmlNodePtr cred; 9579 9580 cred = xmlNewChild(ctxt, NULL, 9581 (xmlChar *)"method_credential", NULL); 9582 if (cred == NULL) 9583 uu_die(emsg_create_xml); 9584 9585 if (pg_get_prop(pg, SCF_PROPERTY_USER, 9586 exp_prop) != 0 || 9587 set_attr_from_prop(exp_prop, cred, 9588 "user") != 0) { 9589 err = 1; 9590 } 9591 9592 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 9593 exp_prop) == 0 && 9594 set_attr_from_prop_default(exp_prop, cred, 9595 "group", ":default") != 0) 9596 err = 1; 9597 9598 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 9599 exp_prop) == 0 && 9600 set_attr_from_prop_default(exp_prop, cred, 9601 "supp_groups", ":default") != 0) 9602 err = 1; 9603 9604 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 9605 exp_prop) == 0 && 9606 set_attr_from_prop_default(exp_prop, cred, 9607 "privileges", ":default") != 0) 9608 err = 1; 9609 9610 if (pg_get_prop(pg, 9611 SCF_PROPERTY_LIMIT_PRIVILEGES, 9612 exp_prop) == 0 && 9613 set_attr_from_prop_default(exp_prop, cred, 9614 "limit_privileges", ":default") != 0) 9615 err = 1; 9616 } 9617 } 9618 } 9619 9620 if ((env = export_method_environment(pg)) != NULL) { 9621 if (ctxt == NULL) { 9622 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9623 if (ctxt == NULL) 9624 uu_die(emsg_create_xml); 9625 } 9626 (void) xmlAddChild(ctxt, env); 9627 } 9628 9629 if (env != NULL || (nonenv && err == 0)) 9630 (void) xmlAddChild(n, ctxt); 9631 else 9632 xmlFreeNode(ctxt); 9633 9634 nonenv = (err == 0); 9635 9636 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9637 scfdie(); 9638 9639 (void) memset(&elts, 0, sizeof (elts)); 9640 9641 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9642 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9643 scfdie(); 9644 9645 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9646 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 9647 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 9648 continue; 9649 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9650 xmlNodePtr m; 9651 9652 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9653 if (m == NULL) 9654 uu_die(emsg_create_xml); 9655 9656 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9657 elts.stability = m; 9658 continue; 9659 } 9660 9661 xmlFreeNode(m); 9662 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 9663 0 || 9664 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 9665 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 9666 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9667 if (nonenv) 9668 continue; 9669 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 9670 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 9671 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 9672 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 9673 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 || 9674 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9675 if (nonenv && !use_profile) 9676 continue; 9677 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9678 if (nonenv && use_profile) 9679 continue; 9680 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 9681 if (env != NULL) 9682 continue; 9683 } 9684 9685 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9686 } 9687 if (ret == -1) 9688 scfdie(); 9689 9690 (void) xmlAddChild(n, elts.stability); 9691 (void) xmlAddChildList(n, elts.propvals); 9692 (void) xmlAddChildList(n, elts.properties); 9693 9694 if (eelts->exec_methods == NULL) 9695 eelts->exec_methods = n; 9696 else 9697 (void) xmlAddSibling(eelts->exec_methods, n); 9698 } 9699 9700 static void 9701 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 9702 struct entity_elts *eelts) 9703 { 9704 xmlNodePtr pgnode; 9705 9706 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 9707 if (pgnode == NULL) 9708 uu_die(emsg_create_xml); 9709 9710 safe_setprop(pgnode, name_attr, name); 9711 safe_setprop(pgnode, type_attr, type); 9712 9713 (void) xmlAddChildList(pgnode, elts->propvals); 9714 (void) xmlAddChildList(pgnode, elts->properties); 9715 9716 if (eelts->property_groups == NULL) 9717 eelts->property_groups = pgnode; 9718 else 9719 (void) xmlAddSibling(eelts->property_groups, pgnode); 9720 } 9721 9722 /* 9723 * Process the general property group for a service. This is the one with the 9724 * goodies. 9725 */ 9726 static void 9727 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 9728 { 9729 struct pg_elts elts; 9730 int ret; 9731 9732 /* 9733 * In case there are properties which don't correspond to child 9734 * entities of the service entity, we'll set up a pg_elts structure to 9735 * put them in. 9736 */ 9737 (void) memset(&elts, 0, sizeof (elts)); 9738 9739 /* Walk the properties, looking for special ones. */ 9740 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9741 scfdie(); 9742 9743 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9744 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9745 scfdie(); 9746 9747 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 9748 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9749 prop_get_val(exp_prop, exp_val) == 0) { 9750 uint8_t b; 9751 9752 if (scf_value_get_boolean(exp_val, &b) != 9753 SCF_SUCCESS) 9754 scfdie(); 9755 9756 if (b) { 9757 selts->single_instance = 9758 xmlNewNode(NULL, 9759 (xmlChar *)"single_instance"); 9760 if (selts->single_instance == NULL) 9761 uu_die(emsg_create_xml); 9762 } 9763 9764 continue; 9765 } 9766 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9767 xmlNodePtr rnode, sfnode; 9768 9769 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9770 if (rnode == NULL) 9771 uu_die(emsg_create_xml); 9772 9773 sfnode = xmlNewChild(rnode, NULL, 9774 (xmlChar *)"service_fmri", NULL); 9775 if (sfnode == NULL) 9776 uu_die(emsg_create_xml); 9777 9778 if (set_attr_from_prop(exp_prop, sfnode, 9779 value_attr) == 0) { 9780 selts->restarter = rnode; 9781 continue; 9782 } 9783 9784 xmlFreeNode(rnode); 9785 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 9786 0) { 9787 xmlNodePtr s; 9788 9789 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9790 if (s == NULL) 9791 uu_die(emsg_create_xml); 9792 9793 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9794 selts->stability = s; 9795 continue; 9796 } 9797 9798 xmlFreeNode(s); 9799 } 9800 9801 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9802 } 9803 if (ret == -1) 9804 scfdie(); 9805 9806 if (elts.propvals != NULL || elts.properties != NULL) 9807 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 9808 selts); 9809 } 9810 9811 static void 9812 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 9813 { 9814 xmlNodePtr n, prof, cred, env; 9815 uint8_t use_profile; 9816 int ret, err = 0; 9817 9818 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 9819 9820 env = export_method_environment(pg); 9821 9822 /* Need to know whether we'll use a profile or not. */ 9823 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9824 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9825 prop_get_val(exp_prop, exp_val) == 0) { 9826 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 9827 scfdie(); 9828 9829 if (use_profile) 9830 prof = 9831 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 9832 NULL); 9833 else 9834 cred = 9835 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 9836 NULL); 9837 } 9838 9839 if (env != NULL) 9840 (void) xmlAddChild(n, env); 9841 9842 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9843 scfdie(); 9844 9845 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9846 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9847 scfdie(); 9848 9849 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 9850 if (set_attr_from_prop(exp_prop, n, 9851 "working_directory") != 0) 9852 err = 1; 9853 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 9854 if (set_attr_from_prop(exp_prop, n, "project") != 0) 9855 err = 1; 9856 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 9857 if (set_attr_from_prop(exp_prop, n, 9858 "resource_pool") != 0) 9859 err = 1; 9860 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9861 if (set_attr_from_prop(exp_prop, n, 9862 "security_flags") != 0) 9863 err = 1; 9864 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9865 /* EMPTY */ 9866 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 9867 if (use_profile || 9868 set_attr_from_prop(exp_prop, cred, "user") != 0) 9869 err = 1; 9870 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 9871 if (use_profile || 9872 set_attr_from_prop(exp_prop, cred, "group") != 0) 9873 err = 1; 9874 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 9875 if (use_profile || set_attr_from_prop(exp_prop, cred, 9876 "supp_groups") != 0) 9877 err = 1; 9878 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 9879 if (use_profile || set_attr_from_prop(exp_prop, cred, 9880 "privileges") != 0) 9881 err = 1; 9882 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 9883 0) { 9884 if (use_profile || set_attr_from_prop(exp_prop, cred, 9885 "limit_privileges") != 0) 9886 err = 1; 9887 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9888 if (!use_profile || set_attr_from_prop(exp_prop, 9889 prof, name_attr) != 0) 9890 err = 1; 9891 } else { 9892 /* Can't have generic properties in method_context's */ 9893 err = 1; 9894 } 9895 } 9896 if (ret == -1) 9897 scfdie(); 9898 9899 if (err && env == NULL) { 9900 xmlFreeNode(n); 9901 export_pg(pg, elts, SCE_ALL_VALUES); 9902 return; 9903 } 9904 9905 elts->method_context = n; 9906 } 9907 9908 /* 9909 * Given a dependency property group in the tfmri entity (target fmri), return 9910 * a dependent element which represents it. 9911 */ 9912 static xmlNodePtr 9913 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 9914 { 9915 uint8_t b; 9916 xmlNodePtr n, sf; 9917 int err = 0, ret; 9918 struct pg_elts pgelts; 9919 9920 /* 9921 * If external isn't set to true then exporting the service will 9922 * export this as a normal dependency, so we should stop to avoid 9923 * duplication. 9924 */ 9925 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 9926 scf_property_get_value(exp_prop, exp_val) != 0 || 9927 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 9928 if (g_verbose) { 9929 warn(gettext("Dependent \"%s\" cannot be exported " 9930 "properly because the \"%s\" property of the " 9931 "\"%s\" dependency of %s is not set to true.\n"), 9932 name, scf_property_external, name, tfmri); 9933 } 9934 9935 return (NULL); 9936 } 9937 9938 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 9939 if (n == NULL) 9940 uu_die(emsg_create_xml); 9941 9942 safe_setprop(n, name_attr, name); 9943 9944 /* Get the required attributes */ 9945 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9946 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9947 err = 1; 9948 9949 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9950 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9951 err = 1; 9952 9953 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9954 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 9955 prop_get_val(exp_prop, exp_val) == 0) { 9956 /* EMPTY */ 9957 } else 9958 err = 1; 9959 9960 if (err) { 9961 xmlFreeNode(n); 9962 return (NULL); 9963 } 9964 9965 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 9966 if (sf == NULL) 9967 uu_die(emsg_create_xml); 9968 9969 safe_setprop(sf, value_attr, tfmri); 9970 9971 /* 9972 * Now add elements for the other properties. 9973 */ 9974 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9975 scfdie(); 9976 9977 (void) memset(&pgelts, 0, sizeof (pgelts)); 9978 9979 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9980 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9981 scfdie(); 9982 9983 if (strcmp(exp_str, scf_property_external) == 0 || 9984 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9985 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9986 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9987 continue; 9988 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 9989 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 9990 prop_get_val(exp_prop, exp_val) == 0) { 9991 char type[sizeof ("service") + 1]; 9992 9993 if (scf_value_get_astring(exp_val, type, 9994 sizeof (type)) < 0) 9995 scfdie(); 9996 9997 if (strcmp(type, "service") == 0) 9998 continue; 9999 } 10000 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 10001 xmlNodePtr s; 10002 10003 s = xmlNewNode(NULL, (xmlChar *)"stability"); 10004 if (s == NULL) 10005 uu_die(emsg_create_xml); 10006 10007 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 10008 pgelts.stability = s; 10009 continue; 10010 } 10011 10012 xmlFreeNode(s); 10013 } 10014 10015 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10016 } 10017 if (ret == -1) 10018 scfdie(); 10019 10020 (void) xmlAddChild(n, pgelts.stability); 10021 (void) xmlAddChildList(n, pgelts.propvals); 10022 (void) xmlAddChildList(n, pgelts.properties); 10023 10024 return (n); 10025 } 10026 10027 static void 10028 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 10029 { 10030 scf_propertygroup_t *opg; 10031 scf_iter_t *iter; 10032 char *type, *fmri; 10033 int ret; 10034 struct pg_elts pgelts; 10035 xmlNodePtr n; 10036 scf_error_t serr; 10037 10038 if ((opg = scf_pg_create(g_hndl)) == NULL || 10039 (iter = scf_iter_create(g_hndl)) == NULL) 10040 scfdie(); 10041 10042 /* Can't use exp_prop_iter due to export_dependent(). */ 10043 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10044 scfdie(); 10045 10046 type = safe_malloc(max_scf_pg_type_len + 1); 10047 10048 /* Get an extra byte so we can tell if values are too long. */ 10049 fmri = safe_malloc(max_scf_fmri_len + 2); 10050 10051 (void) memset(&pgelts, 0, sizeof (pgelts)); 10052 10053 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 10054 void *entity; 10055 int isservice; 10056 scf_type_t ty; 10057 10058 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 10059 scfdie(); 10060 10061 if ((ty != SCF_TYPE_ASTRING && 10062 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 10063 prop_get_val(exp_prop, exp_val) != 0) { 10064 export_property(exp_prop, NULL, &pgelts, 10065 SCE_ALL_VALUES); 10066 continue; 10067 } 10068 10069 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10070 scfdie(); 10071 10072 if (scf_value_get_astring(exp_val, fmri, 10073 max_scf_fmri_len + 2) < 0) 10074 scfdie(); 10075 10076 /* Look for a dependency group in the target fmri. */ 10077 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10078 switch (serr) { 10079 case SCF_ERROR_NONE: 10080 break; 10081 10082 case SCF_ERROR_NO_MEMORY: 10083 uu_die(gettext("Out of memory.\n")); 10084 /* NOTREACHED */ 10085 10086 case SCF_ERROR_INVALID_ARGUMENT: 10087 if (g_verbose) { 10088 if (scf_property_to_fmri(exp_prop, fmri, 10089 max_scf_fmri_len + 2) < 0) 10090 scfdie(); 10091 10092 warn(gettext("The value of %s is not a valid " 10093 "FMRI.\n"), fmri); 10094 } 10095 10096 export_property(exp_prop, exp_str, &pgelts, 10097 SCE_ALL_VALUES); 10098 continue; 10099 10100 case SCF_ERROR_CONSTRAINT_VIOLATED: 10101 if (g_verbose) { 10102 if (scf_property_to_fmri(exp_prop, fmri, 10103 max_scf_fmri_len + 2) < 0) 10104 scfdie(); 10105 10106 warn(gettext("The value of %s does not specify " 10107 "a service or an instance.\n"), fmri); 10108 } 10109 10110 export_property(exp_prop, exp_str, &pgelts, 10111 SCE_ALL_VALUES); 10112 continue; 10113 10114 case SCF_ERROR_NOT_FOUND: 10115 if (g_verbose) { 10116 if (scf_property_to_fmri(exp_prop, fmri, 10117 max_scf_fmri_len + 2) < 0) 10118 scfdie(); 10119 10120 warn(gettext("The entity specified by %s does " 10121 "not exist.\n"), fmri); 10122 } 10123 10124 export_property(exp_prop, exp_str, &pgelts, 10125 SCE_ALL_VALUES); 10126 continue; 10127 10128 default: 10129 #ifndef NDEBUG 10130 (void) fprintf(stderr, "%s:%d: %s() failed with " 10131 "unexpected error %d.\n", __FILE__, __LINE__, 10132 "fmri_to_entity", serr); 10133 #endif 10134 abort(); 10135 } 10136 10137 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 10138 if (scf_error() != SCF_ERROR_NOT_FOUND) 10139 scfdie(); 10140 10141 warn(gettext("Entity %s is missing dependency property " 10142 "group %s.\n"), fmri, exp_str); 10143 10144 export_property(exp_prop, NULL, &pgelts, 10145 SCE_ALL_VALUES); 10146 continue; 10147 } 10148 10149 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 10150 scfdie(); 10151 10152 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 10153 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 10154 scfdie(); 10155 10156 warn(gettext("Property group %s is not of " 10157 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 10158 10159 export_property(exp_prop, NULL, &pgelts, 10160 SCE_ALL_VALUES); 10161 continue; 10162 } 10163 10164 n = export_dependent(opg, exp_str, fmri); 10165 if (n == NULL) { 10166 export_property(exp_prop, exp_str, &pgelts, 10167 SCE_ALL_VALUES); 10168 } else { 10169 if (eelts->dependents == NULL) 10170 eelts->dependents = n; 10171 else 10172 (void) xmlAddSibling(eelts->dependents, 10173 n); 10174 } 10175 } 10176 if (ret == -1) 10177 scfdie(); 10178 10179 free(fmri); 10180 free(type); 10181 10182 scf_iter_destroy(iter); 10183 scf_pg_destroy(opg); 10184 10185 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10186 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 10187 eelts); 10188 } 10189 10190 static void 10191 make_node(xmlNodePtr *nodep, const char *name) 10192 { 10193 if (*nodep == NULL) { 10194 *nodep = xmlNewNode(NULL, (xmlChar *)name); 10195 if (*nodep == NULL) 10196 uu_die(emsg_create_xml); 10197 } 10198 } 10199 10200 static xmlNodePtr 10201 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 10202 { 10203 int ret; 10204 xmlNodePtr parent = NULL; 10205 xmlNodePtr loctext = NULL; 10206 10207 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10208 scfdie(); 10209 10210 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10211 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 10212 prop_get_val(exp_prop, exp_val) != 0) 10213 continue; 10214 10215 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 10216 scfdie(); 10217 10218 make_node(&parent, parname); 10219 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 10220 (xmlChar *)exp_str); 10221 if (loctext == NULL) 10222 uu_die(emsg_create_xml); 10223 10224 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10225 scfdie(); 10226 10227 safe_setprop(loctext, "xml:lang", exp_str); 10228 } 10229 10230 if (ret == -1) 10231 scfdie(); 10232 10233 return (parent); 10234 } 10235 10236 static xmlNodePtr 10237 export_tm_manpage(scf_propertygroup_t *pg) 10238 { 10239 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 10240 if (manpage == NULL) 10241 uu_die(emsg_create_xml); 10242 10243 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 10244 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 10245 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 10246 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 10247 xmlFreeNode(manpage); 10248 return (NULL); 10249 } 10250 10251 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 10252 (void) set_attr_from_prop_default(exp_prop, 10253 manpage, "manpath", ":default"); 10254 10255 return (manpage); 10256 } 10257 10258 static xmlNodePtr 10259 export_tm_doc_link(scf_propertygroup_t *pg) 10260 { 10261 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 10262 if (doc_link == NULL) 10263 uu_die(emsg_create_xml); 10264 10265 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 10266 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 10267 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 10268 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 10269 xmlFreeNode(doc_link); 10270 return (NULL); 10271 } 10272 return (doc_link); 10273 } 10274 10275 /* 10276 * Process template information for a service or instances. 10277 */ 10278 static void 10279 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 10280 struct template_elts *telts) 10281 { 10282 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 10283 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 10284 xmlNodePtr child = NULL; 10285 10286 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 10287 scfdie(); 10288 10289 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 10290 telts->common_name = export_tm_loctext(pg, "common_name"); 10291 if (telts->common_name == NULL) 10292 export_pg(pg, elts, SCE_ALL_VALUES); 10293 return; 10294 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 10295 telts->description = export_tm_loctext(pg, "description"); 10296 if (telts->description == NULL) 10297 export_pg(pg, elts, SCE_ALL_VALUES); 10298 return; 10299 } 10300 10301 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 10302 child = export_tm_manpage(pg); 10303 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 10304 child = export_tm_doc_link(pg); 10305 } 10306 10307 if (child != NULL) { 10308 make_node(&telts->documentation, "documentation"); 10309 (void) xmlAddChild(telts->documentation, child); 10310 } else { 10311 export_pg(pg, elts, SCE_ALL_VALUES); 10312 } 10313 } 10314 10315 /* 10316 * Process parameter and paramval elements 10317 */ 10318 static void 10319 export_parameter(scf_property_t *prop, const char *name, 10320 struct params_elts *elts) 10321 { 10322 xmlNodePtr param; 10323 scf_error_t err = 0; 10324 int ret; 10325 10326 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 10327 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL) 10328 uu_die(emsg_create_xml); 10329 10330 safe_setprop(param, name_attr, name); 10331 10332 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 10333 scfdie(); 10334 safe_setprop(param, value_attr, exp_str); 10335 10336 if (elts->paramval == NULL) 10337 elts->paramval = param; 10338 else 10339 (void) xmlAddSibling(elts->paramval, param); 10340 10341 return; 10342 } 10343 10344 err = scf_error(); 10345 10346 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 10347 err != SCF_ERROR_NOT_FOUND) 10348 scfdie(); 10349 10350 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL) 10351 uu_die(emsg_create_xml); 10352 10353 safe_setprop(param, name_attr, name); 10354 10355 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 10356 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 10357 scfdie(); 10358 10359 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 10360 1) { 10361 xmlNodePtr vn; 10362 10363 if ((vn = xmlNewChild(param, NULL, 10364 (xmlChar *)"value_node", NULL)) == NULL) 10365 uu_die(emsg_create_xml); 10366 10367 if (scf_value_get_as_string(exp_val, exp_str, 10368 exp_str_sz) < 0) 10369 scfdie(); 10370 10371 safe_setprop(vn, value_attr, exp_str); 10372 } 10373 if (ret != 0) 10374 scfdie(); 10375 } 10376 10377 if (elts->parameter == NULL) 10378 elts->parameter = param; 10379 else 10380 (void) xmlAddSibling(elts->parameter, param); 10381 } 10382 10383 /* 10384 * Process notification parameters for a service or instance 10385 */ 10386 static void 10387 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts) 10388 { 10389 xmlNodePtr n, event, *type; 10390 struct params_elts *eelts; 10391 int ret, err, i; 10392 10393 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters"); 10394 event = xmlNewNode(NULL, (xmlChar *)"event"); 10395 if (n == NULL || event == NULL) 10396 uu_die(emsg_create_xml); 10397 10398 /* event value */ 10399 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 10400 scfdie(); 10401 safe_setprop(event, value_attr, exp_str); 10402 10403 (void) xmlAddChild(n, event); 10404 10405 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL || 10406 (eelts = calloc(URI_SCHEME_NUM, 10407 sizeof (struct params_elts))) == NULL) 10408 uu_die(gettext("Out of memory.\n")); 10409 10410 err = 0; 10411 10412 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10413 scfdie(); 10414 10415 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10416 char *t, *p; 10417 10418 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10419 scfdie(); 10420 10421 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) { 10422 /* 10423 * this is not a well formed notification parameters 10424 * element, we should export as regular pg 10425 */ 10426 err = 1; 10427 break; 10428 } 10429 10430 if ((i = check_uri_protocol(t)) < 0) { 10431 err = 1; 10432 break; 10433 } 10434 10435 if (type[i] == NULL) { 10436 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) == 10437 NULL) 10438 uu_die(emsg_create_xml); 10439 10440 safe_setprop(type[i], name_attr, t); 10441 } 10442 if (strcmp(p, active_attr) == 0) { 10443 if (set_attr_from_prop(exp_prop, type[i], 10444 active_attr) != 0) { 10445 err = 1; 10446 break; 10447 } 10448 continue; 10449 } 10450 /* 10451 * We export the parameter 10452 */ 10453 export_parameter(exp_prop, p, &eelts[i]); 10454 } 10455 10456 if (ret == -1) 10457 scfdie(); 10458 10459 if (err == 1) { 10460 for (i = 0; i < URI_SCHEME_NUM; ++i) 10461 xmlFree(type[i]); 10462 free(type); 10463 10464 export_pg(pg, elts, SCE_ALL_VALUES); 10465 10466 return; 10467 } else { 10468 for (i = 0; i < URI_SCHEME_NUM; ++i) 10469 if (type[i] != NULL) { 10470 (void) xmlAddChildList(type[i], 10471 eelts[i].paramval); 10472 (void) xmlAddChildList(type[i], 10473 eelts[i].parameter); 10474 (void) xmlAddSibling(event, type[i]); 10475 } 10476 } 10477 free(type); 10478 10479 if (elts->notify_params == NULL) 10480 elts->notify_params = n; 10481 else 10482 (void) xmlAddSibling(elts->notify_params, n); 10483 } 10484 10485 /* 10486 * Process the general property group for an instance. 10487 */ 10488 static void 10489 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 10490 struct entity_elts *elts) 10491 { 10492 uint8_t enabled; 10493 struct pg_elts pgelts; 10494 int ret; 10495 10496 /* enabled */ 10497 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10498 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10499 prop_get_val(exp_prop, exp_val) == 0) { 10500 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10501 scfdie(); 10502 } else { 10503 enabled = 0; 10504 } 10505 10506 safe_setprop(inode, enabled_attr, enabled ? true : false); 10507 10508 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10509 scfdie(); 10510 10511 (void) memset(&pgelts, 0, sizeof (pgelts)); 10512 10513 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10514 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10515 scfdie(); 10516 10517 if (strcmp(exp_str, scf_property_enabled) == 0) { 10518 continue; 10519 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10520 xmlNodePtr rnode, sfnode; 10521 10522 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10523 if (rnode == NULL) 10524 uu_die(emsg_create_xml); 10525 10526 sfnode = xmlNewChild(rnode, NULL, 10527 (xmlChar *)"service_fmri", NULL); 10528 if (sfnode == NULL) 10529 uu_die(emsg_create_xml); 10530 10531 if (set_attr_from_prop(exp_prop, sfnode, 10532 value_attr) == 0) { 10533 elts->restarter = rnode; 10534 continue; 10535 } 10536 10537 xmlFreeNode(rnode); 10538 } 10539 10540 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10541 } 10542 if (ret == -1) 10543 scfdie(); 10544 10545 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10546 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10547 elts); 10548 } 10549 10550 /* 10551 * Put an instance element for the given instance into selts. 10552 */ 10553 static void 10554 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10555 { 10556 xmlNodePtr n; 10557 boolean_t isdefault; 10558 struct entity_elts elts; 10559 struct template_elts template_elts; 10560 int ret; 10561 10562 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10563 if (n == NULL) 10564 uu_die(emsg_create_xml); 10565 10566 /* name */ 10567 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10568 scfdie(); 10569 safe_setprop(n, name_attr, exp_str); 10570 isdefault = strcmp(exp_str, "default") == 0; 10571 10572 /* check existance of general pg (since general/enabled is required) */ 10573 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10574 if (scf_error() != SCF_ERROR_NOT_FOUND) 10575 scfdie(); 10576 10577 if (g_verbose) { 10578 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10579 scfdie(); 10580 10581 warn(gettext("Instance %s has no general property " 10582 "group; it will be marked disabled.\n"), exp_str); 10583 } 10584 10585 safe_setprop(n, enabled_attr, false); 10586 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10587 strcmp(exp_str, scf_group_framework) != 0) { 10588 if (g_verbose) { 10589 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10590 scfdie(); 10591 10592 warn(gettext("Property group %s is not of type " 10593 "framework; the instance will be marked " 10594 "disabled.\n"), exp_str); 10595 } 10596 10597 safe_setprop(n, enabled_attr, false); 10598 } 10599 10600 /* property groups */ 10601 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10602 scfdie(); 10603 10604 (void) memset(&elts, 0, sizeof (elts)); 10605 (void) memset(&template_elts, 0, sizeof (template_elts)); 10606 10607 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10608 uint32_t pgflags; 10609 10610 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10611 scfdie(); 10612 10613 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10614 continue; 10615 10616 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10617 scfdie(); 10618 10619 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10620 export_dependency(exp_pg, &elts); 10621 continue; 10622 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10623 export_method(exp_pg, &elts); 10624 continue; 10625 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10626 if (scf_pg_get_name(exp_pg, exp_str, 10627 max_scf_name_len + 1) < 0) 10628 scfdie(); 10629 10630 if (strcmp(exp_str, scf_pg_general) == 0) { 10631 export_inst_general(exp_pg, n, &elts); 10632 continue; 10633 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10634 0) { 10635 export_method_context(exp_pg, &elts); 10636 continue; 10637 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10638 export_dependents(exp_pg, &elts); 10639 continue; 10640 } 10641 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10642 export_template(exp_pg, &elts, &template_elts); 10643 continue; 10644 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10645 export_notify_params(exp_pg, &elts); 10646 continue; 10647 } 10648 10649 /* Ordinary pg. */ 10650 export_pg(exp_pg, &elts, flags); 10651 } 10652 if (ret == -1) 10653 scfdie(); 10654 10655 if (template_elts.common_name != NULL) { 10656 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10657 (void) xmlAddChild(elts.template, template_elts.common_name); 10658 (void) xmlAddChild(elts.template, template_elts.description); 10659 (void) xmlAddChild(elts.template, template_elts.documentation); 10660 } else { 10661 xmlFreeNode(template_elts.description); 10662 xmlFreeNode(template_elts.documentation); 10663 } 10664 10665 if (isdefault && elts.restarter == NULL && 10666 elts.dependencies == NULL && elts.method_context == NULL && 10667 elts.exec_methods == NULL && elts.notify_params == NULL && 10668 elts.property_groups == NULL && elts.template == NULL) { 10669 xmlChar *eval; 10670 10671 /* This is a default instance */ 10672 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10673 10674 xmlFreeNode(n); 10675 10676 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10677 if (n == NULL) 10678 uu_die(emsg_create_xml); 10679 10680 safe_setprop(n, enabled_attr, (char *)eval); 10681 xmlFree(eval); 10682 10683 selts->create_default_instance = n; 10684 } else { 10685 /* Assemble the children in order. */ 10686 (void) xmlAddChild(n, elts.restarter); 10687 (void) xmlAddChildList(n, elts.dependencies); 10688 (void) xmlAddChildList(n, elts.dependents); 10689 (void) xmlAddChild(n, elts.method_context); 10690 (void) xmlAddChildList(n, elts.exec_methods); 10691 (void) xmlAddChildList(n, elts.notify_params); 10692 (void) xmlAddChildList(n, elts.property_groups); 10693 (void) xmlAddChild(n, elts.template); 10694 10695 if (selts->instances == NULL) 10696 selts->instances = n; 10697 else 10698 (void) xmlAddSibling(selts->instances, n); 10699 } 10700 } 10701 10702 /* 10703 * Return a service element for the given service. 10704 */ 10705 static xmlNodePtr 10706 export_service(scf_service_t *svc, int flags) 10707 { 10708 xmlNodePtr snode; 10709 struct entity_elts elts; 10710 struct template_elts template_elts; 10711 int ret; 10712 10713 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10714 if (snode == NULL) 10715 uu_die(emsg_create_xml); 10716 10717 /* Get & set name attribute */ 10718 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10719 scfdie(); 10720 safe_setprop(snode, name_attr, exp_str); 10721 10722 safe_setprop(snode, type_attr, "service"); 10723 safe_setprop(snode, "version", "0"); 10724 10725 /* Acquire child elements. */ 10726 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10727 scfdie(); 10728 10729 (void) memset(&elts, 0, sizeof (elts)); 10730 (void) memset(&template_elts, 0, sizeof (template_elts)); 10731 10732 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10733 uint32_t pgflags; 10734 10735 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10736 scfdie(); 10737 10738 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10739 continue; 10740 10741 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10742 scfdie(); 10743 10744 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10745 export_dependency(exp_pg, &elts); 10746 continue; 10747 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10748 export_method(exp_pg, &elts); 10749 continue; 10750 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10751 if (scf_pg_get_name(exp_pg, exp_str, 10752 max_scf_name_len + 1) < 0) 10753 scfdie(); 10754 10755 if (strcmp(exp_str, scf_pg_general) == 0) { 10756 export_svc_general(exp_pg, &elts); 10757 continue; 10758 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10759 0) { 10760 export_method_context(exp_pg, &elts); 10761 continue; 10762 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10763 export_dependents(exp_pg, &elts); 10764 continue; 10765 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10766 continue; 10767 } 10768 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10769 export_template(exp_pg, &elts, &template_elts); 10770 continue; 10771 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10772 export_notify_params(exp_pg, &elts); 10773 continue; 10774 } 10775 10776 export_pg(exp_pg, &elts, flags); 10777 } 10778 if (ret == -1) 10779 scfdie(); 10780 10781 if (template_elts.common_name != NULL) { 10782 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10783 (void) xmlAddChild(elts.template, template_elts.common_name); 10784 (void) xmlAddChild(elts.template, template_elts.description); 10785 (void) xmlAddChild(elts.template, template_elts.documentation); 10786 } else { 10787 xmlFreeNode(template_elts.description); 10788 xmlFreeNode(template_elts.documentation); 10789 } 10790 10791 /* Iterate instances */ 10792 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10793 scfdie(); 10794 10795 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10796 export_instance(exp_inst, &elts, flags); 10797 if (ret == -1) 10798 scfdie(); 10799 10800 /* Now add all of the accumulated elements in order. */ 10801 (void) xmlAddChild(snode, elts.create_default_instance); 10802 (void) xmlAddChild(snode, elts.single_instance); 10803 (void) xmlAddChild(snode, elts.restarter); 10804 (void) xmlAddChildList(snode, elts.dependencies); 10805 (void) xmlAddChildList(snode, elts.dependents); 10806 (void) xmlAddChild(snode, elts.method_context); 10807 (void) xmlAddChildList(snode, elts.exec_methods); 10808 (void) xmlAddChildList(snode, elts.notify_params); 10809 (void) xmlAddChildList(snode, elts.property_groups); 10810 (void) xmlAddChildList(snode, elts.instances); 10811 (void) xmlAddChild(snode, elts.stability); 10812 (void) xmlAddChild(snode, elts.template); 10813 10814 return (snode); 10815 } 10816 10817 static int 10818 export_callback(void *data, scf_walkinfo_t *wip) 10819 { 10820 FILE *f; 10821 xmlDocPtr doc; 10822 xmlNodePtr sb; 10823 int result; 10824 struct export_args *argsp = (struct export_args *)data; 10825 10826 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10827 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10828 (exp_prop = scf_property_create(g_hndl)) == NULL || 10829 (exp_val = scf_value_create(g_hndl)) == NULL || 10830 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10831 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10832 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10833 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10834 scfdie(); 10835 10836 exp_str_sz = max_scf_len + 1; 10837 exp_str = safe_malloc(exp_str_sz); 10838 10839 if (argsp->filename != NULL) { 10840 errno = 0; 10841 f = fopen(argsp->filename, "wb"); 10842 if (f == NULL) { 10843 if (errno == 0) 10844 uu_die(gettext("Could not open \"%s\": no free " 10845 "stdio streams.\n"), argsp->filename); 10846 else 10847 uu_die(gettext("Could not open \"%s\""), 10848 argsp->filename); 10849 } 10850 } else 10851 f = stdout; 10852 10853 doc = xmlNewDoc((xmlChar *)"1.0"); 10854 if (doc == NULL) 10855 uu_die(gettext("Could not create XML document.\n")); 10856 10857 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10858 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10859 uu_die(emsg_create_xml); 10860 10861 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10862 if (sb == NULL) 10863 uu_die(emsg_create_xml); 10864 safe_setprop(sb, type_attr, "manifest"); 10865 safe_setprop(sb, name_attr, "export"); 10866 (void) xmlAddSibling(doc->children, sb); 10867 10868 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10869 10870 result = write_service_bundle(doc, f); 10871 10872 free(exp_str); 10873 scf_iter_destroy(exp_val_iter); 10874 scf_iter_destroy(exp_prop_iter); 10875 scf_iter_destroy(exp_pg_iter); 10876 scf_iter_destroy(exp_inst_iter); 10877 scf_value_destroy(exp_val); 10878 scf_property_destroy(exp_prop); 10879 scf_pg_destroy(exp_pg); 10880 scf_instance_destroy(exp_inst); 10881 10882 xmlFreeDoc(doc); 10883 10884 if (f != stdout) 10885 (void) fclose(f); 10886 10887 return (result); 10888 } 10889 10890 /* 10891 * Get the service named by fmri, build an XML tree which represents it, and 10892 * dump it into filename (or stdout if filename is NULL). 10893 */ 10894 int 10895 lscf_service_export(char *fmri, const char *filename, int flags) 10896 { 10897 struct export_args args; 10898 char *fmridup; 10899 const char *scope, *svc, *inst; 10900 size_t cblen = 3 * max_scf_name_len; 10901 char *canonbuf = alloca(cblen); 10902 int ret, err; 10903 10904 lscf_prep_hndl(); 10905 10906 bzero(&args, sizeof (args)); 10907 args.filename = filename; 10908 args.flags = flags; 10909 10910 /* 10911 * If some poor user has passed an exact instance FMRI, of the sort 10912 * one might cut and paste from svcs(1) or an error message, warn 10913 * and chop off the instance instead of failing. 10914 */ 10915 fmridup = alloca(strlen(fmri) + 1); 10916 (void) strcpy(fmridup, fmri); 10917 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX, 10918 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 && 10919 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 && 10920 inst != NULL) { 10921 (void) strlcpy(canonbuf, "svc:/", cblen); 10922 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 10923 (void) strlcat(canonbuf, "/", cblen); 10924 (void) strlcat(canonbuf, scope, cblen); 10925 } 10926 (void) strlcat(canonbuf, svc, cblen); 10927 fmri = canonbuf; 10928 10929 warn(gettext("Only services may be exported; ignoring " 10930 "instance portion of argument.\n")); 10931 } 10932 10933 err = 0; 10934 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10935 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10936 &args, &err, semerr)) != 0) { 10937 if (ret != -1) 10938 semerr(gettext("Failed to walk instances: %s\n"), 10939 scf_strerror(ret)); 10940 return (-1); 10941 } 10942 10943 /* 10944 * Error message has already been printed. 10945 */ 10946 if (err != 0) 10947 return (-1); 10948 10949 return (0); 10950 } 10951 10952 10953 /* 10954 * Archive 10955 */ 10956 10957 static xmlNodePtr 10958 make_archive(int flags) 10959 { 10960 xmlNodePtr sb; 10961 scf_scope_t *scope; 10962 scf_service_t *svc; 10963 scf_iter_t *iter; 10964 int r; 10965 10966 if ((scope = scf_scope_create(g_hndl)) == NULL || 10967 (svc = scf_service_create(g_hndl)) == NULL || 10968 (iter = scf_iter_create(g_hndl)) == NULL || 10969 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10970 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10971 (exp_prop = scf_property_create(g_hndl)) == NULL || 10972 (exp_val = scf_value_create(g_hndl)) == NULL || 10973 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10974 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10975 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10976 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10977 scfdie(); 10978 10979 exp_str_sz = max_scf_len + 1; 10980 exp_str = safe_malloc(exp_str_sz); 10981 10982 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10983 if (sb == NULL) 10984 uu_die(emsg_create_xml); 10985 safe_setprop(sb, type_attr, "archive"); 10986 safe_setprop(sb, name_attr, "none"); 10987 10988 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 10989 scfdie(); 10990 if (scf_iter_scope_services(iter, scope) != 0) 10991 scfdie(); 10992 10993 for (;;) { 10994 r = scf_iter_next_service(iter, svc); 10995 if (r == 0) 10996 break; 10997 if (r != 1) 10998 scfdie(); 10999 11000 if (scf_service_get_name(svc, exp_str, 11001 max_scf_name_len + 1) < 0) 11002 scfdie(); 11003 11004 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 11005 continue; 11006 11007 (void) xmlAddChild(sb, export_service(svc, flags)); 11008 } 11009 11010 free(exp_str); 11011 11012 scf_iter_destroy(exp_val_iter); 11013 scf_iter_destroy(exp_prop_iter); 11014 scf_iter_destroy(exp_pg_iter); 11015 scf_iter_destroy(exp_inst_iter); 11016 scf_value_destroy(exp_val); 11017 scf_property_destroy(exp_prop); 11018 scf_pg_destroy(exp_pg); 11019 scf_instance_destroy(exp_inst); 11020 scf_iter_destroy(iter); 11021 scf_service_destroy(svc); 11022 scf_scope_destroy(scope); 11023 11024 return (sb); 11025 } 11026 11027 int 11028 lscf_archive(const char *filename, int flags) 11029 { 11030 FILE *f; 11031 xmlDocPtr doc; 11032 int result; 11033 11034 lscf_prep_hndl(); 11035 11036 if (filename != NULL) { 11037 errno = 0; 11038 f = fopen(filename, "wb"); 11039 if (f == NULL) { 11040 if (errno == 0) 11041 uu_die(gettext("Could not open \"%s\": no free " 11042 "stdio streams.\n"), filename); 11043 else 11044 uu_die(gettext("Could not open \"%s\""), 11045 filename); 11046 } 11047 } else 11048 f = stdout; 11049 11050 doc = xmlNewDoc((xmlChar *)"1.0"); 11051 if (doc == NULL) 11052 uu_die(gettext("Could not create XML document.\n")); 11053 11054 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11055 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11056 uu_die(emsg_create_xml); 11057 11058 (void) xmlAddSibling(doc->children, make_archive(flags)); 11059 11060 result = write_service_bundle(doc, f); 11061 11062 xmlFreeDoc(doc); 11063 11064 if (f != stdout) 11065 (void) fclose(f); 11066 11067 return (result); 11068 } 11069 11070 11071 /* 11072 * "Extract" a profile. 11073 */ 11074 int 11075 lscf_profile_extract(const char *filename) 11076 { 11077 FILE *f; 11078 xmlDocPtr doc; 11079 xmlNodePtr sb, snode, inode; 11080 scf_scope_t *scope; 11081 scf_service_t *svc; 11082 scf_instance_t *inst; 11083 scf_propertygroup_t *pg; 11084 scf_property_t *prop; 11085 scf_value_t *val; 11086 scf_iter_t *siter, *iiter; 11087 int r, s; 11088 char *namebuf; 11089 uint8_t b; 11090 int result; 11091 11092 lscf_prep_hndl(); 11093 11094 if (filename != NULL) { 11095 errno = 0; 11096 f = fopen(filename, "wb"); 11097 if (f == NULL) { 11098 if (errno == 0) 11099 uu_die(gettext("Could not open \"%s\": no " 11100 "free stdio streams.\n"), filename); 11101 else 11102 uu_die(gettext("Could not open \"%s\""), 11103 filename); 11104 } 11105 } else 11106 f = stdout; 11107 11108 doc = xmlNewDoc((xmlChar *)"1.0"); 11109 if (doc == NULL) 11110 uu_die(gettext("Could not create XML document.\n")); 11111 11112 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11113 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11114 uu_die(emsg_create_xml); 11115 11116 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 11117 if (sb == NULL) 11118 uu_die(emsg_create_xml); 11119 safe_setprop(sb, type_attr, "profile"); 11120 safe_setprop(sb, name_attr, "extract"); 11121 (void) xmlAddSibling(doc->children, sb); 11122 11123 if ((scope = scf_scope_create(g_hndl)) == NULL || 11124 (svc = scf_service_create(g_hndl)) == NULL || 11125 (inst = scf_instance_create(g_hndl)) == NULL || 11126 (pg = scf_pg_create(g_hndl)) == NULL || 11127 (prop = scf_property_create(g_hndl)) == NULL || 11128 (val = scf_value_create(g_hndl)) == NULL || 11129 (siter = scf_iter_create(g_hndl)) == NULL || 11130 (iiter = scf_iter_create(g_hndl)) == NULL) 11131 scfdie(); 11132 11133 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 11134 scfdie(); 11135 11136 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 11137 scfdie(); 11138 11139 namebuf = safe_malloc(max_scf_name_len + 1); 11140 11141 while ((r = scf_iter_next_service(siter, svc)) == 1) { 11142 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 11143 scfdie(); 11144 11145 snode = xmlNewNode(NULL, (xmlChar *)"service"); 11146 if (snode == NULL) 11147 uu_die(emsg_create_xml); 11148 11149 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 11150 0) 11151 scfdie(); 11152 11153 safe_setprop(snode, name_attr, namebuf); 11154 11155 safe_setprop(snode, type_attr, "service"); 11156 safe_setprop(snode, "version", "0"); 11157 11158 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 11159 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 11160 SCF_SUCCESS) { 11161 if (scf_error() != SCF_ERROR_NOT_FOUND) 11162 scfdie(); 11163 11164 if (g_verbose) { 11165 ssize_t len; 11166 char *fmri; 11167 11168 len = 11169 scf_instance_to_fmri(inst, NULL, 0); 11170 if (len < 0) 11171 scfdie(); 11172 11173 fmri = safe_malloc(len + 1); 11174 11175 if (scf_instance_to_fmri(inst, fmri, 11176 len + 1) < 0) 11177 scfdie(); 11178 11179 warn("Instance %s has no \"%s\" " 11180 "property group.\n", fmri, 11181 scf_pg_general); 11182 11183 free(fmri); 11184 } 11185 11186 continue; 11187 } 11188 11189 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 11190 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 11191 prop_get_val(prop, val) != 0) 11192 continue; 11193 11194 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 11195 NULL); 11196 if (inode == NULL) 11197 uu_die(emsg_create_xml); 11198 11199 if (scf_instance_get_name(inst, namebuf, 11200 max_scf_name_len + 1) < 0) 11201 scfdie(); 11202 11203 safe_setprop(inode, name_attr, namebuf); 11204 11205 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 11206 scfdie(); 11207 11208 safe_setprop(inode, enabled_attr, b ? true : false); 11209 } 11210 if (s < 0) 11211 scfdie(); 11212 11213 if (snode->children != NULL) 11214 (void) xmlAddChild(sb, snode); 11215 else 11216 xmlFreeNode(snode); 11217 } 11218 if (r < 0) 11219 scfdie(); 11220 11221 free(namebuf); 11222 11223 result = write_service_bundle(doc, f); 11224 11225 xmlFreeDoc(doc); 11226 11227 if (f != stdout) 11228 (void) fclose(f); 11229 11230 return (result); 11231 } 11232 11233 11234 /* 11235 * Entity manipulation commands 11236 */ 11237 11238 /* 11239 * Entity selection. If no entity is selected, then the current scope is in 11240 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 11241 * only cur_inst is NULL, and when an instance is selected, none are NULL. 11242 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 11243 * cur_inst will be non-NULL. 11244 */ 11245 11246 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 11247 static int 11248 select_inst(const char *name) 11249 { 11250 scf_instance_t *inst; 11251 scf_error_t err; 11252 11253 assert(cur_svc != NULL); 11254 11255 inst = scf_instance_create(g_hndl); 11256 if (inst == NULL) 11257 scfdie(); 11258 11259 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 11260 cur_inst = inst; 11261 return (0); 11262 } 11263 11264 err = scf_error(); 11265 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11266 scfdie(); 11267 11268 scf_instance_destroy(inst); 11269 return (1); 11270 } 11271 11272 /* Returns as above. */ 11273 static int 11274 select_svc(const char *name) 11275 { 11276 scf_service_t *svc; 11277 scf_error_t err; 11278 11279 assert(cur_scope != NULL); 11280 11281 svc = scf_service_create(g_hndl); 11282 if (svc == NULL) 11283 scfdie(); 11284 11285 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 11286 cur_svc = svc; 11287 return (0); 11288 } 11289 11290 err = scf_error(); 11291 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11292 scfdie(); 11293 11294 scf_service_destroy(svc); 11295 return (1); 11296 } 11297 11298 /* ARGSUSED */ 11299 static int 11300 select_callback(void *unused, scf_walkinfo_t *wip) 11301 { 11302 scf_instance_t *inst; 11303 scf_service_t *svc; 11304 scf_scope_t *scope; 11305 11306 if (wip->inst != NULL) { 11307 if ((scope = scf_scope_create(g_hndl)) == NULL || 11308 (svc = scf_service_create(g_hndl)) == NULL || 11309 (inst = scf_instance_create(g_hndl)) == NULL) 11310 scfdie(); 11311 11312 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11313 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11314 scfdie(); 11315 } else { 11316 assert(wip->svc != NULL); 11317 11318 if ((scope = scf_scope_create(g_hndl)) == NULL || 11319 (svc = scf_service_create(g_hndl)) == NULL) 11320 scfdie(); 11321 11322 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11323 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11324 scfdie(); 11325 11326 inst = NULL; 11327 } 11328 11329 /* Clear out the current selection */ 11330 assert(cur_scope != NULL); 11331 scf_scope_destroy(cur_scope); 11332 scf_service_destroy(cur_svc); 11333 scf_instance_destroy(cur_inst); 11334 11335 cur_scope = scope; 11336 cur_svc = svc; 11337 cur_inst = inst; 11338 11339 return (0); 11340 } 11341 11342 static int 11343 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 11344 { 11345 char **fmri = fmri_p; 11346 11347 *fmri = strdup(wip->fmri); 11348 if (*fmri == NULL) 11349 uu_die(gettext("Out of memory.\n")); 11350 11351 return (0); 11352 } 11353 11354 /* 11355 * validate [fmri] 11356 * Perform the validation of an FMRI instance. 11357 */ 11358 void 11359 lscf_validate_fmri(const char *fmri) 11360 { 11361 int ret = 0; 11362 size_t inst_sz; 11363 char *inst_fmri = NULL; 11364 scf_tmpl_errors_t *errs = NULL; 11365 char *snapbuf = NULL; 11366 11367 lscf_prep_hndl(); 11368 11369 if (fmri == NULL) { 11370 inst_sz = max_scf_fmri_len + 1; 11371 inst_fmri = safe_malloc(inst_sz); 11372 11373 if (cur_snap != NULL) { 11374 snapbuf = safe_malloc(max_scf_name_len + 1); 11375 if (scf_snapshot_get_name(cur_snap, snapbuf, 11376 max_scf_name_len + 1) < 0) 11377 scfdie(); 11378 } 11379 if (cur_inst == NULL) { 11380 semerr(gettext("No instance selected\n")); 11381 goto cleanup; 11382 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 11383 inst_sz) >= inst_sz) { 11384 /* sanity check. Should never get here */ 11385 uu_die(gettext("Unexpected error! file %s, line %d\n"), 11386 __FILE__, __LINE__); 11387 } 11388 } else { 11389 scf_error_t scf_err; 11390 int err = 0; 11391 11392 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 11393 validate_callback, &inst_fmri, &err, semerr)) != 0) { 11394 uu_warn("Failed to walk instances: %s\n", 11395 scf_strerror(scf_err)); 11396 goto cleanup; 11397 } 11398 if (err != 0) { 11399 /* error message displayed by scf_walk_fmri */ 11400 goto cleanup; 11401 } 11402 } 11403 11404 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 11405 SCF_TMPL_VALIDATE_FLAG_CURRENT); 11406 if (ret == -1) { 11407 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 11408 warn(gettext("Template data for %s is invalid. " 11409 "Consider reverting to a previous snapshot or " 11410 "restoring original configuration.\n"), inst_fmri); 11411 } else { 11412 uu_warn("%s: %s\n", 11413 gettext("Error validating the instance"), 11414 scf_strerror(scf_error())); 11415 } 11416 } else if (ret == 1 && errs != NULL) { 11417 scf_tmpl_error_t *err = NULL; 11418 char *msg; 11419 size_t len = 256; /* initial error buffer size */ 11420 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 11421 SCF_TMPL_STRERROR_HUMAN : 0; 11422 11423 msg = safe_malloc(len); 11424 11425 while ((err = scf_tmpl_next_error(errs)) != NULL) { 11426 int ret; 11427 11428 if ((ret = scf_tmpl_strerror(err, msg, len, 11429 flag)) >= len) { 11430 len = ret + 1; 11431 msg = realloc(msg, len); 11432 if (msg == NULL) 11433 uu_die(gettext( 11434 "Out of memory.\n")); 11435 (void) scf_tmpl_strerror(err, msg, len, 11436 flag); 11437 } 11438 (void) fprintf(stderr, "%s\n", msg); 11439 } 11440 if (msg != NULL) 11441 free(msg); 11442 } 11443 if (errs != NULL) 11444 scf_tmpl_errors_destroy(errs); 11445 11446 cleanup: 11447 free(inst_fmri); 11448 free(snapbuf); 11449 } 11450 11451 static void 11452 lscf_validate_file(const char *filename) 11453 { 11454 tmpl_errors_t *errs; 11455 11456 bundle_t *b = internal_bundle_new(); 11457 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 11458 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 11459 tmpl_errors_print(stderr, errs, ""); 11460 semerr(gettext("Validation failed.\n")); 11461 } 11462 tmpl_errors_destroy(errs); 11463 } 11464 (void) internal_bundle_free(b); 11465 } 11466 11467 /* 11468 * validate [fmri|file] 11469 */ 11470 void 11471 lscf_validate(const char *arg) 11472 { 11473 const char *str; 11474 11475 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 11476 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 11477 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 11478 lscf_validate_file(str); 11479 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 11480 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 11481 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 11482 lscf_validate_fmri(str); 11483 } else if (access(arg, R_OK | F_OK) == 0) { 11484 lscf_validate_file(arg); 11485 } else { 11486 lscf_validate_fmri(arg); 11487 } 11488 } 11489 11490 void 11491 lscf_select(const char *fmri) 11492 { 11493 int ret, err; 11494 11495 lscf_prep_hndl(); 11496 11497 if (cur_snap != NULL) { 11498 struct snaplevel *elt; 11499 char *buf; 11500 11501 /* Error unless name is that of the next level. */ 11502 elt = uu_list_next(cur_levels, cur_elt); 11503 if (elt == NULL) { 11504 semerr(gettext("No children.\n")); 11505 return; 11506 } 11507 11508 buf = safe_malloc(max_scf_name_len + 1); 11509 11510 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11511 max_scf_name_len + 1) < 0) 11512 scfdie(); 11513 11514 if (strcmp(buf, fmri) != 0) { 11515 semerr(gettext("No such child.\n")); 11516 free(buf); 11517 return; 11518 } 11519 11520 free(buf); 11521 11522 cur_elt = elt; 11523 cur_level = elt->sl; 11524 return; 11525 } 11526 11527 /* 11528 * Special case for 'svc:', which takes the user to the scope level. 11529 */ 11530 if (strcmp(fmri, "svc:") == 0) { 11531 scf_instance_destroy(cur_inst); 11532 scf_service_destroy(cur_svc); 11533 cur_inst = NULL; 11534 cur_svc = NULL; 11535 return; 11536 } 11537 11538 /* 11539 * Special case for ':properties'. This appears as part of 'list' but 11540 * can't be selected. Give a more helpful error message in this case. 11541 */ 11542 if (strcmp(fmri, ":properties") == 0) { 11543 semerr(gettext(":properties is not an entity. Try 'listprop' " 11544 "to list properties.\n")); 11545 return; 11546 } 11547 11548 /* 11549 * First try the argument as relative to the current selection. 11550 */ 11551 if (cur_inst != NULL) { 11552 /* EMPTY */; 11553 } else if (cur_svc != NULL) { 11554 if (select_inst(fmri) != 1) 11555 return; 11556 } else { 11557 if (select_svc(fmri) != 1) 11558 return; 11559 } 11560 11561 err = 0; 11562 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11563 select_callback, NULL, &err, semerr)) != 0) { 11564 semerr(gettext("Failed to walk instances: %s\n"), 11565 scf_strerror(ret)); 11566 } 11567 } 11568 11569 void 11570 lscf_unselect(void) 11571 { 11572 lscf_prep_hndl(); 11573 11574 if (cur_snap != NULL) { 11575 struct snaplevel *elt; 11576 11577 elt = uu_list_prev(cur_levels, cur_elt); 11578 if (elt == NULL) { 11579 semerr(gettext("No parent levels.\n")); 11580 } else { 11581 cur_elt = elt; 11582 cur_level = elt->sl; 11583 } 11584 } else if (cur_inst != NULL) { 11585 scf_instance_destroy(cur_inst); 11586 cur_inst = NULL; 11587 } else if (cur_svc != NULL) { 11588 scf_service_destroy(cur_svc); 11589 cur_svc = NULL; 11590 } else { 11591 semerr(gettext("Cannot unselect at scope level.\n")); 11592 } 11593 } 11594 11595 /* 11596 * Return the FMRI of the current selection, for the prompt. 11597 */ 11598 void 11599 lscf_get_selection_str(char *buf, size_t bufsz) 11600 { 11601 char *cp; 11602 ssize_t fmrilen, szret; 11603 boolean_t deleted = B_FALSE; 11604 11605 if (g_hndl == NULL) { 11606 (void) strlcpy(buf, "svc:", bufsz); 11607 return; 11608 } 11609 11610 if (cur_level != NULL) { 11611 assert(cur_snap != NULL); 11612 11613 /* [ snapshot ] FMRI [: instance ] */ 11614 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11615 + 2 + max_scf_name_len + 1 + 1); 11616 11617 buf[0] = '['; 11618 11619 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11620 max_scf_name_len + 1); 11621 if (szret < 0) { 11622 if (scf_error() != SCF_ERROR_DELETED) 11623 scfdie(); 11624 11625 goto snap_deleted; 11626 } 11627 11628 (void) strcat(buf, "]svc:/"); 11629 11630 cp = strchr(buf, '\0'); 11631 11632 szret = scf_snaplevel_get_service_name(cur_level, cp, 11633 max_scf_name_len + 1); 11634 if (szret < 0) { 11635 if (scf_error() != SCF_ERROR_DELETED) 11636 scfdie(); 11637 11638 goto snap_deleted; 11639 } 11640 11641 cp = strchr(cp, '\0'); 11642 11643 if (snaplevel_is_instance(cur_level)) { 11644 *cp++ = ':'; 11645 11646 if (scf_snaplevel_get_instance_name(cur_level, cp, 11647 max_scf_name_len + 1) < 0) { 11648 if (scf_error() != SCF_ERROR_DELETED) 11649 scfdie(); 11650 11651 goto snap_deleted; 11652 } 11653 } else { 11654 *cp++ = '['; 11655 *cp++ = ':'; 11656 11657 if (scf_instance_get_name(cur_inst, cp, 11658 max_scf_name_len + 1) < 0) { 11659 if (scf_error() != SCF_ERROR_DELETED) 11660 scfdie(); 11661 11662 goto snap_deleted; 11663 } 11664 11665 (void) strcat(buf, "]"); 11666 } 11667 11668 return; 11669 11670 snap_deleted: 11671 deleted = B_TRUE; 11672 free(buf); 11673 unselect_cursnap(); 11674 } 11675 11676 assert(cur_snap == NULL); 11677 11678 if (cur_inst != NULL) { 11679 assert(cur_svc != NULL); 11680 assert(cur_scope != NULL); 11681 11682 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11683 if (fmrilen >= 0) { 11684 assert(fmrilen < bufsz); 11685 if (deleted) 11686 warn(emsg_deleted); 11687 return; 11688 } 11689 11690 if (scf_error() != SCF_ERROR_DELETED) 11691 scfdie(); 11692 11693 deleted = B_TRUE; 11694 11695 scf_instance_destroy(cur_inst); 11696 cur_inst = NULL; 11697 } 11698 11699 if (cur_svc != NULL) { 11700 assert(cur_scope != NULL); 11701 11702 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11703 if (szret >= 0) { 11704 assert(szret < bufsz); 11705 if (deleted) 11706 warn(emsg_deleted); 11707 return; 11708 } 11709 11710 if (scf_error() != SCF_ERROR_DELETED) 11711 scfdie(); 11712 11713 deleted = B_TRUE; 11714 scf_service_destroy(cur_svc); 11715 cur_svc = NULL; 11716 } 11717 11718 assert(cur_scope != NULL); 11719 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11720 11721 if (fmrilen < 0) 11722 scfdie(); 11723 11724 assert(fmrilen < bufsz); 11725 if (deleted) 11726 warn(emsg_deleted); 11727 } 11728 11729 /* 11730 * Entity listing. Entities and colon namespaces (e.g., :properties and 11731 * :statistics) are listed for the current selection. 11732 */ 11733 void 11734 lscf_list(const char *pattern) 11735 { 11736 scf_iter_t *iter; 11737 char *buf; 11738 int ret; 11739 11740 lscf_prep_hndl(); 11741 11742 if (cur_level != NULL) { 11743 struct snaplevel *elt; 11744 11745 (void) fputs(COLON_NAMESPACES, stdout); 11746 11747 elt = uu_list_next(cur_levels, cur_elt); 11748 if (elt == NULL) 11749 return; 11750 11751 /* 11752 * For now, we know that the next level is an instance. But 11753 * if we ever have multiple scopes, this could be complicated. 11754 */ 11755 buf = safe_malloc(max_scf_name_len + 1); 11756 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11757 max_scf_name_len + 1) >= 0) { 11758 (void) puts(buf); 11759 } else { 11760 if (scf_error() != SCF_ERROR_DELETED) 11761 scfdie(); 11762 } 11763 11764 free(buf); 11765 11766 return; 11767 } 11768 11769 if (cur_inst != NULL) { 11770 (void) fputs(COLON_NAMESPACES, stdout); 11771 return; 11772 } 11773 11774 iter = scf_iter_create(g_hndl); 11775 if (iter == NULL) 11776 scfdie(); 11777 11778 buf = safe_malloc(max_scf_name_len + 1); 11779 11780 if (cur_svc != NULL) { 11781 /* List the instances in this service. */ 11782 scf_instance_t *inst; 11783 11784 inst = scf_instance_create(g_hndl); 11785 if (inst == NULL) 11786 scfdie(); 11787 11788 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11789 safe_printf(COLON_NAMESPACES); 11790 11791 for (;;) { 11792 ret = scf_iter_next_instance(iter, inst); 11793 if (ret == 0) 11794 break; 11795 if (ret != 1) { 11796 if (scf_error() != SCF_ERROR_DELETED) 11797 scfdie(); 11798 11799 break; 11800 } 11801 11802 if (scf_instance_get_name(inst, buf, 11803 max_scf_name_len + 1) >= 0) { 11804 if (pattern == NULL || 11805 fnmatch(pattern, buf, 0) == 0) 11806 (void) puts(buf); 11807 } else { 11808 if (scf_error() != SCF_ERROR_DELETED) 11809 scfdie(); 11810 } 11811 } 11812 } else { 11813 if (scf_error() != SCF_ERROR_DELETED) 11814 scfdie(); 11815 } 11816 11817 scf_instance_destroy(inst); 11818 } else { 11819 /* List the services in this scope. */ 11820 scf_service_t *svc; 11821 11822 assert(cur_scope != NULL); 11823 11824 svc = scf_service_create(g_hndl); 11825 if (svc == NULL) 11826 scfdie(); 11827 11828 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11829 scfdie(); 11830 11831 for (;;) { 11832 ret = scf_iter_next_service(iter, svc); 11833 if (ret == 0) 11834 break; 11835 if (ret != 1) 11836 scfdie(); 11837 11838 if (scf_service_get_name(svc, buf, 11839 max_scf_name_len + 1) >= 0) { 11840 if (pattern == NULL || 11841 fnmatch(pattern, buf, 0) == 0) 11842 safe_printf("%s\n", buf); 11843 } else { 11844 if (scf_error() != SCF_ERROR_DELETED) 11845 scfdie(); 11846 } 11847 } 11848 11849 scf_service_destroy(svc); 11850 } 11851 11852 free(buf); 11853 scf_iter_destroy(iter); 11854 } 11855 11856 /* 11857 * Entity addition. Creates an empty entity in the current selection. 11858 */ 11859 void 11860 lscf_add(const char *name) 11861 { 11862 lscf_prep_hndl(); 11863 11864 if (cur_snap != NULL) { 11865 semerr(emsg_cant_modify_snapshots); 11866 } else if (cur_inst != NULL) { 11867 semerr(gettext("Cannot add entities to an instance.\n")); 11868 } else if (cur_svc != NULL) { 11869 11870 if (scf_service_add_instance(cur_svc, name, NULL) != 11871 SCF_SUCCESS) { 11872 switch (scf_error()) { 11873 case SCF_ERROR_INVALID_ARGUMENT: 11874 semerr(gettext("Invalid name.\n")); 11875 break; 11876 11877 case SCF_ERROR_EXISTS: 11878 semerr(gettext("Instance already exists.\n")); 11879 break; 11880 11881 case SCF_ERROR_PERMISSION_DENIED: 11882 semerr(emsg_permission_denied); 11883 break; 11884 11885 default: 11886 scfdie(); 11887 } 11888 } 11889 } else { 11890 assert(cur_scope != NULL); 11891 11892 if (scf_scope_add_service(cur_scope, 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("Service already exists.\n")); 11901 break; 11902 11903 case SCF_ERROR_PERMISSION_DENIED: 11904 semerr(emsg_permission_denied); 11905 break; 11906 11907 case SCF_ERROR_BACKEND_READONLY: 11908 semerr(emsg_read_only); 11909 break; 11910 11911 default: 11912 scfdie(); 11913 } 11914 } 11915 } 11916 } 11917 11918 /* return 1 if the entity has no persistent pgs, else return 0 */ 11919 static int 11920 entity_has_no_pgs(void *ent, int isservice) 11921 { 11922 scf_iter_t *iter = NULL; 11923 scf_propertygroup_t *pg = NULL; 11924 uint32_t flags; 11925 int err; 11926 int ret = 1; 11927 11928 if ((iter = scf_iter_create(g_hndl)) == NULL || 11929 (pg = scf_pg_create(g_hndl)) == NULL) 11930 scfdie(); 11931 11932 if (isservice) { 11933 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11934 scfdie(); 11935 } else { 11936 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11937 scfdie(); 11938 } 11939 11940 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11941 if (scf_pg_get_flags(pg, &flags) != 0) 11942 scfdie(); 11943 11944 /* skip nonpersistent pgs */ 11945 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11946 continue; 11947 11948 ret = 0; 11949 break; 11950 } 11951 11952 if (err == -1) 11953 scfdie(); 11954 11955 scf_pg_destroy(pg); 11956 scf_iter_destroy(iter); 11957 11958 return (ret); 11959 } 11960 11961 /* return 1 if the service has no instances, else return 0 */ 11962 static int 11963 svc_has_no_insts(scf_service_t *svc) 11964 { 11965 scf_instance_t *inst; 11966 scf_iter_t *iter; 11967 int r; 11968 int ret = 1; 11969 11970 if ((inst = scf_instance_create(g_hndl)) == NULL || 11971 (iter = scf_iter_create(g_hndl)) == NULL) 11972 scfdie(); 11973 11974 if (scf_iter_service_instances(iter, svc) != 0) 11975 scfdie(); 11976 11977 r = scf_iter_next_instance(iter, inst); 11978 if (r == 1) { 11979 ret = 0; 11980 } else if (r == 0) { 11981 ret = 1; 11982 } else if (r == -1) { 11983 scfdie(); 11984 } else { 11985 bad_error("scf_iter_next_instance", r); 11986 } 11987 11988 scf_iter_destroy(iter); 11989 scf_instance_destroy(inst); 11990 11991 return (ret); 11992 } 11993 11994 /* 11995 * Entity deletion. 11996 */ 11997 11998 /* 11999 * Delete the property group <fmri>/:properties/<name>. Returns 12000 * SCF_ERROR_NONE on success (or if the entity is not found), 12001 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 12002 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 12003 * denied. 12004 */ 12005 static scf_error_t 12006 delete_dependency_pg(const char *fmri, const char *name) 12007 { 12008 void *entity = NULL; 12009 int isservice; 12010 scf_propertygroup_t *pg = NULL; 12011 scf_error_t result; 12012 char *pgty; 12013 scf_service_t *svc = NULL; 12014 scf_instance_t *inst = NULL; 12015 scf_iter_t *iter = NULL; 12016 char *name_buf = NULL; 12017 12018 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 12019 switch (result) { 12020 case SCF_ERROR_NONE: 12021 break; 12022 12023 case SCF_ERROR_NO_MEMORY: 12024 uu_die(gettext("Out of memory.\n")); 12025 /* NOTREACHED */ 12026 12027 case SCF_ERROR_INVALID_ARGUMENT: 12028 case SCF_ERROR_CONSTRAINT_VIOLATED: 12029 return (SCF_ERROR_INVALID_ARGUMENT); 12030 12031 case SCF_ERROR_NOT_FOUND: 12032 result = SCF_ERROR_NONE; 12033 goto out; 12034 12035 default: 12036 bad_error("fmri_to_entity", result); 12037 } 12038 12039 pg = scf_pg_create(g_hndl); 12040 if (pg == NULL) 12041 scfdie(); 12042 12043 if (entity_get_pg(entity, isservice, name, pg) != 0) { 12044 if (scf_error() != SCF_ERROR_NOT_FOUND) 12045 scfdie(); 12046 12047 result = SCF_ERROR_NONE; 12048 goto out; 12049 } 12050 12051 pgty = safe_malloc(max_scf_pg_type_len + 1); 12052 12053 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12054 scfdie(); 12055 12056 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 12057 result = SCF_ERROR_TYPE_MISMATCH; 12058 free(pgty); 12059 goto out; 12060 } 12061 12062 free(pgty); 12063 12064 if (scf_pg_delete(pg) != 0) { 12065 result = scf_error(); 12066 if (result != SCF_ERROR_PERMISSION_DENIED) 12067 scfdie(); 12068 goto out; 12069 } 12070 12071 /* 12072 * We have to handle the case where we've just deleted the last 12073 * property group of a "dummy" entity (instance or service). 12074 * A "dummy" entity is an entity only present to hold an 12075 * external dependency. 12076 * So, in the case we deleted the last property group then we 12077 * can also delete the entity. If the entity is an instance then 12078 * we must verify if this was the last instance for the service 12079 * and if it is, we can also delete the service if it doesn't 12080 * have any property group either. 12081 */ 12082 12083 result = SCF_ERROR_NONE; 12084 12085 if (isservice) { 12086 svc = (scf_service_t *)entity; 12087 12088 if ((inst = scf_instance_create(g_hndl)) == NULL || 12089 (iter = scf_iter_create(g_hndl)) == NULL) 12090 scfdie(); 12091 12092 name_buf = safe_malloc(max_scf_name_len + 1); 12093 } else { 12094 inst = (scf_instance_t *)entity; 12095 } 12096 12097 /* 12098 * If the entity is an instance and we've just deleted its last 12099 * property group then we should delete it. 12100 */ 12101 if (!isservice && entity_has_no_pgs(entity, isservice)) { 12102 /* find the service before deleting the inst. - needed later */ 12103 if ((svc = scf_service_create(g_hndl)) == NULL) 12104 scfdie(); 12105 12106 if (scf_instance_get_parent(inst, svc) != 0) 12107 scfdie(); 12108 12109 /* delete the instance */ 12110 if (scf_instance_delete(inst) != 0) { 12111 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12112 scfdie(); 12113 12114 result = SCF_ERROR_PERMISSION_DENIED; 12115 goto out; 12116 } 12117 /* no need to refresh the instance */ 12118 inst = NULL; 12119 } 12120 12121 /* 12122 * If the service has no more instances and pgs or we just deleted the 12123 * last instance and the service doesn't have anymore propery groups 12124 * then the service should be deleted. 12125 */ 12126 if (svc != NULL && 12127 svc_has_no_insts(svc) && 12128 entity_has_no_pgs((void *)svc, 1)) { 12129 if (scf_service_delete(svc) == 0) { 12130 if (isservice) { 12131 /* no need to refresh the service */ 12132 svc = NULL; 12133 } 12134 12135 goto out; 12136 } 12137 12138 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12139 scfdie(); 12140 12141 result = SCF_ERROR_PERMISSION_DENIED; 12142 } 12143 12144 /* if the entity has not been deleted, refresh it */ 12145 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 12146 (void) refresh_entity(isservice, entity, fmri, inst, iter, 12147 name_buf); 12148 } 12149 12150 out: 12151 if (isservice && (inst != NULL && iter != NULL)) { 12152 free(name_buf); 12153 scf_iter_destroy(iter); 12154 scf_instance_destroy(inst); 12155 } 12156 12157 if (!isservice && svc != NULL) { 12158 scf_service_destroy(svc); 12159 } 12160 12161 scf_pg_destroy(pg); 12162 if (entity != NULL) 12163 entity_destroy(entity, isservice); 12164 12165 return (result); 12166 } 12167 12168 static int 12169 delete_dependents(scf_propertygroup_t *pg) 12170 { 12171 char *pgty, *name, *fmri; 12172 scf_property_t *prop; 12173 scf_value_t *val; 12174 scf_iter_t *iter; 12175 int r; 12176 scf_error_t err; 12177 12178 /* Verify that the pg has the correct type. */ 12179 pgty = safe_malloc(max_scf_pg_type_len + 1); 12180 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12181 scfdie(); 12182 12183 if (strcmp(pgty, scf_group_framework) != 0) { 12184 if (g_verbose) { 12185 fmri = safe_malloc(max_scf_fmri_len + 1); 12186 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 12187 scfdie(); 12188 12189 warn(gettext("Property group %s is not of expected " 12190 "type %s.\n"), fmri, scf_group_framework); 12191 12192 free(fmri); 12193 } 12194 12195 free(pgty); 12196 return (-1); 12197 } 12198 12199 free(pgty); 12200 12201 /* map delete_dependency_pg onto the properties. */ 12202 if ((prop = scf_property_create(g_hndl)) == NULL || 12203 (val = scf_value_create(g_hndl)) == NULL || 12204 (iter = scf_iter_create(g_hndl)) == NULL) 12205 scfdie(); 12206 12207 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 12208 scfdie(); 12209 12210 name = safe_malloc(max_scf_name_len + 1); 12211 fmri = safe_malloc(max_scf_fmri_len + 2); 12212 12213 while ((r = scf_iter_next_property(iter, prop)) == 1) { 12214 scf_type_t ty; 12215 12216 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 12217 scfdie(); 12218 12219 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 12220 scfdie(); 12221 12222 if ((ty != SCF_TYPE_ASTRING && 12223 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 12224 prop_get_val(prop, val) != 0) 12225 continue; 12226 12227 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 12228 scfdie(); 12229 12230 err = delete_dependency_pg(fmri, name); 12231 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 12232 if (scf_property_to_fmri(prop, fmri, 12233 max_scf_fmri_len + 2) < 0) 12234 scfdie(); 12235 12236 warn(gettext("Value of %s is not a valid FMRI.\n"), 12237 fmri); 12238 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 12239 warn(gettext("Property group \"%s\" of entity \"%s\" " 12240 "does not have dependency type.\n"), name, fmri); 12241 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 12242 warn(gettext("Could not delete property group \"%s\" " 12243 "of entity \"%s\" (permission denied).\n"), name, 12244 fmri); 12245 } 12246 } 12247 if (r == -1) 12248 scfdie(); 12249 12250 scf_value_destroy(val); 12251 scf_property_destroy(prop); 12252 12253 return (0); 12254 } 12255 12256 /* 12257 * Returns 1 if the instance may be running, and 0 otherwise. 12258 */ 12259 static int 12260 inst_is_running(scf_instance_t *inst) 12261 { 12262 scf_propertygroup_t *pg; 12263 scf_property_t *prop; 12264 scf_value_t *val; 12265 char buf[MAX_SCF_STATE_STRING_SZ]; 12266 int ret = 0; 12267 ssize_t szret; 12268 12269 if ((pg = scf_pg_create(g_hndl)) == NULL || 12270 (prop = scf_property_create(g_hndl)) == NULL || 12271 (val = scf_value_create(g_hndl)) == NULL) 12272 scfdie(); 12273 12274 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 12275 if (scf_error() != SCF_ERROR_NOT_FOUND) 12276 scfdie(); 12277 goto out; 12278 } 12279 12280 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 12281 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 12282 prop_get_val(prop, val) != 0) 12283 goto out; 12284 12285 szret = scf_value_get_astring(val, buf, sizeof (buf)); 12286 assert(szret >= 0); 12287 12288 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 12289 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 12290 12291 out: 12292 scf_value_destroy(val); 12293 scf_property_destroy(prop); 12294 scf_pg_destroy(pg); 12295 return (ret); 12296 } 12297 12298 static uint8_t 12299 pg_is_external_dependency(scf_propertygroup_t *pg) 12300 { 12301 char *type; 12302 scf_value_t *val; 12303 scf_property_t *prop; 12304 uint8_t b = B_FALSE; 12305 12306 type = safe_malloc(max_scf_pg_type_len + 1); 12307 12308 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 12309 scfdie(); 12310 12311 if ((prop = scf_property_create(g_hndl)) == NULL || 12312 (val = scf_value_create(g_hndl)) == NULL) 12313 scfdie(); 12314 12315 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 12316 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 12317 if (scf_property_get_value(prop, val) != 0) 12318 scfdie(); 12319 if (scf_value_get_boolean(val, &b) != 0) 12320 scfdie(); 12321 } 12322 } 12323 12324 free(type); 12325 (void) scf_value_destroy(val); 12326 (void) scf_property_destroy(prop); 12327 12328 return (b); 12329 } 12330 12331 #define DELETE_FAILURE -1 12332 #define DELETE_SUCCESS_NOEXTDEPS 0 12333 #define DELETE_SUCCESS_EXTDEPS 1 12334 12335 /* 12336 * lscf_instance_delete() deletes an instance. Before calling 12337 * scf_instance_delete(), though, we make sure the instance isn't 12338 * running and delete dependencies in other entities which the instance 12339 * declared as "dependents". If there are dependencies which were 12340 * created for other entities, then instead of deleting the instance we 12341 * make it "empty" by deleting all other property groups and all 12342 * snapshots. 12343 * 12344 * lscf_instance_delete() verifies that there is no external dependency pgs 12345 * before suppressing the instance. If there is, then we must not remove them 12346 * now in case the instance is re-created otherwise the dependencies would be 12347 * lost. The external dependency pgs will be removed if the dependencies are 12348 * removed. 12349 * 12350 * Returns: 12351 * DELETE_FAILURE on failure 12352 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12353 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12354 */ 12355 static int 12356 lscf_instance_delete(scf_instance_t *inst, int force) 12357 { 12358 scf_propertygroup_t *pg; 12359 scf_snapshot_t *snap; 12360 scf_iter_t *iter; 12361 int err; 12362 int external = 0; 12363 12364 /* If we're not forcing and the instance is running, refuse. */ 12365 if (!force && inst_is_running(inst)) { 12366 char *fmri; 12367 12368 fmri = safe_malloc(max_scf_fmri_len + 1); 12369 12370 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 12371 scfdie(); 12372 12373 semerr(gettext("Instance %s may be running. " 12374 "Use delete -f if it is not.\n"), fmri); 12375 12376 free(fmri); 12377 return (DELETE_FAILURE); 12378 } 12379 12380 pg = scf_pg_create(g_hndl); 12381 if (pg == NULL) 12382 scfdie(); 12383 12384 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 12385 (void) delete_dependents(pg); 12386 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12387 scfdie(); 12388 12389 scf_pg_destroy(pg); 12390 12391 /* 12392 * If the instance has some external dependencies then we must 12393 * keep them in case the instance is reimported otherwise the 12394 * dependencies would be lost on reimport. 12395 */ 12396 if ((iter = scf_iter_create(g_hndl)) == NULL || 12397 (pg = scf_pg_create(g_hndl)) == NULL) 12398 scfdie(); 12399 12400 if (scf_iter_instance_pgs(iter, inst) < 0) 12401 scfdie(); 12402 12403 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 12404 if (pg_is_external_dependency(pg)) { 12405 external = 1; 12406 continue; 12407 } 12408 12409 if (scf_pg_delete(pg) != 0) { 12410 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12411 scfdie(); 12412 else { 12413 semerr(emsg_permission_denied); 12414 12415 (void) scf_iter_destroy(iter); 12416 (void) scf_pg_destroy(pg); 12417 return (DELETE_FAILURE); 12418 } 12419 } 12420 } 12421 12422 if (err == -1) 12423 scfdie(); 12424 12425 (void) scf_iter_destroy(iter); 12426 (void) scf_pg_destroy(pg); 12427 12428 if (external) { 12429 /* 12430 * All the pgs have been deleted for the instance except 12431 * the ones holding the external dependencies. 12432 * For the job to be complete, we must also delete the 12433 * snapshots associated with the instance. 12434 */ 12435 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 12436 NULL) 12437 scfdie(); 12438 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 12439 scfdie(); 12440 12441 if (scf_iter_instance_snapshots(iter, inst) == -1) 12442 scfdie(); 12443 12444 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 12445 if (_scf_snapshot_delete(snap) != 0) { 12446 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12447 scfdie(); 12448 12449 semerr(emsg_permission_denied); 12450 12451 (void) scf_iter_destroy(iter); 12452 (void) scf_snapshot_destroy(snap); 12453 return (DELETE_FAILURE); 12454 } 12455 } 12456 12457 if (err == -1) 12458 scfdie(); 12459 12460 (void) scf_iter_destroy(iter); 12461 (void) scf_snapshot_destroy(snap); 12462 return (DELETE_SUCCESS_EXTDEPS); 12463 } 12464 12465 if (scf_instance_delete(inst) != 0) { 12466 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12467 scfdie(); 12468 12469 semerr(emsg_permission_denied); 12470 12471 return (DELETE_FAILURE); 12472 } 12473 12474 return (DELETE_SUCCESS_NOEXTDEPS); 12475 } 12476 12477 /* 12478 * lscf_service_delete() deletes a service. Before calling 12479 * scf_service_delete(), though, we call lscf_instance_delete() for 12480 * each of the instances and delete dependencies in other entities 12481 * which were created as "dependents" of this service. If there are 12482 * dependencies which were created for other entities, then we delete 12483 * all other property groups in the service and leave it as "empty". 12484 * 12485 * lscf_service_delete() verifies that there is no external dependency 12486 * pgs at the instance & service level before suppressing the service. 12487 * If there is, then we must not remove them now in case the service 12488 * is re-imported otherwise the dependencies would be lost. The external 12489 * dependency pgs will be removed if the dependencies are removed. 12490 * 12491 * Returns: 12492 * DELETE_FAILURE on failure 12493 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12494 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12495 */ 12496 static int 12497 lscf_service_delete(scf_service_t *svc, int force) 12498 { 12499 int r; 12500 scf_instance_t *inst; 12501 scf_propertygroup_t *pg; 12502 scf_iter_t *iter; 12503 int ret; 12504 int external = 0; 12505 12506 if ((inst = scf_instance_create(g_hndl)) == NULL || 12507 (pg = scf_pg_create(g_hndl)) == NULL || 12508 (iter = scf_iter_create(g_hndl)) == NULL) 12509 scfdie(); 12510 12511 if (scf_iter_service_instances(iter, svc) != 0) 12512 scfdie(); 12513 12514 for (r = scf_iter_next_instance(iter, inst); 12515 r == 1; 12516 r = scf_iter_next_instance(iter, inst)) { 12517 12518 ret = lscf_instance_delete(inst, force); 12519 if (ret == DELETE_FAILURE) { 12520 scf_iter_destroy(iter); 12521 scf_pg_destroy(pg); 12522 scf_instance_destroy(inst); 12523 return (DELETE_FAILURE); 12524 } 12525 12526 /* 12527 * Record the fact that there is some external dependencies 12528 * at the instance level. 12529 */ 12530 if (ret == DELETE_SUCCESS_EXTDEPS) 12531 external |= 1; 12532 } 12533 12534 if (r != 0) 12535 scfdie(); 12536 12537 /* Delete dependency property groups in dependent services. */ 12538 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12539 (void) delete_dependents(pg); 12540 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12541 scfdie(); 12542 12543 scf_iter_destroy(iter); 12544 scf_pg_destroy(pg); 12545 scf_instance_destroy(inst); 12546 12547 /* 12548 * If the service has some external dependencies then we don't 12549 * want to remove them in case the service is re-imported. 12550 */ 12551 if ((pg = scf_pg_create(g_hndl)) == NULL || 12552 (iter = scf_iter_create(g_hndl)) == NULL) 12553 scfdie(); 12554 12555 if (scf_iter_service_pgs(iter, svc) < 0) 12556 scfdie(); 12557 12558 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12559 if (pg_is_external_dependency(pg)) { 12560 external |= 2; 12561 continue; 12562 } 12563 12564 if (scf_pg_delete(pg) != 0) { 12565 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12566 scfdie(); 12567 else { 12568 semerr(emsg_permission_denied); 12569 12570 (void) scf_iter_destroy(iter); 12571 (void) scf_pg_destroy(pg); 12572 return (DELETE_FAILURE); 12573 } 12574 } 12575 } 12576 12577 if (r == -1) 12578 scfdie(); 12579 12580 (void) scf_iter_destroy(iter); 12581 (void) scf_pg_destroy(pg); 12582 12583 if (external != 0) 12584 return (DELETE_SUCCESS_EXTDEPS); 12585 12586 if (scf_service_delete(svc) == 0) 12587 return (DELETE_SUCCESS_NOEXTDEPS); 12588 12589 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12590 scfdie(); 12591 12592 semerr(emsg_permission_denied); 12593 return (DELETE_FAILURE); 12594 } 12595 12596 static int 12597 delete_callback(void *data, scf_walkinfo_t *wip) 12598 { 12599 int force = (int)data; 12600 12601 if (wip->inst != NULL) 12602 (void) lscf_instance_delete(wip->inst, force); 12603 else 12604 (void) lscf_service_delete(wip->svc, force); 12605 12606 return (0); 12607 } 12608 12609 void 12610 lscf_delete(const char *fmri, int force) 12611 { 12612 scf_service_t *svc; 12613 scf_instance_t *inst; 12614 int ret; 12615 12616 lscf_prep_hndl(); 12617 12618 if (cur_snap != NULL) { 12619 if (!snaplevel_is_instance(cur_level)) { 12620 char *buf; 12621 12622 buf = safe_malloc(max_scf_name_len + 1); 12623 if (scf_instance_get_name(cur_inst, buf, 12624 max_scf_name_len + 1) >= 0) { 12625 if (strcmp(buf, fmri) == 0) { 12626 semerr(emsg_cant_modify_snapshots); 12627 free(buf); 12628 return; 12629 } 12630 } else if (scf_error() != SCF_ERROR_DELETED) { 12631 scfdie(); 12632 } 12633 free(buf); 12634 } 12635 } else if (cur_inst != NULL) { 12636 /* EMPTY */; 12637 } else if (cur_svc != NULL) { 12638 inst = scf_instance_create(g_hndl); 12639 if (inst == NULL) 12640 scfdie(); 12641 12642 if (scf_service_get_instance(cur_svc, fmri, inst) == 12643 SCF_SUCCESS) { 12644 (void) lscf_instance_delete(inst, force); 12645 scf_instance_destroy(inst); 12646 return; 12647 } 12648 12649 if (scf_error() != SCF_ERROR_NOT_FOUND && 12650 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12651 scfdie(); 12652 12653 scf_instance_destroy(inst); 12654 } else { 12655 assert(cur_scope != NULL); 12656 12657 svc = scf_service_create(g_hndl); 12658 if (svc == NULL) 12659 scfdie(); 12660 12661 if (scf_scope_get_service(cur_scope, fmri, svc) == 12662 SCF_SUCCESS) { 12663 (void) lscf_service_delete(svc, force); 12664 scf_service_destroy(svc); 12665 return; 12666 } 12667 12668 if (scf_error() != SCF_ERROR_NOT_FOUND && 12669 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12670 scfdie(); 12671 12672 scf_service_destroy(svc); 12673 } 12674 12675 /* 12676 * Match FMRI to entity. 12677 */ 12678 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12679 delete_callback, (void *)force, NULL, semerr)) != 0) { 12680 semerr(gettext("Failed to walk instances: %s\n"), 12681 scf_strerror(ret)); 12682 } 12683 } 12684 12685 12686 12687 /* 12688 * :properties commands. These all end with "pg" or "prop" and generally 12689 * operate on the currently selected entity. 12690 */ 12691 12692 /* 12693 * Property listing. List the property groups, properties, their types and 12694 * their values for the currently selected entity. 12695 */ 12696 static void 12697 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12698 { 12699 char *buf; 12700 uint32_t flags; 12701 12702 buf = safe_malloc(max_scf_pg_type_len + 1); 12703 12704 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12705 scfdie(); 12706 12707 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12708 scfdie(); 12709 12710 safe_printf("%-*s %s", namewidth, name, buf); 12711 12712 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12713 safe_printf("\tNONPERSISTENT"); 12714 12715 safe_printf("\n"); 12716 12717 free(buf); 12718 } 12719 12720 static boolean_t 12721 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12722 { 12723 if (scf_property_get_value(prop, val) == 0) { 12724 return (B_FALSE); 12725 } else { 12726 switch (scf_error()) { 12727 case SCF_ERROR_NOT_FOUND: 12728 return (B_FALSE); 12729 case SCF_ERROR_PERMISSION_DENIED: 12730 case SCF_ERROR_CONSTRAINT_VIOLATED: 12731 return (B_TRUE); 12732 default: 12733 scfdie(); 12734 /*NOTREACHED*/ 12735 } 12736 } 12737 } 12738 12739 static void 12740 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12741 { 12742 scf_iter_t *iter; 12743 scf_value_t *val; 12744 const char *type; 12745 int multiple_strings = 0; 12746 int ret; 12747 12748 if ((iter = scf_iter_create(g_hndl)) == NULL || 12749 (val = scf_value_create(g_hndl)) == NULL) 12750 scfdie(); 12751 12752 type = prop_to_typestr(prop); 12753 assert(type != NULL); 12754 12755 safe_printf("%-*s %-7s ", len, name, type); 12756 12757 if (prop_has_multiple_values(prop, val) && 12758 (scf_value_type(val) == SCF_TYPE_ASTRING || 12759 scf_value_type(val) == SCF_TYPE_USTRING)) 12760 multiple_strings = 1; 12761 12762 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12763 scfdie(); 12764 12765 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12766 char *buf; 12767 ssize_t vlen, szret; 12768 12769 vlen = scf_value_get_as_string(val, NULL, 0); 12770 if (vlen < 0) 12771 scfdie(); 12772 12773 buf = safe_malloc(vlen + 1); 12774 12775 szret = scf_value_get_as_string(val, buf, vlen + 1); 12776 if (szret < 0) 12777 scfdie(); 12778 assert(szret <= vlen); 12779 12780 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12781 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12782 safe_printf(" \""); 12783 (void) quote_and_print(buf, stdout, 0); 12784 (void) putchar('"'); 12785 if (ferror(stdout)) { 12786 (void) putchar('\n'); 12787 uu_die(gettext("Error writing to stdout.\n")); 12788 } 12789 } else { 12790 safe_printf(" %s", buf); 12791 } 12792 12793 free(buf); 12794 } 12795 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12796 scfdie(); 12797 12798 if (putchar('\n') != '\n') 12799 uu_die(gettext("Could not output newline")); 12800 } 12801 12802 /* 12803 * Outputs template property group info for the describe subcommand. 12804 * If 'templates' == 2, verbose output is printed in the format expected 12805 * for describe -v, which includes all templates fields. If pg is 12806 * not NULL, we're describing the template data, not an existing property 12807 * group, and formatting should be appropriate for describe -t. 12808 */ 12809 static void 12810 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12811 { 12812 char *buf; 12813 uint8_t required; 12814 scf_property_t *stability_prop; 12815 scf_value_t *stability_val; 12816 12817 if (templates == 0) 12818 return; 12819 12820 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12821 (stability_val = scf_value_create(g_hndl)) == NULL) 12822 scfdie(); 12823 12824 if (templates == 2 && pg != NULL) { 12825 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12826 stability_prop) == 0) { 12827 if (prop_check_type(stability_prop, 12828 SCF_TYPE_ASTRING) == 0 && 12829 prop_get_val(stability_prop, stability_val) == 0) { 12830 char *stability; 12831 12832 stability = safe_malloc(max_scf_value_len + 1); 12833 12834 if (scf_value_get_astring(stability_val, 12835 stability, max_scf_value_len + 1) == -1 && 12836 scf_error() != SCF_ERROR_NOT_FOUND) 12837 scfdie(); 12838 12839 safe_printf("%s%s: %s\n", TMPL_INDENT, 12840 gettext("stability"), stability); 12841 12842 free(stability); 12843 } 12844 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12845 scfdie(); 12846 } 12847 12848 scf_property_destroy(stability_prop); 12849 scf_value_destroy(stability_val); 12850 12851 if (pgt == NULL) 12852 return; 12853 12854 if (pg == NULL || templates == 2) { 12855 /* print type info only if scf_tmpl_pg_name succeeds */ 12856 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12857 if (pg != NULL) 12858 safe_printf("%s", TMPL_INDENT); 12859 safe_printf("%s: ", gettext("name")); 12860 safe_printf("%s\n", buf); 12861 free(buf); 12862 } 12863 12864 /* print type info only if scf_tmpl_pg_type succeeds */ 12865 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12866 if (pg != NULL) 12867 safe_printf("%s", TMPL_INDENT); 12868 safe_printf("%s: ", gettext("type")); 12869 safe_printf("%s\n", buf); 12870 free(buf); 12871 } 12872 } 12873 12874 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12875 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12876 required ? "true" : "false"); 12877 12878 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12879 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12880 buf); 12881 free(buf); 12882 } 12883 12884 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12885 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12886 buf); 12887 free(buf); 12888 } 12889 12890 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12891 if (templates == 2) 12892 safe_printf("%s%s: %s\n", TMPL_INDENT, 12893 gettext("description"), buf); 12894 else 12895 safe_printf("%s%s\n", TMPL_INDENT, buf); 12896 free(buf); 12897 } 12898 12899 } 12900 12901 /* 12902 * With as_value set to true, indent as appropriate for the value level. 12903 * If false, indent to appropriate level for inclusion in constraint 12904 * or choice printout. 12905 */ 12906 static void 12907 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12908 int as_value) 12909 { 12910 char *buf; 12911 12912 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12913 if (as_value == 0) 12914 safe_printf("%s", TMPL_CHOICE_INDENT); 12915 else 12916 safe_printf("%s", TMPL_INDENT); 12917 safe_printf("%s: %s\n", gettext("value common name"), buf); 12918 free(buf); 12919 } 12920 12921 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12922 if (as_value == 0) 12923 safe_printf("%s", TMPL_CHOICE_INDENT); 12924 else 12925 safe_printf("%s", TMPL_INDENT); 12926 safe_printf("%s: %s\n", gettext("value description"), buf); 12927 free(buf); 12928 } 12929 } 12930 12931 static void 12932 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12933 { 12934 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12935 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12936 safe_printf("%s\n", val_buf); 12937 12938 print_template_value_details(prt, val_buf, 1); 12939 } 12940 12941 static void 12942 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12943 { 12944 int i, printed = 0; 12945 scf_values_t values; 12946 scf_count_ranges_t c_ranges; 12947 scf_int_ranges_t i_ranges; 12948 12949 printed = 0; 12950 i = 0; 12951 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12952 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12953 gettext("value constraints")); 12954 printed++; 12955 for (i = 0; i < values.value_count; ++i) { 12956 safe_printf("%s%s: %s\n", TMPL_INDENT, 12957 gettext("value name"), values.values_as_strings[i]); 12958 if (verbose == 1) 12959 print_template_value_details(prt, 12960 values.values_as_strings[i], 0); 12961 } 12962 12963 scf_values_destroy(&values); 12964 } 12965 12966 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12967 if (printed++ == 0) 12968 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12969 gettext("value constraints")); 12970 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12971 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12972 gettext("range"), c_ranges.scr_min[i], 12973 c_ranges.scr_max[i]); 12974 } 12975 scf_count_ranges_destroy(&c_ranges); 12976 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12977 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 12978 if (printed++ == 0) 12979 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12980 gettext("value constraints")); 12981 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12982 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12983 gettext("range"), i_ranges.sir_min[i], 12984 i_ranges.sir_max[i]); 12985 } 12986 scf_int_ranges_destroy(&i_ranges); 12987 } 12988 } 12989 12990 static void 12991 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 12992 { 12993 int i = 0, printed = 0; 12994 scf_values_t values; 12995 scf_count_ranges_t c_ranges; 12996 scf_int_ranges_t i_ranges; 12997 12998 printed = 0; 12999 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 13000 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13001 gettext("value constraints")); 13002 printed++; 13003 for (i = 0; i < values.value_count; i++) { 13004 safe_printf("%s%s: %s\n", TMPL_INDENT, 13005 gettext("value name"), values.values_as_strings[i]); 13006 if (verbose == 1) 13007 print_template_value_details(prt, 13008 values.values_as_strings[i], 0); 13009 } 13010 13011 scf_values_destroy(&values); 13012 } 13013 13014 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 13015 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 13016 if (printed++ == 0) 13017 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13018 gettext("value choices")); 13019 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 13020 gettext("range"), c_ranges.scr_min[i], 13021 c_ranges.scr_max[i]); 13022 } 13023 scf_count_ranges_destroy(&c_ranges); 13024 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 13025 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 13026 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 13027 if (printed++ == 0) 13028 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13029 gettext("value choices")); 13030 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 13031 gettext("range"), i_ranges.sir_min[i], 13032 i_ranges.sir_max[i]); 13033 } 13034 scf_int_ranges_destroy(&i_ranges); 13035 } 13036 } 13037 13038 static void 13039 list_values_by_template(scf_prop_tmpl_t *prt) 13040 { 13041 print_template_constraints(prt, 1); 13042 print_template_choices(prt, 1); 13043 } 13044 13045 static void 13046 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 13047 { 13048 char *val_buf; 13049 scf_iter_t *iter; 13050 scf_value_t *val; 13051 int ret; 13052 13053 if ((iter = scf_iter_create(g_hndl)) == NULL || 13054 (val = scf_value_create(g_hndl)) == NULL) 13055 scfdie(); 13056 13057 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 13058 scfdie(); 13059 13060 val_buf = safe_malloc(max_scf_value_len + 1); 13061 13062 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13063 if (scf_value_get_as_string(val, val_buf, 13064 max_scf_value_len + 1) < 0) 13065 scfdie(); 13066 13067 print_template_value(prt, val_buf); 13068 } 13069 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 13070 scfdie(); 13071 free(val_buf); 13072 13073 print_template_constraints(prt, 0); 13074 print_template_choices(prt, 0); 13075 13076 } 13077 13078 /* 13079 * Outputs property info for the describe subcommand 13080 * Verbose output if templates == 2, -v option of svccfg describe 13081 * Displays template data if prop is not NULL, -t option of svccfg describe 13082 */ 13083 static void 13084 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 13085 { 13086 char *buf; 13087 uint8_t u_buf; 13088 int i; 13089 uint64_t min, max; 13090 scf_values_t values; 13091 13092 if (prt == NULL || templates == 0) 13093 return; 13094 13095 if (prop == NULL) { 13096 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 13097 if (scf_tmpl_prop_name(prt, &buf) > 0) { 13098 safe_printf("%s\n", buf); 13099 free(buf); 13100 } else 13101 safe_printf("(%s)\n", gettext("any")); 13102 } 13103 13104 if (prop == NULL || templates == 2) { 13105 if (prop != NULL) 13106 safe_printf("%s", TMPL_INDENT); 13107 else 13108 safe_printf("%s", TMPL_VALUE_INDENT); 13109 safe_printf("%s: ", gettext("type")); 13110 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 13111 safe_printf("%s\n", buf); 13112 free(buf); 13113 } else 13114 safe_printf("(%s)\n", gettext("any")); 13115 } 13116 13117 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 13118 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 13119 u_buf ? "true" : "false"); 13120 13121 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 13122 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 13123 buf); 13124 free(buf); 13125 } 13126 13127 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 13128 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 13129 buf); 13130 free(buf); 13131 } 13132 13133 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 13134 safe_printf("%s%s\n", TMPL_INDENT, buf); 13135 free(buf); 13136 } 13137 13138 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 13139 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 13140 scf_tmpl_visibility_to_string(u_buf)); 13141 13142 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 13143 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13144 gettext("minimum number of values"), min); 13145 if (max == ULLONG_MAX) { 13146 safe_printf("%s%s: %s\n", TMPL_INDENT, 13147 gettext("maximum number of values"), 13148 gettext("unlimited")); 13149 } else { 13150 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13151 gettext("maximum number of values"), max); 13152 } 13153 } 13154 13155 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 13156 for (i = 0; i < values.value_count; i++) { 13157 if (i == 0) { 13158 safe_printf("%s%s:", TMPL_INDENT, 13159 gettext("internal separators")); 13160 } 13161 safe_printf(" \"%s\"", values.values_as_strings[i]); 13162 } 13163 safe_printf("\n"); 13164 } 13165 13166 if (templates != 2) 13167 return; 13168 13169 if (prop != NULL) 13170 list_values_tmpl(prt, prop); 13171 else 13172 list_values_by_template(prt); 13173 } 13174 13175 static char * 13176 read_astring(scf_propertygroup_t *pg, const char *prop_name) 13177 { 13178 char *rv; 13179 13180 rv = _scf_read_single_astring_from_pg(pg, prop_name); 13181 if (rv == NULL) { 13182 switch (scf_error()) { 13183 case SCF_ERROR_NOT_FOUND: 13184 break; 13185 default: 13186 scfdie(); 13187 } 13188 } 13189 return (rv); 13190 } 13191 13192 static void 13193 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 13194 { 13195 size_t doc_len; 13196 size_t man_len; 13197 char *pg_name; 13198 char *text = NULL; 13199 int rv; 13200 13201 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 13202 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 13203 pg_name = safe_malloc(max_scf_name_len + 1); 13204 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 13205 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 13206 scfdie(); 13207 } 13208 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 13209 /* Display doc_link and and uri */ 13210 safe_printf("%s%s:\n", TMPL_INDENT, 13211 gettext("doc_link")); 13212 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 13213 if (text != NULL) { 13214 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13215 TMPL_INDENT, gettext("name"), text); 13216 uu_free(text); 13217 } 13218 text = read_astring(pg, SCF_PROPERTY_TM_URI); 13219 if (text != NULL) { 13220 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 13221 gettext("uri"), text); 13222 uu_free(text); 13223 } 13224 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 13225 man_len) == 0) { 13226 /* Display manpage title, section and path */ 13227 safe_printf("%s%s:\n", TMPL_INDENT, 13228 gettext("manpage")); 13229 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 13230 if (text != NULL) { 13231 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13232 TMPL_INDENT, gettext("title"), text); 13233 uu_free(text); 13234 } 13235 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 13236 if (text != NULL) { 13237 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13238 TMPL_INDENT, gettext("section"), text); 13239 uu_free(text); 13240 } 13241 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 13242 if (text != NULL) { 13243 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13244 TMPL_INDENT, gettext("manpath"), text); 13245 uu_free(text); 13246 } 13247 } 13248 } 13249 if (rv == -1) 13250 scfdie(); 13251 13252 done: 13253 free(pg_name); 13254 } 13255 13256 static void 13257 list_entity_tmpl(int templates) 13258 { 13259 char *common_name = NULL; 13260 char *description = NULL; 13261 char *locale = NULL; 13262 scf_iter_t *iter; 13263 scf_propertygroup_t *pg; 13264 scf_property_t *prop; 13265 int r; 13266 scf_value_t *val; 13267 13268 if ((pg = scf_pg_create(g_hndl)) == NULL || 13269 (prop = scf_property_create(g_hndl)) == NULL || 13270 (val = scf_value_create(g_hndl)) == NULL || 13271 (iter = scf_iter_create(g_hndl)) == NULL) 13272 scfdie(); 13273 13274 locale = setlocale(LC_MESSAGES, NULL); 13275 13276 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 13277 common_name = safe_malloc(max_scf_value_len + 1); 13278 13279 /* Try both the current locale and the "C" locale. */ 13280 if (scf_pg_get_property(pg, locale, prop) == 0 || 13281 (scf_error() == SCF_ERROR_NOT_FOUND && 13282 scf_pg_get_property(pg, "C", prop) == 0)) { 13283 if (prop_get_val(prop, val) == 0 && 13284 scf_value_get_ustring(val, common_name, 13285 max_scf_value_len + 1) != -1) { 13286 safe_printf("%s%s: %s\n", TMPL_INDENT, 13287 gettext("common name"), common_name); 13288 } 13289 } 13290 } 13291 13292 /* 13293 * Do description, manpages, and doc links if templates == 2. 13294 */ 13295 if (templates == 2) { 13296 /* Get the description. */ 13297 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 13298 description = 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, description, 13306 max_scf_value_len + 1) != -1) { 13307 safe_printf("%s%s: %s\n", TMPL_INDENT, 13308 gettext("description"), 13309 description); 13310 } 13311 } 13312 } 13313 13314 /* Process doc_link & manpage elements. */ 13315 if (cur_level != NULL) { 13316 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 13317 SCF_GROUP_TEMPLATE); 13318 } else if (cur_inst != NULL) { 13319 r = scf_iter_instance_pgs_typed(iter, cur_inst, 13320 SCF_GROUP_TEMPLATE); 13321 } else { 13322 r = scf_iter_service_pgs_typed(iter, cur_svc, 13323 SCF_GROUP_TEMPLATE); 13324 } 13325 if (r == 0) { 13326 display_documentation(iter, pg); 13327 } 13328 } 13329 13330 free(common_name); 13331 free(description); 13332 scf_pg_destroy(pg); 13333 scf_property_destroy(prop); 13334 scf_value_destroy(val); 13335 scf_iter_destroy(iter); 13336 } 13337 13338 static void 13339 listtmpl(const char *pattern, int templates) 13340 { 13341 scf_pg_tmpl_t *pgt; 13342 scf_prop_tmpl_t *prt; 13343 char *snapbuf = NULL; 13344 char *fmribuf; 13345 char *pg_name = NULL, *prop_name = NULL; 13346 ssize_t prop_name_size; 13347 char *qual_prop_name; 13348 char *search_name; 13349 int listed = 0; 13350 13351 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13352 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 13353 scfdie(); 13354 13355 fmribuf = safe_malloc(max_scf_name_len + 1); 13356 qual_prop_name = safe_malloc(max_scf_name_len + 1); 13357 13358 if (cur_snap != NULL) { 13359 snapbuf = safe_malloc(max_scf_name_len + 1); 13360 if (scf_snapshot_get_name(cur_snap, snapbuf, 13361 max_scf_name_len + 1) < 0) 13362 scfdie(); 13363 } 13364 13365 if (cur_inst != NULL) { 13366 if (scf_instance_to_fmri(cur_inst, fmribuf, 13367 max_scf_name_len + 1) < 0) 13368 scfdie(); 13369 } else if (cur_svc != NULL) { 13370 if (scf_service_to_fmri(cur_svc, fmribuf, 13371 max_scf_name_len + 1) < 0) 13372 scfdie(); 13373 } else 13374 abort(); 13375 13376 /* If pattern is specified, we want to list only those items. */ 13377 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) { 13378 listed = 0; 13379 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 13380 fnmatch(pattern, pg_name, 0) == 0)) { 13381 list_pg_tmpl(pgt, NULL, templates); 13382 listed++; 13383 } 13384 13385 scf_tmpl_prop_reset(prt); 13386 13387 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) { 13388 search_name = NULL; 13389 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 13390 if ((prop_name_size > 0) && (pg_name != NULL)) { 13391 if (snprintf(qual_prop_name, 13392 max_scf_name_len + 1, "%s/%s", 13393 pg_name, prop_name) >= 13394 max_scf_name_len + 1) { 13395 prop_name_size = -1; 13396 } else { 13397 search_name = qual_prop_name; 13398 } 13399 } 13400 if (listed > 0 || pattern == NULL || 13401 (prop_name_size > 0 && 13402 fnmatch(pattern, search_name, 13403 FNM_PATHNAME) == 0)) 13404 list_prop_tmpl(prt, NULL, templates); 13405 if (prop_name != NULL) { 13406 free(prop_name); 13407 prop_name = NULL; 13408 } 13409 } 13410 if (pg_name != NULL) { 13411 free(pg_name); 13412 pg_name = NULL; 13413 } 13414 } 13415 13416 scf_tmpl_prop_destroy(prt); 13417 scf_tmpl_pg_destroy(pgt); 13418 free(snapbuf); 13419 free(fmribuf); 13420 free(qual_prop_name); 13421 } 13422 13423 static void 13424 listprop(const char *pattern, int only_pgs, int templates) 13425 { 13426 scf_propertygroup_t *pg; 13427 scf_property_t *prop; 13428 scf_iter_t *iter, *piter; 13429 char *pgnbuf, *prnbuf, *ppnbuf; 13430 scf_pg_tmpl_t *pgt, *pgtp; 13431 scf_prop_tmpl_t *prt; 13432 13433 void **objects; 13434 char **names; 13435 void **tmpls; 13436 int allocd, i; 13437 13438 int ret; 13439 ssize_t pgnlen, prnlen, szret; 13440 size_t max_len = 0; 13441 13442 if (cur_svc == NULL && cur_inst == NULL) { 13443 semerr(emsg_entity_not_selected); 13444 return; 13445 } 13446 13447 if ((pg = scf_pg_create(g_hndl)) == NULL || 13448 (prop = scf_property_create(g_hndl)) == NULL || 13449 (iter = scf_iter_create(g_hndl)) == NULL || 13450 (piter = scf_iter_create(g_hndl)) == NULL || 13451 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13452 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 13453 scfdie(); 13454 13455 prnbuf = safe_malloc(max_scf_name_len + 1); 13456 13457 if (cur_level != NULL) 13458 ret = scf_iter_snaplevel_pgs(iter, cur_level); 13459 else if (cur_inst != NULL) 13460 ret = scf_iter_instance_pgs(iter, cur_inst); 13461 else 13462 ret = scf_iter_service_pgs(iter, cur_svc); 13463 if (ret != 0) { 13464 return; 13465 } 13466 13467 /* 13468 * We want to only list items which match pattern, and we want the 13469 * second column to line up, so during the first pass we'll save 13470 * matching items, their names, and their templates in objects, 13471 * names, and tmpls, computing the maximum name length as we go, 13472 * and then we'll print them out. 13473 * 13474 * Note: We always keep an extra slot available so the array can be 13475 * NULL-terminated. 13476 */ 13477 i = 0; 13478 allocd = 1; 13479 objects = safe_malloc(sizeof (*objects)); 13480 names = safe_malloc(sizeof (*names)); 13481 tmpls = safe_malloc(sizeof (*tmpls)); 13482 13483 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13484 int new_pg = 0; 13485 int print_props = 0; 13486 pgtp = NULL; 13487 13488 pgnlen = scf_pg_get_name(pg, NULL, 0); 13489 if (pgnlen < 0) 13490 scfdie(); 13491 13492 pgnbuf = safe_malloc(pgnlen + 1); 13493 13494 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 13495 if (szret < 0) 13496 scfdie(); 13497 assert(szret <= pgnlen); 13498 13499 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) { 13500 if (scf_error() != SCF_ERROR_NOT_FOUND) 13501 scfdie(); 13502 pgtp = NULL; 13503 } else { 13504 pgtp = pgt; 13505 } 13506 13507 if (pattern == NULL || 13508 fnmatch(pattern, pgnbuf, 0) == 0) { 13509 if (i+1 >= allocd) { 13510 allocd *= 2; 13511 objects = realloc(objects, 13512 sizeof (*objects) * allocd); 13513 names = 13514 realloc(names, sizeof (*names) * allocd); 13515 tmpls = realloc(tmpls, 13516 sizeof (*tmpls) * allocd); 13517 if (objects == NULL || names == NULL || 13518 tmpls == NULL) 13519 uu_die(gettext("Out of memory")); 13520 } 13521 objects[i] = pg; 13522 names[i] = pgnbuf; 13523 13524 if (pgtp == NULL) 13525 tmpls[i] = NULL; 13526 else 13527 tmpls[i] = pgt; 13528 13529 ++i; 13530 13531 if (pgnlen > max_len) 13532 max_len = pgnlen; 13533 13534 new_pg = 1; 13535 print_props = 1; 13536 } 13537 13538 if (only_pgs) { 13539 if (new_pg) { 13540 pg = scf_pg_create(g_hndl); 13541 if (pg == NULL) 13542 scfdie(); 13543 pgt = scf_tmpl_pg_create(g_hndl); 13544 if (pgt == NULL) 13545 scfdie(); 13546 } else 13547 free(pgnbuf); 13548 13549 continue; 13550 } 13551 13552 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13553 scfdie(); 13554 13555 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13556 prnlen = scf_property_get_name(prop, prnbuf, 13557 max_scf_name_len + 1); 13558 if (prnlen < 0) 13559 scfdie(); 13560 13561 /* Will prepend the property group name and a slash. */ 13562 prnlen += pgnlen + 1; 13563 13564 ppnbuf = safe_malloc(prnlen + 1); 13565 13566 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13567 prnbuf) < 0) 13568 uu_die("snprintf"); 13569 13570 if (pattern == NULL || print_props == 1 || 13571 fnmatch(pattern, ppnbuf, 0) == 0) { 13572 if (i+1 >= allocd) { 13573 allocd *= 2; 13574 objects = realloc(objects, 13575 sizeof (*objects) * allocd); 13576 names = realloc(names, 13577 sizeof (*names) * allocd); 13578 tmpls = realloc(tmpls, 13579 sizeof (*tmpls) * allocd); 13580 if (objects == NULL || names == NULL || 13581 tmpls == NULL) 13582 uu_die(gettext( 13583 "Out of memory")); 13584 } 13585 13586 objects[i] = prop; 13587 names[i] = ppnbuf; 13588 13589 if (pgtp != NULL) { 13590 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13591 prt, 0) < 0) { 13592 if (scf_error() != 13593 SCF_ERROR_NOT_FOUND) 13594 scfdie(); 13595 tmpls[i] = NULL; 13596 } else { 13597 tmpls[i] = prt; 13598 } 13599 } else { 13600 tmpls[i] = NULL; 13601 } 13602 13603 ++i; 13604 13605 if (prnlen > max_len) 13606 max_len = prnlen; 13607 13608 prop = scf_property_create(g_hndl); 13609 prt = scf_tmpl_prop_create(g_hndl); 13610 } else { 13611 free(ppnbuf); 13612 } 13613 } 13614 13615 if (new_pg) { 13616 pg = scf_pg_create(g_hndl); 13617 if (pg == NULL) 13618 scfdie(); 13619 pgt = scf_tmpl_pg_create(g_hndl); 13620 if (pgt == NULL) 13621 scfdie(); 13622 } else 13623 free(pgnbuf); 13624 } 13625 if (ret != 0) 13626 scfdie(); 13627 13628 objects[i] = NULL; 13629 13630 scf_pg_destroy(pg); 13631 scf_tmpl_pg_destroy(pgt); 13632 scf_property_destroy(prop); 13633 scf_tmpl_prop_destroy(prt); 13634 13635 for (i = 0; objects[i] != NULL; ++i) { 13636 if (strchr(names[i], '/') == NULL) { 13637 /* property group */ 13638 pg = (scf_propertygroup_t *)objects[i]; 13639 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13640 list_pg_info(pg, names[i], max_len); 13641 list_pg_tmpl(pgt, pg, templates); 13642 free(names[i]); 13643 scf_pg_destroy(pg); 13644 if (pgt != NULL) 13645 scf_tmpl_pg_destroy(pgt); 13646 } else { 13647 /* property */ 13648 prop = (scf_property_t *)objects[i]; 13649 prt = (scf_prop_tmpl_t *)tmpls[i]; 13650 list_prop_info(prop, names[i], max_len); 13651 list_prop_tmpl(prt, prop, templates); 13652 free(names[i]); 13653 scf_property_destroy(prop); 13654 if (prt != NULL) 13655 scf_tmpl_prop_destroy(prt); 13656 } 13657 } 13658 13659 free(names); 13660 free(objects); 13661 free(tmpls); 13662 } 13663 13664 void 13665 lscf_listpg(const char *pattern) 13666 { 13667 lscf_prep_hndl(); 13668 13669 listprop(pattern, 1, 0); 13670 } 13671 13672 /* 13673 * Property group and property creation, setting, and deletion. setprop (and 13674 * its alias, addprop) can either create a property group of a given type, or 13675 * it can create or set a property to a given type and list of values. 13676 */ 13677 void 13678 lscf_addpg(const char *name, const char *type, const char *flags) 13679 { 13680 scf_propertygroup_t *pg; 13681 int ret; 13682 uint32_t flgs = 0; 13683 const char *cp; 13684 13685 13686 lscf_prep_hndl(); 13687 13688 if (cur_snap != NULL) { 13689 semerr(emsg_cant_modify_snapshots); 13690 return; 13691 } 13692 13693 if (cur_inst == NULL && cur_svc == NULL) { 13694 semerr(emsg_entity_not_selected); 13695 return; 13696 } 13697 13698 if (flags != NULL) { 13699 for (cp = flags; *cp != '\0'; ++cp) { 13700 switch (*cp) { 13701 case 'P': 13702 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13703 break; 13704 13705 case 'p': 13706 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13707 break; 13708 13709 default: 13710 semerr(gettext("Invalid property group flag " 13711 "%c."), *cp); 13712 return; 13713 } 13714 } 13715 } 13716 13717 pg = scf_pg_create(g_hndl); 13718 if (pg == NULL) 13719 scfdie(); 13720 13721 if (cur_inst != NULL) 13722 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13723 else 13724 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13725 13726 if (ret != SCF_SUCCESS) { 13727 switch (scf_error()) { 13728 case SCF_ERROR_INVALID_ARGUMENT: 13729 semerr(gettext("Name, type, or flags are invalid.\n")); 13730 break; 13731 13732 case SCF_ERROR_EXISTS: 13733 semerr(gettext("Property group already exists.\n")); 13734 break; 13735 13736 case SCF_ERROR_PERMISSION_DENIED: 13737 semerr(emsg_permission_denied); 13738 break; 13739 13740 case SCF_ERROR_BACKEND_ACCESS: 13741 semerr(gettext("Backend refused access.\n")); 13742 break; 13743 13744 default: 13745 scfdie(); 13746 } 13747 } 13748 13749 scf_pg_destroy(pg); 13750 13751 private_refresh(); 13752 } 13753 13754 void 13755 lscf_delpg(char *name) 13756 { 13757 lscf_prep_hndl(); 13758 13759 if (cur_snap != NULL) { 13760 semerr(emsg_cant_modify_snapshots); 13761 return; 13762 } 13763 13764 if (cur_inst == NULL && cur_svc == NULL) { 13765 semerr(emsg_entity_not_selected); 13766 return; 13767 } 13768 13769 if (strchr(name, '/') != NULL) { 13770 semerr(emsg_invalid_pg_name, name); 13771 return; 13772 } 13773 13774 lscf_delprop(name); 13775 } 13776 13777 /* 13778 * scf_delhash() is used to remove the property group related to the 13779 * hash entry for a specific manifest in the repository. pgname will be 13780 * constructed from the location of the manifest file. If deathrow isn't 0, 13781 * manifest file doesn't need to exist (manifest string will be used as 13782 * an absolute path). 13783 */ 13784 void 13785 lscf_delhash(char *manifest, int deathrow) 13786 { 13787 char *pgname; 13788 13789 if (cur_snap != NULL || 13790 cur_inst != NULL || cur_svc != NULL) { 13791 warn(gettext("error, an entity is selected\n")); 13792 return; 13793 } 13794 13795 /* select smf/manifest */ 13796 lscf_select(HASH_SVC); 13797 /* 13798 * Translate the manifest file name to property name. In the deathrow 13799 * case, the manifest file does not need to exist. 13800 */ 13801 pgname = mhash_filename_to_propname(manifest, 13802 deathrow ? B_TRUE : B_FALSE); 13803 if (pgname == NULL) { 13804 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13805 return; 13806 } 13807 /* delete the hash property name */ 13808 lscf_delpg(pgname); 13809 } 13810 13811 void 13812 lscf_listprop(const char *pattern) 13813 { 13814 lscf_prep_hndl(); 13815 13816 listprop(pattern, 0, 0); 13817 } 13818 13819 int 13820 lscf_setprop(const char *pgname, const char *type, const char *value, 13821 const uu_list_t *values) 13822 { 13823 scf_type_t ty, current_ty; 13824 scf_service_t *svc; 13825 scf_propertygroup_t *pg, *parent_pg; 13826 scf_property_t *prop, *parent_prop; 13827 scf_pg_tmpl_t *pgt; 13828 scf_prop_tmpl_t *prt; 13829 int ret, result = 0; 13830 scf_transaction_t *tx; 13831 scf_transaction_entry_t *e; 13832 scf_value_t *v; 13833 uu_list_walk_t *walk; 13834 string_list_t *sp; 13835 char *propname; 13836 int req_quotes = 0; 13837 13838 lscf_prep_hndl(); 13839 13840 if ((e = scf_entry_create(g_hndl)) == NULL || 13841 (svc = scf_service_create(g_hndl)) == NULL || 13842 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13843 (pg = scf_pg_create(g_hndl)) == NULL || 13844 (parent_prop = scf_property_create(g_hndl)) == NULL || 13845 (prop = scf_property_create(g_hndl)) == NULL || 13846 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13847 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13848 (tx = scf_transaction_create(g_hndl)) == NULL) 13849 scfdie(); 13850 13851 if (cur_snap != NULL) { 13852 semerr(emsg_cant_modify_snapshots); 13853 goto fail; 13854 } 13855 13856 if (cur_inst == NULL && cur_svc == NULL) { 13857 semerr(emsg_entity_not_selected); 13858 goto fail; 13859 } 13860 13861 propname = strchr(pgname, '/'); 13862 if (propname == NULL) { 13863 semerr(gettext("Property names must contain a `/'.\n")); 13864 goto fail; 13865 } 13866 13867 *propname = '\0'; 13868 ++propname; 13869 13870 if (type != NULL) { 13871 ty = string_to_type(type); 13872 if (ty == SCF_TYPE_INVALID) { 13873 semerr(gettext("Unknown type \"%s\".\n"), type); 13874 goto fail; 13875 } 13876 } 13877 13878 if (cur_inst != NULL) 13879 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13880 else 13881 ret = scf_service_get_pg(cur_svc, pgname, pg); 13882 if (ret != SCF_SUCCESS) { 13883 switch (scf_error()) { 13884 case SCF_ERROR_NOT_FOUND: 13885 semerr(emsg_no_such_pg, pgname); 13886 goto fail; 13887 13888 case SCF_ERROR_INVALID_ARGUMENT: 13889 semerr(emsg_invalid_pg_name, pgname); 13890 goto fail; 13891 13892 default: 13893 scfdie(); 13894 break; 13895 } 13896 } 13897 13898 do { 13899 if (scf_pg_update(pg) == -1) 13900 scfdie(); 13901 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13902 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13903 scfdie(); 13904 13905 semerr(emsg_permission_denied); 13906 goto fail; 13907 } 13908 13909 ret = scf_pg_get_property(pg, propname, prop); 13910 if (ret == SCF_SUCCESS) { 13911 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13912 scfdie(); 13913 13914 if (type == NULL) 13915 ty = current_ty; 13916 if (scf_transaction_property_change_type(tx, e, 13917 propname, ty) == -1) 13918 scfdie(); 13919 13920 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13921 /* Infer the type, if possible. */ 13922 if (type == NULL) { 13923 /* 13924 * First check if we're an instance and the 13925 * property is set on the service. 13926 */ 13927 if (cur_inst != NULL && 13928 scf_instance_get_parent(cur_inst, 13929 svc) == 0 && 13930 scf_service_get_pg(cur_svc, pgname, 13931 parent_pg) == 0 && 13932 scf_pg_get_property(parent_pg, propname, 13933 parent_prop) == 0 && 13934 scf_property_type(parent_prop, 13935 ¤t_ty) == 0) { 13936 ty = current_ty; 13937 13938 /* Then check for a type set in a template. */ 13939 } else if (scf_tmpl_get_by_pg(pg, pgt, 13940 0) == 0 && 13941 scf_tmpl_get_by_prop(pgt, propname, prt, 13942 0) == 0 && 13943 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13944 ty = current_ty; 13945 13946 /* If type can't be inferred, fail. */ 13947 } else { 13948 semerr(gettext("Type required for new " 13949 "properties.\n")); 13950 goto fail; 13951 } 13952 } 13953 if (scf_transaction_property_new(tx, e, propname, 13954 ty) == -1) 13955 scfdie(); 13956 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13957 semerr(emsg_invalid_prop_name, propname); 13958 goto fail; 13959 } else { 13960 scfdie(); 13961 } 13962 13963 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13964 req_quotes = 1; 13965 13966 if (value != NULL) { 13967 v = string_to_value(value, ty, 0); 13968 13969 if (v == NULL) 13970 goto fail; 13971 13972 ret = scf_entry_add_value(e, v); 13973 assert(ret == SCF_SUCCESS); 13974 } else { 13975 assert(values != NULL); 13976 13977 walk = uu_list_walk_start((uu_list_t *)values, 13978 UU_DEFAULT); 13979 if (walk == NULL) 13980 uu_die(gettext("Could not walk list")); 13981 13982 for (sp = uu_list_walk_next(walk); sp != NULL; 13983 sp = uu_list_walk_next(walk)) { 13984 v = string_to_value(sp->str, ty, req_quotes); 13985 13986 if (v == NULL) { 13987 scf_entry_destroy_children(e); 13988 goto fail; 13989 } 13990 13991 ret = scf_entry_add_value(e, v); 13992 assert(ret == SCF_SUCCESS); 13993 } 13994 uu_list_walk_end(walk); 13995 } 13996 result = scf_transaction_commit(tx); 13997 13998 scf_transaction_reset(tx); 13999 scf_entry_destroy_children(e); 14000 } while (result == 0); 14001 14002 if (result < 0) { 14003 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14004 scfdie(); 14005 14006 semerr(emsg_permission_denied); 14007 goto fail; 14008 } 14009 14010 ret = 0; 14011 14012 private_refresh(); 14013 14014 goto cleanup; 14015 14016 fail: 14017 ret = -1; 14018 14019 cleanup: 14020 scf_transaction_destroy(tx); 14021 scf_entry_destroy(e); 14022 scf_service_destroy(svc); 14023 scf_pg_destroy(parent_pg); 14024 scf_pg_destroy(pg); 14025 scf_property_destroy(parent_prop); 14026 scf_property_destroy(prop); 14027 scf_tmpl_pg_destroy(pgt); 14028 scf_tmpl_prop_destroy(prt); 14029 14030 return (ret); 14031 } 14032 14033 void 14034 lscf_delprop(char *pgn) 14035 { 14036 char *slash, *pn; 14037 scf_propertygroup_t *pg; 14038 scf_transaction_t *tx; 14039 scf_transaction_entry_t *e; 14040 int ret; 14041 14042 14043 lscf_prep_hndl(); 14044 14045 if (cur_snap != NULL) { 14046 semerr(emsg_cant_modify_snapshots); 14047 return; 14048 } 14049 14050 if (cur_inst == NULL && cur_svc == NULL) { 14051 semerr(emsg_entity_not_selected); 14052 return; 14053 } 14054 14055 pg = scf_pg_create(g_hndl); 14056 if (pg == NULL) 14057 scfdie(); 14058 14059 slash = strchr(pgn, '/'); 14060 if (slash == NULL) { 14061 pn = NULL; 14062 } else { 14063 *slash = '\0'; 14064 pn = slash + 1; 14065 } 14066 14067 if (cur_inst != NULL) 14068 ret = scf_instance_get_pg(cur_inst, pgn, pg); 14069 else 14070 ret = scf_service_get_pg(cur_svc, pgn, pg); 14071 if (ret != SCF_SUCCESS) { 14072 switch (scf_error()) { 14073 case SCF_ERROR_NOT_FOUND: 14074 semerr(emsg_no_such_pg, pgn); 14075 break; 14076 14077 case SCF_ERROR_INVALID_ARGUMENT: 14078 semerr(emsg_invalid_pg_name, pgn); 14079 break; 14080 14081 default: 14082 scfdie(); 14083 } 14084 14085 scf_pg_destroy(pg); 14086 14087 return; 14088 } 14089 14090 if (pn == NULL) { 14091 /* Try to delete the property group. */ 14092 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14093 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14094 scfdie(); 14095 14096 semerr(emsg_permission_denied); 14097 } else { 14098 private_refresh(); 14099 } 14100 14101 scf_pg_destroy(pg); 14102 return; 14103 } 14104 14105 e = scf_entry_create(g_hndl); 14106 tx = scf_transaction_create(g_hndl); 14107 14108 do { 14109 if (scf_pg_update(pg) == -1) 14110 scfdie(); 14111 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 14112 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14113 scfdie(); 14114 14115 semerr(emsg_permission_denied); 14116 break; 14117 } 14118 14119 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 14120 if (scf_error() == SCF_ERROR_NOT_FOUND) { 14121 semerr(gettext("No such property %s/%s.\n"), 14122 pgn, pn); 14123 break; 14124 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14125 semerr(emsg_invalid_prop_name, pn); 14126 break; 14127 } else { 14128 scfdie(); 14129 } 14130 } 14131 14132 ret = scf_transaction_commit(tx); 14133 14134 if (ret == 0) 14135 scf_transaction_reset(tx); 14136 } while (ret == 0); 14137 14138 if (ret < 0) { 14139 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14140 scfdie(); 14141 14142 semerr(emsg_permission_denied); 14143 } else { 14144 private_refresh(); 14145 } 14146 14147 scf_transaction_destroy(tx); 14148 scf_entry_destroy(e); 14149 scf_pg_destroy(pg); 14150 } 14151 14152 /* 14153 * Property editing. 14154 */ 14155 14156 static int 14157 write_edit_script(FILE *strm) 14158 { 14159 char *fmribuf; 14160 ssize_t fmrilen; 14161 14162 scf_propertygroup_t *pg; 14163 scf_property_t *prop; 14164 scf_value_t *val; 14165 scf_type_t ty; 14166 int ret, result = 0; 14167 scf_iter_t *iter, *piter, *viter; 14168 char *buf, *tybuf, *pname; 14169 const char *emsg_write_error; 14170 14171 14172 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 14173 14174 14175 /* select fmri */ 14176 if (cur_inst != NULL) { 14177 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 14178 if (fmrilen < 0) 14179 scfdie(); 14180 fmribuf = safe_malloc(fmrilen + 1); 14181 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 14182 scfdie(); 14183 } else { 14184 assert(cur_svc != NULL); 14185 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 14186 if (fmrilen < 0) 14187 scfdie(); 14188 fmribuf = safe_malloc(fmrilen + 1); 14189 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 14190 scfdie(); 14191 } 14192 14193 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 14194 warn(emsg_write_error, strerror(errno)); 14195 free(fmribuf); 14196 return (-1); 14197 } 14198 14199 free(fmribuf); 14200 14201 14202 if ((pg = scf_pg_create(g_hndl)) == NULL || 14203 (prop = scf_property_create(g_hndl)) == NULL || 14204 (val = scf_value_create(g_hndl)) == NULL || 14205 (iter = scf_iter_create(g_hndl)) == NULL || 14206 (piter = scf_iter_create(g_hndl)) == NULL || 14207 (viter = scf_iter_create(g_hndl)) == NULL) 14208 scfdie(); 14209 14210 buf = safe_malloc(max_scf_name_len + 1); 14211 tybuf = safe_malloc(max_scf_pg_type_len + 1); 14212 pname = safe_malloc(max_scf_name_len + 1); 14213 14214 if (cur_inst != NULL) 14215 ret = scf_iter_instance_pgs(iter, cur_inst); 14216 else 14217 ret = scf_iter_service_pgs(iter, cur_svc); 14218 if (ret != SCF_SUCCESS) 14219 scfdie(); 14220 14221 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 14222 int ret2; 14223 14224 /* 14225 * # delprop pg 14226 * # addpg pg type 14227 */ 14228 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 14229 scfdie(); 14230 14231 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 14232 scfdie(); 14233 14234 if (fprintf(strm, "# Property group \"%s\"\n" 14235 "# delprop %s\n" 14236 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 14237 warn(emsg_write_error, strerror(errno)); 14238 result = -1; 14239 goto out; 14240 } 14241 14242 /* # setprop pg/prop = (values) */ 14243 14244 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 14245 scfdie(); 14246 14247 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 14248 int first = 1; 14249 int ret3; 14250 int multiple; 14251 int is_str; 14252 scf_type_t bty; 14253 14254 if (scf_property_get_name(prop, pname, 14255 max_scf_name_len + 1) < 0) 14256 scfdie(); 14257 14258 if (scf_property_type(prop, &ty) != 0) 14259 scfdie(); 14260 14261 multiple = prop_has_multiple_values(prop, val); 14262 14263 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 14264 pname, scf_type_to_string(ty), multiple ? "(" : "") 14265 < 0) { 14266 warn(emsg_write_error, strerror(errno)); 14267 result = -1; 14268 goto out; 14269 } 14270 14271 (void) scf_type_base_type(ty, &bty); 14272 is_str = (bty == SCF_TYPE_ASTRING); 14273 14274 if (scf_iter_property_values(viter, prop) != 14275 SCF_SUCCESS) 14276 scfdie(); 14277 14278 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 14279 char *buf; 14280 ssize_t buflen; 14281 14282 buflen = scf_value_get_as_string(val, NULL, 0); 14283 if (buflen < 0) 14284 scfdie(); 14285 14286 buf = safe_malloc(buflen + 1); 14287 14288 if (scf_value_get_as_string(val, buf, 14289 buflen + 1) < 0) 14290 scfdie(); 14291 14292 if (first) 14293 first = 0; 14294 else { 14295 if (putc(' ', strm) != ' ') { 14296 warn(emsg_write_error, 14297 strerror(errno)); 14298 result = -1; 14299 goto out; 14300 } 14301 } 14302 14303 if ((is_str && multiple) || 14304 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 14305 (void) putc('"', strm); 14306 (void) quote_and_print(buf, strm, 1); 14307 (void) putc('"', strm); 14308 14309 if (ferror(strm)) { 14310 warn(emsg_write_error, 14311 strerror(errno)); 14312 result = -1; 14313 goto out; 14314 } 14315 } else { 14316 if (fprintf(strm, "%s", buf) < 0) { 14317 warn(emsg_write_error, 14318 strerror(errno)); 14319 result = -1; 14320 goto out; 14321 } 14322 } 14323 14324 free(buf); 14325 } 14326 if (ret3 < 0 && 14327 scf_error() != SCF_ERROR_PERMISSION_DENIED) 14328 scfdie(); 14329 14330 /* Write closing paren if mult-value property */ 14331 if ((multiple && putc(')', strm) == EOF) || 14332 14333 /* Write final newline */ 14334 fputc('\n', strm) == EOF) { 14335 warn(emsg_write_error, strerror(errno)); 14336 result = -1; 14337 goto out; 14338 } 14339 } 14340 if (ret2 < 0) 14341 scfdie(); 14342 14343 if (fputc('\n', strm) == EOF) { 14344 warn(emsg_write_error, strerror(errno)); 14345 result = -1; 14346 goto out; 14347 } 14348 } 14349 if (ret < 0) 14350 scfdie(); 14351 14352 out: 14353 free(pname); 14354 free(tybuf); 14355 free(buf); 14356 scf_iter_destroy(viter); 14357 scf_iter_destroy(piter); 14358 scf_iter_destroy(iter); 14359 scf_value_destroy(val); 14360 scf_property_destroy(prop); 14361 scf_pg_destroy(pg); 14362 14363 if (result == 0) { 14364 if (fflush(strm) != 0) { 14365 warn(emsg_write_error, strerror(errno)); 14366 return (-1); 14367 } 14368 } 14369 14370 return (result); 14371 } 14372 14373 int 14374 lscf_editprop() 14375 { 14376 char *buf, *editor; 14377 size_t bufsz; 14378 int tmpfd; 14379 char tempname[] = TEMP_FILE_PATTERN; 14380 14381 lscf_prep_hndl(); 14382 14383 if (cur_snap != NULL) { 14384 semerr(emsg_cant_modify_snapshots); 14385 return (-1); 14386 } 14387 14388 if (cur_svc == NULL && cur_inst == NULL) { 14389 semerr(emsg_entity_not_selected); 14390 return (-1); 14391 } 14392 14393 tmpfd = mkstemp(tempname); 14394 if (tmpfd == -1) { 14395 semerr(gettext("Could not create temporary file.\n")); 14396 return (-1); 14397 } 14398 14399 (void) strcpy(tempfilename, tempname); 14400 14401 tempfile = fdopen(tmpfd, "r+"); 14402 if (tempfile == NULL) { 14403 warn(gettext("Could not create temporary file.\n")); 14404 if (close(tmpfd) == -1) 14405 warn(gettext("Could not close temporary file: %s.\n"), 14406 strerror(errno)); 14407 14408 remove_tempfile(); 14409 14410 return (-1); 14411 } 14412 14413 if (write_edit_script(tempfile) == -1) { 14414 remove_tempfile(); 14415 return (-1); 14416 } 14417 14418 editor = getenv("EDITOR"); 14419 if (editor == NULL) 14420 editor = "vi"; 14421 14422 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 14423 buf = safe_malloc(bufsz); 14424 14425 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 14426 uu_die(gettext("Error creating editor command")); 14427 14428 if (system(buf) == -1) { 14429 semerr(gettext("Could not launch editor %s: %s\n"), editor, 14430 strerror(errno)); 14431 free(buf); 14432 remove_tempfile(); 14433 return (-1); 14434 } 14435 14436 free(buf); 14437 14438 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 14439 14440 remove_tempfile(); 14441 14442 return (0); 14443 } 14444 14445 static void 14446 add_string(uu_list_t *strlist, const char *str) 14447 { 14448 string_list_t *elem; 14449 elem = safe_malloc(sizeof (*elem)); 14450 uu_list_node_init(elem, &elem->node, string_pool); 14451 elem->str = safe_strdup(str); 14452 if (uu_list_append(strlist, elem) != 0) 14453 uu_die(gettext("libuutil error: %s\n"), 14454 uu_strerror(uu_error())); 14455 } 14456 14457 static int 14458 remove_string(uu_list_t *strlist, const char *str) 14459 { 14460 uu_list_walk_t *elems; 14461 string_list_t *sp; 14462 14463 /* 14464 * Find the element that needs to be removed. 14465 */ 14466 elems = uu_list_walk_start(strlist, UU_DEFAULT); 14467 while ((sp = uu_list_walk_next(elems)) != NULL) { 14468 if (strcmp(sp->str, str) == 0) 14469 break; 14470 } 14471 uu_list_walk_end(elems); 14472 14473 /* 14474 * Returning 1 here as the value was not found, this 14475 * might not be an error. Leave it to the caller to 14476 * decide. 14477 */ 14478 if (sp == NULL) { 14479 return (1); 14480 } 14481 14482 uu_list_remove(strlist, sp); 14483 14484 free(sp->str); 14485 free(sp); 14486 14487 return (0); 14488 } 14489 14490 /* 14491 * Get all property values that don't match the given glob pattern, 14492 * if a pattern is specified. 14493 */ 14494 static void 14495 get_prop_values(scf_property_t *prop, uu_list_t *values, 14496 const char *pattern) 14497 { 14498 scf_iter_t *iter; 14499 scf_value_t *val; 14500 int ret; 14501 14502 if ((iter = scf_iter_create(g_hndl)) == NULL || 14503 (val = scf_value_create(g_hndl)) == NULL) 14504 scfdie(); 14505 14506 if (scf_iter_property_values(iter, prop) != 0) 14507 scfdie(); 14508 14509 while ((ret = scf_iter_next_value(iter, val)) == 1) { 14510 char *buf; 14511 ssize_t vlen, szret; 14512 14513 vlen = scf_value_get_as_string(val, NULL, 0); 14514 if (vlen < 0) 14515 scfdie(); 14516 14517 buf = safe_malloc(vlen + 1); 14518 14519 szret = scf_value_get_as_string(val, buf, vlen + 1); 14520 if (szret < 0) 14521 scfdie(); 14522 assert(szret <= vlen); 14523 14524 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 14525 add_string(values, buf); 14526 14527 free(buf); 14528 } 14529 14530 if (ret == -1) 14531 scfdie(); 14532 14533 scf_value_destroy(val); 14534 scf_iter_destroy(iter); 14535 } 14536 14537 static int 14538 lscf_setpropvalue(const char *pgname, const char *type, 14539 const char *arg, int isadd, int isnotfoundok) 14540 { 14541 scf_type_t ty; 14542 scf_propertygroup_t *pg; 14543 scf_property_t *prop; 14544 int ret, result = 0; 14545 scf_transaction_t *tx; 14546 scf_transaction_entry_t *e; 14547 scf_value_t *v; 14548 string_list_t *sp; 14549 char *propname; 14550 uu_list_t *values; 14551 uu_list_walk_t *walk; 14552 void *cookie = NULL; 14553 char *pattern = NULL; 14554 14555 lscf_prep_hndl(); 14556 14557 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14558 uu_die(gettext("Could not create property list: %s\n"), 14559 uu_strerror(uu_error())); 14560 14561 if (!isadd) 14562 pattern = safe_strdup(arg); 14563 14564 if ((e = scf_entry_create(g_hndl)) == NULL || 14565 (pg = scf_pg_create(g_hndl)) == NULL || 14566 (prop = scf_property_create(g_hndl)) == NULL || 14567 (tx = scf_transaction_create(g_hndl)) == NULL) 14568 scfdie(); 14569 14570 if (cur_snap != NULL) { 14571 semerr(emsg_cant_modify_snapshots); 14572 goto fail; 14573 } 14574 14575 if (cur_inst == NULL && cur_svc == NULL) { 14576 semerr(emsg_entity_not_selected); 14577 goto fail; 14578 } 14579 14580 propname = strchr(pgname, '/'); 14581 if (propname == NULL) { 14582 semerr(gettext("Property names must contain a `/'.\n")); 14583 goto fail; 14584 } 14585 14586 *propname = '\0'; 14587 ++propname; 14588 14589 if (type != NULL) { 14590 ty = string_to_type(type); 14591 if (ty == SCF_TYPE_INVALID) { 14592 semerr(gettext("Unknown type \"%s\".\n"), type); 14593 goto fail; 14594 } 14595 } 14596 14597 if (cur_inst != NULL) 14598 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14599 else 14600 ret = scf_service_get_pg(cur_svc, pgname, pg); 14601 if (ret != 0) { 14602 switch (scf_error()) { 14603 case SCF_ERROR_NOT_FOUND: 14604 if (isnotfoundok) { 14605 result = 0; 14606 } else { 14607 semerr(emsg_no_such_pg, pgname); 14608 result = -1; 14609 } 14610 goto out; 14611 14612 case SCF_ERROR_INVALID_ARGUMENT: 14613 semerr(emsg_invalid_pg_name, pgname); 14614 goto fail; 14615 14616 default: 14617 scfdie(); 14618 } 14619 } 14620 14621 do { 14622 if (scf_pg_update(pg) == -1) 14623 scfdie(); 14624 if (scf_transaction_start(tx, pg) != 0) { 14625 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14626 scfdie(); 14627 14628 semerr(emsg_permission_denied); 14629 goto fail; 14630 } 14631 14632 ret = scf_pg_get_property(pg, propname, prop); 14633 if (ret == 0) { 14634 scf_type_t ptype; 14635 char *pat = pattern; 14636 14637 if (scf_property_type(prop, &ptype) != 0) 14638 scfdie(); 14639 14640 if (isadd) { 14641 if (type != NULL && ptype != ty) { 14642 semerr(gettext("Property \"%s\" is not " 14643 "of type \"%s\".\n"), propname, 14644 type); 14645 goto fail; 14646 } 14647 14648 pat = NULL; 14649 } else { 14650 size_t len = strlen(pat); 14651 if (len > 0 && pat[len - 1] == '\"') 14652 pat[len - 1] = '\0'; 14653 if (len > 0 && pat[0] == '\"') 14654 pat++; 14655 } 14656 14657 ty = ptype; 14658 14659 get_prop_values(prop, values, pat); 14660 14661 if (isadd) 14662 add_string(values, arg); 14663 14664 if (scf_transaction_property_change(tx, e, 14665 propname, ty) == -1) 14666 scfdie(); 14667 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14668 if (isadd) { 14669 if (type == NULL) { 14670 semerr(gettext("Type required " 14671 "for new properties.\n")); 14672 goto fail; 14673 } 14674 14675 add_string(values, arg); 14676 14677 if (scf_transaction_property_new(tx, e, 14678 propname, ty) == -1) 14679 scfdie(); 14680 } else if (isnotfoundok) { 14681 result = 0; 14682 goto out; 14683 } else { 14684 semerr(gettext("No such property %s/%s.\n"), 14685 pgname, propname); 14686 result = -1; 14687 goto out; 14688 } 14689 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14690 semerr(emsg_invalid_prop_name, propname); 14691 goto fail; 14692 } else { 14693 scfdie(); 14694 } 14695 14696 walk = uu_list_walk_start(values, UU_DEFAULT); 14697 if (walk == NULL) 14698 uu_die(gettext("Could not walk property list.\n")); 14699 14700 for (sp = uu_list_walk_next(walk); sp != NULL; 14701 sp = uu_list_walk_next(walk)) { 14702 v = string_to_value(sp->str, ty, 0); 14703 14704 if (v == NULL) { 14705 scf_entry_destroy_children(e); 14706 goto fail; 14707 } 14708 ret = scf_entry_add_value(e, v); 14709 assert(ret == 0); 14710 } 14711 uu_list_walk_end(walk); 14712 14713 result = scf_transaction_commit(tx); 14714 14715 scf_transaction_reset(tx); 14716 scf_entry_destroy_children(e); 14717 } while (result == 0); 14718 14719 if (result < 0) { 14720 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14721 scfdie(); 14722 14723 semerr(emsg_permission_denied); 14724 goto fail; 14725 } 14726 14727 result = 0; 14728 14729 private_refresh(); 14730 14731 out: 14732 scf_transaction_destroy(tx); 14733 scf_entry_destroy(e); 14734 scf_pg_destroy(pg); 14735 scf_property_destroy(prop); 14736 free(pattern); 14737 14738 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14739 free(sp->str); 14740 free(sp); 14741 } 14742 14743 uu_list_destroy(values); 14744 14745 return (result); 14746 14747 fail: 14748 result = -1; 14749 goto out; 14750 } 14751 14752 int 14753 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14754 { 14755 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14756 } 14757 14758 int 14759 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14760 { 14761 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14762 } 14763 14764 /* 14765 * Look for a standard start method, first in the instance (if any), 14766 * then the service. 14767 */ 14768 static const char * 14769 start_method_name(int *in_instance) 14770 { 14771 scf_propertygroup_t *pg; 14772 char **p; 14773 int ret; 14774 scf_instance_t *inst = cur_inst; 14775 14776 if ((pg = scf_pg_create(g_hndl)) == NULL) 14777 scfdie(); 14778 14779 again: 14780 for (p = start_method_names; *p != NULL; p++) { 14781 if (inst != NULL) 14782 ret = scf_instance_get_pg(inst, *p, pg); 14783 else 14784 ret = scf_service_get_pg(cur_svc, *p, pg); 14785 14786 if (ret == 0) { 14787 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14788 char *buf = safe_malloc(bufsz); 14789 14790 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14791 free(buf); 14792 continue; 14793 } 14794 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14795 free(buf); 14796 continue; 14797 } 14798 14799 free(buf); 14800 *in_instance = (inst != NULL); 14801 scf_pg_destroy(pg); 14802 return (*p); 14803 } 14804 14805 if (scf_error() == SCF_ERROR_NOT_FOUND) 14806 continue; 14807 14808 scfdie(); 14809 } 14810 14811 if (inst != NULL) { 14812 inst = NULL; 14813 goto again; 14814 } 14815 14816 scf_pg_destroy(pg); 14817 return (NULL); 14818 } 14819 14820 static int 14821 addpg(const char *name, const char *type) 14822 { 14823 scf_propertygroup_t *pg; 14824 int ret; 14825 14826 pg = scf_pg_create(g_hndl); 14827 if (pg == NULL) 14828 scfdie(); 14829 14830 if (cur_inst != NULL) 14831 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14832 else 14833 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14834 14835 if (ret != 0) { 14836 switch (scf_error()) { 14837 case SCF_ERROR_EXISTS: 14838 ret = 0; 14839 break; 14840 14841 case SCF_ERROR_PERMISSION_DENIED: 14842 semerr(emsg_permission_denied); 14843 break; 14844 14845 default: 14846 scfdie(); 14847 } 14848 } 14849 14850 scf_pg_destroy(pg); 14851 return (ret); 14852 } 14853 14854 int 14855 lscf_setenv(uu_list_t *args, int isunset) 14856 { 14857 int ret = 0; 14858 size_t i; 14859 int argc; 14860 char **argv = NULL; 14861 string_list_t *slp; 14862 char *pattern; 14863 char *prop; 14864 int do_service = 0; 14865 int do_instance = 0; 14866 const char *method = NULL; 14867 const char *name = NULL; 14868 const char *value = NULL; 14869 scf_instance_t *saved_cur_inst = cur_inst; 14870 14871 lscf_prep_hndl(); 14872 14873 argc = uu_list_numnodes(args); 14874 if (argc < 1) 14875 goto usage; 14876 14877 argv = calloc(argc + 1, sizeof (char *)); 14878 if (argv == NULL) 14879 uu_die(gettext("Out of memory.\n")); 14880 14881 for (slp = uu_list_first(args), i = 0; 14882 slp != NULL; 14883 slp = uu_list_next(args, slp), ++i) 14884 argv[i] = slp->str; 14885 14886 argv[i] = NULL; 14887 14888 opterr = 0; 14889 optind = 0; 14890 for (;;) { 14891 ret = getopt(argc, argv, "sim:"); 14892 if (ret == -1) 14893 break; 14894 14895 switch (ret) { 14896 case 's': 14897 do_service = 1; 14898 cur_inst = NULL; 14899 break; 14900 14901 case 'i': 14902 do_instance = 1; 14903 break; 14904 14905 case 'm': 14906 method = optarg; 14907 break; 14908 14909 case '?': 14910 goto usage; 14911 14912 default: 14913 bad_error("getopt", ret); 14914 } 14915 } 14916 14917 argc -= optind; 14918 if ((do_service && do_instance) || 14919 (isunset && argc != 1) || 14920 (!isunset && argc != 2)) 14921 goto usage; 14922 14923 name = argv[optind]; 14924 if (!isunset) 14925 value = argv[optind + 1]; 14926 14927 if (cur_snap != NULL) { 14928 semerr(emsg_cant_modify_snapshots); 14929 ret = -1; 14930 goto out; 14931 } 14932 14933 if (cur_inst == NULL && cur_svc == NULL) { 14934 semerr(emsg_entity_not_selected); 14935 ret = -1; 14936 goto out; 14937 } 14938 14939 if (do_instance && cur_inst == NULL) { 14940 semerr(gettext("No instance is selected.\n")); 14941 ret = -1; 14942 goto out; 14943 } 14944 14945 if (do_service && cur_svc == NULL) { 14946 semerr(gettext("No service is selected.\n")); 14947 ret = -1; 14948 goto out; 14949 } 14950 14951 if (method == NULL) { 14952 if (do_instance || do_service) { 14953 method = "method_context"; 14954 if (!isunset) { 14955 ret = addpg("method_context", 14956 SCF_GROUP_FRAMEWORK); 14957 if (ret != 0) 14958 goto out; 14959 } 14960 } else { 14961 int in_instance; 14962 method = start_method_name(&in_instance); 14963 if (method == NULL) { 14964 semerr(gettext( 14965 "Couldn't find start method; please " 14966 "specify a method with '-m'.\n")); 14967 ret = -1; 14968 goto out; 14969 } 14970 if (!in_instance) 14971 cur_inst = NULL; 14972 } 14973 } else { 14974 scf_propertygroup_t *pg; 14975 size_t bufsz; 14976 char *buf; 14977 int ret; 14978 14979 if ((pg = scf_pg_create(g_hndl)) == NULL) 14980 scfdie(); 14981 14982 if (cur_inst != NULL) 14983 ret = scf_instance_get_pg(cur_inst, method, pg); 14984 else 14985 ret = scf_service_get_pg(cur_svc, method, pg); 14986 14987 if (ret != 0) { 14988 scf_pg_destroy(pg); 14989 switch (scf_error()) { 14990 case SCF_ERROR_NOT_FOUND: 14991 semerr(gettext("Couldn't find the method " 14992 "\"%s\".\n"), method); 14993 goto out; 14994 14995 case SCF_ERROR_INVALID_ARGUMENT: 14996 semerr(gettext("Invalid method name \"%s\".\n"), 14997 method); 14998 goto out; 14999 15000 default: 15001 scfdie(); 15002 } 15003 } 15004 15005 bufsz = strlen(SCF_GROUP_METHOD) + 1; 15006 buf = safe_malloc(bufsz); 15007 15008 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 15009 strcmp(buf, SCF_GROUP_METHOD) != 0) { 15010 semerr(gettext("Property group \"%s\" is not of type " 15011 "\"method\".\n"), method); 15012 ret = -1; 15013 free(buf); 15014 scf_pg_destroy(pg); 15015 goto out; 15016 } 15017 15018 free(buf); 15019 scf_pg_destroy(pg); 15020 } 15021 15022 prop = uu_msprintf("%s/environment", method); 15023 pattern = uu_msprintf("%s=*", name); 15024 15025 if (prop == NULL || pattern == NULL) 15026 uu_die(gettext("Out of memory.\n")); 15027 15028 ret = lscf_delpropvalue(prop, pattern, !isunset); 15029 15030 if (ret == 0 && !isunset) { 15031 uu_free(pattern); 15032 uu_free(prop); 15033 prop = uu_msprintf("%s/environment", method); 15034 pattern = uu_msprintf("%s=%s", name, value); 15035 if (prop == NULL || pattern == NULL) 15036 uu_die(gettext("Out of memory.\n")); 15037 ret = lscf_addpropvalue(prop, "astring:", pattern); 15038 } 15039 uu_free(pattern); 15040 uu_free(prop); 15041 15042 out: 15043 cur_inst = saved_cur_inst; 15044 15045 free(argv); 15046 return (ret); 15047 usage: 15048 ret = -2; 15049 goto out; 15050 } 15051 15052 /* 15053 * Snapshot commands 15054 */ 15055 15056 void 15057 lscf_listsnap() 15058 { 15059 scf_snapshot_t *snap; 15060 scf_iter_t *iter; 15061 char *nb; 15062 int r; 15063 15064 lscf_prep_hndl(); 15065 15066 if (cur_inst == NULL) { 15067 semerr(gettext("Instance not selected.\n")); 15068 return; 15069 } 15070 15071 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15072 (iter = scf_iter_create(g_hndl)) == NULL) 15073 scfdie(); 15074 15075 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 15076 scfdie(); 15077 15078 nb = safe_malloc(max_scf_name_len + 1); 15079 15080 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 15081 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 15082 scfdie(); 15083 15084 (void) puts(nb); 15085 } 15086 if (r < 0) 15087 scfdie(); 15088 15089 free(nb); 15090 scf_iter_destroy(iter); 15091 scf_snapshot_destroy(snap); 15092 } 15093 15094 void 15095 lscf_selectsnap(const char *name) 15096 { 15097 scf_snapshot_t *snap; 15098 scf_snaplevel_t *level; 15099 15100 lscf_prep_hndl(); 15101 15102 if (cur_inst == NULL) { 15103 semerr(gettext("Instance not selected.\n")); 15104 return; 15105 } 15106 15107 if (cur_snap != NULL) { 15108 if (name != NULL) { 15109 char *cur_snap_name; 15110 boolean_t nochange; 15111 15112 cur_snap_name = safe_malloc(max_scf_name_len + 1); 15113 15114 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 15115 max_scf_name_len + 1) < 0) 15116 scfdie(); 15117 15118 nochange = strcmp(name, cur_snap_name) == 0; 15119 15120 free(cur_snap_name); 15121 15122 if (nochange) 15123 return; 15124 } 15125 15126 unselect_cursnap(); 15127 } 15128 15129 if (name == NULL) 15130 return; 15131 15132 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15133 (level = scf_snaplevel_create(g_hndl)) == NULL) 15134 scfdie(); 15135 15136 if (scf_instance_get_snapshot(cur_inst, name, snap) != 15137 SCF_SUCCESS) { 15138 switch (scf_error()) { 15139 case SCF_ERROR_INVALID_ARGUMENT: 15140 semerr(gettext("Invalid name \"%s\".\n"), name); 15141 break; 15142 15143 case SCF_ERROR_NOT_FOUND: 15144 semerr(gettext("No such snapshot \"%s\".\n"), name); 15145 break; 15146 15147 default: 15148 scfdie(); 15149 } 15150 15151 scf_snaplevel_destroy(level); 15152 scf_snapshot_destroy(snap); 15153 return; 15154 } 15155 15156 /* Load the snaplevels into our list. */ 15157 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 15158 if (cur_levels == NULL) 15159 uu_die(gettext("Could not create list: %s\n"), 15160 uu_strerror(uu_error())); 15161 15162 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15163 if (scf_error() != SCF_ERROR_NOT_FOUND) 15164 scfdie(); 15165 15166 semerr(gettext("Snapshot has no snaplevels.\n")); 15167 15168 scf_snaplevel_destroy(level); 15169 scf_snapshot_destroy(snap); 15170 return; 15171 } 15172 15173 cur_snap = snap; 15174 15175 for (;;) { 15176 cur_elt = safe_malloc(sizeof (*cur_elt)); 15177 uu_list_node_init(cur_elt, &cur_elt->list_node, 15178 snaplevel_pool); 15179 cur_elt->sl = level; 15180 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 15181 uu_die(gettext("libuutil error: %s\n"), 15182 uu_strerror(uu_error())); 15183 15184 level = scf_snaplevel_create(g_hndl); 15185 if (level == NULL) 15186 scfdie(); 15187 15188 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 15189 level) != SCF_SUCCESS) { 15190 if (scf_error() != SCF_ERROR_NOT_FOUND) 15191 scfdie(); 15192 15193 scf_snaplevel_destroy(level); 15194 break; 15195 } 15196 } 15197 15198 cur_elt = uu_list_last(cur_levels); 15199 cur_level = cur_elt->sl; 15200 } 15201 15202 /* 15203 * Copies the properties & values in src to dst. Assumes src won't change. 15204 * Returns -1 if permission is denied, -2 if another transaction interrupts, 15205 * and 0 on success. 15206 * 15207 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 15208 * property, if it is copied and has type boolean. (See comment in 15209 * lscf_revert()). 15210 */ 15211 static int 15212 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 15213 uint8_t enabled) 15214 { 15215 scf_transaction_t *tx; 15216 scf_iter_t *iter, *viter; 15217 scf_property_t *prop; 15218 scf_value_t *v; 15219 char *nbuf; 15220 int r; 15221 15222 tx = scf_transaction_create(g_hndl); 15223 if (tx == NULL) 15224 scfdie(); 15225 15226 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 15227 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15228 scfdie(); 15229 15230 scf_transaction_destroy(tx); 15231 15232 return (-1); 15233 } 15234 15235 if ((iter = scf_iter_create(g_hndl)) == NULL || 15236 (prop = scf_property_create(g_hndl)) == NULL || 15237 (viter = scf_iter_create(g_hndl)) == NULL) 15238 scfdie(); 15239 15240 nbuf = safe_malloc(max_scf_name_len + 1); 15241 15242 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 15243 scfdie(); 15244 15245 for (;;) { 15246 scf_transaction_entry_t *e; 15247 scf_type_t ty; 15248 15249 r = scf_iter_next_property(iter, prop); 15250 if (r == -1) 15251 scfdie(); 15252 if (r == 0) 15253 break; 15254 15255 e = scf_entry_create(g_hndl); 15256 if (e == NULL) 15257 scfdie(); 15258 15259 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 15260 scfdie(); 15261 15262 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 15263 scfdie(); 15264 15265 if (scf_transaction_property_new(tx, e, nbuf, 15266 ty) != SCF_SUCCESS) 15267 scfdie(); 15268 15269 if ((enabled == 0 || enabled == 1) && 15270 strcmp(nbuf, scf_property_enabled) == 0 && 15271 ty == SCF_TYPE_BOOLEAN) { 15272 v = scf_value_create(g_hndl); 15273 if (v == NULL) 15274 scfdie(); 15275 15276 scf_value_set_boolean(v, enabled); 15277 15278 if (scf_entry_add_value(e, v) != 0) 15279 scfdie(); 15280 } else { 15281 if (scf_iter_property_values(viter, prop) != 0) 15282 scfdie(); 15283 15284 for (;;) { 15285 v = scf_value_create(g_hndl); 15286 if (v == NULL) 15287 scfdie(); 15288 15289 r = scf_iter_next_value(viter, v); 15290 if (r == -1) 15291 scfdie(); 15292 if (r == 0) { 15293 scf_value_destroy(v); 15294 break; 15295 } 15296 15297 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 15298 scfdie(); 15299 } 15300 } 15301 } 15302 15303 free(nbuf); 15304 scf_iter_destroy(viter); 15305 scf_property_destroy(prop); 15306 scf_iter_destroy(iter); 15307 15308 r = scf_transaction_commit(tx); 15309 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 15310 scfdie(); 15311 15312 scf_transaction_destroy_children(tx); 15313 scf_transaction_destroy(tx); 15314 15315 switch (r) { 15316 case 1: return (0); 15317 case 0: return (-2); 15318 case -1: return (-1); 15319 15320 default: 15321 abort(); 15322 } 15323 15324 /* NOTREACHED */ 15325 } 15326 15327 void 15328 lscf_revert(const char *snapname) 15329 { 15330 scf_snapshot_t *snap, *prev; 15331 scf_snaplevel_t *level, *nlevel; 15332 scf_iter_t *iter; 15333 scf_propertygroup_t *pg, *npg; 15334 scf_property_t *prop; 15335 scf_value_t *val; 15336 char *nbuf, *tbuf; 15337 uint8_t enabled; 15338 15339 lscf_prep_hndl(); 15340 15341 if (cur_inst == NULL) { 15342 semerr(gettext("Instance not selected.\n")); 15343 return; 15344 } 15345 15346 if (snapname != NULL) { 15347 snap = scf_snapshot_create(g_hndl); 15348 if (snap == NULL) 15349 scfdie(); 15350 15351 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 15352 SCF_SUCCESS) { 15353 switch (scf_error()) { 15354 case SCF_ERROR_INVALID_ARGUMENT: 15355 semerr(gettext("Invalid snapshot name " 15356 "\"%s\".\n"), snapname); 15357 break; 15358 15359 case SCF_ERROR_NOT_FOUND: 15360 semerr(gettext("No such snapshot.\n")); 15361 break; 15362 15363 default: 15364 scfdie(); 15365 } 15366 15367 scf_snapshot_destroy(snap); 15368 return; 15369 } 15370 } else { 15371 if (cur_snap != NULL) { 15372 snap = cur_snap; 15373 } else { 15374 semerr(gettext("No snapshot selected.\n")); 15375 return; 15376 } 15377 } 15378 15379 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 15380 (level = scf_snaplevel_create(g_hndl)) == NULL || 15381 (iter = scf_iter_create(g_hndl)) == NULL || 15382 (pg = scf_pg_create(g_hndl)) == NULL || 15383 (npg = scf_pg_create(g_hndl)) == NULL || 15384 (prop = scf_property_create(g_hndl)) == NULL || 15385 (val = scf_value_create(g_hndl)) == NULL) 15386 scfdie(); 15387 15388 nbuf = safe_malloc(max_scf_name_len + 1); 15389 tbuf = safe_malloc(max_scf_pg_type_len + 1); 15390 15391 /* Take the "previous" snapshot before we blow away the properties. */ 15392 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 15393 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 15394 scfdie(); 15395 } else { 15396 if (scf_error() != SCF_ERROR_NOT_FOUND) 15397 scfdie(); 15398 15399 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 15400 scfdie(); 15401 } 15402 15403 /* Save general/enabled, since we're probably going to replace it. */ 15404 enabled = 2; 15405 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 15406 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 15407 scf_property_get_value(prop, val) == 0) 15408 (void) scf_value_get_boolean(val, &enabled); 15409 15410 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15411 if (scf_error() != SCF_ERROR_NOT_FOUND) 15412 scfdie(); 15413 15414 goto out; 15415 } 15416 15417 for (;;) { 15418 boolean_t isinst; 15419 uint32_t flags; 15420 int r; 15421 15422 /* Clear the properties from the corresponding entity. */ 15423 isinst = snaplevel_is_instance(level); 15424 15425 if (!isinst) 15426 r = scf_iter_service_pgs(iter, cur_svc); 15427 else 15428 r = scf_iter_instance_pgs(iter, cur_inst); 15429 if (r != SCF_SUCCESS) 15430 scfdie(); 15431 15432 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15433 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15434 scfdie(); 15435 15436 /* Skip nonpersistent pgs. */ 15437 if (flags & SCF_PG_FLAG_NONPERSISTENT) 15438 continue; 15439 15440 if (scf_pg_delete(pg) != SCF_SUCCESS) { 15441 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15442 scfdie(); 15443 15444 semerr(emsg_permission_denied); 15445 goto out; 15446 } 15447 } 15448 if (r == -1) 15449 scfdie(); 15450 15451 /* Copy the properties to the corresponding entity. */ 15452 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 15453 scfdie(); 15454 15455 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15456 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 15457 scfdie(); 15458 15459 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 15460 0) 15461 scfdie(); 15462 15463 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15464 scfdie(); 15465 15466 if (!isinst) 15467 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 15468 flags, npg); 15469 else 15470 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 15471 flags, npg); 15472 if (r != SCF_SUCCESS) { 15473 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15474 scfdie(); 15475 15476 semerr(emsg_permission_denied); 15477 goto out; 15478 } 15479 15480 if ((enabled == 0 || enabled == 1) && 15481 strcmp(nbuf, scf_pg_general) == 0) 15482 r = pg_copy(pg, npg, enabled); 15483 else 15484 r = pg_copy(pg, npg, 2); 15485 15486 switch (r) { 15487 case 0: 15488 break; 15489 15490 case -1: 15491 semerr(emsg_permission_denied); 15492 goto out; 15493 15494 case -2: 15495 semerr(gettext( 15496 "Interrupted by another change.\n")); 15497 goto out; 15498 15499 default: 15500 abort(); 15501 } 15502 } 15503 if (r == -1) 15504 scfdie(); 15505 15506 /* Get next level. */ 15507 nlevel = scf_snaplevel_create(g_hndl); 15508 if (nlevel == NULL) 15509 scfdie(); 15510 15511 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 15512 SCF_SUCCESS) { 15513 if (scf_error() != SCF_ERROR_NOT_FOUND) 15514 scfdie(); 15515 15516 scf_snaplevel_destroy(nlevel); 15517 break; 15518 } 15519 15520 scf_snaplevel_destroy(level); 15521 level = nlevel; 15522 } 15523 15524 if (snapname == NULL) { 15525 lscf_selectsnap(NULL); 15526 snap = NULL; /* cur_snap has been destroyed */ 15527 } 15528 15529 out: 15530 free(tbuf); 15531 free(nbuf); 15532 scf_value_destroy(val); 15533 scf_property_destroy(prop); 15534 scf_pg_destroy(npg); 15535 scf_pg_destroy(pg); 15536 scf_iter_destroy(iter); 15537 scf_snaplevel_destroy(level); 15538 scf_snapshot_destroy(prev); 15539 if (snap != cur_snap) 15540 scf_snapshot_destroy(snap); 15541 } 15542 15543 void 15544 lscf_refresh(void) 15545 { 15546 ssize_t fmrilen; 15547 size_t bufsz; 15548 char *fmribuf; 15549 int r; 15550 15551 lscf_prep_hndl(); 15552 15553 if (cur_inst == NULL) { 15554 semerr(gettext("Instance not selected.\n")); 15555 return; 15556 } 15557 15558 bufsz = max_scf_fmri_len + 1; 15559 fmribuf = safe_malloc(bufsz); 15560 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15561 if (fmrilen < 0) { 15562 free(fmribuf); 15563 if (scf_error() != SCF_ERROR_DELETED) 15564 scfdie(); 15565 scf_instance_destroy(cur_inst); 15566 cur_inst = NULL; 15567 warn(emsg_deleted); 15568 return; 15569 } 15570 assert(fmrilen < bufsz); 15571 15572 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15573 switch (r) { 15574 case 0: 15575 break; 15576 15577 case ECONNABORTED: 15578 warn(gettext("Could not refresh %s " 15579 "(repository connection broken).\n"), fmribuf); 15580 break; 15581 15582 case ECANCELED: 15583 warn(emsg_deleted); 15584 break; 15585 15586 case EPERM: 15587 warn(gettext("Could not refresh %s " 15588 "(permission denied).\n"), fmribuf); 15589 break; 15590 15591 case ENOSPC: 15592 warn(gettext("Could not refresh %s " 15593 "(repository server out of resources).\n"), 15594 fmribuf); 15595 break; 15596 15597 case EACCES: 15598 default: 15599 bad_error("refresh_entity", scf_error()); 15600 } 15601 15602 free(fmribuf); 15603 } 15604 15605 /* 15606 * describe [-v] [-t] [pg/prop] 15607 */ 15608 int 15609 lscf_describe(uu_list_t *args, int hasargs) 15610 { 15611 int ret = 0; 15612 size_t i; 15613 int argc; 15614 char **argv = NULL; 15615 string_list_t *slp; 15616 int do_verbose = 0; 15617 int do_templates = 0; 15618 char *pattern = NULL; 15619 15620 lscf_prep_hndl(); 15621 15622 if (hasargs != 0) { 15623 argc = uu_list_numnodes(args); 15624 if (argc < 1) 15625 goto usage; 15626 15627 argv = calloc(argc + 1, sizeof (char *)); 15628 if (argv == NULL) 15629 uu_die(gettext("Out of memory.\n")); 15630 15631 for (slp = uu_list_first(args), i = 0; 15632 slp != NULL; 15633 slp = uu_list_next(args, slp), ++i) 15634 argv[i] = slp->str; 15635 15636 argv[i] = NULL; 15637 15638 /* 15639 * We start optind = 0 because our list of arguments 15640 * starts at argv[0] 15641 */ 15642 optind = 0; 15643 opterr = 0; 15644 for (;;) { 15645 ret = getopt(argc, argv, "vt"); 15646 if (ret == -1) 15647 break; 15648 15649 switch (ret) { 15650 case 'v': 15651 do_verbose = 1; 15652 break; 15653 15654 case 't': 15655 do_templates = 1; 15656 break; 15657 15658 case '?': 15659 goto usage; 15660 15661 default: 15662 bad_error("getopt", ret); 15663 } 15664 } 15665 15666 pattern = argv[optind]; 15667 } 15668 15669 if (cur_inst == NULL && cur_svc == NULL) { 15670 semerr(emsg_entity_not_selected); 15671 ret = -1; 15672 goto out; 15673 } 15674 15675 /* 15676 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15677 * output if their last parameter is set to 2. Less information is 15678 * produced if the parameter is set to 1. 15679 */ 15680 if (pattern == NULL) { 15681 if (do_verbose == 1) 15682 list_entity_tmpl(2); 15683 else 15684 list_entity_tmpl(1); 15685 } 15686 15687 if (do_templates == 0) { 15688 if (do_verbose == 1) 15689 listprop(pattern, 0, 2); 15690 else 15691 listprop(pattern, 0, 1); 15692 } else { 15693 if (do_verbose == 1) 15694 listtmpl(pattern, 2); 15695 else 15696 listtmpl(pattern, 1); 15697 } 15698 15699 ret = 0; 15700 out: 15701 if (argv != NULL) 15702 free(argv); 15703 return (ret); 15704 usage: 15705 ret = -2; 15706 goto out; 15707 } 15708 15709 #define PARAM_ACTIVE ((const char *) "active") 15710 #define PARAM_INACTIVE ((const char *) "inactive") 15711 #define PARAM_SMTP_TO ((const char *) "to") 15712 15713 /* 15714 * tokenize() 15715 * Breaks down the string according to the tokens passed. 15716 * Caller is responsible for freeing array of pointers returned. 15717 * Returns NULL on failure 15718 */ 15719 char ** 15720 tokenize(char *str, const char *sep) 15721 { 15722 char *token, *lasts; 15723 char **buf; 15724 int n = 0; /* number of elements */ 15725 int size = 8; /* size of the array (initial) */ 15726 15727 buf = safe_malloc(size * sizeof (char *)); 15728 15729 for (token = strtok_r(str, sep, &lasts); token != NULL; 15730 token = strtok_r(NULL, sep, &lasts), ++n) { 15731 if (n + 1 >= size) { 15732 size *= 2; 15733 if ((buf = realloc(buf, size * sizeof (char *))) == 15734 NULL) { 15735 uu_die(gettext("Out of memory")); 15736 } 15737 } 15738 buf[n] = token; 15739 } 15740 /* NULL terminate the pointer array */ 15741 buf[n] = NULL; 15742 15743 return (buf); 15744 } 15745 15746 int32_t 15747 check_tokens(char **p) 15748 { 15749 int32_t smf = 0; 15750 int32_t fma = 0; 15751 15752 while (*p) { 15753 int32_t t = string_to_tset(*p); 15754 15755 if (t == 0) { 15756 if (is_fma_token(*p) == 0) 15757 return (INVALID_TOKENS); 15758 fma = 1; /* this token is an fma event */ 15759 } else { 15760 smf |= t; 15761 } 15762 15763 if (smf != 0 && fma == 1) 15764 return (MIXED_TOKENS); 15765 ++p; 15766 } 15767 15768 if (smf > 0) 15769 return (smf); 15770 else if (fma == 1) 15771 return (FMA_TOKENS); 15772 15773 return (INVALID_TOKENS); 15774 } 15775 15776 static int 15777 get_selection_str(char *fmri, size_t sz) 15778 { 15779 if (g_hndl == NULL) { 15780 semerr(emsg_entity_not_selected); 15781 return (-1); 15782 } else if (cur_level != NULL) { 15783 semerr(emsg_invalid_for_snapshot); 15784 return (-1); 15785 } else { 15786 lscf_get_selection_str(fmri, sz); 15787 } 15788 15789 return (0); 15790 } 15791 15792 void 15793 lscf_delnotify(const char *set, int global) 15794 { 15795 char *str = strdup(set); 15796 char **pgs; 15797 char **p; 15798 int32_t tset; 15799 char *fmri = NULL; 15800 15801 if (str == NULL) 15802 uu_die(gettext("Out of memory.\n")); 15803 15804 pgs = tokenize(str, ","); 15805 15806 if ((tset = check_tokens(pgs)) > 0) { 15807 size_t sz = max_scf_fmri_len + 1; 15808 15809 fmri = safe_malloc(sz); 15810 if (global) { 15811 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15812 } else if (get_selection_str(fmri, sz) != 0) { 15813 goto out; 15814 } 15815 15816 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri, 15817 tset) != SCF_SUCCESS) { 15818 uu_warn(gettext("Failed smf_notify_del_params: %s\n"), 15819 scf_strerror(scf_error())); 15820 } 15821 } else if (tset == FMA_TOKENS) { 15822 if (global) { 15823 semerr(gettext("Can't use option '-g' with FMA event " 15824 "definitions\n")); 15825 goto out; 15826 } 15827 15828 for (p = pgs; *p; ++p) { 15829 if (smf_notify_del_params(de_tag(*p), NULL, 0) != 15830 SCF_SUCCESS) { 15831 uu_warn(gettext("Failed for \"%s\": %s\n"), *p, 15832 scf_strerror(scf_error())); 15833 goto out; 15834 } 15835 } 15836 } else if (tset == MIXED_TOKENS) { 15837 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15838 goto out; 15839 } else { 15840 uu_die(gettext("Invalid input.\n")); 15841 } 15842 15843 out: 15844 free(fmri); 15845 free(pgs); 15846 free(str); 15847 } 15848 15849 void 15850 lscf_listnotify(const char *set, int global) 15851 { 15852 char *str = safe_strdup(set); 15853 char **pgs; 15854 char **p; 15855 int32_t tset; 15856 nvlist_t *nvl; 15857 char *fmri = NULL; 15858 15859 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 15860 uu_die(gettext("Out of memory.\n")); 15861 15862 pgs = tokenize(str, ","); 15863 15864 if ((tset = check_tokens(pgs)) > 0) { 15865 size_t sz = max_scf_fmri_len + 1; 15866 15867 fmri = safe_malloc(sz); 15868 if (global) { 15869 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15870 } else if (get_selection_str(fmri, sz) != 0) { 15871 goto out; 15872 } 15873 15874 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) != 15875 SCF_SUCCESS) { 15876 if (scf_error() != SCF_ERROR_NOT_FOUND && 15877 scf_error() != SCF_ERROR_DELETED) 15878 uu_warn(gettext( 15879 "Failed listnotify: %s\n"), 15880 scf_strerror(scf_error())); 15881 goto out; 15882 } 15883 15884 listnotify_print(nvl, NULL); 15885 } else if (tset == FMA_TOKENS) { 15886 if (global) { 15887 semerr(gettext("Can't use option '-g' with FMA event " 15888 "definitions\n")); 15889 goto out; 15890 } 15891 15892 for (p = pgs; *p; ++p) { 15893 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) != 15894 SCF_SUCCESS) { 15895 /* 15896 * if the preferences have just been deleted 15897 * or does not exist, just skip. 15898 */ 15899 if (scf_error() == SCF_ERROR_NOT_FOUND || 15900 scf_error() == SCF_ERROR_DELETED) 15901 continue; 15902 uu_warn(gettext( 15903 "Failed listnotify: %s\n"), 15904 scf_strerror(scf_error())); 15905 goto out; 15906 } 15907 listnotify_print(nvl, re_tag(*p)); 15908 } 15909 } else if (tset == MIXED_TOKENS) { 15910 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15911 goto out; 15912 } else { 15913 semerr(gettext("Invalid input.\n")); 15914 } 15915 15916 out: 15917 nvlist_free(nvl); 15918 free(fmri); 15919 free(pgs); 15920 free(str); 15921 } 15922 15923 static char * 15924 strip_quotes_and_blanks(char *s) 15925 { 15926 char *start = s; 15927 char *end = strrchr(s, '\"'); 15928 15929 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') { 15930 start = s + 1; 15931 while (isblank(*start)) 15932 start++; 15933 while (isblank(*(end - 1)) && end > start) { 15934 end--; 15935 } 15936 *end = '\0'; 15937 } 15938 15939 return (start); 15940 } 15941 15942 static int 15943 set_active(nvlist_t *mech, const char *hier_part) 15944 { 15945 boolean_t b; 15946 15947 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) { 15948 b = B_TRUE; 15949 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) { 15950 b = B_FALSE; 15951 } else { 15952 return (-1); 15953 } 15954 15955 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0) 15956 uu_die(gettext("Out of memory.\n")); 15957 15958 return (0); 15959 } 15960 15961 static int 15962 add_snmp_params(nvlist_t *mech, char *hier_part) 15963 { 15964 return (set_active(mech, hier_part)); 15965 } 15966 15967 static int 15968 add_syslog_params(nvlist_t *mech, char *hier_part) 15969 { 15970 return (set_active(mech, hier_part)); 15971 } 15972 15973 /* 15974 * add_mailto_paramas() 15975 * parse the hier_part of mailto URI 15976 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]] 15977 * or mailto:{[active]|inactive} 15978 */ 15979 static int 15980 add_mailto_params(nvlist_t *mech, char *hier_part) 15981 { 15982 const char *tok = "?&"; 15983 char *p; 15984 char *lasts; 15985 char *param; 15986 char *val; 15987 15988 /* 15989 * If the notification parametes are in the form of 15990 * 15991 * malito:{[active]|inactive} 15992 * 15993 * we set the property accordingly and return. 15994 * Otherwise, we make the notification type active and 15995 * process the hier_part. 15996 */ 15997 if (set_active(mech, hier_part) == 0) 15998 return (0); 15999 else if (set_active(mech, PARAM_ACTIVE) != 0) 16000 return (-1); 16001 16002 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) { 16003 /* 16004 * sanity check: we only get here if hier_part = "", but 16005 * that's handled by set_active 16006 */ 16007 uu_die("strtok_r"); 16008 } 16009 16010 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0) 16011 uu_die(gettext("Out of memory.\n")); 16012 16013 while ((p = strtok_r(NULL, tok, &lasts)) != NULL) 16014 if ((param = strtok_r(p, "=", &val)) != NULL) 16015 if (nvlist_add_string(mech, param, val) != 0) 16016 uu_die(gettext("Out of memory.\n")); 16017 16018 return (0); 16019 } 16020 16021 static int 16022 uri_split(char *uri, char **scheme, char **hier_part) 16023 { 16024 int r = -1; 16025 16026 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL || 16027 *hier_part == NULL) { 16028 semerr(gettext("'%s' is not an URI\n"), uri); 16029 return (r); 16030 } 16031 16032 if ((r = check_uri_scheme(*scheme)) < 0) { 16033 semerr(gettext("Unkown URI scheme: %s\n"), *scheme); 16034 return (r); 16035 } 16036 16037 return (r); 16038 } 16039 16040 static int 16041 process_uri(nvlist_t *params, char *uri) 16042 { 16043 char *scheme; 16044 char *hier_part; 16045 nvlist_t *mech; 16046 int index; 16047 int r; 16048 16049 if ((index = uri_split(uri, &scheme, &hier_part)) < 0) 16050 return (-1); 16051 16052 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0) 16053 uu_die(gettext("Out of memory.\n")); 16054 16055 switch (index) { 16056 case 0: 16057 /* error messages displayed by called function */ 16058 r = add_mailto_params(mech, hier_part); 16059 break; 16060 16061 case 1: 16062 if ((r = add_snmp_params(mech, hier_part)) != 0) 16063 semerr(gettext("Not valid parameters: '%s'\n"), 16064 hier_part); 16065 break; 16066 16067 case 2: 16068 if ((r = add_syslog_params(mech, hier_part)) != 0) 16069 semerr(gettext("Not valid parameters: '%s'\n"), 16070 hier_part); 16071 break; 16072 16073 default: 16074 r = -1; 16075 } 16076 16077 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol, 16078 mech) != 0) 16079 uu_die(gettext("Out of memory.\n")); 16080 16081 nvlist_free(mech); 16082 return (r); 16083 } 16084 16085 static int 16086 set_params(nvlist_t *params, char **p) 16087 { 16088 char *uri; 16089 16090 if (p == NULL) 16091 /* sanity check */ 16092 uu_die("set_params"); 16093 16094 while (*p) { 16095 uri = strip_quotes_and_blanks(*p); 16096 if (process_uri(params, uri) != 0) 16097 return (-1); 16098 16099 ++p; 16100 } 16101 16102 return (0); 16103 } 16104 16105 static int 16106 setnotify(const char *e, char **p, int global) 16107 { 16108 char *str = safe_strdup(e); 16109 char **events; 16110 int32_t tset; 16111 int r = -1; 16112 nvlist_t *nvl, *params; 16113 char *fmri = NULL; 16114 16115 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 16116 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 || 16117 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 16118 SCF_NOTIFY_PARAMS_VERSION) != 0) 16119 uu_die(gettext("Out of memory.\n")); 16120 16121 events = tokenize(str, ","); 16122 16123 if ((tset = check_tokens(events)) > 0) { 16124 /* SMF state transitions parameters */ 16125 size_t sz = max_scf_fmri_len + 1; 16126 16127 fmri = safe_malloc(sz); 16128 if (global) { 16129 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 16130 } else if (get_selection_str(fmri, sz) != 0) { 16131 goto out; 16132 } 16133 16134 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 || 16135 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0) 16136 uu_die(gettext("Out of memory.\n")); 16137 16138 if ((r = set_params(params, p)) == 0) { 16139 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, 16140 params) != 0) 16141 uu_die(gettext("Out of memory.\n")); 16142 16143 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS, 16144 nvl) != SCF_SUCCESS) { 16145 r = -1; 16146 uu_warn(gettext( 16147 "Failed smf_notify_set_params(3SCF): %s\n"), 16148 scf_strerror(scf_error())); 16149 } 16150 } 16151 } else if (tset == FMA_TOKENS) { 16152 /* FMA event parameters */ 16153 if (global) { 16154 semerr(gettext("Can't use option '-g' with FMA event " 16155 "definitions\n")); 16156 goto out; 16157 } 16158 16159 if ((r = set_params(params, p)) != 0) 16160 goto out; 16161 16162 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0) 16163 uu_die(gettext("Out of memory.\n")); 16164 16165 while (*events) { 16166 if (smf_notify_set_params(de_tag(*events), nvl) != 16167 SCF_SUCCESS) 16168 uu_warn(gettext( 16169 "Failed smf_notify_set_params(3SCF) for " 16170 "event %s: %s\n"), *events, 16171 scf_strerror(scf_error())); 16172 events++; 16173 } 16174 } else if (tset == MIXED_TOKENS) { 16175 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 16176 } else { 16177 /* Sanity check */ 16178 uu_die(gettext("Invalid input.\n")); 16179 } 16180 16181 out: 16182 nvlist_free(nvl); 16183 nvlist_free(params); 16184 free(fmri); 16185 free(str); 16186 16187 return (r); 16188 } 16189 16190 int 16191 lscf_setnotify(uu_list_t *args) 16192 { 16193 int argc; 16194 char **argv = NULL; 16195 string_list_t *slp; 16196 int global; 16197 char *events; 16198 char **p; 16199 int i; 16200 int ret; 16201 16202 if ((argc = uu_list_numnodes(args)) < 2) 16203 goto usage; 16204 16205 argv = calloc(argc + 1, sizeof (char *)); 16206 if (argv == NULL) 16207 uu_die(gettext("Out of memory.\n")); 16208 16209 for (slp = uu_list_first(args), i = 0; 16210 slp != NULL; 16211 slp = uu_list_next(args, slp), ++i) 16212 argv[i] = slp->str; 16213 16214 argv[i] = NULL; 16215 16216 if (strcmp(argv[0], "-g") == 0) { 16217 global = 1; 16218 events = argv[1]; 16219 p = argv + 2; 16220 } else { 16221 global = 0; 16222 events = argv[0]; 16223 p = argv + 1; 16224 } 16225 16226 ret = setnotify(events, p, global); 16227 16228 out: 16229 free(argv); 16230 return (ret); 16231 16232 usage: 16233 ret = -2; 16234 goto out; 16235 } 16236 16237 /* 16238 * Creates a list of instance name strings associated with a service. If 16239 * wohandcrafted flag is set, get only instances that have a last-import 16240 * snapshot, instances that were imported via svccfg. 16241 */ 16242 static uu_list_t * 16243 create_instance_list(scf_service_t *svc, int wohandcrafted) 16244 { 16245 scf_snapshot_t *snap = NULL; 16246 scf_instance_t *inst; 16247 scf_iter_t *inst_iter; 16248 uu_list_t *instances; 16249 char *instname; 16250 int r; 16251 16252 inst_iter = scf_iter_create(g_hndl); 16253 inst = scf_instance_create(g_hndl); 16254 if (inst_iter == NULL || inst == NULL) { 16255 uu_warn(gettext("Could not create instance or iterator\n")); 16256 scfdie(); 16257 } 16258 16259 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 16260 return (instances); 16261 16262 if (scf_iter_service_instances(inst_iter, svc) != 0) { 16263 switch (scf_error()) { 16264 case SCF_ERROR_CONNECTION_BROKEN: 16265 case SCF_ERROR_DELETED: 16266 uu_list_destroy(instances); 16267 instances = NULL; 16268 goto out; 16269 16270 case SCF_ERROR_HANDLE_MISMATCH: 16271 case SCF_ERROR_NOT_BOUND: 16272 case SCF_ERROR_NOT_SET: 16273 default: 16274 bad_error("scf_iter_service_instances", scf_error()); 16275 } 16276 } 16277 16278 instname = safe_malloc(max_scf_name_len + 1); 16279 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 16280 if (r == -1) { 16281 (void) uu_warn(gettext("Unable to iterate through " 16282 "instances to create instance list : %s\n"), 16283 scf_strerror(scf_error())); 16284 16285 uu_list_destroy(instances); 16286 instances = NULL; 16287 goto out; 16288 } 16289 16290 /* 16291 * If the instance does not have a last-import snapshot 16292 * then do not add it to the list as it is a hand-crafted 16293 * instance that should not be managed. 16294 */ 16295 if (wohandcrafted) { 16296 if (snap == NULL && 16297 (snap = scf_snapshot_create(g_hndl)) == NULL) { 16298 uu_warn(gettext("Unable to create snapshot " 16299 "entity\n")); 16300 scfdie(); 16301 } 16302 16303 if (scf_instance_get_snapshot(inst, 16304 snap_lastimport, snap) != 0) { 16305 switch (scf_error()) { 16306 case SCF_ERROR_NOT_FOUND : 16307 case SCF_ERROR_DELETED: 16308 continue; 16309 16310 case SCF_ERROR_CONNECTION_BROKEN: 16311 uu_list_destroy(instances); 16312 instances = NULL; 16313 goto out; 16314 16315 case SCF_ERROR_HANDLE_MISMATCH: 16316 case SCF_ERROR_NOT_BOUND: 16317 case SCF_ERROR_NOT_SET: 16318 default: 16319 bad_error("scf_iter_service_instances", 16320 scf_error()); 16321 } 16322 } 16323 } 16324 16325 if (scf_instance_get_name(inst, instname, 16326 max_scf_name_len + 1) < 0) { 16327 switch (scf_error()) { 16328 case SCF_ERROR_NOT_FOUND : 16329 continue; 16330 16331 case SCF_ERROR_CONNECTION_BROKEN: 16332 case SCF_ERROR_DELETED: 16333 uu_list_destroy(instances); 16334 instances = NULL; 16335 goto out; 16336 16337 case SCF_ERROR_HANDLE_MISMATCH: 16338 case SCF_ERROR_NOT_BOUND: 16339 case SCF_ERROR_NOT_SET: 16340 default: 16341 bad_error("scf_iter_service_instances", 16342 scf_error()); 16343 } 16344 } 16345 16346 add_string(instances, instname); 16347 } 16348 16349 out: 16350 if (snap) 16351 scf_snapshot_destroy(snap); 16352 16353 scf_instance_destroy(inst); 16354 scf_iter_destroy(inst_iter); 16355 free(instname); 16356 return (instances); 16357 } 16358 16359 /* 16360 * disable an instance but wait for the instance to 16361 * move out of the running state. 16362 * 16363 * Returns 0 : if the instance did not disable 16364 * Returns non-zero : if the instance disabled. 16365 * 16366 */ 16367 static int 16368 disable_instance(scf_instance_t *instance) 16369 { 16370 char *fmribuf; 16371 int enabled = 10000; 16372 16373 if (inst_is_running(instance)) { 16374 fmribuf = safe_malloc(max_scf_name_len + 1); 16375 if (scf_instance_to_fmri(instance, fmribuf, 16376 max_scf_name_len + 1) < 0) { 16377 free(fmribuf); 16378 return (0); 16379 } 16380 16381 /* 16382 * If the instance cannot be disabled then return 16383 * failure to disable and let the caller decide 16384 * if that is of importance. 16385 */ 16386 if (smf_disable_instance(fmribuf, 0) != 0) { 16387 free(fmribuf); 16388 return (0); 16389 } 16390 16391 while (enabled) { 16392 if (!inst_is_running(instance)) 16393 break; 16394 16395 (void) poll(NULL, 0, 5); 16396 enabled = enabled - 5; 16397 } 16398 16399 free(fmribuf); 16400 } 16401 16402 return (enabled); 16403 } 16404 16405 /* 16406 * Function to compare two service_manifest structures. 16407 */ 16408 /* ARGSUSED2 */ 16409 static int 16410 service_manifest_compare(const void *left, const void *right, void *unused) 16411 { 16412 service_manifest_t *l = (service_manifest_t *)left; 16413 service_manifest_t *r = (service_manifest_t *)right; 16414 int rc; 16415 16416 rc = strcmp(l->servicename, r->servicename); 16417 16418 return (rc); 16419 } 16420 16421 /* 16422 * Look for the provided service in the service to manifest 16423 * tree. If the service exists, and a manifest was provided 16424 * then add the manifest to that service. If the service 16425 * does not exist, then add the service and manifest to the 16426 * list. 16427 * 16428 * If the manifest is NULL, return the element if found. If 16429 * the service is not found return NULL. 16430 */ 16431 service_manifest_t * 16432 find_add_svc_mfst(const char *svnbuf, const char *mfst) 16433 { 16434 service_manifest_t elem; 16435 service_manifest_t *fnelem; 16436 uu_avl_index_t marker; 16437 16438 elem.servicename = svnbuf; 16439 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 16440 16441 if (mfst) { 16442 if (fnelem) { 16443 add_string(fnelem->mfstlist, strdup(mfst)); 16444 } else { 16445 fnelem = safe_malloc(sizeof (*fnelem)); 16446 fnelem->servicename = safe_strdup(svnbuf); 16447 if ((fnelem->mfstlist = 16448 uu_list_create(string_pool, NULL, 0)) == NULL) 16449 uu_die(gettext("Could not create property " 16450 "list: %s\n"), uu_strerror(uu_error())); 16451 16452 add_string(fnelem->mfstlist, safe_strdup(mfst)); 16453 16454 uu_avl_insert(service_manifest_tree, fnelem, marker); 16455 } 16456 } 16457 16458 return (fnelem); 16459 } 16460 16461 /* 16462 * Create the service to manifest avl tree. 16463 * 16464 * Walk each of the manifests currently installed in the supported 16465 * directories, /lib/svc/manifests and /var/svc/manifests. For 16466 * each of the manifests, inventory the services and add them to 16467 * the tree. 16468 * 16469 * Code that calls this function should make sure fileystem/minimal is online, 16470 * /var is available, since this function walks the /var/svc/manifest directory. 16471 */ 16472 static void 16473 create_manifest_tree(void) 16474 { 16475 manifest_info_t **entry; 16476 manifest_info_t **manifests; 16477 uu_list_walk_t *svcs; 16478 bundle_t *b; 16479 entity_t *mfsvc; 16480 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 16481 int c, status; 16482 16483 if (service_manifest_pool) 16484 return; 16485 16486 /* 16487 * Create the list pool for the service manifest list 16488 */ 16489 service_manifest_pool = uu_avl_pool_create("service_manifest", 16490 sizeof (service_manifest_t), 16491 offsetof(service_manifest_t, svcmfst_node), 16492 service_manifest_compare, UU_DEFAULT); 16493 if (service_manifest_pool == NULL) 16494 uu_die(gettext("service_manifest pool creation failed: %s\n"), 16495 uu_strerror(uu_error())); 16496 16497 /* 16498 * Create the list 16499 */ 16500 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 16501 UU_DEFAULT); 16502 if (service_manifest_tree == NULL) 16503 uu_die(gettext("service_manifest tree creation failed: %s\n"), 16504 uu_strerror(uu_error())); 16505 16506 /* 16507 * Walk the manifests adding the service(s) from each manifest. 16508 * 16509 * If a service already exists add the manifest to the manifest 16510 * list for that service. This covers the case of a service that 16511 * is supported by multiple manifest files. 16512 */ 16513 for (c = 0; dirs[c]; c++) { 16514 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT); 16515 if (status < 0) { 16516 uu_warn(gettext("file tree walk of %s encountered " 16517 "error %s\n"), dirs[c], strerror(errno)); 16518 16519 uu_avl_destroy(service_manifest_tree); 16520 service_manifest_tree = NULL; 16521 return; 16522 } 16523 16524 /* 16525 * If a manifest that was in the list is not found 16526 * then skip and go to the next manifest file. 16527 */ 16528 if (manifests != NULL) { 16529 for (entry = manifests; *entry != NULL; entry++) { 16530 b = internal_bundle_new(); 16531 if (lxml_get_bundle_file(b, (*entry)->mi_path, 16532 SVCCFG_OP_IMPORT) != 0) { 16533 internal_bundle_free(b); 16534 continue; 16535 } 16536 16537 svcs = uu_list_walk_start(b->sc_bundle_services, 16538 0); 16539 if (svcs == NULL) { 16540 internal_bundle_free(b); 16541 continue; 16542 } 16543 16544 while ((mfsvc = uu_list_walk_next(svcs)) != 16545 NULL) { 16546 /* Add manifest to service */ 16547 (void) find_add_svc_mfst(mfsvc->sc_name, 16548 (*entry)->mi_path); 16549 } 16550 16551 uu_list_walk_end(svcs); 16552 internal_bundle_free(b); 16553 } 16554 16555 free_manifest_array(manifests); 16556 } 16557 } 16558 } 16559 16560 /* 16561 * Check the manifest history file to see 16562 * if the service was ever installed from 16563 * one of the supported directories. 16564 * 16565 * Return Values : 16566 * -1 - if there's error reading manifest history file 16567 * 1 - if the service is not found 16568 * 0 - if the service is found 16569 */ 16570 static int 16571 check_mfst_history(const char *svcname) 16572 { 16573 struct stat st; 16574 caddr_t mfsthist_start; 16575 char *svnbuf; 16576 int fd; 16577 int r = 1; 16578 16579 fd = open(MFSTHISTFILE, O_RDONLY); 16580 if (fd == -1) { 16581 uu_warn(gettext("Unable to open the history file\n")); 16582 return (-1); 16583 } 16584 16585 if (fstat(fd, &st) == -1) { 16586 uu_warn(gettext("Unable to stat the history file\n")); 16587 return (-1); 16588 } 16589 16590 mfsthist_start = mmap(0, st.st_size, PROT_READ, 16591 MAP_PRIVATE, fd, 0); 16592 16593 (void) close(fd); 16594 if (mfsthist_start == MAP_FAILED || 16595 *(mfsthist_start + st.st_size) != '\0') { 16596 (void) munmap(mfsthist_start, st.st_size); 16597 return (-1); 16598 } 16599 16600 /* 16601 * The manifest history file is a space delimited list 16602 * of service and instance to manifest linkage. Adding 16603 * a space to the end of the service name so to get only 16604 * the service that is being searched for. 16605 */ 16606 svnbuf = uu_msprintf("%s ", svcname); 16607 if (svnbuf == NULL) 16608 uu_die(gettext("Out of memory")); 16609 16610 if (strstr(mfsthist_start, svnbuf) != NULL) 16611 r = 0; 16612 16613 (void) munmap(mfsthist_start, st.st_size); 16614 uu_free(svnbuf); 16615 return (r); 16616 } 16617 16618 /* 16619 * Take down each of the instances in the service 16620 * and remove them, then delete the service. 16621 */ 16622 static void 16623 teardown_service(scf_service_t *svc, const char *svnbuf) 16624 { 16625 scf_instance_t *instance; 16626 scf_iter_t *iter; 16627 int r; 16628 16629 safe_printf(gettext("Delete service %s as there are no " 16630 "supporting manifests\n"), svnbuf); 16631 16632 instance = scf_instance_create(g_hndl); 16633 iter = scf_iter_create(g_hndl); 16634 if (iter == NULL || instance == NULL) { 16635 uu_warn(gettext("Unable to create supporting entities to " 16636 "teardown the service\n")); 16637 uu_warn(gettext("scf error is : %s\n"), 16638 scf_strerror(scf_error())); 16639 scfdie(); 16640 } 16641 16642 if (scf_iter_service_instances(iter, svc) != 0) { 16643 switch (scf_error()) { 16644 case SCF_ERROR_CONNECTION_BROKEN: 16645 case SCF_ERROR_DELETED: 16646 goto out; 16647 16648 case SCF_ERROR_HANDLE_MISMATCH: 16649 case SCF_ERROR_NOT_BOUND: 16650 case SCF_ERROR_NOT_SET: 16651 default: 16652 bad_error("scf_iter_service_instances", 16653 scf_error()); 16654 } 16655 } 16656 16657 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 16658 if (r == -1) { 16659 uu_warn(gettext("Error - %s\n"), 16660 scf_strerror(scf_error())); 16661 goto out; 16662 } 16663 16664 (void) disable_instance(instance); 16665 } 16666 16667 /* 16668 * Delete the service... forcing the deletion in case 16669 * any of the instances did not disable. 16670 */ 16671 (void) lscf_service_delete(svc, 1); 16672 out: 16673 scf_instance_destroy(instance); 16674 scf_iter_destroy(iter); 16675 } 16676 16677 /* 16678 * Get the list of instances supported by the manifest 16679 * file. 16680 * 16681 * Return 0 if there are no instances. 16682 * 16683 * Return -1 if there are errors attempting to collect instances. 16684 * 16685 * Return the count of instances found if there are no errors. 16686 * 16687 */ 16688 static int 16689 check_instance_support(char *mfstfile, const char *svcname, 16690 uu_list_t *instances) 16691 { 16692 uu_list_walk_t *svcs, *insts; 16693 uu_list_t *ilist; 16694 bundle_t *b; 16695 entity_t *mfsvc, *mfinst; 16696 const char *svcn; 16697 int rminstcnt = 0; 16698 16699 16700 b = internal_bundle_new(); 16701 16702 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 16703 /* 16704 * Unable to process the manifest file for 16705 * instance support, so just return as 16706 * don't want to remove instances that could 16707 * not be accounted for that might exist here. 16708 */ 16709 internal_bundle_free(b); 16710 return (0); 16711 } 16712 16713 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 16714 if (svcs == NULL) { 16715 internal_bundle_free(b); 16716 return (0); 16717 } 16718 16719 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 16720 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 16721 16722 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 16723 if (strcmp(mfsvc->sc_name, svcn) == 0) 16724 break; 16725 } 16726 uu_list_walk_end(svcs); 16727 16728 if (mfsvc == NULL) { 16729 internal_bundle_free(b); 16730 return (-1); 16731 } 16732 16733 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 16734 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 16735 internal_bundle_free(b); 16736 return (0); 16737 } 16738 16739 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 16740 /* 16741 * Remove the instance from the instances list. 16742 * The unaccounted for instances will be removed 16743 * from the service once all manifests are 16744 * processed. 16745 */ 16746 (void) remove_string(instances, 16747 mfinst->sc_name); 16748 rminstcnt++; 16749 } 16750 16751 uu_list_walk_end(insts); 16752 internal_bundle_free(b); 16753 16754 return (rminstcnt); 16755 } 16756 16757 /* 16758 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 16759 * 'false' to indicate there's no manifest file(s) found for the service. 16760 */ 16761 static void 16762 svc_add_no_support(scf_service_t *svc) 16763 { 16764 char *pname; 16765 16766 /* Add no support */ 16767 cur_svc = svc; 16768 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 16769 return; 16770 16771 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 16772 if (pname == NULL) 16773 uu_die(gettext("Out of memory.\n")); 16774 16775 (void) lscf_addpropvalue(pname, "boolean:", "0"); 16776 16777 uu_free(pname); 16778 cur_svc = NULL; 16779 } 16780 16781 /* 16782 * This function handles all upgrade scenarios for a service that doesn't have 16783 * SCF_PG_MANIFESTFILES pg. The function creates and populates 16784 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 16785 * manifest(s) mapping. Manifests under supported directories are inventoried 16786 * and a property is added for each file that delivers configuration to the 16787 * service. A service that has no corresponding manifest files (deleted) are 16788 * removed from repository. 16789 * 16790 * Unsupported services: 16791 * 16792 * A service is considered unsupported if there is no corresponding manifest 16793 * in the supported directories for that service and the service isn't in the 16794 * history file list. The history file, MFSTHISTFILE, contains a list of all 16795 * services and instances that were delivered by Solaris before the introduction 16796 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 16797 * the path to the manifest file that defined the service or instance. 16798 * 16799 * Another type of unsupported services is 'handcrafted' services, 16800 * programmatically created services or services created by dependent entries 16801 * in other manifests. A handcrafted service is identified by its lack of any 16802 * instance containing last-import snapshot which is created during svccfg 16803 * import. 16804 * 16805 * This function sets a flag for unsupported services by setting services' 16806 * SCF_PG_MANIFESTFILES/support property to false. 16807 */ 16808 static void 16809 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 16810 { 16811 service_manifest_t *elem; 16812 uu_list_walk_t *mfwalk; 16813 string_list_t *mfile; 16814 uu_list_t *instances; 16815 const char *sname; 16816 char *pname; 16817 int r; 16818 16819 /* 16820 * Since there's no guarantee manifests under /var are available during 16821 * early import, don't perform any upgrade during early import. 16822 */ 16823 if (IGNORE_VAR) 16824 return; 16825 16826 if (service_manifest_tree == NULL) { 16827 create_manifest_tree(); 16828 } 16829 16830 /* 16831 * Find service's supporting manifest(s) after 16832 * stripping off the svc:/ prefix that is part 16833 * of the fmri that is not used in the service 16834 * manifest bundle list. 16835 */ 16836 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 16837 strlen(SCF_FMRI_SERVICE_PREFIX); 16838 elem = find_add_svc_mfst(sname, NULL); 16839 if (elem == NULL) { 16840 16841 /* 16842 * A handcrafted service, one that has no instance containing 16843 * last-import snapshot, should get unsupported flag. 16844 */ 16845 instances = create_instance_list(svc, 1); 16846 if (instances == NULL) { 16847 uu_warn(gettext("Unable to create instance list %s\n"), 16848 svcname); 16849 return; 16850 } 16851 16852 if (uu_list_numnodes(instances) == 0) { 16853 svc_add_no_support(svc); 16854 return; 16855 } 16856 16857 /* 16858 * If the service is in the history file, and its supporting 16859 * manifests are not found, we can safely delete the service 16860 * because its manifests are removed from the system. 16861 * 16862 * Services not found in the history file are not delivered by 16863 * Solaris and/or delivered outside supported directories, set 16864 * unsupported flag for these services. 16865 */ 16866 r = check_mfst_history(svcname); 16867 if (r == -1) 16868 return; 16869 16870 if (r) { 16871 /* Set unsupported flag for service */ 16872 svc_add_no_support(svc); 16873 } else { 16874 /* Delete the service */ 16875 teardown_service(svc, svcname); 16876 } 16877 16878 return; 16879 } 16880 16881 /* 16882 * Walk through the list of manifests and add them 16883 * to the service. 16884 * 16885 * Create a manifestfiles pg and add the property. 16886 */ 16887 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 16888 if (mfwalk == NULL) 16889 return; 16890 16891 cur_svc = svc; 16892 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 16893 if (r != 0) { 16894 cur_svc = NULL; 16895 return; 16896 } 16897 16898 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 16899 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16900 mhash_filename_to_propname(mfile->str, 0)); 16901 if (pname == NULL) 16902 uu_die(gettext("Out of memory.\n")); 16903 16904 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 16905 uu_free(pname); 16906 } 16907 uu_list_walk_end(mfwalk); 16908 16909 cur_svc = NULL; 16910 } 16911 16912 /* 16913 * Take a service and process the manifest file entires to see if 16914 * there is continued support for the service and instances. If 16915 * not cleanup as appropriate. 16916 * 16917 * If a service does not have a manifest files entry flag it for 16918 * upgrade and return. 16919 * 16920 * For each manifestfiles property check if the manifest file is 16921 * under the supported /lib/svc/manifest or /var/svc/manifest path 16922 * and if not then return immediately as this service is not supported 16923 * by the cleanup mechanism and should be ignored. 16924 * 16925 * For each manifest file that is supported, check to see if the 16926 * file exists. If not then remove the manifest file property 16927 * from the service and the smf/manifest hash table. If the manifest 16928 * file exists then verify that it supports the instances that are 16929 * part of the service. 16930 * 16931 * Once all manifest files have been accounted for remove any instances 16932 * that are no longer supported in the service. 16933 * 16934 * Return values : 16935 * 0 - Successfully processed the service 16936 * non-zero - failed to process the service 16937 * 16938 * On most errors, will just return to wait and get the next service, 16939 * unless in case of unable to create the needed structures which is 16940 * most likely a fatal error that is not going to be recoverable. 16941 */ 16942 int 16943 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 16944 { 16945 struct mpg_mfile *mpntov; 16946 struct mpg_mfile **mpvarry = NULL; 16947 scf_service_t *svc; 16948 scf_propertygroup_t *mpg; 16949 scf_property_t *mp; 16950 scf_value_t *mv; 16951 scf_iter_t *mi; 16952 scf_instance_t *instance; 16953 uu_list_walk_t *insts; 16954 uu_list_t *instances = NULL; 16955 boolean_t activity = (boolean_t)act; 16956 char *mpnbuf; 16957 char *mpvbuf; 16958 char *pgpropbuf; 16959 int mfstcnt, rminstct, instct, mfstmax; 16960 int index; 16961 int r = 0; 16962 16963 assert(g_hndl != NULL); 16964 assert(wip->svc != NULL); 16965 assert(wip->fmri != NULL); 16966 16967 svc = wip->svc; 16968 16969 mpg = scf_pg_create(g_hndl); 16970 mp = scf_property_create(g_hndl); 16971 mi = scf_iter_create(g_hndl); 16972 mv = scf_value_create(g_hndl); 16973 instance = scf_instance_create(g_hndl); 16974 16975 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 16976 instance == NULL) { 16977 uu_warn(gettext("Unable to create the supporting entities\n")); 16978 uu_warn(gettext("scf error is : %s\n"), 16979 scf_strerror(scf_error())); 16980 scfdie(); 16981 } 16982 16983 /* 16984 * Get the manifestfiles property group to be parsed for 16985 * files existence. 16986 */ 16987 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 16988 switch (scf_error()) { 16989 case SCF_ERROR_NOT_FOUND: 16990 upgrade_svc_mfst_connection(svc, wip->fmri); 16991 break; 16992 case SCF_ERROR_DELETED: 16993 case SCF_ERROR_CONNECTION_BROKEN: 16994 goto out; 16995 16996 case SCF_ERROR_HANDLE_MISMATCH: 16997 case SCF_ERROR_NOT_BOUND: 16998 case SCF_ERROR_NOT_SET: 16999 default: 17000 bad_error("scf_iter_pg_properties", 17001 scf_error()); 17002 } 17003 17004 goto out; 17005 } 17006 17007 /* 17008 * Iterate through each of the manifestfiles properties 17009 * to determine what manifestfiles are available. 17010 * 17011 * If a manifest file is supported then increment the 17012 * count and therefore the service is safe. 17013 */ 17014 if (scf_iter_pg_properties(mi, mpg) != 0) { 17015 switch (scf_error()) { 17016 case SCF_ERROR_DELETED: 17017 case SCF_ERROR_CONNECTION_BROKEN: 17018 goto out; 17019 17020 case SCF_ERROR_HANDLE_MISMATCH: 17021 case SCF_ERROR_NOT_BOUND: 17022 case SCF_ERROR_NOT_SET: 17023 default: 17024 bad_error("scf_iter_pg_properties", 17025 scf_error()); 17026 } 17027 } 17028 17029 mfstcnt = 0; 17030 mfstmax = MFSTFILE_MAX; 17031 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 17032 while ((r = scf_iter_next_property(mi, mp)) != 0) { 17033 if (r == -1) 17034 bad_error(gettext("Unable to iterate through " 17035 "manifestfiles properties : %s"), 17036 scf_error()); 17037 17038 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 17039 mpnbuf = safe_malloc(max_scf_name_len + 1); 17040 mpvbuf = safe_malloc(max_scf_value_len + 1); 17041 mpntov->mpg = mpnbuf; 17042 mpntov->mfile = mpvbuf; 17043 mpntov->access = 1; 17044 if (scf_property_get_name(mp, mpnbuf, 17045 max_scf_name_len + 1) < 0) { 17046 uu_warn(gettext("Unable to get manifest file " 17047 "property : %s\n"), 17048 scf_strerror(scf_error())); 17049 17050 switch (scf_error()) { 17051 case SCF_ERROR_DELETED: 17052 case SCF_ERROR_CONNECTION_BROKEN: 17053 r = scferror2errno(scf_error()); 17054 goto out_free; 17055 17056 case SCF_ERROR_HANDLE_MISMATCH: 17057 case SCF_ERROR_NOT_BOUND: 17058 case SCF_ERROR_NOT_SET: 17059 default: 17060 bad_error("scf_iter_pg_properties", 17061 scf_error()); 17062 } 17063 } 17064 17065 /* 17066 * The support property is a boolean value that indicates 17067 * if the service is supported for manifest file deletion. 17068 * Currently at this time there is no code that sets this 17069 * value to true. So while we could just let this be caught 17070 * by the support check below, in the future this by be set 17071 * to true and require processing. So for that, go ahead 17072 * and check here, and just return if false. Otherwise, 17073 * fall through expecting that other support checks will 17074 * handle the entries. 17075 */ 17076 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 17077 uint8_t support; 17078 17079 if (scf_property_get_value(mp, mv) != 0 || 17080 scf_value_get_boolean(mv, &support) != 0) { 17081 uu_warn(gettext("Unable to get the manifest " 17082 "support value: %s\n"), 17083 scf_strerror(scf_error())); 17084 17085 switch (scf_error()) { 17086 case SCF_ERROR_DELETED: 17087 case SCF_ERROR_CONNECTION_BROKEN: 17088 r = scferror2errno(scf_error()); 17089 goto out_free; 17090 17091 case SCF_ERROR_HANDLE_MISMATCH: 17092 case SCF_ERROR_NOT_BOUND: 17093 case SCF_ERROR_NOT_SET: 17094 default: 17095 bad_error("scf_iter_pg_properties", 17096 scf_error()); 17097 } 17098 } 17099 17100 if (support == B_FALSE) 17101 goto out_free; 17102 } 17103 17104 /* 17105 * Anything with a manifest outside of the supported 17106 * directories, immediately bail out because that makes 17107 * this service non-supported. We don't even want 17108 * to do instance processing in this case because the 17109 * instances could be part of the non-supported manifest. 17110 */ 17111 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 17112 /* 17113 * Manifest is not in /lib/svc, so we need to 17114 * consider the /var/svc case. 17115 */ 17116 if (strncmp(mpnbuf, VARSVC_PR, 17117 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 17118 /* 17119 * Either the manifest is not in /var/svc or 17120 * /var is not yet mounted. We ignore the 17121 * manifest either because it is not in a 17122 * standard location or because we cannot 17123 * currently access the manifest. 17124 */ 17125 goto out_free; 17126 } 17127 } 17128 17129 /* 17130 * Get the value to of the manifest file for this entry 17131 * for access verification and instance support 17132 * verification if it still exists. 17133 * 17134 * During Early Manifest Import if the manifest is in 17135 * /var/svc then it may not yet be available for checking 17136 * so we must determine if /var/svc is available. If not 17137 * then defer until Late Manifest Import to cleanup. 17138 */ 17139 if (scf_property_get_value(mp, mv) != 0) { 17140 uu_warn(gettext("Unable to get the manifest file " 17141 "value: %s\n"), 17142 scf_strerror(scf_error())); 17143 17144 switch (scf_error()) { 17145 case SCF_ERROR_DELETED: 17146 case SCF_ERROR_CONNECTION_BROKEN: 17147 r = scferror2errno(scf_error()); 17148 goto out_free; 17149 17150 case SCF_ERROR_HANDLE_MISMATCH: 17151 case SCF_ERROR_NOT_BOUND: 17152 case SCF_ERROR_NOT_SET: 17153 default: 17154 bad_error("scf_property_get_value", 17155 scf_error()); 17156 } 17157 } 17158 17159 if (scf_value_get_astring(mv, mpvbuf, 17160 max_scf_value_len + 1) < 0) { 17161 uu_warn(gettext("Unable to get the manifest " 17162 "file : %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_value_get_astring", 17176 scf_error()); 17177 } 17178 } 17179 17180 mpvarry[mfstcnt] = mpntov; 17181 mfstcnt++; 17182 17183 /* 17184 * Check for the need to reallocate array 17185 */ 17186 if (mfstcnt >= (mfstmax - 1)) { 17187 struct mpg_mfile **newmpvarry; 17188 17189 mfstmax = mfstmax * 2; 17190 newmpvarry = realloc(mpvarry, 17191 sizeof (struct mpg_mfile *) * mfstmax); 17192 17193 if (newmpvarry == NULL) 17194 goto out_free; 17195 17196 mpvarry = newmpvarry; 17197 } 17198 17199 mpvarry[mfstcnt] = NULL; 17200 } 17201 17202 for (index = 0; mpvarry[index]; index++) { 17203 mpntov = mpvarry[index]; 17204 17205 /* 17206 * Check to see if the manifestfile is accessable, if so hand 17207 * this service and manifestfile off to be processed for 17208 * instance support. 17209 */ 17210 mpnbuf = mpntov->mpg; 17211 mpvbuf = mpntov->mfile; 17212 if (access(mpvbuf, F_OK) != 0) { 17213 mpntov->access = 0; 17214 activity++; 17215 mfstcnt--; 17216 /* Remove the entry from the service */ 17217 cur_svc = svc; 17218 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 17219 mpnbuf); 17220 if (pgpropbuf == NULL) 17221 uu_die(gettext("Out of memory.\n")); 17222 17223 lscf_delprop(pgpropbuf); 17224 cur_svc = NULL; 17225 17226 uu_free(pgpropbuf); 17227 } 17228 } 17229 17230 /* 17231 * If mfstcnt is 0, none of the manifests that supported the service 17232 * existed so remove the service. 17233 */ 17234 if (mfstcnt == 0) { 17235 teardown_service(svc, wip->fmri); 17236 17237 goto out_free; 17238 } 17239 17240 if (activity) { 17241 int nosvcsupport = 0; 17242 17243 /* 17244 * If the list of service instances is NULL then 17245 * create the list. 17246 */ 17247 instances = create_instance_list(svc, 1); 17248 if (instances == NULL) { 17249 uu_warn(gettext("Unable to create instance list %s\n"), 17250 wip->fmri); 17251 goto out_free; 17252 } 17253 17254 rminstct = uu_list_numnodes(instances); 17255 instct = rminstct; 17256 17257 for (index = 0; mpvarry[index]; index++) { 17258 mpntov = mpvarry[index]; 17259 if (mpntov->access == 0) 17260 continue; 17261 17262 mpnbuf = mpntov->mpg; 17263 mpvbuf = mpntov->mfile; 17264 r = check_instance_support(mpvbuf, wip->fmri, 17265 instances); 17266 if (r == -1) { 17267 nosvcsupport++; 17268 } else { 17269 rminstct -= r; 17270 } 17271 } 17272 17273 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 17274 teardown_service(svc, wip->fmri); 17275 17276 goto out_free; 17277 } 17278 } 17279 17280 /* 17281 * If there are instances left on the instance list, then 17282 * we must remove them. 17283 */ 17284 if (instances != NULL && uu_list_numnodes(instances)) { 17285 string_list_t *sp; 17286 17287 insts = uu_list_walk_start(instances, 0); 17288 while ((sp = uu_list_walk_next(insts)) != NULL) { 17289 /* 17290 * Remove the instance from the instances list. 17291 */ 17292 safe_printf(gettext("Delete instance %s from " 17293 "service %s\n"), sp->str, wip->fmri); 17294 if (scf_service_get_instance(svc, sp->str, 17295 instance) != SCF_SUCCESS) { 17296 (void) uu_warn("scf_error - %s\n", 17297 scf_strerror(scf_error())); 17298 17299 continue; 17300 } 17301 17302 (void) disable_instance(instance); 17303 17304 (void) lscf_instance_delete(instance, 1); 17305 } 17306 scf_instance_destroy(instance); 17307 uu_list_walk_end(insts); 17308 } 17309 17310 out_free: 17311 if (mpvarry) { 17312 struct mpg_mfile *fmpntov; 17313 17314 for (index = 0; mpvarry[index]; index++) { 17315 fmpntov = mpvarry[index]; 17316 if (fmpntov->mpg == mpnbuf) 17317 mpnbuf = NULL; 17318 free(fmpntov->mpg); 17319 17320 if (fmpntov->mfile == mpvbuf) 17321 mpvbuf = NULL; 17322 free(fmpntov->mfile); 17323 17324 if (fmpntov == mpntov) 17325 mpntov = NULL; 17326 free(fmpntov); 17327 } 17328 if (mpnbuf) 17329 free(mpnbuf); 17330 if (mpvbuf) 17331 free(mpvbuf); 17332 if (mpntov) 17333 free(mpntov); 17334 17335 free(mpvarry); 17336 } 17337 out: 17338 scf_pg_destroy(mpg); 17339 scf_property_destroy(mp); 17340 scf_iter_destroy(mi); 17341 scf_value_destroy(mv); 17342 17343 return (0); 17344 } 17345 17346 /* 17347 * Take the service and search for the manifestfiles property 17348 * in each of the property groups. If the manifest file 17349 * associated with the property does not exist then remove 17350 * the property group. 17351 */ 17352 int 17353 lscf_hash_cleanup() 17354 { 17355 scf_service_t *svc; 17356 scf_scope_t *scope; 17357 scf_propertygroup_t *pg; 17358 scf_property_t *prop; 17359 scf_value_t *val; 17360 scf_iter_t *iter; 17361 char *pgname = NULL; 17362 char *mfile = NULL; 17363 int r; 17364 17365 svc = scf_service_create(g_hndl); 17366 scope = scf_scope_create(g_hndl); 17367 pg = scf_pg_create(g_hndl); 17368 prop = scf_property_create(g_hndl); 17369 val = scf_value_create(g_hndl); 17370 iter = scf_iter_create(g_hndl); 17371 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 17372 svc == NULL || scope == NULL) { 17373 uu_warn(gettext("Unable to create a property group, or " 17374 "property\n")); 17375 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 17376 "pg is not NULL"); 17377 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 17378 "prop is not NULL"); 17379 uu_warn("%s\n", val == NULL ? "val is NULL" : 17380 "val is not NULL"); 17381 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 17382 "iter is not NULL"); 17383 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 17384 "svc is not NULL"); 17385 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 17386 "scope is not NULL"); 17387 uu_warn(gettext("scf error is : %s\n"), 17388 scf_strerror(scf_error())); 17389 scfdie(); 17390 } 17391 17392 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 17393 switch (scf_error()) { 17394 case SCF_ERROR_CONNECTION_BROKEN: 17395 case SCF_ERROR_NOT_FOUND: 17396 goto out; 17397 17398 case SCF_ERROR_HANDLE_MISMATCH: 17399 case SCF_ERROR_NOT_BOUND: 17400 case SCF_ERROR_INVALID_ARGUMENT: 17401 default: 17402 bad_error("scf_handle_get_scope", scf_error()); 17403 } 17404 } 17405 17406 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 17407 uu_warn(gettext("Unable to process the hash service, %s\n"), 17408 HASH_SVC); 17409 goto out; 17410 } 17411 17412 pgname = safe_malloc(max_scf_name_len + 1); 17413 mfile = safe_malloc(max_scf_value_len + 1); 17414 17415 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 17416 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 17417 scf_strerror(scf_error())); 17418 goto out; 17419 } 17420 17421 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 17422 if (r == -1) 17423 goto out; 17424 17425 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 17426 switch (scf_error()) { 17427 case SCF_ERROR_DELETED: 17428 return (ENODEV); 17429 17430 case SCF_ERROR_CONNECTION_BROKEN: 17431 return (ECONNABORTED); 17432 17433 case SCF_ERROR_NOT_SET: 17434 case SCF_ERROR_NOT_BOUND: 17435 default: 17436 bad_error("scf_pg_get_name", scf_error()); 17437 } 17438 } 17439 if (IGNORE_VAR) { 17440 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 17441 continue; 17442 } 17443 17444 /* 17445 * If unable to get the property continue as this is an 17446 * entry that has no location to check against. 17447 */ 17448 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 17449 continue; 17450 } 17451 17452 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 17453 uu_warn(gettext("Unable to get value from %s\n"), 17454 pgname); 17455 17456 switch (scf_error()) { 17457 case SCF_ERROR_DELETED: 17458 case SCF_ERROR_CONSTRAINT_VIOLATED: 17459 case SCF_ERROR_NOT_FOUND: 17460 case SCF_ERROR_NOT_SET: 17461 continue; 17462 17463 case SCF_ERROR_CONNECTION_BROKEN: 17464 r = scferror2errno(scf_error()); 17465 goto out; 17466 17467 case SCF_ERROR_HANDLE_MISMATCH: 17468 case SCF_ERROR_NOT_BOUND: 17469 default: 17470 bad_error("scf_property_get_value", 17471 scf_error()); 17472 } 17473 } 17474 17475 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) 17476 == -1) { 17477 uu_warn(gettext("Unable to get astring from %s : %s\n"), 17478 pgname, scf_strerror(scf_error())); 17479 17480 switch (scf_error()) { 17481 case SCF_ERROR_NOT_SET: 17482 case SCF_ERROR_TYPE_MISMATCH: 17483 continue; 17484 17485 default: 17486 bad_error("scf_value_get_astring", scf_error()); 17487 } 17488 } 17489 17490 if (access(mfile, F_OK) == 0) 17491 continue; 17492 17493 (void) scf_pg_delete(pg); 17494 } 17495 17496 out: 17497 scf_scope_destroy(scope); 17498 scf_service_destroy(svc); 17499 scf_pg_destroy(pg); 17500 scf_property_destroy(prop); 17501 scf_value_destroy(val); 17502 scf_iter_destroy(iter); 17503 free(pgname); 17504 free(mfile); 17505 17506 return (0); 17507 } 17508 17509 #ifndef NATIVE_BUILD 17510 /* ARGSUSED */ 17511 CPL_MATCH_FN(complete_select) 17512 { 17513 const char *arg0, *arg1, *arg1end; 17514 int word_start, err = 0, r; 17515 size_t len; 17516 char *buf; 17517 17518 lscf_prep_hndl(); 17519 17520 arg0 = line + strspn(line, " \t"); 17521 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 17522 17523 arg1 = arg0 + sizeof ("select") - 1; 17524 arg1 += strspn(arg1, " \t"); 17525 word_start = arg1 - line; 17526 17527 arg1end = arg1 + strcspn(arg1, " \t"); 17528 if (arg1end < line + word_end) 17529 return (0); 17530 17531 len = line + word_end - arg1; 17532 17533 buf = safe_malloc(max_scf_name_len + 1); 17534 17535 if (cur_snap != NULL) { 17536 return (0); 17537 } else if (cur_inst != NULL) { 17538 return (0); 17539 } else if (cur_svc != NULL) { 17540 scf_instance_t *inst; 17541 scf_iter_t *iter; 17542 17543 if ((inst = scf_instance_create(g_hndl)) == NULL || 17544 (iter = scf_iter_create(g_hndl)) == NULL) 17545 scfdie(); 17546 17547 if (scf_iter_service_instances(iter, cur_svc) != 0) 17548 scfdie(); 17549 17550 for (;;) { 17551 r = scf_iter_next_instance(iter, inst); 17552 if (r == 0) 17553 break; 17554 if (r != 1) 17555 scfdie(); 17556 17557 if (scf_instance_get_name(inst, buf, 17558 max_scf_name_len + 1) < 0) 17559 scfdie(); 17560 17561 if (strncmp(buf, arg1, len) == 0) { 17562 err = cpl_add_completion(cpl, line, word_start, 17563 word_end, buf + len, "", " "); 17564 if (err != 0) 17565 break; 17566 } 17567 } 17568 17569 scf_iter_destroy(iter); 17570 scf_instance_destroy(inst); 17571 17572 return (err); 17573 } else { 17574 scf_service_t *svc; 17575 scf_iter_t *iter; 17576 17577 assert(cur_scope != NULL); 17578 17579 if ((svc = scf_service_create(g_hndl)) == NULL || 17580 (iter = scf_iter_create(g_hndl)) == NULL) 17581 scfdie(); 17582 17583 if (scf_iter_scope_services(iter, cur_scope) != 0) 17584 scfdie(); 17585 17586 for (;;) { 17587 r = scf_iter_next_service(iter, svc); 17588 if (r == 0) 17589 break; 17590 if (r != 1) 17591 scfdie(); 17592 17593 if (scf_service_get_name(svc, buf, 17594 max_scf_name_len + 1) < 0) 17595 scfdie(); 17596 17597 if (strncmp(buf, arg1, len) == 0) { 17598 err = cpl_add_completion(cpl, line, word_start, 17599 word_end, buf + len, "", " "); 17600 if (err != 0) 17601 break; 17602 } 17603 } 17604 17605 scf_iter_destroy(iter); 17606 scf_service_destroy(svc); 17607 17608 return (err); 17609 } 17610 } 17611 17612 /* ARGSUSED */ 17613 CPL_MATCH_FN(complete_command) 17614 { 17615 uint32_t scope = 0; 17616 17617 if (cur_snap != NULL) 17618 scope = CS_SNAP; 17619 else if (cur_inst != NULL) 17620 scope = CS_INST; 17621 else if (cur_svc != NULL) 17622 scope = CS_SVC; 17623 else 17624 scope = CS_SCOPE; 17625 17626 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 17627 } 17628 #endif /* NATIVE_BUILD */