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 10390 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters"); 10391 event = xmlNewNode(NULL, (xmlChar *)"event"); 10392 if (n == NULL || event == NULL) 10393 uu_die(emsg_create_xml); 10394 10395 /* event value */ 10396 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 10397 scfdie(); 10398 safe_setprop(event, value_attr, exp_str); 10399 10400 (void) xmlAddChild(n, event); 10401 10402 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL || 10403 (eelts = calloc(URI_SCHEME_NUM, 10404 sizeof (struct params_elts))) == NULL) 10405 uu_die(gettext("Out of memory.\n")); 10406 10407 err = 0; 10408 10409 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10410 scfdie(); 10411 10412 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10413 char *t, *p; 10414 10415 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10416 scfdie(); 10417 10418 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) { 10419 /* 10420 * this is not a well formed notification parameters 10421 * element, we should export as regular pg 10422 */ 10423 err = 1; 10424 break; 10425 } 10426 10427 if ((i = check_uri_protocol(t)) < 0) { 10428 err = 1; 10429 break; 10430 } 10431 10432 if (type[i] == NULL) { 10433 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) == 10434 NULL) 10435 uu_die(emsg_create_xml); 10436 10437 safe_setprop(type[i], name_attr, t); 10438 } 10439 if (strcmp(p, active_attr) == 0) { 10440 if (set_attr_from_prop(exp_prop, type[i], 10441 active_attr) != 0) { 10442 err = 1; 10443 break; 10444 } 10445 continue; 10446 } 10447 /* 10448 * We export the parameter 10449 */ 10450 export_parameter(exp_prop, p, &eelts[i]); 10451 } 10452 10453 if (ret == -1) 10454 scfdie(); 10455 10456 if (err == 1) { 10457 for (i = 0; i < URI_SCHEME_NUM; ++i) 10458 xmlFree(type[i]); 10459 free(type); 10460 10461 export_pg(pg, elts, SCE_ALL_VALUES); 10462 10463 return; 10464 } else { 10465 for (i = 0; i < URI_SCHEME_NUM; ++i) 10466 if (type[i] != NULL) { 10467 (void) xmlAddChildList(type[i], 10468 eelts[i].paramval); 10469 (void) xmlAddChildList(type[i], 10470 eelts[i].parameter); 10471 (void) xmlAddSibling(event, type[i]); 10472 } 10473 } 10474 free(type); 10475 10476 if (elts->notify_params == NULL) 10477 elts->notify_params = n; 10478 else 10479 (void) xmlAddSibling(elts->notify_params, n); 10480 } 10481 10482 /* 10483 * Process the general property group for an instance. 10484 */ 10485 static void 10486 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 10487 struct entity_elts *elts) 10488 { 10489 uint8_t enabled; 10490 struct pg_elts pgelts; 10491 int ret; 10492 10493 /* enabled */ 10494 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10495 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10496 prop_get_val(exp_prop, exp_val) == 0) { 10497 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10498 scfdie(); 10499 } else { 10500 enabled = 0; 10501 } 10502 10503 safe_setprop(inode, enabled_attr, enabled ? true : false); 10504 10505 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10506 scfdie(); 10507 10508 (void) memset(&pgelts, 0, sizeof (pgelts)); 10509 10510 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10511 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10512 scfdie(); 10513 10514 if (strcmp(exp_str, scf_property_enabled) == 0) { 10515 continue; 10516 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10517 xmlNodePtr rnode, sfnode; 10518 10519 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10520 if (rnode == NULL) 10521 uu_die(emsg_create_xml); 10522 10523 sfnode = xmlNewChild(rnode, NULL, 10524 (xmlChar *)"service_fmri", NULL); 10525 if (sfnode == NULL) 10526 uu_die(emsg_create_xml); 10527 10528 if (set_attr_from_prop(exp_prop, sfnode, 10529 value_attr) == 0) { 10530 elts->restarter = rnode; 10531 continue; 10532 } 10533 10534 xmlFreeNode(rnode); 10535 } 10536 10537 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10538 } 10539 if (ret == -1) 10540 scfdie(); 10541 10542 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10543 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10544 elts); 10545 } 10546 10547 /* 10548 * Put an instance element for the given instance into selts. 10549 */ 10550 static void 10551 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10552 { 10553 xmlNodePtr n; 10554 boolean_t isdefault; 10555 struct entity_elts elts; 10556 struct template_elts template_elts; 10557 int ret; 10558 10559 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10560 if (n == NULL) 10561 uu_die(emsg_create_xml); 10562 10563 /* name */ 10564 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10565 scfdie(); 10566 safe_setprop(n, name_attr, exp_str); 10567 isdefault = strcmp(exp_str, "default") == 0; 10568 10569 /* check existance of general pg (since general/enabled is required) */ 10570 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10571 if (scf_error() != SCF_ERROR_NOT_FOUND) 10572 scfdie(); 10573 10574 if (g_verbose) { 10575 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10576 scfdie(); 10577 10578 warn(gettext("Instance %s has no general property " 10579 "group; it will be marked disabled.\n"), exp_str); 10580 } 10581 10582 safe_setprop(n, enabled_attr, false); 10583 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10584 strcmp(exp_str, scf_group_framework) != 0) { 10585 if (g_verbose) { 10586 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10587 scfdie(); 10588 10589 warn(gettext("Property group %s is not of type " 10590 "framework; the instance will be marked " 10591 "disabled.\n"), exp_str); 10592 } 10593 10594 safe_setprop(n, enabled_attr, false); 10595 } 10596 10597 /* property groups */ 10598 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10599 scfdie(); 10600 10601 (void) memset(&elts, 0, sizeof (elts)); 10602 (void) memset(&template_elts, 0, sizeof (template_elts)); 10603 10604 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10605 uint32_t pgflags; 10606 10607 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10608 scfdie(); 10609 10610 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10611 continue; 10612 10613 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10614 scfdie(); 10615 10616 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10617 export_dependency(exp_pg, &elts); 10618 continue; 10619 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10620 export_method(exp_pg, &elts); 10621 continue; 10622 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10623 if (scf_pg_get_name(exp_pg, exp_str, 10624 max_scf_name_len + 1) < 0) 10625 scfdie(); 10626 10627 if (strcmp(exp_str, scf_pg_general) == 0) { 10628 export_inst_general(exp_pg, n, &elts); 10629 continue; 10630 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10631 0) { 10632 export_method_context(exp_pg, &elts); 10633 continue; 10634 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10635 export_dependents(exp_pg, &elts); 10636 continue; 10637 } 10638 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10639 export_template(exp_pg, &elts, &template_elts); 10640 continue; 10641 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10642 export_notify_params(exp_pg, &elts); 10643 continue; 10644 } 10645 10646 /* Ordinary pg. */ 10647 export_pg(exp_pg, &elts, flags); 10648 } 10649 if (ret == -1) 10650 scfdie(); 10651 10652 if (template_elts.common_name != NULL) { 10653 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10654 (void) xmlAddChild(elts.template, template_elts.common_name); 10655 (void) xmlAddChild(elts.template, template_elts.description); 10656 (void) xmlAddChild(elts.template, template_elts.documentation); 10657 } else { 10658 xmlFreeNode(template_elts.description); 10659 xmlFreeNode(template_elts.documentation); 10660 } 10661 10662 if (isdefault && elts.restarter == NULL && 10663 elts.dependencies == NULL && elts.method_context == NULL && 10664 elts.exec_methods == NULL && elts.notify_params == NULL && 10665 elts.property_groups == NULL && elts.template == NULL) { 10666 xmlChar *eval; 10667 10668 /* This is a default instance */ 10669 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10670 10671 xmlFreeNode(n); 10672 10673 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10674 if (n == NULL) 10675 uu_die(emsg_create_xml); 10676 10677 safe_setprop(n, enabled_attr, (char *)eval); 10678 xmlFree(eval); 10679 10680 selts->create_default_instance = n; 10681 } else { 10682 /* Assemble the children in order. */ 10683 (void) xmlAddChild(n, elts.restarter); 10684 (void) xmlAddChildList(n, elts.dependencies); 10685 (void) xmlAddChildList(n, elts.dependents); 10686 (void) xmlAddChild(n, elts.method_context); 10687 (void) xmlAddChildList(n, elts.exec_methods); 10688 (void) xmlAddChildList(n, elts.notify_params); 10689 (void) xmlAddChildList(n, elts.property_groups); 10690 (void) xmlAddChild(n, elts.template); 10691 10692 if (selts->instances == NULL) 10693 selts->instances = n; 10694 else 10695 (void) xmlAddSibling(selts->instances, n); 10696 } 10697 } 10698 10699 /* 10700 * Return a service element for the given service. 10701 */ 10702 static xmlNodePtr 10703 export_service(scf_service_t *svc, int flags) 10704 { 10705 xmlNodePtr snode; 10706 struct entity_elts elts; 10707 struct template_elts template_elts; 10708 int ret; 10709 10710 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10711 if (snode == NULL) 10712 uu_die(emsg_create_xml); 10713 10714 /* Get & set name attribute */ 10715 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10716 scfdie(); 10717 safe_setprop(snode, name_attr, exp_str); 10718 10719 safe_setprop(snode, type_attr, "service"); 10720 safe_setprop(snode, "version", "0"); 10721 10722 /* Acquire child elements. */ 10723 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10724 scfdie(); 10725 10726 (void) memset(&elts, 0, sizeof (elts)); 10727 (void) memset(&template_elts, 0, sizeof (template_elts)); 10728 10729 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10730 uint32_t pgflags; 10731 10732 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10733 scfdie(); 10734 10735 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10736 continue; 10737 10738 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10739 scfdie(); 10740 10741 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10742 export_dependency(exp_pg, &elts); 10743 continue; 10744 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10745 export_method(exp_pg, &elts); 10746 continue; 10747 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10748 if (scf_pg_get_name(exp_pg, exp_str, 10749 max_scf_name_len + 1) < 0) 10750 scfdie(); 10751 10752 if (strcmp(exp_str, scf_pg_general) == 0) { 10753 export_svc_general(exp_pg, &elts); 10754 continue; 10755 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10756 0) { 10757 export_method_context(exp_pg, &elts); 10758 continue; 10759 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10760 export_dependents(exp_pg, &elts); 10761 continue; 10762 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10763 continue; 10764 } 10765 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10766 export_template(exp_pg, &elts, &template_elts); 10767 continue; 10768 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10769 export_notify_params(exp_pg, &elts); 10770 continue; 10771 } 10772 10773 export_pg(exp_pg, &elts, flags); 10774 } 10775 if (ret == -1) 10776 scfdie(); 10777 10778 if (template_elts.common_name != NULL) { 10779 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10780 (void) xmlAddChild(elts.template, template_elts.common_name); 10781 (void) xmlAddChild(elts.template, template_elts.description); 10782 (void) xmlAddChild(elts.template, template_elts.documentation); 10783 } else { 10784 xmlFreeNode(template_elts.description); 10785 xmlFreeNode(template_elts.documentation); 10786 } 10787 10788 /* Iterate instances */ 10789 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10790 scfdie(); 10791 10792 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10793 export_instance(exp_inst, &elts, flags); 10794 if (ret == -1) 10795 scfdie(); 10796 10797 /* Now add all of the accumulated elements in order. */ 10798 (void) xmlAddChild(snode, elts.create_default_instance); 10799 (void) xmlAddChild(snode, elts.single_instance); 10800 (void) xmlAddChild(snode, elts.restarter); 10801 (void) xmlAddChildList(snode, elts.dependencies); 10802 (void) xmlAddChildList(snode, elts.dependents); 10803 (void) xmlAddChild(snode, elts.method_context); 10804 (void) xmlAddChildList(snode, elts.exec_methods); 10805 (void) xmlAddChildList(snode, elts.notify_params); 10806 (void) xmlAddChildList(snode, elts.property_groups); 10807 (void) xmlAddChildList(snode, elts.instances); 10808 (void) xmlAddChild(snode, elts.stability); 10809 (void) xmlAddChild(snode, elts.template); 10810 10811 return (snode); 10812 } 10813 10814 static int 10815 export_callback(void *data, scf_walkinfo_t *wip) 10816 { 10817 FILE *f; 10818 xmlDocPtr doc; 10819 xmlNodePtr sb; 10820 int result; 10821 struct export_args *argsp = (struct export_args *)data; 10822 10823 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10824 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10825 (exp_prop = scf_property_create(g_hndl)) == NULL || 10826 (exp_val = scf_value_create(g_hndl)) == NULL || 10827 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10828 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10829 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10830 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10831 scfdie(); 10832 10833 exp_str_sz = max_scf_len + 1; 10834 exp_str = safe_malloc(exp_str_sz); 10835 10836 if (argsp->filename != NULL) { 10837 errno = 0; 10838 f = fopen(argsp->filename, "wb"); 10839 if (f == NULL) { 10840 if (errno == 0) 10841 uu_die(gettext("Could not open \"%s\": no free " 10842 "stdio streams.\n"), argsp->filename); 10843 else 10844 uu_die(gettext("Could not open \"%s\""), 10845 argsp->filename); 10846 } 10847 } else 10848 f = stdout; 10849 10850 doc = xmlNewDoc((xmlChar *)"1.0"); 10851 if (doc == NULL) 10852 uu_die(gettext("Could not create XML document.\n")); 10853 10854 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10855 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10856 uu_die(emsg_create_xml); 10857 10858 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10859 if (sb == NULL) 10860 uu_die(emsg_create_xml); 10861 safe_setprop(sb, type_attr, "manifest"); 10862 safe_setprop(sb, name_attr, "export"); 10863 (void) xmlAddSibling(doc->children, sb); 10864 10865 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10866 10867 result = write_service_bundle(doc, f); 10868 10869 free(exp_str); 10870 scf_iter_destroy(exp_val_iter); 10871 scf_iter_destroy(exp_prop_iter); 10872 scf_iter_destroy(exp_pg_iter); 10873 scf_iter_destroy(exp_inst_iter); 10874 scf_value_destroy(exp_val); 10875 scf_property_destroy(exp_prop); 10876 scf_pg_destroy(exp_pg); 10877 scf_instance_destroy(exp_inst); 10878 10879 xmlFreeDoc(doc); 10880 10881 if (f != stdout) 10882 (void) fclose(f); 10883 10884 return (result); 10885 } 10886 10887 /* 10888 * Get the service named by fmri, build an XML tree which represents it, and 10889 * dump it into filename (or stdout if filename is NULL). 10890 */ 10891 int 10892 lscf_service_export(char *fmri, const char *filename, int flags) 10893 { 10894 struct export_args args; 10895 char *fmridup; 10896 const char *scope, *svc, *inst; 10897 size_t cblen = 3 * max_scf_name_len; 10898 char *canonbuf = alloca(cblen); 10899 int ret, err; 10900 10901 lscf_prep_hndl(); 10902 10903 bzero(&args, sizeof (args)); 10904 args.filename = filename; 10905 args.flags = flags; 10906 10907 /* 10908 * If some poor user has passed an exact instance FMRI, of the sort 10909 * one might cut and paste from svcs(1) or an error message, warn 10910 * and chop off the instance instead of failing. 10911 */ 10912 fmridup = alloca(strlen(fmri) + 1); 10913 (void) strcpy(fmridup, fmri); 10914 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX, 10915 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 && 10916 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 && 10917 inst != NULL) { 10918 (void) strlcpy(canonbuf, "svc:/", cblen); 10919 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 10920 (void) strlcat(canonbuf, "/", cblen); 10921 (void) strlcat(canonbuf, scope, cblen); 10922 } 10923 (void) strlcat(canonbuf, svc, cblen); 10924 fmri = canonbuf; 10925 10926 warn(gettext("Only services may be exported; ignoring " 10927 "instance portion of argument.\n")); 10928 } 10929 10930 err = 0; 10931 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10932 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10933 &args, &err, semerr)) != 0) { 10934 if (ret != -1) 10935 semerr(gettext("Failed to walk instances: %s\n"), 10936 scf_strerror(ret)); 10937 return (-1); 10938 } 10939 10940 /* 10941 * Error message has already been printed. 10942 */ 10943 if (err != 0) 10944 return (-1); 10945 10946 return (0); 10947 } 10948 10949 10950 /* 10951 * Archive 10952 */ 10953 10954 static xmlNodePtr 10955 make_archive(int flags) 10956 { 10957 xmlNodePtr sb; 10958 scf_scope_t *scope; 10959 scf_service_t *svc; 10960 scf_iter_t *iter; 10961 int r; 10962 10963 if ((scope = scf_scope_create(g_hndl)) == NULL || 10964 (svc = scf_service_create(g_hndl)) == NULL || 10965 (iter = scf_iter_create(g_hndl)) == NULL || 10966 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10967 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10968 (exp_prop = scf_property_create(g_hndl)) == NULL || 10969 (exp_val = scf_value_create(g_hndl)) == NULL || 10970 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10971 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10972 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10973 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10974 scfdie(); 10975 10976 exp_str_sz = max_scf_len + 1; 10977 exp_str = safe_malloc(exp_str_sz); 10978 10979 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10980 if (sb == NULL) 10981 uu_die(emsg_create_xml); 10982 safe_setprop(sb, type_attr, "archive"); 10983 safe_setprop(sb, name_attr, "none"); 10984 10985 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 10986 scfdie(); 10987 if (scf_iter_scope_services(iter, scope) != 0) 10988 scfdie(); 10989 10990 for (;;) { 10991 r = scf_iter_next_service(iter, svc); 10992 if (r == 0) 10993 break; 10994 if (r != 1) 10995 scfdie(); 10996 10997 if (scf_service_get_name(svc, exp_str, 10998 max_scf_name_len + 1) < 0) 10999 scfdie(); 11000 11001 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 11002 continue; 11003 11004 (void) xmlAddChild(sb, export_service(svc, flags)); 11005 } 11006 11007 free(exp_str); 11008 11009 scf_iter_destroy(exp_val_iter); 11010 scf_iter_destroy(exp_prop_iter); 11011 scf_iter_destroy(exp_pg_iter); 11012 scf_iter_destroy(exp_inst_iter); 11013 scf_value_destroy(exp_val); 11014 scf_property_destroy(exp_prop); 11015 scf_pg_destroy(exp_pg); 11016 scf_instance_destroy(exp_inst); 11017 scf_iter_destroy(iter); 11018 scf_service_destroy(svc); 11019 scf_scope_destroy(scope); 11020 11021 return (sb); 11022 } 11023 11024 int 11025 lscf_archive(const char *filename, int flags) 11026 { 11027 FILE *f; 11028 xmlDocPtr doc; 11029 int result; 11030 11031 lscf_prep_hndl(); 11032 11033 if (filename != NULL) { 11034 errno = 0; 11035 f = fopen(filename, "wb"); 11036 if (f == NULL) { 11037 if (errno == 0) 11038 uu_die(gettext("Could not open \"%s\": no free " 11039 "stdio streams.\n"), filename); 11040 else 11041 uu_die(gettext("Could not open \"%s\""), 11042 filename); 11043 } 11044 } else 11045 f = stdout; 11046 11047 doc = xmlNewDoc((xmlChar *)"1.0"); 11048 if (doc == NULL) 11049 uu_die(gettext("Could not create XML document.\n")); 11050 11051 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11052 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11053 uu_die(emsg_create_xml); 11054 11055 (void) xmlAddSibling(doc->children, make_archive(flags)); 11056 11057 result = write_service_bundle(doc, f); 11058 11059 xmlFreeDoc(doc); 11060 11061 if (f != stdout) 11062 (void) fclose(f); 11063 11064 return (result); 11065 } 11066 11067 11068 /* 11069 * "Extract" a profile. 11070 */ 11071 int 11072 lscf_profile_extract(const char *filename) 11073 { 11074 FILE *f; 11075 xmlDocPtr doc; 11076 xmlNodePtr sb, snode, inode; 11077 scf_scope_t *scope; 11078 scf_service_t *svc; 11079 scf_instance_t *inst; 11080 scf_propertygroup_t *pg; 11081 scf_property_t *prop; 11082 scf_value_t *val; 11083 scf_iter_t *siter, *iiter; 11084 int r, s; 11085 char *namebuf; 11086 uint8_t b; 11087 int result; 11088 11089 lscf_prep_hndl(); 11090 11091 if (filename != NULL) { 11092 errno = 0; 11093 f = fopen(filename, "wb"); 11094 if (f == NULL) { 11095 if (errno == 0) 11096 uu_die(gettext("Could not open \"%s\": no " 11097 "free stdio streams.\n"), filename); 11098 else 11099 uu_die(gettext("Could not open \"%s\""), 11100 filename); 11101 } 11102 } else 11103 f = stdout; 11104 11105 doc = xmlNewDoc((xmlChar *)"1.0"); 11106 if (doc == NULL) 11107 uu_die(gettext("Could not create XML document.\n")); 11108 11109 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11110 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11111 uu_die(emsg_create_xml); 11112 11113 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 11114 if (sb == NULL) 11115 uu_die(emsg_create_xml); 11116 safe_setprop(sb, type_attr, "profile"); 11117 safe_setprop(sb, name_attr, "extract"); 11118 (void) xmlAddSibling(doc->children, sb); 11119 11120 if ((scope = scf_scope_create(g_hndl)) == NULL || 11121 (svc = scf_service_create(g_hndl)) == NULL || 11122 (inst = scf_instance_create(g_hndl)) == NULL || 11123 (pg = scf_pg_create(g_hndl)) == NULL || 11124 (prop = scf_property_create(g_hndl)) == NULL || 11125 (val = scf_value_create(g_hndl)) == NULL || 11126 (siter = scf_iter_create(g_hndl)) == NULL || 11127 (iiter = scf_iter_create(g_hndl)) == NULL) 11128 scfdie(); 11129 11130 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 11131 scfdie(); 11132 11133 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 11134 scfdie(); 11135 11136 namebuf = safe_malloc(max_scf_name_len + 1); 11137 11138 while ((r = scf_iter_next_service(siter, svc)) == 1) { 11139 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 11140 scfdie(); 11141 11142 snode = xmlNewNode(NULL, (xmlChar *)"service"); 11143 if (snode == NULL) 11144 uu_die(emsg_create_xml); 11145 11146 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 11147 0) 11148 scfdie(); 11149 11150 safe_setprop(snode, name_attr, namebuf); 11151 11152 safe_setprop(snode, type_attr, "service"); 11153 safe_setprop(snode, "version", "0"); 11154 11155 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 11156 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 11157 SCF_SUCCESS) { 11158 if (scf_error() != SCF_ERROR_NOT_FOUND) 11159 scfdie(); 11160 11161 if (g_verbose) { 11162 ssize_t len; 11163 char *fmri; 11164 11165 len = 11166 scf_instance_to_fmri(inst, NULL, 0); 11167 if (len < 0) 11168 scfdie(); 11169 11170 fmri = safe_malloc(len + 1); 11171 11172 if (scf_instance_to_fmri(inst, fmri, 11173 len + 1) < 0) 11174 scfdie(); 11175 11176 warn("Instance %s has no \"%s\" " 11177 "property group.\n", fmri, 11178 scf_pg_general); 11179 11180 free(fmri); 11181 } 11182 11183 continue; 11184 } 11185 11186 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 11187 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 11188 prop_get_val(prop, val) != 0) 11189 continue; 11190 11191 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 11192 NULL); 11193 if (inode == NULL) 11194 uu_die(emsg_create_xml); 11195 11196 if (scf_instance_get_name(inst, namebuf, 11197 max_scf_name_len + 1) < 0) 11198 scfdie(); 11199 11200 safe_setprop(inode, name_attr, namebuf); 11201 11202 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 11203 scfdie(); 11204 11205 safe_setprop(inode, enabled_attr, b ? true : false); 11206 } 11207 if (s < 0) 11208 scfdie(); 11209 11210 if (snode->children != NULL) 11211 (void) xmlAddChild(sb, snode); 11212 else 11213 xmlFreeNode(snode); 11214 } 11215 if (r < 0) 11216 scfdie(); 11217 11218 free(namebuf); 11219 11220 result = write_service_bundle(doc, f); 11221 11222 xmlFreeDoc(doc); 11223 11224 if (f != stdout) 11225 (void) fclose(f); 11226 11227 return (result); 11228 } 11229 11230 11231 /* 11232 * Entity manipulation commands 11233 */ 11234 11235 /* 11236 * Entity selection. If no entity is selected, then the current scope is in 11237 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 11238 * only cur_inst is NULL, and when an instance is selected, none are NULL. 11239 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 11240 * cur_inst will be non-NULL. 11241 */ 11242 11243 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 11244 static int 11245 select_inst(const char *name) 11246 { 11247 scf_instance_t *inst; 11248 scf_error_t err; 11249 11250 assert(cur_svc != NULL); 11251 11252 inst = scf_instance_create(g_hndl); 11253 if (inst == NULL) 11254 scfdie(); 11255 11256 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 11257 cur_inst = inst; 11258 return (0); 11259 } 11260 11261 err = scf_error(); 11262 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11263 scfdie(); 11264 11265 scf_instance_destroy(inst); 11266 return (1); 11267 } 11268 11269 /* Returns as above. */ 11270 static int 11271 select_svc(const char *name) 11272 { 11273 scf_service_t *svc; 11274 scf_error_t err; 11275 11276 assert(cur_scope != NULL); 11277 11278 svc = scf_service_create(g_hndl); 11279 if (svc == NULL) 11280 scfdie(); 11281 11282 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 11283 cur_svc = svc; 11284 return (0); 11285 } 11286 11287 err = scf_error(); 11288 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11289 scfdie(); 11290 11291 scf_service_destroy(svc); 11292 return (1); 11293 } 11294 11295 /* ARGSUSED */ 11296 static int 11297 select_callback(void *unused, scf_walkinfo_t *wip) 11298 { 11299 scf_instance_t *inst; 11300 scf_service_t *svc; 11301 scf_scope_t *scope; 11302 11303 if (wip->inst != NULL) { 11304 if ((scope = scf_scope_create(g_hndl)) == NULL || 11305 (svc = scf_service_create(g_hndl)) == NULL || 11306 (inst = scf_instance_create(g_hndl)) == NULL) 11307 scfdie(); 11308 11309 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11310 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11311 scfdie(); 11312 } else { 11313 assert(wip->svc != NULL); 11314 11315 if ((scope = scf_scope_create(g_hndl)) == NULL || 11316 (svc = scf_service_create(g_hndl)) == NULL) 11317 scfdie(); 11318 11319 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11320 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11321 scfdie(); 11322 11323 inst = NULL; 11324 } 11325 11326 /* Clear out the current selection */ 11327 assert(cur_scope != NULL); 11328 scf_scope_destroy(cur_scope); 11329 scf_service_destroy(cur_svc); 11330 scf_instance_destroy(cur_inst); 11331 11332 cur_scope = scope; 11333 cur_svc = svc; 11334 cur_inst = inst; 11335 11336 return (0); 11337 } 11338 11339 static int 11340 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 11341 { 11342 char **fmri = fmri_p; 11343 11344 *fmri = strdup(wip->fmri); 11345 if (*fmri == NULL) 11346 uu_die(gettext("Out of memory.\n")); 11347 11348 return (0); 11349 } 11350 11351 /* 11352 * validate [fmri] 11353 * Perform the validation of an FMRI instance. 11354 */ 11355 void 11356 lscf_validate_fmri(const char *fmri) 11357 { 11358 int ret = 0; 11359 size_t inst_sz; 11360 char *inst_fmri = NULL; 11361 scf_tmpl_errors_t *errs = NULL; 11362 char *snapbuf = NULL; 11363 11364 lscf_prep_hndl(); 11365 11366 if (fmri == NULL) { 11367 inst_sz = max_scf_fmri_len + 1; 11368 inst_fmri = safe_malloc(inst_sz); 11369 11370 if (cur_snap != NULL) { 11371 snapbuf = safe_malloc(max_scf_name_len + 1); 11372 if (scf_snapshot_get_name(cur_snap, snapbuf, 11373 max_scf_name_len + 1) < 0) 11374 scfdie(); 11375 } 11376 if (cur_inst == NULL) { 11377 semerr(gettext("No instance selected\n")); 11378 goto cleanup; 11379 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 11380 inst_sz) >= inst_sz) { 11381 /* sanity check. Should never get here */ 11382 uu_die(gettext("Unexpected error! file %s, line %d\n"), 11383 __FILE__, __LINE__); 11384 } 11385 } else { 11386 scf_error_t scf_err; 11387 int err = 0; 11388 11389 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 11390 validate_callback, &inst_fmri, &err, semerr)) != 0) { 11391 uu_warn("Failed to walk instances: %s\n", 11392 scf_strerror(scf_err)); 11393 goto cleanup; 11394 } 11395 if (err != 0) { 11396 /* error message displayed by scf_walk_fmri */ 11397 goto cleanup; 11398 } 11399 } 11400 11401 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 11402 SCF_TMPL_VALIDATE_FLAG_CURRENT); 11403 if (ret == -1) { 11404 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 11405 warn(gettext("Template data for %s is invalid. " 11406 "Consider reverting to a previous snapshot or " 11407 "restoring original configuration.\n"), inst_fmri); 11408 } else { 11409 uu_warn("%s: %s\n", 11410 gettext("Error validating the instance"), 11411 scf_strerror(scf_error())); 11412 } 11413 } else if (ret == 1 && errs != NULL) { 11414 scf_tmpl_error_t *err = NULL; 11415 char *msg; 11416 size_t len = 256; /* initial error buffer size */ 11417 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 11418 SCF_TMPL_STRERROR_HUMAN : 0; 11419 11420 msg = safe_malloc(len); 11421 11422 while ((err = scf_tmpl_next_error(errs)) != NULL) { 11423 int ret; 11424 11425 if ((ret = scf_tmpl_strerror(err, msg, len, 11426 flag)) >= len) { 11427 len = ret + 1; 11428 msg = realloc(msg, len); 11429 if (msg == NULL) 11430 uu_die(gettext( 11431 "Out of memory.\n")); 11432 (void) scf_tmpl_strerror(err, msg, len, 11433 flag); 11434 } 11435 (void) fprintf(stderr, "%s\n", msg); 11436 } 11437 if (msg != NULL) 11438 free(msg); 11439 } 11440 if (errs != NULL) 11441 scf_tmpl_errors_destroy(errs); 11442 11443 cleanup: 11444 free(inst_fmri); 11445 free(snapbuf); 11446 } 11447 11448 static void 11449 lscf_validate_file(const char *filename) 11450 { 11451 tmpl_errors_t *errs; 11452 11453 bundle_t *b = internal_bundle_new(); 11454 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 11455 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 11456 tmpl_errors_print(stderr, errs, ""); 11457 semerr(gettext("Validation failed.\n")); 11458 } 11459 tmpl_errors_destroy(errs); 11460 } 11461 (void) internal_bundle_free(b); 11462 } 11463 11464 /* 11465 * validate [fmri|file] 11466 */ 11467 void 11468 lscf_validate(const char *arg) 11469 { 11470 const char *str; 11471 11472 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 11473 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 11474 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 11475 lscf_validate_file(str); 11476 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 11477 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 11478 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 11479 lscf_validate_fmri(str); 11480 } else if (access(arg, R_OK | F_OK) == 0) { 11481 lscf_validate_file(arg); 11482 } else { 11483 lscf_validate_fmri(arg); 11484 } 11485 } 11486 11487 void 11488 lscf_select(const char *fmri) 11489 { 11490 int ret, err; 11491 11492 lscf_prep_hndl(); 11493 11494 if (cur_snap != NULL) { 11495 struct snaplevel *elt; 11496 char *buf; 11497 11498 /* Error unless name is that of the next level. */ 11499 elt = uu_list_next(cur_levels, cur_elt); 11500 if (elt == NULL) { 11501 semerr(gettext("No children.\n")); 11502 return; 11503 } 11504 11505 buf = safe_malloc(max_scf_name_len + 1); 11506 11507 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11508 max_scf_name_len + 1) < 0) 11509 scfdie(); 11510 11511 if (strcmp(buf, fmri) != 0) { 11512 semerr(gettext("No such child.\n")); 11513 free(buf); 11514 return; 11515 } 11516 11517 free(buf); 11518 11519 cur_elt = elt; 11520 cur_level = elt->sl; 11521 return; 11522 } 11523 11524 /* 11525 * Special case for 'svc:', which takes the user to the scope level. 11526 */ 11527 if (strcmp(fmri, "svc:") == 0) { 11528 scf_instance_destroy(cur_inst); 11529 scf_service_destroy(cur_svc); 11530 cur_inst = NULL; 11531 cur_svc = NULL; 11532 return; 11533 } 11534 11535 /* 11536 * Special case for ':properties'. This appears as part of 'list' but 11537 * can't be selected. Give a more helpful error message in this case. 11538 */ 11539 if (strcmp(fmri, ":properties") == 0) { 11540 semerr(gettext(":properties is not an entity. Try 'listprop' " 11541 "to list properties.\n")); 11542 return; 11543 } 11544 11545 /* 11546 * First try the argument as relative to the current selection. 11547 */ 11548 if (cur_inst != NULL) { 11549 /* EMPTY */; 11550 } else if (cur_svc != NULL) { 11551 if (select_inst(fmri) != 1) 11552 return; 11553 } else { 11554 if (select_svc(fmri) != 1) 11555 return; 11556 } 11557 11558 err = 0; 11559 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11560 select_callback, NULL, &err, semerr)) != 0) { 11561 semerr(gettext("Failed to walk instances: %s\n"), 11562 scf_strerror(ret)); 11563 } 11564 } 11565 11566 void 11567 lscf_unselect(void) 11568 { 11569 lscf_prep_hndl(); 11570 11571 if (cur_snap != NULL) { 11572 struct snaplevel *elt; 11573 11574 elt = uu_list_prev(cur_levels, cur_elt); 11575 if (elt == NULL) { 11576 semerr(gettext("No parent levels.\n")); 11577 } else { 11578 cur_elt = elt; 11579 cur_level = elt->sl; 11580 } 11581 } else if (cur_inst != NULL) { 11582 scf_instance_destroy(cur_inst); 11583 cur_inst = NULL; 11584 } else if (cur_svc != NULL) { 11585 scf_service_destroy(cur_svc); 11586 cur_svc = NULL; 11587 } else { 11588 semerr(gettext("Cannot unselect at scope level.\n")); 11589 } 11590 } 11591 11592 /* 11593 * Return the FMRI of the current selection, for the prompt. 11594 */ 11595 void 11596 lscf_get_selection_str(char *buf, size_t bufsz) 11597 { 11598 char *cp; 11599 ssize_t fmrilen, szret; 11600 boolean_t deleted = B_FALSE; 11601 11602 if (g_hndl == NULL) { 11603 (void) strlcpy(buf, "svc:", bufsz); 11604 return; 11605 } 11606 11607 if (cur_level != NULL) { 11608 assert(cur_snap != NULL); 11609 11610 /* [ snapshot ] FMRI [: instance ] */ 11611 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11612 + 2 + max_scf_name_len + 1 + 1); 11613 11614 buf[0] = '['; 11615 11616 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11617 max_scf_name_len + 1); 11618 if (szret < 0) { 11619 if (scf_error() != SCF_ERROR_DELETED) 11620 scfdie(); 11621 11622 goto snap_deleted; 11623 } 11624 11625 (void) strcat(buf, "]svc:/"); 11626 11627 cp = strchr(buf, '\0'); 11628 11629 szret = scf_snaplevel_get_service_name(cur_level, cp, 11630 max_scf_name_len + 1); 11631 if (szret < 0) { 11632 if (scf_error() != SCF_ERROR_DELETED) 11633 scfdie(); 11634 11635 goto snap_deleted; 11636 } 11637 11638 cp = strchr(cp, '\0'); 11639 11640 if (snaplevel_is_instance(cur_level)) { 11641 *cp++ = ':'; 11642 11643 if (scf_snaplevel_get_instance_name(cur_level, cp, 11644 max_scf_name_len + 1) < 0) { 11645 if (scf_error() != SCF_ERROR_DELETED) 11646 scfdie(); 11647 11648 goto snap_deleted; 11649 } 11650 } else { 11651 *cp++ = '['; 11652 *cp++ = ':'; 11653 11654 if (scf_instance_get_name(cur_inst, cp, 11655 max_scf_name_len + 1) < 0) { 11656 if (scf_error() != SCF_ERROR_DELETED) 11657 scfdie(); 11658 11659 goto snap_deleted; 11660 } 11661 11662 (void) strcat(buf, "]"); 11663 } 11664 11665 return; 11666 11667 snap_deleted: 11668 deleted = B_TRUE; 11669 free(buf); 11670 unselect_cursnap(); 11671 } 11672 11673 assert(cur_snap == NULL); 11674 11675 if (cur_inst != NULL) { 11676 assert(cur_svc != NULL); 11677 assert(cur_scope != NULL); 11678 11679 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11680 if (fmrilen >= 0) { 11681 assert(fmrilen < bufsz); 11682 if (deleted) 11683 warn(emsg_deleted); 11684 return; 11685 } 11686 11687 if (scf_error() != SCF_ERROR_DELETED) 11688 scfdie(); 11689 11690 deleted = B_TRUE; 11691 11692 scf_instance_destroy(cur_inst); 11693 cur_inst = NULL; 11694 } 11695 11696 if (cur_svc != NULL) { 11697 assert(cur_scope != NULL); 11698 11699 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11700 if (szret >= 0) { 11701 assert(szret < bufsz); 11702 if (deleted) 11703 warn(emsg_deleted); 11704 return; 11705 } 11706 11707 if (scf_error() != SCF_ERROR_DELETED) 11708 scfdie(); 11709 11710 deleted = B_TRUE; 11711 scf_service_destroy(cur_svc); 11712 cur_svc = NULL; 11713 } 11714 11715 assert(cur_scope != NULL); 11716 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11717 11718 if (fmrilen < 0) 11719 scfdie(); 11720 11721 assert(fmrilen < bufsz); 11722 if (deleted) 11723 warn(emsg_deleted); 11724 } 11725 11726 /* 11727 * Entity listing. Entities and colon namespaces (e.g., :properties and 11728 * :statistics) are listed for the current selection. 11729 */ 11730 void 11731 lscf_list(const char *pattern) 11732 { 11733 scf_iter_t *iter; 11734 char *buf; 11735 int ret; 11736 11737 lscf_prep_hndl(); 11738 11739 if (cur_level != NULL) { 11740 struct snaplevel *elt; 11741 11742 (void) fputs(COLON_NAMESPACES, stdout); 11743 11744 elt = uu_list_next(cur_levels, cur_elt); 11745 if (elt == NULL) 11746 return; 11747 11748 /* 11749 * For now, we know that the next level is an instance. But 11750 * if we ever have multiple scopes, this could be complicated. 11751 */ 11752 buf = safe_malloc(max_scf_name_len + 1); 11753 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11754 max_scf_name_len + 1) >= 0) { 11755 (void) puts(buf); 11756 } else { 11757 if (scf_error() != SCF_ERROR_DELETED) 11758 scfdie(); 11759 } 11760 11761 free(buf); 11762 11763 return; 11764 } 11765 11766 if (cur_inst != NULL) { 11767 (void) fputs(COLON_NAMESPACES, stdout); 11768 return; 11769 } 11770 11771 iter = scf_iter_create(g_hndl); 11772 if (iter == NULL) 11773 scfdie(); 11774 11775 buf = safe_malloc(max_scf_name_len + 1); 11776 11777 if (cur_svc != NULL) { 11778 /* List the instances in this service. */ 11779 scf_instance_t *inst; 11780 11781 inst = scf_instance_create(g_hndl); 11782 if (inst == NULL) 11783 scfdie(); 11784 11785 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11786 safe_printf(COLON_NAMESPACES); 11787 11788 for (;;) { 11789 ret = scf_iter_next_instance(iter, inst); 11790 if (ret == 0) 11791 break; 11792 if (ret != 1) { 11793 if (scf_error() != SCF_ERROR_DELETED) 11794 scfdie(); 11795 11796 break; 11797 } 11798 11799 if (scf_instance_get_name(inst, buf, 11800 max_scf_name_len + 1) >= 0) { 11801 if (pattern == NULL || 11802 fnmatch(pattern, buf, 0) == 0) 11803 (void) puts(buf); 11804 } else { 11805 if (scf_error() != SCF_ERROR_DELETED) 11806 scfdie(); 11807 } 11808 } 11809 } else { 11810 if (scf_error() != SCF_ERROR_DELETED) 11811 scfdie(); 11812 } 11813 11814 scf_instance_destroy(inst); 11815 } else { 11816 /* List the services in this scope. */ 11817 scf_service_t *svc; 11818 11819 assert(cur_scope != NULL); 11820 11821 svc = scf_service_create(g_hndl); 11822 if (svc == NULL) 11823 scfdie(); 11824 11825 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11826 scfdie(); 11827 11828 for (;;) { 11829 ret = scf_iter_next_service(iter, svc); 11830 if (ret == 0) 11831 break; 11832 if (ret != 1) 11833 scfdie(); 11834 11835 if (scf_service_get_name(svc, buf, 11836 max_scf_name_len + 1) >= 0) { 11837 if (pattern == NULL || 11838 fnmatch(pattern, buf, 0) == 0) 11839 safe_printf("%s\n", buf); 11840 } else { 11841 if (scf_error() != SCF_ERROR_DELETED) 11842 scfdie(); 11843 } 11844 } 11845 11846 scf_service_destroy(svc); 11847 } 11848 11849 free(buf); 11850 scf_iter_destroy(iter); 11851 } 11852 11853 /* 11854 * Entity addition. Creates an empty entity in the current selection. 11855 */ 11856 void 11857 lscf_add(const char *name) 11858 { 11859 lscf_prep_hndl(); 11860 11861 if (cur_snap != NULL) { 11862 semerr(emsg_cant_modify_snapshots); 11863 } else if (cur_inst != NULL) { 11864 semerr(gettext("Cannot add entities to an instance.\n")); 11865 } else if (cur_svc != NULL) { 11866 11867 if (scf_service_add_instance(cur_svc, name, NULL) != 11868 SCF_SUCCESS) { 11869 switch (scf_error()) { 11870 case SCF_ERROR_INVALID_ARGUMENT: 11871 semerr(gettext("Invalid name.\n")); 11872 break; 11873 11874 case SCF_ERROR_EXISTS: 11875 semerr(gettext("Instance already exists.\n")); 11876 break; 11877 11878 case SCF_ERROR_PERMISSION_DENIED: 11879 semerr(emsg_permission_denied); 11880 break; 11881 11882 default: 11883 scfdie(); 11884 } 11885 } 11886 } else { 11887 assert(cur_scope != NULL); 11888 11889 if (scf_scope_add_service(cur_scope, name, NULL) != 11890 SCF_SUCCESS) { 11891 switch (scf_error()) { 11892 case SCF_ERROR_INVALID_ARGUMENT: 11893 semerr(gettext("Invalid name.\n")); 11894 break; 11895 11896 case SCF_ERROR_EXISTS: 11897 semerr(gettext("Service already exists.\n")); 11898 break; 11899 11900 case SCF_ERROR_PERMISSION_DENIED: 11901 semerr(emsg_permission_denied); 11902 break; 11903 11904 case SCF_ERROR_BACKEND_READONLY: 11905 semerr(emsg_read_only); 11906 break; 11907 11908 default: 11909 scfdie(); 11910 } 11911 } 11912 } 11913 } 11914 11915 /* return 1 if the entity has no persistent pgs, else return 0 */ 11916 static int 11917 entity_has_no_pgs(void *ent, int isservice) 11918 { 11919 scf_iter_t *iter = NULL; 11920 scf_propertygroup_t *pg = NULL; 11921 uint32_t flags; 11922 int err; 11923 int ret = 1; 11924 11925 if ((iter = scf_iter_create(g_hndl)) == NULL || 11926 (pg = scf_pg_create(g_hndl)) == NULL) 11927 scfdie(); 11928 11929 if (isservice) { 11930 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11931 scfdie(); 11932 } else { 11933 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11934 scfdie(); 11935 } 11936 11937 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11938 if (scf_pg_get_flags(pg, &flags) != 0) 11939 scfdie(); 11940 11941 /* skip nonpersistent pgs */ 11942 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11943 continue; 11944 11945 ret = 0; 11946 break; 11947 } 11948 11949 if (err == -1) 11950 scfdie(); 11951 11952 scf_pg_destroy(pg); 11953 scf_iter_destroy(iter); 11954 11955 return (ret); 11956 } 11957 11958 /* return 1 if the service has no instances, else return 0 */ 11959 static int 11960 svc_has_no_insts(scf_service_t *svc) 11961 { 11962 scf_instance_t *inst; 11963 scf_iter_t *iter; 11964 int r; 11965 int ret = 1; 11966 11967 if ((inst = scf_instance_create(g_hndl)) == NULL || 11968 (iter = scf_iter_create(g_hndl)) == NULL) 11969 scfdie(); 11970 11971 if (scf_iter_service_instances(iter, svc) != 0) 11972 scfdie(); 11973 11974 r = scf_iter_next_instance(iter, inst); 11975 if (r == 1) { 11976 ret = 0; 11977 } else if (r == 0) { 11978 ret = 1; 11979 } else if (r == -1) { 11980 scfdie(); 11981 } else { 11982 bad_error("scf_iter_next_instance", r); 11983 } 11984 11985 scf_iter_destroy(iter); 11986 scf_instance_destroy(inst); 11987 11988 return (ret); 11989 } 11990 11991 /* 11992 * Entity deletion. 11993 */ 11994 11995 /* 11996 * Delete the property group <fmri>/:properties/<name>. Returns 11997 * SCF_ERROR_NONE on success (or if the entity is not found), 11998 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 11999 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 12000 * denied. 12001 */ 12002 static scf_error_t 12003 delete_dependency_pg(const char *fmri, const char *name) 12004 { 12005 void *entity = NULL; 12006 int isservice; 12007 scf_propertygroup_t *pg = NULL; 12008 scf_error_t result; 12009 char *pgty; 12010 scf_service_t *svc = NULL; 12011 scf_instance_t *inst = NULL; 12012 scf_iter_t *iter = NULL; 12013 char *name_buf = NULL; 12014 12015 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 12016 switch (result) { 12017 case SCF_ERROR_NONE: 12018 break; 12019 12020 case SCF_ERROR_NO_MEMORY: 12021 uu_die(gettext("Out of memory.\n")); 12022 /* NOTREACHED */ 12023 12024 case SCF_ERROR_INVALID_ARGUMENT: 12025 case SCF_ERROR_CONSTRAINT_VIOLATED: 12026 return (SCF_ERROR_INVALID_ARGUMENT); 12027 12028 case SCF_ERROR_NOT_FOUND: 12029 result = SCF_ERROR_NONE; 12030 goto out; 12031 12032 default: 12033 bad_error("fmri_to_entity", result); 12034 } 12035 12036 pg = scf_pg_create(g_hndl); 12037 if (pg == NULL) 12038 scfdie(); 12039 12040 if (entity_get_pg(entity, isservice, name, pg) != 0) { 12041 if (scf_error() != SCF_ERROR_NOT_FOUND) 12042 scfdie(); 12043 12044 result = SCF_ERROR_NONE; 12045 goto out; 12046 } 12047 12048 pgty = safe_malloc(max_scf_pg_type_len + 1); 12049 12050 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12051 scfdie(); 12052 12053 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 12054 result = SCF_ERROR_TYPE_MISMATCH; 12055 free(pgty); 12056 goto out; 12057 } 12058 12059 free(pgty); 12060 12061 if (scf_pg_delete(pg) != 0) { 12062 result = scf_error(); 12063 if (result != SCF_ERROR_PERMISSION_DENIED) 12064 scfdie(); 12065 goto out; 12066 } 12067 12068 /* 12069 * We have to handle the case where we've just deleted the last 12070 * property group of a "dummy" entity (instance or service). 12071 * A "dummy" entity is an entity only present to hold an 12072 * external dependency. 12073 * So, in the case we deleted the last property group then we 12074 * can also delete the entity. If the entity is an instance then 12075 * we must verify if this was the last instance for the service 12076 * and if it is, we can also delete the service if it doesn't 12077 * have any property group either. 12078 */ 12079 12080 result = SCF_ERROR_NONE; 12081 12082 if (isservice) { 12083 svc = (scf_service_t *)entity; 12084 12085 if ((inst = scf_instance_create(g_hndl)) == NULL || 12086 (iter = scf_iter_create(g_hndl)) == NULL) 12087 scfdie(); 12088 12089 name_buf = safe_malloc(max_scf_name_len + 1); 12090 } else { 12091 inst = (scf_instance_t *)entity; 12092 } 12093 12094 /* 12095 * If the entity is an instance and we've just deleted its last 12096 * property group then we should delete it. 12097 */ 12098 if (!isservice && entity_has_no_pgs(entity, isservice)) { 12099 /* find the service before deleting the inst. - needed later */ 12100 if ((svc = scf_service_create(g_hndl)) == NULL) 12101 scfdie(); 12102 12103 if (scf_instance_get_parent(inst, svc) != 0) 12104 scfdie(); 12105 12106 /* delete the instance */ 12107 if (scf_instance_delete(inst) != 0) { 12108 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12109 scfdie(); 12110 12111 result = SCF_ERROR_PERMISSION_DENIED; 12112 goto out; 12113 } 12114 /* no need to refresh the instance */ 12115 inst = NULL; 12116 } 12117 12118 /* 12119 * If the service has no more instances and pgs or we just deleted the 12120 * last instance and the service doesn't have anymore propery groups 12121 * then the service should be deleted. 12122 */ 12123 if (svc != NULL && 12124 svc_has_no_insts(svc) && 12125 entity_has_no_pgs((void *)svc, 1)) { 12126 if (scf_service_delete(svc) == 0) { 12127 if (isservice) { 12128 /* no need to refresh the service */ 12129 svc = NULL; 12130 } 12131 12132 goto out; 12133 } 12134 12135 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12136 scfdie(); 12137 12138 result = SCF_ERROR_PERMISSION_DENIED; 12139 } 12140 12141 /* if the entity has not been deleted, refresh it */ 12142 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 12143 (void) refresh_entity(isservice, entity, fmri, inst, iter, 12144 name_buf); 12145 } 12146 12147 out: 12148 if (isservice && (inst != NULL && iter != NULL)) { 12149 free(name_buf); 12150 scf_iter_destroy(iter); 12151 scf_instance_destroy(inst); 12152 } 12153 12154 if (!isservice && svc != NULL) { 12155 scf_service_destroy(svc); 12156 } 12157 12158 scf_pg_destroy(pg); 12159 if (entity != NULL) 12160 entity_destroy(entity, isservice); 12161 12162 return (result); 12163 } 12164 12165 static int 12166 delete_dependents(scf_propertygroup_t *pg) 12167 { 12168 char *pgty, *name, *fmri; 12169 scf_property_t *prop; 12170 scf_value_t *val; 12171 scf_iter_t *iter; 12172 int r; 12173 scf_error_t err; 12174 12175 /* Verify that the pg has the correct type. */ 12176 pgty = safe_malloc(max_scf_pg_type_len + 1); 12177 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12178 scfdie(); 12179 12180 if (strcmp(pgty, scf_group_framework) != 0) { 12181 if (g_verbose) { 12182 fmri = safe_malloc(max_scf_fmri_len + 1); 12183 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 12184 scfdie(); 12185 12186 warn(gettext("Property group %s is not of expected " 12187 "type %s.\n"), fmri, scf_group_framework); 12188 12189 free(fmri); 12190 } 12191 12192 free(pgty); 12193 return (-1); 12194 } 12195 12196 free(pgty); 12197 12198 /* map delete_dependency_pg onto the properties. */ 12199 if ((prop = scf_property_create(g_hndl)) == NULL || 12200 (val = scf_value_create(g_hndl)) == NULL || 12201 (iter = scf_iter_create(g_hndl)) == NULL) 12202 scfdie(); 12203 12204 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 12205 scfdie(); 12206 12207 name = safe_malloc(max_scf_name_len + 1); 12208 fmri = safe_malloc(max_scf_fmri_len + 2); 12209 12210 while ((r = scf_iter_next_property(iter, prop)) == 1) { 12211 scf_type_t ty; 12212 12213 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 12214 scfdie(); 12215 12216 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 12217 scfdie(); 12218 12219 if ((ty != SCF_TYPE_ASTRING && 12220 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 12221 prop_get_val(prop, val) != 0) 12222 continue; 12223 12224 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 12225 scfdie(); 12226 12227 err = delete_dependency_pg(fmri, name); 12228 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 12229 if (scf_property_to_fmri(prop, fmri, 12230 max_scf_fmri_len + 2) < 0) 12231 scfdie(); 12232 12233 warn(gettext("Value of %s is not a valid FMRI.\n"), 12234 fmri); 12235 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 12236 warn(gettext("Property group \"%s\" of entity \"%s\" " 12237 "does not have dependency type.\n"), name, fmri); 12238 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 12239 warn(gettext("Could not delete property group \"%s\" " 12240 "of entity \"%s\" (permission denied).\n"), name, 12241 fmri); 12242 } 12243 } 12244 if (r == -1) 12245 scfdie(); 12246 12247 scf_value_destroy(val); 12248 scf_property_destroy(prop); 12249 12250 return (0); 12251 } 12252 12253 /* 12254 * Returns 1 if the instance may be running, and 0 otherwise. 12255 */ 12256 static int 12257 inst_is_running(scf_instance_t *inst) 12258 { 12259 scf_propertygroup_t *pg; 12260 scf_property_t *prop; 12261 scf_value_t *val; 12262 char buf[MAX_SCF_STATE_STRING_SZ]; 12263 int ret = 0; 12264 ssize_t szret; 12265 12266 if ((pg = scf_pg_create(g_hndl)) == NULL || 12267 (prop = scf_property_create(g_hndl)) == NULL || 12268 (val = scf_value_create(g_hndl)) == NULL) 12269 scfdie(); 12270 12271 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 12272 if (scf_error() != SCF_ERROR_NOT_FOUND) 12273 scfdie(); 12274 goto out; 12275 } 12276 12277 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 12278 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 12279 prop_get_val(prop, val) != 0) 12280 goto out; 12281 12282 szret = scf_value_get_astring(val, buf, sizeof (buf)); 12283 assert(szret >= 0); 12284 12285 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 12286 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 12287 12288 out: 12289 scf_value_destroy(val); 12290 scf_property_destroy(prop); 12291 scf_pg_destroy(pg); 12292 return (ret); 12293 } 12294 12295 static uint8_t 12296 pg_is_external_dependency(scf_propertygroup_t *pg) 12297 { 12298 char *type; 12299 scf_value_t *val; 12300 scf_property_t *prop; 12301 uint8_t b = B_FALSE; 12302 12303 type = safe_malloc(max_scf_pg_type_len + 1); 12304 12305 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 12306 scfdie(); 12307 12308 if ((prop = scf_property_create(g_hndl)) == NULL || 12309 (val = scf_value_create(g_hndl)) == NULL) 12310 scfdie(); 12311 12312 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 12313 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 12314 if (scf_property_get_value(prop, val) != 0) 12315 scfdie(); 12316 if (scf_value_get_boolean(val, &b) != 0) 12317 scfdie(); 12318 } 12319 } 12320 12321 free(type); 12322 (void) scf_value_destroy(val); 12323 (void) scf_property_destroy(prop); 12324 12325 return (b); 12326 } 12327 12328 #define DELETE_FAILURE -1 12329 #define DELETE_SUCCESS_NOEXTDEPS 0 12330 #define DELETE_SUCCESS_EXTDEPS 1 12331 12332 /* 12333 * lscf_instance_delete() deletes an instance. Before calling 12334 * scf_instance_delete(), though, we make sure the instance isn't 12335 * running and delete dependencies in other entities which the instance 12336 * declared as "dependents". If there are dependencies which were 12337 * created for other entities, then instead of deleting the instance we 12338 * make it "empty" by deleting all other property groups and all 12339 * snapshots. 12340 * 12341 * lscf_instance_delete() verifies that there is no external dependency pgs 12342 * before suppressing the instance. If there is, then we must not remove them 12343 * now in case the instance is re-created otherwise the dependencies would be 12344 * lost. The external dependency pgs will be removed if the dependencies are 12345 * removed. 12346 * 12347 * Returns: 12348 * DELETE_FAILURE on failure 12349 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12350 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12351 */ 12352 static int 12353 lscf_instance_delete(scf_instance_t *inst, int force) 12354 { 12355 scf_propertygroup_t *pg; 12356 scf_snapshot_t *snap; 12357 scf_iter_t *iter; 12358 int err; 12359 int external = 0; 12360 12361 /* If we're not forcing and the instance is running, refuse. */ 12362 if (!force && inst_is_running(inst)) { 12363 char *fmri; 12364 12365 fmri = safe_malloc(max_scf_fmri_len + 1); 12366 12367 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 12368 scfdie(); 12369 12370 semerr(gettext("Instance %s may be running. " 12371 "Use delete -f if it is not.\n"), fmri); 12372 12373 free(fmri); 12374 return (DELETE_FAILURE); 12375 } 12376 12377 pg = scf_pg_create(g_hndl); 12378 if (pg == NULL) 12379 scfdie(); 12380 12381 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 12382 (void) delete_dependents(pg); 12383 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12384 scfdie(); 12385 12386 scf_pg_destroy(pg); 12387 12388 /* 12389 * If the instance has some external dependencies then we must 12390 * keep them in case the instance is reimported otherwise the 12391 * dependencies would be lost on reimport. 12392 */ 12393 if ((iter = scf_iter_create(g_hndl)) == NULL || 12394 (pg = scf_pg_create(g_hndl)) == NULL) 12395 scfdie(); 12396 12397 if (scf_iter_instance_pgs(iter, inst) < 0) 12398 scfdie(); 12399 12400 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 12401 if (pg_is_external_dependency(pg)) { 12402 external = 1; 12403 continue; 12404 } 12405 12406 if (scf_pg_delete(pg) != 0) { 12407 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12408 scfdie(); 12409 else { 12410 semerr(emsg_permission_denied); 12411 12412 (void) scf_iter_destroy(iter); 12413 (void) scf_pg_destroy(pg); 12414 return (DELETE_FAILURE); 12415 } 12416 } 12417 } 12418 12419 if (err == -1) 12420 scfdie(); 12421 12422 (void) scf_iter_destroy(iter); 12423 (void) scf_pg_destroy(pg); 12424 12425 if (external) { 12426 /* 12427 * All the pgs have been deleted for the instance except 12428 * the ones holding the external dependencies. 12429 * For the job to be complete, we must also delete the 12430 * snapshots associated with the instance. 12431 */ 12432 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 12433 NULL) 12434 scfdie(); 12435 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 12436 scfdie(); 12437 12438 if (scf_iter_instance_snapshots(iter, inst) == -1) 12439 scfdie(); 12440 12441 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 12442 if (_scf_snapshot_delete(snap) != 0) { 12443 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12444 scfdie(); 12445 12446 semerr(emsg_permission_denied); 12447 12448 (void) scf_iter_destroy(iter); 12449 (void) scf_snapshot_destroy(snap); 12450 return (DELETE_FAILURE); 12451 } 12452 } 12453 12454 if (err == -1) 12455 scfdie(); 12456 12457 (void) scf_iter_destroy(iter); 12458 (void) scf_snapshot_destroy(snap); 12459 return (DELETE_SUCCESS_EXTDEPS); 12460 } 12461 12462 if (scf_instance_delete(inst) != 0) { 12463 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12464 scfdie(); 12465 12466 semerr(emsg_permission_denied); 12467 12468 return (DELETE_FAILURE); 12469 } 12470 12471 return (DELETE_SUCCESS_NOEXTDEPS); 12472 } 12473 12474 /* 12475 * lscf_service_delete() deletes a service. Before calling 12476 * scf_service_delete(), though, we call lscf_instance_delete() for 12477 * each of the instances and delete dependencies in other entities 12478 * which were created as "dependents" of this service. If there are 12479 * dependencies which were created for other entities, then we delete 12480 * all other property groups in the service and leave it as "empty". 12481 * 12482 * lscf_service_delete() verifies that there is no external dependency 12483 * pgs at the instance & service level before suppressing the service. 12484 * If there is, then we must not remove them now in case the service 12485 * is re-imported otherwise the dependencies would be lost. The external 12486 * dependency pgs will be removed if the dependencies are removed. 12487 * 12488 * Returns: 12489 * DELETE_FAILURE on failure 12490 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12491 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12492 */ 12493 static int 12494 lscf_service_delete(scf_service_t *svc, int force) 12495 { 12496 int r; 12497 scf_instance_t *inst; 12498 scf_propertygroup_t *pg; 12499 scf_iter_t *iter; 12500 int ret; 12501 int external = 0; 12502 12503 if ((inst = scf_instance_create(g_hndl)) == NULL || 12504 (pg = scf_pg_create(g_hndl)) == NULL || 12505 (iter = scf_iter_create(g_hndl)) == NULL) 12506 scfdie(); 12507 12508 if (scf_iter_service_instances(iter, svc) != 0) 12509 scfdie(); 12510 12511 for (r = scf_iter_next_instance(iter, inst); 12512 r == 1; 12513 r = scf_iter_next_instance(iter, inst)) { 12514 12515 ret = lscf_instance_delete(inst, force); 12516 if (ret == DELETE_FAILURE) { 12517 scf_iter_destroy(iter); 12518 scf_pg_destroy(pg); 12519 scf_instance_destroy(inst); 12520 return (DELETE_FAILURE); 12521 } 12522 12523 /* 12524 * Record the fact that there is some external dependencies 12525 * at the instance level. 12526 */ 12527 if (ret == DELETE_SUCCESS_EXTDEPS) 12528 external |= 1; 12529 } 12530 12531 if (r != 0) 12532 scfdie(); 12533 12534 /* Delete dependency property groups in dependent services. */ 12535 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12536 (void) delete_dependents(pg); 12537 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12538 scfdie(); 12539 12540 scf_iter_destroy(iter); 12541 scf_pg_destroy(pg); 12542 scf_instance_destroy(inst); 12543 12544 /* 12545 * If the service has some external dependencies then we don't 12546 * want to remove them in case the service is re-imported. 12547 */ 12548 if ((pg = scf_pg_create(g_hndl)) == NULL || 12549 (iter = scf_iter_create(g_hndl)) == NULL) 12550 scfdie(); 12551 12552 if (scf_iter_service_pgs(iter, svc) < 0) 12553 scfdie(); 12554 12555 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12556 if (pg_is_external_dependency(pg)) { 12557 external |= 2; 12558 continue; 12559 } 12560 12561 if (scf_pg_delete(pg) != 0) { 12562 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12563 scfdie(); 12564 else { 12565 semerr(emsg_permission_denied); 12566 12567 (void) scf_iter_destroy(iter); 12568 (void) scf_pg_destroy(pg); 12569 return (DELETE_FAILURE); 12570 } 12571 } 12572 } 12573 12574 if (r == -1) 12575 scfdie(); 12576 12577 (void) scf_iter_destroy(iter); 12578 (void) scf_pg_destroy(pg); 12579 12580 if (external != 0) 12581 return (DELETE_SUCCESS_EXTDEPS); 12582 12583 if (scf_service_delete(svc) == 0) 12584 return (DELETE_SUCCESS_NOEXTDEPS); 12585 12586 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12587 scfdie(); 12588 12589 semerr(emsg_permission_denied); 12590 return (DELETE_FAILURE); 12591 } 12592 12593 static int 12594 delete_callback(void *data, scf_walkinfo_t *wip) 12595 { 12596 int force = (int)data; 12597 12598 if (wip->inst != NULL) 12599 (void) lscf_instance_delete(wip->inst, force); 12600 else 12601 (void) lscf_service_delete(wip->svc, force); 12602 12603 return (0); 12604 } 12605 12606 void 12607 lscf_delete(const char *fmri, int force) 12608 { 12609 scf_service_t *svc; 12610 scf_instance_t *inst; 12611 int ret; 12612 12613 lscf_prep_hndl(); 12614 12615 if (cur_snap != NULL) { 12616 if (!snaplevel_is_instance(cur_level)) { 12617 char *buf; 12618 12619 buf = safe_malloc(max_scf_name_len + 1); 12620 if (scf_instance_get_name(cur_inst, buf, 12621 max_scf_name_len + 1) >= 0) { 12622 if (strcmp(buf, fmri) == 0) { 12623 semerr(emsg_cant_modify_snapshots); 12624 free(buf); 12625 return; 12626 } 12627 } else if (scf_error() != SCF_ERROR_DELETED) { 12628 scfdie(); 12629 } 12630 free(buf); 12631 } 12632 } else if (cur_inst != NULL) { 12633 /* EMPTY */; 12634 } else if (cur_svc != NULL) { 12635 inst = scf_instance_create(g_hndl); 12636 if (inst == NULL) 12637 scfdie(); 12638 12639 if (scf_service_get_instance(cur_svc, fmri, inst) == 12640 SCF_SUCCESS) { 12641 (void) lscf_instance_delete(inst, force); 12642 scf_instance_destroy(inst); 12643 return; 12644 } 12645 12646 if (scf_error() != SCF_ERROR_NOT_FOUND && 12647 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12648 scfdie(); 12649 12650 scf_instance_destroy(inst); 12651 } else { 12652 assert(cur_scope != NULL); 12653 12654 svc = scf_service_create(g_hndl); 12655 if (svc == NULL) 12656 scfdie(); 12657 12658 if (scf_scope_get_service(cur_scope, fmri, svc) == 12659 SCF_SUCCESS) { 12660 (void) lscf_service_delete(svc, force); 12661 scf_service_destroy(svc); 12662 return; 12663 } 12664 12665 if (scf_error() != SCF_ERROR_NOT_FOUND && 12666 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12667 scfdie(); 12668 12669 scf_service_destroy(svc); 12670 } 12671 12672 /* 12673 * Match FMRI to entity. 12674 */ 12675 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12676 delete_callback, (void *)force, NULL, semerr)) != 0) { 12677 semerr(gettext("Failed to walk instances: %s\n"), 12678 scf_strerror(ret)); 12679 } 12680 } 12681 12682 12683 12684 /* 12685 * :properties commands. These all end with "pg" or "prop" and generally 12686 * operate on the currently selected entity. 12687 */ 12688 12689 /* 12690 * Property listing. List the property groups, properties, their types and 12691 * their values for the currently selected entity. 12692 */ 12693 static void 12694 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12695 { 12696 char *buf; 12697 uint32_t flags; 12698 12699 buf = safe_malloc(max_scf_pg_type_len + 1); 12700 12701 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12702 scfdie(); 12703 12704 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12705 scfdie(); 12706 12707 safe_printf("%-*s %s", namewidth, name, buf); 12708 12709 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12710 safe_printf("\tNONPERSISTENT"); 12711 12712 safe_printf("\n"); 12713 12714 free(buf); 12715 } 12716 12717 static boolean_t 12718 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12719 { 12720 if (scf_property_get_value(prop, val) == 0) { 12721 return (B_FALSE); 12722 } else { 12723 switch (scf_error()) { 12724 case SCF_ERROR_NOT_FOUND: 12725 return (B_FALSE); 12726 case SCF_ERROR_PERMISSION_DENIED: 12727 case SCF_ERROR_CONSTRAINT_VIOLATED: 12728 return (B_TRUE); 12729 default: 12730 scfdie(); 12731 /*NOTREACHED*/ 12732 } 12733 } 12734 } 12735 12736 static void 12737 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12738 { 12739 scf_iter_t *iter; 12740 scf_value_t *val; 12741 const char *type; 12742 int multiple_strings = 0; 12743 int ret; 12744 12745 if ((iter = scf_iter_create(g_hndl)) == NULL || 12746 (val = scf_value_create(g_hndl)) == NULL) 12747 scfdie(); 12748 12749 type = prop_to_typestr(prop); 12750 assert(type != NULL); 12751 12752 safe_printf("%-*s %-7s ", len, name, type); 12753 12754 if (prop_has_multiple_values(prop, val) && 12755 (scf_value_type(val) == SCF_TYPE_ASTRING || 12756 scf_value_type(val) == SCF_TYPE_USTRING)) 12757 multiple_strings = 1; 12758 12759 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12760 scfdie(); 12761 12762 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12763 char *buf; 12764 ssize_t vlen, szret; 12765 12766 vlen = scf_value_get_as_string(val, NULL, 0); 12767 if (vlen < 0) 12768 scfdie(); 12769 12770 buf = safe_malloc(vlen + 1); 12771 12772 szret = scf_value_get_as_string(val, buf, vlen + 1); 12773 if (szret < 0) 12774 scfdie(); 12775 assert(szret <= vlen); 12776 12777 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12778 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12779 safe_printf(" \""); 12780 (void) quote_and_print(buf, stdout, 0); 12781 (void) putchar('"'); 12782 if (ferror(stdout)) { 12783 (void) putchar('\n'); 12784 uu_die(gettext("Error writing to stdout.\n")); 12785 } 12786 } else { 12787 safe_printf(" %s", buf); 12788 } 12789 12790 free(buf); 12791 } 12792 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12793 scfdie(); 12794 12795 if (putchar('\n') != '\n') 12796 uu_die(gettext("Could not output newline")); 12797 } 12798 12799 /* 12800 * Outputs template property group info for the describe subcommand. 12801 * If 'templates' == 2, verbose output is printed in the format expected 12802 * for describe -v, which includes all templates fields. If pg is 12803 * not NULL, we're describing the template data, not an existing property 12804 * group, and formatting should be appropriate for describe -t. 12805 */ 12806 static void 12807 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12808 { 12809 char *buf; 12810 uint8_t required; 12811 scf_property_t *stability_prop; 12812 scf_value_t *stability_val; 12813 12814 if (templates == 0) 12815 return; 12816 12817 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12818 (stability_val = scf_value_create(g_hndl)) == NULL) 12819 scfdie(); 12820 12821 if (templates == 2 && pg != NULL) { 12822 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12823 stability_prop) == 0) { 12824 if (prop_check_type(stability_prop, 12825 SCF_TYPE_ASTRING) == 0 && 12826 prop_get_val(stability_prop, stability_val) == 0) { 12827 char *stability; 12828 12829 stability = safe_malloc(max_scf_value_len + 1); 12830 12831 if (scf_value_get_astring(stability_val, 12832 stability, max_scf_value_len + 1) == -1 && 12833 scf_error() != SCF_ERROR_NOT_FOUND) 12834 scfdie(); 12835 12836 safe_printf("%s%s: %s\n", TMPL_INDENT, 12837 gettext("stability"), stability); 12838 12839 free(stability); 12840 } 12841 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12842 scfdie(); 12843 } 12844 12845 scf_property_destroy(stability_prop); 12846 scf_value_destroy(stability_val); 12847 12848 if (pgt == NULL) 12849 return; 12850 12851 if (pg == NULL || templates == 2) { 12852 /* print type info only if scf_tmpl_pg_name succeeds */ 12853 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12854 if (pg != NULL) 12855 safe_printf("%s", TMPL_INDENT); 12856 safe_printf("%s: ", gettext("name")); 12857 safe_printf("%s\n", buf); 12858 free(buf); 12859 } 12860 12861 /* print type info only if scf_tmpl_pg_type succeeds */ 12862 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12863 if (pg != NULL) 12864 safe_printf("%s", TMPL_INDENT); 12865 safe_printf("%s: ", gettext("type")); 12866 safe_printf("%s\n", buf); 12867 free(buf); 12868 } 12869 } 12870 12871 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12872 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12873 required ? "true" : "false"); 12874 12875 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12876 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12877 buf); 12878 free(buf); 12879 } 12880 12881 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12882 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12883 buf); 12884 free(buf); 12885 } 12886 12887 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12888 if (templates == 2) 12889 safe_printf("%s%s: %s\n", TMPL_INDENT, 12890 gettext("description"), buf); 12891 else 12892 safe_printf("%s%s\n", TMPL_INDENT, buf); 12893 free(buf); 12894 } 12895 12896 } 12897 12898 /* 12899 * With as_value set to true, indent as appropriate for the value level. 12900 * If false, indent to appropriate level for inclusion in constraint 12901 * or choice printout. 12902 */ 12903 static void 12904 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12905 int as_value) 12906 { 12907 char *buf; 12908 12909 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12910 if (as_value == 0) 12911 safe_printf("%s", TMPL_CHOICE_INDENT); 12912 else 12913 safe_printf("%s", TMPL_INDENT); 12914 safe_printf("%s: %s\n", gettext("value common name"), buf); 12915 free(buf); 12916 } 12917 12918 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12919 if (as_value == 0) 12920 safe_printf("%s", TMPL_CHOICE_INDENT); 12921 else 12922 safe_printf("%s", TMPL_INDENT); 12923 safe_printf("%s: %s\n", gettext("value description"), buf); 12924 free(buf); 12925 } 12926 } 12927 12928 static void 12929 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12930 { 12931 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12932 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12933 safe_printf("%s\n", val_buf); 12934 12935 print_template_value_details(prt, val_buf, 1); 12936 } 12937 12938 static void 12939 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12940 { 12941 int i, printed = 0; 12942 scf_values_t values; 12943 scf_count_ranges_t c_ranges; 12944 scf_int_ranges_t i_ranges; 12945 12946 printed = 0; 12947 i = 0; 12948 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12949 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12950 gettext("value constraints")); 12951 printed++; 12952 for (i = 0; i < values.value_count; ++i) { 12953 safe_printf("%s%s: %s\n", TMPL_INDENT, 12954 gettext("value name"), values.values_as_strings[i]); 12955 if (verbose == 1) 12956 print_template_value_details(prt, 12957 values.values_as_strings[i], 0); 12958 } 12959 12960 scf_values_destroy(&values); 12961 } 12962 12963 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12964 if (printed++ == 0) 12965 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12966 gettext("value constraints")); 12967 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12968 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12969 gettext("range"), c_ranges.scr_min[i], 12970 c_ranges.scr_max[i]); 12971 } 12972 scf_count_ranges_destroy(&c_ranges); 12973 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12974 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 12975 if (printed++ == 0) 12976 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12977 gettext("value constraints")); 12978 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12979 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12980 gettext("range"), i_ranges.sir_min[i], 12981 i_ranges.sir_max[i]); 12982 } 12983 scf_int_ranges_destroy(&i_ranges); 12984 } 12985 } 12986 12987 static void 12988 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 12989 { 12990 int i = 0, printed = 0; 12991 scf_values_t values; 12992 scf_count_ranges_t c_ranges; 12993 scf_int_ranges_t i_ranges; 12994 12995 printed = 0; 12996 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 12997 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12998 gettext("value constraints")); 12999 printed++; 13000 for (i = 0; i < values.value_count; i++) { 13001 safe_printf("%s%s: %s\n", TMPL_INDENT, 13002 gettext("value name"), values.values_as_strings[i]); 13003 if (verbose == 1) 13004 print_template_value_details(prt, 13005 values.values_as_strings[i], 0); 13006 } 13007 13008 scf_values_destroy(&values); 13009 } 13010 13011 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 13012 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 13013 if (printed++ == 0) 13014 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13015 gettext("value choices")); 13016 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 13017 gettext("range"), c_ranges.scr_min[i], 13018 c_ranges.scr_max[i]); 13019 } 13020 scf_count_ranges_destroy(&c_ranges); 13021 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 13022 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 13023 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 13024 if (printed++ == 0) 13025 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13026 gettext("value choices")); 13027 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 13028 gettext("range"), i_ranges.sir_min[i], 13029 i_ranges.sir_max[i]); 13030 } 13031 scf_int_ranges_destroy(&i_ranges); 13032 } 13033 } 13034 13035 static void 13036 list_values_by_template(scf_prop_tmpl_t *prt) 13037 { 13038 print_template_constraints(prt, 1); 13039 print_template_choices(prt, 1); 13040 } 13041 13042 static void 13043 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 13044 { 13045 char *val_buf; 13046 scf_iter_t *iter; 13047 scf_value_t *val; 13048 int ret; 13049 13050 if ((iter = scf_iter_create(g_hndl)) == NULL || 13051 (val = scf_value_create(g_hndl)) == NULL) 13052 scfdie(); 13053 13054 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 13055 scfdie(); 13056 13057 val_buf = safe_malloc(max_scf_value_len + 1); 13058 13059 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13060 if (scf_value_get_as_string(val, val_buf, 13061 max_scf_value_len + 1) < 0) 13062 scfdie(); 13063 13064 print_template_value(prt, val_buf); 13065 } 13066 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 13067 scfdie(); 13068 free(val_buf); 13069 13070 print_template_constraints(prt, 0); 13071 print_template_choices(prt, 0); 13072 13073 } 13074 13075 /* 13076 * Outputs property info for the describe subcommand 13077 * Verbose output if templates == 2, -v option of svccfg describe 13078 * Displays template data if prop is not NULL, -t option of svccfg describe 13079 */ 13080 static void 13081 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 13082 { 13083 char *buf; 13084 uint8_t u_buf; 13085 int i; 13086 uint64_t min, max; 13087 scf_values_t values; 13088 13089 if (prt == NULL || templates == 0) 13090 return; 13091 13092 if (prop == NULL) { 13093 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 13094 if (scf_tmpl_prop_name(prt, &buf) > 0) { 13095 safe_printf("%s\n", buf); 13096 free(buf); 13097 } else 13098 safe_printf("(%s)\n", gettext("any")); 13099 } 13100 13101 if (prop == NULL || templates == 2) { 13102 if (prop != NULL) 13103 safe_printf("%s", TMPL_INDENT); 13104 else 13105 safe_printf("%s", TMPL_VALUE_INDENT); 13106 safe_printf("%s: ", gettext("type")); 13107 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 13108 safe_printf("%s\n", buf); 13109 free(buf); 13110 } else 13111 safe_printf("(%s)\n", gettext("any")); 13112 } 13113 13114 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 13115 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 13116 u_buf ? "true" : "false"); 13117 13118 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 13119 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 13120 buf); 13121 free(buf); 13122 } 13123 13124 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 13125 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 13126 buf); 13127 free(buf); 13128 } 13129 13130 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 13131 safe_printf("%s%s\n", TMPL_INDENT, buf); 13132 free(buf); 13133 } 13134 13135 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 13136 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 13137 scf_tmpl_visibility_to_string(u_buf)); 13138 13139 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 13140 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13141 gettext("minimum number of values"), min); 13142 if (max == ULLONG_MAX) { 13143 safe_printf("%s%s: %s\n", TMPL_INDENT, 13144 gettext("maximum number of values"), 13145 gettext("unlimited")); 13146 } else { 13147 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13148 gettext("maximum number of values"), max); 13149 } 13150 } 13151 13152 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 13153 for (i = 0; i < values.value_count; i++) { 13154 if (i == 0) { 13155 safe_printf("%s%s:", TMPL_INDENT, 13156 gettext("internal separators")); 13157 } 13158 safe_printf(" \"%s\"", values.values_as_strings[i]); 13159 } 13160 safe_printf("\n"); 13161 } 13162 13163 if (templates != 2) 13164 return; 13165 13166 if (prop != NULL) 13167 list_values_tmpl(prt, prop); 13168 else 13169 list_values_by_template(prt); 13170 } 13171 13172 static char * 13173 read_astring(scf_propertygroup_t *pg, const char *prop_name) 13174 { 13175 char *rv; 13176 13177 rv = _scf_read_single_astring_from_pg(pg, prop_name); 13178 if (rv == NULL) { 13179 switch (scf_error()) { 13180 case SCF_ERROR_NOT_FOUND: 13181 break; 13182 default: 13183 scfdie(); 13184 } 13185 } 13186 return (rv); 13187 } 13188 13189 static void 13190 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 13191 { 13192 size_t doc_len; 13193 size_t man_len; 13194 char *pg_name; 13195 char *text = NULL; 13196 int rv; 13197 13198 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 13199 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 13200 pg_name = safe_malloc(max_scf_name_len + 1); 13201 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 13202 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 13203 scfdie(); 13204 } 13205 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 13206 /* Display doc_link and and uri */ 13207 safe_printf("%s%s:\n", TMPL_INDENT, 13208 gettext("doc_link")); 13209 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 13210 if (text != NULL) { 13211 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13212 TMPL_INDENT, gettext("name"), text); 13213 uu_free(text); 13214 } 13215 text = read_astring(pg, SCF_PROPERTY_TM_URI); 13216 if (text != NULL) { 13217 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 13218 gettext("uri"), text); 13219 uu_free(text); 13220 } 13221 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 13222 man_len) == 0) { 13223 /* Display manpage title, section and path */ 13224 safe_printf("%s%s:\n", TMPL_INDENT, 13225 gettext("manpage")); 13226 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 13227 if (text != NULL) { 13228 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13229 TMPL_INDENT, gettext("title"), text); 13230 uu_free(text); 13231 } 13232 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 13233 if (text != NULL) { 13234 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13235 TMPL_INDENT, gettext("section"), text); 13236 uu_free(text); 13237 } 13238 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 13239 if (text != NULL) { 13240 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13241 TMPL_INDENT, gettext("manpath"), text); 13242 uu_free(text); 13243 } 13244 } 13245 } 13246 if (rv == -1) 13247 scfdie(); 13248 13249 done: 13250 free(pg_name); 13251 } 13252 13253 static void 13254 list_entity_tmpl(int templates) 13255 { 13256 char *common_name = NULL; 13257 char *description = NULL; 13258 char *locale = NULL; 13259 scf_iter_t *iter; 13260 scf_propertygroup_t *pg; 13261 scf_property_t *prop; 13262 int r; 13263 scf_value_t *val; 13264 13265 if ((pg = scf_pg_create(g_hndl)) == NULL || 13266 (prop = scf_property_create(g_hndl)) == NULL || 13267 (val = scf_value_create(g_hndl)) == NULL || 13268 (iter = scf_iter_create(g_hndl)) == NULL) 13269 scfdie(); 13270 13271 locale = setlocale(LC_MESSAGES, NULL); 13272 13273 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 13274 common_name = safe_malloc(max_scf_value_len + 1); 13275 13276 /* Try both the current locale and the "C" locale. */ 13277 if (scf_pg_get_property(pg, locale, prop) == 0 || 13278 (scf_error() == SCF_ERROR_NOT_FOUND && 13279 scf_pg_get_property(pg, "C", prop) == 0)) { 13280 if (prop_get_val(prop, val) == 0 && 13281 scf_value_get_ustring(val, common_name, 13282 max_scf_value_len + 1) != -1) { 13283 safe_printf("%s%s: %s\n", TMPL_INDENT, 13284 gettext("common name"), common_name); 13285 } 13286 } 13287 } 13288 13289 /* 13290 * Do description, manpages, and doc links if templates == 2. 13291 */ 13292 if (templates == 2) { 13293 /* Get the description. */ 13294 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 13295 description = safe_malloc(max_scf_value_len + 1); 13296 13297 /* Try both the current locale and the "C" locale. */ 13298 if (scf_pg_get_property(pg, locale, prop) == 0 || 13299 (scf_error() == SCF_ERROR_NOT_FOUND && 13300 scf_pg_get_property(pg, "C", prop) == 0)) { 13301 if (prop_get_val(prop, val) == 0 && 13302 scf_value_get_ustring(val, description, 13303 max_scf_value_len + 1) != -1) { 13304 safe_printf("%s%s: %s\n", TMPL_INDENT, 13305 gettext("description"), 13306 description); 13307 } 13308 } 13309 } 13310 13311 /* Process doc_link & manpage elements. */ 13312 if (cur_level != NULL) { 13313 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 13314 SCF_GROUP_TEMPLATE); 13315 } else if (cur_inst != NULL) { 13316 r = scf_iter_instance_pgs_typed(iter, cur_inst, 13317 SCF_GROUP_TEMPLATE); 13318 } else { 13319 r = scf_iter_service_pgs_typed(iter, cur_svc, 13320 SCF_GROUP_TEMPLATE); 13321 } 13322 if (r == 0) { 13323 display_documentation(iter, pg); 13324 } 13325 } 13326 13327 free(common_name); 13328 free(description); 13329 scf_pg_destroy(pg); 13330 scf_property_destroy(prop); 13331 scf_value_destroy(val); 13332 scf_iter_destroy(iter); 13333 } 13334 13335 static void 13336 listtmpl(const char *pattern, int templates) 13337 { 13338 scf_pg_tmpl_t *pgt; 13339 scf_prop_tmpl_t *prt; 13340 char *snapbuf = NULL; 13341 char *fmribuf; 13342 char *pg_name = NULL, *prop_name = NULL; 13343 ssize_t prop_name_size; 13344 char *qual_prop_name; 13345 char *search_name; 13346 int listed = 0; 13347 13348 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13349 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 13350 scfdie(); 13351 13352 fmribuf = safe_malloc(max_scf_name_len + 1); 13353 qual_prop_name = safe_malloc(max_scf_name_len + 1); 13354 13355 if (cur_snap != NULL) { 13356 snapbuf = safe_malloc(max_scf_name_len + 1); 13357 if (scf_snapshot_get_name(cur_snap, snapbuf, 13358 max_scf_name_len + 1) < 0) 13359 scfdie(); 13360 } 13361 13362 if (cur_inst != NULL) { 13363 if (scf_instance_to_fmri(cur_inst, fmribuf, 13364 max_scf_name_len + 1) < 0) 13365 scfdie(); 13366 } else if (cur_svc != NULL) { 13367 if (scf_service_to_fmri(cur_svc, fmribuf, 13368 max_scf_name_len + 1) < 0) 13369 scfdie(); 13370 } else 13371 abort(); 13372 13373 /* If pattern is specified, we want to list only those items. */ 13374 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) { 13375 listed = 0; 13376 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 13377 fnmatch(pattern, pg_name, 0) == 0)) { 13378 list_pg_tmpl(pgt, NULL, templates); 13379 listed++; 13380 } 13381 13382 scf_tmpl_prop_reset(prt); 13383 13384 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) { 13385 search_name = NULL; 13386 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 13387 if ((prop_name_size > 0) && (pg_name != NULL)) { 13388 if (snprintf(qual_prop_name, 13389 max_scf_name_len + 1, "%s/%s", 13390 pg_name, prop_name) >= 13391 max_scf_name_len + 1) { 13392 prop_name_size = -1; 13393 } else { 13394 search_name = qual_prop_name; 13395 } 13396 } 13397 if (listed > 0 || pattern == NULL || 13398 (prop_name_size > 0 && 13399 fnmatch(pattern, search_name, 13400 FNM_PATHNAME) == 0)) 13401 list_prop_tmpl(prt, NULL, templates); 13402 if (prop_name != NULL) { 13403 free(prop_name); 13404 prop_name = NULL; 13405 } 13406 } 13407 if (pg_name != NULL) { 13408 free(pg_name); 13409 pg_name = NULL; 13410 } 13411 } 13412 13413 scf_tmpl_prop_destroy(prt); 13414 scf_tmpl_pg_destroy(pgt); 13415 free(snapbuf); 13416 free(fmribuf); 13417 free(qual_prop_name); 13418 } 13419 13420 static void 13421 listprop(const char *pattern, int only_pgs, int templates) 13422 { 13423 scf_propertygroup_t *pg; 13424 scf_property_t *prop; 13425 scf_iter_t *iter, *piter; 13426 char *pgnbuf, *prnbuf, *ppnbuf; 13427 scf_pg_tmpl_t *pgt, *pgtp; 13428 scf_prop_tmpl_t *prt; 13429 13430 void **objects; 13431 char **names; 13432 void **tmpls; 13433 int allocd, i; 13434 13435 int ret; 13436 ssize_t pgnlen, prnlen, szret; 13437 size_t max_len = 0; 13438 13439 if (cur_svc == NULL && cur_inst == NULL) { 13440 semerr(emsg_entity_not_selected); 13441 return; 13442 } 13443 13444 if ((pg = scf_pg_create(g_hndl)) == NULL || 13445 (prop = scf_property_create(g_hndl)) == NULL || 13446 (iter = scf_iter_create(g_hndl)) == NULL || 13447 (piter = scf_iter_create(g_hndl)) == NULL || 13448 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13449 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 13450 scfdie(); 13451 13452 prnbuf = safe_malloc(max_scf_name_len + 1); 13453 13454 if (cur_level != NULL) 13455 ret = scf_iter_snaplevel_pgs(iter, cur_level); 13456 else if (cur_inst != NULL) 13457 ret = scf_iter_instance_pgs(iter, cur_inst); 13458 else 13459 ret = scf_iter_service_pgs(iter, cur_svc); 13460 if (ret != 0) { 13461 return; 13462 } 13463 13464 /* 13465 * We want to only list items which match pattern, and we want the 13466 * second column to line up, so during the first pass we'll save 13467 * matching items, their names, and their templates in objects, 13468 * names, and tmpls, computing the maximum name length as we go, 13469 * and then we'll print them out. 13470 * 13471 * Note: We always keep an extra slot available so the array can be 13472 * NULL-terminated. 13473 */ 13474 i = 0; 13475 allocd = 1; 13476 objects = safe_malloc(sizeof (*objects)); 13477 names = safe_malloc(sizeof (*names)); 13478 tmpls = safe_malloc(sizeof (*tmpls)); 13479 13480 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13481 int new_pg = 0; 13482 int print_props = 0; 13483 pgtp = NULL; 13484 13485 pgnlen = scf_pg_get_name(pg, NULL, 0); 13486 if (pgnlen < 0) 13487 scfdie(); 13488 13489 pgnbuf = safe_malloc(pgnlen + 1); 13490 13491 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 13492 if (szret < 0) 13493 scfdie(); 13494 assert(szret <= pgnlen); 13495 13496 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) { 13497 if (scf_error() != SCF_ERROR_NOT_FOUND) 13498 scfdie(); 13499 pgtp = NULL; 13500 } else { 13501 pgtp = pgt; 13502 } 13503 13504 if (pattern == NULL || 13505 fnmatch(pattern, pgnbuf, 0) == 0) { 13506 if (i+1 >= allocd) { 13507 allocd *= 2; 13508 objects = realloc(objects, 13509 sizeof (*objects) * allocd); 13510 names = 13511 realloc(names, sizeof (*names) * allocd); 13512 tmpls = realloc(tmpls, 13513 sizeof (*tmpls) * allocd); 13514 if (objects == NULL || names == NULL || 13515 tmpls == NULL) 13516 uu_die(gettext("Out of memory")); 13517 } 13518 objects[i] = pg; 13519 names[i] = pgnbuf; 13520 13521 if (pgtp == NULL) 13522 tmpls[i] = NULL; 13523 else 13524 tmpls[i] = pgt; 13525 13526 ++i; 13527 13528 if (pgnlen > max_len) 13529 max_len = pgnlen; 13530 13531 new_pg = 1; 13532 print_props = 1; 13533 } 13534 13535 if (only_pgs) { 13536 if (new_pg) { 13537 pg = scf_pg_create(g_hndl); 13538 if (pg == NULL) 13539 scfdie(); 13540 pgt = scf_tmpl_pg_create(g_hndl); 13541 if (pgt == NULL) 13542 scfdie(); 13543 } else 13544 free(pgnbuf); 13545 13546 continue; 13547 } 13548 13549 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13550 scfdie(); 13551 13552 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13553 prnlen = scf_property_get_name(prop, prnbuf, 13554 max_scf_name_len + 1); 13555 if (prnlen < 0) 13556 scfdie(); 13557 13558 /* Will prepend the property group name and a slash. */ 13559 prnlen += pgnlen + 1; 13560 13561 ppnbuf = safe_malloc(prnlen + 1); 13562 13563 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13564 prnbuf) < 0) 13565 uu_die("snprintf"); 13566 13567 if (pattern == NULL || print_props == 1 || 13568 fnmatch(pattern, ppnbuf, 0) == 0) { 13569 if (i+1 >= allocd) { 13570 allocd *= 2; 13571 objects = realloc(objects, 13572 sizeof (*objects) * allocd); 13573 names = realloc(names, 13574 sizeof (*names) * allocd); 13575 tmpls = realloc(tmpls, 13576 sizeof (*tmpls) * allocd); 13577 if (objects == NULL || names == NULL || 13578 tmpls == NULL) 13579 uu_die(gettext( 13580 "Out of memory")); 13581 } 13582 13583 objects[i] = prop; 13584 names[i] = ppnbuf; 13585 13586 if (pgtp != NULL) { 13587 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13588 prt, 0) < 0) { 13589 if (scf_error() != 13590 SCF_ERROR_NOT_FOUND) 13591 scfdie(); 13592 tmpls[i] = NULL; 13593 } else { 13594 tmpls[i] = prt; 13595 } 13596 } else { 13597 tmpls[i] = NULL; 13598 } 13599 13600 ++i; 13601 13602 if (prnlen > max_len) 13603 max_len = prnlen; 13604 13605 prop = scf_property_create(g_hndl); 13606 prt = scf_tmpl_prop_create(g_hndl); 13607 } else { 13608 free(ppnbuf); 13609 } 13610 } 13611 13612 if (new_pg) { 13613 pg = scf_pg_create(g_hndl); 13614 if (pg == NULL) 13615 scfdie(); 13616 pgt = scf_tmpl_pg_create(g_hndl); 13617 if (pgt == NULL) 13618 scfdie(); 13619 } else 13620 free(pgnbuf); 13621 } 13622 if (ret != 0) 13623 scfdie(); 13624 13625 objects[i] = NULL; 13626 13627 scf_pg_destroy(pg); 13628 scf_tmpl_pg_destroy(pgt); 13629 scf_property_destroy(prop); 13630 scf_tmpl_prop_destroy(prt); 13631 13632 for (i = 0; objects[i] != NULL; ++i) { 13633 if (strchr(names[i], '/') == NULL) { 13634 /* property group */ 13635 pg = (scf_propertygroup_t *)objects[i]; 13636 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13637 list_pg_info(pg, names[i], max_len); 13638 list_pg_tmpl(pgt, pg, templates); 13639 free(names[i]); 13640 scf_pg_destroy(pg); 13641 if (pgt != NULL) 13642 scf_tmpl_pg_destroy(pgt); 13643 } else { 13644 /* property */ 13645 prop = (scf_property_t *)objects[i]; 13646 prt = (scf_prop_tmpl_t *)tmpls[i]; 13647 list_prop_info(prop, names[i], max_len); 13648 list_prop_tmpl(prt, prop, templates); 13649 free(names[i]); 13650 scf_property_destroy(prop); 13651 if (prt != NULL) 13652 scf_tmpl_prop_destroy(prt); 13653 } 13654 } 13655 13656 free(names); 13657 free(objects); 13658 free(tmpls); 13659 } 13660 13661 void 13662 lscf_listpg(const char *pattern) 13663 { 13664 lscf_prep_hndl(); 13665 13666 listprop(pattern, 1, 0); 13667 } 13668 13669 /* 13670 * Property group and property creation, setting, and deletion. setprop (and 13671 * its alias, addprop) can either create a property group of a given type, or 13672 * it can create or set a property to a given type and list of values. 13673 */ 13674 void 13675 lscf_addpg(const char *name, const char *type, const char *flags) 13676 { 13677 scf_propertygroup_t *pg; 13678 int ret; 13679 uint32_t flgs = 0; 13680 const char *cp; 13681 13682 13683 lscf_prep_hndl(); 13684 13685 if (cur_snap != NULL) { 13686 semerr(emsg_cant_modify_snapshots); 13687 return; 13688 } 13689 13690 if (cur_inst == NULL && cur_svc == NULL) { 13691 semerr(emsg_entity_not_selected); 13692 return; 13693 } 13694 13695 if (flags != NULL) { 13696 for (cp = flags; *cp != '\0'; ++cp) { 13697 switch (*cp) { 13698 case 'P': 13699 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13700 break; 13701 13702 case 'p': 13703 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13704 break; 13705 13706 default: 13707 semerr(gettext("Invalid property group flag " 13708 "%c."), *cp); 13709 return; 13710 } 13711 } 13712 } 13713 13714 pg = scf_pg_create(g_hndl); 13715 if (pg == NULL) 13716 scfdie(); 13717 13718 if (cur_inst != NULL) 13719 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13720 else 13721 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13722 13723 if (ret != SCF_SUCCESS) { 13724 switch (scf_error()) { 13725 case SCF_ERROR_INVALID_ARGUMENT: 13726 semerr(gettext("Name, type, or flags are invalid.\n")); 13727 break; 13728 13729 case SCF_ERROR_EXISTS: 13730 semerr(gettext("Property group already exists.\n")); 13731 break; 13732 13733 case SCF_ERROR_PERMISSION_DENIED: 13734 semerr(emsg_permission_denied); 13735 break; 13736 13737 case SCF_ERROR_BACKEND_ACCESS: 13738 semerr(gettext("Backend refused access.\n")); 13739 break; 13740 13741 default: 13742 scfdie(); 13743 } 13744 } 13745 13746 scf_pg_destroy(pg); 13747 13748 private_refresh(); 13749 } 13750 13751 void 13752 lscf_delpg(char *name) 13753 { 13754 lscf_prep_hndl(); 13755 13756 if (cur_snap != NULL) { 13757 semerr(emsg_cant_modify_snapshots); 13758 return; 13759 } 13760 13761 if (cur_inst == NULL && cur_svc == NULL) { 13762 semerr(emsg_entity_not_selected); 13763 return; 13764 } 13765 13766 if (strchr(name, '/') != NULL) { 13767 semerr(emsg_invalid_pg_name, name); 13768 return; 13769 } 13770 13771 lscf_delprop(name); 13772 } 13773 13774 /* 13775 * scf_delhash() is used to remove the property group related to the 13776 * hash entry for a specific manifest in the repository. pgname will be 13777 * constructed from the location of the manifest file. If deathrow isn't 0, 13778 * manifest file doesn't need to exist (manifest string will be used as 13779 * an absolute path). 13780 */ 13781 void 13782 lscf_delhash(char *manifest, int deathrow) 13783 { 13784 char *pgname; 13785 13786 if (cur_snap != NULL || 13787 cur_inst != NULL || cur_svc != NULL) { 13788 warn(gettext("error, an entity is selected\n")); 13789 return; 13790 } 13791 13792 /* select smf/manifest */ 13793 lscf_select(HASH_SVC); 13794 /* 13795 * Translate the manifest file name to property name. In the deathrow 13796 * case, the manifest file does not need to exist. 13797 */ 13798 pgname = mhash_filename_to_propname(manifest, 13799 deathrow ? B_TRUE : B_FALSE); 13800 if (pgname == NULL) { 13801 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13802 return; 13803 } 13804 /* delete the hash property name */ 13805 lscf_delpg(pgname); 13806 } 13807 13808 void 13809 lscf_listprop(const char *pattern) 13810 { 13811 lscf_prep_hndl(); 13812 13813 listprop(pattern, 0, 0); 13814 } 13815 13816 int 13817 lscf_setprop(const char *pgname, const char *type, const char *value, 13818 const uu_list_t *values) 13819 { 13820 scf_type_t ty, current_ty; 13821 scf_service_t *svc; 13822 scf_propertygroup_t *pg, *parent_pg; 13823 scf_property_t *prop, *parent_prop; 13824 scf_pg_tmpl_t *pgt; 13825 scf_prop_tmpl_t *prt; 13826 int ret, result = 0; 13827 scf_transaction_t *tx; 13828 scf_transaction_entry_t *e; 13829 scf_value_t *v; 13830 uu_list_walk_t *walk; 13831 string_list_t *sp; 13832 char *propname; 13833 int req_quotes = 0; 13834 13835 lscf_prep_hndl(); 13836 13837 if ((e = scf_entry_create(g_hndl)) == NULL || 13838 (svc = scf_service_create(g_hndl)) == NULL || 13839 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13840 (pg = scf_pg_create(g_hndl)) == NULL || 13841 (parent_prop = scf_property_create(g_hndl)) == NULL || 13842 (prop = scf_property_create(g_hndl)) == NULL || 13843 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13844 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13845 (tx = scf_transaction_create(g_hndl)) == NULL) 13846 scfdie(); 13847 13848 if (cur_snap != NULL) { 13849 semerr(emsg_cant_modify_snapshots); 13850 goto fail; 13851 } 13852 13853 if (cur_inst == NULL && cur_svc == NULL) { 13854 semerr(emsg_entity_not_selected); 13855 goto fail; 13856 } 13857 13858 propname = strchr(pgname, '/'); 13859 if (propname == NULL) { 13860 semerr(gettext("Property names must contain a `/'.\n")); 13861 goto fail; 13862 } 13863 13864 *propname = '\0'; 13865 ++propname; 13866 13867 if (type != NULL) { 13868 ty = string_to_type(type); 13869 if (ty == SCF_TYPE_INVALID) { 13870 semerr(gettext("Unknown type \"%s\".\n"), type); 13871 goto fail; 13872 } 13873 } 13874 13875 if (cur_inst != NULL) 13876 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13877 else 13878 ret = scf_service_get_pg(cur_svc, pgname, pg); 13879 if (ret != SCF_SUCCESS) { 13880 switch (scf_error()) { 13881 case SCF_ERROR_NOT_FOUND: 13882 semerr(emsg_no_such_pg, pgname); 13883 goto fail; 13884 13885 case SCF_ERROR_INVALID_ARGUMENT: 13886 semerr(emsg_invalid_pg_name, pgname); 13887 goto fail; 13888 13889 default: 13890 scfdie(); 13891 break; 13892 } 13893 } 13894 13895 do { 13896 if (scf_pg_update(pg) == -1) 13897 scfdie(); 13898 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13899 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13900 scfdie(); 13901 13902 semerr(emsg_permission_denied); 13903 goto fail; 13904 } 13905 13906 ret = scf_pg_get_property(pg, propname, prop); 13907 if (ret == SCF_SUCCESS) { 13908 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13909 scfdie(); 13910 13911 if (type == NULL) 13912 ty = current_ty; 13913 if (scf_transaction_property_change_type(tx, e, 13914 propname, ty) == -1) 13915 scfdie(); 13916 13917 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13918 /* Infer the type, if possible. */ 13919 if (type == NULL) { 13920 /* 13921 * First check if we're an instance and the 13922 * property is set on the service. 13923 */ 13924 if (cur_inst != NULL && 13925 scf_instance_get_parent(cur_inst, 13926 svc) == 0 && 13927 scf_service_get_pg(cur_svc, pgname, 13928 parent_pg) == 0 && 13929 scf_pg_get_property(parent_pg, propname, 13930 parent_prop) == 0 && 13931 scf_property_type(parent_prop, 13932 ¤t_ty) == 0) { 13933 ty = current_ty; 13934 13935 /* Then check for a type set in a template. */ 13936 } else if (scf_tmpl_get_by_pg(pg, pgt, 13937 0) == 0 && 13938 scf_tmpl_get_by_prop(pgt, propname, prt, 13939 0) == 0 && 13940 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13941 ty = current_ty; 13942 13943 /* If type can't be inferred, fail. */ 13944 } else { 13945 semerr(gettext("Type required for new " 13946 "properties.\n")); 13947 goto fail; 13948 } 13949 } 13950 if (scf_transaction_property_new(tx, e, propname, 13951 ty) == -1) 13952 scfdie(); 13953 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13954 semerr(emsg_invalid_prop_name, propname); 13955 goto fail; 13956 } else { 13957 scfdie(); 13958 } 13959 13960 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13961 req_quotes = 1; 13962 13963 if (value != NULL) { 13964 v = string_to_value(value, ty, 0); 13965 13966 if (v == NULL) 13967 goto fail; 13968 13969 ret = scf_entry_add_value(e, v); 13970 assert(ret == SCF_SUCCESS); 13971 } else { 13972 assert(values != NULL); 13973 13974 walk = uu_list_walk_start((uu_list_t *)values, 13975 UU_DEFAULT); 13976 if (walk == NULL) 13977 uu_die(gettext("Could not walk list")); 13978 13979 for (sp = uu_list_walk_next(walk); sp != NULL; 13980 sp = uu_list_walk_next(walk)) { 13981 v = string_to_value(sp->str, ty, req_quotes); 13982 13983 if (v == NULL) { 13984 scf_entry_destroy_children(e); 13985 goto fail; 13986 } 13987 13988 ret = scf_entry_add_value(e, v); 13989 assert(ret == SCF_SUCCESS); 13990 } 13991 uu_list_walk_end(walk); 13992 } 13993 result = scf_transaction_commit(tx); 13994 13995 scf_transaction_reset(tx); 13996 scf_entry_destroy_children(e); 13997 } while (result == 0); 13998 13999 if (result < 0) { 14000 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14001 scfdie(); 14002 14003 semerr(emsg_permission_denied); 14004 goto fail; 14005 } 14006 14007 ret = 0; 14008 14009 private_refresh(); 14010 14011 goto cleanup; 14012 14013 fail: 14014 ret = -1; 14015 14016 cleanup: 14017 scf_transaction_destroy(tx); 14018 scf_entry_destroy(e); 14019 scf_service_destroy(svc); 14020 scf_pg_destroy(parent_pg); 14021 scf_pg_destroy(pg); 14022 scf_property_destroy(parent_prop); 14023 scf_property_destroy(prop); 14024 scf_tmpl_pg_destroy(pgt); 14025 scf_tmpl_prop_destroy(prt); 14026 14027 return (ret); 14028 } 14029 14030 void 14031 lscf_delprop(char *pgn) 14032 { 14033 char *slash, *pn; 14034 scf_propertygroup_t *pg; 14035 scf_transaction_t *tx; 14036 scf_transaction_entry_t *e; 14037 int ret; 14038 14039 14040 lscf_prep_hndl(); 14041 14042 if (cur_snap != NULL) { 14043 semerr(emsg_cant_modify_snapshots); 14044 return; 14045 } 14046 14047 if (cur_inst == NULL && cur_svc == NULL) { 14048 semerr(emsg_entity_not_selected); 14049 return; 14050 } 14051 14052 pg = scf_pg_create(g_hndl); 14053 if (pg == NULL) 14054 scfdie(); 14055 14056 slash = strchr(pgn, '/'); 14057 if (slash == NULL) { 14058 pn = NULL; 14059 } else { 14060 *slash = '\0'; 14061 pn = slash + 1; 14062 } 14063 14064 if (cur_inst != NULL) 14065 ret = scf_instance_get_pg(cur_inst, pgn, pg); 14066 else 14067 ret = scf_service_get_pg(cur_svc, pgn, pg); 14068 if (ret != SCF_SUCCESS) { 14069 switch (scf_error()) { 14070 case SCF_ERROR_NOT_FOUND: 14071 semerr(emsg_no_such_pg, pgn); 14072 break; 14073 14074 case SCF_ERROR_INVALID_ARGUMENT: 14075 semerr(emsg_invalid_pg_name, pgn); 14076 break; 14077 14078 default: 14079 scfdie(); 14080 } 14081 14082 scf_pg_destroy(pg); 14083 14084 return; 14085 } 14086 14087 if (pn == NULL) { 14088 /* Try to delete the property group. */ 14089 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14090 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14091 scfdie(); 14092 14093 semerr(emsg_permission_denied); 14094 } else { 14095 private_refresh(); 14096 } 14097 14098 scf_pg_destroy(pg); 14099 return; 14100 } 14101 14102 e = scf_entry_create(g_hndl); 14103 tx = scf_transaction_create(g_hndl); 14104 14105 do { 14106 if (scf_pg_update(pg) == -1) 14107 scfdie(); 14108 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 14109 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14110 scfdie(); 14111 14112 semerr(emsg_permission_denied); 14113 break; 14114 } 14115 14116 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 14117 if (scf_error() == SCF_ERROR_NOT_FOUND) { 14118 semerr(gettext("No such property %s/%s.\n"), 14119 pgn, pn); 14120 break; 14121 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14122 semerr(emsg_invalid_prop_name, pn); 14123 break; 14124 } else { 14125 scfdie(); 14126 } 14127 } 14128 14129 ret = scf_transaction_commit(tx); 14130 14131 if (ret == 0) 14132 scf_transaction_reset(tx); 14133 } while (ret == 0); 14134 14135 if (ret < 0) { 14136 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14137 scfdie(); 14138 14139 semerr(emsg_permission_denied); 14140 } else { 14141 private_refresh(); 14142 } 14143 14144 scf_transaction_destroy(tx); 14145 scf_entry_destroy(e); 14146 scf_pg_destroy(pg); 14147 } 14148 14149 /* 14150 * Property editing. 14151 */ 14152 14153 static int 14154 write_edit_script(FILE *strm) 14155 { 14156 char *fmribuf; 14157 ssize_t fmrilen; 14158 14159 scf_propertygroup_t *pg; 14160 scf_property_t *prop; 14161 scf_value_t *val; 14162 scf_type_t ty; 14163 int ret, result = 0; 14164 scf_iter_t *iter, *piter, *viter; 14165 char *buf, *tybuf, *pname; 14166 const char *emsg_write_error; 14167 14168 14169 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 14170 14171 14172 /* select fmri */ 14173 if (cur_inst != NULL) { 14174 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 14175 if (fmrilen < 0) 14176 scfdie(); 14177 fmribuf = safe_malloc(fmrilen + 1); 14178 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 14179 scfdie(); 14180 } else { 14181 assert(cur_svc != NULL); 14182 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 14183 if (fmrilen < 0) 14184 scfdie(); 14185 fmribuf = safe_malloc(fmrilen + 1); 14186 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 14187 scfdie(); 14188 } 14189 14190 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 14191 warn(emsg_write_error, strerror(errno)); 14192 free(fmribuf); 14193 return (-1); 14194 } 14195 14196 free(fmribuf); 14197 14198 14199 if ((pg = scf_pg_create(g_hndl)) == NULL || 14200 (prop = scf_property_create(g_hndl)) == NULL || 14201 (val = scf_value_create(g_hndl)) == NULL || 14202 (iter = scf_iter_create(g_hndl)) == NULL || 14203 (piter = scf_iter_create(g_hndl)) == NULL || 14204 (viter = scf_iter_create(g_hndl)) == NULL) 14205 scfdie(); 14206 14207 buf = safe_malloc(max_scf_name_len + 1); 14208 tybuf = safe_malloc(max_scf_pg_type_len + 1); 14209 pname = safe_malloc(max_scf_name_len + 1); 14210 14211 if (cur_inst != NULL) 14212 ret = scf_iter_instance_pgs(iter, cur_inst); 14213 else 14214 ret = scf_iter_service_pgs(iter, cur_svc); 14215 if (ret != SCF_SUCCESS) 14216 scfdie(); 14217 14218 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 14219 int ret2; 14220 14221 /* 14222 * # delprop pg 14223 * # addpg pg type 14224 */ 14225 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 14226 scfdie(); 14227 14228 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 14229 scfdie(); 14230 14231 if (fprintf(strm, "# Property group \"%s\"\n" 14232 "# delprop %s\n" 14233 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 14234 warn(emsg_write_error, strerror(errno)); 14235 result = -1; 14236 goto out; 14237 } 14238 14239 /* # setprop pg/prop = (values) */ 14240 14241 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 14242 scfdie(); 14243 14244 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 14245 int first = 1; 14246 int ret3; 14247 int multiple; 14248 int is_str; 14249 scf_type_t bty; 14250 14251 if (scf_property_get_name(prop, pname, 14252 max_scf_name_len + 1) < 0) 14253 scfdie(); 14254 14255 if (scf_property_type(prop, &ty) != 0) 14256 scfdie(); 14257 14258 multiple = prop_has_multiple_values(prop, val); 14259 14260 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 14261 pname, scf_type_to_string(ty), multiple ? "(" : "") 14262 < 0) { 14263 warn(emsg_write_error, strerror(errno)); 14264 result = -1; 14265 goto out; 14266 } 14267 14268 (void) scf_type_base_type(ty, &bty); 14269 is_str = (bty == SCF_TYPE_ASTRING); 14270 14271 if (scf_iter_property_values(viter, prop) != 14272 SCF_SUCCESS) 14273 scfdie(); 14274 14275 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 14276 char *buf; 14277 ssize_t buflen; 14278 14279 buflen = scf_value_get_as_string(val, NULL, 0); 14280 if (buflen < 0) 14281 scfdie(); 14282 14283 buf = safe_malloc(buflen + 1); 14284 14285 if (scf_value_get_as_string(val, buf, 14286 buflen + 1) < 0) 14287 scfdie(); 14288 14289 if (first) 14290 first = 0; 14291 else { 14292 if (putc(' ', strm) != ' ') { 14293 warn(emsg_write_error, 14294 strerror(errno)); 14295 result = -1; 14296 goto out; 14297 } 14298 } 14299 14300 if ((is_str && multiple) || 14301 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 14302 (void) putc('"', strm); 14303 (void) quote_and_print(buf, strm, 1); 14304 (void) putc('"', strm); 14305 14306 if (ferror(strm)) { 14307 warn(emsg_write_error, 14308 strerror(errno)); 14309 result = -1; 14310 goto out; 14311 } 14312 } else { 14313 if (fprintf(strm, "%s", buf) < 0) { 14314 warn(emsg_write_error, 14315 strerror(errno)); 14316 result = -1; 14317 goto out; 14318 } 14319 } 14320 14321 free(buf); 14322 } 14323 if (ret3 < 0 && 14324 scf_error() != SCF_ERROR_PERMISSION_DENIED) 14325 scfdie(); 14326 14327 /* Write closing paren if mult-value property */ 14328 if ((multiple && putc(')', strm) == EOF) || 14329 14330 /* Write final newline */ 14331 fputc('\n', strm) == EOF) { 14332 warn(emsg_write_error, strerror(errno)); 14333 result = -1; 14334 goto out; 14335 } 14336 } 14337 if (ret2 < 0) 14338 scfdie(); 14339 14340 if (fputc('\n', strm) == EOF) { 14341 warn(emsg_write_error, strerror(errno)); 14342 result = -1; 14343 goto out; 14344 } 14345 } 14346 if (ret < 0) 14347 scfdie(); 14348 14349 out: 14350 free(pname); 14351 free(tybuf); 14352 free(buf); 14353 scf_iter_destroy(viter); 14354 scf_iter_destroy(piter); 14355 scf_iter_destroy(iter); 14356 scf_value_destroy(val); 14357 scf_property_destroy(prop); 14358 scf_pg_destroy(pg); 14359 14360 if (result == 0) { 14361 if (fflush(strm) != 0) { 14362 warn(emsg_write_error, strerror(errno)); 14363 return (-1); 14364 } 14365 } 14366 14367 return (result); 14368 } 14369 14370 int 14371 lscf_editprop() 14372 { 14373 char *buf, *editor; 14374 size_t bufsz; 14375 int tmpfd; 14376 char tempname[] = TEMP_FILE_PATTERN; 14377 14378 lscf_prep_hndl(); 14379 14380 if (cur_snap != NULL) { 14381 semerr(emsg_cant_modify_snapshots); 14382 return (-1); 14383 } 14384 14385 if (cur_svc == NULL && cur_inst == NULL) { 14386 semerr(emsg_entity_not_selected); 14387 return (-1); 14388 } 14389 14390 tmpfd = mkstemp(tempname); 14391 if (tmpfd == -1) { 14392 semerr(gettext("Could not create temporary file.\n")); 14393 return (-1); 14394 } 14395 14396 (void) strcpy(tempfilename, tempname); 14397 14398 tempfile = fdopen(tmpfd, "r+"); 14399 if (tempfile == NULL) { 14400 warn(gettext("Could not create temporary file.\n")); 14401 if (close(tmpfd) == -1) 14402 warn(gettext("Could not close temporary file: %s.\n"), 14403 strerror(errno)); 14404 14405 remove_tempfile(); 14406 14407 return (-1); 14408 } 14409 14410 if (write_edit_script(tempfile) == -1) { 14411 remove_tempfile(); 14412 return (-1); 14413 } 14414 14415 editor = getenv("EDITOR"); 14416 if (editor == NULL) 14417 editor = "vi"; 14418 14419 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 14420 buf = safe_malloc(bufsz); 14421 14422 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 14423 uu_die(gettext("Error creating editor command")); 14424 14425 if (system(buf) == -1) { 14426 semerr(gettext("Could not launch editor %s: %s\n"), editor, 14427 strerror(errno)); 14428 free(buf); 14429 remove_tempfile(); 14430 return (-1); 14431 } 14432 14433 free(buf); 14434 14435 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 14436 14437 remove_tempfile(); 14438 14439 return (0); 14440 } 14441 14442 static void 14443 add_string(uu_list_t *strlist, const char *str) 14444 { 14445 string_list_t *elem; 14446 elem = safe_malloc(sizeof (*elem)); 14447 uu_list_node_init(elem, &elem->node, string_pool); 14448 elem->str = safe_strdup(str); 14449 if (uu_list_append(strlist, elem) != 0) 14450 uu_die(gettext("libuutil error: %s\n"), 14451 uu_strerror(uu_error())); 14452 } 14453 14454 static int 14455 remove_string(uu_list_t *strlist, const char *str) 14456 { 14457 uu_list_walk_t *elems; 14458 string_list_t *sp; 14459 14460 /* 14461 * Find the element that needs to be removed. 14462 */ 14463 elems = uu_list_walk_start(strlist, UU_DEFAULT); 14464 while ((sp = uu_list_walk_next(elems)) != NULL) { 14465 if (strcmp(sp->str, str) == 0) 14466 break; 14467 } 14468 uu_list_walk_end(elems); 14469 14470 /* 14471 * Returning 1 here as the value was not found, this 14472 * might not be an error. Leave it to the caller to 14473 * decide. 14474 */ 14475 if (sp == NULL) { 14476 return (1); 14477 } 14478 14479 uu_list_remove(strlist, sp); 14480 14481 free(sp->str); 14482 free(sp); 14483 14484 return (0); 14485 } 14486 14487 /* 14488 * Get all property values that don't match the given glob pattern, 14489 * if a pattern is specified. 14490 */ 14491 static void 14492 get_prop_values(scf_property_t *prop, uu_list_t *values, 14493 const char *pattern) 14494 { 14495 scf_iter_t *iter; 14496 scf_value_t *val; 14497 int ret; 14498 14499 if ((iter = scf_iter_create(g_hndl)) == NULL || 14500 (val = scf_value_create(g_hndl)) == NULL) 14501 scfdie(); 14502 14503 if (scf_iter_property_values(iter, prop) != 0) 14504 scfdie(); 14505 14506 while ((ret = scf_iter_next_value(iter, val)) == 1) { 14507 char *buf; 14508 ssize_t vlen, szret; 14509 14510 vlen = scf_value_get_as_string(val, NULL, 0); 14511 if (vlen < 0) 14512 scfdie(); 14513 14514 buf = safe_malloc(vlen + 1); 14515 14516 szret = scf_value_get_as_string(val, buf, vlen + 1); 14517 if (szret < 0) 14518 scfdie(); 14519 assert(szret <= vlen); 14520 14521 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 14522 add_string(values, buf); 14523 14524 free(buf); 14525 } 14526 14527 if (ret == -1) 14528 scfdie(); 14529 14530 scf_value_destroy(val); 14531 scf_iter_destroy(iter); 14532 } 14533 14534 static int 14535 lscf_setpropvalue(const char *pgname, const char *type, 14536 const char *arg, int isadd, int isnotfoundok) 14537 { 14538 scf_type_t ty; 14539 scf_propertygroup_t *pg; 14540 scf_property_t *prop; 14541 int ret, result = 0; 14542 scf_transaction_t *tx; 14543 scf_transaction_entry_t *e; 14544 scf_value_t *v; 14545 string_list_t *sp; 14546 char *propname; 14547 uu_list_t *values; 14548 uu_list_walk_t *walk; 14549 void *cookie = NULL; 14550 char *pattern = NULL; 14551 14552 lscf_prep_hndl(); 14553 14554 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14555 uu_die(gettext("Could not create property list: %s\n"), 14556 uu_strerror(uu_error())); 14557 14558 if (!isadd) 14559 pattern = safe_strdup(arg); 14560 14561 if ((e = scf_entry_create(g_hndl)) == NULL || 14562 (pg = scf_pg_create(g_hndl)) == NULL || 14563 (prop = scf_property_create(g_hndl)) == NULL || 14564 (tx = scf_transaction_create(g_hndl)) == NULL) 14565 scfdie(); 14566 14567 if (cur_snap != NULL) { 14568 semerr(emsg_cant_modify_snapshots); 14569 goto fail; 14570 } 14571 14572 if (cur_inst == NULL && cur_svc == NULL) { 14573 semerr(emsg_entity_not_selected); 14574 goto fail; 14575 } 14576 14577 propname = strchr(pgname, '/'); 14578 if (propname == NULL) { 14579 semerr(gettext("Property names must contain a `/'.\n")); 14580 goto fail; 14581 } 14582 14583 *propname = '\0'; 14584 ++propname; 14585 14586 if (type != NULL) { 14587 ty = string_to_type(type); 14588 if (ty == SCF_TYPE_INVALID) { 14589 semerr(gettext("Unknown type \"%s\".\n"), type); 14590 goto fail; 14591 } 14592 } 14593 14594 if (cur_inst != NULL) 14595 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14596 else 14597 ret = scf_service_get_pg(cur_svc, pgname, pg); 14598 if (ret != 0) { 14599 switch (scf_error()) { 14600 case SCF_ERROR_NOT_FOUND: 14601 if (isnotfoundok) { 14602 result = 0; 14603 } else { 14604 semerr(emsg_no_such_pg, pgname); 14605 result = -1; 14606 } 14607 goto out; 14608 14609 case SCF_ERROR_INVALID_ARGUMENT: 14610 semerr(emsg_invalid_pg_name, pgname); 14611 goto fail; 14612 14613 default: 14614 scfdie(); 14615 } 14616 } 14617 14618 do { 14619 if (scf_pg_update(pg) == -1) 14620 scfdie(); 14621 if (scf_transaction_start(tx, pg) != 0) { 14622 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14623 scfdie(); 14624 14625 semerr(emsg_permission_denied); 14626 goto fail; 14627 } 14628 14629 ret = scf_pg_get_property(pg, propname, prop); 14630 if (ret == 0) { 14631 scf_type_t ptype; 14632 char *pat = pattern; 14633 14634 if (scf_property_type(prop, &ptype) != 0) 14635 scfdie(); 14636 14637 if (isadd) { 14638 if (type != NULL && ptype != ty) { 14639 semerr(gettext("Property \"%s\" is not " 14640 "of type \"%s\".\n"), propname, 14641 type); 14642 goto fail; 14643 } 14644 14645 pat = NULL; 14646 } else { 14647 size_t len = strlen(pat); 14648 if (len > 0 && pat[len - 1] == '\"') 14649 pat[len - 1] = '\0'; 14650 if (len > 0 && pat[0] == '\"') 14651 pat++; 14652 } 14653 14654 ty = ptype; 14655 14656 get_prop_values(prop, values, pat); 14657 14658 if (isadd) 14659 add_string(values, arg); 14660 14661 if (scf_transaction_property_change(tx, e, 14662 propname, ty) == -1) 14663 scfdie(); 14664 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14665 if (isadd) { 14666 if (type == NULL) { 14667 semerr(gettext("Type required " 14668 "for new properties.\n")); 14669 goto fail; 14670 } 14671 14672 add_string(values, arg); 14673 14674 if (scf_transaction_property_new(tx, e, 14675 propname, ty) == -1) 14676 scfdie(); 14677 } else if (isnotfoundok) { 14678 result = 0; 14679 goto out; 14680 } else { 14681 semerr(gettext("No such property %s/%s.\n"), 14682 pgname, propname); 14683 result = -1; 14684 goto out; 14685 } 14686 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14687 semerr(emsg_invalid_prop_name, propname); 14688 goto fail; 14689 } else { 14690 scfdie(); 14691 } 14692 14693 walk = uu_list_walk_start(values, UU_DEFAULT); 14694 if (walk == NULL) 14695 uu_die(gettext("Could not walk property list.\n")); 14696 14697 for (sp = uu_list_walk_next(walk); sp != NULL; 14698 sp = uu_list_walk_next(walk)) { 14699 v = string_to_value(sp->str, ty, 0); 14700 14701 if (v == NULL) { 14702 scf_entry_destroy_children(e); 14703 goto fail; 14704 } 14705 ret = scf_entry_add_value(e, v); 14706 assert(ret == 0); 14707 } 14708 uu_list_walk_end(walk); 14709 14710 result = scf_transaction_commit(tx); 14711 14712 scf_transaction_reset(tx); 14713 scf_entry_destroy_children(e); 14714 } while (result == 0); 14715 14716 if (result < 0) { 14717 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14718 scfdie(); 14719 14720 semerr(emsg_permission_denied); 14721 goto fail; 14722 } 14723 14724 result = 0; 14725 14726 private_refresh(); 14727 14728 out: 14729 scf_transaction_destroy(tx); 14730 scf_entry_destroy(e); 14731 scf_pg_destroy(pg); 14732 scf_property_destroy(prop); 14733 free(pattern); 14734 14735 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14736 free(sp->str); 14737 free(sp); 14738 } 14739 14740 uu_list_destroy(values); 14741 14742 return (result); 14743 14744 fail: 14745 result = -1; 14746 goto out; 14747 } 14748 14749 int 14750 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14751 { 14752 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14753 } 14754 14755 int 14756 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14757 { 14758 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14759 } 14760 14761 /* 14762 * Look for a standard start method, first in the instance (if any), 14763 * then the service. 14764 */ 14765 static const char * 14766 start_method_name(int *in_instance) 14767 { 14768 scf_propertygroup_t *pg; 14769 char **p; 14770 int ret; 14771 scf_instance_t *inst = cur_inst; 14772 14773 if ((pg = scf_pg_create(g_hndl)) == NULL) 14774 scfdie(); 14775 14776 again: 14777 for (p = start_method_names; *p != NULL; p++) { 14778 if (inst != NULL) 14779 ret = scf_instance_get_pg(inst, *p, pg); 14780 else 14781 ret = scf_service_get_pg(cur_svc, *p, pg); 14782 14783 if (ret == 0) { 14784 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14785 char *buf = safe_malloc(bufsz); 14786 14787 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14788 free(buf); 14789 continue; 14790 } 14791 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14792 free(buf); 14793 continue; 14794 } 14795 14796 free(buf); 14797 *in_instance = (inst != NULL); 14798 scf_pg_destroy(pg); 14799 return (*p); 14800 } 14801 14802 if (scf_error() == SCF_ERROR_NOT_FOUND) 14803 continue; 14804 14805 scfdie(); 14806 } 14807 14808 if (inst != NULL) { 14809 inst = NULL; 14810 goto again; 14811 } 14812 14813 scf_pg_destroy(pg); 14814 return (NULL); 14815 } 14816 14817 static int 14818 addpg(const char *name, const char *type) 14819 { 14820 scf_propertygroup_t *pg; 14821 int ret; 14822 14823 pg = scf_pg_create(g_hndl); 14824 if (pg == NULL) 14825 scfdie(); 14826 14827 if (cur_inst != NULL) 14828 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14829 else 14830 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14831 14832 if (ret != 0) { 14833 switch (scf_error()) { 14834 case SCF_ERROR_EXISTS: 14835 ret = 0; 14836 break; 14837 14838 case SCF_ERROR_PERMISSION_DENIED: 14839 semerr(emsg_permission_denied); 14840 break; 14841 14842 default: 14843 scfdie(); 14844 } 14845 } 14846 14847 scf_pg_destroy(pg); 14848 return (ret); 14849 } 14850 14851 int 14852 lscf_setenv(uu_list_t *args, int isunset) 14853 { 14854 int ret = 0; 14855 size_t i; 14856 int argc; 14857 char **argv = NULL; 14858 string_list_t *slp; 14859 char *pattern; 14860 char *prop; 14861 int do_service = 0; 14862 int do_instance = 0; 14863 const char *method = NULL; 14864 const char *name = NULL; 14865 const char *value = NULL; 14866 scf_instance_t *saved_cur_inst = cur_inst; 14867 14868 lscf_prep_hndl(); 14869 14870 argc = uu_list_numnodes(args); 14871 if (argc < 1) 14872 goto usage; 14873 14874 argv = calloc(argc + 1, sizeof (char *)); 14875 if (argv == NULL) 14876 uu_die(gettext("Out of memory.\n")); 14877 14878 for (slp = uu_list_first(args), i = 0; 14879 slp != NULL; 14880 slp = uu_list_next(args, slp), ++i) 14881 argv[i] = slp->str; 14882 14883 argv[i] = NULL; 14884 14885 opterr = 0; 14886 optind = 0; 14887 for (;;) { 14888 ret = getopt(argc, argv, "sim:"); 14889 if (ret == -1) 14890 break; 14891 14892 switch (ret) { 14893 case 's': 14894 do_service = 1; 14895 cur_inst = NULL; 14896 break; 14897 14898 case 'i': 14899 do_instance = 1; 14900 break; 14901 14902 case 'm': 14903 method = optarg; 14904 break; 14905 14906 case '?': 14907 goto usage; 14908 14909 default: 14910 bad_error("getopt", ret); 14911 } 14912 } 14913 14914 argc -= optind; 14915 if ((do_service && do_instance) || 14916 (isunset && argc != 1) || 14917 (!isunset && argc != 2)) 14918 goto usage; 14919 14920 name = argv[optind]; 14921 if (!isunset) 14922 value = argv[optind + 1]; 14923 14924 if (cur_snap != NULL) { 14925 semerr(emsg_cant_modify_snapshots); 14926 ret = -1; 14927 goto out; 14928 } 14929 14930 if (cur_inst == NULL && cur_svc == NULL) { 14931 semerr(emsg_entity_not_selected); 14932 ret = -1; 14933 goto out; 14934 } 14935 14936 if (do_instance && cur_inst == NULL) { 14937 semerr(gettext("No instance is selected.\n")); 14938 ret = -1; 14939 goto out; 14940 } 14941 14942 if (do_service && cur_svc == NULL) { 14943 semerr(gettext("No service is selected.\n")); 14944 ret = -1; 14945 goto out; 14946 } 14947 14948 if (method == NULL) { 14949 if (do_instance || do_service) { 14950 method = "method_context"; 14951 if (!isunset) { 14952 ret = addpg("method_context", 14953 SCF_GROUP_FRAMEWORK); 14954 if (ret != 0) 14955 goto out; 14956 } 14957 } else { 14958 int in_instance; 14959 method = start_method_name(&in_instance); 14960 if (method == NULL) { 14961 semerr(gettext( 14962 "Couldn't find start method; please " 14963 "specify a method with '-m'.\n")); 14964 ret = -1; 14965 goto out; 14966 } 14967 if (!in_instance) 14968 cur_inst = NULL; 14969 } 14970 } else { 14971 scf_propertygroup_t *pg; 14972 size_t bufsz; 14973 char *buf; 14974 int ret; 14975 14976 if ((pg = scf_pg_create(g_hndl)) == NULL) 14977 scfdie(); 14978 14979 if (cur_inst != NULL) 14980 ret = scf_instance_get_pg(cur_inst, method, pg); 14981 else 14982 ret = scf_service_get_pg(cur_svc, method, pg); 14983 14984 if (ret != 0) { 14985 scf_pg_destroy(pg); 14986 switch (scf_error()) { 14987 case SCF_ERROR_NOT_FOUND: 14988 semerr(gettext("Couldn't find the method " 14989 "\"%s\".\n"), method); 14990 goto out; 14991 14992 case SCF_ERROR_INVALID_ARGUMENT: 14993 semerr(gettext("Invalid method name \"%s\".\n"), 14994 method); 14995 goto out; 14996 14997 default: 14998 scfdie(); 14999 } 15000 } 15001 15002 bufsz = strlen(SCF_GROUP_METHOD) + 1; 15003 buf = safe_malloc(bufsz); 15004 15005 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 15006 strcmp(buf, SCF_GROUP_METHOD) != 0) { 15007 semerr(gettext("Property group \"%s\" is not of type " 15008 "\"method\".\n"), method); 15009 ret = -1; 15010 free(buf); 15011 scf_pg_destroy(pg); 15012 goto out; 15013 } 15014 15015 free(buf); 15016 scf_pg_destroy(pg); 15017 } 15018 15019 prop = uu_msprintf("%s/environment", method); 15020 pattern = uu_msprintf("%s=*", name); 15021 15022 if (prop == NULL || pattern == NULL) 15023 uu_die(gettext("Out of memory.\n")); 15024 15025 ret = lscf_delpropvalue(prop, pattern, !isunset); 15026 15027 if (ret == 0 && !isunset) { 15028 uu_free(pattern); 15029 uu_free(prop); 15030 prop = uu_msprintf("%s/environment", method); 15031 pattern = uu_msprintf("%s=%s", name, value); 15032 if (prop == NULL || pattern == NULL) 15033 uu_die(gettext("Out of memory.\n")); 15034 ret = lscf_addpropvalue(prop, "astring:", pattern); 15035 } 15036 uu_free(pattern); 15037 uu_free(prop); 15038 15039 out: 15040 cur_inst = saved_cur_inst; 15041 15042 free(argv); 15043 return (ret); 15044 usage: 15045 ret = -2; 15046 goto out; 15047 } 15048 15049 /* 15050 * Snapshot commands 15051 */ 15052 15053 void 15054 lscf_listsnap() 15055 { 15056 scf_snapshot_t *snap; 15057 scf_iter_t *iter; 15058 char *nb; 15059 int r; 15060 15061 lscf_prep_hndl(); 15062 15063 if (cur_inst == NULL) { 15064 semerr(gettext("Instance not selected.\n")); 15065 return; 15066 } 15067 15068 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15069 (iter = scf_iter_create(g_hndl)) == NULL) 15070 scfdie(); 15071 15072 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 15073 scfdie(); 15074 15075 nb = safe_malloc(max_scf_name_len + 1); 15076 15077 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 15078 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 15079 scfdie(); 15080 15081 (void) puts(nb); 15082 } 15083 if (r < 0) 15084 scfdie(); 15085 15086 free(nb); 15087 scf_iter_destroy(iter); 15088 scf_snapshot_destroy(snap); 15089 } 15090 15091 void 15092 lscf_selectsnap(const char *name) 15093 { 15094 scf_snapshot_t *snap; 15095 scf_snaplevel_t *level; 15096 15097 lscf_prep_hndl(); 15098 15099 if (cur_inst == NULL) { 15100 semerr(gettext("Instance not selected.\n")); 15101 return; 15102 } 15103 15104 if (cur_snap != NULL) { 15105 if (name != NULL) { 15106 char *cur_snap_name; 15107 boolean_t nochange; 15108 15109 cur_snap_name = safe_malloc(max_scf_name_len + 1); 15110 15111 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 15112 max_scf_name_len + 1) < 0) 15113 scfdie(); 15114 15115 nochange = strcmp(name, cur_snap_name) == 0; 15116 15117 free(cur_snap_name); 15118 15119 if (nochange) 15120 return; 15121 } 15122 15123 unselect_cursnap(); 15124 } 15125 15126 if (name == NULL) 15127 return; 15128 15129 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15130 (level = scf_snaplevel_create(g_hndl)) == NULL) 15131 scfdie(); 15132 15133 if (scf_instance_get_snapshot(cur_inst, name, snap) != 15134 SCF_SUCCESS) { 15135 switch (scf_error()) { 15136 case SCF_ERROR_INVALID_ARGUMENT: 15137 semerr(gettext("Invalid name \"%s\".\n"), name); 15138 break; 15139 15140 case SCF_ERROR_NOT_FOUND: 15141 semerr(gettext("No such snapshot \"%s\".\n"), name); 15142 break; 15143 15144 default: 15145 scfdie(); 15146 } 15147 15148 scf_snaplevel_destroy(level); 15149 scf_snapshot_destroy(snap); 15150 return; 15151 } 15152 15153 /* Load the snaplevels into our list. */ 15154 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 15155 if (cur_levels == NULL) 15156 uu_die(gettext("Could not create list: %s\n"), 15157 uu_strerror(uu_error())); 15158 15159 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15160 if (scf_error() != SCF_ERROR_NOT_FOUND) 15161 scfdie(); 15162 15163 semerr(gettext("Snapshot has no snaplevels.\n")); 15164 15165 scf_snaplevel_destroy(level); 15166 scf_snapshot_destroy(snap); 15167 return; 15168 } 15169 15170 cur_snap = snap; 15171 15172 for (;;) { 15173 cur_elt = safe_malloc(sizeof (*cur_elt)); 15174 uu_list_node_init(cur_elt, &cur_elt->list_node, 15175 snaplevel_pool); 15176 cur_elt->sl = level; 15177 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 15178 uu_die(gettext("libuutil error: %s\n"), 15179 uu_strerror(uu_error())); 15180 15181 level = scf_snaplevel_create(g_hndl); 15182 if (level == NULL) 15183 scfdie(); 15184 15185 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 15186 level) != SCF_SUCCESS) { 15187 if (scf_error() != SCF_ERROR_NOT_FOUND) 15188 scfdie(); 15189 15190 scf_snaplevel_destroy(level); 15191 break; 15192 } 15193 } 15194 15195 cur_elt = uu_list_last(cur_levels); 15196 cur_level = cur_elt->sl; 15197 } 15198 15199 /* 15200 * Copies the properties & values in src to dst. Assumes src won't change. 15201 * Returns -1 if permission is denied, -2 if another transaction interrupts, 15202 * and 0 on success. 15203 * 15204 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 15205 * property, if it is copied and has type boolean. (See comment in 15206 * lscf_revert()). 15207 */ 15208 static int 15209 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 15210 uint8_t enabled) 15211 { 15212 scf_transaction_t *tx; 15213 scf_iter_t *iter, *viter; 15214 scf_property_t *prop; 15215 scf_value_t *v; 15216 char *nbuf; 15217 int r; 15218 15219 tx = scf_transaction_create(g_hndl); 15220 if (tx == NULL) 15221 scfdie(); 15222 15223 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 15224 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15225 scfdie(); 15226 15227 scf_transaction_destroy(tx); 15228 15229 return (-1); 15230 } 15231 15232 if ((iter = scf_iter_create(g_hndl)) == NULL || 15233 (prop = scf_property_create(g_hndl)) == NULL || 15234 (viter = scf_iter_create(g_hndl)) == NULL) 15235 scfdie(); 15236 15237 nbuf = safe_malloc(max_scf_name_len + 1); 15238 15239 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 15240 scfdie(); 15241 15242 for (;;) { 15243 scf_transaction_entry_t *e; 15244 scf_type_t ty; 15245 15246 r = scf_iter_next_property(iter, prop); 15247 if (r == -1) 15248 scfdie(); 15249 if (r == 0) 15250 break; 15251 15252 e = scf_entry_create(g_hndl); 15253 if (e == NULL) 15254 scfdie(); 15255 15256 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 15257 scfdie(); 15258 15259 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 15260 scfdie(); 15261 15262 if (scf_transaction_property_new(tx, e, nbuf, 15263 ty) != SCF_SUCCESS) 15264 scfdie(); 15265 15266 if ((enabled == 0 || enabled == 1) && 15267 strcmp(nbuf, scf_property_enabled) == 0 && 15268 ty == SCF_TYPE_BOOLEAN) { 15269 v = scf_value_create(g_hndl); 15270 if (v == NULL) 15271 scfdie(); 15272 15273 scf_value_set_boolean(v, enabled); 15274 15275 if (scf_entry_add_value(e, v) != 0) 15276 scfdie(); 15277 } else { 15278 if (scf_iter_property_values(viter, prop) != 0) 15279 scfdie(); 15280 15281 for (;;) { 15282 v = scf_value_create(g_hndl); 15283 if (v == NULL) 15284 scfdie(); 15285 15286 r = scf_iter_next_value(viter, v); 15287 if (r == -1) 15288 scfdie(); 15289 if (r == 0) { 15290 scf_value_destroy(v); 15291 break; 15292 } 15293 15294 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 15295 scfdie(); 15296 } 15297 } 15298 } 15299 15300 free(nbuf); 15301 scf_iter_destroy(viter); 15302 scf_property_destroy(prop); 15303 scf_iter_destroy(iter); 15304 15305 r = scf_transaction_commit(tx); 15306 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 15307 scfdie(); 15308 15309 scf_transaction_destroy_children(tx); 15310 scf_transaction_destroy(tx); 15311 15312 switch (r) { 15313 case 1: return (0); 15314 case 0: return (-2); 15315 case -1: return (-1); 15316 15317 default: 15318 abort(); 15319 } 15320 15321 /* NOTREACHED */ 15322 } 15323 15324 void 15325 lscf_revert(const char *snapname) 15326 { 15327 scf_snapshot_t *snap, *prev; 15328 scf_snaplevel_t *level, *nlevel; 15329 scf_iter_t *iter; 15330 scf_propertygroup_t *pg, *npg; 15331 scf_property_t *prop; 15332 scf_value_t *val; 15333 char *nbuf, *tbuf; 15334 uint8_t enabled; 15335 15336 lscf_prep_hndl(); 15337 15338 if (cur_inst == NULL) { 15339 semerr(gettext("Instance not selected.\n")); 15340 return; 15341 } 15342 15343 if (snapname != NULL) { 15344 snap = scf_snapshot_create(g_hndl); 15345 if (snap == NULL) 15346 scfdie(); 15347 15348 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 15349 SCF_SUCCESS) { 15350 switch (scf_error()) { 15351 case SCF_ERROR_INVALID_ARGUMENT: 15352 semerr(gettext("Invalid snapshot name " 15353 "\"%s\".\n"), snapname); 15354 break; 15355 15356 case SCF_ERROR_NOT_FOUND: 15357 semerr(gettext("No such snapshot.\n")); 15358 break; 15359 15360 default: 15361 scfdie(); 15362 } 15363 15364 scf_snapshot_destroy(snap); 15365 return; 15366 } 15367 } else { 15368 if (cur_snap != NULL) { 15369 snap = cur_snap; 15370 } else { 15371 semerr(gettext("No snapshot selected.\n")); 15372 return; 15373 } 15374 } 15375 15376 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 15377 (level = scf_snaplevel_create(g_hndl)) == NULL || 15378 (iter = scf_iter_create(g_hndl)) == NULL || 15379 (pg = scf_pg_create(g_hndl)) == NULL || 15380 (npg = scf_pg_create(g_hndl)) == NULL || 15381 (prop = scf_property_create(g_hndl)) == NULL || 15382 (val = scf_value_create(g_hndl)) == NULL) 15383 scfdie(); 15384 15385 nbuf = safe_malloc(max_scf_name_len + 1); 15386 tbuf = safe_malloc(max_scf_pg_type_len + 1); 15387 15388 /* Take the "previous" snapshot before we blow away the properties. */ 15389 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 15390 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 15391 scfdie(); 15392 } else { 15393 if (scf_error() != SCF_ERROR_NOT_FOUND) 15394 scfdie(); 15395 15396 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 15397 scfdie(); 15398 } 15399 15400 /* Save general/enabled, since we're probably going to replace it. */ 15401 enabled = 2; 15402 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 15403 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 15404 scf_property_get_value(prop, val) == 0) 15405 (void) scf_value_get_boolean(val, &enabled); 15406 15407 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15408 if (scf_error() != SCF_ERROR_NOT_FOUND) 15409 scfdie(); 15410 15411 goto out; 15412 } 15413 15414 for (;;) { 15415 boolean_t isinst; 15416 uint32_t flags; 15417 int r; 15418 15419 /* Clear the properties from the corresponding entity. */ 15420 isinst = snaplevel_is_instance(level); 15421 15422 if (!isinst) 15423 r = scf_iter_service_pgs(iter, cur_svc); 15424 else 15425 r = scf_iter_instance_pgs(iter, cur_inst); 15426 if (r != SCF_SUCCESS) 15427 scfdie(); 15428 15429 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15430 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15431 scfdie(); 15432 15433 /* Skip nonpersistent pgs. */ 15434 if (flags & SCF_PG_FLAG_NONPERSISTENT) 15435 continue; 15436 15437 if (scf_pg_delete(pg) != SCF_SUCCESS) { 15438 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15439 scfdie(); 15440 15441 semerr(emsg_permission_denied); 15442 goto out; 15443 } 15444 } 15445 if (r == -1) 15446 scfdie(); 15447 15448 /* Copy the properties to the corresponding entity. */ 15449 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 15450 scfdie(); 15451 15452 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15453 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 15454 scfdie(); 15455 15456 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 15457 0) 15458 scfdie(); 15459 15460 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15461 scfdie(); 15462 15463 if (!isinst) 15464 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 15465 flags, npg); 15466 else 15467 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 15468 flags, npg); 15469 if (r != SCF_SUCCESS) { 15470 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15471 scfdie(); 15472 15473 semerr(emsg_permission_denied); 15474 goto out; 15475 } 15476 15477 if ((enabled == 0 || enabled == 1) && 15478 strcmp(nbuf, scf_pg_general) == 0) 15479 r = pg_copy(pg, npg, enabled); 15480 else 15481 r = pg_copy(pg, npg, 2); 15482 15483 switch (r) { 15484 case 0: 15485 break; 15486 15487 case -1: 15488 semerr(emsg_permission_denied); 15489 goto out; 15490 15491 case -2: 15492 semerr(gettext( 15493 "Interrupted by another change.\n")); 15494 goto out; 15495 15496 default: 15497 abort(); 15498 } 15499 } 15500 if (r == -1) 15501 scfdie(); 15502 15503 /* Get next level. */ 15504 nlevel = scf_snaplevel_create(g_hndl); 15505 if (nlevel == NULL) 15506 scfdie(); 15507 15508 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 15509 SCF_SUCCESS) { 15510 if (scf_error() != SCF_ERROR_NOT_FOUND) 15511 scfdie(); 15512 15513 scf_snaplevel_destroy(nlevel); 15514 break; 15515 } 15516 15517 scf_snaplevel_destroy(level); 15518 level = nlevel; 15519 } 15520 15521 if (snapname == NULL) { 15522 lscf_selectsnap(NULL); 15523 snap = NULL; /* cur_snap has been destroyed */ 15524 } 15525 15526 out: 15527 free(tbuf); 15528 free(nbuf); 15529 scf_value_destroy(val); 15530 scf_property_destroy(prop); 15531 scf_pg_destroy(npg); 15532 scf_pg_destroy(pg); 15533 scf_iter_destroy(iter); 15534 scf_snaplevel_destroy(level); 15535 scf_snapshot_destroy(prev); 15536 if (snap != cur_snap) 15537 scf_snapshot_destroy(snap); 15538 } 15539 15540 void 15541 lscf_refresh(void) 15542 { 15543 ssize_t fmrilen; 15544 size_t bufsz; 15545 char *fmribuf; 15546 int r; 15547 15548 lscf_prep_hndl(); 15549 15550 if (cur_inst == NULL) { 15551 semerr(gettext("Instance not selected.\n")); 15552 return; 15553 } 15554 15555 bufsz = max_scf_fmri_len + 1; 15556 fmribuf = safe_malloc(bufsz); 15557 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15558 if (fmrilen < 0) { 15559 free(fmribuf); 15560 if (scf_error() != SCF_ERROR_DELETED) 15561 scfdie(); 15562 scf_instance_destroy(cur_inst); 15563 cur_inst = NULL; 15564 warn(emsg_deleted); 15565 return; 15566 } 15567 assert(fmrilen < bufsz); 15568 15569 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15570 switch (r) { 15571 case 0: 15572 break; 15573 15574 case ECONNABORTED: 15575 warn(gettext("Could not refresh %s " 15576 "(repository connection broken).\n"), fmribuf); 15577 break; 15578 15579 case ECANCELED: 15580 warn(emsg_deleted); 15581 break; 15582 15583 case EPERM: 15584 warn(gettext("Could not refresh %s " 15585 "(permission denied).\n"), fmribuf); 15586 break; 15587 15588 case ENOSPC: 15589 warn(gettext("Could not refresh %s " 15590 "(repository server out of resources).\n"), 15591 fmribuf); 15592 break; 15593 15594 case EACCES: 15595 default: 15596 bad_error("refresh_entity", scf_error()); 15597 } 15598 15599 free(fmribuf); 15600 } 15601 15602 /* 15603 * describe [-v] [-t] [pg/prop] 15604 */ 15605 int 15606 lscf_describe(uu_list_t *args, int hasargs) 15607 { 15608 int ret = 0; 15609 size_t i; 15610 int argc; 15611 char **argv = NULL; 15612 string_list_t *slp; 15613 int do_verbose = 0; 15614 int do_templates = 0; 15615 char *pattern = NULL; 15616 15617 lscf_prep_hndl(); 15618 15619 if (hasargs != 0) { 15620 argc = uu_list_numnodes(args); 15621 if (argc < 1) 15622 goto usage; 15623 15624 argv = calloc(argc + 1, sizeof (char *)); 15625 if (argv == NULL) 15626 uu_die(gettext("Out of memory.\n")); 15627 15628 for (slp = uu_list_first(args), i = 0; 15629 slp != NULL; 15630 slp = uu_list_next(args, slp), ++i) 15631 argv[i] = slp->str; 15632 15633 argv[i] = NULL; 15634 15635 /* 15636 * We start optind = 0 because our list of arguments 15637 * starts at argv[0] 15638 */ 15639 optind = 0; 15640 opterr = 0; 15641 for (;;) { 15642 ret = getopt(argc, argv, "vt"); 15643 if (ret == -1) 15644 break; 15645 15646 switch (ret) { 15647 case 'v': 15648 do_verbose = 1; 15649 break; 15650 15651 case 't': 15652 do_templates = 1; 15653 break; 15654 15655 case '?': 15656 goto usage; 15657 15658 default: 15659 bad_error("getopt", ret); 15660 } 15661 } 15662 15663 pattern = argv[optind]; 15664 } 15665 15666 if (cur_inst == NULL && cur_svc == NULL) { 15667 semerr(emsg_entity_not_selected); 15668 ret = -1; 15669 goto out; 15670 } 15671 15672 /* 15673 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15674 * output if their last parameter is set to 2. Less information is 15675 * produced if the parameter is set to 1. 15676 */ 15677 if (pattern == NULL) { 15678 if (do_verbose == 1) 15679 list_entity_tmpl(2); 15680 else 15681 list_entity_tmpl(1); 15682 } 15683 15684 if (do_templates == 0) { 15685 if (do_verbose == 1) 15686 listprop(pattern, 0, 2); 15687 else 15688 listprop(pattern, 0, 1); 15689 } else { 15690 if (do_verbose == 1) 15691 listtmpl(pattern, 2); 15692 else 15693 listtmpl(pattern, 1); 15694 } 15695 15696 ret = 0; 15697 out: 15698 if (argv != NULL) 15699 free(argv); 15700 return (ret); 15701 usage: 15702 ret = -2; 15703 goto out; 15704 } 15705 15706 #define PARAM_ACTIVE ((const char *) "active") 15707 #define PARAM_INACTIVE ((const char *) "inactive") 15708 #define PARAM_SMTP_TO ((const char *) "to") 15709 15710 /* 15711 * tokenize() 15712 * Breaks down the string according to the tokens passed. 15713 * Caller is responsible for freeing array of pointers returned. 15714 * Returns NULL on failure 15715 */ 15716 char ** 15717 tokenize(char *str, const char *sep) 15718 { 15719 char *token, *lasts; 15720 char **buf; 15721 int n = 0; /* number of elements */ 15722 int size = 8; /* size of the array (initial) */ 15723 15724 buf = safe_malloc(size * sizeof (char *)); 15725 15726 for (token = strtok_r(str, sep, &lasts); token != NULL; 15727 token = strtok_r(NULL, sep, &lasts), ++n) { 15728 if (n + 1 >= size) { 15729 size *= 2; 15730 if ((buf = realloc(buf, size * sizeof (char *))) == 15731 NULL) { 15732 uu_die(gettext("Out of memory")); 15733 } 15734 } 15735 buf[n] = token; 15736 } 15737 /* NULL terminate the pointer array */ 15738 buf[n] = NULL; 15739 15740 return (buf); 15741 } 15742 15743 int32_t 15744 check_tokens(char **p) 15745 { 15746 int32_t smf = 0; 15747 int32_t fma = 0; 15748 15749 while (*p) { 15750 int32_t t = string_to_tset(*p); 15751 15752 if (t == 0) { 15753 if (is_fma_token(*p) == 0) 15754 return (INVALID_TOKENS); 15755 fma = 1; /* this token is an fma event */ 15756 } else { 15757 smf |= t; 15758 } 15759 15760 if (smf != 0 && fma == 1) 15761 return (MIXED_TOKENS); 15762 ++p; 15763 } 15764 15765 if (smf > 0) 15766 return (smf); 15767 else if (fma == 1) 15768 return (FMA_TOKENS); 15769 15770 return (INVALID_TOKENS); 15771 } 15772 15773 static int 15774 get_selection_str(char *fmri, size_t sz) 15775 { 15776 if (g_hndl == NULL) { 15777 semerr(emsg_entity_not_selected); 15778 return (-1); 15779 } else if (cur_level != NULL) { 15780 semerr(emsg_invalid_for_snapshot); 15781 return (-1); 15782 } else { 15783 lscf_get_selection_str(fmri, sz); 15784 } 15785 15786 return (0); 15787 } 15788 15789 void 15790 lscf_delnotify(const char *set, int global) 15791 { 15792 char *str = strdup(set); 15793 char **pgs; 15794 char **p; 15795 int32_t tset; 15796 char *fmri = NULL; 15797 15798 if (str == NULL) 15799 uu_die(gettext("Out of memory.\n")); 15800 15801 pgs = tokenize(str, ","); 15802 15803 if ((tset = check_tokens(pgs)) > 0) { 15804 size_t sz = max_scf_fmri_len + 1; 15805 15806 fmri = safe_malloc(sz); 15807 if (global) { 15808 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15809 } else if (get_selection_str(fmri, sz) != 0) { 15810 goto out; 15811 } 15812 15813 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri, 15814 tset) != SCF_SUCCESS) { 15815 uu_warn(gettext("Failed smf_notify_del_params: %s\n"), 15816 scf_strerror(scf_error())); 15817 } 15818 } else if (tset == FMA_TOKENS) { 15819 if (global) { 15820 semerr(gettext("Can't use option '-g' with FMA event " 15821 "definitions\n")); 15822 goto out; 15823 } 15824 15825 for (p = pgs; *p; ++p) { 15826 if (smf_notify_del_params(de_tag(*p), NULL, 0) != 15827 SCF_SUCCESS) { 15828 uu_warn(gettext("Failed for \"%s\": %s\n"), *p, 15829 scf_strerror(scf_error())); 15830 goto out; 15831 } 15832 } 15833 } else if (tset == MIXED_TOKENS) { 15834 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15835 goto out; 15836 } else { 15837 uu_die(gettext("Invalid input.\n")); 15838 } 15839 15840 out: 15841 free(fmri); 15842 free(pgs); 15843 free(str); 15844 } 15845 15846 void 15847 lscf_listnotify(const char *set, int global) 15848 { 15849 char *str = safe_strdup(set); 15850 char **pgs; 15851 char **p; 15852 int32_t tset; 15853 nvlist_t *nvl; 15854 char *fmri = NULL; 15855 15856 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 15857 uu_die(gettext("Out of memory.\n")); 15858 15859 pgs = tokenize(str, ","); 15860 15861 if ((tset = check_tokens(pgs)) > 0) { 15862 size_t sz = max_scf_fmri_len + 1; 15863 15864 fmri = safe_malloc(sz); 15865 if (global) { 15866 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15867 } else if (get_selection_str(fmri, sz) != 0) { 15868 goto out; 15869 } 15870 15871 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) != 15872 SCF_SUCCESS) { 15873 if (scf_error() != SCF_ERROR_NOT_FOUND && 15874 scf_error() != SCF_ERROR_DELETED) 15875 uu_warn(gettext( 15876 "Failed listnotify: %s\n"), 15877 scf_strerror(scf_error())); 15878 goto out; 15879 } 15880 15881 listnotify_print(nvl, NULL); 15882 } else if (tset == FMA_TOKENS) { 15883 if (global) { 15884 semerr(gettext("Can't use option '-g' with FMA event " 15885 "definitions\n")); 15886 goto out; 15887 } 15888 15889 for (p = pgs; *p; ++p) { 15890 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) != 15891 SCF_SUCCESS) { 15892 /* 15893 * if the preferences have just been deleted 15894 * or does not exist, just skip. 15895 */ 15896 if (scf_error() == SCF_ERROR_NOT_FOUND || 15897 scf_error() == SCF_ERROR_DELETED) 15898 continue; 15899 uu_warn(gettext( 15900 "Failed listnotify: %s\n"), 15901 scf_strerror(scf_error())); 15902 goto out; 15903 } 15904 listnotify_print(nvl, re_tag(*p)); 15905 } 15906 } else if (tset == MIXED_TOKENS) { 15907 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15908 goto out; 15909 } else { 15910 semerr(gettext("Invalid input.\n")); 15911 } 15912 15913 out: 15914 nvlist_free(nvl); 15915 free(fmri); 15916 free(pgs); 15917 free(str); 15918 } 15919 15920 static char * 15921 strip_quotes_and_blanks(char *s) 15922 { 15923 char *start = s; 15924 char *end = strrchr(s, '\"'); 15925 15926 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') { 15927 start = s + 1; 15928 while (isblank(*start)) 15929 start++; 15930 while (isblank(*(end - 1)) && end > start) { 15931 end--; 15932 } 15933 *end = '\0'; 15934 } 15935 15936 return (start); 15937 } 15938 15939 static int 15940 set_active(nvlist_t *mech, const char *hier_part) 15941 { 15942 boolean_t b; 15943 15944 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) { 15945 b = B_TRUE; 15946 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) { 15947 b = B_FALSE; 15948 } else { 15949 return (-1); 15950 } 15951 15952 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0) 15953 uu_die(gettext("Out of memory.\n")); 15954 15955 return (0); 15956 } 15957 15958 static int 15959 add_snmp_params(nvlist_t *mech, char *hier_part) 15960 { 15961 return (set_active(mech, hier_part)); 15962 } 15963 15964 static int 15965 add_syslog_params(nvlist_t *mech, char *hier_part) 15966 { 15967 return (set_active(mech, hier_part)); 15968 } 15969 15970 /* 15971 * add_mailto_paramas() 15972 * parse the hier_part of mailto URI 15973 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]] 15974 * or mailto:{[active]|inactive} 15975 */ 15976 static int 15977 add_mailto_params(nvlist_t *mech, char *hier_part) 15978 { 15979 const char *tok = "?&"; 15980 char *p; 15981 char *lasts; 15982 char *param; 15983 char *val; 15984 15985 /* 15986 * If the notification parametes are in the form of 15987 * 15988 * malito:{[active]|inactive} 15989 * 15990 * we set the property accordingly and return. 15991 * Otherwise, we make the notification type active and 15992 * process the hier_part. 15993 */ 15994 if (set_active(mech, hier_part) == 0) 15995 return (0); 15996 else if (set_active(mech, PARAM_ACTIVE) != 0) 15997 return (-1); 15998 15999 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) { 16000 /* 16001 * sanity check: we only get here if hier_part = "", but 16002 * that's handled by set_active 16003 */ 16004 uu_die("strtok_r"); 16005 } 16006 16007 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0) 16008 uu_die(gettext("Out of memory.\n")); 16009 16010 while ((p = strtok_r(NULL, tok, &lasts)) != NULL) 16011 if ((param = strtok_r(p, "=", &val)) != NULL) 16012 if (nvlist_add_string(mech, param, val) != 0) 16013 uu_die(gettext("Out of memory.\n")); 16014 16015 return (0); 16016 } 16017 16018 static int 16019 uri_split(char *uri, char **scheme, char **hier_part) 16020 { 16021 int r = -1; 16022 16023 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL || 16024 *hier_part == NULL) { 16025 semerr(gettext("'%s' is not an URI\n"), uri); 16026 return (r); 16027 } 16028 16029 if ((r = check_uri_scheme(*scheme)) < 0) { 16030 semerr(gettext("Unkown URI scheme: %s\n"), *scheme); 16031 return (r); 16032 } 16033 16034 return (r); 16035 } 16036 16037 static int 16038 process_uri(nvlist_t *params, char *uri) 16039 { 16040 char *scheme; 16041 char *hier_part; 16042 nvlist_t *mech; 16043 int index; 16044 int r; 16045 16046 if ((index = uri_split(uri, &scheme, &hier_part)) < 0) 16047 return (-1); 16048 16049 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0) 16050 uu_die(gettext("Out of memory.\n")); 16051 16052 switch (index) { 16053 case 0: 16054 /* error messages displayed by called function */ 16055 r = add_mailto_params(mech, hier_part); 16056 break; 16057 16058 case 1: 16059 if ((r = add_snmp_params(mech, hier_part)) != 0) 16060 semerr(gettext("Not valid parameters: '%s'\n"), 16061 hier_part); 16062 break; 16063 16064 case 2: 16065 if ((r = add_syslog_params(mech, hier_part)) != 0) 16066 semerr(gettext("Not valid parameters: '%s'\n"), 16067 hier_part); 16068 break; 16069 16070 default: 16071 r = -1; 16072 } 16073 16074 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol, 16075 mech) != 0) 16076 uu_die(gettext("Out of memory.\n")); 16077 16078 nvlist_free(mech); 16079 return (r); 16080 } 16081 16082 static int 16083 set_params(nvlist_t *params, char **p) 16084 { 16085 char *uri; 16086 16087 if (p == NULL) 16088 /* sanity check */ 16089 uu_die("set_params"); 16090 16091 while (*p) { 16092 uri = strip_quotes_and_blanks(*p); 16093 if (process_uri(params, uri) != 0) 16094 return (-1); 16095 16096 ++p; 16097 } 16098 16099 return (0); 16100 } 16101 16102 static int 16103 setnotify(const char *e, char **p, int global) 16104 { 16105 char *str = safe_strdup(e); 16106 char **events; 16107 int32_t tset; 16108 int r = -1; 16109 nvlist_t *nvl, *params; 16110 char *fmri = NULL; 16111 16112 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 16113 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 || 16114 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 16115 SCF_NOTIFY_PARAMS_VERSION) != 0) 16116 uu_die(gettext("Out of memory.\n")); 16117 16118 events = tokenize(str, ","); 16119 16120 if ((tset = check_tokens(events)) > 0) { 16121 /* SMF state transitions parameters */ 16122 size_t sz = max_scf_fmri_len + 1; 16123 16124 fmri = safe_malloc(sz); 16125 if (global) { 16126 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 16127 } else if (get_selection_str(fmri, sz) != 0) { 16128 goto out; 16129 } 16130 16131 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 || 16132 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0) 16133 uu_die(gettext("Out of memory.\n")); 16134 16135 if ((r = set_params(params, p)) == 0) { 16136 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, 16137 params) != 0) 16138 uu_die(gettext("Out of memory.\n")); 16139 16140 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS, 16141 nvl) != SCF_SUCCESS) { 16142 r = -1; 16143 uu_warn(gettext( 16144 "Failed smf_notify_set_params(3SCF): %s\n"), 16145 scf_strerror(scf_error())); 16146 } 16147 } 16148 } else if (tset == FMA_TOKENS) { 16149 /* FMA event parameters */ 16150 if (global) { 16151 semerr(gettext("Can't use option '-g' with FMA event " 16152 "definitions\n")); 16153 goto out; 16154 } 16155 16156 if ((r = set_params(params, p)) != 0) 16157 goto out; 16158 16159 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0) 16160 uu_die(gettext("Out of memory.\n")); 16161 16162 while (*events) { 16163 if (smf_notify_set_params(de_tag(*events), nvl) != 16164 SCF_SUCCESS) 16165 uu_warn(gettext( 16166 "Failed smf_notify_set_params(3SCF) for " 16167 "event %s: %s\n"), *events, 16168 scf_strerror(scf_error())); 16169 events++; 16170 } 16171 } else if (tset == MIXED_TOKENS) { 16172 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 16173 } else { 16174 /* Sanity check */ 16175 uu_die(gettext("Invalid input.\n")); 16176 } 16177 16178 out: 16179 nvlist_free(nvl); 16180 nvlist_free(params); 16181 free(fmri); 16182 free(str); 16183 16184 return (r); 16185 } 16186 16187 int 16188 lscf_setnotify(uu_list_t *args) 16189 { 16190 int argc; 16191 char **argv = NULL; 16192 string_list_t *slp; 16193 int global; 16194 char *events; 16195 char **p; 16196 int i; 16197 int ret; 16198 16199 if ((argc = uu_list_numnodes(args)) < 2) 16200 goto usage; 16201 16202 argv = calloc(argc + 1, sizeof (char *)); 16203 if (argv == NULL) 16204 uu_die(gettext("Out of memory.\n")); 16205 16206 for (slp = uu_list_first(args), i = 0; 16207 slp != NULL; 16208 slp = uu_list_next(args, slp), ++i) 16209 argv[i] = slp->str; 16210 16211 argv[i] = NULL; 16212 16213 if (strcmp(argv[0], "-g") == 0) { 16214 global = 1; 16215 events = argv[1]; 16216 p = argv + 2; 16217 } else { 16218 global = 0; 16219 events = argv[0]; 16220 p = argv + 1; 16221 } 16222 16223 ret = setnotify(events, p, global); 16224 16225 out: 16226 free(argv); 16227 return (ret); 16228 16229 usage: 16230 ret = -2; 16231 goto out; 16232 } 16233 16234 /* 16235 * Creates a list of instance name strings associated with a service. If 16236 * wohandcrafted flag is set, get only instances that have a last-import 16237 * snapshot, instances that were imported via svccfg. 16238 */ 16239 static uu_list_t * 16240 create_instance_list(scf_service_t *svc, int wohandcrafted) 16241 { 16242 scf_snapshot_t *snap = NULL; 16243 scf_instance_t *inst; 16244 scf_iter_t *inst_iter; 16245 uu_list_t *instances; 16246 char *instname; 16247 int r; 16248 16249 inst_iter = scf_iter_create(g_hndl); 16250 inst = scf_instance_create(g_hndl); 16251 if (inst_iter == NULL || inst == NULL) { 16252 uu_warn(gettext("Could not create instance or iterator\n")); 16253 scfdie(); 16254 } 16255 16256 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 16257 return (instances); 16258 16259 if (scf_iter_service_instances(inst_iter, svc) != 0) { 16260 switch (scf_error()) { 16261 case SCF_ERROR_CONNECTION_BROKEN: 16262 case SCF_ERROR_DELETED: 16263 uu_list_destroy(instances); 16264 instances = NULL; 16265 goto out; 16266 16267 case SCF_ERROR_HANDLE_MISMATCH: 16268 case SCF_ERROR_NOT_BOUND: 16269 case SCF_ERROR_NOT_SET: 16270 default: 16271 bad_error("scf_iter_service_instances", scf_error()); 16272 } 16273 } 16274 16275 instname = safe_malloc(max_scf_name_len + 1); 16276 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 16277 if (r == -1) { 16278 (void) uu_warn(gettext("Unable to iterate through " 16279 "instances to create instance list : %s\n"), 16280 scf_strerror(scf_error())); 16281 16282 uu_list_destroy(instances); 16283 instances = NULL; 16284 goto out; 16285 } 16286 16287 /* 16288 * If the instance does not have a last-import snapshot 16289 * then do not add it to the list as it is a hand-crafted 16290 * instance that should not be managed. 16291 */ 16292 if (wohandcrafted) { 16293 if (snap == NULL && 16294 (snap = scf_snapshot_create(g_hndl)) == NULL) { 16295 uu_warn(gettext("Unable to create snapshot " 16296 "entity\n")); 16297 scfdie(); 16298 } 16299 16300 if (scf_instance_get_snapshot(inst, 16301 snap_lastimport, snap) != 0) { 16302 switch (scf_error()) { 16303 case SCF_ERROR_NOT_FOUND : 16304 case SCF_ERROR_DELETED: 16305 continue; 16306 16307 case SCF_ERROR_CONNECTION_BROKEN: 16308 uu_list_destroy(instances); 16309 instances = NULL; 16310 goto out; 16311 16312 case SCF_ERROR_HANDLE_MISMATCH: 16313 case SCF_ERROR_NOT_BOUND: 16314 case SCF_ERROR_NOT_SET: 16315 default: 16316 bad_error("scf_iter_service_instances", 16317 scf_error()); 16318 } 16319 } 16320 } 16321 16322 if (scf_instance_get_name(inst, instname, 16323 max_scf_name_len + 1) < 0) { 16324 switch (scf_error()) { 16325 case SCF_ERROR_NOT_FOUND : 16326 continue; 16327 16328 case SCF_ERROR_CONNECTION_BROKEN: 16329 case SCF_ERROR_DELETED: 16330 uu_list_destroy(instances); 16331 instances = NULL; 16332 goto out; 16333 16334 case SCF_ERROR_HANDLE_MISMATCH: 16335 case SCF_ERROR_NOT_BOUND: 16336 case SCF_ERROR_NOT_SET: 16337 default: 16338 bad_error("scf_iter_service_instances", 16339 scf_error()); 16340 } 16341 } 16342 16343 add_string(instances, instname); 16344 } 16345 16346 out: 16347 if (snap) 16348 scf_snapshot_destroy(snap); 16349 16350 scf_instance_destroy(inst); 16351 scf_iter_destroy(inst_iter); 16352 free(instname); 16353 return (instances); 16354 } 16355 16356 /* 16357 * disable an instance but wait for the instance to 16358 * move out of the running state. 16359 * 16360 * Returns 0 : if the instance did not disable 16361 * Returns non-zero : if the instance disabled. 16362 * 16363 */ 16364 static int 16365 disable_instance(scf_instance_t *instance) 16366 { 16367 char *fmribuf; 16368 int enabled = 10000; 16369 16370 if (inst_is_running(instance)) { 16371 fmribuf = safe_malloc(max_scf_name_len + 1); 16372 if (scf_instance_to_fmri(instance, fmribuf, 16373 max_scf_name_len + 1) < 0) { 16374 free(fmribuf); 16375 return (0); 16376 } 16377 16378 /* 16379 * If the instance cannot be disabled then return 16380 * failure to disable and let the caller decide 16381 * if that is of importance. 16382 */ 16383 if (smf_disable_instance(fmribuf, 0) != 0) { 16384 free(fmribuf); 16385 return (0); 16386 } 16387 16388 while (enabled) { 16389 if (!inst_is_running(instance)) 16390 break; 16391 16392 (void) poll(NULL, 0, 5); 16393 enabled = enabled - 5; 16394 } 16395 16396 free(fmribuf); 16397 } 16398 16399 return (enabled); 16400 } 16401 16402 /* 16403 * Function to compare two service_manifest structures. 16404 */ 16405 /* ARGSUSED2 */ 16406 static int 16407 service_manifest_compare(const void *left, const void *right, void *unused) 16408 { 16409 service_manifest_t *l = (service_manifest_t *)left; 16410 service_manifest_t *r = (service_manifest_t *)right; 16411 int rc; 16412 16413 rc = strcmp(l->servicename, r->servicename); 16414 16415 return (rc); 16416 } 16417 16418 /* 16419 * Look for the provided service in the service to manifest 16420 * tree. If the service exists, and a manifest was provided 16421 * then add the manifest to that service. If the service 16422 * does not exist, then add the service and manifest to the 16423 * list. 16424 * 16425 * If the manifest is NULL, return the element if found. If 16426 * the service is not found return NULL. 16427 */ 16428 service_manifest_t * 16429 find_add_svc_mfst(const char *svnbuf, const char *mfst) 16430 { 16431 service_manifest_t elem; 16432 service_manifest_t *fnelem; 16433 uu_avl_index_t marker; 16434 16435 elem.servicename = svnbuf; 16436 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 16437 16438 if (mfst) { 16439 if (fnelem) { 16440 add_string(fnelem->mfstlist, strdup(mfst)); 16441 } else { 16442 fnelem = safe_malloc(sizeof (*fnelem)); 16443 fnelem->servicename = safe_strdup(svnbuf); 16444 if ((fnelem->mfstlist = 16445 uu_list_create(string_pool, NULL, 0)) == NULL) 16446 uu_die(gettext("Could not create property " 16447 "list: %s\n"), uu_strerror(uu_error())); 16448 16449 add_string(fnelem->mfstlist, safe_strdup(mfst)); 16450 16451 uu_avl_insert(service_manifest_tree, fnelem, marker); 16452 } 16453 } 16454 16455 return (fnelem); 16456 } 16457 16458 /* 16459 * Create the service to manifest avl tree. 16460 * 16461 * Walk each of the manifests currently installed in the supported 16462 * directories, /lib/svc/manifests and /var/svc/manifests. For 16463 * each of the manifests, inventory the services and add them to 16464 * the tree. 16465 * 16466 * Code that calls this function should make sure fileystem/minimal is online, 16467 * /var is available, since this function walks the /var/svc/manifest directory. 16468 */ 16469 static void 16470 create_manifest_tree(void) 16471 { 16472 manifest_info_t **entry; 16473 manifest_info_t **manifests; 16474 uu_list_walk_t *svcs; 16475 bundle_t *b; 16476 entity_t *mfsvc; 16477 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 16478 int c, status; 16479 16480 if (service_manifest_pool) 16481 return; 16482 16483 /* 16484 * Create the list pool for the service manifest list 16485 */ 16486 service_manifest_pool = uu_avl_pool_create("service_manifest", 16487 sizeof (service_manifest_t), 16488 offsetof(service_manifest_t, svcmfst_node), 16489 service_manifest_compare, UU_DEFAULT); 16490 if (service_manifest_pool == NULL) 16491 uu_die(gettext("service_manifest pool creation failed: %s\n"), 16492 uu_strerror(uu_error())); 16493 16494 /* 16495 * Create the list 16496 */ 16497 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 16498 UU_DEFAULT); 16499 if (service_manifest_tree == NULL) 16500 uu_die(gettext("service_manifest tree creation failed: %s\n"), 16501 uu_strerror(uu_error())); 16502 16503 /* 16504 * Walk the manifests adding the service(s) from each manifest. 16505 * 16506 * If a service already exists add the manifest to the manifest 16507 * list for that service. This covers the case of a service that 16508 * is supported by multiple manifest files. 16509 */ 16510 for (c = 0; dirs[c]; c++) { 16511 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT); 16512 if (status < 0) { 16513 uu_warn(gettext("file tree walk of %s encountered " 16514 "error %s\n"), dirs[c], strerror(errno)); 16515 16516 uu_avl_destroy(service_manifest_tree); 16517 service_manifest_tree = NULL; 16518 return; 16519 } 16520 16521 /* 16522 * If a manifest that was in the list is not found 16523 * then skip and go to the next manifest file. 16524 */ 16525 if (manifests != NULL) { 16526 for (entry = manifests; *entry != NULL; entry++) { 16527 b = internal_bundle_new(); 16528 if (lxml_get_bundle_file(b, (*entry)->mi_path, 16529 SVCCFG_OP_IMPORT) != 0) { 16530 internal_bundle_free(b); 16531 continue; 16532 } 16533 16534 svcs = uu_list_walk_start(b->sc_bundle_services, 16535 0); 16536 if (svcs == NULL) { 16537 internal_bundle_free(b); 16538 continue; 16539 } 16540 16541 while ((mfsvc = uu_list_walk_next(svcs)) != 16542 NULL) { 16543 /* Add manifest to service */ 16544 (void) find_add_svc_mfst(mfsvc->sc_name, 16545 (*entry)->mi_path); 16546 } 16547 16548 uu_list_walk_end(svcs); 16549 internal_bundle_free(b); 16550 } 16551 16552 free_manifest_array(manifests); 16553 } 16554 } 16555 } 16556 16557 /* 16558 * Check the manifest history file to see 16559 * if the service was ever installed from 16560 * one of the supported directories. 16561 * 16562 * Return Values : 16563 * -1 - if there's error reading manifest history file 16564 * 1 - if the service is not found 16565 * 0 - if the service is found 16566 */ 16567 static int 16568 check_mfst_history(const char *svcname) 16569 { 16570 struct stat st; 16571 caddr_t mfsthist_start; 16572 char *svnbuf; 16573 int fd; 16574 int r = 1; 16575 16576 fd = open(MFSTHISTFILE, O_RDONLY); 16577 if (fd == -1) { 16578 uu_warn(gettext("Unable to open the history file\n")); 16579 return (-1); 16580 } 16581 16582 if (fstat(fd, &st) == -1) { 16583 uu_warn(gettext("Unable to stat the history file\n")); 16584 return (-1); 16585 } 16586 16587 mfsthist_start = mmap(0, st.st_size, PROT_READ, 16588 MAP_PRIVATE, fd, 0); 16589 16590 (void) close(fd); 16591 if (mfsthist_start == MAP_FAILED || 16592 *(mfsthist_start + st.st_size) != '\0') { 16593 (void) munmap(mfsthist_start, st.st_size); 16594 return (-1); 16595 } 16596 16597 /* 16598 * The manifest history file is a space delimited list 16599 * of service and instance to manifest linkage. Adding 16600 * a space to the end of the service name so to get only 16601 * the service that is being searched for. 16602 */ 16603 svnbuf = uu_msprintf("%s ", svcname); 16604 if (svnbuf == NULL) 16605 uu_die(gettext("Out of memory")); 16606 16607 if (strstr(mfsthist_start, svnbuf) != NULL) 16608 r = 0; 16609 16610 (void) munmap(mfsthist_start, st.st_size); 16611 uu_free(svnbuf); 16612 return (r); 16613 } 16614 16615 /* 16616 * Take down each of the instances in the service 16617 * and remove them, then delete the service. 16618 */ 16619 static void 16620 teardown_service(scf_service_t *svc, const char *svnbuf) 16621 { 16622 scf_instance_t *instance; 16623 scf_iter_t *iter; 16624 int r; 16625 16626 safe_printf(gettext("Delete service %s as there are no " 16627 "supporting manifests\n"), svnbuf); 16628 16629 instance = scf_instance_create(g_hndl); 16630 iter = scf_iter_create(g_hndl); 16631 if (iter == NULL || instance == NULL) { 16632 uu_warn(gettext("Unable to create supporting entities to " 16633 "teardown the service\n")); 16634 uu_warn(gettext("scf error is : %s\n"), 16635 scf_strerror(scf_error())); 16636 scfdie(); 16637 } 16638 16639 if (scf_iter_service_instances(iter, svc) != 0) { 16640 switch (scf_error()) { 16641 case SCF_ERROR_CONNECTION_BROKEN: 16642 case SCF_ERROR_DELETED: 16643 goto out; 16644 16645 case SCF_ERROR_HANDLE_MISMATCH: 16646 case SCF_ERROR_NOT_BOUND: 16647 case SCF_ERROR_NOT_SET: 16648 default: 16649 bad_error("scf_iter_service_instances", 16650 scf_error()); 16651 } 16652 } 16653 16654 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 16655 if (r == -1) { 16656 uu_warn(gettext("Error - %s\n"), 16657 scf_strerror(scf_error())); 16658 goto out; 16659 } 16660 16661 (void) disable_instance(instance); 16662 } 16663 16664 /* 16665 * Delete the service... forcing the deletion in case 16666 * any of the instances did not disable. 16667 */ 16668 (void) lscf_service_delete(svc, 1); 16669 out: 16670 scf_instance_destroy(instance); 16671 scf_iter_destroy(iter); 16672 } 16673 16674 /* 16675 * Get the list of instances supported by the manifest 16676 * file. 16677 * 16678 * Return 0 if there are no instances. 16679 * 16680 * Return -1 if there are errors attempting to collect instances. 16681 * 16682 * Return the count of instances found if there are no errors. 16683 * 16684 */ 16685 static int 16686 check_instance_support(char *mfstfile, const char *svcname, 16687 uu_list_t *instances) 16688 { 16689 uu_list_walk_t *svcs, *insts; 16690 uu_list_t *ilist; 16691 bundle_t *b; 16692 entity_t *mfsvc, *mfinst; 16693 const char *svcn; 16694 int rminstcnt = 0; 16695 16696 16697 b = internal_bundle_new(); 16698 16699 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 16700 /* 16701 * Unable to process the manifest file for 16702 * instance support, so just return as 16703 * don't want to remove instances that could 16704 * not be accounted for that might exist here. 16705 */ 16706 internal_bundle_free(b); 16707 return (0); 16708 } 16709 16710 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 16711 if (svcs == NULL) { 16712 internal_bundle_free(b); 16713 return (0); 16714 } 16715 16716 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 16717 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 16718 16719 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 16720 if (strcmp(mfsvc->sc_name, svcn) == 0) 16721 break; 16722 } 16723 uu_list_walk_end(svcs); 16724 16725 if (mfsvc == NULL) { 16726 internal_bundle_free(b); 16727 return (-1); 16728 } 16729 16730 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 16731 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 16732 internal_bundle_free(b); 16733 return (0); 16734 } 16735 16736 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 16737 /* 16738 * Remove the instance from the instances list. 16739 * The unaccounted for instances will be removed 16740 * from the service once all manifests are 16741 * processed. 16742 */ 16743 (void) remove_string(instances, 16744 mfinst->sc_name); 16745 rminstcnt++; 16746 } 16747 16748 uu_list_walk_end(insts); 16749 internal_bundle_free(b); 16750 16751 return (rminstcnt); 16752 } 16753 16754 /* 16755 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 16756 * 'false' to indicate there's no manifest file(s) found for the service. 16757 */ 16758 static void 16759 svc_add_no_support(scf_service_t *svc) 16760 { 16761 char *pname; 16762 16763 /* Add no support */ 16764 cur_svc = svc; 16765 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 16766 return; 16767 16768 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 16769 if (pname == NULL) 16770 uu_die(gettext("Out of memory.\n")); 16771 16772 (void) lscf_addpropvalue(pname, "boolean:", "0"); 16773 16774 uu_free(pname); 16775 cur_svc = NULL; 16776 } 16777 16778 /* 16779 * This function handles all upgrade scenarios for a service that doesn't have 16780 * SCF_PG_MANIFESTFILES pg. The function creates and populates 16781 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 16782 * manifest(s) mapping. Manifests under supported directories are inventoried 16783 * and a property is added for each file that delivers configuration to the 16784 * service. A service that has no corresponding manifest files (deleted) are 16785 * removed from repository. 16786 * 16787 * Unsupported services: 16788 * 16789 * A service is considered unsupported if there is no corresponding manifest 16790 * in the supported directories for that service and the service isn't in the 16791 * history file list. The history file, MFSTHISTFILE, contains a list of all 16792 * services and instances that were delivered by Solaris before the introduction 16793 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 16794 * the path to the manifest file that defined the service or instance. 16795 * 16796 * Another type of unsupported services is 'handcrafted' services, 16797 * programmatically created services or services created by dependent entries 16798 * in other manifests. A handcrafted service is identified by its lack of any 16799 * instance containing last-import snapshot which is created during svccfg 16800 * import. 16801 * 16802 * This function sets a flag for unsupported services by setting services' 16803 * SCF_PG_MANIFESTFILES/support property to false. 16804 */ 16805 static void 16806 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 16807 { 16808 service_manifest_t *elem; 16809 uu_list_walk_t *mfwalk; 16810 string_list_t *mfile; 16811 uu_list_t *instances; 16812 const char *sname; 16813 char *pname; 16814 int r; 16815 16816 /* 16817 * Since there's no guarantee manifests under /var are available during 16818 * early import, don't perform any upgrade during early import. 16819 */ 16820 if (IGNORE_VAR) 16821 return; 16822 16823 if (service_manifest_tree == NULL) { 16824 create_manifest_tree(); 16825 } 16826 16827 /* 16828 * Find service's supporting manifest(s) after 16829 * stripping off the svc:/ prefix that is part 16830 * of the fmri that is not used in the service 16831 * manifest bundle list. 16832 */ 16833 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 16834 strlen(SCF_FMRI_SERVICE_PREFIX); 16835 elem = find_add_svc_mfst(sname, NULL); 16836 if (elem == NULL) { 16837 16838 /* 16839 * A handcrafted service, one that has no instance containing 16840 * last-import snapshot, should get unsupported flag. 16841 */ 16842 instances = create_instance_list(svc, 1); 16843 if (instances == NULL) { 16844 uu_warn(gettext("Unable to create instance list %s\n"), 16845 svcname); 16846 return; 16847 } 16848 16849 if (uu_list_numnodes(instances) == 0) { 16850 svc_add_no_support(svc); 16851 return; 16852 } 16853 16854 /* 16855 * If the service is in the history file, and its supporting 16856 * manifests are not found, we can safely delete the service 16857 * because its manifests are removed from the system. 16858 * 16859 * Services not found in the history file are not delivered by 16860 * Solaris and/or delivered outside supported directories, set 16861 * unsupported flag for these services. 16862 */ 16863 r = check_mfst_history(svcname); 16864 if (r == -1) 16865 return; 16866 16867 if (r) { 16868 /* Set unsupported flag for service */ 16869 svc_add_no_support(svc); 16870 } else { 16871 /* Delete the service */ 16872 teardown_service(svc, svcname); 16873 } 16874 16875 return; 16876 } 16877 16878 /* 16879 * Walk through the list of manifests and add them 16880 * to the service. 16881 * 16882 * Create a manifestfiles pg and add the property. 16883 */ 16884 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 16885 if (mfwalk == NULL) 16886 return; 16887 16888 cur_svc = svc; 16889 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 16890 if (r != 0) { 16891 cur_svc = NULL; 16892 return; 16893 } 16894 16895 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 16896 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16897 mhash_filename_to_propname(mfile->str, 0)); 16898 if (pname == NULL) 16899 uu_die(gettext("Out of memory.\n")); 16900 16901 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 16902 uu_free(pname); 16903 } 16904 uu_list_walk_end(mfwalk); 16905 16906 cur_svc = NULL; 16907 } 16908 16909 /* 16910 * Take a service and process the manifest file entires to see if 16911 * there is continued support for the service and instances. If 16912 * not cleanup as appropriate. 16913 * 16914 * If a service does not have a manifest files entry flag it for 16915 * upgrade and return. 16916 * 16917 * For each manifestfiles property check if the manifest file is 16918 * under the supported /lib/svc/manifest or /var/svc/manifest path 16919 * and if not then return immediately as this service is not supported 16920 * by the cleanup mechanism and should be ignored. 16921 * 16922 * For each manifest file that is supported, check to see if the 16923 * file exists. If not then remove the manifest file property 16924 * from the service and the smf/manifest hash table. If the manifest 16925 * file exists then verify that it supports the instances that are 16926 * part of the service. 16927 * 16928 * Once all manifest files have been accounted for remove any instances 16929 * that are no longer supported in the service. 16930 * 16931 * Return values : 16932 * 0 - Successfully processed the service 16933 * non-zero - failed to process the service 16934 * 16935 * On most errors, will just return to wait and get the next service, 16936 * unless in case of unable to create the needed structures which is 16937 * most likely a fatal error that is not going to be recoverable. 16938 */ 16939 int 16940 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 16941 { 16942 struct mpg_mfile *mpntov; 16943 struct mpg_mfile **mpvarry = NULL; 16944 scf_service_t *svc; 16945 scf_propertygroup_t *mpg; 16946 scf_property_t *mp; 16947 scf_value_t *mv; 16948 scf_iter_t *mi; 16949 scf_instance_t *instance; 16950 uu_list_walk_t *insts; 16951 uu_list_t *instances = NULL; 16952 boolean_t activity = (boolean_t)act; 16953 char *mpnbuf; 16954 char *mpvbuf; 16955 char *pgpropbuf; 16956 int mfstcnt, rminstct, instct, mfstmax; 16957 int index; 16958 int r = 0; 16959 16960 assert(g_hndl != NULL); 16961 assert(wip->svc != NULL); 16962 assert(wip->fmri != NULL); 16963 16964 svc = wip->svc; 16965 16966 mpg = scf_pg_create(g_hndl); 16967 mp = scf_property_create(g_hndl); 16968 mi = scf_iter_create(g_hndl); 16969 mv = scf_value_create(g_hndl); 16970 instance = scf_instance_create(g_hndl); 16971 16972 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 16973 instance == NULL) { 16974 uu_warn(gettext("Unable to create the supporting entities\n")); 16975 uu_warn(gettext("scf error is : %s\n"), 16976 scf_strerror(scf_error())); 16977 scfdie(); 16978 } 16979 16980 /* 16981 * Get the manifestfiles property group to be parsed for 16982 * files existence. 16983 */ 16984 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 16985 switch (scf_error()) { 16986 case SCF_ERROR_NOT_FOUND: 16987 upgrade_svc_mfst_connection(svc, wip->fmri); 16988 break; 16989 case SCF_ERROR_DELETED: 16990 case SCF_ERROR_CONNECTION_BROKEN: 16991 goto out; 16992 16993 case SCF_ERROR_HANDLE_MISMATCH: 16994 case SCF_ERROR_NOT_BOUND: 16995 case SCF_ERROR_NOT_SET: 16996 default: 16997 bad_error("scf_iter_pg_properties", 16998 scf_error()); 16999 } 17000 17001 goto out; 17002 } 17003 17004 /* 17005 * Iterate through each of the manifestfiles properties 17006 * to determine what manifestfiles are available. 17007 * 17008 * If a manifest file is supported then increment the 17009 * count and therefore the service is safe. 17010 */ 17011 if (scf_iter_pg_properties(mi, mpg) != 0) { 17012 switch (scf_error()) { 17013 case SCF_ERROR_DELETED: 17014 case SCF_ERROR_CONNECTION_BROKEN: 17015 goto out; 17016 17017 case SCF_ERROR_HANDLE_MISMATCH: 17018 case SCF_ERROR_NOT_BOUND: 17019 case SCF_ERROR_NOT_SET: 17020 default: 17021 bad_error("scf_iter_pg_properties", 17022 scf_error()); 17023 } 17024 } 17025 17026 mfstcnt = 0; 17027 mfstmax = MFSTFILE_MAX; 17028 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 17029 while ((r = scf_iter_next_property(mi, mp)) != 0) { 17030 if (r == -1) 17031 bad_error(gettext("Unable to iterate through " 17032 "manifestfiles properties : %s"), 17033 scf_error()); 17034 17035 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 17036 mpnbuf = safe_malloc(max_scf_name_len + 1); 17037 mpvbuf = safe_malloc(max_scf_value_len + 1); 17038 mpntov->mpg = mpnbuf; 17039 mpntov->mfile = mpvbuf; 17040 mpntov->access = 1; 17041 if (scf_property_get_name(mp, mpnbuf, 17042 max_scf_name_len + 1) < 0) { 17043 uu_warn(gettext("Unable to get manifest file " 17044 "property : %s\n"), 17045 scf_strerror(scf_error())); 17046 17047 switch (scf_error()) { 17048 case SCF_ERROR_DELETED: 17049 case SCF_ERROR_CONNECTION_BROKEN: 17050 r = scferror2errno(scf_error()); 17051 goto out_free; 17052 17053 case SCF_ERROR_HANDLE_MISMATCH: 17054 case SCF_ERROR_NOT_BOUND: 17055 case SCF_ERROR_NOT_SET: 17056 default: 17057 bad_error("scf_iter_pg_properties", 17058 scf_error()); 17059 } 17060 } 17061 17062 /* 17063 * The support property is a boolean value that indicates 17064 * if the service is supported for manifest file deletion. 17065 * Currently at this time there is no code that sets this 17066 * value to true. So while we could just let this be caught 17067 * by the support check below, in the future this by be set 17068 * to true and require processing. So for that, go ahead 17069 * and check here, and just return if false. Otherwise, 17070 * fall through expecting that other support checks will 17071 * handle the entries. 17072 */ 17073 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 17074 uint8_t support; 17075 17076 if (scf_property_get_value(mp, mv) != 0 || 17077 scf_value_get_boolean(mv, &support) != 0) { 17078 uu_warn(gettext("Unable to get the manifest " 17079 "support value: %s\n"), 17080 scf_strerror(scf_error())); 17081 17082 switch (scf_error()) { 17083 case SCF_ERROR_DELETED: 17084 case SCF_ERROR_CONNECTION_BROKEN: 17085 r = scferror2errno(scf_error()); 17086 goto out_free; 17087 17088 case SCF_ERROR_HANDLE_MISMATCH: 17089 case SCF_ERROR_NOT_BOUND: 17090 case SCF_ERROR_NOT_SET: 17091 default: 17092 bad_error("scf_iter_pg_properties", 17093 scf_error()); 17094 } 17095 } 17096 17097 if (support == B_FALSE) 17098 goto out_free; 17099 } 17100 17101 /* 17102 * Anything with a manifest outside of the supported 17103 * directories, immediately bail out because that makes 17104 * this service non-supported. We don't even want 17105 * to do instance processing in this case because the 17106 * instances could be part of the non-supported manifest. 17107 */ 17108 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 17109 /* 17110 * Manifest is not in /lib/svc, so we need to 17111 * consider the /var/svc case. 17112 */ 17113 if (strncmp(mpnbuf, VARSVC_PR, 17114 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 17115 /* 17116 * Either the manifest is not in /var/svc or 17117 * /var is not yet mounted. We ignore the 17118 * manifest either because it is not in a 17119 * standard location or because we cannot 17120 * currently access the manifest. 17121 */ 17122 goto out_free; 17123 } 17124 } 17125 17126 /* 17127 * Get the value to of the manifest file for this entry 17128 * for access verification and instance support 17129 * verification if it still exists. 17130 * 17131 * During Early Manifest Import if the manifest is in 17132 * /var/svc then it may not yet be available for checking 17133 * so we must determine if /var/svc is available. If not 17134 * then defer until Late Manifest Import to cleanup. 17135 */ 17136 if (scf_property_get_value(mp, mv) != 0) { 17137 uu_warn(gettext("Unable to get the manifest file " 17138 "value: %s\n"), 17139 scf_strerror(scf_error())); 17140 17141 switch (scf_error()) { 17142 case SCF_ERROR_DELETED: 17143 case SCF_ERROR_CONNECTION_BROKEN: 17144 r = scferror2errno(scf_error()); 17145 goto out_free; 17146 17147 case SCF_ERROR_HANDLE_MISMATCH: 17148 case SCF_ERROR_NOT_BOUND: 17149 case SCF_ERROR_NOT_SET: 17150 default: 17151 bad_error("scf_property_get_value", 17152 scf_error()); 17153 } 17154 } 17155 17156 if (scf_value_get_astring(mv, mpvbuf, 17157 max_scf_value_len + 1) < 0) { 17158 uu_warn(gettext("Unable to get the manifest " 17159 "file : %s\n"), 17160 scf_strerror(scf_error())); 17161 17162 switch (scf_error()) { 17163 case SCF_ERROR_DELETED: 17164 case SCF_ERROR_CONNECTION_BROKEN: 17165 r = scferror2errno(scf_error()); 17166 goto out_free; 17167 17168 case SCF_ERROR_HANDLE_MISMATCH: 17169 case SCF_ERROR_NOT_BOUND: 17170 case SCF_ERROR_NOT_SET: 17171 default: 17172 bad_error("scf_value_get_astring", 17173 scf_error()); 17174 } 17175 } 17176 17177 mpvarry[mfstcnt] = mpntov; 17178 mfstcnt++; 17179 17180 /* 17181 * Check for the need to reallocate array 17182 */ 17183 if (mfstcnt >= (mfstmax - 1)) { 17184 struct mpg_mfile **newmpvarry; 17185 17186 mfstmax = mfstmax * 2; 17187 newmpvarry = realloc(mpvarry, 17188 sizeof (struct mpg_mfile *) * mfstmax); 17189 17190 if (newmpvarry == NULL) 17191 goto out_free; 17192 17193 mpvarry = newmpvarry; 17194 } 17195 17196 mpvarry[mfstcnt] = NULL; 17197 } 17198 17199 for (index = 0; mpvarry[index]; index++) { 17200 mpntov = mpvarry[index]; 17201 17202 /* 17203 * Check to see if the manifestfile is accessable, if so hand 17204 * this service and manifestfile off to be processed for 17205 * instance support. 17206 */ 17207 mpnbuf = mpntov->mpg; 17208 mpvbuf = mpntov->mfile; 17209 if (access(mpvbuf, F_OK) != 0) { 17210 mpntov->access = 0; 17211 activity++; 17212 mfstcnt--; 17213 /* Remove the entry from the service */ 17214 cur_svc = svc; 17215 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 17216 mpnbuf); 17217 if (pgpropbuf == NULL) 17218 uu_die(gettext("Out of memory.\n")); 17219 17220 lscf_delprop(pgpropbuf); 17221 cur_svc = NULL; 17222 17223 uu_free(pgpropbuf); 17224 } 17225 } 17226 17227 /* 17228 * If mfstcnt is 0, none of the manifests that supported the service 17229 * existed so remove the service. 17230 */ 17231 if (mfstcnt == 0) { 17232 teardown_service(svc, wip->fmri); 17233 17234 goto out_free; 17235 } 17236 17237 if (activity) { 17238 int nosvcsupport = 0; 17239 17240 /* 17241 * If the list of service instances is NULL then 17242 * create the list. 17243 */ 17244 instances = create_instance_list(svc, 1); 17245 if (instances == NULL) { 17246 uu_warn(gettext("Unable to create instance list %s\n"), 17247 wip->fmri); 17248 goto out_free; 17249 } 17250 17251 rminstct = uu_list_numnodes(instances); 17252 instct = rminstct; 17253 17254 for (index = 0; mpvarry[index]; index++) { 17255 mpntov = mpvarry[index]; 17256 if (mpntov->access == 0) 17257 continue; 17258 17259 mpnbuf = mpntov->mpg; 17260 mpvbuf = mpntov->mfile; 17261 r = check_instance_support(mpvbuf, wip->fmri, 17262 instances); 17263 if (r == -1) { 17264 nosvcsupport++; 17265 } else { 17266 rminstct -= r; 17267 } 17268 } 17269 17270 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 17271 teardown_service(svc, wip->fmri); 17272 17273 goto out_free; 17274 } 17275 } 17276 17277 /* 17278 * If there are instances left on the instance list, then 17279 * we must remove them. 17280 */ 17281 if (instances != NULL && uu_list_numnodes(instances)) { 17282 string_list_t *sp; 17283 17284 insts = uu_list_walk_start(instances, 0); 17285 while ((sp = uu_list_walk_next(insts)) != NULL) { 17286 /* 17287 * Remove the instance from the instances list. 17288 */ 17289 safe_printf(gettext("Delete instance %s from " 17290 "service %s\n"), sp->str, wip->fmri); 17291 if (scf_service_get_instance(svc, sp->str, 17292 instance) != SCF_SUCCESS) { 17293 (void) uu_warn("scf_error - %s\n", 17294 scf_strerror(scf_error())); 17295 17296 continue; 17297 } 17298 17299 (void) disable_instance(instance); 17300 17301 (void) lscf_instance_delete(instance, 1); 17302 } 17303 scf_instance_destroy(instance); 17304 uu_list_walk_end(insts); 17305 } 17306 17307 out_free: 17308 if (mpvarry) { 17309 struct mpg_mfile *fmpntov; 17310 17311 for (index = 0; mpvarry[index]; index++) { 17312 fmpntov = mpvarry[index]; 17313 if (fmpntov->mpg == mpnbuf) 17314 mpnbuf = NULL; 17315 free(fmpntov->mpg); 17316 17317 if (fmpntov->mfile == mpvbuf) 17318 mpvbuf = NULL; 17319 free(fmpntov->mfile); 17320 17321 if (fmpntov == mpntov) 17322 mpntov = NULL; 17323 free(fmpntov); 17324 } 17325 if (mpnbuf) 17326 free(mpnbuf); 17327 if (mpvbuf) 17328 free(mpvbuf); 17329 if (mpntov) 17330 free(mpntov); 17331 17332 free(mpvarry); 17333 } 17334 out: 17335 scf_pg_destroy(mpg); 17336 scf_property_destroy(mp); 17337 scf_iter_destroy(mi); 17338 scf_value_destroy(mv); 17339 17340 return (0); 17341 } 17342 17343 /* 17344 * Take the service and search for the manifestfiles property 17345 * in each of the property groups. If the manifest file 17346 * associated with the property does not exist then remove 17347 * the property group. 17348 */ 17349 int 17350 lscf_hash_cleanup() 17351 { 17352 scf_service_t *svc; 17353 scf_scope_t *scope; 17354 scf_propertygroup_t *pg; 17355 scf_property_t *prop; 17356 scf_value_t *val; 17357 scf_iter_t *iter; 17358 char *pgname = NULL; 17359 char *mfile = NULL; 17360 int r; 17361 17362 svc = scf_service_create(g_hndl); 17363 scope = scf_scope_create(g_hndl); 17364 pg = scf_pg_create(g_hndl); 17365 prop = scf_property_create(g_hndl); 17366 val = scf_value_create(g_hndl); 17367 iter = scf_iter_create(g_hndl); 17368 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 17369 svc == NULL || scope == NULL) { 17370 uu_warn(gettext("Unable to create a property group, or " 17371 "property\n")); 17372 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 17373 "pg is not NULL"); 17374 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 17375 "prop is not NULL"); 17376 uu_warn("%s\n", val == NULL ? "val is NULL" : 17377 "val is not NULL"); 17378 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 17379 "iter is not NULL"); 17380 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 17381 "svc is not NULL"); 17382 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 17383 "scope is not NULL"); 17384 uu_warn(gettext("scf error is : %s\n"), 17385 scf_strerror(scf_error())); 17386 scfdie(); 17387 } 17388 17389 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 17390 switch (scf_error()) { 17391 case SCF_ERROR_CONNECTION_BROKEN: 17392 case SCF_ERROR_NOT_FOUND: 17393 goto out; 17394 17395 case SCF_ERROR_HANDLE_MISMATCH: 17396 case SCF_ERROR_NOT_BOUND: 17397 case SCF_ERROR_INVALID_ARGUMENT: 17398 default: 17399 bad_error("scf_handle_get_scope", scf_error()); 17400 } 17401 } 17402 17403 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 17404 uu_warn(gettext("Unable to process the hash service, %s\n"), 17405 HASH_SVC); 17406 goto out; 17407 } 17408 17409 pgname = safe_malloc(max_scf_name_len + 1); 17410 mfile = safe_malloc(max_scf_value_len + 1); 17411 17412 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 17413 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 17414 scf_strerror(scf_error())); 17415 goto out; 17416 } 17417 17418 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 17419 if (r == -1) 17420 goto out; 17421 17422 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 17423 switch (scf_error()) { 17424 case SCF_ERROR_DELETED: 17425 return (ENODEV); 17426 17427 case SCF_ERROR_CONNECTION_BROKEN: 17428 return (ECONNABORTED); 17429 17430 case SCF_ERROR_NOT_SET: 17431 case SCF_ERROR_NOT_BOUND: 17432 default: 17433 bad_error("scf_pg_get_name", scf_error()); 17434 } 17435 } 17436 if (IGNORE_VAR) { 17437 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 17438 continue; 17439 } 17440 17441 /* 17442 * If unable to get the property continue as this is an 17443 * entry that has no location to check against. 17444 */ 17445 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 17446 continue; 17447 } 17448 17449 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 17450 uu_warn(gettext("Unable to get value from %s\n"), 17451 pgname); 17452 17453 switch (scf_error()) { 17454 case SCF_ERROR_DELETED: 17455 case SCF_ERROR_CONSTRAINT_VIOLATED: 17456 case SCF_ERROR_NOT_FOUND: 17457 case SCF_ERROR_NOT_SET: 17458 continue; 17459 17460 case SCF_ERROR_CONNECTION_BROKEN: 17461 r = scferror2errno(scf_error()); 17462 goto out; 17463 17464 case SCF_ERROR_HANDLE_MISMATCH: 17465 case SCF_ERROR_NOT_BOUND: 17466 default: 17467 bad_error("scf_property_get_value", 17468 scf_error()); 17469 } 17470 } 17471 17472 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) 17473 == -1) { 17474 uu_warn(gettext("Unable to get astring from %s : %s\n"), 17475 pgname, scf_strerror(scf_error())); 17476 17477 switch (scf_error()) { 17478 case SCF_ERROR_NOT_SET: 17479 case SCF_ERROR_TYPE_MISMATCH: 17480 continue; 17481 17482 default: 17483 bad_error("scf_value_get_astring", scf_error()); 17484 } 17485 } 17486 17487 if (access(mfile, F_OK) == 0) 17488 continue; 17489 17490 (void) scf_pg_delete(pg); 17491 } 17492 17493 out: 17494 scf_scope_destroy(scope); 17495 scf_service_destroy(svc); 17496 scf_pg_destroy(pg); 17497 scf_property_destroy(prop); 17498 scf_value_destroy(val); 17499 scf_iter_destroy(iter); 17500 free(pgname); 17501 free(mfile); 17502 17503 return (0); 17504 } 17505 17506 #ifndef NATIVE_BUILD 17507 /* ARGSUSED */ 17508 CPL_MATCH_FN(complete_select) 17509 { 17510 const char *arg0, *arg1, *arg1end; 17511 int word_start, err = 0, r; 17512 size_t len; 17513 char *buf; 17514 17515 lscf_prep_hndl(); 17516 17517 arg0 = line + strspn(line, " \t"); 17518 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 17519 17520 arg1 = arg0 + sizeof ("select") - 1; 17521 arg1 += strspn(arg1, " \t"); 17522 word_start = arg1 - line; 17523 17524 arg1end = arg1 + strcspn(arg1, " \t"); 17525 if (arg1end < line + word_end) 17526 return (0); 17527 17528 len = line + word_end - arg1; 17529 17530 buf = safe_malloc(max_scf_name_len + 1); 17531 17532 if (cur_snap != NULL) { 17533 return (0); 17534 } else if (cur_inst != NULL) { 17535 return (0); 17536 } else if (cur_svc != NULL) { 17537 scf_instance_t *inst; 17538 scf_iter_t *iter; 17539 17540 if ((inst = scf_instance_create(g_hndl)) == NULL || 17541 (iter = scf_iter_create(g_hndl)) == NULL) 17542 scfdie(); 17543 17544 if (scf_iter_service_instances(iter, cur_svc) != 0) 17545 scfdie(); 17546 17547 for (;;) { 17548 r = scf_iter_next_instance(iter, inst); 17549 if (r == 0) 17550 break; 17551 if (r != 1) 17552 scfdie(); 17553 17554 if (scf_instance_get_name(inst, buf, 17555 max_scf_name_len + 1) < 0) 17556 scfdie(); 17557 17558 if (strncmp(buf, arg1, len) == 0) { 17559 err = cpl_add_completion(cpl, line, word_start, 17560 word_end, buf + len, "", " "); 17561 if (err != 0) 17562 break; 17563 } 17564 } 17565 17566 scf_iter_destroy(iter); 17567 scf_instance_destroy(inst); 17568 17569 return (err); 17570 } else { 17571 scf_service_t *svc; 17572 scf_iter_t *iter; 17573 17574 assert(cur_scope != NULL); 17575 17576 if ((svc = scf_service_create(g_hndl)) == NULL || 17577 (iter = scf_iter_create(g_hndl)) == NULL) 17578 scfdie(); 17579 17580 if (scf_iter_scope_services(iter, cur_scope) != 0) 17581 scfdie(); 17582 17583 for (;;) { 17584 r = scf_iter_next_service(iter, svc); 17585 if (r == 0) 17586 break; 17587 if (r != 1) 17588 scfdie(); 17589 17590 if (scf_service_get_name(svc, buf, 17591 max_scf_name_len + 1) < 0) 17592 scfdie(); 17593 17594 if (strncmp(buf, arg1, len) == 0) { 17595 err = cpl_add_completion(cpl, line, word_start, 17596 word_end, buf + len, "", " "); 17597 if (err != 0) 17598 break; 17599 } 17600 } 17601 17602 scf_iter_destroy(iter); 17603 scf_service_destroy(svc); 17604 17605 return (err); 17606 } 17607 } 17608 17609 /* ARGSUSED */ 17610 CPL_MATCH_FN(complete_command) 17611 { 17612 uint32_t scope = 0; 17613 17614 if (cur_snap != NULL) 17615 scope = CS_SNAP; 17616 else if (cur_inst != NULL) 17617 scope = CS_INST; 17618 else if (cur_svc != NULL) 17619 scope = CS_SVC; 17620 else 17621 scope = CS_SCOPE; 17622 17623 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 17624 } 17625 #endif /* NATIVE_BUILD */