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 2012 Milan Jurik. All rights reserved. 25 */ 26 27 28 #include <alloca.h> 29 #include <assert.h> 30 #include <ctype.h> 31 #include <door.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <fnmatch.h> 35 #include <inttypes.h> 36 #include <libintl.h> 37 #include <libnvpair.h> 38 #include <libscf.h> 39 #include <libscf_priv.h> 40 #include <libtecla.h> 41 #include <libuutil.h> 42 #include <limits.h> 43 #include <locale.h> 44 #include <stdarg.h> 45 #include <string.h> 46 #include <strings.h> 47 #include <unistd.h> 48 #include <wait.h> 49 #include <poll.h> 50 51 #include <libxml/tree.h> 52 53 #include <sys/param.h> 54 55 #include <sys/stat.h> 56 #include <sys/mman.h> 57 58 #include "svccfg.h" 59 #include "notify_params.h" 60 #include "manifest_hash.h" 61 #include "manifest_find.h" 62 63 /* The colon namespaces in each entity (each followed by a newline). */ 64 #define COLON_NAMESPACES ":properties\n" 65 66 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 67 68 /* These are characters which the lexer requires to be in double-quotes. */ 69 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 70 71 #define HASH_SIZE 16 72 #define HASH_PG_TYPE "framework" 73 #define HASH_PG_FLAGS 0 74 #define HASH_PROP "md5sum" 75 76 /* 77 * Indentation used in the output of the describe subcommand. 78 */ 79 #define TMPL_VALUE_INDENT " " 80 #define TMPL_INDENT " " 81 #define TMPL_INDENT_2X " " 82 #define TMPL_CHOICE_INDENT " " 83 84 /* 85 * Directory locations for manifests 86 */ 87 #define VARSVC_DIR "/var/svc/manifest" 88 #define LIBSVC_DIR "/lib/svc/manifest" 89 #define VARSVC_PR "var_svc_manifest" 90 #define LIBSVC_PR "lib_svc_manifest" 91 #define MFSTFILEPR "manifestfile" 92 93 #define SUPPORTPROP "support" 94 95 #define MFSTHISTFILE "/lib/svc/share/mfsthistory" 96 97 #define MFSTFILE_MAX 16 98 99 /* 100 * These are the classes of elements which may appear as children of service 101 * or instance elements in XML manifests. 102 */ 103 struct entity_elts { 104 xmlNodePtr create_default_instance; 105 xmlNodePtr single_instance; 106 xmlNodePtr restarter; 107 xmlNodePtr dependencies; 108 xmlNodePtr dependents; 109 xmlNodePtr method_context; 110 xmlNodePtr exec_methods; 111 xmlNodePtr notify_params; 112 xmlNodePtr property_groups; 113 xmlNodePtr instances; 114 xmlNodePtr stability; 115 xmlNodePtr template; 116 }; 117 118 /* 119 * Likewise for property_group elements. 120 */ 121 struct pg_elts { 122 xmlNodePtr stability; 123 xmlNodePtr propvals; 124 xmlNodePtr properties; 125 }; 126 127 /* 128 * Likewise for template elements. 129 */ 130 struct template_elts { 131 xmlNodePtr common_name; 132 xmlNodePtr description; 133 xmlNodePtr documentation; 134 }; 135 136 /* 137 * Likewise for type (for notification parameters) elements. 138 */ 139 struct params_elts { 140 xmlNodePtr paramval; 141 xmlNodePtr parameter; 142 }; 143 144 /* 145 * This structure is for snaplevel lists. They are convenient because libscf 146 * only allows traversing snaplevels in one direction. 147 */ 148 struct snaplevel { 149 uu_list_node_t list_node; 150 scf_snaplevel_t *sl; 151 }; 152 153 /* 154 * This is used for communication between lscf_service_export and 155 * export_callback. 156 */ 157 struct export_args { 158 const char *filename; 159 int flags; 160 }; 161 162 /* 163 * The service_manifest structure is used by the upgrade process 164 * to create a list of service to manifest linkages from the manifests 165 * in a set of given directories. 166 */ 167 typedef struct service_manifest { 168 const char *servicename; 169 uu_list_t *mfstlist; 170 size_t mfstlist_sz; 171 172 uu_avl_node_t svcmfst_node; 173 } service_manifest_t; 174 175 /* 176 * Structure to track the manifest file property group 177 * and the manifest file associated with that property 178 * group. Also, a flag to keep the access once it has 179 * been checked. 180 */ 181 struct mpg_mfile { 182 char *mpg; 183 char *mfile; 184 int access; 185 }; 186 187 const char * const scf_pg_general = SCF_PG_GENERAL; 188 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 189 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 190 const char * const scf_property_external = "external"; 191 192 const char * const snap_initial = "initial"; 193 const char * const snap_lastimport = "last-import"; 194 const char * const snap_previous = "previous"; 195 const char * const snap_running = "running"; 196 197 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 198 199 ssize_t max_scf_fmri_len; 200 ssize_t max_scf_name_len; 201 ssize_t max_scf_pg_type_len; 202 ssize_t max_scf_value_len; 203 static size_t max_scf_len; 204 205 static scf_scope_t *cur_scope; 206 static scf_service_t *cur_svc = NULL; 207 static scf_instance_t *cur_inst = NULL; 208 static scf_snapshot_t *cur_snap = NULL; 209 static scf_snaplevel_t *cur_level = NULL; 210 211 static uu_list_pool_t *snaplevel_pool; 212 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 213 static uu_list_t *cur_levels; 214 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 215 216 static FILE *tempfile = NULL; 217 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 218 219 static const char *emsg_entity_not_selected; 220 static const char *emsg_permission_denied; 221 static const char *emsg_create_xml; 222 static const char *emsg_cant_modify_snapshots; 223 static const char *emsg_invalid_for_snapshot; 224 static const char *emsg_read_only; 225 static const char *emsg_deleted; 226 static const char *emsg_invalid_pg_name; 227 static const char *emsg_invalid_prop_name; 228 static const char *emsg_no_such_pg; 229 static const char *emsg_fmri_invalid_pg_name; 230 static const char *emsg_fmri_invalid_pg_name_type; 231 static const char *emsg_pg_added; 232 static const char *emsg_pg_changed; 233 static const char *emsg_pg_deleted; 234 static const char *emsg_pg_mod_perm; 235 static const char *emsg_pg_add_perm; 236 static const char *emsg_pg_del_perm; 237 static const char *emsg_snap_perm; 238 static const char *emsg_dpt_dangling; 239 static const char *emsg_dpt_no_dep; 240 241 static int li_only = 0; 242 static int no_refresh = 0; 243 244 /* import globals, to minimize allocations */ 245 static scf_scope_t *imp_scope = NULL; 246 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 247 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 248 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 249 static scf_snapshot_t *imp_rsnap = NULL; 250 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 251 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 252 static scf_property_t *imp_prop = NULL; 253 static scf_iter_t *imp_iter = NULL; 254 static scf_iter_t *imp_rpg_iter = NULL; 255 static scf_iter_t *imp_up_iter = NULL; 256 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 257 static char *imp_str = NULL; 258 static size_t imp_str_sz; 259 static char *imp_tsname = NULL; 260 static char *imp_fe1 = NULL; /* for fmri_equal() */ 261 static char *imp_fe2 = NULL; 262 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 263 264 /* upgrade_dependents() globals */ 265 static scf_instance_t *ud_inst = NULL; 266 static scf_snaplevel_t *ud_snpl = NULL; 267 static scf_propertygroup_t *ud_pg = NULL; 268 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 269 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 270 static int ud_run_dpts_pg_set = 0; 271 static scf_property_t *ud_prop = NULL; 272 static scf_property_t *ud_dpt_prop = NULL; 273 static scf_value_t *ud_val = NULL; 274 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 275 static scf_transaction_t *ud_tx = NULL; 276 static char *ud_ctarg = NULL; 277 static char *ud_oldtarg = NULL; 278 static char *ud_name = NULL; 279 280 /* export globals */ 281 static scf_instance_t *exp_inst; 282 static scf_propertygroup_t *exp_pg; 283 static scf_property_t *exp_prop; 284 static scf_value_t *exp_val; 285 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 286 static char *exp_str; 287 static size_t exp_str_sz; 288 289 /* cleanup globals */ 290 static uu_avl_pool_t *service_manifest_pool = NULL; 291 static uu_avl_t *service_manifest_tree = NULL; 292 293 static void scfdie_lineno(int lineno) __NORETURN; 294 295 static char *start_method_names[] = { 296 "start", 297 "inetd_start", 298 NULL 299 }; 300 301 static struct uri_scheme { 302 const char *scheme; 303 const char *protocol; 304 } uri_scheme[] = { 305 { "mailto", "smtp" }, 306 { "snmp", "snmp" }, 307 { "syslog", "syslog" }, 308 { NULL, NULL } 309 }; 310 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \ 311 sizeof (struct uri_scheme)) - 1) 312 313 static int 314 check_uri_scheme(const char *scheme) 315 { 316 int i; 317 318 for (i = 0; uri_scheme[i].scheme != NULL; ++i) { 319 if (strcmp(scheme, uri_scheme[i].scheme) == 0) 320 return (i); 321 } 322 323 return (-1); 324 } 325 326 static int 327 check_uri_protocol(const char *p) 328 { 329 int i; 330 331 for (i = 0; uri_scheme[i].protocol != NULL; ++i) { 332 if (strcmp(p, uri_scheme[i].protocol) == 0) 333 return (i); 334 } 335 336 return (-1); 337 } 338 339 /* 340 * For unexpected libscf errors. 341 */ 342 #ifdef NDEBUG 343 344 static void scfdie(void) __NORETURN; 345 346 static void 347 scfdie(void) 348 { 349 scf_error_t err = scf_error(); 350 351 if (err == SCF_ERROR_CONNECTION_BROKEN) 352 uu_die(gettext("Repository connection broken. Exiting.\n")); 353 354 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 355 scf_strerror(err)); 356 } 357 358 #else 359 360 #define scfdie() scfdie_lineno(__LINE__) 361 362 static void 363 scfdie_lineno(int lineno) 364 { 365 scf_error_t err = scf_error(); 366 367 if (err == SCF_ERROR_CONNECTION_BROKEN) 368 uu_die(gettext("Repository connection broken. Exiting.\n")); 369 370 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 371 ": %s.\n"), lineno, scf_strerror(err)); 372 } 373 374 #endif 375 376 static void 377 scfwarn(void) 378 { 379 warn(gettext("Unexpected libscf error: %s.\n"), 380 scf_strerror(scf_error())); 381 } 382 383 /* 384 * Clear a field of a structure. 385 */ 386 static int 387 clear_int(void *a, void *b) 388 { 389 /* LINTED */ 390 *(int *)((char *)a + (size_t)b) = 0; 391 392 return (UU_WALK_NEXT); 393 } 394 395 static int 396 scferror2errno(scf_error_t err) 397 { 398 switch (err) { 399 case SCF_ERROR_BACKEND_ACCESS: 400 return (EACCES); 401 402 case SCF_ERROR_BACKEND_READONLY: 403 return (EROFS); 404 405 case SCF_ERROR_CONNECTION_BROKEN: 406 return (ECONNABORTED); 407 408 case SCF_ERROR_CONSTRAINT_VIOLATED: 409 case SCF_ERROR_INVALID_ARGUMENT: 410 return (EINVAL); 411 412 case SCF_ERROR_DELETED: 413 return (ECANCELED); 414 415 case SCF_ERROR_EXISTS: 416 return (EEXIST); 417 418 case SCF_ERROR_NO_MEMORY: 419 return (ENOMEM); 420 421 case SCF_ERROR_NO_RESOURCES: 422 return (ENOSPC); 423 424 case SCF_ERROR_NOT_FOUND: 425 return (ENOENT); 426 427 case SCF_ERROR_PERMISSION_DENIED: 428 return (EPERM); 429 430 default: 431 #ifndef NDEBUG 432 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 433 __FILE__, __LINE__, err); 434 #else 435 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 436 #endif 437 abort(); 438 /* NOTREACHED */ 439 } 440 } 441 442 static int 443 entity_get_pg(void *ent, int issvc, const char *name, 444 scf_propertygroup_t *pg) 445 { 446 if (issvc) 447 return (scf_service_get_pg(ent, name, pg)); 448 else 449 return (scf_instance_get_pg(ent, name, pg)); 450 } 451 452 static void 453 entity_destroy(void *ent, int issvc) 454 { 455 if (issvc) 456 scf_service_destroy(ent); 457 else 458 scf_instance_destroy(ent); 459 } 460 461 static int 462 get_pg(const char *pg_name, scf_propertygroup_t *pg) 463 { 464 int ret; 465 466 if (cur_level != NULL) 467 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 468 else if (cur_inst != NULL) 469 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 470 else 471 ret = scf_service_get_pg(cur_svc, pg_name, pg); 472 473 return (ret); 474 } 475 476 /* 477 * Find a snaplevel in a snapshot. If get_svc is true, find the service 478 * snaplevel. Otherwise find the instance snaplevel. 479 * 480 * Returns 481 * 0 - success 482 * ECONNABORTED - repository connection broken 483 * ECANCELED - instance containing snap was deleted 484 * ENOENT - snap has no snaplevels 485 * - requested snaplevel not found 486 */ 487 static int 488 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 489 { 490 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 491 switch (scf_error()) { 492 case SCF_ERROR_CONNECTION_BROKEN: 493 case SCF_ERROR_DELETED: 494 case SCF_ERROR_NOT_FOUND: 495 return (scferror2errno(scf_error())); 496 497 case SCF_ERROR_HANDLE_MISMATCH: 498 case SCF_ERROR_NOT_BOUND: 499 case SCF_ERROR_NOT_SET: 500 default: 501 bad_error("scf_snapshot_get_base_snaplevel", 502 scf_error()); 503 } 504 } 505 506 for (;;) { 507 ssize_t ssz; 508 509 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 510 if (ssz >= 0) { 511 if (!get_svc) 512 return (0); 513 } else { 514 switch (scf_error()) { 515 case SCF_ERROR_CONSTRAINT_VIOLATED: 516 if (get_svc) 517 return (0); 518 break; 519 520 case SCF_ERROR_DELETED: 521 case SCF_ERROR_CONNECTION_BROKEN: 522 return (scferror2errno(scf_error())); 523 524 case SCF_ERROR_NOT_SET: 525 case SCF_ERROR_NOT_BOUND: 526 default: 527 bad_error("scf_snaplevel_get_instance_name", 528 scf_error()); 529 } 530 } 531 532 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 533 switch (scf_error()) { 534 case SCF_ERROR_NOT_FOUND: 535 case SCF_ERROR_CONNECTION_BROKEN: 536 case SCF_ERROR_DELETED: 537 return (scferror2errno(scf_error())); 538 539 case SCF_ERROR_HANDLE_MISMATCH: 540 case SCF_ERROR_NOT_BOUND: 541 case SCF_ERROR_NOT_SET: 542 case SCF_ERROR_INVALID_ARGUMENT: 543 default: 544 bad_error("scf_snaplevel_get_next_snaplevel", 545 scf_error()); 546 } 547 } 548 } 549 } 550 551 /* 552 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 553 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 554 * the property group named name in it. If it doesn't have a running 555 * snapshot, set pg to the instance's current property group named name. 556 * 557 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 558 * its instances. If one has a running snapshot with a service snaplevel, set 559 * pg to the property group named name in it. If no such snaplevel could be 560 * found, set pg to the service's current property group named name. 561 * 562 * iter, inst, snap, and snpl are required scratch objects. 563 * 564 * Returns 565 * 0 - success 566 * ECONNABORTED - repository connection broken 567 * ECANCELED - ent was deleted 568 * ENOENT - no such property group 569 * EINVAL - name is an invalid property group name 570 * EBADF - found running snapshot is missing a snaplevel 571 */ 572 static int 573 entity_get_running_pg(void *ent, int issvc, const char *name, 574 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 575 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 576 { 577 int r; 578 579 if (issvc) { 580 /* Search for an instance with a running snapshot. */ 581 if (scf_iter_service_instances(iter, ent) != 0) { 582 switch (scf_error()) { 583 case SCF_ERROR_DELETED: 584 case SCF_ERROR_CONNECTION_BROKEN: 585 return (scferror2errno(scf_error())); 586 587 case SCF_ERROR_NOT_SET: 588 case SCF_ERROR_NOT_BOUND: 589 case SCF_ERROR_HANDLE_MISMATCH: 590 default: 591 bad_error("scf_iter_service_instances", 592 scf_error()); 593 } 594 } 595 596 for (;;) { 597 r = scf_iter_next_instance(iter, inst); 598 if (r == 0) { 599 if (scf_service_get_pg(ent, name, pg) == 0) 600 return (0); 601 602 switch (scf_error()) { 603 case SCF_ERROR_DELETED: 604 case SCF_ERROR_NOT_FOUND: 605 case SCF_ERROR_INVALID_ARGUMENT: 606 case SCF_ERROR_CONNECTION_BROKEN: 607 return (scferror2errno(scf_error())); 608 609 case SCF_ERROR_NOT_BOUND: 610 case SCF_ERROR_HANDLE_MISMATCH: 611 case SCF_ERROR_NOT_SET: 612 default: 613 bad_error("scf_service_get_pg", 614 scf_error()); 615 } 616 } 617 if (r != 1) { 618 switch (scf_error()) { 619 case SCF_ERROR_DELETED: 620 case SCF_ERROR_CONNECTION_BROKEN: 621 return (scferror2errno(scf_error())); 622 623 case SCF_ERROR_INVALID_ARGUMENT: 624 case SCF_ERROR_NOT_SET: 625 case SCF_ERROR_NOT_BOUND: 626 case SCF_ERROR_HANDLE_MISMATCH: 627 default: 628 bad_error("scf_iter_next_instance", 629 scf_error()); 630 } 631 } 632 633 if (scf_instance_get_snapshot(inst, snap_running, 634 snap) == 0) 635 break; 636 637 switch (scf_error()) { 638 case SCF_ERROR_NOT_FOUND: 639 case SCF_ERROR_DELETED: 640 continue; 641 642 case SCF_ERROR_CONNECTION_BROKEN: 643 return (ECONNABORTED); 644 645 case SCF_ERROR_HANDLE_MISMATCH: 646 case SCF_ERROR_INVALID_ARGUMENT: 647 case SCF_ERROR_NOT_SET: 648 case SCF_ERROR_NOT_BOUND: 649 default: 650 bad_error("scf_instance_get_snapshot", 651 scf_error()); 652 } 653 } 654 } else { 655 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 656 switch (scf_error()) { 657 case SCF_ERROR_NOT_FOUND: 658 break; 659 660 case SCF_ERROR_DELETED: 661 case SCF_ERROR_CONNECTION_BROKEN: 662 return (scferror2errno(scf_error())); 663 664 case SCF_ERROR_NOT_BOUND: 665 case SCF_ERROR_HANDLE_MISMATCH: 666 case SCF_ERROR_INVALID_ARGUMENT: 667 case SCF_ERROR_NOT_SET: 668 default: 669 bad_error("scf_instance_get_snapshot", 670 scf_error()); 671 } 672 673 if (scf_instance_get_pg(ent, name, pg) == 0) 674 return (0); 675 676 switch (scf_error()) { 677 case SCF_ERROR_DELETED: 678 case SCF_ERROR_NOT_FOUND: 679 case SCF_ERROR_INVALID_ARGUMENT: 680 case SCF_ERROR_CONNECTION_BROKEN: 681 return (scferror2errno(scf_error())); 682 683 case SCF_ERROR_NOT_BOUND: 684 case SCF_ERROR_HANDLE_MISMATCH: 685 case SCF_ERROR_NOT_SET: 686 default: 687 bad_error("scf_instance_get_pg", scf_error()); 688 } 689 } 690 } 691 692 r = get_snaplevel(snap, issvc, snpl); 693 switch (r) { 694 case 0: 695 break; 696 697 case ECONNABORTED: 698 case ECANCELED: 699 return (r); 700 701 case ENOENT: 702 return (EBADF); 703 704 default: 705 bad_error("get_snaplevel", r); 706 } 707 708 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 709 return (0); 710 711 switch (scf_error()) { 712 case SCF_ERROR_DELETED: 713 case SCF_ERROR_INVALID_ARGUMENT: 714 case SCF_ERROR_CONNECTION_BROKEN: 715 case SCF_ERROR_NOT_FOUND: 716 return (scferror2errno(scf_error())); 717 718 case SCF_ERROR_NOT_BOUND: 719 case SCF_ERROR_HANDLE_MISMATCH: 720 case SCF_ERROR_NOT_SET: 721 default: 722 bad_error("scf_snaplevel_get_pg", scf_error()); 723 /* NOTREACHED */ 724 } 725 } 726 727 /* 728 * To be registered with atexit(). 729 */ 730 static void 731 remove_tempfile(void) 732 { 733 int ret; 734 735 if (tempfile != NULL) { 736 if (fclose(tempfile) == EOF) 737 (void) warn(gettext("Could not close temporary file")); 738 tempfile = NULL; 739 } 740 741 if (tempfilename[0] != '\0') { 742 do { 743 ret = remove(tempfilename); 744 } while (ret == -1 && errno == EINTR); 745 if (ret == -1) 746 warn(gettext("Could not remove temporary file")); 747 tempfilename[0] = '\0'; 748 } 749 } 750 751 /* 752 * Launch private svc.configd(1M) for manipulating alternate repositories. 753 */ 754 static void 755 start_private_repository(engine_state_t *est) 756 { 757 int fd, stat; 758 struct door_info info; 759 pid_t pid; 760 761 /* 762 * 1. Create a temporary file for the door. 763 */ 764 if (est->sc_repo_doorname != NULL) 765 free((void *)est->sc_repo_doorname); 766 767 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 768 if (est->sc_repo_doorname == NULL) 769 uu_die(gettext("Could not acquire temporary filename")); 770 771 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 772 if (fd < 0) 773 uu_die(gettext("Could not create temporary file for " 774 "repository server")); 775 776 (void) close(fd); 777 778 /* 779 * 2. Launch a configd with that door, using the specified 780 * repository. 781 */ 782 if ((est->sc_repo_pid = fork()) == 0) { 783 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 784 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 785 NULL); 786 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 787 } else if (est->sc_repo_pid == -1) 788 uu_die(gettext("Attempt to fork failed")); 789 790 do { 791 pid = waitpid(est->sc_repo_pid, &stat, 0); 792 } while (pid == -1 && errno == EINTR); 793 794 if (pid == -1) 795 uu_die(gettext("Could not waitpid() for repository server")); 796 797 if (!WIFEXITED(stat)) { 798 uu_die(gettext("Repository server failed (status %d).\n"), 799 stat); 800 } else if (WEXITSTATUS(stat) != 0) { 801 uu_die(gettext("Repository server failed (exit %d).\n"), 802 WEXITSTATUS(stat)); 803 } 804 805 /* 806 * See if it was successful by checking if the door is a door. 807 */ 808 809 fd = open(est->sc_repo_doorname, O_RDWR); 810 if (fd < 0) 811 uu_die(gettext("Could not open door \"%s\""), 812 est->sc_repo_doorname); 813 814 if (door_info(fd, &info) < 0) 815 uu_die(gettext("Unexpected door_info() error")); 816 817 if (close(fd) == -1) 818 warn(gettext("Could not close repository door"), 819 strerror(errno)); 820 821 est->sc_repo_pid = info.di_target; 822 } 823 824 void 825 lscf_cleanup(void) 826 { 827 /* 828 * In the case where we've launched a private svc.configd(1M) 829 * instance, we must terminate our child and remove the temporary 830 * rendezvous point. 831 */ 832 if (est->sc_repo_pid > 0) { 833 (void) kill(est->sc_repo_pid, SIGTERM); 834 (void) waitpid(est->sc_repo_pid, NULL, 0); 835 (void) unlink(est->sc_repo_doorname); 836 837 est->sc_repo_pid = 0; 838 } 839 } 840 841 void 842 unselect_cursnap(void) 843 { 844 void *cookie; 845 846 cur_level = NULL; 847 848 cookie = NULL; 849 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 850 scf_snaplevel_destroy(cur_elt->sl); 851 free(cur_elt); 852 } 853 854 scf_snapshot_destroy(cur_snap); 855 cur_snap = NULL; 856 } 857 858 void 859 lscf_prep_hndl(void) 860 { 861 if (g_hndl != NULL) 862 return; 863 864 g_hndl = scf_handle_create(SCF_VERSION); 865 if (g_hndl == NULL) 866 scfdie(); 867 868 if (est->sc_repo_filename != NULL) 869 start_private_repository(est); 870 871 if (est->sc_repo_doorname != NULL) { 872 scf_value_t *repo_value; 873 int ret; 874 875 repo_value = scf_value_create(g_hndl); 876 if (repo_value == NULL) 877 scfdie(); 878 879 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 880 assert(ret == SCF_SUCCESS); 881 882 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 883 SCF_SUCCESS) 884 scfdie(); 885 886 scf_value_destroy(repo_value); 887 } 888 889 if (scf_handle_bind(g_hndl) != 0) 890 uu_die(gettext("Could not connect to repository server: %s.\n"), 891 scf_strerror(scf_error())); 892 893 cur_scope = scf_scope_create(g_hndl); 894 if (cur_scope == NULL) 895 scfdie(); 896 897 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 898 scfdie(); 899 } 900 901 static void 902 repository_teardown(void) 903 { 904 if (g_hndl != NULL) { 905 if (cur_snap != NULL) 906 unselect_cursnap(); 907 scf_instance_destroy(cur_inst); 908 scf_service_destroy(cur_svc); 909 scf_scope_destroy(cur_scope); 910 scf_handle_destroy(g_hndl); 911 cur_inst = NULL; 912 cur_svc = NULL; 913 cur_scope = NULL; 914 g_hndl = NULL; 915 lscf_cleanup(); 916 } 917 } 918 919 void 920 lscf_set_repository(const char *repfile, int force) 921 { 922 repository_teardown(); 923 924 if (est->sc_repo_filename != NULL) { 925 free((void *)est->sc_repo_filename); 926 est->sc_repo_filename = NULL; 927 } 928 929 if ((force == 0) && (access(repfile, R_OK) != 0)) { 930 /* 931 * Repository file does not exist 932 * or has no read permission. 933 */ 934 warn(gettext("Cannot access \"%s\": %s\n"), 935 repfile, strerror(errno)); 936 } else { 937 est->sc_repo_filename = safe_strdup(repfile); 938 } 939 940 lscf_prep_hndl(); 941 } 942 943 void 944 lscf_init() 945 { 946 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 947 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 948 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 949 0 || 950 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 951 scfdie(); 952 953 max_scf_len = max_scf_fmri_len; 954 if (max_scf_name_len > max_scf_len) 955 max_scf_len = max_scf_name_len; 956 if (max_scf_pg_type_len > max_scf_len) 957 max_scf_len = max_scf_pg_type_len; 958 /* 959 * When a value of type opaque is represented as a string, the 960 * string contains 2 characters for every byte of data. That is 961 * because the string contains the hex representation of the opaque 962 * value. 963 */ 964 if (2 * max_scf_value_len > max_scf_len) 965 max_scf_len = 2 * max_scf_value_len; 966 967 if (atexit(remove_tempfile) != 0) 968 uu_die(gettext("Could not register atexit() function")); 969 970 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 971 emsg_permission_denied = gettext("Permission denied.\n"); 972 emsg_create_xml = gettext("Could not create XML node.\n"); 973 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 974 emsg_invalid_for_snapshot = 975 gettext("Invalid operation on a snapshot.\n"); 976 emsg_read_only = gettext("Backend read-only.\n"); 977 emsg_deleted = gettext("Current selection has been deleted.\n"); 978 emsg_invalid_pg_name = 979 gettext("Invalid property group name \"%s\".\n"); 980 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 981 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 982 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 983 "with invalid name \"%s\".\n"); 984 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 985 "group with invalid name \"%s\" or type \"%s\".\n"); 986 emsg_pg_added = gettext("%s changed unexpectedly " 987 "(property group \"%s\" added).\n"); 988 emsg_pg_changed = gettext("%s changed unexpectedly " 989 "(property group \"%s\" changed).\n"); 990 emsg_pg_deleted = gettext("%s changed unexpectedly " 991 "(property group \"%s\" or an ancestor was deleted).\n"); 992 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 993 "in %s (permission denied).\n"); 994 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 995 "in %s (permission denied).\n"); 996 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 997 "in %s (permission denied).\n"); 998 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 999 "(permission denied).\n"); 1000 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 1001 "new dependent \"%s\" because it already exists). Warning: The " 1002 "current dependent's target (%s) does not exist.\n"); 1003 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 1004 "dependent \"%s\" because it already exists). Warning: The " 1005 "current dependent's target (%s) does not have a dependency named " 1006 "\"%s\" as expected.\n"); 1007 1008 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 1009 offsetof(string_list_t, node), NULL, 0); 1010 snaplevel_pool = uu_list_pool_create("snaplevels", 1011 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 1012 NULL, 0); 1013 } 1014 1015 1016 static const char * 1017 prop_to_typestr(const scf_property_t *prop) 1018 { 1019 scf_type_t ty; 1020 1021 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 1022 scfdie(); 1023 1024 return (scf_type_to_string(ty)); 1025 } 1026 1027 static scf_type_t 1028 string_to_type(const char *type) 1029 { 1030 size_t len = strlen(type); 1031 char *buf; 1032 1033 if (len == 0 || type[len - 1] != ':') 1034 return (SCF_TYPE_INVALID); 1035 1036 buf = (char *)alloca(len + 1); 1037 (void) strlcpy(buf, type, len + 1); 1038 buf[len - 1] = 0; 1039 1040 return (scf_string_to_type(buf)); 1041 } 1042 1043 static scf_value_t * 1044 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 1045 { 1046 scf_value_t *v; 1047 char *dup, *nstr; 1048 size_t len; 1049 1050 v = scf_value_create(g_hndl); 1051 if (v == NULL) 1052 scfdie(); 1053 1054 len = strlen(str); 1055 if (require_quotes && 1056 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1057 semerr(gettext("Multiple string values or string values " 1058 "with spaces must be quoted with '\"'.\n")); 1059 scf_value_destroy(v); 1060 return (NULL); 1061 } 1062 1063 nstr = dup = safe_strdup(str); 1064 if (dup[0] == '\"') { 1065 /* 1066 * Strip out the first and the last quote. 1067 */ 1068 dup[len - 1] = '\0'; 1069 nstr = dup + 1; 1070 } 1071 1072 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1073 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1074 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1075 scf_type_to_string(ty), nstr); 1076 scf_value_destroy(v); 1077 v = NULL; 1078 } 1079 free(dup); 1080 return (v); 1081 } 1082 1083 /* 1084 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1085 * Optionally append a comment prefix ('#') to newlines ('\n'). 1086 */ 1087 static int 1088 quote_and_print(const char *str, FILE *strm, int commentnl) 1089 { 1090 const char *cp; 1091 1092 for (cp = str; *cp != '\0'; ++cp) { 1093 if (*cp == '"' || *cp == '\\') 1094 (void) putc('\\', strm); 1095 1096 (void) putc(*cp, strm); 1097 1098 if (commentnl && *cp == '\n') { 1099 (void) putc('#', strm); 1100 } 1101 } 1102 1103 return (ferror(strm)); 1104 } 1105 1106 /* 1107 * These wrappers around lowlevel functions provide consistent error checking 1108 * and warnings. 1109 */ 1110 static int 1111 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1112 { 1113 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1114 return (0); 1115 1116 if (scf_error() != SCF_ERROR_NOT_FOUND) 1117 scfdie(); 1118 1119 if (g_verbose) { 1120 ssize_t len; 1121 char *fmri; 1122 1123 len = scf_pg_to_fmri(pg, NULL, 0); 1124 if (len < 0) 1125 scfdie(); 1126 1127 fmri = safe_malloc(len + 1); 1128 1129 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1130 scfdie(); 1131 1132 warn(gettext("Expected property %s of property group %s is " 1133 "missing.\n"), propname, fmri); 1134 1135 free(fmri); 1136 } 1137 1138 return (-1); 1139 } 1140 1141 static int 1142 prop_check_type(scf_property_t *prop, scf_type_t ty) 1143 { 1144 scf_type_t pty; 1145 1146 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1147 scfdie(); 1148 1149 if (ty == pty) 1150 return (0); 1151 1152 if (g_verbose) { 1153 ssize_t len; 1154 char *fmri; 1155 const char *tystr; 1156 1157 len = scf_property_to_fmri(prop, NULL, 0); 1158 if (len < 0) 1159 scfdie(); 1160 1161 fmri = safe_malloc(len + 1); 1162 1163 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1164 scfdie(); 1165 1166 tystr = scf_type_to_string(ty); 1167 if (tystr == NULL) 1168 tystr = "?"; 1169 1170 warn(gettext("Property %s is not of expected type %s.\n"), 1171 fmri, tystr); 1172 1173 free(fmri); 1174 } 1175 1176 return (-1); 1177 } 1178 1179 static int 1180 prop_get_val(scf_property_t *prop, scf_value_t *val) 1181 { 1182 scf_error_t err; 1183 1184 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1185 return (0); 1186 1187 err = scf_error(); 1188 1189 if (err != SCF_ERROR_NOT_FOUND && 1190 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1191 err != SCF_ERROR_PERMISSION_DENIED) 1192 scfdie(); 1193 1194 if (g_verbose) { 1195 ssize_t len; 1196 char *fmri, *emsg; 1197 1198 len = scf_property_to_fmri(prop, NULL, 0); 1199 if (len < 0) 1200 scfdie(); 1201 1202 fmri = safe_malloc(len + 1); 1203 1204 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1205 scfdie(); 1206 1207 if (err == SCF_ERROR_NOT_FOUND) 1208 emsg = gettext("Property %s has no values; expected " 1209 "one.\n"); 1210 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1211 emsg = gettext("Property %s has multiple values; " 1212 "expected one.\n"); 1213 else 1214 emsg = gettext("No permission to read property %s.\n"); 1215 1216 warn(emsg, fmri); 1217 1218 free(fmri); 1219 } 1220 1221 return (-1); 1222 } 1223 1224 1225 static boolean_t 1226 snaplevel_is_instance(const scf_snaplevel_t *level) 1227 { 1228 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1229 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1230 scfdie(); 1231 return (0); 1232 } else { 1233 return (1); 1234 } 1235 } 1236 1237 /* 1238 * Decode FMRI into a service or instance, and put the result in *ep. If 1239 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1240 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1241 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1242 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1243 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1244 * whether *ep is a service. 1245 */ 1246 static scf_error_t 1247 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1248 { 1249 char *fmri_copy; 1250 const char *sstr, *istr, *pgstr; 1251 scf_service_t *svc; 1252 scf_instance_t *inst; 1253 1254 fmri_copy = strdup(fmri); 1255 if (fmri_copy == NULL) 1256 return (SCF_ERROR_NO_MEMORY); 1257 1258 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1259 SCF_SUCCESS) { 1260 free(fmri_copy); 1261 return (SCF_ERROR_INVALID_ARGUMENT); 1262 } 1263 1264 free(fmri_copy); 1265 1266 if (sstr == NULL || pgstr != NULL) 1267 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1268 1269 if (istr == NULL) { 1270 svc = scf_service_create(h); 1271 if (svc == NULL) 1272 return (SCF_ERROR_NO_MEMORY); 1273 1274 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1275 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1276 if (scf_error() != SCF_ERROR_NOT_FOUND) 1277 scfdie(); 1278 1279 return (SCF_ERROR_NOT_FOUND); 1280 } 1281 1282 *ep = svc; 1283 *isservice = 1; 1284 } else { 1285 inst = scf_instance_create(h); 1286 if (inst == NULL) 1287 return (SCF_ERROR_NO_MEMORY); 1288 1289 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1290 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1291 if (scf_error() != SCF_ERROR_NOT_FOUND) 1292 scfdie(); 1293 1294 return (SCF_ERROR_NOT_FOUND); 1295 } 1296 1297 *ep = inst; 1298 *isservice = 0; 1299 } 1300 1301 return (SCF_ERROR_NONE); 1302 } 1303 1304 /* 1305 * Create the entity named by fmri. Place a pointer to its libscf handle in 1306 * *ep, and set or clear *isservicep if it is a service or an instance. 1307 * Returns 1308 * SCF_ERROR_NONE - success 1309 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1310 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1311 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1312 * SCF_ERROR_NOT_FOUND - no such scope 1313 * SCF_ERROR_PERMISSION_DENIED 1314 * SCF_ERROR_BACKEND_READONLY 1315 * SCF_ERROR_BACKEND_ACCESS 1316 */ 1317 static scf_error_t 1318 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1319 { 1320 char *fmri_copy; 1321 const char *scstr, *sstr, *istr, *pgstr; 1322 scf_scope_t *scope = NULL; 1323 scf_service_t *svc = NULL; 1324 scf_instance_t *inst = NULL; 1325 scf_error_t scfe; 1326 1327 fmri_copy = safe_strdup(fmri); 1328 1329 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1330 0) { 1331 free(fmri_copy); 1332 return (SCF_ERROR_INVALID_ARGUMENT); 1333 } 1334 1335 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1336 free(fmri_copy); 1337 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1338 } 1339 1340 *ep = NULL; 1341 1342 if ((scope = scf_scope_create(h)) == NULL || 1343 (svc = scf_service_create(h)) == NULL || 1344 (inst = scf_instance_create(h)) == NULL) { 1345 scfe = SCF_ERROR_NO_MEMORY; 1346 goto out; 1347 } 1348 1349 get_scope: 1350 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1351 switch (scf_error()) { 1352 case SCF_ERROR_CONNECTION_BROKEN: 1353 scfdie(); 1354 /* NOTREACHED */ 1355 1356 case SCF_ERROR_NOT_FOUND: 1357 scfe = SCF_ERROR_NOT_FOUND; 1358 goto out; 1359 1360 case SCF_ERROR_HANDLE_MISMATCH: 1361 case SCF_ERROR_NOT_BOUND: 1362 case SCF_ERROR_INVALID_ARGUMENT: 1363 default: 1364 bad_error("scf_handle_get_scope", scf_error()); 1365 } 1366 } 1367 1368 get_svc: 1369 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1370 switch (scf_error()) { 1371 case SCF_ERROR_CONNECTION_BROKEN: 1372 scfdie(); 1373 /* NOTREACHED */ 1374 1375 case SCF_ERROR_DELETED: 1376 goto get_scope; 1377 1378 case SCF_ERROR_NOT_FOUND: 1379 break; 1380 1381 case SCF_ERROR_HANDLE_MISMATCH: 1382 case SCF_ERROR_INVALID_ARGUMENT: 1383 case SCF_ERROR_NOT_BOUND: 1384 case SCF_ERROR_NOT_SET: 1385 default: 1386 bad_error("scf_scope_get_service", scf_error()); 1387 } 1388 1389 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1390 switch (scf_error()) { 1391 case SCF_ERROR_CONNECTION_BROKEN: 1392 scfdie(); 1393 /* NOTREACHED */ 1394 1395 case SCF_ERROR_DELETED: 1396 goto get_scope; 1397 1398 case SCF_ERROR_PERMISSION_DENIED: 1399 case SCF_ERROR_BACKEND_READONLY: 1400 case SCF_ERROR_BACKEND_ACCESS: 1401 scfe = scf_error(); 1402 goto out; 1403 1404 case SCF_ERROR_HANDLE_MISMATCH: 1405 case SCF_ERROR_INVALID_ARGUMENT: 1406 case SCF_ERROR_NOT_BOUND: 1407 case SCF_ERROR_NOT_SET: 1408 default: 1409 bad_error("scf_scope_get_service", scf_error()); 1410 } 1411 } 1412 } 1413 1414 if (istr == NULL) { 1415 scfe = SCF_ERROR_NONE; 1416 *ep = svc; 1417 *isservicep = 1; 1418 goto out; 1419 } 1420 1421 get_inst: 1422 if (scf_service_get_instance(svc, istr, inst) != 0) { 1423 switch (scf_error()) { 1424 case SCF_ERROR_CONNECTION_BROKEN: 1425 scfdie(); 1426 /* NOTREACHED */ 1427 1428 case SCF_ERROR_DELETED: 1429 goto get_svc; 1430 1431 case SCF_ERROR_NOT_FOUND: 1432 break; 1433 1434 case SCF_ERROR_HANDLE_MISMATCH: 1435 case SCF_ERROR_INVALID_ARGUMENT: 1436 case SCF_ERROR_NOT_BOUND: 1437 case SCF_ERROR_NOT_SET: 1438 default: 1439 bad_error("scf_service_get_instance", scf_error()); 1440 } 1441 1442 if (scf_service_add_instance(svc, istr, inst) != 0) { 1443 switch (scf_error()) { 1444 case SCF_ERROR_CONNECTION_BROKEN: 1445 scfdie(); 1446 /* NOTREACHED */ 1447 1448 case SCF_ERROR_DELETED: 1449 goto get_svc; 1450 1451 case SCF_ERROR_PERMISSION_DENIED: 1452 case SCF_ERROR_BACKEND_READONLY: 1453 case SCF_ERROR_BACKEND_ACCESS: 1454 scfe = scf_error(); 1455 goto out; 1456 1457 case SCF_ERROR_HANDLE_MISMATCH: 1458 case SCF_ERROR_INVALID_ARGUMENT: 1459 case SCF_ERROR_NOT_BOUND: 1460 case SCF_ERROR_NOT_SET: 1461 default: 1462 bad_error("scf_service_add_instance", 1463 scf_error()); 1464 } 1465 } 1466 } 1467 1468 scfe = SCF_ERROR_NONE; 1469 *ep = inst; 1470 *isservicep = 0; 1471 1472 out: 1473 if (*ep != inst) 1474 scf_instance_destroy(inst); 1475 if (*ep != svc) 1476 scf_service_destroy(svc); 1477 scf_scope_destroy(scope); 1478 free(fmri_copy); 1479 return (scfe); 1480 } 1481 1482 /* 1483 * Create or update a snapshot of inst. snap is a required scratch object. 1484 * 1485 * Returns 1486 * 0 - success 1487 * ECONNABORTED - repository connection broken 1488 * EPERM - permission denied 1489 * ENOSPC - configd is out of resources 1490 * ECANCELED - inst was deleted 1491 * -1 - unknown libscf error (message printed) 1492 */ 1493 static int 1494 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1495 { 1496 again: 1497 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1498 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1499 switch (scf_error()) { 1500 case SCF_ERROR_CONNECTION_BROKEN: 1501 case SCF_ERROR_PERMISSION_DENIED: 1502 case SCF_ERROR_NO_RESOURCES: 1503 return (scferror2errno(scf_error())); 1504 1505 case SCF_ERROR_NOT_SET: 1506 case SCF_ERROR_INVALID_ARGUMENT: 1507 default: 1508 bad_error("_scf_snapshot_take_attach", 1509 scf_error()); 1510 } 1511 } 1512 } else { 1513 switch (scf_error()) { 1514 case SCF_ERROR_NOT_FOUND: 1515 break; 1516 1517 case SCF_ERROR_DELETED: 1518 case SCF_ERROR_CONNECTION_BROKEN: 1519 return (scferror2errno(scf_error())); 1520 1521 case SCF_ERROR_HANDLE_MISMATCH: 1522 case SCF_ERROR_NOT_BOUND: 1523 case SCF_ERROR_INVALID_ARGUMENT: 1524 case SCF_ERROR_NOT_SET: 1525 default: 1526 bad_error("scf_instance_get_snapshot", scf_error()); 1527 } 1528 1529 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1530 switch (scf_error()) { 1531 case SCF_ERROR_EXISTS: 1532 goto again; 1533 1534 case SCF_ERROR_CONNECTION_BROKEN: 1535 case SCF_ERROR_NO_RESOURCES: 1536 case SCF_ERROR_PERMISSION_DENIED: 1537 return (scferror2errno(scf_error())); 1538 1539 default: 1540 scfwarn(); 1541 return (-1); 1542 1543 case SCF_ERROR_NOT_SET: 1544 case SCF_ERROR_INTERNAL: 1545 case SCF_ERROR_INVALID_ARGUMENT: 1546 case SCF_ERROR_HANDLE_MISMATCH: 1547 bad_error("_scf_snapshot_take_new", 1548 scf_error()); 1549 } 1550 } 1551 } 1552 1553 return (0); 1554 } 1555 1556 static int 1557 refresh_running_snapshot(void *entity) 1558 { 1559 scf_snapshot_t *snap; 1560 int r; 1561 1562 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1563 scfdie(); 1564 r = take_snap(entity, snap_running, snap); 1565 scf_snapshot_destroy(snap); 1566 1567 return (r); 1568 } 1569 1570 /* 1571 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1572 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1573 * instances. fmri is used for messages. inst, iter, and name_buf are used 1574 * for scratch space. Returns 1575 * 0 - success 1576 * ECONNABORTED - repository connection broken 1577 * ECANCELED - entity was deleted 1578 * EACCES - backend denied access 1579 * EPERM - permission denied 1580 * ENOSPC - repository server out of resources 1581 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1582 */ 1583 static int 1584 refresh_entity(int isservice, void *entity, const char *fmri, 1585 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1586 { 1587 scf_error_t scfe; 1588 int r; 1589 1590 if (!isservice) { 1591 /* 1592 * Let restarter handles refreshing and making new running 1593 * snapshot only if operating on a live repository and not 1594 * running in early import. 1595 */ 1596 if (est->sc_repo_filename == NULL && 1597 est->sc_repo_doorname == NULL && 1598 est->sc_in_emi == 0) { 1599 if (_smf_refresh_instance_i(entity) == 0) { 1600 if (g_verbose) 1601 warn(gettext("Refreshed %s.\n"), fmri); 1602 return (0); 1603 } 1604 1605 switch (scf_error()) { 1606 case SCF_ERROR_BACKEND_ACCESS: 1607 return (EACCES); 1608 1609 case SCF_ERROR_PERMISSION_DENIED: 1610 return (EPERM); 1611 1612 default: 1613 return (-1); 1614 } 1615 } else { 1616 r = refresh_running_snapshot(entity); 1617 switch (r) { 1618 case 0: 1619 break; 1620 1621 case ECONNABORTED: 1622 case ECANCELED: 1623 case EPERM: 1624 case ENOSPC: 1625 break; 1626 1627 default: 1628 bad_error("refresh_running_snapshot", 1629 scf_error()); 1630 } 1631 1632 return (r); 1633 } 1634 } 1635 1636 if (scf_iter_service_instances(iter, entity) != 0) { 1637 switch (scf_error()) { 1638 case SCF_ERROR_CONNECTION_BROKEN: 1639 return (ECONNABORTED); 1640 1641 case SCF_ERROR_DELETED: 1642 return (ECANCELED); 1643 1644 case SCF_ERROR_HANDLE_MISMATCH: 1645 case SCF_ERROR_NOT_BOUND: 1646 case SCF_ERROR_NOT_SET: 1647 default: 1648 bad_error("scf_iter_service_instances", scf_error()); 1649 } 1650 } 1651 1652 for (;;) { 1653 r = scf_iter_next_instance(iter, inst); 1654 if (r == 0) 1655 break; 1656 if (r != 1) { 1657 switch (scf_error()) { 1658 case SCF_ERROR_CONNECTION_BROKEN: 1659 return (ECONNABORTED); 1660 1661 case SCF_ERROR_DELETED: 1662 return (ECANCELED); 1663 1664 case SCF_ERROR_HANDLE_MISMATCH: 1665 case SCF_ERROR_NOT_BOUND: 1666 case SCF_ERROR_NOT_SET: 1667 case SCF_ERROR_INVALID_ARGUMENT: 1668 default: 1669 bad_error("scf_iter_next_instance", 1670 scf_error()); 1671 } 1672 } 1673 1674 /* 1675 * Similarly, just take a new running snapshot if operating on 1676 * a non-live repository or running during early import. 1677 */ 1678 if (est->sc_repo_filename != NULL || 1679 est->sc_repo_doorname != NULL || 1680 est->sc_in_emi == 1) { 1681 r = refresh_running_snapshot(inst); 1682 switch (r) { 1683 case 0: 1684 continue; 1685 1686 case ECONNABORTED: 1687 case ECANCELED: 1688 case EPERM: 1689 case ENOSPC: 1690 break; 1691 default: 1692 bad_error("refresh_running_snapshot", 1693 scf_error()); 1694 } 1695 1696 return (r); 1697 1698 } 1699 1700 if (_smf_refresh_instance_i(inst) == 0) { 1701 if (g_verbose) { 1702 if (scf_instance_get_name(inst, name_buf, 1703 max_scf_name_len + 1) < 0) 1704 (void) strcpy(name_buf, "?"); 1705 1706 warn(gettext("Refreshed %s:%s.\n"), 1707 fmri, name_buf); 1708 } 1709 } else { 1710 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1711 g_verbose) { 1712 scfe = scf_error(); 1713 1714 if (scf_instance_to_fmri(inst, name_buf, 1715 max_scf_name_len + 1) < 0) 1716 (void) strcpy(name_buf, "?"); 1717 1718 warn(gettext( 1719 "Refresh of %s:%s failed: %s.\n"), fmri, 1720 name_buf, scf_strerror(scfe)); 1721 } 1722 } 1723 } 1724 1725 return (0); 1726 } 1727 1728 static void 1729 private_refresh(void) 1730 { 1731 scf_instance_t *pinst = NULL; 1732 scf_iter_t *piter = NULL; 1733 ssize_t fmrilen; 1734 size_t bufsz; 1735 char *fmribuf; 1736 void *ent; 1737 int issvc; 1738 int r; 1739 1740 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1741 return; 1742 1743 assert(cur_svc != NULL); 1744 1745 bufsz = max_scf_fmri_len + 1; 1746 fmribuf = safe_malloc(bufsz); 1747 if (cur_inst) { 1748 issvc = 0; 1749 ent = cur_inst; 1750 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1751 } else { 1752 issvc = 1; 1753 ent = cur_svc; 1754 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1755 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1756 scfdie(); 1757 1758 if ((piter = scf_iter_create(g_hndl)) == NULL) 1759 scfdie(); 1760 } 1761 if (fmrilen < 0) { 1762 free(fmribuf); 1763 if (scf_error() != SCF_ERROR_DELETED) 1764 scfdie(); 1765 1766 warn(emsg_deleted); 1767 return; 1768 } 1769 assert(fmrilen < bufsz); 1770 1771 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1772 switch (r) { 1773 case 0: 1774 break; 1775 1776 case ECONNABORTED: 1777 warn(gettext("Could not refresh %s " 1778 "(repository connection broken).\n"), fmribuf); 1779 break; 1780 1781 case ECANCELED: 1782 warn(emsg_deleted); 1783 break; 1784 1785 case EPERM: 1786 warn(gettext("Could not refresh %s " 1787 "(permission denied).\n"), fmribuf); 1788 break; 1789 1790 case ENOSPC: 1791 warn(gettext("Could not refresh %s " 1792 "(repository server out of resources).\n"), 1793 fmribuf); 1794 break; 1795 1796 case EACCES: 1797 default: 1798 bad_error("refresh_entity", scf_error()); 1799 } 1800 1801 if (issvc) { 1802 scf_instance_destroy(pinst); 1803 scf_iter_destroy(piter); 1804 } 1805 1806 free(fmribuf); 1807 } 1808 1809 1810 static int 1811 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1812 { 1813 cbp->sc_err = scferror2errno(err); 1814 return (UU_WALK_ERROR); 1815 } 1816 1817 static int 1818 stash_scferror(scf_callback_t *cbp) 1819 { 1820 return (stash_scferror_err(cbp, scf_error())); 1821 } 1822 1823 static int select_inst(const char *); 1824 static int select_svc(const char *); 1825 1826 /* 1827 * Take a property that does not have a type and check to see if a type 1828 * exists or can be gleened from the current data. Set the type. 1829 * 1830 * Check the current level (instance) and then check the higher level 1831 * (service). This could be the case for adding a new property to 1832 * the instance that's going to "override" a service level property. 1833 * 1834 * For a property : 1835 * 1. Take the type from an existing property 1836 * 2. Take the type from a template entry 1837 * 1838 * If the type can not be found, then leave the type as is, and let the import 1839 * report the problem of the missing type. 1840 */ 1841 static int 1842 find_current_prop_type(void *p, void *g) 1843 { 1844 property_t *prop = p; 1845 scf_callback_t *lcb = g; 1846 pgroup_t *pg = NULL; 1847 1848 const char *fmri = NULL; 1849 char *lfmri = NULL; 1850 char *cur_selection = NULL; 1851 1852 scf_propertygroup_t *sc_pg = NULL; 1853 scf_property_t *sc_prop = NULL; 1854 scf_pg_tmpl_t *t_pg = NULL; 1855 scf_prop_tmpl_t *t_prop = NULL; 1856 scf_type_t prop_type; 1857 1858 value_t *vp; 1859 int issvc = lcb->sc_service; 1860 int r = UU_WALK_ERROR; 1861 1862 if (prop->sc_value_type != SCF_TYPE_INVALID) 1863 return (UU_WALK_NEXT); 1864 1865 t_prop = scf_tmpl_prop_create(g_hndl); 1866 sc_prop = scf_property_create(g_hndl); 1867 if (sc_prop == NULL || t_prop == NULL) { 1868 warn(gettext("Unable to create the property to attempt and " 1869 "find a missing type.\n")); 1870 1871 scf_property_destroy(sc_prop); 1872 scf_tmpl_prop_destroy(t_prop); 1873 1874 return (UU_WALK_ERROR); 1875 } 1876 1877 if (lcb->sc_flags == 1) { 1878 pg = lcb->sc_parent; 1879 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT); 1880 fmri = pg->sc_parent->sc_fmri; 1881 retry_pg: 1882 if (cur_svc && cur_selection == NULL) { 1883 cur_selection = safe_malloc(max_scf_fmri_len + 1); 1884 lscf_get_selection_str(cur_selection, 1885 max_scf_fmri_len + 1); 1886 1887 if (strcmp(cur_selection, fmri) != 0) { 1888 lscf_select(fmri); 1889 } else { 1890 free(cur_selection); 1891 cur_selection = NULL; 1892 } 1893 } else { 1894 lscf_select(fmri); 1895 } 1896 1897 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) { 1898 warn(gettext("Unable to create property group to " 1899 "find a missing property type.\n")); 1900 1901 goto out; 1902 } 1903 1904 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) { 1905 /* 1906 * If this is the sc_pg from the parent 1907 * let the caller clean up the sc_pg, 1908 * and just throw it away in this case. 1909 */ 1910 if (sc_pg != lcb->sc_parent) 1911 scf_pg_destroy(sc_pg); 1912 1913 sc_pg = NULL; 1914 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1915 warn(gettext("Unable to create template " 1916 "property group to find a property " 1917 "type.\n")); 1918 1919 goto out; 1920 } 1921 1922 if (scf_tmpl_get_by_pg_name(fmri, NULL, 1923 pg->sc_pgroup_name, NULL, t_pg, 1924 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) { 1925 /* 1926 * if instance get service and jump back 1927 */ 1928 scf_tmpl_pg_destroy(t_pg); 1929 t_pg = NULL; 1930 if (issvc == 0) { 1931 entity_t *e = pg->sc_parent->sc_parent; 1932 1933 fmri = e->sc_fmri; 1934 issvc = 1; 1935 goto retry_pg; 1936 } else { 1937 goto out; 1938 } 1939 } 1940 } 1941 } else { 1942 sc_pg = lcb->sc_parent; 1943 } 1944 1945 /* 1946 * Attempt to get the type from an existing property. If the property 1947 * cannot be found then attempt to get the type from a template entry 1948 * for the property. 1949 * 1950 * Finally, if at the instance level look at the service level. 1951 */ 1952 if (sc_pg != NULL && 1953 pg_get_prop(sc_pg, prop->sc_property_name, 1954 sc_prop) == SCF_SUCCESS && 1955 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) { 1956 prop->sc_value_type = prop_type; 1957 1958 /* 1959 * Found a type, update the value types and validate 1960 * the actual value against this type. 1961 */ 1962 for (vp = uu_list_first(prop->sc_property_values); 1963 vp != NULL; 1964 vp = uu_list_next(prop->sc_property_values, vp)) { 1965 vp->sc_type = prop->sc_value_type; 1966 lxml_store_value(vp, 0, NULL); 1967 } 1968 1969 r = UU_WALK_NEXT; 1970 goto out; 1971 } 1972 1973 /* 1974 * If we get here with t_pg set to NULL then we had to have 1975 * gotten an sc_pg but that sc_pg did not have the property 1976 * we are looking for. So if the t_pg is not null look up 1977 * the template entry for the property. 1978 * 1979 * If the t_pg is null then need to attempt to get a matching 1980 * template entry for the sc_pg, and see if there is a property 1981 * entry for that template entry. 1982 */ 1983 do_tmpl : 1984 if (t_pg != NULL && 1985 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name, 1986 t_prop, 0) == SCF_SUCCESS) { 1987 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) { 1988 prop->sc_value_type = prop_type; 1989 1990 /* 1991 * Found a type, update the value types and validate 1992 * the actual value against this type. 1993 */ 1994 for (vp = uu_list_first(prop->sc_property_values); 1995 vp != NULL; 1996 vp = uu_list_next(prop->sc_property_values, vp)) { 1997 vp->sc_type = prop->sc_value_type; 1998 lxml_store_value(vp, 0, NULL); 1999 } 2000 2001 r = UU_WALK_NEXT; 2002 goto out; 2003 } 2004 } else { 2005 if (t_pg == NULL && sc_pg) { 2006 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 2007 warn(gettext("Unable to create template " 2008 "property group to find a property " 2009 "type.\n")); 2010 2011 goto out; 2012 } 2013 2014 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) { 2015 scf_tmpl_pg_destroy(t_pg); 2016 t_pg = NULL; 2017 } else { 2018 goto do_tmpl; 2019 } 2020 } 2021 } 2022 2023 if (issvc == 0) { 2024 scf_instance_t *i; 2025 scf_service_t *s; 2026 2027 issvc = 1; 2028 if (lcb->sc_flags == 1) { 2029 entity_t *e = pg->sc_parent->sc_parent; 2030 2031 fmri = e->sc_fmri; 2032 goto retry_pg; 2033 } 2034 2035 /* 2036 * because lcb->sc_flags was not set then this means 2037 * the pg was not used and can be used here. 2038 */ 2039 if ((pg = internal_pgroup_new()) == NULL) { 2040 warn(gettext("Could not create internal property group " 2041 "to find a missing type.")); 2042 2043 goto out; 2044 } 2045 2046 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1); 2047 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name, 2048 max_scf_name_len + 1) < 0) 2049 goto out; 2050 2051 i = scf_instance_create(g_hndl); 2052 s = scf_service_create(g_hndl); 2053 if (i == NULL || s == NULL || 2054 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) { 2055 warn(gettext("Could not get a service for the instance " 2056 "to find a missing type.")); 2057 2058 goto out; 2059 } 2060 2061 /* 2062 * Check to see truly at the instance level. 2063 */ 2064 lfmri = safe_malloc(max_scf_fmri_len + 1); 2065 if (scf_instance_get_parent(i, s) == SCF_SUCCESS && 2066 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0) 2067 goto out; 2068 else 2069 fmri = (const char *)lfmri; 2070 2071 goto retry_pg; 2072 } 2073 2074 out : 2075 if (sc_pg != lcb->sc_parent) { 2076 scf_pg_destroy(sc_pg); 2077 } 2078 2079 /* 2080 * If this is true then the pg was allocated 2081 * here, and the name was set so need to free 2082 * the name and the pg. 2083 */ 2084 if (pg != NULL && pg != lcb->sc_parent) { 2085 free((char *)pg->sc_pgroup_name); 2086 internal_pgroup_free(pg); 2087 } 2088 2089 if (cur_selection) { 2090 lscf_select(cur_selection); 2091 free(cur_selection); 2092 } 2093 2094 scf_tmpl_pg_destroy(t_pg); 2095 scf_tmpl_prop_destroy(t_prop); 2096 scf_property_destroy(sc_prop); 2097 2098 if (r != UU_WALK_NEXT) 2099 warn(gettext("Could not find property type for \"%s\" " 2100 "from \"%s\"\n"), prop->sc_property_name, 2101 fmri != NULL ? fmri : lcb->sc_source_fmri); 2102 2103 free(lfmri); 2104 2105 return (r); 2106 } 2107 2108 /* 2109 * Take a property group that does not have a type and check to see if a type 2110 * exists or can be gleened from the current data. Set the type. 2111 * 2112 * Check the current level (instance) and then check the higher level 2113 * (service). This could be the case for adding a new property to 2114 * the instance that's going to "override" a service level property. 2115 * 2116 * For a property group 2117 * 1. Take the type from an existing property group 2118 * 2. Take the type from a template entry 2119 * 2120 * If the type can not be found, then leave the type as is, and let the import 2121 * report the problem of the missing type. 2122 */ 2123 static int 2124 find_current_pg_type(void *p, void *sori) 2125 { 2126 entity_t *si = sori; 2127 pgroup_t *pg = p; 2128 2129 const char *ofmri, *fmri; 2130 char *cur_selection = NULL; 2131 char *pg_type = NULL; 2132 2133 scf_propertygroup_t *sc_pg = NULL; 2134 scf_pg_tmpl_t *t_pg = NULL; 2135 2136 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2137 int r = UU_WALK_ERROR; 2138 2139 ofmri = fmri = si->sc_fmri; 2140 if (pg->sc_pgroup_type != NULL) { 2141 r = UU_WALK_NEXT; 2142 2143 goto out; 2144 } 2145 2146 sc_pg = scf_pg_create(g_hndl); 2147 if (sc_pg == NULL) { 2148 warn(gettext("Unable to create property group to attempt " 2149 "and find a missing type.\n")); 2150 2151 return (UU_WALK_ERROR); 2152 } 2153 2154 /* 2155 * Using get_pg() requires that the cur_svc/cur_inst be 2156 * via lscf_select. Need to preserve the current selection 2157 * if going to use lscf_select() to set up the cur_svc/cur_inst 2158 */ 2159 if (cur_svc) { 2160 cur_selection = safe_malloc(max_scf_fmri_len + 1); 2161 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1); 2162 } 2163 2164 /* 2165 * If the property group exists get the type, and set 2166 * the pgroup_t type of that type. 2167 * 2168 * If not the check for a template pg_pattern entry 2169 * and take the type from that. 2170 */ 2171 retry_svc: 2172 lscf_select(fmri); 2173 2174 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) { 2175 pg_type = safe_malloc(max_scf_pg_type_len + 1); 2176 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type, 2177 max_scf_pg_type_len + 1) != -1) { 2178 pg->sc_pgroup_type = pg_type; 2179 2180 r = UU_WALK_NEXT; 2181 goto out; 2182 } else { 2183 free(pg_type); 2184 } 2185 } else { 2186 if ((t_pg == NULL) && 2187 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) 2188 goto out; 2189 2190 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name, 2191 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS && 2192 scf_tmpl_pg_type(t_pg, &pg_type) != -1) { 2193 pg->sc_pgroup_type = pg_type; 2194 2195 r = UU_WALK_NEXT; 2196 goto out; 2197 } 2198 } 2199 2200 /* 2201 * If type is not found at the instance level then attempt to 2202 * find the type at the service level. 2203 */ 2204 if (!issvc) { 2205 si = si->sc_parent; 2206 fmri = si->sc_fmri; 2207 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2208 goto retry_svc; 2209 } 2210 2211 out : 2212 if (cur_selection) { 2213 lscf_select(cur_selection); 2214 free(cur_selection); 2215 } 2216 2217 /* 2218 * Now walk the properties of the property group to make sure that 2219 * all properties have the correct type and values are valid for 2220 * those types. 2221 */ 2222 if (r == UU_WALK_NEXT) { 2223 scf_callback_t cb; 2224 2225 cb.sc_service = issvc; 2226 cb.sc_source_fmri = ofmri; 2227 if (sc_pg != NULL) { 2228 cb.sc_parent = sc_pg; 2229 cb.sc_flags = 0; 2230 } else { 2231 cb.sc_parent = pg; 2232 cb.sc_flags = 1; 2233 } 2234 2235 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type, 2236 &cb, UU_DEFAULT) != 0) { 2237 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2238 bad_error("uu_list_walk", uu_error()); 2239 2240 r = UU_WALK_ERROR; 2241 } 2242 } else { 2243 warn(gettext("Could not find property group type for " 2244 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri); 2245 } 2246 2247 scf_tmpl_pg_destroy(t_pg); 2248 scf_pg_destroy(sc_pg); 2249 2250 return (r); 2251 } 2252 2253 /* 2254 * Import. These functions import a bundle into the repository. 2255 */ 2256 2257 /* 2258 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 2259 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 2260 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2261 * lcbdata->sc_err to 2262 * ENOMEM - out of memory 2263 * ECONNABORTED - repository connection broken 2264 * ECANCELED - sc_trans's property group was deleted 2265 * EINVAL - p's name is invalid (error printed) 2266 * - p has an invalid value (error printed) 2267 */ 2268 static int 2269 lscf_property_import(void *v, void *pvt) 2270 { 2271 property_t *p = v; 2272 scf_callback_t *lcbdata = pvt; 2273 value_t *vp; 2274 scf_transaction_t *trans = lcbdata->sc_trans; 2275 scf_transaction_entry_t *entr; 2276 scf_value_t *val; 2277 scf_type_t tp; 2278 2279 if ((lcbdata->sc_flags & SCI_NOENABLED || 2280 lcbdata->sc_flags & SCI_DELAYENABLE) && 2281 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 2282 lcbdata->sc_enable = p; 2283 return (UU_WALK_NEXT); 2284 } 2285 2286 entr = scf_entry_create(lcbdata->sc_handle); 2287 if (entr == NULL) { 2288 switch (scf_error()) { 2289 case SCF_ERROR_NO_MEMORY: 2290 return (stash_scferror(lcbdata)); 2291 2292 case SCF_ERROR_INVALID_ARGUMENT: 2293 default: 2294 bad_error("scf_entry_create", scf_error()); 2295 } 2296 } 2297 2298 tp = p->sc_value_type; 2299 2300 if (scf_transaction_property_new(trans, entr, 2301 p->sc_property_name, tp) != 0) { 2302 switch (scf_error()) { 2303 case SCF_ERROR_INVALID_ARGUMENT: 2304 semerr(emsg_invalid_prop_name, p->sc_property_name); 2305 scf_entry_destroy(entr); 2306 return (stash_scferror(lcbdata)); 2307 2308 case SCF_ERROR_EXISTS: 2309 break; 2310 2311 case SCF_ERROR_DELETED: 2312 case SCF_ERROR_CONNECTION_BROKEN: 2313 scf_entry_destroy(entr); 2314 return (stash_scferror(lcbdata)); 2315 2316 case SCF_ERROR_NOT_BOUND: 2317 case SCF_ERROR_HANDLE_MISMATCH: 2318 case SCF_ERROR_NOT_SET: 2319 default: 2320 bad_error("scf_transaction_property_new", scf_error()); 2321 } 2322 2323 if (scf_transaction_property_change_type(trans, entr, 2324 p->sc_property_name, tp) != 0) { 2325 switch (scf_error()) { 2326 case SCF_ERROR_DELETED: 2327 case SCF_ERROR_CONNECTION_BROKEN: 2328 scf_entry_destroy(entr); 2329 return (stash_scferror(lcbdata)); 2330 2331 case SCF_ERROR_INVALID_ARGUMENT: 2332 semerr(emsg_invalid_prop_name, 2333 p->sc_property_name); 2334 scf_entry_destroy(entr); 2335 return (stash_scferror(lcbdata)); 2336 2337 case SCF_ERROR_NOT_FOUND: 2338 case SCF_ERROR_NOT_SET: 2339 case SCF_ERROR_HANDLE_MISMATCH: 2340 case SCF_ERROR_NOT_BOUND: 2341 default: 2342 bad_error( 2343 "scf_transaction_property_change_type", 2344 scf_error()); 2345 } 2346 } 2347 } 2348 2349 for (vp = uu_list_first(p->sc_property_values); 2350 vp != NULL; 2351 vp = uu_list_next(p->sc_property_values, vp)) { 2352 val = scf_value_create(g_hndl); 2353 if (val == NULL) { 2354 switch (scf_error()) { 2355 case SCF_ERROR_NO_MEMORY: 2356 return (stash_scferror(lcbdata)); 2357 2358 case SCF_ERROR_INVALID_ARGUMENT: 2359 default: 2360 bad_error("scf_value_create", scf_error()); 2361 } 2362 } 2363 2364 switch (tp) { 2365 case SCF_TYPE_BOOLEAN: 2366 scf_value_set_boolean(val, vp->sc_u.sc_count); 2367 break; 2368 case SCF_TYPE_COUNT: 2369 scf_value_set_count(val, vp->sc_u.sc_count); 2370 break; 2371 case SCF_TYPE_INTEGER: 2372 scf_value_set_integer(val, vp->sc_u.sc_integer); 2373 break; 2374 default: 2375 assert(vp->sc_u.sc_string != NULL); 2376 if (scf_value_set_from_string(val, tp, 2377 vp->sc_u.sc_string) != 0) { 2378 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 2379 bad_error("scf_value_set_from_string", 2380 scf_error()); 2381 2382 warn(gettext("Value \"%s\" is not a valid " 2383 "%s.\n"), vp->sc_u.sc_string, 2384 scf_type_to_string(tp)); 2385 scf_value_destroy(val); 2386 return (stash_scferror(lcbdata)); 2387 } 2388 break; 2389 } 2390 2391 if (scf_entry_add_value(entr, val) != 0) 2392 bad_error("scf_entry_add_value", scf_error()); 2393 } 2394 2395 return (UU_WALK_NEXT); 2396 } 2397 2398 /* 2399 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 2400 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 2401 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 2402 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2403 * lcbdata->sc_err to 2404 * ECONNABORTED - repository connection broken 2405 * ENOMEM - out of memory 2406 * ENOSPC - svc.configd is out of resources 2407 * ECANCELED - sc_parent was deleted 2408 * EPERM - could not create property group (permission denied) (error printed) 2409 * - could not modify property group (permission denied) (error printed) 2410 * - could not delete property group (permission denied) (error printed) 2411 * EROFS - could not create property group (repository is read-only) 2412 * - could not delete property group (repository is read-only) 2413 * EACCES - could not create property group (backend access denied) 2414 * - could not delete property group (backend access denied) 2415 * EEXIST - could not create property group (already exists) 2416 * EINVAL - invalid property group name (error printed) 2417 * - invalid property name (error printed) 2418 * - invalid value (error printed) 2419 * EBUSY - new property group deleted (error printed) 2420 * - new property group changed (error printed) 2421 * - property group added (error printed) 2422 * - property group deleted (error printed) 2423 */ 2424 static int 2425 entity_pgroup_import(void *v, void *pvt) 2426 { 2427 pgroup_t *p = v; 2428 scf_callback_t cbdata; 2429 scf_callback_t *lcbdata = pvt; 2430 void *ent = lcbdata->sc_parent; 2431 int issvc = lcbdata->sc_service; 2432 int r; 2433 2434 const char * const pg_changed = gettext("%s changed unexpectedly " 2435 "(new property group \"%s\" changed).\n"); 2436 2437 /* Never import deleted property groups. */ 2438 if (p->sc_pgroup_delete) { 2439 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY && 2440 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) { 2441 goto delete_pg; 2442 } 2443 return (UU_WALK_NEXT); 2444 } 2445 2446 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 2447 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 2448 lcbdata->sc_general = p; 2449 return (UU_WALK_NEXT); 2450 } 2451 2452 add_pg: 2453 if (issvc) 2454 r = scf_service_add_pg(ent, p->sc_pgroup_name, 2455 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2456 else 2457 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 2458 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2459 if (r != 0) { 2460 switch (scf_error()) { 2461 case SCF_ERROR_DELETED: 2462 case SCF_ERROR_CONNECTION_BROKEN: 2463 case SCF_ERROR_BACKEND_READONLY: 2464 case SCF_ERROR_BACKEND_ACCESS: 2465 case SCF_ERROR_NO_RESOURCES: 2466 return (stash_scferror(lcbdata)); 2467 2468 case SCF_ERROR_EXISTS: 2469 if (lcbdata->sc_flags & SCI_FORCE) 2470 break; 2471 return (stash_scferror(lcbdata)); 2472 2473 case SCF_ERROR_INVALID_ARGUMENT: 2474 warn(emsg_fmri_invalid_pg_name_type, 2475 lcbdata->sc_source_fmri, 2476 p->sc_pgroup_name, p->sc_pgroup_type); 2477 return (stash_scferror(lcbdata)); 2478 2479 case SCF_ERROR_PERMISSION_DENIED: 2480 warn(emsg_pg_add_perm, p->sc_pgroup_name, 2481 lcbdata->sc_target_fmri); 2482 return (stash_scferror(lcbdata)); 2483 2484 case SCF_ERROR_NOT_BOUND: 2485 case SCF_ERROR_HANDLE_MISMATCH: 2486 case SCF_ERROR_NOT_SET: 2487 default: 2488 bad_error("scf_service_add_pg", scf_error()); 2489 } 2490 2491 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2492 switch (scf_error()) { 2493 case SCF_ERROR_CONNECTION_BROKEN: 2494 case SCF_ERROR_DELETED: 2495 return (stash_scferror(lcbdata)); 2496 2497 case SCF_ERROR_INVALID_ARGUMENT: 2498 warn(emsg_fmri_invalid_pg_name, 2499 lcbdata->sc_source_fmri, 2500 p->sc_pgroup_name); 2501 return (stash_scferror(lcbdata)); 2502 2503 case SCF_ERROR_NOT_FOUND: 2504 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2505 p->sc_pgroup_name); 2506 lcbdata->sc_err = EBUSY; 2507 return (UU_WALK_ERROR); 2508 2509 case SCF_ERROR_NOT_BOUND: 2510 case SCF_ERROR_HANDLE_MISMATCH: 2511 case SCF_ERROR_NOT_SET: 2512 default: 2513 bad_error("entity_get_pg", scf_error()); 2514 } 2515 } 2516 2517 if (lcbdata->sc_flags & SCI_KEEP) 2518 goto props; 2519 2520 delete_pg: 2521 if (scf_pg_delete(imp_pg) != 0) { 2522 switch (scf_error()) { 2523 case SCF_ERROR_DELETED: 2524 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2525 p->sc_pgroup_name); 2526 lcbdata->sc_err = EBUSY; 2527 return (UU_WALK_ERROR); 2528 2529 case SCF_ERROR_PERMISSION_DENIED: 2530 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2531 lcbdata->sc_target_fmri); 2532 return (stash_scferror(lcbdata)); 2533 2534 case SCF_ERROR_BACKEND_READONLY: 2535 case SCF_ERROR_BACKEND_ACCESS: 2536 case SCF_ERROR_CONNECTION_BROKEN: 2537 return (stash_scferror(lcbdata)); 2538 2539 case SCF_ERROR_NOT_SET: 2540 default: 2541 bad_error("scf_pg_delete", scf_error()); 2542 } 2543 } 2544 2545 if (p->sc_pgroup_delete) 2546 return (UU_WALK_NEXT); 2547 2548 goto add_pg; 2549 } 2550 2551 props: 2552 2553 /* 2554 * Add properties to property group, if any. 2555 */ 2556 cbdata.sc_handle = lcbdata->sc_handle; 2557 cbdata.sc_parent = imp_pg; 2558 cbdata.sc_flags = lcbdata->sc_flags; 2559 cbdata.sc_trans = imp_tx; 2560 cbdata.sc_enable = NULL; 2561 2562 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2563 switch (scf_error()) { 2564 case SCF_ERROR_BACKEND_ACCESS: 2565 case SCF_ERROR_BACKEND_READONLY: 2566 case SCF_ERROR_CONNECTION_BROKEN: 2567 return (stash_scferror(lcbdata)); 2568 2569 case SCF_ERROR_DELETED: 2570 warn(pg_changed, lcbdata->sc_target_fmri, 2571 p->sc_pgroup_name); 2572 lcbdata->sc_err = EBUSY; 2573 return (UU_WALK_ERROR); 2574 2575 case SCF_ERROR_PERMISSION_DENIED: 2576 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2577 lcbdata->sc_target_fmri); 2578 return (stash_scferror(lcbdata)); 2579 2580 case SCF_ERROR_NOT_BOUND: 2581 case SCF_ERROR_NOT_SET: 2582 case SCF_ERROR_IN_USE: 2583 case SCF_ERROR_HANDLE_MISMATCH: 2584 default: 2585 bad_error("scf_transaction_start", scf_error()); 2586 } 2587 } 2588 2589 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2590 UU_DEFAULT) != 0) { 2591 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2592 bad_error("uu_list_walk", uu_error()); 2593 scf_transaction_reset(imp_tx); 2594 2595 lcbdata->sc_err = cbdata.sc_err; 2596 if (cbdata.sc_err == ECANCELED) { 2597 warn(pg_changed, lcbdata->sc_target_fmri, 2598 p->sc_pgroup_name); 2599 lcbdata->sc_err = EBUSY; 2600 } 2601 return (UU_WALK_ERROR); 2602 } 2603 2604 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2605 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2606 2607 /* 2608 * take the snapshot running snapshot then 2609 * import the stored general/enable property 2610 */ 2611 r = take_snap(ent, snap_running, imp_rsnap); 2612 switch (r) { 2613 case 0: 2614 break; 2615 2616 case ECONNABORTED: 2617 warn(gettext("Could not take %s snapshot on import " 2618 "(repository connection broken).\n"), 2619 snap_running); 2620 lcbdata->sc_err = r; 2621 return (UU_WALK_ERROR); 2622 case ECANCELED: 2623 warn(emsg_deleted); 2624 lcbdata->sc_err = r; 2625 return (UU_WALK_ERROR); 2626 2627 case EPERM: 2628 warn(gettext("Could not take %s snapshot " 2629 "(permission denied).\n"), snap_running); 2630 lcbdata->sc_err = r; 2631 return (UU_WALK_ERROR); 2632 2633 case ENOSPC: 2634 warn(gettext("Could not take %s snapshot" 2635 "(repository server out of resources).\n"), 2636 snap_running); 2637 lcbdata->sc_err = r; 2638 return (UU_WALK_ERROR); 2639 2640 default: 2641 bad_error("take_snap", r); 2642 } 2643 2644 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2645 if (r != UU_WALK_NEXT) { 2646 if (r != UU_WALK_ERROR) 2647 bad_error("lscf_property_import", r); 2648 return (EINVAL); 2649 } 2650 } 2651 2652 r = scf_transaction_commit(imp_tx); 2653 switch (r) { 2654 case 1: 2655 r = UU_WALK_NEXT; 2656 break; 2657 2658 case 0: 2659 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2660 lcbdata->sc_err = EBUSY; 2661 r = UU_WALK_ERROR; 2662 break; 2663 2664 case -1: 2665 switch (scf_error()) { 2666 case SCF_ERROR_BACKEND_READONLY: 2667 case SCF_ERROR_BACKEND_ACCESS: 2668 case SCF_ERROR_CONNECTION_BROKEN: 2669 case SCF_ERROR_NO_RESOURCES: 2670 r = stash_scferror(lcbdata); 2671 break; 2672 2673 case SCF_ERROR_DELETED: 2674 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2675 p->sc_pgroup_name); 2676 lcbdata->sc_err = EBUSY; 2677 r = UU_WALK_ERROR; 2678 break; 2679 2680 case SCF_ERROR_PERMISSION_DENIED: 2681 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2682 lcbdata->sc_target_fmri); 2683 r = stash_scferror(lcbdata); 2684 break; 2685 2686 case SCF_ERROR_NOT_SET: 2687 case SCF_ERROR_INVALID_ARGUMENT: 2688 case SCF_ERROR_NOT_BOUND: 2689 default: 2690 bad_error("scf_transaction_commit", scf_error()); 2691 } 2692 break; 2693 2694 default: 2695 bad_error("scf_transaction_commit", r); 2696 } 2697 2698 scf_transaction_destroy_children(imp_tx); 2699 2700 return (r); 2701 } 2702 2703 /* 2704 * Returns 2705 * 0 - success 2706 * ECONNABORTED - repository connection broken 2707 * ENOMEM - out of memory 2708 * ENOSPC - svc.configd is out of resources 2709 * ECANCELED - inst was deleted 2710 * EPERM - could not create property group (permission denied) (error printed) 2711 * - could not modify property group (permission denied) (error printed) 2712 * EROFS - could not create property group (repository is read-only) 2713 * EACCES - could not create property group (backend access denied) 2714 * EEXIST - could not create property group (already exists) 2715 * EINVAL - invalid property group name (error printed) 2716 * - invalid property name (error printed) 2717 * - invalid value (error printed) 2718 * EBUSY - new property group changed (error printed) 2719 */ 2720 static int 2721 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2722 const entity_t *isvc, int flags) 2723 { 2724 scf_callback_t cbdata; 2725 2726 cbdata.sc_handle = scf_service_handle(svc); 2727 cbdata.sc_parent = svc; 2728 cbdata.sc_service = 1; 2729 cbdata.sc_general = 0; 2730 cbdata.sc_enable = 0; 2731 cbdata.sc_flags = flags; 2732 cbdata.sc_source_fmri = isvc->sc_fmri; 2733 cbdata.sc_target_fmri = target_fmri; 2734 2735 /* 2736 * If the op is set, then add the flag to the callback 2737 * flags for later use. 2738 */ 2739 if (isvc->sc_op != SVCCFG_OP_NONE) { 2740 switch (isvc->sc_op) { 2741 case SVCCFG_OP_IMPORT : 2742 cbdata.sc_flags |= SCI_OP_IMPORT; 2743 break; 2744 case SVCCFG_OP_APPLY : 2745 cbdata.sc_flags |= SCI_OP_APPLY; 2746 break; 2747 case SVCCFG_OP_RESTORE : 2748 cbdata.sc_flags |= SCI_OP_RESTORE; 2749 break; 2750 default : 2751 uu_die(gettext("lscf_import_service_pgs : " 2752 "Unknown op stored in the service entity\n")); 2753 2754 } 2755 } 2756 2757 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2758 UU_DEFAULT) != 0) { 2759 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2760 bad_error("uu_list_walk", uu_error()); 2761 2762 return (cbdata.sc_err); 2763 } 2764 2765 return (0); 2766 } 2767 2768 /* 2769 * Returns 2770 * 0 - success 2771 * ECONNABORTED - repository connection broken 2772 * ENOMEM - out of memory 2773 * ENOSPC - svc.configd is out of resources 2774 * ECANCELED - inst was deleted 2775 * EPERM - could not create property group (permission denied) (error printed) 2776 * - could not modify property group (permission denied) (error printed) 2777 * EROFS - could not create property group (repository is read-only) 2778 * EACCES - could not create property group (backend access denied) 2779 * EEXIST - could not create property group (already exists) 2780 * EINVAL - invalid property group name (error printed) 2781 * - invalid property name (error printed) 2782 * - invalid value (error printed) 2783 * EBUSY - new property group changed (error printed) 2784 */ 2785 static int 2786 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2787 const entity_t *iinst, int flags) 2788 { 2789 scf_callback_t cbdata; 2790 2791 cbdata.sc_handle = scf_instance_handle(inst); 2792 cbdata.sc_parent = inst; 2793 cbdata.sc_service = 0; 2794 cbdata.sc_general = NULL; 2795 cbdata.sc_enable = NULL; 2796 cbdata.sc_flags = flags; 2797 cbdata.sc_source_fmri = iinst->sc_fmri; 2798 cbdata.sc_target_fmri = target_fmri; 2799 2800 /* 2801 * If the op is set, then add the flag to the callback 2802 * flags for later use. 2803 */ 2804 if (iinst->sc_op != SVCCFG_OP_NONE) { 2805 switch (iinst->sc_op) { 2806 case SVCCFG_OP_IMPORT : 2807 cbdata.sc_flags |= SCI_OP_IMPORT; 2808 break; 2809 case SVCCFG_OP_APPLY : 2810 cbdata.sc_flags |= SCI_OP_APPLY; 2811 break; 2812 case SVCCFG_OP_RESTORE : 2813 cbdata.sc_flags |= SCI_OP_RESTORE; 2814 break; 2815 default : 2816 uu_die(gettext("lscf_import_instance_pgs : " 2817 "Unknown op stored in the instance entity\n")); 2818 } 2819 } 2820 2821 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2822 UU_DEFAULT) != 0) { 2823 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2824 bad_error("uu_list_walk", uu_error()); 2825 2826 return (cbdata.sc_err); 2827 } 2828 2829 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2830 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2831 /* 2832 * If importing with the SCI_NOENABLED flag then 2833 * skip the delay, but if not then add the delay 2834 * of the enable property. 2835 */ 2836 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2837 cbdata.sc_flags |= SCI_DELAYENABLE; 2838 } 2839 2840 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2841 != UU_WALK_NEXT) 2842 return (cbdata.sc_err); 2843 } 2844 2845 return (0); 2846 } 2847 2848 /* 2849 * Report the reasons why we can't upgrade pg2 to pg1. 2850 */ 2851 static void 2852 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2853 int new) 2854 { 2855 property_t *p1, *p2; 2856 2857 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2858 2859 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2860 return; 2861 2862 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2863 p1 != NULL; 2864 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2865 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2866 if (p2 != NULL) { 2867 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2868 new); 2869 continue; 2870 } 2871 2872 if (new) 2873 warn(gettext("Conflict upgrading %s (new property " 2874 "group \"%s\" is missing property \"%s\").\n"), 2875 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2876 else 2877 warn(gettext("Conflict upgrading %s (property " 2878 "\"%s/%s\" is missing).\n"), fmri, 2879 pg1->sc_pgroup_name, p1->sc_property_name); 2880 } 2881 2882 /* 2883 * Since pg1 should be from the manifest, any properties in pg2 which 2884 * aren't in pg1 shouldn't be reported as conflicts. 2885 */ 2886 } 2887 2888 /* 2889 * Add transaction entries to tx which will upgrade cur's pg according to old 2890 * & new. 2891 * 2892 * Returns 2893 * 0 - success 2894 * EINVAL - new has a property with an invalid name or value (message emitted) 2895 * ENOMEM - out of memory 2896 */ 2897 static int 2898 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2899 pgroup_t *cur, int speak, const char *fmri) 2900 { 2901 property_t *p, *new_p, *cur_p; 2902 scf_transaction_entry_t *e; 2903 int r; 2904 int is_general; 2905 int is_protected; 2906 2907 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2908 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2909 bad_error("uu_list_walk", uu_error()); 2910 2911 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2912 2913 for (p = uu_list_first(old->sc_pgroup_props); 2914 p != NULL; 2915 p = uu_list_next(old->sc_pgroup_props, p)) { 2916 /* p is a property in the old property group. */ 2917 2918 /* Protect live properties. */ 2919 is_protected = 0; 2920 if (is_general) { 2921 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2922 0 || 2923 strcmp(p->sc_property_name, 2924 SCF_PROPERTY_RESTARTER) == 0) 2925 is_protected = 1; 2926 } 2927 2928 /* Look for the same property in the new properties. */ 2929 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2930 if (new_p != NULL) { 2931 new_p->sc_seen = 1; 2932 2933 /* 2934 * If the new property is the same as the old, don't do 2935 * anything (leave any user customizations). 2936 */ 2937 if (prop_equal(p, new_p, NULL, NULL, 0)) 2938 continue; 2939 2940 if (new_p->sc_property_override) 2941 goto upgrade; 2942 } 2943 2944 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2945 if (cur_p == NULL) { 2946 /* 2947 * p has been deleted from the repository. If we were 2948 * going to delete it anyway, do nothing. Otherwise 2949 * report a conflict. 2950 */ 2951 if (new_p == NULL) 2952 continue; 2953 2954 if (is_protected) 2955 continue; 2956 2957 warn(gettext("Conflict upgrading %s " 2958 "(property \"%s/%s\" is missing).\n"), fmri, 2959 old->sc_pgroup_name, p->sc_property_name); 2960 continue; 2961 } 2962 2963 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2964 /* 2965 * Conflict. Don't warn if the property is already the 2966 * way we want it, though. 2967 */ 2968 if (is_protected) 2969 continue; 2970 2971 if (new_p == NULL) 2972 (void) prop_equal(p, cur_p, fmri, 2973 old->sc_pgroup_name, 0); 2974 else 2975 (void) prop_equal(cur_p, new_p, fmri, 2976 old->sc_pgroup_name, 0); 2977 continue; 2978 } 2979 2980 if (is_protected) { 2981 if (speak) 2982 warn(gettext("%s: Refusing to upgrade " 2983 "\"%s/%s\" (live property).\n"), fmri, 2984 old->sc_pgroup_name, p->sc_property_name); 2985 continue; 2986 } 2987 2988 upgrade: 2989 /* p hasn't been customized in the repository. Upgrade it. */ 2990 if (new_p == NULL) { 2991 /* p was deleted. Delete from cur if unchanged. */ 2992 if (speak) 2993 warn(gettext( 2994 "%s: Deleting property \"%s/%s\".\n"), 2995 fmri, old->sc_pgroup_name, 2996 p->sc_property_name); 2997 2998 e = scf_entry_create(g_hndl); 2999 if (e == NULL) 3000 return (ENOMEM); 3001 3002 if (scf_transaction_property_delete(tx, e, 3003 p->sc_property_name) != 0) { 3004 switch (scf_error()) { 3005 case SCF_ERROR_DELETED: 3006 scf_entry_destroy(e); 3007 return (ECANCELED); 3008 3009 case SCF_ERROR_CONNECTION_BROKEN: 3010 scf_entry_destroy(e); 3011 return (ECONNABORTED); 3012 3013 case SCF_ERROR_NOT_FOUND: 3014 /* 3015 * This can happen if cur is from the 3016 * running snapshot (and it differs 3017 * from the live properties). 3018 */ 3019 scf_entry_destroy(e); 3020 break; 3021 3022 case SCF_ERROR_HANDLE_MISMATCH: 3023 case SCF_ERROR_NOT_BOUND: 3024 case SCF_ERROR_NOT_SET: 3025 case SCF_ERROR_INVALID_ARGUMENT: 3026 default: 3027 bad_error( 3028 "scf_transaction_property_delete", 3029 scf_error()); 3030 } 3031 } 3032 } else { 3033 scf_callback_t ctx; 3034 3035 if (speak) 3036 warn(gettext( 3037 "%s: Upgrading property \"%s/%s\".\n"), 3038 fmri, old->sc_pgroup_name, 3039 p->sc_property_name); 3040 3041 ctx.sc_handle = g_hndl; 3042 ctx.sc_trans = tx; 3043 ctx.sc_flags = 0; 3044 3045 r = lscf_property_import(new_p, &ctx); 3046 if (r != UU_WALK_NEXT) { 3047 if (r != UU_WALK_ERROR) 3048 bad_error("lscf_property_import", r); 3049 return (EINVAL); 3050 } 3051 } 3052 } 3053 3054 /* Go over the properties which were added. */ 3055 for (new_p = uu_list_first(new->sc_pgroup_props); 3056 new_p != NULL; 3057 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 3058 if (new_p->sc_seen) 3059 continue; 3060 3061 /* This is a new property. */ 3062 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 3063 if (cur_p == NULL) { 3064 scf_callback_t ctx; 3065 3066 ctx.sc_handle = g_hndl; 3067 ctx.sc_trans = tx; 3068 ctx.sc_flags = 0; 3069 3070 r = lscf_property_import(new_p, &ctx); 3071 if (r != UU_WALK_NEXT) { 3072 if (r != UU_WALK_ERROR) 3073 bad_error("lscf_property_import", r); 3074 return (EINVAL); 3075 } 3076 continue; 3077 } 3078 3079 /* 3080 * Report a conflict if the new property differs from the 3081 * current one. Unless it's general/enabled, since that's 3082 * never in the last-import snapshot. 3083 */ 3084 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 3085 0 && 3086 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 3087 continue; 3088 3089 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 3090 } 3091 3092 return (0); 3093 } 3094 3095 /* 3096 * Upgrade pg according to old & new. 3097 * 3098 * Returns 3099 * 0 - success 3100 * ECONNABORTED - repository connection broken 3101 * ENOMEM - out of memory 3102 * ENOSPC - svc.configd is out of resources 3103 * ECANCELED - pg was deleted 3104 * EPERM - couldn't modify pg (permission denied) 3105 * EROFS - couldn't modify pg (backend read-only) 3106 * EACCES - couldn't modify pg (backend access denied) 3107 * EINVAL - new has a property with invalid name or value (error printed) 3108 * EBUSY - pg changed unexpectedly 3109 */ 3110 static int 3111 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 3112 pgroup_t *new, int speak, const char *fmri) 3113 { 3114 int r; 3115 3116 if (scf_transaction_start(imp_tx, pg) != 0) { 3117 switch (scf_error()) { 3118 case SCF_ERROR_CONNECTION_BROKEN: 3119 case SCF_ERROR_DELETED: 3120 case SCF_ERROR_PERMISSION_DENIED: 3121 case SCF_ERROR_BACKEND_READONLY: 3122 case SCF_ERROR_BACKEND_ACCESS: 3123 return (scferror2errno(scf_error())); 3124 3125 case SCF_ERROR_HANDLE_MISMATCH: 3126 case SCF_ERROR_IN_USE: 3127 case SCF_ERROR_NOT_BOUND: 3128 case SCF_ERROR_NOT_SET: 3129 default: 3130 bad_error("scf_transaction_start", scf_error()); 3131 } 3132 } 3133 3134 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 3135 switch (r) { 3136 case 0: 3137 break; 3138 3139 case EINVAL: 3140 case ENOMEM: 3141 scf_transaction_destroy_children(imp_tx); 3142 return (r); 3143 3144 default: 3145 bad_error("add_upgrade_entries", r); 3146 } 3147 3148 r = scf_transaction_commit(imp_tx); 3149 3150 scf_transaction_destroy_children(imp_tx); 3151 3152 switch (r) { 3153 case 1: 3154 break; 3155 3156 case 0: 3157 return (EBUSY); 3158 3159 case -1: 3160 switch (scf_error()) { 3161 case SCF_ERROR_CONNECTION_BROKEN: 3162 case SCF_ERROR_NO_RESOURCES: 3163 case SCF_ERROR_PERMISSION_DENIED: 3164 case SCF_ERROR_BACKEND_READONLY: 3165 case SCF_ERROR_BACKEND_ACCESS: 3166 case SCF_ERROR_DELETED: 3167 return (scferror2errno(scf_error())); 3168 3169 case SCF_ERROR_NOT_BOUND: 3170 case SCF_ERROR_INVALID_ARGUMENT: 3171 case SCF_ERROR_NOT_SET: 3172 default: 3173 bad_error("scf_transaction_commit", scf_error()); 3174 } 3175 3176 default: 3177 bad_error("scf_transaction_commit", r); 3178 } 3179 3180 return (0); 3181 } 3182 3183 /* 3184 * Compares two entity FMRIs. Returns 3185 * 3186 * 1 - equal 3187 * 0 - not equal 3188 * -1 - f1 is invalid or not an entity 3189 * -2 - f2 is invalid or not an entity 3190 */ 3191 static int 3192 fmri_equal(const char *f1, const char *f2) 3193 { 3194 int r; 3195 const char *s1, *i1, *pg1; 3196 const char *s2, *i2, *pg2; 3197 3198 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3199 return (-1); 3200 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 3201 return (-1); 3202 3203 if (s1 == NULL || pg1 != NULL) 3204 return (-1); 3205 3206 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3207 return (-2); 3208 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 3209 return (-2); 3210 3211 if (s2 == NULL || pg2 != NULL) 3212 return (-2); 3213 3214 r = strcmp(s1, s2); 3215 if (r != 0) 3216 return (0); 3217 3218 if (i1 == NULL && i2 == NULL) 3219 return (1); 3220 3221 if (i1 == NULL || i2 == NULL) 3222 return (0); 3223 3224 return (strcmp(i1, i2) == 0); 3225 } 3226 3227 /* 3228 * Import a dependent by creating a dependency property group in the dependent 3229 * entity. If lcbdata->sc_trans is set, assume it's been started on the 3230 * dependents pg, and add an entry to create a new property for this 3231 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 3232 * 3233 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 3234 * lcbdata->sc_err to 3235 * ECONNABORTED - repository connection broken 3236 * ENOMEM - out of memory 3237 * ENOSPC - configd is out of resources 3238 * EINVAL - target is invalid (error printed) 3239 * - target is not an entity (error printed) 3240 * - dependent has invalid name (error printed) 3241 * - invalid property name (error printed) 3242 * - invalid value (error printed) 3243 * - scope of target does not exist (error printed) 3244 * EPERM - couldn't create target (permission denied) (error printed) 3245 * - couldn't create dependency pg (permission denied) (error printed) 3246 * - couldn't modify dependency pg (permission denied) (error printed) 3247 * EROFS - couldn't create target (repository read-only) 3248 * - couldn't create dependency pg (repository read-only) 3249 * EACCES - couldn't create target (backend access denied) 3250 * - couldn't create dependency pg (backend access denied) 3251 * ECANCELED - sc_trans's pg was deleted 3252 * EALREADY - property for dependent already exists in sc_trans's pg 3253 * EEXIST - dependency pg already exists in target (error printed) 3254 * EBUSY - target deleted (error printed) 3255 * - property group changed during import (error printed) 3256 */ 3257 static int 3258 lscf_dependent_import(void *a1, void *pvt) 3259 { 3260 pgroup_t *pgrp = a1; 3261 scf_callback_t *lcbdata = pvt; 3262 3263 int isservice; 3264 int ret; 3265 scf_transaction_entry_t *e; 3266 scf_value_t *val; 3267 scf_callback_t dependent_cbdata; 3268 scf_error_t scfe; 3269 3270 /* 3271 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 3272 * it's invalid, we fail before modifying the repository. 3273 */ 3274 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3275 &dependent_cbdata.sc_parent, &isservice); 3276 switch (scfe) { 3277 case SCF_ERROR_NONE: 3278 break; 3279 3280 case SCF_ERROR_NO_MEMORY: 3281 return (stash_scferror_err(lcbdata, scfe)); 3282 3283 case SCF_ERROR_INVALID_ARGUMENT: 3284 semerr(gettext("The FMRI for the \"%s\" dependent is " 3285 "invalid.\n"), pgrp->sc_pgroup_name); 3286 return (stash_scferror_err(lcbdata, scfe)); 3287 3288 case SCF_ERROR_CONSTRAINT_VIOLATED: 3289 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 3290 "specifies neither a service nor an instance.\n"), 3291 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3292 return (stash_scferror_err(lcbdata, scfe)); 3293 3294 case SCF_ERROR_NOT_FOUND: 3295 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3296 &dependent_cbdata.sc_parent, &isservice); 3297 switch (scfe) { 3298 case SCF_ERROR_NONE: 3299 break; 3300 3301 case SCF_ERROR_NO_MEMORY: 3302 case SCF_ERROR_BACKEND_READONLY: 3303 case SCF_ERROR_BACKEND_ACCESS: 3304 return (stash_scferror_err(lcbdata, scfe)); 3305 3306 case SCF_ERROR_NOT_FOUND: 3307 semerr(gettext("The scope in FMRI \"%s\" for the " 3308 "\"%s\" dependent does not exist.\n"), 3309 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3310 lcbdata->sc_err = EINVAL; 3311 return (UU_WALK_ERROR); 3312 3313 case SCF_ERROR_PERMISSION_DENIED: 3314 warn(gettext( 3315 "Could not create %s (permission denied).\n"), 3316 pgrp->sc_pgroup_fmri); 3317 return (stash_scferror_err(lcbdata, scfe)); 3318 3319 case SCF_ERROR_INVALID_ARGUMENT: 3320 case SCF_ERROR_CONSTRAINT_VIOLATED: 3321 default: 3322 bad_error("create_entity", scfe); 3323 } 3324 break; 3325 3326 default: 3327 bad_error("fmri_to_entity", scfe); 3328 } 3329 3330 if (lcbdata->sc_trans != NULL) { 3331 e = scf_entry_create(lcbdata->sc_handle); 3332 if (e == NULL) { 3333 if (scf_error() != SCF_ERROR_NO_MEMORY) 3334 bad_error("scf_entry_create", scf_error()); 3335 3336 entity_destroy(dependent_cbdata.sc_parent, isservice); 3337 return (stash_scferror(lcbdata)); 3338 } 3339 3340 if (scf_transaction_property_new(lcbdata->sc_trans, e, 3341 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 3342 switch (scf_error()) { 3343 case SCF_ERROR_INVALID_ARGUMENT: 3344 warn(gettext("Dependent of %s has invalid name " 3345 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 3346 pgrp->sc_pgroup_name); 3347 /* FALLTHROUGH */ 3348 3349 case SCF_ERROR_DELETED: 3350 case SCF_ERROR_CONNECTION_BROKEN: 3351 scf_entry_destroy(e); 3352 entity_destroy(dependent_cbdata.sc_parent, 3353 isservice); 3354 return (stash_scferror(lcbdata)); 3355 3356 case SCF_ERROR_EXISTS: 3357 scf_entry_destroy(e); 3358 entity_destroy(dependent_cbdata.sc_parent, 3359 isservice); 3360 lcbdata->sc_err = EALREADY; 3361 return (UU_WALK_ERROR); 3362 3363 case SCF_ERROR_NOT_BOUND: 3364 case SCF_ERROR_HANDLE_MISMATCH: 3365 case SCF_ERROR_NOT_SET: 3366 default: 3367 bad_error("scf_transaction_property_new", 3368 scf_error()); 3369 } 3370 } 3371 3372 val = scf_value_create(lcbdata->sc_handle); 3373 if (val == NULL) { 3374 if (scf_error() != SCF_ERROR_NO_MEMORY) 3375 bad_error("scf_value_create", scf_error()); 3376 3377 entity_destroy(dependent_cbdata.sc_parent, isservice); 3378 return (stash_scferror(lcbdata)); 3379 } 3380 3381 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3382 pgrp->sc_pgroup_fmri) != 0) 3383 /* invalid should have been caught above */ 3384 bad_error("scf_value_set_from_string", scf_error()); 3385 3386 if (scf_entry_add_value(e, val) != 0) 3387 bad_error("scf_entry_add_value", scf_error()); 3388 } 3389 3390 /* Add the property group to the target entity. */ 3391 3392 dependent_cbdata.sc_handle = lcbdata->sc_handle; 3393 dependent_cbdata.sc_flags = lcbdata->sc_flags; 3394 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 3395 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 3396 3397 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 3398 3399 entity_destroy(dependent_cbdata.sc_parent, isservice); 3400 3401 if (ret == UU_WALK_NEXT) 3402 return (ret); 3403 3404 if (ret != UU_WALK_ERROR) 3405 bad_error("entity_pgroup_import", ret); 3406 3407 switch (dependent_cbdata.sc_err) { 3408 case ECANCELED: 3409 warn(gettext("%s deleted unexpectedly.\n"), 3410 pgrp->sc_pgroup_fmri); 3411 lcbdata->sc_err = EBUSY; 3412 break; 3413 3414 case EEXIST: 3415 warn(gettext("Could not create \"%s\" dependency in %s " 3416 "(already exists).\n"), pgrp->sc_pgroup_name, 3417 pgrp->sc_pgroup_fmri); 3418 /* FALLTHROUGH */ 3419 3420 default: 3421 lcbdata->sc_err = dependent_cbdata.sc_err; 3422 } 3423 3424 return (UU_WALK_ERROR); 3425 } 3426 3427 static int upgrade_dependent(const scf_property_t *, const entity_t *, 3428 const scf_snaplevel_t *, scf_transaction_t *); 3429 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 3430 const pgroup_t *); 3431 3432 /* 3433 * Upgrade uncustomized dependents of ent to those specified in ient. Read 3434 * the current dependent targets from running (the snaplevel of a running 3435 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 3436 * scf_instance_t * according to ient, otherwise). Draw the ancestral 3437 * dependent targets and dependency properties from li_dpts_pg (the 3438 * "dependents" property group in snpl) and snpl (the snaplevel which 3439 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 3440 * snpl doesn't have a "dependents" property group, and any dependents in ient 3441 * are new. 3442 * 3443 * Returns 3444 * 0 - success 3445 * ECONNABORTED - repository connection broken 3446 * ENOMEM - out of memory 3447 * ENOSPC - configd is out of resources 3448 * ECANCELED - ent was deleted 3449 * ENODEV - the entity containing li_dpts_pg was deleted 3450 * EPERM - could not modify dependents pg (permission denied) (error printed) 3451 * - couldn't upgrade dependent (permission denied) (error printed) 3452 * - couldn't create dependent (permission denied) (error printed) 3453 * EROFS - could not modify dependents pg (repository read-only) 3454 * - couldn't upgrade dependent (repository read-only) 3455 * - couldn't create dependent (repository read-only) 3456 * EACCES - could not modify dependents pg (backend access denied) 3457 * - could not upgrade dependent (backend access denied) 3458 * - could not create dependent (backend access denied) 3459 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 3460 * - dependent target deleted (error printed) 3461 * - dependent pg changed (error printed) 3462 * EINVAL - new dependent is invalid (error printed) 3463 * EBADF - snpl is corrupt (error printed) 3464 * - snpl has corrupt pg (error printed) 3465 * - dependency pg in target is corrupt (error printed) 3466 * - target has corrupt snapshot (error printed) 3467 * EEXIST - dependency pg already existed in target service (error printed) 3468 */ 3469 static int 3470 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 3471 const scf_snaplevel_t *snpl, const entity_t *ient, 3472 const scf_snaplevel_t *running, void *ent) 3473 { 3474 pgroup_t *new_dpt_pgroup; 3475 scf_callback_t cbdata; 3476 int r, unseen, tx_started = 0; 3477 int have_cur_depts; 3478 3479 const char * const dependents = "dependents"; 3480 3481 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3482 3483 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 3484 /* Nothing to do. */ 3485 return (0); 3486 3487 /* Fetch the current version of the "dependents" property group. */ 3488 have_cur_depts = 1; 3489 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 3490 switch (scf_error()) { 3491 case SCF_ERROR_NOT_FOUND: 3492 break; 3493 3494 case SCF_ERROR_DELETED: 3495 case SCF_ERROR_CONNECTION_BROKEN: 3496 return (scferror2errno(scf_error())); 3497 3498 case SCF_ERROR_NOT_SET: 3499 case SCF_ERROR_INVALID_ARGUMENT: 3500 case SCF_ERROR_HANDLE_MISMATCH: 3501 case SCF_ERROR_NOT_BOUND: 3502 default: 3503 bad_error("entity_get_pg", scf_error()); 3504 } 3505 3506 have_cur_depts = 0; 3507 } 3508 3509 /* Fetch the running version of the "dependents" property group. */ 3510 ud_run_dpts_pg_set = 0; 3511 if (running != NULL) 3512 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 3513 else 3514 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 3515 if (r == 0) { 3516 ud_run_dpts_pg_set = 1; 3517 } else { 3518 switch (scf_error()) { 3519 case SCF_ERROR_NOT_FOUND: 3520 break; 3521 3522 case SCF_ERROR_DELETED: 3523 case SCF_ERROR_CONNECTION_BROKEN: 3524 return (scferror2errno(scf_error())); 3525 3526 case SCF_ERROR_NOT_SET: 3527 case SCF_ERROR_INVALID_ARGUMENT: 3528 case SCF_ERROR_HANDLE_MISMATCH: 3529 case SCF_ERROR_NOT_BOUND: 3530 default: 3531 bad_error(running ? "scf_snaplevel_get_pg" : 3532 "entity_get_pg", scf_error()); 3533 } 3534 } 3535 3536 /* 3537 * Clear the seen fields of the dependents, so we can tell which ones 3538 * are new. 3539 */ 3540 if (uu_list_walk(ient->sc_dependents, clear_int, 3541 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3542 bad_error("uu_list_walk", uu_error()); 3543 3544 if (li_dpts_pg != NULL) { 3545 /* 3546 * Each property in li_dpts_pg represents a dependent tag in 3547 * the old manifest. For each, call upgrade_dependent(), 3548 * which will change ud_cur_depts_pg or dependencies in other 3549 * services as appropriate. Note (a) that changes to 3550 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3551 * made en masse, and (b) it's ok if the entity doesn't have 3552 * a current version of the "dependents" property group, 3553 * because we'll just consider all dependents as customized 3554 * (by being deleted). 3555 */ 3556 3557 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3558 switch (scf_error()) { 3559 case SCF_ERROR_DELETED: 3560 return (ENODEV); 3561 3562 case SCF_ERROR_CONNECTION_BROKEN: 3563 return (ECONNABORTED); 3564 3565 case SCF_ERROR_HANDLE_MISMATCH: 3566 case SCF_ERROR_NOT_BOUND: 3567 case SCF_ERROR_NOT_SET: 3568 default: 3569 bad_error("scf_iter_pg_properties", 3570 scf_error()); 3571 } 3572 } 3573 3574 if (have_cur_depts && 3575 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3576 switch (scf_error()) { 3577 case SCF_ERROR_BACKEND_ACCESS: 3578 case SCF_ERROR_BACKEND_READONLY: 3579 case SCF_ERROR_CONNECTION_BROKEN: 3580 return (scferror2errno(scf_error())); 3581 3582 case SCF_ERROR_DELETED: 3583 warn(emsg_pg_deleted, ient->sc_fmri, 3584 dependents); 3585 return (EBUSY); 3586 3587 case SCF_ERROR_PERMISSION_DENIED: 3588 warn(emsg_pg_mod_perm, dependents, 3589 ient->sc_fmri); 3590 return (scferror2errno(scf_error())); 3591 3592 case SCF_ERROR_HANDLE_MISMATCH: 3593 case SCF_ERROR_IN_USE: 3594 case SCF_ERROR_NOT_BOUND: 3595 case SCF_ERROR_NOT_SET: 3596 default: 3597 bad_error("scf_transaction_start", scf_error()); 3598 } 3599 } 3600 tx_started = have_cur_depts; 3601 3602 for (;;) { 3603 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3604 if (r == 0) 3605 break; 3606 if (r == 1) { 3607 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3608 tx_started ? ud_tx : NULL); 3609 switch (r) { 3610 case 0: 3611 continue; 3612 3613 case ECONNABORTED: 3614 case ENOMEM: 3615 case ENOSPC: 3616 case EBADF: 3617 case EBUSY: 3618 case EINVAL: 3619 case EPERM: 3620 case EROFS: 3621 case EACCES: 3622 case EEXIST: 3623 break; 3624 3625 case ECANCELED: 3626 r = ENODEV; 3627 break; 3628 3629 default: 3630 bad_error("upgrade_dependent", r); 3631 } 3632 3633 if (tx_started) 3634 scf_transaction_destroy_children(ud_tx); 3635 return (r); 3636 } 3637 if (r != -1) 3638 bad_error("scf_iter_next_property", r); 3639 3640 switch (scf_error()) { 3641 case SCF_ERROR_DELETED: 3642 r = ENODEV; 3643 break; 3644 3645 case SCF_ERROR_CONNECTION_BROKEN: 3646 r = ECONNABORTED; 3647 break; 3648 3649 case SCF_ERROR_NOT_SET: 3650 case SCF_ERROR_INVALID_ARGUMENT: 3651 case SCF_ERROR_NOT_BOUND: 3652 case SCF_ERROR_HANDLE_MISMATCH: 3653 default: 3654 bad_error("scf_iter_next_property", 3655 scf_error()); 3656 } 3657 3658 if (tx_started) 3659 scf_transaction_destroy_children(ud_tx); 3660 return (r); 3661 } 3662 } 3663 3664 /* import unseen dependents */ 3665 unseen = 0; 3666 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3667 new_dpt_pgroup != NULL; 3668 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3669 new_dpt_pgroup)) { 3670 if (!new_dpt_pgroup->sc_pgroup_seen) { 3671 unseen = 1; 3672 break; 3673 } 3674 } 3675 3676 /* If there are none, exit early. */ 3677 if (unseen == 0) 3678 goto commit; 3679 3680 /* Set up for lscf_dependent_import() */ 3681 cbdata.sc_handle = g_hndl; 3682 cbdata.sc_parent = ent; 3683 cbdata.sc_service = issvc; 3684 cbdata.sc_flags = 0; 3685 3686 if (!have_cur_depts) { 3687 /* 3688 * We have new dependents to import, so we need a "dependents" 3689 * property group. 3690 */ 3691 if (issvc) 3692 r = scf_service_add_pg(ent, dependents, 3693 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3694 else 3695 r = scf_instance_add_pg(ent, dependents, 3696 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3697 if (r != 0) { 3698 switch (scf_error()) { 3699 case SCF_ERROR_DELETED: 3700 case SCF_ERROR_CONNECTION_BROKEN: 3701 case SCF_ERROR_BACKEND_READONLY: 3702 case SCF_ERROR_BACKEND_ACCESS: 3703 case SCF_ERROR_NO_RESOURCES: 3704 return (scferror2errno(scf_error())); 3705 3706 case SCF_ERROR_EXISTS: 3707 warn(emsg_pg_added, ient->sc_fmri, dependents); 3708 return (EBUSY); 3709 3710 case SCF_ERROR_PERMISSION_DENIED: 3711 warn(emsg_pg_add_perm, dependents, 3712 ient->sc_fmri); 3713 return (scferror2errno(scf_error())); 3714 3715 case SCF_ERROR_NOT_BOUND: 3716 case SCF_ERROR_HANDLE_MISMATCH: 3717 case SCF_ERROR_INVALID_ARGUMENT: 3718 case SCF_ERROR_NOT_SET: 3719 default: 3720 bad_error("scf_service_add_pg", scf_error()); 3721 } 3722 } 3723 } 3724 3725 cbdata.sc_trans = ud_tx; 3726 3727 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3728 switch (scf_error()) { 3729 case SCF_ERROR_CONNECTION_BROKEN: 3730 case SCF_ERROR_BACKEND_ACCESS: 3731 case SCF_ERROR_BACKEND_READONLY: 3732 return (scferror2errno(scf_error())); 3733 3734 case SCF_ERROR_DELETED: 3735 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3736 return (EBUSY); 3737 3738 case SCF_ERROR_PERMISSION_DENIED: 3739 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3740 return (scferror2errno(scf_error())); 3741 3742 case SCF_ERROR_HANDLE_MISMATCH: 3743 case SCF_ERROR_IN_USE: 3744 case SCF_ERROR_NOT_BOUND: 3745 case SCF_ERROR_NOT_SET: 3746 default: 3747 bad_error("scf_transaction_start", scf_error()); 3748 } 3749 } 3750 tx_started = 1; 3751 3752 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3753 new_dpt_pgroup != NULL; 3754 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3755 new_dpt_pgroup)) { 3756 if (new_dpt_pgroup->sc_pgroup_seen) 3757 continue; 3758 3759 if (ud_run_dpts_pg_set) { 3760 /* 3761 * If the dependent is already there, then we have 3762 * a conflict. 3763 */ 3764 if (scf_pg_get_property(ud_run_dpts_pg, 3765 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3766 r = handle_dependent_conflict(ient, ud_prop, 3767 new_dpt_pgroup); 3768 switch (r) { 3769 case 0: 3770 continue; 3771 3772 case ECONNABORTED: 3773 case ENOMEM: 3774 case EBUSY: 3775 case EBADF: 3776 case EINVAL: 3777 scf_transaction_destroy_children(ud_tx); 3778 return (r); 3779 3780 default: 3781 bad_error("handle_dependent_conflict", 3782 r); 3783 } 3784 } else { 3785 switch (scf_error()) { 3786 case SCF_ERROR_NOT_FOUND: 3787 break; 3788 3789 case SCF_ERROR_INVALID_ARGUMENT: 3790 warn(emsg_fmri_invalid_pg_name, 3791 ient->sc_fmri, 3792 new_dpt_pgroup->sc_pgroup_name); 3793 scf_transaction_destroy_children(ud_tx); 3794 return (EINVAL); 3795 3796 case SCF_ERROR_DELETED: 3797 warn(emsg_pg_deleted, ient->sc_fmri, 3798 new_dpt_pgroup->sc_pgroup_name); 3799 scf_transaction_destroy_children(ud_tx); 3800 return (EBUSY); 3801 3802 case SCF_ERROR_CONNECTION_BROKEN: 3803 scf_transaction_destroy_children(ud_tx); 3804 return (ECONNABORTED); 3805 3806 case SCF_ERROR_NOT_BOUND: 3807 case SCF_ERROR_HANDLE_MISMATCH: 3808 case SCF_ERROR_NOT_SET: 3809 default: 3810 bad_error("scf_pg_get_property", 3811 scf_error()); 3812 } 3813 } 3814 } 3815 3816 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3817 if (r != UU_WALK_NEXT) { 3818 if (r != UU_WALK_ERROR) 3819 bad_error("lscf_dependent_import", r); 3820 3821 if (cbdata.sc_err == EALREADY) { 3822 /* Collisions were handled preemptively. */ 3823 bad_error("lscf_dependent_import", 3824 cbdata.sc_err); 3825 } 3826 3827 scf_transaction_destroy_children(ud_tx); 3828 return (cbdata.sc_err); 3829 } 3830 } 3831 3832 commit: 3833 if (!tx_started) 3834 return (0); 3835 3836 r = scf_transaction_commit(ud_tx); 3837 3838 scf_transaction_destroy_children(ud_tx); 3839 3840 switch (r) { 3841 case 1: 3842 return (0); 3843 3844 case 0: 3845 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3846 return (EBUSY); 3847 3848 case -1: 3849 break; 3850 3851 default: 3852 bad_error("scf_transaction_commit", r); 3853 } 3854 3855 switch (scf_error()) { 3856 case SCF_ERROR_CONNECTION_BROKEN: 3857 case SCF_ERROR_BACKEND_READONLY: 3858 case SCF_ERROR_BACKEND_ACCESS: 3859 case SCF_ERROR_NO_RESOURCES: 3860 return (scferror2errno(scf_error())); 3861 3862 case SCF_ERROR_DELETED: 3863 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3864 return (EBUSY); 3865 3866 case SCF_ERROR_PERMISSION_DENIED: 3867 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3868 return (scferror2errno(scf_error())); 3869 3870 case SCF_ERROR_NOT_BOUND: 3871 case SCF_ERROR_INVALID_ARGUMENT: 3872 case SCF_ERROR_NOT_SET: 3873 default: 3874 bad_error("scf_transaction_destroy", scf_error()); 3875 /* NOTREACHED */ 3876 } 3877 } 3878 3879 /* 3880 * Used to add the manifests to the list of currently supported manifests. 3881 * We can modify the existing manifest list removing entries if the files 3882 * don't exist. 3883 * 3884 * Get the old list and the new file name 3885 * If the new file name is in the list return 3886 * If not then add the file to the list. 3887 * As we process the list check to see if the files in the old list exist 3888 * if not then remove the file from the list. 3889 * Commit the list of manifest file names. 3890 * 3891 */ 3892 static int 3893 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient, 3894 const scf_snaplevel_t *running, void *ent) 3895 { 3896 scf_propertygroup_t *ud_mfsts_pg = NULL; 3897 scf_property_t *ud_prop = NULL; 3898 scf_iter_t *ud_prop_iter; 3899 scf_value_t *fname_value; 3900 scf_callback_t cbdata; 3901 pgroup_t *mfst_pgroup; 3902 property_t *mfst_prop; 3903 property_t *old_prop; 3904 char *pname; 3905 char *fval; 3906 char *old_pname; 3907 char *old_fval; 3908 int no_upgrade_pg; 3909 int mfst_seen; 3910 int r; 3911 3912 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3913 3914 /* 3915 * This should always be the service base on the code 3916 * path, and the fact that the manifests pg is a service 3917 * level property group only. 3918 */ 3919 ud_mfsts_pg = scf_pg_create(g_hndl); 3920 ud_prop = scf_property_create(g_hndl); 3921 ud_prop_iter = scf_iter_create(g_hndl); 3922 fname_value = scf_value_create(g_hndl); 3923 3924 /* Fetch the "manifests" property group */ 3925 no_upgrade_pg = 0; 3926 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3927 ud_mfsts_pg); 3928 if (r != 0) { 3929 switch (scf_error()) { 3930 case SCF_ERROR_NOT_FOUND: 3931 no_upgrade_pg = 1; 3932 break; 3933 3934 case SCF_ERROR_DELETED: 3935 case SCF_ERROR_CONNECTION_BROKEN: 3936 return (scferror2errno(scf_error())); 3937 3938 case SCF_ERROR_NOT_SET: 3939 case SCF_ERROR_INVALID_ARGUMENT: 3940 case SCF_ERROR_HANDLE_MISMATCH: 3941 case SCF_ERROR_NOT_BOUND: 3942 default: 3943 bad_error(running ? "scf_snaplevel_get_pg" : 3944 "entity_get_pg", scf_error()); 3945 } 3946 } 3947 3948 if (no_upgrade_pg) { 3949 cbdata.sc_handle = g_hndl; 3950 cbdata.sc_parent = ent; 3951 cbdata.sc_service = issvc; 3952 cbdata.sc_flags = SCI_FORCE; 3953 cbdata.sc_source_fmri = ient->sc_fmri; 3954 cbdata.sc_target_fmri = ient->sc_fmri; 3955 3956 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3957 return (cbdata.sc_err); 3958 3959 return (0); 3960 } 3961 3962 /* Fetch the new manifests property group */ 3963 for (mfst_pgroup = uu_list_first(ient->sc_pgroups); 3964 mfst_pgroup != NULL; 3965 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) { 3966 if (strcmp(mfst_pgroup->sc_pgroup_name, 3967 SCF_PG_MANIFESTFILES) == 0) 3968 break; 3969 } 3970 3971 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3972 SCF_SUCCESS) 3973 return (-1); 3974 3975 if ((pname = malloc(MAXPATHLEN)) == NULL) 3976 return (ENOMEM); 3977 if ((fval = malloc(MAXPATHLEN)) == NULL) { 3978 free(pname); 3979 return (ENOMEM); 3980 } 3981 3982 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 3983 mfst_seen = 0; 3984 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 3985 continue; 3986 3987 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3988 mfst_prop != NULL; 3989 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3990 mfst_prop)) { 3991 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3992 mfst_seen = 1; 3993 } 3994 } 3995 3996 /* 3997 * If the manifest is not seen then add it to the new mfst 3998 * property list to get proccessed into the repo. 3999 */ 4000 if (mfst_seen == 0) { 4001 /* 4002 * If we cannot get the value then there is no 4003 * reason to attempt to attach the value to 4004 * the property group 4005 */ 4006 if (prop_get_val(ud_prop, fname_value) == 0 && 4007 scf_value_get_astring(fname_value, fval, 4008 MAXPATHLEN) != -1) { 4009 old_pname = safe_strdup(pname); 4010 old_fval = safe_strdup(fval); 4011 old_prop = internal_property_create(old_pname, 4012 SCF_TYPE_ASTRING, 1, old_fval); 4013 4014 /* 4015 * Already checked to see if the property exists 4016 * in the group, and it does not. 4017 */ 4018 (void) internal_attach_property(mfst_pgroup, 4019 old_prop); 4020 } 4021 } 4022 } 4023 free(pname); 4024 free(fval); 4025 4026 cbdata.sc_handle = g_hndl; 4027 cbdata.sc_parent = ent; 4028 cbdata.sc_service = issvc; 4029 cbdata.sc_flags = SCI_FORCE; 4030 cbdata.sc_source_fmri = ient->sc_fmri; 4031 cbdata.sc_target_fmri = ient->sc_fmri; 4032 4033 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 4034 return (cbdata.sc_err); 4035 4036 return (r); 4037 } 4038 4039 /* 4040 * prop is taken to be a property in the "dependents" property group of snpl, 4041 * which is taken to be the snaplevel of a last-import snapshot corresponding 4042 * to ient. If prop is a valid dependents property, upgrade the dependent it 4043 * represents according to the repository & ient. If ud_run_dpts_pg_set is 4044 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 4045 * of the entity ient represents (possibly in the running snapshot). If it 4046 * needs to be changed, an entry will be added to tx, if not NULL. 4047 * 4048 * Returns 4049 * 0 - success 4050 * ECONNABORTED - repository connection broken 4051 * ENOMEM - out of memory 4052 * ENOSPC - configd was out of resources 4053 * ECANCELED - snpl's entity was deleted 4054 * EINVAL - dependent target is invalid (error printed) 4055 * - dependent is invalid (error printed) 4056 * EBADF - snpl is corrupt (error printed) 4057 * - snpl has corrupt pg (error printed) 4058 * - dependency pg in target is corrupt (error printed) 4059 * - running snapshot in dependent is missing snaplevel (error printed) 4060 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 4061 * - couldn't create dependent (permission denied) (error printed) 4062 * - couldn't modify dependent pg (permission denied) (error printed) 4063 * EROFS - couldn't delete dependency pg (repository read-only) 4064 * - couldn't create dependent (repository read-only) 4065 * EACCES - couldn't delete dependency pg (backend access denied) 4066 * - couldn't create dependent (backend access denied) 4067 * EBUSY - ud_run_dpts_pg was deleted (error printed) 4068 * - tx's pg was deleted (error printed) 4069 * - dependent pg was changed or deleted (error printed) 4070 * EEXIST - dependency pg already exists in new target (error printed) 4071 */ 4072 static int 4073 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 4074 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 4075 { 4076 pgroup_t pgrp; 4077 scf_type_t ty; 4078 pgroup_t *new_dpt_pgroup; 4079 pgroup_t *old_dpt_pgroup = NULL; 4080 pgroup_t *current_pg; 4081 pgroup_t *dpt; 4082 scf_callback_t cbdata; 4083 int tissvc; 4084 void *target_ent; 4085 scf_error_t serr; 4086 int r; 4087 scf_transaction_entry_t *ent; 4088 4089 const char * const cf_inval = gettext("Conflict upgrading %s " 4090 "(dependent \"%s\" has invalid dependents property).\n"); 4091 const char * const cf_missing = gettext("Conflict upgrading %s " 4092 "(dependent \"%s\" is missing).\n"); 4093 const char * const cf_newdpg = gettext("Conflict upgrading %s " 4094 "(dependent \"%s\" has new dependency property group).\n"); 4095 const char * const cf_newtarg = gettext("Conflict upgrading %s " 4096 "(dependent \"%s\" has new target).\n"); 4097 const char * const li_corrupt = 4098 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 4099 const char * const upgrading = 4100 gettext("%s: Upgrading dependent \"%s\".\n"); 4101 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 4102 "corrupt (missing snaplevel).\n"); 4103 4104 if (scf_property_type(prop, &ty) != 0) { 4105 switch (scf_error()) { 4106 case SCF_ERROR_DELETED: 4107 case SCF_ERROR_CONNECTION_BROKEN: 4108 return (scferror2errno(scf_error())); 4109 4110 case SCF_ERROR_NOT_BOUND: 4111 case SCF_ERROR_NOT_SET: 4112 default: 4113 bad_error("scf_property_type", scf_error()); 4114 } 4115 } 4116 4117 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4118 warn(li_corrupt, ient->sc_fmri); 4119 return (EBADF); 4120 } 4121 4122 /* 4123 * prop represents a dependent in the old manifest. It is named after 4124 * the dependent. 4125 */ 4126 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 4127 switch (scf_error()) { 4128 case SCF_ERROR_DELETED: 4129 case SCF_ERROR_CONNECTION_BROKEN: 4130 return (scferror2errno(scf_error())); 4131 4132 case SCF_ERROR_NOT_BOUND: 4133 case SCF_ERROR_NOT_SET: 4134 default: 4135 bad_error("scf_property_get_name", scf_error()); 4136 } 4137 } 4138 4139 /* See if it's in the new manifest. */ 4140 pgrp.sc_pgroup_name = ud_name; 4141 new_dpt_pgroup = 4142 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 4143 4144 /* If it's not, delete it... if it hasn't been customized. */ 4145 if (new_dpt_pgroup == NULL) { 4146 if (!ud_run_dpts_pg_set) 4147 return (0); 4148 4149 if (scf_property_get_value(prop, ud_val) != 0) { 4150 switch (scf_error()) { 4151 case SCF_ERROR_NOT_FOUND: 4152 case SCF_ERROR_CONSTRAINT_VIOLATED: 4153 warn(li_corrupt, ient->sc_fmri); 4154 return (EBADF); 4155 4156 case SCF_ERROR_DELETED: 4157 case SCF_ERROR_CONNECTION_BROKEN: 4158 return (scferror2errno(scf_error())); 4159 4160 case SCF_ERROR_HANDLE_MISMATCH: 4161 case SCF_ERROR_NOT_BOUND: 4162 case SCF_ERROR_NOT_SET: 4163 case SCF_ERROR_PERMISSION_DENIED: 4164 default: 4165 bad_error("scf_property_get_value", 4166 scf_error()); 4167 } 4168 } 4169 4170 if (scf_value_get_as_string(ud_val, ud_oldtarg, 4171 max_scf_value_len + 1) < 0) 4172 bad_error("scf_value_get_as_string", scf_error()); 4173 4174 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 4175 0) { 4176 switch (scf_error()) { 4177 case SCF_ERROR_NOT_FOUND: 4178 return (0); 4179 4180 case SCF_ERROR_CONNECTION_BROKEN: 4181 return (scferror2errno(scf_error())); 4182 4183 case SCF_ERROR_DELETED: 4184 warn(emsg_pg_deleted, ient->sc_fmri, 4185 "dependents"); 4186 return (EBUSY); 4187 4188 case SCF_ERROR_INVALID_ARGUMENT: 4189 case SCF_ERROR_NOT_BOUND: 4190 case SCF_ERROR_HANDLE_MISMATCH: 4191 case SCF_ERROR_NOT_SET: 4192 default: 4193 bad_error("scf_pg_get_property", scf_error()); 4194 } 4195 } 4196 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4197 switch (scf_error()) { 4198 case SCF_ERROR_NOT_FOUND: 4199 case SCF_ERROR_CONSTRAINT_VIOLATED: 4200 warn(cf_inval, ient->sc_fmri, ud_name); 4201 return (0); 4202 4203 case SCF_ERROR_DELETED: 4204 case SCF_ERROR_CONNECTION_BROKEN: 4205 return (scferror2errno(scf_error())); 4206 4207 case SCF_ERROR_HANDLE_MISMATCH: 4208 case SCF_ERROR_NOT_BOUND: 4209 case SCF_ERROR_NOT_SET: 4210 case SCF_ERROR_PERMISSION_DENIED: 4211 default: 4212 bad_error("scf_property_get_value", 4213 scf_error()); 4214 } 4215 } 4216 4217 ty = scf_value_type(ud_val); 4218 assert(ty != SCF_TYPE_INVALID); 4219 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4220 warn(cf_inval, ient->sc_fmri, ud_name); 4221 return (0); 4222 } 4223 4224 if (scf_value_get_as_string(ud_val, ud_ctarg, 4225 max_scf_value_len + 1) < 0) 4226 bad_error("scf_value_get_as_string", scf_error()); 4227 4228 r = fmri_equal(ud_ctarg, ud_oldtarg); 4229 switch (r) { 4230 case 1: 4231 break; 4232 4233 case 0: 4234 case -1: /* warn? */ 4235 warn(cf_newtarg, ient->sc_fmri, ud_name); 4236 return (0); 4237 4238 case -2: 4239 warn(li_corrupt, ient->sc_fmri); 4240 return (EBADF); 4241 4242 default: 4243 bad_error("fmri_equal", r); 4244 } 4245 4246 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4247 switch (scf_error()) { 4248 case SCF_ERROR_NOT_FOUND: 4249 warn(li_corrupt, ient->sc_fmri); 4250 return (EBADF); 4251 4252 case SCF_ERROR_DELETED: 4253 case SCF_ERROR_CONNECTION_BROKEN: 4254 return (scferror2errno(scf_error())); 4255 4256 case SCF_ERROR_NOT_BOUND: 4257 case SCF_ERROR_HANDLE_MISMATCH: 4258 case SCF_ERROR_INVALID_ARGUMENT: 4259 case SCF_ERROR_NOT_SET: 4260 default: 4261 bad_error("scf_snaplevel_get_pg", scf_error()); 4262 } 4263 } 4264 4265 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4266 snap_lastimport); 4267 switch (r) { 4268 case 0: 4269 break; 4270 4271 case ECANCELED: 4272 case ECONNABORTED: 4273 case ENOMEM: 4274 case EBADF: 4275 return (r); 4276 4277 case EACCES: 4278 default: 4279 bad_error("load_pg", r); 4280 } 4281 4282 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4283 switch (serr) { 4284 case SCF_ERROR_NONE: 4285 break; 4286 4287 case SCF_ERROR_NO_MEMORY: 4288 internal_pgroup_free(old_dpt_pgroup); 4289 return (ENOMEM); 4290 4291 case SCF_ERROR_NOT_FOUND: 4292 internal_pgroup_free(old_dpt_pgroup); 4293 goto delprop; 4294 4295 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 4296 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 4297 default: 4298 bad_error("fmri_to_entity", serr); 4299 } 4300 4301 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4302 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4303 switch (r) { 4304 case 0: 4305 break; 4306 4307 case ECONNABORTED: 4308 internal_pgroup_free(old_dpt_pgroup); 4309 return (r); 4310 4311 case ECANCELED: 4312 case ENOENT: 4313 internal_pgroup_free(old_dpt_pgroup); 4314 goto delprop; 4315 4316 case EBADF: 4317 warn(r_no_lvl, ud_ctarg); 4318 internal_pgroup_free(old_dpt_pgroup); 4319 return (r); 4320 4321 case EINVAL: 4322 default: 4323 bad_error("entity_get_running_pg", r); 4324 } 4325 4326 /* load it */ 4327 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4328 switch (r) { 4329 case 0: 4330 break; 4331 4332 case ECANCELED: 4333 internal_pgroup_free(old_dpt_pgroup); 4334 goto delprop; 4335 4336 case ECONNABORTED: 4337 case ENOMEM: 4338 case EBADF: 4339 internal_pgroup_free(old_dpt_pgroup); 4340 return (r); 4341 4342 case EACCES: 4343 default: 4344 bad_error("load_pg", r); 4345 } 4346 4347 /* compare property groups */ 4348 if (!pg_equal(old_dpt_pgroup, current_pg)) { 4349 warn(cf_newdpg, ient->sc_fmri, ud_name); 4350 internal_pgroup_free(old_dpt_pgroup); 4351 internal_pgroup_free(current_pg); 4352 return (0); 4353 } 4354 4355 internal_pgroup_free(old_dpt_pgroup); 4356 internal_pgroup_free(current_pg); 4357 4358 if (g_verbose) 4359 warn(gettext("%s: Deleting dependent \"%s\".\n"), 4360 ient->sc_fmri, ud_name); 4361 4362 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4363 switch (scf_error()) { 4364 case SCF_ERROR_NOT_FOUND: 4365 case SCF_ERROR_DELETED: 4366 internal_pgroup_free(old_dpt_pgroup); 4367 goto delprop; 4368 4369 case SCF_ERROR_CONNECTION_BROKEN: 4370 internal_pgroup_free(old_dpt_pgroup); 4371 return (ECONNABORTED); 4372 4373 case SCF_ERROR_NOT_SET: 4374 case SCF_ERROR_INVALID_ARGUMENT: 4375 case SCF_ERROR_HANDLE_MISMATCH: 4376 case SCF_ERROR_NOT_BOUND: 4377 default: 4378 bad_error("entity_get_pg", scf_error()); 4379 } 4380 } 4381 4382 if (scf_pg_delete(ud_pg) != 0) { 4383 switch (scf_error()) { 4384 case SCF_ERROR_DELETED: 4385 break; 4386 4387 case SCF_ERROR_CONNECTION_BROKEN: 4388 case SCF_ERROR_BACKEND_READONLY: 4389 case SCF_ERROR_BACKEND_ACCESS: 4390 return (scferror2errno(scf_error())); 4391 4392 case SCF_ERROR_PERMISSION_DENIED: 4393 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4394 return (scferror2errno(scf_error())); 4395 4396 case SCF_ERROR_NOT_SET: 4397 default: 4398 bad_error("scf_pg_delete", scf_error()); 4399 } 4400 } 4401 4402 /* 4403 * This service was changed, so it must be refreshed. But 4404 * since it's not mentioned in the new manifest, we have to 4405 * record its FMRI here for use later. We record the name 4406 * & the entity (via sc_parent) in case we need to print error 4407 * messages during the refresh. 4408 */ 4409 dpt = internal_pgroup_new(); 4410 if (dpt == NULL) 4411 return (ENOMEM); 4412 dpt->sc_pgroup_name = strdup(ud_name); 4413 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 4414 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4415 return (ENOMEM); 4416 dpt->sc_parent = (entity_t *)ient; 4417 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4418 uu_die(gettext("libuutil error: %s\n"), 4419 uu_strerror(uu_error())); 4420 4421 delprop: 4422 if (tx == NULL) 4423 return (0); 4424 4425 ent = scf_entry_create(g_hndl); 4426 if (ent == NULL) 4427 return (ENOMEM); 4428 4429 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 4430 scf_entry_destroy(ent); 4431 switch (scf_error()) { 4432 case SCF_ERROR_DELETED: 4433 warn(emsg_pg_deleted, ient->sc_fmri, 4434 "dependents"); 4435 return (EBUSY); 4436 4437 case SCF_ERROR_CONNECTION_BROKEN: 4438 return (scferror2errno(scf_error())); 4439 4440 case SCF_ERROR_NOT_FOUND: 4441 break; 4442 4443 case SCF_ERROR_HANDLE_MISMATCH: 4444 case SCF_ERROR_NOT_BOUND: 4445 case SCF_ERROR_INVALID_ARGUMENT: 4446 case SCF_ERROR_NOT_SET: 4447 default: 4448 bad_error("scf_transaction_property_delete", 4449 scf_error()); 4450 } 4451 } 4452 4453 return (0); 4454 } 4455 4456 new_dpt_pgroup->sc_pgroup_seen = 1; 4457 4458 /* 4459 * Decide whether the dependent has changed in the manifest. 4460 */ 4461 /* Compare the target. */ 4462 if (scf_property_get_value(prop, ud_val) != 0) { 4463 switch (scf_error()) { 4464 case SCF_ERROR_NOT_FOUND: 4465 case SCF_ERROR_CONSTRAINT_VIOLATED: 4466 warn(li_corrupt, ient->sc_fmri); 4467 return (EBADF); 4468 4469 case SCF_ERROR_DELETED: 4470 case SCF_ERROR_CONNECTION_BROKEN: 4471 return (scferror2errno(scf_error())); 4472 4473 case SCF_ERROR_HANDLE_MISMATCH: 4474 case SCF_ERROR_NOT_BOUND: 4475 case SCF_ERROR_NOT_SET: 4476 case SCF_ERROR_PERMISSION_DENIED: 4477 default: 4478 bad_error("scf_property_get_value", scf_error()); 4479 } 4480 } 4481 4482 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 4483 0) 4484 bad_error("scf_value_get_as_string", scf_error()); 4485 4486 /* 4487 * If the fmri's are not equal then the old fmri will need to 4488 * be refreshed to ensure that the changes are properly updated 4489 * in that service. 4490 */ 4491 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 4492 switch (r) { 4493 case 0: 4494 dpt = internal_pgroup_new(); 4495 if (dpt == NULL) 4496 return (ENOMEM); 4497 dpt->sc_pgroup_name = strdup(ud_name); 4498 dpt->sc_pgroup_fmri = strdup(ud_oldtarg); 4499 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4500 return (ENOMEM); 4501 dpt->sc_parent = (entity_t *)ient; 4502 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4503 uu_die(gettext("libuutil error: %s\n"), 4504 uu_strerror(uu_error())); 4505 break; 4506 4507 case 1: 4508 /* Compare the dependency pgs. */ 4509 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4510 switch (scf_error()) { 4511 case SCF_ERROR_NOT_FOUND: 4512 warn(li_corrupt, ient->sc_fmri); 4513 return (EBADF); 4514 4515 case SCF_ERROR_DELETED: 4516 case SCF_ERROR_CONNECTION_BROKEN: 4517 return (scferror2errno(scf_error())); 4518 4519 case SCF_ERROR_NOT_BOUND: 4520 case SCF_ERROR_HANDLE_MISMATCH: 4521 case SCF_ERROR_INVALID_ARGUMENT: 4522 case SCF_ERROR_NOT_SET: 4523 default: 4524 bad_error("scf_snaplevel_get_pg", scf_error()); 4525 } 4526 } 4527 4528 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4529 snap_lastimport); 4530 switch (r) { 4531 case 0: 4532 break; 4533 4534 case ECANCELED: 4535 case ECONNABORTED: 4536 case ENOMEM: 4537 case EBADF: 4538 return (r); 4539 4540 case EACCES: 4541 default: 4542 bad_error("load_pg", r); 4543 } 4544 4545 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4546 /* no change, leave customizations */ 4547 internal_pgroup_free(old_dpt_pgroup); 4548 return (0); 4549 } 4550 break; 4551 4552 case -1: 4553 warn(li_corrupt, ient->sc_fmri); 4554 return (EBADF); 4555 4556 case -2: 4557 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4558 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4559 return (EINVAL); 4560 4561 default: 4562 bad_error("fmri_equal", r); 4563 } 4564 4565 /* 4566 * The dependent has changed in the manifest. Upgrade the current 4567 * properties if they haven't been customized. 4568 */ 4569 4570 /* 4571 * If new_dpt_pgroup->sc_override, then act as though the property 4572 * group hasn't been customized. 4573 */ 4574 if (new_dpt_pgroup->sc_pgroup_override) { 4575 (void) strcpy(ud_ctarg, ud_oldtarg); 4576 goto nocust; 4577 } 4578 4579 if (!ud_run_dpts_pg_set) { 4580 warn(cf_missing, ient->sc_fmri, ud_name); 4581 r = 0; 4582 goto out; 4583 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4584 switch (scf_error()) { 4585 case SCF_ERROR_NOT_FOUND: 4586 warn(cf_missing, ient->sc_fmri, ud_name); 4587 r = 0; 4588 goto out; 4589 4590 case SCF_ERROR_CONNECTION_BROKEN: 4591 r = scferror2errno(scf_error()); 4592 goto out; 4593 4594 case SCF_ERROR_DELETED: 4595 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4596 r = EBUSY; 4597 goto out; 4598 4599 case SCF_ERROR_INVALID_ARGUMENT: 4600 case SCF_ERROR_NOT_BOUND: 4601 case SCF_ERROR_HANDLE_MISMATCH: 4602 case SCF_ERROR_NOT_SET: 4603 default: 4604 bad_error("scf_pg_get_property", scf_error()); 4605 } 4606 } 4607 4608 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4609 switch (scf_error()) { 4610 case SCF_ERROR_NOT_FOUND: 4611 case SCF_ERROR_CONSTRAINT_VIOLATED: 4612 warn(cf_inval, ient->sc_fmri, ud_name); 4613 r = 0; 4614 goto out; 4615 4616 case SCF_ERROR_DELETED: 4617 case SCF_ERROR_CONNECTION_BROKEN: 4618 r = scferror2errno(scf_error()); 4619 goto out; 4620 4621 case SCF_ERROR_HANDLE_MISMATCH: 4622 case SCF_ERROR_NOT_BOUND: 4623 case SCF_ERROR_NOT_SET: 4624 case SCF_ERROR_PERMISSION_DENIED: 4625 default: 4626 bad_error("scf_property_get_value", scf_error()); 4627 } 4628 } 4629 4630 ty = scf_value_type(ud_val); 4631 assert(ty != SCF_TYPE_INVALID); 4632 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4633 warn(cf_inval, ient->sc_fmri, ud_name); 4634 r = 0; 4635 goto out; 4636 } 4637 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4638 0) 4639 bad_error("scf_value_get_as_string", scf_error()); 4640 4641 r = fmri_equal(ud_ctarg, ud_oldtarg); 4642 if (r == -1) { 4643 warn(cf_inval, ient->sc_fmri, ud_name); 4644 r = 0; 4645 goto out; 4646 } else if (r == -2) { 4647 warn(li_corrupt, ient->sc_fmri); 4648 r = EBADF; 4649 goto out; 4650 } else if (r == 0) { 4651 /* 4652 * Target has been changed. Only abort now if it's been 4653 * changed to something other than what's in the manifest. 4654 */ 4655 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4656 if (r == -1) { 4657 warn(cf_inval, ient->sc_fmri, ud_name); 4658 r = 0; 4659 goto out; 4660 } else if (r == 0) { 4661 warn(cf_newtarg, ient->sc_fmri, ud_name); 4662 r = 0; 4663 goto out; 4664 } else if (r != 1) { 4665 /* invalid sc_pgroup_fmri caught above */ 4666 bad_error("fmri_equal", r); 4667 } 4668 4669 /* 4670 * Fetch the current dependency pg. If it's what the manifest 4671 * says, then no problem. 4672 */ 4673 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4674 switch (serr) { 4675 case SCF_ERROR_NONE: 4676 break; 4677 4678 case SCF_ERROR_NOT_FOUND: 4679 warn(cf_missing, ient->sc_fmri, ud_name); 4680 r = 0; 4681 goto out; 4682 4683 case SCF_ERROR_NO_MEMORY: 4684 r = ENOMEM; 4685 goto out; 4686 4687 case SCF_ERROR_CONSTRAINT_VIOLATED: 4688 case SCF_ERROR_INVALID_ARGUMENT: 4689 default: 4690 bad_error("fmri_to_entity", serr); 4691 } 4692 4693 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4694 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4695 switch (r) { 4696 case 0: 4697 break; 4698 4699 case ECONNABORTED: 4700 goto out; 4701 4702 case ECANCELED: 4703 case ENOENT: 4704 warn(cf_missing, ient->sc_fmri, ud_name); 4705 r = 0; 4706 goto out; 4707 4708 case EBADF: 4709 warn(r_no_lvl, ud_ctarg); 4710 goto out; 4711 4712 case EINVAL: 4713 default: 4714 bad_error("entity_get_running_pg", r); 4715 } 4716 4717 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4718 switch (r) { 4719 case 0: 4720 break; 4721 4722 case ECANCELED: 4723 warn(cf_missing, ient->sc_fmri, ud_name); 4724 r = 0; 4725 goto out; 4726 4727 case ECONNABORTED: 4728 case ENOMEM: 4729 case EBADF: 4730 goto out; 4731 4732 case EACCES: 4733 default: 4734 bad_error("load_pg", r); 4735 } 4736 4737 if (!pg_equal(current_pg, new_dpt_pgroup)) 4738 warn(cf_newdpg, ient->sc_fmri, ud_name); 4739 internal_pgroup_free(current_pg); 4740 r = 0; 4741 goto out; 4742 } else if (r != 1) { 4743 bad_error("fmri_equal", r); 4744 } 4745 4746 nocust: 4747 /* 4748 * Target has not been customized. Check the dependency property 4749 * group. 4750 */ 4751 4752 if (old_dpt_pgroup == NULL) { 4753 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4754 ud_pg) != 0) { 4755 switch (scf_error()) { 4756 case SCF_ERROR_NOT_FOUND: 4757 warn(li_corrupt, ient->sc_fmri); 4758 return (EBADF); 4759 4760 case SCF_ERROR_DELETED: 4761 case SCF_ERROR_CONNECTION_BROKEN: 4762 return (scferror2errno(scf_error())); 4763 4764 case SCF_ERROR_NOT_BOUND: 4765 case SCF_ERROR_HANDLE_MISMATCH: 4766 case SCF_ERROR_INVALID_ARGUMENT: 4767 case SCF_ERROR_NOT_SET: 4768 default: 4769 bad_error("scf_snaplevel_get_pg", scf_error()); 4770 } 4771 } 4772 4773 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4774 snap_lastimport); 4775 switch (r) { 4776 case 0: 4777 break; 4778 4779 case ECANCELED: 4780 case ECONNABORTED: 4781 case ENOMEM: 4782 case EBADF: 4783 return (r); 4784 4785 case EACCES: 4786 default: 4787 bad_error("load_pg", r); 4788 } 4789 } 4790 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4791 switch (serr) { 4792 case SCF_ERROR_NONE: 4793 break; 4794 4795 case SCF_ERROR_NOT_FOUND: 4796 warn(cf_missing, ient->sc_fmri, ud_name); 4797 r = 0; 4798 goto out; 4799 4800 case SCF_ERROR_NO_MEMORY: 4801 r = ENOMEM; 4802 goto out; 4803 4804 case SCF_ERROR_CONSTRAINT_VIOLATED: 4805 case SCF_ERROR_INVALID_ARGUMENT: 4806 default: 4807 bad_error("fmri_to_entity", serr); 4808 } 4809 4810 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4811 ud_iter2, ud_inst, imp_snap, ud_snpl); 4812 switch (r) { 4813 case 0: 4814 break; 4815 4816 case ECONNABORTED: 4817 goto out; 4818 4819 case ECANCELED: 4820 case ENOENT: 4821 warn(cf_missing, ient->sc_fmri, ud_name); 4822 r = 0; 4823 goto out; 4824 4825 case EBADF: 4826 warn(r_no_lvl, ud_ctarg); 4827 goto out; 4828 4829 case EINVAL: 4830 default: 4831 bad_error("entity_get_running_pg", r); 4832 } 4833 4834 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4835 switch (r) { 4836 case 0: 4837 break; 4838 4839 case ECANCELED: 4840 warn(cf_missing, ient->sc_fmri, ud_name); 4841 goto out; 4842 4843 case ECONNABORTED: 4844 case ENOMEM: 4845 case EBADF: 4846 goto out; 4847 4848 case EACCES: 4849 default: 4850 bad_error("load_pg", r); 4851 } 4852 4853 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4854 if (!pg_equal(current_pg, new_dpt_pgroup)) 4855 warn(cf_newdpg, ient->sc_fmri, ud_name); 4856 internal_pgroup_free(current_pg); 4857 r = 0; 4858 goto out; 4859 } 4860 4861 /* Uncustomized. Upgrade. */ 4862 4863 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4864 switch (r) { 4865 case 1: 4866 if (pg_equal(current_pg, new_dpt_pgroup)) { 4867 /* Already upgraded. */ 4868 internal_pgroup_free(current_pg); 4869 r = 0; 4870 goto out; 4871 } 4872 4873 internal_pgroup_free(current_pg); 4874 4875 /* upgrade current_pg */ 4876 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4877 switch (scf_error()) { 4878 case SCF_ERROR_CONNECTION_BROKEN: 4879 r = scferror2errno(scf_error()); 4880 goto out; 4881 4882 case SCF_ERROR_DELETED: 4883 warn(cf_missing, ient->sc_fmri, ud_name); 4884 r = 0; 4885 goto out; 4886 4887 case SCF_ERROR_NOT_FOUND: 4888 break; 4889 4890 case SCF_ERROR_INVALID_ARGUMENT: 4891 case SCF_ERROR_NOT_BOUND: 4892 case SCF_ERROR_NOT_SET: 4893 case SCF_ERROR_HANDLE_MISMATCH: 4894 default: 4895 bad_error("entity_get_pg", scf_error()); 4896 } 4897 4898 if (tissvc) 4899 r = scf_service_add_pg(target_ent, ud_name, 4900 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4901 else 4902 r = scf_instance_add_pg(target_ent, ud_name, 4903 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4904 if (r != 0) { 4905 switch (scf_error()) { 4906 case SCF_ERROR_CONNECTION_BROKEN: 4907 case SCF_ERROR_NO_RESOURCES: 4908 case SCF_ERROR_BACKEND_READONLY: 4909 case SCF_ERROR_BACKEND_ACCESS: 4910 r = scferror2errno(scf_error()); 4911 goto out; 4912 4913 case SCF_ERROR_DELETED: 4914 warn(cf_missing, ient->sc_fmri, 4915 ud_name); 4916 r = 0; 4917 goto out; 4918 4919 case SCF_ERROR_PERMISSION_DENIED: 4920 warn(emsg_pg_deleted, ud_ctarg, 4921 ud_name); 4922 r = EPERM; 4923 goto out; 4924 4925 case SCF_ERROR_EXISTS: 4926 warn(emsg_pg_added, ud_ctarg, ud_name); 4927 r = EBUSY; 4928 goto out; 4929 4930 case SCF_ERROR_NOT_BOUND: 4931 case SCF_ERROR_HANDLE_MISMATCH: 4932 case SCF_ERROR_INVALID_ARGUMENT: 4933 case SCF_ERROR_NOT_SET: 4934 default: 4935 bad_error("entity_add_pg", scf_error()); 4936 } 4937 } 4938 } 4939 4940 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4941 switch (r) { 4942 case 0: 4943 break; 4944 4945 case ECANCELED: 4946 warn(cf_missing, ient->sc_fmri, ud_name); 4947 goto out; 4948 4949 case ECONNABORTED: 4950 case ENOMEM: 4951 case EBADF: 4952 goto out; 4953 4954 case EACCES: 4955 default: 4956 bad_error("load_pg", r); 4957 } 4958 4959 if (g_verbose) 4960 warn(upgrading, ient->sc_fmri, ud_name); 4961 4962 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4963 new_dpt_pgroup, 0, ient->sc_fmri); 4964 switch (r) { 4965 case 0: 4966 break; 4967 4968 case ECANCELED: 4969 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4970 r = EBUSY; 4971 goto out; 4972 4973 case EPERM: 4974 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4975 goto out; 4976 4977 case EBUSY: 4978 warn(emsg_pg_changed, ud_ctarg, ud_name); 4979 goto out; 4980 4981 case ECONNABORTED: 4982 case ENOMEM: 4983 case ENOSPC: 4984 case EROFS: 4985 case EACCES: 4986 case EINVAL: 4987 goto out; 4988 4989 default: 4990 bad_error("upgrade_pg", r); 4991 } 4992 break; 4993 4994 case 0: { 4995 scf_transaction_entry_t *ent; 4996 scf_value_t *val; 4997 4998 internal_pgroup_free(current_pg); 4999 5000 /* delete old pg */ 5001 if (g_verbose) 5002 warn(upgrading, ient->sc_fmri, ud_name); 5003 5004 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 5005 switch (scf_error()) { 5006 case SCF_ERROR_CONNECTION_BROKEN: 5007 r = scferror2errno(scf_error()); 5008 goto out; 5009 5010 case SCF_ERROR_DELETED: 5011 warn(cf_missing, ient->sc_fmri, ud_name); 5012 r = 0; 5013 goto out; 5014 5015 case SCF_ERROR_NOT_FOUND: 5016 break; 5017 5018 case SCF_ERROR_INVALID_ARGUMENT: 5019 case SCF_ERROR_NOT_BOUND: 5020 case SCF_ERROR_NOT_SET: 5021 case SCF_ERROR_HANDLE_MISMATCH: 5022 default: 5023 bad_error("entity_get_pg", scf_error()); 5024 } 5025 } else if (scf_pg_delete(ud_pg) != 0) { 5026 switch (scf_error()) { 5027 case SCF_ERROR_DELETED: 5028 break; 5029 5030 case SCF_ERROR_CONNECTION_BROKEN: 5031 case SCF_ERROR_BACKEND_READONLY: 5032 case SCF_ERROR_BACKEND_ACCESS: 5033 r = scferror2errno(scf_error()); 5034 goto out; 5035 5036 case SCF_ERROR_PERMISSION_DENIED: 5037 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 5038 r = scferror2errno(scf_error()); 5039 goto out; 5040 5041 case SCF_ERROR_NOT_SET: 5042 default: 5043 bad_error("scf_pg_delete", scf_error()); 5044 } 5045 } 5046 5047 /* import new one */ 5048 cbdata.sc_handle = g_hndl; 5049 cbdata.sc_trans = NULL; /* handled below */ 5050 cbdata.sc_flags = 0; 5051 5052 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 5053 if (r != UU_WALK_NEXT) { 5054 if (r != UU_WALK_ERROR) 5055 bad_error("lscf_dependent_import", r); 5056 5057 r = cbdata.sc_err; 5058 goto out; 5059 } 5060 5061 if (tx == NULL) 5062 break; 5063 5064 if ((ent = scf_entry_create(g_hndl)) == NULL || 5065 (val = scf_value_create(g_hndl)) == NULL) { 5066 if (scf_error() == SCF_ERROR_NO_MEMORY) 5067 return (ENOMEM); 5068 5069 bad_error("scf_entry_create", scf_error()); 5070 } 5071 5072 if (scf_transaction_property_change_type(tx, ent, ud_name, 5073 SCF_TYPE_FMRI) != 0) { 5074 switch (scf_error()) { 5075 case SCF_ERROR_CONNECTION_BROKEN: 5076 r = scferror2errno(scf_error()); 5077 goto out; 5078 5079 case SCF_ERROR_DELETED: 5080 warn(emsg_pg_deleted, ient->sc_fmri, 5081 "dependents"); 5082 r = EBUSY; 5083 goto out; 5084 5085 case SCF_ERROR_NOT_FOUND: 5086 break; 5087 5088 case SCF_ERROR_NOT_BOUND: 5089 case SCF_ERROR_HANDLE_MISMATCH: 5090 case SCF_ERROR_INVALID_ARGUMENT: 5091 case SCF_ERROR_NOT_SET: 5092 default: 5093 bad_error("scf_transaction_property_" 5094 "change_type", scf_error()); 5095 } 5096 5097 if (scf_transaction_property_new(tx, ent, ud_name, 5098 SCF_TYPE_FMRI) != 0) { 5099 switch (scf_error()) { 5100 case SCF_ERROR_CONNECTION_BROKEN: 5101 r = scferror2errno(scf_error()); 5102 goto out; 5103 5104 case SCF_ERROR_DELETED: 5105 warn(emsg_pg_deleted, ient->sc_fmri, 5106 "dependents"); 5107 r = EBUSY; 5108 goto out; 5109 5110 case SCF_ERROR_EXISTS: 5111 warn(emsg_pg_changed, ient->sc_fmri, 5112 "dependents"); 5113 r = EBUSY; 5114 goto out; 5115 5116 case SCF_ERROR_INVALID_ARGUMENT: 5117 case SCF_ERROR_HANDLE_MISMATCH: 5118 case SCF_ERROR_NOT_BOUND: 5119 case SCF_ERROR_NOT_SET: 5120 default: 5121 bad_error("scf_transaction_property_" 5122 "new", scf_error()); 5123 } 5124 } 5125 } 5126 5127 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 5128 new_dpt_pgroup->sc_pgroup_fmri) != 0) 5129 /* invalid sc_pgroup_fmri caught above */ 5130 bad_error("scf_value_set_from_string", 5131 scf_error()); 5132 5133 if (scf_entry_add_value(ent, val) != 0) 5134 bad_error("scf_entry_add_value", scf_error()); 5135 break; 5136 } 5137 5138 case -2: 5139 warn(li_corrupt, ient->sc_fmri); 5140 internal_pgroup_free(current_pg); 5141 r = EBADF; 5142 goto out; 5143 5144 case -1: 5145 default: 5146 /* invalid sc_pgroup_fmri caught above */ 5147 bad_error("fmri_equal", r); 5148 } 5149 5150 r = 0; 5151 5152 out: 5153 if (old_dpt_pgroup != NULL) 5154 internal_pgroup_free(old_dpt_pgroup); 5155 5156 return (r); 5157 } 5158 5159 /* 5160 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 5161 * would import it, except it seems to exist in the service anyway. Compare 5162 * the existent dependent with the one we would import, and report any 5163 * differences (if there are none, be silent). prop is the property which 5164 * represents the existent dependent (in the dependents property group) in the 5165 * entity corresponding to ient. 5166 * 5167 * Returns 5168 * 0 - success (Sort of. At least, we can continue importing.) 5169 * ECONNABORTED - repository connection broken 5170 * EBUSY - ancestor of prop was deleted (error printed) 5171 * ENOMEM - out of memory 5172 * EBADF - corrupt property group (error printed) 5173 * EINVAL - new_dpt_pgroup has invalid target (error printed) 5174 */ 5175 static int 5176 handle_dependent_conflict(const entity_t * const ient, 5177 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 5178 { 5179 int r; 5180 scf_type_t ty; 5181 scf_error_t scfe; 5182 void *tptr; 5183 int tissvc; 5184 pgroup_t *pgroup; 5185 5186 if (scf_property_get_value(prop, ud_val) != 0) { 5187 switch (scf_error()) { 5188 case SCF_ERROR_CONNECTION_BROKEN: 5189 return (scferror2errno(scf_error())); 5190 5191 case SCF_ERROR_DELETED: 5192 warn(emsg_pg_deleted, ient->sc_fmri, 5193 new_dpt_pgroup->sc_pgroup_name); 5194 return (EBUSY); 5195 5196 case SCF_ERROR_CONSTRAINT_VIOLATED: 5197 case SCF_ERROR_NOT_FOUND: 5198 warn(gettext("Conflict upgrading %s (not importing " 5199 "dependent \"%s\" because it already exists.) " 5200 "Warning: The \"%s/%2$s\" property has more or " 5201 "fewer than one value)).\n"), ient->sc_fmri, 5202 new_dpt_pgroup->sc_pgroup_name, "dependents"); 5203 return (0); 5204 5205 case SCF_ERROR_HANDLE_MISMATCH: 5206 case SCF_ERROR_NOT_BOUND: 5207 case SCF_ERROR_NOT_SET: 5208 case SCF_ERROR_PERMISSION_DENIED: 5209 default: 5210 bad_error("scf_property_get_value", 5211 scf_error()); 5212 } 5213 } 5214 5215 ty = scf_value_type(ud_val); 5216 assert(ty != SCF_TYPE_INVALID); 5217 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 5218 warn(gettext("Conflict upgrading %s (not importing dependent " 5219 "\"%s\" because it already exists). Warning: The " 5220 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 5221 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 5222 scf_type_to_string(ty), "dependents"); 5223 return (0); 5224 } 5225 5226 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 5227 0) 5228 bad_error("scf_value_get_as_string", scf_error()); 5229 5230 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 5231 switch (r) { 5232 case 0: 5233 warn(gettext("Conflict upgrading %s (not importing dependent " 5234 "\"%s\" (target \"%s\") because it already exists with " 5235 "target \"%s\").\n"), ient->sc_fmri, 5236 new_dpt_pgroup->sc_pgroup_name, 5237 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 5238 return (0); 5239 5240 case 1: 5241 break; 5242 5243 case -1: 5244 warn(gettext("Conflict upgrading %s (not importing dependent " 5245 "\"%s\" because it already exists). Warning: The current " 5246 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 5247 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5248 return (0); 5249 5250 case -2: 5251 warn(gettext("Dependent \"%s\" of %s has invalid target " 5252 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 5253 new_dpt_pgroup->sc_pgroup_fmri); 5254 return (EINVAL); 5255 5256 default: 5257 bad_error("fmri_equal", r); 5258 } 5259 5260 /* compare dependency pgs in target */ 5261 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 5262 switch (scfe) { 5263 case SCF_ERROR_NONE: 5264 break; 5265 5266 case SCF_ERROR_NO_MEMORY: 5267 return (ENOMEM); 5268 5269 case SCF_ERROR_NOT_FOUND: 5270 warn(emsg_dpt_dangling, ient->sc_fmri, 5271 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5272 return (0); 5273 5274 case SCF_ERROR_CONSTRAINT_VIOLATED: 5275 case SCF_ERROR_INVALID_ARGUMENT: 5276 default: 5277 bad_error("fmri_to_entity", scfe); 5278 } 5279 5280 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 5281 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 5282 switch (r) { 5283 case 0: 5284 break; 5285 5286 case ECONNABORTED: 5287 return (r); 5288 5289 case ECANCELED: 5290 warn(emsg_dpt_dangling, ient->sc_fmri, 5291 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5292 return (0); 5293 5294 case EBADF: 5295 if (tissvc) 5296 warn(gettext("%s has an instance with a \"%s\" " 5297 "snapshot which is missing a snaplevel.\n"), 5298 ud_ctarg, "running"); 5299 else 5300 warn(gettext("%s has a \"%s\" snapshot which is " 5301 "missing a snaplevel.\n"), ud_ctarg, "running"); 5302 /* FALLTHROUGH */ 5303 5304 case ENOENT: 5305 warn(emsg_dpt_no_dep, ient->sc_fmri, 5306 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5307 new_dpt_pgroup->sc_pgroup_name); 5308 return (0); 5309 5310 case EINVAL: 5311 default: 5312 bad_error("entity_get_running_pg", r); 5313 } 5314 5315 pgroup = internal_pgroup_new(); 5316 if (pgroup == NULL) 5317 return (ENOMEM); 5318 5319 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 5320 switch (r) { 5321 case 0: 5322 break; 5323 5324 case ECONNABORTED: 5325 case EBADF: 5326 case ENOMEM: 5327 internal_pgroup_free(pgroup); 5328 return (r); 5329 5330 case ECANCELED: 5331 warn(emsg_dpt_no_dep, ient->sc_fmri, 5332 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5333 new_dpt_pgroup->sc_pgroup_name); 5334 internal_pgroup_free(pgroup); 5335 return (0); 5336 5337 case EACCES: 5338 default: 5339 bad_error("load_pg", r); 5340 } 5341 5342 /* report differences */ 5343 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 5344 internal_pgroup_free(pgroup); 5345 return (0); 5346 } 5347 5348 /* 5349 * lipg is a property group in the last-import snapshot of ent, which is an 5350 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 5351 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 5352 * in ents's property groups, compare and upgrade ent appropriately. 5353 * 5354 * Returns 5355 * 0 - success 5356 * ECONNABORTED - repository connection broken 5357 * ENOMEM - out of memory 5358 * ENOSPC - configd is out of resources 5359 * EINVAL - ient has invalid dependent (error printed) 5360 * - ient has invalid pgroup_t (error printed) 5361 * ECANCELED - ent has been deleted 5362 * ENODEV - entity containing lipg has been deleted 5363 * - entity containing running has been deleted 5364 * EPERM - could not delete pg (permission denied) (error printed) 5365 * - couldn't upgrade dependents (permission denied) (error printed) 5366 * - couldn't import pg (permission denied) (error printed) 5367 * - couldn't upgrade pg (permission denied) (error printed) 5368 * EROFS - could not delete pg (repository read-only) 5369 * - couldn't upgrade dependents (repository read-only) 5370 * - couldn't import pg (repository read-only) 5371 * - couldn't upgrade pg (repository read-only) 5372 * EACCES - could not delete pg (backend access denied) 5373 * - couldn't upgrade dependents (backend access denied) 5374 * - couldn't import pg (backend access denied) 5375 * - couldn't upgrade pg (backend access denied) 5376 * - couldn't read property (backend access denied) 5377 * EBUSY - property group was added (error printed) 5378 * - property group was deleted (error printed) 5379 * - property group changed (error printed) 5380 * - "dependents" pg was added, changed, or deleted (error printed) 5381 * - dependent target deleted (error printed) 5382 * - dependent pg changed (error printed) 5383 * EBADF - imp_snpl is corrupt (error printed) 5384 * - ent has bad pg (error printed) 5385 * EEXIST - dependent collision in target service (error printed) 5386 */ 5387 static int 5388 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 5389 const scf_snaplevel_t *running) 5390 { 5391 int r; 5392 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 5393 scf_callback_t cbdata; 5394 5395 const char * const cf_pg_missing = 5396 gettext("Conflict upgrading %s (property group %s is missing)\n"); 5397 const char * const deleting = 5398 gettext("%s: Deleting property group \"%s\".\n"); 5399 5400 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5401 5402 /* Skip dependent property groups. */ 5403 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 5404 switch (scf_error()) { 5405 case SCF_ERROR_DELETED: 5406 return (ENODEV); 5407 5408 case SCF_ERROR_CONNECTION_BROKEN: 5409 return (ECONNABORTED); 5410 5411 case SCF_ERROR_NOT_SET: 5412 case SCF_ERROR_NOT_BOUND: 5413 default: 5414 bad_error("scf_pg_get_type", scf_error()); 5415 } 5416 } 5417 5418 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 5419 if (scf_pg_get_property(lipg, "external", NULL) == 0) 5420 return (0); 5421 5422 switch (scf_error()) { 5423 case SCF_ERROR_NOT_FOUND: 5424 break; 5425 5426 case SCF_ERROR_CONNECTION_BROKEN: 5427 return (ECONNABORTED); 5428 5429 case SCF_ERROR_DELETED: 5430 return (ENODEV); 5431 5432 case SCF_ERROR_INVALID_ARGUMENT: 5433 case SCF_ERROR_NOT_BOUND: 5434 case SCF_ERROR_HANDLE_MISMATCH: 5435 case SCF_ERROR_NOT_SET: 5436 default: 5437 bad_error("scf_pg_get_property", scf_error()); 5438 } 5439 } 5440 5441 /* lookup pg in new properties */ 5442 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 5443 switch (scf_error()) { 5444 case SCF_ERROR_DELETED: 5445 return (ENODEV); 5446 5447 case SCF_ERROR_CONNECTION_BROKEN: 5448 return (ECONNABORTED); 5449 5450 case SCF_ERROR_NOT_SET: 5451 case SCF_ERROR_NOT_BOUND: 5452 default: 5453 bad_error("scf_pg_get_name", scf_error()); 5454 } 5455 } 5456 5457 pgrp.sc_pgroup_name = imp_str; 5458 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 5459 5460 if (mpg != NULL) 5461 mpg->sc_pgroup_seen = 1; 5462 5463 /* Special handling for dependents */ 5464 if (strcmp(imp_str, "dependents") == 0) 5465 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 5466 5467 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 5468 return (upgrade_manifestfiles(NULL, ient, running, ent)); 5469 5470 if (mpg == NULL || mpg->sc_pgroup_delete) { 5471 /* property group was deleted from manifest */ 5472 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5473 switch (scf_error()) { 5474 case SCF_ERROR_NOT_FOUND: 5475 return (0); 5476 5477 case SCF_ERROR_DELETED: 5478 case SCF_ERROR_CONNECTION_BROKEN: 5479 return (scferror2errno(scf_error())); 5480 5481 case SCF_ERROR_INVALID_ARGUMENT: 5482 case SCF_ERROR_HANDLE_MISMATCH: 5483 case SCF_ERROR_NOT_BOUND: 5484 case SCF_ERROR_NOT_SET: 5485 default: 5486 bad_error("entity_get_pg", scf_error()); 5487 } 5488 } 5489 5490 if (mpg != NULL && mpg->sc_pgroup_delete) { 5491 if (g_verbose) 5492 warn(deleting, ient->sc_fmri, imp_str); 5493 if (scf_pg_delete(imp_pg2) == 0) 5494 return (0); 5495 5496 switch (scf_error()) { 5497 case SCF_ERROR_DELETED: 5498 return (0); 5499 5500 case SCF_ERROR_CONNECTION_BROKEN: 5501 case SCF_ERROR_BACKEND_READONLY: 5502 case SCF_ERROR_BACKEND_ACCESS: 5503 return (scferror2errno(scf_error())); 5504 5505 case SCF_ERROR_PERMISSION_DENIED: 5506 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 5507 return (scferror2errno(scf_error())); 5508 5509 case SCF_ERROR_NOT_SET: 5510 default: 5511 bad_error("scf_pg_delete", scf_error()); 5512 } 5513 } 5514 5515 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5516 switch (r) { 5517 case 0: 5518 break; 5519 5520 case ECANCELED: 5521 return (ENODEV); 5522 5523 case ECONNABORTED: 5524 case ENOMEM: 5525 case EBADF: 5526 case EACCES: 5527 return (r); 5528 5529 default: 5530 bad_error("load_pg", r); 5531 } 5532 5533 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5534 switch (r) { 5535 case 0: 5536 break; 5537 5538 case ECANCELED: 5539 case ECONNABORTED: 5540 case ENOMEM: 5541 case EBADF: 5542 case EACCES: 5543 internal_pgroup_free(lipg_i); 5544 return (r); 5545 5546 default: 5547 bad_error("load_pg", r); 5548 } 5549 5550 if (pg_equal(lipg_i, curpg_i)) { 5551 if (g_verbose) 5552 warn(deleting, ient->sc_fmri, imp_str); 5553 if (scf_pg_delete(imp_pg2) != 0) { 5554 switch (scf_error()) { 5555 case SCF_ERROR_DELETED: 5556 break; 5557 5558 case SCF_ERROR_CONNECTION_BROKEN: 5559 internal_pgroup_free(lipg_i); 5560 internal_pgroup_free(curpg_i); 5561 return (ECONNABORTED); 5562 5563 case SCF_ERROR_NOT_SET: 5564 case SCF_ERROR_NOT_BOUND: 5565 default: 5566 bad_error("scf_pg_delete", scf_error()); 5567 } 5568 } 5569 } else { 5570 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5571 } 5572 5573 internal_pgroup_free(lipg_i); 5574 internal_pgroup_free(curpg_i); 5575 5576 return (0); 5577 } 5578 5579 /* 5580 * Only dependent pgs can have override set, and we skipped those 5581 * above. 5582 */ 5583 assert(!mpg->sc_pgroup_override); 5584 5585 /* compare */ 5586 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5587 switch (r) { 5588 case 0: 5589 break; 5590 5591 case ECANCELED: 5592 return (ENODEV); 5593 5594 case ECONNABORTED: 5595 case EBADF: 5596 case ENOMEM: 5597 case EACCES: 5598 return (r); 5599 5600 default: 5601 bad_error("load_pg", r); 5602 } 5603 5604 if (pg_equal(mpg, lipg_i)) { 5605 /* The manifest pg has not changed. Move on. */ 5606 r = 0; 5607 goto out; 5608 } 5609 5610 /* upgrade current properties according to lipg & mpg */ 5611 if (running != NULL) 5612 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5613 else 5614 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5615 if (r != 0) { 5616 switch (scf_error()) { 5617 case SCF_ERROR_CONNECTION_BROKEN: 5618 r = scferror2errno(scf_error()); 5619 goto out; 5620 5621 case SCF_ERROR_DELETED: 5622 if (running != NULL) 5623 r = ENODEV; 5624 else 5625 r = ECANCELED; 5626 goto out; 5627 5628 case SCF_ERROR_NOT_FOUND: 5629 break; 5630 5631 case SCF_ERROR_INVALID_ARGUMENT: 5632 case SCF_ERROR_HANDLE_MISMATCH: 5633 case SCF_ERROR_NOT_BOUND: 5634 case SCF_ERROR_NOT_SET: 5635 default: 5636 bad_error("entity_get_pg", scf_error()); 5637 } 5638 5639 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5640 5641 r = 0; 5642 goto out; 5643 } 5644 5645 r = load_pg_attrs(imp_pg2, &curpg_i); 5646 switch (r) { 5647 case 0: 5648 break; 5649 5650 case ECANCELED: 5651 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5652 r = 0; 5653 goto out; 5654 5655 case ECONNABORTED: 5656 case ENOMEM: 5657 goto out; 5658 5659 default: 5660 bad_error("load_pg_attrs", r); 5661 } 5662 5663 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5664 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5665 internal_pgroup_free(curpg_i); 5666 r = 0; 5667 goto out; 5668 } 5669 5670 internal_pgroup_free(curpg_i); 5671 5672 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5673 switch (r) { 5674 case 0: 5675 break; 5676 5677 case ECANCELED: 5678 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5679 r = 0; 5680 goto out; 5681 5682 case ECONNABORTED: 5683 case EBADF: 5684 case ENOMEM: 5685 case EACCES: 5686 goto out; 5687 5688 default: 5689 bad_error("load_pg", r); 5690 } 5691 5692 if (pg_equal(lipg_i, curpg_i) && 5693 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5694 int do_delete = 1; 5695 5696 if (g_verbose) 5697 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5698 ient->sc_fmri, mpg->sc_pgroup_name); 5699 5700 internal_pgroup_free(curpg_i); 5701 5702 if (running != NULL && 5703 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5704 switch (scf_error()) { 5705 case SCF_ERROR_DELETED: 5706 r = ECANCELED; 5707 goto out; 5708 5709 case SCF_ERROR_NOT_FOUND: 5710 do_delete = 0; 5711 break; 5712 5713 case SCF_ERROR_CONNECTION_BROKEN: 5714 r = scferror2errno(scf_error()); 5715 goto out; 5716 5717 case SCF_ERROR_HANDLE_MISMATCH: 5718 case SCF_ERROR_INVALID_ARGUMENT: 5719 case SCF_ERROR_NOT_SET: 5720 case SCF_ERROR_NOT_BOUND: 5721 default: 5722 bad_error("entity_get_pg", scf_error()); 5723 } 5724 } 5725 5726 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5727 switch (scf_error()) { 5728 case SCF_ERROR_DELETED: 5729 break; 5730 5731 case SCF_ERROR_CONNECTION_BROKEN: 5732 case SCF_ERROR_BACKEND_READONLY: 5733 case SCF_ERROR_BACKEND_ACCESS: 5734 r = scferror2errno(scf_error()); 5735 goto out; 5736 5737 case SCF_ERROR_PERMISSION_DENIED: 5738 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5739 ient->sc_fmri); 5740 r = scferror2errno(scf_error()); 5741 goto out; 5742 5743 case SCF_ERROR_NOT_SET: 5744 case SCF_ERROR_NOT_BOUND: 5745 default: 5746 bad_error("scf_pg_delete", scf_error()); 5747 } 5748 } 5749 5750 cbdata.sc_handle = g_hndl; 5751 cbdata.sc_parent = ent; 5752 cbdata.sc_service = issvc; 5753 cbdata.sc_flags = 0; 5754 cbdata.sc_source_fmri = ient->sc_fmri; 5755 cbdata.sc_target_fmri = ient->sc_fmri; 5756 5757 r = entity_pgroup_import(mpg, &cbdata); 5758 switch (r) { 5759 case UU_WALK_NEXT: 5760 r = 0; 5761 goto out; 5762 5763 case UU_WALK_ERROR: 5764 if (cbdata.sc_err == EEXIST) { 5765 warn(emsg_pg_added, ient->sc_fmri, 5766 mpg->sc_pgroup_name); 5767 r = EBUSY; 5768 } else { 5769 r = cbdata.sc_err; 5770 } 5771 goto out; 5772 5773 default: 5774 bad_error("entity_pgroup_import", r); 5775 } 5776 } 5777 5778 if (running != NULL && 5779 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5780 switch (scf_error()) { 5781 case SCF_ERROR_CONNECTION_BROKEN: 5782 case SCF_ERROR_DELETED: 5783 r = scferror2errno(scf_error()); 5784 goto out; 5785 5786 case SCF_ERROR_NOT_FOUND: 5787 break; 5788 5789 case SCF_ERROR_HANDLE_MISMATCH: 5790 case SCF_ERROR_INVALID_ARGUMENT: 5791 case SCF_ERROR_NOT_SET: 5792 case SCF_ERROR_NOT_BOUND: 5793 default: 5794 bad_error("entity_get_pg", scf_error()); 5795 } 5796 5797 cbdata.sc_handle = g_hndl; 5798 cbdata.sc_parent = ent; 5799 cbdata.sc_service = issvc; 5800 cbdata.sc_flags = SCI_FORCE; 5801 cbdata.sc_source_fmri = ient->sc_fmri; 5802 cbdata.sc_target_fmri = ient->sc_fmri; 5803 5804 r = entity_pgroup_import(mpg, &cbdata); 5805 switch (r) { 5806 case UU_WALK_NEXT: 5807 r = 0; 5808 goto out; 5809 5810 case UU_WALK_ERROR: 5811 if (cbdata.sc_err == EEXIST) { 5812 warn(emsg_pg_added, ient->sc_fmri, 5813 mpg->sc_pgroup_name); 5814 r = EBUSY; 5815 } else { 5816 r = cbdata.sc_err; 5817 } 5818 goto out; 5819 5820 default: 5821 bad_error("entity_pgroup_import", r); 5822 } 5823 } 5824 5825 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5826 internal_pgroup_free(curpg_i); 5827 switch (r) { 5828 case 0: 5829 ient->sc_import_state = IMPORT_PROP_BEGUN; 5830 break; 5831 5832 case ECANCELED: 5833 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5834 r = EBUSY; 5835 break; 5836 5837 case EPERM: 5838 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5839 break; 5840 5841 case EBUSY: 5842 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5843 break; 5844 5845 case ECONNABORTED: 5846 case ENOMEM: 5847 case ENOSPC: 5848 case EROFS: 5849 case EACCES: 5850 case EINVAL: 5851 break; 5852 5853 default: 5854 bad_error("upgrade_pg", r); 5855 } 5856 5857 out: 5858 internal_pgroup_free(lipg_i); 5859 return (r); 5860 } 5861 5862 /* 5863 * Upgrade the properties of ent according to snpl & ient. 5864 * 5865 * Returns 5866 * 0 - success 5867 * ECONNABORTED - repository connection broken 5868 * ENOMEM - out of memory 5869 * ENOSPC - configd is out of resources 5870 * ECANCELED - ent was deleted 5871 * ENODEV - entity containing snpl was deleted 5872 * - entity containing running was deleted 5873 * EBADF - imp_snpl is corrupt (error printed) 5874 * - ent has corrupt pg (error printed) 5875 * - dependent has corrupt pg (error printed) 5876 * - dependent target has a corrupt snapshot (error printed) 5877 * EBUSY - pg was added, changed, or deleted (error printed) 5878 * - dependent target was deleted (error printed) 5879 * - dependent pg changed (error printed) 5880 * EINVAL - invalid property group name (error printed) 5881 * - invalid property name (error printed) 5882 * - invalid value (error printed) 5883 * - ient has invalid pgroup or dependent (error printed) 5884 * EPERM - could not create property group (permission denied) (error printed) 5885 * - could not modify property group (permission denied) (error printed) 5886 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5887 * EROFS - could not create property group (repository read-only) 5888 * - couldn't delete, upgrade, or import pg or dependent 5889 * EACCES - could not create property group (backend access denied) 5890 * - couldn't delete, upgrade, or import pg or dependent 5891 * EEXIST - dependent collision in target service (error printed) 5892 */ 5893 static int 5894 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5895 entity_t *ient) 5896 { 5897 pgroup_t *pg, *rpg; 5898 int r; 5899 uu_list_t *pgs = ient->sc_pgroups; 5900 5901 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5902 5903 /* clear sc_sceen for pgs */ 5904 if (uu_list_walk(pgs, clear_int, 5905 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5906 bad_error("uu_list_walk", uu_error()); 5907 5908 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5909 switch (scf_error()) { 5910 case SCF_ERROR_DELETED: 5911 return (ENODEV); 5912 5913 case SCF_ERROR_CONNECTION_BROKEN: 5914 return (ECONNABORTED); 5915 5916 case SCF_ERROR_NOT_SET: 5917 case SCF_ERROR_NOT_BOUND: 5918 case SCF_ERROR_HANDLE_MISMATCH: 5919 default: 5920 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5921 } 5922 } 5923 5924 for (;;) { 5925 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5926 if (r == 0) 5927 break; 5928 if (r == 1) { 5929 r = process_old_pg(imp_pg, ient, ent, running); 5930 switch (r) { 5931 case 0: 5932 break; 5933 5934 case ECONNABORTED: 5935 case ENOMEM: 5936 case ENOSPC: 5937 case ECANCELED: 5938 case ENODEV: 5939 case EPERM: 5940 case EROFS: 5941 case EACCES: 5942 case EBADF: 5943 case EBUSY: 5944 case EINVAL: 5945 case EEXIST: 5946 return (r); 5947 5948 default: 5949 bad_error("process_old_pg", r); 5950 } 5951 continue; 5952 } 5953 if (r != -1) 5954 bad_error("scf_iter_next_pg", r); 5955 5956 switch (scf_error()) { 5957 case SCF_ERROR_DELETED: 5958 return (ENODEV); 5959 5960 case SCF_ERROR_CONNECTION_BROKEN: 5961 return (ECONNABORTED); 5962 5963 case SCF_ERROR_HANDLE_MISMATCH: 5964 case SCF_ERROR_NOT_BOUND: 5965 case SCF_ERROR_NOT_SET: 5966 case SCF_ERROR_INVALID_ARGUMENT: 5967 default: 5968 bad_error("scf_iter_next_pg", scf_error()); 5969 } 5970 } 5971 5972 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5973 if (pg->sc_pgroup_seen) 5974 continue; 5975 5976 /* pg is new */ 5977 5978 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5979 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5980 ent); 5981 switch (r) { 5982 case 0: 5983 break; 5984 5985 case ECONNABORTED: 5986 case ENOMEM: 5987 case ENOSPC: 5988 case ECANCELED: 5989 case ENODEV: 5990 case EBADF: 5991 case EBUSY: 5992 case EINVAL: 5993 case EPERM: 5994 case EROFS: 5995 case EACCES: 5996 case EEXIST: 5997 return (r); 5998 5999 default: 6000 bad_error("upgrade_dependents", r); 6001 } 6002 continue; 6003 } 6004 6005 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 6006 r = upgrade_manifestfiles(pg, ient, running, ent); 6007 switch (r) { 6008 case 0: 6009 break; 6010 6011 case ECONNABORTED: 6012 case ENOMEM: 6013 case ENOSPC: 6014 case ECANCELED: 6015 case ENODEV: 6016 case EBADF: 6017 case EBUSY: 6018 case EINVAL: 6019 case EPERM: 6020 case EROFS: 6021 case EACCES: 6022 case EEXIST: 6023 return (r); 6024 6025 default: 6026 bad_error("upgrade_manifestfiles", r); 6027 } 6028 continue; 6029 } 6030 6031 if (running != NULL) { 6032 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 6033 imp_pg); 6034 } else { 6035 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 6036 imp_pg); 6037 } 6038 if (r != 0) { 6039 scf_callback_t cbdata; 6040 6041 switch (scf_error()) { 6042 case SCF_ERROR_NOT_FOUND: 6043 break; 6044 6045 case SCF_ERROR_CONNECTION_BROKEN: 6046 return (scferror2errno(scf_error())); 6047 6048 case SCF_ERROR_DELETED: 6049 if (running != NULL) 6050 return (ENODEV); 6051 else 6052 return (scferror2errno(scf_error())); 6053 6054 case SCF_ERROR_INVALID_ARGUMENT: 6055 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 6056 pg->sc_pgroup_name); 6057 return (EINVAL); 6058 6059 case SCF_ERROR_NOT_SET: 6060 case SCF_ERROR_HANDLE_MISMATCH: 6061 case SCF_ERROR_NOT_BOUND: 6062 default: 6063 bad_error("entity_get_pg", scf_error()); 6064 } 6065 6066 /* User doesn't have pg, so import it. */ 6067 6068 cbdata.sc_handle = g_hndl; 6069 cbdata.sc_parent = ent; 6070 cbdata.sc_service = issvc; 6071 cbdata.sc_flags = SCI_FORCE; 6072 cbdata.sc_source_fmri = ient->sc_fmri; 6073 cbdata.sc_target_fmri = ient->sc_fmri; 6074 6075 r = entity_pgroup_import(pg, &cbdata); 6076 switch (r) { 6077 case UU_WALK_NEXT: 6078 ient->sc_import_state = IMPORT_PROP_BEGUN; 6079 continue; 6080 6081 case UU_WALK_ERROR: 6082 if (cbdata.sc_err == EEXIST) { 6083 warn(emsg_pg_added, ient->sc_fmri, 6084 pg->sc_pgroup_name); 6085 return (EBUSY); 6086 } 6087 return (cbdata.sc_err); 6088 6089 default: 6090 bad_error("entity_pgroup_import", r); 6091 } 6092 } 6093 6094 /* report differences between pg & current */ 6095 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 6096 switch (r) { 6097 case 0: 6098 break; 6099 6100 case ECANCELED: 6101 warn(emsg_pg_deleted, ient->sc_fmri, 6102 pg->sc_pgroup_name); 6103 return (EBUSY); 6104 6105 case ECONNABORTED: 6106 case EBADF: 6107 case ENOMEM: 6108 case EACCES: 6109 return (r); 6110 6111 default: 6112 bad_error("load_pg", r); 6113 } 6114 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 6115 internal_pgroup_free(rpg); 6116 rpg = NULL; 6117 } 6118 6119 return (0); 6120 } 6121 6122 /* 6123 * Import an instance. If it doesn't exist, create it. If it has 6124 * a last-import snapshot, upgrade its properties. Finish by updating its 6125 * last-import snapshot. If it doesn't have a last-import snapshot then it 6126 * could have been created for a dependent tag in another manifest. Import the 6127 * new properties. If there's a conflict, don't override, like now? 6128 * 6129 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 6130 * lcbdata->sc_err to 6131 * ECONNABORTED - repository connection broken 6132 * ENOMEM - out of memory 6133 * ENOSPC - svc.configd is out of resources 6134 * EEXIST - dependency collision in dependent service (error printed) 6135 * EPERM - couldn't create temporary instance (permission denied) 6136 * - couldn't import into temporary instance (permission denied) 6137 * - couldn't take snapshot (permission denied) 6138 * - couldn't upgrade properties (permission denied) 6139 * - couldn't import properties (permission denied) 6140 * - couldn't import dependents (permission denied) 6141 * EROFS - couldn't create temporary instance (repository read-only) 6142 * - couldn't import into temporary instance (repository read-only) 6143 * - couldn't upgrade properties (repository read-only) 6144 * - couldn't import properties (repository read-only) 6145 * - couldn't import dependents (repository read-only) 6146 * EACCES - couldn't create temporary instance (backend access denied) 6147 * - couldn't import into temporary instance (backend access denied) 6148 * - couldn't upgrade properties (backend access denied) 6149 * - couldn't import properties (backend access denied) 6150 * - couldn't import dependents (backend access denied) 6151 * EINVAL - invalid instance name (error printed) 6152 * - invalid pgroup_t's (error printed) 6153 * - invalid dependents (error printed) 6154 * EBUSY - temporary service deleted (error printed) 6155 * - temporary instance deleted (error printed) 6156 * - temporary instance changed (error printed) 6157 * - temporary instance already exists (error printed) 6158 * - instance deleted (error printed) 6159 * EBADF - instance has corrupt last-import snapshot (error printed) 6160 * - instance is corrupt (error printed) 6161 * - dependent has corrupt pg (error printed) 6162 * - dependent target has a corrupt snapshot (error printed) 6163 * -1 - unknown libscf error (error printed) 6164 */ 6165 static int 6166 lscf_instance_import(void *v, void *pvt) 6167 { 6168 entity_t *inst = v; 6169 scf_callback_t ctx; 6170 scf_callback_t *lcbdata = pvt; 6171 scf_service_t *rsvc = lcbdata->sc_parent; 6172 int r; 6173 scf_snaplevel_t *running; 6174 int flags = lcbdata->sc_flags; 6175 6176 const char * const emsg_tdel = 6177 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 6178 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 6179 "changed unexpectedly.\n"); 6180 const char * const emsg_del = gettext("%s changed unexpectedly " 6181 "(instance \"%s\" was deleted.)\n"); 6182 const char * const emsg_badsnap = gettext( 6183 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 6184 6185 /* 6186 * prepare last-import snapshot: 6187 * create temporary instance (service was precreated) 6188 * populate with properties from bundle 6189 * take snapshot 6190 */ 6191 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 6192 switch (scf_error()) { 6193 case SCF_ERROR_CONNECTION_BROKEN: 6194 case SCF_ERROR_NO_RESOURCES: 6195 case SCF_ERROR_BACKEND_READONLY: 6196 case SCF_ERROR_BACKEND_ACCESS: 6197 return (stash_scferror(lcbdata)); 6198 6199 case SCF_ERROR_EXISTS: 6200 warn(gettext("Temporary service svc:/%s " 6201 "changed unexpectedly (instance \"%s\" added).\n"), 6202 imp_tsname, inst->sc_name); 6203 lcbdata->sc_err = EBUSY; 6204 return (UU_WALK_ERROR); 6205 6206 case SCF_ERROR_DELETED: 6207 warn(gettext("Temporary service svc:/%s " 6208 "was deleted unexpectedly.\n"), imp_tsname); 6209 lcbdata->sc_err = EBUSY; 6210 return (UU_WALK_ERROR); 6211 6212 case SCF_ERROR_INVALID_ARGUMENT: 6213 warn(gettext("Invalid instance name \"%s\".\n"), 6214 inst->sc_name); 6215 return (stash_scferror(lcbdata)); 6216 6217 case SCF_ERROR_PERMISSION_DENIED: 6218 warn(gettext("Could not create temporary instance " 6219 "\"%s\" in svc:/%s (permission denied).\n"), 6220 inst->sc_name, imp_tsname); 6221 return (stash_scferror(lcbdata)); 6222 6223 case SCF_ERROR_HANDLE_MISMATCH: 6224 case SCF_ERROR_NOT_BOUND: 6225 case SCF_ERROR_NOT_SET: 6226 default: 6227 bad_error("scf_service_add_instance", scf_error()); 6228 } 6229 } 6230 6231 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6232 inst->sc_name); 6233 if (r < 0) 6234 bad_error("snprintf", errno); 6235 6236 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 6237 lcbdata->sc_flags | SCI_NOENABLED); 6238 switch (r) { 6239 case 0: 6240 break; 6241 6242 case ECANCELED: 6243 warn(emsg_tdel, imp_tsname, inst->sc_name); 6244 lcbdata->sc_err = EBUSY; 6245 r = UU_WALK_ERROR; 6246 goto deltemp; 6247 6248 case EEXIST: 6249 warn(emsg_tchg, imp_tsname, inst->sc_name); 6250 lcbdata->sc_err = EBUSY; 6251 r = UU_WALK_ERROR; 6252 goto deltemp; 6253 6254 case ECONNABORTED: 6255 goto connaborted; 6256 6257 case ENOMEM: 6258 case ENOSPC: 6259 case EPERM: 6260 case EROFS: 6261 case EACCES: 6262 case EINVAL: 6263 case EBUSY: 6264 lcbdata->sc_err = r; 6265 r = UU_WALK_ERROR; 6266 goto deltemp; 6267 6268 default: 6269 bad_error("lscf_import_instance_pgs", r); 6270 } 6271 6272 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6273 inst->sc_name); 6274 if (r < 0) 6275 bad_error("snprintf", errno); 6276 6277 ctx.sc_handle = lcbdata->sc_handle; 6278 ctx.sc_parent = imp_tinst; 6279 ctx.sc_service = 0; 6280 ctx.sc_source_fmri = inst->sc_fmri; 6281 ctx.sc_target_fmri = imp_str; 6282 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 6283 UU_DEFAULT) != 0) { 6284 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6285 bad_error("uu_list_walk", uu_error()); 6286 6287 switch (ctx.sc_err) { 6288 case ECONNABORTED: 6289 goto connaborted; 6290 6291 case ECANCELED: 6292 warn(emsg_tdel, imp_tsname, inst->sc_name); 6293 lcbdata->sc_err = EBUSY; 6294 break; 6295 6296 case EEXIST: 6297 warn(emsg_tchg, imp_tsname, inst->sc_name); 6298 lcbdata->sc_err = EBUSY; 6299 break; 6300 6301 default: 6302 lcbdata->sc_err = ctx.sc_err; 6303 } 6304 r = UU_WALK_ERROR; 6305 goto deltemp; 6306 } 6307 6308 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 6309 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 6310 switch (scf_error()) { 6311 case SCF_ERROR_CONNECTION_BROKEN: 6312 goto connaborted; 6313 6314 case SCF_ERROR_NO_RESOURCES: 6315 r = stash_scferror(lcbdata); 6316 goto deltemp; 6317 6318 case SCF_ERROR_EXISTS: 6319 warn(emsg_tchg, imp_tsname, inst->sc_name); 6320 lcbdata->sc_err = EBUSY; 6321 r = UU_WALK_ERROR; 6322 goto deltemp; 6323 6324 case SCF_ERROR_PERMISSION_DENIED: 6325 warn(gettext("Could not take \"%s\" snapshot of %s " 6326 "(permission denied).\n"), snap_lastimport, 6327 imp_str); 6328 r = stash_scferror(lcbdata); 6329 goto deltemp; 6330 6331 default: 6332 scfwarn(); 6333 lcbdata->sc_err = -1; 6334 r = UU_WALK_ERROR; 6335 goto deltemp; 6336 6337 case SCF_ERROR_HANDLE_MISMATCH: 6338 case SCF_ERROR_INVALID_ARGUMENT: 6339 case SCF_ERROR_NOT_SET: 6340 bad_error("_scf_snapshot_take_new_named", scf_error()); 6341 } 6342 } 6343 6344 if (lcbdata->sc_flags & SCI_FRESH) 6345 goto fresh; 6346 6347 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 6348 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6349 imp_lisnap) != 0) { 6350 switch (scf_error()) { 6351 case SCF_ERROR_DELETED: 6352 warn(emsg_del, inst->sc_parent->sc_fmri, 6353 inst->sc_name); 6354 lcbdata->sc_err = EBUSY; 6355 r = UU_WALK_ERROR; 6356 goto deltemp; 6357 6358 case SCF_ERROR_NOT_FOUND: 6359 flags |= SCI_FORCE; 6360 goto nosnap; 6361 6362 case SCF_ERROR_CONNECTION_BROKEN: 6363 goto connaborted; 6364 6365 case SCF_ERROR_INVALID_ARGUMENT: 6366 case SCF_ERROR_HANDLE_MISMATCH: 6367 case SCF_ERROR_NOT_BOUND: 6368 case SCF_ERROR_NOT_SET: 6369 default: 6370 bad_error("scf_instance_get_snapshot", 6371 scf_error()); 6372 } 6373 } 6374 6375 /* upgrade */ 6376 6377 /* 6378 * compare new properties with last-import properties 6379 * upgrade current properties 6380 */ 6381 /* clear sc_sceen for pgs */ 6382 if (uu_list_walk(inst->sc_pgroups, clear_int, 6383 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 6384 0) 6385 bad_error("uu_list_walk", uu_error()); 6386 6387 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 6388 switch (r) { 6389 case 0: 6390 break; 6391 6392 case ECONNABORTED: 6393 goto connaborted; 6394 6395 case ECANCELED: 6396 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6397 lcbdata->sc_err = EBUSY; 6398 r = UU_WALK_ERROR; 6399 goto deltemp; 6400 6401 case ENOENT: 6402 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 6403 lcbdata->sc_err = EBADF; 6404 r = UU_WALK_ERROR; 6405 goto deltemp; 6406 6407 default: 6408 bad_error("get_snaplevel", r); 6409 } 6410 6411 if (scf_instance_get_snapshot(imp_inst, snap_running, 6412 imp_rsnap) != 0) { 6413 switch (scf_error()) { 6414 case SCF_ERROR_DELETED: 6415 warn(emsg_del, inst->sc_parent->sc_fmri, 6416 inst->sc_name); 6417 lcbdata->sc_err = EBUSY; 6418 r = UU_WALK_ERROR; 6419 goto deltemp; 6420 6421 case SCF_ERROR_NOT_FOUND: 6422 break; 6423 6424 case SCF_ERROR_CONNECTION_BROKEN: 6425 goto connaborted; 6426 6427 case SCF_ERROR_INVALID_ARGUMENT: 6428 case SCF_ERROR_HANDLE_MISMATCH: 6429 case SCF_ERROR_NOT_BOUND: 6430 case SCF_ERROR_NOT_SET: 6431 default: 6432 bad_error("scf_instance_get_snapshot", 6433 scf_error()); 6434 } 6435 6436 running = NULL; 6437 } else { 6438 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 6439 switch (r) { 6440 case 0: 6441 running = imp_rsnpl; 6442 break; 6443 6444 case ECONNABORTED: 6445 goto connaborted; 6446 6447 case ECANCELED: 6448 warn(emsg_del, inst->sc_parent->sc_fmri, 6449 inst->sc_name); 6450 lcbdata->sc_err = EBUSY; 6451 r = UU_WALK_ERROR; 6452 goto deltemp; 6453 6454 case ENOENT: 6455 warn(emsg_badsnap, snap_running, inst->sc_fmri); 6456 lcbdata->sc_err = EBADF; 6457 r = UU_WALK_ERROR; 6458 goto deltemp; 6459 6460 default: 6461 bad_error("get_snaplevel", r); 6462 } 6463 } 6464 6465 r = upgrade_props(imp_inst, running, imp_snpl, inst); 6466 switch (r) { 6467 case 0: 6468 break; 6469 6470 case ECANCELED: 6471 case ENODEV: 6472 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6473 lcbdata->sc_err = EBUSY; 6474 r = UU_WALK_ERROR; 6475 goto deltemp; 6476 6477 case ECONNABORTED: 6478 goto connaborted; 6479 6480 case ENOMEM: 6481 case ENOSPC: 6482 case EBADF: 6483 case EBUSY: 6484 case EINVAL: 6485 case EPERM: 6486 case EROFS: 6487 case EACCES: 6488 case EEXIST: 6489 lcbdata->sc_err = r; 6490 r = UU_WALK_ERROR; 6491 goto deltemp; 6492 6493 default: 6494 bad_error("upgrade_props", r); 6495 } 6496 6497 inst->sc_import_state = IMPORT_PROP_DONE; 6498 } else { 6499 switch (scf_error()) { 6500 case SCF_ERROR_CONNECTION_BROKEN: 6501 goto connaborted; 6502 6503 case SCF_ERROR_NOT_FOUND: 6504 break; 6505 6506 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6507 case SCF_ERROR_HANDLE_MISMATCH: 6508 case SCF_ERROR_NOT_BOUND: 6509 case SCF_ERROR_NOT_SET: 6510 default: 6511 bad_error("scf_service_get_instance", scf_error()); 6512 } 6513 6514 fresh: 6515 /* create instance */ 6516 if (scf_service_add_instance(rsvc, inst->sc_name, 6517 imp_inst) != 0) { 6518 switch (scf_error()) { 6519 case SCF_ERROR_CONNECTION_BROKEN: 6520 goto connaborted; 6521 6522 case SCF_ERROR_NO_RESOURCES: 6523 case SCF_ERROR_BACKEND_READONLY: 6524 case SCF_ERROR_BACKEND_ACCESS: 6525 r = stash_scferror(lcbdata); 6526 goto deltemp; 6527 6528 case SCF_ERROR_EXISTS: 6529 warn(gettext("%s changed unexpectedly " 6530 "(instance \"%s\" added).\n"), 6531 inst->sc_parent->sc_fmri, inst->sc_name); 6532 lcbdata->sc_err = EBUSY; 6533 r = UU_WALK_ERROR; 6534 goto deltemp; 6535 6536 case SCF_ERROR_PERMISSION_DENIED: 6537 warn(gettext("Could not create \"%s\" instance " 6538 "in %s (permission denied).\n"), 6539 inst->sc_name, inst->sc_parent->sc_fmri); 6540 r = stash_scferror(lcbdata); 6541 goto deltemp; 6542 6543 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6544 case SCF_ERROR_HANDLE_MISMATCH: 6545 case SCF_ERROR_NOT_BOUND: 6546 case SCF_ERROR_NOT_SET: 6547 default: 6548 bad_error("scf_service_add_instance", 6549 scf_error()); 6550 } 6551 } 6552 6553 nosnap: 6554 /* 6555 * Create a last-import snapshot to serve as an attachment 6556 * point for the real one from the temporary instance. Since 6557 * the contents is irrelevant, take it now, while the instance 6558 * is empty, to minimize svc.configd's work. 6559 */ 6560 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6561 imp_lisnap) != 0) { 6562 switch (scf_error()) { 6563 case SCF_ERROR_CONNECTION_BROKEN: 6564 goto connaborted; 6565 6566 case SCF_ERROR_NO_RESOURCES: 6567 r = stash_scferror(lcbdata); 6568 goto deltemp; 6569 6570 case SCF_ERROR_EXISTS: 6571 warn(gettext("%s changed unexpectedly " 6572 "(snapshot \"%s\" added).\n"), 6573 inst->sc_fmri, snap_lastimport); 6574 lcbdata->sc_err = EBUSY; 6575 r = UU_WALK_ERROR; 6576 goto deltemp; 6577 6578 case SCF_ERROR_PERMISSION_DENIED: 6579 warn(gettext("Could not take \"%s\" snapshot " 6580 "of %s (permission denied).\n"), 6581 snap_lastimport, inst->sc_fmri); 6582 r = stash_scferror(lcbdata); 6583 goto deltemp; 6584 6585 default: 6586 scfwarn(); 6587 lcbdata->sc_err = -1; 6588 r = UU_WALK_ERROR; 6589 goto deltemp; 6590 6591 case SCF_ERROR_NOT_SET: 6592 case SCF_ERROR_INTERNAL: 6593 case SCF_ERROR_INVALID_ARGUMENT: 6594 case SCF_ERROR_HANDLE_MISMATCH: 6595 bad_error("_scf_snapshot_take_new", 6596 scf_error()); 6597 } 6598 } 6599 6600 if (li_only) 6601 goto lionly; 6602 6603 inst->sc_import_state = IMPORT_PROP_BEGUN; 6604 6605 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6606 flags); 6607 switch (r) { 6608 case 0: 6609 break; 6610 6611 case ECONNABORTED: 6612 goto connaborted; 6613 6614 case ECANCELED: 6615 warn(gettext("%s changed unexpectedly " 6616 "(instance \"%s\" deleted).\n"), 6617 inst->sc_parent->sc_fmri, inst->sc_name); 6618 lcbdata->sc_err = EBUSY; 6619 r = UU_WALK_ERROR; 6620 goto deltemp; 6621 6622 case EEXIST: 6623 warn(gettext("%s changed unexpectedly " 6624 "(property group added).\n"), inst->sc_fmri); 6625 lcbdata->sc_err = EBUSY; 6626 r = UU_WALK_ERROR; 6627 goto deltemp; 6628 6629 default: 6630 lcbdata->sc_err = r; 6631 r = UU_WALK_ERROR; 6632 goto deltemp; 6633 6634 case EINVAL: /* caught above */ 6635 bad_error("lscf_import_instance_pgs", r); 6636 } 6637 6638 ctx.sc_parent = imp_inst; 6639 ctx.sc_service = 0; 6640 ctx.sc_trans = NULL; 6641 ctx.sc_flags = 0; 6642 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6643 &ctx, UU_DEFAULT) != 0) { 6644 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6645 bad_error("uu_list_walk", uu_error()); 6646 6647 if (ctx.sc_err == ECONNABORTED) 6648 goto connaborted; 6649 lcbdata->sc_err = ctx.sc_err; 6650 r = UU_WALK_ERROR; 6651 goto deltemp; 6652 } 6653 6654 inst->sc_import_state = IMPORT_PROP_DONE; 6655 6656 if (g_verbose) 6657 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6658 snap_initial, inst->sc_fmri); 6659 r = take_snap(imp_inst, snap_initial, imp_snap); 6660 switch (r) { 6661 case 0: 6662 break; 6663 6664 case ECONNABORTED: 6665 goto connaborted; 6666 6667 case ENOSPC: 6668 case -1: 6669 lcbdata->sc_err = r; 6670 r = UU_WALK_ERROR; 6671 goto deltemp; 6672 6673 case ECANCELED: 6674 warn(gettext("%s changed unexpectedly " 6675 "(instance %s deleted).\n"), 6676 inst->sc_parent->sc_fmri, inst->sc_name); 6677 lcbdata->sc_err = r; 6678 r = UU_WALK_ERROR; 6679 goto deltemp; 6680 6681 case EPERM: 6682 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6683 lcbdata->sc_err = r; 6684 r = UU_WALK_ERROR; 6685 goto deltemp; 6686 6687 default: 6688 bad_error("take_snap", r); 6689 } 6690 } 6691 6692 lionly: 6693 if (lcbdata->sc_flags & SCI_NOSNAP) 6694 goto deltemp; 6695 6696 /* transfer snapshot from temporary instance */ 6697 if (g_verbose) 6698 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6699 snap_lastimport, inst->sc_fmri); 6700 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6701 switch (scf_error()) { 6702 case SCF_ERROR_CONNECTION_BROKEN: 6703 goto connaborted; 6704 6705 case SCF_ERROR_NO_RESOURCES: 6706 r = stash_scferror(lcbdata); 6707 goto deltemp; 6708 6709 case SCF_ERROR_PERMISSION_DENIED: 6710 warn(gettext("Could not take \"%s\" snapshot for %s " 6711 "(permission denied).\n"), snap_lastimport, 6712 inst->sc_fmri); 6713 r = stash_scferror(lcbdata); 6714 goto deltemp; 6715 6716 case SCF_ERROR_NOT_SET: 6717 case SCF_ERROR_HANDLE_MISMATCH: 6718 default: 6719 bad_error("_scf_snapshot_attach", scf_error()); 6720 } 6721 } 6722 6723 inst->sc_import_state = IMPORT_COMPLETE; 6724 6725 r = UU_WALK_NEXT; 6726 6727 deltemp: 6728 /* delete temporary instance */ 6729 if (scf_instance_delete(imp_tinst) != 0) { 6730 switch (scf_error()) { 6731 case SCF_ERROR_DELETED: 6732 break; 6733 6734 case SCF_ERROR_CONNECTION_BROKEN: 6735 goto connaborted; 6736 6737 case SCF_ERROR_NOT_SET: 6738 case SCF_ERROR_NOT_BOUND: 6739 default: 6740 bad_error("scf_instance_delete", scf_error()); 6741 } 6742 } 6743 6744 return (r); 6745 6746 connaborted: 6747 warn(gettext("Could not delete svc:/%s:%s " 6748 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6749 lcbdata->sc_err = ECONNABORTED; 6750 return (UU_WALK_ERROR); 6751 } 6752 6753 /* 6754 * If the service is missing, create it, import its properties, and import the 6755 * instances. Since the service is brand new, it should be empty, and if we 6756 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6757 * 6758 * If the service exists, we want to upgrade its properties and import the 6759 * instances. Upgrade requires a last-import snapshot, though, which are 6760 * children of instances, so first we'll have to go through the instances 6761 * looking for a last-import snapshot. If we don't find one then we'll just 6762 * override-import the service properties (but don't delete existing 6763 * properties: another service might have declared us as a dependent). Before 6764 * we change anything, though, we want to take the previous snapshots. We 6765 * also give lscf_instance_import() a leg up on taking last-import snapshots 6766 * by importing the manifest's service properties into a temporary service. 6767 * 6768 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6769 * sets lcbdata->sc_err to 6770 * ECONNABORTED - repository connection broken 6771 * ENOMEM - out of memory 6772 * ENOSPC - svc.configd is out of resources 6773 * EPERM - couldn't create temporary service (error printed) 6774 * - couldn't import into temp service (error printed) 6775 * - couldn't create service (error printed) 6776 * - couldn't import dependent (error printed) 6777 * - couldn't take snapshot (error printed) 6778 * - couldn't create instance (error printed) 6779 * - couldn't create, modify, or delete pg (error printed) 6780 * - couldn't create, modify, or delete dependent (error printed) 6781 * - couldn't import instance (error printed) 6782 * EROFS - couldn't create temporary service (repository read-only) 6783 * - couldn't import into temporary service (repository read-only) 6784 * - couldn't create service (repository read-only) 6785 * - couldn't import dependent (repository read-only) 6786 * - couldn't create instance (repository read-only) 6787 * - couldn't create, modify, or delete pg or dependent 6788 * - couldn't import instance (repository read-only) 6789 * EACCES - couldn't create temporary service (backend access denied) 6790 * - couldn't import into temporary service (backend access denied) 6791 * - couldn't create service (backend access denied) 6792 * - couldn't import dependent (backend access denied) 6793 * - couldn't create instance (backend access denied) 6794 * - couldn't create, modify, or delete pg or dependent 6795 * - couldn't import instance (backend access denied) 6796 * EINVAL - service name is invalid (error printed) 6797 * - service name is too long (error printed) 6798 * - s has invalid pgroup (error printed) 6799 * - s has invalid dependent (error printed) 6800 * - instance name is invalid (error printed) 6801 * - instance entity_t is invalid (error printed) 6802 * EEXIST - couldn't create temporary service (already exists) (error printed) 6803 * - couldn't import dependent (dependency pg already exists) (printed) 6804 * - dependency collision in dependent service (error printed) 6805 * EBUSY - temporary service deleted (error printed) 6806 * - property group added to temporary service (error printed) 6807 * - new property group changed or was deleted (error printed) 6808 * - service was added unexpectedly (error printed) 6809 * - service was deleted unexpectedly (error printed) 6810 * - property group added to new service (error printed) 6811 * - instance added unexpectedly (error printed) 6812 * - instance deleted unexpectedly (error printed) 6813 * - dependent service deleted unexpectedly (error printed) 6814 * - pg was added, changed, or deleted (error printed) 6815 * - dependent pg changed (error printed) 6816 * - temporary instance added, changed, or deleted (error printed) 6817 * EBADF - a last-import snapshot is corrupt (error printed) 6818 * - the service is corrupt (error printed) 6819 * - a dependent is corrupt (error printed) 6820 * - an instance is corrupt (error printed) 6821 * - an instance has a corrupt last-import snapshot (error printed) 6822 * - dependent target has a corrupt snapshot (error printed) 6823 * -1 - unknown libscf error (error printed) 6824 */ 6825 static int 6826 lscf_service_import(void *v, void *pvt) 6827 { 6828 entity_t *s = v; 6829 scf_callback_t cbdata; 6830 scf_callback_t *lcbdata = pvt; 6831 scf_scope_t *scope = lcbdata->sc_parent; 6832 entity_t *inst, linst; 6833 int r; 6834 int fresh = 0; 6835 scf_snaplevel_t *running; 6836 int have_ge = 0; 6837 6838 const char * const ts_deleted = gettext("Temporary service svc:/%s " 6839 "was deleted unexpectedly.\n"); 6840 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 6841 "changed unexpectedly (property group added).\n"); 6842 const char * const s_deleted = 6843 gettext("%s was deleted unexpectedly.\n"); 6844 const char * const i_deleted = 6845 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 6846 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 6847 "is corrupt (missing service snaplevel).\n"); 6848 const char * const s_mfile_upd = 6849 gettext("Unable to update the manifest file connection " 6850 "for %s\n"); 6851 6852 li_only = 0; 6853 /* Validate the service name */ 6854 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6855 switch (scf_error()) { 6856 case SCF_ERROR_CONNECTION_BROKEN: 6857 return (stash_scferror(lcbdata)); 6858 6859 case SCF_ERROR_INVALID_ARGUMENT: 6860 warn(gettext("\"%s\" is an invalid service name. " 6861 "Cannot import.\n"), s->sc_name); 6862 return (stash_scferror(lcbdata)); 6863 6864 case SCF_ERROR_NOT_FOUND: 6865 break; 6866 6867 case SCF_ERROR_HANDLE_MISMATCH: 6868 case SCF_ERROR_NOT_BOUND: 6869 case SCF_ERROR_NOT_SET: 6870 default: 6871 bad_error("scf_scope_get_service", scf_error()); 6872 } 6873 } 6874 6875 /* create temporary service */ 6876 /* 6877 * the size of the buffer was reduced to max_scf_name_len to prevent 6878 * hitting bug 6681151. After the bug fix, the size of the buffer 6879 * should be restored to its original value (max_scf_name_len +1) 6880 */ 6881 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 6882 if (r < 0) 6883 bad_error("snprintf", errno); 6884 if (r > max_scf_name_len) { 6885 warn(gettext( 6886 "Service name \"%s\" is too long. Cannot import.\n"), 6887 s->sc_name); 6888 lcbdata->sc_err = EINVAL; 6889 return (UU_WALK_ERROR); 6890 } 6891 6892 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 6893 switch (scf_error()) { 6894 case SCF_ERROR_CONNECTION_BROKEN: 6895 case SCF_ERROR_NO_RESOURCES: 6896 case SCF_ERROR_BACKEND_READONLY: 6897 case SCF_ERROR_BACKEND_ACCESS: 6898 return (stash_scferror(lcbdata)); 6899 6900 case SCF_ERROR_EXISTS: 6901 warn(gettext( 6902 "Temporary service \"%s\" must be deleted before " 6903 "this manifest can be imported.\n"), imp_tsname); 6904 return (stash_scferror(lcbdata)); 6905 6906 case SCF_ERROR_PERMISSION_DENIED: 6907 warn(gettext("Could not create temporary service " 6908 "\"%s\" (permission denied).\n"), imp_tsname); 6909 return (stash_scferror(lcbdata)); 6910 6911 case SCF_ERROR_INVALID_ARGUMENT: 6912 case SCF_ERROR_HANDLE_MISMATCH: 6913 case SCF_ERROR_NOT_BOUND: 6914 case SCF_ERROR_NOT_SET: 6915 default: 6916 bad_error("scf_scope_add_service", scf_error()); 6917 } 6918 } 6919 6920 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 6921 if (r < 0) 6922 bad_error("snprintf", errno); 6923 6924 cbdata.sc_handle = lcbdata->sc_handle; 6925 cbdata.sc_parent = imp_tsvc; 6926 cbdata.sc_service = 1; 6927 cbdata.sc_source_fmri = s->sc_fmri; 6928 cbdata.sc_target_fmri = imp_str; 6929 cbdata.sc_flags = 0; 6930 6931 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 6932 UU_DEFAULT) != 0) { 6933 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6934 bad_error("uu_list_walk", uu_error()); 6935 6936 lcbdata->sc_err = cbdata.sc_err; 6937 switch (cbdata.sc_err) { 6938 case ECONNABORTED: 6939 goto connaborted; 6940 6941 case ECANCELED: 6942 warn(ts_deleted, imp_tsname); 6943 lcbdata->sc_err = EBUSY; 6944 return (UU_WALK_ERROR); 6945 6946 case EEXIST: 6947 warn(ts_pg_added, imp_tsname); 6948 lcbdata->sc_err = EBUSY; 6949 return (UU_WALK_ERROR); 6950 } 6951 6952 r = UU_WALK_ERROR; 6953 goto deltemp; 6954 } 6955 6956 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 6957 UU_DEFAULT) != 0) { 6958 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6959 bad_error("uu_list_walk", uu_error()); 6960 6961 lcbdata->sc_err = cbdata.sc_err; 6962 switch (cbdata.sc_err) { 6963 case ECONNABORTED: 6964 goto connaborted; 6965 6966 case ECANCELED: 6967 warn(ts_deleted, imp_tsname); 6968 lcbdata->sc_err = EBUSY; 6969 return (UU_WALK_ERROR); 6970 6971 case EEXIST: 6972 warn(ts_pg_added, imp_tsname); 6973 lcbdata->sc_err = EBUSY; 6974 return (UU_WALK_ERROR); 6975 } 6976 6977 r = UU_WALK_ERROR; 6978 goto deltemp; 6979 } 6980 6981 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6982 switch (scf_error()) { 6983 case SCF_ERROR_NOT_FOUND: 6984 break; 6985 6986 case SCF_ERROR_CONNECTION_BROKEN: 6987 goto connaborted; 6988 6989 case SCF_ERROR_INVALID_ARGUMENT: 6990 case SCF_ERROR_HANDLE_MISMATCH: 6991 case SCF_ERROR_NOT_BOUND: 6992 case SCF_ERROR_NOT_SET: 6993 default: 6994 bad_error("scf_scope_get_service", scf_error()); 6995 } 6996 6997 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 6998 switch (scf_error()) { 6999 case SCF_ERROR_CONNECTION_BROKEN: 7000 goto connaborted; 7001 7002 case SCF_ERROR_NO_RESOURCES: 7003 case SCF_ERROR_BACKEND_READONLY: 7004 case SCF_ERROR_BACKEND_ACCESS: 7005 r = stash_scferror(lcbdata); 7006 goto deltemp; 7007 7008 case SCF_ERROR_EXISTS: 7009 warn(gettext("Scope \"%s\" changed unexpectedly" 7010 " (service \"%s\" added).\n"), 7011 SCF_SCOPE_LOCAL, s->sc_name); 7012 lcbdata->sc_err = EBUSY; 7013 goto deltemp; 7014 7015 case SCF_ERROR_PERMISSION_DENIED: 7016 warn(gettext("Could not create service \"%s\" " 7017 "(permission denied).\n"), s->sc_name); 7018 goto deltemp; 7019 7020 case SCF_ERROR_INVALID_ARGUMENT: 7021 case SCF_ERROR_HANDLE_MISMATCH: 7022 case SCF_ERROR_NOT_BOUND: 7023 case SCF_ERROR_NOT_SET: 7024 default: 7025 bad_error("scf_scope_add_service", scf_error()); 7026 } 7027 } 7028 7029 s->sc_import_state = IMPORT_PROP_BEGUN; 7030 7031 /* import service properties */ 7032 cbdata.sc_handle = lcbdata->sc_handle; 7033 cbdata.sc_parent = imp_svc; 7034 cbdata.sc_service = 1; 7035 cbdata.sc_flags = lcbdata->sc_flags; 7036 cbdata.sc_source_fmri = s->sc_fmri; 7037 cbdata.sc_target_fmri = s->sc_fmri; 7038 7039 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7040 &cbdata, UU_DEFAULT) != 0) { 7041 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7042 bad_error("uu_list_walk", uu_error()); 7043 7044 lcbdata->sc_err = cbdata.sc_err; 7045 switch (cbdata.sc_err) { 7046 case ECONNABORTED: 7047 goto connaborted; 7048 7049 case ECANCELED: 7050 warn(s_deleted, s->sc_fmri); 7051 lcbdata->sc_err = EBUSY; 7052 return (UU_WALK_ERROR); 7053 7054 case EEXIST: 7055 warn(gettext("%s changed unexpectedly " 7056 "(property group added).\n"), s->sc_fmri); 7057 lcbdata->sc_err = EBUSY; 7058 return (UU_WALK_ERROR); 7059 7060 case EINVAL: 7061 /* caught above */ 7062 bad_error("entity_pgroup_import", 7063 cbdata.sc_err); 7064 } 7065 7066 r = UU_WALK_ERROR; 7067 goto deltemp; 7068 } 7069 7070 cbdata.sc_trans = NULL; 7071 cbdata.sc_flags = 0; 7072 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 7073 &cbdata, UU_DEFAULT) != 0) { 7074 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7075 bad_error("uu_list_walk", uu_error()); 7076 7077 lcbdata->sc_err = cbdata.sc_err; 7078 if (cbdata.sc_err == ECONNABORTED) 7079 goto connaborted; 7080 r = UU_WALK_ERROR; 7081 goto deltemp; 7082 } 7083 7084 s->sc_import_state = IMPORT_PROP_DONE; 7085 7086 /* 7087 * This is a new service, so we can't take previous snapshots 7088 * or upgrade service properties. 7089 */ 7090 fresh = 1; 7091 goto instances; 7092 } 7093 7094 /* Clear sc_seen for the instances. */ 7095 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 7096 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 7097 bad_error("uu_list_walk", uu_error()); 7098 7099 /* 7100 * Take previous snapshots for all instances. Even for ones not 7101 * mentioned in the bundle, since we might change their service 7102 * properties. 7103 */ 7104 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7105 switch (scf_error()) { 7106 case SCF_ERROR_CONNECTION_BROKEN: 7107 goto connaborted; 7108 7109 case SCF_ERROR_DELETED: 7110 warn(s_deleted, s->sc_fmri); 7111 lcbdata->sc_err = EBUSY; 7112 r = UU_WALK_ERROR; 7113 goto deltemp; 7114 7115 case SCF_ERROR_HANDLE_MISMATCH: 7116 case SCF_ERROR_NOT_BOUND: 7117 case SCF_ERROR_NOT_SET: 7118 default: 7119 bad_error("scf_iter_service_instances", scf_error()); 7120 } 7121 } 7122 7123 for (;;) { 7124 r = scf_iter_next_instance(imp_iter, imp_inst); 7125 if (r == 0) 7126 break; 7127 if (r != 1) { 7128 switch (scf_error()) { 7129 case SCF_ERROR_DELETED: 7130 warn(s_deleted, s->sc_fmri); 7131 lcbdata->sc_err = EBUSY; 7132 r = UU_WALK_ERROR; 7133 goto deltemp; 7134 7135 case SCF_ERROR_CONNECTION_BROKEN: 7136 goto connaborted; 7137 7138 case SCF_ERROR_NOT_BOUND: 7139 case SCF_ERROR_HANDLE_MISMATCH: 7140 case SCF_ERROR_INVALID_ARGUMENT: 7141 case SCF_ERROR_NOT_SET: 7142 default: 7143 bad_error("scf_iter_next_instance", 7144 scf_error()); 7145 } 7146 } 7147 7148 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 7149 switch (scf_error()) { 7150 case SCF_ERROR_DELETED: 7151 continue; 7152 7153 case SCF_ERROR_CONNECTION_BROKEN: 7154 goto connaborted; 7155 7156 case SCF_ERROR_NOT_SET: 7157 case SCF_ERROR_NOT_BOUND: 7158 default: 7159 bad_error("scf_instance_get_name", scf_error()); 7160 } 7161 } 7162 7163 if (g_verbose) 7164 warn(gettext( 7165 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 7166 snap_previous, s->sc_name, imp_str); 7167 7168 r = take_snap(imp_inst, snap_previous, imp_snap); 7169 switch (r) { 7170 case 0: 7171 break; 7172 7173 case ECANCELED: 7174 continue; 7175 7176 case ECONNABORTED: 7177 goto connaborted; 7178 7179 case EPERM: 7180 warn(gettext("Could not take \"%s\" snapshot of " 7181 "svc:/%s:%s (permission denied).\n"), 7182 snap_previous, s->sc_name, imp_str); 7183 lcbdata->sc_err = r; 7184 return (UU_WALK_ERROR); 7185 7186 case ENOSPC: 7187 case -1: 7188 lcbdata->sc_err = r; 7189 r = UU_WALK_ERROR; 7190 goto deltemp; 7191 7192 default: 7193 bad_error("take_snap", r); 7194 } 7195 7196 linst.sc_name = imp_str; 7197 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 7198 &linst, NULL, NULL); 7199 if (inst != NULL) { 7200 inst->sc_import_state = IMPORT_PREVIOUS; 7201 inst->sc_seen = 1; 7202 } 7203 } 7204 7205 /* 7206 * Create the new instances and take previous snapshots of 7207 * them. This is not necessary, but it maximizes data preservation. 7208 */ 7209 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 7210 inst != NULL; 7211 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 7212 inst)) { 7213 if (inst->sc_seen) 7214 continue; 7215 7216 if (scf_service_add_instance(imp_svc, inst->sc_name, 7217 imp_inst) != 0) { 7218 switch (scf_error()) { 7219 case SCF_ERROR_CONNECTION_BROKEN: 7220 goto connaborted; 7221 7222 case SCF_ERROR_BACKEND_READONLY: 7223 case SCF_ERROR_BACKEND_ACCESS: 7224 case SCF_ERROR_NO_RESOURCES: 7225 r = stash_scferror(lcbdata); 7226 goto deltemp; 7227 7228 case SCF_ERROR_EXISTS: 7229 warn(gettext("%s changed unexpectedly " 7230 "(instance \"%s\" added).\n"), s->sc_fmri, 7231 inst->sc_name); 7232 lcbdata->sc_err = EBUSY; 7233 r = UU_WALK_ERROR; 7234 goto deltemp; 7235 7236 case SCF_ERROR_INVALID_ARGUMENT: 7237 warn(gettext("Service \"%s\" has instance with " 7238 "invalid name \"%s\".\n"), s->sc_name, 7239 inst->sc_name); 7240 r = stash_scferror(lcbdata); 7241 goto deltemp; 7242 7243 case SCF_ERROR_PERMISSION_DENIED: 7244 warn(gettext("Could not create instance \"%s\" " 7245 "in %s (permission denied).\n"), 7246 inst->sc_name, s->sc_fmri); 7247 r = stash_scferror(lcbdata); 7248 goto deltemp; 7249 7250 case SCF_ERROR_HANDLE_MISMATCH: 7251 case SCF_ERROR_NOT_BOUND: 7252 case SCF_ERROR_NOT_SET: 7253 default: 7254 bad_error("scf_service_add_instance", 7255 scf_error()); 7256 } 7257 } 7258 7259 if (g_verbose) 7260 warn(gettext("Taking \"%s\" snapshot for " 7261 "new service %s.\n"), snap_previous, inst->sc_fmri); 7262 r = take_snap(imp_inst, snap_previous, imp_snap); 7263 switch (r) { 7264 case 0: 7265 break; 7266 7267 case ECANCELED: 7268 warn(i_deleted, s->sc_fmri, inst->sc_name); 7269 lcbdata->sc_err = EBUSY; 7270 r = UU_WALK_ERROR; 7271 goto deltemp; 7272 7273 case ECONNABORTED: 7274 goto connaborted; 7275 7276 case EPERM: 7277 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 7278 lcbdata->sc_err = r; 7279 r = UU_WALK_ERROR; 7280 goto deltemp; 7281 7282 case ENOSPC: 7283 case -1: 7284 r = UU_WALK_ERROR; 7285 goto deltemp; 7286 7287 default: 7288 bad_error("take_snap", r); 7289 } 7290 } 7291 7292 s->sc_import_state = IMPORT_PREVIOUS; 7293 7294 /* 7295 * Upgrade service properties, if we can find a last-import snapshot. 7296 * Any will do because we don't support different service properties 7297 * in different manifests, so all snaplevels of the service in all of 7298 * the last-import snapshots of the instances should be the same. 7299 */ 7300 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7301 switch (scf_error()) { 7302 case SCF_ERROR_CONNECTION_BROKEN: 7303 goto connaborted; 7304 7305 case SCF_ERROR_DELETED: 7306 warn(s_deleted, s->sc_fmri); 7307 lcbdata->sc_err = EBUSY; 7308 r = UU_WALK_ERROR; 7309 goto deltemp; 7310 7311 case SCF_ERROR_HANDLE_MISMATCH: 7312 case SCF_ERROR_NOT_BOUND: 7313 case SCF_ERROR_NOT_SET: 7314 default: 7315 bad_error("scf_iter_service_instances", scf_error()); 7316 } 7317 } 7318 7319 for (;;) { 7320 r = scf_iter_next_instance(imp_iter, imp_inst); 7321 if (r == -1) { 7322 switch (scf_error()) { 7323 case SCF_ERROR_DELETED: 7324 warn(s_deleted, s->sc_fmri); 7325 lcbdata->sc_err = EBUSY; 7326 r = UU_WALK_ERROR; 7327 goto deltemp; 7328 7329 case SCF_ERROR_CONNECTION_BROKEN: 7330 goto connaborted; 7331 7332 case SCF_ERROR_NOT_BOUND: 7333 case SCF_ERROR_HANDLE_MISMATCH: 7334 case SCF_ERROR_INVALID_ARGUMENT: 7335 case SCF_ERROR_NOT_SET: 7336 default: 7337 bad_error("scf_iter_next_instance", 7338 scf_error()); 7339 } 7340 } 7341 7342 if (r == 0) { 7343 /* 7344 * Didn't find any last-import snapshots. Override- 7345 * import the properties. Unless one of the instances 7346 * has a general/enabled property, in which case we're 7347 * probably running a last-import-capable svccfg for 7348 * the first time, and we should only take the 7349 * last-import snapshot. 7350 */ 7351 if (have_ge) { 7352 pgroup_t *mfpg; 7353 scf_callback_t mfcbdata; 7354 7355 li_only = 1; 7356 no_refresh = 1; 7357 /* 7358 * Need to go ahead and import the manifestfiles 7359 * pg if it exists. If the last-import snapshot 7360 * upgrade code is ever removed this code can 7361 * be removed as well. 7362 */ 7363 mfpg = internal_pgroup_find(s, 7364 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 7365 7366 if (mfpg) { 7367 mfcbdata.sc_handle = g_hndl; 7368 mfcbdata.sc_parent = imp_svc; 7369 mfcbdata.sc_service = 1; 7370 mfcbdata.sc_flags = SCI_FORCE; 7371 mfcbdata.sc_source_fmri = s->sc_fmri; 7372 mfcbdata.sc_target_fmri = s->sc_fmri; 7373 if (entity_pgroup_import(mfpg, 7374 &mfcbdata) != UU_WALK_NEXT) { 7375 warn(s_mfile_upd, s->sc_fmri); 7376 r = UU_WALK_ERROR; 7377 goto deltemp; 7378 } 7379 } 7380 break; 7381 } 7382 7383 s->sc_import_state = IMPORT_PROP_BEGUN; 7384 7385 cbdata.sc_handle = g_hndl; 7386 cbdata.sc_parent = imp_svc; 7387 cbdata.sc_service = 1; 7388 cbdata.sc_flags = SCI_FORCE; 7389 cbdata.sc_source_fmri = s->sc_fmri; 7390 cbdata.sc_target_fmri = s->sc_fmri; 7391 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7392 &cbdata, UU_DEFAULT) != 0) { 7393 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7394 bad_error("uu_list_walk", uu_error()); 7395 lcbdata->sc_err = cbdata.sc_err; 7396 switch (cbdata.sc_err) { 7397 case ECONNABORTED: 7398 goto connaborted; 7399 7400 case ECANCELED: 7401 warn(s_deleted, s->sc_fmri); 7402 lcbdata->sc_err = EBUSY; 7403 break; 7404 7405 case EINVAL: /* caught above */ 7406 case EEXIST: 7407 bad_error("entity_pgroup_import", 7408 cbdata.sc_err); 7409 } 7410 7411 r = UU_WALK_ERROR; 7412 goto deltemp; 7413 } 7414 7415 cbdata.sc_trans = NULL; 7416 cbdata.sc_flags = 0; 7417 if (uu_list_walk(s->sc_dependents, 7418 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 7419 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7420 bad_error("uu_list_walk", uu_error()); 7421 lcbdata->sc_err = cbdata.sc_err; 7422 if (cbdata.sc_err == ECONNABORTED) 7423 goto connaborted; 7424 r = UU_WALK_ERROR; 7425 goto deltemp; 7426 } 7427 break; 7428 } 7429 7430 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 7431 imp_snap) != 0) { 7432 switch (scf_error()) { 7433 case SCF_ERROR_DELETED: 7434 continue; 7435 7436 case SCF_ERROR_NOT_FOUND: 7437 break; 7438 7439 case SCF_ERROR_CONNECTION_BROKEN: 7440 goto connaborted; 7441 7442 case SCF_ERROR_HANDLE_MISMATCH: 7443 case SCF_ERROR_NOT_BOUND: 7444 case SCF_ERROR_INVALID_ARGUMENT: 7445 case SCF_ERROR_NOT_SET: 7446 default: 7447 bad_error("scf_instance_get_snapshot", 7448 scf_error()); 7449 } 7450 7451 if (have_ge) 7452 continue; 7453 7454 /* 7455 * Check for a general/enabled property. This is how 7456 * we tell whether to import if there turn out to be 7457 * no last-import snapshots. 7458 */ 7459 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 7460 imp_pg) == 0) { 7461 if (scf_pg_get_property(imp_pg, 7462 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 7463 have_ge = 1; 7464 } else { 7465 switch (scf_error()) { 7466 case SCF_ERROR_DELETED: 7467 case SCF_ERROR_NOT_FOUND: 7468 continue; 7469 7470 case SCF_ERROR_INVALID_ARGUMENT: 7471 case SCF_ERROR_HANDLE_MISMATCH: 7472 case SCF_ERROR_CONNECTION_BROKEN: 7473 case SCF_ERROR_NOT_BOUND: 7474 case SCF_ERROR_NOT_SET: 7475 default: 7476 bad_error("scf_pg_get_property", 7477 scf_error()); 7478 } 7479 } 7480 } else { 7481 switch (scf_error()) { 7482 case SCF_ERROR_DELETED: 7483 case SCF_ERROR_NOT_FOUND: 7484 continue; 7485 7486 case SCF_ERROR_CONNECTION_BROKEN: 7487 goto connaborted; 7488 7489 case SCF_ERROR_NOT_BOUND: 7490 case SCF_ERROR_NOT_SET: 7491 case SCF_ERROR_INVALID_ARGUMENT: 7492 case SCF_ERROR_HANDLE_MISMATCH: 7493 default: 7494 bad_error("scf_instance_get_pg", 7495 scf_error()); 7496 } 7497 } 7498 continue; 7499 } 7500 7501 /* find service snaplevel */ 7502 r = get_snaplevel(imp_snap, 1, imp_snpl); 7503 switch (r) { 7504 case 0: 7505 break; 7506 7507 case ECONNABORTED: 7508 goto connaborted; 7509 7510 case ECANCELED: 7511 continue; 7512 7513 case ENOENT: 7514 if (scf_instance_get_name(imp_inst, imp_str, 7515 imp_str_sz) < 0) 7516 (void) strcpy(imp_str, "?"); 7517 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 7518 lcbdata->sc_err = EBADF; 7519 r = UU_WALK_ERROR; 7520 goto deltemp; 7521 7522 default: 7523 bad_error("get_snaplevel", r); 7524 } 7525 7526 if (scf_instance_get_snapshot(imp_inst, snap_running, 7527 imp_rsnap) != 0) { 7528 switch (scf_error()) { 7529 case SCF_ERROR_DELETED: 7530 continue; 7531 7532 case SCF_ERROR_NOT_FOUND: 7533 break; 7534 7535 case SCF_ERROR_CONNECTION_BROKEN: 7536 goto connaborted; 7537 7538 case SCF_ERROR_INVALID_ARGUMENT: 7539 case SCF_ERROR_HANDLE_MISMATCH: 7540 case SCF_ERROR_NOT_BOUND: 7541 case SCF_ERROR_NOT_SET: 7542 default: 7543 bad_error("scf_instance_get_snapshot", 7544 scf_error()); 7545 } 7546 running = NULL; 7547 } else { 7548 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7549 switch (r) { 7550 case 0: 7551 running = imp_rsnpl; 7552 break; 7553 7554 case ECONNABORTED: 7555 goto connaborted; 7556 7557 case ECANCELED: 7558 continue; 7559 7560 case ENOENT: 7561 if (scf_instance_get_name(imp_inst, imp_str, 7562 imp_str_sz) < 0) 7563 (void) strcpy(imp_str, "?"); 7564 warn(badsnap, snap_running, s->sc_name, 7565 imp_str); 7566 lcbdata->sc_err = EBADF; 7567 r = UU_WALK_ERROR; 7568 goto deltemp; 7569 7570 default: 7571 bad_error("get_snaplevel", r); 7572 } 7573 } 7574 7575 if (g_verbose) { 7576 if (scf_instance_get_name(imp_inst, imp_str, 7577 imp_str_sz) < 0) 7578 (void) strcpy(imp_str, "?"); 7579 warn(gettext("Upgrading properties of %s according to " 7580 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7581 } 7582 7583 /* upgrade service properties */ 7584 r = upgrade_props(imp_svc, running, imp_snpl, s); 7585 if (r == 0) 7586 break; 7587 7588 switch (r) { 7589 case ECONNABORTED: 7590 goto connaborted; 7591 7592 case ECANCELED: 7593 warn(s_deleted, s->sc_fmri); 7594 lcbdata->sc_err = EBUSY; 7595 break; 7596 7597 case ENODEV: 7598 if (scf_instance_get_name(imp_inst, imp_str, 7599 imp_str_sz) < 0) 7600 (void) strcpy(imp_str, "?"); 7601 warn(i_deleted, s->sc_fmri, imp_str); 7602 lcbdata->sc_err = EBUSY; 7603 break; 7604 7605 default: 7606 lcbdata->sc_err = r; 7607 } 7608 7609 r = UU_WALK_ERROR; 7610 goto deltemp; 7611 } 7612 7613 s->sc_import_state = IMPORT_PROP_DONE; 7614 7615 instances: 7616 /* import instances */ 7617 cbdata.sc_handle = lcbdata->sc_handle; 7618 cbdata.sc_parent = imp_svc; 7619 cbdata.sc_service = 1; 7620 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7621 cbdata.sc_general = NULL; 7622 7623 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7624 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7625 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7626 bad_error("uu_list_walk", uu_error()); 7627 7628 lcbdata->sc_err = cbdata.sc_err; 7629 if (cbdata.sc_err == ECONNABORTED) 7630 goto connaborted; 7631 r = UU_WALK_ERROR; 7632 goto deltemp; 7633 } 7634 7635 s->sc_import_state = IMPORT_COMPLETE; 7636 r = UU_WALK_NEXT; 7637 7638 deltemp: 7639 /* delete temporary service */ 7640 if (scf_service_delete(imp_tsvc) != 0) { 7641 switch (scf_error()) { 7642 case SCF_ERROR_DELETED: 7643 break; 7644 7645 case SCF_ERROR_CONNECTION_BROKEN: 7646 goto connaborted; 7647 7648 case SCF_ERROR_EXISTS: 7649 warn(gettext( 7650 "Could not delete svc:/%s (instances exist).\n"), 7651 imp_tsname); 7652 break; 7653 7654 case SCF_ERROR_NOT_SET: 7655 case SCF_ERROR_NOT_BOUND: 7656 default: 7657 bad_error("scf_service_delete", scf_error()); 7658 } 7659 } 7660 7661 return (r); 7662 7663 connaborted: 7664 warn(gettext("Could not delete svc:/%s " 7665 "(repository connection broken).\n"), imp_tsname); 7666 lcbdata->sc_err = ECONNABORTED; 7667 return (UU_WALK_ERROR); 7668 } 7669 7670 static const char * 7671 import_progress(int st) 7672 { 7673 switch (st) { 7674 case 0: 7675 return (gettext("not reached.")); 7676 7677 case IMPORT_PREVIOUS: 7678 return (gettext("previous snapshot taken.")); 7679 7680 case IMPORT_PROP_BEGUN: 7681 return (gettext("some properties imported.")); 7682 7683 case IMPORT_PROP_DONE: 7684 return (gettext("properties imported.")); 7685 7686 case IMPORT_COMPLETE: 7687 return (gettext("imported.")); 7688 7689 case IMPORT_REFRESHED: 7690 return (gettext("refresh requested.")); 7691 7692 default: 7693 #ifndef NDEBUG 7694 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7695 __FILE__, __LINE__, st); 7696 #endif 7697 abort(); 7698 /* NOTREACHED */ 7699 } 7700 } 7701 7702 /* 7703 * Returns 7704 * 0 - success 7705 * - fmri wasn't found (error printed) 7706 * - entity was deleted (error printed) 7707 * - backend denied access (error printed) 7708 * ENOMEM - out of memory (error printed) 7709 * ECONNABORTED - repository connection broken (error printed) 7710 * EPERM - permission denied (error printed) 7711 * -1 - unknown libscf error (error printed) 7712 */ 7713 static int 7714 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7715 { 7716 scf_error_t serr; 7717 void *ent; 7718 int issvc; 7719 int r; 7720 7721 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7722 const char *dpt_deleted = gettext("Could not refresh %s " 7723 "(dependent \"%s\" of %s) (deleted).\n"); 7724 7725 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7726 switch (serr) { 7727 case SCF_ERROR_NONE: 7728 break; 7729 7730 case SCF_ERROR_NO_MEMORY: 7731 if (name == NULL) 7732 warn(gettext("Could not refresh %s (out of memory).\n"), 7733 fmri); 7734 else 7735 warn(gettext("Could not refresh %s " 7736 "(dependent \"%s\" of %s) (out of memory).\n"), 7737 fmri, name, d_fmri); 7738 return (ENOMEM); 7739 7740 case SCF_ERROR_NOT_FOUND: 7741 if (name == NULL) 7742 warn(deleted, fmri); 7743 else 7744 warn(dpt_deleted, fmri, name, d_fmri); 7745 return (0); 7746 7747 case SCF_ERROR_INVALID_ARGUMENT: 7748 case SCF_ERROR_CONSTRAINT_VIOLATED: 7749 default: 7750 bad_error("fmri_to_entity", serr); 7751 } 7752 7753 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7754 switch (r) { 7755 case 0: 7756 break; 7757 7758 case ECONNABORTED: 7759 if (name != NULL) 7760 warn(gettext("Could not refresh %s " 7761 "(dependent \"%s\" of %s) " 7762 "(repository connection broken).\n"), fmri, name, 7763 d_fmri); 7764 return (r); 7765 7766 case ECANCELED: 7767 if (name == NULL) 7768 warn(deleted, fmri); 7769 else 7770 warn(dpt_deleted, fmri, name, d_fmri); 7771 return (0); 7772 7773 case EACCES: 7774 if (!g_verbose) 7775 return (0); 7776 if (name == NULL) 7777 warn(gettext("Could not refresh %s " 7778 "(backend access denied).\n"), fmri); 7779 else 7780 warn(gettext("Could not refresh %s " 7781 "(dependent \"%s\" of %s) " 7782 "(backend access denied).\n"), fmri, name, d_fmri); 7783 return (0); 7784 7785 case EPERM: 7786 if (name == NULL) 7787 warn(gettext("Could not refresh %s " 7788 "(permission denied).\n"), fmri); 7789 else 7790 warn(gettext("Could not refresh %s " 7791 "(dependent \"%s\" of %s) " 7792 "(permission denied).\n"), fmri, name, d_fmri); 7793 return (r); 7794 7795 case ENOSPC: 7796 if (name == NULL) 7797 warn(gettext("Could not refresh %s " 7798 "(repository server out of resources).\n"), 7799 fmri); 7800 else 7801 warn(gettext("Could not refresh %s " 7802 "(dependent \"%s\" of %s) " 7803 "(repository server out of resources).\n"), 7804 fmri, name, d_fmri); 7805 return (r); 7806 7807 case -1: 7808 scfwarn(); 7809 return (r); 7810 7811 default: 7812 bad_error("refresh_entity", r); 7813 } 7814 7815 if (issvc) 7816 scf_service_destroy(ent); 7817 else 7818 scf_instance_destroy(ent); 7819 7820 return (0); 7821 } 7822 7823 static int 7824 alloc_imp_globals() 7825 { 7826 int r; 7827 7828 const char * const emsg_nomem = gettext("Out of memory.\n"); 7829 const char * const emsg_nores = 7830 gettext("svc.configd is out of resources.\n"); 7831 7832 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 7833 max_scf_name_len : max_scf_fmri_len) + 1; 7834 7835 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 7836 (imp_svc = scf_service_create(g_hndl)) == NULL || 7837 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 7838 (imp_inst = scf_instance_create(g_hndl)) == NULL || 7839 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 7840 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 7841 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 7842 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 7843 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 7844 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7845 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 7846 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7847 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 7848 (imp_prop = scf_property_create(g_hndl)) == NULL || 7849 (imp_iter = scf_iter_create(g_hndl)) == NULL || 7850 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 7851 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 7852 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 7853 (imp_str = malloc(imp_str_sz)) == NULL || 7854 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 7855 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 7856 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 7857 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 7858 (ud_inst = scf_instance_create(g_hndl)) == NULL || 7859 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7860 (ud_pg = scf_pg_create(g_hndl)) == NULL || 7861 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 7862 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 7863 (ud_prop = scf_property_create(g_hndl)) == NULL || 7864 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 7865 (ud_val = scf_value_create(g_hndl)) == NULL || 7866 (ud_iter = scf_iter_create(g_hndl)) == NULL || 7867 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 7868 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 7869 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 7870 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 7871 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 7872 if (scf_error() == SCF_ERROR_NO_RESOURCES) 7873 warn(emsg_nores); 7874 else 7875 warn(emsg_nomem); 7876 7877 return (-1); 7878 } 7879 7880 r = load_init(); 7881 switch (r) { 7882 case 0: 7883 break; 7884 7885 case ENOMEM: 7886 warn(emsg_nomem); 7887 return (-1); 7888 7889 default: 7890 bad_error("load_init", r); 7891 } 7892 7893 return (0); 7894 } 7895 7896 static void 7897 free_imp_globals() 7898 { 7899 pgroup_t *old_dpt; 7900 void *cookie; 7901 7902 load_fini(); 7903 7904 free(ud_ctarg); 7905 free(ud_oldtarg); 7906 free(ud_name); 7907 ud_ctarg = ud_oldtarg = ud_name = NULL; 7908 7909 scf_transaction_destroy(ud_tx); 7910 ud_tx = NULL; 7911 scf_iter_destroy(ud_iter); 7912 scf_iter_destroy(ud_iter2); 7913 ud_iter = ud_iter2 = NULL; 7914 scf_value_destroy(ud_val); 7915 ud_val = NULL; 7916 scf_property_destroy(ud_prop); 7917 scf_property_destroy(ud_dpt_prop); 7918 ud_prop = ud_dpt_prop = NULL; 7919 scf_pg_destroy(ud_pg); 7920 scf_pg_destroy(ud_cur_depts_pg); 7921 scf_pg_destroy(ud_run_dpts_pg); 7922 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7923 scf_snaplevel_destroy(ud_snpl); 7924 ud_snpl = NULL; 7925 scf_instance_destroy(ud_inst); 7926 ud_inst = NULL; 7927 7928 free(imp_str); 7929 free(imp_tsname); 7930 free(imp_fe1); 7931 free(imp_fe2); 7932 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7933 7934 cookie = NULL; 7935 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7936 NULL) { 7937 free((char *)old_dpt->sc_pgroup_name); 7938 free((char *)old_dpt->sc_pgroup_fmri); 7939 internal_pgroup_free(old_dpt); 7940 } 7941 uu_list_destroy(imp_deleted_dpts); 7942 7943 scf_transaction_destroy(imp_tx); 7944 imp_tx = NULL; 7945 scf_iter_destroy(imp_iter); 7946 scf_iter_destroy(imp_rpg_iter); 7947 scf_iter_destroy(imp_up_iter); 7948 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7949 scf_property_destroy(imp_prop); 7950 imp_prop = NULL; 7951 scf_pg_destroy(imp_pg); 7952 scf_pg_destroy(imp_pg2); 7953 imp_pg = imp_pg2 = NULL; 7954 scf_snaplevel_destroy(imp_snpl); 7955 scf_snaplevel_destroy(imp_rsnpl); 7956 imp_snpl = imp_rsnpl = NULL; 7957 scf_snapshot_destroy(imp_snap); 7958 scf_snapshot_destroy(imp_lisnap); 7959 scf_snapshot_destroy(imp_tlisnap); 7960 scf_snapshot_destroy(imp_rsnap); 7961 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7962 scf_instance_destroy(imp_inst); 7963 scf_instance_destroy(imp_tinst); 7964 imp_inst = imp_tinst = NULL; 7965 scf_service_destroy(imp_svc); 7966 scf_service_destroy(imp_tsvc); 7967 imp_svc = imp_tsvc = NULL; 7968 scf_scope_destroy(imp_scope); 7969 imp_scope = NULL; 7970 7971 load_fini(); 7972 } 7973 7974 int 7975 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 7976 { 7977 scf_callback_t cbdata; 7978 int result = 0; 7979 entity_t *svc, *inst; 7980 uu_list_t *insts; 7981 int r; 7982 pgroup_t *old_dpt; 7983 int annotation_set = 0; 7984 7985 const char * const emsg_nomem = gettext("Out of memory.\n"); 7986 const char * const emsg_nores = 7987 gettext("svc.configd is out of resources.\n"); 7988 7989 lscf_prep_hndl(); 7990 7991 if (alloc_imp_globals()) 7992 goto out; 7993 7994 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 7995 switch (scf_error()) { 7996 case SCF_ERROR_CONNECTION_BROKEN: 7997 warn(gettext("Repository connection broken.\n")); 7998 repository_teardown(); 7999 result = -1; 8000 goto out; 8001 8002 case SCF_ERROR_NOT_FOUND: 8003 case SCF_ERROR_INVALID_ARGUMENT: 8004 case SCF_ERROR_NOT_BOUND: 8005 case SCF_ERROR_HANDLE_MISMATCH: 8006 default: 8007 bad_error("scf_handle_get_scope", scf_error()); 8008 } 8009 } 8010 8011 /* Set up the auditing annotation. */ 8012 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 8013 annotation_set = 1; 8014 } else { 8015 switch (scf_error()) { 8016 case SCF_ERROR_CONNECTION_BROKEN: 8017 warn(gettext("Repository connection broken.\n")); 8018 repository_teardown(); 8019 result = -1; 8020 goto out; 8021 8022 case SCF_ERROR_INVALID_ARGUMENT: 8023 case SCF_ERROR_NOT_BOUND: 8024 case SCF_ERROR_NO_RESOURCES: 8025 case SCF_ERROR_INTERNAL: 8026 bad_error("_scf_set_annotation", scf_error()); 8027 /* NOTREACHED */ 8028 8029 default: 8030 /* 8031 * Do not terminate import because of inability to 8032 * generate annotation audit event. 8033 */ 8034 warn(gettext("_scf_set_annotation() unexpectedly " 8035 "failed with return code of %d\n"), scf_error()); 8036 break; 8037 } 8038 } 8039 8040 /* 8041 * Clear the sc_import_state's of all services & instances so we can 8042 * report how far we got if we fail. 8043 */ 8044 for (svc = uu_list_first(bndl->sc_bundle_services); 8045 svc != NULL; 8046 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8047 svc->sc_import_state = 0; 8048 8049 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 8050 clear_int, (void *)offsetof(entity_t, sc_import_state), 8051 UU_DEFAULT) != 0) 8052 bad_error("uu_list_walk", uu_error()); 8053 } 8054 8055 cbdata.sc_handle = g_hndl; 8056 cbdata.sc_parent = imp_scope; 8057 cbdata.sc_flags = flags; 8058 cbdata.sc_general = NULL; 8059 8060 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 8061 &cbdata, UU_DEFAULT) == 0) { 8062 /* Success. Refresh everything. */ 8063 8064 if (flags & SCI_NOREFRESH || no_refresh) { 8065 no_refresh = 0; 8066 result = 0; 8067 goto out; 8068 } 8069 8070 for (svc = uu_list_first(bndl->sc_bundle_services); 8071 svc != NULL; 8072 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8073 pgroup_t *dpt; 8074 8075 insts = svc->sc_u.sc_service.sc_service_instances; 8076 8077 for (inst = uu_list_first(insts); 8078 inst != NULL; 8079 inst = uu_list_next(insts, inst)) { 8080 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 8081 switch (r) { 8082 case 0: 8083 break; 8084 8085 case ENOMEM: 8086 case ECONNABORTED: 8087 case EPERM: 8088 case -1: 8089 goto progress; 8090 8091 default: 8092 bad_error("imp_refresh_fmri", r); 8093 } 8094 8095 inst->sc_import_state = IMPORT_REFRESHED; 8096 8097 for (dpt = uu_list_first(inst->sc_dependents); 8098 dpt != NULL; 8099 dpt = uu_list_next(inst->sc_dependents, 8100 dpt)) 8101 if (imp_refresh_fmri( 8102 dpt->sc_pgroup_fmri, 8103 dpt->sc_pgroup_name, 8104 inst->sc_fmri) != 0) 8105 goto progress; 8106 } 8107 8108 for (dpt = uu_list_first(svc->sc_dependents); 8109 dpt != NULL; 8110 dpt = uu_list_next(svc->sc_dependents, dpt)) 8111 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 8112 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 8113 goto progress; 8114 } 8115 8116 for (old_dpt = uu_list_first(imp_deleted_dpts); 8117 old_dpt != NULL; 8118 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 8119 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8120 old_dpt->sc_pgroup_name, 8121 old_dpt->sc_parent->sc_fmri) != 0) 8122 goto progress; 8123 8124 result = 0; 8125 goto out; 8126 } 8127 8128 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8129 bad_error("uu_list_walk", uu_error()); 8130 8131 printerr: 8132 /* If the error hasn't been printed yet, do so here. */ 8133 switch (cbdata.sc_err) { 8134 case ECONNABORTED: 8135 warn(gettext("Repository connection broken.\n")); 8136 break; 8137 8138 case ENOMEM: 8139 warn(emsg_nomem); 8140 break; 8141 8142 case ENOSPC: 8143 warn(emsg_nores); 8144 break; 8145 8146 case EROFS: 8147 warn(gettext("Repository is read-only.\n")); 8148 break; 8149 8150 case EACCES: 8151 warn(gettext("Repository backend denied access.\n")); 8152 break; 8153 8154 case EPERM: 8155 case EINVAL: 8156 case EEXIST: 8157 case EBUSY: 8158 case EBADF: 8159 case -1: 8160 break; 8161 8162 default: 8163 bad_error("lscf_service_import", cbdata.sc_err); 8164 } 8165 8166 progress: 8167 warn(gettext("Import of %s failed. Progress:\n"), filename); 8168 8169 for (svc = uu_list_first(bndl->sc_bundle_services); 8170 svc != NULL; 8171 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8172 insts = svc->sc_u.sc_service.sc_service_instances; 8173 8174 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 8175 import_progress(svc->sc_import_state)); 8176 8177 for (inst = uu_list_first(insts); 8178 inst != NULL; 8179 inst = uu_list_next(insts, inst)) 8180 warn(gettext(" Instance \"%s\": %s\n"), 8181 inst->sc_name, 8182 import_progress(inst->sc_import_state)); 8183 } 8184 8185 if (cbdata.sc_err == ECONNABORTED) 8186 repository_teardown(); 8187 8188 8189 result = -1; 8190 8191 out: 8192 if (annotation_set != 0) { 8193 /* Turn off annotation. It is no longer needed. */ 8194 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8195 } 8196 8197 free_imp_globals(); 8198 8199 return (result); 8200 } 8201 8202 /* 8203 * _lscf_import_err() summarize the error handling returned by 8204 * lscf_import_{instance | service}_pgs 8205 * Return values are: 8206 * IMPORT_NEXT 8207 * IMPORT_OUT 8208 * IMPORT_BAD 8209 */ 8210 8211 #define IMPORT_BAD -1 8212 #define IMPORT_NEXT 0 8213 #define IMPORT_OUT 1 8214 8215 static int 8216 _lscf_import_err(int err, const char *fmri) 8217 { 8218 switch (err) { 8219 case 0: 8220 if (g_verbose) 8221 warn(gettext("%s updated.\n"), fmri); 8222 return (IMPORT_NEXT); 8223 8224 case ECONNABORTED: 8225 warn(gettext("Could not update %s " 8226 "(repository connection broken).\n"), fmri); 8227 return (IMPORT_OUT); 8228 8229 case ENOMEM: 8230 warn(gettext("Could not update %s (out of memory).\n"), fmri); 8231 return (IMPORT_OUT); 8232 8233 case ENOSPC: 8234 warn(gettext("Could not update %s " 8235 "(repository server out of resources).\n"), fmri); 8236 return (IMPORT_OUT); 8237 8238 case ECANCELED: 8239 warn(gettext( 8240 "Could not update %s (deleted).\n"), fmri); 8241 return (IMPORT_NEXT); 8242 8243 case EPERM: 8244 case EINVAL: 8245 case EBUSY: 8246 return (IMPORT_NEXT); 8247 8248 case EROFS: 8249 warn(gettext("Could not update %s (repository read-only).\n"), 8250 fmri); 8251 return (IMPORT_OUT); 8252 8253 case EACCES: 8254 warn(gettext("Could not update %s " 8255 "(backend access denied).\n"), fmri); 8256 return (IMPORT_NEXT); 8257 8258 case EEXIST: 8259 default: 8260 return (IMPORT_BAD); 8261 } 8262 8263 /*NOTREACHED*/ 8264 } 8265 8266 /* 8267 * The global imp_svc and imp_inst should be set by the caller in the 8268 * check to make sure the service and instance exist that the apply is 8269 * working on. 8270 */ 8271 static int 8272 lscf_dependent_apply(void *dpg, void *e) 8273 { 8274 scf_callback_t cb; 8275 pgroup_t *dpt_pgroup = dpg; 8276 pgroup_t *deldpt; 8277 entity_t *ent = e; 8278 int tissvc; 8279 void *sc_ent, *tent; 8280 scf_error_t serr; 8281 int r; 8282 8283 const char * const dependents = "dependents"; 8284 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT); 8285 8286 if (issvc) 8287 sc_ent = imp_svc; 8288 else 8289 sc_ent = imp_inst; 8290 8291 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg, 8292 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 || 8293 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name, 8294 imp_prop) != 0) { 8295 switch (scf_error()) { 8296 case SCF_ERROR_NOT_FOUND: 8297 case SCF_ERROR_DELETED: 8298 break; 8299 8300 case SCF_ERROR_CONNECTION_BROKEN: 8301 case SCF_ERROR_NOT_SET: 8302 case SCF_ERROR_INVALID_ARGUMENT: 8303 case SCF_ERROR_HANDLE_MISMATCH: 8304 case SCF_ERROR_NOT_BOUND: 8305 default: 8306 bad_error("entity_get_pg", scf_error()); 8307 } 8308 } else { 8309 /* 8310 * Found the dependents/<wip dep> so check to 8311 * see if the service is different. If so 8312 * store the service for later refresh, and 8313 * delete the wip dependency from the service 8314 */ 8315 if (scf_property_get_value(imp_prop, ud_val) != 0) { 8316 switch (scf_error()) { 8317 case SCF_ERROR_DELETED: 8318 break; 8319 8320 case SCF_ERROR_CONNECTION_BROKEN: 8321 case SCF_ERROR_NOT_SET: 8322 case SCF_ERROR_INVALID_ARGUMENT: 8323 case SCF_ERROR_HANDLE_MISMATCH: 8324 case SCF_ERROR_NOT_BOUND: 8325 default: 8326 bad_error("scf_property_get_value", 8327 scf_error()); 8328 } 8329 } 8330 8331 if (scf_value_get_as_string(ud_val, ud_oldtarg, 8332 max_scf_value_len + 1) < 0) 8333 bad_error("scf_value_get_as_string", scf_error()); 8334 8335 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 8336 switch (r) { 8337 case 1: 8338 break; 8339 case 0: 8340 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent, 8341 &tissvc)) != SCF_ERROR_NONE) { 8342 if (serr == SCF_ERROR_NOT_FOUND) { 8343 break; 8344 } else { 8345 bad_error("fmri_to_entity", serr); 8346 } 8347 } 8348 8349 if (entity_get_pg(tent, tissvc, 8350 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) { 8351 serr = scf_error(); 8352 if (serr == SCF_ERROR_NOT_FOUND || 8353 serr == SCF_ERROR_DELETED) { 8354 break; 8355 } else { 8356 bad_error("entity_get_pg", scf_error()); 8357 } 8358 } 8359 8360 if (scf_pg_delete(imp_pg) != 0) { 8361 serr = scf_error(); 8362 if (serr == SCF_ERROR_NOT_FOUND || 8363 serr == SCF_ERROR_DELETED) { 8364 break; 8365 } else { 8366 bad_error("scf_pg_delete", scf_error()); 8367 } 8368 } 8369 8370 deldpt = internal_pgroup_new(); 8371 if (deldpt == NULL) 8372 return (ENOMEM); 8373 deldpt->sc_pgroup_name = 8374 strdup(dpt_pgroup->sc_pgroup_name); 8375 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg); 8376 if (deldpt->sc_pgroup_name == NULL || 8377 deldpt->sc_pgroup_fmri == NULL) 8378 return (ENOMEM); 8379 deldpt->sc_parent = (entity_t *)ent; 8380 if (uu_list_insert_after(imp_deleted_dpts, NULL, 8381 deldpt) != 0) 8382 uu_die(gettext("libuutil error: %s\n"), 8383 uu_strerror(uu_error())); 8384 8385 break; 8386 default: 8387 bad_error("fmri_equal", r); 8388 } 8389 } 8390 8391 cb.sc_handle = g_hndl; 8392 cb.sc_parent = ent; 8393 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT; 8394 cb.sc_source_fmri = ent->sc_fmri; 8395 cb.sc_target_fmri = ent->sc_fmri; 8396 cb.sc_trans = NULL; 8397 cb.sc_flags = SCI_FORCE; 8398 8399 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT) 8400 return (UU_WALK_ERROR); 8401 8402 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL); 8403 switch (r) { 8404 case 0: 8405 break; 8406 8407 case ENOMEM: 8408 case ECONNABORTED: 8409 case EPERM: 8410 case -1: 8411 warn(gettext("Unable to refresh \"%s\"\n"), 8412 dpt_pgroup->sc_pgroup_fmri); 8413 return (UU_WALK_ERROR); 8414 8415 default: 8416 bad_error("imp_refresh_fmri", r); 8417 } 8418 8419 return (UU_WALK_NEXT); 8420 } 8421 8422 /* 8423 * Returns 8424 * 0 - success 8425 * -1 - lscf_import_instance_pgs() failed. 8426 */ 8427 int 8428 lscf_bundle_apply(bundle_t *bndl, const char *file) 8429 { 8430 pgroup_t *old_dpt; 8431 entity_t *svc, *inst; 8432 int annotation_set = 0; 8433 int ret = 0; 8434 int r = 0; 8435 8436 lscf_prep_hndl(); 8437 8438 if ((ret = alloc_imp_globals())) 8439 goto out; 8440 8441 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) 8442 scfdie(); 8443 8444 /* 8445 * Set the strings to be used for the security audit annotation 8446 * event. 8447 */ 8448 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 8449 annotation_set = 1; 8450 } else { 8451 switch (scf_error()) { 8452 case SCF_ERROR_CONNECTION_BROKEN: 8453 warn(gettext("Repository connection broken.\n")); 8454 goto out; 8455 8456 case SCF_ERROR_INVALID_ARGUMENT: 8457 case SCF_ERROR_NOT_BOUND: 8458 case SCF_ERROR_NO_RESOURCES: 8459 case SCF_ERROR_INTERNAL: 8460 bad_error("_scf_set_annotation", scf_error()); 8461 /* NOTREACHED */ 8462 8463 default: 8464 /* 8465 * Do not abort apply operation because of 8466 * inability to create annotation audit event. 8467 */ 8468 warn(gettext("_scf_set_annotation() unexpectedly " 8469 "failed with return code of %d\n"), scf_error()); 8470 break; 8471 } 8472 } 8473 8474 for (svc = uu_list_first(bndl->sc_bundle_services); 8475 svc != NULL; 8476 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8477 int refresh = 0; 8478 8479 if (scf_scope_get_service(imp_scope, svc->sc_name, 8480 imp_svc) != 0) { 8481 switch (scf_error()) { 8482 case SCF_ERROR_NOT_FOUND: 8483 if (g_verbose) 8484 warn(gettext("Ignoring nonexistent " 8485 "service %s.\n"), svc->sc_name); 8486 continue; 8487 8488 default: 8489 scfdie(); 8490 } 8491 } 8492 8493 /* 8494 * If there were missing types in the profile, then need to 8495 * attempt to find the types. 8496 */ 8497 if (svc->sc_miss_type) { 8498 if (uu_list_numnodes(svc->sc_pgroups) && 8499 uu_list_walk(svc->sc_pgroups, find_current_pg_type, 8500 svc, UU_DEFAULT) != 0) { 8501 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8502 bad_error("uu_list_walk", uu_error()); 8503 8504 ret = -1; 8505 continue; 8506 } 8507 8508 for (inst = uu_list_first( 8509 svc->sc_u.sc_service.sc_service_instances); 8510 inst != NULL; 8511 inst = uu_list_next( 8512 svc->sc_u.sc_service.sc_service_instances, inst)) { 8513 /* 8514 * If the instance doesn't exist just 8515 * skip to the next instance and let the 8516 * import note the missing instance. 8517 */ 8518 if (scf_service_get_instance(imp_svc, 8519 inst->sc_name, imp_inst) != 0) 8520 continue; 8521 8522 if (uu_list_walk(inst->sc_pgroups, 8523 find_current_pg_type, inst, 8524 UU_DEFAULT) != 0) { 8525 if (uu_error() != 8526 UU_ERROR_CALLBACK_FAILED) 8527 bad_error("uu_list_walk", 8528 uu_error()); 8529 8530 ret = -1; 8531 inst->sc_miss_type = B_TRUE; 8532 } 8533 } 8534 } 8535 8536 /* 8537 * if we have pgs in the profile, we need to refresh ALL 8538 * instances of the service 8539 */ 8540 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 8541 refresh = 1; 8542 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc, 8543 SCI_FORCE | SCI_KEEP); 8544 switch (_lscf_import_err(r, svc->sc_fmri)) { 8545 case IMPORT_NEXT: 8546 break; 8547 8548 case IMPORT_OUT: 8549 goto out; 8550 8551 case IMPORT_BAD: 8552 default: 8553 bad_error("lscf_import_service_pgs", r); 8554 } 8555 } 8556 8557 if (uu_list_numnodes(svc->sc_dependents) != 0) { 8558 uu_list_walk(svc->sc_dependents, 8559 lscf_dependent_apply, svc, UU_DEFAULT); 8560 } 8561 8562 for (inst = uu_list_first( 8563 svc->sc_u.sc_service.sc_service_instances); 8564 inst != NULL; 8565 inst = uu_list_next( 8566 svc->sc_u.sc_service.sc_service_instances, inst)) { 8567 /* 8568 * This instance still has missing types 8569 * so skip it. 8570 */ 8571 if (inst->sc_miss_type) { 8572 if (g_verbose) 8573 warn(gettext("Ignoring instance " 8574 "%s:%s with missing types\n"), 8575 inst->sc_parent->sc_name, 8576 inst->sc_name); 8577 8578 continue; 8579 } 8580 8581 if (scf_service_get_instance(imp_svc, inst->sc_name, 8582 imp_inst) != 0) { 8583 switch (scf_error()) { 8584 case SCF_ERROR_NOT_FOUND: 8585 if (g_verbose) 8586 warn(gettext("Ignoring " 8587 "nonexistant instance " 8588 "%s:%s.\n"), 8589 inst->sc_parent->sc_name, 8590 inst->sc_name); 8591 continue; 8592 8593 default: 8594 scfdie(); 8595 } 8596 } 8597 8598 /* 8599 * If the instance does not have a general/enabled 8600 * property and no last-import snapshot then the 8601 * instance is not a fully installed instance and 8602 * should not have a profile applied to it. 8603 * 8604 * This could happen if a service/instance declares 8605 * a dependent on behalf of another service/instance. 8606 * 8607 */ 8608 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 8609 imp_snap) != 0) { 8610 if (scf_instance_get_pg(imp_inst, 8611 SCF_PG_GENERAL, imp_pg) != 0 || 8612 scf_pg_get_property(imp_pg, 8613 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 8614 if (g_verbose) 8615 warn(gettext("Ignoreing " 8616 "partial instance " 8617 "%s:%s.\n"), 8618 inst->sc_parent->sc_name, 8619 inst->sc_name); 8620 continue; 8621 } 8622 } 8623 8624 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, 8625 inst, SCI_FORCE | SCI_KEEP); 8626 switch (_lscf_import_err(r, inst->sc_fmri)) { 8627 case IMPORT_NEXT: 8628 break; 8629 8630 case IMPORT_OUT: 8631 goto out; 8632 8633 case IMPORT_BAD: 8634 default: 8635 bad_error("lscf_import_instance_pgs", r); 8636 } 8637 8638 if (uu_list_numnodes(inst->sc_dependents) != 0) { 8639 uu_list_walk(inst->sc_dependents, 8640 lscf_dependent_apply, inst, UU_DEFAULT); 8641 } 8642 8643 /* refresh only if there is no pgs in the service */ 8644 if (refresh == 0) 8645 (void) refresh_entity(0, imp_inst, 8646 inst->sc_fmri, NULL, NULL, NULL); 8647 } 8648 8649 if (refresh == 1) { 8650 char *name_buf = safe_malloc(max_scf_name_len + 1); 8651 8652 (void) refresh_entity(1, imp_svc, svc->sc_name, 8653 imp_inst, imp_iter, name_buf); 8654 free(name_buf); 8655 } 8656 8657 for (old_dpt = uu_list_first(imp_deleted_dpts); 8658 old_dpt != NULL; 8659 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) { 8660 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8661 old_dpt->sc_pgroup_name, 8662 old_dpt->sc_parent->sc_fmri) != 0) { 8663 warn(gettext("Unable to refresh \"%s\"\n"), 8664 old_dpt->sc_pgroup_fmri); 8665 } 8666 } 8667 } 8668 8669 out: 8670 if (annotation_set) { 8671 /* Remove security audit annotation strings. */ 8672 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8673 } 8674 8675 free_imp_globals(); 8676 return (ret); 8677 } 8678 8679 8680 /* 8681 * Export. These functions create and output an XML tree of a service 8682 * description from the repository. This is largely the inverse of 8683 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 8684 * 8685 * - We must include any properties which are not represented specifically by 8686 * a service manifest, e.g., properties created by an admin post-import. To 8687 * do so we'll iterate through all properties and deal with each 8688 * apropriately. 8689 * 8690 * - Children of services and instances must must be in the order set by the 8691 * DTD, but we iterate over the properties in undefined order. The elements 8692 * are not easily (or efficiently) sortable by name. Since there's a fixed 8693 * number of classes of them, however, we'll keep the classes separate and 8694 * assemble them in order. 8695 */ 8696 8697 /* 8698 * Convenience function to handle xmlSetProp errors (and type casting). 8699 */ 8700 static void 8701 safe_setprop(xmlNodePtr n, const char *name, const char *val) 8702 { 8703 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 8704 uu_die(gettext("Could not set XML property.\n")); 8705 } 8706 8707 /* 8708 * Convenience function to set an XML attribute to the single value of an 8709 * astring property. If the value happens to be the default, don't set the 8710 * attribute. "dval" should be the default value supplied by the DTD, or 8711 * NULL for no default. 8712 */ 8713 static int 8714 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 8715 const char *name, const char *dval) 8716 { 8717 scf_value_t *val; 8718 ssize_t len; 8719 char *str; 8720 8721 val = scf_value_create(g_hndl); 8722 if (val == NULL) 8723 scfdie(); 8724 8725 if (prop_get_val(prop, val) != 0) { 8726 scf_value_destroy(val); 8727 return (-1); 8728 } 8729 8730 len = scf_value_get_as_string(val, NULL, 0); 8731 if (len < 0) 8732 scfdie(); 8733 8734 str = safe_malloc(len + 1); 8735 8736 if (scf_value_get_as_string(val, str, len + 1) < 0) 8737 scfdie(); 8738 8739 scf_value_destroy(val); 8740 8741 if (dval == NULL || strcmp(str, dval) != 0) 8742 safe_setprop(n, name, str); 8743 8744 free(str); 8745 8746 return (0); 8747 } 8748 8749 /* 8750 * As above, but the attribute is always set. 8751 */ 8752 static int 8753 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 8754 { 8755 return (set_attr_from_prop_default(prop, n, name, NULL)); 8756 } 8757 8758 /* 8759 * Dump the given document onto f, with "'s replaced by ''s. 8760 */ 8761 static int 8762 write_service_bundle(xmlDocPtr doc, FILE *f) 8763 { 8764 xmlChar *mem; 8765 int sz, i; 8766 8767 mem = NULL; 8768 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 8769 8770 if (mem == NULL) { 8771 semerr(gettext("Could not dump XML tree.\n")); 8772 return (-1); 8773 } 8774 8775 /* 8776 * Fortunately libxml produces " instead of ", so we can blindly 8777 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 8778 * ' code?! 8779 */ 8780 for (i = 0; i < sz; ++i) { 8781 char c = (char)mem[i]; 8782 8783 if (c == '"') 8784 (void) fputc('\'', f); 8785 else if (c == '\'') 8786 (void) fwrite("'", sizeof ("'") - 1, 1, f); 8787 else 8788 (void) fputc(c, f); 8789 } 8790 8791 return (0); 8792 } 8793 8794 /* 8795 * Create the DOM elements in elts necessary to (generically) represent prop 8796 * (i.e., a property or propval element). If the name of the property is 8797 * known, it should be passed as name_arg. Otherwise, pass NULL. 8798 */ 8799 static void 8800 export_property(scf_property_t *prop, const char *name_arg, 8801 struct pg_elts *elts, int flags) 8802 { 8803 const char *type; 8804 scf_error_t err = 0; 8805 xmlNodePtr pnode, lnode; 8806 char *lnname; 8807 int ret; 8808 8809 /* name */ 8810 if (name_arg != NULL) { 8811 (void) strcpy(exp_str, name_arg); 8812 } else { 8813 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 8814 scfdie(); 8815 } 8816 8817 /* type */ 8818 type = prop_to_typestr(prop); 8819 if (type == NULL) 8820 uu_die(gettext("Can't export property %s: unknown type.\n"), 8821 exp_str); 8822 8823 /* If we're exporting values, and there's just one, export it here. */ 8824 if (!(flags & SCE_ALL_VALUES)) 8825 goto empty; 8826 8827 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 8828 xmlNodePtr n; 8829 8830 /* Single value, so use propval */ 8831 n = xmlNewNode(NULL, (xmlChar *)"propval"); 8832 if (n == NULL) 8833 uu_die(emsg_create_xml); 8834 8835 safe_setprop(n, name_attr, exp_str); 8836 safe_setprop(n, type_attr, type); 8837 8838 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8839 scfdie(); 8840 safe_setprop(n, value_attr, exp_str); 8841 8842 if (elts->propvals == NULL) 8843 elts->propvals = n; 8844 else 8845 (void) xmlAddSibling(elts->propvals, n); 8846 8847 return; 8848 } 8849 8850 err = scf_error(); 8851 8852 if (err == SCF_ERROR_PERMISSION_DENIED) { 8853 semerr(emsg_permission_denied); 8854 return; 8855 } 8856 8857 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 8858 err != SCF_ERROR_NOT_FOUND && 8859 err != SCF_ERROR_PERMISSION_DENIED) 8860 scfdie(); 8861 8862 empty: 8863 /* Multiple (or no) values, so use property */ 8864 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 8865 if (pnode == NULL) 8866 uu_die(emsg_create_xml); 8867 8868 safe_setprop(pnode, name_attr, exp_str); 8869 safe_setprop(pnode, type_attr, type); 8870 8871 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 8872 lnname = uu_msprintf("%s_list", type); 8873 if (lnname == NULL) 8874 uu_die(gettext("Could not create string")); 8875 8876 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 8877 if (lnode == NULL) 8878 uu_die(emsg_create_xml); 8879 8880 uu_free(lnname); 8881 8882 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 8883 scfdie(); 8884 8885 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 8886 1) { 8887 xmlNodePtr vn; 8888 8889 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 8890 NULL); 8891 if (vn == NULL) 8892 uu_die(emsg_create_xml); 8893 8894 if (scf_value_get_as_string(exp_val, exp_str, 8895 exp_str_sz) < 0) 8896 scfdie(); 8897 safe_setprop(vn, value_attr, exp_str); 8898 } 8899 if (ret != 0) 8900 scfdie(); 8901 } 8902 8903 if (elts->properties == NULL) 8904 elts->properties = pnode; 8905 else 8906 (void) xmlAddSibling(elts->properties, pnode); 8907 } 8908 8909 /* 8910 * Add a property_group element for this property group to elts. 8911 */ 8912 static void 8913 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 8914 { 8915 xmlNodePtr n; 8916 struct pg_elts elts; 8917 int ret; 8918 boolean_t read_protected; 8919 8920 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 8921 8922 /* name */ 8923 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8924 scfdie(); 8925 safe_setprop(n, name_attr, exp_str); 8926 8927 /* type */ 8928 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 8929 scfdie(); 8930 safe_setprop(n, type_attr, exp_str); 8931 8932 /* properties */ 8933 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8934 scfdie(); 8935 8936 (void) memset(&elts, 0, sizeof (elts)); 8937 8938 /* 8939 * If this property group is not read protected, we always want to 8940 * output all the values. Otherwise, we only output the values if the 8941 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 8942 */ 8943 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 8944 scfdie(); 8945 8946 if (!read_protected) 8947 flags |= SCE_ALL_VALUES; 8948 8949 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8950 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8951 scfdie(); 8952 8953 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8954 xmlNodePtr m; 8955 8956 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8957 if (m == NULL) 8958 uu_die(emsg_create_xml); 8959 8960 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8961 elts.stability = m; 8962 continue; 8963 } 8964 8965 xmlFreeNode(m); 8966 } 8967 8968 export_property(exp_prop, NULL, &elts, flags); 8969 } 8970 if (ret == -1) 8971 scfdie(); 8972 8973 (void) xmlAddChild(n, elts.stability); 8974 (void) xmlAddChildList(n, elts.propvals); 8975 (void) xmlAddChildList(n, elts.properties); 8976 8977 if (eelts->property_groups == NULL) 8978 eelts->property_groups = n; 8979 else 8980 (void) xmlAddSibling(eelts->property_groups, n); 8981 } 8982 8983 /* 8984 * Create an XML node representing the dependency described by the given 8985 * property group and put it in eelts. Unless the dependency is not valid, in 8986 * which case create a generic property_group element which represents it and 8987 * put it in eelts. 8988 */ 8989 static void 8990 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 8991 { 8992 xmlNodePtr n; 8993 int err = 0, ret; 8994 struct pg_elts elts; 8995 8996 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 8997 if (n == NULL) 8998 uu_die(emsg_create_xml); 8999 9000 /* 9001 * If the external flag is present, skip this dependency because it 9002 * should have been created by another manifest. 9003 */ 9004 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 9005 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9006 prop_get_val(exp_prop, exp_val) == 0) { 9007 uint8_t b; 9008 9009 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 9010 scfdie(); 9011 9012 if (b) 9013 return; 9014 } 9015 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 9016 scfdie(); 9017 9018 /* Get the required attributes. */ 9019 9020 /* name */ 9021 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9022 scfdie(); 9023 safe_setprop(n, name_attr, exp_str); 9024 9025 /* grouping */ 9026 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9027 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9028 err = 1; 9029 9030 /* restart_on */ 9031 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9032 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9033 err = 1; 9034 9035 /* type */ 9036 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9037 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9038 err = 1; 9039 9040 /* 9041 * entities: Not required, but if we create no children, it will be 9042 * created as empty on import, so fail if it's missing. 9043 */ 9044 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9045 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 9046 scf_iter_t *eiter; 9047 int ret2; 9048 9049 eiter = scf_iter_create(g_hndl); 9050 if (eiter == NULL) 9051 scfdie(); 9052 9053 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 9054 scfdie(); 9055 9056 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 9057 xmlNodePtr ch; 9058 9059 if (scf_value_get_astring(exp_val, exp_str, 9060 exp_str_sz) < 0) 9061 scfdie(); 9062 9063 /* 9064 * service_fmri's must be first, so we can add them 9065 * here. 9066 */ 9067 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 9068 NULL); 9069 if (ch == NULL) 9070 uu_die(emsg_create_xml); 9071 9072 safe_setprop(ch, value_attr, exp_str); 9073 } 9074 if (ret2 == -1) 9075 scfdie(); 9076 9077 scf_iter_destroy(eiter); 9078 } else 9079 err = 1; 9080 9081 if (err) { 9082 xmlFreeNode(n); 9083 9084 export_pg(pg, eelts, 0); 9085 9086 return; 9087 } 9088 9089 /* Iterate through the properties & handle each. */ 9090 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9091 scfdie(); 9092 9093 (void) memset(&elts, 0, sizeof (elts)); 9094 9095 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9096 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9097 scfdie(); 9098 9099 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9100 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9101 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9102 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9103 continue; 9104 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9105 xmlNodePtr m; 9106 9107 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9108 if (m == NULL) 9109 uu_die(emsg_create_xml); 9110 9111 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9112 elts.stability = m; 9113 continue; 9114 } 9115 9116 xmlFreeNode(m); 9117 } 9118 9119 export_property(exp_prop, exp_str, &elts, 0); 9120 } 9121 if (ret == -1) 9122 scfdie(); 9123 9124 (void) xmlAddChild(n, elts.stability); 9125 (void) xmlAddChildList(n, elts.propvals); 9126 (void) xmlAddChildList(n, elts.properties); 9127 9128 if (eelts->dependencies == NULL) 9129 eelts->dependencies = n; 9130 else 9131 (void) xmlAddSibling(eelts->dependencies, n); 9132 } 9133 9134 static xmlNodePtr 9135 export_method_environment(scf_propertygroup_t *pg) 9136 { 9137 xmlNodePtr env; 9138 int ret; 9139 int children = 0; 9140 9141 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 9142 return (NULL); 9143 9144 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 9145 if (env == NULL) 9146 uu_die(emsg_create_xml); 9147 9148 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 9149 scfdie(); 9150 9151 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 9152 scfdie(); 9153 9154 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 9155 xmlNodePtr ev; 9156 char *cp; 9157 9158 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9159 scfdie(); 9160 9161 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 9162 warn(gettext("Invalid environment variable \"%s\".\n"), 9163 exp_str); 9164 continue; 9165 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 9166 warn(gettext("Invalid environment variable \"%s\"; " 9167 "\"SMF_\" prefix is reserved.\n"), exp_str); 9168 continue; 9169 } 9170 9171 *cp = '\0'; 9172 cp++; 9173 9174 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 9175 if (ev == NULL) 9176 uu_die(emsg_create_xml); 9177 9178 safe_setprop(ev, name_attr, exp_str); 9179 safe_setprop(ev, value_attr, cp); 9180 children++; 9181 } 9182 9183 if (ret != 0) 9184 scfdie(); 9185 9186 if (children == 0) { 9187 xmlFreeNode(env); 9188 return (NULL); 9189 } 9190 9191 return (env); 9192 } 9193 9194 /* 9195 * As above, but for a method property group. 9196 */ 9197 static void 9198 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 9199 { 9200 xmlNodePtr n, env; 9201 char *str; 9202 int err = 0, nonenv, ret; 9203 uint8_t use_profile; 9204 struct pg_elts elts; 9205 xmlNodePtr ctxt = NULL; 9206 9207 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 9208 9209 /* Get the required attributes. */ 9210 9211 /* name */ 9212 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9213 scfdie(); 9214 safe_setprop(n, name_attr, exp_str); 9215 9216 /* type */ 9217 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9218 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9219 err = 1; 9220 9221 /* exec */ 9222 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 9223 set_attr_from_prop(exp_prop, n, "exec") != 0) 9224 err = 1; 9225 9226 /* timeout */ 9227 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 9228 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 9229 prop_get_val(exp_prop, exp_val) == 0) { 9230 uint64_t c; 9231 9232 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 9233 scfdie(); 9234 9235 str = uu_msprintf("%llu", c); 9236 if (str == NULL) 9237 uu_die(gettext("Could not create string")); 9238 9239 safe_setprop(n, "timeout_seconds", str); 9240 free(str); 9241 } else 9242 err = 1; 9243 9244 if (err) { 9245 xmlFreeNode(n); 9246 9247 export_pg(pg, eelts, 0); 9248 9249 return; 9250 } 9251 9252 9253 /* 9254 * If we're going to have a method_context child, we need to know 9255 * before we iterate through the properties. Since method_context's 9256 * are optional, we don't want to complain about any properties 9257 * missing if none of them are there. Thus we can't use the 9258 * convenience functions. 9259 */ 9260 nonenv = 9261 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 9262 SCF_SUCCESS || 9263 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 9264 SCF_SUCCESS || 9265 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 9266 SCF_SUCCESS || 9267 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 9268 SCF_SUCCESS; 9269 9270 if (nonenv) { 9271 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9272 if (ctxt == NULL) 9273 uu_die(emsg_create_xml); 9274 9275 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 9276 0 && 9277 set_attr_from_prop_default(exp_prop, ctxt, 9278 "working_directory", ":default") != 0) 9279 err = 1; 9280 9281 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 9282 set_attr_from_prop_default(exp_prop, ctxt, "project", 9283 ":default") != 0) 9284 err = 1; 9285 9286 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 9287 0 && 9288 set_attr_from_prop_default(exp_prop, ctxt, 9289 "resource_pool", ":default") != 0) 9290 err = 1; 9291 /* 9292 * We only want to complain about profile or credential 9293 * properties if we will use them. To determine that we must 9294 * examine USE_PROFILE. 9295 */ 9296 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9297 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9298 prop_get_val(exp_prop, exp_val) == 0) { 9299 if (scf_value_get_boolean(exp_val, &use_profile) != 9300 SCF_SUCCESS) { 9301 scfdie(); 9302 } 9303 9304 if (use_profile) { 9305 xmlNodePtr prof; 9306 9307 prof = xmlNewChild(ctxt, NULL, 9308 (xmlChar *)"method_profile", NULL); 9309 if (prof == NULL) 9310 uu_die(emsg_create_xml); 9311 9312 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 9313 exp_prop) != 0 || 9314 set_attr_from_prop(exp_prop, prof, 9315 name_attr) != 0) 9316 err = 1; 9317 } else { 9318 xmlNodePtr cred; 9319 9320 cred = xmlNewChild(ctxt, NULL, 9321 (xmlChar *)"method_credential", NULL); 9322 if (cred == NULL) 9323 uu_die(emsg_create_xml); 9324 9325 if (pg_get_prop(pg, SCF_PROPERTY_USER, 9326 exp_prop) != 0 || 9327 set_attr_from_prop(exp_prop, cred, 9328 "user") != 0) { 9329 err = 1; 9330 } 9331 9332 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 9333 exp_prop) == 0 && 9334 set_attr_from_prop_default(exp_prop, cred, 9335 "group", ":default") != 0) 9336 err = 1; 9337 9338 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 9339 exp_prop) == 0 && 9340 set_attr_from_prop_default(exp_prop, cred, 9341 "supp_groups", ":default") != 0) 9342 err = 1; 9343 9344 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 9345 exp_prop) == 0 && 9346 set_attr_from_prop_default(exp_prop, cred, 9347 "privileges", ":default") != 0) 9348 err = 1; 9349 9350 if (pg_get_prop(pg, 9351 SCF_PROPERTY_LIMIT_PRIVILEGES, 9352 exp_prop) == 0 && 9353 set_attr_from_prop_default(exp_prop, cred, 9354 "limit_privileges", ":default") != 0) 9355 err = 1; 9356 } 9357 } 9358 } 9359 9360 if ((env = export_method_environment(pg)) != NULL) { 9361 if (ctxt == NULL) { 9362 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9363 if (ctxt == NULL) 9364 uu_die(emsg_create_xml); 9365 } 9366 (void) xmlAddChild(ctxt, env); 9367 } 9368 9369 if (env != NULL || (nonenv && err == 0)) 9370 (void) xmlAddChild(n, ctxt); 9371 else 9372 xmlFreeNode(ctxt); 9373 9374 nonenv = (err == 0); 9375 9376 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9377 scfdie(); 9378 9379 (void) memset(&elts, 0, sizeof (elts)); 9380 9381 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9382 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9383 scfdie(); 9384 9385 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9386 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 9387 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 9388 continue; 9389 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9390 xmlNodePtr m; 9391 9392 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9393 if (m == NULL) 9394 uu_die(emsg_create_xml); 9395 9396 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9397 elts.stability = m; 9398 continue; 9399 } 9400 9401 xmlFreeNode(m); 9402 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 9403 0 || 9404 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 9405 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 9406 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9407 if (nonenv) 9408 continue; 9409 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 9410 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 9411 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 9412 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 9413 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 9414 if (nonenv && !use_profile) 9415 continue; 9416 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9417 if (nonenv && use_profile) 9418 continue; 9419 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 9420 if (env != NULL) 9421 continue; 9422 } 9423 9424 export_property(exp_prop, exp_str, &elts, 0); 9425 } 9426 if (ret == -1) 9427 scfdie(); 9428 9429 (void) xmlAddChild(n, elts.stability); 9430 (void) xmlAddChildList(n, elts.propvals); 9431 (void) xmlAddChildList(n, elts.properties); 9432 9433 if (eelts->exec_methods == NULL) 9434 eelts->exec_methods = n; 9435 else 9436 (void) xmlAddSibling(eelts->exec_methods, n); 9437 } 9438 9439 static void 9440 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 9441 struct entity_elts *eelts) 9442 { 9443 xmlNodePtr pgnode; 9444 9445 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 9446 if (pgnode == NULL) 9447 uu_die(emsg_create_xml); 9448 9449 safe_setprop(pgnode, name_attr, name); 9450 safe_setprop(pgnode, type_attr, type); 9451 9452 (void) xmlAddChildList(pgnode, elts->propvals); 9453 (void) xmlAddChildList(pgnode, elts->properties); 9454 9455 if (eelts->property_groups == NULL) 9456 eelts->property_groups = pgnode; 9457 else 9458 (void) xmlAddSibling(eelts->property_groups, pgnode); 9459 } 9460 9461 /* 9462 * Process the general property group for a service. This is the one with the 9463 * goodies. 9464 */ 9465 static void 9466 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 9467 { 9468 struct pg_elts elts; 9469 int ret; 9470 9471 /* 9472 * In case there are properties which don't correspond to child 9473 * entities of the service entity, we'll set up a pg_elts structure to 9474 * put them in. 9475 */ 9476 (void) memset(&elts, 0, sizeof (elts)); 9477 9478 /* Walk the properties, looking for special ones. */ 9479 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9480 scfdie(); 9481 9482 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9483 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9484 scfdie(); 9485 9486 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 9487 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9488 prop_get_val(exp_prop, exp_val) == 0) { 9489 uint8_t b; 9490 9491 if (scf_value_get_boolean(exp_val, &b) != 9492 SCF_SUCCESS) 9493 scfdie(); 9494 9495 if (b) { 9496 selts->single_instance = 9497 xmlNewNode(NULL, 9498 (xmlChar *)"single_instance"); 9499 if (selts->single_instance == NULL) 9500 uu_die(emsg_create_xml); 9501 } 9502 9503 continue; 9504 } 9505 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9506 xmlNodePtr rnode, sfnode; 9507 9508 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9509 if (rnode == NULL) 9510 uu_die(emsg_create_xml); 9511 9512 sfnode = xmlNewChild(rnode, NULL, 9513 (xmlChar *)"service_fmri", NULL); 9514 if (sfnode == NULL) 9515 uu_die(emsg_create_xml); 9516 9517 if (set_attr_from_prop(exp_prop, sfnode, 9518 value_attr) == 0) { 9519 selts->restarter = rnode; 9520 continue; 9521 } 9522 9523 xmlFreeNode(rnode); 9524 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 9525 0) { 9526 xmlNodePtr s; 9527 9528 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9529 if (s == NULL) 9530 uu_die(emsg_create_xml); 9531 9532 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9533 selts->stability = s; 9534 continue; 9535 } 9536 9537 xmlFreeNode(s); 9538 } 9539 9540 export_property(exp_prop, exp_str, &elts, 0); 9541 } 9542 if (ret == -1) 9543 scfdie(); 9544 9545 if (elts.propvals != NULL || elts.properties != NULL) 9546 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 9547 selts); 9548 } 9549 9550 static void 9551 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 9552 { 9553 xmlNodePtr n, prof, cred, env; 9554 uint8_t use_profile; 9555 int ret, err = 0; 9556 9557 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 9558 9559 env = export_method_environment(pg); 9560 9561 /* Need to know whether we'll use a profile or not. */ 9562 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9563 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9564 prop_get_val(exp_prop, exp_val) == 0) { 9565 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 9566 scfdie(); 9567 9568 if (use_profile) 9569 prof = 9570 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 9571 NULL); 9572 else 9573 cred = 9574 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 9575 NULL); 9576 } 9577 9578 if (env != NULL) 9579 (void) xmlAddChild(n, env); 9580 9581 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9582 scfdie(); 9583 9584 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9585 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9586 scfdie(); 9587 9588 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 9589 if (set_attr_from_prop(exp_prop, n, 9590 "working_directory") != 0) 9591 err = 1; 9592 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 9593 if (set_attr_from_prop(exp_prop, n, "project") != 0) 9594 err = 1; 9595 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 9596 if (set_attr_from_prop(exp_prop, n, 9597 "resource_pool") != 0) 9598 err = 1; 9599 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9600 /* EMPTY */ 9601 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 9602 if (use_profile || 9603 set_attr_from_prop(exp_prop, cred, "user") != 0) 9604 err = 1; 9605 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 9606 if (use_profile || 9607 set_attr_from_prop(exp_prop, cred, "group") != 0) 9608 err = 1; 9609 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 9610 if (use_profile || set_attr_from_prop(exp_prop, cred, 9611 "supp_groups") != 0) 9612 err = 1; 9613 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 9614 if (use_profile || set_attr_from_prop(exp_prop, cred, 9615 "privileges") != 0) 9616 err = 1; 9617 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 9618 0) { 9619 if (use_profile || set_attr_from_prop(exp_prop, cred, 9620 "limit_privileges") != 0) 9621 err = 1; 9622 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9623 if (!use_profile || set_attr_from_prop(exp_prop, 9624 prof, name_attr) != 0) 9625 err = 1; 9626 } else { 9627 /* Can't have generic properties in method_context's */ 9628 err = 1; 9629 } 9630 } 9631 if (ret == -1) 9632 scfdie(); 9633 9634 if (err && env == NULL) { 9635 xmlFreeNode(n); 9636 export_pg(pg, elts, 0); 9637 return; 9638 } 9639 9640 elts->method_context = n; 9641 } 9642 9643 /* 9644 * Given a dependency property group in the tfmri entity (target fmri), return 9645 * a dependent element which represents it. 9646 */ 9647 static xmlNodePtr 9648 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 9649 { 9650 uint8_t b; 9651 xmlNodePtr n, sf; 9652 int err = 0, ret; 9653 struct pg_elts pgelts; 9654 9655 /* 9656 * If external isn't set to true then exporting the service will 9657 * export this as a normal dependency, so we should stop to avoid 9658 * duplication. 9659 */ 9660 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 9661 scf_property_get_value(exp_prop, exp_val) != 0 || 9662 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 9663 if (g_verbose) { 9664 warn(gettext("Dependent \"%s\" cannot be exported " 9665 "properly because the \"%s\" property of the " 9666 "\"%s\" dependency of %s is not set to true.\n"), 9667 name, scf_property_external, name, tfmri); 9668 } 9669 9670 return (NULL); 9671 } 9672 9673 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 9674 if (n == NULL) 9675 uu_die(emsg_create_xml); 9676 9677 safe_setprop(n, name_attr, name); 9678 9679 /* Get the required attributes */ 9680 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9681 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9682 err = 1; 9683 9684 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9685 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9686 err = 1; 9687 9688 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9689 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 9690 prop_get_val(exp_prop, exp_val) == 0) { 9691 /* EMPTY */ 9692 } else 9693 err = 1; 9694 9695 if (err) { 9696 xmlFreeNode(n); 9697 return (NULL); 9698 } 9699 9700 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 9701 if (sf == NULL) 9702 uu_die(emsg_create_xml); 9703 9704 safe_setprop(sf, value_attr, tfmri); 9705 9706 /* 9707 * Now add elements for the other properties. 9708 */ 9709 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9710 scfdie(); 9711 9712 (void) memset(&pgelts, 0, sizeof (pgelts)); 9713 9714 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9715 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9716 scfdie(); 9717 9718 if (strcmp(exp_str, scf_property_external) == 0 || 9719 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9720 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9721 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9722 continue; 9723 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 9724 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 9725 prop_get_val(exp_prop, exp_val) == 0) { 9726 char type[sizeof ("service") + 1]; 9727 9728 if (scf_value_get_astring(exp_val, type, 9729 sizeof (type)) < 0) 9730 scfdie(); 9731 9732 if (strcmp(type, "service") == 0) 9733 continue; 9734 } 9735 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9736 xmlNodePtr s; 9737 9738 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9739 if (s == NULL) 9740 uu_die(emsg_create_xml); 9741 9742 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9743 pgelts.stability = s; 9744 continue; 9745 } 9746 9747 xmlFreeNode(s); 9748 } 9749 9750 export_property(exp_prop, exp_str, &pgelts, 0); 9751 } 9752 if (ret == -1) 9753 scfdie(); 9754 9755 (void) xmlAddChild(n, pgelts.stability); 9756 (void) xmlAddChildList(n, pgelts.propvals); 9757 (void) xmlAddChildList(n, pgelts.properties); 9758 9759 return (n); 9760 } 9761 9762 static void 9763 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 9764 { 9765 scf_propertygroup_t *opg; 9766 scf_iter_t *iter; 9767 char *type, *fmri; 9768 int ret; 9769 struct pg_elts pgelts; 9770 xmlNodePtr n; 9771 scf_error_t serr; 9772 9773 if ((opg = scf_pg_create(g_hndl)) == NULL || 9774 (iter = scf_iter_create(g_hndl)) == NULL) 9775 scfdie(); 9776 9777 /* Can't use exp_prop_iter due to export_dependent(). */ 9778 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 9779 scfdie(); 9780 9781 type = safe_malloc(max_scf_pg_type_len + 1); 9782 9783 /* Get an extra byte so we can tell if values are too long. */ 9784 fmri = safe_malloc(max_scf_fmri_len + 2); 9785 9786 (void) memset(&pgelts, 0, sizeof (pgelts)); 9787 9788 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 9789 void *entity; 9790 int isservice; 9791 scf_type_t ty; 9792 9793 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 9794 scfdie(); 9795 9796 if ((ty != SCF_TYPE_ASTRING && 9797 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 9798 prop_get_val(exp_prop, exp_val) != 0) { 9799 export_property(exp_prop, NULL, &pgelts, 0); 9800 continue; 9801 } 9802 9803 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9804 scfdie(); 9805 9806 if (scf_value_get_astring(exp_val, fmri, 9807 max_scf_fmri_len + 2) < 0) 9808 scfdie(); 9809 9810 /* Look for a dependency group in the target fmri. */ 9811 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 9812 switch (serr) { 9813 case SCF_ERROR_NONE: 9814 break; 9815 9816 case SCF_ERROR_NO_MEMORY: 9817 uu_die(gettext("Out of memory.\n")); 9818 /* NOTREACHED */ 9819 9820 case SCF_ERROR_INVALID_ARGUMENT: 9821 if (g_verbose) { 9822 if (scf_property_to_fmri(exp_prop, fmri, 9823 max_scf_fmri_len + 2) < 0) 9824 scfdie(); 9825 9826 warn(gettext("The value of %s is not a valid " 9827 "FMRI.\n"), fmri); 9828 } 9829 9830 export_property(exp_prop, exp_str, &pgelts, 0); 9831 continue; 9832 9833 case SCF_ERROR_CONSTRAINT_VIOLATED: 9834 if (g_verbose) { 9835 if (scf_property_to_fmri(exp_prop, fmri, 9836 max_scf_fmri_len + 2) < 0) 9837 scfdie(); 9838 9839 warn(gettext("The value of %s does not specify " 9840 "a service or an instance.\n"), fmri); 9841 } 9842 9843 export_property(exp_prop, exp_str, &pgelts, 0); 9844 continue; 9845 9846 case SCF_ERROR_NOT_FOUND: 9847 if (g_verbose) { 9848 if (scf_property_to_fmri(exp_prop, fmri, 9849 max_scf_fmri_len + 2) < 0) 9850 scfdie(); 9851 9852 warn(gettext("The entity specified by %s does " 9853 "not exist.\n"), fmri); 9854 } 9855 9856 export_property(exp_prop, exp_str, &pgelts, 0); 9857 continue; 9858 9859 default: 9860 #ifndef NDEBUG 9861 (void) fprintf(stderr, "%s:%d: %s() failed with " 9862 "unexpected error %d.\n", __FILE__, __LINE__, 9863 "fmri_to_entity", serr); 9864 #endif 9865 abort(); 9866 } 9867 9868 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 9869 if (scf_error() != SCF_ERROR_NOT_FOUND) 9870 scfdie(); 9871 9872 warn(gettext("Entity %s is missing dependency property " 9873 "group %s.\n"), fmri, exp_str); 9874 9875 export_property(exp_prop, NULL, &pgelts, 0); 9876 continue; 9877 } 9878 9879 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 9880 scfdie(); 9881 9882 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 9883 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 9884 scfdie(); 9885 9886 warn(gettext("Property group %s is not of " 9887 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 9888 9889 export_property(exp_prop, NULL, &pgelts, 0); 9890 continue; 9891 } 9892 9893 n = export_dependent(opg, exp_str, fmri); 9894 if (n == NULL) 9895 export_property(exp_prop, exp_str, &pgelts, 0); 9896 else { 9897 if (eelts->dependents == NULL) 9898 eelts->dependents = n; 9899 else 9900 (void) xmlAddSibling(eelts->dependents, 9901 n); 9902 } 9903 } 9904 if (ret == -1) 9905 scfdie(); 9906 9907 free(fmri); 9908 free(type); 9909 9910 scf_iter_destroy(iter); 9911 scf_pg_destroy(opg); 9912 9913 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9914 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 9915 eelts); 9916 } 9917 9918 static void 9919 make_node(xmlNodePtr *nodep, const char *name) 9920 { 9921 if (*nodep == NULL) { 9922 *nodep = xmlNewNode(NULL, (xmlChar *)name); 9923 if (*nodep == NULL) 9924 uu_die(emsg_create_xml); 9925 } 9926 } 9927 9928 static xmlNodePtr 9929 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 9930 { 9931 int ret; 9932 xmlNodePtr parent = NULL; 9933 xmlNodePtr loctext = NULL; 9934 9935 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9936 scfdie(); 9937 9938 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9939 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 9940 prop_get_val(exp_prop, exp_val) != 0) 9941 continue; 9942 9943 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 9944 scfdie(); 9945 9946 make_node(&parent, parname); 9947 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 9948 (xmlChar *)exp_str); 9949 if (loctext == NULL) 9950 uu_die(emsg_create_xml); 9951 9952 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9953 scfdie(); 9954 9955 safe_setprop(loctext, "xml:lang", exp_str); 9956 } 9957 9958 if (ret == -1) 9959 scfdie(); 9960 9961 return (parent); 9962 } 9963 9964 static xmlNodePtr 9965 export_tm_manpage(scf_propertygroup_t *pg) 9966 { 9967 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 9968 if (manpage == NULL) 9969 uu_die(emsg_create_xml); 9970 9971 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 9972 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 9973 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 9974 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 9975 xmlFreeNode(manpage); 9976 return (NULL); 9977 } 9978 9979 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 9980 (void) set_attr_from_prop_default(exp_prop, 9981 manpage, "manpath", ":default"); 9982 9983 return (manpage); 9984 } 9985 9986 static xmlNodePtr 9987 export_tm_doc_link(scf_propertygroup_t *pg) 9988 { 9989 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 9990 if (doc_link == NULL) 9991 uu_die(emsg_create_xml); 9992 9993 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 9994 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 9995 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 9996 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 9997 xmlFreeNode(doc_link); 9998 return (NULL); 9999 } 10000 return (doc_link); 10001 } 10002 10003 /* 10004 * Process template information for a service or instances. 10005 */ 10006 static void 10007 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 10008 struct template_elts *telts) 10009 { 10010 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 10011 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 10012 xmlNodePtr child = NULL; 10013 10014 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 10015 scfdie(); 10016 10017 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 10018 telts->common_name = export_tm_loctext(pg, "common_name"); 10019 if (telts->common_name == NULL) 10020 export_pg(pg, elts, 0); 10021 return; 10022 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 10023 telts->description = export_tm_loctext(pg, "description"); 10024 if (telts->description == NULL) 10025 export_pg(pg, elts, 0); 10026 return; 10027 } 10028 10029 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 10030 child = export_tm_manpage(pg); 10031 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 10032 child = export_tm_doc_link(pg); 10033 } 10034 10035 if (child != NULL) { 10036 make_node(&telts->documentation, "documentation"); 10037 (void) xmlAddChild(telts->documentation, child); 10038 } else { 10039 export_pg(pg, elts, 0); 10040 } 10041 } 10042 10043 /* 10044 * Process parameter and paramval elements 10045 */ 10046 static void 10047 export_parameter(scf_property_t *prop, const char *name, 10048 struct params_elts *elts) 10049 { 10050 xmlNodePtr param; 10051 scf_error_t err = 0; 10052 int ret; 10053 10054 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 10055 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL) 10056 uu_die(emsg_create_xml); 10057 10058 safe_setprop(param, name_attr, name); 10059 10060 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 10061 scfdie(); 10062 safe_setprop(param, value_attr, exp_str); 10063 10064 if (elts->paramval == NULL) 10065 elts->paramval = param; 10066 else 10067 (void) xmlAddSibling(elts->paramval, param); 10068 10069 return; 10070 } 10071 10072 err = scf_error(); 10073 10074 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 10075 err != SCF_ERROR_NOT_FOUND) 10076 scfdie(); 10077 10078 if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL) 10079 uu_die(emsg_create_xml); 10080 10081 safe_setprop(param, name_attr, name); 10082 10083 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 10084 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 10085 scfdie(); 10086 10087 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 10088 1) { 10089 xmlNodePtr vn; 10090 10091 if ((vn = xmlNewChild(param, NULL, 10092 (xmlChar *)"value_node", NULL)) == NULL) 10093 uu_die(emsg_create_xml); 10094 10095 if (scf_value_get_as_string(exp_val, exp_str, 10096 exp_str_sz) < 0) 10097 scfdie(); 10098 10099 safe_setprop(vn, value_attr, exp_str); 10100 } 10101 if (ret != 0) 10102 scfdie(); 10103 } 10104 10105 if (elts->parameter == NULL) 10106 elts->parameter = param; 10107 else 10108 (void) xmlAddSibling(elts->parameter, param); 10109 } 10110 10111 /* 10112 * Process notification parameters for a service or instance 10113 */ 10114 static void 10115 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts) 10116 { 10117 xmlNodePtr n, event, *type; 10118 struct params_elts *eelts; 10119 int ret, err, i; 10120 10121 n = xmlNewNode(NULL, (xmlChar *)"notification_parameters"); 10122 event = xmlNewNode(NULL, (xmlChar *)"event"); 10123 if (n == NULL || event == NULL) 10124 uu_die(emsg_create_xml); 10125 10126 /* event value */ 10127 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 10128 scfdie(); 10129 safe_setprop(event, value_attr, exp_str); 10130 10131 (void) xmlAddChild(n, event); 10132 10133 if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL || 10134 (eelts = calloc(URI_SCHEME_NUM, 10135 sizeof (struct params_elts))) == NULL) 10136 uu_die(gettext("Out of memory.\n")); 10137 10138 err = 0; 10139 10140 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10141 scfdie(); 10142 10143 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10144 char *t, *p; 10145 10146 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10147 scfdie(); 10148 10149 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) { 10150 /* 10151 * this is not a well formed notification parameters 10152 * element, we should export as regular pg 10153 */ 10154 err = 1; 10155 break; 10156 } 10157 10158 if ((i = check_uri_protocol(t)) < 0) { 10159 err = 1; 10160 break; 10161 } 10162 10163 if (type[i] == NULL) { 10164 if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) == 10165 NULL) 10166 uu_die(emsg_create_xml); 10167 10168 safe_setprop(type[i], name_attr, t); 10169 } 10170 if (strcmp(p, active_attr) == 0) { 10171 if (set_attr_from_prop(exp_prop, type[i], 10172 active_attr) != 0) { 10173 err = 1; 10174 break; 10175 } 10176 continue; 10177 } 10178 /* 10179 * We export the parameter 10180 */ 10181 export_parameter(exp_prop, p, &eelts[i]); 10182 } 10183 10184 if (ret == -1) 10185 scfdie(); 10186 10187 if (err == 1) { 10188 for (i = 0; i < URI_SCHEME_NUM; ++i) 10189 xmlFree(type[i]); 10190 free(type); 10191 10192 export_pg(pg, elts, 0); 10193 10194 return; 10195 } else { 10196 for (i = 0; i < URI_SCHEME_NUM; ++i) 10197 if (type[i] != NULL) { 10198 (void) xmlAddChildList(type[i], 10199 eelts[i].paramval); 10200 (void) xmlAddChildList(type[i], 10201 eelts[i].parameter); 10202 (void) xmlAddSibling(event, type[i]); 10203 } 10204 } 10205 free(type); 10206 10207 if (elts->notify_params == NULL) 10208 elts->notify_params = n; 10209 else 10210 (void) xmlAddSibling(elts->notify_params, n); 10211 } 10212 10213 /* 10214 * Process the general property group for an instance. 10215 */ 10216 static void 10217 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 10218 struct entity_elts *elts) 10219 { 10220 uint8_t enabled; 10221 struct pg_elts pgelts; 10222 int ret; 10223 10224 /* enabled */ 10225 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10226 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10227 prop_get_val(exp_prop, exp_val) == 0) { 10228 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10229 scfdie(); 10230 } else { 10231 enabled = 0; 10232 } 10233 10234 safe_setprop(inode, enabled_attr, enabled ? true : false); 10235 10236 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10237 scfdie(); 10238 10239 (void) memset(&pgelts, 0, sizeof (pgelts)); 10240 10241 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10242 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10243 scfdie(); 10244 10245 if (strcmp(exp_str, scf_property_enabled) == 0) { 10246 continue; 10247 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10248 xmlNodePtr rnode, sfnode; 10249 10250 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10251 if (rnode == NULL) 10252 uu_die(emsg_create_xml); 10253 10254 sfnode = xmlNewChild(rnode, NULL, 10255 (xmlChar *)"service_fmri", NULL); 10256 if (sfnode == NULL) 10257 uu_die(emsg_create_xml); 10258 10259 if (set_attr_from_prop(exp_prop, sfnode, 10260 value_attr) == 0) { 10261 elts->restarter = rnode; 10262 continue; 10263 } 10264 10265 xmlFreeNode(rnode); 10266 } 10267 10268 export_property(exp_prop, exp_str, &pgelts, 0); 10269 } 10270 if (ret == -1) 10271 scfdie(); 10272 10273 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10274 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10275 elts); 10276 } 10277 10278 /* 10279 * Put an instance element for the given instance into selts. 10280 */ 10281 static void 10282 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10283 { 10284 xmlNodePtr n; 10285 boolean_t isdefault; 10286 struct entity_elts elts; 10287 struct template_elts template_elts; 10288 int ret; 10289 10290 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10291 if (n == NULL) 10292 uu_die(emsg_create_xml); 10293 10294 /* name */ 10295 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10296 scfdie(); 10297 safe_setprop(n, name_attr, exp_str); 10298 isdefault = strcmp(exp_str, "default") == 0; 10299 10300 /* check existance of general pg (since general/enabled is required) */ 10301 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10302 if (scf_error() != SCF_ERROR_NOT_FOUND) 10303 scfdie(); 10304 10305 if (g_verbose) { 10306 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10307 scfdie(); 10308 10309 warn(gettext("Instance %s has no general property " 10310 "group; it will be marked disabled.\n"), exp_str); 10311 } 10312 10313 safe_setprop(n, enabled_attr, false); 10314 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10315 strcmp(exp_str, scf_group_framework) != 0) { 10316 if (g_verbose) { 10317 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10318 scfdie(); 10319 10320 warn(gettext("Property group %s is not of type " 10321 "framework; the instance will be marked " 10322 "disabled.\n"), exp_str); 10323 } 10324 10325 safe_setprop(n, enabled_attr, false); 10326 } 10327 10328 /* property groups */ 10329 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10330 scfdie(); 10331 10332 (void) memset(&elts, 0, sizeof (elts)); 10333 (void) memset(&template_elts, 0, sizeof (template_elts)); 10334 10335 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10336 uint32_t pgflags; 10337 10338 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10339 scfdie(); 10340 10341 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10342 continue; 10343 10344 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10345 scfdie(); 10346 10347 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10348 export_dependency(exp_pg, &elts); 10349 continue; 10350 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10351 export_method(exp_pg, &elts); 10352 continue; 10353 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10354 if (scf_pg_get_name(exp_pg, exp_str, 10355 max_scf_name_len + 1) < 0) 10356 scfdie(); 10357 10358 if (strcmp(exp_str, scf_pg_general) == 0) { 10359 export_inst_general(exp_pg, n, &elts); 10360 continue; 10361 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10362 0) { 10363 export_method_context(exp_pg, &elts); 10364 continue; 10365 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10366 export_dependents(exp_pg, &elts); 10367 continue; 10368 } 10369 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10370 export_template(exp_pg, &elts, &template_elts); 10371 continue; 10372 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10373 export_notify_params(exp_pg, &elts); 10374 continue; 10375 } 10376 10377 /* Ordinary pg. */ 10378 export_pg(exp_pg, &elts, flags); 10379 } 10380 if (ret == -1) 10381 scfdie(); 10382 10383 if (template_elts.common_name != NULL) { 10384 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10385 (void) xmlAddChild(elts.template, template_elts.common_name); 10386 (void) xmlAddChild(elts.template, template_elts.description); 10387 (void) xmlAddChild(elts.template, template_elts.documentation); 10388 } else { 10389 xmlFreeNode(template_elts.description); 10390 xmlFreeNode(template_elts.documentation); 10391 } 10392 10393 if (isdefault && elts.restarter == NULL && 10394 elts.dependencies == NULL && elts.method_context == NULL && 10395 elts.exec_methods == NULL && elts.notify_params == NULL && 10396 elts.property_groups == NULL && elts.template == NULL) { 10397 xmlChar *eval; 10398 10399 /* This is a default instance */ 10400 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10401 10402 xmlFreeNode(n); 10403 10404 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10405 if (n == NULL) 10406 uu_die(emsg_create_xml); 10407 10408 safe_setprop(n, enabled_attr, (char *)eval); 10409 xmlFree(eval); 10410 10411 selts->create_default_instance = n; 10412 } else { 10413 /* Assemble the children in order. */ 10414 (void) xmlAddChild(n, elts.restarter); 10415 (void) xmlAddChildList(n, elts.dependencies); 10416 (void) xmlAddChildList(n, elts.dependents); 10417 (void) xmlAddChild(n, elts.method_context); 10418 (void) xmlAddChildList(n, elts.exec_methods); 10419 (void) xmlAddChildList(n, elts.notify_params); 10420 (void) xmlAddChildList(n, elts.property_groups); 10421 (void) xmlAddChild(n, elts.template); 10422 10423 if (selts->instances == NULL) 10424 selts->instances = n; 10425 else 10426 (void) xmlAddSibling(selts->instances, n); 10427 } 10428 } 10429 10430 /* 10431 * Return a service element for the given service. 10432 */ 10433 static xmlNodePtr 10434 export_service(scf_service_t *svc, int flags) 10435 { 10436 xmlNodePtr snode; 10437 struct entity_elts elts; 10438 struct template_elts template_elts; 10439 int ret; 10440 10441 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10442 if (snode == NULL) 10443 uu_die(emsg_create_xml); 10444 10445 /* Get & set name attribute */ 10446 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10447 scfdie(); 10448 safe_setprop(snode, name_attr, exp_str); 10449 10450 safe_setprop(snode, type_attr, "service"); 10451 safe_setprop(snode, "version", "0"); 10452 10453 /* Acquire child elements. */ 10454 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10455 scfdie(); 10456 10457 (void) memset(&elts, 0, sizeof (elts)); 10458 (void) memset(&template_elts, 0, sizeof (template_elts)); 10459 10460 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10461 uint32_t pgflags; 10462 10463 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10464 scfdie(); 10465 10466 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10467 continue; 10468 10469 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10470 scfdie(); 10471 10472 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10473 export_dependency(exp_pg, &elts); 10474 continue; 10475 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10476 export_method(exp_pg, &elts); 10477 continue; 10478 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10479 if (scf_pg_get_name(exp_pg, exp_str, 10480 max_scf_name_len + 1) < 0) 10481 scfdie(); 10482 10483 if (strcmp(exp_str, scf_pg_general) == 0) { 10484 export_svc_general(exp_pg, &elts); 10485 continue; 10486 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10487 0) { 10488 export_method_context(exp_pg, &elts); 10489 continue; 10490 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10491 export_dependents(exp_pg, &elts); 10492 continue; 10493 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10494 continue; 10495 } 10496 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10497 export_template(exp_pg, &elts, &template_elts); 10498 continue; 10499 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) { 10500 export_notify_params(exp_pg, &elts); 10501 continue; 10502 } 10503 10504 export_pg(exp_pg, &elts, flags); 10505 } 10506 if (ret == -1) 10507 scfdie(); 10508 10509 if (template_elts.common_name != NULL) { 10510 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10511 (void) xmlAddChild(elts.template, template_elts.common_name); 10512 (void) xmlAddChild(elts.template, template_elts.description); 10513 (void) xmlAddChild(elts.template, template_elts.documentation); 10514 } else { 10515 xmlFreeNode(template_elts.description); 10516 xmlFreeNode(template_elts.documentation); 10517 } 10518 10519 /* Iterate instances */ 10520 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10521 scfdie(); 10522 10523 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10524 export_instance(exp_inst, &elts, flags); 10525 if (ret == -1) 10526 scfdie(); 10527 10528 /* Now add all of the accumulated elements in order. */ 10529 (void) xmlAddChild(snode, elts.create_default_instance); 10530 (void) xmlAddChild(snode, elts.single_instance); 10531 (void) xmlAddChild(snode, elts.restarter); 10532 (void) xmlAddChildList(snode, elts.dependencies); 10533 (void) xmlAddChildList(snode, elts.dependents); 10534 (void) xmlAddChild(snode, elts.method_context); 10535 (void) xmlAddChildList(snode, elts.exec_methods); 10536 (void) xmlAddChildList(snode, elts.notify_params); 10537 (void) xmlAddChildList(snode, elts.property_groups); 10538 (void) xmlAddChildList(snode, elts.instances); 10539 (void) xmlAddChild(snode, elts.stability); 10540 (void) xmlAddChild(snode, elts.template); 10541 10542 return (snode); 10543 } 10544 10545 static int 10546 export_callback(void *data, scf_walkinfo_t *wip) 10547 { 10548 FILE *f; 10549 xmlDocPtr doc; 10550 xmlNodePtr sb; 10551 int result; 10552 struct export_args *argsp = (struct export_args *)data; 10553 10554 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10555 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10556 (exp_prop = scf_property_create(g_hndl)) == NULL || 10557 (exp_val = scf_value_create(g_hndl)) == NULL || 10558 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10559 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10560 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10561 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10562 scfdie(); 10563 10564 exp_str_sz = max_scf_len + 1; 10565 exp_str = safe_malloc(exp_str_sz); 10566 10567 if (argsp->filename != NULL) { 10568 errno = 0; 10569 f = fopen(argsp->filename, "wb"); 10570 if (f == NULL) { 10571 if (errno == 0) 10572 uu_die(gettext("Could not open \"%s\": no free " 10573 "stdio streams.\n"), argsp->filename); 10574 else 10575 uu_die(gettext("Could not open \"%s\""), 10576 argsp->filename); 10577 } 10578 } else 10579 f = stdout; 10580 10581 doc = xmlNewDoc((xmlChar *)"1.0"); 10582 if (doc == NULL) 10583 uu_die(gettext("Could not create XML document.\n")); 10584 10585 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10586 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10587 uu_die(emsg_create_xml); 10588 10589 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10590 if (sb == NULL) 10591 uu_die(emsg_create_xml); 10592 safe_setprop(sb, type_attr, "manifest"); 10593 safe_setprop(sb, name_attr, "export"); 10594 (void) xmlAddSibling(doc->children, sb); 10595 10596 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10597 10598 result = write_service_bundle(doc, f); 10599 10600 free(exp_str); 10601 scf_iter_destroy(exp_val_iter); 10602 scf_iter_destroy(exp_prop_iter); 10603 scf_iter_destroy(exp_pg_iter); 10604 scf_iter_destroy(exp_inst_iter); 10605 scf_value_destroy(exp_val); 10606 scf_property_destroy(exp_prop); 10607 scf_pg_destroy(exp_pg); 10608 scf_instance_destroy(exp_inst); 10609 10610 xmlFreeDoc(doc); 10611 10612 if (f != stdout) 10613 (void) fclose(f); 10614 10615 return (result); 10616 } 10617 10618 /* 10619 * Get the service named by fmri, build an XML tree which represents it, and 10620 * dump it into filename (or stdout if filename is NULL). 10621 */ 10622 int 10623 lscf_service_export(char *fmri, const char *filename, int flags) 10624 { 10625 struct export_args args; 10626 int ret, err; 10627 10628 lscf_prep_hndl(); 10629 10630 bzero(&args, sizeof (args)); 10631 args.filename = filename; 10632 args.flags = flags; 10633 10634 err = 0; 10635 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10636 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10637 &args, &err, semerr)) != 0) { 10638 if (ret != -1) 10639 semerr(gettext("Failed to walk instances: %s\n"), 10640 scf_strerror(ret)); 10641 return (-1); 10642 } 10643 10644 /* 10645 * Error message has already been printed. 10646 */ 10647 if (err != 0) 10648 return (-1); 10649 10650 return (0); 10651 } 10652 10653 10654 /* 10655 * Archive 10656 */ 10657 10658 static xmlNodePtr 10659 make_archive(int flags) 10660 { 10661 xmlNodePtr sb; 10662 scf_scope_t *scope; 10663 scf_service_t *svc; 10664 scf_iter_t *iter; 10665 int r; 10666 10667 if ((scope = scf_scope_create(g_hndl)) == NULL || 10668 (svc = scf_service_create(g_hndl)) == NULL || 10669 (iter = scf_iter_create(g_hndl)) == NULL || 10670 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10671 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10672 (exp_prop = scf_property_create(g_hndl)) == NULL || 10673 (exp_val = scf_value_create(g_hndl)) == NULL || 10674 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10675 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10676 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10677 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10678 scfdie(); 10679 10680 exp_str_sz = max_scf_len + 1; 10681 exp_str = safe_malloc(exp_str_sz); 10682 10683 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10684 if (sb == NULL) 10685 uu_die(emsg_create_xml); 10686 safe_setprop(sb, type_attr, "archive"); 10687 safe_setprop(sb, name_attr, "none"); 10688 10689 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 10690 scfdie(); 10691 if (scf_iter_scope_services(iter, scope) != 0) 10692 scfdie(); 10693 10694 for (;;) { 10695 r = scf_iter_next_service(iter, svc); 10696 if (r == 0) 10697 break; 10698 if (r != 1) 10699 scfdie(); 10700 10701 if (scf_service_get_name(svc, exp_str, 10702 max_scf_name_len + 1) < 0) 10703 scfdie(); 10704 10705 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 10706 continue; 10707 10708 (void) xmlAddChild(sb, export_service(svc, flags)); 10709 } 10710 10711 free(exp_str); 10712 10713 scf_iter_destroy(exp_val_iter); 10714 scf_iter_destroy(exp_prop_iter); 10715 scf_iter_destroy(exp_pg_iter); 10716 scf_iter_destroy(exp_inst_iter); 10717 scf_value_destroy(exp_val); 10718 scf_property_destroy(exp_prop); 10719 scf_pg_destroy(exp_pg); 10720 scf_instance_destroy(exp_inst); 10721 scf_iter_destroy(iter); 10722 scf_service_destroy(svc); 10723 scf_scope_destroy(scope); 10724 10725 return (sb); 10726 } 10727 10728 int 10729 lscf_archive(const char *filename, int flags) 10730 { 10731 FILE *f; 10732 xmlDocPtr doc; 10733 int result; 10734 10735 lscf_prep_hndl(); 10736 10737 if (filename != NULL) { 10738 errno = 0; 10739 f = fopen(filename, "wb"); 10740 if (f == NULL) { 10741 if (errno == 0) 10742 uu_die(gettext("Could not open \"%s\": no free " 10743 "stdio streams.\n"), filename); 10744 else 10745 uu_die(gettext("Could not open \"%s\""), 10746 filename); 10747 } 10748 } else 10749 f = stdout; 10750 10751 doc = xmlNewDoc((xmlChar *)"1.0"); 10752 if (doc == NULL) 10753 uu_die(gettext("Could not create XML document.\n")); 10754 10755 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10756 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10757 uu_die(emsg_create_xml); 10758 10759 (void) xmlAddSibling(doc->children, make_archive(flags)); 10760 10761 result = write_service_bundle(doc, f); 10762 10763 xmlFreeDoc(doc); 10764 10765 if (f != stdout) 10766 (void) fclose(f); 10767 10768 return (result); 10769 } 10770 10771 10772 /* 10773 * "Extract" a profile. 10774 */ 10775 int 10776 lscf_profile_extract(const char *filename) 10777 { 10778 FILE *f; 10779 xmlDocPtr doc; 10780 xmlNodePtr sb, snode, inode; 10781 scf_scope_t *scope; 10782 scf_service_t *svc; 10783 scf_instance_t *inst; 10784 scf_propertygroup_t *pg; 10785 scf_property_t *prop; 10786 scf_value_t *val; 10787 scf_iter_t *siter, *iiter; 10788 int r, s; 10789 char *namebuf; 10790 uint8_t b; 10791 int result; 10792 10793 lscf_prep_hndl(); 10794 10795 if (filename != NULL) { 10796 errno = 0; 10797 f = fopen(filename, "wb"); 10798 if (f == NULL) { 10799 if (errno == 0) 10800 uu_die(gettext("Could not open \"%s\": no " 10801 "free stdio streams.\n"), filename); 10802 else 10803 uu_die(gettext("Could not open \"%s\""), 10804 filename); 10805 } 10806 } else 10807 f = stdout; 10808 10809 doc = xmlNewDoc((xmlChar *)"1.0"); 10810 if (doc == NULL) 10811 uu_die(gettext("Could not create XML document.\n")); 10812 10813 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10814 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10815 uu_die(emsg_create_xml); 10816 10817 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10818 if (sb == NULL) 10819 uu_die(emsg_create_xml); 10820 safe_setprop(sb, type_attr, "profile"); 10821 safe_setprop(sb, name_attr, "extract"); 10822 (void) xmlAddSibling(doc->children, sb); 10823 10824 if ((scope = scf_scope_create(g_hndl)) == NULL || 10825 (svc = scf_service_create(g_hndl)) == NULL || 10826 (inst = scf_instance_create(g_hndl)) == NULL || 10827 (pg = scf_pg_create(g_hndl)) == NULL || 10828 (prop = scf_property_create(g_hndl)) == NULL || 10829 (val = scf_value_create(g_hndl)) == NULL || 10830 (siter = scf_iter_create(g_hndl)) == NULL || 10831 (iiter = scf_iter_create(g_hndl)) == NULL) 10832 scfdie(); 10833 10834 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 10835 scfdie(); 10836 10837 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 10838 scfdie(); 10839 10840 namebuf = safe_malloc(max_scf_name_len + 1); 10841 10842 while ((r = scf_iter_next_service(siter, svc)) == 1) { 10843 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 10844 scfdie(); 10845 10846 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10847 if (snode == NULL) 10848 uu_die(emsg_create_xml); 10849 10850 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 10851 0) 10852 scfdie(); 10853 10854 safe_setprop(snode, name_attr, namebuf); 10855 10856 safe_setprop(snode, type_attr, "service"); 10857 safe_setprop(snode, "version", "0"); 10858 10859 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 10860 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 10861 SCF_SUCCESS) { 10862 if (scf_error() != SCF_ERROR_NOT_FOUND) 10863 scfdie(); 10864 10865 if (g_verbose) { 10866 ssize_t len; 10867 char *fmri; 10868 10869 len = 10870 scf_instance_to_fmri(inst, NULL, 0); 10871 if (len < 0) 10872 scfdie(); 10873 10874 fmri = safe_malloc(len + 1); 10875 10876 if (scf_instance_to_fmri(inst, fmri, 10877 len + 1) < 0) 10878 scfdie(); 10879 10880 warn("Instance %s has no \"%s\" " 10881 "property group.\n", fmri, 10882 scf_pg_general); 10883 10884 free(fmri); 10885 } 10886 10887 continue; 10888 } 10889 10890 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 10891 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 10892 prop_get_val(prop, val) != 0) 10893 continue; 10894 10895 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 10896 NULL); 10897 if (inode == NULL) 10898 uu_die(emsg_create_xml); 10899 10900 if (scf_instance_get_name(inst, namebuf, 10901 max_scf_name_len + 1) < 0) 10902 scfdie(); 10903 10904 safe_setprop(inode, name_attr, namebuf); 10905 10906 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 10907 scfdie(); 10908 10909 safe_setprop(inode, enabled_attr, b ? true : false); 10910 } 10911 if (s < 0) 10912 scfdie(); 10913 10914 if (snode->children != NULL) 10915 (void) xmlAddChild(sb, snode); 10916 else 10917 xmlFreeNode(snode); 10918 } 10919 if (r < 0) 10920 scfdie(); 10921 10922 free(namebuf); 10923 10924 result = write_service_bundle(doc, f); 10925 10926 xmlFreeDoc(doc); 10927 10928 if (f != stdout) 10929 (void) fclose(f); 10930 10931 return (result); 10932 } 10933 10934 10935 /* 10936 * Entity manipulation commands 10937 */ 10938 10939 /* 10940 * Entity selection. If no entity is selected, then the current scope is in 10941 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 10942 * only cur_inst is NULL, and when an instance is selected, none are NULL. 10943 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 10944 * cur_inst will be non-NULL. 10945 */ 10946 10947 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 10948 static int 10949 select_inst(const char *name) 10950 { 10951 scf_instance_t *inst; 10952 scf_error_t err; 10953 10954 assert(cur_svc != NULL); 10955 10956 inst = scf_instance_create(g_hndl); 10957 if (inst == NULL) 10958 scfdie(); 10959 10960 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 10961 cur_inst = inst; 10962 return (0); 10963 } 10964 10965 err = scf_error(); 10966 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10967 scfdie(); 10968 10969 scf_instance_destroy(inst); 10970 return (1); 10971 } 10972 10973 /* Returns as above. */ 10974 static int 10975 select_svc(const char *name) 10976 { 10977 scf_service_t *svc; 10978 scf_error_t err; 10979 10980 assert(cur_scope != NULL); 10981 10982 svc = scf_service_create(g_hndl); 10983 if (svc == NULL) 10984 scfdie(); 10985 10986 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 10987 cur_svc = svc; 10988 return (0); 10989 } 10990 10991 err = scf_error(); 10992 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10993 scfdie(); 10994 10995 scf_service_destroy(svc); 10996 return (1); 10997 } 10998 10999 /* ARGSUSED */ 11000 static int 11001 select_callback(void *unused, scf_walkinfo_t *wip) 11002 { 11003 scf_instance_t *inst; 11004 scf_service_t *svc; 11005 scf_scope_t *scope; 11006 11007 if (wip->inst != NULL) { 11008 if ((scope = scf_scope_create(g_hndl)) == NULL || 11009 (svc = scf_service_create(g_hndl)) == NULL || 11010 (inst = scf_instance_create(g_hndl)) == NULL) 11011 scfdie(); 11012 11013 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11014 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11015 scfdie(); 11016 } else { 11017 assert(wip->svc != NULL); 11018 11019 if ((scope = scf_scope_create(g_hndl)) == NULL || 11020 (svc = scf_service_create(g_hndl)) == NULL) 11021 scfdie(); 11022 11023 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 11024 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 11025 scfdie(); 11026 11027 inst = NULL; 11028 } 11029 11030 /* Clear out the current selection */ 11031 assert(cur_scope != NULL); 11032 scf_scope_destroy(cur_scope); 11033 scf_service_destroy(cur_svc); 11034 scf_instance_destroy(cur_inst); 11035 11036 cur_scope = scope; 11037 cur_svc = svc; 11038 cur_inst = inst; 11039 11040 return (0); 11041 } 11042 11043 static int 11044 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 11045 { 11046 char **fmri = fmri_p; 11047 11048 *fmri = strdup(wip->fmri); 11049 if (*fmri == NULL) 11050 uu_die(gettext("Out of memory.\n")); 11051 11052 return (0); 11053 } 11054 11055 /* 11056 * validate [fmri] 11057 * Perform the validation of an FMRI instance. 11058 */ 11059 void 11060 lscf_validate_fmri(const char *fmri) 11061 { 11062 int ret = 0; 11063 size_t inst_sz; 11064 char *inst_fmri = NULL; 11065 scf_tmpl_errors_t *errs = NULL; 11066 char *snapbuf = NULL; 11067 11068 lscf_prep_hndl(); 11069 11070 if (fmri == NULL) { 11071 inst_sz = max_scf_fmri_len + 1; 11072 inst_fmri = safe_malloc(inst_sz); 11073 11074 if (cur_snap != NULL) { 11075 snapbuf = safe_malloc(max_scf_name_len + 1); 11076 if (scf_snapshot_get_name(cur_snap, snapbuf, 11077 max_scf_name_len + 1) < 0) 11078 scfdie(); 11079 } 11080 if (cur_inst == NULL) { 11081 semerr(gettext("No instance selected\n")); 11082 goto cleanup; 11083 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 11084 inst_sz) >= inst_sz) { 11085 /* sanity check. Should never get here */ 11086 uu_die(gettext("Unexpected error! file %s, line %d\n"), 11087 __FILE__, __LINE__); 11088 } 11089 } else { 11090 scf_error_t scf_err; 11091 int err = 0; 11092 11093 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 11094 validate_callback, &inst_fmri, &err, semerr)) != 0) { 11095 uu_warn("Failed to walk instances: %s\n", 11096 scf_strerror(scf_err)); 11097 goto cleanup; 11098 } 11099 if (err != 0) { 11100 /* error message displayed by scf_walk_fmri */ 11101 goto cleanup; 11102 } 11103 } 11104 11105 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 11106 SCF_TMPL_VALIDATE_FLAG_CURRENT); 11107 if (ret == -1) { 11108 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 11109 warn(gettext("Template data for %s is invalid. " 11110 "Consider reverting to a previous snapshot or " 11111 "restoring original configuration.\n"), inst_fmri); 11112 } else { 11113 uu_warn("%s: %s\n", 11114 gettext("Error validating the instance"), 11115 scf_strerror(scf_error())); 11116 } 11117 } else if (ret == 1 && errs != NULL) { 11118 scf_tmpl_error_t *err = NULL; 11119 char *msg; 11120 size_t len = 256; /* initial error buffer size */ 11121 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 11122 SCF_TMPL_STRERROR_HUMAN : 0; 11123 11124 msg = safe_malloc(len); 11125 11126 while ((err = scf_tmpl_next_error(errs)) != NULL) { 11127 int ret; 11128 11129 if ((ret = scf_tmpl_strerror(err, msg, len, 11130 flag)) >= len) { 11131 len = ret + 1; 11132 msg = realloc(msg, len); 11133 if (msg == NULL) 11134 uu_die(gettext( 11135 "Out of memory.\n")); 11136 (void) scf_tmpl_strerror(err, msg, len, 11137 flag); 11138 } 11139 (void) fprintf(stderr, "%s\n", msg); 11140 } 11141 if (msg != NULL) 11142 free(msg); 11143 } 11144 if (errs != NULL) 11145 scf_tmpl_errors_destroy(errs); 11146 11147 cleanup: 11148 free(inst_fmri); 11149 free(snapbuf); 11150 } 11151 11152 static void 11153 lscf_validate_file(const char *filename) 11154 { 11155 tmpl_errors_t *errs; 11156 11157 bundle_t *b = internal_bundle_new(); 11158 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 11159 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 11160 tmpl_errors_print(stderr, errs, ""); 11161 semerr(gettext("Validation failed.\n")); 11162 } 11163 tmpl_errors_destroy(errs); 11164 } 11165 (void) internal_bundle_free(b); 11166 } 11167 11168 /* 11169 * validate [fmri|file] 11170 */ 11171 void 11172 lscf_validate(const char *arg) 11173 { 11174 const char *str; 11175 11176 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 11177 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 11178 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 11179 lscf_validate_file(str); 11180 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 11181 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 11182 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 11183 lscf_validate_fmri(str); 11184 } else if (access(arg, R_OK | F_OK) == 0) { 11185 lscf_validate_file(arg); 11186 } else { 11187 lscf_validate_fmri(arg); 11188 } 11189 } 11190 11191 void 11192 lscf_select(const char *fmri) 11193 { 11194 int ret, err; 11195 11196 lscf_prep_hndl(); 11197 11198 if (cur_snap != NULL) { 11199 struct snaplevel *elt; 11200 char *buf; 11201 11202 /* Error unless name is that of the next level. */ 11203 elt = uu_list_next(cur_levels, cur_elt); 11204 if (elt == NULL) { 11205 semerr(gettext("No children.\n")); 11206 return; 11207 } 11208 11209 buf = safe_malloc(max_scf_name_len + 1); 11210 11211 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11212 max_scf_name_len + 1) < 0) 11213 scfdie(); 11214 11215 if (strcmp(buf, fmri) != 0) { 11216 semerr(gettext("No such child.\n")); 11217 free(buf); 11218 return; 11219 } 11220 11221 free(buf); 11222 11223 cur_elt = elt; 11224 cur_level = elt->sl; 11225 return; 11226 } 11227 11228 /* 11229 * Special case for 'svc:', which takes the user to the scope level. 11230 */ 11231 if (strcmp(fmri, "svc:") == 0) { 11232 scf_instance_destroy(cur_inst); 11233 scf_service_destroy(cur_svc); 11234 cur_inst = NULL; 11235 cur_svc = NULL; 11236 return; 11237 } 11238 11239 /* 11240 * Special case for ':properties'. This appears as part of 'list' but 11241 * can't be selected. Give a more helpful error message in this case. 11242 */ 11243 if (strcmp(fmri, ":properties") == 0) { 11244 semerr(gettext(":properties is not an entity. Try 'listprop' " 11245 "to list properties.\n")); 11246 return; 11247 } 11248 11249 /* 11250 * First try the argument as relative to the current selection. 11251 */ 11252 if (cur_inst != NULL) { 11253 /* EMPTY */; 11254 } else if (cur_svc != NULL) { 11255 if (select_inst(fmri) != 1) 11256 return; 11257 } else { 11258 if (select_svc(fmri) != 1) 11259 return; 11260 } 11261 11262 err = 0; 11263 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11264 select_callback, NULL, &err, semerr)) != 0) { 11265 semerr(gettext("Failed to walk instances: %s\n"), 11266 scf_strerror(ret)); 11267 } 11268 } 11269 11270 void 11271 lscf_unselect(void) 11272 { 11273 lscf_prep_hndl(); 11274 11275 if (cur_snap != NULL) { 11276 struct snaplevel *elt; 11277 11278 elt = uu_list_prev(cur_levels, cur_elt); 11279 if (elt == NULL) { 11280 semerr(gettext("No parent levels.\n")); 11281 } else { 11282 cur_elt = elt; 11283 cur_level = elt->sl; 11284 } 11285 } else if (cur_inst != NULL) { 11286 scf_instance_destroy(cur_inst); 11287 cur_inst = NULL; 11288 } else if (cur_svc != NULL) { 11289 scf_service_destroy(cur_svc); 11290 cur_svc = NULL; 11291 } else { 11292 semerr(gettext("Cannot unselect at scope level.\n")); 11293 } 11294 } 11295 11296 /* 11297 * Return the FMRI of the current selection, for the prompt. 11298 */ 11299 void 11300 lscf_get_selection_str(char *buf, size_t bufsz) 11301 { 11302 char *cp; 11303 ssize_t fmrilen, szret; 11304 boolean_t deleted = B_FALSE; 11305 11306 if (g_hndl == NULL) { 11307 (void) strlcpy(buf, "svc:", bufsz); 11308 return; 11309 } 11310 11311 if (cur_level != NULL) { 11312 assert(cur_snap != NULL); 11313 11314 /* [ snapshot ] FMRI [: instance ] */ 11315 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11316 + 2 + max_scf_name_len + 1 + 1); 11317 11318 buf[0] = '['; 11319 11320 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11321 max_scf_name_len + 1); 11322 if (szret < 0) { 11323 if (scf_error() != SCF_ERROR_DELETED) 11324 scfdie(); 11325 11326 goto snap_deleted; 11327 } 11328 11329 (void) strcat(buf, "]svc:/"); 11330 11331 cp = strchr(buf, '\0'); 11332 11333 szret = scf_snaplevel_get_service_name(cur_level, cp, 11334 max_scf_name_len + 1); 11335 if (szret < 0) { 11336 if (scf_error() != SCF_ERROR_DELETED) 11337 scfdie(); 11338 11339 goto snap_deleted; 11340 } 11341 11342 cp = strchr(cp, '\0'); 11343 11344 if (snaplevel_is_instance(cur_level)) { 11345 *cp++ = ':'; 11346 11347 if (scf_snaplevel_get_instance_name(cur_level, cp, 11348 max_scf_name_len + 1) < 0) { 11349 if (scf_error() != SCF_ERROR_DELETED) 11350 scfdie(); 11351 11352 goto snap_deleted; 11353 } 11354 } else { 11355 *cp++ = '['; 11356 *cp++ = ':'; 11357 11358 if (scf_instance_get_name(cur_inst, cp, 11359 max_scf_name_len + 1) < 0) { 11360 if (scf_error() != SCF_ERROR_DELETED) 11361 scfdie(); 11362 11363 goto snap_deleted; 11364 } 11365 11366 (void) strcat(buf, "]"); 11367 } 11368 11369 return; 11370 11371 snap_deleted: 11372 deleted = B_TRUE; 11373 free(buf); 11374 unselect_cursnap(); 11375 } 11376 11377 assert(cur_snap == NULL); 11378 11379 if (cur_inst != NULL) { 11380 assert(cur_svc != NULL); 11381 assert(cur_scope != NULL); 11382 11383 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11384 if (fmrilen >= 0) { 11385 assert(fmrilen < bufsz); 11386 if (deleted) 11387 warn(emsg_deleted); 11388 return; 11389 } 11390 11391 if (scf_error() != SCF_ERROR_DELETED) 11392 scfdie(); 11393 11394 deleted = B_TRUE; 11395 11396 scf_instance_destroy(cur_inst); 11397 cur_inst = NULL; 11398 } 11399 11400 if (cur_svc != NULL) { 11401 assert(cur_scope != NULL); 11402 11403 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11404 if (szret >= 0) { 11405 assert(szret < bufsz); 11406 if (deleted) 11407 warn(emsg_deleted); 11408 return; 11409 } 11410 11411 if (scf_error() != SCF_ERROR_DELETED) 11412 scfdie(); 11413 11414 deleted = B_TRUE; 11415 scf_service_destroy(cur_svc); 11416 cur_svc = NULL; 11417 } 11418 11419 assert(cur_scope != NULL); 11420 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11421 11422 if (fmrilen < 0) 11423 scfdie(); 11424 11425 assert(fmrilen < bufsz); 11426 if (deleted) 11427 warn(emsg_deleted); 11428 } 11429 11430 /* 11431 * Entity listing. Entities and colon namespaces (e.g., :properties and 11432 * :statistics) are listed for the current selection. 11433 */ 11434 void 11435 lscf_list(const char *pattern) 11436 { 11437 scf_iter_t *iter; 11438 char *buf; 11439 int ret; 11440 11441 lscf_prep_hndl(); 11442 11443 if (cur_level != NULL) { 11444 struct snaplevel *elt; 11445 11446 (void) fputs(COLON_NAMESPACES, stdout); 11447 11448 elt = uu_list_next(cur_levels, cur_elt); 11449 if (elt == NULL) 11450 return; 11451 11452 /* 11453 * For now, we know that the next level is an instance. But 11454 * if we ever have multiple scopes, this could be complicated. 11455 */ 11456 buf = safe_malloc(max_scf_name_len + 1); 11457 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11458 max_scf_name_len + 1) >= 0) { 11459 (void) puts(buf); 11460 } else { 11461 if (scf_error() != SCF_ERROR_DELETED) 11462 scfdie(); 11463 } 11464 11465 free(buf); 11466 11467 return; 11468 } 11469 11470 if (cur_inst != NULL) { 11471 (void) fputs(COLON_NAMESPACES, stdout); 11472 return; 11473 } 11474 11475 iter = scf_iter_create(g_hndl); 11476 if (iter == NULL) 11477 scfdie(); 11478 11479 buf = safe_malloc(max_scf_name_len + 1); 11480 11481 if (cur_svc != NULL) { 11482 /* List the instances in this service. */ 11483 scf_instance_t *inst; 11484 11485 inst = scf_instance_create(g_hndl); 11486 if (inst == NULL) 11487 scfdie(); 11488 11489 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11490 safe_printf(COLON_NAMESPACES); 11491 11492 for (;;) { 11493 ret = scf_iter_next_instance(iter, inst); 11494 if (ret == 0) 11495 break; 11496 if (ret != 1) { 11497 if (scf_error() != SCF_ERROR_DELETED) 11498 scfdie(); 11499 11500 break; 11501 } 11502 11503 if (scf_instance_get_name(inst, buf, 11504 max_scf_name_len + 1) >= 0) { 11505 if (pattern == NULL || 11506 fnmatch(pattern, buf, 0) == 0) 11507 (void) puts(buf); 11508 } else { 11509 if (scf_error() != SCF_ERROR_DELETED) 11510 scfdie(); 11511 } 11512 } 11513 } else { 11514 if (scf_error() != SCF_ERROR_DELETED) 11515 scfdie(); 11516 } 11517 11518 scf_instance_destroy(inst); 11519 } else { 11520 /* List the services in this scope. */ 11521 scf_service_t *svc; 11522 11523 assert(cur_scope != NULL); 11524 11525 svc = scf_service_create(g_hndl); 11526 if (svc == NULL) 11527 scfdie(); 11528 11529 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11530 scfdie(); 11531 11532 for (;;) { 11533 ret = scf_iter_next_service(iter, svc); 11534 if (ret == 0) 11535 break; 11536 if (ret != 1) 11537 scfdie(); 11538 11539 if (scf_service_get_name(svc, buf, 11540 max_scf_name_len + 1) >= 0) { 11541 if (pattern == NULL || 11542 fnmatch(pattern, buf, 0) == 0) 11543 safe_printf("%s\n", buf); 11544 } else { 11545 if (scf_error() != SCF_ERROR_DELETED) 11546 scfdie(); 11547 } 11548 } 11549 11550 scf_service_destroy(svc); 11551 } 11552 11553 free(buf); 11554 scf_iter_destroy(iter); 11555 } 11556 11557 /* 11558 * Entity addition. Creates an empty entity in the current selection. 11559 */ 11560 void 11561 lscf_add(const char *name) 11562 { 11563 lscf_prep_hndl(); 11564 11565 if (cur_snap != NULL) { 11566 semerr(emsg_cant_modify_snapshots); 11567 } else if (cur_inst != NULL) { 11568 semerr(gettext("Cannot add entities to an instance.\n")); 11569 } else if (cur_svc != NULL) { 11570 11571 if (scf_service_add_instance(cur_svc, name, NULL) != 11572 SCF_SUCCESS) { 11573 switch (scf_error()) { 11574 case SCF_ERROR_INVALID_ARGUMENT: 11575 semerr(gettext("Invalid name.\n")); 11576 break; 11577 11578 case SCF_ERROR_EXISTS: 11579 semerr(gettext("Instance already exists.\n")); 11580 break; 11581 11582 case SCF_ERROR_PERMISSION_DENIED: 11583 semerr(emsg_permission_denied); 11584 break; 11585 11586 default: 11587 scfdie(); 11588 } 11589 } 11590 } else { 11591 assert(cur_scope != NULL); 11592 11593 if (scf_scope_add_service(cur_scope, name, NULL) != 11594 SCF_SUCCESS) { 11595 switch (scf_error()) { 11596 case SCF_ERROR_INVALID_ARGUMENT: 11597 semerr(gettext("Invalid name.\n")); 11598 break; 11599 11600 case SCF_ERROR_EXISTS: 11601 semerr(gettext("Service already exists.\n")); 11602 break; 11603 11604 case SCF_ERROR_PERMISSION_DENIED: 11605 semerr(emsg_permission_denied); 11606 break; 11607 11608 case SCF_ERROR_BACKEND_READONLY: 11609 semerr(emsg_read_only); 11610 break; 11611 11612 default: 11613 scfdie(); 11614 } 11615 } 11616 } 11617 } 11618 11619 /* return 1 if the entity has no persistent pgs, else return 0 */ 11620 static int 11621 entity_has_no_pgs(void *ent, int isservice) 11622 { 11623 scf_iter_t *iter = NULL; 11624 scf_propertygroup_t *pg = NULL; 11625 uint32_t flags; 11626 int err; 11627 int ret = 1; 11628 11629 if ((iter = scf_iter_create(g_hndl)) == NULL || 11630 (pg = scf_pg_create(g_hndl)) == NULL) 11631 scfdie(); 11632 11633 if (isservice) { 11634 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11635 scfdie(); 11636 } else { 11637 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11638 scfdie(); 11639 } 11640 11641 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11642 if (scf_pg_get_flags(pg, &flags) != 0) 11643 scfdie(); 11644 11645 /* skip nonpersistent pgs */ 11646 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11647 continue; 11648 11649 ret = 0; 11650 break; 11651 } 11652 11653 if (err == -1) 11654 scfdie(); 11655 11656 scf_pg_destroy(pg); 11657 scf_iter_destroy(iter); 11658 11659 return (ret); 11660 } 11661 11662 /* return 1 if the service has no instances, else return 0 */ 11663 static int 11664 svc_has_no_insts(scf_service_t *svc) 11665 { 11666 scf_instance_t *inst; 11667 scf_iter_t *iter; 11668 int r; 11669 int ret = 1; 11670 11671 if ((inst = scf_instance_create(g_hndl)) == NULL || 11672 (iter = scf_iter_create(g_hndl)) == NULL) 11673 scfdie(); 11674 11675 if (scf_iter_service_instances(iter, svc) != 0) 11676 scfdie(); 11677 11678 r = scf_iter_next_instance(iter, inst); 11679 if (r == 1) { 11680 ret = 0; 11681 } else if (r == 0) { 11682 ret = 1; 11683 } else if (r == -1) { 11684 scfdie(); 11685 } else { 11686 bad_error("scf_iter_next_instance", r); 11687 } 11688 11689 scf_iter_destroy(iter); 11690 scf_instance_destroy(inst); 11691 11692 return (ret); 11693 } 11694 11695 /* 11696 * Entity deletion. 11697 */ 11698 11699 /* 11700 * Delete the property group <fmri>/:properties/<name>. Returns 11701 * SCF_ERROR_NONE on success (or if the entity is not found), 11702 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 11703 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 11704 * denied. 11705 */ 11706 static scf_error_t 11707 delete_dependency_pg(const char *fmri, const char *name) 11708 { 11709 void *entity = NULL; 11710 int isservice; 11711 scf_propertygroup_t *pg = NULL; 11712 scf_error_t result; 11713 char *pgty; 11714 scf_service_t *svc = NULL; 11715 scf_instance_t *inst = NULL; 11716 scf_iter_t *iter = NULL; 11717 char *name_buf = NULL; 11718 11719 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 11720 switch (result) { 11721 case SCF_ERROR_NONE: 11722 break; 11723 11724 case SCF_ERROR_NO_MEMORY: 11725 uu_die(gettext("Out of memory.\n")); 11726 /* NOTREACHED */ 11727 11728 case SCF_ERROR_INVALID_ARGUMENT: 11729 case SCF_ERROR_CONSTRAINT_VIOLATED: 11730 return (SCF_ERROR_INVALID_ARGUMENT); 11731 11732 case SCF_ERROR_NOT_FOUND: 11733 result = SCF_ERROR_NONE; 11734 goto out; 11735 11736 default: 11737 bad_error("fmri_to_entity", result); 11738 } 11739 11740 pg = scf_pg_create(g_hndl); 11741 if (pg == NULL) 11742 scfdie(); 11743 11744 if (entity_get_pg(entity, isservice, name, pg) != 0) { 11745 if (scf_error() != SCF_ERROR_NOT_FOUND) 11746 scfdie(); 11747 11748 result = SCF_ERROR_NONE; 11749 goto out; 11750 } 11751 11752 pgty = safe_malloc(max_scf_pg_type_len + 1); 11753 11754 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 11755 scfdie(); 11756 11757 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 11758 result = SCF_ERROR_TYPE_MISMATCH; 11759 free(pgty); 11760 goto out; 11761 } 11762 11763 free(pgty); 11764 11765 if (scf_pg_delete(pg) != 0) { 11766 result = scf_error(); 11767 if (result != SCF_ERROR_PERMISSION_DENIED) 11768 scfdie(); 11769 goto out; 11770 } 11771 11772 /* 11773 * We have to handle the case where we've just deleted the last 11774 * property group of a "dummy" entity (instance or service). 11775 * A "dummy" entity is an entity only present to hold an 11776 * external dependency. 11777 * So, in the case we deleted the last property group then we 11778 * can also delete the entity. If the entity is an instance then 11779 * we must verify if this was the last instance for the service 11780 * and if it is, we can also delete the service if it doesn't 11781 * have any property group either. 11782 */ 11783 11784 result = SCF_ERROR_NONE; 11785 11786 if (isservice) { 11787 svc = (scf_service_t *)entity; 11788 11789 if ((inst = scf_instance_create(g_hndl)) == NULL || 11790 (iter = scf_iter_create(g_hndl)) == NULL) 11791 scfdie(); 11792 11793 name_buf = safe_malloc(max_scf_name_len + 1); 11794 } else { 11795 inst = (scf_instance_t *)entity; 11796 } 11797 11798 /* 11799 * If the entity is an instance and we've just deleted its last 11800 * property group then we should delete it. 11801 */ 11802 if (!isservice && entity_has_no_pgs(entity, isservice)) { 11803 /* find the service before deleting the inst. - needed later */ 11804 if ((svc = scf_service_create(g_hndl)) == NULL) 11805 scfdie(); 11806 11807 if (scf_instance_get_parent(inst, svc) != 0) 11808 scfdie(); 11809 11810 /* delete the instance */ 11811 if (scf_instance_delete(inst) != 0) { 11812 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11813 scfdie(); 11814 11815 result = SCF_ERROR_PERMISSION_DENIED; 11816 goto out; 11817 } 11818 /* no need to refresh the instance */ 11819 inst = NULL; 11820 } 11821 11822 /* 11823 * If the service has no more instances and pgs or we just deleted the 11824 * last instance and the service doesn't have anymore propery groups 11825 * then the service should be deleted. 11826 */ 11827 if (svc != NULL && 11828 svc_has_no_insts(svc) && 11829 entity_has_no_pgs((void *)svc, 1)) { 11830 if (scf_service_delete(svc) == 0) { 11831 if (isservice) { 11832 /* no need to refresh the service */ 11833 svc = NULL; 11834 } 11835 11836 goto out; 11837 } 11838 11839 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11840 scfdie(); 11841 11842 result = SCF_ERROR_PERMISSION_DENIED; 11843 } 11844 11845 /* if the entity has not been deleted, refresh it */ 11846 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 11847 (void) refresh_entity(isservice, entity, fmri, inst, iter, 11848 name_buf); 11849 } 11850 11851 out: 11852 if (isservice && (inst != NULL && iter != NULL)) { 11853 free(name_buf); 11854 scf_iter_destroy(iter); 11855 scf_instance_destroy(inst); 11856 } 11857 11858 if (!isservice && svc != NULL) { 11859 scf_service_destroy(svc); 11860 } 11861 11862 scf_pg_destroy(pg); 11863 if (entity != NULL) 11864 entity_destroy(entity, isservice); 11865 11866 return (result); 11867 } 11868 11869 static int 11870 delete_dependents(scf_propertygroup_t *pg) 11871 { 11872 char *pgty, *name, *fmri; 11873 scf_property_t *prop; 11874 scf_value_t *val; 11875 scf_iter_t *iter; 11876 int r; 11877 scf_error_t err; 11878 11879 /* Verify that the pg has the correct type. */ 11880 pgty = safe_malloc(max_scf_pg_type_len + 1); 11881 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 11882 scfdie(); 11883 11884 if (strcmp(pgty, scf_group_framework) != 0) { 11885 if (g_verbose) { 11886 fmri = safe_malloc(max_scf_fmri_len + 1); 11887 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 11888 scfdie(); 11889 11890 warn(gettext("Property group %s is not of expected " 11891 "type %s.\n"), fmri, scf_group_framework); 11892 11893 free(fmri); 11894 } 11895 11896 free(pgty); 11897 return (-1); 11898 } 11899 11900 free(pgty); 11901 11902 /* map delete_dependency_pg onto the properties. */ 11903 if ((prop = scf_property_create(g_hndl)) == NULL || 11904 (val = scf_value_create(g_hndl)) == NULL || 11905 (iter = scf_iter_create(g_hndl)) == NULL) 11906 scfdie(); 11907 11908 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 11909 scfdie(); 11910 11911 name = safe_malloc(max_scf_name_len + 1); 11912 fmri = safe_malloc(max_scf_fmri_len + 2); 11913 11914 while ((r = scf_iter_next_property(iter, prop)) == 1) { 11915 scf_type_t ty; 11916 11917 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 11918 scfdie(); 11919 11920 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 11921 scfdie(); 11922 11923 if ((ty != SCF_TYPE_ASTRING && 11924 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 11925 prop_get_val(prop, val) != 0) 11926 continue; 11927 11928 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 11929 scfdie(); 11930 11931 err = delete_dependency_pg(fmri, name); 11932 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 11933 if (scf_property_to_fmri(prop, fmri, 11934 max_scf_fmri_len + 2) < 0) 11935 scfdie(); 11936 11937 warn(gettext("Value of %s is not a valid FMRI.\n"), 11938 fmri); 11939 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 11940 warn(gettext("Property group \"%s\" of entity \"%s\" " 11941 "does not have dependency type.\n"), name, fmri); 11942 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 11943 warn(gettext("Could not delete property group \"%s\" " 11944 "of entity \"%s\" (permission denied).\n"), name, 11945 fmri); 11946 } 11947 } 11948 if (r == -1) 11949 scfdie(); 11950 11951 scf_value_destroy(val); 11952 scf_property_destroy(prop); 11953 11954 return (0); 11955 } 11956 11957 /* 11958 * Returns 1 if the instance may be running, and 0 otherwise. 11959 */ 11960 static int 11961 inst_is_running(scf_instance_t *inst) 11962 { 11963 scf_propertygroup_t *pg; 11964 scf_property_t *prop; 11965 scf_value_t *val; 11966 char buf[MAX_SCF_STATE_STRING_SZ]; 11967 int ret = 0; 11968 ssize_t szret; 11969 11970 if ((pg = scf_pg_create(g_hndl)) == NULL || 11971 (prop = scf_property_create(g_hndl)) == NULL || 11972 (val = scf_value_create(g_hndl)) == NULL) 11973 scfdie(); 11974 11975 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 11976 if (scf_error() != SCF_ERROR_NOT_FOUND) 11977 scfdie(); 11978 goto out; 11979 } 11980 11981 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 11982 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 11983 prop_get_val(prop, val) != 0) 11984 goto out; 11985 11986 szret = scf_value_get_astring(val, buf, sizeof (buf)); 11987 assert(szret >= 0); 11988 11989 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 11990 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 11991 11992 out: 11993 scf_value_destroy(val); 11994 scf_property_destroy(prop); 11995 scf_pg_destroy(pg); 11996 return (ret); 11997 } 11998 11999 static uint8_t 12000 pg_is_external_dependency(scf_propertygroup_t *pg) 12001 { 12002 char *type; 12003 scf_value_t *val; 12004 scf_property_t *prop; 12005 uint8_t b = B_FALSE; 12006 12007 type = safe_malloc(max_scf_pg_type_len + 1); 12008 12009 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 12010 scfdie(); 12011 12012 if ((prop = scf_property_create(g_hndl)) == NULL || 12013 (val = scf_value_create(g_hndl)) == NULL) 12014 scfdie(); 12015 12016 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 12017 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 12018 if (scf_property_get_value(prop, val) != 0) 12019 scfdie(); 12020 if (scf_value_get_boolean(val, &b) != 0) 12021 scfdie(); 12022 } 12023 } 12024 12025 free(type); 12026 (void) scf_value_destroy(val); 12027 (void) scf_property_destroy(prop); 12028 12029 return (b); 12030 } 12031 12032 #define DELETE_FAILURE -1 12033 #define DELETE_SUCCESS_NOEXTDEPS 0 12034 #define DELETE_SUCCESS_EXTDEPS 1 12035 12036 /* 12037 * lscf_instance_delete() deletes an instance. Before calling 12038 * scf_instance_delete(), though, we make sure the instance isn't 12039 * running and delete dependencies in other entities which the instance 12040 * declared as "dependents". If there are dependencies which were 12041 * created for other entities, then instead of deleting the instance we 12042 * make it "empty" by deleting all other property groups and all 12043 * snapshots. 12044 * 12045 * lscf_instance_delete() verifies that there is no external dependency pgs 12046 * before suppressing the instance. If there is, then we must not remove them 12047 * now in case the instance is re-created otherwise the dependencies would be 12048 * lost. The external dependency pgs will be removed if the dependencies are 12049 * removed. 12050 * 12051 * Returns: 12052 * DELETE_FAILURE on failure 12053 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12054 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12055 */ 12056 static int 12057 lscf_instance_delete(scf_instance_t *inst, int force) 12058 { 12059 scf_propertygroup_t *pg; 12060 scf_snapshot_t *snap; 12061 scf_iter_t *iter; 12062 int err; 12063 int external = 0; 12064 12065 /* If we're not forcing and the instance is running, refuse. */ 12066 if (!force && inst_is_running(inst)) { 12067 char *fmri; 12068 12069 fmri = safe_malloc(max_scf_fmri_len + 1); 12070 12071 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 12072 scfdie(); 12073 12074 semerr(gettext("Instance %s may be running. " 12075 "Use delete -f if it is not.\n"), fmri); 12076 12077 free(fmri); 12078 return (DELETE_FAILURE); 12079 } 12080 12081 pg = scf_pg_create(g_hndl); 12082 if (pg == NULL) 12083 scfdie(); 12084 12085 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 12086 (void) delete_dependents(pg); 12087 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12088 scfdie(); 12089 12090 scf_pg_destroy(pg); 12091 12092 /* 12093 * If the instance has some external dependencies then we must 12094 * keep them in case the instance is reimported otherwise the 12095 * dependencies would be lost on reimport. 12096 */ 12097 if ((iter = scf_iter_create(g_hndl)) == NULL || 12098 (pg = scf_pg_create(g_hndl)) == NULL) 12099 scfdie(); 12100 12101 if (scf_iter_instance_pgs(iter, inst) < 0) 12102 scfdie(); 12103 12104 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 12105 if (pg_is_external_dependency(pg)) { 12106 external = 1; 12107 continue; 12108 } 12109 12110 if (scf_pg_delete(pg) != 0) { 12111 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12112 scfdie(); 12113 else { 12114 semerr(emsg_permission_denied); 12115 12116 (void) scf_iter_destroy(iter); 12117 (void) scf_pg_destroy(pg); 12118 return (DELETE_FAILURE); 12119 } 12120 } 12121 } 12122 12123 if (err == -1) 12124 scfdie(); 12125 12126 (void) scf_iter_destroy(iter); 12127 (void) scf_pg_destroy(pg); 12128 12129 if (external) { 12130 /* 12131 * All the pgs have been deleted for the instance except 12132 * the ones holding the external dependencies. 12133 * For the job to be complete, we must also delete the 12134 * snapshots associated with the instance. 12135 */ 12136 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 12137 NULL) 12138 scfdie(); 12139 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 12140 scfdie(); 12141 12142 if (scf_iter_instance_snapshots(iter, inst) == -1) 12143 scfdie(); 12144 12145 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 12146 if (_scf_snapshot_delete(snap) != 0) { 12147 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12148 scfdie(); 12149 12150 semerr(emsg_permission_denied); 12151 12152 (void) scf_iter_destroy(iter); 12153 (void) scf_snapshot_destroy(snap); 12154 return (DELETE_FAILURE); 12155 } 12156 } 12157 12158 if (err == -1) 12159 scfdie(); 12160 12161 (void) scf_iter_destroy(iter); 12162 (void) scf_snapshot_destroy(snap); 12163 return (DELETE_SUCCESS_EXTDEPS); 12164 } 12165 12166 if (scf_instance_delete(inst) != 0) { 12167 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12168 scfdie(); 12169 12170 semerr(emsg_permission_denied); 12171 12172 return (DELETE_FAILURE); 12173 } 12174 12175 return (DELETE_SUCCESS_NOEXTDEPS); 12176 } 12177 12178 /* 12179 * lscf_service_delete() deletes a service. Before calling 12180 * scf_service_delete(), though, we call lscf_instance_delete() for 12181 * each of the instances and delete dependencies in other entities 12182 * which were created as "dependents" of this service. If there are 12183 * dependencies which were created for other entities, then we delete 12184 * all other property groups in the service and leave it as "empty". 12185 * 12186 * lscf_service_delete() verifies that there is no external dependency 12187 * pgs at the instance & service level before suppressing the service. 12188 * If there is, then we must not remove them now in case the service 12189 * is re-imported otherwise the dependencies would be lost. The external 12190 * dependency pgs will be removed if the dependencies are removed. 12191 * 12192 * Returns: 12193 * DELETE_FAILURE on failure 12194 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 12195 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 12196 */ 12197 static int 12198 lscf_service_delete(scf_service_t *svc, int force) 12199 { 12200 int r; 12201 scf_instance_t *inst; 12202 scf_propertygroup_t *pg; 12203 scf_iter_t *iter; 12204 int ret; 12205 int external = 0; 12206 12207 if ((inst = scf_instance_create(g_hndl)) == NULL || 12208 (pg = scf_pg_create(g_hndl)) == NULL || 12209 (iter = scf_iter_create(g_hndl)) == NULL) 12210 scfdie(); 12211 12212 if (scf_iter_service_instances(iter, svc) != 0) 12213 scfdie(); 12214 12215 for (r = scf_iter_next_instance(iter, inst); 12216 r == 1; 12217 r = scf_iter_next_instance(iter, inst)) { 12218 12219 ret = lscf_instance_delete(inst, force); 12220 if (ret == DELETE_FAILURE) { 12221 scf_iter_destroy(iter); 12222 scf_pg_destroy(pg); 12223 scf_instance_destroy(inst); 12224 return (DELETE_FAILURE); 12225 } 12226 12227 /* 12228 * Record the fact that there is some external dependencies 12229 * at the instance level. 12230 */ 12231 if (ret == DELETE_SUCCESS_EXTDEPS) 12232 external |= 1; 12233 } 12234 12235 if (r != 0) 12236 scfdie(); 12237 12238 /* Delete dependency property groups in dependent services. */ 12239 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12240 (void) delete_dependents(pg); 12241 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12242 scfdie(); 12243 12244 scf_iter_destroy(iter); 12245 scf_pg_destroy(pg); 12246 scf_instance_destroy(inst); 12247 12248 /* 12249 * If the service has some external dependencies then we don't 12250 * want to remove them in case the service is re-imported. 12251 */ 12252 if ((pg = scf_pg_create(g_hndl)) == NULL || 12253 (iter = scf_iter_create(g_hndl)) == NULL) 12254 scfdie(); 12255 12256 if (scf_iter_service_pgs(iter, svc) < 0) 12257 scfdie(); 12258 12259 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12260 if (pg_is_external_dependency(pg)) { 12261 external |= 2; 12262 continue; 12263 } 12264 12265 if (scf_pg_delete(pg) != 0) { 12266 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12267 scfdie(); 12268 else { 12269 semerr(emsg_permission_denied); 12270 12271 (void) scf_iter_destroy(iter); 12272 (void) scf_pg_destroy(pg); 12273 return (DELETE_FAILURE); 12274 } 12275 } 12276 } 12277 12278 if (r == -1) 12279 scfdie(); 12280 12281 (void) scf_iter_destroy(iter); 12282 (void) scf_pg_destroy(pg); 12283 12284 if (external != 0) 12285 return (DELETE_SUCCESS_EXTDEPS); 12286 12287 if (scf_service_delete(svc) == 0) 12288 return (DELETE_SUCCESS_NOEXTDEPS); 12289 12290 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12291 scfdie(); 12292 12293 semerr(emsg_permission_denied); 12294 return (DELETE_FAILURE); 12295 } 12296 12297 static int 12298 delete_callback(void *data, scf_walkinfo_t *wip) 12299 { 12300 int force = (int)data; 12301 12302 if (wip->inst != NULL) 12303 (void) lscf_instance_delete(wip->inst, force); 12304 else 12305 (void) lscf_service_delete(wip->svc, force); 12306 12307 return (0); 12308 } 12309 12310 void 12311 lscf_delete(const char *fmri, int force) 12312 { 12313 scf_service_t *svc; 12314 scf_instance_t *inst; 12315 int ret; 12316 12317 lscf_prep_hndl(); 12318 12319 if (cur_snap != NULL) { 12320 if (!snaplevel_is_instance(cur_level)) { 12321 char *buf; 12322 12323 buf = safe_malloc(max_scf_name_len + 1); 12324 if (scf_instance_get_name(cur_inst, buf, 12325 max_scf_name_len + 1) >= 0) { 12326 if (strcmp(buf, fmri) == 0) { 12327 semerr(emsg_cant_modify_snapshots); 12328 free(buf); 12329 return; 12330 } 12331 } else if (scf_error() != SCF_ERROR_DELETED) { 12332 scfdie(); 12333 } 12334 free(buf); 12335 } 12336 } else if (cur_inst != NULL) { 12337 /* EMPTY */; 12338 } else if (cur_svc != NULL) { 12339 inst = scf_instance_create(g_hndl); 12340 if (inst == NULL) 12341 scfdie(); 12342 12343 if (scf_service_get_instance(cur_svc, fmri, inst) == 12344 SCF_SUCCESS) { 12345 (void) lscf_instance_delete(inst, force); 12346 scf_instance_destroy(inst); 12347 return; 12348 } 12349 12350 if (scf_error() != SCF_ERROR_NOT_FOUND && 12351 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12352 scfdie(); 12353 12354 scf_instance_destroy(inst); 12355 } else { 12356 assert(cur_scope != NULL); 12357 12358 svc = scf_service_create(g_hndl); 12359 if (svc == NULL) 12360 scfdie(); 12361 12362 if (scf_scope_get_service(cur_scope, fmri, svc) == 12363 SCF_SUCCESS) { 12364 (void) lscf_service_delete(svc, force); 12365 scf_service_destroy(svc); 12366 return; 12367 } 12368 12369 if (scf_error() != SCF_ERROR_NOT_FOUND && 12370 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12371 scfdie(); 12372 12373 scf_service_destroy(svc); 12374 } 12375 12376 /* 12377 * Match FMRI to entity. 12378 */ 12379 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12380 delete_callback, (void *)force, NULL, semerr)) != 0) { 12381 semerr(gettext("Failed to walk instances: %s\n"), 12382 scf_strerror(ret)); 12383 } 12384 } 12385 12386 12387 12388 /* 12389 * :properties commands. These all end with "pg" or "prop" and generally 12390 * operate on the currently selected entity. 12391 */ 12392 12393 /* 12394 * Property listing. List the property groups, properties, their types and 12395 * their values for the currently selected entity. 12396 */ 12397 static void 12398 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12399 { 12400 char *buf; 12401 uint32_t flags; 12402 12403 buf = safe_malloc(max_scf_pg_type_len + 1); 12404 12405 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12406 scfdie(); 12407 12408 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12409 scfdie(); 12410 12411 safe_printf("%-*s %s", namewidth, name, buf); 12412 12413 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12414 safe_printf("\tNONPERSISTENT"); 12415 12416 safe_printf("\n"); 12417 12418 free(buf); 12419 } 12420 12421 static boolean_t 12422 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12423 { 12424 if (scf_property_get_value(prop, val) == 0) { 12425 return (B_FALSE); 12426 } else { 12427 switch (scf_error()) { 12428 case SCF_ERROR_NOT_FOUND: 12429 return (B_FALSE); 12430 case SCF_ERROR_PERMISSION_DENIED: 12431 case SCF_ERROR_CONSTRAINT_VIOLATED: 12432 return (B_TRUE); 12433 default: 12434 scfdie(); 12435 /*NOTREACHED*/ 12436 } 12437 } 12438 } 12439 12440 static void 12441 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12442 { 12443 scf_iter_t *iter; 12444 scf_value_t *val; 12445 const char *type; 12446 int multiple_strings = 0; 12447 int ret; 12448 12449 if ((iter = scf_iter_create(g_hndl)) == NULL || 12450 (val = scf_value_create(g_hndl)) == NULL) 12451 scfdie(); 12452 12453 type = prop_to_typestr(prop); 12454 assert(type != NULL); 12455 12456 safe_printf("%-*s %-7s ", len, name, type); 12457 12458 if (prop_has_multiple_values(prop, val) && 12459 (scf_value_type(val) == SCF_TYPE_ASTRING || 12460 scf_value_type(val) == SCF_TYPE_USTRING)) 12461 multiple_strings = 1; 12462 12463 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12464 scfdie(); 12465 12466 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12467 char *buf; 12468 ssize_t vlen, szret; 12469 12470 vlen = scf_value_get_as_string(val, NULL, 0); 12471 if (vlen < 0) 12472 scfdie(); 12473 12474 buf = safe_malloc(vlen + 1); 12475 12476 szret = scf_value_get_as_string(val, buf, vlen + 1); 12477 if (szret < 0) 12478 scfdie(); 12479 assert(szret <= vlen); 12480 12481 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12482 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12483 safe_printf(" \""); 12484 (void) quote_and_print(buf, stdout, 0); 12485 (void) putchar('"'); 12486 if (ferror(stdout)) { 12487 (void) putchar('\n'); 12488 uu_die(gettext("Error writing to stdout.\n")); 12489 } 12490 } else { 12491 safe_printf(" %s", buf); 12492 } 12493 12494 free(buf); 12495 } 12496 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12497 scfdie(); 12498 12499 if (putchar('\n') != '\n') 12500 uu_die(gettext("Could not output newline")); 12501 } 12502 12503 /* 12504 * Outputs template property group info for the describe subcommand. 12505 * If 'templates' == 2, verbose output is printed in the format expected 12506 * for describe -v, which includes all templates fields. If pg is 12507 * not NULL, we're describing the template data, not an existing property 12508 * group, and formatting should be appropriate for describe -t. 12509 */ 12510 static void 12511 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12512 { 12513 char *buf; 12514 uint8_t required; 12515 scf_property_t *stability_prop; 12516 scf_value_t *stability_val; 12517 12518 if (templates == 0) 12519 return; 12520 12521 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12522 (stability_val = scf_value_create(g_hndl)) == NULL) 12523 scfdie(); 12524 12525 if (templates == 2 && pg != NULL) { 12526 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12527 stability_prop) == 0) { 12528 if (prop_check_type(stability_prop, 12529 SCF_TYPE_ASTRING) == 0 && 12530 prop_get_val(stability_prop, stability_val) == 0) { 12531 char *stability; 12532 12533 stability = safe_malloc(max_scf_value_len + 1); 12534 12535 if (scf_value_get_astring(stability_val, 12536 stability, max_scf_value_len + 1) == -1 && 12537 scf_error() != SCF_ERROR_NOT_FOUND) 12538 scfdie(); 12539 12540 safe_printf("%s%s: %s\n", TMPL_INDENT, 12541 gettext("stability"), stability); 12542 12543 free(stability); 12544 } 12545 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12546 scfdie(); 12547 } 12548 12549 scf_property_destroy(stability_prop); 12550 scf_value_destroy(stability_val); 12551 12552 if (pgt == NULL) 12553 return; 12554 12555 if (pg == NULL || templates == 2) { 12556 /* print type info only if scf_tmpl_pg_name succeeds */ 12557 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12558 if (pg != NULL) 12559 safe_printf("%s", TMPL_INDENT); 12560 safe_printf("%s: ", gettext("name")); 12561 safe_printf("%s\n", buf); 12562 free(buf); 12563 } 12564 12565 /* print type info only if scf_tmpl_pg_type succeeds */ 12566 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12567 if (pg != NULL) 12568 safe_printf("%s", TMPL_INDENT); 12569 safe_printf("%s: ", gettext("type")); 12570 safe_printf("%s\n", buf); 12571 free(buf); 12572 } 12573 } 12574 12575 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12576 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12577 required ? "true" : "false"); 12578 12579 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12580 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12581 buf); 12582 free(buf); 12583 } 12584 12585 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12586 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12587 buf); 12588 free(buf); 12589 } 12590 12591 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12592 if (templates == 2) 12593 safe_printf("%s%s: %s\n", TMPL_INDENT, 12594 gettext("description"), buf); 12595 else 12596 safe_printf("%s%s\n", TMPL_INDENT, buf); 12597 free(buf); 12598 } 12599 12600 } 12601 12602 /* 12603 * With as_value set to true, indent as appropriate for the value level. 12604 * If false, indent to appropriate level for inclusion in constraint 12605 * or choice printout. 12606 */ 12607 static void 12608 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12609 int as_value) 12610 { 12611 char *buf; 12612 12613 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12614 if (as_value == 0) 12615 safe_printf("%s", TMPL_CHOICE_INDENT); 12616 else 12617 safe_printf("%s", TMPL_INDENT); 12618 safe_printf("%s: %s\n", gettext("value common name"), buf); 12619 free(buf); 12620 } 12621 12622 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12623 if (as_value == 0) 12624 safe_printf("%s", TMPL_CHOICE_INDENT); 12625 else 12626 safe_printf("%s", TMPL_INDENT); 12627 safe_printf("%s: %s\n", gettext("value description"), buf); 12628 free(buf); 12629 } 12630 } 12631 12632 static void 12633 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12634 { 12635 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12636 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12637 safe_printf("%s\n", val_buf); 12638 12639 print_template_value_details(prt, val_buf, 1); 12640 } 12641 12642 static void 12643 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12644 { 12645 int i, printed = 0; 12646 scf_values_t values; 12647 scf_count_ranges_t c_ranges; 12648 scf_int_ranges_t i_ranges; 12649 12650 printed = 0; 12651 i = 0; 12652 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12653 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12654 gettext("value constraints")); 12655 printed++; 12656 for (i = 0; i < values.value_count; ++i) { 12657 safe_printf("%s%s: %s\n", TMPL_INDENT, 12658 gettext("value name"), values.values_as_strings[i]); 12659 if (verbose == 1) 12660 print_template_value_details(prt, 12661 values.values_as_strings[i], 0); 12662 } 12663 12664 scf_values_destroy(&values); 12665 } 12666 12667 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12668 if (printed++ == 0) 12669 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12670 gettext("value constraints")); 12671 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12672 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12673 gettext("range"), c_ranges.scr_min[i], 12674 c_ranges.scr_max[i]); 12675 } 12676 scf_count_ranges_destroy(&c_ranges); 12677 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12678 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 12679 if (printed++ == 0) 12680 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12681 gettext("value constraints")); 12682 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12683 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12684 gettext("range"), i_ranges.sir_min[i], 12685 i_ranges.sir_max[i]); 12686 } 12687 scf_int_ranges_destroy(&i_ranges); 12688 } 12689 } 12690 12691 static void 12692 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 12693 { 12694 int i = 0, printed = 0; 12695 scf_values_t values; 12696 scf_count_ranges_t c_ranges; 12697 scf_int_ranges_t i_ranges; 12698 12699 printed = 0; 12700 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 12701 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12702 gettext("value constraints")); 12703 printed++; 12704 for (i = 0; i < values.value_count; i++) { 12705 safe_printf("%s%s: %s\n", TMPL_INDENT, 12706 gettext("value name"), values.values_as_strings[i]); 12707 if (verbose == 1) 12708 print_template_value_details(prt, 12709 values.values_as_strings[i], 0); 12710 } 12711 12712 scf_values_destroy(&values); 12713 } 12714 12715 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 12716 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12717 if (printed++ == 0) 12718 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12719 gettext("value choices")); 12720 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12721 gettext("range"), c_ranges.scr_min[i], 12722 c_ranges.scr_max[i]); 12723 } 12724 scf_count_ranges_destroy(&c_ranges); 12725 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12726 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 12727 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12728 if (printed++ == 0) 12729 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12730 gettext("value choices")); 12731 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12732 gettext("range"), i_ranges.sir_min[i], 12733 i_ranges.sir_max[i]); 12734 } 12735 scf_int_ranges_destroy(&i_ranges); 12736 } 12737 } 12738 12739 static void 12740 list_values_by_template(scf_prop_tmpl_t *prt) 12741 { 12742 print_template_constraints(prt, 1); 12743 print_template_choices(prt, 1); 12744 } 12745 12746 static void 12747 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 12748 { 12749 char *val_buf; 12750 scf_iter_t *iter; 12751 scf_value_t *val; 12752 int ret; 12753 12754 if ((iter = scf_iter_create(g_hndl)) == NULL || 12755 (val = scf_value_create(g_hndl)) == NULL) 12756 scfdie(); 12757 12758 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12759 scfdie(); 12760 12761 val_buf = safe_malloc(max_scf_value_len + 1); 12762 12763 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12764 if (scf_value_get_as_string(val, val_buf, 12765 max_scf_value_len + 1) < 0) 12766 scfdie(); 12767 12768 print_template_value(prt, val_buf); 12769 } 12770 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12771 scfdie(); 12772 free(val_buf); 12773 12774 print_template_constraints(prt, 0); 12775 print_template_choices(prt, 0); 12776 12777 } 12778 12779 /* 12780 * Outputs property info for the describe subcommand 12781 * Verbose output if templates == 2, -v option of svccfg describe 12782 * Displays template data if prop is not NULL, -t option of svccfg describe 12783 */ 12784 static void 12785 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 12786 { 12787 char *buf; 12788 uint8_t u_buf; 12789 int i; 12790 uint64_t min, max; 12791 scf_values_t values; 12792 12793 if (prt == NULL || templates == 0) 12794 return; 12795 12796 if (prop == NULL) { 12797 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 12798 if (scf_tmpl_prop_name(prt, &buf) > 0) { 12799 safe_printf("%s\n", buf); 12800 free(buf); 12801 } else 12802 safe_printf("(%s)\n", gettext("any")); 12803 } 12804 12805 if (prop == NULL || templates == 2) { 12806 if (prop != NULL) 12807 safe_printf("%s", TMPL_INDENT); 12808 else 12809 safe_printf("%s", TMPL_VALUE_INDENT); 12810 safe_printf("%s: ", gettext("type")); 12811 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 12812 safe_printf("%s\n", buf); 12813 free(buf); 12814 } else 12815 safe_printf("(%s)\n", gettext("any")); 12816 } 12817 12818 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 12819 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12820 u_buf ? "true" : "false"); 12821 12822 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 12823 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12824 buf); 12825 free(buf); 12826 } 12827 12828 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 12829 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 12830 buf); 12831 free(buf); 12832 } 12833 12834 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 12835 safe_printf("%s%s\n", TMPL_INDENT, buf); 12836 free(buf); 12837 } 12838 12839 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 12840 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 12841 scf_tmpl_visibility_to_string(u_buf)); 12842 12843 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 12844 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 12845 gettext("minimum number of values"), min); 12846 if (max == ULLONG_MAX) { 12847 safe_printf("%s%s: %s\n", TMPL_INDENT, 12848 gettext("maximum number of values"), 12849 gettext("unlimited")); 12850 } else { 12851 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 12852 gettext("maximum number of values"), max); 12853 } 12854 } 12855 12856 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 12857 for (i = 0; i < values.value_count; i++) { 12858 if (i == 0) { 12859 safe_printf("%s%s:", TMPL_INDENT, 12860 gettext("internal separators")); 12861 } 12862 safe_printf(" \"%s\"", values.values_as_strings[i]); 12863 } 12864 safe_printf("\n"); 12865 } 12866 12867 if (templates != 2) 12868 return; 12869 12870 if (prop != NULL) 12871 list_values_tmpl(prt, prop); 12872 else 12873 list_values_by_template(prt); 12874 } 12875 12876 static char * 12877 read_astring(scf_propertygroup_t *pg, const char *prop_name) 12878 { 12879 char *rv; 12880 12881 rv = _scf_read_single_astring_from_pg(pg, prop_name); 12882 if (rv == NULL) { 12883 switch (scf_error()) { 12884 case SCF_ERROR_NOT_FOUND: 12885 break; 12886 default: 12887 scfdie(); 12888 } 12889 } 12890 return (rv); 12891 } 12892 12893 static void 12894 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 12895 { 12896 size_t doc_len; 12897 size_t man_len; 12898 char *pg_name; 12899 char *text = NULL; 12900 int rv; 12901 12902 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 12903 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 12904 pg_name = safe_malloc(max_scf_name_len + 1); 12905 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 12906 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 12907 scfdie(); 12908 } 12909 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 12910 /* Display doc_link and and uri */ 12911 safe_printf("%s%s:\n", TMPL_INDENT, 12912 gettext("doc_link")); 12913 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 12914 if (text != NULL) { 12915 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12916 TMPL_INDENT, gettext("name"), text); 12917 uu_free(text); 12918 } 12919 text = read_astring(pg, SCF_PROPERTY_TM_URI); 12920 if (text != NULL) { 12921 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 12922 gettext("uri"), text); 12923 uu_free(text); 12924 } 12925 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 12926 man_len) == 0) { 12927 /* Display manpage title, section and path */ 12928 safe_printf("%s%s:\n", TMPL_INDENT, 12929 gettext("manpage")); 12930 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 12931 if (text != NULL) { 12932 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12933 TMPL_INDENT, gettext("title"), text); 12934 uu_free(text); 12935 } 12936 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 12937 if (text != NULL) { 12938 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12939 TMPL_INDENT, gettext("section"), text); 12940 uu_free(text); 12941 } 12942 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 12943 if (text != NULL) { 12944 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12945 TMPL_INDENT, gettext("manpath"), text); 12946 uu_free(text); 12947 } 12948 } 12949 } 12950 if (rv == -1) 12951 scfdie(); 12952 12953 done: 12954 free(pg_name); 12955 } 12956 12957 static void 12958 list_entity_tmpl(int templates) 12959 { 12960 char *common_name = NULL; 12961 char *description = NULL; 12962 char *locale = NULL; 12963 scf_iter_t *iter; 12964 scf_propertygroup_t *pg; 12965 scf_property_t *prop; 12966 int r; 12967 scf_value_t *val; 12968 12969 if ((pg = scf_pg_create(g_hndl)) == NULL || 12970 (prop = scf_property_create(g_hndl)) == NULL || 12971 (val = scf_value_create(g_hndl)) == NULL || 12972 (iter = scf_iter_create(g_hndl)) == NULL) 12973 scfdie(); 12974 12975 locale = setlocale(LC_MESSAGES, NULL); 12976 12977 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 12978 common_name = safe_malloc(max_scf_value_len + 1); 12979 12980 /* Try both the current locale and the "C" locale. */ 12981 if (scf_pg_get_property(pg, locale, prop) == 0 || 12982 (scf_error() == SCF_ERROR_NOT_FOUND && 12983 scf_pg_get_property(pg, "C", prop) == 0)) { 12984 if (prop_get_val(prop, val) == 0 && 12985 scf_value_get_ustring(val, common_name, 12986 max_scf_value_len + 1) != -1) { 12987 safe_printf("%s%s: %s\n", TMPL_INDENT, 12988 gettext("common name"), common_name); 12989 } 12990 } 12991 } 12992 12993 /* 12994 * Do description, manpages, and doc links if templates == 2. 12995 */ 12996 if (templates == 2) { 12997 /* Get the description. */ 12998 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 12999 description = safe_malloc(max_scf_value_len + 1); 13000 13001 /* Try both the current locale and the "C" locale. */ 13002 if (scf_pg_get_property(pg, locale, prop) == 0 || 13003 (scf_error() == SCF_ERROR_NOT_FOUND && 13004 scf_pg_get_property(pg, "C", prop) == 0)) { 13005 if (prop_get_val(prop, val) == 0 && 13006 scf_value_get_ustring(val, description, 13007 max_scf_value_len + 1) != -1) { 13008 safe_printf("%s%s: %s\n", TMPL_INDENT, 13009 gettext("description"), 13010 description); 13011 } 13012 } 13013 } 13014 13015 /* Process doc_link & manpage elements. */ 13016 if (cur_level != NULL) { 13017 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 13018 SCF_GROUP_TEMPLATE); 13019 } else if (cur_inst != NULL) { 13020 r = scf_iter_instance_pgs_typed(iter, cur_inst, 13021 SCF_GROUP_TEMPLATE); 13022 } else { 13023 r = scf_iter_service_pgs_typed(iter, cur_svc, 13024 SCF_GROUP_TEMPLATE); 13025 } 13026 if (r == 0) { 13027 display_documentation(iter, pg); 13028 } 13029 } 13030 13031 free(common_name); 13032 free(description); 13033 scf_pg_destroy(pg); 13034 scf_property_destroy(prop); 13035 scf_value_destroy(val); 13036 scf_iter_destroy(iter); 13037 } 13038 13039 static void 13040 listtmpl(const char *pattern, int templates) 13041 { 13042 scf_pg_tmpl_t *pgt; 13043 scf_prop_tmpl_t *prt; 13044 char *snapbuf = NULL; 13045 char *fmribuf; 13046 char *pg_name = NULL, *prop_name = NULL; 13047 ssize_t prop_name_size; 13048 char *qual_prop_name; 13049 char *search_name; 13050 int listed = 0; 13051 13052 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13053 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 13054 scfdie(); 13055 13056 fmribuf = safe_malloc(max_scf_name_len + 1); 13057 qual_prop_name = safe_malloc(max_scf_name_len + 1); 13058 13059 if (cur_snap != NULL) { 13060 snapbuf = safe_malloc(max_scf_name_len + 1); 13061 if (scf_snapshot_get_name(cur_snap, snapbuf, 13062 max_scf_name_len + 1) < 0) 13063 scfdie(); 13064 } 13065 13066 if (cur_inst != NULL) { 13067 if (scf_instance_to_fmri(cur_inst, fmribuf, 13068 max_scf_name_len + 1) < 0) 13069 scfdie(); 13070 } else if (cur_svc != NULL) { 13071 if (scf_service_to_fmri(cur_svc, fmribuf, 13072 max_scf_name_len + 1) < 0) 13073 scfdie(); 13074 } else 13075 abort(); 13076 13077 /* If pattern is specified, we want to list only those items. */ 13078 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) { 13079 listed = 0; 13080 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 13081 fnmatch(pattern, pg_name, 0) == 0)) { 13082 list_pg_tmpl(pgt, NULL, templates); 13083 listed++; 13084 } 13085 13086 scf_tmpl_prop_reset(prt); 13087 13088 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) { 13089 search_name = NULL; 13090 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 13091 if ((prop_name_size > 0) && (pg_name != NULL)) { 13092 if (snprintf(qual_prop_name, 13093 max_scf_name_len + 1, "%s/%s", 13094 pg_name, prop_name) >= 13095 max_scf_name_len + 1) { 13096 prop_name_size = -1; 13097 } else { 13098 search_name = qual_prop_name; 13099 } 13100 } 13101 if (listed > 0 || pattern == NULL || 13102 (prop_name_size > 0 && 13103 fnmatch(pattern, search_name, 13104 FNM_PATHNAME) == 0)) 13105 list_prop_tmpl(prt, NULL, templates); 13106 if (prop_name != NULL) { 13107 free(prop_name); 13108 prop_name = NULL; 13109 } 13110 } 13111 if (pg_name != NULL) { 13112 free(pg_name); 13113 pg_name = NULL; 13114 } 13115 } 13116 13117 scf_tmpl_prop_destroy(prt); 13118 scf_tmpl_pg_destroy(pgt); 13119 free(snapbuf); 13120 free(fmribuf); 13121 free(qual_prop_name); 13122 } 13123 13124 static void 13125 listprop(const char *pattern, int only_pgs, int templates) 13126 { 13127 scf_propertygroup_t *pg; 13128 scf_property_t *prop; 13129 scf_iter_t *iter, *piter; 13130 char *pgnbuf, *prnbuf, *ppnbuf; 13131 scf_pg_tmpl_t *pgt, *pgtp; 13132 scf_prop_tmpl_t *prt; 13133 13134 void **objects; 13135 char **names; 13136 void **tmpls; 13137 int allocd, i; 13138 13139 int ret; 13140 ssize_t pgnlen, prnlen, szret; 13141 size_t max_len = 0; 13142 13143 if (cur_svc == NULL && cur_inst == NULL) { 13144 semerr(emsg_entity_not_selected); 13145 return; 13146 } 13147 13148 if ((pg = scf_pg_create(g_hndl)) == NULL || 13149 (prop = scf_property_create(g_hndl)) == NULL || 13150 (iter = scf_iter_create(g_hndl)) == NULL || 13151 (piter = scf_iter_create(g_hndl)) == NULL || 13152 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13153 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 13154 scfdie(); 13155 13156 prnbuf = safe_malloc(max_scf_name_len + 1); 13157 13158 if (cur_level != NULL) 13159 ret = scf_iter_snaplevel_pgs(iter, cur_level); 13160 else if (cur_inst != NULL) 13161 ret = scf_iter_instance_pgs(iter, cur_inst); 13162 else 13163 ret = scf_iter_service_pgs(iter, cur_svc); 13164 if (ret != 0) { 13165 return; 13166 } 13167 13168 /* 13169 * We want to only list items which match pattern, and we want the 13170 * second column to line up, so during the first pass we'll save 13171 * matching items, their names, and their templates in objects, 13172 * names, and tmpls, computing the maximum name length as we go, 13173 * and then we'll print them out. 13174 * 13175 * Note: We always keep an extra slot available so the array can be 13176 * NULL-terminated. 13177 */ 13178 i = 0; 13179 allocd = 1; 13180 objects = safe_malloc(sizeof (*objects)); 13181 names = safe_malloc(sizeof (*names)); 13182 tmpls = safe_malloc(sizeof (*tmpls)); 13183 13184 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13185 int new_pg = 0; 13186 int print_props = 0; 13187 pgtp = NULL; 13188 13189 pgnlen = scf_pg_get_name(pg, NULL, 0); 13190 if (pgnlen < 0) 13191 scfdie(); 13192 13193 pgnbuf = safe_malloc(pgnlen + 1); 13194 13195 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 13196 if (szret < 0) 13197 scfdie(); 13198 assert(szret <= pgnlen); 13199 13200 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) { 13201 if (scf_error() != SCF_ERROR_NOT_FOUND) 13202 scfdie(); 13203 pgtp = NULL; 13204 } else { 13205 pgtp = pgt; 13206 } 13207 13208 if (pattern == NULL || 13209 fnmatch(pattern, pgnbuf, 0) == 0) { 13210 if (i+1 >= allocd) { 13211 allocd *= 2; 13212 objects = realloc(objects, 13213 sizeof (*objects) * allocd); 13214 names = 13215 realloc(names, sizeof (*names) * allocd); 13216 tmpls = realloc(tmpls, 13217 sizeof (*tmpls) * allocd); 13218 if (objects == NULL || names == NULL || 13219 tmpls == NULL) 13220 uu_die(gettext("Out of memory")); 13221 } 13222 objects[i] = pg; 13223 names[i] = pgnbuf; 13224 13225 if (pgtp == NULL) 13226 tmpls[i] = NULL; 13227 else 13228 tmpls[i] = pgt; 13229 13230 ++i; 13231 13232 if (pgnlen > max_len) 13233 max_len = pgnlen; 13234 13235 new_pg = 1; 13236 print_props = 1; 13237 } 13238 13239 if (only_pgs) { 13240 if (new_pg) { 13241 pg = scf_pg_create(g_hndl); 13242 if (pg == NULL) 13243 scfdie(); 13244 pgt = scf_tmpl_pg_create(g_hndl); 13245 if (pgt == NULL) 13246 scfdie(); 13247 } else 13248 free(pgnbuf); 13249 13250 continue; 13251 } 13252 13253 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13254 scfdie(); 13255 13256 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13257 prnlen = scf_property_get_name(prop, prnbuf, 13258 max_scf_name_len + 1); 13259 if (prnlen < 0) 13260 scfdie(); 13261 13262 /* Will prepend the property group name and a slash. */ 13263 prnlen += pgnlen + 1; 13264 13265 ppnbuf = safe_malloc(prnlen + 1); 13266 13267 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13268 prnbuf) < 0) 13269 uu_die("snprintf"); 13270 13271 if (pattern == NULL || print_props == 1 || 13272 fnmatch(pattern, ppnbuf, 0) == 0) { 13273 if (i+1 >= allocd) { 13274 allocd *= 2; 13275 objects = realloc(objects, 13276 sizeof (*objects) * allocd); 13277 names = realloc(names, 13278 sizeof (*names) * allocd); 13279 tmpls = realloc(tmpls, 13280 sizeof (*tmpls) * allocd); 13281 if (objects == NULL || names == NULL || 13282 tmpls == NULL) 13283 uu_die(gettext( 13284 "Out of memory")); 13285 } 13286 13287 objects[i] = prop; 13288 names[i] = ppnbuf; 13289 13290 if (pgtp != NULL) { 13291 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13292 prt, 0) < 0) { 13293 if (scf_error() != 13294 SCF_ERROR_NOT_FOUND) 13295 scfdie(); 13296 tmpls[i] = NULL; 13297 } else { 13298 tmpls[i] = prt; 13299 } 13300 } else { 13301 tmpls[i] = NULL; 13302 } 13303 13304 ++i; 13305 13306 if (prnlen > max_len) 13307 max_len = prnlen; 13308 13309 prop = scf_property_create(g_hndl); 13310 prt = scf_tmpl_prop_create(g_hndl); 13311 } else { 13312 free(ppnbuf); 13313 } 13314 } 13315 13316 if (new_pg) { 13317 pg = scf_pg_create(g_hndl); 13318 if (pg == NULL) 13319 scfdie(); 13320 pgt = scf_tmpl_pg_create(g_hndl); 13321 if (pgt == NULL) 13322 scfdie(); 13323 } else 13324 free(pgnbuf); 13325 } 13326 if (ret != 0) 13327 scfdie(); 13328 13329 objects[i] = NULL; 13330 13331 scf_pg_destroy(pg); 13332 scf_tmpl_pg_destroy(pgt); 13333 scf_property_destroy(prop); 13334 scf_tmpl_prop_destroy(prt); 13335 13336 for (i = 0; objects[i] != NULL; ++i) { 13337 if (strchr(names[i], '/') == NULL) { 13338 /* property group */ 13339 pg = (scf_propertygroup_t *)objects[i]; 13340 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13341 list_pg_info(pg, names[i], max_len); 13342 list_pg_tmpl(pgt, pg, templates); 13343 free(names[i]); 13344 scf_pg_destroy(pg); 13345 if (pgt != NULL) 13346 scf_tmpl_pg_destroy(pgt); 13347 } else { 13348 /* property */ 13349 prop = (scf_property_t *)objects[i]; 13350 prt = (scf_prop_tmpl_t *)tmpls[i]; 13351 list_prop_info(prop, names[i], max_len); 13352 list_prop_tmpl(prt, prop, templates); 13353 free(names[i]); 13354 scf_property_destroy(prop); 13355 if (prt != NULL) 13356 scf_tmpl_prop_destroy(prt); 13357 } 13358 } 13359 13360 free(names); 13361 free(objects); 13362 free(tmpls); 13363 } 13364 13365 void 13366 lscf_listpg(const char *pattern) 13367 { 13368 lscf_prep_hndl(); 13369 13370 listprop(pattern, 1, 0); 13371 } 13372 13373 /* 13374 * Property group and property creation, setting, and deletion. setprop (and 13375 * its alias, addprop) can either create a property group of a given type, or 13376 * it can create or set a property to a given type and list of values. 13377 */ 13378 void 13379 lscf_addpg(const char *name, const char *type, const char *flags) 13380 { 13381 scf_propertygroup_t *pg; 13382 int ret; 13383 uint32_t flgs = 0; 13384 const char *cp; 13385 13386 13387 lscf_prep_hndl(); 13388 13389 if (cur_snap != NULL) { 13390 semerr(emsg_cant_modify_snapshots); 13391 return; 13392 } 13393 13394 if (cur_inst == NULL && cur_svc == NULL) { 13395 semerr(emsg_entity_not_selected); 13396 return; 13397 } 13398 13399 if (flags != NULL) { 13400 for (cp = flags; *cp != '\0'; ++cp) { 13401 switch (*cp) { 13402 case 'P': 13403 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13404 break; 13405 13406 case 'p': 13407 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13408 break; 13409 13410 default: 13411 semerr(gettext("Invalid property group flag " 13412 "%c."), *cp); 13413 return; 13414 } 13415 } 13416 } 13417 13418 pg = scf_pg_create(g_hndl); 13419 if (pg == NULL) 13420 scfdie(); 13421 13422 if (cur_inst != NULL) 13423 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13424 else 13425 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13426 13427 if (ret != SCF_SUCCESS) { 13428 switch (scf_error()) { 13429 case SCF_ERROR_INVALID_ARGUMENT: 13430 semerr(gettext("Name, type, or flags are invalid.\n")); 13431 break; 13432 13433 case SCF_ERROR_EXISTS: 13434 semerr(gettext("Property group already exists.\n")); 13435 break; 13436 13437 case SCF_ERROR_PERMISSION_DENIED: 13438 semerr(emsg_permission_denied); 13439 break; 13440 13441 case SCF_ERROR_BACKEND_ACCESS: 13442 semerr(gettext("Backend refused access.\n")); 13443 break; 13444 13445 default: 13446 scfdie(); 13447 } 13448 } 13449 13450 scf_pg_destroy(pg); 13451 13452 private_refresh(); 13453 } 13454 13455 void 13456 lscf_delpg(char *name) 13457 { 13458 lscf_prep_hndl(); 13459 13460 if (cur_snap != NULL) { 13461 semerr(emsg_cant_modify_snapshots); 13462 return; 13463 } 13464 13465 if (cur_inst == NULL && cur_svc == NULL) { 13466 semerr(emsg_entity_not_selected); 13467 return; 13468 } 13469 13470 if (strchr(name, '/') != NULL) { 13471 semerr(emsg_invalid_pg_name, name); 13472 return; 13473 } 13474 13475 lscf_delprop(name); 13476 } 13477 13478 /* 13479 * scf_delhash() is used to remove the property group related to the 13480 * hash entry for a specific manifest in the repository. pgname will be 13481 * constructed from the location of the manifest file. If deathrow isn't 0, 13482 * manifest file doesn't need to exist (manifest string will be used as 13483 * an absolute path). 13484 */ 13485 void 13486 lscf_delhash(char *manifest, int deathrow) 13487 { 13488 char *pgname; 13489 13490 if (cur_snap != NULL || 13491 cur_inst != NULL || cur_svc != NULL) { 13492 warn(gettext("error, an entity is selected\n")); 13493 return; 13494 } 13495 13496 /* select smf/manifest */ 13497 lscf_select(HASH_SVC); 13498 /* 13499 * Translate the manifest file name to property name. In the deathrow 13500 * case, the manifest file does not need to exist. 13501 */ 13502 pgname = mhash_filename_to_propname(manifest, 13503 deathrow ? B_TRUE : B_FALSE); 13504 if (pgname == NULL) { 13505 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13506 return; 13507 } 13508 /* delete the hash property name */ 13509 lscf_delpg(pgname); 13510 } 13511 13512 void 13513 lscf_listprop(const char *pattern) 13514 { 13515 lscf_prep_hndl(); 13516 13517 listprop(pattern, 0, 0); 13518 } 13519 13520 int 13521 lscf_setprop(const char *pgname, const char *type, const char *value, 13522 const uu_list_t *values) 13523 { 13524 scf_type_t ty, current_ty; 13525 scf_service_t *svc; 13526 scf_propertygroup_t *pg, *parent_pg; 13527 scf_property_t *prop, *parent_prop; 13528 scf_pg_tmpl_t *pgt; 13529 scf_prop_tmpl_t *prt; 13530 int ret, result = 0; 13531 scf_transaction_t *tx; 13532 scf_transaction_entry_t *e; 13533 scf_value_t *v; 13534 uu_list_walk_t *walk; 13535 string_list_t *sp; 13536 char *propname; 13537 int req_quotes = 0; 13538 13539 lscf_prep_hndl(); 13540 13541 if ((e = scf_entry_create(g_hndl)) == NULL || 13542 (svc = scf_service_create(g_hndl)) == NULL || 13543 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13544 (pg = scf_pg_create(g_hndl)) == NULL || 13545 (parent_prop = scf_property_create(g_hndl)) == NULL || 13546 (prop = scf_property_create(g_hndl)) == NULL || 13547 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13548 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13549 (tx = scf_transaction_create(g_hndl)) == NULL) 13550 scfdie(); 13551 13552 if (cur_snap != NULL) { 13553 semerr(emsg_cant_modify_snapshots); 13554 goto fail; 13555 } 13556 13557 if (cur_inst == NULL && cur_svc == NULL) { 13558 semerr(emsg_entity_not_selected); 13559 goto fail; 13560 } 13561 13562 propname = strchr(pgname, '/'); 13563 if (propname == NULL) { 13564 semerr(gettext("Property names must contain a `/'.\n")); 13565 goto fail; 13566 } 13567 13568 *propname = '\0'; 13569 ++propname; 13570 13571 if (type != NULL) { 13572 ty = string_to_type(type); 13573 if (ty == SCF_TYPE_INVALID) { 13574 semerr(gettext("Unknown type \"%s\".\n"), type); 13575 goto fail; 13576 } 13577 } 13578 13579 if (cur_inst != NULL) 13580 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13581 else 13582 ret = scf_service_get_pg(cur_svc, pgname, pg); 13583 if (ret != SCF_SUCCESS) { 13584 switch (scf_error()) { 13585 case SCF_ERROR_NOT_FOUND: 13586 semerr(emsg_no_such_pg, pgname); 13587 goto fail; 13588 13589 case SCF_ERROR_INVALID_ARGUMENT: 13590 semerr(emsg_invalid_pg_name, pgname); 13591 goto fail; 13592 13593 default: 13594 scfdie(); 13595 break; 13596 } 13597 } 13598 13599 do { 13600 if (scf_pg_update(pg) == -1) 13601 scfdie(); 13602 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13603 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13604 scfdie(); 13605 13606 semerr(emsg_permission_denied); 13607 goto fail; 13608 } 13609 13610 ret = scf_pg_get_property(pg, propname, prop); 13611 if (ret == SCF_SUCCESS) { 13612 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13613 scfdie(); 13614 13615 if (type == NULL) 13616 ty = current_ty; 13617 if (scf_transaction_property_change_type(tx, e, 13618 propname, ty) == -1) 13619 scfdie(); 13620 13621 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13622 /* Infer the type, if possible. */ 13623 if (type == NULL) { 13624 /* 13625 * First check if we're an instance and the 13626 * property is set on the service. 13627 */ 13628 if (cur_inst != NULL && 13629 scf_instance_get_parent(cur_inst, 13630 svc) == 0 && 13631 scf_service_get_pg(cur_svc, pgname, 13632 parent_pg) == 0 && 13633 scf_pg_get_property(parent_pg, propname, 13634 parent_prop) == 0 && 13635 scf_property_type(parent_prop, 13636 ¤t_ty) == 0) { 13637 ty = current_ty; 13638 13639 /* Then check for a type set in a template. */ 13640 } else if (scf_tmpl_get_by_pg(pg, pgt, 13641 0) == 0 && 13642 scf_tmpl_get_by_prop(pgt, propname, prt, 13643 0) == 0 && 13644 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13645 ty = current_ty; 13646 13647 /* If type can't be inferred, fail. */ 13648 } else { 13649 semerr(gettext("Type required for new " 13650 "properties.\n")); 13651 goto fail; 13652 } 13653 } 13654 if (scf_transaction_property_new(tx, e, propname, 13655 ty) == -1) 13656 scfdie(); 13657 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13658 semerr(emsg_invalid_prop_name, propname); 13659 goto fail; 13660 } else { 13661 scfdie(); 13662 } 13663 13664 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13665 req_quotes = 1; 13666 13667 if (value != NULL) { 13668 v = string_to_value(value, ty, 0); 13669 13670 if (v == NULL) 13671 goto fail; 13672 13673 ret = scf_entry_add_value(e, v); 13674 assert(ret == SCF_SUCCESS); 13675 } else { 13676 assert(values != NULL); 13677 13678 walk = uu_list_walk_start((uu_list_t *)values, 13679 UU_DEFAULT); 13680 if (walk == NULL) 13681 uu_die(gettext("Could not walk list")); 13682 13683 for (sp = uu_list_walk_next(walk); sp != NULL; 13684 sp = uu_list_walk_next(walk)) { 13685 v = string_to_value(sp->str, ty, req_quotes); 13686 13687 if (v == NULL) { 13688 scf_entry_destroy_children(e); 13689 goto fail; 13690 } 13691 13692 ret = scf_entry_add_value(e, v); 13693 assert(ret == SCF_SUCCESS); 13694 } 13695 uu_list_walk_end(walk); 13696 } 13697 result = scf_transaction_commit(tx); 13698 13699 scf_transaction_reset(tx); 13700 scf_entry_destroy_children(e); 13701 } while (result == 0); 13702 13703 if (result < 0) { 13704 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13705 scfdie(); 13706 13707 semerr(emsg_permission_denied); 13708 goto fail; 13709 } 13710 13711 ret = 0; 13712 13713 private_refresh(); 13714 13715 goto cleanup; 13716 13717 fail: 13718 ret = -1; 13719 13720 cleanup: 13721 scf_transaction_destroy(tx); 13722 scf_entry_destroy(e); 13723 scf_service_destroy(svc); 13724 scf_pg_destroy(parent_pg); 13725 scf_pg_destroy(pg); 13726 scf_property_destroy(parent_prop); 13727 scf_property_destroy(prop); 13728 scf_tmpl_pg_destroy(pgt); 13729 scf_tmpl_prop_destroy(prt); 13730 13731 return (ret); 13732 } 13733 13734 void 13735 lscf_delprop(char *pgn) 13736 { 13737 char *slash, *pn; 13738 scf_propertygroup_t *pg; 13739 scf_transaction_t *tx; 13740 scf_transaction_entry_t *e; 13741 int ret; 13742 13743 13744 lscf_prep_hndl(); 13745 13746 if (cur_snap != NULL) { 13747 semerr(emsg_cant_modify_snapshots); 13748 return; 13749 } 13750 13751 if (cur_inst == NULL && cur_svc == NULL) { 13752 semerr(emsg_entity_not_selected); 13753 return; 13754 } 13755 13756 pg = scf_pg_create(g_hndl); 13757 if (pg == NULL) 13758 scfdie(); 13759 13760 slash = strchr(pgn, '/'); 13761 if (slash == NULL) { 13762 pn = NULL; 13763 } else { 13764 *slash = '\0'; 13765 pn = slash + 1; 13766 } 13767 13768 if (cur_inst != NULL) 13769 ret = scf_instance_get_pg(cur_inst, pgn, pg); 13770 else 13771 ret = scf_service_get_pg(cur_svc, pgn, pg); 13772 if (ret != SCF_SUCCESS) { 13773 switch (scf_error()) { 13774 case SCF_ERROR_NOT_FOUND: 13775 semerr(emsg_no_such_pg, pgn); 13776 break; 13777 13778 case SCF_ERROR_INVALID_ARGUMENT: 13779 semerr(emsg_invalid_pg_name, pgn); 13780 break; 13781 13782 default: 13783 scfdie(); 13784 } 13785 13786 scf_pg_destroy(pg); 13787 13788 return; 13789 } 13790 13791 if (pn == NULL) { 13792 /* Try to delete the property group. */ 13793 if (scf_pg_delete(pg) != SCF_SUCCESS) { 13794 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13795 scfdie(); 13796 13797 semerr(emsg_permission_denied); 13798 } else { 13799 private_refresh(); 13800 } 13801 13802 scf_pg_destroy(pg); 13803 return; 13804 } 13805 13806 e = scf_entry_create(g_hndl); 13807 tx = scf_transaction_create(g_hndl); 13808 13809 do { 13810 if (scf_pg_update(pg) == -1) 13811 scfdie(); 13812 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13813 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13814 scfdie(); 13815 13816 semerr(emsg_permission_denied); 13817 break; 13818 } 13819 13820 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 13821 if (scf_error() == SCF_ERROR_NOT_FOUND) { 13822 semerr(gettext("No such property %s/%s.\n"), 13823 pgn, pn); 13824 break; 13825 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13826 semerr(emsg_invalid_prop_name, pn); 13827 break; 13828 } else { 13829 scfdie(); 13830 } 13831 } 13832 13833 ret = scf_transaction_commit(tx); 13834 13835 if (ret == 0) 13836 scf_transaction_reset(tx); 13837 } while (ret == 0); 13838 13839 if (ret < 0) { 13840 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13841 scfdie(); 13842 13843 semerr(emsg_permission_denied); 13844 } else { 13845 private_refresh(); 13846 } 13847 13848 scf_transaction_destroy(tx); 13849 scf_entry_destroy(e); 13850 scf_pg_destroy(pg); 13851 } 13852 13853 /* 13854 * Property editing. 13855 */ 13856 13857 static int 13858 write_edit_script(FILE *strm) 13859 { 13860 char *fmribuf; 13861 ssize_t fmrilen; 13862 13863 scf_propertygroup_t *pg; 13864 scf_property_t *prop; 13865 scf_value_t *val; 13866 scf_type_t ty; 13867 int ret, result = 0; 13868 scf_iter_t *iter, *piter, *viter; 13869 char *buf, *tybuf, *pname; 13870 const char *emsg_write_error; 13871 13872 13873 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 13874 13875 13876 /* select fmri */ 13877 if (cur_inst != NULL) { 13878 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 13879 if (fmrilen < 0) 13880 scfdie(); 13881 fmribuf = safe_malloc(fmrilen + 1); 13882 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 13883 scfdie(); 13884 } else { 13885 assert(cur_svc != NULL); 13886 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 13887 if (fmrilen < 0) 13888 scfdie(); 13889 fmribuf = safe_malloc(fmrilen + 1); 13890 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 13891 scfdie(); 13892 } 13893 13894 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 13895 warn(emsg_write_error, strerror(errno)); 13896 free(fmribuf); 13897 return (-1); 13898 } 13899 13900 free(fmribuf); 13901 13902 13903 if ((pg = scf_pg_create(g_hndl)) == NULL || 13904 (prop = scf_property_create(g_hndl)) == NULL || 13905 (val = scf_value_create(g_hndl)) == NULL || 13906 (iter = scf_iter_create(g_hndl)) == NULL || 13907 (piter = scf_iter_create(g_hndl)) == NULL || 13908 (viter = scf_iter_create(g_hndl)) == NULL) 13909 scfdie(); 13910 13911 buf = safe_malloc(max_scf_name_len + 1); 13912 tybuf = safe_malloc(max_scf_pg_type_len + 1); 13913 pname = safe_malloc(max_scf_name_len + 1); 13914 13915 if (cur_inst != NULL) 13916 ret = scf_iter_instance_pgs(iter, cur_inst); 13917 else 13918 ret = scf_iter_service_pgs(iter, cur_svc); 13919 if (ret != SCF_SUCCESS) 13920 scfdie(); 13921 13922 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13923 int ret2; 13924 13925 /* 13926 * # delprop pg 13927 * # addpg pg type 13928 */ 13929 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 13930 scfdie(); 13931 13932 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 13933 scfdie(); 13934 13935 if (fprintf(strm, "# Property group \"%s\"\n" 13936 "# delprop %s\n" 13937 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 13938 warn(emsg_write_error, strerror(errno)); 13939 result = -1; 13940 goto out; 13941 } 13942 13943 /* # setprop pg/prop = (values) */ 13944 13945 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13946 scfdie(); 13947 13948 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 13949 int first = 1; 13950 int ret3; 13951 int multiple; 13952 int is_str; 13953 scf_type_t bty; 13954 13955 if (scf_property_get_name(prop, pname, 13956 max_scf_name_len + 1) < 0) 13957 scfdie(); 13958 13959 if (scf_property_type(prop, &ty) != 0) 13960 scfdie(); 13961 13962 multiple = prop_has_multiple_values(prop, val); 13963 13964 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 13965 pname, scf_type_to_string(ty), multiple ? "(" : "") 13966 < 0) { 13967 warn(emsg_write_error, strerror(errno)); 13968 result = -1; 13969 goto out; 13970 } 13971 13972 (void) scf_type_base_type(ty, &bty); 13973 is_str = (bty == SCF_TYPE_ASTRING); 13974 13975 if (scf_iter_property_values(viter, prop) != 13976 SCF_SUCCESS) 13977 scfdie(); 13978 13979 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 13980 char *buf; 13981 ssize_t buflen; 13982 13983 buflen = scf_value_get_as_string(val, NULL, 0); 13984 if (buflen < 0) 13985 scfdie(); 13986 13987 buf = safe_malloc(buflen + 1); 13988 13989 if (scf_value_get_as_string(val, buf, 13990 buflen + 1) < 0) 13991 scfdie(); 13992 13993 if (first) 13994 first = 0; 13995 else { 13996 if (putc(' ', strm) != ' ') { 13997 warn(emsg_write_error, 13998 strerror(errno)); 13999 result = -1; 14000 goto out; 14001 } 14002 } 14003 14004 if ((is_str && multiple) || 14005 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 14006 (void) putc('"', strm); 14007 (void) quote_and_print(buf, strm, 1); 14008 (void) putc('"', strm); 14009 14010 if (ferror(strm)) { 14011 warn(emsg_write_error, 14012 strerror(errno)); 14013 result = -1; 14014 goto out; 14015 } 14016 } else { 14017 if (fprintf(strm, "%s", buf) < 0) { 14018 warn(emsg_write_error, 14019 strerror(errno)); 14020 result = -1; 14021 goto out; 14022 } 14023 } 14024 14025 free(buf); 14026 } 14027 if (ret3 < 0 && 14028 scf_error() != SCF_ERROR_PERMISSION_DENIED) 14029 scfdie(); 14030 14031 /* Write closing paren if mult-value property */ 14032 if ((multiple && putc(')', strm) == EOF) || 14033 14034 /* Write final newline */ 14035 fputc('\n', strm) == EOF) { 14036 warn(emsg_write_error, strerror(errno)); 14037 result = -1; 14038 goto out; 14039 } 14040 } 14041 if (ret2 < 0) 14042 scfdie(); 14043 14044 if (fputc('\n', strm) == EOF) { 14045 warn(emsg_write_error, strerror(errno)); 14046 result = -1; 14047 goto out; 14048 } 14049 } 14050 if (ret < 0) 14051 scfdie(); 14052 14053 out: 14054 free(pname); 14055 free(tybuf); 14056 free(buf); 14057 scf_iter_destroy(viter); 14058 scf_iter_destroy(piter); 14059 scf_iter_destroy(iter); 14060 scf_value_destroy(val); 14061 scf_property_destroy(prop); 14062 scf_pg_destroy(pg); 14063 14064 if (result == 0) { 14065 if (fflush(strm) != 0) { 14066 warn(emsg_write_error, strerror(errno)); 14067 return (-1); 14068 } 14069 } 14070 14071 return (result); 14072 } 14073 14074 int 14075 lscf_editprop() 14076 { 14077 char *buf, *editor; 14078 size_t bufsz; 14079 int tmpfd; 14080 char tempname[] = TEMP_FILE_PATTERN; 14081 14082 lscf_prep_hndl(); 14083 14084 if (cur_snap != NULL) { 14085 semerr(emsg_cant_modify_snapshots); 14086 return (-1); 14087 } 14088 14089 if (cur_svc == NULL && cur_inst == NULL) { 14090 semerr(emsg_entity_not_selected); 14091 return (-1); 14092 } 14093 14094 tmpfd = mkstemp(tempname); 14095 if (tmpfd == -1) { 14096 semerr(gettext("Could not create temporary file.\n")); 14097 return (-1); 14098 } 14099 14100 (void) strcpy(tempfilename, tempname); 14101 14102 tempfile = fdopen(tmpfd, "r+"); 14103 if (tempfile == NULL) { 14104 warn(gettext("Could not create temporary file.\n")); 14105 if (close(tmpfd) == -1) 14106 warn(gettext("Could not close temporary file: %s.\n"), 14107 strerror(errno)); 14108 14109 remove_tempfile(); 14110 14111 return (-1); 14112 } 14113 14114 if (write_edit_script(tempfile) == -1) { 14115 remove_tempfile(); 14116 return (-1); 14117 } 14118 14119 editor = getenv("EDITOR"); 14120 if (editor == NULL) 14121 editor = "vi"; 14122 14123 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 14124 buf = safe_malloc(bufsz); 14125 14126 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 14127 uu_die(gettext("Error creating editor command")); 14128 14129 if (system(buf) == -1) { 14130 semerr(gettext("Could not launch editor %s: %s\n"), editor, 14131 strerror(errno)); 14132 free(buf); 14133 remove_tempfile(); 14134 return (-1); 14135 } 14136 14137 free(buf); 14138 14139 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 14140 14141 remove_tempfile(); 14142 14143 return (0); 14144 } 14145 14146 static void 14147 add_string(uu_list_t *strlist, const char *str) 14148 { 14149 string_list_t *elem; 14150 elem = safe_malloc(sizeof (*elem)); 14151 uu_list_node_init(elem, &elem->node, string_pool); 14152 elem->str = safe_strdup(str); 14153 if (uu_list_append(strlist, elem) != 0) 14154 uu_die(gettext("libuutil error: %s\n"), 14155 uu_strerror(uu_error())); 14156 } 14157 14158 static int 14159 remove_string(uu_list_t *strlist, const char *str) 14160 { 14161 uu_list_walk_t *elems; 14162 string_list_t *sp; 14163 14164 /* 14165 * Find the element that needs to be removed. 14166 */ 14167 elems = uu_list_walk_start(strlist, UU_DEFAULT); 14168 while ((sp = uu_list_walk_next(elems)) != NULL) { 14169 if (strcmp(sp->str, str) == 0) 14170 break; 14171 } 14172 uu_list_walk_end(elems); 14173 14174 /* 14175 * Returning 1 here as the value was not found, this 14176 * might not be an error. Leave it to the caller to 14177 * decide. 14178 */ 14179 if (sp == NULL) { 14180 return (1); 14181 } 14182 14183 uu_list_remove(strlist, sp); 14184 14185 free(sp->str); 14186 free(sp); 14187 14188 return (0); 14189 } 14190 14191 /* 14192 * Get all property values that don't match the given glob pattern, 14193 * if a pattern is specified. 14194 */ 14195 static void 14196 get_prop_values(scf_property_t *prop, uu_list_t *values, 14197 const char *pattern) 14198 { 14199 scf_iter_t *iter; 14200 scf_value_t *val; 14201 int ret; 14202 14203 if ((iter = scf_iter_create(g_hndl)) == NULL || 14204 (val = scf_value_create(g_hndl)) == NULL) 14205 scfdie(); 14206 14207 if (scf_iter_property_values(iter, prop) != 0) 14208 scfdie(); 14209 14210 while ((ret = scf_iter_next_value(iter, val)) == 1) { 14211 char *buf; 14212 ssize_t vlen, szret; 14213 14214 vlen = scf_value_get_as_string(val, NULL, 0); 14215 if (vlen < 0) 14216 scfdie(); 14217 14218 buf = safe_malloc(vlen + 1); 14219 14220 szret = scf_value_get_as_string(val, buf, vlen + 1); 14221 if (szret < 0) 14222 scfdie(); 14223 assert(szret <= vlen); 14224 14225 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 14226 add_string(values, buf); 14227 14228 free(buf); 14229 } 14230 14231 if (ret == -1) 14232 scfdie(); 14233 14234 scf_value_destroy(val); 14235 scf_iter_destroy(iter); 14236 } 14237 14238 static int 14239 lscf_setpropvalue(const char *pgname, const char *type, 14240 const char *arg, int isadd, int isnotfoundok) 14241 { 14242 scf_type_t ty; 14243 scf_propertygroup_t *pg; 14244 scf_property_t *prop; 14245 int ret, result = 0; 14246 scf_transaction_t *tx; 14247 scf_transaction_entry_t *e; 14248 scf_value_t *v; 14249 string_list_t *sp; 14250 char *propname; 14251 uu_list_t *values; 14252 uu_list_walk_t *walk; 14253 void *cookie = NULL; 14254 char *pattern = NULL; 14255 14256 lscf_prep_hndl(); 14257 14258 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14259 uu_die(gettext("Could not create property list: %s\n"), 14260 uu_strerror(uu_error())); 14261 14262 if (!isadd) 14263 pattern = safe_strdup(arg); 14264 14265 if ((e = scf_entry_create(g_hndl)) == NULL || 14266 (pg = scf_pg_create(g_hndl)) == NULL || 14267 (prop = scf_property_create(g_hndl)) == NULL || 14268 (tx = scf_transaction_create(g_hndl)) == NULL) 14269 scfdie(); 14270 14271 if (cur_snap != NULL) { 14272 semerr(emsg_cant_modify_snapshots); 14273 goto fail; 14274 } 14275 14276 if (cur_inst == NULL && cur_svc == NULL) { 14277 semerr(emsg_entity_not_selected); 14278 goto fail; 14279 } 14280 14281 propname = strchr(pgname, '/'); 14282 if (propname == NULL) { 14283 semerr(gettext("Property names must contain a `/'.\n")); 14284 goto fail; 14285 } 14286 14287 *propname = '\0'; 14288 ++propname; 14289 14290 if (type != NULL) { 14291 ty = string_to_type(type); 14292 if (ty == SCF_TYPE_INVALID) { 14293 semerr(gettext("Unknown type \"%s\".\n"), type); 14294 goto fail; 14295 } 14296 } 14297 14298 if (cur_inst != NULL) 14299 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14300 else 14301 ret = scf_service_get_pg(cur_svc, pgname, pg); 14302 if (ret != 0) { 14303 switch (scf_error()) { 14304 case SCF_ERROR_NOT_FOUND: 14305 if (isnotfoundok) { 14306 result = 0; 14307 } else { 14308 semerr(emsg_no_such_pg, pgname); 14309 result = -1; 14310 } 14311 goto out; 14312 14313 case SCF_ERROR_INVALID_ARGUMENT: 14314 semerr(emsg_invalid_pg_name, pgname); 14315 goto fail; 14316 14317 default: 14318 scfdie(); 14319 } 14320 } 14321 14322 do { 14323 if (scf_pg_update(pg) == -1) 14324 scfdie(); 14325 if (scf_transaction_start(tx, pg) != 0) { 14326 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14327 scfdie(); 14328 14329 semerr(emsg_permission_denied); 14330 goto fail; 14331 } 14332 14333 ret = scf_pg_get_property(pg, propname, prop); 14334 if (ret == 0) { 14335 scf_type_t ptype; 14336 char *pat = pattern; 14337 14338 if (scf_property_type(prop, &ptype) != 0) 14339 scfdie(); 14340 14341 if (isadd) { 14342 if (type != NULL && ptype != ty) { 14343 semerr(gettext("Property \"%s\" is not " 14344 "of type \"%s\".\n"), propname, 14345 type); 14346 goto fail; 14347 } 14348 14349 pat = NULL; 14350 } else { 14351 size_t len = strlen(pat); 14352 if (len > 0 && pat[len - 1] == '\"') 14353 pat[len - 1] = '\0'; 14354 if (len > 0 && pat[0] == '\"') 14355 pat++; 14356 } 14357 14358 ty = ptype; 14359 14360 get_prop_values(prop, values, pat); 14361 14362 if (isadd) 14363 add_string(values, arg); 14364 14365 if (scf_transaction_property_change(tx, e, 14366 propname, ty) == -1) 14367 scfdie(); 14368 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14369 if (isadd) { 14370 if (type == NULL) { 14371 semerr(gettext("Type required " 14372 "for new properties.\n")); 14373 goto fail; 14374 } 14375 14376 add_string(values, arg); 14377 14378 if (scf_transaction_property_new(tx, e, 14379 propname, ty) == -1) 14380 scfdie(); 14381 } else if (isnotfoundok) { 14382 result = 0; 14383 goto out; 14384 } else { 14385 semerr(gettext("No such property %s/%s.\n"), 14386 pgname, propname); 14387 result = -1; 14388 goto out; 14389 } 14390 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14391 semerr(emsg_invalid_prop_name, propname); 14392 goto fail; 14393 } else { 14394 scfdie(); 14395 } 14396 14397 walk = uu_list_walk_start(values, UU_DEFAULT); 14398 if (walk == NULL) 14399 uu_die(gettext("Could not walk property list.\n")); 14400 14401 for (sp = uu_list_walk_next(walk); sp != NULL; 14402 sp = uu_list_walk_next(walk)) { 14403 v = string_to_value(sp->str, ty, 0); 14404 14405 if (v == NULL) { 14406 scf_entry_destroy_children(e); 14407 goto fail; 14408 } 14409 ret = scf_entry_add_value(e, v); 14410 assert(ret == 0); 14411 } 14412 uu_list_walk_end(walk); 14413 14414 result = scf_transaction_commit(tx); 14415 14416 scf_transaction_reset(tx); 14417 scf_entry_destroy_children(e); 14418 } while (result == 0); 14419 14420 if (result < 0) { 14421 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14422 scfdie(); 14423 14424 semerr(emsg_permission_denied); 14425 goto fail; 14426 } 14427 14428 result = 0; 14429 14430 private_refresh(); 14431 14432 out: 14433 scf_transaction_destroy(tx); 14434 scf_entry_destroy(e); 14435 scf_pg_destroy(pg); 14436 scf_property_destroy(prop); 14437 free(pattern); 14438 14439 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14440 free(sp->str); 14441 free(sp); 14442 } 14443 14444 uu_list_destroy(values); 14445 14446 return (result); 14447 14448 fail: 14449 result = -1; 14450 goto out; 14451 } 14452 14453 int 14454 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14455 { 14456 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14457 } 14458 14459 int 14460 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14461 { 14462 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14463 } 14464 14465 /* 14466 * Look for a standard start method, first in the instance (if any), 14467 * then the service. 14468 */ 14469 static const char * 14470 start_method_name(int *in_instance) 14471 { 14472 scf_propertygroup_t *pg; 14473 char **p; 14474 int ret; 14475 scf_instance_t *inst = cur_inst; 14476 14477 if ((pg = scf_pg_create(g_hndl)) == NULL) 14478 scfdie(); 14479 14480 again: 14481 for (p = start_method_names; *p != NULL; p++) { 14482 if (inst != NULL) 14483 ret = scf_instance_get_pg(inst, *p, pg); 14484 else 14485 ret = scf_service_get_pg(cur_svc, *p, pg); 14486 14487 if (ret == 0) { 14488 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14489 char *buf = safe_malloc(bufsz); 14490 14491 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14492 free(buf); 14493 continue; 14494 } 14495 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14496 free(buf); 14497 continue; 14498 } 14499 14500 free(buf); 14501 *in_instance = (inst != NULL); 14502 scf_pg_destroy(pg); 14503 return (*p); 14504 } 14505 14506 if (scf_error() == SCF_ERROR_NOT_FOUND) 14507 continue; 14508 14509 scfdie(); 14510 } 14511 14512 if (inst != NULL) { 14513 inst = NULL; 14514 goto again; 14515 } 14516 14517 scf_pg_destroy(pg); 14518 return (NULL); 14519 } 14520 14521 static int 14522 addpg(const char *name, const char *type) 14523 { 14524 scf_propertygroup_t *pg; 14525 int ret; 14526 14527 pg = scf_pg_create(g_hndl); 14528 if (pg == NULL) 14529 scfdie(); 14530 14531 if (cur_inst != NULL) 14532 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14533 else 14534 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14535 14536 if (ret != 0) { 14537 switch (scf_error()) { 14538 case SCF_ERROR_EXISTS: 14539 ret = 0; 14540 break; 14541 14542 case SCF_ERROR_PERMISSION_DENIED: 14543 semerr(emsg_permission_denied); 14544 break; 14545 14546 default: 14547 scfdie(); 14548 } 14549 } 14550 14551 scf_pg_destroy(pg); 14552 return (ret); 14553 } 14554 14555 int 14556 lscf_setenv(uu_list_t *args, int isunset) 14557 { 14558 int ret = 0; 14559 size_t i; 14560 int argc; 14561 char **argv = NULL; 14562 string_list_t *slp; 14563 char *pattern; 14564 char *prop; 14565 int do_service = 0; 14566 int do_instance = 0; 14567 const char *method = NULL; 14568 const char *name = NULL; 14569 const char *value = NULL; 14570 scf_instance_t *saved_cur_inst = cur_inst; 14571 14572 lscf_prep_hndl(); 14573 14574 argc = uu_list_numnodes(args); 14575 if (argc < 1) 14576 goto usage; 14577 14578 argv = calloc(argc + 1, sizeof (char *)); 14579 if (argv == NULL) 14580 uu_die(gettext("Out of memory.\n")); 14581 14582 for (slp = uu_list_first(args), i = 0; 14583 slp != NULL; 14584 slp = uu_list_next(args, slp), ++i) 14585 argv[i] = slp->str; 14586 14587 argv[i] = NULL; 14588 14589 opterr = 0; 14590 optind = 0; 14591 for (;;) { 14592 ret = getopt(argc, argv, "sim:"); 14593 if (ret == -1) 14594 break; 14595 14596 switch (ret) { 14597 case 's': 14598 do_service = 1; 14599 cur_inst = NULL; 14600 break; 14601 14602 case 'i': 14603 do_instance = 1; 14604 break; 14605 14606 case 'm': 14607 method = optarg; 14608 break; 14609 14610 case '?': 14611 goto usage; 14612 14613 default: 14614 bad_error("getopt", ret); 14615 } 14616 } 14617 14618 argc -= optind; 14619 if ((do_service && do_instance) || 14620 (isunset && argc != 1) || 14621 (!isunset && argc != 2)) 14622 goto usage; 14623 14624 name = argv[optind]; 14625 if (!isunset) 14626 value = argv[optind + 1]; 14627 14628 if (cur_snap != NULL) { 14629 semerr(emsg_cant_modify_snapshots); 14630 ret = -1; 14631 goto out; 14632 } 14633 14634 if (cur_inst == NULL && cur_svc == NULL) { 14635 semerr(emsg_entity_not_selected); 14636 ret = -1; 14637 goto out; 14638 } 14639 14640 if (do_instance && cur_inst == NULL) { 14641 semerr(gettext("No instance is selected.\n")); 14642 ret = -1; 14643 goto out; 14644 } 14645 14646 if (do_service && cur_svc == NULL) { 14647 semerr(gettext("No service is selected.\n")); 14648 ret = -1; 14649 goto out; 14650 } 14651 14652 if (method == NULL) { 14653 if (do_instance || do_service) { 14654 method = "method_context"; 14655 if (!isunset) { 14656 ret = addpg("method_context", 14657 SCF_GROUP_FRAMEWORK); 14658 if (ret != 0) 14659 goto out; 14660 } 14661 } else { 14662 int in_instance; 14663 method = start_method_name(&in_instance); 14664 if (method == NULL) { 14665 semerr(gettext( 14666 "Couldn't find start method; please " 14667 "specify a method with '-m'.\n")); 14668 ret = -1; 14669 goto out; 14670 } 14671 if (!in_instance) 14672 cur_inst = NULL; 14673 } 14674 } else { 14675 scf_propertygroup_t *pg; 14676 size_t bufsz; 14677 char *buf; 14678 int ret; 14679 14680 if ((pg = scf_pg_create(g_hndl)) == NULL) 14681 scfdie(); 14682 14683 if (cur_inst != NULL) 14684 ret = scf_instance_get_pg(cur_inst, method, pg); 14685 else 14686 ret = scf_service_get_pg(cur_svc, method, pg); 14687 14688 if (ret != 0) { 14689 scf_pg_destroy(pg); 14690 switch (scf_error()) { 14691 case SCF_ERROR_NOT_FOUND: 14692 semerr(gettext("Couldn't find the method " 14693 "\"%s\".\n"), method); 14694 goto out; 14695 14696 case SCF_ERROR_INVALID_ARGUMENT: 14697 semerr(gettext("Invalid method name \"%s\".\n"), 14698 method); 14699 goto out; 14700 14701 default: 14702 scfdie(); 14703 } 14704 } 14705 14706 bufsz = strlen(SCF_GROUP_METHOD) + 1; 14707 buf = safe_malloc(bufsz); 14708 14709 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 14710 strcmp(buf, SCF_GROUP_METHOD) != 0) { 14711 semerr(gettext("Property group \"%s\" is not of type " 14712 "\"method\".\n"), method); 14713 ret = -1; 14714 free(buf); 14715 scf_pg_destroy(pg); 14716 goto out; 14717 } 14718 14719 free(buf); 14720 scf_pg_destroy(pg); 14721 } 14722 14723 prop = uu_msprintf("%s/environment", method); 14724 pattern = uu_msprintf("%s=*", name); 14725 14726 if (prop == NULL || pattern == NULL) 14727 uu_die(gettext("Out of memory.\n")); 14728 14729 ret = lscf_delpropvalue(prop, pattern, !isunset); 14730 14731 if (ret == 0 && !isunset) { 14732 uu_free(pattern); 14733 uu_free(prop); 14734 prop = uu_msprintf("%s/environment", method); 14735 pattern = uu_msprintf("%s=%s", name, value); 14736 if (prop == NULL || pattern == NULL) 14737 uu_die(gettext("Out of memory.\n")); 14738 ret = lscf_addpropvalue(prop, "astring:", pattern); 14739 } 14740 uu_free(pattern); 14741 uu_free(prop); 14742 14743 out: 14744 cur_inst = saved_cur_inst; 14745 14746 free(argv); 14747 return (ret); 14748 usage: 14749 ret = -2; 14750 goto out; 14751 } 14752 14753 /* 14754 * Snapshot commands 14755 */ 14756 14757 void 14758 lscf_listsnap() 14759 { 14760 scf_snapshot_t *snap; 14761 scf_iter_t *iter; 14762 char *nb; 14763 int r; 14764 14765 lscf_prep_hndl(); 14766 14767 if (cur_inst == NULL) { 14768 semerr(gettext("Instance not selected.\n")); 14769 return; 14770 } 14771 14772 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 14773 (iter = scf_iter_create(g_hndl)) == NULL) 14774 scfdie(); 14775 14776 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 14777 scfdie(); 14778 14779 nb = safe_malloc(max_scf_name_len + 1); 14780 14781 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 14782 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 14783 scfdie(); 14784 14785 (void) puts(nb); 14786 } 14787 if (r < 0) 14788 scfdie(); 14789 14790 free(nb); 14791 scf_iter_destroy(iter); 14792 scf_snapshot_destroy(snap); 14793 } 14794 14795 void 14796 lscf_selectsnap(const char *name) 14797 { 14798 scf_snapshot_t *snap; 14799 scf_snaplevel_t *level; 14800 14801 lscf_prep_hndl(); 14802 14803 if (cur_inst == NULL) { 14804 semerr(gettext("Instance not selected.\n")); 14805 return; 14806 } 14807 14808 if (cur_snap != NULL) { 14809 if (name != NULL) { 14810 char *cur_snap_name; 14811 boolean_t nochange; 14812 14813 cur_snap_name = safe_malloc(max_scf_name_len + 1); 14814 14815 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 14816 max_scf_name_len + 1) < 0) 14817 scfdie(); 14818 14819 nochange = strcmp(name, cur_snap_name) == 0; 14820 14821 free(cur_snap_name); 14822 14823 if (nochange) 14824 return; 14825 } 14826 14827 unselect_cursnap(); 14828 } 14829 14830 if (name == NULL) 14831 return; 14832 14833 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 14834 (level = scf_snaplevel_create(g_hndl)) == NULL) 14835 scfdie(); 14836 14837 if (scf_instance_get_snapshot(cur_inst, name, snap) != 14838 SCF_SUCCESS) { 14839 switch (scf_error()) { 14840 case SCF_ERROR_INVALID_ARGUMENT: 14841 semerr(gettext("Invalid name \"%s\".\n"), name); 14842 break; 14843 14844 case SCF_ERROR_NOT_FOUND: 14845 semerr(gettext("No such snapshot \"%s\".\n"), name); 14846 break; 14847 14848 default: 14849 scfdie(); 14850 } 14851 14852 scf_snaplevel_destroy(level); 14853 scf_snapshot_destroy(snap); 14854 return; 14855 } 14856 14857 /* Load the snaplevels into our list. */ 14858 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 14859 if (cur_levels == NULL) 14860 uu_die(gettext("Could not create list: %s\n"), 14861 uu_strerror(uu_error())); 14862 14863 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 14864 if (scf_error() != SCF_ERROR_NOT_FOUND) 14865 scfdie(); 14866 14867 semerr(gettext("Snapshot has no snaplevels.\n")); 14868 14869 scf_snaplevel_destroy(level); 14870 scf_snapshot_destroy(snap); 14871 return; 14872 } 14873 14874 cur_snap = snap; 14875 14876 for (;;) { 14877 cur_elt = safe_malloc(sizeof (*cur_elt)); 14878 uu_list_node_init(cur_elt, &cur_elt->list_node, 14879 snaplevel_pool); 14880 cur_elt->sl = level; 14881 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 14882 uu_die(gettext("libuutil error: %s\n"), 14883 uu_strerror(uu_error())); 14884 14885 level = scf_snaplevel_create(g_hndl); 14886 if (level == NULL) 14887 scfdie(); 14888 14889 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 14890 level) != SCF_SUCCESS) { 14891 if (scf_error() != SCF_ERROR_NOT_FOUND) 14892 scfdie(); 14893 14894 scf_snaplevel_destroy(level); 14895 break; 14896 } 14897 } 14898 14899 cur_elt = uu_list_last(cur_levels); 14900 cur_level = cur_elt->sl; 14901 } 14902 14903 /* 14904 * Copies the properties & values in src to dst. Assumes src won't change. 14905 * Returns -1 if permission is denied, -2 if another transaction interrupts, 14906 * and 0 on success. 14907 * 14908 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 14909 * property, if it is copied and has type boolean. (See comment in 14910 * lscf_revert()). 14911 */ 14912 static int 14913 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 14914 uint8_t enabled) 14915 { 14916 scf_transaction_t *tx; 14917 scf_iter_t *iter, *viter; 14918 scf_property_t *prop; 14919 scf_value_t *v; 14920 char *nbuf; 14921 int r; 14922 14923 tx = scf_transaction_create(g_hndl); 14924 if (tx == NULL) 14925 scfdie(); 14926 14927 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 14928 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14929 scfdie(); 14930 14931 scf_transaction_destroy(tx); 14932 14933 return (-1); 14934 } 14935 14936 if ((iter = scf_iter_create(g_hndl)) == NULL || 14937 (prop = scf_property_create(g_hndl)) == NULL || 14938 (viter = scf_iter_create(g_hndl)) == NULL) 14939 scfdie(); 14940 14941 nbuf = safe_malloc(max_scf_name_len + 1); 14942 14943 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 14944 scfdie(); 14945 14946 for (;;) { 14947 scf_transaction_entry_t *e; 14948 scf_type_t ty; 14949 14950 r = scf_iter_next_property(iter, prop); 14951 if (r == -1) 14952 scfdie(); 14953 if (r == 0) 14954 break; 14955 14956 e = scf_entry_create(g_hndl); 14957 if (e == NULL) 14958 scfdie(); 14959 14960 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 14961 scfdie(); 14962 14963 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 14964 scfdie(); 14965 14966 if (scf_transaction_property_new(tx, e, nbuf, 14967 ty) != SCF_SUCCESS) 14968 scfdie(); 14969 14970 if ((enabled == 0 || enabled == 1) && 14971 strcmp(nbuf, scf_property_enabled) == 0 && 14972 ty == SCF_TYPE_BOOLEAN) { 14973 v = scf_value_create(g_hndl); 14974 if (v == NULL) 14975 scfdie(); 14976 14977 scf_value_set_boolean(v, enabled); 14978 14979 if (scf_entry_add_value(e, v) != 0) 14980 scfdie(); 14981 } else { 14982 if (scf_iter_property_values(viter, prop) != 0) 14983 scfdie(); 14984 14985 for (;;) { 14986 v = scf_value_create(g_hndl); 14987 if (v == NULL) 14988 scfdie(); 14989 14990 r = scf_iter_next_value(viter, v); 14991 if (r == -1) 14992 scfdie(); 14993 if (r == 0) { 14994 scf_value_destroy(v); 14995 break; 14996 } 14997 14998 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 14999 scfdie(); 15000 } 15001 } 15002 } 15003 15004 free(nbuf); 15005 scf_iter_destroy(viter); 15006 scf_property_destroy(prop); 15007 scf_iter_destroy(iter); 15008 15009 r = scf_transaction_commit(tx); 15010 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 15011 scfdie(); 15012 15013 scf_transaction_destroy_children(tx); 15014 scf_transaction_destroy(tx); 15015 15016 switch (r) { 15017 case 1: return (0); 15018 case 0: return (-2); 15019 case -1: return (-1); 15020 15021 default: 15022 abort(); 15023 } 15024 15025 /* NOTREACHED */ 15026 } 15027 15028 void 15029 lscf_revert(const char *snapname) 15030 { 15031 scf_snapshot_t *snap, *prev; 15032 scf_snaplevel_t *level, *nlevel; 15033 scf_iter_t *iter; 15034 scf_propertygroup_t *pg, *npg; 15035 scf_property_t *prop; 15036 scf_value_t *val; 15037 char *nbuf, *tbuf; 15038 uint8_t enabled; 15039 15040 lscf_prep_hndl(); 15041 15042 if (cur_inst == NULL) { 15043 semerr(gettext("Instance not selected.\n")); 15044 return; 15045 } 15046 15047 if (snapname != NULL) { 15048 snap = scf_snapshot_create(g_hndl); 15049 if (snap == NULL) 15050 scfdie(); 15051 15052 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 15053 SCF_SUCCESS) { 15054 switch (scf_error()) { 15055 case SCF_ERROR_INVALID_ARGUMENT: 15056 semerr(gettext("Invalid snapshot name " 15057 "\"%s\".\n"), snapname); 15058 break; 15059 15060 case SCF_ERROR_NOT_FOUND: 15061 semerr(gettext("No such snapshot.\n")); 15062 break; 15063 15064 default: 15065 scfdie(); 15066 } 15067 15068 scf_snapshot_destroy(snap); 15069 return; 15070 } 15071 } else { 15072 if (cur_snap != NULL) { 15073 snap = cur_snap; 15074 } else { 15075 semerr(gettext("No snapshot selected.\n")); 15076 return; 15077 } 15078 } 15079 15080 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 15081 (level = scf_snaplevel_create(g_hndl)) == NULL || 15082 (iter = scf_iter_create(g_hndl)) == NULL || 15083 (pg = scf_pg_create(g_hndl)) == NULL || 15084 (npg = scf_pg_create(g_hndl)) == NULL || 15085 (prop = scf_property_create(g_hndl)) == NULL || 15086 (val = scf_value_create(g_hndl)) == NULL) 15087 scfdie(); 15088 15089 nbuf = safe_malloc(max_scf_name_len + 1); 15090 tbuf = safe_malloc(max_scf_pg_type_len + 1); 15091 15092 /* Take the "previous" snapshot before we blow away the properties. */ 15093 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 15094 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 15095 scfdie(); 15096 } else { 15097 if (scf_error() != SCF_ERROR_NOT_FOUND) 15098 scfdie(); 15099 15100 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 15101 scfdie(); 15102 } 15103 15104 /* Save general/enabled, since we're probably going to replace it. */ 15105 enabled = 2; 15106 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 15107 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 15108 scf_property_get_value(prop, val) == 0) 15109 (void) scf_value_get_boolean(val, &enabled); 15110 15111 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 15112 if (scf_error() != SCF_ERROR_NOT_FOUND) 15113 scfdie(); 15114 15115 goto out; 15116 } 15117 15118 for (;;) { 15119 boolean_t isinst; 15120 uint32_t flags; 15121 int r; 15122 15123 /* Clear the properties from the corresponding entity. */ 15124 isinst = snaplevel_is_instance(level); 15125 15126 if (!isinst) 15127 r = scf_iter_service_pgs(iter, cur_svc); 15128 else 15129 r = scf_iter_instance_pgs(iter, cur_inst); 15130 if (r != SCF_SUCCESS) 15131 scfdie(); 15132 15133 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15134 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15135 scfdie(); 15136 15137 /* Skip nonpersistent pgs. */ 15138 if (flags & SCF_PG_FLAG_NONPERSISTENT) 15139 continue; 15140 15141 if (scf_pg_delete(pg) != SCF_SUCCESS) { 15142 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15143 scfdie(); 15144 15145 semerr(emsg_permission_denied); 15146 goto out; 15147 } 15148 } 15149 if (r == -1) 15150 scfdie(); 15151 15152 /* Copy the properties to the corresponding entity. */ 15153 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 15154 scfdie(); 15155 15156 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 15157 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 15158 scfdie(); 15159 15160 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 15161 0) 15162 scfdie(); 15163 15164 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 15165 scfdie(); 15166 15167 if (!isinst) 15168 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 15169 flags, npg); 15170 else 15171 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 15172 flags, npg); 15173 if (r != SCF_SUCCESS) { 15174 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 15175 scfdie(); 15176 15177 semerr(emsg_permission_denied); 15178 goto out; 15179 } 15180 15181 if ((enabled == 0 || enabled == 1) && 15182 strcmp(nbuf, scf_pg_general) == 0) 15183 r = pg_copy(pg, npg, enabled); 15184 else 15185 r = pg_copy(pg, npg, 2); 15186 15187 switch (r) { 15188 case 0: 15189 break; 15190 15191 case -1: 15192 semerr(emsg_permission_denied); 15193 goto out; 15194 15195 case -2: 15196 semerr(gettext( 15197 "Interrupted by another change.\n")); 15198 goto out; 15199 15200 default: 15201 abort(); 15202 } 15203 } 15204 if (r == -1) 15205 scfdie(); 15206 15207 /* Get next level. */ 15208 nlevel = scf_snaplevel_create(g_hndl); 15209 if (nlevel == NULL) 15210 scfdie(); 15211 15212 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 15213 SCF_SUCCESS) { 15214 if (scf_error() != SCF_ERROR_NOT_FOUND) 15215 scfdie(); 15216 15217 scf_snaplevel_destroy(nlevel); 15218 break; 15219 } 15220 15221 scf_snaplevel_destroy(level); 15222 level = nlevel; 15223 } 15224 15225 if (snapname == NULL) { 15226 lscf_selectsnap(NULL); 15227 snap = NULL; /* cur_snap has been destroyed */ 15228 } 15229 15230 out: 15231 free(tbuf); 15232 free(nbuf); 15233 scf_value_destroy(val); 15234 scf_property_destroy(prop); 15235 scf_pg_destroy(npg); 15236 scf_pg_destroy(pg); 15237 scf_iter_destroy(iter); 15238 scf_snaplevel_destroy(level); 15239 scf_snapshot_destroy(prev); 15240 if (snap != cur_snap) 15241 scf_snapshot_destroy(snap); 15242 } 15243 15244 void 15245 lscf_refresh(void) 15246 { 15247 ssize_t fmrilen; 15248 size_t bufsz; 15249 char *fmribuf; 15250 int r; 15251 15252 lscf_prep_hndl(); 15253 15254 if (cur_inst == NULL) { 15255 semerr(gettext("Instance not selected.\n")); 15256 return; 15257 } 15258 15259 bufsz = max_scf_fmri_len + 1; 15260 fmribuf = safe_malloc(bufsz); 15261 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15262 if (fmrilen < 0) { 15263 free(fmribuf); 15264 if (scf_error() != SCF_ERROR_DELETED) 15265 scfdie(); 15266 scf_instance_destroy(cur_inst); 15267 cur_inst = NULL; 15268 warn(emsg_deleted); 15269 return; 15270 } 15271 assert(fmrilen < bufsz); 15272 15273 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15274 switch (r) { 15275 case 0: 15276 break; 15277 15278 case ECONNABORTED: 15279 warn(gettext("Could not refresh %s " 15280 "(repository connection broken).\n"), fmribuf); 15281 break; 15282 15283 case ECANCELED: 15284 warn(emsg_deleted); 15285 break; 15286 15287 case EPERM: 15288 warn(gettext("Could not refresh %s " 15289 "(permission denied).\n"), fmribuf); 15290 break; 15291 15292 case ENOSPC: 15293 warn(gettext("Could not refresh %s " 15294 "(repository server out of resources).\n"), 15295 fmribuf); 15296 break; 15297 15298 case EACCES: 15299 default: 15300 bad_error("refresh_entity", scf_error()); 15301 } 15302 15303 free(fmribuf); 15304 } 15305 15306 /* 15307 * describe [-v] [-t] [pg/prop] 15308 */ 15309 int 15310 lscf_describe(uu_list_t *args, int hasargs) 15311 { 15312 int ret = 0; 15313 size_t i; 15314 int argc; 15315 char **argv = NULL; 15316 string_list_t *slp; 15317 int do_verbose = 0; 15318 int do_templates = 0; 15319 char *pattern = NULL; 15320 15321 lscf_prep_hndl(); 15322 15323 if (hasargs != 0) { 15324 argc = uu_list_numnodes(args); 15325 if (argc < 1) 15326 goto usage; 15327 15328 argv = calloc(argc + 1, sizeof (char *)); 15329 if (argv == NULL) 15330 uu_die(gettext("Out of memory.\n")); 15331 15332 for (slp = uu_list_first(args), i = 0; 15333 slp != NULL; 15334 slp = uu_list_next(args, slp), ++i) 15335 argv[i] = slp->str; 15336 15337 argv[i] = NULL; 15338 15339 /* 15340 * We start optind = 0 because our list of arguments 15341 * starts at argv[0] 15342 */ 15343 optind = 0; 15344 opterr = 0; 15345 for (;;) { 15346 ret = getopt(argc, argv, "vt"); 15347 if (ret == -1) 15348 break; 15349 15350 switch (ret) { 15351 case 'v': 15352 do_verbose = 1; 15353 break; 15354 15355 case 't': 15356 do_templates = 1; 15357 break; 15358 15359 case '?': 15360 goto usage; 15361 15362 default: 15363 bad_error("getopt", ret); 15364 } 15365 } 15366 15367 pattern = argv[optind]; 15368 } 15369 15370 if (cur_inst == NULL && cur_svc == NULL) { 15371 semerr(emsg_entity_not_selected); 15372 ret = -1; 15373 goto out; 15374 } 15375 15376 /* 15377 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15378 * output if their last parameter is set to 2. Less information is 15379 * produced if the parameter is set to 1. 15380 */ 15381 if (pattern == NULL) { 15382 if (do_verbose == 1) 15383 list_entity_tmpl(2); 15384 else 15385 list_entity_tmpl(1); 15386 } 15387 15388 if (do_templates == 0) { 15389 if (do_verbose == 1) 15390 listprop(pattern, 0, 2); 15391 else 15392 listprop(pattern, 0, 1); 15393 } else { 15394 if (do_verbose == 1) 15395 listtmpl(pattern, 2); 15396 else 15397 listtmpl(pattern, 1); 15398 } 15399 15400 ret = 0; 15401 out: 15402 if (argv != NULL) 15403 free(argv); 15404 return (ret); 15405 usage: 15406 ret = -2; 15407 goto out; 15408 } 15409 15410 #define PARAM_ACTIVE ((const char *) "active") 15411 #define PARAM_INACTIVE ((const char *) "inactive") 15412 #define PARAM_SMTP_TO ((const char *) "to") 15413 15414 /* 15415 * tokenize() 15416 * Breaks down the string according to the tokens passed. 15417 * Caller is responsible for freeing array of pointers returned. 15418 * Returns NULL on failure 15419 */ 15420 char ** 15421 tokenize(char *str, const char *sep) 15422 { 15423 char *token, *lasts; 15424 char **buf; 15425 int n = 0; /* number of elements */ 15426 int size = 8; /* size of the array (initial) */ 15427 15428 buf = safe_malloc(size * sizeof (char *)); 15429 15430 for (token = strtok_r(str, sep, &lasts); token != NULL; 15431 token = strtok_r(NULL, sep, &lasts), ++n) { 15432 if (n + 1 >= size) { 15433 size *= 2; 15434 if ((buf = realloc(buf, size * sizeof (char *))) == 15435 NULL) { 15436 uu_die(gettext("Out of memory")); 15437 } 15438 } 15439 buf[n] = token; 15440 } 15441 /* NULL terminate the pointer array */ 15442 buf[n] = NULL; 15443 15444 return (buf); 15445 } 15446 15447 int32_t 15448 check_tokens(char **p) 15449 { 15450 int32_t smf = 0; 15451 int32_t fma = 0; 15452 15453 while (*p) { 15454 int32_t t = string_to_tset(*p); 15455 15456 if (t == 0) { 15457 if (is_fma_token(*p) == 0) 15458 return (INVALID_TOKENS); 15459 fma = 1; /* this token is an fma event */ 15460 } else { 15461 smf |= t; 15462 } 15463 15464 if (smf != 0 && fma == 1) 15465 return (MIXED_TOKENS); 15466 ++p; 15467 } 15468 15469 if (smf > 0) 15470 return (smf); 15471 else if (fma == 1) 15472 return (FMA_TOKENS); 15473 15474 return (INVALID_TOKENS); 15475 } 15476 15477 static int 15478 get_selection_str(char *fmri, size_t sz) 15479 { 15480 if (g_hndl == NULL) { 15481 semerr(emsg_entity_not_selected); 15482 return (-1); 15483 } else if (cur_level != NULL) { 15484 semerr(emsg_invalid_for_snapshot); 15485 return (-1); 15486 } else { 15487 lscf_get_selection_str(fmri, sz); 15488 } 15489 15490 return (0); 15491 } 15492 15493 void 15494 lscf_delnotify(const char *set, int global) 15495 { 15496 char *str = strdup(set); 15497 char **pgs; 15498 char **p; 15499 int32_t tset; 15500 char *fmri = NULL; 15501 15502 if (str == NULL) 15503 uu_die(gettext("Out of memory.\n")); 15504 15505 pgs = tokenize(str, ","); 15506 15507 if ((tset = check_tokens(pgs)) > 0) { 15508 size_t sz = max_scf_fmri_len + 1; 15509 15510 fmri = safe_malloc(sz); 15511 if (global) { 15512 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15513 } else if (get_selection_str(fmri, sz) != 0) { 15514 goto out; 15515 } 15516 15517 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri, 15518 tset) != SCF_SUCCESS) { 15519 uu_warn(gettext("Failed smf_notify_del_params: %s\n"), 15520 scf_strerror(scf_error())); 15521 } 15522 } else if (tset == FMA_TOKENS) { 15523 if (global) { 15524 semerr(gettext("Can't use option '-g' with FMA event " 15525 "definitions\n")); 15526 goto out; 15527 } 15528 15529 for (p = pgs; *p; ++p) { 15530 if (smf_notify_del_params(de_tag(*p), NULL, 0) != 15531 SCF_SUCCESS) { 15532 uu_warn(gettext("Failed for \"%s\": %s\n"), *p, 15533 scf_strerror(scf_error())); 15534 goto out; 15535 } 15536 } 15537 } else if (tset == MIXED_TOKENS) { 15538 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15539 goto out; 15540 } else { 15541 uu_die(gettext("Invalid input.\n")); 15542 } 15543 15544 out: 15545 free(fmri); 15546 free(pgs); 15547 free(str); 15548 } 15549 15550 void 15551 lscf_listnotify(const char *set, int global) 15552 { 15553 char *str = safe_strdup(set); 15554 char **pgs; 15555 char **p; 15556 int32_t tset; 15557 nvlist_t *nvl; 15558 char *fmri = NULL; 15559 15560 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 15561 uu_die(gettext("Out of memory.\n")); 15562 15563 pgs = tokenize(str, ","); 15564 15565 if ((tset = check_tokens(pgs)) > 0) { 15566 size_t sz = max_scf_fmri_len + 1; 15567 15568 fmri = safe_malloc(sz); 15569 if (global) { 15570 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15571 } else if (get_selection_str(fmri, sz) != 0) { 15572 goto out; 15573 } 15574 15575 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) != 15576 SCF_SUCCESS) { 15577 if (scf_error() != SCF_ERROR_NOT_FOUND && 15578 scf_error() != SCF_ERROR_DELETED) 15579 uu_warn(gettext( 15580 "Failed listnotify: %s\n"), 15581 scf_strerror(scf_error())); 15582 goto out; 15583 } 15584 15585 listnotify_print(nvl, NULL); 15586 } else if (tset == FMA_TOKENS) { 15587 if (global) { 15588 semerr(gettext("Can't use option '-g' with FMA event " 15589 "definitions\n")); 15590 goto out; 15591 } 15592 15593 for (p = pgs; *p; ++p) { 15594 if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) != 15595 SCF_SUCCESS) { 15596 /* 15597 * if the preferences have just been deleted 15598 * or does not exist, just skip. 15599 */ 15600 if (scf_error() == SCF_ERROR_NOT_FOUND || 15601 scf_error() == SCF_ERROR_DELETED) 15602 continue; 15603 uu_warn(gettext( 15604 "Failed listnotify: %s\n"), 15605 scf_strerror(scf_error())); 15606 goto out; 15607 } 15608 listnotify_print(nvl, re_tag(*p)); 15609 } 15610 } else if (tset == MIXED_TOKENS) { 15611 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15612 goto out; 15613 } else { 15614 semerr(gettext("Invalid input.\n")); 15615 } 15616 15617 out: 15618 nvlist_free(nvl); 15619 free(fmri); 15620 free(pgs); 15621 free(str); 15622 } 15623 15624 static char * 15625 strip_quotes_and_blanks(char *s) 15626 { 15627 char *start = s; 15628 char *end = strrchr(s, '\"'); 15629 15630 if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') { 15631 start = s + 1; 15632 while (isblank(*start)) 15633 start++; 15634 while (isblank(*(end - 1)) && end > start) { 15635 end--; 15636 } 15637 *end = '\0'; 15638 } 15639 15640 return (start); 15641 } 15642 15643 static int 15644 set_active(nvlist_t *mech, const char *hier_part) 15645 { 15646 boolean_t b; 15647 15648 if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) { 15649 b = B_TRUE; 15650 } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) { 15651 b = B_FALSE; 15652 } else { 15653 return (-1); 15654 } 15655 15656 if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0) 15657 uu_die(gettext("Out of memory.\n")); 15658 15659 return (0); 15660 } 15661 15662 static int 15663 add_snmp_params(nvlist_t *mech, char *hier_part) 15664 { 15665 return (set_active(mech, hier_part)); 15666 } 15667 15668 static int 15669 add_syslog_params(nvlist_t *mech, char *hier_part) 15670 { 15671 return (set_active(mech, hier_part)); 15672 } 15673 15674 /* 15675 * add_mailto_paramas() 15676 * parse the hier_part of mailto URI 15677 * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]] 15678 * or mailto:{[active]|inactive} 15679 */ 15680 static int 15681 add_mailto_params(nvlist_t *mech, char *hier_part) 15682 { 15683 const char *tok = "?&"; 15684 char *p; 15685 char *lasts; 15686 char *param; 15687 char *val; 15688 15689 /* 15690 * If the notification parametes are in the form of 15691 * 15692 * malito:{[active]|inactive} 15693 * 15694 * we set the property accordingly and return. 15695 * Otherwise, we make the notification type active and 15696 * process the hier_part. 15697 */ 15698 if (set_active(mech, hier_part) == 0) 15699 return (0); 15700 else if (set_active(mech, PARAM_ACTIVE) != 0) 15701 return (-1); 15702 15703 if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) { 15704 /* 15705 * sanity check: we only get here if hier_part = "", but 15706 * that's handled by set_active 15707 */ 15708 uu_die("strtok_r"); 15709 } 15710 15711 if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0) 15712 uu_die(gettext("Out of memory.\n")); 15713 15714 while ((p = strtok_r(NULL, tok, &lasts)) != NULL) 15715 if ((param = strtok_r(p, "=", &val)) != NULL) 15716 if (nvlist_add_string(mech, param, val) != 0) 15717 uu_die(gettext("Out of memory.\n")); 15718 15719 return (0); 15720 } 15721 15722 static int 15723 uri_split(char *uri, char **scheme, char **hier_part) 15724 { 15725 int r = -1; 15726 15727 if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL || 15728 *hier_part == NULL) { 15729 semerr(gettext("'%s' is not an URI\n"), uri); 15730 return (r); 15731 } 15732 15733 if ((r = check_uri_scheme(*scheme)) < 0) { 15734 semerr(gettext("Unkown URI scheme: %s\n"), *scheme); 15735 return (r); 15736 } 15737 15738 return (r); 15739 } 15740 15741 static int 15742 process_uri(nvlist_t *params, char *uri) 15743 { 15744 char *scheme; 15745 char *hier_part; 15746 nvlist_t *mech; 15747 int index; 15748 int r; 15749 15750 if ((index = uri_split(uri, &scheme, &hier_part)) < 0) 15751 return (-1); 15752 15753 if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0) 15754 uu_die(gettext("Out of memory.\n")); 15755 15756 switch (index) { 15757 case 0: 15758 /* error messages displayed by called function */ 15759 r = add_mailto_params(mech, hier_part); 15760 break; 15761 15762 case 1: 15763 if ((r = add_snmp_params(mech, hier_part)) != 0) 15764 semerr(gettext("Not valid parameters: '%s'\n"), 15765 hier_part); 15766 break; 15767 15768 case 2: 15769 if ((r = add_syslog_params(mech, hier_part)) != 0) 15770 semerr(gettext("Not valid parameters: '%s'\n"), 15771 hier_part); 15772 break; 15773 15774 default: 15775 r = -1; 15776 } 15777 15778 if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol, 15779 mech) != 0) 15780 uu_die(gettext("Out of memory.\n")); 15781 15782 nvlist_free(mech); 15783 return (r); 15784 } 15785 15786 static int 15787 set_params(nvlist_t *params, char **p) 15788 { 15789 char *uri; 15790 15791 if (p == NULL) 15792 /* sanity check */ 15793 uu_die("set_params"); 15794 15795 while (*p) { 15796 uri = strip_quotes_and_blanks(*p); 15797 if (process_uri(params, uri) != 0) 15798 return (-1); 15799 15800 ++p; 15801 } 15802 15803 return (0); 15804 } 15805 15806 static int 15807 setnotify(const char *e, char **p, int global) 15808 { 15809 char *str = safe_strdup(e); 15810 char **events; 15811 int32_t tset; 15812 int r = -1; 15813 nvlist_t *nvl, *params; 15814 char *fmri = NULL; 15815 15816 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || 15817 nvlist_alloc(¶ms, NV_UNIQUE_NAME, 0) != 0 || 15818 nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION, 15819 SCF_NOTIFY_PARAMS_VERSION) != 0) 15820 uu_die(gettext("Out of memory.\n")); 15821 15822 events = tokenize(str, ","); 15823 15824 if ((tset = check_tokens(events)) > 0) { 15825 /* SMF state transitions parameters */ 15826 size_t sz = max_scf_fmri_len + 1; 15827 15828 fmri = safe_malloc(sz); 15829 if (global) { 15830 (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz); 15831 } else if (get_selection_str(fmri, sz) != 0) { 15832 goto out; 15833 } 15834 15835 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 || 15836 nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0) 15837 uu_die(gettext("Out of memory.\n")); 15838 15839 if ((r = set_params(params, p)) == 0) { 15840 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, 15841 params) != 0) 15842 uu_die(gettext("Out of memory.\n")); 15843 15844 if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS, 15845 nvl) != SCF_SUCCESS) { 15846 r = -1; 15847 uu_warn(gettext( 15848 "Failed smf_notify_set_params(3SCF): %s\n"), 15849 scf_strerror(scf_error())); 15850 } 15851 } 15852 } else if (tset == FMA_TOKENS) { 15853 /* FMA event parameters */ 15854 if (global) { 15855 semerr(gettext("Can't use option '-g' with FMA event " 15856 "definitions\n")); 15857 goto out; 15858 } 15859 15860 if ((r = set_params(params, p)) != 0) 15861 goto out; 15862 15863 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0) 15864 uu_die(gettext("Out of memory.\n")); 15865 15866 while (*events) { 15867 if (smf_notify_set_params(de_tag(*events), nvl) != 15868 SCF_SUCCESS) 15869 uu_warn(gettext( 15870 "Failed smf_notify_set_params(3SCF) for " 15871 "event %s: %s\n"), *events, 15872 scf_strerror(scf_error())); 15873 events++; 15874 } 15875 } else if (tset == MIXED_TOKENS) { 15876 semerr(gettext("Can't mix SMF and FMA event definitions\n")); 15877 } else { 15878 /* Sanity check */ 15879 uu_die(gettext("Invalid input.\n")); 15880 } 15881 15882 out: 15883 nvlist_free(nvl); 15884 nvlist_free(params); 15885 free(fmri); 15886 free(str); 15887 15888 return (r); 15889 } 15890 15891 int 15892 lscf_setnotify(uu_list_t *args) 15893 { 15894 int argc; 15895 char **argv = NULL; 15896 string_list_t *slp; 15897 int global; 15898 char *events; 15899 char **p; 15900 int i; 15901 int ret; 15902 15903 if ((argc = uu_list_numnodes(args)) < 2) 15904 goto usage; 15905 15906 argv = calloc(argc + 1, sizeof (char *)); 15907 if (argv == NULL) 15908 uu_die(gettext("Out of memory.\n")); 15909 15910 for (slp = uu_list_first(args), i = 0; 15911 slp != NULL; 15912 slp = uu_list_next(args, slp), ++i) 15913 argv[i] = slp->str; 15914 15915 argv[i] = NULL; 15916 15917 if (strcmp(argv[0], "-g") == 0) { 15918 global = 1; 15919 events = argv[1]; 15920 p = argv + 2; 15921 } else { 15922 global = 0; 15923 events = argv[0]; 15924 p = argv + 1; 15925 } 15926 15927 ret = setnotify(events, p, global); 15928 15929 out: 15930 free(argv); 15931 return (ret); 15932 15933 usage: 15934 ret = -2; 15935 goto out; 15936 } 15937 15938 /* 15939 * Creates a list of instance name strings associated with a service. If 15940 * wohandcrafted flag is set, get only instances that have a last-import 15941 * snapshot, instances that were imported via svccfg. 15942 */ 15943 static uu_list_t * 15944 create_instance_list(scf_service_t *svc, int wohandcrafted) 15945 { 15946 scf_snapshot_t *snap = NULL; 15947 scf_instance_t *inst; 15948 scf_iter_t *inst_iter; 15949 uu_list_t *instances; 15950 char *instname; 15951 int r; 15952 15953 inst_iter = scf_iter_create(g_hndl); 15954 inst = scf_instance_create(g_hndl); 15955 if (inst_iter == NULL || inst == NULL) { 15956 uu_warn(gettext("Could not create instance or iterator\n")); 15957 scfdie(); 15958 } 15959 15960 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 15961 return (instances); 15962 15963 if (scf_iter_service_instances(inst_iter, svc) != 0) { 15964 switch (scf_error()) { 15965 case SCF_ERROR_CONNECTION_BROKEN: 15966 case SCF_ERROR_DELETED: 15967 uu_list_destroy(instances); 15968 instances = NULL; 15969 goto out; 15970 15971 case SCF_ERROR_HANDLE_MISMATCH: 15972 case SCF_ERROR_NOT_BOUND: 15973 case SCF_ERROR_NOT_SET: 15974 default: 15975 bad_error("scf_iter_service_instances", scf_error()); 15976 } 15977 } 15978 15979 instname = safe_malloc(max_scf_name_len + 1); 15980 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 15981 if (r == -1) { 15982 (void) uu_warn(gettext("Unable to iterate through " 15983 "instances to create instance list : %s\n"), 15984 scf_strerror(scf_error())); 15985 15986 uu_list_destroy(instances); 15987 instances = NULL; 15988 goto out; 15989 } 15990 15991 /* 15992 * If the instance does not have a last-import snapshot 15993 * then do not add it to the list as it is a hand-crafted 15994 * instance that should not be managed. 15995 */ 15996 if (wohandcrafted) { 15997 if (snap == NULL && 15998 (snap = scf_snapshot_create(g_hndl)) == NULL) { 15999 uu_warn(gettext("Unable to create snapshot " 16000 "entity\n")); 16001 scfdie(); 16002 } 16003 16004 if (scf_instance_get_snapshot(inst, 16005 snap_lastimport, snap) != 0) { 16006 switch (scf_error()) { 16007 case SCF_ERROR_NOT_FOUND : 16008 case SCF_ERROR_DELETED: 16009 continue; 16010 16011 case SCF_ERROR_CONNECTION_BROKEN: 16012 uu_list_destroy(instances); 16013 instances = NULL; 16014 goto out; 16015 16016 case SCF_ERROR_HANDLE_MISMATCH: 16017 case SCF_ERROR_NOT_BOUND: 16018 case SCF_ERROR_NOT_SET: 16019 default: 16020 bad_error("scf_iter_service_instances", 16021 scf_error()); 16022 } 16023 } 16024 } 16025 16026 if (scf_instance_get_name(inst, instname, 16027 max_scf_name_len + 1) < 0) { 16028 switch (scf_error()) { 16029 case SCF_ERROR_NOT_FOUND : 16030 continue; 16031 16032 case SCF_ERROR_CONNECTION_BROKEN: 16033 case SCF_ERROR_DELETED: 16034 uu_list_destroy(instances); 16035 instances = NULL; 16036 goto out; 16037 16038 case SCF_ERROR_HANDLE_MISMATCH: 16039 case SCF_ERROR_NOT_BOUND: 16040 case SCF_ERROR_NOT_SET: 16041 default: 16042 bad_error("scf_iter_service_instances", 16043 scf_error()); 16044 } 16045 } 16046 16047 add_string(instances, instname); 16048 } 16049 16050 out: 16051 if (snap) 16052 scf_snapshot_destroy(snap); 16053 16054 scf_instance_destroy(inst); 16055 scf_iter_destroy(inst_iter); 16056 free(instname); 16057 return (instances); 16058 } 16059 16060 /* 16061 * disable an instance but wait for the instance to 16062 * move out of the running state. 16063 * 16064 * Returns 0 : if the instance did not disable 16065 * Returns non-zero : if the instance disabled. 16066 * 16067 */ 16068 static int 16069 disable_instance(scf_instance_t *instance) 16070 { 16071 char *fmribuf; 16072 int enabled = 10000; 16073 16074 if (inst_is_running(instance)) { 16075 fmribuf = safe_malloc(max_scf_name_len + 1); 16076 if (scf_instance_to_fmri(instance, fmribuf, 16077 max_scf_name_len + 1) < 0) { 16078 free(fmribuf); 16079 return (0); 16080 } 16081 16082 /* 16083 * If the instance cannot be disabled then return 16084 * failure to disable and let the caller decide 16085 * if that is of importance. 16086 */ 16087 if (smf_disable_instance(fmribuf, 0) != 0) { 16088 free(fmribuf); 16089 return (0); 16090 } 16091 16092 while (enabled) { 16093 if (!inst_is_running(instance)) 16094 break; 16095 16096 (void) poll(NULL, 0, 5); 16097 enabled = enabled - 5; 16098 } 16099 16100 free(fmribuf); 16101 } 16102 16103 return (enabled); 16104 } 16105 16106 /* 16107 * Function to compare two service_manifest structures. 16108 */ 16109 /* ARGSUSED2 */ 16110 static int 16111 service_manifest_compare(const void *left, const void *right, void *unused) 16112 { 16113 service_manifest_t *l = (service_manifest_t *)left; 16114 service_manifest_t *r = (service_manifest_t *)right; 16115 int rc; 16116 16117 rc = strcmp(l->servicename, r->servicename); 16118 16119 return (rc); 16120 } 16121 16122 /* 16123 * Look for the provided service in the service to manifest 16124 * tree. If the service exists, and a manifest was provided 16125 * then add the manifest to that service. If the service 16126 * does not exist, then add the service and manifest to the 16127 * list. 16128 * 16129 * If the manifest is NULL, return the element if found. If 16130 * the service is not found return NULL. 16131 */ 16132 service_manifest_t * 16133 find_add_svc_mfst(const char *svnbuf, const char *mfst) 16134 { 16135 service_manifest_t elem; 16136 service_manifest_t *fnelem; 16137 uu_avl_index_t marker; 16138 16139 elem.servicename = svnbuf; 16140 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 16141 16142 if (mfst) { 16143 if (fnelem) { 16144 add_string(fnelem->mfstlist, strdup(mfst)); 16145 } else { 16146 fnelem = safe_malloc(sizeof (*fnelem)); 16147 fnelem->servicename = safe_strdup(svnbuf); 16148 if ((fnelem->mfstlist = 16149 uu_list_create(string_pool, NULL, 0)) == NULL) 16150 uu_die(gettext("Could not create property " 16151 "list: %s\n"), uu_strerror(uu_error())); 16152 16153 add_string(fnelem->mfstlist, safe_strdup(mfst)); 16154 16155 uu_avl_insert(service_manifest_tree, fnelem, marker); 16156 } 16157 } 16158 16159 return (fnelem); 16160 } 16161 16162 /* 16163 * Create the service to manifest avl tree. 16164 * 16165 * Walk each of the manifests currently installed in the supported 16166 * directories, /lib/svc/manifests and /var/svc/manifests. For 16167 * each of the manifests, inventory the services and add them to 16168 * the tree. 16169 * 16170 * Code that calls this function should make sure fileystem/minimal is online, 16171 * /var is available, since this function walks the /var/svc/manifest directory. 16172 */ 16173 static void 16174 create_manifest_tree(void) 16175 { 16176 manifest_info_t **entry; 16177 manifest_info_t **manifests; 16178 uu_list_walk_t *svcs; 16179 bundle_t *b; 16180 entity_t *mfsvc; 16181 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 16182 int c, status; 16183 16184 if (service_manifest_pool) 16185 return; 16186 16187 /* 16188 * Create the list pool for the service manifest list 16189 */ 16190 service_manifest_pool = uu_avl_pool_create("service_manifest", 16191 sizeof (service_manifest_t), 16192 offsetof(service_manifest_t, svcmfst_node), 16193 service_manifest_compare, UU_DEFAULT); 16194 if (service_manifest_pool == NULL) 16195 uu_die(gettext("service_manifest pool creation failed: %s\n"), 16196 uu_strerror(uu_error())); 16197 16198 /* 16199 * Create the list 16200 */ 16201 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 16202 UU_DEFAULT); 16203 if (service_manifest_tree == NULL) 16204 uu_die(gettext("service_manifest tree creation failed: %s\n"), 16205 uu_strerror(uu_error())); 16206 16207 /* 16208 * Walk the manifests adding the service(s) from each manifest. 16209 * 16210 * If a service already exists add the manifest to the manifest 16211 * list for that service. This covers the case of a service that 16212 * is supported by multiple manifest files. 16213 */ 16214 for (c = 0; dirs[c]; c++) { 16215 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT); 16216 if (status < 0) { 16217 uu_warn(gettext("file tree walk of %s encountered " 16218 "error %s\n"), dirs[c], strerror(errno)); 16219 16220 uu_avl_destroy(service_manifest_tree); 16221 service_manifest_tree = NULL; 16222 return; 16223 } 16224 16225 /* 16226 * If a manifest that was in the list is not found 16227 * then skip and go to the next manifest file. 16228 */ 16229 if (manifests != NULL) { 16230 for (entry = manifests; *entry != NULL; entry++) { 16231 b = internal_bundle_new(); 16232 if (lxml_get_bundle_file(b, (*entry)->mi_path, 16233 SVCCFG_OP_IMPORT) != 0) { 16234 internal_bundle_free(b); 16235 continue; 16236 } 16237 16238 svcs = uu_list_walk_start(b->sc_bundle_services, 16239 0); 16240 if (svcs == NULL) { 16241 internal_bundle_free(b); 16242 continue; 16243 } 16244 16245 while ((mfsvc = uu_list_walk_next(svcs)) != 16246 NULL) { 16247 /* Add manifest to service */ 16248 (void) find_add_svc_mfst(mfsvc->sc_name, 16249 (*entry)->mi_path); 16250 } 16251 16252 uu_list_walk_end(svcs); 16253 internal_bundle_free(b); 16254 } 16255 16256 free_manifest_array(manifests); 16257 } 16258 } 16259 } 16260 16261 /* 16262 * Check the manifest history file to see 16263 * if the service was ever installed from 16264 * one of the supported directories. 16265 * 16266 * Return Values : 16267 * -1 - if there's error reading manifest history file 16268 * 1 - if the service is not found 16269 * 0 - if the service is found 16270 */ 16271 static int 16272 check_mfst_history(const char *svcname) 16273 { 16274 struct stat st; 16275 caddr_t mfsthist_start; 16276 char *svnbuf; 16277 int fd; 16278 int r = 1; 16279 16280 fd = open(MFSTHISTFILE, O_RDONLY); 16281 if (fd == -1) { 16282 uu_warn(gettext("Unable to open the history file\n")); 16283 return (-1); 16284 } 16285 16286 if (fstat(fd, &st) == -1) { 16287 uu_warn(gettext("Unable to stat the history file\n")); 16288 return (-1); 16289 } 16290 16291 mfsthist_start = mmap(0, st.st_size, PROT_READ, 16292 MAP_PRIVATE, fd, 0); 16293 16294 (void) close(fd); 16295 if (mfsthist_start == MAP_FAILED || 16296 *(mfsthist_start + st.st_size) != '\0') { 16297 (void) munmap(mfsthist_start, st.st_size); 16298 return (-1); 16299 } 16300 16301 /* 16302 * The manifest history file is a space delimited list 16303 * of service and instance to manifest linkage. Adding 16304 * a space to the end of the service name so to get only 16305 * the service that is being searched for. 16306 */ 16307 svnbuf = uu_msprintf("%s ", svcname); 16308 if (svnbuf == NULL) 16309 uu_die(gettext("Out of memory")); 16310 16311 if (strstr(mfsthist_start, svnbuf) != NULL) 16312 r = 0; 16313 16314 (void) munmap(mfsthist_start, st.st_size); 16315 uu_free(svnbuf); 16316 return (r); 16317 } 16318 16319 /* 16320 * Take down each of the instances in the service 16321 * and remove them, then delete the service. 16322 */ 16323 static void 16324 teardown_service(scf_service_t *svc, const char *svnbuf) 16325 { 16326 scf_instance_t *instance; 16327 scf_iter_t *iter; 16328 int r; 16329 16330 safe_printf(gettext("Delete service %s as there are no " 16331 "supporting manifests\n"), svnbuf); 16332 16333 instance = scf_instance_create(g_hndl); 16334 iter = scf_iter_create(g_hndl); 16335 if (iter == NULL || instance == NULL) { 16336 uu_warn(gettext("Unable to create supporting entities to " 16337 "teardown the service\n")); 16338 uu_warn(gettext("scf error is : %s\n"), 16339 scf_strerror(scf_error())); 16340 scfdie(); 16341 } 16342 16343 if (scf_iter_service_instances(iter, svc) != 0) { 16344 switch (scf_error()) { 16345 case SCF_ERROR_CONNECTION_BROKEN: 16346 case SCF_ERROR_DELETED: 16347 goto out; 16348 16349 case SCF_ERROR_HANDLE_MISMATCH: 16350 case SCF_ERROR_NOT_BOUND: 16351 case SCF_ERROR_NOT_SET: 16352 default: 16353 bad_error("scf_iter_service_instances", 16354 scf_error()); 16355 } 16356 } 16357 16358 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 16359 if (r == -1) { 16360 uu_warn(gettext("Error - %s\n"), 16361 scf_strerror(scf_error())); 16362 goto out; 16363 } 16364 16365 (void) disable_instance(instance); 16366 } 16367 16368 /* 16369 * Delete the service... forcing the deletion in case 16370 * any of the instances did not disable. 16371 */ 16372 (void) lscf_service_delete(svc, 1); 16373 out: 16374 scf_instance_destroy(instance); 16375 scf_iter_destroy(iter); 16376 } 16377 16378 /* 16379 * Get the list of instances supported by the manifest 16380 * file. 16381 * 16382 * Return 0 if there are no instances. 16383 * 16384 * Return -1 if there are errors attempting to collect instances. 16385 * 16386 * Return the count of instances found if there are no errors. 16387 * 16388 */ 16389 static int 16390 check_instance_support(char *mfstfile, const char *svcname, 16391 uu_list_t *instances) 16392 { 16393 uu_list_walk_t *svcs, *insts; 16394 uu_list_t *ilist; 16395 bundle_t *b; 16396 entity_t *mfsvc, *mfinst; 16397 const char *svcn; 16398 int rminstcnt = 0; 16399 16400 16401 b = internal_bundle_new(); 16402 16403 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 16404 /* 16405 * Unable to process the manifest file for 16406 * instance support, so just return as 16407 * don't want to remove instances that could 16408 * not be accounted for that might exist here. 16409 */ 16410 internal_bundle_free(b); 16411 return (0); 16412 } 16413 16414 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 16415 if (svcs == NULL) { 16416 internal_bundle_free(b); 16417 return (0); 16418 } 16419 16420 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 16421 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 16422 16423 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 16424 if (strcmp(mfsvc->sc_name, svcn) == 0) 16425 break; 16426 } 16427 uu_list_walk_end(svcs); 16428 16429 if (mfsvc == NULL) { 16430 internal_bundle_free(b); 16431 return (-1); 16432 } 16433 16434 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 16435 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 16436 internal_bundle_free(b); 16437 return (0); 16438 } 16439 16440 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 16441 /* 16442 * Remove the instance from the instances list. 16443 * The unaccounted for instances will be removed 16444 * from the service once all manifests are 16445 * processed. 16446 */ 16447 (void) remove_string(instances, 16448 mfinst->sc_name); 16449 rminstcnt++; 16450 } 16451 16452 uu_list_walk_end(insts); 16453 internal_bundle_free(b); 16454 16455 return (rminstcnt); 16456 } 16457 16458 /* 16459 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 16460 * 'false' to indicate there's no manifest file(s) found for the service. 16461 */ 16462 static void 16463 svc_add_no_support(scf_service_t *svc) 16464 { 16465 char *pname; 16466 16467 /* Add no support */ 16468 cur_svc = svc; 16469 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 16470 return; 16471 16472 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 16473 if (pname == NULL) 16474 uu_die(gettext("Out of memory.\n")); 16475 16476 (void) lscf_addpropvalue(pname, "boolean:", "0"); 16477 16478 uu_free(pname); 16479 cur_svc = NULL; 16480 } 16481 16482 /* 16483 * This function handles all upgrade scenarios for a service that doesn't have 16484 * SCF_PG_MANIFESTFILES pg. The function creates and populates 16485 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 16486 * manifest(s) mapping. Manifests under supported directories are inventoried 16487 * and a property is added for each file that delivers configuration to the 16488 * service. A service that has no corresponding manifest files (deleted) are 16489 * removed from repository. 16490 * 16491 * Unsupported services: 16492 * 16493 * A service is considered unsupported if there is no corresponding manifest 16494 * in the supported directories for that service and the service isn't in the 16495 * history file list. The history file, MFSTHISTFILE, contains a list of all 16496 * services and instances that were delivered by Solaris before the introduction 16497 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 16498 * the path to the manifest file that defined the service or instance. 16499 * 16500 * Another type of unsupported services is 'handcrafted' services, 16501 * programmatically created services or services created by dependent entries 16502 * in other manifests. A handcrafted service is identified by its lack of any 16503 * instance containing last-import snapshot which is created during svccfg 16504 * import. 16505 * 16506 * This function sets a flag for unsupported services by setting services' 16507 * SCF_PG_MANIFESTFILES/support property to false. 16508 */ 16509 static void 16510 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 16511 { 16512 service_manifest_t *elem; 16513 uu_list_walk_t *mfwalk; 16514 string_list_t *mfile; 16515 uu_list_t *instances; 16516 const char *sname; 16517 char *pname; 16518 int r; 16519 16520 /* 16521 * Since there's no guarantee manifests under /var are available during 16522 * early import, don't perform any upgrade during early import. 16523 */ 16524 if (IGNORE_VAR) 16525 return; 16526 16527 if (service_manifest_tree == NULL) { 16528 create_manifest_tree(); 16529 } 16530 16531 /* 16532 * Find service's supporting manifest(s) after 16533 * stripping off the svc:/ prefix that is part 16534 * of the fmri that is not used in the service 16535 * manifest bundle list. 16536 */ 16537 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 16538 strlen(SCF_FMRI_SERVICE_PREFIX); 16539 elem = find_add_svc_mfst(sname, NULL); 16540 if (elem == NULL) { 16541 16542 /* 16543 * A handcrafted service, one that has no instance containing 16544 * last-import snapshot, should get unsupported flag. 16545 */ 16546 instances = create_instance_list(svc, 1); 16547 if (instances == NULL) { 16548 uu_warn(gettext("Unable to create instance list %s\n"), 16549 svcname); 16550 return; 16551 } 16552 16553 if (uu_list_numnodes(instances) == 0) { 16554 svc_add_no_support(svc); 16555 return; 16556 } 16557 16558 /* 16559 * If the service is in the history file, and its supporting 16560 * manifests are not found, we can safely delete the service 16561 * because its manifests are removed from the system. 16562 * 16563 * Services not found in the history file are not delivered by 16564 * Solaris and/or delivered outside supported directories, set 16565 * unsupported flag for these services. 16566 */ 16567 r = check_mfst_history(svcname); 16568 if (r == -1) 16569 return; 16570 16571 if (r) { 16572 /* Set unsupported flag for service */ 16573 svc_add_no_support(svc); 16574 } else { 16575 /* Delete the service */ 16576 teardown_service(svc, svcname); 16577 } 16578 16579 return; 16580 } 16581 16582 /* 16583 * Walk through the list of manifests and add them 16584 * to the service. 16585 * 16586 * Create a manifestfiles pg and add the property. 16587 */ 16588 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 16589 if (mfwalk == NULL) 16590 return; 16591 16592 cur_svc = svc; 16593 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 16594 if (r != 0) { 16595 cur_svc = NULL; 16596 return; 16597 } 16598 16599 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 16600 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16601 mhash_filename_to_propname(mfile->str, 0)); 16602 if (pname == NULL) 16603 uu_die(gettext("Out of memory.\n")); 16604 16605 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 16606 uu_free(pname); 16607 } 16608 uu_list_walk_end(mfwalk); 16609 16610 cur_svc = NULL; 16611 } 16612 16613 /* 16614 * Take a service and process the manifest file entires to see if 16615 * there is continued support for the service and instances. If 16616 * not cleanup as appropriate. 16617 * 16618 * If a service does not have a manifest files entry flag it for 16619 * upgrade and return. 16620 * 16621 * For each manifestfiles property check if the manifest file is 16622 * under the supported /lib/svc/manifest or /var/svc/manifest path 16623 * and if not then return immediately as this service is not supported 16624 * by the cleanup mechanism and should be ignored. 16625 * 16626 * For each manifest file that is supported, check to see if the 16627 * file exists. If not then remove the manifest file property 16628 * from the service and the smf/manifest hash table. If the manifest 16629 * file exists then verify that it supports the instances that are 16630 * part of the service. 16631 * 16632 * Once all manifest files have been accounted for remove any instances 16633 * that are no longer supported in the service. 16634 * 16635 * Return values : 16636 * 0 - Successfully processed the service 16637 * non-zero - failed to process the service 16638 * 16639 * On most errors, will just return to wait and get the next service, 16640 * unless in case of unable to create the needed structures which is 16641 * most likely a fatal error that is not going to be recoverable. 16642 */ 16643 int 16644 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 16645 { 16646 struct mpg_mfile *mpntov; 16647 struct mpg_mfile **mpvarry = NULL; 16648 scf_service_t *svc; 16649 scf_propertygroup_t *mpg; 16650 scf_property_t *mp; 16651 scf_value_t *mv; 16652 scf_iter_t *mi; 16653 scf_instance_t *instance; 16654 uu_list_walk_t *insts; 16655 uu_list_t *instances = NULL; 16656 boolean_t activity = (boolean_t)act; 16657 char *mpnbuf; 16658 char *mpvbuf; 16659 char *pgpropbuf; 16660 int mfstcnt, rminstct, instct, mfstmax; 16661 int index; 16662 int r = 0; 16663 16664 assert(g_hndl != NULL); 16665 assert(wip->svc != NULL); 16666 assert(wip->fmri != NULL); 16667 16668 svc = wip->svc; 16669 16670 mpg = scf_pg_create(g_hndl); 16671 mp = scf_property_create(g_hndl); 16672 mi = scf_iter_create(g_hndl); 16673 mv = scf_value_create(g_hndl); 16674 instance = scf_instance_create(g_hndl); 16675 16676 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 16677 instance == NULL) { 16678 uu_warn(gettext("Unable to create the supporting entities\n")); 16679 uu_warn(gettext("scf error is : %s\n"), 16680 scf_strerror(scf_error())); 16681 scfdie(); 16682 } 16683 16684 /* 16685 * Get the manifestfiles property group to be parsed for 16686 * files existence. 16687 */ 16688 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 16689 switch (scf_error()) { 16690 case SCF_ERROR_NOT_FOUND: 16691 upgrade_svc_mfst_connection(svc, wip->fmri); 16692 break; 16693 case SCF_ERROR_DELETED: 16694 case SCF_ERROR_CONNECTION_BROKEN: 16695 goto out; 16696 16697 case SCF_ERROR_HANDLE_MISMATCH: 16698 case SCF_ERROR_NOT_BOUND: 16699 case SCF_ERROR_NOT_SET: 16700 default: 16701 bad_error("scf_iter_pg_properties", 16702 scf_error()); 16703 } 16704 16705 goto out; 16706 } 16707 16708 /* 16709 * Iterate through each of the manifestfiles properties 16710 * to determine what manifestfiles are available. 16711 * 16712 * If a manifest file is supported then increment the 16713 * count and therefore the service is safe. 16714 */ 16715 if (scf_iter_pg_properties(mi, mpg) != 0) { 16716 switch (scf_error()) { 16717 case SCF_ERROR_DELETED: 16718 case SCF_ERROR_CONNECTION_BROKEN: 16719 goto out; 16720 16721 case SCF_ERROR_HANDLE_MISMATCH: 16722 case SCF_ERROR_NOT_BOUND: 16723 case SCF_ERROR_NOT_SET: 16724 default: 16725 bad_error("scf_iter_pg_properties", 16726 scf_error()); 16727 } 16728 } 16729 16730 mfstcnt = 0; 16731 mfstmax = MFSTFILE_MAX; 16732 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 16733 while ((r = scf_iter_next_property(mi, mp)) != 0) { 16734 if (r == -1) 16735 bad_error(gettext("Unable to iterate through " 16736 "manifestfiles properties : %s"), 16737 scf_error()); 16738 16739 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 16740 mpnbuf = safe_malloc(max_scf_name_len + 1); 16741 mpvbuf = safe_malloc(max_scf_value_len + 1); 16742 mpntov->mpg = mpnbuf; 16743 mpntov->mfile = mpvbuf; 16744 mpntov->access = 1; 16745 if (scf_property_get_name(mp, mpnbuf, 16746 max_scf_name_len + 1) < 0) { 16747 uu_warn(gettext("Unable to get manifest file " 16748 "property : %s\n"), 16749 scf_strerror(scf_error())); 16750 16751 switch (scf_error()) { 16752 case SCF_ERROR_DELETED: 16753 case SCF_ERROR_CONNECTION_BROKEN: 16754 r = scferror2errno(scf_error()); 16755 goto out_free; 16756 16757 case SCF_ERROR_HANDLE_MISMATCH: 16758 case SCF_ERROR_NOT_BOUND: 16759 case SCF_ERROR_NOT_SET: 16760 default: 16761 bad_error("scf_iter_pg_properties", 16762 scf_error()); 16763 } 16764 } 16765 16766 /* 16767 * The support property is a boolean value that indicates 16768 * if the service is supported for manifest file deletion. 16769 * Currently at this time there is no code that sets this 16770 * value to true. So while we could just let this be caught 16771 * by the support check below, in the future this by be set 16772 * to true and require processing. So for that, go ahead 16773 * and check here, and just return if false. Otherwise, 16774 * fall through expecting that other support checks will 16775 * handle the entries. 16776 */ 16777 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 16778 uint8_t support; 16779 16780 if (scf_property_get_value(mp, mv) != 0 || 16781 scf_value_get_boolean(mv, &support) != 0) { 16782 uu_warn(gettext("Unable to get the manifest " 16783 "support value: %s\n"), 16784 scf_strerror(scf_error())); 16785 16786 switch (scf_error()) { 16787 case SCF_ERROR_DELETED: 16788 case SCF_ERROR_CONNECTION_BROKEN: 16789 r = scferror2errno(scf_error()); 16790 goto out_free; 16791 16792 case SCF_ERROR_HANDLE_MISMATCH: 16793 case SCF_ERROR_NOT_BOUND: 16794 case SCF_ERROR_NOT_SET: 16795 default: 16796 bad_error("scf_iter_pg_properties", 16797 scf_error()); 16798 } 16799 } 16800 16801 if (support == B_FALSE) 16802 goto out_free; 16803 } 16804 16805 /* 16806 * Anything with a manifest outside of the supported 16807 * directories, immediately bail out because that makes 16808 * this service non-supported. We don't even want 16809 * to do instance processing in this case because the 16810 * instances could be part of the non-supported manifest. 16811 */ 16812 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 16813 /* 16814 * Manifest is not in /lib/svc, so we need to 16815 * consider the /var/svc case. 16816 */ 16817 if (strncmp(mpnbuf, VARSVC_PR, 16818 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 16819 /* 16820 * Either the manifest is not in /var/svc or 16821 * /var is not yet mounted. We ignore the 16822 * manifest either because it is not in a 16823 * standard location or because we cannot 16824 * currently access the manifest. 16825 */ 16826 goto out_free; 16827 } 16828 } 16829 16830 /* 16831 * Get the value to of the manifest file for this entry 16832 * for access verification and instance support 16833 * verification if it still exists. 16834 * 16835 * During Early Manifest Import if the manifest is in 16836 * /var/svc then it may not yet be available for checking 16837 * so we must determine if /var/svc is available. If not 16838 * then defer until Late Manifest Import to cleanup. 16839 */ 16840 if (scf_property_get_value(mp, mv) != 0) { 16841 uu_warn(gettext("Unable to get the manifest file " 16842 "value: %s\n"), 16843 scf_strerror(scf_error())); 16844 16845 switch (scf_error()) { 16846 case SCF_ERROR_DELETED: 16847 case SCF_ERROR_CONNECTION_BROKEN: 16848 r = scferror2errno(scf_error()); 16849 goto out_free; 16850 16851 case SCF_ERROR_HANDLE_MISMATCH: 16852 case SCF_ERROR_NOT_BOUND: 16853 case SCF_ERROR_NOT_SET: 16854 default: 16855 bad_error("scf_property_get_value", 16856 scf_error()); 16857 } 16858 } 16859 16860 if (scf_value_get_astring(mv, mpvbuf, 16861 max_scf_value_len + 1) < 0) { 16862 uu_warn(gettext("Unable to get the manifest " 16863 "file : %s\n"), 16864 scf_strerror(scf_error())); 16865 16866 switch (scf_error()) { 16867 case SCF_ERROR_DELETED: 16868 case SCF_ERROR_CONNECTION_BROKEN: 16869 r = scferror2errno(scf_error()); 16870 goto out_free; 16871 16872 case SCF_ERROR_HANDLE_MISMATCH: 16873 case SCF_ERROR_NOT_BOUND: 16874 case SCF_ERROR_NOT_SET: 16875 default: 16876 bad_error("scf_value_get_astring", 16877 scf_error()); 16878 } 16879 } 16880 16881 mpvarry[mfstcnt] = mpntov; 16882 mfstcnt++; 16883 16884 /* 16885 * Check for the need to reallocate array 16886 */ 16887 if (mfstcnt >= (mfstmax - 1)) { 16888 struct mpg_mfile **newmpvarry; 16889 16890 mfstmax = mfstmax * 2; 16891 newmpvarry = realloc(mpvarry, 16892 sizeof (struct mpg_mfile *) * mfstmax); 16893 16894 if (newmpvarry == NULL) 16895 goto out_free; 16896 16897 mpvarry = newmpvarry; 16898 } 16899 16900 mpvarry[mfstcnt] = NULL; 16901 } 16902 16903 for (index = 0; mpvarry[index]; index++) { 16904 mpntov = mpvarry[index]; 16905 16906 /* 16907 * Check to see if the manifestfile is accessable, if so hand 16908 * this service and manifestfile off to be processed for 16909 * instance support. 16910 */ 16911 mpnbuf = mpntov->mpg; 16912 mpvbuf = mpntov->mfile; 16913 if (access(mpvbuf, F_OK) != 0) { 16914 mpntov->access = 0; 16915 activity++; 16916 mfstcnt--; 16917 /* Remove the entry from the service */ 16918 cur_svc = svc; 16919 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16920 mpnbuf); 16921 if (pgpropbuf == NULL) 16922 uu_die(gettext("Out of memory.\n")); 16923 16924 lscf_delprop(pgpropbuf); 16925 cur_svc = NULL; 16926 16927 uu_free(pgpropbuf); 16928 } 16929 } 16930 16931 /* 16932 * If mfstcnt is 0, none of the manifests that supported the service 16933 * existed so remove the service. 16934 */ 16935 if (mfstcnt == 0) { 16936 teardown_service(svc, wip->fmri); 16937 16938 goto out_free; 16939 } 16940 16941 if (activity) { 16942 int nosvcsupport = 0; 16943 16944 /* 16945 * If the list of service instances is NULL then 16946 * create the list. 16947 */ 16948 instances = create_instance_list(svc, 1); 16949 if (instances == NULL) { 16950 uu_warn(gettext("Unable to create instance list %s\n"), 16951 wip->fmri); 16952 goto out_free; 16953 } 16954 16955 rminstct = uu_list_numnodes(instances); 16956 instct = rminstct; 16957 16958 for (index = 0; mpvarry[index]; index++) { 16959 mpntov = mpvarry[index]; 16960 if (mpntov->access == 0) 16961 continue; 16962 16963 mpnbuf = mpntov->mpg; 16964 mpvbuf = mpntov->mfile; 16965 r = check_instance_support(mpvbuf, wip->fmri, 16966 instances); 16967 if (r == -1) { 16968 nosvcsupport++; 16969 } else { 16970 rminstct -= r; 16971 } 16972 } 16973 16974 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 16975 teardown_service(svc, wip->fmri); 16976 16977 goto out_free; 16978 } 16979 } 16980 16981 /* 16982 * If there are instances left on the instance list, then 16983 * we must remove them. 16984 */ 16985 if (instances != NULL && uu_list_numnodes(instances)) { 16986 string_list_t *sp; 16987 16988 insts = uu_list_walk_start(instances, 0); 16989 while ((sp = uu_list_walk_next(insts)) != NULL) { 16990 /* 16991 * Remove the instance from the instances list. 16992 */ 16993 safe_printf(gettext("Delete instance %s from " 16994 "service %s\n"), sp->str, wip->fmri); 16995 if (scf_service_get_instance(svc, sp->str, 16996 instance) != SCF_SUCCESS) { 16997 (void) uu_warn("scf_error - %s\n", 16998 scf_strerror(scf_error())); 16999 17000 continue; 17001 } 17002 17003 (void) disable_instance(instance); 17004 17005 (void) lscf_instance_delete(instance, 1); 17006 } 17007 scf_instance_destroy(instance); 17008 uu_list_walk_end(insts); 17009 } 17010 17011 out_free: 17012 if (mpvarry) { 17013 struct mpg_mfile *fmpntov; 17014 17015 for (index = 0; mpvarry[index]; index++) { 17016 fmpntov = mpvarry[index]; 17017 if (fmpntov->mpg == mpnbuf) 17018 mpnbuf = NULL; 17019 free(fmpntov->mpg); 17020 17021 if (fmpntov->mfile == mpvbuf) 17022 mpvbuf = NULL; 17023 free(fmpntov->mfile); 17024 17025 if (fmpntov == mpntov) 17026 mpntov = NULL; 17027 free(fmpntov); 17028 } 17029 if (mpnbuf) 17030 free(mpnbuf); 17031 if (mpvbuf) 17032 free(mpvbuf); 17033 if (mpntov) 17034 free(mpntov); 17035 17036 free(mpvarry); 17037 } 17038 out: 17039 scf_pg_destroy(mpg); 17040 scf_property_destroy(mp); 17041 scf_iter_destroy(mi); 17042 scf_value_destroy(mv); 17043 17044 return (0); 17045 } 17046 17047 /* 17048 * Take the service and search for the manifestfiles property 17049 * in each of the property groups. If the manifest file 17050 * associated with the property does not exist then remove 17051 * the property group. 17052 */ 17053 int 17054 lscf_hash_cleanup() 17055 { 17056 scf_service_t *svc; 17057 scf_scope_t *scope; 17058 scf_propertygroup_t *pg; 17059 scf_property_t *prop; 17060 scf_value_t *val; 17061 scf_iter_t *iter; 17062 char *pgname = NULL; 17063 char *mfile = NULL; 17064 int r; 17065 17066 svc = scf_service_create(g_hndl); 17067 scope = scf_scope_create(g_hndl); 17068 pg = scf_pg_create(g_hndl); 17069 prop = scf_property_create(g_hndl); 17070 val = scf_value_create(g_hndl); 17071 iter = scf_iter_create(g_hndl); 17072 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 17073 svc == NULL || scope == NULL) { 17074 uu_warn(gettext("Unable to create a property group, or " 17075 "property\n")); 17076 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 17077 "pg is not NULL"); 17078 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 17079 "prop is not NULL"); 17080 uu_warn("%s\n", val == NULL ? "val is NULL" : 17081 "val is not NULL"); 17082 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 17083 "iter is not NULL"); 17084 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 17085 "svc is not NULL"); 17086 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 17087 "scope is not NULL"); 17088 uu_warn(gettext("scf error is : %s\n"), 17089 scf_strerror(scf_error())); 17090 scfdie(); 17091 } 17092 17093 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 17094 switch (scf_error()) { 17095 case SCF_ERROR_CONNECTION_BROKEN: 17096 case SCF_ERROR_NOT_FOUND: 17097 goto out; 17098 17099 case SCF_ERROR_HANDLE_MISMATCH: 17100 case SCF_ERROR_NOT_BOUND: 17101 case SCF_ERROR_INVALID_ARGUMENT: 17102 default: 17103 bad_error("scf_handle_get_scope", scf_error()); 17104 } 17105 } 17106 17107 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 17108 uu_warn(gettext("Unable to process the hash service, %s\n"), 17109 HASH_SVC); 17110 goto out; 17111 } 17112 17113 pgname = safe_malloc(max_scf_name_len + 1); 17114 mfile = safe_malloc(max_scf_value_len + 1); 17115 17116 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 17117 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 17118 scf_strerror(scf_error())); 17119 goto out; 17120 } 17121 17122 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 17123 if (r == -1) 17124 goto out; 17125 17126 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 17127 switch (scf_error()) { 17128 case SCF_ERROR_DELETED: 17129 return (ENODEV); 17130 17131 case SCF_ERROR_CONNECTION_BROKEN: 17132 return (ECONNABORTED); 17133 17134 case SCF_ERROR_NOT_SET: 17135 case SCF_ERROR_NOT_BOUND: 17136 default: 17137 bad_error("scf_pg_get_name", scf_error()); 17138 } 17139 } 17140 if (IGNORE_VAR) { 17141 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 17142 continue; 17143 } 17144 17145 /* 17146 * If unable to get the property continue as this is an 17147 * entry that has no location to check against. 17148 */ 17149 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 17150 continue; 17151 } 17152 17153 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 17154 uu_warn(gettext("Unable to get value from %s\n"), 17155 pgname); 17156 17157 switch (scf_error()) { 17158 case SCF_ERROR_DELETED: 17159 case SCF_ERROR_CONSTRAINT_VIOLATED: 17160 case SCF_ERROR_NOT_FOUND: 17161 case SCF_ERROR_NOT_SET: 17162 continue; 17163 17164 case SCF_ERROR_CONNECTION_BROKEN: 17165 r = scferror2errno(scf_error()); 17166 goto out; 17167 17168 case SCF_ERROR_HANDLE_MISMATCH: 17169 case SCF_ERROR_NOT_BOUND: 17170 default: 17171 bad_error("scf_property_get_value", 17172 scf_error()); 17173 } 17174 } 17175 17176 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) 17177 == -1) { 17178 uu_warn(gettext("Unable to get astring from %s : %s\n"), 17179 pgname, scf_strerror(scf_error())); 17180 17181 switch (scf_error()) { 17182 case SCF_ERROR_NOT_SET: 17183 case SCF_ERROR_TYPE_MISMATCH: 17184 continue; 17185 17186 default: 17187 bad_error("scf_value_get_astring", scf_error()); 17188 } 17189 } 17190 17191 if (access(mfile, F_OK) == 0) 17192 continue; 17193 17194 (void) scf_pg_delete(pg); 17195 } 17196 17197 out: 17198 scf_scope_destroy(scope); 17199 scf_service_destroy(svc); 17200 scf_pg_destroy(pg); 17201 scf_property_destroy(prop); 17202 scf_value_destroy(val); 17203 scf_iter_destroy(iter); 17204 free(pgname); 17205 free(mfile); 17206 17207 return (0); 17208 } 17209 17210 #ifndef NATIVE_BUILD 17211 /* ARGSUSED */ 17212 CPL_MATCH_FN(complete_select) 17213 { 17214 const char *arg0, *arg1, *arg1end; 17215 int word_start, err = 0, r; 17216 size_t len; 17217 char *buf; 17218 17219 lscf_prep_hndl(); 17220 17221 arg0 = line + strspn(line, " \t"); 17222 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 17223 17224 arg1 = arg0 + sizeof ("select") - 1; 17225 arg1 += strspn(arg1, " \t"); 17226 word_start = arg1 - line; 17227 17228 arg1end = arg1 + strcspn(arg1, " \t"); 17229 if (arg1end < line + word_end) 17230 return (0); 17231 17232 len = line + word_end - arg1; 17233 17234 buf = safe_malloc(max_scf_name_len + 1); 17235 17236 if (cur_snap != NULL) { 17237 return (0); 17238 } else if (cur_inst != NULL) { 17239 return (0); 17240 } else if (cur_svc != NULL) { 17241 scf_instance_t *inst; 17242 scf_iter_t *iter; 17243 17244 if ((inst = scf_instance_create(g_hndl)) == NULL || 17245 (iter = scf_iter_create(g_hndl)) == NULL) 17246 scfdie(); 17247 17248 if (scf_iter_service_instances(iter, cur_svc) != 0) 17249 scfdie(); 17250 17251 for (;;) { 17252 r = scf_iter_next_instance(iter, inst); 17253 if (r == 0) 17254 break; 17255 if (r != 1) 17256 scfdie(); 17257 17258 if (scf_instance_get_name(inst, buf, 17259 max_scf_name_len + 1) < 0) 17260 scfdie(); 17261 17262 if (strncmp(buf, arg1, len) == 0) { 17263 err = cpl_add_completion(cpl, line, word_start, 17264 word_end, buf + len, "", " "); 17265 if (err != 0) 17266 break; 17267 } 17268 } 17269 17270 scf_iter_destroy(iter); 17271 scf_instance_destroy(inst); 17272 17273 return (err); 17274 } else { 17275 scf_service_t *svc; 17276 scf_iter_t *iter; 17277 17278 assert(cur_scope != NULL); 17279 17280 if ((svc = scf_service_create(g_hndl)) == NULL || 17281 (iter = scf_iter_create(g_hndl)) == NULL) 17282 scfdie(); 17283 17284 if (scf_iter_scope_services(iter, cur_scope) != 0) 17285 scfdie(); 17286 17287 for (;;) { 17288 r = scf_iter_next_service(iter, svc); 17289 if (r == 0) 17290 break; 17291 if (r != 1) 17292 scfdie(); 17293 17294 if (scf_service_get_name(svc, buf, 17295 max_scf_name_len + 1) < 0) 17296 scfdie(); 17297 17298 if (strncmp(buf, arg1, len) == 0) { 17299 err = cpl_add_completion(cpl, line, word_start, 17300 word_end, buf + len, "", " "); 17301 if (err != 0) 17302 break; 17303 } 17304 } 17305 17306 scf_iter_destroy(iter); 17307 scf_service_destroy(svc); 17308 17309 return (err); 17310 } 17311 } 17312 17313 /* ARGSUSED */ 17314 CPL_MATCH_FN(complete_command) 17315 { 17316 uint32_t scope = 0; 17317 17318 if (cur_snap != NULL) 17319 scope = CS_SNAP; 17320 else if (cur_inst != NULL) 17321 scope = CS_INST; 17322 else if (cur_svc != NULL) 17323 scope = CS_SVC; 17324 else 17325 scope = CS_SCOPE; 17326 17327 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 17328 } 17329 #endif /* NATIVE_BUILD */ 17330