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