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