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 */ 25 26 27 #include <alloca.h> 28 #include <assert.h> 29 #include <ctype.h> 30 #include <door.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <fnmatch.h> 34 #include <inttypes.h> 35 #include <libintl.h> 36 #include <libscf.h> 37 #include <libscf_priv.h> 38 #include <libtecla.h> 39 #include <libuutil.h> 40 #include <limits.h> 41 #include <locale.h> 42 #include <stdarg.h> 43 #include <string.h> 44 #include <strings.h> 45 #include <unistd.h> 46 #include <wait.h> 47 #include <poll.h> 48 49 #include <libxml/tree.h> 50 51 #include <sys/param.h> 52 53 #include <sys/stat.h> 54 #include <sys/mman.h> 55 56 #include "svccfg.h" 57 #include "manifest_hash.h" 58 #include "manifest_find.h" 59 60 /* The colon namespaces in each entity (each followed by a newline). */ 61 #define COLON_NAMESPACES ":properties\n" 62 63 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 64 65 /* These are characters which the lexer requires to be in double-quotes. */ 66 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 67 68 #define HASH_SIZE 16 69 #define HASH_PG_TYPE "framework" 70 #define HASH_PG_FLAGS 0 71 #define HASH_PROP "md5sum" 72 73 /* 74 * Indentation used in the output of the describe subcommand. 75 */ 76 #define TMPL_VALUE_INDENT " " 77 #define TMPL_INDENT " " 78 #define TMPL_INDENT_2X " " 79 #define TMPL_CHOICE_INDENT " " 80 81 /* 82 * Directory locations for manifests 83 */ 84 #define VARSVC_DIR "/var/svc/manifest" 85 #define LIBSVC_DIR "/lib/svc/manifest" 86 #define VARSVC_PR "var_svc_manifest" 87 #define LIBSVC_PR "lib_svc_manifest" 88 #define MFSTFILEPR "manifestfile" 89 90 #define SUPPORTPROP "support" 91 92 #define MFSTHISTFILE "/lib/svc/share/mfsthistory" 93 94 #define MFSTFILE_MAX 16 95 96 /* 97 * These are the classes of elements which may appear as children of service 98 * or instance elements in XML manifests. 99 */ 100 struct entity_elts { 101 xmlNodePtr create_default_instance; 102 xmlNodePtr single_instance; 103 xmlNodePtr restarter; 104 xmlNodePtr dependencies; 105 xmlNodePtr dependents; 106 xmlNodePtr method_context; 107 xmlNodePtr exec_methods; 108 xmlNodePtr property_groups; 109 xmlNodePtr instances; 110 xmlNodePtr stability; 111 xmlNodePtr template; 112 }; 113 114 /* 115 * Likewise for property_group elements. 116 */ 117 struct pg_elts { 118 xmlNodePtr stability; 119 xmlNodePtr propvals; 120 xmlNodePtr properties; 121 }; 122 123 /* 124 * Likewise for template elements. 125 */ 126 struct template_elts { 127 xmlNodePtr common_name; 128 xmlNodePtr description; 129 xmlNodePtr documentation; 130 }; 131 132 /* 133 * This structure is for snaplevel lists. They are convenient because libscf 134 * only allows traversing snaplevels in one direction. 135 */ 136 struct snaplevel { 137 uu_list_node_t list_node; 138 scf_snaplevel_t *sl; 139 }; 140 141 /* 142 * This is used for communication between lscf_service_export and 143 * export_callback. 144 */ 145 struct export_args { 146 const char *filename; 147 int flags; 148 }; 149 150 /* 151 * The service_manifest structure is used by the upgrade process 152 * to create a list of service to manifest linkages from the manifests 153 * in a set of given directories. 154 */ 155 typedef struct service_manifest { 156 const char *servicename; 157 uu_list_t *mfstlist; 158 size_t mfstlist_sz; 159 160 uu_avl_node_t svcmfst_node; 161 } service_manifest_t; 162 163 /* 164 * Structure to track the manifest file property group 165 * and the manifest file associated with that property 166 * group. Also, a flag to keep the access once it has 167 * been checked. 168 */ 169 struct mpg_mfile { 170 char *mpg; 171 char *mfile; 172 int access; 173 }; 174 175 const char * const scf_pg_general = SCF_PG_GENERAL; 176 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 177 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 178 const char * const scf_property_external = "external"; 179 180 const char * const snap_initial = "initial"; 181 const char * const snap_lastimport = "last-import"; 182 const char * const snap_previous = "previous"; 183 const char * const snap_running = "running"; 184 185 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 186 187 ssize_t max_scf_fmri_len; 188 ssize_t max_scf_name_len; 189 ssize_t max_scf_pg_type_len; 190 ssize_t max_scf_value_len; 191 static size_t max_scf_len; 192 193 static scf_scope_t *cur_scope; 194 static scf_service_t *cur_svc = NULL; 195 static scf_instance_t *cur_inst = NULL; 196 static scf_snapshot_t *cur_snap = NULL; 197 static scf_snaplevel_t *cur_level = NULL; 198 199 static uu_list_pool_t *snaplevel_pool; 200 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 201 static uu_list_t *cur_levels; 202 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 203 204 static FILE *tempfile = NULL; 205 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 206 207 static const char *emsg_entity_not_selected; 208 static const char *emsg_permission_denied; 209 static const char *emsg_create_xml; 210 static const char *emsg_cant_modify_snapshots; 211 static const char *emsg_read_only; 212 static const char *emsg_deleted; 213 static const char *emsg_invalid_pg_name; 214 static const char *emsg_invalid_prop_name; 215 static const char *emsg_no_such_pg; 216 static const char *emsg_fmri_invalid_pg_name; 217 static const char *emsg_fmri_invalid_pg_name_type; 218 static const char *emsg_pg_added; 219 static const char *emsg_pg_changed; 220 static const char *emsg_pg_deleted; 221 static const char *emsg_pg_mod_perm; 222 static const char *emsg_pg_add_perm; 223 static const char *emsg_pg_del_perm; 224 static const char *emsg_snap_perm; 225 static const char *emsg_dpt_dangling; 226 static const char *emsg_dpt_no_dep; 227 228 static int li_only = 0; 229 static int no_refresh = 0; 230 231 /* import globals, to minimize allocations */ 232 static scf_scope_t *imp_scope = NULL; 233 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 234 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 235 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 236 static scf_snapshot_t *imp_rsnap = NULL; 237 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 238 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 239 static scf_property_t *imp_prop = NULL; 240 static scf_iter_t *imp_iter = NULL; 241 static scf_iter_t *imp_rpg_iter = NULL; 242 static scf_iter_t *imp_up_iter = NULL; 243 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 244 static char *imp_str = NULL; 245 static size_t imp_str_sz; 246 static char *imp_tsname = NULL; 247 static char *imp_fe1 = NULL; /* for fmri_equal() */ 248 static char *imp_fe2 = NULL; 249 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 250 251 /* upgrade_dependents() globals */ 252 static scf_instance_t *ud_inst = NULL; 253 static scf_snaplevel_t *ud_snpl = NULL; 254 static scf_propertygroup_t *ud_pg = NULL; 255 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 256 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 257 static int ud_run_dpts_pg_set = 0; 258 static scf_property_t *ud_prop = NULL; 259 static scf_property_t *ud_dpt_prop = NULL; 260 static scf_value_t *ud_val = NULL; 261 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 262 static scf_transaction_t *ud_tx = NULL; 263 static char *ud_ctarg = NULL; 264 static char *ud_oldtarg = NULL; 265 static char *ud_name = NULL; 266 267 /* export globals */ 268 static scf_instance_t *exp_inst; 269 static scf_propertygroup_t *exp_pg; 270 static scf_property_t *exp_prop; 271 static scf_value_t *exp_val; 272 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 273 static char *exp_str; 274 static size_t exp_str_sz; 275 276 /* cleanup globals */ 277 static uu_avl_pool_t *service_manifest_pool = NULL; 278 static uu_avl_t *service_manifest_tree = NULL; 279 280 static void scfdie_lineno(int lineno) __NORETURN; 281 282 static char *start_method_names[] = { 283 "start", 284 "inetd_start", 285 NULL 286 }; 287 288 static void 289 safe_printf(const char *fmt, ...) 290 { 291 va_list va; 292 293 va_start(va, fmt); 294 if (vprintf(fmt, va) < 0) 295 uu_die(gettext("Error writing to stdout")); 296 va_end(va); 297 } 298 299 /* 300 * For unexpected libscf errors. 301 */ 302 #ifdef NDEBUG 303 304 static void scfdie(void) __NORETURN; 305 306 static void 307 scfdie(void) 308 { 309 scf_error_t err = scf_error(); 310 311 if (err == SCF_ERROR_CONNECTION_BROKEN) 312 uu_die(gettext("Repository connection broken. Exiting.\n")); 313 314 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 315 scf_strerror(err)); 316 } 317 318 #else 319 320 #define scfdie() scfdie_lineno(__LINE__) 321 322 static void 323 scfdie_lineno(int lineno) 324 { 325 scf_error_t err = scf_error(); 326 327 if (err == SCF_ERROR_CONNECTION_BROKEN) 328 uu_die(gettext("Repository connection broken. Exiting.\n")); 329 330 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 331 ": %s.\n"), lineno, scf_strerror(err)); 332 } 333 334 #endif 335 336 static void 337 scfwarn(void) 338 { 339 warn(gettext("Unexpected libscf error: %s.\n"), 340 scf_strerror(scf_error())); 341 } 342 343 /* 344 * Clear a field of a structure. 345 */ 346 static int 347 clear_int(void *a, void *b) 348 { 349 /* LINTED */ 350 *(int *)((char *)a + (size_t)b) = 0; 351 352 return (UU_WALK_NEXT); 353 } 354 355 static int 356 scferror2errno(scf_error_t err) 357 { 358 switch (err) { 359 case SCF_ERROR_BACKEND_ACCESS: 360 return (EACCES); 361 362 case SCF_ERROR_BACKEND_READONLY: 363 return (EROFS); 364 365 case SCF_ERROR_CONNECTION_BROKEN: 366 return (ECONNABORTED); 367 368 case SCF_ERROR_CONSTRAINT_VIOLATED: 369 case SCF_ERROR_INVALID_ARGUMENT: 370 return (EINVAL); 371 372 case SCF_ERROR_DELETED: 373 return (ECANCELED); 374 375 case SCF_ERROR_EXISTS: 376 return (EEXIST); 377 378 case SCF_ERROR_NO_MEMORY: 379 return (ENOMEM); 380 381 case SCF_ERROR_NO_RESOURCES: 382 return (ENOSPC); 383 384 case SCF_ERROR_NOT_FOUND: 385 return (ENOENT); 386 387 case SCF_ERROR_PERMISSION_DENIED: 388 return (EPERM); 389 390 default: 391 #ifndef NDEBUG 392 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 393 __FILE__, __LINE__, err); 394 #else 395 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 396 #endif 397 abort(); 398 /* NOTREACHED */ 399 } 400 } 401 402 static int 403 entity_get_pg(void *ent, int issvc, const char *name, 404 scf_propertygroup_t *pg) 405 { 406 if (issvc) 407 return (scf_service_get_pg(ent, name, pg)); 408 else 409 return (scf_instance_get_pg(ent, name, pg)); 410 } 411 412 static void 413 entity_destroy(void *ent, int issvc) 414 { 415 if (issvc) 416 scf_service_destroy(ent); 417 else 418 scf_instance_destroy(ent); 419 } 420 421 static int 422 get_pg(const char *pg_name, scf_propertygroup_t *pg) 423 { 424 int ret; 425 426 if (cur_level != NULL) 427 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 428 else if (cur_inst != NULL) 429 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 430 else 431 ret = scf_service_get_pg(cur_svc, pg_name, pg); 432 433 return (ret); 434 } 435 436 /* 437 * Find a snaplevel in a snapshot. If get_svc is true, find the service 438 * snaplevel. Otherwise find the instance snaplevel. 439 * 440 * Returns 441 * 0 - success 442 * ECONNABORTED - repository connection broken 443 * ECANCELED - instance containing snap was deleted 444 * ENOENT - snap has no snaplevels 445 * - requested snaplevel not found 446 */ 447 static int 448 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 449 { 450 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 451 switch (scf_error()) { 452 case SCF_ERROR_CONNECTION_BROKEN: 453 case SCF_ERROR_DELETED: 454 case SCF_ERROR_NOT_FOUND: 455 return (scferror2errno(scf_error())); 456 457 case SCF_ERROR_HANDLE_MISMATCH: 458 case SCF_ERROR_NOT_BOUND: 459 case SCF_ERROR_NOT_SET: 460 default: 461 bad_error("scf_snapshot_get_base_snaplevel", 462 scf_error()); 463 } 464 } 465 466 for (;;) { 467 ssize_t ssz; 468 469 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 470 if (ssz >= 0) { 471 if (!get_svc) 472 return (0); 473 } else { 474 switch (scf_error()) { 475 case SCF_ERROR_CONSTRAINT_VIOLATED: 476 if (get_svc) 477 return (0); 478 break; 479 480 case SCF_ERROR_DELETED: 481 case SCF_ERROR_CONNECTION_BROKEN: 482 return (scferror2errno(scf_error())); 483 484 case SCF_ERROR_NOT_SET: 485 case SCF_ERROR_NOT_BOUND: 486 default: 487 bad_error("scf_snaplevel_get_instance_name", 488 scf_error()); 489 } 490 } 491 492 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 493 switch (scf_error()) { 494 case SCF_ERROR_NOT_FOUND: 495 case SCF_ERROR_CONNECTION_BROKEN: 496 case SCF_ERROR_DELETED: 497 return (scferror2errno(scf_error())); 498 499 case SCF_ERROR_HANDLE_MISMATCH: 500 case SCF_ERROR_NOT_BOUND: 501 case SCF_ERROR_NOT_SET: 502 case SCF_ERROR_INVALID_ARGUMENT: 503 default: 504 bad_error("scf_snaplevel_get_next_snaplevel", 505 scf_error()); 506 } 507 } 508 } 509 } 510 511 /* 512 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 513 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 514 * the property group named name in it. If it doesn't have a running 515 * snapshot, set pg to the instance's current property group named name. 516 * 517 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 518 * its instances. If one has a running snapshot with a service snaplevel, set 519 * pg to the property group named name in it. If no such snaplevel could be 520 * found, set pg to the service's current property group named name. 521 * 522 * iter, inst, snap, and snpl are required scratch objects. 523 * 524 * Returns 525 * 0 - success 526 * ECONNABORTED - repository connection broken 527 * ECANCELED - ent was deleted 528 * ENOENT - no such property group 529 * EINVAL - name is an invalid property group name 530 * EBADF - found running snapshot is missing a snaplevel 531 */ 532 static int 533 entity_get_running_pg(void *ent, int issvc, const char *name, 534 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 535 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 536 { 537 int r; 538 539 if (issvc) { 540 /* Search for an instance with a running snapshot. */ 541 if (scf_iter_service_instances(iter, ent) != 0) { 542 switch (scf_error()) { 543 case SCF_ERROR_DELETED: 544 case SCF_ERROR_CONNECTION_BROKEN: 545 return (scferror2errno(scf_error())); 546 547 case SCF_ERROR_NOT_SET: 548 case SCF_ERROR_NOT_BOUND: 549 case SCF_ERROR_HANDLE_MISMATCH: 550 default: 551 bad_error("scf_iter_service_instances", 552 scf_error()); 553 } 554 } 555 556 for (;;) { 557 r = scf_iter_next_instance(iter, inst); 558 if (r == 0) { 559 if (scf_service_get_pg(ent, name, pg) == 0) 560 return (0); 561 562 switch (scf_error()) { 563 case SCF_ERROR_DELETED: 564 case SCF_ERROR_NOT_FOUND: 565 case SCF_ERROR_INVALID_ARGUMENT: 566 case SCF_ERROR_CONNECTION_BROKEN: 567 return (scferror2errno(scf_error())); 568 569 case SCF_ERROR_NOT_BOUND: 570 case SCF_ERROR_HANDLE_MISMATCH: 571 case SCF_ERROR_NOT_SET: 572 default: 573 bad_error("scf_service_get_pg", 574 scf_error()); 575 } 576 } 577 if (r != 1) { 578 switch (scf_error()) { 579 case SCF_ERROR_DELETED: 580 case SCF_ERROR_CONNECTION_BROKEN: 581 return (scferror2errno(scf_error())); 582 583 case SCF_ERROR_INVALID_ARGUMENT: 584 case SCF_ERROR_NOT_SET: 585 case SCF_ERROR_NOT_BOUND: 586 case SCF_ERROR_HANDLE_MISMATCH: 587 default: 588 bad_error("scf_iter_next_instance", 589 scf_error()); 590 } 591 } 592 593 if (scf_instance_get_snapshot(inst, snap_running, 594 snap) == 0) 595 break; 596 597 switch (scf_error()) { 598 case SCF_ERROR_NOT_FOUND: 599 case SCF_ERROR_DELETED: 600 continue; 601 602 case SCF_ERROR_CONNECTION_BROKEN: 603 return (ECONNABORTED); 604 605 case SCF_ERROR_HANDLE_MISMATCH: 606 case SCF_ERROR_INVALID_ARGUMENT: 607 case SCF_ERROR_NOT_SET: 608 case SCF_ERROR_NOT_BOUND: 609 default: 610 bad_error("scf_instance_get_snapshot", 611 scf_error()); 612 } 613 } 614 } else { 615 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 616 switch (scf_error()) { 617 case SCF_ERROR_NOT_FOUND: 618 break; 619 620 case SCF_ERROR_DELETED: 621 case SCF_ERROR_CONNECTION_BROKEN: 622 return (scferror2errno(scf_error())); 623 624 case SCF_ERROR_NOT_BOUND: 625 case SCF_ERROR_HANDLE_MISMATCH: 626 case SCF_ERROR_INVALID_ARGUMENT: 627 case SCF_ERROR_NOT_SET: 628 default: 629 bad_error("scf_instance_get_snapshot", 630 scf_error()); 631 } 632 633 if (scf_instance_get_pg(ent, name, pg) == 0) 634 return (0); 635 636 switch (scf_error()) { 637 case SCF_ERROR_DELETED: 638 case SCF_ERROR_NOT_FOUND: 639 case SCF_ERROR_INVALID_ARGUMENT: 640 case SCF_ERROR_CONNECTION_BROKEN: 641 return (scferror2errno(scf_error())); 642 643 case SCF_ERROR_NOT_BOUND: 644 case SCF_ERROR_HANDLE_MISMATCH: 645 case SCF_ERROR_NOT_SET: 646 default: 647 bad_error("scf_instance_get_pg", scf_error()); 648 } 649 } 650 } 651 652 r = get_snaplevel(snap, issvc, snpl); 653 switch (r) { 654 case 0: 655 break; 656 657 case ECONNABORTED: 658 case ECANCELED: 659 return (r); 660 661 case ENOENT: 662 return (EBADF); 663 664 default: 665 bad_error("get_snaplevel", r); 666 } 667 668 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 669 return (0); 670 671 switch (scf_error()) { 672 case SCF_ERROR_DELETED: 673 case SCF_ERROR_INVALID_ARGUMENT: 674 case SCF_ERROR_CONNECTION_BROKEN: 675 case SCF_ERROR_NOT_FOUND: 676 return (scferror2errno(scf_error())); 677 678 case SCF_ERROR_NOT_BOUND: 679 case SCF_ERROR_HANDLE_MISMATCH: 680 case SCF_ERROR_NOT_SET: 681 default: 682 bad_error("scf_snaplevel_get_pg", scf_error()); 683 /* NOTREACHED */ 684 } 685 } 686 687 /* 688 * To be registered with atexit(). 689 */ 690 static void 691 remove_tempfile(void) 692 { 693 int ret; 694 695 if (tempfile != NULL) { 696 if (fclose(tempfile) == EOF) 697 (void) warn(gettext("Could not close temporary file")); 698 tempfile = NULL; 699 } 700 701 if (tempfilename[0] != '\0') { 702 do { 703 ret = remove(tempfilename); 704 } while (ret == -1 && errno == EINTR); 705 if (ret == -1) 706 warn(gettext("Could not remove temporary file")); 707 tempfilename[0] = '\0'; 708 } 709 } 710 711 /* 712 * Launch private svc.configd(1M) for manipulating alternate repositories. 713 */ 714 static void 715 start_private_repository(engine_state_t *est) 716 { 717 int fd, stat; 718 struct door_info info; 719 pid_t pid; 720 721 /* 722 * 1. Create a temporary file for the door. 723 */ 724 if (est->sc_repo_doorname != NULL) 725 free((void *)est->sc_repo_doorname); 726 727 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 728 if (est->sc_repo_doorname == NULL) 729 uu_die(gettext("Could not acquire temporary filename")); 730 731 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 732 if (fd < 0) 733 uu_die(gettext("Could not create temporary file for " 734 "repository server")); 735 736 (void) close(fd); 737 738 /* 739 * 2. Launch a configd with that door, using the specified 740 * repository. 741 */ 742 if ((est->sc_repo_pid = fork()) == 0) { 743 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 744 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 745 NULL); 746 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 747 } else if (est->sc_repo_pid == -1) 748 uu_die(gettext("Attempt to fork failed")); 749 750 do { 751 pid = waitpid(est->sc_repo_pid, &stat, 0); 752 } while (pid == -1 && errno == EINTR); 753 754 if (pid == -1) 755 uu_die(gettext("Could not waitpid() for repository server")); 756 757 if (!WIFEXITED(stat)) { 758 uu_die(gettext("Repository server failed (status %d).\n"), 759 stat); 760 } else if (WEXITSTATUS(stat) != 0) { 761 uu_die(gettext("Repository server failed (exit %d).\n"), 762 WEXITSTATUS(stat)); 763 } 764 765 /* 766 * See if it was successful by checking if the door is a door. 767 */ 768 769 fd = open(est->sc_repo_doorname, O_RDWR); 770 if (fd < 0) 771 uu_die(gettext("Could not open door \"%s\""), 772 est->sc_repo_doorname); 773 774 if (door_info(fd, &info) < 0) 775 uu_die(gettext("Unexpected door_info() error")); 776 777 if (close(fd) == -1) 778 warn(gettext("Could not close repository door"), 779 strerror(errno)); 780 781 est->sc_repo_pid = info.di_target; 782 } 783 784 void 785 lscf_cleanup(void) 786 { 787 /* 788 * In the case where we've launched a private svc.configd(1M) 789 * instance, we must terminate our child and remove the temporary 790 * rendezvous point. 791 */ 792 if (est->sc_repo_pid > 0) { 793 (void) kill(est->sc_repo_pid, SIGTERM); 794 (void) waitpid(est->sc_repo_pid, NULL, 0); 795 (void) unlink(est->sc_repo_doorname); 796 797 est->sc_repo_pid = 0; 798 } 799 } 800 801 void 802 unselect_cursnap(void) 803 { 804 void *cookie; 805 806 cur_level = NULL; 807 808 cookie = NULL; 809 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 810 scf_snaplevel_destroy(cur_elt->sl); 811 free(cur_elt); 812 } 813 814 scf_snapshot_destroy(cur_snap); 815 cur_snap = NULL; 816 } 817 818 void 819 lscf_prep_hndl(void) 820 { 821 if (g_hndl != NULL) 822 return; 823 824 g_hndl = scf_handle_create(SCF_VERSION); 825 if (g_hndl == NULL) 826 scfdie(); 827 828 if (est->sc_repo_filename != NULL) 829 start_private_repository(est); 830 831 if (est->sc_repo_doorname != NULL) { 832 scf_value_t *repo_value; 833 int ret; 834 835 repo_value = scf_value_create(g_hndl); 836 if (repo_value == NULL) 837 scfdie(); 838 839 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 840 assert(ret == SCF_SUCCESS); 841 842 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 843 SCF_SUCCESS) 844 scfdie(); 845 846 scf_value_destroy(repo_value); 847 } 848 849 if (scf_handle_bind(g_hndl) != 0) 850 uu_die(gettext("Could not connect to repository server: %s.\n"), 851 scf_strerror(scf_error())); 852 853 cur_scope = scf_scope_create(g_hndl); 854 if (cur_scope == NULL) 855 scfdie(); 856 857 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 858 scfdie(); 859 } 860 861 static void 862 repository_teardown(void) 863 { 864 if (g_hndl != NULL) { 865 if (cur_snap != NULL) 866 unselect_cursnap(); 867 scf_instance_destroy(cur_inst); 868 scf_service_destroy(cur_svc); 869 scf_scope_destroy(cur_scope); 870 scf_handle_destroy(g_hndl); 871 cur_inst = NULL; 872 cur_svc = NULL; 873 cur_scope = NULL; 874 g_hndl = NULL; 875 lscf_cleanup(); 876 } 877 } 878 879 void 880 lscf_set_repository(const char *repfile, int force) 881 { 882 repository_teardown(); 883 884 if (est->sc_repo_filename != NULL) { 885 free((void *)est->sc_repo_filename); 886 est->sc_repo_filename = NULL; 887 } 888 889 if ((force == 0) && (access(repfile, R_OK) != 0)) { 890 /* 891 * Repository file does not exist 892 * or has no read permission. 893 */ 894 warn(gettext("Cannot access \"%s\": %s\n"), 895 repfile, strerror(errno)); 896 } else { 897 est->sc_repo_filename = safe_strdup(repfile); 898 } 899 900 lscf_prep_hndl(); 901 } 902 903 void 904 lscf_init() 905 { 906 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 907 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 908 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 909 0 || 910 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 911 scfdie(); 912 913 max_scf_len = max_scf_fmri_len; 914 if (max_scf_name_len > max_scf_len) 915 max_scf_len = max_scf_name_len; 916 if (max_scf_pg_type_len > max_scf_len) 917 max_scf_len = max_scf_pg_type_len; 918 if (max_scf_value_len > max_scf_len) 919 max_scf_len = max_scf_value_len; 920 921 if (atexit(remove_tempfile) != 0) 922 uu_die(gettext("Could not register atexit() function")); 923 924 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 925 emsg_permission_denied = gettext("Permission denied.\n"); 926 emsg_create_xml = gettext("Could not create XML node.\n"); 927 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 928 emsg_read_only = gettext("Backend read-only.\n"); 929 emsg_deleted = gettext("Current selection has been deleted.\n"); 930 emsg_invalid_pg_name = 931 gettext("Invalid property group name \"%s\".\n"); 932 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 933 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 934 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 935 "with invalid name \"%s\".\n"); 936 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 937 "group with invalid name \"%s\" or type \"%s\".\n"); 938 emsg_pg_added = gettext("%s changed unexpectedly " 939 "(property group \"%s\" added).\n"); 940 emsg_pg_changed = gettext("%s changed unexpectedly " 941 "(property group \"%s\" changed).\n"); 942 emsg_pg_deleted = gettext("%s changed unexpectedly " 943 "(property group \"%s\" or an ancestor was deleted).\n"); 944 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 945 "in %s (permission denied).\n"); 946 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 947 "in %s (permission denied).\n"); 948 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 949 "in %s (permission denied).\n"); 950 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 951 "(permission denied).\n"); 952 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 953 "new dependent \"%s\" because it already exists). Warning: The " 954 "current dependent's target (%s) does not exist.\n"); 955 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 956 "dependent \"%s\" because it already exists). Warning: The " 957 "current dependent's target (%s) does not have a dependency named " 958 "\"%s\" as expected.\n"); 959 960 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 961 offsetof(string_list_t, node), NULL, 0); 962 snaplevel_pool = uu_list_pool_create("snaplevels", 963 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 964 NULL, 0); 965 } 966 967 968 static const char * 969 prop_to_typestr(const scf_property_t *prop) 970 { 971 scf_type_t ty; 972 973 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 974 scfdie(); 975 976 return (scf_type_to_string(ty)); 977 } 978 979 static scf_type_t 980 string_to_type(const char *type) 981 { 982 size_t len = strlen(type); 983 char *buf; 984 985 if (len == 0 || type[len - 1] != ':') 986 return (SCF_TYPE_INVALID); 987 988 buf = (char *)alloca(len + 1); 989 (void) strlcpy(buf, type, len + 1); 990 buf[len - 1] = 0; 991 992 return (scf_string_to_type(buf)); 993 } 994 995 static scf_value_t * 996 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 997 { 998 scf_value_t *v; 999 char *dup, *nstr; 1000 size_t len; 1001 1002 v = scf_value_create(g_hndl); 1003 if (v == NULL) 1004 scfdie(); 1005 1006 len = strlen(str); 1007 if (require_quotes && 1008 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1009 semerr(gettext("Multiple string values or string values " 1010 "with spaces must be quoted with '\"'.\n")); 1011 scf_value_destroy(v); 1012 return (NULL); 1013 } 1014 1015 nstr = dup = safe_strdup(str); 1016 if (dup[0] == '\"') { 1017 /* 1018 * Strip out the first and the last quote. 1019 */ 1020 dup[len - 1] = '\0'; 1021 nstr = dup + 1; 1022 } 1023 1024 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1025 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1026 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1027 scf_type_to_string(ty), nstr); 1028 scf_value_destroy(v); 1029 v = NULL; 1030 } 1031 free(dup); 1032 return (v); 1033 } 1034 1035 /* 1036 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1037 * Optionally append a comment prefix ('#') to newlines ('\n'). 1038 */ 1039 static int 1040 quote_and_print(const char *str, FILE *strm, int commentnl) 1041 { 1042 const char *cp; 1043 1044 for (cp = str; *cp != '\0'; ++cp) { 1045 if (*cp == '"' || *cp == '\\') 1046 (void) putc('\\', strm); 1047 1048 (void) putc(*cp, strm); 1049 1050 if (commentnl && *cp == '\n') { 1051 (void) putc('#', strm); 1052 } 1053 } 1054 1055 return (ferror(strm)); 1056 } 1057 1058 /* 1059 * These wrappers around lowlevel functions provide consistent error checking 1060 * and warnings. 1061 */ 1062 static int 1063 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1064 { 1065 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1066 return (0); 1067 1068 if (scf_error() != SCF_ERROR_NOT_FOUND) 1069 scfdie(); 1070 1071 if (g_verbose) { 1072 ssize_t len; 1073 char *fmri; 1074 1075 len = scf_pg_to_fmri(pg, NULL, 0); 1076 if (len < 0) 1077 scfdie(); 1078 1079 fmri = safe_malloc(len + 1); 1080 1081 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1082 scfdie(); 1083 1084 warn(gettext("Expected property %s of property group %s is " 1085 "missing.\n"), propname, fmri); 1086 1087 free(fmri); 1088 } 1089 1090 return (-1); 1091 } 1092 1093 static int 1094 prop_check_type(scf_property_t *prop, scf_type_t ty) 1095 { 1096 scf_type_t pty; 1097 1098 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1099 scfdie(); 1100 1101 if (ty == pty) 1102 return (0); 1103 1104 if (g_verbose) { 1105 ssize_t len; 1106 char *fmri; 1107 const char *tystr; 1108 1109 len = scf_property_to_fmri(prop, NULL, 0); 1110 if (len < 0) 1111 scfdie(); 1112 1113 fmri = safe_malloc(len + 1); 1114 1115 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1116 scfdie(); 1117 1118 tystr = scf_type_to_string(ty); 1119 if (tystr == NULL) 1120 tystr = "?"; 1121 1122 warn(gettext("Property %s is not of expected type %s.\n"), 1123 fmri, tystr); 1124 1125 free(fmri); 1126 } 1127 1128 return (-1); 1129 } 1130 1131 static int 1132 prop_get_val(scf_property_t *prop, scf_value_t *val) 1133 { 1134 scf_error_t err; 1135 1136 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1137 return (0); 1138 1139 err = scf_error(); 1140 1141 if (err != SCF_ERROR_NOT_FOUND && 1142 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1143 err != SCF_ERROR_PERMISSION_DENIED) 1144 scfdie(); 1145 1146 if (g_verbose) { 1147 ssize_t len; 1148 char *fmri, *emsg; 1149 1150 len = scf_property_to_fmri(prop, NULL, 0); 1151 if (len < 0) 1152 scfdie(); 1153 1154 fmri = safe_malloc(len + 1); 1155 1156 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1157 scfdie(); 1158 1159 if (err == SCF_ERROR_NOT_FOUND) 1160 emsg = gettext("Property %s has no values; expected " 1161 "one.\n"); 1162 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1163 emsg = gettext("Property %s has multiple values; " 1164 "expected one.\n"); 1165 else 1166 emsg = gettext("No permission to read property %s.\n"); 1167 1168 warn(emsg, fmri); 1169 1170 free(fmri); 1171 } 1172 1173 return (-1); 1174 } 1175 1176 1177 static boolean_t 1178 snaplevel_is_instance(const scf_snaplevel_t *level) 1179 { 1180 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1181 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1182 scfdie(); 1183 return (0); 1184 } else { 1185 return (1); 1186 } 1187 } 1188 1189 /* 1190 * Decode FMRI into a service or instance, and put the result in *ep. If 1191 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1192 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1193 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1194 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1195 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1196 * whether *ep is a service. 1197 */ 1198 static scf_error_t 1199 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1200 { 1201 char *fmri_copy; 1202 const char *sstr, *istr, *pgstr; 1203 scf_service_t *svc; 1204 scf_instance_t *inst; 1205 1206 fmri_copy = strdup(fmri); 1207 if (fmri_copy == NULL) 1208 return (SCF_ERROR_NO_MEMORY); 1209 1210 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1211 SCF_SUCCESS) { 1212 free(fmri_copy); 1213 return (SCF_ERROR_INVALID_ARGUMENT); 1214 } 1215 1216 free(fmri_copy); 1217 1218 if (sstr == NULL || pgstr != NULL) 1219 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1220 1221 if (istr == NULL) { 1222 svc = scf_service_create(h); 1223 if (svc == NULL) 1224 return (SCF_ERROR_NO_MEMORY); 1225 1226 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1227 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1228 if (scf_error() != SCF_ERROR_NOT_FOUND) 1229 scfdie(); 1230 1231 return (SCF_ERROR_NOT_FOUND); 1232 } 1233 1234 *ep = svc; 1235 *isservice = 1; 1236 } else { 1237 inst = scf_instance_create(h); 1238 if (inst == NULL) 1239 return (SCF_ERROR_NO_MEMORY); 1240 1241 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1242 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1243 if (scf_error() != SCF_ERROR_NOT_FOUND) 1244 scfdie(); 1245 1246 return (SCF_ERROR_NOT_FOUND); 1247 } 1248 1249 *ep = inst; 1250 *isservice = 0; 1251 } 1252 1253 return (SCF_ERROR_NONE); 1254 } 1255 1256 /* 1257 * Create the entity named by fmri. Place a pointer to its libscf handle in 1258 * *ep, and set or clear *isservicep if it is a service or an instance. 1259 * Returns 1260 * SCF_ERROR_NONE - success 1261 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1262 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1263 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1264 * SCF_ERROR_NOT_FOUND - no such scope 1265 * SCF_ERROR_PERMISSION_DENIED 1266 * SCF_ERROR_BACKEND_READONLY 1267 * SCF_ERROR_BACKEND_ACCESS 1268 */ 1269 static scf_error_t 1270 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1271 { 1272 char *fmri_copy; 1273 const char *scstr, *sstr, *istr, *pgstr; 1274 scf_scope_t *scope = NULL; 1275 scf_service_t *svc = NULL; 1276 scf_instance_t *inst = NULL; 1277 scf_error_t scfe; 1278 1279 fmri_copy = safe_strdup(fmri); 1280 1281 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1282 0) { 1283 free(fmri_copy); 1284 return (SCF_ERROR_INVALID_ARGUMENT); 1285 } 1286 1287 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1288 free(fmri_copy); 1289 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1290 } 1291 1292 *ep = NULL; 1293 1294 if ((scope = scf_scope_create(h)) == NULL || 1295 (svc = scf_service_create(h)) == NULL || 1296 (inst = scf_instance_create(h)) == NULL) { 1297 scfe = SCF_ERROR_NO_MEMORY; 1298 goto out; 1299 } 1300 1301 get_scope: 1302 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1303 switch (scf_error()) { 1304 case SCF_ERROR_CONNECTION_BROKEN: 1305 scfdie(); 1306 /* NOTREACHED */ 1307 1308 case SCF_ERROR_NOT_FOUND: 1309 scfe = SCF_ERROR_NOT_FOUND; 1310 goto out; 1311 1312 case SCF_ERROR_HANDLE_MISMATCH: 1313 case SCF_ERROR_NOT_BOUND: 1314 case SCF_ERROR_INVALID_ARGUMENT: 1315 default: 1316 bad_error("scf_handle_get_scope", scf_error()); 1317 } 1318 } 1319 1320 get_svc: 1321 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1322 switch (scf_error()) { 1323 case SCF_ERROR_CONNECTION_BROKEN: 1324 scfdie(); 1325 /* NOTREACHED */ 1326 1327 case SCF_ERROR_DELETED: 1328 goto get_scope; 1329 1330 case SCF_ERROR_NOT_FOUND: 1331 break; 1332 1333 case SCF_ERROR_HANDLE_MISMATCH: 1334 case SCF_ERROR_INVALID_ARGUMENT: 1335 case SCF_ERROR_NOT_BOUND: 1336 case SCF_ERROR_NOT_SET: 1337 default: 1338 bad_error("scf_scope_get_service", scf_error()); 1339 } 1340 1341 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1342 switch (scf_error()) { 1343 case SCF_ERROR_CONNECTION_BROKEN: 1344 scfdie(); 1345 /* NOTREACHED */ 1346 1347 case SCF_ERROR_DELETED: 1348 goto get_scope; 1349 1350 case SCF_ERROR_PERMISSION_DENIED: 1351 case SCF_ERROR_BACKEND_READONLY: 1352 case SCF_ERROR_BACKEND_ACCESS: 1353 scfe = scf_error(); 1354 goto out; 1355 1356 case SCF_ERROR_HANDLE_MISMATCH: 1357 case SCF_ERROR_INVALID_ARGUMENT: 1358 case SCF_ERROR_NOT_BOUND: 1359 case SCF_ERROR_NOT_SET: 1360 default: 1361 bad_error("scf_scope_get_service", scf_error()); 1362 } 1363 } 1364 } 1365 1366 if (istr == NULL) { 1367 scfe = SCF_ERROR_NONE; 1368 *ep = svc; 1369 *isservicep = 1; 1370 goto out; 1371 } 1372 1373 get_inst: 1374 if (scf_service_get_instance(svc, istr, inst) != 0) { 1375 switch (scf_error()) { 1376 case SCF_ERROR_CONNECTION_BROKEN: 1377 scfdie(); 1378 /* NOTREACHED */ 1379 1380 case SCF_ERROR_DELETED: 1381 goto get_svc; 1382 1383 case SCF_ERROR_NOT_FOUND: 1384 break; 1385 1386 case SCF_ERROR_HANDLE_MISMATCH: 1387 case SCF_ERROR_INVALID_ARGUMENT: 1388 case SCF_ERROR_NOT_BOUND: 1389 case SCF_ERROR_NOT_SET: 1390 default: 1391 bad_error("scf_service_get_instance", scf_error()); 1392 } 1393 1394 if (scf_service_add_instance(svc, istr, inst) != 0) { 1395 switch (scf_error()) { 1396 case SCF_ERROR_CONNECTION_BROKEN: 1397 scfdie(); 1398 /* NOTREACHED */ 1399 1400 case SCF_ERROR_DELETED: 1401 goto get_svc; 1402 1403 case SCF_ERROR_PERMISSION_DENIED: 1404 case SCF_ERROR_BACKEND_READONLY: 1405 case SCF_ERROR_BACKEND_ACCESS: 1406 scfe = scf_error(); 1407 goto out; 1408 1409 case SCF_ERROR_HANDLE_MISMATCH: 1410 case SCF_ERROR_INVALID_ARGUMENT: 1411 case SCF_ERROR_NOT_BOUND: 1412 case SCF_ERROR_NOT_SET: 1413 default: 1414 bad_error("scf_service_add_instance", 1415 scf_error()); 1416 } 1417 } 1418 } 1419 1420 scfe = SCF_ERROR_NONE; 1421 *ep = inst; 1422 *isservicep = 0; 1423 1424 out: 1425 if (*ep != inst) 1426 scf_instance_destroy(inst); 1427 if (*ep != svc) 1428 scf_service_destroy(svc); 1429 scf_scope_destroy(scope); 1430 free(fmri_copy); 1431 return (scfe); 1432 } 1433 1434 /* 1435 * Create or update a snapshot of inst. snap is a required scratch object. 1436 * 1437 * Returns 1438 * 0 - success 1439 * ECONNABORTED - repository connection broken 1440 * EPERM - permission denied 1441 * ENOSPC - configd is out of resources 1442 * ECANCELED - inst was deleted 1443 * -1 - unknown libscf error (message printed) 1444 */ 1445 static int 1446 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1447 { 1448 again: 1449 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1450 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1451 switch (scf_error()) { 1452 case SCF_ERROR_CONNECTION_BROKEN: 1453 case SCF_ERROR_PERMISSION_DENIED: 1454 case SCF_ERROR_NO_RESOURCES: 1455 return (scferror2errno(scf_error())); 1456 1457 case SCF_ERROR_NOT_SET: 1458 case SCF_ERROR_INVALID_ARGUMENT: 1459 default: 1460 bad_error("_scf_snapshot_take_attach", 1461 scf_error()); 1462 } 1463 } 1464 } else { 1465 switch (scf_error()) { 1466 case SCF_ERROR_NOT_FOUND: 1467 break; 1468 1469 case SCF_ERROR_DELETED: 1470 case SCF_ERROR_CONNECTION_BROKEN: 1471 return (scferror2errno(scf_error())); 1472 1473 case SCF_ERROR_HANDLE_MISMATCH: 1474 case SCF_ERROR_NOT_BOUND: 1475 case SCF_ERROR_INVALID_ARGUMENT: 1476 case SCF_ERROR_NOT_SET: 1477 default: 1478 bad_error("scf_instance_get_snapshot", scf_error()); 1479 } 1480 1481 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1482 switch (scf_error()) { 1483 case SCF_ERROR_EXISTS: 1484 goto again; 1485 1486 case SCF_ERROR_CONNECTION_BROKEN: 1487 case SCF_ERROR_NO_RESOURCES: 1488 case SCF_ERROR_PERMISSION_DENIED: 1489 return (scferror2errno(scf_error())); 1490 1491 default: 1492 scfwarn(); 1493 return (-1); 1494 1495 case SCF_ERROR_NOT_SET: 1496 case SCF_ERROR_INTERNAL: 1497 case SCF_ERROR_INVALID_ARGUMENT: 1498 case SCF_ERROR_HANDLE_MISMATCH: 1499 bad_error("_scf_snapshot_take_new", 1500 scf_error()); 1501 } 1502 } 1503 } 1504 1505 return (0); 1506 } 1507 1508 static int 1509 refresh_running_snapshot(void *entity) 1510 { 1511 scf_snapshot_t *snap; 1512 int r; 1513 1514 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1515 scfdie(); 1516 r = take_snap(entity, snap_running, snap); 1517 scf_snapshot_destroy(snap); 1518 1519 return (r); 1520 } 1521 1522 /* 1523 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1524 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1525 * instances. fmri is used for messages. inst, iter, and name_buf are used 1526 * for scratch space. Returns 1527 * 0 - success 1528 * ECONNABORTED - repository connection broken 1529 * ECANCELED - entity was deleted 1530 * EACCES - backend denied access 1531 * EPERM - permission denied 1532 * ENOSPC - repository server out of resources 1533 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1534 */ 1535 static int 1536 refresh_entity(int isservice, void *entity, const char *fmri, 1537 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1538 { 1539 scf_error_t scfe; 1540 int r; 1541 1542 if (!isservice) { 1543 /* 1544 * Let restarter handles refreshing and making new running 1545 * snapshot only if operating on a live repository and not 1546 * running in early import. 1547 */ 1548 if (est->sc_repo_filename == NULL && 1549 est->sc_repo_doorname == NULL && 1550 est->sc_in_emi == 0) { 1551 if (_smf_refresh_instance_i(entity) == 0) { 1552 if (g_verbose) 1553 warn(gettext("Refreshed %s.\n"), fmri); 1554 return (0); 1555 } 1556 1557 switch (scf_error()) { 1558 case SCF_ERROR_BACKEND_ACCESS: 1559 return (EACCES); 1560 1561 case SCF_ERROR_PERMISSION_DENIED: 1562 return (EPERM); 1563 1564 default: 1565 return (-1); 1566 } 1567 } else { 1568 r = refresh_running_snapshot(entity); 1569 switch (r) { 1570 case 0: 1571 break; 1572 1573 case ECONNABORTED: 1574 case ECANCELED: 1575 case EPERM: 1576 case ENOSPC: 1577 break; 1578 1579 default: 1580 bad_error("refresh_running_snapshot", 1581 scf_error()); 1582 } 1583 1584 return (r); 1585 } 1586 } 1587 1588 if (scf_iter_service_instances(iter, entity) != 0) { 1589 switch (scf_error()) { 1590 case SCF_ERROR_CONNECTION_BROKEN: 1591 return (ECONNABORTED); 1592 1593 case SCF_ERROR_DELETED: 1594 return (ECANCELED); 1595 1596 case SCF_ERROR_HANDLE_MISMATCH: 1597 case SCF_ERROR_NOT_BOUND: 1598 case SCF_ERROR_NOT_SET: 1599 default: 1600 bad_error("scf_iter_service_instances", scf_error()); 1601 } 1602 } 1603 1604 for (;;) { 1605 r = scf_iter_next_instance(iter, inst); 1606 if (r == 0) 1607 break; 1608 if (r != 1) { 1609 switch (scf_error()) { 1610 case SCF_ERROR_CONNECTION_BROKEN: 1611 return (ECONNABORTED); 1612 1613 case SCF_ERROR_DELETED: 1614 return (ECANCELED); 1615 1616 case SCF_ERROR_HANDLE_MISMATCH: 1617 case SCF_ERROR_NOT_BOUND: 1618 case SCF_ERROR_NOT_SET: 1619 case SCF_ERROR_INVALID_ARGUMENT: 1620 default: 1621 bad_error("scf_iter_next_instance", 1622 scf_error()); 1623 } 1624 } 1625 1626 /* 1627 * Similarly, just take a new running snapshot if operating on 1628 * a non-live repository or running during early import. 1629 */ 1630 if (est->sc_repo_filename != NULL || 1631 est->sc_repo_doorname != NULL || 1632 est->sc_in_emi == 1) { 1633 r = refresh_running_snapshot(inst); 1634 switch (r) { 1635 case 0: 1636 continue; 1637 1638 case ECONNABORTED: 1639 case ECANCELED: 1640 case EPERM: 1641 case ENOSPC: 1642 break; 1643 default: 1644 bad_error("refresh_running_snapshot", 1645 scf_error()); 1646 } 1647 1648 return (r); 1649 1650 } 1651 1652 if (_smf_refresh_instance_i(inst) == 0) { 1653 if (g_verbose) { 1654 if (scf_instance_get_name(inst, name_buf, 1655 max_scf_name_len + 1) < 0) 1656 (void) strcpy(name_buf, "?"); 1657 1658 warn(gettext("Refreshed %s:%s.\n"), 1659 fmri, name_buf); 1660 } 1661 } else { 1662 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1663 g_verbose) { 1664 scfe = scf_error(); 1665 1666 if (scf_instance_to_fmri(inst, name_buf, 1667 max_scf_name_len + 1) < 0) 1668 (void) strcpy(name_buf, "?"); 1669 1670 warn(gettext( 1671 "Refresh of %s:%s failed: %s.\n"), fmri, 1672 name_buf, scf_strerror(scfe)); 1673 } 1674 } 1675 } 1676 1677 return (0); 1678 } 1679 1680 static void 1681 private_refresh(void) 1682 { 1683 scf_instance_t *pinst = NULL; 1684 scf_iter_t *piter = NULL; 1685 ssize_t fmrilen; 1686 size_t bufsz; 1687 char *fmribuf; 1688 void *ent; 1689 int issvc; 1690 int r; 1691 1692 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1693 return; 1694 1695 assert(cur_svc != NULL); 1696 1697 bufsz = max_scf_fmri_len + 1; 1698 fmribuf = safe_malloc(bufsz); 1699 if (cur_inst) { 1700 issvc = 0; 1701 ent = cur_inst; 1702 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1703 } else { 1704 issvc = 1; 1705 ent = cur_svc; 1706 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1707 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1708 scfdie(); 1709 1710 if ((piter = scf_iter_create(g_hndl)) == NULL) 1711 scfdie(); 1712 } 1713 if (fmrilen < 0) { 1714 free(fmribuf); 1715 if (scf_error() != SCF_ERROR_DELETED) 1716 scfdie(); 1717 1718 warn(emsg_deleted); 1719 return; 1720 } 1721 assert(fmrilen < bufsz); 1722 1723 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1724 switch (r) { 1725 case 0: 1726 break; 1727 1728 case ECONNABORTED: 1729 warn(gettext("Could not refresh %s " 1730 "(repository connection broken).\n"), fmribuf); 1731 break; 1732 1733 case ECANCELED: 1734 warn(emsg_deleted); 1735 break; 1736 1737 case EPERM: 1738 warn(gettext("Could not refresh %s " 1739 "(permission denied).\n"), fmribuf); 1740 break; 1741 1742 case ENOSPC: 1743 warn(gettext("Could not refresh %s " 1744 "(repository server out of resources).\n"), 1745 fmribuf); 1746 break; 1747 1748 case EACCES: 1749 default: 1750 bad_error("refresh_entity", scf_error()); 1751 } 1752 1753 if (issvc) { 1754 scf_instance_destroy(pinst); 1755 scf_iter_destroy(piter); 1756 } 1757 1758 free(fmribuf); 1759 } 1760 1761 1762 static int 1763 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1764 { 1765 cbp->sc_err = scferror2errno(err); 1766 return (UU_WALK_ERROR); 1767 } 1768 1769 static int 1770 stash_scferror(scf_callback_t *cbp) 1771 { 1772 return (stash_scferror_err(cbp, scf_error())); 1773 } 1774 1775 static int select_inst(const char *); 1776 static int select_svc(const char *); 1777 1778 /* 1779 * Take a property that does not have a type and check to see if a type 1780 * exists or can be gleened from the current data. Set the type. 1781 * 1782 * Check the current level (instance) and then check the higher level 1783 * (service). This could be the case for adding a new property to 1784 * the instance that's going to "override" a service level property. 1785 * 1786 * For a property : 1787 * 1. Take the type from an existing property 1788 * 2. Take the type from a template entry 1789 * 1790 * If the type can not be found, then leave the type as is, and let the import 1791 * report the problem of the missing type. 1792 */ 1793 static int 1794 find_current_prop_type(void *p, void *g) 1795 { 1796 property_t *prop = p; 1797 scf_callback_t *lcb = g; 1798 pgroup_t *pg = NULL; 1799 1800 const char *fmri = NULL; 1801 char *lfmri = NULL; 1802 char *cur_selection = NULL; 1803 1804 scf_propertygroup_t *sc_pg = NULL; 1805 scf_property_t *sc_prop = NULL; 1806 scf_pg_tmpl_t *t_pg = NULL; 1807 scf_prop_tmpl_t *t_prop = NULL; 1808 scf_type_t prop_type; 1809 1810 value_t *vp; 1811 int issvc = lcb->sc_service; 1812 int r = UU_WALK_ERROR; 1813 1814 if (prop->sc_value_type != SCF_TYPE_INVALID) 1815 return (UU_WALK_NEXT); 1816 1817 t_prop = scf_tmpl_prop_create(g_hndl); 1818 sc_prop = scf_property_create(g_hndl); 1819 if (sc_prop == NULL || t_prop == NULL) { 1820 warn(gettext("Unable to create the property to attempt and " 1821 "find a missing type.\n")); 1822 1823 scf_property_destroy(sc_prop); 1824 scf_tmpl_prop_destroy(t_prop); 1825 1826 return (UU_WALK_ERROR); 1827 } 1828 1829 if (lcb->sc_flags == 1) { 1830 pg = lcb->sc_parent; 1831 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT); 1832 fmri = pg->sc_parent->sc_fmri; 1833 retry_pg: 1834 if (cur_svc && cur_selection == NULL) { 1835 cur_selection = safe_malloc(max_scf_fmri_len + 1); 1836 lscf_get_selection_str(cur_selection, 1837 max_scf_fmri_len + 1); 1838 1839 if (strcmp(cur_selection, fmri) != 0) { 1840 lscf_select(fmri); 1841 } else { 1842 free(cur_selection); 1843 cur_selection = NULL; 1844 } 1845 } else { 1846 lscf_select(fmri); 1847 } 1848 1849 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) { 1850 warn(gettext("Unable to create property group to " 1851 "find a missing property type.\n")); 1852 1853 goto out; 1854 } 1855 1856 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) { 1857 /* 1858 * If this is the sc_pg from the parent 1859 * let the caller clean up the sc_pg, 1860 * and just throw it away in this case. 1861 */ 1862 if (sc_pg != lcb->sc_parent) 1863 scf_pg_destroy(sc_pg); 1864 1865 sc_pg = NULL; 1866 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1867 warn(gettext("Unable to create template " 1868 "property group to find a property " 1869 "type.\n")); 1870 1871 goto out; 1872 } 1873 1874 if (scf_tmpl_get_by_pg_name(fmri, NULL, 1875 pg->sc_pgroup_name, NULL, t_pg, 1876 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) { 1877 /* 1878 * if instance get service and jump back 1879 */ 1880 scf_tmpl_pg_destroy(t_pg); 1881 t_pg = NULL; 1882 if (issvc == 0) { 1883 entity_t *e = pg->sc_parent->sc_parent; 1884 1885 fmri = e->sc_fmri; 1886 issvc = 1; 1887 goto retry_pg; 1888 } else { 1889 goto out; 1890 } 1891 } 1892 } 1893 } else { 1894 sc_pg = lcb->sc_parent; 1895 } 1896 1897 /* 1898 * Attempt to get the type from an existing property. If the property 1899 * cannot be found then attempt to get the type from a template entry 1900 * for the property. 1901 * 1902 * Finally, if at the instance level look at the service level. 1903 */ 1904 if (sc_pg != NULL && 1905 pg_get_prop(sc_pg, prop->sc_property_name, 1906 sc_prop) == SCF_SUCCESS && 1907 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) { 1908 prop->sc_value_type = prop_type; 1909 1910 /* 1911 * Found a type, update the value types and validate 1912 * the actual value against this type. 1913 */ 1914 for (vp = uu_list_first(prop->sc_property_values); 1915 vp != NULL; 1916 vp = uu_list_next(prop->sc_property_values, vp)) { 1917 vp->sc_type = prop->sc_value_type; 1918 lxml_store_value(vp, 0, NULL); 1919 } 1920 1921 r = UU_WALK_NEXT; 1922 goto out; 1923 } 1924 1925 /* 1926 * If we get here with t_pg set to NULL then we had to have 1927 * gotten an sc_pg but that sc_pg did not have the property 1928 * we are looking for. So if the t_pg is not null look up 1929 * the template entry for the property. 1930 * 1931 * If the t_pg is null then need to attempt to get a matching 1932 * template entry for the sc_pg, and see if there is a property 1933 * entry for that template entry. 1934 */ 1935 do_tmpl : 1936 if (t_pg != NULL && 1937 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name, 1938 t_prop, 0) == SCF_SUCCESS) { 1939 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) { 1940 prop->sc_value_type = prop_type; 1941 1942 /* 1943 * Found a type, update the value types and validate 1944 * the actual value against this type. 1945 */ 1946 for (vp = uu_list_first(prop->sc_property_values); 1947 vp != NULL; 1948 vp = uu_list_next(prop->sc_property_values, vp)) { 1949 vp->sc_type = prop->sc_value_type; 1950 lxml_store_value(vp, 0, NULL); 1951 } 1952 1953 r = UU_WALK_NEXT; 1954 goto out; 1955 } 1956 } else { 1957 if (t_pg == NULL && sc_pg) { 1958 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1959 warn(gettext("Unable to create template " 1960 "property group to find a property " 1961 "type.\n")); 1962 1963 goto out; 1964 } 1965 1966 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) { 1967 scf_tmpl_pg_destroy(t_pg); 1968 t_pg = NULL; 1969 } else { 1970 goto do_tmpl; 1971 } 1972 } 1973 } 1974 1975 if (issvc == 0) { 1976 scf_instance_t *i; 1977 scf_service_t *s; 1978 1979 issvc = 1; 1980 if (lcb->sc_flags == 1) { 1981 entity_t *e = pg->sc_parent->sc_parent; 1982 1983 fmri = e->sc_fmri; 1984 goto retry_pg; 1985 } 1986 1987 /* 1988 * because lcb->sc_flags was not set then this means 1989 * the pg was not used and can be used here. 1990 */ 1991 if ((pg = internal_pgroup_new()) == NULL) { 1992 warn(gettext("Could not create internal property group " 1993 "to find a missing type.")); 1994 1995 goto out; 1996 } 1997 1998 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1); 1999 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name, 2000 max_scf_name_len + 1) < 0) 2001 goto out; 2002 2003 i = scf_instance_create(g_hndl); 2004 s = scf_service_create(g_hndl); 2005 if (i == NULL || s == NULL || 2006 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) { 2007 warn(gettext("Could not get a service for the instance " 2008 "to find a missing type.")); 2009 2010 goto out; 2011 } 2012 2013 /* 2014 * Check to see truly at the instance level. 2015 */ 2016 lfmri = safe_malloc(max_scf_fmri_len + 1); 2017 if (scf_instance_get_parent(i, s) == SCF_SUCCESS && 2018 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0) 2019 goto out; 2020 else 2021 fmri = (const char *)lfmri; 2022 2023 goto retry_pg; 2024 } 2025 2026 out : 2027 if (sc_pg != lcb->sc_parent) { 2028 scf_pg_destroy(sc_pg); 2029 } 2030 2031 /* 2032 * If this is true then the pg was allocated 2033 * here, and the name was set so need to free 2034 * the name and the pg. 2035 */ 2036 if (pg != NULL && pg != lcb->sc_parent) { 2037 free((char *)pg->sc_pgroup_name); 2038 internal_pgroup_free(pg); 2039 } 2040 2041 if (cur_selection) { 2042 lscf_select(cur_selection); 2043 free(cur_selection); 2044 } 2045 2046 scf_tmpl_pg_destroy(t_pg); 2047 scf_tmpl_prop_destroy(t_prop); 2048 scf_property_destroy(sc_prop); 2049 2050 if (r != UU_WALK_NEXT) 2051 warn(gettext("Could not find property type for \"%s\" " 2052 "from \"%s\"\n"), prop->sc_property_name, 2053 fmri != NULL ? fmri : lcb->sc_source_fmri); 2054 2055 free(lfmri); 2056 2057 return (r); 2058 } 2059 2060 /* 2061 * Take a property group that does not have a type and check to see if a type 2062 * exists or can be gleened from the current data. Set the type. 2063 * 2064 * Check the current level (instance) and then check the higher level 2065 * (service). This could be the case for adding a new property to 2066 * the instance that's going to "override" a service level property. 2067 * 2068 * For a property group 2069 * 1. Take the type from an existing property group 2070 * 2. Take the type from a template entry 2071 * 2072 * If the type can not be found, then leave the type as is, and let the import 2073 * report the problem of the missing type. 2074 */ 2075 static int 2076 find_current_pg_type(void *p, void *sori) 2077 { 2078 entity_t *si = sori; 2079 pgroup_t *pg = p; 2080 2081 const char *ofmri, *fmri; 2082 char *cur_selection = NULL; 2083 char *pg_type = NULL; 2084 2085 scf_propertygroup_t *sc_pg = NULL; 2086 scf_pg_tmpl_t *t_pg = NULL; 2087 2088 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2089 int r = UU_WALK_ERROR; 2090 2091 ofmri = fmri = si->sc_fmri; 2092 if (pg->sc_pgroup_type != NULL) { 2093 r = UU_WALK_NEXT; 2094 2095 goto out; 2096 } 2097 2098 sc_pg = scf_pg_create(g_hndl); 2099 if (sc_pg == NULL) { 2100 warn(gettext("Unable to create property group to attempt " 2101 "and find a missing type.\n")); 2102 2103 return (UU_WALK_ERROR); 2104 } 2105 2106 /* 2107 * Using get_pg() requires that the cur_svc/cur_inst be 2108 * via lscf_select. Need to preserve the current selection 2109 * if going to use lscf_select() to set up the cur_svc/cur_inst 2110 */ 2111 if (cur_svc) { 2112 cur_selection = safe_malloc(max_scf_fmri_len + 1); 2113 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1); 2114 } 2115 2116 /* 2117 * If the property group exists get the type, and set 2118 * the pgroup_t type of that type. 2119 * 2120 * If not the check for a template pg_pattern entry 2121 * and take the type from that. 2122 */ 2123 retry_svc: 2124 lscf_select(fmri); 2125 2126 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) { 2127 pg_type = safe_malloc(max_scf_pg_type_len + 1); 2128 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type, 2129 max_scf_pg_type_len + 1) != -1) { 2130 pg->sc_pgroup_type = pg_type; 2131 2132 r = UU_WALK_NEXT; 2133 goto out; 2134 } else { 2135 free(pg_type); 2136 } 2137 } else { 2138 if ((t_pg == NULL) && 2139 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) 2140 goto out; 2141 2142 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name, 2143 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS && 2144 scf_tmpl_pg_type(t_pg, &pg_type) != -1) { 2145 pg->sc_pgroup_type = pg_type; 2146 2147 r = UU_WALK_NEXT; 2148 goto out; 2149 } 2150 } 2151 2152 /* 2153 * If type is not found at the instance level then attempt to 2154 * find the type at the service level. 2155 */ 2156 if (!issvc) { 2157 si = si->sc_parent; 2158 fmri = si->sc_fmri; 2159 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2160 goto retry_svc; 2161 } 2162 2163 out : 2164 if (cur_selection) { 2165 lscf_select(cur_selection); 2166 free(cur_selection); 2167 } 2168 2169 /* 2170 * Now walk the properties of the property group to make sure that 2171 * all properties have the correct type and values are valid for 2172 * those types. 2173 */ 2174 if (r == UU_WALK_NEXT) { 2175 scf_callback_t cb; 2176 2177 cb.sc_service = issvc; 2178 cb.sc_source_fmri = ofmri; 2179 if (sc_pg != NULL) { 2180 cb.sc_parent = sc_pg; 2181 cb.sc_flags = 0; 2182 } else { 2183 cb.sc_parent = pg; 2184 cb.sc_flags = 1; 2185 } 2186 2187 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type, 2188 &cb, UU_DEFAULT) != 0) { 2189 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2190 bad_error("uu_list_walk", uu_error()); 2191 2192 r = UU_WALK_ERROR; 2193 } 2194 } else { 2195 warn(gettext("Could not find property group type for " 2196 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri); 2197 } 2198 2199 scf_tmpl_pg_destroy(t_pg); 2200 scf_pg_destroy(sc_pg); 2201 2202 return (r); 2203 } 2204 2205 /* 2206 * Import. These functions import a bundle into the repository. 2207 */ 2208 2209 /* 2210 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 2211 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 2212 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2213 * lcbdata->sc_err to 2214 * ENOMEM - out of memory 2215 * ECONNABORTED - repository connection broken 2216 * ECANCELED - sc_trans's property group was deleted 2217 * EINVAL - p's name is invalid (error printed) 2218 * - p has an invalid value (error printed) 2219 */ 2220 static int 2221 lscf_property_import(void *v, void *pvt) 2222 { 2223 property_t *p = v; 2224 scf_callback_t *lcbdata = pvt; 2225 value_t *vp; 2226 scf_transaction_t *trans = lcbdata->sc_trans; 2227 scf_transaction_entry_t *entr; 2228 scf_value_t *val; 2229 scf_type_t tp; 2230 2231 if ((lcbdata->sc_flags & SCI_NOENABLED || 2232 lcbdata->sc_flags & SCI_DELAYENABLE) && 2233 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 2234 lcbdata->sc_enable = p; 2235 return (UU_WALK_NEXT); 2236 } 2237 2238 entr = scf_entry_create(lcbdata->sc_handle); 2239 if (entr == NULL) { 2240 switch (scf_error()) { 2241 case SCF_ERROR_NO_MEMORY: 2242 return (stash_scferror(lcbdata)); 2243 2244 case SCF_ERROR_INVALID_ARGUMENT: 2245 default: 2246 bad_error("scf_entry_create", scf_error()); 2247 } 2248 } 2249 2250 tp = p->sc_value_type; 2251 2252 if (scf_transaction_property_new(trans, entr, 2253 p->sc_property_name, tp) != 0) { 2254 switch (scf_error()) { 2255 case SCF_ERROR_INVALID_ARGUMENT: 2256 semerr(emsg_invalid_prop_name, p->sc_property_name); 2257 scf_entry_destroy(entr); 2258 return (stash_scferror(lcbdata)); 2259 2260 case SCF_ERROR_EXISTS: 2261 break; 2262 2263 case SCF_ERROR_DELETED: 2264 case SCF_ERROR_CONNECTION_BROKEN: 2265 scf_entry_destroy(entr); 2266 return (stash_scferror(lcbdata)); 2267 2268 case SCF_ERROR_NOT_BOUND: 2269 case SCF_ERROR_HANDLE_MISMATCH: 2270 case SCF_ERROR_NOT_SET: 2271 default: 2272 bad_error("scf_transaction_property_new", scf_error()); 2273 } 2274 2275 if (scf_transaction_property_change_type(trans, entr, 2276 p->sc_property_name, tp) != 0) { 2277 switch (scf_error()) { 2278 case SCF_ERROR_DELETED: 2279 case SCF_ERROR_CONNECTION_BROKEN: 2280 scf_entry_destroy(entr); 2281 return (stash_scferror(lcbdata)); 2282 2283 case SCF_ERROR_INVALID_ARGUMENT: 2284 semerr(emsg_invalid_prop_name, 2285 p->sc_property_name); 2286 scf_entry_destroy(entr); 2287 return (stash_scferror(lcbdata)); 2288 2289 case SCF_ERROR_NOT_FOUND: 2290 case SCF_ERROR_NOT_SET: 2291 case SCF_ERROR_HANDLE_MISMATCH: 2292 case SCF_ERROR_NOT_BOUND: 2293 default: 2294 bad_error( 2295 "scf_transaction_property_change_type", 2296 scf_error()); 2297 } 2298 } 2299 } 2300 2301 for (vp = uu_list_first(p->sc_property_values); 2302 vp != NULL; 2303 vp = uu_list_next(p->sc_property_values, vp)) { 2304 val = scf_value_create(g_hndl); 2305 if (val == NULL) { 2306 switch (scf_error()) { 2307 case SCF_ERROR_NO_MEMORY: 2308 return (stash_scferror(lcbdata)); 2309 2310 case SCF_ERROR_INVALID_ARGUMENT: 2311 default: 2312 bad_error("scf_value_create", scf_error()); 2313 } 2314 } 2315 2316 switch (tp) { 2317 case SCF_TYPE_BOOLEAN: 2318 scf_value_set_boolean(val, vp->sc_u.sc_count); 2319 break; 2320 case SCF_TYPE_COUNT: 2321 scf_value_set_count(val, vp->sc_u.sc_count); 2322 break; 2323 case SCF_TYPE_INTEGER: 2324 scf_value_set_integer(val, vp->sc_u.sc_integer); 2325 break; 2326 default: 2327 assert(vp->sc_u.sc_string != NULL); 2328 if (scf_value_set_from_string(val, tp, 2329 vp->sc_u.sc_string) != 0) { 2330 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 2331 bad_error("scf_value_set_from_string", 2332 scf_error()); 2333 2334 warn(gettext("Value \"%s\" is not a valid " 2335 "%s.\n"), vp->sc_u.sc_string, 2336 scf_type_to_string(tp)); 2337 scf_value_destroy(val); 2338 return (stash_scferror(lcbdata)); 2339 } 2340 break; 2341 } 2342 2343 if (scf_entry_add_value(entr, val) != 0) 2344 bad_error("scf_entry_add_value", scf_error()); 2345 } 2346 2347 return (UU_WALK_NEXT); 2348 } 2349 2350 /* 2351 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 2352 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 2353 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 2354 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2355 * lcbdata->sc_err to 2356 * ECONNABORTED - repository connection broken 2357 * ENOMEM - out of memory 2358 * ENOSPC - svc.configd is out of resources 2359 * ECANCELED - sc_parent was deleted 2360 * EPERM - could not create property group (permission denied) (error printed) 2361 * - could not modify property group (permission denied) (error printed) 2362 * - could not delete property group (permission denied) (error printed) 2363 * EROFS - could not create property group (repository is read-only) 2364 * - could not delete property group (repository is read-only) 2365 * EACCES - could not create property group (backend access denied) 2366 * - could not delete property group (backend access denied) 2367 * EEXIST - could not create property group (already exists) 2368 * EINVAL - invalid property group name (error printed) 2369 * - invalid property name (error printed) 2370 * - invalid value (error printed) 2371 * EBUSY - new property group deleted (error printed) 2372 * - new property group changed (error printed) 2373 * - property group added (error printed) 2374 * - property group deleted (error printed) 2375 */ 2376 static int 2377 entity_pgroup_import(void *v, void *pvt) 2378 { 2379 pgroup_t *p = v; 2380 scf_callback_t cbdata; 2381 scf_callback_t *lcbdata = pvt; 2382 void *ent = lcbdata->sc_parent; 2383 int issvc = lcbdata->sc_service; 2384 int r; 2385 2386 const char * const pg_changed = gettext("%s changed unexpectedly " 2387 "(new property group \"%s\" changed).\n"); 2388 2389 /* Never import deleted property groups. */ 2390 if (p->sc_pgroup_delete) { 2391 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY && 2392 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) { 2393 goto delete_pg; 2394 } 2395 return (UU_WALK_NEXT); 2396 } 2397 2398 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 2399 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 2400 lcbdata->sc_general = p; 2401 return (UU_WALK_NEXT); 2402 } 2403 2404 add_pg: 2405 if (issvc) 2406 r = scf_service_add_pg(ent, p->sc_pgroup_name, 2407 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2408 else 2409 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 2410 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2411 if (r != 0) { 2412 switch (scf_error()) { 2413 case SCF_ERROR_DELETED: 2414 case SCF_ERROR_CONNECTION_BROKEN: 2415 case SCF_ERROR_BACKEND_READONLY: 2416 case SCF_ERROR_BACKEND_ACCESS: 2417 case SCF_ERROR_NO_RESOURCES: 2418 return (stash_scferror(lcbdata)); 2419 2420 case SCF_ERROR_EXISTS: 2421 if (lcbdata->sc_flags & SCI_FORCE) 2422 break; 2423 return (stash_scferror(lcbdata)); 2424 2425 case SCF_ERROR_INVALID_ARGUMENT: 2426 warn(emsg_fmri_invalid_pg_name_type, 2427 lcbdata->sc_source_fmri, 2428 p->sc_pgroup_name, p->sc_pgroup_type); 2429 return (stash_scferror(lcbdata)); 2430 2431 case SCF_ERROR_PERMISSION_DENIED: 2432 warn(emsg_pg_add_perm, p->sc_pgroup_name, 2433 lcbdata->sc_target_fmri); 2434 return (stash_scferror(lcbdata)); 2435 2436 case SCF_ERROR_NOT_BOUND: 2437 case SCF_ERROR_HANDLE_MISMATCH: 2438 case SCF_ERROR_NOT_SET: 2439 default: 2440 bad_error("scf_service_add_pg", scf_error()); 2441 } 2442 2443 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2444 switch (scf_error()) { 2445 case SCF_ERROR_CONNECTION_BROKEN: 2446 case SCF_ERROR_DELETED: 2447 return (stash_scferror(lcbdata)); 2448 2449 case SCF_ERROR_INVALID_ARGUMENT: 2450 warn(emsg_fmri_invalid_pg_name, 2451 lcbdata->sc_source_fmri, 2452 p->sc_pgroup_name); 2453 return (stash_scferror(lcbdata)); 2454 2455 case SCF_ERROR_NOT_FOUND: 2456 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2457 p->sc_pgroup_name); 2458 lcbdata->sc_err = EBUSY; 2459 return (UU_WALK_ERROR); 2460 2461 case SCF_ERROR_NOT_BOUND: 2462 case SCF_ERROR_HANDLE_MISMATCH: 2463 case SCF_ERROR_NOT_SET: 2464 default: 2465 bad_error("entity_get_pg", scf_error()); 2466 } 2467 } 2468 2469 if (lcbdata->sc_flags & SCI_KEEP) 2470 goto props; 2471 2472 delete_pg: 2473 if (scf_pg_delete(imp_pg) != 0) { 2474 switch (scf_error()) { 2475 case SCF_ERROR_DELETED: 2476 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2477 p->sc_pgroup_name); 2478 lcbdata->sc_err = EBUSY; 2479 return (UU_WALK_ERROR); 2480 2481 case SCF_ERROR_PERMISSION_DENIED: 2482 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2483 lcbdata->sc_target_fmri); 2484 return (stash_scferror(lcbdata)); 2485 2486 case SCF_ERROR_BACKEND_READONLY: 2487 case SCF_ERROR_BACKEND_ACCESS: 2488 case SCF_ERROR_CONNECTION_BROKEN: 2489 return (stash_scferror(lcbdata)); 2490 2491 case SCF_ERROR_NOT_SET: 2492 default: 2493 bad_error("scf_pg_delete", scf_error()); 2494 } 2495 } 2496 2497 if (p->sc_pgroup_delete) 2498 return (UU_WALK_NEXT); 2499 2500 goto add_pg; 2501 } 2502 2503 props: 2504 2505 /* 2506 * Add properties to property group, if any. 2507 */ 2508 cbdata.sc_handle = lcbdata->sc_handle; 2509 cbdata.sc_parent = imp_pg; 2510 cbdata.sc_flags = lcbdata->sc_flags; 2511 cbdata.sc_trans = imp_tx; 2512 cbdata.sc_enable = NULL; 2513 2514 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2515 switch (scf_error()) { 2516 case SCF_ERROR_BACKEND_ACCESS: 2517 case SCF_ERROR_BACKEND_READONLY: 2518 case SCF_ERROR_CONNECTION_BROKEN: 2519 return (stash_scferror(lcbdata)); 2520 2521 case SCF_ERROR_DELETED: 2522 warn(pg_changed, lcbdata->sc_target_fmri, 2523 p->sc_pgroup_name); 2524 lcbdata->sc_err = EBUSY; 2525 return (UU_WALK_ERROR); 2526 2527 case SCF_ERROR_PERMISSION_DENIED: 2528 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2529 lcbdata->sc_target_fmri); 2530 return (stash_scferror(lcbdata)); 2531 2532 case SCF_ERROR_NOT_BOUND: 2533 case SCF_ERROR_NOT_SET: 2534 case SCF_ERROR_IN_USE: 2535 case SCF_ERROR_HANDLE_MISMATCH: 2536 default: 2537 bad_error("scf_transaction_start", scf_error()); 2538 } 2539 } 2540 2541 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2542 UU_DEFAULT) != 0) { 2543 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2544 bad_error("uu_list_walk", uu_error()); 2545 scf_transaction_reset(imp_tx); 2546 2547 lcbdata->sc_err = cbdata.sc_err; 2548 if (cbdata.sc_err == ECANCELED) { 2549 warn(pg_changed, lcbdata->sc_target_fmri, 2550 p->sc_pgroup_name); 2551 lcbdata->sc_err = EBUSY; 2552 } 2553 return (UU_WALK_ERROR); 2554 } 2555 2556 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2557 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2558 2559 /* 2560 * take the snapshot running snapshot then 2561 * import the stored general/enable property 2562 */ 2563 r = take_snap(ent, snap_running, imp_rsnap); 2564 switch (r) { 2565 case 0: 2566 break; 2567 2568 case ECONNABORTED: 2569 warn(gettext("Could not take %s snapshot on import " 2570 "(repository connection broken).\n"), 2571 snap_running); 2572 lcbdata->sc_err = r; 2573 return (UU_WALK_ERROR); 2574 case ECANCELED: 2575 warn(emsg_deleted); 2576 lcbdata->sc_err = r; 2577 return (UU_WALK_ERROR); 2578 2579 case EPERM: 2580 warn(gettext("Could not take %s snapshot " 2581 "(permission denied).\n"), snap_running); 2582 lcbdata->sc_err = r; 2583 return (UU_WALK_ERROR); 2584 2585 case ENOSPC: 2586 warn(gettext("Could not take %s snapshot" 2587 "(repository server out of resources).\n"), 2588 snap_running); 2589 lcbdata->sc_err = r; 2590 return (UU_WALK_ERROR); 2591 2592 default: 2593 bad_error("take_snap", r); 2594 } 2595 2596 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2597 if (r != UU_WALK_NEXT) { 2598 if (r != UU_WALK_ERROR) 2599 bad_error("lscf_property_import", r); 2600 return (EINVAL); 2601 } 2602 } 2603 2604 r = scf_transaction_commit(imp_tx); 2605 switch (r) { 2606 case 1: 2607 r = UU_WALK_NEXT; 2608 break; 2609 2610 case 0: 2611 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2612 lcbdata->sc_err = EBUSY; 2613 r = UU_WALK_ERROR; 2614 break; 2615 2616 case -1: 2617 switch (scf_error()) { 2618 case SCF_ERROR_BACKEND_READONLY: 2619 case SCF_ERROR_BACKEND_ACCESS: 2620 case SCF_ERROR_CONNECTION_BROKEN: 2621 case SCF_ERROR_NO_RESOURCES: 2622 r = stash_scferror(lcbdata); 2623 break; 2624 2625 case SCF_ERROR_DELETED: 2626 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2627 p->sc_pgroup_name); 2628 lcbdata->sc_err = EBUSY; 2629 r = UU_WALK_ERROR; 2630 break; 2631 2632 case SCF_ERROR_PERMISSION_DENIED: 2633 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2634 lcbdata->sc_target_fmri); 2635 r = stash_scferror(lcbdata); 2636 break; 2637 2638 case SCF_ERROR_NOT_SET: 2639 case SCF_ERROR_INVALID_ARGUMENT: 2640 case SCF_ERROR_NOT_BOUND: 2641 default: 2642 bad_error("scf_transaction_commit", scf_error()); 2643 } 2644 break; 2645 2646 default: 2647 bad_error("scf_transaction_commit", r); 2648 } 2649 2650 scf_transaction_destroy_children(imp_tx); 2651 2652 return (r); 2653 } 2654 2655 /* 2656 * Returns 2657 * 0 - success 2658 * ECONNABORTED - repository connection broken 2659 * ENOMEM - out of memory 2660 * ENOSPC - svc.configd is out of resources 2661 * ECANCELED - inst was deleted 2662 * EPERM - could not create property group (permission denied) (error printed) 2663 * - could not modify property group (permission denied) (error printed) 2664 * EROFS - could not create property group (repository is read-only) 2665 * EACCES - could not create property group (backend access denied) 2666 * EEXIST - could not create property group (already exists) 2667 * EINVAL - invalid property group name (error printed) 2668 * - invalid property name (error printed) 2669 * - invalid value (error printed) 2670 * EBUSY - new property group changed (error printed) 2671 */ 2672 static int 2673 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2674 const entity_t *isvc, int flags) 2675 { 2676 scf_callback_t cbdata; 2677 2678 cbdata.sc_handle = scf_service_handle(svc); 2679 cbdata.sc_parent = svc; 2680 cbdata.sc_service = 1; 2681 cbdata.sc_general = 0; 2682 cbdata.sc_enable = 0; 2683 cbdata.sc_flags = flags; 2684 cbdata.sc_source_fmri = isvc->sc_fmri; 2685 cbdata.sc_target_fmri = target_fmri; 2686 2687 /* 2688 * If the op is set, then add the flag to the callback 2689 * flags for later use. 2690 */ 2691 if (isvc->sc_op != SVCCFG_OP_NONE) { 2692 switch (isvc->sc_op) { 2693 case SVCCFG_OP_IMPORT : 2694 cbdata.sc_flags |= SCI_OP_IMPORT; 2695 break; 2696 case SVCCFG_OP_APPLY : 2697 cbdata.sc_flags |= SCI_OP_APPLY; 2698 break; 2699 case SVCCFG_OP_RESTORE : 2700 cbdata.sc_flags |= SCI_OP_RESTORE; 2701 break; 2702 default : 2703 uu_die(gettext("lscf_import_service_pgs : " 2704 "Unknown op stored in the service entity\n")); 2705 2706 } 2707 } 2708 2709 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2710 UU_DEFAULT) != 0) { 2711 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2712 bad_error("uu_list_walk", uu_error()); 2713 2714 return (cbdata.sc_err); 2715 } 2716 2717 return (0); 2718 } 2719 2720 /* 2721 * Returns 2722 * 0 - success 2723 * ECONNABORTED - repository connection broken 2724 * ENOMEM - out of memory 2725 * ENOSPC - svc.configd is out of resources 2726 * ECANCELED - inst was deleted 2727 * EPERM - could not create property group (permission denied) (error printed) 2728 * - could not modify property group (permission denied) (error printed) 2729 * EROFS - could not create property group (repository is read-only) 2730 * EACCES - could not create property group (backend access denied) 2731 * EEXIST - could not create property group (already exists) 2732 * EINVAL - invalid property group name (error printed) 2733 * - invalid property name (error printed) 2734 * - invalid value (error printed) 2735 * EBUSY - new property group changed (error printed) 2736 */ 2737 static int 2738 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2739 const entity_t *iinst, int flags) 2740 { 2741 scf_callback_t cbdata; 2742 2743 cbdata.sc_handle = scf_instance_handle(inst); 2744 cbdata.sc_parent = inst; 2745 cbdata.sc_service = 0; 2746 cbdata.sc_general = NULL; 2747 cbdata.sc_enable = NULL; 2748 cbdata.sc_flags = flags; 2749 cbdata.sc_source_fmri = iinst->sc_fmri; 2750 cbdata.sc_target_fmri = target_fmri; 2751 2752 /* 2753 * If the op is set, then add the flag to the callback 2754 * flags for later use. 2755 */ 2756 if (iinst->sc_op != SVCCFG_OP_NONE) { 2757 switch (iinst->sc_op) { 2758 case SVCCFG_OP_IMPORT : 2759 cbdata.sc_flags |= SCI_OP_IMPORT; 2760 break; 2761 case SVCCFG_OP_APPLY : 2762 cbdata.sc_flags |= SCI_OP_APPLY; 2763 break; 2764 case SVCCFG_OP_RESTORE : 2765 cbdata.sc_flags |= SCI_OP_RESTORE; 2766 break; 2767 default : 2768 uu_die(gettext("lscf_import_instance_pgs : " 2769 "Unknown op stored in the instance entity\n")); 2770 } 2771 } 2772 2773 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2774 UU_DEFAULT) != 0) { 2775 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2776 bad_error("uu_list_walk", uu_error()); 2777 2778 return (cbdata.sc_err); 2779 } 2780 2781 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2782 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2783 /* 2784 * If importing with the SCI_NOENABLED flag then 2785 * skip the delay, but if not then add the delay 2786 * of the enable property. 2787 */ 2788 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2789 cbdata.sc_flags |= SCI_DELAYENABLE; 2790 } 2791 2792 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2793 != UU_WALK_NEXT) 2794 return (cbdata.sc_err); 2795 } 2796 2797 return (0); 2798 } 2799 2800 /* 2801 * Report the reasons why we can't upgrade pg2 to pg1. 2802 */ 2803 static void 2804 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2805 int new) 2806 { 2807 property_t *p1, *p2; 2808 2809 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2810 2811 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2812 return; 2813 2814 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2815 p1 != NULL; 2816 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2817 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2818 if (p2 != NULL) { 2819 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2820 new); 2821 continue; 2822 } 2823 2824 if (new) 2825 warn(gettext("Conflict upgrading %s (new property " 2826 "group \"%s\" is missing property \"%s\").\n"), 2827 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2828 else 2829 warn(gettext("Conflict upgrading %s (property " 2830 "\"%s/%s\" is missing).\n"), fmri, 2831 pg1->sc_pgroup_name, p1->sc_property_name); 2832 } 2833 2834 /* 2835 * Since pg1 should be from the manifest, any properties in pg2 which 2836 * aren't in pg1 shouldn't be reported as conflicts. 2837 */ 2838 } 2839 2840 /* 2841 * Add transaction entries to tx which will upgrade cur's pg according to old 2842 * & new. 2843 * 2844 * Returns 2845 * 0 - success 2846 * EINVAL - new has a property with an invalid name or value (message emitted) 2847 * ENOMEM - out of memory 2848 */ 2849 static int 2850 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2851 pgroup_t *cur, int speak, const char *fmri) 2852 { 2853 property_t *p, *new_p, *cur_p; 2854 scf_transaction_entry_t *e; 2855 int r; 2856 int is_general; 2857 int is_protected; 2858 2859 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2860 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2861 bad_error("uu_list_walk", uu_error()); 2862 2863 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2864 2865 for (p = uu_list_first(old->sc_pgroup_props); 2866 p != NULL; 2867 p = uu_list_next(old->sc_pgroup_props, p)) { 2868 /* p is a property in the old property group. */ 2869 2870 /* Protect live properties. */ 2871 is_protected = 0; 2872 if (is_general) { 2873 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2874 0 || 2875 strcmp(p->sc_property_name, 2876 SCF_PROPERTY_RESTARTER) == 0) 2877 is_protected = 1; 2878 } 2879 2880 /* Look for the same property in the new properties. */ 2881 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2882 if (new_p != NULL) { 2883 new_p->sc_seen = 1; 2884 2885 /* 2886 * If the new property is the same as the old, don't do 2887 * anything (leave any user customizations). 2888 */ 2889 if (prop_equal(p, new_p, NULL, NULL, 0)) 2890 continue; 2891 2892 if (new_p->sc_property_override) 2893 goto upgrade; 2894 } 2895 2896 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2897 if (cur_p == NULL) { 2898 /* 2899 * p has been deleted from the repository. If we were 2900 * going to delete it anyway, do nothing. Otherwise 2901 * report a conflict. 2902 */ 2903 if (new_p == NULL) 2904 continue; 2905 2906 if (is_protected) 2907 continue; 2908 2909 warn(gettext("Conflict upgrading %s " 2910 "(property \"%s/%s\" is missing).\n"), fmri, 2911 old->sc_pgroup_name, p->sc_property_name); 2912 continue; 2913 } 2914 2915 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2916 /* 2917 * Conflict. Don't warn if the property is already the 2918 * way we want it, though. 2919 */ 2920 if (is_protected) 2921 continue; 2922 2923 if (new_p == NULL) 2924 (void) prop_equal(p, cur_p, fmri, 2925 old->sc_pgroup_name, 0); 2926 else 2927 (void) prop_equal(cur_p, new_p, fmri, 2928 old->sc_pgroup_name, 0); 2929 continue; 2930 } 2931 2932 if (is_protected) { 2933 if (speak) 2934 warn(gettext("%s: Refusing to upgrade " 2935 "\"%s/%s\" (live property).\n"), fmri, 2936 old->sc_pgroup_name, p->sc_property_name); 2937 continue; 2938 } 2939 2940 upgrade: 2941 /* p hasn't been customized in the repository. Upgrade it. */ 2942 if (new_p == NULL) { 2943 /* p was deleted. Delete from cur if unchanged. */ 2944 if (speak) 2945 warn(gettext( 2946 "%s: Deleting property \"%s/%s\".\n"), 2947 fmri, old->sc_pgroup_name, 2948 p->sc_property_name); 2949 2950 e = scf_entry_create(g_hndl); 2951 if (e == NULL) 2952 return (ENOMEM); 2953 2954 if (scf_transaction_property_delete(tx, e, 2955 p->sc_property_name) != 0) { 2956 switch (scf_error()) { 2957 case SCF_ERROR_DELETED: 2958 scf_entry_destroy(e); 2959 return (ECANCELED); 2960 2961 case SCF_ERROR_CONNECTION_BROKEN: 2962 scf_entry_destroy(e); 2963 return (ECONNABORTED); 2964 2965 case SCF_ERROR_NOT_FOUND: 2966 /* 2967 * This can happen if cur is from the 2968 * running snapshot (and it differs 2969 * from the live properties). 2970 */ 2971 scf_entry_destroy(e); 2972 break; 2973 2974 case SCF_ERROR_HANDLE_MISMATCH: 2975 case SCF_ERROR_NOT_BOUND: 2976 case SCF_ERROR_NOT_SET: 2977 case SCF_ERROR_INVALID_ARGUMENT: 2978 default: 2979 bad_error( 2980 "scf_transaction_property_delete", 2981 scf_error()); 2982 } 2983 } 2984 } else { 2985 scf_callback_t ctx; 2986 2987 if (speak) 2988 warn(gettext( 2989 "%s: Upgrading property \"%s/%s\".\n"), 2990 fmri, old->sc_pgroup_name, 2991 p->sc_property_name); 2992 2993 ctx.sc_handle = g_hndl; 2994 ctx.sc_trans = tx; 2995 ctx.sc_flags = 0; 2996 2997 r = lscf_property_import(new_p, &ctx); 2998 if (r != UU_WALK_NEXT) { 2999 if (r != UU_WALK_ERROR) 3000 bad_error("lscf_property_import", r); 3001 return (EINVAL); 3002 } 3003 } 3004 } 3005 3006 /* Go over the properties which were added. */ 3007 for (new_p = uu_list_first(new->sc_pgroup_props); 3008 new_p != NULL; 3009 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 3010 if (new_p->sc_seen) 3011 continue; 3012 3013 /* This is a new property. */ 3014 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 3015 if (cur_p == NULL) { 3016 scf_callback_t ctx; 3017 3018 ctx.sc_handle = g_hndl; 3019 ctx.sc_trans = tx; 3020 ctx.sc_flags = 0; 3021 3022 r = lscf_property_import(new_p, &ctx); 3023 if (r != UU_WALK_NEXT) { 3024 if (r != UU_WALK_ERROR) 3025 bad_error("lscf_property_import", r); 3026 return (EINVAL); 3027 } 3028 continue; 3029 } 3030 3031 /* 3032 * Report a conflict if the new property differs from the 3033 * current one. Unless it's general/enabled, since that's 3034 * never in the last-import snapshot. 3035 */ 3036 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 3037 0 && 3038 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 3039 continue; 3040 3041 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 3042 } 3043 3044 return (0); 3045 } 3046 3047 /* 3048 * Upgrade pg according to old & new. 3049 * 3050 * Returns 3051 * 0 - success 3052 * ECONNABORTED - repository connection broken 3053 * ENOMEM - out of memory 3054 * ENOSPC - svc.configd is out of resources 3055 * ECANCELED - pg was deleted 3056 * EPERM - couldn't modify pg (permission denied) 3057 * EROFS - couldn't modify pg (backend read-only) 3058 * EACCES - couldn't modify pg (backend access denied) 3059 * EINVAL - new has a property with invalid name or value (error printed) 3060 * EBUSY - pg changed unexpectedly 3061 */ 3062 static int 3063 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 3064 pgroup_t *new, int speak, const char *fmri) 3065 { 3066 int r; 3067 3068 if (scf_transaction_start(imp_tx, pg) != 0) { 3069 switch (scf_error()) { 3070 case SCF_ERROR_CONNECTION_BROKEN: 3071 case SCF_ERROR_DELETED: 3072 case SCF_ERROR_PERMISSION_DENIED: 3073 case SCF_ERROR_BACKEND_READONLY: 3074 case SCF_ERROR_BACKEND_ACCESS: 3075 return (scferror2errno(scf_error())); 3076 3077 case SCF_ERROR_HANDLE_MISMATCH: 3078 case SCF_ERROR_IN_USE: 3079 case SCF_ERROR_NOT_BOUND: 3080 case SCF_ERROR_NOT_SET: 3081 default: 3082 bad_error("scf_transaction_start", scf_error()); 3083 } 3084 } 3085 3086 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 3087 switch (r) { 3088 case 0: 3089 break; 3090 3091 case EINVAL: 3092 case ENOMEM: 3093 scf_transaction_destroy_children(imp_tx); 3094 return (r); 3095 3096 default: 3097 bad_error("add_upgrade_entries", r); 3098 } 3099 3100 r = scf_transaction_commit(imp_tx); 3101 3102 scf_transaction_destroy_children(imp_tx); 3103 3104 switch (r) { 3105 case 1: 3106 break; 3107 3108 case 0: 3109 return (EBUSY); 3110 3111 case -1: 3112 switch (scf_error()) { 3113 case SCF_ERROR_CONNECTION_BROKEN: 3114 case SCF_ERROR_NO_RESOURCES: 3115 case SCF_ERROR_PERMISSION_DENIED: 3116 case SCF_ERROR_BACKEND_READONLY: 3117 case SCF_ERROR_BACKEND_ACCESS: 3118 case SCF_ERROR_DELETED: 3119 return (scferror2errno(scf_error())); 3120 3121 case SCF_ERROR_NOT_BOUND: 3122 case SCF_ERROR_INVALID_ARGUMENT: 3123 case SCF_ERROR_NOT_SET: 3124 default: 3125 bad_error("scf_transaction_commit", scf_error()); 3126 } 3127 3128 default: 3129 bad_error("scf_transaction_commit", r); 3130 } 3131 3132 return (0); 3133 } 3134 3135 /* 3136 * Compares two entity FMRIs. Returns 3137 * 3138 * 1 - equal 3139 * 0 - not equal 3140 * -1 - f1 is invalid or not an entity 3141 * -2 - f2 is invalid or not an entity 3142 */ 3143 static int 3144 fmri_equal(const char *f1, const char *f2) 3145 { 3146 int r; 3147 const char *s1, *i1, *pg1; 3148 const char *s2, *i2, *pg2; 3149 3150 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3151 return (-1); 3152 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 3153 return (-1); 3154 3155 if (s1 == NULL || pg1 != NULL) 3156 return (-1); 3157 3158 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3159 return (-2); 3160 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 3161 return (-2); 3162 3163 if (s2 == NULL || pg2 != NULL) 3164 return (-2); 3165 3166 r = strcmp(s1, s2); 3167 if (r != 0) 3168 return (0); 3169 3170 if (i1 == NULL && i2 == NULL) 3171 return (1); 3172 3173 if (i1 == NULL || i2 == NULL) 3174 return (0); 3175 3176 return (strcmp(i1, i2) == 0); 3177 } 3178 3179 /* 3180 * Import a dependent by creating a dependency property group in the dependent 3181 * entity. If lcbdata->sc_trans is set, assume it's been started on the 3182 * dependents pg, and add an entry to create a new property for this 3183 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 3184 * 3185 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 3186 * lcbdata->sc_err to 3187 * ECONNABORTED - repository connection broken 3188 * ENOMEM - out of memory 3189 * ENOSPC - configd is out of resources 3190 * EINVAL - target is invalid (error printed) 3191 * - target is not an entity (error printed) 3192 * - dependent has invalid name (error printed) 3193 * - invalid property name (error printed) 3194 * - invalid value (error printed) 3195 * - scope of target does not exist (error printed) 3196 * EPERM - couldn't create target (permission denied) (error printed) 3197 * - couldn't create dependency pg (permission denied) (error printed) 3198 * - couldn't modify dependency pg (permission denied) (error printed) 3199 * EROFS - couldn't create target (repository read-only) 3200 * - couldn't create dependency pg (repository read-only) 3201 * EACCES - couldn't create target (backend access denied) 3202 * - couldn't create dependency pg (backend access denied) 3203 * ECANCELED - sc_trans's pg was deleted 3204 * EALREADY - property for dependent already exists in sc_trans's pg 3205 * EEXIST - dependency pg already exists in target (error printed) 3206 * EBUSY - target deleted (error printed) 3207 * - property group changed during import (error printed) 3208 */ 3209 static int 3210 lscf_dependent_import(void *a1, void *pvt) 3211 { 3212 pgroup_t *pgrp = a1; 3213 scf_callback_t *lcbdata = pvt; 3214 3215 int isservice; 3216 int ret; 3217 scf_transaction_entry_t *e; 3218 scf_value_t *val; 3219 scf_callback_t dependent_cbdata; 3220 scf_error_t scfe; 3221 3222 /* 3223 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 3224 * it's invalid, we fail before modifying the repository. 3225 */ 3226 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3227 &dependent_cbdata.sc_parent, &isservice); 3228 switch (scfe) { 3229 case SCF_ERROR_NONE: 3230 break; 3231 3232 case SCF_ERROR_NO_MEMORY: 3233 return (stash_scferror_err(lcbdata, scfe)); 3234 3235 case SCF_ERROR_INVALID_ARGUMENT: 3236 semerr(gettext("The FMRI for the \"%s\" dependent is " 3237 "invalid.\n"), pgrp->sc_pgroup_name); 3238 return (stash_scferror_err(lcbdata, scfe)); 3239 3240 case SCF_ERROR_CONSTRAINT_VIOLATED: 3241 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 3242 "specifies neither a service nor an instance.\n"), 3243 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3244 return (stash_scferror_err(lcbdata, scfe)); 3245 3246 case SCF_ERROR_NOT_FOUND: 3247 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3248 &dependent_cbdata.sc_parent, &isservice); 3249 switch (scfe) { 3250 case SCF_ERROR_NONE: 3251 break; 3252 3253 case SCF_ERROR_NO_MEMORY: 3254 case SCF_ERROR_BACKEND_READONLY: 3255 case SCF_ERROR_BACKEND_ACCESS: 3256 return (stash_scferror_err(lcbdata, scfe)); 3257 3258 case SCF_ERROR_NOT_FOUND: 3259 semerr(gettext("The scope in FMRI \"%s\" for the " 3260 "\"%s\" dependent does not exist.\n"), 3261 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3262 lcbdata->sc_err = EINVAL; 3263 return (UU_WALK_ERROR); 3264 3265 case SCF_ERROR_PERMISSION_DENIED: 3266 warn(gettext( 3267 "Could not create %s (permission denied).\n"), 3268 pgrp->sc_pgroup_fmri); 3269 return (stash_scferror_err(lcbdata, scfe)); 3270 3271 case SCF_ERROR_INVALID_ARGUMENT: 3272 case SCF_ERROR_CONSTRAINT_VIOLATED: 3273 default: 3274 bad_error("create_entity", scfe); 3275 } 3276 break; 3277 3278 default: 3279 bad_error("fmri_to_entity", scfe); 3280 } 3281 3282 if (lcbdata->sc_trans != NULL) { 3283 e = scf_entry_create(lcbdata->sc_handle); 3284 if (e == NULL) { 3285 if (scf_error() != SCF_ERROR_NO_MEMORY) 3286 bad_error("scf_entry_create", scf_error()); 3287 3288 entity_destroy(dependent_cbdata.sc_parent, isservice); 3289 return (stash_scferror(lcbdata)); 3290 } 3291 3292 if (scf_transaction_property_new(lcbdata->sc_trans, e, 3293 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 3294 switch (scf_error()) { 3295 case SCF_ERROR_INVALID_ARGUMENT: 3296 warn(gettext("Dependent of %s has invalid name " 3297 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 3298 pgrp->sc_pgroup_name); 3299 /* FALLTHROUGH */ 3300 3301 case SCF_ERROR_DELETED: 3302 case SCF_ERROR_CONNECTION_BROKEN: 3303 scf_entry_destroy(e); 3304 entity_destroy(dependent_cbdata.sc_parent, 3305 isservice); 3306 return (stash_scferror(lcbdata)); 3307 3308 case SCF_ERROR_EXISTS: 3309 scf_entry_destroy(e); 3310 entity_destroy(dependent_cbdata.sc_parent, 3311 isservice); 3312 lcbdata->sc_err = EALREADY; 3313 return (UU_WALK_ERROR); 3314 3315 case SCF_ERROR_NOT_BOUND: 3316 case SCF_ERROR_HANDLE_MISMATCH: 3317 case SCF_ERROR_NOT_SET: 3318 default: 3319 bad_error("scf_transaction_property_new", 3320 scf_error()); 3321 } 3322 } 3323 3324 val = scf_value_create(lcbdata->sc_handle); 3325 if (val == NULL) { 3326 if (scf_error() != SCF_ERROR_NO_MEMORY) 3327 bad_error("scf_value_create", scf_error()); 3328 3329 entity_destroy(dependent_cbdata.sc_parent, isservice); 3330 return (stash_scferror(lcbdata)); 3331 } 3332 3333 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3334 pgrp->sc_pgroup_fmri) != 0) 3335 /* invalid should have been caught above */ 3336 bad_error("scf_value_set_from_string", scf_error()); 3337 3338 if (scf_entry_add_value(e, val) != 0) 3339 bad_error("scf_entry_add_value", scf_error()); 3340 } 3341 3342 /* Add the property group to the target entity. */ 3343 3344 dependent_cbdata.sc_handle = lcbdata->sc_handle; 3345 dependent_cbdata.sc_flags = lcbdata->sc_flags; 3346 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 3347 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 3348 3349 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 3350 3351 entity_destroy(dependent_cbdata.sc_parent, isservice); 3352 3353 if (ret == UU_WALK_NEXT) 3354 return (ret); 3355 3356 if (ret != UU_WALK_ERROR) 3357 bad_error("entity_pgroup_import", ret); 3358 3359 switch (dependent_cbdata.sc_err) { 3360 case ECANCELED: 3361 warn(gettext("%s deleted unexpectedly.\n"), 3362 pgrp->sc_pgroup_fmri); 3363 lcbdata->sc_err = EBUSY; 3364 break; 3365 3366 case EEXIST: 3367 warn(gettext("Could not create \"%s\" dependency in %s " 3368 "(already exists).\n"), pgrp->sc_pgroup_name, 3369 pgrp->sc_pgroup_fmri); 3370 /* FALLTHROUGH */ 3371 3372 default: 3373 lcbdata->sc_err = dependent_cbdata.sc_err; 3374 } 3375 3376 return (UU_WALK_ERROR); 3377 } 3378 3379 static int upgrade_dependent(const scf_property_t *, const entity_t *, 3380 const scf_snaplevel_t *, scf_transaction_t *); 3381 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 3382 const pgroup_t *); 3383 3384 /* 3385 * Upgrade uncustomized dependents of ent to those specified in ient. Read 3386 * the current dependent targets from running (the snaplevel of a running 3387 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 3388 * scf_instance_t * according to ient, otherwise). Draw the ancestral 3389 * dependent targets and dependency properties from li_dpts_pg (the 3390 * "dependents" property group in snpl) and snpl (the snaplevel which 3391 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 3392 * snpl doesn't have a "dependents" property group, and any dependents in ient 3393 * are new. 3394 * 3395 * Returns 3396 * 0 - success 3397 * ECONNABORTED - repository connection broken 3398 * ENOMEM - out of memory 3399 * ENOSPC - configd is out of resources 3400 * ECANCELED - ent was deleted 3401 * ENODEV - the entity containing li_dpts_pg was deleted 3402 * EPERM - could not modify dependents pg (permission denied) (error printed) 3403 * - couldn't upgrade dependent (permission denied) (error printed) 3404 * - couldn't create dependent (permission denied) (error printed) 3405 * EROFS - could not modify dependents pg (repository read-only) 3406 * - couldn't upgrade dependent (repository read-only) 3407 * - couldn't create dependent (repository read-only) 3408 * EACCES - could not modify dependents pg (backend access denied) 3409 * - could not upgrade dependent (backend access denied) 3410 * - could not create dependent (backend access denied) 3411 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 3412 * - dependent target deleted (error printed) 3413 * - dependent pg changed (error printed) 3414 * EINVAL - new dependent is invalid (error printed) 3415 * EBADF - snpl is corrupt (error printed) 3416 * - snpl has corrupt pg (error printed) 3417 * - dependency pg in target is corrupt (error printed) 3418 * - target has corrupt snapshot (error printed) 3419 * EEXIST - dependency pg already existed in target service (error printed) 3420 */ 3421 static int 3422 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 3423 const scf_snaplevel_t *snpl, const entity_t *ient, 3424 const scf_snaplevel_t *running, void *ent) 3425 { 3426 pgroup_t *new_dpt_pgroup; 3427 scf_callback_t cbdata; 3428 int r, unseen, tx_started = 0; 3429 int have_cur_depts; 3430 3431 const char * const dependents = "dependents"; 3432 3433 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3434 3435 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 3436 /* Nothing to do. */ 3437 return (0); 3438 3439 /* Fetch the current version of the "dependents" property group. */ 3440 have_cur_depts = 1; 3441 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 3442 switch (scf_error()) { 3443 case SCF_ERROR_NOT_FOUND: 3444 break; 3445 3446 case SCF_ERROR_DELETED: 3447 case SCF_ERROR_CONNECTION_BROKEN: 3448 return (scferror2errno(scf_error())); 3449 3450 case SCF_ERROR_NOT_SET: 3451 case SCF_ERROR_INVALID_ARGUMENT: 3452 case SCF_ERROR_HANDLE_MISMATCH: 3453 case SCF_ERROR_NOT_BOUND: 3454 default: 3455 bad_error("entity_get_pg", scf_error()); 3456 } 3457 3458 have_cur_depts = 0; 3459 } 3460 3461 /* Fetch the running version of the "dependents" property group. */ 3462 ud_run_dpts_pg_set = 0; 3463 if (running != NULL) 3464 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 3465 else 3466 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 3467 if (r == 0) { 3468 ud_run_dpts_pg_set = 1; 3469 } else { 3470 switch (scf_error()) { 3471 case SCF_ERROR_NOT_FOUND: 3472 break; 3473 3474 case SCF_ERROR_DELETED: 3475 case SCF_ERROR_CONNECTION_BROKEN: 3476 return (scferror2errno(scf_error())); 3477 3478 case SCF_ERROR_NOT_SET: 3479 case SCF_ERROR_INVALID_ARGUMENT: 3480 case SCF_ERROR_HANDLE_MISMATCH: 3481 case SCF_ERROR_NOT_BOUND: 3482 default: 3483 bad_error(running ? "scf_snaplevel_get_pg" : 3484 "entity_get_pg", scf_error()); 3485 } 3486 } 3487 3488 /* 3489 * Clear the seen fields of the dependents, so we can tell which ones 3490 * are new. 3491 */ 3492 if (uu_list_walk(ient->sc_dependents, clear_int, 3493 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3494 bad_error("uu_list_walk", uu_error()); 3495 3496 if (li_dpts_pg != NULL) { 3497 /* 3498 * Each property in li_dpts_pg represents a dependent tag in 3499 * the old manifest. For each, call upgrade_dependent(), 3500 * which will change ud_cur_depts_pg or dependencies in other 3501 * services as appropriate. Note (a) that changes to 3502 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3503 * made en masse, and (b) it's ok if the entity doesn't have 3504 * a current version of the "dependents" property group, 3505 * because we'll just consider all dependents as customized 3506 * (by being deleted). 3507 */ 3508 3509 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3510 switch (scf_error()) { 3511 case SCF_ERROR_DELETED: 3512 return (ENODEV); 3513 3514 case SCF_ERROR_CONNECTION_BROKEN: 3515 return (ECONNABORTED); 3516 3517 case SCF_ERROR_HANDLE_MISMATCH: 3518 case SCF_ERROR_NOT_BOUND: 3519 case SCF_ERROR_NOT_SET: 3520 default: 3521 bad_error("scf_iter_pg_properties", 3522 scf_error()); 3523 } 3524 } 3525 3526 if (have_cur_depts && 3527 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3528 switch (scf_error()) { 3529 case SCF_ERROR_BACKEND_ACCESS: 3530 case SCF_ERROR_BACKEND_READONLY: 3531 case SCF_ERROR_CONNECTION_BROKEN: 3532 return (scferror2errno(scf_error())); 3533 3534 case SCF_ERROR_DELETED: 3535 warn(emsg_pg_deleted, ient->sc_fmri, 3536 dependents); 3537 return (EBUSY); 3538 3539 case SCF_ERROR_PERMISSION_DENIED: 3540 warn(emsg_pg_mod_perm, dependents, 3541 ient->sc_fmri); 3542 return (scferror2errno(scf_error())); 3543 3544 case SCF_ERROR_HANDLE_MISMATCH: 3545 case SCF_ERROR_IN_USE: 3546 case SCF_ERROR_NOT_BOUND: 3547 case SCF_ERROR_NOT_SET: 3548 default: 3549 bad_error("scf_transaction_start", scf_error()); 3550 } 3551 } 3552 tx_started = have_cur_depts; 3553 3554 for (;;) { 3555 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3556 if (r == 0) 3557 break; 3558 if (r == 1) { 3559 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3560 tx_started ? ud_tx : NULL); 3561 switch (r) { 3562 case 0: 3563 continue; 3564 3565 case ECONNABORTED: 3566 case ENOMEM: 3567 case ENOSPC: 3568 case EBADF: 3569 case EBUSY: 3570 case EINVAL: 3571 case EPERM: 3572 case EROFS: 3573 case EACCES: 3574 case EEXIST: 3575 break; 3576 3577 case ECANCELED: 3578 r = ENODEV; 3579 break; 3580 3581 default: 3582 bad_error("upgrade_dependent", r); 3583 } 3584 3585 if (tx_started) 3586 scf_transaction_destroy_children(ud_tx); 3587 return (r); 3588 } 3589 if (r != -1) 3590 bad_error("scf_iter_next_property", r); 3591 3592 switch (scf_error()) { 3593 case SCF_ERROR_DELETED: 3594 r = ENODEV; 3595 break; 3596 3597 case SCF_ERROR_CONNECTION_BROKEN: 3598 r = ECONNABORTED; 3599 break; 3600 3601 case SCF_ERROR_NOT_SET: 3602 case SCF_ERROR_INVALID_ARGUMENT: 3603 case SCF_ERROR_NOT_BOUND: 3604 case SCF_ERROR_HANDLE_MISMATCH: 3605 default: 3606 bad_error("scf_iter_next_property", 3607 scf_error()); 3608 } 3609 3610 if (tx_started) 3611 scf_transaction_destroy_children(ud_tx); 3612 return (r); 3613 } 3614 } 3615 3616 /* import unseen dependents */ 3617 unseen = 0; 3618 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3619 new_dpt_pgroup != NULL; 3620 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3621 new_dpt_pgroup)) { 3622 if (!new_dpt_pgroup->sc_pgroup_seen) { 3623 unseen = 1; 3624 break; 3625 } 3626 } 3627 3628 /* If there are none, exit early. */ 3629 if (unseen == 0) 3630 goto commit; 3631 3632 /* Set up for lscf_dependent_import() */ 3633 cbdata.sc_handle = g_hndl; 3634 cbdata.sc_parent = ent; 3635 cbdata.sc_service = issvc; 3636 cbdata.sc_flags = 0; 3637 3638 if (!have_cur_depts) { 3639 /* 3640 * We have new dependents to import, so we need a "dependents" 3641 * property group. 3642 */ 3643 if (issvc) 3644 r = scf_service_add_pg(ent, dependents, 3645 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3646 else 3647 r = scf_instance_add_pg(ent, dependents, 3648 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3649 if (r != 0) { 3650 switch (scf_error()) { 3651 case SCF_ERROR_DELETED: 3652 case SCF_ERROR_CONNECTION_BROKEN: 3653 case SCF_ERROR_BACKEND_READONLY: 3654 case SCF_ERROR_BACKEND_ACCESS: 3655 case SCF_ERROR_NO_RESOURCES: 3656 return (scferror2errno(scf_error())); 3657 3658 case SCF_ERROR_EXISTS: 3659 warn(emsg_pg_added, ient->sc_fmri, dependents); 3660 return (EBUSY); 3661 3662 case SCF_ERROR_PERMISSION_DENIED: 3663 warn(emsg_pg_add_perm, dependents, 3664 ient->sc_fmri); 3665 return (scferror2errno(scf_error())); 3666 3667 case SCF_ERROR_NOT_BOUND: 3668 case SCF_ERROR_HANDLE_MISMATCH: 3669 case SCF_ERROR_INVALID_ARGUMENT: 3670 case SCF_ERROR_NOT_SET: 3671 default: 3672 bad_error("scf_service_add_pg", scf_error()); 3673 } 3674 } 3675 } 3676 3677 cbdata.sc_trans = ud_tx; 3678 3679 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3680 switch (scf_error()) { 3681 case SCF_ERROR_CONNECTION_BROKEN: 3682 case SCF_ERROR_BACKEND_ACCESS: 3683 case SCF_ERROR_BACKEND_READONLY: 3684 return (scferror2errno(scf_error())); 3685 3686 case SCF_ERROR_DELETED: 3687 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3688 return (EBUSY); 3689 3690 case SCF_ERROR_PERMISSION_DENIED: 3691 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3692 return (scferror2errno(scf_error())); 3693 3694 case SCF_ERROR_HANDLE_MISMATCH: 3695 case SCF_ERROR_IN_USE: 3696 case SCF_ERROR_NOT_BOUND: 3697 case SCF_ERROR_NOT_SET: 3698 default: 3699 bad_error("scf_transaction_start", scf_error()); 3700 } 3701 } 3702 tx_started = 1; 3703 3704 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3705 new_dpt_pgroup != NULL; 3706 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3707 new_dpt_pgroup)) { 3708 if (new_dpt_pgroup->sc_pgroup_seen) 3709 continue; 3710 3711 if (ud_run_dpts_pg_set) { 3712 /* 3713 * If the dependent is already there, then we have 3714 * a conflict. 3715 */ 3716 if (scf_pg_get_property(ud_run_dpts_pg, 3717 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3718 r = handle_dependent_conflict(ient, ud_prop, 3719 new_dpt_pgroup); 3720 switch (r) { 3721 case 0: 3722 continue; 3723 3724 case ECONNABORTED: 3725 case ENOMEM: 3726 case EBUSY: 3727 case EBADF: 3728 case EINVAL: 3729 scf_transaction_destroy_children(ud_tx); 3730 return (r); 3731 3732 default: 3733 bad_error("handle_dependent_conflict", 3734 r); 3735 } 3736 } else { 3737 switch (scf_error()) { 3738 case SCF_ERROR_NOT_FOUND: 3739 break; 3740 3741 case SCF_ERROR_INVALID_ARGUMENT: 3742 warn(emsg_fmri_invalid_pg_name, 3743 ient->sc_fmri, 3744 new_dpt_pgroup->sc_pgroup_name); 3745 scf_transaction_destroy_children(ud_tx); 3746 return (EINVAL); 3747 3748 case SCF_ERROR_DELETED: 3749 warn(emsg_pg_deleted, ient->sc_fmri, 3750 new_dpt_pgroup->sc_pgroup_name); 3751 scf_transaction_destroy_children(ud_tx); 3752 return (EBUSY); 3753 3754 case SCF_ERROR_CONNECTION_BROKEN: 3755 scf_transaction_destroy_children(ud_tx); 3756 return (ECONNABORTED); 3757 3758 case SCF_ERROR_NOT_BOUND: 3759 case SCF_ERROR_HANDLE_MISMATCH: 3760 case SCF_ERROR_NOT_SET: 3761 default: 3762 bad_error("scf_pg_get_property", 3763 scf_error()); 3764 } 3765 } 3766 } 3767 3768 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3769 if (r != UU_WALK_NEXT) { 3770 if (r != UU_WALK_ERROR) 3771 bad_error("lscf_dependent_import", r); 3772 3773 if (cbdata.sc_err == EALREADY) { 3774 /* Collisions were handled preemptively. */ 3775 bad_error("lscf_dependent_import", 3776 cbdata.sc_err); 3777 } 3778 3779 scf_transaction_destroy_children(ud_tx); 3780 return (cbdata.sc_err); 3781 } 3782 } 3783 3784 commit: 3785 if (!tx_started) 3786 return (0); 3787 3788 r = scf_transaction_commit(ud_tx); 3789 3790 scf_transaction_destroy_children(ud_tx); 3791 3792 switch (r) { 3793 case 1: 3794 return (0); 3795 3796 case 0: 3797 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3798 return (EBUSY); 3799 3800 case -1: 3801 break; 3802 3803 default: 3804 bad_error("scf_transaction_commit", r); 3805 } 3806 3807 switch (scf_error()) { 3808 case SCF_ERROR_CONNECTION_BROKEN: 3809 case SCF_ERROR_BACKEND_READONLY: 3810 case SCF_ERROR_BACKEND_ACCESS: 3811 case SCF_ERROR_NO_RESOURCES: 3812 return (scferror2errno(scf_error())); 3813 3814 case SCF_ERROR_DELETED: 3815 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3816 return (EBUSY); 3817 3818 case SCF_ERROR_PERMISSION_DENIED: 3819 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3820 return (scferror2errno(scf_error())); 3821 3822 case SCF_ERROR_NOT_BOUND: 3823 case SCF_ERROR_INVALID_ARGUMENT: 3824 case SCF_ERROR_NOT_SET: 3825 default: 3826 bad_error("scf_transaction_destroy", scf_error()); 3827 /* NOTREACHED */ 3828 } 3829 } 3830 3831 /* 3832 * Used to add the manifests to the list of currently supported manifests. 3833 * We can modify the existing manifest list removing entries if the files 3834 * don't exist. 3835 * 3836 * Get the old list and the new file name 3837 * If the new file name is in the list return 3838 * If not then add the file to the list. 3839 * As we process the list check to see if the files in the old list exist 3840 * if not then remove the file from the list. 3841 * Commit the list of manifest file names. 3842 * 3843 */ 3844 static int 3845 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient, 3846 const scf_snaplevel_t *running, void *ent) 3847 { 3848 scf_propertygroup_t *ud_mfsts_pg = NULL; 3849 scf_property_t *ud_prop = NULL; 3850 scf_iter_t *ud_prop_iter; 3851 scf_value_t *fname_value; 3852 scf_callback_t cbdata; 3853 pgroup_t *mfst_pgroup; 3854 property_t *mfst_prop; 3855 property_t *old_prop; 3856 char *pname = malloc(MAXPATHLEN); 3857 char *fval = NULL; 3858 char *old_pname; 3859 char *old_fval; 3860 int no_upgrade_pg; 3861 int mfst_seen; 3862 int r; 3863 3864 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3865 3866 /* 3867 * This should always be the service base on the code 3868 * path, and the fact that the manifests pg is a service 3869 * level property group only. 3870 */ 3871 ud_mfsts_pg = scf_pg_create(g_hndl); 3872 ud_prop = scf_property_create(g_hndl); 3873 ud_prop_iter = scf_iter_create(g_hndl); 3874 fname_value = scf_value_create(g_hndl); 3875 3876 /* Fetch the "manifests" property group */ 3877 no_upgrade_pg = 0; 3878 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3879 ud_mfsts_pg); 3880 if (r != 0) { 3881 switch (scf_error()) { 3882 case SCF_ERROR_NOT_FOUND: 3883 no_upgrade_pg = 1; 3884 break; 3885 3886 case SCF_ERROR_DELETED: 3887 case SCF_ERROR_CONNECTION_BROKEN: 3888 return (scferror2errno(scf_error())); 3889 3890 case SCF_ERROR_NOT_SET: 3891 case SCF_ERROR_INVALID_ARGUMENT: 3892 case SCF_ERROR_HANDLE_MISMATCH: 3893 case SCF_ERROR_NOT_BOUND: 3894 default: 3895 bad_error(running ? "scf_snaplevel_get_pg" : 3896 "entity_get_pg", scf_error()); 3897 } 3898 } 3899 3900 if (no_upgrade_pg) { 3901 cbdata.sc_handle = g_hndl; 3902 cbdata.sc_parent = ent; 3903 cbdata.sc_service = issvc; 3904 cbdata.sc_flags = SCI_FORCE; 3905 cbdata.sc_source_fmri = ient->sc_fmri; 3906 cbdata.sc_target_fmri = ient->sc_fmri; 3907 3908 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3909 return (cbdata.sc_err); 3910 3911 return (0); 3912 } 3913 3914 /* Fetch the new manifests property group */ 3915 for (mfst_pgroup = uu_list_first(ient->sc_pgroups); 3916 mfst_pgroup != NULL; 3917 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) { 3918 if (strcmp(mfst_pgroup->sc_pgroup_name, 3919 SCF_PG_MANIFESTFILES) == 0) 3920 break; 3921 } 3922 3923 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3924 SCF_SUCCESS) 3925 return (-1); 3926 3927 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 3928 mfst_seen = 0; 3929 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 3930 continue; 3931 3932 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3933 mfst_prop != NULL; 3934 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3935 mfst_prop)) { 3936 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3937 mfst_seen = 1; 3938 } 3939 } 3940 3941 /* 3942 * If the manifest is not seen then add it to the new mfst 3943 * property list to get proccessed into the repo. 3944 */ 3945 if (mfst_seen == 0) { 3946 if (fval == NULL) 3947 fval = malloc(MAXPATHLEN); 3948 3949 /* 3950 * If we cannot get the value then there is no 3951 * reason to attempt to attach the value to 3952 * the property group 3953 */ 3954 if (fval != NULL && 3955 prop_get_val(ud_prop, fname_value) == 0 && 3956 scf_value_get_astring(fname_value, fval, 3957 MAXPATHLEN) != -1) { 3958 old_pname = safe_strdup(pname); 3959 old_fval = safe_strdup(fval); 3960 old_prop = internal_property_create(old_pname, 3961 SCF_TYPE_ASTRING, 1, old_fval); 3962 3963 /* 3964 * Already checked to see if the property exists 3965 * in the group, and it does not. 3966 */ 3967 (void) internal_attach_property(mfst_pgroup, 3968 old_prop); 3969 } 3970 } 3971 } 3972 free(fval); 3973 3974 cbdata.sc_handle = g_hndl; 3975 cbdata.sc_parent = ent; 3976 cbdata.sc_service = issvc; 3977 cbdata.sc_flags = SCI_FORCE; 3978 cbdata.sc_source_fmri = ient->sc_fmri; 3979 cbdata.sc_target_fmri = ient->sc_fmri; 3980 3981 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 3982 return (cbdata.sc_err); 3983 3984 return (r); 3985 } 3986 3987 /* 3988 * prop is taken to be a property in the "dependents" property group of snpl, 3989 * which is taken to be the snaplevel of a last-import snapshot corresponding 3990 * to ient. If prop is a valid dependents property, upgrade the dependent it 3991 * represents according to the repository & ient. If ud_run_dpts_pg_set is 3992 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 3993 * of the entity ient represents (possibly in the running snapshot). If it 3994 * needs to be changed, an entry will be added to tx, if not NULL. 3995 * 3996 * Returns 3997 * 0 - success 3998 * ECONNABORTED - repository connection broken 3999 * ENOMEM - out of memory 4000 * ENOSPC - configd was out of resources 4001 * ECANCELED - snpl's entity was deleted 4002 * EINVAL - dependent target is invalid (error printed) 4003 * - dependent is invalid (error printed) 4004 * EBADF - snpl is corrupt (error printed) 4005 * - snpl has corrupt pg (error printed) 4006 * - dependency pg in target is corrupt (error printed) 4007 * - running snapshot in dependent is missing snaplevel (error printed) 4008 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 4009 * - couldn't create dependent (permission denied) (error printed) 4010 * - couldn't modify dependent pg (permission denied) (error printed) 4011 * EROFS - couldn't delete dependency pg (repository read-only) 4012 * - couldn't create dependent (repository read-only) 4013 * EACCES - couldn't delete dependency pg (backend access denied) 4014 * - couldn't create dependent (backend access denied) 4015 * EBUSY - ud_run_dpts_pg was deleted (error printed) 4016 * - tx's pg was deleted (error printed) 4017 * - dependent pg was changed or deleted (error printed) 4018 * EEXIST - dependency pg already exists in new target (error printed) 4019 */ 4020 static int 4021 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 4022 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 4023 { 4024 pgroup_t pgrp; 4025 scf_type_t ty; 4026 pgroup_t *new_dpt_pgroup; 4027 pgroup_t *old_dpt_pgroup = NULL; 4028 pgroup_t *current_pg; 4029 pgroup_t *dpt; 4030 scf_callback_t cbdata; 4031 int tissvc; 4032 void *target_ent; 4033 scf_error_t serr; 4034 int r; 4035 scf_transaction_entry_t *ent; 4036 4037 const char * const cf_inval = gettext("Conflict upgrading %s " 4038 "(dependent \"%s\" has invalid dependents property).\n"); 4039 const char * const cf_missing = gettext("Conflict upgrading %s " 4040 "(dependent \"%s\" is missing).\n"); 4041 const char * const cf_newdpg = gettext("Conflict upgrading %s " 4042 "(dependent \"%s\" has new dependency property group).\n"); 4043 const char * const cf_newtarg = gettext("Conflict upgrading %s " 4044 "(dependent \"%s\" has new target).\n"); 4045 const char * const li_corrupt = 4046 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 4047 const char * const upgrading = 4048 gettext("%s: Upgrading dependent \"%s\".\n"); 4049 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 4050 "corrupt (missing snaplevel).\n"); 4051 4052 if (scf_property_type(prop, &ty) != 0) { 4053 switch (scf_error()) { 4054 case SCF_ERROR_DELETED: 4055 case SCF_ERROR_CONNECTION_BROKEN: 4056 return (scferror2errno(scf_error())); 4057 4058 case SCF_ERROR_NOT_BOUND: 4059 case SCF_ERROR_NOT_SET: 4060 default: 4061 bad_error("scf_property_type", scf_error()); 4062 } 4063 } 4064 4065 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4066 warn(li_corrupt, ient->sc_fmri); 4067 return (EBADF); 4068 } 4069 4070 /* 4071 * prop represents a dependent in the old manifest. It is named after 4072 * the dependent. 4073 */ 4074 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 4075 switch (scf_error()) { 4076 case SCF_ERROR_DELETED: 4077 case SCF_ERROR_CONNECTION_BROKEN: 4078 return (scferror2errno(scf_error())); 4079 4080 case SCF_ERROR_NOT_BOUND: 4081 case SCF_ERROR_NOT_SET: 4082 default: 4083 bad_error("scf_property_get_name", scf_error()); 4084 } 4085 } 4086 4087 /* See if it's in the new manifest. */ 4088 pgrp.sc_pgroup_name = ud_name; 4089 new_dpt_pgroup = 4090 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 4091 4092 /* If it's not, delete it... if it hasn't been customized. */ 4093 if (new_dpt_pgroup == NULL) { 4094 if (!ud_run_dpts_pg_set) 4095 return (0); 4096 4097 if (scf_property_get_value(prop, ud_val) != 0) { 4098 switch (scf_error()) { 4099 case SCF_ERROR_NOT_FOUND: 4100 case SCF_ERROR_CONSTRAINT_VIOLATED: 4101 warn(li_corrupt, ient->sc_fmri); 4102 return (EBADF); 4103 4104 case SCF_ERROR_DELETED: 4105 case SCF_ERROR_CONNECTION_BROKEN: 4106 return (scferror2errno(scf_error())); 4107 4108 case SCF_ERROR_HANDLE_MISMATCH: 4109 case SCF_ERROR_NOT_BOUND: 4110 case SCF_ERROR_NOT_SET: 4111 case SCF_ERROR_PERMISSION_DENIED: 4112 default: 4113 bad_error("scf_property_get_value", 4114 scf_error()); 4115 } 4116 } 4117 4118 if (scf_value_get_as_string(ud_val, ud_oldtarg, 4119 max_scf_value_len + 1) < 0) 4120 bad_error("scf_value_get_as_string", scf_error()); 4121 4122 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 4123 0) { 4124 switch (scf_error()) { 4125 case SCF_ERROR_NOT_FOUND: 4126 return (0); 4127 4128 case SCF_ERROR_CONNECTION_BROKEN: 4129 return (scferror2errno(scf_error())); 4130 4131 case SCF_ERROR_DELETED: 4132 warn(emsg_pg_deleted, ient->sc_fmri, 4133 "dependents"); 4134 return (EBUSY); 4135 4136 case SCF_ERROR_INVALID_ARGUMENT: 4137 case SCF_ERROR_NOT_BOUND: 4138 case SCF_ERROR_HANDLE_MISMATCH: 4139 case SCF_ERROR_NOT_SET: 4140 default: 4141 bad_error("scf_pg_get_property", scf_error()); 4142 } 4143 } 4144 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4145 switch (scf_error()) { 4146 case SCF_ERROR_NOT_FOUND: 4147 case SCF_ERROR_CONSTRAINT_VIOLATED: 4148 warn(cf_inval, ient->sc_fmri, ud_name); 4149 return (0); 4150 4151 case SCF_ERROR_DELETED: 4152 case SCF_ERROR_CONNECTION_BROKEN: 4153 return (scferror2errno(scf_error())); 4154 4155 case SCF_ERROR_HANDLE_MISMATCH: 4156 case SCF_ERROR_NOT_BOUND: 4157 case SCF_ERROR_NOT_SET: 4158 case SCF_ERROR_PERMISSION_DENIED: 4159 default: 4160 bad_error("scf_property_get_value", 4161 scf_error()); 4162 } 4163 } 4164 4165 ty = scf_value_type(ud_val); 4166 assert(ty != SCF_TYPE_INVALID); 4167 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4168 warn(cf_inval, ient->sc_fmri, ud_name); 4169 return (0); 4170 } 4171 4172 if (scf_value_get_as_string(ud_val, ud_ctarg, 4173 max_scf_value_len + 1) < 0) 4174 bad_error("scf_value_get_as_string", scf_error()); 4175 4176 r = fmri_equal(ud_ctarg, ud_oldtarg); 4177 switch (r) { 4178 case 1: 4179 break; 4180 4181 case 0: 4182 case -1: /* warn? */ 4183 warn(cf_newtarg, ient->sc_fmri, ud_name); 4184 return (0); 4185 4186 case -2: 4187 warn(li_corrupt, ient->sc_fmri); 4188 return (EBADF); 4189 4190 default: 4191 bad_error("fmri_equal", r); 4192 } 4193 4194 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4195 switch (scf_error()) { 4196 case SCF_ERROR_NOT_FOUND: 4197 warn(li_corrupt, ient->sc_fmri); 4198 return (EBADF); 4199 4200 case SCF_ERROR_DELETED: 4201 case SCF_ERROR_CONNECTION_BROKEN: 4202 return (scferror2errno(scf_error())); 4203 4204 case SCF_ERROR_NOT_BOUND: 4205 case SCF_ERROR_HANDLE_MISMATCH: 4206 case SCF_ERROR_INVALID_ARGUMENT: 4207 case SCF_ERROR_NOT_SET: 4208 default: 4209 bad_error("scf_snaplevel_get_pg", scf_error()); 4210 } 4211 } 4212 4213 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4214 snap_lastimport); 4215 switch (r) { 4216 case 0: 4217 break; 4218 4219 case ECANCELED: 4220 case ECONNABORTED: 4221 case ENOMEM: 4222 case EBADF: 4223 return (r); 4224 4225 case EACCES: 4226 default: 4227 bad_error("load_pg", r); 4228 } 4229 4230 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4231 switch (serr) { 4232 case SCF_ERROR_NONE: 4233 break; 4234 4235 case SCF_ERROR_NO_MEMORY: 4236 internal_pgroup_free(old_dpt_pgroup); 4237 return (ENOMEM); 4238 4239 case SCF_ERROR_NOT_FOUND: 4240 internal_pgroup_free(old_dpt_pgroup); 4241 goto delprop; 4242 4243 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 4244 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 4245 default: 4246 bad_error("fmri_to_entity", serr); 4247 } 4248 4249 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4250 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4251 switch (r) { 4252 case 0: 4253 break; 4254 4255 case ECONNABORTED: 4256 internal_pgroup_free(old_dpt_pgroup); 4257 return (r); 4258 4259 case ECANCELED: 4260 case ENOENT: 4261 internal_pgroup_free(old_dpt_pgroup); 4262 goto delprop; 4263 4264 case EBADF: 4265 warn(r_no_lvl, ud_ctarg); 4266 internal_pgroup_free(old_dpt_pgroup); 4267 return (r); 4268 4269 case EINVAL: 4270 default: 4271 bad_error("entity_get_running_pg", r); 4272 } 4273 4274 /* load it */ 4275 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4276 switch (r) { 4277 case 0: 4278 break; 4279 4280 case ECANCELED: 4281 internal_pgroup_free(old_dpt_pgroup); 4282 goto delprop; 4283 4284 case ECONNABORTED: 4285 case ENOMEM: 4286 case EBADF: 4287 internal_pgroup_free(old_dpt_pgroup); 4288 return (r); 4289 4290 case EACCES: 4291 default: 4292 bad_error("load_pg", r); 4293 } 4294 4295 /* compare property groups */ 4296 if (!pg_equal(old_dpt_pgroup, current_pg)) { 4297 warn(cf_newdpg, ient->sc_fmri, ud_name); 4298 internal_pgroup_free(old_dpt_pgroup); 4299 internal_pgroup_free(current_pg); 4300 return (0); 4301 } 4302 4303 internal_pgroup_free(old_dpt_pgroup); 4304 internal_pgroup_free(current_pg); 4305 4306 if (g_verbose) 4307 warn(gettext("%s: Deleting dependent \"%s\".\n"), 4308 ient->sc_fmri, ud_name); 4309 4310 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4311 switch (scf_error()) { 4312 case SCF_ERROR_NOT_FOUND: 4313 case SCF_ERROR_DELETED: 4314 internal_pgroup_free(old_dpt_pgroup); 4315 goto delprop; 4316 4317 case SCF_ERROR_CONNECTION_BROKEN: 4318 internal_pgroup_free(old_dpt_pgroup); 4319 return (ECONNABORTED); 4320 4321 case SCF_ERROR_NOT_SET: 4322 case SCF_ERROR_INVALID_ARGUMENT: 4323 case SCF_ERROR_HANDLE_MISMATCH: 4324 case SCF_ERROR_NOT_BOUND: 4325 default: 4326 bad_error("entity_get_pg", scf_error()); 4327 } 4328 } 4329 4330 if (scf_pg_delete(ud_pg) != 0) { 4331 switch (scf_error()) { 4332 case SCF_ERROR_DELETED: 4333 break; 4334 4335 case SCF_ERROR_CONNECTION_BROKEN: 4336 case SCF_ERROR_BACKEND_READONLY: 4337 case SCF_ERROR_BACKEND_ACCESS: 4338 return (scferror2errno(scf_error())); 4339 4340 case SCF_ERROR_PERMISSION_DENIED: 4341 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4342 return (scferror2errno(scf_error())); 4343 4344 case SCF_ERROR_NOT_SET: 4345 default: 4346 bad_error("scf_pg_delete", scf_error()); 4347 } 4348 } 4349 4350 /* 4351 * This service was changed, so it must be refreshed. But 4352 * since it's not mentioned in the new manifest, we have to 4353 * record its FMRI here for use later. We record the name 4354 * & the entity (via sc_parent) in case we need to print error 4355 * messages during the refresh. 4356 */ 4357 dpt = internal_pgroup_new(); 4358 if (dpt == NULL) 4359 return (ENOMEM); 4360 dpt->sc_pgroup_name = strdup(ud_name); 4361 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 4362 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4363 return (ENOMEM); 4364 dpt->sc_parent = (entity_t *)ient; 4365 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4366 uu_die(gettext("libuutil error: %s\n"), 4367 uu_strerror(uu_error())); 4368 4369 delprop: 4370 if (tx == NULL) 4371 return (0); 4372 4373 ent = scf_entry_create(g_hndl); 4374 if (ent == NULL) 4375 return (ENOMEM); 4376 4377 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 4378 scf_entry_destroy(ent); 4379 switch (scf_error()) { 4380 case SCF_ERROR_DELETED: 4381 warn(emsg_pg_deleted, ient->sc_fmri, 4382 "dependents"); 4383 return (EBUSY); 4384 4385 case SCF_ERROR_CONNECTION_BROKEN: 4386 return (scferror2errno(scf_error())); 4387 4388 case SCF_ERROR_NOT_FOUND: 4389 break; 4390 4391 case SCF_ERROR_HANDLE_MISMATCH: 4392 case SCF_ERROR_NOT_BOUND: 4393 case SCF_ERROR_INVALID_ARGUMENT: 4394 case SCF_ERROR_NOT_SET: 4395 default: 4396 bad_error("scf_transaction_property_delete", 4397 scf_error()); 4398 } 4399 } 4400 4401 return (0); 4402 } 4403 4404 new_dpt_pgroup->sc_pgroup_seen = 1; 4405 4406 /* 4407 * Decide whether the dependent has changed in the manifest. 4408 */ 4409 /* Compare the target. */ 4410 if (scf_property_get_value(prop, ud_val) != 0) { 4411 switch (scf_error()) { 4412 case SCF_ERROR_NOT_FOUND: 4413 case SCF_ERROR_CONSTRAINT_VIOLATED: 4414 warn(li_corrupt, ient->sc_fmri); 4415 return (EBADF); 4416 4417 case SCF_ERROR_DELETED: 4418 case SCF_ERROR_CONNECTION_BROKEN: 4419 return (scferror2errno(scf_error())); 4420 4421 case SCF_ERROR_HANDLE_MISMATCH: 4422 case SCF_ERROR_NOT_BOUND: 4423 case SCF_ERROR_NOT_SET: 4424 case SCF_ERROR_PERMISSION_DENIED: 4425 default: 4426 bad_error("scf_property_get_value", scf_error()); 4427 } 4428 } 4429 4430 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 4431 0) 4432 bad_error("scf_value_get_as_string", scf_error()); 4433 4434 /* 4435 * If the fmri's are not equal then the old fmri will need to 4436 * be refreshed to ensure that the changes are properly updated 4437 * in that service. 4438 */ 4439 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 4440 switch (r) { 4441 case 0: 4442 dpt = internal_pgroup_new(); 4443 if (dpt == NULL) 4444 return (ENOMEM); 4445 dpt->sc_pgroup_name = strdup(ud_name); 4446 dpt->sc_pgroup_fmri = strdup(ud_oldtarg); 4447 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4448 return (ENOMEM); 4449 dpt->sc_parent = (entity_t *)ient; 4450 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4451 uu_die(gettext("libuutil error: %s\n"), 4452 uu_strerror(uu_error())); 4453 break; 4454 4455 case 1: 4456 /* Compare the dependency pgs. */ 4457 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4458 switch (scf_error()) { 4459 case SCF_ERROR_NOT_FOUND: 4460 warn(li_corrupt, ient->sc_fmri); 4461 return (EBADF); 4462 4463 case SCF_ERROR_DELETED: 4464 case SCF_ERROR_CONNECTION_BROKEN: 4465 return (scferror2errno(scf_error())); 4466 4467 case SCF_ERROR_NOT_BOUND: 4468 case SCF_ERROR_HANDLE_MISMATCH: 4469 case SCF_ERROR_INVALID_ARGUMENT: 4470 case SCF_ERROR_NOT_SET: 4471 default: 4472 bad_error("scf_snaplevel_get_pg", scf_error()); 4473 } 4474 } 4475 4476 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4477 snap_lastimport); 4478 switch (r) { 4479 case 0: 4480 break; 4481 4482 case ECANCELED: 4483 case ECONNABORTED: 4484 case ENOMEM: 4485 case EBADF: 4486 return (r); 4487 4488 case EACCES: 4489 default: 4490 bad_error("load_pg", r); 4491 } 4492 4493 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4494 /* no change, leave customizations */ 4495 internal_pgroup_free(old_dpt_pgroup); 4496 return (0); 4497 } 4498 break; 4499 4500 case -1: 4501 warn(li_corrupt, ient->sc_fmri); 4502 return (EBADF); 4503 4504 case -2: 4505 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4506 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4507 return (EINVAL); 4508 4509 default: 4510 bad_error("fmri_equal", r); 4511 } 4512 4513 /* 4514 * The dependent has changed in the manifest. Upgrade the current 4515 * properties if they haven't been customized. 4516 */ 4517 4518 /* 4519 * If new_dpt_pgroup->sc_override, then act as though the property 4520 * group hasn't been customized. 4521 */ 4522 if (new_dpt_pgroup->sc_pgroup_override) { 4523 (void) strcpy(ud_ctarg, ud_oldtarg); 4524 goto nocust; 4525 } 4526 4527 if (!ud_run_dpts_pg_set) { 4528 warn(cf_missing, ient->sc_fmri, ud_name); 4529 r = 0; 4530 goto out; 4531 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4532 switch (scf_error()) { 4533 case SCF_ERROR_NOT_FOUND: 4534 warn(cf_missing, ient->sc_fmri, ud_name); 4535 r = 0; 4536 goto out; 4537 4538 case SCF_ERROR_CONNECTION_BROKEN: 4539 r = scferror2errno(scf_error()); 4540 goto out; 4541 4542 case SCF_ERROR_DELETED: 4543 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4544 r = EBUSY; 4545 goto out; 4546 4547 case SCF_ERROR_INVALID_ARGUMENT: 4548 case SCF_ERROR_NOT_BOUND: 4549 case SCF_ERROR_HANDLE_MISMATCH: 4550 case SCF_ERROR_NOT_SET: 4551 default: 4552 bad_error("scf_pg_get_property", scf_error()); 4553 } 4554 } 4555 4556 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4557 switch (scf_error()) { 4558 case SCF_ERROR_NOT_FOUND: 4559 case SCF_ERROR_CONSTRAINT_VIOLATED: 4560 warn(cf_inval, ient->sc_fmri, ud_name); 4561 r = 0; 4562 goto out; 4563 4564 case SCF_ERROR_DELETED: 4565 case SCF_ERROR_CONNECTION_BROKEN: 4566 r = scferror2errno(scf_error()); 4567 goto out; 4568 4569 case SCF_ERROR_HANDLE_MISMATCH: 4570 case SCF_ERROR_NOT_BOUND: 4571 case SCF_ERROR_NOT_SET: 4572 case SCF_ERROR_PERMISSION_DENIED: 4573 default: 4574 bad_error("scf_property_get_value", scf_error()); 4575 } 4576 } 4577 4578 ty = scf_value_type(ud_val); 4579 assert(ty != SCF_TYPE_INVALID); 4580 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4581 warn(cf_inval, ient->sc_fmri, ud_name); 4582 r = 0; 4583 goto out; 4584 } 4585 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4586 0) 4587 bad_error("scf_value_get_as_string", scf_error()); 4588 4589 r = fmri_equal(ud_ctarg, ud_oldtarg); 4590 if (r == -1) { 4591 warn(cf_inval, ient->sc_fmri, ud_name); 4592 r = 0; 4593 goto out; 4594 } else if (r == -2) { 4595 warn(li_corrupt, ient->sc_fmri); 4596 r = EBADF; 4597 goto out; 4598 } else if (r == 0) { 4599 /* 4600 * Target has been changed. Only abort now if it's been 4601 * changed to something other than what's in the manifest. 4602 */ 4603 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4604 if (r == -1) { 4605 warn(cf_inval, ient->sc_fmri, ud_name); 4606 r = 0; 4607 goto out; 4608 } else if (r == 0) { 4609 warn(cf_newtarg, ient->sc_fmri, ud_name); 4610 r = 0; 4611 goto out; 4612 } else if (r != 1) { 4613 /* invalid sc_pgroup_fmri caught above */ 4614 bad_error("fmri_equal", r); 4615 } 4616 4617 /* 4618 * Fetch the current dependency pg. If it's what the manifest 4619 * says, then no problem. 4620 */ 4621 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4622 switch (serr) { 4623 case SCF_ERROR_NONE: 4624 break; 4625 4626 case SCF_ERROR_NOT_FOUND: 4627 warn(cf_missing, ient->sc_fmri, ud_name); 4628 r = 0; 4629 goto out; 4630 4631 case SCF_ERROR_NO_MEMORY: 4632 r = ENOMEM; 4633 goto out; 4634 4635 case SCF_ERROR_CONSTRAINT_VIOLATED: 4636 case SCF_ERROR_INVALID_ARGUMENT: 4637 default: 4638 bad_error("fmri_to_entity", serr); 4639 } 4640 4641 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4642 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4643 switch (r) { 4644 case 0: 4645 break; 4646 4647 case ECONNABORTED: 4648 goto out; 4649 4650 case ECANCELED: 4651 case ENOENT: 4652 warn(cf_missing, ient->sc_fmri, ud_name); 4653 r = 0; 4654 goto out; 4655 4656 case EBADF: 4657 warn(r_no_lvl, ud_ctarg); 4658 goto out; 4659 4660 case EINVAL: 4661 default: 4662 bad_error("entity_get_running_pg", r); 4663 } 4664 4665 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4666 switch (r) { 4667 case 0: 4668 break; 4669 4670 case ECANCELED: 4671 warn(cf_missing, ient->sc_fmri, ud_name); 4672 r = 0; 4673 goto out; 4674 4675 case ECONNABORTED: 4676 case ENOMEM: 4677 case EBADF: 4678 goto out; 4679 4680 case EACCES: 4681 default: 4682 bad_error("load_pg", r); 4683 } 4684 4685 if (!pg_equal(current_pg, new_dpt_pgroup)) 4686 warn(cf_newdpg, ient->sc_fmri, ud_name); 4687 internal_pgroup_free(current_pg); 4688 r = 0; 4689 goto out; 4690 } else if (r != 1) { 4691 bad_error("fmri_equal", r); 4692 } 4693 4694 nocust: 4695 /* 4696 * Target has not been customized. Check the dependency property 4697 * group. 4698 */ 4699 4700 if (old_dpt_pgroup == NULL) { 4701 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4702 ud_pg) != 0) { 4703 switch (scf_error()) { 4704 case SCF_ERROR_NOT_FOUND: 4705 warn(li_corrupt, ient->sc_fmri); 4706 return (EBADF); 4707 4708 case SCF_ERROR_DELETED: 4709 case SCF_ERROR_CONNECTION_BROKEN: 4710 return (scferror2errno(scf_error())); 4711 4712 case SCF_ERROR_NOT_BOUND: 4713 case SCF_ERROR_HANDLE_MISMATCH: 4714 case SCF_ERROR_INVALID_ARGUMENT: 4715 case SCF_ERROR_NOT_SET: 4716 default: 4717 bad_error("scf_snaplevel_get_pg", scf_error()); 4718 } 4719 } 4720 4721 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4722 snap_lastimport); 4723 switch (r) { 4724 case 0: 4725 break; 4726 4727 case ECANCELED: 4728 case ECONNABORTED: 4729 case ENOMEM: 4730 case EBADF: 4731 return (r); 4732 4733 case EACCES: 4734 default: 4735 bad_error("load_pg", r); 4736 } 4737 } 4738 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4739 switch (serr) { 4740 case SCF_ERROR_NONE: 4741 break; 4742 4743 case SCF_ERROR_NOT_FOUND: 4744 warn(cf_missing, ient->sc_fmri, ud_name); 4745 r = 0; 4746 goto out; 4747 4748 case SCF_ERROR_NO_MEMORY: 4749 r = ENOMEM; 4750 goto out; 4751 4752 case SCF_ERROR_CONSTRAINT_VIOLATED: 4753 case SCF_ERROR_INVALID_ARGUMENT: 4754 default: 4755 bad_error("fmri_to_entity", serr); 4756 } 4757 4758 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4759 ud_iter2, ud_inst, imp_snap, ud_snpl); 4760 switch (r) { 4761 case 0: 4762 break; 4763 4764 case ECONNABORTED: 4765 goto out; 4766 4767 case ECANCELED: 4768 case ENOENT: 4769 warn(cf_missing, ient->sc_fmri, ud_name); 4770 r = 0; 4771 goto out; 4772 4773 case EBADF: 4774 warn(r_no_lvl, ud_ctarg); 4775 goto out; 4776 4777 case EINVAL: 4778 default: 4779 bad_error("entity_get_running_pg", r); 4780 } 4781 4782 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4783 switch (r) { 4784 case 0: 4785 break; 4786 4787 case ECANCELED: 4788 warn(cf_missing, ient->sc_fmri, ud_name); 4789 goto out; 4790 4791 case ECONNABORTED: 4792 case ENOMEM: 4793 case EBADF: 4794 goto out; 4795 4796 case EACCES: 4797 default: 4798 bad_error("load_pg", r); 4799 } 4800 4801 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4802 if (!pg_equal(current_pg, new_dpt_pgroup)) 4803 warn(cf_newdpg, ient->sc_fmri, ud_name); 4804 internal_pgroup_free(current_pg); 4805 r = 0; 4806 goto out; 4807 } 4808 4809 /* Uncustomized. Upgrade. */ 4810 4811 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4812 switch (r) { 4813 case 1: 4814 if (pg_equal(current_pg, new_dpt_pgroup)) { 4815 /* Already upgraded. */ 4816 internal_pgroup_free(current_pg); 4817 r = 0; 4818 goto out; 4819 } 4820 4821 internal_pgroup_free(current_pg); 4822 4823 /* upgrade current_pg */ 4824 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4825 switch (scf_error()) { 4826 case SCF_ERROR_CONNECTION_BROKEN: 4827 r = scferror2errno(scf_error()); 4828 goto out; 4829 4830 case SCF_ERROR_DELETED: 4831 warn(cf_missing, ient->sc_fmri, ud_name); 4832 r = 0; 4833 goto out; 4834 4835 case SCF_ERROR_NOT_FOUND: 4836 break; 4837 4838 case SCF_ERROR_INVALID_ARGUMENT: 4839 case SCF_ERROR_NOT_BOUND: 4840 case SCF_ERROR_NOT_SET: 4841 case SCF_ERROR_HANDLE_MISMATCH: 4842 default: 4843 bad_error("entity_get_pg", scf_error()); 4844 } 4845 4846 if (tissvc) 4847 r = scf_service_add_pg(target_ent, ud_name, 4848 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4849 else 4850 r = scf_instance_add_pg(target_ent, ud_name, 4851 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4852 if (r != 0) { 4853 switch (scf_error()) { 4854 case SCF_ERROR_CONNECTION_BROKEN: 4855 case SCF_ERROR_NO_RESOURCES: 4856 case SCF_ERROR_BACKEND_READONLY: 4857 case SCF_ERROR_BACKEND_ACCESS: 4858 r = scferror2errno(scf_error()); 4859 goto out; 4860 4861 case SCF_ERROR_DELETED: 4862 warn(cf_missing, ient->sc_fmri, 4863 ud_name); 4864 r = 0; 4865 goto out; 4866 4867 case SCF_ERROR_PERMISSION_DENIED: 4868 warn(emsg_pg_deleted, ud_ctarg, 4869 ud_name); 4870 r = EPERM; 4871 goto out; 4872 4873 case SCF_ERROR_EXISTS: 4874 warn(emsg_pg_added, ud_ctarg, ud_name); 4875 r = EBUSY; 4876 goto out; 4877 4878 case SCF_ERROR_NOT_BOUND: 4879 case SCF_ERROR_HANDLE_MISMATCH: 4880 case SCF_ERROR_INVALID_ARGUMENT: 4881 case SCF_ERROR_NOT_SET: 4882 default: 4883 bad_error("entity_add_pg", scf_error()); 4884 } 4885 } 4886 } 4887 4888 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4889 switch (r) { 4890 case 0: 4891 break; 4892 4893 case ECANCELED: 4894 warn(cf_missing, ient->sc_fmri, ud_name); 4895 goto out; 4896 4897 case ECONNABORTED: 4898 case ENOMEM: 4899 case EBADF: 4900 goto out; 4901 4902 case EACCES: 4903 default: 4904 bad_error("load_pg", r); 4905 } 4906 4907 if (g_verbose) 4908 warn(upgrading, ient->sc_fmri, ud_name); 4909 4910 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4911 new_dpt_pgroup, 0, ient->sc_fmri); 4912 switch (r) { 4913 case 0: 4914 break; 4915 4916 case ECANCELED: 4917 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4918 r = EBUSY; 4919 goto out; 4920 4921 case EPERM: 4922 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4923 goto out; 4924 4925 case EBUSY: 4926 warn(emsg_pg_changed, ud_ctarg, ud_name); 4927 goto out; 4928 4929 case ECONNABORTED: 4930 case ENOMEM: 4931 case ENOSPC: 4932 case EROFS: 4933 case EACCES: 4934 case EINVAL: 4935 goto out; 4936 4937 default: 4938 bad_error("upgrade_pg", r); 4939 } 4940 break; 4941 4942 case 0: { 4943 scf_transaction_entry_t *ent; 4944 scf_value_t *val; 4945 4946 internal_pgroup_free(current_pg); 4947 4948 /* delete old pg */ 4949 if (g_verbose) 4950 warn(upgrading, ient->sc_fmri, ud_name); 4951 4952 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4953 switch (scf_error()) { 4954 case SCF_ERROR_CONNECTION_BROKEN: 4955 r = scferror2errno(scf_error()); 4956 goto out; 4957 4958 case SCF_ERROR_DELETED: 4959 warn(cf_missing, ient->sc_fmri, ud_name); 4960 r = 0; 4961 goto out; 4962 4963 case SCF_ERROR_NOT_FOUND: 4964 break; 4965 4966 case SCF_ERROR_INVALID_ARGUMENT: 4967 case SCF_ERROR_NOT_BOUND: 4968 case SCF_ERROR_NOT_SET: 4969 case SCF_ERROR_HANDLE_MISMATCH: 4970 default: 4971 bad_error("entity_get_pg", scf_error()); 4972 } 4973 } else if (scf_pg_delete(ud_pg) != 0) { 4974 switch (scf_error()) { 4975 case SCF_ERROR_DELETED: 4976 break; 4977 4978 case SCF_ERROR_CONNECTION_BROKEN: 4979 case SCF_ERROR_BACKEND_READONLY: 4980 case SCF_ERROR_BACKEND_ACCESS: 4981 r = scferror2errno(scf_error()); 4982 goto out; 4983 4984 case SCF_ERROR_PERMISSION_DENIED: 4985 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4986 r = scferror2errno(scf_error()); 4987 goto out; 4988 4989 case SCF_ERROR_NOT_SET: 4990 default: 4991 bad_error("scf_pg_delete", scf_error()); 4992 } 4993 } 4994 4995 /* import new one */ 4996 cbdata.sc_handle = g_hndl; 4997 cbdata.sc_trans = NULL; /* handled below */ 4998 cbdata.sc_flags = 0; 4999 5000 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 5001 if (r != UU_WALK_NEXT) { 5002 if (r != UU_WALK_ERROR) 5003 bad_error("lscf_dependent_import", r); 5004 5005 r = cbdata.sc_err; 5006 goto out; 5007 } 5008 5009 if (tx == NULL) 5010 break; 5011 5012 if ((ent = scf_entry_create(g_hndl)) == NULL || 5013 (val = scf_value_create(g_hndl)) == NULL) { 5014 if (scf_error() == SCF_ERROR_NO_MEMORY) 5015 return (ENOMEM); 5016 5017 bad_error("scf_entry_create", scf_error()); 5018 } 5019 5020 if (scf_transaction_property_change_type(tx, ent, ud_name, 5021 SCF_TYPE_FMRI) != 0) { 5022 switch (scf_error()) { 5023 case SCF_ERROR_CONNECTION_BROKEN: 5024 r = scferror2errno(scf_error()); 5025 goto out; 5026 5027 case SCF_ERROR_DELETED: 5028 warn(emsg_pg_deleted, ient->sc_fmri, 5029 "dependents"); 5030 r = EBUSY; 5031 goto out; 5032 5033 case SCF_ERROR_NOT_FOUND: 5034 break; 5035 5036 case SCF_ERROR_NOT_BOUND: 5037 case SCF_ERROR_HANDLE_MISMATCH: 5038 case SCF_ERROR_INVALID_ARGUMENT: 5039 case SCF_ERROR_NOT_SET: 5040 default: 5041 bad_error("scf_transaction_property_" 5042 "change_type", scf_error()); 5043 } 5044 5045 if (scf_transaction_property_new(tx, ent, ud_name, 5046 SCF_TYPE_FMRI) != 0) { 5047 switch (scf_error()) { 5048 case SCF_ERROR_CONNECTION_BROKEN: 5049 r = scferror2errno(scf_error()); 5050 goto out; 5051 5052 case SCF_ERROR_DELETED: 5053 warn(emsg_pg_deleted, ient->sc_fmri, 5054 "dependents"); 5055 r = EBUSY; 5056 goto out; 5057 5058 case SCF_ERROR_EXISTS: 5059 warn(emsg_pg_changed, ient->sc_fmri, 5060 "dependents"); 5061 r = EBUSY; 5062 goto out; 5063 5064 case SCF_ERROR_INVALID_ARGUMENT: 5065 case SCF_ERROR_HANDLE_MISMATCH: 5066 case SCF_ERROR_NOT_BOUND: 5067 case SCF_ERROR_NOT_SET: 5068 default: 5069 bad_error("scf_transaction_property_" 5070 "new", scf_error()); 5071 } 5072 } 5073 } 5074 5075 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 5076 new_dpt_pgroup->sc_pgroup_fmri) != 0) 5077 /* invalid sc_pgroup_fmri caught above */ 5078 bad_error("scf_value_set_from_string", 5079 scf_error()); 5080 5081 if (scf_entry_add_value(ent, val) != 0) 5082 bad_error("scf_entry_add_value", scf_error()); 5083 break; 5084 } 5085 5086 case -2: 5087 warn(li_corrupt, ient->sc_fmri); 5088 internal_pgroup_free(current_pg); 5089 r = EBADF; 5090 goto out; 5091 5092 case -1: 5093 default: 5094 /* invalid sc_pgroup_fmri caught above */ 5095 bad_error("fmri_equal", r); 5096 } 5097 5098 r = 0; 5099 5100 out: 5101 if (old_dpt_pgroup != NULL) 5102 internal_pgroup_free(old_dpt_pgroup); 5103 5104 return (r); 5105 } 5106 5107 /* 5108 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 5109 * would import it, except it seems to exist in the service anyway. Compare 5110 * the existent dependent with the one we would import, and report any 5111 * differences (if there are none, be silent). prop is the property which 5112 * represents the existent dependent (in the dependents property group) in the 5113 * entity corresponding to ient. 5114 * 5115 * Returns 5116 * 0 - success (Sort of. At least, we can continue importing.) 5117 * ECONNABORTED - repository connection broken 5118 * EBUSY - ancestor of prop was deleted (error printed) 5119 * ENOMEM - out of memory 5120 * EBADF - corrupt property group (error printed) 5121 * EINVAL - new_dpt_pgroup has invalid target (error printed) 5122 */ 5123 static int 5124 handle_dependent_conflict(const entity_t * const ient, 5125 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 5126 { 5127 int r; 5128 scf_type_t ty; 5129 scf_error_t scfe; 5130 void *tptr; 5131 int tissvc; 5132 pgroup_t *pgroup; 5133 5134 if (scf_property_get_value(prop, ud_val) != 0) { 5135 switch (scf_error()) { 5136 case SCF_ERROR_CONNECTION_BROKEN: 5137 return (scferror2errno(scf_error())); 5138 5139 case SCF_ERROR_DELETED: 5140 warn(emsg_pg_deleted, ient->sc_fmri, 5141 new_dpt_pgroup->sc_pgroup_name); 5142 return (EBUSY); 5143 5144 case SCF_ERROR_CONSTRAINT_VIOLATED: 5145 case SCF_ERROR_NOT_FOUND: 5146 warn(gettext("Conflict upgrading %s (not importing " 5147 "dependent \"%s\" because it already exists.) " 5148 "Warning: The \"%s/%2$s\" property has more or " 5149 "fewer than one value)).\n"), ient->sc_fmri, 5150 new_dpt_pgroup->sc_pgroup_name, "dependents"); 5151 return (0); 5152 5153 case SCF_ERROR_HANDLE_MISMATCH: 5154 case SCF_ERROR_NOT_BOUND: 5155 case SCF_ERROR_NOT_SET: 5156 case SCF_ERROR_PERMISSION_DENIED: 5157 default: 5158 bad_error("scf_property_get_value", 5159 scf_error()); 5160 } 5161 } 5162 5163 ty = scf_value_type(ud_val); 5164 assert(ty != SCF_TYPE_INVALID); 5165 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 5166 warn(gettext("Conflict upgrading %s (not importing dependent " 5167 "\"%s\" because it already exists). Warning: The " 5168 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 5169 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 5170 scf_type_to_string(ty), "dependents"); 5171 return (0); 5172 } 5173 5174 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 5175 0) 5176 bad_error("scf_value_get_as_string", scf_error()); 5177 5178 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 5179 switch (r) { 5180 case 0: 5181 warn(gettext("Conflict upgrading %s (not importing dependent " 5182 "\"%s\" (target \"%s\") because it already exists with " 5183 "target \"%s\").\n"), ient->sc_fmri, 5184 new_dpt_pgroup->sc_pgroup_name, 5185 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 5186 return (0); 5187 5188 case 1: 5189 break; 5190 5191 case -1: 5192 warn(gettext("Conflict upgrading %s (not importing dependent " 5193 "\"%s\" because it already exists). Warning: The current " 5194 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 5195 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5196 return (0); 5197 5198 case -2: 5199 warn(gettext("Dependent \"%s\" of %s has invalid target " 5200 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 5201 new_dpt_pgroup->sc_pgroup_fmri); 5202 return (EINVAL); 5203 5204 default: 5205 bad_error("fmri_equal", r); 5206 } 5207 5208 /* compare dependency pgs in target */ 5209 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 5210 switch (scfe) { 5211 case SCF_ERROR_NONE: 5212 break; 5213 5214 case SCF_ERROR_NO_MEMORY: 5215 return (ENOMEM); 5216 5217 case SCF_ERROR_NOT_FOUND: 5218 warn(emsg_dpt_dangling, ient->sc_fmri, 5219 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5220 return (0); 5221 5222 case SCF_ERROR_CONSTRAINT_VIOLATED: 5223 case SCF_ERROR_INVALID_ARGUMENT: 5224 default: 5225 bad_error("fmri_to_entity", scfe); 5226 } 5227 5228 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 5229 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 5230 switch (r) { 5231 case 0: 5232 break; 5233 5234 case ECONNABORTED: 5235 return (r); 5236 5237 case ECANCELED: 5238 warn(emsg_dpt_dangling, ient->sc_fmri, 5239 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5240 return (0); 5241 5242 case EBADF: 5243 if (tissvc) 5244 warn(gettext("%s has an instance with a \"%s\" " 5245 "snapshot which is missing a snaplevel.\n"), 5246 ud_ctarg, "running"); 5247 else 5248 warn(gettext("%s has a \"%s\" snapshot which is " 5249 "missing a snaplevel.\n"), ud_ctarg, "running"); 5250 /* FALLTHROUGH */ 5251 5252 case ENOENT: 5253 warn(emsg_dpt_no_dep, ient->sc_fmri, 5254 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5255 new_dpt_pgroup->sc_pgroup_name); 5256 return (0); 5257 5258 case EINVAL: 5259 default: 5260 bad_error("entity_get_running_pg", r); 5261 } 5262 5263 pgroup = internal_pgroup_new(); 5264 if (pgroup == NULL) 5265 return (ENOMEM); 5266 5267 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 5268 switch (r) { 5269 case 0: 5270 break; 5271 5272 case ECONNABORTED: 5273 case EBADF: 5274 case ENOMEM: 5275 internal_pgroup_free(pgroup); 5276 return (r); 5277 5278 case ECANCELED: 5279 warn(emsg_dpt_no_dep, ient->sc_fmri, 5280 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5281 new_dpt_pgroup->sc_pgroup_name); 5282 internal_pgroup_free(pgroup); 5283 return (0); 5284 5285 case EACCES: 5286 default: 5287 bad_error("load_pg", r); 5288 } 5289 5290 /* report differences */ 5291 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 5292 internal_pgroup_free(pgroup); 5293 return (0); 5294 } 5295 5296 /* 5297 * lipg is a property group in the last-import snapshot of ent, which is an 5298 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 5299 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 5300 * in ents's property groups, compare and upgrade ent appropriately. 5301 * 5302 * Returns 5303 * 0 - success 5304 * ECONNABORTED - repository connection broken 5305 * ENOMEM - out of memory 5306 * ENOSPC - configd is out of resources 5307 * EINVAL - ient has invalid dependent (error printed) 5308 * - ient has invalid pgroup_t (error printed) 5309 * ECANCELED - ent has been deleted 5310 * ENODEV - entity containing lipg has been deleted 5311 * - entity containing running has been deleted 5312 * EPERM - could not delete pg (permission denied) (error printed) 5313 * - couldn't upgrade dependents (permission denied) (error printed) 5314 * - couldn't import pg (permission denied) (error printed) 5315 * - couldn't upgrade pg (permission denied) (error printed) 5316 * EROFS - could not delete pg (repository read-only) 5317 * - couldn't upgrade dependents (repository read-only) 5318 * - couldn't import pg (repository read-only) 5319 * - couldn't upgrade pg (repository read-only) 5320 * EACCES - could not delete pg (backend access denied) 5321 * - couldn't upgrade dependents (backend access denied) 5322 * - couldn't import pg (backend access denied) 5323 * - couldn't upgrade pg (backend access denied) 5324 * - couldn't read property (backend access denied) 5325 * EBUSY - property group was added (error printed) 5326 * - property group was deleted (error printed) 5327 * - property group changed (error printed) 5328 * - "dependents" pg was added, changed, or deleted (error printed) 5329 * - dependent target deleted (error printed) 5330 * - dependent pg changed (error printed) 5331 * EBADF - imp_snpl is corrupt (error printed) 5332 * - ent has bad pg (error printed) 5333 * EEXIST - dependent collision in target service (error printed) 5334 */ 5335 static int 5336 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 5337 const scf_snaplevel_t *running) 5338 { 5339 int r; 5340 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 5341 scf_callback_t cbdata; 5342 5343 const char * const cf_pg_missing = 5344 gettext("Conflict upgrading %s (property group %s is missing)\n"); 5345 const char * const deleting = 5346 gettext("%s: Deleting property group \"%s\".\n"); 5347 5348 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5349 5350 /* Skip dependent property groups. */ 5351 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 5352 switch (scf_error()) { 5353 case SCF_ERROR_DELETED: 5354 return (ENODEV); 5355 5356 case SCF_ERROR_CONNECTION_BROKEN: 5357 return (ECONNABORTED); 5358 5359 case SCF_ERROR_NOT_SET: 5360 case SCF_ERROR_NOT_BOUND: 5361 default: 5362 bad_error("scf_pg_get_type", scf_error()); 5363 } 5364 } 5365 5366 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 5367 if (scf_pg_get_property(lipg, "external", NULL) == 0) 5368 return (0); 5369 5370 switch (scf_error()) { 5371 case SCF_ERROR_NOT_FOUND: 5372 break; 5373 5374 case SCF_ERROR_CONNECTION_BROKEN: 5375 return (ECONNABORTED); 5376 5377 case SCF_ERROR_DELETED: 5378 return (ENODEV); 5379 5380 case SCF_ERROR_INVALID_ARGUMENT: 5381 case SCF_ERROR_NOT_BOUND: 5382 case SCF_ERROR_HANDLE_MISMATCH: 5383 case SCF_ERROR_NOT_SET: 5384 default: 5385 bad_error("scf_pg_get_property", scf_error()); 5386 } 5387 } 5388 5389 /* lookup pg in new properties */ 5390 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 5391 switch (scf_error()) { 5392 case SCF_ERROR_DELETED: 5393 return (ENODEV); 5394 5395 case SCF_ERROR_CONNECTION_BROKEN: 5396 return (ECONNABORTED); 5397 5398 case SCF_ERROR_NOT_SET: 5399 case SCF_ERROR_NOT_BOUND: 5400 default: 5401 bad_error("scf_pg_get_name", scf_error()); 5402 } 5403 } 5404 5405 pgrp.sc_pgroup_name = imp_str; 5406 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 5407 5408 if (mpg != NULL) 5409 mpg->sc_pgroup_seen = 1; 5410 5411 /* Special handling for dependents */ 5412 if (strcmp(imp_str, "dependents") == 0) 5413 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 5414 5415 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 5416 return (upgrade_manifestfiles(NULL, ient, running, ent)); 5417 5418 if (mpg == NULL || mpg->sc_pgroup_delete) { 5419 /* property group was deleted from manifest */ 5420 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5421 switch (scf_error()) { 5422 case SCF_ERROR_NOT_FOUND: 5423 return (0); 5424 5425 case SCF_ERROR_DELETED: 5426 case SCF_ERROR_CONNECTION_BROKEN: 5427 return (scferror2errno(scf_error())); 5428 5429 case SCF_ERROR_INVALID_ARGUMENT: 5430 case SCF_ERROR_HANDLE_MISMATCH: 5431 case SCF_ERROR_NOT_BOUND: 5432 case SCF_ERROR_NOT_SET: 5433 default: 5434 bad_error("entity_get_pg", scf_error()); 5435 } 5436 } 5437 5438 if (mpg != NULL && mpg->sc_pgroup_delete) { 5439 if (g_verbose) 5440 warn(deleting, ient->sc_fmri, imp_str); 5441 if (scf_pg_delete(imp_pg2) == 0) 5442 return (0); 5443 5444 switch (scf_error()) { 5445 case SCF_ERROR_DELETED: 5446 return (0); 5447 5448 case SCF_ERROR_CONNECTION_BROKEN: 5449 case SCF_ERROR_BACKEND_READONLY: 5450 case SCF_ERROR_BACKEND_ACCESS: 5451 return (scferror2errno(scf_error())); 5452 5453 case SCF_ERROR_PERMISSION_DENIED: 5454 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 5455 return (scferror2errno(scf_error())); 5456 5457 case SCF_ERROR_NOT_SET: 5458 default: 5459 bad_error("scf_pg_delete", scf_error()); 5460 } 5461 } 5462 5463 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5464 switch (r) { 5465 case 0: 5466 break; 5467 5468 case ECANCELED: 5469 return (ENODEV); 5470 5471 case ECONNABORTED: 5472 case ENOMEM: 5473 case EBADF: 5474 case EACCES: 5475 return (r); 5476 5477 default: 5478 bad_error("load_pg", r); 5479 } 5480 5481 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5482 switch (r) { 5483 case 0: 5484 break; 5485 5486 case ECANCELED: 5487 case ECONNABORTED: 5488 case ENOMEM: 5489 case EBADF: 5490 case EACCES: 5491 internal_pgroup_free(lipg_i); 5492 return (r); 5493 5494 default: 5495 bad_error("load_pg", r); 5496 } 5497 5498 if (pg_equal(lipg_i, curpg_i)) { 5499 if (g_verbose) 5500 warn(deleting, ient->sc_fmri, imp_str); 5501 if (scf_pg_delete(imp_pg2) != 0) { 5502 switch (scf_error()) { 5503 case SCF_ERROR_DELETED: 5504 break; 5505 5506 case SCF_ERROR_CONNECTION_BROKEN: 5507 internal_pgroup_free(lipg_i); 5508 internal_pgroup_free(curpg_i); 5509 return (ECONNABORTED); 5510 5511 case SCF_ERROR_NOT_SET: 5512 case SCF_ERROR_NOT_BOUND: 5513 default: 5514 bad_error("scf_pg_delete", scf_error()); 5515 } 5516 } 5517 } else { 5518 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5519 } 5520 5521 internal_pgroup_free(lipg_i); 5522 internal_pgroup_free(curpg_i); 5523 5524 return (0); 5525 } 5526 5527 /* 5528 * Only dependent pgs can have override set, and we skipped those 5529 * above. 5530 */ 5531 assert(!mpg->sc_pgroup_override); 5532 5533 /* compare */ 5534 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5535 switch (r) { 5536 case 0: 5537 break; 5538 5539 case ECANCELED: 5540 return (ENODEV); 5541 5542 case ECONNABORTED: 5543 case EBADF: 5544 case ENOMEM: 5545 case EACCES: 5546 return (r); 5547 5548 default: 5549 bad_error("load_pg", r); 5550 } 5551 5552 if (pg_equal(mpg, lipg_i)) { 5553 /* The manifest pg has not changed. Move on. */ 5554 r = 0; 5555 goto out; 5556 } 5557 5558 /* upgrade current properties according to lipg & mpg */ 5559 if (running != NULL) 5560 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5561 else 5562 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5563 if (r != 0) { 5564 switch (scf_error()) { 5565 case SCF_ERROR_CONNECTION_BROKEN: 5566 r = scferror2errno(scf_error()); 5567 goto out; 5568 5569 case SCF_ERROR_DELETED: 5570 if (running != NULL) 5571 r = ENODEV; 5572 else 5573 r = ECANCELED; 5574 goto out; 5575 5576 case SCF_ERROR_NOT_FOUND: 5577 break; 5578 5579 case SCF_ERROR_INVALID_ARGUMENT: 5580 case SCF_ERROR_HANDLE_MISMATCH: 5581 case SCF_ERROR_NOT_BOUND: 5582 case SCF_ERROR_NOT_SET: 5583 default: 5584 bad_error("entity_get_pg", scf_error()); 5585 } 5586 5587 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5588 5589 r = 0; 5590 goto out; 5591 } 5592 5593 r = load_pg_attrs(imp_pg2, &curpg_i); 5594 switch (r) { 5595 case 0: 5596 break; 5597 5598 case ECANCELED: 5599 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5600 r = 0; 5601 goto out; 5602 5603 case ECONNABORTED: 5604 case ENOMEM: 5605 goto out; 5606 5607 default: 5608 bad_error("load_pg_attrs", r); 5609 } 5610 5611 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5612 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5613 internal_pgroup_free(curpg_i); 5614 r = 0; 5615 goto out; 5616 } 5617 5618 internal_pgroup_free(curpg_i); 5619 5620 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5621 switch (r) { 5622 case 0: 5623 break; 5624 5625 case ECANCELED: 5626 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5627 r = 0; 5628 goto out; 5629 5630 case ECONNABORTED: 5631 case EBADF: 5632 case ENOMEM: 5633 case EACCES: 5634 goto out; 5635 5636 default: 5637 bad_error("load_pg", r); 5638 } 5639 5640 if (pg_equal(lipg_i, curpg_i) && 5641 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5642 int do_delete = 1; 5643 5644 if (g_verbose) 5645 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5646 ient->sc_fmri, mpg->sc_pgroup_name); 5647 5648 internal_pgroup_free(curpg_i); 5649 5650 if (running != NULL && 5651 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5652 switch (scf_error()) { 5653 case SCF_ERROR_DELETED: 5654 r = ECANCELED; 5655 goto out; 5656 5657 case SCF_ERROR_NOT_FOUND: 5658 do_delete = 0; 5659 break; 5660 5661 case SCF_ERROR_CONNECTION_BROKEN: 5662 r = scferror2errno(scf_error()); 5663 goto out; 5664 5665 case SCF_ERROR_HANDLE_MISMATCH: 5666 case SCF_ERROR_INVALID_ARGUMENT: 5667 case SCF_ERROR_NOT_SET: 5668 case SCF_ERROR_NOT_BOUND: 5669 default: 5670 bad_error("entity_get_pg", scf_error()); 5671 } 5672 } 5673 5674 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5675 switch (scf_error()) { 5676 case SCF_ERROR_DELETED: 5677 break; 5678 5679 case SCF_ERROR_CONNECTION_BROKEN: 5680 case SCF_ERROR_BACKEND_READONLY: 5681 case SCF_ERROR_BACKEND_ACCESS: 5682 r = scferror2errno(scf_error()); 5683 goto out; 5684 5685 case SCF_ERROR_PERMISSION_DENIED: 5686 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5687 ient->sc_fmri); 5688 r = scferror2errno(scf_error()); 5689 goto out; 5690 5691 case SCF_ERROR_NOT_SET: 5692 case SCF_ERROR_NOT_BOUND: 5693 default: 5694 bad_error("scf_pg_delete", scf_error()); 5695 } 5696 } 5697 5698 cbdata.sc_handle = g_hndl; 5699 cbdata.sc_parent = ent; 5700 cbdata.sc_service = issvc; 5701 cbdata.sc_flags = 0; 5702 cbdata.sc_source_fmri = ient->sc_fmri; 5703 cbdata.sc_target_fmri = ient->sc_fmri; 5704 5705 r = entity_pgroup_import(mpg, &cbdata); 5706 switch (r) { 5707 case UU_WALK_NEXT: 5708 r = 0; 5709 goto out; 5710 5711 case UU_WALK_ERROR: 5712 if (cbdata.sc_err == EEXIST) { 5713 warn(emsg_pg_added, ient->sc_fmri, 5714 mpg->sc_pgroup_name); 5715 r = EBUSY; 5716 } else { 5717 r = cbdata.sc_err; 5718 } 5719 goto out; 5720 5721 default: 5722 bad_error("entity_pgroup_import", r); 5723 } 5724 } 5725 5726 if (running != NULL && 5727 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5728 switch (scf_error()) { 5729 case SCF_ERROR_CONNECTION_BROKEN: 5730 case SCF_ERROR_DELETED: 5731 r = scferror2errno(scf_error()); 5732 goto out; 5733 5734 case SCF_ERROR_NOT_FOUND: 5735 break; 5736 5737 case SCF_ERROR_HANDLE_MISMATCH: 5738 case SCF_ERROR_INVALID_ARGUMENT: 5739 case SCF_ERROR_NOT_SET: 5740 case SCF_ERROR_NOT_BOUND: 5741 default: 5742 bad_error("entity_get_pg", scf_error()); 5743 } 5744 5745 cbdata.sc_handle = g_hndl; 5746 cbdata.sc_parent = ent; 5747 cbdata.sc_service = issvc; 5748 cbdata.sc_flags = SCI_FORCE; 5749 cbdata.sc_source_fmri = ient->sc_fmri; 5750 cbdata.sc_target_fmri = ient->sc_fmri; 5751 5752 r = entity_pgroup_import(mpg, &cbdata); 5753 switch (r) { 5754 case UU_WALK_NEXT: 5755 r = 0; 5756 goto out; 5757 5758 case UU_WALK_ERROR: 5759 if (cbdata.sc_err == EEXIST) { 5760 warn(emsg_pg_added, ient->sc_fmri, 5761 mpg->sc_pgroup_name); 5762 r = EBUSY; 5763 } else { 5764 r = cbdata.sc_err; 5765 } 5766 goto out; 5767 5768 default: 5769 bad_error("entity_pgroup_import", r); 5770 } 5771 } 5772 5773 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5774 internal_pgroup_free(curpg_i); 5775 switch (r) { 5776 case 0: 5777 ient->sc_import_state = IMPORT_PROP_BEGUN; 5778 break; 5779 5780 case ECANCELED: 5781 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5782 r = EBUSY; 5783 break; 5784 5785 case EPERM: 5786 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5787 break; 5788 5789 case EBUSY: 5790 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5791 break; 5792 5793 case ECONNABORTED: 5794 case ENOMEM: 5795 case ENOSPC: 5796 case EROFS: 5797 case EACCES: 5798 case EINVAL: 5799 break; 5800 5801 default: 5802 bad_error("upgrade_pg", r); 5803 } 5804 5805 out: 5806 internal_pgroup_free(lipg_i); 5807 return (r); 5808 } 5809 5810 /* 5811 * Upgrade the properties of ent according to snpl & ient. 5812 * 5813 * Returns 5814 * 0 - success 5815 * ECONNABORTED - repository connection broken 5816 * ENOMEM - out of memory 5817 * ENOSPC - configd is out of resources 5818 * ECANCELED - ent was deleted 5819 * ENODEV - entity containing snpl was deleted 5820 * - entity containing running was deleted 5821 * EBADF - imp_snpl is corrupt (error printed) 5822 * - ent has corrupt pg (error printed) 5823 * - dependent has corrupt pg (error printed) 5824 * - dependent target has a corrupt snapshot (error printed) 5825 * EBUSY - pg was added, changed, or deleted (error printed) 5826 * - dependent target was deleted (error printed) 5827 * - dependent pg changed (error printed) 5828 * EINVAL - invalid property group name (error printed) 5829 * - invalid property name (error printed) 5830 * - invalid value (error printed) 5831 * - ient has invalid pgroup or dependent (error printed) 5832 * EPERM - could not create property group (permission denied) (error printed) 5833 * - could not modify property group (permission denied) (error printed) 5834 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5835 * EROFS - could not create property group (repository read-only) 5836 * - couldn't delete, upgrade, or import pg or dependent 5837 * EACCES - could not create property group (backend access denied) 5838 * - couldn't delete, upgrade, or import pg or dependent 5839 * EEXIST - dependent collision in target service (error printed) 5840 */ 5841 static int 5842 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5843 entity_t *ient) 5844 { 5845 pgroup_t *pg, *rpg; 5846 int r; 5847 uu_list_t *pgs = ient->sc_pgroups; 5848 5849 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5850 5851 /* clear sc_sceen for pgs */ 5852 if (uu_list_walk(pgs, clear_int, 5853 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5854 bad_error("uu_list_walk", uu_error()); 5855 5856 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5857 switch (scf_error()) { 5858 case SCF_ERROR_DELETED: 5859 return (ENODEV); 5860 5861 case SCF_ERROR_CONNECTION_BROKEN: 5862 return (ECONNABORTED); 5863 5864 case SCF_ERROR_NOT_SET: 5865 case SCF_ERROR_NOT_BOUND: 5866 case SCF_ERROR_HANDLE_MISMATCH: 5867 default: 5868 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5869 } 5870 } 5871 5872 for (;;) { 5873 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5874 if (r == 0) 5875 break; 5876 if (r == 1) { 5877 r = process_old_pg(imp_pg, ient, ent, running); 5878 switch (r) { 5879 case 0: 5880 break; 5881 5882 case ECONNABORTED: 5883 case ENOMEM: 5884 case ENOSPC: 5885 case ECANCELED: 5886 case ENODEV: 5887 case EPERM: 5888 case EROFS: 5889 case EACCES: 5890 case EBADF: 5891 case EBUSY: 5892 case EINVAL: 5893 case EEXIST: 5894 return (r); 5895 5896 default: 5897 bad_error("process_old_pg", r); 5898 } 5899 continue; 5900 } 5901 if (r != -1) 5902 bad_error("scf_iter_next_pg", r); 5903 5904 switch (scf_error()) { 5905 case SCF_ERROR_DELETED: 5906 return (ENODEV); 5907 5908 case SCF_ERROR_CONNECTION_BROKEN: 5909 return (ECONNABORTED); 5910 5911 case SCF_ERROR_HANDLE_MISMATCH: 5912 case SCF_ERROR_NOT_BOUND: 5913 case SCF_ERROR_NOT_SET: 5914 case SCF_ERROR_INVALID_ARGUMENT: 5915 default: 5916 bad_error("scf_iter_next_pg", scf_error()); 5917 } 5918 } 5919 5920 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5921 if (pg->sc_pgroup_seen) 5922 continue; 5923 5924 /* pg is new */ 5925 5926 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5927 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5928 ent); 5929 switch (r) { 5930 case 0: 5931 break; 5932 5933 case ECONNABORTED: 5934 case ENOMEM: 5935 case ENOSPC: 5936 case ECANCELED: 5937 case ENODEV: 5938 case EBADF: 5939 case EBUSY: 5940 case EINVAL: 5941 case EPERM: 5942 case EROFS: 5943 case EACCES: 5944 case EEXIST: 5945 return (r); 5946 5947 default: 5948 bad_error("upgrade_dependents", r); 5949 } 5950 continue; 5951 } 5952 5953 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 5954 r = upgrade_manifestfiles(pg, ient, running, ent); 5955 switch (r) { 5956 case 0: 5957 break; 5958 5959 case ECONNABORTED: 5960 case ENOMEM: 5961 case ENOSPC: 5962 case ECANCELED: 5963 case ENODEV: 5964 case EBADF: 5965 case EBUSY: 5966 case EINVAL: 5967 case EPERM: 5968 case EROFS: 5969 case EACCES: 5970 case EEXIST: 5971 return (r); 5972 5973 default: 5974 bad_error("upgrade_manifestfiles", r); 5975 } 5976 continue; 5977 } 5978 5979 if (running != NULL) { 5980 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 5981 imp_pg); 5982 } else { 5983 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 5984 imp_pg); 5985 } 5986 if (r != 0) { 5987 scf_callback_t cbdata; 5988 5989 switch (scf_error()) { 5990 case SCF_ERROR_NOT_FOUND: 5991 break; 5992 5993 case SCF_ERROR_CONNECTION_BROKEN: 5994 return (scferror2errno(scf_error())); 5995 5996 case SCF_ERROR_DELETED: 5997 if (running != NULL) 5998 return (ENODEV); 5999 else 6000 return (scferror2errno(scf_error())); 6001 6002 case SCF_ERROR_INVALID_ARGUMENT: 6003 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 6004 pg->sc_pgroup_name); 6005 return (EINVAL); 6006 6007 case SCF_ERROR_NOT_SET: 6008 case SCF_ERROR_HANDLE_MISMATCH: 6009 case SCF_ERROR_NOT_BOUND: 6010 default: 6011 bad_error("entity_get_pg", scf_error()); 6012 } 6013 6014 /* User doesn't have pg, so import it. */ 6015 6016 cbdata.sc_handle = g_hndl; 6017 cbdata.sc_parent = ent; 6018 cbdata.sc_service = issvc; 6019 cbdata.sc_flags = SCI_FORCE; 6020 cbdata.sc_source_fmri = ient->sc_fmri; 6021 cbdata.sc_target_fmri = ient->sc_fmri; 6022 6023 r = entity_pgroup_import(pg, &cbdata); 6024 switch (r) { 6025 case UU_WALK_NEXT: 6026 ient->sc_import_state = IMPORT_PROP_BEGUN; 6027 continue; 6028 6029 case UU_WALK_ERROR: 6030 if (cbdata.sc_err == EEXIST) { 6031 warn(emsg_pg_added, ient->sc_fmri, 6032 pg->sc_pgroup_name); 6033 return (EBUSY); 6034 } 6035 return (cbdata.sc_err); 6036 6037 default: 6038 bad_error("entity_pgroup_import", r); 6039 } 6040 } 6041 6042 /* report differences between pg & current */ 6043 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 6044 switch (r) { 6045 case 0: 6046 break; 6047 6048 case ECANCELED: 6049 warn(emsg_pg_deleted, ient->sc_fmri, 6050 pg->sc_pgroup_name); 6051 return (EBUSY); 6052 6053 case ECONNABORTED: 6054 case EBADF: 6055 case ENOMEM: 6056 case EACCES: 6057 return (r); 6058 6059 default: 6060 bad_error("load_pg", r); 6061 } 6062 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 6063 internal_pgroup_free(rpg); 6064 rpg = NULL; 6065 } 6066 6067 return (0); 6068 } 6069 6070 /* 6071 * Import an instance. If it doesn't exist, create it. If it has 6072 * a last-import snapshot, upgrade its properties. Finish by updating its 6073 * last-import snapshot. If it doesn't have a last-import snapshot then it 6074 * could have been created for a dependent tag in another manifest. Import the 6075 * new properties. If there's a conflict, don't override, like now? 6076 * 6077 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 6078 * lcbdata->sc_err to 6079 * ECONNABORTED - repository connection broken 6080 * ENOMEM - out of memory 6081 * ENOSPC - svc.configd is out of resources 6082 * EEXIST - dependency collision in dependent service (error printed) 6083 * EPERM - couldn't create temporary instance (permission denied) 6084 * - couldn't import into temporary instance (permission denied) 6085 * - couldn't take snapshot (permission denied) 6086 * - couldn't upgrade properties (permission denied) 6087 * - couldn't import properties (permission denied) 6088 * - couldn't import dependents (permission denied) 6089 * EROFS - couldn't create temporary instance (repository read-only) 6090 * - couldn't import into temporary instance (repository read-only) 6091 * - couldn't upgrade properties (repository read-only) 6092 * - couldn't import properties (repository read-only) 6093 * - couldn't import dependents (repository read-only) 6094 * EACCES - couldn't create temporary instance (backend access denied) 6095 * - couldn't import into temporary instance (backend access denied) 6096 * - couldn't upgrade properties (backend access denied) 6097 * - couldn't import properties (backend access denied) 6098 * - couldn't import dependents (backend access denied) 6099 * EINVAL - invalid instance name (error printed) 6100 * - invalid pgroup_t's (error printed) 6101 * - invalid dependents (error printed) 6102 * EBUSY - temporary service deleted (error printed) 6103 * - temporary instance deleted (error printed) 6104 * - temporary instance changed (error printed) 6105 * - temporary instance already exists (error printed) 6106 * - instance deleted (error printed) 6107 * EBADF - instance has corrupt last-import snapshot (error printed) 6108 * - instance is corrupt (error printed) 6109 * - dependent has corrupt pg (error printed) 6110 * - dependent target has a corrupt snapshot (error printed) 6111 * -1 - unknown libscf error (error printed) 6112 */ 6113 static int 6114 lscf_instance_import(void *v, void *pvt) 6115 { 6116 entity_t *inst = v; 6117 scf_callback_t ctx; 6118 scf_callback_t *lcbdata = pvt; 6119 scf_service_t *rsvc = lcbdata->sc_parent; 6120 int r; 6121 scf_snaplevel_t *running; 6122 int flags = lcbdata->sc_flags; 6123 6124 const char * const emsg_tdel = 6125 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 6126 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 6127 "changed unexpectedly.\n"); 6128 const char * const emsg_del = gettext("%s changed unexpectedly " 6129 "(instance \"%s\" was deleted.)\n"); 6130 const char * const emsg_badsnap = gettext( 6131 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 6132 6133 /* 6134 * prepare last-import snapshot: 6135 * create temporary instance (service was precreated) 6136 * populate with properties from bundle 6137 * take snapshot 6138 */ 6139 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 6140 switch (scf_error()) { 6141 case SCF_ERROR_CONNECTION_BROKEN: 6142 case SCF_ERROR_NO_RESOURCES: 6143 case SCF_ERROR_BACKEND_READONLY: 6144 case SCF_ERROR_BACKEND_ACCESS: 6145 return (stash_scferror(lcbdata)); 6146 6147 case SCF_ERROR_EXISTS: 6148 warn(gettext("Temporary service svc:/%s " 6149 "changed unexpectedly (instance \"%s\" added).\n"), 6150 imp_tsname, inst->sc_name); 6151 lcbdata->sc_err = EBUSY; 6152 return (UU_WALK_ERROR); 6153 6154 case SCF_ERROR_DELETED: 6155 warn(gettext("Temporary service svc:/%s " 6156 "was deleted unexpectedly.\n"), imp_tsname); 6157 lcbdata->sc_err = EBUSY; 6158 return (UU_WALK_ERROR); 6159 6160 case SCF_ERROR_INVALID_ARGUMENT: 6161 warn(gettext("Invalid instance name \"%s\".\n"), 6162 inst->sc_name); 6163 return (stash_scferror(lcbdata)); 6164 6165 case SCF_ERROR_PERMISSION_DENIED: 6166 warn(gettext("Could not create temporary instance " 6167 "\"%s\" in svc:/%s (permission denied).\n"), 6168 inst->sc_name, imp_tsname); 6169 return (stash_scferror(lcbdata)); 6170 6171 case SCF_ERROR_HANDLE_MISMATCH: 6172 case SCF_ERROR_NOT_BOUND: 6173 case SCF_ERROR_NOT_SET: 6174 default: 6175 bad_error("scf_service_add_instance", scf_error()); 6176 } 6177 } 6178 6179 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6180 inst->sc_name); 6181 if (r < 0) 6182 bad_error("snprintf", errno); 6183 6184 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 6185 lcbdata->sc_flags | SCI_NOENABLED); 6186 switch (r) { 6187 case 0: 6188 break; 6189 6190 case ECANCELED: 6191 warn(emsg_tdel, imp_tsname, inst->sc_name); 6192 lcbdata->sc_err = EBUSY; 6193 r = UU_WALK_ERROR; 6194 goto deltemp; 6195 6196 case EEXIST: 6197 warn(emsg_tchg, imp_tsname, inst->sc_name); 6198 lcbdata->sc_err = EBUSY; 6199 r = UU_WALK_ERROR; 6200 goto deltemp; 6201 6202 case ECONNABORTED: 6203 goto connaborted; 6204 6205 case ENOMEM: 6206 case ENOSPC: 6207 case EPERM: 6208 case EROFS: 6209 case EACCES: 6210 case EINVAL: 6211 case EBUSY: 6212 lcbdata->sc_err = r; 6213 r = UU_WALK_ERROR; 6214 goto deltemp; 6215 6216 default: 6217 bad_error("lscf_import_instance_pgs", r); 6218 } 6219 6220 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6221 inst->sc_name); 6222 if (r < 0) 6223 bad_error("snprintf", errno); 6224 6225 ctx.sc_handle = lcbdata->sc_handle; 6226 ctx.sc_parent = imp_tinst; 6227 ctx.sc_service = 0; 6228 ctx.sc_source_fmri = inst->sc_fmri; 6229 ctx.sc_target_fmri = imp_str; 6230 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 6231 UU_DEFAULT) != 0) { 6232 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6233 bad_error("uu_list_walk", uu_error()); 6234 6235 switch (ctx.sc_err) { 6236 case ECONNABORTED: 6237 goto connaborted; 6238 6239 case ECANCELED: 6240 warn(emsg_tdel, imp_tsname, inst->sc_name); 6241 lcbdata->sc_err = EBUSY; 6242 break; 6243 6244 case EEXIST: 6245 warn(emsg_tchg, imp_tsname, inst->sc_name); 6246 lcbdata->sc_err = EBUSY; 6247 break; 6248 6249 default: 6250 lcbdata->sc_err = ctx.sc_err; 6251 } 6252 r = UU_WALK_ERROR; 6253 goto deltemp; 6254 } 6255 6256 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 6257 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 6258 switch (scf_error()) { 6259 case SCF_ERROR_CONNECTION_BROKEN: 6260 goto connaborted; 6261 6262 case SCF_ERROR_NO_RESOURCES: 6263 r = stash_scferror(lcbdata); 6264 goto deltemp; 6265 6266 case SCF_ERROR_EXISTS: 6267 warn(emsg_tchg, imp_tsname, inst->sc_name); 6268 lcbdata->sc_err = EBUSY; 6269 r = UU_WALK_ERROR; 6270 goto deltemp; 6271 6272 case SCF_ERROR_PERMISSION_DENIED: 6273 warn(gettext("Could not take \"%s\" snapshot of %s " 6274 "(permission denied).\n"), snap_lastimport, 6275 imp_str); 6276 r = stash_scferror(lcbdata); 6277 goto deltemp; 6278 6279 default: 6280 scfwarn(); 6281 lcbdata->sc_err = -1; 6282 r = UU_WALK_ERROR; 6283 goto deltemp; 6284 6285 case SCF_ERROR_HANDLE_MISMATCH: 6286 case SCF_ERROR_INVALID_ARGUMENT: 6287 case SCF_ERROR_NOT_SET: 6288 bad_error("_scf_snapshot_take_new_named", scf_error()); 6289 } 6290 } 6291 6292 if (lcbdata->sc_flags & SCI_FRESH) 6293 goto fresh; 6294 6295 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 6296 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6297 imp_lisnap) != 0) { 6298 switch (scf_error()) { 6299 case SCF_ERROR_DELETED: 6300 warn(emsg_del, inst->sc_parent->sc_fmri, 6301 inst->sc_name); 6302 lcbdata->sc_err = EBUSY; 6303 r = UU_WALK_ERROR; 6304 goto deltemp; 6305 6306 case SCF_ERROR_NOT_FOUND: 6307 flags |= SCI_FORCE; 6308 goto nosnap; 6309 6310 case SCF_ERROR_CONNECTION_BROKEN: 6311 goto connaborted; 6312 6313 case SCF_ERROR_INVALID_ARGUMENT: 6314 case SCF_ERROR_HANDLE_MISMATCH: 6315 case SCF_ERROR_NOT_BOUND: 6316 case SCF_ERROR_NOT_SET: 6317 default: 6318 bad_error("scf_instance_get_snapshot", 6319 scf_error()); 6320 } 6321 } 6322 6323 /* upgrade */ 6324 6325 /* 6326 * compare new properties with last-import properties 6327 * upgrade current properties 6328 */ 6329 /* clear sc_sceen for pgs */ 6330 if (uu_list_walk(inst->sc_pgroups, clear_int, 6331 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 6332 0) 6333 bad_error("uu_list_walk", uu_error()); 6334 6335 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 6336 switch (r) { 6337 case 0: 6338 break; 6339 6340 case ECONNABORTED: 6341 goto connaborted; 6342 6343 case ECANCELED: 6344 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6345 lcbdata->sc_err = EBUSY; 6346 r = UU_WALK_ERROR; 6347 goto deltemp; 6348 6349 case ENOENT: 6350 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 6351 lcbdata->sc_err = EBADF; 6352 r = UU_WALK_ERROR; 6353 goto deltemp; 6354 6355 default: 6356 bad_error("get_snaplevel", r); 6357 } 6358 6359 if (scf_instance_get_snapshot(imp_inst, snap_running, 6360 imp_rsnap) != 0) { 6361 switch (scf_error()) { 6362 case SCF_ERROR_DELETED: 6363 warn(emsg_del, inst->sc_parent->sc_fmri, 6364 inst->sc_name); 6365 lcbdata->sc_err = EBUSY; 6366 r = UU_WALK_ERROR; 6367 goto deltemp; 6368 6369 case SCF_ERROR_NOT_FOUND: 6370 break; 6371 6372 case SCF_ERROR_CONNECTION_BROKEN: 6373 goto connaborted; 6374 6375 case SCF_ERROR_INVALID_ARGUMENT: 6376 case SCF_ERROR_HANDLE_MISMATCH: 6377 case SCF_ERROR_NOT_BOUND: 6378 case SCF_ERROR_NOT_SET: 6379 default: 6380 bad_error("scf_instance_get_snapshot", 6381 scf_error()); 6382 } 6383 6384 running = NULL; 6385 } else { 6386 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 6387 switch (r) { 6388 case 0: 6389 running = imp_rsnpl; 6390 break; 6391 6392 case ECONNABORTED: 6393 goto connaborted; 6394 6395 case ECANCELED: 6396 warn(emsg_del, inst->sc_parent->sc_fmri, 6397 inst->sc_name); 6398 lcbdata->sc_err = EBUSY; 6399 r = UU_WALK_ERROR; 6400 goto deltemp; 6401 6402 case ENOENT: 6403 warn(emsg_badsnap, snap_running, inst->sc_fmri); 6404 lcbdata->sc_err = EBADF; 6405 r = UU_WALK_ERROR; 6406 goto deltemp; 6407 6408 default: 6409 bad_error("get_snaplevel", r); 6410 } 6411 } 6412 6413 r = upgrade_props(imp_inst, running, imp_snpl, inst); 6414 switch (r) { 6415 case 0: 6416 break; 6417 6418 case ECANCELED: 6419 case ENODEV: 6420 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6421 lcbdata->sc_err = EBUSY; 6422 r = UU_WALK_ERROR; 6423 goto deltemp; 6424 6425 case ECONNABORTED: 6426 goto connaborted; 6427 6428 case ENOMEM: 6429 case ENOSPC: 6430 case EBADF: 6431 case EBUSY: 6432 case EINVAL: 6433 case EPERM: 6434 case EROFS: 6435 case EACCES: 6436 case EEXIST: 6437 lcbdata->sc_err = r; 6438 r = UU_WALK_ERROR; 6439 goto deltemp; 6440 6441 default: 6442 bad_error("upgrade_props", r); 6443 } 6444 6445 inst->sc_import_state = IMPORT_PROP_DONE; 6446 } else { 6447 switch (scf_error()) { 6448 case SCF_ERROR_CONNECTION_BROKEN: 6449 goto connaborted; 6450 6451 case SCF_ERROR_NOT_FOUND: 6452 break; 6453 6454 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6455 case SCF_ERROR_HANDLE_MISMATCH: 6456 case SCF_ERROR_NOT_BOUND: 6457 case SCF_ERROR_NOT_SET: 6458 default: 6459 bad_error("scf_service_get_instance", scf_error()); 6460 } 6461 6462 fresh: 6463 /* create instance */ 6464 if (scf_service_add_instance(rsvc, inst->sc_name, 6465 imp_inst) != 0) { 6466 switch (scf_error()) { 6467 case SCF_ERROR_CONNECTION_BROKEN: 6468 goto connaborted; 6469 6470 case SCF_ERROR_NO_RESOURCES: 6471 case SCF_ERROR_BACKEND_READONLY: 6472 case SCF_ERROR_BACKEND_ACCESS: 6473 r = stash_scferror(lcbdata); 6474 goto deltemp; 6475 6476 case SCF_ERROR_EXISTS: 6477 warn(gettext("%s changed unexpectedly " 6478 "(instance \"%s\" added).\n"), 6479 inst->sc_parent->sc_fmri, inst->sc_name); 6480 lcbdata->sc_err = EBUSY; 6481 r = UU_WALK_ERROR; 6482 goto deltemp; 6483 6484 case SCF_ERROR_PERMISSION_DENIED: 6485 warn(gettext("Could not create \"%s\" instance " 6486 "in %s (permission denied).\n"), 6487 inst->sc_name, inst->sc_parent->sc_fmri); 6488 r = stash_scferror(lcbdata); 6489 goto deltemp; 6490 6491 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6492 case SCF_ERROR_HANDLE_MISMATCH: 6493 case SCF_ERROR_NOT_BOUND: 6494 case SCF_ERROR_NOT_SET: 6495 default: 6496 bad_error("scf_service_add_instance", 6497 scf_error()); 6498 } 6499 } 6500 6501 nosnap: 6502 /* 6503 * Create a last-import snapshot to serve as an attachment 6504 * point for the real one from the temporary instance. Since 6505 * the contents is irrelevant, take it now, while the instance 6506 * is empty, to minimize svc.configd's work. 6507 */ 6508 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6509 imp_lisnap) != 0) { 6510 switch (scf_error()) { 6511 case SCF_ERROR_CONNECTION_BROKEN: 6512 goto connaborted; 6513 6514 case SCF_ERROR_NO_RESOURCES: 6515 r = stash_scferror(lcbdata); 6516 goto deltemp; 6517 6518 case SCF_ERROR_EXISTS: 6519 warn(gettext("%s changed unexpectedly " 6520 "(snapshot \"%s\" added).\n"), 6521 inst->sc_fmri, snap_lastimport); 6522 lcbdata->sc_err = EBUSY; 6523 r = UU_WALK_ERROR; 6524 goto deltemp; 6525 6526 case SCF_ERROR_PERMISSION_DENIED: 6527 warn(gettext("Could not take \"%s\" snapshot " 6528 "of %s (permission denied).\n"), 6529 snap_lastimport, inst->sc_fmri); 6530 r = stash_scferror(lcbdata); 6531 goto deltemp; 6532 6533 default: 6534 scfwarn(); 6535 lcbdata->sc_err = -1; 6536 r = UU_WALK_ERROR; 6537 goto deltemp; 6538 6539 case SCF_ERROR_NOT_SET: 6540 case SCF_ERROR_INTERNAL: 6541 case SCF_ERROR_INVALID_ARGUMENT: 6542 case SCF_ERROR_HANDLE_MISMATCH: 6543 bad_error("_scf_snapshot_take_new", 6544 scf_error()); 6545 } 6546 } 6547 6548 if (li_only) 6549 goto lionly; 6550 6551 inst->sc_import_state = IMPORT_PROP_BEGUN; 6552 6553 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6554 flags); 6555 switch (r) { 6556 case 0: 6557 break; 6558 6559 case ECONNABORTED: 6560 goto connaborted; 6561 6562 case ECANCELED: 6563 warn(gettext("%s changed unexpectedly " 6564 "(instance \"%s\" deleted).\n"), 6565 inst->sc_parent->sc_fmri, inst->sc_name); 6566 lcbdata->sc_err = EBUSY; 6567 r = UU_WALK_ERROR; 6568 goto deltemp; 6569 6570 case EEXIST: 6571 warn(gettext("%s changed unexpectedly " 6572 "(property group added).\n"), inst->sc_fmri); 6573 lcbdata->sc_err = EBUSY; 6574 r = UU_WALK_ERROR; 6575 goto deltemp; 6576 6577 default: 6578 lcbdata->sc_err = r; 6579 r = UU_WALK_ERROR; 6580 goto deltemp; 6581 6582 case EINVAL: /* caught above */ 6583 bad_error("lscf_import_instance_pgs", r); 6584 } 6585 6586 ctx.sc_parent = imp_inst; 6587 ctx.sc_service = 0; 6588 ctx.sc_trans = NULL; 6589 ctx.sc_flags = 0; 6590 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6591 &ctx, UU_DEFAULT) != 0) { 6592 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6593 bad_error("uu_list_walk", uu_error()); 6594 6595 if (ctx.sc_err == ECONNABORTED) 6596 goto connaborted; 6597 lcbdata->sc_err = ctx.sc_err; 6598 r = UU_WALK_ERROR; 6599 goto deltemp; 6600 } 6601 6602 inst->sc_import_state = IMPORT_PROP_DONE; 6603 6604 if (g_verbose) 6605 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6606 snap_initial, inst->sc_fmri); 6607 r = take_snap(imp_inst, snap_initial, imp_snap); 6608 switch (r) { 6609 case 0: 6610 break; 6611 6612 case ECONNABORTED: 6613 goto connaborted; 6614 6615 case ENOSPC: 6616 case -1: 6617 lcbdata->sc_err = r; 6618 r = UU_WALK_ERROR; 6619 goto deltemp; 6620 6621 case ECANCELED: 6622 warn(gettext("%s changed unexpectedly " 6623 "(instance %s deleted).\n"), 6624 inst->sc_parent->sc_fmri, inst->sc_name); 6625 lcbdata->sc_err = r; 6626 r = UU_WALK_ERROR; 6627 goto deltemp; 6628 6629 case EPERM: 6630 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6631 lcbdata->sc_err = r; 6632 r = UU_WALK_ERROR; 6633 goto deltemp; 6634 6635 default: 6636 bad_error("take_snap", r); 6637 } 6638 } 6639 6640 lionly: 6641 if (lcbdata->sc_flags & SCI_NOSNAP) 6642 goto deltemp; 6643 6644 /* transfer snapshot from temporary instance */ 6645 if (g_verbose) 6646 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6647 snap_lastimport, inst->sc_fmri); 6648 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6649 switch (scf_error()) { 6650 case SCF_ERROR_CONNECTION_BROKEN: 6651 goto connaborted; 6652 6653 case SCF_ERROR_NO_RESOURCES: 6654 r = stash_scferror(lcbdata); 6655 goto deltemp; 6656 6657 case SCF_ERROR_PERMISSION_DENIED: 6658 warn(gettext("Could not take \"%s\" snapshot for %s " 6659 "(permission denied).\n"), snap_lastimport, 6660 inst->sc_fmri); 6661 r = stash_scferror(lcbdata); 6662 goto deltemp; 6663 6664 case SCF_ERROR_NOT_SET: 6665 case SCF_ERROR_HANDLE_MISMATCH: 6666 default: 6667 bad_error("_scf_snapshot_attach", scf_error()); 6668 } 6669 } 6670 6671 inst->sc_import_state = IMPORT_COMPLETE; 6672 6673 r = UU_WALK_NEXT; 6674 6675 deltemp: 6676 /* delete temporary instance */ 6677 if (scf_instance_delete(imp_tinst) != 0) { 6678 switch (scf_error()) { 6679 case SCF_ERROR_DELETED: 6680 break; 6681 6682 case SCF_ERROR_CONNECTION_BROKEN: 6683 goto connaborted; 6684 6685 case SCF_ERROR_NOT_SET: 6686 case SCF_ERROR_NOT_BOUND: 6687 default: 6688 bad_error("scf_instance_delete", scf_error()); 6689 } 6690 } 6691 6692 return (r); 6693 6694 connaborted: 6695 warn(gettext("Could not delete svc:/%s:%s " 6696 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6697 lcbdata->sc_err = ECONNABORTED; 6698 return (UU_WALK_ERROR); 6699 } 6700 6701 /* 6702 * If the service is missing, create it, import its properties, and import the 6703 * instances. Since the service is brand new, it should be empty, and if we 6704 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6705 * 6706 * If the service exists, we want to upgrade its properties and import the 6707 * instances. Upgrade requires a last-import snapshot, though, which are 6708 * children of instances, so first we'll have to go through the instances 6709 * looking for a last-import snapshot. If we don't find one then we'll just 6710 * override-import the service properties (but don't delete existing 6711 * properties: another service might have declared us as a dependent). Before 6712 * we change anything, though, we want to take the previous snapshots. We 6713 * also give lscf_instance_import() a leg up on taking last-import snapshots 6714 * by importing the manifest's service properties into a temporary service. 6715 * 6716 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6717 * sets lcbdata->sc_err to 6718 * ECONNABORTED - repository connection broken 6719 * ENOMEM - out of memory 6720 * ENOSPC - svc.configd is out of resources 6721 * EPERM - couldn't create temporary service (error printed) 6722 * - couldn't import into temp service (error printed) 6723 * - couldn't create service (error printed) 6724 * - couldn't import dependent (error printed) 6725 * - couldn't take snapshot (error printed) 6726 * - couldn't create instance (error printed) 6727 * - couldn't create, modify, or delete pg (error printed) 6728 * - couldn't create, modify, or delete dependent (error printed) 6729 * - couldn't import instance (error printed) 6730 * EROFS - couldn't create temporary service (repository read-only) 6731 * - couldn't import into temporary service (repository read-only) 6732 * - couldn't create service (repository read-only) 6733 * - couldn't import dependent (repository read-only) 6734 * - couldn't create instance (repository read-only) 6735 * - couldn't create, modify, or delete pg or dependent 6736 * - couldn't import instance (repository read-only) 6737 * EACCES - couldn't create temporary service (backend access denied) 6738 * - couldn't import into temporary service (backend access denied) 6739 * - couldn't create service (backend access denied) 6740 * - couldn't import dependent (backend access denied) 6741 * - couldn't create instance (backend access denied) 6742 * - couldn't create, modify, or delete pg or dependent 6743 * - couldn't import instance (backend access denied) 6744 * EINVAL - service name is invalid (error printed) 6745 * - service name is too long (error printed) 6746 * - s has invalid pgroup (error printed) 6747 * - s has invalid dependent (error printed) 6748 * - instance name is invalid (error printed) 6749 * - instance entity_t is invalid (error printed) 6750 * EEXIST - couldn't create temporary service (already exists) (error printed) 6751 * - couldn't import dependent (dependency pg already exists) (printed) 6752 * - dependency collision in dependent service (error printed) 6753 * EBUSY - temporary service deleted (error printed) 6754 * - property group added to temporary service (error printed) 6755 * - new property group changed or was deleted (error printed) 6756 * - service was added unexpectedly (error printed) 6757 * - service was deleted unexpectedly (error printed) 6758 * - property group added to new service (error printed) 6759 * - instance added unexpectedly (error printed) 6760 * - instance deleted unexpectedly (error printed) 6761 * - dependent service deleted unexpectedly (error printed) 6762 * - pg was added, changed, or deleted (error printed) 6763 * - dependent pg changed (error printed) 6764 * - temporary instance added, changed, or deleted (error printed) 6765 * EBADF - a last-import snapshot is corrupt (error printed) 6766 * - the service is corrupt (error printed) 6767 * - a dependent is corrupt (error printed) 6768 * - an instance is corrupt (error printed) 6769 * - an instance has a corrupt last-import snapshot (error printed) 6770 * - dependent target has a corrupt snapshot (error printed) 6771 * -1 - unknown libscf error (error printed) 6772 */ 6773 static int 6774 lscf_service_import(void *v, void *pvt) 6775 { 6776 entity_t *s = v; 6777 scf_callback_t cbdata; 6778 scf_callback_t *lcbdata = pvt; 6779 scf_scope_t *scope = lcbdata->sc_parent; 6780 entity_t *inst, linst; 6781 int r; 6782 int fresh = 0; 6783 scf_snaplevel_t *running; 6784 int have_ge = 0; 6785 6786 const char * const ts_deleted = gettext("Temporary service svc:/%s " 6787 "was deleted unexpectedly.\n"); 6788 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 6789 "changed unexpectedly (property group added).\n"); 6790 const char * const s_deleted = 6791 gettext("%s was deleted unexpectedly.\n"); 6792 const char * const i_deleted = 6793 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 6794 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 6795 "is corrupt (missing service snaplevel).\n"); 6796 const char * const s_mfile_upd = 6797 gettext("Unable to update the manifest file connection " 6798 "for %s\n"); 6799 6800 li_only = 0; 6801 /* Validate the service name */ 6802 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6803 switch (scf_error()) { 6804 case SCF_ERROR_CONNECTION_BROKEN: 6805 return (stash_scferror(lcbdata)); 6806 6807 case SCF_ERROR_INVALID_ARGUMENT: 6808 warn(gettext("\"%s\" is an invalid service name. " 6809 "Cannot import.\n"), s->sc_name); 6810 return (stash_scferror(lcbdata)); 6811 6812 case SCF_ERROR_NOT_FOUND: 6813 break; 6814 6815 case SCF_ERROR_HANDLE_MISMATCH: 6816 case SCF_ERROR_NOT_BOUND: 6817 case SCF_ERROR_NOT_SET: 6818 default: 6819 bad_error("scf_scope_get_service", scf_error()); 6820 } 6821 } 6822 6823 /* create temporary service */ 6824 /* 6825 * the size of the buffer was reduced to max_scf_name_len to prevent 6826 * hitting bug 6681151. After the bug fix, the size of the buffer 6827 * should be restored to its original value (max_scf_name_len +1) 6828 */ 6829 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 6830 if (r < 0) 6831 bad_error("snprintf", errno); 6832 if (r > max_scf_name_len) { 6833 warn(gettext( 6834 "Service name \"%s\" is too long. Cannot import.\n"), 6835 s->sc_name); 6836 lcbdata->sc_err = EINVAL; 6837 return (UU_WALK_ERROR); 6838 } 6839 6840 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 6841 switch (scf_error()) { 6842 case SCF_ERROR_CONNECTION_BROKEN: 6843 case SCF_ERROR_NO_RESOURCES: 6844 case SCF_ERROR_BACKEND_READONLY: 6845 case SCF_ERROR_BACKEND_ACCESS: 6846 return (stash_scferror(lcbdata)); 6847 6848 case SCF_ERROR_EXISTS: 6849 warn(gettext( 6850 "Temporary service \"%s\" must be deleted before " 6851 "this manifest can be imported.\n"), imp_tsname); 6852 return (stash_scferror(lcbdata)); 6853 6854 case SCF_ERROR_PERMISSION_DENIED: 6855 warn(gettext("Could not create temporary service " 6856 "\"%s\" (permission denied).\n"), imp_tsname); 6857 return (stash_scferror(lcbdata)); 6858 6859 case SCF_ERROR_INVALID_ARGUMENT: 6860 case SCF_ERROR_HANDLE_MISMATCH: 6861 case SCF_ERROR_NOT_BOUND: 6862 case SCF_ERROR_NOT_SET: 6863 default: 6864 bad_error("scf_scope_add_service", scf_error()); 6865 } 6866 } 6867 6868 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 6869 if (r < 0) 6870 bad_error("snprintf", errno); 6871 6872 cbdata.sc_handle = lcbdata->sc_handle; 6873 cbdata.sc_parent = imp_tsvc; 6874 cbdata.sc_service = 1; 6875 cbdata.sc_source_fmri = s->sc_fmri; 6876 cbdata.sc_target_fmri = imp_str; 6877 cbdata.sc_flags = 0; 6878 6879 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 6880 UU_DEFAULT) != 0) { 6881 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6882 bad_error("uu_list_walk", uu_error()); 6883 6884 lcbdata->sc_err = cbdata.sc_err; 6885 switch (cbdata.sc_err) { 6886 case ECONNABORTED: 6887 goto connaborted; 6888 6889 case ECANCELED: 6890 warn(ts_deleted, imp_tsname); 6891 lcbdata->sc_err = EBUSY; 6892 return (UU_WALK_ERROR); 6893 6894 case EEXIST: 6895 warn(ts_pg_added, imp_tsname); 6896 lcbdata->sc_err = EBUSY; 6897 return (UU_WALK_ERROR); 6898 } 6899 6900 r = UU_WALK_ERROR; 6901 goto deltemp; 6902 } 6903 6904 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 6905 UU_DEFAULT) != 0) { 6906 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6907 bad_error("uu_list_walk", uu_error()); 6908 6909 lcbdata->sc_err = cbdata.sc_err; 6910 switch (cbdata.sc_err) { 6911 case ECONNABORTED: 6912 goto connaborted; 6913 6914 case ECANCELED: 6915 warn(ts_deleted, imp_tsname); 6916 lcbdata->sc_err = EBUSY; 6917 return (UU_WALK_ERROR); 6918 6919 case EEXIST: 6920 warn(ts_pg_added, imp_tsname); 6921 lcbdata->sc_err = EBUSY; 6922 return (UU_WALK_ERROR); 6923 } 6924 6925 r = UU_WALK_ERROR; 6926 goto deltemp; 6927 } 6928 6929 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6930 switch (scf_error()) { 6931 case SCF_ERROR_NOT_FOUND: 6932 break; 6933 6934 case SCF_ERROR_CONNECTION_BROKEN: 6935 goto connaborted; 6936 6937 case SCF_ERROR_INVALID_ARGUMENT: 6938 case SCF_ERROR_HANDLE_MISMATCH: 6939 case SCF_ERROR_NOT_BOUND: 6940 case SCF_ERROR_NOT_SET: 6941 default: 6942 bad_error("scf_scope_get_service", scf_error()); 6943 } 6944 6945 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 6946 switch (scf_error()) { 6947 case SCF_ERROR_CONNECTION_BROKEN: 6948 goto connaborted; 6949 6950 case SCF_ERROR_NO_RESOURCES: 6951 case SCF_ERROR_BACKEND_READONLY: 6952 case SCF_ERROR_BACKEND_ACCESS: 6953 r = stash_scferror(lcbdata); 6954 goto deltemp; 6955 6956 case SCF_ERROR_EXISTS: 6957 warn(gettext("Scope \"%s\" changed unexpectedly" 6958 " (service \"%s\" added).\n"), 6959 SCF_SCOPE_LOCAL, s->sc_name); 6960 lcbdata->sc_err = EBUSY; 6961 goto deltemp; 6962 6963 case SCF_ERROR_PERMISSION_DENIED: 6964 warn(gettext("Could not create service \"%s\" " 6965 "(permission denied).\n"), s->sc_name); 6966 goto deltemp; 6967 6968 case SCF_ERROR_INVALID_ARGUMENT: 6969 case SCF_ERROR_HANDLE_MISMATCH: 6970 case SCF_ERROR_NOT_BOUND: 6971 case SCF_ERROR_NOT_SET: 6972 default: 6973 bad_error("scf_scope_add_service", scf_error()); 6974 } 6975 } 6976 6977 s->sc_import_state = IMPORT_PROP_BEGUN; 6978 6979 /* import service properties */ 6980 cbdata.sc_handle = lcbdata->sc_handle; 6981 cbdata.sc_parent = imp_svc; 6982 cbdata.sc_service = 1; 6983 cbdata.sc_flags = lcbdata->sc_flags; 6984 cbdata.sc_source_fmri = s->sc_fmri; 6985 cbdata.sc_target_fmri = s->sc_fmri; 6986 6987 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6988 &cbdata, UU_DEFAULT) != 0) { 6989 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6990 bad_error("uu_list_walk", uu_error()); 6991 6992 lcbdata->sc_err = cbdata.sc_err; 6993 switch (cbdata.sc_err) { 6994 case ECONNABORTED: 6995 goto connaborted; 6996 6997 case ECANCELED: 6998 warn(s_deleted, s->sc_fmri); 6999 lcbdata->sc_err = EBUSY; 7000 return (UU_WALK_ERROR); 7001 7002 case EEXIST: 7003 warn(gettext("%s changed unexpectedly " 7004 "(property group added).\n"), s->sc_fmri); 7005 lcbdata->sc_err = EBUSY; 7006 return (UU_WALK_ERROR); 7007 7008 case EINVAL: 7009 /* caught above */ 7010 bad_error("entity_pgroup_import", 7011 cbdata.sc_err); 7012 } 7013 7014 r = UU_WALK_ERROR; 7015 goto deltemp; 7016 } 7017 7018 cbdata.sc_trans = NULL; 7019 cbdata.sc_flags = 0; 7020 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 7021 &cbdata, UU_DEFAULT) != 0) { 7022 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7023 bad_error("uu_list_walk", uu_error()); 7024 7025 lcbdata->sc_err = cbdata.sc_err; 7026 if (cbdata.sc_err == ECONNABORTED) 7027 goto connaborted; 7028 r = UU_WALK_ERROR; 7029 goto deltemp; 7030 } 7031 7032 s->sc_import_state = IMPORT_PROP_DONE; 7033 7034 /* 7035 * This is a new service, so we can't take previous snapshots 7036 * or upgrade service properties. 7037 */ 7038 fresh = 1; 7039 goto instances; 7040 } 7041 7042 /* Clear sc_seen for the instances. */ 7043 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 7044 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 7045 bad_error("uu_list_walk", uu_error()); 7046 7047 /* 7048 * Take previous snapshots for all instances. Even for ones not 7049 * mentioned in the bundle, since we might change their service 7050 * properties. 7051 */ 7052 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7053 switch (scf_error()) { 7054 case SCF_ERROR_CONNECTION_BROKEN: 7055 goto connaborted; 7056 7057 case SCF_ERROR_DELETED: 7058 warn(s_deleted, s->sc_fmri); 7059 lcbdata->sc_err = EBUSY; 7060 r = UU_WALK_ERROR; 7061 goto deltemp; 7062 7063 case SCF_ERROR_HANDLE_MISMATCH: 7064 case SCF_ERROR_NOT_BOUND: 7065 case SCF_ERROR_NOT_SET: 7066 default: 7067 bad_error("scf_iter_service_instances", scf_error()); 7068 } 7069 } 7070 7071 for (;;) { 7072 r = scf_iter_next_instance(imp_iter, imp_inst); 7073 if (r == 0) 7074 break; 7075 if (r != 1) { 7076 switch (scf_error()) { 7077 case SCF_ERROR_DELETED: 7078 warn(s_deleted, s->sc_fmri); 7079 lcbdata->sc_err = EBUSY; 7080 r = UU_WALK_ERROR; 7081 goto deltemp; 7082 7083 case SCF_ERROR_CONNECTION_BROKEN: 7084 goto connaborted; 7085 7086 case SCF_ERROR_NOT_BOUND: 7087 case SCF_ERROR_HANDLE_MISMATCH: 7088 case SCF_ERROR_INVALID_ARGUMENT: 7089 case SCF_ERROR_NOT_SET: 7090 default: 7091 bad_error("scf_iter_next_instance", 7092 scf_error()); 7093 } 7094 } 7095 7096 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 7097 switch (scf_error()) { 7098 case SCF_ERROR_DELETED: 7099 continue; 7100 7101 case SCF_ERROR_CONNECTION_BROKEN: 7102 goto connaborted; 7103 7104 case SCF_ERROR_NOT_SET: 7105 case SCF_ERROR_NOT_BOUND: 7106 default: 7107 bad_error("scf_instance_get_name", scf_error()); 7108 } 7109 } 7110 7111 if (g_verbose) 7112 warn(gettext( 7113 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 7114 snap_previous, s->sc_name, imp_str); 7115 7116 r = take_snap(imp_inst, snap_previous, imp_snap); 7117 switch (r) { 7118 case 0: 7119 break; 7120 7121 case ECANCELED: 7122 continue; 7123 7124 case ECONNABORTED: 7125 goto connaborted; 7126 7127 case EPERM: 7128 warn(gettext("Could not take \"%s\" snapshot of " 7129 "svc:/%s:%s (permission denied).\n"), 7130 snap_previous, s->sc_name, imp_str); 7131 lcbdata->sc_err = r; 7132 return (UU_WALK_ERROR); 7133 7134 case ENOSPC: 7135 case -1: 7136 lcbdata->sc_err = r; 7137 r = UU_WALK_ERROR; 7138 goto deltemp; 7139 7140 default: 7141 bad_error("take_snap", r); 7142 } 7143 7144 linst.sc_name = imp_str; 7145 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 7146 &linst, NULL, NULL); 7147 if (inst != NULL) { 7148 inst->sc_import_state = IMPORT_PREVIOUS; 7149 inst->sc_seen = 1; 7150 } 7151 } 7152 7153 /* 7154 * Create the new instances and take previous snapshots of 7155 * them. This is not necessary, but it maximizes data preservation. 7156 */ 7157 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 7158 inst != NULL; 7159 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 7160 inst)) { 7161 if (inst->sc_seen) 7162 continue; 7163 7164 if (scf_service_add_instance(imp_svc, inst->sc_name, 7165 imp_inst) != 0) { 7166 switch (scf_error()) { 7167 case SCF_ERROR_CONNECTION_BROKEN: 7168 goto connaborted; 7169 7170 case SCF_ERROR_BACKEND_READONLY: 7171 case SCF_ERROR_BACKEND_ACCESS: 7172 case SCF_ERROR_NO_RESOURCES: 7173 r = stash_scferror(lcbdata); 7174 goto deltemp; 7175 7176 case SCF_ERROR_EXISTS: 7177 warn(gettext("%s changed unexpectedly " 7178 "(instance \"%s\" added).\n"), s->sc_fmri, 7179 inst->sc_name); 7180 lcbdata->sc_err = EBUSY; 7181 r = UU_WALK_ERROR; 7182 goto deltemp; 7183 7184 case SCF_ERROR_INVALID_ARGUMENT: 7185 warn(gettext("Service \"%s\" has instance with " 7186 "invalid name \"%s\".\n"), s->sc_name, 7187 inst->sc_name); 7188 r = stash_scferror(lcbdata); 7189 goto deltemp; 7190 7191 case SCF_ERROR_PERMISSION_DENIED: 7192 warn(gettext("Could not create instance \"%s\" " 7193 "in %s (permission denied).\n"), 7194 inst->sc_name, s->sc_fmri); 7195 r = stash_scferror(lcbdata); 7196 goto deltemp; 7197 7198 case SCF_ERROR_HANDLE_MISMATCH: 7199 case SCF_ERROR_NOT_BOUND: 7200 case SCF_ERROR_NOT_SET: 7201 default: 7202 bad_error("scf_service_add_instance", 7203 scf_error()); 7204 } 7205 } 7206 7207 if (g_verbose) 7208 warn(gettext("Taking \"%s\" snapshot for " 7209 "new service %s.\n"), snap_previous, inst->sc_fmri); 7210 r = take_snap(imp_inst, snap_previous, imp_snap); 7211 switch (r) { 7212 case 0: 7213 break; 7214 7215 case ECANCELED: 7216 warn(i_deleted, s->sc_fmri, inst->sc_name); 7217 lcbdata->sc_err = EBUSY; 7218 r = UU_WALK_ERROR; 7219 goto deltemp; 7220 7221 case ECONNABORTED: 7222 goto connaborted; 7223 7224 case EPERM: 7225 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 7226 lcbdata->sc_err = r; 7227 r = UU_WALK_ERROR; 7228 goto deltemp; 7229 7230 case ENOSPC: 7231 case -1: 7232 r = UU_WALK_ERROR; 7233 goto deltemp; 7234 7235 default: 7236 bad_error("take_snap", r); 7237 } 7238 } 7239 7240 s->sc_import_state = IMPORT_PREVIOUS; 7241 7242 /* 7243 * Upgrade service properties, if we can find a last-import snapshot. 7244 * Any will do because we don't support different service properties 7245 * in different manifests, so all snaplevels of the service in all of 7246 * the last-import snapshots of the instances should be the same. 7247 */ 7248 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7249 switch (scf_error()) { 7250 case SCF_ERROR_CONNECTION_BROKEN: 7251 goto connaborted; 7252 7253 case SCF_ERROR_DELETED: 7254 warn(s_deleted, s->sc_fmri); 7255 lcbdata->sc_err = EBUSY; 7256 r = UU_WALK_ERROR; 7257 goto deltemp; 7258 7259 case SCF_ERROR_HANDLE_MISMATCH: 7260 case SCF_ERROR_NOT_BOUND: 7261 case SCF_ERROR_NOT_SET: 7262 default: 7263 bad_error("scf_iter_service_instances", scf_error()); 7264 } 7265 } 7266 7267 for (;;) { 7268 r = scf_iter_next_instance(imp_iter, imp_inst); 7269 if (r == -1) { 7270 switch (scf_error()) { 7271 case SCF_ERROR_DELETED: 7272 warn(s_deleted, s->sc_fmri); 7273 lcbdata->sc_err = EBUSY; 7274 r = UU_WALK_ERROR; 7275 goto deltemp; 7276 7277 case SCF_ERROR_CONNECTION_BROKEN: 7278 goto connaborted; 7279 7280 case SCF_ERROR_NOT_BOUND: 7281 case SCF_ERROR_HANDLE_MISMATCH: 7282 case SCF_ERROR_INVALID_ARGUMENT: 7283 case SCF_ERROR_NOT_SET: 7284 default: 7285 bad_error("scf_iter_next_instance", 7286 scf_error()); 7287 } 7288 } 7289 7290 if (r == 0) { 7291 /* 7292 * Didn't find any last-import snapshots. Override- 7293 * import the properties. Unless one of the instances 7294 * has a general/enabled property, in which case we're 7295 * probably running a last-import-capable svccfg for 7296 * the first time, and we should only take the 7297 * last-import snapshot. 7298 */ 7299 if (have_ge) { 7300 pgroup_t *mfpg; 7301 scf_callback_t mfcbdata; 7302 7303 li_only = 1; 7304 no_refresh = 1; 7305 /* 7306 * Need to go ahead and import the manifestfiles 7307 * pg if it exists. If the last-import snapshot 7308 * upgrade code is ever removed this code can 7309 * be removed as well. 7310 */ 7311 mfpg = internal_pgroup_find(s, 7312 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 7313 7314 if (mfpg) { 7315 mfcbdata.sc_handle = g_hndl; 7316 mfcbdata.sc_parent = imp_svc; 7317 mfcbdata.sc_service = 1; 7318 mfcbdata.sc_flags = SCI_FORCE; 7319 mfcbdata.sc_source_fmri = s->sc_fmri; 7320 mfcbdata.sc_target_fmri = s->sc_fmri; 7321 if (entity_pgroup_import(mfpg, 7322 &mfcbdata) != UU_WALK_NEXT) { 7323 warn(s_mfile_upd, s->sc_fmri); 7324 r = UU_WALK_ERROR; 7325 goto deltemp; 7326 } 7327 } 7328 break; 7329 } 7330 7331 s->sc_import_state = IMPORT_PROP_BEGUN; 7332 7333 cbdata.sc_handle = g_hndl; 7334 cbdata.sc_parent = imp_svc; 7335 cbdata.sc_service = 1; 7336 cbdata.sc_flags = SCI_FORCE; 7337 cbdata.sc_source_fmri = s->sc_fmri; 7338 cbdata.sc_target_fmri = s->sc_fmri; 7339 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7340 &cbdata, UU_DEFAULT) != 0) { 7341 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7342 bad_error("uu_list_walk", uu_error()); 7343 lcbdata->sc_err = cbdata.sc_err; 7344 switch (cbdata.sc_err) { 7345 case ECONNABORTED: 7346 goto connaborted; 7347 7348 case ECANCELED: 7349 warn(s_deleted, s->sc_fmri); 7350 lcbdata->sc_err = EBUSY; 7351 break; 7352 7353 case EINVAL: /* caught above */ 7354 case EEXIST: 7355 bad_error("entity_pgroup_import", 7356 cbdata.sc_err); 7357 } 7358 7359 r = UU_WALK_ERROR; 7360 goto deltemp; 7361 } 7362 7363 cbdata.sc_trans = NULL; 7364 cbdata.sc_flags = 0; 7365 if (uu_list_walk(s->sc_dependents, 7366 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 7367 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7368 bad_error("uu_list_walk", uu_error()); 7369 lcbdata->sc_err = cbdata.sc_err; 7370 if (cbdata.sc_err == ECONNABORTED) 7371 goto connaborted; 7372 r = UU_WALK_ERROR; 7373 goto deltemp; 7374 } 7375 break; 7376 } 7377 7378 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 7379 imp_snap) != 0) { 7380 switch (scf_error()) { 7381 case SCF_ERROR_DELETED: 7382 continue; 7383 7384 case SCF_ERROR_NOT_FOUND: 7385 break; 7386 7387 case SCF_ERROR_CONNECTION_BROKEN: 7388 goto connaborted; 7389 7390 case SCF_ERROR_HANDLE_MISMATCH: 7391 case SCF_ERROR_NOT_BOUND: 7392 case SCF_ERROR_INVALID_ARGUMENT: 7393 case SCF_ERROR_NOT_SET: 7394 default: 7395 bad_error("scf_instance_get_snapshot", 7396 scf_error()); 7397 } 7398 7399 if (have_ge) 7400 continue; 7401 7402 /* 7403 * Check for a general/enabled property. This is how 7404 * we tell whether to import if there turn out to be 7405 * no last-import snapshots. 7406 */ 7407 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 7408 imp_pg) == 0) { 7409 if (scf_pg_get_property(imp_pg, 7410 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 7411 have_ge = 1; 7412 } else { 7413 switch (scf_error()) { 7414 case SCF_ERROR_DELETED: 7415 case SCF_ERROR_NOT_FOUND: 7416 continue; 7417 7418 case SCF_ERROR_INVALID_ARGUMENT: 7419 case SCF_ERROR_HANDLE_MISMATCH: 7420 case SCF_ERROR_CONNECTION_BROKEN: 7421 case SCF_ERROR_NOT_BOUND: 7422 case SCF_ERROR_NOT_SET: 7423 default: 7424 bad_error("scf_pg_get_property", 7425 scf_error()); 7426 } 7427 } 7428 } else { 7429 switch (scf_error()) { 7430 case SCF_ERROR_DELETED: 7431 case SCF_ERROR_NOT_FOUND: 7432 continue; 7433 7434 case SCF_ERROR_CONNECTION_BROKEN: 7435 goto connaborted; 7436 7437 case SCF_ERROR_NOT_BOUND: 7438 case SCF_ERROR_NOT_SET: 7439 case SCF_ERROR_INVALID_ARGUMENT: 7440 case SCF_ERROR_HANDLE_MISMATCH: 7441 default: 7442 bad_error("scf_instance_get_pg", 7443 scf_error()); 7444 } 7445 } 7446 continue; 7447 } 7448 7449 /* find service snaplevel */ 7450 r = get_snaplevel(imp_snap, 1, imp_snpl); 7451 switch (r) { 7452 case 0: 7453 break; 7454 7455 case ECONNABORTED: 7456 goto connaborted; 7457 7458 case ECANCELED: 7459 continue; 7460 7461 case ENOENT: 7462 if (scf_instance_get_name(imp_inst, imp_str, 7463 imp_str_sz) < 0) 7464 (void) strcpy(imp_str, "?"); 7465 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 7466 lcbdata->sc_err = EBADF; 7467 r = UU_WALK_ERROR; 7468 goto deltemp; 7469 7470 default: 7471 bad_error("get_snaplevel", r); 7472 } 7473 7474 if (scf_instance_get_snapshot(imp_inst, snap_running, 7475 imp_rsnap) != 0) { 7476 switch (scf_error()) { 7477 case SCF_ERROR_DELETED: 7478 continue; 7479 7480 case SCF_ERROR_NOT_FOUND: 7481 break; 7482 7483 case SCF_ERROR_CONNECTION_BROKEN: 7484 goto connaborted; 7485 7486 case SCF_ERROR_INVALID_ARGUMENT: 7487 case SCF_ERROR_HANDLE_MISMATCH: 7488 case SCF_ERROR_NOT_BOUND: 7489 case SCF_ERROR_NOT_SET: 7490 default: 7491 bad_error("scf_instance_get_snapshot", 7492 scf_error()); 7493 } 7494 running = NULL; 7495 } else { 7496 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7497 switch (r) { 7498 case 0: 7499 running = imp_rsnpl; 7500 break; 7501 7502 case ECONNABORTED: 7503 goto connaborted; 7504 7505 case ECANCELED: 7506 continue; 7507 7508 case ENOENT: 7509 if (scf_instance_get_name(imp_inst, imp_str, 7510 imp_str_sz) < 0) 7511 (void) strcpy(imp_str, "?"); 7512 warn(badsnap, snap_running, s->sc_name, 7513 imp_str); 7514 lcbdata->sc_err = EBADF; 7515 r = UU_WALK_ERROR; 7516 goto deltemp; 7517 7518 default: 7519 bad_error("get_snaplevel", r); 7520 } 7521 } 7522 7523 if (g_verbose) { 7524 if (scf_instance_get_name(imp_inst, imp_str, 7525 imp_str_sz) < 0) 7526 (void) strcpy(imp_str, "?"); 7527 warn(gettext("Upgrading properties of %s according to " 7528 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7529 } 7530 7531 /* upgrade service properties */ 7532 r = upgrade_props(imp_svc, running, imp_snpl, s); 7533 if (r == 0) 7534 break; 7535 7536 switch (r) { 7537 case ECONNABORTED: 7538 goto connaborted; 7539 7540 case ECANCELED: 7541 warn(s_deleted, s->sc_fmri); 7542 lcbdata->sc_err = EBUSY; 7543 break; 7544 7545 case ENODEV: 7546 if (scf_instance_get_name(imp_inst, imp_str, 7547 imp_str_sz) < 0) 7548 (void) strcpy(imp_str, "?"); 7549 warn(i_deleted, s->sc_fmri, imp_str); 7550 lcbdata->sc_err = EBUSY; 7551 break; 7552 7553 default: 7554 lcbdata->sc_err = r; 7555 } 7556 7557 r = UU_WALK_ERROR; 7558 goto deltemp; 7559 } 7560 7561 s->sc_import_state = IMPORT_PROP_DONE; 7562 7563 instances: 7564 /* import instances */ 7565 cbdata.sc_handle = lcbdata->sc_handle; 7566 cbdata.sc_parent = imp_svc; 7567 cbdata.sc_service = 1; 7568 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7569 cbdata.sc_general = NULL; 7570 7571 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7572 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7573 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7574 bad_error("uu_list_walk", uu_error()); 7575 7576 lcbdata->sc_err = cbdata.sc_err; 7577 if (cbdata.sc_err == ECONNABORTED) 7578 goto connaborted; 7579 r = UU_WALK_ERROR; 7580 goto deltemp; 7581 } 7582 7583 s->sc_import_state = IMPORT_COMPLETE; 7584 r = UU_WALK_NEXT; 7585 7586 deltemp: 7587 /* delete temporary service */ 7588 if (scf_service_delete(imp_tsvc) != 0) { 7589 switch (scf_error()) { 7590 case SCF_ERROR_DELETED: 7591 break; 7592 7593 case SCF_ERROR_CONNECTION_BROKEN: 7594 goto connaborted; 7595 7596 case SCF_ERROR_EXISTS: 7597 warn(gettext( 7598 "Could not delete svc:/%s (instances exist).\n"), 7599 imp_tsname); 7600 break; 7601 7602 case SCF_ERROR_NOT_SET: 7603 case SCF_ERROR_NOT_BOUND: 7604 default: 7605 bad_error("scf_service_delete", scf_error()); 7606 } 7607 } 7608 7609 return (r); 7610 7611 connaborted: 7612 warn(gettext("Could not delete svc:/%s " 7613 "(repository connection broken).\n"), imp_tsname); 7614 lcbdata->sc_err = ECONNABORTED; 7615 return (UU_WALK_ERROR); 7616 } 7617 7618 static const char * 7619 import_progress(int st) 7620 { 7621 switch (st) { 7622 case 0: 7623 return (gettext("not reached.")); 7624 7625 case IMPORT_PREVIOUS: 7626 return (gettext("previous snapshot taken.")); 7627 7628 case IMPORT_PROP_BEGUN: 7629 return (gettext("some properties imported.")); 7630 7631 case IMPORT_PROP_DONE: 7632 return (gettext("properties imported.")); 7633 7634 case IMPORT_COMPLETE: 7635 return (gettext("imported.")); 7636 7637 case IMPORT_REFRESHED: 7638 return (gettext("refresh requested.")); 7639 7640 default: 7641 #ifndef NDEBUG 7642 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7643 __FILE__, __LINE__, st); 7644 #endif 7645 abort(); 7646 /* NOTREACHED */ 7647 } 7648 } 7649 7650 /* 7651 * Returns 7652 * 0 - success 7653 * - fmri wasn't found (error printed) 7654 * - entity was deleted (error printed) 7655 * - backend denied access (error printed) 7656 * ENOMEM - out of memory (error printed) 7657 * ECONNABORTED - repository connection broken (error printed) 7658 * EPERM - permission denied (error printed) 7659 * -1 - unknown libscf error (error printed) 7660 */ 7661 static int 7662 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7663 { 7664 scf_error_t serr; 7665 void *ent; 7666 int issvc; 7667 int r; 7668 7669 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7670 const char *dpt_deleted = gettext("Could not refresh %s " 7671 "(dependent \"%s\" of %s) (deleted).\n"); 7672 7673 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7674 switch (serr) { 7675 case SCF_ERROR_NONE: 7676 break; 7677 7678 case SCF_ERROR_NO_MEMORY: 7679 if (name == NULL) 7680 warn(gettext("Could not refresh %s (out of memory).\n"), 7681 fmri); 7682 else 7683 warn(gettext("Could not refresh %s " 7684 "(dependent \"%s\" of %s) (out of memory).\n"), 7685 fmri, name, d_fmri); 7686 return (ENOMEM); 7687 7688 case SCF_ERROR_NOT_FOUND: 7689 if (name == NULL) 7690 warn(deleted, fmri); 7691 else 7692 warn(dpt_deleted, fmri, name, d_fmri); 7693 return (0); 7694 7695 case SCF_ERROR_INVALID_ARGUMENT: 7696 case SCF_ERROR_CONSTRAINT_VIOLATED: 7697 default: 7698 bad_error("fmri_to_entity", serr); 7699 } 7700 7701 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7702 switch (r) { 7703 case 0: 7704 break; 7705 7706 case ECONNABORTED: 7707 if (name != NULL) 7708 warn(gettext("Could not refresh %s " 7709 "(dependent \"%s\" of %s) " 7710 "(repository connection broken).\n"), fmri, name, 7711 d_fmri); 7712 return (r); 7713 7714 case ECANCELED: 7715 if (name == NULL) 7716 warn(deleted, fmri); 7717 else 7718 warn(dpt_deleted, fmri, name, d_fmri); 7719 return (0); 7720 7721 case EACCES: 7722 if (!g_verbose) 7723 return (0); 7724 if (name == NULL) 7725 warn(gettext("Could not refresh %s " 7726 "(backend access denied).\n"), fmri); 7727 else 7728 warn(gettext("Could not refresh %s " 7729 "(dependent \"%s\" of %s) " 7730 "(backend access denied).\n"), fmri, name, d_fmri); 7731 return (0); 7732 7733 case EPERM: 7734 if (name == NULL) 7735 warn(gettext("Could not refresh %s " 7736 "(permission denied).\n"), fmri); 7737 else 7738 warn(gettext("Could not refresh %s " 7739 "(dependent \"%s\" of %s) " 7740 "(permission denied).\n"), fmri, name, d_fmri); 7741 return (r); 7742 7743 case ENOSPC: 7744 if (name == NULL) 7745 warn(gettext("Could not refresh %s " 7746 "(repository server out of resources).\n"), 7747 fmri); 7748 else 7749 warn(gettext("Could not refresh %s " 7750 "(dependent \"%s\" of %s) " 7751 "(repository server out of resources).\n"), 7752 fmri, name, d_fmri); 7753 return (r); 7754 7755 case -1: 7756 scfwarn(); 7757 return (r); 7758 7759 default: 7760 bad_error("refresh_entity", r); 7761 } 7762 7763 if (issvc) 7764 scf_service_destroy(ent); 7765 else 7766 scf_instance_destroy(ent); 7767 7768 return (0); 7769 } 7770 7771 static int 7772 alloc_imp_globals() 7773 { 7774 int r; 7775 7776 const char * const emsg_nomem = gettext("Out of memory.\n"); 7777 const char * const emsg_nores = 7778 gettext("svc.configd is out of resources.\n"); 7779 7780 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 7781 max_scf_name_len : max_scf_fmri_len) + 1; 7782 7783 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 7784 (imp_svc = scf_service_create(g_hndl)) == NULL || 7785 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 7786 (imp_inst = scf_instance_create(g_hndl)) == NULL || 7787 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 7788 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 7789 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 7790 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 7791 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 7792 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7793 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 7794 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7795 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 7796 (imp_prop = scf_property_create(g_hndl)) == NULL || 7797 (imp_iter = scf_iter_create(g_hndl)) == NULL || 7798 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 7799 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 7800 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 7801 (imp_str = malloc(imp_str_sz)) == NULL || 7802 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 7803 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 7804 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 7805 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 7806 (ud_inst = scf_instance_create(g_hndl)) == NULL || 7807 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7808 (ud_pg = scf_pg_create(g_hndl)) == NULL || 7809 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 7810 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 7811 (ud_prop = scf_property_create(g_hndl)) == NULL || 7812 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 7813 (ud_val = scf_value_create(g_hndl)) == NULL || 7814 (ud_iter = scf_iter_create(g_hndl)) == NULL || 7815 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 7816 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 7817 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 7818 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 7819 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 7820 if (scf_error() == SCF_ERROR_NO_RESOURCES) 7821 warn(emsg_nores); 7822 else 7823 warn(emsg_nomem); 7824 7825 return (-1); 7826 } 7827 7828 r = load_init(); 7829 switch (r) { 7830 case 0: 7831 break; 7832 7833 case ENOMEM: 7834 warn(emsg_nomem); 7835 return (-1); 7836 7837 default: 7838 bad_error("load_init", r); 7839 } 7840 7841 return (0); 7842 } 7843 7844 static void 7845 free_imp_globals() 7846 { 7847 pgroup_t *old_dpt; 7848 void *cookie; 7849 7850 load_fini(); 7851 7852 free(ud_ctarg); 7853 free(ud_oldtarg); 7854 free(ud_name); 7855 ud_ctarg = ud_oldtarg = ud_name = NULL; 7856 7857 scf_transaction_destroy(ud_tx); 7858 ud_tx = NULL; 7859 scf_iter_destroy(ud_iter); 7860 scf_iter_destroy(ud_iter2); 7861 ud_iter = ud_iter2 = NULL; 7862 scf_value_destroy(ud_val); 7863 ud_val = NULL; 7864 scf_property_destroy(ud_prop); 7865 scf_property_destroy(ud_dpt_prop); 7866 ud_prop = ud_dpt_prop = NULL; 7867 scf_pg_destroy(ud_pg); 7868 scf_pg_destroy(ud_cur_depts_pg); 7869 scf_pg_destroy(ud_run_dpts_pg); 7870 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7871 scf_snaplevel_destroy(ud_snpl); 7872 ud_snpl = NULL; 7873 scf_instance_destroy(ud_inst); 7874 ud_inst = NULL; 7875 7876 free(imp_str); 7877 free(imp_tsname); 7878 free(imp_fe1); 7879 free(imp_fe2); 7880 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7881 7882 cookie = NULL; 7883 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7884 NULL) { 7885 free((char *)old_dpt->sc_pgroup_name); 7886 free((char *)old_dpt->sc_pgroup_fmri); 7887 internal_pgroup_free(old_dpt); 7888 } 7889 uu_list_destroy(imp_deleted_dpts); 7890 7891 scf_transaction_destroy(imp_tx); 7892 imp_tx = NULL; 7893 scf_iter_destroy(imp_iter); 7894 scf_iter_destroy(imp_rpg_iter); 7895 scf_iter_destroy(imp_up_iter); 7896 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7897 scf_property_destroy(imp_prop); 7898 imp_prop = NULL; 7899 scf_pg_destroy(imp_pg); 7900 scf_pg_destroy(imp_pg2); 7901 imp_pg = imp_pg2 = NULL; 7902 scf_snaplevel_destroy(imp_snpl); 7903 scf_snaplevel_destroy(imp_rsnpl); 7904 imp_snpl = imp_rsnpl = NULL; 7905 scf_snapshot_destroy(imp_snap); 7906 scf_snapshot_destroy(imp_lisnap); 7907 scf_snapshot_destroy(imp_tlisnap); 7908 scf_snapshot_destroy(imp_rsnap); 7909 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7910 scf_instance_destroy(imp_inst); 7911 scf_instance_destroy(imp_tinst); 7912 imp_inst = imp_tinst = NULL; 7913 scf_service_destroy(imp_svc); 7914 scf_service_destroy(imp_tsvc); 7915 imp_svc = imp_tsvc = NULL; 7916 scf_scope_destroy(imp_scope); 7917 imp_scope = NULL; 7918 7919 load_fini(); 7920 } 7921 7922 int 7923 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 7924 { 7925 scf_callback_t cbdata; 7926 int result = 0; 7927 entity_t *svc, *inst; 7928 uu_list_t *insts; 7929 int r; 7930 pgroup_t *old_dpt; 7931 int annotation_set = 0; 7932 7933 const char * const emsg_nomem = gettext("Out of memory.\n"); 7934 const char * const emsg_nores = 7935 gettext("svc.configd is out of resources.\n"); 7936 7937 lscf_prep_hndl(); 7938 7939 if (alloc_imp_globals()) 7940 goto out; 7941 7942 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 7943 switch (scf_error()) { 7944 case SCF_ERROR_CONNECTION_BROKEN: 7945 warn(gettext("Repository connection broken.\n")); 7946 repository_teardown(); 7947 result = -1; 7948 goto out; 7949 7950 case SCF_ERROR_NOT_FOUND: 7951 case SCF_ERROR_INVALID_ARGUMENT: 7952 case SCF_ERROR_NOT_BOUND: 7953 case SCF_ERROR_HANDLE_MISMATCH: 7954 default: 7955 bad_error("scf_handle_get_scope", scf_error()); 7956 } 7957 } 7958 7959 /* Set up the auditing annotation. */ 7960 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 7961 annotation_set = 1; 7962 } else { 7963 switch (scf_error()) { 7964 case SCF_ERROR_CONNECTION_BROKEN: 7965 warn(gettext("Repository connection broken.\n")); 7966 repository_teardown(); 7967 result = -1; 7968 goto out; 7969 7970 case SCF_ERROR_INVALID_ARGUMENT: 7971 case SCF_ERROR_NOT_BOUND: 7972 case SCF_ERROR_NO_RESOURCES: 7973 case SCF_ERROR_INTERNAL: 7974 bad_error("_scf_set_annotation", scf_error()); 7975 /* NOTREACHED */ 7976 7977 default: 7978 /* 7979 * Do not terminate import because of inability to 7980 * generate annotation audit event. 7981 */ 7982 warn(gettext("_scf_set_annotation() unexpectedly " 7983 "failed with return code of %d\n"), scf_error()); 7984 break; 7985 } 7986 } 7987 7988 /* 7989 * Clear the sc_import_state's of all services & instances so we can 7990 * report how far we got if we fail. 7991 */ 7992 for (svc = uu_list_first(bndl->sc_bundle_services); 7993 svc != NULL; 7994 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7995 svc->sc_import_state = 0; 7996 7997 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 7998 clear_int, (void *)offsetof(entity_t, sc_import_state), 7999 UU_DEFAULT) != 0) 8000 bad_error("uu_list_walk", uu_error()); 8001 } 8002 8003 cbdata.sc_handle = g_hndl; 8004 cbdata.sc_parent = imp_scope; 8005 cbdata.sc_flags = flags; 8006 cbdata.sc_general = NULL; 8007 8008 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 8009 &cbdata, UU_DEFAULT) == 0) { 8010 /* Success. Refresh everything. */ 8011 8012 if (flags & SCI_NOREFRESH || no_refresh) { 8013 no_refresh = 0; 8014 result = 0; 8015 goto out; 8016 } 8017 8018 for (svc = uu_list_first(bndl->sc_bundle_services); 8019 svc != NULL; 8020 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8021 pgroup_t *dpt; 8022 8023 insts = svc->sc_u.sc_service.sc_service_instances; 8024 8025 for (inst = uu_list_first(insts); 8026 inst != NULL; 8027 inst = uu_list_next(insts, inst)) { 8028 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 8029 switch (r) { 8030 case 0: 8031 break; 8032 8033 case ENOMEM: 8034 case ECONNABORTED: 8035 case EPERM: 8036 case -1: 8037 goto progress; 8038 8039 default: 8040 bad_error("imp_refresh_fmri", r); 8041 } 8042 8043 inst->sc_import_state = IMPORT_REFRESHED; 8044 8045 for (dpt = uu_list_first(inst->sc_dependents); 8046 dpt != NULL; 8047 dpt = uu_list_next(inst->sc_dependents, 8048 dpt)) 8049 if (imp_refresh_fmri( 8050 dpt->sc_pgroup_fmri, 8051 dpt->sc_pgroup_name, 8052 inst->sc_fmri) != 0) 8053 goto progress; 8054 } 8055 8056 for (dpt = uu_list_first(svc->sc_dependents); 8057 dpt != NULL; 8058 dpt = uu_list_next(svc->sc_dependents, dpt)) 8059 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 8060 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 8061 goto progress; 8062 } 8063 8064 for (old_dpt = uu_list_first(imp_deleted_dpts); 8065 old_dpt != NULL; 8066 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 8067 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8068 old_dpt->sc_pgroup_name, 8069 old_dpt->sc_parent->sc_fmri) != 0) 8070 goto progress; 8071 8072 result = 0; 8073 goto out; 8074 } 8075 8076 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8077 bad_error("uu_list_walk", uu_error()); 8078 8079 printerr: 8080 /* If the error hasn't been printed yet, do so here. */ 8081 switch (cbdata.sc_err) { 8082 case ECONNABORTED: 8083 warn(gettext("Repository connection broken.\n")); 8084 break; 8085 8086 case ENOMEM: 8087 warn(emsg_nomem); 8088 break; 8089 8090 case ENOSPC: 8091 warn(emsg_nores); 8092 break; 8093 8094 case EROFS: 8095 warn(gettext("Repository is read-only.\n")); 8096 break; 8097 8098 case EACCES: 8099 warn(gettext("Repository backend denied access.\n")); 8100 break; 8101 8102 case EPERM: 8103 case EINVAL: 8104 case EEXIST: 8105 case EBUSY: 8106 case EBADF: 8107 case -1: 8108 break; 8109 8110 default: 8111 bad_error("lscf_service_import", cbdata.sc_err); 8112 } 8113 8114 progress: 8115 warn(gettext("Import of %s failed. Progress:\n"), filename); 8116 8117 for (svc = uu_list_first(bndl->sc_bundle_services); 8118 svc != NULL; 8119 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8120 insts = svc->sc_u.sc_service.sc_service_instances; 8121 8122 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 8123 import_progress(svc->sc_import_state)); 8124 8125 for (inst = uu_list_first(insts); 8126 inst != NULL; 8127 inst = uu_list_next(insts, inst)) 8128 warn(gettext(" Instance \"%s\": %s\n"), 8129 inst->sc_name, 8130 import_progress(inst->sc_import_state)); 8131 } 8132 8133 if (cbdata.sc_err == ECONNABORTED) 8134 repository_teardown(); 8135 8136 8137 result = -1; 8138 8139 out: 8140 if (annotation_set != 0) { 8141 /* Turn off annotation. It is no longer needed. */ 8142 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8143 } 8144 8145 free_imp_globals(); 8146 8147 return (result); 8148 } 8149 8150 /* 8151 * _lscf_import_err() summarize the error handling returned by 8152 * lscf_import_{instance | service}_pgs 8153 * Return values are: 8154 * IMPORT_NEXT 8155 * IMPORT_OUT 8156 * IMPORT_BAD 8157 */ 8158 8159 #define IMPORT_BAD -1 8160 #define IMPORT_NEXT 0 8161 #define IMPORT_OUT 1 8162 8163 static int 8164 _lscf_import_err(int err, const char *fmri) 8165 { 8166 switch (err) { 8167 case 0: 8168 if (g_verbose) 8169 warn(gettext("%s updated.\n"), fmri); 8170 return (IMPORT_NEXT); 8171 8172 case ECONNABORTED: 8173 warn(gettext("Could not update %s " 8174 "(repository connection broken).\n"), fmri); 8175 return (IMPORT_OUT); 8176 8177 case ENOMEM: 8178 warn(gettext("Could not update %s (out of memory).\n"), fmri); 8179 return (IMPORT_OUT); 8180 8181 case ENOSPC: 8182 warn(gettext("Could not update %s " 8183 "(repository server out of resources).\n"), fmri); 8184 return (IMPORT_OUT); 8185 8186 case ECANCELED: 8187 warn(gettext( 8188 "Could not update %s (deleted).\n"), fmri); 8189 return (IMPORT_NEXT); 8190 8191 case EPERM: 8192 case EINVAL: 8193 case EBUSY: 8194 return (IMPORT_NEXT); 8195 8196 case EROFS: 8197 warn(gettext("Could not update %s (repository read-only).\n"), 8198 fmri); 8199 return (IMPORT_OUT); 8200 8201 case EACCES: 8202 warn(gettext("Could not update %s " 8203 "(backend access denied).\n"), fmri); 8204 return (IMPORT_NEXT); 8205 8206 case EEXIST: 8207 default: 8208 return (IMPORT_BAD); 8209 } 8210 8211 /*NOTREACHED*/ 8212 } 8213 8214 /* 8215 * The global imp_svc and imp_inst should be set by the caller in the 8216 * check to make sure the service and instance exist that the apply is 8217 * working on. 8218 */ 8219 static int 8220 lscf_dependent_apply(void *dpg, void *e) 8221 { 8222 scf_callback_t cb; 8223 pgroup_t *dpt_pgroup = dpg; 8224 pgroup_t *deldpt; 8225 entity_t *ent = e; 8226 int tissvc; 8227 void *sc_ent, *tent; 8228 scf_error_t serr; 8229 int r; 8230 8231 const char * const dependents = "dependents"; 8232 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT); 8233 8234 if (issvc) 8235 sc_ent = imp_svc; 8236 else 8237 sc_ent = imp_inst; 8238 8239 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg, 8240 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 || 8241 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name, 8242 imp_prop) != 0) { 8243 switch (scf_error()) { 8244 case SCF_ERROR_NOT_FOUND: 8245 case SCF_ERROR_DELETED: 8246 break; 8247 8248 case SCF_ERROR_CONNECTION_BROKEN: 8249 case SCF_ERROR_NOT_SET: 8250 case SCF_ERROR_INVALID_ARGUMENT: 8251 case SCF_ERROR_HANDLE_MISMATCH: 8252 case SCF_ERROR_NOT_BOUND: 8253 default: 8254 bad_error("entity_get_pg", scf_error()); 8255 } 8256 } else { 8257 /* 8258 * Found the dependents/<wip dep> so check to 8259 * see if the service is different. If so 8260 * store the service for later refresh, and 8261 * delete the wip dependency from the service 8262 */ 8263 if (scf_property_get_value(imp_prop, ud_val) != 0) { 8264 switch (scf_error()) { 8265 case SCF_ERROR_DELETED: 8266 break; 8267 8268 case SCF_ERROR_CONNECTION_BROKEN: 8269 case SCF_ERROR_NOT_SET: 8270 case SCF_ERROR_INVALID_ARGUMENT: 8271 case SCF_ERROR_HANDLE_MISMATCH: 8272 case SCF_ERROR_NOT_BOUND: 8273 default: 8274 bad_error("scf_property_get_value", 8275 scf_error()); 8276 } 8277 } 8278 8279 if (scf_value_get_as_string(ud_val, ud_oldtarg, 8280 max_scf_value_len + 1) < 0) 8281 bad_error("scf_value_get_as_string", scf_error()); 8282 8283 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 8284 switch (r) { 8285 case 1: 8286 break; 8287 case 0: 8288 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent, 8289 &tissvc)) != SCF_ERROR_NONE) { 8290 if (serr == SCF_ERROR_NOT_FOUND) { 8291 break; 8292 } else { 8293 bad_error("fmri_to_entity", serr); 8294 } 8295 } 8296 8297 if (entity_get_pg(tent, tissvc, 8298 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) { 8299 serr = scf_error(); 8300 if (serr == SCF_ERROR_NOT_FOUND || 8301 serr == SCF_ERROR_DELETED) { 8302 break; 8303 } else { 8304 bad_error("entity_get_pg", scf_error()); 8305 } 8306 } 8307 8308 if (scf_pg_delete(imp_pg) != 0) { 8309 serr = scf_error(); 8310 if (serr == SCF_ERROR_NOT_FOUND || 8311 serr == SCF_ERROR_DELETED) { 8312 break; 8313 } else { 8314 bad_error("scf_pg_delete", scf_error()); 8315 } 8316 } 8317 8318 deldpt = internal_pgroup_new(); 8319 if (deldpt == NULL) 8320 return (ENOMEM); 8321 deldpt->sc_pgroup_name = 8322 strdup(dpt_pgroup->sc_pgroup_name); 8323 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg); 8324 if (deldpt->sc_pgroup_name == NULL || 8325 deldpt->sc_pgroup_fmri == NULL) 8326 return (ENOMEM); 8327 deldpt->sc_parent = (entity_t *)ent; 8328 if (uu_list_insert_after(imp_deleted_dpts, NULL, 8329 deldpt) != 0) 8330 uu_die(gettext("libuutil error: %s\n"), 8331 uu_strerror(uu_error())); 8332 8333 break; 8334 default: 8335 bad_error("fmri_equal", r); 8336 } 8337 } 8338 8339 cb.sc_handle = g_hndl; 8340 cb.sc_parent = ent; 8341 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT; 8342 cb.sc_source_fmri = ent->sc_fmri; 8343 cb.sc_target_fmri = ent->sc_fmri; 8344 cb.sc_trans = NULL; 8345 cb.sc_flags = SCI_FORCE; 8346 8347 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT) 8348 return (UU_WALK_ERROR); 8349 8350 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL); 8351 switch (r) { 8352 case 0: 8353 break; 8354 8355 case ENOMEM: 8356 case ECONNABORTED: 8357 case EPERM: 8358 case -1: 8359 warn(gettext("Unable to refresh \"%s\"\n"), 8360 dpt_pgroup->sc_pgroup_fmri); 8361 return (UU_WALK_ERROR); 8362 8363 default: 8364 bad_error("imp_refresh_fmri", r); 8365 } 8366 8367 return (UU_WALK_NEXT); 8368 } 8369 8370 /* 8371 * Returns 8372 * 0 - success 8373 * -1 - lscf_import_instance_pgs() failed. 8374 */ 8375 int 8376 lscf_bundle_apply(bundle_t *bndl, const char *file) 8377 { 8378 pgroup_t *old_dpt; 8379 entity_t *svc, *inst; 8380 int annotation_set = 0; 8381 int ret = 0; 8382 int r = 0; 8383 8384 lscf_prep_hndl(); 8385 8386 if ((ret = alloc_imp_globals())) 8387 goto out; 8388 8389 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) 8390 scfdie(); 8391 8392 /* 8393 * Set the strings to be used for the security audit annotation 8394 * event. 8395 */ 8396 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 8397 annotation_set = 1; 8398 } else { 8399 switch (scf_error()) { 8400 case SCF_ERROR_CONNECTION_BROKEN: 8401 warn(gettext("Repository connection broken.\n")); 8402 goto out; 8403 8404 case SCF_ERROR_INVALID_ARGUMENT: 8405 case SCF_ERROR_NOT_BOUND: 8406 case SCF_ERROR_NO_RESOURCES: 8407 case SCF_ERROR_INTERNAL: 8408 bad_error("_scf_set_annotation", scf_error()); 8409 /* NOTREACHED */ 8410 8411 default: 8412 /* 8413 * Do not abort apply operation because of 8414 * inability to create annotation audit event. 8415 */ 8416 warn(gettext("_scf_set_annotation() unexpectedly " 8417 "failed with return code of %d\n"), scf_error()); 8418 break; 8419 } 8420 } 8421 8422 for (svc = uu_list_first(bndl->sc_bundle_services); 8423 svc != NULL; 8424 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8425 int refresh = 0; 8426 8427 if (scf_scope_get_service(imp_scope, svc->sc_name, 8428 imp_svc) != 0) { 8429 switch (scf_error()) { 8430 case SCF_ERROR_NOT_FOUND: 8431 if (g_verbose) 8432 warn(gettext("Ignoring nonexistent " 8433 "service %s.\n"), svc->sc_name); 8434 continue; 8435 8436 default: 8437 scfdie(); 8438 } 8439 } 8440 8441 /* 8442 * If there were missing types in the profile, then need to 8443 * attempt to find the types. 8444 */ 8445 if (svc->sc_miss_type) { 8446 if (uu_list_numnodes(svc->sc_pgroups) && 8447 uu_list_walk(svc->sc_pgroups, find_current_pg_type, 8448 svc, UU_DEFAULT) != 0) { 8449 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8450 bad_error("uu_list_walk", uu_error()); 8451 8452 ret = -1; 8453 continue; 8454 } 8455 8456 for (inst = uu_list_first( 8457 svc->sc_u.sc_service.sc_service_instances); 8458 inst != NULL; 8459 inst = uu_list_next( 8460 svc->sc_u.sc_service.sc_service_instances, inst)) { 8461 /* 8462 * If the instance doesn't exist just 8463 * skip to the next instance and let the 8464 * import note the missing instance. 8465 */ 8466 if (scf_service_get_instance(imp_svc, 8467 inst->sc_name, imp_inst) != 0) 8468 continue; 8469 8470 if (uu_list_walk(inst->sc_pgroups, 8471 find_current_pg_type, inst, 8472 UU_DEFAULT) != 0) { 8473 if (uu_error() != 8474 UU_ERROR_CALLBACK_FAILED) 8475 bad_error("uu_list_walk", 8476 uu_error()); 8477 8478 ret = -1; 8479 inst->sc_miss_type = B_TRUE; 8480 } 8481 } 8482 } 8483 8484 /* 8485 * if we have pgs in the profile, we need to refresh ALL 8486 * instances of the service 8487 */ 8488 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 8489 refresh = 1; 8490 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc, 8491 SCI_FORCE | SCI_KEEP); 8492 switch (_lscf_import_err(r, svc->sc_fmri)) { 8493 case IMPORT_NEXT: 8494 break; 8495 8496 case IMPORT_OUT: 8497 goto out; 8498 8499 case IMPORT_BAD: 8500 default: 8501 bad_error("lscf_import_service_pgs", r); 8502 } 8503 } 8504 8505 if (uu_list_numnodes(svc->sc_dependents) != 0) { 8506 uu_list_walk(svc->sc_dependents, 8507 lscf_dependent_apply, svc, UU_DEFAULT); 8508 } 8509 8510 for (inst = uu_list_first( 8511 svc->sc_u.sc_service.sc_service_instances); 8512 inst != NULL; 8513 inst = uu_list_next( 8514 svc->sc_u.sc_service.sc_service_instances, inst)) { 8515 /* 8516 * This instance still has missing types 8517 * so skip it. 8518 */ 8519 if (inst->sc_miss_type) { 8520 if (g_verbose) 8521 warn(gettext("Ignoring instance " 8522 "%s:%s with missing types\n"), 8523 inst->sc_parent->sc_name, 8524 inst->sc_name); 8525 8526 continue; 8527 } 8528 8529 if (scf_service_get_instance(imp_svc, inst->sc_name, 8530 imp_inst) != 0) { 8531 switch (scf_error()) { 8532 case SCF_ERROR_NOT_FOUND: 8533 if (g_verbose) 8534 warn(gettext("Ignoring " 8535 "nonexistant instance " 8536 "%s:%s.\n"), 8537 inst->sc_parent->sc_name, 8538 inst->sc_name); 8539 continue; 8540 8541 default: 8542 scfdie(); 8543 } 8544 } 8545 8546 /* 8547 * If the instance does not have a general/enabled 8548 * property and no last-import snapshot then the 8549 * instance is not a fully installed instance and 8550 * should not have a profile applied to it. 8551 * 8552 * This could happen if a service/instance declares 8553 * a dependent on behalf of another service/instance. 8554 * 8555 */ 8556 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 8557 imp_snap) != 0) { 8558 if (scf_instance_get_pg(imp_inst, 8559 SCF_PG_GENERAL, imp_pg) != 0 || 8560 scf_pg_get_property(imp_pg, 8561 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 8562 if (g_verbose) 8563 warn(gettext("Ignoreing " 8564 "partial instance " 8565 "%s:%s.\n"), 8566 inst->sc_parent->sc_name, 8567 inst->sc_name); 8568 continue; 8569 } 8570 } 8571 8572 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, 8573 inst, SCI_FORCE | SCI_KEEP); 8574 switch (_lscf_import_err(r, inst->sc_fmri)) { 8575 case IMPORT_NEXT: 8576 break; 8577 8578 case IMPORT_OUT: 8579 goto out; 8580 8581 case IMPORT_BAD: 8582 default: 8583 bad_error("lscf_import_instance_pgs", r); 8584 } 8585 8586 if (uu_list_numnodes(inst->sc_dependents) != 0) { 8587 uu_list_walk(inst->sc_dependents, 8588 lscf_dependent_apply, inst, UU_DEFAULT); 8589 } 8590 8591 /* refresh only if there is no pgs in the service */ 8592 if (refresh == 0) 8593 (void) refresh_entity(0, imp_inst, 8594 inst->sc_fmri, NULL, NULL, NULL); 8595 } 8596 8597 if (refresh == 1) { 8598 char *name_buf = safe_malloc(max_scf_name_len + 1); 8599 8600 (void) refresh_entity(1, imp_svc, svc->sc_name, 8601 imp_inst, imp_iter, name_buf); 8602 free(name_buf); 8603 } 8604 8605 for (old_dpt = uu_list_first(imp_deleted_dpts); 8606 old_dpt != NULL; 8607 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) { 8608 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8609 old_dpt->sc_pgroup_name, 8610 old_dpt->sc_parent->sc_fmri) != 0) { 8611 warn(gettext("Unable to refresh \"%s\"\n"), 8612 old_dpt->sc_pgroup_fmri); 8613 } 8614 } 8615 } 8616 8617 out: 8618 if (annotation_set) { 8619 /* Remove security audit annotation strings. */ 8620 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8621 } 8622 8623 free_imp_globals(); 8624 return (ret); 8625 } 8626 8627 8628 /* 8629 * Export. These functions create and output an XML tree of a service 8630 * description from the repository. This is largely the inverse of 8631 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 8632 * 8633 * - We must include any properties which are not represented specifically by 8634 * a service manifest, e.g., properties created by an admin post-import. To 8635 * do so we'll iterate through all properties and deal with each 8636 * apropriately. 8637 * 8638 * - Children of services and instances must must be in the order set by the 8639 * DTD, but we iterate over the properties in undefined order. The elements 8640 * are not easily (or efficiently) sortable by name. Since there's a fixed 8641 * number of classes of them, however, we'll keep the classes separate and 8642 * assemble them in order. 8643 */ 8644 8645 /* 8646 * Convenience function to handle xmlSetProp errors (and type casting). 8647 */ 8648 static void 8649 safe_setprop(xmlNodePtr n, const char *name, const char *val) 8650 { 8651 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 8652 uu_die(gettext("Could not set XML property.\n")); 8653 } 8654 8655 /* 8656 * Convenience function to set an XML attribute to the single value of an 8657 * astring property. If the value happens to be the default, don't set the 8658 * attribute. "dval" should be the default value supplied by the DTD, or 8659 * NULL for no default. 8660 */ 8661 static int 8662 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 8663 const char *name, const char *dval) 8664 { 8665 scf_value_t *val; 8666 ssize_t len; 8667 char *str; 8668 8669 val = scf_value_create(g_hndl); 8670 if (val == NULL) 8671 scfdie(); 8672 8673 if (prop_get_val(prop, val) != 0) { 8674 scf_value_destroy(val); 8675 return (-1); 8676 } 8677 8678 len = scf_value_get_as_string(val, NULL, 0); 8679 if (len < 0) 8680 scfdie(); 8681 8682 str = safe_malloc(len + 1); 8683 8684 if (scf_value_get_as_string(val, str, len + 1) < 0) 8685 scfdie(); 8686 8687 scf_value_destroy(val); 8688 8689 if (dval == NULL || strcmp(str, dval) != 0) 8690 safe_setprop(n, name, str); 8691 8692 free(str); 8693 8694 return (0); 8695 } 8696 8697 /* 8698 * As above, but the attribute is always set. 8699 */ 8700 static int 8701 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 8702 { 8703 return (set_attr_from_prop_default(prop, n, name, NULL)); 8704 } 8705 8706 /* 8707 * Dump the given document onto f, with "'s replaced by ''s. 8708 */ 8709 static int 8710 write_service_bundle(xmlDocPtr doc, FILE *f) 8711 { 8712 xmlChar *mem; 8713 int sz, i; 8714 8715 mem = NULL; 8716 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 8717 8718 if (mem == NULL) { 8719 semerr(gettext("Could not dump XML tree.\n")); 8720 return (-1); 8721 } 8722 8723 /* 8724 * Fortunately libxml produces " instead of ", so we can blindly 8725 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 8726 * ' code?! 8727 */ 8728 for (i = 0; i < sz; ++i) { 8729 char c = (char)mem[i]; 8730 8731 if (c == '"') 8732 (void) fputc('\'', f); 8733 else if (c == '\'') 8734 (void) fwrite("'", sizeof ("'") - 1, 1, f); 8735 else 8736 (void) fputc(c, f); 8737 } 8738 8739 return (0); 8740 } 8741 8742 /* 8743 * Create the DOM elements in elts necessary to (generically) represent prop 8744 * (i.e., a property or propval element). If the name of the property is 8745 * known, it should be passed as name_arg. Otherwise, pass NULL. 8746 */ 8747 static void 8748 export_property(scf_property_t *prop, const char *name_arg, 8749 struct pg_elts *elts, int flags) 8750 { 8751 const char *type; 8752 scf_error_t err = 0; 8753 xmlNodePtr pnode, lnode; 8754 char *lnname; 8755 int ret; 8756 8757 /* name */ 8758 if (name_arg != NULL) { 8759 (void) strcpy(exp_str, name_arg); 8760 } else { 8761 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 8762 scfdie(); 8763 } 8764 8765 /* type */ 8766 type = prop_to_typestr(prop); 8767 if (type == NULL) 8768 uu_die(gettext("Can't export property %s: unknown type.\n"), 8769 exp_str); 8770 8771 /* If we're exporting values, and there's just one, export it here. */ 8772 if (!(flags & SCE_ALL_VALUES)) 8773 goto empty; 8774 8775 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 8776 xmlNodePtr n; 8777 8778 /* Single value, so use propval */ 8779 n = xmlNewNode(NULL, (xmlChar *)"propval"); 8780 if (n == NULL) 8781 uu_die(emsg_create_xml); 8782 8783 safe_setprop(n, name_attr, exp_str); 8784 safe_setprop(n, type_attr, type); 8785 8786 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8787 scfdie(); 8788 safe_setprop(n, value_attr, exp_str); 8789 8790 if (elts->propvals == NULL) 8791 elts->propvals = n; 8792 else 8793 (void) xmlAddSibling(elts->propvals, n); 8794 8795 return; 8796 } 8797 8798 err = scf_error(); 8799 8800 if (err == SCF_ERROR_PERMISSION_DENIED) { 8801 semerr(emsg_permission_denied); 8802 return; 8803 } 8804 8805 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 8806 err != SCF_ERROR_NOT_FOUND && 8807 err != SCF_ERROR_PERMISSION_DENIED) 8808 scfdie(); 8809 8810 empty: 8811 /* Multiple (or no) values, so use property */ 8812 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 8813 if (pnode == NULL) 8814 uu_die(emsg_create_xml); 8815 8816 safe_setprop(pnode, name_attr, exp_str); 8817 safe_setprop(pnode, type_attr, type); 8818 8819 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 8820 lnname = uu_msprintf("%s_list", type); 8821 if (lnname == NULL) 8822 uu_die(gettext("Could not create string")); 8823 8824 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 8825 if (lnode == NULL) 8826 uu_die(emsg_create_xml); 8827 8828 uu_free(lnname); 8829 8830 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 8831 scfdie(); 8832 8833 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 8834 1) { 8835 xmlNodePtr vn; 8836 8837 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 8838 NULL); 8839 if (vn == NULL) 8840 uu_die(emsg_create_xml); 8841 8842 if (scf_value_get_as_string(exp_val, exp_str, 8843 exp_str_sz) < 0) 8844 scfdie(); 8845 safe_setprop(vn, value_attr, exp_str); 8846 } 8847 if (ret != 0) 8848 scfdie(); 8849 } 8850 8851 if (elts->properties == NULL) 8852 elts->properties = pnode; 8853 else 8854 (void) xmlAddSibling(elts->properties, pnode); 8855 } 8856 8857 /* 8858 * Add a property_group element for this property group to elts. 8859 */ 8860 static void 8861 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 8862 { 8863 xmlNodePtr n; 8864 struct pg_elts elts; 8865 int ret; 8866 boolean_t read_protected; 8867 8868 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 8869 8870 /* name */ 8871 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8872 scfdie(); 8873 safe_setprop(n, name_attr, exp_str); 8874 8875 /* type */ 8876 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 8877 scfdie(); 8878 safe_setprop(n, type_attr, exp_str); 8879 8880 /* properties */ 8881 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8882 scfdie(); 8883 8884 (void) memset(&elts, 0, sizeof (elts)); 8885 8886 /* 8887 * If this property group is not read protected, we always want to 8888 * output all the values. Otherwise, we only output the values if the 8889 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 8890 */ 8891 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 8892 scfdie(); 8893 8894 if (!read_protected) 8895 flags |= SCE_ALL_VALUES; 8896 8897 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8898 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8899 scfdie(); 8900 8901 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8902 xmlNodePtr m; 8903 8904 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8905 if (m == NULL) 8906 uu_die(emsg_create_xml); 8907 8908 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8909 elts.stability = m; 8910 continue; 8911 } 8912 8913 xmlFreeNode(m); 8914 } 8915 8916 export_property(exp_prop, NULL, &elts, flags); 8917 } 8918 if (ret == -1) 8919 scfdie(); 8920 8921 (void) xmlAddChild(n, elts.stability); 8922 (void) xmlAddChildList(n, elts.propvals); 8923 (void) xmlAddChildList(n, elts.properties); 8924 8925 if (eelts->property_groups == NULL) 8926 eelts->property_groups = n; 8927 else 8928 (void) xmlAddSibling(eelts->property_groups, n); 8929 } 8930 8931 /* 8932 * Create an XML node representing the dependency described by the given 8933 * property group and put it in eelts. Unless the dependency is not valid, in 8934 * which case create a generic property_group element which represents it and 8935 * put it in eelts. 8936 */ 8937 static void 8938 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 8939 { 8940 xmlNodePtr n; 8941 int err = 0, ret; 8942 struct pg_elts elts; 8943 8944 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 8945 if (n == NULL) 8946 uu_die(emsg_create_xml); 8947 8948 /* 8949 * If the external flag is present, skip this dependency because it 8950 * should have been created by another manifest. 8951 */ 8952 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 8953 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8954 prop_get_val(exp_prop, exp_val) == 0) { 8955 uint8_t b; 8956 8957 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 8958 scfdie(); 8959 8960 if (b) 8961 return; 8962 } 8963 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 8964 scfdie(); 8965 8966 /* Get the required attributes. */ 8967 8968 /* name */ 8969 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8970 scfdie(); 8971 safe_setprop(n, name_attr, exp_str); 8972 8973 /* grouping */ 8974 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8975 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8976 err = 1; 8977 8978 /* restart_on */ 8979 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8980 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8981 err = 1; 8982 8983 /* type */ 8984 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8985 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8986 err = 1; 8987 8988 /* 8989 * entities: Not required, but if we create no children, it will be 8990 * created as empty on import, so fail if it's missing. 8991 */ 8992 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8993 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 8994 scf_iter_t *eiter; 8995 int ret2; 8996 8997 eiter = scf_iter_create(g_hndl); 8998 if (eiter == NULL) 8999 scfdie(); 9000 9001 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 9002 scfdie(); 9003 9004 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 9005 xmlNodePtr ch; 9006 9007 if (scf_value_get_astring(exp_val, exp_str, 9008 exp_str_sz) < 0) 9009 scfdie(); 9010 9011 /* 9012 * service_fmri's must be first, so we can add them 9013 * here. 9014 */ 9015 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 9016 NULL); 9017 if (ch == NULL) 9018 uu_die(emsg_create_xml); 9019 9020 safe_setprop(ch, value_attr, exp_str); 9021 } 9022 if (ret2 == -1) 9023 scfdie(); 9024 9025 scf_iter_destroy(eiter); 9026 } else 9027 err = 1; 9028 9029 if (err) { 9030 xmlFreeNode(n); 9031 9032 export_pg(pg, eelts, 0); 9033 9034 return; 9035 } 9036 9037 /* Iterate through the properties & handle each. */ 9038 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9039 scfdie(); 9040 9041 (void) memset(&elts, 0, sizeof (elts)); 9042 9043 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9044 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9045 scfdie(); 9046 9047 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9048 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9049 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9050 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9051 continue; 9052 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9053 xmlNodePtr m; 9054 9055 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9056 if (m == NULL) 9057 uu_die(emsg_create_xml); 9058 9059 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9060 elts.stability = m; 9061 continue; 9062 } 9063 9064 xmlFreeNode(m); 9065 } 9066 9067 export_property(exp_prop, exp_str, &elts, 0); 9068 } 9069 if (ret == -1) 9070 scfdie(); 9071 9072 (void) xmlAddChild(n, elts.stability); 9073 (void) xmlAddChildList(n, elts.propvals); 9074 (void) xmlAddChildList(n, elts.properties); 9075 9076 if (eelts->dependencies == NULL) 9077 eelts->dependencies = n; 9078 else 9079 (void) xmlAddSibling(eelts->dependencies, n); 9080 } 9081 9082 static xmlNodePtr 9083 export_method_environment(scf_propertygroup_t *pg) 9084 { 9085 xmlNodePtr env; 9086 int ret; 9087 int children = 0; 9088 9089 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 9090 return (NULL); 9091 9092 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 9093 if (env == NULL) 9094 uu_die(emsg_create_xml); 9095 9096 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 9097 scfdie(); 9098 9099 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 9100 scfdie(); 9101 9102 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 9103 xmlNodePtr ev; 9104 char *cp; 9105 9106 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9107 scfdie(); 9108 9109 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 9110 warn(gettext("Invalid environment variable \"%s\".\n"), 9111 exp_str); 9112 continue; 9113 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 9114 warn(gettext("Invalid environment variable \"%s\"; " 9115 "\"SMF_\" prefix is reserved.\n"), exp_str); 9116 continue; 9117 } 9118 9119 *cp = '\0'; 9120 cp++; 9121 9122 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 9123 if (ev == NULL) 9124 uu_die(emsg_create_xml); 9125 9126 safe_setprop(ev, name_attr, exp_str); 9127 safe_setprop(ev, value_attr, cp); 9128 children++; 9129 } 9130 9131 if (ret != 0) 9132 scfdie(); 9133 9134 if (children == 0) { 9135 xmlFreeNode(env); 9136 return (NULL); 9137 } 9138 9139 return (env); 9140 } 9141 9142 /* 9143 * As above, but for a method property group. 9144 */ 9145 static void 9146 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 9147 { 9148 xmlNodePtr n, env; 9149 char *str; 9150 int err = 0, nonenv, ret; 9151 uint8_t use_profile; 9152 struct pg_elts elts; 9153 xmlNodePtr ctxt = NULL; 9154 9155 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 9156 9157 /* Get the required attributes. */ 9158 9159 /* name */ 9160 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9161 scfdie(); 9162 safe_setprop(n, name_attr, exp_str); 9163 9164 /* type */ 9165 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9166 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9167 err = 1; 9168 9169 /* exec */ 9170 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 9171 set_attr_from_prop(exp_prop, n, "exec") != 0) 9172 err = 1; 9173 9174 /* timeout */ 9175 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 9176 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 9177 prop_get_val(exp_prop, exp_val) == 0) { 9178 uint64_t c; 9179 9180 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 9181 scfdie(); 9182 9183 str = uu_msprintf("%llu", c); 9184 if (str == NULL) 9185 uu_die(gettext("Could not create string")); 9186 9187 safe_setprop(n, "timeout_seconds", str); 9188 free(str); 9189 } else 9190 err = 1; 9191 9192 if (err) { 9193 xmlFreeNode(n); 9194 9195 export_pg(pg, eelts, 0); 9196 9197 return; 9198 } 9199 9200 9201 /* 9202 * If we're going to have a method_context child, we need to know 9203 * before we iterate through the properties. Since method_context's 9204 * are optional, we don't want to complain about any properties 9205 * missing if none of them are there. Thus we can't use the 9206 * convenience functions. 9207 */ 9208 nonenv = 9209 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 9210 SCF_SUCCESS || 9211 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 9212 SCF_SUCCESS || 9213 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 9214 SCF_SUCCESS || 9215 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 9216 SCF_SUCCESS; 9217 9218 if (nonenv) { 9219 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9220 if (ctxt == NULL) 9221 uu_die(emsg_create_xml); 9222 9223 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 9224 0 && 9225 set_attr_from_prop_default(exp_prop, ctxt, 9226 "working_directory", ":default") != 0) 9227 err = 1; 9228 9229 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 9230 set_attr_from_prop_default(exp_prop, ctxt, "project", 9231 ":default") != 0) 9232 err = 1; 9233 9234 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 9235 0 && 9236 set_attr_from_prop_default(exp_prop, ctxt, 9237 "resource_pool", ":default") != 0) 9238 err = 1; 9239 /* 9240 * We only want to complain about profile or credential 9241 * properties if we will use them. To determine that we must 9242 * examine USE_PROFILE. 9243 */ 9244 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9245 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9246 prop_get_val(exp_prop, exp_val) == 0) { 9247 if (scf_value_get_boolean(exp_val, &use_profile) != 9248 SCF_SUCCESS) { 9249 scfdie(); 9250 } 9251 9252 if (use_profile) { 9253 xmlNodePtr prof; 9254 9255 prof = xmlNewChild(ctxt, NULL, 9256 (xmlChar *)"method_profile", NULL); 9257 if (prof == NULL) 9258 uu_die(emsg_create_xml); 9259 9260 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 9261 exp_prop) != 0 || 9262 set_attr_from_prop(exp_prop, prof, 9263 name_attr) != 0) 9264 err = 1; 9265 } else { 9266 xmlNodePtr cred; 9267 9268 cred = xmlNewChild(ctxt, NULL, 9269 (xmlChar *)"method_credential", NULL); 9270 if (cred == NULL) 9271 uu_die(emsg_create_xml); 9272 9273 if (pg_get_prop(pg, SCF_PROPERTY_USER, 9274 exp_prop) != 0 || 9275 set_attr_from_prop(exp_prop, cred, 9276 "user") != 0) { 9277 err = 1; 9278 } 9279 9280 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 9281 exp_prop) == 0 && 9282 set_attr_from_prop_default(exp_prop, cred, 9283 "group", ":default") != 0) 9284 err = 1; 9285 9286 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 9287 exp_prop) == 0 && 9288 set_attr_from_prop_default(exp_prop, cred, 9289 "supp_groups", ":default") != 0) 9290 err = 1; 9291 9292 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 9293 exp_prop) == 0 && 9294 set_attr_from_prop_default(exp_prop, cred, 9295 "privileges", ":default") != 0) 9296 err = 1; 9297 9298 if (pg_get_prop(pg, 9299 SCF_PROPERTY_LIMIT_PRIVILEGES, 9300 exp_prop) == 0 && 9301 set_attr_from_prop_default(exp_prop, cred, 9302 "limit_privileges", ":default") != 0) 9303 err = 1; 9304 } 9305 } 9306 } 9307 9308 if ((env = export_method_environment(pg)) != NULL) { 9309 if (ctxt == NULL) { 9310 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9311 if (ctxt == NULL) 9312 uu_die(emsg_create_xml); 9313 } 9314 (void) xmlAddChild(ctxt, env); 9315 } 9316 9317 if (env != NULL || (nonenv && err == 0)) 9318 (void) xmlAddChild(n, ctxt); 9319 else 9320 xmlFreeNode(ctxt); 9321 9322 nonenv = (err == 0); 9323 9324 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9325 scfdie(); 9326 9327 (void) memset(&elts, 0, sizeof (elts)); 9328 9329 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9330 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9331 scfdie(); 9332 9333 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9334 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 9335 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 9336 continue; 9337 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9338 xmlNodePtr m; 9339 9340 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9341 if (m == NULL) 9342 uu_die(emsg_create_xml); 9343 9344 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9345 elts.stability = m; 9346 continue; 9347 } 9348 9349 xmlFreeNode(m); 9350 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 9351 0 || 9352 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 9353 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 9354 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9355 if (nonenv) 9356 continue; 9357 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 9358 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 9359 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 9360 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 9361 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 9362 if (nonenv && !use_profile) 9363 continue; 9364 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9365 if (nonenv && use_profile) 9366 continue; 9367 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 9368 if (env != NULL) 9369 continue; 9370 } 9371 9372 export_property(exp_prop, exp_str, &elts, 0); 9373 } 9374 if (ret == -1) 9375 scfdie(); 9376 9377 (void) xmlAddChild(n, elts.stability); 9378 (void) xmlAddChildList(n, elts.propvals); 9379 (void) xmlAddChildList(n, elts.properties); 9380 9381 if (eelts->exec_methods == NULL) 9382 eelts->exec_methods = n; 9383 else 9384 (void) xmlAddSibling(eelts->exec_methods, n); 9385 } 9386 9387 static void 9388 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 9389 struct entity_elts *eelts) 9390 { 9391 xmlNodePtr pgnode; 9392 9393 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 9394 if (pgnode == NULL) 9395 uu_die(emsg_create_xml); 9396 9397 safe_setprop(pgnode, name_attr, name); 9398 safe_setprop(pgnode, type_attr, type); 9399 9400 (void) xmlAddChildList(pgnode, elts->propvals); 9401 (void) xmlAddChildList(pgnode, elts->properties); 9402 9403 if (eelts->property_groups == NULL) 9404 eelts->property_groups = pgnode; 9405 else 9406 (void) xmlAddSibling(eelts->property_groups, pgnode); 9407 } 9408 9409 /* 9410 * Process the general property group for a service. This is the one with the 9411 * goodies. 9412 */ 9413 static void 9414 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 9415 { 9416 struct pg_elts elts; 9417 int ret; 9418 9419 /* 9420 * In case there are properties which don't correspond to child 9421 * entities of the service entity, we'll set up a pg_elts structure to 9422 * put them in. 9423 */ 9424 (void) memset(&elts, 0, sizeof (elts)); 9425 9426 /* Walk the properties, looking for special ones. */ 9427 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9428 scfdie(); 9429 9430 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9431 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9432 scfdie(); 9433 9434 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 9435 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9436 prop_get_val(exp_prop, exp_val) == 0) { 9437 uint8_t b; 9438 9439 if (scf_value_get_boolean(exp_val, &b) != 9440 SCF_SUCCESS) 9441 scfdie(); 9442 9443 if (b) { 9444 selts->single_instance = 9445 xmlNewNode(NULL, 9446 (xmlChar *)"single_instance"); 9447 if (selts->single_instance == NULL) 9448 uu_die(emsg_create_xml); 9449 } 9450 9451 continue; 9452 } 9453 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9454 xmlNodePtr rnode, sfnode; 9455 9456 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9457 if (rnode == NULL) 9458 uu_die(emsg_create_xml); 9459 9460 sfnode = xmlNewChild(rnode, NULL, 9461 (xmlChar *)"service_fmri", NULL); 9462 if (sfnode == NULL) 9463 uu_die(emsg_create_xml); 9464 9465 if (set_attr_from_prop(exp_prop, sfnode, 9466 value_attr) == 0) { 9467 selts->restarter = rnode; 9468 continue; 9469 } 9470 9471 xmlFreeNode(rnode); 9472 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 9473 0) { 9474 xmlNodePtr s; 9475 9476 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9477 if (s == NULL) 9478 uu_die(emsg_create_xml); 9479 9480 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9481 selts->stability = s; 9482 continue; 9483 } 9484 9485 xmlFreeNode(s); 9486 } 9487 9488 export_property(exp_prop, exp_str, &elts, 0); 9489 } 9490 if (ret == -1) 9491 scfdie(); 9492 9493 if (elts.propvals != NULL || elts.properties != NULL) 9494 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 9495 selts); 9496 } 9497 9498 static void 9499 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 9500 { 9501 xmlNodePtr n, prof, cred, env; 9502 uint8_t use_profile; 9503 int ret, err = 0; 9504 9505 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 9506 9507 env = export_method_environment(pg); 9508 9509 /* Need to know whether we'll use a profile or not. */ 9510 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9511 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9512 prop_get_val(exp_prop, exp_val) == 0) { 9513 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 9514 scfdie(); 9515 9516 if (use_profile) 9517 prof = 9518 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 9519 NULL); 9520 else 9521 cred = 9522 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 9523 NULL); 9524 } 9525 9526 if (env != NULL) 9527 (void) xmlAddChild(n, env); 9528 9529 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9530 scfdie(); 9531 9532 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9533 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9534 scfdie(); 9535 9536 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 9537 if (set_attr_from_prop(exp_prop, n, 9538 "working_directory") != 0) 9539 err = 1; 9540 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 9541 if (set_attr_from_prop(exp_prop, n, "project") != 0) 9542 err = 1; 9543 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 9544 if (set_attr_from_prop(exp_prop, n, 9545 "resource_pool") != 0) 9546 err = 1; 9547 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9548 /* EMPTY */ 9549 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 9550 if (use_profile || 9551 set_attr_from_prop(exp_prop, cred, "user") != 0) 9552 err = 1; 9553 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 9554 if (use_profile || 9555 set_attr_from_prop(exp_prop, cred, "group") != 0) 9556 err = 1; 9557 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 9558 if (use_profile || set_attr_from_prop(exp_prop, cred, 9559 "supp_groups") != 0) 9560 err = 1; 9561 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 9562 if (use_profile || set_attr_from_prop(exp_prop, cred, 9563 "privileges") != 0) 9564 err = 1; 9565 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 9566 0) { 9567 if (use_profile || set_attr_from_prop(exp_prop, cred, 9568 "limit_privileges") != 0) 9569 err = 1; 9570 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9571 if (!use_profile || set_attr_from_prop(exp_prop, 9572 prof, name_attr) != 0) 9573 err = 1; 9574 } else { 9575 /* Can't have generic properties in method_context's */ 9576 err = 1; 9577 } 9578 } 9579 if (ret == -1) 9580 scfdie(); 9581 9582 if (err && env == NULL) { 9583 xmlFreeNode(n); 9584 export_pg(pg, elts, 0); 9585 return; 9586 } 9587 9588 elts->method_context = n; 9589 } 9590 9591 /* 9592 * Given a dependency property group in the tfmri entity (target fmri), return 9593 * a dependent element which represents it. 9594 */ 9595 static xmlNodePtr 9596 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 9597 { 9598 uint8_t b; 9599 xmlNodePtr n, sf; 9600 int err = 0, ret; 9601 struct pg_elts pgelts; 9602 9603 /* 9604 * If external isn't set to true then exporting the service will 9605 * export this as a normal dependency, so we should stop to avoid 9606 * duplication. 9607 */ 9608 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 9609 scf_property_get_value(exp_prop, exp_val) != 0 || 9610 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 9611 if (g_verbose) { 9612 warn(gettext("Dependent \"%s\" cannot be exported " 9613 "properly because the \"%s\" property of the " 9614 "\"%s\" dependency of %s is not set to true.\n"), 9615 name, scf_property_external, name, tfmri); 9616 } 9617 9618 return (NULL); 9619 } 9620 9621 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 9622 if (n == NULL) 9623 uu_die(emsg_create_xml); 9624 9625 safe_setprop(n, name_attr, name); 9626 9627 /* Get the required attributes */ 9628 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9629 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9630 err = 1; 9631 9632 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9633 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9634 err = 1; 9635 9636 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9637 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 9638 prop_get_val(exp_prop, exp_val) == 0) { 9639 /* EMPTY */ 9640 } else 9641 err = 1; 9642 9643 if (err) { 9644 xmlFreeNode(n); 9645 return (NULL); 9646 } 9647 9648 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 9649 if (sf == NULL) 9650 uu_die(emsg_create_xml); 9651 9652 safe_setprop(sf, value_attr, tfmri); 9653 9654 /* 9655 * Now add elements for the other properties. 9656 */ 9657 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9658 scfdie(); 9659 9660 (void) memset(&pgelts, 0, sizeof (pgelts)); 9661 9662 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9663 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9664 scfdie(); 9665 9666 if (strcmp(exp_str, scf_property_external) == 0 || 9667 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9668 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9669 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9670 continue; 9671 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 9672 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 9673 prop_get_val(exp_prop, exp_val) == 0) { 9674 char type[sizeof ("service") + 1]; 9675 9676 if (scf_value_get_astring(exp_val, type, 9677 sizeof (type)) < 0) 9678 scfdie(); 9679 9680 if (strcmp(type, "service") == 0) 9681 continue; 9682 } 9683 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9684 xmlNodePtr s; 9685 9686 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9687 if (s == NULL) 9688 uu_die(emsg_create_xml); 9689 9690 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9691 pgelts.stability = s; 9692 continue; 9693 } 9694 9695 xmlFreeNode(s); 9696 } 9697 9698 export_property(exp_prop, exp_str, &pgelts, 0); 9699 } 9700 if (ret == -1) 9701 scfdie(); 9702 9703 (void) xmlAddChild(n, pgelts.stability); 9704 (void) xmlAddChildList(n, pgelts.propvals); 9705 (void) xmlAddChildList(n, pgelts.properties); 9706 9707 return (n); 9708 } 9709 9710 static void 9711 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 9712 { 9713 scf_propertygroup_t *opg; 9714 scf_iter_t *iter; 9715 char *type, *fmri; 9716 int ret; 9717 struct pg_elts pgelts; 9718 xmlNodePtr n; 9719 scf_error_t serr; 9720 9721 if ((opg = scf_pg_create(g_hndl)) == NULL || 9722 (iter = scf_iter_create(g_hndl)) == NULL) 9723 scfdie(); 9724 9725 /* Can't use exp_prop_iter due to export_dependent(). */ 9726 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 9727 scfdie(); 9728 9729 type = safe_malloc(max_scf_pg_type_len + 1); 9730 9731 /* Get an extra byte so we can tell if values are too long. */ 9732 fmri = safe_malloc(max_scf_fmri_len + 2); 9733 9734 (void) memset(&pgelts, 0, sizeof (pgelts)); 9735 9736 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 9737 void *entity; 9738 int isservice; 9739 scf_type_t ty; 9740 9741 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 9742 scfdie(); 9743 9744 if ((ty != SCF_TYPE_ASTRING && 9745 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 9746 prop_get_val(exp_prop, exp_val) != 0) { 9747 export_property(exp_prop, NULL, &pgelts, 0); 9748 continue; 9749 } 9750 9751 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9752 scfdie(); 9753 9754 if (scf_value_get_astring(exp_val, fmri, 9755 max_scf_fmri_len + 2) < 0) 9756 scfdie(); 9757 9758 /* Look for a dependency group in the target fmri. */ 9759 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 9760 switch (serr) { 9761 case SCF_ERROR_NONE: 9762 break; 9763 9764 case SCF_ERROR_NO_MEMORY: 9765 uu_die(gettext("Out of memory.\n")); 9766 /* NOTREACHED */ 9767 9768 case SCF_ERROR_INVALID_ARGUMENT: 9769 if (g_verbose) { 9770 if (scf_property_to_fmri(exp_prop, fmri, 9771 max_scf_fmri_len + 2) < 0) 9772 scfdie(); 9773 9774 warn(gettext("The value of %s is not a valid " 9775 "FMRI.\n"), fmri); 9776 } 9777 9778 export_property(exp_prop, exp_str, &pgelts, 0); 9779 continue; 9780 9781 case SCF_ERROR_CONSTRAINT_VIOLATED: 9782 if (g_verbose) { 9783 if (scf_property_to_fmri(exp_prop, fmri, 9784 max_scf_fmri_len + 2) < 0) 9785 scfdie(); 9786 9787 warn(gettext("The value of %s does not specify " 9788 "a service or an instance.\n"), fmri); 9789 } 9790 9791 export_property(exp_prop, exp_str, &pgelts, 0); 9792 continue; 9793 9794 case SCF_ERROR_NOT_FOUND: 9795 if (g_verbose) { 9796 if (scf_property_to_fmri(exp_prop, fmri, 9797 max_scf_fmri_len + 2) < 0) 9798 scfdie(); 9799 9800 warn(gettext("The entity specified by %s does " 9801 "not exist.\n"), fmri); 9802 } 9803 9804 export_property(exp_prop, exp_str, &pgelts, 0); 9805 continue; 9806 9807 default: 9808 #ifndef NDEBUG 9809 (void) fprintf(stderr, "%s:%d: %s() failed with " 9810 "unexpected error %d.\n", __FILE__, __LINE__, 9811 "fmri_to_entity", serr); 9812 #endif 9813 abort(); 9814 } 9815 9816 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 9817 if (scf_error() != SCF_ERROR_NOT_FOUND) 9818 scfdie(); 9819 9820 warn(gettext("Entity %s is missing dependency property " 9821 "group %s.\n"), fmri, exp_str); 9822 9823 export_property(exp_prop, NULL, &pgelts, 0); 9824 continue; 9825 } 9826 9827 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 9828 scfdie(); 9829 9830 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 9831 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 9832 scfdie(); 9833 9834 warn(gettext("Property group %s is not of " 9835 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 9836 9837 export_property(exp_prop, NULL, &pgelts, 0); 9838 continue; 9839 } 9840 9841 n = export_dependent(opg, exp_str, fmri); 9842 if (n == NULL) 9843 export_property(exp_prop, exp_str, &pgelts, 0); 9844 else { 9845 if (eelts->dependents == NULL) 9846 eelts->dependents = n; 9847 else 9848 (void) xmlAddSibling(eelts->dependents, 9849 n); 9850 } 9851 } 9852 if (ret == -1) 9853 scfdie(); 9854 9855 free(fmri); 9856 free(type); 9857 9858 scf_iter_destroy(iter); 9859 scf_pg_destroy(opg); 9860 9861 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9862 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 9863 eelts); 9864 } 9865 9866 static void 9867 make_node(xmlNodePtr *nodep, const char *name) 9868 { 9869 if (*nodep == NULL) { 9870 *nodep = xmlNewNode(NULL, (xmlChar *)name); 9871 if (*nodep == NULL) 9872 uu_die(emsg_create_xml); 9873 } 9874 } 9875 9876 static xmlNodePtr 9877 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 9878 { 9879 int ret; 9880 xmlNodePtr parent = NULL; 9881 xmlNodePtr loctext = NULL; 9882 9883 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9884 scfdie(); 9885 9886 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9887 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 9888 prop_get_val(exp_prop, exp_val) != 0) 9889 continue; 9890 9891 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 9892 scfdie(); 9893 9894 make_node(&parent, parname); 9895 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 9896 (xmlChar *)exp_str); 9897 if (loctext == NULL) 9898 uu_die(emsg_create_xml); 9899 9900 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9901 scfdie(); 9902 9903 safe_setprop(loctext, "xml:lang", exp_str); 9904 } 9905 9906 if (ret == -1) 9907 scfdie(); 9908 9909 return (parent); 9910 } 9911 9912 static xmlNodePtr 9913 export_tm_manpage(scf_propertygroup_t *pg) 9914 { 9915 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 9916 if (manpage == NULL) 9917 uu_die(emsg_create_xml); 9918 9919 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 9920 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 9921 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 9922 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 9923 xmlFreeNode(manpage); 9924 return (NULL); 9925 } 9926 9927 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 9928 (void) set_attr_from_prop_default(exp_prop, 9929 manpage, "manpath", ":default"); 9930 9931 return (manpage); 9932 } 9933 9934 static xmlNodePtr 9935 export_tm_doc_link(scf_propertygroup_t *pg) 9936 { 9937 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 9938 if (doc_link == NULL) 9939 uu_die(emsg_create_xml); 9940 9941 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 9942 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 9943 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 9944 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 9945 xmlFreeNode(doc_link); 9946 return (NULL); 9947 } 9948 return (doc_link); 9949 } 9950 9951 /* 9952 * Process template information for a service or instances. 9953 */ 9954 static void 9955 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 9956 struct template_elts *telts) 9957 { 9958 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 9959 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 9960 xmlNodePtr child = NULL; 9961 9962 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 9963 scfdie(); 9964 9965 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 9966 telts->common_name = export_tm_loctext(pg, "common_name"); 9967 if (telts->common_name == NULL) 9968 export_pg(pg, elts, 0); 9969 return; 9970 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 9971 telts->description = export_tm_loctext(pg, "description"); 9972 if (telts->description == NULL) 9973 export_pg(pg, elts, 0); 9974 return; 9975 } 9976 9977 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 9978 child = export_tm_manpage(pg); 9979 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 9980 child = export_tm_doc_link(pg); 9981 } 9982 9983 if (child != NULL) { 9984 make_node(&telts->documentation, "documentation"); 9985 (void) xmlAddChild(telts->documentation, child); 9986 } else { 9987 export_pg(pg, elts, 0); 9988 } 9989 } 9990 9991 /* 9992 * Process the general property group for an instance. 9993 */ 9994 static void 9995 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 9996 struct entity_elts *elts) 9997 { 9998 uint8_t enabled; 9999 struct pg_elts pgelts; 10000 int ret; 10001 10002 /* enabled */ 10003 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10004 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10005 prop_get_val(exp_prop, exp_val) == 0) { 10006 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10007 scfdie(); 10008 } else { 10009 enabled = 0; 10010 } 10011 10012 safe_setprop(inode, enabled_attr, enabled ? true : false); 10013 10014 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10015 scfdie(); 10016 10017 (void) memset(&pgelts, 0, sizeof (pgelts)); 10018 10019 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10020 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10021 scfdie(); 10022 10023 if (strcmp(exp_str, scf_property_enabled) == 0) { 10024 continue; 10025 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10026 xmlNodePtr rnode, sfnode; 10027 10028 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10029 if (rnode == NULL) 10030 uu_die(emsg_create_xml); 10031 10032 sfnode = xmlNewChild(rnode, NULL, 10033 (xmlChar *)"service_fmri", NULL); 10034 if (sfnode == NULL) 10035 uu_die(emsg_create_xml); 10036 10037 if (set_attr_from_prop(exp_prop, sfnode, 10038 value_attr) == 0) { 10039 elts->restarter = rnode; 10040 continue; 10041 } 10042 10043 xmlFreeNode(rnode); 10044 } 10045 10046 export_property(exp_prop, exp_str, &pgelts, 0); 10047 } 10048 if (ret == -1) 10049 scfdie(); 10050 10051 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10052 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10053 elts); 10054 } 10055 10056 /* 10057 * Put an instance element for the given instance into selts. 10058 */ 10059 static void 10060 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10061 { 10062 xmlNodePtr n; 10063 boolean_t isdefault; 10064 struct entity_elts elts; 10065 struct template_elts template_elts; 10066 int ret; 10067 10068 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10069 if (n == NULL) 10070 uu_die(emsg_create_xml); 10071 10072 /* name */ 10073 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10074 scfdie(); 10075 safe_setprop(n, name_attr, exp_str); 10076 isdefault = strcmp(exp_str, "default") == 0; 10077 10078 /* check existance of general pg (since general/enabled is required) */ 10079 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10080 if (scf_error() != SCF_ERROR_NOT_FOUND) 10081 scfdie(); 10082 10083 if (g_verbose) { 10084 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10085 scfdie(); 10086 10087 warn(gettext("Instance %s has no general property " 10088 "group; it will be marked disabled.\n"), exp_str); 10089 } 10090 10091 safe_setprop(n, enabled_attr, false); 10092 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10093 strcmp(exp_str, scf_group_framework) != 0) { 10094 if (g_verbose) { 10095 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10096 scfdie(); 10097 10098 warn(gettext("Property group %s is not of type " 10099 "framework; the instance will be marked " 10100 "disabled.\n"), exp_str); 10101 } 10102 10103 safe_setprop(n, enabled_attr, false); 10104 } 10105 10106 /* property groups */ 10107 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10108 scfdie(); 10109 10110 (void) memset(&elts, 0, sizeof (elts)); 10111 (void) memset(&template_elts, 0, sizeof (template_elts)); 10112 10113 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10114 uint32_t pgflags; 10115 10116 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10117 scfdie(); 10118 10119 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10120 continue; 10121 10122 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10123 scfdie(); 10124 10125 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10126 export_dependency(exp_pg, &elts); 10127 continue; 10128 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10129 export_method(exp_pg, &elts); 10130 continue; 10131 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10132 if (scf_pg_get_name(exp_pg, exp_str, 10133 max_scf_name_len + 1) < 0) 10134 scfdie(); 10135 10136 if (strcmp(exp_str, scf_pg_general) == 0) { 10137 export_inst_general(exp_pg, n, &elts); 10138 continue; 10139 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10140 0) { 10141 export_method_context(exp_pg, &elts); 10142 continue; 10143 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10144 export_dependents(exp_pg, &elts); 10145 continue; 10146 } 10147 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10148 export_template(exp_pg, &elts, &template_elts); 10149 continue; 10150 } 10151 10152 /* Ordinary pg. */ 10153 export_pg(exp_pg, &elts, flags); 10154 } 10155 if (ret == -1) 10156 scfdie(); 10157 10158 if (template_elts.common_name != NULL) { 10159 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10160 (void) xmlAddChild(elts.template, template_elts.common_name); 10161 (void) xmlAddChild(elts.template, template_elts.description); 10162 (void) xmlAddChild(elts.template, template_elts.documentation); 10163 } else { 10164 xmlFreeNode(template_elts.description); 10165 xmlFreeNode(template_elts.documentation); 10166 } 10167 10168 if (isdefault && elts.restarter == NULL && 10169 elts.dependencies == NULL && elts.method_context == NULL && 10170 elts.exec_methods == NULL && elts.property_groups == NULL && 10171 elts.template == NULL) { 10172 xmlChar *eval; 10173 10174 /* This is a default instance */ 10175 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10176 10177 xmlFreeNode(n); 10178 10179 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10180 if (n == NULL) 10181 uu_die(emsg_create_xml); 10182 10183 safe_setprop(n, enabled_attr, (char *)eval); 10184 xmlFree(eval); 10185 10186 selts->create_default_instance = n; 10187 } else { 10188 /* Assemble the children in order. */ 10189 (void) xmlAddChild(n, elts.restarter); 10190 (void) xmlAddChildList(n, elts.dependencies); 10191 (void) xmlAddChildList(n, elts.dependents); 10192 (void) xmlAddChild(n, elts.method_context); 10193 (void) xmlAddChildList(n, elts.exec_methods); 10194 (void) xmlAddChildList(n, elts.property_groups); 10195 (void) xmlAddChild(n, elts.template); 10196 10197 if (selts->instances == NULL) 10198 selts->instances = n; 10199 else 10200 (void) xmlAddSibling(selts->instances, n); 10201 } 10202 } 10203 10204 /* 10205 * Return a service element for the given service. 10206 */ 10207 static xmlNodePtr 10208 export_service(scf_service_t *svc, int flags) 10209 { 10210 xmlNodePtr snode; 10211 struct entity_elts elts; 10212 struct template_elts template_elts; 10213 int ret; 10214 10215 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10216 if (snode == NULL) 10217 uu_die(emsg_create_xml); 10218 10219 /* Get & set name attribute */ 10220 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10221 scfdie(); 10222 safe_setprop(snode, name_attr, exp_str); 10223 10224 safe_setprop(snode, type_attr, "service"); 10225 safe_setprop(snode, "version", "0"); 10226 10227 /* Acquire child elements. */ 10228 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10229 scfdie(); 10230 10231 (void) memset(&elts, 0, sizeof (elts)); 10232 (void) memset(&template_elts, 0, sizeof (template_elts)); 10233 10234 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10235 uint32_t pgflags; 10236 10237 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10238 scfdie(); 10239 10240 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10241 continue; 10242 10243 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10244 scfdie(); 10245 10246 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10247 export_dependency(exp_pg, &elts); 10248 continue; 10249 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10250 export_method(exp_pg, &elts); 10251 continue; 10252 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10253 if (scf_pg_get_name(exp_pg, exp_str, 10254 max_scf_name_len + 1) < 0) 10255 scfdie(); 10256 10257 if (strcmp(exp_str, scf_pg_general) == 0) { 10258 export_svc_general(exp_pg, &elts); 10259 continue; 10260 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10261 0) { 10262 export_method_context(exp_pg, &elts); 10263 continue; 10264 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10265 export_dependents(exp_pg, &elts); 10266 continue; 10267 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10268 continue; 10269 } 10270 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10271 export_template(exp_pg, &elts, &template_elts); 10272 continue; 10273 } 10274 10275 export_pg(exp_pg, &elts, flags); 10276 } 10277 if (ret == -1) 10278 scfdie(); 10279 10280 if (template_elts.common_name != NULL) { 10281 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10282 (void) xmlAddChild(elts.template, template_elts.common_name); 10283 (void) xmlAddChild(elts.template, template_elts.description); 10284 (void) xmlAddChild(elts.template, template_elts.documentation); 10285 } else { 10286 xmlFreeNode(template_elts.description); 10287 xmlFreeNode(template_elts.documentation); 10288 } 10289 10290 /* Iterate instances */ 10291 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10292 scfdie(); 10293 10294 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10295 export_instance(exp_inst, &elts, flags); 10296 if (ret == -1) 10297 scfdie(); 10298 10299 /* Now add all of the accumulated elements in order. */ 10300 (void) xmlAddChild(snode, elts.create_default_instance); 10301 (void) xmlAddChild(snode, elts.single_instance); 10302 (void) xmlAddChild(snode, elts.restarter); 10303 (void) xmlAddChildList(snode, elts.dependencies); 10304 (void) xmlAddChildList(snode, elts.dependents); 10305 (void) xmlAddChild(snode, elts.method_context); 10306 (void) xmlAddChildList(snode, elts.exec_methods); 10307 (void) xmlAddChildList(snode, elts.property_groups); 10308 (void) xmlAddChildList(snode, elts.instances); 10309 (void) xmlAddChild(snode, elts.stability); 10310 (void) xmlAddChild(snode, elts.template); 10311 10312 return (snode); 10313 } 10314 10315 static int 10316 export_callback(void *data, scf_walkinfo_t *wip) 10317 { 10318 FILE *f; 10319 xmlDocPtr doc; 10320 xmlNodePtr sb; 10321 int result; 10322 struct export_args *argsp = (struct export_args *)data; 10323 10324 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10325 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10326 (exp_prop = scf_property_create(g_hndl)) == NULL || 10327 (exp_val = scf_value_create(g_hndl)) == NULL || 10328 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10329 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10330 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10331 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10332 scfdie(); 10333 10334 exp_str_sz = max_scf_len + 1; 10335 exp_str = safe_malloc(exp_str_sz); 10336 10337 if (argsp->filename != NULL) { 10338 errno = 0; 10339 f = fopen(argsp->filename, "wb"); 10340 if (f == NULL) { 10341 if (errno == 0) 10342 uu_die(gettext("Could not open \"%s\": no free " 10343 "stdio streams.\n"), argsp->filename); 10344 else 10345 uu_die(gettext("Could not open \"%s\""), 10346 argsp->filename); 10347 } 10348 } else 10349 f = stdout; 10350 10351 doc = xmlNewDoc((xmlChar *)"1.0"); 10352 if (doc == NULL) 10353 uu_die(gettext("Could not create XML document.\n")); 10354 10355 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10356 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10357 uu_die(emsg_create_xml); 10358 10359 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10360 if (sb == NULL) 10361 uu_die(emsg_create_xml); 10362 safe_setprop(sb, type_attr, "manifest"); 10363 safe_setprop(sb, name_attr, "export"); 10364 (void) xmlAddSibling(doc->children, sb); 10365 10366 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10367 10368 result = write_service_bundle(doc, f); 10369 10370 free(exp_str); 10371 scf_iter_destroy(exp_val_iter); 10372 scf_iter_destroy(exp_prop_iter); 10373 scf_iter_destroy(exp_pg_iter); 10374 scf_iter_destroy(exp_inst_iter); 10375 scf_value_destroy(exp_val); 10376 scf_property_destroy(exp_prop); 10377 scf_pg_destroy(exp_pg); 10378 scf_instance_destroy(exp_inst); 10379 10380 xmlFreeDoc(doc); 10381 10382 if (f != stdout) 10383 (void) fclose(f); 10384 10385 return (result); 10386 } 10387 10388 /* 10389 * Get the service named by fmri, build an XML tree which represents it, and 10390 * dump it into filename (or stdout if filename is NULL). 10391 */ 10392 int 10393 lscf_service_export(char *fmri, const char *filename, int flags) 10394 { 10395 struct export_args args; 10396 int ret, err; 10397 10398 lscf_prep_hndl(); 10399 10400 bzero(&args, sizeof (args)); 10401 args.filename = filename; 10402 args.flags = flags; 10403 10404 err = 0; 10405 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10406 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10407 &args, &err, semerr)) != 0) { 10408 if (ret != -1) 10409 semerr(gettext("Failed to walk instances: %s\n"), 10410 scf_strerror(ret)); 10411 return (-1); 10412 } 10413 10414 /* 10415 * Error message has already been printed. 10416 */ 10417 if (err != 0) 10418 return (-1); 10419 10420 return (0); 10421 } 10422 10423 10424 /* 10425 * Archive 10426 */ 10427 10428 static xmlNodePtr 10429 make_archive(int flags) 10430 { 10431 xmlNodePtr sb; 10432 scf_scope_t *scope; 10433 scf_service_t *svc; 10434 scf_iter_t *iter; 10435 int r; 10436 10437 if ((scope = scf_scope_create(g_hndl)) == NULL || 10438 (svc = scf_service_create(g_hndl)) == NULL || 10439 (iter = scf_iter_create(g_hndl)) == NULL || 10440 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10441 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10442 (exp_prop = scf_property_create(g_hndl)) == NULL || 10443 (exp_val = scf_value_create(g_hndl)) == NULL || 10444 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10445 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10446 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10447 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10448 scfdie(); 10449 10450 exp_str_sz = max_scf_len + 1; 10451 exp_str = safe_malloc(exp_str_sz); 10452 10453 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10454 if (sb == NULL) 10455 uu_die(emsg_create_xml); 10456 safe_setprop(sb, type_attr, "archive"); 10457 safe_setprop(sb, name_attr, "none"); 10458 10459 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 10460 scfdie(); 10461 if (scf_iter_scope_services(iter, scope) != 0) 10462 scfdie(); 10463 10464 for (;;) { 10465 r = scf_iter_next_service(iter, svc); 10466 if (r == 0) 10467 break; 10468 if (r != 1) 10469 scfdie(); 10470 10471 if (scf_service_get_name(svc, exp_str, 10472 max_scf_name_len + 1) < 0) 10473 scfdie(); 10474 10475 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 10476 continue; 10477 10478 (void) xmlAddChild(sb, export_service(svc, flags)); 10479 } 10480 10481 free(exp_str); 10482 10483 scf_iter_destroy(exp_val_iter); 10484 scf_iter_destroy(exp_prop_iter); 10485 scf_iter_destroy(exp_pg_iter); 10486 scf_iter_destroy(exp_inst_iter); 10487 scf_value_destroy(exp_val); 10488 scf_property_destroy(exp_prop); 10489 scf_pg_destroy(exp_pg); 10490 scf_instance_destroy(exp_inst); 10491 scf_iter_destroy(iter); 10492 scf_service_destroy(svc); 10493 scf_scope_destroy(scope); 10494 10495 return (sb); 10496 } 10497 10498 int 10499 lscf_archive(const char *filename, int flags) 10500 { 10501 FILE *f; 10502 xmlDocPtr doc; 10503 int result; 10504 10505 lscf_prep_hndl(); 10506 10507 if (filename != NULL) { 10508 errno = 0; 10509 f = fopen(filename, "wb"); 10510 if (f == NULL) { 10511 if (errno == 0) 10512 uu_die(gettext("Could not open \"%s\": no free " 10513 "stdio streams.\n"), filename); 10514 else 10515 uu_die(gettext("Could not open \"%s\""), 10516 filename); 10517 } 10518 } else 10519 f = stdout; 10520 10521 doc = xmlNewDoc((xmlChar *)"1.0"); 10522 if (doc == NULL) 10523 uu_die(gettext("Could not create XML document.\n")); 10524 10525 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10526 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10527 uu_die(emsg_create_xml); 10528 10529 (void) xmlAddSibling(doc->children, make_archive(flags)); 10530 10531 result = write_service_bundle(doc, f); 10532 10533 xmlFreeDoc(doc); 10534 10535 if (f != stdout) 10536 (void) fclose(f); 10537 10538 return (result); 10539 } 10540 10541 10542 /* 10543 * "Extract" a profile. 10544 */ 10545 int 10546 lscf_profile_extract(const char *filename) 10547 { 10548 FILE *f; 10549 xmlDocPtr doc; 10550 xmlNodePtr sb, snode, inode; 10551 scf_scope_t *scope; 10552 scf_service_t *svc; 10553 scf_instance_t *inst; 10554 scf_propertygroup_t *pg; 10555 scf_property_t *prop; 10556 scf_value_t *val; 10557 scf_iter_t *siter, *iiter; 10558 int r, s; 10559 char *namebuf; 10560 uint8_t b; 10561 int result; 10562 10563 lscf_prep_hndl(); 10564 10565 if (filename != NULL) { 10566 errno = 0; 10567 f = fopen(filename, "wb"); 10568 if (f == NULL) { 10569 if (errno == 0) 10570 uu_die(gettext("Could not open \"%s\": no " 10571 "free stdio streams.\n"), filename); 10572 else 10573 uu_die(gettext("Could not open \"%s\""), 10574 filename); 10575 } 10576 } else 10577 f = stdout; 10578 10579 doc = xmlNewDoc((xmlChar *)"1.0"); 10580 if (doc == NULL) 10581 uu_die(gettext("Could not create XML document.\n")); 10582 10583 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10584 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10585 uu_die(emsg_create_xml); 10586 10587 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10588 if (sb == NULL) 10589 uu_die(emsg_create_xml); 10590 safe_setprop(sb, type_attr, "profile"); 10591 safe_setprop(sb, name_attr, "extract"); 10592 (void) xmlAddSibling(doc->children, sb); 10593 10594 if ((scope = scf_scope_create(g_hndl)) == NULL || 10595 (svc = scf_service_create(g_hndl)) == NULL || 10596 (inst = scf_instance_create(g_hndl)) == NULL || 10597 (pg = scf_pg_create(g_hndl)) == NULL || 10598 (prop = scf_property_create(g_hndl)) == NULL || 10599 (val = scf_value_create(g_hndl)) == NULL || 10600 (siter = scf_iter_create(g_hndl)) == NULL || 10601 (iiter = scf_iter_create(g_hndl)) == NULL) 10602 scfdie(); 10603 10604 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 10605 scfdie(); 10606 10607 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 10608 scfdie(); 10609 10610 namebuf = safe_malloc(max_scf_name_len + 1); 10611 10612 while ((r = scf_iter_next_service(siter, svc)) == 1) { 10613 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 10614 scfdie(); 10615 10616 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10617 if (snode == NULL) 10618 uu_die(emsg_create_xml); 10619 10620 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 10621 0) 10622 scfdie(); 10623 10624 safe_setprop(snode, name_attr, namebuf); 10625 10626 safe_setprop(snode, type_attr, "service"); 10627 safe_setprop(snode, "version", "0"); 10628 10629 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 10630 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 10631 SCF_SUCCESS) { 10632 if (scf_error() != SCF_ERROR_NOT_FOUND) 10633 scfdie(); 10634 10635 if (g_verbose) { 10636 ssize_t len; 10637 char *fmri; 10638 10639 len = 10640 scf_instance_to_fmri(inst, NULL, 0); 10641 if (len < 0) 10642 scfdie(); 10643 10644 fmri = safe_malloc(len + 1); 10645 10646 if (scf_instance_to_fmri(inst, fmri, 10647 len + 1) < 0) 10648 scfdie(); 10649 10650 warn("Instance %s has no \"%s\" " 10651 "property group.\n", fmri, 10652 scf_pg_general); 10653 10654 free(fmri); 10655 } 10656 10657 continue; 10658 } 10659 10660 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 10661 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 10662 prop_get_val(prop, val) != 0) 10663 continue; 10664 10665 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 10666 NULL); 10667 if (inode == NULL) 10668 uu_die(emsg_create_xml); 10669 10670 if (scf_instance_get_name(inst, namebuf, 10671 max_scf_name_len + 1) < 0) 10672 scfdie(); 10673 10674 safe_setprop(inode, name_attr, namebuf); 10675 10676 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 10677 scfdie(); 10678 10679 safe_setprop(inode, enabled_attr, b ? true : false); 10680 } 10681 if (s < 0) 10682 scfdie(); 10683 10684 if (snode->children != NULL) 10685 (void) xmlAddChild(sb, snode); 10686 else 10687 xmlFreeNode(snode); 10688 } 10689 if (r < 0) 10690 scfdie(); 10691 10692 free(namebuf); 10693 10694 result = write_service_bundle(doc, f); 10695 10696 xmlFreeDoc(doc); 10697 10698 if (f != stdout) 10699 (void) fclose(f); 10700 10701 return (result); 10702 } 10703 10704 10705 /* 10706 * Entity manipulation commands 10707 */ 10708 10709 /* 10710 * Entity selection. If no entity is selected, then the current scope is in 10711 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 10712 * only cur_inst is NULL, and when an instance is selected, none are NULL. 10713 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 10714 * cur_inst will be non-NULL. 10715 */ 10716 10717 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 10718 static int 10719 select_inst(const char *name) 10720 { 10721 scf_instance_t *inst; 10722 scf_error_t err; 10723 10724 assert(cur_svc != NULL); 10725 10726 inst = scf_instance_create(g_hndl); 10727 if (inst == NULL) 10728 scfdie(); 10729 10730 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 10731 cur_inst = inst; 10732 return (0); 10733 } 10734 10735 err = scf_error(); 10736 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10737 scfdie(); 10738 10739 scf_instance_destroy(inst); 10740 return (1); 10741 } 10742 10743 /* Returns as above. */ 10744 static int 10745 select_svc(const char *name) 10746 { 10747 scf_service_t *svc; 10748 scf_error_t err; 10749 10750 assert(cur_scope != NULL); 10751 10752 svc = scf_service_create(g_hndl); 10753 if (svc == NULL) 10754 scfdie(); 10755 10756 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 10757 cur_svc = svc; 10758 return (0); 10759 } 10760 10761 err = scf_error(); 10762 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10763 scfdie(); 10764 10765 scf_service_destroy(svc); 10766 return (1); 10767 } 10768 10769 /* ARGSUSED */ 10770 static int 10771 select_callback(void *unused, scf_walkinfo_t *wip) 10772 { 10773 scf_instance_t *inst; 10774 scf_service_t *svc; 10775 scf_scope_t *scope; 10776 10777 if (wip->inst != NULL) { 10778 if ((scope = scf_scope_create(g_hndl)) == NULL || 10779 (svc = scf_service_create(g_hndl)) == NULL || 10780 (inst = scf_instance_create(g_hndl)) == NULL) 10781 scfdie(); 10782 10783 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 10784 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 10785 scfdie(); 10786 } else { 10787 assert(wip->svc != NULL); 10788 10789 if ((scope = scf_scope_create(g_hndl)) == NULL || 10790 (svc = scf_service_create(g_hndl)) == NULL) 10791 scfdie(); 10792 10793 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 10794 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 10795 scfdie(); 10796 10797 inst = NULL; 10798 } 10799 10800 /* Clear out the current selection */ 10801 assert(cur_scope != NULL); 10802 scf_scope_destroy(cur_scope); 10803 scf_service_destroy(cur_svc); 10804 scf_instance_destroy(cur_inst); 10805 10806 cur_scope = scope; 10807 cur_svc = svc; 10808 cur_inst = inst; 10809 10810 return (0); 10811 } 10812 10813 static int 10814 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 10815 { 10816 char **fmri = fmri_p; 10817 10818 *fmri = strdup(wip->fmri); 10819 if (*fmri == NULL) 10820 uu_die(gettext("Out of memory.\n")); 10821 10822 return (0); 10823 } 10824 10825 /* 10826 * validate [fmri] 10827 * Perform the validation of an FMRI instance. 10828 */ 10829 void 10830 lscf_validate_fmri(const char *fmri) 10831 { 10832 int ret = 0; 10833 size_t inst_sz; 10834 char *inst_fmri = NULL; 10835 scf_tmpl_errors_t *errs = NULL; 10836 char *snapbuf = NULL; 10837 10838 lscf_prep_hndl(); 10839 10840 if (fmri == NULL) { 10841 inst_sz = max_scf_fmri_len + 1; 10842 inst_fmri = safe_malloc(inst_sz); 10843 10844 if (cur_snap != NULL) { 10845 snapbuf = safe_malloc(max_scf_name_len + 1); 10846 if (scf_snapshot_get_name(cur_snap, snapbuf, 10847 max_scf_name_len + 1) < 0) 10848 scfdie(); 10849 } 10850 if (cur_inst == NULL) { 10851 semerr(gettext("No instance selected\n")); 10852 goto cleanup; 10853 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 10854 inst_sz) >= inst_sz) { 10855 /* sanity check. Should never get here */ 10856 uu_die(gettext("Unexpected error! file %s, line %d\n"), 10857 __FILE__, __LINE__); 10858 } 10859 } else { 10860 scf_error_t scf_err; 10861 int err = 0; 10862 10863 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 10864 validate_callback, &inst_fmri, &err, semerr)) != 0) { 10865 uu_warn("Failed to walk instances: %s\n", 10866 scf_strerror(scf_err)); 10867 goto cleanup; 10868 } 10869 if (err != 0) { 10870 /* error message displayed by scf_walk_fmri */ 10871 goto cleanup; 10872 } 10873 } 10874 10875 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 10876 SCF_TMPL_VALIDATE_FLAG_CURRENT); 10877 if (ret == -1) { 10878 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 10879 warn(gettext("Template data for %s is invalid. " 10880 "Consider reverting to a previous snapshot or " 10881 "restoring original configuration.\n"), inst_fmri); 10882 } else { 10883 uu_warn("%s: %s\n", 10884 gettext("Error validating the instance"), 10885 scf_strerror(scf_error())); 10886 } 10887 } else if (ret == 1 && errs != NULL) { 10888 scf_tmpl_error_t *err = NULL; 10889 char *msg; 10890 size_t len = 256; /* initial error buffer size */ 10891 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 10892 SCF_TMPL_STRERROR_HUMAN : 0; 10893 10894 msg = safe_malloc(len); 10895 10896 while ((err = scf_tmpl_next_error(errs)) != NULL) { 10897 int ret; 10898 10899 if ((ret = scf_tmpl_strerror(err, msg, len, 10900 flag)) >= len) { 10901 len = ret + 1; 10902 msg = realloc(msg, len); 10903 if (msg == NULL) 10904 uu_die(gettext( 10905 "Out of memory.\n")); 10906 (void) scf_tmpl_strerror(err, msg, len, 10907 flag); 10908 } 10909 (void) fprintf(stderr, "%s\n", msg); 10910 } 10911 if (msg != NULL) 10912 free(msg); 10913 } 10914 if (errs != NULL) 10915 scf_tmpl_errors_destroy(errs); 10916 10917 cleanup: 10918 free(inst_fmri); 10919 free(snapbuf); 10920 } 10921 10922 static void 10923 lscf_validate_file(const char *filename) 10924 { 10925 tmpl_errors_t *errs; 10926 10927 bundle_t *b = internal_bundle_new(); 10928 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 10929 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 10930 tmpl_errors_print(stderr, errs, ""); 10931 semerr(gettext("Validation failed.\n")); 10932 } 10933 tmpl_errors_destroy(errs); 10934 } 10935 (void) internal_bundle_free(b); 10936 } 10937 10938 /* 10939 * validate [fmri|file] 10940 */ 10941 void 10942 lscf_validate(const char *arg) 10943 { 10944 const char *str; 10945 10946 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 10947 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 10948 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 10949 lscf_validate_file(str); 10950 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 10951 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 10952 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 10953 lscf_validate_fmri(str); 10954 } else if (access(arg, R_OK | F_OK) == 0) { 10955 lscf_validate_file(arg); 10956 } else { 10957 lscf_validate_fmri(arg); 10958 } 10959 } 10960 10961 void 10962 lscf_select(const char *fmri) 10963 { 10964 int ret, err; 10965 10966 lscf_prep_hndl(); 10967 10968 if (cur_snap != NULL) { 10969 struct snaplevel *elt; 10970 char *buf; 10971 10972 /* Error unless name is that of the next level. */ 10973 elt = uu_list_next(cur_levels, cur_elt); 10974 if (elt == NULL) { 10975 semerr(gettext("No children.\n")); 10976 return; 10977 } 10978 10979 buf = safe_malloc(max_scf_name_len + 1); 10980 10981 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10982 max_scf_name_len + 1) < 0) 10983 scfdie(); 10984 10985 if (strcmp(buf, fmri) != 0) { 10986 semerr(gettext("No such child.\n")); 10987 free(buf); 10988 return; 10989 } 10990 10991 free(buf); 10992 10993 cur_elt = elt; 10994 cur_level = elt->sl; 10995 return; 10996 } 10997 10998 /* 10999 * Special case for 'svc:', which takes the user to the scope level. 11000 */ 11001 if (strcmp(fmri, "svc:") == 0) { 11002 scf_instance_destroy(cur_inst); 11003 scf_service_destroy(cur_svc); 11004 cur_inst = NULL; 11005 cur_svc = NULL; 11006 return; 11007 } 11008 11009 /* 11010 * Special case for ':properties'. This appears as part of 'list' but 11011 * can't be selected. Give a more helpful error message in this case. 11012 */ 11013 if (strcmp(fmri, ":properties") == 0) { 11014 semerr(gettext(":properties is not an entity. Try 'listprop' " 11015 "to list properties.\n")); 11016 return; 11017 } 11018 11019 /* 11020 * First try the argument as relative to the current selection. 11021 */ 11022 if (cur_inst != NULL) { 11023 /* EMPTY */; 11024 } else if (cur_svc != NULL) { 11025 if (select_inst(fmri) != 1) 11026 return; 11027 } else { 11028 if (select_svc(fmri) != 1) 11029 return; 11030 } 11031 11032 err = 0; 11033 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11034 select_callback, NULL, &err, semerr)) != 0) { 11035 semerr(gettext("Failed to walk instances: %s\n"), 11036 scf_strerror(ret)); 11037 } 11038 } 11039 11040 void 11041 lscf_unselect(void) 11042 { 11043 lscf_prep_hndl(); 11044 11045 if (cur_snap != NULL) { 11046 struct snaplevel *elt; 11047 11048 elt = uu_list_prev(cur_levels, cur_elt); 11049 if (elt == NULL) { 11050 semerr(gettext("No parent levels.\n")); 11051 } else { 11052 cur_elt = elt; 11053 cur_level = elt->sl; 11054 } 11055 } else if (cur_inst != NULL) { 11056 scf_instance_destroy(cur_inst); 11057 cur_inst = NULL; 11058 } else if (cur_svc != NULL) { 11059 scf_service_destroy(cur_svc); 11060 cur_svc = NULL; 11061 } else { 11062 semerr(gettext("Cannot unselect at scope level.\n")); 11063 } 11064 } 11065 11066 /* 11067 * Return the FMRI of the current selection, for the prompt. 11068 */ 11069 void 11070 lscf_get_selection_str(char *buf, size_t bufsz) 11071 { 11072 char *cp; 11073 ssize_t fmrilen, szret; 11074 boolean_t deleted = B_FALSE; 11075 11076 if (g_hndl == NULL) { 11077 (void) strlcpy(buf, "svc:", bufsz); 11078 return; 11079 } 11080 11081 if (cur_level != NULL) { 11082 assert(cur_snap != NULL); 11083 11084 /* [ snapshot ] FMRI [: instance ] */ 11085 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11086 + 2 + max_scf_name_len + 1 + 1); 11087 11088 buf[0] = '['; 11089 11090 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11091 max_scf_name_len + 1); 11092 if (szret < 0) { 11093 if (scf_error() != SCF_ERROR_DELETED) 11094 scfdie(); 11095 11096 goto snap_deleted; 11097 } 11098 11099 (void) strcat(buf, "]svc:/"); 11100 11101 cp = strchr(buf, '\0'); 11102 11103 szret = scf_snaplevel_get_service_name(cur_level, cp, 11104 max_scf_name_len + 1); 11105 if (szret < 0) { 11106 if (scf_error() != SCF_ERROR_DELETED) 11107 scfdie(); 11108 11109 goto snap_deleted; 11110 } 11111 11112 cp = strchr(cp, '\0'); 11113 11114 if (snaplevel_is_instance(cur_level)) { 11115 *cp++ = ':'; 11116 11117 if (scf_snaplevel_get_instance_name(cur_level, cp, 11118 max_scf_name_len + 1) < 0) { 11119 if (scf_error() != SCF_ERROR_DELETED) 11120 scfdie(); 11121 11122 goto snap_deleted; 11123 } 11124 } else { 11125 *cp++ = '['; 11126 *cp++ = ':'; 11127 11128 if (scf_instance_get_name(cur_inst, cp, 11129 max_scf_name_len + 1) < 0) { 11130 if (scf_error() != SCF_ERROR_DELETED) 11131 scfdie(); 11132 11133 goto snap_deleted; 11134 } 11135 11136 (void) strcat(buf, "]"); 11137 } 11138 11139 return; 11140 11141 snap_deleted: 11142 deleted = B_TRUE; 11143 free(buf); 11144 unselect_cursnap(); 11145 } 11146 11147 assert(cur_snap == NULL); 11148 11149 if (cur_inst != NULL) { 11150 assert(cur_svc != NULL); 11151 assert(cur_scope != NULL); 11152 11153 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11154 if (fmrilen >= 0) { 11155 assert(fmrilen < bufsz); 11156 if (deleted) 11157 warn(emsg_deleted); 11158 return; 11159 } 11160 11161 if (scf_error() != SCF_ERROR_DELETED) 11162 scfdie(); 11163 11164 deleted = B_TRUE; 11165 11166 scf_instance_destroy(cur_inst); 11167 cur_inst = NULL; 11168 } 11169 11170 if (cur_svc != NULL) { 11171 assert(cur_scope != NULL); 11172 11173 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11174 if (szret >= 0) { 11175 assert(szret < bufsz); 11176 if (deleted) 11177 warn(emsg_deleted); 11178 return; 11179 } 11180 11181 if (scf_error() != SCF_ERROR_DELETED) 11182 scfdie(); 11183 11184 deleted = B_TRUE; 11185 scf_service_destroy(cur_svc); 11186 cur_svc = NULL; 11187 } 11188 11189 assert(cur_scope != NULL); 11190 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11191 11192 if (fmrilen < 0) 11193 scfdie(); 11194 11195 assert(fmrilen < bufsz); 11196 if (deleted) 11197 warn(emsg_deleted); 11198 } 11199 11200 /* 11201 * Entity listing. Entities and colon namespaces (e.g., :properties and 11202 * :statistics) are listed for the current selection. 11203 */ 11204 void 11205 lscf_list(const char *pattern) 11206 { 11207 scf_iter_t *iter; 11208 char *buf; 11209 int ret; 11210 11211 lscf_prep_hndl(); 11212 11213 if (cur_level != NULL) { 11214 struct snaplevel *elt; 11215 11216 (void) fputs(COLON_NAMESPACES, stdout); 11217 11218 elt = uu_list_next(cur_levels, cur_elt); 11219 if (elt == NULL) 11220 return; 11221 11222 /* 11223 * For now, we know that the next level is an instance. But 11224 * if we ever have multiple scopes, this could be complicated. 11225 */ 11226 buf = safe_malloc(max_scf_name_len + 1); 11227 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11228 max_scf_name_len + 1) >= 0) { 11229 (void) puts(buf); 11230 } else { 11231 if (scf_error() != SCF_ERROR_DELETED) 11232 scfdie(); 11233 } 11234 11235 free(buf); 11236 11237 return; 11238 } 11239 11240 if (cur_inst != NULL) { 11241 (void) fputs(COLON_NAMESPACES, stdout); 11242 return; 11243 } 11244 11245 iter = scf_iter_create(g_hndl); 11246 if (iter == NULL) 11247 scfdie(); 11248 11249 buf = safe_malloc(max_scf_name_len + 1); 11250 11251 if (cur_svc != NULL) { 11252 /* List the instances in this service. */ 11253 scf_instance_t *inst; 11254 11255 inst = scf_instance_create(g_hndl); 11256 if (inst == NULL) 11257 scfdie(); 11258 11259 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11260 safe_printf(COLON_NAMESPACES); 11261 11262 for (;;) { 11263 ret = scf_iter_next_instance(iter, inst); 11264 if (ret == 0) 11265 break; 11266 if (ret != 1) { 11267 if (scf_error() != SCF_ERROR_DELETED) 11268 scfdie(); 11269 11270 break; 11271 } 11272 11273 if (scf_instance_get_name(inst, buf, 11274 max_scf_name_len + 1) >= 0) { 11275 if (pattern == NULL || 11276 fnmatch(pattern, buf, 0) == 0) 11277 (void) puts(buf); 11278 } else { 11279 if (scf_error() != SCF_ERROR_DELETED) 11280 scfdie(); 11281 } 11282 } 11283 } else { 11284 if (scf_error() != SCF_ERROR_DELETED) 11285 scfdie(); 11286 } 11287 11288 scf_instance_destroy(inst); 11289 } else { 11290 /* List the services in this scope. */ 11291 scf_service_t *svc; 11292 11293 assert(cur_scope != NULL); 11294 11295 svc = scf_service_create(g_hndl); 11296 if (svc == NULL) 11297 scfdie(); 11298 11299 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11300 scfdie(); 11301 11302 for (;;) { 11303 ret = scf_iter_next_service(iter, svc); 11304 if (ret == 0) 11305 break; 11306 if (ret != 1) 11307 scfdie(); 11308 11309 if (scf_service_get_name(svc, buf, 11310 max_scf_name_len + 1) >= 0) { 11311 if (pattern == NULL || 11312 fnmatch(pattern, buf, 0) == 0) 11313 safe_printf("%s\n", buf); 11314 } else { 11315 if (scf_error() != SCF_ERROR_DELETED) 11316 scfdie(); 11317 } 11318 } 11319 11320 scf_service_destroy(svc); 11321 } 11322 11323 free(buf); 11324 scf_iter_destroy(iter); 11325 } 11326 11327 /* 11328 * Entity addition. Creates an empty entity in the current selection. 11329 */ 11330 void 11331 lscf_add(const char *name) 11332 { 11333 lscf_prep_hndl(); 11334 11335 if (cur_snap != NULL) { 11336 semerr(emsg_cant_modify_snapshots); 11337 } else if (cur_inst != NULL) { 11338 semerr(gettext("Cannot add entities to an instance.\n")); 11339 } else if (cur_svc != NULL) { 11340 11341 if (scf_service_add_instance(cur_svc, name, NULL) != 11342 SCF_SUCCESS) { 11343 switch (scf_error()) { 11344 case SCF_ERROR_INVALID_ARGUMENT: 11345 semerr(gettext("Invalid name.\n")); 11346 break; 11347 11348 case SCF_ERROR_EXISTS: 11349 semerr(gettext("Instance already exists.\n")); 11350 break; 11351 11352 case SCF_ERROR_PERMISSION_DENIED: 11353 semerr(emsg_permission_denied); 11354 break; 11355 11356 default: 11357 scfdie(); 11358 } 11359 } 11360 } else { 11361 assert(cur_scope != NULL); 11362 11363 if (scf_scope_add_service(cur_scope, name, NULL) != 11364 SCF_SUCCESS) { 11365 switch (scf_error()) { 11366 case SCF_ERROR_INVALID_ARGUMENT: 11367 semerr(gettext("Invalid name.\n")); 11368 break; 11369 11370 case SCF_ERROR_EXISTS: 11371 semerr(gettext("Service already exists.\n")); 11372 break; 11373 11374 case SCF_ERROR_PERMISSION_DENIED: 11375 semerr(emsg_permission_denied); 11376 break; 11377 11378 case SCF_ERROR_BACKEND_READONLY: 11379 semerr(emsg_read_only); 11380 break; 11381 11382 default: 11383 scfdie(); 11384 } 11385 } 11386 } 11387 } 11388 11389 /* return 1 if the entity has no persistent pgs, else return 0 */ 11390 static int 11391 entity_has_no_pgs(void *ent, int isservice) 11392 { 11393 scf_iter_t *iter = NULL; 11394 scf_propertygroup_t *pg = NULL; 11395 uint32_t flags; 11396 int err; 11397 int ret = 1; 11398 11399 if ((iter = scf_iter_create(g_hndl)) == NULL || 11400 (pg = scf_pg_create(g_hndl)) == NULL) 11401 scfdie(); 11402 11403 if (isservice) { 11404 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11405 scfdie(); 11406 } else { 11407 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11408 scfdie(); 11409 } 11410 11411 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11412 if (scf_pg_get_flags(pg, &flags) != 0) 11413 scfdie(); 11414 11415 /* skip nonpersistent pgs */ 11416 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11417 continue; 11418 11419 ret = 0; 11420 break; 11421 } 11422 11423 if (err == -1) 11424 scfdie(); 11425 11426 scf_pg_destroy(pg); 11427 scf_iter_destroy(iter); 11428 11429 return (ret); 11430 } 11431 11432 /* return 1 if the service has no instances, else return 0 */ 11433 static int 11434 svc_has_no_insts(scf_service_t *svc) 11435 { 11436 scf_instance_t *inst; 11437 scf_iter_t *iter; 11438 int r; 11439 int ret = 1; 11440 11441 if ((inst = scf_instance_create(g_hndl)) == NULL || 11442 (iter = scf_iter_create(g_hndl)) == NULL) 11443 scfdie(); 11444 11445 if (scf_iter_service_instances(iter, svc) != 0) 11446 scfdie(); 11447 11448 r = scf_iter_next_instance(iter, inst); 11449 if (r == 1) { 11450 ret = 0; 11451 } else if (r == 0) { 11452 ret = 1; 11453 } else if (r == -1) { 11454 scfdie(); 11455 } else { 11456 bad_error("scf_iter_next_instance", r); 11457 } 11458 11459 scf_iter_destroy(iter); 11460 scf_instance_destroy(inst); 11461 11462 return (ret); 11463 } 11464 11465 /* 11466 * Entity deletion. 11467 */ 11468 11469 /* 11470 * Delete the property group <fmri>/:properties/<name>. Returns 11471 * SCF_ERROR_NONE on success (or if the entity is not found), 11472 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 11473 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 11474 * denied. 11475 */ 11476 static scf_error_t 11477 delete_dependency_pg(const char *fmri, const char *name) 11478 { 11479 void *entity = NULL; 11480 int isservice; 11481 scf_propertygroup_t *pg = NULL; 11482 scf_error_t result; 11483 char *pgty; 11484 scf_service_t *svc = NULL; 11485 scf_instance_t *inst = NULL; 11486 scf_iter_t *iter = NULL; 11487 char *name_buf = NULL; 11488 11489 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 11490 switch (result) { 11491 case SCF_ERROR_NONE: 11492 break; 11493 11494 case SCF_ERROR_NO_MEMORY: 11495 uu_die(gettext("Out of memory.\n")); 11496 /* NOTREACHED */ 11497 11498 case SCF_ERROR_INVALID_ARGUMENT: 11499 case SCF_ERROR_CONSTRAINT_VIOLATED: 11500 return (SCF_ERROR_INVALID_ARGUMENT); 11501 11502 case SCF_ERROR_NOT_FOUND: 11503 result = SCF_ERROR_NONE; 11504 goto out; 11505 11506 default: 11507 bad_error("fmri_to_entity", result); 11508 } 11509 11510 pg = scf_pg_create(g_hndl); 11511 if (pg == NULL) 11512 scfdie(); 11513 11514 if (entity_get_pg(entity, isservice, name, pg) != 0) { 11515 if (scf_error() != SCF_ERROR_NOT_FOUND) 11516 scfdie(); 11517 11518 result = SCF_ERROR_NONE; 11519 goto out; 11520 } 11521 11522 pgty = safe_malloc(max_scf_pg_type_len + 1); 11523 11524 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 11525 scfdie(); 11526 11527 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 11528 result = SCF_ERROR_TYPE_MISMATCH; 11529 free(pgty); 11530 goto out; 11531 } 11532 11533 free(pgty); 11534 11535 if (scf_pg_delete(pg) != 0) { 11536 result = scf_error(); 11537 if (result != SCF_ERROR_PERMISSION_DENIED) 11538 scfdie(); 11539 goto out; 11540 } 11541 11542 /* 11543 * We have to handle the case where we've just deleted the last 11544 * property group of a "dummy" entity (instance or service). 11545 * A "dummy" entity is an entity only present to hold an 11546 * external dependency. 11547 * So, in the case we deleted the last property group then we 11548 * can also delete the entity. If the entity is an instance then 11549 * we must verify if this was the last instance for the service 11550 * and if it is, we can also delete the service if it doesn't 11551 * have any property group either. 11552 */ 11553 11554 result = SCF_ERROR_NONE; 11555 11556 if (isservice) { 11557 svc = (scf_service_t *)entity; 11558 11559 if ((inst = scf_instance_create(g_hndl)) == NULL || 11560 (iter = scf_iter_create(g_hndl)) == NULL) 11561 scfdie(); 11562 11563 name_buf = safe_malloc(max_scf_name_len + 1); 11564 } else { 11565 inst = (scf_instance_t *)entity; 11566 } 11567 11568 /* 11569 * If the entity is an instance and we've just deleted its last 11570 * property group then we should delete it. 11571 */ 11572 if (!isservice && entity_has_no_pgs(entity, isservice)) { 11573 /* find the service before deleting the inst. - needed later */ 11574 if ((svc = scf_service_create(g_hndl)) == NULL) 11575 scfdie(); 11576 11577 if (scf_instance_get_parent(inst, svc) != 0) 11578 scfdie(); 11579 11580 /* delete the instance */ 11581 if (scf_instance_delete(inst) != 0) { 11582 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11583 scfdie(); 11584 11585 result = SCF_ERROR_PERMISSION_DENIED; 11586 goto out; 11587 } 11588 /* no need to refresh the instance */ 11589 inst = NULL; 11590 } 11591 11592 /* 11593 * If the service has no more instances and pgs or we just deleted the 11594 * last instance and the service doesn't have anymore propery groups 11595 * then the service should be deleted. 11596 */ 11597 if (svc != NULL && 11598 svc_has_no_insts(svc) && 11599 entity_has_no_pgs((void *)svc, 1)) { 11600 if (scf_service_delete(svc) == 0) { 11601 if (isservice) { 11602 /* no need to refresh the service */ 11603 svc = NULL; 11604 } 11605 11606 goto out; 11607 } 11608 11609 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11610 scfdie(); 11611 11612 result = SCF_ERROR_PERMISSION_DENIED; 11613 } 11614 11615 /* if the entity has not been deleted, refresh it */ 11616 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 11617 (void) refresh_entity(isservice, entity, fmri, inst, iter, 11618 name_buf); 11619 } 11620 11621 out: 11622 if (isservice && (inst != NULL && iter != NULL)) { 11623 free(name_buf); 11624 scf_iter_destroy(iter); 11625 scf_instance_destroy(inst); 11626 } 11627 11628 if (!isservice && svc != NULL) { 11629 scf_service_destroy(svc); 11630 } 11631 11632 scf_pg_destroy(pg); 11633 if (entity != NULL) 11634 entity_destroy(entity, isservice); 11635 11636 return (result); 11637 } 11638 11639 static int 11640 delete_dependents(scf_propertygroup_t *pg) 11641 { 11642 char *pgty, *name, *fmri; 11643 scf_property_t *prop; 11644 scf_value_t *val; 11645 scf_iter_t *iter; 11646 int r; 11647 scf_error_t err; 11648 11649 /* Verify that the pg has the correct type. */ 11650 pgty = safe_malloc(max_scf_pg_type_len + 1); 11651 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 11652 scfdie(); 11653 11654 if (strcmp(pgty, scf_group_framework) != 0) { 11655 if (g_verbose) { 11656 fmri = safe_malloc(max_scf_fmri_len + 1); 11657 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 11658 scfdie(); 11659 11660 warn(gettext("Property group %s is not of expected " 11661 "type %s.\n"), fmri, scf_group_framework); 11662 11663 free(fmri); 11664 } 11665 11666 free(pgty); 11667 return (-1); 11668 } 11669 11670 free(pgty); 11671 11672 /* map delete_dependency_pg onto the properties. */ 11673 if ((prop = scf_property_create(g_hndl)) == NULL || 11674 (val = scf_value_create(g_hndl)) == NULL || 11675 (iter = scf_iter_create(g_hndl)) == NULL) 11676 scfdie(); 11677 11678 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 11679 scfdie(); 11680 11681 name = safe_malloc(max_scf_name_len + 1); 11682 fmri = safe_malloc(max_scf_fmri_len + 2); 11683 11684 while ((r = scf_iter_next_property(iter, prop)) == 1) { 11685 scf_type_t ty; 11686 11687 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 11688 scfdie(); 11689 11690 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 11691 scfdie(); 11692 11693 if ((ty != SCF_TYPE_ASTRING && 11694 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 11695 prop_get_val(prop, val) != 0) 11696 continue; 11697 11698 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 11699 scfdie(); 11700 11701 err = delete_dependency_pg(fmri, name); 11702 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 11703 if (scf_property_to_fmri(prop, fmri, 11704 max_scf_fmri_len + 2) < 0) 11705 scfdie(); 11706 11707 warn(gettext("Value of %s is not a valid FMRI.\n"), 11708 fmri); 11709 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 11710 warn(gettext("Property group \"%s\" of entity \"%s\" " 11711 "does not have dependency type.\n"), name, fmri); 11712 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 11713 warn(gettext("Could not delete property group \"%s\" " 11714 "of entity \"%s\" (permission denied).\n"), name, 11715 fmri); 11716 } 11717 } 11718 if (r == -1) 11719 scfdie(); 11720 11721 scf_value_destroy(val); 11722 scf_property_destroy(prop); 11723 11724 return (0); 11725 } 11726 11727 /* 11728 * Returns 1 if the instance may be running, and 0 otherwise. 11729 */ 11730 static int 11731 inst_is_running(scf_instance_t *inst) 11732 { 11733 scf_propertygroup_t *pg; 11734 scf_property_t *prop; 11735 scf_value_t *val; 11736 char buf[MAX_SCF_STATE_STRING_SZ]; 11737 int ret = 0; 11738 ssize_t szret; 11739 11740 if ((pg = scf_pg_create(g_hndl)) == NULL || 11741 (prop = scf_property_create(g_hndl)) == NULL || 11742 (val = scf_value_create(g_hndl)) == NULL) 11743 scfdie(); 11744 11745 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 11746 if (scf_error() != SCF_ERROR_NOT_FOUND) 11747 scfdie(); 11748 goto out; 11749 } 11750 11751 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 11752 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 11753 prop_get_val(prop, val) != 0) 11754 goto out; 11755 11756 szret = scf_value_get_astring(val, buf, sizeof (buf)); 11757 assert(szret >= 0); 11758 11759 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 11760 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 11761 11762 out: 11763 scf_value_destroy(val); 11764 scf_property_destroy(prop); 11765 scf_pg_destroy(pg); 11766 return (ret); 11767 } 11768 11769 static uint8_t 11770 pg_is_external_dependency(scf_propertygroup_t *pg) 11771 { 11772 char *type; 11773 scf_value_t *val; 11774 scf_property_t *prop; 11775 uint8_t b = B_FALSE; 11776 11777 type = safe_malloc(max_scf_pg_type_len + 1); 11778 11779 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 11780 scfdie(); 11781 11782 if ((prop = scf_property_create(g_hndl)) == NULL || 11783 (val = scf_value_create(g_hndl)) == NULL) 11784 scfdie(); 11785 11786 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 11787 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 11788 if (scf_property_get_value(prop, val) != 0) 11789 scfdie(); 11790 if (scf_value_get_boolean(val, &b) != 0) 11791 scfdie(); 11792 } 11793 } 11794 11795 free(type); 11796 (void) scf_value_destroy(val); 11797 (void) scf_property_destroy(prop); 11798 11799 return (b); 11800 } 11801 11802 #define DELETE_FAILURE -1 11803 #define DELETE_SUCCESS_NOEXTDEPS 0 11804 #define DELETE_SUCCESS_EXTDEPS 1 11805 11806 /* 11807 * lscf_instance_delete() deletes an instance. Before calling 11808 * scf_instance_delete(), though, we make sure the instance isn't 11809 * running and delete dependencies in other entities which the instance 11810 * declared as "dependents". If there are dependencies which were 11811 * created for other entities, then instead of deleting the instance we 11812 * make it "empty" by deleting all other property groups and all 11813 * snapshots. 11814 * 11815 * lscf_instance_delete() verifies that there is no external dependency pgs 11816 * before suppressing the instance. If there is, then we must not remove them 11817 * now in case the instance is re-created otherwise the dependencies would be 11818 * lost. The external dependency pgs will be removed if the dependencies are 11819 * removed. 11820 * 11821 * Returns: 11822 * DELETE_FAILURE on failure 11823 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 11824 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 11825 */ 11826 static int 11827 lscf_instance_delete(scf_instance_t *inst, int force) 11828 { 11829 scf_propertygroup_t *pg; 11830 scf_snapshot_t *snap; 11831 scf_iter_t *iter; 11832 int err; 11833 int external = 0; 11834 11835 /* If we're not forcing and the instance is running, refuse. */ 11836 if (!force && inst_is_running(inst)) { 11837 char *fmri; 11838 11839 fmri = safe_malloc(max_scf_fmri_len + 1); 11840 11841 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 11842 scfdie(); 11843 11844 semerr(gettext("Instance %s may be running. " 11845 "Use delete -f if it is not.\n"), fmri); 11846 11847 free(fmri); 11848 return (DELETE_FAILURE); 11849 } 11850 11851 pg = scf_pg_create(g_hndl); 11852 if (pg == NULL) 11853 scfdie(); 11854 11855 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 11856 (void) delete_dependents(pg); 11857 else if (scf_error() != SCF_ERROR_NOT_FOUND) 11858 scfdie(); 11859 11860 scf_pg_destroy(pg); 11861 11862 /* 11863 * If the instance has some external dependencies then we must 11864 * keep them in case the instance is reimported otherwise the 11865 * dependencies would be lost on reimport. 11866 */ 11867 if ((iter = scf_iter_create(g_hndl)) == NULL || 11868 (pg = scf_pg_create(g_hndl)) == NULL) 11869 scfdie(); 11870 11871 if (scf_iter_instance_pgs(iter, inst) < 0) 11872 scfdie(); 11873 11874 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11875 if (pg_is_external_dependency(pg)) { 11876 external = 1; 11877 continue; 11878 } 11879 11880 if (scf_pg_delete(pg) != 0) { 11881 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11882 scfdie(); 11883 else { 11884 semerr(emsg_permission_denied); 11885 11886 (void) scf_iter_destroy(iter); 11887 (void) scf_pg_destroy(pg); 11888 return (DELETE_FAILURE); 11889 } 11890 } 11891 } 11892 11893 if (err == -1) 11894 scfdie(); 11895 11896 (void) scf_iter_destroy(iter); 11897 (void) scf_pg_destroy(pg); 11898 11899 if (external) { 11900 /* 11901 * All the pgs have been deleted for the instance except 11902 * the ones holding the external dependencies. 11903 * For the job to be complete, we must also delete the 11904 * snapshots associated with the instance. 11905 */ 11906 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 11907 NULL) 11908 scfdie(); 11909 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 11910 scfdie(); 11911 11912 if (scf_iter_instance_snapshots(iter, inst) == -1) 11913 scfdie(); 11914 11915 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 11916 if (_scf_snapshot_delete(snap) != 0) { 11917 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11918 scfdie(); 11919 11920 semerr(emsg_permission_denied); 11921 11922 (void) scf_iter_destroy(iter); 11923 (void) scf_snapshot_destroy(snap); 11924 return (DELETE_FAILURE); 11925 } 11926 } 11927 11928 if (err == -1) 11929 scfdie(); 11930 11931 (void) scf_iter_destroy(iter); 11932 (void) scf_snapshot_destroy(snap); 11933 return (DELETE_SUCCESS_EXTDEPS); 11934 } 11935 11936 if (scf_instance_delete(inst) != 0) { 11937 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11938 scfdie(); 11939 11940 semerr(emsg_permission_denied); 11941 11942 return (DELETE_FAILURE); 11943 } 11944 11945 return (DELETE_SUCCESS_NOEXTDEPS); 11946 } 11947 11948 /* 11949 * lscf_service_delete() deletes a service. Before calling 11950 * scf_service_delete(), though, we call lscf_instance_delete() for 11951 * each of the instances and delete dependencies in other entities 11952 * which were created as "dependents" of this service. If there are 11953 * dependencies which were created for other entities, then we delete 11954 * all other property groups in the service and leave it as "empty". 11955 * 11956 * lscf_service_delete() verifies that there is no external dependency 11957 * pgs at the instance & service level before suppressing the service. 11958 * If there is, then we must not remove them now in case the service 11959 * is re-imported otherwise the dependencies would be lost. The external 11960 * dependency pgs will be removed if the dependencies are removed. 11961 * 11962 * Returns: 11963 * DELETE_FAILURE on failure 11964 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 11965 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 11966 */ 11967 static int 11968 lscf_service_delete(scf_service_t *svc, int force) 11969 { 11970 int r; 11971 scf_instance_t *inst; 11972 scf_propertygroup_t *pg; 11973 scf_iter_t *iter; 11974 int ret; 11975 int external = 0; 11976 11977 if ((inst = scf_instance_create(g_hndl)) == NULL || 11978 (pg = scf_pg_create(g_hndl)) == NULL || 11979 (iter = scf_iter_create(g_hndl)) == NULL) 11980 scfdie(); 11981 11982 if (scf_iter_service_instances(iter, svc) != 0) 11983 scfdie(); 11984 11985 for (r = scf_iter_next_instance(iter, inst); 11986 r == 1; 11987 r = scf_iter_next_instance(iter, inst)) { 11988 11989 ret = lscf_instance_delete(inst, force); 11990 if (ret == DELETE_FAILURE) { 11991 scf_iter_destroy(iter); 11992 scf_pg_destroy(pg); 11993 scf_instance_destroy(inst); 11994 return (DELETE_FAILURE); 11995 } 11996 11997 /* 11998 * Record the fact that there is some external dependencies 11999 * at the instance level. 12000 */ 12001 if (ret == DELETE_SUCCESS_EXTDEPS) 12002 external |= 1; 12003 } 12004 12005 if (r != 0) 12006 scfdie(); 12007 12008 /* Delete dependency property groups in dependent services. */ 12009 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12010 (void) delete_dependents(pg); 12011 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12012 scfdie(); 12013 12014 scf_iter_destroy(iter); 12015 scf_pg_destroy(pg); 12016 scf_instance_destroy(inst); 12017 12018 /* 12019 * If the service has some external dependencies then we don't 12020 * want to remove them in case the service is re-imported. 12021 */ 12022 if ((pg = scf_pg_create(g_hndl)) == NULL || 12023 (iter = scf_iter_create(g_hndl)) == NULL) 12024 scfdie(); 12025 12026 if (scf_iter_service_pgs(iter, svc) < 0) 12027 scfdie(); 12028 12029 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12030 if (pg_is_external_dependency(pg)) { 12031 external |= 2; 12032 continue; 12033 } 12034 12035 if (scf_pg_delete(pg) != 0) { 12036 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12037 scfdie(); 12038 else { 12039 semerr(emsg_permission_denied); 12040 12041 (void) scf_iter_destroy(iter); 12042 (void) scf_pg_destroy(pg); 12043 return (DELETE_FAILURE); 12044 } 12045 } 12046 } 12047 12048 if (r == -1) 12049 scfdie(); 12050 12051 (void) scf_iter_destroy(iter); 12052 (void) scf_pg_destroy(pg); 12053 12054 if (external != 0) 12055 return (DELETE_SUCCESS_EXTDEPS); 12056 12057 if (scf_service_delete(svc) == 0) 12058 return (DELETE_SUCCESS_NOEXTDEPS); 12059 12060 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12061 scfdie(); 12062 12063 semerr(emsg_permission_denied); 12064 return (DELETE_FAILURE); 12065 } 12066 12067 static int 12068 delete_callback(void *data, scf_walkinfo_t *wip) 12069 { 12070 int force = (int)data; 12071 12072 if (wip->inst != NULL) 12073 (void) lscf_instance_delete(wip->inst, force); 12074 else 12075 (void) lscf_service_delete(wip->svc, force); 12076 12077 return (0); 12078 } 12079 12080 void 12081 lscf_delete(const char *fmri, int force) 12082 { 12083 scf_service_t *svc; 12084 scf_instance_t *inst; 12085 int ret; 12086 12087 lscf_prep_hndl(); 12088 12089 if (cur_snap != NULL) { 12090 if (!snaplevel_is_instance(cur_level)) { 12091 char *buf; 12092 12093 buf = safe_malloc(max_scf_name_len + 1); 12094 if (scf_instance_get_name(cur_inst, buf, 12095 max_scf_name_len + 1) >= 0) { 12096 if (strcmp(buf, fmri) == 0) { 12097 semerr(emsg_cant_modify_snapshots); 12098 free(buf); 12099 return; 12100 } 12101 } else if (scf_error() != SCF_ERROR_DELETED) { 12102 scfdie(); 12103 } 12104 free(buf); 12105 } 12106 } else if (cur_inst != NULL) { 12107 /* EMPTY */; 12108 } else if (cur_svc != NULL) { 12109 inst = scf_instance_create(g_hndl); 12110 if (inst == NULL) 12111 scfdie(); 12112 12113 if (scf_service_get_instance(cur_svc, fmri, inst) == 12114 SCF_SUCCESS) { 12115 (void) lscf_instance_delete(inst, force); 12116 scf_instance_destroy(inst); 12117 return; 12118 } 12119 12120 if (scf_error() != SCF_ERROR_NOT_FOUND && 12121 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12122 scfdie(); 12123 12124 scf_instance_destroy(inst); 12125 } else { 12126 assert(cur_scope != NULL); 12127 12128 svc = scf_service_create(g_hndl); 12129 if (svc == NULL) 12130 scfdie(); 12131 12132 if (scf_scope_get_service(cur_scope, fmri, svc) == 12133 SCF_SUCCESS) { 12134 (void) lscf_service_delete(svc, force); 12135 scf_service_destroy(svc); 12136 return; 12137 } 12138 12139 if (scf_error() != SCF_ERROR_NOT_FOUND && 12140 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12141 scfdie(); 12142 12143 scf_service_destroy(svc); 12144 } 12145 12146 /* 12147 * Match FMRI to entity. 12148 */ 12149 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12150 delete_callback, (void *)force, NULL, semerr)) != 0) { 12151 semerr(gettext("Failed to walk instances: %s\n"), 12152 scf_strerror(ret)); 12153 } 12154 } 12155 12156 12157 12158 /* 12159 * :properties commands. These all end with "pg" or "prop" and generally 12160 * operate on the currently selected entity. 12161 */ 12162 12163 /* 12164 * Property listing. List the property groups, properties, their types and 12165 * their values for the currently selected entity. 12166 */ 12167 static void 12168 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12169 { 12170 char *buf; 12171 uint32_t flags; 12172 12173 buf = safe_malloc(max_scf_pg_type_len + 1); 12174 12175 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12176 scfdie(); 12177 12178 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12179 scfdie(); 12180 12181 safe_printf("%-*s %s", namewidth, name, buf); 12182 12183 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12184 safe_printf("\tNONPERSISTENT"); 12185 12186 safe_printf("\n"); 12187 12188 free(buf); 12189 } 12190 12191 static boolean_t 12192 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12193 { 12194 if (scf_property_get_value(prop, val) == 0) { 12195 return (B_FALSE); 12196 } else { 12197 switch (scf_error()) { 12198 case SCF_ERROR_NOT_FOUND: 12199 return (B_FALSE); 12200 case SCF_ERROR_PERMISSION_DENIED: 12201 case SCF_ERROR_CONSTRAINT_VIOLATED: 12202 return (B_TRUE); 12203 default: 12204 scfdie(); 12205 /*NOTREACHED*/ 12206 } 12207 } 12208 } 12209 12210 static void 12211 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12212 { 12213 scf_iter_t *iter; 12214 scf_value_t *val; 12215 const char *type; 12216 int multiple_strings = 0; 12217 int ret; 12218 12219 if ((iter = scf_iter_create(g_hndl)) == NULL || 12220 (val = scf_value_create(g_hndl)) == NULL) 12221 scfdie(); 12222 12223 type = prop_to_typestr(prop); 12224 assert(type != NULL); 12225 12226 safe_printf("%-*s %-7s ", len, name, type); 12227 12228 if (prop_has_multiple_values(prop, val) && 12229 (scf_value_type(val) == SCF_TYPE_ASTRING || 12230 scf_value_type(val) == SCF_TYPE_USTRING)) 12231 multiple_strings = 1; 12232 12233 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12234 scfdie(); 12235 12236 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12237 char *buf; 12238 ssize_t vlen, szret; 12239 12240 vlen = scf_value_get_as_string(val, NULL, 0); 12241 if (vlen < 0) 12242 scfdie(); 12243 12244 buf = safe_malloc(vlen + 1); 12245 12246 szret = scf_value_get_as_string(val, buf, vlen + 1); 12247 if (szret < 0) 12248 scfdie(); 12249 assert(szret <= vlen); 12250 12251 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12252 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12253 safe_printf(" \""); 12254 (void) quote_and_print(buf, stdout, 0); 12255 (void) putchar('"'); 12256 if (ferror(stdout)) { 12257 (void) putchar('\n'); 12258 uu_die(gettext("Error writing to stdout.\n")); 12259 } 12260 } else { 12261 safe_printf(" %s", buf); 12262 } 12263 12264 free(buf); 12265 } 12266 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12267 scfdie(); 12268 12269 if (putchar('\n') != '\n') 12270 uu_die(gettext("Could not output newline")); 12271 } 12272 12273 /* 12274 * Outputs template property group info for the describe subcommand. 12275 * If 'templates' == 2, verbose output is printed in the format expected 12276 * for describe -v, which includes all templates fields. If pg is 12277 * not NULL, we're describing the template data, not an existing property 12278 * group, and formatting should be appropriate for describe -t. 12279 */ 12280 static void 12281 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12282 { 12283 char *buf; 12284 uint8_t required; 12285 scf_property_t *stability_prop; 12286 scf_value_t *stability_val; 12287 12288 if (templates == 0) 12289 return; 12290 12291 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12292 (stability_val = scf_value_create(g_hndl)) == NULL) 12293 scfdie(); 12294 12295 if (templates == 2 && pg != NULL) { 12296 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12297 stability_prop) == 0) { 12298 if (prop_check_type(stability_prop, 12299 SCF_TYPE_ASTRING) == 0 && 12300 prop_get_val(stability_prop, stability_val) == 0) { 12301 char *stability; 12302 12303 stability = safe_malloc(max_scf_value_len + 1); 12304 12305 if (scf_value_get_astring(stability_val, 12306 stability, max_scf_value_len + 1) == -1 && 12307 scf_error() != SCF_ERROR_NOT_FOUND) 12308 scfdie(); 12309 12310 safe_printf("%s%s: %s\n", TMPL_INDENT, 12311 gettext("stability"), stability); 12312 12313 free(stability); 12314 } 12315 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12316 scfdie(); 12317 } 12318 12319 scf_property_destroy(stability_prop); 12320 scf_value_destroy(stability_val); 12321 12322 if (pgt == NULL) 12323 return; 12324 12325 if (pg == NULL || templates == 2) { 12326 /* print type info only if scf_tmpl_pg_name succeeds */ 12327 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12328 if (pg != NULL) 12329 safe_printf("%s", TMPL_INDENT); 12330 safe_printf("%s: ", gettext("name")); 12331 safe_printf("%s\n", buf); 12332 free(buf); 12333 } 12334 12335 /* print type info only if scf_tmpl_pg_type succeeds */ 12336 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12337 if (pg != NULL) 12338 safe_printf("%s", TMPL_INDENT); 12339 safe_printf("%s: ", gettext("type")); 12340 safe_printf("%s\n", buf); 12341 free(buf); 12342 } 12343 } 12344 12345 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12346 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12347 required ? "true" : "false"); 12348 12349 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12350 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12351 buf); 12352 free(buf); 12353 } 12354 12355 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12356 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12357 buf); 12358 free(buf); 12359 } 12360 12361 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12362 if (templates == 2) 12363 safe_printf("%s%s: %s\n", TMPL_INDENT, 12364 gettext("description"), buf); 12365 else 12366 safe_printf("%s%s\n", TMPL_INDENT, buf); 12367 free(buf); 12368 } 12369 12370 } 12371 12372 /* 12373 * With as_value set to true, indent as appropriate for the value level. 12374 * If false, indent to appropriate level for inclusion in constraint 12375 * or choice printout. 12376 */ 12377 static void 12378 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12379 int as_value) 12380 { 12381 char *buf; 12382 12383 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12384 if (as_value == 0) 12385 safe_printf("%s", TMPL_CHOICE_INDENT); 12386 else 12387 safe_printf("%s", TMPL_INDENT); 12388 safe_printf("%s: %s\n", gettext("value common name"), buf); 12389 free(buf); 12390 } 12391 12392 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12393 if (as_value == 0) 12394 safe_printf("%s", TMPL_CHOICE_INDENT); 12395 else 12396 safe_printf("%s", TMPL_INDENT); 12397 safe_printf("%s: %s\n", gettext("value description"), buf); 12398 free(buf); 12399 } 12400 } 12401 12402 static void 12403 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12404 { 12405 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12406 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12407 safe_printf("%s\n", val_buf); 12408 12409 print_template_value_details(prt, val_buf, 1); 12410 } 12411 12412 static void 12413 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12414 { 12415 int i, printed = 0; 12416 scf_values_t values; 12417 scf_count_ranges_t c_ranges; 12418 scf_int_ranges_t i_ranges; 12419 12420 printed = 0; 12421 i = 0; 12422 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12423 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12424 gettext("value constraints")); 12425 printed++; 12426 for (i = 0; i < values.value_count; ++i) { 12427 safe_printf("%s%s: %s\n", TMPL_INDENT, 12428 gettext("value name"), values.values_as_strings[i]); 12429 if (verbose == 1) 12430 print_template_value_details(prt, 12431 values.values_as_strings[i], 0); 12432 } 12433 12434 scf_values_destroy(&values); 12435 } 12436 12437 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12438 if (printed++ == 0) 12439 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12440 gettext("value constraints")); 12441 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12442 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12443 gettext("range"), c_ranges.scr_min[i], 12444 c_ranges.scr_max[i]); 12445 } 12446 scf_count_ranges_destroy(&c_ranges); 12447 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12448 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 12449 if (printed++ == 0) 12450 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12451 gettext("value constraints")); 12452 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12453 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12454 gettext("range"), i_ranges.sir_min[i], 12455 i_ranges.sir_max[i]); 12456 } 12457 scf_int_ranges_destroy(&i_ranges); 12458 } 12459 } 12460 12461 static void 12462 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 12463 { 12464 int i = 0, printed = 0; 12465 scf_values_t values; 12466 scf_count_ranges_t c_ranges; 12467 scf_int_ranges_t i_ranges; 12468 12469 printed = 0; 12470 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 12471 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12472 gettext("value constraints")); 12473 printed++; 12474 for (i = 0; i < values.value_count; i++) { 12475 safe_printf("%s%s: %s\n", TMPL_INDENT, 12476 gettext("value name"), values.values_as_strings[i]); 12477 if (verbose == 1) 12478 print_template_value_details(prt, 12479 values.values_as_strings[i], 0); 12480 } 12481 12482 scf_values_destroy(&values); 12483 } 12484 12485 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 12486 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12487 if (printed++ == 0) 12488 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12489 gettext("value choices")); 12490 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12491 gettext("range"), c_ranges.scr_min[i], 12492 c_ranges.scr_max[i]); 12493 } 12494 scf_count_ranges_destroy(&c_ranges); 12495 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12496 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 12497 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12498 if (printed++ == 0) 12499 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12500 gettext("value choices")); 12501 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12502 gettext("range"), i_ranges.sir_min[i], 12503 i_ranges.sir_max[i]); 12504 } 12505 scf_int_ranges_destroy(&i_ranges); 12506 } 12507 } 12508 12509 static void 12510 list_values_by_template(scf_prop_tmpl_t *prt) 12511 { 12512 print_template_constraints(prt, 1); 12513 print_template_choices(prt, 1); 12514 } 12515 12516 static void 12517 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 12518 { 12519 char *val_buf; 12520 scf_iter_t *iter; 12521 scf_value_t *val; 12522 int ret; 12523 12524 if ((iter = scf_iter_create(g_hndl)) == NULL || 12525 (val = scf_value_create(g_hndl)) == NULL) 12526 scfdie(); 12527 12528 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12529 scfdie(); 12530 12531 val_buf = safe_malloc(max_scf_value_len + 1); 12532 12533 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12534 if (scf_value_get_as_string(val, val_buf, 12535 max_scf_value_len + 1) < 0) 12536 scfdie(); 12537 12538 print_template_value(prt, val_buf); 12539 } 12540 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12541 scfdie(); 12542 free(val_buf); 12543 12544 print_template_constraints(prt, 0); 12545 print_template_choices(prt, 0); 12546 12547 } 12548 12549 /* 12550 * Outputs property info for the describe subcommand 12551 * Verbose output if templates == 2, -v option of svccfg describe 12552 * Displays template data if prop is not NULL, -t option of svccfg describe 12553 */ 12554 static void 12555 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 12556 { 12557 char *buf; 12558 uint8_t u_buf; 12559 int i; 12560 uint64_t min, max; 12561 scf_values_t values; 12562 12563 if (prt == NULL || templates == 0) 12564 return; 12565 12566 if (prop == NULL) { 12567 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 12568 if (scf_tmpl_prop_name(prt, &buf) > 0) { 12569 safe_printf("%s\n", buf); 12570 free(buf); 12571 } else 12572 safe_printf("(%s)\n", gettext("any")); 12573 } 12574 12575 if (prop == NULL || templates == 2) { 12576 if (prop != NULL) 12577 safe_printf("%s", TMPL_INDENT); 12578 else 12579 safe_printf("%s", TMPL_VALUE_INDENT); 12580 safe_printf("%s: ", gettext("type")); 12581 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 12582 safe_printf("%s\n", buf); 12583 free(buf); 12584 } else 12585 safe_printf("(%s)\n", gettext("any")); 12586 } 12587 12588 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 12589 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12590 u_buf ? "true" : "false"); 12591 12592 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 12593 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12594 buf); 12595 free(buf); 12596 } 12597 12598 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 12599 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 12600 buf); 12601 free(buf); 12602 } 12603 12604 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 12605 safe_printf("%s%s\n", TMPL_INDENT, buf); 12606 free(buf); 12607 } 12608 12609 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 12610 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 12611 scf_tmpl_visibility_to_string(u_buf)); 12612 12613 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 12614 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 12615 gettext("minimum number of values"), min); 12616 if (max == ULLONG_MAX) { 12617 safe_printf("%s%s: %s\n", TMPL_INDENT, 12618 gettext("maximum number of values"), 12619 gettext("unlimited")); 12620 } else { 12621 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 12622 gettext("maximum number of values"), max); 12623 } 12624 } 12625 12626 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 12627 for (i = 0; i < values.value_count; i++) { 12628 if (i == 0) { 12629 safe_printf("%s%s:", TMPL_INDENT, 12630 gettext("internal separators")); 12631 } 12632 safe_printf(" \"%s\"", values.values_as_strings[i]); 12633 } 12634 safe_printf("\n"); 12635 } 12636 12637 if (templates != 2) 12638 return; 12639 12640 if (prop != NULL) 12641 list_values_tmpl(prt, prop); 12642 else 12643 list_values_by_template(prt); 12644 } 12645 12646 static char * 12647 read_astring(scf_propertygroup_t *pg, const char *prop_name) 12648 { 12649 char *rv; 12650 12651 rv = _scf_read_single_astring_from_pg(pg, prop_name); 12652 if (rv == NULL) { 12653 switch (scf_error()) { 12654 case SCF_ERROR_NOT_FOUND: 12655 break; 12656 default: 12657 scfdie(); 12658 } 12659 } 12660 return (rv); 12661 } 12662 12663 static void 12664 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 12665 { 12666 size_t doc_len; 12667 size_t man_len; 12668 char *pg_name; 12669 char *text = NULL; 12670 int rv; 12671 12672 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 12673 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 12674 pg_name = safe_malloc(max_scf_name_len + 1); 12675 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 12676 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 12677 scfdie(); 12678 } 12679 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 12680 /* Display doc_link and and uri */ 12681 safe_printf("%s%s:\n", TMPL_INDENT, 12682 gettext("doc_link")); 12683 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 12684 if (text != NULL) { 12685 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12686 TMPL_INDENT, gettext("name"), text); 12687 uu_free(text); 12688 } 12689 text = read_astring(pg, SCF_PROPERTY_TM_URI); 12690 if (text != NULL) { 12691 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 12692 gettext("uri"), text); 12693 uu_free(text); 12694 } 12695 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 12696 man_len) == 0) { 12697 /* Display manpage title, section and path */ 12698 safe_printf("%s%s:\n", TMPL_INDENT, 12699 gettext("manpage")); 12700 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 12701 if (text != NULL) { 12702 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12703 TMPL_INDENT, gettext("title"), text); 12704 uu_free(text); 12705 } 12706 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 12707 if (text != NULL) { 12708 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12709 TMPL_INDENT, gettext("section"), text); 12710 uu_free(text); 12711 } 12712 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 12713 if (text != NULL) { 12714 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12715 TMPL_INDENT, gettext("manpath"), text); 12716 uu_free(text); 12717 } 12718 } 12719 } 12720 if (rv == -1) 12721 scfdie(); 12722 12723 done: 12724 free(pg_name); 12725 } 12726 12727 static void 12728 list_entity_tmpl(int templates) 12729 { 12730 char *common_name = NULL; 12731 char *description = NULL; 12732 char *locale = NULL; 12733 scf_iter_t *iter; 12734 scf_propertygroup_t *pg; 12735 scf_property_t *prop; 12736 int r; 12737 scf_value_t *val; 12738 12739 if ((pg = scf_pg_create(g_hndl)) == NULL || 12740 (prop = scf_property_create(g_hndl)) == NULL || 12741 (val = scf_value_create(g_hndl)) == NULL || 12742 (iter = scf_iter_create(g_hndl)) == NULL) 12743 scfdie(); 12744 12745 locale = setlocale(LC_MESSAGES, NULL); 12746 12747 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 12748 common_name = safe_malloc(max_scf_value_len + 1); 12749 12750 /* Try both the current locale and the "C" locale. */ 12751 if (scf_pg_get_property(pg, locale, prop) == 0 || 12752 (scf_error() == SCF_ERROR_NOT_FOUND && 12753 scf_pg_get_property(pg, "C", prop) == 0)) { 12754 if (prop_get_val(prop, val) == 0 && 12755 scf_value_get_ustring(val, common_name, 12756 max_scf_value_len + 1) != -1) { 12757 safe_printf("%s%s: %s\n", TMPL_INDENT, 12758 gettext("common name"), common_name); 12759 } 12760 } 12761 } 12762 12763 /* 12764 * Do description, manpages, and doc links if templates == 2. 12765 */ 12766 if (templates == 2) { 12767 /* Get the description. */ 12768 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 12769 description = safe_malloc(max_scf_value_len + 1); 12770 12771 /* Try both the current locale and the "C" locale. */ 12772 if (scf_pg_get_property(pg, locale, prop) == 0 || 12773 (scf_error() == SCF_ERROR_NOT_FOUND && 12774 scf_pg_get_property(pg, "C", prop) == 0)) { 12775 if (prop_get_val(prop, val) == 0 && 12776 scf_value_get_ustring(val, description, 12777 max_scf_value_len + 1) != -1) { 12778 safe_printf("%s%s: %s\n", TMPL_INDENT, 12779 gettext("description"), 12780 description); 12781 } 12782 } 12783 } 12784 12785 /* Process doc_link & manpage elements. */ 12786 if (cur_level != NULL) { 12787 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 12788 SCF_GROUP_TEMPLATE); 12789 } else if (cur_inst != NULL) { 12790 r = scf_iter_instance_pgs_typed(iter, cur_inst, 12791 SCF_GROUP_TEMPLATE); 12792 } else { 12793 r = scf_iter_service_pgs_typed(iter, cur_svc, 12794 SCF_GROUP_TEMPLATE); 12795 } 12796 if (r == 0) { 12797 display_documentation(iter, pg); 12798 } 12799 } 12800 12801 free(common_name); 12802 free(description); 12803 scf_pg_destroy(pg); 12804 scf_property_destroy(prop); 12805 scf_value_destroy(val); 12806 scf_iter_destroy(iter); 12807 } 12808 12809 static void 12810 listtmpl(const char *pattern, int templates) 12811 { 12812 scf_pg_tmpl_t *pgt; 12813 scf_prop_tmpl_t *prt; 12814 char *snapbuf = NULL; 12815 char *fmribuf; 12816 char *pg_name = NULL, *prop_name = NULL; 12817 ssize_t prop_name_size; 12818 char *qual_prop_name; 12819 char *search_name; 12820 int listed = 0; 12821 12822 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 12823 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 12824 scfdie(); 12825 12826 fmribuf = safe_malloc(max_scf_name_len + 1); 12827 qual_prop_name = safe_malloc(max_scf_name_len + 1); 12828 12829 if (cur_snap != NULL) { 12830 snapbuf = safe_malloc(max_scf_name_len + 1); 12831 if (scf_snapshot_get_name(cur_snap, snapbuf, 12832 max_scf_name_len + 1) < 0) 12833 scfdie(); 12834 } 12835 12836 if (cur_inst != NULL) { 12837 if (scf_instance_to_fmri(cur_inst, fmribuf, 12838 max_scf_name_len + 1) < 0) 12839 scfdie(); 12840 } else if (cur_svc != NULL) { 12841 if (scf_service_to_fmri(cur_svc, fmribuf, 12842 max_scf_name_len + 1) < 0) 12843 scfdie(); 12844 } else 12845 abort(); 12846 12847 /* If pattern is specified, we want to list only those items. */ 12848 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) { 12849 listed = 0; 12850 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 12851 fnmatch(pattern, pg_name, 0) == 0)) { 12852 list_pg_tmpl(pgt, NULL, templates); 12853 listed++; 12854 } 12855 12856 scf_tmpl_prop_reset(prt); 12857 12858 while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) { 12859 search_name = NULL; 12860 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 12861 if ((prop_name_size > 0) && (pg_name != NULL)) { 12862 if (snprintf(qual_prop_name, 12863 max_scf_name_len + 1, "%s/%s", 12864 pg_name, prop_name) >= 12865 max_scf_name_len + 1) { 12866 prop_name_size = -1; 12867 } else { 12868 search_name = qual_prop_name; 12869 } 12870 } 12871 if (listed > 0 || pattern == NULL || 12872 (prop_name_size > 0 && 12873 fnmatch(pattern, search_name, 12874 FNM_PATHNAME) == 0)) 12875 list_prop_tmpl(prt, NULL, templates); 12876 if (prop_name != NULL) { 12877 free(prop_name); 12878 prop_name = NULL; 12879 } 12880 } 12881 if (pg_name != NULL) { 12882 free(pg_name); 12883 pg_name = NULL; 12884 } 12885 } 12886 12887 scf_tmpl_prop_destroy(prt); 12888 scf_tmpl_pg_destroy(pgt); 12889 free(snapbuf); 12890 free(fmribuf); 12891 free(qual_prop_name); 12892 } 12893 12894 static void 12895 listprop(const char *pattern, int only_pgs, int templates) 12896 { 12897 scf_propertygroup_t *pg; 12898 scf_property_t *prop; 12899 scf_iter_t *iter, *piter; 12900 char *pgnbuf, *prnbuf, *ppnbuf; 12901 scf_pg_tmpl_t *pgt, *pgtp; 12902 scf_prop_tmpl_t *prt; 12903 12904 void **objects; 12905 char **names; 12906 void **tmpls; 12907 int allocd, i; 12908 12909 int ret; 12910 ssize_t pgnlen, prnlen, szret; 12911 size_t max_len = 0; 12912 12913 if (cur_svc == NULL && cur_inst == NULL) { 12914 semerr(emsg_entity_not_selected); 12915 return; 12916 } 12917 12918 if ((pg = scf_pg_create(g_hndl)) == NULL || 12919 (prop = scf_property_create(g_hndl)) == NULL || 12920 (iter = scf_iter_create(g_hndl)) == NULL || 12921 (piter = scf_iter_create(g_hndl)) == NULL || 12922 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12923 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 12924 scfdie(); 12925 12926 prnbuf = safe_malloc(max_scf_name_len + 1); 12927 12928 if (cur_level != NULL) 12929 ret = scf_iter_snaplevel_pgs(iter, cur_level); 12930 else if (cur_inst != NULL) 12931 ret = scf_iter_instance_pgs(iter, cur_inst); 12932 else 12933 ret = scf_iter_service_pgs(iter, cur_svc); 12934 if (ret != 0) { 12935 return; 12936 } 12937 12938 /* 12939 * We want to only list items which match pattern, and we want the 12940 * second column to line up, so during the first pass we'll save 12941 * matching items, their names, and their templates in objects, 12942 * names, and tmpls, computing the maximum name length as we go, 12943 * and then we'll print them out. 12944 * 12945 * Note: We always keep an extra slot available so the array can be 12946 * NULL-terminated. 12947 */ 12948 i = 0; 12949 allocd = 1; 12950 objects = safe_malloc(sizeof (*objects)); 12951 names = safe_malloc(sizeof (*names)); 12952 tmpls = safe_malloc(sizeof (*tmpls)); 12953 12954 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12955 int new_pg = 0; 12956 int print_props = 0; 12957 pgtp = NULL; 12958 12959 pgnlen = scf_pg_get_name(pg, NULL, 0); 12960 if (pgnlen < 0) 12961 scfdie(); 12962 12963 pgnbuf = safe_malloc(pgnlen + 1); 12964 12965 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 12966 if (szret < 0) 12967 scfdie(); 12968 assert(szret <= pgnlen); 12969 12970 if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) { 12971 if (scf_error() != SCF_ERROR_NOT_FOUND) 12972 scfdie(); 12973 pgtp = NULL; 12974 } else { 12975 pgtp = pgt; 12976 } 12977 12978 if (pattern == NULL || 12979 fnmatch(pattern, pgnbuf, 0) == 0) { 12980 if (i+1 >= allocd) { 12981 allocd *= 2; 12982 objects = realloc(objects, 12983 sizeof (*objects) * allocd); 12984 names = 12985 realloc(names, sizeof (*names) * allocd); 12986 tmpls = realloc(tmpls, 12987 sizeof (*tmpls) * allocd); 12988 if (objects == NULL || names == NULL || 12989 tmpls == NULL) 12990 uu_die(gettext("Out of memory")); 12991 } 12992 objects[i] = pg; 12993 names[i] = pgnbuf; 12994 12995 if (pgtp == NULL) 12996 tmpls[i] = NULL; 12997 else 12998 tmpls[i] = pgt; 12999 13000 ++i; 13001 13002 if (pgnlen > max_len) 13003 max_len = pgnlen; 13004 13005 new_pg = 1; 13006 print_props = 1; 13007 } 13008 13009 if (only_pgs) { 13010 if (new_pg) { 13011 pg = scf_pg_create(g_hndl); 13012 if (pg == NULL) 13013 scfdie(); 13014 pgt = scf_tmpl_pg_create(g_hndl); 13015 if (pgt == NULL) 13016 scfdie(); 13017 } else 13018 free(pgnbuf); 13019 13020 continue; 13021 } 13022 13023 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13024 scfdie(); 13025 13026 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13027 prnlen = scf_property_get_name(prop, prnbuf, 13028 max_scf_name_len + 1); 13029 if (prnlen < 0) 13030 scfdie(); 13031 13032 /* Will prepend the property group name and a slash. */ 13033 prnlen += pgnlen + 1; 13034 13035 ppnbuf = safe_malloc(prnlen + 1); 13036 13037 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13038 prnbuf) < 0) 13039 uu_die("snprintf"); 13040 13041 if (pattern == NULL || print_props == 1 || 13042 fnmatch(pattern, ppnbuf, 0) == 0) { 13043 if (i+1 >= allocd) { 13044 allocd *= 2; 13045 objects = realloc(objects, 13046 sizeof (*objects) * allocd); 13047 names = realloc(names, 13048 sizeof (*names) * allocd); 13049 tmpls = realloc(tmpls, 13050 sizeof (*tmpls) * allocd); 13051 if (objects == NULL || names == NULL || 13052 tmpls == NULL) 13053 uu_die(gettext( 13054 "Out of memory")); 13055 } 13056 13057 objects[i] = prop; 13058 names[i] = ppnbuf; 13059 13060 if (pgtp != NULL) { 13061 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13062 prt, NULL) < 0) { 13063 if (scf_error() != 13064 SCF_ERROR_NOT_FOUND) 13065 scfdie(); 13066 tmpls[i] = NULL; 13067 } else { 13068 tmpls[i] = prt; 13069 } 13070 } else { 13071 tmpls[i] = NULL; 13072 } 13073 13074 ++i; 13075 13076 if (prnlen > max_len) 13077 max_len = prnlen; 13078 13079 prop = scf_property_create(g_hndl); 13080 prt = scf_tmpl_prop_create(g_hndl); 13081 } else { 13082 free(ppnbuf); 13083 } 13084 } 13085 13086 if (new_pg) { 13087 pg = scf_pg_create(g_hndl); 13088 if (pg == NULL) 13089 scfdie(); 13090 pgt = scf_tmpl_pg_create(g_hndl); 13091 if (pgt == NULL) 13092 scfdie(); 13093 } else 13094 free(pgnbuf); 13095 } 13096 if (ret != 0) 13097 scfdie(); 13098 13099 objects[i] = NULL; 13100 13101 scf_pg_destroy(pg); 13102 scf_tmpl_pg_destroy(pgt); 13103 scf_property_destroy(prop); 13104 scf_tmpl_prop_destroy(prt); 13105 13106 for (i = 0; objects[i] != NULL; ++i) { 13107 if (strchr(names[i], '/') == NULL) { 13108 /* property group */ 13109 pg = (scf_propertygroup_t *)objects[i]; 13110 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13111 list_pg_info(pg, names[i], max_len); 13112 list_pg_tmpl(pgt, pg, templates); 13113 free(names[i]); 13114 scf_pg_destroy(pg); 13115 if (pgt != NULL) 13116 scf_tmpl_pg_destroy(pgt); 13117 } else { 13118 /* property */ 13119 prop = (scf_property_t *)objects[i]; 13120 prt = (scf_prop_tmpl_t *)tmpls[i]; 13121 list_prop_info(prop, names[i], max_len); 13122 list_prop_tmpl(prt, prop, templates); 13123 free(names[i]); 13124 scf_property_destroy(prop); 13125 if (prt != NULL) 13126 scf_tmpl_prop_destroy(prt); 13127 } 13128 } 13129 13130 free(names); 13131 free(objects); 13132 free(tmpls); 13133 } 13134 13135 void 13136 lscf_listpg(const char *pattern) 13137 { 13138 lscf_prep_hndl(); 13139 13140 listprop(pattern, 1, 0); 13141 } 13142 13143 /* 13144 * Property group and property creation, setting, and deletion. setprop (and 13145 * its alias, addprop) can either create a property group of a given type, or 13146 * it can create or set a property to a given type and list of values. 13147 */ 13148 void 13149 lscf_addpg(const char *name, const char *type, const char *flags) 13150 { 13151 scf_propertygroup_t *pg; 13152 int ret; 13153 uint32_t flgs = 0; 13154 const char *cp; 13155 13156 13157 lscf_prep_hndl(); 13158 13159 if (cur_snap != NULL) { 13160 semerr(emsg_cant_modify_snapshots); 13161 return; 13162 } 13163 13164 if (cur_inst == NULL && cur_svc == NULL) { 13165 semerr(emsg_entity_not_selected); 13166 return; 13167 } 13168 13169 if (flags != NULL) { 13170 for (cp = flags; *cp != '\0'; ++cp) { 13171 switch (*cp) { 13172 case 'P': 13173 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13174 break; 13175 13176 case 'p': 13177 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13178 break; 13179 13180 default: 13181 semerr(gettext("Invalid property group flag " 13182 "%c."), *cp); 13183 return; 13184 } 13185 } 13186 } 13187 13188 pg = scf_pg_create(g_hndl); 13189 if (pg == NULL) 13190 scfdie(); 13191 13192 if (cur_inst != NULL) 13193 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13194 else 13195 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13196 13197 if (ret != SCF_SUCCESS) { 13198 switch (scf_error()) { 13199 case SCF_ERROR_INVALID_ARGUMENT: 13200 semerr(gettext("Name, type, or flags are invalid.\n")); 13201 break; 13202 13203 case SCF_ERROR_EXISTS: 13204 semerr(gettext("Property group already exists.\n")); 13205 break; 13206 13207 case SCF_ERROR_PERMISSION_DENIED: 13208 semerr(emsg_permission_denied); 13209 break; 13210 13211 case SCF_ERROR_BACKEND_ACCESS: 13212 semerr(gettext("Backend refused access.\n")); 13213 break; 13214 13215 default: 13216 scfdie(); 13217 } 13218 } 13219 13220 scf_pg_destroy(pg); 13221 13222 private_refresh(); 13223 } 13224 13225 void 13226 lscf_delpg(char *name) 13227 { 13228 lscf_prep_hndl(); 13229 13230 if (cur_snap != NULL) { 13231 semerr(emsg_cant_modify_snapshots); 13232 return; 13233 } 13234 13235 if (cur_inst == NULL && cur_svc == NULL) { 13236 semerr(emsg_entity_not_selected); 13237 return; 13238 } 13239 13240 if (strchr(name, '/') != NULL) { 13241 semerr(emsg_invalid_pg_name, name); 13242 return; 13243 } 13244 13245 lscf_delprop(name); 13246 } 13247 13248 /* 13249 * scf_delhash() is used to remove the property group related to the 13250 * hash entry for a specific manifest in the repository. pgname will be 13251 * constructed from the location of the manifest file. If deathrow isn't 0, 13252 * manifest file doesn't need to exist (manifest string will be used as 13253 * an absolute path). 13254 */ 13255 void 13256 lscf_delhash(char *manifest, int deathrow) 13257 { 13258 char *pgname; 13259 13260 if (cur_snap != NULL || 13261 cur_inst != NULL || cur_svc != NULL) { 13262 warn(gettext("error, an entity is selected\n")); 13263 return; 13264 } 13265 13266 /* select smf/manifest */ 13267 lscf_select(HASH_SVC); 13268 /* 13269 * Translate the manifest file name to property name. In the deathrow 13270 * case, the manifest file does not need to exist. 13271 */ 13272 pgname = mhash_filename_to_propname(manifest, 13273 deathrow ? B_TRUE : B_FALSE); 13274 if (pgname == NULL) { 13275 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13276 return; 13277 } 13278 /* delete the hash property name */ 13279 lscf_delpg(pgname); 13280 } 13281 13282 void 13283 lscf_listprop(const char *pattern) 13284 { 13285 lscf_prep_hndl(); 13286 13287 listprop(pattern, 0, 0); 13288 } 13289 13290 int 13291 lscf_setprop(const char *pgname, const char *type, const char *value, 13292 const uu_list_t *values) 13293 { 13294 scf_type_t ty, current_ty; 13295 scf_service_t *svc; 13296 scf_propertygroup_t *pg, *parent_pg; 13297 scf_property_t *prop, *parent_prop; 13298 scf_pg_tmpl_t *pgt; 13299 scf_prop_tmpl_t *prt; 13300 int ret, result = 0; 13301 scf_transaction_t *tx; 13302 scf_transaction_entry_t *e; 13303 scf_value_t *v; 13304 uu_list_walk_t *walk; 13305 string_list_t *sp; 13306 char *propname; 13307 int req_quotes = 0; 13308 13309 lscf_prep_hndl(); 13310 13311 if ((e = scf_entry_create(g_hndl)) == NULL || 13312 (svc = scf_service_create(g_hndl)) == NULL || 13313 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13314 (pg = scf_pg_create(g_hndl)) == NULL || 13315 (parent_prop = scf_property_create(g_hndl)) == NULL || 13316 (prop = scf_property_create(g_hndl)) == NULL || 13317 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13318 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13319 (tx = scf_transaction_create(g_hndl)) == NULL) 13320 scfdie(); 13321 13322 if (cur_snap != NULL) { 13323 semerr(emsg_cant_modify_snapshots); 13324 goto fail; 13325 } 13326 13327 if (cur_inst == NULL && cur_svc == NULL) { 13328 semerr(emsg_entity_not_selected); 13329 goto fail; 13330 } 13331 13332 propname = strchr(pgname, '/'); 13333 if (propname == NULL) { 13334 semerr(gettext("Property names must contain a `/'.\n")); 13335 goto fail; 13336 } 13337 13338 *propname = '\0'; 13339 ++propname; 13340 13341 if (type != NULL) { 13342 ty = string_to_type(type); 13343 if (ty == SCF_TYPE_INVALID) { 13344 semerr(gettext("Unknown type \"%s\".\n"), type); 13345 goto fail; 13346 } 13347 } 13348 13349 if (cur_inst != NULL) 13350 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13351 else 13352 ret = scf_service_get_pg(cur_svc, pgname, pg); 13353 if (ret != SCF_SUCCESS) { 13354 switch (scf_error()) { 13355 case SCF_ERROR_NOT_FOUND: 13356 semerr(emsg_no_such_pg, pgname); 13357 goto fail; 13358 13359 case SCF_ERROR_INVALID_ARGUMENT: 13360 semerr(emsg_invalid_pg_name, pgname); 13361 goto fail; 13362 13363 default: 13364 scfdie(); 13365 break; 13366 } 13367 } 13368 13369 do { 13370 if (scf_pg_update(pg) == -1) 13371 scfdie(); 13372 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13373 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13374 scfdie(); 13375 13376 semerr(emsg_permission_denied); 13377 goto fail; 13378 } 13379 13380 ret = scf_pg_get_property(pg, propname, prop); 13381 if (ret == SCF_SUCCESS) { 13382 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13383 scfdie(); 13384 13385 if (type == NULL) 13386 ty = current_ty; 13387 if (scf_transaction_property_change_type(tx, e, 13388 propname, ty) == -1) 13389 scfdie(); 13390 13391 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13392 /* Infer the type, if possible. */ 13393 if (type == NULL) { 13394 /* 13395 * First check if we're an instance and the 13396 * property is set on the service. 13397 */ 13398 if (cur_inst != NULL && 13399 scf_instance_get_parent(cur_inst, 13400 svc) == 0 && 13401 scf_service_get_pg(cur_svc, pgname, 13402 parent_pg) == 0 && 13403 scf_pg_get_property(parent_pg, propname, 13404 parent_prop) == 0 && 13405 scf_property_type(parent_prop, 13406 ¤t_ty) == 0) { 13407 ty = current_ty; 13408 13409 /* Then check for a type set in a template. */ 13410 } else if (scf_tmpl_get_by_pg(pg, pgt, 13411 NULL) == 0 && 13412 scf_tmpl_get_by_prop(pgt, propname, prt, 13413 NULL) == 0 && 13414 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13415 ty = current_ty; 13416 13417 /* If type can't be inferred, fail. */ 13418 } else { 13419 semerr(gettext("Type required for new " 13420 "properties.\n")); 13421 goto fail; 13422 } 13423 } 13424 if (scf_transaction_property_new(tx, e, propname, 13425 ty) == -1) 13426 scfdie(); 13427 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13428 semerr(emsg_invalid_prop_name, propname); 13429 goto fail; 13430 } else { 13431 scfdie(); 13432 } 13433 13434 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13435 req_quotes = 1; 13436 13437 if (value != NULL) { 13438 v = string_to_value(value, ty, 0); 13439 13440 if (v == NULL) 13441 goto fail; 13442 13443 ret = scf_entry_add_value(e, v); 13444 assert(ret == SCF_SUCCESS); 13445 } else { 13446 assert(values != NULL); 13447 13448 walk = uu_list_walk_start((uu_list_t *)values, 13449 UU_DEFAULT); 13450 if (walk == NULL) 13451 uu_die(gettext("Could not walk list")); 13452 13453 for (sp = uu_list_walk_next(walk); sp != NULL; 13454 sp = uu_list_walk_next(walk)) { 13455 v = string_to_value(sp->str, ty, req_quotes); 13456 13457 if (v == NULL) { 13458 scf_entry_destroy_children(e); 13459 goto fail; 13460 } 13461 13462 ret = scf_entry_add_value(e, v); 13463 assert(ret == SCF_SUCCESS); 13464 } 13465 uu_list_walk_end(walk); 13466 } 13467 result = scf_transaction_commit(tx); 13468 13469 scf_transaction_reset(tx); 13470 scf_entry_destroy_children(e); 13471 } while (result == 0); 13472 13473 if (result < 0) { 13474 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13475 scfdie(); 13476 13477 semerr(emsg_permission_denied); 13478 goto fail; 13479 } 13480 13481 ret = 0; 13482 13483 private_refresh(); 13484 13485 goto cleanup; 13486 13487 fail: 13488 ret = -1; 13489 13490 cleanup: 13491 scf_transaction_destroy(tx); 13492 scf_entry_destroy(e); 13493 scf_service_destroy(svc); 13494 scf_pg_destroy(parent_pg); 13495 scf_pg_destroy(pg); 13496 scf_property_destroy(parent_prop); 13497 scf_property_destroy(prop); 13498 scf_tmpl_pg_destroy(pgt); 13499 scf_tmpl_prop_destroy(prt); 13500 13501 return (ret); 13502 } 13503 13504 void 13505 lscf_delprop(char *pgn) 13506 { 13507 char *slash, *pn; 13508 scf_propertygroup_t *pg; 13509 scf_transaction_t *tx; 13510 scf_transaction_entry_t *e; 13511 int ret; 13512 13513 13514 lscf_prep_hndl(); 13515 13516 if (cur_snap != NULL) { 13517 semerr(emsg_cant_modify_snapshots); 13518 return; 13519 } 13520 13521 if (cur_inst == NULL && cur_svc == NULL) { 13522 semerr(emsg_entity_not_selected); 13523 return; 13524 } 13525 13526 pg = scf_pg_create(g_hndl); 13527 if (pg == NULL) 13528 scfdie(); 13529 13530 slash = strchr(pgn, '/'); 13531 if (slash == NULL) { 13532 pn = NULL; 13533 } else { 13534 *slash = '\0'; 13535 pn = slash + 1; 13536 } 13537 13538 if (cur_inst != NULL) 13539 ret = scf_instance_get_pg(cur_inst, pgn, pg); 13540 else 13541 ret = scf_service_get_pg(cur_svc, pgn, pg); 13542 if (ret != SCF_SUCCESS) { 13543 switch (scf_error()) { 13544 case SCF_ERROR_NOT_FOUND: 13545 semerr(emsg_no_such_pg, pgn); 13546 break; 13547 13548 case SCF_ERROR_INVALID_ARGUMENT: 13549 semerr(emsg_invalid_pg_name, pgn); 13550 break; 13551 13552 default: 13553 scfdie(); 13554 } 13555 13556 scf_pg_destroy(pg); 13557 13558 return; 13559 } 13560 13561 if (pn == NULL) { 13562 /* Try to delete the property group. */ 13563 if (scf_pg_delete(pg) != SCF_SUCCESS) { 13564 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13565 scfdie(); 13566 13567 semerr(emsg_permission_denied); 13568 } else { 13569 private_refresh(); 13570 } 13571 13572 scf_pg_destroy(pg); 13573 return; 13574 } 13575 13576 e = scf_entry_create(g_hndl); 13577 tx = scf_transaction_create(g_hndl); 13578 13579 do { 13580 if (scf_pg_update(pg) == -1) 13581 scfdie(); 13582 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13583 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13584 scfdie(); 13585 13586 semerr(emsg_permission_denied); 13587 break; 13588 } 13589 13590 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 13591 if (scf_error() == SCF_ERROR_NOT_FOUND) { 13592 semerr(gettext("No such property %s/%s.\n"), 13593 pgn, pn); 13594 break; 13595 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13596 semerr(emsg_invalid_prop_name, pn); 13597 break; 13598 } else { 13599 scfdie(); 13600 } 13601 } 13602 13603 ret = scf_transaction_commit(tx); 13604 13605 if (ret == 0) 13606 scf_transaction_reset(tx); 13607 } while (ret == 0); 13608 13609 if (ret < 0) { 13610 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13611 scfdie(); 13612 13613 semerr(emsg_permission_denied); 13614 } else { 13615 private_refresh(); 13616 } 13617 13618 scf_transaction_destroy(tx); 13619 scf_entry_destroy(e); 13620 scf_pg_destroy(pg); 13621 } 13622 13623 /* 13624 * Property editing. 13625 */ 13626 13627 static int 13628 write_edit_script(FILE *strm) 13629 { 13630 char *fmribuf; 13631 ssize_t fmrilen; 13632 13633 scf_propertygroup_t *pg; 13634 scf_property_t *prop; 13635 scf_value_t *val; 13636 scf_type_t ty; 13637 int ret, result = 0; 13638 scf_iter_t *iter, *piter, *viter; 13639 char *buf, *tybuf, *pname; 13640 const char *emsg_write_error; 13641 13642 13643 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 13644 13645 13646 /* select fmri */ 13647 if (cur_inst != NULL) { 13648 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 13649 if (fmrilen < 0) 13650 scfdie(); 13651 fmribuf = safe_malloc(fmrilen + 1); 13652 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 13653 scfdie(); 13654 } else { 13655 assert(cur_svc != NULL); 13656 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 13657 if (fmrilen < 0) 13658 scfdie(); 13659 fmribuf = safe_malloc(fmrilen + 1); 13660 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 13661 scfdie(); 13662 } 13663 13664 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 13665 warn(emsg_write_error, strerror(errno)); 13666 free(fmribuf); 13667 return (-1); 13668 } 13669 13670 free(fmribuf); 13671 13672 13673 if ((pg = scf_pg_create(g_hndl)) == NULL || 13674 (prop = scf_property_create(g_hndl)) == NULL || 13675 (val = scf_value_create(g_hndl)) == NULL || 13676 (iter = scf_iter_create(g_hndl)) == NULL || 13677 (piter = scf_iter_create(g_hndl)) == NULL || 13678 (viter = scf_iter_create(g_hndl)) == NULL) 13679 scfdie(); 13680 13681 buf = safe_malloc(max_scf_name_len + 1); 13682 tybuf = safe_malloc(max_scf_pg_type_len + 1); 13683 pname = safe_malloc(max_scf_name_len + 1); 13684 13685 if (cur_inst != NULL) 13686 ret = scf_iter_instance_pgs(iter, cur_inst); 13687 else 13688 ret = scf_iter_service_pgs(iter, cur_svc); 13689 if (ret != SCF_SUCCESS) 13690 scfdie(); 13691 13692 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13693 int ret2; 13694 13695 /* 13696 * # delprop pg 13697 * # addpg pg type 13698 */ 13699 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 13700 scfdie(); 13701 13702 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 13703 scfdie(); 13704 13705 if (fprintf(strm, "# Property group \"%s\"\n" 13706 "# delprop %s\n" 13707 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 13708 warn(emsg_write_error, strerror(errno)); 13709 result = -1; 13710 goto out; 13711 } 13712 13713 /* # setprop pg/prop = (values) */ 13714 13715 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13716 scfdie(); 13717 13718 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 13719 int first = 1; 13720 int ret3; 13721 int multiple; 13722 int is_str; 13723 scf_type_t bty; 13724 13725 if (scf_property_get_name(prop, pname, 13726 max_scf_name_len + 1) < 0) 13727 scfdie(); 13728 13729 if (scf_property_type(prop, &ty) != 0) 13730 scfdie(); 13731 13732 multiple = prop_has_multiple_values(prop, val); 13733 13734 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 13735 pname, scf_type_to_string(ty), multiple ? "(" : "") 13736 < 0) { 13737 warn(emsg_write_error, strerror(errno)); 13738 result = -1; 13739 goto out; 13740 } 13741 13742 (void) scf_type_base_type(ty, &bty); 13743 is_str = (bty == SCF_TYPE_ASTRING); 13744 13745 if (scf_iter_property_values(viter, prop) != 13746 SCF_SUCCESS) 13747 scfdie(); 13748 13749 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 13750 char *buf; 13751 ssize_t buflen; 13752 13753 buflen = scf_value_get_as_string(val, NULL, 0); 13754 if (buflen < 0) 13755 scfdie(); 13756 13757 buf = safe_malloc(buflen + 1); 13758 13759 if (scf_value_get_as_string(val, buf, 13760 buflen + 1) < 0) 13761 scfdie(); 13762 13763 if (first) 13764 first = 0; 13765 else { 13766 if (putc(' ', strm) != ' ') { 13767 warn(emsg_write_error, 13768 strerror(errno)); 13769 result = -1; 13770 goto out; 13771 } 13772 } 13773 13774 if ((is_str && multiple) || 13775 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 13776 (void) putc('"', strm); 13777 (void) quote_and_print(buf, strm, 1); 13778 (void) putc('"', strm); 13779 13780 if (ferror(strm)) { 13781 warn(emsg_write_error, 13782 strerror(errno)); 13783 result = -1; 13784 goto out; 13785 } 13786 } else { 13787 if (fprintf(strm, "%s", buf) < 0) { 13788 warn(emsg_write_error, 13789 strerror(errno)); 13790 result = -1; 13791 goto out; 13792 } 13793 } 13794 13795 free(buf); 13796 } 13797 if (ret3 < 0 && 13798 scf_error() != SCF_ERROR_PERMISSION_DENIED) 13799 scfdie(); 13800 13801 /* Write closing paren if mult-value property */ 13802 if ((multiple && putc(')', strm) == EOF) || 13803 13804 /* Write final newline */ 13805 fputc('\n', strm) == EOF) { 13806 warn(emsg_write_error, strerror(errno)); 13807 result = -1; 13808 goto out; 13809 } 13810 } 13811 if (ret2 < 0) 13812 scfdie(); 13813 13814 if (fputc('\n', strm) == EOF) { 13815 warn(emsg_write_error, strerror(errno)); 13816 result = -1; 13817 goto out; 13818 } 13819 } 13820 if (ret < 0) 13821 scfdie(); 13822 13823 out: 13824 free(pname); 13825 free(tybuf); 13826 free(buf); 13827 scf_iter_destroy(viter); 13828 scf_iter_destroy(piter); 13829 scf_iter_destroy(iter); 13830 scf_value_destroy(val); 13831 scf_property_destroy(prop); 13832 scf_pg_destroy(pg); 13833 13834 if (result == 0) { 13835 if (fflush(strm) != 0) { 13836 warn(emsg_write_error, strerror(errno)); 13837 return (-1); 13838 } 13839 } 13840 13841 return (result); 13842 } 13843 13844 int 13845 lscf_editprop() 13846 { 13847 char *buf, *editor; 13848 size_t bufsz; 13849 int tmpfd; 13850 char tempname[] = TEMP_FILE_PATTERN; 13851 13852 lscf_prep_hndl(); 13853 13854 if (cur_snap != NULL) { 13855 semerr(emsg_cant_modify_snapshots); 13856 return (-1); 13857 } 13858 13859 if (cur_svc == NULL && cur_inst == NULL) { 13860 semerr(emsg_entity_not_selected); 13861 return (-1); 13862 } 13863 13864 tmpfd = mkstemp(tempname); 13865 if (tmpfd == -1) { 13866 semerr(gettext("Could not create temporary file.\n")); 13867 return (-1); 13868 } 13869 13870 (void) strcpy(tempfilename, tempname); 13871 13872 tempfile = fdopen(tmpfd, "r+"); 13873 if (tempfile == NULL) { 13874 warn(gettext("Could not create temporary file.\n")); 13875 if (close(tmpfd) == -1) 13876 warn(gettext("Could not close temporary file: %s.\n"), 13877 strerror(errno)); 13878 13879 remove_tempfile(); 13880 13881 return (-1); 13882 } 13883 13884 if (write_edit_script(tempfile) == -1) { 13885 remove_tempfile(); 13886 return (-1); 13887 } 13888 13889 editor = getenv("EDITOR"); 13890 if (editor == NULL) 13891 editor = "vi"; 13892 13893 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 13894 buf = safe_malloc(bufsz); 13895 13896 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 13897 uu_die(gettext("Error creating editor command")); 13898 13899 if (system(buf) == -1) { 13900 semerr(gettext("Could not launch editor %s: %s\n"), editor, 13901 strerror(errno)); 13902 free(buf); 13903 remove_tempfile(); 13904 return (-1); 13905 } 13906 13907 free(buf); 13908 13909 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 13910 13911 remove_tempfile(); 13912 13913 return (0); 13914 } 13915 13916 static void 13917 add_string(uu_list_t *strlist, const char *str) 13918 { 13919 string_list_t *elem; 13920 elem = safe_malloc(sizeof (*elem)); 13921 uu_list_node_init(elem, &elem->node, string_pool); 13922 elem->str = safe_strdup(str); 13923 if (uu_list_append(strlist, elem) != 0) 13924 uu_die(gettext("libuutil error: %s\n"), 13925 uu_strerror(uu_error())); 13926 } 13927 13928 static int 13929 remove_string(uu_list_t *strlist, const char *str) 13930 { 13931 uu_list_walk_t *elems; 13932 string_list_t *sp; 13933 13934 /* 13935 * Find the element that needs to be removed. 13936 */ 13937 elems = uu_list_walk_start(strlist, UU_DEFAULT); 13938 while ((sp = uu_list_walk_next(elems)) != NULL) { 13939 if (strcmp(sp->str, str) == 0) 13940 break; 13941 } 13942 uu_list_walk_end(elems); 13943 13944 /* 13945 * Returning 1 here as the value was not found, this 13946 * might not be an error. Leave it to the caller to 13947 * decide. 13948 */ 13949 if (sp == NULL) { 13950 return (1); 13951 } 13952 13953 uu_list_remove(strlist, sp); 13954 13955 free(sp->str); 13956 free(sp); 13957 13958 return (0); 13959 } 13960 13961 /* 13962 * Get all property values that don't match the given glob pattern, 13963 * if a pattern is specified. 13964 */ 13965 static void 13966 get_prop_values(scf_property_t *prop, uu_list_t *values, 13967 const char *pattern) 13968 { 13969 scf_iter_t *iter; 13970 scf_value_t *val; 13971 int ret; 13972 13973 if ((iter = scf_iter_create(g_hndl)) == NULL || 13974 (val = scf_value_create(g_hndl)) == NULL) 13975 scfdie(); 13976 13977 if (scf_iter_property_values(iter, prop) != 0) 13978 scfdie(); 13979 13980 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13981 char *buf; 13982 ssize_t vlen, szret; 13983 13984 vlen = scf_value_get_as_string(val, NULL, 0); 13985 if (vlen < 0) 13986 scfdie(); 13987 13988 buf = safe_malloc(vlen + 1); 13989 13990 szret = scf_value_get_as_string(val, buf, vlen + 1); 13991 if (szret < 0) 13992 scfdie(); 13993 assert(szret <= vlen); 13994 13995 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 13996 add_string(values, buf); 13997 13998 free(buf); 13999 } 14000 14001 if (ret == -1) 14002 scfdie(); 14003 14004 scf_value_destroy(val); 14005 scf_iter_destroy(iter); 14006 } 14007 14008 static int 14009 lscf_setpropvalue(const char *pgname, const char *type, 14010 const char *arg, int isadd, int isnotfoundok) 14011 { 14012 scf_type_t ty; 14013 scf_propertygroup_t *pg; 14014 scf_property_t *prop; 14015 int ret, result = 0; 14016 scf_transaction_t *tx; 14017 scf_transaction_entry_t *e; 14018 scf_value_t *v; 14019 string_list_t *sp; 14020 char *propname; 14021 uu_list_t *values; 14022 uu_list_walk_t *walk; 14023 void *cookie = NULL; 14024 char *pattern = NULL; 14025 14026 lscf_prep_hndl(); 14027 14028 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14029 uu_die(gettext("Could not create property list: %s\n"), 14030 uu_strerror(uu_error())); 14031 14032 if (!isadd) 14033 pattern = safe_strdup(arg); 14034 14035 if ((e = scf_entry_create(g_hndl)) == NULL || 14036 (pg = scf_pg_create(g_hndl)) == NULL || 14037 (prop = scf_property_create(g_hndl)) == NULL || 14038 (tx = scf_transaction_create(g_hndl)) == NULL) 14039 scfdie(); 14040 14041 if (cur_snap != NULL) { 14042 semerr(emsg_cant_modify_snapshots); 14043 goto fail; 14044 } 14045 14046 if (cur_inst == NULL && cur_svc == NULL) { 14047 semerr(emsg_entity_not_selected); 14048 goto fail; 14049 } 14050 14051 propname = strchr(pgname, '/'); 14052 if (propname == NULL) { 14053 semerr(gettext("Property names must contain a `/'.\n")); 14054 goto fail; 14055 } 14056 14057 *propname = '\0'; 14058 ++propname; 14059 14060 if (type != NULL) { 14061 ty = string_to_type(type); 14062 if (ty == SCF_TYPE_INVALID) { 14063 semerr(gettext("Unknown type \"%s\".\n"), type); 14064 goto fail; 14065 } 14066 } 14067 14068 if (cur_inst != NULL) 14069 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14070 else 14071 ret = scf_service_get_pg(cur_svc, pgname, pg); 14072 if (ret != 0) { 14073 switch (scf_error()) { 14074 case SCF_ERROR_NOT_FOUND: 14075 if (isnotfoundok) { 14076 result = 0; 14077 } else { 14078 semerr(emsg_no_such_pg, pgname); 14079 result = -1; 14080 } 14081 goto out; 14082 14083 case SCF_ERROR_INVALID_ARGUMENT: 14084 semerr(emsg_invalid_pg_name, pgname); 14085 goto fail; 14086 14087 default: 14088 scfdie(); 14089 } 14090 } 14091 14092 do { 14093 if (scf_pg_update(pg) == -1) 14094 scfdie(); 14095 if (scf_transaction_start(tx, pg) != 0) { 14096 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14097 scfdie(); 14098 14099 semerr(emsg_permission_denied); 14100 goto fail; 14101 } 14102 14103 ret = scf_pg_get_property(pg, propname, prop); 14104 if (ret == 0) { 14105 scf_type_t ptype; 14106 char *pat = pattern; 14107 14108 if (scf_property_type(prop, &ptype) != 0) 14109 scfdie(); 14110 14111 if (isadd) { 14112 if (type != NULL && ptype != ty) { 14113 semerr(gettext("Property \"%s\" is not " 14114 "of type \"%s\".\n"), propname, 14115 type); 14116 goto fail; 14117 } 14118 14119 pat = NULL; 14120 } else { 14121 size_t len = strlen(pat); 14122 if (len > 0 && pat[len - 1] == '\"') 14123 pat[len - 1] = '\0'; 14124 if (len > 0 && pat[0] == '\"') 14125 pat++; 14126 } 14127 14128 ty = ptype; 14129 14130 get_prop_values(prop, values, pat); 14131 14132 if (isadd) 14133 add_string(values, arg); 14134 14135 if (scf_transaction_property_change(tx, e, 14136 propname, ty) == -1) 14137 scfdie(); 14138 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14139 if (isadd) { 14140 if (type == NULL) { 14141 semerr(gettext("Type required " 14142 "for new properties.\n")); 14143 goto fail; 14144 } 14145 14146 add_string(values, arg); 14147 14148 if (scf_transaction_property_new(tx, e, 14149 propname, ty) == -1) 14150 scfdie(); 14151 } else if (isnotfoundok) { 14152 result = 0; 14153 goto out; 14154 } else { 14155 semerr(gettext("No such property %s/%s.\n"), 14156 pgname, propname); 14157 result = -1; 14158 goto out; 14159 } 14160 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14161 semerr(emsg_invalid_prop_name, propname); 14162 goto fail; 14163 } else { 14164 scfdie(); 14165 } 14166 14167 walk = uu_list_walk_start(values, UU_DEFAULT); 14168 if (walk == NULL) 14169 uu_die(gettext("Could not walk property list.\n")); 14170 14171 for (sp = uu_list_walk_next(walk); sp != NULL; 14172 sp = uu_list_walk_next(walk)) { 14173 v = string_to_value(sp->str, ty, 0); 14174 14175 if (v == NULL) { 14176 scf_entry_destroy_children(e); 14177 goto fail; 14178 } 14179 ret = scf_entry_add_value(e, v); 14180 assert(ret == 0); 14181 } 14182 uu_list_walk_end(walk); 14183 14184 result = scf_transaction_commit(tx); 14185 14186 scf_transaction_reset(tx); 14187 scf_entry_destroy_children(e); 14188 } while (result == 0); 14189 14190 if (result < 0) { 14191 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14192 scfdie(); 14193 14194 semerr(emsg_permission_denied); 14195 goto fail; 14196 } 14197 14198 result = 0; 14199 14200 private_refresh(); 14201 14202 out: 14203 scf_transaction_destroy(tx); 14204 scf_entry_destroy(e); 14205 scf_pg_destroy(pg); 14206 scf_property_destroy(prop); 14207 free(pattern); 14208 14209 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14210 free(sp->str); 14211 free(sp); 14212 } 14213 14214 uu_list_destroy(values); 14215 14216 return (result); 14217 14218 fail: 14219 result = -1; 14220 goto out; 14221 } 14222 14223 int 14224 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14225 { 14226 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14227 } 14228 14229 int 14230 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14231 { 14232 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14233 } 14234 14235 /* 14236 * Look for a standard start method, first in the instance (if any), 14237 * then the service. 14238 */ 14239 static const char * 14240 start_method_name(int *in_instance) 14241 { 14242 scf_propertygroup_t *pg; 14243 char **p; 14244 int ret; 14245 scf_instance_t *inst = cur_inst; 14246 14247 if ((pg = scf_pg_create(g_hndl)) == NULL) 14248 scfdie(); 14249 14250 again: 14251 for (p = start_method_names; *p != NULL; p++) { 14252 if (inst != NULL) 14253 ret = scf_instance_get_pg(inst, *p, pg); 14254 else 14255 ret = scf_service_get_pg(cur_svc, *p, pg); 14256 14257 if (ret == 0) { 14258 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14259 char *buf = safe_malloc(bufsz); 14260 14261 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14262 free(buf); 14263 continue; 14264 } 14265 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14266 free(buf); 14267 continue; 14268 } 14269 14270 free(buf); 14271 *in_instance = (inst != NULL); 14272 scf_pg_destroy(pg); 14273 return (*p); 14274 } 14275 14276 if (scf_error() == SCF_ERROR_NOT_FOUND) 14277 continue; 14278 14279 scfdie(); 14280 } 14281 14282 if (inst != NULL) { 14283 inst = NULL; 14284 goto again; 14285 } 14286 14287 scf_pg_destroy(pg); 14288 return (NULL); 14289 } 14290 14291 static int 14292 addpg(const char *name, const char *type) 14293 { 14294 scf_propertygroup_t *pg; 14295 int ret; 14296 14297 pg = scf_pg_create(g_hndl); 14298 if (pg == NULL) 14299 scfdie(); 14300 14301 if (cur_inst != NULL) 14302 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14303 else 14304 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14305 14306 if (ret != 0) { 14307 switch (scf_error()) { 14308 case SCF_ERROR_EXISTS: 14309 ret = 0; 14310 break; 14311 14312 case SCF_ERROR_PERMISSION_DENIED: 14313 semerr(emsg_permission_denied); 14314 break; 14315 14316 default: 14317 scfdie(); 14318 } 14319 } 14320 14321 scf_pg_destroy(pg); 14322 return (ret); 14323 } 14324 14325 int 14326 lscf_setenv(uu_list_t *args, int isunset) 14327 { 14328 int ret = 0; 14329 size_t i; 14330 int argc; 14331 char **argv = NULL; 14332 string_list_t *slp; 14333 char *pattern; 14334 char *prop; 14335 int do_service = 0; 14336 int do_instance = 0; 14337 const char *method = NULL; 14338 const char *name = NULL; 14339 const char *value = NULL; 14340 scf_instance_t *saved_cur_inst = cur_inst; 14341 14342 lscf_prep_hndl(); 14343 14344 argc = uu_list_numnodes(args); 14345 if (argc < 1) 14346 goto usage; 14347 14348 argv = calloc(argc + 1, sizeof (char *)); 14349 if (argv == NULL) 14350 uu_die(gettext("Out of memory.\n")); 14351 14352 for (slp = uu_list_first(args), i = 0; 14353 slp != NULL; 14354 slp = uu_list_next(args, slp), ++i) 14355 argv[i] = slp->str; 14356 14357 argv[i] = NULL; 14358 14359 opterr = 0; 14360 optind = 0; 14361 for (;;) { 14362 ret = getopt(argc, argv, "sim:"); 14363 if (ret == -1) 14364 break; 14365 14366 switch (ret) { 14367 case 's': 14368 do_service = 1; 14369 cur_inst = NULL; 14370 break; 14371 14372 case 'i': 14373 do_instance = 1; 14374 break; 14375 14376 case 'm': 14377 method = optarg; 14378 break; 14379 14380 case '?': 14381 goto usage; 14382 14383 default: 14384 bad_error("getopt", ret); 14385 } 14386 } 14387 14388 argc -= optind; 14389 if ((do_service && do_instance) || 14390 (isunset && argc != 1) || 14391 (!isunset && argc != 2)) 14392 goto usage; 14393 14394 name = argv[optind]; 14395 if (!isunset) 14396 value = argv[optind + 1]; 14397 14398 if (cur_snap != NULL) { 14399 semerr(emsg_cant_modify_snapshots); 14400 ret = -1; 14401 goto out; 14402 } 14403 14404 if (cur_inst == NULL && cur_svc == NULL) { 14405 semerr(emsg_entity_not_selected); 14406 ret = -1; 14407 goto out; 14408 } 14409 14410 if (do_instance && cur_inst == NULL) { 14411 semerr(gettext("No instance is selected.\n")); 14412 ret = -1; 14413 goto out; 14414 } 14415 14416 if (do_service && cur_svc == NULL) { 14417 semerr(gettext("No service is selected.\n")); 14418 ret = -1; 14419 goto out; 14420 } 14421 14422 if (method == NULL) { 14423 if (do_instance || do_service) { 14424 method = "method_context"; 14425 if (!isunset) { 14426 ret = addpg("method_context", 14427 SCF_GROUP_FRAMEWORK); 14428 if (ret != 0) 14429 goto out; 14430 } 14431 } else { 14432 int in_instance; 14433 method = start_method_name(&in_instance); 14434 if (method == NULL) { 14435 semerr(gettext( 14436 "Couldn't find start method; please " 14437 "specify a method with '-m'.\n")); 14438 ret = -1; 14439 goto out; 14440 } 14441 if (!in_instance) 14442 cur_inst = NULL; 14443 } 14444 } else { 14445 scf_propertygroup_t *pg; 14446 size_t bufsz; 14447 char *buf; 14448 int ret; 14449 14450 if ((pg = scf_pg_create(g_hndl)) == NULL) 14451 scfdie(); 14452 14453 if (cur_inst != NULL) 14454 ret = scf_instance_get_pg(cur_inst, method, pg); 14455 else 14456 ret = scf_service_get_pg(cur_svc, method, pg); 14457 14458 if (ret != 0) { 14459 scf_pg_destroy(pg); 14460 switch (scf_error()) { 14461 case SCF_ERROR_NOT_FOUND: 14462 semerr(gettext("Couldn't find the method " 14463 "\"%s\".\n"), method); 14464 goto out; 14465 14466 case SCF_ERROR_INVALID_ARGUMENT: 14467 semerr(gettext("Invalid method name \"%s\".\n"), 14468 method); 14469 goto out; 14470 14471 default: 14472 scfdie(); 14473 } 14474 } 14475 14476 bufsz = strlen(SCF_GROUP_METHOD) + 1; 14477 buf = safe_malloc(bufsz); 14478 14479 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 14480 strcmp(buf, SCF_GROUP_METHOD) != 0) { 14481 semerr(gettext("Property group \"%s\" is not of type " 14482 "\"method\".\n"), method); 14483 ret = -1; 14484 free(buf); 14485 scf_pg_destroy(pg); 14486 goto out; 14487 } 14488 14489 free(buf); 14490 scf_pg_destroy(pg); 14491 } 14492 14493 prop = uu_msprintf("%s/environment", method); 14494 pattern = uu_msprintf("%s=*", name); 14495 14496 if (prop == NULL || pattern == NULL) 14497 uu_die(gettext("Out of memory.\n")); 14498 14499 ret = lscf_delpropvalue(prop, pattern, !isunset); 14500 14501 if (ret == 0 && !isunset) { 14502 uu_free(pattern); 14503 uu_free(prop); 14504 prop = uu_msprintf("%s/environment", method); 14505 pattern = uu_msprintf("%s=%s", name, value); 14506 if (prop == NULL || pattern == NULL) 14507 uu_die(gettext("Out of memory.\n")); 14508 ret = lscf_addpropvalue(prop, "astring:", pattern); 14509 } 14510 uu_free(pattern); 14511 uu_free(prop); 14512 14513 out: 14514 cur_inst = saved_cur_inst; 14515 14516 free(argv); 14517 return (ret); 14518 usage: 14519 ret = -2; 14520 goto out; 14521 } 14522 14523 /* 14524 * Snapshot commands 14525 */ 14526 14527 void 14528 lscf_listsnap() 14529 { 14530 scf_snapshot_t *snap; 14531 scf_iter_t *iter; 14532 char *nb; 14533 int r; 14534 14535 lscf_prep_hndl(); 14536 14537 if (cur_inst == NULL) { 14538 semerr(gettext("Instance not selected.\n")); 14539 return; 14540 } 14541 14542 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 14543 (iter = scf_iter_create(g_hndl)) == NULL) 14544 scfdie(); 14545 14546 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 14547 scfdie(); 14548 14549 nb = safe_malloc(max_scf_name_len + 1); 14550 14551 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 14552 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 14553 scfdie(); 14554 14555 (void) puts(nb); 14556 } 14557 if (r < 0) 14558 scfdie(); 14559 14560 free(nb); 14561 scf_iter_destroy(iter); 14562 scf_snapshot_destroy(snap); 14563 } 14564 14565 void 14566 lscf_selectsnap(const char *name) 14567 { 14568 scf_snapshot_t *snap; 14569 scf_snaplevel_t *level; 14570 14571 lscf_prep_hndl(); 14572 14573 if (cur_inst == NULL) { 14574 semerr(gettext("Instance not selected.\n")); 14575 return; 14576 } 14577 14578 if (cur_snap != NULL) { 14579 if (name != NULL) { 14580 char *cur_snap_name; 14581 boolean_t nochange; 14582 14583 cur_snap_name = safe_malloc(max_scf_name_len + 1); 14584 14585 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 14586 max_scf_name_len + 1) < 0) 14587 scfdie(); 14588 14589 nochange = strcmp(name, cur_snap_name) == 0; 14590 14591 free(cur_snap_name); 14592 14593 if (nochange) 14594 return; 14595 } 14596 14597 unselect_cursnap(); 14598 } 14599 14600 if (name == NULL) 14601 return; 14602 14603 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 14604 (level = scf_snaplevel_create(g_hndl)) == NULL) 14605 scfdie(); 14606 14607 if (scf_instance_get_snapshot(cur_inst, name, snap) != 14608 SCF_SUCCESS) { 14609 switch (scf_error()) { 14610 case SCF_ERROR_INVALID_ARGUMENT: 14611 semerr(gettext("Invalid name \"%s\".\n"), name); 14612 break; 14613 14614 case SCF_ERROR_NOT_FOUND: 14615 semerr(gettext("No such snapshot \"%s\".\n"), name); 14616 break; 14617 14618 default: 14619 scfdie(); 14620 } 14621 14622 scf_snaplevel_destroy(level); 14623 scf_snapshot_destroy(snap); 14624 return; 14625 } 14626 14627 /* Load the snaplevels into our list. */ 14628 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 14629 if (cur_levels == NULL) 14630 uu_die(gettext("Could not create list: %s\n"), 14631 uu_strerror(uu_error())); 14632 14633 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 14634 if (scf_error() != SCF_ERROR_NOT_FOUND) 14635 scfdie(); 14636 14637 semerr(gettext("Snapshot has no snaplevels.\n")); 14638 14639 scf_snaplevel_destroy(level); 14640 scf_snapshot_destroy(snap); 14641 return; 14642 } 14643 14644 cur_snap = snap; 14645 14646 for (;;) { 14647 cur_elt = safe_malloc(sizeof (*cur_elt)); 14648 uu_list_node_init(cur_elt, &cur_elt->list_node, 14649 snaplevel_pool); 14650 cur_elt->sl = level; 14651 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 14652 uu_die(gettext("libuutil error: %s\n"), 14653 uu_strerror(uu_error())); 14654 14655 level = scf_snaplevel_create(g_hndl); 14656 if (level == NULL) 14657 scfdie(); 14658 14659 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 14660 level) != SCF_SUCCESS) { 14661 if (scf_error() != SCF_ERROR_NOT_FOUND) 14662 scfdie(); 14663 14664 scf_snaplevel_destroy(level); 14665 break; 14666 } 14667 } 14668 14669 cur_elt = uu_list_last(cur_levels); 14670 cur_level = cur_elt->sl; 14671 } 14672 14673 /* 14674 * Copies the properties & values in src to dst. Assumes src won't change. 14675 * Returns -1 if permission is denied, -2 if another transaction interrupts, 14676 * and 0 on success. 14677 * 14678 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 14679 * property, if it is copied and has type boolean. (See comment in 14680 * lscf_revert()). 14681 */ 14682 static int 14683 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 14684 uint8_t enabled) 14685 { 14686 scf_transaction_t *tx; 14687 scf_iter_t *iter, *viter; 14688 scf_property_t *prop; 14689 scf_value_t *v; 14690 char *nbuf; 14691 int r; 14692 14693 tx = scf_transaction_create(g_hndl); 14694 if (tx == NULL) 14695 scfdie(); 14696 14697 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 14698 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14699 scfdie(); 14700 14701 scf_transaction_destroy(tx); 14702 14703 return (-1); 14704 } 14705 14706 if ((iter = scf_iter_create(g_hndl)) == NULL || 14707 (prop = scf_property_create(g_hndl)) == NULL || 14708 (viter = scf_iter_create(g_hndl)) == NULL) 14709 scfdie(); 14710 14711 nbuf = safe_malloc(max_scf_name_len + 1); 14712 14713 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 14714 scfdie(); 14715 14716 for (;;) { 14717 scf_transaction_entry_t *e; 14718 scf_type_t ty; 14719 14720 r = scf_iter_next_property(iter, prop); 14721 if (r == -1) 14722 scfdie(); 14723 if (r == 0) 14724 break; 14725 14726 e = scf_entry_create(g_hndl); 14727 if (e == NULL) 14728 scfdie(); 14729 14730 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 14731 scfdie(); 14732 14733 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 14734 scfdie(); 14735 14736 if (scf_transaction_property_new(tx, e, nbuf, 14737 ty) != SCF_SUCCESS) 14738 scfdie(); 14739 14740 if ((enabled == 0 || enabled == 1) && 14741 strcmp(nbuf, scf_property_enabled) == 0 && 14742 ty == SCF_TYPE_BOOLEAN) { 14743 v = scf_value_create(g_hndl); 14744 if (v == NULL) 14745 scfdie(); 14746 14747 scf_value_set_boolean(v, enabled); 14748 14749 if (scf_entry_add_value(e, v) != 0) 14750 scfdie(); 14751 } else { 14752 if (scf_iter_property_values(viter, prop) != 0) 14753 scfdie(); 14754 14755 for (;;) { 14756 v = scf_value_create(g_hndl); 14757 if (v == NULL) 14758 scfdie(); 14759 14760 r = scf_iter_next_value(viter, v); 14761 if (r == -1) 14762 scfdie(); 14763 if (r == 0) { 14764 scf_value_destroy(v); 14765 break; 14766 } 14767 14768 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 14769 scfdie(); 14770 } 14771 } 14772 } 14773 14774 free(nbuf); 14775 scf_iter_destroy(viter); 14776 scf_property_destroy(prop); 14777 scf_iter_destroy(iter); 14778 14779 r = scf_transaction_commit(tx); 14780 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 14781 scfdie(); 14782 14783 scf_transaction_destroy_children(tx); 14784 scf_transaction_destroy(tx); 14785 14786 switch (r) { 14787 case 1: return (0); 14788 case 0: return (-2); 14789 case -1: return (-1); 14790 14791 default: 14792 abort(); 14793 } 14794 14795 /* NOTREACHED */ 14796 } 14797 14798 void 14799 lscf_revert(const char *snapname) 14800 { 14801 scf_snapshot_t *snap, *prev; 14802 scf_snaplevel_t *level, *nlevel; 14803 scf_iter_t *iter; 14804 scf_propertygroup_t *pg, *npg; 14805 scf_property_t *prop; 14806 scf_value_t *val; 14807 char *nbuf, *tbuf; 14808 uint8_t enabled; 14809 14810 lscf_prep_hndl(); 14811 14812 if (cur_inst == NULL) { 14813 semerr(gettext("Instance not selected.\n")); 14814 return; 14815 } 14816 14817 if (snapname != NULL) { 14818 snap = scf_snapshot_create(g_hndl); 14819 if (snap == NULL) 14820 scfdie(); 14821 14822 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 14823 SCF_SUCCESS) { 14824 switch (scf_error()) { 14825 case SCF_ERROR_INVALID_ARGUMENT: 14826 semerr(gettext("Invalid snapshot name " 14827 "\"%s\".\n"), snapname); 14828 break; 14829 14830 case SCF_ERROR_NOT_FOUND: 14831 semerr(gettext("No such snapshot.\n")); 14832 break; 14833 14834 default: 14835 scfdie(); 14836 } 14837 14838 scf_snapshot_destroy(snap); 14839 return; 14840 } 14841 } else { 14842 if (cur_snap != NULL) { 14843 snap = cur_snap; 14844 } else { 14845 semerr(gettext("No snapshot selected.\n")); 14846 return; 14847 } 14848 } 14849 14850 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 14851 (level = scf_snaplevel_create(g_hndl)) == NULL || 14852 (iter = scf_iter_create(g_hndl)) == NULL || 14853 (pg = scf_pg_create(g_hndl)) == NULL || 14854 (npg = scf_pg_create(g_hndl)) == NULL || 14855 (prop = scf_property_create(g_hndl)) == NULL || 14856 (val = scf_value_create(g_hndl)) == NULL) 14857 scfdie(); 14858 14859 nbuf = safe_malloc(max_scf_name_len + 1); 14860 tbuf = safe_malloc(max_scf_pg_type_len + 1); 14861 14862 /* Take the "previous" snapshot before we blow away the properties. */ 14863 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 14864 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 14865 scfdie(); 14866 } else { 14867 if (scf_error() != SCF_ERROR_NOT_FOUND) 14868 scfdie(); 14869 14870 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 14871 scfdie(); 14872 } 14873 14874 /* Save general/enabled, since we're probably going to replace it. */ 14875 enabled = 2; 14876 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 14877 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 14878 scf_property_get_value(prop, val) == 0) 14879 (void) scf_value_get_boolean(val, &enabled); 14880 14881 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 14882 if (scf_error() != SCF_ERROR_NOT_FOUND) 14883 scfdie(); 14884 14885 goto out; 14886 } 14887 14888 for (;;) { 14889 boolean_t isinst; 14890 uint32_t flags; 14891 int r; 14892 14893 /* Clear the properties from the corresponding entity. */ 14894 isinst = snaplevel_is_instance(level); 14895 14896 if (!isinst) 14897 r = scf_iter_service_pgs(iter, cur_svc); 14898 else 14899 r = scf_iter_instance_pgs(iter, cur_inst); 14900 if (r != SCF_SUCCESS) 14901 scfdie(); 14902 14903 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 14904 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 14905 scfdie(); 14906 14907 /* Skip nonpersistent pgs. */ 14908 if (flags & SCF_PG_FLAG_NONPERSISTENT) 14909 continue; 14910 14911 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14912 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14913 scfdie(); 14914 14915 semerr(emsg_permission_denied); 14916 goto out; 14917 } 14918 } 14919 if (r == -1) 14920 scfdie(); 14921 14922 /* Copy the properties to the corresponding entity. */ 14923 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 14924 scfdie(); 14925 14926 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 14927 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 14928 scfdie(); 14929 14930 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 14931 0) 14932 scfdie(); 14933 14934 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 14935 scfdie(); 14936 14937 if (!isinst) 14938 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 14939 flags, npg); 14940 else 14941 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 14942 flags, npg); 14943 if (r != SCF_SUCCESS) { 14944 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14945 scfdie(); 14946 14947 semerr(emsg_permission_denied); 14948 goto out; 14949 } 14950 14951 if ((enabled == 0 || enabled == 1) && 14952 strcmp(nbuf, scf_pg_general) == 0) 14953 r = pg_copy(pg, npg, enabled); 14954 else 14955 r = pg_copy(pg, npg, 2); 14956 14957 switch (r) { 14958 case 0: 14959 break; 14960 14961 case -1: 14962 semerr(emsg_permission_denied); 14963 goto out; 14964 14965 case -2: 14966 semerr(gettext( 14967 "Interrupted by another change.\n")); 14968 goto out; 14969 14970 default: 14971 abort(); 14972 } 14973 } 14974 if (r == -1) 14975 scfdie(); 14976 14977 /* Get next level. */ 14978 nlevel = scf_snaplevel_create(g_hndl); 14979 if (nlevel == NULL) 14980 scfdie(); 14981 14982 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 14983 SCF_SUCCESS) { 14984 if (scf_error() != SCF_ERROR_NOT_FOUND) 14985 scfdie(); 14986 14987 scf_snaplevel_destroy(nlevel); 14988 break; 14989 } 14990 14991 scf_snaplevel_destroy(level); 14992 level = nlevel; 14993 } 14994 14995 if (snapname == NULL) { 14996 lscf_selectsnap(NULL); 14997 snap = NULL; /* cur_snap has been destroyed */ 14998 } 14999 15000 out: 15001 free(tbuf); 15002 free(nbuf); 15003 scf_value_destroy(val); 15004 scf_property_destroy(prop); 15005 scf_pg_destroy(npg); 15006 scf_pg_destroy(pg); 15007 scf_iter_destroy(iter); 15008 scf_snaplevel_destroy(level); 15009 scf_snapshot_destroy(prev); 15010 if (snap != cur_snap) 15011 scf_snapshot_destroy(snap); 15012 } 15013 15014 void 15015 lscf_refresh(void) 15016 { 15017 ssize_t fmrilen; 15018 size_t bufsz; 15019 char *fmribuf; 15020 int r; 15021 15022 lscf_prep_hndl(); 15023 15024 if (cur_inst == NULL) { 15025 semerr(gettext("Instance not selected.\n")); 15026 return; 15027 } 15028 15029 bufsz = max_scf_fmri_len + 1; 15030 fmribuf = safe_malloc(bufsz); 15031 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15032 if (fmrilen < 0) { 15033 free(fmribuf); 15034 if (scf_error() != SCF_ERROR_DELETED) 15035 scfdie(); 15036 scf_instance_destroy(cur_inst); 15037 cur_inst = NULL; 15038 warn(emsg_deleted); 15039 return; 15040 } 15041 assert(fmrilen < bufsz); 15042 15043 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15044 switch (r) { 15045 case 0: 15046 break; 15047 15048 case ECONNABORTED: 15049 warn(gettext("Could not refresh %s " 15050 "(repository connection broken).\n"), fmribuf); 15051 break; 15052 15053 case ECANCELED: 15054 warn(emsg_deleted); 15055 break; 15056 15057 case EPERM: 15058 warn(gettext("Could not refresh %s " 15059 "(permission denied).\n"), fmribuf); 15060 break; 15061 15062 case ENOSPC: 15063 warn(gettext("Could not refresh %s " 15064 "(repository server out of resources).\n"), 15065 fmribuf); 15066 break; 15067 15068 case EACCES: 15069 default: 15070 bad_error("refresh_entity", scf_error()); 15071 } 15072 15073 free(fmribuf); 15074 } 15075 15076 /* 15077 * describe [-v] [-t] [pg/prop] 15078 */ 15079 int 15080 lscf_describe(uu_list_t *args, int hasargs) 15081 { 15082 int ret = 0; 15083 size_t i; 15084 int argc; 15085 char **argv = NULL; 15086 string_list_t *slp; 15087 int do_verbose = 0; 15088 int do_templates = 0; 15089 char *pattern = NULL; 15090 15091 lscf_prep_hndl(); 15092 15093 if (hasargs != 0) { 15094 argc = uu_list_numnodes(args); 15095 if (argc < 1) 15096 goto usage; 15097 15098 argv = calloc(argc + 1, sizeof (char *)); 15099 if (argv == NULL) 15100 uu_die(gettext("Out of memory.\n")); 15101 15102 for (slp = uu_list_first(args), i = 0; 15103 slp != NULL; 15104 slp = uu_list_next(args, slp), ++i) 15105 argv[i] = slp->str; 15106 15107 argv[i] = NULL; 15108 15109 /* 15110 * We start optind = 0 because our list of arguments 15111 * starts at argv[0] 15112 */ 15113 optind = 0; 15114 opterr = 0; 15115 for (;;) { 15116 ret = getopt(argc, argv, "vt"); 15117 if (ret == -1) 15118 break; 15119 15120 switch (ret) { 15121 case 'v': 15122 do_verbose = 1; 15123 break; 15124 15125 case 't': 15126 do_templates = 1; 15127 break; 15128 15129 case '?': 15130 goto usage; 15131 15132 default: 15133 bad_error("getopt", ret); 15134 } 15135 } 15136 15137 pattern = argv[optind]; 15138 } 15139 15140 if (cur_inst == NULL && cur_svc == NULL) { 15141 semerr(emsg_entity_not_selected); 15142 ret = -1; 15143 goto out; 15144 } 15145 15146 /* 15147 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15148 * output if their last parameter is set to 2. Less information is 15149 * produced if the parameter is set to 1. 15150 */ 15151 if (pattern == NULL) { 15152 if (do_verbose == 1) 15153 list_entity_tmpl(2); 15154 else 15155 list_entity_tmpl(1); 15156 } 15157 15158 if (do_templates == 0) { 15159 if (do_verbose == 1) 15160 listprop(pattern, 0, 2); 15161 else 15162 listprop(pattern, 0, 1); 15163 } else { 15164 if (do_verbose == 1) 15165 listtmpl(pattern, 2); 15166 else 15167 listtmpl(pattern, 1); 15168 } 15169 15170 ret = 0; 15171 out: 15172 if (argv != NULL) 15173 free(argv); 15174 return (ret); 15175 usage: 15176 ret = -2; 15177 goto out; 15178 } 15179 15180 /* 15181 * Creates a list of instance name strings associated with a service. If 15182 * wohandcrafted flag is set, get only instances that have a last-import 15183 * snapshot, instances that were imported via svccfg. 15184 */ 15185 static uu_list_t * 15186 create_instance_list(scf_service_t *svc, int wohandcrafted) 15187 { 15188 scf_snapshot_t *snap = NULL; 15189 scf_instance_t *inst; 15190 scf_iter_t *inst_iter; 15191 uu_list_t *instances; 15192 char *instname; 15193 int r; 15194 15195 inst_iter = scf_iter_create(g_hndl); 15196 inst = scf_instance_create(g_hndl); 15197 if (inst_iter == NULL || inst == NULL) { 15198 uu_warn(gettext("Could not create instance or iterator\n")); 15199 scfdie(); 15200 } 15201 15202 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 15203 return (instances); 15204 15205 if (scf_iter_service_instances(inst_iter, svc) != 0) { 15206 switch (scf_error()) { 15207 case SCF_ERROR_CONNECTION_BROKEN: 15208 case SCF_ERROR_DELETED: 15209 uu_list_destroy(instances); 15210 instances = NULL; 15211 goto out; 15212 15213 case SCF_ERROR_HANDLE_MISMATCH: 15214 case SCF_ERROR_NOT_BOUND: 15215 case SCF_ERROR_NOT_SET: 15216 default: 15217 bad_error("scf_iter_service_instances", scf_error()); 15218 } 15219 } 15220 15221 instname = safe_malloc(max_scf_name_len + 1); 15222 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 15223 if (r == -1) { 15224 (void) uu_warn(gettext("Unable to iterate through " 15225 "instances to create instance list : %s\n"), 15226 scf_strerror(scf_error())); 15227 15228 uu_list_destroy(instances); 15229 instances = NULL; 15230 goto out; 15231 } 15232 15233 /* 15234 * If the instance does not have a last-import snapshot 15235 * then do not add it to the list as it is a hand-crafted 15236 * instance that should not be managed. 15237 */ 15238 if (wohandcrafted) { 15239 if (snap == NULL && 15240 (snap = scf_snapshot_create(g_hndl)) == NULL) { 15241 uu_warn(gettext("Unable to create snapshot " 15242 "entity\n")); 15243 scfdie(); 15244 } 15245 15246 if (scf_instance_get_snapshot(inst, 15247 snap_lastimport, snap) != 0) { 15248 switch (scf_error()) { 15249 case SCF_ERROR_NOT_FOUND : 15250 case SCF_ERROR_DELETED: 15251 continue; 15252 15253 case SCF_ERROR_CONNECTION_BROKEN: 15254 uu_list_destroy(instances); 15255 instances = NULL; 15256 goto out; 15257 15258 case SCF_ERROR_HANDLE_MISMATCH: 15259 case SCF_ERROR_NOT_BOUND: 15260 case SCF_ERROR_NOT_SET: 15261 default: 15262 bad_error("scf_iter_service_instances", 15263 scf_error()); 15264 } 15265 } 15266 } 15267 15268 if (scf_instance_get_name(inst, instname, 15269 max_scf_name_len + 1) < 0) { 15270 switch (scf_error()) { 15271 case SCF_ERROR_NOT_FOUND : 15272 continue; 15273 15274 case SCF_ERROR_CONNECTION_BROKEN: 15275 case SCF_ERROR_DELETED: 15276 uu_list_destroy(instances); 15277 instances = NULL; 15278 goto out; 15279 15280 case SCF_ERROR_HANDLE_MISMATCH: 15281 case SCF_ERROR_NOT_BOUND: 15282 case SCF_ERROR_NOT_SET: 15283 default: 15284 bad_error("scf_iter_service_instances", 15285 scf_error()); 15286 } 15287 } 15288 15289 add_string(instances, instname); 15290 } 15291 15292 out: 15293 if (snap) 15294 scf_snapshot_destroy(snap); 15295 15296 scf_instance_destroy(inst); 15297 scf_iter_destroy(inst_iter); 15298 free(instname); 15299 return (instances); 15300 } 15301 15302 /* 15303 * disable an instance but wait for the instance to 15304 * move out of the running state. 15305 * 15306 * Returns 0 : if the instance did not disable 15307 * Returns non-zero : if the instance disabled. 15308 * 15309 */ 15310 static int 15311 disable_instance(scf_instance_t *instance) 15312 { 15313 char *fmribuf; 15314 int enabled = 10000; 15315 15316 if (inst_is_running(instance)) { 15317 fmribuf = safe_malloc(max_scf_name_len + 1); 15318 if (scf_instance_to_fmri(instance, fmribuf, 15319 max_scf_name_len + 1) < 0) { 15320 free(fmribuf); 15321 return (0); 15322 } 15323 15324 /* 15325 * If the instance cannot be disabled then return 15326 * failure to disable and let the caller decide 15327 * if that is of importance. 15328 */ 15329 if (smf_disable_instance(fmribuf, 0) != 0) { 15330 free(fmribuf); 15331 return (0); 15332 } 15333 15334 while (enabled) { 15335 if (!inst_is_running(instance)) 15336 break; 15337 15338 (void) poll(NULL, 0, 5); 15339 enabled = enabled - 5; 15340 } 15341 15342 free(fmribuf); 15343 } 15344 15345 return (enabled); 15346 } 15347 15348 /* 15349 * Function to compare two service_manifest structures. 15350 */ 15351 /* ARGSUSED2 */ 15352 static int 15353 service_manifest_compare(const void *left, const void *right, void *unused) 15354 { 15355 service_manifest_t *l = (service_manifest_t *)left; 15356 service_manifest_t *r = (service_manifest_t *)right; 15357 int rc; 15358 15359 rc = strcmp(l->servicename, r->servicename); 15360 15361 return (rc); 15362 } 15363 15364 /* 15365 * Look for the provided service in the service to manifest 15366 * tree. If the service exists, and a manifest was provided 15367 * then add the manifest to that service. If the service 15368 * does not exist, then add the service and manifest to the 15369 * list. 15370 * 15371 * If the manifest is NULL, return the element if found. If 15372 * the service is not found return NULL. 15373 */ 15374 service_manifest_t * 15375 find_add_svc_mfst(const char *svnbuf, const char *mfst) 15376 { 15377 service_manifest_t elem; 15378 service_manifest_t *fnelem; 15379 uu_avl_index_t marker; 15380 15381 elem.servicename = svnbuf; 15382 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 15383 15384 if (mfst) { 15385 if (fnelem) { 15386 add_string(fnelem->mfstlist, strdup(mfst)); 15387 } else { 15388 fnelem = safe_malloc(sizeof (*fnelem)); 15389 fnelem->servicename = safe_strdup(svnbuf); 15390 if ((fnelem->mfstlist = 15391 uu_list_create(string_pool, NULL, 0)) == NULL) 15392 uu_die(gettext("Could not create property " 15393 "list: %s\n"), uu_strerror(uu_error())); 15394 15395 add_string(fnelem->mfstlist, safe_strdup(mfst)); 15396 15397 uu_avl_insert(service_manifest_tree, fnelem, marker); 15398 } 15399 } 15400 15401 return (fnelem); 15402 } 15403 15404 /* 15405 * Create the service to manifest avl tree. 15406 * 15407 * Walk each of the manifests currently installed in the supported 15408 * directories, /lib/svc/manifests and /var/svc/manifests. For 15409 * each of the manifests, inventory the services and add them to 15410 * the tree. 15411 * 15412 * Code that calls this function should make sure fileystem/minimal is online, 15413 * /var is available, since this function walks the /var/svc/manifest directory. 15414 */ 15415 static void 15416 create_manifest_tree(void) 15417 { 15418 manifest_info_t **entry; 15419 manifest_info_t **manifests; 15420 uu_list_walk_t *svcs; 15421 bundle_t *b; 15422 entity_t *mfsvc; 15423 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 15424 int c, status; 15425 15426 if (service_manifest_pool) 15427 return; 15428 15429 /* 15430 * Create the list pool for the service manifest list 15431 */ 15432 service_manifest_pool = uu_avl_pool_create("service_manifest", 15433 sizeof (service_manifest_t), 15434 offsetof(service_manifest_t, svcmfst_node), 15435 service_manifest_compare, UU_DEFAULT); 15436 if (service_manifest_pool == NULL) 15437 uu_die(gettext("service_manifest pool creation failed: %s\n"), 15438 uu_strerror(uu_error())); 15439 15440 /* 15441 * Create the list 15442 */ 15443 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 15444 UU_DEFAULT); 15445 if (service_manifest_tree == NULL) 15446 uu_die(gettext("service_manifest tree creation failed: %s\n"), 15447 uu_strerror(uu_error())); 15448 15449 /* 15450 * Walk the manifests adding the service(s) from each manifest. 15451 * 15452 * If a service already exists add the manifest to the manifest 15453 * list for that service. This covers the case of a service that 15454 * is supported by multiple manifest files. 15455 */ 15456 for (c = 0; dirs[c]; c++) { 15457 status = find_manifests(dirs[c], &manifests, CHECKEXT); 15458 if (status < 0) { 15459 uu_warn(gettext("file tree walk of %s encountered " 15460 "error %s\n"), dirs[c], strerror(errno)); 15461 15462 uu_avl_destroy(service_manifest_tree); 15463 service_manifest_tree = NULL; 15464 return; 15465 } 15466 15467 /* 15468 * If a manifest that was in the list is not found 15469 * then skip and go to the next manifest file. 15470 */ 15471 if (manifests != NULL) { 15472 for (entry = manifests; *entry != NULL; entry++) { 15473 b = internal_bundle_new(); 15474 if (lxml_get_bundle_file(b, (*entry)->mi_path, 15475 SVCCFG_OP_IMPORT) != 0) { 15476 internal_bundle_free(b); 15477 continue; 15478 } 15479 15480 svcs = uu_list_walk_start(b->sc_bundle_services, 15481 0); 15482 if (svcs == NULL) { 15483 internal_bundle_free(b); 15484 continue; 15485 } 15486 15487 while ((mfsvc = uu_list_walk_next(svcs)) != 15488 NULL) { 15489 /* Add manifest to service */ 15490 (void) find_add_svc_mfst(mfsvc->sc_name, 15491 (*entry)->mi_path); 15492 } 15493 15494 uu_list_walk_end(svcs); 15495 internal_bundle_free(b); 15496 } 15497 15498 free_manifest_array(manifests); 15499 } 15500 } 15501 } 15502 15503 /* 15504 * Check the manifest history file to see 15505 * if the service was ever installed from 15506 * one of the supported directories. 15507 * 15508 * Return Values : 15509 * -1 - if there's error reading manifest history file 15510 * 1 - if the service is not found 15511 * 0 - if the service is found 15512 */ 15513 static int 15514 check_mfst_history(const char *svcname) 15515 { 15516 struct stat st; 15517 caddr_t mfsthist_start; 15518 char *svnbuf; 15519 int fd; 15520 int r = 1; 15521 15522 fd = open(MFSTHISTFILE, O_RDONLY); 15523 if (fd == -1) { 15524 uu_warn(gettext("Unable to open the history file\n")); 15525 return (-1); 15526 } 15527 15528 if (fstat(fd, &st) == -1) { 15529 uu_warn(gettext("Unable to stat the history file\n")); 15530 return (-1); 15531 } 15532 15533 mfsthist_start = mmap(0, st.st_size, PROT_READ, 15534 MAP_PRIVATE, fd, 0); 15535 15536 (void) close(fd); 15537 if (mfsthist_start == MAP_FAILED || 15538 *(mfsthist_start + st.st_size) != '\0') { 15539 (void) munmap(mfsthist_start, st.st_size); 15540 return (-1); 15541 } 15542 15543 /* 15544 * The manifest history file is a space delimited list 15545 * of service and instance to manifest linkage. Adding 15546 * a space to the end of the service name so to get only 15547 * the service that is being searched for. 15548 */ 15549 svnbuf = uu_msprintf("%s ", svcname); 15550 if (svnbuf == NULL) 15551 uu_die(gettext("Out of memory")); 15552 15553 if (strstr(mfsthist_start, svnbuf) != NULL) 15554 r = 0; 15555 15556 (void) munmap(mfsthist_start, st.st_size); 15557 uu_free(svnbuf); 15558 return (r); 15559 } 15560 15561 /* 15562 * Take down each of the instances in the service 15563 * and remove them, then delete the service. 15564 */ 15565 static void 15566 teardown_service(scf_service_t *svc, const char *svnbuf) 15567 { 15568 scf_instance_t *instance; 15569 scf_iter_t *iter; 15570 int r; 15571 15572 safe_printf(gettext("Delete service %s as there are no " 15573 "supporting manifests\n"), svnbuf); 15574 15575 instance = scf_instance_create(g_hndl); 15576 iter = scf_iter_create(g_hndl); 15577 if (iter == NULL || instance == NULL) { 15578 uu_warn(gettext("Unable to create supporting entities to " 15579 "teardown the service\n")); 15580 uu_warn(gettext("scf error is : %s\n"), 15581 scf_strerror(scf_error())); 15582 scfdie(); 15583 } 15584 15585 if (scf_iter_service_instances(iter, svc) != 0) { 15586 switch (scf_error()) { 15587 case SCF_ERROR_CONNECTION_BROKEN: 15588 case SCF_ERROR_DELETED: 15589 goto out; 15590 15591 case SCF_ERROR_HANDLE_MISMATCH: 15592 case SCF_ERROR_NOT_BOUND: 15593 case SCF_ERROR_NOT_SET: 15594 default: 15595 bad_error("scf_iter_service_instances", 15596 scf_error()); 15597 } 15598 } 15599 15600 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 15601 if (r == -1) { 15602 uu_warn(gettext("Error - %s\n"), 15603 scf_strerror(scf_error())); 15604 goto out; 15605 } 15606 15607 (void) disable_instance(instance); 15608 } 15609 15610 /* 15611 * Delete the service... forcing the deletion in case 15612 * any of the instances did not disable. 15613 */ 15614 (void) lscf_service_delete(svc, 1); 15615 out: 15616 scf_instance_destroy(instance); 15617 scf_iter_destroy(iter); 15618 } 15619 15620 /* 15621 * Get the list of instances supported by the manifest 15622 * file. 15623 * 15624 * Return 0 if there are no instances. 15625 * 15626 * Return -1 if there are errors attempting to collect instances. 15627 * 15628 * Return the count of instances found if there are no errors. 15629 * 15630 */ 15631 static int 15632 check_instance_support(char *mfstfile, const char *svcname, 15633 uu_list_t *instances) 15634 { 15635 uu_list_walk_t *svcs, *insts; 15636 uu_list_t *ilist; 15637 bundle_t *b; 15638 entity_t *mfsvc, *mfinst; 15639 const char *svcn; 15640 int rminstcnt = 0; 15641 15642 15643 b = internal_bundle_new(); 15644 15645 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 15646 /* 15647 * Unable to process the manifest file for 15648 * instance support, so just return as 15649 * don't want to remove instances that could 15650 * not be accounted for that might exist here. 15651 */ 15652 internal_bundle_free(b); 15653 return (0); 15654 } 15655 15656 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 15657 if (svcs == NULL) { 15658 internal_bundle_free(b); 15659 return (0); 15660 } 15661 15662 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 15663 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 15664 15665 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 15666 if (strcmp(mfsvc->sc_name, svcn) == 0) 15667 break; 15668 } 15669 uu_list_walk_end(svcs); 15670 15671 if (mfsvc == NULL) { 15672 internal_bundle_free(b); 15673 return (-1); 15674 } 15675 15676 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 15677 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 15678 internal_bundle_free(b); 15679 return (0); 15680 } 15681 15682 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 15683 /* 15684 * Remove the instance from the instances list. 15685 * The unaccounted for instances will be removed 15686 * from the service once all manifests are 15687 * processed. 15688 */ 15689 (void) remove_string(instances, 15690 mfinst->sc_name); 15691 rminstcnt++; 15692 } 15693 15694 uu_list_walk_end(insts); 15695 internal_bundle_free(b); 15696 15697 return (rminstcnt); 15698 } 15699 15700 /* 15701 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 15702 * 'false' to indicate there's no manifest file(s) found for the service. 15703 */ 15704 static void 15705 svc_add_no_support(scf_service_t *svc) 15706 { 15707 char *pname; 15708 15709 /* Add no support */ 15710 cur_svc = svc; 15711 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 15712 return; 15713 15714 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 15715 if (pname == NULL) 15716 uu_die(gettext("Out of memory.\n")); 15717 15718 (void) lscf_addpropvalue(pname, "boolean:", "0"); 15719 15720 uu_free(pname); 15721 cur_svc = NULL; 15722 } 15723 15724 /* 15725 * This function handles all upgrade scenarios for a service that doesn't have 15726 * SCF_PG_MANIFESTFILES pg. The function creates and populates 15727 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 15728 * manifest(s) mapping. Manifests under supported directories are inventoried 15729 * and a property is added for each file that delivers configuration to the 15730 * service. A service that has no corresponding manifest files (deleted) are 15731 * removed from repository. 15732 * 15733 * Unsupported services: 15734 * 15735 * A service is considered unsupported if there is no corresponding manifest 15736 * in the supported directories for that service and the service isn't in the 15737 * history file list. The history file, MFSTHISTFILE, contains a list of all 15738 * services and instances that were delivered by Solaris before the introduction 15739 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 15740 * the path to the manifest file that defined the service or instance. 15741 * 15742 * Another type of unsupported services is 'handcrafted' services, 15743 * programmatically created services or services created by dependent entries 15744 * in other manifests. A handcrafted service is identified by its lack of any 15745 * instance containing last-import snapshot which is created during svccfg 15746 * import. 15747 * 15748 * This function sets a flag for unsupported services by setting services' 15749 * SCF_PG_MANIFESTFILES/support property to false. 15750 */ 15751 static void 15752 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 15753 { 15754 service_manifest_t *elem; 15755 uu_list_walk_t *mfwalk; 15756 string_list_t *mfile; 15757 uu_list_t *instances; 15758 const char *sname; 15759 char *pname; 15760 int r; 15761 15762 /* 15763 * Since there's no guarantee manifests under /var are available during 15764 * early import, don't perform any upgrade during early import. 15765 */ 15766 if (IGNORE_VAR) 15767 return; 15768 15769 if (service_manifest_tree == NULL) { 15770 create_manifest_tree(); 15771 } 15772 15773 /* 15774 * Find service's supporting manifest(s) after 15775 * stripping off the svc:/ prefix that is part 15776 * of the fmri that is not used in the service 15777 * manifest bundle list. 15778 */ 15779 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 15780 strlen(SCF_FMRI_SERVICE_PREFIX); 15781 elem = find_add_svc_mfst(sname, NULL); 15782 if (elem == NULL) { 15783 15784 /* 15785 * A handcrafted service, one that has no instance containing 15786 * last-import snapshot, should get unsupported flag. 15787 */ 15788 instances = create_instance_list(svc, 1); 15789 if (instances == NULL) { 15790 uu_warn(gettext("Unable to create instance list %s\n"), 15791 svcname); 15792 return; 15793 } 15794 15795 if (uu_list_numnodes(instances) == 0) { 15796 svc_add_no_support(svc); 15797 return; 15798 } 15799 15800 /* 15801 * If the service is in the history file, and its supporting 15802 * manifests are not found, we can safely delete the service 15803 * because its manifests are removed from the system. 15804 * 15805 * Services not found in the history file are not delivered by 15806 * Solaris and/or delivered outside supported directories, set 15807 * unsupported flag for these services. 15808 */ 15809 r = check_mfst_history(svcname); 15810 if (r == -1) 15811 return; 15812 15813 if (r) { 15814 /* Set unsupported flag for service */ 15815 svc_add_no_support(svc); 15816 } else { 15817 /* Delete the service */ 15818 teardown_service(svc, svcname); 15819 } 15820 15821 return; 15822 } 15823 15824 /* 15825 * Walk through the list of manifests and add them 15826 * to the service. 15827 * 15828 * Create a manifestfiles pg and add the property. 15829 */ 15830 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 15831 if (mfwalk == NULL) 15832 return; 15833 15834 cur_svc = svc; 15835 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 15836 if (r != 0) { 15837 cur_svc = NULL; 15838 return; 15839 } 15840 15841 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 15842 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 15843 mhash_filename_to_propname(mfile->str, 0)); 15844 if (pname == NULL) 15845 uu_die(gettext("Out of memory.\n")); 15846 15847 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 15848 uu_free(pname); 15849 } 15850 uu_list_walk_end(mfwalk); 15851 15852 cur_svc = NULL; 15853 } 15854 15855 /* 15856 * Take a service and process the manifest file entires to see if 15857 * there is continued support for the service and instances. If 15858 * not cleanup as appropriate. 15859 * 15860 * If a service does not have a manifest files entry flag it for 15861 * upgrade and return. 15862 * 15863 * For each manifestfiles property check if the manifest file is 15864 * under the supported /lib/svc/manifest or /var/svc/manifest path 15865 * and if not then return immediately as this service is not supported 15866 * by the cleanup mechanism and should be ignored. 15867 * 15868 * For each manifest file that is supported, check to see if the 15869 * file exists. If not then remove the manifest file property 15870 * from the service and the smf/manifest hash table. If the manifest 15871 * file exists then verify that it supports the instances that are 15872 * part of the service. 15873 * 15874 * Once all manifest files have been accounted for remove any instances 15875 * that are no longer supported in the service. 15876 * 15877 * Return values : 15878 * 0 - Successfully processed the service 15879 * non-zero - failed to process the service 15880 * 15881 * On most errors, will just return to wait and get the next service, 15882 * unless in case of unable to create the needed structures which is 15883 * most likely a fatal error that is not going to be recoverable. 15884 */ 15885 int 15886 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 15887 { 15888 struct mpg_mfile *mpntov; 15889 struct mpg_mfile **mpvarry = NULL; 15890 scf_service_t *svc; 15891 scf_propertygroup_t *mpg; 15892 scf_property_t *mp; 15893 scf_value_t *mv; 15894 scf_iter_t *mi; 15895 scf_instance_t *instance; 15896 uu_list_walk_t *insts; 15897 uu_list_t *instances = NULL; 15898 boolean_t activity = (boolean_t)act; 15899 char *mpnbuf; 15900 char *mpvbuf; 15901 char *pgpropbuf; 15902 int mfstcnt, rminstct, instct, mfstmax; 15903 int index; 15904 int r = 0; 15905 15906 assert(g_hndl != NULL); 15907 assert(wip->svc != NULL); 15908 assert(wip->fmri != NULL); 15909 15910 svc = wip->svc; 15911 15912 mpg = scf_pg_create(g_hndl); 15913 mp = scf_property_create(g_hndl); 15914 mi = scf_iter_create(g_hndl); 15915 mv = scf_value_create(g_hndl); 15916 instance = scf_instance_create(g_hndl); 15917 15918 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 15919 instance == NULL) { 15920 uu_warn(gettext("Unable to create the supporting entities\n")); 15921 uu_warn(gettext("scf error is : %s\n"), 15922 scf_strerror(scf_error())); 15923 scfdie(); 15924 } 15925 15926 /* 15927 * Get the manifestfiles property group to be parsed for 15928 * files existence. 15929 */ 15930 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 15931 switch (scf_error()) { 15932 case SCF_ERROR_NOT_FOUND: 15933 upgrade_svc_mfst_connection(svc, wip->fmri); 15934 break; 15935 case SCF_ERROR_DELETED: 15936 case SCF_ERROR_CONNECTION_BROKEN: 15937 goto out; 15938 15939 case SCF_ERROR_HANDLE_MISMATCH: 15940 case SCF_ERROR_NOT_BOUND: 15941 case SCF_ERROR_NOT_SET: 15942 default: 15943 bad_error("scf_iter_pg_properties", 15944 scf_error()); 15945 } 15946 15947 goto out; 15948 } 15949 15950 /* 15951 * Iterate through each of the manifestfiles properties 15952 * to determine what manifestfiles are available. 15953 * 15954 * If a manifest file is supported then increment the 15955 * count and therefore the service is safe. 15956 */ 15957 if (scf_iter_pg_properties(mi, mpg) != 0) { 15958 switch (scf_error()) { 15959 case SCF_ERROR_DELETED: 15960 case SCF_ERROR_CONNECTION_BROKEN: 15961 goto out; 15962 15963 case SCF_ERROR_HANDLE_MISMATCH: 15964 case SCF_ERROR_NOT_BOUND: 15965 case SCF_ERROR_NOT_SET: 15966 default: 15967 bad_error("scf_iter_pg_properties", 15968 scf_error()); 15969 } 15970 } 15971 15972 mfstcnt = 0; 15973 mfstmax = MFSTFILE_MAX; 15974 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 15975 while ((r = scf_iter_next_property(mi, mp)) != 0) { 15976 if (r == -1) 15977 bad_error(gettext("Unable to iterate through " 15978 "manifestfiles properties : %s"), 15979 scf_error()); 15980 15981 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 15982 mpnbuf = safe_malloc(max_scf_name_len + 1); 15983 mpvbuf = safe_malloc(max_scf_value_len + 1); 15984 mpntov->mpg = mpnbuf; 15985 mpntov->mfile = mpvbuf; 15986 mpntov->access = 1; 15987 if (scf_property_get_name(mp, mpnbuf, 15988 max_scf_name_len + 1) < 0) { 15989 uu_warn(gettext("Unable to get manifest file " 15990 "property : %s\n"), 15991 scf_strerror(scf_error())); 15992 15993 switch (scf_error()) { 15994 case SCF_ERROR_DELETED: 15995 case SCF_ERROR_CONNECTION_BROKEN: 15996 r = scferror2errno(scf_error()); 15997 goto out_free; 15998 15999 case SCF_ERROR_HANDLE_MISMATCH: 16000 case SCF_ERROR_NOT_BOUND: 16001 case SCF_ERROR_NOT_SET: 16002 default: 16003 bad_error("scf_iter_pg_properties", 16004 scf_error()); 16005 } 16006 } 16007 16008 /* 16009 * The support property is a boolean value that indicates 16010 * if the service is supported for manifest file deletion. 16011 * Currently at this time there is no code that sets this 16012 * value to true. So while we could just let this be caught 16013 * by the support check below, in the future this by be set 16014 * to true and require processing. So for that, go ahead 16015 * and check here, and just return if false. Otherwise, 16016 * fall through expecting that other support checks will 16017 * handle the entries. 16018 */ 16019 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 16020 uint8_t support; 16021 16022 if (scf_property_get_value(mp, mv) != 0 || 16023 scf_value_get_boolean(mv, &support) != 0) { 16024 uu_warn(gettext("Unable to get the manifest " 16025 "support value: %s\n"), 16026 scf_strerror(scf_error())); 16027 16028 switch (scf_error()) { 16029 case SCF_ERROR_DELETED: 16030 case SCF_ERROR_CONNECTION_BROKEN: 16031 r = scferror2errno(scf_error()); 16032 goto out_free; 16033 16034 case SCF_ERROR_HANDLE_MISMATCH: 16035 case SCF_ERROR_NOT_BOUND: 16036 case SCF_ERROR_NOT_SET: 16037 default: 16038 bad_error("scf_iter_pg_properties", 16039 scf_error()); 16040 } 16041 } 16042 16043 if (support == B_FALSE) 16044 goto out_free; 16045 } 16046 16047 /* 16048 * Anything with a manifest outside of the supported 16049 * directories, immediately bail out because that makes 16050 * this service non-supported. We don't even want 16051 * to do instance processing in this case because the 16052 * instances could be part of the non-supported manifest. 16053 */ 16054 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 16055 /* 16056 * Manifest is not in /lib/svc, so we need to 16057 * consider the /var/svc case. 16058 */ 16059 if (strncmp(mpnbuf, VARSVC_PR, 16060 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 16061 /* 16062 * Either the manifest is not in /var/svc or 16063 * /var is not yet mounted. We ignore the 16064 * manifest either because it is not in a 16065 * standard location or because we cannot 16066 * currently access the manifest. 16067 */ 16068 goto out_free; 16069 } 16070 } 16071 16072 /* 16073 * Get the value to of the manifest file for this entry 16074 * for access verification and instance support 16075 * verification if it still exists. 16076 * 16077 * During Early Manifest Import if the manifest is in 16078 * /var/svc then it may not yet be available for checking 16079 * so we must determine if /var/svc is available. If not 16080 * then defer until Late Manifest Import to cleanup. 16081 */ 16082 if (scf_property_get_value(mp, mv) != 0) { 16083 uu_warn(gettext("Unable to get the manifest file " 16084 "value: %s\n"), 16085 scf_strerror(scf_error())); 16086 16087 switch (scf_error()) { 16088 case SCF_ERROR_DELETED: 16089 case SCF_ERROR_CONNECTION_BROKEN: 16090 r = scferror2errno(scf_error()); 16091 goto out_free; 16092 16093 case SCF_ERROR_HANDLE_MISMATCH: 16094 case SCF_ERROR_NOT_BOUND: 16095 case SCF_ERROR_NOT_SET: 16096 default: 16097 bad_error("scf_property_get_value", 16098 scf_error()); 16099 } 16100 } 16101 16102 if (scf_value_get_astring(mv, mpvbuf, 16103 max_scf_value_len + 1) < 0) { 16104 uu_warn(gettext("Unable to get the manifest " 16105 "file : %s\n"), 16106 scf_strerror(scf_error())); 16107 16108 switch (scf_error()) { 16109 case SCF_ERROR_DELETED: 16110 case SCF_ERROR_CONNECTION_BROKEN: 16111 r = scferror2errno(scf_error()); 16112 goto out_free; 16113 16114 case SCF_ERROR_HANDLE_MISMATCH: 16115 case SCF_ERROR_NOT_BOUND: 16116 case SCF_ERROR_NOT_SET: 16117 default: 16118 bad_error("scf_value_get_astring", 16119 scf_error()); 16120 } 16121 } 16122 16123 mpvarry[mfstcnt] = mpntov; 16124 mfstcnt++; 16125 16126 /* 16127 * Check for the need to reallocate array 16128 */ 16129 if (mfstcnt >= (mfstmax - 1)) { 16130 struct mpg_mfile **newmpvarry; 16131 16132 mfstmax = mfstmax * 2; 16133 newmpvarry = realloc(mpvarry, 16134 sizeof (struct mpg_mfile *) * mfstmax); 16135 16136 if (newmpvarry == NULL) 16137 goto out_free; 16138 16139 mpvarry = newmpvarry; 16140 } 16141 16142 mpvarry[mfstcnt] = NULL; 16143 } 16144 16145 for (index = 0; mpvarry[index]; index++) { 16146 mpntov = mpvarry[index]; 16147 16148 /* 16149 * Check to see if the manifestfile is accessable, if so hand 16150 * this service and manifestfile off to be processed for 16151 * instance support. 16152 */ 16153 mpnbuf = mpntov->mpg; 16154 mpvbuf = mpntov->mfile; 16155 if (access(mpvbuf, F_OK) != 0) { 16156 mpntov->access = 0; 16157 activity++; 16158 mfstcnt--; 16159 /* Remove the entry from the service */ 16160 cur_svc = svc; 16161 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16162 mpnbuf); 16163 if (pgpropbuf == NULL) 16164 uu_die(gettext("Out of memory.\n")); 16165 16166 lscf_delprop(pgpropbuf); 16167 cur_svc = NULL; 16168 16169 uu_free(pgpropbuf); 16170 } 16171 } 16172 16173 /* 16174 * If mfstcnt is 0, none of the manifests that supported the service 16175 * existed so remove the service. 16176 */ 16177 if (mfstcnt == 0) { 16178 teardown_service(svc, wip->fmri); 16179 16180 goto out_free; 16181 } 16182 16183 if (activity) { 16184 int nosvcsupport = 0; 16185 16186 /* 16187 * If the list of service instances is NULL then 16188 * create the list. 16189 */ 16190 instances = create_instance_list(svc, 1); 16191 if (instances == NULL) { 16192 uu_warn(gettext("Unable to create instance list %s\n"), 16193 wip->fmri); 16194 goto out_free; 16195 } 16196 16197 rminstct = uu_list_numnodes(instances); 16198 instct = rminstct; 16199 16200 for (index = 0; mpvarry[index]; index++) { 16201 mpntov = mpvarry[index]; 16202 if (mpntov->access == 0) 16203 continue; 16204 16205 mpnbuf = mpntov->mpg; 16206 mpvbuf = mpntov->mfile; 16207 r = check_instance_support(mpvbuf, wip->fmri, 16208 instances); 16209 if (r == -1) { 16210 nosvcsupport++; 16211 } else { 16212 rminstct -= r; 16213 } 16214 } 16215 16216 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 16217 teardown_service(svc, wip->fmri); 16218 16219 goto out_free; 16220 } 16221 } 16222 16223 /* 16224 * If there are instances left on the instance list, then 16225 * we must remove them. 16226 */ 16227 if (instances != NULL && uu_list_numnodes(instances)) { 16228 string_list_t *sp; 16229 16230 insts = uu_list_walk_start(instances, 0); 16231 while ((sp = uu_list_walk_next(insts)) != NULL) { 16232 /* 16233 * Remove the instance from the instances list. 16234 */ 16235 safe_printf(gettext("Delete instance %s from " 16236 "service %s\n"), sp->str, wip->fmri); 16237 if (scf_service_get_instance(svc, sp->str, 16238 instance) != SCF_SUCCESS) { 16239 (void) uu_warn("scf_error - %s\n", 16240 scf_strerror(scf_error())); 16241 16242 continue; 16243 } 16244 16245 (void) disable_instance(instance); 16246 16247 (void) lscf_instance_delete(instance, 1); 16248 } 16249 scf_instance_destroy(instance); 16250 uu_list_walk_end(insts); 16251 } 16252 16253 out_free: 16254 if (mpvarry) { 16255 struct mpg_mfile *fmpntov; 16256 16257 for (index = 0; mpvarry[index]; index++) { 16258 fmpntov = mpvarry[index]; 16259 if (fmpntov->mpg == mpnbuf) 16260 mpnbuf = NULL; 16261 free(fmpntov->mpg); 16262 16263 if (fmpntov->mfile == mpvbuf) 16264 mpvbuf = NULL; 16265 free(fmpntov->mfile); 16266 16267 if (fmpntov == mpntov) 16268 mpntov = NULL; 16269 free(fmpntov); 16270 } 16271 if (mpnbuf) 16272 free(mpnbuf); 16273 if (mpvbuf) 16274 free(mpvbuf); 16275 if (mpntov) 16276 free(mpntov); 16277 16278 free(mpvarry); 16279 } 16280 out: 16281 scf_pg_destroy(mpg); 16282 scf_property_destroy(mp); 16283 scf_iter_destroy(mi); 16284 scf_value_destroy(mv); 16285 16286 return (0); 16287 } 16288 16289 /* 16290 * Take the service and search for the manifestfiles property 16291 * in each of the property groups. If the manifest file 16292 * associated with the property does not exist then remove 16293 * the property group. 16294 */ 16295 int 16296 lscf_hash_cleanup() 16297 { 16298 scf_service_t *svc; 16299 scf_scope_t *scope; 16300 scf_propertygroup_t *pg; 16301 scf_property_t *prop; 16302 scf_value_t *val; 16303 scf_iter_t *iter; 16304 char *pgname; 16305 char *mfile; 16306 int r; 16307 16308 svc = scf_service_create(g_hndl); 16309 scope = scf_scope_create(g_hndl); 16310 pg = scf_pg_create(g_hndl); 16311 prop = scf_property_create(g_hndl); 16312 val = scf_value_create(g_hndl); 16313 iter = scf_iter_create(g_hndl); 16314 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 16315 svc == NULL || scope == NULL) { 16316 uu_warn(gettext("Unable to create a property group, or " 16317 "property\n")); 16318 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 16319 "pg is not NULL"); 16320 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 16321 "prop is not NULL"); 16322 uu_warn("%s\n", val == NULL ? "val is NULL" : 16323 "val is not NULL"); 16324 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 16325 "iter is not NULL"); 16326 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 16327 "svc is not NULL"); 16328 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 16329 "scope is not NULL"); 16330 uu_warn(gettext("scf error is : %s\n"), 16331 scf_strerror(scf_error())); 16332 scfdie(); 16333 } 16334 16335 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 16336 switch (scf_error()) { 16337 case SCF_ERROR_CONNECTION_BROKEN: 16338 case SCF_ERROR_NOT_FOUND: 16339 goto out; 16340 16341 case SCF_ERROR_HANDLE_MISMATCH: 16342 case SCF_ERROR_NOT_BOUND: 16343 case SCF_ERROR_INVALID_ARGUMENT: 16344 default: 16345 bad_error("scf_handle_get_scope", scf_error()); 16346 } 16347 } 16348 16349 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 16350 uu_warn(gettext("Unable to process the hash service, %s\n"), 16351 HASH_SVC); 16352 goto out; 16353 } 16354 16355 pgname = safe_malloc(max_scf_name_len + 1); 16356 mfile = safe_malloc(max_scf_value_len + 1); 16357 16358 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 16359 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 16360 scf_strerror(scf_error())); 16361 goto out; 16362 } 16363 16364 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 16365 if (r == -1) 16366 goto out; 16367 16368 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 16369 switch (scf_error()) { 16370 case SCF_ERROR_DELETED: 16371 return (ENODEV); 16372 16373 case SCF_ERROR_CONNECTION_BROKEN: 16374 return (ECONNABORTED); 16375 16376 case SCF_ERROR_NOT_SET: 16377 case SCF_ERROR_NOT_BOUND: 16378 default: 16379 bad_error("scf_pg_get_name", scf_error()); 16380 } 16381 } 16382 if (IGNORE_VAR) { 16383 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 16384 continue; 16385 } 16386 16387 /* 16388 * If unable to get the property continue as this is an 16389 * entry that has no location to check against. 16390 */ 16391 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 16392 continue; 16393 } 16394 16395 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 16396 uu_warn(gettext("Unable to get value from %s\n"), 16397 pgname); 16398 goto error_handle; 16399 } 16400 16401 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) == 16402 -1) { 16403 uu_warn(gettext("Unable to get astring from %s : %s\n"), 16404 pgname, scf_strerror(scf_error())); 16405 goto error_handle; 16406 } 16407 16408 if (access(mfile, F_OK) == 0) 16409 continue; 16410 16411 (void) scf_pg_delete(pg); 16412 16413 error_handle: 16414 switch (scf_error()) { 16415 case SCF_ERROR_DELETED: 16416 case SCF_ERROR_CONSTRAINT_VIOLATED: 16417 case SCF_ERROR_NOT_FOUND: 16418 case SCF_ERROR_NOT_SET: 16419 continue; 16420 16421 case SCF_ERROR_CONNECTION_BROKEN: 16422 r = scferror2errno(scf_error()); 16423 goto out; 16424 16425 case SCF_ERROR_HANDLE_MISMATCH: 16426 case SCF_ERROR_NOT_BOUND: 16427 default: 16428 bad_error("scf_value_get_astring", 16429 scf_error()); 16430 } 16431 } 16432 16433 out: 16434 scf_scope_destroy(scope); 16435 scf_service_destroy(svc); 16436 scf_pg_destroy(pg); 16437 scf_property_destroy(prop); 16438 scf_value_destroy(val); 16439 scf_iter_destroy(iter); 16440 free(pgname); 16441 free(mfile); 16442 16443 return (0); 16444 } 16445 16446 #ifndef NATIVE_BUILD 16447 /* ARGSUSED */ 16448 CPL_MATCH_FN(complete_select) 16449 { 16450 const char *arg0, *arg1, *arg1end; 16451 int word_start, err = 0, r; 16452 size_t len; 16453 char *buf; 16454 16455 lscf_prep_hndl(); 16456 16457 arg0 = line + strspn(line, " \t"); 16458 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 16459 16460 arg1 = arg0 + sizeof ("select") - 1; 16461 arg1 += strspn(arg1, " \t"); 16462 word_start = arg1 - line; 16463 16464 arg1end = arg1 + strcspn(arg1, " \t"); 16465 if (arg1end < line + word_end) 16466 return (0); 16467 16468 len = line + word_end - arg1; 16469 16470 buf = safe_malloc(max_scf_name_len + 1); 16471 16472 if (cur_snap != NULL) { 16473 return (0); 16474 } else if (cur_inst != NULL) { 16475 return (0); 16476 } else if (cur_svc != NULL) { 16477 scf_instance_t *inst; 16478 scf_iter_t *iter; 16479 16480 if ((inst = scf_instance_create(g_hndl)) == NULL || 16481 (iter = scf_iter_create(g_hndl)) == NULL) 16482 scfdie(); 16483 16484 if (scf_iter_service_instances(iter, cur_svc) != 0) 16485 scfdie(); 16486 16487 for (;;) { 16488 r = scf_iter_next_instance(iter, inst); 16489 if (r == 0) 16490 break; 16491 if (r != 1) 16492 scfdie(); 16493 16494 if (scf_instance_get_name(inst, buf, 16495 max_scf_name_len + 1) < 0) 16496 scfdie(); 16497 16498 if (strncmp(buf, arg1, len) == 0) { 16499 err = cpl_add_completion(cpl, line, word_start, 16500 word_end, buf + len, "", " "); 16501 if (err != 0) 16502 break; 16503 } 16504 } 16505 16506 scf_iter_destroy(iter); 16507 scf_instance_destroy(inst); 16508 16509 return (err); 16510 } else { 16511 scf_service_t *svc; 16512 scf_iter_t *iter; 16513 16514 assert(cur_scope != NULL); 16515 16516 if ((svc = scf_service_create(g_hndl)) == NULL || 16517 (iter = scf_iter_create(g_hndl)) == NULL) 16518 scfdie(); 16519 16520 if (scf_iter_scope_services(iter, cur_scope) != 0) 16521 scfdie(); 16522 16523 for (;;) { 16524 r = scf_iter_next_service(iter, svc); 16525 if (r == 0) 16526 break; 16527 if (r != 1) 16528 scfdie(); 16529 16530 if (scf_service_get_name(svc, buf, 16531 max_scf_name_len + 1) < 0) 16532 scfdie(); 16533 16534 if (strncmp(buf, arg1, len) == 0) { 16535 err = cpl_add_completion(cpl, line, word_start, 16536 word_end, buf + len, "", " "); 16537 if (err != 0) 16538 break; 16539 } 16540 } 16541 16542 scf_iter_destroy(iter); 16543 scf_service_destroy(svc); 16544 16545 return (err); 16546 } 16547 } 16548 16549 /* ARGSUSED */ 16550 CPL_MATCH_FN(complete_command) 16551 { 16552 uint32_t scope = 0; 16553 16554 if (cur_snap != NULL) 16555 scope = CS_SNAP; 16556 else if (cur_inst != NULL) 16557 scope = CS_INST; 16558 else if (cur_svc != NULL) 16559 scope = CS_SVC; 16560 else 16561 scope = CS_SCOPE; 16562 16563 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 16564 } 16565 #endif /* NATIVE_BUILD */ 16566