1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2020 Joyent, Inc. 25 * Copyright 2012 Milan Jurik. All rights reserved. 26 * Copyright 2017 RackTop Systems. 27 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 28 */ 29 30 31 #include <alloca.h> 32 #include <assert.h> 33 #include <ctype.h> 34 #include <door.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <fnmatch.h> 38 #include <inttypes.h> 39 #include <libintl.h> 40 #include <libnvpair.h> 41 #include <libscf.h> 42 #include <libscf_priv.h> 43 #include <libtecla.h> 44 #include <libuutil.h> 45 #include <limits.h> 46 #include <locale.h> 47 #include <stdarg.h> 48 #include <string.h> 49 #include <strings.h> 50 #include <time.h> 51 #include <unistd.h> 52 #include <wait.h> 53 #include <poll.h> 54 55 #include <libxml/tree.h> 56 57 #include <sys/param.h> 58 59 #include <sys/stat.h> 60 #include <sys/mman.h> 61 62 #include "svccfg.h" 63 #include "notify_params.h" 64 #include "manifest_hash.h" 65 #include "manifest_find.h" 66 67 /* The colon namespaces in each entity (each followed by a newline). */ 68 #define COLON_NAMESPACES ":properties\n" 69 70 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 71 72 /* These are characters which the lexer requires to be in double-quotes. */ 73 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 74 75 #define HASH_SIZE 16 76 #define HASH_PG_TYPE "framework" 77 #define HASH_PG_FLAGS 0 78 #define HASH_PROP "md5sum" 79 80 /* 81 * Indentation used in the output of the describe subcommand. 82 */ 83 #define TMPL_VALUE_INDENT " " 84 #define TMPL_INDENT " " 85 #define TMPL_INDENT_2X " " 86 #define TMPL_CHOICE_INDENT " " 87 88 /* 89 * Directory locations for manifests 90 */ 91 #define VARSVC_DIR "/var/svc/manifest" 92 #define LIBSVC_DIR "/lib/svc/manifest" 93 #define VARSVC_PR "var_svc_manifest" 94 #define LIBSVC_PR "lib_svc_manifest" 95 #define MFSTFILEPR "manifestfile" 96 97 #define SUPPORTPROP "support" 98 99 #define MFSTHISTFILE "/lib/svc/share/mfsthistory" 100 101 #define MFSTFILE_MAX 16 102 103 /* 104 * These are the classes of elements which may appear as children of service 105 * or instance elements in XML manifests. 106 */ 107 struct entity_elts { 108 xmlNodePtr create_default_instance; 109 xmlNodePtr single_instance; 110 xmlNodePtr restarter; 111 xmlNodePtr dependencies; 112 xmlNodePtr dependents; 113 xmlNodePtr method_context; 114 xmlNodePtr exec_methods; 115 xmlNodePtr notify_params; 116 xmlNodePtr property_groups; 117 xmlNodePtr instances; 118 xmlNodePtr stability; 119 xmlNodePtr template; 120 }; 121 122 /* 123 * Likewise for property_group elements. 124 */ 125 struct pg_elts { 126 xmlNodePtr stability; 127 xmlNodePtr propvals; 128 xmlNodePtr properties; 129 }; 130 131 /* 132 * Likewise for template elements. 133 */ 134 struct template_elts { 135 xmlNodePtr common_name; 136 xmlNodePtr description; 137 xmlNodePtr documentation; 138 }; 139 140 /* 141 * Likewise for type (for notification parameters) elements. 142 */ 143 struct params_elts { 144 xmlNodePtr paramval; 145 xmlNodePtr parameter; 146 }; 147 148 /* 149 * This structure is for snaplevel lists. They are convenient because libscf 150 * only allows traversing snaplevels in one direction. 151 */ 152 struct snaplevel { 153 uu_list_node_t list_node; 154 scf_snaplevel_t *sl; 155 }; 156 157 /* 158 * This is used for communication between lscf_service_export and 159 * export_callback. 160 */ 161 struct export_args { 162 const char *filename; 163 int flags; 164 }; 165 166 /* 167 * The service_manifest structure is used by the upgrade process 168 * to create a list of service to manifest linkages from the manifests 169 * in a set of given directories. 170 */ 171 typedef struct service_manifest { 172 const char *servicename; 173 uu_list_t *mfstlist; 174 size_t mfstlist_sz; 175 176 uu_avl_node_t svcmfst_node; 177 } service_manifest_t; 178 179 /* 180 * Structure to track the manifest file property group 181 * and the manifest file associated with that property 182 * group. Also, a flag to keep the access once it has 183 * been checked. 184 */ 185 struct mpg_mfile { 186 char *mpg; 187 char *mfile; 188 int access; 189 }; 190 191 const char * const scf_pg_general = SCF_PG_GENERAL; 192 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 193 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 194 const char * const scf_property_external = "external"; 195 196 const char * const snap_initial = "initial"; 197 const char * const snap_lastimport = "last-import"; 198 const char * const snap_previous = "previous"; 199 const char * const snap_running = "running"; 200 201 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 202 203 ssize_t max_scf_fmri_len; 204 ssize_t max_scf_name_len; 205 ssize_t max_scf_pg_type_len; 206 ssize_t max_scf_value_len; 207 static size_t max_scf_len; 208 209 static scf_scope_t *cur_scope; 210 static scf_service_t *cur_svc = NULL; 211 static scf_instance_t *cur_inst = NULL; 212 static scf_snapshot_t *cur_snap = NULL; 213 static scf_snaplevel_t *cur_level = NULL; 214 215 static uu_list_pool_t *snaplevel_pool; 216 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 217 static uu_list_t *cur_levels; 218 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 219 220 static FILE *tempfile = NULL; 221 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 222 223 static const char *emsg_entity_not_selected; 224 static const char *emsg_permission_denied; 225 static const char *emsg_create_xml; 226 static const char *emsg_cant_modify_snapshots; 227 static const char *emsg_invalid_for_snapshot; 228 static const char *emsg_read_only; 229 static const char *emsg_deleted; 230 static const char *emsg_invalid_pg_name; 231 static const char *emsg_invalid_prop_name; 232 static const char *emsg_no_such_pg; 233 static const char *emsg_fmri_invalid_pg_name; 234 static const char *emsg_fmri_invalid_pg_name_type; 235 static const char *emsg_pg_added; 236 static const char *emsg_pg_changed; 237 static const char *emsg_pg_deleted; 238 static const char *emsg_pg_mod_perm; 239 static const char *emsg_pg_add_perm; 240 static const char *emsg_pg_del_perm; 241 static const char *emsg_snap_perm; 242 static const char *emsg_dpt_dangling; 243 static const char *emsg_dpt_no_dep; 244 245 static int li_only = 0; 246 static int no_refresh = 0; 247 248 /* how long in ns we should wait between checks for a pg */ 249 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC); 250 251 /* import globals, to minimize allocations */ 252 static scf_scope_t *imp_scope = NULL; 253 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 254 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 255 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 256 static scf_snapshot_t *imp_rsnap = NULL; 257 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 258 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 259 static scf_property_t *imp_prop = NULL; 260 static scf_iter_t *imp_iter = NULL; 261 static scf_iter_t *imp_rpg_iter = NULL; 262 static scf_iter_t *imp_up_iter = NULL; 263 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 264 static char *imp_str = NULL; 265 static size_t imp_str_sz; 266 static char *imp_tsname = NULL; 267 static char *imp_fe1 = NULL; /* for fmri_equal() */ 268 static char *imp_fe2 = NULL; 269 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 270 271 /* upgrade_dependents() globals */ 272 static scf_instance_t *ud_inst = NULL; 273 static scf_snaplevel_t *ud_snpl = NULL; 274 static scf_propertygroup_t *ud_pg = NULL; 275 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 276 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 277 static int ud_run_dpts_pg_set = 0; 278 static scf_property_t *ud_prop = NULL; 279 static scf_property_t *ud_dpt_prop = NULL; 280 static scf_value_t *ud_val = NULL; 281 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 282 static scf_transaction_t *ud_tx = NULL; 283 static char *ud_ctarg = NULL; 284 static char *ud_oldtarg = NULL; 285 static char *ud_name = NULL; 286 287 /* export globals */ 288 static scf_instance_t *exp_inst; 289 static scf_propertygroup_t *exp_pg; 290 static scf_property_t *exp_prop; 291 static scf_value_t *exp_val; 292 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 293 static char *exp_str; 294 static size_t exp_str_sz; 295 296 /* cleanup globals */ 297 static uu_avl_pool_t *service_manifest_pool = NULL; 298 static uu_avl_t *service_manifest_tree = NULL; 299 300 static void scfdie_lineno(int lineno) __NORETURN; 301 302 static char *start_method_names[] = { 303 "start", 304 "inetd_start", 305 NULL 306 }; 307 308 static struct uri_scheme { 309 const char *scheme; 310 const char *protocol; 311 } uri_scheme[] = { 312 { "mailto", "smtp" }, 313 { "snmp", "snmp" }, 314 { "syslog", "syslog" }, 315 { NULL, NULL } 316 }; 317 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \ 318 sizeof (struct uri_scheme)) - 1) 319 320 static int 321 check_uri_scheme(const char *scheme) 322 { 323 int i; 324 325 for (i = 0; uri_scheme[i].scheme != NULL; ++i) { 326 if (strcmp(scheme, uri_scheme[i].scheme) == 0) 327 return (i); 328 } 329 330 return (-1); 331 } 332 333 static int 334 check_uri_protocol(const char *p) 335 { 336 int i; 337 338 for (i = 0; uri_scheme[i].protocol != NULL; ++i) { 339 if (strcmp(p, uri_scheme[i].protocol) == 0) 340 return (i); 341 } 342 343 return (-1); 344 } 345 346 /* 347 * For unexpected libscf errors. 348 */ 349 #ifdef NDEBUG 350 351 static void scfdie(void) __NORETURN; 352 353 static void 354 scfdie(void) 355 { 356 scf_error_t err = scf_error(); 357 358 if (err == SCF_ERROR_CONNECTION_BROKEN) 359 uu_die(gettext("Repository connection broken. Exiting.\n")); 360 361 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 362 scf_strerror(err)); 363 } 364 365 #else 366 367 #define scfdie() scfdie_lineno(__LINE__) 368 369 static void 370 scfdie_lineno(int lineno) 371 { 372 scf_error_t err = scf_error(); 373 374 if (err == SCF_ERROR_CONNECTION_BROKEN) 375 uu_die(gettext("Repository connection broken. Exiting.\n")); 376 377 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 378 ": %s.\n"), lineno, scf_strerror(err)); 379 } 380 381 #endif 382 383 static void 384 scfwarn(void) 385 { 386 warn(gettext("Unexpected libscf error: %s.\n"), 387 scf_strerror(scf_error())); 388 } 389 390 /* 391 * Clear a field of a structure. 392 */ 393 static int 394 clear_int(void *a, void *b) 395 { 396 /* LINTED */ 397 *(int *)((char *)a + (size_t)b) = 0; 398 399 return (UU_WALK_NEXT); 400 } 401 402 static int 403 scferror2errno(scf_error_t err) 404 { 405 switch (err) { 406 case SCF_ERROR_BACKEND_ACCESS: 407 return (EACCES); 408 409 case SCF_ERROR_BACKEND_READONLY: 410 return (EROFS); 411 412 case SCF_ERROR_CONNECTION_BROKEN: 413 return (ECONNABORTED); 414 415 case SCF_ERROR_CONSTRAINT_VIOLATED: 416 case SCF_ERROR_INVALID_ARGUMENT: 417 return (EINVAL); 418 419 case SCF_ERROR_DELETED: 420 return (ECANCELED); 421 422 case SCF_ERROR_EXISTS: 423 return (EEXIST); 424 425 case SCF_ERROR_NO_MEMORY: 426 return (ENOMEM); 427 428 case SCF_ERROR_NO_RESOURCES: 429 return (ENOSPC); 430 431 case SCF_ERROR_NOT_FOUND: 432 return (ENOENT); 433 434 case SCF_ERROR_PERMISSION_DENIED: 435 return (EPERM); 436 437 default: 438 #ifndef NDEBUG 439 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 440 __FILE__, __LINE__, err); 441 #else 442 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 443 #endif 444 abort(); 445 /* NOTREACHED */ 446 } 447 } 448 449 static int 450 entity_get_pg(void *ent, int issvc, const char *name, 451 scf_propertygroup_t *pg) 452 { 453 if (issvc) 454 return (scf_service_get_pg(ent, name, pg)); 455 else 456 return (scf_instance_get_pg(ent, name, pg)); 457 } 458 459 static void 460 entity_destroy(void *ent, int issvc) 461 { 462 if (issvc) 463 scf_service_destroy(ent); 464 else 465 scf_instance_destroy(ent); 466 } 467 468 static int 469 get_pg(const char *pg_name, scf_propertygroup_t *pg) 470 { 471 int ret; 472 473 if (cur_level != NULL) 474 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 475 else if (cur_inst != NULL) 476 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 477 else 478 ret = scf_service_get_pg(cur_svc, pg_name, pg); 479 480 return (ret); 481 } 482 483 /* 484 * Find a snaplevel in a snapshot. If get_svc is true, find the service 485 * snaplevel. Otherwise find the instance snaplevel. 486 * 487 * Returns 488 * 0 - success 489 * ECONNABORTED - repository connection broken 490 * ECANCELED - instance containing snap was deleted 491 * ENOENT - snap has no snaplevels 492 * - requested snaplevel not found 493 */ 494 static int 495 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 496 { 497 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 498 switch (scf_error()) { 499 case SCF_ERROR_CONNECTION_BROKEN: 500 case SCF_ERROR_DELETED: 501 case SCF_ERROR_NOT_FOUND: 502 return (scferror2errno(scf_error())); 503 504 case SCF_ERROR_HANDLE_MISMATCH: 505 case SCF_ERROR_NOT_BOUND: 506 case SCF_ERROR_NOT_SET: 507 default: 508 bad_error("scf_snapshot_get_base_snaplevel", 509 scf_error()); 510 } 511 } 512 513 for (;;) { 514 ssize_t ssz; 515 516 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 517 if (ssz >= 0) { 518 if (!get_svc) 519 return (0); 520 } else { 521 switch (scf_error()) { 522 case SCF_ERROR_CONSTRAINT_VIOLATED: 523 if (get_svc) 524 return (0); 525 break; 526 527 case SCF_ERROR_DELETED: 528 case SCF_ERROR_CONNECTION_BROKEN: 529 return (scferror2errno(scf_error())); 530 531 case SCF_ERROR_NOT_SET: 532 case SCF_ERROR_NOT_BOUND: 533 default: 534 bad_error("scf_snaplevel_get_instance_name", 535 scf_error()); 536 } 537 } 538 539 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 540 switch (scf_error()) { 541 case SCF_ERROR_NOT_FOUND: 542 case SCF_ERROR_CONNECTION_BROKEN: 543 case SCF_ERROR_DELETED: 544 return (scferror2errno(scf_error())); 545 546 case SCF_ERROR_HANDLE_MISMATCH: 547 case SCF_ERROR_NOT_BOUND: 548 case SCF_ERROR_NOT_SET: 549 case SCF_ERROR_INVALID_ARGUMENT: 550 default: 551 bad_error("scf_snaplevel_get_next_snaplevel", 552 scf_error()); 553 } 554 } 555 } 556 } 557 558 /* 559 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 560 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 561 * the property group named name in it. If it doesn't have a running 562 * snapshot, set pg to the instance's current property group named name. 563 * 564 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 565 * its instances. If one has a running snapshot with a service snaplevel, set 566 * pg to the property group named name in it. If no such snaplevel could be 567 * found, set pg to the service's current property group named name. 568 * 569 * iter, inst, snap, and snpl are required scratch objects. 570 * 571 * Returns 572 * 0 - success 573 * ECONNABORTED - repository connection broken 574 * ECANCELED - ent was deleted 575 * ENOENT - no such property group 576 * EINVAL - name is an invalid property group name 577 * EBADF - found running snapshot is missing a snaplevel 578 */ 579 static int 580 entity_get_running_pg(void *ent, int issvc, const char *name, 581 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 582 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 583 { 584 int r; 585 586 if (issvc) { 587 /* Search for an instance with a running snapshot. */ 588 if (scf_iter_service_instances(iter, ent) != 0) { 589 switch (scf_error()) { 590 case SCF_ERROR_DELETED: 591 case SCF_ERROR_CONNECTION_BROKEN: 592 return (scferror2errno(scf_error())); 593 594 case SCF_ERROR_NOT_SET: 595 case SCF_ERROR_NOT_BOUND: 596 case SCF_ERROR_HANDLE_MISMATCH: 597 default: 598 bad_error("scf_iter_service_instances", 599 scf_error()); 600 } 601 } 602 603 for (;;) { 604 r = scf_iter_next_instance(iter, inst); 605 if (r == 0) { 606 if (scf_service_get_pg(ent, name, pg) == 0) 607 return (0); 608 609 switch (scf_error()) { 610 case SCF_ERROR_DELETED: 611 case SCF_ERROR_NOT_FOUND: 612 case SCF_ERROR_INVALID_ARGUMENT: 613 case SCF_ERROR_CONNECTION_BROKEN: 614 return (scferror2errno(scf_error())); 615 616 case SCF_ERROR_NOT_BOUND: 617 case SCF_ERROR_HANDLE_MISMATCH: 618 case SCF_ERROR_NOT_SET: 619 default: 620 bad_error("scf_service_get_pg", 621 scf_error()); 622 } 623 } 624 if (r != 1) { 625 switch (scf_error()) { 626 case SCF_ERROR_DELETED: 627 case SCF_ERROR_CONNECTION_BROKEN: 628 return (scferror2errno(scf_error())); 629 630 case SCF_ERROR_INVALID_ARGUMENT: 631 case SCF_ERROR_NOT_SET: 632 case SCF_ERROR_NOT_BOUND: 633 case SCF_ERROR_HANDLE_MISMATCH: 634 default: 635 bad_error("scf_iter_next_instance", 636 scf_error()); 637 } 638 } 639 640 if (scf_instance_get_snapshot(inst, snap_running, 641 snap) == 0) 642 break; 643 644 switch (scf_error()) { 645 case SCF_ERROR_NOT_FOUND: 646 case SCF_ERROR_DELETED: 647 continue; 648 649 case SCF_ERROR_CONNECTION_BROKEN: 650 return (ECONNABORTED); 651 652 case SCF_ERROR_HANDLE_MISMATCH: 653 case SCF_ERROR_INVALID_ARGUMENT: 654 case SCF_ERROR_NOT_SET: 655 case SCF_ERROR_NOT_BOUND: 656 default: 657 bad_error("scf_instance_get_snapshot", 658 scf_error()); 659 } 660 } 661 } else { 662 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 663 switch (scf_error()) { 664 case SCF_ERROR_NOT_FOUND: 665 break; 666 667 case SCF_ERROR_DELETED: 668 case SCF_ERROR_CONNECTION_BROKEN: 669 return (scferror2errno(scf_error())); 670 671 case SCF_ERROR_NOT_BOUND: 672 case SCF_ERROR_HANDLE_MISMATCH: 673 case SCF_ERROR_INVALID_ARGUMENT: 674 case SCF_ERROR_NOT_SET: 675 default: 676 bad_error("scf_instance_get_snapshot", 677 scf_error()); 678 } 679 680 if (scf_instance_get_pg(ent, name, pg) == 0) 681 return (0); 682 683 switch (scf_error()) { 684 case SCF_ERROR_DELETED: 685 case SCF_ERROR_NOT_FOUND: 686 case SCF_ERROR_INVALID_ARGUMENT: 687 case SCF_ERROR_CONNECTION_BROKEN: 688 return (scferror2errno(scf_error())); 689 690 case SCF_ERROR_NOT_BOUND: 691 case SCF_ERROR_HANDLE_MISMATCH: 692 case SCF_ERROR_NOT_SET: 693 default: 694 bad_error("scf_instance_get_pg", scf_error()); 695 } 696 } 697 } 698 699 r = get_snaplevel(snap, issvc, snpl); 700 switch (r) { 701 case 0: 702 break; 703 704 case ECONNABORTED: 705 case ECANCELED: 706 return (r); 707 708 case ENOENT: 709 return (EBADF); 710 711 default: 712 bad_error("get_snaplevel", r); 713 } 714 715 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 716 return (0); 717 718 switch (scf_error()) { 719 case SCF_ERROR_DELETED: 720 case SCF_ERROR_INVALID_ARGUMENT: 721 case SCF_ERROR_CONNECTION_BROKEN: 722 case SCF_ERROR_NOT_FOUND: 723 return (scferror2errno(scf_error())); 724 725 case SCF_ERROR_NOT_BOUND: 726 case SCF_ERROR_HANDLE_MISMATCH: 727 case SCF_ERROR_NOT_SET: 728 default: 729 bad_error("scf_snaplevel_get_pg", scf_error()); 730 /* NOTREACHED */ 731 } 732 } 733 734 /* 735 * To be registered with atexit(). 736 */ 737 static void 738 remove_tempfile(void) 739 { 740 int ret; 741 742 if (tempfile != NULL) { 743 if (fclose(tempfile) == EOF) 744 (void) warn(gettext("Could not close temporary file")); 745 tempfile = NULL; 746 } 747 748 if (tempfilename[0] != '\0') { 749 do { 750 ret = remove(tempfilename); 751 } while (ret == -1 && errno == EINTR); 752 if (ret == -1) 753 warn(gettext("Could not remove temporary file")); 754 tempfilename[0] = '\0'; 755 } 756 } 757 758 /* 759 * Launch private svc.configd(8) for manipulating alternate repositories. 760 */ 761 static void 762 start_private_repository(engine_state_t *est) 763 { 764 int fd, stat; 765 struct door_info info; 766 pid_t pid; 767 768 /* 769 * 1. Create a temporary file for the door. 770 */ 771 if (est->sc_repo_doorname != NULL) 772 free((void *)est->sc_repo_doorname); 773 774 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 775 if (est->sc_repo_doorname == NULL) 776 uu_die(gettext("Could not acquire temporary filename")); 777 778 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 779 if (fd < 0) 780 uu_die(gettext("Could not create temporary file for " 781 "repository server")); 782 783 (void) close(fd); 784 785 /* 786 * 2. Launch a configd with that door, using the specified 787 * repository. 788 */ 789 if ((est->sc_repo_pid = fork()) == 0) { 790 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 791 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 792 NULL); 793 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 794 } else if (est->sc_repo_pid == -1) 795 uu_die(gettext("Attempt to fork failed")); 796 797 do { 798 pid = waitpid(est->sc_repo_pid, &stat, 0); 799 } while (pid == -1 && errno == EINTR); 800 801 if (pid == -1) 802 uu_die(gettext("Could not waitpid() for repository server")); 803 804 if (!WIFEXITED(stat)) { 805 uu_die(gettext("Repository server failed (status %d).\n"), 806 stat); 807 } else if (WEXITSTATUS(stat) != 0) { 808 uu_die(gettext("Repository server failed (exit %d).\n"), 809 WEXITSTATUS(stat)); 810 } 811 812 /* 813 * See if it was successful by checking if the door is a door. 814 */ 815 816 fd = open(est->sc_repo_doorname, O_RDWR); 817 if (fd < 0) 818 uu_die(gettext("Could not open door \"%s\""), 819 est->sc_repo_doorname); 820 821 if (door_info(fd, &info) < 0) 822 uu_die(gettext("Unexpected door_info() error")); 823 824 if (close(fd) == -1) 825 warn(gettext("Could not close repository door"), 826 strerror(errno)); 827 828 est->sc_repo_pid = info.di_target; 829 } 830 831 void 832 lscf_cleanup(void) 833 { 834 /* 835 * In the case where we've launched a private svc.configd(8) 836 * instance, we must terminate our child and remove the temporary 837 * rendezvous point. 838 */ 839 if (est->sc_repo_pid > 0) { 840 (void) kill(est->sc_repo_pid, SIGTERM); 841 (void) waitpid(est->sc_repo_pid, NULL, 0); 842 (void) unlink(est->sc_repo_doorname); 843 844 est->sc_repo_pid = 0; 845 } 846 } 847 848 void 849 unselect_cursnap(void) 850 { 851 void *cookie; 852 853 cur_level = NULL; 854 855 cookie = NULL; 856 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 857 scf_snaplevel_destroy(cur_elt->sl); 858 free(cur_elt); 859 } 860 861 scf_snapshot_destroy(cur_snap); 862 cur_snap = NULL; 863 } 864 865 void 866 lscf_prep_hndl(void) 867 { 868 if (g_hndl != NULL) 869 return; 870 871 g_hndl = scf_handle_create(SCF_VERSION); 872 if (g_hndl == NULL) 873 scfdie(); 874 875 if (est->sc_repo_filename != NULL) 876 start_private_repository(est); 877 878 if (est->sc_repo_doorname != NULL) { 879 scf_value_t *repo_value; 880 int ret; 881 882 repo_value = scf_value_create(g_hndl); 883 if (repo_value == NULL) 884 scfdie(); 885 886 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 887 assert(ret == SCF_SUCCESS); 888 889 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 890 SCF_SUCCESS) 891 scfdie(); 892 893 scf_value_destroy(repo_value); 894 } 895 896 if (scf_handle_bind(g_hndl) != 0) 897 uu_die(gettext("Could not connect to repository server: %s.\n"), 898 scf_strerror(scf_error())); 899 900 cur_scope = scf_scope_create(g_hndl); 901 if (cur_scope == NULL) 902 scfdie(); 903 904 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 905 scfdie(); 906 } 907 908 static void 909 repository_teardown(void) 910 { 911 if (g_hndl != NULL) { 912 if (cur_snap != NULL) 913 unselect_cursnap(); 914 scf_instance_destroy(cur_inst); 915 scf_service_destroy(cur_svc); 916 scf_scope_destroy(cur_scope); 917 scf_handle_destroy(g_hndl); 918 cur_inst = NULL; 919 cur_svc = NULL; 920 cur_scope = NULL; 921 g_hndl = NULL; 922 lscf_cleanup(); 923 } 924 } 925 926 void 927 lscf_set_repository(const char *repfile, int force) 928 { 929 repository_teardown(); 930 931 if (est->sc_repo_filename != NULL) { 932 free((void *)est->sc_repo_filename); 933 est->sc_repo_filename = NULL; 934 } 935 936 if ((force == 0) && (access(repfile, R_OK) != 0)) { 937 /* 938 * Repository file does not exist 939 * or has no read permission. 940 */ 941 warn(gettext("Cannot access \"%s\": %s\n"), 942 repfile, strerror(errno)); 943 } else { 944 est->sc_repo_filename = safe_strdup(repfile); 945 } 946 947 lscf_prep_hndl(); 948 } 949 950 void 951 lscf_init() 952 { 953 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 954 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 955 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 956 0 || 957 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 958 scfdie(); 959 960 max_scf_len = max_scf_fmri_len; 961 if (max_scf_name_len > max_scf_len) 962 max_scf_len = max_scf_name_len; 963 if (max_scf_pg_type_len > max_scf_len) 964 max_scf_len = max_scf_pg_type_len; 965 /* 966 * When a value of type opaque is represented as a string, the 967 * string contains 2 characters for every byte of data. That is 968 * because the string contains the hex representation of the opaque 969 * value. 970 */ 971 if (2 * max_scf_value_len > max_scf_len) 972 max_scf_len = 2 * max_scf_value_len; 973 974 if (atexit(remove_tempfile) != 0) 975 uu_die(gettext("Could not register atexit() function")); 976 977 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 978 emsg_permission_denied = gettext("Permission denied.\n"); 979 emsg_create_xml = gettext("Could not create XML node.\n"); 980 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 981 emsg_invalid_for_snapshot = 982 gettext("Invalid operation on a snapshot.\n"); 983 emsg_read_only = gettext("Backend read-only.\n"); 984 emsg_deleted = gettext("Current selection has been deleted.\n"); 985 emsg_invalid_pg_name = 986 gettext("Invalid property group name \"%s\".\n"); 987 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 988 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 989 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 990 "with invalid name \"%s\".\n"); 991 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 992 "group with invalid name \"%s\" or type \"%s\".\n"); 993 emsg_pg_added = gettext("%s changed unexpectedly " 994 "(property group \"%s\" added).\n"); 995 emsg_pg_changed = gettext("%s changed unexpectedly " 996 "(property group \"%s\" changed).\n"); 997 emsg_pg_deleted = gettext("%s changed unexpectedly " 998 "(property group \"%s\" or an ancestor was deleted).\n"); 999 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 1000 "in %s (permission denied).\n"); 1001 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 1002 "in %s (permission denied).\n"); 1003 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 1004 "in %s (permission denied).\n"); 1005 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 1006 "(permission denied).\n"); 1007 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 1008 "new dependent \"%s\" because it already exists). Warning: The " 1009 "current dependent's target (%s) does not exist.\n"); 1010 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 1011 "dependent \"%s\" because it already exists). Warning: The " 1012 "current dependent's target (%s) does not have a dependency named " 1013 "\"%s\" as expected.\n"); 1014 1015 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 1016 offsetof(string_list_t, node), NULL, 0); 1017 snaplevel_pool = uu_list_pool_create("snaplevels", 1018 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 1019 NULL, 0); 1020 } 1021 1022 1023 static const char * 1024 prop_to_typestr(const scf_property_t *prop) 1025 { 1026 scf_type_t ty; 1027 1028 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 1029 scfdie(); 1030 1031 return (scf_type_to_string(ty)); 1032 } 1033 1034 static scf_type_t 1035 string_to_type(const char *type) 1036 { 1037 size_t len = strlen(type); 1038 char *buf; 1039 1040 if (len == 0 || type[len - 1] != ':') 1041 return (SCF_TYPE_INVALID); 1042 1043 buf = (char *)alloca(len + 1); 1044 (void) strlcpy(buf, type, len + 1); 1045 buf[len - 1] = 0; 1046 1047 return (scf_string_to_type(buf)); 1048 } 1049 1050 static scf_value_t * 1051 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 1052 { 1053 scf_value_t *v; 1054 char *dup, *nstr; 1055 size_t len; 1056 1057 v = scf_value_create(g_hndl); 1058 if (v == NULL) 1059 scfdie(); 1060 1061 len = strlen(str); 1062 if (require_quotes && 1063 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1064 semerr(gettext("Multiple string values or string values " 1065 "with spaces must be quoted with '\"'.\n")); 1066 scf_value_destroy(v); 1067 return (NULL); 1068 } 1069 1070 nstr = dup = safe_strdup(str); 1071 if (dup[0] == '\"') { 1072 /* 1073 * Strip out the first and the last quote. 1074 */ 1075 dup[len - 1] = '\0'; 1076 nstr = dup + 1; 1077 } 1078 1079 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1080 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1081 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1082 scf_type_to_string(ty), nstr); 1083 scf_value_destroy(v); 1084 v = NULL; 1085 } 1086 free(dup); 1087 return (v); 1088 } 1089 1090 /* 1091 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1092 * Optionally append a comment prefix ('#') to newlines ('\n'). 1093 */ 1094 static int 1095 quote_and_print(const char *str, FILE *strm, int commentnl) 1096 { 1097 const char *cp; 1098 1099 for (cp = str; *cp != '\0'; ++cp) { 1100 if (*cp == '"' || *cp == '\\') 1101 (void) putc('\\', strm); 1102 1103 (void) putc(*cp, strm); 1104 1105 if (commentnl && *cp == '\n') { 1106 (void) putc('#', strm); 1107 } 1108 } 1109 1110 return (ferror(strm)); 1111 } 1112 1113 /* 1114 * These wrappers around lowlevel functions provide consistent error checking 1115 * and warnings. 1116 */ 1117 static int 1118 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1119 { 1120 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1121 return (0); 1122 1123 if (scf_error() != SCF_ERROR_NOT_FOUND) 1124 scfdie(); 1125 1126 if (g_verbose) { 1127 ssize_t len; 1128 char *fmri; 1129 1130 len = scf_pg_to_fmri(pg, NULL, 0); 1131 if (len < 0) 1132 scfdie(); 1133 1134 fmri = safe_malloc(len + 1); 1135 1136 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1137 scfdie(); 1138 1139 warn(gettext("Expected property %s of property group %s is " 1140 "missing.\n"), propname, fmri); 1141 1142 free(fmri); 1143 } 1144 1145 return (-1); 1146 } 1147 1148 static int 1149 prop_check_type(scf_property_t *prop, scf_type_t ty) 1150 { 1151 scf_type_t pty; 1152 1153 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1154 scfdie(); 1155 1156 if (ty == pty) 1157 return (0); 1158 1159 if (g_verbose) { 1160 ssize_t len; 1161 char *fmri; 1162 const char *tystr; 1163 1164 len = scf_property_to_fmri(prop, NULL, 0); 1165 if (len < 0) 1166 scfdie(); 1167 1168 fmri = safe_malloc(len + 1); 1169 1170 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1171 scfdie(); 1172 1173 tystr = scf_type_to_string(ty); 1174 if (tystr == NULL) 1175 tystr = "?"; 1176 1177 warn(gettext("Property %s is not of expected type %s.\n"), 1178 fmri, tystr); 1179 1180 free(fmri); 1181 } 1182 1183 return (-1); 1184 } 1185 1186 static int 1187 prop_get_val(scf_property_t *prop, scf_value_t *val) 1188 { 1189 scf_error_t err; 1190 1191 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1192 return (0); 1193 1194 err = scf_error(); 1195 1196 if (err != SCF_ERROR_NOT_FOUND && 1197 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1198 err != SCF_ERROR_PERMISSION_DENIED) 1199 scfdie(); 1200 1201 if (g_verbose) { 1202 ssize_t len; 1203 char *fmri, *emsg; 1204 1205 len = scf_property_to_fmri(prop, NULL, 0); 1206 if (len < 0) 1207 scfdie(); 1208 1209 fmri = safe_malloc(len + 1); 1210 1211 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1212 scfdie(); 1213 1214 if (err == SCF_ERROR_NOT_FOUND) 1215 emsg = gettext("Property %s has no values; expected " 1216 "one.\n"); 1217 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1218 emsg = gettext("Property %s has multiple values; " 1219 "expected one.\n"); 1220 else 1221 emsg = gettext("No permission to read property %s.\n"); 1222 1223 warn(emsg, fmri); 1224 1225 free(fmri); 1226 } 1227 1228 return (-1); 1229 } 1230 1231 1232 static boolean_t 1233 snaplevel_is_instance(const scf_snaplevel_t *level) 1234 { 1235 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1236 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1237 scfdie(); 1238 return (0); 1239 } else { 1240 return (1); 1241 } 1242 } 1243 1244 /* 1245 * Decode FMRI into a service or instance, and put the result in *ep. If 1246 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1247 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1248 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1249 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1250 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1251 * whether *ep is a service. 1252 */ 1253 static scf_error_t 1254 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1255 { 1256 char *fmri_copy; 1257 const char *sstr, *istr, *pgstr; 1258 scf_service_t *svc; 1259 scf_instance_t *inst; 1260 1261 fmri_copy = strdup(fmri); 1262 if (fmri_copy == NULL) 1263 return (SCF_ERROR_NO_MEMORY); 1264 1265 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1266 SCF_SUCCESS) { 1267 free(fmri_copy); 1268 return (SCF_ERROR_INVALID_ARGUMENT); 1269 } 1270 1271 free(fmri_copy); 1272 1273 if (sstr == NULL || pgstr != NULL) 1274 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1275 1276 if (istr == NULL) { 1277 svc = scf_service_create(h); 1278 if (svc == NULL) 1279 return (SCF_ERROR_NO_MEMORY); 1280 1281 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1282 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1283 if (scf_error() != SCF_ERROR_NOT_FOUND) 1284 scfdie(); 1285 1286 return (SCF_ERROR_NOT_FOUND); 1287 } 1288 1289 *ep = svc; 1290 *isservice = 1; 1291 } else { 1292 inst = scf_instance_create(h); 1293 if (inst == NULL) 1294 return (SCF_ERROR_NO_MEMORY); 1295 1296 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1297 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1298 if (scf_error() != SCF_ERROR_NOT_FOUND) 1299 scfdie(); 1300 1301 return (SCF_ERROR_NOT_FOUND); 1302 } 1303 1304 *ep = inst; 1305 *isservice = 0; 1306 } 1307 1308 return (SCF_ERROR_NONE); 1309 } 1310 1311 /* 1312 * Create the entity named by fmri. Place a pointer to its libscf handle in 1313 * *ep, and set or clear *isservicep if it is a service or an instance. 1314 * Returns 1315 * SCF_ERROR_NONE - success 1316 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1317 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1318 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1319 * SCF_ERROR_NOT_FOUND - no such scope 1320 * SCF_ERROR_PERMISSION_DENIED 1321 * SCF_ERROR_BACKEND_READONLY 1322 * SCF_ERROR_BACKEND_ACCESS 1323 */ 1324 static scf_error_t 1325 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1326 { 1327 char *fmri_copy; 1328 const char *scstr, *sstr, *istr, *pgstr; 1329 scf_scope_t *scope = NULL; 1330 scf_service_t *svc = NULL; 1331 scf_instance_t *inst = NULL; 1332 scf_error_t scfe; 1333 1334 fmri_copy = safe_strdup(fmri); 1335 1336 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1337 0) { 1338 free(fmri_copy); 1339 return (SCF_ERROR_INVALID_ARGUMENT); 1340 } 1341 1342 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1343 free(fmri_copy); 1344 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1345 } 1346 1347 *ep = NULL; 1348 1349 if ((scope = scf_scope_create(h)) == NULL || 1350 (svc = scf_service_create(h)) == NULL || 1351 (inst = scf_instance_create(h)) == NULL) { 1352 scfe = SCF_ERROR_NO_MEMORY; 1353 goto out; 1354 } 1355 1356 get_scope: 1357 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1358 switch (scf_error()) { 1359 case SCF_ERROR_CONNECTION_BROKEN: 1360 scfdie(); 1361 /* NOTREACHED */ 1362 1363 case SCF_ERROR_NOT_FOUND: 1364 scfe = SCF_ERROR_NOT_FOUND; 1365 goto out; 1366 1367 case SCF_ERROR_HANDLE_MISMATCH: 1368 case SCF_ERROR_NOT_BOUND: 1369 case SCF_ERROR_INVALID_ARGUMENT: 1370 default: 1371 bad_error("scf_handle_get_scope", scf_error()); 1372 } 1373 } 1374 1375 get_svc: 1376 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1377 switch (scf_error()) { 1378 case SCF_ERROR_CONNECTION_BROKEN: 1379 scfdie(); 1380 /* NOTREACHED */ 1381 1382 case SCF_ERROR_DELETED: 1383 goto get_scope; 1384 1385 case SCF_ERROR_NOT_FOUND: 1386 break; 1387 1388 case SCF_ERROR_HANDLE_MISMATCH: 1389 case SCF_ERROR_INVALID_ARGUMENT: 1390 case SCF_ERROR_NOT_BOUND: 1391 case SCF_ERROR_NOT_SET: 1392 default: 1393 bad_error("scf_scope_get_service", scf_error()); 1394 } 1395 1396 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1397 switch (scf_error()) { 1398 case SCF_ERROR_CONNECTION_BROKEN: 1399 scfdie(); 1400 /* NOTREACHED */ 1401 1402 case SCF_ERROR_DELETED: 1403 goto get_scope; 1404 1405 case SCF_ERROR_PERMISSION_DENIED: 1406 case SCF_ERROR_BACKEND_READONLY: 1407 case SCF_ERROR_BACKEND_ACCESS: 1408 scfe = scf_error(); 1409 goto out; 1410 1411 case SCF_ERROR_HANDLE_MISMATCH: 1412 case SCF_ERROR_INVALID_ARGUMENT: 1413 case SCF_ERROR_NOT_BOUND: 1414 case SCF_ERROR_NOT_SET: 1415 default: 1416 bad_error("scf_scope_get_service", scf_error()); 1417 } 1418 } 1419 } 1420 1421 if (istr == NULL) { 1422 scfe = SCF_ERROR_NONE; 1423 *ep = svc; 1424 *isservicep = 1; 1425 goto out; 1426 } 1427 1428 get_inst: 1429 if (scf_service_get_instance(svc, istr, inst) != 0) { 1430 switch (scf_error()) { 1431 case SCF_ERROR_CONNECTION_BROKEN: 1432 scfdie(); 1433 /* NOTREACHED */ 1434 1435 case SCF_ERROR_DELETED: 1436 goto get_svc; 1437 1438 case SCF_ERROR_NOT_FOUND: 1439 break; 1440 1441 case SCF_ERROR_HANDLE_MISMATCH: 1442 case SCF_ERROR_INVALID_ARGUMENT: 1443 case SCF_ERROR_NOT_BOUND: 1444 case SCF_ERROR_NOT_SET: 1445 default: 1446 bad_error("scf_service_get_instance", scf_error()); 1447 } 1448 1449 if (scf_service_add_instance(svc, istr, inst) != 0) { 1450 switch (scf_error()) { 1451 case SCF_ERROR_CONNECTION_BROKEN: 1452 scfdie(); 1453 /* NOTREACHED */ 1454 1455 case SCF_ERROR_DELETED: 1456 goto get_svc; 1457 1458 case SCF_ERROR_PERMISSION_DENIED: 1459 case SCF_ERROR_BACKEND_READONLY: 1460 case SCF_ERROR_BACKEND_ACCESS: 1461 scfe = scf_error(); 1462 goto out; 1463 1464 case SCF_ERROR_HANDLE_MISMATCH: 1465 case SCF_ERROR_INVALID_ARGUMENT: 1466 case SCF_ERROR_NOT_BOUND: 1467 case SCF_ERROR_NOT_SET: 1468 default: 1469 bad_error("scf_service_add_instance", 1470 scf_error()); 1471 } 1472 } 1473 } 1474 1475 scfe = SCF_ERROR_NONE; 1476 *ep = inst; 1477 *isservicep = 0; 1478 1479 out: 1480 if (*ep != inst) 1481 scf_instance_destroy(inst); 1482 if (*ep != svc) 1483 scf_service_destroy(svc); 1484 scf_scope_destroy(scope); 1485 free(fmri_copy); 1486 return (scfe); 1487 } 1488 1489 /* 1490 * Create or update a snapshot of inst. snap is a required scratch object. 1491 * 1492 * Returns 1493 * 0 - success 1494 * ECONNABORTED - repository connection broken 1495 * EPERM - permission denied 1496 * ENOSPC - configd is out of resources 1497 * ECANCELED - inst was deleted 1498 * -1 - unknown libscf error (message printed) 1499 */ 1500 static int 1501 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1502 { 1503 again: 1504 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1505 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1506 switch (scf_error()) { 1507 case SCF_ERROR_CONNECTION_BROKEN: 1508 case SCF_ERROR_PERMISSION_DENIED: 1509 case SCF_ERROR_NO_RESOURCES: 1510 return (scferror2errno(scf_error())); 1511 1512 case SCF_ERROR_NOT_SET: 1513 case SCF_ERROR_INVALID_ARGUMENT: 1514 default: 1515 bad_error("_scf_snapshot_take_attach", 1516 scf_error()); 1517 } 1518 } 1519 } else { 1520 switch (scf_error()) { 1521 case SCF_ERROR_NOT_FOUND: 1522 break; 1523 1524 case SCF_ERROR_DELETED: 1525 case SCF_ERROR_CONNECTION_BROKEN: 1526 return (scferror2errno(scf_error())); 1527 1528 case SCF_ERROR_HANDLE_MISMATCH: 1529 case SCF_ERROR_NOT_BOUND: 1530 case SCF_ERROR_INVALID_ARGUMENT: 1531 case SCF_ERROR_NOT_SET: 1532 default: 1533 bad_error("scf_instance_get_snapshot", scf_error()); 1534 } 1535 1536 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1537 switch (scf_error()) { 1538 case SCF_ERROR_EXISTS: 1539 goto again; 1540 1541 case SCF_ERROR_CONNECTION_BROKEN: 1542 case SCF_ERROR_NO_RESOURCES: 1543 case SCF_ERROR_PERMISSION_DENIED: 1544 return (scferror2errno(scf_error())); 1545 1546 default: 1547 scfwarn(); 1548 return (-1); 1549 1550 case SCF_ERROR_NOT_SET: 1551 case SCF_ERROR_INTERNAL: 1552 case SCF_ERROR_INVALID_ARGUMENT: 1553 case SCF_ERROR_HANDLE_MISMATCH: 1554 bad_error("_scf_snapshot_take_new", 1555 scf_error()); 1556 } 1557 } 1558 } 1559 1560 return (0); 1561 } 1562 1563 static int 1564 refresh_running_snapshot(void *entity) 1565 { 1566 scf_snapshot_t *snap; 1567 int r; 1568 1569 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1570 scfdie(); 1571 r = take_snap(entity, snap_running, snap); 1572 scf_snapshot_destroy(snap); 1573 1574 return (r); 1575 } 1576 1577 /* 1578 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1579 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1580 * instances. fmri is used for messages. inst, iter, and name_buf are used 1581 * for scratch space. Returns 1582 * 0 - success 1583 * ECONNABORTED - repository connection broken 1584 * ECANCELED - entity was deleted 1585 * EACCES - backend denied access 1586 * EPERM - permission denied 1587 * ENOSPC - repository server out of resources 1588 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1589 */ 1590 static int 1591 refresh_entity(int isservice, void *entity, const char *fmri, 1592 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1593 { 1594 scf_error_t scfe; 1595 int r; 1596 1597 if (!isservice) { 1598 /* 1599 * Let restarter handles refreshing and making new running 1600 * snapshot only if operating on a live repository and not 1601 * running in early import. 1602 */ 1603 if (est->sc_repo_filename == NULL && 1604 est->sc_repo_doorname == NULL && 1605 est->sc_in_emi == 0) { 1606 if (_smf_refresh_instance_i(entity) == 0) { 1607 if (g_verbose) 1608 warn(gettext("Refreshed %s.\n"), fmri); 1609 return (0); 1610 } 1611 1612 switch (scf_error()) { 1613 case SCF_ERROR_BACKEND_ACCESS: 1614 return (EACCES); 1615 1616 case SCF_ERROR_PERMISSION_DENIED: 1617 return (EPERM); 1618 1619 default: 1620 return (-1); 1621 } 1622 } else { 1623 r = refresh_running_snapshot(entity); 1624 switch (r) { 1625 case 0: 1626 break; 1627 1628 case ECONNABORTED: 1629 case ECANCELED: 1630 case EPERM: 1631 case ENOSPC: 1632 break; 1633 1634 default: 1635 bad_error("refresh_running_snapshot", 1636 scf_error()); 1637 } 1638 1639 return (r); 1640 } 1641 } 1642 1643 if (scf_iter_service_instances(iter, entity) != 0) { 1644 switch (scf_error()) { 1645 case SCF_ERROR_CONNECTION_BROKEN: 1646 return (ECONNABORTED); 1647 1648 case SCF_ERROR_DELETED: 1649 return (ECANCELED); 1650 1651 case SCF_ERROR_HANDLE_MISMATCH: 1652 case SCF_ERROR_NOT_BOUND: 1653 case SCF_ERROR_NOT_SET: 1654 default: 1655 bad_error("scf_iter_service_instances", scf_error()); 1656 } 1657 } 1658 1659 for (;;) { 1660 r = scf_iter_next_instance(iter, inst); 1661 if (r == 0) 1662 break; 1663 if (r != 1) { 1664 switch (scf_error()) { 1665 case SCF_ERROR_CONNECTION_BROKEN: 1666 return (ECONNABORTED); 1667 1668 case SCF_ERROR_DELETED: 1669 return (ECANCELED); 1670 1671 case SCF_ERROR_HANDLE_MISMATCH: 1672 case SCF_ERROR_NOT_BOUND: 1673 case SCF_ERROR_NOT_SET: 1674 case SCF_ERROR_INVALID_ARGUMENT: 1675 default: 1676 bad_error("scf_iter_next_instance", 1677 scf_error()); 1678 } 1679 } 1680 1681 /* 1682 * Similarly, just take a new running snapshot if operating on 1683 * a non-live repository or running during early import. 1684 */ 1685 if (est->sc_repo_filename != NULL || 1686 est->sc_repo_doorname != NULL || 1687 est->sc_in_emi == 1) { 1688 r = refresh_running_snapshot(inst); 1689 switch (r) { 1690 case 0: 1691 continue; 1692 1693 case ECONNABORTED: 1694 case ECANCELED: 1695 case EPERM: 1696 case ENOSPC: 1697 break; 1698 default: 1699 bad_error("refresh_running_snapshot", 1700 scf_error()); 1701 } 1702 1703 return (r); 1704 1705 } 1706 1707 if (_smf_refresh_instance_i(inst) == 0) { 1708 if (g_verbose) { 1709 if (scf_instance_get_name(inst, name_buf, 1710 max_scf_name_len + 1) < 0) 1711 (void) strcpy(name_buf, "?"); 1712 1713 warn(gettext("Refreshed %s:%s.\n"), 1714 fmri, name_buf); 1715 } 1716 } else { 1717 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1718 g_verbose) { 1719 scfe = scf_error(); 1720 1721 if (scf_instance_to_fmri(inst, name_buf, 1722 max_scf_name_len + 1) < 0) 1723 (void) strcpy(name_buf, "?"); 1724 1725 warn(gettext( 1726 "Refresh of %s:%s failed: %s.\n"), fmri, 1727 name_buf, scf_strerror(scfe)); 1728 } 1729 } 1730 } 1731 1732 return (0); 1733 } 1734 1735 static void 1736 private_refresh(void) 1737 { 1738 scf_instance_t *pinst = NULL; 1739 scf_iter_t *piter = NULL; 1740 ssize_t fmrilen; 1741 size_t bufsz; 1742 char *fmribuf; 1743 void *ent; 1744 int issvc; 1745 int r; 1746 1747 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1748 return; 1749 1750 assert(cur_svc != NULL); 1751 1752 bufsz = max_scf_fmri_len + 1; 1753 fmribuf = safe_malloc(bufsz); 1754 if (cur_inst) { 1755 issvc = 0; 1756 ent = cur_inst; 1757 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1758 } else { 1759 issvc = 1; 1760 ent = cur_svc; 1761 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1762 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1763 scfdie(); 1764 1765 if ((piter = scf_iter_create(g_hndl)) == NULL) 1766 scfdie(); 1767 } 1768 if (fmrilen < 0) { 1769 free(fmribuf); 1770 if (scf_error() != SCF_ERROR_DELETED) 1771 scfdie(); 1772 1773 warn(emsg_deleted); 1774 return; 1775 } 1776 assert(fmrilen < bufsz); 1777 1778 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1779 switch (r) { 1780 case 0: 1781 break; 1782 1783 case ECONNABORTED: 1784 warn(gettext("Could not refresh %s " 1785 "(repository connection broken).\n"), fmribuf); 1786 break; 1787 1788 case ECANCELED: 1789 warn(emsg_deleted); 1790 break; 1791 1792 case EPERM: 1793 warn(gettext("Could not refresh %s " 1794 "(permission denied).\n"), fmribuf); 1795 break; 1796 1797 case ENOSPC: 1798 warn(gettext("Could not refresh %s " 1799 "(repository server out of resources).\n"), 1800 fmribuf); 1801 break; 1802 1803 case EACCES: 1804 default: 1805 bad_error("refresh_entity", scf_error()); 1806 } 1807 1808 if (issvc) { 1809 scf_instance_destroy(pinst); 1810 scf_iter_destroy(piter); 1811 } 1812 1813 free(fmribuf); 1814 } 1815 1816 1817 static int 1818 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1819 { 1820 cbp->sc_err = scferror2errno(err); 1821 return (UU_WALK_ERROR); 1822 } 1823 1824 static int 1825 stash_scferror(scf_callback_t *cbp) 1826 { 1827 return (stash_scferror_err(cbp, scf_error())); 1828 } 1829 1830 static int select_inst(const char *); 1831 static int select_svc(const char *); 1832 1833 /* 1834 * Take a property that does not have a type and check to see if a type 1835 * exists or can be gleened from the current data. Set the type. 1836 * 1837 * Check the current level (instance) and then check the higher level 1838 * (service). This could be the case for adding a new property to 1839 * the instance that's going to "override" a service level property. 1840 * 1841 * For a property : 1842 * 1. Take the type from an existing property 1843 * 2. Take the type from a template entry 1844 * 1845 * If the type can not be found, then leave the type as is, and let the import 1846 * report the problem of the missing type. 1847 */ 1848 static int 1849 find_current_prop_type(void *p, void *g) 1850 { 1851 property_t *prop = p; 1852 scf_callback_t *lcb = g; 1853 pgroup_t *pg = NULL; 1854 1855 const char *fmri = NULL; 1856 char *lfmri = NULL; 1857 char *cur_selection = NULL; 1858 1859 scf_propertygroup_t *sc_pg = NULL; 1860 scf_property_t *sc_prop = NULL; 1861 scf_pg_tmpl_t *t_pg = NULL; 1862 scf_prop_tmpl_t *t_prop = NULL; 1863 scf_type_t prop_type; 1864 1865 value_t *vp; 1866 int issvc = lcb->sc_service; 1867 int r = UU_WALK_ERROR; 1868 1869 if (prop->sc_value_type != SCF_TYPE_INVALID) 1870 return (UU_WALK_NEXT); 1871 1872 t_prop = scf_tmpl_prop_create(g_hndl); 1873 sc_prop = scf_property_create(g_hndl); 1874 if (sc_prop == NULL || t_prop == NULL) { 1875 warn(gettext("Unable to create the property to attempt and " 1876 "find a missing type.\n")); 1877 1878 scf_property_destroy(sc_prop); 1879 scf_tmpl_prop_destroy(t_prop); 1880 1881 return (UU_WALK_ERROR); 1882 } 1883 1884 if (lcb->sc_flags == 1) { 1885 pg = lcb->sc_parent; 1886 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT); 1887 fmri = pg->sc_parent->sc_fmri; 1888 retry_pg: 1889 if (cur_svc && cur_selection == NULL) { 1890 cur_selection = safe_malloc(max_scf_fmri_len + 1); 1891 lscf_get_selection_str(cur_selection, 1892 max_scf_fmri_len + 1); 1893 1894 if (strcmp(cur_selection, fmri) != 0) { 1895 lscf_select(fmri); 1896 } else { 1897 free(cur_selection); 1898 cur_selection = NULL; 1899 } 1900 } else { 1901 lscf_select(fmri); 1902 } 1903 1904 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) { 1905 warn(gettext("Unable to create property group to " 1906 "find a missing property type.\n")); 1907 1908 goto out; 1909 } 1910 1911 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) { 1912 /* 1913 * If this is the sc_pg from the parent 1914 * let the caller clean up the sc_pg, 1915 * and just throw it away in this case. 1916 */ 1917 if (sc_pg != lcb->sc_parent) 1918 scf_pg_destroy(sc_pg); 1919 1920 sc_pg = NULL; 1921 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1922 warn(gettext("Unable to create template " 1923 "property group to find a property " 1924 "type.\n")); 1925 1926 goto out; 1927 } 1928 1929 if (scf_tmpl_get_by_pg_name(fmri, NULL, 1930 pg->sc_pgroup_name, NULL, t_pg, 1931 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) { 1932 /* 1933 * if instance get service and jump back 1934 */ 1935 scf_tmpl_pg_destroy(t_pg); 1936 t_pg = NULL; 1937 if (issvc == 0) { 1938 entity_t *e = pg->sc_parent->sc_parent; 1939 1940 fmri = e->sc_fmri; 1941 issvc = 1; 1942 goto retry_pg; 1943 } else { 1944 goto out; 1945 } 1946 } 1947 } 1948 } else { 1949 sc_pg = lcb->sc_parent; 1950 } 1951 1952 /* 1953 * Attempt to get the type from an existing property. If the property 1954 * cannot be found then attempt to get the type from a template entry 1955 * for the property. 1956 * 1957 * Finally, if at the instance level look at the service level. 1958 */ 1959 if (sc_pg != NULL && 1960 pg_get_prop(sc_pg, prop->sc_property_name, 1961 sc_prop) == SCF_SUCCESS && 1962 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) { 1963 prop->sc_value_type = prop_type; 1964 1965 /* 1966 * Found a type, update the value types and validate 1967 * the actual value against this type. 1968 */ 1969 for (vp = uu_list_first(prop->sc_property_values); 1970 vp != NULL; 1971 vp = uu_list_next(prop->sc_property_values, vp)) { 1972 vp->sc_type = prop->sc_value_type; 1973 lxml_store_value(vp, 0, NULL); 1974 } 1975 1976 r = UU_WALK_NEXT; 1977 goto out; 1978 } 1979 1980 /* 1981 * If we get here with t_pg set to NULL then we had to have 1982 * gotten an sc_pg but that sc_pg did not have the property 1983 * we are looking for. So if the t_pg is not null look up 1984 * the template entry for the property. 1985 * 1986 * If the t_pg is null then need to attempt to get a matching 1987 * template entry for the sc_pg, and see if there is a property 1988 * entry for that template entry. 1989 */ 1990 do_tmpl : 1991 if (t_pg != NULL && 1992 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name, 1993 t_prop, 0) == SCF_SUCCESS) { 1994 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) { 1995 prop->sc_value_type = prop_type; 1996 1997 /* 1998 * Found a type, update the value types and validate 1999 * the actual value against this type. 2000 */ 2001 for (vp = uu_list_first(prop->sc_property_values); 2002 vp != NULL; 2003 vp = uu_list_next(prop->sc_property_values, vp)) { 2004 vp->sc_type = prop->sc_value_type; 2005 lxml_store_value(vp, 0, NULL); 2006 } 2007 2008 r = UU_WALK_NEXT; 2009 goto out; 2010 } 2011 } else { 2012 if (t_pg == NULL && sc_pg) { 2013 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 2014 warn(gettext("Unable to create template " 2015 "property group to find a property " 2016 "type.\n")); 2017 2018 goto out; 2019 } 2020 2021 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) { 2022 scf_tmpl_pg_destroy(t_pg); 2023 t_pg = NULL; 2024 } else { 2025 goto do_tmpl; 2026 } 2027 } 2028 } 2029 2030 if (issvc == 0) { 2031 scf_instance_t *i; 2032 scf_service_t *s; 2033 2034 issvc = 1; 2035 if (lcb->sc_flags == 1) { 2036 entity_t *e = pg->sc_parent->sc_parent; 2037 2038 fmri = e->sc_fmri; 2039 goto retry_pg; 2040 } 2041 2042 /* 2043 * because lcb->sc_flags was not set then this means 2044 * the pg was not used and can be used here. 2045 */ 2046 if ((pg = internal_pgroup_new()) == NULL) { 2047 warn(gettext("Could not create internal property group " 2048 "to find a missing type.")); 2049 2050 goto out; 2051 } 2052 2053 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1); 2054 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name, 2055 max_scf_name_len + 1) < 0) 2056 goto out; 2057 2058 i = scf_instance_create(g_hndl); 2059 s = scf_service_create(g_hndl); 2060 if (i == NULL || s == NULL || 2061 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) { 2062 warn(gettext("Could not get a service for the instance " 2063 "to find a missing type.")); 2064 2065 goto out; 2066 } 2067 2068 /* 2069 * Check to see truly at the instance level. 2070 */ 2071 lfmri = safe_malloc(max_scf_fmri_len + 1); 2072 if (scf_instance_get_parent(i, s) == SCF_SUCCESS && 2073 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0) 2074 goto out; 2075 else 2076 fmri = (const char *)lfmri; 2077 2078 goto retry_pg; 2079 } 2080 2081 out : 2082 if (sc_pg != lcb->sc_parent) { 2083 scf_pg_destroy(sc_pg); 2084 } 2085 2086 /* 2087 * If this is true then the pg was allocated 2088 * here, and the name was set so need to free 2089 * the name and the pg. 2090 */ 2091 if (pg != NULL && pg != lcb->sc_parent) { 2092 free((char *)pg->sc_pgroup_name); 2093 internal_pgroup_free(pg); 2094 } 2095 2096 if (cur_selection) { 2097 lscf_select(cur_selection); 2098 free(cur_selection); 2099 } 2100 2101 scf_tmpl_pg_destroy(t_pg); 2102 scf_tmpl_prop_destroy(t_prop); 2103 scf_property_destroy(sc_prop); 2104 2105 if (r != UU_WALK_NEXT) 2106 warn(gettext("Could not find property type for \"%s\" " 2107 "from \"%s\"\n"), prop->sc_property_name, 2108 fmri != NULL ? fmri : lcb->sc_source_fmri); 2109 2110 free(lfmri); 2111 2112 return (r); 2113 } 2114 2115 /* 2116 * Take a property group that does not have a type and check to see if a type 2117 * exists or can be gleened from the current data. Set the type. 2118 * 2119 * Check the current level (instance) and then check the higher level 2120 * (service). This could be the case for adding a new property to 2121 * the instance that's going to "override" a service level property. 2122 * 2123 * For a property group 2124 * 1. Take the type from an existing property group 2125 * 2. Take the type from a template entry 2126 * 2127 * If the type can not be found, then leave the type as is, and let the import 2128 * report the problem of the missing type. 2129 */ 2130 static int 2131 find_current_pg_type(void *p, void *sori) 2132 { 2133 entity_t *si = sori; 2134 pgroup_t *pg = p; 2135 2136 const char *ofmri, *fmri; 2137 char *cur_selection = NULL; 2138 char *pg_type = NULL; 2139 2140 scf_propertygroup_t *sc_pg = NULL; 2141 scf_pg_tmpl_t *t_pg = NULL; 2142 2143 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2144 int r = UU_WALK_ERROR; 2145 2146 ofmri = fmri = si->sc_fmri; 2147 if (pg->sc_pgroup_type != NULL) { 2148 r = UU_WALK_NEXT; 2149 2150 goto out; 2151 } 2152 2153 sc_pg = scf_pg_create(g_hndl); 2154 if (sc_pg == NULL) { 2155 warn(gettext("Unable to create property group to attempt " 2156 "and find a missing type.\n")); 2157 2158 return (UU_WALK_ERROR); 2159 } 2160 2161 /* 2162 * Using get_pg() requires that the cur_svc/cur_inst be 2163 * via lscf_select. Need to preserve the current selection 2164 * if going to use lscf_select() to set up the cur_svc/cur_inst 2165 */ 2166 if (cur_svc) { 2167 cur_selection = safe_malloc(max_scf_fmri_len + 1); 2168 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1); 2169 } 2170 2171 /* 2172 * If the property group exists get the type, and set 2173 * the pgroup_t type of that type. 2174 * 2175 * If not the check for a template pg_pattern entry 2176 * and take the type from that. 2177 */ 2178 retry_svc: 2179 lscf_select(fmri); 2180 2181 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) { 2182 pg_type = safe_malloc(max_scf_pg_type_len + 1); 2183 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type, 2184 max_scf_pg_type_len + 1) != -1) { 2185 pg->sc_pgroup_type = pg_type; 2186 2187 r = UU_WALK_NEXT; 2188 goto out; 2189 } else { 2190 free(pg_type); 2191 } 2192 } else { 2193 if ((t_pg == NULL) && 2194 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) 2195 goto out; 2196 2197 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name, 2198 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS && 2199 scf_tmpl_pg_type(t_pg, &pg_type) != -1) { 2200 pg->sc_pgroup_type = pg_type; 2201 2202 r = UU_WALK_NEXT; 2203 goto out; 2204 } 2205 } 2206 2207 /* 2208 * If type is not found at the instance level then attempt to 2209 * find the type at the service level. 2210 */ 2211 if (!issvc) { 2212 si = si->sc_parent; 2213 fmri = si->sc_fmri; 2214 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2215 goto retry_svc; 2216 } 2217 2218 out : 2219 if (cur_selection) { 2220 lscf_select(cur_selection); 2221 free(cur_selection); 2222 } 2223 2224 /* 2225 * Now walk the properties of the property group to make sure that 2226 * all properties have the correct type and values are valid for 2227 * those types. 2228 */ 2229 if (r == UU_WALK_NEXT) { 2230 scf_callback_t cb; 2231 2232 cb.sc_service = issvc; 2233 cb.sc_source_fmri = ofmri; 2234 if (sc_pg != NULL) { 2235 cb.sc_parent = sc_pg; 2236 cb.sc_flags = 0; 2237 } else { 2238 cb.sc_parent = pg; 2239 cb.sc_flags = 1; 2240 } 2241 2242 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type, 2243 &cb, UU_DEFAULT) != 0) { 2244 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2245 bad_error("uu_list_walk", uu_error()); 2246 2247 r = UU_WALK_ERROR; 2248 } 2249 } else { 2250 warn(gettext("Could not find property group type for " 2251 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri); 2252 } 2253 2254 scf_tmpl_pg_destroy(t_pg); 2255 scf_pg_destroy(sc_pg); 2256 2257 return (r); 2258 } 2259 2260 /* 2261 * Import. These functions import a bundle into the repository. 2262 */ 2263 2264 /* 2265 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 2266 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 2267 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2268 * lcbdata->sc_err to 2269 * ENOMEM - out of memory 2270 * ECONNABORTED - repository connection broken 2271 * ECANCELED - sc_trans's property group was deleted 2272 * EINVAL - p's name is invalid (error printed) 2273 * - p has an invalid value (error printed) 2274 */ 2275 static int 2276 lscf_property_import(void *v, void *pvt) 2277 { 2278 property_t *p = v; 2279 scf_callback_t *lcbdata = pvt; 2280 value_t *vp; 2281 scf_transaction_t *trans = lcbdata->sc_trans; 2282 scf_transaction_entry_t *entr; 2283 scf_value_t *val; 2284 scf_type_t tp; 2285 2286 if ((lcbdata->sc_flags & SCI_NOENABLED || 2287 lcbdata->sc_flags & SCI_DELAYENABLE) && 2288 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 2289 lcbdata->sc_enable = p; 2290 return (UU_WALK_NEXT); 2291 } 2292 2293 entr = scf_entry_create(lcbdata->sc_handle); 2294 if (entr == NULL) { 2295 switch (scf_error()) { 2296 case SCF_ERROR_NO_MEMORY: 2297 return (stash_scferror(lcbdata)); 2298 2299 case SCF_ERROR_INVALID_ARGUMENT: 2300 default: 2301 bad_error("scf_entry_create", scf_error()); 2302 } 2303 } 2304 2305 tp = p->sc_value_type; 2306 2307 if (scf_transaction_property_new(trans, entr, 2308 p->sc_property_name, tp) != 0) { 2309 switch (scf_error()) { 2310 case SCF_ERROR_INVALID_ARGUMENT: 2311 semerr(emsg_invalid_prop_name, p->sc_property_name); 2312 scf_entry_destroy(entr); 2313 return (stash_scferror(lcbdata)); 2314 2315 case SCF_ERROR_EXISTS: 2316 break; 2317 2318 case SCF_ERROR_DELETED: 2319 case SCF_ERROR_CONNECTION_BROKEN: 2320 scf_entry_destroy(entr); 2321 return (stash_scferror(lcbdata)); 2322 2323 case SCF_ERROR_NOT_BOUND: 2324 case SCF_ERROR_HANDLE_MISMATCH: 2325 case SCF_ERROR_NOT_SET: 2326 default: 2327 bad_error("scf_transaction_property_new", scf_error()); 2328 } 2329 2330 if (scf_transaction_property_change_type(trans, entr, 2331 p->sc_property_name, tp) != 0) { 2332 switch (scf_error()) { 2333 case SCF_ERROR_DELETED: 2334 case SCF_ERROR_CONNECTION_BROKEN: 2335 scf_entry_destroy(entr); 2336 return (stash_scferror(lcbdata)); 2337 2338 case SCF_ERROR_INVALID_ARGUMENT: 2339 semerr(emsg_invalid_prop_name, 2340 p->sc_property_name); 2341 scf_entry_destroy(entr); 2342 return (stash_scferror(lcbdata)); 2343 2344 case SCF_ERROR_NOT_FOUND: 2345 case SCF_ERROR_NOT_SET: 2346 case SCF_ERROR_HANDLE_MISMATCH: 2347 case SCF_ERROR_NOT_BOUND: 2348 default: 2349 bad_error( 2350 "scf_transaction_property_change_type", 2351 scf_error()); 2352 } 2353 } 2354 } 2355 2356 for (vp = uu_list_first(p->sc_property_values); 2357 vp != NULL; 2358 vp = uu_list_next(p->sc_property_values, vp)) { 2359 val = scf_value_create(g_hndl); 2360 if (val == NULL) { 2361 switch (scf_error()) { 2362 case SCF_ERROR_NO_MEMORY: 2363 return (stash_scferror(lcbdata)); 2364 2365 case SCF_ERROR_INVALID_ARGUMENT: 2366 default: 2367 bad_error("scf_value_create", scf_error()); 2368 } 2369 } 2370 2371 switch (tp) { 2372 case SCF_TYPE_BOOLEAN: 2373 scf_value_set_boolean(val, vp->sc_u.sc_count); 2374 break; 2375 case SCF_TYPE_COUNT: 2376 scf_value_set_count(val, vp->sc_u.sc_count); 2377 break; 2378 case SCF_TYPE_INTEGER: 2379 scf_value_set_integer(val, vp->sc_u.sc_integer); 2380 break; 2381 default: 2382 assert(vp->sc_u.sc_string != NULL); 2383 if (scf_value_set_from_string(val, tp, 2384 vp->sc_u.sc_string) != 0) { 2385 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 2386 bad_error("scf_value_set_from_string", 2387 scf_error()); 2388 2389 warn(gettext("Value \"%s\" is not a valid " 2390 "%s.\n"), vp->sc_u.sc_string, 2391 scf_type_to_string(tp)); 2392 scf_value_destroy(val); 2393 return (stash_scferror(lcbdata)); 2394 } 2395 break; 2396 } 2397 2398 if (scf_entry_add_value(entr, val) != 0) 2399 bad_error("scf_entry_add_value", scf_error()); 2400 } 2401 2402 return (UU_WALK_NEXT); 2403 } 2404 2405 /* 2406 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 2407 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 2408 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 2409 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2410 * lcbdata->sc_err to 2411 * ECONNABORTED - repository connection broken 2412 * ENOMEM - out of memory 2413 * ENOSPC - svc.configd is out of resources 2414 * ECANCELED - sc_parent was deleted 2415 * EPERM - could not create property group (permission denied) (error printed) 2416 * - could not modify property group (permission denied) (error printed) 2417 * - could not delete property group (permission denied) (error printed) 2418 * EROFS - could not create property group (repository is read-only) 2419 * - could not delete property group (repository is read-only) 2420 * EACCES - could not create property group (backend access denied) 2421 * - could not delete property group (backend access denied) 2422 * EEXIST - could not create property group (already exists) 2423 * EINVAL - invalid property group name (error printed) 2424 * - invalid property name (error printed) 2425 * - invalid value (error printed) 2426 * EBUSY - new property group deleted (error printed) 2427 * - new property group changed (error printed) 2428 * - property group added (error printed) 2429 * - property group deleted (error printed) 2430 */ 2431 static int 2432 entity_pgroup_import(void *v, void *pvt) 2433 { 2434 pgroup_t *p = v; 2435 scf_callback_t cbdata; 2436 scf_callback_t *lcbdata = pvt; 2437 void *ent = lcbdata->sc_parent; 2438 int issvc = lcbdata->sc_service; 2439 int r; 2440 2441 const char * const pg_changed = gettext("%s changed unexpectedly " 2442 "(new property group \"%s\" changed).\n"); 2443 2444 /* Never import deleted property groups. */ 2445 if (p->sc_pgroup_delete) { 2446 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY && 2447 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) { 2448 goto delete_pg; 2449 } 2450 return (UU_WALK_NEXT); 2451 } 2452 2453 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 2454 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 2455 lcbdata->sc_general = p; 2456 return (UU_WALK_NEXT); 2457 } 2458 2459 add_pg: 2460 if (issvc) 2461 r = scf_service_add_pg(ent, p->sc_pgroup_name, 2462 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2463 else 2464 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 2465 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2466 if (r != 0) { 2467 switch (scf_error()) { 2468 case SCF_ERROR_DELETED: 2469 case SCF_ERROR_CONNECTION_BROKEN: 2470 case SCF_ERROR_BACKEND_READONLY: 2471 case SCF_ERROR_BACKEND_ACCESS: 2472 case SCF_ERROR_NO_RESOURCES: 2473 return (stash_scferror(lcbdata)); 2474 2475 case SCF_ERROR_EXISTS: 2476 if (lcbdata->sc_flags & SCI_FORCE) 2477 break; 2478 return (stash_scferror(lcbdata)); 2479 2480 case SCF_ERROR_INVALID_ARGUMENT: 2481 warn(emsg_fmri_invalid_pg_name_type, 2482 lcbdata->sc_source_fmri, 2483 p->sc_pgroup_name, p->sc_pgroup_type); 2484 return (stash_scferror(lcbdata)); 2485 2486 case SCF_ERROR_PERMISSION_DENIED: 2487 warn(emsg_pg_add_perm, p->sc_pgroup_name, 2488 lcbdata->sc_target_fmri); 2489 return (stash_scferror(lcbdata)); 2490 2491 case SCF_ERROR_NOT_BOUND: 2492 case SCF_ERROR_HANDLE_MISMATCH: 2493 case SCF_ERROR_NOT_SET: 2494 default: 2495 bad_error("scf_service_add_pg", scf_error()); 2496 } 2497 2498 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2499 switch (scf_error()) { 2500 case SCF_ERROR_CONNECTION_BROKEN: 2501 case SCF_ERROR_DELETED: 2502 return (stash_scferror(lcbdata)); 2503 2504 case SCF_ERROR_INVALID_ARGUMENT: 2505 warn(emsg_fmri_invalid_pg_name, 2506 lcbdata->sc_source_fmri, 2507 p->sc_pgroup_name); 2508 return (stash_scferror(lcbdata)); 2509 2510 case SCF_ERROR_NOT_FOUND: 2511 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2512 p->sc_pgroup_name); 2513 lcbdata->sc_err = EBUSY; 2514 return (UU_WALK_ERROR); 2515 2516 case SCF_ERROR_NOT_BOUND: 2517 case SCF_ERROR_HANDLE_MISMATCH: 2518 case SCF_ERROR_NOT_SET: 2519 default: 2520 bad_error("entity_get_pg", scf_error()); 2521 } 2522 } 2523 2524 if (lcbdata->sc_flags & SCI_KEEP) 2525 goto props; 2526 2527 delete_pg: 2528 if (scf_pg_delete(imp_pg) != 0) { 2529 switch (scf_error()) { 2530 case SCF_ERROR_DELETED: 2531 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2532 p->sc_pgroup_name); 2533 lcbdata->sc_err = EBUSY; 2534 return (UU_WALK_ERROR); 2535 2536 case SCF_ERROR_PERMISSION_DENIED: 2537 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2538 lcbdata->sc_target_fmri); 2539 return (stash_scferror(lcbdata)); 2540 2541 case SCF_ERROR_BACKEND_READONLY: 2542 case SCF_ERROR_BACKEND_ACCESS: 2543 case SCF_ERROR_CONNECTION_BROKEN: 2544 return (stash_scferror(lcbdata)); 2545 2546 case SCF_ERROR_NOT_SET: 2547 default: 2548 bad_error("scf_pg_delete", scf_error()); 2549 } 2550 } 2551 2552 if (p->sc_pgroup_delete) 2553 return (UU_WALK_NEXT); 2554 2555 goto add_pg; 2556 } 2557 2558 props: 2559 2560 /* 2561 * Add properties to property group, if any. 2562 */ 2563 cbdata.sc_handle = lcbdata->sc_handle; 2564 cbdata.sc_parent = imp_pg; 2565 cbdata.sc_flags = lcbdata->sc_flags; 2566 cbdata.sc_trans = imp_tx; 2567 cbdata.sc_enable = NULL; 2568 2569 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2570 switch (scf_error()) { 2571 case SCF_ERROR_BACKEND_ACCESS: 2572 case SCF_ERROR_BACKEND_READONLY: 2573 case SCF_ERROR_CONNECTION_BROKEN: 2574 return (stash_scferror(lcbdata)); 2575 2576 case SCF_ERROR_DELETED: 2577 warn(pg_changed, lcbdata->sc_target_fmri, 2578 p->sc_pgroup_name); 2579 lcbdata->sc_err = EBUSY; 2580 return (UU_WALK_ERROR); 2581 2582 case SCF_ERROR_PERMISSION_DENIED: 2583 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2584 lcbdata->sc_target_fmri); 2585 return (stash_scferror(lcbdata)); 2586 2587 case SCF_ERROR_NOT_BOUND: 2588 case SCF_ERROR_NOT_SET: 2589 case SCF_ERROR_IN_USE: 2590 case SCF_ERROR_HANDLE_MISMATCH: 2591 default: 2592 bad_error("scf_transaction_start", scf_error()); 2593 } 2594 } 2595 2596 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2597 UU_DEFAULT) != 0) { 2598 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2599 bad_error("uu_list_walk", uu_error()); 2600 scf_transaction_reset(imp_tx); 2601 2602 lcbdata->sc_err = cbdata.sc_err; 2603 if (cbdata.sc_err == ECANCELED) { 2604 warn(pg_changed, lcbdata->sc_target_fmri, 2605 p->sc_pgroup_name); 2606 lcbdata->sc_err = EBUSY; 2607 } 2608 return (UU_WALK_ERROR); 2609 } 2610 2611 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2612 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2613 2614 /* 2615 * take the snapshot running snapshot then 2616 * import the stored general/enable property 2617 */ 2618 r = take_snap(ent, snap_running, imp_rsnap); 2619 switch (r) { 2620 case 0: 2621 break; 2622 2623 case ECONNABORTED: 2624 warn(gettext("Could not take %s snapshot on import " 2625 "(repository connection broken).\n"), 2626 snap_running); 2627 lcbdata->sc_err = r; 2628 return (UU_WALK_ERROR); 2629 case ECANCELED: 2630 warn(emsg_deleted); 2631 lcbdata->sc_err = r; 2632 return (UU_WALK_ERROR); 2633 2634 case EPERM: 2635 warn(gettext("Could not take %s snapshot " 2636 "(permission denied).\n"), snap_running); 2637 lcbdata->sc_err = r; 2638 return (UU_WALK_ERROR); 2639 2640 case ENOSPC: 2641 warn(gettext("Could not take %s snapshot" 2642 "(repository server out of resources).\n"), 2643 snap_running); 2644 lcbdata->sc_err = r; 2645 return (UU_WALK_ERROR); 2646 2647 default: 2648 bad_error("take_snap", r); 2649 } 2650 2651 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2652 if (r != UU_WALK_NEXT) { 2653 if (r != UU_WALK_ERROR) 2654 bad_error("lscf_property_import", r); 2655 return (EINVAL); 2656 } 2657 } 2658 2659 r = scf_transaction_commit(imp_tx); 2660 switch (r) { 2661 case 1: 2662 r = UU_WALK_NEXT; 2663 break; 2664 2665 case 0: 2666 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2667 lcbdata->sc_err = EBUSY; 2668 r = UU_WALK_ERROR; 2669 break; 2670 2671 case -1: 2672 switch (scf_error()) { 2673 case SCF_ERROR_BACKEND_READONLY: 2674 case SCF_ERROR_BACKEND_ACCESS: 2675 case SCF_ERROR_CONNECTION_BROKEN: 2676 case SCF_ERROR_NO_RESOURCES: 2677 r = stash_scferror(lcbdata); 2678 break; 2679 2680 case SCF_ERROR_DELETED: 2681 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2682 p->sc_pgroup_name); 2683 lcbdata->sc_err = EBUSY; 2684 r = UU_WALK_ERROR; 2685 break; 2686 2687 case SCF_ERROR_PERMISSION_DENIED: 2688 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2689 lcbdata->sc_target_fmri); 2690 r = stash_scferror(lcbdata); 2691 break; 2692 2693 case SCF_ERROR_NOT_SET: 2694 case SCF_ERROR_INVALID_ARGUMENT: 2695 case SCF_ERROR_NOT_BOUND: 2696 default: 2697 bad_error("scf_transaction_commit", scf_error()); 2698 } 2699 break; 2700 2701 default: 2702 bad_error("scf_transaction_commit", r); 2703 } 2704 2705 scf_transaction_destroy_children(imp_tx); 2706 2707 return (r); 2708 } 2709 2710 /* 2711 * Returns 2712 * 0 - success 2713 * ECONNABORTED - repository connection broken 2714 * ENOMEM - out of memory 2715 * ENOSPC - svc.configd is out of resources 2716 * ECANCELED - inst was deleted 2717 * EPERM - could not create property group (permission denied) (error printed) 2718 * - could not modify property group (permission denied) (error printed) 2719 * EROFS - could not create property group (repository is read-only) 2720 * EACCES - could not create property group (backend access denied) 2721 * EEXIST - could not create property group (already exists) 2722 * EINVAL - invalid property group name (error printed) 2723 * - invalid property name (error printed) 2724 * - invalid value (error printed) 2725 * EBUSY - new property group changed (error printed) 2726 */ 2727 static int 2728 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2729 const entity_t *isvc, int flags) 2730 { 2731 scf_callback_t cbdata; 2732 2733 cbdata.sc_handle = scf_service_handle(svc); 2734 cbdata.sc_parent = svc; 2735 cbdata.sc_service = 1; 2736 cbdata.sc_general = 0; 2737 cbdata.sc_enable = 0; 2738 cbdata.sc_flags = flags; 2739 cbdata.sc_source_fmri = isvc->sc_fmri; 2740 cbdata.sc_target_fmri = target_fmri; 2741 2742 /* 2743 * If the op is set, then add the flag to the callback 2744 * flags for later use. 2745 */ 2746 if (isvc->sc_op != SVCCFG_OP_NONE) { 2747 switch (isvc->sc_op) { 2748 case SVCCFG_OP_IMPORT : 2749 cbdata.sc_flags |= SCI_OP_IMPORT; 2750 break; 2751 case SVCCFG_OP_APPLY : 2752 cbdata.sc_flags |= SCI_OP_APPLY; 2753 break; 2754 case SVCCFG_OP_RESTORE : 2755 cbdata.sc_flags |= SCI_OP_RESTORE; 2756 break; 2757 default : 2758 uu_die(gettext("lscf_import_service_pgs : " 2759 "Unknown op stored in the service entity\n")); 2760 2761 } 2762 } 2763 2764 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2765 UU_DEFAULT) != 0) { 2766 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2767 bad_error("uu_list_walk", uu_error()); 2768 2769 return (cbdata.sc_err); 2770 } 2771 2772 return (0); 2773 } 2774 2775 /* 2776 * Returns 2777 * 0 - success 2778 * ECONNABORTED - repository connection broken 2779 * ENOMEM - out of memory 2780 * ENOSPC - svc.configd is out of resources 2781 * ECANCELED - inst was deleted 2782 * EPERM - could not create property group (permission denied) (error printed) 2783 * - could not modify property group (permission denied) (error printed) 2784 * EROFS - could not create property group (repository is read-only) 2785 * EACCES - could not create property group (backend access denied) 2786 * EEXIST - could not create property group (already exists) 2787 * EINVAL - invalid property group name (error printed) 2788 * - invalid property name (error printed) 2789 * - invalid value (error printed) 2790 * EBUSY - new property group changed (error printed) 2791 */ 2792 static int 2793 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2794 const entity_t *iinst, int flags) 2795 { 2796 scf_callback_t cbdata; 2797 2798 cbdata.sc_handle = scf_instance_handle(inst); 2799 cbdata.sc_parent = inst; 2800 cbdata.sc_service = 0; 2801 cbdata.sc_general = NULL; 2802 cbdata.sc_enable = NULL; 2803 cbdata.sc_flags = flags; 2804 cbdata.sc_source_fmri = iinst->sc_fmri; 2805 cbdata.sc_target_fmri = target_fmri; 2806 2807 /* 2808 * If the op is set, then add the flag to the callback 2809 * flags for later use. 2810 */ 2811 if (iinst->sc_op != SVCCFG_OP_NONE) { 2812 switch (iinst->sc_op) { 2813 case SVCCFG_OP_IMPORT : 2814 cbdata.sc_flags |= SCI_OP_IMPORT; 2815 break; 2816 case SVCCFG_OP_APPLY : 2817 cbdata.sc_flags |= SCI_OP_APPLY; 2818 break; 2819 case SVCCFG_OP_RESTORE : 2820 cbdata.sc_flags |= SCI_OP_RESTORE; 2821 break; 2822 default : 2823 uu_die(gettext("lscf_import_instance_pgs : " 2824 "Unknown op stored in the instance entity\n")); 2825 } 2826 } 2827 2828 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2829 UU_DEFAULT) != 0) { 2830 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2831 bad_error("uu_list_walk", uu_error()); 2832 2833 return (cbdata.sc_err); 2834 } 2835 2836 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2837 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2838 /* 2839 * If importing with the SCI_NOENABLED flag then 2840 * skip the delay, but if not then add the delay 2841 * of the enable property. 2842 */ 2843 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2844 cbdata.sc_flags |= SCI_DELAYENABLE; 2845 } 2846 2847 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2848 != UU_WALK_NEXT) 2849 return (cbdata.sc_err); 2850 } 2851 2852 return (0); 2853 } 2854 2855 /* 2856 * Report the reasons why we can't upgrade pg2 to pg1. 2857 */ 2858 static void 2859 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2860 int new) 2861 { 2862 property_t *p1, *p2; 2863 2864 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2865 2866 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2867 return; 2868 2869 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2870 p1 != NULL; 2871 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2872 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2873 if (p2 != NULL) { 2874 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2875 new); 2876 continue; 2877 } 2878 2879 if (new) 2880 warn(gettext("Conflict upgrading %s (new property " 2881 "group \"%s\" is missing property \"%s\").\n"), 2882 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2883 else 2884 warn(gettext("Conflict upgrading %s (property " 2885 "\"%s/%s\" is missing).\n"), fmri, 2886 pg1->sc_pgroup_name, p1->sc_property_name); 2887 } 2888 2889 /* 2890 * Since pg1 should be from the manifest, any properties in pg2 which 2891 * aren't in pg1 shouldn't be reported as conflicts. 2892 */ 2893 } 2894 2895 /* 2896 * Add transaction entries to tx which will upgrade cur's pg according to old 2897 * & new. 2898 * 2899 * Returns 2900 * 0 - success 2901 * EINVAL - new has a property with an invalid name or value (message emitted) 2902 * ENOMEM - out of memory 2903 */ 2904 static int 2905 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2906 pgroup_t *cur, int speak, const char *fmri) 2907 { 2908 property_t *p, *new_p, *cur_p; 2909 scf_transaction_entry_t *e; 2910 int r; 2911 int is_general; 2912 int is_protected; 2913 2914 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2915 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2916 bad_error("uu_list_walk", uu_error()); 2917 2918 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2919 2920 for (p = uu_list_first(old->sc_pgroup_props); 2921 p != NULL; 2922 p = uu_list_next(old->sc_pgroup_props, p)) { 2923 /* p is a property in the old property group. */ 2924 2925 /* Protect live properties. */ 2926 is_protected = 0; 2927 if (is_general) { 2928 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2929 0 || 2930 strcmp(p->sc_property_name, 2931 SCF_PROPERTY_RESTARTER) == 0) 2932 is_protected = 1; 2933 } 2934 2935 /* Look for the same property in the new properties. */ 2936 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2937 if (new_p != NULL) { 2938 new_p->sc_seen = 1; 2939 2940 /* 2941 * If the new property is the same as the old, don't do 2942 * anything (leave any user customizations). 2943 */ 2944 if (prop_equal(p, new_p, NULL, NULL, 0)) 2945 continue; 2946 2947 if (new_p->sc_property_override) 2948 goto upgrade; 2949 } 2950 2951 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2952 if (cur_p == NULL) { 2953 /* 2954 * p has been deleted from the repository. If we were 2955 * going to delete it anyway, do nothing. Otherwise 2956 * report a conflict. 2957 */ 2958 if (new_p == NULL) 2959 continue; 2960 2961 if (is_protected) 2962 continue; 2963 2964 warn(gettext("Conflict upgrading %s " 2965 "(property \"%s/%s\" is missing).\n"), fmri, 2966 old->sc_pgroup_name, p->sc_property_name); 2967 continue; 2968 } 2969 2970 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2971 /* 2972 * Conflict. Don't warn if the property is already the 2973 * way we want it, though. 2974 */ 2975 if (is_protected) 2976 continue; 2977 2978 if (new_p == NULL) 2979 (void) prop_equal(p, cur_p, fmri, 2980 old->sc_pgroup_name, 0); 2981 else 2982 (void) prop_equal(cur_p, new_p, fmri, 2983 old->sc_pgroup_name, 0); 2984 continue; 2985 } 2986 2987 if (is_protected) { 2988 if (speak) 2989 warn(gettext("%s: Refusing to upgrade " 2990 "\"%s/%s\" (live property).\n"), fmri, 2991 old->sc_pgroup_name, p->sc_property_name); 2992 continue; 2993 } 2994 2995 upgrade: 2996 /* p hasn't been customized in the repository. Upgrade it. */ 2997 if (new_p == NULL) { 2998 /* p was deleted. Delete from cur if unchanged. */ 2999 if (speak) 3000 warn(gettext( 3001 "%s: Deleting property \"%s/%s\".\n"), 3002 fmri, old->sc_pgroup_name, 3003 p->sc_property_name); 3004 3005 e = scf_entry_create(g_hndl); 3006 if (e == NULL) 3007 return (ENOMEM); 3008 3009 if (scf_transaction_property_delete(tx, e, 3010 p->sc_property_name) != 0) { 3011 switch (scf_error()) { 3012 case SCF_ERROR_DELETED: 3013 scf_entry_destroy(e); 3014 return (ECANCELED); 3015 3016 case SCF_ERROR_CONNECTION_BROKEN: 3017 scf_entry_destroy(e); 3018 return (ECONNABORTED); 3019 3020 case SCF_ERROR_NOT_FOUND: 3021 /* 3022 * This can happen if cur is from the 3023 * running snapshot (and it differs 3024 * from the live properties). 3025 */ 3026 scf_entry_destroy(e); 3027 break; 3028 3029 case SCF_ERROR_HANDLE_MISMATCH: 3030 case SCF_ERROR_NOT_BOUND: 3031 case SCF_ERROR_NOT_SET: 3032 case SCF_ERROR_INVALID_ARGUMENT: 3033 default: 3034 bad_error( 3035 "scf_transaction_property_delete", 3036 scf_error()); 3037 } 3038 } 3039 } else { 3040 scf_callback_t ctx; 3041 3042 if (speak) 3043 warn(gettext( 3044 "%s: Upgrading property \"%s/%s\".\n"), 3045 fmri, old->sc_pgroup_name, 3046 p->sc_property_name); 3047 3048 ctx.sc_handle = g_hndl; 3049 ctx.sc_trans = tx; 3050 ctx.sc_flags = 0; 3051 3052 r = lscf_property_import(new_p, &ctx); 3053 if (r != UU_WALK_NEXT) { 3054 if (r != UU_WALK_ERROR) 3055 bad_error("lscf_property_import", r); 3056 return (EINVAL); 3057 } 3058 } 3059 } 3060 3061 /* Go over the properties which were added. */ 3062 for (new_p = uu_list_first(new->sc_pgroup_props); 3063 new_p != NULL; 3064 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 3065 if (new_p->sc_seen) 3066 continue; 3067 3068 /* This is a new property. */ 3069 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 3070 if (cur_p == NULL) { 3071 scf_callback_t ctx; 3072 3073 ctx.sc_handle = g_hndl; 3074 ctx.sc_trans = tx; 3075 ctx.sc_flags = 0; 3076 3077 r = lscf_property_import(new_p, &ctx); 3078 if (r != UU_WALK_NEXT) { 3079 if (r != UU_WALK_ERROR) 3080 bad_error("lscf_property_import", r); 3081 return (EINVAL); 3082 } 3083 continue; 3084 } 3085 3086 /* 3087 * Report a conflict if the new property differs from the 3088 * current one. Unless it's general/enabled, since that's 3089 * never in the last-import snapshot. 3090 */ 3091 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 3092 0 && 3093 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 3094 continue; 3095 3096 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 3097 } 3098 3099 return (0); 3100 } 3101 3102 /* 3103 * Upgrade pg according to old & new. 3104 * 3105 * Returns 3106 * 0 - success 3107 * ECONNABORTED - repository connection broken 3108 * ENOMEM - out of memory 3109 * ENOSPC - svc.configd is out of resources 3110 * ECANCELED - pg was deleted 3111 * EPERM - couldn't modify pg (permission denied) 3112 * EROFS - couldn't modify pg (backend read-only) 3113 * EACCES - couldn't modify pg (backend access denied) 3114 * EINVAL - new has a property with invalid name or value (error printed) 3115 * EBUSY - pg changed unexpectedly 3116 */ 3117 static int 3118 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 3119 pgroup_t *new, int speak, const char *fmri) 3120 { 3121 int r; 3122 3123 if (scf_transaction_start(imp_tx, pg) != 0) { 3124 switch (scf_error()) { 3125 case SCF_ERROR_CONNECTION_BROKEN: 3126 case SCF_ERROR_DELETED: 3127 case SCF_ERROR_PERMISSION_DENIED: 3128 case SCF_ERROR_BACKEND_READONLY: 3129 case SCF_ERROR_BACKEND_ACCESS: 3130 return (scferror2errno(scf_error())); 3131 3132 case SCF_ERROR_HANDLE_MISMATCH: 3133 case SCF_ERROR_IN_USE: 3134 case SCF_ERROR_NOT_BOUND: 3135 case SCF_ERROR_NOT_SET: 3136 default: 3137 bad_error("scf_transaction_start", scf_error()); 3138 } 3139 } 3140 3141 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 3142 switch (r) { 3143 case 0: 3144 break; 3145 3146 case EINVAL: 3147 case ENOMEM: 3148 scf_transaction_destroy_children(imp_tx); 3149 return (r); 3150 3151 default: 3152 bad_error("add_upgrade_entries", r); 3153 } 3154 3155 r = scf_transaction_commit(imp_tx); 3156 3157 scf_transaction_destroy_children(imp_tx); 3158 3159 switch (r) { 3160 case 1: 3161 break; 3162 3163 case 0: 3164 return (EBUSY); 3165 3166 case -1: 3167 switch (scf_error()) { 3168 case SCF_ERROR_CONNECTION_BROKEN: 3169 case SCF_ERROR_NO_RESOURCES: 3170 case SCF_ERROR_PERMISSION_DENIED: 3171 case SCF_ERROR_BACKEND_READONLY: 3172 case SCF_ERROR_BACKEND_ACCESS: 3173 case SCF_ERROR_DELETED: 3174 return (scferror2errno(scf_error())); 3175 3176 case SCF_ERROR_NOT_BOUND: 3177 case SCF_ERROR_INVALID_ARGUMENT: 3178 case SCF_ERROR_NOT_SET: 3179 default: 3180 bad_error("scf_transaction_commit", scf_error()); 3181 } 3182 3183 default: 3184 bad_error("scf_transaction_commit", r); 3185 } 3186 3187 return (0); 3188 } 3189 3190 /* 3191 * Compares two entity FMRIs. Returns 3192 * 3193 * 1 - equal 3194 * 0 - not equal 3195 * -1 - f1 is invalid or not an entity 3196 * -2 - f2 is invalid or not an entity 3197 */ 3198 static int 3199 fmri_equal(const char *f1, const char *f2) 3200 { 3201 int r; 3202 const char *s1, *i1, *pg1; 3203 const char *s2, *i2, *pg2; 3204 3205 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3206 return (-1); 3207 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 3208 return (-1); 3209 3210 if (s1 == NULL || pg1 != NULL) 3211 return (-1); 3212 3213 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3214 return (-2); 3215 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 3216 return (-2); 3217 3218 if (s2 == NULL || pg2 != NULL) 3219 return (-2); 3220 3221 r = strcmp(s1, s2); 3222 if (r != 0) 3223 return (0); 3224 3225 if (i1 == NULL && i2 == NULL) 3226 return (1); 3227 3228 if (i1 == NULL || i2 == NULL) 3229 return (0); 3230 3231 return (strcmp(i1, i2) == 0); 3232 } 3233 3234 /* 3235 * Import a dependent by creating a dependency property group in the dependent 3236 * entity. If lcbdata->sc_trans is set, assume it's been started on the 3237 * dependents pg, and add an entry to create a new property for this 3238 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 3239 * 3240 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 3241 * lcbdata->sc_err to 3242 * ECONNABORTED - repository connection broken 3243 * ENOMEM - out of memory 3244 * ENOSPC - configd is out of resources 3245 * EINVAL - target is invalid (error printed) 3246 * - target is not an entity (error printed) 3247 * - dependent has invalid name (error printed) 3248 * - invalid property name (error printed) 3249 * - invalid value (error printed) 3250 * - scope of target does not exist (error printed) 3251 * EPERM - couldn't create target (permission denied) (error printed) 3252 * - couldn't create dependency pg (permission denied) (error printed) 3253 * - couldn't modify dependency pg (permission denied) (error printed) 3254 * EROFS - couldn't create target (repository read-only) 3255 * - couldn't create dependency pg (repository read-only) 3256 * EACCES - couldn't create target (backend access denied) 3257 * - couldn't create dependency pg (backend access denied) 3258 * ECANCELED - sc_trans's pg was deleted 3259 * EALREADY - property for dependent already exists in sc_trans's pg 3260 * EEXIST - dependency pg already exists in target (error printed) 3261 * EBUSY - target deleted (error printed) 3262 * - property group changed during import (error printed) 3263 */ 3264 static int 3265 lscf_dependent_import(void *a1, void *pvt) 3266 { 3267 pgroup_t *pgrp = a1; 3268 scf_callback_t *lcbdata = pvt; 3269 3270 int isservice; 3271 int ret; 3272 scf_transaction_entry_t *e; 3273 scf_value_t *val; 3274 scf_callback_t dependent_cbdata; 3275 scf_error_t scfe; 3276 3277 /* 3278 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 3279 * it's invalid, we fail before modifying the repository. 3280 */ 3281 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3282 &dependent_cbdata.sc_parent, &isservice); 3283 switch (scfe) { 3284 case SCF_ERROR_NONE: 3285 break; 3286 3287 case SCF_ERROR_NO_MEMORY: 3288 return (stash_scferror_err(lcbdata, scfe)); 3289 3290 case SCF_ERROR_INVALID_ARGUMENT: 3291 semerr(gettext("The FMRI for the \"%s\" dependent is " 3292 "invalid.\n"), pgrp->sc_pgroup_name); 3293 return (stash_scferror_err(lcbdata, scfe)); 3294 3295 case SCF_ERROR_CONSTRAINT_VIOLATED: 3296 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 3297 "specifies neither a service nor an instance.\n"), 3298 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3299 return (stash_scferror_err(lcbdata, scfe)); 3300 3301 case SCF_ERROR_NOT_FOUND: 3302 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3303 &dependent_cbdata.sc_parent, &isservice); 3304 switch (scfe) { 3305 case SCF_ERROR_NONE: 3306 break; 3307 3308 case SCF_ERROR_NO_MEMORY: 3309 case SCF_ERROR_BACKEND_READONLY: 3310 case SCF_ERROR_BACKEND_ACCESS: 3311 return (stash_scferror_err(lcbdata, scfe)); 3312 3313 case SCF_ERROR_NOT_FOUND: 3314 semerr(gettext("The scope in FMRI \"%s\" for the " 3315 "\"%s\" dependent does not exist.\n"), 3316 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3317 lcbdata->sc_err = EINVAL; 3318 return (UU_WALK_ERROR); 3319 3320 case SCF_ERROR_PERMISSION_DENIED: 3321 warn(gettext( 3322 "Could not create %s (permission denied).\n"), 3323 pgrp->sc_pgroup_fmri); 3324 return (stash_scferror_err(lcbdata, scfe)); 3325 3326 case SCF_ERROR_INVALID_ARGUMENT: 3327 case SCF_ERROR_CONSTRAINT_VIOLATED: 3328 default: 3329 bad_error("create_entity", scfe); 3330 } 3331 break; 3332 3333 default: 3334 bad_error("fmri_to_entity", scfe); 3335 } 3336 3337 if (lcbdata->sc_trans != NULL) { 3338 e = scf_entry_create(lcbdata->sc_handle); 3339 if (e == NULL) { 3340 if (scf_error() != SCF_ERROR_NO_MEMORY) 3341 bad_error("scf_entry_create", scf_error()); 3342 3343 entity_destroy(dependent_cbdata.sc_parent, isservice); 3344 return (stash_scferror(lcbdata)); 3345 } 3346 3347 if (scf_transaction_property_new(lcbdata->sc_trans, e, 3348 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 3349 switch (scf_error()) { 3350 case SCF_ERROR_INVALID_ARGUMENT: 3351 warn(gettext("Dependent of %s has invalid name " 3352 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 3353 pgrp->sc_pgroup_name); 3354 /* FALLTHROUGH */ 3355 3356 case SCF_ERROR_DELETED: 3357 case SCF_ERROR_CONNECTION_BROKEN: 3358 scf_entry_destroy(e); 3359 entity_destroy(dependent_cbdata.sc_parent, 3360 isservice); 3361 return (stash_scferror(lcbdata)); 3362 3363 case SCF_ERROR_EXISTS: 3364 scf_entry_destroy(e); 3365 entity_destroy(dependent_cbdata.sc_parent, 3366 isservice); 3367 lcbdata->sc_err = EALREADY; 3368 return (UU_WALK_ERROR); 3369 3370 case SCF_ERROR_NOT_BOUND: 3371 case SCF_ERROR_HANDLE_MISMATCH: 3372 case SCF_ERROR_NOT_SET: 3373 default: 3374 bad_error("scf_transaction_property_new", 3375 scf_error()); 3376 } 3377 } 3378 3379 val = scf_value_create(lcbdata->sc_handle); 3380 if (val == NULL) { 3381 if (scf_error() != SCF_ERROR_NO_MEMORY) 3382 bad_error("scf_value_create", scf_error()); 3383 3384 entity_destroy(dependent_cbdata.sc_parent, isservice); 3385 return (stash_scferror(lcbdata)); 3386 } 3387 3388 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3389 pgrp->sc_pgroup_fmri) != 0) 3390 /* invalid should have been caught above */ 3391 bad_error("scf_value_set_from_string", scf_error()); 3392 3393 if (scf_entry_add_value(e, val) != 0) 3394 bad_error("scf_entry_add_value", scf_error()); 3395 } 3396 3397 /* Add the property group to the target entity. */ 3398 3399 dependent_cbdata.sc_handle = lcbdata->sc_handle; 3400 dependent_cbdata.sc_flags = lcbdata->sc_flags; 3401 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 3402 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 3403 3404 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 3405 3406 entity_destroy(dependent_cbdata.sc_parent, isservice); 3407 3408 if (ret == UU_WALK_NEXT) 3409 return (ret); 3410 3411 if (ret != UU_WALK_ERROR) 3412 bad_error("entity_pgroup_import", ret); 3413 3414 switch (dependent_cbdata.sc_err) { 3415 case ECANCELED: 3416 warn(gettext("%s deleted unexpectedly.\n"), 3417 pgrp->sc_pgroup_fmri); 3418 lcbdata->sc_err = EBUSY; 3419 break; 3420 3421 case EEXIST: 3422 warn(gettext("Could not create \"%s\" dependency in %s " 3423 "(already exists).\n"), pgrp->sc_pgroup_name, 3424 pgrp->sc_pgroup_fmri); 3425 /* FALLTHROUGH */ 3426 3427 default: 3428 lcbdata->sc_err = dependent_cbdata.sc_err; 3429 } 3430 3431 return (UU_WALK_ERROR); 3432 } 3433 3434 static int upgrade_dependent(const scf_property_t *, const entity_t *, 3435 const scf_snaplevel_t *, scf_transaction_t *); 3436 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 3437 const pgroup_t *); 3438 3439 /* 3440 * Upgrade uncustomized dependents of ent to those specified in ient. Read 3441 * the current dependent targets from running (the snaplevel of a running 3442 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 3443 * scf_instance_t * according to ient, otherwise). Draw the ancestral 3444 * dependent targets and dependency properties from li_dpts_pg (the 3445 * "dependents" property group in snpl) and snpl (the snaplevel which 3446 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 3447 * snpl doesn't have a "dependents" property group, and any dependents in ient 3448 * are new. 3449 * 3450 * Returns 3451 * 0 - success 3452 * ECONNABORTED - repository connection broken 3453 * ENOMEM - out of memory 3454 * ENOSPC - configd is out of resources 3455 * ECANCELED - ent was deleted 3456 * ENODEV - the entity containing li_dpts_pg was deleted 3457 * EPERM - could not modify dependents pg (permission denied) (error printed) 3458 * - couldn't upgrade dependent (permission denied) (error printed) 3459 * - couldn't create dependent (permission denied) (error printed) 3460 * EROFS - could not modify dependents pg (repository read-only) 3461 * - couldn't upgrade dependent (repository read-only) 3462 * - couldn't create dependent (repository read-only) 3463 * EACCES - could not modify dependents pg (backend access denied) 3464 * - could not upgrade dependent (backend access denied) 3465 * - could not create dependent (backend access denied) 3466 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 3467 * - dependent target deleted (error printed) 3468 * - dependent pg changed (error printed) 3469 * EINVAL - new dependent is invalid (error printed) 3470 * EBADF - snpl is corrupt (error printed) 3471 * - snpl has corrupt pg (error printed) 3472 * - dependency pg in target is corrupt (error printed) 3473 * - target has corrupt snapshot (error printed) 3474 * EEXIST - dependency pg already existed in target service (error printed) 3475 */ 3476 static int 3477 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 3478 const scf_snaplevel_t *snpl, const entity_t *ient, 3479 const scf_snaplevel_t *running, void *ent) 3480 { 3481 pgroup_t *new_dpt_pgroup; 3482 scf_callback_t cbdata; 3483 int r, unseen, tx_started = 0; 3484 int have_cur_depts; 3485 3486 const char * const dependents = "dependents"; 3487 3488 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3489 3490 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 3491 /* Nothing to do. */ 3492 return (0); 3493 3494 /* Fetch the current version of the "dependents" property group. */ 3495 have_cur_depts = 1; 3496 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 3497 switch (scf_error()) { 3498 case SCF_ERROR_NOT_FOUND: 3499 break; 3500 3501 case SCF_ERROR_DELETED: 3502 case SCF_ERROR_CONNECTION_BROKEN: 3503 return (scferror2errno(scf_error())); 3504 3505 case SCF_ERROR_NOT_SET: 3506 case SCF_ERROR_INVALID_ARGUMENT: 3507 case SCF_ERROR_HANDLE_MISMATCH: 3508 case SCF_ERROR_NOT_BOUND: 3509 default: 3510 bad_error("entity_get_pg", scf_error()); 3511 } 3512 3513 have_cur_depts = 0; 3514 } 3515 3516 /* Fetch the running version of the "dependents" property group. */ 3517 ud_run_dpts_pg_set = 0; 3518 if (running != NULL) 3519 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 3520 else 3521 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 3522 if (r == 0) { 3523 ud_run_dpts_pg_set = 1; 3524 } else { 3525 switch (scf_error()) { 3526 case SCF_ERROR_NOT_FOUND: 3527 break; 3528 3529 case SCF_ERROR_DELETED: 3530 case SCF_ERROR_CONNECTION_BROKEN: 3531 return (scferror2errno(scf_error())); 3532 3533 case SCF_ERROR_NOT_SET: 3534 case SCF_ERROR_INVALID_ARGUMENT: 3535 case SCF_ERROR_HANDLE_MISMATCH: 3536 case SCF_ERROR_NOT_BOUND: 3537 default: 3538 bad_error(running ? "scf_snaplevel_get_pg" : 3539 "entity_get_pg", scf_error()); 3540 } 3541 } 3542 3543 /* 3544 * Clear the seen fields of the dependents, so we can tell which ones 3545 * are new. 3546 */ 3547 if (uu_list_walk(ient->sc_dependents, clear_int, 3548 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3549 bad_error("uu_list_walk", uu_error()); 3550 3551 if (li_dpts_pg != NULL) { 3552 /* 3553 * Each property in li_dpts_pg represents a dependent tag in 3554 * the old manifest. For each, call upgrade_dependent(), 3555 * which will change ud_cur_depts_pg or dependencies in other 3556 * services as appropriate. Note (a) that changes to 3557 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3558 * made en masse, and (b) it's ok if the entity doesn't have 3559 * a current version of the "dependents" property group, 3560 * because we'll just consider all dependents as customized 3561 * (by being deleted). 3562 */ 3563 3564 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3565 switch (scf_error()) { 3566 case SCF_ERROR_DELETED: 3567 return (ENODEV); 3568 3569 case SCF_ERROR_CONNECTION_BROKEN: 3570 return (ECONNABORTED); 3571 3572 case SCF_ERROR_HANDLE_MISMATCH: 3573 case SCF_ERROR_NOT_BOUND: 3574 case SCF_ERROR_NOT_SET: 3575 default: 3576 bad_error("scf_iter_pg_properties", 3577 scf_error()); 3578 } 3579 } 3580 3581 if (have_cur_depts && 3582 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3583 switch (scf_error()) { 3584 case SCF_ERROR_BACKEND_ACCESS: 3585 case SCF_ERROR_BACKEND_READONLY: 3586 case SCF_ERROR_CONNECTION_BROKEN: 3587 return (scferror2errno(scf_error())); 3588 3589 case SCF_ERROR_DELETED: 3590 warn(emsg_pg_deleted, ient->sc_fmri, 3591 dependents); 3592 return (EBUSY); 3593 3594 case SCF_ERROR_PERMISSION_DENIED: 3595 warn(emsg_pg_mod_perm, dependents, 3596 ient->sc_fmri); 3597 return (scferror2errno(scf_error())); 3598 3599 case SCF_ERROR_HANDLE_MISMATCH: 3600 case SCF_ERROR_IN_USE: 3601 case SCF_ERROR_NOT_BOUND: 3602 case SCF_ERROR_NOT_SET: 3603 default: 3604 bad_error("scf_transaction_start", scf_error()); 3605 } 3606 } 3607 tx_started = have_cur_depts; 3608 3609 for (;;) { 3610 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3611 if (r == 0) 3612 break; 3613 if (r == 1) { 3614 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3615 tx_started ? ud_tx : NULL); 3616 switch (r) { 3617 case 0: 3618 continue; 3619 3620 case ECONNABORTED: 3621 case ENOMEM: 3622 case ENOSPC: 3623 case EBADF: 3624 case EBUSY: 3625 case EINVAL: 3626 case EPERM: 3627 case EROFS: 3628 case EACCES: 3629 case EEXIST: 3630 break; 3631 3632 case ECANCELED: 3633 r = ENODEV; 3634 break; 3635 3636 default: 3637 bad_error("upgrade_dependent", r); 3638 } 3639 3640 if (tx_started) 3641 scf_transaction_destroy_children(ud_tx); 3642 return (r); 3643 } 3644 if (r != -1) 3645 bad_error("scf_iter_next_property", r); 3646 3647 switch (scf_error()) { 3648 case SCF_ERROR_DELETED: 3649 r = ENODEV; 3650 break; 3651 3652 case SCF_ERROR_CONNECTION_BROKEN: 3653 r = ECONNABORTED; 3654 break; 3655 3656 case SCF_ERROR_NOT_SET: 3657 case SCF_ERROR_INVALID_ARGUMENT: 3658 case SCF_ERROR_NOT_BOUND: 3659 case SCF_ERROR_HANDLE_MISMATCH: 3660 default: 3661 bad_error("scf_iter_next_property", 3662 scf_error()); 3663 } 3664 3665 if (tx_started) 3666 scf_transaction_destroy_children(ud_tx); 3667 return (r); 3668 } 3669 } 3670 3671 /* import unseen dependents */ 3672 unseen = 0; 3673 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3674 new_dpt_pgroup != NULL; 3675 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3676 new_dpt_pgroup)) { 3677 if (!new_dpt_pgroup->sc_pgroup_seen) { 3678 unseen = 1; 3679 break; 3680 } 3681 } 3682 3683 /* If there are none, exit early. */ 3684 if (unseen == 0) 3685 goto commit; 3686 3687 /* Set up for lscf_dependent_import() */ 3688 cbdata.sc_handle = g_hndl; 3689 cbdata.sc_parent = ent; 3690 cbdata.sc_service = issvc; 3691 cbdata.sc_flags = 0; 3692 3693 if (!have_cur_depts) { 3694 /* 3695 * We have new dependents to import, so we need a "dependents" 3696 * property group. 3697 */ 3698 if (issvc) 3699 r = scf_service_add_pg(ent, dependents, 3700 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3701 else 3702 r = scf_instance_add_pg(ent, dependents, 3703 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3704 if (r != 0) { 3705 switch (scf_error()) { 3706 case SCF_ERROR_DELETED: 3707 case SCF_ERROR_CONNECTION_BROKEN: 3708 case SCF_ERROR_BACKEND_READONLY: 3709 case SCF_ERROR_BACKEND_ACCESS: 3710 case SCF_ERROR_NO_RESOURCES: 3711 return (scferror2errno(scf_error())); 3712 3713 case SCF_ERROR_EXISTS: 3714 warn(emsg_pg_added, ient->sc_fmri, dependents); 3715 return (EBUSY); 3716 3717 case SCF_ERROR_PERMISSION_DENIED: 3718 warn(emsg_pg_add_perm, dependents, 3719 ient->sc_fmri); 3720 return (scferror2errno(scf_error())); 3721 3722 case SCF_ERROR_NOT_BOUND: 3723 case SCF_ERROR_HANDLE_MISMATCH: 3724 case SCF_ERROR_INVALID_ARGUMENT: 3725 case SCF_ERROR_NOT_SET: 3726 default: 3727 bad_error("scf_service_add_pg", scf_error()); 3728 } 3729 } 3730 } 3731 3732 cbdata.sc_trans = ud_tx; 3733 3734 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3735 switch (scf_error()) { 3736 case SCF_ERROR_CONNECTION_BROKEN: 3737 case SCF_ERROR_BACKEND_ACCESS: 3738 case SCF_ERROR_BACKEND_READONLY: 3739 return (scferror2errno(scf_error())); 3740 3741 case SCF_ERROR_DELETED: 3742 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3743 return (EBUSY); 3744 3745 case SCF_ERROR_PERMISSION_DENIED: 3746 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3747 return (scferror2errno(scf_error())); 3748 3749 case SCF_ERROR_HANDLE_MISMATCH: 3750 case SCF_ERROR_IN_USE: 3751 case SCF_ERROR_NOT_BOUND: 3752 case SCF_ERROR_NOT_SET: 3753 default: 3754 bad_error("scf_transaction_start", scf_error()); 3755 } 3756 } 3757 tx_started = 1; 3758 3759 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3760 new_dpt_pgroup != NULL; 3761 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3762 new_dpt_pgroup)) { 3763 if (new_dpt_pgroup->sc_pgroup_seen) 3764 continue; 3765 3766 if (ud_run_dpts_pg_set) { 3767 /* 3768 * If the dependent is already there, then we have 3769 * a conflict. 3770 */ 3771 if (scf_pg_get_property(ud_run_dpts_pg, 3772 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3773 r = handle_dependent_conflict(ient, ud_prop, 3774 new_dpt_pgroup); 3775 switch (r) { 3776 case 0: 3777 continue; 3778 3779 case ECONNABORTED: 3780 case ENOMEM: 3781 case EBUSY: 3782 case EBADF: 3783 case EINVAL: 3784 scf_transaction_destroy_children(ud_tx); 3785 return (r); 3786 3787 default: 3788 bad_error("handle_dependent_conflict", 3789 r); 3790 } 3791 } else { 3792 switch (scf_error()) { 3793 case SCF_ERROR_NOT_FOUND: 3794 break; 3795 3796 case SCF_ERROR_INVALID_ARGUMENT: 3797 warn(emsg_fmri_invalid_pg_name, 3798 ient->sc_fmri, 3799 new_dpt_pgroup->sc_pgroup_name); 3800 scf_transaction_destroy_children(ud_tx); 3801 return (EINVAL); 3802 3803 case SCF_ERROR_DELETED: 3804 warn(emsg_pg_deleted, ient->sc_fmri, 3805 new_dpt_pgroup->sc_pgroup_name); 3806 scf_transaction_destroy_children(ud_tx); 3807 return (EBUSY); 3808 3809 case SCF_ERROR_CONNECTION_BROKEN: 3810 scf_transaction_destroy_children(ud_tx); 3811 return (ECONNABORTED); 3812 3813 case SCF_ERROR_NOT_BOUND: 3814 case SCF_ERROR_HANDLE_MISMATCH: 3815 case SCF_ERROR_NOT_SET: 3816 default: 3817 bad_error("scf_pg_get_property", 3818 scf_error()); 3819 } 3820 } 3821 } 3822 3823 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3824 if (r != UU_WALK_NEXT) { 3825 if (r != UU_WALK_ERROR) 3826 bad_error("lscf_dependent_import", r); 3827 3828 if (cbdata.sc_err == EALREADY) { 3829 /* Collisions were handled preemptively. */ 3830 bad_error("lscf_dependent_import", 3831 cbdata.sc_err); 3832 } 3833 3834 scf_transaction_destroy_children(ud_tx); 3835 return (cbdata.sc_err); 3836 } 3837 } 3838 3839 commit: 3840 if (!tx_started) 3841 return (0); 3842 3843 r = scf_transaction_commit(ud_tx); 3844 3845 scf_transaction_destroy_children(ud_tx); 3846 3847 switch (r) { 3848 case 1: 3849 return (0); 3850 3851 case 0: 3852 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3853 return (EBUSY); 3854 3855 case -1: 3856 break; 3857 3858 default: 3859 bad_error("scf_transaction_commit", r); 3860 } 3861 3862 switch (scf_error()) { 3863 case SCF_ERROR_CONNECTION_BROKEN: 3864 case SCF_ERROR_BACKEND_READONLY: 3865 case SCF_ERROR_BACKEND_ACCESS: 3866 case SCF_ERROR_NO_RESOURCES: 3867 return (scferror2errno(scf_error())); 3868 3869 case SCF_ERROR_DELETED: 3870 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3871 return (EBUSY); 3872 3873 case SCF_ERROR_PERMISSION_DENIED: 3874 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3875 return (scferror2errno(scf_error())); 3876 3877 case SCF_ERROR_NOT_BOUND: 3878 case SCF_ERROR_INVALID_ARGUMENT: 3879 case SCF_ERROR_NOT_SET: 3880 default: 3881 bad_error("scf_transaction_destroy", scf_error()); 3882 /* NOTREACHED */ 3883 } 3884 } 3885 3886 /* 3887 * Used to add the manifests to the list of currently supported manifests. 3888 * We can modify the existing manifest list removing entries if the files 3889 * don't exist. 3890 * 3891 * Get the old list and the new file name 3892 * If the new file name is in the list return 3893 * If not then add the file to the list. 3894 * As we process the list check to see if the files in the old list exist 3895 * if not then remove the file from the list. 3896 * Commit the list of manifest file names. 3897 * 3898 */ 3899 static int 3900 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient, 3901 const scf_snaplevel_t *running, void *ent) 3902 { 3903 scf_propertygroup_t *ud_mfsts_pg = NULL; 3904 scf_property_t *ud_prop = NULL; 3905 scf_iter_t *ud_prop_iter; 3906 scf_value_t *fname_value; 3907 scf_callback_t cbdata; 3908 pgroup_t *mfst_pgroup; 3909 property_t *mfst_prop; 3910 property_t *old_prop; 3911 char *pname; 3912 char *fval; 3913 char *old_pname; 3914 char *old_fval; 3915 int no_upgrade_pg; 3916 int mfst_seen; 3917 int r; 3918 3919 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3920 3921 /* 3922 * This should always be the service base on the code 3923 * path, and the fact that the manifests pg is a service 3924 * level property group only. 3925 */ 3926 ud_mfsts_pg = scf_pg_create(g_hndl); 3927 ud_prop = scf_property_create(g_hndl); 3928 ud_prop_iter = scf_iter_create(g_hndl); 3929 fname_value = scf_value_create(g_hndl); 3930 3931 /* Fetch the "manifests" property group */ 3932 no_upgrade_pg = 0; 3933 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3934 ud_mfsts_pg); 3935 if (r != 0) { 3936 switch (scf_error()) { 3937 case SCF_ERROR_NOT_FOUND: 3938 no_upgrade_pg = 1; 3939 break; 3940 3941 case SCF_ERROR_DELETED: 3942 case SCF_ERROR_CONNECTION_BROKEN: 3943 return (scferror2errno(scf_error())); 3944 3945 case SCF_ERROR_NOT_SET: 3946 case SCF_ERROR_INVALID_ARGUMENT: 3947 case SCF_ERROR_HANDLE_MISMATCH: 3948 case SCF_ERROR_NOT_BOUND: 3949 default: 3950 bad_error(running ? "scf_snaplevel_get_pg" : 3951 "entity_get_pg", scf_error()); 3952 } 3953 } 3954 3955 if (no_upgrade_pg) { 3956 cbdata.sc_handle = g_hndl; 3957 cbdata.sc_parent = ent; 3958 cbdata.sc_service = issvc; 3959 cbdata.sc_flags = SCI_FORCE; 3960 cbdata.sc_source_fmri = ient->sc_fmri; 3961 cbdata.sc_target_fmri = ient->sc_fmri; 3962 3963 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3964 return (cbdata.sc_err); 3965 3966 return (0); 3967 } 3968 3969 /* Fetch the new manifests property group */ 3970 mfst_pgroup = internal_pgroup_find_or_create(ient, 3971 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 3972 assert(mfst_pgroup != NULL); 3973 3974 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3975 SCF_SUCCESS) 3976 return (-1); 3977 3978 if ((pname = malloc(MAXPATHLEN)) == NULL) 3979 return (ENOMEM); 3980 if ((fval = malloc(MAXPATHLEN)) == NULL) { 3981 free(pname); 3982 return (ENOMEM); 3983 } 3984 3985 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 3986 mfst_seen = 0; 3987 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 3988 continue; 3989 3990 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3991 mfst_prop != NULL; 3992 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3993 mfst_prop)) { 3994 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3995 mfst_seen = 1; 3996 } 3997 } 3998 3999 /* 4000 * If the manifest is not seen then add it to the new mfst 4001 * property list to get proccessed into the repo. 4002 */ 4003 if (mfst_seen == 0) { 4004 /* 4005 * If we cannot get the value then there is no 4006 * reason to attempt to attach the value to 4007 * the property group 4008 */ 4009 if (prop_get_val(ud_prop, fname_value) == 0 && 4010 scf_value_get_astring(fname_value, fval, 4011 MAXPATHLEN) != -1) { 4012 old_pname = safe_strdup(pname); 4013 old_fval = safe_strdup(fval); 4014 old_prop = internal_property_create(old_pname, 4015 SCF_TYPE_ASTRING, 1, old_fval); 4016 4017 /* 4018 * Already checked to see if the property exists 4019 * in the group, and it does not. 4020 */ 4021 (void) internal_attach_property(mfst_pgroup, 4022 old_prop); 4023 } 4024 } 4025 } 4026 free(pname); 4027 free(fval); 4028 4029 cbdata.sc_handle = g_hndl; 4030 cbdata.sc_parent = ent; 4031 cbdata.sc_service = issvc; 4032 cbdata.sc_flags = SCI_FORCE; 4033 cbdata.sc_source_fmri = ient->sc_fmri; 4034 cbdata.sc_target_fmri = ient->sc_fmri; 4035 4036 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 4037 return (cbdata.sc_err); 4038 4039 return (r); 4040 } 4041 4042 /* 4043 * prop is taken to be a property in the "dependents" property group of snpl, 4044 * which is taken to be the snaplevel of a last-import snapshot corresponding 4045 * to ient. If prop is a valid dependents property, upgrade the dependent it 4046 * represents according to the repository & ient. If ud_run_dpts_pg_set is 4047 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 4048 * of the entity ient represents (possibly in the running snapshot). If it 4049 * needs to be changed, an entry will be added to tx, if not NULL. 4050 * 4051 * Returns 4052 * 0 - success 4053 * ECONNABORTED - repository connection broken 4054 * ENOMEM - out of memory 4055 * ENOSPC - configd was out of resources 4056 * ECANCELED - snpl's entity was deleted 4057 * EINVAL - dependent target is invalid (error printed) 4058 * - dependent is invalid (error printed) 4059 * EBADF - snpl is corrupt (error printed) 4060 * - snpl has corrupt pg (error printed) 4061 * - dependency pg in target is corrupt (error printed) 4062 * - running snapshot in dependent is missing snaplevel (error printed) 4063 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 4064 * - couldn't create dependent (permission denied) (error printed) 4065 * - couldn't modify dependent pg (permission denied) (error printed) 4066 * EROFS - couldn't delete dependency pg (repository read-only) 4067 * - couldn't create dependent (repository read-only) 4068 * EACCES - couldn't delete dependency pg (backend access denied) 4069 * - couldn't create dependent (backend access denied) 4070 * EBUSY - ud_run_dpts_pg was deleted (error printed) 4071 * - tx's pg was deleted (error printed) 4072 * - dependent pg was changed or deleted (error printed) 4073 * EEXIST - dependency pg already exists in new target (error printed) 4074 */ 4075 static int 4076 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 4077 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 4078 { 4079 pgroup_t pgrp; 4080 scf_type_t ty; 4081 pgroup_t *new_dpt_pgroup; 4082 pgroup_t *old_dpt_pgroup = NULL; 4083 pgroup_t *current_pg; 4084 pgroup_t *dpt; 4085 scf_callback_t cbdata; 4086 int tissvc; 4087 void *target_ent; 4088 scf_error_t serr; 4089 int r; 4090 scf_transaction_entry_t *ent; 4091 4092 const char * const cf_inval = gettext("Conflict upgrading %s " 4093 "(dependent \"%s\" has invalid dependents property).\n"); 4094 const char * const cf_missing = gettext("Conflict upgrading %s " 4095 "(dependent \"%s\" is missing).\n"); 4096 const char * const cf_newdpg = gettext("Conflict upgrading %s " 4097 "(dependent \"%s\" has new dependency property group).\n"); 4098 const char * const cf_newtarg = gettext("Conflict upgrading %s " 4099 "(dependent \"%s\" has new target).\n"); 4100 const char * const li_corrupt = 4101 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 4102 const char * const upgrading = 4103 gettext("%s: Upgrading dependent \"%s\".\n"); 4104 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 4105 "corrupt (missing snaplevel).\n"); 4106 4107 if (scf_property_type(prop, &ty) != 0) { 4108 switch (scf_error()) { 4109 case SCF_ERROR_DELETED: 4110 case SCF_ERROR_CONNECTION_BROKEN: 4111 return (scferror2errno(scf_error())); 4112 4113 case SCF_ERROR_NOT_BOUND: 4114 case SCF_ERROR_NOT_SET: 4115 default: 4116 bad_error("scf_property_type", scf_error()); 4117 } 4118 } 4119 4120 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4121 warn(li_corrupt, ient->sc_fmri); 4122 return (EBADF); 4123 } 4124 4125 /* 4126 * prop represents a dependent in the old manifest. It is named after 4127 * the dependent. 4128 */ 4129 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 4130 switch (scf_error()) { 4131 case SCF_ERROR_DELETED: 4132 case SCF_ERROR_CONNECTION_BROKEN: 4133 return (scferror2errno(scf_error())); 4134 4135 case SCF_ERROR_NOT_BOUND: 4136 case SCF_ERROR_NOT_SET: 4137 default: 4138 bad_error("scf_property_get_name", scf_error()); 4139 } 4140 } 4141 4142 /* See if it's in the new manifest. */ 4143 pgrp.sc_pgroup_name = ud_name; 4144 new_dpt_pgroup = 4145 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 4146 4147 /* If it's not, delete it... if it hasn't been customized. */ 4148 if (new_dpt_pgroup == NULL) { 4149 if (!ud_run_dpts_pg_set) 4150 return (0); 4151 4152 if (scf_property_get_value(prop, ud_val) != 0) { 4153 switch (scf_error()) { 4154 case SCF_ERROR_NOT_FOUND: 4155 case SCF_ERROR_CONSTRAINT_VIOLATED: 4156 warn(li_corrupt, ient->sc_fmri); 4157 return (EBADF); 4158 4159 case SCF_ERROR_DELETED: 4160 case SCF_ERROR_CONNECTION_BROKEN: 4161 return (scferror2errno(scf_error())); 4162 4163 case SCF_ERROR_HANDLE_MISMATCH: 4164 case SCF_ERROR_NOT_BOUND: 4165 case SCF_ERROR_NOT_SET: 4166 case SCF_ERROR_PERMISSION_DENIED: 4167 default: 4168 bad_error("scf_property_get_value", 4169 scf_error()); 4170 } 4171 } 4172 4173 if (scf_value_get_as_string(ud_val, ud_oldtarg, 4174 max_scf_value_len + 1) < 0) 4175 bad_error("scf_value_get_as_string", scf_error()); 4176 4177 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 4178 0) { 4179 switch (scf_error()) { 4180 case SCF_ERROR_NOT_FOUND: 4181 return (0); 4182 4183 case SCF_ERROR_CONNECTION_BROKEN: 4184 return (scferror2errno(scf_error())); 4185 4186 case SCF_ERROR_DELETED: 4187 warn(emsg_pg_deleted, ient->sc_fmri, 4188 "dependents"); 4189 return (EBUSY); 4190 4191 case SCF_ERROR_INVALID_ARGUMENT: 4192 case SCF_ERROR_NOT_BOUND: 4193 case SCF_ERROR_HANDLE_MISMATCH: 4194 case SCF_ERROR_NOT_SET: 4195 default: 4196 bad_error("scf_pg_get_property", scf_error()); 4197 } 4198 } 4199 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4200 switch (scf_error()) { 4201 case SCF_ERROR_NOT_FOUND: 4202 case SCF_ERROR_CONSTRAINT_VIOLATED: 4203 warn(cf_inval, ient->sc_fmri, ud_name); 4204 return (0); 4205 4206 case SCF_ERROR_DELETED: 4207 case SCF_ERROR_CONNECTION_BROKEN: 4208 return (scferror2errno(scf_error())); 4209 4210 case SCF_ERROR_HANDLE_MISMATCH: 4211 case SCF_ERROR_NOT_BOUND: 4212 case SCF_ERROR_NOT_SET: 4213 case SCF_ERROR_PERMISSION_DENIED: 4214 default: 4215 bad_error("scf_property_get_value", 4216 scf_error()); 4217 } 4218 } 4219 4220 ty = scf_value_type(ud_val); 4221 assert(ty != SCF_TYPE_INVALID); 4222 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4223 warn(cf_inval, ient->sc_fmri, ud_name); 4224 return (0); 4225 } 4226 4227 if (scf_value_get_as_string(ud_val, ud_ctarg, 4228 max_scf_value_len + 1) < 0) 4229 bad_error("scf_value_get_as_string", scf_error()); 4230 4231 r = fmri_equal(ud_ctarg, ud_oldtarg); 4232 switch (r) { 4233 case 1: 4234 break; 4235 4236 case 0: 4237 case -1: /* warn? */ 4238 warn(cf_newtarg, ient->sc_fmri, ud_name); 4239 return (0); 4240 4241 case -2: 4242 warn(li_corrupt, ient->sc_fmri); 4243 return (EBADF); 4244 4245 default: 4246 bad_error("fmri_equal", r); 4247 } 4248 4249 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4250 switch (scf_error()) { 4251 case SCF_ERROR_NOT_FOUND: 4252 warn(li_corrupt, ient->sc_fmri); 4253 return (EBADF); 4254 4255 case SCF_ERROR_DELETED: 4256 case SCF_ERROR_CONNECTION_BROKEN: 4257 return (scferror2errno(scf_error())); 4258 4259 case SCF_ERROR_NOT_BOUND: 4260 case SCF_ERROR_HANDLE_MISMATCH: 4261 case SCF_ERROR_INVALID_ARGUMENT: 4262 case SCF_ERROR_NOT_SET: 4263 default: 4264 bad_error("scf_snaplevel_get_pg", scf_error()); 4265 } 4266 } 4267 4268 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4269 snap_lastimport); 4270 switch (r) { 4271 case 0: 4272 break; 4273 4274 case ECANCELED: 4275 case ECONNABORTED: 4276 case ENOMEM: 4277 case EBADF: 4278 return (r); 4279 4280 case EACCES: 4281 default: 4282 bad_error("load_pg", r); 4283 } 4284 4285 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4286 switch (serr) { 4287 case SCF_ERROR_NONE: 4288 break; 4289 4290 case SCF_ERROR_NO_MEMORY: 4291 internal_pgroup_free(old_dpt_pgroup); 4292 return (ENOMEM); 4293 4294 case SCF_ERROR_NOT_FOUND: 4295 internal_pgroup_free(old_dpt_pgroup); 4296 goto delprop; 4297 4298 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 4299 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 4300 default: 4301 bad_error("fmri_to_entity", serr); 4302 } 4303 4304 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4305 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4306 switch (r) { 4307 case 0: 4308 break; 4309 4310 case ECONNABORTED: 4311 internal_pgroup_free(old_dpt_pgroup); 4312 return (r); 4313 4314 case ECANCELED: 4315 case ENOENT: 4316 internal_pgroup_free(old_dpt_pgroup); 4317 goto delprop; 4318 4319 case EBADF: 4320 warn(r_no_lvl, ud_ctarg); 4321 internal_pgroup_free(old_dpt_pgroup); 4322 return (r); 4323 4324 case EINVAL: 4325 default: 4326 bad_error("entity_get_running_pg", r); 4327 } 4328 4329 /* load it */ 4330 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4331 switch (r) { 4332 case 0: 4333 break; 4334 4335 case ECANCELED: 4336 internal_pgroup_free(old_dpt_pgroup); 4337 goto delprop; 4338 4339 case ECONNABORTED: 4340 case ENOMEM: 4341 case EBADF: 4342 internal_pgroup_free(old_dpt_pgroup); 4343 return (r); 4344 4345 case EACCES: 4346 default: 4347 bad_error("load_pg", r); 4348 } 4349 4350 /* compare property groups */ 4351 if (!pg_equal(old_dpt_pgroup, current_pg)) { 4352 warn(cf_newdpg, ient->sc_fmri, ud_name); 4353 internal_pgroup_free(old_dpt_pgroup); 4354 internal_pgroup_free(current_pg); 4355 return (0); 4356 } 4357 4358 internal_pgroup_free(old_dpt_pgroup); 4359 internal_pgroup_free(current_pg); 4360 4361 if (g_verbose) 4362 warn(gettext("%s: Deleting dependent \"%s\".\n"), 4363 ient->sc_fmri, ud_name); 4364 4365 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4366 switch (scf_error()) { 4367 case SCF_ERROR_NOT_FOUND: 4368 case SCF_ERROR_DELETED: 4369 internal_pgroup_free(old_dpt_pgroup); 4370 goto delprop; 4371 4372 case SCF_ERROR_CONNECTION_BROKEN: 4373 internal_pgroup_free(old_dpt_pgroup); 4374 return (ECONNABORTED); 4375 4376 case SCF_ERROR_NOT_SET: 4377 case SCF_ERROR_INVALID_ARGUMENT: 4378 case SCF_ERROR_HANDLE_MISMATCH: 4379 case SCF_ERROR_NOT_BOUND: 4380 default: 4381 bad_error("entity_get_pg", scf_error()); 4382 } 4383 } 4384 4385 if (scf_pg_delete(ud_pg) != 0) { 4386 switch (scf_error()) { 4387 case SCF_ERROR_DELETED: 4388 break; 4389 4390 case SCF_ERROR_CONNECTION_BROKEN: 4391 case SCF_ERROR_BACKEND_READONLY: 4392 case SCF_ERROR_BACKEND_ACCESS: 4393 return (scferror2errno(scf_error())); 4394 4395 case SCF_ERROR_PERMISSION_DENIED: 4396 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4397 return (scferror2errno(scf_error())); 4398 4399 case SCF_ERROR_NOT_SET: 4400 default: 4401 bad_error("scf_pg_delete", scf_error()); 4402 } 4403 } 4404 4405 /* 4406 * This service was changed, so it must be refreshed. But 4407 * since it's not mentioned in the new manifest, we have to 4408 * record its FMRI here for use later. We record the name 4409 * & the entity (via sc_parent) in case we need to print error 4410 * messages during the refresh. 4411 */ 4412 dpt = internal_pgroup_new(); 4413 if (dpt == NULL) 4414 return (ENOMEM); 4415 dpt->sc_pgroup_name = strdup(ud_name); 4416 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 4417 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4418 return (ENOMEM); 4419 dpt->sc_parent = (entity_t *)ient; 4420 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4421 uu_die(gettext("libuutil error: %s\n"), 4422 uu_strerror(uu_error())); 4423 4424 delprop: 4425 if (tx == NULL) 4426 return (0); 4427 4428 ent = scf_entry_create(g_hndl); 4429 if (ent == NULL) 4430 return (ENOMEM); 4431 4432 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 4433 scf_entry_destroy(ent); 4434 switch (scf_error()) { 4435 case SCF_ERROR_DELETED: 4436 warn(emsg_pg_deleted, ient->sc_fmri, 4437 "dependents"); 4438 return (EBUSY); 4439 4440 case SCF_ERROR_CONNECTION_BROKEN: 4441 return (scferror2errno(scf_error())); 4442 4443 case SCF_ERROR_NOT_FOUND: 4444 break; 4445 4446 case SCF_ERROR_HANDLE_MISMATCH: 4447 case SCF_ERROR_NOT_BOUND: 4448 case SCF_ERROR_INVALID_ARGUMENT: 4449 case SCF_ERROR_NOT_SET: 4450 default: 4451 bad_error("scf_transaction_property_delete", 4452 scf_error()); 4453 } 4454 } 4455 4456 return (0); 4457 } 4458 4459 new_dpt_pgroup->sc_pgroup_seen = 1; 4460 4461 /* 4462 * Decide whether the dependent has changed in the manifest. 4463 */ 4464 /* Compare the target. */ 4465 if (scf_property_get_value(prop, ud_val) != 0) { 4466 switch (scf_error()) { 4467 case SCF_ERROR_NOT_FOUND: 4468 case SCF_ERROR_CONSTRAINT_VIOLATED: 4469 warn(li_corrupt, ient->sc_fmri); 4470 return (EBADF); 4471 4472 case SCF_ERROR_DELETED: 4473 case SCF_ERROR_CONNECTION_BROKEN: 4474 return (scferror2errno(scf_error())); 4475 4476 case SCF_ERROR_HANDLE_MISMATCH: 4477 case SCF_ERROR_NOT_BOUND: 4478 case SCF_ERROR_NOT_SET: 4479 case SCF_ERROR_PERMISSION_DENIED: 4480 default: 4481 bad_error("scf_property_get_value", scf_error()); 4482 } 4483 } 4484 4485 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 4486 0) 4487 bad_error("scf_value_get_as_string", scf_error()); 4488 4489 /* 4490 * If the fmri's are not equal then the old fmri will need to 4491 * be refreshed to ensure that the changes are properly updated 4492 * in that service. 4493 */ 4494 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 4495 switch (r) { 4496 case 0: 4497 dpt = internal_pgroup_new(); 4498 if (dpt == NULL) 4499 return (ENOMEM); 4500 dpt->sc_pgroup_name = strdup(ud_name); 4501 dpt->sc_pgroup_fmri = strdup(ud_oldtarg); 4502 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4503 return (ENOMEM); 4504 dpt->sc_parent = (entity_t *)ient; 4505 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4506 uu_die(gettext("libuutil error: %s\n"), 4507 uu_strerror(uu_error())); 4508 break; 4509 4510 case 1: 4511 /* Compare the dependency pgs. */ 4512 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4513 switch (scf_error()) { 4514 case SCF_ERROR_NOT_FOUND: 4515 warn(li_corrupt, ient->sc_fmri); 4516 return (EBADF); 4517 4518 case SCF_ERROR_DELETED: 4519 case SCF_ERROR_CONNECTION_BROKEN: 4520 return (scferror2errno(scf_error())); 4521 4522 case SCF_ERROR_NOT_BOUND: 4523 case SCF_ERROR_HANDLE_MISMATCH: 4524 case SCF_ERROR_INVALID_ARGUMENT: 4525 case SCF_ERROR_NOT_SET: 4526 default: 4527 bad_error("scf_snaplevel_get_pg", scf_error()); 4528 } 4529 } 4530 4531 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4532 snap_lastimport); 4533 switch (r) { 4534 case 0: 4535 break; 4536 4537 case ECANCELED: 4538 case ECONNABORTED: 4539 case ENOMEM: 4540 case EBADF: 4541 return (r); 4542 4543 case EACCES: 4544 default: 4545 bad_error("load_pg", r); 4546 } 4547 4548 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4549 /* no change, leave customizations */ 4550 internal_pgroup_free(old_dpt_pgroup); 4551 return (0); 4552 } 4553 break; 4554 4555 case -1: 4556 warn(li_corrupt, ient->sc_fmri); 4557 return (EBADF); 4558 4559 case -2: 4560 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4561 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4562 return (EINVAL); 4563 4564 default: 4565 bad_error("fmri_equal", r); 4566 } 4567 4568 /* 4569 * The dependent has changed in the manifest. Upgrade the current 4570 * properties if they haven't been customized. 4571 */ 4572 4573 /* 4574 * If new_dpt_pgroup->sc_override, then act as though the property 4575 * group hasn't been customized. 4576 */ 4577 if (new_dpt_pgroup->sc_pgroup_override) { 4578 (void) strcpy(ud_ctarg, ud_oldtarg); 4579 goto nocust; 4580 } 4581 4582 if (!ud_run_dpts_pg_set) { 4583 warn(cf_missing, ient->sc_fmri, ud_name); 4584 r = 0; 4585 goto out; 4586 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4587 switch (scf_error()) { 4588 case SCF_ERROR_NOT_FOUND: 4589 warn(cf_missing, ient->sc_fmri, ud_name); 4590 r = 0; 4591 goto out; 4592 4593 case SCF_ERROR_CONNECTION_BROKEN: 4594 r = scferror2errno(scf_error()); 4595 goto out; 4596 4597 case SCF_ERROR_DELETED: 4598 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4599 r = EBUSY; 4600 goto out; 4601 4602 case SCF_ERROR_INVALID_ARGUMENT: 4603 case SCF_ERROR_NOT_BOUND: 4604 case SCF_ERROR_HANDLE_MISMATCH: 4605 case SCF_ERROR_NOT_SET: 4606 default: 4607 bad_error("scf_pg_get_property", scf_error()); 4608 } 4609 } 4610 4611 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4612 switch (scf_error()) { 4613 case SCF_ERROR_NOT_FOUND: 4614 case SCF_ERROR_CONSTRAINT_VIOLATED: 4615 warn(cf_inval, ient->sc_fmri, ud_name); 4616 r = 0; 4617 goto out; 4618 4619 case SCF_ERROR_DELETED: 4620 case SCF_ERROR_CONNECTION_BROKEN: 4621 r = scferror2errno(scf_error()); 4622 goto out; 4623 4624 case SCF_ERROR_HANDLE_MISMATCH: 4625 case SCF_ERROR_NOT_BOUND: 4626 case SCF_ERROR_NOT_SET: 4627 case SCF_ERROR_PERMISSION_DENIED: 4628 default: 4629 bad_error("scf_property_get_value", scf_error()); 4630 } 4631 } 4632 4633 ty = scf_value_type(ud_val); 4634 assert(ty != SCF_TYPE_INVALID); 4635 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4636 warn(cf_inval, ient->sc_fmri, ud_name); 4637 r = 0; 4638 goto out; 4639 } 4640 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4641 0) 4642 bad_error("scf_value_get_as_string", scf_error()); 4643 4644 r = fmri_equal(ud_ctarg, ud_oldtarg); 4645 if (r == -1) { 4646 warn(cf_inval, ient->sc_fmri, ud_name); 4647 r = 0; 4648 goto out; 4649 } else if (r == -2) { 4650 warn(li_corrupt, ient->sc_fmri); 4651 r = EBADF; 4652 goto out; 4653 } else if (r == 0) { 4654 /* 4655 * Target has been changed. Only abort now if it's been 4656 * changed to something other than what's in the manifest. 4657 */ 4658 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4659 if (r == -1) { 4660 warn(cf_inval, ient->sc_fmri, ud_name); 4661 r = 0; 4662 goto out; 4663 } else if (r == 0) { 4664 warn(cf_newtarg, ient->sc_fmri, ud_name); 4665 r = 0; 4666 goto out; 4667 } else if (r != 1) { 4668 /* invalid sc_pgroup_fmri caught above */ 4669 bad_error("fmri_equal", r); 4670 } 4671 4672 /* 4673 * Fetch the current dependency pg. If it's what the manifest 4674 * says, then no problem. 4675 */ 4676 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4677 switch (serr) { 4678 case SCF_ERROR_NONE: 4679 break; 4680 4681 case SCF_ERROR_NOT_FOUND: 4682 warn(cf_missing, ient->sc_fmri, ud_name); 4683 r = 0; 4684 goto out; 4685 4686 case SCF_ERROR_NO_MEMORY: 4687 r = ENOMEM; 4688 goto out; 4689 4690 case SCF_ERROR_CONSTRAINT_VIOLATED: 4691 case SCF_ERROR_INVALID_ARGUMENT: 4692 default: 4693 bad_error("fmri_to_entity", serr); 4694 } 4695 4696 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4697 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4698 switch (r) { 4699 case 0: 4700 break; 4701 4702 case ECONNABORTED: 4703 goto out; 4704 4705 case ECANCELED: 4706 case ENOENT: 4707 warn(cf_missing, ient->sc_fmri, ud_name); 4708 r = 0; 4709 goto out; 4710 4711 case EBADF: 4712 warn(r_no_lvl, ud_ctarg); 4713 goto out; 4714 4715 case EINVAL: 4716 default: 4717 bad_error("entity_get_running_pg", r); 4718 } 4719 4720 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4721 switch (r) { 4722 case 0: 4723 break; 4724 4725 case ECANCELED: 4726 warn(cf_missing, ient->sc_fmri, ud_name); 4727 r = 0; 4728 goto out; 4729 4730 case ECONNABORTED: 4731 case ENOMEM: 4732 case EBADF: 4733 goto out; 4734 4735 case EACCES: 4736 default: 4737 bad_error("load_pg", r); 4738 } 4739 4740 if (!pg_equal(current_pg, new_dpt_pgroup)) 4741 warn(cf_newdpg, ient->sc_fmri, ud_name); 4742 internal_pgroup_free(current_pg); 4743 r = 0; 4744 goto out; 4745 } else if (r != 1) { 4746 bad_error("fmri_equal", r); 4747 } 4748 4749 nocust: 4750 /* 4751 * Target has not been customized. Check the dependency property 4752 * group. 4753 */ 4754 4755 if (old_dpt_pgroup == NULL) { 4756 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4757 ud_pg) != 0) { 4758 switch (scf_error()) { 4759 case SCF_ERROR_NOT_FOUND: 4760 warn(li_corrupt, ient->sc_fmri); 4761 return (EBADF); 4762 4763 case SCF_ERROR_DELETED: 4764 case SCF_ERROR_CONNECTION_BROKEN: 4765 return (scferror2errno(scf_error())); 4766 4767 case SCF_ERROR_NOT_BOUND: 4768 case SCF_ERROR_HANDLE_MISMATCH: 4769 case SCF_ERROR_INVALID_ARGUMENT: 4770 case SCF_ERROR_NOT_SET: 4771 default: 4772 bad_error("scf_snaplevel_get_pg", scf_error()); 4773 } 4774 } 4775 4776 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4777 snap_lastimport); 4778 switch (r) { 4779 case 0: 4780 break; 4781 4782 case ECANCELED: 4783 case ECONNABORTED: 4784 case ENOMEM: 4785 case EBADF: 4786 return (r); 4787 4788 case EACCES: 4789 default: 4790 bad_error("load_pg", r); 4791 } 4792 } 4793 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4794 switch (serr) { 4795 case SCF_ERROR_NONE: 4796 break; 4797 4798 case SCF_ERROR_NOT_FOUND: 4799 warn(cf_missing, ient->sc_fmri, ud_name); 4800 r = 0; 4801 goto out; 4802 4803 case SCF_ERROR_NO_MEMORY: 4804 r = ENOMEM; 4805 goto out; 4806 4807 case SCF_ERROR_CONSTRAINT_VIOLATED: 4808 case SCF_ERROR_INVALID_ARGUMENT: 4809 default: 4810 bad_error("fmri_to_entity", serr); 4811 } 4812 4813 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4814 ud_iter2, ud_inst, imp_snap, ud_snpl); 4815 switch (r) { 4816 case 0: 4817 break; 4818 4819 case ECONNABORTED: 4820 goto out; 4821 4822 case ECANCELED: 4823 case ENOENT: 4824 warn(cf_missing, ient->sc_fmri, ud_name); 4825 r = 0; 4826 goto out; 4827 4828 case EBADF: 4829 warn(r_no_lvl, ud_ctarg); 4830 goto out; 4831 4832 case EINVAL: 4833 default: 4834 bad_error("entity_get_running_pg", r); 4835 } 4836 4837 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4838 switch (r) { 4839 case 0: 4840 break; 4841 4842 case ECANCELED: 4843 warn(cf_missing, ient->sc_fmri, ud_name); 4844 goto out; 4845 4846 case ECONNABORTED: 4847 case ENOMEM: 4848 case EBADF: 4849 goto out; 4850 4851 case EACCES: 4852 default: 4853 bad_error("load_pg", r); 4854 } 4855 4856 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4857 if (!pg_equal(current_pg, new_dpt_pgroup)) 4858 warn(cf_newdpg, ient->sc_fmri, ud_name); 4859 internal_pgroup_free(current_pg); 4860 r = 0; 4861 goto out; 4862 } 4863 4864 /* Uncustomized. Upgrade. */ 4865 4866 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4867 switch (r) { 4868 case 1: 4869 if (pg_equal(current_pg, new_dpt_pgroup)) { 4870 /* Already upgraded. */ 4871 internal_pgroup_free(current_pg); 4872 r = 0; 4873 goto out; 4874 } 4875 4876 internal_pgroup_free(current_pg); 4877 4878 /* upgrade current_pg */ 4879 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4880 switch (scf_error()) { 4881 case SCF_ERROR_CONNECTION_BROKEN: 4882 r = scferror2errno(scf_error()); 4883 goto out; 4884 4885 case SCF_ERROR_DELETED: 4886 warn(cf_missing, ient->sc_fmri, ud_name); 4887 r = 0; 4888 goto out; 4889 4890 case SCF_ERROR_NOT_FOUND: 4891 break; 4892 4893 case SCF_ERROR_INVALID_ARGUMENT: 4894 case SCF_ERROR_NOT_BOUND: 4895 case SCF_ERROR_NOT_SET: 4896 case SCF_ERROR_HANDLE_MISMATCH: 4897 default: 4898 bad_error("entity_get_pg", scf_error()); 4899 } 4900 4901 if (tissvc) 4902 r = scf_service_add_pg(target_ent, ud_name, 4903 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4904 else 4905 r = scf_instance_add_pg(target_ent, ud_name, 4906 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4907 if (r != 0) { 4908 switch (scf_error()) { 4909 case SCF_ERROR_CONNECTION_BROKEN: 4910 case SCF_ERROR_NO_RESOURCES: 4911 case SCF_ERROR_BACKEND_READONLY: 4912 case SCF_ERROR_BACKEND_ACCESS: 4913 r = scferror2errno(scf_error()); 4914 goto out; 4915 4916 case SCF_ERROR_DELETED: 4917 warn(cf_missing, ient->sc_fmri, 4918 ud_name); 4919 r = 0; 4920 goto out; 4921 4922 case SCF_ERROR_PERMISSION_DENIED: 4923 warn(emsg_pg_deleted, ud_ctarg, 4924 ud_name); 4925 r = EPERM; 4926 goto out; 4927 4928 case SCF_ERROR_EXISTS: 4929 warn(emsg_pg_added, ud_ctarg, ud_name); 4930 r = EBUSY; 4931 goto out; 4932 4933 case SCF_ERROR_NOT_BOUND: 4934 case SCF_ERROR_HANDLE_MISMATCH: 4935 case SCF_ERROR_INVALID_ARGUMENT: 4936 case SCF_ERROR_NOT_SET: 4937 default: 4938 bad_error("entity_add_pg", scf_error()); 4939 } 4940 } 4941 } 4942 4943 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4944 switch (r) { 4945 case 0: 4946 break; 4947 4948 case ECANCELED: 4949 warn(cf_missing, ient->sc_fmri, ud_name); 4950 goto out; 4951 4952 case ECONNABORTED: 4953 case ENOMEM: 4954 case EBADF: 4955 goto out; 4956 4957 case EACCES: 4958 default: 4959 bad_error("load_pg", r); 4960 } 4961 4962 if (g_verbose) 4963 warn(upgrading, ient->sc_fmri, ud_name); 4964 4965 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4966 new_dpt_pgroup, 0, ient->sc_fmri); 4967 switch (r) { 4968 case 0: 4969 break; 4970 4971 case ECANCELED: 4972 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4973 r = EBUSY; 4974 goto out; 4975 4976 case EPERM: 4977 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4978 goto out; 4979 4980 case EBUSY: 4981 warn(emsg_pg_changed, ud_ctarg, ud_name); 4982 goto out; 4983 4984 case ECONNABORTED: 4985 case ENOMEM: 4986 case ENOSPC: 4987 case EROFS: 4988 case EACCES: 4989 case EINVAL: 4990 goto out; 4991 4992 default: 4993 bad_error("upgrade_pg", r); 4994 } 4995 break; 4996 4997 case 0: { 4998 scf_transaction_entry_t *ent; 4999 scf_value_t *val; 5000 5001 internal_pgroup_free(current_pg); 5002 5003 /* delete old pg */ 5004 if (g_verbose) 5005 warn(upgrading, ient->sc_fmri, ud_name); 5006 5007 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 5008 switch (scf_error()) { 5009 case SCF_ERROR_CONNECTION_BROKEN: 5010 r = scferror2errno(scf_error()); 5011 goto out; 5012 5013 case SCF_ERROR_DELETED: 5014 warn(cf_missing, ient->sc_fmri, ud_name); 5015 r = 0; 5016 goto out; 5017 5018 case SCF_ERROR_NOT_FOUND: 5019 break; 5020 5021 case SCF_ERROR_INVALID_ARGUMENT: 5022 case SCF_ERROR_NOT_BOUND: 5023 case SCF_ERROR_NOT_SET: 5024 case SCF_ERROR_HANDLE_MISMATCH: 5025 default: 5026 bad_error("entity_get_pg", scf_error()); 5027 } 5028 } else if (scf_pg_delete(ud_pg) != 0) { 5029 switch (scf_error()) { 5030 case SCF_ERROR_DELETED: 5031 break; 5032 5033 case SCF_ERROR_CONNECTION_BROKEN: 5034 case SCF_ERROR_BACKEND_READONLY: 5035 case SCF_ERROR_BACKEND_ACCESS: 5036 r = scferror2errno(scf_error()); 5037 goto out; 5038 5039 case SCF_ERROR_PERMISSION_DENIED: 5040 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 5041 r = scferror2errno(scf_error()); 5042 goto out; 5043 5044 case SCF_ERROR_NOT_SET: 5045 default: 5046 bad_error("scf_pg_delete", scf_error()); 5047 } 5048 } 5049 5050 /* import new one */ 5051 cbdata.sc_handle = g_hndl; 5052 cbdata.sc_trans = NULL; /* handled below */ 5053 cbdata.sc_flags = 0; 5054 5055 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 5056 if (r != UU_WALK_NEXT) { 5057 if (r != UU_WALK_ERROR) 5058 bad_error("lscf_dependent_import", r); 5059 5060 r = cbdata.sc_err; 5061 goto out; 5062 } 5063 5064 if (tx == NULL) 5065 break; 5066 5067 if ((ent = scf_entry_create(g_hndl)) == NULL || 5068 (val = scf_value_create(g_hndl)) == NULL) { 5069 if (scf_error() == SCF_ERROR_NO_MEMORY) 5070 return (ENOMEM); 5071 5072 bad_error("scf_entry_create", scf_error()); 5073 } 5074 5075 if (scf_transaction_property_change_type(tx, ent, ud_name, 5076 SCF_TYPE_FMRI) != 0) { 5077 switch (scf_error()) { 5078 case SCF_ERROR_CONNECTION_BROKEN: 5079 r = scferror2errno(scf_error()); 5080 goto out; 5081 5082 case SCF_ERROR_DELETED: 5083 warn(emsg_pg_deleted, ient->sc_fmri, 5084 "dependents"); 5085 r = EBUSY; 5086 goto out; 5087 5088 case SCF_ERROR_NOT_FOUND: 5089 break; 5090 5091 case SCF_ERROR_NOT_BOUND: 5092 case SCF_ERROR_HANDLE_MISMATCH: 5093 case SCF_ERROR_INVALID_ARGUMENT: 5094 case SCF_ERROR_NOT_SET: 5095 default: 5096 bad_error("scf_transaction_property_" 5097 "change_type", scf_error()); 5098 } 5099 5100 if (scf_transaction_property_new(tx, ent, ud_name, 5101 SCF_TYPE_FMRI) != 0) { 5102 switch (scf_error()) { 5103 case SCF_ERROR_CONNECTION_BROKEN: 5104 r = scferror2errno(scf_error()); 5105 goto out; 5106 5107 case SCF_ERROR_DELETED: 5108 warn(emsg_pg_deleted, ient->sc_fmri, 5109 "dependents"); 5110 r = EBUSY; 5111 goto out; 5112 5113 case SCF_ERROR_EXISTS: 5114 warn(emsg_pg_changed, ient->sc_fmri, 5115 "dependents"); 5116 r = EBUSY; 5117 goto out; 5118 5119 case SCF_ERROR_INVALID_ARGUMENT: 5120 case SCF_ERROR_HANDLE_MISMATCH: 5121 case SCF_ERROR_NOT_BOUND: 5122 case SCF_ERROR_NOT_SET: 5123 default: 5124 bad_error("scf_transaction_property_" 5125 "new", scf_error()); 5126 } 5127 } 5128 } 5129 5130 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 5131 new_dpt_pgroup->sc_pgroup_fmri) != 0) 5132 /* invalid sc_pgroup_fmri caught above */ 5133 bad_error("scf_value_set_from_string", 5134 scf_error()); 5135 5136 if (scf_entry_add_value(ent, val) != 0) 5137 bad_error("scf_entry_add_value", scf_error()); 5138 break; 5139 } 5140 5141 case -2: 5142 warn(li_corrupt, ient->sc_fmri); 5143 internal_pgroup_free(current_pg); 5144 r = EBADF; 5145 goto out; 5146 5147 case -1: 5148 default: 5149 /* invalid sc_pgroup_fmri caught above */ 5150 bad_error("fmri_equal", r); 5151 } 5152 5153 r = 0; 5154 5155 out: 5156 if (old_dpt_pgroup != NULL) 5157 internal_pgroup_free(old_dpt_pgroup); 5158 5159 return (r); 5160 } 5161 5162 /* 5163 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 5164 * would import it, except it seems to exist in the service anyway. Compare 5165 * the existent dependent with the one we would import, and report any 5166 * differences (if there are none, be silent). prop is the property which 5167 * represents the existent dependent (in the dependents property group) in the 5168 * entity corresponding to ient. 5169 * 5170 * Returns 5171 * 0 - success (Sort of. At least, we can continue importing.) 5172 * ECONNABORTED - repository connection broken 5173 * EBUSY - ancestor of prop was deleted (error printed) 5174 * ENOMEM - out of memory 5175 * EBADF - corrupt property group (error printed) 5176 * EINVAL - new_dpt_pgroup has invalid target (error printed) 5177 */ 5178 static int 5179 handle_dependent_conflict(const entity_t * const ient, 5180 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 5181 { 5182 int r; 5183 scf_type_t ty; 5184 scf_error_t scfe; 5185 void *tptr; 5186 int tissvc; 5187 pgroup_t *pgroup; 5188 5189 if (scf_property_get_value(prop, ud_val) != 0) { 5190 switch (scf_error()) { 5191 case SCF_ERROR_CONNECTION_BROKEN: 5192 return (scferror2errno(scf_error())); 5193 5194 case SCF_ERROR_DELETED: 5195 warn(emsg_pg_deleted, ient->sc_fmri, 5196 new_dpt_pgroup->sc_pgroup_name); 5197 return (EBUSY); 5198 5199 case SCF_ERROR_CONSTRAINT_VIOLATED: 5200 case SCF_ERROR_NOT_FOUND: 5201 warn(gettext("Conflict upgrading %s (not importing " 5202 "dependent \"%s\" because it already exists.) " 5203 "Warning: The \"%s/%2$s\" property has more or " 5204 "fewer than one value)).\n"), ient->sc_fmri, 5205 new_dpt_pgroup->sc_pgroup_name, "dependents"); 5206 return (0); 5207 5208 case SCF_ERROR_HANDLE_MISMATCH: 5209 case SCF_ERROR_NOT_BOUND: 5210 case SCF_ERROR_NOT_SET: 5211 case SCF_ERROR_PERMISSION_DENIED: 5212 default: 5213 bad_error("scf_property_get_value", 5214 scf_error()); 5215 } 5216 } 5217 5218 ty = scf_value_type(ud_val); 5219 assert(ty != SCF_TYPE_INVALID); 5220 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 5221 warn(gettext("Conflict upgrading %s (not importing dependent " 5222 "\"%s\" because it already exists). Warning: The " 5223 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 5224 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 5225 scf_type_to_string(ty), "dependents"); 5226 return (0); 5227 } 5228 5229 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 5230 0) 5231 bad_error("scf_value_get_as_string", scf_error()); 5232 5233 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 5234 switch (r) { 5235 case 0: 5236 warn(gettext("Conflict upgrading %s (not importing dependent " 5237 "\"%s\" (target \"%s\") because it already exists with " 5238 "target \"%s\").\n"), ient->sc_fmri, 5239 new_dpt_pgroup->sc_pgroup_name, 5240 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 5241 return (0); 5242 5243 case 1: 5244 break; 5245 5246 case -1: 5247 warn(gettext("Conflict upgrading %s (not importing dependent " 5248 "\"%s\" because it already exists). Warning: The current " 5249 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 5250 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5251 return (0); 5252 5253 case -2: 5254 warn(gettext("Dependent \"%s\" of %s has invalid target " 5255 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 5256 new_dpt_pgroup->sc_pgroup_fmri); 5257 return (EINVAL); 5258 5259 default: 5260 bad_error("fmri_equal", r); 5261 } 5262 5263 /* compare dependency pgs in target */ 5264 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 5265 switch (scfe) { 5266 case SCF_ERROR_NONE: 5267 break; 5268 5269 case SCF_ERROR_NO_MEMORY: 5270 return (ENOMEM); 5271 5272 case SCF_ERROR_NOT_FOUND: 5273 warn(emsg_dpt_dangling, ient->sc_fmri, 5274 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5275 return (0); 5276 5277 case SCF_ERROR_CONSTRAINT_VIOLATED: 5278 case SCF_ERROR_INVALID_ARGUMENT: 5279 default: 5280 bad_error("fmri_to_entity", scfe); 5281 } 5282 5283 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 5284 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 5285 switch (r) { 5286 case 0: 5287 break; 5288 5289 case ECONNABORTED: 5290 return (r); 5291 5292 case ECANCELED: 5293 warn(emsg_dpt_dangling, ient->sc_fmri, 5294 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5295 return (0); 5296 5297 case EBADF: 5298 if (tissvc) 5299 warn(gettext("%s has an instance with a \"%s\" " 5300 "snapshot which is missing a snaplevel.\n"), 5301 ud_ctarg, "running"); 5302 else 5303 warn(gettext("%s has a \"%s\" snapshot which is " 5304 "missing a snaplevel.\n"), ud_ctarg, "running"); 5305 /* FALLTHROUGH */ 5306 5307 case ENOENT: 5308 warn(emsg_dpt_no_dep, ient->sc_fmri, 5309 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5310 new_dpt_pgroup->sc_pgroup_name); 5311 return (0); 5312 5313 case EINVAL: 5314 default: 5315 bad_error("entity_get_running_pg", r); 5316 } 5317 5318 pgroup = internal_pgroup_new(); 5319 if (pgroup == NULL) 5320 return (ENOMEM); 5321 5322 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 5323 switch (r) { 5324 case 0: 5325 break; 5326 5327 case ECONNABORTED: 5328 case EBADF: 5329 case ENOMEM: 5330 internal_pgroup_free(pgroup); 5331 return (r); 5332 5333 case ECANCELED: 5334 warn(emsg_dpt_no_dep, ient->sc_fmri, 5335 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5336 new_dpt_pgroup->sc_pgroup_name); 5337 internal_pgroup_free(pgroup); 5338 return (0); 5339 5340 case EACCES: 5341 default: 5342 bad_error("load_pg", r); 5343 } 5344 5345 /* report differences */ 5346 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 5347 internal_pgroup_free(pgroup); 5348 return (0); 5349 } 5350 5351 /* 5352 * lipg is a property group in the last-import snapshot of ent, which is an 5353 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 5354 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 5355 * in ents's property groups, compare and upgrade ent appropriately. 5356 * 5357 * Returns 5358 * 0 - success 5359 * ECONNABORTED - repository connection broken 5360 * ENOMEM - out of memory 5361 * ENOSPC - configd is out of resources 5362 * EINVAL - ient has invalid dependent (error printed) 5363 * - ient has invalid pgroup_t (error printed) 5364 * ECANCELED - ent has been deleted 5365 * ENODEV - entity containing lipg has been deleted 5366 * - entity containing running has been deleted 5367 * EPERM - could not delete pg (permission denied) (error printed) 5368 * - couldn't upgrade dependents (permission denied) (error printed) 5369 * - couldn't import pg (permission denied) (error printed) 5370 * - couldn't upgrade pg (permission denied) (error printed) 5371 * EROFS - could not delete pg (repository read-only) 5372 * - couldn't upgrade dependents (repository read-only) 5373 * - couldn't import pg (repository read-only) 5374 * - couldn't upgrade pg (repository read-only) 5375 * EACCES - could not delete pg (backend access denied) 5376 * - couldn't upgrade dependents (backend access denied) 5377 * - couldn't import pg (backend access denied) 5378 * - couldn't upgrade pg (backend access denied) 5379 * - couldn't read property (backend access denied) 5380 * EBUSY - property group was added (error printed) 5381 * - property group was deleted (error printed) 5382 * - property group changed (error printed) 5383 * - "dependents" pg was added, changed, or deleted (error printed) 5384 * - dependent target deleted (error printed) 5385 * - dependent pg changed (error printed) 5386 * EBADF - imp_snpl is corrupt (error printed) 5387 * - ent has bad pg (error printed) 5388 * EEXIST - dependent collision in target service (error printed) 5389 */ 5390 static int 5391 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 5392 const scf_snaplevel_t *running) 5393 { 5394 int r; 5395 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 5396 scf_callback_t cbdata; 5397 5398 const char * const cf_pg_missing = 5399 gettext("Conflict upgrading %s (property group %s is missing)\n"); 5400 const char * const deleting = 5401 gettext("%s: Deleting property group \"%s\".\n"); 5402 5403 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5404 5405 /* Skip dependent property groups. */ 5406 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 5407 switch (scf_error()) { 5408 case SCF_ERROR_DELETED: 5409 return (ENODEV); 5410 5411 case SCF_ERROR_CONNECTION_BROKEN: 5412 return (ECONNABORTED); 5413 5414 case SCF_ERROR_NOT_SET: 5415 case SCF_ERROR_NOT_BOUND: 5416 default: 5417 bad_error("scf_pg_get_type", scf_error()); 5418 } 5419 } 5420 5421 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 5422 if (scf_pg_get_property(lipg, "external", NULL) == 0) 5423 return (0); 5424 5425 switch (scf_error()) { 5426 case SCF_ERROR_NOT_FOUND: 5427 break; 5428 5429 case SCF_ERROR_CONNECTION_BROKEN: 5430 return (ECONNABORTED); 5431 5432 case SCF_ERROR_DELETED: 5433 return (ENODEV); 5434 5435 case SCF_ERROR_INVALID_ARGUMENT: 5436 case SCF_ERROR_NOT_BOUND: 5437 case SCF_ERROR_HANDLE_MISMATCH: 5438 case SCF_ERROR_NOT_SET: 5439 default: 5440 bad_error("scf_pg_get_property", scf_error()); 5441 } 5442 } 5443 5444 /* lookup pg in new properties */ 5445 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 5446 switch (scf_error()) { 5447 case SCF_ERROR_DELETED: 5448 return (ENODEV); 5449 5450 case SCF_ERROR_CONNECTION_BROKEN: 5451 return (ECONNABORTED); 5452 5453 case SCF_ERROR_NOT_SET: 5454 case SCF_ERROR_NOT_BOUND: 5455 default: 5456 bad_error("scf_pg_get_name", scf_error()); 5457 } 5458 } 5459 5460 pgrp.sc_pgroup_name = imp_str; 5461 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 5462 5463 if (mpg != NULL) 5464 mpg->sc_pgroup_seen = 1; 5465 5466 /* Special handling for dependents */ 5467 if (strcmp(imp_str, "dependents") == 0) 5468 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 5469 5470 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 5471 return (upgrade_manifestfiles(NULL, ient, running, ent)); 5472 5473 if (mpg == NULL || mpg->sc_pgroup_delete) { 5474 /* property group was deleted from manifest */ 5475 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5476 switch (scf_error()) { 5477 case SCF_ERROR_NOT_FOUND: 5478 return (0); 5479 5480 case SCF_ERROR_DELETED: 5481 case SCF_ERROR_CONNECTION_BROKEN: 5482 return (scferror2errno(scf_error())); 5483 5484 case SCF_ERROR_INVALID_ARGUMENT: 5485 case SCF_ERROR_HANDLE_MISMATCH: 5486 case SCF_ERROR_NOT_BOUND: 5487 case SCF_ERROR_NOT_SET: 5488 default: 5489 bad_error("entity_get_pg", scf_error()); 5490 } 5491 } 5492 5493 if (mpg != NULL && mpg->sc_pgroup_delete) { 5494 if (g_verbose) 5495 warn(deleting, ient->sc_fmri, imp_str); 5496 if (scf_pg_delete(imp_pg2) == 0) 5497 return (0); 5498 5499 switch (scf_error()) { 5500 case SCF_ERROR_DELETED: 5501 return (0); 5502 5503 case SCF_ERROR_CONNECTION_BROKEN: 5504 case SCF_ERROR_BACKEND_READONLY: 5505 case SCF_ERROR_BACKEND_ACCESS: 5506 return (scferror2errno(scf_error())); 5507 5508 case SCF_ERROR_PERMISSION_DENIED: 5509 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 5510 return (scferror2errno(scf_error())); 5511 5512 case SCF_ERROR_NOT_SET: 5513 default: 5514 bad_error("scf_pg_delete", scf_error()); 5515 } 5516 } 5517 5518 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5519 switch (r) { 5520 case 0: 5521 break; 5522 5523 case ECANCELED: 5524 return (ENODEV); 5525 5526 case ECONNABORTED: 5527 case ENOMEM: 5528 case EBADF: 5529 case EACCES: 5530 return (r); 5531 5532 default: 5533 bad_error("load_pg", r); 5534 } 5535 5536 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5537 switch (r) { 5538 case 0: 5539 break; 5540 5541 case ECANCELED: 5542 case ECONNABORTED: 5543 case ENOMEM: 5544 case EBADF: 5545 case EACCES: 5546 internal_pgroup_free(lipg_i); 5547 return (r); 5548 5549 default: 5550 bad_error("load_pg", r); 5551 } 5552 5553 if (pg_equal(lipg_i, curpg_i)) { 5554 if (g_verbose) 5555 warn(deleting, ient->sc_fmri, imp_str); 5556 if (scf_pg_delete(imp_pg2) != 0) { 5557 switch (scf_error()) { 5558 case SCF_ERROR_DELETED: 5559 break; 5560 5561 case SCF_ERROR_CONNECTION_BROKEN: 5562 internal_pgroup_free(lipg_i); 5563 internal_pgroup_free(curpg_i); 5564 return (ECONNABORTED); 5565 5566 case SCF_ERROR_NOT_SET: 5567 case SCF_ERROR_NOT_BOUND: 5568 default: 5569 bad_error("scf_pg_delete", scf_error()); 5570 } 5571 } 5572 } else { 5573 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5574 } 5575 5576 internal_pgroup_free(lipg_i); 5577 internal_pgroup_free(curpg_i); 5578 5579 return (0); 5580 } 5581 5582 /* 5583 * Only dependent pgs can have override set, and we skipped those 5584 * above. 5585 */ 5586 assert(!mpg->sc_pgroup_override); 5587 5588 /* compare */ 5589 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5590 switch (r) { 5591 case 0: 5592 break; 5593 5594 case ECANCELED: 5595 return (ENODEV); 5596 5597 case ECONNABORTED: 5598 case EBADF: 5599 case ENOMEM: 5600 case EACCES: 5601 return (r); 5602 5603 default: 5604 bad_error("load_pg", r); 5605 } 5606 5607 if (pg_equal(mpg, lipg_i)) { 5608 /* The manifest pg has not changed. Move on. */ 5609 r = 0; 5610 goto out; 5611 } 5612 5613 /* upgrade current properties according to lipg & mpg */ 5614 if (running != NULL) 5615 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5616 else 5617 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5618 if (r != 0) { 5619 switch (scf_error()) { 5620 case SCF_ERROR_CONNECTION_BROKEN: 5621 r = scferror2errno(scf_error()); 5622 goto out; 5623 5624 case SCF_ERROR_DELETED: 5625 if (running != NULL) 5626 r = ENODEV; 5627 else 5628 r = ECANCELED; 5629 goto out; 5630 5631 case SCF_ERROR_NOT_FOUND: 5632 break; 5633 5634 case SCF_ERROR_INVALID_ARGUMENT: 5635 case SCF_ERROR_HANDLE_MISMATCH: 5636 case SCF_ERROR_NOT_BOUND: 5637 case SCF_ERROR_NOT_SET: 5638 default: 5639 bad_error("entity_get_pg", scf_error()); 5640 } 5641 5642 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5643 5644 r = 0; 5645 goto out; 5646 } 5647 5648 r = load_pg_attrs(imp_pg2, &curpg_i); 5649 switch (r) { 5650 case 0: 5651 break; 5652 5653 case ECANCELED: 5654 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5655 r = 0; 5656 goto out; 5657 5658 case ECONNABORTED: 5659 case ENOMEM: 5660 goto out; 5661 5662 default: 5663 bad_error("load_pg_attrs", r); 5664 } 5665 5666 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5667 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5668 internal_pgroup_free(curpg_i); 5669 r = 0; 5670 goto out; 5671 } 5672 5673 internal_pgroup_free(curpg_i); 5674 5675 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5676 switch (r) { 5677 case 0: 5678 break; 5679 5680 case ECANCELED: 5681 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5682 r = 0; 5683 goto out; 5684 5685 case ECONNABORTED: 5686 case EBADF: 5687 case ENOMEM: 5688 case EACCES: 5689 goto out; 5690 5691 default: 5692 bad_error("load_pg", r); 5693 } 5694 5695 if (pg_equal(lipg_i, curpg_i) && 5696 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5697 int do_delete = 1; 5698 5699 if (g_verbose) 5700 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5701 ient->sc_fmri, mpg->sc_pgroup_name); 5702 5703 internal_pgroup_free(curpg_i); 5704 5705 if (running != NULL && 5706 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5707 switch (scf_error()) { 5708 case SCF_ERROR_DELETED: 5709 r = ECANCELED; 5710 goto out; 5711 5712 case SCF_ERROR_NOT_FOUND: 5713 do_delete = 0; 5714 break; 5715 5716 case SCF_ERROR_CONNECTION_BROKEN: 5717 r = scferror2errno(scf_error()); 5718 goto out; 5719 5720 case SCF_ERROR_HANDLE_MISMATCH: 5721 case SCF_ERROR_INVALID_ARGUMENT: 5722 case SCF_ERROR_NOT_SET: 5723 case SCF_ERROR_NOT_BOUND: 5724 default: 5725 bad_error("entity_get_pg", scf_error()); 5726 } 5727 } 5728 5729 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5730 switch (scf_error()) { 5731 case SCF_ERROR_DELETED: 5732 break; 5733 5734 case SCF_ERROR_CONNECTION_BROKEN: 5735 case SCF_ERROR_BACKEND_READONLY: 5736 case SCF_ERROR_BACKEND_ACCESS: 5737 r = scferror2errno(scf_error()); 5738 goto out; 5739 5740 case SCF_ERROR_PERMISSION_DENIED: 5741 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5742 ient->sc_fmri); 5743 r = scferror2errno(scf_error()); 5744 goto out; 5745 5746 case SCF_ERROR_NOT_SET: 5747 case SCF_ERROR_NOT_BOUND: 5748 default: 5749 bad_error("scf_pg_delete", scf_error()); 5750 } 5751 } 5752 5753 cbdata.sc_handle = g_hndl; 5754 cbdata.sc_parent = ent; 5755 cbdata.sc_service = issvc; 5756 cbdata.sc_flags = 0; 5757 cbdata.sc_source_fmri = ient->sc_fmri; 5758 cbdata.sc_target_fmri = ient->sc_fmri; 5759 5760 r = entity_pgroup_import(mpg, &cbdata); 5761 switch (r) { 5762 case UU_WALK_NEXT: 5763 r = 0; 5764 goto out; 5765 5766 case UU_WALK_ERROR: 5767 if (cbdata.sc_err == EEXIST) { 5768 warn(emsg_pg_added, ient->sc_fmri, 5769 mpg->sc_pgroup_name); 5770 r = EBUSY; 5771 } else { 5772 r = cbdata.sc_err; 5773 } 5774 goto out; 5775 5776 default: 5777 bad_error("entity_pgroup_import", r); 5778 } 5779 } 5780 5781 if (running != NULL && 5782 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5783 switch (scf_error()) { 5784 case SCF_ERROR_CONNECTION_BROKEN: 5785 case SCF_ERROR_DELETED: 5786 r = scferror2errno(scf_error()); 5787 goto out; 5788 5789 case SCF_ERROR_NOT_FOUND: 5790 break; 5791 5792 case SCF_ERROR_HANDLE_MISMATCH: 5793 case SCF_ERROR_INVALID_ARGUMENT: 5794 case SCF_ERROR_NOT_SET: 5795 case SCF_ERROR_NOT_BOUND: 5796 default: 5797 bad_error("entity_get_pg", scf_error()); 5798 } 5799 5800 cbdata.sc_handle = g_hndl; 5801 cbdata.sc_parent = ent; 5802 cbdata.sc_service = issvc; 5803 cbdata.sc_flags = SCI_FORCE; 5804 cbdata.sc_source_fmri = ient->sc_fmri; 5805 cbdata.sc_target_fmri = ient->sc_fmri; 5806 5807 r = entity_pgroup_import(mpg, &cbdata); 5808 switch (r) { 5809 case UU_WALK_NEXT: 5810 r = 0; 5811 goto out; 5812 5813 case UU_WALK_ERROR: 5814 if (cbdata.sc_err == EEXIST) { 5815 warn(emsg_pg_added, ient->sc_fmri, 5816 mpg->sc_pgroup_name); 5817 r = EBUSY; 5818 } else { 5819 r = cbdata.sc_err; 5820 } 5821 goto out; 5822 5823 default: 5824 bad_error("entity_pgroup_import", r); 5825 } 5826 } 5827 5828 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5829 internal_pgroup_free(curpg_i); 5830 switch (r) { 5831 case 0: 5832 ient->sc_import_state = IMPORT_PROP_BEGUN; 5833 break; 5834 5835 case ECANCELED: 5836 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5837 r = EBUSY; 5838 break; 5839 5840 case EPERM: 5841 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5842 break; 5843 5844 case EBUSY: 5845 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5846 break; 5847 5848 case ECONNABORTED: 5849 case ENOMEM: 5850 case ENOSPC: 5851 case EROFS: 5852 case EACCES: 5853 case EINVAL: 5854 break; 5855 5856 default: 5857 bad_error("upgrade_pg", r); 5858 } 5859 5860 out: 5861 internal_pgroup_free(lipg_i); 5862 return (r); 5863 } 5864 5865 /* 5866 * Upgrade the properties of ent according to snpl & ient. 5867 * 5868 * Returns 5869 * 0 - success 5870 * ECONNABORTED - repository connection broken 5871 * ENOMEM - out of memory 5872 * ENOSPC - configd is out of resources 5873 * ECANCELED - ent was deleted 5874 * ENODEV - entity containing snpl was deleted 5875 * - entity containing running was deleted 5876 * EBADF - imp_snpl is corrupt (error printed) 5877 * - ent has corrupt pg (error printed) 5878 * - dependent has corrupt pg (error printed) 5879 * - dependent target has a corrupt snapshot (error printed) 5880 * EBUSY - pg was added, changed, or deleted (error printed) 5881 * - dependent target was deleted (error printed) 5882 * - dependent pg changed (error printed) 5883 * EINVAL - invalid property group name (error printed) 5884 * - invalid property name (error printed) 5885 * - invalid value (error printed) 5886 * - ient has invalid pgroup or dependent (error printed) 5887 * EPERM - could not create property group (permission denied) (error printed) 5888 * - could not modify property group (permission denied) (error printed) 5889 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5890 * EROFS - could not create property group (repository read-only) 5891 * - couldn't delete, upgrade, or import pg or dependent 5892 * EACCES - could not create property group (backend access denied) 5893 * - couldn't delete, upgrade, or import pg or dependent 5894 * EEXIST - dependent collision in target service (error printed) 5895 */ 5896 static int 5897 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5898 entity_t *ient) 5899 { 5900 pgroup_t *pg, *rpg; 5901 int r; 5902 uu_list_t *pgs = ient->sc_pgroups; 5903 5904 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5905 5906 /* clear sc_sceen for pgs */ 5907 if (uu_list_walk(pgs, clear_int, 5908 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5909 bad_error("uu_list_walk", uu_error()); 5910 5911 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5912 switch (scf_error()) { 5913 case SCF_ERROR_DELETED: 5914 return (ENODEV); 5915 5916 case SCF_ERROR_CONNECTION_BROKEN: 5917 return (ECONNABORTED); 5918 5919 case SCF_ERROR_NOT_SET: 5920 case SCF_ERROR_NOT_BOUND: 5921 case SCF_ERROR_HANDLE_MISMATCH: 5922 default: 5923 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5924 } 5925 } 5926 5927 for (;;) { 5928 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5929 if (r == 0) 5930 break; 5931 if (r == 1) { 5932 r = process_old_pg(imp_pg, ient, ent, running); 5933 switch (r) { 5934 case 0: 5935 break; 5936 5937 case ECONNABORTED: 5938 case ENOMEM: 5939 case ENOSPC: 5940 case ECANCELED: 5941 case ENODEV: 5942 case EPERM: 5943 case EROFS: 5944 case EACCES: 5945 case EBADF: 5946 case EBUSY: 5947 case EINVAL: 5948 case EEXIST: 5949 return (r); 5950 5951 default: 5952 bad_error("process_old_pg", r); 5953 } 5954 continue; 5955 } 5956 if (r != -1) 5957 bad_error("scf_iter_next_pg", r); 5958 5959 switch (scf_error()) { 5960 case SCF_ERROR_DELETED: 5961 return (ENODEV); 5962 5963 case SCF_ERROR_CONNECTION_BROKEN: 5964 return (ECONNABORTED); 5965 5966 case SCF_ERROR_HANDLE_MISMATCH: 5967 case SCF_ERROR_NOT_BOUND: 5968 case SCF_ERROR_NOT_SET: 5969 case SCF_ERROR_INVALID_ARGUMENT: 5970 default: 5971 bad_error("scf_iter_next_pg", scf_error()); 5972 } 5973 } 5974 5975 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5976 if (pg->sc_pgroup_seen) 5977 continue; 5978 5979 /* pg is new */ 5980 5981 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5982 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5983 ent); 5984 switch (r) { 5985 case 0: 5986 break; 5987 5988 case ECONNABORTED: 5989 case ENOMEM: 5990 case ENOSPC: 5991 case ECANCELED: 5992 case ENODEV: 5993 case EBADF: 5994 case EBUSY: 5995 case EINVAL: 5996 case EPERM: 5997 case EROFS: 5998 case EACCES: 5999 case EEXIST: 6000 return (r); 6001 6002 default: 6003 bad_error("upgrade_dependents", r); 6004 } 6005 continue; 6006 } 6007 6008 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 6009 r = upgrade_manifestfiles(pg, ient, running, ent); 6010 switch (r) { 6011 case 0: 6012 break; 6013 6014 case ECONNABORTED: 6015 case ENOMEM: 6016 case ENOSPC: 6017 case ECANCELED: 6018 case ENODEV: 6019 case EBADF: 6020 case EBUSY: 6021 case EINVAL: 6022 case EPERM: 6023 case EROFS: 6024 case EACCES: 6025 case EEXIST: 6026 return (r); 6027 6028 default: 6029 bad_error("upgrade_manifestfiles", r); 6030 } 6031 continue; 6032 } 6033 6034 if (running != NULL) { 6035 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 6036 imp_pg); 6037 } else { 6038 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 6039 imp_pg); 6040 } 6041 if (r != 0) { 6042 scf_callback_t cbdata; 6043 6044 switch (scf_error()) { 6045 case SCF_ERROR_NOT_FOUND: 6046 break; 6047 6048 case SCF_ERROR_CONNECTION_BROKEN: 6049 return (scferror2errno(scf_error())); 6050 6051 case SCF_ERROR_DELETED: 6052 if (running != NULL) 6053 return (ENODEV); 6054 else 6055 return (scferror2errno(scf_error())); 6056 6057 case SCF_ERROR_INVALID_ARGUMENT: 6058 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 6059 pg->sc_pgroup_name); 6060 return (EINVAL); 6061 6062 case SCF_ERROR_NOT_SET: 6063 case SCF_ERROR_HANDLE_MISMATCH: 6064 case SCF_ERROR_NOT_BOUND: 6065 default: 6066 bad_error("entity_get_pg", scf_error()); 6067 } 6068 6069 /* User doesn't have pg, so import it. */ 6070 6071 cbdata.sc_handle = g_hndl; 6072 cbdata.sc_parent = ent; 6073 cbdata.sc_service = issvc; 6074 cbdata.sc_flags = SCI_FORCE; 6075 cbdata.sc_source_fmri = ient->sc_fmri; 6076 cbdata.sc_target_fmri = ient->sc_fmri; 6077 6078 r = entity_pgroup_import(pg, &cbdata); 6079 switch (r) { 6080 case UU_WALK_NEXT: 6081 ient->sc_import_state = IMPORT_PROP_BEGUN; 6082 continue; 6083 6084 case UU_WALK_ERROR: 6085 if (cbdata.sc_err == EEXIST) { 6086 warn(emsg_pg_added, ient->sc_fmri, 6087 pg->sc_pgroup_name); 6088 return (EBUSY); 6089 } 6090 return (cbdata.sc_err); 6091 6092 default: 6093 bad_error("entity_pgroup_import", r); 6094 } 6095 } 6096 6097 /* report differences between pg & current */ 6098 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 6099 switch (r) { 6100 case 0: 6101 break; 6102 6103 case ECANCELED: 6104 warn(emsg_pg_deleted, ient->sc_fmri, 6105 pg->sc_pgroup_name); 6106 return (EBUSY); 6107 6108 case ECONNABORTED: 6109 case EBADF: 6110 case ENOMEM: 6111 case EACCES: 6112 return (r); 6113 6114 default: 6115 bad_error("load_pg", r); 6116 } 6117 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 6118 internal_pgroup_free(rpg); 6119 rpg = NULL; 6120 } 6121 6122 return (0); 6123 } 6124 6125 /* 6126 * Import an instance. If it doesn't exist, create it. If it has 6127 * a last-import snapshot, upgrade its properties. Finish by updating its 6128 * last-import snapshot. If it doesn't have a last-import snapshot then it 6129 * could have been created for a dependent tag in another manifest. Import the 6130 * new properties. If there's a conflict, don't override, like now? 6131 * 6132 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 6133 * lcbdata->sc_err to 6134 * ECONNABORTED - repository connection broken 6135 * ENOMEM - out of memory 6136 * ENOSPC - svc.configd is out of resources 6137 * EEXIST - dependency collision in dependent service (error printed) 6138 * EPERM - couldn't create temporary instance (permission denied) 6139 * - couldn't import into temporary instance (permission denied) 6140 * - couldn't take snapshot (permission denied) 6141 * - couldn't upgrade properties (permission denied) 6142 * - couldn't import properties (permission denied) 6143 * - couldn't import dependents (permission denied) 6144 * EROFS - couldn't create temporary instance (repository read-only) 6145 * - couldn't import into temporary instance (repository read-only) 6146 * - couldn't upgrade properties (repository read-only) 6147 * - couldn't import properties (repository read-only) 6148 * - couldn't import dependents (repository read-only) 6149 * EACCES - couldn't create temporary instance (backend access denied) 6150 * - couldn't import into temporary instance (backend access denied) 6151 * - couldn't upgrade properties (backend access denied) 6152 * - couldn't import properties (backend access denied) 6153 * - couldn't import dependents (backend access denied) 6154 * EINVAL - invalid instance name (error printed) 6155 * - invalid pgroup_t's (error printed) 6156 * - invalid dependents (error printed) 6157 * EBUSY - temporary service deleted (error printed) 6158 * - temporary instance deleted (error printed) 6159 * - temporary instance changed (error printed) 6160 * - temporary instance already exists (error printed) 6161 * - instance deleted (error printed) 6162 * EBADF - instance has corrupt last-import snapshot (error printed) 6163 * - instance is corrupt (error printed) 6164 * - dependent has corrupt pg (error printed) 6165 * - dependent target has a corrupt snapshot (error printed) 6166 * -1 - unknown libscf error (error printed) 6167 */ 6168 static int 6169 lscf_instance_import(void *v, void *pvt) 6170 { 6171 entity_t *inst = v; 6172 scf_callback_t ctx; 6173 scf_callback_t *lcbdata = pvt; 6174 scf_service_t *rsvc = lcbdata->sc_parent; 6175 int r; 6176 scf_snaplevel_t *running; 6177 int flags = lcbdata->sc_flags; 6178 6179 const char * const emsg_tdel = 6180 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 6181 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 6182 "changed unexpectedly.\n"); 6183 const char * const emsg_del = gettext("%s changed unexpectedly " 6184 "(instance \"%s\" was deleted.)\n"); 6185 const char * const emsg_badsnap = gettext( 6186 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 6187 6188 /* 6189 * prepare last-import snapshot: 6190 * create temporary instance (service was precreated) 6191 * populate with properties from bundle 6192 * take snapshot 6193 */ 6194 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 6195 switch (scf_error()) { 6196 case SCF_ERROR_CONNECTION_BROKEN: 6197 case SCF_ERROR_NO_RESOURCES: 6198 case SCF_ERROR_BACKEND_READONLY: 6199 case SCF_ERROR_BACKEND_ACCESS: 6200 return (stash_scferror(lcbdata)); 6201 6202 case SCF_ERROR_EXISTS: 6203 warn(gettext("Temporary service svc:/%s " 6204 "changed unexpectedly (instance \"%s\" added).\n"), 6205 imp_tsname, inst->sc_name); 6206 lcbdata->sc_err = EBUSY; 6207 return (UU_WALK_ERROR); 6208 6209 case SCF_ERROR_DELETED: 6210 warn(gettext("Temporary service svc:/%s " 6211 "was deleted unexpectedly.\n"), imp_tsname); 6212 lcbdata->sc_err = EBUSY; 6213 return (UU_WALK_ERROR); 6214 6215 case SCF_ERROR_INVALID_ARGUMENT: 6216 warn(gettext("Invalid instance name \"%s\".\n"), 6217 inst->sc_name); 6218 return (stash_scferror(lcbdata)); 6219 6220 case SCF_ERROR_PERMISSION_DENIED: 6221 warn(gettext("Could not create temporary instance " 6222 "\"%s\" in svc:/%s (permission denied).\n"), 6223 inst->sc_name, imp_tsname); 6224 return (stash_scferror(lcbdata)); 6225 6226 case SCF_ERROR_HANDLE_MISMATCH: 6227 case SCF_ERROR_NOT_BOUND: 6228 case SCF_ERROR_NOT_SET: 6229 default: 6230 bad_error("scf_service_add_instance", scf_error()); 6231 } 6232 } 6233 6234 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6235 inst->sc_name); 6236 if (r < 0) 6237 bad_error("snprintf", errno); 6238 6239 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 6240 lcbdata->sc_flags | SCI_NOENABLED); 6241 switch (r) { 6242 case 0: 6243 break; 6244 6245 case ECANCELED: 6246 warn(emsg_tdel, imp_tsname, inst->sc_name); 6247 lcbdata->sc_err = EBUSY; 6248 r = UU_WALK_ERROR; 6249 goto deltemp; 6250 6251 case EEXIST: 6252 warn(emsg_tchg, imp_tsname, inst->sc_name); 6253 lcbdata->sc_err = EBUSY; 6254 r = UU_WALK_ERROR; 6255 goto deltemp; 6256 6257 case ECONNABORTED: 6258 goto connaborted; 6259 6260 case ENOMEM: 6261 case ENOSPC: 6262 case EPERM: 6263 case EROFS: 6264 case EACCES: 6265 case EINVAL: 6266 case EBUSY: 6267 lcbdata->sc_err = r; 6268 r = UU_WALK_ERROR; 6269 goto deltemp; 6270 6271 default: 6272 bad_error("lscf_import_instance_pgs", r); 6273 } 6274 6275 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6276 inst->sc_name); 6277 if (r < 0) 6278 bad_error("snprintf", errno); 6279 6280 ctx.sc_handle = lcbdata->sc_handle; 6281 ctx.sc_parent = imp_tinst; 6282 ctx.sc_service = 0; 6283 ctx.sc_source_fmri = inst->sc_fmri; 6284 ctx.sc_target_fmri = imp_str; 6285 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 6286 UU_DEFAULT) != 0) { 6287 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6288 bad_error("uu_list_walk", uu_error()); 6289 6290 switch (ctx.sc_err) { 6291 case ECONNABORTED: 6292 goto connaborted; 6293 6294 case ECANCELED: 6295 warn(emsg_tdel, imp_tsname, inst->sc_name); 6296 lcbdata->sc_err = EBUSY; 6297 break; 6298 6299 case EEXIST: 6300 warn(emsg_tchg, imp_tsname, inst->sc_name); 6301 lcbdata->sc_err = EBUSY; 6302 break; 6303 6304 default: 6305 lcbdata->sc_err = ctx.sc_err; 6306 } 6307 r = UU_WALK_ERROR; 6308 goto deltemp; 6309 } 6310 6311 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 6312 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 6313 switch (scf_error()) { 6314 case SCF_ERROR_CONNECTION_BROKEN: 6315 goto connaborted; 6316 6317 case SCF_ERROR_NO_RESOURCES: 6318 r = stash_scferror(lcbdata); 6319 goto deltemp; 6320 6321 case SCF_ERROR_EXISTS: 6322 warn(emsg_tchg, imp_tsname, inst->sc_name); 6323 lcbdata->sc_err = EBUSY; 6324 r = UU_WALK_ERROR; 6325 goto deltemp; 6326 6327 case SCF_ERROR_PERMISSION_DENIED: 6328 warn(gettext("Could not take \"%s\" snapshot of %s " 6329 "(permission denied).\n"), snap_lastimport, 6330 imp_str); 6331 r = stash_scferror(lcbdata); 6332 goto deltemp; 6333 6334 default: 6335 scfwarn(); 6336 lcbdata->sc_err = -1; 6337 r = UU_WALK_ERROR; 6338 goto deltemp; 6339 6340 case SCF_ERROR_HANDLE_MISMATCH: 6341 case SCF_ERROR_INVALID_ARGUMENT: 6342 case SCF_ERROR_NOT_SET: 6343 bad_error("_scf_snapshot_take_new_named", scf_error()); 6344 } 6345 } 6346 6347 if (lcbdata->sc_flags & SCI_FRESH) 6348 goto fresh; 6349 6350 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 6351 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6352 imp_lisnap) != 0) { 6353 switch (scf_error()) { 6354 case SCF_ERROR_DELETED: 6355 warn(emsg_del, inst->sc_parent->sc_fmri, 6356 inst->sc_name); 6357 lcbdata->sc_err = EBUSY; 6358 r = UU_WALK_ERROR; 6359 goto deltemp; 6360 6361 case SCF_ERROR_NOT_FOUND: 6362 flags |= SCI_FORCE; 6363 goto nosnap; 6364 6365 case SCF_ERROR_CONNECTION_BROKEN: 6366 goto connaborted; 6367 6368 case SCF_ERROR_INVALID_ARGUMENT: 6369 case SCF_ERROR_HANDLE_MISMATCH: 6370 case SCF_ERROR_NOT_BOUND: 6371 case SCF_ERROR_NOT_SET: 6372 default: 6373 bad_error("scf_instance_get_snapshot", 6374 scf_error()); 6375 } 6376 } 6377 6378 /* upgrade */ 6379 6380 /* 6381 * compare new properties with last-import properties 6382 * upgrade current properties 6383 */ 6384 /* clear sc_sceen for pgs */ 6385 if (uu_list_walk(inst->sc_pgroups, clear_int, 6386 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 6387 0) 6388 bad_error("uu_list_walk", uu_error()); 6389 6390 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 6391 switch (r) { 6392 case 0: 6393 break; 6394 6395 case ECONNABORTED: 6396 goto connaborted; 6397 6398 case ECANCELED: 6399 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6400 lcbdata->sc_err = EBUSY; 6401 r = UU_WALK_ERROR; 6402 goto deltemp; 6403 6404 case ENOENT: 6405 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 6406 lcbdata->sc_err = EBADF; 6407 r = UU_WALK_ERROR; 6408 goto deltemp; 6409 6410 default: 6411 bad_error("get_snaplevel", r); 6412 } 6413 6414 if (scf_instance_get_snapshot(imp_inst, snap_running, 6415 imp_rsnap) != 0) { 6416 switch (scf_error()) { 6417 case SCF_ERROR_DELETED: 6418 warn(emsg_del, inst->sc_parent->sc_fmri, 6419 inst->sc_name); 6420 lcbdata->sc_err = EBUSY; 6421 r = UU_WALK_ERROR; 6422 goto deltemp; 6423 6424 case SCF_ERROR_NOT_FOUND: 6425 break; 6426 6427 case SCF_ERROR_CONNECTION_BROKEN: 6428 goto connaborted; 6429 6430 case SCF_ERROR_INVALID_ARGUMENT: 6431 case SCF_ERROR_HANDLE_MISMATCH: 6432 case SCF_ERROR_NOT_BOUND: 6433 case SCF_ERROR_NOT_SET: 6434 default: 6435 bad_error("scf_instance_get_snapshot", 6436 scf_error()); 6437 } 6438 6439 running = NULL; 6440 } else { 6441 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 6442 switch (r) { 6443 case 0: 6444 running = imp_rsnpl; 6445 break; 6446 6447 case ECONNABORTED: 6448 goto connaborted; 6449 6450 case ECANCELED: 6451 warn(emsg_del, inst->sc_parent->sc_fmri, 6452 inst->sc_name); 6453 lcbdata->sc_err = EBUSY; 6454 r = UU_WALK_ERROR; 6455 goto deltemp; 6456 6457 case ENOENT: 6458 warn(emsg_badsnap, snap_running, inst->sc_fmri); 6459 lcbdata->sc_err = EBADF; 6460 r = UU_WALK_ERROR; 6461 goto deltemp; 6462 6463 default: 6464 bad_error("get_snaplevel", r); 6465 } 6466 } 6467 6468 r = upgrade_props(imp_inst, running, imp_snpl, inst); 6469 switch (r) { 6470 case 0: 6471 break; 6472 6473 case ECANCELED: 6474 case ENODEV: 6475 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6476 lcbdata->sc_err = EBUSY; 6477 r = UU_WALK_ERROR; 6478 goto deltemp; 6479 6480 case ECONNABORTED: 6481 goto connaborted; 6482 6483 case ENOMEM: 6484 case ENOSPC: 6485 case EBADF: 6486 case EBUSY: 6487 case EINVAL: 6488 case EPERM: 6489 case EROFS: 6490 case EACCES: 6491 case EEXIST: 6492 lcbdata->sc_err = r; 6493 r = UU_WALK_ERROR; 6494 goto deltemp; 6495 6496 default: 6497 bad_error("upgrade_props", r); 6498 } 6499 6500 inst->sc_import_state = IMPORT_PROP_DONE; 6501 } else { 6502 switch (scf_error()) { 6503 case SCF_ERROR_CONNECTION_BROKEN: 6504 goto connaborted; 6505 6506 case SCF_ERROR_NOT_FOUND: 6507 break; 6508 6509 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6510 case SCF_ERROR_HANDLE_MISMATCH: 6511 case SCF_ERROR_NOT_BOUND: 6512 case SCF_ERROR_NOT_SET: 6513 default: 6514 bad_error("scf_service_get_instance", scf_error()); 6515 } 6516 6517 fresh: 6518 /* create instance */ 6519 if (scf_service_add_instance(rsvc, inst->sc_name, 6520 imp_inst) != 0) { 6521 switch (scf_error()) { 6522 case SCF_ERROR_CONNECTION_BROKEN: 6523 goto connaborted; 6524 6525 case SCF_ERROR_NO_RESOURCES: 6526 case SCF_ERROR_BACKEND_READONLY: 6527 case SCF_ERROR_BACKEND_ACCESS: 6528 r = stash_scferror(lcbdata); 6529 goto deltemp; 6530 6531 case SCF_ERROR_EXISTS: 6532 warn(gettext("%s changed unexpectedly " 6533 "(instance \"%s\" added).\n"), 6534 inst->sc_parent->sc_fmri, inst->sc_name); 6535 lcbdata->sc_err = EBUSY; 6536 r = UU_WALK_ERROR; 6537 goto deltemp; 6538 6539 case SCF_ERROR_PERMISSION_DENIED: 6540 warn(gettext("Could not create \"%s\" instance " 6541 "in %s (permission denied).\n"), 6542 inst->sc_name, inst->sc_parent->sc_fmri); 6543 r = stash_scferror(lcbdata); 6544 goto deltemp; 6545 6546 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6547 case SCF_ERROR_HANDLE_MISMATCH: 6548 case SCF_ERROR_NOT_BOUND: 6549 case SCF_ERROR_NOT_SET: 6550 default: 6551 bad_error("scf_service_add_instance", 6552 scf_error()); 6553 } 6554 } 6555 6556 nosnap: 6557 /* 6558 * Create a last-import snapshot to serve as an attachment 6559 * point for the real one from the temporary instance. Since 6560 * the contents is irrelevant, take it now, while the instance 6561 * is empty, to minimize svc.configd's work. 6562 */ 6563 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6564 imp_lisnap) != 0) { 6565 switch (scf_error()) { 6566 case SCF_ERROR_CONNECTION_BROKEN: 6567 goto connaborted; 6568 6569 case SCF_ERROR_NO_RESOURCES: 6570 r = stash_scferror(lcbdata); 6571 goto deltemp; 6572 6573 case SCF_ERROR_EXISTS: 6574 warn(gettext("%s changed unexpectedly " 6575 "(snapshot \"%s\" added).\n"), 6576 inst->sc_fmri, snap_lastimport); 6577 lcbdata->sc_err = EBUSY; 6578 r = UU_WALK_ERROR; 6579 goto deltemp; 6580 6581 case SCF_ERROR_PERMISSION_DENIED: 6582 warn(gettext("Could not take \"%s\" snapshot " 6583 "of %s (permission denied).\n"), 6584 snap_lastimport, inst->sc_fmri); 6585 r = stash_scferror(lcbdata); 6586 goto deltemp; 6587 6588 default: 6589 scfwarn(); 6590 lcbdata->sc_err = -1; 6591 r = UU_WALK_ERROR; 6592 goto deltemp; 6593 6594 case SCF_ERROR_NOT_SET: 6595 case SCF_ERROR_INTERNAL: 6596 case SCF_ERROR_INVALID_ARGUMENT: 6597 case SCF_ERROR_HANDLE_MISMATCH: 6598 bad_error("_scf_snapshot_take_new", 6599 scf_error()); 6600 } 6601 } 6602 6603 if (li_only) 6604 goto lionly; 6605 6606 inst->sc_import_state = IMPORT_PROP_BEGUN; 6607 6608 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6609 flags); 6610 switch (r) { 6611 case 0: 6612 break; 6613 6614 case ECONNABORTED: 6615 goto connaborted; 6616 6617 case ECANCELED: 6618 warn(gettext("%s changed unexpectedly " 6619 "(instance \"%s\" deleted).\n"), 6620 inst->sc_parent->sc_fmri, inst->sc_name); 6621 lcbdata->sc_err = EBUSY; 6622 r = UU_WALK_ERROR; 6623 goto deltemp; 6624 6625 case EEXIST: 6626 warn(gettext("%s changed unexpectedly " 6627 "(property group added).\n"), inst->sc_fmri); 6628 lcbdata->sc_err = EBUSY; 6629 r = UU_WALK_ERROR; 6630 goto deltemp; 6631 6632 default: 6633 lcbdata->sc_err = r; 6634 r = UU_WALK_ERROR; 6635 goto deltemp; 6636 6637 case EINVAL: /* caught above */ 6638 bad_error("lscf_import_instance_pgs", r); 6639 } 6640 6641 ctx.sc_parent = imp_inst; 6642 ctx.sc_service = 0; 6643 ctx.sc_trans = NULL; 6644 ctx.sc_flags = 0; 6645 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6646 &ctx, UU_DEFAULT) != 0) { 6647 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6648 bad_error("uu_list_walk", uu_error()); 6649 6650 if (ctx.sc_err == ECONNABORTED) 6651 goto connaborted; 6652 lcbdata->sc_err = ctx.sc_err; 6653 r = UU_WALK_ERROR; 6654 goto deltemp; 6655 } 6656 6657 inst->sc_import_state = IMPORT_PROP_DONE; 6658 6659 if (g_verbose) 6660 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6661 snap_initial, inst->sc_fmri); 6662 r = take_snap(imp_inst, snap_initial, imp_snap); 6663 switch (r) { 6664 case 0: 6665 break; 6666 6667 case ECONNABORTED: 6668 goto connaborted; 6669 6670 case ENOSPC: 6671 case -1: 6672 lcbdata->sc_err = r; 6673 r = UU_WALK_ERROR; 6674 goto deltemp; 6675 6676 case ECANCELED: 6677 warn(gettext("%s changed unexpectedly " 6678 "(instance %s deleted).\n"), 6679 inst->sc_parent->sc_fmri, inst->sc_name); 6680 lcbdata->sc_err = r; 6681 r = UU_WALK_ERROR; 6682 goto deltemp; 6683 6684 case EPERM: 6685 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6686 lcbdata->sc_err = r; 6687 r = UU_WALK_ERROR; 6688 goto deltemp; 6689 6690 default: 6691 bad_error("take_snap", r); 6692 } 6693 } 6694 6695 lionly: 6696 if (lcbdata->sc_flags & SCI_NOSNAP) 6697 goto deltemp; 6698 6699 /* transfer snapshot from temporary instance */ 6700 if (g_verbose) 6701 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6702 snap_lastimport, inst->sc_fmri); 6703 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6704 switch (scf_error()) { 6705 case SCF_ERROR_CONNECTION_BROKEN: 6706 goto connaborted; 6707 6708 case SCF_ERROR_NO_RESOURCES: 6709 r = stash_scferror(lcbdata); 6710 goto deltemp; 6711 6712 case SCF_ERROR_PERMISSION_DENIED: 6713 warn(gettext("Could not take \"%s\" snapshot for %s " 6714 "(permission denied).\n"), snap_lastimport, 6715 inst->sc_fmri); 6716 r = stash_scferror(lcbdata); 6717 goto deltemp; 6718 6719 case SCF_ERROR_NOT_SET: 6720 case SCF_ERROR_HANDLE_MISMATCH: 6721 default: 6722 bad_error("_scf_snapshot_attach", scf_error()); 6723 } 6724 } 6725 6726 inst->sc_import_state = IMPORT_COMPLETE; 6727 6728 r = UU_WALK_NEXT; 6729 6730 deltemp: 6731 /* delete temporary instance */ 6732 if (scf_instance_delete(imp_tinst) != 0) { 6733 switch (scf_error()) { 6734 case SCF_ERROR_DELETED: 6735 break; 6736 6737 case SCF_ERROR_CONNECTION_BROKEN: 6738 goto connaborted; 6739 6740 case SCF_ERROR_NOT_SET: 6741 case SCF_ERROR_NOT_BOUND: 6742 default: 6743 bad_error("scf_instance_delete", scf_error()); 6744 } 6745 } 6746 6747 return (r); 6748 6749 connaborted: 6750 warn(gettext("Could not delete svc:/%s:%s " 6751 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6752 lcbdata->sc_err = ECONNABORTED; 6753 return (UU_WALK_ERROR); 6754 } 6755 6756 /* 6757 * When an instance is imported we end up telling configd about it. Once we tell 6758 * configd about these changes, startd eventually notices. If this is a new 6759 * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter) 6760 * property group. However, many of the other tools expect that this property 6761 * group exists and has certain values. 6762 * 6763 * These values are added asynchronously by startd. We should not return from 6764 * this routine until we can verify that the property group we need is there. 6765 * 6766 * Before we go ahead and verify this, we have to ask ourselves an important 6767 * question: Is the early manifest service currently running? Because if it is 6768 * running and it has invoked us, then the service will never get a restarter 6769 * property because svc.startd is blocked on EMI finishing before it lets itself 6770 * fully connect to svc.configd. Of course, this means that this race condition 6771 * is in fact impossible to 100% eliminate. 6772 * 6773 * svc.startd makes sure that EMI only runs once and has succeeded by checking 6774 * the state of the EMI instance. If it is online it bails out and makes sure 6775 * that it doesn't run again. In this case, we're going to do something similar, 6776 * only if the state is online, then we're going to actually verify. EMI always 6777 * has to be present, but it can be explicitly disabled to reduce the amount of 6778 * damage it can cause. If EMI has been disabled then we no longer have to worry 6779 * about the implicit race condition and can go ahead and check things. If EMI 6780 * is in some state that isn't online or disabled and isn't runinng, then we 6781 * assume that things are rather bad and we're not going to get in your way, 6782 * even if the rest of SMF does. 6783 * 6784 * Returns 0 on success or returns an errno. 6785 */ 6786 #ifndef NATIVE_BUILD 6787 static int 6788 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst) 6789 { 6790 int ret, err; 6791 struct timespec ts; 6792 char *emi_state; 6793 6794 /* 6795 * smf_get_state does not distinguish between its different failure 6796 * modes: memory allocation failures, SMF internal failures, and a lack 6797 * of EMI entirely because it's been removed. In these cases, we're 6798 * going to be conservative and opt to say that if we don't know, better 6799 * to not block import or falsely warn to the user. 6800 */ 6801 if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) { 6802 return (0); 6803 } 6804 6805 /* 6806 * As per the block comment for this function check the state of EMI 6807 */ 6808 if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 && 6809 strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) { 6810 warn(gettext("Not validating instance %s:%s because EMI's " 6811 "state is %s\n"), svc->sc_name, inst->sc_name, emi_state); 6812 free(emi_state); 6813 return (0); 6814 } 6815 6816 free(emi_state); 6817 6818 /* 6819 * First we have to get the property. 6820 */ 6821 if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) { 6822 ret = scf_error(); 6823 warn(gettext("Failed to look up service: %s\n"), svc->sc_name); 6824 return (ret); 6825 } 6826 6827 /* 6828 * We should always be able to get the instance. It should already 6829 * exist because we just created it or got it. There probably is a 6830 * slim chance that someone may have come in and deleted it though from 6831 * under us. 6832 */ 6833 if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst)) 6834 != 0) { 6835 ret = scf_error(); 6836 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name); 6837 switch (ret) { 6838 case SCF_ERROR_DELETED: 6839 err = ENODEV; 6840 break; 6841 case SCF_ERROR_CONNECTION_BROKEN: 6842 warn(gettext("Lost repository connection\n")); 6843 err = ECONNABORTED; 6844 break; 6845 case SCF_ERROR_NOT_FOUND: 6846 warn(gettext("Instance \"%s\" disappeared out from " 6847 "under us.\n"), inst->sc_name); 6848 err = ENOENT; 6849 break; 6850 default: 6851 bad_error("scf_service_get_instance", ret); 6852 } 6853 6854 return (err); 6855 } 6856 6857 /* 6858 * An astute observer may want to use _scf_wait_pg which would notify us 6859 * of a property group change, unfortunately that does not work if the 6860 * property group in question does not exist. So instead we have to 6861 * manually poll and ask smf the best way to get to it. 6862 */ 6863 while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg)) 6864 != SCF_SUCCESS) { 6865 ret = scf_error(); 6866 if (ret != SCF_ERROR_NOT_FOUND) { 6867 warn(gettext("Failed to get restarter property " 6868 "group for instance: %s\n"), inst->sc_name); 6869 switch (ret) { 6870 case SCF_ERROR_DELETED: 6871 err = ENODEV; 6872 break; 6873 case SCF_ERROR_CONNECTION_BROKEN: 6874 warn(gettext("Lost repository connection\n")); 6875 err = ECONNABORTED; 6876 break; 6877 default: 6878 bad_error("scf_service_get_instance", ret); 6879 } 6880 6881 return (err); 6882 } 6883 6884 ts.tv_sec = pg_timeout / NANOSEC; 6885 ts.tv_nsec = pg_timeout % NANOSEC; 6886 6887 (void) nanosleep(&ts, NULL); 6888 } 6889 6890 /* 6891 * svcadm also expects that the SCF_PROPERTY_STATE property is present. 6892 * So in addition to the property group being present, we need to wait 6893 * for the property to be there in some form. 6894 * 6895 * Note that a property group is a frozen snapshot in time. To properly 6896 * get beyond this, you have to refresh the property group each time. 6897 */ 6898 while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE, 6899 imp_prop)) != 0) { 6900 6901 ret = scf_error(); 6902 if (ret != SCF_ERROR_NOT_FOUND) { 6903 warn(gettext("Failed to get property %s from the " 6904 "restarter property group of instance %s\n"), 6905 SCF_PROPERTY_STATE, inst->sc_name); 6906 switch (ret) { 6907 case SCF_ERROR_CONNECTION_BROKEN: 6908 warn(gettext("Lost repository connection\n")); 6909 err = ECONNABORTED; 6910 break; 6911 case SCF_ERROR_DELETED: 6912 err = ENODEV; 6913 break; 6914 default: 6915 bad_error("scf_pg_get_property", ret); 6916 } 6917 6918 return (err); 6919 } 6920 6921 ts.tv_sec = pg_timeout / NANOSEC; 6922 ts.tv_nsec = pg_timeout % NANOSEC; 6923 6924 (void) nanosleep(&ts, NULL); 6925 6926 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg); 6927 if (ret != SCF_SUCCESS) { 6928 warn(gettext("Failed to get restarter property " 6929 "group for instance: %s\n"), inst->sc_name); 6930 switch (ret) { 6931 case SCF_ERROR_DELETED: 6932 err = ENODEV; 6933 break; 6934 case SCF_ERROR_CONNECTION_BROKEN: 6935 warn(gettext("Lost repository connection\n")); 6936 err = ECONNABORTED; 6937 break; 6938 default: 6939 bad_error("scf_service_get_instance", ret); 6940 } 6941 6942 return (err); 6943 } 6944 } 6945 6946 /* 6947 * We don't have to free the property groups or other values that we got 6948 * because we stored them in global variables that are allocated and 6949 * freed by the routines that call into these functions. Unless of 6950 * course the rest of the code here that we are basing this on is 6951 * mistaken. 6952 */ 6953 return (0); 6954 } 6955 #endif 6956 6957 /* 6958 * If the service is missing, create it, import its properties, and import the 6959 * instances. Since the service is brand new, it should be empty, and if we 6960 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6961 * 6962 * If the service exists, we want to upgrade its properties and import the 6963 * instances. Upgrade requires a last-import snapshot, though, which are 6964 * children of instances, so first we'll have to go through the instances 6965 * looking for a last-import snapshot. If we don't find one then we'll just 6966 * override-import the service properties (but don't delete existing 6967 * properties: another service might have declared us as a dependent). Before 6968 * we change anything, though, we want to take the previous snapshots. We 6969 * also give lscf_instance_import() a leg up on taking last-import snapshots 6970 * by importing the manifest's service properties into a temporary service. 6971 * 6972 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6973 * sets lcbdata->sc_err to 6974 * ECONNABORTED - repository connection broken 6975 * ENOMEM - out of memory 6976 * ENOSPC - svc.configd is out of resources 6977 * EPERM - couldn't create temporary service (error printed) 6978 * - couldn't import into temp service (error printed) 6979 * - couldn't create service (error printed) 6980 * - couldn't import dependent (error printed) 6981 * - couldn't take snapshot (error printed) 6982 * - couldn't create instance (error printed) 6983 * - couldn't create, modify, or delete pg (error printed) 6984 * - couldn't create, modify, or delete dependent (error printed) 6985 * - couldn't import instance (error printed) 6986 * EROFS - couldn't create temporary service (repository read-only) 6987 * - couldn't import into temporary service (repository read-only) 6988 * - couldn't create service (repository read-only) 6989 * - couldn't import dependent (repository read-only) 6990 * - couldn't create instance (repository read-only) 6991 * - couldn't create, modify, or delete pg or dependent 6992 * - couldn't import instance (repository read-only) 6993 * EACCES - couldn't create temporary service (backend access denied) 6994 * - couldn't import into temporary service (backend access denied) 6995 * - couldn't create service (backend access denied) 6996 * - couldn't import dependent (backend access denied) 6997 * - couldn't create instance (backend access denied) 6998 * - couldn't create, modify, or delete pg or dependent 6999 * - couldn't import instance (backend access denied) 7000 * EINVAL - service name is invalid (error printed) 7001 * - service name is too long (error printed) 7002 * - s has invalid pgroup (error printed) 7003 * - s has invalid dependent (error printed) 7004 * - instance name is invalid (error printed) 7005 * - instance entity_t is invalid (error printed) 7006 * EEXIST - couldn't create temporary service (already exists) (error printed) 7007 * - couldn't import dependent (dependency pg already exists) (printed) 7008 * - dependency collision in dependent service (error printed) 7009 * EBUSY - temporary service deleted (error printed) 7010 * - property group added to temporary service (error printed) 7011 * - new property group changed or was deleted (error printed) 7012 * - service was added unexpectedly (error printed) 7013 * - service was deleted unexpectedly (error printed) 7014 * - property group added to new service (error printed) 7015 * - instance added unexpectedly (error printed) 7016 * - instance deleted unexpectedly (error printed) 7017 * - dependent service deleted unexpectedly (error printed) 7018 * - pg was added, changed, or deleted (error printed) 7019 * - dependent pg changed (error printed) 7020 * - temporary instance added, changed, or deleted (error printed) 7021 * EBADF - a last-import snapshot is corrupt (error printed) 7022 * - the service is corrupt (error printed) 7023 * - a dependent is corrupt (error printed) 7024 * - an instance is corrupt (error printed) 7025 * - an instance has a corrupt last-import snapshot (error printed) 7026 * - dependent target has a corrupt snapshot (error printed) 7027 * -1 - unknown libscf error (error printed) 7028 */ 7029 static int 7030 lscf_service_import(void *v, void *pvt) 7031 { 7032 entity_t *s = v; 7033 scf_callback_t cbdata; 7034 scf_callback_t *lcbdata = pvt; 7035 scf_scope_t *scope = lcbdata->sc_parent; 7036 entity_t *inst, linst; 7037 int r; 7038 int fresh = 0; 7039 scf_snaplevel_t *running; 7040 int have_ge = 0; 7041 boolean_t retried = B_FALSE; 7042 7043 const char * const ts_deleted = gettext("Temporary service svc:/%s " 7044 "was deleted unexpectedly.\n"); 7045 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 7046 "changed unexpectedly (property group added).\n"); 7047 const char * const s_deleted = 7048 gettext("%s was deleted unexpectedly.\n"); 7049 const char * const i_deleted = 7050 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 7051 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 7052 "is corrupt (missing service snaplevel).\n"); 7053 const char * const s_mfile_upd = 7054 gettext("Unable to update the manifest file connection " 7055 "for %s\n"); 7056 7057 li_only = 0; 7058 /* Validate the service name */ 7059 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7060 switch (scf_error()) { 7061 case SCF_ERROR_CONNECTION_BROKEN: 7062 return (stash_scferror(lcbdata)); 7063 7064 case SCF_ERROR_INVALID_ARGUMENT: 7065 warn(gettext("\"%s\" is an invalid service name. " 7066 "Cannot import.\n"), s->sc_name); 7067 return (stash_scferror(lcbdata)); 7068 7069 case SCF_ERROR_NOT_FOUND: 7070 break; 7071 7072 case SCF_ERROR_HANDLE_MISMATCH: 7073 case SCF_ERROR_NOT_BOUND: 7074 case SCF_ERROR_NOT_SET: 7075 default: 7076 bad_error("scf_scope_get_service", scf_error()); 7077 } 7078 } 7079 7080 /* create temporary service */ 7081 /* 7082 * the size of the buffer was reduced to max_scf_name_len to prevent 7083 * hitting bug 6681151. After the bug fix, the size of the buffer 7084 * should be restored to its original value (max_scf_name_len +1) 7085 */ 7086 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 7087 if (r < 0) 7088 bad_error("snprintf", errno); 7089 if (r > max_scf_name_len) { 7090 warn(gettext( 7091 "Service name \"%s\" is too long. Cannot import.\n"), 7092 s->sc_name); 7093 lcbdata->sc_err = EINVAL; 7094 return (UU_WALK_ERROR); 7095 } 7096 7097 retry: 7098 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 7099 switch (scf_error()) { 7100 case SCF_ERROR_CONNECTION_BROKEN: 7101 case SCF_ERROR_NO_RESOURCES: 7102 case SCF_ERROR_BACKEND_READONLY: 7103 case SCF_ERROR_BACKEND_ACCESS: 7104 return (stash_scferror(lcbdata)); 7105 7106 case SCF_ERROR_EXISTS: 7107 if (!retried) { 7108 lscf_delete(imp_tsname, 0); 7109 retried = B_TRUE; 7110 goto retry; 7111 } 7112 warn(gettext( 7113 "Temporary service \"%s\" must be deleted before " 7114 "this manifest can be imported.\n"), imp_tsname); 7115 return (stash_scferror(lcbdata)); 7116 7117 case SCF_ERROR_PERMISSION_DENIED: 7118 warn(gettext("Could not create temporary service " 7119 "\"%s\" (permission denied).\n"), imp_tsname); 7120 return (stash_scferror(lcbdata)); 7121 7122 case SCF_ERROR_INVALID_ARGUMENT: 7123 case SCF_ERROR_HANDLE_MISMATCH: 7124 case SCF_ERROR_NOT_BOUND: 7125 case SCF_ERROR_NOT_SET: 7126 default: 7127 bad_error("scf_scope_add_service", scf_error()); 7128 } 7129 } 7130 7131 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 7132 if (r < 0) 7133 bad_error("snprintf", errno); 7134 7135 cbdata.sc_handle = lcbdata->sc_handle; 7136 cbdata.sc_parent = imp_tsvc; 7137 cbdata.sc_service = 1; 7138 cbdata.sc_source_fmri = s->sc_fmri; 7139 cbdata.sc_target_fmri = imp_str; 7140 cbdata.sc_flags = 0; 7141 7142 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 7143 UU_DEFAULT) != 0) { 7144 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7145 bad_error("uu_list_walk", uu_error()); 7146 7147 lcbdata->sc_err = cbdata.sc_err; 7148 switch (cbdata.sc_err) { 7149 case ECONNABORTED: 7150 goto connaborted; 7151 7152 case ECANCELED: 7153 warn(ts_deleted, imp_tsname); 7154 lcbdata->sc_err = EBUSY; 7155 return (UU_WALK_ERROR); 7156 7157 case EEXIST: 7158 warn(ts_pg_added, imp_tsname); 7159 lcbdata->sc_err = EBUSY; 7160 return (UU_WALK_ERROR); 7161 } 7162 7163 r = UU_WALK_ERROR; 7164 goto deltemp; 7165 } 7166 7167 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 7168 UU_DEFAULT) != 0) { 7169 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7170 bad_error("uu_list_walk", uu_error()); 7171 7172 lcbdata->sc_err = cbdata.sc_err; 7173 switch (cbdata.sc_err) { 7174 case ECONNABORTED: 7175 goto connaborted; 7176 7177 case ECANCELED: 7178 warn(ts_deleted, imp_tsname); 7179 lcbdata->sc_err = EBUSY; 7180 return (UU_WALK_ERROR); 7181 7182 case EEXIST: 7183 warn(ts_pg_added, imp_tsname); 7184 lcbdata->sc_err = EBUSY; 7185 return (UU_WALK_ERROR); 7186 } 7187 7188 r = UU_WALK_ERROR; 7189 goto deltemp; 7190 } 7191 7192 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 7193 switch (scf_error()) { 7194 case SCF_ERROR_NOT_FOUND: 7195 break; 7196 7197 case SCF_ERROR_CONNECTION_BROKEN: 7198 goto connaborted; 7199 7200 case SCF_ERROR_INVALID_ARGUMENT: 7201 case SCF_ERROR_HANDLE_MISMATCH: 7202 case SCF_ERROR_NOT_BOUND: 7203 case SCF_ERROR_NOT_SET: 7204 default: 7205 bad_error("scf_scope_get_service", scf_error()); 7206 } 7207 7208 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 7209 switch (scf_error()) { 7210 case SCF_ERROR_CONNECTION_BROKEN: 7211 goto connaborted; 7212 7213 case SCF_ERROR_NO_RESOURCES: 7214 case SCF_ERROR_BACKEND_READONLY: 7215 case SCF_ERROR_BACKEND_ACCESS: 7216 r = stash_scferror(lcbdata); 7217 goto deltemp; 7218 7219 case SCF_ERROR_EXISTS: 7220 warn(gettext("Scope \"%s\" changed unexpectedly" 7221 " (service \"%s\" added).\n"), 7222 SCF_SCOPE_LOCAL, s->sc_name); 7223 lcbdata->sc_err = EBUSY; 7224 goto deltemp; 7225 7226 case SCF_ERROR_PERMISSION_DENIED: 7227 warn(gettext("Could not create service \"%s\" " 7228 "(permission denied).\n"), s->sc_name); 7229 goto deltemp; 7230 7231 case SCF_ERROR_INVALID_ARGUMENT: 7232 case SCF_ERROR_HANDLE_MISMATCH: 7233 case SCF_ERROR_NOT_BOUND: 7234 case SCF_ERROR_NOT_SET: 7235 default: 7236 bad_error("scf_scope_add_service", scf_error()); 7237 } 7238 } 7239 7240 s->sc_import_state = IMPORT_PROP_BEGUN; 7241 7242 /* import service properties */ 7243 cbdata.sc_handle = lcbdata->sc_handle; 7244 cbdata.sc_parent = imp_svc; 7245 cbdata.sc_service = 1; 7246 cbdata.sc_flags = lcbdata->sc_flags; 7247 cbdata.sc_source_fmri = s->sc_fmri; 7248 cbdata.sc_target_fmri = s->sc_fmri; 7249 7250 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7251 &cbdata, UU_DEFAULT) != 0) { 7252 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7253 bad_error("uu_list_walk", uu_error()); 7254 7255 lcbdata->sc_err = cbdata.sc_err; 7256 switch (cbdata.sc_err) { 7257 case ECONNABORTED: 7258 goto connaborted; 7259 7260 case ECANCELED: 7261 warn(s_deleted, s->sc_fmri); 7262 lcbdata->sc_err = EBUSY; 7263 return (UU_WALK_ERROR); 7264 7265 case EEXIST: 7266 warn(gettext("%s changed unexpectedly " 7267 "(property group added).\n"), s->sc_fmri); 7268 lcbdata->sc_err = EBUSY; 7269 return (UU_WALK_ERROR); 7270 7271 case EINVAL: 7272 /* caught above */ 7273 bad_error("entity_pgroup_import", 7274 cbdata.sc_err); 7275 } 7276 7277 r = UU_WALK_ERROR; 7278 goto deltemp; 7279 } 7280 7281 cbdata.sc_trans = NULL; 7282 cbdata.sc_flags = 0; 7283 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 7284 &cbdata, UU_DEFAULT) != 0) { 7285 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7286 bad_error("uu_list_walk", uu_error()); 7287 7288 lcbdata->sc_err = cbdata.sc_err; 7289 if (cbdata.sc_err == ECONNABORTED) 7290 goto connaborted; 7291 r = UU_WALK_ERROR; 7292 goto deltemp; 7293 } 7294 7295 s->sc_import_state = IMPORT_PROP_DONE; 7296 7297 /* 7298 * This is a new service, so we can't take previous snapshots 7299 * or upgrade service properties. 7300 */ 7301 fresh = 1; 7302 goto instances; 7303 } 7304 7305 /* Clear sc_seen for the instances. */ 7306 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 7307 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 7308 bad_error("uu_list_walk", uu_error()); 7309 7310 /* 7311 * Take previous snapshots for all instances. Even for ones not 7312 * mentioned in the bundle, since we might change their service 7313 * properties. 7314 */ 7315 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7316 switch (scf_error()) { 7317 case SCF_ERROR_CONNECTION_BROKEN: 7318 goto connaborted; 7319 7320 case SCF_ERROR_DELETED: 7321 warn(s_deleted, s->sc_fmri); 7322 lcbdata->sc_err = EBUSY; 7323 r = UU_WALK_ERROR; 7324 goto deltemp; 7325 7326 case SCF_ERROR_HANDLE_MISMATCH: 7327 case SCF_ERROR_NOT_BOUND: 7328 case SCF_ERROR_NOT_SET: 7329 default: 7330 bad_error("scf_iter_service_instances", scf_error()); 7331 } 7332 } 7333 7334 for (;;) { 7335 r = scf_iter_next_instance(imp_iter, imp_inst); 7336 if (r == 0) 7337 break; 7338 if (r != 1) { 7339 switch (scf_error()) { 7340 case SCF_ERROR_DELETED: 7341 warn(s_deleted, s->sc_fmri); 7342 lcbdata->sc_err = EBUSY; 7343 r = UU_WALK_ERROR; 7344 goto deltemp; 7345 7346 case SCF_ERROR_CONNECTION_BROKEN: 7347 goto connaborted; 7348 7349 case SCF_ERROR_NOT_BOUND: 7350 case SCF_ERROR_HANDLE_MISMATCH: 7351 case SCF_ERROR_INVALID_ARGUMENT: 7352 case SCF_ERROR_NOT_SET: 7353 default: 7354 bad_error("scf_iter_next_instance", 7355 scf_error()); 7356 } 7357 } 7358 7359 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 7360 switch (scf_error()) { 7361 case SCF_ERROR_DELETED: 7362 continue; 7363 7364 case SCF_ERROR_CONNECTION_BROKEN: 7365 goto connaborted; 7366 7367 case SCF_ERROR_NOT_SET: 7368 case SCF_ERROR_NOT_BOUND: 7369 default: 7370 bad_error("scf_instance_get_name", scf_error()); 7371 } 7372 } 7373 7374 if (g_verbose) 7375 warn(gettext( 7376 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 7377 snap_previous, s->sc_name, imp_str); 7378 7379 r = take_snap(imp_inst, snap_previous, imp_snap); 7380 switch (r) { 7381 case 0: 7382 break; 7383 7384 case ECANCELED: 7385 continue; 7386 7387 case ECONNABORTED: 7388 goto connaborted; 7389 7390 case EPERM: 7391 warn(gettext("Could not take \"%s\" snapshot of " 7392 "svc:/%s:%s (permission denied).\n"), 7393 snap_previous, s->sc_name, imp_str); 7394 lcbdata->sc_err = r; 7395 return (UU_WALK_ERROR); 7396 7397 case ENOSPC: 7398 case -1: 7399 lcbdata->sc_err = r; 7400 r = UU_WALK_ERROR; 7401 goto deltemp; 7402 7403 default: 7404 bad_error("take_snap", r); 7405 } 7406 7407 linst.sc_name = imp_str; 7408 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 7409 &linst, NULL, NULL); 7410 if (inst != NULL) { 7411 inst->sc_import_state = IMPORT_PREVIOUS; 7412 inst->sc_seen = 1; 7413 } 7414 } 7415 7416 /* 7417 * Create the new instances and take previous snapshots of 7418 * them. This is not necessary, but it maximizes data preservation. 7419 */ 7420 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 7421 inst != NULL; 7422 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 7423 inst)) { 7424 if (inst->sc_seen) 7425 continue; 7426 7427 if (scf_service_add_instance(imp_svc, inst->sc_name, 7428 imp_inst) != 0) { 7429 switch (scf_error()) { 7430 case SCF_ERROR_CONNECTION_BROKEN: 7431 goto connaborted; 7432 7433 case SCF_ERROR_BACKEND_READONLY: 7434 case SCF_ERROR_BACKEND_ACCESS: 7435 case SCF_ERROR_NO_RESOURCES: 7436 r = stash_scferror(lcbdata); 7437 goto deltemp; 7438 7439 case SCF_ERROR_EXISTS: 7440 warn(gettext("%s changed unexpectedly " 7441 "(instance \"%s\" added).\n"), s->sc_fmri, 7442 inst->sc_name); 7443 lcbdata->sc_err = EBUSY; 7444 r = UU_WALK_ERROR; 7445 goto deltemp; 7446 7447 case SCF_ERROR_INVALID_ARGUMENT: 7448 warn(gettext("Service \"%s\" has instance with " 7449 "invalid name \"%s\".\n"), s->sc_name, 7450 inst->sc_name); 7451 r = stash_scferror(lcbdata); 7452 goto deltemp; 7453 7454 case SCF_ERROR_PERMISSION_DENIED: 7455 warn(gettext("Could not create instance \"%s\" " 7456 "in %s (permission denied).\n"), 7457 inst->sc_name, s->sc_fmri); 7458 r = stash_scferror(lcbdata); 7459 goto deltemp; 7460 7461 case SCF_ERROR_HANDLE_MISMATCH: 7462 case SCF_ERROR_NOT_BOUND: 7463 case SCF_ERROR_NOT_SET: 7464 default: 7465 bad_error("scf_service_add_instance", 7466 scf_error()); 7467 } 7468 } 7469 7470 if (g_verbose) 7471 warn(gettext("Taking \"%s\" snapshot for " 7472 "new service %s.\n"), snap_previous, inst->sc_fmri); 7473 r = take_snap(imp_inst, snap_previous, imp_snap); 7474 switch (r) { 7475 case 0: 7476 break; 7477 7478 case ECANCELED: 7479 warn(i_deleted, s->sc_fmri, inst->sc_name); 7480 lcbdata->sc_err = EBUSY; 7481 r = UU_WALK_ERROR; 7482 goto deltemp; 7483 7484 case ECONNABORTED: 7485 goto connaborted; 7486 7487 case EPERM: 7488 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 7489 lcbdata->sc_err = r; 7490 r = UU_WALK_ERROR; 7491 goto deltemp; 7492 7493 case ENOSPC: 7494 case -1: 7495 r = UU_WALK_ERROR; 7496 goto deltemp; 7497 7498 default: 7499 bad_error("take_snap", r); 7500 } 7501 } 7502 7503 s->sc_import_state = IMPORT_PREVIOUS; 7504 7505 /* 7506 * Upgrade service properties, if we can find a last-import snapshot. 7507 * Any will do because we don't support different service properties 7508 * in different manifests, so all snaplevels of the service in all of 7509 * the last-import snapshots of the instances should be the same. 7510 */ 7511 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7512 switch (scf_error()) { 7513 case SCF_ERROR_CONNECTION_BROKEN: 7514 goto connaborted; 7515 7516 case SCF_ERROR_DELETED: 7517 warn(s_deleted, s->sc_fmri); 7518 lcbdata->sc_err = EBUSY; 7519 r = UU_WALK_ERROR; 7520 goto deltemp; 7521 7522 case SCF_ERROR_HANDLE_MISMATCH: 7523 case SCF_ERROR_NOT_BOUND: 7524 case SCF_ERROR_NOT_SET: 7525 default: 7526 bad_error("scf_iter_service_instances", scf_error()); 7527 } 7528 } 7529 7530 for (;;) { 7531 r = scf_iter_next_instance(imp_iter, imp_inst); 7532 if (r == -1) { 7533 switch (scf_error()) { 7534 case SCF_ERROR_DELETED: 7535 warn(s_deleted, s->sc_fmri); 7536 lcbdata->sc_err = EBUSY; 7537 r = UU_WALK_ERROR; 7538 goto deltemp; 7539 7540 case SCF_ERROR_CONNECTION_BROKEN: 7541 goto connaborted; 7542 7543 case SCF_ERROR_NOT_BOUND: 7544 case SCF_ERROR_HANDLE_MISMATCH: 7545 case SCF_ERROR_INVALID_ARGUMENT: 7546 case SCF_ERROR_NOT_SET: 7547 default: 7548 bad_error("scf_iter_next_instance", 7549 scf_error()); 7550 } 7551 } 7552 7553 if (r == 0) { 7554 /* 7555 * Didn't find any last-import snapshots. Override- 7556 * import the properties. Unless one of the instances 7557 * has a general/enabled property, in which case we're 7558 * probably running a last-import-capable svccfg for 7559 * the first time, and we should only take the 7560 * last-import snapshot. 7561 */ 7562 if (have_ge) { 7563 pgroup_t *mfpg; 7564 scf_callback_t mfcbdata; 7565 7566 li_only = 1; 7567 no_refresh = 1; 7568 /* 7569 * Need to go ahead and import the manifestfiles 7570 * pg if it exists. If the last-import snapshot 7571 * upgrade code is ever removed this code can 7572 * be removed as well. 7573 */ 7574 mfpg = internal_pgroup_find(s, 7575 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 7576 7577 if (mfpg) { 7578 mfcbdata.sc_handle = g_hndl; 7579 mfcbdata.sc_parent = imp_svc; 7580 mfcbdata.sc_service = 1; 7581 mfcbdata.sc_flags = SCI_FORCE; 7582 mfcbdata.sc_source_fmri = s->sc_fmri; 7583 mfcbdata.sc_target_fmri = s->sc_fmri; 7584 if (entity_pgroup_import(mfpg, 7585 &mfcbdata) != UU_WALK_NEXT) { 7586 warn(s_mfile_upd, s->sc_fmri); 7587 r = UU_WALK_ERROR; 7588 goto deltemp; 7589 } 7590 } 7591 break; 7592 } 7593 7594 s->sc_import_state = IMPORT_PROP_BEGUN; 7595 7596 cbdata.sc_handle = g_hndl; 7597 cbdata.sc_parent = imp_svc; 7598 cbdata.sc_service = 1; 7599 cbdata.sc_flags = SCI_FORCE; 7600 cbdata.sc_source_fmri = s->sc_fmri; 7601 cbdata.sc_target_fmri = s->sc_fmri; 7602 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7603 &cbdata, UU_DEFAULT) != 0) { 7604 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7605 bad_error("uu_list_walk", uu_error()); 7606 lcbdata->sc_err = cbdata.sc_err; 7607 switch (cbdata.sc_err) { 7608 case ECONNABORTED: 7609 goto connaborted; 7610 7611 case ECANCELED: 7612 warn(s_deleted, s->sc_fmri); 7613 lcbdata->sc_err = EBUSY; 7614 break; 7615 7616 case EINVAL: /* caught above */ 7617 case EEXIST: 7618 bad_error("entity_pgroup_import", 7619 cbdata.sc_err); 7620 } 7621 7622 r = UU_WALK_ERROR; 7623 goto deltemp; 7624 } 7625 7626 cbdata.sc_trans = NULL; 7627 cbdata.sc_flags = 0; 7628 if (uu_list_walk(s->sc_dependents, 7629 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 7630 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7631 bad_error("uu_list_walk", uu_error()); 7632 lcbdata->sc_err = cbdata.sc_err; 7633 if (cbdata.sc_err == ECONNABORTED) 7634 goto connaborted; 7635 r = UU_WALK_ERROR; 7636 goto deltemp; 7637 } 7638 break; 7639 } 7640 7641 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 7642 imp_snap) != 0) { 7643 switch (scf_error()) { 7644 case SCF_ERROR_DELETED: 7645 continue; 7646 7647 case SCF_ERROR_NOT_FOUND: 7648 break; 7649 7650 case SCF_ERROR_CONNECTION_BROKEN: 7651 goto connaborted; 7652 7653 case SCF_ERROR_HANDLE_MISMATCH: 7654 case SCF_ERROR_NOT_BOUND: 7655 case SCF_ERROR_INVALID_ARGUMENT: 7656 case SCF_ERROR_NOT_SET: 7657 default: 7658 bad_error("scf_instance_get_snapshot", 7659 scf_error()); 7660 } 7661 7662 if (have_ge) 7663 continue; 7664 7665 /* 7666 * Check for a general/enabled property. This is how 7667 * we tell whether to import if there turn out to be 7668 * no last-import snapshots. 7669 */ 7670 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 7671 imp_pg) == 0) { 7672 if (scf_pg_get_property(imp_pg, 7673 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 7674 have_ge = 1; 7675 } else { 7676 switch (scf_error()) { 7677 case SCF_ERROR_DELETED: 7678 case SCF_ERROR_NOT_FOUND: 7679 continue; 7680 7681 case SCF_ERROR_INVALID_ARGUMENT: 7682 case SCF_ERROR_HANDLE_MISMATCH: 7683 case SCF_ERROR_CONNECTION_BROKEN: 7684 case SCF_ERROR_NOT_BOUND: 7685 case SCF_ERROR_NOT_SET: 7686 default: 7687 bad_error("scf_pg_get_property", 7688 scf_error()); 7689 } 7690 } 7691 } else { 7692 switch (scf_error()) { 7693 case SCF_ERROR_DELETED: 7694 case SCF_ERROR_NOT_FOUND: 7695 continue; 7696 7697 case SCF_ERROR_CONNECTION_BROKEN: 7698 goto connaborted; 7699 7700 case SCF_ERROR_NOT_BOUND: 7701 case SCF_ERROR_NOT_SET: 7702 case SCF_ERROR_INVALID_ARGUMENT: 7703 case SCF_ERROR_HANDLE_MISMATCH: 7704 default: 7705 bad_error("scf_instance_get_pg", 7706 scf_error()); 7707 } 7708 } 7709 continue; 7710 } 7711 7712 /* find service snaplevel */ 7713 r = get_snaplevel(imp_snap, 1, imp_snpl); 7714 switch (r) { 7715 case 0: 7716 break; 7717 7718 case ECONNABORTED: 7719 goto connaborted; 7720 7721 case ECANCELED: 7722 continue; 7723 7724 case ENOENT: 7725 if (scf_instance_get_name(imp_inst, imp_str, 7726 imp_str_sz) < 0) 7727 (void) strcpy(imp_str, "?"); 7728 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 7729 lcbdata->sc_err = EBADF; 7730 r = UU_WALK_ERROR; 7731 goto deltemp; 7732 7733 default: 7734 bad_error("get_snaplevel", r); 7735 } 7736 7737 if (scf_instance_get_snapshot(imp_inst, snap_running, 7738 imp_rsnap) != 0) { 7739 switch (scf_error()) { 7740 case SCF_ERROR_DELETED: 7741 continue; 7742 7743 case SCF_ERROR_NOT_FOUND: 7744 break; 7745 7746 case SCF_ERROR_CONNECTION_BROKEN: 7747 goto connaborted; 7748 7749 case SCF_ERROR_INVALID_ARGUMENT: 7750 case SCF_ERROR_HANDLE_MISMATCH: 7751 case SCF_ERROR_NOT_BOUND: 7752 case SCF_ERROR_NOT_SET: 7753 default: 7754 bad_error("scf_instance_get_snapshot", 7755 scf_error()); 7756 } 7757 running = NULL; 7758 } else { 7759 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7760 switch (r) { 7761 case 0: 7762 running = imp_rsnpl; 7763 break; 7764 7765 case ECONNABORTED: 7766 goto connaborted; 7767 7768 case ECANCELED: 7769 continue; 7770 7771 case ENOENT: 7772 if (scf_instance_get_name(imp_inst, imp_str, 7773 imp_str_sz) < 0) 7774 (void) strcpy(imp_str, "?"); 7775 warn(badsnap, snap_running, s->sc_name, 7776 imp_str); 7777 lcbdata->sc_err = EBADF; 7778 r = UU_WALK_ERROR; 7779 goto deltemp; 7780 7781 default: 7782 bad_error("get_snaplevel", r); 7783 } 7784 } 7785 7786 if (g_verbose) { 7787 if (scf_instance_get_name(imp_inst, imp_str, 7788 imp_str_sz) < 0) 7789 (void) strcpy(imp_str, "?"); 7790 warn(gettext("Upgrading properties of %s according to " 7791 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7792 } 7793 7794 /* upgrade service properties */ 7795 r = upgrade_props(imp_svc, running, imp_snpl, s); 7796 if (r == 0) 7797 break; 7798 7799 switch (r) { 7800 case ECONNABORTED: 7801 goto connaborted; 7802 7803 case ECANCELED: 7804 warn(s_deleted, s->sc_fmri); 7805 lcbdata->sc_err = EBUSY; 7806 break; 7807 7808 case ENODEV: 7809 if (scf_instance_get_name(imp_inst, imp_str, 7810 imp_str_sz) < 0) 7811 (void) strcpy(imp_str, "?"); 7812 warn(i_deleted, s->sc_fmri, imp_str); 7813 lcbdata->sc_err = EBUSY; 7814 break; 7815 7816 default: 7817 lcbdata->sc_err = r; 7818 } 7819 7820 r = UU_WALK_ERROR; 7821 goto deltemp; 7822 } 7823 7824 s->sc_import_state = IMPORT_PROP_DONE; 7825 7826 instances: 7827 /* import instances */ 7828 cbdata.sc_handle = lcbdata->sc_handle; 7829 cbdata.sc_parent = imp_svc; 7830 cbdata.sc_service = 1; 7831 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7832 cbdata.sc_general = NULL; 7833 7834 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7835 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7836 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7837 bad_error("uu_list_walk", uu_error()); 7838 7839 lcbdata->sc_err = cbdata.sc_err; 7840 if (cbdata.sc_err == ECONNABORTED) 7841 goto connaborted; 7842 r = UU_WALK_ERROR; 7843 goto deltemp; 7844 } 7845 7846 s->sc_import_state = IMPORT_COMPLETE; 7847 r = UU_WALK_NEXT; 7848 7849 deltemp: 7850 /* delete temporary service */ 7851 if (scf_service_delete(imp_tsvc) != 0) { 7852 switch (scf_error()) { 7853 case SCF_ERROR_DELETED: 7854 break; 7855 7856 case SCF_ERROR_CONNECTION_BROKEN: 7857 goto connaborted; 7858 7859 case SCF_ERROR_EXISTS: 7860 warn(gettext( 7861 "Could not delete svc:/%s (instances exist).\n"), 7862 imp_tsname); 7863 break; 7864 7865 case SCF_ERROR_NOT_SET: 7866 case SCF_ERROR_NOT_BOUND: 7867 default: 7868 bad_error("scf_service_delete", scf_error()); 7869 } 7870 } 7871 7872 return (r); 7873 7874 connaborted: 7875 warn(gettext("Could not delete svc:/%s " 7876 "(repository connection broken).\n"), imp_tsname); 7877 lcbdata->sc_err = ECONNABORTED; 7878 return (UU_WALK_ERROR); 7879 } 7880 7881 static const char * 7882 import_progress(int st) 7883 { 7884 switch (st) { 7885 case 0: 7886 return (gettext("not reached.")); 7887 7888 case IMPORT_PREVIOUS: 7889 return (gettext("previous snapshot taken.")); 7890 7891 case IMPORT_PROP_BEGUN: 7892 return (gettext("some properties imported.")); 7893 7894 case IMPORT_PROP_DONE: 7895 return (gettext("properties imported.")); 7896 7897 case IMPORT_COMPLETE: 7898 return (gettext("imported.")); 7899 7900 case IMPORT_REFRESHED: 7901 return (gettext("refresh requested.")); 7902 7903 default: 7904 #ifndef NDEBUG 7905 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7906 __FILE__, __LINE__, st); 7907 #endif 7908 abort(); 7909 /* NOTREACHED */ 7910 } 7911 } 7912 7913 /* 7914 * Returns 7915 * 0 - success 7916 * - fmri wasn't found (error printed) 7917 * - entity was deleted (error printed) 7918 * - backend denied access (error printed) 7919 * ENOMEM - out of memory (error printed) 7920 * ECONNABORTED - repository connection broken (error printed) 7921 * EPERM - permission denied (error printed) 7922 * -1 - unknown libscf error (error printed) 7923 */ 7924 static int 7925 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7926 { 7927 scf_error_t serr; 7928 void *ent; 7929 int issvc; 7930 int r; 7931 7932 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7933 const char *dpt_deleted = gettext("Could not refresh %s " 7934 "(dependent \"%s\" of %s) (deleted).\n"); 7935 7936 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7937 switch (serr) { 7938 case SCF_ERROR_NONE: 7939 break; 7940 7941 case SCF_ERROR_NO_MEMORY: 7942 if (name == NULL) 7943 warn(gettext("Could not refresh %s (out of memory).\n"), 7944 fmri); 7945 else 7946 warn(gettext("Could not refresh %s " 7947 "(dependent \"%s\" of %s) (out of memory).\n"), 7948 fmri, name, d_fmri); 7949 return (ENOMEM); 7950 7951 case SCF_ERROR_NOT_FOUND: 7952 if (name == NULL) 7953 warn(deleted, fmri); 7954 else 7955 warn(dpt_deleted, fmri, name, d_fmri); 7956 return (0); 7957 7958 case SCF_ERROR_INVALID_ARGUMENT: 7959 case SCF_ERROR_CONSTRAINT_VIOLATED: 7960 default: 7961 bad_error("fmri_to_entity", serr); 7962 } 7963 7964 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7965 switch (r) { 7966 case 0: 7967 break; 7968 7969 case ECONNABORTED: 7970 if (name != NULL) 7971 warn(gettext("Could not refresh %s " 7972 "(dependent \"%s\" of %s) " 7973 "(repository connection broken).\n"), fmri, name, 7974 d_fmri); 7975 return (r); 7976 7977 case ECANCELED: 7978 if (name == NULL) 7979 warn(deleted, fmri); 7980 else 7981 warn(dpt_deleted, fmri, name, d_fmri); 7982 return (0); 7983 7984 case EACCES: 7985 if (!g_verbose) 7986 return (0); 7987 if (name == NULL) 7988 warn(gettext("Could not refresh %s " 7989 "(backend access denied).\n"), fmri); 7990 else 7991 warn(gettext("Could not refresh %s " 7992 "(dependent \"%s\" of %s) " 7993 "(backend access denied).\n"), fmri, name, d_fmri); 7994 return (0); 7995 7996 case EPERM: 7997 if (name == NULL) 7998 warn(gettext("Could not refresh %s " 7999 "(permission denied).\n"), fmri); 8000 else 8001 warn(gettext("Could not refresh %s " 8002 "(dependent \"%s\" of %s) " 8003 "(permission denied).\n"), fmri, name, d_fmri); 8004 return (r); 8005 8006 case ENOSPC: 8007 if (name == NULL) 8008 warn(gettext("Could not refresh %s " 8009 "(repository server out of resources).\n"), 8010 fmri); 8011 else 8012 warn(gettext("Could not refresh %s " 8013 "(dependent \"%s\" of %s) " 8014 "(repository server out of resources).\n"), 8015 fmri, name, d_fmri); 8016 return (r); 8017 8018 case -1: 8019 scfwarn(); 8020 return (r); 8021 8022 default: 8023 bad_error("refresh_entity", r); 8024 } 8025 8026 if (issvc) 8027 scf_service_destroy(ent); 8028 else 8029 scf_instance_destroy(ent); 8030 8031 return (0); 8032 } 8033 8034 static int 8035 alloc_imp_globals() 8036 { 8037 int r; 8038 8039 const char * const emsg_nomem = gettext("Out of memory.\n"); 8040 const char * const emsg_nores = 8041 gettext("svc.configd is out of resources.\n"); 8042 8043 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 8044 max_scf_name_len : max_scf_fmri_len) + 1; 8045 8046 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 8047 (imp_svc = scf_service_create(g_hndl)) == NULL || 8048 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 8049 (imp_inst = scf_instance_create(g_hndl)) == NULL || 8050 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 8051 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 8052 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 8053 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 8054 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 8055 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8056 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 8057 (imp_pg = scf_pg_create(g_hndl)) == NULL || 8058 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 8059 (imp_prop = scf_property_create(g_hndl)) == NULL || 8060 (imp_iter = scf_iter_create(g_hndl)) == NULL || 8061 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 8062 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 8063 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 8064 (imp_str = malloc(imp_str_sz)) == NULL || 8065 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 8066 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 8067 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 8068 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 8069 (ud_inst = scf_instance_create(g_hndl)) == NULL || 8070 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 8071 (ud_pg = scf_pg_create(g_hndl)) == NULL || 8072 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 8073 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 8074 (ud_prop = scf_property_create(g_hndl)) == NULL || 8075 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 8076 (ud_val = scf_value_create(g_hndl)) == NULL || 8077 (ud_iter = scf_iter_create(g_hndl)) == NULL || 8078 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 8079 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 8080 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 8081 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 8082 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 8083 if (scf_error() == SCF_ERROR_NO_RESOURCES) 8084 warn(emsg_nores); 8085 else 8086 warn(emsg_nomem); 8087 8088 return (-1); 8089 } 8090 8091 r = load_init(); 8092 switch (r) { 8093 case 0: 8094 break; 8095 8096 case ENOMEM: 8097 warn(emsg_nomem); 8098 return (-1); 8099 8100 default: 8101 bad_error("load_init", r); 8102 } 8103 8104 return (0); 8105 } 8106 8107 static void 8108 free_imp_globals() 8109 { 8110 pgroup_t *old_dpt; 8111 void *cookie; 8112 8113 load_fini(); 8114 8115 free(ud_ctarg); 8116 free(ud_oldtarg); 8117 free(ud_name); 8118 ud_ctarg = ud_oldtarg = ud_name = NULL; 8119 8120 scf_transaction_destroy(ud_tx); 8121 ud_tx = NULL; 8122 scf_iter_destroy(ud_iter); 8123 scf_iter_destroy(ud_iter2); 8124 ud_iter = ud_iter2 = NULL; 8125 scf_value_destroy(ud_val); 8126 ud_val = NULL; 8127 scf_property_destroy(ud_prop); 8128 scf_property_destroy(ud_dpt_prop); 8129 ud_prop = ud_dpt_prop = NULL; 8130 scf_pg_destroy(ud_pg); 8131 scf_pg_destroy(ud_cur_depts_pg); 8132 scf_pg_destroy(ud_run_dpts_pg); 8133 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 8134 scf_snaplevel_destroy(ud_snpl); 8135 ud_snpl = NULL; 8136 scf_instance_destroy(ud_inst); 8137 ud_inst = NULL; 8138 8139 free(imp_str); 8140 free(imp_tsname); 8141 free(imp_fe1); 8142 free(imp_fe2); 8143 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 8144 8145 cookie = NULL; 8146 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 8147 NULL) { 8148 free((char *)old_dpt->sc_pgroup_name); 8149 free((char *)old_dpt->sc_pgroup_fmri); 8150 internal_pgroup_free(old_dpt); 8151 } 8152 uu_list_destroy(imp_deleted_dpts); 8153 8154 scf_transaction_destroy(imp_tx); 8155 imp_tx = NULL; 8156 scf_iter_destroy(imp_iter); 8157 scf_iter_destroy(imp_rpg_iter); 8158 scf_iter_destroy(imp_up_iter); 8159 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 8160 scf_property_destroy(imp_prop); 8161 imp_prop = NULL; 8162 scf_pg_destroy(imp_pg); 8163 scf_pg_destroy(imp_pg2); 8164 imp_pg = imp_pg2 = NULL; 8165 scf_snaplevel_destroy(imp_snpl); 8166 scf_snaplevel_destroy(imp_rsnpl); 8167 imp_snpl = imp_rsnpl = NULL; 8168 scf_snapshot_destroy(imp_snap); 8169 scf_snapshot_destroy(imp_lisnap); 8170 scf_snapshot_destroy(imp_tlisnap); 8171 scf_snapshot_destroy(imp_rsnap); 8172 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 8173 scf_instance_destroy(imp_inst); 8174 scf_instance_destroy(imp_tinst); 8175 imp_inst = imp_tinst = NULL; 8176 scf_service_destroy(imp_svc); 8177 scf_service_destroy(imp_tsvc); 8178 imp_svc = imp_tsvc = NULL; 8179 scf_scope_destroy(imp_scope); 8180 imp_scope = NULL; 8181 8182 load_fini(); 8183 } 8184 8185 int 8186 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 8187 { 8188 scf_callback_t cbdata; 8189 int result = 0; 8190 entity_t *svc, *inst; 8191 uu_list_t *insts; 8192 int r; 8193 pgroup_t *old_dpt; 8194 int annotation_set = 0; 8195 8196 const char * const emsg_nomem = gettext("Out of memory.\n"); 8197 const char * const emsg_nores = 8198 gettext("svc.configd is out of resources.\n"); 8199 8200 lscf_prep_hndl(); 8201 8202 if (alloc_imp_globals()) 8203 goto out; 8204 8205 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 8206 switch (scf_error()) { 8207 case SCF_ERROR_CONNECTION_BROKEN: 8208 warn(gettext("Repository connection broken.\n")); 8209 repository_teardown(); 8210 result = -1; 8211 goto out; 8212 8213 case SCF_ERROR_NOT_FOUND: 8214 case SCF_ERROR_INVALID_ARGUMENT: 8215 case SCF_ERROR_NOT_BOUND: 8216 case SCF_ERROR_HANDLE_MISMATCH: 8217 default: 8218 bad_error("scf_handle_get_scope", scf_error()); 8219 } 8220 } 8221 8222 /* Set up the auditing annotation. */ 8223 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 8224 annotation_set = 1; 8225 } else { 8226 switch (scf_error()) { 8227 case SCF_ERROR_CONNECTION_BROKEN: 8228 warn(gettext("Repository connection broken.\n")); 8229 repository_teardown(); 8230 result = -1; 8231 goto out; 8232 8233 case SCF_ERROR_INVALID_ARGUMENT: 8234 case SCF_ERROR_NOT_BOUND: 8235 case SCF_ERROR_NO_RESOURCES: 8236 case SCF_ERROR_INTERNAL: 8237 bad_error("_scf_set_annotation", scf_error()); 8238 /* NOTREACHED */ 8239 8240 default: 8241 /* 8242 * Do not terminate import because of inability to 8243 * generate annotation audit event. 8244 */ 8245 warn(gettext("_scf_set_annotation() unexpectedly " 8246 "failed with return code of %d\n"), scf_error()); 8247 break; 8248 } 8249 } 8250 8251 /* 8252 * Clear the sc_import_state's of all services & instances so we can 8253 * report how far we got if we fail. 8254 */ 8255 for (svc = uu_list_first(bndl->sc_bundle_services); 8256 svc != NULL; 8257 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8258 svc->sc_import_state = 0; 8259 8260 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 8261 clear_int, (void *)offsetof(entity_t, sc_import_state), 8262 UU_DEFAULT) != 0) 8263 bad_error("uu_list_walk", uu_error()); 8264 } 8265 8266 cbdata.sc_handle = g_hndl; 8267 cbdata.sc_parent = imp_scope; 8268 cbdata.sc_flags = flags; 8269 cbdata.sc_general = NULL; 8270 8271 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 8272 &cbdata, UU_DEFAULT) == 0) { 8273 char *eptr; 8274 /* Success. Refresh everything. */ 8275 8276 if (flags & SCI_NOREFRESH || no_refresh) { 8277 no_refresh = 0; 8278 result = 0; 8279 goto out; 8280 } 8281 8282 for (svc = uu_list_first(bndl->sc_bundle_services); 8283 svc != NULL; 8284 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8285 pgroup_t *dpt; 8286 8287 insts = svc->sc_u.sc_service.sc_service_instances; 8288 8289 for (inst = uu_list_first(insts); 8290 inst != NULL; 8291 inst = uu_list_next(insts, inst)) { 8292 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 8293 switch (r) { 8294 case 0: 8295 break; 8296 8297 case ENOMEM: 8298 case ECONNABORTED: 8299 case EPERM: 8300 case -1: 8301 goto progress; 8302 8303 default: 8304 bad_error("imp_refresh_fmri", r); 8305 } 8306 8307 inst->sc_import_state = IMPORT_REFRESHED; 8308 8309 for (dpt = uu_list_first(inst->sc_dependents); 8310 dpt != NULL; 8311 dpt = uu_list_next(inst->sc_dependents, 8312 dpt)) 8313 if (imp_refresh_fmri( 8314 dpt->sc_pgroup_fmri, 8315 dpt->sc_pgroup_name, 8316 inst->sc_fmri) != 0) 8317 goto progress; 8318 } 8319 8320 for (dpt = uu_list_first(svc->sc_dependents); 8321 dpt != NULL; 8322 dpt = uu_list_next(svc->sc_dependents, dpt)) 8323 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 8324 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 8325 goto progress; 8326 } 8327 8328 for (old_dpt = uu_list_first(imp_deleted_dpts); 8329 old_dpt != NULL; 8330 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 8331 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8332 old_dpt->sc_pgroup_name, 8333 old_dpt->sc_parent->sc_fmri) != 0) 8334 goto progress; 8335 8336 result = 0; 8337 8338 /* 8339 * This snippet of code assumes that we are running svccfg as we 8340 * normally do -- witih svc.startd running. Of course, that is 8341 * not actually the case all the time because we also use a 8342 * varient of svc.configd and svccfg which are only meant to 8343 * run during the build process. During this time we have no 8344 * svc.startd, so this check would hang the build process. 8345 * 8346 * However, we've also given other consolidations, a bit of a 8347 * means to tie themselves into a knot. They're not properly 8348 * using the native build equivalents, but they've been getting 8349 * away with it anyways. Therefore, if we've found that 8350 * SVCCFG_REPOSITORY is set indicating that a separate configd 8351 * should be spun up, then we have to assume it's not using a 8352 * startd and we should not do this check. 8353 */ 8354 #ifndef NATIVE_BUILD 8355 /* 8356 * Verify that the restarter group is preset 8357 */ 8358 eptr = getenv("SVCCFG_REPOSITORY"); 8359 for (svc = uu_list_first(bndl->sc_bundle_services); 8360 svc != NULL && eptr == NULL; 8361 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8362 8363 insts = svc->sc_u.sc_service.sc_service_instances; 8364 8365 for (inst = uu_list_first(insts); 8366 inst != NULL; 8367 inst = uu_list_next(insts, inst)) { 8368 if (lscf_instance_verify(imp_scope, svc, 8369 inst) != 0) 8370 goto progress; 8371 } 8372 } 8373 #endif 8374 goto out; 8375 8376 } 8377 8378 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8379 bad_error("uu_list_walk", uu_error()); 8380 8381 printerr: 8382 /* If the error hasn't been printed yet, do so here. */ 8383 switch (cbdata.sc_err) { 8384 case ECONNABORTED: 8385 warn(gettext("Repository connection broken.\n")); 8386 break; 8387 8388 case ENOMEM: 8389 warn(emsg_nomem); 8390 break; 8391 8392 case ENOSPC: 8393 warn(emsg_nores); 8394 break; 8395 8396 case EROFS: 8397 warn(gettext("Repository is read-only.\n")); 8398 break; 8399 8400 case EACCES: 8401 warn(gettext("Repository backend denied access.\n")); 8402 break; 8403 8404 case EPERM: 8405 case EINVAL: 8406 case EEXIST: 8407 case EBUSY: 8408 case EBADF: 8409 case -1: 8410 break; 8411 8412 default: 8413 bad_error("lscf_service_import", cbdata.sc_err); 8414 } 8415 8416 progress: 8417 warn(gettext("Import of %s failed. Progress:\n"), filename); 8418 8419 for (svc = uu_list_first(bndl->sc_bundle_services); 8420 svc != NULL; 8421 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8422 insts = svc->sc_u.sc_service.sc_service_instances; 8423 8424 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 8425 import_progress(svc->sc_import_state)); 8426 8427 for (inst = uu_list_first(insts); 8428 inst != NULL; 8429 inst = uu_list_next(insts, inst)) 8430 warn(gettext(" Instance \"%s\": %s\n"), 8431 inst->sc_name, 8432 import_progress(inst->sc_import_state)); 8433 } 8434 8435 if (cbdata.sc_err == ECONNABORTED) 8436 repository_teardown(); 8437 8438 8439 result = -1; 8440 8441 out: 8442 if (annotation_set != 0) { 8443 /* Turn off annotation. It is no longer needed. */ 8444 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8445 } 8446 8447 free_imp_globals(); 8448 8449 return (result); 8450 } 8451 8452 /* 8453 * _lscf_import_err() summarize the error handling returned by 8454 * lscf_import_{instance | service}_pgs 8455 * Return values are: 8456 * IMPORT_NEXT 8457 * IMPORT_OUT 8458 * IMPORT_BAD 8459 */ 8460 8461 #define IMPORT_BAD -1 8462 #define IMPORT_NEXT 0 8463 #define IMPORT_OUT 1 8464 8465 static int 8466 _lscf_import_err(int err, const char *fmri) 8467 { 8468 switch (err) { 8469 case 0: 8470 if (g_verbose) 8471 warn(gettext("%s updated.\n"), fmri); 8472 return (IMPORT_NEXT); 8473 8474 case ECONNABORTED: 8475 warn(gettext("Could not update %s " 8476 "(repository connection broken).\n"), fmri); 8477 return (IMPORT_OUT); 8478 8479 case ENOMEM: 8480 warn(gettext("Could not update %s (out of memory).\n"), fmri); 8481 return (IMPORT_OUT); 8482 8483 case ENOSPC: 8484 warn(gettext("Could not update %s " 8485 "(repository server out of resources).\n"), fmri); 8486 return (IMPORT_OUT); 8487 8488 case ECANCELED: 8489 warn(gettext( 8490 "Could not update %s (deleted).\n"), fmri); 8491 return (IMPORT_NEXT); 8492 8493 case EPERM: 8494 case EINVAL: 8495 case EBUSY: 8496 return (IMPORT_NEXT); 8497 8498 case EROFS: 8499 warn(gettext("Could not update %s (repository read-only).\n"), 8500 fmri); 8501 return (IMPORT_OUT); 8502 8503 case EACCES: 8504 warn(gettext("Could not update %s " 8505 "(backend access denied).\n"), fmri); 8506 return (IMPORT_NEXT); 8507 8508 case EEXIST: 8509 default: 8510 return (IMPORT_BAD); 8511 } 8512 8513 /*NOTREACHED*/ 8514 } 8515 8516 /* 8517 * The global imp_svc and imp_inst should be set by the caller in the 8518 * check to make sure the service and instance exist that the apply is 8519 * working on. 8520 */ 8521 static int 8522 lscf_dependent_apply(void *dpg, void *e) 8523 { 8524 scf_callback_t cb; 8525 pgroup_t *dpt_pgroup = dpg; 8526 pgroup_t *deldpt; 8527 entity_t *ent = e; 8528 int tissvc; 8529 void *sc_ent, *tent; 8530 scf_error_t serr; 8531 int r; 8532 8533 const char * const dependents = "dependents"; 8534 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT); 8535 8536 if (issvc) 8537 sc_ent = imp_svc; 8538 else 8539 sc_ent = imp_inst; 8540 8541 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg, 8542 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 || 8543 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name, 8544 imp_prop) != 0) { 8545 switch (scf_error()) { 8546 case SCF_ERROR_NOT_FOUND: 8547 case SCF_ERROR_DELETED: 8548 break; 8549 8550 case SCF_ERROR_CONNECTION_BROKEN: 8551 case SCF_ERROR_NOT_SET: 8552 case SCF_ERROR_INVALID_ARGUMENT: 8553 case SCF_ERROR_HANDLE_MISMATCH: 8554 case SCF_ERROR_NOT_BOUND: 8555 default: 8556 bad_error("entity_get_pg", scf_error()); 8557 } 8558 } else { 8559 /* 8560 * Found the dependents/<wip dep> so check to 8561 * see if the service is different. If so 8562 * store the service for later refresh, and 8563 * delete the wip dependency from the service 8564 */ 8565 if (scf_property_get_value(imp_prop, ud_val) != 0) { 8566 switch (scf_error()) { 8567 case SCF_ERROR_DELETED: 8568 break; 8569 8570 case SCF_ERROR_CONNECTION_BROKEN: 8571 case SCF_ERROR_NOT_SET: 8572 case SCF_ERROR_INVALID_ARGUMENT: 8573 case SCF_ERROR_HANDLE_MISMATCH: 8574 case SCF_ERROR_NOT_BOUND: 8575 default: 8576 bad_error("scf_property_get_value", 8577 scf_error()); 8578 } 8579 } 8580 8581 if (scf_value_get_as_string(ud_val, ud_oldtarg, 8582 max_scf_value_len + 1) < 0) 8583 bad_error("scf_value_get_as_string", scf_error()); 8584 8585 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 8586 switch (r) { 8587 case 1: 8588 break; 8589 case 0: 8590 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent, 8591 &tissvc)) != SCF_ERROR_NONE) { 8592 if (serr == SCF_ERROR_NOT_FOUND) { 8593 break; 8594 } else { 8595 bad_error("fmri_to_entity", serr); 8596 } 8597 } 8598 8599 if (entity_get_pg(tent, tissvc, 8600 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) { 8601 serr = scf_error(); 8602 if (serr == SCF_ERROR_NOT_FOUND || 8603 serr == SCF_ERROR_DELETED) { 8604 break; 8605 } else { 8606 bad_error("entity_get_pg", scf_error()); 8607 } 8608 } 8609 8610 if (scf_pg_delete(imp_pg) != 0) { 8611 serr = scf_error(); 8612 if (serr == SCF_ERROR_NOT_FOUND || 8613 serr == SCF_ERROR_DELETED) { 8614 break; 8615 } else { 8616 bad_error("scf_pg_delete", scf_error()); 8617 } 8618 } 8619 8620 deldpt = internal_pgroup_new(); 8621 if (deldpt == NULL) 8622 return (ENOMEM); 8623 deldpt->sc_pgroup_name = 8624 strdup(dpt_pgroup->sc_pgroup_name); 8625 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg); 8626 if (deldpt->sc_pgroup_name == NULL || 8627 deldpt->sc_pgroup_fmri == NULL) 8628 return (ENOMEM); 8629 deldpt->sc_parent = (entity_t *)ent; 8630 if (uu_list_insert_after(imp_deleted_dpts, NULL, 8631 deldpt) != 0) 8632 uu_die(gettext("libuutil error: %s\n"), 8633 uu_strerror(uu_error())); 8634 8635 break; 8636 default: 8637 bad_error("fmri_equal", r); 8638 } 8639 } 8640 8641 cb.sc_handle = g_hndl; 8642 cb.sc_parent = ent; 8643 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT; 8644 cb.sc_source_fmri = ent->sc_fmri; 8645 cb.sc_target_fmri = ent->sc_fmri; 8646 cb.sc_trans = NULL; 8647 cb.sc_flags = SCI_FORCE; 8648 8649 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT) 8650 return (UU_WALK_ERROR); 8651 8652 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL); 8653 switch (r) { 8654 case 0: 8655 break; 8656 8657 case ENOMEM: 8658 case ECONNABORTED: 8659 case EPERM: 8660 case -1: 8661 warn(gettext("Unable to refresh \"%s\"\n"), 8662 dpt_pgroup->sc_pgroup_fmri); 8663 return (UU_WALK_ERROR); 8664 8665 default: 8666 bad_error("imp_refresh_fmri", r); 8667 } 8668 8669 return (UU_WALK_NEXT); 8670 } 8671 8672 /* 8673 * Returns 8674 * 0 - success 8675 * -1 - lscf_import_instance_pgs() failed. 8676 */ 8677 int 8678 lscf_bundle_apply(bundle_t *bndl, const char *file) 8679 { 8680 pgroup_t *old_dpt; 8681 entity_t *svc, *inst; 8682 int annotation_set = 0; 8683 int ret = 0; 8684 int r = 0; 8685 8686 lscf_prep_hndl(); 8687 8688 if ((ret = alloc_imp_globals())) 8689 goto out; 8690 8691 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) 8692 scfdie(); 8693 8694 /* 8695 * Set the strings to be used for the security audit annotation 8696 * event. 8697 */ 8698 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 8699 annotation_set = 1; 8700 } else { 8701 switch (scf_error()) { 8702 case SCF_ERROR_CONNECTION_BROKEN: 8703 warn(gettext("Repository connection broken.\n")); 8704 goto out; 8705 8706 case SCF_ERROR_INVALID_ARGUMENT: 8707 case SCF_ERROR_NOT_BOUND: 8708 case SCF_ERROR_NO_RESOURCES: 8709 case SCF_ERROR_INTERNAL: 8710 bad_error("_scf_set_annotation", scf_error()); 8711 /* NOTREACHED */ 8712 8713 default: 8714 /* 8715 * Do not abort apply operation because of 8716 * inability to create annotation audit event. 8717 */ 8718 warn(gettext("_scf_set_annotation() unexpectedly " 8719 "failed with return code of %d\n"), scf_error()); 8720 break; 8721 } 8722 } 8723 8724 for (svc = uu_list_first(bndl->sc_bundle_services); 8725 svc != NULL; 8726 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8727 int refresh = 0; 8728 8729 if (scf_scope_get_service(imp_scope, svc->sc_name, 8730 imp_svc) != 0) { 8731 switch (scf_error()) { 8732 case SCF_ERROR_NOT_FOUND: 8733 if (g_verbose) 8734 warn(gettext("Ignoring nonexistent " 8735 "service %s.\n"), svc->sc_name); 8736 continue; 8737 8738 default: 8739 scfdie(); 8740 } 8741 } 8742 8743 /* 8744 * If there were missing types in the profile, then need to 8745 * attempt to find the types. 8746 */ 8747 if (svc->sc_miss_type) { 8748 if (uu_list_numnodes(svc->sc_pgroups) && 8749 uu_list_walk(svc->sc_pgroups, find_current_pg_type, 8750 svc, UU_DEFAULT) != 0) { 8751 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8752 bad_error("uu_list_walk", uu_error()); 8753 8754 ret = -1; 8755 continue; 8756 } 8757 8758 for (inst = uu_list_first( 8759 svc->sc_u.sc_service.sc_service_instances); 8760 inst != NULL; 8761 inst = uu_list_next( 8762 svc->sc_u.sc_service.sc_service_instances, inst)) { 8763 /* 8764 * If the instance doesn't exist just 8765 * skip to the next instance and let the 8766 * import note the missing instance. 8767 */ 8768 if (scf_service_get_instance(imp_svc, 8769 inst->sc_name, imp_inst) != 0) 8770 continue; 8771 8772 if (uu_list_walk(inst->sc_pgroups, 8773 find_current_pg_type, inst, 8774 UU_DEFAULT) != 0) { 8775 if (uu_error() != 8776 UU_ERROR_CALLBACK_FAILED) 8777 bad_error("uu_list_walk", 8778 uu_error()); 8779 8780 ret = -1; 8781 inst->sc_miss_type = B_TRUE; 8782 } 8783 } 8784 } 8785 8786 /* 8787 * if we have pgs in the profile, we need to refresh ALL 8788 * instances of the service 8789 */ 8790 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 8791 refresh = 1; 8792 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc, 8793 SCI_FORCE | SCI_KEEP); 8794 switch (_lscf_import_err(r, svc->sc_fmri)) { 8795 case IMPORT_NEXT: 8796 break; 8797 8798 case IMPORT_OUT: 8799 goto out; 8800 8801 case IMPORT_BAD: 8802 default: 8803 bad_error("lscf_import_service_pgs", r); 8804 } 8805 } 8806 8807 if (uu_list_numnodes(svc->sc_dependents) != 0) { 8808 uu_list_walk(svc->sc_dependents, 8809 lscf_dependent_apply, svc, UU_DEFAULT); 8810 } 8811 8812 for (inst = uu_list_first( 8813 svc->sc_u.sc_service.sc_service_instances); 8814 inst != NULL; 8815 inst = uu_list_next( 8816 svc->sc_u.sc_service.sc_service_instances, inst)) { 8817 /* 8818 * This instance still has missing types 8819 * so skip it. 8820 */ 8821 if (inst->sc_miss_type) { 8822 if (g_verbose) 8823 warn(gettext("Ignoring instance " 8824 "%s:%s with missing types\n"), 8825 inst->sc_parent->sc_name, 8826 inst->sc_name); 8827 8828 continue; 8829 } 8830 8831 if (scf_service_get_instance(imp_svc, inst->sc_name, 8832 imp_inst) != 0) { 8833 switch (scf_error()) { 8834 case SCF_ERROR_NOT_FOUND: 8835 if (g_verbose) 8836 warn(gettext("Ignoring " 8837 "nonexistant instance " 8838 "%s:%s.\n"), 8839 inst->sc_parent->sc_name, 8840 inst->sc_name); 8841 continue; 8842 8843 default: 8844 scfdie(); 8845 } 8846 } 8847 8848 /* 8849 * If the instance does not have a general/enabled 8850 * property and no last-import snapshot then the 8851 * instance is not a fully installed instance and 8852 * should not have a profile applied to it. 8853 * 8854 * This could happen if a service/instance declares 8855 * a dependent on behalf of another service/instance. 8856 * 8857 */ 8858 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 8859 imp_snap) != 0) { 8860 if (scf_instance_get_pg(imp_inst, 8861 SCF_PG_GENERAL, imp_pg) != 0 || 8862 scf_pg_get_property(imp_pg, 8863 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 8864 if (g_verbose) 8865 warn(gettext("Ignoreing " 8866 "partial instance " 8867 "%s:%s.\n"), 8868 inst->sc_parent->sc_name, 8869 inst->sc_name); 8870 continue; 8871 } 8872 } 8873 8874 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, 8875 inst, SCI_FORCE | SCI_KEEP); 8876 switch (_lscf_import_err(r, inst->sc_fmri)) { 8877 case IMPORT_NEXT: 8878 break; 8879 8880 case IMPORT_OUT: 8881 goto out; 8882 8883 case IMPORT_BAD: 8884 default: 8885 bad_error("lscf_import_instance_pgs", r); 8886 } 8887 8888 if (uu_list_numnodes(inst->sc_dependents) != 0) { 8889 uu_list_walk(inst->sc_dependents, 8890 lscf_dependent_apply, inst, UU_DEFAULT); 8891 } 8892 8893 /* refresh only if there is no pgs in the service */ 8894 if (refresh == 0) 8895 (void) refresh_entity(0, imp_inst, 8896 inst->sc_fmri, NULL, NULL, NULL); 8897 } 8898 8899 if (refresh == 1) { 8900 char *name_buf = safe_malloc(max_scf_name_len + 1); 8901 8902 (void) refresh_entity(1, imp_svc, svc->sc_name, 8903 imp_inst, imp_iter, name_buf); 8904 free(name_buf); 8905 } 8906 8907 for (old_dpt = uu_list_first(imp_deleted_dpts); 8908 old_dpt != NULL; 8909 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) { 8910 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8911 old_dpt->sc_pgroup_name, 8912 old_dpt->sc_parent->sc_fmri) != 0) { 8913 warn(gettext("Unable to refresh \"%s\"\n"), 8914 old_dpt->sc_pgroup_fmri); 8915 } 8916 } 8917 } 8918 8919 out: 8920 if (annotation_set) { 8921 /* Remove security audit annotation strings. */ 8922 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8923 } 8924 8925 free_imp_globals(); 8926 return (ret); 8927 } 8928 8929 8930 /* 8931 * Export. These functions create and output an XML tree of a service 8932 * description from the repository. This is largely the inverse of 8933 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 8934 * 8935 * - We must include any properties which are not represented specifically by 8936 * a service manifest, e.g., properties created by an admin post-import. To 8937 * do so we'll iterate through all properties and deal with each 8938 * apropriately. 8939 * 8940 * - Children of services and instances must must be in the order set by the 8941 * DTD, but we iterate over the properties in undefined order. The elements 8942 * are not easily (or efficiently) sortable by name. Since there's a fixed 8943 * number of classes of them, however, we'll keep the classes separate and 8944 * assemble them in order. 8945 */ 8946 8947 /* 8948 * Convenience function to handle xmlSetProp errors (and type casting). 8949 */ 8950 static void 8951 safe_setprop(xmlNodePtr n, const char *name, const char *val) 8952 { 8953 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 8954 uu_die(gettext("Could not set XML property.\n")); 8955 } 8956 8957 /* 8958 * Convenience function to set an XML attribute to the single value of an 8959 * astring property. If the value happens to be the default, don't set the 8960 * attribute. "dval" should be the default value supplied by the DTD, or 8961 * NULL for no default. 8962 */ 8963 static int 8964 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 8965 const char *name, const char *dval) 8966 { 8967 scf_value_t *val; 8968 ssize_t len; 8969 char *str; 8970 8971 val = scf_value_create(g_hndl); 8972 if (val == NULL) 8973 scfdie(); 8974 8975 if (prop_get_val(prop, val) != 0) { 8976 scf_value_destroy(val); 8977 return (-1); 8978 } 8979 8980 len = scf_value_get_as_string(val, NULL, 0); 8981 if (len < 0) 8982 scfdie(); 8983 8984 str = safe_malloc(len + 1); 8985 8986 if (scf_value_get_as_string(val, str, len + 1) < 0) 8987 scfdie(); 8988 8989 scf_value_destroy(val); 8990 8991 if (dval == NULL || strcmp(str, dval) != 0) 8992 safe_setprop(n, name, str); 8993 8994 free(str); 8995 8996 return (0); 8997 } 8998 8999 /* 9000 * As above, but the attribute is always set. 9001 */ 9002 static int 9003 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 9004 { 9005 return (set_attr_from_prop_default(prop, n, name, NULL)); 9006 } 9007 9008 /* 9009 * Dump the given document onto f, with "'s replaced by ''s. 9010 */ 9011 static int 9012 write_service_bundle(xmlDocPtr doc, FILE *f) 9013 { 9014 xmlChar *mem; 9015 int sz, i; 9016 9017 mem = NULL; 9018 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 9019 9020 if (mem == NULL) { 9021 semerr(gettext("Could not dump XML tree.\n")); 9022 return (-1); 9023 } 9024 9025 /* 9026 * Fortunately libxml produces " instead of ", so we can blindly 9027 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 9028 * ' code?! 9029 */ 9030 for (i = 0; i < sz; ++i) { 9031 char c = (char)mem[i]; 9032 9033 if (c == '"') 9034 (void) fputc('\'', f); 9035 else if (c == '\'') 9036 (void) fwrite("'", sizeof ("'") - 1, 1, f); 9037 else 9038 (void) fputc(c, f); 9039 } 9040 9041 return (0); 9042 } 9043 9044 /* 9045 * Create the DOM elements in elts necessary to (generically) represent prop 9046 * (i.e., a property or propval element). If the name of the property is 9047 * known, it should be passed as name_arg. Otherwise, pass NULL. 9048 */ 9049 static void 9050 export_property(scf_property_t *prop, const char *name_arg, 9051 struct pg_elts *elts, int flags) 9052 { 9053 const char *type; 9054 scf_error_t err = 0; 9055 xmlNodePtr pnode, lnode; 9056 char *lnname; 9057 int ret; 9058 9059 /* name */ 9060 if (name_arg != NULL) { 9061 (void) strcpy(exp_str, name_arg); 9062 } else { 9063 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 9064 scfdie(); 9065 } 9066 9067 /* type */ 9068 type = prop_to_typestr(prop); 9069 if (type == NULL) 9070 uu_die(gettext("Can't export property %s: unknown type.\n"), 9071 exp_str); 9072 9073 /* If we're exporting values, and there's just one, export it here. */ 9074 if (!(flags & SCE_ALL_VALUES)) 9075 goto empty; 9076 9077 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 9078 xmlNodePtr n; 9079 9080 /* Single value, so use propval */ 9081 n = xmlNewNode(NULL, (xmlChar *)"propval"); 9082 if (n == NULL) 9083 uu_die(emsg_create_xml); 9084 9085 safe_setprop(n, name_attr, exp_str); 9086 safe_setprop(n, type_attr, type); 9087 9088 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9089 scfdie(); 9090 safe_setprop(n, value_attr, exp_str); 9091 9092 if (elts->propvals == NULL) 9093 elts->propvals = n; 9094 else 9095 (void) xmlAddSibling(elts->propvals, n); 9096 9097 return; 9098 } 9099 9100 err = scf_error(); 9101 9102 if (err == SCF_ERROR_PERMISSION_DENIED) { 9103 semerr(emsg_permission_denied); 9104 return; 9105 } 9106 9107 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 9108 err != SCF_ERROR_NOT_FOUND && 9109 err != SCF_ERROR_PERMISSION_DENIED) 9110 scfdie(); 9111 9112 empty: 9113 /* Multiple (or no) values, so use property */ 9114 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 9115 if (pnode == NULL) 9116 uu_die(emsg_create_xml); 9117 9118 safe_setprop(pnode, name_attr, exp_str); 9119 safe_setprop(pnode, type_attr, type); 9120 9121 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 9122 lnname = uu_msprintf("%s_list", type); 9123 if (lnname == NULL) 9124 uu_die(gettext("Could not create string")); 9125 9126 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 9127 if (lnode == NULL) 9128 uu_die(emsg_create_xml); 9129 9130 uu_free(lnname); 9131 9132 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 9133 scfdie(); 9134 9135 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 9136 1) { 9137 xmlNodePtr vn; 9138 9139 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 9140 NULL); 9141 if (vn == NULL) 9142 uu_die(emsg_create_xml); 9143 9144 if (scf_value_get_as_string(exp_val, exp_str, 9145 exp_str_sz) < 0) 9146 scfdie(); 9147 safe_setprop(vn, value_attr, exp_str); 9148 } 9149 if (ret != 0) 9150 scfdie(); 9151 } 9152 9153 if (elts->properties == NULL) 9154 elts->properties = pnode; 9155 else 9156 (void) xmlAddSibling(elts->properties, pnode); 9157 } 9158 9159 /* 9160 * Add a property_group element for this property group to elts. 9161 */ 9162 static void 9163 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 9164 { 9165 xmlNodePtr n; 9166 struct pg_elts elts; 9167 int ret; 9168 boolean_t read_protected; 9169 9170 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 9171 9172 /* name */ 9173 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9174 scfdie(); 9175 safe_setprop(n, name_attr, exp_str); 9176 9177 /* type */ 9178 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 9179 scfdie(); 9180 safe_setprop(n, type_attr, exp_str); 9181 9182 /* properties */ 9183 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9184 scfdie(); 9185 9186 (void) memset(&elts, 0, sizeof (elts)); 9187 9188 /* 9189 * If this property group is not read protected, we always want to 9190 * output all the values. Otherwise, we only output the values if the 9191 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 9192 */ 9193 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 9194 scfdie(); 9195 9196 if (!read_protected) 9197 flags |= SCE_ALL_VALUES; 9198 9199 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9200 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9201 scfdie(); 9202 9203 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9204 xmlNodePtr m; 9205 9206 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9207 if (m == NULL) 9208 uu_die(emsg_create_xml); 9209 9210 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9211 elts.stability = m; 9212 continue; 9213 } 9214 9215 xmlFreeNode(m); 9216 } 9217 9218 export_property(exp_prop, NULL, &elts, flags); 9219 } 9220 if (ret == -1) 9221 scfdie(); 9222 9223 (void) xmlAddChild(n, elts.stability); 9224 (void) xmlAddChildList(n, elts.propvals); 9225 (void) xmlAddChildList(n, elts.properties); 9226 9227 if (eelts->property_groups == NULL) 9228 eelts->property_groups = n; 9229 else 9230 (void) xmlAddSibling(eelts->property_groups, n); 9231 } 9232 9233 /* 9234 * Create an XML node representing the dependency described by the given 9235 * property group and put it in eelts. Unless the dependency is not valid, in 9236 * which case create a generic property_group element which represents it and 9237 * put it in eelts. 9238 */ 9239 static void 9240 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 9241 { 9242 xmlNodePtr n; 9243 int err = 0, ret; 9244 struct pg_elts elts; 9245 9246 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 9247 if (n == NULL) 9248 uu_die(emsg_create_xml); 9249 9250 /* 9251 * If the external flag is present, skip this dependency because it 9252 * should have been created by another manifest. 9253 */ 9254 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 9255 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9256 prop_get_val(exp_prop, exp_val) == 0) { 9257 uint8_t b; 9258 9259 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 9260 scfdie(); 9261 9262 if (b) 9263 return; 9264 } 9265 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 9266 scfdie(); 9267 9268 /* Get the required attributes. */ 9269 9270 /* name */ 9271 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9272 scfdie(); 9273 safe_setprop(n, name_attr, exp_str); 9274 9275 /* grouping */ 9276 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9277 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9278 err = 1; 9279 9280 /* restart_on */ 9281 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9282 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9283 err = 1; 9284 9285 /* type */ 9286 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9287 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9288 err = 1; 9289 9290 /* 9291 * entities: Not required, but if we create no children, it will be 9292 * created as empty on import, so fail if it's missing. 9293 */ 9294 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9295 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 9296 scf_iter_t *eiter; 9297 int ret2; 9298 9299 eiter = scf_iter_create(g_hndl); 9300 if (eiter == NULL) 9301 scfdie(); 9302 9303 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 9304 scfdie(); 9305 9306 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 9307 xmlNodePtr ch; 9308 9309 if (scf_value_get_astring(exp_val, exp_str, 9310 exp_str_sz) < 0) 9311 scfdie(); 9312 9313 /* 9314 * service_fmri's must be first, so we can add them 9315 * here. 9316 */ 9317 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 9318 NULL); 9319 if (ch == NULL) 9320 uu_die(emsg_create_xml); 9321 9322 safe_setprop(ch, value_attr, exp_str); 9323 } 9324 if (ret2 == -1) 9325 scfdie(); 9326 9327 scf_iter_destroy(eiter); 9328 } else 9329 err = 1; 9330 9331 if (err) { 9332 xmlFreeNode(n); 9333 9334 export_pg(pg, eelts, SCE_ALL_VALUES); 9335 9336 return; 9337 } 9338 9339 /* Iterate through the properties & handle each. */ 9340 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9341 scfdie(); 9342 9343 (void) memset(&elts, 0, sizeof (elts)); 9344 9345 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9346 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9347 scfdie(); 9348 9349 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9350 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9351 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9352 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9353 continue; 9354 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9355 xmlNodePtr m; 9356 9357 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9358 if (m == NULL) 9359 uu_die(emsg_create_xml); 9360 9361 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9362 elts.stability = m; 9363 continue; 9364 } 9365 9366 xmlFreeNode(m); 9367 } 9368 9369 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9370 } 9371 if (ret == -1) 9372 scfdie(); 9373 9374 (void) xmlAddChild(n, elts.stability); 9375 (void) xmlAddChildList(n, elts.propvals); 9376 (void) xmlAddChildList(n, elts.properties); 9377 9378 if (eelts->dependencies == NULL) 9379 eelts->dependencies = n; 9380 else 9381 (void) xmlAddSibling(eelts->dependencies, n); 9382 } 9383 9384 static xmlNodePtr 9385 export_method_environment(scf_propertygroup_t *pg) 9386 { 9387 xmlNodePtr env; 9388 int ret; 9389 int children = 0; 9390 9391 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 9392 return (NULL); 9393 9394 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 9395 if (env == NULL) 9396 uu_die(emsg_create_xml); 9397 9398 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 9399 scfdie(); 9400 9401 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 9402 scfdie(); 9403 9404 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 9405 xmlNodePtr ev; 9406 char *cp; 9407 9408 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9409 scfdie(); 9410 9411 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 9412 warn(gettext("Invalid environment variable \"%s\".\n"), 9413 exp_str); 9414 continue; 9415 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 9416 warn(gettext("Invalid environment variable \"%s\"; " 9417 "\"SMF_\" prefix is reserved.\n"), exp_str); 9418 continue; 9419 } 9420 9421 *cp = '\0'; 9422 cp++; 9423 9424 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 9425 if (ev == NULL) 9426 uu_die(emsg_create_xml); 9427 9428 safe_setprop(ev, name_attr, exp_str); 9429 safe_setprop(ev, value_attr, cp); 9430 children++; 9431 } 9432 9433 if (ret != 0) 9434 scfdie(); 9435 9436 if (children == 0) { 9437 xmlFreeNode(env); 9438 return (NULL); 9439 } 9440 9441 return (env); 9442 } 9443 9444 /* 9445 * As above, but for a method property group. 9446 */ 9447 static void 9448 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 9449 { 9450 xmlNodePtr n, env; 9451 char *str; 9452 int err = 0, nonenv, ret; 9453 uint8_t use_profile; 9454 struct pg_elts elts; 9455 xmlNodePtr ctxt = NULL; 9456 9457 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 9458 9459 /* Get the required attributes. */ 9460 9461 /* name */ 9462 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9463 scfdie(); 9464 safe_setprop(n, name_attr, exp_str); 9465 9466 /* type */ 9467 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9468 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9469 err = 1; 9470 9471 /* exec */ 9472 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 9473 set_attr_from_prop(exp_prop, n, "exec") != 0) 9474 err = 1; 9475 9476 /* timeout */ 9477 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 9478 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 9479 prop_get_val(exp_prop, exp_val) == 0) { 9480 uint64_t c; 9481 9482 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 9483 scfdie(); 9484 9485 str = uu_msprintf("%llu", c); 9486 if (str == NULL) 9487 uu_die(gettext("Could not create string")); 9488 9489 safe_setprop(n, "timeout_seconds", str); 9490 free(str); 9491 } else 9492 err = 1; 9493 9494 if (err) { 9495 xmlFreeNode(n); 9496 9497 export_pg(pg, eelts, SCE_ALL_VALUES); 9498 9499 return; 9500 } 9501 9502 9503 /* 9504 * If we're going to have a method_context child, we need to know 9505 * before we iterate through the properties. Since method_context's 9506 * are optional, we don't want to complain about any properties 9507 * missing if none of them are there. Thus we can't use the 9508 * convenience functions. 9509 */ 9510 nonenv = 9511 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 9512 SCF_SUCCESS || 9513 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 9514 SCF_SUCCESS || 9515 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 9516 SCF_SUCCESS || 9517 scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) == 9518 SCF_SUCCESS || 9519 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 9520 SCF_SUCCESS; 9521 9522 if (nonenv) { 9523 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9524 if (ctxt == NULL) 9525 uu_die(emsg_create_xml); 9526 9527 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 9528 0 && 9529 set_attr_from_prop_default(exp_prop, ctxt, 9530 "working_directory", ":default") != 0) 9531 err = 1; 9532 9533 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 9534 set_attr_from_prop_default(exp_prop, ctxt, "project", 9535 ":default") != 0) 9536 err = 1; 9537 9538 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 9539 0 && 9540 set_attr_from_prop_default(exp_prop, ctxt, 9541 "resource_pool", ":default") != 0) 9542 err = 1; 9543 9544 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 && 9545 set_attr_from_prop_default(exp_prop, ctxt, 9546 "security_flags", ":default") != 0) 9547 err = 1; 9548 9549 /* 9550 * We only want to complain about profile or credential 9551 * properties if we will use them. To determine that we must 9552 * examine USE_PROFILE. 9553 */ 9554 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9555 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9556 prop_get_val(exp_prop, exp_val) == 0) { 9557 if (scf_value_get_boolean(exp_val, &use_profile) != 9558 SCF_SUCCESS) { 9559 scfdie(); 9560 } 9561 9562 if (use_profile) { 9563 xmlNodePtr prof; 9564 9565 prof = xmlNewChild(ctxt, NULL, 9566 (xmlChar *)"method_profile", NULL); 9567 if (prof == NULL) 9568 uu_die(emsg_create_xml); 9569 9570 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 9571 exp_prop) != 0 || 9572 set_attr_from_prop(exp_prop, prof, 9573 name_attr) != 0) 9574 err = 1; 9575 } else { 9576 xmlNodePtr cred; 9577 9578 cred = xmlNewChild(ctxt, NULL, 9579 (xmlChar *)"method_credential", NULL); 9580 if (cred == NULL) 9581 uu_die(emsg_create_xml); 9582 9583 if (pg_get_prop(pg, SCF_PROPERTY_USER, 9584 exp_prop) != 0 || 9585 set_attr_from_prop(exp_prop, cred, 9586 "user") != 0) { 9587 err = 1; 9588 } 9589 9590 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 9591 exp_prop) == 0 && 9592 set_attr_from_prop_default(exp_prop, cred, 9593 "group", ":default") != 0) 9594 err = 1; 9595 9596 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 9597 exp_prop) == 0 && 9598 set_attr_from_prop_default(exp_prop, cred, 9599 "supp_groups", ":default") != 0) 9600 err = 1; 9601 9602 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 9603 exp_prop) == 0 && 9604 set_attr_from_prop_default(exp_prop, cred, 9605 "privileges", ":default") != 0) 9606 err = 1; 9607 9608 if (pg_get_prop(pg, 9609 SCF_PROPERTY_LIMIT_PRIVILEGES, 9610 exp_prop) == 0 && 9611 set_attr_from_prop_default(exp_prop, cred, 9612 "limit_privileges", ":default") != 0) 9613 err = 1; 9614 } 9615 } 9616 } 9617 9618 if ((env = export_method_environment(pg)) != NULL) { 9619 if (ctxt == NULL) { 9620 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9621 if (ctxt == NULL) 9622 uu_die(emsg_create_xml); 9623 } 9624 (void) xmlAddChild(ctxt, env); 9625 } 9626 9627 if (env != NULL || (nonenv && err == 0)) 9628 (void) xmlAddChild(n, ctxt); 9629 else 9630 xmlFreeNode(ctxt); 9631 9632 nonenv = (err == 0); 9633 9634 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9635 scfdie(); 9636 9637 (void) memset(&elts, 0, sizeof (elts)); 9638 9639 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9640 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9641 scfdie(); 9642 9643 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9644 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 9645 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 9646 continue; 9647 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9648 xmlNodePtr m; 9649 9650 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9651 if (m == NULL) 9652 uu_die(emsg_create_xml); 9653 9654 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9655 elts.stability = m; 9656 continue; 9657 } 9658 9659 xmlFreeNode(m); 9660 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 9661 0 || 9662 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 9663 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 9664 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9665 if (nonenv) 9666 continue; 9667 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 9668 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 9669 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 9670 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 9671 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 || 9672 strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9673 if (nonenv && !use_profile) 9674 continue; 9675 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9676 if (nonenv && use_profile) 9677 continue; 9678 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 9679 if (env != NULL) 9680 continue; 9681 } 9682 9683 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9684 } 9685 if (ret == -1) 9686 scfdie(); 9687 9688 (void) xmlAddChild(n, elts.stability); 9689 (void) xmlAddChildList(n, elts.propvals); 9690 (void) xmlAddChildList(n, elts.properties); 9691 9692 if (eelts->exec_methods == NULL) 9693 eelts->exec_methods = n; 9694 else 9695 (void) xmlAddSibling(eelts->exec_methods, n); 9696 } 9697 9698 static void 9699 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 9700 struct entity_elts *eelts) 9701 { 9702 xmlNodePtr pgnode; 9703 9704 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 9705 if (pgnode == NULL) 9706 uu_die(emsg_create_xml); 9707 9708 safe_setprop(pgnode, name_attr, name); 9709 safe_setprop(pgnode, type_attr, type); 9710 9711 (void) xmlAddChildList(pgnode, elts->propvals); 9712 (void) xmlAddChildList(pgnode, elts->properties); 9713 9714 if (eelts->property_groups == NULL) 9715 eelts->property_groups = pgnode; 9716 else 9717 (void) xmlAddSibling(eelts->property_groups, pgnode); 9718 } 9719 9720 /* 9721 * Process the general property group for a service. This is the one with the 9722 * goodies. 9723 */ 9724 static void 9725 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 9726 { 9727 struct pg_elts elts; 9728 int ret; 9729 9730 /* 9731 * In case there are properties which don't correspond to child 9732 * entities of the service entity, we'll set up a pg_elts structure to 9733 * put them in. 9734 */ 9735 (void) memset(&elts, 0, sizeof (elts)); 9736 9737 /* Walk the properties, looking for special ones. */ 9738 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9739 scfdie(); 9740 9741 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9742 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9743 scfdie(); 9744 9745 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 9746 /* 9747 * Unimplemented and obsolete, but we still process it 9748 * for compatibility purposes. 9749 */ 9750 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9751 prop_get_val(exp_prop, exp_val) == 0) { 9752 uint8_t b; 9753 9754 if (scf_value_get_boolean(exp_val, &b) != 9755 SCF_SUCCESS) 9756 scfdie(); 9757 9758 if (b) { 9759 selts->single_instance = 9760 xmlNewNode(NULL, 9761 (xmlChar *)"single_instance"); 9762 if (selts->single_instance == NULL) 9763 uu_die(emsg_create_xml); 9764 } 9765 9766 continue; 9767 } 9768 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9769 xmlNodePtr rnode, sfnode; 9770 9771 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9772 if (rnode == NULL) 9773 uu_die(emsg_create_xml); 9774 9775 sfnode = xmlNewChild(rnode, NULL, 9776 (xmlChar *)"service_fmri", NULL); 9777 if (sfnode == NULL) 9778 uu_die(emsg_create_xml); 9779 9780 if (set_attr_from_prop(exp_prop, sfnode, 9781 value_attr) == 0) { 9782 selts->restarter = rnode; 9783 continue; 9784 } 9785 9786 xmlFreeNode(rnode); 9787 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 9788 0) { 9789 xmlNodePtr s; 9790 9791 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9792 if (s == NULL) 9793 uu_die(emsg_create_xml); 9794 9795 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9796 selts->stability = s; 9797 continue; 9798 } 9799 9800 xmlFreeNode(s); 9801 } 9802 9803 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES); 9804 } 9805 if (ret == -1) 9806 scfdie(); 9807 9808 if (elts.propvals != NULL || elts.properties != NULL) 9809 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 9810 selts); 9811 } 9812 9813 static void 9814 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 9815 { 9816 xmlNodePtr n, prof, cred, env; 9817 uint8_t use_profile; 9818 int ret, err = 0; 9819 9820 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 9821 9822 env = export_method_environment(pg); 9823 9824 /* Need to know whether we'll use a profile or not. */ 9825 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9826 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9827 prop_get_val(exp_prop, exp_val) == 0) { 9828 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 9829 scfdie(); 9830 9831 if (use_profile) 9832 prof = 9833 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 9834 NULL); 9835 else 9836 cred = 9837 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 9838 NULL); 9839 } 9840 9841 if (env != NULL) 9842 (void) xmlAddChild(n, env); 9843 9844 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9845 scfdie(); 9846 9847 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9848 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9849 scfdie(); 9850 9851 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 9852 if (set_attr_from_prop(exp_prop, n, 9853 "working_directory") != 0) 9854 err = 1; 9855 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 9856 if (set_attr_from_prop(exp_prop, n, "project") != 0) 9857 err = 1; 9858 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 9859 if (set_attr_from_prop(exp_prop, n, 9860 "resource_pool") != 0) 9861 err = 1; 9862 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) { 9863 if (set_attr_from_prop(exp_prop, n, 9864 "security_flags") != 0) 9865 err = 1; 9866 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9867 /* EMPTY */ 9868 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 9869 if (use_profile || 9870 set_attr_from_prop(exp_prop, cred, "user") != 0) 9871 err = 1; 9872 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 9873 if (use_profile || 9874 set_attr_from_prop(exp_prop, cred, "group") != 0) 9875 err = 1; 9876 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 9877 if (use_profile || set_attr_from_prop(exp_prop, cred, 9878 "supp_groups") != 0) 9879 err = 1; 9880 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 9881 if (use_profile || set_attr_from_prop(exp_prop, cred, 9882 "privileges") != 0) 9883 err = 1; 9884 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 9885 0) { 9886 if (use_profile || set_attr_from_prop(exp_prop, cred, 9887 "limit_privileges") != 0) 9888 err = 1; 9889 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9890 if (!use_profile || set_attr_from_prop(exp_prop, 9891 prof, name_attr) != 0) 9892 err = 1; 9893 } else { 9894 /* Can't have generic properties in method_context's */ 9895 err = 1; 9896 } 9897 } 9898 if (ret == -1) 9899 scfdie(); 9900 9901 if (err && env == NULL) { 9902 xmlFreeNode(n); 9903 export_pg(pg, elts, SCE_ALL_VALUES); 9904 return; 9905 } 9906 9907 elts->method_context = n; 9908 } 9909 9910 /* 9911 * Given a dependency property group in the tfmri entity (target fmri), return 9912 * a dependent element which represents it. 9913 */ 9914 static xmlNodePtr 9915 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 9916 { 9917 uint8_t b; 9918 xmlNodePtr n, sf; 9919 int err = 0, ret; 9920 struct pg_elts pgelts; 9921 9922 /* 9923 * If external isn't set to true then exporting the service will 9924 * export this as a normal dependency, so we should stop to avoid 9925 * duplication. 9926 */ 9927 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 9928 scf_property_get_value(exp_prop, exp_val) != 0 || 9929 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 9930 if (g_verbose) { 9931 warn(gettext("Dependent \"%s\" cannot be exported " 9932 "properly because the \"%s\" property of the " 9933 "\"%s\" dependency of %s is not set to true.\n"), 9934 name, scf_property_external, name, tfmri); 9935 } 9936 9937 return (NULL); 9938 } 9939 9940 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 9941 if (n == NULL) 9942 uu_die(emsg_create_xml); 9943 9944 safe_setprop(n, name_attr, name); 9945 9946 /* Get the required attributes */ 9947 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9948 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9949 err = 1; 9950 9951 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9952 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9953 err = 1; 9954 9955 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9956 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 9957 prop_get_val(exp_prop, exp_val) == 0) { 9958 /* EMPTY */ 9959 } else 9960 err = 1; 9961 9962 if (err) { 9963 xmlFreeNode(n); 9964 return (NULL); 9965 } 9966 9967 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 9968 if (sf == NULL) 9969 uu_die(emsg_create_xml); 9970 9971 safe_setprop(sf, value_attr, tfmri); 9972 9973 /* 9974 * Now add elements for the other properties. 9975 */ 9976 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9977 scfdie(); 9978 9979 (void) memset(&pgelts, 0, sizeof (pgelts)); 9980 9981 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9982 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9983 scfdie(); 9984 9985 if (strcmp(exp_str, scf_property_external) == 0 || 9986 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9987 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9988 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9989 continue; 9990 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 9991 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 9992 prop_get_val(exp_prop, exp_val) == 0) { 9993 char type[sizeof ("service") + 1]; 9994 9995 if (scf_value_get_astring(exp_val, type, 9996 sizeof (type)) < 0) 9997 scfdie(); 9998 9999 if (strcmp(type, "service") == 0) 10000 continue; 10001 } 10002 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 10003 xmlNodePtr s; 10004 10005 s = xmlNewNode(NULL, (xmlChar *)"stability"); 10006 if (s == NULL) 10007 uu_die(emsg_create_xml); 10008 10009 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 10010 pgelts.stability = s; 10011 continue; 10012 } 10013 10014 xmlFreeNode(s); 10015 } 10016 10017 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10018 } 10019 if (ret == -1) 10020 scfdie(); 10021 10022 (void) xmlAddChild(n, pgelts.stability); 10023 (void) xmlAddChildList(n, pgelts.propvals); 10024 (void) xmlAddChildList(n, pgelts.properties); 10025 10026 return (n); 10027 } 10028 10029 static void 10030 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 10031 { 10032 scf_propertygroup_t *opg; 10033 scf_iter_t *iter; 10034 char *type, *fmri; 10035 int ret; 10036 struct pg_elts pgelts; 10037 xmlNodePtr n; 10038 scf_error_t serr; 10039 10040 if ((opg = scf_pg_create(g_hndl)) == NULL || 10041 (iter = scf_iter_create(g_hndl)) == NULL) 10042 scfdie(); 10043 10044 /* Can't use exp_prop_iter due to export_dependent(). */ 10045 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10046 scfdie(); 10047 10048 type = safe_malloc(max_scf_pg_type_len + 1); 10049 10050 /* Get an extra byte so we can tell if values are too long. */ 10051 fmri = safe_malloc(max_scf_fmri_len + 2); 10052 10053 (void) memset(&pgelts, 0, sizeof (pgelts)); 10054 10055 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 10056 void *entity; 10057 int isservice; 10058 scf_type_t ty; 10059 10060 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 10061 scfdie(); 10062 10063 if ((ty != SCF_TYPE_ASTRING && 10064 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 10065 prop_get_val(exp_prop, exp_val) != 0) { 10066 export_property(exp_prop, NULL, &pgelts, 10067 SCE_ALL_VALUES); 10068 continue; 10069 } 10070 10071 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10072 scfdie(); 10073 10074 if (scf_value_get_astring(exp_val, fmri, 10075 max_scf_fmri_len + 2) < 0) 10076 scfdie(); 10077 10078 /* Look for a dependency group in the target fmri. */ 10079 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10080 switch (serr) { 10081 case SCF_ERROR_NONE: 10082 break; 10083 10084 case SCF_ERROR_NO_MEMORY: 10085 uu_die(gettext("Out of memory.\n")); 10086 /* NOTREACHED */ 10087 10088 case SCF_ERROR_INVALID_ARGUMENT: 10089 if (g_verbose) { 10090 if (scf_property_to_fmri(exp_prop, fmri, 10091 max_scf_fmri_len + 2) < 0) 10092 scfdie(); 10093 10094 warn(gettext("The value of %s is not a valid " 10095 "FMRI.\n"), fmri); 10096 } 10097 10098 export_property(exp_prop, exp_str, &pgelts, 10099 SCE_ALL_VALUES); 10100 continue; 10101 10102 case SCF_ERROR_CONSTRAINT_VIOLATED: 10103 if (g_verbose) { 10104 if (scf_property_to_fmri(exp_prop, fmri, 10105 max_scf_fmri_len + 2) < 0) 10106 scfdie(); 10107 10108 warn(gettext("The value of %s does not specify " 10109 "a service or an instance.\n"), fmri); 10110 } 10111 10112 export_property(exp_prop, exp_str, &pgelts, 10113 SCE_ALL_VALUES); 10114 continue; 10115 10116 case SCF_ERROR_NOT_FOUND: 10117 if (g_verbose) { 10118 if (scf_property_to_fmri(exp_prop, fmri, 10119 max_scf_fmri_len + 2) < 0) 10120 scfdie(); 10121 10122 warn(gettext("The entity specified by %s does " 10123 "not exist.\n"), fmri); 10124 } 10125 10126 export_property(exp_prop, exp_str, &pgelts, 10127 SCE_ALL_VALUES); 10128 continue; 10129 10130 default: 10131 #ifndef NDEBUG 10132 (void) fprintf(stderr, "%s:%d: %s() failed with " 10133 "unexpected error %d.\n", __FILE__, __LINE__, 10134 "fmri_to_entity", serr); 10135 #endif 10136 abort(); 10137 } 10138 10139 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 10140 if (scf_error() != SCF_ERROR_NOT_FOUND) 10141 scfdie(); 10142 10143 warn(gettext("Entity %s is missing dependency property " 10144 "group %s.\n"), fmri, exp_str); 10145 10146 export_property(exp_prop, NULL, &pgelts, 10147 SCE_ALL_VALUES); 10148 continue; 10149 } 10150 10151 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 10152 scfdie(); 10153 10154 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 10155 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 10156 scfdie(); 10157 10158 warn(gettext("Property group %s is not of " 10159 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 10160 10161 export_property(exp_prop, NULL, &pgelts, 10162 SCE_ALL_VALUES); 10163 continue; 10164 } 10165 10166 n = export_dependent(opg, exp_str, fmri); 10167 if (n == NULL) { 10168 export_property(exp_prop, exp_str, &pgelts, 10169 SCE_ALL_VALUES); 10170 } else { 10171 if (eelts->dependents == NULL) 10172 eelts->dependents = n; 10173 else 10174 (void) xmlAddSibling(eelts->dependents, 10175 n); 10176 } 10177 } 10178 if (ret == -1) 10179 scfdie(); 10180 10181 free(fmri); 10182 free(type); 10183 10184 scf_iter_destroy(iter); 10185 scf_pg_destroy(opg); 10186 10187 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10188 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 10189 eelts); 10190 } 10191 10192 static void 10193 make_node(xmlNodePtr *nodep, const char *name) 10194 { 10195 if (*nodep == NULL) { 10196 *nodep = xmlNewNode(NULL, (xmlChar *)name); 10197 if (*nodep == NULL) 10198 uu_die(emsg_create_xml); 10199 } 10200 } 10201 10202 static xmlNodePtr 10203 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 10204 { 10205 int ret; 10206 xmlNodePtr parent = NULL; 10207 xmlNodePtr loctext = NULL; 10208 10209 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10210 scfdie(); 10211 10212 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10213 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 10214 prop_get_val(exp_prop, exp_val) != 0) 10215 continue; 10216 10217 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 10218 scfdie(); 10219 10220 make_node(&parent, parname); 10221 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 10222 (xmlChar *)exp_str); 10223 if (loctext == NULL) 10224 uu_die(emsg_create_xml); 10225 10226 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10227 scfdie(); 10228 10229 safe_setprop(loctext, "xml:lang", exp_str); 10230 } 10231 10232 if (ret == -1) 10233 scfdie(); 10234 10235 return (parent); 10236 } 10237 10238 static xmlNodePtr 10239 export_tm_manpage(scf_propertygroup_t *pg) 10240 { 10241 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 10242 if (manpage == NULL) 10243 uu_die(emsg_create_xml); 10244 10245 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 10246 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 10247 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 10248 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 10249 xmlFreeNode(manpage); 10250 return (NULL); 10251 } 10252 10253 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 10254 (void) set_attr_from_prop_default(exp_prop, 10255 manpage, "manpath", ":default"); 10256 10257 return (manpage); 10258 } 10259 10260 static xmlNodePtr 10261 export_tm_doc_link(scf_propertygroup_t *pg) 10262 { 10263 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 10264 if (doc_link == NULL) 10265 uu_die(emsg_create_xml); 10266 10267 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 10268 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 10269 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 10270 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 10271 xmlFreeNode(doc_link); 10272 return (NULL); 10273 } 10274 return (doc_link); 10275 } 10276 10277 /* 10278 * Process template information for a service or instances. 10279 */ 10280 static void 10281 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 10282 struct template_elts *telts) 10283 { 10284 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 10285 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 10286 xmlNodePtr child = NULL; 10287 10288 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 10289 scfdie(); 10290 10291 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 10292 telts->common_name = export_tm_loctext(pg, "common_name"); 10293 if (telts->common_name == NULL) 10294 export_pg(pg, elts, SCE_ALL_VALUES); 10295 return; 10296 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 10297 telts->description = export_tm_loctext(pg, "description"); 10298 if (telts->description == NULL) 10299 export_pg(pg, elts, SCE_ALL_VALUES); 10300 return; 10301 } 10302 10303 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 10304 child = export_tm_manpage(pg); 10305 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 10306 child = export_tm_doc_link(pg); 10307 } 10308 10309 if (child != NULL) { 10310 make_node(&telts->documentation, "documentation"); 10311 (void) xmlAddChild(telts->documentation, child); 10312 } else { 10313 export_pg(pg, elts, SCE_ALL_VALUES); 10314 } 10315 } 10316 10317 /* 10318 * Process parameter and paramval elements 10319 */ 10320 static void 10321 export_parameter(scf_property_t *prop, const char *name, 10322 struct params_elts *elts) 10323 { 10324 xmlNodePtr param; 10325 scf_error_t err = 0; 10326 int ret; 10327 10328 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 10329 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL) 10330 uu_die(emsg_create_xml); 10331 10332 safe_setprop(param, name_attr, name); 10333 10334 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 10335 scfdie(); 10336 safe_setprop(param, value_attr, exp_str); 10337 10338 if (elts->paramval == NULL) 10339 elts->paramval = param; 10340 else 10341 (void) xmlAddSibling(elts->paramval, param); 10342 10343 return; 10344 } 10345 10346 err = scf_error(); 10347 10348 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 10349 err != SCF_ERROR_NOT_FOUND) 10350 scfdie(); 10351 10352 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL) 10353 uu_die(emsg_create_xml); 10354 10355 safe_setprop(param, name_attr, name); 10356 10357 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 10358 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 10359 scfdie(); 10360 10361 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 10362 1) { 10363 xmlNodePtr vn; 10364 10365 if ((vn = xmlNewChild(param, NULL, 10366 (xmlChar *)"value_node", NULL)) == NULL) 10367 uu_die(emsg_create_xml); 10368 10369 if (scf_value_get_as_string(exp_val, exp_str, 10370 exp_str_sz) < 0) 10371 scfdie(); 10372 10373 safe_setprop(vn, value_attr, exp_str); 10374 } 10375 if (ret != 0) 10376 scfdie(); 10377 } 10378 10379 if (elts->parameter == NULL) 10380 elts->parameter = param; 10381 else 10382 (void) xmlAddSibling(elts->parameter, param); 10383 } 10384 10385 /* 10386 * Process notification parameters for a service or instance 10387 */ 10388 static void 10389 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts) 10390 { 10391 xmlNodePtr n, event, *type; 10392 struct params_elts *eelts; 10393 int ret, err, i; 10394 char *s; 10395 10396 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters"); 10397 event = xmlNewNode(NULL, (xmlChar *)"event"); 10398 if (n == NULL || event == NULL) 10399 uu_die(emsg_create_xml); 10400 10401 /* event value */ 10402 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 10403 scfdie(); 10404 /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */ 10405 if ((s = strchr(exp_str, ',')) != NULL) 10406 *s = '\0'; 10407 safe_setprop(event, value_attr, exp_str); 10408 10409 (void) xmlAddChild(n, event); 10410 10411 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL || 10412 (eelts = calloc(URI_SCHEME_NUM, 10413 sizeof (struct params_elts))) == NULL) 10414 uu_die(gettext("Out of memory.\n")); 10415 10416 err = 0; 10417 10418 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10419 scfdie(); 10420 10421 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10422 char *t, *p; 10423 10424 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10425 scfdie(); 10426 10427 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) { 10428 /* 10429 * this is not a well formed notification parameters 10430 * element, we should export as regular pg 10431 */ 10432 err = 1; 10433 break; 10434 } 10435 10436 if ((i = check_uri_protocol(t)) < 0) { 10437 err = 1; 10438 break; 10439 } 10440 10441 if (type[i] == NULL) { 10442 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) == 10443 NULL) 10444 uu_die(emsg_create_xml); 10445 10446 safe_setprop(type[i], name_attr, t); 10447 } 10448 if (strcmp(p, active_attr) == 0) { 10449 if (set_attr_from_prop(exp_prop, type[i], 10450 active_attr) != 0) { 10451 err = 1; 10452 break; 10453 } 10454 continue; 10455 } 10456 /* 10457 * We export the parameter 10458 */ 10459 export_parameter(exp_prop, p, &eelts[i]); 10460 } 10461 10462 if (ret == -1) 10463 scfdie(); 10464 10465 if (err == 1) { 10466 for (i = 0; i < URI_SCHEME_NUM; ++i) 10467 xmlFree(type[i]); 10468 free(type); 10469 10470 export_pg(pg, elts, SCE_ALL_VALUES); 10471 10472 return; 10473 } else { 10474 for (i = 0; i < URI_SCHEME_NUM; ++i) 10475 if (type[i] != NULL) { 10476 (void) xmlAddChildList(type[i], 10477 eelts[i].paramval); 10478 (void) xmlAddChildList(type[i], 10479 eelts[i].parameter); 10480 (void) xmlAddSibling(event, type[i]); 10481 } 10482 } 10483 free(type); 10484 10485 if (elts->notify_params == NULL) 10486 elts->notify_params = n; 10487 else 10488 (void) xmlAddSibling(elts->notify_params, n); 10489 } 10490 10491 /* 10492 * Process the general property group for an instance. 10493 */ 10494 static void 10495 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 10496 struct entity_elts *elts) 10497 { 10498 uint8_t enabled; 10499 struct pg_elts pgelts; 10500 int ret; 10501 10502 /* enabled */ 10503 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10504 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10505 prop_get_val(exp_prop, exp_val) == 0) { 10506 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10507 scfdie(); 10508 } else { 10509 enabled = 0; 10510 } 10511 10512 safe_setprop(inode, enabled_attr, enabled ? true : false); 10513 10514 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10515 scfdie(); 10516 10517 (void) memset(&pgelts, 0, sizeof (pgelts)); 10518 10519 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10520 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10521 scfdie(); 10522 10523 if (strcmp(exp_str, scf_property_enabled) == 0) { 10524 continue; 10525 } else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) { 10526 continue; 10527 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10528 xmlNodePtr rnode, sfnode; 10529 10530 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10531 if (rnode == NULL) 10532 uu_die(emsg_create_xml); 10533 10534 sfnode = xmlNewChild(rnode, NULL, 10535 (xmlChar *)"service_fmri", NULL); 10536 if (sfnode == NULL) 10537 uu_die(emsg_create_xml); 10538 10539 if (set_attr_from_prop(exp_prop, sfnode, 10540 value_attr) == 0) { 10541 elts->restarter = rnode; 10542 continue; 10543 } 10544 10545 xmlFreeNode(rnode); 10546 } 10547 10548 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES); 10549 } 10550 if (ret == -1) 10551 scfdie(); 10552 10553 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10554 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10555 elts); 10556 } 10557 10558 /* 10559 * Put an instance element for the given instance into selts. 10560 */ 10561 static void 10562 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10563 { 10564 xmlNodePtr n; 10565 boolean_t isdefault; 10566 struct entity_elts elts; 10567 struct template_elts template_elts; 10568 int ret; 10569 10570 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10571 if (n == NULL) 10572 uu_die(emsg_create_xml); 10573 10574 /* name */ 10575 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10576 scfdie(); 10577 safe_setprop(n, name_attr, exp_str); 10578 isdefault = strcmp(exp_str, "default") == 0; 10579 10580 /* check existance of general pg (since general/enabled is required) */ 10581 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10582 if (scf_error() != SCF_ERROR_NOT_FOUND) 10583 scfdie(); 10584 10585 if (g_verbose) { 10586 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10587 scfdie(); 10588 10589 warn(gettext("Instance %s has no general property " 10590 "group; it will be marked disabled.\n"), exp_str); 10591 } 10592 10593 safe_setprop(n, enabled_attr, false); 10594 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10595 strcmp(exp_str, scf_group_framework) != 0) { 10596 if (g_verbose) { 10597 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10598 scfdie(); 10599 10600 warn(gettext("Property group %s is not of type " 10601 "framework; the instance will be marked " 10602 "disabled.\n"), exp_str); 10603 } 10604 10605 safe_setprop(n, enabled_attr, false); 10606 } 10607 10608 /* property groups */ 10609 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10610 scfdie(); 10611 10612 (void) memset(&elts, 0, sizeof (elts)); 10613 (void) memset(&template_elts, 0, sizeof (template_elts)); 10614 10615 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10616 uint32_t pgflags; 10617 10618 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10619 scfdie(); 10620 10621 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10622 continue; 10623 10624 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10625 scfdie(); 10626 10627 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10628 export_dependency(exp_pg, &elts); 10629 continue; 10630 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10631 export_method(exp_pg, &elts); 10632 continue; 10633 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10634 if (scf_pg_get_name(exp_pg, exp_str, 10635 max_scf_name_len + 1) < 0) 10636 scfdie(); 10637 10638 if (strcmp(exp_str, scf_pg_general) == 0) { 10639 export_inst_general(exp_pg, n, &elts); 10640 continue; 10641 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10642 0) { 10643 export_method_context(exp_pg, &elts); 10644 continue; 10645 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10646 export_dependents(exp_pg, &elts); 10647 continue; 10648 } 10649 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10650 export_template(exp_pg, &elts, &template_elts); 10651 continue; 10652 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10653 export_notify_params(exp_pg, &elts); 10654 continue; 10655 } 10656 10657 /* Ordinary pg. */ 10658 export_pg(exp_pg, &elts, flags); 10659 } 10660 if (ret == -1) 10661 scfdie(); 10662 10663 if (template_elts.common_name != NULL) { 10664 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10665 (void) xmlAddChild(elts.template, template_elts.common_name); 10666 (void) xmlAddChild(elts.template, template_elts.description); 10667 (void) xmlAddChild(elts.template, template_elts.documentation); 10668 } else { 10669 xmlFreeNode(template_elts.description); 10670 xmlFreeNode(template_elts.documentation); 10671 } 10672 10673 if (isdefault && elts.restarter == NULL && 10674 elts.dependencies == NULL && elts.method_context == NULL && 10675 elts.exec_methods == NULL && elts.notify_params == NULL && 10676 elts.property_groups == NULL && elts.template == NULL) { 10677 xmlChar *eval; 10678 10679 /* This is a default instance */ 10680 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10681 10682 xmlFreeNode(n); 10683 10684 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10685 if (n == NULL) 10686 uu_die(emsg_create_xml); 10687 10688 safe_setprop(n, enabled_attr, (char *)eval); 10689 xmlFree(eval); 10690 10691 selts->create_default_instance = n; 10692 } else { 10693 /* Assemble the children in order. */ 10694 (void) xmlAddChild(n, elts.restarter); 10695 (void) xmlAddChildList(n, elts.dependencies); 10696 (void) xmlAddChildList(n, elts.dependents); 10697 (void) xmlAddChild(n, elts.method_context); 10698 (void) xmlAddChildList(n, elts.exec_methods); 10699 (void) xmlAddChildList(n, elts.notify_params); 10700 (void) xmlAddChildList(n, elts.property_groups); 10701 (void) xmlAddChild(n, elts.template); 10702 10703 if (selts->instances == NULL) 10704 selts->instances = n; 10705 else 10706 (void) xmlAddSibling(selts->instances, n); 10707 } 10708 } 10709 10710 /* 10711 * Return a service element for the given service. 10712 */ 10713 static xmlNodePtr 10714 export_service(scf_service_t *svc, int flags) 10715 { 10716 xmlNodePtr snode; 10717 struct entity_elts elts; 10718 struct template_elts template_elts; 10719 int ret; 10720 10721 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10722 if (snode == NULL) 10723 uu_die(emsg_create_xml); 10724 10725 /* Get & set name attribute */ 10726 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10727 scfdie(); 10728 safe_setprop(snode, name_attr, exp_str); 10729 10730 safe_setprop(snode, type_attr, "service"); 10731 safe_setprop(snode, "version", "0"); 10732 10733 /* Acquire child elements. */ 10734 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10735 scfdie(); 10736 10737 (void) memset(&elts, 0, sizeof (elts)); 10738 (void) memset(&template_elts, 0, sizeof (template_elts)); 10739 10740 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10741 uint32_t pgflags; 10742 10743 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10744 scfdie(); 10745 10746 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10747 continue; 10748 10749 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10750 scfdie(); 10751 10752 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10753 export_dependency(exp_pg, &elts); 10754 continue; 10755 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10756 export_method(exp_pg, &elts); 10757 continue; 10758 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10759 if (scf_pg_get_name(exp_pg, exp_str, 10760 max_scf_name_len + 1) < 0) 10761 scfdie(); 10762 10763 if (strcmp(exp_str, scf_pg_general) == 0) { 10764 export_svc_general(exp_pg, &elts); 10765 continue; 10766 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10767 0) { 10768 export_method_context(exp_pg, &elts); 10769 continue; 10770 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10771 export_dependents(exp_pg, &elts); 10772 continue; 10773 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10774 continue; 10775 } 10776 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10777 export_template(exp_pg, &elts, &template_elts); 10778 continue; 10779 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10780 export_notify_params(exp_pg, &elts); 10781 continue; 10782 } 10783 10784 export_pg(exp_pg, &elts, flags); 10785 } 10786 if (ret == -1) 10787 scfdie(); 10788 10789 if (template_elts.common_name != NULL) { 10790 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10791 (void) xmlAddChild(elts.template, template_elts.common_name); 10792 (void) xmlAddChild(elts.template, template_elts.description); 10793 (void) xmlAddChild(elts.template, template_elts.documentation); 10794 } else { 10795 xmlFreeNode(template_elts.description); 10796 xmlFreeNode(template_elts.documentation); 10797 } 10798 10799 /* Iterate instances */ 10800 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10801 scfdie(); 10802 10803 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10804 export_instance(exp_inst, &elts, flags); 10805 if (ret == -1) 10806 scfdie(); 10807 10808 /* Now add all of the accumulated elements in order. */ 10809 (void) xmlAddChild(snode, elts.create_default_instance); 10810 (void) xmlAddChild(snode, elts.single_instance); 10811 (void) xmlAddChild(snode, elts.restarter); 10812 (void) xmlAddChildList(snode, elts.dependencies); 10813 (void) xmlAddChildList(snode, elts.dependents); 10814 (void) xmlAddChild(snode, elts.method_context); 10815 (void) xmlAddChildList(snode, elts.exec_methods); 10816 (void) xmlAddChildList(snode, elts.notify_params); 10817 (void) xmlAddChildList(snode, elts.property_groups); 10818 (void) xmlAddChildList(snode, elts.instances); 10819 (void) xmlAddChild(snode, elts.stability); 10820 (void) xmlAddChild(snode, elts.template); 10821 10822 return (snode); 10823 } 10824 10825 static int 10826 export_callback(void *data, scf_walkinfo_t *wip) 10827 { 10828 FILE *f; 10829 xmlDocPtr doc; 10830 xmlNodePtr sb; 10831 int result; 10832 struct export_args *argsp = (struct export_args *)data; 10833 10834 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10835 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10836 (exp_prop = scf_property_create(g_hndl)) == NULL || 10837 (exp_val = scf_value_create(g_hndl)) == NULL || 10838 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10839 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10840 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10841 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10842 scfdie(); 10843 10844 exp_str_sz = max_scf_len + 1; 10845 exp_str = safe_malloc(exp_str_sz); 10846 10847 if (argsp->filename != NULL) { 10848 errno = 0; 10849 f = fopen(argsp->filename, "wb"); 10850 if (f == NULL) { 10851 if (errno == 0) 10852 uu_die(gettext("Could not open \"%s\": no free " 10853 "stdio streams.\n"), argsp->filename); 10854 else 10855 uu_die(gettext("Could not open \"%s\""), 10856 argsp->filename); 10857 } 10858 } else 10859 f = stdout; 10860 10861 doc = xmlNewDoc((xmlChar *)"1.0"); 10862 if (doc == NULL) 10863 uu_die(gettext("Could not create XML document.\n")); 10864 10865 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10866 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10867 uu_die(emsg_create_xml); 10868 10869 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10870 if (sb == NULL) 10871 uu_die(emsg_create_xml); 10872 safe_setprop(sb, type_attr, "manifest"); 10873 safe_setprop(sb, name_attr, "export"); 10874 (void) xmlAddSibling(doc->children, sb); 10875 10876 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10877 10878 result = write_service_bundle(doc, f); 10879 10880 free(exp_str); 10881 scf_iter_destroy(exp_val_iter); 10882 scf_iter_destroy(exp_prop_iter); 10883 scf_iter_destroy(exp_pg_iter); 10884 scf_iter_destroy(exp_inst_iter); 10885 scf_value_destroy(exp_val); 10886 scf_property_destroy(exp_prop); 10887 scf_pg_destroy(exp_pg); 10888 scf_instance_destroy(exp_inst); 10889 10890 xmlFreeDoc(doc); 10891 10892 if (f != stdout) 10893 (void) fclose(f); 10894 10895 return (result); 10896 } 10897 10898 /* 10899 * Get the service named by fmri, build an XML tree which represents it, and 10900 * dump it into filename (or stdout if filename is NULL). 10901 */ 10902 int 10903 lscf_service_export(char *fmri, const char *filename, int flags) 10904 { 10905 struct export_args args; 10906 char *fmridup; 10907 const char *scope, *svc, *inst; 10908 size_t cblen = 3 * max_scf_name_len; 10909 char *canonbuf = alloca(cblen); 10910 int ret, err; 10911 10912 lscf_prep_hndl(); 10913 10914 bzero(&args, sizeof (args)); 10915 args.filename = filename; 10916 args.flags = flags; 10917 10918 /* 10919 * If some poor user has passed an exact instance FMRI, of the sort 10920 * one might cut and paste from svcs(1) or an error message, warn 10921 * and chop off the instance instead of failing. 10922 */ 10923 fmridup = alloca(strlen(fmri) + 1); 10924 (void) strcpy(fmridup, fmri); 10925 if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX, 10926 sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 && 10927 scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 && 10928 inst != NULL) { 10929 (void) strlcpy(canonbuf, "svc:/", cblen); 10930 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) { 10931 (void) strlcat(canonbuf, "/", cblen); 10932 (void) strlcat(canonbuf, scope, cblen); 10933 } 10934 (void) strlcat(canonbuf, svc, cblen); 10935 fmri = canonbuf; 10936 10937 warn(gettext("Only services may be exported; ignoring " 10938 "instance portion of argument.\n")); 10939 } 10940 10941 err = 0; 10942 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10943 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10944 &args, &err, semerr)) != 0) { 10945 if (ret != -1) 10946 semerr(gettext("Failed to walk instances: %s\n"), 10947 scf_strerror(ret)); 10948 return (-1); 10949 } 10950 10951 /* 10952 * Error message has already been printed. 10953 */ 10954 if (err != 0) 10955 return (-1); 10956 10957 return (0); 10958 } 10959 10960 10961 /* 10962 * Archive 10963 */ 10964 10965 static xmlNodePtr 10966 make_archive(int flags) 10967 { 10968 xmlNodePtr sb; 10969 scf_scope_t *scope; 10970 scf_service_t *svc; 10971 scf_iter_t *iter; 10972 int r; 10973 10974 if ((scope = scf_scope_create(g_hndl)) == NULL || 10975 (svc = scf_service_create(g_hndl)) == NULL || 10976 (iter = scf_iter_create(g_hndl)) == NULL || 10977 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10978 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10979 (exp_prop = scf_property_create(g_hndl)) == NULL || 10980 (exp_val = scf_value_create(g_hndl)) == NULL || 10981 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10982 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10983 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10984 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10985 scfdie(); 10986 10987 exp_str_sz = max_scf_len + 1; 10988 exp_str = safe_malloc(exp_str_sz); 10989 10990 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10991 if (sb == NULL) 10992 uu_die(emsg_create_xml); 10993 safe_setprop(sb, type_attr, "archive"); 10994 safe_setprop(sb, name_attr, "none"); 10995 10996 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 10997 scfdie(); 10998 if (scf_iter_scope_services(iter, scope) != 0) 10999 scfdie(); 11000 11001 for (;;) { 11002 r = scf_iter_next_service(iter, svc); 11003 if (r == 0) 11004 break; 11005 if (r != 1) 11006 scfdie(); 11007 11008 if (scf_service_get_name(svc, exp_str, 11009 max_scf_name_len + 1) < 0) 11010 scfdie(); 11011 11012 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 11013 continue; 11014 11015 (void) xmlAddChild(sb, export_service(svc, flags)); 11016 } 11017 11018 free(exp_str); 11019 11020 scf_iter_destroy(exp_val_iter); 11021 scf_iter_destroy(exp_prop_iter); 11022 scf_iter_destroy(exp_pg_iter); 11023 scf_iter_destroy(exp_inst_iter); 11024 scf_value_destroy(exp_val); 11025 scf_property_destroy(exp_prop); 11026 scf_pg_destroy(exp_pg); 11027 scf_instance_destroy(exp_inst); 11028 scf_iter_destroy(iter); 11029 scf_service_destroy(svc); 11030 scf_scope_destroy(scope); 11031 11032 return (sb); 11033 } 11034 11035 int 11036 lscf_archive(const char *filename, int flags) 11037 { 11038 FILE *f; 11039 xmlDocPtr doc; 11040 int result; 11041 11042 lscf_prep_hndl(); 11043 11044 if (filename != NULL) { 11045 errno = 0; 11046 f = fopen(filename, "wb"); 11047 if (f == NULL) { 11048 if (errno == 0) 11049 uu_die(gettext("Could not open \"%s\": no free " 11050 "stdio streams.\n"), filename); 11051 else 11052 uu_die(gettext("Could not open \"%s\""), 11053 filename); 11054 } 11055 } else 11056 f = stdout; 11057 11058 doc = xmlNewDoc((xmlChar *)"1.0"); 11059 if (doc == NULL) 11060 uu_die(gettext("Could not create XML document.\n")); 11061 11062 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11063 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11064 uu_die(emsg_create_xml); 11065 11066 (void) xmlAddSibling(doc->children, make_archive(flags)); 11067 11068 result = write_service_bundle(doc, f); 11069 11070 xmlFreeDoc(doc); 11071 11072 if (f != stdout) 11073 (void) fclose(f); 11074 11075 return (result); 11076 } 11077 11078 11079 /* 11080 * "Extract" a profile. 11081 */ 11082 int 11083 lscf_profile_extract(const char *filename) 11084 { 11085 FILE *f; 11086 xmlDocPtr doc; 11087 xmlNodePtr sb, snode, inode; 11088 scf_scope_t *scope; 11089 scf_service_t *svc; 11090 scf_instance_t *inst; 11091 scf_propertygroup_t *pg; 11092 scf_property_t *prop; 11093 scf_value_t *val; 11094 scf_iter_t *siter, *iiter; 11095 int r, s; 11096 char *namebuf; 11097 uint8_t b; 11098 int result; 11099 11100 lscf_prep_hndl(); 11101 11102 if (filename != NULL) { 11103 errno = 0; 11104 f = fopen(filename, "wb"); 11105 if (f == NULL) { 11106 if (errno == 0) 11107 uu_die(gettext("Could not open \"%s\": no " 11108 "free stdio streams.\n"), filename); 11109 else 11110 uu_die(gettext("Could not open \"%s\""), 11111 filename); 11112 } 11113 } else 11114 f = stdout; 11115 11116 doc = xmlNewDoc((xmlChar *)"1.0"); 11117 if (doc == NULL) 11118 uu_die(gettext("Could not create XML document.\n")); 11119 11120 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 11121 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 11122 uu_die(emsg_create_xml); 11123 11124 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 11125 if (sb == NULL) 11126 uu_die(emsg_create_xml); 11127 safe_setprop(sb, type_attr, "profile"); 11128 safe_setprop(sb, name_attr, "extract"); 11129 (void) xmlAddSibling(doc->children, sb); 11130 11131 if ((scope = scf_scope_create(g_hndl)) == NULL || 11132 (svc = scf_service_create(g_hndl)) == NULL || 11133 (inst = scf_instance_create(g_hndl)) == NULL || 11134 (pg = scf_pg_create(g_hndl)) == NULL || 11135 (prop = scf_property_create(g_hndl)) == NULL || 11136 (val = scf_value_create(g_hndl)) == NULL || 11137 (siter = scf_iter_create(g_hndl)) == NULL || 11138 (iiter = scf_iter_create(g_hndl)) == NULL) 11139 scfdie(); 11140 11141 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 11142 scfdie(); 11143 11144 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 11145 scfdie(); 11146 11147 namebuf = safe_malloc(max_scf_name_len + 1); 11148 11149 while ((r = scf_iter_next_service(siter, svc)) == 1) { 11150 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 11151 scfdie(); 11152 11153 snode = xmlNewNode(NULL, (xmlChar *)"service"); 11154 if (snode == NULL) 11155 uu_die(emsg_create_xml); 11156 11157 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 11158 0) 11159 scfdie(); 11160 11161 safe_setprop(snode, name_attr, namebuf); 11162 11163 safe_setprop(snode, type_attr, "service"); 11164 safe_setprop(snode, "version", "0"); 11165 11166 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 11167 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 11168 SCF_SUCCESS) { 11169 if (scf_error() != SCF_ERROR_NOT_FOUND) 11170 scfdie(); 11171 11172 if (g_verbose) { 11173 ssize_t len; 11174 char *fmri; 11175 11176 len = 11177 scf_instance_to_fmri(inst, NULL, 0); 11178 if (len < 0) 11179 scfdie(); 11180 11181 fmri = safe_malloc(len + 1); 11182 11183 if (scf_instance_to_fmri(inst, fmri, 11184 len + 1) < 0) 11185 scfdie(); 11186 11187 warn("Instance %s has no \"%s\" " 11188 "property group.\n", fmri, 11189 scf_pg_general); 11190 11191 free(fmri); 11192 } 11193 11194 continue; 11195 } 11196 11197 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 11198 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 11199 prop_get_val(prop, val) != 0) 11200 continue; 11201 11202 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 11203 NULL); 11204 if (inode == NULL) 11205 uu_die(emsg_create_xml); 11206 11207 if (scf_instance_get_name(inst, namebuf, 11208 max_scf_name_len + 1) < 0) 11209 scfdie(); 11210 11211 safe_setprop(inode, name_attr, namebuf); 11212 11213 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 11214 scfdie(); 11215 11216 safe_setprop(inode, enabled_attr, b ? true : false); 11217 } 11218 if (s < 0) 11219 scfdie(); 11220 11221 if (snode->children != NULL) 11222 (void) xmlAddChild(sb, snode); 11223 else 11224 xmlFreeNode(snode); 11225 } 11226 if (r < 0) 11227 scfdie(); 11228 11229 free(namebuf); 11230 11231 result = write_service_bundle(doc, f); 11232 11233 xmlFreeDoc(doc); 11234 11235 if (f != stdout) 11236 (void) fclose(f); 11237 11238 return (result); 11239 } 11240 11241 11242 /* 11243 * Entity manipulation commands 11244 */ 11245 11246 /* 11247 * Entity selection. If no entity is selected, then the current scope is in 11248 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 11249 * only cur_inst is NULL, and when an instance is selected, none are NULL. 11250 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 11251 * cur_inst will be non-NULL. 11252 */ 11253 11254 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 11255 static int 11256 select_inst(const char *name) 11257 { 11258 scf_instance_t *inst; 11259 scf_error_t err; 11260 11261 assert(cur_svc != NULL); 11262 11263 inst = scf_instance_create(g_hndl); 11264 if (inst == NULL) 11265 scfdie(); 11266 11267 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 11268 cur_inst = inst; 11269 return (0); 11270 } 11271 11272 err = scf_error(); 11273 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11274 scfdie(); 11275 11276 scf_instance_destroy(inst); 11277 return (1); 11278 } 11279 11280 /* Returns as above. */ 11281 static int 11282 select_svc(const char *name) 11283 { 11284 scf_service_t *svc; 11285 scf_error_t err; 11286 11287 assert(cur_scope != NULL); 11288 11289 svc = scf_service_create(g_hndl); 11290 if (svc == NULL) 11291 scfdie(); 11292 11293 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 11294 cur_svc = svc; 11295 return (0); 11296 } 11297 11298 err = scf_error(); 11299 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 11300 scfdie(); 11301 11302 scf_service_destroy(svc); 11303 return (1); 11304 } 11305 11306 /* ARGSUSED */ 11307 static int 11308 select_callback(void *unused, scf_walkinfo_t *wip) 11309 { 11310 scf_instance_t *inst; 11311 scf_service_t *svc; 11312 scf_scope_t *scope; 11313 11314 if (wip->inst != NULL) { 11315 if ((scope = scf_scope_create(g_hndl)) == NULL || 11316 (svc = scf_service_create(g_hndl)) == NULL || 11317 (inst = scf_instance_create(g_hndl)) == NULL) 11318 scfdie(); 11319 11320 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11321 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11322 scfdie(); 11323 } else { 11324 assert(wip->svc != NULL); 11325 11326 if ((scope = scf_scope_create(g_hndl)) == NULL || 11327 (svc = scf_service_create(g_hndl)) == NULL) 11328 scfdie(); 11329 11330 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11331 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11332 scfdie(); 11333 11334 inst = NULL; 11335 } 11336 11337 /* Clear out the current selection */ 11338 assert(cur_scope != NULL); 11339 scf_scope_destroy(cur_scope); 11340 scf_service_destroy(cur_svc); 11341 scf_instance_destroy(cur_inst); 11342 11343 cur_scope = scope; 11344 cur_svc = svc; 11345 cur_inst = inst; 11346 11347 return (0); 11348 } 11349 11350 static int 11351 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 11352 { 11353 char **fmri = fmri_p; 11354 11355 *fmri = strdup(wip->fmri); 11356 if (*fmri == NULL) 11357 uu_die(gettext("Out of memory.\n")); 11358 11359 return (0); 11360 } 11361 11362 /* 11363 * validate [fmri] 11364 * Perform the validation of an FMRI instance. 11365 */ 11366 void 11367 lscf_validate_fmri(const char *fmri) 11368 { 11369 int ret = 0; 11370 size_t inst_sz; 11371 char *inst_fmri = NULL; 11372 scf_tmpl_errors_t *errs = NULL; 11373 char *snapbuf = NULL; 11374 11375 lscf_prep_hndl(); 11376 11377 if (fmri == NULL) { 11378 inst_sz = max_scf_fmri_len + 1; 11379 inst_fmri = safe_malloc(inst_sz); 11380 11381 if (cur_snap != NULL) { 11382 snapbuf = safe_malloc(max_scf_name_len + 1); 11383 if (scf_snapshot_get_name(cur_snap, snapbuf, 11384 max_scf_name_len + 1) < 0) 11385 scfdie(); 11386 } 11387 if (cur_inst == NULL) { 11388 semerr(gettext("No instance selected\n")); 11389 goto cleanup; 11390 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 11391 inst_sz) >= inst_sz) { 11392 /* sanity check. Should never get here */ 11393 uu_die(gettext("Unexpected error! file %s, line %d\n"), 11394 __FILE__, __LINE__); 11395 } 11396 } else { 11397 scf_error_t scf_err; 11398 int err = 0; 11399 11400 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 11401 validate_callback, &inst_fmri, &err, semerr)) != 0) { 11402 uu_warn("Failed to walk instances: %s\n", 11403 scf_strerror(scf_err)); 11404 goto cleanup; 11405 } 11406 if (err != 0) { 11407 /* error message displayed by scf_walk_fmri */ 11408 goto cleanup; 11409 } 11410 } 11411 11412 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 11413 SCF_TMPL_VALIDATE_FLAG_CURRENT); 11414 if (ret == -1) { 11415 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 11416 warn(gettext("Template data for %s is invalid. " 11417 "Consider reverting to a previous snapshot or " 11418 "restoring original configuration.\n"), inst_fmri); 11419 } else { 11420 uu_warn("%s: %s\n", 11421 gettext("Error validating the instance"), 11422 scf_strerror(scf_error())); 11423 } 11424 } else if (ret == 1 && errs != NULL) { 11425 scf_tmpl_error_t *err = NULL; 11426 char *msg; 11427 size_t len = 256; /* initial error buffer size */ 11428 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 11429 SCF_TMPL_STRERROR_HUMAN : 0; 11430 11431 msg = safe_malloc(len); 11432 11433 while ((err = scf_tmpl_next_error(errs)) != NULL) { 11434 int ret; 11435 11436 if ((ret = scf_tmpl_strerror(err, msg, len, 11437 flag)) >= len) { 11438 len = ret + 1; 11439 msg = realloc(msg, len); 11440 if (msg == NULL) 11441 uu_die(gettext( 11442 "Out of memory.\n")); 11443 (void) scf_tmpl_strerror(err, msg, len, 11444 flag); 11445 } 11446 (void) fprintf(stderr, "%s\n", msg); 11447 } 11448 if (msg != NULL) 11449 free(msg); 11450 } 11451 if (errs != NULL) 11452 scf_tmpl_errors_destroy(errs); 11453 11454 cleanup: 11455 free(inst_fmri); 11456 free(snapbuf); 11457 } 11458 11459 static void 11460 lscf_validate_file(const char *filename) 11461 { 11462 tmpl_errors_t *errs; 11463 11464 bundle_t *b = internal_bundle_new(); 11465 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 11466 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 11467 tmpl_errors_print(stderr, errs, ""); 11468 semerr(gettext("Validation failed.\n")); 11469 } 11470 tmpl_errors_destroy(errs); 11471 } 11472 (void) internal_bundle_free(b); 11473 } 11474 11475 /* 11476 * validate [fmri|file] 11477 */ 11478 void 11479 lscf_validate(const char *arg) 11480 { 11481 const char *str; 11482 11483 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 11484 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 11485 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 11486 lscf_validate_file(str); 11487 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 11488 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 11489 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 11490 lscf_validate_fmri(str); 11491 } else if (access(arg, R_OK | F_OK) == 0) { 11492 lscf_validate_file(arg); 11493 } else { 11494 lscf_validate_fmri(arg); 11495 } 11496 } 11497 11498 void 11499 lscf_select(const char *fmri) 11500 { 11501 int ret, err; 11502 11503 lscf_prep_hndl(); 11504 11505 if (cur_snap != NULL) { 11506 struct snaplevel *elt; 11507 char *buf; 11508 11509 /* Error unless name is that of the next level. */ 11510 elt = uu_list_next(cur_levels, cur_elt); 11511 if (elt == NULL) { 11512 semerr(gettext("No children.\n")); 11513 return; 11514 } 11515 11516 buf = safe_malloc(max_scf_name_len + 1); 11517 11518 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11519 max_scf_name_len + 1) < 0) 11520 scfdie(); 11521 11522 if (strcmp(buf, fmri) != 0) { 11523 semerr(gettext("No such child.\n")); 11524 free(buf); 11525 return; 11526 } 11527 11528 free(buf); 11529 11530 cur_elt = elt; 11531 cur_level = elt->sl; 11532 return; 11533 } 11534 11535 /* 11536 * Special case for 'svc:', which takes the user to the scope level. 11537 */ 11538 if (strcmp(fmri, "svc:") == 0) { 11539 scf_instance_destroy(cur_inst); 11540 scf_service_destroy(cur_svc); 11541 cur_inst = NULL; 11542 cur_svc = NULL; 11543 return; 11544 } 11545 11546 /* 11547 * Special case for ':properties'. This appears as part of 'list' but 11548 * can't be selected. Give a more helpful error message in this case. 11549 */ 11550 if (strcmp(fmri, ":properties") == 0) { 11551 semerr(gettext(":properties is not an entity. Try 'listprop' " 11552 "to list properties.\n")); 11553 return; 11554 } 11555 11556 /* 11557 * First try the argument as relative to the current selection. 11558 */ 11559 if (cur_inst != NULL) { 11560 /* EMPTY */; 11561 } else if (cur_svc != NULL) { 11562 if (select_inst(fmri) != 1) 11563 return; 11564 } else { 11565 if (select_svc(fmri) != 1) 11566 return; 11567 } 11568 11569 err = 0; 11570 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11571 select_callback, NULL, &err, semerr)) != 0) { 11572 semerr(gettext("Failed to walk instances: %s\n"), 11573 scf_strerror(ret)); 11574 } 11575 } 11576 11577 void 11578 lscf_unselect(void) 11579 { 11580 lscf_prep_hndl(); 11581 11582 if (cur_snap != NULL) { 11583 struct snaplevel *elt; 11584 11585 elt = uu_list_prev(cur_levels, cur_elt); 11586 if (elt == NULL) { 11587 semerr(gettext("No parent levels.\n")); 11588 } else { 11589 cur_elt = elt; 11590 cur_level = elt->sl; 11591 } 11592 } else if (cur_inst != NULL) { 11593 scf_instance_destroy(cur_inst); 11594 cur_inst = NULL; 11595 } else if (cur_svc != NULL) { 11596 scf_service_destroy(cur_svc); 11597 cur_svc = NULL; 11598 } else { 11599 semerr(gettext("Cannot unselect at scope level.\n")); 11600 } 11601 } 11602 11603 /* 11604 * Return the FMRI of the current selection, for the prompt. 11605 */ 11606 void 11607 lscf_get_selection_str(char *buf, size_t bufsz) 11608 { 11609 char *cp; 11610 ssize_t fmrilen, szret; 11611 boolean_t deleted = B_FALSE; 11612 11613 if (g_hndl == NULL) { 11614 (void) strlcpy(buf, "svc:", bufsz); 11615 return; 11616 } 11617 11618 if (cur_level != NULL) { 11619 assert(cur_snap != NULL); 11620 11621 /* [ snapshot ] FMRI [: instance ] */ 11622 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11623 + 2 + max_scf_name_len + 1 + 1); 11624 11625 buf[0] = '['; 11626 11627 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11628 max_scf_name_len + 1); 11629 if (szret < 0) { 11630 if (scf_error() != SCF_ERROR_DELETED) 11631 scfdie(); 11632 11633 goto snap_deleted; 11634 } 11635 11636 (void) strcat(buf, "]svc:/"); 11637 11638 cp = strchr(buf, '\0'); 11639 11640 szret = scf_snaplevel_get_service_name(cur_level, cp, 11641 max_scf_name_len + 1); 11642 if (szret < 0) { 11643 if (scf_error() != SCF_ERROR_DELETED) 11644 scfdie(); 11645 11646 goto snap_deleted; 11647 } 11648 11649 cp = strchr(cp, '\0'); 11650 11651 if (snaplevel_is_instance(cur_level)) { 11652 *cp++ = ':'; 11653 11654 if (scf_snaplevel_get_instance_name(cur_level, cp, 11655 max_scf_name_len + 1) < 0) { 11656 if (scf_error() != SCF_ERROR_DELETED) 11657 scfdie(); 11658 11659 goto snap_deleted; 11660 } 11661 } else { 11662 *cp++ = '['; 11663 *cp++ = ':'; 11664 11665 if (scf_instance_get_name(cur_inst, cp, 11666 max_scf_name_len + 1) < 0) { 11667 if (scf_error() != SCF_ERROR_DELETED) 11668 scfdie(); 11669 11670 goto snap_deleted; 11671 } 11672 11673 (void) strcat(buf, "]"); 11674 } 11675 11676 return; 11677 11678 snap_deleted: 11679 deleted = B_TRUE; 11680 free(buf); 11681 unselect_cursnap(); 11682 } 11683 11684 assert(cur_snap == NULL); 11685 11686 if (cur_inst != NULL) { 11687 assert(cur_svc != NULL); 11688 assert(cur_scope != NULL); 11689 11690 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11691 if (fmrilen >= 0) { 11692 assert(fmrilen < bufsz); 11693 if (deleted) 11694 warn(emsg_deleted); 11695 return; 11696 } 11697 11698 if (scf_error() != SCF_ERROR_DELETED) 11699 scfdie(); 11700 11701 deleted = B_TRUE; 11702 11703 scf_instance_destroy(cur_inst); 11704 cur_inst = NULL; 11705 } 11706 11707 if (cur_svc != NULL) { 11708 assert(cur_scope != NULL); 11709 11710 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11711 if (szret >= 0) { 11712 assert(szret < bufsz); 11713 if (deleted) 11714 warn(emsg_deleted); 11715 return; 11716 } 11717 11718 if (scf_error() != SCF_ERROR_DELETED) 11719 scfdie(); 11720 11721 deleted = B_TRUE; 11722 scf_service_destroy(cur_svc); 11723 cur_svc = NULL; 11724 } 11725 11726 assert(cur_scope != NULL); 11727 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11728 11729 if (fmrilen < 0) 11730 scfdie(); 11731 11732 assert(fmrilen < bufsz); 11733 if (deleted) 11734 warn(emsg_deleted); 11735 } 11736 11737 /* 11738 * Entity listing. Entities and colon namespaces (e.g., :properties and 11739 * :statistics) are listed for the current selection. 11740 */ 11741 void 11742 lscf_list(const char *pattern) 11743 { 11744 scf_iter_t *iter; 11745 char *buf; 11746 int ret; 11747 11748 lscf_prep_hndl(); 11749 11750 if (cur_level != NULL) { 11751 struct snaplevel *elt; 11752 11753 (void) fputs(COLON_NAMESPACES, stdout); 11754 11755 elt = uu_list_next(cur_levels, cur_elt); 11756 if (elt == NULL) 11757 return; 11758 11759 /* 11760 * For now, we know that the next level is an instance. But 11761 * if we ever have multiple scopes, this could be complicated. 11762 */ 11763 buf = safe_malloc(max_scf_name_len + 1); 11764 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11765 max_scf_name_len + 1) >= 0) { 11766 (void) puts(buf); 11767 } else { 11768 if (scf_error() != SCF_ERROR_DELETED) 11769 scfdie(); 11770 } 11771 11772 free(buf); 11773 11774 return; 11775 } 11776 11777 if (cur_inst != NULL) { 11778 (void) fputs(COLON_NAMESPACES, stdout); 11779 return; 11780 } 11781 11782 iter = scf_iter_create(g_hndl); 11783 if (iter == NULL) 11784 scfdie(); 11785 11786 buf = safe_malloc(max_scf_name_len + 1); 11787 11788 if (cur_svc != NULL) { 11789 /* List the instances in this service. */ 11790 scf_instance_t *inst; 11791 11792 inst = scf_instance_create(g_hndl); 11793 if (inst == NULL) 11794 scfdie(); 11795 11796 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11797 safe_printf(COLON_NAMESPACES); 11798 11799 for (;;) { 11800 ret = scf_iter_next_instance(iter, inst); 11801 if (ret == 0) 11802 break; 11803 if (ret != 1) { 11804 if (scf_error() != SCF_ERROR_DELETED) 11805 scfdie(); 11806 11807 break; 11808 } 11809 11810 if (scf_instance_get_name(inst, buf, 11811 max_scf_name_len + 1) >= 0) { 11812 if (pattern == NULL || 11813 fnmatch(pattern, buf, 0) == 0) 11814 (void) puts(buf); 11815 } else { 11816 if (scf_error() != SCF_ERROR_DELETED) 11817 scfdie(); 11818 } 11819 } 11820 } else { 11821 if (scf_error() != SCF_ERROR_DELETED) 11822 scfdie(); 11823 } 11824 11825 scf_instance_destroy(inst); 11826 } else { 11827 /* List the services in this scope. */ 11828 scf_service_t *svc; 11829 11830 assert(cur_scope != NULL); 11831 11832 svc = scf_service_create(g_hndl); 11833 if (svc == NULL) 11834 scfdie(); 11835 11836 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11837 scfdie(); 11838 11839 for (;;) { 11840 ret = scf_iter_next_service(iter, svc); 11841 if (ret == 0) 11842 break; 11843 if (ret != 1) 11844 scfdie(); 11845 11846 if (scf_service_get_name(svc, buf, 11847 max_scf_name_len + 1) >= 0) { 11848 if (pattern == NULL || 11849 fnmatch(pattern, buf, 0) == 0) 11850 safe_printf("%s\n", buf); 11851 } else { 11852 if (scf_error() != SCF_ERROR_DELETED) 11853 scfdie(); 11854 } 11855 } 11856 11857 scf_service_destroy(svc); 11858 } 11859 11860 free(buf); 11861 scf_iter_destroy(iter); 11862 } 11863 11864 /* 11865 * Entity addition. Creates an empty entity in the current selection. 11866 */ 11867 void 11868 lscf_add(const char *name) 11869 { 11870 lscf_prep_hndl(); 11871 11872 if (cur_snap != NULL) { 11873 semerr(emsg_cant_modify_snapshots); 11874 } else if (cur_inst != NULL) { 11875 semerr(gettext("Cannot add entities to an instance.\n")); 11876 } else if (cur_svc != NULL) { 11877 11878 if (scf_service_add_instance(cur_svc, name, NULL) != 11879 SCF_SUCCESS) { 11880 switch (scf_error()) { 11881 case SCF_ERROR_INVALID_ARGUMENT: 11882 semerr(gettext("Invalid name.\n")); 11883 break; 11884 11885 case SCF_ERROR_EXISTS: 11886 semerr(gettext("Instance already exists.\n")); 11887 break; 11888 11889 case SCF_ERROR_PERMISSION_DENIED: 11890 semerr(emsg_permission_denied); 11891 break; 11892 11893 default: 11894 scfdie(); 11895 } 11896 } 11897 } else { 11898 assert(cur_scope != NULL); 11899 11900 if (scf_scope_add_service(cur_scope, name, NULL) != 11901 SCF_SUCCESS) { 11902 switch (scf_error()) { 11903 case SCF_ERROR_INVALID_ARGUMENT: 11904 semerr(gettext("Invalid name.\n")); 11905 break; 11906 11907 case SCF_ERROR_EXISTS: 11908 semerr(gettext("Service already exists.\n")); 11909 break; 11910 11911 case SCF_ERROR_PERMISSION_DENIED: 11912 semerr(emsg_permission_denied); 11913 break; 11914 11915 case SCF_ERROR_BACKEND_READONLY: 11916 semerr(emsg_read_only); 11917 break; 11918 11919 default: 11920 scfdie(); 11921 } 11922 } 11923 } 11924 } 11925 11926 /* return 1 if the entity has no persistent pgs, else return 0 */ 11927 static int 11928 entity_has_no_pgs(void *ent, int isservice) 11929 { 11930 scf_iter_t *iter = NULL; 11931 scf_propertygroup_t *pg = NULL; 11932 uint32_t flags; 11933 int err; 11934 int ret = 1; 11935 11936 if ((iter = scf_iter_create(g_hndl)) == NULL || 11937 (pg = scf_pg_create(g_hndl)) == NULL) 11938 scfdie(); 11939 11940 if (isservice) { 11941 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11942 scfdie(); 11943 } else { 11944 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11945 scfdie(); 11946 } 11947 11948 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11949 if (scf_pg_get_flags(pg, &flags) != 0) 11950 scfdie(); 11951 11952 /* skip nonpersistent pgs */ 11953 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11954 continue; 11955 11956 ret = 0; 11957 break; 11958 } 11959 11960 if (err == -1) 11961 scfdie(); 11962 11963 scf_pg_destroy(pg); 11964 scf_iter_destroy(iter); 11965 11966 return (ret); 11967 } 11968 11969 /* return 1 if the service has no instances, else return 0 */ 11970 static int 11971 svc_has_no_insts(scf_service_t *svc) 11972 { 11973 scf_instance_t *inst; 11974 scf_iter_t *iter; 11975 int r; 11976 int ret = 1; 11977 11978 if ((inst = scf_instance_create(g_hndl)) == NULL || 11979 (iter = scf_iter_create(g_hndl)) == NULL) 11980 scfdie(); 11981 11982 if (scf_iter_service_instances(iter, svc) != 0) 11983 scfdie(); 11984 11985 r = scf_iter_next_instance(iter, inst); 11986 if (r == 1) { 11987 ret = 0; 11988 } else if (r == 0) { 11989 ret = 1; 11990 } else if (r == -1) { 11991 scfdie(); 11992 } else { 11993 bad_error("scf_iter_next_instance", r); 11994 } 11995 11996 scf_iter_destroy(iter); 11997 scf_instance_destroy(inst); 11998 11999 return (ret); 12000 } 12001 12002 /* 12003 * Entity deletion. 12004 */ 12005 12006 /* 12007 * Delete the property group <fmri>/:properties/<name>. Returns 12008 * SCF_ERROR_NONE on success (or if the entity is not found), 12009 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 12010 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 12011 * denied. 12012 */ 12013 static scf_error_t 12014 delete_dependency_pg(const char *fmri, const char *name) 12015 { 12016 void *entity = NULL; 12017 int isservice; 12018 scf_propertygroup_t *pg = NULL; 12019 scf_error_t result; 12020 char *pgty; 12021 scf_service_t *svc = NULL; 12022 scf_instance_t *inst = NULL; 12023 scf_iter_t *iter = NULL; 12024 char *name_buf = NULL; 12025 12026 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 12027 switch (result) { 12028 case SCF_ERROR_NONE: 12029 break; 12030 12031 case SCF_ERROR_NO_MEMORY: 12032 uu_die(gettext("Out of memory.\n")); 12033 /* NOTREACHED */ 12034 12035 case SCF_ERROR_INVALID_ARGUMENT: 12036 case SCF_ERROR_CONSTRAINT_VIOLATED: 12037 return (SCF_ERROR_INVALID_ARGUMENT); 12038 12039 case SCF_ERROR_NOT_FOUND: 12040 result = SCF_ERROR_NONE; 12041 goto out; 12042 12043 default: 12044 bad_error("fmri_to_entity", result); 12045 } 12046 12047 pg = scf_pg_create(g_hndl); 12048 if (pg == NULL) 12049 scfdie(); 12050 12051 if (entity_get_pg(entity, isservice, name, pg) != 0) { 12052 if (scf_error() != SCF_ERROR_NOT_FOUND) 12053 scfdie(); 12054 12055 result = SCF_ERROR_NONE; 12056 goto out; 12057 } 12058 12059 pgty = safe_malloc(max_scf_pg_type_len + 1); 12060 12061 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12062 scfdie(); 12063 12064 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 12065 result = SCF_ERROR_TYPE_MISMATCH; 12066 free(pgty); 12067 goto out; 12068 } 12069 12070 free(pgty); 12071 12072 if (scf_pg_delete(pg) != 0) { 12073 result = scf_error(); 12074 if (result != SCF_ERROR_PERMISSION_DENIED) 12075 scfdie(); 12076 goto out; 12077 } 12078 12079 /* 12080 * We have to handle the case where we've just deleted the last 12081 * property group of a "dummy" entity (instance or service). 12082 * A "dummy" entity is an entity only present to hold an 12083 * external dependency. 12084 * So, in the case we deleted the last property group then we 12085 * can also delete the entity. If the entity is an instance then 12086 * we must verify if this was the last instance for the service 12087 * and if it is, we can also delete the service if it doesn't 12088 * have any property group either. 12089 */ 12090 12091 result = SCF_ERROR_NONE; 12092 12093 if (isservice) { 12094 svc = (scf_service_t *)entity; 12095 12096 if ((inst = scf_instance_create(g_hndl)) == NULL || 12097 (iter = scf_iter_create(g_hndl)) == NULL) 12098 scfdie(); 12099 12100 name_buf = safe_malloc(max_scf_name_len + 1); 12101 } else { 12102 inst = (scf_instance_t *)entity; 12103 } 12104 12105 /* 12106 * If the entity is an instance and we've just deleted its last 12107 * property group then we should delete it. 12108 */ 12109 if (!isservice && entity_has_no_pgs(entity, isservice)) { 12110 /* find the service before deleting the inst. - needed later */ 12111 if ((svc = scf_service_create(g_hndl)) == NULL) 12112 scfdie(); 12113 12114 if (scf_instance_get_parent(inst, svc) != 0) 12115 scfdie(); 12116 12117 /* delete the instance */ 12118 if (scf_instance_delete(inst) != 0) { 12119 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12120 scfdie(); 12121 12122 result = SCF_ERROR_PERMISSION_DENIED; 12123 goto out; 12124 } 12125 /* no need to refresh the instance */ 12126 inst = NULL; 12127 } 12128 12129 /* 12130 * If the service has no more instances and pgs or we just deleted the 12131 * last instance and the service doesn't have anymore propery groups 12132 * then the service should be deleted. 12133 */ 12134 if (svc != NULL && 12135 svc_has_no_insts(svc) && 12136 entity_has_no_pgs((void *)svc, 1)) { 12137 if (scf_service_delete(svc) == 0) { 12138 if (isservice) { 12139 /* no need to refresh the service */ 12140 svc = NULL; 12141 } 12142 12143 goto out; 12144 } 12145 12146 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12147 scfdie(); 12148 12149 result = SCF_ERROR_PERMISSION_DENIED; 12150 } 12151 12152 /* if the entity has not been deleted, refresh it */ 12153 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 12154 (void) refresh_entity(isservice, entity, fmri, inst, iter, 12155 name_buf); 12156 } 12157 12158 out: 12159 if (isservice && (inst != NULL && iter != NULL)) { 12160 free(name_buf); 12161 scf_iter_destroy(iter); 12162 scf_instance_destroy(inst); 12163 } 12164 12165 if (!isservice && svc != NULL) { 12166 scf_service_destroy(svc); 12167 } 12168 12169 scf_pg_destroy(pg); 12170 if (entity != NULL) 12171 entity_destroy(entity, isservice); 12172 12173 return (result); 12174 } 12175 12176 static int 12177 delete_dependents(scf_propertygroup_t *pg) 12178 { 12179 char *pgty, *name, *fmri; 12180 scf_property_t *prop; 12181 scf_value_t *val; 12182 scf_iter_t *iter; 12183 int r; 12184 scf_error_t err; 12185 12186 /* Verify that the pg has the correct type. */ 12187 pgty = safe_malloc(max_scf_pg_type_len + 1); 12188 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 12189 scfdie(); 12190 12191 if (strcmp(pgty, scf_group_framework) != 0) { 12192 if (g_verbose) { 12193 fmri = safe_malloc(max_scf_fmri_len + 1); 12194 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 12195 scfdie(); 12196 12197 warn(gettext("Property group %s is not of expected " 12198 "type %s.\n"), fmri, scf_group_framework); 12199 12200 free(fmri); 12201 } 12202 12203 free(pgty); 12204 return (-1); 12205 } 12206 12207 free(pgty); 12208 12209 /* map delete_dependency_pg onto the properties. */ 12210 if ((prop = scf_property_create(g_hndl)) == NULL || 12211 (val = scf_value_create(g_hndl)) == NULL || 12212 (iter = scf_iter_create(g_hndl)) == NULL) 12213 scfdie(); 12214 12215 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 12216 scfdie(); 12217 12218 name = safe_malloc(max_scf_name_len + 1); 12219 fmri = safe_malloc(max_scf_fmri_len + 2); 12220 12221 while ((r = scf_iter_next_property(iter, prop)) == 1) { 12222 scf_type_t ty; 12223 12224 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 12225 scfdie(); 12226 12227 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 12228 scfdie(); 12229 12230 if ((ty != SCF_TYPE_ASTRING && 12231 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 12232 prop_get_val(prop, val) != 0) 12233 continue; 12234 12235 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 12236 scfdie(); 12237 12238 err = delete_dependency_pg(fmri, name); 12239 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 12240 if (scf_property_to_fmri(prop, fmri, 12241 max_scf_fmri_len + 2) < 0) 12242 scfdie(); 12243 12244 warn(gettext("Value of %s is not a valid FMRI.\n"), 12245 fmri); 12246 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 12247 warn(gettext("Property group \"%s\" of entity \"%s\" " 12248 "does not have dependency type.\n"), name, fmri); 12249 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 12250 warn(gettext("Could not delete property group \"%s\" " 12251 "of entity \"%s\" (permission denied).\n"), name, 12252 fmri); 12253 } 12254 } 12255 if (r == -1) 12256 scfdie(); 12257 12258 scf_value_destroy(val); 12259 scf_property_destroy(prop); 12260 12261 return (0); 12262 } 12263 12264 /* 12265 * Returns 1 if the instance may be running, and 0 otherwise. 12266 */ 12267 static int 12268 inst_is_running(scf_instance_t *inst) 12269 { 12270 scf_propertygroup_t *pg; 12271 scf_property_t *prop; 12272 scf_value_t *val; 12273 char buf[MAX_SCF_STATE_STRING_SZ]; 12274 int ret = 0; 12275 ssize_t szret; 12276 12277 if ((pg = scf_pg_create(g_hndl)) == NULL || 12278 (prop = scf_property_create(g_hndl)) == NULL || 12279 (val = scf_value_create(g_hndl)) == NULL) 12280 scfdie(); 12281 12282 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 12283 if (scf_error() != SCF_ERROR_NOT_FOUND) 12284 scfdie(); 12285 goto out; 12286 } 12287 12288 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 12289 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 12290 prop_get_val(prop, val) != 0) 12291 goto out; 12292 12293 szret = scf_value_get_astring(val, buf, sizeof (buf)); 12294 assert(szret >= 0); 12295 12296 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 12297 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 12298 12299 out: 12300 scf_value_destroy(val); 12301 scf_property_destroy(prop); 12302 scf_pg_destroy(pg); 12303 return (ret); 12304 } 12305 12306 static uint8_t 12307 pg_is_external_dependency(scf_propertygroup_t *pg) 12308 { 12309 char *type; 12310 scf_value_t *val; 12311 scf_property_t *prop; 12312 uint8_t b = B_FALSE; 12313 12314 type = safe_malloc(max_scf_pg_type_len + 1); 12315 12316 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 12317 scfdie(); 12318 12319 if ((prop = scf_property_create(g_hndl)) == NULL || 12320 (val = scf_value_create(g_hndl)) == NULL) 12321 scfdie(); 12322 12323 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 12324 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 12325 if (scf_property_get_value(prop, val) != 0) 12326 scfdie(); 12327 if (scf_value_get_boolean(val, &b) != 0) 12328 scfdie(); 12329 } 12330 } 12331 12332 free(type); 12333 (void) scf_value_destroy(val); 12334 (void) scf_property_destroy(prop); 12335 12336 return (b); 12337 } 12338 12339 #define DELETE_FAILURE -1 12340 #define DELETE_SUCCESS_NOEXTDEPS 0 12341 #define DELETE_SUCCESS_EXTDEPS 1 12342 12343 /* 12344 * lscf_instance_delete() deletes an instance. Before calling 12345 * scf_instance_delete(), though, we make sure the instance isn't 12346 * running and delete dependencies in other entities which the instance 12347 * declared as "dependents". If there are dependencies which were 12348 * created for other entities, then instead of deleting the instance we 12349 * make it "empty" by deleting all other property groups and all 12350 * snapshots. 12351 * 12352 * lscf_instance_delete() verifies that there is no external dependency pgs 12353 * before suppressing the instance. If there is, then we must not remove them 12354 * now in case the instance is re-created otherwise the dependencies would be 12355 * lost. The external dependency pgs will be removed if the dependencies are 12356 * removed. 12357 * 12358 * Returns: 12359 * DELETE_FAILURE on failure 12360 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12361 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12362 */ 12363 static int 12364 lscf_instance_delete(scf_instance_t *inst, int force) 12365 { 12366 scf_propertygroup_t *pg; 12367 scf_snapshot_t *snap; 12368 scf_iter_t *iter; 12369 int err; 12370 int external = 0; 12371 12372 /* If we're not forcing and the instance is running, refuse. */ 12373 if (!force && inst_is_running(inst)) { 12374 char *fmri; 12375 12376 fmri = safe_malloc(max_scf_fmri_len + 1); 12377 12378 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 12379 scfdie(); 12380 12381 semerr(gettext("Instance %s may be running. " 12382 "Use delete -f if it is not.\n"), fmri); 12383 12384 free(fmri); 12385 return (DELETE_FAILURE); 12386 } 12387 12388 pg = scf_pg_create(g_hndl); 12389 if (pg == NULL) 12390 scfdie(); 12391 12392 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 12393 (void) delete_dependents(pg); 12394 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12395 scfdie(); 12396 12397 scf_pg_destroy(pg); 12398 12399 /* 12400 * If the instance has some external dependencies then we must 12401 * keep them in case the instance is reimported otherwise the 12402 * dependencies would be lost on reimport. 12403 */ 12404 if ((iter = scf_iter_create(g_hndl)) == NULL || 12405 (pg = scf_pg_create(g_hndl)) == NULL) 12406 scfdie(); 12407 12408 if (scf_iter_instance_pgs(iter, inst) < 0) 12409 scfdie(); 12410 12411 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 12412 if (pg_is_external_dependency(pg)) { 12413 external = 1; 12414 continue; 12415 } 12416 12417 if (scf_pg_delete(pg) != 0) { 12418 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12419 scfdie(); 12420 else { 12421 semerr(emsg_permission_denied); 12422 12423 (void) scf_iter_destroy(iter); 12424 (void) scf_pg_destroy(pg); 12425 return (DELETE_FAILURE); 12426 } 12427 } 12428 } 12429 12430 if (err == -1) 12431 scfdie(); 12432 12433 (void) scf_iter_destroy(iter); 12434 (void) scf_pg_destroy(pg); 12435 12436 if (external) { 12437 /* 12438 * All the pgs have been deleted for the instance except 12439 * the ones holding the external dependencies. 12440 * For the job to be complete, we must also delete the 12441 * snapshots associated with the instance. 12442 */ 12443 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 12444 NULL) 12445 scfdie(); 12446 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 12447 scfdie(); 12448 12449 if (scf_iter_instance_snapshots(iter, inst) == -1) 12450 scfdie(); 12451 12452 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 12453 if (_scf_snapshot_delete(snap) != 0) { 12454 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12455 scfdie(); 12456 12457 semerr(emsg_permission_denied); 12458 12459 (void) scf_iter_destroy(iter); 12460 (void) scf_snapshot_destroy(snap); 12461 return (DELETE_FAILURE); 12462 } 12463 } 12464 12465 if (err == -1) 12466 scfdie(); 12467 12468 (void) scf_iter_destroy(iter); 12469 (void) scf_snapshot_destroy(snap); 12470 return (DELETE_SUCCESS_EXTDEPS); 12471 } 12472 12473 if (scf_instance_delete(inst) != 0) { 12474 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12475 scfdie(); 12476 12477 semerr(emsg_permission_denied); 12478 12479 return (DELETE_FAILURE); 12480 } 12481 12482 return (DELETE_SUCCESS_NOEXTDEPS); 12483 } 12484 12485 /* 12486 * lscf_service_delete() deletes a service. Before calling 12487 * scf_service_delete(), though, we call lscf_instance_delete() for 12488 * each of the instances and delete dependencies in other entities 12489 * which were created as "dependents" of this service. If there are 12490 * dependencies which were created for other entities, then we delete 12491 * all other property groups in the service and leave it as "empty". 12492 * 12493 * lscf_service_delete() verifies that there is no external dependency 12494 * pgs at the instance & service level before suppressing the service. 12495 * If there is, then we must not remove them now in case the service 12496 * is re-imported otherwise the dependencies would be lost. The external 12497 * dependency pgs will be removed if the dependencies are removed. 12498 * 12499 * Returns: 12500 * DELETE_FAILURE on failure 12501 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12502 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12503 */ 12504 static int 12505 lscf_service_delete(scf_service_t *svc, int force) 12506 { 12507 int r; 12508 scf_instance_t *inst; 12509 scf_propertygroup_t *pg; 12510 scf_iter_t *iter; 12511 int ret; 12512 int external = 0; 12513 12514 if ((inst = scf_instance_create(g_hndl)) == NULL || 12515 (pg = scf_pg_create(g_hndl)) == NULL || 12516 (iter = scf_iter_create(g_hndl)) == NULL) 12517 scfdie(); 12518 12519 if (scf_iter_service_instances(iter, svc) != 0) 12520 scfdie(); 12521 12522 for (r = scf_iter_next_instance(iter, inst); 12523 r == 1; 12524 r = scf_iter_next_instance(iter, inst)) { 12525 12526 ret = lscf_instance_delete(inst, force); 12527 if (ret == DELETE_FAILURE) { 12528 scf_iter_destroy(iter); 12529 scf_pg_destroy(pg); 12530 scf_instance_destroy(inst); 12531 return (DELETE_FAILURE); 12532 } 12533 12534 /* 12535 * Record the fact that there is some external dependencies 12536 * at the instance level. 12537 */ 12538 if (ret == DELETE_SUCCESS_EXTDEPS) 12539 external |= 1; 12540 } 12541 12542 if (r != 0) 12543 scfdie(); 12544 12545 /* Delete dependency property groups in dependent services. */ 12546 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12547 (void) delete_dependents(pg); 12548 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12549 scfdie(); 12550 12551 scf_iter_destroy(iter); 12552 scf_pg_destroy(pg); 12553 scf_instance_destroy(inst); 12554 12555 /* 12556 * If the service has some external dependencies then we don't 12557 * want to remove them in case the service is re-imported. 12558 */ 12559 if ((pg = scf_pg_create(g_hndl)) == NULL || 12560 (iter = scf_iter_create(g_hndl)) == NULL) 12561 scfdie(); 12562 12563 if (scf_iter_service_pgs(iter, svc) < 0) 12564 scfdie(); 12565 12566 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12567 if (pg_is_external_dependency(pg)) { 12568 external |= 2; 12569 continue; 12570 } 12571 12572 if (scf_pg_delete(pg) != 0) { 12573 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12574 scfdie(); 12575 else { 12576 semerr(emsg_permission_denied); 12577 12578 (void) scf_iter_destroy(iter); 12579 (void) scf_pg_destroy(pg); 12580 return (DELETE_FAILURE); 12581 } 12582 } 12583 } 12584 12585 if (r == -1) 12586 scfdie(); 12587 12588 (void) scf_iter_destroy(iter); 12589 (void) scf_pg_destroy(pg); 12590 12591 if (external != 0) 12592 return (DELETE_SUCCESS_EXTDEPS); 12593 12594 if (scf_service_delete(svc) == 0) 12595 return (DELETE_SUCCESS_NOEXTDEPS); 12596 12597 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12598 scfdie(); 12599 12600 semerr(emsg_permission_denied); 12601 return (DELETE_FAILURE); 12602 } 12603 12604 static int 12605 delete_callback(void *data, scf_walkinfo_t *wip) 12606 { 12607 int force = (int)data; 12608 12609 if (wip->inst != NULL) 12610 (void) lscf_instance_delete(wip->inst, force); 12611 else 12612 (void) lscf_service_delete(wip->svc, force); 12613 12614 return (0); 12615 } 12616 12617 void 12618 lscf_delete(const char *fmri, int force) 12619 { 12620 scf_service_t *svc; 12621 scf_instance_t *inst; 12622 int ret; 12623 12624 lscf_prep_hndl(); 12625 12626 if (cur_snap != NULL) { 12627 if (!snaplevel_is_instance(cur_level)) { 12628 char *buf; 12629 12630 buf = safe_malloc(max_scf_name_len + 1); 12631 if (scf_instance_get_name(cur_inst, buf, 12632 max_scf_name_len + 1) >= 0) { 12633 if (strcmp(buf, fmri) == 0) { 12634 semerr(emsg_cant_modify_snapshots); 12635 free(buf); 12636 return; 12637 } 12638 } else if (scf_error() != SCF_ERROR_DELETED) { 12639 scfdie(); 12640 } 12641 free(buf); 12642 } 12643 } else if (cur_inst != NULL) { 12644 /* EMPTY */; 12645 } else if (cur_svc != NULL) { 12646 inst = scf_instance_create(g_hndl); 12647 if (inst == NULL) 12648 scfdie(); 12649 12650 if (scf_service_get_instance(cur_svc, fmri, inst) == 12651 SCF_SUCCESS) { 12652 (void) lscf_instance_delete(inst, force); 12653 scf_instance_destroy(inst); 12654 return; 12655 } 12656 12657 if (scf_error() != SCF_ERROR_NOT_FOUND && 12658 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12659 scfdie(); 12660 12661 scf_instance_destroy(inst); 12662 } else { 12663 assert(cur_scope != NULL); 12664 12665 svc = scf_service_create(g_hndl); 12666 if (svc == NULL) 12667 scfdie(); 12668 12669 if (scf_scope_get_service(cur_scope, fmri, svc) == 12670 SCF_SUCCESS) { 12671 (void) lscf_service_delete(svc, force); 12672 scf_service_destroy(svc); 12673 return; 12674 } 12675 12676 if (scf_error() != SCF_ERROR_NOT_FOUND && 12677 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12678 scfdie(); 12679 12680 scf_service_destroy(svc); 12681 } 12682 12683 /* 12684 * Match FMRI to entity. 12685 */ 12686 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12687 delete_callback, (void *)force, NULL, semerr)) != 0) { 12688 semerr(gettext("Failed to walk instances: %s\n"), 12689 scf_strerror(ret)); 12690 } 12691 } 12692 12693 12694 12695 /* 12696 * :properties commands. These all end with "pg" or "prop" and generally 12697 * operate on the currently selected entity. 12698 */ 12699 12700 /* 12701 * Property listing. List the property groups, properties, their types and 12702 * their values for the currently selected entity. 12703 */ 12704 static void 12705 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12706 { 12707 char *buf; 12708 uint32_t flags; 12709 12710 buf = safe_malloc(max_scf_pg_type_len + 1); 12711 12712 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12713 scfdie(); 12714 12715 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12716 scfdie(); 12717 12718 safe_printf("%-*s %s", namewidth, name, buf); 12719 12720 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12721 safe_printf("\tNONPERSISTENT"); 12722 12723 safe_printf("\n"); 12724 12725 free(buf); 12726 } 12727 12728 static boolean_t 12729 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12730 { 12731 if (scf_property_get_value(prop, val) == 0) { 12732 return (B_FALSE); 12733 } else { 12734 switch (scf_error()) { 12735 case SCF_ERROR_NOT_FOUND: 12736 return (B_FALSE); 12737 case SCF_ERROR_PERMISSION_DENIED: 12738 case SCF_ERROR_CONSTRAINT_VIOLATED: 12739 return (B_TRUE); 12740 default: 12741 scfdie(); 12742 /*NOTREACHED*/ 12743 } 12744 } 12745 } 12746 12747 static void 12748 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12749 { 12750 scf_iter_t *iter; 12751 scf_value_t *val; 12752 const char *type; 12753 int multiple_strings = 0; 12754 int ret; 12755 12756 if ((iter = scf_iter_create(g_hndl)) == NULL || 12757 (val = scf_value_create(g_hndl)) == NULL) 12758 scfdie(); 12759 12760 type = prop_to_typestr(prop); 12761 assert(type != NULL); 12762 12763 safe_printf("%-*s %-7s ", len, name, type); 12764 12765 if (prop_has_multiple_values(prop, val) && 12766 (scf_value_type(val) == SCF_TYPE_ASTRING || 12767 scf_value_type(val) == SCF_TYPE_USTRING)) 12768 multiple_strings = 1; 12769 12770 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12771 scfdie(); 12772 12773 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12774 char *buf; 12775 ssize_t vlen, szret; 12776 12777 vlen = scf_value_get_as_string(val, NULL, 0); 12778 if (vlen < 0) 12779 scfdie(); 12780 12781 buf = safe_malloc(vlen + 1); 12782 12783 szret = scf_value_get_as_string(val, buf, vlen + 1); 12784 if (szret < 0) 12785 scfdie(); 12786 assert(szret <= vlen); 12787 12788 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12789 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12790 safe_printf(" \""); 12791 (void) quote_and_print(buf, stdout, 0); 12792 (void) putchar('"'); 12793 if (ferror(stdout)) { 12794 (void) putchar('\n'); 12795 uu_die(gettext("Error writing to stdout.\n")); 12796 } 12797 } else { 12798 safe_printf(" %s", buf); 12799 } 12800 12801 free(buf); 12802 } 12803 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12804 scfdie(); 12805 12806 if (putchar('\n') != '\n') 12807 uu_die(gettext("Could not output newline")); 12808 } 12809 12810 /* 12811 * Outputs template property group info for the describe subcommand. 12812 * If 'templates' == 2, verbose output is printed in the format expected 12813 * for describe -v, which includes all templates fields. If pg is 12814 * not NULL, we're describing the template data, not an existing property 12815 * group, and formatting should be appropriate for describe -t. 12816 */ 12817 static void 12818 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12819 { 12820 char *buf; 12821 uint8_t required; 12822 scf_property_t *stability_prop; 12823 scf_value_t *stability_val; 12824 12825 if (templates == 0) 12826 return; 12827 12828 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12829 (stability_val = scf_value_create(g_hndl)) == NULL) 12830 scfdie(); 12831 12832 if (templates == 2 && pg != NULL) { 12833 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12834 stability_prop) == 0) { 12835 if (prop_check_type(stability_prop, 12836 SCF_TYPE_ASTRING) == 0 && 12837 prop_get_val(stability_prop, stability_val) == 0) { 12838 char *stability; 12839 12840 stability = safe_malloc(max_scf_value_len + 1); 12841 12842 if (scf_value_get_astring(stability_val, 12843 stability, max_scf_value_len + 1) == -1 && 12844 scf_error() != SCF_ERROR_NOT_FOUND) 12845 scfdie(); 12846 12847 safe_printf("%s%s: %s\n", TMPL_INDENT, 12848 gettext("stability"), stability); 12849 12850 free(stability); 12851 } 12852 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12853 scfdie(); 12854 } 12855 12856 scf_property_destroy(stability_prop); 12857 scf_value_destroy(stability_val); 12858 12859 if (pgt == NULL) 12860 return; 12861 12862 if (pg == NULL || templates == 2) { 12863 /* print type info only if scf_tmpl_pg_name succeeds */ 12864 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12865 if (pg != NULL) 12866 safe_printf("%s", TMPL_INDENT); 12867 safe_printf("%s: ", gettext("name")); 12868 safe_printf("%s\n", buf); 12869 free(buf); 12870 } 12871 12872 /* print type info only if scf_tmpl_pg_type succeeds */ 12873 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12874 if (pg != NULL) 12875 safe_printf("%s", TMPL_INDENT); 12876 safe_printf("%s: ", gettext("type")); 12877 safe_printf("%s\n", buf); 12878 free(buf); 12879 } 12880 } 12881 12882 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12883 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12884 required ? "true" : "false"); 12885 12886 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12887 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12888 buf); 12889 free(buf); 12890 } 12891 12892 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12893 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12894 buf); 12895 free(buf); 12896 } 12897 12898 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12899 if (templates == 2) 12900 safe_printf("%s%s: %s\n", TMPL_INDENT, 12901 gettext("description"), buf); 12902 else 12903 safe_printf("%s%s\n", TMPL_INDENT, buf); 12904 free(buf); 12905 } 12906 12907 } 12908 12909 /* 12910 * With as_value set to true, indent as appropriate for the value level. 12911 * If false, indent to appropriate level for inclusion in constraint 12912 * or choice printout. 12913 */ 12914 static void 12915 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12916 int as_value) 12917 { 12918 char *buf; 12919 12920 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12921 if (as_value == 0) 12922 safe_printf("%s", TMPL_CHOICE_INDENT); 12923 else 12924 safe_printf("%s", TMPL_INDENT); 12925 safe_printf("%s: %s\n", gettext("value common name"), buf); 12926 free(buf); 12927 } 12928 12929 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12930 if (as_value == 0) 12931 safe_printf("%s", TMPL_CHOICE_INDENT); 12932 else 12933 safe_printf("%s", TMPL_INDENT); 12934 safe_printf("%s: %s\n", gettext("value description"), buf); 12935 free(buf); 12936 } 12937 } 12938 12939 static void 12940 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12941 { 12942 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12943 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12944 safe_printf("%s\n", val_buf); 12945 12946 print_template_value_details(prt, val_buf, 1); 12947 } 12948 12949 static void 12950 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12951 { 12952 int i, printed = 0; 12953 scf_values_t values; 12954 scf_count_ranges_t c_ranges; 12955 scf_int_ranges_t i_ranges; 12956 12957 printed = 0; 12958 i = 0; 12959 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12960 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12961 gettext("value constraints")); 12962 printed++; 12963 for (i = 0; i < values.value_count; ++i) { 12964 safe_printf("%s%s: %s\n", TMPL_INDENT, 12965 gettext("value name"), values.values_as_strings[i]); 12966 if (verbose == 1) 12967 print_template_value_details(prt, 12968 values.values_as_strings[i], 0); 12969 } 12970 12971 scf_values_destroy(&values); 12972 } 12973 12974 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12975 if (printed++ == 0) 12976 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12977 gettext("value constraints")); 12978 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12979 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12980 gettext("range"), c_ranges.scr_min[i], 12981 c_ranges.scr_max[i]); 12982 } 12983 scf_count_ranges_destroy(&c_ranges); 12984 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12985 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 12986 if (printed++ == 0) 12987 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12988 gettext("value constraints")); 12989 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12990 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12991 gettext("range"), i_ranges.sir_min[i], 12992 i_ranges.sir_max[i]); 12993 } 12994 scf_int_ranges_destroy(&i_ranges); 12995 } 12996 } 12997 12998 static void 12999 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 13000 { 13001 int i = 0, printed = 0; 13002 scf_values_t values; 13003 scf_count_ranges_t c_ranges; 13004 scf_int_ranges_t i_ranges; 13005 13006 printed = 0; 13007 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 13008 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13009 gettext("value constraints")); 13010 printed++; 13011 for (i = 0; i < values.value_count; i++) { 13012 safe_printf("%s%s: %s\n", TMPL_INDENT, 13013 gettext("value name"), values.values_as_strings[i]); 13014 if (verbose == 1) 13015 print_template_value_details(prt, 13016 values.values_as_strings[i], 0); 13017 } 13018 13019 scf_values_destroy(&values); 13020 } 13021 13022 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 13023 for (i = 0; i < c_ranges.scr_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: %llu to %llu\n", TMPL_INDENT, 13028 gettext("range"), c_ranges.scr_min[i], 13029 c_ranges.scr_max[i]); 13030 } 13031 scf_count_ranges_destroy(&c_ranges); 13032 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 13033 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 13034 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 13035 if (printed++ == 0) 13036 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 13037 gettext("value choices")); 13038 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 13039 gettext("range"), i_ranges.sir_min[i], 13040 i_ranges.sir_max[i]); 13041 } 13042 scf_int_ranges_destroy(&i_ranges); 13043 } 13044 } 13045 13046 static void 13047 list_values_by_template(scf_prop_tmpl_t *prt) 13048 { 13049 print_template_constraints(prt, 1); 13050 print_template_choices(prt, 1); 13051 } 13052 13053 static void 13054 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 13055 { 13056 char *val_buf; 13057 scf_iter_t *iter; 13058 scf_value_t *val; 13059 int ret; 13060 13061 if ((iter = scf_iter_create(g_hndl)) == NULL || 13062 (val = scf_value_create(g_hndl)) == NULL) 13063 scfdie(); 13064 13065 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 13066 scfdie(); 13067 13068 val_buf = safe_malloc(max_scf_value_len + 1); 13069 13070 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13071 if (scf_value_get_as_string(val, val_buf, 13072 max_scf_value_len + 1) < 0) 13073 scfdie(); 13074 13075 print_template_value(prt, val_buf); 13076 } 13077 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 13078 scfdie(); 13079 free(val_buf); 13080 13081 print_template_constraints(prt, 0); 13082 print_template_choices(prt, 0); 13083 13084 } 13085 13086 /* 13087 * Outputs property info for the describe subcommand 13088 * Verbose output if templates == 2, -v option of svccfg describe 13089 * Displays template data if prop is not NULL, -t option of svccfg describe 13090 */ 13091 static void 13092 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 13093 { 13094 char *buf; 13095 uint8_t u_buf; 13096 int i; 13097 uint64_t min, max; 13098 scf_values_t values; 13099 13100 if (prt == NULL || templates == 0) 13101 return; 13102 13103 if (prop == NULL) { 13104 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 13105 if (scf_tmpl_prop_name(prt, &buf) > 0) { 13106 safe_printf("%s\n", buf); 13107 free(buf); 13108 } else 13109 safe_printf("(%s)\n", gettext("any")); 13110 } 13111 13112 if (prop == NULL || templates == 2) { 13113 if (prop != NULL) 13114 safe_printf("%s", TMPL_INDENT); 13115 else 13116 safe_printf("%s", TMPL_VALUE_INDENT); 13117 safe_printf("%s: ", gettext("type")); 13118 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 13119 safe_printf("%s\n", buf); 13120 free(buf); 13121 } else 13122 safe_printf("(%s)\n", gettext("any")); 13123 } 13124 13125 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 13126 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 13127 u_buf ? "true" : "false"); 13128 13129 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 13130 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 13131 buf); 13132 free(buf); 13133 } 13134 13135 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 13136 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 13137 buf); 13138 free(buf); 13139 } 13140 13141 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 13142 safe_printf("%s%s\n", TMPL_INDENT, buf); 13143 free(buf); 13144 } 13145 13146 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 13147 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 13148 scf_tmpl_visibility_to_string(u_buf)); 13149 13150 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 13151 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13152 gettext("minimum number of values"), min); 13153 if (max == ULLONG_MAX) { 13154 safe_printf("%s%s: %s\n", TMPL_INDENT, 13155 gettext("maximum number of values"), 13156 gettext("unlimited")); 13157 } else { 13158 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 13159 gettext("maximum number of values"), max); 13160 } 13161 } 13162 13163 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 13164 for (i = 0; i < values.value_count; i++) { 13165 if (i == 0) { 13166 safe_printf("%s%s:", TMPL_INDENT, 13167 gettext("internal separators")); 13168 } 13169 safe_printf(" \"%s\"", values.values_as_strings[i]); 13170 } 13171 safe_printf("\n"); 13172 } 13173 13174 if (templates != 2) 13175 return; 13176 13177 if (prop != NULL) 13178 list_values_tmpl(prt, prop); 13179 else 13180 list_values_by_template(prt); 13181 } 13182 13183 static char * 13184 read_astring(scf_propertygroup_t *pg, const char *prop_name) 13185 { 13186 char *rv; 13187 13188 rv = _scf_read_single_astring_from_pg(pg, prop_name); 13189 if (rv == NULL) { 13190 switch (scf_error()) { 13191 case SCF_ERROR_NOT_FOUND: 13192 break; 13193 default: 13194 scfdie(); 13195 } 13196 } 13197 return (rv); 13198 } 13199 13200 static void 13201 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 13202 { 13203 size_t doc_len; 13204 size_t man_len; 13205 char *pg_name; 13206 char *text = NULL; 13207 int rv; 13208 13209 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 13210 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 13211 pg_name = safe_malloc(max_scf_name_len + 1); 13212 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 13213 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 13214 scfdie(); 13215 } 13216 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 13217 /* Display doc_link and and uri */ 13218 safe_printf("%s%s:\n", TMPL_INDENT, 13219 gettext("doc_link")); 13220 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 13221 if (text != NULL) { 13222 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13223 TMPL_INDENT, gettext("name"), text); 13224 uu_free(text); 13225 } 13226 text = read_astring(pg, SCF_PROPERTY_TM_URI); 13227 if (text != NULL) { 13228 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 13229 gettext("uri"), text); 13230 uu_free(text); 13231 } 13232 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 13233 man_len) == 0) { 13234 /* Display manpage title, section and path */ 13235 safe_printf("%s%s:\n", TMPL_INDENT, 13236 gettext("manpage")); 13237 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 13238 if (text != NULL) { 13239 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13240 TMPL_INDENT, gettext("title"), text); 13241 uu_free(text); 13242 } 13243 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 13244 if (text != NULL) { 13245 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13246 TMPL_INDENT, gettext("section"), text); 13247 uu_free(text); 13248 } 13249 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 13250 if (text != NULL) { 13251 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 13252 TMPL_INDENT, gettext("manpath"), text); 13253 uu_free(text); 13254 } 13255 } 13256 } 13257 if (rv == -1) 13258 scfdie(); 13259 13260 done: 13261 free(pg_name); 13262 } 13263 13264 static void 13265 list_entity_tmpl(int templates) 13266 { 13267 char *common_name = NULL; 13268 char *description = NULL; 13269 char *locale = NULL; 13270 scf_iter_t *iter; 13271 scf_propertygroup_t *pg; 13272 scf_property_t *prop; 13273 int r; 13274 scf_value_t *val; 13275 13276 if ((pg = scf_pg_create(g_hndl)) == NULL || 13277 (prop = scf_property_create(g_hndl)) == NULL || 13278 (val = scf_value_create(g_hndl)) == NULL || 13279 (iter = scf_iter_create(g_hndl)) == NULL) 13280 scfdie(); 13281 13282 locale = setlocale(LC_MESSAGES, NULL); 13283 13284 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 13285 common_name = safe_malloc(max_scf_value_len + 1); 13286 13287 /* Try both the current locale and the "C" locale. */ 13288 if (scf_pg_get_property(pg, locale, prop) == 0 || 13289 (scf_error() == SCF_ERROR_NOT_FOUND && 13290 scf_pg_get_property(pg, "C", prop) == 0)) { 13291 if (prop_get_val(prop, val) == 0 && 13292 scf_value_get_ustring(val, common_name, 13293 max_scf_value_len + 1) != -1) { 13294 safe_printf("%s%s: %s\n", TMPL_INDENT, 13295 gettext("common name"), common_name); 13296 } 13297 } 13298 } 13299 13300 /* 13301 * Do description, manpages, and doc links if templates == 2. 13302 */ 13303 if (templates == 2) { 13304 /* Get the description. */ 13305 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 13306 description = safe_malloc(max_scf_value_len + 1); 13307 13308 /* Try both the current locale and the "C" locale. */ 13309 if (scf_pg_get_property(pg, locale, prop) == 0 || 13310 (scf_error() == SCF_ERROR_NOT_FOUND && 13311 scf_pg_get_property(pg, "C", prop) == 0)) { 13312 if (prop_get_val(prop, val) == 0 && 13313 scf_value_get_ustring(val, description, 13314 max_scf_value_len + 1) != -1) { 13315 safe_printf("%s%s: %s\n", TMPL_INDENT, 13316 gettext("description"), 13317 description); 13318 } 13319 } 13320 } 13321 13322 /* Process doc_link & manpage elements. */ 13323 if (cur_level != NULL) { 13324 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 13325 SCF_GROUP_TEMPLATE); 13326 } else if (cur_inst != NULL) { 13327 r = scf_iter_instance_pgs_typed(iter, cur_inst, 13328 SCF_GROUP_TEMPLATE); 13329 } else { 13330 r = scf_iter_service_pgs_typed(iter, cur_svc, 13331 SCF_GROUP_TEMPLATE); 13332 } 13333 if (r == 0) { 13334 display_documentation(iter, pg); 13335 } 13336 } 13337 13338 free(common_name); 13339 free(description); 13340 scf_pg_destroy(pg); 13341 scf_property_destroy(prop); 13342 scf_value_destroy(val); 13343 scf_iter_destroy(iter); 13344 } 13345 13346 static void 13347 listtmpl(const char *pattern, int templates) 13348 { 13349 scf_pg_tmpl_t *pgt; 13350 scf_prop_tmpl_t *prt; 13351 char *snapbuf = NULL; 13352 char *fmribuf; 13353 char *pg_name = NULL, *prop_name = NULL; 13354 ssize_t prop_name_size; 13355 char *qual_prop_name; 13356 char *search_name; 13357 int listed = 0; 13358 13359 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13360 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 13361 scfdie(); 13362 13363 fmribuf = safe_malloc(max_scf_name_len + 1); 13364 qual_prop_name = safe_malloc(max_scf_name_len + 1); 13365 13366 if (cur_snap != NULL) { 13367 snapbuf = safe_malloc(max_scf_name_len + 1); 13368 if (scf_snapshot_get_name(cur_snap, snapbuf, 13369 max_scf_name_len + 1) < 0) 13370 scfdie(); 13371 } 13372 13373 if (cur_inst != NULL) { 13374 if (scf_instance_to_fmri(cur_inst, fmribuf, 13375 max_scf_name_len + 1) < 0) 13376 scfdie(); 13377 } else if (cur_svc != NULL) { 13378 if (scf_service_to_fmri(cur_svc, fmribuf, 13379 max_scf_name_len + 1) < 0) 13380 scfdie(); 13381 } else 13382 abort(); 13383 13384 /* If pattern is specified, we want to list only those items. */ 13385 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) { 13386 listed = 0; 13387 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 13388 fnmatch(pattern, pg_name, 0) == 0)) { 13389 list_pg_tmpl(pgt, NULL, templates); 13390 listed++; 13391 } 13392 13393 scf_tmpl_prop_reset(prt); 13394 13395 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) { 13396 search_name = NULL; 13397 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 13398 if ((prop_name_size > 0) && (pg_name != NULL)) { 13399 if (snprintf(qual_prop_name, 13400 max_scf_name_len + 1, "%s/%s", 13401 pg_name, prop_name) >= 13402 max_scf_name_len + 1) { 13403 prop_name_size = -1; 13404 } else { 13405 search_name = qual_prop_name; 13406 } 13407 } 13408 if (listed > 0 || pattern == NULL || 13409 (prop_name_size > 0 && 13410 fnmatch(pattern, search_name, 13411 FNM_PATHNAME) == 0)) 13412 list_prop_tmpl(prt, NULL, templates); 13413 if (prop_name != NULL) { 13414 free(prop_name); 13415 prop_name = NULL; 13416 } 13417 } 13418 if (pg_name != NULL) { 13419 free(pg_name); 13420 pg_name = NULL; 13421 } 13422 } 13423 13424 scf_tmpl_prop_destroy(prt); 13425 scf_tmpl_pg_destroy(pgt); 13426 free(snapbuf); 13427 free(fmribuf); 13428 free(qual_prop_name); 13429 } 13430 13431 static void 13432 listprop(const char *pattern, int only_pgs, int templates) 13433 { 13434 scf_propertygroup_t *pg; 13435 scf_property_t *prop; 13436 scf_iter_t *iter, *piter; 13437 char *pgnbuf, *prnbuf, *ppnbuf; 13438 scf_pg_tmpl_t *pgt, *pgtp; 13439 scf_prop_tmpl_t *prt; 13440 13441 void **objects; 13442 char **names; 13443 void **tmpls; 13444 int allocd, i; 13445 13446 int ret; 13447 ssize_t pgnlen, prnlen, szret; 13448 size_t max_len = 0; 13449 13450 if (cur_svc == NULL && cur_inst == NULL) { 13451 semerr(emsg_entity_not_selected); 13452 return; 13453 } 13454 13455 if ((pg = scf_pg_create(g_hndl)) == NULL || 13456 (prop = scf_property_create(g_hndl)) == NULL || 13457 (iter = scf_iter_create(g_hndl)) == NULL || 13458 (piter = scf_iter_create(g_hndl)) == NULL || 13459 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13460 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 13461 scfdie(); 13462 13463 prnbuf = safe_malloc(max_scf_name_len + 1); 13464 13465 if (cur_level != NULL) 13466 ret = scf_iter_snaplevel_pgs(iter, cur_level); 13467 else if (cur_inst != NULL) 13468 ret = scf_iter_instance_pgs(iter, cur_inst); 13469 else 13470 ret = scf_iter_service_pgs(iter, cur_svc); 13471 if (ret != 0) { 13472 return; 13473 } 13474 13475 /* 13476 * We want to only list items which match pattern, and we want the 13477 * second column to line up, so during the first pass we'll save 13478 * matching items, their names, and their templates in objects, 13479 * names, and tmpls, computing the maximum name length as we go, 13480 * and then we'll print them out. 13481 * 13482 * Note: We always keep an extra slot available so the array can be 13483 * NULL-terminated. 13484 */ 13485 i = 0; 13486 allocd = 1; 13487 objects = safe_malloc(sizeof (*objects)); 13488 names = safe_malloc(sizeof (*names)); 13489 tmpls = safe_malloc(sizeof (*tmpls)); 13490 13491 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13492 int new_pg = 0; 13493 int print_props = 0; 13494 pgtp = NULL; 13495 13496 pgnlen = scf_pg_get_name(pg, NULL, 0); 13497 if (pgnlen < 0) 13498 scfdie(); 13499 13500 pgnbuf = safe_malloc(pgnlen + 1); 13501 13502 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 13503 if (szret < 0) 13504 scfdie(); 13505 assert(szret <= pgnlen); 13506 13507 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) { 13508 if (scf_error() != SCF_ERROR_NOT_FOUND) 13509 scfdie(); 13510 pgtp = NULL; 13511 } else { 13512 pgtp = pgt; 13513 } 13514 13515 if (pattern == NULL || 13516 fnmatch(pattern, pgnbuf, 0) == 0) { 13517 if (i+1 >= allocd) { 13518 allocd *= 2; 13519 objects = realloc(objects, 13520 sizeof (*objects) * allocd); 13521 names = 13522 realloc(names, sizeof (*names) * allocd); 13523 tmpls = realloc(tmpls, 13524 sizeof (*tmpls) * allocd); 13525 if (objects == NULL || names == NULL || 13526 tmpls == NULL) 13527 uu_die(gettext("Out of memory")); 13528 } 13529 objects[i] = pg; 13530 names[i] = pgnbuf; 13531 13532 if (pgtp == NULL) 13533 tmpls[i] = NULL; 13534 else 13535 tmpls[i] = pgt; 13536 13537 ++i; 13538 13539 if (pgnlen > max_len) 13540 max_len = pgnlen; 13541 13542 new_pg = 1; 13543 print_props = 1; 13544 } 13545 13546 if (only_pgs) { 13547 if (new_pg) { 13548 pg = scf_pg_create(g_hndl); 13549 if (pg == NULL) 13550 scfdie(); 13551 pgt = scf_tmpl_pg_create(g_hndl); 13552 if (pgt == NULL) 13553 scfdie(); 13554 } else 13555 free(pgnbuf); 13556 13557 continue; 13558 } 13559 13560 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13561 scfdie(); 13562 13563 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13564 prnlen = scf_property_get_name(prop, prnbuf, 13565 max_scf_name_len + 1); 13566 if (prnlen < 0) 13567 scfdie(); 13568 13569 /* Will prepend the property group name and a slash. */ 13570 prnlen += pgnlen + 1; 13571 13572 ppnbuf = safe_malloc(prnlen + 1); 13573 13574 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13575 prnbuf) < 0) 13576 uu_die("snprintf"); 13577 13578 if (pattern == NULL || print_props == 1 || 13579 fnmatch(pattern, ppnbuf, 0) == 0) { 13580 if (i+1 >= allocd) { 13581 allocd *= 2; 13582 objects = realloc(objects, 13583 sizeof (*objects) * allocd); 13584 names = realloc(names, 13585 sizeof (*names) * allocd); 13586 tmpls = realloc(tmpls, 13587 sizeof (*tmpls) * allocd); 13588 if (objects == NULL || names == NULL || 13589 tmpls == NULL) 13590 uu_die(gettext( 13591 "Out of memory")); 13592 } 13593 13594 objects[i] = prop; 13595 names[i] = ppnbuf; 13596 13597 if (pgtp != NULL) { 13598 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13599 prt, 0) < 0) { 13600 if (scf_error() != 13601 SCF_ERROR_NOT_FOUND) 13602 scfdie(); 13603 tmpls[i] = NULL; 13604 } else { 13605 tmpls[i] = prt; 13606 } 13607 } else { 13608 tmpls[i] = NULL; 13609 } 13610 13611 ++i; 13612 13613 if (prnlen > max_len) 13614 max_len = prnlen; 13615 13616 prop = scf_property_create(g_hndl); 13617 prt = scf_tmpl_prop_create(g_hndl); 13618 } else { 13619 free(ppnbuf); 13620 } 13621 } 13622 13623 if (new_pg) { 13624 pg = scf_pg_create(g_hndl); 13625 if (pg == NULL) 13626 scfdie(); 13627 pgt = scf_tmpl_pg_create(g_hndl); 13628 if (pgt == NULL) 13629 scfdie(); 13630 } else 13631 free(pgnbuf); 13632 } 13633 if (ret != 0) 13634 scfdie(); 13635 13636 objects[i] = NULL; 13637 13638 scf_pg_destroy(pg); 13639 scf_tmpl_pg_destroy(pgt); 13640 scf_property_destroy(prop); 13641 scf_tmpl_prop_destroy(prt); 13642 13643 for (i = 0; objects[i] != NULL; ++i) { 13644 if (strchr(names[i], '/') == NULL) { 13645 /* property group */ 13646 pg = (scf_propertygroup_t *)objects[i]; 13647 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13648 list_pg_info(pg, names[i], max_len); 13649 list_pg_tmpl(pgt, pg, templates); 13650 free(names[i]); 13651 scf_pg_destroy(pg); 13652 if (pgt != NULL) 13653 scf_tmpl_pg_destroy(pgt); 13654 } else { 13655 /* property */ 13656 prop = (scf_property_t *)objects[i]; 13657 prt = (scf_prop_tmpl_t *)tmpls[i]; 13658 list_prop_info(prop, names[i], max_len); 13659 list_prop_tmpl(prt, prop, templates); 13660 free(names[i]); 13661 scf_property_destroy(prop); 13662 if (prt != NULL) 13663 scf_tmpl_prop_destroy(prt); 13664 } 13665 } 13666 13667 free(names); 13668 free(objects); 13669 free(tmpls); 13670 } 13671 13672 void 13673 lscf_listpg(const char *pattern) 13674 { 13675 lscf_prep_hndl(); 13676 13677 listprop(pattern, 1, 0); 13678 } 13679 13680 /* 13681 * Property group and property creation, setting, and deletion. setprop (and 13682 * its alias, addprop) can either create a property group of a given type, or 13683 * it can create or set a property to a given type and list of values. 13684 */ 13685 void 13686 lscf_addpg(const char *name, const char *type, const char *flags) 13687 { 13688 scf_propertygroup_t *pg; 13689 int ret; 13690 uint32_t flgs = 0; 13691 const char *cp; 13692 13693 13694 lscf_prep_hndl(); 13695 13696 if (cur_snap != NULL) { 13697 semerr(emsg_cant_modify_snapshots); 13698 return; 13699 } 13700 13701 if (cur_inst == NULL && cur_svc == NULL) { 13702 semerr(emsg_entity_not_selected); 13703 return; 13704 } 13705 13706 if (flags != NULL) { 13707 for (cp = flags; *cp != '\0'; ++cp) { 13708 switch (*cp) { 13709 case 'P': 13710 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13711 break; 13712 13713 case 'p': 13714 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13715 break; 13716 13717 default: 13718 semerr(gettext("Invalid property group flag " 13719 "%c."), *cp); 13720 return; 13721 } 13722 } 13723 } 13724 13725 pg = scf_pg_create(g_hndl); 13726 if (pg == NULL) 13727 scfdie(); 13728 13729 if (cur_inst != NULL) 13730 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13731 else 13732 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13733 13734 if (ret != SCF_SUCCESS) { 13735 switch (scf_error()) { 13736 case SCF_ERROR_INVALID_ARGUMENT: 13737 semerr(gettext("Name, type, or flags are invalid.\n")); 13738 break; 13739 13740 case SCF_ERROR_EXISTS: 13741 semerr(gettext("Property group already exists.\n")); 13742 break; 13743 13744 case SCF_ERROR_PERMISSION_DENIED: 13745 semerr(emsg_permission_denied); 13746 break; 13747 13748 case SCF_ERROR_BACKEND_ACCESS: 13749 semerr(gettext("Backend refused access.\n")); 13750 break; 13751 13752 default: 13753 scfdie(); 13754 } 13755 } 13756 13757 scf_pg_destroy(pg); 13758 13759 private_refresh(); 13760 } 13761 13762 void 13763 lscf_delpg(char *name) 13764 { 13765 lscf_prep_hndl(); 13766 13767 if (cur_snap != NULL) { 13768 semerr(emsg_cant_modify_snapshots); 13769 return; 13770 } 13771 13772 if (cur_inst == NULL && cur_svc == NULL) { 13773 semerr(emsg_entity_not_selected); 13774 return; 13775 } 13776 13777 if (strchr(name, '/') != NULL) { 13778 semerr(emsg_invalid_pg_name, name); 13779 return; 13780 } 13781 13782 lscf_delprop(name); 13783 } 13784 13785 /* 13786 * scf_delhash() is used to remove the property group related to the 13787 * hash entry for a specific manifest in the repository. pgname will be 13788 * constructed from the location of the manifest file. If deathrow isn't 0, 13789 * manifest file doesn't need to exist (manifest string will be used as 13790 * an absolute path). 13791 */ 13792 void 13793 lscf_delhash(char *manifest, int deathrow) 13794 { 13795 char *pgname; 13796 13797 if (cur_snap != NULL || 13798 cur_inst != NULL || cur_svc != NULL) { 13799 warn(gettext("error, an entity is selected\n")); 13800 return; 13801 } 13802 13803 /* select smf/manifest */ 13804 lscf_select(HASH_SVC); 13805 /* 13806 * Translate the manifest file name to property name. In the deathrow 13807 * case, the manifest file does not need to exist. 13808 */ 13809 pgname = mhash_filename_to_propname(manifest, 13810 deathrow ? B_TRUE : B_FALSE); 13811 if (pgname == NULL) { 13812 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13813 return; 13814 } 13815 /* delete the hash property name */ 13816 lscf_delpg(pgname); 13817 } 13818 13819 void 13820 lscf_listprop(const char *pattern) 13821 { 13822 lscf_prep_hndl(); 13823 13824 listprop(pattern, 0, 0); 13825 } 13826 13827 int 13828 lscf_setprop(const char *pgname, const char *type, const char *value, 13829 const uu_list_t *values) 13830 { 13831 scf_type_t ty, current_ty; 13832 scf_service_t *svc; 13833 scf_propertygroup_t *pg, *parent_pg; 13834 scf_property_t *prop, *parent_prop; 13835 scf_pg_tmpl_t *pgt; 13836 scf_prop_tmpl_t *prt; 13837 int ret, result = 0; 13838 scf_transaction_t *tx; 13839 scf_transaction_entry_t *e; 13840 scf_value_t *v; 13841 uu_list_walk_t *walk; 13842 string_list_t *sp; 13843 char *propname; 13844 int req_quotes = 0; 13845 13846 lscf_prep_hndl(); 13847 13848 if ((e = scf_entry_create(g_hndl)) == NULL || 13849 (svc = scf_service_create(g_hndl)) == NULL || 13850 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13851 (pg = scf_pg_create(g_hndl)) == NULL || 13852 (parent_prop = scf_property_create(g_hndl)) == NULL || 13853 (prop = scf_property_create(g_hndl)) == NULL || 13854 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13855 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13856 (tx = scf_transaction_create(g_hndl)) == NULL) 13857 scfdie(); 13858 13859 if (cur_snap != NULL) { 13860 semerr(emsg_cant_modify_snapshots); 13861 goto fail; 13862 } 13863 13864 if (cur_inst == NULL && cur_svc == NULL) { 13865 semerr(emsg_entity_not_selected); 13866 goto fail; 13867 } 13868 13869 propname = strchr(pgname, '/'); 13870 if (propname == NULL) { 13871 semerr(gettext("Property names must contain a `/'.\n")); 13872 goto fail; 13873 } 13874 13875 *propname = '\0'; 13876 ++propname; 13877 13878 if (type != NULL) { 13879 ty = string_to_type(type); 13880 if (ty == SCF_TYPE_INVALID) { 13881 semerr(gettext("Unknown type \"%s\".\n"), type); 13882 goto fail; 13883 } 13884 } 13885 13886 if (cur_inst != NULL) 13887 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13888 else 13889 ret = scf_service_get_pg(cur_svc, pgname, pg); 13890 if (ret != SCF_SUCCESS) { 13891 switch (scf_error()) { 13892 case SCF_ERROR_NOT_FOUND: 13893 semerr(emsg_no_such_pg, pgname); 13894 goto fail; 13895 13896 case SCF_ERROR_INVALID_ARGUMENT: 13897 semerr(emsg_invalid_pg_name, pgname); 13898 goto fail; 13899 13900 default: 13901 scfdie(); 13902 break; 13903 } 13904 } 13905 13906 do { 13907 if (scf_pg_update(pg) == -1) 13908 scfdie(); 13909 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13910 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13911 scfdie(); 13912 13913 semerr(emsg_permission_denied); 13914 goto fail; 13915 } 13916 13917 ret = scf_pg_get_property(pg, propname, prop); 13918 if (ret == SCF_SUCCESS) { 13919 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13920 scfdie(); 13921 13922 if (type == NULL) 13923 ty = current_ty; 13924 if (scf_transaction_property_change_type(tx, e, 13925 propname, ty) == -1) 13926 scfdie(); 13927 13928 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13929 /* Infer the type, if possible. */ 13930 if (type == NULL) { 13931 /* 13932 * First check if we're an instance and the 13933 * property is set on the service. 13934 */ 13935 if (cur_inst != NULL && 13936 scf_instance_get_parent(cur_inst, 13937 svc) == 0 && 13938 scf_service_get_pg(cur_svc, pgname, 13939 parent_pg) == 0 && 13940 scf_pg_get_property(parent_pg, propname, 13941 parent_prop) == 0 && 13942 scf_property_type(parent_prop, 13943 ¤t_ty) == 0) { 13944 ty = current_ty; 13945 13946 /* Then check for a type set in a template. */ 13947 } else if (scf_tmpl_get_by_pg(pg, pgt, 13948 0) == 0 && 13949 scf_tmpl_get_by_prop(pgt, propname, prt, 13950 0) == 0 && 13951 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13952 ty = current_ty; 13953 13954 /* If type can't be inferred, fail. */ 13955 } else { 13956 semerr(gettext("Type required for new " 13957 "properties.\n")); 13958 goto fail; 13959 } 13960 } 13961 if (scf_transaction_property_new(tx, e, propname, 13962 ty) == -1) 13963 scfdie(); 13964 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13965 semerr(emsg_invalid_prop_name, propname); 13966 goto fail; 13967 } else { 13968 scfdie(); 13969 } 13970 13971 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13972 req_quotes = 1; 13973 13974 if (value != NULL) { 13975 v = string_to_value(value, ty, 0); 13976 13977 if (v == NULL) 13978 goto fail; 13979 13980 ret = scf_entry_add_value(e, v); 13981 assert(ret == SCF_SUCCESS); 13982 } else { 13983 assert(values != NULL); 13984 13985 walk = uu_list_walk_start((uu_list_t *)values, 13986 UU_DEFAULT); 13987 if (walk == NULL) 13988 uu_die(gettext("Could not walk list")); 13989 13990 for (sp = uu_list_walk_next(walk); sp != NULL; 13991 sp = uu_list_walk_next(walk)) { 13992 v = string_to_value(sp->str, ty, req_quotes); 13993 13994 if (v == NULL) { 13995 scf_entry_destroy_children(e); 13996 goto fail; 13997 } 13998 13999 ret = scf_entry_add_value(e, v); 14000 assert(ret == SCF_SUCCESS); 14001 } 14002 uu_list_walk_end(walk); 14003 } 14004 result = scf_transaction_commit(tx); 14005 14006 scf_transaction_reset(tx); 14007 scf_entry_destroy_children(e); 14008 } while (result == 0); 14009 14010 if (result < 0) { 14011 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14012 scfdie(); 14013 14014 semerr(emsg_permission_denied); 14015 goto fail; 14016 } 14017 14018 ret = 0; 14019 14020 private_refresh(); 14021 14022 goto cleanup; 14023 14024 fail: 14025 ret = -1; 14026 14027 cleanup: 14028 scf_transaction_destroy(tx); 14029 scf_entry_destroy(e); 14030 scf_service_destroy(svc); 14031 scf_pg_destroy(parent_pg); 14032 scf_pg_destroy(pg); 14033 scf_property_destroy(parent_prop); 14034 scf_property_destroy(prop); 14035 scf_tmpl_pg_destroy(pgt); 14036 scf_tmpl_prop_destroy(prt); 14037 14038 return (ret); 14039 } 14040 14041 void 14042 lscf_delprop(char *pgn) 14043 { 14044 char *slash, *pn; 14045 scf_propertygroup_t *pg; 14046 scf_transaction_t *tx; 14047 scf_transaction_entry_t *e; 14048 int ret; 14049 14050 14051 lscf_prep_hndl(); 14052 14053 if (cur_snap != NULL) { 14054 semerr(emsg_cant_modify_snapshots); 14055 return; 14056 } 14057 14058 if (cur_inst == NULL && cur_svc == NULL) { 14059 semerr(emsg_entity_not_selected); 14060 return; 14061 } 14062 14063 pg = scf_pg_create(g_hndl); 14064 if (pg == NULL) 14065 scfdie(); 14066 14067 slash = strchr(pgn, '/'); 14068 if (slash == NULL) { 14069 pn = NULL; 14070 } else { 14071 *slash = '\0'; 14072 pn = slash + 1; 14073 } 14074 14075 if (cur_inst != NULL) 14076 ret = scf_instance_get_pg(cur_inst, pgn, pg); 14077 else 14078 ret = scf_service_get_pg(cur_svc, pgn, pg); 14079 if (ret != SCF_SUCCESS) { 14080 switch (scf_error()) { 14081 case SCF_ERROR_NOT_FOUND: 14082 semerr(emsg_no_such_pg, pgn); 14083 break; 14084 14085 case SCF_ERROR_INVALID_ARGUMENT: 14086 semerr(emsg_invalid_pg_name, pgn); 14087 break; 14088 14089 default: 14090 scfdie(); 14091 } 14092 14093 scf_pg_destroy(pg); 14094 14095 return; 14096 } 14097 14098 if (pn == NULL) { 14099 /* Try to delete the property group. */ 14100 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14101 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14102 scfdie(); 14103 14104 semerr(emsg_permission_denied); 14105 } else { 14106 private_refresh(); 14107 } 14108 14109 scf_pg_destroy(pg); 14110 return; 14111 } 14112 14113 e = scf_entry_create(g_hndl); 14114 tx = scf_transaction_create(g_hndl); 14115 14116 do { 14117 if (scf_pg_update(pg) == -1) 14118 scfdie(); 14119 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 14120 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14121 scfdie(); 14122 14123 semerr(emsg_permission_denied); 14124 break; 14125 } 14126 14127 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 14128 if (scf_error() == SCF_ERROR_NOT_FOUND) { 14129 semerr(gettext("No such property %s/%s.\n"), 14130 pgn, pn); 14131 break; 14132 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14133 semerr(emsg_invalid_prop_name, pn); 14134 break; 14135 } else { 14136 scfdie(); 14137 } 14138 } 14139 14140 ret = scf_transaction_commit(tx); 14141 14142 if (ret == 0) 14143 scf_transaction_reset(tx); 14144 } while (ret == 0); 14145 14146 if (ret < 0) { 14147 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14148 scfdie(); 14149 14150 semerr(emsg_permission_denied); 14151 } else { 14152 private_refresh(); 14153 } 14154 14155 scf_transaction_destroy(tx); 14156 scf_entry_destroy(e); 14157 scf_pg_destroy(pg); 14158 } 14159 14160 /* 14161 * Property editing. 14162 */ 14163 14164 static int 14165 write_edit_script(FILE *strm) 14166 { 14167 char *fmribuf; 14168 ssize_t fmrilen; 14169 14170 scf_propertygroup_t *pg; 14171 scf_property_t *prop; 14172 scf_value_t *val; 14173 scf_type_t ty; 14174 int ret, result = 0; 14175 scf_iter_t *iter, *piter, *viter; 14176 char *buf, *tybuf, *pname; 14177 const char *emsg_write_error; 14178 14179 14180 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 14181 14182 14183 /* select fmri */ 14184 if (cur_inst != NULL) { 14185 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 14186 if (fmrilen < 0) 14187 scfdie(); 14188 fmribuf = safe_malloc(fmrilen + 1); 14189 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 14190 scfdie(); 14191 } else { 14192 assert(cur_svc != NULL); 14193 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 14194 if (fmrilen < 0) 14195 scfdie(); 14196 fmribuf = safe_malloc(fmrilen + 1); 14197 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 14198 scfdie(); 14199 } 14200 14201 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 14202 warn(emsg_write_error, strerror(errno)); 14203 free(fmribuf); 14204 return (-1); 14205 } 14206 14207 free(fmribuf); 14208 14209 14210 if ((pg = scf_pg_create(g_hndl)) == NULL || 14211 (prop = scf_property_create(g_hndl)) == NULL || 14212 (val = scf_value_create(g_hndl)) == NULL || 14213 (iter = scf_iter_create(g_hndl)) == NULL || 14214 (piter = scf_iter_create(g_hndl)) == NULL || 14215 (viter = scf_iter_create(g_hndl)) == NULL) 14216 scfdie(); 14217 14218 buf = safe_malloc(max_scf_name_len + 1); 14219 tybuf = safe_malloc(max_scf_pg_type_len + 1); 14220 pname = safe_malloc(max_scf_name_len + 1); 14221 14222 if (cur_inst != NULL) 14223 ret = scf_iter_instance_pgs(iter, cur_inst); 14224 else 14225 ret = scf_iter_service_pgs(iter, cur_svc); 14226 if (ret != SCF_SUCCESS) 14227 scfdie(); 14228 14229 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 14230 int ret2; 14231 14232 /* 14233 * # delprop pg 14234 * # addpg pg type 14235 */ 14236 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 14237 scfdie(); 14238 14239 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 14240 scfdie(); 14241 14242 if (fprintf(strm, "# Property group \"%s\"\n" 14243 "# delprop %s\n" 14244 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 14245 warn(emsg_write_error, strerror(errno)); 14246 result = -1; 14247 goto out; 14248 } 14249 14250 /* # setprop pg/prop = (values) */ 14251 14252 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 14253 scfdie(); 14254 14255 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 14256 int first = 1; 14257 int ret3; 14258 int multiple; 14259 int is_str; 14260 scf_type_t bty; 14261 14262 if (scf_property_get_name(prop, pname, 14263 max_scf_name_len + 1) < 0) 14264 scfdie(); 14265 14266 if (scf_property_type(prop, &ty) != 0) 14267 scfdie(); 14268 14269 multiple = prop_has_multiple_values(prop, val); 14270 14271 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 14272 pname, scf_type_to_string(ty), multiple ? "(" : "") 14273 < 0) { 14274 warn(emsg_write_error, strerror(errno)); 14275 result = -1; 14276 goto out; 14277 } 14278 14279 (void) scf_type_base_type(ty, &bty); 14280 is_str = (bty == SCF_TYPE_ASTRING); 14281 14282 if (scf_iter_property_values(viter, prop) != 14283 SCF_SUCCESS) 14284 scfdie(); 14285 14286 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 14287 char *buf; 14288 ssize_t buflen; 14289 14290 buflen = scf_value_get_as_string(val, NULL, 0); 14291 if (buflen < 0) 14292 scfdie(); 14293 14294 buf = safe_malloc(buflen + 1); 14295 14296 if (scf_value_get_as_string(val, buf, 14297 buflen + 1) < 0) 14298 scfdie(); 14299 14300 if (first) 14301 first = 0; 14302 else { 14303 if (putc(' ', strm) != ' ') { 14304 warn(emsg_write_error, 14305 strerror(errno)); 14306 result = -1; 14307 goto out; 14308 } 14309 } 14310 14311 if ((is_str && multiple) || 14312 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 14313 (void) putc('"', strm); 14314 (void) quote_and_print(buf, strm, 1); 14315 (void) putc('"', strm); 14316 14317 if (ferror(strm)) { 14318 warn(emsg_write_error, 14319 strerror(errno)); 14320 result = -1; 14321 goto out; 14322 } 14323 } else { 14324 if (fprintf(strm, "%s", buf) < 0) { 14325 warn(emsg_write_error, 14326 strerror(errno)); 14327 result = -1; 14328 goto out; 14329 } 14330 } 14331 14332 free(buf); 14333 } 14334 if (ret3 < 0 && 14335 scf_error() != SCF_ERROR_PERMISSION_DENIED) 14336 scfdie(); 14337 14338 /* Write closing paren if mult-value property */ 14339 if ((multiple && putc(')', strm) == EOF) || 14340 14341 /* Write final newline */ 14342 fputc('\n', strm) == EOF) { 14343 warn(emsg_write_error, strerror(errno)); 14344 result = -1; 14345 goto out; 14346 } 14347 } 14348 if (ret2 < 0) 14349 scfdie(); 14350 14351 if (fputc('\n', strm) == EOF) { 14352 warn(emsg_write_error, strerror(errno)); 14353 result = -1; 14354 goto out; 14355 } 14356 } 14357 if (ret < 0) 14358 scfdie(); 14359 14360 out: 14361 free(pname); 14362 free(tybuf); 14363 free(buf); 14364 scf_iter_destroy(viter); 14365 scf_iter_destroy(piter); 14366 scf_iter_destroy(iter); 14367 scf_value_destroy(val); 14368 scf_property_destroy(prop); 14369 scf_pg_destroy(pg); 14370 14371 if (result == 0) { 14372 if (fflush(strm) != 0) { 14373 warn(emsg_write_error, strerror(errno)); 14374 return (-1); 14375 } 14376 } 14377 14378 return (result); 14379 } 14380 14381 int 14382 lscf_editprop() 14383 { 14384 char *buf, *editor; 14385 size_t bufsz; 14386 int tmpfd; 14387 char tempname[] = TEMP_FILE_PATTERN; 14388 14389 lscf_prep_hndl(); 14390 14391 if (cur_snap != NULL) { 14392 semerr(emsg_cant_modify_snapshots); 14393 return (-1); 14394 } 14395 14396 if (cur_svc == NULL && cur_inst == NULL) { 14397 semerr(emsg_entity_not_selected); 14398 return (-1); 14399 } 14400 14401 tmpfd = mkstemp(tempname); 14402 if (tmpfd == -1) { 14403 semerr(gettext("Could not create temporary file.\n")); 14404 return (-1); 14405 } 14406 14407 (void) strcpy(tempfilename, tempname); 14408 14409 tempfile = fdopen(tmpfd, "r+"); 14410 if (tempfile == NULL) { 14411 warn(gettext("Could not create temporary file.\n")); 14412 if (close(tmpfd) == -1) 14413 warn(gettext("Could not close temporary file: %s.\n"), 14414 strerror(errno)); 14415 14416 remove_tempfile(); 14417 14418 return (-1); 14419 } 14420 14421 if (write_edit_script(tempfile) == -1) { 14422 remove_tempfile(); 14423 return (-1); 14424 } 14425 14426 editor = getenv("EDITOR"); 14427 if (editor == NULL) 14428 editor = "vi"; 14429 14430 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 14431 buf = safe_malloc(bufsz); 14432 14433 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 14434 uu_die(gettext("Error creating editor command")); 14435 14436 if (system(buf) == -1) { 14437 semerr(gettext("Could not launch editor %s: %s\n"), editor, 14438 strerror(errno)); 14439 free(buf); 14440 remove_tempfile(); 14441 return (-1); 14442 } 14443 14444 free(buf); 14445 14446 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 14447 14448 remove_tempfile(); 14449 14450 return (0); 14451 } 14452 14453 static void 14454 add_string(uu_list_t *strlist, const char *str) 14455 { 14456 string_list_t *elem; 14457 elem = safe_malloc(sizeof (*elem)); 14458 uu_list_node_init(elem, &elem->node, string_pool); 14459 elem->str = safe_strdup(str); 14460 if (uu_list_append(strlist, elem) != 0) 14461 uu_die(gettext("libuutil error: %s\n"), 14462 uu_strerror(uu_error())); 14463 } 14464 14465 static int 14466 remove_string(uu_list_t *strlist, const char *str) 14467 { 14468 uu_list_walk_t *elems; 14469 string_list_t *sp; 14470 14471 /* 14472 * Find the element that needs to be removed. 14473 */ 14474 elems = uu_list_walk_start(strlist, UU_DEFAULT); 14475 while ((sp = uu_list_walk_next(elems)) != NULL) { 14476 if (strcmp(sp->str, str) == 0) 14477 break; 14478 } 14479 uu_list_walk_end(elems); 14480 14481 /* 14482 * Returning 1 here as the value was not found, this 14483 * might not be an error. Leave it to the caller to 14484 * decide. 14485 */ 14486 if (sp == NULL) { 14487 return (1); 14488 } 14489 14490 uu_list_remove(strlist, sp); 14491 14492 free(sp->str); 14493 free(sp); 14494 14495 return (0); 14496 } 14497 14498 /* 14499 * Get all property values that don't match the given glob pattern, 14500 * if a pattern is specified. 14501 */ 14502 static void 14503 get_prop_values(scf_property_t *prop, uu_list_t *values, 14504 const char *pattern) 14505 { 14506 scf_iter_t *iter; 14507 scf_value_t *val; 14508 int ret; 14509 14510 if ((iter = scf_iter_create(g_hndl)) == NULL || 14511 (val = scf_value_create(g_hndl)) == NULL) 14512 scfdie(); 14513 14514 if (scf_iter_property_values(iter, prop) != 0) 14515 scfdie(); 14516 14517 while ((ret = scf_iter_next_value(iter, val)) == 1) { 14518 char *buf; 14519 ssize_t vlen, szret; 14520 14521 vlen = scf_value_get_as_string(val, NULL, 0); 14522 if (vlen < 0) 14523 scfdie(); 14524 14525 buf = safe_malloc(vlen + 1); 14526 14527 szret = scf_value_get_as_string(val, buf, vlen + 1); 14528 if (szret < 0) 14529 scfdie(); 14530 assert(szret <= vlen); 14531 14532 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 14533 add_string(values, buf); 14534 14535 free(buf); 14536 } 14537 14538 if (ret == -1) 14539 scfdie(); 14540 14541 scf_value_destroy(val); 14542 scf_iter_destroy(iter); 14543 } 14544 14545 static int 14546 lscf_setpropvalue(const char *pgname, const char *type, 14547 const char *arg, int isadd, int isnotfoundok) 14548 { 14549 scf_type_t ty; 14550 scf_propertygroup_t *pg; 14551 scf_property_t *prop; 14552 int ret, result = 0; 14553 scf_transaction_t *tx; 14554 scf_transaction_entry_t *e; 14555 scf_value_t *v; 14556 string_list_t *sp; 14557 char *propname; 14558 uu_list_t *values; 14559 uu_list_walk_t *walk; 14560 void *cookie = NULL; 14561 char *pattern = NULL; 14562 14563 lscf_prep_hndl(); 14564 14565 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14566 uu_die(gettext("Could not create property list: %s\n"), 14567 uu_strerror(uu_error())); 14568 14569 if (!isadd) 14570 pattern = safe_strdup(arg); 14571 14572 if ((e = scf_entry_create(g_hndl)) == NULL || 14573 (pg = scf_pg_create(g_hndl)) == NULL || 14574 (prop = scf_property_create(g_hndl)) == NULL || 14575 (tx = scf_transaction_create(g_hndl)) == NULL) 14576 scfdie(); 14577 14578 if (cur_snap != NULL) { 14579 semerr(emsg_cant_modify_snapshots); 14580 goto fail; 14581 } 14582 14583 if (cur_inst == NULL && cur_svc == NULL) { 14584 semerr(emsg_entity_not_selected); 14585 goto fail; 14586 } 14587 14588 propname = strchr(pgname, '/'); 14589 if (propname == NULL) { 14590 semerr(gettext("Property names must contain a `/'.\n")); 14591 goto fail; 14592 } 14593 14594 *propname = '\0'; 14595 ++propname; 14596 14597 if (type != NULL) { 14598 ty = string_to_type(type); 14599 if (ty == SCF_TYPE_INVALID) { 14600 semerr(gettext("Unknown type \"%s\".\n"), type); 14601 goto fail; 14602 } 14603 } 14604 14605 if (cur_inst != NULL) 14606 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14607 else 14608 ret = scf_service_get_pg(cur_svc, pgname, pg); 14609 if (ret != 0) { 14610 switch (scf_error()) { 14611 case SCF_ERROR_NOT_FOUND: 14612 if (isnotfoundok) { 14613 result = 0; 14614 } else { 14615 semerr(emsg_no_such_pg, pgname); 14616 result = -1; 14617 } 14618 goto out; 14619 14620 case SCF_ERROR_INVALID_ARGUMENT: 14621 semerr(emsg_invalid_pg_name, pgname); 14622 goto fail; 14623 14624 default: 14625 scfdie(); 14626 } 14627 } 14628 14629 do { 14630 if (scf_pg_update(pg) == -1) 14631 scfdie(); 14632 if (scf_transaction_start(tx, pg) != 0) { 14633 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14634 scfdie(); 14635 14636 semerr(emsg_permission_denied); 14637 goto fail; 14638 } 14639 14640 ret = scf_pg_get_property(pg, propname, prop); 14641 if (ret == 0) { 14642 scf_type_t ptype; 14643 char *pat = pattern; 14644 14645 if (scf_property_type(prop, &ptype) != 0) 14646 scfdie(); 14647 14648 if (isadd) { 14649 if (type != NULL && ptype != ty) { 14650 semerr(gettext("Property \"%s\" is not " 14651 "of type \"%s\".\n"), propname, 14652 type); 14653 goto fail; 14654 } 14655 14656 pat = NULL; 14657 } else { 14658 size_t len = strlen(pat); 14659 if (len > 0 && pat[len - 1] == '\"') 14660 pat[len - 1] = '\0'; 14661 if (len > 0 && pat[0] == '\"') 14662 pat++; 14663 } 14664 14665 ty = ptype; 14666 14667 get_prop_values(prop, values, pat); 14668 14669 if (isadd) 14670 add_string(values, arg); 14671 14672 if (scf_transaction_property_change(tx, e, 14673 propname, ty) == -1) 14674 scfdie(); 14675 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14676 if (isadd) { 14677 if (type == NULL) { 14678 semerr(gettext("Type required " 14679 "for new properties.\n")); 14680 goto fail; 14681 } 14682 14683 add_string(values, arg); 14684 14685 if (scf_transaction_property_new(tx, e, 14686 propname, ty) == -1) 14687 scfdie(); 14688 } else if (isnotfoundok) { 14689 result = 0; 14690 goto out; 14691 } else { 14692 semerr(gettext("No such property %s/%s.\n"), 14693 pgname, propname); 14694 result = -1; 14695 goto out; 14696 } 14697 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14698 semerr(emsg_invalid_prop_name, propname); 14699 goto fail; 14700 } else { 14701 scfdie(); 14702 } 14703 14704 walk = uu_list_walk_start(values, UU_DEFAULT); 14705 if (walk == NULL) 14706 uu_die(gettext("Could not walk property list.\n")); 14707 14708 for (sp = uu_list_walk_next(walk); sp != NULL; 14709 sp = uu_list_walk_next(walk)) { 14710 v = string_to_value(sp->str, ty, 0); 14711 14712 if (v == NULL) { 14713 scf_entry_destroy_children(e); 14714 goto fail; 14715 } 14716 ret = scf_entry_add_value(e, v); 14717 assert(ret == 0); 14718 } 14719 uu_list_walk_end(walk); 14720 14721 result = scf_transaction_commit(tx); 14722 14723 scf_transaction_reset(tx); 14724 scf_entry_destroy_children(e); 14725 } while (result == 0); 14726 14727 if (result < 0) { 14728 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14729 scfdie(); 14730 14731 semerr(emsg_permission_denied); 14732 goto fail; 14733 } 14734 14735 result = 0; 14736 14737 private_refresh(); 14738 14739 out: 14740 scf_transaction_destroy(tx); 14741 scf_entry_destroy(e); 14742 scf_pg_destroy(pg); 14743 scf_property_destroy(prop); 14744 free(pattern); 14745 14746 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14747 free(sp->str); 14748 free(sp); 14749 } 14750 14751 uu_list_destroy(values); 14752 14753 return (result); 14754 14755 fail: 14756 result = -1; 14757 goto out; 14758 } 14759 14760 int 14761 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14762 { 14763 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14764 } 14765 14766 int 14767 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14768 { 14769 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14770 } 14771 14772 /* 14773 * Look for a standard start method, first in the instance (if any), 14774 * then the service. 14775 */ 14776 static const char * 14777 start_method_name(int *in_instance) 14778 { 14779 scf_propertygroup_t *pg; 14780 char **p; 14781 int ret; 14782 scf_instance_t *inst = cur_inst; 14783 14784 if ((pg = scf_pg_create(g_hndl)) == NULL) 14785 scfdie(); 14786 14787 again: 14788 for (p = start_method_names; *p != NULL; p++) { 14789 if (inst != NULL) 14790 ret = scf_instance_get_pg(inst, *p, pg); 14791 else 14792 ret = scf_service_get_pg(cur_svc, *p, pg); 14793 14794 if (ret == 0) { 14795 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14796 char *buf = safe_malloc(bufsz); 14797 14798 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14799 free(buf); 14800 continue; 14801 } 14802 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14803 free(buf); 14804 continue; 14805 } 14806 14807 free(buf); 14808 *in_instance = (inst != NULL); 14809 scf_pg_destroy(pg); 14810 return (*p); 14811 } 14812 14813 if (scf_error() == SCF_ERROR_NOT_FOUND) 14814 continue; 14815 14816 scfdie(); 14817 } 14818 14819 if (inst != NULL) { 14820 inst = NULL; 14821 goto again; 14822 } 14823 14824 scf_pg_destroy(pg); 14825 return (NULL); 14826 } 14827 14828 static int 14829 addpg(const char *name, const char *type) 14830 { 14831 scf_propertygroup_t *pg; 14832 int ret; 14833 14834 pg = scf_pg_create(g_hndl); 14835 if (pg == NULL) 14836 scfdie(); 14837 14838 if (cur_inst != NULL) 14839 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14840 else 14841 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14842 14843 if (ret != 0) { 14844 switch (scf_error()) { 14845 case SCF_ERROR_EXISTS: 14846 ret = 0; 14847 break; 14848 14849 case SCF_ERROR_PERMISSION_DENIED: 14850 semerr(emsg_permission_denied); 14851 break; 14852 14853 default: 14854 scfdie(); 14855 } 14856 } 14857 14858 scf_pg_destroy(pg); 14859 return (ret); 14860 } 14861 14862 int 14863 lscf_setenv(uu_list_t *args, int isunset) 14864 { 14865 int ret = 0; 14866 size_t i; 14867 int argc; 14868 char **argv = NULL; 14869 string_list_t *slp; 14870 char *pattern; 14871 char *prop; 14872 int do_service = 0; 14873 int do_instance = 0; 14874 const char *method = NULL; 14875 const char *name = NULL; 14876 const char *value = NULL; 14877 scf_instance_t *saved_cur_inst = cur_inst; 14878 14879 lscf_prep_hndl(); 14880 14881 argc = uu_list_numnodes(args); 14882 if (argc < 1) 14883 goto usage; 14884 14885 argv = calloc(argc + 1, sizeof (char *)); 14886 if (argv == NULL) 14887 uu_die(gettext("Out of memory.\n")); 14888 14889 for (slp = uu_list_first(args), i = 0; 14890 slp != NULL; 14891 slp = uu_list_next(args, slp), ++i) 14892 argv[i] = slp->str; 14893 14894 argv[i] = NULL; 14895 14896 opterr = 0; 14897 optind = 0; 14898 for (;;) { 14899 ret = getopt(argc, argv, "sim:"); 14900 if (ret == -1) 14901 break; 14902 14903 switch (ret) { 14904 case 's': 14905 do_service = 1; 14906 cur_inst = NULL; 14907 break; 14908 14909 case 'i': 14910 do_instance = 1; 14911 break; 14912 14913 case 'm': 14914 method = optarg; 14915 break; 14916 14917 case '?': 14918 goto usage; 14919 14920 default: 14921 bad_error("getopt", ret); 14922 } 14923 } 14924 14925 argc -= optind; 14926 if ((do_service && do_instance) || 14927 (isunset && argc != 1) || 14928 (!isunset && argc != 2)) 14929 goto usage; 14930 14931 name = argv[optind]; 14932 if (!isunset) 14933 value = argv[optind + 1]; 14934 14935 if (cur_snap != NULL) { 14936 semerr(emsg_cant_modify_snapshots); 14937 ret = -1; 14938 goto out; 14939 } 14940 14941 if (cur_inst == NULL && cur_svc == NULL) { 14942 semerr(emsg_entity_not_selected); 14943 ret = -1; 14944 goto out; 14945 } 14946 14947 if (do_instance && cur_inst == NULL) { 14948 semerr(gettext("No instance is selected.\n")); 14949 ret = -1; 14950 goto out; 14951 } 14952 14953 if (do_service && cur_svc == NULL) { 14954 semerr(gettext("No service is selected.\n")); 14955 ret = -1; 14956 goto out; 14957 } 14958 14959 if (method == NULL) { 14960 if (do_instance || do_service) { 14961 method = "method_context"; 14962 if (!isunset) { 14963 ret = addpg("method_context", 14964 SCF_GROUP_FRAMEWORK); 14965 if (ret != 0) 14966 goto out; 14967 } 14968 } else { 14969 int in_instance; 14970 method = start_method_name(&in_instance); 14971 if (method == NULL) { 14972 semerr(gettext( 14973 "Couldn't find start method; please " 14974 "specify a method with '-m'.\n")); 14975 ret = -1; 14976 goto out; 14977 } 14978 if (!in_instance) 14979 cur_inst = NULL; 14980 } 14981 } else { 14982 scf_propertygroup_t *pg; 14983 size_t bufsz; 14984 char *buf; 14985 int ret; 14986 14987 if ((pg = scf_pg_create(g_hndl)) == NULL) 14988 scfdie(); 14989 14990 if (cur_inst != NULL) 14991 ret = scf_instance_get_pg(cur_inst, method, pg); 14992 else 14993 ret = scf_service_get_pg(cur_svc, method, pg); 14994 14995 if (ret != 0) { 14996 scf_pg_destroy(pg); 14997 switch (scf_error()) { 14998 case SCF_ERROR_NOT_FOUND: 14999 semerr(gettext("Couldn't find the method " 15000 "\"%s\".\n"), method); 15001 goto out; 15002 15003 case SCF_ERROR_INVALID_ARGUMENT: 15004 semerr(gettext("Invalid method name \"%s\".\n"), 15005 method); 15006 goto out; 15007 15008 default: 15009 scfdie(); 15010 } 15011 } 15012 15013 bufsz = strlen(SCF_GROUP_METHOD) + 1; 15014 buf = safe_malloc(bufsz); 15015 15016 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 15017 strcmp(buf, SCF_GROUP_METHOD) != 0) { 15018 semerr(gettext("Property group \"%s\" is not of type " 15019 "\"method\".\n"), method); 15020 ret = -1; 15021 free(buf); 15022 scf_pg_destroy(pg); 15023 goto out; 15024 } 15025 15026 free(buf); 15027 scf_pg_destroy(pg); 15028 } 15029 15030 prop = uu_msprintf("%s/environment", method); 15031 pattern = uu_msprintf("%s=*", name); 15032 15033 if (prop == NULL || pattern == NULL) 15034 uu_die(gettext("Out of memory.\n")); 15035 15036 ret = lscf_delpropvalue(prop, pattern, !isunset); 15037 15038 if (ret == 0 && !isunset) { 15039 uu_free(pattern); 15040 uu_free(prop); 15041 prop = uu_msprintf("%s/environment", method); 15042 pattern = uu_msprintf("%s=%s", name, value); 15043 if (prop == NULL || pattern == NULL) 15044 uu_die(gettext("Out of memory.\n")); 15045 ret = lscf_addpropvalue(prop, "astring:", pattern); 15046 } 15047 uu_free(pattern); 15048 uu_free(prop); 15049 15050 out: 15051 cur_inst = saved_cur_inst; 15052 15053 free(argv); 15054 return (ret); 15055 usage: 15056 ret = -2; 15057 goto out; 15058 } 15059 15060 /* 15061 * Snapshot commands 15062 */ 15063 15064 void 15065 lscf_listsnap() 15066 { 15067 scf_snapshot_t *snap; 15068 scf_iter_t *iter; 15069 char *nb; 15070 int r; 15071 15072 lscf_prep_hndl(); 15073 15074 if (cur_inst == NULL) { 15075 semerr(gettext("Instance not selected.\n")); 15076 return; 15077 } 15078 15079 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15080 (iter = scf_iter_create(g_hndl)) == NULL) 15081 scfdie(); 15082 15083 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 15084 scfdie(); 15085 15086 nb = safe_malloc(max_scf_name_len + 1); 15087 15088 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 15089 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 15090 scfdie(); 15091 15092 (void) puts(nb); 15093 } 15094 if (r < 0) 15095 scfdie(); 15096 15097 free(nb); 15098 scf_iter_destroy(iter); 15099 scf_snapshot_destroy(snap); 15100 } 15101 15102 void 15103 lscf_selectsnap(const char *name) 15104 { 15105 scf_snapshot_t *snap; 15106 scf_snaplevel_t *level; 15107 15108 lscf_prep_hndl(); 15109 15110 if (cur_inst == NULL) { 15111 semerr(gettext("Instance not selected.\n")); 15112 return; 15113 } 15114 15115 if (cur_snap != NULL) { 15116 if (name != NULL) { 15117 char *cur_snap_name; 15118 boolean_t nochange; 15119 15120 cur_snap_name = safe_malloc(max_scf_name_len + 1); 15121 15122 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 15123 max_scf_name_len + 1) < 0) 15124 scfdie(); 15125 15126 nochange = strcmp(name, cur_snap_name) == 0; 15127 15128 free(cur_snap_name); 15129 15130 if (nochange) 15131 return; 15132 } 15133 15134 unselect_cursnap(); 15135 } 15136 15137 if (name == NULL) 15138 return; 15139 15140 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 15141 (level = scf_snaplevel_create(g_hndl)) == NULL) 15142 scfdie(); 15143 15144 if (scf_instance_get_snapshot(cur_inst, name, snap) != 15145 SCF_SUCCESS) { 15146 switch (scf_error()) { 15147 case SCF_ERROR_INVALID_ARGUMENT: 15148 semerr(gettext("Invalid name \"%s\".\n"), name); 15149 break; 15150 15151 case SCF_ERROR_NOT_FOUND: 15152 semerr(gettext("No such snapshot \"%s\".\n"), name); 15153 break; 15154 15155 default: 15156 scfdie(); 15157 } 15158 15159 scf_snaplevel_destroy(level); 15160 scf_snapshot_destroy(snap); 15161 return; 15162 } 15163 15164 /* Load the snaplevels into our list. */ 15165 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 15166 if (cur_levels == NULL) 15167 uu_die(gettext("Could not create list: %s\n"), 15168 uu_strerror(uu_error())); 15169 15170 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15171 if (scf_error() != SCF_ERROR_NOT_FOUND) 15172 scfdie(); 15173 15174 semerr(gettext("Snapshot has no snaplevels.\n")); 15175 15176 scf_snaplevel_destroy(level); 15177 scf_snapshot_destroy(snap); 15178 return; 15179 } 15180 15181 cur_snap = snap; 15182 15183 for (;;) { 15184 cur_elt = safe_malloc(sizeof (*cur_elt)); 15185 uu_list_node_init(cur_elt, &cur_elt->list_node, 15186 snaplevel_pool); 15187 cur_elt->sl = level; 15188 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 15189 uu_die(gettext("libuutil error: %s\n"), 15190 uu_strerror(uu_error())); 15191 15192 level = scf_snaplevel_create(g_hndl); 15193 if (level == NULL) 15194 scfdie(); 15195 15196 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 15197 level) != SCF_SUCCESS) { 15198 if (scf_error() != SCF_ERROR_NOT_FOUND) 15199 scfdie(); 15200 15201 scf_snaplevel_destroy(level); 15202 break; 15203 } 15204 } 15205 15206 cur_elt = uu_list_last(cur_levels); 15207 cur_level = cur_elt->sl; 15208 } 15209 15210 /* 15211 * Copies the properties & values in src to dst. Assumes src won't change. 15212 * Returns -1 if permission is denied, -2 if another transaction interrupts, 15213 * and 0 on success. 15214 * 15215 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 15216 * property, if it is copied and has type boolean. (See comment in 15217 * lscf_revert()). 15218 */ 15219 static int 15220 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 15221 uint8_t enabled) 15222 { 15223 scf_transaction_t *tx; 15224 scf_iter_t *iter, *viter; 15225 scf_property_t *prop; 15226 scf_value_t *v; 15227 char *nbuf; 15228 int r; 15229 15230 tx = scf_transaction_create(g_hndl); 15231 if (tx == NULL) 15232 scfdie(); 15233 15234 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 15235 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15236 scfdie(); 15237 15238 scf_transaction_destroy(tx); 15239 15240 return (-1); 15241 } 15242 15243 if ((iter = scf_iter_create(g_hndl)) == NULL || 15244 (prop = scf_property_create(g_hndl)) == NULL || 15245 (viter = scf_iter_create(g_hndl)) == NULL) 15246 scfdie(); 15247 15248 nbuf = safe_malloc(max_scf_name_len + 1); 15249 15250 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 15251 scfdie(); 15252 15253 for (;;) { 15254 scf_transaction_entry_t *e; 15255 scf_type_t ty; 15256 15257 r = scf_iter_next_property(iter, prop); 15258 if (r == -1) 15259 scfdie(); 15260 if (r == 0) 15261 break; 15262 15263 e = scf_entry_create(g_hndl); 15264 if (e == NULL) 15265 scfdie(); 15266 15267 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 15268 scfdie(); 15269 15270 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 15271 scfdie(); 15272 15273 if (scf_transaction_property_new(tx, e, nbuf, 15274 ty) != SCF_SUCCESS) 15275 scfdie(); 15276 15277 if ((enabled == 0 || enabled == 1) && 15278 strcmp(nbuf, scf_property_enabled) == 0 && 15279 ty == SCF_TYPE_BOOLEAN) { 15280 v = scf_value_create(g_hndl); 15281 if (v == NULL) 15282 scfdie(); 15283 15284 scf_value_set_boolean(v, enabled); 15285 15286 if (scf_entry_add_value(e, v) != 0) 15287 scfdie(); 15288 } else { 15289 if (scf_iter_property_values(viter, prop) != 0) 15290 scfdie(); 15291 15292 for (;;) { 15293 v = scf_value_create(g_hndl); 15294 if (v == NULL) 15295 scfdie(); 15296 15297 r = scf_iter_next_value(viter, v); 15298 if (r == -1) 15299 scfdie(); 15300 if (r == 0) { 15301 scf_value_destroy(v); 15302 break; 15303 } 15304 15305 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 15306 scfdie(); 15307 } 15308 } 15309 } 15310 15311 free(nbuf); 15312 scf_iter_destroy(viter); 15313 scf_property_destroy(prop); 15314 scf_iter_destroy(iter); 15315 15316 r = scf_transaction_commit(tx); 15317 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 15318 scfdie(); 15319 15320 scf_transaction_destroy_children(tx); 15321 scf_transaction_destroy(tx); 15322 15323 switch (r) { 15324 case 1: return (0); 15325 case 0: return (-2); 15326 case -1: return (-1); 15327 15328 default: 15329 abort(); 15330 } 15331 15332 /* NOTREACHED */ 15333 } 15334 15335 void 15336 lscf_revert(const char *snapname) 15337 { 15338 scf_snapshot_t *snap, *prev; 15339 scf_snaplevel_t *level, *nlevel; 15340 scf_iter_t *iter; 15341 scf_propertygroup_t *pg, *npg; 15342 scf_property_t *prop; 15343 scf_value_t *val; 15344 char *nbuf, *tbuf; 15345 uint8_t enabled; 15346 15347 lscf_prep_hndl(); 15348 15349 if (cur_inst == NULL) { 15350 semerr(gettext("Instance not selected.\n")); 15351 return; 15352 } 15353 15354 if (snapname != NULL) { 15355 snap = scf_snapshot_create(g_hndl); 15356 if (snap == NULL) 15357 scfdie(); 15358 15359 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 15360 SCF_SUCCESS) { 15361 switch (scf_error()) { 15362 case SCF_ERROR_INVALID_ARGUMENT: 15363 semerr(gettext("Invalid snapshot name " 15364 "\"%s\".\n"), snapname); 15365 break; 15366 15367 case SCF_ERROR_NOT_FOUND: 15368 semerr(gettext("No such snapshot.\n")); 15369 break; 15370 15371 default: 15372 scfdie(); 15373 } 15374 15375 scf_snapshot_destroy(snap); 15376 return; 15377 } 15378 } else { 15379 if (cur_snap != NULL) { 15380 snap = cur_snap; 15381 } else { 15382 semerr(gettext("No snapshot selected.\n")); 15383 return; 15384 } 15385 } 15386 15387 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 15388 (level = scf_snaplevel_create(g_hndl)) == NULL || 15389 (iter = scf_iter_create(g_hndl)) == NULL || 15390 (pg = scf_pg_create(g_hndl)) == NULL || 15391 (npg = scf_pg_create(g_hndl)) == NULL || 15392 (prop = scf_property_create(g_hndl)) == NULL || 15393 (val = scf_value_create(g_hndl)) == NULL) 15394 scfdie(); 15395 15396 nbuf = safe_malloc(max_scf_name_len + 1); 15397 tbuf = safe_malloc(max_scf_pg_type_len + 1); 15398 15399 /* Take the "previous" snapshot before we blow away the properties. */ 15400 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 15401 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 15402 scfdie(); 15403 } else { 15404 if (scf_error() != SCF_ERROR_NOT_FOUND) 15405 scfdie(); 15406 15407 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 15408 scfdie(); 15409 } 15410 15411 /* Save general/enabled, since we're probably going to replace it. */ 15412 enabled = 2; 15413 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 15414 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 15415 scf_property_get_value(prop, val) == 0) 15416 (void) scf_value_get_boolean(val, &enabled); 15417 15418 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15419 if (scf_error() != SCF_ERROR_NOT_FOUND) 15420 scfdie(); 15421 15422 goto out; 15423 } 15424 15425 for (;;) { 15426 boolean_t isinst; 15427 uint32_t flags; 15428 int r; 15429 15430 /* Clear the properties from the corresponding entity. */ 15431 isinst = snaplevel_is_instance(level); 15432 15433 if (!isinst) 15434 r = scf_iter_service_pgs(iter, cur_svc); 15435 else 15436 r = scf_iter_instance_pgs(iter, cur_inst); 15437 if (r != SCF_SUCCESS) 15438 scfdie(); 15439 15440 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15441 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15442 scfdie(); 15443 15444 /* Skip nonpersistent pgs. */ 15445 if (flags & SCF_PG_FLAG_NONPERSISTENT) 15446 continue; 15447 15448 if (scf_pg_delete(pg) != SCF_SUCCESS) { 15449 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15450 scfdie(); 15451 15452 semerr(emsg_permission_denied); 15453 goto out; 15454 } 15455 } 15456 if (r == -1) 15457 scfdie(); 15458 15459 /* Copy the properties to the corresponding entity. */ 15460 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 15461 scfdie(); 15462 15463 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15464 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 15465 scfdie(); 15466 15467 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 15468 0) 15469 scfdie(); 15470 15471 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15472 scfdie(); 15473 15474 if (!isinst) 15475 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 15476 flags, npg); 15477 else 15478 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 15479 flags, npg); 15480 if (r != SCF_SUCCESS) { 15481 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15482 scfdie(); 15483 15484 semerr(emsg_permission_denied); 15485 goto out; 15486 } 15487 15488 if ((enabled == 0 || enabled == 1) && 15489 strcmp(nbuf, scf_pg_general) == 0) 15490 r = pg_copy(pg, npg, enabled); 15491 else 15492 r = pg_copy(pg, npg, 2); 15493 15494 switch (r) { 15495 case 0: 15496 break; 15497 15498 case -1: 15499 semerr(emsg_permission_denied); 15500 goto out; 15501 15502 case -2: 15503 semerr(gettext( 15504 "Interrupted by another change.\n")); 15505 goto out; 15506 15507 default: 15508 abort(); 15509 } 15510 } 15511 if (r == -1) 15512 scfdie(); 15513 15514 /* Get next level. */ 15515 nlevel = scf_snaplevel_create(g_hndl); 15516 if (nlevel == NULL) 15517 scfdie(); 15518 15519 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 15520 SCF_SUCCESS) { 15521 if (scf_error() != SCF_ERROR_NOT_FOUND) 15522 scfdie(); 15523 15524 scf_snaplevel_destroy(nlevel); 15525 break; 15526 } 15527 15528 scf_snaplevel_destroy(level); 15529 level = nlevel; 15530 } 15531 15532 if (snapname == NULL) { 15533 lscf_selectsnap(NULL); 15534 snap = NULL; /* cur_snap has been destroyed */ 15535 } 15536 15537 out: 15538 free(tbuf); 15539 free(nbuf); 15540 scf_value_destroy(val); 15541 scf_property_destroy(prop); 15542 scf_pg_destroy(npg); 15543 scf_pg_destroy(pg); 15544 scf_iter_destroy(iter); 15545 scf_snaplevel_destroy(level); 15546 scf_snapshot_destroy(prev); 15547 if (snap != cur_snap) 15548 scf_snapshot_destroy(snap); 15549 } 15550 15551 void 15552 lscf_refresh(void) 15553 { 15554 ssize_t fmrilen; 15555 size_t bufsz; 15556 char *fmribuf; 15557 int r; 15558 15559 lscf_prep_hndl(); 15560 15561 if (cur_inst == NULL) { 15562 semerr(gettext("Instance not selected.\n")); 15563 return; 15564 } 15565 15566 bufsz = max_scf_fmri_len + 1; 15567 fmribuf = safe_malloc(bufsz); 15568 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15569 if (fmrilen < 0) { 15570 free(fmribuf); 15571 if (scf_error() != SCF_ERROR_DELETED) 15572 scfdie(); 15573 scf_instance_destroy(cur_inst); 15574 cur_inst = NULL; 15575 warn(emsg_deleted); 15576 return; 15577 } 15578 assert(fmrilen < bufsz); 15579 15580 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15581 switch (r) { 15582 case 0: 15583 break; 15584 15585 case ECONNABORTED: 15586 warn(gettext("Could not refresh %s " 15587 "(repository connection broken).\n"), fmribuf); 15588 break; 15589 15590 case ECANCELED: 15591 warn(emsg_deleted); 15592 break; 15593 15594 case EPERM: 15595 warn(gettext("Could not refresh %s " 15596 "(permission denied).\n"), fmribuf); 15597 break; 15598 15599 case ENOSPC: 15600 warn(gettext("Could not refresh %s " 15601 "(repository server out of resources).\n"), 15602 fmribuf); 15603 break; 15604 15605 case EACCES: 15606 default: 15607 bad_error("refresh_entity", scf_error()); 15608 } 15609 15610 free(fmribuf); 15611 } 15612 15613 /* 15614 * describe [-v] [-t] [pg/prop] 15615 */ 15616 int 15617 lscf_describe(uu_list_t *args, int hasargs) 15618 { 15619 int ret = 0; 15620 size_t i; 15621 int argc; 15622 char **argv = NULL; 15623 string_list_t *slp; 15624 int do_verbose = 0; 15625 int do_templates = 0; 15626 char *pattern = NULL; 15627 15628 lscf_prep_hndl(); 15629 15630 if (hasargs != 0) { 15631 argc = uu_list_numnodes(args); 15632 if (argc < 1) 15633 goto usage; 15634 15635 argv = calloc(argc + 1, sizeof (char *)); 15636 if (argv == NULL) 15637 uu_die(gettext("Out of memory.\n")); 15638 15639 for (slp = uu_list_first(args), i = 0; 15640 slp != NULL; 15641 slp = uu_list_next(args, slp), ++i) 15642 argv[i] = slp->str; 15643 15644 argv[i] = NULL; 15645 15646 /* 15647 * We start optind = 0 because our list of arguments 15648 * starts at argv[0] 15649 */ 15650 optind = 0; 15651 opterr = 0; 15652 for (;;) { 15653 ret = getopt(argc, argv, "vt"); 15654 if (ret == -1) 15655 break; 15656 15657 switch (ret) { 15658 case 'v': 15659 do_verbose = 1; 15660 break; 15661 15662 case 't': 15663 do_templates = 1; 15664 break; 15665 15666 case '?': 15667 goto usage; 15668 15669 default: 15670 bad_error("getopt", ret); 15671 } 15672 } 15673 15674 pattern = argv[optind]; 15675 } 15676 15677 if (cur_inst == NULL && cur_svc == NULL) { 15678 semerr(emsg_entity_not_selected); 15679 ret = -1; 15680 goto out; 15681 } 15682 15683 /* 15684 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15685 * output if their last parameter is set to 2. Less information is 15686 * produced if the parameter is set to 1. 15687 */ 15688 if (pattern == NULL) { 15689 if (do_verbose == 1) 15690 list_entity_tmpl(2); 15691 else 15692 list_entity_tmpl(1); 15693 } 15694 15695 if (do_templates == 0) { 15696 if (do_verbose == 1) 15697 listprop(pattern, 0, 2); 15698 else 15699 listprop(pattern, 0, 1); 15700 } else { 15701 if (do_verbose == 1) 15702 listtmpl(pattern, 2); 15703 else 15704 listtmpl(pattern, 1); 15705 } 15706 15707 ret = 0; 15708 out: 15709 if (argv != NULL) 15710 free(argv); 15711 return (ret); 15712 usage: 15713 ret = -2; 15714 goto out; 15715 } 15716 15717 #define PARAM_ACTIVE ((const char *) "active") 15718 #define PARAM_INACTIVE ((const char *) "inactive") 15719 #define PARAM_SMTP_TO ((const char *) "to") 15720 15721 /* 15722 * tokenize() 15723 * Breaks down the string according to the tokens passed. 15724 * Caller is responsible for freeing array of pointers returned. 15725 * Returns NULL on failure 15726 */ 15727 char ** 15728 tokenize(char *str, const char *sep) 15729 { 15730 char *token, *lasts; 15731 char **buf; 15732 int n = 0; /* number of elements */ 15733 int size = 8; /* size of the array (initial) */ 15734 15735 buf = safe_malloc(size * sizeof (char *)); 15736 15737 for (token = strtok_r(str, sep, &lasts); token != NULL; 15738 token = strtok_r(NULL, sep, &lasts), ++n) { 15739 if (n + 1 >= size) { 15740 size *= 2; 15741 if ((buf = realloc(buf, size * sizeof (char *))) == 15742 NULL) { 15743 uu_die(gettext("Out of memory")); 15744 } 15745 } 15746 buf[n] = token; 15747 } 15748 /* NULL terminate the pointer array */ 15749 buf[n] = NULL; 15750 15751 return (buf); 15752 } 15753 15754 int32_t 15755 check_tokens(char **p) 15756 { 15757 int32_t smf = 0; 15758 int32_t fma = 0; 15759 15760 while (*p) { 15761 int32_t t = string_to_tset(*p); 15762 15763 if (t == 0) { 15764 if (is_fma_token(*p) == 0) 15765 return (INVALID_TOKENS); 15766 fma = 1; /* this token is an fma event */ 15767 } else { 15768 smf |= t; 15769 } 15770 15771 if (smf != 0 && fma == 1) 15772 return (MIXED_TOKENS); 15773 ++p; 15774 } 15775 15776 if (smf > 0) 15777 return (smf); 15778 else if (fma == 1) 15779 return (FMA_TOKENS); 15780 15781 return (INVALID_TOKENS); 15782 } 15783 15784 static int 15785 get_selection_str(char *fmri, size_t sz) 15786 { 15787 if (g_hndl == NULL) { 15788 semerr(emsg_entity_not_selected); 15789 return (-1); 15790 } else if (cur_level != NULL) { 15791 semerr(emsg_invalid_for_snapshot); 15792 return (-1); 15793 } else { 15794 lscf_get_selection_str(fmri, sz); 15795 } 15796 15797 return (0); 15798 } 15799 15800 void 15801 lscf_delnotify(const char *set, int global) 15802 { 15803 char *str = strdup(set); 15804 char **pgs; 15805 char **p; 15806 int32_t tset; 15807 char *fmri = NULL; 15808 15809 if (str == NULL) 15810 uu_die(gettext("Out of memory.\n")); 15811 15812 pgs = tokenize(str, ","); 15813 15814 if ((tset = check_tokens(pgs)) > 0) { 15815 size_t sz = max_scf_fmri_len + 1; 15816 15817 fmri = safe_malloc(sz); 15818 if (global) { 15819 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15820 } else if (get_selection_str(fmri, sz) != 0) { 15821 goto out; 15822 } 15823 15824 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri, 15825 tset) != SCF_SUCCESS) { 15826 uu_warn(gettext("Failed smf_notify_del_params: %s\n"), 15827 scf_strerror(scf_error())); 15828 } 15829 } else if (tset == FMA_TOKENS) { 15830 if (global) { 15831 semerr(gettext("Can't use option '-g' with FMA event " 15832 "definitions\n")); 15833 goto out; 15834 } 15835 15836 for (p = pgs; *p; ++p) { 15837 if (smf_notify_del_params(de_tag(*p), NULL, 0) != 15838 SCF_SUCCESS) { 15839 uu_warn(gettext("Failed for \"%s\": %s\n"), *p, 15840 scf_strerror(scf_error())); 15841 goto out; 15842 } 15843 } 15844 } else if (tset == MIXED_TOKENS) { 15845 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15846 goto out; 15847 } else { 15848 uu_die(gettext("Invalid input.\n")); 15849 } 15850 15851 out: 15852 free(fmri); 15853 free(pgs); 15854 free(str); 15855 } 15856 15857 void 15858 lscf_listnotify(const char *set, int global) 15859 { 15860 char *str = safe_strdup(set); 15861 char **pgs; 15862 char **p; 15863 int32_t tset; 15864 nvlist_t *nvl; 15865 char *fmri = NULL; 15866 15867 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 15868 uu_die(gettext("Out of memory.\n")); 15869 15870 pgs = tokenize(str, ","); 15871 15872 if ((tset = check_tokens(pgs)) > 0) { 15873 size_t sz = max_scf_fmri_len + 1; 15874 15875 fmri = safe_malloc(sz); 15876 if (global) { 15877 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15878 } else if (get_selection_str(fmri, sz) != 0) { 15879 goto out; 15880 } 15881 15882 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) != 15883 SCF_SUCCESS) { 15884 if (scf_error() != SCF_ERROR_NOT_FOUND && 15885 scf_error() != SCF_ERROR_DELETED) 15886 uu_warn(gettext( 15887 "Failed listnotify: %s\n"), 15888 scf_strerror(scf_error())); 15889 goto out; 15890 } 15891 15892 listnotify_print(nvl, NULL); 15893 } else if (tset == FMA_TOKENS) { 15894 if (global) { 15895 semerr(gettext("Can't use option '-g' with FMA event " 15896 "definitions\n")); 15897 goto out; 15898 } 15899 15900 for (p = pgs; *p; ++p) { 15901 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) != 15902 SCF_SUCCESS) { 15903 /* 15904 * if the preferences have just been deleted 15905 * or does not exist, just skip. 15906 */ 15907 if (scf_error() == SCF_ERROR_NOT_FOUND || 15908 scf_error() == SCF_ERROR_DELETED) 15909 continue; 15910 uu_warn(gettext( 15911 "Failed listnotify: %s\n"), 15912 scf_strerror(scf_error())); 15913 goto out; 15914 } 15915 listnotify_print(nvl, re_tag(*p)); 15916 } 15917 } else if (tset == MIXED_TOKENS) { 15918 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15919 goto out; 15920 } else { 15921 semerr(gettext("Invalid input.\n")); 15922 } 15923 15924 out: 15925 nvlist_free(nvl); 15926 free(fmri); 15927 free(pgs); 15928 free(str); 15929 } 15930 15931 static char * 15932 strip_quotes_and_blanks(char *s) 15933 { 15934 char *start = s; 15935 char *end = strrchr(s, '\"'); 15936 15937 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') { 15938 start = s + 1; 15939 while (isblank(*start)) 15940 start++; 15941 while (isblank(*(end - 1)) && end > start) { 15942 end--; 15943 } 15944 *end = '\0'; 15945 } 15946 15947 return (start); 15948 } 15949 15950 static int 15951 set_active(nvlist_t *mech, const char *hier_part) 15952 { 15953 boolean_t b; 15954 15955 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) { 15956 b = B_TRUE; 15957 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) { 15958 b = B_FALSE; 15959 } else { 15960 return (-1); 15961 } 15962 15963 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0) 15964 uu_die(gettext("Out of memory.\n")); 15965 15966 return (0); 15967 } 15968 15969 static int 15970 add_snmp_params(nvlist_t *mech, char *hier_part) 15971 { 15972 return (set_active(mech, hier_part)); 15973 } 15974 15975 static int 15976 add_syslog_params(nvlist_t *mech, char *hier_part) 15977 { 15978 return (set_active(mech, hier_part)); 15979 } 15980 15981 /* 15982 * add_mailto_paramas() 15983 * parse the hier_part of mailto URI 15984 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]] 15985 * or mailto:{[active]|inactive} 15986 */ 15987 static int 15988 add_mailto_params(nvlist_t *mech, char *hier_part) 15989 { 15990 const char *tok = "?&"; 15991 char *p; 15992 char *lasts; 15993 char *param; 15994 char *val; 15995 15996 /* 15997 * If the notification parametes are in the form of 15998 * 15999 * malito:{[active]|inactive} 16000 * 16001 * we set the property accordingly and return. 16002 * Otherwise, we make the notification type active and 16003 * process the hier_part. 16004 */ 16005 if (set_active(mech, hier_part) == 0) 16006 return (0); 16007 else if (set_active(mech, PARAM_ACTIVE) != 0) 16008 return (-1); 16009 16010 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) { 16011 /* 16012 * sanity check: we only get here if hier_part = "", but 16013 * that's handled by set_active 16014 */ 16015 uu_die("strtok_r"); 16016 } 16017 16018 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0) 16019 uu_die(gettext("Out of memory.\n")); 16020 16021 while ((p = strtok_r(NULL, tok, &lasts)) != NULL) 16022 if ((param = strtok_r(p, "=", &val)) != NULL) 16023 if (nvlist_add_string(mech, param, val) != 0) 16024 uu_die(gettext("Out of memory.\n")); 16025 16026 return (0); 16027 } 16028 16029 static int 16030 uri_split(char *uri, char **scheme, char **hier_part) 16031 { 16032 int r = -1; 16033 16034 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL || 16035 *hier_part == NULL) { 16036 semerr(gettext("'%s' is not an URI\n"), uri); 16037 return (r); 16038 } 16039 16040 if ((r = check_uri_scheme(*scheme)) < 0) { 16041 semerr(gettext("Unkown URI scheme: %s\n"), *scheme); 16042 return (r); 16043 } 16044 16045 return (r); 16046 } 16047 16048 static int 16049 process_uri(nvlist_t *params, char *uri) 16050 { 16051 char *scheme; 16052 char *hier_part; 16053 nvlist_t *mech; 16054 int index; 16055 int r; 16056 16057 if ((index = uri_split(uri, &scheme, &hier_part)) < 0) 16058 return (-1); 16059 16060 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0) 16061 uu_die(gettext("Out of memory.\n")); 16062 16063 switch (index) { 16064 case 0: 16065 /* error messages displayed by called function */ 16066 r = add_mailto_params(mech, hier_part); 16067 break; 16068 16069 case 1: 16070 if ((r = add_snmp_params(mech, hier_part)) != 0) 16071 semerr(gettext("Not valid parameters: '%s'\n"), 16072 hier_part); 16073 break; 16074 16075 case 2: 16076 if ((r = add_syslog_params(mech, hier_part)) != 0) 16077 semerr(gettext("Not valid parameters: '%s'\n"), 16078 hier_part); 16079 break; 16080 16081 default: 16082 r = -1; 16083 } 16084 16085 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol, 16086 mech) != 0) 16087 uu_die(gettext("Out of memory.\n")); 16088 16089 nvlist_free(mech); 16090 return (r); 16091 } 16092 16093 static int 16094 set_params(nvlist_t *params, char **p) 16095 { 16096 char *uri; 16097 16098 if (p == NULL) 16099 /* sanity check */ 16100 uu_die("set_params"); 16101 16102 while (*p) { 16103 uri = strip_quotes_and_blanks(*p); 16104 if (process_uri(params, uri) != 0) 16105 return (-1); 16106 16107 ++p; 16108 } 16109 16110 return (0); 16111 } 16112 16113 static int 16114 setnotify(const char *e, char **p, int global) 16115 { 16116 char *str = safe_strdup(e); 16117 char **events; 16118 int32_t tset; 16119 int r = -1; 16120 nvlist_t *nvl, *params; 16121 char *fmri = NULL; 16122 16123 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 16124 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 || 16125 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 16126 SCF_NOTIFY_PARAMS_VERSION) != 0) 16127 uu_die(gettext("Out of memory.\n")); 16128 16129 events = tokenize(str, ","); 16130 16131 if ((tset = check_tokens(events)) > 0) { 16132 /* SMF state transitions parameters */ 16133 size_t sz = max_scf_fmri_len + 1; 16134 16135 fmri = safe_malloc(sz); 16136 if (global) { 16137 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 16138 } else if (get_selection_str(fmri, sz) != 0) { 16139 goto out; 16140 } 16141 16142 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 || 16143 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0) 16144 uu_die(gettext("Out of memory.\n")); 16145 16146 if ((r = set_params(params, p)) == 0) { 16147 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, 16148 params) != 0) 16149 uu_die(gettext("Out of memory.\n")); 16150 16151 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS, 16152 nvl) != SCF_SUCCESS) { 16153 r = -1; 16154 uu_warn(gettext( 16155 "Failed smf_notify_set_params(3SCF): %s\n"), 16156 scf_strerror(scf_error())); 16157 } 16158 } 16159 } else if (tset == FMA_TOKENS) { 16160 /* FMA event parameters */ 16161 if (global) { 16162 semerr(gettext("Can't use option '-g' with FMA event " 16163 "definitions\n")); 16164 goto out; 16165 } 16166 16167 if ((r = set_params(params, p)) != 0) 16168 goto out; 16169 16170 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0) 16171 uu_die(gettext("Out of memory.\n")); 16172 16173 while (*events) { 16174 if (smf_notify_set_params(de_tag(*events), nvl) != 16175 SCF_SUCCESS) 16176 uu_warn(gettext( 16177 "Failed smf_notify_set_params(3SCF) for " 16178 "event %s: %s\n"), *events, 16179 scf_strerror(scf_error())); 16180 events++; 16181 } 16182 } else if (tset == MIXED_TOKENS) { 16183 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 16184 } else { 16185 /* Sanity check */ 16186 uu_die(gettext("Invalid input.\n")); 16187 } 16188 16189 out: 16190 nvlist_free(nvl); 16191 nvlist_free(params); 16192 free(fmri); 16193 free(str); 16194 16195 return (r); 16196 } 16197 16198 int 16199 lscf_setnotify(uu_list_t *args) 16200 { 16201 int argc; 16202 char **argv = NULL; 16203 string_list_t *slp; 16204 int global; 16205 char *events; 16206 char **p; 16207 int i; 16208 int ret; 16209 16210 if ((argc = uu_list_numnodes(args)) < 2) 16211 goto usage; 16212 16213 argv = calloc(argc + 1, sizeof (char *)); 16214 if (argv == NULL) 16215 uu_die(gettext("Out of memory.\n")); 16216 16217 for (slp = uu_list_first(args), i = 0; 16218 slp != NULL; 16219 slp = uu_list_next(args, slp), ++i) 16220 argv[i] = slp->str; 16221 16222 argv[i] = NULL; 16223 16224 if (strcmp(argv[0], "-g") == 0) { 16225 global = 1; 16226 events = argv[1]; 16227 p = argv + 2; 16228 } else { 16229 global = 0; 16230 events = argv[0]; 16231 p = argv + 1; 16232 } 16233 16234 ret = setnotify(events, p, global); 16235 16236 out: 16237 free(argv); 16238 return (ret); 16239 16240 usage: 16241 ret = -2; 16242 goto out; 16243 } 16244 16245 /* 16246 * Creates a list of instance name strings associated with a service. If 16247 * wohandcrafted flag is set, get only instances that have a last-import 16248 * snapshot, instances that were imported via svccfg. 16249 */ 16250 static uu_list_t * 16251 create_instance_list(scf_service_t *svc, int wohandcrafted) 16252 { 16253 scf_snapshot_t *snap = NULL; 16254 scf_instance_t *inst; 16255 scf_iter_t *inst_iter; 16256 uu_list_t *instances; 16257 char *instname = NULL; 16258 int r; 16259 16260 inst_iter = scf_iter_create(g_hndl); 16261 inst = scf_instance_create(g_hndl); 16262 if (inst_iter == NULL || inst == NULL) { 16263 uu_warn(gettext("Could not create instance or iterator\n")); 16264 scfdie(); 16265 } 16266 16267 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 16268 return (instances); 16269 16270 if (scf_iter_service_instances(inst_iter, svc) != 0) { 16271 switch (scf_error()) { 16272 case SCF_ERROR_CONNECTION_BROKEN: 16273 case SCF_ERROR_DELETED: 16274 uu_list_destroy(instances); 16275 instances = NULL; 16276 goto out; 16277 16278 case SCF_ERROR_HANDLE_MISMATCH: 16279 case SCF_ERROR_NOT_BOUND: 16280 case SCF_ERROR_NOT_SET: 16281 default: 16282 bad_error("scf_iter_service_instances", scf_error()); 16283 } 16284 } 16285 16286 instname = safe_malloc(max_scf_name_len + 1); 16287 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 16288 if (r == -1) { 16289 (void) uu_warn(gettext("Unable to iterate through " 16290 "instances to create instance list : %s\n"), 16291 scf_strerror(scf_error())); 16292 16293 uu_list_destroy(instances); 16294 instances = NULL; 16295 goto out; 16296 } 16297 16298 /* 16299 * If the instance does not have a last-import snapshot 16300 * then do not add it to the list as it is a hand-crafted 16301 * instance that should not be managed. 16302 */ 16303 if (wohandcrafted) { 16304 if (snap == NULL && 16305 (snap = scf_snapshot_create(g_hndl)) == NULL) { 16306 uu_warn(gettext("Unable to create snapshot " 16307 "entity\n")); 16308 scfdie(); 16309 } 16310 16311 if (scf_instance_get_snapshot(inst, 16312 snap_lastimport, snap) != 0) { 16313 switch (scf_error()) { 16314 case SCF_ERROR_NOT_FOUND : 16315 case SCF_ERROR_DELETED: 16316 continue; 16317 16318 case SCF_ERROR_CONNECTION_BROKEN: 16319 uu_list_destroy(instances); 16320 instances = NULL; 16321 goto out; 16322 16323 case SCF_ERROR_HANDLE_MISMATCH: 16324 case SCF_ERROR_NOT_BOUND: 16325 case SCF_ERROR_NOT_SET: 16326 default: 16327 bad_error("scf_iter_service_instances", 16328 scf_error()); 16329 } 16330 } 16331 } 16332 16333 if (scf_instance_get_name(inst, instname, 16334 max_scf_name_len + 1) < 0) { 16335 switch (scf_error()) { 16336 case SCF_ERROR_NOT_FOUND : 16337 continue; 16338 16339 case SCF_ERROR_CONNECTION_BROKEN: 16340 case SCF_ERROR_DELETED: 16341 uu_list_destroy(instances); 16342 instances = NULL; 16343 goto out; 16344 16345 case SCF_ERROR_HANDLE_MISMATCH: 16346 case SCF_ERROR_NOT_BOUND: 16347 case SCF_ERROR_NOT_SET: 16348 default: 16349 bad_error("scf_iter_service_instances", 16350 scf_error()); 16351 } 16352 } 16353 16354 add_string(instances, instname); 16355 } 16356 16357 out: 16358 if (snap) 16359 scf_snapshot_destroy(snap); 16360 16361 scf_instance_destroy(inst); 16362 scf_iter_destroy(inst_iter); 16363 free(instname); 16364 return (instances); 16365 } 16366 16367 /* 16368 * disable an instance but wait for the instance to 16369 * move out of the running state. 16370 * 16371 * Returns 0 : if the instance did not disable 16372 * Returns non-zero : if the instance disabled. 16373 * 16374 */ 16375 static int 16376 disable_instance(scf_instance_t *instance) 16377 { 16378 char *fmribuf; 16379 int enabled = 10000; 16380 16381 if (inst_is_running(instance)) { 16382 fmribuf = safe_malloc(max_scf_name_len + 1); 16383 if (scf_instance_to_fmri(instance, fmribuf, 16384 max_scf_name_len + 1) < 0) { 16385 free(fmribuf); 16386 return (0); 16387 } 16388 16389 /* 16390 * If the instance cannot be disabled then return 16391 * failure to disable and let the caller decide 16392 * if that is of importance. 16393 */ 16394 if (smf_disable_instance(fmribuf, 0) != 0) { 16395 free(fmribuf); 16396 return (0); 16397 } 16398 16399 while (enabled) { 16400 if (!inst_is_running(instance)) 16401 break; 16402 16403 (void) poll(NULL, 0, 5); 16404 enabled = enabled - 5; 16405 } 16406 16407 free(fmribuf); 16408 } 16409 16410 return (enabled); 16411 } 16412 16413 /* 16414 * Function to compare two service_manifest structures. 16415 */ 16416 /* ARGSUSED2 */ 16417 static int 16418 service_manifest_compare(const void *left, const void *right, void *unused) 16419 { 16420 service_manifest_t *l = (service_manifest_t *)left; 16421 service_manifest_t *r = (service_manifest_t *)right; 16422 int rc; 16423 16424 rc = strcmp(l->servicename, r->servicename); 16425 16426 return (rc); 16427 } 16428 16429 /* 16430 * Look for the provided service in the service to manifest 16431 * tree. If the service exists, and a manifest was provided 16432 * then add the manifest to that service. If the service 16433 * does not exist, then add the service and manifest to the 16434 * list. 16435 * 16436 * If the manifest is NULL, return the element if found. If 16437 * the service is not found return NULL. 16438 */ 16439 service_manifest_t * 16440 find_add_svc_mfst(const char *svnbuf, const char *mfst) 16441 { 16442 service_manifest_t elem; 16443 service_manifest_t *fnelem; 16444 uu_avl_index_t marker; 16445 16446 elem.servicename = svnbuf; 16447 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 16448 16449 if (mfst) { 16450 if (fnelem) { 16451 add_string(fnelem->mfstlist, strdup(mfst)); 16452 } else { 16453 fnelem = safe_malloc(sizeof (*fnelem)); 16454 fnelem->servicename = safe_strdup(svnbuf); 16455 if ((fnelem->mfstlist = 16456 uu_list_create(string_pool, NULL, 0)) == NULL) 16457 uu_die(gettext("Could not create property " 16458 "list: %s\n"), uu_strerror(uu_error())); 16459 16460 add_string(fnelem->mfstlist, safe_strdup(mfst)); 16461 16462 uu_avl_insert(service_manifest_tree, fnelem, marker); 16463 } 16464 } 16465 16466 return (fnelem); 16467 } 16468 16469 /* 16470 * Create the service to manifest avl tree. 16471 * 16472 * Walk each of the manifests currently installed in the supported 16473 * directories, /lib/svc/manifest and /var/svc/manifest. For 16474 * each of the manifests, inventory the services and add them to 16475 * the tree. 16476 * 16477 * Code that calls this function should make sure fileystem/minimal is online, 16478 * /var is available, since this function walks the /var/svc/manifest directory. 16479 */ 16480 static void 16481 create_manifest_tree(void) 16482 { 16483 manifest_info_t **entry; 16484 manifest_info_t **manifests; 16485 uu_list_walk_t *svcs; 16486 bundle_t *b; 16487 entity_t *mfsvc; 16488 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 16489 int c, status; 16490 16491 if (service_manifest_pool) 16492 return; 16493 16494 /* 16495 * Create the list pool for the service manifest list 16496 */ 16497 service_manifest_pool = uu_avl_pool_create("service_manifest", 16498 sizeof (service_manifest_t), 16499 offsetof(service_manifest_t, svcmfst_node), 16500 service_manifest_compare, UU_DEFAULT); 16501 if (service_manifest_pool == NULL) 16502 uu_die(gettext("service_manifest pool creation failed: %s\n"), 16503 uu_strerror(uu_error())); 16504 16505 /* 16506 * Create the list 16507 */ 16508 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 16509 UU_DEFAULT); 16510 if (service_manifest_tree == NULL) 16511 uu_die(gettext("service_manifest tree creation failed: %s\n"), 16512 uu_strerror(uu_error())); 16513 16514 /* 16515 * Walk the manifests adding the service(s) from each manifest. 16516 * 16517 * If a service already exists add the manifest to the manifest 16518 * list for that service. This covers the case of a service that 16519 * is supported by multiple manifest files. 16520 */ 16521 for (c = 0; dirs[c]; c++) { 16522 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT); 16523 if (status < 0) { 16524 uu_warn(gettext("file tree walk of %s encountered " 16525 "error %s\n"), dirs[c], strerror(errno)); 16526 16527 uu_avl_destroy(service_manifest_tree); 16528 service_manifest_tree = NULL; 16529 return; 16530 } 16531 16532 /* 16533 * If a manifest that was in the list is not found 16534 * then skip and go to the next manifest file. 16535 */ 16536 if (manifests != NULL) { 16537 for (entry = manifests; *entry != NULL; entry++) { 16538 b = internal_bundle_new(); 16539 if (lxml_get_bundle_file(b, (*entry)->mi_path, 16540 SVCCFG_OP_IMPORT) != 0) { 16541 internal_bundle_free(b); 16542 continue; 16543 } 16544 16545 svcs = uu_list_walk_start(b->sc_bundle_services, 16546 0); 16547 if (svcs == NULL) { 16548 internal_bundle_free(b); 16549 continue; 16550 } 16551 16552 while ((mfsvc = uu_list_walk_next(svcs)) != 16553 NULL) { 16554 /* Add manifest to service */ 16555 (void) find_add_svc_mfst(mfsvc->sc_name, 16556 (*entry)->mi_path); 16557 } 16558 16559 uu_list_walk_end(svcs); 16560 internal_bundle_free(b); 16561 } 16562 16563 free_manifest_array(manifests); 16564 } 16565 } 16566 } 16567 16568 /* 16569 * Check the manifest history file to see 16570 * if the service was ever installed from 16571 * one of the supported directories. 16572 * 16573 * Return Values : 16574 * -1 - if there's error reading manifest history file 16575 * 1 - if the service is not found 16576 * 0 - if the service is found 16577 */ 16578 static int 16579 check_mfst_history(const char *svcname) 16580 { 16581 struct stat st; 16582 caddr_t mfsthist_start; 16583 char *svnbuf; 16584 int fd; 16585 int r = 1; 16586 16587 fd = open(MFSTHISTFILE, O_RDONLY); 16588 if (fd == -1) { 16589 uu_warn(gettext("Unable to open the history file\n")); 16590 return (-1); 16591 } 16592 16593 if (fstat(fd, &st) == -1) { 16594 uu_warn(gettext("Unable to stat the history file\n")); 16595 return (-1); 16596 } 16597 16598 mfsthist_start = mmap(0, st.st_size, PROT_READ, 16599 MAP_PRIVATE, fd, 0); 16600 16601 (void) close(fd); 16602 if (mfsthist_start == MAP_FAILED || 16603 *(mfsthist_start + st.st_size) != '\0') { 16604 (void) munmap(mfsthist_start, st.st_size); 16605 return (-1); 16606 } 16607 16608 /* 16609 * The manifest history file is a space delimited list 16610 * of service and instance to manifest linkage. Adding 16611 * a space to the end of the service name so to get only 16612 * the service that is being searched for. 16613 */ 16614 svnbuf = uu_msprintf("%s ", svcname); 16615 if (svnbuf == NULL) 16616 uu_die(gettext("Out of memory")); 16617 16618 if (strstr(mfsthist_start, svnbuf) != NULL) 16619 r = 0; 16620 16621 (void) munmap(mfsthist_start, st.st_size); 16622 uu_free(svnbuf); 16623 return (r); 16624 } 16625 16626 /* 16627 * Take down each of the instances in the service 16628 * and remove them, then delete the service. 16629 */ 16630 static void 16631 teardown_service(scf_service_t *svc, const char *svnbuf) 16632 { 16633 scf_instance_t *instance; 16634 scf_iter_t *iter; 16635 int r; 16636 16637 safe_printf(gettext("Delete service %s as there are no " 16638 "supporting manifests\n"), svnbuf); 16639 16640 instance = scf_instance_create(g_hndl); 16641 iter = scf_iter_create(g_hndl); 16642 if (iter == NULL || instance == NULL) { 16643 uu_warn(gettext("Unable to create supporting entities to " 16644 "teardown the service\n")); 16645 uu_warn(gettext("scf error is : %s\n"), 16646 scf_strerror(scf_error())); 16647 scfdie(); 16648 } 16649 16650 if (scf_iter_service_instances(iter, svc) != 0) { 16651 switch (scf_error()) { 16652 case SCF_ERROR_CONNECTION_BROKEN: 16653 case SCF_ERROR_DELETED: 16654 goto out; 16655 16656 case SCF_ERROR_HANDLE_MISMATCH: 16657 case SCF_ERROR_NOT_BOUND: 16658 case SCF_ERROR_NOT_SET: 16659 default: 16660 bad_error("scf_iter_service_instances", 16661 scf_error()); 16662 } 16663 } 16664 16665 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 16666 if (r == -1) { 16667 uu_warn(gettext("Error - %s\n"), 16668 scf_strerror(scf_error())); 16669 goto out; 16670 } 16671 16672 (void) disable_instance(instance); 16673 } 16674 16675 /* 16676 * Delete the service... forcing the deletion in case 16677 * any of the instances did not disable. 16678 */ 16679 (void) lscf_service_delete(svc, 1); 16680 out: 16681 scf_instance_destroy(instance); 16682 scf_iter_destroy(iter); 16683 } 16684 16685 /* 16686 * Get the list of instances supported by the manifest 16687 * file. 16688 * 16689 * Return 0 if there are no instances. 16690 * 16691 * Return -1 if there are errors attempting to collect instances. 16692 * 16693 * Return the count of instances found if there are no errors. 16694 * 16695 */ 16696 static int 16697 check_instance_support(char *mfstfile, const char *svcname, 16698 uu_list_t *instances) 16699 { 16700 uu_list_walk_t *svcs, *insts; 16701 uu_list_t *ilist; 16702 bundle_t *b; 16703 entity_t *mfsvc, *mfinst; 16704 const char *svcn; 16705 int rminstcnt = 0; 16706 16707 16708 b = internal_bundle_new(); 16709 16710 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 16711 /* 16712 * Unable to process the manifest file for 16713 * instance support, so just return as 16714 * don't want to remove instances that could 16715 * not be accounted for that might exist here. 16716 */ 16717 internal_bundle_free(b); 16718 return (0); 16719 } 16720 16721 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 16722 if (svcs == NULL) { 16723 internal_bundle_free(b); 16724 return (0); 16725 } 16726 16727 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 16728 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 16729 16730 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 16731 if (strcmp(mfsvc->sc_name, svcn) == 0) 16732 break; 16733 } 16734 uu_list_walk_end(svcs); 16735 16736 if (mfsvc == NULL) { 16737 internal_bundle_free(b); 16738 return (-1); 16739 } 16740 16741 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 16742 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 16743 internal_bundle_free(b); 16744 return (0); 16745 } 16746 16747 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 16748 /* 16749 * Remove the instance from the instances list. 16750 * The unaccounted for instances will be removed 16751 * from the service once all manifests are 16752 * processed. 16753 */ 16754 (void) remove_string(instances, 16755 mfinst->sc_name); 16756 rminstcnt++; 16757 } 16758 16759 uu_list_walk_end(insts); 16760 internal_bundle_free(b); 16761 16762 return (rminstcnt); 16763 } 16764 16765 /* 16766 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 16767 * 'false' to indicate there's no manifest file(s) found for the service. 16768 */ 16769 static void 16770 svc_add_no_support(scf_service_t *svc) 16771 { 16772 char *pname; 16773 16774 /* Add no support */ 16775 cur_svc = svc; 16776 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 16777 return; 16778 16779 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 16780 if (pname == NULL) 16781 uu_die(gettext("Out of memory.\n")); 16782 16783 (void) lscf_addpropvalue(pname, "boolean:", "0"); 16784 16785 uu_free(pname); 16786 cur_svc = NULL; 16787 } 16788 16789 /* 16790 * This function handles all upgrade scenarios for a service that doesn't have 16791 * SCF_PG_MANIFESTFILES pg. The function creates and populates 16792 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 16793 * manifest(s) mapping. Manifests under supported directories are inventoried 16794 * and a property is added for each file that delivers configuration to the 16795 * service. A service that has no corresponding manifest files (deleted) are 16796 * removed from repository. 16797 * 16798 * Unsupported services: 16799 * 16800 * A service is considered unsupported if there is no corresponding manifest 16801 * in the supported directories for that service and the service isn't in the 16802 * history file list. The history file, MFSTHISTFILE, contains a list of all 16803 * services and instances that were delivered by Solaris before the introduction 16804 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 16805 * the path to the manifest file that defined the service or instance. 16806 * 16807 * Another type of unsupported services is 'handcrafted' services, 16808 * programmatically created services or services created by dependent entries 16809 * in other manifests. A handcrafted service is identified by its lack of any 16810 * instance containing last-import snapshot which is created during svccfg 16811 * import. 16812 * 16813 * This function sets a flag for unsupported services by setting services' 16814 * SCF_PG_MANIFESTFILES/support property to false. 16815 */ 16816 static void 16817 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 16818 { 16819 service_manifest_t *elem; 16820 uu_list_walk_t *mfwalk; 16821 string_list_t *mfile; 16822 uu_list_t *instances; 16823 const char *sname; 16824 char *pname; 16825 int r; 16826 16827 /* 16828 * Since there's no guarantee manifests under /var are available during 16829 * early import, don't perform any upgrade during early import. 16830 */ 16831 if (IGNORE_VAR) 16832 return; 16833 16834 if (service_manifest_tree == NULL) { 16835 create_manifest_tree(); 16836 } 16837 16838 /* 16839 * Find service's supporting manifest(s) after 16840 * stripping off the svc:/ prefix that is part 16841 * of the fmri that is not used in the service 16842 * manifest bundle list. 16843 */ 16844 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 16845 strlen(SCF_FMRI_SERVICE_PREFIX); 16846 elem = find_add_svc_mfst(sname, NULL); 16847 if (elem == NULL) { 16848 16849 /* 16850 * A handcrafted service, one that has no instance containing 16851 * last-import snapshot, should get unsupported flag. 16852 */ 16853 instances = create_instance_list(svc, 1); 16854 if (instances == NULL) { 16855 uu_warn(gettext("Unable to create instance list %s\n"), 16856 svcname); 16857 return; 16858 } 16859 16860 if (uu_list_numnodes(instances) == 0) { 16861 svc_add_no_support(svc); 16862 return; 16863 } 16864 16865 /* 16866 * If the service is in the history file, and its supporting 16867 * manifests are not found, we can safely delete the service 16868 * because its manifests are removed from the system. 16869 * 16870 * Services not found in the history file are not delivered by 16871 * Solaris and/or delivered outside supported directories, set 16872 * unsupported flag for these services. 16873 */ 16874 r = check_mfst_history(svcname); 16875 if (r == -1) 16876 return; 16877 16878 if (r) { 16879 /* Set unsupported flag for service */ 16880 svc_add_no_support(svc); 16881 } else { 16882 /* Delete the service */ 16883 teardown_service(svc, svcname); 16884 } 16885 16886 return; 16887 } 16888 16889 /* 16890 * Walk through the list of manifests and add them 16891 * to the service. 16892 * 16893 * Create a manifestfiles pg and add the property. 16894 */ 16895 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 16896 if (mfwalk == NULL) 16897 return; 16898 16899 cur_svc = svc; 16900 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 16901 if (r != 0) { 16902 cur_svc = NULL; 16903 return; 16904 } 16905 16906 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 16907 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16908 mhash_filename_to_propname(mfile->str, 0)); 16909 if (pname == NULL) 16910 uu_die(gettext("Out of memory.\n")); 16911 16912 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 16913 uu_free(pname); 16914 } 16915 uu_list_walk_end(mfwalk); 16916 16917 cur_svc = NULL; 16918 } 16919 16920 /* 16921 * Take a service and process the manifest file entires to see if 16922 * there is continued support for the service and instances. If 16923 * not cleanup as appropriate. 16924 * 16925 * If a service does not have a manifest files entry flag it for 16926 * upgrade and return. 16927 * 16928 * For each manifestfiles property check if the manifest file is 16929 * under the supported /lib/svc/manifest or /var/svc/manifest path 16930 * and if not then return immediately as this service is not supported 16931 * by the cleanup mechanism and should be ignored. 16932 * 16933 * For each manifest file that is supported, check to see if the 16934 * file exists. If not then remove the manifest file property 16935 * from the service and the smf/manifest hash table. If the manifest 16936 * file exists then verify that it supports the instances that are 16937 * part of the service. 16938 * 16939 * Once all manifest files have been accounted for remove any instances 16940 * that are no longer supported in the service. 16941 * 16942 * Return values : 16943 * 0 - Successfully processed the service 16944 * non-zero - failed to process the service 16945 * 16946 * On most errors, will just return to wait and get the next service, 16947 * unless in case of unable to create the needed structures which is 16948 * most likely a fatal error that is not going to be recoverable. 16949 */ 16950 int 16951 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 16952 { 16953 struct mpg_mfile *mpntov = NULL; 16954 struct mpg_mfile **mpvarry = NULL; 16955 scf_service_t *svc; 16956 scf_propertygroup_t *mpg; 16957 scf_property_t *mp; 16958 scf_value_t *mv; 16959 scf_iter_t *mi; 16960 scf_instance_t *instance; 16961 uu_list_walk_t *insts; 16962 uu_list_t *instances = NULL; 16963 boolean_t activity = (boolean_t)act; 16964 char *mpnbuf = NULL; 16965 char *mpvbuf = NULL; 16966 char *pgpropbuf; 16967 int mfstcnt, rminstct, instct, mfstmax; 16968 int index; 16969 int r = 0; 16970 16971 assert(g_hndl != NULL); 16972 assert(wip->svc != NULL); 16973 assert(wip->fmri != NULL); 16974 16975 svc = wip->svc; 16976 16977 mpg = scf_pg_create(g_hndl); 16978 mp = scf_property_create(g_hndl); 16979 mi = scf_iter_create(g_hndl); 16980 mv = scf_value_create(g_hndl); 16981 instance = scf_instance_create(g_hndl); 16982 16983 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 16984 instance == NULL) { 16985 uu_warn(gettext("Unable to create the supporting entities\n")); 16986 uu_warn(gettext("scf error is : %s\n"), 16987 scf_strerror(scf_error())); 16988 scfdie(); 16989 } 16990 16991 /* 16992 * Get the manifestfiles property group to be parsed for 16993 * files existence. 16994 */ 16995 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 16996 switch (scf_error()) { 16997 case SCF_ERROR_NOT_FOUND: 16998 upgrade_svc_mfst_connection(svc, wip->fmri); 16999 break; 17000 case SCF_ERROR_DELETED: 17001 case SCF_ERROR_CONNECTION_BROKEN: 17002 goto out; 17003 17004 case SCF_ERROR_HANDLE_MISMATCH: 17005 case SCF_ERROR_NOT_BOUND: 17006 case SCF_ERROR_NOT_SET: 17007 default: 17008 bad_error("scf_iter_pg_properties", 17009 scf_error()); 17010 } 17011 17012 goto out; 17013 } 17014 17015 /* 17016 * Iterate through each of the manifestfiles properties 17017 * to determine what manifestfiles are available. 17018 * 17019 * If a manifest file is supported then increment the 17020 * count and therefore the service is safe. 17021 */ 17022 if (scf_iter_pg_properties(mi, mpg) != 0) { 17023 switch (scf_error()) { 17024 case SCF_ERROR_DELETED: 17025 case SCF_ERROR_CONNECTION_BROKEN: 17026 goto out; 17027 17028 case SCF_ERROR_HANDLE_MISMATCH: 17029 case SCF_ERROR_NOT_BOUND: 17030 case SCF_ERROR_NOT_SET: 17031 default: 17032 bad_error("scf_iter_pg_properties", 17033 scf_error()); 17034 } 17035 } 17036 17037 mfstcnt = 0; 17038 mfstmax = MFSTFILE_MAX; 17039 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 17040 while ((r = scf_iter_next_property(mi, mp)) != 0) { 17041 if (r == -1) 17042 bad_error(gettext("Unable to iterate through " 17043 "manifestfiles properties : %s"), 17044 scf_error()); 17045 17046 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 17047 mpnbuf = safe_malloc(max_scf_name_len + 1); 17048 mpvbuf = safe_malloc(max_scf_value_len + 1); 17049 mpntov->mpg = mpnbuf; 17050 mpntov->mfile = mpvbuf; 17051 mpntov->access = 1; 17052 if (scf_property_get_name(mp, mpnbuf, 17053 max_scf_name_len + 1) < 0) { 17054 uu_warn(gettext("Unable to get manifest file " 17055 "property : %s\n"), 17056 scf_strerror(scf_error())); 17057 17058 switch (scf_error()) { 17059 case SCF_ERROR_DELETED: 17060 case SCF_ERROR_CONNECTION_BROKEN: 17061 r = scferror2errno(scf_error()); 17062 goto out_free; 17063 17064 case SCF_ERROR_HANDLE_MISMATCH: 17065 case SCF_ERROR_NOT_BOUND: 17066 case SCF_ERROR_NOT_SET: 17067 default: 17068 bad_error("scf_iter_pg_properties", 17069 scf_error()); 17070 } 17071 } 17072 17073 /* 17074 * The support property is a boolean value that indicates 17075 * if the service is supported for manifest file deletion. 17076 * Currently at this time there is no code that sets this 17077 * value to true. So while we could just let this be caught 17078 * by the support check below, in the future this by be set 17079 * to true and require processing. So for that, go ahead 17080 * and check here, and just return if false. Otherwise, 17081 * fall through expecting that other support checks will 17082 * handle the entries. 17083 */ 17084 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 17085 uint8_t support; 17086 17087 if (scf_property_get_value(mp, mv) != 0 || 17088 scf_value_get_boolean(mv, &support) != 0) { 17089 uu_warn(gettext("Unable to get the manifest " 17090 "support value: %s\n"), 17091 scf_strerror(scf_error())); 17092 17093 switch (scf_error()) { 17094 case SCF_ERROR_DELETED: 17095 case SCF_ERROR_CONNECTION_BROKEN: 17096 r = scferror2errno(scf_error()); 17097 goto out_free; 17098 17099 case SCF_ERROR_HANDLE_MISMATCH: 17100 case SCF_ERROR_NOT_BOUND: 17101 case SCF_ERROR_NOT_SET: 17102 default: 17103 bad_error("scf_iter_pg_properties", 17104 scf_error()); 17105 } 17106 } 17107 17108 if (support == B_FALSE) 17109 goto out_free; 17110 } 17111 17112 /* 17113 * Anything with a manifest outside of the supported 17114 * directories, immediately bail out because that makes 17115 * this service non-supported. We don't even want 17116 * to do instance processing in this case because the 17117 * instances could be part of the non-supported manifest. 17118 */ 17119 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 17120 /* 17121 * Manifest is not in /lib/svc, so we need to 17122 * consider the /var/svc case. 17123 */ 17124 if (strncmp(mpnbuf, VARSVC_PR, 17125 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 17126 /* 17127 * Either the manifest is not in /var/svc or 17128 * /var is not yet mounted. We ignore the 17129 * manifest either because it is not in a 17130 * standard location or because we cannot 17131 * currently access the manifest. 17132 */ 17133 goto out_free; 17134 } 17135 } 17136 17137 /* 17138 * Get the value to of the manifest file for this entry 17139 * for access verification and instance support 17140 * verification if it still exists. 17141 * 17142 * During Early Manifest Import if the manifest is in 17143 * /var/svc then it may not yet be available for checking 17144 * so we must determine if /var/svc is available. If not 17145 * then defer until Late Manifest Import to cleanup. 17146 */ 17147 if (scf_property_get_value(mp, mv) != 0) { 17148 uu_warn(gettext("Unable to get the manifest file " 17149 "value: %s\n"), 17150 scf_strerror(scf_error())); 17151 17152 switch (scf_error()) { 17153 case SCF_ERROR_DELETED: 17154 case SCF_ERROR_CONNECTION_BROKEN: 17155 r = scferror2errno(scf_error()); 17156 goto out_free; 17157 17158 case SCF_ERROR_HANDLE_MISMATCH: 17159 case SCF_ERROR_NOT_BOUND: 17160 case SCF_ERROR_NOT_SET: 17161 default: 17162 bad_error("scf_property_get_value", 17163 scf_error()); 17164 } 17165 } 17166 17167 if (scf_value_get_astring(mv, mpvbuf, 17168 max_scf_value_len + 1) < 0) { 17169 uu_warn(gettext("Unable to get the manifest " 17170 "file : %s\n"), 17171 scf_strerror(scf_error())); 17172 17173 switch (scf_error()) { 17174 case SCF_ERROR_DELETED: 17175 case SCF_ERROR_CONNECTION_BROKEN: 17176 r = scferror2errno(scf_error()); 17177 goto out_free; 17178 17179 case SCF_ERROR_HANDLE_MISMATCH: 17180 case SCF_ERROR_NOT_BOUND: 17181 case SCF_ERROR_NOT_SET: 17182 default: 17183 bad_error("scf_value_get_astring", 17184 scf_error()); 17185 } 17186 } 17187 17188 mpvarry[mfstcnt] = mpntov; 17189 mfstcnt++; 17190 17191 /* 17192 * Check for the need to reallocate array 17193 */ 17194 if (mfstcnt >= (mfstmax - 1)) { 17195 struct mpg_mfile **newmpvarry; 17196 17197 mfstmax = mfstmax * 2; 17198 newmpvarry = realloc(mpvarry, 17199 sizeof (struct mpg_mfile *) * mfstmax); 17200 17201 if (newmpvarry == NULL) 17202 goto out_free; 17203 17204 mpvarry = newmpvarry; 17205 } 17206 17207 mpvarry[mfstcnt] = NULL; 17208 } 17209 17210 for (index = 0; mpvarry[index]; index++) { 17211 mpntov = mpvarry[index]; 17212 17213 /* 17214 * Check to see if the manifestfile is accessable, if so hand 17215 * this service and manifestfile off to be processed for 17216 * instance support. 17217 */ 17218 mpnbuf = mpntov->mpg; 17219 mpvbuf = mpntov->mfile; 17220 if (access(mpvbuf, F_OK) != 0) { 17221 mpntov->access = 0; 17222 activity++; 17223 mfstcnt--; 17224 /* Remove the entry from the service */ 17225 cur_svc = svc; 17226 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 17227 mpnbuf); 17228 if (pgpropbuf == NULL) 17229 uu_die(gettext("Out of memory.\n")); 17230 17231 lscf_delprop(pgpropbuf); 17232 cur_svc = NULL; 17233 17234 uu_free(pgpropbuf); 17235 } 17236 } 17237 17238 /* 17239 * If mfstcnt is 0, none of the manifests that supported the service 17240 * existed so remove the service. 17241 */ 17242 if (mfstcnt == 0) { 17243 teardown_service(svc, wip->fmri); 17244 17245 goto out_free; 17246 } 17247 17248 if (activity) { 17249 int nosvcsupport = 0; 17250 17251 /* 17252 * If the list of service instances is NULL then 17253 * create the list. 17254 */ 17255 instances = create_instance_list(svc, 1); 17256 if (instances == NULL) { 17257 uu_warn(gettext("Unable to create instance list %s\n"), 17258 wip->fmri); 17259 goto out_free; 17260 } 17261 17262 rminstct = uu_list_numnodes(instances); 17263 instct = rminstct; 17264 17265 for (index = 0; mpvarry[index]; index++) { 17266 mpntov = mpvarry[index]; 17267 if (mpntov->access == 0) 17268 continue; 17269 17270 mpnbuf = mpntov->mpg; 17271 mpvbuf = mpntov->mfile; 17272 r = check_instance_support(mpvbuf, wip->fmri, 17273 instances); 17274 if (r == -1) { 17275 nosvcsupport++; 17276 } else { 17277 rminstct -= r; 17278 } 17279 } 17280 17281 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 17282 teardown_service(svc, wip->fmri); 17283 17284 goto out_free; 17285 } 17286 } 17287 17288 /* 17289 * If there are instances left on the instance list, then 17290 * we must remove them. 17291 */ 17292 if (instances != NULL && uu_list_numnodes(instances)) { 17293 string_list_t *sp; 17294 17295 insts = uu_list_walk_start(instances, 0); 17296 while ((sp = uu_list_walk_next(insts)) != NULL) { 17297 /* 17298 * Remove the instance from the instances list. 17299 */ 17300 safe_printf(gettext("Delete instance %s from " 17301 "service %s\n"), sp->str, wip->fmri); 17302 if (scf_service_get_instance(svc, sp->str, 17303 instance) != SCF_SUCCESS) { 17304 (void) uu_warn("scf_error - %s\n", 17305 scf_strerror(scf_error())); 17306 17307 continue; 17308 } 17309 17310 (void) disable_instance(instance); 17311 17312 (void) lscf_instance_delete(instance, 1); 17313 } 17314 scf_instance_destroy(instance); 17315 uu_list_walk_end(insts); 17316 } 17317 17318 out_free: 17319 if (mpvarry) { 17320 struct mpg_mfile *fmpntov; 17321 17322 for (index = 0; mpvarry[index]; index++) { 17323 fmpntov = mpvarry[index]; 17324 if (fmpntov->mpg == mpnbuf) 17325 mpnbuf = NULL; 17326 free(fmpntov->mpg); 17327 17328 if (fmpntov->mfile == mpvbuf) 17329 mpvbuf = NULL; 17330 free(fmpntov->mfile); 17331 17332 if (fmpntov == mpntov) 17333 mpntov = NULL; 17334 free(fmpntov); 17335 } 17336 if (mpnbuf) 17337 free(mpnbuf); 17338 if (mpvbuf) 17339 free(mpvbuf); 17340 if (mpntov) 17341 free(mpntov); 17342 17343 free(mpvarry); 17344 } 17345 out: 17346 scf_pg_destroy(mpg); 17347 scf_property_destroy(mp); 17348 scf_iter_destroy(mi); 17349 scf_value_destroy(mv); 17350 17351 return (0); 17352 } 17353 17354 /* 17355 * Take the service and search for the manifestfiles property 17356 * in each of the property groups. If the manifest file 17357 * associated with the property does not exist then remove 17358 * the property group. 17359 */ 17360 int 17361 lscf_hash_cleanup() 17362 { 17363 scf_service_t *svc; 17364 scf_scope_t *scope; 17365 scf_propertygroup_t *pg; 17366 scf_property_t *prop; 17367 scf_value_t *val; 17368 scf_iter_t *iter; 17369 char *pgname = NULL; 17370 char *mfile = NULL; 17371 int r; 17372 17373 svc = scf_service_create(g_hndl); 17374 scope = scf_scope_create(g_hndl); 17375 pg = scf_pg_create(g_hndl); 17376 prop = scf_property_create(g_hndl); 17377 val = scf_value_create(g_hndl); 17378 iter = scf_iter_create(g_hndl); 17379 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 17380 svc == NULL || scope == NULL) { 17381 uu_warn(gettext("Unable to create a property group, or " 17382 "property\n")); 17383 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 17384 "pg is not NULL"); 17385 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 17386 "prop is not NULL"); 17387 uu_warn("%s\n", val == NULL ? "val is NULL" : 17388 "val is not NULL"); 17389 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 17390 "iter is not NULL"); 17391 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 17392 "svc is not NULL"); 17393 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 17394 "scope is not NULL"); 17395 uu_warn(gettext("scf error is : %s\n"), 17396 scf_strerror(scf_error())); 17397 scfdie(); 17398 } 17399 17400 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 17401 switch (scf_error()) { 17402 case SCF_ERROR_CONNECTION_BROKEN: 17403 case SCF_ERROR_NOT_FOUND: 17404 goto out; 17405 17406 case SCF_ERROR_HANDLE_MISMATCH: 17407 case SCF_ERROR_NOT_BOUND: 17408 case SCF_ERROR_INVALID_ARGUMENT: 17409 default: 17410 bad_error("scf_handle_get_scope", scf_error()); 17411 } 17412 } 17413 17414 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 17415 uu_warn(gettext("Unable to process the hash service, %s\n"), 17416 HASH_SVC); 17417 goto out; 17418 } 17419 17420 pgname = safe_malloc(max_scf_name_len + 1); 17421 mfile = safe_malloc(max_scf_value_len + 1); 17422 17423 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 17424 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 17425 scf_strerror(scf_error())); 17426 goto out; 17427 } 17428 17429 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 17430 if (r == -1) 17431 goto out; 17432 17433 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 17434 switch (scf_error()) { 17435 case SCF_ERROR_DELETED: 17436 return (ENODEV); 17437 17438 case SCF_ERROR_CONNECTION_BROKEN: 17439 return (ECONNABORTED); 17440 17441 case SCF_ERROR_NOT_SET: 17442 case SCF_ERROR_NOT_BOUND: 17443 default: 17444 bad_error("scf_pg_get_name", scf_error()); 17445 } 17446 } 17447 if (IGNORE_VAR) { 17448 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 17449 continue; 17450 } 17451 17452 /* 17453 * If unable to get the property continue as this is an 17454 * entry that has no location to check against. 17455 */ 17456 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 17457 continue; 17458 } 17459 17460 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 17461 uu_warn(gettext("Unable to get value from %s\n"), 17462 pgname); 17463 17464 switch (scf_error()) { 17465 case SCF_ERROR_DELETED: 17466 case SCF_ERROR_CONSTRAINT_VIOLATED: 17467 case SCF_ERROR_NOT_FOUND: 17468 case SCF_ERROR_NOT_SET: 17469 continue; 17470 17471 case SCF_ERROR_CONNECTION_BROKEN: 17472 r = scferror2errno(scf_error()); 17473 goto out; 17474 17475 case SCF_ERROR_HANDLE_MISMATCH: 17476 case SCF_ERROR_NOT_BOUND: 17477 default: 17478 bad_error("scf_property_get_value", 17479 scf_error()); 17480 } 17481 } 17482 17483 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) 17484 == -1) { 17485 uu_warn(gettext("Unable to get astring from %s : %s\n"), 17486 pgname, scf_strerror(scf_error())); 17487 17488 switch (scf_error()) { 17489 case SCF_ERROR_NOT_SET: 17490 case SCF_ERROR_TYPE_MISMATCH: 17491 continue; 17492 17493 default: 17494 bad_error("scf_value_get_astring", scf_error()); 17495 } 17496 } 17497 17498 if (access(mfile, F_OK) == 0) 17499 continue; 17500 17501 (void) scf_pg_delete(pg); 17502 } 17503 17504 out: 17505 scf_scope_destroy(scope); 17506 scf_service_destroy(svc); 17507 scf_pg_destroy(pg); 17508 scf_property_destroy(prop); 17509 scf_value_destroy(val); 17510 scf_iter_destroy(iter); 17511 free(pgname); 17512 free(mfile); 17513 17514 return (0); 17515 } 17516 17517 #ifndef NATIVE_BUILD 17518 /* ARGSUSED */ 17519 CPL_MATCH_FN(complete_select) 17520 { 17521 const char *arg0, *arg1, *arg1end; 17522 int word_start, err = 0, r; 17523 size_t len; 17524 char *buf; 17525 17526 lscf_prep_hndl(); 17527 17528 arg0 = line + strspn(line, " \t"); 17529 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 17530 17531 arg1 = arg0 + sizeof ("select") - 1; 17532 arg1 += strspn(arg1, " \t"); 17533 word_start = arg1 - line; 17534 17535 arg1end = arg1 + strcspn(arg1, " \t"); 17536 if (arg1end < line + word_end) 17537 return (0); 17538 17539 len = line + word_end - arg1; 17540 17541 buf = safe_malloc(max_scf_name_len + 1); 17542 17543 if (cur_snap != NULL) { 17544 return (0); 17545 } else if (cur_inst != NULL) { 17546 return (0); 17547 } else if (cur_svc != NULL) { 17548 scf_instance_t *inst; 17549 scf_iter_t *iter; 17550 17551 if ((inst = scf_instance_create(g_hndl)) == NULL || 17552 (iter = scf_iter_create(g_hndl)) == NULL) 17553 scfdie(); 17554 17555 if (scf_iter_service_instances(iter, cur_svc) != 0) 17556 scfdie(); 17557 17558 for (;;) { 17559 r = scf_iter_next_instance(iter, inst); 17560 if (r == 0) 17561 break; 17562 if (r != 1) 17563 scfdie(); 17564 17565 if (scf_instance_get_name(inst, buf, 17566 max_scf_name_len + 1) < 0) 17567 scfdie(); 17568 17569 if (strncmp(buf, arg1, len) == 0) { 17570 err = cpl_add_completion(cpl, line, word_start, 17571 word_end, buf + len, "", " "); 17572 if (err != 0) 17573 break; 17574 } 17575 } 17576 17577 scf_iter_destroy(iter); 17578 scf_instance_destroy(inst); 17579 17580 return (err); 17581 } else { 17582 scf_service_t *svc; 17583 scf_iter_t *iter; 17584 17585 assert(cur_scope != NULL); 17586 17587 if ((svc = scf_service_create(g_hndl)) == NULL || 17588 (iter = scf_iter_create(g_hndl)) == NULL) 17589 scfdie(); 17590 17591 if (scf_iter_scope_services(iter, cur_scope) != 0) 17592 scfdie(); 17593 17594 for (;;) { 17595 r = scf_iter_next_service(iter, svc); 17596 if (r == 0) 17597 break; 17598 if (r != 1) 17599 scfdie(); 17600 17601 if (scf_service_get_name(svc, buf, 17602 max_scf_name_len + 1) < 0) 17603 scfdie(); 17604 17605 if (strncmp(buf, arg1, len) == 0) { 17606 err = cpl_add_completion(cpl, line, word_start, 17607 word_end, buf + len, "", " "); 17608 if (err != 0) 17609 break; 17610 } 17611 } 17612 17613 scf_iter_destroy(iter); 17614 scf_service_destroy(svc); 17615 17616 return (err); 17617 } 17618 } 17619 17620 /* ARGSUSED */ 17621 CPL_MATCH_FN(complete_command) 17622 { 17623 uint32_t scope = 0; 17624 17625 if (cur_snap != NULL) 17626 scope = CS_SNAP; 17627 else if (cur_inst != NULL) 17628 scope = CS_INST; 17629 else if (cur_svc != NULL) 17630 scope = CS_SVC; 17631 else 17632 scope = CS_SCOPE; 17633 17634 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 17635 } 17636 #endif /* NATIVE_BUILD */ 17637