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