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 * Copyright 2017 RackTop Systems. 27 */ 28 29 30 #include <alloca.h> 31 #include <assert.h> 32 #include <ctype.h> 33 #include <door.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <fnmatch.h> 37 #include <inttypes.h> 38 #include <libintl.h> 39 #include <libnvpair.h> 40 #include <libscf.h> 41 #include <libscf_priv.h> 42 #include <libtecla.h> 43 #include <libuutil.h> 44 #include <limits.h> 45 #include <locale.h> 46 #include <stdarg.h> 47 #include <string.h> 48 #include <strings.h> 49 #include <time.h> 50 #include <unistd.h> 51 #include <wait.h> 52 #include <poll.h> 53 54 #include <libxml/tree.h> 55 56 #include <sys/param.h> 57 58 #include <sys/stat.h> 59 #include <sys/mman.h> 60 61 #include "svccfg.h" 62 #include "notify_params.h" 63 #include "manifest_hash.h" 64 #include "manifest_find.h" 65 66 /* The colon namespaces in each entity (each followed by a newline). */ 67 #define COLON_NAMESPACES ":properties\n" 68 69 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 70 71 /* These are characters which the lexer requires to be in double-quotes. */ 72 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 73 74 #define HASH_SIZE 16 75 #define HASH_PG_TYPE "framework" 76 #define HASH_PG_FLAGS 0 77 #define HASH_PROP "md5sum" 78 79 /* 80 * Indentation used in the output of the describe subcommand. 81 */ 82 #define TMPL_VALUE_INDENT " " 83 #define TMPL_INDENT " " 84 #define TMPL_INDENT_2X " " 85 #define TMPL_CHOICE_INDENT " " 86 87 /* 88 * Directory locations for manifests 89 */ 90 #define VARSVC_DIR "/var/svc/manifest" 91 #define LIBSVC_DIR "/lib/svc/manifest" 92 #define VARSVC_PR "var_svc_manifest" 93 #define LIBSVC_PR "lib_svc_manifest" 94 #define MFSTFILEPR "manifestfile" 95 96 #define SUPPORTPROP "support" 97 98 #define MFSTHISTFILE "/lib/svc/share/mfsthistory" 99 100 #define MFSTFILE_MAX 16 101 102 /* 103 * These are the classes of elements which may appear as children of service 104 * or instance elements in XML manifests. 105 */ 106 struct entity_elts { 107 xmlNodePtr create_default_instance; 108 xmlNodePtr single_instance; 109 xmlNodePtr restarter; 110 xmlNodePtr dependencies; 111 xmlNodePtr dependents; 112 xmlNodePtr method_context; 113 xmlNodePtr exec_methods; 114 xmlNodePtr notify_params; 115 xmlNodePtr property_groups; 116 xmlNodePtr instances; 117 xmlNodePtr stability; 118 xmlNodePtr template; 119 }; 120 121 /* 122 * Likewise for property_group elements. 123 */ 124 struct pg_elts { 125 xmlNodePtr stability; 126 xmlNodePtr propvals; 127 xmlNodePtr properties; 128 }; 129 130 /* 131 * Likewise for template elements. 132 */ 133 struct template_elts { 134 xmlNodePtr common_name; 135 xmlNodePtr description; 136 xmlNodePtr documentation; 137 }; 138 139 /* 140 * Likewise for type (for notification parameters) elements. 141 */ 142 struct params_elts { 143 xmlNodePtr paramval; 144 xmlNodePtr parameter; 145 }; 146 147 /* 148 * This structure is for snaplevel lists. They are convenient because libscf 149 * only allows traversing snaplevels in one direction. 150 */ 151 struct snaplevel { 152 uu_list_node_t list_node; 153 scf_snaplevel_t *sl; 154 }; 155 156 /* 157 * This is used for communication between lscf_service_export and 158 * export_callback. 159 */ 160 struct export_args { 161 const char *filename; 162 int flags; 163 }; 164 165 /* 166 * The service_manifest structure is used by the upgrade process 167 * to create a list of service to manifest linkages from the manifests 168 * in a set of given directories. 169 */ 170 typedef struct service_manifest { 171 const char *servicename; 172 uu_list_t *mfstlist; 173 size_t mfstlist_sz; 174 175 uu_avl_node_t svcmfst_node; 176 } service_manifest_t; 177 178 /* 179 * Structure to track the manifest file property group 180 * and the manifest file associated with that property 181 * group. Also, a flag to keep the access once it has 182 * been checked. 183 */ 184 struct mpg_mfile { 185 char *mpg; 186 char *mfile; 187 int access; 188 }; 189 190 const char * const scf_pg_general = SCF_PG_GENERAL; 191 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 192 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 193 const char * const scf_property_external = "external"; 194 195 const char * const snap_initial = "initial"; 196 const char * const snap_lastimport = "last-import"; 197 const char * const snap_previous = "previous"; 198 const char * const snap_running = "running"; 199 200 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 201 202 ssize_t max_scf_fmri_len; 203 ssize_t max_scf_name_len; 204 ssize_t max_scf_pg_type_len; 205 ssize_t max_scf_value_len; 206 static size_t max_scf_len; 207 208 static scf_scope_t *cur_scope; 209 static scf_service_t *cur_svc = NULL; 210 static scf_instance_t *cur_inst = NULL; 211 static scf_snapshot_t *cur_snap = NULL; 212 static scf_snaplevel_t *cur_level = NULL; 213 214 static uu_list_pool_t *snaplevel_pool; 215 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 216 static uu_list_t *cur_levels; 217 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 218 219 static FILE *tempfile = NULL; 220 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 221 222 static const char *emsg_entity_not_selected; 223 static const char *emsg_permission_denied; 224 static const char *emsg_create_xml; 225 static const char *emsg_cant_modify_snapshots; 226 static const char *emsg_invalid_for_snapshot; 227 static const char *emsg_read_only; 228 static const char *emsg_deleted; 229 static const char *emsg_invalid_pg_name; 230 static const char *emsg_invalid_prop_name; 231 static const char *emsg_no_such_pg; 232 static const char *emsg_fmri_invalid_pg_name; 233 static const char *emsg_fmri_invalid_pg_name_type; 234 static const char *emsg_pg_added; 235 static const char *emsg_pg_changed; 236 static const char *emsg_pg_deleted; 237 static const char *emsg_pg_mod_perm; 238 static const char *emsg_pg_add_perm; 239 static const char *emsg_pg_del_perm; 240 static const char *emsg_snap_perm; 241 static const char *emsg_dpt_dangling; 242 static const char *emsg_dpt_no_dep; 243 244 static int li_only = 0; 245 static int no_refresh = 0; 246 247 /* how long in ns we should wait between checks for a pg */ 248 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC); 249 250 /* import globals, to minimize allocations */ 251 static scf_scope_t *imp_scope = NULL; 252 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 253 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 254 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 255 static scf_snapshot_t *imp_rsnap = NULL; 256 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 257 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 258 static scf_property_t *imp_prop = NULL; 259 static scf_iter_t *imp_iter = NULL; 260 static scf_iter_t *imp_rpg_iter = NULL; 261 static scf_iter_t *imp_up_iter = NULL; 262 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 263 static char *imp_str = NULL; 264 static size_t imp_str_sz; 265 static char *imp_tsname = NULL; 266 static char *imp_fe1 = NULL; /* for fmri_equal() */ 267 static char *imp_fe2 = NULL; 268 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 269 270 /* upgrade_dependents() globals */ 271 static scf_instance_t *ud_inst = NULL; 272 static scf_snaplevel_t *ud_snpl = NULL; 273 static scf_propertygroup_t *ud_pg = NULL; 274 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 275 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 276 static int ud_run_dpts_pg_set = 0; 277 static scf_property_t *ud_prop = NULL; 278 static scf_property_t *ud_dpt_prop = NULL; 279 static scf_value_t *ud_val = NULL; 280 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 281 static scf_transaction_t *ud_tx = NULL; 282 static char *ud_ctarg = NULL; 283 static char *ud_oldtarg = NULL; 284 static char *ud_name = NULL; 285 286 /* export globals */ 287 static scf_instance_t *exp_inst; 288 static scf_propertygroup_t *exp_pg; 289 static scf_property_t *exp_prop; 290 static scf_value_t *exp_val; 291 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 292 static char *exp_str; 293 static size_t exp_str_sz; 294 295 /* cleanup globals */ 296 static uu_avl_pool_t *service_manifest_pool = NULL; 297 static uu_avl_t *service_manifest_tree = NULL; 298 299 static void scfdie_lineno(int lineno) __NORETURN; 300 301 static char *start_method_names[] = { 302 "start", 303 "inetd_start", 304 NULL 305 }; 306 307 static struct uri_scheme { 308 const char *scheme; 309 const char *protocol; 310 } uri_scheme[] = { 311 { "mailto", "smtp" }, 312 { "snmp", "snmp" }, 313 { "syslog", "syslog" }, 314 { NULL, NULL } 315 }; 316 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \ 317 sizeof (struct uri_scheme)) - 1) 318 319 static int 320 check_uri_scheme(const char *scheme) 321 { 322 int i; 323 324 for (i = 0; uri_scheme[i].scheme != NULL; ++i) { 325 if (strcmp(scheme, uri_scheme[i].scheme) == 0) 326 return (i); 327 } 328 329 return (-1); 330 } 331 332 static int 333 check_uri_protocol(const char *p) 334 { 335 int i; 336 337 for (i = 0; uri_scheme[i].protocol != NULL; ++i) { 338 if (strcmp(p, uri_scheme[i].protocol) == 0) 339 return (i); 340 } 341 342 return (-1); 343 } 344 345 /* 346 * For unexpected libscf errors. 347 */ 348 #ifdef NDEBUG 349 350 static void scfdie(void) __NORETURN; 351 352 static void 353 scfdie(void) 354 { 355 scf_error_t err = scf_error(); 356 357 if (err == SCF_ERROR_CONNECTION_BROKEN) 358 uu_die(gettext("Repository connection broken. Exiting.\n")); 359 360 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 361 scf_strerror(err)); 362 } 363 364 #else 365 366 #define scfdie() scfdie_lineno(__LINE__) 367 368 static void 369 scfdie_lineno(int lineno) 370 { 371 scf_error_t err = scf_error(); 372 373 if (err == SCF_ERROR_CONNECTION_BROKEN) 374 uu_die(gettext("Repository connection broken. Exiting.\n")); 375 376 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 377 ": %s.\n"), lineno, scf_strerror(err)); 378 } 379 380 #endif 381 382 static void 383 scfwarn(void) 384 { 385 warn(gettext("Unexpected libscf error: %s.\n"), 386 scf_strerror(scf_error())); 387 } 388 389 /* 390 * Clear a field of a structure. 391 */ 392 static int 393 clear_int(void *a, void *b) 394 { 395 /* LINTED */ 396 *(int *)((char *)a + (size_t)b) = 0; 397 398 return (UU_WALK_NEXT); 399 } 400 401 static int 402 scferror2errno(scf_error_t err) 403 { 404 switch (err) { 405 case SCF_ERROR_BACKEND_ACCESS: 406 return (EACCES); 407 408 case SCF_ERROR_BACKEND_READONLY: 409 return (EROFS); 410 411 case SCF_ERROR_CONNECTION_BROKEN: 412 return (ECONNABORTED); 413 414 case SCF_ERROR_CONSTRAINT_VIOLATED: 415 case SCF_ERROR_INVALID_ARGUMENT: 416 return (EINVAL); 417 418 case SCF_ERROR_DELETED: 419 return (ECANCELED); 420 421 case SCF_ERROR_EXISTS: 422 return (EEXIST); 423 424 case SCF_ERROR_NO_MEMORY: 425 return (ENOMEM); 426 427 case SCF_ERROR_NO_RESOURCES: 428 return (ENOSPC); 429 430 case SCF_ERROR_NOT_FOUND: 431 return (ENOENT); 432 433 case SCF_ERROR_PERMISSION_DENIED: 434 return (EPERM); 435 436 default: 437 #ifndef NDEBUG 438 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 439 __FILE__, __LINE__, err); 440 #else 441 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 442 #endif 443 abort(); 444 /* NOTREACHED */ 445 } 446 } 447 448 static int 449 entity_get_pg(void *ent, int issvc, const char *name, 450 scf_propertygroup_t *pg) 451 { 452 if (issvc) 453 return (scf_service_get_pg(ent, name, pg)); 454 else 455 return (scf_instance_get_pg(ent, name, pg)); 456 } 457 458 static void 459 entity_destroy(void *ent, int issvc) 460 { 461 if (issvc) 462 scf_service_destroy(ent); 463 else 464 scf_instance_destroy(ent); 465 } 466 467 static int 468 get_pg(const char *pg_name, scf_propertygroup_t *pg) 469 { 470 int ret; 471 472 if (cur_level != NULL) 473 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 474 else if (cur_inst != NULL) 475 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 476 else 477 ret = scf_service_get_pg(cur_svc, pg_name, pg); 478 479 return (ret); 480 } 481 482 /* 483 * Find a snaplevel in a snapshot. If get_svc is true, find the service 484 * snaplevel. Otherwise find the instance snaplevel. 485 * 486 * Returns 487 * 0 - success 488 * ECONNABORTED - repository connection broken 489 * ECANCELED - instance containing snap was deleted 490 * ENOENT - snap has no snaplevels 491 * - requested snaplevel not found 492 */ 493 static int 494 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 495 { 496 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 497 switch (scf_error()) { 498 case SCF_ERROR_CONNECTION_BROKEN: 499 case SCF_ERROR_DELETED: 500 case SCF_ERROR_NOT_FOUND: 501 return (scferror2errno(scf_error())); 502 503 case SCF_ERROR_HANDLE_MISMATCH: 504 case SCF_ERROR_NOT_BOUND: 505 case SCF_ERROR_NOT_SET: 506 default: 507 bad_error("scf_snapshot_get_base_snaplevel", 508 scf_error()); 509 } 510 } 511 512 for (;;) { 513 ssize_t ssz; 514 515 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 516 if (ssz >= 0) { 517 if (!get_svc) 518 return (0); 519 } else { 520 switch (scf_error()) { 521 case SCF_ERROR_CONSTRAINT_VIOLATED: 522 if (get_svc) 523 return (0); 524 break; 525 526 case SCF_ERROR_DELETED: 527 case SCF_ERROR_CONNECTION_BROKEN: 528 return (scferror2errno(scf_error())); 529 530 case SCF_ERROR_NOT_SET: 531 case SCF_ERROR_NOT_BOUND: 532 default: 533 bad_error("scf_snaplevel_get_instance_name", 534 scf_error()); 535 } 536 } 537 538 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 539 switch (scf_error()) { 540 case SCF_ERROR_NOT_FOUND: 541 case SCF_ERROR_CONNECTION_BROKEN: 542 case SCF_ERROR_DELETED: 543 return (scferror2errno(scf_error())); 544 545 case SCF_ERROR_HANDLE_MISMATCH: 546 case SCF_ERROR_NOT_BOUND: 547 case SCF_ERROR_NOT_SET: 548 case SCF_ERROR_INVALID_ARGUMENT: 549 default: 550 bad_error("scf_snaplevel_get_next_snaplevel", 551 scf_error()); 552 } 553 } 554 } 555 } 556 557 /* 558 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 559 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 560 * the property group named name in it. If it doesn't have a running 561 * snapshot, set pg to the instance's current property group named name. 562 * 563 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 564 * its instances. If one has a running snapshot with a service snaplevel, set 565 * pg to the property group named name in it. If no such snaplevel could be 566 * found, set pg to the service's current property group named name. 567 * 568 * iter, inst, snap, and snpl are required scratch objects. 569 * 570 * Returns 571 * 0 - success 572 * ECONNABORTED - repository connection broken 573 * ECANCELED - ent was deleted 574 * ENOENT - no such property group 575 * EINVAL - name is an invalid property group name 576 * EBADF - found running snapshot is missing a snaplevel 577 */ 578 static int 579 entity_get_running_pg(void *ent, int issvc, const char *name, 580 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 581 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 582 { 583 int r; 584 585 if (issvc) { 586 /* Search for an instance with a running snapshot. */ 587 if (scf_iter_service_instances(iter, ent) != 0) { 588 switch (scf_error()) { 589 case SCF_ERROR_DELETED: 590 case SCF_ERROR_CONNECTION_BROKEN: 591 return (scferror2errno(scf_error())); 592 593 case SCF_ERROR_NOT_SET: 594 case SCF_ERROR_NOT_BOUND: 595 case SCF_ERROR_HANDLE_MISMATCH: 596 default: 597 bad_error("scf_iter_service_instances", 598 scf_error()); 599 } 600 } 601 602 for (;;) { 603 r = scf_iter_next_instance(iter, inst); 604 if (r == 0) { 605 if (scf_service_get_pg(ent, name, pg) == 0) 606 return (0); 607 608 switch (scf_error()) { 609 case SCF_ERROR_DELETED: 610 case SCF_ERROR_NOT_FOUND: 611 case SCF_ERROR_INVALID_ARGUMENT: 612 case SCF_ERROR_CONNECTION_BROKEN: 613 return (scferror2errno(scf_error())); 614 615 case SCF_ERROR_NOT_BOUND: 616 case SCF_ERROR_HANDLE_MISMATCH: 617 case SCF_ERROR_NOT_SET: 618 default: 619 bad_error("scf_service_get_pg", 620 scf_error()); 621 } 622 } 623 if (r != 1) { 624 switch (scf_error()) { 625 case SCF_ERROR_DELETED: 626 case SCF_ERROR_CONNECTION_BROKEN: 627 return (scferror2errno(scf_error())); 628 629 case SCF_ERROR_INVALID_ARGUMENT: 630 case SCF_ERROR_NOT_SET: 631 case SCF_ERROR_NOT_BOUND: 632 case SCF_ERROR_HANDLE_MISMATCH: 633 default: 634 bad_error("scf_iter_next_instance", 635 scf_error()); 636 } 637 } 638 639 if (scf_instance_get_snapshot(inst, snap_running, 640 snap) == 0) 641 break; 642 643 switch (scf_error()) { 644 case SCF_ERROR_NOT_FOUND: 645 case SCF_ERROR_DELETED: 646 continue; 647 648 case SCF_ERROR_CONNECTION_BROKEN: 649 return (ECONNABORTED); 650 651 case SCF_ERROR_HANDLE_MISMATCH: 652 case SCF_ERROR_INVALID_ARGUMENT: 653 case SCF_ERROR_NOT_SET: 654 case SCF_ERROR_NOT_BOUND: 655 default: 656 bad_error("scf_instance_get_snapshot", 657 scf_error()); 658 } 659 } 660 } else { 661 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 662 switch (scf_error()) { 663 case SCF_ERROR_NOT_FOUND: 664 break; 665 666 case SCF_ERROR_DELETED: 667 case SCF_ERROR_CONNECTION_BROKEN: 668 return (scferror2errno(scf_error())); 669 670 case SCF_ERROR_NOT_BOUND: 671 case SCF_ERROR_HANDLE_MISMATCH: 672 case SCF_ERROR_INVALID_ARGUMENT: 673 case SCF_ERROR_NOT_SET: 674 default: 675 bad_error("scf_instance_get_snapshot", 676 scf_error()); 677 } 678 679 if (scf_instance_get_pg(ent, name, pg) == 0) 680 return (0); 681 682 switch (scf_error()) { 683 case SCF_ERROR_DELETED: 684 case SCF_ERROR_NOT_FOUND: 685 case SCF_ERROR_INVALID_ARGUMENT: 686 case SCF_ERROR_CONNECTION_BROKEN: 687 return (scferror2errno(scf_error())); 688 689 case SCF_ERROR_NOT_BOUND: 690 case SCF_ERROR_HANDLE_MISMATCH: 691 case SCF_ERROR_NOT_SET: 692 default: 693 bad_error("scf_instance_get_pg", scf_error()); 694 } 695 } 696 } 697 698 r = get_snaplevel(snap, issvc, snpl); 699 switch (r) { 700 case 0: 701 break; 702 703 case ECONNABORTED: 704 case ECANCELED: 705 return (r); 706 707 case ENOENT: 708 return (EBADF); 709 710 default: 711 bad_error("get_snaplevel", r); 712 } 713 714 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 715 return (0); 716 717 switch (scf_error()) { 718 case SCF_ERROR_DELETED: 719 case SCF_ERROR_INVALID_ARGUMENT: 720 case SCF_ERROR_CONNECTION_BROKEN: 721 case SCF_ERROR_NOT_FOUND: 722 return (scferror2errno(scf_error())); 723 724 case SCF_ERROR_NOT_BOUND: 725 case SCF_ERROR_HANDLE_MISMATCH: 726 case SCF_ERROR_NOT_SET: 727 default: 728 bad_error("scf_snaplevel_get_pg", scf_error()); 729 /* NOTREACHED */ 730 } 731 } 732 733 /* 734 * To be registered with atexit(). 735 */ 736 static void 737 remove_tempfile(void) 738 { 739 int ret; 740 741 if (tempfile != NULL) { 742 if (fclose(tempfile) == EOF) 743 (void) warn(gettext("Could not close temporary file")); 744 tempfile = NULL; 745 } 746 747 if (tempfilename[0] != '\0') { 748 do { 749 ret = remove(tempfilename); 750 } while (ret == -1 && errno == EINTR); 751 if (ret == -1) 752 warn(gettext("Could not remove temporary file")); 753 tempfilename[0] = '\0'; 754 } 755 } 756 757 /* 758 * Launch private svc.configd(1M) for manipulating alternate repositories. 759 */ 760 static void 761 start_private_repository(engine_state_t *est) 762 { 763 int fd, stat; 764 struct door_info info; 765 pid_t pid; 766 767 /* 768 * 1. Create a temporary file for the door. 769 */ 770 if (est->sc_repo_doorname != NULL) 771 free((void *)est->sc_repo_doorname); 772 773 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 774 if (est->sc_repo_doorname == NULL) 775 uu_die(gettext("Could not acquire temporary filename")); 776 777 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 778 if (fd < 0) 779 uu_die(gettext("Could not create temporary file for " 780 "repository server")); 781 782 (void) close(fd); 783 784 /* 785 * 2. Launch a configd with that door, using the specified 786 * repository. 787 */ 788 if ((est->sc_repo_pid = fork()) == 0) { 789 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 790 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 791 NULL); 792 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 793 } else if (est->sc_repo_pid == -1) 794 uu_die(gettext("Attempt to fork failed")); 795 796 do { 797 pid = waitpid(est->sc_repo_pid, &stat, 0); 798 } while (pid == -1 && errno == EINTR); 799 800 if (pid == -1) 801 uu_die(gettext("Could not waitpid() for repository server")); 802 803 if (!WIFEXITED(stat)) { 804 uu_die(gettext("Repository server failed (status %d).\n"), 805 stat); 806 } else if (WEXITSTATUS(stat) != 0) { 807 uu_die(gettext("Repository server failed (exit %d).\n"), 808 WEXITSTATUS(stat)); 809 } 810 811 /* 812 * See if it was successful by checking if the door is a door. 813 */ 814 815 fd = open(est->sc_repo_doorname, O_RDWR); 816 if (fd < 0) 817 uu_die(gettext("Could not open door \"%s\""), 818 est->sc_repo_doorname); 819 820 if (door_info(fd, &info) < 0) 821 uu_die(gettext("Unexpected door_info() error")); 822 823 if (close(fd) == -1) 824 warn(gettext("Could not close repository door"), 825 strerror(errno)); 826 827 est->sc_repo_pid = info.di_target; 828 } 829 830 void 831 lscf_cleanup(void) 832 { 833 /* 834 * In the case where we've launched a private svc.configd(1M) 835 * instance, we must terminate our child and remove the temporary 836 * rendezvous point. 837 */ 838 if (est->sc_repo_pid > 0) { 839 (void) kill(est->sc_repo_pid, SIGTERM); 840 (void) waitpid(est->sc_repo_pid, NULL, 0); 841 (void) unlink(est->sc_repo_doorname); 842 843 est->sc_repo_pid = 0; 844 } 845 } 846 847 void 848 unselect_cursnap(void) 849 { 850 void *cookie; 851 852 cur_level = NULL; 853 854 cookie = NULL; 855 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 856 scf_snaplevel_destroy(cur_elt->sl); 857 free(cur_elt); 858 } 859 860 scf_snapshot_destroy(cur_snap); 861 cur_snap = NULL; 862 } 863 864 void 865 lscf_prep_hndl(void) 866 { 867 if (g_hndl != NULL) 868 return; 869 870 g_hndl = scf_handle_create(SCF_VERSION); 871 if (g_hndl == NULL) 872 scfdie(); 873 874 if (est->sc_repo_filename != NULL) 875 start_private_repository(est); 876 877 if (est->sc_repo_doorname != NULL) { 878 scf_value_t *repo_value; 879 int ret; 880 881 repo_value = scf_value_create(g_hndl); 882 if (repo_value == NULL) 883 scfdie(); 884 885 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 886 assert(ret == SCF_SUCCESS); 887 888 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 889 SCF_SUCCESS) 890 scfdie(); 891 892 scf_value_destroy(repo_value); 893 } 894 895 if (scf_handle_bind(g_hndl) != 0) 896 uu_die(gettext("Could not connect to repository server: %s.\n"), 897 scf_strerror(scf_error())); 898 899 cur_scope = scf_scope_create(g_hndl); 900 if (cur_scope == NULL) 901 scfdie(); 902 903 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 904 scfdie(); 905 } 906 907 static void 908 repository_teardown(void) 909 { 910 if (g_hndl != NULL) { 911 if (cur_snap != NULL) 912 unselect_cursnap(); 913 scf_instance_destroy(cur_inst); 914 scf_service_destroy(cur_svc); 915 scf_scope_destroy(cur_scope); 916 scf_handle_destroy(g_hndl); 917 cur_inst = NULL; 918 cur_svc = NULL; 919 cur_scope = NULL; 920 g_hndl = NULL; 921 lscf_cleanup(); 922 } 923 } 924 925 void 926 lscf_set_repository(const char *repfile, int force) 927 { 928 repository_teardown(); 929 930 if (est->sc_repo_filename != NULL) { 931 free((void *)est->sc_repo_filename); 932 est->sc_repo_filename = NULL; 933 } 934 935 if ((force == 0) && (access(repfile, R_OK) != 0)) { 936 /* 937 * Repository file does not exist 938 * or has no read permission. 939 */ 940 warn(gettext("Cannot access \"%s\": %s\n"), 941 repfile, strerror(errno)); 942 } else { 943 est->sc_repo_filename = safe_strdup(repfile); 944 } 945 946 lscf_prep_hndl(); 947 } 948 949 void 950 lscf_init() 951 { 952 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 953 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 954 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 955 0 || 956 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 957 scfdie(); 958 959 max_scf_len = max_scf_fmri_len; 960 if (max_scf_name_len > max_scf_len) 961 max_scf_len = max_scf_name_len; 962 if (max_scf_pg_type_len > max_scf_len) 963 max_scf_len = max_scf_pg_type_len; 964 /* 965 * When a value of type opaque is represented as a string, the 966 * string contains 2 characters for every byte of data. That is 967 * because the string contains the hex representation of the opaque 968 * value. 969 */ 970 if (2 * max_scf_value_len > max_scf_len) 971 max_scf_len = 2 * max_scf_value_len; 972 973 if (atexit(remove_tempfile) != 0) 974 uu_die(gettext("Could not register atexit() function")); 975 976 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 977 emsg_permission_denied = gettext("Permission denied.\n"); 978 emsg_create_xml = gettext("Could not create XML node.\n"); 979 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 980 emsg_invalid_for_snapshot = 981 gettext("Invalid operation on a snapshot.\n"); 982 emsg_read_only = gettext("Backend read-only.\n"); 983 emsg_deleted = gettext("Current selection has been deleted.\n"); 984 emsg_invalid_pg_name = 985 gettext("Invalid property group name \"%s\".\n"); 986 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 987 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 988 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 989 "with invalid name \"%s\".\n"); 990 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 991 "group with invalid name \"%s\" or type \"%s\".\n"); 992 emsg_pg_added = gettext("%s changed unexpectedly " 993 "(property group \"%s\" added).\n"); 994 emsg_pg_changed = gettext("%s changed unexpectedly " 995 "(property group \"%s\" changed).\n"); 996 emsg_pg_deleted = gettext("%s changed unexpectedly " 997 "(property group \"%s\" or an ancestor was deleted).\n"); 998 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 999 "in %s (permission denied).\n"); 1000 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 1001 "in %s (permission denied).\n"); 1002 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 1003 "in %s (permission denied).\n"); 1004 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 1005 "(permission denied).\n"); 1006 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 1007 "new dependent \"%s\" because it already exists). Warning: The " 1008 "current dependent's target (%s) does not exist.\n"); 1009 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 1010 "dependent \"%s\" because it already exists). Warning: The " 1011 "current dependent's target (%s) does not have a dependency named " 1012 "\"%s\" as expected.\n"); 1013 1014 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 1015 offsetof(string_list_t, node), NULL, 0); 1016 snaplevel_pool = uu_list_pool_create("snaplevels", 1017 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 1018 NULL, 0); 1019 } 1020 1021 1022 static const char * 1023 prop_to_typestr(const scf_property_t *prop) 1024 { 1025 scf_type_t ty; 1026 1027 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 1028 scfdie(); 1029 1030 return (scf_type_to_string(ty)); 1031 } 1032 1033 static scf_type_t 1034 string_to_type(const char *type) 1035 { 1036 size_t len = strlen(type); 1037 char *buf; 1038 1039 if (len == 0 || type[len - 1] != ':') 1040 return (SCF_TYPE_INVALID); 1041 1042 buf = (char *)alloca(len + 1); 1043 (void) strlcpy(buf, type, len + 1); 1044 buf[len - 1] = 0; 1045 1046 return (scf_string_to_type(buf)); 1047 } 1048 1049 static scf_value_t * 1050 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 1051 { 1052 scf_value_t *v; 1053 char *dup, *nstr; 1054 size_t len; 1055 1056 v = scf_value_create(g_hndl); 1057 if (v == NULL) 1058 scfdie(); 1059 1060 len = strlen(str); 1061 if (require_quotes && 1062 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1063 semerr(gettext("Multiple string values or string values " 1064 "with spaces must be quoted with '\"'.\n")); 1065 scf_value_destroy(v); 1066 return (NULL); 1067 } 1068 1069 nstr = dup = safe_strdup(str); 1070 if (dup[0] == '\"') { 1071 /* 1072 * Strip out the first and the last quote. 1073 */ 1074 dup[len - 1] = '\0'; 1075 nstr = dup + 1; 1076 } 1077 1078 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1079 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1080 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1081 scf_type_to_string(ty), nstr); 1082 scf_value_destroy(v); 1083 v = NULL; 1084 } 1085 free(dup); 1086 return (v); 1087 } 1088 1089 /* 1090 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1091 * Optionally append a comment prefix ('#') to newlines ('\n'). 1092 */ 1093 static int 1094 quote_and_print(const char *str, FILE *strm, int commentnl) 1095 { 1096 const char *cp; 1097 1098 for (cp = str; *cp != '\0'; ++cp) { 1099 if (*cp == '"' || *cp == '\\') 1100 (void) putc('\\', strm); 1101 1102 (void) putc(*cp, strm); 1103 1104 if (commentnl && *cp == '\n') { 1105 (void) putc('#', strm); 1106 } 1107 } 1108 1109 return (ferror(strm)); 1110 } 1111 1112 /* 1113 * These wrappers around lowlevel functions provide consistent error checking 1114 * and warnings. 1115 */ 1116 static int 1117 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1118 { 1119 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1120 return (0); 1121 1122 if (scf_error() != SCF_ERROR_NOT_FOUND) 1123 scfdie(); 1124 1125 if (g_verbose) { 1126 ssize_t len; 1127 char *fmri; 1128 1129 len = scf_pg_to_fmri(pg, NULL, 0); 1130 if (len < 0) 1131 scfdie(); 1132 1133 fmri = safe_malloc(len + 1); 1134 1135 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1136 scfdie(); 1137 1138 warn(gettext("Expected property %s of property group %s is " 1139 "missing.\n"), propname, fmri); 1140 1141 free(fmri); 1142 } 1143 1144 return (-1); 1145 } 1146 1147 static int 1148 prop_check_type(scf_property_t *prop, scf_type_t ty) 1149 { 1150 scf_type_t pty; 1151 1152 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1153 scfdie(); 1154 1155 if (ty == pty) 1156 return (0); 1157 1158 if (g_verbose) { 1159 ssize_t len; 1160 char *fmri; 1161 const char *tystr; 1162 1163 len = scf_property_to_fmri(prop, NULL, 0); 1164 if (len < 0) 1165 scfdie(); 1166 1167 fmri = safe_malloc(len + 1); 1168 1169 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1170 scfdie(); 1171 1172 tystr = scf_type_to_string(ty); 1173 if (tystr == NULL) 1174 tystr = "?"; 1175 1176 warn(gettext("Property %s is not of expected type %s.\n"), 1177 fmri, tystr); 1178 1179 free(fmri); 1180 } 1181 1182 return (-1); 1183 } 1184 1185 static int 1186 prop_get_val(scf_property_t *prop, scf_value_t *val) 1187 { 1188 scf_error_t err; 1189 1190 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1191 return (0); 1192 1193 err = scf_error(); 1194 1195 if (err != SCF_ERROR_NOT_FOUND && 1196 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1197 err != SCF_ERROR_PERMISSION_DENIED) 1198 scfdie(); 1199 1200 if (g_verbose) { 1201 ssize_t len; 1202 char *fmri, *emsg; 1203 1204 len = scf_property_to_fmri(prop, NULL, 0); 1205 if (len < 0) 1206 scfdie(); 1207 1208 fmri = safe_malloc(len + 1); 1209 1210 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1211 scfdie(); 1212 1213 if (err == SCF_ERROR_NOT_FOUND) 1214 emsg = gettext("Property %s has no values; expected " 1215 "one.\n"); 1216 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1217 emsg = gettext("Property %s has multiple values; " 1218 "expected one.\n"); 1219 else 1220 emsg = gettext("No permission to read property %s.\n"); 1221 1222 warn(emsg, fmri); 1223 1224 free(fmri); 1225 } 1226 1227 return (-1); 1228 } 1229 1230 1231 static boolean_t 1232 snaplevel_is_instance(const scf_snaplevel_t *level) 1233 { 1234 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1235 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1236 scfdie(); 1237 return (0); 1238 } else { 1239 return (1); 1240 } 1241 } 1242 1243 /* 1244 * Decode FMRI into a service or instance, and put the result in *ep. If 1245 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1246 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1247 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1248 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1249 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1250 * whether *ep is a service. 1251 */ 1252 static scf_error_t 1253 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1254 { 1255 char *fmri_copy; 1256 const char *sstr, *istr, *pgstr; 1257 scf_service_t *svc; 1258 scf_instance_t *inst; 1259 1260 fmri_copy = strdup(fmri); 1261 if (fmri_copy == NULL) 1262 return (SCF_ERROR_NO_MEMORY); 1263 1264 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1265 SCF_SUCCESS) { 1266 free(fmri_copy); 1267 return (SCF_ERROR_INVALID_ARGUMENT); 1268 } 1269 1270 free(fmri_copy); 1271 1272 if (sstr == NULL || pgstr != NULL) 1273 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1274 1275 if (istr == NULL) { 1276 svc = scf_service_create(h); 1277 if (svc == NULL) 1278 return (SCF_ERROR_NO_MEMORY); 1279 1280 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1281 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1282 if (scf_error() != SCF_ERROR_NOT_FOUND) 1283 scfdie(); 1284 1285 return (SCF_ERROR_NOT_FOUND); 1286 } 1287 1288 *ep = svc; 1289 *isservice = 1; 1290 } else { 1291 inst = scf_instance_create(h); 1292 if (inst == NULL) 1293 return (SCF_ERROR_NO_MEMORY); 1294 1295 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1296 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1297 if (scf_error() != SCF_ERROR_NOT_FOUND) 1298 scfdie(); 1299 1300 return (SCF_ERROR_NOT_FOUND); 1301 } 1302 1303 *ep = inst; 1304 *isservice = 0; 1305 } 1306 1307 return (SCF_ERROR_NONE); 1308 } 1309 1310 /* 1311 * Create the entity named by fmri. Place a pointer to its libscf handle in 1312 * *ep, and set or clear *isservicep if it is a service or an instance. 1313 * Returns 1314 * SCF_ERROR_NONE - success 1315 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1316 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1317 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1318 * SCF_ERROR_NOT_FOUND - no such scope 1319 * SCF_ERROR_PERMISSION_DENIED 1320 * SCF_ERROR_BACKEND_READONLY 1321 * SCF_ERROR_BACKEND_ACCESS 1322 */ 1323 static scf_error_t 1324 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1325 { 1326 char *fmri_copy; 1327 const char *scstr, *sstr, *istr, *pgstr; 1328 scf_scope_t *scope = NULL; 1329 scf_service_t *svc = NULL; 1330 scf_instance_t *inst = NULL; 1331 scf_error_t scfe; 1332 1333 fmri_copy = safe_strdup(fmri); 1334 1335 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1336 0) { 1337 free(fmri_copy); 1338 return (SCF_ERROR_INVALID_ARGUMENT); 1339 } 1340 1341 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1342 free(fmri_copy); 1343 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1344 } 1345 1346 *ep = NULL; 1347 1348 if ((scope = scf_scope_create(h)) == NULL || 1349 (svc = scf_service_create(h)) == NULL || 1350 (inst = scf_instance_create(h)) == NULL) { 1351 scfe = SCF_ERROR_NO_MEMORY; 1352 goto out; 1353 } 1354 1355 get_scope: 1356 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1357 switch (scf_error()) { 1358 case SCF_ERROR_CONNECTION_BROKEN: 1359 scfdie(); 1360 /* NOTREACHED */ 1361 1362 case SCF_ERROR_NOT_FOUND: 1363 scfe = SCF_ERROR_NOT_FOUND; 1364 goto out; 1365 1366 case SCF_ERROR_HANDLE_MISMATCH: 1367 case SCF_ERROR_NOT_BOUND: 1368 case SCF_ERROR_INVALID_ARGUMENT: 1369 default: 1370 bad_error("scf_handle_get_scope", scf_error()); 1371 } 1372 } 1373 1374 get_svc: 1375 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1376 switch (scf_error()) { 1377 case SCF_ERROR_CONNECTION_BROKEN: 1378 scfdie(); 1379 /* NOTREACHED */ 1380 1381 case SCF_ERROR_DELETED: 1382 goto get_scope; 1383 1384 case SCF_ERROR_NOT_FOUND: 1385 break; 1386 1387 case SCF_ERROR_HANDLE_MISMATCH: 1388 case SCF_ERROR_INVALID_ARGUMENT: 1389 case SCF_ERROR_NOT_BOUND: 1390 case SCF_ERROR_NOT_SET: 1391 default: 1392 bad_error("scf_scope_get_service", scf_error()); 1393 } 1394 1395 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1396 switch (scf_error()) { 1397 case SCF_ERROR_CONNECTION_BROKEN: 1398 scfdie(); 1399 /* NOTREACHED */ 1400 1401 case SCF_ERROR_DELETED: 1402 goto get_scope; 1403 1404 case SCF_ERROR_PERMISSION_DENIED: 1405 case SCF_ERROR_BACKEND_READONLY: 1406 case SCF_ERROR_BACKEND_ACCESS: 1407 scfe = scf_error(); 1408 goto out; 1409 1410 case SCF_ERROR_HANDLE_MISMATCH: 1411 case SCF_ERROR_INVALID_ARGUMENT: 1412 case SCF_ERROR_NOT_BOUND: 1413 case SCF_ERROR_NOT_SET: 1414 default: 1415 bad_error("scf_scope_get_service", scf_error()); 1416 } 1417 } 1418 } 1419 1420 if (istr == NULL) { 1421 scfe = SCF_ERROR_NONE; 1422 *ep = svc; 1423 *isservicep = 1; 1424 goto out; 1425 } 1426 1427 get_inst: 1428 if (scf_service_get_instance(svc, istr, inst) != 0) { 1429 switch (scf_error()) { 1430 case SCF_ERROR_CONNECTION_BROKEN: 1431 scfdie(); 1432 /* NOTREACHED */ 1433 1434 case SCF_ERROR_DELETED: 1435 goto get_svc; 1436 1437 case SCF_ERROR_NOT_FOUND: 1438 break; 1439 1440 case SCF_ERROR_HANDLE_MISMATCH: 1441 case SCF_ERROR_INVALID_ARGUMENT: 1442 case SCF_ERROR_NOT_BOUND: 1443 case SCF_ERROR_NOT_SET: 1444 default: 1445 bad_error("scf_service_get_instance", scf_error()); 1446 } 1447 1448 if (scf_service_add_instance(svc, istr, inst) != 0) { 1449 switch (scf_error()) { 1450 case SCF_ERROR_CONNECTION_BROKEN: 1451 scfdie(); 1452 /* NOTREACHED */ 1453 1454 case SCF_ERROR_DELETED: 1455 goto get_svc; 1456 1457 case SCF_ERROR_PERMISSION_DENIED: 1458 case SCF_ERROR_BACKEND_READONLY: 1459 case SCF_ERROR_BACKEND_ACCESS: 1460 scfe = scf_error(); 1461 goto out; 1462 1463 case SCF_ERROR_HANDLE_MISMATCH: 1464 case SCF_ERROR_INVALID_ARGUMENT: 1465 case SCF_ERROR_NOT_BOUND: 1466 case SCF_ERROR_NOT_SET: 1467 default: 1468 bad_error("scf_service_add_instance", 1469 scf_error()); 1470 } 1471 } 1472 } 1473 1474 scfe = SCF_ERROR_NONE; 1475 *ep = inst; 1476 *isservicep = 0; 1477 1478 out: 1479 if (*ep != inst) 1480 scf_instance_destroy(inst); 1481 if (*ep != svc) 1482 scf_service_destroy(svc); 1483 scf_scope_destroy(scope); 1484 free(fmri_copy); 1485 return (scfe); 1486 } 1487 1488 /* 1489 * Create or update a snapshot of inst. snap is a required scratch object. 1490 * 1491 * Returns 1492 * 0 - success 1493 * ECONNABORTED - repository connection broken 1494 * EPERM - permission denied 1495 * ENOSPC - configd is out of resources 1496 * ECANCELED - inst was deleted 1497 * -1 - unknown libscf error (message printed) 1498 */ 1499 static int 1500 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1501 { 1502 again: 1503 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1504 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1505 switch (scf_error()) { 1506 case SCF_ERROR_CONNECTION_BROKEN: 1507 case SCF_ERROR_PERMISSION_DENIED: 1508 case SCF_ERROR_NO_RESOURCES: 1509 return (scferror2errno(scf_error())); 1510 1511 case SCF_ERROR_NOT_SET: 1512 case SCF_ERROR_INVALID_ARGUMENT: 1513 default: 1514 bad_error("_scf_snapshot_take_attach", 1515 scf_error()); 1516 } 1517 } 1518 } else { 1519 switch (scf_error()) { 1520 case SCF_ERROR_NOT_FOUND: 1521 break; 1522 1523 case SCF_ERROR_DELETED: 1524 case SCF_ERROR_CONNECTION_BROKEN: 1525 return (scferror2errno(scf_error())); 1526 1527 case SCF_ERROR_HANDLE_MISMATCH: 1528 case SCF_ERROR_NOT_BOUND: 1529 case SCF_ERROR_INVALID_ARGUMENT: 1530 case SCF_ERROR_NOT_SET: 1531 default: 1532 bad_error("scf_instance_get_snapshot", scf_error()); 1533 } 1534 1535 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1536 switch (scf_error()) { 1537 case SCF_ERROR_EXISTS: 1538 goto again; 1539 1540 case SCF_ERROR_CONNECTION_BROKEN: 1541 case SCF_ERROR_NO_RESOURCES: 1542 case SCF_ERROR_PERMISSION_DENIED: 1543 return (scferror2errno(scf_error())); 1544 1545 default: 1546 scfwarn(); 1547 return (-1); 1548 1549 case SCF_ERROR_NOT_SET: 1550 case SCF_ERROR_INTERNAL: 1551 case SCF_ERROR_INVALID_ARGUMENT: 1552 case SCF_ERROR_HANDLE_MISMATCH: 1553 bad_error("_scf_snapshot_take_new", 1554 scf_error()); 1555 } 1556 } 1557 } 1558 1559 return (0); 1560 } 1561 1562 static int 1563 refresh_running_snapshot(void *entity) 1564 { 1565 scf_snapshot_t *snap; 1566 int r; 1567 1568 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1569 scfdie(); 1570 r = take_snap(entity, snap_running, snap); 1571 scf_snapshot_destroy(snap); 1572 1573 return (r); 1574 } 1575 1576 /* 1577 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1578 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1579 * instances. fmri is used for messages. inst, iter, and name_buf are used 1580 * for scratch space. Returns 1581 * 0 - success 1582 * ECONNABORTED - repository connection broken 1583 * ECANCELED - entity was deleted 1584 * EACCES - backend denied access 1585 * EPERM - permission denied 1586 * ENOSPC - repository server out of resources 1587 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1588 */ 1589 static int 1590 refresh_entity(int isservice, void *entity, const char *fmri, 1591 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1592 { 1593 scf_error_t scfe; 1594 int r; 1595 1596 if (!isservice) { 1597 /* 1598 * Let restarter handles refreshing and making new running 1599 * snapshot only if operating on a live repository and not 1600 * running in early import. 1601 */ 1602 if (est->sc_repo_filename == NULL && 1603 est->sc_repo_doorname == NULL && 1604 est->sc_in_emi == 0) { 1605 if (_smf_refresh_instance_i(entity) == 0) { 1606 if (g_verbose) 1607 warn(gettext("Refreshed %s.\n"), fmri); 1608 return (0); 1609 } 1610 1611 switch (scf_error()) { 1612 case SCF_ERROR_BACKEND_ACCESS: 1613 return (EACCES); 1614 1615 case SCF_ERROR_PERMISSION_DENIED: 1616 return (EPERM); 1617 1618 default: 1619 return (-1); 1620 } 1621 } else { 1622 r = refresh_running_snapshot(entity); 1623 switch (r) { 1624 case 0: 1625 break; 1626 1627 case ECONNABORTED: 1628 case ECANCELED: 1629 case EPERM: 1630 case ENOSPC: 1631 break; 1632 1633 default: 1634 bad_error("refresh_running_snapshot", 1635 scf_error()); 1636 } 1637 1638 return (r); 1639 } 1640 } 1641 1642 if (scf_iter_service_instances(iter, entity) != 0) { 1643 switch (scf_error()) { 1644 case SCF_ERROR_CONNECTION_BROKEN: 1645 return (ECONNABORTED); 1646 1647 case SCF_ERROR_DELETED: 1648 return (ECANCELED); 1649 1650 case SCF_ERROR_HANDLE_MISMATCH: 1651 case SCF_ERROR_NOT_BOUND: 1652 case SCF_ERROR_NOT_SET: 1653 default: 1654 bad_error("scf_iter_service_instances", scf_error()); 1655 } 1656 } 1657 1658 for (;;) { 1659 r = scf_iter_next_instance(iter, inst); 1660 if (r == 0) 1661 break; 1662 if (r != 1) { 1663 switch (scf_error()) { 1664 case SCF_ERROR_CONNECTION_BROKEN: 1665 return (ECONNABORTED); 1666 1667 case SCF_ERROR_DELETED: 1668 return (ECANCELED); 1669 1670 case SCF_ERROR_HANDLE_MISMATCH: 1671 case SCF_ERROR_NOT_BOUND: 1672 case SCF_ERROR_NOT_SET: 1673 case SCF_ERROR_INVALID_ARGUMENT: 1674 default: 1675 bad_error("scf_iter_next_instance", 1676 scf_error()); 1677 } 1678 } 1679 1680 /* 1681 * Similarly, just take a new running snapshot if operating on 1682 * a non-live repository or running during early import. 1683 */ 1684 if (est->sc_repo_filename != NULL || 1685 est->sc_repo_doorname != NULL || 1686 est->sc_in_emi == 1) { 1687 r = refresh_running_snapshot(inst); 1688 switch (r) { 1689 case 0: 1690 continue; 1691 1692 case ECONNABORTED: 1693 case ECANCELED: 1694 case EPERM: 1695 case ENOSPC: 1696 break; 1697 default: 1698 bad_error("refresh_running_snapshot", 1699 scf_error()); 1700 } 1701 1702 return (r); 1703 1704 } 1705 1706 if (_smf_refresh_instance_i(inst) == 0) { 1707 if (g_verbose) { 1708 if (scf_instance_get_name(inst, name_buf, 1709 max_scf_name_len + 1) < 0) 1710 (void) strcpy(name_buf, "?"); 1711 1712 warn(gettext("Refreshed %s:%s.\n"), 1713 fmri, name_buf); 1714 } 1715 } else { 1716 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1717 g_verbose) { 1718 scfe = scf_error(); 1719 1720 if (scf_instance_to_fmri(inst, name_buf, 1721 max_scf_name_len + 1) < 0) 1722 (void) strcpy(name_buf, "?"); 1723 1724 warn(gettext( 1725 "Refresh of %s:%s failed: %s.\n"), fmri, 1726 name_buf, scf_strerror(scfe)); 1727 } 1728 } 1729 } 1730 1731 return (0); 1732 } 1733 1734 static void 1735 private_refresh(void) 1736 { 1737 scf_instance_t *pinst = NULL; 1738 scf_iter_t *piter = NULL; 1739 ssize_t fmrilen; 1740 size_t bufsz; 1741 char *fmribuf; 1742 void *ent; 1743 int issvc; 1744 int r; 1745 1746 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1747 return; 1748 1749 assert(cur_svc != NULL); 1750 1751 bufsz = max_scf_fmri_len + 1; 1752 fmribuf = safe_malloc(bufsz); 1753 if (cur_inst) { 1754 issvc = 0; 1755 ent = cur_inst; 1756 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1757 } else { 1758 issvc = 1; 1759 ent = cur_svc; 1760 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1761 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1762 scfdie(); 1763 1764 if ((piter = scf_iter_create(g_hndl)) == NULL) 1765 scfdie(); 1766 } 1767 if (fmrilen < 0) { 1768 free(fmribuf); 1769 if (scf_error() != SCF_ERROR_DELETED) 1770 scfdie(); 1771 1772 warn(emsg_deleted); 1773 return; 1774 } 1775 assert(fmrilen < bufsz); 1776 1777 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1778 switch (r) { 1779 case 0: 1780 break; 1781 1782 case ECONNABORTED: 1783 warn(gettext("Could not refresh %s " 1784 "(repository connection broken).\n"), fmribuf); 1785 break; 1786 1787 case ECANCELED: 1788 warn(emsg_deleted); 1789 break; 1790 1791 case EPERM: 1792 warn(gettext("Could not refresh %s " 1793 "(permission denied).\n"), fmribuf); 1794 break; 1795 1796 case ENOSPC: 1797 warn(gettext("Could not refresh %s " 1798 "(repository server out of resources).\n"), 1799 fmribuf); 1800 break; 1801 1802 case EACCES: 1803 default: 1804 bad_error("refresh_entity", scf_error()); 1805 } 1806 1807 if (issvc) { 1808 scf_instance_destroy(pinst); 1809 scf_iter_destroy(piter); 1810 } 1811 1812 free(fmribuf); 1813 } 1814 1815 1816 static int 1817 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1818 { 1819 cbp->sc_err = scferror2errno(err); 1820 return (UU_WALK_ERROR); 1821 } 1822 1823 static int 1824 stash_scferror(scf_callback_t *cbp) 1825 { 1826 return (stash_scferror_err(cbp, scf_error())); 1827 } 1828 1829 static int select_inst(const char *); 1830 static int select_svc(const char *); 1831 1832 /* 1833 * Take a property that does not have a type and check to see if a type 1834 * exists or can be gleened from the current data. Set the type. 1835 * 1836 * Check the current level (instance) and then check the higher level 1837 * (service). This could be the case for adding a new property to 1838 * the instance that's going to "override" a service level property. 1839 * 1840 * For a property : 1841 * 1. Take the type from an existing property 1842 * 2. Take the type from a template entry 1843 * 1844 * If the type can not be found, then leave the type as is, and let the import 1845 * report the problem of the missing type. 1846 */ 1847 static int 1848 find_current_prop_type(void *p, void *g) 1849 { 1850 property_t *prop = p; 1851 scf_callback_t *lcb = g; 1852 pgroup_t *pg = NULL; 1853 1854 const char *fmri = NULL; 1855 char *lfmri = NULL; 1856 char *cur_selection = NULL; 1857 1858 scf_propertygroup_t *sc_pg = NULL; 1859 scf_property_t *sc_prop = NULL; 1860 scf_pg_tmpl_t *t_pg = NULL; 1861 scf_prop_tmpl_t *t_prop = NULL; 1862 scf_type_t prop_type; 1863 1864 value_t *vp; 1865 int issvc = lcb->sc_service; 1866 int r = UU_WALK_ERROR; 1867 1868 if (prop->sc_value_type != SCF_TYPE_INVALID) 1869 return (UU_WALK_NEXT); 1870 1871 t_prop = scf_tmpl_prop_create(g_hndl); 1872 sc_prop = scf_property_create(g_hndl); 1873 if (sc_prop == NULL || t_prop == NULL) { 1874 warn(gettext("Unable to create the property to attempt and " 1875 "find a missing type.\n")); 1876 1877 scf_property_destroy(sc_prop); 1878 scf_tmpl_prop_destroy(t_prop); 1879 1880 return (UU_WALK_ERROR); 1881 } 1882 1883 if (lcb->sc_flags == 1) { 1884 pg = lcb->sc_parent; 1885 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT); 1886 fmri = pg->sc_parent->sc_fmri; 1887 retry_pg: 1888 if (cur_svc && cur_selection == NULL) { 1889 cur_selection = safe_malloc(max_scf_fmri_len + 1); 1890 lscf_get_selection_str(cur_selection, 1891 max_scf_fmri_len + 1); 1892 1893 if (strcmp(cur_selection, fmri) != 0) { 1894 lscf_select(fmri); 1895 } else { 1896 free(cur_selection); 1897 cur_selection = NULL; 1898 } 1899 } else { 1900 lscf_select(fmri); 1901 } 1902 1903 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) { 1904 warn(gettext("Unable to create property group to " 1905 "find a missing property type.\n")); 1906 1907 goto out; 1908 } 1909 1910 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) { 1911 /* 1912 * If this is the sc_pg from the parent 1913 * let the caller clean up the sc_pg, 1914 * and just throw it away in this case. 1915 */ 1916 if (sc_pg != lcb->sc_parent) 1917 scf_pg_destroy(sc_pg); 1918 1919 sc_pg = NULL; 1920 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1921 warn(gettext("Unable to create template " 1922 "property group to find a property " 1923 "type.\n")); 1924 1925 goto out; 1926 } 1927 1928 if (scf_tmpl_get_by_pg_name(fmri, NULL, 1929 pg->sc_pgroup_name, NULL, t_pg, 1930 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) { 1931 /* 1932 * if instance get service and jump back 1933 */ 1934 scf_tmpl_pg_destroy(t_pg); 1935 t_pg = NULL; 1936 if (issvc == 0) { 1937 entity_t *e = pg->sc_parent->sc_parent; 1938 1939 fmri = e->sc_fmri; 1940 issvc = 1; 1941 goto retry_pg; 1942 } else { 1943 goto out; 1944 } 1945 } 1946 } 1947 } else { 1948 sc_pg = lcb->sc_parent; 1949 } 1950 1951 /* 1952 * Attempt to get the type from an existing property. If the property 1953 * cannot be found then attempt to get the type from a template entry 1954 * for the property. 1955 * 1956 * Finally, if at the instance level look at the service level. 1957 */ 1958 if (sc_pg != NULL && 1959 pg_get_prop(sc_pg, prop->sc_property_name, 1960 sc_prop) == SCF_SUCCESS && 1961 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) { 1962 prop->sc_value_type = prop_type; 1963 1964 /* 1965 * Found a type, update the value types and validate 1966 * the actual value against this type. 1967 */ 1968 for (vp = uu_list_first(prop->sc_property_values); 1969 vp != NULL; 1970 vp = uu_list_next(prop->sc_property_values, vp)) { 1971 vp->sc_type = prop->sc_value_type; 1972 lxml_store_value(vp, 0, NULL); 1973 } 1974 1975 r = UU_WALK_NEXT; 1976 goto out; 1977 } 1978 1979 /* 1980 * If we get here with t_pg set to NULL then we had to have 1981 * gotten an sc_pg but that sc_pg did not have the property 1982 * we are looking for. So if the t_pg is not null look up 1983 * the template entry for the property. 1984 * 1985 * If the t_pg is null then need to attempt to get a matching 1986 * template entry for the sc_pg, and see if there is a property 1987 * entry for that template entry. 1988 */ 1989 do_tmpl : 1990 if (t_pg != NULL && 1991 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name, 1992 t_prop, 0) == SCF_SUCCESS) { 1993 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) { 1994 prop->sc_value_type = prop_type; 1995 1996 /* 1997 * Found a type, update the value types and validate 1998 * the actual value against this type. 1999 */ 2000 for (vp = uu_list_first(prop->sc_property_values); 2001 vp != NULL; 2002 vp = uu_list_next(prop->sc_property_values, vp)) { 2003 vp->sc_type = prop->sc_value_type; 2004 lxml_store_value(vp, 0, NULL); 2005 } 2006 2007 r = UU_WALK_NEXT; 2008 goto out; 2009 } 2010 } else { 2011 if (t_pg == NULL && sc_pg) { 2012 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 2013 warn(gettext("Unable to create template " 2014 "property group to find a property " 2015 "type.\n")); 2016 2017 goto out; 2018 } 2019 2020 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) { 2021 scf_tmpl_pg_destroy(t_pg); 2022 t_pg = NULL; 2023 } else { 2024 goto do_tmpl; 2025 } 2026 } 2027 } 2028 2029 if (issvc == 0) { 2030 scf_instance_t *i; 2031 scf_service_t *s; 2032 2033 issvc = 1; 2034 if (lcb->sc_flags == 1) { 2035 entity_t *e = pg->sc_parent->sc_parent; 2036 2037 fmri = e->sc_fmri; 2038 goto retry_pg; 2039 } 2040 2041 /* 2042 * because lcb->sc_flags was not set then this means 2043 * the pg was not used and can be used here. 2044 */ 2045 if ((pg = internal_pgroup_new()) == NULL) { 2046 warn(gettext("Could not create internal property group " 2047 "to find a missing type.")); 2048 2049 goto out; 2050 } 2051 2052 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1); 2053 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name, 2054 max_scf_name_len + 1) < 0) 2055 goto out; 2056 2057 i = scf_instance_create(g_hndl); 2058 s = scf_service_create(g_hndl); 2059 if (i == NULL || s == NULL || 2060 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) { 2061 warn(gettext("Could not get a service for the instance " 2062 "to find a missing type.")); 2063 2064 goto out; 2065 } 2066 2067 /* 2068 * Check to see truly at the instance level. 2069 */ 2070 lfmri = safe_malloc(max_scf_fmri_len + 1); 2071 if (scf_instance_get_parent(i, s) == SCF_SUCCESS && 2072 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0) 2073 goto out; 2074 else 2075 fmri = (const char *)lfmri; 2076 2077 goto retry_pg; 2078 } 2079 2080 out : 2081 if (sc_pg != lcb->sc_parent) { 2082 scf_pg_destroy(sc_pg); 2083 } 2084 2085 /* 2086 * If this is true then the pg was allocated 2087 * here, and the name was set so need to free 2088 * the name and the pg. 2089 */ 2090 if (pg != NULL && pg != lcb->sc_parent) { 2091 free((char *)pg->sc_pgroup_name); 2092 internal_pgroup_free(pg); 2093 } 2094 2095 if (cur_selection) { 2096 lscf_select(cur_selection); 2097 free(cur_selection); 2098 } 2099 2100 scf_tmpl_pg_destroy(t_pg); 2101 scf_tmpl_prop_destroy(t_prop); 2102 scf_property_destroy(sc_prop); 2103 2104 if (r != UU_WALK_NEXT) 2105 warn(gettext("Could not find property type for \"%s\" " 2106 "from \"%s\"\n"), prop->sc_property_name, 2107 fmri != NULL ? fmri : lcb->sc_source_fmri); 2108 2109 free(lfmri); 2110 2111 return (r); 2112 } 2113 2114 /* 2115 * Take a property group that does not have a type and check to see if a type 2116 * exists or can be gleened from the current data. Set the type. 2117 * 2118 * Check the current level (instance) and then check the higher level 2119 * (service). This could be the case for adding a new property to 2120 * the instance that's going to "override" a service level property. 2121 * 2122 * For a property group 2123 * 1. Take the type from an existing property group 2124 * 2. Take the type from a template entry 2125 * 2126 * If the type can not be found, then leave the type as is, and let the import 2127 * report the problem of the missing type. 2128 */ 2129 static int 2130 find_current_pg_type(void *p, void *sori) 2131 { 2132 entity_t *si = sori; 2133 pgroup_t *pg = p; 2134 2135 const char *ofmri, *fmri; 2136 char *cur_selection = NULL; 2137 char *pg_type = NULL; 2138 2139 scf_propertygroup_t *sc_pg = NULL; 2140 scf_pg_tmpl_t *t_pg = NULL; 2141 2142 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2143 int r = UU_WALK_ERROR; 2144 2145 ofmri = fmri = si->sc_fmri; 2146 if (pg->sc_pgroup_type != NULL) { 2147 r = UU_WALK_NEXT; 2148 2149 goto out; 2150 } 2151 2152 sc_pg = scf_pg_create(g_hndl); 2153 if (sc_pg == NULL) { 2154 warn(gettext("Unable to create property group to attempt " 2155 "and find a missing type.\n")); 2156 2157 return (UU_WALK_ERROR); 2158 } 2159 2160 /* 2161 * Using get_pg() requires that the cur_svc/cur_inst be 2162 * via lscf_select. Need to preserve the current selection 2163 * if going to use lscf_select() to set up the cur_svc/cur_inst 2164 */ 2165 if (cur_svc) { 2166 cur_selection = safe_malloc(max_scf_fmri_len + 1); 2167 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1); 2168 } 2169 2170 /* 2171 * If the property group exists get the type, and set 2172 * the pgroup_t type of that type. 2173 * 2174 * If not the check for a template pg_pattern entry 2175 * and take the type from that. 2176 */ 2177 retry_svc: 2178 lscf_select(fmri); 2179 2180 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) { 2181 pg_type = safe_malloc(max_scf_pg_type_len + 1); 2182 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type, 2183 max_scf_pg_type_len + 1) != -1) { 2184 pg->sc_pgroup_type = pg_type; 2185 2186 r = UU_WALK_NEXT; 2187 goto out; 2188 } else { 2189 free(pg_type); 2190 } 2191 } else { 2192 if ((t_pg == NULL) && 2193 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) 2194 goto out; 2195 2196 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name, 2197 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS && 2198 scf_tmpl_pg_type(t_pg, &pg_type) != -1) { 2199 pg->sc_pgroup_type = pg_type; 2200 2201 r = UU_WALK_NEXT; 2202 goto out; 2203 } 2204 } 2205 2206 /* 2207 * If type is not found at the instance level then attempt to 2208 * find the type at the service level. 2209 */ 2210 if (!issvc) { 2211 si = si->sc_parent; 2212 fmri = si->sc_fmri; 2213 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2214 goto retry_svc; 2215 } 2216 2217 out : 2218 if (cur_selection) { 2219 lscf_select(cur_selection); 2220 free(cur_selection); 2221 } 2222 2223 /* 2224 * Now walk the properties of the property group to make sure that 2225 * all properties have the correct type and values are valid for 2226 * those types. 2227 */ 2228 if (r == UU_WALK_NEXT) { 2229 scf_callback_t cb; 2230 2231 cb.sc_service = issvc; 2232 cb.sc_source_fmri = ofmri; 2233 if (sc_pg != NULL) { 2234 cb.sc_parent = sc_pg; 2235 cb.sc_flags = 0; 2236 } else { 2237 cb.sc_parent = pg; 2238 cb.sc_flags = 1; 2239 } 2240 2241 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type, 2242 &cb, UU_DEFAULT) != 0) { 2243 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2244 bad_error("uu_list_walk", uu_error()); 2245 2246 r = UU_WALK_ERROR; 2247 } 2248 } else { 2249 warn(gettext("Could not find property group type for " 2250 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri); 2251 } 2252 2253 scf_tmpl_pg_destroy(t_pg); 2254 scf_pg_destroy(sc_pg); 2255 2256 return (r); 2257 } 2258 2259 /* 2260 * Import. These functions import a bundle into the repository. 2261 */ 2262 2263 /* 2264 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 2265 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 2266 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2267 * lcbdata->sc_err to 2268 * ENOMEM - out of memory 2269 * ECONNABORTED - repository connection broken 2270 * ECANCELED - sc_trans's property group was deleted 2271 * EINVAL - p's name is invalid (error printed) 2272 * - p has an invalid value (error printed) 2273 */ 2274 static int 2275 lscf_property_import(void *v, void *pvt) 2276 { 2277 property_t *p = v; 2278 scf_callback_t *lcbdata = pvt; 2279 value_t *vp; 2280 scf_transaction_t *trans = lcbdata->sc_trans; 2281 scf_transaction_entry_t *entr; 2282 scf_value_t *val; 2283 scf_type_t tp; 2284 2285 if ((lcbdata->sc_flags & SCI_NOENABLED || 2286 lcbdata->sc_flags & SCI_DELAYENABLE) && 2287 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 2288 lcbdata->sc_enable = p; 2289 return (UU_WALK_NEXT); 2290 } 2291 2292 entr = scf_entry_create(lcbdata->sc_handle); 2293 if (entr == NULL) { 2294 switch (scf_error()) { 2295 case SCF_ERROR_NO_MEMORY: 2296 return (stash_scferror(lcbdata)); 2297 2298 case SCF_ERROR_INVALID_ARGUMENT: 2299 default: 2300 bad_error("scf_entry_create", scf_error()); 2301 } 2302 } 2303 2304 tp = p->sc_value_type; 2305 2306 if (scf_transaction_property_new(trans, entr, 2307 p->sc_property_name, tp) != 0) { 2308 switch (scf_error()) { 2309 case SCF_ERROR_INVALID_ARGUMENT: 2310 semerr(emsg_invalid_prop_name, p->sc_property_name); 2311 scf_entry_destroy(entr); 2312 return (stash_scferror(lcbdata)); 2313 2314 case SCF_ERROR_EXISTS: 2315 break; 2316 2317 case SCF_ERROR_DELETED: 2318 case SCF_ERROR_CONNECTION_BROKEN: 2319 scf_entry_destroy(entr); 2320 return (stash_scferror(lcbdata)); 2321 2322 case SCF_ERROR_NOT_BOUND: 2323 case SCF_ERROR_HANDLE_MISMATCH: 2324 case SCF_ERROR_NOT_SET: 2325 default: 2326 bad_error("scf_transaction_property_new", scf_error()); 2327 } 2328 2329 if (scf_transaction_property_change_type(trans, entr, 2330 p->sc_property_name, tp) != 0) { 2331 switch (scf_error()) { 2332 case SCF_ERROR_DELETED: 2333 case SCF_ERROR_CONNECTION_BROKEN: 2334 scf_entry_destroy(entr); 2335 return (stash_scferror(lcbdata)); 2336 2337 case SCF_ERROR_INVALID_ARGUMENT: 2338 semerr(emsg_invalid_prop_name, 2339 p->sc_property_name); 2340 scf_entry_destroy(entr); 2341 return (stash_scferror(lcbdata)); 2342 2343 case SCF_ERROR_NOT_FOUND: 2344 case SCF_ERROR_NOT_SET: 2345 case SCF_ERROR_HANDLE_MISMATCH: 2346 case SCF_ERROR_NOT_BOUND: 2347 default: 2348 bad_error( 2349 "scf_transaction_property_change_type", 2350 scf_error()); 2351 } 2352 } 2353 } 2354 2355 for (vp = uu_list_first(p->sc_property_values); 2356 vp != NULL; 2357 vp = uu_list_next(p->sc_property_values, vp)) { 2358 val = scf_value_create(g_hndl); 2359 if (val == NULL) { 2360 switch (scf_error()) { 2361 case SCF_ERROR_NO_MEMORY: 2362 return (stash_scferror(lcbdata)); 2363 2364 case SCF_ERROR_INVALID_ARGUMENT: 2365 default: 2366 bad_error("scf_value_create", scf_error()); 2367 } 2368 } 2369 2370 switch (tp) { 2371 case SCF_TYPE_BOOLEAN: 2372 scf_value_set_boolean(val, vp->sc_u.sc_count); 2373 break; 2374 case SCF_TYPE_COUNT: 2375 scf_value_set_count(val, vp->sc_u.sc_count); 2376 break; 2377 case SCF_TYPE_INTEGER: 2378 scf_value_set_integer(val, vp->sc_u.sc_integer); 2379 break; 2380 default: 2381 assert(vp->sc_u.sc_string != NULL); 2382 if (scf_value_set_from_string(val, tp, 2383 vp->sc_u.sc_string) != 0) { 2384 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 2385 bad_error("scf_value_set_from_string", 2386 scf_error()); 2387 2388 warn(gettext("Value \"%s\" is not a valid " 2389 "%s.\n"), vp->sc_u.sc_string, 2390 scf_type_to_string(tp)); 2391 scf_value_destroy(val); 2392 return (stash_scferror(lcbdata)); 2393 } 2394 break; 2395 } 2396 2397 if (scf_entry_add_value(entr, val) != 0) 2398 bad_error("scf_entry_add_value", scf_error()); 2399 } 2400 2401 return (UU_WALK_NEXT); 2402 } 2403 2404 /* 2405 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 2406 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 2407 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 2408 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2409 * lcbdata->sc_err to 2410 * ECONNABORTED - repository connection broken 2411 * ENOMEM - out of memory 2412 * ENOSPC - svc.configd is out of resources 2413 * ECANCELED - sc_parent was deleted 2414 * EPERM - could not create property group (permission denied) (error printed) 2415 * - could not modify property group (permission denied) (error printed) 2416 * - could not delete property group (permission denied) (error printed) 2417 * EROFS - could not create property group (repository is read-only) 2418 * - could not delete property group (repository is read-only) 2419 * EACCES - could not create property group (backend access denied) 2420 * - could not delete property group (backend access denied) 2421 * EEXIST - could not create property group (already exists) 2422 * EINVAL - invalid property group name (error printed) 2423 * - invalid property name (error printed) 2424 * - invalid value (error printed) 2425 * EBUSY - new property group deleted (error printed) 2426 * - new property group changed (error printed) 2427 * - property group added (error printed) 2428 * - property group deleted (error printed) 2429 */ 2430 static int 2431 entity_pgroup_import(void *v, void *pvt) 2432 { 2433 pgroup_t *p = v; 2434 scf_callback_t cbdata; 2435 scf_callback_t *lcbdata = pvt; 2436 void *ent = lcbdata->sc_parent; 2437 int issvc = lcbdata->sc_service; 2438 int r; 2439 2440 const char * const pg_changed = gettext("%s changed unexpectedly " 2441 "(new property group \"%s\" changed).\n"); 2442 2443 /* Never import deleted property groups. */ 2444 if (p->sc_pgroup_delete) { 2445 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY && 2446 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) { 2447 goto delete_pg; 2448 } 2449 return (UU_WALK_NEXT); 2450 } 2451 2452 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 2453 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 2454 lcbdata->sc_general = p; 2455 return (UU_WALK_NEXT); 2456 } 2457 2458 add_pg: 2459 if (issvc) 2460 r = scf_service_add_pg(ent, p->sc_pgroup_name, 2461 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2462 else 2463 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 2464 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2465 if (r != 0) { 2466 switch (scf_error()) { 2467 case SCF_ERROR_DELETED: 2468 case SCF_ERROR_CONNECTION_BROKEN: 2469 case SCF_ERROR_BACKEND_READONLY: 2470 case SCF_ERROR_BACKEND_ACCESS: 2471 case SCF_ERROR_NO_RESOURCES: 2472 return (stash_scferror(lcbdata)); 2473 2474 case SCF_ERROR_EXISTS: 2475 if (lcbdata->sc_flags & SCI_FORCE) 2476 break; 2477 return (stash_scferror(lcbdata)); 2478 2479 case SCF_ERROR_INVALID_ARGUMENT: 2480 warn(emsg_fmri_invalid_pg_name_type, 2481 lcbdata->sc_source_fmri, 2482 p->sc_pgroup_name, p->sc_pgroup_type); 2483 return (stash_scferror(lcbdata)); 2484 2485 case SCF_ERROR_PERMISSION_DENIED: 2486 warn(emsg_pg_add_perm, p->sc_pgroup_name, 2487 lcbdata->sc_target_fmri); 2488 return (stash_scferror(lcbdata)); 2489 2490 case SCF_ERROR_NOT_BOUND: 2491 case SCF_ERROR_HANDLE_MISMATCH: 2492 case SCF_ERROR_NOT_SET: 2493 default: 2494 bad_error("scf_service_add_pg", scf_error()); 2495 } 2496 2497 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2498 switch (scf_error()) { 2499 case SCF_ERROR_CONNECTION_BROKEN: 2500 case SCF_ERROR_DELETED: 2501 return (stash_scferror(lcbdata)); 2502 2503 case SCF_ERROR_INVALID_ARGUMENT: 2504 warn(emsg_fmri_invalid_pg_name, 2505 lcbdata->sc_source_fmri, 2506 p->sc_pgroup_name); 2507 return (stash_scferror(lcbdata)); 2508 2509 case SCF_ERROR_NOT_FOUND: 2510 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2511 p->sc_pgroup_name); 2512 lcbdata->sc_err = EBUSY; 2513 return (UU_WALK_ERROR); 2514 2515 case SCF_ERROR_NOT_BOUND: 2516 case SCF_ERROR_HANDLE_MISMATCH: 2517 case SCF_ERROR_NOT_SET: 2518 default: 2519 bad_error("entity_get_pg", scf_error()); 2520 } 2521 } 2522 2523 if (lcbdata->sc_flags & SCI_KEEP) 2524 goto props; 2525 2526 delete_pg: 2527 if (scf_pg_delete(imp_pg) != 0) { 2528 switch (scf_error()) { 2529 case SCF_ERROR_DELETED: 2530 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2531 p->sc_pgroup_name); 2532 lcbdata->sc_err = EBUSY; 2533 return (UU_WALK_ERROR); 2534 2535 case SCF_ERROR_PERMISSION_DENIED: 2536 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2537 lcbdata->sc_target_fmri); 2538 return (stash_scferror(lcbdata)); 2539 2540 case SCF_ERROR_BACKEND_READONLY: 2541 case SCF_ERROR_BACKEND_ACCESS: 2542 case SCF_ERROR_CONNECTION_BROKEN: 2543 return (stash_scferror(lcbdata)); 2544 2545 case SCF_ERROR_NOT_SET: 2546 default: 2547 bad_error("scf_pg_delete", scf_error()); 2548 } 2549 } 2550 2551 if (p->sc_pgroup_delete) 2552 return (UU_WALK_NEXT); 2553 2554 goto add_pg; 2555 } 2556 2557 props: 2558 2559 /* 2560 * Add properties to property group, if any. 2561 */ 2562 cbdata.sc_handle = lcbdata->sc_handle; 2563 cbdata.sc_parent = imp_pg; 2564 cbdata.sc_flags = lcbdata->sc_flags; 2565 cbdata.sc_trans = imp_tx; 2566 cbdata.sc_enable = NULL; 2567 2568 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2569 switch (scf_error()) { 2570 case SCF_ERROR_BACKEND_ACCESS: 2571 case SCF_ERROR_BACKEND_READONLY: 2572 case SCF_ERROR_CONNECTION_BROKEN: 2573 return (stash_scferror(lcbdata)); 2574 2575 case SCF_ERROR_DELETED: 2576 warn(pg_changed, lcbdata->sc_target_fmri, 2577 p->sc_pgroup_name); 2578 lcbdata->sc_err = EBUSY; 2579 return (UU_WALK_ERROR); 2580 2581 case SCF_ERROR_PERMISSION_DENIED: 2582 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2583 lcbdata->sc_target_fmri); 2584 return (stash_scferror(lcbdata)); 2585 2586 case SCF_ERROR_NOT_BOUND: 2587 case SCF_ERROR_NOT_SET: 2588 case SCF_ERROR_IN_USE: 2589 case SCF_ERROR_HANDLE_MISMATCH: 2590 default: 2591 bad_error("scf_transaction_start", scf_error()); 2592 } 2593 } 2594 2595 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2596 UU_DEFAULT) != 0) { 2597 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2598 bad_error("uu_list_walk", uu_error()); 2599 scf_transaction_reset(imp_tx); 2600 2601 lcbdata->sc_err = cbdata.sc_err; 2602 if (cbdata.sc_err == ECANCELED) { 2603 warn(pg_changed, lcbdata->sc_target_fmri, 2604 p->sc_pgroup_name); 2605 lcbdata->sc_err = EBUSY; 2606 } 2607 return (UU_WALK_ERROR); 2608 } 2609 2610 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2611 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2612 2613 /* 2614 * take the snapshot running snapshot then 2615 * import the stored general/enable property 2616 */ 2617 r = take_snap(ent, snap_running, imp_rsnap); 2618 switch (r) { 2619 case 0: 2620 break; 2621 2622 case ECONNABORTED: 2623 warn(gettext("Could not take %s snapshot on import " 2624 "(repository connection broken).\n"), 2625 snap_running); 2626 lcbdata->sc_err = r; 2627 return (UU_WALK_ERROR); 2628 case ECANCELED: 2629 warn(emsg_deleted); 2630 lcbdata->sc_err = r; 2631 return (UU_WALK_ERROR); 2632 2633 case EPERM: 2634 warn(gettext("Could not take %s snapshot " 2635 "(permission denied).\n"), snap_running); 2636 lcbdata->sc_err = r; 2637 return (UU_WALK_ERROR); 2638 2639 case ENOSPC: 2640 warn(gettext("Could not take %s snapshot" 2641 "(repository server out of resources).\n"), 2642 snap_running); 2643 lcbdata->sc_err = r; 2644 return (UU_WALK_ERROR); 2645 2646 default: 2647 bad_error("take_snap", r); 2648 } 2649 2650 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2651 if (r != UU_WALK_NEXT) { 2652 if (r != UU_WALK_ERROR) 2653 bad_error("lscf_property_import", r); 2654 return (EINVAL); 2655 } 2656 } 2657 2658 r = scf_transaction_commit(imp_tx); 2659 switch (r) { 2660 case 1: 2661 r = UU_WALK_NEXT; 2662 break; 2663 2664 case 0: 2665 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2666 lcbdata->sc_err = EBUSY; 2667 r = UU_WALK_ERROR; 2668 break; 2669 2670 case -1: 2671 switch (scf_error()) { 2672 case SCF_ERROR_BACKEND_READONLY: 2673 case SCF_ERROR_BACKEND_ACCESS: 2674 case SCF_ERROR_CONNECTION_BROKEN: 2675 case SCF_ERROR_NO_RESOURCES: 2676 r = stash_scferror(lcbdata); 2677 break; 2678 2679 case SCF_ERROR_DELETED: 2680 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2681 p->sc_pgroup_name); 2682 lcbdata->sc_err = EBUSY; 2683 r = UU_WALK_ERROR; 2684 break; 2685 2686 case SCF_ERROR_PERMISSION_DENIED: 2687 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2688 lcbdata->sc_target_fmri); 2689 r = stash_scferror(lcbdata); 2690 break; 2691 2692 case SCF_ERROR_NOT_SET: 2693 case SCF_ERROR_INVALID_ARGUMENT: 2694 case SCF_ERROR_NOT_BOUND: 2695 default: 2696 bad_error("scf_transaction_commit", scf_error()); 2697 } 2698 break; 2699 2700 default: 2701 bad_error("scf_transaction_commit", r); 2702 } 2703 2704 scf_transaction_destroy_children(imp_tx); 2705 2706 return (r); 2707 } 2708 2709 /* 2710 * Returns 2711 * 0 - success 2712 * ECONNABORTED - repository connection broken 2713 * ENOMEM - out of memory 2714 * ENOSPC - svc.configd is out of resources 2715 * ECANCELED - inst was deleted 2716 * EPERM - could not create property group (permission denied) (error printed) 2717 * - could not modify property group (permission denied) (error printed) 2718 * EROFS - could not create property group (repository is read-only) 2719 * EACCES - could not create property group (backend access denied) 2720 * EEXIST - could not create property group (already exists) 2721 * EINVAL - invalid property group name (error printed) 2722 * - invalid property name (error printed) 2723 * - invalid value (error printed) 2724 * EBUSY - new property group changed (error printed) 2725 */ 2726 static int 2727 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2728 const entity_t *isvc, int flags) 2729 { 2730 scf_callback_t cbdata; 2731 2732 cbdata.sc_handle = scf_service_handle(svc); 2733 cbdata.sc_parent = svc; 2734 cbdata.sc_service = 1; 2735 cbdata.sc_general = 0; 2736 cbdata.sc_enable = 0; 2737 cbdata.sc_flags = flags; 2738 cbdata.sc_source_fmri = isvc->sc_fmri; 2739 cbdata.sc_target_fmri = target_fmri; 2740 2741 /* 2742 * If the op is set, then add the flag to the callback 2743 * flags for later use. 2744 */ 2745 if (isvc->sc_op != SVCCFG_OP_NONE) { 2746 switch (isvc->sc_op) { 2747 case SVCCFG_OP_IMPORT : 2748 cbdata.sc_flags |= SCI_OP_IMPORT; 2749 break; 2750 case SVCCFG_OP_APPLY : 2751 cbdata.sc_flags |= SCI_OP_APPLY; 2752 break; 2753 case SVCCFG_OP_RESTORE : 2754 cbdata.sc_flags |= SCI_OP_RESTORE; 2755 break; 2756 default : 2757 uu_die(gettext("lscf_import_service_pgs : " 2758 "Unknown op stored in the service entity\n")); 2759 2760 } 2761 } 2762 2763 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2764 UU_DEFAULT) != 0) { 2765 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2766 bad_error("uu_list_walk", uu_error()); 2767 2768 return (cbdata.sc_err); 2769 } 2770 2771 return (0); 2772 } 2773 2774 /* 2775 * Returns 2776 * 0 - success 2777 * ECONNABORTED - repository connection broken 2778 * ENOMEM - out of memory 2779 * ENOSPC - svc.configd is out of resources 2780 * ECANCELED - inst was deleted 2781 * EPERM - could not create property group (permission denied) (error printed) 2782 * - could not modify property group (permission denied) (error printed) 2783 * EROFS - could not create property group (repository is read-only) 2784 * EACCES - could not create property group (backend access denied) 2785 * EEXIST - could not create property group (already exists) 2786 * EINVAL - invalid property group name (error printed) 2787 * - invalid property name (error printed) 2788 * - invalid value (error printed) 2789 * EBUSY - new property group changed (error printed) 2790 */ 2791 static int 2792 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2793 const entity_t *iinst, int flags) 2794 { 2795 scf_callback_t cbdata; 2796 2797 cbdata.sc_handle = scf_instance_handle(inst); 2798 cbdata.sc_parent = inst; 2799 cbdata.sc_service = 0; 2800 cbdata.sc_general = NULL; 2801 cbdata.sc_enable = NULL; 2802 cbdata.sc_flags = flags; 2803 cbdata.sc_source_fmri = iinst->sc_fmri; 2804 cbdata.sc_target_fmri = target_fmri; 2805 2806 /* 2807 * If the op is set, then add the flag to the callback 2808 * flags for later use. 2809 */ 2810 if (iinst->sc_op != SVCCFG_OP_NONE) { 2811 switch (iinst->sc_op) { 2812 case SVCCFG_OP_IMPORT : 2813 cbdata.sc_flags |= SCI_OP_IMPORT; 2814 break; 2815 case SVCCFG_OP_APPLY : 2816 cbdata.sc_flags |= SCI_OP_APPLY; 2817 break; 2818 case SVCCFG_OP_RESTORE : 2819 cbdata.sc_flags |= SCI_OP_RESTORE; 2820 break; 2821 default : 2822 uu_die(gettext("lscf_import_instance_pgs : " 2823 "Unknown op stored in the instance entity\n")); 2824 } 2825 } 2826 2827 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2828 UU_DEFAULT) != 0) { 2829 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2830 bad_error("uu_list_walk", uu_error()); 2831 2832 return (cbdata.sc_err); 2833 } 2834 2835 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2836 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2837 /* 2838 * If importing with the SCI_NOENABLED flag then 2839 * skip the delay, but if not then add the delay 2840 * of the enable property. 2841 */ 2842 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2843 cbdata.sc_flags |= SCI_DELAYENABLE; 2844 } 2845 2846 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2847 != UU_WALK_NEXT) 2848 return (cbdata.sc_err); 2849 } 2850 2851 return (0); 2852 } 2853 2854 /* 2855 * Report the reasons why we can't upgrade pg2 to pg1. 2856 */ 2857 static void 2858 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2859 int new) 2860 { 2861 property_t *p1, *p2; 2862 2863 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2864 2865 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2866 return; 2867 2868 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2869 p1 != NULL; 2870 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2871 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2872 if (p2 != NULL) { 2873 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2874 new); 2875 continue; 2876 } 2877 2878 if (new) 2879 warn(gettext("Conflict upgrading %s (new property " 2880 "group \"%s\" is missing property \"%s\").\n"), 2881 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2882 else 2883 warn(gettext("Conflict upgrading %s (property " 2884 "\"%s/%s\" is missing).\n"), fmri, 2885 pg1->sc_pgroup_name, p1->sc_property_name); 2886 } 2887 2888 /* 2889 * Since pg1 should be from the manifest, any properties in pg2 which 2890 * aren't in pg1 shouldn't be reported as conflicts. 2891 */ 2892 } 2893 2894 /* 2895 * Add transaction entries to tx which will upgrade cur's pg according to old 2896 * & new. 2897 * 2898 * Returns 2899 * 0 - success 2900 * EINVAL - new has a property with an invalid name or value (message emitted) 2901 * ENOMEM - out of memory 2902 */ 2903 static int 2904 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2905 pgroup_t *cur, int speak, const char *fmri) 2906 { 2907 property_t *p, *new_p, *cur_p; 2908 scf_transaction_entry_t *e; 2909 int r; 2910 int is_general; 2911 int is_protected; 2912 2913 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2914 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2915 bad_error("uu_list_walk", uu_error()); 2916 2917 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2918 2919 for (p = uu_list_first(old->sc_pgroup_props); 2920 p != NULL; 2921 p = uu_list_next(old->sc_pgroup_props, p)) { 2922 /* p is a property in the old property group. */ 2923 2924 /* Protect live properties. */ 2925 is_protected = 0; 2926 if (is_general) { 2927 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2928 0 || 2929 strcmp(p->sc_property_name, 2930 SCF_PROPERTY_RESTARTER) == 0) 2931 is_protected = 1; 2932 } 2933 2934 /* Look for the same property in the new properties. */ 2935 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2936 if (new_p != NULL) { 2937 new_p->sc_seen = 1; 2938 2939 /* 2940 * If the new property is the same as the old, don't do 2941 * anything (leave any user customizations). 2942 */ 2943 if (prop_equal(p, new_p, NULL, NULL, 0)) 2944 continue; 2945 2946 if (new_p->sc_property_override) 2947 goto upgrade; 2948 } 2949 2950 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2951 if (cur_p == NULL) { 2952 /* 2953 * p has been deleted from the repository. If we were 2954 * going to delete it anyway, do nothing. Otherwise 2955 * report a conflict. 2956 */ 2957 if (new_p == NULL) 2958 continue; 2959 2960 if (is_protected) 2961 continue; 2962 2963 warn(gettext("Conflict upgrading %s " 2964 "(property \"%s/%s\" is missing).\n"), fmri, 2965 old->sc_pgroup_name, p->sc_property_name); 2966 continue; 2967 } 2968 2969 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2970 /* 2971 * Conflict. Don't warn if the property is already the 2972 * way we want it, though. 2973 */ 2974 if (is_protected) 2975 continue; 2976 2977 if (new_p == NULL) 2978 (void) prop_equal(p, cur_p, fmri, 2979 old->sc_pgroup_name, 0); 2980 else 2981 (void) prop_equal(cur_p, new_p, fmri, 2982 old->sc_pgroup_name, 0); 2983 continue; 2984 } 2985 2986 if (is_protected) { 2987 if (speak) 2988 warn(gettext("%s: Refusing to upgrade " 2989 "\"%s/%s\" (live property).\n"), fmri, 2990 old->sc_pgroup_name, p->sc_property_name); 2991 continue; 2992 } 2993 2994 upgrade: 2995 /* p hasn't been customized in the repository. Upgrade it. */ 2996 if (new_p == NULL) { 2997 /* p was deleted. Delete from cur if unchanged. */ 2998 if (speak) 2999 warn(gettext( 3000 "%s: Deleting property \"%s/%s\".\n"), 3001 fmri, old->sc_pgroup_name, 3002 p->sc_property_name); 3003 3004 e = scf_entry_create(g_hndl); 3005 if (e == NULL) 3006 return (ENOMEM); 3007 3008 if (scf_transaction_property_delete(tx, e, 3009 p->sc_property_name) != 0) { 3010 switch (scf_error()) { 3011 case SCF_ERROR_DELETED: 3012 scf_entry_destroy(e); 3013 return (ECANCELED); 3014 3015 case SCF_ERROR_CONNECTION_BROKEN: 3016 scf_entry_destroy(e); 3017 return (ECONNABORTED); 3018 3019 case SCF_ERROR_NOT_FOUND: 3020 /* 3021 * This can happen if cur is from the 3022 * running snapshot (and it differs 3023 * from the live properties). 3024 */ 3025 scf_entry_destroy(e); 3026 break; 3027 3028 case SCF_ERROR_HANDLE_MISMATCH: 3029 case SCF_ERROR_NOT_BOUND: 3030 case SCF_ERROR_NOT_SET: 3031 case SCF_ERROR_INVALID_ARGUMENT: 3032 default: 3033 bad_error( 3034 "scf_transaction_property_delete", 3035 scf_error()); 3036 } 3037 } 3038 } else { 3039 scf_callback_t ctx; 3040 3041 if (speak) 3042 warn(gettext( 3043 "%s: Upgrading property \"%s/%s\".\n"), 3044 fmri, old->sc_pgroup_name, 3045 p->sc_property_name); 3046 3047 ctx.sc_handle = g_hndl; 3048 ctx.sc_trans = tx; 3049 ctx.sc_flags = 0; 3050 3051 r = lscf_property_import(new_p, &ctx); 3052 if (r != UU_WALK_NEXT) { 3053 if (r != UU_WALK_ERROR) 3054 bad_error("lscf_property_import", r); 3055 return (EINVAL); 3056 } 3057 } 3058 } 3059 3060 /* Go over the properties which were added. */ 3061 for (new_p = uu_list_first(new->sc_pgroup_props); 3062 new_p != NULL; 3063 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 3064 if (new_p->sc_seen) 3065 continue; 3066 3067 /* This is a new property. */ 3068 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 3069 if (cur_p == NULL) { 3070 scf_callback_t ctx; 3071 3072 ctx.sc_handle = g_hndl; 3073 ctx.sc_trans = tx; 3074 ctx.sc_flags = 0; 3075 3076 r = lscf_property_import(new_p, &ctx); 3077 if (r != UU_WALK_NEXT) { 3078 if (r != UU_WALK_ERROR) 3079 bad_error("lscf_property_import", r); 3080 return (EINVAL); 3081 } 3082 continue; 3083 } 3084 3085 /* 3086 * Report a conflict if the new property differs from the 3087 * current one. Unless it's general/enabled, since that's 3088 * never in the last-import snapshot. 3089 */ 3090 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 3091 0 && 3092 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 3093 continue; 3094 3095 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 3096 } 3097 3098 return (0); 3099 } 3100 3101 /* 3102 * Upgrade pg according to old & new. 3103 * 3104 * Returns 3105 * 0 - success 3106 * ECONNABORTED - repository connection broken 3107 * ENOMEM - out of memory 3108 * ENOSPC - svc.configd is out of resources 3109 * ECANCELED - pg was deleted 3110 * EPERM - couldn't modify pg (permission denied) 3111 * EROFS - couldn't modify pg (backend read-only) 3112 * EACCES - couldn't modify pg (backend access denied) 3113 * EINVAL - new has a property with invalid name or value (error printed) 3114 * EBUSY - pg changed unexpectedly 3115 */ 3116 static int 3117 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 3118 pgroup_t *new, int speak, const char *fmri) 3119 { 3120 int r; 3121 3122 if (scf_transaction_start(imp_tx, pg) != 0) { 3123 switch (scf_error()) { 3124 case SCF_ERROR_CONNECTION_BROKEN: 3125 case SCF_ERROR_DELETED: 3126 case SCF_ERROR_PERMISSION_DENIED: 3127 case SCF_ERROR_BACKEND_READONLY: 3128 case SCF_ERROR_BACKEND_ACCESS: 3129 return (scferror2errno(scf_error())); 3130 3131 case SCF_ERROR_HANDLE_MISMATCH: 3132 case SCF_ERROR_IN_USE: 3133 case SCF_ERROR_NOT_BOUND: 3134 case SCF_ERROR_NOT_SET: 3135 default: 3136 bad_error("scf_transaction_start", scf_error()); 3137 } 3138 } 3139 3140 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 3141 switch (r) { 3142 case 0: 3143 break; 3144 3145 case EINVAL: 3146 case ENOMEM: 3147 scf_transaction_destroy_children(imp_tx); 3148 return (r); 3149 3150 default: 3151 bad_error("add_upgrade_entries", r); 3152 } 3153 3154 r = scf_transaction_commit(imp_tx); 3155 3156 scf_transaction_destroy_children(imp_tx); 3157 3158 switch (r) { 3159 case 1: 3160 break; 3161 3162 case 0: 3163 return (EBUSY); 3164 3165 case -1: 3166 switch (scf_error()) { 3167 case SCF_ERROR_CONNECTION_BROKEN: 3168 case SCF_ERROR_NO_RESOURCES: 3169 case SCF_ERROR_PERMISSION_DENIED: 3170 case SCF_ERROR_BACKEND_READONLY: 3171 case SCF_ERROR_BACKEND_ACCESS: 3172 case SCF_ERROR_DELETED: 3173 return (scferror2errno(scf_error())); 3174 3175 case SCF_ERROR_NOT_BOUND: 3176 case SCF_ERROR_INVALID_ARGUMENT: 3177 case SCF_ERROR_NOT_SET: 3178 default: 3179 bad_error("scf_transaction_commit", scf_error()); 3180 } 3181 3182 default: 3183 bad_error("scf_transaction_commit", r); 3184 } 3185 3186 return (0); 3187 } 3188 3189 /* 3190 * Compares two entity FMRIs. Returns 3191 * 3192 * 1 - equal 3193 * 0 - not equal 3194 * -1 - f1 is invalid or not an entity 3195 * -2 - f2 is invalid or not an entity 3196 */ 3197 static int 3198 fmri_equal(const char *f1, const char *f2) 3199 { 3200 int r; 3201 const char *s1, *i1, *pg1; 3202 const char *s2, *i2, *pg2; 3203 3204 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3205 return (-1); 3206 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 3207 return (-1); 3208 3209 if (s1 == NULL || pg1 != NULL) 3210 return (-1); 3211 3212 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3213 return (-2); 3214 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 3215 return (-2); 3216 3217 if (s2 == NULL || pg2 != NULL) 3218 return (-2); 3219 3220 r = strcmp(s1, s2); 3221 if (r != 0) 3222 return (0); 3223 3224 if (i1 == NULL && i2 == NULL) 3225 return (1); 3226 3227 if (i1 == NULL || i2 == NULL) 3228 return (0); 3229 3230 return (strcmp(i1, i2) == 0); 3231 } 3232 3233 /* 3234 * Import a dependent by creating a dependency property group in the dependent 3235 * entity. If lcbdata->sc_trans is set, assume it's been started on the 3236 * dependents pg, and add an entry to create a new property for this 3237 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 3238 * 3239 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 3240 * lcbdata->sc_err to 3241 * ECONNABORTED - repository connection broken 3242 * ENOMEM - out of memory 3243 * ENOSPC - configd is out of resources 3244 * EINVAL - target is invalid (error printed) 3245 * - target is not an entity (error printed) 3246 * - dependent has invalid name (error printed) 3247 * - invalid property name (error printed) 3248 * - invalid value (error printed) 3249 * - scope of target does not exist (error printed) 3250 * EPERM - couldn't create target (permission denied) (error printed) 3251 * - couldn't create dependency pg (permission denied) (error printed) 3252 * - couldn't modify dependency pg (permission denied) (error printed) 3253 * EROFS - couldn't create target (repository read-only) 3254 * - couldn't create dependency pg (repository read-only) 3255 * EACCES - couldn't create target (backend access denied) 3256 * - couldn't create dependency pg (backend access denied) 3257 * ECANCELED - sc_trans's pg was deleted 3258 * EALREADY - property for dependent already exists in sc_trans's pg 3259 * EEXIST - dependency pg already exists in target (error printed) 3260 * EBUSY - target deleted (error printed) 3261 * - property group changed during import (error printed) 3262 */ 3263 static int 3264 lscf_dependent_import(void *a1, void *pvt) 3265 { 3266 pgroup_t *pgrp = a1; 3267 scf_callback_t *lcbdata = pvt; 3268 3269 int isservice; 3270 int ret; 3271 scf_transaction_entry_t *e; 3272 scf_value_t *val; 3273 scf_callback_t dependent_cbdata; 3274 scf_error_t scfe; 3275 3276 /* 3277 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 3278 * it's invalid, we fail before modifying the repository. 3279 */ 3280 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3281 &dependent_cbdata.sc_parent, &isservice); 3282 switch (scfe) { 3283 case SCF_ERROR_NONE: 3284 break; 3285 3286 case SCF_ERROR_NO_MEMORY: 3287 return (stash_scferror_err(lcbdata, scfe)); 3288 3289 case SCF_ERROR_INVALID_ARGUMENT: 3290 semerr(gettext("The FMRI for the \"%s\" dependent is " 3291 "invalid.\n"), pgrp->sc_pgroup_name); 3292 return (stash_scferror_err(lcbdata, scfe)); 3293 3294 case SCF_ERROR_CONSTRAINT_VIOLATED: 3295 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 3296 "specifies neither a service nor an instance.\n"), 3297 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3298 return (stash_scferror_err(lcbdata, scfe)); 3299 3300 case SCF_ERROR_NOT_FOUND: 3301 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3302 &dependent_cbdata.sc_parent, &isservice); 3303 switch (scfe) { 3304 case SCF_ERROR_NONE: 3305 break; 3306 3307 case SCF_ERROR_NO_MEMORY: 3308 case SCF_ERROR_BACKEND_READONLY: 3309 case SCF_ERROR_BACKEND_ACCESS: 3310 return (stash_scferror_err(lcbdata, scfe)); 3311 3312 case SCF_ERROR_NOT_FOUND: 3313 semerr(gettext("The scope in FMRI \"%s\" for the " 3314 "\"%s\" dependent does not exist.\n"), 3315 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3316 lcbdata->sc_err = EINVAL; 3317 return (UU_WALK_ERROR); 3318 3319 case SCF_ERROR_PERMISSION_DENIED: 3320 warn(gettext( 3321 "Could not create %s (permission denied).\n"), 3322 pgrp->sc_pgroup_fmri); 3323 return (stash_scferror_err(lcbdata, scfe)); 3324 3325 case SCF_ERROR_INVALID_ARGUMENT: 3326 case SCF_ERROR_CONSTRAINT_VIOLATED: 3327 default: 3328 bad_error("create_entity", scfe); 3329 } 3330 break; 3331 3332 default: 3333 bad_error("fmri_to_entity", scfe); 3334 } 3335 3336 if (lcbdata->sc_trans != NULL) { 3337 e = scf_entry_create(lcbdata->sc_handle); 3338 if (e == NULL) { 3339 if (scf_error() != SCF_ERROR_NO_MEMORY) 3340 bad_error("scf_entry_create", scf_error()); 3341 3342 entity_destroy(dependent_cbdata.sc_parent, isservice); 3343 return (stash_scferror(lcbdata)); 3344 } 3345 3346 if (scf_transaction_property_new(lcbdata->sc_trans, e, 3347 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 3348 switch (scf_error()) { 3349 case SCF_ERROR_INVALID_ARGUMENT: 3350 warn(gettext("Dependent of %s has invalid name " 3351 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 3352 pgrp->sc_pgroup_name); 3353 /* FALLTHROUGH */ 3354 3355 case SCF_ERROR_DELETED: 3356 case SCF_ERROR_CONNECTION_BROKEN: 3357 scf_entry_destroy(e); 3358 entity_destroy(dependent_cbdata.sc_parent, 3359 isservice); 3360 return (stash_scferror(lcbdata)); 3361 3362 case SCF_ERROR_EXISTS: 3363 scf_entry_destroy(e); 3364 entity_destroy(dependent_cbdata.sc_parent, 3365 isservice); 3366 lcbdata->sc_err = EALREADY; 3367 return (UU_WALK_ERROR); 3368 3369 case SCF_ERROR_NOT_BOUND: 3370 case SCF_ERROR_HANDLE_MISMATCH: 3371 case SCF_ERROR_NOT_SET: 3372 default: 3373 bad_error("scf_transaction_property_new", 3374 scf_error()); 3375 } 3376 } 3377 3378 val = scf_value_create(lcbdata->sc_handle); 3379 if (val == NULL) { 3380 if (scf_error() != SCF_ERROR_NO_MEMORY) 3381 bad_error("scf_value_create", scf_error()); 3382 3383 entity_destroy(dependent_cbdata.sc_parent, isservice); 3384 return (stash_scferror(lcbdata)); 3385 } 3386 3387 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3388 pgrp->sc_pgroup_fmri) != 0) 3389 /* invalid should have been caught above */ 3390 bad_error("scf_value_set_from_string", scf_error()); 3391 3392 if (scf_entry_add_value(e, val) != 0) 3393 bad_error("scf_entry_add_value", scf_error()); 3394 } 3395 3396 /* Add the property group to the target entity. */ 3397 3398 dependent_cbdata.sc_handle = lcbdata->sc_handle; 3399 dependent_cbdata.sc_flags = lcbdata->sc_flags; 3400 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 3401 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 3402 3403 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 3404 3405 entity_destroy(dependent_cbdata.sc_parent, isservice); 3406 3407 if (ret == UU_WALK_NEXT) 3408 return (ret); 3409 3410 if (ret != UU_WALK_ERROR) 3411 bad_error("entity_pgroup_import", ret); 3412 3413 switch (dependent_cbdata.sc_err) { 3414 case ECANCELED: 3415 warn(gettext("%s deleted unexpectedly.\n"), 3416 pgrp->sc_pgroup_fmri); 3417 lcbdata->sc_err = EBUSY; 3418 break; 3419 3420 case EEXIST: 3421 warn(gettext("Could not create \"%s\" dependency in %s " 3422 "(already exists).\n"), pgrp->sc_pgroup_name, 3423 pgrp->sc_pgroup_fmri); 3424 /* FALLTHROUGH */ 3425 3426 default: 3427 lcbdata->sc_err = dependent_cbdata.sc_err; 3428 } 3429 3430 return (UU_WALK_ERROR); 3431 } 3432 3433 static int upgrade_dependent(const scf_property_t *, const entity_t *, 3434 const scf_snaplevel_t *, scf_transaction_t *); 3435 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 3436 const pgroup_t *); 3437 3438 /* 3439 * Upgrade uncustomized dependents of ent to those specified in ient. Read 3440 * the current dependent targets from running (the snaplevel of a running 3441 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 3442 * scf_instance_t * according to ient, otherwise). Draw the ancestral 3443 * dependent targets and dependency properties from li_dpts_pg (the 3444 * "dependents" property group in snpl) and snpl (the snaplevel which 3445 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 3446 * snpl doesn't have a "dependents" property group, and any dependents in ient 3447 * are new. 3448 * 3449 * Returns 3450 * 0 - success 3451 * ECONNABORTED - repository connection broken 3452 * ENOMEM - out of memory 3453 * ENOSPC - configd is out of resources 3454 * ECANCELED - ent was deleted 3455 * ENODEV - the entity containing li_dpts_pg was deleted 3456 * EPERM - could not modify dependents pg (permission denied) (error printed) 3457 * - couldn't upgrade dependent (permission denied) (error printed) 3458 * - couldn't create dependent (permission denied) (error printed) 3459 * EROFS - could not modify dependents pg (repository read-only) 3460 * - couldn't upgrade dependent (repository read-only) 3461 * - couldn't create dependent (repository read-only) 3462 * EACCES - could not modify dependents pg (backend access denied) 3463 * - could not upgrade dependent (backend access denied) 3464 * - could not create dependent (backend access denied) 3465 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 3466 * - dependent target deleted (error printed) 3467 * - dependent pg changed (error printed) 3468 * EINVAL - new dependent is invalid (error printed) 3469 * EBADF - snpl is corrupt (error printed) 3470 * - snpl has corrupt pg (error printed) 3471 * - dependency pg in target is corrupt (error printed) 3472 * - target has corrupt snapshot (error printed) 3473 * EEXIST - dependency pg already existed in target service (error printed) 3474 */ 3475 static int 3476 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 3477 const scf_snaplevel_t *snpl, const entity_t *ient, 3478 const scf_snaplevel_t *running, void *ent) 3479 { 3480 pgroup_t *new_dpt_pgroup; 3481 scf_callback_t cbdata; 3482 int r, unseen, tx_started = 0; 3483 int have_cur_depts; 3484 3485 const char * const dependents = "dependents"; 3486 3487 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3488 3489 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 3490 /* Nothing to do. */ 3491 return (0); 3492 3493 /* Fetch the current version of the "dependents" property group. */ 3494 have_cur_depts = 1; 3495 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 3496 switch (scf_error()) { 3497 case SCF_ERROR_NOT_FOUND: 3498 break; 3499 3500 case SCF_ERROR_DELETED: 3501 case SCF_ERROR_CONNECTION_BROKEN: 3502 return (scferror2errno(scf_error())); 3503 3504 case SCF_ERROR_NOT_SET: 3505 case SCF_ERROR_INVALID_ARGUMENT: 3506 case SCF_ERROR_HANDLE_MISMATCH: 3507 case SCF_ERROR_NOT_BOUND: 3508 default: 3509 bad_error("entity_get_pg", scf_error()); 3510 } 3511 3512 have_cur_depts = 0; 3513 } 3514 3515 /* Fetch the running version of the "dependents" property group. */ 3516 ud_run_dpts_pg_set = 0; 3517 if (running != NULL) 3518 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 3519 else 3520 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 3521 if (r == 0) { 3522 ud_run_dpts_pg_set = 1; 3523 } else { 3524 switch (scf_error()) { 3525 case SCF_ERROR_NOT_FOUND: 3526 break; 3527 3528 case SCF_ERROR_DELETED: 3529 case SCF_ERROR_CONNECTION_BROKEN: 3530 return (scferror2errno(scf_error())); 3531 3532 case SCF_ERROR_NOT_SET: 3533 case SCF_ERROR_INVALID_ARGUMENT: 3534 case SCF_ERROR_HANDLE_MISMATCH: 3535 case SCF_ERROR_NOT_BOUND: 3536 default: 3537 bad_error(running ? "scf_snaplevel_get_pg" : 3538 "entity_get_pg", scf_error()); 3539 } 3540 } 3541 3542 /* 3543 * Clear the seen fields of the dependents, so we can tell which ones 3544 * are new. 3545 */ 3546 if (uu_list_walk(ient->sc_dependents, clear_int, 3547 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3548 bad_error("uu_list_walk", uu_error()); 3549 3550 if (li_dpts_pg != NULL) { 3551 /* 3552 * Each property in li_dpts_pg represents a dependent tag in 3553 * the old manifest. For each, call upgrade_dependent(), 3554 * which will change ud_cur_depts_pg or dependencies in other 3555 * services as appropriate. Note (a) that changes to 3556 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3557 * made en masse, and (b) it's ok if the entity doesn't have 3558 * a current version of the "dependents" property group, 3559 * because we'll just consider all dependents as customized 3560 * (by being deleted). 3561 */ 3562 3563 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3564 switch (scf_error()) { 3565 case SCF_ERROR_DELETED: 3566 return (ENODEV); 3567 3568 case SCF_ERROR_CONNECTION_BROKEN: 3569 return (ECONNABORTED); 3570 3571 case SCF_ERROR_HANDLE_MISMATCH: 3572 case SCF_ERROR_NOT_BOUND: 3573 case SCF_ERROR_NOT_SET: 3574 default: 3575 bad_error("scf_iter_pg_properties", 3576 scf_error()); 3577 } 3578 } 3579 3580 if (have_cur_depts && 3581 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3582 switch (scf_error()) { 3583 case SCF_ERROR_BACKEND_ACCESS: 3584 case SCF_ERROR_BACKEND_READONLY: 3585 case SCF_ERROR_CONNECTION_BROKEN: 3586 return (scferror2errno(scf_error())); 3587 3588 case SCF_ERROR_DELETED: 3589 warn(emsg_pg_deleted, ient->sc_fmri, 3590 dependents); 3591 return (EBUSY); 3592 3593 case SCF_ERROR_PERMISSION_DENIED: 3594 warn(emsg_pg_mod_perm, dependents, 3595 ient->sc_fmri); 3596 return (scferror2errno(scf_error())); 3597 3598 case SCF_ERROR_HANDLE_MISMATCH: 3599 case SCF_ERROR_IN_USE: 3600 case SCF_ERROR_NOT_BOUND: 3601 case SCF_ERROR_NOT_SET: 3602 default: 3603 bad_error("scf_transaction_start", scf_error()); 3604 } 3605 } 3606 tx_started = have_cur_depts; 3607 3608 for (;;) { 3609 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3610 if (r == 0) 3611 break; 3612 if (r == 1) { 3613 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3614 tx_started ? ud_tx : NULL); 3615 switch (r) { 3616 case 0: 3617 continue; 3618 3619 case ECONNABORTED: 3620 case ENOMEM: 3621 case ENOSPC: 3622 case EBADF: 3623 case EBUSY: 3624 case EINVAL: 3625 case EPERM: 3626 case EROFS: 3627 case EACCES: 3628 case EEXIST: 3629 break; 3630 3631 case ECANCELED: 3632 r = ENODEV; 3633 break; 3634 3635 default: 3636 bad_error("upgrade_dependent", r); 3637 } 3638 3639 if (tx_started) 3640 scf_transaction_destroy_children(ud_tx); 3641 return (r); 3642 } 3643 if (r != -1) 3644 bad_error("scf_iter_next_property", r); 3645 3646 switch (scf_error()) { 3647 case SCF_ERROR_DELETED: 3648 r = ENODEV; 3649 break; 3650 3651 case SCF_ERROR_CONNECTION_BROKEN: 3652 r = ECONNABORTED; 3653 break; 3654 3655 case SCF_ERROR_NOT_SET: 3656 case SCF_ERROR_INVALID_ARGUMENT: 3657 case SCF_ERROR_NOT_BOUND: 3658 case SCF_ERROR_HANDLE_MISMATCH: 3659 default: 3660 bad_error("scf_iter_next_property", 3661 scf_error()); 3662 } 3663 3664 if (tx_started) 3665 scf_transaction_destroy_children(ud_tx); 3666 return (r); 3667 } 3668 } 3669 3670 /* import unseen dependents */ 3671 unseen = 0; 3672 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3673 new_dpt_pgroup != NULL; 3674 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3675 new_dpt_pgroup)) { 3676 if (!new_dpt_pgroup->sc_pgroup_seen) { 3677 unseen = 1; 3678 break; 3679 } 3680 } 3681 3682 /* If there are none, exit early. */ 3683 if (unseen == 0) 3684 goto commit; 3685 3686 /* Set up for lscf_dependent_import() */ 3687 cbdata.sc_handle = g_hndl; 3688 cbdata.sc_parent = ent; 3689 cbdata.sc_service = issvc; 3690 cbdata.sc_flags = 0; 3691 3692 if (!have_cur_depts) { 3693 /* 3694 * We have new dependents to import, so we need a "dependents" 3695 * property group. 3696 */ 3697 if (issvc) 3698 r = scf_service_add_pg(ent, dependents, 3699 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3700 else 3701 r = scf_instance_add_pg(ent, dependents, 3702 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3703 if (r != 0) { 3704 switch (scf_error()) { 3705 case SCF_ERROR_DELETED: 3706 case SCF_ERROR_CONNECTION_BROKEN: 3707 case SCF_ERROR_BACKEND_READONLY: 3708 case SCF_ERROR_BACKEND_ACCESS: 3709 case SCF_ERROR_NO_RESOURCES: 3710 return (scferror2errno(scf_error())); 3711 3712 case SCF_ERROR_EXISTS: 3713 warn(emsg_pg_added, ient->sc_fmri, dependents); 3714 return (EBUSY); 3715 3716 case SCF_ERROR_PERMISSION_DENIED: 3717 warn(emsg_pg_add_perm, dependents, 3718 ient->sc_fmri); 3719 return (scferror2errno(scf_error())); 3720 3721 case SCF_ERROR_NOT_BOUND: 3722 case SCF_ERROR_HANDLE_MISMATCH: 3723 case SCF_ERROR_INVALID_ARGUMENT: 3724 case SCF_ERROR_NOT_SET: 3725 default: 3726 bad_error("scf_service_add_pg", scf_error()); 3727 } 3728 } 3729 } 3730 3731 cbdata.sc_trans = ud_tx; 3732 3733 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3734 switch (scf_error()) { 3735 case SCF_ERROR_CONNECTION_BROKEN: 3736 case SCF_ERROR_BACKEND_ACCESS: 3737 case SCF_ERROR_BACKEND_READONLY: 3738 return (scferror2errno(scf_error())); 3739 3740 case SCF_ERROR_DELETED: 3741 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3742 return (EBUSY); 3743 3744 case SCF_ERROR_PERMISSION_DENIED: 3745 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3746 return (scferror2errno(scf_error())); 3747 3748 case SCF_ERROR_HANDLE_MISMATCH: 3749 case SCF_ERROR_IN_USE: 3750 case SCF_ERROR_NOT_BOUND: 3751 case SCF_ERROR_NOT_SET: 3752 default: 3753 bad_error("scf_transaction_start", scf_error()); 3754 } 3755 } 3756 tx_started = 1; 3757 3758 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3759 new_dpt_pgroup != NULL; 3760 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3761 new_dpt_pgroup)) { 3762 if (new_dpt_pgroup->sc_pgroup_seen) 3763 continue; 3764 3765 if (ud_run_dpts_pg_set) { 3766 /* 3767 * If the dependent is already there, then we have 3768 * a conflict. 3769 */ 3770 if (scf_pg_get_property(ud_run_dpts_pg, 3771 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3772 r = handle_dependent_conflict(ient, ud_prop, 3773 new_dpt_pgroup); 3774 switch (r) { 3775 case 0: 3776 continue; 3777 3778 case ECONNABORTED: 3779 case ENOMEM: 3780 case EBUSY: 3781 case EBADF: 3782 case EINVAL: 3783 scf_transaction_destroy_children(ud_tx); 3784 return (r); 3785 3786 default: 3787 bad_error("handle_dependent_conflict", 3788 r); 3789 } 3790 } else { 3791 switch (scf_error()) { 3792 case SCF_ERROR_NOT_FOUND: 3793 break; 3794 3795 case SCF_ERROR_INVALID_ARGUMENT: 3796 warn(emsg_fmri_invalid_pg_name, 3797 ient->sc_fmri, 3798 new_dpt_pgroup->sc_pgroup_name); 3799 scf_transaction_destroy_children(ud_tx); 3800 return (EINVAL); 3801 3802 case SCF_ERROR_DELETED: 3803 warn(emsg_pg_deleted, ient->sc_fmri, 3804 new_dpt_pgroup->sc_pgroup_name); 3805 scf_transaction_destroy_children(ud_tx); 3806 return (EBUSY); 3807 3808 case SCF_ERROR_CONNECTION_BROKEN: 3809 scf_transaction_destroy_children(ud_tx); 3810 return (ECONNABORTED); 3811 3812 case SCF_ERROR_NOT_BOUND: 3813 case SCF_ERROR_HANDLE_MISMATCH: 3814 case SCF_ERROR_NOT_SET: 3815 default: 3816 bad_error("scf_pg_get_property", 3817 scf_error()); 3818 } 3819 } 3820 } 3821 3822 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3823 if (r != UU_WALK_NEXT) { 3824 if (r != UU_WALK_ERROR) 3825 bad_error("lscf_dependent_import", r); 3826 3827 if (cbdata.sc_err == EALREADY) { 3828 /* Collisions were handled preemptively. */ 3829 bad_error("lscf_dependent_import", 3830 cbdata.sc_err); 3831 } 3832 3833 scf_transaction_destroy_children(ud_tx); 3834 return (cbdata.sc_err); 3835 } 3836 } 3837 3838 commit: 3839 if (!tx_started) 3840 return (0); 3841 3842 r = scf_transaction_commit(ud_tx); 3843 3844 scf_transaction_destroy_children(ud_tx); 3845 3846 switch (r) { 3847 case 1: 3848 return (0); 3849 3850 case 0: 3851 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3852 return (EBUSY); 3853 3854 case -1: 3855 break; 3856 3857 default: 3858 bad_error("scf_transaction_commit", r); 3859 } 3860 3861 switch (scf_error()) { 3862 case SCF_ERROR_CONNECTION_BROKEN: 3863 case SCF_ERROR_BACKEND_READONLY: 3864 case SCF_ERROR_BACKEND_ACCESS: 3865 case SCF_ERROR_NO_RESOURCES: 3866 return (scferror2errno(scf_error())); 3867 3868 case SCF_ERROR_DELETED: 3869 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3870 return (EBUSY); 3871 3872 case SCF_ERROR_PERMISSION_DENIED: 3873 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3874 return (scferror2errno(scf_error())); 3875 3876 case SCF_ERROR_NOT_BOUND: 3877 case SCF_ERROR_INVALID_ARGUMENT: 3878 case SCF_ERROR_NOT_SET: 3879 default: 3880 bad_error("scf_transaction_destroy", scf_error()); 3881 /* NOTREACHED */ 3882 } 3883 } 3884 3885 /* 3886 * Used to add the manifests to the list of currently supported manifests. 3887 * We can modify the existing manifest list removing entries if the files 3888 * don't exist. 3889 * 3890 * Get the old list and the new file name 3891 * If the new file name is in the list return 3892 * If not then add the file to the list. 3893 * As we process the list check to see if the files in the old list exist 3894 * if not then remove the file from the list. 3895 * Commit the list of manifest file names. 3896 * 3897 */ 3898 static int 3899 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient, 3900 const scf_snaplevel_t *running, void *ent) 3901 { 3902 scf_propertygroup_t *ud_mfsts_pg = NULL; 3903 scf_property_t *ud_prop = NULL; 3904 scf_iter_t *ud_prop_iter; 3905 scf_value_t *fname_value; 3906 scf_callback_t cbdata; 3907 pgroup_t *mfst_pgroup; 3908 property_t *mfst_prop; 3909 property_t *old_prop; 3910 char *pname; 3911 char *fval; 3912 char *old_pname; 3913 char *old_fval; 3914 int no_upgrade_pg; 3915 int mfst_seen; 3916 int r; 3917 3918 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3919 3920 /* 3921 * This should always be the service base on the code 3922 * path, and the fact that the manifests pg is a service 3923 * level property group only. 3924 */ 3925 ud_mfsts_pg = scf_pg_create(g_hndl); 3926 ud_prop = scf_property_create(g_hndl); 3927 ud_prop_iter = scf_iter_create(g_hndl); 3928 fname_value = scf_value_create(g_hndl); 3929 3930 /* Fetch the "manifests" property group */ 3931 no_upgrade_pg = 0; 3932 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3933 ud_mfsts_pg); 3934 if (r != 0) { 3935 switch (scf_error()) { 3936 case SCF_ERROR_NOT_FOUND: 3937 no_upgrade_pg = 1; 3938 break; 3939 3940 case SCF_ERROR_DELETED: 3941 case SCF_ERROR_CONNECTION_BROKEN: 3942 return (scferror2errno(scf_error())); 3943 3944 case SCF_ERROR_NOT_SET: 3945 case SCF_ERROR_INVALID_ARGUMENT: 3946 case SCF_ERROR_HANDLE_MISMATCH: 3947 case SCF_ERROR_NOT_BOUND: 3948 default: 3949 bad_error(running ? "scf_snaplevel_get_pg" : 3950 "entity_get_pg", scf_error()); 3951 } 3952 } 3953 3954 if (no_upgrade_pg) { 3955 cbdata.sc_handle = g_hndl; 3956 cbdata.sc_parent = ent; 3957 cbdata.sc_service = issvc; 3958 cbdata.sc_flags = SCI_FORCE; 3959 cbdata.sc_source_fmri = ient->sc_fmri; 3960 cbdata.sc_target_fmri = ient->sc_fmri; 3961 3962 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3963 return (cbdata.sc_err); 3964 3965 return (0); 3966 } 3967 3968 /* Fetch the new manifests property group */ 3969 mfst_pgroup = internal_pgroup_find_or_create(ient, 3970 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 3971 assert(mfst_pgroup != NULL); 3972 3973 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3974 SCF_SUCCESS) 3975 return (-1); 3976 3977 if ((pname = malloc(MAXPATHLEN)) == NULL) 3978 return (ENOMEM); 3979 if ((fval = malloc(MAXPATHLEN)) == NULL) { 3980 free(pname); 3981 return (ENOMEM); 3982 } 3983 3984 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 3985 mfst_seen = 0; 3986 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 3987 continue; 3988 3989 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3990 mfst_prop != NULL; 3991 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3992 mfst_prop)) { 3993 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3994 mfst_seen = 1; 3995 } 3996 } 3997 3998 /* 3999 * If the manifest is not seen then add it to the new mfst 4000 * property list to get proccessed into the repo. 4001 */ 4002 if (mfst_seen == 0) { 4003 /* 4004 * If we cannot get the value then there is no 4005 * reason to attempt to attach the value to 4006 * the property group 4007 */ 4008 if (prop_get_val(ud_prop, fname_value) == 0 && 4009 scf_value_get_astring(fname_value, fval, 4010 MAXPATHLEN) != -1) { 4011 old_pname = safe_strdup(pname); 4012 old_fval = safe_strdup(fval); 4013 old_prop = internal_property_create(old_pname, 4014 SCF_TYPE_ASTRING, 1, old_fval); 4015 4016 /* 4017 * Already checked to see if the property exists 4018 * in the group, and it does not. 4019 */ 4020 (void) internal_attach_property(mfst_pgroup, 4021 old_prop); 4022 } 4023 } 4024 } 4025 free(pname); 4026 free(fval); 4027 4028 cbdata.sc_handle = g_hndl; 4029 cbdata.sc_parent = ent; 4030 cbdata.sc_service = issvc; 4031 cbdata.sc_flags = SCI_FORCE; 4032 cbdata.sc_source_fmri = ient->sc_fmri; 4033 cbdata.sc_target_fmri = ient->sc_fmri; 4034 4035 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 4036 return (cbdata.sc_err); 4037 4038 return (r); 4039 } 4040 4041 /* 4042 * prop is taken to be a property in the "dependents" property group of snpl, 4043 * which is taken to be the snaplevel of a last-import snapshot corresponding 4044 * to ient. If prop is a valid dependents property, upgrade the dependent it 4045 * represents according to the repository & ient. If ud_run_dpts_pg_set is 4046 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 4047 * of the entity ient represents (possibly in the running snapshot). If it 4048 * needs to be changed, an entry will be added to tx, if not NULL. 4049 * 4050 * Returns 4051 * 0 - success 4052 * ECONNABORTED - repository connection broken 4053 * ENOMEM - out of memory 4054 * ENOSPC - configd was out of resources 4055 * ECANCELED - snpl's entity was deleted 4056 * EINVAL - dependent target is invalid (error printed) 4057 * - dependent is invalid (error printed) 4058 * EBADF - snpl is corrupt (error printed) 4059 * - snpl has corrupt pg (error printed) 4060 * - dependency pg in target is corrupt (error printed) 4061 * - running snapshot in dependent is missing snaplevel (error printed) 4062 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 4063 * - couldn't create dependent (permission denied) (error printed) 4064 * - couldn't modify dependent pg (permission denied) (error printed) 4065 * EROFS - couldn't delete dependency pg (repository read-only) 4066 * - couldn't create dependent (repository read-only) 4067 * EACCES - couldn't delete dependency pg (backend access denied) 4068 * - couldn't create dependent (backend access denied) 4069 * EBUSY - ud_run_dpts_pg was deleted (error printed) 4070 * - tx's pg was deleted (error printed) 4071 * - dependent pg was changed or deleted (error printed) 4072 * EEXIST - dependency pg already exists in new target (error printed) 4073 */ 4074 static int 4075 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 4076 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 4077 { 4078 pgroup_t pgrp; 4079 scf_type_t ty; 4080 pgroup_t *new_dpt_pgroup; 4081 pgroup_t *old_dpt_pgroup = NULL; 4082 pgroup_t *current_pg; 4083 pgroup_t *dpt; 4084 scf_callback_t cbdata; 4085 int tissvc; 4086 void *target_ent; 4087 scf_error_t serr; 4088 int r; 4089 scf_transaction_entry_t *ent; 4090 4091 const char * const cf_inval = gettext("Conflict upgrading %s " 4092 "(dependent \"%s\" has invalid dependents property).\n"); 4093 const char * const cf_missing = gettext("Conflict upgrading %s " 4094 "(dependent \"%s\" is missing).\n"); 4095 const char * const cf_newdpg = gettext("Conflict upgrading %s " 4096 "(dependent \"%s\" has new dependency property group).\n"); 4097 const char * const cf_newtarg = gettext("Conflict upgrading %s " 4098 "(dependent \"%s\" has new target).\n"); 4099 const char * const li_corrupt = 4100 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 4101 const char * const upgrading = 4102 gettext("%s: Upgrading dependent \"%s\".\n"); 4103 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 4104 "corrupt (missing snaplevel).\n"); 4105 4106 if (scf_property_type(prop, &ty) != 0) { 4107 switch (scf_error()) { 4108 case SCF_ERROR_DELETED: 4109 case SCF_ERROR_CONNECTION_BROKEN: 4110 return (scferror2errno(scf_error())); 4111 4112 case SCF_ERROR_NOT_BOUND: 4113 case SCF_ERROR_NOT_SET: 4114 default: 4115 bad_error("scf_property_type", scf_error()); 4116 } 4117 } 4118 4119 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4120 warn(li_corrupt, ient->sc_fmri); 4121 return (EBADF); 4122 } 4123 4124 /* 4125 * prop represents a dependent in the old manifest. It is named after 4126 * the dependent. 4127 */ 4128 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 4129 switch (scf_error()) { 4130 case SCF_ERROR_DELETED: 4131 case SCF_ERROR_CONNECTION_BROKEN: 4132 return (scferror2errno(scf_error())); 4133 4134 case SCF_ERROR_NOT_BOUND: 4135 case SCF_ERROR_NOT_SET: 4136 default: 4137 bad_error("scf_property_get_name", scf_error()); 4138 } 4139 } 4140 4141 /* See if it's in the new manifest. */ 4142 pgrp.sc_pgroup_name = ud_name; 4143 new_dpt_pgroup = 4144 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 4145 4146 /* If it's not, delete it... if it hasn't been customized. */ 4147 if (new_dpt_pgroup == NULL) { 4148 if (!ud_run_dpts_pg_set) 4149 return (0); 4150 4151 if (scf_property_get_value(prop, ud_val) != 0) { 4152 switch (scf_error()) { 4153 case SCF_ERROR_NOT_FOUND: 4154 case SCF_ERROR_CONSTRAINT_VIOLATED: 4155 warn(li_corrupt, ient->sc_fmri); 4156 return (EBADF); 4157 4158 case SCF_ERROR_DELETED: 4159 case SCF_ERROR_CONNECTION_BROKEN: 4160 return (scferror2errno(scf_error())); 4161 4162 case SCF_ERROR_HANDLE_MISMATCH: 4163 case SCF_ERROR_NOT_BOUND: 4164 case SCF_ERROR_NOT_SET: 4165 case SCF_ERROR_PERMISSION_DENIED: 4166 default: 4167 bad_error("scf_property_get_value", 4168 scf_error()); 4169 } 4170 } 4171 4172 if (scf_value_get_as_string(ud_val, ud_oldtarg, 4173 max_scf_value_len + 1) < 0) 4174 bad_error("scf_value_get_as_string", scf_error()); 4175 4176 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 4177 0) { 4178 switch (scf_error()) { 4179 case SCF_ERROR_NOT_FOUND: 4180 return (0); 4181 4182 case SCF_ERROR_CONNECTION_BROKEN: 4183 return (scferror2errno(scf_error())); 4184 4185 case SCF_ERROR_DELETED: 4186 warn(emsg_pg_deleted, ient->sc_fmri, 4187 "dependents"); 4188 return (EBUSY); 4189 4190 case SCF_ERROR_INVALID_ARGUMENT: 4191 case SCF_ERROR_NOT_BOUND: 4192 case SCF_ERROR_HANDLE_MISMATCH: 4193 case SCF_ERROR_NOT_SET: 4194 default: 4195 bad_error("scf_pg_get_property", scf_error()); 4196 } 4197 } 4198 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4199 switch (scf_error()) { 4200 case SCF_ERROR_NOT_FOUND: 4201 case SCF_ERROR_CONSTRAINT_VIOLATED: 4202 warn(cf_inval, ient->sc_fmri, ud_name); 4203 return (0); 4204 4205 case SCF_ERROR_DELETED: 4206 case SCF_ERROR_CONNECTION_BROKEN: 4207 return (scferror2errno(scf_error())); 4208 4209 case SCF_ERROR_HANDLE_MISMATCH: 4210 case SCF_ERROR_NOT_BOUND: 4211 case SCF_ERROR_NOT_SET: 4212 case SCF_ERROR_PERMISSION_DENIED: 4213 default: 4214 bad_error("scf_property_get_value", 4215 scf_error()); 4216 } 4217 } 4218 4219 ty = scf_value_type(ud_val); 4220 assert(ty != SCF_TYPE_INVALID); 4221 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4222 warn(cf_inval, ient->sc_fmri, ud_name); 4223 return (0); 4224 } 4225 4226 if (scf_value_get_as_string(ud_val, ud_ctarg, 4227 max_scf_value_len + 1) < 0) 4228 bad_error("scf_value_get_as_string", scf_error()); 4229 4230 r = fmri_equal(ud_ctarg, ud_oldtarg); 4231 switch (r) { 4232 case 1: 4233 break; 4234 4235 case 0: 4236 case -1: /* warn? */ 4237 warn(cf_newtarg, ient->sc_fmri, ud_name); 4238 return (0); 4239 4240 case -2: 4241 warn(li_corrupt, ient->sc_fmri); 4242 return (EBADF); 4243 4244 default: 4245 bad_error("fmri_equal", r); 4246 } 4247 4248 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4249 switch (scf_error()) { 4250 case SCF_ERROR_NOT_FOUND: 4251 warn(li_corrupt, ient->sc_fmri); 4252 return (EBADF); 4253 4254 case SCF_ERROR_DELETED: 4255 case SCF_ERROR_CONNECTION_BROKEN: 4256 return (scferror2errno(scf_error())); 4257 4258 case SCF_ERROR_NOT_BOUND: 4259 case SCF_ERROR_HANDLE_MISMATCH: 4260 case SCF_ERROR_INVALID_ARGUMENT: 4261 case SCF_ERROR_NOT_SET: 4262 default: 4263 bad_error("scf_snaplevel_get_pg", scf_error()); 4264 } 4265 } 4266 4267 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4268 snap_lastimport); 4269 switch (r) { 4270 case 0: 4271 break; 4272 4273 case ECANCELED: 4274 case ECONNABORTED: 4275 case ENOMEM: 4276 case EBADF: 4277 return (r); 4278 4279 case EACCES: 4280 default: 4281 bad_error("load_pg", r); 4282 } 4283 4284 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4285 switch (serr) { 4286 case SCF_ERROR_NONE: 4287 break; 4288 4289 case SCF_ERROR_NO_MEMORY: 4290 internal_pgroup_free(old_dpt_pgroup); 4291 return (ENOMEM); 4292 4293 case SCF_ERROR_NOT_FOUND: 4294 internal_pgroup_free(old_dpt_pgroup); 4295 goto delprop; 4296 4297 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 4298 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 4299 default: 4300 bad_error("fmri_to_entity", serr); 4301 } 4302 4303 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4304 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4305 switch (r) { 4306 case 0: 4307 break; 4308 4309 case ECONNABORTED: 4310 internal_pgroup_free(old_dpt_pgroup); 4311 return (r); 4312 4313 case ECANCELED: 4314 case ENOENT: 4315 internal_pgroup_free(old_dpt_pgroup); 4316 goto delprop; 4317 4318 case EBADF: 4319 warn(r_no_lvl, ud_ctarg); 4320 internal_pgroup_free(old_dpt_pgroup); 4321 return (r); 4322 4323 case EINVAL: 4324 default: 4325 bad_error("entity_get_running_pg", r); 4326 } 4327 4328 /* load it */ 4329 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4330 switch (r) { 4331 case 0: 4332 break; 4333 4334 case ECANCELED: 4335 internal_pgroup_free(old_dpt_pgroup); 4336 goto delprop; 4337 4338 case ECONNABORTED: 4339 case ENOMEM: 4340 case EBADF: 4341 internal_pgroup_free(old_dpt_pgroup); 4342 return (r); 4343 4344 case EACCES: 4345 default: 4346 bad_error("load_pg", r); 4347 } 4348 4349 /* compare property groups */ 4350 if (!pg_equal(old_dpt_pgroup, current_pg)) { 4351 warn(cf_newdpg, ient->sc_fmri, ud_name); 4352 internal_pgroup_free(old_dpt_pgroup); 4353 internal_pgroup_free(current_pg); 4354 return (0); 4355 } 4356 4357 internal_pgroup_free(old_dpt_pgroup); 4358 internal_pgroup_free(current_pg); 4359 4360 if (g_verbose) 4361 warn(gettext("%s: Deleting dependent \"%s\".\n"), 4362 ient->sc_fmri, ud_name); 4363 4364 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4365 switch (scf_error()) { 4366 case SCF_ERROR_NOT_FOUND: 4367 case SCF_ERROR_DELETED: 4368 internal_pgroup_free(old_dpt_pgroup); 4369 goto delprop; 4370 4371 case SCF_ERROR_CONNECTION_BROKEN: 4372 internal_pgroup_free(old_dpt_pgroup); 4373 return (ECONNABORTED); 4374 4375 case SCF_ERROR_NOT_SET: 4376 case SCF_ERROR_INVALID_ARGUMENT: 4377 case SCF_ERROR_HANDLE_MISMATCH: 4378 case SCF_ERROR_NOT_BOUND: 4379 default: 4380 bad_error("entity_get_pg", scf_error()); 4381 } 4382 } 4383 4384 if (scf_pg_delete(ud_pg) != 0) { 4385 switch (scf_error()) { 4386 case SCF_ERROR_DELETED: 4387 break; 4388 4389 case SCF_ERROR_CONNECTION_BROKEN: 4390 case SCF_ERROR_BACKEND_READONLY: 4391 case SCF_ERROR_BACKEND_ACCESS: 4392 return (scferror2errno(scf_error())); 4393 4394 case SCF_ERROR_PERMISSION_DENIED: 4395 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4396 return (scferror2errno(scf_error())); 4397 4398 case SCF_ERROR_NOT_SET: 4399 default: 4400 bad_error("scf_pg_delete", scf_error()); 4401 } 4402 } 4403 4404 /* 4405 * This service was changed, so it must be refreshed. But 4406 * since it's not mentioned in the new manifest, we have to 4407 * record its FMRI here for use later. We record the name 4408 * & the entity (via sc_parent) in case we need to print error 4409 * messages during the refresh. 4410 */ 4411 dpt = internal_pgroup_new(); 4412 if (dpt == NULL) 4413 return (ENOMEM); 4414 dpt->sc_pgroup_name = strdup(ud_name); 4415 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 4416 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4417 return (ENOMEM); 4418 dpt->sc_parent = (entity_t *)ient; 4419 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4420 uu_die(gettext("libuutil error: %s\n"), 4421 uu_strerror(uu_error())); 4422 4423 delprop: 4424 if (tx == NULL) 4425 return (0); 4426 4427 ent = scf_entry_create(g_hndl); 4428 if (ent == NULL) 4429 return (ENOMEM); 4430 4431 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 4432 scf_entry_destroy(ent); 4433 switch (scf_error()) { 4434 case SCF_ERROR_DELETED: 4435 warn(emsg_pg_deleted, ient->sc_fmri, 4436 "dependents"); 4437 return (EBUSY); 4438 4439 case SCF_ERROR_CONNECTION_BROKEN: 4440 return (scferror2errno(scf_error())); 4441 4442 case SCF_ERROR_NOT_FOUND: 4443 break; 4444 4445 case SCF_ERROR_HANDLE_MISMATCH: 4446 case SCF_ERROR_NOT_BOUND: 4447 case SCF_ERROR_INVALID_ARGUMENT: 4448 case SCF_ERROR_NOT_SET: 4449 default: 4450 bad_error("scf_transaction_property_delete", 4451 scf_error()); 4452 } 4453 } 4454 4455 return (0); 4456 } 4457 4458 new_dpt_pgroup->sc_pgroup_seen = 1; 4459 4460 /* 4461 * Decide whether the dependent has changed in the manifest. 4462 */ 4463 /* Compare the target. */ 4464 if (scf_property_get_value(prop, ud_val) != 0) { 4465 switch (scf_error()) { 4466 case SCF_ERROR_NOT_FOUND: 4467 case SCF_ERROR_CONSTRAINT_VIOLATED: 4468 warn(li_corrupt, ient->sc_fmri); 4469 return (EBADF); 4470 4471 case SCF_ERROR_DELETED: 4472 case SCF_ERROR_CONNECTION_BROKEN: 4473 return (scferror2errno(scf_error())); 4474 4475 case SCF_ERROR_HANDLE_MISMATCH: 4476 case SCF_ERROR_NOT_BOUND: 4477 case SCF_ERROR_NOT_SET: 4478 case SCF_ERROR_PERMISSION_DENIED: 4479 default: 4480 bad_error("scf_property_get_value", scf_error()); 4481 } 4482 } 4483 4484 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 4485 0) 4486 bad_error("scf_value_get_as_string", scf_error()); 4487 4488 /* 4489 * If the fmri's are not equal then the old fmri will need to 4490 * be refreshed to ensure that the changes are properly updated 4491 * in that service. 4492 */ 4493 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 4494 switch (r) { 4495 case 0: 4496 dpt = internal_pgroup_new(); 4497 if (dpt == NULL) 4498 return (ENOMEM); 4499 dpt->sc_pgroup_name = strdup(ud_name); 4500 dpt->sc_pgroup_fmri = strdup(ud_oldtarg); 4501 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4502 return (ENOMEM); 4503 dpt->sc_parent = (entity_t *)ient; 4504 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4505 uu_die(gettext("libuutil error: %s\n"), 4506 uu_strerror(uu_error())); 4507 break; 4508 4509 case 1: 4510 /* Compare the dependency pgs. */ 4511 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4512 switch (scf_error()) { 4513 case SCF_ERROR_NOT_FOUND: 4514 warn(li_corrupt, ient->sc_fmri); 4515 return (EBADF); 4516 4517 case SCF_ERROR_DELETED: 4518 case SCF_ERROR_CONNECTION_BROKEN: 4519 return (scferror2errno(scf_error())); 4520 4521 case SCF_ERROR_NOT_BOUND: 4522 case SCF_ERROR_HANDLE_MISMATCH: 4523 case SCF_ERROR_INVALID_ARGUMENT: 4524 case SCF_ERROR_NOT_SET: 4525 default: 4526 bad_error("scf_snaplevel_get_pg", scf_error()); 4527 } 4528 } 4529 4530 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4531 snap_lastimport); 4532 switch (r) { 4533 case 0: 4534 break; 4535 4536 case ECANCELED: 4537 case ECONNABORTED: 4538 case ENOMEM: 4539 case EBADF: 4540 return (r); 4541 4542 case EACCES: 4543 default: 4544 bad_error("load_pg", r); 4545 } 4546 4547 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4548 /* no change, leave customizations */ 4549 internal_pgroup_free(old_dpt_pgroup); 4550 return (0); 4551 } 4552 break; 4553 4554 case -1: 4555 warn(li_corrupt, ient->sc_fmri); 4556 return (EBADF); 4557 4558 case -2: 4559 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4560 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4561 return (EINVAL); 4562 4563 default: 4564 bad_error("fmri_equal", r); 4565 } 4566 4567 /* 4568 * The dependent has changed in the manifest. Upgrade the current 4569 * properties if they haven't been customized. 4570 */ 4571 4572 /* 4573 * If new_dpt_pgroup->sc_override, then act as though the property 4574 * group hasn't been customized. 4575 */ 4576 if (new_dpt_pgroup->sc_pgroup_override) { 4577 (void) strcpy(ud_ctarg, ud_oldtarg); 4578 goto nocust; 4579 } 4580 4581 if (!ud_run_dpts_pg_set) { 4582 warn(cf_missing, ient->sc_fmri, ud_name); 4583 r = 0; 4584 goto out; 4585 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4586 switch (scf_error()) { 4587 case SCF_ERROR_NOT_FOUND: 4588 warn(cf_missing, ient->sc_fmri, ud_name); 4589 r = 0; 4590 goto out; 4591 4592 case SCF_ERROR_CONNECTION_BROKEN: 4593 r = scferror2errno(scf_error()); 4594 goto out; 4595 4596 case SCF_ERROR_DELETED: 4597 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4598 r = EBUSY; 4599 goto out; 4600 4601 case SCF_ERROR_INVALID_ARGUMENT: 4602 case SCF_ERROR_NOT_BOUND: 4603 case SCF_ERROR_HANDLE_MISMATCH: 4604 case SCF_ERROR_NOT_SET: 4605 default: 4606 bad_error("scf_pg_get_property", scf_error()); 4607 } 4608 } 4609 4610 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4611 switch (scf_error()) { 4612 case SCF_ERROR_NOT_FOUND: 4613 case SCF_ERROR_CONSTRAINT_VIOLATED: 4614 warn(cf_inval, ient->sc_fmri, ud_name); 4615 r = 0; 4616 goto out; 4617 4618 case SCF_ERROR_DELETED: 4619 case SCF_ERROR_CONNECTION_BROKEN: 4620 r = scferror2errno(scf_error()); 4621 goto out; 4622 4623 case SCF_ERROR_HANDLE_MISMATCH: 4624 case SCF_ERROR_NOT_BOUND: 4625 case SCF_ERROR_NOT_SET: 4626 case SCF_ERROR_PERMISSION_DENIED: 4627 default: 4628 bad_error("scf_property_get_value", scf_error()); 4629 } 4630 } 4631 4632 ty = scf_value_type(ud_val); 4633 assert(ty != SCF_TYPE_INVALID); 4634 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4635 warn(cf_inval, ient->sc_fmri, ud_name); 4636 r = 0; 4637 goto out; 4638 } 4639 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4640 0) 4641 bad_error("scf_value_get_as_string", scf_error()); 4642 4643 r = fmri_equal(ud_ctarg, ud_oldtarg); 4644 if (r == -1) { 4645 warn(cf_inval, ient->sc_fmri, ud_name); 4646 r = 0; 4647 goto out; 4648 } else if (r == -2) { 4649 warn(li_corrupt, ient->sc_fmri); 4650 r = EBADF; 4651 goto out; 4652 } else if (r == 0) { 4653 /* 4654 * Target has been changed. Only abort now if it's been 4655 * changed to something other than what's in the manifest. 4656 */ 4657 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4658 if (r == -1) { 4659 warn(cf_inval, ient->sc_fmri, ud_name); 4660 r = 0; 4661 goto out; 4662 } else if (r == 0) { 4663 warn(cf_newtarg, ient->sc_fmri, ud_name); 4664 r = 0; 4665 goto out; 4666 } else if (r != 1) { 4667 /* invalid sc_pgroup_fmri caught above */ 4668 bad_error("fmri_equal", r); 4669 } 4670 4671 /* 4672 * Fetch the current dependency pg. If it's what the manifest 4673 * says, then no problem. 4674 */ 4675 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4676 switch (serr) { 4677 case SCF_ERROR_NONE: 4678 break; 4679 4680 case SCF_ERROR_NOT_FOUND: 4681 warn(cf_missing, ient->sc_fmri, ud_name); 4682 r = 0; 4683 goto out; 4684 4685 case SCF_ERROR_NO_MEMORY: 4686 r = ENOMEM; 4687 goto out; 4688 4689 case SCF_ERROR_CONSTRAINT_VIOLATED: 4690 case SCF_ERROR_INVALID_ARGUMENT: 4691 default: 4692 bad_error("fmri_to_entity", serr); 4693 } 4694 4695 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4696 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4697 switch (r) { 4698 case 0: 4699 break; 4700 4701 case ECONNABORTED: 4702 goto out; 4703 4704 case ECANCELED: 4705 case ENOENT: 4706 warn(cf_missing, ient->sc_fmri, ud_name); 4707 r = 0; 4708 goto out; 4709 4710 case EBADF: 4711 warn(r_no_lvl, ud_ctarg); 4712 goto out; 4713 4714 case EINVAL: 4715 default: 4716 bad_error("entity_get_running_pg", r); 4717 } 4718 4719 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4720 switch (r) { 4721 case 0: 4722 break; 4723 4724 case ECANCELED: 4725 warn(cf_missing, ient->sc_fmri, ud_name); 4726 r = 0; 4727 goto out; 4728 4729 case ECONNABORTED: 4730 case ENOMEM: 4731 case EBADF: 4732 goto out; 4733 4734 case EACCES: 4735 default: 4736 bad_error("load_pg", r); 4737 } 4738 4739 if (!pg_equal(current_pg, new_dpt_pgroup)) 4740 warn(cf_newdpg, ient->sc_fmri, ud_name); 4741 internal_pgroup_free(current_pg); 4742 r = 0; 4743 goto out; 4744 } else if (r != 1) { 4745 bad_error("fmri_equal", r); 4746 } 4747 4748 nocust: 4749 /* 4750 * Target has not been customized. Check the dependency property 4751 * group. 4752 */ 4753 4754 if (old_dpt_pgroup == NULL) { 4755 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4756 ud_pg) != 0) { 4757 switch (scf_error()) { 4758 case SCF_ERROR_NOT_FOUND: 4759 warn(li_corrupt, ient->sc_fmri); 4760 return (EBADF); 4761 4762 case SCF_ERROR_DELETED: 4763 case SCF_ERROR_CONNECTION_BROKEN: 4764 return (scferror2errno(scf_error())); 4765 4766 case SCF_ERROR_NOT_BOUND: 4767 case SCF_ERROR_HANDLE_MISMATCH: 4768 case SCF_ERROR_INVALID_ARGUMENT: 4769 case SCF_ERROR_NOT_SET: 4770 default: 4771 bad_error("scf_snaplevel_get_pg", scf_error()); 4772 } 4773 } 4774 4775 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4776 snap_lastimport); 4777 switch (r) { 4778 case 0: 4779 break; 4780 4781 case ECANCELED: 4782 case ECONNABORTED: 4783 case ENOMEM: 4784 case EBADF: 4785 return (r); 4786 4787 case EACCES: 4788 default: 4789 bad_error("load_pg", r); 4790 } 4791 } 4792 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4793 switch (serr) { 4794 case SCF_ERROR_NONE: 4795 break; 4796 4797 case SCF_ERROR_NOT_FOUND: 4798 warn(cf_missing, ient->sc_fmri, ud_name); 4799 r = 0; 4800 goto out; 4801 4802 case SCF_ERROR_NO_MEMORY: 4803 r = ENOMEM; 4804 goto out; 4805 4806 case SCF_ERROR_CONSTRAINT_VIOLATED: 4807 case SCF_ERROR_INVALID_ARGUMENT: 4808 default: 4809 bad_error("fmri_to_entity", serr); 4810 } 4811 4812 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4813 ud_iter2, ud_inst, imp_snap, ud_snpl); 4814 switch (r) { 4815 case 0: 4816 break; 4817 4818 case ECONNABORTED: 4819 goto out; 4820 4821 case ECANCELED: 4822 case ENOENT: 4823 warn(cf_missing, ient->sc_fmri, ud_name); 4824 r = 0; 4825 goto out; 4826 4827 case EBADF: 4828 warn(r_no_lvl, ud_ctarg); 4829 goto out; 4830 4831 case EINVAL: 4832 default: 4833 bad_error("entity_get_running_pg", r); 4834 } 4835 4836 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4837 switch (r) { 4838 case 0: 4839 break; 4840 4841 case ECANCELED: 4842 warn(cf_missing, ient->sc_fmri, ud_name); 4843 goto out; 4844 4845 case ECONNABORTED: 4846 case ENOMEM: 4847 case EBADF: 4848 goto out; 4849 4850 case EACCES: 4851 default: 4852 bad_error("load_pg", r); 4853 } 4854 4855 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4856 if (!pg_equal(current_pg, new_dpt_pgroup)) 4857 warn(cf_newdpg, ient->sc_fmri, ud_name); 4858 internal_pgroup_free(current_pg); 4859 r = 0; 4860 goto out; 4861 } 4862 4863 /* Uncustomized. Upgrade. */ 4864 4865 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4866 switch (r) { 4867 case 1: 4868 if (pg_equal(current_pg, new_dpt_pgroup)) { 4869 /* Already upgraded. */ 4870 internal_pgroup_free(current_pg); 4871 r = 0; 4872 goto out; 4873 } 4874 4875 internal_pgroup_free(current_pg); 4876 4877 /* upgrade current_pg */ 4878 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4879 switch (scf_error()) { 4880 case SCF_ERROR_CONNECTION_BROKEN: 4881 r = scferror2errno(scf_error()); 4882 goto out; 4883 4884 case SCF_ERROR_DELETED: 4885 warn(cf_missing, ient->sc_fmri, ud_name); 4886 r = 0; 4887 goto out; 4888 4889 case SCF_ERROR_NOT_FOUND: 4890 break; 4891 4892 case SCF_ERROR_INVALID_ARGUMENT: 4893 case SCF_ERROR_NOT_BOUND: 4894 case SCF_ERROR_NOT_SET: 4895 case SCF_ERROR_HANDLE_MISMATCH: 4896 default: 4897 bad_error("entity_get_pg", scf_error()); 4898 } 4899 4900 if (tissvc) 4901 r = scf_service_add_pg(target_ent, ud_name, 4902 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4903 else 4904 r = scf_instance_add_pg(target_ent, ud_name, 4905 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4906 if (r != 0) { 4907 switch (scf_error()) { 4908 case SCF_ERROR_CONNECTION_BROKEN: 4909 case SCF_ERROR_NO_RESOURCES: 4910 case SCF_ERROR_BACKEND_READONLY: 4911 case SCF_ERROR_BACKEND_ACCESS: 4912 r = scferror2errno(scf_error()); 4913 goto out; 4914 4915 case SCF_ERROR_DELETED: 4916 warn(cf_missing, ient->sc_fmri, 4917 ud_name); 4918 r = 0; 4919 goto out; 4920 4921 case SCF_ERROR_PERMISSION_DENIED: 4922 warn(emsg_pg_deleted, ud_ctarg, 4923 ud_name); 4924 r = EPERM; 4925 goto out; 4926 4927 case SCF_ERROR_EXISTS: 4928 warn(emsg_pg_added, ud_ctarg, ud_name); 4929 r = EBUSY; 4930 goto out; 4931 4932 case SCF_ERROR_NOT_BOUND: 4933 case SCF_ERROR_HANDLE_MISMATCH: 4934 case SCF_ERROR_INVALID_ARGUMENT: 4935 case SCF_ERROR_NOT_SET: 4936 default: 4937 bad_error("entity_add_pg", scf_error()); 4938 } 4939 } 4940 } 4941 4942 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4943 switch (r) { 4944 case 0: 4945 break; 4946 4947 case ECANCELED: 4948 warn(cf_missing, ient->sc_fmri, ud_name); 4949 goto out; 4950 4951 case ECONNABORTED: 4952 case ENOMEM: 4953 case EBADF: 4954 goto out; 4955 4956 case EACCES: 4957 default: 4958 bad_error("load_pg", r); 4959 } 4960 4961 if (g_verbose) 4962 warn(upgrading, ient->sc_fmri, ud_name); 4963 4964 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4965 new_dpt_pgroup, 0, ient->sc_fmri); 4966 switch (r) { 4967 case 0: 4968 break; 4969 4970 case ECANCELED: 4971 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4972 r = EBUSY; 4973 goto out; 4974 4975 case EPERM: 4976 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4977 goto out; 4978 4979 case EBUSY: 4980 warn(emsg_pg_changed, ud_ctarg, ud_name); 4981 goto out; 4982 4983 case ECONNABORTED: 4984 case ENOMEM: 4985 case ENOSPC: 4986 case EROFS: 4987 case EACCES: 4988 case EINVAL: 4989 goto out; 4990 4991 default: 4992 bad_error("upgrade_pg", r); 4993 } 4994 break; 4995 4996 case 0: { 4997 scf_transaction_entry_t *ent; 4998 scf_value_t *val; 4999 5000 internal_pgroup_free(current_pg); 5001 5002 /* delete old pg */ 5003 if (g_verbose) 5004 warn(upgrading, ient->sc_fmri, ud_name); 5005 5006 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 5007 switch (scf_error()) { 5008 case SCF_ERROR_CONNECTION_BROKEN: 5009 r = scferror2errno(scf_error()); 5010 goto out; 5011 5012 case SCF_ERROR_DELETED: 5013 warn(cf_missing, ient->sc_fmri, ud_name); 5014 r = 0; 5015 goto out; 5016 5017 case SCF_ERROR_NOT_FOUND: 5018 break; 5019 5020 case SCF_ERROR_INVALID_ARGUMENT: 5021 case SCF_ERROR_NOT_BOUND: 5022 case SCF_ERROR_NOT_SET: 5023 case SCF_ERROR_HANDLE_MISMATCH: 5024 default: 5025 bad_error("entity_get_pg", scf_error()); 5026 } 5027 } else if (scf_pg_delete(ud_pg) != 0) { 5028 switch (scf_error()) { 5029 case SCF_ERROR_DELETED: 5030 break; 5031 5032 case SCF_ERROR_CONNECTION_BROKEN: 5033 case SCF_ERROR_BACKEND_READONLY: 5034 case SCF_ERROR_BACKEND_ACCESS: 5035 r = scferror2errno(scf_error()); 5036 goto out; 5037 5038 case SCF_ERROR_PERMISSION_DENIED: 5039 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 5040 r = scferror2errno(scf_error()); 5041 goto out; 5042 5043 case SCF_ERROR_NOT_SET: 5044 default: 5045 bad_error("scf_pg_delete", scf_error()); 5046 } 5047 } 5048 5049 /* import new one */ 5050 cbdata.sc_handle = g_hndl; 5051 cbdata.sc_trans = NULL; /* handled below */ 5052 cbdata.sc_flags = 0; 5053 5054 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 5055 if (r != UU_WALK_NEXT) { 5056 if (r != UU_WALK_ERROR) 5057 bad_error("lscf_dependent_import", r); 5058 5059 r = cbdata.sc_err; 5060 goto out; 5061 } 5062 5063 if (tx == NULL) 5064 break; 5065 5066 if ((ent = scf_entry_create(g_hndl)) == NULL || 5067 (val = scf_value_create(g_hndl)) == NULL) { 5068 if (scf_error() == SCF_ERROR_NO_MEMORY) 5069 return (ENOMEM); 5070 5071 bad_error("scf_entry_create", scf_error()); 5072 } 5073 5074 if (scf_transaction_property_change_type(tx, ent, ud_name, 5075 SCF_TYPE_FMRI) != 0) { 5076 switch (scf_error()) { 5077 case SCF_ERROR_CONNECTION_BROKEN: 5078 r = scferror2errno(scf_error()); 5079 goto out; 5080 5081 case SCF_ERROR_DELETED: 5082 warn(emsg_pg_deleted, ient->sc_fmri, 5083 "dependents"); 5084 r = EBUSY; 5085 goto out; 5086 5087 case SCF_ERROR_NOT_FOUND: 5088 break; 5089 5090 case SCF_ERROR_NOT_BOUND: 5091 case SCF_ERROR_HANDLE_MISMATCH: 5092 case SCF_ERROR_INVALID_ARGUMENT: 5093 case SCF_ERROR_NOT_SET: 5094 default: 5095 bad_error("scf_transaction_property_" 5096 "change_type", scf_error()); 5097 } 5098 5099 if (scf_transaction_property_new(tx, ent, ud_name, 5100 SCF_TYPE_FMRI) != 0) { 5101 switch (scf_error()) { 5102 case SCF_ERROR_CONNECTION_BROKEN: 5103 r = scferror2errno(scf_error()); 5104 goto out; 5105 5106 case SCF_ERROR_DELETED: 5107 warn(emsg_pg_deleted, ient->sc_fmri, 5108 "dependents"); 5109 r = EBUSY; 5110 goto out; 5111 5112 case SCF_ERROR_EXISTS: 5113 warn(emsg_pg_changed, ient->sc_fmri, 5114 "dependents"); 5115 r = EBUSY; 5116 goto out; 5117 5118 case SCF_ERROR_INVALID_ARGUMENT: 5119 case SCF_ERROR_HANDLE_MISMATCH: 5120 case SCF_ERROR_NOT_BOUND: 5121 case SCF_ERROR_NOT_SET: 5122 default: 5123 bad_error("scf_transaction_property_" 5124 "new", scf_error()); 5125 } 5126 } 5127 } 5128 5129 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 5130 new_dpt_pgroup->sc_pgroup_fmri) != 0) 5131 /* invalid sc_pgroup_fmri caught above */ 5132 bad_error("scf_value_set_from_string", 5133 scf_error()); 5134 5135 if (scf_entry_add_value(ent, val) != 0) 5136 bad_error("scf_entry_add_value", scf_error()); 5137 break; 5138 } 5139 5140 case -2: 5141 warn(li_corrupt, ient->sc_fmri); 5142 internal_pgroup_free(current_pg); 5143 r = EBADF; 5144 goto out; 5145 5146 case -1: 5147 default: 5148 /* invalid sc_pgroup_fmri caught above */ 5149 bad_error("fmri_equal", r); 5150 } 5151 5152 r = 0; 5153 5154 out: 5155 if (old_dpt_pgroup != NULL) 5156 internal_pgroup_free(old_dpt_pgroup); 5157 5158 return (r); 5159 } 5160 5161 /* 5162 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 5163 * would import it, except it seems to exist in the service anyway. Compare 5164 * the existent dependent with the one we would import, and report any 5165 * differences (if there are none, be silent). prop is the property which 5166 * represents the existent dependent (in the dependents property group) in the 5167 * entity corresponding to ient. 5168 * 5169 * Returns 5170 * 0 - success (Sort of. At least, we can continue importing.) 5171 * ECONNABORTED - repository connection broken 5172 * EBUSY - ancestor of prop was deleted (error printed) 5173 * ENOMEM - out of memory 5174 * EBADF - corrupt property group (error printed) 5175 * EINVAL - new_dpt_pgroup has invalid target (error printed) 5176 */ 5177 static int 5178 handle_dependent_conflict(const entity_t * const ient, 5179 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 5180 { 5181 int r; 5182 scf_type_t ty; 5183 scf_error_t scfe; 5184 void *tptr; 5185 int tissvc; 5186 pgroup_t *pgroup; 5187 5188 if (scf_property_get_value(prop, ud_val) != 0) { 5189 switch (scf_error()) { 5190 case SCF_ERROR_CONNECTION_BROKEN: 5191 return (scferror2errno(scf_error())); 5192 5193 case SCF_ERROR_DELETED: 5194 warn(emsg_pg_deleted, ient->sc_fmri, 5195 new_dpt_pgroup->sc_pgroup_name); 5196 return (EBUSY); 5197 5198 case SCF_ERROR_CONSTRAINT_VIOLATED: 5199 case SCF_ERROR_NOT_FOUND: 5200 warn(gettext("Conflict upgrading %s (not importing " 5201 "dependent \"%s\" because it already exists.) " 5202 "Warning: The \"%s/%2$s\" property has more or " 5203 "fewer than one value)).\n"), ient->sc_fmri, 5204 new_dpt_pgroup->sc_pgroup_name, "dependents"); 5205 return (0); 5206 5207 case SCF_ERROR_HANDLE_MISMATCH: 5208 case SCF_ERROR_NOT_BOUND: 5209 case SCF_ERROR_NOT_SET: 5210 case SCF_ERROR_PERMISSION_DENIED: 5211 default: 5212 bad_error("scf_property_get_value", 5213 scf_error()); 5214 } 5215 } 5216 5217 ty = scf_value_type(ud_val); 5218 assert(ty != SCF_TYPE_INVALID); 5219 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 5220 warn(gettext("Conflict upgrading %s (not importing dependent " 5221 "\"%s\" because it already exists). Warning: The " 5222 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 5223 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 5224 scf_type_to_string(ty), "dependents"); 5225 return (0); 5226 } 5227 5228 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 5229 0) 5230 bad_error("scf_value_get_as_string", scf_error()); 5231 5232 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 5233 switch (r) { 5234 case 0: 5235 warn(gettext("Conflict upgrading %s (not importing dependent " 5236 "\"%s\" (target \"%s\") because it already exists with " 5237 "target \"%s\").\n"), ient->sc_fmri, 5238 new_dpt_pgroup->sc_pgroup_name, 5239 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 5240 return (0); 5241 5242 case 1: 5243 break; 5244 5245 case -1: 5246 warn(gettext("Conflict upgrading %s (not importing dependent " 5247 "\"%s\" because it already exists). Warning: The current " 5248 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 5249 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5250 return (0); 5251 5252 case -2: 5253 warn(gettext("Dependent \"%s\" of %s has invalid target " 5254 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 5255 new_dpt_pgroup->sc_pgroup_fmri); 5256 return (EINVAL); 5257 5258 default: 5259 bad_error("fmri_equal", r); 5260 } 5261 5262 /* compare dependency pgs in target */ 5263 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 5264 switch (scfe) { 5265 case SCF_ERROR_NONE: 5266 break; 5267 5268 case SCF_ERROR_NO_MEMORY: 5269 return (ENOMEM); 5270 5271 case SCF_ERROR_NOT_FOUND: 5272 warn(emsg_dpt_dangling, ient->sc_fmri, 5273 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5274 return (0); 5275 5276 case SCF_ERROR_CONSTRAINT_VIOLATED: 5277 case SCF_ERROR_INVALID_ARGUMENT: 5278 default: 5279 bad_error("fmri_to_entity", scfe); 5280 } 5281 5282 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 5283 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 5284 switch (r) { 5285 case 0: 5286 break; 5287 5288 case ECONNABORTED: 5289 return (r); 5290 5291 case ECANCELED: 5292 warn(emsg_dpt_dangling, ient->sc_fmri, 5293 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5294 return (0); 5295 5296 case EBADF: 5297 if (tissvc) 5298 warn(gettext("%s has an instance with a \"%s\" " 5299 "snapshot which is missing a snaplevel.\n"), 5300 ud_ctarg, "running"); 5301 else 5302 warn(gettext("%s has a \"%s\" snapshot which is " 5303 "missing a snaplevel.\n"), ud_ctarg, "running"); 5304 /* FALLTHROUGH */ 5305 5306 case ENOENT: 5307 warn(emsg_dpt_no_dep, ient->sc_fmri, 5308 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5309 new_dpt_pgroup->sc_pgroup_name); 5310 return (0); 5311 5312 case EINVAL: 5313 default: 5314 bad_error("entity_get_running_pg", r); 5315 } 5316 5317 pgroup = internal_pgroup_new(); 5318 if (pgroup == NULL) 5319 return (ENOMEM); 5320 5321 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 5322 switch (r) { 5323 case 0: 5324 break; 5325 5326 case ECONNABORTED: 5327 case EBADF: 5328 case ENOMEM: 5329 internal_pgroup_free(pgroup); 5330 return (r); 5331 5332 case ECANCELED: 5333 warn(emsg_dpt_no_dep, ient->sc_fmri, 5334 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5335 new_dpt_pgroup->sc_pgroup_name); 5336 internal_pgroup_free(pgroup); 5337 return (0); 5338 5339 case EACCES: 5340 default: 5341 bad_error("load_pg", r); 5342 } 5343 5344 /* report differences */ 5345 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 5346 internal_pgroup_free(pgroup); 5347 return (0); 5348 } 5349 5350 /* 5351 * lipg is a property group in the last-import snapshot of ent, which is an 5352 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 5353 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 5354 * in ents's property groups, compare and upgrade ent appropriately. 5355 * 5356 * Returns 5357 * 0 - success 5358 * ECONNABORTED - repository connection broken 5359 * ENOMEM - out of memory 5360 * ENOSPC - configd is out of resources 5361 * EINVAL - ient has invalid dependent (error printed) 5362 * - ient has invalid pgroup_t (error printed) 5363 * ECANCELED - ent has been deleted 5364 * ENODEV - entity containing lipg has been deleted 5365 * - entity containing running has been deleted 5366 * EPERM - could not delete pg (permission denied) (error printed) 5367 * - couldn't upgrade dependents (permission denied) (error printed) 5368 * - couldn't import pg (permission denied) (error printed) 5369 * - couldn't upgrade pg (permission denied) (error printed) 5370 * EROFS - could not delete pg (repository read-only) 5371 * - couldn't upgrade dependents (repository read-only) 5372 * - couldn't import pg (repository read-only) 5373 * - couldn't upgrade pg (repository read-only) 5374 * EACCES - could not delete pg (backend access denied) 5375 * - couldn't upgrade dependents (backend access denied) 5376 * - couldn't import pg (backend access denied) 5377 * - couldn't upgrade pg (backend access denied) 5378 * - couldn't read property (backend access denied) 5379 * EBUSY - property group was added (error printed) 5380 * - property group was deleted (error printed) 5381 * - property group changed (error printed) 5382 * - "dependents" pg was added, changed, or deleted (error printed) 5383 * - dependent target deleted (error printed) 5384 * - dependent pg changed (error printed) 5385 * EBADF - imp_snpl is corrupt (error printed) 5386 * - ent has bad pg (error printed) 5387 * EEXIST - dependent collision in target service (error printed) 5388 */ 5389 static int 5390 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 5391 const scf_snaplevel_t *running) 5392 { 5393 int r; 5394 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 5395 scf_callback_t cbdata; 5396 5397 const char * const cf_pg_missing = 5398 gettext("Conflict upgrading %s (property group %s is missing)\n"); 5399 const char * const deleting = 5400 gettext("%s: Deleting property group \"%s\".\n"); 5401 5402 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5403 5404 /* Skip dependent property groups. */ 5405 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 5406 switch (scf_error()) { 5407 case SCF_ERROR_DELETED: 5408 return (ENODEV); 5409 5410 case SCF_ERROR_CONNECTION_BROKEN: 5411 return (ECONNABORTED); 5412 5413 case SCF_ERROR_NOT_SET: 5414 case SCF_ERROR_NOT_BOUND: 5415 default: 5416 bad_error("scf_pg_get_type", scf_error()); 5417 } 5418 } 5419 5420 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 5421 if (scf_pg_get_property(lipg, "external", NULL) == 0) 5422 return (0); 5423 5424 switch (scf_error()) { 5425 case SCF_ERROR_NOT_FOUND: 5426 break; 5427 5428 case SCF_ERROR_CONNECTION_BROKEN: 5429 return (ECONNABORTED); 5430 5431 case SCF_ERROR_DELETED: 5432 return (ENODEV); 5433 5434 case SCF_ERROR_INVALID_ARGUMENT: 5435 case SCF_ERROR_NOT_BOUND: 5436 case SCF_ERROR_HANDLE_MISMATCH: 5437 case SCF_ERROR_NOT_SET: 5438 default: 5439 bad_error("scf_pg_get_property", scf_error()); 5440 } 5441 } 5442 5443 /* lookup pg in new properties */ 5444 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 5445 switch (scf_error()) { 5446 case SCF_ERROR_DELETED: 5447 return (ENODEV); 5448 5449 case SCF_ERROR_CONNECTION_BROKEN: 5450 return (ECONNABORTED); 5451 5452 case SCF_ERROR_NOT_SET: 5453 case SCF_ERROR_NOT_BOUND: 5454 default: 5455 bad_error("scf_pg_get_name", scf_error()); 5456 } 5457 } 5458 5459 pgrp.sc_pgroup_name = imp_str; 5460 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 5461 5462 if (mpg != NULL) 5463 mpg->sc_pgroup_seen = 1; 5464 5465 /* Special handling for dependents */ 5466 if (strcmp(imp_str, "dependents") == 0) 5467 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 5468 5469 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 5470 return (upgrade_manifestfiles(NULL, ient, running, ent)); 5471 5472 if (mpg == NULL || mpg->sc_pgroup_delete) { 5473 /* property group was deleted from manifest */ 5474 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5475 switch (scf_error()) { 5476 case SCF_ERROR_NOT_FOUND: 5477 return (0); 5478 5479 case SCF_ERROR_DELETED: 5480 case SCF_ERROR_CONNECTION_BROKEN: 5481 return (scferror2errno(scf_error())); 5482 5483 case SCF_ERROR_INVALID_ARGUMENT: 5484 case SCF_ERROR_HANDLE_MISMATCH: 5485 case SCF_ERROR_NOT_BOUND: 5486 case SCF_ERROR_NOT_SET: 5487 default: 5488 bad_error("entity_get_pg", scf_error()); 5489 } 5490 } 5491 5492 if (mpg != NULL && mpg->sc_pgroup_delete) { 5493 if (g_verbose) 5494 warn(deleting, ient->sc_fmri, imp_str); 5495 if (scf_pg_delete(imp_pg2) == 0) 5496 return (0); 5497 5498 switch (scf_error()) { 5499 case SCF_ERROR_DELETED: 5500 return (0); 5501 5502 case SCF_ERROR_CONNECTION_BROKEN: 5503 case SCF_ERROR_BACKEND_READONLY: 5504 case SCF_ERROR_BACKEND_ACCESS: 5505 return (scferror2errno(scf_error())); 5506 5507 case SCF_ERROR_PERMISSION_DENIED: 5508 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 5509 return (scferror2errno(scf_error())); 5510 5511 case SCF_ERROR_NOT_SET: 5512 default: 5513 bad_error("scf_pg_delete", scf_error()); 5514 } 5515 } 5516 5517 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5518 switch (r) { 5519 case 0: 5520 break; 5521 5522 case ECANCELED: 5523 return (ENODEV); 5524 5525 case ECONNABORTED: 5526 case ENOMEM: 5527 case EBADF: 5528 case EACCES: 5529 return (r); 5530 5531 default: 5532 bad_error("load_pg", r); 5533 } 5534 5535 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5536 switch (r) { 5537 case 0: 5538 break; 5539 5540 case ECANCELED: 5541 case ECONNABORTED: 5542 case ENOMEM: 5543 case EBADF: 5544 case EACCES: 5545 internal_pgroup_free(lipg_i); 5546 return (r); 5547 5548 default: 5549 bad_error("load_pg", r); 5550 } 5551 5552 if (pg_equal(lipg_i, curpg_i)) { 5553 if (g_verbose) 5554 warn(deleting, ient->sc_fmri, imp_str); 5555 if (scf_pg_delete(imp_pg2) != 0) { 5556 switch (scf_error()) { 5557 case SCF_ERROR_DELETED: 5558 break; 5559 5560 case SCF_ERROR_CONNECTION_BROKEN: 5561 internal_pgroup_free(lipg_i); 5562 internal_pgroup_free(curpg_i); 5563 return (ECONNABORTED); 5564 5565 case SCF_ERROR_NOT_SET: 5566 case SCF_ERROR_NOT_BOUND: 5567 default: 5568 bad_error("scf_pg_delete", scf_error()); 5569 } 5570 } 5571 } else { 5572 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5573 } 5574 5575 internal_pgroup_free(lipg_i); 5576 internal_pgroup_free(curpg_i); 5577 5578 return (0); 5579 } 5580 5581 /* 5582 * Only dependent pgs can have override set, and we skipped those 5583 * above. 5584 */ 5585 assert(!mpg->sc_pgroup_override); 5586 5587 /* compare */ 5588 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5589 switch (r) { 5590 case 0: 5591 break; 5592 5593 case ECANCELED: 5594 return (ENODEV); 5595 5596 case ECONNABORTED: 5597 case EBADF: 5598 case ENOMEM: 5599 case EACCES: 5600 return (r); 5601 5602 default: 5603 bad_error("load_pg", r); 5604 } 5605 5606 if (pg_equal(mpg, lipg_i)) { 5607 /* The manifest pg has not changed. Move on. */ 5608 r = 0; 5609 goto out; 5610 } 5611 5612 /* upgrade current properties according to lipg & mpg */ 5613 if (running != NULL) 5614 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5615 else 5616 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5617 if (r != 0) { 5618 switch (scf_error()) { 5619 case SCF_ERROR_CONNECTION_BROKEN: 5620 r = scferror2errno(scf_error()); 5621 goto out; 5622 5623 case SCF_ERROR_DELETED: 5624 if (running != NULL) 5625 r = ENODEV; 5626 else 5627 r = ECANCELED; 5628 goto out; 5629 5630 case SCF_ERROR_NOT_FOUND: 5631 break; 5632 5633 case SCF_ERROR_INVALID_ARGUMENT: 5634 case SCF_ERROR_HANDLE_MISMATCH: 5635 case SCF_ERROR_NOT_BOUND: 5636 case SCF_ERROR_NOT_SET: 5637 default: 5638 bad_error("entity_get_pg", scf_error()); 5639 } 5640 5641 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5642 5643 r = 0; 5644 goto out; 5645 } 5646 5647 r = load_pg_attrs(imp_pg2, &curpg_i); 5648 switch (r) { 5649 case 0: 5650 break; 5651 5652 case ECANCELED: 5653 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5654 r = 0; 5655 goto out; 5656 5657 case ECONNABORTED: 5658 case ENOMEM: 5659 goto out; 5660 5661 default: 5662 bad_error("load_pg_attrs", r); 5663 } 5664 5665 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5666 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5667 internal_pgroup_free(curpg_i); 5668 r = 0; 5669 goto out; 5670 } 5671 5672 internal_pgroup_free(curpg_i); 5673 5674 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5675 switch (r) { 5676 case 0: 5677 break; 5678 5679 case ECANCELED: 5680 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5681 r = 0; 5682 goto out; 5683 5684 case ECONNABORTED: 5685 case EBADF: 5686 case ENOMEM: 5687 case EACCES: 5688 goto out; 5689 5690 default: 5691 bad_error("load_pg", r); 5692 } 5693 5694 if (pg_equal(lipg_i, curpg_i) && 5695 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5696 int do_delete = 1; 5697 5698 if (g_verbose) 5699 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5700 ient->sc_fmri, mpg->sc_pgroup_name); 5701 5702 internal_pgroup_free(curpg_i); 5703 5704 if (running != NULL && 5705 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5706 switch (scf_error()) { 5707 case SCF_ERROR_DELETED: 5708 r = ECANCELED; 5709 goto out; 5710 5711 case SCF_ERROR_NOT_FOUND: 5712 do_delete = 0; 5713 break; 5714 5715 case SCF_ERROR_CONNECTION_BROKEN: 5716 r = scferror2errno(scf_error()); 5717 goto out; 5718 5719 case SCF_ERROR_HANDLE_MISMATCH: 5720 case SCF_ERROR_INVALID_ARGUMENT: 5721 case SCF_ERROR_NOT_SET: 5722 case SCF_ERROR_NOT_BOUND: 5723 default: 5724 bad_error("entity_get_pg", scf_error()); 5725 } 5726 } 5727 5728 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5729 switch (scf_error()) { 5730 case SCF_ERROR_DELETED: 5731 break; 5732 5733 case SCF_ERROR_CONNECTION_BROKEN: 5734 case SCF_ERROR_BACKEND_READONLY: 5735 case SCF_ERROR_BACKEND_ACCESS: 5736 r = scferror2errno(scf_error()); 5737 goto out; 5738 5739 case SCF_ERROR_PERMISSION_DENIED: 5740 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5741 ient->sc_fmri); 5742 r = scferror2errno(scf_error()); 5743 goto out; 5744 5745 case SCF_ERROR_NOT_SET: 5746 case SCF_ERROR_NOT_BOUND: 5747 default: 5748 bad_error("scf_pg_delete", scf_error()); 5749 } 5750 } 5751 5752 cbdata.sc_handle = g_hndl; 5753 cbdata.sc_parent = ent; 5754 cbdata.sc_service = issvc; 5755 cbdata.sc_flags = 0; 5756 cbdata.sc_source_fmri = ient->sc_fmri; 5757 cbdata.sc_target_fmri = ient->sc_fmri; 5758 5759 r = entity_pgroup_import(mpg, &cbdata); 5760 switch (r) { 5761 case UU_WALK_NEXT: 5762 r = 0; 5763 goto out; 5764 5765 case UU_WALK_ERROR: 5766 if (cbdata.sc_err == EEXIST) { 5767 warn(emsg_pg_added, ient->sc_fmri, 5768 mpg->sc_pgroup_name); 5769 r = EBUSY; 5770 } else { 5771 r = cbdata.sc_err; 5772 } 5773 goto out; 5774 5775 default: 5776 bad_error("entity_pgroup_import", r); 5777 } 5778 } 5779 5780 if (running != NULL && 5781 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5782 switch (scf_error()) { 5783 case SCF_ERROR_CONNECTION_BROKEN: 5784 case SCF_ERROR_DELETED: 5785 r = scferror2errno(scf_error()); 5786 goto out; 5787 5788 case SCF_ERROR_NOT_FOUND: 5789 break; 5790 5791 case SCF_ERROR_HANDLE_MISMATCH: 5792 case SCF_ERROR_INVALID_ARGUMENT: 5793 case SCF_ERROR_NOT_SET: 5794 case SCF_ERROR_NOT_BOUND: 5795 default: 5796 bad_error("entity_get_pg", scf_error()); 5797 } 5798 5799 cbdata.sc_handle = g_hndl; 5800 cbdata.sc_parent = ent; 5801 cbdata.sc_service = issvc; 5802 cbdata.sc_flags = SCI_FORCE; 5803 cbdata.sc_source_fmri = ient->sc_fmri; 5804 cbdata.sc_target_fmri = ient->sc_fmri; 5805 5806 r = entity_pgroup_import(mpg, &cbdata); 5807 switch (r) { 5808 case UU_WALK_NEXT: 5809 r = 0; 5810 goto out; 5811 5812 case UU_WALK_ERROR: 5813 if (cbdata.sc_err == EEXIST) { 5814 warn(emsg_pg_added, ient->sc_fmri, 5815 mpg->sc_pgroup_name); 5816 r = EBUSY; 5817 } else { 5818 r = cbdata.sc_err; 5819 } 5820 goto out; 5821 5822 default: 5823 bad_error("entity_pgroup_import", r); 5824 } 5825 } 5826 5827 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5828 internal_pgroup_free(curpg_i); 5829 switch (r) { 5830 case 0: 5831 ient->sc_import_state = IMPORT_PROP_BEGUN; 5832 break; 5833 5834 case ECANCELED: 5835 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5836 r = EBUSY; 5837 break; 5838 5839 case EPERM: 5840 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5841 break; 5842 5843 case EBUSY: 5844 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5845 break; 5846 5847 case ECONNABORTED: 5848 case ENOMEM: 5849 case ENOSPC: 5850 case EROFS: 5851 case EACCES: 5852 case EINVAL: 5853 break; 5854 5855 default: 5856 bad_error("upgrade_pg", r); 5857 } 5858 5859 out: 5860 internal_pgroup_free(lipg_i); 5861 return (r); 5862 } 5863 5864 /* 5865 * Upgrade the properties of ent according to snpl & ient. 5866 * 5867 * Returns 5868 * 0 - success 5869 * ECONNABORTED - repository connection broken 5870 * ENOMEM - out of memory 5871 * ENOSPC - configd is out of resources 5872 * ECANCELED - ent was deleted 5873 * ENODEV - entity containing snpl was deleted 5874 * - entity containing running was deleted 5875 * EBADF - imp_snpl is corrupt (error printed) 5876 * - ent has corrupt pg (error printed) 5877 * - dependent has corrupt pg (error printed) 5878 * - dependent target has a corrupt snapshot (error printed) 5879 * EBUSY - pg was added, changed, or deleted (error printed) 5880 * - dependent target was deleted (error printed) 5881 * - dependent pg changed (error printed) 5882 * EINVAL - invalid property group name (error printed) 5883 * - invalid property name (error printed) 5884 * - invalid value (error printed) 5885 * - ient has invalid pgroup or dependent (error printed) 5886 * EPERM - could not create property group (permission denied) (error printed) 5887 * - could not modify property group (permission denied) (error printed) 5888 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5889 * EROFS - could not create property group (repository read-only) 5890 * - couldn't delete, upgrade, or import pg or dependent 5891 * EACCES - could not create property group (backend access denied) 5892 * - couldn't delete, upgrade, or import pg or dependent 5893 * EEXIST - dependent collision in target service (error printed) 5894 */ 5895 static int 5896 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5897 entity_t *ient) 5898 { 5899 pgroup_t *pg, *rpg; 5900 int r; 5901 uu_list_t *pgs = ient->sc_pgroups; 5902 5903 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5904 5905 /* clear sc_sceen for pgs */ 5906 if (uu_list_walk(pgs, clear_int, 5907 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5908 bad_error("uu_list_walk", uu_error()); 5909 5910 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5911 switch (scf_error()) { 5912 case SCF_ERROR_DELETED: 5913 return (ENODEV); 5914 5915 case SCF_ERROR_CONNECTION_BROKEN: 5916 return (ECONNABORTED); 5917 5918 case SCF_ERROR_NOT_SET: 5919 case SCF_ERROR_NOT_BOUND: 5920 case SCF_ERROR_HANDLE_MISMATCH: 5921 default: 5922 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5923 } 5924 } 5925 5926 for (;;) { 5927 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5928 if (r == 0) 5929 break; 5930 if (r == 1) { 5931 r = process_old_pg(imp_pg, ient, ent, running); 5932 switch (r) { 5933 case 0: 5934 break; 5935 5936 case ECONNABORTED: 5937 case ENOMEM: 5938 case ENOSPC: 5939 case ECANCELED: 5940 case ENODEV: 5941 case EPERM: 5942 case EROFS: 5943 case EACCES: 5944 case EBADF: 5945 case EBUSY: 5946 case EINVAL: 5947 case EEXIST: 5948 return (r); 5949 5950 default: 5951 bad_error("process_old_pg", r); 5952 } 5953 continue; 5954 } 5955 if (r != -1) 5956 bad_error("scf_iter_next_pg", r); 5957 5958 switch (scf_error()) { 5959 case SCF_ERROR_DELETED: 5960 return (ENODEV); 5961 5962 case SCF_ERROR_CONNECTION_BROKEN: 5963 return (ECONNABORTED); 5964 5965 case SCF_ERROR_HANDLE_MISMATCH: 5966 case SCF_ERROR_NOT_BOUND: 5967 case SCF_ERROR_NOT_SET: 5968 case SCF_ERROR_INVALID_ARGUMENT: 5969 default: 5970 bad_error("scf_iter_next_pg", scf_error()); 5971 } 5972 } 5973 5974 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5975 if (pg->sc_pgroup_seen) 5976 continue; 5977 5978 /* pg is new */ 5979 5980 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5981 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5982 ent); 5983 switch (r) { 5984 case 0: 5985 break; 5986 5987 case ECONNABORTED: 5988 case ENOMEM: 5989 case ENOSPC: 5990 case ECANCELED: 5991 case ENODEV: 5992 case EBADF: 5993 case EBUSY: 5994 case EINVAL: 5995 case EPERM: 5996 case EROFS: 5997 case EACCES: 5998 case EEXIST: 5999 return (r); 6000 6001 default: 6002 bad_error("upgrade_dependents", r); 6003 } 6004 continue; 6005 } 6006 6007 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 6008 r = upgrade_manifestfiles(pg, ient, running, ent); 6009 switch (r) { 6010 case 0: 6011 break; 6012 6013 case ECONNABORTED: 6014 case ENOMEM: 6015 case ENOSPC: 6016 case ECANCELED: 6017 case ENODEV: 6018 case EBADF: 6019 case EBUSY: 6020 case EINVAL: 6021 case EPERM: 6022 case EROFS: 6023 case EACCES: 6024 case EEXIST: 6025 return (r); 6026 6027 default: 6028 bad_error("upgrade_manifestfiles", r); 6029 } 6030 continue; 6031 } 6032 6033 if (running != NULL) { 6034 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 6035 imp_pg); 6036 } else { 6037 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 6038 imp_pg); 6039 } 6040 if (r != 0) { 6041 scf_callback_t cbdata; 6042 6043 switch (scf_error()) { 6044 case SCF_ERROR_NOT_FOUND: 6045 break; 6046 6047 case SCF_ERROR_CONNECTION_BROKEN: 6048 return (scferror2errno(scf_error())); 6049 6050 case SCF_ERROR_DELETED: 6051 if (running != NULL) 6052 return (ENODEV); 6053 else 6054 return (scferror2errno(scf_error())); 6055 6056 case SCF_ERROR_INVALID_ARGUMENT: 6057 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 6058 pg->sc_pgroup_name); 6059 return (EINVAL); 6060 6061 case SCF_ERROR_NOT_SET: 6062 case SCF_ERROR_HANDLE_MISMATCH: 6063 case SCF_ERROR_NOT_BOUND: 6064 default: 6065 bad_error("entity_get_pg", scf_error()); 6066 } 6067 6068 /* User doesn't have pg, so import it. */ 6069 6070 cbdata.sc_handle = g_hndl; 6071 cbdata.sc_parent = ent; 6072 cbdata.sc_service = issvc; 6073 cbdata.sc_flags = SCI_FORCE; 6074 cbdata.sc_source_fmri = ient->sc_fmri; 6075 cbdata.sc_target_fmri = ient->sc_fmri; 6076 6077 r = entity_pgroup_import(pg, &cbdata); 6078 switch (r) { 6079 case UU_WALK_NEXT: 6080 ient->sc_import_state = IMPORT_PROP_BEGUN; 6081 continue; 6082 6083 case UU_WALK_ERROR: 6084 if (cbdata.sc_err == EEXIST) { 6085 warn(emsg_pg_added, ient->sc_fmri, 6086 pg->sc_pgroup_name); 6087 return (EBUSY); 6088 } 6089 return (cbdata.sc_err); 6090 6091 default: 6092 bad_error("entity_pgroup_import", r); 6093 } 6094 } 6095 6096 /* report differences between pg & current */ 6097 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 6098 switch (r) { 6099 case 0: 6100 break; 6101 6102 case ECANCELED: 6103 warn(emsg_pg_deleted, ient->sc_fmri, 6104 pg->sc_pgroup_name); 6105 return (EBUSY); 6106 6107 case ECONNABORTED: 6108 case EBADF: 6109 case ENOMEM: 6110 case EACCES: 6111 return (r); 6112 6113 default: 6114 bad_error("load_pg", r); 6115 } 6116 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 6117 internal_pgroup_free(rpg); 6118 rpg = NULL; 6119 } 6120 6121 return (0); 6122 } 6123 6124 /* 6125 * Import an instance. If it doesn't exist, create it. If it has 6126 * a last-import snapshot, upgrade its properties. Finish by updating its 6127 * last-import snapshot. If it doesn't have a last-import snapshot then it 6128 * could have been created for a dependent tag in another manifest. Import the 6129 * new properties. If there's a conflict, don't override, like now? 6130 * 6131 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 6132 * lcbdata->sc_err to 6133 * ECONNABORTED - repository connection broken 6134 * ENOMEM - out of memory 6135 * ENOSPC - svc.configd is out of resources 6136 * EEXIST - dependency collision in dependent service (error printed) 6137 * EPERM - couldn't create temporary instance (permission denied) 6138 * - couldn't import into temporary instance (permission denied) 6139 * - couldn't take snapshot (permission denied) 6140 * - couldn't upgrade properties (permission denied) 6141 * - couldn't import properties (permission denied) 6142 * - couldn't import dependents (permission denied) 6143 * EROFS - couldn't create temporary instance (repository read-only) 6144 * - couldn't import into temporary instance (repository read-only) 6145 * - couldn't upgrade properties (repository read-only) 6146 * - couldn't import properties (repository read-only) 6147 * - couldn't import dependents (repository read-only) 6148 * EACCES - couldn't create temporary instance (backend access denied) 6149 * - couldn't import into temporary instance (backend access denied) 6150 * - couldn't upgrade properties (backend access denied) 6151 * - couldn't import properties (backend access denied) 6152 * - couldn't import dependents (backend access denied) 6153 * EINVAL - invalid instance name (error printed) 6154 * - invalid pgroup_t's (error printed) 6155 * - invalid dependents (error printed) 6156 * EBUSY - temporary service deleted (error printed) 6157 * - temporary instance deleted (error printed) 6158 * - temporary instance changed (error printed) 6159 * - temporary instance already exists (error printed) 6160 * - instance deleted (error printed) 6161 * EBADF - instance has corrupt last-import snapshot (error printed) 6162 * - instance is corrupt (error printed) 6163 * - dependent has corrupt pg (error printed) 6164 * - dependent target has a corrupt snapshot (error printed) 6165 * -1 - unknown libscf error (error printed) 6166 */ 6167 static int 6168 lscf_instance_import(void *v, void *pvt) 6169 { 6170 entity_t *inst = v; 6171 scf_callback_t ctx; 6172 scf_callback_t *lcbdata = pvt; 6173 scf_service_t *rsvc = lcbdata->sc_parent; 6174 int r; 6175 scf_snaplevel_t *running; 6176 int flags = lcbdata->sc_flags; 6177 6178 const char * const emsg_tdel = 6179 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 6180 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 6181 "changed unexpectedly.\n"); 6182 const char * const emsg_del = gettext("%s changed unexpectedly " 6183 "(instance \"%s\" was deleted.)\n"); 6184 const char * const emsg_badsnap = gettext( 6185 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 6186 6187 /* 6188 * prepare last-import snapshot: 6189 * create temporary instance (service was precreated) 6190 * populate with properties from bundle 6191 * take snapshot 6192 */ 6193 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 6194 switch (scf_error()) { 6195 case SCF_ERROR_CONNECTION_BROKEN: 6196 case SCF_ERROR_NO_RESOURCES: 6197 case SCF_ERROR_BACKEND_READONLY: 6198 case SCF_ERROR_BACKEND_ACCESS: 6199 return (stash_scferror(lcbdata)); 6200 6201 case SCF_ERROR_EXISTS: 6202 warn(gettext("Temporary service svc:/%s " 6203 "changed unexpectedly (instance \"%s\" added).\n"), 6204 imp_tsname, inst->sc_name); 6205 lcbdata->sc_err = EBUSY; 6206 return (UU_WALK_ERROR); 6207 6208 case SCF_ERROR_DELETED: 6209 warn(gettext("Temporary service svc:/%s " 6210 "was deleted unexpectedly.\n"), imp_tsname); 6211 lcbdata->sc_err = EBUSY; 6212 return (UU_WALK_ERROR); 6213 6214 case SCF_ERROR_INVALID_ARGUMENT: 6215 warn(gettext("Invalid instance name \"%s\".\n"), 6216 inst->sc_name); 6217 return (stash_scferror(lcbdata)); 6218 6219 case SCF_ERROR_PERMISSION_DENIED: 6220 warn(gettext("Could not create temporary instance " 6221 "\"%s\" in svc:/%s (permission denied).\n"), 6222 inst->sc_name, imp_tsname); 6223 return (stash_scferror(lcbdata)); 6224 6225 case SCF_ERROR_HANDLE_MISMATCH: 6226 case SCF_ERROR_NOT_BOUND: 6227 case SCF_ERROR_NOT_SET: 6228 default: 6229 bad_error("scf_service_add_instance", scf_error()); 6230 } 6231 } 6232 6233 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6234 inst->sc_name); 6235 if (r < 0) 6236 bad_error("snprintf", errno); 6237 6238 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 6239 lcbdata->sc_flags | SCI_NOENABLED); 6240 switch (r) { 6241 case 0: 6242 break; 6243 6244 case ECANCELED: 6245 warn(emsg_tdel, imp_tsname, inst->sc_name); 6246 lcbdata->sc_err = EBUSY; 6247 r = UU_WALK_ERROR; 6248 goto deltemp; 6249 6250 case EEXIST: 6251 warn(emsg_tchg, imp_tsname, inst->sc_name); 6252 lcbdata->sc_err = EBUSY; 6253 r = UU_WALK_ERROR; 6254 goto deltemp; 6255 6256 case ECONNABORTED: 6257 goto connaborted; 6258 6259 case ENOMEM: 6260 case ENOSPC: 6261 case EPERM: 6262 case EROFS: 6263 case EACCES: 6264 case EINVAL: 6265 case EBUSY: 6266 lcbdata->sc_err = r; 6267 r = UU_WALK_ERROR; 6268 goto deltemp; 6269 6270 default: 6271 bad_error("lscf_import_instance_pgs", r); 6272 } 6273 6274 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6275 inst->sc_name); 6276 if (r < 0) 6277 bad_error("snprintf", errno); 6278 6279 ctx.sc_handle = lcbdata->sc_handle; 6280 ctx.sc_parent = imp_tinst; 6281 ctx.sc_service = 0; 6282 ctx.sc_source_fmri = inst->sc_fmri; 6283 ctx.sc_target_fmri = imp_str; 6284 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 6285 UU_DEFAULT) != 0) { 6286 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6287 bad_error("uu_list_walk", uu_error()); 6288 6289 switch (ctx.sc_err) { 6290 case ECONNABORTED: 6291 goto connaborted; 6292 6293 case ECANCELED: 6294 warn(emsg_tdel, imp_tsname, inst->sc_name); 6295 lcbdata->sc_err = EBUSY; 6296 break; 6297 6298 case EEXIST: 6299 warn(emsg_tchg, imp_tsname, inst->sc_name); 6300 lcbdata->sc_err = EBUSY; 6301 break; 6302 6303 default: 6304 lcbdata->sc_err = ctx.sc_err; 6305 } 6306 r = UU_WALK_ERROR; 6307 goto deltemp; 6308 } 6309 6310 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 6311 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 6312 switch (scf_error()) { 6313 case SCF_ERROR_CONNECTION_BROKEN: 6314 goto connaborted; 6315 6316 case SCF_ERROR_NO_RESOURCES: 6317 r = stash_scferror(lcbdata); 6318 goto deltemp; 6319 6320 case SCF_ERROR_EXISTS: 6321 warn(emsg_tchg, imp_tsname, inst->sc_name); 6322 lcbdata->sc_err = EBUSY; 6323 r = UU_WALK_ERROR; 6324 goto deltemp; 6325 6326 case SCF_ERROR_PERMISSION_DENIED: 6327 warn(gettext("Could not take \"%s\" snapshot of %s " 6328 "(permission denied).\n"), snap_lastimport, 6329 imp_str); 6330 r = stash_scferror(lcbdata); 6331 goto deltemp; 6332 6333 default: 6334 scfwarn(); 6335 lcbdata->sc_err = -1; 6336 r = UU_WALK_ERROR; 6337 goto deltemp; 6338 6339 case SCF_ERROR_HANDLE_MISMATCH: 6340 case SCF_ERROR_INVALID_ARGUMENT: 6341 case SCF_ERROR_NOT_SET: 6342 bad_error("_scf_snapshot_take_new_named", scf_error()); 6343 } 6344 } 6345 6346 if (lcbdata->sc_flags & SCI_FRESH) 6347 goto fresh; 6348 6349 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 6350 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6351 imp_lisnap) != 0) { 6352 switch (scf_error()) { 6353 case SCF_ERROR_DELETED: 6354 warn(emsg_del, inst->sc_parent->sc_fmri, 6355 inst->sc_name); 6356 lcbdata->sc_err = EBUSY; 6357 r = UU_WALK_ERROR; 6358 goto deltemp; 6359 6360 case SCF_ERROR_NOT_FOUND: 6361 flags |= SCI_FORCE; 6362 goto nosnap; 6363 6364 case SCF_ERROR_CONNECTION_BROKEN: 6365 goto connaborted; 6366 6367 case SCF_ERROR_INVALID_ARGUMENT: 6368 case SCF_ERROR_HANDLE_MISMATCH: 6369 case SCF_ERROR_NOT_BOUND: 6370 case SCF_ERROR_NOT_SET: 6371 default: 6372 bad_error("scf_instance_get_snapshot", 6373 scf_error()); 6374 } 6375 } 6376 6377 /* upgrade */ 6378 6379 /* 6380 * compare new properties with last-import properties 6381 * upgrade current properties 6382 */ 6383 /* clear sc_sceen for pgs */ 6384 if (uu_list_walk(inst->sc_pgroups, clear_int, 6385 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 6386 0) 6387 bad_error("uu_list_walk", uu_error()); 6388 6389 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 6390 switch (r) { 6391 case 0: 6392 break; 6393 6394 case ECONNABORTED: 6395 goto connaborted; 6396 6397 case ECANCELED: 6398 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6399 lcbdata->sc_err = EBUSY; 6400 r = UU_WALK_ERROR; 6401 goto deltemp; 6402 6403 case ENOENT: 6404 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 6405 lcbdata->sc_err = EBADF; 6406 r = UU_WALK_ERROR; 6407 goto deltemp; 6408 6409 default: 6410 bad_error("get_snaplevel", r); 6411 } 6412 6413 if (scf_instance_get_snapshot(imp_inst, snap_running, 6414 imp_rsnap) != 0) { 6415 switch (scf_error()) { 6416 case SCF_ERROR_DELETED: 6417 warn(emsg_del, inst->sc_parent->sc_fmri, 6418 inst->sc_name); 6419 lcbdata->sc_err = EBUSY; 6420 r = UU_WALK_ERROR; 6421 goto deltemp; 6422 6423 case SCF_ERROR_NOT_FOUND: 6424 break; 6425 6426 case SCF_ERROR_CONNECTION_BROKEN: 6427 goto connaborted; 6428 6429 case SCF_ERROR_INVALID_ARGUMENT: 6430 case SCF_ERROR_HANDLE_MISMATCH: 6431 case SCF_ERROR_NOT_BOUND: 6432 case SCF_ERROR_NOT_SET: 6433 default: 6434 bad_error("scf_instance_get_snapshot", 6435 scf_error()); 6436 } 6437 6438 running = NULL; 6439 } else { 6440 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 6441 switch (r) { 6442 case 0: 6443 running = imp_rsnpl; 6444 break; 6445 6446 case ECONNABORTED: 6447 goto connaborted; 6448 6449 case ECANCELED: 6450 warn(emsg_del, inst->sc_parent->sc_fmri, 6451 inst->sc_name); 6452 lcbdata->sc_err = EBUSY; 6453 r = UU_WALK_ERROR; 6454 goto deltemp; 6455 6456 case ENOENT: 6457 warn(emsg_badsnap, snap_running, inst->sc_fmri); 6458 lcbdata->sc_err = EBADF; 6459 r = UU_WALK_ERROR; 6460 goto deltemp; 6461 6462 default: 6463 bad_error("get_snaplevel", r); 6464 } 6465 } 6466 6467 r = upgrade_props(imp_inst, running, imp_snpl, inst); 6468 switch (r) { 6469 case 0: 6470 break; 6471 6472 case ECANCELED: 6473 case ENODEV: 6474 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6475 lcbdata->sc_err = EBUSY; 6476 r = UU_WALK_ERROR; 6477 goto deltemp; 6478 6479 case ECONNABORTED: 6480 goto connaborted; 6481 6482 case ENOMEM: 6483 case ENOSPC: 6484 case EBADF: 6485 case EBUSY: 6486 case EINVAL: 6487 case EPERM: 6488 case EROFS: 6489 case EACCES: 6490 case EEXIST: 6491 lcbdata->sc_err = r; 6492 r = UU_WALK_ERROR; 6493 goto deltemp; 6494 6495 default: 6496 bad_error("upgrade_props", r); 6497 } 6498 6499 inst->sc_import_state = IMPORT_PROP_DONE; 6500 } else { 6501 switch (scf_error()) { 6502 case SCF_ERROR_CONNECTION_BROKEN: 6503 goto connaborted; 6504 6505 case SCF_ERROR_NOT_FOUND: 6506 break; 6507 6508 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6509 case SCF_ERROR_HANDLE_MISMATCH: 6510 case SCF_ERROR_NOT_BOUND: 6511 case SCF_ERROR_NOT_SET: 6512 default: 6513 bad_error("scf_service_get_instance", scf_error()); 6514 } 6515 6516 fresh: 6517 /* create instance */ 6518 if (scf_service_add_instance(rsvc, inst->sc_name, 6519 imp_inst) != 0) { 6520 switch (scf_error()) { 6521 case SCF_ERROR_CONNECTION_BROKEN: 6522 goto connaborted; 6523 6524 case SCF_ERROR_NO_RESOURCES: 6525 case SCF_ERROR_BACKEND_READONLY: 6526 case SCF_ERROR_BACKEND_ACCESS: 6527 r = stash_scferror(lcbdata); 6528 goto deltemp; 6529 6530 case SCF_ERROR_EXISTS: 6531 warn(gettext("%s changed unexpectedly " 6532 "(instance \"%s\" added).\n"), 6533 inst->sc_parent->sc_fmri, inst->sc_name); 6534 lcbdata->sc_err = EBUSY; 6535 r = UU_WALK_ERROR; 6536 goto deltemp; 6537 6538 case SCF_ERROR_PERMISSION_DENIED: 6539 warn(gettext("Could not create \"%s\" instance " 6540 "in %s (permission denied).\n"), 6541 inst->sc_name, inst->sc_parent->sc_fmri); 6542 r = stash_scferror(lcbdata); 6543 goto deltemp; 6544 6545 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6546 case SCF_ERROR_HANDLE_MISMATCH: 6547 case SCF_ERROR_NOT_BOUND: 6548 case SCF_ERROR_NOT_SET: 6549 default: 6550 bad_error("scf_service_add_instance", 6551 scf_error()); 6552 } 6553 } 6554 6555 nosnap: 6556 /* 6557 * Create a last-import snapshot to serve as an attachment 6558 * point for the real one from the temporary instance. Since 6559 * the contents is irrelevant, take it now, while the instance 6560 * is empty, to minimize svc.configd's work. 6561 */ 6562 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6563 imp_lisnap) != 0) { 6564 switch (scf_error()) { 6565 case SCF_ERROR_CONNECTION_BROKEN: 6566 goto connaborted; 6567 6568 case SCF_ERROR_NO_RESOURCES: 6569 r = stash_scferror(lcbdata); 6570 goto deltemp; 6571 6572 case SCF_ERROR_EXISTS: 6573 warn(gettext("%s changed unexpectedly " 6574 "(snapshot \"%s\" added).\n"), 6575 inst->sc_fmri, snap_lastimport); 6576 lcbdata->sc_err = EBUSY; 6577 r = UU_WALK_ERROR; 6578 goto deltemp; 6579 6580 case SCF_ERROR_PERMISSION_DENIED: 6581 warn(gettext("Could not take \"%s\" snapshot " 6582 "of %s (permission denied).\n"), 6583 snap_lastimport, inst->sc_fmri); 6584 r = stash_scferror(lcbdata); 6585 goto deltemp; 6586 6587 default: 6588 scfwarn(); 6589 lcbdata->sc_err = -1; 6590 r = UU_WALK_ERROR; 6591 goto deltemp; 6592 6593 case SCF_ERROR_NOT_SET: 6594 case SCF_ERROR_INTERNAL: 6595 case SCF_ERROR_INVALID_ARGUMENT: 6596 case SCF_ERROR_HANDLE_MISMATCH: 6597 bad_error("_scf_snapshot_take_new", 6598 scf_error()); 6599 } 6600 } 6601 6602 if (li_only) 6603 goto lionly; 6604 6605 inst->sc_import_state = IMPORT_PROP_BEGUN; 6606 6607 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6608 flags); 6609 switch (r) { 6610 case 0: 6611 break; 6612 6613 case ECONNABORTED: 6614 goto connaborted; 6615 6616 case ECANCELED: 6617 warn(gettext("%s changed unexpectedly " 6618 "(instance \"%s\" deleted).\n"), 6619 inst->sc_parent->sc_fmri, inst->sc_name); 6620 lcbdata->sc_err = EBUSY; 6621 r = UU_WALK_ERROR; 6622 goto deltemp; 6623 6624 case EEXIST: 6625 warn(gettext("%s changed unexpectedly " 6626 "(property group added).\n"), inst->sc_fmri); 6627 lcbdata->sc_err = EBUSY; 6628 r = UU_WALK_ERROR; 6629 goto deltemp; 6630 6631 default: 6632 lcbdata->sc_err = r; 6633 r = UU_WALK_ERROR; 6634 goto deltemp; 6635 6636 case EINVAL: /* caught above */ 6637 bad_error("lscf_import_instance_pgs", r); 6638 } 6639 6640 ctx.sc_parent = imp_inst; 6641 ctx.sc_service = 0; 6642 ctx.sc_trans = NULL; 6643 ctx.sc_flags = 0; 6644 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6645 &ctx, UU_DEFAULT) != 0) { 6646 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6647 bad_error("uu_list_walk", uu_error()); 6648 6649 if (ctx.sc_err == ECONNABORTED) 6650 goto connaborted; 6651 lcbdata->sc_err = ctx.sc_err; 6652 r = UU_WALK_ERROR; 6653 goto deltemp; 6654 } 6655 6656 inst->sc_import_state = IMPORT_PROP_DONE; 6657 6658 if (g_verbose) 6659 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6660 snap_initial, inst->sc_fmri); 6661 r = take_snap(imp_inst, snap_initial, imp_snap); 6662 switch (r) { 6663 case 0: 6664 break; 6665 6666 case ECONNABORTED: 6667 goto connaborted; 6668 6669 case ENOSPC: 6670 case -1: 6671 lcbdata->sc_err = r; 6672 r = UU_WALK_ERROR; 6673 goto deltemp; 6674 6675 case ECANCELED: 6676 warn(gettext("%s changed unexpectedly " 6677 "(instance %s deleted).\n"), 6678 inst->sc_parent->sc_fmri, inst->sc_name); 6679 lcbdata->sc_err = r; 6680 r = UU_WALK_ERROR; 6681 goto deltemp; 6682 6683 case EPERM: 6684 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6685 lcbdata->sc_err = r; 6686 r = UU_WALK_ERROR; 6687 goto deltemp; 6688 6689 default: 6690 bad_error("take_snap", r); 6691 } 6692 } 6693 6694 lionly: 6695 if (lcbdata->sc_flags & SCI_NOSNAP) 6696 goto deltemp; 6697 6698 /* transfer snapshot from temporary instance */ 6699 if (g_verbose) 6700 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6701 snap_lastimport, inst->sc_fmri); 6702 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6703 switch (scf_error()) { 6704 case SCF_ERROR_CONNECTION_BROKEN: 6705 goto connaborted; 6706 6707 case SCF_ERROR_NO_RESOURCES: 6708 r = stash_scferror(lcbdata); 6709 goto deltemp; 6710 6711 case SCF_ERROR_PERMISSION_DENIED: 6712 warn(gettext("Could not take \"%s\" snapshot for %s " 6713 "(permission denied).\n"), snap_lastimport, 6714 inst->sc_fmri); 6715 r = stash_scferror(lcbdata); 6716 goto deltemp; 6717 6718 case SCF_ERROR_NOT_SET: 6719 case SCF_ERROR_HANDLE_MISMATCH: 6720 default: 6721 bad_error("_scf_snapshot_attach", scf_error()); 6722 } 6723 } 6724 6725 inst->sc_import_state = IMPORT_COMPLETE; 6726 6727 r = UU_WALK_NEXT; 6728 6729 deltemp: 6730 /* delete temporary instance */ 6731 if (scf_instance_delete(imp_tinst) != 0) { 6732 switch (scf_error()) { 6733 case SCF_ERROR_DELETED: 6734 break; 6735 6736 case SCF_ERROR_CONNECTION_BROKEN: 6737 goto connaborted; 6738 6739 case SCF_ERROR_NOT_SET: 6740 case SCF_ERROR_NOT_BOUND: 6741 default: 6742 bad_error("scf_instance_delete", scf_error()); 6743 } 6744 } 6745 6746 return (r); 6747 6748 connaborted: 6749 warn(gettext("Could not delete svc:/%s:%s " 6750 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6751 lcbdata->sc_err = ECONNABORTED; 6752 return (UU_WALK_ERROR); 6753 } 6754 6755 /* 6756 * When an instance is imported we end up telling configd about it. Once we tell 6757 * configd about these changes, startd eventually notices. If this is a new 6758 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter) 6759 * property group. However, many of the other tools expect that this property 6760 * group exists and has certain values. 6761 * 6762 * These values are added asynchronously by startd. We should not return from 6763 * this routine until we can verify that the property group we need is there. 6764 * 6765 * Before we go ahead and verify this, we have to ask ourselves an important 6766 * question: Is the early manifest service currently running? Because if it is 6767 * running and it has invoked us, then the service will never get a restarter 6768 * property because svc.startd is blocked on EMI finishing before it lets itself 6769 * fully connect to svc.configd. Of course, this means that this race condition 6770 * is in fact impossible to 100% eliminate. 6771 * 6772 * svc.startd makes sure that EMI only runs once and has succeeded by checking 6773 * the state of the EMI instance. If it is online it bails out and makes sure 6774 * that it doesn't run again. In this case, we're going to do something similar, 6775 * only if the state is online, then we're going to actually verify. EMI always 6776 * has to be present, but it can be explicitly disabled to reduce the amount of 6777 * damage it can cause. If EMI has been disabled then we no longer have to worry 6778 * about the implicit race condition and can go ahead and check things. If EMI 6779 * is in some state that isn't online or disabled and isn't runinng, then we 6780 * assume that things are rather bad and we're not going to get in your way, 6781 * even if the rest of SMF does. 6782 * 6783 * Returns 0 on success or returns an errno. 6784 */ 6785 #ifndef NATIVE_BUILD 6786 static int 6787 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst) 6788 { 6789 int ret, err; 6790 struct timespec ts; 6791 char *emi_state; 6792 6793 /* 6794 * smf_get_state does not distinguish between its different failure 6795 * modes: memory allocation failures, SMF internal failures, and a lack 6796 * of EMI entirely because it's been removed. In these cases, we're 6797 * going to be conservative and opt to say that if we don't know, better 6798 * to not block import or falsely warn to the user. 6799 */ 6800 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) { 6801 return (0); 6802 } 6803 6804 /* 6805 * As per the block comment for this function check the state of EMI 6806 */ 6807 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 && 6808 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) { 6809 warn(gettext("Not validating instance %s:%s because EMI's " 6810 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state); 6811 free(emi_state); 6812 return (0); 6813 } 6814 6815 free(emi_state); 6816 6817 /* 6818 * First we have to get the property. 6819 */ 6820 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) { 6821 ret = scf_error(); 6822 warn(gettext("Failed to look up service: %s\n"), svc->sc_name); 6823 return (ret); 6824 } 6825 6826 /* 6827 * We should always be able to get the instance. It should already 6828 * exist because we just created it or got it. There probably is a 6829 * slim chance that someone may have come in and deleted it though from 6830 * under us. 6831 */ 6832 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst)) 6833 != 0) { 6834 ret = scf_error(); 6835 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name); 6836 switch (ret) { 6837 case SCF_ERROR_DELETED: 6838 err = ENODEV; 6839 break; 6840 case SCF_ERROR_CONNECTION_BROKEN: 6841 warn(gettext("Lost repository connection\n")); 6842 err = ECONNABORTED; 6843 break; 6844 case SCF_ERROR_NOT_FOUND: 6845 warn(gettext("Instance \"%s\" disappeared out from " 6846 "under us.\n"), inst->sc_name); 6847 err = ENOENT; 6848 break; 6849 default: 6850 bad_error("scf_service_get_instance", ret); 6851 } 6852 6853 return (err); 6854 } 6855 6856 /* 6857 * An astute observer may want to use _scf_wait_pg which would notify us 6858 * of a property group change, unfortunately that does not work if the 6859 * property group in question does not exist. So instead we have to 6860 * manually poll and ask smf the best way to get to it. 6861 */ 6862 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg)) 6863 != SCF_SUCCESS) { 6864 ret = scf_error(); 6865 if (ret != SCF_ERROR_NOT_FOUND) { 6866 warn(gettext("Failed to get restarter property " 6867 "group for instance: %s\n"), inst->sc_name); 6868 switch (ret) { 6869 case SCF_ERROR_DELETED: 6870 err = ENODEV; 6871 break; 6872 case SCF_ERROR_CONNECTION_BROKEN: 6873 warn(gettext("Lost repository connection\n")); 6874 err = ECONNABORTED; 6875 break; 6876 default: 6877 bad_error("scf_service_get_instance", ret); 6878 } 6879 6880 return (err); 6881 } 6882 6883 ts.tv_sec = pg_timeout / NANOSEC; 6884 ts.tv_nsec = pg_timeout % NANOSEC; 6885 6886 (void) nanosleep(&ts, NULL); 6887 } 6888 6889 /* 6890 * svcadm also expects that the SCF_PROPERTY_STATE property is present. 6891 * So in addition to the property group being present, we need to wait 6892 * for the property to be there in some form. 6893 * 6894 * Note that a property group is a frozen snapshot in time. To properly 6895 * get beyond this, you have to refresh the property group each time. 6896 */ 6897 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE, 6898 imp_prop)) != 0) { 6899 6900 ret = scf_error(); 6901 if (ret != SCF_ERROR_NOT_FOUND) { 6902 warn(gettext("Failed to get property %s from the " 6903 "restarter property group of instance %s\n"), 6904 SCF_PROPERTY_STATE, inst->sc_name); 6905 switch (ret) { 6906 case SCF_ERROR_CONNECTION_BROKEN: 6907 warn(gettext("Lost repository connection\n")); 6908 err = ECONNABORTED; 6909 break; 6910 case SCF_ERROR_DELETED: 6911 err = ENODEV; 6912 break; 6913 default: 6914 bad_error("scf_pg_get_property", ret); 6915 } 6916 6917 return (err); 6918 } 6919 6920 ts.tv_sec = pg_timeout / NANOSEC; 6921 ts.tv_nsec = pg_timeout % NANOSEC; 6922 6923 (void) nanosleep(&ts, NULL); 6924 6925 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg); 6926 if (ret != SCF_SUCCESS) { 6927 warn(gettext("Failed to get restarter property " 6928 "group for instance: %s\n"), inst->sc_name); 6929 switch (ret) { 6930 case SCF_ERROR_DELETED: 6931 err = ENODEV; 6932 break; 6933 case SCF_ERROR_CONNECTION_BROKEN: 6934 warn(gettext("Lost repository connection\n")); 6935 err = ECONNABORTED; 6936 break; 6937 default: 6938 bad_error("scf_service_get_instance", ret); 6939 } 6940 6941 return (err); 6942 } 6943 } 6944 6945 /* 6946 * We don't have to free the property groups or other values that we got 6947 * because we stored them in global variables that are allocated and 6948 * freed by the routines that call into these functions. Unless of 6949 * course the rest of the code here that we are basing this on is 6950 * mistaken. 6951 */ 6952 return (0); 6953 } 6954 #endif 6955 6956 /* 6957 * If the service is missing, create it, import its properties, and import the 6958 * instances. Since the service is brand new, it should be empty, and if we 6959 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6960 * 6961 * If the service exists, we want to upgrade its properties and import the 6962 * instances. Upgrade requires a last-import snapshot, though, which are 6963 * children of instances, so first we'll have to go through the instances 6964 * looking for a last-import snapshot. If we don't find one then we'll just 6965 * override-import the service properties (but don't delete existing 6966 * properties: another service might have declared us as a dependent). Before 6967 * we change anything, though, we want to take the previous snapshots. We 6968 * also give lscf_instance_import() a leg up on taking last-import snapshots 6969 * by importing the manifest's service properties into a temporary service. 6970 * 6971 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6972 * sets lcbdata->sc_err to 6973 * ECONNABORTED - repository connection broken 6974 * ENOMEM - out of memory 6975 * ENOSPC - svc.configd is out of resources 6976 * EPERM - couldn't create temporary service (error printed) 6977 * - couldn't import into temp service (error printed) 6978 * - couldn't create service (error printed) 6979 * - couldn't import dependent (error printed) 6980 * - couldn't take snapshot (error printed) 6981 * - couldn't create instance (error printed) 6982 * - couldn't create, modify, or delete pg (error printed) 6983 * - couldn't create, modify, or delete dependent (error printed) 6984 * - couldn't import instance (error printed) 6985 * EROFS - couldn't create temporary service (repository read-only) 6986 * - couldn't import into temporary service (repository read-only) 6987 * - couldn't create service (repository read-only) 6988 * - couldn't import dependent (repository read-only) 6989 * - couldn't create instance (repository read-only) 6990 * - couldn't create, modify, or delete pg or dependent 6991 * - couldn't import instance (repository read-only) 6992 * EACCES - couldn't create temporary service (backend access denied) 6993 * - couldn't import into temporary service (backend access denied) 6994 * - couldn't create service (backend access denied) 6995 * - couldn't import dependent (backend access denied) 6996 * - couldn't create instance (backend access denied) 6997 * - couldn't create, modify, or delete pg or dependent 6998 * - couldn't import instance (backend access denied) 6999 * EINVAL - service name is invalid (error printed) 7000 * - service name is too long (error printed) 7001 * - s has invalid pgroup (error printed) 7002 * - s has invalid dependent (error printed) 7003 * - instance name is invalid (error printed) 7004 * - instance entity_t is invalid (error printed) 7005 * EEXIST - couldn't create temporary service (already exists) (error printed) 7006 * - couldn't import dependent (dependency pg already exists) (printed) 7007 * - dependency collision in dependent service (error printed) 7008 * EBUSY - temporary service deleted (error printed) 7009 * - property group added to temporary service (error printed) 7010 * - new property group changed or was deleted (error printed) 7011 * - service was added unexpectedly (error printed) 7012 * - service was deleted unexpectedly (error printed) 7013 * - property group added to new service (error printed) 7014 * - instance added unexpectedly (error printed) 7015 * - instance deleted unexpectedly (error printed) 7016 * - dependent service deleted unexpectedly (error printed) 7017 * - pg was added, changed, or deleted (error printed) 7018 * - dependent pg changed (error printed) 7019 * - temporary instance added, changed, or deleted (error printed) 7020 * EBADF - a last-import snapshot is corrupt (error printed) 7021 * - the service is corrupt (error printed) 7022 * - a dependent is corrupt (error printed) 7023 * - an instance is corrupt (error printed) 7024 * - an instance has a corrupt last-import snapshot (error printed) 7025 * - dependent target has a corrupt snapshot (error printed) 7026 * -1 - unknown libscf error (error printed) 7027 */ 7028 static int 7029 lscf_service_import(void *v, void *pvt) 7030 { 7031 entity_t *s = v; 7032 scf_callback_t cbdata; 7033 scf_callback_t *lcbdata = pvt; 7034 scf_scope_t *scope = lcbdata->sc_parent; 7035 entity_t *inst, linst; 7036 int r; 7037 int fresh = 0; 7038 scf_snaplevel_t *running; 7039 int have_ge = 0; 7040 boolean_t retried = B_FALSE; 7041 7042 const char * const ts_deleted = gettext("Temporary service svc:/%s " 7043 "was deleted unexpectedly.\n"); 7044 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 7045 "changed unexpectedly (property group added).\n"); 7046 const char * const s_deleted = 7047 gettext("%s was deleted unexpectedly.\n"); 7048 const char * const i_deleted = 7049 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 7050 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 7051 "is corrupt (missing service snaplevel).\n"); 7052 const char * const s_mfile_upd = 7053 gettext("Unable to update the manifest file connection " 7054 "for %s\n"); 7055 7056 li_only = 0; 7057 /* Validate the service name */ 7058 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7059 switch (scf_error()) { 7060 case SCF_ERROR_CONNECTION_BROKEN: 7061 return (stash_scferror(lcbdata)); 7062 7063 case SCF_ERROR_INVALID_ARGUMENT: 7064 warn(gettext("\"%s\" is an invalid service name. " 7065 "Cannot import.\n"), s->sc_name); 7066 return (stash_scferror(lcbdata)); 7067 7068 case SCF_ERROR_NOT_FOUND: 7069 break; 7070 7071 case SCF_ERROR_HANDLE_MISMATCH: 7072 case SCF_ERROR_NOT_BOUND: 7073 case SCF_ERROR_NOT_SET: 7074 default: 7075 bad_error("scf_scope_get_service", scf_error()); 7076 } 7077 } 7078 7079 /* create temporary service */ 7080 /* 7081 * the size of the buffer was reduced to max_scf_name_len to prevent 7082 * hitting bug 6681151. After the bug fix, the size of the buffer 7083 * should be restored to its original value (max_scf_name_len +1) 7084 */ 7085 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 7086 if (r < 0) 7087 bad_error("snprintf", errno); 7088 if (r > max_scf_name_len) { 7089 warn(gettext( 7090 "Service name \"%s\" is too long. Cannot import.\n"), 7091 s->sc_name); 7092 lcbdata->sc_err = EINVAL; 7093 return (UU_WALK_ERROR); 7094 } 7095 7096 retry: 7097 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 7098 switch (scf_error()) { 7099 case SCF_ERROR_CONNECTION_BROKEN: 7100 case SCF_ERROR_NO_RESOURCES: 7101 case SCF_ERROR_BACKEND_READONLY: 7102 case SCF_ERROR_BACKEND_ACCESS: 7103 return (stash_scferror(lcbdata)); 7104 7105 case SCF_ERROR_EXISTS: 7106 if (!retried) { 7107 lscf_delete(imp_tsname, 0); 7108 retried = B_TRUE; 7109 goto retry; 7110 } 7111 warn(gettext( 7112 "Temporary service \"%s\" must be deleted before " 7113 "this manifest can be imported.\n"), imp_tsname); 7114 return (stash_scferror(lcbdata)); 7115 7116 case SCF_ERROR_PERMISSION_DENIED: 7117 warn(gettext("Could not create temporary service " 7118 "\"%s\" (permission denied).\n"), imp_tsname); 7119 return (stash_scferror(lcbdata)); 7120 7121 case SCF_ERROR_INVALID_ARGUMENT: 7122 case SCF_ERROR_HANDLE_MISMATCH: 7123 case SCF_ERROR_NOT_BOUND: 7124 case SCF_ERROR_NOT_SET: 7125 default: 7126 bad_error("scf_scope_add_service", scf_error()); 7127 } 7128 } 7129 7130 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 7131 if (r < 0) 7132 bad_error("snprintf", errno); 7133 7134 cbdata.sc_handle = lcbdata->sc_handle; 7135 cbdata.sc_parent = imp_tsvc; 7136 cbdata.sc_service = 1; 7137 cbdata.sc_source_fmri = s->sc_fmri; 7138 cbdata.sc_target_fmri = imp_str; 7139 cbdata.sc_flags = 0; 7140 7141 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 7142 UU_DEFAULT) != 0) { 7143 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7144 bad_error("uu_list_walk", uu_error()); 7145 7146 lcbdata->sc_err = cbdata.sc_err; 7147 switch (cbdata.sc_err) { 7148 case ECONNABORTED: 7149 goto connaborted; 7150 7151 case ECANCELED: 7152 warn(ts_deleted, imp_tsname); 7153 lcbdata->sc_err = EBUSY; 7154 return (UU_WALK_ERROR); 7155 7156 case EEXIST: 7157 warn(ts_pg_added, imp_tsname); 7158 lcbdata->sc_err = EBUSY; 7159 return (UU_WALK_ERROR); 7160 } 7161 7162 r = UU_WALK_ERROR; 7163 goto deltemp; 7164 } 7165 7166 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 7167 UU_DEFAULT) != 0) { 7168 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7169 bad_error("uu_list_walk", uu_error()); 7170 7171 lcbdata->sc_err = cbdata.sc_err; 7172 switch (cbdata.sc_err) { 7173 case ECONNABORTED: 7174 goto connaborted; 7175 7176 case ECANCELED: 7177 warn(ts_deleted, imp_tsname); 7178 lcbdata->sc_err = EBUSY; 7179 return (UU_WALK_ERROR); 7180 7181 case EEXIST: 7182 warn(ts_pg_added, imp_tsname); 7183 lcbdata->sc_err = EBUSY; 7184 return (UU_WALK_ERROR); 7185 } 7186 7187 r = UU_WALK_ERROR; 7188 goto deltemp; 7189 } 7190 7191 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7192 switch (scf_error()) { 7193 case SCF_ERROR_NOT_FOUND: 7194 break; 7195 7196 case SCF_ERROR_CONNECTION_BROKEN: 7197 goto connaborted; 7198 7199 case SCF_ERROR_INVALID_ARGUMENT: 7200 case SCF_ERROR_HANDLE_MISMATCH: 7201 case SCF_ERROR_NOT_BOUND: 7202 case SCF_ERROR_NOT_SET: 7203 default: 7204 bad_error("scf_scope_get_service", scf_error()); 7205 } 7206 7207 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 7208 switch (scf_error()) { 7209 case SCF_ERROR_CONNECTION_BROKEN: 7210 goto connaborted; 7211 7212 case SCF_ERROR_NO_RESOURCES: 7213 case SCF_ERROR_BACKEND_READONLY: 7214 case SCF_ERROR_BACKEND_ACCESS: 7215 r = stash_scferror(lcbdata); 7216 goto deltemp; 7217 7218 case SCF_ERROR_EXISTS: 7219 warn(gettext("Scope \"%s\" changed unexpectedly" 7220 " (service \"%s\" added).\n"), 7221 SCF_SCOPE_LOCAL, s->sc_name); 7222 lcbdata->sc_err = EBUSY; 7223 goto deltemp; 7224 7225 case SCF_ERROR_PERMISSION_DENIED: 7226 warn(gettext("Could not create service \"%s\" " 7227 "(permission denied).\n"), s->sc_name); 7228 goto deltemp; 7229 7230 case SCF_ERROR_INVALID_ARGUMENT: 7231 case SCF_ERROR_HANDLE_MISMATCH: 7232 case SCF_ERROR_NOT_BOUND: 7233 case SCF_ERROR_NOT_SET: 7234 default: 7235 bad_error("scf_scope_add_service", scf_error()); 7236 } 7237 } 7238 7239 s->sc_import_state = IMPORT_PROP_BEGUN; 7240 7241 /* import service properties */ 7242 cbdata.sc_handle = lcbdata->sc_handle; 7243 cbdata.sc_parent = imp_svc; 7244 cbdata.sc_service = 1; 7245 cbdata.sc_flags = lcbdata->sc_flags; 7246 cbdata.sc_source_fmri = s->sc_fmri; 7247 cbdata.sc_target_fmri = s->sc_fmri; 7248 7249 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7250 &cbdata, UU_DEFAULT) != 0) { 7251 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7252 bad_error("uu_list_walk", uu_error()); 7253 7254 lcbdata->sc_err = cbdata.sc_err; 7255 switch (cbdata.sc_err) { 7256 case ECONNABORTED: 7257 goto connaborted; 7258 7259 case ECANCELED: 7260 warn(s_deleted, s->sc_fmri); 7261 lcbdata->sc_err = EBUSY; 7262 return (UU_WALK_ERROR); 7263 7264 case EEXIST: 7265 warn(gettext("%s changed unexpectedly " 7266 "(property group added).\n"), s->sc_fmri); 7267 lcbdata->sc_err = EBUSY; 7268 return (UU_WALK_ERROR); 7269 7270 case EINVAL: 7271 /* caught above */ 7272 bad_error("entity_pgroup_import", 7273 cbdata.sc_err); 7274 } 7275 7276 r = UU_WALK_ERROR; 7277 goto deltemp; 7278 } 7279 7280 cbdata.sc_trans = NULL; 7281 cbdata.sc_flags = 0; 7282 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 7283 &cbdata, UU_DEFAULT) != 0) { 7284 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7285 bad_error("uu_list_walk", uu_error()); 7286 7287 lcbdata->sc_err = cbdata.sc_err; 7288 if (cbdata.sc_err == ECONNABORTED) 7289 goto connaborted; 7290 r = UU_WALK_ERROR; 7291 goto deltemp; 7292 } 7293 7294 s->sc_import_state = IMPORT_PROP_DONE; 7295 7296 /* 7297 * This is a new service, so we can't take previous snapshots 7298 * or upgrade service properties. 7299 */ 7300 fresh = 1; 7301 goto instances; 7302 } 7303 7304 /* Clear sc_seen for the instances. */ 7305 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 7306 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 7307 bad_error("uu_list_walk", uu_error()); 7308 7309 /* 7310 * Take previous snapshots for all instances. Even for ones not 7311 * mentioned in the bundle, since we might change their service 7312 * properties. 7313 */ 7314 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7315 switch (scf_error()) { 7316 case SCF_ERROR_CONNECTION_BROKEN: 7317 goto connaborted; 7318 7319 case SCF_ERROR_DELETED: 7320 warn(s_deleted, s->sc_fmri); 7321 lcbdata->sc_err = EBUSY; 7322 r = UU_WALK_ERROR; 7323 goto deltemp; 7324 7325 case SCF_ERROR_HANDLE_MISMATCH: 7326 case SCF_ERROR_NOT_BOUND: 7327 case SCF_ERROR_NOT_SET: 7328 default: 7329 bad_error("scf_iter_service_instances", scf_error()); 7330 } 7331 } 7332 7333 for (;;) { 7334 r = scf_iter_next_instance(imp_iter, imp_inst); 7335 if (r == 0) 7336 break; 7337 if (r != 1) { 7338 switch (scf_error()) { 7339 case SCF_ERROR_DELETED: 7340 warn(s_deleted, s->sc_fmri); 7341 lcbdata->sc_err = EBUSY; 7342 r = UU_WALK_ERROR; 7343 goto deltemp; 7344 7345 case SCF_ERROR_CONNECTION_BROKEN: 7346 goto connaborted; 7347 7348 case SCF_ERROR_NOT_BOUND: 7349 case SCF_ERROR_HANDLE_MISMATCH: 7350 case SCF_ERROR_INVALID_ARGUMENT: 7351 case SCF_ERROR_NOT_SET: 7352 default: 7353 bad_error("scf_iter_next_instance", 7354 scf_error()); 7355 } 7356 } 7357 7358 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 7359 switch (scf_error()) { 7360 case SCF_ERROR_DELETED: 7361 continue; 7362 7363 case SCF_ERROR_CONNECTION_BROKEN: 7364 goto connaborted; 7365 7366 case SCF_ERROR_NOT_SET: 7367 case SCF_ERROR_NOT_BOUND: 7368 default: 7369 bad_error("scf_instance_get_name", scf_error()); 7370 } 7371 } 7372 7373 if (g_verbose) 7374 warn(gettext( 7375 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 7376 snap_previous, s->sc_name, imp_str); 7377 7378 r = take_snap(imp_inst, snap_previous, imp_snap); 7379 switch (r) { 7380 case 0: 7381 break; 7382 7383 case ECANCELED: 7384 continue; 7385 7386 case ECONNABORTED: 7387 goto connaborted; 7388 7389 case EPERM: 7390 warn(gettext("Could not take \"%s\" snapshot of " 7391 "svc:/%s:%s (permission denied).\n"), 7392 snap_previous, s->sc_name, imp_str); 7393 lcbdata->sc_err = r; 7394 return (UU_WALK_ERROR); 7395 7396 case ENOSPC: 7397 case -1: 7398 lcbdata->sc_err = r; 7399 r = UU_WALK_ERROR; 7400 goto deltemp; 7401 7402 default: 7403 bad_error("take_snap", r); 7404 } 7405 7406 linst.sc_name = imp_str; 7407 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 7408 &linst, NULL, NULL); 7409 if (inst != NULL) { 7410 inst->sc_import_state = IMPORT_PREVIOUS; 7411 inst->sc_seen = 1; 7412 } 7413 } 7414 7415 /* 7416 * Create the new instances and take previous snapshots of 7417 * them. This is not necessary, but it maximizes data preservation. 7418 */ 7419 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 7420 inst != NULL; 7421 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 7422 inst)) { 7423 if (inst->sc_seen) 7424 continue; 7425 7426 if (scf_service_add_instance(imp_svc, inst->sc_name, 7427 imp_inst) != 0) { 7428 switch (scf_error()) { 7429 case SCF_ERROR_CONNECTION_BROKEN: 7430 goto connaborted; 7431 7432 case SCF_ERROR_BACKEND_READONLY: 7433 case SCF_ERROR_BACKEND_ACCESS: 7434 case SCF_ERROR_NO_RESOURCES: 7435 r = stash_scferror(lcbdata); 7436 goto deltemp; 7437 7438 case SCF_ERROR_EXISTS: 7439 warn(gettext("%s changed unexpectedly " 7440 "(instance \"%s\" added).\n"), s->sc_fmri, 7441 inst->sc_name); 7442 lcbdata->sc_err = EBUSY; 7443 r = UU_WALK_ERROR; 7444 goto deltemp; 7445 7446 case SCF_ERROR_INVALID_ARGUMENT: 7447 warn(gettext("Service \"%s\" has instance with " 7448 "invalid name \"%s\".\n"), s->sc_name, 7449 inst->sc_name); 7450 r = stash_scferror(lcbdata); 7451 goto deltemp; 7452 7453 case SCF_ERROR_PERMISSION_DENIED: 7454 warn(gettext("Could not create instance \"%s\" " 7455 "in %s (permission denied).\n"), 7456 inst->sc_name, s->sc_fmri); 7457 r = stash_scferror(lcbdata); 7458 goto deltemp; 7459 7460 case SCF_ERROR_HANDLE_MISMATCH: 7461 case SCF_ERROR_NOT_BOUND: 7462 case SCF_ERROR_NOT_SET: 7463 default: 7464 bad_error("scf_service_add_instance", 7465 scf_error()); 7466 } 7467 } 7468 7469 if (g_verbose) 7470 warn(gettext("Taking \"%s\" snapshot for " 7471 "new service %s.\n"), snap_previous, inst->sc_fmri); 7472 r = take_snap(imp_inst, snap_previous, imp_snap); 7473 switch (r) { 7474 case 0: 7475 break; 7476 7477 case ECANCELED: 7478 warn(i_deleted, s->sc_fmri, inst->sc_name); 7479 lcbdata->sc_err = EBUSY; 7480 r = UU_WALK_ERROR; 7481 goto deltemp; 7482 7483 case ECONNABORTED: 7484 goto connaborted; 7485 7486 case EPERM: 7487 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 7488 lcbdata->sc_err = r; 7489 r = UU_WALK_ERROR; 7490 goto deltemp; 7491 7492 case ENOSPC: 7493 case -1: 7494 r = UU_WALK_ERROR; 7495 goto deltemp; 7496 7497 default: 7498 bad_error("take_snap", r); 7499 } 7500 } 7501 7502 s->sc_import_state = IMPORT_PREVIOUS; 7503 7504 /* 7505 * Upgrade service properties, if we can find a last-import snapshot. 7506 * Any will do because we don't support different service properties 7507 * in different manifests, so all snaplevels of the service in all of 7508 * the last-import snapshots of the instances should be the same. 7509 */ 7510 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7511 switch (scf_error()) { 7512 case SCF_ERROR_CONNECTION_BROKEN: 7513 goto connaborted; 7514 7515 case SCF_ERROR_DELETED: 7516 warn(s_deleted, s->sc_fmri); 7517 lcbdata->sc_err = EBUSY; 7518 r = UU_WALK_ERROR; 7519 goto deltemp; 7520 7521 case SCF_ERROR_HANDLE_MISMATCH: 7522 case SCF_ERROR_NOT_BOUND: 7523 case SCF_ERROR_NOT_SET: 7524 default: 7525 bad_error("scf_iter_service_instances", scf_error()); 7526 } 7527 } 7528 7529 for (;;) { 7530 r = scf_iter_next_instance(imp_iter, imp_inst); 7531 if (r == -1) { 7532 switch (scf_error()) { 7533 case SCF_ERROR_DELETED: 7534 warn(s_deleted, s->sc_fmri); 7535 lcbdata->sc_err = EBUSY; 7536 r = UU_WALK_ERROR; 7537 goto deltemp; 7538 7539 case SCF_ERROR_CONNECTION_BROKEN: 7540 goto connaborted; 7541 7542 case SCF_ERROR_NOT_BOUND: 7543 case SCF_ERROR_HANDLE_MISMATCH: 7544 case SCF_ERROR_INVALID_ARGUMENT: 7545 case SCF_ERROR_NOT_SET: 7546 default: 7547 bad_error("scf_iter_next_instance", 7548 scf_error()); 7549 } 7550 } 7551 7552 if (r == 0) { 7553 /* 7554 * Didn't find any last-import snapshots. Override- 7555 * import the properties. Unless one of the instances 7556 * has a general/enabled property, in which case we're 7557 * probably running a last-import-capable svccfg for 7558 * the first time, and we should only take the 7559 * last-import snapshot. 7560 */ 7561 if (have_ge) { 7562 pgroup_t *mfpg; 7563 scf_callback_t mfcbdata; 7564 7565 li_only = 1; 7566 no_refresh = 1; 7567 /* 7568 * Need to go ahead and import the manifestfiles 7569 * pg if it exists. If the last-import snapshot 7570 * upgrade code is ever removed this code can 7571 * be removed as well. 7572 */ 7573 mfpg = internal_pgroup_find(s, 7574 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 7575 7576 if (mfpg) { 7577 mfcbdata.sc_handle = g_hndl; 7578 mfcbdata.sc_parent = imp_svc; 7579 mfcbdata.sc_service = 1; 7580 mfcbdata.sc_flags = SCI_FORCE; 7581 mfcbdata.sc_source_fmri = s->sc_fmri; 7582 mfcbdata.sc_target_fmri = s->sc_fmri; 7583 if (entity_pgroup_import(mfpg, 7584 &mfcbdata) != UU_WALK_NEXT) { 7585 warn(s_mfile_upd, s->sc_fmri); 7586 r = UU_WALK_ERROR; 7587 goto deltemp; 7588 } 7589 } 7590 break; 7591 } 7592 7593 s->sc_import_state = IMPORT_PROP_BEGUN; 7594 7595 cbdata.sc_handle = g_hndl; 7596 cbdata.sc_parent = imp_svc; 7597 cbdata.sc_service = 1; 7598 cbdata.sc_flags = SCI_FORCE; 7599 cbdata.sc_source_fmri = s->sc_fmri; 7600 cbdata.sc_target_fmri = s->sc_fmri; 7601 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7602 &cbdata, UU_DEFAULT) != 0) { 7603 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7604 bad_error("uu_list_walk", uu_error()); 7605 lcbdata->sc_err = cbdata.sc_err; 7606 switch (cbdata.sc_err) { 7607 case ECONNABORTED: 7608 goto connaborted; 7609 7610 case ECANCELED: 7611 warn(s_deleted, s->sc_fmri); 7612 lcbdata->sc_err = EBUSY; 7613 break; 7614 7615 case EINVAL: /* caught above */ 7616 case EEXIST: 7617 bad_error("entity_pgroup_import", 7618 cbdata.sc_err); 7619 } 7620 7621 r = UU_WALK_ERROR; 7622 goto deltemp; 7623 } 7624 7625 cbdata.sc_trans = NULL; 7626 cbdata.sc_flags = 0; 7627 if (uu_list_walk(s->sc_dependents, 7628 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 7629 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7630 bad_error("uu_list_walk", uu_error()); 7631 lcbdata->sc_err = cbdata.sc_err; 7632 if (cbdata.sc_err == ECONNABORTED) 7633 goto connaborted; 7634 r = UU_WALK_ERROR; 7635 goto deltemp; 7636 } 7637 break; 7638 } 7639 7640 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 7641 imp_snap) != 0) { 7642 switch (scf_error()) { 7643 case SCF_ERROR_DELETED: 7644 continue; 7645 7646 case SCF_ERROR_NOT_FOUND: 7647 break; 7648 7649 case SCF_ERROR_CONNECTION_BROKEN: 7650 goto connaborted; 7651 7652 case SCF_ERROR_HANDLE_MISMATCH: 7653 case SCF_ERROR_NOT_BOUND: 7654 case SCF_ERROR_INVALID_ARGUMENT: 7655 case SCF_ERROR_NOT_SET: 7656 default: 7657 bad_error("scf_instance_get_snapshot", 7658 scf_error()); 7659 } 7660 7661 if (have_ge) 7662 continue; 7663 7664 /* 7665 * Check for a general/enabled property. This is how 7666 * we tell whether to import if there turn out to be 7667 * no last-import snapshots. 7668 */ 7669 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 7670 imp_pg) == 0) { 7671 if (scf_pg_get_property(imp_pg, 7672 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 7673 have_ge = 1; 7674 } else { 7675 switch (scf_error()) { 7676 case SCF_ERROR_DELETED: 7677 case SCF_ERROR_NOT_FOUND: 7678 continue; 7679 7680 case SCF_ERROR_INVALID_ARGUMENT: 7681 case SCF_ERROR_HANDLE_MISMATCH: 7682 case SCF_ERROR_CONNECTION_BROKEN: 7683 case SCF_ERROR_NOT_BOUND: 7684 case SCF_ERROR_NOT_SET: 7685 default: 7686 bad_error("scf_pg_get_property", 7687 scf_error()); 7688 } 7689 } 7690 } else { 7691 switch (scf_error()) { 7692 case SCF_ERROR_DELETED: 7693 case SCF_ERROR_NOT_FOUND: 7694 continue; 7695 7696 case SCF_ERROR_CONNECTION_BROKEN: 7697 goto connaborted; 7698 7699 case SCF_ERROR_NOT_BOUND: 7700 case SCF_ERROR_NOT_SET: 7701 case SCF_ERROR_INVALID_ARGUMENT: 7702 case SCF_ERROR_HANDLE_MISMATCH: 7703 default: 7704 bad_error("scf_instance_get_pg", 7705 scf_error()); 7706 } 7707 } 7708 continue; 7709 } 7710 7711 /* find service snaplevel */ 7712 r = get_snaplevel(imp_snap, 1, imp_snpl); 7713 switch (r) { 7714 case 0: 7715 break; 7716 7717 case ECONNABORTED: 7718 goto connaborted; 7719 7720 case ECANCELED: 7721 continue; 7722 7723 case ENOENT: 7724 if (scf_instance_get_name(imp_inst, imp_str, 7725 imp_str_sz) < 0) 7726 (void) strcpy(imp_str, "?"); 7727 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 7728 lcbdata->sc_err = EBADF; 7729 r = UU_WALK_ERROR; 7730 goto deltemp; 7731 7732 default: 7733 bad_error("get_snaplevel", r); 7734 } 7735 7736 if (scf_instance_get_snapshot(imp_inst, snap_running, 7737 imp_rsnap) != 0) { 7738 switch (scf_error()) { 7739 case SCF_ERROR_DELETED: 7740 continue; 7741 7742 case SCF_ERROR_NOT_FOUND: 7743 break; 7744 7745 case SCF_ERROR_CONNECTION_BROKEN: 7746 goto connaborted; 7747 7748 case SCF_ERROR_INVALID_ARGUMENT: 7749 case SCF_ERROR_HANDLE_MISMATCH: 7750 case SCF_ERROR_NOT_BOUND: 7751 case SCF_ERROR_NOT_SET: 7752 default: 7753 bad_error("scf_instance_get_snapshot", 7754 scf_error()); 7755 } 7756 running = NULL; 7757 } else { 7758 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7759 switch (r) { 7760 case 0: 7761 running = imp_rsnpl; 7762 break; 7763 7764 case ECONNABORTED: 7765 goto connaborted; 7766 7767 case ECANCELED: 7768 continue; 7769 7770 case ENOENT: 7771 if (scf_instance_get_name(imp_inst, imp_str, 7772 imp_str_sz) < 0) 7773 (void) strcpy(imp_str, "?"); 7774 warn(badsnap, snap_running, s->sc_name, 7775 imp_str); 7776 lcbdata->sc_err = EBADF; 7777 r = UU_WALK_ERROR; 7778 goto deltemp; 7779 7780 default: 7781 bad_error("get_snaplevel", r); 7782 } 7783 } 7784 7785 if (g_verbose) { 7786 if (scf_instance_get_name(imp_inst, imp_str, 7787 imp_str_sz) < 0) 7788 (void) strcpy(imp_str, "?"); 7789 warn(gettext("Upgrading properties of %s according to " 7790 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7791 } 7792 7793 /* upgrade service properties */ 7794 r = upgrade_props(imp_svc, running, imp_snpl, s); 7795 if (r == 0) 7796 break; 7797 7798 switch (r) { 7799 case ECONNABORTED: 7800 goto connaborted; 7801 7802 case ECANCELED: 7803 warn(s_deleted, s->sc_fmri); 7804 lcbdata->sc_err = EBUSY; 7805 break; 7806 7807 case ENODEV: 7808 if (scf_instance_get_name(imp_inst, imp_str, 7809 imp_str_sz) < 0) 7810 (void) strcpy(imp_str, "?"); 7811 warn(i_deleted, s->sc_fmri, imp_str); 7812 lcbdata->sc_err = EBUSY; 7813 break; 7814 7815 default: 7816 lcbdata->sc_err = r; 7817 } 7818 7819 r = UU_WALK_ERROR; 7820 goto deltemp; 7821 } 7822 7823 s->sc_import_state = IMPORT_PROP_DONE; 7824 7825 instances: 7826 /* import instances */ 7827 cbdata.sc_handle = lcbdata->sc_handle; 7828 cbdata.sc_parent = imp_svc; 7829 cbdata.sc_service = 1; 7830 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7831 cbdata.sc_general = NULL; 7832 7833 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7834 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7835 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7836 bad_error("uu_list_walk", uu_error()); 7837 7838 lcbdata->sc_err = cbdata.sc_err; 7839 if (cbdata.sc_err == ECONNABORTED) 7840 goto connaborted; 7841 r = UU_WALK_ERROR; 7842 goto deltemp; 7843 } 7844 7845 s->sc_import_state = IMPORT_COMPLETE; 7846 r = UU_WALK_NEXT; 7847 7848 deltemp: 7849 /* delete temporary service */ 7850 if (scf_service_delete(imp_tsvc) != 0) { 7851 switch (scf_error()) { 7852 case SCF_ERROR_DELETED: 7853 break; 7854 7855 case SCF_ERROR_CONNECTION_BROKEN: 7856 goto connaborted; 7857 7858 case SCF_ERROR_EXISTS: 7859 warn(gettext( 7860 "Could not delete svc:/%s (instances exist).\n"), 7861 imp_tsname); 7862 break; 7863 7864 case SCF_ERROR_NOT_SET: 7865 case SCF_ERROR_NOT_BOUND: 7866 default: 7867 bad_error("scf_service_delete", scf_error()); 7868 } 7869 } 7870 7871 return (r); 7872 7873 connaborted: 7874 warn(gettext("Could not delete svc:/%s " 7875 "(repository connection broken).\n"), imp_tsname); 7876 lcbdata->sc_err = ECONNABORTED; 7877 return (UU_WALK_ERROR); 7878 } 7879 7880 static const char * 7881 import_progress(int st) 7882 { 7883 switch (st) { 7884 case 0: 7885 return (gettext("not reached.")); 7886 7887 case IMPORT_PREVIOUS: 7888 return (gettext("previous snapshot taken.")); 7889 7890 case IMPORT_PROP_BEGUN: 7891 return (gettext("some properties imported.")); 7892 7893 case IMPORT_PROP_DONE: 7894 return (gettext("properties imported.")); 7895 7896 case IMPORT_COMPLETE: 7897 return (gettext("imported.")); 7898 7899 case IMPORT_REFRESHED: 7900 return (gettext("refresh requested.")); 7901 7902 default: 7903 #ifndef NDEBUG 7904 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7905 __FILE__, __LINE__, st); 7906 #endif 7907 abort(); 7908 /* NOTREACHED */ 7909 } 7910 } 7911 7912 /* 7913 * Returns 7914 * 0 - success 7915 * - fmri wasn't found (error printed) 7916 * - entity was deleted (error printed) 7917 * - backend denied access (error printed) 7918 * ENOMEM - out of memory (error printed) 7919 * ECONNABORTED - repository connection broken (error printed) 7920 * EPERM - permission denied (error printed) 7921 * -1 - unknown libscf error (error printed) 7922 */ 7923 static int 7924 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7925 { 7926 scf_error_t serr; 7927 void *ent; 7928 int issvc; 7929 int r; 7930 7931 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7932 const char *dpt_deleted = gettext("Could not refresh %s " 7933 "(dependent \"%s\" of %s) (deleted).\n"); 7934 7935 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7936 switch (serr) { 7937 case SCF_ERROR_NONE: 7938 break; 7939 7940 case SCF_ERROR_NO_MEMORY: 7941 if (name == NULL) 7942 warn(gettext("Could not refresh %s (out of memory).\n"), 7943 fmri); 7944 else 7945 warn(gettext("Could not refresh %s " 7946 "(dependent \"%s\" of %s) (out of memory).\n"), 7947 fmri, name, d_fmri); 7948 return (ENOMEM); 7949 7950 case SCF_ERROR_NOT_FOUND: 7951 if (name == NULL) 7952 warn(deleted, fmri); 7953 else 7954 warn(dpt_deleted, fmri, name, d_fmri); 7955 return (0); 7956 7957 case SCF_ERROR_INVALID_ARGUMENT: 7958 case SCF_ERROR_CONSTRAINT_VIOLATED: 7959 default: 7960 bad_error("fmri_to_entity", serr); 7961 } 7962 7963 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7964 switch (r) { 7965 case 0: 7966 break; 7967 7968 case ECONNABORTED: 7969 if (name != NULL) 7970 warn(gettext("Could not refresh %s " 7971 "(dependent \"%s\" of %s) " 7972 "(repository connection broken).\n"), fmri, name, 7973 d_fmri); 7974 return (r); 7975 7976 case ECANCELED: 7977 if (name == NULL) 7978 warn(deleted, fmri); 7979 else 7980 warn(dpt_deleted, fmri, name, d_fmri); 7981 return (0); 7982 7983 case EACCES: 7984 if (!g_verbose) 7985 return (0); 7986 if (name == NULL) 7987 warn(gettext("Could not refresh %s " 7988 "(backend access denied).\n"), fmri); 7989 else 7990 warn(gettext("Could not refresh %s " 7991 "(dependent \"%s\" of %s) " 7992 "(backend access denied).\n"), fmri, name, d_fmri); 7993 return (0); 7994 7995 case EPERM: 7996 if (name == NULL) 7997 warn(gettext("Could not refresh %s " 7998 "(permission denied).\n"), fmri); 7999 else 8000 warn(gettext("Could not refresh %s " 8001 "(dependent \"%s\" of %s) " 8002 "(permission denied).\n"), fmri, name, d_fmri); 8003 return (r); 8004 8005 case ENOSPC: 8006 if (name == NULL) 8007 warn(gettext("Could not refresh %s " 8008 "(repository server out of resources).\n"), 8009 fmri); 8010 else 8011 warn(gettext("Could not refresh %s " 8012 "(dependent \"%s\" of %s) " 8013 "(repository server out of resources).\n"), 8014 fmri, name, d_fmri); 8015 return (r); 8016 8017 case -1: 8018 scfwarn(); 8019 return (r); 8020 8021 default: 8022 bad_error("refresh_entity", r); 8023 } 8024 8025 if (issvc) 8026 scf_service_destroy(ent); 8027 else 8028 scf_instance_destroy(ent); 8029 8030 return (0); 8031 } 8032 8033 static int 8034 alloc_imp_globals() 8035 { 8036 int r; 8037 8038 const char * const emsg_nomem = gettext("Out of memory.\n"); 8039 const char * const emsg_nores = 8040 gettext("svc.configd is out of resources.\n"); 8041 8042 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 8043 max_scf_name_len : max_scf_fmri_len) + 1; 8044 8045 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 8046 (imp_svc = scf_service_create(g_hndl)) == NULL || 8047 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 8048 (imp_inst = scf_instance_create(g_hndl)) == NULL || 8049 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 8050 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 8051 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 8052 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 8053 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 8054 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8055 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 8056 (imp_pg = scf_pg_create(g_hndl)) == NULL || 8057 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 8058 (imp_prop = scf_property_create(g_hndl)) == NULL || 8059 (imp_iter = scf_iter_create(g_hndl)) == NULL || 8060 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 8061 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 8062 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 8063 (imp_str = malloc(imp_str_sz)) == NULL || 8064 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 8065 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 8066 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 8067 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 8068 (ud_inst = scf_instance_create(g_hndl)) == NULL || 8069 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8070 (ud_pg = scf_pg_create(g_hndl)) == NULL || 8071 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 8072 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 8073 (ud_prop = scf_property_create(g_hndl)) == NULL || 8074 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 8075 (ud_val = scf_value_create(g_hndl)) == NULL || 8076 (ud_iter = scf_iter_create(g_hndl)) == NULL || 8077 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 8078 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 8079 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 8080 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 8081 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 8082 if (scf_error() == SCF_ERROR_NO_RESOURCES) 8083 warn(emsg_nores); 8084 else 8085 warn(emsg_nomem); 8086 8087 return (-1); 8088 } 8089 8090 r = load_init(); 8091 switch (r) { 8092 case 0: 8093 break; 8094 8095 case ENOMEM: 8096 warn(emsg_nomem); 8097 return (-1); 8098 8099 default: 8100 bad_error("load_init", r); 8101 } 8102 8103 return (0); 8104 } 8105 8106 static void 8107 free_imp_globals() 8108 { 8109 pgroup_t *old_dpt; 8110 void *cookie; 8111 8112 load_fini(); 8113 8114 free(ud_ctarg); 8115 free(ud_oldtarg); 8116 free(ud_name); 8117 ud_ctarg = ud_oldtarg = ud_name = NULL; 8118 8119 scf_transaction_destroy(ud_tx); 8120 ud_tx = NULL; 8121 scf_iter_destroy(ud_iter); 8122 scf_iter_destroy(ud_iter2); 8123 ud_iter = ud_iter2 = NULL; 8124 scf_value_destroy(ud_val); 8125 ud_val = NULL; 8126 scf_property_destroy(ud_prop); 8127 scf_property_destroy(ud_dpt_prop); 8128 ud_prop = ud_dpt_prop = NULL; 8129 scf_pg_destroy(ud_pg); 8130 scf_pg_destroy(ud_cur_depts_pg); 8131 scf_pg_destroy(ud_run_dpts_pg); 8132 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 8133 scf_snaplevel_destroy(ud_snpl); 8134 ud_snpl = NULL; 8135 scf_instance_destroy(ud_inst); 8136 ud_inst = NULL; 8137 8138 free(imp_str); 8139 free(imp_tsname); 8140 free(imp_fe1); 8141 free(imp_fe2); 8142 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 8143 8144 cookie = NULL; 8145 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 8146 NULL) { 8147 free((char *)old_dpt->sc_pgroup_name); 8148 free((char *)old_dpt->sc_pgroup_fmri); 8149 internal_pgroup_free(old_dpt); 8150 } 8151 uu_list_destroy(imp_deleted_dpts); 8152 8153 scf_transaction_destroy(imp_tx); 8154 imp_tx = NULL; 8155 scf_iter_destroy(imp_iter); 8156 scf_iter_destroy(imp_rpg_iter); 8157 scf_iter_destroy(imp_up_iter); 8158 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 8159 scf_property_destroy(imp_prop); 8160 imp_prop = NULL; 8161 scf_pg_destroy(imp_pg); 8162 scf_pg_destroy(imp_pg2); 8163 imp_pg = imp_pg2 = NULL; 8164 scf_snaplevel_destroy(imp_snpl); 8165 scf_snaplevel_destroy(imp_rsnpl); 8166 imp_snpl = imp_rsnpl = NULL; 8167 scf_snapshot_destroy(imp_snap); 8168 scf_snapshot_destroy(imp_lisnap); 8169 scf_snapshot_destroy(imp_tlisnap); 8170 scf_snapshot_destroy(imp_rsnap); 8171 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 8172 scf_instance_destroy(imp_inst); 8173 scf_instance_destroy(imp_tinst); 8174 imp_inst = imp_tinst = NULL; 8175 scf_service_destroy(imp_svc); 8176 scf_service_destroy(imp_tsvc); 8177 imp_svc = imp_tsvc = NULL; 8178 scf_scope_destroy(imp_scope); 8179 imp_scope = NULL; 8180 8181 load_fini(); 8182 } 8183 8184 int 8185 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 8186 { 8187 scf_callback_t cbdata; 8188 int result = 0; 8189 entity_t *svc, *inst; 8190 uu_list_t *insts; 8191 int r; 8192 pgroup_t *old_dpt; 8193 int annotation_set = 0; 8194 8195 const char * const emsg_nomem = gettext("Out of memory.\n"); 8196 const char * const emsg_nores = 8197 gettext("svc.configd is out of resources.\n"); 8198 8199 lscf_prep_hndl(); 8200 8201 if (alloc_imp_globals()) 8202 goto out; 8203 8204 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 8205 switch (scf_error()) { 8206 case SCF_ERROR_CONNECTION_BROKEN: 8207 warn(gettext("Repository connection broken.\n")); 8208 repository_teardown(); 8209 result = -1; 8210 goto out; 8211 8212 case SCF_ERROR_NOT_FOUND: 8213 case SCF_ERROR_INVALID_ARGUMENT: 8214 case SCF_ERROR_NOT_BOUND: 8215 case SCF_ERROR_HANDLE_MISMATCH: 8216 default: 8217 bad_error("scf_handle_get_scope", scf_error()); 8218 } 8219 } 8220 8221 /* Set up the auditing annotation. */ 8222 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 8223 annotation_set = 1; 8224 } else { 8225 switch (scf_error()) { 8226 case SCF_ERROR_CONNECTION_BROKEN: 8227 warn(gettext("Repository connection broken.\n")); 8228 repository_teardown(); 8229 result = -1; 8230 goto out; 8231 8232 case SCF_ERROR_INVALID_ARGUMENT: 8233 case SCF_ERROR_NOT_BOUND: 8234 case SCF_ERROR_NO_RESOURCES: 8235 case SCF_ERROR_INTERNAL: 8236 bad_error("_scf_set_annotation", scf_error()); 8237 /* NOTREACHED */ 8238 8239 default: 8240 /* 8241 * Do not terminate import because of inability to 8242 * generate annotation audit event. 8243 */ 8244 warn(gettext("_scf_set_annotation() unexpectedly " 8245 "failed with return code of %d\n"), scf_error()); 8246 break; 8247 } 8248 } 8249 8250 /* 8251 * Clear the sc_import_state's of all services & instances so we can 8252 * report how far we got if we fail. 8253 */ 8254 for (svc = uu_list_first(bndl->sc_bundle_services); 8255 svc != NULL; 8256 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8257 svc->sc_import_state = 0; 8258 8259 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 8260 clear_int, (void *)offsetof(entity_t, sc_import_state), 8261 UU_DEFAULT) != 0) 8262 bad_error("uu_list_walk", uu_error()); 8263 } 8264 8265 cbdata.sc_handle = g_hndl; 8266 cbdata.sc_parent = imp_scope; 8267 cbdata.sc_flags = flags; 8268 cbdata.sc_general = NULL; 8269 8270 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 8271 &cbdata, UU_DEFAULT) == 0) { 8272 char *eptr; 8273 /* Success. Refresh everything. */ 8274 8275 if (flags & SCI_NOREFRESH || no_refresh) { 8276 no_refresh = 0; 8277 result = 0; 8278 goto out; 8279 } 8280 8281 for (svc = uu_list_first(bndl->sc_bundle_services); 8282 svc != NULL; 8283 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8284 pgroup_t *dpt; 8285 8286 insts = svc->sc_u.sc_service.sc_service_instances; 8287 8288 for (inst = uu_list_first(insts); 8289 inst != NULL; 8290 inst = uu_list_next(insts, inst)) { 8291 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 8292 switch (r) { 8293 case 0: 8294 break; 8295 8296 case ENOMEM: 8297 case ECONNABORTED: 8298 case EPERM: 8299 case -1: 8300 goto progress; 8301 8302 default: 8303 bad_error("imp_refresh_fmri", r); 8304 } 8305 8306 inst->sc_import_state = IMPORT_REFRESHED; 8307 8308 for (dpt = uu_list_first(inst->sc_dependents); 8309 dpt != NULL; 8310 dpt = uu_list_next(inst->sc_dependents, 8311 dpt)) 8312 if (imp_refresh_fmri( 8313 dpt->sc_pgroup_fmri, 8314 dpt->sc_pgroup_name, 8315 inst->sc_fmri) != 0) 8316 goto progress; 8317 } 8318 8319 for (dpt = uu_list_first(svc->sc_dependents); 8320 dpt != NULL; 8321 dpt = uu_list_next(svc->sc_dependents, dpt)) 8322 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 8323 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 8324 goto progress; 8325 } 8326 8327 for (old_dpt = uu_list_first(imp_deleted_dpts); 8328 old_dpt != NULL; 8329 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 8330 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8331 old_dpt->sc_pgroup_name, 8332 old_dpt->sc_parent->sc_fmri) != 0) 8333 goto progress; 8334 8335 result = 0; 8336 8337 /* 8338 * This snippet of code assumes that we are running svccfg as we 8339 * normally do -- witih svc.startd running. Of course, that is 8340 * not actually the case all the time because we also use a 8341 * varient of svc.configd and svccfg which are only meant to 8342 * run during the build process. During this time we have no 8343 * svc.startd, so this check would hang the build process. 8344 * 8345 * However, we've also given other consolidations, a bit of a 8346 * means to tie themselves into a knot. They're not properly 8347 * using the native build equivalents, but they've been getting 8348 * away with it anyways. Therefore, if we've found that 8349 * SVCCFG_REPOSITORY is set indicating that a separate configd 8350 * should be spun up, then we have to assume it's not using a 8351 * startd and we should not do this check. 8352 */ 8353 #ifndef NATIVE_BUILD 8354 /* 8355 * Verify that the restarter group is preset 8356 */ 8357 eptr = getenv("SVCCFG_REPOSITORY"); 8358 for (svc = uu_list_first(bndl->sc_bundle_services); 8359 svc != NULL && eptr == NULL; 8360 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8361 8362 insts = svc->sc_u.sc_service.sc_service_instances; 8363 8364 for (inst = uu_list_first(insts); 8365 inst != NULL; 8366 inst = uu_list_next(insts, inst)) { 8367 if (lscf_instance_verify(imp_scope, svc, 8368 inst) != 0) 8369 goto progress; 8370 } 8371 } 8372 #endif 8373 goto out; 8374 8375 } 8376 8377 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8378 bad_error("uu_list_walk", uu_error()); 8379 8380 printerr: 8381 /* If the error hasn't been printed yet, do so here. */ 8382 switch (cbdata.sc_err) { 8383 case ECONNABORTED: 8384 warn(gettext("Repository connection broken.\n")); 8385 break; 8386 8387 case ENOMEM: 8388 warn(emsg_nomem); 8389 break; 8390 8391 case ENOSPC: 8392 warn(emsg_nores); 8393 break; 8394 8395 case EROFS: 8396 warn(gettext("Repository is read-only.\n")); 8397 break; 8398 8399 case EACCES: 8400 warn(gettext("Repository backend denied access.\n")); 8401 break; 8402 8403 case EPERM: 8404 case EINVAL: 8405 case EEXIST: 8406 case EBUSY: 8407 case EBADF: 8408 case -1: 8409 break; 8410 8411 default: 8412 bad_error("lscf_service_import", cbdata.sc_err); 8413 } 8414 8415 progress: 8416 warn(gettext("Import of %s failed. Progress:\n"), filename); 8417 8418 for (svc = uu_list_first(bndl->sc_bundle_services); 8419 svc != NULL; 8420 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8421 insts = svc->sc_u.sc_service.sc_service_instances; 8422 8423 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 8424 import_progress(svc->sc_import_state)); 8425 8426 for (inst = uu_list_first(insts); 8427 inst != NULL; 8428 inst = uu_list_next(insts, inst)) 8429 warn(gettext(" Instance \"%s\": %s\n"), 8430 inst->sc_name, 8431 import_progress(inst->sc_import_state)); 8432 } 8433 8434 if (cbdata.sc_err == ECONNABORTED) 8435 repository_teardown(); 8436 8437 8438 result = -1; 8439 8440 out: 8441 if (annotation_set != 0) { 8442 /* Turn off annotation. It is no longer needed. */ 8443 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8444 } 8445 8446 free_imp_globals(); 8447 8448 return (result); 8449 } 8450 8451 /* 8452 * _lscf_import_err() summarize the error handling returned by 8453 * lscf_import_{instance | service}_pgs 8454 * Return values are: 8455 * IMPORT_NEXT 8456 * IMPORT_OUT 8457 * IMPORT_BAD 8458 */ 8459 8460 #define IMPORT_BAD -1 8461 #define IMPORT_NEXT 0 8462 #define IMPORT_OUT 1 8463 8464 static int 8465 _lscf_import_err(int err, const char *fmri) 8466 { 8467 switch (err) { 8468 case 0: 8469 if (g_verbose) 8470 warn(gettext("%s updated.\n"), fmri); 8471 return (IMPORT_NEXT); 8472 8473 case ECONNABORTED: 8474 warn(gettext("Could not update %s " 8475 "(repository connection broken).\n"), fmri); 8476 return (IMPORT_OUT); 8477 8478 case ENOMEM: 8479 warn(gettext("Could not update %s (out of memory).\n"), fmri); 8480 return (IMPORT_OUT); 8481 8482 case ENOSPC: 8483 warn(gettext("Could not update %s " 8484 "(repository server out of resources).\n"), fmri); 8485 return (IMPORT_OUT); 8486 8487 case ECANCELED: 8488 warn(gettext( 8489 "Could not update %s (deleted).\n"), fmri); 8490 return (IMPORT_NEXT); 8491 8492 case EPERM: 8493 case EINVAL: 8494 case EBUSY: 8495 return (IMPORT_NEXT); 8496 8497 case EROFS: 8498 warn(gettext("Could not update %s (repository read-only).\n"), 8499 fmri); 8500 return (IMPORT_OUT); 8501 8502 case EACCES: 8503 warn(gettext("Could not update %s " 8504 "(backend access denied).\n"), fmri); 8505 return (IMPORT_NEXT); 8506 8507 case EEXIST: 8508 default: 8509 return (IMPORT_BAD); 8510 } 8511 8512 /*NOTREACHED*/ 8513 } 8514 8515 /* 8516 * The global imp_svc and imp_inst should be set by the caller in the 8517 * check to make sure the service and instance exist that the apply is 8518 * working on. 8519 */ 8520 static int 8521 lscf_dependent_apply(void *dpg, void *e) 8522 { 8523 scf_callback_t cb; 8524 pgroup_t *dpt_pgroup = dpg; 8525 pgroup_t *deldpt; 8526 entity_t *ent = e; 8527 int tissvc; 8528 void *sc_ent, *tent; 8529 scf_error_t serr; 8530 int r; 8531 8532 const char * const dependents = "dependents"; 8533 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT); 8534 8535 if (issvc) 8536 sc_ent = imp_svc; 8537 else 8538 sc_ent = imp_inst; 8539 8540 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg, 8541 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 || 8542 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name, 8543 imp_prop) != 0) { 8544 switch (scf_error()) { 8545 case SCF_ERROR_NOT_FOUND: 8546 case SCF_ERROR_DELETED: 8547 break; 8548 8549 case SCF_ERROR_CONNECTION_BROKEN: 8550 case SCF_ERROR_NOT_SET: 8551 case SCF_ERROR_INVALID_ARGUMENT: 8552 case SCF_ERROR_HANDLE_MISMATCH: 8553 case SCF_ERROR_NOT_BOUND: 8554 default: 8555 bad_error("entity_get_pg", scf_error()); 8556 } 8557 } else { 8558 /* 8559 * Found the dependents/<wip dep> so check to 8560 * see if the service is different. If so 8561 * store the service for later refresh, and 8562 * delete the wip dependency from the service 8563 */ 8564 if (scf_property_get_value(imp_prop, ud_val) != 0) { 8565 switch (scf_error()) { 8566 case SCF_ERROR_DELETED: 8567 break; 8568 8569 case SCF_ERROR_CONNECTION_BROKEN: 8570 case SCF_ERROR_NOT_SET: 8571 case SCF_ERROR_INVALID_ARGUMENT: 8572 case SCF_ERROR_HANDLE_MISMATCH: 8573 case SCF_ERROR_NOT_BOUND: 8574 default: 8575 bad_error("scf_property_get_value", 8576 scf_error()); 8577 } 8578 } 8579 8580 if (scf_value_get_as_string(ud_val, ud_oldtarg, 8581 max_scf_value_len + 1) < 0) 8582 bad_error("scf_value_get_as_string", scf_error()); 8583 8584 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 8585 switch (r) { 8586 case 1: 8587 break; 8588 case 0: 8589 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent, 8590 &tissvc)) != SCF_ERROR_NONE) { 8591 if (serr == SCF_ERROR_NOT_FOUND) { 8592 break; 8593 } else { 8594 bad_error("fmri_to_entity", serr); 8595 } 8596 } 8597 8598 if (entity_get_pg(tent, tissvc, 8599 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) { 8600 serr = scf_error(); 8601 if (serr == SCF_ERROR_NOT_FOUND || 8602 serr == SCF_ERROR_DELETED) { 8603 break; 8604 } else { 8605 bad_error("entity_get_pg", scf_error()); 8606 } 8607 } 8608 8609 if (scf_pg_delete(imp_pg) != 0) { 8610 serr = scf_error(); 8611 if (serr == SCF_ERROR_NOT_FOUND || 8612 serr == SCF_ERROR_DELETED) { 8613 break; 8614 } else { 8615 bad_error("scf_pg_delete", scf_error()); 8616 } 8617 } 8618 8619 deldpt = internal_pgroup_new(); 8620 if (deldpt == NULL) 8621 return (ENOMEM); 8622 deldpt->sc_pgroup_name = 8623 strdup(dpt_pgroup->sc_pgroup_name); 8624 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg); 8625 if (deldpt->sc_pgroup_name == NULL || 8626 deldpt->sc_pgroup_fmri == NULL) 8627 return (ENOMEM); 8628 deldpt->sc_parent = (entity_t *)ent; 8629 if (uu_list_insert_after(imp_deleted_dpts, NULL, 8630 deldpt) != 0) 8631 uu_die(gettext("libuutil error: %s\n"), 8632 uu_strerror(uu_error())); 8633 8634 break; 8635 default: 8636 bad_error("fmri_equal", r); 8637 } 8638 } 8639 8640 cb.sc_handle = g_hndl; 8641 cb.sc_parent = ent; 8642 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT; 8643 cb.sc_source_fmri = ent->sc_fmri; 8644 cb.sc_target_fmri = ent->sc_fmri; 8645 cb.sc_trans = NULL; 8646 cb.sc_flags = SCI_FORCE; 8647 8648 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT) 8649 return (UU_WALK_ERROR); 8650 8651 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL); 8652 switch (r) { 8653 case 0: 8654 break; 8655 8656 case ENOMEM: 8657 case ECONNABORTED: 8658 case EPERM: 8659 case -1: 8660 warn(gettext("Unable to refresh \"%s\"\n"), 8661 dpt_pgroup->sc_pgroup_fmri); 8662 return (UU_WALK_ERROR); 8663 8664 default: 8665 bad_error("imp_refresh_fmri", r); 8666 } 8667 8668 return (UU_WALK_NEXT); 8669 } 8670 8671 /* 8672 * Returns 8673 * 0 - success 8674 * -1 - lscf_import_instance_pgs() failed. 8675 */ 8676 int 8677 lscf_bundle_apply(bundle_t *bndl, const char *file) 8678 { 8679 pgroup_t *old_dpt; 8680 entity_t *svc, *inst; 8681 int annotation_set = 0; 8682 int ret = 0; 8683 int r = 0; 8684 8685 lscf_prep_hndl(); 8686 8687 if ((ret = alloc_imp_globals())) 8688 goto out; 8689 8690 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) 8691 scfdie(); 8692 8693 /* 8694 * Set the strings to be used for the security audit annotation 8695 * event. 8696 */ 8697 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 8698 annotation_set = 1; 8699 } else { 8700 switch (scf_error()) { 8701 case SCF_ERROR_CONNECTION_BROKEN: 8702 warn(gettext("Repository connection broken.\n")); 8703 goto out; 8704 8705 case SCF_ERROR_INVALID_ARGUMENT: 8706 case SCF_ERROR_NOT_BOUND: 8707 case SCF_ERROR_NO_RESOURCES: 8708 case SCF_ERROR_INTERNAL: 8709 bad_error("_scf_set_annotation", scf_error()); 8710 /* NOTREACHED */ 8711 8712 default: 8713 /* 8714 * Do not abort apply operation because of 8715 * inability to create annotation audit event. 8716 */ 8717 warn(gettext("_scf_set_annotation() unexpectedly " 8718 "failed with return code of %d\n"), scf_error()); 8719 break; 8720 } 8721 } 8722 8723 for (svc = uu_list_first(bndl->sc_bundle_services); 8724 svc != NULL; 8725 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8726 int refresh = 0; 8727 8728 if (scf_scope_get_service(imp_scope, svc->sc_name, 8729 imp_svc) != 0) { 8730 switch (scf_error()) { 8731 case SCF_ERROR_NOT_FOUND: 8732 if (g_verbose) 8733 warn(gettext("Ignoring nonexistent " 8734 "service %s.\n"), svc->sc_name); 8735 continue; 8736 8737 default: 8738 scfdie(); 8739 } 8740 } 8741 8742 /* 8743 * If there were missing types in the profile, then need to 8744 * attempt to find the types. 8745 */ 8746 if (svc->sc_miss_type) { 8747 if (uu_list_numnodes(svc->sc_pgroups) && 8748 uu_list_walk(svc->sc_pgroups, find_current_pg_type, 8749 svc, UU_DEFAULT) != 0) { 8750 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8751 bad_error("uu_list_walk", uu_error()); 8752 8753 ret = -1; 8754 continue; 8755 } 8756 8757 for (inst = uu_list_first( 8758 svc->sc_u.sc_service.sc_service_instances); 8759 inst != NULL; 8760 inst = uu_list_next( 8761 svc->sc_u.sc_service.sc_service_instances, inst)) { 8762 /* 8763 * If the instance doesn't exist just 8764 * skip to the next instance and let the 8765 * import note the missing instance. 8766 */ 8767 if (scf_service_get_instance(imp_svc, 8768 inst->sc_name, imp_inst) != 0) 8769 continue; 8770 8771 if (uu_list_walk(inst->sc_pgroups, 8772 find_current_pg_type, inst, 8773 UU_DEFAULT) != 0) { 8774 if (uu_error() != 8775 UU_ERROR_CALLBACK_FAILED) 8776 bad_error("uu_list_walk", 8777 uu_error()); 8778 8779 ret = -1; 8780 inst->sc_miss_type = B_TRUE; 8781 } 8782 } 8783 } 8784 8785 /* 8786 * if we have pgs in the profile, we need to refresh ALL 8787 * instances of the service 8788 */ 8789 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 8790 refresh = 1; 8791 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc, 8792 SCI_FORCE | SCI_KEEP); 8793 switch (_lscf_import_err(r, svc->sc_fmri)) { 8794 case IMPORT_NEXT: 8795 break; 8796 8797 case IMPORT_OUT: 8798 goto out; 8799 8800 case IMPORT_BAD: 8801 default: 8802 bad_error("lscf_import_service_pgs", r); 8803 } 8804 } 8805 8806 if (uu_list_numnodes(svc->sc_dependents) != 0) { 8807 uu_list_walk(svc->sc_dependents, 8808 lscf_dependent_apply, svc, UU_DEFAULT); 8809 } 8810 8811 for (inst = uu_list_first( 8812 svc->sc_u.sc_service.sc_service_instances); 8813 inst != NULL; 8814 inst = uu_list_next( 8815 svc->sc_u.sc_service.sc_service_instances, inst)) { 8816 /* 8817 * This instance still has missing types 8818 * so skip it. 8819 */ 8820 if (inst->sc_miss_type) { 8821 if (g_verbose) 8822 warn(gettext("Ignoring instance " 8823 "%s:%s with missing types\n"), 8824 inst->sc_parent->sc_name, 8825 inst->sc_name); 8826 8827 continue; 8828 } 8829 8830 if (scf_service_get_instance(imp_svc, inst->sc_name, 8831 imp_inst) != 0) { 8832 switch (scf_error()) { 8833 case SCF_ERROR_NOT_FOUND: 8834 if (g_verbose) 8835 warn(gettext("Ignoring " 8836 "nonexistant instance " 8837 "%s:%s.\n"), 8838 inst->sc_parent->sc_name, 8839 inst->sc_name); 8840 continue; 8841 8842 default: 8843 scfdie(); 8844 } 8845 } 8846 8847 /* 8848 * If the instance does not have a general/enabled 8849 * property and no last-import snapshot then the 8850 * instance is not a fully installed instance and 8851 * should not have a profile applied to it. 8852 * 8853 * This could happen if a service/instance declares 8854 * a dependent on behalf of another service/instance. 8855 * 8856 */ 8857 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 8858 imp_snap) != 0) { 8859 if (scf_instance_get_pg(imp_inst, 8860 SCF_PG_GENERAL, imp_pg) != 0 || 8861 scf_pg_get_property(imp_pg, 8862 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 8863 if (g_verbose) 8864 warn(gettext("Ignoreing " 8865 "partial instance " 8866 "%s:%s.\n"), 8867 inst->sc_parent->sc_name, 8868 inst->sc_name); 8869 continue; 8870 } 8871 } 8872 8873 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, 8874 inst, SCI_FORCE | SCI_KEEP); 8875 switch (_lscf_import_err(r, inst->sc_fmri)) { 8876 case IMPORT_NEXT: 8877 break; 8878 8879 case IMPORT_OUT: 8880 goto out; 8881 8882 case IMPORT_BAD: 8883 default: 8884 bad_error("lscf_import_instance_pgs", r); 8885 } 8886 8887 if (uu_list_numnodes(inst->sc_dependents) != 0) { 8888 uu_list_walk(inst->sc_dependents, 8889 lscf_dependent_apply, inst, UU_DEFAULT); 8890 } 8891 8892 /* refresh only if there is no pgs in the service */ 8893 if (refresh == 0) 8894 (void) refresh_entity(0, imp_inst, 8895 inst->sc_fmri, NULL, NULL, NULL); 8896 } 8897 8898 if (refresh == 1) { 8899 char *name_buf = safe_malloc(max_scf_name_len + 1); 8900 8901 (void) refresh_entity(1, imp_svc, svc->sc_name, 8902 imp_inst, imp_iter, name_buf); 8903 free(name_buf); 8904 } 8905 8906 for (old_dpt = uu_list_first(imp_deleted_dpts); 8907 old_dpt != NULL; 8908 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) { 8909 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8910 old_dpt->sc_pgroup_name, 8911 old_dpt->sc_parent->sc_fmri) != 0) { 8912 warn(gettext("Unable to refresh \"%s\"\n"), 8913 old_dpt->sc_pgroup_fmri); 8914 } 8915 } 8916 } 8917 8918 out: 8919 if (annotation_set) { 8920 /* Remove security audit annotation strings. */ 8921 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8922 } 8923 8924 free_imp_globals(); 8925 return (ret); 8926 } 8927 8928 8929 /* 8930 * Export. These functions create and output an XML tree of a service 8931 * description from the repository. This is largely the inverse of 8932 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 8933 * 8934 * - We must include any properties which are not represented specifically by 8935 * a service manifest, e.g., properties created by an admin post-import. To 8936 * do so we'll iterate through all properties and deal with each 8937 * apropriately. 8938 * 8939 * - Children of services and instances must must be in the order set by the 8940 * DTD, but we iterate over the properties in undefined order. The elements 8941 * are not easily (or efficiently) sortable by name. Since there's a fixed 8942 * number of classes of them, however, we'll keep the classes separate and 8943 * assemble them in order. 8944 */ 8945 8946 /* 8947 * Convenience function to handle xmlSetProp errors (and type casting). 8948 */ 8949 static void 8950 safe_setprop(xmlNodePtr n, const char *name, const char *val) 8951 { 8952 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 8953 uu_die(gettext("Could not set XML property.\n")); 8954 } 8955 8956 /* 8957 * Convenience function to set an XML attribute to the single value of an 8958 * astring property. If the value happens to be the default, don't set the 8959 * attribute. "dval" should be the default value supplied by the DTD, or 8960 * NULL for no default. 8961 */ 8962 static int 8963 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 8964 const char *name, const char *dval) 8965 { 8966 scf_value_t *val; 8967 ssize_t len; 8968 char *str; 8969 8970 val = scf_value_create(g_hndl); 8971 if (val == NULL) 8972 scfdie(); 8973 8974 if (prop_get_val(prop, val) != 0) { 8975 scf_value_destroy(val); 8976 return (-1); 8977 } 8978 8979 len = scf_value_get_as_string(val, NULL, 0); 8980 if (len < 0) 8981 scfdie(); 8982 8983 str = safe_malloc(len + 1); 8984 8985 if (scf_value_get_as_string(val, str, len + 1) < 0) 8986 scfdie(); 8987 8988 scf_value_destroy(val); 8989 8990 if (dval == NULL || strcmp(str, dval) != 0) 8991 safe_setprop(n, name, str); 8992 8993 free(str); 8994 8995 return (0); 8996 } 8997 8998 /* 8999 * As above, but the attribute is always set. 9000 */ 9001 static int 9002 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 9003 { 9004 return (set_attr_from_prop_default(prop, n, name, NULL)); 9005 } 9006 9007 /* 9008 * Dump the given document onto f, with "'s replaced by ''s. 9009 */ 9010 static int 9011 write_service_bundle(xmlDocPtr doc, FILE *f) 9012 { 9013 xmlChar *mem; 9014 int sz, i; 9015 9016 mem = NULL; 9017 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 9018 9019 if (mem == NULL) { 9020 semerr(gettext("Could not dump XML tree.\n")); 9021 return (-1); 9022 } 9023 9024 /* 9025 * Fortunately libxml produces " instead of ", so we can blindly 9026 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 9027 * ' code?! 9028 */ 9029 for (i = 0; i < sz; ++i) { 9030 char c = (char)mem[i]; 9031 9032 if (c == '"') 9033 (void) fputc('\'', f); 9034 else if (c == '\'') 9035 (void) fwrite("'", sizeof ("'") - 1, 1, f); 9036 else 9037 (void) fputc(c, f); 9038 } 9039 9040 return (0); 9041 } 9042 9043 /* 9044 * Create the DOM elements in elts necessary to (generically) represent prop 9045 * (i.e., a property or propval element). If the name of the property is 9046 * known, it should be passed as name_arg. Otherwise, pass NULL. 9047 */ 9048 static void 9049 export_property(scf_property_t *prop, const char *name_arg, 9050 struct pg_elts *elts, int flags) 9051 { 9052 const char *type; 9053 scf_error_t err = 0; 9054 xmlNodePtr pnode, lnode; 9055 char *lnname; 9056 int ret; 9057 9058 /* name */ 9059 if (name_arg != NULL) { 9060 (void) strcpy(exp_str, name_arg); 9061 } else { 9062 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 9063 scfdie(); 9064 } 9065 9066 /* type */ 9067 type = prop_to_typestr(prop); 9068 if (type == NULL) 9069 uu_die(gettext("Can't export property %s: unknown type.\n"), 9070 exp_str); 9071 9072 /* If we're exporting values, and there's just one, export it here. */ 9073 if (!(flags & SCE_ALL_VALUES)) 9074 goto empty; 9075 9076 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 9077 xmlNodePtr n; 9078 9079 /* Single value, so use propval */ 9080 n = xmlNewNode(NULL, (xmlChar *)"propval"); 9081 if (n == NULL) 9082 uu_die(emsg_create_xml); 9083 9084 safe_setprop(n, name_attr, exp_str); 9085 safe_setprop(n, type_attr, type); 9086 9087 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9088 scfdie(); 9089 safe_setprop(n, value_attr, exp_str); 9090 9091 if (elts->propvals == NULL) 9092 elts->propvals = n; 9093 else 9094 (void) xmlAddSibling(elts->propvals, n); 9095 9096 return; 9097 } 9098 9099 err = scf_error(); 9100 9101 if (err == SCF_ERROR_PERMISSION_DENIED) { 9102 semerr(emsg_permission_denied); 9103 return; 9104 } 9105 9106 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 9107 err != SCF_ERROR_NOT_FOUND && 9108 err != SCF_ERROR_PERMISSION_DENIED) 9109 scfdie(); 9110 9111 empty: 9112 /* Multiple (or no) values, so use property */ 9113 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 9114 if (pnode == NULL) 9115 uu_die(emsg_create_xml); 9116 9117 safe_setprop(pnode, name_attr, exp_str); 9118 safe_setprop(pnode, type_attr, type); 9119 9120 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 9121 lnname = uu_msprintf("%s_list", type); 9122 if (lnname == NULL) 9123 uu_die(gettext("Could not create string")); 9124 9125 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 9126 if (lnode == NULL) 9127 uu_die(emsg_create_xml); 9128 9129 uu_free(lnname); 9130 9131 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 9132 scfdie(); 9133 9134 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 9135 1) { 9136 xmlNodePtr vn; 9137 9138 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 9139 NULL); 9140 if (vn == NULL) 9141 uu_die(emsg_create_xml); 9142 9143 if (scf_value_get_as_string(exp_val, exp_str, 9144 exp_str_sz) < 0) 9145 scfdie(); 9146 safe_setprop(vn, value_attr, exp_str); 9147 } 9148 if (ret != 0) 9149 scfdie(); 9150 } 9151 9152 if (elts->properties == NULL) 9153 elts->properties = pnode; 9154 else 9155 (void) xmlAddSibling(elts->properties, pnode); 9156 } 9157 9158 /* 9159 * Add a property_group element for this property group to elts. 9160 */ 9161 static void 9162 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 9163 { 9164 xmlNodePtr n; 9165 struct pg_elts elts; 9166 int ret; 9167 boolean_t read_protected; 9168 9169 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 9170 9171 /* name */ 9172 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9173 scfdie(); 9174 safe_setprop(n, name_attr, exp_str); 9175 9176 /* type */ 9177 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 9178 scfdie(); 9179 safe_setprop(n, type_attr, exp_str); 9180 9181 /* properties */ 9182 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9183 scfdie(); 9184 9185 (void) memset(&elts, 0, sizeof (elts)); 9186 9187 /* 9188 * If this property group is not read protected, we always want to 9189 * output all the values. Otherwise, we only output the values if the 9190 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 9191 */ 9192 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 9193 scfdie(); 9194 9195 if (!read_protected) 9196 flags |= SCE_ALL_VALUES; 9197 9198 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9199 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9200 scfdie(); 9201 9202 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9203 xmlNodePtr m; 9204 9205 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9206 if (m == NULL) 9207 uu_die(emsg_create_xml); 9208 9209 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9210 elts.stability = m; 9211 continue; 9212 } 9213 9214 xmlFreeNode(m); 9215 } 9216 9217 export_property(exp_prop, NULL, &elts, flags); 9218 } 9219 if (ret == -1) 9220 scfdie(); 9221 9222 (void) xmlAddChild(n, elts.stability); 9223 (void) xmlAddChildList(n, elts.propvals); 9224 (void) xmlAddChildList(n, elts.properties); 9225 9226 if (eelts->property_groups == NULL) 9227 eelts->property_groups = n; 9228 else 9229 (void) xmlAddSibling(eelts->property_groups, n); 9230 } 9231 9232 /* 9233 * Create an XML node representing the dependency described by the given 9234 * property group and put it in eelts. Unless the dependency is not valid, in 9235 * which case create a generic property_group element which represents it and 9236 * put it in eelts. 9237 */ 9238 static void 9239 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 9240 { 9241 xmlNodePtr n; 9242 int err = 0, ret; 9243 struct pg_elts elts; 9244 9245 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 9246 if (n == NULL) 9247 uu_die(emsg_create_xml); 9248 9249 /* 9250 * If the external flag is present, skip this dependency because it 9251 * should have been created by another manifest. 9252 */ 9253 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 9254 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9255 prop_get_val(exp_prop, exp_val) == 0) { 9256 uint8_t b; 9257 9258 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 9259 scfdie(); 9260 9261 if (b) 9262 return; 9263 } 9264 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 9265 scfdie(); 9266 9267 /* Get the required attributes. */ 9268 9269 /* name */ 9270 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9271 scfdie(); 9272 safe_setprop(n, name_attr, exp_str); 9273 9274 /* grouping */ 9275 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9276 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9277 err = 1; 9278 9279 /* restart_on */ 9280 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9281 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9282 err = 1; 9283 9284 /* type */ 9285 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9286 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9287 err = 1; 9288 9289 /* 9290 * entities: Not required, but if we create no children, it will be 9291 * created as empty on import, so fail if it's missing. 9292 */ 9293 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9294 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 9295 scf_iter_t *eiter; 9296 int ret2; 9297 9298 eiter = scf_iter_create(g_hndl); 9299 if (eiter == NULL) 9300 scfdie(); 9301 9302 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 9303 scfdie(); 9304 9305 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 9306 xmlNodePtr ch; 9307 9308 if (scf_value_get_astring(exp_val, exp_str, 9309 exp_str_sz) < 0) 9310 scfdie(); 9311 9312 /* 9313 * service_fmri's must be first, so we can add them 9314 * here. 9315 */ 9316 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 9317 NULL); 9318 if (ch == NULL) 9319 uu_die(emsg_create_xml); 9320 9321 safe_setprop(ch, value_attr, exp_str); 9322 } 9323 if (ret2 == -1) 9324 scfdie(); 9325 9326 scf_iter_destroy(eiter); 9327 } else 9328 err = 1; 9329 9330 if (err) { 9331 xmlFreeNode(n); 9332 9333 export_pg(pg, eelts, SCE_ALL_VALUES); 9334 9335 return; 9336 } 9337 9338 /* Iterate through the properties & handle each. */ 9339 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9340 scfdie(); 9341 9342 (void) memset(&elts, 0, sizeof (elts)); 9343 9344 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9345 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9346 scfdie(); 9347 9348 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9349 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9350 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9351 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9352 continue; 9353 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9354 xmlNodePtr m; 9355 9356 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9357 if (m == NULL) 9358 uu_die(emsg_create_xml); 9359 9360 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9361 elts.stability = m; 9362 continue; 9363 } 9364 9365 xmlFreeNode(m); 9366 } 9367 9368 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9369 } 9370 if (ret == -1) 9371 scfdie(); 9372 9373 (void) xmlAddChild(n, elts.stability); 9374 (void) xmlAddChildList(n, elts.propvals); 9375 (void) xmlAddChildList(n, elts.properties); 9376 9377 if (eelts->dependencies == NULL) 9378 eelts->dependencies = n; 9379 else 9380 (void) xmlAddSibling(eelts->dependencies, n); 9381 } 9382 9383 static xmlNodePtr 9384 export_method_environment(scf_propertygroup_t *pg) 9385 { 9386 xmlNodePtr env; 9387 int ret; 9388 int children = 0; 9389 9390 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 9391 return (NULL); 9392 9393 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 9394 if (env == NULL) 9395 uu_die(emsg_create_xml); 9396 9397 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 9398 scfdie(); 9399 9400 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 9401 scfdie(); 9402 9403 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 9404 xmlNodePtr ev; 9405 char *cp; 9406 9407 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9408 scfdie(); 9409 9410 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 9411 warn(gettext("Invalid environment variable \"%s\".\n"), 9412 exp_str); 9413 continue; 9414 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 9415 warn(gettext("Invalid environment variable \"%s\"; " 9416 "\"SMF_\" prefix is reserved.\n"), exp_str); 9417 continue; 9418 } 9419 9420 *cp = '\0'; 9421 cp++; 9422 9423 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 9424 if (ev == NULL) 9425 uu_die(emsg_create_xml); 9426 9427 safe_setprop(ev, name_attr, exp_str); 9428 safe_setprop(ev, value_attr, cp); 9429 children++; 9430 } 9431 9432 if (ret != 0) 9433 scfdie(); 9434 9435 if (children == 0) { 9436 xmlFreeNode(env); 9437 return (NULL); 9438 } 9439 9440 return (env); 9441 } 9442 9443 /* 9444 * As above, but for a method property group. 9445 */ 9446 static void 9447 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 9448 { 9449 xmlNodePtr n, env; 9450 char *str; 9451 int err = 0, nonenv, ret; 9452 uint8_t use_profile; 9453 struct pg_elts elts; 9454 xmlNodePtr ctxt = NULL; 9455 9456 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 9457 9458 /* Get the required attributes. */ 9459 9460 /* name */ 9461 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9462 scfdie(); 9463 safe_setprop(n, name_attr, exp_str); 9464 9465 /* type */ 9466 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9467 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9468 err = 1; 9469 9470 /* exec */ 9471 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 9472 set_attr_from_prop(exp_prop, n, "exec") != 0) 9473 err = 1; 9474 9475 /* timeout */ 9476 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 9477 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 9478 prop_get_val(exp_prop, exp_val) == 0) { 9479 uint64_t c; 9480 9481 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 9482 scfdie(); 9483 9484 str = uu_msprintf("%llu", c); 9485 if (str == NULL) 9486 uu_die(gettext("Could not create string")); 9487 9488 safe_setprop(n, "timeout_seconds", str); 9489 free(str); 9490 } else 9491 err = 1; 9492 9493 if (err) { 9494 xmlFreeNode(n); 9495 9496 export_pg(pg, eelts, SCE_ALL_VALUES); 9497 9498 return; 9499 } 9500 9501 9502 /* 9503 * If we're going to have a method_context child, we need to know 9504 * before we iterate through the properties. Since method_context's 9505 * are optional, we don't want to complain about any properties 9506 * missing if none of them are there. Thus we can't use the 9507 * convenience functions. 9508 */ 9509 nonenv = 9510 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 9511 SCF_SUCCESS || 9512 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 9513 SCF_SUCCESS || 9514 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 9515 SCF_SUCCESS || 9516 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) == 9517 SCF_SUCCESS || 9518 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 9519 SCF_SUCCESS; 9520 9521 if (nonenv) { 9522 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9523 if (ctxt == NULL) 9524 uu_die(emsg_create_xml); 9525 9526 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 9527 0 && 9528 set_attr_from_prop_default(exp_prop, ctxt, 9529 "working_directory", ":default") != 0) 9530 err = 1; 9531 9532 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 9533 set_attr_from_prop_default(exp_prop, ctxt, "project", 9534 ":default") != 0) 9535 err = 1; 9536 9537 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 9538 0 && 9539 set_attr_from_prop_default(exp_prop, ctxt, 9540 "resource_pool", ":default") != 0) 9541 err = 1; 9542 9543 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 && 9544 set_attr_from_prop_default(exp_prop, ctxt, 9545 "security_flags", ":default") != 0) 9546 err = 1; 9547 9548 /* 9549 * We only want to complain about profile or credential 9550 * properties if we will use them. To determine that we must 9551 * examine USE_PROFILE. 9552 */ 9553 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9554 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9555 prop_get_val(exp_prop, exp_val) == 0) { 9556 if (scf_value_get_boolean(exp_val, &use_profile) != 9557 SCF_SUCCESS) { 9558 scfdie(); 9559 } 9560 9561 if (use_profile) { 9562 xmlNodePtr prof; 9563 9564 prof = xmlNewChild(ctxt, NULL, 9565 (xmlChar *)"method_profile", NULL); 9566 if (prof == NULL) 9567 uu_die(emsg_create_xml); 9568 9569 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 9570 exp_prop) != 0 || 9571 set_attr_from_prop(exp_prop, prof, 9572 name_attr) != 0) 9573 err = 1; 9574 } else { 9575 xmlNodePtr cred; 9576 9577 cred = xmlNewChild(ctxt, NULL, 9578 (xmlChar *)"method_credential", NULL); 9579 if (cred == NULL) 9580 uu_die(emsg_create_xml); 9581 9582 if (pg_get_prop(pg, SCF_PROPERTY_USER, 9583 exp_prop) != 0 || 9584 set_attr_from_prop(exp_prop, cred, 9585 "user") != 0) { 9586 err = 1; 9587 } 9588 9589 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 9590 exp_prop) == 0 && 9591 set_attr_from_prop_default(exp_prop, cred, 9592 "group", ":default") != 0) 9593 err = 1; 9594 9595 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 9596 exp_prop) == 0 && 9597 set_attr_from_prop_default(exp_prop, cred, 9598 "supp_groups", ":default") != 0) 9599 err = 1; 9600 9601 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 9602 exp_prop) == 0 && 9603 set_attr_from_prop_default(exp_prop, cred, 9604 "privileges", ":default") != 0) 9605 err = 1; 9606 9607 if (pg_get_prop(pg, 9608 SCF_PROPERTY_LIMIT_PRIVILEGES, 9609 exp_prop) == 0 && 9610 set_attr_from_prop_default(exp_prop, cred, 9611 "limit_privileges", ":default") != 0) 9612 err = 1; 9613 } 9614 } 9615 } 9616 9617 if ((env = export_method_environment(pg)) != NULL) { 9618 if (ctxt == NULL) { 9619 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9620 if (ctxt == NULL) 9621 uu_die(emsg_create_xml); 9622 } 9623 (void) xmlAddChild(ctxt, env); 9624 } 9625 9626 if (env != NULL || (nonenv && err == 0)) 9627 (void) xmlAddChild(n, ctxt); 9628 else 9629 xmlFreeNode(ctxt); 9630 9631 nonenv = (err == 0); 9632 9633 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9634 scfdie(); 9635 9636 (void) memset(&elts, 0, sizeof (elts)); 9637 9638 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9639 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9640 scfdie(); 9641 9642 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9643 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 9644 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 9645 continue; 9646 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9647 xmlNodePtr m; 9648 9649 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9650 if (m == NULL) 9651 uu_die(emsg_create_xml); 9652 9653 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9654 elts.stability = m; 9655 continue; 9656 } 9657 9658 xmlFreeNode(m); 9659 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 9660 0 || 9661 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 9662 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 9663 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9664 if (nonenv) 9665 continue; 9666 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 9667 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 9668 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 9669 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 9670 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 || 9671 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9672 if (nonenv && !use_profile) 9673 continue; 9674 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9675 if (nonenv && use_profile) 9676 continue; 9677 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 9678 if (env != NULL) 9679 continue; 9680 } 9681 9682 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9683 } 9684 if (ret == -1) 9685 scfdie(); 9686 9687 (void) xmlAddChild(n, elts.stability); 9688 (void) xmlAddChildList(n, elts.propvals); 9689 (void) xmlAddChildList(n, elts.properties); 9690 9691 if (eelts->exec_methods == NULL) 9692 eelts->exec_methods = n; 9693 else 9694 (void) xmlAddSibling(eelts->exec_methods, n); 9695 } 9696 9697 static void 9698 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 9699 struct entity_elts *eelts) 9700 { 9701 xmlNodePtr pgnode; 9702 9703 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 9704 if (pgnode == NULL) 9705 uu_die(emsg_create_xml); 9706 9707 safe_setprop(pgnode, name_attr, name); 9708 safe_setprop(pgnode, type_attr, type); 9709 9710 (void) xmlAddChildList(pgnode, elts->propvals); 9711 (void) xmlAddChildList(pgnode, elts->properties); 9712 9713 if (eelts->property_groups == NULL) 9714 eelts->property_groups = pgnode; 9715 else 9716 (void) xmlAddSibling(eelts->property_groups, pgnode); 9717 } 9718 9719 /* 9720 * Process the general property group for a service. This is the one with the 9721 * goodies. 9722 */ 9723 static void 9724 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 9725 { 9726 struct pg_elts elts; 9727 int ret; 9728 9729 /* 9730 * In case there are properties which don't correspond to child 9731 * entities of the service entity, we'll set up a pg_elts structure to 9732 * put them in. 9733 */ 9734 (void) memset(&elts, 0, sizeof (elts)); 9735 9736 /* Walk the properties, looking for special ones. */ 9737 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9738 scfdie(); 9739 9740 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9741 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9742 scfdie(); 9743 9744 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 9745 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9746 prop_get_val(exp_prop, exp_val) == 0) { 9747 uint8_t b; 9748 9749 if (scf_value_get_boolean(exp_val, &b) != 9750 SCF_SUCCESS) 9751 scfdie(); 9752 9753 if (b) { 9754 selts->single_instance = 9755 xmlNewNode(NULL, 9756 (xmlChar *)"single_instance"); 9757 if (selts->single_instance == NULL) 9758 uu_die(emsg_create_xml); 9759 } 9760 9761 continue; 9762 } 9763 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9764 xmlNodePtr rnode, sfnode; 9765 9766 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9767 if (rnode == NULL) 9768 uu_die(emsg_create_xml); 9769 9770 sfnode = xmlNewChild(rnode, NULL, 9771 (xmlChar *)"service_fmri", NULL); 9772 if (sfnode == NULL) 9773 uu_die(emsg_create_xml); 9774 9775 if (set_attr_from_prop(exp_prop, sfnode, 9776 value_attr) == 0) { 9777 selts->restarter = rnode; 9778 continue; 9779 } 9780 9781 xmlFreeNode(rnode); 9782 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 9783 0) { 9784 xmlNodePtr s; 9785 9786 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9787 if (s == NULL) 9788 uu_die(emsg_create_xml); 9789 9790 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9791 selts->stability = s; 9792 continue; 9793 } 9794 9795 xmlFreeNode(s); 9796 } 9797 9798 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9799 } 9800 if (ret == -1) 9801 scfdie(); 9802 9803 if (elts.propvals != NULL || elts.properties != NULL) 9804 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 9805 selts); 9806 } 9807 9808 static void 9809 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 9810 { 9811 xmlNodePtr n, prof, cred, env; 9812 uint8_t use_profile; 9813 int ret, err = 0; 9814 9815 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 9816 9817 env = export_method_environment(pg); 9818 9819 /* Need to know whether we'll use a profile or not. */ 9820 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9821 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9822 prop_get_val(exp_prop, exp_val) == 0) { 9823 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 9824 scfdie(); 9825 9826 if (use_profile) 9827 prof = 9828 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 9829 NULL); 9830 else 9831 cred = 9832 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 9833 NULL); 9834 } 9835 9836 if (env != NULL) 9837 (void) xmlAddChild(n, env); 9838 9839 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9840 scfdie(); 9841 9842 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9843 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9844 scfdie(); 9845 9846 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 9847 if (set_attr_from_prop(exp_prop, n, 9848 "working_directory") != 0) 9849 err = 1; 9850 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 9851 if (set_attr_from_prop(exp_prop, n, "project") != 0) 9852 err = 1; 9853 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 9854 if (set_attr_from_prop(exp_prop, n, 9855 "resource_pool") != 0) 9856 err = 1; 9857 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9858 if (set_attr_from_prop(exp_prop, n, 9859 "security_flags") != 0) 9860 err = 1; 9861 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9862 /* EMPTY */ 9863 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 9864 if (use_profile || 9865 set_attr_from_prop(exp_prop, cred, "user") != 0) 9866 err = 1; 9867 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 9868 if (use_profile || 9869 set_attr_from_prop(exp_prop, cred, "group") != 0) 9870 err = 1; 9871 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 9872 if (use_profile || set_attr_from_prop(exp_prop, cred, 9873 "supp_groups") != 0) 9874 err = 1; 9875 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 9876 if (use_profile || set_attr_from_prop(exp_prop, cred, 9877 "privileges") != 0) 9878 err = 1; 9879 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 9880 0) { 9881 if (use_profile || set_attr_from_prop(exp_prop, cred, 9882 "limit_privileges") != 0) 9883 err = 1; 9884 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9885 if (!use_profile || set_attr_from_prop(exp_prop, 9886 prof, name_attr) != 0) 9887 err = 1; 9888 } else { 9889 /* Can't have generic properties in method_context's */ 9890 err = 1; 9891 } 9892 } 9893 if (ret == -1) 9894 scfdie(); 9895 9896 if (err && env == NULL) { 9897 xmlFreeNode(n); 9898 export_pg(pg, elts, SCE_ALL_VALUES); 9899 return; 9900 } 9901 9902 elts->method_context = n; 9903 } 9904 9905 /* 9906 * Given a dependency property group in the tfmri entity (target fmri), return 9907 * a dependent element which represents it. 9908 */ 9909 static xmlNodePtr 9910 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 9911 { 9912 uint8_t b; 9913 xmlNodePtr n, sf; 9914 int err = 0, ret; 9915 struct pg_elts pgelts; 9916 9917 /* 9918 * If external isn't set to true then exporting the service will 9919 * export this as a normal dependency, so we should stop to avoid 9920 * duplication. 9921 */ 9922 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 9923 scf_property_get_value(exp_prop, exp_val) != 0 || 9924 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 9925 if (g_verbose) { 9926 warn(gettext("Dependent \"%s\" cannot be exported " 9927 "properly because the \"%s\" property of the " 9928 "\"%s\" dependency of %s is not set to true.\n"), 9929 name, scf_property_external, name, tfmri); 9930 } 9931 9932 return (NULL); 9933 } 9934 9935 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 9936 if (n == NULL) 9937 uu_die(emsg_create_xml); 9938 9939 safe_setprop(n, name_attr, name); 9940 9941 /* Get the required attributes */ 9942 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9943 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9944 err = 1; 9945 9946 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9947 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9948 err = 1; 9949 9950 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9951 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 9952 prop_get_val(exp_prop, exp_val) == 0) { 9953 /* EMPTY */ 9954 } else 9955 err = 1; 9956 9957 if (err) { 9958 xmlFreeNode(n); 9959 return (NULL); 9960 } 9961 9962 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 9963 if (sf == NULL) 9964 uu_die(emsg_create_xml); 9965 9966 safe_setprop(sf, value_attr, tfmri); 9967 9968 /* 9969 * Now add elements for the other properties. 9970 */ 9971 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9972 scfdie(); 9973 9974 (void) memset(&pgelts, 0, sizeof (pgelts)); 9975 9976 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9977 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9978 scfdie(); 9979 9980 if (strcmp(exp_str, scf_property_external) == 0 || 9981 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9982 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9983 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9984 continue; 9985 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 9986 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 9987 prop_get_val(exp_prop, exp_val) == 0) { 9988 char type[sizeof ("service") + 1]; 9989 9990 if (scf_value_get_astring(exp_val, type, 9991 sizeof (type)) < 0) 9992 scfdie(); 9993 9994 if (strcmp(type, "service") == 0) 9995 continue; 9996 } 9997 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9998 xmlNodePtr s; 9999 10000 s = xmlNewNode(NULL, (xmlChar *)"stability"); 10001 if (s == NULL) 10002 uu_die(emsg_create_xml); 10003 10004 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 10005 pgelts.stability = s; 10006 continue; 10007 } 10008 10009 xmlFreeNode(s); 10010 } 10011 10012 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10013 } 10014 if (ret == -1) 10015 scfdie(); 10016 10017 (void) xmlAddChild(n, pgelts.stability); 10018 (void) xmlAddChildList(n, pgelts.propvals); 10019 (void) xmlAddChildList(n, pgelts.properties); 10020 10021 return (n); 10022 } 10023 10024 static void 10025 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 10026 { 10027 scf_propertygroup_t *opg; 10028 scf_iter_t *iter; 10029 char *type, *fmri; 10030 int ret; 10031 struct pg_elts pgelts; 10032 xmlNodePtr n; 10033 scf_error_t serr; 10034 10035 if ((opg = scf_pg_create(g_hndl)) == NULL || 10036 (iter = scf_iter_create(g_hndl)) == NULL) 10037 scfdie(); 10038 10039 /* Can't use exp_prop_iter due to export_dependent(). */ 10040 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10041 scfdie(); 10042 10043 type = safe_malloc(max_scf_pg_type_len + 1); 10044 10045 /* Get an extra byte so we can tell if values are too long. */ 10046 fmri = safe_malloc(max_scf_fmri_len + 2); 10047 10048 (void) memset(&pgelts, 0, sizeof (pgelts)); 10049 10050 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 10051 void *entity; 10052 int isservice; 10053 scf_type_t ty; 10054 10055 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 10056 scfdie(); 10057 10058 if ((ty != SCF_TYPE_ASTRING && 10059 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 10060 prop_get_val(exp_prop, exp_val) != 0) { 10061 export_property(exp_prop, NULL, &pgelts, 10062 SCE_ALL_VALUES); 10063 continue; 10064 } 10065 10066 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10067 scfdie(); 10068 10069 if (scf_value_get_astring(exp_val, fmri, 10070 max_scf_fmri_len + 2) < 0) 10071 scfdie(); 10072 10073 /* Look for a dependency group in the target fmri. */ 10074 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10075 switch (serr) { 10076 case SCF_ERROR_NONE: 10077 break; 10078 10079 case SCF_ERROR_NO_MEMORY: 10080 uu_die(gettext("Out of memory.\n")); 10081 /* NOTREACHED */ 10082 10083 case SCF_ERROR_INVALID_ARGUMENT: 10084 if (g_verbose) { 10085 if (scf_property_to_fmri(exp_prop, fmri, 10086 max_scf_fmri_len + 2) < 0) 10087 scfdie(); 10088 10089 warn(gettext("The value of %s is not a valid " 10090 "FMRI.\n"), fmri); 10091 } 10092 10093 export_property(exp_prop, exp_str, &pgelts, 10094 SCE_ALL_VALUES); 10095 continue; 10096 10097 case SCF_ERROR_CONSTRAINT_VIOLATED: 10098 if (g_verbose) { 10099 if (scf_property_to_fmri(exp_prop, fmri, 10100 max_scf_fmri_len + 2) < 0) 10101 scfdie(); 10102 10103 warn(gettext("The value of %s does not specify " 10104 "a service or an instance.\n"), fmri); 10105 } 10106 10107 export_property(exp_prop, exp_str, &pgelts, 10108 SCE_ALL_VALUES); 10109 continue; 10110 10111 case SCF_ERROR_NOT_FOUND: 10112 if (g_verbose) { 10113 if (scf_property_to_fmri(exp_prop, fmri, 10114 max_scf_fmri_len + 2) < 0) 10115 scfdie(); 10116 10117 warn(gettext("The entity specified by %s does " 10118 "not exist.\n"), fmri); 10119 } 10120 10121 export_property(exp_prop, exp_str, &pgelts, 10122 SCE_ALL_VALUES); 10123 continue; 10124 10125 default: 10126 #ifndef NDEBUG 10127 (void) fprintf(stderr, "%s:%d: %s() failed with " 10128 "unexpected error %d.\n", __FILE__, __LINE__, 10129 "fmri_to_entity", serr); 10130 #endif 10131 abort(); 10132 } 10133 10134 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 10135 if (scf_error() != SCF_ERROR_NOT_FOUND) 10136 scfdie(); 10137 10138 warn(gettext("Entity %s is missing dependency property " 10139 "group %s.\n"), fmri, exp_str); 10140 10141 export_property(exp_prop, NULL, &pgelts, 10142 SCE_ALL_VALUES); 10143 continue; 10144 } 10145 10146 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 10147 scfdie(); 10148 10149 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 10150 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 10151 scfdie(); 10152 10153 warn(gettext("Property group %s is not of " 10154 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 10155 10156 export_property(exp_prop, NULL, &pgelts, 10157 SCE_ALL_VALUES); 10158 continue; 10159 } 10160 10161 n = export_dependent(opg, exp_str, fmri); 10162 if (n == NULL) { 10163 export_property(exp_prop, exp_str, &pgelts, 10164 SCE_ALL_VALUES); 10165 } else { 10166 if (eelts->dependents == NULL) 10167 eelts->dependents = n; 10168 else 10169 (void) xmlAddSibling(eelts->dependents, 10170 n); 10171 } 10172 } 10173 if (ret == -1) 10174 scfdie(); 10175 10176 free(fmri); 10177 free(type); 10178 10179 scf_iter_destroy(iter); 10180 scf_pg_destroy(opg); 10181 10182 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10183 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 10184 eelts); 10185 } 10186 10187 static void 10188 make_node(xmlNodePtr *nodep, const char *name) 10189 { 10190 if (*nodep == NULL) { 10191 *nodep = xmlNewNode(NULL, (xmlChar *)name); 10192 if (*nodep == NULL) 10193 uu_die(emsg_create_xml); 10194 } 10195 } 10196 10197 static xmlNodePtr 10198 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 10199 { 10200 int ret; 10201 xmlNodePtr parent = NULL; 10202 xmlNodePtr loctext = NULL; 10203 10204 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10205 scfdie(); 10206 10207 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10208 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 10209 prop_get_val(exp_prop, exp_val) != 0) 10210 continue; 10211 10212 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 10213 scfdie(); 10214 10215 make_node(&parent, parname); 10216 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 10217 (xmlChar *)exp_str); 10218 if (loctext == NULL) 10219 uu_die(emsg_create_xml); 10220 10221 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10222 scfdie(); 10223 10224 safe_setprop(loctext, "xml:lang", exp_str); 10225 } 10226 10227 if (ret == -1) 10228 scfdie(); 10229 10230 return (parent); 10231 } 10232 10233 static xmlNodePtr 10234 export_tm_manpage(scf_propertygroup_t *pg) 10235 { 10236 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 10237 if (manpage == NULL) 10238 uu_die(emsg_create_xml); 10239 10240 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 10241 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 10242 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 10243 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 10244 xmlFreeNode(manpage); 10245 return (NULL); 10246 } 10247 10248 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 10249 (void) set_attr_from_prop_default(exp_prop, 10250 manpage, "manpath", ":default"); 10251 10252 return (manpage); 10253 } 10254 10255 static xmlNodePtr 10256 export_tm_doc_link(scf_propertygroup_t *pg) 10257 { 10258 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 10259 if (doc_link == NULL) 10260 uu_die(emsg_create_xml); 10261 10262 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 10263 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 10264 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 10265 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 10266 xmlFreeNode(doc_link); 10267 return (NULL); 10268 } 10269 return (doc_link); 10270 } 10271 10272 /* 10273 * Process template information for a service or instances. 10274 */ 10275 static void 10276 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 10277 struct template_elts *telts) 10278 { 10279 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 10280 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 10281 xmlNodePtr child = NULL; 10282 10283 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 10284 scfdie(); 10285 10286 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 10287 telts->common_name = export_tm_loctext(pg, "common_name"); 10288 if (telts->common_name == NULL) 10289 export_pg(pg, elts, SCE_ALL_VALUES); 10290 return; 10291 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 10292 telts->description = export_tm_loctext(pg, "description"); 10293 if (telts->description == NULL) 10294 export_pg(pg, elts, SCE_ALL_VALUES); 10295 return; 10296 } 10297 10298 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 10299 child = export_tm_manpage(pg); 10300 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 10301 child = export_tm_doc_link(pg); 10302 } 10303 10304 if (child != NULL) { 10305 make_node(&telts->documentation, "documentation"); 10306 (void) xmlAddChild(telts->documentation, child); 10307 } else { 10308 export_pg(pg, elts, SCE_ALL_VALUES); 10309 } 10310 } 10311 10312 /* 10313 * Process parameter and paramval elements 10314 */ 10315 static void 10316 export_parameter(scf_property_t *prop, const char *name, 10317 struct params_elts *elts) 10318 { 10319 xmlNodePtr param; 10320 scf_error_t err = 0; 10321 int ret; 10322 10323 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 10324 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL) 10325 uu_die(emsg_create_xml); 10326 10327 safe_setprop(param, name_attr, name); 10328 10329 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 10330 scfdie(); 10331 safe_setprop(param, value_attr, exp_str); 10332 10333 if (elts->paramval == NULL) 10334 elts->paramval = param; 10335 else 10336 (void) xmlAddSibling(elts->paramval, param); 10337 10338 return; 10339 } 10340 10341 err = scf_error(); 10342 10343 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 10344 err != SCF_ERROR_NOT_FOUND) 10345 scfdie(); 10346 10347 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL) 10348 uu_die(emsg_create_xml); 10349 10350 safe_setprop(param, name_attr, name); 10351 10352 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 10353 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 10354 scfdie(); 10355 10356 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 10357 1) { 10358 xmlNodePtr vn; 10359 10360 if ((vn = xmlNewChild(param, NULL, 10361 (xmlChar *)"value_node", NULL)) == NULL) 10362 uu_die(emsg_create_xml); 10363 10364 if (scf_value_get_as_string(exp_val, exp_str, 10365 exp_str_sz) < 0) 10366 scfdie(); 10367 10368 safe_setprop(vn, value_attr, exp_str); 10369 } 10370 if (ret != 0) 10371 scfdie(); 10372 } 10373 10374 if (elts->parameter == NULL) 10375 elts->parameter = param; 10376 else 10377 (void) xmlAddSibling(elts->parameter, param); 10378 } 10379 10380 /* 10381 * Process notification parameters for a service or instance 10382 */ 10383 static void 10384 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts) 10385 { 10386 xmlNodePtr n, event, *type; 10387 struct params_elts *eelts; 10388 int ret, err, i; 10389 char *s; 10390 10391 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters"); 10392 event = xmlNewNode(NULL, (xmlChar *)"event"); 10393 if (n == NULL || event == NULL) 10394 uu_die(emsg_create_xml); 10395 10396 /* event value */ 10397 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 10398 scfdie(); 10399 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */ 10400 if ((s = strchr(exp_str, ',')) != NULL) 10401 *s = '\0'; 10402 safe_setprop(event, value_attr, exp_str); 10403 10404 (void) xmlAddChild(n, event); 10405 10406 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL || 10407 (eelts = calloc(URI_SCHEME_NUM, 10408 sizeof (struct params_elts))) == NULL) 10409 uu_die(gettext("Out of memory.\n")); 10410 10411 err = 0; 10412 10413 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10414 scfdie(); 10415 10416 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10417 char *t, *p; 10418 10419 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10420 scfdie(); 10421 10422 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) { 10423 /* 10424 * this is not a well formed notification parameters 10425 * element, we should export as regular pg 10426 */ 10427 err = 1; 10428 break; 10429 } 10430 10431 if ((i = check_uri_protocol(t)) < 0) { 10432 err = 1; 10433 break; 10434 } 10435 10436 if (type[i] == NULL) { 10437 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) == 10438 NULL) 10439 uu_die(emsg_create_xml); 10440 10441 safe_setprop(type[i], name_attr, t); 10442 } 10443 if (strcmp(p, active_attr) == 0) { 10444 if (set_attr_from_prop(exp_prop, type[i], 10445 active_attr) != 0) { 10446 err = 1; 10447 break; 10448 } 10449 continue; 10450 } 10451 /* 10452 * We export the parameter 10453 */ 10454 export_parameter(exp_prop, p, &eelts[i]); 10455 } 10456 10457 if (ret == -1) 10458 scfdie(); 10459 10460 if (err == 1) { 10461 for (i = 0; i < URI_SCHEME_NUM; ++i) 10462 xmlFree(type[i]); 10463 free(type); 10464 10465 export_pg(pg, elts, SCE_ALL_VALUES); 10466 10467 return; 10468 } else { 10469 for (i = 0; i < URI_SCHEME_NUM; ++i) 10470 if (type[i] != NULL) { 10471 (void) xmlAddChildList(type[i], 10472 eelts[i].paramval); 10473 (void) xmlAddChildList(type[i], 10474 eelts[i].parameter); 10475 (void) xmlAddSibling(event, type[i]); 10476 } 10477 } 10478 free(type); 10479 10480 if (elts->notify_params == NULL) 10481 elts->notify_params = n; 10482 else 10483 (void) xmlAddSibling(elts->notify_params, n); 10484 } 10485 10486 /* 10487 * Process the general property group for an instance. 10488 */ 10489 static void 10490 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 10491 struct entity_elts *elts) 10492 { 10493 uint8_t enabled; 10494 struct pg_elts pgelts; 10495 int ret; 10496 10497 /* enabled */ 10498 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10499 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10500 prop_get_val(exp_prop, exp_val) == 0) { 10501 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10502 scfdie(); 10503 } else { 10504 enabled = 0; 10505 } 10506 10507 safe_setprop(inode, enabled_attr, enabled ? true : false); 10508 10509 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10510 scfdie(); 10511 10512 (void) memset(&pgelts, 0, sizeof (pgelts)); 10513 10514 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10515 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10516 scfdie(); 10517 10518 if (strcmp(exp_str, scf_property_enabled) == 0) { 10519 continue; 10520 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10521 xmlNodePtr rnode, sfnode; 10522 10523 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10524 if (rnode == NULL) 10525 uu_die(emsg_create_xml); 10526 10527 sfnode = xmlNewChild(rnode, NULL, 10528 (xmlChar *)"service_fmri", NULL); 10529 if (sfnode == NULL) 10530 uu_die(emsg_create_xml); 10531 10532 if (set_attr_from_prop(exp_prop, sfnode, 10533 value_attr) == 0) { 10534 elts->restarter = rnode; 10535 continue; 10536 } 10537 10538 xmlFreeNode(rnode); 10539 } 10540 10541 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10542 } 10543 if (ret == -1) 10544 scfdie(); 10545 10546 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10547 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10548 elts); 10549 } 10550 10551 /* 10552 * Put an instance element for the given instance into selts. 10553 */ 10554 static void 10555 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10556 { 10557 xmlNodePtr n; 10558 boolean_t isdefault; 10559 struct entity_elts elts; 10560 struct template_elts template_elts; 10561 int ret; 10562 10563 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10564 if (n == NULL) 10565 uu_die(emsg_create_xml); 10566 10567 /* name */ 10568 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10569 scfdie(); 10570 safe_setprop(n, name_attr, exp_str); 10571 isdefault = strcmp(exp_str, "default") == 0; 10572 10573 /* check existance of general pg (since general/enabled is required) */ 10574 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10575 if (scf_error() != SCF_ERROR_NOT_FOUND) 10576 scfdie(); 10577 10578 if (g_verbose) { 10579 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10580 scfdie(); 10581 10582 warn(gettext("Instance %s has no general property " 10583 "group; it will be marked disabled.\n"), exp_str); 10584 } 10585 10586 safe_setprop(n, enabled_attr, false); 10587 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10588 strcmp(exp_str, scf_group_framework) != 0) { 10589 if (g_verbose) { 10590 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10591 scfdie(); 10592 10593 warn(gettext("Property group %s is not of type " 10594 "framework; the instance will be marked " 10595 "disabled.\n"), exp_str); 10596 } 10597 10598 safe_setprop(n, enabled_attr, false); 10599 } 10600 10601 /* property groups */ 10602 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10603 scfdie(); 10604 10605 (void) memset(&elts, 0, sizeof (elts)); 10606 (void) memset(&template_elts, 0, sizeof (template_elts)); 10607 10608 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10609 uint32_t pgflags; 10610 10611 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10612 scfdie(); 10613 10614 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10615 continue; 10616 10617 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10618 scfdie(); 10619 10620 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10621 export_dependency(exp_pg, &elts); 10622 continue; 10623 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10624 export_method(exp_pg, &elts); 10625 continue; 10626 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10627 if (scf_pg_get_name(exp_pg, exp_str, 10628 max_scf_name_len + 1) < 0) 10629 scfdie(); 10630 10631 if (strcmp(exp_str, scf_pg_general) == 0) { 10632 export_inst_general(exp_pg, n, &elts); 10633 continue; 10634 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10635 0) { 10636 export_method_context(exp_pg, &elts); 10637 continue; 10638 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10639 export_dependents(exp_pg, &elts); 10640 continue; 10641 } 10642 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10643 export_template(exp_pg, &elts, &template_elts); 10644 continue; 10645 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10646 export_notify_params(exp_pg, &elts); 10647 continue; 10648 } 10649 10650 /* Ordinary pg. */ 10651 export_pg(exp_pg, &elts, flags); 10652 } 10653 if (ret == -1) 10654 scfdie(); 10655 10656 if (template_elts.common_name != NULL) { 10657 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10658 (void) xmlAddChild(elts.template, template_elts.common_name); 10659 (void) xmlAddChild(elts.template, template_elts.description); 10660 (void) xmlAddChild(elts.template, template_elts.documentation); 10661 } else { 10662 xmlFreeNode(template_elts.description); 10663 xmlFreeNode(template_elts.documentation); 10664 } 10665 10666 if (isdefault && elts.restarter == NULL && 10667 elts.dependencies == NULL && elts.method_context == NULL && 10668 elts.exec_methods == NULL && elts.notify_params == NULL && 10669 elts.property_groups == NULL && elts.template == NULL) { 10670 xmlChar *eval; 10671 10672 /* This is a default instance */ 10673 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10674 10675 xmlFreeNode(n); 10676 10677 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10678 if (n == NULL) 10679 uu_die(emsg_create_xml); 10680 10681 safe_setprop(n, enabled_attr, (char *)eval); 10682 xmlFree(eval); 10683 10684 selts->create_default_instance = n; 10685 } else { 10686 /* Assemble the children in order. */ 10687 (void) xmlAddChild(n, elts.restarter); 10688 (void) xmlAddChildList(n, elts.dependencies); 10689 (void) xmlAddChildList(n, elts.dependents); 10690 (void) xmlAddChild(n, elts.method_context); 10691 (void) xmlAddChildList(n, elts.exec_methods); 10692 (void) xmlAddChildList(n, elts.notify_params); 10693 (void) xmlAddChildList(n, elts.property_groups); 10694 (void) xmlAddChild(n, elts.template); 10695 10696 if (selts->instances == NULL) 10697 selts->instances = n; 10698 else 10699 (void) xmlAddSibling(selts->instances, n); 10700 } 10701 } 10702 10703 /* 10704 * Return a service element for the given service. 10705 */ 10706 static xmlNodePtr 10707 export_service(scf_service_t *svc, int flags) 10708 { 10709 xmlNodePtr snode; 10710 struct entity_elts elts; 10711 struct template_elts template_elts; 10712 int ret; 10713 10714 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10715 if (snode == NULL) 10716 uu_die(emsg_create_xml); 10717 10718 /* Get & set name attribute */ 10719 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10720 scfdie(); 10721 safe_setprop(snode, name_attr, exp_str); 10722 10723 safe_setprop(snode, type_attr, "service"); 10724 safe_setprop(snode, "version", "0"); 10725 10726 /* Acquire child elements. */ 10727 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10728 scfdie(); 10729 10730 (void) memset(&elts, 0, sizeof (elts)); 10731 (void) memset(&template_elts, 0, sizeof (template_elts)); 10732 10733 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10734 uint32_t pgflags; 10735 10736 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10737 scfdie(); 10738 10739 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10740 continue; 10741 10742 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10743 scfdie(); 10744 10745 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10746 export_dependency(exp_pg, &elts); 10747 continue; 10748 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10749 export_method(exp_pg, &elts); 10750 continue; 10751 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10752 if (scf_pg_get_name(exp_pg, exp_str, 10753 max_scf_name_len + 1) < 0) 10754 scfdie(); 10755 10756 if (strcmp(exp_str, scf_pg_general) == 0) { 10757 export_svc_general(exp_pg, &elts); 10758 continue; 10759 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10760 0) { 10761 export_method_context(exp_pg, &elts); 10762 continue; 10763 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10764 export_dependents(exp_pg, &elts); 10765 continue; 10766 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10767 continue; 10768 } 10769 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10770 export_template(exp_pg, &elts, &template_elts); 10771 continue; 10772 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10773 export_notify_params(exp_pg, &elts); 10774 continue; 10775 } 10776 10777 export_pg(exp_pg, &elts, flags); 10778 } 10779 if (ret == -1) 10780 scfdie(); 10781 10782 if (template_elts.common_name != NULL) { 10783 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10784 (void) xmlAddChild(elts.template, template_elts.common_name); 10785 (void) xmlAddChild(elts.template, template_elts.description); 10786 (void) xmlAddChild(elts.template, template_elts.documentation); 10787 } else { 10788 xmlFreeNode(template_elts.description); 10789 xmlFreeNode(template_elts.documentation); 10790 } 10791 10792 /* Iterate instances */ 10793 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10794 scfdie(); 10795 10796 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10797 export_instance(exp_inst, &elts, flags); 10798 if (ret == -1) 10799 scfdie(); 10800 10801 /* Now add all of the accumulated elements in order. */ 10802 (void) xmlAddChild(snode, elts.create_default_instance); 10803 (void) xmlAddChild(snode, elts.single_instance); 10804 (void) xmlAddChild(snode, elts.restarter); 10805 (void) xmlAddChildList(snode, elts.dependencies); 10806 (void) xmlAddChildList(snode, elts.dependents); 10807 (void) xmlAddChild(snode, elts.method_context); 10808 (void) xmlAddChildList(snode, elts.exec_methods); 10809 (void) xmlAddChildList(snode, elts.notify_params); 10810 (void) xmlAddChildList(snode, elts.property_groups); 10811 (void) xmlAddChildList(snode, elts.instances); 10812 (void) xmlAddChild(snode, elts.stability); 10813 (void) xmlAddChild(snode, elts.template); 10814 10815 return (snode); 10816 } 10817 10818 static int 10819 export_callback(void *data, scf_walkinfo_t *wip) 10820 { 10821 FILE *f; 10822 xmlDocPtr doc; 10823 xmlNodePtr sb; 10824 int result; 10825 struct export_args *argsp = (struct export_args *)data; 10826 10827 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10828 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10829 (exp_prop = scf_property_create(g_hndl)) == NULL || 10830 (exp_val = scf_value_create(g_hndl)) == NULL || 10831 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10832 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10833 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10834 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10835 scfdie(); 10836 10837 exp_str_sz = max_scf_len + 1; 10838 exp_str = safe_malloc(exp_str_sz); 10839 10840 if (argsp->filename != NULL) { 10841 errno = 0; 10842 f = fopen(argsp->filename, "wb"); 10843 if (f == NULL) { 10844 if (errno == 0) 10845 uu_die(gettext("Could not open \"%s\": no free " 10846 "stdio streams.\n"), argsp->filename); 10847 else 10848 uu_die(gettext("Could not open \"%s\""), 10849 argsp->filename); 10850 } 10851 } else 10852 f = stdout; 10853 10854 doc = xmlNewDoc((xmlChar *)"1.0"); 10855 if (doc == NULL) 10856 uu_die(gettext("Could not create XML document.\n")); 10857 10858 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10859 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10860 uu_die(emsg_create_xml); 10861 10862 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10863 if (sb == NULL) 10864 uu_die(emsg_create_xml); 10865 safe_setprop(sb, type_attr, "manifest"); 10866 safe_setprop(sb, name_attr, "export"); 10867 (void) xmlAddSibling(doc->children, sb); 10868 10869 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10870 10871 result = write_service_bundle(doc, f); 10872 10873 free(exp_str); 10874 scf_iter_destroy(exp_val_iter); 10875 scf_iter_destroy(exp_prop_iter); 10876 scf_iter_destroy(exp_pg_iter); 10877 scf_iter_destroy(exp_inst_iter); 10878 scf_value_destroy(exp_val); 10879 scf_property_destroy(exp_prop); 10880 scf_pg_destroy(exp_pg); 10881 scf_instance_destroy(exp_inst); 10882 10883 xmlFreeDoc(doc); 10884 10885 if (f != stdout) 10886 (void) fclose(f); 10887 10888 return (result); 10889 } 10890 10891 /* 10892 * Get the service named by fmri, build an XML tree which represents it, and 10893 * dump it into filename (or stdout if filename is NULL). 10894 */ 10895 int 10896 lscf_service_export(char *fmri, const char *filename, int flags) 10897 { 10898 struct export_args args; 10899 char *fmridup; 10900 const char *scope, *svc, *inst; 10901 size_t cblen = 3 * max_scf_name_len; 10902 char *canonbuf = alloca(cblen); 10903 int ret, err; 10904 10905 lscf_prep_hndl(); 10906 10907 bzero(&args, sizeof (args)); 10908 args.filename = filename; 10909 args.flags = flags; 10910 10911 /* 10912 * If some poor user has passed an exact instance FMRI, of the sort 10913 * one might cut and paste from svcs(1) or an error message, warn 10914 * and chop off the instance instead of failing. 10915 */ 10916 fmridup = alloca(strlen(fmri) + 1); 10917 (void) strcpy(fmridup, fmri); 10918 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX, 10919 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 && 10920 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 && 10921 inst != NULL) { 10922 (void) strlcpy(canonbuf, "svc:/", cblen); 10923 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 10924 (void) strlcat(canonbuf, "/", cblen); 10925 (void) strlcat(canonbuf, scope, cblen); 10926 } 10927 (void) strlcat(canonbuf, svc, cblen); 10928 fmri = canonbuf; 10929 10930 warn(gettext("Only services may be exported; ignoring " 10931 "instance portion of argument.\n")); 10932 } 10933 10934 err = 0; 10935 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10936 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10937 &args, &err, semerr)) != 0) { 10938 if (ret != -1) 10939 semerr(gettext("Failed to walk instances: %s\n"), 10940 scf_strerror(ret)); 10941 return (-1); 10942 } 10943 10944 /* 10945 * Error message has already been printed. 10946 */ 10947 if (err != 0) 10948 return (-1); 10949 10950 return (0); 10951 } 10952 10953 10954 /* 10955 * Archive 10956 */ 10957 10958 static xmlNodePtr 10959 make_archive(int flags) 10960 { 10961 xmlNodePtr sb; 10962 scf_scope_t *scope; 10963 scf_service_t *svc; 10964 scf_iter_t *iter; 10965 int r; 10966 10967 if ((scope = scf_scope_create(g_hndl)) == NULL || 10968 (svc = scf_service_create(g_hndl)) == NULL || 10969 (iter = scf_iter_create(g_hndl)) == NULL || 10970 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10971 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10972 (exp_prop = scf_property_create(g_hndl)) == NULL || 10973 (exp_val = scf_value_create(g_hndl)) == NULL || 10974 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10975 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10976 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10977 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10978 scfdie(); 10979 10980 exp_str_sz = max_scf_len + 1; 10981 exp_str = safe_malloc(exp_str_sz); 10982 10983 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10984 if (sb == NULL) 10985 uu_die(emsg_create_xml); 10986 safe_setprop(sb, type_attr, "archive"); 10987 safe_setprop(sb, name_attr, "none"); 10988 10989 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 10990 scfdie(); 10991 if (scf_iter_scope_services(iter, scope) != 0) 10992 scfdie(); 10993 10994 for (;;) { 10995 r = scf_iter_next_service(iter, svc); 10996 if (r == 0) 10997 break; 10998 if (r != 1) 10999 scfdie(); 11000 11001 if (scf_service_get_name(svc, exp_str, 11002 max_scf_name_len + 1) < 0) 11003 scfdie(); 11004 11005 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 11006 continue; 11007 11008 (void) xmlAddChild(sb, export_service(svc, flags)); 11009 } 11010 11011 free(exp_str); 11012 11013 scf_iter_destroy(exp_val_iter); 11014 scf_iter_destroy(exp_prop_iter); 11015 scf_iter_destroy(exp_pg_iter); 11016 scf_iter_destroy(exp_inst_iter); 11017 scf_value_destroy(exp_val); 11018 scf_property_destroy(exp_prop); 11019 scf_pg_destroy(exp_pg); 11020 scf_instance_destroy(exp_inst); 11021 scf_iter_destroy(iter); 11022 scf_service_destroy(svc); 11023 scf_scope_destroy(scope); 11024 11025 return (sb); 11026 } 11027 11028 int 11029 lscf_archive(const char *filename, int flags) 11030 { 11031 FILE *f; 11032 xmlDocPtr doc; 11033 int result; 11034 11035 lscf_prep_hndl(); 11036 11037 if (filename != NULL) { 11038 errno = 0; 11039 f = fopen(filename, "wb"); 11040 if (f == NULL) { 11041 if (errno == 0) 11042 uu_die(gettext("Could not open \"%s\": no free " 11043 "stdio streams.\n"), filename); 11044 else 11045 uu_die(gettext("Could not open \"%s\""), 11046 filename); 11047 } 11048 } else 11049 f = stdout; 11050 11051 doc = xmlNewDoc((xmlChar *)"1.0"); 11052 if (doc == NULL) 11053 uu_die(gettext("Could not create XML document.\n")); 11054 11055 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11056 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11057 uu_die(emsg_create_xml); 11058 11059 (void) xmlAddSibling(doc->children, make_archive(flags)); 11060 11061 result = write_service_bundle(doc, f); 11062 11063 xmlFreeDoc(doc); 11064 11065 if (f != stdout) 11066 (void) fclose(f); 11067 11068 return (result); 11069 } 11070 11071 11072 /* 11073 * "Extract" a profile. 11074 */ 11075 int 11076 lscf_profile_extract(const char *filename) 11077 { 11078 FILE *f; 11079 xmlDocPtr doc; 11080 xmlNodePtr sb, snode, inode; 11081 scf_scope_t *scope; 11082 scf_service_t *svc; 11083 scf_instance_t *inst; 11084 scf_propertygroup_t *pg; 11085 scf_property_t *prop; 11086 scf_value_t *val; 11087 scf_iter_t *siter, *iiter; 11088 int r, s; 11089 char *namebuf; 11090 uint8_t b; 11091 int result; 11092 11093 lscf_prep_hndl(); 11094 11095 if (filename != NULL) { 11096 errno = 0; 11097 f = fopen(filename, "wb"); 11098 if (f == NULL) { 11099 if (errno == 0) 11100 uu_die(gettext("Could not open \"%s\": no " 11101 "free stdio streams.\n"), filename); 11102 else 11103 uu_die(gettext("Could not open \"%s\""), 11104 filename); 11105 } 11106 } else 11107 f = stdout; 11108 11109 doc = xmlNewDoc((xmlChar *)"1.0"); 11110 if (doc == NULL) 11111 uu_die(gettext("Could not create XML document.\n")); 11112 11113 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11114 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11115 uu_die(emsg_create_xml); 11116 11117 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 11118 if (sb == NULL) 11119 uu_die(emsg_create_xml); 11120 safe_setprop(sb, type_attr, "profile"); 11121 safe_setprop(sb, name_attr, "extract"); 11122 (void) xmlAddSibling(doc->children, sb); 11123 11124 if ((scope = scf_scope_create(g_hndl)) == NULL || 11125 (svc = scf_service_create(g_hndl)) == NULL || 11126 (inst = scf_instance_create(g_hndl)) == NULL || 11127 (pg = scf_pg_create(g_hndl)) == NULL || 11128 (prop = scf_property_create(g_hndl)) == NULL || 11129 (val = scf_value_create(g_hndl)) == NULL || 11130 (siter = scf_iter_create(g_hndl)) == NULL || 11131 (iiter = scf_iter_create(g_hndl)) == NULL) 11132 scfdie(); 11133 11134 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 11135 scfdie(); 11136 11137 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 11138 scfdie(); 11139 11140 namebuf = safe_malloc(max_scf_name_len + 1); 11141 11142 while ((r = scf_iter_next_service(siter, svc)) == 1) { 11143 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 11144 scfdie(); 11145 11146 snode = xmlNewNode(NULL, (xmlChar *)"service"); 11147 if (snode == NULL) 11148 uu_die(emsg_create_xml); 11149 11150 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 11151 0) 11152 scfdie(); 11153 11154 safe_setprop(snode, name_attr, namebuf); 11155 11156 safe_setprop(snode, type_attr, "service"); 11157 safe_setprop(snode, "version", "0"); 11158 11159 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 11160 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 11161 SCF_SUCCESS) { 11162 if (scf_error() != SCF_ERROR_NOT_FOUND) 11163 scfdie(); 11164 11165 if (g_verbose) { 11166 ssize_t len; 11167 char *fmri; 11168 11169 len = 11170 scf_instance_to_fmri(inst, NULL, 0); 11171 if (len < 0) 11172 scfdie(); 11173 11174 fmri = safe_malloc(len + 1); 11175 11176 if (scf_instance_to_fmri(inst, fmri, 11177 len + 1) < 0) 11178 scfdie(); 11179 11180 warn("Instance %s has no \"%s\" " 11181 "property group.\n", fmri, 11182 scf_pg_general); 11183 11184 free(fmri); 11185 } 11186 11187 continue; 11188 } 11189 11190 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 11191 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 11192 prop_get_val(prop, val) != 0) 11193 continue; 11194 11195 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 11196 NULL); 11197 if (inode == NULL) 11198 uu_die(emsg_create_xml); 11199 11200 if (scf_instance_get_name(inst, namebuf, 11201 max_scf_name_len + 1) < 0) 11202 scfdie(); 11203 11204 safe_setprop(inode, name_attr, namebuf); 11205 11206 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 11207 scfdie(); 11208 11209 safe_setprop(inode, enabled_attr, b ? true : false); 11210 } 11211 if (s < 0) 11212 scfdie(); 11213 11214 if (snode->children != NULL) 11215 (void) xmlAddChild(sb, snode); 11216 else 11217 xmlFreeNode(snode); 11218 } 11219 if (r < 0) 11220 scfdie(); 11221 11222 free(namebuf); 11223 11224 result = write_service_bundle(doc, f); 11225 11226 xmlFreeDoc(doc); 11227 11228 if (f != stdout) 11229 (void) fclose(f); 11230 11231 return (result); 11232 } 11233 11234 11235 /* 11236 * Entity manipulation commands 11237 */ 11238 11239 /* 11240 * Entity selection. If no entity is selected, then the current scope is in 11241 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 11242 * only cur_inst is NULL, and when an instance is selected, none are NULL. 11243 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 11244 * cur_inst will be non-NULL. 11245 */ 11246 11247 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 11248 static int 11249 select_inst(const char *name) 11250 { 11251 scf_instance_t *inst; 11252 scf_error_t err; 11253 11254 assert(cur_svc != NULL); 11255 11256 inst = scf_instance_create(g_hndl); 11257 if (inst == NULL) 11258 scfdie(); 11259 11260 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 11261 cur_inst = inst; 11262 return (0); 11263 } 11264 11265 err = scf_error(); 11266 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11267 scfdie(); 11268 11269 scf_instance_destroy(inst); 11270 return (1); 11271 } 11272 11273 /* Returns as above. */ 11274 static int 11275 select_svc(const char *name) 11276 { 11277 scf_service_t *svc; 11278 scf_error_t err; 11279 11280 assert(cur_scope != NULL); 11281 11282 svc = scf_service_create(g_hndl); 11283 if (svc == NULL) 11284 scfdie(); 11285 11286 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 11287 cur_svc = svc; 11288 return (0); 11289 } 11290 11291 err = scf_error(); 11292 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11293 scfdie(); 11294 11295 scf_service_destroy(svc); 11296 return (1); 11297 } 11298 11299 /* ARGSUSED */ 11300 static int 11301 select_callback(void *unused, scf_walkinfo_t *wip) 11302 { 11303 scf_instance_t *inst; 11304 scf_service_t *svc; 11305 scf_scope_t *scope; 11306 11307 if (wip->inst != NULL) { 11308 if ((scope = scf_scope_create(g_hndl)) == NULL || 11309 (svc = scf_service_create(g_hndl)) == NULL || 11310 (inst = scf_instance_create(g_hndl)) == NULL) 11311 scfdie(); 11312 11313 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11314 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11315 scfdie(); 11316 } else { 11317 assert(wip->svc != NULL); 11318 11319 if ((scope = scf_scope_create(g_hndl)) == NULL || 11320 (svc = scf_service_create(g_hndl)) == NULL) 11321 scfdie(); 11322 11323 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11324 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11325 scfdie(); 11326 11327 inst = NULL; 11328 } 11329 11330 /* Clear out the current selection */ 11331 assert(cur_scope != NULL); 11332 scf_scope_destroy(cur_scope); 11333 scf_service_destroy(cur_svc); 11334 scf_instance_destroy(cur_inst); 11335 11336 cur_scope = scope; 11337 cur_svc = svc; 11338 cur_inst = inst; 11339 11340 return (0); 11341 } 11342 11343 static int 11344 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 11345 { 11346 char **fmri = fmri_p; 11347 11348 *fmri = strdup(wip->fmri); 11349 if (*fmri == NULL) 11350 uu_die(gettext("Out of memory.\n")); 11351 11352 return (0); 11353 } 11354 11355 /* 11356 * validate [fmri] 11357 * Perform the validation of an FMRI instance. 11358 */ 11359 void 11360 lscf_validate_fmri(const char *fmri) 11361 { 11362 int ret = 0; 11363 size_t inst_sz; 11364 char *inst_fmri = NULL; 11365 scf_tmpl_errors_t *errs = NULL; 11366 char *snapbuf = NULL; 11367 11368 lscf_prep_hndl(); 11369 11370 if (fmri == NULL) { 11371 inst_sz = max_scf_fmri_len + 1; 11372 inst_fmri = safe_malloc(inst_sz); 11373 11374 if (cur_snap != NULL) { 11375 snapbuf = safe_malloc(max_scf_name_len + 1); 11376 if (scf_snapshot_get_name(cur_snap, snapbuf, 11377 max_scf_name_len + 1) < 0) 11378 scfdie(); 11379 } 11380 if (cur_inst == NULL) { 11381 semerr(gettext("No instance selected\n")); 11382 goto cleanup; 11383 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 11384 inst_sz) >= inst_sz) { 11385 /* sanity check. Should never get here */ 11386 uu_die(gettext("Unexpected error! file %s, line %d\n"), 11387 __FILE__, __LINE__); 11388 } 11389 } else { 11390 scf_error_t scf_err; 11391 int err = 0; 11392 11393 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 11394 validate_callback, &inst_fmri, &err, semerr)) != 0) { 11395 uu_warn("Failed to walk instances: %s\n", 11396 scf_strerror(scf_err)); 11397 goto cleanup; 11398 } 11399 if (err != 0) { 11400 /* error message displayed by scf_walk_fmri */ 11401 goto cleanup; 11402 } 11403 } 11404 11405 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 11406 SCF_TMPL_VALIDATE_FLAG_CURRENT); 11407 if (ret == -1) { 11408 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 11409 warn(gettext("Template data for %s is invalid. " 11410 "Consider reverting to a previous snapshot or " 11411 "restoring original configuration.\n"), inst_fmri); 11412 } else { 11413 uu_warn("%s: %s\n", 11414 gettext("Error validating the instance"), 11415 scf_strerror(scf_error())); 11416 } 11417 } else if (ret == 1 && errs != NULL) { 11418 scf_tmpl_error_t *err = NULL; 11419 char *msg; 11420 size_t len = 256; /* initial error buffer size */ 11421 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 11422 SCF_TMPL_STRERROR_HUMAN : 0; 11423 11424 msg = safe_malloc(len); 11425 11426 while ((err = scf_tmpl_next_error(errs)) != NULL) { 11427 int ret; 11428 11429 if ((ret = scf_tmpl_strerror(err, msg, len, 11430 flag)) >= len) { 11431 len = ret + 1; 11432 msg = realloc(msg, len); 11433 if (msg == NULL) 11434 uu_die(gettext( 11435 "Out of memory.\n")); 11436 (void) scf_tmpl_strerror(err, msg, len, 11437 flag); 11438 } 11439 (void) fprintf(stderr, "%s\n", msg); 11440 } 11441 if (msg != NULL) 11442 free(msg); 11443 } 11444 if (errs != NULL) 11445 scf_tmpl_errors_destroy(errs); 11446 11447 cleanup: 11448 free(inst_fmri); 11449 free(snapbuf); 11450 } 11451 11452 static void 11453 lscf_validate_file(const char *filename) 11454 { 11455 tmpl_errors_t *errs; 11456 11457 bundle_t *b = internal_bundle_new(); 11458 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 11459 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 11460 tmpl_errors_print(stderr, errs, ""); 11461 semerr(gettext("Validation failed.\n")); 11462 } 11463 tmpl_errors_destroy(errs); 11464 } 11465 (void) internal_bundle_free(b); 11466 } 11467 11468 /* 11469 * validate [fmri|file] 11470 */ 11471 void 11472 lscf_validate(const char *arg) 11473 { 11474 const char *str; 11475 11476 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 11477 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 11478 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 11479 lscf_validate_file(str); 11480 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 11481 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 11482 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 11483 lscf_validate_fmri(str); 11484 } else if (access(arg, R_OK | F_OK) == 0) { 11485 lscf_validate_file(arg); 11486 } else { 11487 lscf_validate_fmri(arg); 11488 } 11489 } 11490 11491 void 11492 lscf_select(const char *fmri) 11493 { 11494 int ret, err; 11495 11496 lscf_prep_hndl(); 11497 11498 if (cur_snap != NULL) { 11499 struct snaplevel *elt; 11500 char *buf; 11501 11502 /* Error unless name is that of the next level. */ 11503 elt = uu_list_next(cur_levels, cur_elt); 11504 if (elt == NULL) { 11505 semerr(gettext("No children.\n")); 11506 return; 11507 } 11508 11509 buf = safe_malloc(max_scf_name_len + 1); 11510 11511 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11512 max_scf_name_len + 1) < 0) 11513 scfdie(); 11514 11515 if (strcmp(buf, fmri) != 0) { 11516 semerr(gettext("No such child.\n")); 11517 free(buf); 11518 return; 11519 } 11520 11521 free(buf); 11522 11523 cur_elt = elt; 11524 cur_level = elt->sl; 11525 return; 11526 } 11527 11528 /* 11529 * Special case for 'svc:', which takes the user to the scope level. 11530 */ 11531 if (strcmp(fmri, "svc:") == 0) { 11532 scf_instance_destroy(cur_inst); 11533 scf_service_destroy(cur_svc); 11534 cur_inst = NULL; 11535 cur_svc = NULL; 11536 return; 11537 } 11538 11539 /* 11540 * Special case for ':properties'. This appears as part of 'list' but 11541 * can't be selected. Give a more helpful error message in this case. 11542 */ 11543 if (strcmp(fmri, ":properties") == 0) { 11544 semerr(gettext(":properties is not an entity. Try 'listprop' " 11545 "to list properties.\n")); 11546 return; 11547 } 11548 11549 /* 11550 * First try the argument as relative to the current selection. 11551 */ 11552 if (cur_inst != NULL) { 11553 /* EMPTY */; 11554 } else if (cur_svc != NULL) { 11555 if (select_inst(fmri) != 1) 11556 return; 11557 } else { 11558 if (select_svc(fmri) != 1) 11559 return; 11560 } 11561 11562 err = 0; 11563 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11564 select_callback, NULL, &err, semerr)) != 0) { 11565 semerr(gettext("Failed to walk instances: %s\n"), 11566 scf_strerror(ret)); 11567 } 11568 } 11569 11570 void 11571 lscf_unselect(void) 11572 { 11573 lscf_prep_hndl(); 11574 11575 if (cur_snap != NULL) { 11576 struct snaplevel *elt; 11577 11578 elt = uu_list_prev(cur_levels, cur_elt); 11579 if (elt == NULL) { 11580 semerr(gettext("No parent levels.\n")); 11581 } else { 11582 cur_elt = elt; 11583 cur_level = elt->sl; 11584 } 11585 } else if (cur_inst != NULL) { 11586 scf_instance_destroy(cur_inst); 11587 cur_inst = NULL; 11588 } else if (cur_svc != NULL) { 11589 scf_service_destroy(cur_svc); 11590 cur_svc = NULL; 11591 } else { 11592 semerr(gettext("Cannot unselect at scope level.\n")); 11593 } 11594 } 11595 11596 /* 11597 * Return the FMRI of the current selection, for the prompt. 11598 */ 11599 void 11600 lscf_get_selection_str(char *buf, size_t bufsz) 11601 { 11602 char *cp; 11603 ssize_t fmrilen, szret; 11604 boolean_t deleted = B_FALSE; 11605 11606 if (g_hndl == NULL) { 11607 (void) strlcpy(buf, "svc:", bufsz); 11608 return; 11609 } 11610 11611 if (cur_level != NULL) { 11612 assert(cur_snap != NULL); 11613 11614 /* [ snapshot ] FMRI [: instance ] */ 11615 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11616 + 2 + max_scf_name_len + 1 + 1); 11617 11618 buf[0] = '['; 11619 11620 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11621 max_scf_name_len + 1); 11622 if (szret < 0) { 11623 if (scf_error() != SCF_ERROR_DELETED) 11624 scfdie(); 11625 11626 goto snap_deleted; 11627 } 11628 11629 (void) strcat(buf, "]svc:/"); 11630 11631 cp = strchr(buf, '\0'); 11632 11633 szret = scf_snaplevel_get_service_name(cur_level, cp, 11634 max_scf_name_len + 1); 11635 if (szret < 0) { 11636 if (scf_error() != SCF_ERROR_DELETED) 11637 scfdie(); 11638 11639 goto snap_deleted; 11640 } 11641 11642 cp = strchr(cp, '\0'); 11643 11644 if (snaplevel_is_instance(cur_level)) { 11645 *cp++ = ':'; 11646 11647 if (scf_snaplevel_get_instance_name(cur_level, cp, 11648 max_scf_name_len + 1) < 0) { 11649 if (scf_error() != SCF_ERROR_DELETED) 11650 scfdie(); 11651 11652 goto snap_deleted; 11653 } 11654 } else { 11655 *cp++ = '['; 11656 *cp++ = ':'; 11657 11658 if (scf_instance_get_name(cur_inst, cp, 11659 max_scf_name_len + 1) < 0) { 11660 if (scf_error() != SCF_ERROR_DELETED) 11661 scfdie(); 11662 11663 goto snap_deleted; 11664 } 11665 11666 (void) strcat(buf, "]"); 11667 } 11668 11669 return; 11670 11671 snap_deleted: 11672 deleted = B_TRUE; 11673 free(buf); 11674 unselect_cursnap(); 11675 } 11676 11677 assert(cur_snap == NULL); 11678 11679 if (cur_inst != NULL) { 11680 assert(cur_svc != NULL); 11681 assert(cur_scope != NULL); 11682 11683 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11684 if (fmrilen >= 0) { 11685 assert(fmrilen < bufsz); 11686 if (deleted) 11687 warn(emsg_deleted); 11688 return; 11689 } 11690 11691 if (scf_error() != SCF_ERROR_DELETED) 11692 scfdie(); 11693 11694 deleted = B_TRUE; 11695 11696 scf_instance_destroy(cur_inst); 11697 cur_inst = NULL; 11698 } 11699 11700 if (cur_svc != NULL) { 11701 assert(cur_scope != NULL); 11702 11703 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11704 if (szret >= 0) { 11705 assert(szret < bufsz); 11706 if (deleted) 11707 warn(emsg_deleted); 11708 return; 11709 } 11710 11711 if (scf_error() != SCF_ERROR_DELETED) 11712 scfdie(); 11713 11714 deleted = B_TRUE; 11715 scf_service_destroy(cur_svc); 11716 cur_svc = NULL; 11717 } 11718 11719 assert(cur_scope != NULL); 11720 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11721 11722 if (fmrilen < 0) 11723 scfdie(); 11724 11725 assert(fmrilen < bufsz); 11726 if (deleted) 11727 warn(emsg_deleted); 11728 } 11729 11730 /* 11731 * Entity listing. Entities and colon namespaces (e.g., :properties and 11732 * :statistics) are listed for the current selection. 11733 */ 11734 void 11735 lscf_list(const char *pattern) 11736 { 11737 scf_iter_t *iter; 11738 char *buf; 11739 int ret; 11740 11741 lscf_prep_hndl(); 11742 11743 if (cur_level != NULL) { 11744 struct snaplevel *elt; 11745 11746 (void) fputs(COLON_NAMESPACES, stdout); 11747 11748 elt = uu_list_next(cur_levels, cur_elt); 11749 if (elt == NULL) 11750 return; 11751 11752 /* 11753 * For now, we know that the next level is an instance. But 11754 * if we ever have multiple scopes, this could be complicated. 11755 */ 11756 buf = safe_malloc(max_scf_name_len + 1); 11757 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11758 max_scf_name_len + 1) >= 0) { 11759 (void) puts(buf); 11760 } else { 11761 if (scf_error() != SCF_ERROR_DELETED) 11762 scfdie(); 11763 } 11764 11765 free(buf); 11766 11767 return; 11768 } 11769 11770 if (cur_inst != NULL) { 11771 (void) fputs(COLON_NAMESPACES, stdout); 11772 return; 11773 } 11774 11775 iter = scf_iter_create(g_hndl); 11776 if (iter == NULL) 11777 scfdie(); 11778 11779 buf = safe_malloc(max_scf_name_len + 1); 11780 11781 if (cur_svc != NULL) { 11782 /* List the instances in this service. */ 11783 scf_instance_t *inst; 11784 11785 inst = scf_instance_create(g_hndl); 11786 if (inst == NULL) 11787 scfdie(); 11788 11789 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11790 safe_printf(COLON_NAMESPACES); 11791 11792 for (;;) { 11793 ret = scf_iter_next_instance(iter, inst); 11794 if (ret == 0) 11795 break; 11796 if (ret != 1) { 11797 if (scf_error() != SCF_ERROR_DELETED) 11798 scfdie(); 11799 11800 break; 11801 } 11802 11803 if (scf_instance_get_name(inst, buf, 11804 max_scf_name_len + 1) >= 0) { 11805 if (pattern == NULL || 11806 fnmatch(pattern, buf, 0) == 0) 11807 (void) puts(buf); 11808 } else { 11809 if (scf_error() != SCF_ERROR_DELETED) 11810 scfdie(); 11811 } 11812 } 11813 } else { 11814 if (scf_error() != SCF_ERROR_DELETED) 11815 scfdie(); 11816 } 11817 11818 scf_instance_destroy(inst); 11819 } else { 11820 /* List the services in this scope. */ 11821 scf_service_t *svc; 11822 11823 assert(cur_scope != NULL); 11824 11825 svc = scf_service_create(g_hndl); 11826 if (svc == NULL) 11827 scfdie(); 11828 11829 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11830 scfdie(); 11831 11832 for (;;) { 11833 ret = scf_iter_next_service(iter, svc); 11834 if (ret == 0) 11835 break; 11836 if (ret != 1) 11837 scfdie(); 11838 11839 if (scf_service_get_name(svc, buf, 11840 max_scf_name_len + 1) >= 0) { 11841 if (pattern == NULL || 11842 fnmatch(pattern, buf, 0) == 0) 11843 safe_printf("%s\n", buf); 11844 } else { 11845 if (scf_error() != SCF_ERROR_DELETED) 11846 scfdie(); 11847 } 11848 } 11849 11850 scf_service_destroy(svc); 11851 } 11852 11853 free(buf); 11854 scf_iter_destroy(iter); 11855 } 11856 11857 /* 11858 * Entity addition. Creates an empty entity in the current selection. 11859 */ 11860 void 11861 lscf_add(const char *name) 11862 { 11863 lscf_prep_hndl(); 11864 11865 if (cur_snap != NULL) { 11866 semerr(emsg_cant_modify_snapshots); 11867 } else if (cur_inst != NULL) { 11868 semerr(gettext("Cannot add entities to an instance.\n")); 11869 } else if (cur_svc != NULL) { 11870 11871 if (scf_service_add_instance(cur_svc, name, NULL) != 11872 SCF_SUCCESS) { 11873 switch (scf_error()) { 11874 case SCF_ERROR_INVALID_ARGUMENT: 11875 semerr(gettext("Invalid name.\n")); 11876 break; 11877 11878 case SCF_ERROR_EXISTS: 11879 semerr(gettext("Instance already exists.\n")); 11880 break; 11881 11882 case SCF_ERROR_PERMISSION_DENIED: 11883 semerr(emsg_permission_denied); 11884 break; 11885 11886 default: 11887 scfdie(); 11888 } 11889 } 11890 } else { 11891 assert(cur_scope != NULL); 11892 11893 if (scf_scope_add_service(cur_scope, name, NULL) != 11894 SCF_SUCCESS) { 11895 switch (scf_error()) { 11896 case SCF_ERROR_INVALID_ARGUMENT: 11897 semerr(gettext("Invalid name.\n")); 11898 break; 11899 11900 case SCF_ERROR_EXISTS: 11901 semerr(gettext("Service already exists.\n")); 11902 break; 11903 11904 case SCF_ERROR_PERMISSION_DENIED: 11905 semerr(emsg_permission_denied); 11906 break; 11907 11908 case SCF_ERROR_BACKEND_READONLY: 11909 semerr(emsg_read_only); 11910 break; 11911 11912 default: 11913 scfdie(); 11914 } 11915 } 11916 } 11917 } 11918 11919 /* return 1 if the entity has no persistent pgs, else return 0 */ 11920 static int 11921 entity_has_no_pgs(void *ent, int isservice) 11922 { 11923 scf_iter_t *iter = NULL; 11924 scf_propertygroup_t *pg = NULL; 11925 uint32_t flags; 11926 int err; 11927 int ret = 1; 11928 11929 if ((iter = scf_iter_create(g_hndl)) == NULL || 11930 (pg = scf_pg_create(g_hndl)) == NULL) 11931 scfdie(); 11932 11933 if (isservice) { 11934 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11935 scfdie(); 11936 } else { 11937 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11938 scfdie(); 11939 } 11940 11941 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11942 if (scf_pg_get_flags(pg, &flags) != 0) 11943 scfdie(); 11944 11945 /* skip nonpersistent pgs */ 11946 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11947 continue; 11948 11949 ret = 0; 11950 break; 11951 } 11952 11953 if (err == -1) 11954 scfdie(); 11955 11956 scf_pg_destroy(pg); 11957 scf_iter_destroy(iter); 11958 11959 return (ret); 11960 } 11961 11962 /* return 1 if the service has no instances, else return 0 */ 11963 static int 11964 svc_has_no_insts(scf_service_t *svc) 11965 { 11966 scf_instance_t *inst; 11967 scf_iter_t *iter; 11968 int r; 11969 int ret = 1; 11970 11971 if ((inst = scf_instance_create(g_hndl)) == NULL || 11972 (iter = scf_iter_create(g_hndl)) == NULL) 11973 scfdie(); 11974 11975 if (scf_iter_service_instances(iter, svc) != 0) 11976 scfdie(); 11977 11978 r = scf_iter_next_instance(iter, inst); 11979 if (r == 1) { 11980 ret = 0; 11981 } else if (r == 0) { 11982 ret = 1; 11983 } else if (r == -1) { 11984 scfdie(); 11985 } else { 11986 bad_error("scf_iter_next_instance", r); 11987 } 11988 11989 scf_iter_destroy(iter); 11990 scf_instance_destroy(inst); 11991 11992 return (ret); 11993 } 11994 11995 /* 11996 * Entity deletion. 11997 */ 11998 11999 /* 12000 * Delete the property group <fmri>/:properties/<name>. Returns 12001 * SCF_ERROR_NONE on success (or if the entity is not found), 12002 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 12003 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 12004 * denied. 12005 */ 12006 static scf_error_t 12007 delete_dependency_pg(const char *fmri, const char *name) 12008 { 12009 void *entity = NULL; 12010 int isservice; 12011 scf_propertygroup_t *pg = NULL; 12012 scf_error_t result; 12013 char *pgty; 12014 scf_service_t *svc = NULL; 12015 scf_instance_t *inst = NULL; 12016 scf_iter_t *iter = NULL; 12017 char *name_buf = NULL; 12018 12019 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 12020 switch (result) { 12021 case SCF_ERROR_NONE: 12022 break; 12023 12024 case SCF_ERROR_NO_MEMORY: 12025 uu_die(gettext("Out of memory.\n")); 12026 /* NOTREACHED */ 12027 12028 case SCF_ERROR_INVALID_ARGUMENT: 12029 case SCF_ERROR_CONSTRAINT_VIOLATED: 12030 return (SCF_ERROR_INVALID_ARGUMENT); 12031 12032 case SCF_ERROR_NOT_FOUND: 12033 result = SCF_ERROR_NONE; 12034 goto out; 12035 12036 default: 12037 bad_error("fmri_to_entity", result); 12038 } 12039 12040 pg = scf_pg_create(g_hndl); 12041 if (pg == NULL) 12042 scfdie(); 12043 12044 if (entity_get_pg(entity, isservice, name, pg) != 0) { 12045 if (scf_error() != SCF_ERROR_NOT_FOUND) 12046 scfdie(); 12047 12048 result = SCF_ERROR_NONE; 12049 goto out; 12050 } 12051 12052 pgty = safe_malloc(max_scf_pg_type_len + 1); 12053 12054 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12055 scfdie(); 12056 12057 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 12058 result = SCF_ERROR_TYPE_MISMATCH; 12059 free(pgty); 12060 goto out; 12061 } 12062 12063 free(pgty); 12064 12065 if (scf_pg_delete(pg) != 0) { 12066 result = scf_error(); 12067 if (result != SCF_ERROR_PERMISSION_DENIED) 12068 scfdie(); 12069 goto out; 12070 } 12071 12072 /* 12073 * We have to handle the case where we've just deleted the last 12074 * property group of a "dummy" entity (instance or service). 12075 * A "dummy" entity is an entity only present to hold an 12076 * external dependency. 12077 * So, in the case we deleted the last property group then we 12078 * can also delete the entity. If the entity is an instance then 12079 * we must verify if this was the last instance for the service 12080 * and if it is, we can also delete the service if it doesn't 12081 * have any property group either. 12082 */ 12083 12084 result = SCF_ERROR_NONE; 12085 12086 if (isservice) { 12087 svc = (scf_service_t *)entity; 12088 12089 if ((inst = scf_instance_create(g_hndl)) == NULL || 12090 (iter = scf_iter_create(g_hndl)) == NULL) 12091 scfdie(); 12092 12093 name_buf = safe_malloc(max_scf_name_len + 1); 12094 } else { 12095 inst = (scf_instance_t *)entity; 12096 } 12097 12098 /* 12099 * If the entity is an instance and we've just deleted its last 12100 * property group then we should delete it. 12101 */ 12102 if (!isservice && entity_has_no_pgs(entity, isservice)) { 12103 /* find the service before deleting the inst. - needed later */ 12104 if ((svc = scf_service_create(g_hndl)) == NULL) 12105 scfdie(); 12106 12107 if (scf_instance_get_parent(inst, svc) != 0) 12108 scfdie(); 12109 12110 /* delete the instance */ 12111 if (scf_instance_delete(inst) != 0) { 12112 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12113 scfdie(); 12114 12115 result = SCF_ERROR_PERMISSION_DENIED; 12116 goto out; 12117 } 12118 /* no need to refresh the instance */ 12119 inst = NULL; 12120 } 12121 12122 /* 12123 * If the service has no more instances and pgs or we just deleted the 12124 * last instance and the service doesn't have anymore propery groups 12125 * then the service should be deleted. 12126 */ 12127 if (svc != NULL && 12128 svc_has_no_insts(svc) && 12129 entity_has_no_pgs((void *)svc, 1)) { 12130 if (scf_service_delete(svc) == 0) { 12131 if (isservice) { 12132 /* no need to refresh the service */ 12133 svc = NULL; 12134 } 12135 12136 goto out; 12137 } 12138 12139 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12140 scfdie(); 12141 12142 result = SCF_ERROR_PERMISSION_DENIED; 12143 } 12144 12145 /* if the entity has not been deleted, refresh it */ 12146 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 12147 (void) refresh_entity(isservice, entity, fmri, inst, iter, 12148 name_buf); 12149 } 12150 12151 out: 12152 if (isservice && (inst != NULL && iter != NULL)) { 12153 free(name_buf); 12154 scf_iter_destroy(iter); 12155 scf_instance_destroy(inst); 12156 } 12157 12158 if (!isservice && svc != NULL) { 12159 scf_service_destroy(svc); 12160 } 12161 12162 scf_pg_destroy(pg); 12163 if (entity != NULL) 12164 entity_destroy(entity, isservice); 12165 12166 return (result); 12167 } 12168 12169 static int 12170 delete_dependents(scf_propertygroup_t *pg) 12171 { 12172 char *pgty, *name, *fmri; 12173 scf_property_t *prop; 12174 scf_value_t *val; 12175 scf_iter_t *iter; 12176 int r; 12177 scf_error_t err; 12178 12179 /* Verify that the pg has the correct type. */ 12180 pgty = safe_malloc(max_scf_pg_type_len + 1); 12181 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12182 scfdie(); 12183 12184 if (strcmp(pgty, scf_group_framework) != 0) { 12185 if (g_verbose) { 12186 fmri = safe_malloc(max_scf_fmri_len + 1); 12187 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 12188 scfdie(); 12189 12190 warn(gettext("Property group %s is not of expected " 12191 "type %s.\n"), fmri, scf_group_framework); 12192 12193 free(fmri); 12194 } 12195 12196 free(pgty); 12197 return (-1); 12198 } 12199 12200 free(pgty); 12201 12202 /* map delete_dependency_pg onto the properties. */ 12203 if ((prop = scf_property_create(g_hndl)) == NULL || 12204 (val = scf_value_create(g_hndl)) == NULL || 12205 (iter = scf_iter_create(g_hndl)) == NULL) 12206 scfdie(); 12207 12208 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 12209 scfdie(); 12210 12211 name = safe_malloc(max_scf_name_len + 1); 12212 fmri = safe_malloc(max_scf_fmri_len + 2); 12213 12214 while ((r = scf_iter_next_property(iter, prop)) == 1) { 12215 scf_type_t ty; 12216 12217 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 12218 scfdie(); 12219 12220 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 12221 scfdie(); 12222 12223 if ((ty != SCF_TYPE_ASTRING && 12224 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 12225 prop_get_val(prop, val) != 0) 12226 continue; 12227 12228 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 12229 scfdie(); 12230 12231 err = delete_dependency_pg(fmri, name); 12232 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 12233 if (scf_property_to_fmri(prop, fmri, 12234 max_scf_fmri_len + 2) < 0) 12235 scfdie(); 12236 12237 warn(gettext("Value of %s is not a valid FMRI.\n"), 12238 fmri); 12239 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 12240 warn(gettext("Property group \"%s\" of entity \"%s\" " 12241 "does not have dependency type.\n"), name, fmri); 12242 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 12243 warn(gettext("Could not delete property group \"%s\" " 12244 "of entity \"%s\" (permission denied).\n"), name, 12245 fmri); 12246 } 12247 } 12248 if (r == -1) 12249 scfdie(); 12250 12251 scf_value_destroy(val); 12252 scf_property_destroy(prop); 12253 12254 return (0); 12255 } 12256 12257 /* 12258 * Returns 1 if the instance may be running, and 0 otherwise. 12259 */ 12260 static int 12261 inst_is_running(scf_instance_t *inst) 12262 { 12263 scf_propertygroup_t *pg; 12264 scf_property_t *prop; 12265 scf_value_t *val; 12266 char buf[MAX_SCF_STATE_STRING_SZ]; 12267 int ret = 0; 12268 ssize_t szret; 12269 12270 if ((pg = scf_pg_create(g_hndl)) == NULL || 12271 (prop = scf_property_create(g_hndl)) == NULL || 12272 (val = scf_value_create(g_hndl)) == NULL) 12273 scfdie(); 12274 12275 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 12276 if (scf_error() != SCF_ERROR_NOT_FOUND) 12277 scfdie(); 12278 goto out; 12279 } 12280 12281 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 12282 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 12283 prop_get_val(prop, val) != 0) 12284 goto out; 12285 12286 szret = scf_value_get_astring(val, buf, sizeof (buf)); 12287 assert(szret >= 0); 12288 12289 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 12290 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 12291 12292 out: 12293 scf_value_destroy(val); 12294 scf_property_destroy(prop); 12295 scf_pg_destroy(pg); 12296 return (ret); 12297 } 12298 12299 static uint8_t 12300 pg_is_external_dependency(scf_propertygroup_t *pg) 12301 { 12302 char *type; 12303 scf_value_t *val; 12304 scf_property_t *prop; 12305 uint8_t b = B_FALSE; 12306 12307 type = safe_malloc(max_scf_pg_type_len + 1); 12308 12309 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 12310 scfdie(); 12311 12312 if ((prop = scf_property_create(g_hndl)) == NULL || 12313 (val = scf_value_create(g_hndl)) == NULL) 12314 scfdie(); 12315 12316 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 12317 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 12318 if (scf_property_get_value(prop, val) != 0) 12319 scfdie(); 12320 if (scf_value_get_boolean(val, &b) != 0) 12321 scfdie(); 12322 } 12323 } 12324 12325 free(type); 12326 (void) scf_value_destroy(val); 12327 (void) scf_property_destroy(prop); 12328 12329 return (b); 12330 } 12331 12332 #define DELETE_FAILURE -1 12333 #define DELETE_SUCCESS_NOEXTDEPS 0 12334 #define DELETE_SUCCESS_EXTDEPS 1 12335 12336 /* 12337 * lscf_instance_delete() deletes an instance. Before calling 12338 * scf_instance_delete(), though, we make sure the instance isn't 12339 * running and delete dependencies in other entities which the instance 12340 * declared as "dependents". If there are dependencies which were 12341 * created for other entities, then instead of deleting the instance we 12342 * make it "empty" by deleting all other property groups and all 12343 * snapshots. 12344 * 12345 * lscf_instance_delete() verifies that there is no external dependency pgs 12346 * before suppressing the instance. If there is, then we must not remove them 12347 * now in case the instance is re-created otherwise the dependencies would be 12348 * lost. The external dependency pgs will be removed if the dependencies are 12349 * removed. 12350 * 12351 * Returns: 12352 * DELETE_FAILURE on failure 12353 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12354 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12355 */ 12356 static int 12357 lscf_instance_delete(scf_instance_t *inst, int force) 12358 { 12359 scf_propertygroup_t *pg; 12360 scf_snapshot_t *snap; 12361 scf_iter_t *iter; 12362 int err; 12363 int external = 0; 12364 12365 /* If we're not forcing and the instance is running, refuse. */ 12366 if (!force && inst_is_running(inst)) { 12367 char *fmri; 12368 12369 fmri = safe_malloc(max_scf_fmri_len + 1); 12370 12371 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 12372 scfdie(); 12373 12374 semerr(gettext("Instance %s may be running. " 12375 "Use delete -f if it is not.\n"), fmri); 12376 12377 free(fmri); 12378 return (DELETE_FAILURE); 12379 } 12380 12381 pg = scf_pg_create(g_hndl); 12382 if (pg == NULL) 12383 scfdie(); 12384 12385 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 12386 (void) delete_dependents(pg); 12387 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12388 scfdie(); 12389 12390 scf_pg_destroy(pg); 12391 12392 /* 12393 * If the instance has some external dependencies then we must 12394 * keep them in case the instance is reimported otherwise the 12395 * dependencies would be lost on reimport. 12396 */ 12397 if ((iter = scf_iter_create(g_hndl)) == NULL || 12398 (pg = scf_pg_create(g_hndl)) == NULL) 12399 scfdie(); 12400 12401 if (scf_iter_instance_pgs(iter, inst) < 0) 12402 scfdie(); 12403 12404 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 12405 if (pg_is_external_dependency(pg)) { 12406 external = 1; 12407 continue; 12408 } 12409 12410 if (scf_pg_delete(pg) != 0) { 12411 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12412 scfdie(); 12413 else { 12414 semerr(emsg_permission_denied); 12415 12416 (void) scf_iter_destroy(iter); 12417 (void) scf_pg_destroy(pg); 12418 return (DELETE_FAILURE); 12419 } 12420 } 12421 } 12422 12423 if (err == -1) 12424 scfdie(); 12425 12426 (void) scf_iter_destroy(iter); 12427 (void) scf_pg_destroy(pg); 12428 12429 if (external) { 12430 /* 12431 * All the pgs have been deleted for the instance except 12432 * the ones holding the external dependencies. 12433 * For the job to be complete, we must also delete the 12434 * snapshots associated with the instance. 12435 */ 12436 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 12437 NULL) 12438 scfdie(); 12439 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 12440 scfdie(); 12441 12442 if (scf_iter_instance_snapshots(iter, inst) == -1) 12443 scfdie(); 12444 12445 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 12446 if (_scf_snapshot_delete(snap) != 0) { 12447 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12448 scfdie(); 12449 12450 semerr(emsg_permission_denied); 12451 12452 (void) scf_iter_destroy(iter); 12453 (void) scf_snapshot_destroy(snap); 12454 return (DELETE_FAILURE); 12455 } 12456 } 12457 12458 if (err == -1) 12459 scfdie(); 12460 12461 (void) scf_iter_destroy(iter); 12462 (void) scf_snapshot_destroy(snap); 12463 return (DELETE_SUCCESS_EXTDEPS); 12464 } 12465 12466 if (scf_instance_delete(inst) != 0) { 12467 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12468 scfdie(); 12469 12470 semerr(emsg_permission_denied); 12471 12472 return (DELETE_FAILURE); 12473 } 12474 12475 return (DELETE_SUCCESS_NOEXTDEPS); 12476 } 12477 12478 /* 12479 * lscf_service_delete() deletes a service. Before calling 12480 * scf_service_delete(), though, we call lscf_instance_delete() for 12481 * each of the instances and delete dependencies in other entities 12482 * which were created as "dependents" of this service. If there are 12483 * dependencies which were created for other entities, then we delete 12484 * all other property groups in the service and leave it as "empty". 12485 * 12486 * lscf_service_delete() verifies that there is no external dependency 12487 * pgs at the instance & service level before suppressing the service. 12488 * If there is, then we must not remove them now in case the service 12489 * is re-imported otherwise the dependencies would be lost. The external 12490 * dependency pgs will be removed if the dependencies are removed. 12491 * 12492 * Returns: 12493 * DELETE_FAILURE on failure 12494 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12495 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12496 */ 12497 static int 12498 lscf_service_delete(scf_service_t *svc, int force) 12499 { 12500 int r; 12501 scf_instance_t *inst; 12502 scf_propertygroup_t *pg; 12503 scf_iter_t *iter; 12504 int ret; 12505 int external = 0; 12506 12507 if ((inst = scf_instance_create(g_hndl)) == NULL || 12508 (pg = scf_pg_create(g_hndl)) == NULL || 12509 (iter = scf_iter_create(g_hndl)) == NULL) 12510 scfdie(); 12511 12512 if (scf_iter_service_instances(iter, svc) != 0) 12513 scfdie(); 12514 12515 for (r = scf_iter_next_instance(iter, inst); 12516 r == 1; 12517 r = scf_iter_next_instance(iter, inst)) { 12518 12519 ret = lscf_instance_delete(inst, force); 12520 if (ret == DELETE_FAILURE) { 12521 scf_iter_destroy(iter); 12522 scf_pg_destroy(pg); 12523 scf_instance_destroy(inst); 12524 return (DELETE_FAILURE); 12525 } 12526 12527 /* 12528 * Record the fact that there is some external dependencies 12529 * at the instance level. 12530 */ 12531 if (ret == DELETE_SUCCESS_EXTDEPS) 12532 external |= 1; 12533 } 12534 12535 if (r != 0) 12536 scfdie(); 12537 12538 /* Delete dependency property groups in dependent services. */ 12539 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12540 (void) delete_dependents(pg); 12541 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12542 scfdie(); 12543 12544 scf_iter_destroy(iter); 12545 scf_pg_destroy(pg); 12546 scf_instance_destroy(inst); 12547 12548 /* 12549 * If the service has some external dependencies then we don't 12550 * want to remove them in case the service is re-imported. 12551 */ 12552 if ((pg = scf_pg_create(g_hndl)) == NULL || 12553 (iter = scf_iter_create(g_hndl)) == NULL) 12554 scfdie(); 12555 12556 if (scf_iter_service_pgs(iter, svc) < 0) 12557 scfdie(); 12558 12559 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12560 if (pg_is_external_dependency(pg)) { 12561 external |= 2; 12562 continue; 12563 } 12564 12565 if (scf_pg_delete(pg) != 0) { 12566 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12567 scfdie(); 12568 else { 12569 semerr(emsg_permission_denied); 12570 12571 (void) scf_iter_destroy(iter); 12572 (void) scf_pg_destroy(pg); 12573 return (DELETE_FAILURE); 12574 } 12575 } 12576 } 12577 12578 if (r == -1) 12579 scfdie(); 12580 12581 (void) scf_iter_destroy(iter); 12582 (void) scf_pg_destroy(pg); 12583 12584 if (external != 0) 12585 return (DELETE_SUCCESS_EXTDEPS); 12586 12587 if (scf_service_delete(svc) == 0) 12588 return (DELETE_SUCCESS_NOEXTDEPS); 12589 12590 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12591 scfdie(); 12592 12593 semerr(emsg_permission_denied); 12594 return (DELETE_FAILURE); 12595 } 12596 12597 static int 12598 delete_callback(void *data, scf_walkinfo_t *wip) 12599 { 12600 int force = (int)data; 12601 12602 if (wip->inst != NULL) 12603 (void) lscf_instance_delete(wip->inst, force); 12604 else 12605 (void) lscf_service_delete(wip->svc, force); 12606 12607 return (0); 12608 } 12609 12610 void 12611 lscf_delete(const char *fmri, int force) 12612 { 12613 scf_service_t *svc; 12614 scf_instance_t *inst; 12615 int ret; 12616 12617 lscf_prep_hndl(); 12618 12619 if (cur_snap != NULL) { 12620 if (!snaplevel_is_instance(cur_level)) { 12621 char *buf; 12622 12623 buf = safe_malloc(max_scf_name_len + 1); 12624 if (scf_instance_get_name(cur_inst, buf, 12625 max_scf_name_len + 1) >= 0) { 12626 if (strcmp(buf, fmri) == 0) { 12627 semerr(emsg_cant_modify_snapshots); 12628 free(buf); 12629 return; 12630 } 12631 } else if (scf_error() != SCF_ERROR_DELETED) { 12632 scfdie(); 12633 } 12634 free(buf); 12635 } 12636 } else if (cur_inst != NULL) { 12637 /* EMPTY */; 12638 } else if (cur_svc != NULL) { 12639 inst = scf_instance_create(g_hndl); 12640 if (inst == NULL) 12641 scfdie(); 12642 12643 if (scf_service_get_instance(cur_svc, fmri, inst) == 12644 SCF_SUCCESS) { 12645 (void) lscf_instance_delete(inst, force); 12646 scf_instance_destroy(inst); 12647 return; 12648 } 12649 12650 if (scf_error() != SCF_ERROR_NOT_FOUND && 12651 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12652 scfdie(); 12653 12654 scf_instance_destroy(inst); 12655 } else { 12656 assert(cur_scope != NULL); 12657 12658 svc = scf_service_create(g_hndl); 12659 if (svc == NULL) 12660 scfdie(); 12661 12662 if (scf_scope_get_service(cur_scope, fmri, svc) == 12663 SCF_SUCCESS) { 12664 (void) lscf_service_delete(svc, force); 12665 scf_service_destroy(svc); 12666 return; 12667 } 12668 12669 if (scf_error() != SCF_ERROR_NOT_FOUND && 12670 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12671 scfdie(); 12672 12673 scf_service_destroy(svc); 12674 } 12675 12676 /* 12677 * Match FMRI to entity. 12678 */ 12679 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12680 delete_callback, (void *)force, NULL, semerr)) != 0) { 12681 semerr(gettext("Failed to walk instances: %s\n"), 12682 scf_strerror(ret)); 12683 } 12684 } 12685 12686 12687 12688 /* 12689 * :properties commands. These all end with "pg" or "prop" and generally 12690 * operate on the currently selected entity. 12691 */ 12692 12693 /* 12694 * Property listing. List the property groups, properties, their types and 12695 * their values for the currently selected entity. 12696 */ 12697 static void 12698 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12699 { 12700 char *buf; 12701 uint32_t flags; 12702 12703 buf = safe_malloc(max_scf_pg_type_len + 1); 12704 12705 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12706 scfdie(); 12707 12708 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12709 scfdie(); 12710 12711 safe_printf("%-*s %s", namewidth, name, buf); 12712 12713 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12714 safe_printf("\tNONPERSISTENT"); 12715 12716 safe_printf("\n"); 12717 12718 free(buf); 12719 } 12720 12721 static boolean_t 12722 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12723 { 12724 if (scf_property_get_value(prop, val) == 0) { 12725 return (B_FALSE); 12726 } else { 12727 switch (scf_error()) { 12728 case SCF_ERROR_NOT_FOUND: 12729 return (B_FALSE); 12730 case SCF_ERROR_PERMISSION_DENIED: 12731 case SCF_ERROR_CONSTRAINT_VIOLATED: 12732 return (B_TRUE); 12733 default: 12734 scfdie(); 12735 /*NOTREACHED*/ 12736 } 12737 } 12738 } 12739 12740 static void 12741 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12742 { 12743 scf_iter_t *iter; 12744 scf_value_t *val; 12745 const char *type; 12746 int multiple_strings = 0; 12747 int ret; 12748 12749 if ((iter = scf_iter_create(g_hndl)) == NULL || 12750 (val = scf_value_create(g_hndl)) == NULL) 12751 scfdie(); 12752 12753 type = prop_to_typestr(prop); 12754 assert(type != NULL); 12755 12756 safe_printf("%-*s %-7s ", len, name, type); 12757 12758 if (prop_has_multiple_values(prop, val) && 12759 (scf_value_type(val) == SCF_TYPE_ASTRING || 12760 scf_value_type(val) == SCF_TYPE_USTRING)) 12761 multiple_strings = 1; 12762 12763 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12764 scfdie(); 12765 12766 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12767 char *buf; 12768 ssize_t vlen, szret; 12769 12770 vlen = scf_value_get_as_string(val, NULL, 0); 12771 if (vlen < 0) 12772 scfdie(); 12773 12774 buf = safe_malloc(vlen + 1); 12775 12776 szret = scf_value_get_as_string(val, buf, vlen + 1); 12777 if (szret < 0) 12778 scfdie(); 12779 assert(szret <= vlen); 12780 12781 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12782 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12783 safe_printf(" \""); 12784 (void) quote_and_print(buf, stdout, 0); 12785 (void) putchar('"'); 12786 if (ferror(stdout)) { 12787 (void) putchar('\n'); 12788 uu_die(gettext("Error writing to stdout.\n")); 12789 } 12790 } else { 12791 safe_printf(" %s", buf); 12792 } 12793 12794 free(buf); 12795 } 12796 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12797 scfdie(); 12798 12799 if (putchar('\n') != '\n') 12800 uu_die(gettext("Could not output newline")); 12801 } 12802 12803 /* 12804 * Outputs template property group info for the describe subcommand. 12805 * If 'templates' == 2, verbose output is printed in the format expected 12806 * for describe -v, which includes all templates fields. If pg is 12807 * not NULL, we're describing the template data, not an existing property 12808 * group, and formatting should be appropriate for describe -t. 12809 */ 12810 static void 12811 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12812 { 12813 char *buf; 12814 uint8_t required; 12815 scf_property_t *stability_prop; 12816 scf_value_t *stability_val; 12817 12818 if (templates == 0) 12819 return; 12820 12821 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12822 (stability_val = scf_value_create(g_hndl)) == NULL) 12823 scfdie(); 12824 12825 if (templates == 2 && pg != NULL) { 12826 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12827 stability_prop) == 0) { 12828 if (prop_check_type(stability_prop, 12829 SCF_TYPE_ASTRING) == 0 && 12830 prop_get_val(stability_prop, stability_val) == 0) { 12831 char *stability; 12832 12833 stability = safe_malloc(max_scf_value_len + 1); 12834 12835 if (scf_value_get_astring(stability_val, 12836 stability, max_scf_value_len + 1) == -1 && 12837 scf_error() != SCF_ERROR_NOT_FOUND) 12838 scfdie(); 12839 12840 safe_printf("%s%s: %s\n", TMPL_INDENT, 12841 gettext("stability"), stability); 12842 12843 free(stability); 12844 } 12845 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12846 scfdie(); 12847 } 12848 12849 scf_property_destroy(stability_prop); 12850 scf_value_destroy(stability_val); 12851 12852 if (pgt == NULL) 12853 return; 12854 12855 if (pg == NULL || templates == 2) { 12856 /* print type info only if scf_tmpl_pg_name succeeds */ 12857 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12858 if (pg != NULL) 12859 safe_printf("%s", TMPL_INDENT); 12860 safe_printf("%s: ", gettext("name")); 12861 safe_printf("%s\n", buf); 12862 free(buf); 12863 } 12864 12865 /* print type info only if scf_tmpl_pg_type succeeds */ 12866 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12867 if (pg != NULL) 12868 safe_printf("%s", TMPL_INDENT); 12869 safe_printf("%s: ", gettext("type")); 12870 safe_printf("%s\n", buf); 12871 free(buf); 12872 } 12873 } 12874 12875 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12876 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12877 required ? "true" : "false"); 12878 12879 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12880 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12881 buf); 12882 free(buf); 12883 } 12884 12885 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12886 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12887 buf); 12888 free(buf); 12889 } 12890 12891 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12892 if (templates == 2) 12893 safe_printf("%s%s: %s\n", TMPL_INDENT, 12894 gettext("description"), buf); 12895 else 12896 safe_printf("%s%s\n", TMPL_INDENT, buf); 12897 free(buf); 12898 } 12899 12900 } 12901 12902 /* 12903 * With as_value set to true, indent as appropriate for the value level. 12904 * If false, indent to appropriate level for inclusion in constraint 12905 * or choice printout. 12906 */ 12907 static void 12908 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12909 int as_value) 12910 { 12911 char *buf; 12912 12913 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12914 if (as_value == 0) 12915 safe_printf("%s", TMPL_CHOICE_INDENT); 12916 else 12917 safe_printf("%s", TMPL_INDENT); 12918 safe_printf("%s: %s\n", gettext("value common name"), buf); 12919 free(buf); 12920 } 12921 12922 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12923 if (as_value == 0) 12924 safe_printf("%s", TMPL_CHOICE_INDENT); 12925 else 12926 safe_printf("%s", TMPL_INDENT); 12927 safe_printf("%s: %s\n", gettext("value description"), buf); 12928 free(buf); 12929 } 12930 } 12931 12932 static void 12933 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12934 { 12935 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12936 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12937 safe_printf("%s\n", val_buf); 12938 12939 print_template_value_details(prt, val_buf, 1); 12940 } 12941 12942 static void 12943 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12944 { 12945 int i, printed = 0; 12946 scf_values_t values; 12947 scf_count_ranges_t c_ranges; 12948 scf_int_ranges_t i_ranges; 12949 12950 printed = 0; 12951 i = 0; 12952 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12953 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12954 gettext("value constraints")); 12955 printed++; 12956 for (i = 0; i < values.value_count; ++i) { 12957 safe_printf("%s%s: %s\n", TMPL_INDENT, 12958 gettext("value name"), values.values_as_strings[i]); 12959 if (verbose == 1) 12960 print_template_value_details(prt, 12961 values.values_as_strings[i], 0); 12962 } 12963 12964 scf_values_destroy(&values); 12965 } 12966 12967 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12968 if (printed++ == 0) 12969 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12970 gettext("value constraints")); 12971 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12972 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12973 gettext("range"), c_ranges.scr_min[i], 12974 c_ranges.scr_max[i]); 12975 } 12976 scf_count_ranges_destroy(&c_ranges); 12977 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12978 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 12979 if (printed++ == 0) 12980 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12981 gettext("value constraints")); 12982 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12983 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12984 gettext("range"), i_ranges.sir_min[i], 12985 i_ranges.sir_max[i]); 12986 } 12987 scf_int_ranges_destroy(&i_ranges); 12988 } 12989 } 12990 12991 static void 12992 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 12993 { 12994 int i = 0, printed = 0; 12995 scf_values_t values; 12996 scf_count_ranges_t c_ranges; 12997 scf_int_ranges_t i_ranges; 12998 12999 printed = 0; 13000 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 13001 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13002 gettext("value constraints")); 13003 printed++; 13004 for (i = 0; i < values.value_count; i++) { 13005 safe_printf("%s%s: %s\n", TMPL_INDENT, 13006 gettext("value name"), values.values_as_strings[i]); 13007 if (verbose == 1) 13008 print_template_value_details(prt, 13009 values.values_as_strings[i], 0); 13010 } 13011 13012 scf_values_destroy(&values); 13013 } 13014 13015 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 13016 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 13017 if (printed++ == 0) 13018 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13019 gettext("value choices")); 13020 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 13021 gettext("range"), c_ranges.scr_min[i], 13022 c_ranges.scr_max[i]); 13023 } 13024 scf_count_ranges_destroy(&c_ranges); 13025 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 13026 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 13027 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 13028 if (printed++ == 0) 13029 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13030 gettext("value choices")); 13031 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 13032 gettext("range"), i_ranges.sir_min[i], 13033 i_ranges.sir_max[i]); 13034 } 13035 scf_int_ranges_destroy(&i_ranges); 13036 } 13037 } 13038 13039 static void 13040 list_values_by_template(scf_prop_tmpl_t *prt) 13041 { 13042 print_template_constraints(prt, 1); 13043 print_template_choices(prt, 1); 13044 } 13045 13046 static void 13047 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 13048 { 13049 char *val_buf; 13050 scf_iter_t *iter; 13051 scf_value_t *val; 13052 int ret; 13053 13054 if ((iter = scf_iter_create(g_hndl)) == NULL || 13055 (val = scf_value_create(g_hndl)) == NULL) 13056 scfdie(); 13057 13058 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 13059 scfdie(); 13060 13061 val_buf = safe_malloc(max_scf_value_len + 1); 13062 13063 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13064 if (scf_value_get_as_string(val, val_buf, 13065 max_scf_value_len + 1) < 0) 13066 scfdie(); 13067 13068 print_template_value(prt, val_buf); 13069 } 13070 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 13071 scfdie(); 13072 free(val_buf); 13073 13074 print_template_constraints(prt, 0); 13075 print_template_choices(prt, 0); 13076 13077 } 13078 13079 /* 13080 * Outputs property info for the describe subcommand 13081 * Verbose output if templates == 2, -v option of svccfg describe 13082 * Displays template data if prop is not NULL, -t option of svccfg describe 13083 */ 13084 static void 13085 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 13086 { 13087 char *buf; 13088 uint8_t u_buf; 13089 int i; 13090 uint64_t min, max; 13091 scf_values_t values; 13092 13093 if (prt == NULL || templates == 0) 13094 return; 13095 13096 if (prop == NULL) { 13097 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 13098 if (scf_tmpl_prop_name(prt, &buf) > 0) { 13099 safe_printf("%s\n", buf); 13100 free(buf); 13101 } else 13102 safe_printf("(%s)\n", gettext("any")); 13103 } 13104 13105 if (prop == NULL || templates == 2) { 13106 if (prop != NULL) 13107 safe_printf("%s", TMPL_INDENT); 13108 else 13109 safe_printf("%s", TMPL_VALUE_INDENT); 13110 safe_printf("%s: ", gettext("type")); 13111 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 13112 safe_printf("%s\n", buf); 13113 free(buf); 13114 } else 13115 safe_printf("(%s)\n", gettext("any")); 13116 } 13117 13118 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 13119 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 13120 u_buf ? "true" : "false"); 13121 13122 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 13123 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 13124 buf); 13125 free(buf); 13126 } 13127 13128 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 13129 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 13130 buf); 13131 free(buf); 13132 } 13133 13134 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 13135 safe_printf("%s%s\n", TMPL_INDENT, buf); 13136 free(buf); 13137 } 13138 13139 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 13140 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 13141 scf_tmpl_visibility_to_string(u_buf)); 13142 13143 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 13144 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13145 gettext("minimum number of values"), min); 13146 if (max == ULLONG_MAX) { 13147 safe_printf("%s%s: %s\n", TMPL_INDENT, 13148 gettext("maximum number of values"), 13149 gettext("unlimited")); 13150 } else { 13151 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13152 gettext("maximum number of values"), max); 13153 } 13154 } 13155 13156 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 13157 for (i = 0; i < values.value_count; i++) { 13158 if (i == 0) { 13159 safe_printf("%s%s:", TMPL_INDENT, 13160 gettext("internal separators")); 13161 } 13162 safe_printf(" \"%s\"", values.values_as_strings[i]); 13163 } 13164 safe_printf("\n"); 13165 } 13166 13167 if (templates != 2) 13168 return; 13169 13170 if (prop != NULL) 13171 list_values_tmpl(prt, prop); 13172 else 13173 list_values_by_template(prt); 13174 } 13175 13176 static char * 13177 read_astring(scf_propertygroup_t *pg, const char *prop_name) 13178 { 13179 char *rv; 13180 13181 rv = _scf_read_single_astring_from_pg(pg, prop_name); 13182 if (rv == NULL) { 13183 switch (scf_error()) { 13184 case SCF_ERROR_NOT_FOUND: 13185 break; 13186 default: 13187 scfdie(); 13188 } 13189 } 13190 return (rv); 13191 } 13192 13193 static void 13194 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 13195 { 13196 size_t doc_len; 13197 size_t man_len; 13198 char *pg_name; 13199 char *text = NULL; 13200 int rv; 13201 13202 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 13203 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 13204 pg_name = safe_malloc(max_scf_name_len + 1); 13205 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 13206 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 13207 scfdie(); 13208 } 13209 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 13210 /* Display doc_link and and uri */ 13211 safe_printf("%s%s:\n", TMPL_INDENT, 13212 gettext("doc_link")); 13213 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 13214 if (text != NULL) { 13215 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13216 TMPL_INDENT, gettext("name"), text); 13217 uu_free(text); 13218 } 13219 text = read_astring(pg, SCF_PROPERTY_TM_URI); 13220 if (text != NULL) { 13221 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 13222 gettext("uri"), text); 13223 uu_free(text); 13224 } 13225 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 13226 man_len) == 0) { 13227 /* Display manpage title, section and path */ 13228 safe_printf("%s%s:\n", TMPL_INDENT, 13229 gettext("manpage")); 13230 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 13231 if (text != NULL) { 13232 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13233 TMPL_INDENT, gettext("title"), text); 13234 uu_free(text); 13235 } 13236 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 13237 if (text != NULL) { 13238 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13239 TMPL_INDENT, gettext("section"), text); 13240 uu_free(text); 13241 } 13242 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 13243 if (text != NULL) { 13244 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13245 TMPL_INDENT, gettext("manpath"), text); 13246 uu_free(text); 13247 } 13248 } 13249 } 13250 if (rv == -1) 13251 scfdie(); 13252 13253 done: 13254 free(pg_name); 13255 } 13256 13257 static void 13258 list_entity_tmpl(int templates) 13259 { 13260 char *common_name = NULL; 13261 char *description = NULL; 13262 char *locale = NULL; 13263 scf_iter_t *iter; 13264 scf_propertygroup_t *pg; 13265 scf_property_t *prop; 13266 int r; 13267 scf_value_t *val; 13268 13269 if ((pg = scf_pg_create(g_hndl)) == NULL || 13270 (prop = scf_property_create(g_hndl)) == NULL || 13271 (val = scf_value_create(g_hndl)) == NULL || 13272 (iter = scf_iter_create(g_hndl)) == NULL) 13273 scfdie(); 13274 13275 locale = setlocale(LC_MESSAGES, NULL); 13276 13277 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 13278 common_name = safe_malloc(max_scf_value_len + 1); 13279 13280 /* Try both the current locale and the "C" locale. */ 13281 if (scf_pg_get_property(pg, locale, prop) == 0 || 13282 (scf_error() == SCF_ERROR_NOT_FOUND && 13283 scf_pg_get_property(pg, "C", prop) == 0)) { 13284 if (prop_get_val(prop, val) == 0 && 13285 scf_value_get_ustring(val, common_name, 13286 max_scf_value_len + 1) != -1) { 13287 safe_printf("%s%s: %s\n", TMPL_INDENT, 13288 gettext("common name"), common_name); 13289 } 13290 } 13291 } 13292 13293 /* 13294 * Do description, manpages, and doc links if templates == 2. 13295 */ 13296 if (templates == 2) { 13297 /* Get the description. */ 13298 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 13299 description = safe_malloc(max_scf_value_len + 1); 13300 13301 /* Try both the current locale and the "C" locale. */ 13302 if (scf_pg_get_property(pg, locale, prop) == 0 || 13303 (scf_error() == SCF_ERROR_NOT_FOUND && 13304 scf_pg_get_property(pg, "C", prop) == 0)) { 13305 if (prop_get_val(prop, val) == 0 && 13306 scf_value_get_ustring(val, description, 13307 max_scf_value_len + 1) != -1) { 13308 safe_printf("%s%s: %s\n", TMPL_INDENT, 13309 gettext("description"), 13310 description); 13311 } 13312 } 13313 } 13314 13315 /* Process doc_link & manpage elements. */ 13316 if (cur_level != NULL) { 13317 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 13318 SCF_GROUP_TEMPLATE); 13319 } else if (cur_inst != NULL) { 13320 r = scf_iter_instance_pgs_typed(iter, cur_inst, 13321 SCF_GROUP_TEMPLATE); 13322 } else { 13323 r = scf_iter_service_pgs_typed(iter, cur_svc, 13324 SCF_GROUP_TEMPLATE); 13325 } 13326 if (r == 0) { 13327 display_documentation(iter, pg); 13328 } 13329 } 13330 13331 free(common_name); 13332 free(description); 13333 scf_pg_destroy(pg); 13334 scf_property_destroy(prop); 13335 scf_value_destroy(val); 13336 scf_iter_destroy(iter); 13337 } 13338 13339 static void 13340 listtmpl(const char *pattern, int templates) 13341 { 13342 scf_pg_tmpl_t *pgt; 13343 scf_prop_tmpl_t *prt; 13344 char *snapbuf = NULL; 13345 char *fmribuf; 13346 char *pg_name = NULL, *prop_name = NULL; 13347 ssize_t prop_name_size; 13348 char *qual_prop_name; 13349 char *search_name; 13350 int listed = 0; 13351 13352 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13353 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 13354 scfdie(); 13355 13356 fmribuf = safe_malloc(max_scf_name_len + 1); 13357 qual_prop_name = safe_malloc(max_scf_name_len + 1); 13358 13359 if (cur_snap != NULL) { 13360 snapbuf = safe_malloc(max_scf_name_len + 1); 13361 if (scf_snapshot_get_name(cur_snap, snapbuf, 13362 max_scf_name_len + 1) < 0) 13363 scfdie(); 13364 } 13365 13366 if (cur_inst != NULL) { 13367 if (scf_instance_to_fmri(cur_inst, fmribuf, 13368 max_scf_name_len + 1) < 0) 13369 scfdie(); 13370 } else if (cur_svc != NULL) { 13371 if (scf_service_to_fmri(cur_svc, fmribuf, 13372 max_scf_name_len + 1) < 0) 13373 scfdie(); 13374 } else 13375 abort(); 13376 13377 /* If pattern is specified, we want to list only those items. */ 13378 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) { 13379 listed = 0; 13380 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 13381 fnmatch(pattern, pg_name, 0) == 0)) { 13382 list_pg_tmpl(pgt, NULL, templates); 13383 listed++; 13384 } 13385 13386 scf_tmpl_prop_reset(prt); 13387 13388 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) { 13389 search_name = NULL; 13390 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 13391 if ((prop_name_size > 0) && (pg_name != NULL)) { 13392 if (snprintf(qual_prop_name, 13393 max_scf_name_len + 1, "%s/%s", 13394 pg_name, prop_name) >= 13395 max_scf_name_len + 1) { 13396 prop_name_size = -1; 13397 } else { 13398 search_name = qual_prop_name; 13399 } 13400 } 13401 if (listed > 0 || pattern == NULL || 13402 (prop_name_size > 0 && 13403 fnmatch(pattern, search_name, 13404 FNM_PATHNAME) == 0)) 13405 list_prop_tmpl(prt, NULL, templates); 13406 if (prop_name != NULL) { 13407 free(prop_name); 13408 prop_name = NULL; 13409 } 13410 } 13411 if (pg_name != NULL) { 13412 free(pg_name); 13413 pg_name = NULL; 13414 } 13415 } 13416 13417 scf_tmpl_prop_destroy(prt); 13418 scf_tmpl_pg_destroy(pgt); 13419 free(snapbuf); 13420 free(fmribuf); 13421 free(qual_prop_name); 13422 } 13423 13424 static void 13425 listprop(const char *pattern, int only_pgs, int templates) 13426 { 13427 scf_propertygroup_t *pg; 13428 scf_property_t *prop; 13429 scf_iter_t *iter, *piter; 13430 char *pgnbuf, *prnbuf, *ppnbuf; 13431 scf_pg_tmpl_t *pgt, *pgtp; 13432 scf_prop_tmpl_t *prt; 13433 13434 void **objects; 13435 char **names; 13436 void **tmpls; 13437 int allocd, i; 13438 13439 int ret; 13440 ssize_t pgnlen, prnlen, szret; 13441 size_t max_len = 0; 13442 13443 if (cur_svc == NULL && cur_inst == NULL) { 13444 semerr(emsg_entity_not_selected); 13445 return; 13446 } 13447 13448 if ((pg = scf_pg_create(g_hndl)) == NULL || 13449 (prop = scf_property_create(g_hndl)) == NULL || 13450 (iter = scf_iter_create(g_hndl)) == NULL || 13451 (piter = scf_iter_create(g_hndl)) == NULL || 13452 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13453 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 13454 scfdie(); 13455 13456 prnbuf = safe_malloc(max_scf_name_len + 1); 13457 13458 if (cur_level != NULL) 13459 ret = scf_iter_snaplevel_pgs(iter, cur_level); 13460 else if (cur_inst != NULL) 13461 ret = scf_iter_instance_pgs(iter, cur_inst); 13462 else 13463 ret = scf_iter_service_pgs(iter, cur_svc); 13464 if (ret != 0) { 13465 return; 13466 } 13467 13468 /* 13469 * We want to only list items which match pattern, and we want the 13470 * second column to line up, so during the first pass we'll save 13471 * matching items, their names, and their templates in objects, 13472 * names, and tmpls, computing the maximum name length as we go, 13473 * and then we'll print them out. 13474 * 13475 * Note: We always keep an extra slot available so the array can be 13476 * NULL-terminated. 13477 */ 13478 i = 0; 13479 allocd = 1; 13480 objects = safe_malloc(sizeof (*objects)); 13481 names = safe_malloc(sizeof (*names)); 13482 tmpls = safe_malloc(sizeof (*tmpls)); 13483 13484 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13485 int new_pg = 0; 13486 int print_props = 0; 13487 pgtp = NULL; 13488 13489 pgnlen = scf_pg_get_name(pg, NULL, 0); 13490 if (pgnlen < 0) 13491 scfdie(); 13492 13493 pgnbuf = safe_malloc(pgnlen + 1); 13494 13495 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 13496 if (szret < 0) 13497 scfdie(); 13498 assert(szret <= pgnlen); 13499 13500 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) { 13501 if (scf_error() != SCF_ERROR_NOT_FOUND) 13502 scfdie(); 13503 pgtp = NULL; 13504 } else { 13505 pgtp = pgt; 13506 } 13507 13508 if (pattern == NULL || 13509 fnmatch(pattern, pgnbuf, 0) == 0) { 13510 if (i+1 >= allocd) { 13511 allocd *= 2; 13512 objects = realloc(objects, 13513 sizeof (*objects) * allocd); 13514 names = 13515 realloc(names, sizeof (*names) * allocd); 13516 tmpls = realloc(tmpls, 13517 sizeof (*tmpls) * allocd); 13518 if (objects == NULL || names == NULL || 13519 tmpls == NULL) 13520 uu_die(gettext("Out of memory")); 13521 } 13522 objects[i] = pg; 13523 names[i] = pgnbuf; 13524 13525 if (pgtp == NULL) 13526 tmpls[i] = NULL; 13527 else 13528 tmpls[i] = pgt; 13529 13530 ++i; 13531 13532 if (pgnlen > max_len) 13533 max_len = pgnlen; 13534 13535 new_pg = 1; 13536 print_props = 1; 13537 } 13538 13539 if (only_pgs) { 13540 if (new_pg) { 13541 pg = scf_pg_create(g_hndl); 13542 if (pg == NULL) 13543 scfdie(); 13544 pgt = scf_tmpl_pg_create(g_hndl); 13545 if (pgt == NULL) 13546 scfdie(); 13547 } else 13548 free(pgnbuf); 13549 13550 continue; 13551 } 13552 13553 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13554 scfdie(); 13555 13556 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13557 prnlen = scf_property_get_name(prop, prnbuf, 13558 max_scf_name_len + 1); 13559 if (prnlen < 0) 13560 scfdie(); 13561 13562 /* Will prepend the property group name and a slash. */ 13563 prnlen += pgnlen + 1; 13564 13565 ppnbuf = safe_malloc(prnlen + 1); 13566 13567 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13568 prnbuf) < 0) 13569 uu_die("snprintf"); 13570 13571 if (pattern == NULL || print_props == 1 || 13572 fnmatch(pattern, ppnbuf, 0) == 0) { 13573 if (i+1 >= allocd) { 13574 allocd *= 2; 13575 objects = realloc(objects, 13576 sizeof (*objects) * allocd); 13577 names = realloc(names, 13578 sizeof (*names) * allocd); 13579 tmpls = realloc(tmpls, 13580 sizeof (*tmpls) * allocd); 13581 if (objects == NULL || names == NULL || 13582 tmpls == NULL) 13583 uu_die(gettext( 13584 "Out of memory")); 13585 } 13586 13587 objects[i] = prop; 13588 names[i] = ppnbuf; 13589 13590 if (pgtp != NULL) { 13591 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13592 prt, 0) < 0) { 13593 if (scf_error() != 13594 SCF_ERROR_NOT_FOUND) 13595 scfdie(); 13596 tmpls[i] = NULL; 13597 } else { 13598 tmpls[i] = prt; 13599 } 13600 } else { 13601 tmpls[i] = NULL; 13602 } 13603 13604 ++i; 13605 13606 if (prnlen > max_len) 13607 max_len = prnlen; 13608 13609 prop = scf_property_create(g_hndl); 13610 prt = scf_tmpl_prop_create(g_hndl); 13611 } else { 13612 free(ppnbuf); 13613 } 13614 } 13615 13616 if (new_pg) { 13617 pg = scf_pg_create(g_hndl); 13618 if (pg == NULL) 13619 scfdie(); 13620 pgt = scf_tmpl_pg_create(g_hndl); 13621 if (pgt == NULL) 13622 scfdie(); 13623 } else 13624 free(pgnbuf); 13625 } 13626 if (ret != 0) 13627 scfdie(); 13628 13629 objects[i] = NULL; 13630 13631 scf_pg_destroy(pg); 13632 scf_tmpl_pg_destroy(pgt); 13633 scf_property_destroy(prop); 13634 scf_tmpl_prop_destroy(prt); 13635 13636 for (i = 0; objects[i] != NULL; ++i) { 13637 if (strchr(names[i], '/') == NULL) { 13638 /* property group */ 13639 pg = (scf_propertygroup_t *)objects[i]; 13640 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13641 list_pg_info(pg, names[i], max_len); 13642 list_pg_tmpl(pgt, pg, templates); 13643 free(names[i]); 13644 scf_pg_destroy(pg); 13645 if (pgt != NULL) 13646 scf_tmpl_pg_destroy(pgt); 13647 } else { 13648 /* property */ 13649 prop = (scf_property_t *)objects[i]; 13650 prt = (scf_prop_tmpl_t *)tmpls[i]; 13651 list_prop_info(prop, names[i], max_len); 13652 list_prop_tmpl(prt, prop, templates); 13653 free(names[i]); 13654 scf_property_destroy(prop); 13655 if (prt != NULL) 13656 scf_tmpl_prop_destroy(prt); 13657 } 13658 } 13659 13660 free(names); 13661 free(objects); 13662 free(tmpls); 13663 } 13664 13665 void 13666 lscf_listpg(const char *pattern) 13667 { 13668 lscf_prep_hndl(); 13669 13670 listprop(pattern, 1, 0); 13671 } 13672 13673 /* 13674 * Property group and property creation, setting, and deletion. setprop (and 13675 * its alias, addprop) can either create a property group of a given type, or 13676 * it can create or set a property to a given type and list of values. 13677 */ 13678 void 13679 lscf_addpg(const char *name, const char *type, const char *flags) 13680 { 13681 scf_propertygroup_t *pg; 13682 int ret; 13683 uint32_t flgs = 0; 13684 const char *cp; 13685 13686 13687 lscf_prep_hndl(); 13688 13689 if (cur_snap != NULL) { 13690 semerr(emsg_cant_modify_snapshots); 13691 return; 13692 } 13693 13694 if (cur_inst == NULL && cur_svc == NULL) { 13695 semerr(emsg_entity_not_selected); 13696 return; 13697 } 13698 13699 if (flags != NULL) { 13700 for (cp = flags; *cp != '\0'; ++cp) { 13701 switch (*cp) { 13702 case 'P': 13703 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13704 break; 13705 13706 case 'p': 13707 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13708 break; 13709 13710 default: 13711 semerr(gettext("Invalid property group flag " 13712 "%c."), *cp); 13713 return; 13714 } 13715 } 13716 } 13717 13718 pg = scf_pg_create(g_hndl); 13719 if (pg == NULL) 13720 scfdie(); 13721 13722 if (cur_inst != NULL) 13723 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13724 else 13725 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13726 13727 if (ret != SCF_SUCCESS) { 13728 switch (scf_error()) { 13729 case SCF_ERROR_INVALID_ARGUMENT: 13730 semerr(gettext("Name, type, or flags are invalid.\n")); 13731 break; 13732 13733 case SCF_ERROR_EXISTS: 13734 semerr(gettext("Property group already exists.\n")); 13735 break; 13736 13737 case SCF_ERROR_PERMISSION_DENIED: 13738 semerr(emsg_permission_denied); 13739 break; 13740 13741 case SCF_ERROR_BACKEND_ACCESS: 13742 semerr(gettext("Backend refused access.\n")); 13743 break; 13744 13745 default: 13746 scfdie(); 13747 } 13748 } 13749 13750 scf_pg_destroy(pg); 13751 13752 private_refresh(); 13753 } 13754 13755 void 13756 lscf_delpg(char *name) 13757 { 13758 lscf_prep_hndl(); 13759 13760 if (cur_snap != NULL) { 13761 semerr(emsg_cant_modify_snapshots); 13762 return; 13763 } 13764 13765 if (cur_inst == NULL && cur_svc == NULL) { 13766 semerr(emsg_entity_not_selected); 13767 return; 13768 } 13769 13770 if (strchr(name, '/') != NULL) { 13771 semerr(emsg_invalid_pg_name, name); 13772 return; 13773 } 13774 13775 lscf_delprop(name); 13776 } 13777 13778 /* 13779 * scf_delhash() is used to remove the property group related to the 13780 * hash entry for a specific manifest in the repository. pgname will be 13781 * constructed from the location of the manifest file. If deathrow isn't 0, 13782 * manifest file doesn't need to exist (manifest string will be used as 13783 * an absolute path). 13784 */ 13785 void 13786 lscf_delhash(char *manifest, int deathrow) 13787 { 13788 char *pgname; 13789 13790 if (cur_snap != NULL || 13791 cur_inst != NULL || cur_svc != NULL) { 13792 warn(gettext("error, an entity is selected\n")); 13793 return; 13794 } 13795 13796 /* select smf/manifest */ 13797 lscf_select(HASH_SVC); 13798 /* 13799 * Translate the manifest file name to property name. In the deathrow 13800 * case, the manifest file does not need to exist. 13801 */ 13802 pgname = mhash_filename_to_propname(manifest, 13803 deathrow ? B_TRUE : B_FALSE); 13804 if (pgname == NULL) { 13805 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13806 return; 13807 } 13808 /* delete the hash property name */ 13809 lscf_delpg(pgname); 13810 } 13811 13812 void 13813 lscf_listprop(const char *pattern) 13814 { 13815 lscf_prep_hndl(); 13816 13817 listprop(pattern, 0, 0); 13818 } 13819 13820 int 13821 lscf_setprop(const char *pgname, const char *type, const char *value, 13822 const uu_list_t *values) 13823 { 13824 scf_type_t ty, current_ty; 13825 scf_service_t *svc; 13826 scf_propertygroup_t *pg, *parent_pg; 13827 scf_property_t *prop, *parent_prop; 13828 scf_pg_tmpl_t *pgt; 13829 scf_prop_tmpl_t *prt; 13830 int ret, result = 0; 13831 scf_transaction_t *tx; 13832 scf_transaction_entry_t *e; 13833 scf_value_t *v; 13834 uu_list_walk_t *walk; 13835 string_list_t *sp; 13836 char *propname; 13837 int req_quotes = 0; 13838 13839 lscf_prep_hndl(); 13840 13841 if ((e = scf_entry_create(g_hndl)) == NULL || 13842 (svc = scf_service_create(g_hndl)) == NULL || 13843 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13844 (pg = scf_pg_create(g_hndl)) == NULL || 13845 (parent_prop = scf_property_create(g_hndl)) == NULL || 13846 (prop = scf_property_create(g_hndl)) == NULL || 13847 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13848 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13849 (tx = scf_transaction_create(g_hndl)) == NULL) 13850 scfdie(); 13851 13852 if (cur_snap != NULL) { 13853 semerr(emsg_cant_modify_snapshots); 13854 goto fail; 13855 } 13856 13857 if (cur_inst == NULL && cur_svc == NULL) { 13858 semerr(emsg_entity_not_selected); 13859 goto fail; 13860 } 13861 13862 propname = strchr(pgname, '/'); 13863 if (propname == NULL) { 13864 semerr(gettext("Property names must contain a `/'.\n")); 13865 goto fail; 13866 } 13867 13868 *propname = '\0'; 13869 ++propname; 13870 13871 if (type != NULL) { 13872 ty = string_to_type(type); 13873 if (ty == SCF_TYPE_INVALID) { 13874 semerr(gettext("Unknown type \"%s\".\n"), type); 13875 goto fail; 13876 } 13877 } 13878 13879 if (cur_inst != NULL) 13880 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13881 else 13882 ret = scf_service_get_pg(cur_svc, pgname, pg); 13883 if (ret != SCF_SUCCESS) { 13884 switch (scf_error()) { 13885 case SCF_ERROR_NOT_FOUND: 13886 semerr(emsg_no_such_pg, pgname); 13887 goto fail; 13888 13889 case SCF_ERROR_INVALID_ARGUMENT: 13890 semerr(emsg_invalid_pg_name, pgname); 13891 goto fail; 13892 13893 default: 13894 scfdie(); 13895 break; 13896 } 13897 } 13898 13899 do { 13900 if (scf_pg_update(pg) == -1) 13901 scfdie(); 13902 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13903 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13904 scfdie(); 13905 13906 semerr(emsg_permission_denied); 13907 goto fail; 13908 } 13909 13910 ret = scf_pg_get_property(pg, propname, prop); 13911 if (ret == SCF_SUCCESS) { 13912 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13913 scfdie(); 13914 13915 if (type == NULL) 13916 ty = current_ty; 13917 if (scf_transaction_property_change_type(tx, e, 13918 propname, ty) == -1) 13919 scfdie(); 13920 13921 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13922 /* Infer the type, if possible. */ 13923 if (type == NULL) { 13924 /* 13925 * First check if we're an instance and the 13926 * property is set on the service. 13927 */ 13928 if (cur_inst != NULL && 13929 scf_instance_get_parent(cur_inst, 13930 svc) == 0 && 13931 scf_service_get_pg(cur_svc, pgname, 13932 parent_pg) == 0 && 13933 scf_pg_get_property(parent_pg, propname, 13934 parent_prop) == 0 && 13935 scf_property_type(parent_prop, 13936 ¤t_ty) == 0) { 13937 ty = current_ty; 13938 13939 /* Then check for a type set in a template. */ 13940 } else if (scf_tmpl_get_by_pg(pg, pgt, 13941 0) == 0 && 13942 scf_tmpl_get_by_prop(pgt, propname, prt, 13943 0) == 0 && 13944 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13945 ty = current_ty; 13946 13947 /* If type can't be inferred, fail. */ 13948 } else { 13949 semerr(gettext("Type required for new " 13950 "properties.\n")); 13951 goto fail; 13952 } 13953 } 13954 if (scf_transaction_property_new(tx, e, propname, 13955 ty) == -1) 13956 scfdie(); 13957 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13958 semerr(emsg_invalid_prop_name, propname); 13959 goto fail; 13960 } else { 13961 scfdie(); 13962 } 13963 13964 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13965 req_quotes = 1; 13966 13967 if (value != NULL) { 13968 v = string_to_value(value, ty, 0); 13969 13970 if (v == NULL) 13971 goto fail; 13972 13973 ret = scf_entry_add_value(e, v); 13974 assert(ret == SCF_SUCCESS); 13975 } else { 13976 assert(values != NULL); 13977 13978 walk = uu_list_walk_start((uu_list_t *)values, 13979 UU_DEFAULT); 13980 if (walk == NULL) 13981 uu_die(gettext("Could not walk list")); 13982 13983 for (sp = uu_list_walk_next(walk); sp != NULL; 13984 sp = uu_list_walk_next(walk)) { 13985 v = string_to_value(sp->str, ty, req_quotes); 13986 13987 if (v == NULL) { 13988 scf_entry_destroy_children(e); 13989 goto fail; 13990 } 13991 13992 ret = scf_entry_add_value(e, v); 13993 assert(ret == SCF_SUCCESS); 13994 } 13995 uu_list_walk_end(walk); 13996 } 13997 result = scf_transaction_commit(tx); 13998 13999 scf_transaction_reset(tx); 14000 scf_entry_destroy_children(e); 14001 } while (result == 0); 14002 14003 if (result < 0) { 14004 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14005 scfdie(); 14006 14007 semerr(emsg_permission_denied); 14008 goto fail; 14009 } 14010 14011 ret = 0; 14012 14013 private_refresh(); 14014 14015 goto cleanup; 14016 14017 fail: 14018 ret = -1; 14019 14020 cleanup: 14021 scf_transaction_destroy(tx); 14022 scf_entry_destroy(e); 14023 scf_service_destroy(svc); 14024 scf_pg_destroy(parent_pg); 14025 scf_pg_destroy(pg); 14026 scf_property_destroy(parent_prop); 14027 scf_property_destroy(prop); 14028 scf_tmpl_pg_destroy(pgt); 14029 scf_tmpl_prop_destroy(prt); 14030 14031 return (ret); 14032 } 14033 14034 void 14035 lscf_delprop(char *pgn) 14036 { 14037 char *slash, *pn; 14038 scf_propertygroup_t *pg; 14039 scf_transaction_t *tx; 14040 scf_transaction_entry_t *e; 14041 int ret; 14042 14043 14044 lscf_prep_hndl(); 14045 14046 if (cur_snap != NULL) { 14047 semerr(emsg_cant_modify_snapshots); 14048 return; 14049 } 14050 14051 if (cur_inst == NULL && cur_svc == NULL) { 14052 semerr(emsg_entity_not_selected); 14053 return; 14054 } 14055 14056 pg = scf_pg_create(g_hndl); 14057 if (pg == NULL) 14058 scfdie(); 14059 14060 slash = strchr(pgn, '/'); 14061 if (slash == NULL) { 14062 pn = NULL; 14063 } else { 14064 *slash = '\0'; 14065 pn = slash + 1; 14066 } 14067 14068 if (cur_inst != NULL) 14069 ret = scf_instance_get_pg(cur_inst, pgn, pg); 14070 else 14071 ret = scf_service_get_pg(cur_svc, pgn, pg); 14072 if (ret != SCF_SUCCESS) { 14073 switch (scf_error()) { 14074 case SCF_ERROR_NOT_FOUND: 14075 semerr(emsg_no_such_pg, pgn); 14076 break; 14077 14078 case SCF_ERROR_INVALID_ARGUMENT: 14079 semerr(emsg_invalid_pg_name, pgn); 14080 break; 14081 14082 default: 14083 scfdie(); 14084 } 14085 14086 scf_pg_destroy(pg); 14087 14088 return; 14089 } 14090 14091 if (pn == NULL) { 14092 /* Try to delete the property group. */ 14093 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14094 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14095 scfdie(); 14096 14097 semerr(emsg_permission_denied); 14098 } else { 14099 private_refresh(); 14100 } 14101 14102 scf_pg_destroy(pg); 14103 return; 14104 } 14105 14106 e = scf_entry_create(g_hndl); 14107 tx = scf_transaction_create(g_hndl); 14108 14109 do { 14110 if (scf_pg_update(pg) == -1) 14111 scfdie(); 14112 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 14113 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14114 scfdie(); 14115 14116 semerr(emsg_permission_denied); 14117 break; 14118 } 14119 14120 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 14121 if (scf_error() == SCF_ERROR_NOT_FOUND) { 14122 semerr(gettext("No such property %s/%s.\n"), 14123 pgn, pn); 14124 break; 14125 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14126 semerr(emsg_invalid_prop_name, pn); 14127 break; 14128 } else { 14129 scfdie(); 14130 } 14131 } 14132 14133 ret = scf_transaction_commit(tx); 14134 14135 if (ret == 0) 14136 scf_transaction_reset(tx); 14137 } while (ret == 0); 14138 14139 if (ret < 0) { 14140 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14141 scfdie(); 14142 14143 semerr(emsg_permission_denied); 14144 } else { 14145 private_refresh(); 14146 } 14147 14148 scf_transaction_destroy(tx); 14149 scf_entry_destroy(e); 14150 scf_pg_destroy(pg); 14151 } 14152 14153 /* 14154 * Property editing. 14155 */ 14156 14157 static int 14158 write_edit_script(FILE *strm) 14159 { 14160 char *fmribuf; 14161 ssize_t fmrilen; 14162 14163 scf_propertygroup_t *pg; 14164 scf_property_t *prop; 14165 scf_value_t *val; 14166 scf_type_t ty; 14167 int ret, result = 0; 14168 scf_iter_t *iter, *piter, *viter; 14169 char *buf, *tybuf, *pname; 14170 const char *emsg_write_error; 14171 14172 14173 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 14174 14175 14176 /* select fmri */ 14177 if (cur_inst != NULL) { 14178 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 14179 if (fmrilen < 0) 14180 scfdie(); 14181 fmribuf = safe_malloc(fmrilen + 1); 14182 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 14183 scfdie(); 14184 } else { 14185 assert(cur_svc != NULL); 14186 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 14187 if (fmrilen < 0) 14188 scfdie(); 14189 fmribuf = safe_malloc(fmrilen + 1); 14190 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 14191 scfdie(); 14192 } 14193 14194 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 14195 warn(emsg_write_error, strerror(errno)); 14196 free(fmribuf); 14197 return (-1); 14198 } 14199 14200 free(fmribuf); 14201 14202 14203 if ((pg = scf_pg_create(g_hndl)) == NULL || 14204 (prop = scf_property_create(g_hndl)) == NULL || 14205 (val = scf_value_create(g_hndl)) == NULL || 14206 (iter = scf_iter_create(g_hndl)) == NULL || 14207 (piter = scf_iter_create(g_hndl)) == NULL || 14208 (viter = scf_iter_create(g_hndl)) == NULL) 14209 scfdie(); 14210 14211 buf = safe_malloc(max_scf_name_len + 1); 14212 tybuf = safe_malloc(max_scf_pg_type_len + 1); 14213 pname = safe_malloc(max_scf_name_len + 1); 14214 14215 if (cur_inst != NULL) 14216 ret = scf_iter_instance_pgs(iter, cur_inst); 14217 else 14218 ret = scf_iter_service_pgs(iter, cur_svc); 14219 if (ret != SCF_SUCCESS) 14220 scfdie(); 14221 14222 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 14223 int ret2; 14224 14225 /* 14226 * # delprop pg 14227 * # addpg pg type 14228 */ 14229 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 14230 scfdie(); 14231 14232 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 14233 scfdie(); 14234 14235 if (fprintf(strm, "# Property group \"%s\"\n" 14236 "# delprop %s\n" 14237 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 14238 warn(emsg_write_error, strerror(errno)); 14239 result = -1; 14240 goto out; 14241 } 14242 14243 /* # setprop pg/prop = (values) */ 14244 14245 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 14246 scfdie(); 14247 14248 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 14249 int first = 1; 14250 int ret3; 14251 int multiple; 14252 int is_str; 14253 scf_type_t bty; 14254 14255 if (scf_property_get_name(prop, pname, 14256 max_scf_name_len + 1) < 0) 14257 scfdie(); 14258 14259 if (scf_property_type(prop, &ty) != 0) 14260 scfdie(); 14261 14262 multiple = prop_has_multiple_values(prop, val); 14263 14264 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 14265 pname, scf_type_to_string(ty), multiple ? "(" : "") 14266 < 0) { 14267 warn(emsg_write_error, strerror(errno)); 14268 result = -1; 14269 goto out; 14270 } 14271 14272 (void) scf_type_base_type(ty, &bty); 14273 is_str = (bty == SCF_TYPE_ASTRING); 14274 14275 if (scf_iter_property_values(viter, prop) != 14276 SCF_SUCCESS) 14277 scfdie(); 14278 14279 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 14280 char *buf; 14281 ssize_t buflen; 14282 14283 buflen = scf_value_get_as_string(val, NULL, 0); 14284 if (buflen < 0) 14285 scfdie(); 14286 14287 buf = safe_malloc(buflen + 1); 14288 14289 if (scf_value_get_as_string(val, buf, 14290 buflen + 1) < 0) 14291 scfdie(); 14292 14293 if (first) 14294 first = 0; 14295 else { 14296 if (putc(' ', strm) != ' ') { 14297 warn(emsg_write_error, 14298 strerror(errno)); 14299 result = -1; 14300 goto out; 14301 } 14302 } 14303 14304 if ((is_str && multiple) || 14305 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 14306 (void) putc('"', strm); 14307 (void) quote_and_print(buf, strm, 1); 14308 (void) putc('"', strm); 14309 14310 if (ferror(strm)) { 14311 warn(emsg_write_error, 14312 strerror(errno)); 14313 result = -1; 14314 goto out; 14315 } 14316 } else { 14317 if (fprintf(strm, "%s", buf) < 0) { 14318 warn(emsg_write_error, 14319 strerror(errno)); 14320 result = -1; 14321 goto out; 14322 } 14323 } 14324 14325 free(buf); 14326 } 14327 if (ret3 < 0 && 14328 scf_error() != SCF_ERROR_PERMISSION_DENIED) 14329 scfdie(); 14330 14331 /* Write closing paren if mult-value property */ 14332 if ((multiple && putc(')', strm) == EOF) || 14333 14334 /* Write final newline */ 14335 fputc('\n', strm) == EOF) { 14336 warn(emsg_write_error, strerror(errno)); 14337 result = -1; 14338 goto out; 14339 } 14340 } 14341 if (ret2 < 0) 14342 scfdie(); 14343 14344 if (fputc('\n', strm) == EOF) { 14345 warn(emsg_write_error, strerror(errno)); 14346 result = -1; 14347 goto out; 14348 } 14349 } 14350 if (ret < 0) 14351 scfdie(); 14352 14353 out: 14354 free(pname); 14355 free(tybuf); 14356 free(buf); 14357 scf_iter_destroy(viter); 14358 scf_iter_destroy(piter); 14359 scf_iter_destroy(iter); 14360 scf_value_destroy(val); 14361 scf_property_destroy(prop); 14362 scf_pg_destroy(pg); 14363 14364 if (result == 0) { 14365 if (fflush(strm) != 0) { 14366 warn(emsg_write_error, strerror(errno)); 14367 return (-1); 14368 } 14369 } 14370 14371 return (result); 14372 } 14373 14374 int 14375 lscf_editprop() 14376 { 14377 char *buf, *editor; 14378 size_t bufsz; 14379 int tmpfd; 14380 char tempname[] = TEMP_FILE_PATTERN; 14381 14382 lscf_prep_hndl(); 14383 14384 if (cur_snap != NULL) { 14385 semerr(emsg_cant_modify_snapshots); 14386 return (-1); 14387 } 14388 14389 if (cur_svc == NULL && cur_inst == NULL) { 14390 semerr(emsg_entity_not_selected); 14391 return (-1); 14392 } 14393 14394 tmpfd = mkstemp(tempname); 14395 if (tmpfd == -1) { 14396 semerr(gettext("Could not create temporary file.\n")); 14397 return (-1); 14398 } 14399 14400 (void) strcpy(tempfilename, tempname); 14401 14402 tempfile = fdopen(tmpfd, "r+"); 14403 if (tempfile == NULL) { 14404 warn(gettext("Could not create temporary file.\n")); 14405 if (close(tmpfd) == -1) 14406 warn(gettext("Could not close temporary file: %s.\n"), 14407 strerror(errno)); 14408 14409 remove_tempfile(); 14410 14411 return (-1); 14412 } 14413 14414 if (write_edit_script(tempfile) == -1) { 14415 remove_tempfile(); 14416 return (-1); 14417 } 14418 14419 editor = getenv("EDITOR"); 14420 if (editor == NULL) 14421 editor = "vi"; 14422 14423 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 14424 buf = safe_malloc(bufsz); 14425 14426 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 14427 uu_die(gettext("Error creating editor command")); 14428 14429 if (system(buf) == -1) { 14430 semerr(gettext("Could not launch editor %s: %s\n"), editor, 14431 strerror(errno)); 14432 free(buf); 14433 remove_tempfile(); 14434 return (-1); 14435 } 14436 14437 free(buf); 14438 14439 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 14440 14441 remove_tempfile(); 14442 14443 return (0); 14444 } 14445 14446 static void 14447 add_string(uu_list_t *strlist, const char *str) 14448 { 14449 string_list_t *elem; 14450 elem = safe_malloc(sizeof (*elem)); 14451 uu_list_node_init(elem, &elem->node, string_pool); 14452 elem->str = safe_strdup(str); 14453 if (uu_list_append(strlist, elem) != 0) 14454 uu_die(gettext("libuutil error: %s\n"), 14455 uu_strerror(uu_error())); 14456 } 14457 14458 static int 14459 remove_string(uu_list_t *strlist, const char *str) 14460 { 14461 uu_list_walk_t *elems; 14462 string_list_t *sp; 14463 14464 /* 14465 * Find the element that needs to be removed. 14466 */ 14467 elems = uu_list_walk_start(strlist, UU_DEFAULT); 14468 while ((sp = uu_list_walk_next(elems)) != NULL) { 14469 if (strcmp(sp->str, str) == 0) 14470 break; 14471 } 14472 uu_list_walk_end(elems); 14473 14474 /* 14475 * Returning 1 here as the value was not found, this 14476 * might not be an error. Leave it to the caller to 14477 * decide. 14478 */ 14479 if (sp == NULL) { 14480 return (1); 14481 } 14482 14483 uu_list_remove(strlist, sp); 14484 14485 free(sp->str); 14486 free(sp); 14487 14488 return (0); 14489 } 14490 14491 /* 14492 * Get all property values that don't match the given glob pattern, 14493 * if a pattern is specified. 14494 */ 14495 static void 14496 get_prop_values(scf_property_t *prop, uu_list_t *values, 14497 const char *pattern) 14498 { 14499 scf_iter_t *iter; 14500 scf_value_t *val; 14501 int ret; 14502 14503 if ((iter = scf_iter_create(g_hndl)) == NULL || 14504 (val = scf_value_create(g_hndl)) == NULL) 14505 scfdie(); 14506 14507 if (scf_iter_property_values(iter, prop) != 0) 14508 scfdie(); 14509 14510 while ((ret = scf_iter_next_value(iter, val)) == 1) { 14511 char *buf; 14512 ssize_t vlen, szret; 14513 14514 vlen = scf_value_get_as_string(val, NULL, 0); 14515 if (vlen < 0) 14516 scfdie(); 14517 14518 buf = safe_malloc(vlen + 1); 14519 14520 szret = scf_value_get_as_string(val, buf, vlen + 1); 14521 if (szret < 0) 14522 scfdie(); 14523 assert(szret <= vlen); 14524 14525 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 14526 add_string(values, buf); 14527 14528 free(buf); 14529 } 14530 14531 if (ret == -1) 14532 scfdie(); 14533 14534 scf_value_destroy(val); 14535 scf_iter_destroy(iter); 14536 } 14537 14538 static int 14539 lscf_setpropvalue(const char *pgname, const char *type, 14540 const char *arg, int isadd, int isnotfoundok) 14541 { 14542 scf_type_t ty; 14543 scf_propertygroup_t *pg; 14544 scf_property_t *prop; 14545 int ret, result = 0; 14546 scf_transaction_t *tx; 14547 scf_transaction_entry_t *e; 14548 scf_value_t *v; 14549 string_list_t *sp; 14550 char *propname; 14551 uu_list_t *values; 14552 uu_list_walk_t *walk; 14553 void *cookie = NULL; 14554 char *pattern = NULL; 14555 14556 lscf_prep_hndl(); 14557 14558 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14559 uu_die(gettext("Could not create property list: %s\n"), 14560 uu_strerror(uu_error())); 14561 14562 if (!isadd) 14563 pattern = safe_strdup(arg); 14564 14565 if ((e = scf_entry_create(g_hndl)) == NULL || 14566 (pg = scf_pg_create(g_hndl)) == NULL || 14567 (prop = scf_property_create(g_hndl)) == NULL || 14568 (tx = scf_transaction_create(g_hndl)) == NULL) 14569 scfdie(); 14570 14571 if (cur_snap != NULL) { 14572 semerr(emsg_cant_modify_snapshots); 14573 goto fail; 14574 } 14575 14576 if (cur_inst == NULL && cur_svc == NULL) { 14577 semerr(emsg_entity_not_selected); 14578 goto fail; 14579 } 14580 14581 propname = strchr(pgname, '/'); 14582 if (propname == NULL) { 14583 semerr(gettext("Property names must contain a `/'.\n")); 14584 goto fail; 14585 } 14586 14587 *propname = '\0'; 14588 ++propname; 14589 14590 if (type != NULL) { 14591 ty = string_to_type(type); 14592 if (ty == SCF_TYPE_INVALID) { 14593 semerr(gettext("Unknown type \"%s\".\n"), type); 14594 goto fail; 14595 } 14596 } 14597 14598 if (cur_inst != NULL) 14599 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14600 else 14601 ret = scf_service_get_pg(cur_svc, pgname, pg); 14602 if (ret != 0) { 14603 switch (scf_error()) { 14604 case SCF_ERROR_NOT_FOUND: 14605 if (isnotfoundok) { 14606 result = 0; 14607 } else { 14608 semerr(emsg_no_such_pg, pgname); 14609 result = -1; 14610 } 14611 goto out; 14612 14613 case SCF_ERROR_INVALID_ARGUMENT: 14614 semerr(emsg_invalid_pg_name, pgname); 14615 goto fail; 14616 14617 default: 14618 scfdie(); 14619 } 14620 } 14621 14622 do { 14623 if (scf_pg_update(pg) == -1) 14624 scfdie(); 14625 if (scf_transaction_start(tx, pg) != 0) { 14626 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14627 scfdie(); 14628 14629 semerr(emsg_permission_denied); 14630 goto fail; 14631 } 14632 14633 ret = scf_pg_get_property(pg, propname, prop); 14634 if (ret == 0) { 14635 scf_type_t ptype; 14636 char *pat = pattern; 14637 14638 if (scf_property_type(prop, &ptype) != 0) 14639 scfdie(); 14640 14641 if (isadd) { 14642 if (type != NULL && ptype != ty) { 14643 semerr(gettext("Property \"%s\" is not " 14644 "of type \"%s\".\n"), propname, 14645 type); 14646 goto fail; 14647 } 14648 14649 pat = NULL; 14650 } else { 14651 size_t len = strlen(pat); 14652 if (len > 0 && pat[len - 1] == '\"') 14653 pat[len - 1] = '\0'; 14654 if (len > 0 && pat[0] == '\"') 14655 pat++; 14656 } 14657 14658 ty = ptype; 14659 14660 get_prop_values(prop, values, pat); 14661 14662 if (isadd) 14663 add_string(values, arg); 14664 14665 if (scf_transaction_property_change(tx, e, 14666 propname, ty) == -1) 14667 scfdie(); 14668 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14669 if (isadd) { 14670 if (type == NULL) { 14671 semerr(gettext("Type required " 14672 "for new properties.\n")); 14673 goto fail; 14674 } 14675 14676 add_string(values, arg); 14677 14678 if (scf_transaction_property_new(tx, e, 14679 propname, ty) == -1) 14680 scfdie(); 14681 } else if (isnotfoundok) { 14682 result = 0; 14683 goto out; 14684 } else { 14685 semerr(gettext("No such property %s/%s.\n"), 14686 pgname, propname); 14687 result = -1; 14688 goto out; 14689 } 14690 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14691 semerr(emsg_invalid_prop_name, propname); 14692 goto fail; 14693 } else { 14694 scfdie(); 14695 } 14696 14697 walk = uu_list_walk_start(values, UU_DEFAULT); 14698 if (walk == NULL) 14699 uu_die(gettext("Could not walk property list.\n")); 14700 14701 for (sp = uu_list_walk_next(walk); sp != NULL; 14702 sp = uu_list_walk_next(walk)) { 14703 v = string_to_value(sp->str, ty, 0); 14704 14705 if (v == NULL) { 14706 scf_entry_destroy_children(e); 14707 goto fail; 14708 } 14709 ret = scf_entry_add_value(e, v); 14710 assert(ret == 0); 14711 } 14712 uu_list_walk_end(walk); 14713 14714 result = scf_transaction_commit(tx); 14715 14716 scf_transaction_reset(tx); 14717 scf_entry_destroy_children(e); 14718 } while (result == 0); 14719 14720 if (result < 0) { 14721 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14722 scfdie(); 14723 14724 semerr(emsg_permission_denied); 14725 goto fail; 14726 } 14727 14728 result = 0; 14729 14730 private_refresh(); 14731 14732 out: 14733 scf_transaction_destroy(tx); 14734 scf_entry_destroy(e); 14735 scf_pg_destroy(pg); 14736 scf_property_destroy(prop); 14737 free(pattern); 14738 14739 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14740 free(sp->str); 14741 free(sp); 14742 } 14743 14744 uu_list_destroy(values); 14745 14746 return (result); 14747 14748 fail: 14749 result = -1; 14750 goto out; 14751 } 14752 14753 int 14754 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14755 { 14756 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14757 } 14758 14759 int 14760 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14761 { 14762 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14763 } 14764 14765 /* 14766 * Look for a standard start method, first in the instance (if any), 14767 * then the service. 14768 */ 14769 static const char * 14770 start_method_name(int *in_instance) 14771 { 14772 scf_propertygroup_t *pg; 14773 char **p; 14774 int ret; 14775 scf_instance_t *inst = cur_inst; 14776 14777 if ((pg = scf_pg_create(g_hndl)) == NULL) 14778 scfdie(); 14779 14780 again: 14781 for (p = start_method_names; *p != NULL; p++) { 14782 if (inst != NULL) 14783 ret = scf_instance_get_pg(inst, *p, pg); 14784 else 14785 ret = scf_service_get_pg(cur_svc, *p, pg); 14786 14787 if (ret == 0) { 14788 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14789 char *buf = safe_malloc(bufsz); 14790 14791 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14792 free(buf); 14793 continue; 14794 } 14795 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14796 free(buf); 14797 continue; 14798 } 14799 14800 free(buf); 14801 *in_instance = (inst != NULL); 14802 scf_pg_destroy(pg); 14803 return (*p); 14804 } 14805 14806 if (scf_error() == SCF_ERROR_NOT_FOUND) 14807 continue; 14808 14809 scfdie(); 14810 } 14811 14812 if (inst != NULL) { 14813 inst = NULL; 14814 goto again; 14815 } 14816 14817 scf_pg_destroy(pg); 14818 return (NULL); 14819 } 14820 14821 static int 14822 addpg(const char *name, const char *type) 14823 { 14824 scf_propertygroup_t *pg; 14825 int ret; 14826 14827 pg = scf_pg_create(g_hndl); 14828 if (pg == NULL) 14829 scfdie(); 14830 14831 if (cur_inst != NULL) 14832 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14833 else 14834 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14835 14836 if (ret != 0) { 14837 switch (scf_error()) { 14838 case SCF_ERROR_EXISTS: 14839 ret = 0; 14840 break; 14841 14842 case SCF_ERROR_PERMISSION_DENIED: 14843 semerr(emsg_permission_denied); 14844 break; 14845 14846 default: 14847 scfdie(); 14848 } 14849 } 14850 14851 scf_pg_destroy(pg); 14852 return (ret); 14853 } 14854 14855 int 14856 lscf_setenv(uu_list_t *args, int isunset) 14857 { 14858 int ret = 0; 14859 size_t i; 14860 int argc; 14861 char **argv = NULL; 14862 string_list_t *slp; 14863 char *pattern; 14864 char *prop; 14865 int do_service = 0; 14866 int do_instance = 0; 14867 const char *method = NULL; 14868 const char *name = NULL; 14869 const char *value = NULL; 14870 scf_instance_t *saved_cur_inst = cur_inst; 14871 14872 lscf_prep_hndl(); 14873 14874 argc = uu_list_numnodes(args); 14875 if (argc < 1) 14876 goto usage; 14877 14878 argv = calloc(argc + 1, sizeof (char *)); 14879 if (argv == NULL) 14880 uu_die(gettext("Out of memory.\n")); 14881 14882 for (slp = uu_list_first(args), i = 0; 14883 slp != NULL; 14884 slp = uu_list_next(args, slp), ++i) 14885 argv[i] = slp->str; 14886 14887 argv[i] = NULL; 14888 14889 opterr = 0; 14890 optind = 0; 14891 for (;;) { 14892 ret = getopt(argc, argv, "sim:"); 14893 if (ret == -1) 14894 break; 14895 14896 switch (ret) { 14897 case 's': 14898 do_service = 1; 14899 cur_inst = NULL; 14900 break; 14901 14902 case 'i': 14903 do_instance = 1; 14904 break; 14905 14906 case 'm': 14907 method = optarg; 14908 break; 14909 14910 case '?': 14911 goto usage; 14912 14913 default: 14914 bad_error("getopt", ret); 14915 } 14916 } 14917 14918 argc -= optind; 14919 if ((do_service && do_instance) || 14920 (isunset && argc != 1) || 14921 (!isunset && argc != 2)) 14922 goto usage; 14923 14924 name = argv[optind]; 14925 if (!isunset) 14926 value = argv[optind + 1]; 14927 14928 if (cur_snap != NULL) { 14929 semerr(emsg_cant_modify_snapshots); 14930 ret = -1; 14931 goto out; 14932 } 14933 14934 if (cur_inst == NULL && cur_svc == NULL) { 14935 semerr(emsg_entity_not_selected); 14936 ret = -1; 14937 goto out; 14938 } 14939 14940 if (do_instance && cur_inst == NULL) { 14941 semerr(gettext("No instance is selected.\n")); 14942 ret = -1; 14943 goto out; 14944 } 14945 14946 if (do_service && cur_svc == NULL) { 14947 semerr(gettext("No service is selected.\n")); 14948 ret = -1; 14949 goto out; 14950 } 14951 14952 if (method == NULL) { 14953 if (do_instance || do_service) { 14954 method = "method_context"; 14955 if (!isunset) { 14956 ret = addpg("method_context", 14957 SCF_GROUP_FRAMEWORK); 14958 if (ret != 0) 14959 goto out; 14960 } 14961 } else { 14962 int in_instance; 14963 method = start_method_name(&in_instance); 14964 if (method == NULL) { 14965 semerr(gettext( 14966 "Couldn't find start method; please " 14967 "specify a method with '-m'.\n")); 14968 ret = -1; 14969 goto out; 14970 } 14971 if (!in_instance) 14972 cur_inst = NULL; 14973 } 14974 } else { 14975 scf_propertygroup_t *pg; 14976 size_t bufsz; 14977 char *buf; 14978 int ret; 14979 14980 if ((pg = scf_pg_create(g_hndl)) == NULL) 14981 scfdie(); 14982 14983 if (cur_inst != NULL) 14984 ret = scf_instance_get_pg(cur_inst, method, pg); 14985 else 14986 ret = scf_service_get_pg(cur_svc, method, pg); 14987 14988 if (ret != 0) { 14989 scf_pg_destroy(pg); 14990 switch (scf_error()) { 14991 case SCF_ERROR_NOT_FOUND: 14992 semerr(gettext("Couldn't find the method " 14993 "\"%s\".\n"), method); 14994 goto out; 14995 14996 case SCF_ERROR_INVALID_ARGUMENT: 14997 semerr(gettext("Invalid method name \"%s\".\n"), 14998 method); 14999 goto out; 15000 15001 default: 15002 scfdie(); 15003 } 15004 } 15005 15006 bufsz = strlen(SCF_GROUP_METHOD) + 1; 15007 buf = safe_malloc(bufsz); 15008 15009 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 15010 strcmp(buf, SCF_GROUP_METHOD) != 0) { 15011 semerr(gettext("Property group \"%s\" is not of type " 15012 "\"method\".\n"), method); 15013 ret = -1; 15014 free(buf); 15015 scf_pg_destroy(pg); 15016 goto out; 15017 } 15018 15019 free(buf); 15020 scf_pg_destroy(pg); 15021 } 15022 15023 prop = uu_msprintf("%s/environment", method); 15024 pattern = uu_msprintf("%s=*", name); 15025 15026 if (prop == NULL || pattern == NULL) 15027 uu_die(gettext("Out of memory.\n")); 15028 15029 ret = lscf_delpropvalue(prop, pattern, !isunset); 15030 15031 if (ret == 0 && !isunset) { 15032 uu_free(pattern); 15033 uu_free(prop); 15034 prop = uu_msprintf("%s/environment", method); 15035 pattern = uu_msprintf("%s=%s", name, value); 15036 if (prop == NULL || pattern == NULL) 15037 uu_die(gettext("Out of memory.\n")); 15038 ret = lscf_addpropvalue(prop, "astring:", pattern); 15039 } 15040 uu_free(pattern); 15041 uu_free(prop); 15042 15043 out: 15044 cur_inst = saved_cur_inst; 15045 15046 free(argv); 15047 return (ret); 15048 usage: 15049 ret = -2; 15050 goto out; 15051 } 15052 15053 /* 15054 * Snapshot commands 15055 */ 15056 15057 void 15058 lscf_listsnap() 15059 { 15060 scf_snapshot_t *snap; 15061 scf_iter_t *iter; 15062 char *nb; 15063 int r; 15064 15065 lscf_prep_hndl(); 15066 15067 if (cur_inst == NULL) { 15068 semerr(gettext("Instance not selected.\n")); 15069 return; 15070 } 15071 15072 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15073 (iter = scf_iter_create(g_hndl)) == NULL) 15074 scfdie(); 15075 15076 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 15077 scfdie(); 15078 15079 nb = safe_malloc(max_scf_name_len + 1); 15080 15081 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 15082 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 15083 scfdie(); 15084 15085 (void) puts(nb); 15086 } 15087 if (r < 0) 15088 scfdie(); 15089 15090 free(nb); 15091 scf_iter_destroy(iter); 15092 scf_snapshot_destroy(snap); 15093 } 15094 15095 void 15096 lscf_selectsnap(const char *name) 15097 { 15098 scf_snapshot_t *snap; 15099 scf_snaplevel_t *level; 15100 15101 lscf_prep_hndl(); 15102 15103 if (cur_inst == NULL) { 15104 semerr(gettext("Instance not selected.\n")); 15105 return; 15106 } 15107 15108 if (cur_snap != NULL) { 15109 if (name != NULL) { 15110 char *cur_snap_name; 15111 boolean_t nochange; 15112 15113 cur_snap_name = safe_malloc(max_scf_name_len + 1); 15114 15115 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 15116 max_scf_name_len + 1) < 0) 15117 scfdie(); 15118 15119 nochange = strcmp(name, cur_snap_name) == 0; 15120 15121 free(cur_snap_name); 15122 15123 if (nochange) 15124 return; 15125 } 15126 15127 unselect_cursnap(); 15128 } 15129 15130 if (name == NULL) 15131 return; 15132 15133 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15134 (level = scf_snaplevel_create(g_hndl)) == NULL) 15135 scfdie(); 15136 15137 if (scf_instance_get_snapshot(cur_inst, name, snap) != 15138 SCF_SUCCESS) { 15139 switch (scf_error()) { 15140 case SCF_ERROR_INVALID_ARGUMENT: 15141 semerr(gettext("Invalid name \"%s\".\n"), name); 15142 break; 15143 15144 case SCF_ERROR_NOT_FOUND: 15145 semerr(gettext("No such snapshot \"%s\".\n"), name); 15146 break; 15147 15148 default: 15149 scfdie(); 15150 } 15151 15152 scf_snaplevel_destroy(level); 15153 scf_snapshot_destroy(snap); 15154 return; 15155 } 15156 15157 /* Load the snaplevels into our list. */ 15158 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 15159 if (cur_levels == NULL) 15160 uu_die(gettext("Could not create list: %s\n"), 15161 uu_strerror(uu_error())); 15162 15163 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15164 if (scf_error() != SCF_ERROR_NOT_FOUND) 15165 scfdie(); 15166 15167 semerr(gettext("Snapshot has no snaplevels.\n")); 15168 15169 scf_snaplevel_destroy(level); 15170 scf_snapshot_destroy(snap); 15171 return; 15172 } 15173 15174 cur_snap = snap; 15175 15176 for (;;) { 15177 cur_elt = safe_malloc(sizeof (*cur_elt)); 15178 uu_list_node_init(cur_elt, &cur_elt->list_node, 15179 snaplevel_pool); 15180 cur_elt->sl = level; 15181 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 15182 uu_die(gettext("libuutil error: %s\n"), 15183 uu_strerror(uu_error())); 15184 15185 level = scf_snaplevel_create(g_hndl); 15186 if (level == NULL) 15187 scfdie(); 15188 15189 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 15190 level) != SCF_SUCCESS) { 15191 if (scf_error() != SCF_ERROR_NOT_FOUND) 15192 scfdie(); 15193 15194 scf_snaplevel_destroy(level); 15195 break; 15196 } 15197 } 15198 15199 cur_elt = uu_list_last(cur_levels); 15200 cur_level = cur_elt->sl; 15201 } 15202 15203 /* 15204 * Copies the properties & values in src to dst. Assumes src won't change. 15205 * Returns -1 if permission is denied, -2 if another transaction interrupts, 15206 * and 0 on success. 15207 * 15208 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 15209 * property, if it is copied and has type boolean. (See comment in 15210 * lscf_revert()). 15211 */ 15212 static int 15213 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 15214 uint8_t enabled) 15215 { 15216 scf_transaction_t *tx; 15217 scf_iter_t *iter, *viter; 15218 scf_property_t *prop; 15219 scf_value_t *v; 15220 char *nbuf; 15221 int r; 15222 15223 tx = scf_transaction_create(g_hndl); 15224 if (tx == NULL) 15225 scfdie(); 15226 15227 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 15228 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15229 scfdie(); 15230 15231 scf_transaction_destroy(tx); 15232 15233 return (-1); 15234 } 15235 15236 if ((iter = scf_iter_create(g_hndl)) == NULL || 15237 (prop = scf_property_create(g_hndl)) == NULL || 15238 (viter = scf_iter_create(g_hndl)) == NULL) 15239 scfdie(); 15240 15241 nbuf = safe_malloc(max_scf_name_len + 1); 15242 15243 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 15244 scfdie(); 15245 15246 for (;;) { 15247 scf_transaction_entry_t *e; 15248 scf_type_t ty; 15249 15250 r = scf_iter_next_property(iter, prop); 15251 if (r == -1) 15252 scfdie(); 15253 if (r == 0) 15254 break; 15255 15256 e = scf_entry_create(g_hndl); 15257 if (e == NULL) 15258 scfdie(); 15259 15260 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 15261 scfdie(); 15262 15263 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 15264 scfdie(); 15265 15266 if (scf_transaction_property_new(tx, e, nbuf, 15267 ty) != SCF_SUCCESS) 15268 scfdie(); 15269 15270 if ((enabled == 0 || enabled == 1) && 15271 strcmp(nbuf, scf_property_enabled) == 0 && 15272 ty == SCF_TYPE_BOOLEAN) { 15273 v = scf_value_create(g_hndl); 15274 if (v == NULL) 15275 scfdie(); 15276 15277 scf_value_set_boolean(v, enabled); 15278 15279 if (scf_entry_add_value(e, v) != 0) 15280 scfdie(); 15281 } else { 15282 if (scf_iter_property_values(viter, prop) != 0) 15283 scfdie(); 15284 15285 for (;;) { 15286 v = scf_value_create(g_hndl); 15287 if (v == NULL) 15288 scfdie(); 15289 15290 r = scf_iter_next_value(viter, v); 15291 if (r == -1) 15292 scfdie(); 15293 if (r == 0) { 15294 scf_value_destroy(v); 15295 break; 15296 } 15297 15298 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 15299 scfdie(); 15300 } 15301 } 15302 } 15303 15304 free(nbuf); 15305 scf_iter_destroy(viter); 15306 scf_property_destroy(prop); 15307 scf_iter_destroy(iter); 15308 15309 r = scf_transaction_commit(tx); 15310 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 15311 scfdie(); 15312 15313 scf_transaction_destroy_children(tx); 15314 scf_transaction_destroy(tx); 15315 15316 switch (r) { 15317 case 1: return (0); 15318 case 0: return (-2); 15319 case -1: return (-1); 15320 15321 default: 15322 abort(); 15323 } 15324 15325 /* NOTREACHED */ 15326 } 15327 15328 void 15329 lscf_revert(const char *snapname) 15330 { 15331 scf_snapshot_t *snap, *prev; 15332 scf_snaplevel_t *level, *nlevel; 15333 scf_iter_t *iter; 15334 scf_propertygroup_t *pg, *npg; 15335 scf_property_t *prop; 15336 scf_value_t *val; 15337 char *nbuf, *tbuf; 15338 uint8_t enabled; 15339 15340 lscf_prep_hndl(); 15341 15342 if (cur_inst == NULL) { 15343 semerr(gettext("Instance not selected.\n")); 15344 return; 15345 } 15346 15347 if (snapname != NULL) { 15348 snap = scf_snapshot_create(g_hndl); 15349 if (snap == NULL) 15350 scfdie(); 15351 15352 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 15353 SCF_SUCCESS) { 15354 switch (scf_error()) { 15355 case SCF_ERROR_INVALID_ARGUMENT: 15356 semerr(gettext("Invalid snapshot name " 15357 "\"%s\".\n"), snapname); 15358 break; 15359 15360 case SCF_ERROR_NOT_FOUND: 15361 semerr(gettext("No such snapshot.\n")); 15362 break; 15363 15364 default: 15365 scfdie(); 15366 } 15367 15368 scf_snapshot_destroy(snap); 15369 return; 15370 } 15371 } else { 15372 if (cur_snap != NULL) { 15373 snap = cur_snap; 15374 } else { 15375 semerr(gettext("No snapshot selected.\n")); 15376 return; 15377 } 15378 } 15379 15380 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 15381 (level = scf_snaplevel_create(g_hndl)) == NULL || 15382 (iter = scf_iter_create(g_hndl)) == NULL || 15383 (pg = scf_pg_create(g_hndl)) == NULL || 15384 (npg = scf_pg_create(g_hndl)) == NULL || 15385 (prop = scf_property_create(g_hndl)) == NULL || 15386 (val = scf_value_create(g_hndl)) == NULL) 15387 scfdie(); 15388 15389 nbuf = safe_malloc(max_scf_name_len + 1); 15390 tbuf = safe_malloc(max_scf_pg_type_len + 1); 15391 15392 /* Take the "previous" snapshot before we blow away the properties. */ 15393 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 15394 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 15395 scfdie(); 15396 } else { 15397 if (scf_error() != SCF_ERROR_NOT_FOUND) 15398 scfdie(); 15399 15400 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 15401 scfdie(); 15402 } 15403 15404 /* Save general/enabled, since we're probably going to replace it. */ 15405 enabled = 2; 15406 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 15407 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 15408 scf_property_get_value(prop, val) == 0) 15409 (void) scf_value_get_boolean(val, &enabled); 15410 15411 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15412 if (scf_error() != SCF_ERROR_NOT_FOUND) 15413 scfdie(); 15414 15415 goto out; 15416 } 15417 15418 for (;;) { 15419 boolean_t isinst; 15420 uint32_t flags; 15421 int r; 15422 15423 /* Clear the properties from the corresponding entity. */ 15424 isinst = snaplevel_is_instance(level); 15425 15426 if (!isinst) 15427 r = scf_iter_service_pgs(iter, cur_svc); 15428 else 15429 r = scf_iter_instance_pgs(iter, cur_inst); 15430 if (r != SCF_SUCCESS) 15431 scfdie(); 15432 15433 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15434 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15435 scfdie(); 15436 15437 /* Skip nonpersistent pgs. */ 15438 if (flags & SCF_PG_FLAG_NONPERSISTENT) 15439 continue; 15440 15441 if (scf_pg_delete(pg) != SCF_SUCCESS) { 15442 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15443 scfdie(); 15444 15445 semerr(emsg_permission_denied); 15446 goto out; 15447 } 15448 } 15449 if (r == -1) 15450 scfdie(); 15451 15452 /* Copy the properties to the corresponding entity. */ 15453 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 15454 scfdie(); 15455 15456 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15457 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 15458 scfdie(); 15459 15460 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 15461 0) 15462 scfdie(); 15463 15464 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15465 scfdie(); 15466 15467 if (!isinst) 15468 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 15469 flags, npg); 15470 else 15471 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 15472 flags, npg); 15473 if (r != SCF_SUCCESS) { 15474 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15475 scfdie(); 15476 15477 semerr(emsg_permission_denied); 15478 goto out; 15479 } 15480 15481 if ((enabled == 0 || enabled == 1) && 15482 strcmp(nbuf, scf_pg_general) == 0) 15483 r = pg_copy(pg, npg, enabled); 15484 else 15485 r = pg_copy(pg, npg, 2); 15486 15487 switch (r) { 15488 case 0: 15489 break; 15490 15491 case -1: 15492 semerr(emsg_permission_denied); 15493 goto out; 15494 15495 case -2: 15496 semerr(gettext( 15497 "Interrupted by another change.\n")); 15498 goto out; 15499 15500 default: 15501 abort(); 15502 } 15503 } 15504 if (r == -1) 15505 scfdie(); 15506 15507 /* Get next level. */ 15508 nlevel = scf_snaplevel_create(g_hndl); 15509 if (nlevel == NULL) 15510 scfdie(); 15511 15512 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 15513 SCF_SUCCESS) { 15514 if (scf_error() != SCF_ERROR_NOT_FOUND) 15515 scfdie(); 15516 15517 scf_snaplevel_destroy(nlevel); 15518 break; 15519 } 15520 15521 scf_snaplevel_destroy(level); 15522 level = nlevel; 15523 } 15524 15525 if (snapname == NULL) { 15526 lscf_selectsnap(NULL); 15527 snap = NULL; /* cur_snap has been destroyed */ 15528 } 15529 15530 out: 15531 free(tbuf); 15532 free(nbuf); 15533 scf_value_destroy(val); 15534 scf_property_destroy(prop); 15535 scf_pg_destroy(npg); 15536 scf_pg_destroy(pg); 15537 scf_iter_destroy(iter); 15538 scf_snaplevel_destroy(level); 15539 scf_snapshot_destroy(prev); 15540 if (snap != cur_snap) 15541 scf_snapshot_destroy(snap); 15542 } 15543 15544 void 15545 lscf_refresh(void) 15546 { 15547 ssize_t fmrilen; 15548 size_t bufsz; 15549 char *fmribuf; 15550 int r; 15551 15552 lscf_prep_hndl(); 15553 15554 if (cur_inst == NULL) { 15555 semerr(gettext("Instance not selected.\n")); 15556 return; 15557 } 15558 15559 bufsz = max_scf_fmri_len + 1; 15560 fmribuf = safe_malloc(bufsz); 15561 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15562 if (fmrilen < 0) { 15563 free(fmribuf); 15564 if (scf_error() != SCF_ERROR_DELETED) 15565 scfdie(); 15566 scf_instance_destroy(cur_inst); 15567 cur_inst = NULL; 15568 warn(emsg_deleted); 15569 return; 15570 } 15571 assert(fmrilen < bufsz); 15572 15573 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15574 switch (r) { 15575 case 0: 15576 break; 15577 15578 case ECONNABORTED: 15579 warn(gettext("Could not refresh %s " 15580 "(repository connection broken).\n"), fmribuf); 15581 break; 15582 15583 case ECANCELED: 15584 warn(emsg_deleted); 15585 break; 15586 15587 case EPERM: 15588 warn(gettext("Could not refresh %s " 15589 "(permission denied).\n"), fmribuf); 15590 break; 15591 15592 case ENOSPC: 15593 warn(gettext("Could not refresh %s " 15594 "(repository server out of resources).\n"), 15595 fmribuf); 15596 break; 15597 15598 case EACCES: 15599 default: 15600 bad_error("refresh_entity", scf_error()); 15601 } 15602 15603 free(fmribuf); 15604 } 15605 15606 /* 15607 * describe [-v] [-t] [pg/prop] 15608 */ 15609 int 15610 lscf_describe(uu_list_t *args, int hasargs) 15611 { 15612 int ret = 0; 15613 size_t i; 15614 int argc; 15615 char **argv = NULL; 15616 string_list_t *slp; 15617 int do_verbose = 0; 15618 int do_templates = 0; 15619 char *pattern = NULL; 15620 15621 lscf_prep_hndl(); 15622 15623 if (hasargs != 0) { 15624 argc = uu_list_numnodes(args); 15625 if (argc < 1) 15626 goto usage; 15627 15628 argv = calloc(argc + 1, sizeof (char *)); 15629 if (argv == NULL) 15630 uu_die(gettext("Out of memory.\n")); 15631 15632 for (slp = uu_list_first(args), i = 0; 15633 slp != NULL; 15634 slp = uu_list_next(args, slp), ++i) 15635 argv[i] = slp->str; 15636 15637 argv[i] = NULL; 15638 15639 /* 15640 * We start optind = 0 because our list of arguments 15641 * starts at argv[0] 15642 */ 15643 optind = 0; 15644 opterr = 0; 15645 for (;;) { 15646 ret = getopt(argc, argv, "vt"); 15647 if (ret == -1) 15648 break; 15649 15650 switch (ret) { 15651 case 'v': 15652 do_verbose = 1; 15653 break; 15654 15655 case 't': 15656 do_templates = 1; 15657 break; 15658 15659 case '?': 15660 goto usage; 15661 15662 default: 15663 bad_error("getopt", ret); 15664 } 15665 } 15666 15667 pattern = argv[optind]; 15668 } 15669 15670 if (cur_inst == NULL && cur_svc == NULL) { 15671 semerr(emsg_entity_not_selected); 15672 ret = -1; 15673 goto out; 15674 } 15675 15676 /* 15677 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15678 * output if their last parameter is set to 2. Less information is 15679 * produced if the parameter is set to 1. 15680 */ 15681 if (pattern == NULL) { 15682 if (do_verbose == 1) 15683 list_entity_tmpl(2); 15684 else 15685 list_entity_tmpl(1); 15686 } 15687 15688 if (do_templates == 0) { 15689 if (do_verbose == 1) 15690 listprop(pattern, 0, 2); 15691 else 15692 listprop(pattern, 0, 1); 15693 } else { 15694 if (do_verbose == 1) 15695 listtmpl(pattern, 2); 15696 else 15697 listtmpl(pattern, 1); 15698 } 15699 15700 ret = 0; 15701 out: 15702 if (argv != NULL) 15703 free(argv); 15704 return (ret); 15705 usage: 15706 ret = -2; 15707 goto out; 15708 } 15709 15710 #define PARAM_ACTIVE ((const char *) "active") 15711 #define PARAM_INACTIVE ((const char *) "inactive") 15712 #define PARAM_SMTP_TO ((const char *) "to") 15713 15714 /* 15715 * tokenize() 15716 * Breaks down the string according to the tokens passed. 15717 * Caller is responsible for freeing array of pointers returned. 15718 * Returns NULL on failure 15719 */ 15720 char ** 15721 tokenize(char *str, const char *sep) 15722 { 15723 char *token, *lasts; 15724 char **buf; 15725 int n = 0; /* number of elements */ 15726 int size = 8; /* size of the array (initial) */ 15727 15728 buf = safe_malloc(size * sizeof (char *)); 15729 15730 for (token = strtok_r(str, sep, &lasts); token != NULL; 15731 token = strtok_r(NULL, sep, &lasts), ++n) { 15732 if (n + 1 >= size) { 15733 size *= 2; 15734 if ((buf = realloc(buf, size * sizeof (char *))) == 15735 NULL) { 15736 uu_die(gettext("Out of memory")); 15737 } 15738 } 15739 buf[n] = token; 15740 } 15741 /* NULL terminate the pointer array */ 15742 buf[n] = NULL; 15743 15744 return (buf); 15745 } 15746 15747 int32_t 15748 check_tokens(char **p) 15749 { 15750 int32_t smf = 0; 15751 int32_t fma = 0; 15752 15753 while (*p) { 15754 int32_t t = string_to_tset(*p); 15755 15756 if (t == 0) { 15757 if (is_fma_token(*p) == 0) 15758 return (INVALID_TOKENS); 15759 fma = 1; /* this token is an fma event */ 15760 } else { 15761 smf |= t; 15762 } 15763 15764 if (smf != 0 && fma == 1) 15765 return (MIXED_TOKENS); 15766 ++p; 15767 } 15768 15769 if (smf > 0) 15770 return (smf); 15771 else if (fma == 1) 15772 return (FMA_TOKENS); 15773 15774 return (INVALID_TOKENS); 15775 } 15776 15777 static int 15778 get_selection_str(char *fmri, size_t sz) 15779 { 15780 if (g_hndl == NULL) { 15781 semerr(emsg_entity_not_selected); 15782 return (-1); 15783 } else if (cur_level != NULL) { 15784 semerr(emsg_invalid_for_snapshot); 15785 return (-1); 15786 } else { 15787 lscf_get_selection_str(fmri, sz); 15788 } 15789 15790 return (0); 15791 } 15792 15793 void 15794 lscf_delnotify(const char *set, int global) 15795 { 15796 char *str = strdup(set); 15797 char **pgs; 15798 char **p; 15799 int32_t tset; 15800 char *fmri = NULL; 15801 15802 if (str == NULL) 15803 uu_die(gettext("Out of memory.\n")); 15804 15805 pgs = tokenize(str, ","); 15806 15807 if ((tset = check_tokens(pgs)) > 0) { 15808 size_t sz = max_scf_fmri_len + 1; 15809 15810 fmri = safe_malloc(sz); 15811 if (global) { 15812 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15813 } else if (get_selection_str(fmri, sz) != 0) { 15814 goto out; 15815 } 15816 15817 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri, 15818 tset) != SCF_SUCCESS) { 15819 uu_warn(gettext("Failed smf_notify_del_params: %s\n"), 15820 scf_strerror(scf_error())); 15821 } 15822 } else if (tset == FMA_TOKENS) { 15823 if (global) { 15824 semerr(gettext("Can't use option '-g' with FMA event " 15825 "definitions\n")); 15826 goto out; 15827 } 15828 15829 for (p = pgs; *p; ++p) { 15830 if (smf_notify_del_params(de_tag(*p), NULL, 0) != 15831 SCF_SUCCESS) { 15832 uu_warn(gettext("Failed for \"%s\": %s\n"), *p, 15833 scf_strerror(scf_error())); 15834 goto out; 15835 } 15836 } 15837 } else if (tset == MIXED_TOKENS) { 15838 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15839 goto out; 15840 } else { 15841 uu_die(gettext("Invalid input.\n")); 15842 } 15843 15844 out: 15845 free(fmri); 15846 free(pgs); 15847 free(str); 15848 } 15849 15850 void 15851 lscf_listnotify(const char *set, int global) 15852 { 15853 char *str = safe_strdup(set); 15854 char **pgs; 15855 char **p; 15856 int32_t tset; 15857 nvlist_t *nvl; 15858 char *fmri = NULL; 15859 15860 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 15861 uu_die(gettext("Out of memory.\n")); 15862 15863 pgs = tokenize(str, ","); 15864 15865 if ((tset = check_tokens(pgs)) > 0) { 15866 size_t sz = max_scf_fmri_len + 1; 15867 15868 fmri = safe_malloc(sz); 15869 if (global) { 15870 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15871 } else if (get_selection_str(fmri, sz) != 0) { 15872 goto out; 15873 } 15874 15875 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) != 15876 SCF_SUCCESS) { 15877 if (scf_error() != SCF_ERROR_NOT_FOUND && 15878 scf_error() != SCF_ERROR_DELETED) 15879 uu_warn(gettext( 15880 "Failed listnotify: %s\n"), 15881 scf_strerror(scf_error())); 15882 goto out; 15883 } 15884 15885 listnotify_print(nvl, NULL); 15886 } else if (tset == FMA_TOKENS) { 15887 if (global) { 15888 semerr(gettext("Can't use option '-g' with FMA event " 15889 "definitions\n")); 15890 goto out; 15891 } 15892 15893 for (p = pgs; *p; ++p) { 15894 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) != 15895 SCF_SUCCESS) { 15896 /* 15897 * if the preferences have just been deleted 15898 * or does not exist, just skip. 15899 */ 15900 if (scf_error() == SCF_ERROR_NOT_FOUND || 15901 scf_error() == SCF_ERROR_DELETED) 15902 continue; 15903 uu_warn(gettext( 15904 "Failed listnotify: %s\n"), 15905 scf_strerror(scf_error())); 15906 goto out; 15907 } 15908 listnotify_print(nvl, re_tag(*p)); 15909 } 15910 } else if (tset == MIXED_TOKENS) { 15911 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15912 goto out; 15913 } else { 15914 semerr(gettext("Invalid input.\n")); 15915 } 15916 15917 out: 15918 nvlist_free(nvl); 15919 free(fmri); 15920 free(pgs); 15921 free(str); 15922 } 15923 15924 static char * 15925 strip_quotes_and_blanks(char *s) 15926 { 15927 char *start = s; 15928 char *end = strrchr(s, '\"'); 15929 15930 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') { 15931 start = s + 1; 15932 while (isblank(*start)) 15933 start++; 15934 while (isblank(*(end - 1)) && end > start) { 15935 end--; 15936 } 15937 *end = '\0'; 15938 } 15939 15940 return (start); 15941 } 15942 15943 static int 15944 set_active(nvlist_t *mech, const char *hier_part) 15945 { 15946 boolean_t b; 15947 15948 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) { 15949 b = B_TRUE; 15950 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) { 15951 b = B_FALSE; 15952 } else { 15953 return (-1); 15954 } 15955 15956 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0) 15957 uu_die(gettext("Out of memory.\n")); 15958 15959 return (0); 15960 } 15961 15962 static int 15963 add_snmp_params(nvlist_t *mech, char *hier_part) 15964 { 15965 return (set_active(mech, hier_part)); 15966 } 15967 15968 static int 15969 add_syslog_params(nvlist_t *mech, char *hier_part) 15970 { 15971 return (set_active(mech, hier_part)); 15972 } 15973 15974 /* 15975 * add_mailto_paramas() 15976 * parse the hier_part of mailto URI 15977 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]] 15978 * or mailto:{[active]|inactive} 15979 */ 15980 static int 15981 add_mailto_params(nvlist_t *mech, char *hier_part) 15982 { 15983 const char *tok = "?&"; 15984 char *p; 15985 char *lasts; 15986 char *param; 15987 char *val; 15988 15989 /* 15990 * If the notification parametes are in the form of 15991 * 15992 * malito:{[active]|inactive} 15993 * 15994 * we set the property accordingly and return. 15995 * Otherwise, we make the notification type active and 15996 * process the hier_part. 15997 */ 15998 if (set_active(mech, hier_part) == 0) 15999 return (0); 16000 else if (set_active(mech, PARAM_ACTIVE) != 0) 16001 return (-1); 16002 16003 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) { 16004 /* 16005 * sanity check: we only get here if hier_part = "", but 16006 * that's handled by set_active 16007 */ 16008 uu_die("strtok_r"); 16009 } 16010 16011 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0) 16012 uu_die(gettext("Out of memory.\n")); 16013 16014 while ((p = strtok_r(NULL, tok, &lasts)) != NULL) 16015 if ((param = strtok_r(p, "=", &val)) != NULL) 16016 if (nvlist_add_string(mech, param, val) != 0) 16017 uu_die(gettext("Out of memory.\n")); 16018 16019 return (0); 16020 } 16021 16022 static int 16023 uri_split(char *uri, char **scheme, char **hier_part) 16024 { 16025 int r = -1; 16026 16027 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL || 16028 *hier_part == NULL) { 16029 semerr(gettext("'%s' is not an URI\n"), uri); 16030 return (r); 16031 } 16032 16033 if ((r = check_uri_scheme(*scheme)) < 0) { 16034 semerr(gettext("Unkown URI scheme: %s\n"), *scheme); 16035 return (r); 16036 } 16037 16038 return (r); 16039 } 16040 16041 static int 16042 process_uri(nvlist_t *params, char *uri) 16043 { 16044 char *scheme; 16045 char *hier_part; 16046 nvlist_t *mech; 16047 int index; 16048 int r; 16049 16050 if ((index = uri_split(uri, &scheme, &hier_part)) < 0) 16051 return (-1); 16052 16053 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0) 16054 uu_die(gettext("Out of memory.\n")); 16055 16056 switch (index) { 16057 case 0: 16058 /* error messages displayed by called function */ 16059 r = add_mailto_params(mech, hier_part); 16060 break; 16061 16062 case 1: 16063 if ((r = add_snmp_params(mech, hier_part)) != 0) 16064 semerr(gettext("Not valid parameters: '%s'\n"), 16065 hier_part); 16066 break; 16067 16068 case 2: 16069 if ((r = add_syslog_params(mech, hier_part)) != 0) 16070 semerr(gettext("Not valid parameters: '%s'\n"), 16071 hier_part); 16072 break; 16073 16074 default: 16075 r = -1; 16076 } 16077 16078 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol, 16079 mech) != 0) 16080 uu_die(gettext("Out of memory.\n")); 16081 16082 nvlist_free(mech); 16083 return (r); 16084 } 16085 16086 static int 16087 set_params(nvlist_t *params, char **p) 16088 { 16089 char *uri; 16090 16091 if (p == NULL) 16092 /* sanity check */ 16093 uu_die("set_params"); 16094 16095 while (*p) { 16096 uri = strip_quotes_and_blanks(*p); 16097 if (process_uri(params, uri) != 0) 16098 return (-1); 16099 16100 ++p; 16101 } 16102 16103 return (0); 16104 } 16105 16106 static int 16107 setnotify(const char *e, char **p, int global) 16108 { 16109 char *str = safe_strdup(e); 16110 char **events; 16111 int32_t tset; 16112 int r = -1; 16113 nvlist_t *nvl, *params; 16114 char *fmri = NULL; 16115 16116 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 16117 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 || 16118 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 16119 SCF_NOTIFY_PARAMS_VERSION) != 0) 16120 uu_die(gettext("Out of memory.\n")); 16121 16122 events = tokenize(str, ","); 16123 16124 if ((tset = check_tokens(events)) > 0) { 16125 /* SMF state transitions parameters */ 16126 size_t sz = max_scf_fmri_len + 1; 16127 16128 fmri = safe_malloc(sz); 16129 if (global) { 16130 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 16131 } else if (get_selection_str(fmri, sz) != 0) { 16132 goto out; 16133 } 16134 16135 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 || 16136 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0) 16137 uu_die(gettext("Out of memory.\n")); 16138 16139 if ((r = set_params(params, p)) == 0) { 16140 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, 16141 params) != 0) 16142 uu_die(gettext("Out of memory.\n")); 16143 16144 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS, 16145 nvl) != SCF_SUCCESS) { 16146 r = -1; 16147 uu_warn(gettext( 16148 "Failed smf_notify_set_params(3SCF): %s\n"), 16149 scf_strerror(scf_error())); 16150 } 16151 } 16152 } else if (tset == FMA_TOKENS) { 16153 /* FMA event parameters */ 16154 if (global) { 16155 semerr(gettext("Can't use option '-g' with FMA event " 16156 "definitions\n")); 16157 goto out; 16158 } 16159 16160 if ((r = set_params(params, p)) != 0) 16161 goto out; 16162 16163 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0) 16164 uu_die(gettext("Out of memory.\n")); 16165 16166 while (*events) { 16167 if (smf_notify_set_params(de_tag(*events), nvl) != 16168 SCF_SUCCESS) 16169 uu_warn(gettext( 16170 "Failed smf_notify_set_params(3SCF) for " 16171 "event %s: %s\n"), *events, 16172 scf_strerror(scf_error())); 16173 events++; 16174 } 16175 } else if (tset == MIXED_TOKENS) { 16176 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 16177 } else { 16178 /* Sanity check */ 16179 uu_die(gettext("Invalid input.\n")); 16180 } 16181 16182 out: 16183 nvlist_free(nvl); 16184 nvlist_free(params); 16185 free(fmri); 16186 free(str); 16187 16188 return (r); 16189 } 16190 16191 int 16192 lscf_setnotify(uu_list_t *args) 16193 { 16194 int argc; 16195 char **argv = NULL; 16196 string_list_t *slp; 16197 int global; 16198 char *events; 16199 char **p; 16200 int i; 16201 int ret; 16202 16203 if ((argc = uu_list_numnodes(args)) < 2) 16204 goto usage; 16205 16206 argv = calloc(argc + 1, sizeof (char *)); 16207 if (argv == NULL) 16208 uu_die(gettext("Out of memory.\n")); 16209 16210 for (slp = uu_list_first(args), i = 0; 16211 slp != NULL; 16212 slp = uu_list_next(args, slp), ++i) 16213 argv[i] = slp->str; 16214 16215 argv[i] = NULL; 16216 16217 if (strcmp(argv[0], "-g") == 0) { 16218 global = 1; 16219 events = argv[1]; 16220 p = argv + 2; 16221 } else { 16222 global = 0; 16223 events = argv[0]; 16224 p = argv + 1; 16225 } 16226 16227 ret = setnotify(events, p, global); 16228 16229 out: 16230 free(argv); 16231 return (ret); 16232 16233 usage: 16234 ret = -2; 16235 goto out; 16236 } 16237 16238 /* 16239 * Creates a list of instance name strings associated with a service. If 16240 * wohandcrafted flag is set, get only instances that have a last-import 16241 * snapshot, instances that were imported via svccfg. 16242 */ 16243 static uu_list_t * 16244 create_instance_list(scf_service_t *svc, int wohandcrafted) 16245 { 16246 scf_snapshot_t *snap = NULL; 16247 scf_instance_t *inst; 16248 scf_iter_t *inst_iter; 16249 uu_list_t *instances; 16250 char *instname; 16251 int r; 16252 16253 inst_iter = scf_iter_create(g_hndl); 16254 inst = scf_instance_create(g_hndl); 16255 if (inst_iter == NULL || inst == NULL) { 16256 uu_warn(gettext("Could not create instance or iterator\n")); 16257 scfdie(); 16258 } 16259 16260 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 16261 return (instances); 16262 16263 if (scf_iter_service_instances(inst_iter, svc) != 0) { 16264 switch (scf_error()) { 16265 case SCF_ERROR_CONNECTION_BROKEN: 16266 case SCF_ERROR_DELETED: 16267 uu_list_destroy(instances); 16268 instances = NULL; 16269 goto out; 16270 16271 case SCF_ERROR_HANDLE_MISMATCH: 16272 case SCF_ERROR_NOT_BOUND: 16273 case SCF_ERROR_NOT_SET: 16274 default: 16275 bad_error("scf_iter_service_instances", scf_error()); 16276 } 16277 } 16278 16279 instname = safe_malloc(max_scf_name_len + 1); 16280 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 16281 if (r == -1) { 16282 (void) uu_warn(gettext("Unable to iterate through " 16283 "instances to create instance list : %s\n"), 16284 scf_strerror(scf_error())); 16285 16286 uu_list_destroy(instances); 16287 instances = NULL; 16288 goto out; 16289 } 16290 16291 /* 16292 * If the instance does not have a last-import snapshot 16293 * then do not add it to the list as it is a hand-crafted 16294 * instance that should not be managed. 16295 */ 16296 if (wohandcrafted) { 16297 if (snap == NULL && 16298 (snap = scf_snapshot_create(g_hndl)) == NULL) { 16299 uu_warn(gettext("Unable to create snapshot " 16300 "entity\n")); 16301 scfdie(); 16302 } 16303 16304 if (scf_instance_get_snapshot(inst, 16305 snap_lastimport, snap) != 0) { 16306 switch (scf_error()) { 16307 case SCF_ERROR_NOT_FOUND : 16308 case SCF_ERROR_DELETED: 16309 continue; 16310 16311 case SCF_ERROR_CONNECTION_BROKEN: 16312 uu_list_destroy(instances); 16313 instances = NULL; 16314 goto out; 16315 16316 case SCF_ERROR_HANDLE_MISMATCH: 16317 case SCF_ERROR_NOT_BOUND: 16318 case SCF_ERROR_NOT_SET: 16319 default: 16320 bad_error("scf_iter_service_instances", 16321 scf_error()); 16322 } 16323 } 16324 } 16325 16326 if (scf_instance_get_name(inst, instname, 16327 max_scf_name_len + 1) < 0) { 16328 switch (scf_error()) { 16329 case SCF_ERROR_NOT_FOUND : 16330 continue; 16331 16332 case SCF_ERROR_CONNECTION_BROKEN: 16333 case SCF_ERROR_DELETED: 16334 uu_list_destroy(instances); 16335 instances = NULL; 16336 goto out; 16337 16338 case SCF_ERROR_HANDLE_MISMATCH: 16339 case SCF_ERROR_NOT_BOUND: 16340 case SCF_ERROR_NOT_SET: 16341 default: 16342 bad_error("scf_iter_service_instances", 16343 scf_error()); 16344 } 16345 } 16346 16347 add_string(instances, instname); 16348 } 16349 16350 out: 16351 if (snap) 16352 scf_snapshot_destroy(snap); 16353 16354 scf_instance_destroy(inst); 16355 scf_iter_destroy(inst_iter); 16356 free(instname); 16357 return (instances); 16358 } 16359 16360 /* 16361 * disable an instance but wait for the instance to 16362 * move out of the running state. 16363 * 16364 * Returns 0 : if the instance did not disable 16365 * Returns non-zero : if the instance disabled. 16366 * 16367 */ 16368 static int 16369 disable_instance(scf_instance_t *instance) 16370 { 16371 char *fmribuf; 16372 int enabled = 10000; 16373 16374 if (inst_is_running(instance)) { 16375 fmribuf = safe_malloc(max_scf_name_len + 1); 16376 if (scf_instance_to_fmri(instance, fmribuf, 16377 max_scf_name_len + 1) < 0) { 16378 free(fmribuf); 16379 return (0); 16380 } 16381 16382 /* 16383 * If the instance cannot be disabled then return 16384 * failure to disable and let the caller decide 16385 * if that is of importance. 16386 */ 16387 if (smf_disable_instance(fmribuf, 0) != 0) { 16388 free(fmribuf); 16389 return (0); 16390 } 16391 16392 while (enabled) { 16393 if (!inst_is_running(instance)) 16394 break; 16395 16396 (void) poll(NULL, 0, 5); 16397 enabled = enabled - 5; 16398 } 16399 16400 free(fmribuf); 16401 } 16402 16403 return (enabled); 16404 } 16405 16406 /* 16407 * Function to compare two service_manifest structures. 16408 */ 16409 /* ARGSUSED2 */ 16410 static int 16411 service_manifest_compare(const void *left, const void *right, void *unused) 16412 { 16413 service_manifest_t *l = (service_manifest_t *)left; 16414 service_manifest_t *r = (service_manifest_t *)right; 16415 int rc; 16416 16417 rc = strcmp(l->servicename, r->servicename); 16418 16419 return (rc); 16420 } 16421 16422 /* 16423 * Look for the provided service in the service to manifest 16424 * tree. If the service exists, and a manifest was provided 16425 * then add the manifest to that service. If the service 16426 * does not exist, then add the service and manifest to the 16427 * list. 16428 * 16429 * If the manifest is NULL, return the element if found. If 16430 * the service is not found return NULL. 16431 */ 16432 service_manifest_t * 16433 find_add_svc_mfst(const char *svnbuf, const char *mfst) 16434 { 16435 service_manifest_t elem; 16436 service_manifest_t *fnelem; 16437 uu_avl_index_t marker; 16438 16439 elem.servicename = svnbuf; 16440 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 16441 16442 if (mfst) { 16443 if (fnelem) { 16444 add_string(fnelem->mfstlist, strdup(mfst)); 16445 } else { 16446 fnelem = safe_malloc(sizeof (*fnelem)); 16447 fnelem->servicename = safe_strdup(svnbuf); 16448 if ((fnelem->mfstlist = 16449 uu_list_create(string_pool, NULL, 0)) == NULL) 16450 uu_die(gettext("Could not create property " 16451 "list: %s\n"), uu_strerror(uu_error())); 16452 16453 add_string(fnelem->mfstlist, safe_strdup(mfst)); 16454 16455 uu_avl_insert(service_manifest_tree, fnelem, marker); 16456 } 16457 } 16458 16459 return (fnelem); 16460 } 16461 16462 /* 16463 * Create the service to manifest avl tree. 16464 * 16465 * Walk each of the manifests currently installed in the supported 16466 * directories, /lib/svc/manifests and /var/svc/manifests. For 16467 * each of the manifests, inventory the services and add them to 16468 * the tree. 16469 * 16470 * Code that calls this function should make sure fileystem/minimal is online, 16471 * /var is available, since this function walks the /var/svc/manifest directory. 16472 */ 16473 static void 16474 create_manifest_tree(void) 16475 { 16476 manifest_info_t **entry; 16477 manifest_info_t **manifests; 16478 uu_list_walk_t *svcs; 16479 bundle_t *b; 16480 entity_t *mfsvc; 16481 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 16482 int c, status; 16483 16484 if (service_manifest_pool) 16485 return; 16486 16487 /* 16488 * Create the list pool for the service manifest list 16489 */ 16490 service_manifest_pool = uu_avl_pool_create("service_manifest", 16491 sizeof (service_manifest_t), 16492 offsetof(service_manifest_t, svcmfst_node), 16493 service_manifest_compare, UU_DEFAULT); 16494 if (service_manifest_pool == NULL) 16495 uu_die(gettext("service_manifest pool creation failed: %s\n"), 16496 uu_strerror(uu_error())); 16497 16498 /* 16499 * Create the list 16500 */ 16501 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 16502 UU_DEFAULT); 16503 if (service_manifest_tree == NULL) 16504 uu_die(gettext("service_manifest tree creation failed: %s\n"), 16505 uu_strerror(uu_error())); 16506 16507 /* 16508 * Walk the manifests adding the service(s) from each manifest. 16509 * 16510 * If a service already exists add the manifest to the manifest 16511 * list for that service. This covers the case of a service that 16512 * is supported by multiple manifest files. 16513 */ 16514 for (c = 0; dirs[c]; c++) { 16515 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT); 16516 if (status < 0) { 16517 uu_warn(gettext("file tree walk of %s encountered " 16518 "error %s\n"), dirs[c], strerror(errno)); 16519 16520 uu_avl_destroy(service_manifest_tree); 16521 service_manifest_tree = NULL; 16522 return; 16523 } 16524 16525 /* 16526 * If a manifest that was in the list is not found 16527 * then skip and go to the next manifest file. 16528 */ 16529 if (manifests != NULL) { 16530 for (entry = manifests; *entry != NULL; entry++) { 16531 b = internal_bundle_new(); 16532 if (lxml_get_bundle_file(b, (*entry)->mi_path, 16533 SVCCFG_OP_IMPORT) != 0) { 16534 internal_bundle_free(b); 16535 continue; 16536 } 16537 16538 svcs = uu_list_walk_start(b->sc_bundle_services, 16539 0); 16540 if (svcs == NULL) { 16541 internal_bundle_free(b); 16542 continue; 16543 } 16544 16545 while ((mfsvc = uu_list_walk_next(svcs)) != 16546 NULL) { 16547 /* Add manifest to service */ 16548 (void) find_add_svc_mfst(mfsvc->sc_name, 16549 (*entry)->mi_path); 16550 } 16551 16552 uu_list_walk_end(svcs); 16553 internal_bundle_free(b); 16554 } 16555 16556 free_manifest_array(manifests); 16557 } 16558 } 16559 } 16560 16561 /* 16562 * Check the manifest history file to see 16563 * if the service was ever installed from 16564 * one of the supported directories. 16565 * 16566 * Return Values : 16567 * -1 - if there's error reading manifest history file 16568 * 1 - if the service is not found 16569 * 0 - if the service is found 16570 */ 16571 static int 16572 check_mfst_history(const char *svcname) 16573 { 16574 struct stat st; 16575 caddr_t mfsthist_start; 16576 char *svnbuf; 16577 int fd; 16578 int r = 1; 16579 16580 fd = open(MFSTHISTFILE, O_RDONLY); 16581 if (fd == -1) { 16582 uu_warn(gettext("Unable to open the history file\n")); 16583 return (-1); 16584 } 16585 16586 if (fstat(fd, &st) == -1) { 16587 uu_warn(gettext("Unable to stat the history file\n")); 16588 return (-1); 16589 } 16590 16591 mfsthist_start = mmap(0, st.st_size, PROT_READ, 16592 MAP_PRIVATE, fd, 0); 16593 16594 (void) close(fd); 16595 if (mfsthist_start == MAP_FAILED || 16596 *(mfsthist_start + st.st_size) != '\0') { 16597 (void) munmap(mfsthist_start, st.st_size); 16598 return (-1); 16599 } 16600 16601 /* 16602 * The manifest history file is a space delimited list 16603 * of service and instance to manifest linkage. Adding 16604 * a space to the end of the service name so to get only 16605 * the service that is being searched for. 16606 */ 16607 svnbuf = uu_msprintf("%s ", svcname); 16608 if (svnbuf == NULL) 16609 uu_die(gettext("Out of memory")); 16610 16611 if (strstr(mfsthist_start, svnbuf) != NULL) 16612 r = 0; 16613 16614 (void) munmap(mfsthist_start, st.st_size); 16615 uu_free(svnbuf); 16616 return (r); 16617 } 16618 16619 /* 16620 * Take down each of the instances in the service 16621 * and remove them, then delete the service. 16622 */ 16623 static void 16624 teardown_service(scf_service_t *svc, const char *svnbuf) 16625 { 16626 scf_instance_t *instance; 16627 scf_iter_t *iter; 16628 int r; 16629 16630 safe_printf(gettext("Delete service %s as there are no " 16631 "supporting manifests\n"), svnbuf); 16632 16633 instance = scf_instance_create(g_hndl); 16634 iter = scf_iter_create(g_hndl); 16635 if (iter == NULL || instance == NULL) { 16636 uu_warn(gettext("Unable to create supporting entities to " 16637 "teardown the service\n")); 16638 uu_warn(gettext("scf error is : %s\n"), 16639 scf_strerror(scf_error())); 16640 scfdie(); 16641 } 16642 16643 if (scf_iter_service_instances(iter, svc) != 0) { 16644 switch (scf_error()) { 16645 case SCF_ERROR_CONNECTION_BROKEN: 16646 case SCF_ERROR_DELETED: 16647 goto out; 16648 16649 case SCF_ERROR_HANDLE_MISMATCH: 16650 case SCF_ERROR_NOT_BOUND: 16651 case SCF_ERROR_NOT_SET: 16652 default: 16653 bad_error("scf_iter_service_instances", 16654 scf_error()); 16655 } 16656 } 16657 16658 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 16659 if (r == -1) { 16660 uu_warn(gettext("Error - %s\n"), 16661 scf_strerror(scf_error())); 16662 goto out; 16663 } 16664 16665 (void) disable_instance(instance); 16666 } 16667 16668 /* 16669 * Delete the service... forcing the deletion in case 16670 * any of the instances did not disable. 16671 */ 16672 (void) lscf_service_delete(svc, 1); 16673 out: 16674 scf_instance_destroy(instance); 16675 scf_iter_destroy(iter); 16676 } 16677 16678 /* 16679 * Get the list of instances supported by the manifest 16680 * file. 16681 * 16682 * Return 0 if there are no instances. 16683 * 16684 * Return -1 if there are errors attempting to collect instances. 16685 * 16686 * Return the count of instances found if there are no errors. 16687 * 16688 */ 16689 static int 16690 check_instance_support(char *mfstfile, const char *svcname, 16691 uu_list_t *instances) 16692 { 16693 uu_list_walk_t *svcs, *insts; 16694 uu_list_t *ilist; 16695 bundle_t *b; 16696 entity_t *mfsvc, *mfinst; 16697 const char *svcn; 16698 int rminstcnt = 0; 16699 16700 16701 b = internal_bundle_new(); 16702 16703 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 16704 /* 16705 * Unable to process the manifest file for 16706 * instance support, so just return as 16707 * don't want to remove instances that could 16708 * not be accounted for that might exist here. 16709 */ 16710 internal_bundle_free(b); 16711 return (0); 16712 } 16713 16714 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 16715 if (svcs == NULL) { 16716 internal_bundle_free(b); 16717 return (0); 16718 } 16719 16720 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 16721 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 16722 16723 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 16724 if (strcmp(mfsvc->sc_name, svcn) == 0) 16725 break; 16726 } 16727 uu_list_walk_end(svcs); 16728 16729 if (mfsvc == NULL) { 16730 internal_bundle_free(b); 16731 return (-1); 16732 } 16733 16734 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 16735 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 16736 internal_bundle_free(b); 16737 return (0); 16738 } 16739 16740 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 16741 /* 16742 * Remove the instance from the instances list. 16743 * The unaccounted for instances will be removed 16744 * from the service once all manifests are 16745 * processed. 16746 */ 16747 (void) remove_string(instances, 16748 mfinst->sc_name); 16749 rminstcnt++; 16750 } 16751 16752 uu_list_walk_end(insts); 16753 internal_bundle_free(b); 16754 16755 return (rminstcnt); 16756 } 16757 16758 /* 16759 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 16760 * 'false' to indicate there's no manifest file(s) found for the service. 16761 */ 16762 static void 16763 svc_add_no_support(scf_service_t *svc) 16764 { 16765 char *pname; 16766 16767 /* Add no support */ 16768 cur_svc = svc; 16769 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 16770 return; 16771 16772 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 16773 if (pname == NULL) 16774 uu_die(gettext("Out of memory.\n")); 16775 16776 (void) lscf_addpropvalue(pname, "boolean:", "0"); 16777 16778 uu_free(pname); 16779 cur_svc = NULL; 16780 } 16781 16782 /* 16783 * This function handles all upgrade scenarios for a service that doesn't have 16784 * SCF_PG_MANIFESTFILES pg. The function creates and populates 16785 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 16786 * manifest(s) mapping. Manifests under supported directories are inventoried 16787 * and a property is added for each file that delivers configuration to the 16788 * service. A service that has no corresponding manifest files (deleted) are 16789 * removed from repository. 16790 * 16791 * Unsupported services: 16792 * 16793 * A service is considered unsupported if there is no corresponding manifest 16794 * in the supported directories for that service and the service isn't in the 16795 * history file list. The history file, MFSTHISTFILE, contains a list of all 16796 * services and instances that were delivered by Solaris before the introduction 16797 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 16798 * the path to the manifest file that defined the service or instance. 16799 * 16800 * Another type of unsupported services is 'handcrafted' services, 16801 * programmatically created services or services created by dependent entries 16802 * in other manifests. A handcrafted service is identified by its lack of any 16803 * instance containing last-import snapshot which is created during svccfg 16804 * import. 16805 * 16806 * This function sets a flag for unsupported services by setting services' 16807 * SCF_PG_MANIFESTFILES/support property to false. 16808 */ 16809 static void 16810 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 16811 { 16812 service_manifest_t *elem; 16813 uu_list_walk_t *mfwalk; 16814 string_list_t *mfile; 16815 uu_list_t *instances; 16816 const char *sname; 16817 char *pname; 16818 int r; 16819 16820 /* 16821 * Since there's no guarantee manifests under /var are available during 16822 * early import, don't perform any upgrade during early import. 16823 */ 16824 if (IGNORE_VAR) 16825 return; 16826 16827 if (service_manifest_tree == NULL) { 16828 create_manifest_tree(); 16829 } 16830 16831 /* 16832 * Find service's supporting manifest(s) after 16833 * stripping off the svc:/ prefix that is part 16834 * of the fmri that is not used in the service 16835 * manifest bundle list. 16836 */ 16837 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 16838 strlen(SCF_FMRI_SERVICE_PREFIX); 16839 elem = find_add_svc_mfst(sname, NULL); 16840 if (elem == NULL) { 16841 16842 /* 16843 * A handcrafted service, one that has no instance containing 16844 * last-import snapshot, should get unsupported flag. 16845 */ 16846 instances = create_instance_list(svc, 1); 16847 if (instances == NULL) { 16848 uu_warn(gettext("Unable to create instance list %s\n"), 16849 svcname); 16850 return; 16851 } 16852 16853 if (uu_list_numnodes(instances) == 0) { 16854 svc_add_no_support(svc); 16855 return; 16856 } 16857 16858 /* 16859 * If the service is in the history file, and its supporting 16860 * manifests are not found, we can safely delete the service 16861 * because its manifests are removed from the system. 16862 * 16863 * Services not found in the history file are not delivered by 16864 * Solaris and/or delivered outside supported directories, set 16865 * unsupported flag for these services. 16866 */ 16867 r = check_mfst_history(svcname); 16868 if (r == -1) 16869 return; 16870 16871 if (r) { 16872 /* Set unsupported flag for service */ 16873 svc_add_no_support(svc); 16874 } else { 16875 /* Delete the service */ 16876 teardown_service(svc, svcname); 16877 } 16878 16879 return; 16880 } 16881 16882 /* 16883 * Walk through the list of manifests and add them 16884 * to the service. 16885 * 16886 * Create a manifestfiles pg and add the property. 16887 */ 16888 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 16889 if (mfwalk == NULL) 16890 return; 16891 16892 cur_svc = svc; 16893 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 16894 if (r != 0) { 16895 cur_svc = NULL; 16896 return; 16897 } 16898 16899 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 16900 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16901 mhash_filename_to_propname(mfile->str, 0)); 16902 if (pname == NULL) 16903 uu_die(gettext("Out of memory.\n")); 16904 16905 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 16906 uu_free(pname); 16907 } 16908 uu_list_walk_end(mfwalk); 16909 16910 cur_svc = NULL; 16911 } 16912 16913 /* 16914 * Take a service and process the manifest file entires to see if 16915 * there is continued support for the service and instances. If 16916 * not cleanup as appropriate. 16917 * 16918 * If a service does not have a manifest files entry flag it for 16919 * upgrade and return. 16920 * 16921 * For each manifestfiles property check if the manifest file is 16922 * under the supported /lib/svc/manifest or /var/svc/manifest path 16923 * and if not then return immediately as this service is not supported 16924 * by the cleanup mechanism and should be ignored. 16925 * 16926 * For each manifest file that is supported, check to see if the 16927 * file exists. If not then remove the manifest file property 16928 * from the service and the smf/manifest hash table. If the manifest 16929 * file exists then verify that it supports the instances that are 16930 * part of the service. 16931 * 16932 * Once all manifest files have been accounted for remove any instances 16933 * that are no longer supported in the service. 16934 * 16935 * Return values : 16936 * 0 - Successfully processed the service 16937 * non-zero - failed to process the service 16938 * 16939 * On most errors, will just return to wait and get the next service, 16940 * unless in case of unable to create the needed structures which is 16941 * most likely a fatal error that is not going to be recoverable. 16942 */ 16943 int 16944 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 16945 { 16946 struct mpg_mfile *mpntov; 16947 struct mpg_mfile **mpvarry = NULL; 16948 scf_service_t *svc; 16949 scf_propertygroup_t *mpg; 16950 scf_property_t *mp; 16951 scf_value_t *mv; 16952 scf_iter_t *mi; 16953 scf_instance_t *instance; 16954 uu_list_walk_t *insts; 16955 uu_list_t *instances = NULL; 16956 boolean_t activity = (boolean_t)act; 16957 char *mpnbuf; 16958 char *mpvbuf; 16959 char *pgpropbuf; 16960 int mfstcnt, rminstct, instct, mfstmax; 16961 int index; 16962 int r = 0; 16963 16964 assert(g_hndl != NULL); 16965 assert(wip->svc != NULL); 16966 assert(wip->fmri != NULL); 16967 16968 svc = wip->svc; 16969 16970 mpg = scf_pg_create(g_hndl); 16971 mp = scf_property_create(g_hndl); 16972 mi = scf_iter_create(g_hndl); 16973 mv = scf_value_create(g_hndl); 16974 instance = scf_instance_create(g_hndl); 16975 16976 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 16977 instance == NULL) { 16978 uu_warn(gettext("Unable to create the supporting entities\n")); 16979 uu_warn(gettext("scf error is : %s\n"), 16980 scf_strerror(scf_error())); 16981 scfdie(); 16982 } 16983 16984 /* 16985 * Get the manifestfiles property group to be parsed for 16986 * files existence. 16987 */ 16988 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 16989 switch (scf_error()) { 16990 case SCF_ERROR_NOT_FOUND: 16991 upgrade_svc_mfst_connection(svc, wip->fmri); 16992 break; 16993 case SCF_ERROR_DELETED: 16994 case SCF_ERROR_CONNECTION_BROKEN: 16995 goto out; 16996 16997 case SCF_ERROR_HANDLE_MISMATCH: 16998 case SCF_ERROR_NOT_BOUND: 16999 case SCF_ERROR_NOT_SET: 17000 default: 17001 bad_error("scf_iter_pg_properties", 17002 scf_error()); 17003 } 17004 17005 goto out; 17006 } 17007 17008 /* 17009 * Iterate through each of the manifestfiles properties 17010 * to determine what manifestfiles are available. 17011 * 17012 * If a manifest file is supported then increment the 17013 * count and therefore the service is safe. 17014 */ 17015 if (scf_iter_pg_properties(mi, mpg) != 0) { 17016 switch (scf_error()) { 17017 case SCF_ERROR_DELETED: 17018 case SCF_ERROR_CONNECTION_BROKEN: 17019 goto out; 17020 17021 case SCF_ERROR_HANDLE_MISMATCH: 17022 case SCF_ERROR_NOT_BOUND: 17023 case SCF_ERROR_NOT_SET: 17024 default: 17025 bad_error("scf_iter_pg_properties", 17026 scf_error()); 17027 } 17028 } 17029 17030 mfstcnt = 0; 17031 mfstmax = MFSTFILE_MAX; 17032 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 17033 while ((r = scf_iter_next_property(mi, mp)) != 0) { 17034 if (r == -1) 17035 bad_error(gettext("Unable to iterate through " 17036 "manifestfiles properties : %s"), 17037 scf_error()); 17038 17039 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 17040 mpnbuf = safe_malloc(max_scf_name_len + 1); 17041 mpvbuf = safe_malloc(max_scf_value_len + 1); 17042 mpntov->mpg = mpnbuf; 17043 mpntov->mfile = mpvbuf; 17044 mpntov->access = 1; 17045 if (scf_property_get_name(mp, mpnbuf, 17046 max_scf_name_len + 1) < 0) { 17047 uu_warn(gettext("Unable to get manifest file " 17048 "property : %s\n"), 17049 scf_strerror(scf_error())); 17050 17051 switch (scf_error()) { 17052 case SCF_ERROR_DELETED: 17053 case SCF_ERROR_CONNECTION_BROKEN: 17054 r = scferror2errno(scf_error()); 17055 goto out_free; 17056 17057 case SCF_ERROR_HANDLE_MISMATCH: 17058 case SCF_ERROR_NOT_BOUND: 17059 case SCF_ERROR_NOT_SET: 17060 default: 17061 bad_error("scf_iter_pg_properties", 17062 scf_error()); 17063 } 17064 } 17065 17066 /* 17067 * The support property is a boolean value that indicates 17068 * if the service is supported for manifest file deletion. 17069 * Currently at this time there is no code that sets this 17070 * value to true. So while we could just let this be caught 17071 * by the support check below, in the future this by be set 17072 * to true and require processing. So for that, go ahead 17073 * and check here, and just return if false. Otherwise, 17074 * fall through expecting that other support checks will 17075 * handle the entries. 17076 */ 17077 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 17078 uint8_t support; 17079 17080 if (scf_property_get_value(mp, mv) != 0 || 17081 scf_value_get_boolean(mv, &support) != 0) { 17082 uu_warn(gettext("Unable to get the manifest " 17083 "support value: %s\n"), 17084 scf_strerror(scf_error())); 17085 17086 switch (scf_error()) { 17087 case SCF_ERROR_DELETED: 17088 case SCF_ERROR_CONNECTION_BROKEN: 17089 r = scferror2errno(scf_error()); 17090 goto out_free; 17091 17092 case SCF_ERROR_HANDLE_MISMATCH: 17093 case SCF_ERROR_NOT_BOUND: 17094 case SCF_ERROR_NOT_SET: 17095 default: 17096 bad_error("scf_iter_pg_properties", 17097 scf_error()); 17098 } 17099 } 17100 17101 if (support == B_FALSE) 17102 goto out_free; 17103 } 17104 17105 /* 17106 * Anything with a manifest outside of the supported 17107 * directories, immediately bail out because that makes 17108 * this service non-supported. We don't even want 17109 * to do instance processing in this case because the 17110 * instances could be part of the non-supported manifest. 17111 */ 17112 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 17113 /* 17114 * Manifest is not in /lib/svc, so we need to 17115 * consider the /var/svc case. 17116 */ 17117 if (strncmp(mpnbuf, VARSVC_PR, 17118 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 17119 /* 17120 * Either the manifest is not in /var/svc or 17121 * /var is not yet mounted. We ignore the 17122 * manifest either because it is not in a 17123 * standard location or because we cannot 17124 * currently access the manifest. 17125 */ 17126 goto out_free; 17127 } 17128 } 17129 17130 /* 17131 * Get the value to of the manifest file for this entry 17132 * for access verification and instance support 17133 * verification if it still exists. 17134 * 17135 * During Early Manifest Import if the manifest is in 17136 * /var/svc then it may not yet be available for checking 17137 * so we must determine if /var/svc is available. If not 17138 * then defer until Late Manifest Import to cleanup. 17139 */ 17140 if (scf_property_get_value(mp, mv) != 0) { 17141 uu_warn(gettext("Unable to get the manifest file " 17142 "value: %s\n"), 17143 scf_strerror(scf_error())); 17144 17145 switch (scf_error()) { 17146 case SCF_ERROR_DELETED: 17147 case SCF_ERROR_CONNECTION_BROKEN: 17148 r = scferror2errno(scf_error()); 17149 goto out_free; 17150 17151 case SCF_ERROR_HANDLE_MISMATCH: 17152 case SCF_ERROR_NOT_BOUND: 17153 case SCF_ERROR_NOT_SET: 17154 default: 17155 bad_error("scf_property_get_value", 17156 scf_error()); 17157 } 17158 } 17159 17160 if (scf_value_get_astring(mv, mpvbuf, 17161 max_scf_value_len + 1) < 0) { 17162 uu_warn(gettext("Unable to get the manifest " 17163 "file : %s\n"), 17164 scf_strerror(scf_error())); 17165 17166 switch (scf_error()) { 17167 case SCF_ERROR_DELETED: 17168 case SCF_ERROR_CONNECTION_BROKEN: 17169 r = scferror2errno(scf_error()); 17170 goto out_free; 17171 17172 case SCF_ERROR_HANDLE_MISMATCH: 17173 case SCF_ERROR_NOT_BOUND: 17174 case SCF_ERROR_NOT_SET: 17175 default: 17176 bad_error("scf_value_get_astring", 17177 scf_error()); 17178 } 17179 } 17180 17181 mpvarry[mfstcnt] = mpntov; 17182 mfstcnt++; 17183 17184 /* 17185 * Check for the need to reallocate array 17186 */ 17187 if (mfstcnt >= (mfstmax - 1)) { 17188 struct mpg_mfile **newmpvarry; 17189 17190 mfstmax = mfstmax * 2; 17191 newmpvarry = realloc(mpvarry, 17192 sizeof (struct mpg_mfile *) * mfstmax); 17193 17194 if (newmpvarry == NULL) 17195 goto out_free; 17196 17197 mpvarry = newmpvarry; 17198 } 17199 17200 mpvarry[mfstcnt] = NULL; 17201 } 17202 17203 for (index = 0; mpvarry[index]; index++) { 17204 mpntov = mpvarry[index]; 17205 17206 /* 17207 * Check to see if the manifestfile is accessable, if so hand 17208 * this service and manifestfile off to be processed for 17209 * instance support. 17210 */ 17211 mpnbuf = mpntov->mpg; 17212 mpvbuf = mpntov->mfile; 17213 if (access(mpvbuf, F_OK) != 0) { 17214 mpntov->access = 0; 17215 activity++; 17216 mfstcnt--; 17217 /* Remove the entry from the service */ 17218 cur_svc = svc; 17219 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 17220 mpnbuf); 17221 if (pgpropbuf == NULL) 17222 uu_die(gettext("Out of memory.\n")); 17223 17224 lscf_delprop(pgpropbuf); 17225 cur_svc = NULL; 17226 17227 uu_free(pgpropbuf); 17228 } 17229 } 17230 17231 /* 17232 * If mfstcnt is 0, none of the manifests that supported the service 17233 * existed so remove the service. 17234 */ 17235 if (mfstcnt == 0) { 17236 teardown_service(svc, wip->fmri); 17237 17238 goto out_free; 17239 } 17240 17241 if (activity) { 17242 int nosvcsupport = 0; 17243 17244 /* 17245 * If the list of service instances is NULL then 17246 * create the list. 17247 */ 17248 instances = create_instance_list(svc, 1); 17249 if (instances == NULL) { 17250 uu_warn(gettext("Unable to create instance list %s\n"), 17251 wip->fmri); 17252 goto out_free; 17253 } 17254 17255 rminstct = uu_list_numnodes(instances); 17256 instct = rminstct; 17257 17258 for (index = 0; mpvarry[index]; index++) { 17259 mpntov = mpvarry[index]; 17260 if (mpntov->access == 0) 17261 continue; 17262 17263 mpnbuf = mpntov->mpg; 17264 mpvbuf = mpntov->mfile; 17265 r = check_instance_support(mpvbuf, wip->fmri, 17266 instances); 17267 if (r == -1) { 17268 nosvcsupport++; 17269 } else { 17270 rminstct -= r; 17271 } 17272 } 17273 17274 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 17275 teardown_service(svc, wip->fmri); 17276 17277 goto out_free; 17278 } 17279 } 17280 17281 /* 17282 * If there are instances left on the instance list, then 17283 * we must remove them. 17284 */ 17285 if (instances != NULL && uu_list_numnodes(instances)) { 17286 string_list_t *sp; 17287 17288 insts = uu_list_walk_start(instances, 0); 17289 while ((sp = uu_list_walk_next(insts)) != NULL) { 17290 /* 17291 * Remove the instance from the instances list. 17292 */ 17293 safe_printf(gettext("Delete instance %s from " 17294 "service %s\n"), sp->str, wip->fmri); 17295 if (scf_service_get_instance(svc, sp->str, 17296 instance) != SCF_SUCCESS) { 17297 (void) uu_warn("scf_error - %s\n", 17298 scf_strerror(scf_error())); 17299 17300 continue; 17301 } 17302 17303 (void) disable_instance(instance); 17304 17305 (void) lscf_instance_delete(instance, 1); 17306 } 17307 scf_instance_destroy(instance); 17308 uu_list_walk_end(insts); 17309 } 17310 17311 out_free: 17312 if (mpvarry) { 17313 struct mpg_mfile *fmpntov; 17314 17315 for (index = 0; mpvarry[index]; index++) { 17316 fmpntov = mpvarry[index]; 17317 if (fmpntov->mpg == mpnbuf) 17318 mpnbuf = NULL; 17319 free(fmpntov->mpg); 17320 17321 if (fmpntov->mfile == mpvbuf) 17322 mpvbuf = NULL; 17323 free(fmpntov->mfile); 17324 17325 if (fmpntov == mpntov) 17326 mpntov = NULL; 17327 free(fmpntov); 17328 } 17329 if (mpnbuf) 17330 free(mpnbuf); 17331 if (mpvbuf) 17332 free(mpvbuf); 17333 if (mpntov) 17334 free(mpntov); 17335 17336 free(mpvarry); 17337 } 17338 out: 17339 scf_pg_destroy(mpg); 17340 scf_property_destroy(mp); 17341 scf_iter_destroy(mi); 17342 scf_value_destroy(mv); 17343 17344 return (0); 17345 } 17346 17347 /* 17348 * Take the service and search for the manifestfiles property 17349 * in each of the property groups. If the manifest file 17350 * associated with the property does not exist then remove 17351 * the property group. 17352 */ 17353 int 17354 lscf_hash_cleanup() 17355 { 17356 scf_service_t *svc; 17357 scf_scope_t *scope; 17358 scf_propertygroup_t *pg; 17359 scf_property_t *prop; 17360 scf_value_t *val; 17361 scf_iter_t *iter; 17362 char *pgname = NULL; 17363 char *mfile = NULL; 17364 int r; 17365 17366 svc = scf_service_create(g_hndl); 17367 scope = scf_scope_create(g_hndl); 17368 pg = scf_pg_create(g_hndl); 17369 prop = scf_property_create(g_hndl); 17370 val = scf_value_create(g_hndl); 17371 iter = scf_iter_create(g_hndl); 17372 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 17373 svc == NULL || scope == NULL) { 17374 uu_warn(gettext("Unable to create a property group, or " 17375 "property\n")); 17376 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 17377 "pg is not NULL"); 17378 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 17379 "prop is not NULL"); 17380 uu_warn("%s\n", val == NULL ? "val is NULL" : 17381 "val is not NULL"); 17382 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 17383 "iter is not NULL"); 17384 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 17385 "svc is not NULL"); 17386 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 17387 "scope is not NULL"); 17388 uu_warn(gettext("scf error is : %s\n"), 17389 scf_strerror(scf_error())); 17390 scfdie(); 17391 } 17392 17393 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 17394 switch (scf_error()) { 17395 case SCF_ERROR_CONNECTION_BROKEN: 17396 case SCF_ERROR_NOT_FOUND: 17397 goto out; 17398 17399 case SCF_ERROR_HANDLE_MISMATCH: 17400 case SCF_ERROR_NOT_BOUND: 17401 case SCF_ERROR_INVALID_ARGUMENT: 17402 default: 17403 bad_error("scf_handle_get_scope", scf_error()); 17404 } 17405 } 17406 17407 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 17408 uu_warn(gettext("Unable to process the hash service, %s\n"), 17409 HASH_SVC); 17410 goto out; 17411 } 17412 17413 pgname = safe_malloc(max_scf_name_len + 1); 17414 mfile = safe_malloc(max_scf_value_len + 1); 17415 17416 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 17417 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 17418 scf_strerror(scf_error())); 17419 goto out; 17420 } 17421 17422 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 17423 if (r == -1) 17424 goto out; 17425 17426 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 17427 switch (scf_error()) { 17428 case SCF_ERROR_DELETED: 17429 return (ENODEV); 17430 17431 case SCF_ERROR_CONNECTION_BROKEN: 17432 return (ECONNABORTED); 17433 17434 case SCF_ERROR_NOT_SET: 17435 case SCF_ERROR_NOT_BOUND: 17436 default: 17437 bad_error("scf_pg_get_name", scf_error()); 17438 } 17439 } 17440 if (IGNORE_VAR) { 17441 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 17442 continue; 17443 } 17444 17445 /* 17446 * If unable to get the property continue as this is an 17447 * entry that has no location to check against. 17448 */ 17449 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 17450 continue; 17451 } 17452 17453 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 17454 uu_warn(gettext("Unable to get value from %s\n"), 17455 pgname); 17456 17457 switch (scf_error()) { 17458 case SCF_ERROR_DELETED: 17459 case SCF_ERROR_CONSTRAINT_VIOLATED: 17460 case SCF_ERROR_NOT_FOUND: 17461 case SCF_ERROR_NOT_SET: 17462 continue; 17463 17464 case SCF_ERROR_CONNECTION_BROKEN: 17465 r = scferror2errno(scf_error()); 17466 goto out; 17467 17468 case SCF_ERROR_HANDLE_MISMATCH: 17469 case SCF_ERROR_NOT_BOUND: 17470 default: 17471 bad_error("scf_property_get_value", 17472 scf_error()); 17473 } 17474 } 17475 17476 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) 17477 == -1) { 17478 uu_warn(gettext("Unable to get astring from %s : %s\n"), 17479 pgname, scf_strerror(scf_error())); 17480 17481 switch (scf_error()) { 17482 case SCF_ERROR_NOT_SET: 17483 case SCF_ERROR_TYPE_MISMATCH: 17484 continue; 17485 17486 default: 17487 bad_error("scf_value_get_astring", scf_error()); 17488 } 17489 } 17490 17491 if (access(mfile, F_OK) == 0) 17492 continue; 17493 17494 (void) scf_pg_delete(pg); 17495 } 17496 17497 out: 17498 scf_scope_destroy(scope); 17499 scf_service_destroy(svc); 17500 scf_pg_destroy(pg); 17501 scf_property_destroy(prop); 17502 scf_value_destroy(val); 17503 scf_iter_destroy(iter); 17504 free(pgname); 17505 free(mfile); 17506 17507 return (0); 17508 } 17509 17510 #ifndef NATIVE_BUILD 17511 /* ARGSUSED */ 17512 CPL_MATCH_FN(complete_select) 17513 { 17514 const char *arg0, *arg1, *arg1end; 17515 int word_start, err = 0, r; 17516 size_t len; 17517 char *buf; 17518 17519 lscf_prep_hndl(); 17520 17521 arg0 = line + strspn(line, " \t"); 17522 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 17523 17524 arg1 = arg0 + sizeof ("select") - 1; 17525 arg1 += strspn(arg1, " \t"); 17526 word_start = arg1 - line; 17527 17528 arg1end = arg1 + strcspn(arg1, " \t"); 17529 if (arg1end < line + word_end) 17530 return (0); 17531 17532 len = line + word_end - arg1; 17533 17534 buf = safe_malloc(max_scf_name_len + 1); 17535 17536 if (cur_snap != NULL) { 17537 return (0); 17538 } else if (cur_inst != NULL) { 17539 return (0); 17540 } else if (cur_svc != NULL) { 17541 scf_instance_t *inst; 17542 scf_iter_t *iter; 17543 17544 if ((inst = scf_instance_create(g_hndl)) == NULL || 17545 (iter = scf_iter_create(g_hndl)) == NULL) 17546 scfdie(); 17547 17548 if (scf_iter_service_instances(iter, cur_svc) != 0) 17549 scfdie(); 17550 17551 for (;;) { 17552 r = scf_iter_next_instance(iter, inst); 17553 if (r == 0) 17554 break; 17555 if (r != 1) 17556 scfdie(); 17557 17558 if (scf_instance_get_name(inst, buf, 17559 max_scf_name_len + 1) < 0) 17560 scfdie(); 17561 17562 if (strncmp(buf, arg1, len) == 0) { 17563 err = cpl_add_completion(cpl, line, word_start, 17564 word_end, buf + len, "", " "); 17565 if (err != 0) 17566 break; 17567 } 17568 } 17569 17570 scf_iter_destroy(iter); 17571 scf_instance_destroy(inst); 17572 17573 return (err); 17574 } else { 17575 scf_service_t *svc; 17576 scf_iter_t *iter; 17577 17578 assert(cur_scope != NULL); 17579 17580 if ((svc = scf_service_create(g_hndl)) == NULL || 17581 (iter = scf_iter_create(g_hndl)) == NULL) 17582 scfdie(); 17583 17584 if (scf_iter_scope_services(iter, cur_scope) != 0) 17585 scfdie(); 17586 17587 for (;;) { 17588 r = scf_iter_next_service(iter, svc); 17589 if (r == 0) 17590 break; 17591 if (r != 1) 17592 scfdie(); 17593 17594 if (scf_service_get_name(svc, buf, 17595 max_scf_name_len + 1) < 0) 17596 scfdie(); 17597 17598 if (strncmp(buf, arg1, len) == 0) { 17599 err = cpl_add_completion(cpl, line, word_start, 17600 word_end, buf + len, "", " "); 17601 if (err != 0) 17602 break; 17603 } 17604 } 17605 17606 scf_iter_destroy(iter); 17607 scf_service_destroy(svc); 17608 17609 return (err); 17610 } 17611 } 17612 17613 /* ARGSUSED */ 17614 CPL_MATCH_FN(complete_command) 17615 { 17616 uint32_t scope = 0; 17617 17618 if (cur_snap != NULL) 17619 scope = CS_SNAP; 17620 else if (cur_inst != NULL) 17621 scope = CS_INST; 17622 else if (cur_svc != NULL) 17623 scope = CS_SVC; 17624 else 17625 scope = CS_SCOPE; 17626 17627 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 17628 } 17629 #endif /* NATIVE_BUILD */