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