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 /* 919 * When a value of type opaque is represented as a string, the 920 * string contains 2 characters for every byte of data. That is 921 * because the string contains the hex representation of the opaque 922 * value. 923 */ 924 if (2 * max_scf_value_len > max_scf_len) 925 max_scf_len = 2 * max_scf_value_len; 926 927 if (atexit(remove_tempfile) != 0) 928 uu_die(gettext("Could not register atexit() function")); 929 930 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 931 emsg_permission_denied = gettext("Permission denied.\n"); 932 emsg_create_xml = gettext("Could not create XML node.\n"); 933 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 934 emsg_read_only = gettext("Backend read-only.\n"); 935 emsg_deleted = gettext("Current selection has been deleted.\n"); 936 emsg_invalid_pg_name = 937 gettext("Invalid property group name \"%s\".\n"); 938 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 939 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 940 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 941 "with invalid name \"%s\".\n"); 942 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 943 "group with invalid name \"%s\" or type \"%s\".\n"); 944 emsg_pg_added = gettext("%s changed unexpectedly " 945 "(property group \"%s\" added).\n"); 946 emsg_pg_changed = gettext("%s changed unexpectedly " 947 "(property group \"%s\" changed).\n"); 948 emsg_pg_deleted = gettext("%s changed unexpectedly " 949 "(property group \"%s\" or an ancestor was deleted).\n"); 950 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 951 "in %s (permission denied).\n"); 952 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 953 "in %s (permission denied).\n"); 954 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 955 "in %s (permission denied).\n"); 956 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 957 "(permission denied).\n"); 958 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 959 "new dependent \"%s\" because it already exists). Warning: The " 960 "current dependent's target (%s) does not exist.\n"); 961 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 962 "dependent \"%s\" because it already exists). Warning: The " 963 "current dependent's target (%s) does not have a dependency named " 964 "\"%s\" as expected.\n"); 965 966 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 967 offsetof(string_list_t, node), NULL, 0); 968 snaplevel_pool = uu_list_pool_create("snaplevels", 969 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 970 NULL, 0); 971 } 972 973 974 static const char * 975 prop_to_typestr(const scf_property_t *prop) 976 { 977 scf_type_t ty; 978 979 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 980 scfdie(); 981 982 return (scf_type_to_string(ty)); 983 } 984 985 static scf_type_t 986 string_to_type(const char *type) 987 { 988 size_t len = strlen(type); 989 char *buf; 990 991 if (len == 0 || type[len - 1] != ':') 992 return (SCF_TYPE_INVALID); 993 994 buf = (char *)alloca(len + 1); 995 (void) strlcpy(buf, type, len + 1); 996 buf[len - 1] = 0; 997 998 return (scf_string_to_type(buf)); 999 } 1000 1001 static scf_value_t * 1002 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 1003 { 1004 scf_value_t *v; 1005 char *dup, *nstr; 1006 size_t len; 1007 1008 v = scf_value_create(g_hndl); 1009 if (v == NULL) 1010 scfdie(); 1011 1012 len = strlen(str); 1013 if (require_quotes && 1014 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1015 semerr(gettext("Multiple string values or string values " 1016 "with spaces must be quoted with '\"'.\n")); 1017 scf_value_destroy(v); 1018 return (NULL); 1019 } 1020 1021 nstr = dup = safe_strdup(str); 1022 if (dup[0] == '\"') { 1023 /* 1024 * Strip out the first and the last quote. 1025 */ 1026 dup[len - 1] = '\0'; 1027 nstr = dup + 1; 1028 } 1029 1030 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1031 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1032 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1033 scf_type_to_string(ty), nstr); 1034 scf_value_destroy(v); 1035 v = NULL; 1036 } 1037 free(dup); 1038 return (v); 1039 } 1040 1041 /* 1042 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1043 * Optionally append a comment prefix ('#') to newlines ('\n'). 1044 */ 1045 static int 1046 quote_and_print(const char *str, FILE *strm, int commentnl) 1047 { 1048 const char *cp; 1049 1050 for (cp = str; *cp != '\0'; ++cp) { 1051 if (*cp == '"' || *cp == '\\') 1052 (void) putc('\\', strm); 1053 1054 (void) putc(*cp, strm); 1055 1056 if (commentnl && *cp == '\n') { 1057 (void) putc('#', strm); 1058 } 1059 } 1060 1061 return (ferror(strm)); 1062 } 1063 1064 /* 1065 * These wrappers around lowlevel functions provide consistent error checking 1066 * and warnings. 1067 */ 1068 static int 1069 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1070 { 1071 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1072 return (0); 1073 1074 if (scf_error() != SCF_ERROR_NOT_FOUND) 1075 scfdie(); 1076 1077 if (g_verbose) { 1078 ssize_t len; 1079 char *fmri; 1080 1081 len = scf_pg_to_fmri(pg, NULL, 0); 1082 if (len < 0) 1083 scfdie(); 1084 1085 fmri = safe_malloc(len + 1); 1086 1087 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1088 scfdie(); 1089 1090 warn(gettext("Expected property %s of property group %s is " 1091 "missing.\n"), propname, fmri); 1092 1093 free(fmri); 1094 } 1095 1096 return (-1); 1097 } 1098 1099 static int 1100 prop_check_type(scf_property_t *prop, scf_type_t ty) 1101 { 1102 scf_type_t pty; 1103 1104 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1105 scfdie(); 1106 1107 if (ty == pty) 1108 return (0); 1109 1110 if (g_verbose) { 1111 ssize_t len; 1112 char *fmri; 1113 const char *tystr; 1114 1115 len = scf_property_to_fmri(prop, NULL, 0); 1116 if (len < 0) 1117 scfdie(); 1118 1119 fmri = safe_malloc(len + 1); 1120 1121 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1122 scfdie(); 1123 1124 tystr = scf_type_to_string(ty); 1125 if (tystr == NULL) 1126 tystr = "?"; 1127 1128 warn(gettext("Property %s is not of expected type %s.\n"), 1129 fmri, tystr); 1130 1131 free(fmri); 1132 } 1133 1134 return (-1); 1135 } 1136 1137 static int 1138 prop_get_val(scf_property_t *prop, scf_value_t *val) 1139 { 1140 scf_error_t err; 1141 1142 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1143 return (0); 1144 1145 err = scf_error(); 1146 1147 if (err != SCF_ERROR_NOT_FOUND && 1148 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1149 err != SCF_ERROR_PERMISSION_DENIED) 1150 scfdie(); 1151 1152 if (g_verbose) { 1153 ssize_t len; 1154 char *fmri, *emsg; 1155 1156 len = scf_property_to_fmri(prop, NULL, 0); 1157 if (len < 0) 1158 scfdie(); 1159 1160 fmri = safe_malloc(len + 1); 1161 1162 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1163 scfdie(); 1164 1165 if (err == SCF_ERROR_NOT_FOUND) 1166 emsg = gettext("Property %s has no values; expected " 1167 "one.\n"); 1168 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1169 emsg = gettext("Property %s has multiple values; " 1170 "expected one.\n"); 1171 else 1172 emsg = gettext("No permission to read property %s.\n"); 1173 1174 warn(emsg, fmri); 1175 1176 free(fmri); 1177 } 1178 1179 return (-1); 1180 } 1181 1182 1183 static boolean_t 1184 snaplevel_is_instance(const scf_snaplevel_t *level) 1185 { 1186 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1187 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1188 scfdie(); 1189 return (0); 1190 } else { 1191 return (1); 1192 } 1193 } 1194 1195 /* 1196 * Decode FMRI into a service or instance, and put the result in *ep. If 1197 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1198 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1199 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1200 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1201 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1202 * whether *ep is a service. 1203 */ 1204 static scf_error_t 1205 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1206 { 1207 char *fmri_copy; 1208 const char *sstr, *istr, *pgstr; 1209 scf_service_t *svc; 1210 scf_instance_t *inst; 1211 1212 fmri_copy = strdup(fmri); 1213 if (fmri_copy == NULL) 1214 return (SCF_ERROR_NO_MEMORY); 1215 1216 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1217 SCF_SUCCESS) { 1218 free(fmri_copy); 1219 return (SCF_ERROR_INVALID_ARGUMENT); 1220 } 1221 1222 free(fmri_copy); 1223 1224 if (sstr == NULL || pgstr != NULL) 1225 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1226 1227 if (istr == NULL) { 1228 svc = scf_service_create(h); 1229 if (svc == NULL) 1230 return (SCF_ERROR_NO_MEMORY); 1231 1232 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1233 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1234 if (scf_error() != SCF_ERROR_NOT_FOUND) 1235 scfdie(); 1236 1237 return (SCF_ERROR_NOT_FOUND); 1238 } 1239 1240 *ep = svc; 1241 *isservice = 1; 1242 } else { 1243 inst = scf_instance_create(h); 1244 if (inst == NULL) 1245 return (SCF_ERROR_NO_MEMORY); 1246 1247 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1248 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1249 if (scf_error() != SCF_ERROR_NOT_FOUND) 1250 scfdie(); 1251 1252 return (SCF_ERROR_NOT_FOUND); 1253 } 1254 1255 *ep = inst; 1256 *isservice = 0; 1257 } 1258 1259 return (SCF_ERROR_NONE); 1260 } 1261 1262 /* 1263 * Create the entity named by fmri. Place a pointer to its libscf handle in 1264 * *ep, and set or clear *isservicep if it is a service or an instance. 1265 * Returns 1266 * SCF_ERROR_NONE - success 1267 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1268 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1269 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1270 * SCF_ERROR_NOT_FOUND - no such scope 1271 * SCF_ERROR_PERMISSION_DENIED 1272 * SCF_ERROR_BACKEND_READONLY 1273 * SCF_ERROR_BACKEND_ACCESS 1274 */ 1275 static scf_error_t 1276 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1277 { 1278 char *fmri_copy; 1279 const char *scstr, *sstr, *istr, *pgstr; 1280 scf_scope_t *scope = NULL; 1281 scf_service_t *svc = NULL; 1282 scf_instance_t *inst = NULL; 1283 scf_error_t scfe; 1284 1285 fmri_copy = safe_strdup(fmri); 1286 1287 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1288 0) { 1289 free(fmri_copy); 1290 return (SCF_ERROR_INVALID_ARGUMENT); 1291 } 1292 1293 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1294 free(fmri_copy); 1295 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1296 } 1297 1298 *ep = NULL; 1299 1300 if ((scope = scf_scope_create(h)) == NULL || 1301 (svc = scf_service_create(h)) == NULL || 1302 (inst = scf_instance_create(h)) == NULL) { 1303 scfe = SCF_ERROR_NO_MEMORY; 1304 goto out; 1305 } 1306 1307 get_scope: 1308 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1309 switch (scf_error()) { 1310 case SCF_ERROR_CONNECTION_BROKEN: 1311 scfdie(); 1312 /* NOTREACHED */ 1313 1314 case SCF_ERROR_NOT_FOUND: 1315 scfe = SCF_ERROR_NOT_FOUND; 1316 goto out; 1317 1318 case SCF_ERROR_HANDLE_MISMATCH: 1319 case SCF_ERROR_NOT_BOUND: 1320 case SCF_ERROR_INVALID_ARGUMENT: 1321 default: 1322 bad_error("scf_handle_get_scope", scf_error()); 1323 } 1324 } 1325 1326 get_svc: 1327 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1328 switch (scf_error()) { 1329 case SCF_ERROR_CONNECTION_BROKEN: 1330 scfdie(); 1331 /* NOTREACHED */ 1332 1333 case SCF_ERROR_DELETED: 1334 goto get_scope; 1335 1336 case SCF_ERROR_NOT_FOUND: 1337 break; 1338 1339 case SCF_ERROR_HANDLE_MISMATCH: 1340 case SCF_ERROR_INVALID_ARGUMENT: 1341 case SCF_ERROR_NOT_BOUND: 1342 case SCF_ERROR_NOT_SET: 1343 default: 1344 bad_error("scf_scope_get_service", scf_error()); 1345 } 1346 1347 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1348 switch (scf_error()) { 1349 case SCF_ERROR_CONNECTION_BROKEN: 1350 scfdie(); 1351 /* NOTREACHED */ 1352 1353 case SCF_ERROR_DELETED: 1354 goto get_scope; 1355 1356 case SCF_ERROR_PERMISSION_DENIED: 1357 case SCF_ERROR_BACKEND_READONLY: 1358 case SCF_ERROR_BACKEND_ACCESS: 1359 scfe = scf_error(); 1360 goto out; 1361 1362 case SCF_ERROR_HANDLE_MISMATCH: 1363 case SCF_ERROR_INVALID_ARGUMENT: 1364 case SCF_ERROR_NOT_BOUND: 1365 case SCF_ERROR_NOT_SET: 1366 default: 1367 bad_error("scf_scope_get_service", scf_error()); 1368 } 1369 } 1370 } 1371 1372 if (istr == NULL) { 1373 scfe = SCF_ERROR_NONE; 1374 *ep = svc; 1375 *isservicep = 1; 1376 goto out; 1377 } 1378 1379 get_inst: 1380 if (scf_service_get_instance(svc, istr, inst) != 0) { 1381 switch (scf_error()) { 1382 case SCF_ERROR_CONNECTION_BROKEN: 1383 scfdie(); 1384 /* NOTREACHED */ 1385 1386 case SCF_ERROR_DELETED: 1387 goto get_svc; 1388 1389 case SCF_ERROR_NOT_FOUND: 1390 break; 1391 1392 case SCF_ERROR_HANDLE_MISMATCH: 1393 case SCF_ERROR_INVALID_ARGUMENT: 1394 case SCF_ERROR_NOT_BOUND: 1395 case SCF_ERROR_NOT_SET: 1396 default: 1397 bad_error("scf_service_get_instance", scf_error()); 1398 } 1399 1400 if (scf_service_add_instance(svc, istr, inst) != 0) { 1401 switch (scf_error()) { 1402 case SCF_ERROR_CONNECTION_BROKEN: 1403 scfdie(); 1404 /* NOTREACHED */ 1405 1406 case SCF_ERROR_DELETED: 1407 goto get_svc; 1408 1409 case SCF_ERROR_PERMISSION_DENIED: 1410 case SCF_ERROR_BACKEND_READONLY: 1411 case SCF_ERROR_BACKEND_ACCESS: 1412 scfe = scf_error(); 1413 goto out; 1414 1415 case SCF_ERROR_HANDLE_MISMATCH: 1416 case SCF_ERROR_INVALID_ARGUMENT: 1417 case SCF_ERROR_NOT_BOUND: 1418 case SCF_ERROR_NOT_SET: 1419 default: 1420 bad_error("scf_service_add_instance", 1421 scf_error()); 1422 } 1423 } 1424 } 1425 1426 scfe = SCF_ERROR_NONE; 1427 *ep = inst; 1428 *isservicep = 0; 1429 1430 out: 1431 if (*ep != inst) 1432 scf_instance_destroy(inst); 1433 if (*ep != svc) 1434 scf_service_destroy(svc); 1435 scf_scope_destroy(scope); 1436 free(fmri_copy); 1437 return (scfe); 1438 } 1439 1440 /* 1441 * Create or update a snapshot of inst. snap is a required scratch object. 1442 * 1443 * Returns 1444 * 0 - success 1445 * ECONNABORTED - repository connection broken 1446 * EPERM - permission denied 1447 * ENOSPC - configd is out of resources 1448 * ECANCELED - inst was deleted 1449 * -1 - unknown libscf error (message printed) 1450 */ 1451 static int 1452 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1453 { 1454 again: 1455 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1456 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1457 switch (scf_error()) { 1458 case SCF_ERROR_CONNECTION_BROKEN: 1459 case SCF_ERROR_PERMISSION_DENIED: 1460 case SCF_ERROR_NO_RESOURCES: 1461 return (scferror2errno(scf_error())); 1462 1463 case SCF_ERROR_NOT_SET: 1464 case SCF_ERROR_INVALID_ARGUMENT: 1465 default: 1466 bad_error("_scf_snapshot_take_attach", 1467 scf_error()); 1468 } 1469 } 1470 } else { 1471 switch (scf_error()) { 1472 case SCF_ERROR_NOT_FOUND: 1473 break; 1474 1475 case SCF_ERROR_DELETED: 1476 case SCF_ERROR_CONNECTION_BROKEN: 1477 return (scferror2errno(scf_error())); 1478 1479 case SCF_ERROR_HANDLE_MISMATCH: 1480 case SCF_ERROR_NOT_BOUND: 1481 case SCF_ERROR_INVALID_ARGUMENT: 1482 case SCF_ERROR_NOT_SET: 1483 default: 1484 bad_error("scf_instance_get_snapshot", scf_error()); 1485 } 1486 1487 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1488 switch (scf_error()) { 1489 case SCF_ERROR_EXISTS: 1490 goto again; 1491 1492 case SCF_ERROR_CONNECTION_BROKEN: 1493 case SCF_ERROR_NO_RESOURCES: 1494 case SCF_ERROR_PERMISSION_DENIED: 1495 return (scferror2errno(scf_error())); 1496 1497 default: 1498 scfwarn(); 1499 return (-1); 1500 1501 case SCF_ERROR_NOT_SET: 1502 case SCF_ERROR_INTERNAL: 1503 case SCF_ERROR_INVALID_ARGUMENT: 1504 case SCF_ERROR_HANDLE_MISMATCH: 1505 bad_error("_scf_snapshot_take_new", 1506 scf_error()); 1507 } 1508 } 1509 } 1510 1511 return (0); 1512 } 1513 1514 static int 1515 refresh_running_snapshot(void *entity) 1516 { 1517 scf_snapshot_t *snap; 1518 int r; 1519 1520 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1521 scfdie(); 1522 r = take_snap(entity, snap_running, snap); 1523 scf_snapshot_destroy(snap); 1524 1525 return (r); 1526 } 1527 1528 /* 1529 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1530 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1531 * instances. fmri is used for messages. inst, iter, and name_buf are used 1532 * for scratch space. Returns 1533 * 0 - success 1534 * ECONNABORTED - repository connection broken 1535 * ECANCELED - entity was deleted 1536 * EACCES - backend denied access 1537 * EPERM - permission denied 1538 * ENOSPC - repository server out of resources 1539 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1540 */ 1541 static int 1542 refresh_entity(int isservice, void *entity, const char *fmri, 1543 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1544 { 1545 scf_error_t scfe; 1546 int r; 1547 1548 if (!isservice) { 1549 /* 1550 * Let restarter handles refreshing and making new running 1551 * snapshot only if operating on a live repository and not 1552 * running in early import. 1553 */ 1554 if (est->sc_repo_filename == NULL && 1555 est->sc_repo_doorname == NULL && 1556 est->sc_in_emi == 0) { 1557 if (_smf_refresh_instance_i(entity) == 0) { 1558 if (g_verbose) 1559 warn(gettext("Refreshed %s.\n"), fmri); 1560 return (0); 1561 } 1562 1563 switch (scf_error()) { 1564 case SCF_ERROR_BACKEND_ACCESS: 1565 return (EACCES); 1566 1567 case SCF_ERROR_PERMISSION_DENIED: 1568 return (EPERM); 1569 1570 default: 1571 return (-1); 1572 } 1573 } else { 1574 r = refresh_running_snapshot(entity); 1575 switch (r) { 1576 case 0: 1577 break; 1578 1579 case ECONNABORTED: 1580 case ECANCELED: 1581 case EPERM: 1582 case ENOSPC: 1583 break; 1584 1585 default: 1586 bad_error("refresh_running_snapshot", 1587 scf_error()); 1588 } 1589 1590 return (r); 1591 } 1592 } 1593 1594 if (scf_iter_service_instances(iter, entity) != 0) { 1595 switch (scf_error()) { 1596 case SCF_ERROR_CONNECTION_BROKEN: 1597 return (ECONNABORTED); 1598 1599 case SCF_ERROR_DELETED: 1600 return (ECANCELED); 1601 1602 case SCF_ERROR_HANDLE_MISMATCH: 1603 case SCF_ERROR_NOT_BOUND: 1604 case SCF_ERROR_NOT_SET: 1605 default: 1606 bad_error("scf_iter_service_instances", scf_error()); 1607 } 1608 } 1609 1610 for (;;) { 1611 r = scf_iter_next_instance(iter, inst); 1612 if (r == 0) 1613 break; 1614 if (r != 1) { 1615 switch (scf_error()) { 1616 case SCF_ERROR_CONNECTION_BROKEN: 1617 return (ECONNABORTED); 1618 1619 case SCF_ERROR_DELETED: 1620 return (ECANCELED); 1621 1622 case SCF_ERROR_HANDLE_MISMATCH: 1623 case SCF_ERROR_NOT_BOUND: 1624 case SCF_ERROR_NOT_SET: 1625 case SCF_ERROR_INVALID_ARGUMENT: 1626 default: 1627 bad_error("scf_iter_next_instance", 1628 scf_error()); 1629 } 1630 } 1631 1632 /* 1633 * Similarly, just take a new running snapshot if operating on 1634 * a non-live repository or running during early import. 1635 */ 1636 if (est->sc_repo_filename != NULL || 1637 est->sc_repo_doorname != NULL || 1638 est->sc_in_emi == 1) { 1639 r = refresh_running_snapshot(inst); 1640 switch (r) { 1641 case 0: 1642 continue; 1643 1644 case ECONNABORTED: 1645 case ECANCELED: 1646 case EPERM: 1647 case ENOSPC: 1648 break; 1649 default: 1650 bad_error("refresh_running_snapshot", 1651 scf_error()); 1652 } 1653 1654 return (r); 1655 1656 } 1657 1658 if (_smf_refresh_instance_i(inst) == 0) { 1659 if (g_verbose) { 1660 if (scf_instance_get_name(inst, name_buf, 1661 max_scf_name_len + 1) < 0) 1662 (void) strcpy(name_buf, "?"); 1663 1664 warn(gettext("Refreshed %s:%s.\n"), 1665 fmri, name_buf); 1666 } 1667 } else { 1668 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1669 g_verbose) { 1670 scfe = scf_error(); 1671 1672 if (scf_instance_to_fmri(inst, name_buf, 1673 max_scf_name_len + 1) < 0) 1674 (void) strcpy(name_buf, "?"); 1675 1676 warn(gettext( 1677 "Refresh of %s:%s failed: %s.\n"), fmri, 1678 name_buf, scf_strerror(scfe)); 1679 } 1680 } 1681 } 1682 1683 return (0); 1684 } 1685 1686 static void 1687 private_refresh(void) 1688 { 1689 scf_instance_t *pinst = NULL; 1690 scf_iter_t *piter = NULL; 1691 ssize_t fmrilen; 1692 size_t bufsz; 1693 char *fmribuf; 1694 void *ent; 1695 int issvc; 1696 int r; 1697 1698 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1699 return; 1700 1701 assert(cur_svc != NULL); 1702 1703 bufsz = max_scf_fmri_len + 1; 1704 fmribuf = safe_malloc(bufsz); 1705 if (cur_inst) { 1706 issvc = 0; 1707 ent = cur_inst; 1708 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1709 } else { 1710 issvc = 1; 1711 ent = cur_svc; 1712 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1713 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1714 scfdie(); 1715 1716 if ((piter = scf_iter_create(g_hndl)) == NULL) 1717 scfdie(); 1718 } 1719 if (fmrilen < 0) { 1720 free(fmribuf); 1721 if (scf_error() != SCF_ERROR_DELETED) 1722 scfdie(); 1723 1724 warn(emsg_deleted); 1725 return; 1726 } 1727 assert(fmrilen < bufsz); 1728 1729 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1730 switch (r) { 1731 case 0: 1732 break; 1733 1734 case ECONNABORTED: 1735 warn(gettext("Could not refresh %s " 1736 "(repository connection broken).\n"), fmribuf); 1737 break; 1738 1739 case ECANCELED: 1740 warn(emsg_deleted); 1741 break; 1742 1743 case EPERM: 1744 warn(gettext("Could not refresh %s " 1745 "(permission denied).\n"), fmribuf); 1746 break; 1747 1748 case ENOSPC: 1749 warn(gettext("Could not refresh %s " 1750 "(repository server out of resources).\n"), 1751 fmribuf); 1752 break; 1753 1754 case EACCES: 1755 default: 1756 bad_error("refresh_entity", scf_error()); 1757 } 1758 1759 if (issvc) { 1760 scf_instance_destroy(pinst); 1761 scf_iter_destroy(piter); 1762 } 1763 1764 free(fmribuf); 1765 } 1766 1767 1768 static int 1769 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1770 { 1771 cbp->sc_err = scferror2errno(err); 1772 return (UU_WALK_ERROR); 1773 } 1774 1775 static int 1776 stash_scferror(scf_callback_t *cbp) 1777 { 1778 return (stash_scferror_err(cbp, scf_error())); 1779 } 1780 1781 static int select_inst(const char *); 1782 static int select_svc(const char *); 1783 1784 /* 1785 * Take a property that does not have a type and check to see if a type 1786 * exists or can be gleened from the current data. Set the type. 1787 * 1788 * Check the current level (instance) and then check the higher level 1789 * (service). This could be the case for adding a new property to 1790 * the instance that's going to "override" a service level property. 1791 * 1792 * For a property : 1793 * 1. Take the type from an existing property 1794 * 2. Take the type from a template entry 1795 * 1796 * If the type can not be found, then leave the type as is, and let the import 1797 * report the problem of the missing type. 1798 */ 1799 static int 1800 find_current_prop_type(void *p, void *g) 1801 { 1802 property_t *prop = p; 1803 scf_callback_t *lcb = g; 1804 pgroup_t *pg = NULL; 1805 1806 const char *fmri = NULL; 1807 char *lfmri = NULL; 1808 char *cur_selection = NULL; 1809 1810 scf_propertygroup_t *sc_pg = NULL; 1811 scf_property_t *sc_prop = NULL; 1812 scf_pg_tmpl_t *t_pg = NULL; 1813 scf_prop_tmpl_t *t_prop = NULL; 1814 scf_type_t prop_type; 1815 1816 value_t *vp; 1817 int issvc = lcb->sc_service; 1818 int r = UU_WALK_ERROR; 1819 1820 if (prop->sc_value_type != SCF_TYPE_INVALID) 1821 return (UU_WALK_NEXT); 1822 1823 t_prop = scf_tmpl_prop_create(g_hndl); 1824 sc_prop = scf_property_create(g_hndl); 1825 if (sc_prop == NULL || t_prop == NULL) { 1826 warn(gettext("Unable to create the property to attempt and " 1827 "find a missing type.\n")); 1828 1829 scf_property_destroy(sc_prop); 1830 scf_tmpl_prop_destroy(t_prop); 1831 1832 return (UU_WALK_ERROR); 1833 } 1834 1835 if (lcb->sc_flags == 1) { 1836 pg = lcb->sc_parent; 1837 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT); 1838 fmri = pg->sc_parent->sc_fmri; 1839 retry_pg: 1840 if (cur_svc && cur_selection == NULL) { 1841 cur_selection = safe_malloc(max_scf_fmri_len + 1); 1842 lscf_get_selection_str(cur_selection, 1843 max_scf_fmri_len + 1); 1844 1845 if (strcmp(cur_selection, fmri) != 0) { 1846 lscf_select(fmri); 1847 } else { 1848 free(cur_selection); 1849 cur_selection = NULL; 1850 } 1851 } else { 1852 lscf_select(fmri); 1853 } 1854 1855 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) { 1856 warn(gettext("Unable to create property group to " 1857 "find a missing property type.\n")); 1858 1859 goto out; 1860 } 1861 1862 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) { 1863 /* 1864 * If this is the sc_pg from the parent 1865 * let the caller clean up the sc_pg, 1866 * and just throw it away in this case. 1867 */ 1868 if (sc_pg != lcb->sc_parent) 1869 scf_pg_destroy(sc_pg); 1870 1871 sc_pg = NULL; 1872 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1873 warn(gettext("Unable to create template " 1874 "property group to find a property " 1875 "type.\n")); 1876 1877 goto out; 1878 } 1879 1880 if (scf_tmpl_get_by_pg_name(fmri, NULL, 1881 pg->sc_pgroup_name, NULL, t_pg, 1882 SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) { 1883 /* 1884 * if instance get service and jump back 1885 */ 1886 scf_tmpl_pg_destroy(t_pg); 1887 t_pg = NULL; 1888 if (issvc == 0) { 1889 entity_t *e = pg->sc_parent->sc_parent; 1890 1891 fmri = e->sc_fmri; 1892 issvc = 1; 1893 goto retry_pg; 1894 } else { 1895 goto out; 1896 } 1897 } 1898 } 1899 } else { 1900 sc_pg = lcb->sc_parent; 1901 } 1902 1903 /* 1904 * Attempt to get the type from an existing property. If the property 1905 * cannot be found then attempt to get the type from a template entry 1906 * for the property. 1907 * 1908 * Finally, if at the instance level look at the service level. 1909 */ 1910 if (sc_pg != NULL && 1911 pg_get_prop(sc_pg, prop->sc_property_name, 1912 sc_prop) == SCF_SUCCESS && 1913 scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) { 1914 prop->sc_value_type = prop_type; 1915 1916 /* 1917 * Found a type, update the value types and validate 1918 * the actual value against this type. 1919 */ 1920 for (vp = uu_list_first(prop->sc_property_values); 1921 vp != NULL; 1922 vp = uu_list_next(prop->sc_property_values, vp)) { 1923 vp->sc_type = prop->sc_value_type; 1924 lxml_store_value(vp, 0, NULL); 1925 } 1926 1927 r = UU_WALK_NEXT; 1928 goto out; 1929 } 1930 1931 /* 1932 * If we get here with t_pg set to NULL then we had to have 1933 * gotten an sc_pg but that sc_pg did not have the property 1934 * we are looking for. So if the t_pg is not null look up 1935 * the template entry for the property. 1936 * 1937 * If the t_pg is null then need to attempt to get a matching 1938 * template entry for the sc_pg, and see if there is a property 1939 * entry for that template entry. 1940 */ 1941 do_tmpl : 1942 if (t_pg != NULL && 1943 scf_tmpl_get_by_prop(t_pg, prop->sc_property_name, 1944 t_prop, 0) == SCF_SUCCESS) { 1945 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) { 1946 prop->sc_value_type = prop_type; 1947 1948 /* 1949 * Found a type, update the value types and validate 1950 * the actual value against this type. 1951 */ 1952 for (vp = uu_list_first(prop->sc_property_values); 1953 vp != NULL; 1954 vp = uu_list_next(prop->sc_property_values, vp)) { 1955 vp->sc_type = prop->sc_value_type; 1956 lxml_store_value(vp, 0, NULL); 1957 } 1958 1959 r = UU_WALK_NEXT; 1960 goto out; 1961 } 1962 } else { 1963 if (t_pg == NULL && sc_pg) { 1964 if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) { 1965 warn(gettext("Unable to create template " 1966 "property group to find a property " 1967 "type.\n")); 1968 1969 goto out; 1970 } 1971 1972 if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) { 1973 scf_tmpl_pg_destroy(t_pg); 1974 t_pg = NULL; 1975 } else { 1976 goto do_tmpl; 1977 } 1978 } 1979 } 1980 1981 if (issvc == 0) { 1982 scf_instance_t *i; 1983 scf_service_t *s; 1984 1985 issvc = 1; 1986 if (lcb->sc_flags == 1) { 1987 entity_t *e = pg->sc_parent->sc_parent; 1988 1989 fmri = e->sc_fmri; 1990 goto retry_pg; 1991 } 1992 1993 /* 1994 * because lcb->sc_flags was not set then this means 1995 * the pg was not used and can be used here. 1996 */ 1997 if ((pg = internal_pgroup_new()) == NULL) { 1998 warn(gettext("Could not create internal property group " 1999 "to find a missing type.")); 2000 2001 goto out; 2002 } 2003 2004 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1); 2005 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name, 2006 max_scf_name_len + 1) < 0) 2007 goto out; 2008 2009 i = scf_instance_create(g_hndl); 2010 s = scf_service_create(g_hndl); 2011 if (i == NULL || s == NULL || 2012 scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) { 2013 warn(gettext("Could not get a service for the instance " 2014 "to find a missing type.")); 2015 2016 goto out; 2017 } 2018 2019 /* 2020 * Check to see truly at the instance level. 2021 */ 2022 lfmri = safe_malloc(max_scf_fmri_len + 1); 2023 if (scf_instance_get_parent(i, s) == SCF_SUCCESS && 2024 scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0) 2025 goto out; 2026 else 2027 fmri = (const char *)lfmri; 2028 2029 goto retry_pg; 2030 } 2031 2032 out : 2033 if (sc_pg != lcb->sc_parent) { 2034 scf_pg_destroy(sc_pg); 2035 } 2036 2037 /* 2038 * If this is true then the pg was allocated 2039 * here, and the name was set so need to free 2040 * the name and the pg. 2041 */ 2042 if (pg != NULL && pg != lcb->sc_parent) { 2043 free((char *)pg->sc_pgroup_name); 2044 internal_pgroup_free(pg); 2045 } 2046 2047 if (cur_selection) { 2048 lscf_select(cur_selection); 2049 free(cur_selection); 2050 } 2051 2052 scf_tmpl_pg_destroy(t_pg); 2053 scf_tmpl_prop_destroy(t_prop); 2054 scf_property_destroy(sc_prop); 2055 2056 if (r != UU_WALK_NEXT) 2057 warn(gettext("Could not find property type for \"%s\" " 2058 "from \"%s\"\n"), prop->sc_property_name, 2059 fmri != NULL ? fmri : lcb->sc_source_fmri); 2060 2061 free(lfmri); 2062 2063 return (r); 2064 } 2065 2066 /* 2067 * Take a property group that does not have a type and check to see if a type 2068 * exists or can be gleened from the current data. Set the type. 2069 * 2070 * Check the current level (instance) and then check the higher level 2071 * (service). This could be the case for adding a new property to 2072 * the instance that's going to "override" a service level property. 2073 * 2074 * For a property group 2075 * 1. Take the type from an existing property group 2076 * 2. Take the type from a template entry 2077 * 2078 * If the type can not be found, then leave the type as is, and let the import 2079 * report the problem of the missing type. 2080 */ 2081 static int 2082 find_current_pg_type(void *p, void *sori) 2083 { 2084 entity_t *si = sori; 2085 pgroup_t *pg = p; 2086 2087 const char *ofmri, *fmri; 2088 char *cur_selection = NULL; 2089 char *pg_type = NULL; 2090 2091 scf_propertygroup_t *sc_pg = NULL; 2092 scf_pg_tmpl_t *t_pg = NULL; 2093 2094 int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2095 int r = UU_WALK_ERROR; 2096 2097 ofmri = fmri = si->sc_fmri; 2098 if (pg->sc_pgroup_type != NULL) { 2099 r = UU_WALK_NEXT; 2100 2101 goto out; 2102 } 2103 2104 sc_pg = scf_pg_create(g_hndl); 2105 if (sc_pg == NULL) { 2106 warn(gettext("Unable to create property group to attempt " 2107 "and find a missing type.\n")); 2108 2109 return (UU_WALK_ERROR); 2110 } 2111 2112 /* 2113 * Using get_pg() requires that the cur_svc/cur_inst be 2114 * via lscf_select. Need to preserve the current selection 2115 * if going to use lscf_select() to set up the cur_svc/cur_inst 2116 */ 2117 if (cur_svc) { 2118 cur_selection = safe_malloc(max_scf_fmri_len + 1); 2119 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1); 2120 } 2121 2122 /* 2123 * If the property group exists get the type, and set 2124 * the pgroup_t type of that type. 2125 * 2126 * If not the check for a template pg_pattern entry 2127 * and take the type from that. 2128 */ 2129 retry_svc: 2130 lscf_select(fmri); 2131 2132 if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) { 2133 pg_type = safe_malloc(max_scf_pg_type_len + 1); 2134 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type, 2135 max_scf_pg_type_len + 1) != -1) { 2136 pg->sc_pgroup_type = pg_type; 2137 2138 r = UU_WALK_NEXT; 2139 goto out; 2140 } else { 2141 free(pg_type); 2142 } 2143 } else { 2144 if ((t_pg == NULL) && 2145 (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) 2146 goto out; 2147 2148 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name, 2149 NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS && 2150 scf_tmpl_pg_type(t_pg, &pg_type) != -1) { 2151 pg->sc_pgroup_type = pg_type; 2152 2153 r = UU_WALK_NEXT; 2154 goto out; 2155 } 2156 } 2157 2158 /* 2159 * If type is not found at the instance level then attempt to 2160 * find the type at the service level. 2161 */ 2162 if (!issvc) { 2163 si = si->sc_parent; 2164 fmri = si->sc_fmri; 2165 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT); 2166 goto retry_svc; 2167 } 2168 2169 out : 2170 if (cur_selection) { 2171 lscf_select(cur_selection); 2172 free(cur_selection); 2173 } 2174 2175 /* 2176 * Now walk the properties of the property group to make sure that 2177 * all properties have the correct type and values are valid for 2178 * those types. 2179 */ 2180 if (r == UU_WALK_NEXT) { 2181 scf_callback_t cb; 2182 2183 cb.sc_service = issvc; 2184 cb.sc_source_fmri = ofmri; 2185 if (sc_pg != NULL) { 2186 cb.sc_parent = sc_pg; 2187 cb.sc_flags = 0; 2188 } else { 2189 cb.sc_parent = pg; 2190 cb.sc_flags = 1; 2191 } 2192 2193 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type, 2194 &cb, UU_DEFAULT) != 0) { 2195 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2196 bad_error("uu_list_walk", uu_error()); 2197 2198 r = UU_WALK_ERROR; 2199 } 2200 } else { 2201 warn(gettext("Could not find property group type for " 2202 "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri); 2203 } 2204 2205 scf_tmpl_pg_destroy(t_pg); 2206 scf_pg_destroy(sc_pg); 2207 2208 return (r); 2209 } 2210 2211 /* 2212 * Import. These functions import a bundle into the repository. 2213 */ 2214 2215 /* 2216 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 2217 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 2218 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2219 * lcbdata->sc_err to 2220 * ENOMEM - out of memory 2221 * ECONNABORTED - repository connection broken 2222 * ECANCELED - sc_trans's property group was deleted 2223 * EINVAL - p's name is invalid (error printed) 2224 * - p has an invalid value (error printed) 2225 */ 2226 static int 2227 lscf_property_import(void *v, void *pvt) 2228 { 2229 property_t *p = v; 2230 scf_callback_t *lcbdata = pvt; 2231 value_t *vp; 2232 scf_transaction_t *trans = lcbdata->sc_trans; 2233 scf_transaction_entry_t *entr; 2234 scf_value_t *val; 2235 scf_type_t tp; 2236 2237 if ((lcbdata->sc_flags & SCI_NOENABLED || 2238 lcbdata->sc_flags & SCI_DELAYENABLE) && 2239 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 2240 lcbdata->sc_enable = p; 2241 return (UU_WALK_NEXT); 2242 } 2243 2244 entr = scf_entry_create(lcbdata->sc_handle); 2245 if (entr == NULL) { 2246 switch (scf_error()) { 2247 case SCF_ERROR_NO_MEMORY: 2248 return (stash_scferror(lcbdata)); 2249 2250 case SCF_ERROR_INVALID_ARGUMENT: 2251 default: 2252 bad_error("scf_entry_create", scf_error()); 2253 } 2254 } 2255 2256 tp = p->sc_value_type; 2257 2258 if (scf_transaction_property_new(trans, entr, 2259 p->sc_property_name, tp) != 0) { 2260 switch (scf_error()) { 2261 case SCF_ERROR_INVALID_ARGUMENT: 2262 semerr(emsg_invalid_prop_name, p->sc_property_name); 2263 scf_entry_destroy(entr); 2264 return (stash_scferror(lcbdata)); 2265 2266 case SCF_ERROR_EXISTS: 2267 break; 2268 2269 case SCF_ERROR_DELETED: 2270 case SCF_ERROR_CONNECTION_BROKEN: 2271 scf_entry_destroy(entr); 2272 return (stash_scferror(lcbdata)); 2273 2274 case SCF_ERROR_NOT_BOUND: 2275 case SCF_ERROR_HANDLE_MISMATCH: 2276 case SCF_ERROR_NOT_SET: 2277 default: 2278 bad_error("scf_transaction_property_new", scf_error()); 2279 } 2280 2281 if (scf_transaction_property_change_type(trans, entr, 2282 p->sc_property_name, tp) != 0) { 2283 switch (scf_error()) { 2284 case SCF_ERROR_DELETED: 2285 case SCF_ERROR_CONNECTION_BROKEN: 2286 scf_entry_destroy(entr); 2287 return (stash_scferror(lcbdata)); 2288 2289 case SCF_ERROR_INVALID_ARGUMENT: 2290 semerr(emsg_invalid_prop_name, 2291 p->sc_property_name); 2292 scf_entry_destroy(entr); 2293 return (stash_scferror(lcbdata)); 2294 2295 case SCF_ERROR_NOT_FOUND: 2296 case SCF_ERROR_NOT_SET: 2297 case SCF_ERROR_HANDLE_MISMATCH: 2298 case SCF_ERROR_NOT_BOUND: 2299 default: 2300 bad_error( 2301 "scf_transaction_property_change_type", 2302 scf_error()); 2303 } 2304 } 2305 } 2306 2307 for (vp = uu_list_first(p->sc_property_values); 2308 vp != NULL; 2309 vp = uu_list_next(p->sc_property_values, vp)) { 2310 val = scf_value_create(g_hndl); 2311 if (val == NULL) { 2312 switch (scf_error()) { 2313 case SCF_ERROR_NO_MEMORY: 2314 return (stash_scferror(lcbdata)); 2315 2316 case SCF_ERROR_INVALID_ARGUMENT: 2317 default: 2318 bad_error("scf_value_create", scf_error()); 2319 } 2320 } 2321 2322 switch (tp) { 2323 case SCF_TYPE_BOOLEAN: 2324 scf_value_set_boolean(val, vp->sc_u.sc_count); 2325 break; 2326 case SCF_TYPE_COUNT: 2327 scf_value_set_count(val, vp->sc_u.sc_count); 2328 break; 2329 case SCF_TYPE_INTEGER: 2330 scf_value_set_integer(val, vp->sc_u.sc_integer); 2331 break; 2332 default: 2333 assert(vp->sc_u.sc_string != NULL); 2334 if (scf_value_set_from_string(val, tp, 2335 vp->sc_u.sc_string) != 0) { 2336 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 2337 bad_error("scf_value_set_from_string", 2338 scf_error()); 2339 2340 warn(gettext("Value \"%s\" is not a valid " 2341 "%s.\n"), vp->sc_u.sc_string, 2342 scf_type_to_string(tp)); 2343 scf_value_destroy(val); 2344 return (stash_scferror(lcbdata)); 2345 } 2346 break; 2347 } 2348 2349 if (scf_entry_add_value(entr, val) != 0) 2350 bad_error("scf_entry_add_value", scf_error()); 2351 } 2352 2353 return (UU_WALK_NEXT); 2354 } 2355 2356 /* 2357 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 2358 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 2359 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 2360 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 2361 * lcbdata->sc_err to 2362 * ECONNABORTED - repository connection broken 2363 * ENOMEM - out of memory 2364 * ENOSPC - svc.configd is out of resources 2365 * ECANCELED - sc_parent was deleted 2366 * EPERM - could not create property group (permission denied) (error printed) 2367 * - could not modify property group (permission denied) (error printed) 2368 * - could not delete property group (permission denied) (error printed) 2369 * EROFS - could not create property group (repository is read-only) 2370 * - could not delete property group (repository is read-only) 2371 * EACCES - could not create property group (backend access denied) 2372 * - could not delete property group (backend access denied) 2373 * EEXIST - could not create property group (already exists) 2374 * EINVAL - invalid property group name (error printed) 2375 * - invalid property name (error printed) 2376 * - invalid value (error printed) 2377 * EBUSY - new property group deleted (error printed) 2378 * - new property group changed (error printed) 2379 * - property group added (error printed) 2380 * - property group deleted (error printed) 2381 */ 2382 static int 2383 entity_pgroup_import(void *v, void *pvt) 2384 { 2385 pgroup_t *p = v; 2386 scf_callback_t cbdata; 2387 scf_callback_t *lcbdata = pvt; 2388 void *ent = lcbdata->sc_parent; 2389 int issvc = lcbdata->sc_service; 2390 int r; 2391 2392 const char * const pg_changed = gettext("%s changed unexpectedly " 2393 "(new property group \"%s\" changed).\n"); 2394 2395 /* Never import deleted property groups. */ 2396 if (p->sc_pgroup_delete) { 2397 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY && 2398 entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) { 2399 goto delete_pg; 2400 } 2401 return (UU_WALK_NEXT); 2402 } 2403 2404 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 2405 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 2406 lcbdata->sc_general = p; 2407 return (UU_WALK_NEXT); 2408 } 2409 2410 add_pg: 2411 if (issvc) 2412 r = scf_service_add_pg(ent, p->sc_pgroup_name, 2413 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2414 else 2415 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 2416 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 2417 if (r != 0) { 2418 switch (scf_error()) { 2419 case SCF_ERROR_DELETED: 2420 case SCF_ERROR_CONNECTION_BROKEN: 2421 case SCF_ERROR_BACKEND_READONLY: 2422 case SCF_ERROR_BACKEND_ACCESS: 2423 case SCF_ERROR_NO_RESOURCES: 2424 return (stash_scferror(lcbdata)); 2425 2426 case SCF_ERROR_EXISTS: 2427 if (lcbdata->sc_flags & SCI_FORCE) 2428 break; 2429 return (stash_scferror(lcbdata)); 2430 2431 case SCF_ERROR_INVALID_ARGUMENT: 2432 warn(emsg_fmri_invalid_pg_name_type, 2433 lcbdata->sc_source_fmri, 2434 p->sc_pgroup_name, p->sc_pgroup_type); 2435 return (stash_scferror(lcbdata)); 2436 2437 case SCF_ERROR_PERMISSION_DENIED: 2438 warn(emsg_pg_add_perm, p->sc_pgroup_name, 2439 lcbdata->sc_target_fmri); 2440 return (stash_scferror(lcbdata)); 2441 2442 case SCF_ERROR_NOT_BOUND: 2443 case SCF_ERROR_HANDLE_MISMATCH: 2444 case SCF_ERROR_NOT_SET: 2445 default: 2446 bad_error("scf_service_add_pg", scf_error()); 2447 } 2448 2449 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2450 switch (scf_error()) { 2451 case SCF_ERROR_CONNECTION_BROKEN: 2452 case SCF_ERROR_DELETED: 2453 return (stash_scferror(lcbdata)); 2454 2455 case SCF_ERROR_INVALID_ARGUMENT: 2456 warn(emsg_fmri_invalid_pg_name, 2457 lcbdata->sc_source_fmri, 2458 p->sc_pgroup_name); 2459 return (stash_scferror(lcbdata)); 2460 2461 case SCF_ERROR_NOT_FOUND: 2462 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2463 p->sc_pgroup_name); 2464 lcbdata->sc_err = EBUSY; 2465 return (UU_WALK_ERROR); 2466 2467 case SCF_ERROR_NOT_BOUND: 2468 case SCF_ERROR_HANDLE_MISMATCH: 2469 case SCF_ERROR_NOT_SET: 2470 default: 2471 bad_error("entity_get_pg", scf_error()); 2472 } 2473 } 2474 2475 if (lcbdata->sc_flags & SCI_KEEP) 2476 goto props; 2477 2478 delete_pg: 2479 if (scf_pg_delete(imp_pg) != 0) { 2480 switch (scf_error()) { 2481 case SCF_ERROR_DELETED: 2482 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2483 p->sc_pgroup_name); 2484 lcbdata->sc_err = EBUSY; 2485 return (UU_WALK_ERROR); 2486 2487 case SCF_ERROR_PERMISSION_DENIED: 2488 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2489 lcbdata->sc_target_fmri); 2490 return (stash_scferror(lcbdata)); 2491 2492 case SCF_ERROR_BACKEND_READONLY: 2493 case SCF_ERROR_BACKEND_ACCESS: 2494 case SCF_ERROR_CONNECTION_BROKEN: 2495 return (stash_scferror(lcbdata)); 2496 2497 case SCF_ERROR_NOT_SET: 2498 default: 2499 bad_error("scf_pg_delete", scf_error()); 2500 } 2501 } 2502 2503 if (p->sc_pgroup_delete) 2504 return (UU_WALK_NEXT); 2505 2506 goto add_pg; 2507 } 2508 2509 props: 2510 2511 /* 2512 * Add properties to property group, if any. 2513 */ 2514 cbdata.sc_handle = lcbdata->sc_handle; 2515 cbdata.sc_parent = imp_pg; 2516 cbdata.sc_flags = lcbdata->sc_flags; 2517 cbdata.sc_trans = imp_tx; 2518 cbdata.sc_enable = NULL; 2519 2520 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2521 switch (scf_error()) { 2522 case SCF_ERROR_BACKEND_ACCESS: 2523 case SCF_ERROR_BACKEND_READONLY: 2524 case SCF_ERROR_CONNECTION_BROKEN: 2525 return (stash_scferror(lcbdata)); 2526 2527 case SCF_ERROR_DELETED: 2528 warn(pg_changed, lcbdata->sc_target_fmri, 2529 p->sc_pgroup_name); 2530 lcbdata->sc_err = EBUSY; 2531 return (UU_WALK_ERROR); 2532 2533 case SCF_ERROR_PERMISSION_DENIED: 2534 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2535 lcbdata->sc_target_fmri); 2536 return (stash_scferror(lcbdata)); 2537 2538 case SCF_ERROR_NOT_BOUND: 2539 case SCF_ERROR_NOT_SET: 2540 case SCF_ERROR_IN_USE: 2541 case SCF_ERROR_HANDLE_MISMATCH: 2542 default: 2543 bad_error("scf_transaction_start", scf_error()); 2544 } 2545 } 2546 2547 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2548 UU_DEFAULT) != 0) { 2549 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2550 bad_error("uu_list_walk", uu_error()); 2551 scf_transaction_reset(imp_tx); 2552 2553 lcbdata->sc_err = cbdata.sc_err; 2554 if (cbdata.sc_err == ECANCELED) { 2555 warn(pg_changed, lcbdata->sc_target_fmri, 2556 p->sc_pgroup_name); 2557 lcbdata->sc_err = EBUSY; 2558 } 2559 return (UU_WALK_ERROR); 2560 } 2561 2562 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2563 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2564 2565 /* 2566 * take the snapshot running snapshot then 2567 * import the stored general/enable property 2568 */ 2569 r = take_snap(ent, snap_running, imp_rsnap); 2570 switch (r) { 2571 case 0: 2572 break; 2573 2574 case ECONNABORTED: 2575 warn(gettext("Could not take %s snapshot on import " 2576 "(repository connection broken).\n"), 2577 snap_running); 2578 lcbdata->sc_err = r; 2579 return (UU_WALK_ERROR); 2580 case ECANCELED: 2581 warn(emsg_deleted); 2582 lcbdata->sc_err = r; 2583 return (UU_WALK_ERROR); 2584 2585 case EPERM: 2586 warn(gettext("Could not take %s snapshot " 2587 "(permission denied).\n"), snap_running); 2588 lcbdata->sc_err = r; 2589 return (UU_WALK_ERROR); 2590 2591 case ENOSPC: 2592 warn(gettext("Could not take %s snapshot" 2593 "(repository server out of resources).\n"), 2594 snap_running); 2595 lcbdata->sc_err = r; 2596 return (UU_WALK_ERROR); 2597 2598 default: 2599 bad_error("take_snap", r); 2600 } 2601 2602 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2603 if (r != UU_WALK_NEXT) { 2604 if (r != UU_WALK_ERROR) 2605 bad_error("lscf_property_import", r); 2606 return (EINVAL); 2607 } 2608 } 2609 2610 r = scf_transaction_commit(imp_tx); 2611 switch (r) { 2612 case 1: 2613 r = UU_WALK_NEXT; 2614 break; 2615 2616 case 0: 2617 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2618 lcbdata->sc_err = EBUSY; 2619 r = UU_WALK_ERROR; 2620 break; 2621 2622 case -1: 2623 switch (scf_error()) { 2624 case SCF_ERROR_BACKEND_READONLY: 2625 case SCF_ERROR_BACKEND_ACCESS: 2626 case SCF_ERROR_CONNECTION_BROKEN: 2627 case SCF_ERROR_NO_RESOURCES: 2628 r = stash_scferror(lcbdata); 2629 break; 2630 2631 case SCF_ERROR_DELETED: 2632 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2633 p->sc_pgroup_name); 2634 lcbdata->sc_err = EBUSY; 2635 r = UU_WALK_ERROR; 2636 break; 2637 2638 case SCF_ERROR_PERMISSION_DENIED: 2639 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2640 lcbdata->sc_target_fmri); 2641 r = stash_scferror(lcbdata); 2642 break; 2643 2644 case SCF_ERROR_NOT_SET: 2645 case SCF_ERROR_INVALID_ARGUMENT: 2646 case SCF_ERROR_NOT_BOUND: 2647 default: 2648 bad_error("scf_transaction_commit", scf_error()); 2649 } 2650 break; 2651 2652 default: 2653 bad_error("scf_transaction_commit", r); 2654 } 2655 2656 scf_transaction_destroy_children(imp_tx); 2657 2658 return (r); 2659 } 2660 2661 /* 2662 * Returns 2663 * 0 - success 2664 * ECONNABORTED - repository connection broken 2665 * ENOMEM - out of memory 2666 * ENOSPC - svc.configd is out of resources 2667 * ECANCELED - inst was deleted 2668 * EPERM - could not create property group (permission denied) (error printed) 2669 * - could not modify property group (permission denied) (error printed) 2670 * EROFS - could not create property group (repository is read-only) 2671 * EACCES - could not create property group (backend access denied) 2672 * EEXIST - could not create property group (already exists) 2673 * EINVAL - invalid property group name (error printed) 2674 * - invalid property name (error printed) 2675 * - invalid value (error printed) 2676 * EBUSY - new property group changed (error printed) 2677 */ 2678 static int 2679 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2680 const entity_t *isvc, int flags) 2681 { 2682 scf_callback_t cbdata; 2683 2684 cbdata.sc_handle = scf_service_handle(svc); 2685 cbdata.sc_parent = svc; 2686 cbdata.sc_service = 1; 2687 cbdata.sc_general = 0; 2688 cbdata.sc_enable = 0; 2689 cbdata.sc_flags = flags; 2690 cbdata.sc_source_fmri = isvc->sc_fmri; 2691 cbdata.sc_target_fmri = target_fmri; 2692 2693 /* 2694 * If the op is set, then add the flag to the callback 2695 * flags for later use. 2696 */ 2697 if (isvc->sc_op != SVCCFG_OP_NONE) { 2698 switch (isvc->sc_op) { 2699 case SVCCFG_OP_IMPORT : 2700 cbdata.sc_flags |= SCI_OP_IMPORT; 2701 break; 2702 case SVCCFG_OP_APPLY : 2703 cbdata.sc_flags |= SCI_OP_APPLY; 2704 break; 2705 case SVCCFG_OP_RESTORE : 2706 cbdata.sc_flags |= SCI_OP_RESTORE; 2707 break; 2708 default : 2709 uu_die(gettext("lscf_import_service_pgs : " 2710 "Unknown op stored in the service entity\n")); 2711 2712 } 2713 } 2714 2715 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2716 UU_DEFAULT) != 0) { 2717 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2718 bad_error("uu_list_walk", uu_error()); 2719 2720 return (cbdata.sc_err); 2721 } 2722 2723 return (0); 2724 } 2725 2726 /* 2727 * Returns 2728 * 0 - success 2729 * ECONNABORTED - repository connection broken 2730 * ENOMEM - out of memory 2731 * ENOSPC - svc.configd is out of resources 2732 * ECANCELED - inst was deleted 2733 * EPERM - could not create property group (permission denied) (error printed) 2734 * - could not modify property group (permission denied) (error printed) 2735 * EROFS - could not create property group (repository is read-only) 2736 * EACCES - could not create property group (backend access denied) 2737 * EEXIST - could not create property group (already exists) 2738 * EINVAL - invalid property group name (error printed) 2739 * - invalid property name (error printed) 2740 * - invalid value (error printed) 2741 * EBUSY - new property group changed (error printed) 2742 */ 2743 static int 2744 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2745 const entity_t *iinst, int flags) 2746 { 2747 scf_callback_t cbdata; 2748 2749 cbdata.sc_handle = scf_instance_handle(inst); 2750 cbdata.sc_parent = inst; 2751 cbdata.sc_service = 0; 2752 cbdata.sc_general = NULL; 2753 cbdata.sc_enable = NULL; 2754 cbdata.sc_flags = flags; 2755 cbdata.sc_source_fmri = iinst->sc_fmri; 2756 cbdata.sc_target_fmri = target_fmri; 2757 2758 /* 2759 * If the op is set, then add the flag to the callback 2760 * flags for later use. 2761 */ 2762 if (iinst->sc_op != SVCCFG_OP_NONE) { 2763 switch (iinst->sc_op) { 2764 case SVCCFG_OP_IMPORT : 2765 cbdata.sc_flags |= SCI_OP_IMPORT; 2766 break; 2767 case SVCCFG_OP_APPLY : 2768 cbdata.sc_flags |= SCI_OP_APPLY; 2769 break; 2770 case SVCCFG_OP_RESTORE : 2771 cbdata.sc_flags |= SCI_OP_RESTORE; 2772 break; 2773 default : 2774 uu_die(gettext("lscf_import_instance_pgs : " 2775 "Unknown op stored in the instance entity\n")); 2776 } 2777 } 2778 2779 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2780 UU_DEFAULT) != 0) { 2781 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2782 bad_error("uu_list_walk", uu_error()); 2783 2784 return (cbdata.sc_err); 2785 } 2786 2787 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2788 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2789 /* 2790 * If importing with the SCI_NOENABLED flag then 2791 * skip the delay, but if not then add the delay 2792 * of the enable property. 2793 */ 2794 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2795 cbdata.sc_flags |= SCI_DELAYENABLE; 2796 } 2797 2798 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2799 != UU_WALK_NEXT) 2800 return (cbdata.sc_err); 2801 } 2802 2803 return (0); 2804 } 2805 2806 /* 2807 * Report the reasons why we can't upgrade pg2 to pg1. 2808 */ 2809 static void 2810 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2811 int new) 2812 { 2813 property_t *p1, *p2; 2814 2815 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2816 2817 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2818 return; 2819 2820 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2821 p1 != NULL; 2822 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2823 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2824 if (p2 != NULL) { 2825 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2826 new); 2827 continue; 2828 } 2829 2830 if (new) 2831 warn(gettext("Conflict upgrading %s (new property " 2832 "group \"%s\" is missing property \"%s\").\n"), 2833 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2834 else 2835 warn(gettext("Conflict upgrading %s (property " 2836 "\"%s/%s\" is missing).\n"), fmri, 2837 pg1->sc_pgroup_name, p1->sc_property_name); 2838 } 2839 2840 /* 2841 * Since pg1 should be from the manifest, any properties in pg2 which 2842 * aren't in pg1 shouldn't be reported as conflicts. 2843 */ 2844 } 2845 2846 /* 2847 * Add transaction entries to tx which will upgrade cur's pg according to old 2848 * & new. 2849 * 2850 * Returns 2851 * 0 - success 2852 * EINVAL - new has a property with an invalid name or value (message emitted) 2853 * ENOMEM - out of memory 2854 */ 2855 static int 2856 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2857 pgroup_t *cur, int speak, const char *fmri) 2858 { 2859 property_t *p, *new_p, *cur_p; 2860 scf_transaction_entry_t *e; 2861 int r; 2862 int is_general; 2863 int is_protected; 2864 2865 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2866 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2867 bad_error("uu_list_walk", uu_error()); 2868 2869 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2870 2871 for (p = uu_list_first(old->sc_pgroup_props); 2872 p != NULL; 2873 p = uu_list_next(old->sc_pgroup_props, p)) { 2874 /* p is a property in the old property group. */ 2875 2876 /* Protect live properties. */ 2877 is_protected = 0; 2878 if (is_general) { 2879 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2880 0 || 2881 strcmp(p->sc_property_name, 2882 SCF_PROPERTY_RESTARTER) == 0) 2883 is_protected = 1; 2884 } 2885 2886 /* Look for the same property in the new properties. */ 2887 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2888 if (new_p != NULL) { 2889 new_p->sc_seen = 1; 2890 2891 /* 2892 * If the new property is the same as the old, don't do 2893 * anything (leave any user customizations). 2894 */ 2895 if (prop_equal(p, new_p, NULL, NULL, 0)) 2896 continue; 2897 2898 if (new_p->sc_property_override) 2899 goto upgrade; 2900 } 2901 2902 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2903 if (cur_p == NULL) { 2904 /* 2905 * p has been deleted from the repository. If we were 2906 * going to delete it anyway, do nothing. Otherwise 2907 * report a conflict. 2908 */ 2909 if (new_p == NULL) 2910 continue; 2911 2912 if (is_protected) 2913 continue; 2914 2915 warn(gettext("Conflict upgrading %s " 2916 "(property \"%s/%s\" is missing).\n"), fmri, 2917 old->sc_pgroup_name, p->sc_property_name); 2918 continue; 2919 } 2920 2921 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2922 /* 2923 * Conflict. Don't warn if the property is already the 2924 * way we want it, though. 2925 */ 2926 if (is_protected) 2927 continue; 2928 2929 if (new_p == NULL) 2930 (void) prop_equal(p, cur_p, fmri, 2931 old->sc_pgroup_name, 0); 2932 else 2933 (void) prop_equal(cur_p, new_p, fmri, 2934 old->sc_pgroup_name, 0); 2935 continue; 2936 } 2937 2938 if (is_protected) { 2939 if (speak) 2940 warn(gettext("%s: Refusing to upgrade " 2941 "\"%s/%s\" (live property).\n"), fmri, 2942 old->sc_pgroup_name, p->sc_property_name); 2943 continue; 2944 } 2945 2946 upgrade: 2947 /* p hasn't been customized in the repository. Upgrade it. */ 2948 if (new_p == NULL) { 2949 /* p was deleted. Delete from cur if unchanged. */ 2950 if (speak) 2951 warn(gettext( 2952 "%s: Deleting property \"%s/%s\".\n"), 2953 fmri, old->sc_pgroup_name, 2954 p->sc_property_name); 2955 2956 e = scf_entry_create(g_hndl); 2957 if (e == NULL) 2958 return (ENOMEM); 2959 2960 if (scf_transaction_property_delete(tx, e, 2961 p->sc_property_name) != 0) { 2962 switch (scf_error()) { 2963 case SCF_ERROR_DELETED: 2964 scf_entry_destroy(e); 2965 return (ECANCELED); 2966 2967 case SCF_ERROR_CONNECTION_BROKEN: 2968 scf_entry_destroy(e); 2969 return (ECONNABORTED); 2970 2971 case SCF_ERROR_NOT_FOUND: 2972 /* 2973 * This can happen if cur is from the 2974 * running snapshot (and it differs 2975 * from the live properties). 2976 */ 2977 scf_entry_destroy(e); 2978 break; 2979 2980 case SCF_ERROR_HANDLE_MISMATCH: 2981 case SCF_ERROR_NOT_BOUND: 2982 case SCF_ERROR_NOT_SET: 2983 case SCF_ERROR_INVALID_ARGUMENT: 2984 default: 2985 bad_error( 2986 "scf_transaction_property_delete", 2987 scf_error()); 2988 } 2989 } 2990 } else { 2991 scf_callback_t ctx; 2992 2993 if (speak) 2994 warn(gettext( 2995 "%s: Upgrading property \"%s/%s\".\n"), 2996 fmri, old->sc_pgroup_name, 2997 p->sc_property_name); 2998 2999 ctx.sc_handle = g_hndl; 3000 ctx.sc_trans = tx; 3001 ctx.sc_flags = 0; 3002 3003 r = lscf_property_import(new_p, &ctx); 3004 if (r != UU_WALK_NEXT) { 3005 if (r != UU_WALK_ERROR) 3006 bad_error("lscf_property_import", r); 3007 return (EINVAL); 3008 } 3009 } 3010 } 3011 3012 /* Go over the properties which were added. */ 3013 for (new_p = uu_list_first(new->sc_pgroup_props); 3014 new_p != NULL; 3015 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 3016 if (new_p->sc_seen) 3017 continue; 3018 3019 /* This is a new property. */ 3020 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 3021 if (cur_p == NULL) { 3022 scf_callback_t ctx; 3023 3024 ctx.sc_handle = g_hndl; 3025 ctx.sc_trans = tx; 3026 ctx.sc_flags = 0; 3027 3028 r = lscf_property_import(new_p, &ctx); 3029 if (r != UU_WALK_NEXT) { 3030 if (r != UU_WALK_ERROR) 3031 bad_error("lscf_property_import", r); 3032 return (EINVAL); 3033 } 3034 continue; 3035 } 3036 3037 /* 3038 * Report a conflict if the new property differs from the 3039 * current one. Unless it's general/enabled, since that's 3040 * never in the last-import snapshot. 3041 */ 3042 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 3043 0 && 3044 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 3045 continue; 3046 3047 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 3048 } 3049 3050 return (0); 3051 } 3052 3053 /* 3054 * Upgrade pg according to old & new. 3055 * 3056 * Returns 3057 * 0 - success 3058 * ECONNABORTED - repository connection broken 3059 * ENOMEM - out of memory 3060 * ENOSPC - svc.configd is out of resources 3061 * ECANCELED - pg was deleted 3062 * EPERM - couldn't modify pg (permission denied) 3063 * EROFS - couldn't modify pg (backend read-only) 3064 * EACCES - couldn't modify pg (backend access denied) 3065 * EINVAL - new has a property with invalid name or value (error printed) 3066 * EBUSY - pg changed unexpectedly 3067 */ 3068 static int 3069 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 3070 pgroup_t *new, int speak, const char *fmri) 3071 { 3072 int r; 3073 3074 if (scf_transaction_start(imp_tx, pg) != 0) { 3075 switch (scf_error()) { 3076 case SCF_ERROR_CONNECTION_BROKEN: 3077 case SCF_ERROR_DELETED: 3078 case SCF_ERROR_PERMISSION_DENIED: 3079 case SCF_ERROR_BACKEND_READONLY: 3080 case SCF_ERROR_BACKEND_ACCESS: 3081 return (scferror2errno(scf_error())); 3082 3083 case SCF_ERROR_HANDLE_MISMATCH: 3084 case SCF_ERROR_IN_USE: 3085 case SCF_ERROR_NOT_BOUND: 3086 case SCF_ERROR_NOT_SET: 3087 default: 3088 bad_error("scf_transaction_start", scf_error()); 3089 } 3090 } 3091 3092 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 3093 switch (r) { 3094 case 0: 3095 break; 3096 3097 case EINVAL: 3098 case ENOMEM: 3099 scf_transaction_destroy_children(imp_tx); 3100 return (r); 3101 3102 default: 3103 bad_error("add_upgrade_entries", r); 3104 } 3105 3106 r = scf_transaction_commit(imp_tx); 3107 3108 scf_transaction_destroy_children(imp_tx); 3109 3110 switch (r) { 3111 case 1: 3112 break; 3113 3114 case 0: 3115 return (EBUSY); 3116 3117 case -1: 3118 switch (scf_error()) { 3119 case SCF_ERROR_CONNECTION_BROKEN: 3120 case SCF_ERROR_NO_RESOURCES: 3121 case SCF_ERROR_PERMISSION_DENIED: 3122 case SCF_ERROR_BACKEND_READONLY: 3123 case SCF_ERROR_BACKEND_ACCESS: 3124 case SCF_ERROR_DELETED: 3125 return (scferror2errno(scf_error())); 3126 3127 case SCF_ERROR_NOT_BOUND: 3128 case SCF_ERROR_INVALID_ARGUMENT: 3129 case SCF_ERROR_NOT_SET: 3130 default: 3131 bad_error("scf_transaction_commit", scf_error()); 3132 } 3133 3134 default: 3135 bad_error("scf_transaction_commit", r); 3136 } 3137 3138 return (0); 3139 } 3140 3141 /* 3142 * Compares two entity FMRIs. Returns 3143 * 3144 * 1 - equal 3145 * 0 - not equal 3146 * -1 - f1 is invalid or not an entity 3147 * -2 - f2 is invalid or not an entity 3148 */ 3149 static int 3150 fmri_equal(const char *f1, const char *f2) 3151 { 3152 int r; 3153 const char *s1, *i1, *pg1; 3154 const char *s2, *i2, *pg2; 3155 3156 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3157 return (-1); 3158 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 3159 return (-1); 3160 3161 if (s1 == NULL || pg1 != NULL) 3162 return (-1); 3163 3164 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 3165 return (-2); 3166 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 3167 return (-2); 3168 3169 if (s2 == NULL || pg2 != NULL) 3170 return (-2); 3171 3172 r = strcmp(s1, s2); 3173 if (r != 0) 3174 return (0); 3175 3176 if (i1 == NULL && i2 == NULL) 3177 return (1); 3178 3179 if (i1 == NULL || i2 == NULL) 3180 return (0); 3181 3182 return (strcmp(i1, i2) == 0); 3183 } 3184 3185 /* 3186 * Import a dependent by creating a dependency property group in the dependent 3187 * entity. If lcbdata->sc_trans is set, assume it's been started on the 3188 * dependents pg, and add an entry to create a new property for this 3189 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 3190 * 3191 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 3192 * lcbdata->sc_err to 3193 * ECONNABORTED - repository connection broken 3194 * ENOMEM - out of memory 3195 * ENOSPC - configd is out of resources 3196 * EINVAL - target is invalid (error printed) 3197 * - target is not an entity (error printed) 3198 * - dependent has invalid name (error printed) 3199 * - invalid property name (error printed) 3200 * - invalid value (error printed) 3201 * - scope of target does not exist (error printed) 3202 * EPERM - couldn't create target (permission denied) (error printed) 3203 * - couldn't create dependency pg (permission denied) (error printed) 3204 * - couldn't modify dependency pg (permission denied) (error printed) 3205 * EROFS - couldn't create target (repository read-only) 3206 * - couldn't create dependency pg (repository read-only) 3207 * EACCES - couldn't create target (backend access denied) 3208 * - couldn't create dependency pg (backend access denied) 3209 * ECANCELED - sc_trans's pg was deleted 3210 * EALREADY - property for dependent already exists in sc_trans's pg 3211 * EEXIST - dependency pg already exists in target (error printed) 3212 * EBUSY - target deleted (error printed) 3213 * - property group changed during import (error printed) 3214 */ 3215 static int 3216 lscf_dependent_import(void *a1, void *pvt) 3217 { 3218 pgroup_t *pgrp = a1; 3219 scf_callback_t *lcbdata = pvt; 3220 3221 int isservice; 3222 int ret; 3223 scf_transaction_entry_t *e; 3224 scf_value_t *val; 3225 scf_callback_t dependent_cbdata; 3226 scf_error_t scfe; 3227 3228 /* 3229 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 3230 * it's invalid, we fail before modifying the repository. 3231 */ 3232 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3233 &dependent_cbdata.sc_parent, &isservice); 3234 switch (scfe) { 3235 case SCF_ERROR_NONE: 3236 break; 3237 3238 case SCF_ERROR_NO_MEMORY: 3239 return (stash_scferror_err(lcbdata, scfe)); 3240 3241 case SCF_ERROR_INVALID_ARGUMENT: 3242 semerr(gettext("The FMRI for the \"%s\" dependent is " 3243 "invalid.\n"), pgrp->sc_pgroup_name); 3244 return (stash_scferror_err(lcbdata, scfe)); 3245 3246 case SCF_ERROR_CONSTRAINT_VIOLATED: 3247 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 3248 "specifies neither a service nor an instance.\n"), 3249 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3250 return (stash_scferror_err(lcbdata, scfe)); 3251 3252 case SCF_ERROR_NOT_FOUND: 3253 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 3254 &dependent_cbdata.sc_parent, &isservice); 3255 switch (scfe) { 3256 case SCF_ERROR_NONE: 3257 break; 3258 3259 case SCF_ERROR_NO_MEMORY: 3260 case SCF_ERROR_BACKEND_READONLY: 3261 case SCF_ERROR_BACKEND_ACCESS: 3262 return (stash_scferror_err(lcbdata, scfe)); 3263 3264 case SCF_ERROR_NOT_FOUND: 3265 semerr(gettext("The scope in FMRI \"%s\" for the " 3266 "\"%s\" dependent does not exist.\n"), 3267 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 3268 lcbdata->sc_err = EINVAL; 3269 return (UU_WALK_ERROR); 3270 3271 case SCF_ERROR_PERMISSION_DENIED: 3272 warn(gettext( 3273 "Could not create %s (permission denied).\n"), 3274 pgrp->sc_pgroup_fmri); 3275 return (stash_scferror_err(lcbdata, scfe)); 3276 3277 case SCF_ERROR_INVALID_ARGUMENT: 3278 case SCF_ERROR_CONSTRAINT_VIOLATED: 3279 default: 3280 bad_error("create_entity", scfe); 3281 } 3282 break; 3283 3284 default: 3285 bad_error("fmri_to_entity", scfe); 3286 } 3287 3288 if (lcbdata->sc_trans != NULL) { 3289 e = scf_entry_create(lcbdata->sc_handle); 3290 if (e == NULL) { 3291 if (scf_error() != SCF_ERROR_NO_MEMORY) 3292 bad_error("scf_entry_create", scf_error()); 3293 3294 entity_destroy(dependent_cbdata.sc_parent, isservice); 3295 return (stash_scferror(lcbdata)); 3296 } 3297 3298 if (scf_transaction_property_new(lcbdata->sc_trans, e, 3299 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 3300 switch (scf_error()) { 3301 case SCF_ERROR_INVALID_ARGUMENT: 3302 warn(gettext("Dependent of %s has invalid name " 3303 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 3304 pgrp->sc_pgroup_name); 3305 /* FALLTHROUGH */ 3306 3307 case SCF_ERROR_DELETED: 3308 case SCF_ERROR_CONNECTION_BROKEN: 3309 scf_entry_destroy(e); 3310 entity_destroy(dependent_cbdata.sc_parent, 3311 isservice); 3312 return (stash_scferror(lcbdata)); 3313 3314 case SCF_ERROR_EXISTS: 3315 scf_entry_destroy(e); 3316 entity_destroy(dependent_cbdata.sc_parent, 3317 isservice); 3318 lcbdata->sc_err = EALREADY; 3319 return (UU_WALK_ERROR); 3320 3321 case SCF_ERROR_NOT_BOUND: 3322 case SCF_ERROR_HANDLE_MISMATCH: 3323 case SCF_ERROR_NOT_SET: 3324 default: 3325 bad_error("scf_transaction_property_new", 3326 scf_error()); 3327 } 3328 } 3329 3330 val = scf_value_create(lcbdata->sc_handle); 3331 if (val == NULL) { 3332 if (scf_error() != SCF_ERROR_NO_MEMORY) 3333 bad_error("scf_value_create", scf_error()); 3334 3335 entity_destroy(dependent_cbdata.sc_parent, isservice); 3336 return (stash_scferror(lcbdata)); 3337 } 3338 3339 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 3340 pgrp->sc_pgroup_fmri) != 0) 3341 /* invalid should have been caught above */ 3342 bad_error("scf_value_set_from_string", scf_error()); 3343 3344 if (scf_entry_add_value(e, val) != 0) 3345 bad_error("scf_entry_add_value", scf_error()); 3346 } 3347 3348 /* Add the property group to the target entity. */ 3349 3350 dependent_cbdata.sc_handle = lcbdata->sc_handle; 3351 dependent_cbdata.sc_flags = lcbdata->sc_flags; 3352 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 3353 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 3354 3355 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 3356 3357 entity_destroy(dependent_cbdata.sc_parent, isservice); 3358 3359 if (ret == UU_WALK_NEXT) 3360 return (ret); 3361 3362 if (ret != UU_WALK_ERROR) 3363 bad_error("entity_pgroup_import", ret); 3364 3365 switch (dependent_cbdata.sc_err) { 3366 case ECANCELED: 3367 warn(gettext("%s deleted unexpectedly.\n"), 3368 pgrp->sc_pgroup_fmri); 3369 lcbdata->sc_err = EBUSY; 3370 break; 3371 3372 case EEXIST: 3373 warn(gettext("Could not create \"%s\" dependency in %s " 3374 "(already exists).\n"), pgrp->sc_pgroup_name, 3375 pgrp->sc_pgroup_fmri); 3376 /* FALLTHROUGH */ 3377 3378 default: 3379 lcbdata->sc_err = dependent_cbdata.sc_err; 3380 } 3381 3382 return (UU_WALK_ERROR); 3383 } 3384 3385 static int upgrade_dependent(const scf_property_t *, const entity_t *, 3386 const scf_snaplevel_t *, scf_transaction_t *); 3387 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 3388 const pgroup_t *); 3389 3390 /* 3391 * Upgrade uncustomized dependents of ent to those specified in ient. Read 3392 * the current dependent targets from running (the snaplevel of a running 3393 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 3394 * scf_instance_t * according to ient, otherwise). Draw the ancestral 3395 * dependent targets and dependency properties from li_dpts_pg (the 3396 * "dependents" property group in snpl) and snpl (the snaplevel which 3397 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 3398 * snpl doesn't have a "dependents" property group, and any dependents in ient 3399 * are new. 3400 * 3401 * Returns 3402 * 0 - success 3403 * ECONNABORTED - repository connection broken 3404 * ENOMEM - out of memory 3405 * ENOSPC - configd is out of resources 3406 * ECANCELED - ent was deleted 3407 * ENODEV - the entity containing li_dpts_pg was deleted 3408 * EPERM - could not modify dependents pg (permission denied) (error printed) 3409 * - couldn't upgrade dependent (permission denied) (error printed) 3410 * - couldn't create dependent (permission denied) (error printed) 3411 * EROFS - could not modify dependents pg (repository read-only) 3412 * - couldn't upgrade dependent (repository read-only) 3413 * - couldn't create dependent (repository read-only) 3414 * EACCES - could not modify dependents pg (backend access denied) 3415 * - could not upgrade dependent (backend access denied) 3416 * - could not create dependent (backend access denied) 3417 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 3418 * - dependent target deleted (error printed) 3419 * - dependent pg changed (error printed) 3420 * EINVAL - new dependent is invalid (error printed) 3421 * EBADF - snpl is corrupt (error printed) 3422 * - snpl has corrupt pg (error printed) 3423 * - dependency pg in target is corrupt (error printed) 3424 * - target has corrupt snapshot (error printed) 3425 * EEXIST - dependency pg already existed in target service (error printed) 3426 */ 3427 static int 3428 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 3429 const scf_snaplevel_t *snpl, const entity_t *ient, 3430 const scf_snaplevel_t *running, void *ent) 3431 { 3432 pgroup_t *new_dpt_pgroup; 3433 scf_callback_t cbdata; 3434 int r, unseen, tx_started = 0; 3435 int have_cur_depts; 3436 3437 const char * const dependents = "dependents"; 3438 3439 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3440 3441 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 3442 /* Nothing to do. */ 3443 return (0); 3444 3445 /* Fetch the current version of the "dependents" property group. */ 3446 have_cur_depts = 1; 3447 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 3448 switch (scf_error()) { 3449 case SCF_ERROR_NOT_FOUND: 3450 break; 3451 3452 case SCF_ERROR_DELETED: 3453 case SCF_ERROR_CONNECTION_BROKEN: 3454 return (scferror2errno(scf_error())); 3455 3456 case SCF_ERROR_NOT_SET: 3457 case SCF_ERROR_INVALID_ARGUMENT: 3458 case SCF_ERROR_HANDLE_MISMATCH: 3459 case SCF_ERROR_NOT_BOUND: 3460 default: 3461 bad_error("entity_get_pg", scf_error()); 3462 } 3463 3464 have_cur_depts = 0; 3465 } 3466 3467 /* Fetch the running version of the "dependents" property group. */ 3468 ud_run_dpts_pg_set = 0; 3469 if (running != NULL) 3470 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 3471 else 3472 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 3473 if (r == 0) { 3474 ud_run_dpts_pg_set = 1; 3475 } else { 3476 switch (scf_error()) { 3477 case SCF_ERROR_NOT_FOUND: 3478 break; 3479 3480 case SCF_ERROR_DELETED: 3481 case SCF_ERROR_CONNECTION_BROKEN: 3482 return (scferror2errno(scf_error())); 3483 3484 case SCF_ERROR_NOT_SET: 3485 case SCF_ERROR_INVALID_ARGUMENT: 3486 case SCF_ERROR_HANDLE_MISMATCH: 3487 case SCF_ERROR_NOT_BOUND: 3488 default: 3489 bad_error(running ? "scf_snaplevel_get_pg" : 3490 "entity_get_pg", scf_error()); 3491 } 3492 } 3493 3494 /* 3495 * Clear the seen fields of the dependents, so we can tell which ones 3496 * are new. 3497 */ 3498 if (uu_list_walk(ient->sc_dependents, clear_int, 3499 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3500 bad_error("uu_list_walk", uu_error()); 3501 3502 if (li_dpts_pg != NULL) { 3503 /* 3504 * Each property in li_dpts_pg represents a dependent tag in 3505 * the old manifest. For each, call upgrade_dependent(), 3506 * which will change ud_cur_depts_pg or dependencies in other 3507 * services as appropriate. Note (a) that changes to 3508 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3509 * made en masse, and (b) it's ok if the entity doesn't have 3510 * a current version of the "dependents" property group, 3511 * because we'll just consider all dependents as customized 3512 * (by being deleted). 3513 */ 3514 3515 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3516 switch (scf_error()) { 3517 case SCF_ERROR_DELETED: 3518 return (ENODEV); 3519 3520 case SCF_ERROR_CONNECTION_BROKEN: 3521 return (ECONNABORTED); 3522 3523 case SCF_ERROR_HANDLE_MISMATCH: 3524 case SCF_ERROR_NOT_BOUND: 3525 case SCF_ERROR_NOT_SET: 3526 default: 3527 bad_error("scf_iter_pg_properties", 3528 scf_error()); 3529 } 3530 } 3531 3532 if (have_cur_depts && 3533 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3534 switch (scf_error()) { 3535 case SCF_ERROR_BACKEND_ACCESS: 3536 case SCF_ERROR_BACKEND_READONLY: 3537 case SCF_ERROR_CONNECTION_BROKEN: 3538 return (scferror2errno(scf_error())); 3539 3540 case SCF_ERROR_DELETED: 3541 warn(emsg_pg_deleted, ient->sc_fmri, 3542 dependents); 3543 return (EBUSY); 3544 3545 case SCF_ERROR_PERMISSION_DENIED: 3546 warn(emsg_pg_mod_perm, dependents, 3547 ient->sc_fmri); 3548 return (scferror2errno(scf_error())); 3549 3550 case SCF_ERROR_HANDLE_MISMATCH: 3551 case SCF_ERROR_IN_USE: 3552 case SCF_ERROR_NOT_BOUND: 3553 case SCF_ERROR_NOT_SET: 3554 default: 3555 bad_error("scf_transaction_start", scf_error()); 3556 } 3557 } 3558 tx_started = have_cur_depts; 3559 3560 for (;;) { 3561 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3562 if (r == 0) 3563 break; 3564 if (r == 1) { 3565 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3566 tx_started ? ud_tx : NULL); 3567 switch (r) { 3568 case 0: 3569 continue; 3570 3571 case ECONNABORTED: 3572 case ENOMEM: 3573 case ENOSPC: 3574 case EBADF: 3575 case EBUSY: 3576 case EINVAL: 3577 case EPERM: 3578 case EROFS: 3579 case EACCES: 3580 case EEXIST: 3581 break; 3582 3583 case ECANCELED: 3584 r = ENODEV; 3585 break; 3586 3587 default: 3588 bad_error("upgrade_dependent", r); 3589 } 3590 3591 if (tx_started) 3592 scf_transaction_destroy_children(ud_tx); 3593 return (r); 3594 } 3595 if (r != -1) 3596 bad_error("scf_iter_next_property", r); 3597 3598 switch (scf_error()) { 3599 case SCF_ERROR_DELETED: 3600 r = ENODEV; 3601 break; 3602 3603 case SCF_ERROR_CONNECTION_BROKEN: 3604 r = ECONNABORTED; 3605 break; 3606 3607 case SCF_ERROR_NOT_SET: 3608 case SCF_ERROR_INVALID_ARGUMENT: 3609 case SCF_ERROR_NOT_BOUND: 3610 case SCF_ERROR_HANDLE_MISMATCH: 3611 default: 3612 bad_error("scf_iter_next_property", 3613 scf_error()); 3614 } 3615 3616 if (tx_started) 3617 scf_transaction_destroy_children(ud_tx); 3618 return (r); 3619 } 3620 } 3621 3622 /* import unseen dependents */ 3623 unseen = 0; 3624 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3625 new_dpt_pgroup != NULL; 3626 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3627 new_dpt_pgroup)) { 3628 if (!new_dpt_pgroup->sc_pgroup_seen) { 3629 unseen = 1; 3630 break; 3631 } 3632 } 3633 3634 /* If there are none, exit early. */ 3635 if (unseen == 0) 3636 goto commit; 3637 3638 /* Set up for lscf_dependent_import() */ 3639 cbdata.sc_handle = g_hndl; 3640 cbdata.sc_parent = ent; 3641 cbdata.sc_service = issvc; 3642 cbdata.sc_flags = 0; 3643 3644 if (!have_cur_depts) { 3645 /* 3646 * We have new dependents to import, so we need a "dependents" 3647 * property group. 3648 */ 3649 if (issvc) 3650 r = scf_service_add_pg(ent, dependents, 3651 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3652 else 3653 r = scf_instance_add_pg(ent, dependents, 3654 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3655 if (r != 0) { 3656 switch (scf_error()) { 3657 case SCF_ERROR_DELETED: 3658 case SCF_ERROR_CONNECTION_BROKEN: 3659 case SCF_ERROR_BACKEND_READONLY: 3660 case SCF_ERROR_BACKEND_ACCESS: 3661 case SCF_ERROR_NO_RESOURCES: 3662 return (scferror2errno(scf_error())); 3663 3664 case SCF_ERROR_EXISTS: 3665 warn(emsg_pg_added, ient->sc_fmri, dependents); 3666 return (EBUSY); 3667 3668 case SCF_ERROR_PERMISSION_DENIED: 3669 warn(emsg_pg_add_perm, dependents, 3670 ient->sc_fmri); 3671 return (scferror2errno(scf_error())); 3672 3673 case SCF_ERROR_NOT_BOUND: 3674 case SCF_ERROR_HANDLE_MISMATCH: 3675 case SCF_ERROR_INVALID_ARGUMENT: 3676 case SCF_ERROR_NOT_SET: 3677 default: 3678 bad_error("scf_service_add_pg", scf_error()); 3679 } 3680 } 3681 } 3682 3683 cbdata.sc_trans = ud_tx; 3684 3685 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3686 switch (scf_error()) { 3687 case SCF_ERROR_CONNECTION_BROKEN: 3688 case SCF_ERROR_BACKEND_ACCESS: 3689 case SCF_ERROR_BACKEND_READONLY: 3690 return (scferror2errno(scf_error())); 3691 3692 case SCF_ERROR_DELETED: 3693 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3694 return (EBUSY); 3695 3696 case SCF_ERROR_PERMISSION_DENIED: 3697 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3698 return (scferror2errno(scf_error())); 3699 3700 case SCF_ERROR_HANDLE_MISMATCH: 3701 case SCF_ERROR_IN_USE: 3702 case SCF_ERROR_NOT_BOUND: 3703 case SCF_ERROR_NOT_SET: 3704 default: 3705 bad_error("scf_transaction_start", scf_error()); 3706 } 3707 } 3708 tx_started = 1; 3709 3710 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3711 new_dpt_pgroup != NULL; 3712 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3713 new_dpt_pgroup)) { 3714 if (new_dpt_pgroup->sc_pgroup_seen) 3715 continue; 3716 3717 if (ud_run_dpts_pg_set) { 3718 /* 3719 * If the dependent is already there, then we have 3720 * a conflict. 3721 */ 3722 if (scf_pg_get_property(ud_run_dpts_pg, 3723 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3724 r = handle_dependent_conflict(ient, ud_prop, 3725 new_dpt_pgroup); 3726 switch (r) { 3727 case 0: 3728 continue; 3729 3730 case ECONNABORTED: 3731 case ENOMEM: 3732 case EBUSY: 3733 case EBADF: 3734 case EINVAL: 3735 scf_transaction_destroy_children(ud_tx); 3736 return (r); 3737 3738 default: 3739 bad_error("handle_dependent_conflict", 3740 r); 3741 } 3742 } else { 3743 switch (scf_error()) { 3744 case SCF_ERROR_NOT_FOUND: 3745 break; 3746 3747 case SCF_ERROR_INVALID_ARGUMENT: 3748 warn(emsg_fmri_invalid_pg_name, 3749 ient->sc_fmri, 3750 new_dpt_pgroup->sc_pgroup_name); 3751 scf_transaction_destroy_children(ud_tx); 3752 return (EINVAL); 3753 3754 case SCF_ERROR_DELETED: 3755 warn(emsg_pg_deleted, ient->sc_fmri, 3756 new_dpt_pgroup->sc_pgroup_name); 3757 scf_transaction_destroy_children(ud_tx); 3758 return (EBUSY); 3759 3760 case SCF_ERROR_CONNECTION_BROKEN: 3761 scf_transaction_destroy_children(ud_tx); 3762 return (ECONNABORTED); 3763 3764 case SCF_ERROR_NOT_BOUND: 3765 case SCF_ERROR_HANDLE_MISMATCH: 3766 case SCF_ERROR_NOT_SET: 3767 default: 3768 bad_error("scf_pg_get_property", 3769 scf_error()); 3770 } 3771 } 3772 } 3773 3774 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3775 if (r != UU_WALK_NEXT) { 3776 if (r != UU_WALK_ERROR) 3777 bad_error("lscf_dependent_import", r); 3778 3779 if (cbdata.sc_err == EALREADY) { 3780 /* Collisions were handled preemptively. */ 3781 bad_error("lscf_dependent_import", 3782 cbdata.sc_err); 3783 } 3784 3785 scf_transaction_destroy_children(ud_tx); 3786 return (cbdata.sc_err); 3787 } 3788 } 3789 3790 commit: 3791 if (!tx_started) 3792 return (0); 3793 3794 r = scf_transaction_commit(ud_tx); 3795 3796 scf_transaction_destroy_children(ud_tx); 3797 3798 switch (r) { 3799 case 1: 3800 return (0); 3801 3802 case 0: 3803 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3804 return (EBUSY); 3805 3806 case -1: 3807 break; 3808 3809 default: 3810 bad_error("scf_transaction_commit", r); 3811 } 3812 3813 switch (scf_error()) { 3814 case SCF_ERROR_CONNECTION_BROKEN: 3815 case SCF_ERROR_BACKEND_READONLY: 3816 case SCF_ERROR_BACKEND_ACCESS: 3817 case SCF_ERROR_NO_RESOURCES: 3818 return (scferror2errno(scf_error())); 3819 3820 case SCF_ERROR_DELETED: 3821 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3822 return (EBUSY); 3823 3824 case SCF_ERROR_PERMISSION_DENIED: 3825 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3826 return (scferror2errno(scf_error())); 3827 3828 case SCF_ERROR_NOT_BOUND: 3829 case SCF_ERROR_INVALID_ARGUMENT: 3830 case SCF_ERROR_NOT_SET: 3831 default: 3832 bad_error("scf_transaction_destroy", scf_error()); 3833 /* NOTREACHED */ 3834 } 3835 } 3836 3837 /* 3838 * Used to add the manifests to the list of currently supported manifests. 3839 * We can modify the existing manifest list removing entries if the files 3840 * don't exist. 3841 * 3842 * Get the old list and the new file name 3843 * If the new file name is in the list return 3844 * If not then add the file to the list. 3845 * As we process the list check to see if the files in the old list exist 3846 * if not then remove the file from the list. 3847 * Commit the list of manifest file names. 3848 * 3849 */ 3850 static int 3851 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient, 3852 const scf_snaplevel_t *running, void *ent) 3853 { 3854 scf_propertygroup_t *ud_mfsts_pg = NULL; 3855 scf_property_t *ud_prop = NULL; 3856 scf_iter_t *ud_prop_iter; 3857 scf_value_t *fname_value; 3858 scf_callback_t cbdata; 3859 pgroup_t *mfst_pgroup; 3860 property_t *mfst_prop; 3861 property_t *old_prop; 3862 char *pname = malloc(MAXPATHLEN); 3863 char *fval = NULL; 3864 char *old_pname; 3865 char *old_fval; 3866 int no_upgrade_pg; 3867 int mfst_seen; 3868 int r; 3869 3870 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3871 3872 /* 3873 * This should always be the service base on the code 3874 * path, and the fact that the manifests pg is a service 3875 * level property group only. 3876 */ 3877 ud_mfsts_pg = scf_pg_create(g_hndl); 3878 ud_prop = scf_property_create(g_hndl); 3879 ud_prop_iter = scf_iter_create(g_hndl); 3880 fname_value = scf_value_create(g_hndl); 3881 3882 /* Fetch the "manifests" property group */ 3883 no_upgrade_pg = 0; 3884 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3885 ud_mfsts_pg); 3886 if (r != 0) { 3887 switch (scf_error()) { 3888 case SCF_ERROR_NOT_FOUND: 3889 no_upgrade_pg = 1; 3890 break; 3891 3892 case SCF_ERROR_DELETED: 3893 case SCF_ERROR_CONNECTION_BROKEN: 3894 return (scferror2errno(scf_error())); 3895 3896 case SCF_ERROR_NOT_SET: 3897 case SCF_ERROR_INVALID_ARGUMENT: 3898 case SCF_ERROR_HANDLE_MISMATCH: 3899 case SCF_ERROR_NOT_BOUND: 3900 default: 3901 bad_error(running ? "scf_snaplevel_get_pg" : 3902 "entity_get_pg", scf_error()); 3903 } 3904 } 3905 3906 if (no_upgrade_pg) { 3907 cbdata.sc_handle = g_hndl; 3908 cbdata.sc_parent = ent; 3909 cbdata.sc_service = issvc; 3910 cbdata.sc_flags = SCI_FORCE; 3911 cbdata.sc_source_fmri = ient->sc_fmri; 3912 cbdata.sc_target_fmri = ient->sc_fmri; 3913 3914 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3915 return (cbdata.sc_err); 3916 3917 return (0); 3918 } 3919 3920 /* Fetch the new manifests property group */ 3921 for (mfst_pgroup = uu_list_first(ient->sc_pgroups); 3922 mfst_pgroup != NULL; 3923 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) { 3924 if (strcmp(mfst_pgroup->sc_pgroup_name, 3925 SCF_PG_MANIFESTFILES) == 0) 3926 break; 3927 } 3928 3929 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3930 SCF_SUCCESS) 3931 return (-1); 3932 3933 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 3934 mfst_seen = 0; 3935 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 3936 continue; 3937 3938 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3939 mfst_prop != NULL; 3940 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3941 mfst_prop)) { 3942 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3943 mfst_seen = 1; 3944 } 3945 } 3946 3947 /* 3948 * If the manifest is not seen then add it to the new mfst 3949 * property list to get proccessed into the repo. 3950 */ 3951 if (mfst_seen == 0) { 3952 if (fval == NULL) 3953 fval = malloc(MAXPATHLEN); 3954 3955 /* 3956 * If we cannot get the value then there is no 3957 * reason to attempt to attach the value to 3958 * the property group 3959 */ 3960 if (fval != NULL && 3961 prop_get_val(ud_prop, fname_value) == 0 && 3962 scf_value_get_astring(fname_value, fval, 3963 MAXPATHLEN) != -1) { 3964 old_pname = safe_strdup(pname); 3965 old_fval = safe_strdup(fval); 3966 old_prop = internal_property_create(old_pname, 3967 SCF_TYPE_ASTRING, 1, old_fval); 3968 3969 /* 3970 * Already checked to see if the property exists 3971 * in the group, and it does not. 3972 */ 3973 (void) internal_attach_property(mfst_pgroup, 3974 old_prop); 3975 } 3976 } 3977 } 3978 free(fval); 3979 3980 cbdata.sc_handle = g_hndl; 3981 cbdata.sc_parent = ent; 3982 cbdata.sc_service = issvc; 3983 cbdata.sc_flags = SCI_FORCE; 3984 cbdata.sc_source_fmri = ient->sc_fmri; 3985 cbdata.sc_target_fmri = ient->sc_fmri; 3986 3987 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 3988 return (cbdata.sc_err); 3989 3990 return (r); 3991 } 3992 3993 /* 3994 * prop is taken to be a property in the "dependents" property group of snpl, 3995 * which is taken to be the snaplevel of a last-import snapshot corresponding 3996 * to ient. If prop is a valid dependents property, upgrade the dependent it 3997 * represents according to the repository & ient. If ud_run_dpts_pg_set is 3998 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 3999 * of the entity ient represents (possibly in the running snapshot). If it 4000 * needs to be changed, an entry will be added to tx, if not NULL. 4001 * 4002 * Returns 4003 * 0 - success 4004 * ECONNABORTED - repository connection broken 4005 * ENOMEM - out of memory 4006 * ENOSPC - configd was out of resources 4007 * ECANCELED - snpl's entity was deleted 4008 * EINVAL - dependent target is invalid (error printed) 4009 * - dependent is invalid (error printed) 4010 * EBADF - snpl is corrupt (error printed) 4011 * - snpl has corrupt pg (error printed) 4012 * - dependency pg in target is corrupt (error printed) 4013 * - running snapshot in dependent is missing snaplevel (error printed) 4014 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 4015 * - couldn't create dependent (permission denied) (error printed) 4016 * - couldn't modify dependent pg (permission denied) (error printed) 4017 * EROFS - couldn't delete dependency pg (repository read-only) 4018 * - couldn't create dependent (repository read-only) 4019 * EACCES - couldn't delete dependency pg (backend access denied) 4020 * - couldn't create dependent (backend access denied) 4021 * EBUSY - ud_run_dpts_pg was deleted (error printed) 4022 * - tx's pg was deleted (error printed) 4023 * - dependent pg was changed or deleted (error printed) 4024 * EEXIST - dependency pg already exists in new target (error printed) 4025 */ 4026 static int 4027 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 4028 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 4029 { 4030 pgroup_t pgrp; 4031 scf_type_t ty; 4032 pgroup_t *new_dpt_pgroup; 4033 pgroup_t *old_dpt_pgroup = NULL; 4034 pgroup_t *current_pg; 4035 pgroup_t *dpt; 4036 scf_callback_t cbdata; 4037 int tissvc; 4038 void *target_ent; 4039 scf_error_t serr; 4040 int r; 4041 scf_transaction_entry_t *ent; 4042 4043 const char * const cf_inval = gettext("Conflict upgrading %s " 4044 "(dependent \"%s\" has invalid dependents property).\n"); 4045 const char * const cf_missing = gettext("Conflict upgrading %s " 4046 "(dependent \"%s\" is missing).\n"); 4047 const char * const cf_newdpg = gettext("Conflict upgrading %s " 4048 "(dependent \"%s\" has new dependency property group).\n"); 4049 const char * const cf_newtarg = gettext("Conflict upgrading %s " 4050 "(dependent \"%s\" has new target).\n"); 4051 const char * const li_corrupt = 4052 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 4053 const char * const upgrading = 4054 gettext("%s: Upgrading dependent \"%s\".\n"); 4055 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 4056 "corrupt (missing snaplevel).\n"); 4057 4058 if (scf_property_type(prop, &ty) != 0) { 4059 switch (scf_error()) { 4060 case SCF_ERROR_DELETED: 4061 case SCF_ERROR_CONNECTION_BROKEN: 4062 return (scferror2errno(scf_error())); 4063 4064 case SCF_ERROR_NOT_BOUND: 4065 case SCF_ERROR_NOT_SET: 4066 default: 4067 bad_error("scf_property_type", scf_error()); 4068 } 4069 } 4070 4071 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4072 warn(li_corrupt, ient->sc_fmri); 4073 return (EBADF); 4074 } 4075 4076 /* 4077 * prop represents a dependent in the old manifest. It is named after 4078 * the dependent. 4079 */ 4080 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 4081 switch (scf_error()) { 4082 case SCF_ERROR_DELETED: 4083 case SCF_ERROR_CONNECTION_BROKEN: 4084 return (scferror2errno(scf_error())); 4085 4086 case SCF_ERROR_NOT_BOUND: 4087 case SCF_ERROR_NOT_SET: 4088 default: 4089 bad_error("scf_property_get_name", scf_error()); 4090 } 4091 } 4092 4093 /* See if it's in the new manifest. */ 4094 pgrp.sc_pgroup_name = ud_name; 4095 new_dpt_pgroup = 4096 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 4097 4098 /* If it's not, delete it... if it hasn't been customized. */ 4099 if (new_dpt_pgroup == NULL) { 4100 if (!ud_run_dpts_pg_set) 4101 return (0); 4102 4103 if (scf_property_get_value(prop, ud_val) != 0) { 4104 switch (scf_error()) { 4105 case SCF_ERROR_NOT_FOUND: 4106 case SCF_ERROR_CONSTRAINT_VIOLATED: 4107 warn(li_corrupt, ient->sc_fmri); 4108 return (EBADF); 4109 4110 case SCF_ERROR_DELETED: 4111 case SCF_ERROR_CONNECTION_BROKEN: 4112 return (scferror2errno(scf_error())); 4113 4114 case SCF_ERROR_HANDLE_MISMATCH: 4115 case SCF_ERROR_NOT_BOUND: 4116 case SCF_ERROR_NOT_SET: 4117 case SCF_ERROR_PERMISSION_DENIED: 4118 default: 4119 bad_error("scf_property_get_value", 4120 scf_error()); 4121 } 4122 } 4123 4124 if (scf_value_get_as_string(ud_val, ud_oldtarg, 4125 max_scf_value_len + 1) < 0) 4126 bad_error("scf_value_get_as_string", scf_error()); 4127 4128 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 4129 0) { 4130 switch (scf_error()) { 4131 case SCF_ERROR_NOT_FOUND: 4132 return (0); 4133 4134 case SCF_ERROR_CONNECTION_BROKEN: 4135 return (scferror2errno(scf_error())); 4136 4137 case SCF_ERROR_DELETED: 4138 warn(emsg_pg_deleted, ient->sc_fmri, 4139 "dependents"); 4140 return (EBUSY); 4141 4142 case SCF_ERROR_INVALID_ARGUMENT: 4143 case SCF_ERROR_NOT_BOUND: 4144 case SCF_ERROR_HANDLE_MISMATCH: 4145 case SCF_ERROR_NOT_SET: 4146 default: 4147 bad_error("scf_pg_get_property", scf_error()); 4148 } 4149 } 4150 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4151 switch (scf_error()) { 4152 case SCF_ERROR_NOT_FOUND: 4153 case SCF_ERROR_CONSTRAINT_VIOLATED: 4154 warn(cf_inval, ient->sc_fmri, ud_name); 4155 return (0); 4156 4157 case SCF_ERROR_DELETED: 4158 case SCF_ERROR_CONNECTION_BROKEN: 4159 return (scferror2errno(scf_error())); 4160 4161 case SCF_ERROR_HANDLE_MISMATCH: 4162 case SCF_ERROR_NOT_BOUND: 4163 case SCF_ERROR_NOT_SET: 4164 case SCF_ERROR_PERMISSION_DENIED: 4165 default: 4166 bad_error("scf_property_get_value", 4167 scf_error()); 4168 } 4169 } 4170 4171 ty = scf_value_type(ud_val); 4172 assert(ty != SCF_TYPE_INVALID); 4173 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4174 warn(cf_inval, ient->sc_fmri, ud_name); 4175 return (0); 4176 } 4177 4178 if (scf_value_get_as_string(ud_val, ud_ctarg, 4179 max_scf_value_len + 1) < 0) 4180 bad_error("scf_value_get_as_string", scf_error()); 4181 4182 r = fmri_equal(ud_ctarg, ud_oldtarg); 4183 switch (r) { 4184 case 1: 4185 break; 4186 4187 case 0: 4188 case -1: /* warn? */ 4189 warn(cf_newtarg, ient->sc_fmri, ud_name); 4190 return (0); 4191 4192 case -2: 4193 warn(li_corrupt, ient->sc_fmri); 4194 return (EBADF); 4195 4196 default: 4197 bad_error("fmri_equal", r); 4198 } 4199 4200 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4201 switch (scf_error()) { 4202 case SCF_ERROR_NOT_FOUND: 4203 warn(li_corrupt, ient->sc_fmri); 4204 return (EBADF); 4205 4206 case SCF_ERROR_DELETED: 4207 case SCF_ERROR_CONNECTION_BROKEN: 4208 return (scferror2errno(scf_error())); 4209 4210 case SCF_ERROR_NOT_BOUND: 4211 case SCF_ERROR_HANDLE_MISMATCH: 4212 case SCF_ERROR_INVALID_ARGUMENT: 4213 case SCF_ERROR_NOT_SET: 4214 default: 4215 bad_error("scf_snaplevel_get_pg", scf_error()); 4216 } 4217 } 4218 4219 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4220 snap_lastimport); 4221 switch (r) { 4222 case 0: 4223 break; 4224 4225 case ECANCELED: 4226 case ECONNABORTED: 4227 case ENOMEM: 4228 case EBADF: 4229 return (r); 4230 4231 case EACCES: 4232 default: 4233 bad_error("load_pg", r); 4234 } 4235 4236 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4237 switch (serr) { 4238 case SCF_ERROR_NONE: 4239 break; 4240 4241 case SCF_ERROR_NO_MEMORY: 4242 internal_pgroup_free(old_dpt_pgroup); 4243 return (ENOMEM); 4244 4245 case SCF_ERROR_NOT_FOUND: 4246 internal_pgroup_free(old_dpt_pgroup); 4247 goto delprop; 4248 4249 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 4250 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 4251 default: 4252 bad_error("fmri_to_entity", serr); 4253 } 4254 4255 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4256 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4257 switch (r) { 4258 case 0: 4259 break; 4260 4261 case ECONNABORTED: 4262 internal_pgroup_free(old_dpt_pgroup); 4263 return (r); 4264 4265 case ECANCELED: 4266 case ENOENT: 4267 internal_pgroup_free(old_dpt_pgroup); 4268 goto delprop; 4269 4270 case EBADF: 4271 warn(r_no_lvl, ud_ctarg); 4272 internal_pgroup_free(old_dpt_pgroup); 4273 return (r); 4274 4275 case EINVAL: 4276 default: 4277 bad_error("entity_get_running_pg", r); 4278 } 4279 4280 /* load it */ 4281 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4282 switch (r) { 4283 case 0: 4284 break; 4285 4286 case ECANCELED: 4287 internal_pgroup_free(old_dpt_pgroup); 4288 goto delprop; 4289 4290 case ECONNABORTED: 4291 case ENOMEM: 4292 case EBADF: 4293 internal_pgroup_free(old_dpt_pgroup); 4294 return (r); 4295 4296 case EACCES: 4297 default: 4298 bad_error("load_pg", r); 4299 } 4300 4301 /* compare property groups */ 4302 if (!pg_equal(old_dpt_pgroup, current_pg)) { 4303 warn(cf_newdpg, ient->sc_fmri, ud_name); 4304 internal_pgroup_free(old_dpt_pgroup); 4305 internal_pgroup_free(current_pg); 4306 return (0); 4307 } 4308 4309 internal_pgroup_free(old_dpt_pgroup); 4310 internal_pgroup_free(current_pg); 4311 4312 if (g_verbose) 4313 warn(gettext("%s: Deleting dependent \"%s\".\n"), 4314 ient->sc_fmri, ud_name); 4315 4316 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4317 switch (scf_error()) { 4318 case SCF_ERROR_NOT_FOUND: 4319 case SCF_ERROR_DELETED: 4320 internal_pgroup_free(old_dpt_pgroup); 4321 goto delprop; 4322 4323 case SCF_ERROR_CONNECTION_BROKEN: 4324 internal_pgroup_free(old_dpt_pgroup); 4325 return (ECONNABORTED); 4326 4327 case SCF_ERROR_NOT_SET: 4328 case SCF_ERROR_INVALID_ARGUMENT: 4329 case SCF_ERROR_HANDLE_MISMATCH: 4330 case SCF_ERROR_NOT_BOUND: 4331 default: 4332 bad_error("entity_get_pg", scf_error()); 4333 } 4334 } 4335 4336 if (scf_pg_delete(ud_pg) != 0) { 4337 switch (scf_error()) { 4338 case SCF_ERROR_DELETED: 4339 break; 4340 4341 case SCF_ERROR_CONNECTION_BROKEN: 4342 case SCF_ERROR_BACKEND_READONLY: 4343 case SCF_ERROR_BACKEND_ACCESS: 4344 return (scferror2errno(scf_error())); 4345 4346 case SCF_ERROR_PERMISSION_DENIED: 4347 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4348 return (scferror2errno(scf_error())); 4349 4350 case SCF_ERROR_NOT_SET: 4351 default: 4352 bad_error("scf_pg_delete", scf_error()); 4353 } 4354 } 4355 4356 /* 4357 * This service was changed, so it must be refreshed. But 4358 * since it's not mentioned in the new manifest, we have to 4359 * record its FMRI here for use later. We record the name 4360 * & the entity (via sc_parent) in case we need to print error 4361 * messages during the refresh. 4362 */ 4363 dpt = internal_pgroup_new(); 4364 if (dpt == NULL) 4365 return (ENOMEM); 4366 dpt->sc_pgroup_name = strdup(ud_name); 4367 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 4368 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4369 return (ENOMEM); 4370 dpt->sc_parent = (entity_t *)ient; 4371 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4372 uu_die(gettext("libuutil error: %s\n"), 4373 uu_strerror(uu_error())); 4374 4375 delprop: 4376 if (tx == NULL) 4377 return (0); 4378 4379 ent = scf_entry_create(g_hndl); 4380 if (ent == NULL) 4381 return (ENOMEM); 4382 4383 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 4384 scf_entry_destroy(ent); 4385 switch (scf_error()) { 4386 case SCF_ERROR_DELETED: 4387 warn(emsg_pg_deleted, ient->sc_fmri, 4388 "dependents"); 4389 return (EBUSY); 4390 4391 case SCF_ERROR_CONNECTION_BROKEN: 4392 return (scferror2errno(scf_error())); 4393 4394 case SCF_ERROR_NOT_FOUND: 4395 break; 4396 4397 case SCF_ERROR_HANDLE_MISMATCH: 4398 case SCF_ERROR_NOT_BOUND: 4399 case SCF_ERROR_INVALID_ARGUMENT: 4400 case SCF_ERROR_NOT_SET: 4401 default: 4402 bad_error("scf_transaction_property_delete", 4403 scf_error()); 4404 } 4405 } 4406 4407 return (0); 4408 } 4409 4410 new_dpt_pgroup->sc_pgroup_seen = 1; 4411 4412 /* 4413 * Decide whether the dependent has changed in the manifest. 4414 */ 4415 /* Compare the target. */ 4416 if (scf_property_get_value(prop, ud_val) != 0) { 4417 switch (scf_error()) { 4418 case SCF_ERROR_NOT_FOUND: 4419 case SCF_ERROR_CONSTRAINT_VIOLATED: 4420 warn(li_corrupt, ient->sc_fmri); 4421 return (EBADF); 4422 4423 case SCF_ERROR_DELETED: 4424 case SCF_ERROR_CONNECTION_BROKEN: 4425 return (scferror2errno(scf_error())); 4426 4427 case SCF_ERROR_HANDLE_MISMATCH: 4428 case SCF_ERROR_NOT_BOUND: 4429 case SCF_ERROR_NOT_SET: 4430 case SCF_ERROR_PERMISSION_DENIED: 4431 default: 4432 bad_error("scf_property_get_value", scf_error()); 4433 } 4434 } 4435 4436 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 4437 0) 4438 bad_error("scf_value_get_as_string", scf_error()); 4439 4440 /* 4441 * If the fmri's are not equal then the old fmri will need to 4442 * be refreshed to ensure that the changes are properly updated 4443 * in that service. 4444 */ 4445 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 4446 switch (r) { 4447 case 0: 4448 dpt = internal_pgroup_new(); 4449 if (dpt == NULL) 4450 return (ENOMEM); 4451 dpt->sc_pgroup_name = strdup(ud_name); 4452 dpt->sc_pgroup_fmri = strdup(ud_oldtarg); 4453 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 4454 return (ENOMEM); 4455 dpt->sc_parent = (entity_t *)ient; 4456 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 4457 uu_die(gettext("libuutil error: %s\n"), 4458 uu_strerror(uu_error())); 4459 break; 4460 4461 case 1: 4462 /* Compare the dependency pgs. */ 4463 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 4464 switch (scf_error()) { 4465 case SCF_ERROR_NOT_FOUND: 4466 warn(li_corrupt, ient->sc_fmri); 4467 return (EBADF); 4468 4469 case SCF_ERROR_DELETED: 4470 case SCF_ERROR_CONNECTION_BROKEN: 4471 return (scferror2errno(scf_error())); 4472 4473 case SCF_ERROR_NOT_BOUND: 4474 case SCF_ERROR_HANDLE_MISMATCH: 4475 case SCF_ERROR_INVALID_ARGUMENT: 4476 case SCF_ERROR_NOT_SET: 4477 default: 4478 bad_error("scf_snaplevel_get_pg", scf_error()); 4479 } 4480 } 4481 4482 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4483 snap_lastimport); 4484 switch (r) { 4485 case 0: 4486 break; 4487 4488 case ECANCELED: 4489 case ECONNABORTED: 4490 case ENOMEM: 4491 case EBADF: 4492 return (r); 4493 4494 case EACCES: 4495 default: 4496 bad_error("load_pg", r); 4497 } 4498 4499 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4500 /* no change, leave customizations */ 4501 internal_pgroup_free(old_dpt_pgroup); 4502 return (0); 4503 } 4504 break; 4505 4506 case -1: 4507 warn(li_corrupt, ient->sc_fmri); 4508 return (EBADF); 4509 4510 case -2: 4511 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4512 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4513 return (EINVAL); 4514 4515 default: 4516 bad_error("fmri_equal", r); 4517 } 4518 4519 /* 4520 * The dependent has changed in the manifest. Upgrade the current 4521 * properties if they haven't been customized. 4522 */ 4523 4524 /* 4525 * If new_dpt_pgroup->sc_override, then act as though the property 4526 * group hasn't been customized. 4527 */ 4528 if (new_dpt_pgroup->sc_pgroup_override) { 4529 (void) strcpy(ud_ctarg, ud_oldtarg); 4530 goto nocust; 4531 } 4532 4533 if (!ud_run_dpts_pg_set) { 4534 warn(cf_missing, ient->sc_fmri, ud_name); 4535 r = 0; 4536 goto out; 4537 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4538 switch (scf_error()) { 4539 case SCF_ERROR_NOT_FOUND: 4540 warn(cf_missing, ient->sc_fmri, ud_name); 4541 r = 0; 4542 goto out; 4543 4544 case SCF_ERROR_CONNECTION_BROKEN: 4545 r = scferror2errno(scf_error()); 4546 goto out; 4547 4548 case SCF_ERROR_DELETED: 4549 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4550 r = EBUSY; 4551 goto out; 4552 4553 case SCF_ERROR_INVALID_ARGUMENT: 4554 case SCF_ERROR_NOT_BOUND: 4555 case SCF_ERROR_HANDLE_MISMATCH: 4556 case SCF_ERROR_NOT_SET: 4557 default: 4558 bad_error("scf_pg_get_property", scf_error()); 4559 } 4560 } 4561 4562 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4563 switch (scf_error()) { 4564 case SCF_ERROR_NOT_FOUND: 4565 case SCF_ERROR_CONSTRAINT_VIOLATED: 4566 warn(cf_inval, ient->sc_fmri, ud_name); 4567 r = 0; 4568 goto out; 4569 4570 case SCF_ERROR_DELETED: 4571 case SCF_ERROR_CONNECTION_BROKEN: 4572 r = scferror2errno(scf_error()); 4573 goto out; 4574 4575 case SCF_ERROR_HANDLE_MISMATCH: 4576 case SCF_ERROR_NOT_BOUND: 4577 case SCF_ERROR_NOT_SET: 4578 case SCF_ERROR_PERMISSION_DENIED: 4579 default: 4580 bad_error("scf_property_get_value", scf_error()); 4581 } 4582 } 4583 4584 ty = scf_value_type(ud_val); 4585 assert(ty != SCF_TYPE_INVALID); 4586 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4587 warn(cf_inval, ient->sc_fmri, ud_name); 4588 r = 0; 4589 goto out; 4590 } 4591 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4592 0) 4593 bad_error("scf_value_get_as_string", scf_error()); 4594 4595 r = fmri_equal(ud_ctarg, ud_oldtarg); 4596 if (r == -1) { 4597 warn(cf_inval, ient->sc_fmri, ud_name); 4598 r = 0; 4599 goto out; 4600 } else if (r == -2) { 4601 warn(li_corrupt, ient->sc_fmri); 4602 r = EBADF; 4603 goto out; 4604 } else if (r == 0) { 4605 /* 4606 * Target has been changed. Only abort now if it's been 4607 * changed to something other than what's in the manifest. 4608 */ 4609 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4610 if (r == -1) { 4611 warn(cf_inval, ient->sc_fmri, ud_name); 4612 r = 0; 4613 goto out; 4614 } else if (r == 0) { 4615 warn(cf_newtarg, ient->sc_fmri, ud_name); 4616 r = 0; 4617 goto out; 4618 } else if (r != 1) { 4619 /* invalid sc_pgroup_fmri caught above */ 4620 bad_error("fmri_equal", r); 4621 } 4622 4623 /* 4624 * Fetch the current dependency pg. If it's what the manifest 4625 * says, then no problem. 4626 */ 4627 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4628 switch (serr) { 4629 case SCF_ERROR_NONE: 4630 break; 4631 4632 case SCF_ERROR_NOT_FOUND: 4633 warn(cf_missing, ient->sc_fmri, ud_name); 4634 r = 0; 4635 goto out; 4636 4637 case SCF_ERROR_NO_MEMORY: 4638 r = ENOMEM; 4639 goto out; 4640 4641 case SCF_ERROR_CONSTRAINT_VIOLATED: 4642 case SCF_ERROR_INVALID_ARGUMENT: 4643 default: 4644 bad_error("fmri_to_entity", serr); 4645 } 4646 4647 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4648 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4649 switch (r) { 4650 case 0: 4651 break; 4652 4653 case ECONNABORTED: 4654 goto out; 4655 4656 case ECANCELED: 4657 case ENOENT: 4658 warn(cf_missing, ient->sc_fmri, ud_name); 4659 r = 0; 4660 goto out; 4661 4662 case EBADF: 4663 warn(r_no_lvl, ud_ctarg); 4664 goto out; 4665 4666 case EINVAL: 4667 default: 4668 bad_error("entity_get_running_pg", r); 4669 } 4670 4671 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4672 switch (r) { 4673 case 0: 4674 break; 4675 4676 case ECANCELED: 4677 warn(cf_missing, ient->sc_fmri, ud_name); 4678 r = 0; 4679 goto out; 4680 4681 case ECONNABORTED: 4682 case ENOMEM: 4683 case EBADF: 4684 goto out; 4685 4686 case EACCES: 4687 default: 4688 bad_error("load_pg", r); 4689 } 4690 4691 if (!pg_equal(current_pg, new_dpt_pgroup)) 4692 warn(cf_newdpg, ient->sc_fmri, ud_name); 4693 internal_pgroup_free(current_pg); 4694 r = 0; 4695 goto out; 4696 } else if (r != 1) { 4697 bad_error("fmri_equal", r); 4698 } 4699 4700 nocust: 4701 /* 4702 * Target has not been customized. Check the dependency property 4703 * group. 4704 */ 4705 4706 if (old_dpt_pgroup == NULL) { 4707 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4708 ud_pg) != 0) { 4709 switch (scf_error()) { 4710 case SCF_ERROR_NOT_FOUND: 4711 warn(li_corrupt, ient->sc_fmri); 4712 return (EBADF); 4713 4714 case SCF_ERROR_DELETED: 4715 case SCF_ERROR_CONNECTION_BROKEN: 4716 return (scferror2errno(scf_error())); 4717 4718 case SCF_ERROR_NOT_BOUND: 4719 case SCF_ERROR_HANDLE_MISMATCH: 4720 case SCF_ERROR_INVALID_ARGUMENT: 4721 case SCF_ERROR_NOT_SET: 4722 default: 4723 bad_error("scf_snaplevel_get_pg", scf_error()); 4724 } 4725 } 4726 4727 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4728 snap_lastimport); 4729 switch (r) { 4730 case 0: 4731 break; 4732 4733 case ECANCELED: 4734 case ECONNABORTED: 4735 case ENOMEM: 4736 case EBADF: 4737 return (r); 4738 4739 case EACCES: 4740 default: 4741 bad_error("load_pg", r); 4742 } 4743 } 4744 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4745 switch (serr) { 4746 case SCF_ERROR_NONE: 4747 break; 4748 4749 case SCF_ERROR_NOT_FOUND: 4750 warn(cf_missing, ient->sc_fmri, ud_name); 4751 r = 0; 4752 goto out; 4753 4754 case SCF_ERROR_NO_MEMORY: 4755 r = ENOMEM; 4756 goto out; 4757 4758 case SCF_ERROR_CONSTRAINT_VIOLATED: 4759 case SCF_ERROR_INVALID_ARGUMENT: 4760 default: 4761 bad_error("fmri_to_entity", serr); 4762 } 4763 4764 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4765 ud_iter2, ud_inst, imp_snap, ud_snpl); 4766 switch (r) { 4767 case 0: 4768 break; 4769 4770 case ECONNABORTED: 4771 goto out; 4772 4773 case ECANCELED: 4774 case ENOENT: 4775 warn(cf_missing, ient->sc_fmri, ud_name); 4776 r = 0; 4777 goto out; 4778 4779 case EBADF: 4780 warn(r_no_lvl, ud_ctarg); 4781 goto out; 4782 4783 case EINVAL: 4784 default: 4785 bad_error("entity_get_running_pg", r); 4786 } 4787 4788 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4789 switch (r) { 4790 case 0: 4791 break; 4792 4793 case ECANCELED: 4794 warn(cf_missing, ient->sc_fmri, ud_name); 4795 goto out; 4796 4797 case ECONNABORTED: 4798 case ENOMEM: 4799 case EBADF: 4800 goto out; 4801 4802 case EACCES: 4803 default: 4804 bad_error("load_pg", r); 4805 } 4806 4807 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4808 if (!pg_equal(current_pg, new_dpt_pgroup)) 4809 warn(cf_newdpg, ient->sc_fmri, ud_name); 4810 internal_pgroup_free(current_pg); 4811 r = 0; 4812 goto out; 4813 } 4814 4815 /* Uncustomized. Upgrade. */ 4816 4817 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4818 switch (r) { 4819 case 1: 4820 if (pg_equal(current_pg, new_dpt_pgroup)) { 4821 /* Already upgraded. */ 4822 internal_pgroup_free(current_pg); 4823 r = 0; 4824 goto out; 4825 } 4826 4827 internal_pgroup_free(current_pg); 4828 4829 /* upgrade current_pg */ 4830 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4831 switch (scf_error()) { 4832 case SCF_ERROR_CONNECTION_BROKEN: 4833 r = scferror2errno(scf_error()); 4834 goto out; 4835 4836 case SCF_ERROR_DELETED: 4837 warn(cf_missing, ient->sc_fmri, ud_name); 4838 r = 0; 4839 goto out; 4840 4841 case SCF_ERROR_NOT_FOUND: 4842 break; 4843 4844 case SCF_ERROR_INVALID_ARGUMENT: 4845 case SCF_ERROR_NOT_BOUND: 4846 case SCF_ERROR_NOT_SET: 4847 case SCF_ERROR_HANDLE_MISMATCH: 4848 default: 4849 bad_error("entity_get_pg", scf_error()); 4850 } 4851 4852 if (tissvc) 4853 r = scf_service_add_pg(target_ent, ud_name, 4854 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4855 else 4856 r = scf_instance_add_pg(target_ent, ud_name, 4857 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4858 if (r != 0) { 4859 switch (scf_error()) { 4860 case SCF_ERROR_CONNECTION_BROKEN: 4861 case SCF_ERROR_NO_RESOURCES: 4862 case SCF_ERROR_BACKEND_READONLY: 4863 case SCF_ERROR_BACKEND_ACCESS: 4864 r = scferror2errno(scf_error()); 4865 goto out; 4866 4867 case SCF_ERROR_DELETED: 4868 warn(cf_missing, ient->sc_fmri, 4869 ud_name); 4870 r = 0; 4871 goto out; 4872 4873 case SCF_ERROR_PERMISSION_DENIED: 4874 warn(emsg_pg_deleted, ud_ctarg, 4875 ud_name); 4876 r = EPERM; 4877 goto out; 4878 4879 case SCF_ERROR_EXISTS: 4880 warn(emsg_pg_added, ud_ctarg, ud_name); 4881 r = EBUSY; 4882 goto out; 4883 4884 case SCF_ERROR_NOT_BOUND: 4885 case SCF_ERROR_HANDLE_MISMATCH: 4886 case SCF_ERROR_INVALID_ARGUMENT: 4887 case SCF_ERROR_NOT_SET: 4888 default: 4889 bad_error("entity_add_pg", scf_error()); 4890 } 4891 } 4892 } 4893 4894 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4895 switch (r) { 4896 case 0: 4897 break; 4898 4899 case ECANCELED: 4900 warn(cf_missing, ient->sc_fmri, ud_name); 4901 goto out; 4902 4903 case ECONNABORTED: 4904 case ENOMEM: 4905 case EBADF: 4906 goto out; 4907 4908 case EACCES: 4909 default: 4910 bad_error("load_pg", r); 4911 } 4912 4913 if (g_verbose) 4914 warn(upgrading, ient->sc_fmri, ud_name); 4915 4916 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4917 new_dpt_pgroup, 0, ient->sc_fmri); 4918 switch (r) { 4919 case 0: 4920 break; 4921 4922 case ECANCELED: 4923 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4924 r = EBUSY; 4925 goto out; 4926 4927 case EPERM: 4928 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4929 goto out; 4930 4931 case EBUSY: 4932 warn(emsg_pg_changed, ud_ctarg, ud_name); 4933 goto out; 4934 4935 case ECONNABORTED: 4936 case ENOMEM: 4937 case ENOSPC: 4938 case EROFS: 4939 case EACCES: 4940 case EINVAL: 4941 goto out; 4942 4943 default: 4944 bad_error("upgrade_pg", r); 4945 } 4946 break; 4947 4948 case 0: { 4949 scf_transaction_entry_t *ent; 4950 scf_value_t *val; 4951 4952 internal_pgroup_free(current_pg); 4953 4954 /* delete old pg */ 4955 if (g_verbose) 4956 warn(upgrading, ient->sc_fmri, ud_name); 4957 4958 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4959 switch (scf_error()) { 4960 case SCF_ERROR_CONNECTION_BROKEN: 4961 r = scferror2errno(scf_error()); 4962 goto out; 4963 4964 case SCF_ERROR_DELETED: 4965 warn(cf_missing, ient->sc_fmri, ud_name); 4966 r = 0; 4967 goto out; 4968 4969 case SCF_ERROR_NOT_FOUND: 4970 break; 4971 4972 case SCF_ERROR_INVALID_ARGUMENT: 4973 case SCF_ERROR_NOT_BOUND: 4974 case SCF_ERROR_NOT_SET: 4975 case SCF_ERROR_HANDLE_MISMATCH: 4976 default: 4977 bad_error("entity_get_pg", scf_error()); 4978 } 4979 } else if (scf_pg_delete(ud_pg) != 0) { 4980 switch (scf_error()) { 4981 case SCF_ERROR_DELETED: 4982 break; 4983 4984 case SCF_ERROR_CONNECTION_BROKEN: 4985 case SCF_ERROR_BACKEND_READONLY: 4986 case SCF_ERROR_BACKEND_ACCESS: 4987 r = scferror2errno(scf_error()); 4988 goto out; 4989 4990 case SCF_ERROR_PERMISSION_DENIED: 4991 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4992 r = scferror2errno(scf_error()); 4993 goto out; 4994 4995 case SCF_ERROR_NOT_SET: 4996 default: 4997 bad_error("scf_pg_delete", scf_error()); 4998 } 4999 } 5000 5001 /* import new one */ 5002 cbdata.sc_handle = g_hndl; 5003 cbdata.sc_trans = NULL; /* handled below */ 5004 cbdata.sc_flags = 0; 5005 5006 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 5007 if (r != UU_WALK_NEXT) { 5008 if (r != UU_WALK_ERROR) 5009 bad_error("lscf_dependent_import", r); 5010 5011 r = cbdata.sc_err; 5012 goto out; 5013 } 5014 5015 if (tx == NULL) 5016 break; 5017 5018 if ((ent = scf_entry_create(g_hndl)) == NULL || 5019 (val = scf_value_create(g_hndl)) == NULL) { 5020 if (scf_error() == SCF_ERROR_NO_MEMORY) 5021 return (ENOMEM); 5022 5023 bad_error("scf_entry_create", scf_error()); 5024 } 5025 5026 if (scf_transaction_property_change_type(tx, ent, ud_name, 5027 SCF_TYPE_FMRI) != 0) { 5028 switch (scf_error()) { 5029 case SCF_ERROR_CONNECTION_BROKEN: 5030 r = scferror2errno(scf_error()); 5031 goto out; 5032 5033 case SCF_ERROR_DELETED: 5034 warn(emsg_pg_deleted, ient->sc_fmri, 5035 "dependents"); 5036 r = EBUSY; 5037 goto out; 5038 5039 case SCF_ERROR_NOT_FOUND: 5040 break; 5041 5042 case SCF_ERROR_NOT_BOUND: 5043 case SCF_ERROR_HANDLE_MISMATCH: 5044 case SCF_ERROR_INVALID_ARGUMENT: 5045 case SCF_ERROR_NOT_SET: 5046 default: 5047 bad_error("scf_transaction_property_" 5048 "change_type", scf_error()); 5049 } 5050 5051 if (scf_transaction_property_new(tx, ent, ud_name, 5052 SCF_TYPE_FMRI) != 0) { 5053 switch (scf_error()) { 5054 case SCF_ERROR_CONNECTION_BROKEN: 5055 r = scferror2errno(scf_error()); 5056 goto out; 5057 5058 case SCF_ERROR_DELETED: 5059 warn(emsg_pg_deleted, ient->sc_fmri, 5060 "dependents"); 5061 r = EBUSY; 5062 goto out; 5063 5064 case SCF_ERROR_EXISTS: 5065 warn(emsg_pg_changed, ient->sc_fmri, 5066 "dependents"); 5067 r = EBUSY; 5068 goto out; 5069 5070 case SCF_ERROR_INVALID_ARGUMENT: 5071 case SCF_ERROR_HANDLE_MISMATCH: 5072 case SCF_ERROR_NOT_BOUND: 5073 case SCF_ERROR_NOT_SET: 5074 default: 5075 bad_error("scf_transaction_property_" 5076 "new", scf_error()); 5077 } 5078 } 5079 } 5080 5081 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 5082 new_dpt_pgroup->sc_pgroup_fmri) != 0) 5083 /* invalid sc_pgroup_fmri caught above */ 5084 bad_error("scf_value_set_from_string", 5085 scf_error()); 5086 5087 if (scf_entry_add_value(ent, val) != 0) 5088 bad_error("scf_entry_add_value", scf_error()); 5089 break; 5090 } 5091 5092 case -2: 5093 warn(li_corrupt, ient->sc_fmri); 5094 internal_pgroup_free(current_pg); 5095 r = EBADF; 5096 goto out; 5097 5098 case -1: 5099 default: 5100 /* invalid sc_pgroup_fmri caught above */ 5101 bad_error("fmri_equal", r); 5102 } 5103 5104 r = 0; 5105 5106 out: 5107 if (old_dpt_pgroup != NULL) 5108 internal_pgroup_free(old_dpt_pgroup); 5109 5110 return (r); 5111 } 5112 5113 /* 5114 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 5115 * would import it, except it seems to exist in the service anyway. Compare 5116 * the existent dependent with the one we would import, and report any 5117 * differences (if there are none, be silent). prop is the property which 5118 * represents the existent dependent (in the dependents property group) in the 5119 * entity corresponding to ient. 5120 * 5121 * Returns 5122 * 0 - success (Sort of. At least, we can continue importing.) 5123 * ECONNABORTED - repository connection broken 5124 * EBUSY - ancestor of prop was deleted (error printed) 5125 * ENOMEM - out of memory 5126 * EBADF - corrupt property group (error printed) 5127 * EINVAL - new_dpt_pgroup has invalid target (error printed) 5128 */ 5129 static int 5130 handle_dependent_conflict(const entity_t * const ient, 5131 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 5132 { 5133 int r; 5134 scf_type_t ty; 5135 scf_error_t scfe; 5136 void *tptr; 5137 int tissvc; 5138 pgroup_t *pgroup; 5139 5140 if (scf_property_get_value(prop, ud_val) != 0) { 5141 switch (scf_error()) { 5142 case SCF_ERROR_CONNECTION_BROKEN: 5143 return (scferror2errno(scf_error())); 5144 5145 case SCF_ERROR_DELETED: 5146 warn(emsg_pg_deleted, ient->sc_fmri, 5147 new_dpt_pgroup->sc_pgroup_name); 5148 return (EBUSY); 5149 5150 case SCF_ERROR_CONSTRAINT_VIOLATED: 5151 case SCF_ERROR_NOT_FOUND: 5152 warn(gettext("Conflict upgrading %s (not importing " 5153 "dependent \"%s\" because it already exists.) " 5154 "Warning: The \"%s/%2$s\" property has more or " 5155 "fewer than one value)).\n"), ient->sc_fmri, 5156 new_dpt_pgroup->sc_pgroup_name, "dependents"); 5157 return (0); 5158 5159 case SCF_ERROR_HANDLE_MISMATCH: 5160 case SCF_ERROR_NOT_BOUND: 5161 case SCF_ERROR_NOT_SET: 5162 case SCF_ERROR_PERMISSION_DENIED: 5163 default: 5164 bad_error("scf_property_get_value", 5165 scf_error()); 5166 } 5167 } 5168 5169 ty = scf_value_type(ud_val); 5170 assert(ty != SCF_TYPE_INVALID); 5171 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 5172 warn(gettext("Conflict upgrading %s (not importing dependent " 5173 "\"%s\" because it already exists). Warning: The " 5174 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 5175 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 5176 scf_type_to_string(ty), "dependents"); 5177 return (0); 5178 } 5179 5180 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 5181 0) 5182 bad_error("scf_value_get_as_string", scf_error()); 5183 5184 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 5185 switch (r) { 5186 case 0: 5187 warn(gettext("Conflict upgrading %s (not importing dependent " 5188 "\"%s\" (target \"%s\") because it already exists with " 5189 "target \"%s\").\n"), ient->sc_fmri, 5190 new_dpt_pgroup->sc_pgroup_name, 5191 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 5192 return (0); 5193 5194 case 1: 5195 break; 5196 5197 case -1: 5198 warn(gettext("Conflict upgrading %s (not importing dependent " 5199 "\"%s\" because it already exists). Warning: The current " 5200 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 5201 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5202 return (0); 5203 5204 case -2: 5205 warn(gettext("Dependent \"%s\" of %s has invalid target " 5206 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 5207 new_dpt_pgroup->sc_pgroup_fmri); 5208 return (EINVAL); 5209 5210 default: 5211 bad_error("fmri_equal", r); 5212 } 5213 5214 /* compare dependency pgs in target */ 5215 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 5216 switch (scfe) { 5217 case SCF_ERROR_NONE: 5218 break; 5219 5220 case SCF_ERROR_NO_MEMORY: 5221 return (ENOMEM); 5222 5223 case SCF_ERROR_NOT_FOUND: 5224 warn(emsg_dpt_dangling, ient->sc_fmri, 5225 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5226 return (0); 5227 5228 case SCF_ERROR_CONSTRAINT_VIOLATED: 5229 case SCF_ERROR_INVALID_ARGUMENT: 5230 default: 5231 bad_error("fmri_to_entity", scfe); 5232 } 5233 5234 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 5235 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 5236 switch (r) { 5237 case 0: 5238 break; 5239 5240 case ECONNABORTED: 5241 return (r); 5242 5243 case ECANCELED: 5244 warn(emsg_dpt_dangling, ient->sc_fmri, 5245 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 5246 return (0); 5247 5248 case EBADF: 5249 if (tissvc) 5250 warn(gettext("%s has an instance with a \"%s\" " 5251 "snapshot which is missing a snaplevel.\n"), 5252 ud_ctarg, "running"); 5253 else 5254 warn(gettext("%s has a \"%s\" snapshot which is " 5255 "missing a snaplevel.\n"), ud_ctarg, "running"); 5256 /* FALLTHROUGH */ 5257 5258 case ENOENT: 5259 warn(emsg_dpt_no_dep, ient->sc_fmri, 5260 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5261 new_dpt_pgroup->sc_pgroup_name); 5262 return (0); 5263 5264 case EINVAL: 5265 default: 5266 bad_error("entity_get_running_pg", r); 5267 } 5268 5269 pgroup = internal_pgroup_new(); 5270 if (pgroup == NULL) 5271 return (ENOMEM); 5272 5273 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 5274 switch (r) { 5275 case 0: 5276 break; 5277 5278 case ECONNABORTED: 5279 case EBADF: 5280 case ENOMEM: 5281 internal_pgroup_free(pgroup); 5282 return (r); 5283 5284 case ECANCELED: 5285 warn(emsg_dpt_no_dep, ient->sc_fmri, 5286 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 5287 new_dpt_pgroup->sc_pgroup_name); 5288 internal_pgroup_free(pgroup); 5289 return (0); 5290 5291 case EACCES: 5292 default: 5293 bad_error("load_pg", r); 5294 } 5295 5296 /* report differences */ 5297 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 5298 internal_pgroup_free(pgroup); 5299 return (0); 5300 } 5301 5302 /* 5303 * lipg is a property group in the last-import snapshot of ent, which is an 5304 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 5305 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 5306 * in ents's property groups, compare and upgrade ent appropriately. 5307 * 5308 * Returns 5309 * 0 - success 5310 * ECONNABORTED - repository connection broken 5311 * ENOMEM - out of memory 5312 * ENOSPC - configd is out of resources 5313 * EINVAL - ient has invalid dependent (error printed) 5314 * - ient has invalid pgroup_t (error printed) 5315 * ECANCELED - ent has been deleted 5316 * ENODEV - entity containing lipg has been deleted 5317 * - entity containing running has been deleted 5318 * EPERM - could not delete pg (permission denied) (error printed) 5319 * - couldn't upgrade dependents (permission denied) (error printed) 5320 * - couldn't import pg (permission denied) (error printed) 5321 * - couldn't upgrade pg (permission denied) (error printed) 5322 * EROFS - could not delete pg (repository read-only) 5323 * - couldn't upgrade dependents (repository read-only) 5324 * - couldn't import pg (repository read-only) 5325 * - couldn't upgrade pg (repository read-only) 5326 * EACCES - could not delete pg (backend access denied) 5327 * - couldn't upgrade dependents (backend access denied) 5328 * - couldn't import pg (backend access denied) 5329 * - couldn't upgrade pg (backend access denied) 5330 * - couldn't read property (backend access denied) 5331 * EBUSY - property group was added (error printed) 5332 * - property group was deleted (error printed) 5333 * - property group changed (error printed) 5334 * - "dependents" pg was added, changed, or deleted (error printed) 5335 * - dependent target deleted (error printed) 5336 * - dependent pg changed (error printed) 5337 * EBADF - imp_snpl is corrupt (error printed) 5338 * - ent has bad pg (error printed) 5339 * EEXIST - dependent collision in target service (error printed) 5340 */ 5341 static int 5342 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 5343 const scf_snaplevel_t *running) 5344 { 5345 int r; 5346 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 5347 scf_callback_t cbdata; 5348 5349 const char * const cf_pg_missing = 5350 gettext("Conflict upgrading %s (property group %s is missing)\n"); 5351 const char * const deleting = 5352 gettext("%s: Deleting property group \"%s\".\n"); 5353 5354 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5355 5356 /* Skip dependent property groups. */ 5357 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 5358 switch (scf_error()) { 5359 case SCF_ERROR_DELETED: 5360 return (ENODEV); 5361 5362 case SCF_ERROR_CONNECTION_BROKEN: 5363 return (ECONNABORTED); 5364 5365 case SCF_ERROR_NOT_SET: 5366 case SCF_ERROR_NOT_BOUND: 5367 default: 5368 bad_error("scf_pg_get_type", scf_error()); 5369 } 5370 } 5371 5372 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 5373 if (scf_pg_get_property(lipg, "external", NULL) == 0) 5374 return (0); 5375 5376 switch (scf_error()) { 5377 case SCF_ERROR_NOT_FOUND: 5378 break; 5379 5380 case SCF_ERROR_CONNECTION_BROKEN: 5381 return (ECONNABORTED); 5382 5383 case SCF_ERROR_DELETED: 5384 return (ENODEV); 5385 5386 case SCF_ERROR_INVALID_ARGUMENT: 5387 case SCF_ERROR_NOT_BOUND: 5388 case SCF_ERROR_HANDLE_MISMATCH: 5389 case SCF_ERROR_NOT_SET: 5390 default: 5391 bad_error("scf_pg_get_property", scf_error()); 5392 } 5393 } 5394 5395 /* lookup pg in new properties */ 5396 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 5397 switch (scf_error()) { 5398 case SCF_ERROR_DELETED: 5399 return (ENODEV); 5400 5401 case SCF_ERROR_CONNECTION_BROKEN: 5402 return (ECONNABORTED); 5403 5404 case SCF_ERROR_NOT_SET: 5405 case SCF_ERROR_NOT_BOUND: 5406 default: 5407 bad_error("scf_pg_get_name", scf_error()); 5408 } 5409 } 5410 5411 pgrp.sc_pgroup_name = imp_str; 5412 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 5413 5414 if (mpg != NULL) 5415 mpg->sc_pgroup_seen = 1; 5416 5417 /* Special handling for dependents */ 5418 if (strcmp(imp_str, "dependents") == 0) 5419 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 5420 5421 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 5422 return (upgrade_manifestfiles(NULL, ient, running, ent)); 5423 5424 if (mpg == NULL || mpg->sc_pgroup_delete) { 5425 /* property group was deleted from manifest */ 5426 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5427 switch (scf_error()) { 5428 case SCF_ERROR_NOT_FOUND: 5429 return (0); 5430 5431 case SCF_ERROR_DELETED: 5432 case SCF_ERROR_CONNECTION_BROKEN: 5433 return (scferror2errno(scf_error())); 5434 5435 case SCF_ERROR_INVALID_ARGUMENT: 5436 case SCF_ERROR_HANDLE_MISMATCH: 5437 case SCF_ERROR_NOT_BOUND: 5438 case SCF_ERROR_NOT_SET: 5439 default: 5440 bad_error("entity_get_pg", scf_error()); 5441 } 5442 } 5443 5444 if (mpg != NULL && mpg->sc_pgroup_delete) { 5445 if (g_verbose) 5446 warn(deleting, ient->sc_fmri, imp_str); 5447 if (scf_pg_delete(imp_pg2) == 0) 5448 return (0); 5449 5450 switch (scf_error()) { 5451 case SCF_ERROR_DELETED: 5452 return (0); 5453 5454 case SCF_ERROR_CONNECTION_BROKEN: 5455 case SCF_ERROR_BACKEND_READONLY: 5456 case SCF_ERROR_BACKEND_ACCESS: 5457 return (scferror2errno(scf_error())); 5458 5459 case SCF_ERROR_PERMISSION_DENIED: 5460 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 5461 return (scferror2errno(scf_error())); 5462 5463 case SCF_ERROR_NOT_SET: 5464 default: 5465 bad_error("scf_pg_delete", scf_error()); 5466 } 5467 } 5468 5469 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5470 switch (r) { 5471 case 0: 5472 break; 5473 5474 case ECANCELED: 5475 return (ENODEV); 5476 5477 case ECONNABORTED: 5478 case ENOMEM: 5479 case EBADF: 5480 case EACCES: 5481 return (r); 5482 5483 default: 5484 bad_error("load_pg", r); 5485 } 5486 5487 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5488 switch (r) { 5489 case 0: 5490 break; 5491 5492 case ECANCELED: 5493 case ECONNABORTED: 5494 case ENOMEM: 5495 case EBADF: 5496 case EACCES: 5497 internal_pgroup_free(lipg_i); 5498 return (r); 5499 5500 default: 5501 bad_error("load_pg", r); 5502 } 5503 5504 if (pg_equal(lipg_i, curpg_i)) { 5505 if (g_verbose) 5506 warn(deleting, ient->sc_fmri, imp_str); 5507 if (scf_pg_delete(imp_pg2) != 0) { 5508 switch (scf_error()) { 5509 case SCF_ERROR_DELETED: 5510 break; 5511 5512 case SCF_ERROR_CONNECTION_BROKEN: 5513 internal_pgroup_free(lipg_i); 5514 internal_pgroup_free(curpg_i); 5515 return (ECONNABORTED); 5516 5517 case SCF_ERROR_NOT_SET: 5518 case SCF_ERROR_NOT_BOUND: 5519 default: 5520 bad_error("scf_pg_delete", scf_error()); 5521 } 5522 } 5523 } else { 5524 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5525 } 5526 5527 internal_pgroup_free(lipg_i); 5528 internal_pgroup_free(curpg_i); 5529 5530 return (0); 5531 } 5532 5533 /* 5534 * Only dependent pgs can have override set, and we skipped those 5535 * above. 5536 */ 5537 assert(!mpg->sc_pgroup_override); 5538 5539 /* compare */ 5540 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5541 switch (r) { 5542 case 0: 5543 break; 5544 5545 case ECANCELED: 5546 return (ENODEV); 5547 5548 case ECONNABORTED: 5549 case EBADF: 5550 case ENOMEM: 5551 case EACCES: 5552 return (r); 5553 5554 default: 5555 bad_error("load_pg", r); 5556 } 5557 5558 if (pg_equal(mpg, lipg_i)) { 5559 /* The manifest pg has not changed. Move on. */ 5560 r = 0; 5561 goto out; 5562 } 5563 5564 /* upgrade current properties according to lipg & mpg */ 5565 if (running != NULL) 5566 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5567 else 5568 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5569 if (r != 0) { 5570 switch (scf_error()) { 5571 case SCF_ERROR_CONNECTION_BROKEN: 5572 r = scferror2errno(scf_error()); 5573 goto out; 5574 5575 case SCF_ERROR_DELETED: 5576 if (running != NULL) 5577 r = ENODEV; 5578 else 5579 r = ECANCELED; 5580 goto out; 5581 5582 case SCF_ERROR_NOT_FOUND: 5583 break; 5584 5585 case SCF_ERROR_INVALID_ARGUMENT: 5586 case SCF_ERROR_HANDLE_MISMATCH: 5587 case SCF_ERROR_NOT_BOUND: 5588 case SCF_ERROR_NOT_SET: 5589 default: 5590 bad_error("entity_get_pg", scf_error()); 5591 } 5592 5593 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5594 5595 r = 0; 5596 goto out; 5597 } 5598 5599 r = load_pg_attrs(imp_pg2, &curpg_i); 5600 switch (r) { 5601 case 0: 5602 break; 5603 5604 case ECANCELED: 5605 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5606 r = 0; 5607 goto out; 5608 5609 case ECONNABORTED: 5610 case ENOMEM: 5611 goto out; 5612 5613 default: 5614 bad_error("load_pg_attrs", r); 5615 } 5616 5617 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5618 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5619 internal_pgroup_free(curpg_i); 5620 r = 0; 5621 goto out; 5622 } 5623 5624 internal_pgroup_free(curpg_i); 5625 5626 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5627 switch (r) { 5628 case 0: 5629 break; 5630 5631 case ECANCELED: 5632 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5633 r = 0; 5634 goto out; 5635 5636 case ECONNABORTED: 5637 case EBADF: 5638 case ENOMEM: 5639 case EACCES: 5640 goto out; 5641 5642 default: 5643 bad_error("load_pg", r); 5644 } 5645 5646 if (pg_equal(lipg_i, curpg_i) && 5647 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5648 int do_delete = 1; 5649 5650 if (g_verbose) 5651 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5652 ient->sc_fmri, mpg->sc_pgroup_name); 5653 5654 internal_pgroup_free(curpg_i); 5655 5656 if (running != NULL && 5657 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5658 switch (scf_error()) { 5659 case SCF_ERROR_DELETED: 5660 r = ECANCELED; 5661 goto out; 5662 5663 case SCF_ERROR_NOT_FOUND: 5664 do_delete = 0; 5665 break; 5666 5667 case SCF_ERROR_CONNECTION_BROKEN: 5668 r = scferror2errno(scf_error()); 5669 goto out; 5670 5671 case SCF_ERROR_HANDLE_MISMATCH: 5672 case SCF_ERROR_INVALID_ARGUMENT: 5673 case SCF_ERROR_NOT_SET: 5674 case SCF_ERROR_NOT_BOUND: 5675 default: 5676 bad_error("entity_get_pg", scf_error()); 5677 } 5678 } 5679 5680 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5681 switch (scf_error()) { 5682 case SCF_ERROR_DELETED: 5683 break; 5684 5685 case SCF_ERROR_CONNECTION_BROKEN: 5686 case SCF_ERROR_BACKEND_READONLY: 5687 case SCF_ERROR_BACKEND_ACCESS: 5688 r = scferror2errno(scf_error()); 5689 goto out; 5690 5691 case SCF_ERROR_PERMISSION_DENIED: 5692 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5693 ient->sc_fmri); 5694 r = scferror2errno(scf_error()); 5695 goto out; 5696 5697 case SCF_ERROR_NOT_SET: 5698 case SCF_ERROR_NOT_BOUND: 5699 default: 5700 bad_error("scf_pg_delete", scf_error()); 5701 } 5702 } 5703 5704 cbdata.sc_handle = g_hndl; 5705 cbdata.sc_parent = ent; 5706 cbdata.sc_service = issvc; 5707 cbdata.sc_flags = 0; 5708 cbdata.sc_source_fmri = ient->sc_fmri; 5709 cbdata.sc_target_fmri = ient->sc_fmri; 5710 5711 r = entity_pgroup_import(mpg, &cbdata); 5712 switch (r) { 5713 case UU_WALK_NEXT: 5714 r = 0; 5715 goto out; 5716 5717 case UU_WALK_ERROR: 5718 if (cbdata.sc_err == EEXIST) { 5719 warn(emsg_pg_added, ient->sc_fmri, 5720 mpg->sc_pgroup_name); 5721 r = EBUSY; 5722 } else { 5723 r = cbdata.sc_err; 5724 } 5725 goto out; 5726 5727 default: 5728 bad_error("entity_pgroup_import", r); 5729 } 5730 } 5731 5732 if (running != NULL && 5733 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5734 switch (scf_error()) { 5735 case SCF_ERROR_CONNECTION_BROKEN: 5736 case SCF_ERROR_DELETED: 5737 r = scferror2errno(scf_error()); 5738 goto out; 5739 5740 case SCF_ERROR_NOT_FOUND: 5741 break; 5742 5743 case SCF_ERROR_HANDLE_MISMATCH: 5744 case SCF_ERROR_INVALID_ARGUMENT: 5745 case SCF_ERROR_NOT_SET: 5746 case SCF_ERROR_NOT_BOUND: 5747 default: 5748 bad_error("entity_get_pg", scf_error()); 5749 } 5750 5751 cbdata.sc_handle = g_hndl; 5752 cbdata.sc_parent = ent; 5753 cbdata.sc_service = issvc; 5754 cbdata.sc_flags = SCI_FORCE; 5755 cbdata.sc_source_fmri = ient->sc_fmri; 5756 cbdata.sc_target_fmri = ient->sc_fmri; 5757 5758 r = entity_pgroup_import(mpg, &cbdata); 5759 switch (r) { 5760 case UU_WALK_NEXT: 5761 r = 0; 5762 goto out; 5763 5764 case UU_WALK_ERROR: 5765 if (cbdata.sc_err == EEXIST) { 5766 warn(emsg_pg_added, ient->sc_fmri, 5767 mpg->sc_pgroup_name); 5768 r = EBUSY; 5769 } else { 5770 r = cbdata.sc_err; 5771 } 5772 goto out; 5773 5774 default: 5775 bad_error("entity_pgroup_import", r); 5776 } 5777 } 5778 5779 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5780 internal_pgroup_free(curpg_i); 5781 switch (r) { 5782 case 0: 5783 ient->sc_import_state = IMPORT_PROP_BEGUN; 5784 break; 5785 5786 case ECANCELED: 5787 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5788 r = EBUSY; 5789 break; 5790 5791 case EPERM: 5792 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5793 break; 5794 5795 case EBUSY: 5796 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5797 break; 5798 5799 case ECONNABORTED: 5800 case ENOMEM: 5801 case ENOSPC: 5802 case EROFS: 5803 case EACCES: 5804 case EINVAL: 5805 break; 5806 5807 default: 5808 bad_error("upgrade_pg", r); 5809 } 5810 5811 out: 5812 internal_pgroup_free(lipg_i); 5813 return (r); 5814 } 5815 5816 /* 5817 * Upgrade the properties of ent according to snpl & ient. 5818 * 5819 * Returns 5820 * 0 - success 5821 * ECONNABORTED - repository connection broken 5822 * ENOMEM - out of memory 5823 * ENOSPC - configd is out of resources 5824 * ECANCELED - ent was deleted 5825 * ENODEV - entity containing snpl was deleted 5826 * - entity containing running was deleted 5827 * EBADF - imp_snpl is corrupt (error printed) 5828 * - ent has corrupt pg (error printed) 5829 * - dependent has corrupt pg (error printed) 5830 * - dependent target has a corrupt snapshot (error printed) 5831 * EBUSY - pg was added, changed, or deleted (error printed) 5832 * - dependent target was deleted (error printed) 5833 * - dependent pg changed (error printed) 5834 * EINVAL - invalid property group name (error printed) 5835 * - invalid property name (error printed) 5836 * - invalid value (error printed) 5837 * - ient has invalid pgroup or dependent (error printed) 5838 * EPERM - could not create property group (permission denied) (error printed) 5839 * - could not modify property group (permission denied) (error printed) 5840 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5841 * EROFS - could not create property group (repository read-only) 5842 * - couldn't delete, upgrade, or import pg or dependent 5843 * EACCES - could not create property group (backend access denied) 5844 * - couldn't delete, upgrade, or import pg or dependent 5845 * EEXIST - dependent collision in target service (error printed) 5846 */ 5847 static int 5848 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5849 entity_t *ient) 5850 { 5851 pgroup_t *pg, *rpg; 5852 int r; 5853 uu_list_t *pgs = ient->sc_pgroups; 5854 5855 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5856 5857 /* clear sc_sceen for pgs */ 5858 if (uu_list_walk(pgs, clear_int, 5859 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5860 bad_error("uu_list_walk", uu_error()); 5861 5862 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5863 switch (scf_error()) { 5864 case SCF_ERROR_DELETED: 5865 return (ENODEV); 5866 5867 case SCF_ERROR_CONNECTION_BROKEN: 5868 return (ECONNABORTED); 5869 5870 case SCF_ERROR_NOT_SET: 5871 case SCF_ERROR_NOT_BOUND: 5872 case SCF_ERROR_HANDLE_MISMATCH: 5873 default: 5874 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5875 } 5876 } 5877 5878 for (;;) { 5879 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5880 if (r == 0) 5881 break; 5882 if (r == 1) { 5883 r = process_old_pg(imp_pg, ient, ent, running); 5884 switch (r) { 5885 case 0: 5886 break; 5887 5888 case ECONNABORTED: 5889 case ENOMEM: 5890 case ENOSPC: 5891 case ECANCELED: 5892 case ENODEV: 5893 case EPERM: 5894 case EROFS: 5895 case EACCES: 5896 case EBADF: 5897 case EBUSY: 5898 case EINVAL: 5899 case EEXIST: 5900 return (r); 5901 5902 default: 5903 bad_error("process_old_pg", r); 5904 } 5905 continue; 5906 } 5907 if (r != -1) 5908 bad_error("scf_iter_next_pg", r); 5909 5910 switch (scf_error()) { 5911 case SCF_ERROR_DELETED: 5912 return (ENODEV); 5913 5914 case SCF_ERROR_CONNECTION_BROKEN: 5915 return (ECONNABORTED); 5916 5917 case SCF_ERROR_HANDLE_MISMATCH: 5918 case SCF_ERROR_NOT_BOUND: 5919 case SCF_ERROR_NOT_SET: 5920 case SCF_ERROR_INVALID_ARGUMENT: 5921 default: 5922 bad_error("scf_iter_next_pg", scf_error()); 5923 } 5924 } 5925 5926 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5927 if (pg->sc_pgroup_seen) 5928 continue; 5929 5930 /* pg is new */ 5931 5932 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5933 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5934 ent); 5935 switch (r) { 5936 case 0: 5937 break; 5938 5939 case ECONNABORTED: 5940 case ENOMEM: 5941 case ENOSPC: 5942 case ECANCELED: 5943 case ENODEV: 5944 case EBADF: 5945 case EBUSY: 5946 case EINVAL: 5947 case EPERM: 5948 case EROFS: 5949 case EACCES: 5950 case EEXIST: 5951 return (r); 5952 5953 default: 5954 bad_error("upgrade_dependents", r); 5955 } 5956 continue; 5957 } 5958 5959 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 5960 r = upgrade_manifestfiles(pg, ient, running, ent); 5961 switch (r) { 5962 case 0: 5963 break; 5964 5965 case ECONNABORTED: 5966 case ENOMEM: 5967 case ENOSPC: 5968 case ECANCELED: 5969 case ENODEV: 5970 case EBADF: 5971 case EBUSY: 5972 case EINVAL: 5973 case EPERM: 5974 case EROFS: 5975 case EACCES: 5976 case EEXIST: 5977 return (r); 5978 5979 default: 5980 bad_error("upgrade_manifestfiles", r); 5981 } 5982 continue; 5983 } 5984 5985 if (running != NULL) { 5986 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 5987 imp_pg); 5988 } else { 5989 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 5990 imp_pg); 5991 } 5992 if (r != 0) { 5993 scf_callback_t cbdata; 5994 5995 switch (scf_error()) { 5996 case SCF_ERROR_NOT_FOUND: 5997 break; 5998 5999 case SCF_ERROR_CONNECTION_BROKEN: 6000 return (scferror2errno(scf_error())); 6001 6002 case SCF_ERROR_DELETED: 6003 if (running != NULL) 6004 return (ENODEV); 6005 else 6006 return (scferror2errno(scf_error())); 6007 6008 case SCF_ERROR_INVALID_ARGUMENT: 6009 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 6010 pg->sc_pgroup_name); 6011 return (EINVAL); 6012 6013 case SCF_ERROR_NOT_SET: 6014 case SCF_ERROR_HANDLE_MISMATCH: 6015 case SCF_ERROR_NOT_BOUND: 6016 default: 6017 bad_error("entity_get_pg", scf_error()); 6018 } 6019 6020 /* User doesn't have pg, so import it. */ 6021 6022 cbdata.sc_handle = g_hndl; 6023 cbdata.sc_parent = ent; 6024 cbdata.sc_service = issvc; 6025 cbdata.sc_flags = SCI_FORCE; 6026 cbdata.sc_source_fmri = ient->sc_fmri; 6027 cbdata.sc_target_fmri = ient->sc_fmri; 6028 6029 r = entity_pgroup_import(pg, &cbdata); 6030 switch (r) { 6031 case UU_WALK_NEXT: 6032 ient->sc_import_state = IMPORT_PROP_BEGUN; 6033 continue; 6034 6035 case UU_WALK_ERROR: 6036 if (cbdata.sc_err == EEXIST) { 6037 warn(emsg_pg_added, ient->sc_fmri, 6038 pg->sc_pgroup_name); 6039 return (EBUSY); 6040 } 6041 return (cbdata.sc_err); 6042 6043 default: 6044 bad_error("entity_pgroup_import", r); 6045 } 6046 } 6047 6048 /* report differences between pg & current */ 6049 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 6050 switch (r) { 6051 case 0: 6052 break; 6053 6054 case ECANCELED: 6055 warn(emsg_pg_deleted, ient->sc_fmri, 6056 pg->sc_pgroup_name); 6057 return (EBUSY); 6058 6059 case ECONNABORTED: 6060 case EBADF: 6061 case ENOMEM: 6062 case EACCES: 6063 return (r); 6064 6065 default: 6066 bad_error("load_pg", r); 6067 } 6068 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 6069 internal_pgroup_free(rpg); 6070 rpg = NULL; 6071 } 6072 6073 return (0); 6074 } 6075 6076 /* 6077 * Import an instance. If it doesn't exist, create it. If it has 6078 * a last-import snapshot, upgrade its properties. Finish by updating its 6079 * last-import snapshot. If it doesn't have a last-import snapshot then it 6080 * could have been created for a dependent tag in another manifest. Import the 6081 * new properties. If there's a conflict, don't override, like now? 6082 * 6083 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 6084 * lcbdata->sc_err to 6085 * ECONNABORTED - repository connection broken 6086 * ENOMEM - out of memory 6087 * ENOSPC - svc.configd is out of resources 6088 * EEXIST - dependency collision in dependent service (error printed) 6089 * EPERM - couldn't create temporary instance (permission denied) 6090 * - couldn't import into temporary instance (permission denied) 6091 * - couldn't take snapshot (permission denied) 6092 * - couldn't upgrade properties (permission denied) 6093 * - couldn't import properties (permission denied) 6094 * - couldn't import dependents (permission denied) 6095 * EROFS - couldn't create temporary instance (repository read-only) 6096 * - couldn't import into temporary instance (repository read-only) 6097 * - couldn't upgrade properties (repository read-only) 6098 * - couldn't import properties (repository read-only) 6099 * - couldn't import dependents (repository read-only) 6100 * EACCES - couldn't create temporary instance (backend access denied) 6101 * - couldn't import into temporary instance (backend access denied) 6102 * - couldn't upgrade properties (backend access denied) 6103 * - couldn't import properties (backend access denied) 6104 * - couldn't import dependents (backend access denied) 6105 * EINVAL - invalid instance name (error printed) 6106 * - invalid pgroup_t's (error printed) 6107 * - invalid dependents (error printed) 6108 * EBUSY - temporary service deleted (error printed) 6109 * - temporary instance deleted (error printed) 6110 * - temporary instance changed (error printed) 6111 * - temporary instance already exists (error printed) 6112 * - instance deleted (error printed) 6113 * EBADF - instance has corrupt last-import snapshot (error printed) 6114 * - instance is corrupt (error printed) 6115 * - dependent has corrupt pg (error printed) 6116 * - dependent target has a corrupt snapshot (error printed) 6117 * -1 - unknown libscf error (error printed) 6118 */ 6119 static int 6120 lscf_instance_import(void *v, void *pvt) 6121 { 6122 entity_t *inst = v; 6123 scf_callback_t ctx; 6124 scf_callback_t *lcbdata = pvt; 6125 scf_service_t *rsvc = lcbdata->sc_parent; 6126 int r; 6127 scf_snaplevel_t *running; 6128 int flags = lcbdata->sc_flags; 6129 6130 const char * const emsg_tdel = 6131 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 6132 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 6133 "changed unexpectedly.\n"); 6134 const char * const emsg_del = gettext("%s changed unexpectedly " 6135 "(instance \"%s\" was deleted.)\n"); 6136 const char * const emsg_badsnap = gettext( 6137 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 6138 6139 /* 6140 * prepare last-import snapshot: 6141 * create temporary instance (service was precreated) 6142 * populate with properties from bundle 6143 * take snapshot 6144 */ 6145 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 6146 switch (scf_error()) { 6147 case SCF_ERROR_CONNECTION_BROKEN: 6148 case SCF_ERROR_NO_RESOURCES: 6149 case SCF_ERROR_BACKEND_READONLY: 6150 case SCF_ERROR_BACKEND_ACCESS: 6151 return (stash_scferror(lcbdata)); 6152 6153 case SCF_ERROR_EXISTS: 6154 warn(gettext("Temporary service svc:/%s " 6155 "changed unexpectedly (instance \"%s\" added).\n"), 6156 imp_tsname, inst->sc_name); 6157 lcbdata->sc_err = EBUSY; 6158 return (UU_WALK_ERROR); 6159 6160 case SCF_ERROR_DELETED: 6161 warn(gettext("Temporary service svc:/%s " 6162 "was deleted unexpectedly.\n"), imp_tsname); 6163 lcbdata->sc_err = EBUSY; 6164 return (UU_WALK_ERROR); 6165 6166 case SCF_ERROR_INVALID_ARGUMENT: 6167 warn(gettext("Invalid instance name \"%s\".\n"), 6168 inst->sc_name); 6169 return (stash_scferror(lcbdata)); 6170 6171 case SCF_ERROR_PERMISSION_DENIED: 6172 warn(gettext("Could not create temporary instance " 6173 "\"%s\" in svc:/%s (permission denied).\n"), 6174 inst->sc_name, imp_tsname); 6175 return (stash_scferror(lcbdata)); 6176 6177 case SCF_ERROR_HANDLE_MISMATCH: 6178 case SCF_ERROR_NOT_BOUND: 6179 case SCF_ERROR_NOT_SET: 6180 default: 6181 bad_error("scf_service_add_instance", scf_error()); 6182 } 6183 } 6184 6185 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6186 inst->sc_name); 6187 if (r < 0) 6188 bad_error("snprintf", errno); 6189 6190 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 6191 lcbdata->sc_flags | SCI_NOENABLED); 6192 switch (r) { 6193 case 0: 6194 break; 6195 6196 case ECANCELED: 6197 warn(emsg_tdel, imp_tsname, inst->sc_name); 6198 lcbdata->sc_err = EBUSY; 6199 r = UU_WALK_ERROR; 6200 goto deltemp; 6201 6202 case EEXIST: 6203 warn(emsg_tchg, imp_tsname, inst->sc_name); 6204 lcbdata->sc_err = EBUSY; 6205 r = UU_WALK_ERROR; 6206 goto deltemp; 6207 6208 case ECONNABORTED: 6209 goto connaborted; 6210 6211 case ENOMEM: 6212 case ENOSPC: 6213 case EPERM: 6214 case EROFS: 6215 case EACCES: 6216 case EINVAL: 6217 case EBUSY: 6218 lcbdata->sc_err = r; 6219 r = UU_WALK_ERROR; 6220 goto deltemp; 6221 6222 default: 6223 bad_error("lscf_import_instance_pgs", r); 6224 } 6225 6226 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 6227 inst->sc_name); 6228 if (r < 0) 6229 bad_error("snprintf", errno); 6230 6231 ctx.sc_handle = lcbdata->sc_handle; 6232 ctx.sc_parent = imp_tinst; 6233 ctx.sc_service = 0; 6234 ctx.sc_source_fmri = inst->sc_fmri; 6235 ctx.sc_target_fmri = imp_str; 6236 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 6237 UU_DEFAULT) != 0) { 6238 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6239 bad_error("uu_list_walk", uu_error()); 6240 6241 switch (ctx.sc_err) { 6242 case ECONNABORTED: 6243 goto connaborted; 6244 6245 case ECANCELED: 6246 warn(emsg_tdel, imp_tsname, inst->sc_name); 6247 lcbdata->sc_err = EBUSY; 6248 break; 6249 6250 case EEXIST: 6251 warn(emsg_tchg, imp_tsname, inst->sc_name); 6252 lcbdata->sc_err = EBUSY; 6253 break; 6254 6255 default: 6256 lcbdata->sc_err = ctx.sc_err; 6257 } 6258 r = UU_WALK_ERROR; 6259 goto deltemp; 6260 } 6261 6262 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 6263 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 6264 switch (scf_error()) { 6265 case SCF_ERROR_CONNECTION_BROKEN: 6266 goto connaborted; 6267 6268 case SCF_ERROR_NO_RESOURCES: 6269 r = stash_scferror(lcbdata); 6270 goto deltemp; 6271 6272 case SCF_ERROR_EXISTS: 6273 warn(emsg_tchg, imp_tsname, inst->sc_name); 6274 lcbdata->sc_err = EBUSY; 6275 r = UU_WALK_ERROR; 6276 goto deltemp; 6277 6278 case SCF_ERROR_PERMISSION_DENIED: 6279 warn(gettext("Could not take \"%s\" snapshot of %s " 6280 "(permission denied).\n"), snap_lastimport, 6281 imp_str); 6282 r = stash_scferror(lcbdata); 6283 goto deltemp; 6284 6285 default: 6286 scfwarn(); 6287 lcbdata->sc_err = -1; 6288 r = UU_WALK_ERROR; 6289 goto deltemp; 6290 6291 case SCF_ERROR_HANDLE_MISMATCH: 6292 case SCF_ERROR_INVALID_ARGUMENT: 6293 case SCF_ERROR_NOT_SET: 6294 bad_error("_scf_snapshot_take_new_named", scf_error()); 6295 } 6296 } 6297 6298 if (lcbdata->sc_flags & SCI_FRESH) 6299 goto fresh; 6300 6301 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 6302 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6303 imp_lisnap) != 0) { 6304 switch (scf_error()) { 6305 case SCF_ERROR_DELETED: 6306 warn(emsg_del, inst->sc_parent->sc_fmri, 6307 inst->sc_name); 6308 lcbdata->sc_err = EBUSY; 6309 r = UU_WALK_ERROR; 6310 goto deltemp; 6311 6312 case SCF_ERROR_NOT_FOUND: 6313 flags |= SCI_FORCE; 6314 goto nosnap; 6315 6316 case SCF_ERROR_CONNECTION_BROKEN: 6317 goto connaborted; 6318 6319 case SCF_ERROR_INVALID_ARGUMENT: 6320 case SCF_ERROR_HANDLE_MISMATCH: 6321 case SCF_ERROR_NOT_BOUND: 6322 case SCF_ERROR_NOT_SET: 6323 default: 6324 bad_error("scf_instance_get_snapshot", 6325 scf_error()); 6326 } 6327 } 6328 6329 /* upgrade */ 6330 6331 /* 6332 * compare new properties with last-import properties 6333 * upgrade current properties 6334 */ 6335 /* clear sc_sceen for pgs */ 6336 if (uu_list_walk(inst->sc_pgroups, clear_int, 6337 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 6338 0) 6339 bad_error("uu_list_walk", uu_error()); 6340 6341 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 6342 switch (r) { 6343 case 0: 6344 break; 6345 6346 case ECONNABORTED: 6347 goto connaborted; 6348 6349 case ECANCELED: 6350 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6351 lcbdata->sc_err = EBUSY; 6352 r = UU_WALK_ERROR; 6353 goto deltemp; 6354 6355 case ENOENT: 6356 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 6357 lcbdata->sc_err = EBADF; 6358 r = UU_WALK_ERROR; 6359 goto deltemp; 6360 6361 default: 6362 bad_error("get_snaplevel", r); 6363 } 6364 6365 if (scf_instance_get_snapshot(imp_inst, snap_running, 6366 imp_rsnap) != 0) { 6367 switch (scf_error()) { 6368 case SCF_ERROR_DELETED: 6369 warn(emsg_del, inst->sc_parent->sc_fmri, 6370 inst->sc_name); 6371 lcbdata->sc_err = EBUSY; 6372 r = UU_WALK_ERROR; 6373 goto deltemp; 6374 6375 case SCF_ERROR_NOT_FOUND: 6376 break; 6377 6378 case SCF_ERROR_CONNECTION_BROKEN: 6379 goto connaborted; 6380 6381 case SCF_ERROR_INVALID_ARGUMENT: 6382 case SCF_ERROR_HANDLE_MISMATCH: 6383 case SCF_ERROR_NOT_BOUND: 6384 case SCF_ERROR_NOT_SET: 6385 default: 6386 bad_error("scf_instance_get_snapshot", 6387 scf_error()); 6388 } 6389 6390 running = NULL; 6391 } else { 6392 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 6393 switch (r) { 6394 case 0: 6395 running = imp_rsnpl; 6396 break; 6397 6398 case ECONNABORTED: 6399 goto connaborted; 6400 6401 case ECANCELED: 6402 warn(emsg_del, inst->sc_parent->sc_fmri, 6403 inst->sc_name); 6404 lcbdata->sc_err = EBUSY; 6405 r = UU_WALK_ERROR; 6406 goto deltemp; 6407 6408 case ENOENT: 6409 warn(emsg_badsnap, snap_running, inst->sc_fmri); 6410 lcbdata->sc_err = EBADF; 6411 r = UU_WALK_ERROR; 6412 goto deltemp; 6413 6414 default: 6415 bad_error("get_snaplevel", r); 6416 } 6417 } 6418 6419 r = upgrade_props(imp_inst, running, imp_snpl, inst); 6420 switch (r) { 6421 case 0: 6422 break; 6423 6424 case ECANCELED: 6425 case ENODEV: 6426 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 6427 lcbdata->sc_err = EBUSY; 6428 r = UU_WALK_ERROR; 6429 goto deltemp; 6430 6431 case ECONNABORTED: 6432 goto connaborted; 6433 6434 case ENOMEM: 6435 case ENOSPC: 6436 case EBADF: 6437 case EBUSY: 6438 case EINVAL: 6439 case EPERM: 6440 case EROFS: 6441 case EACCES: 6442 case EEXIST: 6443 lcbdata->sc_err = r; 6444 r = UU_WALK_ERROR; 6445 goto deltemp; 6446 6447 default: 6448 bad_error("upgrade_props", r); 6449 } 6450 6451 inst->sc_import_state = IMPORT_PROP_DONE; 6452 } else { 6453 switch (scf_error()) { 6454 case SCF_ERROR_CONNECTION_BROKEN: 6455 goto connaborted; 6456 6457 case SCF_ERROR_NOT_FOUND: 6458 break; 6459 6460 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6461 case SCF_ERROR_HANDLE_MISMATCH: 6462 case SCF_ERROR_NOT_BOUND: 6463 case SCF_ERROR_NOT_SET: 6464 default: 6465 bad_error("scf_service_get_instance", scf_error()); 6466 } 6467 6468 fresh: 6469 /* create instance */ 6470 if (scf_service_add_instance(rsvc, inst->sc_name, 6471 imp_inst) != 0) { 6472 switch (scf_error()) { 6473 case SCF_ERROR_CONNECTION_BROKEN: 6474 goto connaborted; 6475 6476 case SCF_ERROR_NO_RESOURCES: 6477 case SCF_ERROR_BACKEND_READONLY: 6478 case SCF_ERROR_BACKEND_ACCESS: 6479 r = stash_scferror(lcbdata); 6480 goto deltemp; 6481 6482 case SCF_ERROR_EXISTS: 6483 warn(gettext("%s changed unexpectedly " 6484 "(instance \"%s\" added).\n"), 6485 inst->sc_parent->sc_fmri, inst->sc_name); 6486 lcbdata->sc_err = EBUSY; 6487 r = UU_WALK_ERROR; 6488 goto deltemp; 6489 6490 case SCF_ERROR_PERMISSION_DENIED: 6491 warn(gettext("Could not create \"%s\" instance " 6492 "in %s (permission denied).\n"), 6493 inst->sc_name, inst->sc_parent->sc_fmri); 6494 r = stash_scferror(lcbdata); 6495 goto deltemp; 6496 6497 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6498 case SCF_ERROR_HANDLE_MISMATCH: 6499 case SCF_ERROR_NOT_BOUND: 6500 case SCF_ERROR_NOT_SET: 6501 default: 6502 bad_error("scf_service_add_instance", 6503 scf_error()); 6504 } 6505 } 6506 6507 nosnap: 6508 /* 6509 * Create a last-import snapshot to serve as an attachment 6510 * point for the real one from the temporary instance. Since 6511 * the contents is irrelevant, take it now, while the instance 6512 * is empty, to minimize svc.configd's work. 6513 */ 6514 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6515 imp_lisnap) != 0) { 6516 switch (scf_error()) { 6517 case SCF_ERROR_CONNECTION_BROKEN: 6518 goto connaborted; 6519 6520 case SCF_ERROR_NO_RESOURCES: 6521 r = stash_scferror(lcbdata); 6522 goto deltemp; 6523 6524 case SCF_ERROR_EXISTS: 6525 warn(gettext("%s changed unexpectedly " 6526 "(snapshot \"%s\" added).\n"), 6527 inst->sc_fmri, snap_lastimport); 6528 lcbdata->sc_err = EBUSY; 6529 r = UU_WALK_ERROR; 6530 goto deltemp; 6531 6532 case SCF_ERROR_PERMISSION_DENIED: 6533 warn(gettext("Could not take \"%s\" snapshot " 6534 "of %s (permission denied).\n"), 6535 snap_lastimport, inst->sc_fmri); 6536 r = stash_scferror(lcbdata); 6537 goto deltemp; 6538 6539 default: 6540 scfwarn(); 6541 lcbdata->sc_err = -1; 6542 r = UU_WALK_ERROR; 6543 goto deltemp; 6544 6545 case SCF_ERROR_NOT_SET: 6546 case SCF_ERROR_INTERNAL: 6547 case SCF_ERROR_INVALID_ARGUMENT: 6548 case SCF_ERROR_HANDLE_MISMATCH: 6549 bad_error("_scf_snapshot_take_new", 6550 scf_error()); 6551 } 6552 } 6553 6554 if (li_only) 6555 goto lionly; 6556 6557 inst->sc_import_state = IMPORT_PROP_BEGUN; 6558 6559 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6560 flags); 6561 switch (r) { 6562 case 0: 6563 break; 6564 6565 case ECONNABORTED: 6566 goto connaborted; 6567 6568 case ECANCELED: 6569 warn(gettext("%s changed unexpectedly " 6570 "(instance \"%s\" deleted).\n"), 6571 inst->sc_parent->sc_fmri, inst->sc_name); 6572 lcbdata->sc_err = EBUSY; 6573 r = UU_WALK_ERROR; 6574 goto deltemp; 6575 6576 case EEXIST: 6577 warn(gettext("%s changed unexpectedly " 6578 "(property group added).\n"), inst->sc_fmri); 6579 lcbdata->sc_err = EBUSY; 6580 r = UU_WALK_ERROR; 6581 goto deltemp; 6582 6583 default: 6584 lcbdata->sc_err = r; 6585 r = UU_WALK_ERROR; 6586 goto deltemp; 6587 6588 case EINVAL: /* caught above */ 6589 bad_error("lscf_import_instance_pgs", r); 6590 } 6591 6592 ctx.sc_parent = imp_inst; 6593 ctx.sc_service = 0; 6594 ctx.sc_trans = NULL; 6595 ctx.sc_flags = 0; 6596 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6597 &ctx, UU_DEFAULT) != 0) { 6598 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6599 bad_error("uu_list_walk", uu_error()); 6600 6601 if (ctx.sc_err == ECONNABORTED) 6602 goto connaborted; 6603 lcbdata->sc_err = ctx.sc_err; 6604 r = UU_WALK_ERROR; 6605 goto deltemp; 6606 } 6607 6608 inst->sc_import_state = IMPORT_PROP_DONE; 6609 6610 if (g_verbose) 6611 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6612 snap_initial, inst->sc_fmri); 6613 r = take_snap(imp_inst, snap_initial, imp_snap); 6614 switch (r) { 6615 case 0: 6616 break; 6617 6618 case ECONNABORTED: 6619 goto connaborted; 6620 6621 case ENOSPC: 6622 case -1: 6623 lcbdata->sc_err = r; 6624 r = UU_WALK_ERROR; 6625 goto deltemp; 6626 6627 case ECANCELED: 6628 warn(gettext("%s changed unexpectedly " 6629 "(instance %s deleted).\n"), 6630 inst->sc_parent->sc_fmri, inst->sc_name); 6631 lcbdata->sc_err = r; 6632 r = UU_WALK_ERROR; 6633 goto deltemp; 6634 6635 case EPERM: 6636 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6637 lcbdata->sc_err = r; 6638 r = UU_WALK_ERROR; 6639 goto deltemp; 6640 6641 default: 6642 bad_error("take_snap", r); 6643 } 6644 } 6645 6646 lionly: 6647 if (lcbdata->sc_flags & SCI_NOSNAP) 6648 goto deltemp; 6649 6650 /* transfer snapshot from temporary instance */ 6651 if (g_verbose) 6652 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6653 snap_lastimport, inst->sc_fmri); 6654 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6655 switch (scf_error()) { 6656 case SCF_ERROR_CONNECTION_BROKEN: 6657 goto connaborted; 6658 6659 case SCF_ERROR_NO_RESOURCES: 6660 r = stash_scferror(lcbdata); 6661 goto deltemp; 6662 6663 case SCF_ERROR_PERMISSION_DENIED: 6664 warn(gettext("Could not take \"%s\" snapshot for %s " 6665 "(permission denied).\n"), snap_lastimport, 6666 inst->sc_fmri); 6667 r = stash_scferror(lcbdata); 6668 goto deltemp; 6669 6670 case SCF_ERROR_NOT_SET: 6671 case SCF_ERROR_HANDLE_MISMATCH: 6672 default: 6673 bad_error("_scf_snapshot_attach", scf_error()); 6674 } 6675 } 6676 6677 inst->sc_import_state = IMPORT_COMPLETE; 6678 6679 r = UU_WALK_NEXT; 6680 6681 deltemp: 6682 /* delete temporary instance */ 6683 if (scf_instance_delete(imp_tinst) != 0) { 6684 switch (scf_error()) { 6685 case SCF_ERROR_DELETED: 6686 break; 6687 6688 case SCF_ERROR_CONNECTION_BROKEN: 6689 goto connaborted; 6690 6691 case SCF_ERROR_NOT_SET: 6692 case SCF_ERROR_NOT_BOUND: 6693 default: 6694 bad_error("scf_instance_delete", scf_error()); 6695 } 6696 } 6697 6698 return (r); 6699 6700 connaborted: 6701 warn(gettext("Could not delete svc:/%s:%s " 6702 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6703 lcbdata->sc_err = ECONNABORTED; 6704 return (UU_WALK_ERROR); 6705 } 6706 6707 /* 6708 * If the service is missing, create it, import its properties, and import the 6709 * instances. Since the service is brand new, it should be empty, and if we 6710 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6711 * 6712 * If the service exists, we want to upgrade its properties and import the 6713 * instances. Upgrade requires a last-import snapshot, though, which are 6714 * children of instances, so first we'll have to go through the instances 6715 * looking for a last-import snapshot. If we don't find one then we'll just 6716 * override-import the service properties (but don't delete existing 6717 * properties: another service might have declared us as a dependent). Before 6718 * we change anything, though, we want to take the previous snapshots. We 6719 * also give lscf_instance_import() a leg up on taking last-import snapshots 6720 * by importing the manifest's service properties into a temporary service. 6721 * 6722 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6723 * sets lcbdata->sc_err to 6724 * ECONNABORTED - repository connection broken 6725 * ENOMEM - out of memory 6726 * ENOSPC - svc.configd is out of resources 6727 * EPERM - couldn't create temporary service (error printed) 6728 * - couldn't import into temp service (error printed) 6729 * - couldn't create service (error printed) 6730 * - couldn't import dependent (error printed) 6731 * - couldn't take snapshot (error printed) 6732 * - couldn't create instance (error printed) 6733 * - couldn't create, modify, or delete pg (error printed) 6734 * - couldn't create, modify, or delete dependent (error printed) 6735 * - couldn't import instance (error printed) 6736 * EROFS - couldn't create temporary service (repository read-only) 6737 * - couldn't import into temporary service (repository read-only) 6738 * - couldn't create service (repository read-only) 6739 * - couldn't import dependent (repository read-only) 6740 * - couldn't create instance (repository read-only) 6741 * - couldn't create, modify, or delete pg or dependent 6742 * - couldn't import instance (repository read-only) 6743 * EACCES - couldn't create temporary service (backend access denied) 6744 * - couldn't import into temporary service (backend access denied) 6745 * - couldn't create service (backend access denied) 6746 * - couldn't import dependent (backend access denied) 6747 * - couldn't create instance (backend access denied) 6748 * - couldn't create, modify, or delete pg or dependent 6749 * - couldn't import instance (backend access denied) 6750 * EINVAL - service name is invalid (error printed) 6751 * - service name is too long (error printed) 6752 * - s has invalid pgroup (error printed) 6753 * - s has invalid dependent (error printed) 6754 * - instance name is invalid (error printed) 6755 * - instance entity_t is invalid (error printed) 6756 * EEXIST - couldn't create temporary service (already exists) (error printed) 6757 * - couldn't import dependent (dependency pg already exists) (printed) 6758 * - dependency collision in dependent service (error printed) 6759 * EBUSY - temporary service deleted (error printed) 6760 * - property group added to temporary service (error printed) 6761 * - new property group changed or was deleted (error printed) 6762 * - service was added unexpectedly (error printed) 6763 * - service was deleted unexpectedly (error printed) 6764 * - property group added to new service (error printed) 6765 * - instance added unexpectedly (error printed) 6766 * - instance deleted unexpectedly (error printed) 6767 * - dependent service deleted unexpectedly (error printed) 6768 * - pg was added, changed, or deleted (error printed) 6769 * - dependent pg changed (error printed) 6770 * - temporary instance added, changed, or deleted (error printed) 6771 * EBADF - a last-import snapshot is corrupt (error printed) 6772 * - the service is corrupt (error printed) 6773 * - a dependent is corrupt (error printed) 6774 * - an instance is corrupt (error printed) 6775 * - an instance has a corrupt last-import snapshot (error printed) 6776 * - dependent target has a corrupt snapshot (error printed) 6777 * -1 - unknown libscf error (error printed) 6778 */ 6779 static int 6780 lscf_service_import(void *v, void *pvt) 6781 { 6782 entity_t *s = v; 6783 scf_callback_t cbdata; 6784 scf_callback_t *lcbdata = pvt; 6785 scf_scope_t *scope = lcbdata->sc_parent; 6786 entity_t *inst, linst; 6787 int r; 6788 int fresh = 0; 6789 scf_snaplevel_t *running; 6790 int have_ge = 0; 6791 6792 const char * const ts_deleted = gettext("Temporary service svc:/%s " 6793 "was deleted unexpectedly.\n"); 6794 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 6795 "changed unexpectedly (property group added).\n"); 6796 const char * const s_deleted = 6797 gettext("%s was deleted unexpectedly.\n"); 6798 const char * const i_deleted = 6799 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 6800 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 6801 "is corrupt (missing service snaplevel).\n"); 6802 const char * const s_mfile_upd = 6803 gettext("Unable to update the manifest file connection " 6804 "for %s\n"); 6805 6806 li_only = 0; 6807 /* Validate the service name */ 6808 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6809 switch (scf_error()) { 6810 case SCF_ERROR_CONNECTION_BROKEN: 6811 return (stash_scferror(lcbdata)); 6812 6813 case SCF_ERROR_INVALID_ARGUMENT: 6814 warn(gettext("\"%s\" is an invalid service name. " 6815 "Cannot import.\n"), s->sc_name); 6816 return (stash_scferror(lcbdata)); 6817 6818 case SCF_ERROR_NOT_FOUND: 6819 break; 6820 6821 case SCF_ERROR_HANDLE_MISMATCH: 6822 case SCF_ERROR_NOT_BOUND: 6823 case SCF_ERROR_NOT_SET: 6824 default: 6825 bad_error("scf_scope_get_service", scf_error()); 6826 } 6827 } 6828 6829 /* create temporary service */ 6830 /* 6831 * the size of the buffer was reduced to max_scf_name_len to prevent 6832 * hitting bug 6681151. After the bug fix, the size of the buffer 6833 * should be restored to its original value (max_scf_name_len +1) 6834 */ 6835 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 6836 if (r < 0) 6837 bad_error("snprintf", errno); 6838 if (r > max_scf_name_len) { 6839 warn(gettext( 6840 "Service name \"%s\" is too long. Cannot import.\n"), 6841 s->sc_name); 6842 lcbdata->sc_err = EINVAL; 6843 return (UU_WALK_ERROR); 6844 } 6845 6846 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 6847 switch (scf_error()) { 6848 case SCF_ERROR_CONNECTION_BROKEN: 6849 case SCF_ERROR_NO_RESOURCES: 6850 case SCF_ERROR_BACKEND_READONLY: 6851 case SCF_ERROR_BACKEND_ACCESS: 6852 return (stash_scferror(lcbdata)); 6853 6854 case SCF_ERROR_EXISTS: 6855 warn(gettext( 6856 "Temporary service \"%s\" must be deleted before " 6857 "this manifest can be imported.\n"), imp_tsname); 6858 return (stash_scferror(lcbdata)); 6859 6860 case SCF_ERROR_PERMISSION_DENIED: 6861 warn(gettext("Could not create temporary service " 6862 "\"%s\" (permission denied).\n"), imp_tsname); 6863 return (stash_scferror(lcbdata)); 6864 6865 case SCF_ERROR_INVALID_ARGUMENT: 6866 case SCF_ERROR_HANDLE_MISMATCH: 6867 case SCF_ERROR_NOT_BOUND: 6868 case SCF_ERROR_NOT_SET: 6869 default: 6870 bad_error("scf_scope_add_service", scf_error()); 6871 } 6872 } 6873 6874 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 6875 if (r < 0) 6876 bad_error("snprintf", errno); 6877 6878 cbdata.sc_handle = lcbdata->sc_handle; 6879 cbdata.sc_parent = imp_tsvc; 6880 cbdata.sc_service = 1; 6881 cbdata.sc_source_fmri = s->sc_fmri; 6882 cbdata.sc_target_fmri = imp_str; 6883 cbdata.sc_flags = 0; 6884 6885 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 6886 UU_DEFAULT) != 0) { 6887 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6888 bad_error("uu_list_walk", uu_error()); 6889 6890 lcbdata->sc_err = cbdata.sc_err; 6891 switch (cbdata.sc_err) { 6892 case ECONNABORTED: 6893 goto connaborted; 6894 6895 case ECANCELED: 6896 warn(ts_deleted, imp_tsname); 6897 lcbdata->sc_err = EBUSY; 6898 return (UU_WALK_ERROR); 6899 6900 case EEXIST: 6901 warn(ts_pg_added, imp_tsname); 6902 lcbdata->sc_err = EBUSY; 6903 return (UU_WALK_ERROR); 6904 } 6905 6906 r = UU_WALK_ERROR; 6907 goto deltemp; 6908 } 6909 6910 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 6911 UU_DEFAULT) != 0) { 6912 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6913 bad_error("uu_list_walk", uu_error()); 6914 6915 lcbdata->sc_err = cbdata.sc_err; 6916 switch (cbdata.sc_err) { 6917 case ECONNABORTED: 6918 goto connaborted; 6919 6920 case ECANCELED: 6921 warn(ts_deleted, imp_tsname); 6922 lcbdata->sc_err = EBUSY; 6923 return (UU_WALK_ERROR); 6924 6925 case EEXIST: 6926 warn(ts_pg_added, imp_tsname); 6927 lcbdata->sc_err = EBUSY; 6928 return (UU_WALK_ERROR); 6929 } 6930 6931 r = UU_WALK_ERROR; 6932 goto deltemp; 6933 } 6934 6935 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6936 switch (scf_error()) { 6937 case SCF_ERROR_NOT_FOUND: 6938 break; 6939 6940 case SCF_ERROR_CONNECTION_BROKEN: 6941 goto connaborted; 6942 6943 case SCF_ERROR_INVALID_ARGUMENT: 6944 case SCF_ERROR_HANDLE_MISMATCH: 6945 case SCF_ERROR_NOT_BOUND: 6946 case SCF_ERROR_NOT_SET: 6947 default: 6948 bad_error("scf_scope_get_service", scf_error()); 6949 } 6950 6951 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 6952 switch (scf_error()) { 6953 case SCF_ERROR_CONNECTION_BROKEN: 6954 goto connaborted; 6955 6956 case SCF_ERROR_NO_RESOURCES: 6957 case SCF_ERROR_BACKEND_READONLY: 6958 case SCF_ERROR_BACKEND_ACCESS: 6959 r = stash_scferror(lcbdata); 6960 goto deltemp; 6961 6962 case SCF_ERROR_EXISTS: 6963 warn(gettext("Scope \"%s\" changed unexpectedly" 6964 " (service \"%s\" added).\n"), 6965 SCF_SCOPE_LOCAL, s->sc_name); 6966 lcbdata->sc_err = EBUSY; 6967 goto deltemp; 6968 6969 case SCF_ERROR_PERMISSION_DENIED: 6970 warn(gettext("Could not create service \"%s\" " 6971 "(permission denied).\n"), s->sc_name); 6972 goto deltemp; 6973 6974 case SCF_ERROR_INVALID_ARGUMENT: 6975 case SCF_ERROR_HANDLE_MISMATCH: 6976 case SCF_ERROR_NOT_BOUND: 6977 case SCF_ERROR_NOT_SET: 6978 default: 6979 bad_error("scf_scope_add_service", scf_error()); 6980 } 6981 } 6982 6983 s->sc_import_state = IMPORT_PROP_BEGUN; 6984 6985 /* import service properties */ 6986 cbdata.sc_handle = lcbdata->sc_handle; 6987 cbdata.sc_parent = imp_svc; 6988 cbdata.sc_service = 1; 6989 cbdata.sc_flags = lcbdata->sc_flags; 6990 cbdata.sc_source_fmri = s->sc_fmri; 6991 cbdata.sc_target_fmri = s->sc_fmri; 6992 6993 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6994 &cbdata, UU_DEFAULT) != 0) { 6995 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6996 bad_error("uu_list_walk", uu_error()); 6997 6998 lcbdata->sc_err = cbdata.sc_err; 6999 switch (cbdata.sc_err) { 7000 case ECONNABORTED: 7001 goto connaborted; 7002 7003 case ECANCELED: 7004 warn(s_deleted, s->sc_fmri); 7005 lcbdata->sc_err = EBUSY; 7006 return (UU_WALK_ERROR); 7007 7008 case EEXIST: 7009 warn(gettext("%s changed unexpectedly " 7010 "(property group added).\n"), s->sc_fmri); 7011 lcbdata->sc_err = EBUSY; 7012 return (UU_WALK_ERROR); 7013 7014 case EINVAL: 7015 /* caught above */ 7016 bad_error("entity_pgroup_import", 7017 cbdata.sc_err); 7018 } 7019 7020 r = UU_WALK_ERROR; 7021 goto deltemp; 7022 } 7023 7024 cbdata.sc_trans = NULL; 7025 cbdata.sc_flags = 0; 7026 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 7027 &cbdata, UU_DEFAULT) != 0) { 7028 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7029 bad_error("uu_list_walk", uu_error()); 7030 7031 lcbdata->sc_err = cbdata.sc_err; 7032 if (cbdata.sc_err == ECONNABORTED) 7033 goto connaborted; 7034 r = UU_WALK_ERROR; 7035 goto deltemp; 7036 } 7037 7038 s->sc_import_state = IMPORT_PROP_DONE; 7039 7040 /* 7041 * This is a new service, so we can't take previous snapshots 7042 * or upgrade service properties. 7043 */ 7044 fresh = 1; 7045 goto instances; 7046 } 7047 7048 /* Clear sc_seen for the instances. */ 7049 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 7050 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 7051 bad_error("uu_list_walk", uu_error()); 7052 7053 /* 7054 * Take previous snapshots for all instances. Even for ones not 7055 * mentioned in the bundle, since we might change their service 7056 * properties. 7057 */ 7058 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7059 switch (scf_error()) { 7060 case SCF_ERROR_CONNECTION_BROKEN: 7061 goto connaborted; 7062 7063 case SCF_ERROR_DELETED: 7064 warn(s_deleted, s->sc_fmri); 7065 lcbdata->sc_err = EBUSY; 7066 r = UU_WALK_ERROR; 7067 goto deltemp; 7068 7069 case SCF_ERROR_HANDLE_MISMATCH: 7070 case SCF_ERROR_NOT_BOUND: 7071 case SCF_ERROR_NOT_SET: 7072 default: 7073 bad_error("scf_iter_service_instances", scf_error()); 7074 } 7075 } 7076 7077 for (;;) { 7078 r = scf_iter_next_instance(imp_iter, imp_inst); 7079 if (r == 0) 7080 break; 7081 if (r != 1) { 7082 switch (scf_error()) { 7083 case SCF_ERROR_DELETED: 7084 warn(s_deleted, s->sc_fmri); 7085 lcbdata->sc_err = EBUSY; 7086 r = UU_WALK_ERROR; 7087 goto deltemp; 7088 7089 case SCF_ERROR_CONNECTION_BROKEN: 7090 goto connaborted; 7091 7092 case SCF_ERROR_NOT_BOUND: 7093 case SCF_ERROR_HANDLE_MISMATCH: 7094 case SCF_ERROR_INVALID_ARGUMENT: 7095 case SCF_ERROR_NOT_SET: 7096 default: 7097 bad_error("scf_iter_next_instance", 7098 scf_error()); 7099 } 7100 } 7101 7102 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 7103 switch (scf_error()) { 7104 case SCF_ERROR_DELETED: 7105 continue; 7106 7107 case SCF_ERROR_CONNECTION_BROKEN: 7108 goto connaborted; 7109 7110 case SCF_ERROR_NOT_SET: 7111 case SCF_ERROR_NOT_BOUND: 7112 default: 7113 bad_error("scf_instance_get_name", scf_error()); 7114 } 7115 } 7116 7117 if (g_verbose) 7118 warn(gettext( 7119 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 7120 snap_previous, s->sc_name, imp_str); 7121 7122 r = take_snap(imp_inst, snap_previous, imp_snap); 7123 switch (r) { 7124 case 0: 7125 break; 7126 7127 case ECANCELED: 7128 continue; 7129 7130 case ECONNABORTED: 7131 goto connaborted; 7132 7133 case EPERM: 7134 warn(gettext("Could not take \"%s\" snapshot of " 7135 "svc:/%s:%s (permission denied).\n"), 7136 snap_previous, s->sc_name, imp_str); 7137 lcbdata->sc_err = r; 7138 return (UU_WALK_ERROR); 7139 7140 case ENOSPC: 7141 case -1: 7142 lcbdata->sc_err = r; 7143 r = UU_WALK_ERROR; 7144 goto deltemp; 7145 7146 default: 7147 bad_error("take_snap", r); 7148 } 7149 7150 linst.sc_name = imp_str; 7151 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 7152 &linst, NULL, NULL); 7153 if (inst != NULL) { 7154 inst->sc_import_state = IMPORT_PREVIOUS; 7155 inst->sc_seen = 1; 7156 } 7157 } 7158 7159 /* 7160 * Create the new instances and take previous snapshots of 7161 * them. This is not necessary, but it maximizes data preservation. 7162 */ 7163 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 7164 inst != NULL; 7165 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 7166 inst)) { 7167 if (inst->sc_seen) 7168 continue; 7169 7170 if (scf_service_add_instance(imp_svc, inst->sc_name, 7171 imp_inst) != 0) { 7172 switch (scf_error()) { 7173 case SCF_ERROR_CONNECTION_BROKEN: 7174 goto connaborted; 7175 7176 case SCF_ERROR_BACKEND_READONLY: 7177 case SCF_ERROR_BACKEND_ACCESS: 7178 case SCF_ERROR_NO_RESOURCES: 7179 r = stash_scferror(lcbdata); 7180 goto deltemp; 7181 7182 case SCF_ERROR_EXISTS: 7183 warn(gettext("%s changed unexpectedly " 7184 "(instance \"%s\" added).\n"), s->sc_fmri, 7185 inst->sc_name); 7186 lcbdata->sc_err = EBUSY; 7187 r = UU_WALK_ERROR; 7188 goto deltemp; 7189 7190 case SCF_ERROR_INVALID_ARGUMENT: 7191 warn(gettext("Service \"%s\" has instance with " 7192 "invalid name \"%s\".\n"), s->sc_name, 7193 inst->sc_name); 7194 r = stash_scferror(lcbdata); 7195 goto deltemp; 7196 7197 case SCF_ERROR_PERMISSION_DENIED: 7198 warn(gettext("Could not create instance \"%s\" " 7199 "in %s (permission denied).\n"), 7200 inst->sc_name, s->sc_fmri); 7201 r = stash_scferror(lcbdata); 7202 goto deltemp; 7203 7204 case SCF_ERROR_HANDLE_MISMATCH: 7205 case SCF_ERROR_NOT_BOUND: 7206 case SCF_ERROR_NOT_SET: 7207 default: 7208 bad_error("scf_service_add_instance", 7209 scf_error()); 7210 } 7211 } 7212 7213 if (g_verbose) 7214 warn(gettext("Taking \"%s\" snapshot for " 7215 "new service %s.\n"), snap_previous, inst->sc_fmri); 7216 r = take_snap(imp_inst, snap_previous, imp_snap); 7217 switch (r) { 7218 case 0: 7219 break; 7220 7221 case ECANCELED: 7222 warn(i_deleted, s->sc_fmri, inst->sc_name); 7223 lcbdata->sc_err = EBUSY; 7224 r = UU_WALK_ERROR; 7225 goto deltemp; 7226 7227 case ECONNABORTED: 7228 goto connaborted; 7229 7230 case EPERM: 7231 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 7232 lcbdata->sc_err = r; 7233 r = UU_WALK_ERROR; 7234 goto deltemp; 7235 7236 case ENOSPC: 7237 case -1: 7238 r = UU_WALK_ERROR; 7239 goto deltemp; 7240 7241 default: 7242 bad_error("take_snap", r); 7243 } 7244 } 7245 7246 s->sc_import_state = IMPORT_PREVIOUS; 7247 7248 /* 7249 * Upgrade service properties, if we can find a last-import snapshot. 7250 * Any will do because we don't support different service properties 7251 * in different manifests, so all snaplevels of the service in all of 7252 * the last-import snapshots of the instances should be the same. 7253 */ 7254 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 7255 switch (scf_error()) { 7256 case SCF_ERROR_CONNECTION_BROKEN: 7257 goto connaborted; 7258 7259 case SCF_ERROR_DELETED: 7260 warn(s_deleted, s->sc_fmri); 7261 lcbdata->sc_err = EBUSY; 7262 r = UU_WALK_ERROR; 7263 goto deltemp; 7264 7265 case SCF_ERROR_HANDLE_MISMATCH: 7266 case SCF_ERROR_NOT_BOUND: 7267 case SCF_ERROR_NOT_SET: 7268 default: 7269 bad_error("scf_iter_service_instances", scf_error()); 7270 } 7271 } 7272 7273 for (;;) { 7274 r = scf_iter_next_instance(imp_iter, imp_inst); 7275 if (r == -1) { 7276 switch (scf_error()) { 7277 case SCF_ERROR_DELETED: 7278 warn(s_deleted, s->sc_fmri); 7279 lcbdata->sc_err = EBUSY; 7280 r = UU_WALK_ERROR; 7281 goto deltemp; 7282 7283 case SCF_ERROR_CONNECTION_BROKEN: 7284 goto connaborted; 7285 7286 case SCF_ERROR_NOT_BOUND: 7287 case SCF_ERROR_HANDLE_MISMATCH: 7288 case SCF_ERROR_INVALID_ARGUMENT: 7289 case SCF_ERROR_NOT_SET: 7290 default: 7291 bad_error("scf_iter_next_instance", 7292 scf_error()); 7293 } 7294 } 7295 7296 if (r == 0) { 7297 /* 7298 * Didn't find any last-import snapshots. Override- 7299 * import the properties. Unless one of the instances 7300 * has a general/enabled property, in which case we're 7301 * probably running a last-import-capable svccfg for 7302 * the first time, and we should only take the 7303 * last-import snapshot. 7304 */ 7305 if (have_ge) { 7306 pgroup_t *mfpg; 7307 scf_callback_t mfcbdata; 7308 7309 li_only = 1; 7310 no_refresh = 1; 7311 /* 7312 * Need to go ahead and import the manifestfiles 7313 * pg if it exists. If the last-import snapshot 7314 * upgrade code is ever removed this code can 7315 * be removed as well. 7316 */ 7317 mfpg = internal_pgroup_find(s, 7318 SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 7319 7320 if (mfpg) { 7321 mfcbdata.sc_handle = g_hndl; 7322 mfcbdata.sc_parent = imp_svc; 7323 mfcbdata.sc_service = 1; 7324 mfcbdata.sc_flags = SCI_FORCE; 7325 mfcbdata.sc_source_fmri = s->sc_fmri; 7326 mfcbdata.sc_target_fmri = s->sc_fmri; 7327 if (entity_pgroup_import(mfpg, 7328 &mfcbdata) != UU_WALK_NEXT) { 7329 warn(s_mfile_upd, s->sc_fmri); 7330 r = UU_WALK_ERROR; 7331 goto deltemp; 7332 } 7333 } 7334 break; 7335 } 7336 7337 s->sc_import_state = IMPORT_PROP_BEGUN; 7338 7339 cbdata.sc_handle = g_hndl; 7340 cbdata.sc_parent = imp_svc; 7341 cbdata.sc_service = 1; 7342 cbdata.sc_flags = SCI_FORCE; 7343 cbdata.sc_source_fmri = s->sc_fmri; 7344 cbdata.sc_target_fmri = s->sc_fmri; 7345 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 7346 &cbdata, UU_DEFAULT) != 0) { 7347 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7348 bad_error("uu_list_walk", uu_error()); 7349 lcbdata->sc_err = cbdata.sc_err; 7350 switch (cbdata.sc_err) { 7351 case ECONNABORTED: 7352 goto connaborted; 7353 7354 case ECANCELED: 7355 warn(s_deleted, s->sc_fmri); 7356 lcbdata->sc_err = EBUSY; 7357 break; 7358 7359 case EINVAL: /* caught above */ 7360 case EEXIST: 7361 bad_error("entity_pgroup_import", 7362 cbdata.sc_err); 7363 } 7364 7365 r = UU_WALK_ERROR; 7366 goto deltemp; 7367 } 7368 7369 cbdata.sc_trans = NULL; 7370 cbdata.sc_flags = 0; 7371 if (uu_list_walk(s->sc_dependents, 7372 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 7373 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7374 bad_error("uu_list_walk", uu_error()); 7375 lcbdata->sc_err = cbdata.sc_err; 7376 if (cbdata.sc_err == ECONNABORTED) 7377 goto connaborted; 7378 r = UU_WALK_ERROR; 7379 goto deltemp; 7380 } 7381 break; 7382 } 7383 7384 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 7385 imp_snap) != 0) { 7386 switch (scf_error()) { 7387 case SCF_ERROR_DELETED: 7388 continue; 7389 7390 case SCF_ERROR_NOT_FOUND: 7391 break; 7392 7393 case SCF_ERROR_CONNECTION_BROKEN: 7394 goto connaborted; 7395 7396 case SCF_ERROR_HANDLE_MISMATCH: 7397 case SCF_ERROR_NOT_BOUND: 7398 case SCF_ERROR_INVALID_ARGUMENT: 7399 case SCF_ERROR_NOT_SET: 7400 default: 7401 bad_error("scf_instance_get_snapshot", 7402 scf_error()); 7403 } 7404 7405 if (have_ge) 7406 continue; 7407 7408 /* 7409 * Check for a general/enabled property. This is how 7410 * we tell whether to import if there turn out to be 7411 * no last-import snapshots. 7412 */ 7413 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 7414 imp_pg) == 0) { 7415 if (scf_pg_get_property(imp_pg, 7416 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 7417 have_ge = 1; 7418 } else { 7419 switch (scf_error()) { 7420 case SCF_ERROR_DELETED: 7421 case SCF_ERROR_NOT_FOUND: 7422 continue; 7423 7424 case SCF_ERROR_INVALID_ARGUMENT: 7425 case SCF_ERROR_HANDLE_MISMATCH: 7426 case SCF_ERROR_CONNECTION_BROKEN: 7427 case SCF_ERROR_NOT_BOUND: 7428 case SCF_ERROR_NOT_SET: 7429 default: 7430 bad_error("scf_pg_get_property", 7431 scf_error()); 7432 } 7433 } 7434 } else { 7435 switch (scf_error()) { 7436 case SCF_ERROR_DELETED: 7437 case SCF_ERROR_NOT_FOUND: 7438 continue; 7439 7440 case SCF_ERROR_CONNECTION_BROKEN: 7441 goto connaborted; 7442 7443 case SCF_ERROR_NOT_BOUND: 7444 case SCF_ERROR_NOT_SET: 7445 case SCF_ERROR_INVALID_ARGUMENT: 7446 case SCF_ERROR_HANDLE_MISMATCH: 7447 default: 7448 bad_error("scf_instance_get_pg", 7449 scf_error()); 7450 } 7451 } 7452 continue; 7453 } 7454 7455 /* find service snaplevel */ 7456 r = get_snaplevel(imp_snap, 1, imp_snpl); 7457 switch (r) { 7458 case 0: 7459 break; 7460 7461 case ECONNABORTED: 7462 goto connaborted; 7463 7464 case ECANCELED: 7465 continue; 7466 7467 case ENOENT: 7468 if (scf_instance_get_name(imp_inst, imp_str, 7469 imp_str_sz) < 0) 7470 (void) strcpy(imp_str, "?"); 7471 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 7472 lcbdata->sc_err = EBADF; 7473 r = UU_WALK_ERROR; 7474 goto deltemp; 7475 7476 default: 7477 bad_error("get_snaplevel", r); 7478 } 7479 7480 if (scf_instance_get_snapshot(imp_inst, snap_running, 7481 imp_rsnap) != 0) { 7482 switch (scf_error()) { 7483 case SCF_ERROR_DELETED: 7484 continue; 7485 7486 case SCF_ERROR_NOT_FOUND: 7487 break; 7488 7489 case SCF_ERROR_CONNECTION_BROKEN: 7490 goto connaborted; 7491 7492 case SCF_ERROR_INVALID_ARGUMENT: 7493 case SCF_ERROR_HANDLE_MISMATCH: 7494 case SCF_ERROR_NOT_BOUND: 7495 case SCF_ERROR_NOT_SET: 7496 default: 7497 bad_error("scf_instance_get_snapshot", 7498 scf_error()); 7499 } 7500 running = NULL; 7501 } else { 7502 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 7503 switch (r) { 7504 case 0: 7505 running = imp_rsnpl; 7506 break; 7507 7508 case ECONNABORTED: 7509 goto connaborted; 7510 7511 case ECANCELED: 7512 continue; 7513 7514 case ENOENT: 7515 if (scf_instance_get_name(imp_inst, imp_str, 7516 imp_str_sz) < 0) 7517 (void) strcpy(imp_str, "?"); 7518 warn(badsnap, snap_running, s->sc_name, 7519 imp_str); 7520 lcbdata->sc_err = EBADF; 7521 r = UU_WALK_ERROR; 7522 goto deltemp; 7523 7524 default: 7525 bad_error("get_snaplevel", r); 7526 } 7527 } 7528 7529 if (g_verbose) { 7530 if (scf_instance_get_name(imp_inst, imp_str, 7531 imp_str_sz) < 0) 7532 (void) strcpy(imp_str, "?"); 7533 warn(gettext("Upgrading properties of %s according to " 7534 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7535 } 7536 7537 /* upgrade service properties */ 7538 r = upgrade_props(imp_svc, running, imp_snpl, s); 7539 if (r == 0) 7540 break; 7541 7542 switch (r) { 7543 case ECONNABORTED: 7544 goto connaborted; 7545 7546 case ECANCELED: 7547 warn(s_deleted, s->sc_fmri); 7548 lcbdata->sc_err = EBUSY; 7549 break; 7550 7551 case ENODEV: 7552 if (scf_instance_get_name(imp_inst, imp_str, 7553 imp_str_sz) < 0) 7554 (void) strcpy(imp_str, "?"); 7555 warn(i_deleted, s->sc_fmri, imp_str); 7556 lcbdata->sc_err = EBUSY; 7557 break; 7558 7559 default: 7560 lcbdata->sc_err = r; 7561 } 7562 7563 r = UU_WALK_ERROR; 7564 goto deltemp; 7565 } 7566 7567 s->sc_import_state = IMPORT_PROP_DONE; 7568 7569 instances: 7570 /* import instances */ 7571 cbdata.sc_handle = lcbdata->sc_handle; 7572 cbdata.sc_parent = imp_svc; 7573 cbdata.sc_service = 1; 7574 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7575 cbdata.sc_general = NULL; 7576 7577 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7578 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7579 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7580 bad_error("uu_list_walk", uu_error()); 7581 7582 lcbdata->sc_err = cbdata.sc_err; 7583 if (cbdata.sc_err == ECONNABORTED) 7584 goto connaborted; 7585 r = UU_WALK_ERROR; 7586 goto deltemp; 7587 } 7588 7589 s->sc_import_state = IMPORT_COMPLETE; 7590 r = UU_WALK_NEXT; 7591 7592 deltemp: 7593 /* delete temporary service */ 7594 if (scf_service_delete(imp_tsvc) != 0) { 7595 switch (scf_error()) { 7596 case SCF_ERROR_DELETED: 7597 break; 7598 7599 case SCF_ERROR_CONNECTION_BROKEN: 7600 goto connaborted; 7601 7602 case SCF_ERROR_EXISTS: 7603 warn(gettext( 7604 "Could not delete svc:/%s (instances exist).\n"), 7605 imp_tsname); 7606 break; 7607 7608 case SCF_ERROR_NOT_SET: 7609 case SCF_ERROR_NOT_BOUND: 7610 default: 7611 bad_error("scf_service_delete", scf_error()); 7612 } 7613 } 7614 7615 return (r); 7616 7617 connaborted: 7618 warn(gettext("Could not delete svc:/%s " 7619 "(repository connection broken).\n"), imp_tsname); 7620 lcbdata->sc_err = ECONNABORTED; 7621 return (UU_WALK_ERROR); 7622 } 7623 7624 static const char * 7625 import_progress(int st) 7626 { 7627 switch (st) { 7628 case 0: 7629 return (gettext("not reached.")); 7630 7631 case IMPORT_PREVIOUS: 7632 return (gettext("previous snapshot taken.")); 7633 7634 case IMPORT_PROP_BEGUN: 7635 return (gettext("some properties imported.")); 7636 7637 case IMPORT_PROP_DONE: 7638 return (gettext("properties imported.")); 7639 7640 case IMPORT_COMPLETE: 7641 return (gettext("imported.")); 7642 7643 case IMPORT_REFRESHED: 7644 return (gettext("refresh requested.")); 7645 7646 default: 7647 #ifndef NDEBUG 7648 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7649 __FILE__, __LINE__, st); 7650 #endif 7651 abort(); 7652 /* NOTREACHED */ 7653 } 7654 } 7655 7656 /* 7657 * Returns 7658 * 0 - success 7659 * - fmri wasn't found (error printed) 7660 * - entity was deleted (error printed) 7661 * - backend denied access (error printed) 7662 * ENOMEM - out of memory (error printed) 7663 * ECONNABORTED - repository connection broken (error printed) 7664 * EPERM - permission denied (error printed) 7665 * -1 - unknown libscf error (error printed) 7666 */ 7667 static int 7668 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7669 { 7670 scf_error_t serr; 7671 void *ent; 7672 int issvc; 7673 int r; 7674 7675 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7676 const char *dpt_deleted = gettext("Could not refresh %s " 7677 "(dependent \"%s\" of %s) (deleted).\n"); 7678 7679 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7680 switch (serr) { 7681 case SCF_ERROR_NONE: 7682 break; 7683 7684 case SCF_ERROR_NO_MEMORY: 7685 if (name == NULL) 7686 warn(gettext("Could not refresh %s (out of memory).\n"), 7687 fmri); 7688 else 7689 warn(gettext("Could not refresh %s " 7690 "(dependent \"%s\" of %s) (out of memory).\n"), 7691 fmri, name, d_fmri); 7692 return (ENOMEM); 7693 7694 case SCF_ERROR_NOT_FOUND: 7695 if (name == NULL) 7696 warn(deleted, fmri); 7697 else 7698 warn(dpt_deleted, fmri, name, d_fmri); 7699 return (0); 7700 7701 case SCF_ERROR_INVALID_ARGUMENT: 7702 case SCF_ERROR_CONSTRAINT_VIOLATED: 7703 default: 7704 bad_error("fmri_to_entity", serr); 7705 } 7706 7707 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7708 switch (r) { 7709 case 0: 7710 break; 7711 7712 case ECONNABORTED: 7713 if (name != NULL) 7714 warn(gettext("Could not refresh %s " 7715 "(dependent \"%s\" of %s) " 7716 "(repository connection broken).\n"), fmri, name, 7717 d_fmri); 7718 return (r); 7719 7720 case ECANCELED: 7721 if (name == NULL) 7722 warn(deleted, fmri); 7723 else 7724 warn(dpt_deleted, fmri, name, d_fmri); 7725 return (0); 7726 7727 case EACCES: 7728 if (!g_verbose) 7729 return (0); 7730 if (name == NULL) 7731 warn(gettext("Could not refresh %s " 7732 "(backend access denied).\n"), fmri); 7733 else 7734 warn(gettext("Could not refresh %s " 7735 "(dependent \"%s\" of %s) " 7736 "(backend access denied).\n"), fmri, name, d_fmri); 7737 return (0); 7738 7739 case EPERM: 7740 if (name == NULL) 7741 warn(gettext("Could not refresh %s " 7742 "(permission denied).\n"), fmri); 7743 else 7744 warn(gettext("Could not refresh %s " 7745 "(dependent \"%s\" of %s) " 7746 "(permission denied).\n"), fmri, name, d_fmri); 7747 return (r); 7748 7749 case ENOSPC: 7750 if (name == NULL) 7751 warn(gettext("Could not refresh %s " 7752 "(repository server out of resources).\n"), 7753 fmri); 7754 else 7755 warn(gettext("Could not refresh %s " 7756 "(dependent \"%s\" of %s) " 7757 "(repository server out of resources).\n"), 7758 fmri, name, d_fmri); 7759 return (r); 7760 7761 case -1: 7762 scfwarn(); 7763 return (r); 7764 7765 default: 7766 bad_error("refresh_entity", r); 7767 } 7768 7769 if (issvc) 7770 scf_service_destroy(ent); 7771 else 7772 scf_instance_destroy(ent); 7773 7774 return (0); 7775 } 7776 7777 static int 7778 alloc_imp_globals() 7779 { 7780 int r; 7781 7782 const char * const emsg_nomem = gettext("Out of memory.\n"); 7783 const char * const emsg_nores = 7784 gettext("svc.configd is out of resources.\n"); 7785 7786 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 7787 max_scf_name_len : max_scf_fmri_len) + 1; 7788 7789 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 7790 (imp_svc = scf_service_create(g_hndl)) == NULL || 7791 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 7792 (imp_inst = scf_instance_create(g_hndl)) == NULL || 7793 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 7794 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 7795 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 7796 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 7797 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 7798 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7799 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 7800 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7801 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 7802 (imp_prop = scf_property_create(g_hndl)) == NULL || 7803 (imp_iter = scf_iter_create(g_hndl)) == NULL || 7804 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 7805 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 7806 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 7807 (imp_str = malloc(imp_str_sz)) == NULL || 7808 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 7809 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 7810 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 7811 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 7812 (ud_inst = scf_instance_create(g_hndl)) == NULL || 7813 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7814 (ud_pg = scf_pg_create(g_hndl)) == NULL || 7815 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 7816 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 7817 (ud_prop = scf_property_create(g_hndl)) == NULL || 7818 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 7819 (ud_val = scf_value_create(g_hndl)) == NULL || 7820 (ud_iter = scf_iter_create(g_hndl)) == NULL || 7821 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 7822 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 7823 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 7824 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 7825 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 7826 if (scf_error() == SCF_ERROR_NO_RESOURCES) 7827 warn(emsg_nores); 7828 else 7829 warn(emsg_nomem); 7830 7831 return (-1); 7832 } 7833 7834 r = load_init(); 7835 switch (r) { 7836 case 0: 7837 break; 7838 7839 case ENOMEM: 7840 warn(emsg_nomem); 7841 return (-1); 7842 7843 default: 7844 bad_error("load_init", r); 7845 } 7846 7847 return (0); 7848 } 7849 7850 static void 7851 free_imp_globals() 7852 { 7853 pgroup_t *old_dpt; 7854 void *cookie; 7855 7856 load_fini(); 7857 7858 free(ud_ctarg); 7859 free(ud_oldtarg); 7860 free(ud_name); 7861 ud_ctarg = ud_oldtarg = ud_name = NULL; 7862 7863 scf_transaction_destroy(ud_tx); 7864 ud_tx = NULL; 7865 scf_iter_destroy(ud_iter); 7866 scf_iter_destroy(ud_iter2); 7867 ud_iter = ud_iter2 = NULL; 7868 scf_value_destroy(ud_val); 7869 ud_val = NULL; 7870 scf_property_destroy(ud_prop); 7871 scf_property_destroy(ud_dpt_prop); 7872 ud_prop = ud_dpt_prop = NULL; 7873 scf_pg_destroy(ud_pg); 7874 scf_pg_destroy(ud_cur_depts_pg); 7875 scf_pg_destroy(ud_run_dpts_pg); 7876 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7877 scf_snaplevel_destroy(ud_snpl); 7878 ud_snpl = NULL; 7879 scf_instance_destroy(ud_inst); 7880 ud_inst = NULL; 7881 7882 free(imp_str); 7883 free(imp_tsname); 7884 free(imp_fe1); 7885 free(imp_fe2); 7886 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7887 7888 cookie = NULL; 7889 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7890 NULL) { 7891 free((char *)old_dpt->sc_pgroup_name); 7892 free((char *)old_dpt->sc_pgroup_fmri); 7893 internal_pgroup_free(old_dpt); 7894 } 7895 uu_list_destroy(imp_deleted_dpts); 7896 7897 scf_transaction_destroy(imp_tx); 7898 imp_tx = NULL; 7899 scf_iter_destroy(imp_iter); 7900 scf_iter_destroy(imp_rpg_iter); 7901 scf_iter_destroy(imp_up_iter); 7902 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7903 scf_property_destroy(imp_prop); 7904 imp_prop = NULL; 7905 scf_pg_destroy(imp_pg); 7906 scf_pg_destroy(imp_pg2); 7907 imp_pg = imp_pg2 = NULL; 7908 scf_snaplevel_destroy(imp_snpl); 7909 scf_snaplevel_destroy(imp_rsnpl); 7910 imp_snpl = imp_rsnpl = NULL; 7911 scf_snapshot_destroy(imp_snap); 7912 scf_snapshot_destroy(imp_lisnap); 7913 scf_snapshot_destroy(imp_tlisnap); 7914 scf_snapshot_destroy(imp_rsnap); 7915 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7916 scf_instance_destroy(imp_inst); 7917 scf_instance_destroy(imp_tinst); 7918 imp_inst = imp_tinst = NULL; 7919 scf_service_destroy(imp_svc); 7920 scf_service_destroy(imp_tsvc); 7921 imp_svc = imp_tsvc = NULL; 7922 scf_scope_destroy(imp_scope); 7923 imp_scope = NULL; 7924 7925 load_fini(); 7926 } 7927 7928 int 7929 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 7930 { 7931 scf_callback_t cbdata; 7932 int result = 0; 7933 entity_t *svc, *inst; 7934 uu_list_t *insts; 7935 int r; 7936 pgroup_t *old_dpt; 7937 int annotation_set = 0; 7938 7939 const char * const emsg_nomem = gettext("Out of memory.\n"); 7940 const char * const emsg_nores = 7941 gettext("svc.configd is out of resources.\n"); 7942 7943 lscf_prep_hndl(); 7944 7945 if (alloc_imp_globals()) 7946 goto out; 7947 7948 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 7949 switch (scf_error()) { 7950 case SCF_ERROR_CONNECTION_BROKEN: 7951 warn(gettext("Repository connection broken.\n")); 7952 repository_teardown(); 7953 result = -1; 7954 goto out; 7955 7956 case SCF_ERROR_NOT_FOUND: 7957 case SCF_ERROR_INVALID_ARGUMENT: 7958 case SCF_ERROR_NOT_BOUND: 7959 case SCF_ERROR_HANDLE_MISMATCH: 7960 default: 7961 bad_error("scf_handle_get_scope", scf_error()); 7962 } 7963 } 7964 7965 /* Set up the auditing annotation. */ 7966 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 7967 annotation_set = 1; 7968 } else { 7969 switch (scf_error()) { 7970 case SCF_ERROR_CONNECTION_BROKEN: 7971 warn(gettext("Repository connection broken.\n")); 7972 repository_teardown(); 7973 result = -1; 7974 goto out; 7975 7976 case SCF_ERROR_INVALID_ARGUMENT: 7977 case SCF_ERROR_NOT_BOUND: 7978 case SCF_ERROR_NO_RESOURCES: 7979 case SCF_ERROR_INTERNAL: 7980 bad_error("_scf_set_annotation", scf_error()); 7981 /* NOTREACHED */ 7982 7983 default: 7984 /* 7985 * Do not terminate import because of inability to 7986 * generate annotation audit event. 7987 */ 7988 warn(gettext("_scf_set_annotation() unexpectedly " 7989 "failed with return code of %d\n"), scf_error()); 7990 break; 7991 } 7992 } 7993 7994 /* 7995 * Clear the sc_import_state's of all services & instances so we can 7996 * report how far we got if we fail. 7997 */ 7998 for (svc = uu_list_first(bndl->sc_bundle_services); 7999 svc != NULL; 8000 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8001 svc->sc_import_state = 0; 8002 8003 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 8004 clear_int, (void *)offsetof(entity_t, sc_import_state), 8005 UU_DEFAULT) != 0) 8006 bad_error("uu_list_walk", uu_error()); 8007 } 8008 8009 cbdata.sc_handle = g_hndl; 8010 cbdata.sc_parent = imp_scope; 8011 cbdata.sc_flags = flags; 8012 cbdata.sc_general = NULL; 8013 8014 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 8015 &cbdata, UU_DEFAULT) == 0) { 8016 /* Success. Refresh everything. */ 8017 8018 if (flags & SCI_NOREFRESH || no_refresh) { 8019 no_refresh = 0; 8020 result = 0; 8021 goto out; 8022 } 8023 8024 for (svc = uu_list_first(bndl->sc_bundle_services); 8025 svc != NULL; 8026 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8027 pgroup_t *dpt; 8028 8029 insts = svc->sc_u.sc_service.sc_service_instances; 8030 8031 for (inst = uu_list_first(insts); 8032 inst != NULL; 8033 inst = uu_list_next(insts, inst)) { 8034 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 8035 switch (r) { 8036 case 0: 8037 break; 8038 8039 case ENOMEM: 8040 case ECONNABORTED: 8041 case EPERM: 8042 case -1: 8043 goto progress; 8044 8045 default: 8046 bad_error("imp_refresh_fmri", r); 8047 } 8048 8049 inst->sc_import_state = IMPORT_REFRESHED; 8050 8051 for (dpt = uu_list_first(inst->sc_dependents); 8052 dpt != NULL; 8053 dpt = uu_list_next(inst->sc_dependents, 8054 dpt)) 8055 if (imp_refresh_fmri( 8056 dpt->sc_pgroup_fmri, 8057 dpt->sc_pgroup_name, 8058 inst->sc_fmri) != 0) 8059 goto progress; 8060 } 8061 8062 for (dpt = uu_list_first(svc->sc_dependents); 8063 dpt != NULL; 8064 dpt = uu_list_next(svc->sc_dependents, dpt)) 8065 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 8066 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 8067 goto progress; 8068 } 8069 8070 for (old_dpt = uu_list_first(imp_deleted_dpts); 8071 old_dpt != NULL; 8072 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 8073 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8074 old_dpt->sc_pgroup_name, 8075 old_dpt->sc_parent->sc_fmri) != 0) 8076 goto progress; 8077 8078 result = 0; 8079 goto out; 8080 } 8081 8082 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8083 bad_error("uu_list_walk", uu_error()); 8084 8085 printerr: 8086 /* If the error hasn't been printed yet, do so here. */ 8087 switch (cbdata.sc_err) { 8088 case ECONNABORTED: 8089 warn(gettext("Repository connection broken.\n")); 8090 break; 8091 8092 case ENOMEM: 8093 warn(emsg_nomem); 8094 break; 8095 8096 case ENOSPC: 8097 warn(emsg_nores); 8098 break; 8099 8100 case EROFS: 8101 warn(gettext("Repository is read-only.\n")); 8102 break; 8103 8104 case EACCES: 8105 warn(gettext("Repository backend denied access.\n")); 8106 break; 8107 8108 case EPERM: 8109 case EINVAL: 8110 case EEXIST: 8111 case EBUSY: 8112 case EBADF: 8113 case -1: 8114 break; 8115 8116 default: 8117 bad_error("lscf_service_import", cbdata.sc_err); 8118 } 8119 8120 progress: 8121 warn(gettext("Import of %s failed. Progress:\n"), filename); 8122 8123 for (svc = uu_list_first(bndl->sc_bundle_services); 8124 svc != NULL; 8125 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8126 insts = svc->sc_u.sc_service.sc_service_instances; 8127 8128 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 8129 import_progress(svc->sc_import_state)); 8130 8131 for (inst = uu_list_first(insts); 8132 inst != NULL; 8133 inst = uu_list_next(insts, inst)) 8134 warn(gettext(" Instance \"%s\": %s\n"), 8135 inst->sc_name, 8136 import_progress(inst->sc_import_state)); 8137 } 8138 8139 if (cbdata.sc_err == ECONNABORTED) 8140 repository_teardown(); 8141 8142 8143 result = -1; 8144 8145 out: 8146 if (annotation_set != 0) { 8147 /* Turn off annotation. It is no longer needed. */ 8148 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8149 } 8150 8151 free_imp_globals(); 8152 8153 return (result); 8154 } 8155 8156 /* 8157 * _lscf_import_err() summarize the error handling returned by 8158 * lscf_import_{instance | service}_pgs 8159 * Return values are: 8160 * IMPORT_NEXT 8161 * IMPORT_OUT 8162 * IMPORT_BAD 8163 */ 8164 8165 #define IMPORT_BAD -1 8166 #define IMPORT_NEXT 0 8167 #define IMPORT_OUT 1 8168 8169 static int 8170 _lscf_import_err(int err, const char *fmri) 8171 { 8172 switch (err) { 8173 case 0: 8174 if (g_verbose) 8175 warn(gettext("%s updated.\n"), fmri); 8176 return (IMPORT_NEXT); 8177 8178 case ECONNABORTED: 8179 warn(gettext("Could not update %s " 8180 "(repository connection broken).\n"), fmri); 8181 return (IMPORT_OUT); 8182 8183 case ENOMEM: 8184 warn(gettext("Could not update %s (out of memory).\n"), fmri); 8185 return (IMPORT_OUT); 8186 8187 case ENOSPC: 8188 warn(gettext("Could not update %s " 8189 "(repository server out of resources).\n"), fmri); 8190 return (IMPORT_OUT); 8191 8192 case ECANCELED: 8193 warn(gettext( 8194 "Could not update %s (deleted).\n"), fmri); 8195 return (IMPORT_NEXT); 8196 8197 case EPERM: 8198 case EINVAL: 8199 case EBUSY: 8200 return (IMPORT_NEXT); 8201 8202 case EROFS: 8203 warn(gettext("Could not update %s (repository read-only).\n"), 8204 fmri); 8205 return (IMPORT_OUT); 8206 8207 case EACCES: 8208 warn(gettext("Could not update %s " 8209 "(backend access denied).\n"), fmri); 8210 return (IMPORT_NEXT); 8211 8212 case EEXIST: 8213 default: 8214 return (IMPORT_BAD); 8215 } 8216 8217 /*NOTREACHED*/ 8218 } 8219 8220 /* 8221 * The global imp_svc and imp_inst should be set by the caller in the 8222 * check to make sure the service and instance exist that the apply is 8223 * working on. 8224 */ 8225 static int 8226 lscf_dependent_apply(void *dpg, void *e) 8227 { 8228 scf_callback_t cb; 8229 pgroup_t *dpt_pgroup = dpg; 8230 pgroup_t *deldpt; 8231 entity_t *ent = e; 8232 int tissvc; 8233 void *sc_ent, *tent; 8234 scf_error_t serr; 8235 int r; 8236 8237 const char * const dependents = "dependents"; 8238 const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT); 8239 8240 if (issvc) 8241 sc_ent = imp_svc; 8242 else 8243 sc_ent = imp_inst; 8244 8245 if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg, 8246 imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 || 8247 scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name, 8248 imp_prop) != 0) { 8249 switch (scf_error()) { 8250 case SCF_ERROR_NOT_FOUND: 8251 case SCF_ERROR_DELETED: 8252 break; 8253 8254 case SCF_ERROR_CONNECTION_BROKEN: 8255 case SCF_ERROR_NOT_SET: 8256 case SCF_ERROR_INVALID_ARGUMENT: 8257 case SCF_ERROR_HANDLE_MISMATCH: 8258 case SCF_ERROR_NOT_BOUND: 8259 default: 8260 bad_error("entity_get_pg", scf_error()); 8261 } 8262 } else { 8263 /* 8264 * Found the dependents/<wip dep> so check to 8265 * see if the service is different. If so 8266 * store the service for later refresh, and 8267 * delete the wip dependency from the service 8268 */ 8269 if (scf_property_get_value(imp_prop, ud_val) != 0) { 8270 switch (scf_error()) { 8271 case SCF_ERROR_DELETED: 8272 break; 8273 8274 case SCF_ERROR_CONNECTION_BROKEN: 8275 case SCF_ERROR_NOT_SET: 8276 case SCF_ERROR_INVALID_ARGUMENT: 8277 case SCF_ERROR_HANDLE_MISMATCH: 8278 case SCF_ERROR_NOT_BOUND: 8279 default: 8280 bad_error("scf_property_get_value", 8281 scf_error()); 8282 } 8283 } 8284 8285 if (scf_value_get_as_string(ud_val, ud_oldtarg, 8286 max_scf_value_len + 1) < 0) 8287 bad_error("scf_value_get_as_string", scf_error()); 8288 8289 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 8290 switch (r) { 8291 case 1: 8292 break; 8293 case 0: 8294 if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent, 8295 &tissvc)) != SCF_ERROR_NONE) { 8296 if (serr == SCF_ERROR_NOT_FOUND) { 8297 break; 8298 } else { 8299 bad_error("fmri_to_entity", serr); 8300 } 8301 } 8302 8303 if (entity_get_pg(tent, tissvc, 8304 dpt_pgroup->sc_pgroup_name, imp_pg) != 0) { 8305 serr = scf_error(); 8306 if (serr == SCF_ERROR_NOT_FOUND || 8307 serr == SCF_ERROR_DELETED) { 8308 break; 8309 } else { 8310 bad_error("entity_get_pg", scf_error()); 8311 } 8312 } 8313 8314 if (scf_pg_delete(imp_pg) != 0) { 8315 serr = scf_error(); 8316 if (serr == SCF_ERROR_NOT_FOUND || 8317 serr == SCF_ERROR_DELETED) { 8318 break; 8319 } else { 8320 bad_error("scf_pg_delete", scf_error()); 8321 } 8322 } 8323 8324 deldpt = internal_pgroup_new(); 8325 if (deldpt == NULL) 8326 return (ENOMEM); 8327 deldpt->sc_pgroup_name = 8328 strdup(dpt_pgroup->sc_pgroup_name); 8329 deldpt->sc_pgroup_fmri = strdup(ud_oldtarg); 8330 if (deldpt->sc_pgroup_name == NULL || 8331 deldpt->sc_pgroup_fmri == NULL) 8332 return (ENOMEM); 8333 deldpt->sc_parent = (entity_t *)ent; 8334 if (uu_list_insert_after(imp_deleted_dpts, NULL, 8335 deldpt) != 0) 8336 uu_die(gettext("libuutil error: %s\n"), 8337 uu_strerror(uu_error())); 8338 8339 break; 8340 default: 8341 bad_error("fmri_equal", r); 8342 } 8343 } 8344 8345 cb.sc_handle = g_hndl; 8346 cb.sc_parent = ent; 8347 cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT; 8348 cb.sc_source_fmri = ent->sc_fmri; 8349 cb.sc_target_fmri = ent->sc_fmri; 8350 cb.sc_trans = NULL; 8351 cb.sc_flags = SCI_FORCE; 8352 8353 if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT) 8354 return (UU_WALK_ERROR); 8355 8356 r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL); 8357 switch (r) { 8358 case 0: 8359 break; 8360 8361 case ENOMEM: 8362 case ECONNABORTED: 8363 case EPERM: 8364 case -1: 8365 warn(gettext("Unable to refresh \"%s\"\n"), 8366 dpt_pgroup->sc_pgroup_fmri); 8367 return (UU_WALK_ERROR); 8368 8369 default: 8370 bad_error("imp_refresh_fmri", r); 8371 } 8372 8373 return (UU_WALK_NEXT); 8374 } 8375 8376 /* 8377 * Returns 8378 * 0 - success 8379 * -1 - lscf_import_instance_pgs() failed. 8380 */ 8381 int 8382 lscf_bundle_apply(bundle_t *bndl, const char *file) 8383 { 8384 pgroup_t *old_dpt; 8385 entity_t *svc, *inst; 8386 int annotation_set = 0; 8387 int ret = 0; 8388 int r = 0; 8389 8390 lscf_prep_hndl(); 8391 8392 if ((ret = alloc_imp_globals())) 8393 goto out; 8394 8395 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) 8396 scfdie(); 8397 8398 /* 8399 * Set the strings to be used for the security audit annotation 8400 * event. 8401 */ 8402 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 8403 annotation_set = 1; 8404 } else { 8405 switch (scf_error()) { 8406 case SCF_ERROR_CONNECTION_BROKEN: 8407 warn(gettext("Repository connection broken.\n")); 8408 goto out; 8409 8410 case SCF_ERROR_INVALID_ARGUMENT: 8411 case SCF_ERROR_NOT_BOUND: 8412 case SCF_ERROR_NO_RESOURCES: 8413 case SCF_ERROR_INTERNAL: 8414 bad_error("_scf_set_annotation", scf_error()); 8415 /* NOTREACHED */ 8416 8417 default: 8418 /* 8419 * Do not abort apply operation because of 8420 * inability to create annotation audit event. 8421 */ 8422 warn(gettext("_scf_set_annotation() unexpectedly " 8423 "failed with return code of %d\n"), scf_error()); 8424 break; 8425 } 8426 } 8427 8428 for (svc = uu_list_first(bndl->sc_bundle_services); 8429 svc != NULL; 8430 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 8431 int refresh = 0; 8432 8433 if (scf_scope_get_service(imp_scope, svc->sc_name, 8434 imp_svc) != 0) { 8435 switch (scf_error()) { 8436 case SCF_ERROR_NOT_FOUND: 8437 if (g_verbose) 8438 warn(gettext("Ignoring nonexistent " 8439 "service %s.\n"), svc->sc_name); 8440 continue; 8441 8442 default: 8443 scfdie(); 8444 } 8445 } 8446 8447 /* 8448 * If there were missing types in the profile, then need to 8449 * attempt to find the types. 8450 */ 8451 if (svc->sc_miss_type) { 8452 if (uu_list_numnodes(svc->sc_pgroups) && 8453 uu_list_walk(svc->sc_pgroups, find_current_pg_type, 8454 svc, UU_DEFAULT) != 0) { 8455 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 8456 bad_error("uu_list_walk", uu_error()); 8457 8458 ret = -1; 8459 continue; 8460 } 8461 8462 for (inst = uu_list_first( 8463 svc->sc_u.sc_service.sc_service_instances); 8464 inst != NULL; 8465 inst = uu_list_next( 8466 svc->sc_u.sc_service.sc_service_instances, inst)) { 8467 /* 8468 * If the instance doesn't exist just 8469 * skip to the next instance and let the 8470 * import note the missing instance. 8471 */ 8472 if (scf_service_get_instance(imp_svc, 8473 inst->sc_name, imp_inst) != 0) 8474 continue; 8475 8476 if (uu_list_walk(inst->sc_pgroups, 8477 find_current_pg_type, inst, 8478 UU_DEFAULT) != 0) { 8479 if (uu_error() != 8480 UU_ERROR_CALLBACK_FAILED) 8481 bad_error("uu_list_walk", 8482 uu_error()); 8483 8484 ret = -1; 8485 inst->sc_miss_type = B_TRUE; 8486 } 8487 } 8488 } 8489 8490 /* 8491 * if we have pgs in the profile, we need to refresh ALL 8492 * instances of the service 8493 */ 8494 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 8495 refresh = 1; 8496 r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc, 8497 SCI_FORCE | SCI_KEEP); 8498 switch (_lscf_import_err(r, svc->sc_fmri)) { 8499 case IMPORT_NEXT: 8500 break; 8501 8502 case IMPORT_OUT: 8503 goto out; 8504 8505 case IMPORT_BAD: 8506 default: 8507 bad_error("lscf_import_service_pgs", r); 8508 } 8509 } 8510 8511 if (uu_list_numnodes(svc->sc_dependents) != 0) { 8512 uu_list_walk(svc->sc_dependents, 8513 lscf_dependent_apply, svc, UU_DEFAULT); 8514 } 8515 8516 for (inst = uu_list_first( 8517 svc->sc_u.sc_service.sc_service_instances); 8518 inst != NULL; 8519 inst = uu_list_next( 8520 svc->sc_u.sc_service.sc_service_instances, inst)) { 8521 /* 8522 * This instance still has missing types 8523 * so skip it. 8524 */ 8525 if (inst->sc_miss_type) { 8526 if (g_verbose) 8527 warn(gettext("Ignoring instance " 8528 "%s:%s with missing types\n"), 8529 inst->sc_parent->sc_name, 8530 inst->sc_name); 8531 8532 continue; 8533 } 8534 8535 if (scf_service_get_instance(imp_svc, inst->sc_name, 8536 imp_inst) != 0) { 8537 switch (scf_error()) { 8538 case SCF_ERROR_NOT_FOUND: 8539 if (g_verbose) 8540 warn(gettext("Ignoring " 8541 "nonexistant instance " 8542 "%s:%s.\n"), 8543 inst->sc_parent->sc_name, 8544 inst->sc_name); 8545 continue; 8546 8547 default: 8548 scfdie(); 8549 } 8550 } 8551 8552 /* 8553 * If the instance does not have a general/enabled 8554 * property and no last-import snapshot then the 8555 * instance is not a fully installed instance and 8556 * should not have a profile applied to it. 8557 * 8558 * This could happen if a service/instance declares 8559 * a dependent on behalf of another service/instance. 8560 * 8561 */ 8562 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 8563 imp_snap) != 0) { 8564 if (scf_instance_get_pg(imp_inst, 8565 SCF_PG_GENERAL, imp_pg) != 0 || 8566 scf_pg_get_property(imp_pg, 8567 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 8568 if (g_verbose) 8569 warn(gettext("Ignoreing " 8570 "partial instance " 8571 "%s:%s.\n"), 8572 inst->sc_parent->sc_name, 8573 inst->sc_name); 8574 continue; 8575 } 8576 } 8577 8578 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, 8579 inst, SCI_FORCE | SCI_KEEP); 8580 switch (_lscf_import_err(r, inst->sc_fmri)) { 8581 case IMPORT_NEXT: 8582 break; 8583 8584 case IMPORT_OUT: 8585 goto out; 8586 8587 case IMPORT_BAD: 8588 default: 8589 bad_error("lscf_import_instance_pgs", r); 8590 } 8591 8592 if (uu_list_numnodes(inst->sc_dependents) != 0) { 8593 uu_list_walk(inst->sc_dependents, 8594 lscf_dependent_apply, inst, UU_DEFAULT); 8595 } 8596 8597 /* refresh only if there is no pgs in the service */ 8598 if (refresh == 0) 8599 (void) refresh_entity(0, imp_inst, 8600 inst->sc_fmri, NULL, NULL, NULL); 8601 } 8602 8603 if (refresh == 1) { 8604 char *name_buf = safe_malloc(max_scf_name_len + 1); 8605 8606 (void) refresh_entity(1, imp_svc, svc->sc_name, 8607 imp_inst, imp_iter, name_buf); 8608 free(name_buf); 8609 } 8610 8611 for (old_dpt = uu_list_first(imp_deleted_dpts); 8612 old_dpt != NULL; 8613 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) { 8614 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 8615 old_dpt->sc_pgroup_name, 8616 old_dpt->sc_parent->sc_fmri) != 0) { 8617 warn(gettext("Unable to refresh \"%s\"\n"), 8618 old_dpt->sc_pgroup_fmri); 8619 } 8620 } 8621 } 8622 8623 out: 8624 if (annotation_set) { 8625 /* Remove security audit annotation strings. */ 8626 (void) _scf_set_annotation(g_hndl, NULL, NULL); 8627 } 8628 8629 free_imp_globals(); 8630 return (ret); 8631 } 8632 8633 8634 /* 8635 * Export. These functions create and output an XML tree of a service 8636 * description from the repository. This is largely the inverse of 8637 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 8638 * 8639 * - We must include any properties which are not represented specifically by 8640 * a service manifest, e.g., properties created by an admin post-import. To 8641 * do so we'll iterate through all properties and deal with each 8642 * apropriately. 8643 * 8644 * - Children of services and instances must must be in the order set by the 8645 * DTD, but we iterate over the properties in undefined order. The elements 8646 * are not easily (or efficiently) sortable by name. Since there's a fixed 8647 * number of classes of them, however, we'll keep the classes separate and 8648 * assemble them in order. 8649 */ 8650 8651 /* 8652 * Convenience function to handle xmlSetProp errors (and type casting). 8653 */ 8654 static void 8655 safe_setprop(xmlNodePtr n, const char *name, const char *val) 8656 { 8657 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 8658 uu_die(gettext("Could not set XML property.\n")); 8659 } 8660 8661 /* 8662 * Convenience function to set an XML attribute to the single value of an 8663 * astring property. If the value happens to be the default, don't set the 8664 * attribute. "dval" should be the default value supplied by the DTD, or 8665 * NULL for no default. 8666 */ 8667 static int 8668 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 8669 const char *name, const char *dval) 8670 { 8671 scf_value_t *val; 8672 ssize_t len; 8673 char *str; 8674 8675 val = scf_value_create(g_hndl); 8676 if (val == NULL) 8677 scfdie(); 8678 8679 if (prop_get_val(prop, val) != 0) { 8680 scf_value_destroy(val); 8681 return (-1); 8682 } 8683 8684 len = scf_value_get_as_string(val, NULL, 0); 8685 if (len < 0) 8686 scfdie(); 8687 8688 str = safe_malloc(len + 1); 8689 8690 if (scf_value_get_as_string(val, str, len + 1) < 0) 8691 scfdie(); 8692 8693 scf_value_destroy(val); 8694 8695 if (dval == NULL || strcmp(str, dval) != 0) 8696 safe_setprop(n, name, str); 8697 8698 free(str); 8699 8700 return (0); 8701 } 8702 8703 /* 8704 * As above, but the attribute is always set. 8705 */ 8706 static int 8707 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 8708 { 8709 return (set_attr_from_prop_default(prop, n, name, NULL)); 8710 } 8711 8712 /* 8713 * Dump the given document onto f, with "'s replaced by ''s. 8714 */ 8715 static int 8716 write_service_bundle(xmlDocPtr doc, FILE *f) 8717 { 8718 xmlChar *mem; 8719 int sz, i; 8720 8721 mem = NULL; 8722 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 8723 8724 if (mem == NULL) { 8725 semerr(gettext("Could not dump XML tree.\n")); 8726 return (-1); 8727 } 8728 8729 /* 8730 * Fortunately libxml produces " instead of ", so we can blindly 8731 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 8732 * ' code?! 8733 */ 8734 for (i = 0; i < sz; ++i) { 8735 char c = (char)mem[i]; 8736 8737 if (c == '"') 8738 (void) fputc('\'', f); 8739 else if (c == '\'') 8740 (void) fwrite("'", sizeof ("'") - 1, 1, f); 8741 else 8742 (void) fputc(c, f); 8743 } 8744 8745 return (0); 8746 } 8747 8748 /* 8749 * Create the DOM elements in elts necessary to (generically) represent prop 8750 * (i.e., a property or propval element). If the name of the property is 8751 * known, it should be passed as name_arg. Otherwise, pass NULL. 8752 */ 8753 static void 8754 export_property(scf_property_t *prop, const char *name_arg, 8755 struct pg_elts *elts, int flags) 8756 { 8757 const char *type; 8758 scf_error_t err = 0; 8759 xmlNodePtr pnode, lnode; 8760 char *lnname; 8761 int ret; 8762 8763 /* name */ 8764 if (name_arg != NULL) { 8765 (void) strcpy(exp_str, name_arg); 8766 } else { 8767 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 8768 scfdie(); 8769 } 8770 8771 /* type */ 8772 type = prop_to_typestr(prop); 8773 if (type == NULL) 8774 uu_die(gettext("Can't export property %s: unknown type.\n"), 8775 exp_str); 8776 8777 /* If we're exporting values, and there's just one, export it here. */ 8778 if (!(flags & SCE_ALL_VALUES)) 8779 goto empty; 8780 8781 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 8782 xmlNodePtr n; 8783 8784 /* Single value, so use propval */ 8785 n = xmlNewNode(NULL, (xmlChar *)"propval"); 8786 if (n == NULL) 8787 uu_die(emsg_create_xml); 8788 8789 safe_setprop(n, name_attr, exp_str); 8790 safe_setprop(n, type_attr, type); 8791 8792 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8793 scfdie(); 8794 safe_setprop(n, value_attr, exp_str); 8795 8796 if (elts->propvals == NULL) 8797 elts->propvals = n; 8798 else 8799 (void) xmlAddSibling(elts->propvals, n); 8800 8801 return; 8802 } 8803 8804 err = scf_error(); 8805 8806 if (err == SCF_ERROR_PERMISSION_DENIED) { 8807 semerr(emsg_permission_denied); 8808 return; 8809 } 8810 8811 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 8812 err != SCF_ERROR_NOT_FOUND && 8813 err != SCF_ERROR_PERMISSION_DENIED) 8814 scfdie(); 8815 8816 empty: 8817 /* Multiple (or no) values, so use property */ 8818 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 8819 if (pnode == NULL) 8820 uu_die(emsg_create_xml); 8821 8822 safe_setprop(pnode, name_attr, exp_str); 8823 safe_setprop(pnode, type_attr, type); 8824 8825 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 8826 lnname = uu_msprintf("%s_list", type); 8827 if (lnname == NULL) 8828 uu_die(gettext("Could not create string")); 8829 8830 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 8831 if (lnode == NULL) 8832 uu_die(emsg_create_xml); 8833 8834 uu_free(lnname); 8835 8836 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 8837 scfdie(); 8838 8839 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 8840 1) { 8841 xmlNodePtr vn; 8842 8843 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 8844 NULL); 8845 if (vn == NULL) 8846 uu_die(emsg_create_xml); 8847 8848 if (scf_value_get_as_string(exp_val, exp_str, 8849 exp_str_sz) < 0) 8850 scfdie(); 8851 safe_setprop(vn, value_attr, exp_str); 8852 } 8853 if (ret != 0) 8854 scfdie(); 8855 } 8856 8857 if (elts->properties == NULL) 8858 elts->properties = pnode; 8859 else 8860 (void) xmlAddSibling(elts->properties, pnode); 8861 } 8862 8863 /* 8864 * Add a property_group element for this property group to elts. 8865 */ 8866 static void 8867 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 8868 { 8869 xmlNodePtr n; 8870 struct pg_elts elts; 8871 int ret; 8872 boolean_t read_protected; 8873 8874 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 8875 8876 /* name */ 8877 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8878 scfdie(); 8879 safe_setprop(n, name_attr, exp_str); 8880 8881 /* type */ 8882 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 8883 scfdie(); 8884 safe_setprop(n, type_attr, exp_str); 8885 8886 /* properties */ 8887 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8888 scfdie(); 8889 8890 (void) memset(&elts, 0, sizeof (elts)); 8891 8892 /* 8893 * If this property group is not read protected, we always want to 8894 * output all the values. Otherwise, we only output the values if the 8895 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 8896 */ 8897 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 8898 scfdie(); 8899 8900 if (!read_protected) 8901 flags |= SCE_ALL_VALUES; 8902 8903 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8904 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8905 scfdie(); 8906 8907 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8908 xmlNodePtr m; 8909 8910 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8911 if (m == NULL) 8912 uu_die(emsg_create_xml); 8913 8914 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8915 elts.stability = m; 8916 continue; 8917 } 8918 8919 xmlFreeNode(m); 8920 } 8921 8922 export_property(exp_prop, NULL, &elts, flags); 8923 } 8924 if (ret == -1) 8925 scfdie(); 8926 8927 (void) xmlAddChild(n, elts.stability); 8928 (void) xmlAddChildList(n, elts.propvals); 8929 (void) xmlAddChildList(n, elts.properties); 8930 8931 if (eelts->property_groups == NULL) 8932 eelts->property_groups = n; 8933 else 8934 (void) xmlAddSibling(eelts->property_groups, n); 8935 } 8936 8937 /* 8938 * Create an XML node representing the dependency described by the given 8939 * property group and put it in eelts. Unless the dependency is not valid, in 8940 * which case create a generic property_group element which represents it and 8941 * put it in eelts. 8942 */ 8943 static void 8944 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 8945 { 8946 xmlNodePtr n; 8947 int err = 0, ret; 8948 struct pg_elts elts; 8949 8950 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 8951 if (n == NULL) 8952 uu_die(emsg_create_xml); 8953 8954 /* 8955 * If the external flag is present, skip this dependency because it 8956 * should have been created by another manifest. 8957 */ 8958 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 8959 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8960 prop_get_val(exp_prop, exp_val) == 0) { 8961 uint8_t b; 8962 8963 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 8964 scfdie(); 8965 8966 if (b) 8967 return; 8968 } 8969 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 8970 scfdie(); 8971 8972 /* Get the required attributes. */ 8973 8974 /* name */ 8975 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8976 scfdie(); 8977 safe_setprop(n, name_attr, exp_str); 8978 8979 /* grouping */ 8980 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8981 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8982 err = 1; 8983 8984 /* restart_on */ 8985 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8986 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8987 err = 1; 8988 8989 /* type */ 8990 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8991 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8992 err = 1; 8993 8994 /* 8995 * entities: Not required, but if we create no children, it will be 8996 * created as empty on import, so fail if it's missing. 8997 */ 8998 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8999 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 9000 scf_iter_t *eiter; 9001 int ret2; 9002 9003 eiter = scf_iter_create(g_hndl); 9004 if (eiter == NULL) 9005 scfdie(); 9006 9007 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 9008 scfdie(); 9009 9010 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 9011 xmlNodePtr ch; 9012 9013 if (scf_value_get_astring(exp_val, exp_str, 9014 exp_str_sz) < 0) 9015 scfdie(); 9016 9017 /* 9018 * service_fmri's must be first, so we can add them 9019 * here. 9020 */ 9021 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 9022 NULL); 9023 if (ch == NULL) 9024 uu_die(emsg_create_xml); 9025 9026 safe_setprop(ch, value_attr, exp_str); 9027 } 9028 if (ret2 == -1) 9029 scfdie(); 9030 9031 scf_iter_destroy(eiter); 9032 } else 9033 err = 1; 9034 9035 if (err) { 9036 xmlFreeNode(n); 9037 9038 export_pg(pg, eelts, 0); 9039 9040 return; 9041 } 9042 9043 /* Iterate through the properties & handle each. */ 9044 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9045 scfdie(); 9046 9047 (void) memset(&elts, 0, sizeof (elts)); 9048 9049 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9050 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9051 scfdie(); 9052 9053 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9054 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9055 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9056 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9057 continue; 9058 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9059 xmlNodePtr m; 9060 9061 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9062 if (m == NULL) 9063 uu_die(emsg_create_xml); 9064 9065 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9066 elts.stability = m; 9067 continue; 9068 } 9069 9070 xmlFreeNode(m); 9071 } 9072 9073 export_property(exp_prop, exp_str, &elts, 0); 9074 } 9075 if (ret == -1) 9076 scfdie(); 9077 9078 (void) xmlAddChild(n, elts.stability); 9079 (void) xmlAddChildList(n, elts.propvals); 9080 (void) xmlAddChildList(n, elts.properties); 9081 9082 if (eelts->dependencies == NULL) 9083 eelts->dependencies = n; 9084 else 9085 (void) xmlAddSibling(eelts->dependencies, n); 9086 } 9087 9088 static xmlNodePtr 9089 export_method_environment(scf_propertygroup_t *pg) 9090 { 9091 xmlNodePtr env; 9092 int ret; 9093 int children = 0; 9094 9095 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 9096 return (NULL); 9097 9098 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 9099 if (env == NULL) 9100 uu_die(emsg_create_xml); 9101 9102 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 9103 scfdie(); 9104 9105 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 9106 scfdie(); 9107 9108 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 9109 xmlNodePtr ev; 9110 char *cp; 9111 9112 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 9113 scfdie(); 9114 9115 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 9116 warn(gettext("Invalid environment variable \"%s\".\n"), 9117 exp_str); 9118 continue; 9119 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 9120 warn(gettext("Invalid environment variable \"%s\"; " 9121 "\"SMF_\" prefix is reserved.\n"), exp_str); 9122 continue; 9123 } 9124 9125 *cp = '\0'; 9126 cp++; 9127 9128 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 9129 if (ev == NULL) 9130 uu_die(emsg_create_xml); 9131 9132 safe_setprop(ev, name_attr, exp_str); 9133 safe_setprop(ev, value_attr, cp); 9134 children++; 9135 } 9136 9137 if (ret != 0) 9138 scfdie(); 9139 9140 if (children == 0) { 9141 xmlFreeNode(env); 9142 return (NULL); 9143 } 9144 9145 return (env); 9146 } 9147 9148 /* 9149 * As above, but for a method property group. 9150 */ 9151 static void 9152 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 9153 { 9154 xmlNodePtr n, env; 9155 char *str; 9156 int err = 0, nonenv, ret; 9157 uint8_t use_profile; 9158 struct pg_elts elts; 9159 xmlNodePtr ctxt = NULL; 9160 9161 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 9162 9163 /* Get the required attributes. */ 9164 9165 /* name */ 9166 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 9167 scfdie(); 9168 safe_setprop(n, name_attr, exp_str); 9169 9170 /* type */ 9171 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 9172 set_attr_from_prop(exp_prop, n, type_attr) != 0) 9173 err = 1; 9174 9175 /* exec */ 9176 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 9177 set_attr_from_prop(exp_prop, n, "exec") != 0) 9178 err = 1; 9179 9180 /* timeout */ 9181 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 9182 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 9183 prop_get_val(exp_prop, exp_val) == 0) { 9184 uint64_t c; 9185 9186 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 9187 scfdie(); 9188 9189 str = uu_msprintf("%llu", c); 9190 if (str == NULL) 9191 uu_die(gettext("Could not create string")); 9192 9193 safe_setprop(n, "timeout_seconds", str); 9194 free(str); 9195 } else 9196 err = 1; 9197 9198 if (err) { 9199 xmlFreeNode(n); 9200 9201 export_pg(pg, eelts, 0); 9202 9203 return; 9204 } 9205 9206 9207 /* 9208 * If we're going to have a method_context child, we need to know 9209 * before we iterate through the properties. Since method_context's 9210 * are optional, we don't want to complain about any properties 9211 * missing if none of them are there. Thus we can't use the 9212 * convenience functions. 9213 */ 9214 nonenv = 9215 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 9216 SCF_SUCCESS || 9217 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 9218 SCF_SUCCESS || 9219 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 9220 SCF_SUCCESS || 9221 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 9222 SCF_SUCCESS; 9223 9224 if (nonenv) { 9225 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9226 if (ctxt == NULL) 9227 uu_die(emsg_create_xml); 9228 9229 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 9230 0 && 9231 set_attr_from_prop_default(exp_prop, ctxt, 9232 "working_directory", ":default") != 0) 9233 err = 1; 9234 9235 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 9236 set_attr_from_prop_default(exp_prop, ctxt, "project", 9237 ":default") != 0) 9238 err = 1; 9239 9240 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 9241 0 && 9242 set_attr_from_prop_default(exp_prop, ctxt, 9243 "resource_pool", ":default") != 0) 9244 err = 1; 9245 /* 9246 * We only want to complain about profile or credential 9247 * properties if we will use them. To determine that we must 9248 * examine USE_PROFILE. 9249 */ 9250 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9251 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9252 prop_get_val(exp_prop, exp_val) == 0) { 9253 if (scf_value_get_boolean(exp_val, &use_profile) != 9254 SCF_SUCCESS) { 9255 scfdie(); 9256 } 9257 9258 if (use_profile) { 9259 xmlNodePtr prof; 9260 9261 prof = xmlNewChild(ctxt, NULL, 9262 (xmlChar *)"method_profile", NULL); 9263 if (prof == NULL) 9264 uu_die(emsg_create_xml); 9265 9266 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 9267 exp_prop) != 0 || 9268 set_attr_from_prop(exp_prop, prof, 9269 name_attr) != 0) 9270 err = 1; 9271 } else { 9272 xmlNodePtr cred; 9273 9274 cred = xmlNewChild(ctxt, NULL, 9275 (xmlChar *)"method_credential", NULL); 9276 if (cred == NULL) 9277 uu_die(emsg_create_xml); 9278 9279 if (pg_get_prop(pg, SCF_PROPERTY_USER, 9280 exp_prop) != 0 || 9281 set_attr_from_prop(exp_prop, cred, 9282 "user") != 0) { 9283 err = 1; 9284 } 9285 9286 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 9287 exp_prop) == 0 && 9288 set_attr_from_prop_default(exp_prop, cred, 9289 "group", ":default") != 0) 9290 err = 1; 9291 9292 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 9293 exp_prop) == 0 && 9294 set_attr_from_prop_default(exp_prop, cred, 9295 "supp_groups", ":default") != 0) 9296 err = 1; 9297 9298 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 9299 exp_prop) == 0 && 9300 set_attr_from_prop_default(exp_prop, cred, 9301 "privileges", ":default") != 0) 9302 err = 1; 9303 9304 if (pg_get_prop(pg, 9305 SCF_PROPERTY_LIMIT_PRIVILEGES, 9306 exp_prop) == 0 && 9307 set_attr_from_prop_default(exp_prop, cred, 9308 "limit_privileges", ":default") != 0) 9309 err = 1; 9310 } 9311 } 9312 } 9313 9314 if ((env = export_method_environment(pg)) != NULL) { 9315 if (ctxt == NULL) { 9316 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 9317 if (ctxt == NULL) 9318 uu_die(emsg_create_xml); 9319 } 9320 (void) xmlAddChild(ctxt, env); 9321 } 9322 9323 if (env != NULL || (nonenv && err == 0)) 9324 (void) xmlAddChild(n, ctxt); 9325 else 9326 xmlFreeNode(ctxt); 9327 9328 nonenv = (err == 0); 9329 9330 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9331 scfdie(); 9332 9333 (void) memset(&elts, 0, sizeof (elts)); 9334 9335 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9336 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9337 scfdie(); 9338 9339 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 9340 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 9341 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 9342 continue; 9343 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9344 xmlNodePtr m; 9345 9346 m = xmlNewNode(NULL, (xmlChar *)"stability"); 9347 if (m == NULL) 9348 uu_die(emsg_create_xml); 9349 9350 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 9351 elts.stability = m; 9352 continue; 9353 } 9354 9355 xmlFreeNode(m); 9356 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 9357 0 || 9358 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 9359 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 9360 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9361 if (nonenv) 9362 continue; 9363 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 9364 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 9365 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 9366 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 9367 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 9368 if (nonenv && !use_profile) 9369 continue; 9370 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9371 if (nonenv && use_profile) 9372 continue; 9373 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 9374 if (env != NULL) 9375 continue; 9376 } 9377 9378 export_property(exp_prop, exp_str, &elts, 0); 9379 } 9380 if (ret == -1) 9381 scfdie(); 9382 9383 (void) xmlAddChild(n, elts.stability); 9384 (void) xmlAddChildList(n, elts.propvals); 9385 (void) xmlAddChildList(n, elts.properties); 9386 9387 if (eelts->exec_methods == NULL) 9388 eelts->exec_methods = n; 9389 else 9390 (void) xmlAddSibling(eelts->exec_methods, n); 9391 } 9392 9393 static void 9394 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 9395 struct entity_elts *eelts) 9396 { 9397 xmlNodePtr pgnode; 9398 9399 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 9400 if (pgnode == NULL) 9401 uu_die(emsg_create_xml); 9402 9403 safe_setprop(pgnode, name_attr, name); 9404 safe_setprop(pgnode, type_attr, type); 9405 9406 (void) xmlAddChildList(pgnode, elts->propvals); 9407 (void) xmlAddChildList(pgnode, elts->properties); 9408 9409 if (eelts->property_groups == NULL) 9410 eelts->property_groups = pgnode; 9411 else 9412 (void) xmlAddSibling(eelts->property_groups, pgnode); 9413 } 9414 9415 /* 9416 * Process the general property group for a service. This is the one with the 9417 * goodies. 9418 */ 9419 static void 9420 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 9421 { 9422 struct pg_elts elts; 9423 int ret; 9424 9425 /* 9426 * In case there are properties which don't correspond to child 9427 * entities of the service entity, we'll set up a pg_elts structure to 9428 * put them in. 9429 */ 9430 (void) memset(&elts, 0, sizeof (elts)); 9431 9432 /* Walk the properties, looking for special ones. */ 9433 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9434 scfdie(); 9435 9436 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9437 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9438 scfdie(); 9439 9440 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 9441 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9442 prop_get_val(exp_prop, exp_val) == 0) { 9443 uint8_t b; 9444 9445 if (scf_value_get_boolean(exp_val, &b) != 9446 SCF_SUCCESS) 9447 scfdie(); 9448 9449 if (b) { 9450 selts->single_instance = 9451 xmlNewNode(NULL, 9452 (xmlChar *)"single_instance"); 9453 if (selts->single_instance == NULL) 9454 uu_die(emsg_create_xml); 9455 } 9456 9457 continue; 9458 } 9459 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9460 xmlNodePtr rnode, sfnode; 9461 9462 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9463 if (rnode == NULL) 9464 uu_die(emsg_create_xml); 9465 9466 sfnode = xmlNewChild(rnode, NULL, 9467 (xmlChar *)"service_fmri", NULL); 9468 if (sfnode == NULL) 9469 uu_die(emsg_create_xml); 9470 9471 if (set_attr_from_prop(exp_prop, sfnode, 9472 value_attr) == 0) { 9473 selts->restarter = rnode; 9474 continue; 9475 } 9476 9477 xmlFreeNode(rnode); 9478 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 9479 0) { 9480 xmlNodePtr s; 9481 9482 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9483 if (s == NULL) 9484 uu_die(emsg_create_xml); 9485 9486 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9487 selts->stability = s; 9488 continue; 9489 } 9490 9491 xmlFreeNode(s); 9492 } 9493 9494 export_property(exp_prop, exp_str, &elts, 0); 9495 } 9496 if (ret == -1) 9497 scfdie(); 9498 9499 if (elts.propvals != NULL || elts.properties != NULL) 9500 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 9501 selts); 9502 } 9503 9504 static void 9505 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 9506 { 9507 xmlNodePtr n, prof, cred, env; 9508 uint8_t use_profile; 9509 int ret, err = 0; 9510 9511 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 9512 9513 env = export_method_environment(pg); 9514 9515 /* Need to know whether we'll use a profile or not. */ 9516 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 9517 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9518 prop_get_val(exp_prop, exp_val) == 0) { 9519 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 9520 scfdie(); 9521 9522 if (use_profile) 9523 prof = 9524 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 9525 NULL); 9526 else 9527 cred = 9528 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 9529 NULL); 9530 } 9531 9532 if (env != NULL) 9533 (void) xmlAddChild(n, env); 9534 9535 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9536 scfdie(); 9537 9538 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9539 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9540 scfdie(); 9541 9542 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 9543 if (set_attr_from_prop(exp_prop, n, 9544 "working_directory") != 0) 9545 err = 1; 9546 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 9547 if (set_attr_from_prop(exp_prop, n, "project") != 0) 9548 err = 1; 9549 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 9550 if (set_attr_from_prop(exp_prop, n, 9551 "resource_pool") != 0) 9552 err = 1; 9553 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 9554 /* EMPTY */ 9555 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 9556 if (use_profile || 9557 set_attr_from_prop(exp_prop, cred, "user") != 0) 9558 err = 1; 9559 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 9560 if (use_profile || 9561 set_attr_from_prop(exp_prop, cred, "group") != 0) 9562 err = 1; 9563 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 9564 if (use_profile || set_attr_from_prop(exp_prop, cred, 9565 "supp_groups") != 0) 9566 err = 1; 9567 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 9568 if (use_profile || set_attr_from_prop(exp_prop, cred, 9569 "privileges") != 0) 9570 err = 1; 9571 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 9572 0) { 9573 if (use_profile || set_attr_from_prop(exp_prop, cred, 9574 "limit_privileges") != 0) 9575 err = 1; 9576 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 9577 if (!use_profile || set_attr_from_prop(exp_prop, 9578 prof, name_attr) != 0) 9579 err = 1; 9580 } else { 9581 /* Can't have generic properties in method_context's */ 9582 err = 1; 9583 } 9584 } 9585 if (ret == -1) 9586 scfdie(); 9587 9588 if (err && env == NULL) { 9589 xmlFreeNode(n); 9590 export_pg(pg, elts, 0); 9591 return; 9592 } 9593 9594 elts->method_context = n; 9595 } 9596 9597 /* 9598 * Given a dependency property group in the tfmri entity (target fmri), return 9599 * a dependent element which represents it. 9600 */ 9601 static xmlNodePtr 9602 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 9603 { 9604 uint8_t b; 9605 xmlNodePtr n, sf; 9606 int err = 0, ret; 9607 struct pg_elts pgelts; 9608 9609 /* 9610 * If external isn't set to true then exporting the service will 9611 * export this as a normal dependency, so we should stop to avoid 9612 * duplication. 9613 */ 9614 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 9615 scf_property_get_value(exp_prop, exp_val) != 0 || 9616 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 9617 if (g_verbose) { 9618 warn(gettext("Dependent \"%s\" cannot be exported " 9619 "properly because the \"%s\" property of the " 9620 "\"%s\" dependency of %s is not set to true.\n"), 9621 name, scf_property_external, name, tfmri); 9622 } 9623 9624 return (NULL); 9625 } 9626 9627 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 9628 if (n == NULL) 9629 uu_die(emsg_create_xml); 9630 9631 safe_setprop(n, name_attr, name); 9632 9633 /* Get the required attributes */ 9634 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 9635 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 9636 err = 1; 9637 9638 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 9639 set_attr_from_prop(exp_prop, n, "grouping") != 0) 9640 err = 1; 9641 9642 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 9643 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 9644 prop_get_val(exp_prop, exp_val) == 0) { 9645 /* EMPTY */ 9646 } else 9647 err = 1; 9648 9649 if (err) { 9650 xmlFreeNode(n); 9651 return (NULL); 9652 } 9653 9654 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 9655 if (sf == NULL) 9656 uu_die(emsg_create_xml); 9657 9658 safe_setprop(sf, value_attr, tfmri); 9659 9660 /* 9661 * Now add elements for the other properties. 9662 */ 9663 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9664 scfdie(); 9665 9666 (void) memset(&pgelts, 0, sizeof (pgelts)); 9667 9668 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9669 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9670 scfdie(); 9671 9672 if (strcmp(exp_str, scf_property_external) == 0 || 9673 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 9674 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 9675 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 9676 continue; 9677 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 9678 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 9679 prop_get_val(exp_prop, exp_val) == 0) { 9680 char type[sizeof ("service") + 1]; 9681 9682 if (scf_value_get_astring(exp_val, type, 9683 sizeof (type)) < 0) 9684 scfdie(); 9685 9686 if (strcmp(type, "service") == 0) 9687 continue; 9688 } 9689 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 9690 xmlNodePtr s; 9691 9692 s = xmlNewNode(NULL, (xmlChar *)"stability"); 9693 if (s == NULL) 9694 uu_die(emsg_create_xml); 9695 9696 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 9697 pgelts.stability = s; 9698 continue; 9699 } 9700 9701 xmlFreeNode(s); 9702 } 9703 9704 export_property(exp_prop, exp_str, &pgelts, 0); 9705 } 9706 if (ret == -1) 9707 scfdie(); 9708 9709 (void) xmlAddChild(n, pgelts.stability); 9710 (void) xmlAddChildList(n, pgelts.propvals); 9711 (void) xmlAddChildList(n, pgelts.properties); 9712 9713 return (n); 9714 } 9715 9716 static void 9717 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 9718 { 9719 scf_propertygroup_t *opg; 9720 scf_iter_t *iter; 9721 char *type, *fmri; 9722 int ret; 9723 struct pg_elts pgelts; 9724 xmlNodePtr n; 9725 scf_error_t serr; 9726 9727 if ((opg = scf_pg_create(g_hndl)) == NULL || 9728 (iter = scf_iter_create(g_hndl)) == NULL) 9729 scfdie(); 9730 9731 /* Can't use exp_prop_iter due to export_dependent(). */ 9732 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 9733 scfdie(); 9734 9735 type = safe_malloc(max_scf_pg_type_len + 1); 9736 9737 /* Get an extra byte so we can tell if values are too long. */ 9738 fmri = safe_malloc(max_scf_fmri_len + 2); 9739 9740 (void) memset(&pgelts, 0, sizeof (pgelts)); 9741 9742 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 9743 void *entity; 9744 int isservice; 9745 scf_type_t ty; 9746 9747 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 9748 scfdie(); 9749 9750 if ((ty != SCF_TYPE_ASTRING && 9751 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 9752 prop_get_val(exp_prop, exp_val) != 0) { 9753 export_property(exp_prop, NULL, &pgelts, 0); 9754 continue; 9755 } 9756 9757 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9758 scfdie(); 9759 9760 if (scf_value_get_astring(exp_val, fmri, 9761 max_scf_fmri_len + 2) < 0) 9762 scfdie(); 9763 9764 /* Look for a dependency group in the target fmri. */ 9765 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 9766 switch (serr) { 9767 case SCF_ERROR_NONE: 9768 break; 9769 9770 case SCF_ERROR_NO_MEMORY: 9771 uu_die(gettext("Out of memory.\n")); 9772 /* NOTREACHED */ 9773 9774 case SCF_ERROR_INVALID_ARGUMENT: 9775 if (g_verbose) { 9776 if (scf_property_to_fmri(exp_prop, fmri, 9777 max_scf_fmri_len + 2) < 0) 9778 scfdie(); 9779 9780 warn(gettext("The value of %s is not a valid " 9781 "FMRI.\n"), fmri); 9782 } 9783 9784 export_property(exp_prop, exp_str, &pgelts, 0); 9785 continue; 9786 9787 case SCF_ERROR_CONSTRAINT_VIOLATED: 9788 if (g_verbose) { 9789 if (scf_property_to_fmri(exp_prop, fmri, 9790 max_scf_fmri_len + 2) < 0) 9791 scfdie(); 9792 9793 warn(gettext("The value of %s does not specify " 9794 "a service or an instance.\n"), fmri); 9795 } 9796 9797 export_property(exp_prop, exp_str, &pgelts, 0); 9798 continue; 9799 9800 case SCF_ERROR_NOT_FOUND: 9801 if (g_verbose) { 9802 if (scf_property_to_fmri(exp_prop, fmri, 9803 max_scf_fmri_len + 2) < 0) 9804 scfdie(); 9805 9806 warn(gettext("The entity specified by %s does " 9807 "not exist.\n"), fmri); 9808 } 9809 9810 export_property(exp_prop, exp_str, &pgelts, 0); 9811 continue; 9812 9813 default: 9814 #ifndef NDEBUG 9815 (void) fprintf(stderr, "%s:%d: %s() failed with " 9816 "unexpected error %d.\n", __FILE__, __LINE__, 9817 "fmri_to_entity", serr); 9818 #endif 9819 abort(); 9820 } 9821 9822 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 9823 if (scf_error() != SCF_ERROR_NOT_FOUND) 9824 scfdie(); 9825 9826 warn(gettext("Entity %s is missing dependency property " 9827 "group %s.\n"), fmri, exp_str); 9828 9829 export_property(exp_prop, NULL, &pgelts, 0); 9830 continue; 9831 } 9832 9833 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 9834 scfdie(); 9835 9836 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 9837 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 9838 scfdie(); 9839 9840 warn(gettext("Property group %s is not of " 9841 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 9842 9843 export_property(exp_prop, NULL, &pgelts, 0); 9844 continue; 9845 } 9846 9847 n = export_dependent(opg, exp_str, fmri); 9848 if (n == NULL) 9849 export_property(exp_prop, exp_str, &pgelts, 0); 9850 else { 9851 if (eelts->dependents == NULL) 9852 eelts->dependents = n; 9853 else 9854 (void) xmlAddSibling(eelts->dependents, 9855 n); 9856 } 9857 } 9858 if (ret == -1) 9859 scfdie(); 9860 9861 free(fmri); 9862 free(type); 9863 9864 scf_iter_destroy(iter); 9865 scf_pg_destroy(opg); 9866 9867 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9868 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 9869 eelts); 9870 } 9871 9872 static void 9873 make_node(xmlNodePtr *nodep, const char *name) 9874 { 9875 if (*nodep == NULL) { 9876 *nodep = xmlNewNode(NULL, (xmlChar *)name); 9877 if (*nodep == NULL) 9878 uu_die(emsg_create_xml); 9879 } 9880 } 9881 9882 static xmlNodePtr 9883 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 9884 { 9885 int ret; 9886 xmlNodePtr parent = NULL; 9887 xmlNodePtr loctext = NULL; 9888 9889 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9890 scfdie(); 9891 9892 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9893 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 9894 prop_get_val(exp_prop, exp_val) != 0) 9895 continue; 9896 9897 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 9898 scfdie(); 9899 9900 make_node(&parent, parname); 9901 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 9902 (xmlChar *)exp_str); 9903 if (loctext == NULL) 9904 uu_die(emsg_create_xml); 9905 9906 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9907 scfdie(); 9908 9909 safe_setprop(loctext, "xml:lang", exp_str); 9910 } 9911 9912 if (ret == -1) 9913 scfdie(); 9914 9915 return (parent); 9916 } 9917 9918 static xmlNodePtr 9919 export_tm_manpage(scf_propertygroup_t *pg) 9920 { 9921 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 9922 if (manpage == NULL) 9923 uu_die(emsg_create_xml); 9924 9925 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 9926 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 9927 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 9928 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 9929 xmlFreeNode(manpage); 9930 return (NULL); 9931 } 9932 9933 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 9934 (void) set_attr_from_prop_default(exp_prop, 9935 manpage, "manpath", ":default"); 9936 9937 return (manpage); 9938 } 9939 9940 static xmlNodePtr 9941 export_tm_doc_link(scf_propertygroup_t *pg) 9942 { 9943 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 9944 if (doc_link == NULL) 9945 uu_die(emsg_create_xml); 9946 9947 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 9948 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 9949 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 9950 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 9951 xmlFreeNode(doc_link); 9952 return (NULL); 9953 } 9954 return (doc_link); 9955 } 9956 9957 /* 9958 * Process template information for a service or instances. 9959 */ 9960 static void 9961 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 9962 struct template_elts *telts) 9963 { 9964 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 9965 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 9966 xmlNodePtr child = NULL; 9967 9968 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 9969 scfdie(); 9970 9971 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 9972 telts->common_name = export_tm_loctext(pg, "common_name"); 9973 if (telts->common_name == NULL) 9974 export_pg(pg, elts, 0); 9975 return; 9976 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 9977 telts->description = export_tm_loctext(pg, "description"); 9978 if (telts->description == NULL) 9979 export_pg(pg, elts, 0); 9980 return; 9981 } 9982 9983 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 9984 child = export_tm_manpage(pg); 9985 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 9986 child = export_tm_doc_link(pg); 9987 } 9988 9989 if (child != NULL) { 9990 make_node(&telts->documentation, "documentation"); 9991 (void) xmlAddChild(telts->documentation, child); 9992 } else { 9993 export_pg(pg, elts, 0); 9994 } 9995 } 9996 9997 /* 9998 * Process the general property group for an instance. 9999 */ 10000 static void 10001 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 10002 struct entity_elts *elts) 10003 { 10004 uint8_t enabled; 10005 struct pg_elts pgelts; 10006 int ret; 10007 10008 /* enabled */ 10009 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 10010 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 10011 prop_get_val(exp_prop, exp_val) == 0) { 10012 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 10013 scfdie(); 10014 } else { 10015 enabled = 0; 10016 } 10017 10018 safe_setprop(inode, enabled_attr, enabled ? true : false); 10019 10020 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 10021 scfdie(); 10022 10023 (void) memset(&pgelts, 0, sizeof (pgelts)); 10024 10025 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 10026 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 10027 scfdie(); 10028 10029 if (strcmp(exp_str, scf_property_enabled) == 0) { 10030 continue; 10031 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 10032 xmlNodePtr rnode, sfnode; 10033 10034 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 10035 if (rnode == NULL) 10036 uu_die(emsg_create_xml); 10037 10038 sfnode = xmlNewChild(rnode, NULL, 10039 (xmlChar *)"service_fmri", NULL); 10040 if (sfnode == NULL) 10041 uu_die(emsg_create_xml); 10042 10043 if (set_attr_from_prop(exp_prop, sfnode, 10044 value_attr) == 0) { 10045 elts->restarter = rnode; 10046 continue; 10047 } 10048 10049 xmlFreeNode(rnode); 10050 } 10051 10052 export_property(exp_prop, exp_str, &pgelts, 0); 10053 } 10054 if (ret == -1) 10055 scfdie(); 10056 10057 if (pgelts.propvals != NULL || pgelts.properties != NULL) 10058 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 10059 elts); 10060 } 10061 10062 /* 10063 * Put an instance element for the given instance into selts. 10064 */ 10065 static void 10066 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 10067 { 10068 xmlNodePtr n; 10069 boolean_t isdefault; 10070 struct entity_elts elts; 10071 struct template_elts template_elts; 10072 int ret; 10073 10074 n = xmlNewNode(NULL, (xmlChar *)"instance"); 10075 if (n == NULL) 10076 uu_die(emsg_create_xml); 10077 10078 /* name */ 10079 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 10080 scfdie(); 10081 safe_setprop(n, name_attr, exp_str); 10082 isdefault = strcmp(exp_str, "default") == 0; 10083 10084 /* check existance of general pg (since general/enabled is required) */ 10085 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 10086 if (scf_error() != SCF_ERROR_NOT_FOUND) 10087 scfdie(); 10088 10089 if (g_verbose) { 10090 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 10091 scfdie(); 10092 10093 warn(gettext("Instance %s has no general property " 10094 "group; it will be marked disabled.\n"), exp_str); 10095 } 10096 10097 safe_setprop(n, enabled_attr, false); 10098 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 10099 strcmp(exp_str, scf_group_framework) != 0) { 10100 if (g_verbose) { 10101 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 10102 scfdie(); 10103 10104 warn(gettext("Property group %s is not of type " 10105 "framework; the instance will be marked " 10106 "disabled.\n"), exp_str); 10107 } 10108 10109 safe_setprop(n, enabled_attr, false); 10110 } 10111 10112 /* property groups */ 10113 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 10114 scfdie(); 10115 10116 (void) memset(&elts, 0, sizeof (elts)); 10117 (void) memset(&template_elts, 0, sizeof (template_elts)); 10118 10119 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10120 uint32_t pgflags; 10121 10122 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10123 scfdie(); 10124 10125 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10126 continue; 10127 10128 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10129 scfdie(); 10130 10131 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10132 export_dependency(exp_pg, &elts); 10133 continue; 10134 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10135 export_method(exp_pg, &elts); 10136 continue; 10137 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10138 if (scf_pg_get_name(exp_pg, exp_str, 10139 max_scf_name_len + 1) < 0) 10140 scfdie(); 10141 10142 if (strcmp(exp_str, scf_pg_general) == 0) { 10143 export_inst_general(exp_pg, n, &elts); 10144 continue; 10145 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10146 0) { 10147 export_method_context(exp_pg, &elts); 10148 continue; 10149 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10150 export_dependents(exp_pg, &elts); 10151 continue; 10152 } 10153 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10154 export_template(exp_pg, &elts, &template_elts); 10155 continue; 10156 } 10157 10158 /* Ordinary pg. */ 10159 export_pg(exp_pg, &elts, flags); 10160 } 10161 if (ret == -1) 10162 scfdie(); 10163 10164 if (template_elts.common_name != NULL) { 10165 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10166 (void) xmlAddChild(elts.template, template_elts.common_name); 10167 (void) xmlAddChild(elts.template, template_elts.description); 10168 (void) xmlAddChild(elts.template, template_elts.documentation); 10169 } else { 10170 xmlFreeNode(template_elts.description); 10171 xmlFreeNode(template_elts.documentation); 10172 } 10173 10174 if (isdefault && elts.restarter == NULL && 10175 elts.dependencies == NULL && elts.method_context == NULL && 10176 elts.exec_methods == NULL && elts.property_groups == NULL && 10177 elts.template == NULL) { 10178 xmlChar *eval; 10179 10180 /* This is a default instance */ 10181 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 10182 10183 xmlFreeNode(n); 10184 10185 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 10186 if (n == NULL) 10187 uu_die(emsg_create_xml); 10188 10189 safe_setprop(n, enabled_attr, (char *)eval); 10190 xmlFree(eval); 10191 10192 selts->create_default_instance = n; 10193 } else { 10194 /* Assemble the children in order. */ 10195 (void) xmlAddChild(n, elts.restarter); 10196 (void) xmlAddChildList(n, elts.dependencies); 10197 (void) xmlAddChildList(n, elts.dependents); 10198 (void) xmlAddChild(n, elts.method_context); 10199 (void) xmlAddChildList(n, elts.exec_methods); 10200 (void) xmlAddChildList(n, elts.property_groups); 10201 (void) xmlAddChild(n, elts.template); 10202 10203 if (selts->instances == NULL) 10204 selts->instances = n; 10205 else 10206 (void) xmlAddSibling(selts->instances, n); 10207 } 10208 } 10209 10210 /* 10211 * Return a service element for the given service. 10212 */ 10213 static xmlNodePtr 10214 export_service(scf_service_t *svc, int flags) 10215 { 10216 xmlNodePtr snode; 10217 struct entity_elts elts; 10218 struct template_elts template_elts; 10219 int ret; 10220 10221 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10222 if (snode == NULL) 10223 uu_die(emsg_create_xml); 10224 10225 /* Get & set name attribute */ 10226 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 10227 scfdie(); 10228 safe_setprop(snode, name_attr, exp_str); 10229 10230 safe_setprop(snode, type_attr, "service"); 10231 safe_setprop(snode, "version", "0"); 10232 10233 /* Acquire child elements. */ 10234 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 10235 scfdie(); 10236 10237 (void) memset(&elts, 0, sizeof (elts)); 10238 (void) memset(&template_elts, 0, sizeof (template_elts)); 10239 10240 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 10241 uint32_t pgflags; 10242 10243 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 10244 scfdie(); 10245 10246 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 10247 continue; 10248 10249 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 10250 scfdie(); 10251 10252 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 10253 export_dependency(exp_pg, &elts); 10254 continue; 10255 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 10256 export_method(exp_pg, &elts); 10257 continue; 10258 } else if (strcmp(exp_str, scf_group_framework) == 0) { 10259 if (scf_pg_get_name(exp_pg, exp_str, 10260 max_scf_name_len + 1) < 0) 10261 scfdie(); 10262 10263 if (strcmp(exp_str, scf_pg_general) == 0) { 10264 export_svc_general(exp_pg, &elts); 10265 continue; 10266 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 10267 0) { 10268 export_method_context(exp_pg, &elts); 10269 continue; 10270 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 10271 export_dependents(exp_pg, &elts); 10272 continue; 10273 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 10274 continue; 10275 } 10276 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 10277 export_template(exp_pg, &elts, &template_elts); 10278 continue; 10279 } 10280 10281 export_pg(exp_pg, &elts, flags); 10282 } 10283 if (ret == -1) 10284 scfdie(); 10285 10286 if (template_elts.common_name != NULL) { 10287 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 10288 (void) xmlAddChild(elts.template, template_elts.common_name); 10289 (void) xmlAddChild(elts.template, template_elts.description); 10290 (void) xmlAddChild(elts.template, template_elts.documentation); 10291 } else { 10292 xmlFreeNode(template_elts.description); 10293 xmlFreeNode(template_elts.documentation); 10294 } 10295 10296 /* Iterate instances */ 10297 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 10298 scfdie(); 10299 10300 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 10301 export_instance(exp_inst, &elts, flags); 10302 if (ret == -1) 10303 scfdie(); 10304 10305 /* Now add all of the accumulated elements in order. */ 10306 (void) xmlAddChild(snode, elts.create_default_instance); 10307 (void) xmlAddChild(snode, elts.single_instance); 10308 (void) xmlAddChild(snode, elts.restarter); 10309 (void) xmlAddChildList(snode, elts.dependencies); 10310 (void) xmlAddChildList(snode, elts.dependents); 10311 (void) xmlAddChild(snode, elts.method_context); 10312 (void) xmlAddChildList(snode, elts.exec_methods); 10313 (void) xmlAddChildList(snode, elts.property_groups); 10314 (void) xmlAddChildList(snode, elts.instances); 10315 (void) xmlAddChild(snode, elts.stability); 10316 (void) xmlAddChild(snode, elts.template); 10317 10318 return (snode); 10319 } 10320 10321 static int 10322 export_callback(void *data, scf_walkinfo_t *wip) 10323 { 10324 FILE *f; 10325 xmlDocPtr doc; 10326 xmlNodePtr sb; 10327 int result; 10328 struct export_args *argsp = (struct export_args *)data; 10329 10330 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 10331 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10332 (exp_prop = scf_property_create(g_hndl)) == NULL || 10333 (exp_val = scf_value_create(g_hndl)) == NULL || 10334 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10335 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10336 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10337 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10338 scfdie(); 10339 10340 exp_str_sz = max_scf_len + 1; 10341 exp_str = safe_malloc(exp_str_sz); 10342 10343 if (argsp->filename != NULL) { 10344 errno = 0; 10345 f = fopen(argsp->filename, "wb"); 10346 if (f == NULL) { 10347 if (errno == 0) 10348 uu_die(gettext("Could not open \"%s\": no free " 10349 "stdio streams.\n"), argsp->filename); 10350 else 10351 uu_die(gettext("Could not open \"%s\""), 10352 argsp->filename); 10353 } 10354 } else 10355 f = stdout; 10356 10357 doc = xmlNewDoc((xmlChar *)"1.0"); 10358 if (doc == NULL) 10359 uu_die(gettext("Could not create XML document.\n")); 10360 10361 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10362 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10363 uu_die(emsg_create_xml); 10364 10365 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10366 if (sb == NULL) 10367 uu_die(emsg_create_xml); 10368 safe_setprop(sb, type_attr, "manifest"); 10369 safe_setprop(sb, name_attr, "export"); 10370 (void) xmlAddSibling(doc->children, sb); 10371 10372 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 10373 10374 result = write_service_bundle(doc, f); 10375 10376 free(exp_str); 10377 scf_iter_destroy(exp_val_iter); 10378 scf_iter_destroy(exp_prop_iter); 10379 scf_iter_destroy(exp_pg_iter); 10380 scf_iter_destroy(exp_inst_iter); 10381 scf_value_destroy(exp_val); 10382 scf_property_destroy(exp_prop); 10383 scf_pg_destroy(exp_pg); 10384 scf_instance_destroy(exp_inst); 10385 10386 xmlFreeDoc(doc); 10387 10388 if (f != stdout) 10389 (void) fclose(f); 10390 10391 return (result); 10392 } 10393 10394 /* 10395 * Get the service named by fmri, build an XML tree which represents it, and 10396 * dump it into filename (or stdout if filename is NULL). 10397 */ 10398 int 10399 lscf_service_export(char *fmri, const char *filename, int flags) 10400 { 10401 struct export_args args; 10402 int ret, err; 10403 10404 lscf_prep_hndl(); 10405 10406 bzero(&args, sizeof (args)); 10407 args.filename = filename; 10408 args.flags = flags; 10409 10410 err = 0; 10411 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 10412 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 10413 &args, &err, semerr)) != 0) { 10414 if (ret != -1) 10415 semerr(gettext("Failed to walk instances: %s\n"), 10416 scf_strerror(ret)); 10417 return (-1); 10418 } 10419 10420 /* 10421 * Error message has already been printed. 10422 */ 10423 if (err != 0) 10424 return (-1); 10425 10426 return (0); 10427 } 10428 10429 10430 /* 10431 * Archive 10432 */ 10433 10434 static xmlNodePtr 10435 make_archive(int flags) 10436 { 10437 xmlNodePtr sb; 10438 scf_scope_t *scope; 10439 scf_service_t *svc; 10440 scf_iter_t *iter; 10441 int r; 10442 10443 if ((scope = scf_scope_create(g_hndl)) == NULL || 10444 (svc = scf_service_create(g_hndl)) == NULL || 10445 (iter = scf_iter_create(g_hndl)) == NULL || 10446 (exp_inst = scf_instance_create(g_hndl)) == NULL || 10447 (exp_pg = scf_pg_create(g_hndl)) == NULL || 10448 (exp_prop = scf_property_create(g_hndl)) == NULL || 10449 (exp_val = scf_value_create(g_hndl)) == NULL || 10450 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 10451 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 10452 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 10453 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 10454 scfdie(); 10455 10456 exp_str_sz = max_scf_len + 1; 10457 exp_str = safe_malloc(exp_str_sz); 10458 10459 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10460 if (sb == NULL) 10461 uu_die(emsg_create_xml); 10462 safe_setprop(sb, type_attr, "archive"); 10463 safe_setprop(sb, name_attr, "none"); 10464 10465 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 10466 scfdie(); 10467 if (scf_iter_scope_services(iter, scope) != 0) 10468 scfdie(); 10469 10470 for (;;) { 10471 r = scf_iter_next_service(iter, svc); 10472 if (r == 0) 10473 break; 10474 if (r != 1) 10475 scfdie(); 10476 10477 if (scf_service_get_name(svc, exp_str, 10478 max_scf_name_len + 1) < 0) 10479 scfdie(); 10480 10481 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 10482 continue; 10483 10484 (void) xmlAddChild(sb, export_service(svc, flags)); 10485 } 10486 10487 free(exp_str); 10488 10489 scf_iter_destroy(exp_val_iter); 10490 scf_iter_destroy(exp_prop_iter); 10491 scf_iter_destroy(exp_pg_iter); 10492 scf_iter_destroy(exp_inst_iter); 10493 scf_value_destroy(exp_val); 10494 scf_property_destroy(exp_prop); 10495 scf_pg_destroy(exp_pg); 10496 scf_instance_destroy(exp_inst); 10497 scf_iter_destroy(iter); 10498 scf_service_destroy(svc); 10499 scf_scope_destroy(scope); 10500 10501 return (sb); 10502 } 10503 10504 int 10505 lscf_archive(const char *filename, int flags) 10506 { 10507 FILE *f; 10508 xmlDocPtr doc; 10509 int result; 10510 10511 lscf_prep_hndl(); 10512 10513 if (filename != NULL) { 10514 errno = 0; 10515 f = fopen(filename, "wb"); 10516 if (f == NULL) { 10517 if (errno == 0) 10518 uu_die(gettext("Could not open \"%s\": no free " 10519 "stdio streams.\n"), filename); 10520 else 10521 uu_die(gettext("Could not open \"%s\""), 10522 filename); 10523 } 10524 } else 10525 f = stdout; 10526 10527 doc = xmlNewDoc((xmlChar *)"1.0"); 10528 if (doc == NULL) 10529 uu_die(gettext("Could not create XML document.\n")); 10530 10531 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10532 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10533 uu_die(emsg_create_xml); 10534 10535 (void) xmlAddSibling(doc->children, make_archive(flags)); 10536 10537 result = write_service_bundle(doc, f); 10538 10539 xmlFreeDoc(doc); 10540 10541 if (f != stdout) 10542 (void) fclose(f); 10543 10544 return (result); 10545 } 10546 10547 10548 /* 10549 * "Extract" a profile. 10550 */ 10551 int 10552 lscf_profile_extract(const char *filename) 10553 { 10554 FILE *f; 10555 xmlDocPtr doc; 10556 xmlNodePtr sb, snode, inode; 10557 scf_scope_t *scope; 10558 scf_service_t *svc; 10559 scf_instance_t *inst; 10560 scf_propertygroup_t *pg; 10561 scf_property_t *prop; 10562 scf_value_t *val; 10563 scf_iter_t *siter, *iiter; 10564 int r, s; 10565 char *namebuf; 10566 uint8_t b; 10567 int result; 10568 10569 lscf_prep_hndl(); 10570 10571 if (filename != NULL) { 10572 errno = 0; 10573 f = fopen(filename, "wb"); 10574 if (f == NULL) { 10575 if (errno == 0) 10576 uu_die(gettext("Could not open \"%s\": no " 10577 "free stdio streams.\n"), filename); 10578 else 10579 uu_die(gettext("Could not open \"%s\""), 10580 filename); 10581 } 10582 } else 10583 f = stdout; 10584 10585 doc = xmlNewDoc((xmlChar *)"1.0"); 10586 if (doc == NULL) 10587 uu_die(gettext("Could not create XML document.\n")); 10588 10589 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 10590 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 10591 uu_die(emsg_create_xml); 10592 10593 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 10594 if (sb == NULL) 10595 uu_die(emsg_create_xml); 10596 safe_setprop(sb, type_attr, "profile"); 10597 safe_setprop(sb, name_attr, "extract"); 10598 (void) xmlAddSibling(doc->children, sb); 10599 10600 if ((scope = scf_scope_create(g_hndl)) == NULL || 10601 (svc = scf_service_create(g_hndl)) == NULL || 10602 (inst = scf_instance_create(g_hndl)) == NULL || 10603 (pg = scf_pg_create(g_hndl)) == NULL || 10604 (prop = scf_property_create(g_hndl)) == NULL || 10605 (val = scf_value_create(g_hndl)) == NULL || 10606 (siter = scf_iter_create(g_hndl)) == NULL || 10607 (iiter = scf_iter_create(g_hndl)) == NULL) 10608 scfdie(); 10609 10610 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 10611 scfdie(); 10612 10613 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 10614 scfdie(); 10615 10616 namebuf = safe_malloc(max_scf_name_len + 1); 10617 10618 while ((r = scf_iter_next_service(siter, svc)) == 1) { 10619 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 10620 scfdie(); 10621 10622 snode = xmlNewNode(NULL, (xmlChar *)"service"); 10623 if (snode == NULL) 10624 uu_die(emsg_create_xml); 10625 10626 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 10627 0) 10628 scfdie(); 10629 10630 safe_setprop(snode, name_attr, namebuf); 10631 10632 safe_setprop(snode, type_attr, "service"); 10633 safe_setprop(snode, "version", "0"); 10634 10635 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 10636 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 10637 SCF_SUCCESS) { 10638 if (scf_error() != SCF_ERROR_NOT_FOUND) 10639 scfdie(); 10640 10641 if (g_verbose) { 10642 ssize_t len; 10643 char *fmri; 10644 10645 len = 10646 scf_instance_to_fmri(inst, NULL, 0); 10647 if (len < 0) 10648 scfdie(); 10649 10650 fmri = safe_malloc(len + 1); 10651 10652 if (scf_instance_to_fmri(inst, fmri, 10653 len + 1) < 0) 10654 scfdie(); 10655 10656 warn("Instance %s has no \"%s\" " 10657 "property group.\n", fmri, 10658 scf_pg_general); 10659 10660 free(fmri); 10661 } 10662 10663 continue; 10664 } 10665 10666 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 10667 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 10668 prop_get_val(prop, val) != 0) 10669 continue; 10670 10671 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 10672 NULL); 10673 if (inode == NULL) 10674 uu_die(emsg_create_xml); 10675 10676 if (scf_instance_get_name(inst, namebuf, 10677 max_scf_name_len + 1) < 0) 10678 scfdie(); 10679 10680 safe_setprop(inode, name_attr, namebuf); 10681 10682 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 10683 scfdie(); 10684 10685 safe_setprop(inode, enabled_attr, b ? true : false); 10686 } 10687 if (s < 0) 10688 scfdie(); 10689 10690 if (snode->children != NULL) 10691 (void) xmlAddChild(sb, snode); 10692 else 10693 xmlFreeNode(snode); 10694 } 10695 if (r < 0) 10696 scfdie(); 10697 10698 free(namebuf); 10699 10700 result = write_service_bundle(doc, f); 10701 10702 xmlFreeDoc(doc); 10703 10704 if (f != stdout) 10705 (void) fclose(f); 10706 10707 return (result); 10708 } 10709 10710 10711 /* 10712 * Entity manipulation commands 10713 */ 10714 10715 /* 10716 * Entity selection. If no entity is selected, then the current scope is in 10717 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 10718 * only cur_inst is NULL, and when an instance is selected, none are NULL. 10719 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 10720 * cur_inst will be non-NULL. 10721 */ 10722 10723 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 10724 static int 10725 select_inst(const char *name) 10726 { 10727 scf_instance_t *inst; 10728 scf_error_t err; 10729 10730 assert(cur_svc != NULL); 10731 10732 inst = scf_instance_create(g_hndl); 10733 if (inst == NULL) 10734 scfdie(); 10735 10736 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 10737 cur_inst = inst; 10738 return (0); 10739 } 10740 10741 err = scf_error(); 10742 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10743 scfdie(); 10744 10745 scf_instance_destroy(inst); 10746 return (1); 10747 } 10748 10749 /* Returns as above. */ 10750 static int 10751 select_svc(const char *name) 10752 { 10753 scf_service_t *svc; 10754 scf_error_t err; 10755 10756 assert(cur_scope != NULL); 10757 10758 svc = scf_service_create(g_hndl); 10759 if (svc == NULL) 10760 scfdie(); 10761 10762 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 10763 cur_svc = svc; 10764 return (0); 10765 } 10766 10767 err = scf_error(); 10768 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10769 scfdie(); 10770 10771 scf_service_destroy(svc); 10772 return (1); 10773 } 10774 10775 /* ARGSUSED */ 10776 static int 10777 select_callback(void *unused, scf_walkinfo_t *wip) 10778 { 10779 scf_instance_t *inst; 10780 scf_service_t *svc; 10781 scf_scope_t *scope; 10782 10783 if (wip->inst != NULL) { 10784 if ((scope = scf_scope_create(g_hndl)) == NULL || 10785 (svc = scf_service_create(g_hndl)) == NULL || 10786 (inst = scf_instance_create(g_hndl)) == NULL) 10787 scfdie(); 10788 10789 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 10790 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 10791 scfdie(); 10792 } else { 10793 assert(wip->svc != NULL); 10794 10795 if ((scope = scf_scope_create(g_hndl)) == NULL || 10796 (svc = scf_service_create(g_hndl)) == NULL) 10797 scfdie(); 10798 10799 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 10800 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 10801 scfdie(); 10802 10803 inst = NULL; 10804 } 10805 10806 /* Clear out the current selection */ 10807 assert(cur_scope != NULL); 10808 scf_scope_destroy(cur_scope); 10809 scf_service_destroy(cur_svc); 10810 scf_instance_destroy(cur_inst); 10811 10812 cur_scope = scope; 10813 cur_svc = svc; 10814 cur_inst = inst; 10815 10816 return (0); 10817 } 10818 10819 static int 10820 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 10821 { 10822 char **fmri = fmri_p; 10823 10824 *fmri = strdup(wip->fmri); 10825 if (*fmri == NULL) 10826 uu_die(gettext("Out of memory.\n")); 10827 10828 return (0); 10829 } 10830 10831 /* 10832 * validate [fmri] 10833 * Perform the validation of an FMRI instance. 10834 */ 10835 void 10836 lscf_validate_fmri(const char *fmri) 10837 { 10838 int ret = 0; 10839 size_t inst_sz; 10840 char *inst_fmri = NULL; 10841 scf_tmpl_errors_t *errs = NULL; 10842 char *snapbuf = NULL; 10843 10844 lscf_prep_hndl(); 10845 10846 if (fmri == NULL) { 10847 inst_sz = max_scf_fmri_len + 1; 10848 inst_fmri = safe_malloc(inst_sz); 10849 10850 if (cur_snap != NULL) { 10851 snapbuf = safe_malloc(max_scf_name_len + 1); 10852 if (scf_snapshot_get_name(cur_snap, snapbuf, 10853 max_scf_name_len + 1) < 0) 10854 scfdie(); 10855 } 10856 if (cur_inst == NULL) { 10857 semerr(gettext("No instance selected\n")); 10858 goto cleanup; 10859 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 10860 inst_sz) >= inst_sz) { 10861 /* sanity check. Should never get here */ 10862 uu_die(gettext("Unexpected error! file %s, line %d\n"), 10863 __FILE__, __LINE__); 10864 } 10865 } else { 10866 scf_error_t scf_err; 10867 int err = 0; 10868 10869 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 10870 validate_callback, &inst_fmri, &err, semerr)) != 0) { 10871 uu_warn("Failed to walk instances: %s\n", 10872 scf_strerror(scf_err)); 10873 goto cleanup; 10874 } 10875 if (err != 0) { 10876 /* error message displayed by scf_walk_fmri */ 10877 goto cleanup; 10878 } 10879 } 10880 10881 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 10882 SCF_TMPL_VALIDATE_FLAG_CURRENT); 10883 if (ret == -1) { 10884 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 10885 warn(gettext("Template data for %s is invalid. " 10886 "Consider reverting to a previous snapshot or " 10887 "restoring original configuration.\n"), inst_fmri); 10888 } else { 10889 uu_warn("%s: %s\n", 10890 gettext("Error validating the instance"), 10891 scf_strerror(scf_error())); 10892 } 10893 } else if (ret == 1 && errs != NULL) { 10894 scf_tmpl_error_t *err = NULL; 10895 char *msg; 10896 size_t len = 256; /* initial error buffer size */ 10897 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 10898 SCF_TMPL_STRERROR_HUMAN : 0; 10899 10900 msg = safe_malloc(len); 10901 10902 while ((err = scf_tmpl_next_error(errs)) != NULL) { 10903 int ret; 10904 10905 if ((ret = scf_tmpl_strerror(err, msg, len, 10906 flag)) >= len) { 10907 len = ret + 1; 10908 msg = realloc(msg, len); 10909 if (msg == NULL) 10910 uu_die(gettext( 10911 "Out of memory.\n")); 10912 (void) scf_tmpl_strerror(err, msg, len, 10913 flag); 10914 } 10915 (void) fprintf(stderr, "%s\n", msg); 10916 } 10917 if (msg != NULL) 10918 free(msg); 10919 } 10920 if (errs != NULL) 10921 scf_tmpl_errors_destroy(errs); 10922 10923 cleanup: 10924 free(inst_fmri); 10925 free(snapbuf); 10926 } 10927 10928 static void 10929 lscf_validate_file(const char *filename) 10930 { 10931 tmpl_errors_t *errs; 10932 10933 bundle_t *b = internal_bundle_new(); 10934 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 10935 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 10936 tmpl_errors_print(stderr, errs, ""); 10937 semerr(gettext("Validation failed.\n")); 10938 } 10939 tmpl_errors_destroy(errs); 10940 } 10941 (void) internal_bundle_free(b); 10942 } 10943 10944 /* 10945 * validate [fmri|file] 10946 */ 10947 void 10948 lscf_validate(const char *arg) 10949 { 10950 const char *str; 10951 10952 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 10953 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 10954 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 10955 lscf_validate_file(str); 10956 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 10957 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 10958 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 10959 lscf_validate_fmri(str); 10960 } else if (access(arg, R_OK | F_OK) == 0) { 10961 lscf_validate_file(arg); 10962 } else { 10963 lscf_validate_fmri(arg); 10964 } 10965 } 10966 10967 void 10968 lscf_select(const char *fmri) 10969 { 10970 int ret, err; 10971 10972 lscf_prep_hndl(); 10973 10974 if (cur_snap != NULL) { 10975 struct snaplevel *elt; 10976 char *buf; 10977 10978 /* Error unless name is that of the next level. */ 10979 elt = uu_list_next(cur_levels, cur_elt); 10980 if (elt == NULL) { 10981 semerr(gettext("No children.\n")); 10982 return; 10983 } 10984 10985 buf = safe_malloc(max_scf_name_len + 1); 10986 10987 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10988 max_scf_name_len + 1) < 0) 10989 scfdie(); 10990 10991 if (strcmp(buf, fmri) != 0) { 10992 semerr(gettext("No such child.\n")); 10993 free(buf); 10994 return; 10995 } 10996 10997 free(buf); 10998 10999 cur_elt = elt; 11000 cur_level = elt->sl; 11001 return; 11002 } 11003 11004 /* 11005 * Special case for 'svc:', which takes the user to the scope level. 11006 */ 11007 if (strcmp(fmri, "svc:") == 0) { 11008 scf_instance_destroy(cur_inst); 11009 scf_service_destroy(cur_svc); 11010 cur_inst = NULL; 11011 cur_svc = NULL; 11012 return; 11013 } 11014 11015 /* 11016 * Special case for ':properties'. This appears as part of 'list' but 11017 * can't be selected. Give a more helpful error message in this case. 11018 */ 11019 if (strcmp(fmri, ":properties") == 0) { 11020 semerr(gettext(":properties is not an entity. Try 'listprop' " 11021 "to list properties.\n")); 11022 return; 11023 } 11024 11025 /* 11026 * First try the argument as relative to the current selection. 11027 */ 11028 if (cur_inst != NULL) { 11029 /* EMPTY */; 11030 } else if (cur_svc != NULL) { 11031 if (select_inst(fmri) != 1) 11032 return; 11033 } else { 11034 if (select_svc(fmri) != 1) 11035 return; 11036 } 11037 11038 err = 0; 11039 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11040 select_callback, NULL, &err, semerr)) != 0) { 11041 semerr(gettext("Failed to walk instances: %s\n"), 11042 scf_strerror(ret)); 11043 } 11044 } 11045 11046 void 11047 lscf_unselect(void) 11048 { 11049 lscf_prep_hndl(); 11050 11051 if (cur_snap != NULL) { 11052 struct snaplevel *elt; 11053 11054 elt = uu_list_prev(cur_levels, cur_elt); 11055 if (elt == NULL) { 11056 semerr(gettext("No parent levels.\n")); 11057 } else { 11058 cur_elt = elt; 11059 cur_level = elt->sl; 11060 } 11061 } else if (cur_inst != NULL) { 11062 scf_instance_destroy(cur_inst); 11063 cur_inst = NULL; 11064 } else if (cur_svc != NULL) { 11065 scf_service_destroy(cur_svc); 11066 cur_svc = NULL; 11067 } else { 11068 semerr(gettext("Cannot unselect at scope level.\n")); 11069 } 11070 } 11071 11072 /* 11073 * Return the FMRI of the current selection, for the prompt. 11074 */ 11075 void 11076 lscf_get_selection_str(char *buf, size_t bufsz) 11077 { 11078 char *cp; 11079 ssize_t fmrilen, szret; 11080 boolean_t deleted = B_FALSE; 11081 11082 if (g_hndl == NULL) { 11083 (void) strlcpy(buf, "svc:", bufsz); 11084 return; 11085 } 11086 11087 if (cur_level != NULL) { 11088 assert(cur_snap != NULL); 11089 11090 /* [ snapshot ] FMRI [: instance ] */ 11091 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 11092 + 2 + max_scf_name_len + 1 + 1); 11093 11094 buf[0] = '['; 11095 11096 szret = scf_snapshot_get_name(cur_snap, buf + 1, 11097 max_scf_name_len + 1); 11098 if (szret < 0) { 11099 if (scf_error() != SCF_ERROR_DELETED) 11100 scfdie(); 11101 11102 goto snap_deleted; 11103 } 11104 11105 (void) strcat(buf, "]svc:/"); 11106 11107 cp = strchr(buf, '\0'); 11108 11109 szret = scf_snaplevel_get_service_name(cur_level, cp, 11110 max_scf_name_len + 1); 11111 if (szret < 0) { 11112 if (scf_error() != SCF_ERROR_DELETED) 11113 scfdie(); 11114 11115 goto snap_deleted; 11116 } 11117 11118 cp = strchr(cp, '\0'); 11119 11120 if (snaplevel_is_instance(cur_level)) { 11121 *cp++ = ':'; 11122 11123 if (scf_snaplevel_get_instance_name(cur_level, cp, 11124 max_scf_name_len + 1) < 0) { 11125 if (scf_error() != SCF_ERROR_DELETED) 11126 scfdie(); 11127 11128 goto snap_deleted; 11129 } 11130 } else { 11131 *cp++ = '['; 11132 *cp++ = ':'; 11133 11134 if (scf_instance_get_name(cur_inst, cp, 11135 max_scf_name_len + 1) < 0) { 11136 if (scf_error() != SCF_ERROR_DELETED) 11137 scfdie(); 11138 11139 goto snap_deleted; 11140 } 11141 11142 (void) strcat(buf, "]"); 11143 } 11144 11145 return; 11146 11147 snap_deleted: 11148 deleted = B_TRUE; 11149 free(buf); 11150 unselect_cursnap(); 11151 } 11152 11153 assert(cur_snap == NULL); 11154 11155 if (cur_inst != NULL) { 11156 assert(cur_svc != NULL); 11157 assert(cur_scope != NULL); 11158 11159 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 11160 if (fmrilen >= 0) { 11161 assert(fmrilen < bufsz); 11162 if (deleted) 11163 warn(emsg_deleted); 11164 return; 11165 } 11166 11167 if (scf_error() != SCF_ERROR_DELETED) 11168 scfdie(); 11169 11170 deleted = B_TRUE; 11171 11172 scf_instance_destroy(cur_inst); 11173 cur_inst = NULL; 11174 } 11175 11176 if (cur_svc != NULL) { 11177 assert(cur_scope != NULL); 11178 11179 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 11180 if (szret >= 0) { 11181 assert(szret < bufsz); 11182 if (deleted) 11183 warn(emsg_deleted); 11184 return; 11185 } 11186 11187 if (scf_error() != SCF_ERROR_DELETED) 11188 scfdie(); 11189 11190 deleted = B_TRUE; 11191 scf_service_destroy(cur_svc); 11192 cur_svc = NULL; 11193 } 11194 11195 assert(cur_scope != NULL); 11196 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 11197 11198 if (fmrilen < 0) 11199 scfdie(); 11200 11201 assert(fmrilen < bufsz); 11202 if (deleted) 11203 warn(emsg_deleted); 11204 } 11205 11206 /* 11207 * Entity listing. Entities and colon namespaces (e.g., :properties and 11208 * :statistics) are listed for the current selection. 11209 */ 11210 void 11211 lscf_list(const char *pattern) 11212 { 11213 scf_iter_t *iter; 11214 char *buf; 11215 int ret; 11216 11217 lscf_prep_hndl(); 11218 11219 if (cur_level != NULL) { 11220 struct snaplevel *elt; 11221 11222 (void) fputs(COLON_NAMESPACES, stdout); 11223 11224 elt = uu_list_next(cur_levels, cur_elt); 11225 if (elt == NULL) 11226 return; 11227 11228 /* 11229 * For now, we know that the next level is an instance. But 11230 * if we ever have multiple scopes, this could be complicated. 11231 */ 11232 buf = safe_malloc(max_scf_name_len + 1); 11233 if (scf_snaplevel_get_instance_name(elt->sl, buf, 11234 max_scf_name_len + 1) >= 0) { 11235 (void) puts(buf); 11236 } else { 11237 if (scf_error() != SCF_ERROR_DELETED) 11238 scfdie(); 11239 } 11240 11241 free(buf); 11242 11243 return; 11244 } 11245 11246 if (cur_inst != NULL) { 11247 (void) fputs(COLON_NAMESPACES, stdout); 11248 return; 11249 } 11250 11251 iter = scf_iter_create(g_hndl); 11252 if (iter == NULL) 11253 scfdie(); 11254 11255 buf = safe_malloc(max_scf_name_len + 1); 11256 11257 if (cur_svc != NULL) { 11258 /* List the instances in this service. */ 11259 scf_instance_t *inst; 11260 11261 inst = scf_instance_create(g_hndl); 11262 if (inst == NULL) 11263 scfdie(); 11264 11265 if (scf_iter_service_instances(iter, cur_svc) == 0) { 11266 safe_printf(COLON_NAMESPACES); 11267 11268 for (;;) { 11269 ret = scf_iter_next_instance(iter, inst); 11270 if (ret == 0) 11271 break; 11272 if (ret != 1) { 11273 if (scf_error() != SCF_ERROR_DELETED) 11274 scfdie(); 11275 11276 break; 11277 } 11278 11279 if (scf_instance_get_name(inst, buf, 11280 max_scf_name_len + 1) >= 0) { 11281 if (pattern == NULL || 11282 fnmatch(pattern, buf, 0) == 0) 11283 (void) puts(buf); 11284 } else { 11285 if (scf_error() != SCF_ERROR_DELETED) 11286 scfdie(); 11287 } 11288 } 11289 } else { 11290 if (scf_error() != SCF_ERROR_DELETED) 11291 scfdie(); 11292 } 11293 11294 scf_instance_destroy(inst); 11295 } else { 11296 /* List the services in this scope. */ 11297 scf_service_t *svc; 11298 11299 assert(cur_scope != NULL); 11300 11301 svc = scf_service_create(g_hndl); 11302 if (svc == NULL) 11303 scfdie(); 11304 11305 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 11306 scfdie(); 11307 11308 for (;;) { 11309 ret = scf_iter_next_service(iter, svc); 11310 if (ret == 0) 11311 break; 11312 if (ret != 1) 11313 scfdie(); 11314 11315 if (scf_service_get_name(svc, buf, 11316 max_scf_name_len + 1) >= 0) { 11317 if (pattern == NULL || 11318 fnmatch(pattern, buf, 0) == 0) 11319 safe_printf("%s\n", buf); 11320 } else { 11321 if (scf_error() != SCF_ERROR_DELETED) 11322 scfdie(); 11323 } 11324 } 11325 11326 scf_service_destroy(svc); 11327 } 11328 11329 free(buf); 11330 scf_iter_destroy(iter); 11331 } 11332 11333 /* 11334 * Entity addition. Creates an empty entity in the current selection. 11335 */ 11336 void 11337 lscf_add(const char *name) 11338 { 11339 lscf_prep_hndl(); 11340 11341 if (cur_snap != NULL) { 11342 semerr(emsg_cant_modify_snapshots); 11343 } else if (cur_inst != NULL) { 11344 semerr(gettext("Cannot add entities to an instance.\n")); 11345 } else if (cur_svc != NULL) { 11346 11347 if (scf_service_add_instance(cur_svc, name, NULL) != 11348 SCF_SUCCESS) { 11349 switch (scf_error()) { 11350 case SCF_ERROR_INVALID_ARGUMENT: 11351 semerr(gettext("Invalid name.\n")); 11352 break; 11353 11354 case SCF_ERROR_EXISTS: 11355 semerr(gettext("Instance already exists.\n")); 11356 break; 11357 11358 case SCF_ERROR_PERMISSION_DENIED: 11359 semerr(emsg_permission_denied); 11360 break; 11361 11362 default: 11363 scfdie(); 11364 } 11365 } 11366 } else { 11367 assert(cur_scope != NULL); 11368 11369 if (scf_scope_add_service(cur_scope, name, NULL) != 11370 SCF_SUCCESS) { 11371 switch (scf_error()) { 11372 case SCF_ERROR_INVALID_ARGUMENT: 11373 semerr(gettext("Invalid name.\n")); 11374 break; 11375 11376 case SCF_ERROR_EXISTS: 11377 semerr(gettext("Service already exists.\n")); 11378 break; 11379 11380 case SCF_ERROR_PERMISSION_DENIED: 11381 semerr(emsg_permission_denied); 11382 break; 11383 11384 case SCF_ERROR_BACKEND_READONLY: 11385 semerr(emsg_read_only); 11386 break; 11387 11388 default: 11389 scfdie(); 11390 } 11391 } 11392 } 11393 } 11394 11395 /* return 1 if the entity has no persistent pgs, else return 0 */ 11396 static int 11397 entity_has_no_pgs(void *ent, int isservice) 11398 { 11399 scf_iter_t *iter = NULL; 11400 scf_propertygroup_t *pg = NULL; 11401 uint32_t flags; 11402 int err; 11403 int ret = 1; 11404 11405 if ((iter = scf_iter_create(g_hndl)) == NULL || 11406 (pg = scf_pg_create(g_hndl)) == NULL) 11407 scfdie(); 11408 11409 if (isservice) { 11410 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 11411 scfdie(); 11412 } else { 11413 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 11414 scfdie(); 11415 } 11416 11417 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11418 if (scf_pg_get_flags(pg, &flags) != 0) 11419 scfdie(); 11420 11421 /* skip nonpersistent pgs */ 11422 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11423 continue; 11424 11425 ret = 0; 11426 break; 11427 } 11428 11429 if (err == -1) 11430 scfdie(); 11431 11432 scf_pg_destroy(pg); 11433 scf_iter_destroy(iter); 11434 11435 return (ret); 11436 } 11437 11438 /* return 1 if the service has no instances, else return 0 */ 11439 static int 11440 svc_has_no_insts(scf_service_t *svc) 11441 { 11442 scf_instance_t *inst; 11443 scf_iter_t *iter; 11444 int r; 11445 int ret = 1; 11446 11447 if ((inst = scf_instance_create(g_hndl)) == NULL || 11448 (iter = scf_iter_create(g_hndl)) == NULL) 11449 scfdie(); 11450 11451 if (scf_iter_service_instances(iter, svc) != 0) 11452 scfdie(); 11453 11454 r = scf_iter_next_instance(iter, inst); 11455 if (r == 1) { 11456 ret = 0; 11457 } else if (r == 0) { 11458 ret = 1; 11459 } else if (r == -1) { 11460 scfdie(); 11461 } else { 11462 bad_error("scf_iter_next_instance", r); 11463 } 11464 11465 scf_iter_destroy(iter); 11466 scf_instance_destroy(inst); 11467 11468 return (ret); 11469 } 11470 11471 /* 11472 * Entity deletion. 11473 */ 11474 11475 /* 11476 * Delete the property group <fmri>/:properties/<name>. Returns 11477 * SCF_ERROR_NONE on success (or if the entity is not found), 11478 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 11479 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 11480 * denied. 11481 */ 11482 static scf_error_t 11483 delete_dependency_pg(const char *fmri, const char *name) 11484 { 11485 void *entity = NULL; 11486 int isservice; 11487 scf_propertygroup_t *pg = NULL; 11488 scf_error_t result; 11489 char *pgty; 11490 scf_service_t *svc = NULL; 11491 scf_instance_t *inst = NULL; 11492 scf_iter_t *iter = NULL; 11493 char *name_buf = NULL; 11494 11495 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 11496 switch (result) { 11497 case SCF_ERROR_NONE: 11498 break; 11499 11500 case SCF_ERROR_NO_MEMORY: 11501 uu_die(gettext("Out of memory.\n")); 11502 /* NOTREACHED */ 11503 11504 case SCF_ERROR_INVALID_ARGUMENT: 11505 case SCF_ERROR_CONSTRAINT_VIOLATED: 11506 return (SCF_ERROR_INVALID_ARGUMENT); 11507 11508 case SCF_ERROR_NOT_FOUND: 11509 result = SCF_ERROR_NONE; 11510 goto out; 11511 11512 default: 11513 bad_error("fmri_to_entity", result); 11514 } 11515 11516 pg = scf_pg_create(g_hndl); 11517 if (pg == NULL) 11518 scfdie(); 11519 11520 if (entity_get_pg(entity, isservice, name, pg) != 0) { 11521 if (scf_error() != SCF_ERROR_NOT_FOUND) 11522 scfdie(); 11523 11524 result = SCF_ERROR_NONE; 11525 goto out; 11526 } 11527 11528 pgty = safe_malloc(max_scf_pg_type_len + 1); 11529 11530 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 11531 scfdie(); 11532 11533 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 11534 result = SCF_ERROR_TYPE_MISMATCH; 11535 free(pgty); 11536 goto out; 11537 } 11538 11539 free(pgty); 11540 11541 if (scf_pg_delete(pg) != 0) { 11542 result = scf_error(); 11543 if (result != SCF_ERROR_PERMISSION_DENIED) 11544 scfdie(); 11545 goto out; 11546 } 11547 11548 /* 11549 * We have to handle the case where we've just deleted the last 11550 * property group of a "dummy" entity (instance or service). 11551 * A "dummy" entity is an entity only present to hold an 11552 * external dependency. 11553 * So, in the case we deleted the last property group then we 11554 * can also delete the entity. If the entity is an instance then 11555 * we must verify if this was the last instance for the service 11556 * and if it is, we can also delete the service if it doesn't 11557 * have any property group either. 11558 */ 11559 11560 result = SCF_ERROR_NONE; 11561 11562 if (isservice) { 11563 svc = (scf_service_t *)entity; 11564 11565 if ((inst = scf_instance_create(g_hndl)) == NULL || 11566 (iter = scf_iter_create(g_hndl)) == NULL) 11567 scfdie(); 11568 11569 name_buf = safe_malloc(max_scf_name_len + 1); 11570 } else { 11571 inst = (scf_instance_t *)entity; 11572 } 11573 11574 /* 11575 * If the entity is an instance and we've just deleted its last 11576 * property group then we should delete it. 11577 */ 11578 if (!isservice && entity_has_no_pgs(entity, isservice)) { 11579 /* find the service before deleting the inst. - needed later */ 11580 if ((svc = scf_service_create(g_hndl)) == NULL) 11581 scfdie(); 11582 11583 if (scf_instance_get_parent(inst, svc) != 0) 11584 scfdie(); 11585 11586 /* delete the instance */ 11587 if (scf_instance_delete(inst) != 0) { 11588 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11589 scfdie(); 11590 11591 result = SCF_ERROR_PERMISSION_DENIED; 11592 goto out; 11593 } 11594 /* no need to refresh the instance */ 11595 inst = NULL; 11596 } 11597 11598 /* 11599 * If the service has no more instances and pgs or we just deleted the 11600 * last instance and the service doesn't have anymore propery groups 11601 * then the service should be deleted. 11602 */ 11603 if (svc != NULL && 11604 svc_has_no_insts(svc) && 11605 entity_has_no_pgs((void *)svc, 1)) { 11606 if (scf_service_delete(svc) == 0) { 11607 if (isservice) { 11608 /* no need to refresh the service */ 11609 svc = NULL; 11610 } 11611 11612 goto out; 11613 } 11614 11615 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11616 scfdie(); 11617 11618 result = SCF_ERROR_PERMISSION_DENIED; 11619 } 11620 11621 /* if the entity has not been deleted, refresh it */ 11622 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 11623 (void) refresh_entity(isservice, entity, fmri, inst, iter, 11624 name_buf); 11625 } 11626 11627 out: 11628 if (isservice && (inst != NULL && iter != NULL)) { 11629 free(name_buf); 11630 scf_iter_destroy(iter); 11631 scf_instance_destroy(inst); 11632 } 11633 11634 if (!isservice && svc != NULL) { 11635 scf_service_destroy(svc); 11636 } 11637 11638 scf_pg_destroy(pg); 11639 if (entity != NULL) 11640 entity_destroy(entity, isservice); 11641 11642 return (result); 11643 } 11644 11645 static int 11646 delete_dependents(scf_propertygroup_t *pg) 11647 { 11648 char *pgty, *name, *fmri; 11649 scf_property_t *prop; 11650 scf_value_t *val; 11651 scf_iter_t *iter; 11652 int r; 11653 scf_error_t err; 11654 11655 /* Verify that the pg has the correct type. */ 11656 pgty = safe_malloc(max_scf_pg_type_len + 1); 11657 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 11658 scfdie(); 11659 11660 if (strcmp(pgty, scf_group_framework) != 0) { 11661 if (g_verbose) { 11662 fmri = safe_malloc(max_scf_fmri_len + 1); 11663 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 11664 scfdie(); 11665 11666 warn(gettext("Property group %s is not of expected " 11667 "type %s.\n"), fmri, scf_group_framework); 11668 11669 free(fmri); 11670 } 11671 11672 free(pgty); 11673 return (-1); 11674 } 11675 11676 free(pgty); 11677 11678 /* map delete_dependency_pg onto the properties. */ 11679 if ((prop = scf_property_create(g_hndl)) == NULL || 11680 (val = scf_value_create(g_hndl)) == NULL || 11681 (iter = scf_iter_create(g_hndl)) == NULL) 11682 scfdie(); 11683 11684 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 11685 scfdie(); 11686 11687 name = safe_malloc(max_scf_name_len + 1); 11688 fmri = safe_malloc(max_scf_fmri_len + 2); 11689 11690 while ((r = scf_iter_next_property(iter, prop)) == 1) { 11691 scf_type_t ty; 11692 11693 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 11694 scfdie(); 11695 11696 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 11697 scfdie(); 11698 11699 if ((ty != SCF_TYPE_ASTRING && 11700 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 11701 prop_get_val(prop, val) != 0) 11702 continue; 11703 11704 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 11705 scfdie(); 11706 11707 err = delete_dependency_pg(fmri, name); 11708 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 11709 if (scf_property_to_fmri(prop, fmri, 11710 max_scf_fmri_len + 2) < 0) 11711 scfdie(); 11712 11713 warn(gettext("Value of %s is not a valid FMRI.\n"), 11714 fmri); 11715 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 11716 warn(gettext("Property group \"%s\" of entity \"%s\" " 11717 "does not have dependency type.\n"), name, fmri); 11718 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 11719 warn(gettext("Could not delete property group \"%s\" " 11720 "of entity \"%s\" (permission denied).\n"), name, 11721 fmri); 11722 } 11723 } 11724 if (r == -1) 11725 scfdie(); 11726 11727 scf_value_destroy(val); 11728 scf_property_destroy(prop); 11729 11730 return (0); 11731 } 11732 11733 /* 11734 * Returns 1 if the instance may be running, and 0 otherwise. 11735 */ 11736 static int 11737 inst_is_running(scf_instance_t *inst) 11738 { 11739 scf_propertygroup_t *pg; 11740 scf_property_t *prop; 11741 scf_value_t *val; 11742 char buf[MAX_SCF_STATE_STRING_SZ]; 11743 int ret = 0; 11744 ssize_t szret; 11745 11746 if ((pg = scf_pg_create(g_hndl)) == NULL || 11747 (prop = scf_property_create(g_hndl)) == NULL || 11748 (val = scf_value_create(g_hndl)) == NULL) 11749 scfdie(); 11750 11751 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 11752 if (scf_error() != SCF_ERROR_NOT_FOUND) 11753 scfdie(); 11754 goto out; 11755 } 11756 11757 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 11758 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 11759 prop_get_val(prop, val) != 0) 11760 goto out; 11761 11762 szret = scf_value_get_astring(val, buf, sizeof (buf)); 11763 assert(szret >= 0); 11764 11765 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 11766 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 11767 11768 out: 11769 scf_value_destroy(val); 11770 scf_property_destroy(prop); 11771 scf_pg_destroy(pg); 11772 return (ret); 11773 } 11774 11775 static uint8_t 11776 pg_is_external_dependency(scf_propertygroup_t *pg) 11777 { 11778 char *type; 11779 scf_value_t *val; 11780 scf_property_t *prop; 11781 uint8_t b = B_FALSE; 11782 11783 type = safe_malloc(max_scf_pg_type_len + 1); 11784 11785 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 11786 scfdie(); 11787 11788 if ((prop = scf_property_create(g_hndl)) == NULL || 11789 (val = scf_value_create(g_hndl)) == NULL) 11790 scfdie(); 11791 11792 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 11793 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 11794 if (scf_property_get_value(prop, val) != 0) 11795 scfdie(); 11796 if (scf_value_get_boolean(val, &b) != 0) 11797 scfdie(); 11798 } 11799 } 11800 11801 free(type); 11802 (void) scf_value_destroy(val); 11803 (void) scf_property_destroy(prop); 11804 11805 return (b); 11806 } 11807 11808 #define DELETE_FAILURE -1 11809 #define DELETE_SUCCESS_NOEXTDEPS 0 11810 #define DELETE_SUCCESS_EXTDEPS 1 11811 11812 /* 11813 * lscf_instance_delete() deletes an instance. Before calling 11814 * scf_instance_delete(), though, we make sure the instance isn't 11815 * running and delete dependencies in other entities which the instance 11816 * declared as "dependents". If there are dependencies which were 11817 * created for other entities, then instead of deleting the instance we 11818 * make it "empty" by deleting all other property groups and all 11819 * snapshots. 11820 * 11821 * lscf_instance_delete() verifies that there is no external dependency pgs 11822 * before suppressing the instance. If there is, then we must not remove them 11823 * now in case the instance is re-created otherwise the dependencies would be 11824 * lost. The external dependency pgs will be removed if the dependencies are 11825 * removed. 11826 * 11827 * Returns: 11828 * DELETE_FAILURE on failure 11829 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 11830 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 11831 */ 11832 static int 11833 lscf_instance_delete(scf_instance_t *inst, int force) 11834 { 11835 scf_propertygroup_t *pg; 11836 scf_snapshot_t *snap; 11837 scf_iter_t *iter; 11838 int err; 11839 int external = 0; 11840 11841 /* If we're not forcing and the instance is running, refuse. */ 11842 if (!force && inst_is_running(inst)) { 11843 char *fmri; 11844 11845 fmri = safe_malloc(max_scf_fmri_len + 1); 11846 11847 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 11848 scfdie(); 11849 11850 semerr(gettext("Instance %s may be running. " 11851 "Use delete -f if it is not.\n"), fmri); 11852 11853 free(fmri); 11854 return (DELETE_FAILURE); 11855 } 11856 11857 pg = scf_pg_create(g_hndl); 11858 if (pg == NULL) 11859 scfdie(); 11860 11861 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 11862 (void) delete_dependents(pg); 11863 else if (scf_error() != SCF_ERROR_NOT_FOUND) 11864 scfdie(); 11865 11866 scf_pg_destroy(pg); 11867 11868 /* 11869 * If the instance has some external dependencies then we must 11870 * keep them in case the instance is reimported otherwise the 11871 * dependencies would be lost on reimport. 11872 */ 11873 if ((iter = scf_iter_create(g_hndl)) == NULL || 11874 (pg = scf_pg_create(g_hndl)) == NULL) 11875 scfdie(); 11876 11877 if (scf_iter_instance_pgs(iter, inst) < 0) 11878 scfdie(); 11879 11880 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11881 if (pg_is_external_dependency(pg)) { 11882 external = 1; 11883 continue; 11884 } 11885 11886 if (scf_pg_delete(pg) != 0) { 11887 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11888 scfdie(); 11889 else { 11890 semerr(emsg_permission_denied); 11891 11892 (void) scf_iter_destroy(iter); 11893 (void) scf_pg_destroy(pg); 11894 return (DELETE_FAILURE); 11895 } 11896 } 11897 } 11898 11899 if (err == -1) 11900 scfdie(); 11901 11902 (void) scf_iter_destroy(iter); 11903 (void) scf_pg_destroy(pg); 11904 11905 if (external) { 11906 /* 11907 * All the pgs have been deleted for the instance except 11908 * the ones holding the external dependencies. 11909 * For the job to be complete, we must also delete the 11910 * snapshots associated with the instance. 11911 */ 11912 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 11913 NULL) 11914 scfdie(); 11915 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 11916 scfdie(); 11917 11918 if (scf_iter_instance_snapshots(iter, inst) == -1) 11919 scfdie(); 11920 11921 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 11922 if (_scf_snapshot_delete(snap) != 0) { 11923 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11924 scfdie(); 11925 11926 semerr(emsg_permission_denied); 11927 11928 (void) scf_iter_destroy(iter); 11929 (void) scf_snapshot_destroy(snap); 11930 return (DELETE_FAILURE); 11931 } 11932 } 11933 11934 if (err == -1) 11935 scfdie(); 11936 11937 (void) scf_iter_destroy(iter); 11938 (void) scf_snapshot_destroy(snap); 11939 return (DELETE_SUCCESS_EXTDEPS); 11940 } 11941 11942 if (scf_instance_delete(inst) != 0) { 11943 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11944 scfdie(); 11945 11946 semerr(emsg_permission_denied); 11947 11948 return (DELETE_FAILURE); 11949 } 11950 11951 return (DELETE_SUCCESS_NOEXTDEPS); 11952 } 11953 11954 /* 11955 * lscf_service_delete() deletes a service. Before calling 11956 * scf_service_delete(), though, we call lscf_instance_delete() for 11957 * each of the instances and delete dependencies in other entities 11958 * which were created as "dependents" of this service. If there are 11959 * dependencies which were created for other entities, then we delete 11960 * all other property groups in the service and leave it as "empty". 11961 * 11962 * lscf_service_delete() verifies that there is no external dependency 11963 * pgs at the instance & service level before suppressing the service. 11964 * If there is, then we must not remove them now in case the service 11965 * is re-imported otherwise the dependencies would be lost. The external 11966 * dependency pgs will be removed if the dependencies are removed. 11967 * 11968 * Returns: 11969 * DELETE_FAILURE on failure 11970 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 11971 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 11972 */ 11973 static int 11974 lscf_service_delete(scf_service_t *svc, int force) 11975 { 11976 int r; 11977 scf_instance_t *inst; 11978 scf_propertygroup_t *pg; 11979 scf_iter_t *iter; 11980 int ret; 11981 int external = 0; 11982 11983 if ((inst = scf_instance_create(g_hndl)) == NULL || 11984 (pg = scf_pg_create(g_hndl)) == NULL || 11985 (iter = scf_iter_create(g_hndl)) == NULL) 11986 scfdie(); 11987 11988 if (scf_iter_service_instances(iter, svc) != 0) 11989 scfdie(); 11990 11991 for (r = scf_iter_next_instance(iter, inst); 11992 r == 1; 11993 r = scf_iter_next_instance(iter, inst)) { 11994 11995 ret = lscf_instance_delete(inst, force); 11996 if (ret == DELETE_FAILURE) { 11997 scf_iter_destroy(iter); 11998 scf_pg_destroy(pg); 11999 scf_instance_destroy(inst); 12000 return (DELETE_FAILURE); 12001 } 12002 12003 /* 12004 * Record the fact that there is some external dependencies 12005 * at the instance level. 12006 */ 12007 if (ret == DELETE_SUCCESS_EXTDEPS) 12008 external |= 1; 12009 } 12010 12011 if (r != 0) 12012 scfdie(); 12013 12014 /* Delete dependency property groups in dependent services. */ 12015 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 12016 (void) delete_dependents(pg); 12017 else if (scf_error() != SCF_ERROR_NOT_FOUND) 12018 scfdie(); 12019 12020 scf_iter_destroy(iter); 12021 scf_pg_destroy(pg); 12022 scf_instance_destroy(inst); 12023 12024 /* 12025 * If the service has some external dependencies then we don't 12026 * want to remove them in case the service is re-imported. 12027 */ 12028 if ((pg = scf_pg_create(g_hndl)) == NULL || 12029 (iter = scf_iter_create(g_hndl)) == NULL) 12030 scfdie(); 12031 12032 if (scf_iter_service_pgs(iter, svc) < 0) 12033 scfdie(); 12034 12035 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 12036 if (pg_is_external_dependency(pg)) { 12037 external |= 2; 12038 continue; 12039 } 12040 12041 if (scf_pg_delete(pg) != 0) { 12042 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12043 scfdie(); 12044 else { 12045 semerr(emsg_permission_denied); 12046 12047 (void) scf_iter_destroy(iter); 12048 (void) scf_pg_destroy(pg); 12049 return (DELETE_FAILURE); 12050 } 12051 } 12052 } 12053 12054 if (r == -1) 12055 scfdie(); 12056 12057 (void) scf_iter_destroy(iter); 12058 (void) scf_pg_destroy(pg); 12059 12060 if (external != 0) 12061 return (DELETE_SUCCESS_EXTDEPS); 12062 12063 if (scf_service_delete(svc) == 0) 12064 return (DELETE_SUCCESS_NOEXTDEPS); 12065 12066 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12067 scfdie(); 12068 12069 semerr(emsg_permission_denied); 12070 return (DELETE_FAILURE); 12071 } 12072 12073 static int 12074 delete_callback(void *data, scf_walkinfo_t *wip) 12075 { 12076 int force = (int)data; 12077 12078 if (wip->inst != NULL) 12079 (void) lscf_instance_delete(wip->inst, force); 12080 else 12081 (void) lscf_service_delete(wip->svc, force); 12082 12083 return (0); 12084 } 12085 12086 void 12087 lscf_delete(const char *fmri, int force) 12088 { 12089 scf_service_t *svc; 12090 scf_instance_t *inst; 12091 int ret; 12092 12093 lscf_prep_hndl(); 12094 12095 if (cur_snap != NULL) { 12096 if (!snaplevel_is_instance(cur_level)) { 12097 char *buf; 12098 12099 buf = safe_malloc(max_scf_name_len + 1); 12100 if (scf_instance_get_name(cur_inst, buf, 12101 max_scf_name_len + 1) >= 0) { 12102 if (strcmp(buf, fmri) == 0) { 12103 semerr(emsg_cant_modify_snapshots); 12104 free(buf); 12105 return; 12106 } 12107 } else if (scf_error() != SCF_ERROR_DELETED) { 12108 scfdie(); 12109 } 12110 free(buf); 12111 } 12112 } else if (cur_inst != NULL) { 12113 /* EMPTY */; 12114 } else if (cur_svc != NULL) { 12115 inst = scf_instance_create(g_hndl); 12116 if (inst == NULL) 12117 scfdie(); 12118 12119 if (scf_service_get_instance(cur_svc, fmri, inst) == 12120 SCF_SUCCESS) { 12121 (void) lscf_instance_delete(inst, force); 12122 scf_instance_destroy(inst); 12123 return; 12124 } 12125 12126 if (scf_error() != SCF_ERROR_NOT_FOUND && 12127 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12128 scfdie(); 12129 12130 scf_instance_destroy(inst); 12131 } else { 12132 assert(cur_scope != NULL); 12133 12134 svc = scf_service_create(g_hndl); 12135 if (svc == NULL) 12136 scfdie(); 12137 12138 if (scf_scope_get_service(cur_scope, fmri, svc) == 12139 SCF_SUCCESS) { 12140 (void) lscf_service_delete(svc, force); 12141 scf_service_destroy(svc); 12142 return; 12143 } 12144 12145 if (scf_error() != SCF_ERROR_NOT_FOUND && 12146 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 12147 scfdie(); 12148 12149 scf_service_destroy(svc); 12150 } 12151 12152 /* 12153 * Match FMRI to entity. 12154 */ 12155 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 12156 delete_callback, (void *)force, NULL, semerr)) != 0) { 12157 semerr(gettext("Failed to walk instances: %s\n"), 12158 scf_strerror(ret)); 12159 } 12160 } 12161 12162 12163 12164 /* 12165 * :properties commands. These all end with "pg" or "prop" and generally 12166 * operate on the currently selected entity. 12167 */ 12168 12169 /* 12170 * Property listing. List the property groups, properties, their types and 12171 * their values for the currently selected entity. 12172 */ 12173 static void 12174 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 12175 { 12176 char *buf; 12177 uint32_t flags; 12178 12179 buf = safe_malloc(max_scf_pg_type_len + 1); 12180 12181 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 12182 scfdie(); 12183 12184 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 12185 scfdie(); 12186 12187 safe_printf("%-*s %s", namewidth, name, buf); 12188 12189 if (flags & SCF_PG_FLAG_NONPERSISTENT) 12190 safe_printf("\tNONPERSISTENT"); 12191 12192 safe_printf("\n"); 12193 12194 free(buf); 12195 } 12196 12197 static boolean_t 12198 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 12199 { 12200 if (scf_property_get_value(prop, val) == 0) { 12201 return (B_FALSE); 12202 } else { 12203 switch (scf_error()) { 12204 case SCF_ERROR_NOT_FOUND: 12205 return (B_FALSE); 12206 case SCF_ERROR_PERMISSION_DENIED: 12207 case SCF_ERROR_CONSTRAINT_VIOLATED: 12208 return (B_TRUE); 12209 default: 12210 scfdie(); 12211 /*NOTREACHED*/ 12212 } 12213 } 12214 } 12215 12216 static void 12217 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 12218 { 12219 scf_iter_t *iter; 12220 scf_value_t *val; 12221 const char *type; 12222 int multiple_strings = 0; 12223 int ret; 12224 12225 if ((iter = scf_iter_create(g_hndl)) == NULL || 12226 (val = scf_value_create(g_hndl)) == NULL) 12227 scfdie(); 12228 12229 type = prop_to_typestr(prop); 12230 assert(type != NULL); 12231 12232 safe_printf("%-*s %-7s ", len, name, type); 12233 12234 if (prop_has_multiple_values(prop, val) && 12235 (scf_value_type(val) == SCF_TYPE_ASTRING || 12236 scf_value_type(val) == SCF_TYPE_USTRING)) 12237 multiple_strings = 1; 12238 12239 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12240 scfdie(); 12241 12242 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12243 char *buf; 12244 ssize_t vlen, szret; 12245 12246 vlen = scf_value_get_as_string(val, NULL, 0); 12247 if (vlen < 0) 12248 scfdie(); 12249 12250 buf = safe_malloc(vlen + 1); 12251 12252 szret = scf_value_get_as_string(val, buf, vlen + 1); 12253 if (szret < 0) 12254 scfdie(); 12255 assert(szret <= vlen); 12256 12257 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12258 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 12259 safe_printf(" \""); 12260 (void) quote_and_print(buf, stdout, 0); 12261 (void) putchar('"'); 12262 if (ferror(stdout)) { 12263 (void) putchar('\n'); 12264 uu_die(gettext("Error writing to stdout.\n")); 12265 } 12266 } else { 12267 safe_printf(" %s", buf); 12268 } 12269 12270 free(buf); 12271 } 12272 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12273 scfdie(); 12274 12275 if (putchar('\n') != '\n') 12276 uu_die(gettext("Could not output newline")); 12277 } 12278 12279 /* 12280 * Outputs template property group info for the describe subcommand. 12281 * If 'templates' == 2, verbose output is printed in the format expected 12282 * for describe -v, which includes all templates fields. If pg is 12283 * not NULL, we're describing the template data, not an existing property 12284 * group, and formatting should be appropriate for describe -t. 12285 */ 12286 static void 12287 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 12288 { 12289 char *buf; 12290 uint8_t required; 12291 scf_property_t *stability_prop; 12292 scf_value_t *stability_val; 12293 12294 if (templates == 0) 12295 return; 12296 12297 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 12298 (stability_val = scf_value_create(g_hndl)) == NULL) 12299 scfdie(); 12300 12301 if (templates == 2 && pg != NULL) { 12302 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 12303 stability_prop) == 0) { 12304 if (prop_check_type(stability_prop, 12305 SCF_TYPE_ASTRING) == 0 && 12306 prop_get_val(stability_prop, stability_val) == 0) { 12307 char *stability; 12308 12309 stability = safe_malloc(max_scf_value_len + 1); 12310 12311 if (scf_value_get_astring(stability_val, 12312 stability, max_scf_value_len + 1) == -1 && 12313 scf_error() != SCF_ERROR_NOT_FOUND) 12314 scfdie(); 12315 12316 safe_printf("%s%s: %s\n", TMPL_INDENT, 12317 gettext("stability"), stability); 12318 12319 free(stability); 12320 } 12321 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 12322 scfdie(); 12323 } 12324 12325 scf_property_destroy(stability_prop); 12326 scf_value_destroy(stability_val); 12327 12328 if (pgt == NULL) 12329 return; 12330 12331 if (pg == NULL || templates == 2) { 12332 /* print type info only if scf_tmpl_pg_name succeeds */ 12333 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 12334 if (pg != NULL) 12335 safe_printf("%s", TMPL_INDENT); 12336 safe_printf("%s: ", gettext("name")); 12337 safe_printf("%s\n", buf); 12338 free(buf); 12339 } 12340 12341 /* print type info only if scf_tmpl_pg_type succeeds */ 12342 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 12343 if (pg != NULL) 12344 safe_printf("%s", TMPL_INDENT); 12345 safe_printf("%s: ", gettext("type")); 12346 safe_printf("%s\n", buf); 12347 free(buf); 12348 } 12349 } 12350 12351 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 12352 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12353 required ? "true" : "false"); 12354 12355 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 12356 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 12357 buf); 12358 free(buf); 12359 } 12360 12361 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 12362 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12363 buf); 12364 free(buf); 12365 } 12366 12367 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 12368 if (templates == 2) 12369 safe_printf("%s%s: %s\n", TMPL_INDENT, 12370 gettext("description"), buf); 12371 else 12372 safe_printf("%s%s\n", TMPL_INDENT, buf); 12373 free(buf); 12374 } 12375 12376 } 12377 12378 /* 12379 * With as_value set to true, indent as appropriate for the value level. 12380 * If false, indent to appropriate level for inclusion in constraint 12381 * or choice printout. 12382 */ 12383 static void 12384 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 12385 int as_value) 12386 { 12387 char *buf; 12388 12389 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 12390 if (as_value == 0) 12391 safe_printf("%s", TMPL_CHOICE_INDENT); 12392 else 12393 safe_printf("%s", TMPL_INDENT); 12394 safe_printf("%s: %s\n", gettext("value common name"), buf); 12395 free(buf); 12396 } 12397 12398 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 12399 if (as_value == 0) 12400 safe_printf("%s", TMPL_CHOICE_INDENT); 12401 else 12402 safe_printf("%s", TMPL_INDENT); 12403 safe_printf("%s: %s\n", gettext("value description"), buf); 12404 free(buf); 12405 } 12406 } 12407 12408 static void 12409 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 12410 { 12411 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 12412 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 12413 safe_printf("%s\n", val_buf); 12414 12415 print_template_value_details(prt, val_buf, 1); 12416 } 12417 12418 static void 12419 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 12420 { 12421 int i, printed = 0; 12422 scf_values_t values; 12423 scf_count_ranges_t c_ranges; 12424 scf_int_ranges_t i_ranges; 12425 12426 printed = 0; 12427 i = 0; 12428 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 12429 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12430 gettext("value constraints")); 12431 printed++; 12432 for (i = 0; i < values.value_count; ++i) { 12433 safe_printf("%s%s: %s\n", TMPL_INDENT, 12434 gettext("value name"), values.values_as_strings[i]); 12435 if (verbose == 1) 12436 print_template_value_details(prt, 12437 values.values_as_strings[i], 0); 12438 } 12439 12440 scf_values_destroy(&values); 12441 } 12442 12443 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 12444 if (printed++ == 0) 12445 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12446 gettext("value constraints")); 12447 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12448 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12449 gettext("range"), c_ranges.scr_min[i], 12450 c_ranges.scr_max[i]); 12451 } 12452 scf_count_ranges_destroy(&c_ranges); 12453 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12454 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 12455 if (printed++ == 0) 12456 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12457 gettext("value constraints")); 12458 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12459 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12460 gettext("range"), i_ranges.sir_min[i], 12461 i_ranges.sir_max[i]); 12462 } 12463 scf_int_ranges_destroy(&i_ranges); 12464 } 12465 } 12466 12467 static void 12468 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 12469 { 12470 int i = 0, printed = 0; 12471 scf_values_t values; 12472 scf_count_ranges_t c_ranges; 12473 scf_int_ranges_t i_ranges; 12474 12475 printed = 0; 12476 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 12477 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12478 gettext("value constraints")); 12479 printed++; 12480 for (i = 0; i < values.value_count; i++) { 12481 safe_printf("%s%s: %s\n", TMPL_INDENT, 12482 gettext("value name"), values.values_as_strings[i]); 12483 if (verbose == 1) 12484 print_template_value_details(prt, 12485 values.values_as_strings[i], 0); 12486 } 12487 12488 scf_values_destroy(&values); 12489 } 12490 12491 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 12492 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 12493 if (printed++ == 0) 12494 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12495 gettext("value choices")); 12496 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 12497 gettext("range"), c_ranges.scr_min[i], 12498 c_ranges.scr_max[i]); 12499 } 12500 scf_count_ranges_destroy(&c_ranges); 12501 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 12502 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 12503 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 12504 if (printed++ == 0) 12505 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 12506 gettext("value choices")); 12507 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 12508 gettext("range"), i_ranges.sir_min[i], 12509 i_ranges.sir_max[i]); 12510 } 12511 scf_int_ranges_destroy(&i_ranges); 12512 } 12513 } 12514 12515 static void 12516 list_values_by_template(scf_prop_tmpl_t *prt) 12517 { 12518 print_template_constraints(prt, 1); 12519 print_template_choices(prt, 1); 12520 } 12521 12522 static void 12523 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 12524 { 12525 char *val_buf; 12526 scf_iter_t *iter; 12527 scf_value_t *val; 12528 int ret; 12529 12530 if ((iter = scf_iter_create(g_hndl)) == NULL || 12531 (val = scf_value_create(g_hndl)) == NULL) 12532 scfdie(); 12533 12534 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 12535 scfdie(); 12536 12537 val_buf = safe_malloc(max_scf_value_len + 1); 12538 12539 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12540 if (scf_value_get_as_string(val, val_buf, 12541 max_scf_value_len + 1) < 0) 12542 scfdie(); 12543 12544 print_template_value(prt, val_buf); 12545 } 12546 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 12547 scfdie(); 12548 free(val_buf); 12549 12550 print_template_constraints(prt, 0); 12551 print_template_choices(prt, 0); 12552 12553 } 12554 12555 /* 12556 * Outputs property info for the describe subcommand 12557 * Verbose output if templates == 2, -v option of svccfg describe 12558 * Displays template data if prop is not NULL, -t option of svccfg describe 12559 */ 12560 static void 12561 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 12562 { 12563 char *buf; 12564 uint8_t u_buf; 12565 int i; 12566 uint64_t min, max; 12567 scf_values_t values; 12568 12569 if (prt == NULL || templates == 0) 12570 return; 12571 12572 if (prop == NULL) { 12573 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 12574 if (scf_tmpl_prop_name(prt, &buf) > 0) { 12575 safe_printf("%s\n", buf); 12576 free(buf); 12577 } else 12578 safe_printf("(%s)\n", gettext("any")); 12579 } 12580 12581 if (prop == NULL || templates == 2) { 12582 if (prop != NULL) 12583 safe_printf("%s", TMPL_INDENT); 12584 else 12585 safe_printf("%s", TMPL_VALUE_INDENT); 12586 safe_printf("%s: ", gettext("type")); 12587 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 12588 safe_printf("%s\n", buf); 12589 free(buf); 12590 } else 12591 safe_printf("(%s)\n", gettext("any")); 12592 } 12593 12594 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 12595 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 12596 u_buf ? "true" : "false"); 12597 12598 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 12599 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 12600 buf); 12601 free(buf); 12602 } 12603 12604 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 12605 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 12606 buf); 12607 free(buf); 12608 } 12609 12610 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 12611 safe_printf("%s%s\n", TMPL_INDENT, buf); 12612 free(buf); 12613 } 12614 12615 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 12616 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 12617 scf_tmpl_visibility_to_string(u_buf)); 12618 12619 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 12620 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 12621 gettext("minimum number of values"), min); 12622 if (max == ULLONG_MAX) { 12623 safe_printf("%s%s: %s\n", TMPL_INDENT, 12624 gettext("maximum number of values"), 12625 gettext("unlimited")); 12626 } else { 12627 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 12628 gettext("maximum number of values"), max); 12629 } 12630 } 12631 12632 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 12633 for (i = 0; i < values.value_count; i++) { 12634 if (i == 0) { 12635 safe_printf("%s%s:", TMPL_INDENT, 12636 gettext("internal separators")); 12637 } 12638 safe_printf(" \"%s\"", values.values_as_strings[i]); 12639 } 12640 safe_printf("\n"); 12641 } 12642 12643 if (templates != 2) 12644 return; 12645 12646 if (prop != NULL) 12647 list_values_tmpl(prt, prop); 12648 else 12649 list_values_by_template(prt); 12650 } 12651 12652 static char * 12653 read_astring(scf_propertygroup_t *pg, const char *prop_name) 12654 { 12655 char *rv; 12656 12657 rv = _scf_read_single_astring_from_pg(pg, prop_name); 12658 if (rv == NULL) { 12659 switch (scf_error()) { 12660 case SCF_ERROR_NOT_FOUND: 12661 break; 12662 default: 12663 scfdie(); 12664 } 12665 } 12666 return (rv); 12667 } 12668 12669 static void 12670 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 12671 { 12672 size_t doc_len; 12673 size_t man_len; 12674 char *pg_name; 12675 char *text = NULL; 12676 int rv; 12677 12678 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 12679 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 12680 pg_name = safe_malloc(max_scf_name_len + 1); 12681 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 12682 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 12683 scfdie(); 12684 } 12685 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 12686 /* Display doc_link and and uri */ 12687 safe_printf("%s%s:\n", TMPL_INDENT, 12688 gettext("doc_link")); 12689 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 12690 if (text != NULL) { 12691 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12692 TMPL_INDENT, gettext("name"), text); 12693 uu_free(text); 12694 } 12695 text = read_astring(pg, SCF_PROPERTY_TM_URI); 12696 if (text != NULL) { 12697 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 12698 gettext("uri"), text); 12699 uu_free(text); 12700 } 12701 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 12702 man_len) == 0) { 12703 /* Display manpage title, section and path */ 12704 safe_printf("%s%s:\n", TMPL_INDENT, 12705 gettext("manpage")); 12706 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 12707 if (text != NULL) { 12708 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12709 TMPL_INDENT, gettext("title"), text); 12710 uu_free(text); 12711 } 12712 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 12713 if (text != NULL) { 12714 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12715 TMPL_INDENT, gettext("section"), text); 12716 uu_free(text); 12717 } 12718 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 12719 if (text != NULL) { 12720 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 12721 TMPL_INDENT, gettext("manpath"), text); 12722 uu_free(text); 12723 } 12724 } 12725 } 12726 if (rv == -1) 12727 scfdie(); 12728 12729 done: 12730 free(pg_name); 12731 } 12732 12733 static void 12734 list_entity_tmpl(int templates) 12735 { 12736 char *common_name = NULL; 12737 char *description = NULL; 12738 char *locale = NULL; 12739 scf_iter_t *iter; 12740 scf_propertygroup_t *pg; 12741 scf_property_t *prop; 12742 int r; 12743 scf_value_t *val; 12744 12745 if ((pg = scf_pg_create(g_hndl)) == NULL || 12746 (prop = scf_property_create(g_hndl)) == NULL || 12747 (val = scf_value_create(g_hndl)) == NULL || 12748 (iter = scf_iter_create(g_hndl)) == NULL) 12749 scfdie(); 12750 12751 locale = setlocale(LC_MESSAGES, NULL); 12752 12753 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 12754 common_name = safe_malloc(max_scf_value_len + 1); 12755 12756 /* Try both the current locale and the "C" locale. */ 12757 if (scf_pg_get_property(pg, locale, prop) == 0 || 12758 (scf_error() == SCF_ERROR_NOT_FOUND && 12759 scf_pg_get_property(pg, "C", prop) == 0)) { 12760 if (prop_get_val(prop, val) == 0 && 12761 scf_value_get_ustring(val, common_name, 12762 max_scf_value_len + 1) != -1) { 12763 safe_printf("%s%s: %s\n", TMPL_INDENT, 12764 gettext("common name"), common_name); 12765 } 12766 } 12767 } 12768 12769 /* 12770 * Do description, manpages, and doc links if templates == 2. 12771 */ 12772 if (templates == 2) { 12773 /* Get the description. */ 12774 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 12775 description = safe_malloc(max_scf_value_len + 1); 12776 12777 /* Try both the current locale and the "C" locale. */ 12778 if (scf_pg_get_property(pg, locale, prop) == 0 || 12779 (scf_error() == SCF_ERROR_NOT_FOUND && 12780 scf_pg_get_property(pg, "C", prop) == 0)) { 12781 if (prop_get_val(prop, val) == 0 && 12782 scf_value_get_ustring(val, description, 12783 max_scf_value_len + 1) != -1) { 12784 safe_printf("%s%s: %s\n", TMPL_INDENT, 12785 gettext("description"), 12786 description); 12787 } 12788 } 12789 } 12790 12791 /* Process doc_link & manpage elements. */ 12792 if (cur_level != NULL) { 12793 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 12794 SCF_GROUP_TEMPLATE); 12795 } else if (cur_inst != NULL) { 12796 r = scf_iter_instance_pgs_typed(iter, cur_inst, 12797 SCF_GROUP_TEMPLATE); 12798 } else { 12799 r = scf_iter_service_pgs_typed(iter, cur_svc, 12800 SCF_GROUP_TEMPLATE); 12801 } 12802 if (r == 0) { 12803 display_documentation(iter, pg); 12804 } 12805 } 12806 12807 free(common_name); 12808 free(description); 12809 scf_pg_destroy(pg); 12810 scf_property_destroy(prop); 12811 scf_value_destroy(val); 12812 scf_iter_destroy(iter); 12813 } 12814 12815 static void 12816 listtmpl(const char *pattern, int templates) 12817 { 12818 scf_pg_tmpl_t *pgt; 12819 scf_prop_tmpl_t *prt; 12820 char *snapbuf = NULL; 12821 char *fmribuf; 12822 char *pg_name = NULL, *prop_name = NULL; 12823 ssize_t prop_name_size; 12824 char *qual_prop_name; 12825 char *search_name; 12826 int listed = 0; 12827 12828 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 12829 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 12830 scfdie(); 12831 12832 fmribuf = safe_malloc(max_scf_name_len + 1); 12833 qual_prop_name = safe_malloc(max_scf_name_len + 1); 12834 12835 if (cur_snap != NULL) { 12836 snapbuf = safe_malloc(max_scf_name_len + 1); 12837 if (scf_snapshot_get_name(cur_snap, snapbuf, 12838 max_scf_name_len + 1) < 0) 12839 scfdie(); 12840 } 12841 12842 if (cur_inst != NULL) { 12843 if (scf_instance_to_fmri(cur_inst, fmribuf, 12844 max_scf_name_len + 1) < 0) 12845 scfdie(); 12846 } else if (cur_svc != NULL) { 12847 if (scf_service_to_fmri(cur_svc, fmribuf, 12848 max_scf_name_len + 1) < 0) 12849 scfdie(); 12850 } else 12851 abort(); 12852 12853 /* If pattern is specified, we want to list only those items. */ 12854 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) { 12855 listed = 0; 12856 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 12857 fnmatch(pattern, pg_name, 0) == 0)) { 12858 list_pg_tmpl(pgt, NULL, templates); 12859 listed++; 12860 } 12861 12862 scf_tmpl_prop_reset(prt); 12863 12864 while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) { 12865 search_name = NULL; 12866 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 12867 if ((prop_name_size > 0) && (pg_name != NULL)) { 12868 if (snprintf(qual_prop_name, 12869 max_scf_name_len + 1, "%s/%s", 12870 pg_name, prop_name) >= 12871 max_scf_name_len + 1) { 12872 prop_name_size = -1; 12873 } else { 12874 search_name = qual_prop_name; 12875 } 12876 } 12877 if (listed > 0 || pattern == NULL || 12878 (prop_name_size > 0 && 12879 fnmatch(pattern, search_name, 12880 FNM_PATHNAME) == 0)) 12881 list_prop_tmpl(prt, NULL, templates); 12882 if (prop_name != NULL) { 12883 free(prop_name); 12884 prop_name = NULL; 12885 } 12886 } 12887 if (pg_name != NULL) { 12888 free(pg_name); 12889 pg_name = NULL; 12890 } 12891 } 12892 12893 scf_tmpl_prop_destroy(prt); 12894 scf_tmpl_pg_destroy(pgt); 12895 free(snapbuf); 12896 free(fmribuf); 12897 free(qual_prop_name); 12898 } 12899 12900 static void 12901 listprop(const char *pattern, int only_pgs, int templates) 12902 { 12903 scf_propertygroup_t *pg; 12904 scf_property_t *prop; 12905 scf_iter_t *iter, *piter; 12906 char *pgnbuf, *prnbuf, *ppnbuf; 12907 scf_pg_tmpl_t *pgt, *pgtp; 12908 scf_prop_tmpl_t *prt; 12909 12910 void **objects; 12911 char **names; 12912 void **tmpls; 12913 int allocd, i; 12914 12915 int ret; 12916 ssize_t pgnlen, prnlen, szret; 12917 size_t max_len = 0; 12918 12919 if (cur_svc == NULL && cur_inst == NULL) { 12920 semerr(emsg_entity_not_selected); 12921 return; 12922 } 12923 12924 if ((pg = scf_pg_create(g_hndl)) == NULL || 12925 (prop = scf_property_create(g_hndl)) == NULL || 12926 (iter = scf_iter_create(g_hndl)) == NULL || 12927 (piter = scf_iter_create(g_hndl)) == NULL || 12928 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12929 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 12930 scfdie(); 12931 12932 prnbuf = safe_malloc(max_scf_name_len + 1); 12933 12934 if (cur_level != NULL) 12935 ret = scf_iter_snaplevel_pgs(iter, cur_level); 12936 else if (cur_inst != NULL) 12937 ret = scf_iter_instance_pgs(iter, cur_inst); 12938 else 12939 ret = scf_iter_service_pgs(iter, cur_svc); 12940 if (ret != 0) { 12941 return; 12942 } 12943 12944 /* 12945 * We want to only list items which match pattern, and we want the 12946 * second column to line up, so during the first pass we'll save 12947 * matching items, their names, and their templates in objects, 12948 * names, and tmpls, computing the maximum name length as we go, 12949 * and then we'll print them out. 12950 * 12951 * Note: We always keep an extra slot available so the array can be 12952 * NULL-terminated. 12953 */ 12954 i = 0; 12955 allocd = 1; 12956 objects = safe_malloc(sizeof (*objects)); 12957 names = safe_malloc(sizeof (*names)); 12958 tmpls = safe_malloc(sizeof (*tmpls)); 12959 12960 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12961 int new_pg = 0; 12962 int print_props = 0; 12963 pgtp = NULL; 12964 12965 pgnlen = scf_pg_get_name(pg, NULL, 0); 12966 if (pgnlen < 0) 12967 scfdie(); 12968 12969 pgnbuf = safe_malloc(pgnlen + 1); 12970 12971 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 12972 if (szret < 0) 12973 scfdie(); 12974 assert(szret <= pgnlen); 12975 12976 if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) { 12977 if (scf_error() != SCF_ERROR_NOT_FOUND) 12978 scfdie(); 12979 pgtp = NULL; 12980 } else { 12981 pgtp = pgt; 12982 } 12983 12984 if (pattern == NULL || 12985 fnmatch(pattern, pgnbuf, 0) == 0) { 12986 if (i+1 >= allocd) { 12987 allocd *= 2; 12988 objects = realloc(objects, 12989 sizeof (*objects) * allocd); 12990 names = 12991 realloc(names, sizeof (*names) * allocd); 12992 tmpls = realloc(tmpls, 12993 sizeof (*tmpls) * allocd); 12994 if (objects == NULL || names == NULL || 12995 tmpls == NULL) 12996 uu_die(gettext("Out of memory")); 12997 } 12998 objects[i] = pg; 12999 names[i] = pgnbuf; 13000 13001 if (pgtp == NULL) 13002 tmpls[i] = NULL; 13003 else 13004 tmpls[i] = pgt; 13005 13006 ++i; 13007 13008 if (pgnlen > max_len) 13009 max_len = pgnlen; 13010 13011 new_pg = 1; 13012 print_props = 1; 13013 } 13014 13015 if (only_pgs) { 13016 if (new_pg) { 13017 pg = scf_pg_create(g_hndl); 13018 if (pg == NULL) 13019 scfdie(); 13020 pgt = scf_tmpl_pg_create(g_hndl); 13021 if (pgt == NULL) 13022 scfdie(); 13023 } else 13024 free(pgnbuf); 13025 13026 continue; 13027 } 13028 13029 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13030 scfdie(); 13031 13032 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 13033 prnlen = scf_property_get_name(prop, prnbuf, 13034 max_scf_name_len + 1); 13035 if (prnlen < 0) 13036 scfdie(); 13037 13038 /* Will prepend the property group name and a slash. */ 13039 prnlen += pgnlen + 1; 13040 13041 ppnbuf = safe_malloc(prnlen + 1); 13042 13043 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 13044 prnbuf) < 0) 13045 uu_die("snprintf"); 13046 13047 if (pattern == NULL || print_props == 1 || 13048 fnmatch(pattern, ppnbuf, 0) == 0) { 13049 if (i+1 >= allocd) { 13050 allocd *= 2; 13051 objects = realloc(objects, 13052 sizeof (*objects) * allocd); 13053 names = realloc(names, 13054 sizeof (*names) * allocd); 13055 tmpls = realloc(tmpls, 13056 sizeof (*tmpls) * allocd); 13057 if (objects == NULL || names == NULL || 13058 tmpls == NULL) 13059 uu_die(gettext( 13060 "Out of memory")); 13061 } 13062 13063 objects[i] = prop; 13064 names[i] = ppnbuf; 13065 13066 if (pgtp != NULL) { 13067 if (scf_tmpl_get_by_prop(pgt, prnbuf, 13068 prt, NULL) < 0) { 13069 if (scf_error() != 13070 SCF_ERROR_NOT_FOUND) 13071 scfdie(); 13072 tmpls[i] = NULL; 13073 } else { 13074 tmpls[i] = prt; 13075 } 13076 } else { 13077 tmpls[i] = NULL; 13078 } 13079 13080 ++i; 13081 13082 if (prnlen > max_len) 13083 max_len = prnlen; 13084 13085 prop = scf_property_create(g_hndl); 13086 prt = scf_tmpl_prop_create(g_hndl); 13087 } else { 13088 free(ppnbuf); 13089 } 13090 } 13091 13092 if (new_pg) { 13093 pg = scf_pg_create(g_hndl); 13094 if (pg == NULL) 13095 scfdie(); 13096 pgt = scf_tmpl_pg_create(g_hndl); 13097 if (pgt == NULL) 13098 scfdie(); 13099 } else 13100 free(pgnbuf); 13101 } 13102 if (ret != 0) 13103 scfdie(); 13104 13105 objects[i] = NULL; 13106 13107 scf_pg_destroy(pg); 13108 scf_tmpl_pg_destroy(pgt); 13109 scf_property_destroy(prop); 13110 scf_tmpl_prop_destroy(prt); 13111 13112 for (i = 0; objects[i] != NULL; ++i) { 13113 if (strchr(names[i], '/') == NULL) { 13114 /* property group */ 13115 pg = (scf_propertygroup_t *)objects[i]; 13116 pgt = (scf_pg_tmpl_t *)tmpls[i]; 13117 list_pg_info(pg, names[i], max_len); 13118 list_pg_tmpl(pgt, pg, templates); 13119 free(names[i]); 13120 scf_pg_destroy(pg); 13121 if (pgt != NULL) 13122 scf_tmpl_pg_destroy(pgt); 13123 } else { 13124 /* property */ 13125 prop = (scf_property_t *)objects[i]; 13126 prt = (scf_prop_tmpl_t *)tmpls[i]; 13127 list_prop_info(prop, names[i], max_len); 13128 list_prop_tmpl(prt, prop, templates); 13129 free(names[i]); 13130 scf_property_destroy(prop); 13131 if (prt != NULL) 13132 scf_tmpl_prop_destroy(prt); 13133 } 13134 } 13135 13136 free(names); 13137 free(objects); 13138 free(tmpls); 13139 } 13140 13141 void 13142 lscf_listpg(const char *pattern) 13143 { 13144 lscf_prep_hndl(); 13145 13146 listprop(pattern, 1, 0); 13147 } 13148 13149 /* 13150 * Property group and property creation, setting, and deletion. setprop (and 13151 * its alias, addprop) can either create a property group of a given type, or 13152 * it can create or set a property to a given type and list of values. 13153 */ 13154 void 13155 lscf_addpg(const char *name, const char *type, const char *flags) 13156 { 13157 scf_propertygroup_t *pg; 13158 int ret; 13159 uint32_t flgs = 0; 13160 const char *cp; 13161 13162 13163 lscf_prep_hndl(); 13164 13165 if (cur_snap != NULL) { 13166 semerr(emsg_cant_modify_snapshots); 13167 return; 13168 } 13169 13170 if (cur_inst == NULL && cur_svc == NULL) { 13171 semerr(emsg_entity_not_selected); 13172 return; 13173 } 13174 13175 if (flags != NULL) { 13176 for (cp = flags; *cp != '\0'; ++cp) { 13177 switch (*cp) { 13178 case 'P': 13179 flgs |= SCF_PG_FLAG_NONPERSISTENT; 13180 break; 13181 13182 case 'p': 13183 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 13184 break; 13185 13186 default: 13187 semerr(gettext("Invalid property group flag " 13188 "%c."), *cp); 13189 return; 13190 } 13191 } 13192 } 13193 13194 pg = scf_pg_create(g_hndl); 13195 if (pg == NULL) 13196 scfdie(); 13197 13198 if (cur_inst != NULL) 13199 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 13200 else 13201 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 13202 13203 if (ret != SCF_SUCCESS) { 13204 switch (scf_error()) { 13205 case SCF_ERROR_INVALID_ARGUMENT: 13206 semerr(gettext("Name, type, or flags are invalid.\n")); 13207 break; 13208 13209 case SCF_ERROR_EXISTS: 13210 semerr(gettext("Property group already exists.\n")); 13211 break; 13212 13213 case SCF_ERROR_PERMISSION_DENIED: 13214 semerr(emsg_permission_denied); 13215 break; 13216 13217 case SCF_ERROR_BACKEND_ACCESS: 13218 semerr(gettext("Backend refused access.\n")); 13219 break; 13220 13221 default: 13222 scfdie(); 13223 } 13224 } 13225 13226 scf_pg_destroy(pg); 13227 13228 private_refresh(); 13229 } 13230 13231 void 13232 lscf_delpg(char *name) 13233 { 13234 lscf_prep_hndl(); 13235 13236 if (cur_snap != NULL) { 13237 semerr(emsg_cant_modify_snapshots); 13238 return; 13239 } 13240 13241 if (cur_inst == NULL && cur_svc == NULL) { 13242 semerr(emsg_entity_not_selected); 13243 return; 13244 } 13245 13246 if (strchr(name, '/') != NULL) { 13247 semerr(emsg_invalid_pg_name, name); 13248 return; 13249 } 13250 13251 lscf_delprop(name); 13252 } 13253 13254 /* 13255 * scf_delhash() is used to remove the property group related to the 13256 * hash entry for a specific manifest in the repository. pgname will be 13257 * constructed from the location of the manifest file. If deathrow isn't 0, 13258 * manifest file doesn't need to exist (manifest string will be used as 13259 * an absolute path). 13260 */ 13261 void 13262 lscf_delhash(char *manifest, int deathrow) 13263 { 13264 char *pgname; 13265 13266 if (cur_snap != NULL || 13267 cur_inst != NULL || cur_svc != NULL) { 13268 warn(gettext("error, an entity is selected\n")); 13269 return; 13270 } 13271 13272 /* select smf/manifest */ 13273 lscf_select(HASH_SVC); 13274 /* 13275 * Translate the manifest file name to property name. In the deathrow 13276 * case, the manifest file does not need to exist. 13277 */ 13278 pgname = mhash_filename_to_propname(manifest, 13279 deathrow ? B_TRUE : B_FALSE); 13280 if (pgname == NULL) { 13281 warn(gettext("cannot resolve pathname for %s\n"), manifest); 13282 return; 13283 } 13284 /* delete the hash property name */ 13285 lscf_delpg(pgname); 13286 } 13287 13288 void 13289 lscf_listprop(const char *pattern) 13290 { 13291 lscf_prep_hndl(); 13292 13293 listprop(pattern, 0, 0); 13294 } 13295 13296 int 13297 lscf_setprop(const char *pgname, const char *type, const char *value, 13298 const uu_list_t *values) 13299 { 13300 scf_type_t ty, current_ty; 13301 scf_service_t *svc; 13302 scf_propertygroup_t *pg, *parent_pg; 13303 scf_property_t *prop, *parent_prop; 13304 scf_pg_tmpl_t *pgt; 13305 scf_prop_tmpl_t *prt; 13306 int ret, result = 0; 13307 scf_transaction_t *tx; 13308 scf_transaction_entry_t *e; 13309 scf_value_t *v; 13310 uu_list_walk_t *walk; 13311 string_list_t *sp; 13312 char *propname; 13313 int req_quotes = 0; 13314 13315 lscf_prep_hndl(); 13316 13317 if ((e = scf_entry_create(g_hndl)) == NULL || 13318 (svc = scf_service_create(g_hndl)) == NULL || 13319 (parent_pg = scf_pg_create(g_hndl)) == NULL || 13320 (pg = scf_pg_create(g_hndl)) == NULL || 13321 (parent_prop = scf_property_create(g_hndl)) == NULL || 13322 (prop = scf_property_create(g_hndl)) == NULL || 13323 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 13324 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 13325 (tx = scf_transaction_create(g_hndl)) == NULL) 13326 scfdie(); 13327 13328 if (cur_snap != NULL) { 13329 semerr(emsg_cant_modify_snapshots); 13330 goto fail; 13331 } 13332 13333 if (cur_inst == NULL && cur_svc == NULL) { 13334 semerr(emsg_entity_not_selected); 13335 goto fail; 13336 } 13337 13338 propname = strchr(pgname, '/'); 13339 if (propname == NULL) { 13340 semerr(gettext("Property names must contain a `/'.\n")); 13341 goto fail; 13342 } 13343 13344 *propname = '\0'; 13345 ++propname; 13346 13347 if (type != NULL) { 13348 ty = string_to_type(type); 13349 if (ty == SCF_TYPE_INVALID) { 13350 semerr(gettext("Unknown type \"%s\".\n"), type); 13351 goto fail; 13352 } 13353 } 13354 13355 if (cur_inst != NULL) 13356 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13357 else 13358 ret = scf_service_get_pg(cur_svc, pgname, pg); 13359 if (ret != SCF_SUCCESS) { 13360 switch (scf_error()) { 13361 case SCF_ERROR_NOT_FOUND: 13362 semerr(emsg_no_such_pg, pgname); 13363 goto fail; 13364 13365 case SCF_ERROR_INVALID_ARGUMENT: 13366 semerr(emsg_invalid_pg_name, pgname); 13367 goto fail; 13368 13369 default: 13370 scfdie(); 13371 break; 13372 } 13373 } 13374 13375 do { 13376 if (scf_pg_update(pg) == -1) 13377 scfdie(); 13378 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13379 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13380 scfdie(); 13381 13382 semerr(emsg_permission_denied); 13383 goto fail; 13384 } 13385 13386 ret = scf_pg_get_property(pg, propname, prop); 13387 if (ret == SCF_SUCCESS) { 13388 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 13389 scfdie(); 13390 13391 if (type == NULL) 13392 ty = current_ty; 13393 if (scf_transaction_property_change_type(tx, e, 13394 propname, ty) == -1) 13395 scfdie(); 13396 13397 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13398 /* Infer the type, if possible. */ 13399 if (type == NULL) { 13400 /* 13401 * First check if we're an instance and the 13402 * property is set on the service. 13403 */ 13404 if (cur_inst != NULL && 13405 scf_instance_get_parent(cur_inst, 13406 svc) == 0 && 13407 scf_service_get_pg(cur_svc, pgname, 13408 parent_pg) == 0 && 13409 scf_pg_get_property(parent_pg, propname, 13410 parent_prop) == 0 && 13411 scf_property_type(parent_prop, 13412 ¤t_ty) == 0) { 13413 ty = current_ty; 13414 13415 /* Then check for a type set in a template. */ 13416 } else if (scf_tmpl_get_by_pg(pg, pgt, 13417 NULL) == 0 && 13418 scf_tmpl_get_by_prop(pgt, propname, prt, 13419 NULL) == 0 && 13420 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 13421 ty = current_ty; 13422 13423 /* If type can't be inferred, fail. */ 13424 } else { 13425 semerr(gettext("Type required for new " 13426 "properties.\n")); 13427 goto fail; 13428 } 13429 } 13430 if (scf_transaction_property_new(tx, e, propname, 13431 ty) == -1) 13432 scfdie(); 13433 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13434 semerr(emsg_invalid_prop_name, propname); 13435 goto fail; 13436 } else { 13437 scfdie(); 13438 } 13439 13440 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 13441 req_quotes = 1; 13442 13443 if (value != NULL) { 13444 v = string_to_value(value, ty, 0); 13445 13446 if (v == NULL) 13447 goto fail; 13448 13449 ret = scf_entry_add_value(e, v); 13450 assert(ret == SCF_SUCCESS); 13451 } else { 13452 assert(values != NULL); 13453 13454 walk = uu_list_walk_start((uu_list_t *)values, 13455 UU_DEFAULT); 13456 if (walk == NULL) 13457 uu_die(gettext("Could not walk list")); 13458 13459 for (sp = uu_list_walk_next(walk); sp != NULL; 13460 sp = uu_list_walk_next(walk)) { 13461 v = string_to_value(sp->str, ty, req_quotes); 13462 13463 if (v == NULL) { 13464 scf_entry_destroy_children(e); 13465 goto fail; 13466 } 13467 13468 ret = scf_entry_add_value(e, v); 13469 assert(ret == SCF_SUCCESS); 13470 } 13471 uu_list_walk_end(walk); 13472 } 13473 result = scf_transaction_commit(tx); 13474 13475 scf_transaction_reset(tx); 13476 scf_entry_destroy_children(e); 13477 } while (result == 0); 13478 13479 if (result < 0) { 13480 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13481 scfdie(); 13482 13483 semerr(emsg_permission_denied); 13484 goto fail; 13485 } 13486 13487 ret = 0; 13488 13489 private_refresh(); 13490 13491 goto cleanup; 13492 13493 fail: 13494 ret = -1; 13495 13496 cleanup: 13497 scf_transaction_destroy(tx); 13498 scf_entry_destroy(e); 13499 scf_service_destroy(svc); 13500 scf_pg_destroy(parent_pg); 13501 scf_pg_destroy(pg); 13502 scf_property_destroy(parent_prop); 13503 scf_property_destroy(prop); 13504 scf_tmpl_pg_destroy(pgt); 13505 scf_tmpl_prop_destroy(prt); 13506 13507 return (ret); 13508 } 13509 13510 void 13511 lscf_delprop(char *pgn) 13512 { 13513 char *slash, *pn; 13514 scf_propertygroup_t *pg; 13515 scf_transaction_t *tx; 13516 scf_transaction_entry_t *e; 13517 int ret; 13518 13519 13520 lscf_prep_hndl(); 13521 13522 if (cur_snap != NULL) { 13523 semerr(emsg_cant_modify_snapshots); 13524 return; 13525 } 13526 13527 if (cur_inst == NULL && cur_svc == NULL) { 13528 semerr(emsg_entity_not_selected); 13529 return; 13530 } 13531 13532 pg = scf_pg_create(g_hndl); 13533 if (pg == NULL) 13534 scfdie(); 13535 13536 slash = strchr(pgn, '/'); 13537 if (slash == NULL) { 13538 pn = NULL; 13539 } else { 13540 *slash = '\0'; 13541 pn = slash + 1; 13542 } 13543 13544 if (cur_inst != NULL) 13545 ret = scf_instance_get_pg(cur_inst, pgn, pg); 13546 else 13547 ret = scf_service_get_pg(cur_svc, pgn, pg); 13548 if (ret != SCF_SUCCESS) { 13549 switch (scf_error()) { 13550 case SCF_ERROR_NOT_FOUND: 13551 semerr(emsg_no_such_pg, pgn); 13552 break; 13553 13554 case SCF_ERROR_INVALID_ARGUMENT: 13555 semerr(emsg_invalid_pg_name, pgn); 13556 break; 13557 13558 default: 13559 scfdie(); 13560 } 13561 13562 scf_pg_destroy(pg); 13563 13564 return; 13565 } 13566 13567 if (pn == NULL) { 13568 /* Try to delete the property group. */ 13569 if (scf_pg_delete(pg) != SCF_SUCCESS) { 13570 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13571 scfdie(); 13572 13573 semerr(emsg_permission_denied); 13574 } else { 13575 private_refresh(); 13576 } 13577 13578 scf_pg_destroy(pg); 13579 return; 13580 } 13581 13582 e = scf_entry_create(g_hndl); 13583 tx = scf_transaction_create(g_hndl); 13584 13585 do { 13586 if (scf_pg_update(pg) == -1) 13587 scfdie(); 13588 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 13589 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13590 scfdie(); 13591 13592 semerr(emsg_permission_denied); 13593 break; 13594 } 13595 13596 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 13597 if (scf_error() == SCF_ERROR_NOT_FOUND) { 13598 semerr(gettext("No such property %s/%s.\n"), 13599 pgn, pn); 13600 break; 13601 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13602 semerr(emsg_invalid_prop_name, pn); 13603 break; 13604 } else { 13605 scfdie(); 13606 } 13607 } 13608 13609 ret = scf_transaction_commit(tx); 13610 13611 if (ret == 0) 13612 scf_transaction_reset(tx); 13613 } while (ret == 0); 13614 13615 if (ret < 0) { 13616 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13617 scfdie(); 13618 13619 semerr(emsg_permission_denied); 13620 } else { 13621 private_refresh(); 13622 } 13623 13624 scf_transaction_destroy(tx); 13625 scf_entry_destroy(e); 13626 scf_pg_destroy(pg); 13627 } 13628 13629 /* 13630 * Property editing. 13631 */ 13632 13633 static int 13634 write_edit_script(FILE *strm) 13635 { 13636 char *fmribuf; 13637 ssize_t fmrilen; 13638 13639 scf_propertygroup_t *pg; 13640 scf_property_t *prop; 13641 scf_value_t *val; 13642 scf_type_t ty; 13643 int ret, result = 0; 13644 scf_iter_t *iter, *piter, *viter; 13645 char *buf, *tybuf, *pname; 13646 const char *emsg_write_error; 13647 13648 13649 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 13650 13651 13652 /* select fmri */ 13653 if (cur_inst != NULL) { 13654 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 13655 if (fmrilen < 0) 13656 scfdie(); 13657 fmribuf = safe_malloc(fmrilen + 1); 13658 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 13659 scfdie(); 13660 } else { 13661 assert(cur_svc != NULL); 13662 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 13663 if (fmrilen < 0) 13664 scfdie(); 13665 fmribuf = safe_malloc(fmrilen + 1); 13666 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 13667 scfdie(); 13668 } 13669 13670 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 13671 warn(emsg_write_error, strerror(errno)); 13672 free(fmribuf); 13673 return (-1); 13674 } 13675 13676 free(fmribuf); 13677 13678 13679 if ((pg = scf_pg_create(g_hndl)) == NULL || 13680 (prop = scf_property_create(g_hndl)) == NULL || 13681 (val = scf_value_create(g_hndl)) == NULL || 13682 (iter = scf_iter_create(g_hndl)) == NULL || 13683 (piter = scf_iter_create(g_hndl)) == NULL || 13684 (viter = scf_iter_create(g_hndl)) == NULL) 13685 scfdie(); 13686 13687 buf = safe_malloc(max_scf_name_len + 1); 13688 tybuf = safe_malloc(max_scf_pg_type_len + 1); 13689 pname = safe_malloc(max_scf_name_len + 1); 13690 13691 if (cur_inst != NULL) 13692 ret = scf_iter_instance_pgs(iter, cur_inst); 13693 else 13694 ret = scf_iter_service_pgs(iter, cur_svc); 13695 if (ret != SCF_SUCCESS) 13696 scfdie(); 13697 13698 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 13699 int ret2; 13700 13701 /* 13702 * # delprop pg 13703 * # addpg pg type 13704 */ 13705 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 13706 scfdie(); 13707 13708 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 13709 scfdie(); 13710 13711 if (fprintf(strm, "# Property group \"%s\"\n" 13712 "# delprop %s\n" 13713 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 13714 warn(emsg_write_error, strerror(errno)); 13715 result = -1; 13716 goto out; 13717 } 13718 13719 /* # setprop pg/prop = (values) */ 13720 13721 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 13722 scfdie(); 13723 13724 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 13725 int first = 1; 13726 int ret3; 13727 int multiple; 13728 int is_str; 13729 scf_type_t bty; 13730 13731 if (scf_property_get_name(prop, pname, 13732 max_scf_name_len + 1) < 0) 13733 scfdie(); 13734 13735 if (scf_property_type(prop, &ty) != 0) 13736 scfdie(); 13737 13738 multiple = prop_has_multiple_values(prop, val); 13739 13740 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 13741 pname, scf_type_to_string(ty), multiple ? "(" : "") 13742 < 0) { 13743 warn(emsg_write_error, strerror(errno)); 13744 result = -1; 13745 goto out; 13746 } 13747 13748 (void) scf_type_base_type(ty, &bty); 13749 is_str = (bty == SCF_TYPE_ASTRING); 13750 13751 if (scf_iter_property_values(viter, prop) != 13752 SCF_SUCCESS) 13753 scfdie(); 13754 13755 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 13756 char *buf; 13757 ssize_t buflen; 13758 13759 buflen = scf_value_get_as_string(val, NULL, 0); 13760 if (buflen < 0) 13761 scfdie(); 13762 13763 buf = safe_malloc(buflen + 1); 13764 13765 if (scf_value_get_as_string(val, buf, 13766 buflen + 1) < 0) 13767 scfdie(); 13768 13769 if (first) 13770 first = 0; 13771 else { 13772 if (putc(' ', strm) != ' ') { 13773 warn(emsg_write_error, 13774 strerror(errno)); 13775 result = -1; 13776 goto out; 13777 } 13778 } 13779 13780 if ((is_str && multiple) || 13781 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 13782 (void) putc('"', strm); 13783 (void) quote_and_print(buf, strm, 1); 13784 (void) putc('"', strm); 13785 13786 if (ferror(strm)) { 13787 warn(emsg_write_error, 13788 strerror(errno)); 13789 result = -1; 13790 goto out; 13791 } 13792 } else { 13793 if (fprintf(strm, "%s", buf) < 0) { 13794 warn(emsg_write_error, 13795 strerror(errno)); 13796 result = -1; 13797 goto out; 13798 } 13799 } 13800 13801 free(buf); 13802 } 13803 if (ret3 < 0 && 13804 scf_error() != SCF_ERROR_PERMISSION_DENIED) 13805 scfdie(); 13806 13807 /* Write closing paren if mult-value property */ 13808 if ((multiple && putc(')', strm) == EOF) || 13809 13810 /* Write final newline */ 13811 fputc('\n', strm) == EOF) { 13812 warn(emsg_write_error, strerror(errno)); 13813 result = -1; 13814 goto out; 13815 } 13816 } 13817 if (ret2 < 0) 13818 scfdie(); 13819 13820 if (fputc('\n', strm) == EOF) { 13821 warn(emsg_write_error, strerror(errno)); 13822 result = -1; 13823 goto out; 13824 } 13825 } 13826 if (ret < 0) 13827 scfdie(); 13828 13829 out: 13830 free(pname); 13831 free(tybuf); 13832 free(buf); 13833 scf_iter_destroy(viter); 13834 scf_iter_destroy(piter); 13835 scf_iter_destroy(iter); 13836 scf_value_destroy(val); 13837 scf_property_destroy(prop); 13838 scf_pg_destroy(pg); 13839 13840 if (result == 0) { 13841 if (fflush(strm) != 0) { 13842 warn(emsg_write_error, strerror(errno)); 13843 return (-1); 13844 } 13845 } 13846 13847 return (result); 13848 } 13849 13850 int 13851 lscf_editprop() 13852 { 13853 char *buf, *editor; 13854 size_t bufsz; 13855 int tmpfd; 13856 char tempname[] = TEMP_FILE_PATTERN; 13857 13858 lscf_prep_hndl(); 13859 13860 if (cur_snap != NULL) { 13861 semerr(emsg_cant_modify_snapshots); 13862 return (-1); 13863 } 13864 13865 if (cur_svc == NULL && cur_inst == NULL) { 13866 semerr(emsg_entity_not_selected); 13867 return (-1); 13868 } 13869 13870 tmpfd = mkstemp(tempname); 13871 if (tmpfd == -1) { 13872 semerr(gettext("Could not create temporary file.\n")); 13873 return (-1); 13874 } 13875 13876 (void) strcpy(tempfilename, tempname); 13877 13878 tempfile = fdopen(tmpfd, "r+"); 13879 if (tempfile == NULL) { 13880 warn(gettext("Could not create temporary file.\n")); 13881 if (close(tmpfd) == -1) 13882 warn(gettext("Could not close temporary file: %s.\n"), 13883 strerror(errno)); 13884 13885 remove_tempfile(); 13886 13887 return (-1); 13888 } 13889 13890 if (write_edit_script(tempfile) == -1) { 13891 remove_tempfile(); 13892 return (-1); 13893 } 13894 13895 editor = getenv("EDITOR"); 13896 if (editor == NULL) 13897 editor = "vi"; 13898 13899 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 13900 buf = safe_malloc(bufsz); 13901 13902 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 13903 uu_die(gettext("Error creating editor command")); 13904 13905 if (system(buf) == -1) { 13906 semerr(gettext("Could not launch editor %s: %s\n"), editor, 13907 strerror(errno)); 13908 free(buf); 13909 remove_tempfile(); 13910 return (-1); 13911 } 13912 13913 free(buf); 13914 13915 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 13916 13917 remove_tempfile(); 13918 13919 return (0); 13920 } 13921 13922 static void 13923 add_string(uu_list_t *strlist, const char *str) 13924 { 13925 string_list_t *elem; 13926 elem = safe_malloc(sizeof (*elem)); 13927 uu_list_node_init(elem, &elem->node, string_pool); 13928 elem->str = safe_strdup(str); 13929 if (uu_list_append(strlist, elem) != 0) 13930 uu_die(gettext("libuutil error: %s\n"), 13931 uu_strerror(uu_error())); 13932 } 13933 13934 static int 13935 remove_string(uu_list_t *strlist, const char *str) 13936 { 13937 uu_list_walk_t *elems; 13938 string_list_t *sp; 13939 13940 /* 13941 * Find the element that needs to be removed. 13942 */ 13943 elems = uu_list_walk_start(strlist, UU_DEFAULT); 13944 while ((sp = uu_list_walk_next(elems)) != NULL) { 13945 if (strcmp(sp->str, str) == 0) 13946 break; 13947 } 13948 uu_list_walk_end(elems); 13949 13950 /* 13951 * Returning 1 here as the value was not found, this 13952 * might not be an error. Leave it to the caller to 13953 * decide. 13954 */ 13955 if (sp == NULL) { 13956 return (1); 13957 } 13958 13959 uu_list_remove(strlist, sp); 13960 13961 free(sp->str); 13962 free(sp); 13963 13964 return (0); 13965 } 13966 13967 /* 13968 * Get all property values that don't match the given glob pattern, 13969 * if a pattern is specified. 13970 */ 13971 static void 13972 get_prop_values(scf_property_t *prop, uu_list_t *values, 13973 const char *pattern) 13974 { 13975 scf_iter_t *iter; 13976 scf_value_t *val; 13977 int ret; 13978 13979 if ((iter = scf_iter_create(g_hndl)) == NULL || 13980 (val = scf_value_create(g_hndl)) == NULL) 13981 scfdie(); 13982 13983 if (scf_iter_property_values(iter, prop) != 0) 13984 scfdie(); 13985 13986 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13987 char *buf; 13988 ssize_t vlen, szret; 13989 13990 vlen = scf_value_get_as_string(val, NULL, 0); 13991 if (vlen < 0) 13992 scfdie(); 13993 13994 buf = safe_malloc(vlen + 1); 13995 13996 szret = scf_value_get_as_string(val, buf, vlen + 1); 13997 if (szret < 0) 13998 scfdie(); 13999 assert(szret <= vlen); 14000 14001 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 14002 add_string(values, buf); 14003 14004 free(buf); 14005 } 14006 14007 if (ret == -1) 14008 scfdie(); 14009 14010 scf_value_destroy(val); 14011 scf_iter_destroy(iter); 14012 } 14013 14014 static int 14015 lscf_setpropvalue(const char *pgname, const char *type, 14016 const char *arg, int isadd, int isnotfoundok) 14017 { 14018 scf_type_t ty; 14019 scf_propertygroup_t *pg; 14020 scf_property_t *prop; 14021 int ret, result = 0; 14022 scf_transaction_t *tx; 14023 scf_transaction_entry_t *e; 14024 scf_value_t *v; 14025 string_list_t *sp; 14026 char *propname; 14027 uu_list_t *values; 14028 uu_list_walk_t *walk; 14029 void *cookie = NULL; 14030 char *pattern = NULL; 14031 14032 lscf_prep_hndl(); 14033 14034 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 14035 uu_die(gettext("Could not create property list: %s\n"), 14036 uu_strerror(uu_error())); 14037 14038 if (!isadd) 14039 pattern = safe_strdup(arg); 14040 14041 if ((e = scf_entry_create(g_hndl)) == NULL || 14042 (pg = scf_pg_create(g_hndl)) == NULL || 14043 (prop = scf_property_create(g_hndl)) == NULL || 14044 (tx = scf_transaction_create(g_hndl)) == NULL) 14045 scfdie(); 14046 14047 if (cur_snap != NULL) { 14048 semerr(emsg_cant_modify_snapshots); 14049 goto fail; 14050 } 14051 14052 if (cur_inst == NULL && cur_svc == NULL) { 14053 semerr(emsg_entity_not_selected); 14054 goto fail; 14055 } 14056 14057 propname = strchr(pgname, '/'); 14058 if (propname == NULL) { 14059 semerr(gettext("Property names must contain a `/'.\n")); 14060 goto fail; 14061 } 14062 14063 *propname = '\0'; 14064 ++propname; 14065 14066 if (type != NULL) { 14067 ty = string_to_type(type); 14068 if (ty == SCF_TYPE_INVALID) { 14069 semerr(gettext("Unknown type \"%s\".\n"), type); 14070 goto fail; 14071 } 14072 } 14073 14074 if (cur_inst != NULL) 14075 ret = scf_instance_get_pg(cur_inst, pgname, pg); 14076 else 14077 ret = scf_service_get_pg(cur_svc, pgname, pg); 14078 if (ret != 0) { 14079 switch (scf_error()) { 14080 case SCF_ERROR_NOT_FOUND: 14081 if (isnotfoundok) { 14082 result = 0; 14083 } else { 14084 semerr(emsg_no_such_pg, pgname); 14085 result = -1; 14086 } 14087 goto out; 14088 14089 case SCF_ERROR_INVALID_ARGUMENT: 14090 semerr(emsg_invalid_pg_name, pgname); 14091 goto fail; 14092 14093 default: 14094 scfdie(); 14095 } 14096 } 14097 14098 do { 14099 if (scf_pg_update(pg) == -1) 14100 scfdie(); 14101 if (scf_transaction_start(tx, pg) != 0) { 14102 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14103 scfdie(); 14104 14105 semerr(emsg_permission_denied); 14106 goto fail; 14107 } 14108 14109 ret = scf_pg_get_property(pg, propname, prop); 14110 if (ret == 0) { 14111 scf_type_t ptype; 14112 char *pat = pattern; 14113 14114 if (scf_property_type(prop, &ptype) != 0) 14115 scfdie(); 14116 14117 if (isadd) { 14118 if (type != NULL && ptype != ty) { 14119 semerr(gettext("Property \"%s\" is not " 14120 "of type \"%s\".\n"), propname, 14121 type); 14122 goto fail; 14123 } 14124 14125 pat = NULL; 14126 } else { 14127 size_t len = strlen(pat); 14128 if (len > 0 && pat[len - 1] == '\"') 14129 pat[len - 1] = '\0'; 14130 if (len > 0 && pat[0] == '\"') 14131 pat++; 14132 } 14133 14134 ty = ptype; 14135 14136 get_prop_values(prop, values, pat); 14137 14138 if (isadd) 14139 add_string(values, arg); 14140 14141 if (scf_transaction_property_change(tx, e, 14142 propname, ty) == -1) 14143 scfdie(); 14144 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 14145 if (isadd) { 14146 if (type == NULL) { 14147 semerr(gettext("Type required " 14148 "for new properties.\n")); 14149 goto fail; 14150 } 14151 14152 add_string(values, arg); 14153 14154 if (scf_transaction_property_new(tx, e, 14155 propname, ty) == -1) 14156 scfdie(); 14157 } else if (isnotfoundok) { 14158 result = 0; 14159 goto out; 14160 } else { 14161 semerr(gettext("No such property %s/%s.\n"), 14162 pgname, propname); 14163 result = -1; 14164 goto out; 14165 } 14166 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 14167 semerr(emsg_invalid_prop_name, propname); 14168 goto fail; 14169 } else { 14170 scfdie(); 14171 } 14172 14173 walk = uu_list_walk_start(values, UU_DEFAULT); 14174 if (walk == NULL) 14175 uu_die(gettext("Could not walk property list.\n")); 14176 14177 for (sp = uu_list_walk_next(walk); sp != NULL; 14178 sp = uu_list_walk_next(walk)) { 14179 v = string_to_value(sp->str, ty, 0); 14180 14181 if (v == NULL) { 14182 scf_entry_destroy_children(e); 14183 goto fail; 14184 } 14185 ret = scf_entry_add_value(e, v); 14186 assert(ret == 0); 14187 } 14188 uu_list_walk_end(walk); 14189 14190 result = scf_transaction_commit(tx); 14191 14192 scf_transaction_reset(tx); 14193 scf_entry_destroy_children(e); 14194 } while (result == 0); 14195 14196 if (result < 0) { 14197 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14198 scfdie(); 14199 14200 semerr(emsg_permission_denied); 14201 goto fail; 14202 } 14203 14204 result = 0; 14205 14206 private_refresh(); 14207 14208 out: 14209 scf_transaction_destroy(tx); 14210 scf_entry_destroy(e); 14211 scf_pg_destroy(pg); 14212 scf_property_destroy(prop); 14213 free(pattern); 14214 14215 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 14216 free(sp->str); 14217 free(sp); 14218 } 14219 14220 uu_list_destroy(values); 14221 14222 return (result); 14223 14224 fail: 14225 result = -1; 14226 goto out; 14227 } 14228 14229 int 14230 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 14231 { 14232 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 14233 } 14234 14235 int 14236 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 14237 { 14238 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 14239 } 14240 14241 /* 14242 * Look for a standard start method, first in the instance (if any), 14243 * then the service. 14244 */ 14245 static const char * 14246 start_method_name(int *in_instance) 14247 { 14248 scf_propertygroup_t *pg; 14249 char **p; 14250 int ret; 14251 scf_instance_t *inst = cur_inst; 14252 14253 if ((pg = scf_pg_create(g_hndl)) == NULL) 14254 scfdie(); 14255 14256 again: 14257 for (p = start_method_names; *p != NULL; p++) { 14258 if (inst != NULL) 14259 ret = scf_instance_get_pg(inst, *p, pg); 14260 else 14261 ret = scf_service_get_pg(cur_svc, *p, pg); 14262 14263 if (ret == 0) { 14264 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 14265 char *buf = safe_malloc(bufsz); 14266 14267 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 14268 free(buf); 14269 continue; 14270 } 14271 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 14272 free(buf); 14273 continue; 14274 } 14275 14276 free(buf); 14277 *in_instance = (inst != NULL); 14278 scf_pg_destroy(pg); 14279 return (*p); 14280 } 14281 14282 if (scf_error() == SCF_ERROR_NOT_FOUND) 14283 continue; 14284 14285 scfdie(); 14286 } 14287 14288 if (inst != NULL) { 14289 inst = NULL; 14290 goto again; 14291 } 14292 14293 scf_pg_destroy(pg); 14294 return (NULL); 14295 } 14296 14297 static int 14298 addpg(const char *name, const char *type) 14299 { 14300 scf_propertygroup_t *pg; 14301 int ret; 14302 14303 pg = scf_pg_create(g_hndl); 14304 if (pg == NULL) 14305 scfdie(); 14306 14307 if (cur_inst != NULL) 14308 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 14309 else 14310 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 14311 14312 if (ret != 0) { 14313 switch (scf_error()) { 14314 case SCF_ERROR_EXISTS: 14315 ret = 0; 14316 break; 14317 14318 case SCF_ERROR_PERMISSION_DENIED: 14319 semerr(emsg_permission_denied); 14320 break; 14321 14322 default: 14323 scfdie(); 14324 } 14325 } 14326 14327 scf_pg_destroy(pg); 14328 return (ret); 14329 } 14330 14331 int 14332 lscf_setenv(uu_list_t *args, int isunset) 14333 { 14334 int ret = 0; 14335 size_t i; 14336 int argc; 14337 char **argv = NULL; 14338 string_list_t *slp; 14339 char *pattern; 14340 char *prop; 14341 int do_service = 0; 14342 int do_instance = 0; 14343 const char *method = NULL; 14344 const char *name = NULL; 14345 const char *value = NULL; 14346 scf_instance_t *saved_cur_inst = cur_inst; 14347 14348 lscf_prep_hndl(); 14349 14350 argc = uu_list_numnodes(args); 14351 if (argc < 1) 14352 goto usage; 14353 14354 argv = calloc(argc + 1, sizeof (char *)); 14355 if (argv == NULL) 14356 uu_die(gettext("Out of memory.\n")); 14357 14358 for (slp = uu_list_first(args), i = 0; 14359 slp != NULL; 14360 slp = uu_list_next(args, slp), ++i) 14361 argv[i] = slp->str; 14362 14363 argv[i] = NULL; 14364 14365 opterr = 0; 14366 optind = 0; 14367 for (;;) { 14368 ret = getopt(argc, argv, "sim:"); 14369 if (ret == -1) 14370 break; 14371 14372 switch (ret) { 14373 case 's': 14374 do_service = 1; 14375 cur_inst = NULL; 14376 break; 14377 14378 case 'i': 14379 do_instance = 1; 14380 break; 14381 14382 case 'm': 14383 method = optarg; 14384 break; 14385 14386 case '?': 14387 goto usage; 14388 14389 default: 14390 bad_error("getopt", ret); 14391 } 14392 } 14393 14394 argc -= optind; 14395 if ((do_service && do_instance) || 14396 (isunset && argc != 1) || 14397 (!isunset && argc != 2)) 14398 goto usage; 14399 14400 name = argv[optind]; 14401 if (!isunset) 14402 value = argv[optind + 1]; 14403 14404 if (cur_snap != NULL) { 14405 semerr(emsg_cant_modify_snapshots); 14406 ret = -1; 14407 goto out; 14408 } 14409 14410 if (cur_inst == NULL && cur_svc == NULL) { 14411 semerr(emsg_entity_not_selected); 14412 ret = -1; 14413 goto out; 14414 } 14415 14416 if (do_instance && cur_inst == NULL) { 14417 semerr(gettext("No instance is selected.\n")); 14418 ret = -1; 14419 goto out; 14420 } 14421 14422 if (do_service && cur_svc == NULL) { 14423 semerr(gettext("No service is selected.\n")); 14424 ret = -1; 14425 goto out; 14426 } 14427 14428 if (method == NULL) { 14429 if (do_instance || do_service) { 14430 method = "method_context"; 14431 if (!isunset) { 14432 ret = addpg("method_context", 14433 SCF_GROUP_FRAMEWORK); 14434 if (ret != 0) 14435 goto out; 14436 } 14437 } else { 14438 int in_instance; 14439 method = start_method_name(&in_instance); 14440 if (method == NULL) { 14441 semerr(gettext( 14442 "Couldn't find start method; please " 14443 "specify a method with '-m'.\n")); 14444 ret = -1; 14445 goto out; 14446 } 14447 if (!in_instance) 14448 cur_inst = NULL; 14449 } 14450 } else { 14451 scf_propertygroup_t *pg; 14452 size_t bufsz; 14453 char *buf; 14454 int ret; 14455 14456 if ((pg = scf_pg_create(g_hndl)) == NULL) 14457 scfdie(); 14458 14459 if (cur_inst != NULL) 14460 ret = scf_instance_get_pg(cur_inst, method, pg); 14461 else 14462 ret = scf_service_get_pg(cur_svc, method, pg); 14463 14464 if (ret != 0) { 14465 scf_pg_destroy(pg); 14466 switch (scf_error()) { 14467 case SCF_ERROR_NOT_FOUND: 14468 semerr(gettext("Couldn't find the method " 14469 "\"%s\".\n"), method); 14470 goto out; 14471 14472 case SCF_ERROR_INVALID_ARGUMENT: 14473 semerr(gettext("Invalid method name \"%s\".\n"), 14474 method); 14475 goto out; 14476 14477 default: 14478 scfdie(); 14479 } 14480 } 14481 14482 bufsz = strlen(SCF_GROUP_METHOD) + 1; 14483 buf = safe_malloc(bufsz); 14484 14485 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 14486 strcmp(buf, SCF_GROUP_METHOD) != 0) { 14487 semerr(gettext("Property group \"%s\" is not of type " 14488 "\"method\".\n"), method); 14489 ret = -1; 14490 free(buf); 14491 scf_pg_destroy(pg); 14492 goto out; 14493 } 14494 14495 free(buf); 14496 scf_pg_destroy(pg); 14497 } 14498 14499 prop = uu_msprintf("%s/environment", method); 14500 pattern = uu_msprintf("%s=*", name); 14501 14502 if (prop == NULL || pattern == NULL) 14503 uu_die(gettext("Out of memory.\n")); 14504 14505 ret = lscf_delpropvalue(prop, pattern, !isunset); 14506 14507 if (ret == 0 && !isunset) { 14508 uu_free(pattern); 14509 uu_free(prop); 14510 prop = uu_msprintf("%s/environment", method); 14511 pattern = uu_msprintf("%s=%s", name, value); 14512 if (prop == NULL || pattern == NULL) 14513 uu_die(gettext("Out of memory.\n")); 14514 ret = lscf_addpropvalue(prop, "astring:", pattern); 14515 } 14516 uu_free(pattern); 14517 uu_free(prop); 14518 14519 out: 14520 cur_inst = saved_cur_inst; 14521 14522 free(argv); 14523 return (ret); 14524 usage: 14525 ret = -2; 14526 goto out; 14527 } 14528 14529 /* 14530 * Snapshot commands 14531 */ 14532 14533 void 14534 lscf_listsnap() 14535 { 14536 scf_snapshot_t *snap; 14537 scf_iter_t *iter; 14538 char *nb; 14539 int r; 14540 14541 lscf_prep_hndl(); 14542 14543 if (cur_inst == NULL) { 14544 semerr(gettext("Instance not selected.\n")); 14545 return; 14546 } 14547 14548 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 14549 (iter = scf_iter_create(g_hndl)) == NULL) 14550 scfdie(); 14551 14552 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 14553 scfdie(); 14554 14555 nb = safe_malloc(max_scf_name_len + 1); 14556 14557 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 14558 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 14559 scfdie(); 14560 14561 (void) puts(nb); 14562 } 14563 if (r < 0) 14564 scfdie(); 14565 14566 free(nb); 14567 scf_iter_destroy(iter); 14568 scf_snapshot_destroy(snap); 14569 } 14570 14571 void 14572 lscf_selectsnap(const char *name) 14573 { 14574 scf_snapshot_t *snap; 14575 scf_snaplevel_t *level; 14576 14577 lscf_prep_hndl(); 14578 14579 if (cur_inst == NULL) { 14580 semerr(gettext("Instance not selected.\n")); 14581 return; 14582 } 14583 14584 if (cur_snap != NULL) { 14585 if (name != NULL) { 14586 char *cur_snap_name; 14587 boolean_t nochange; 14588 14589 cur_snap_name = safe_malloc(max_scf_name_len + 1); 14590 14591 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 14592 max_scf_name_len + 1) < 0) 14593 scfdie(); 14594 14595 nochange = strcmp(name, cur_snap_name) == 0; 14596 14597 free(cur_snap_name); 14598 14599 if (nochange) 14600 return; 14601 } 14602 14603 unselect_cursnap(); 14604 } 14605 14606 if (name == NULL) 14607 return; 14608 14609 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 14610 (level = scf_snaplevel_create(g_hndl)) == NULL) 14611 scfdie(); 14612 14613 if (scf_instance_get_snapshot(cur_inst, name, snap) != 14614 SCF_SUCCESS) { 14615 switch (scf_error()) { 14616 case SCF_ERROR_INVALID_ARGUMENT: 14617 semerr(gettext("Invalid name \"%s\".\n"), name); 14618 break; 14619 14620 case SCF_ERROR_NOT_FOUND: 14621 semerr(gettext("No such snapshot \"%s\".\n"), name); 14622 break; 14623 14624 default: 14625 scfdie(); 14626 } 14627 14628 scf_snaplevel_destroy(level); 14629 scf_snapshot_destroy(snap); 14630 return; 14631 } 14632 14633 /* Load the snaplevels into our list. */ 14634 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 14635 if (cur_levels == NULL) 14636 uu_die(gettext("Could not create list: %s\n"), 14637 uu_strerror(uu_error())); 14638 14639 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 14640 if (scf_error() != SCF_ERROR_NOT_FOUND) 14641 scfdie(); 14642 14643 semerr(gettext("Snapshot has no snaplevels.\n")); 14644 14645 scf_snaplevel_destroy(level); 14646 scf_snapshot_destroy(snap); 14647 return; 14648 } 14649 14650 cur_snap = snap; 14651 14652 for (;;) { 14653 cur_elt = safe_malloc(sizeof (*cur_elt)); 14654 uu_list_node_init(cur_elt, &cur_elt->list_node, 14655 snaplevel_pool); 14656 cur_elt->sl = level; 14657 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 14658 uu_die(gettext("libuutil error: %s\n"), 14659 uu_strerror(uu_error())); 14660 14661 level = scf_snaplevel_create(g_hndl); 14662 if (level == NULL) 14663 scfdie(); 14664 14665 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 14666 level) != SCF_SUCCESS) { 14667 if (scf_error() != SCF_ERROR_NOT_FOUND) 14668 scfdie(); 14669 14670 scf_snaplevel_destroy(level); 14671 break; 14672 } 14673 } 14674 14675 cur_elt = uu_list_last(cur_levels); 14676 cur_level = cur_elt->sl; 14677 } 14678 14679 /* 14680 * Copies the properties & values in src to dst. Assumes src won't change. 14681 * Returns -1 if permission is denied, -2 if another transaction interrupts, 14682 * and 0 on success. 14683 * 14684 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 14685 * property, if it is copied and has type boolean. (See comment in 14686 * lscf_revert()). 14687 */ 14688 static int 14689 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 14690 uint8_t enabled) 14691 { 14692 scf_transaction_t *tx; 14693 scf_iter_t *iter, *viter; 14694 scf_property_t *prop; 14695 scf_value_t *v; 14696 char *nbuf; 14697 int r; 14698 14699 tx = scf_transaction_create(g_hndl); 14700 if (tx == NULL) 14701 scfdie(); 14702 14703 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 14704 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14705 scfdie(); 14706 14707 scf_transaction_destroy(tx); 14708 14709 return (-1); 14710 } 14711 14712 if ((iter = scf_iter_create(g_hndl)) == NULL || 14713 (prop = scf_property_create(g_hndl)) == NULL || 14714 (viter = scf_iter_create(g_hndl)) == NULL) 14715 scfdie(); 14716 14717 nbuf = safe_malloc(max_scf_name_len + 1); 14718 14719 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 14720 scfdie(); 14721 14722 for (;;) { 14723 scf_transaction_entry_t *e; 14724 scf_type_t ty; 14725 14726 r = scf_iter_next_property(iter, prop); 14727 if (r == -1) 14728 scfdie(); 14729 if (r == 0) 14730 break; 14731 14732 e = scf_entry_create(g_hndl); 14733 if (e == NULL) 14734 scfdie(); 14735 14736 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 14737 scfdie(); 14738 14739 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 14740 scfdie(); 14741 14742 if (scf_transaction_property_new(tx, e, nbuf, 14743 ty) != SCF_SUCCESS) 14744 scfdie(); 14745 14746 if ((enabled == 0 || enabled == 1) && 14747 strcmp(nbuf, scf_property_enabled) == 0 && 14748 ty == SCF_TYPE_BOOLEAN) { 14749 v = scf_value_create(g_hndl); 14750 if (v == NULL) 14751 scfdie(); 14752 14753 scf_value_set_boolean(v, enabled); 14754 14755 if (scf_entry_add_value(e, v) != 0) 14756 scfdie(); 14757 } else { 14758 if (scf_iter_property_values(viter, prop) != 0) 14759 scfdie(); 14760 14761 for (;;) { 14762 v = scf_value_create(g_hndl); 14763 if (v == NULL) 14764 scfdie(); 14765 14766 r = scf_iter_next_value(viter, v); 14767 if (r == -1) 14768 scfdie(); 14769 if (r == 0) { 14770 scf_value_destroy(v); 14771 break; 14772 } 14773 14774 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 14775 scfdie(); 14776 } 14777 } 14778 } 14779 14780 free(nbuf); 14781 scf_iter_destroy(viter); 14782 scf_property_destroy(prop); 14783 scf_iter_destroy(iter); 14784 14785 r = scf_transaction_commit(tx); 14786 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 14787 scfdie(); 14788 14789 scf_transaction_destroy_children(tx); 14790 scf_transaction_destroy(tx); 14791 14792 switch (r) { 14793 case 1: return (0); 14794 case 0: return (-2); 14795 case -1: return (-1); 14796 14797 default: 14798 abort(); 14799 } 14800 14801 /* NOTREACHED */ 14802 } 14803 14804 void 14805 lscf_revert(const char *snapname) 14806 { 14807 scf_snapshot_t *snap, *prev; 14808 scf_snaplevel_t *level, *nlevel; 14809 scf_iter_t *iter; 14810 scf_propertygroup_t *pg, *npg; 14811 scf_property_t *prop; 14812 scf_value_t *val; 14813 char *nbuf, *tbuf; 14814 uint8_t enabled; 14815 14816 lscf_prep_hndl(); 14817 14818 if (cur_inst == NULL) { 14819 semerr(gettext("Instance not selected.\n")); 14820 return; 14821 } 14822 14823 if (snapname != NULL) { 14824 snap = scf_snapshot_create(g_hndl); 14825 if (snap == NULL) 14826 scfdie(); 14827 14828 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 14829 SCF_SUCCESS) { 14830 switch (scf_error()) { 14831 case SCF_ERROR_INVALID_ARGUMENT: 14832 semerr(gettext("Invalid snapshot name " 14833 "\"%s\".\n"), snapname); 14834 break; 14835 14836 case SCF_ERROR_NOT_FOUND: 14837 semerr(gettext("No such snapshot.\n")); 14838 break; 14839 14840 default: 14841 scfdie(); 14842 } 14843 14844 scf_snapshot_destroy(snap); 14845 return; 14846 } 14847 } else { 14848 if (cur_snap != NULL) { 14849 snap = cur_snap; 14850 } else { 14851 semerr(gettext("No snapshot selected.\n")); 14852 return; 14853 } 14854 } 14855 14856 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 14857 (level = scf_snaplevel_create(g_hndl)) == NULL || 14858 (iter = scf_iter_create(g_hndl)) == NULL || 14859 (pg = scf_pg_create(g_hndl)) == NULL || 14860 (npg = scf_pg_create(g_hndl)) == NULL || 14861 (prop = scf_property_create(g_hndl)) == NULL || 14862 (val = scf_value_create(g_hndl)) == NULL) 14863 scfdie(); 14864 14865 nbuf = safe_malloc(max_scf_name_len + 1); 14866 tbuf = safe_malloc(max_scf_pg_type_len + 1); 14867 14868 /* Take the "previous" snapshot before we blow away the properties. */ 14869 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 14870 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 14871 scfdie(); 14872 } else { 14873 if (scf_error() != SCF_ERROR_NOT_FOUND) 14874 scfdie(); 14875 14876 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 14877 scfdie(); 14878 } 14879 14880 /* Save general/enabled, since we're probably going to replace it. */ 14881 enabled = 2; 14882 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 14883 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 14884 scf_property_get_value(prop, val) == 0) 14885 (void) scf_value_get_boolean(val, &enabled); 14886 14887 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 14888 if (scf_error() != SCF_ERROR_NOT_FOUND) 14889 scfdie(); 14890 14891 goto out; 14892 } 14893 14894 for (;;) { 14895 boolean_t isinst; 14896 uint32_t flags; 14897 int r; 14898 14899 /* Clear the properties from the corresponding entity. */ 14900 isinst = snaplevel_is_instance(level); 14901 14902 if (!isinst) 14903 r = scf_iter_service_pgs(iter, cur_svc); 14904 else 14905 r = scf_iter_instance_pgs(iter, cur_inst); 14906 if (r != SCF_SUCCESS) 14907 scfdie(); 14908 14909 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 14910 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 14911 scfdie(); 14912 14913 /* Skip nonpersistent pgs. */ 14914 if (flags & SCF_PG_FLAG_NONPERSISTENT) 14915 continue; 14916 14917 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14918 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14919 scfdie(); 14920 14921 semerr(emsg_permission_denied); 14922 goto out; 14923 } 14924 } 14925 if (r == -1) 14926 scfdie(); 14927 14928 /* Copy the properties to the corresponding entity. */ 14929 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 14930 scfdie(); 14931 14932 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 14933 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 14934 scfdie(); 14935 14936 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 14937 0) 14938 scfdie(); 14939 14940 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 14941 scfdie(); 14942 14943 if (!isinst) 14944 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 14945 flags, npg); 14946 else 14947 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 14948 flags, npg); 14949 if (r != SCF_SUCCESS) { 14950 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14951 scfdie(); 14952 14953 semerr(emsg_permission_denied); 14954 goto out; 14955 } 14956 14957 if ((enabled == 0 || enabled == 1) && 14958 strcmp(nbuf, scf_pg_general) == 0) 14959 r = pg_copy(pg, npg, enabled); 14960 else 14961 r = pg_copy(pg, npg, 2); 14962 14963 switch (r) { 14964 case 0: 14965 break; 14966 14967 case -1: 14968 semerr(emsg_permission_denied); 14969 goto out; 14970 14971 case -2: 14972 semerr(gettext( 14973 "Interrupted by another change.\n")); 14974 goto out; 14975 14976 default: 14977 abort(); 14978 } 14979 } 14980 if (r == -1) 14981 scfdie(); 14982 14983 /* Get next level. */ 14984 nlevel = scf_snaplevel_create(g_hndl); 14985 if (nlevel == NULL) 14986 scfdie(); 14987 14988 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 14989 SCF_SUCCESS) { 14990 if (scf_error() != SCF_ERROR_NOT_FOUND) 14991 scfdie(); 14992 14993 scf_snaplevel_destroy(nlevel); 14994 break; 14995 } 14996 14997 scf_snaplevel_destroy(level); 14998 level = nlevel; 14999 } 15000 15001 if (snapname == NULL) { 15002 lscf_selectsnap(NULL); 15003 snap = NULL; /* cur_snap has been destroyed */ 15004 } 15005 15006 out: 15007 free(tbuf); 15008 free(nbuf); 15009 scf_value_destroy(val); 15010 scf_property_destroy(prop); 15011 scf_pg_destroy(npg); 15012 scf_pg_destroy(pg); 15013 scf_iter_destroy(iter); 15014 scf_snaplevel_destroy(level); 15015 scf_snapshot_destroy(prev); 15016 if (snap != cur_snap) 15017 scf_snapshot_destroy(snap); 15018 } 15019 15020 void 15021 lscf_refresh(void) 15022 { 15023 ssize_t fmrilen; 15024 size_t bufsz; 15025 char *fmribuf; 15026 int r; 15027 15028 lscf_prep_hndl(); 15029 15030 if (cur_inst == NULL) { 15031 semerr(gettext("Instance not selected.\n")); 15032 return; 15033 } 15034 15035 bufsz = max_scf_fmri_len + 1; 15036 fmribuf = safe_malloc(bufsz); 15037 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 15038 if (fmrilen < 0) { 15039 free(fmribuf); 15040 if (scf_error() != SCF_ERROR_DELETED) 15041 scfdie(); 15042 scf_instance_destroy(cur_inst); 15043 cur_inst = NULL; 15044 warn(emsg_deleted); 15045 return; 15046 } 15047 assert(fmrilen < bufsz); 15048 15049 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 15050 switch (r) { 15051 case 0: 15052 break; 15053 15054 case ECONNABORTED: 15055 warn(gettext("Could not refresh %s " 15056 "(repository connection broken).\n"), fmribuf); 15057 break; 15058 15059 case ECANCELED: 15060 warn(emsg_deleted); 15061 break; 15062 15063 case EPERM: 15064 warn(gettext("Could not refresh %s " 15065 "(permission denied).\n"), fmribuf); 15066 break; 15067 15068 case ENOSPC: 15069 warn(gettext("Could not refresh %s " 15070 "(repository server out of resources).\n"), 15071 fmribuf); 15072 break; 15073 15074 case EACCES: 15075 default: 15076 bad_error("refresh_entity", scf_error()); 15077 } 15078 15079 free(fmribuf); 15080 } 15081 15082 /* 15083 * describe [-v] [-t] [pg/prop] 15084 */ 15085 int 15086 lscf_describe(uu_list_t *args, int hasargs) 15087 { 15088 int ret = 0; 15089 size_t i; 15090 int argc; 15091 char **argv = NULL; 15092 string_list_t *slp; 15093 int do_verbose = 0; 15094 int do_templates = 0; 15095 char *pattern = NULL; 15096 15097 lscf_prep_hndl(); 15098 15099 if (hasargs != 0) { 15100 argc = uu_list_numnodes(args); 15101 if (argc < 1) 15102 goto usage; 15103 15104 argv = calloc(argc + 1, sizeof (char *)); 15105 if (argv == NULL) 15106 uu_die(gettext("Out of memory.\n")); 15107 15108 for (slp = uu_list_first(args), i = 0; 15109 slp != NULL; 15110 slp = uu_list_next(args, slp), ++i) 15111 argv[i] = slp->str; 15112 15113 argv[i] = NULL; 15114 15115 /* 15116 * We start optind = 0 because our list of arguments 15117 * starts at argv[0] 15118 */ 15119 optind = 0; 15120 opterr = 0; 15121 for (;;) { 15122 ret = getopt(argc, argv, "vt"); 15123 if (ret == -1) 15124 break; 15125 15126 switch (ret) { 15127 case 'v': 15128 do_verbose = 1; 15129 break; 15130 15131 case 't': 15132 do_templates = 1; 15133 break; 15134 15135 case '?': 15136 goto usage; 15137 15138 default: 15139 bad_error("getopt", ret); 15140 } 15141 } 15142 15143 pattern = argv[optind]; 15144 } 15145 15146 if (cur_inst == NULL && cur_svc == NULL) { 15147 semerr(emsg_entity_not_selected); 15148 ret = -1; 15149 goto out; 15150 } 15151 15152 /* 15153 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 15154 * output if their last parameter is set to 2. Less information is 15155 * produced if the parameter is set to 1. 15156 */ 15157 if (pattern == NULL) { 15158 if (do_verbose == 1) 15159 list_entity_tmpl(2); 15160 else 15161 list_entity_tmpl(1); 15162 } 15163 15164 if (do_templates == 0) { 15165 if (do_verbose == 1) 15166 listprop(pattern, 0, 2); 15167 else 15168 listprop(pattern, 0, 1); 15169 } else { 15170 if (do_verbose == 1) 15171 listtmpl(pattern, 2); 15172 else 15173 listtmpl(pattern, 1); 15174 } 15175 15176 ret = 0; 15177 out: 15178 if (argv != NULL) 15179 free(argv); 15180 return (ret); 15181 usage: 15182 ret = -2; 15183 goto out; 15184 } 15185 15186 /* 15187 * Creates a list of instance name strings associated with a service. If 15188 * wohandcrafted flag is set, get only instances that have a last-import 15189 * snapshot, instances that were imported via svccfg. 15190 */ 15191 static uu_list_t * 15192 create_instance_list(scf_service_t *svc, int wohandcrafted) 15193 { 15194 scf_snapshot_t *snap = NULL; 15195 scf_instance_t *inst; 15196 scf_iter_t *inst_iter; 15197 uu_list_t *instances; 15198 char *instname; 15199 int r; 15200 15201 inst_iter = scf_iter_create(g_hndl); 15202 inst = scf_instance_create(g_hndl); 15203 if (inst_iter == NULL || inst == NULL) { 15204 uu_warn(gettext("Could not create instance or iterator\n")); 15205 scfdie(); 15206 } 15207 15208 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 15209 return (instances); 15210 15211 if (scf_iter_service_instances(inst_iter, svc) != 0) { 15212 switch (scf_error()) { 15213 case SCF_ERROR_CONNECTION_BROKEN: 15214 case SCF_ERROR_DELETED: 15215 uu_list_destroy(instances); 15216 instances = NULL; 15217 goto out; 15218 15219 case SCF_ERROR_HANDLE_MISMATCH: 15220 case SCF_ERROR_NOT_BOUND: 15221 case SCF_ERROR_NOT_SET: 15222 default: 15223 bad_error("scf_iter_service_instances", scf_error()); 15224 } 15225 } 15226 15227 instname = safe_malloc(max_scf_name_len + 1); 15228 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 15229 if (r == -1) { 15230 (void) uu_warn(gettext("Unable to iterate through " 15231 "instances to create instance list : %s\n"), 15232 scf_strerror(scf_error())); 15233 15234 uu_list_destroy(instances); 15235 instances = NULL; 15236 goto out; 15237 } 15238 15239 /* 15240 * If the instance does not have a last-import snapshot 15241 * then do not add it to the list as it is a hand-crafted 15242 * instance that should not be managed. 15243 */ 15244 if (wohandcrafted) { 15245 if (snap == NULL && 15246 (snap = scf_snapshot_create(g_hndl)) == NULL) { 15247 uu_warn(gettext("Unable to create snapshot " 15248 "entity\n")); 15249 scfdie(); 15250 } 15251 15252 if (scf_instance_get_snapshot(inst, 15253 snap_lastimport, snap) != 0) { 15254 switch (scf_error()) { 15255 case SCF_ERROR_NOT_FOUND : 15256 case SCF_ERROR_DELETED: 15257 continue; 15258 15259 case SCF_ERROR_CONNECTION_BROKEN: 15260 uu_list_destroy(instances); 15261 instances = NULL; 15262 goto out; 15263 15264 case SCF_ERROR_HANDLE_MISMATCH: 15265 case SCF_ERROR_NOT_BOUND: 15266 case SCF_ERROR_NOT_SET: 15267 default: 15268 bad_error("scf_iter_service_instances", 15269 scf_error()); 15270 } 15271 } 15272 } 15273 15274 if (scf_instance_get_name(inst, instname, 15275 max_scf_name_len + 1) < 0) { 15276 switch (scf_error()) { 15277 case SCF_ERROR_NOT_FOUND : 15278 continue; 15279 15280 case SCF_ERROR_CONNECTION_BROKEN: 15281 case SCF_ERROR_DELETED: 15282 uu_list_destroy(instances); 15283 instances = NULL; 15284 goto out; 15285 15286 case SCF_ERROR_HANDLE_MISMATCH: 15287 case SCF_ERROR_NOT_BOUND: 15288 case SCF_ERROR_NOT_SET: 15289 default: 15290 bad_error("scf_iter_service_instances", 15291 scf_error()); 15292 } 15293 } 15294 15295 add_string(instances, instname); 15296 } 15297 15298 out: 15299 if (snap) 15300 scf_snapshot_destroy(snap); 15301 15302 scf_instance_destroy(inst); 15303 scf_iter_destroy(inst_iter); 15304 free(instname); 15305 return (instances); 15306 } 15307 15308 /* 15309 * disable an instance but wait for the instance to 15310 * move out of the running state. 15311 * 15312 * Returns 0 : if the instance did not disable 15313 * Returns non-zero : if the instance disabled. 15314 * 15315 */ 15316 static int 15317 disable_instance(scf_instance_t *instance) 15318 { 15319 char *fmribuf; 15320 int enabled = 10000; 15321 15322 if (inst_is_running(instance)) { 15323 fmribuf = safe_malloc(max_scf_name_len + 1); 15324 if (scf_instance_to_fmri(instance, fmribuf, 15325 max_scf_name_len + 1) < 0) { 15326 free(fmribuf); 15327 return (0); 15328 } 15329 15330 /* 15331 * If the instance cannot be disabled then return 15332 * failure to disable and let the caller decide 15333 * if that is of importance. 15334 */ 15335 if (smf_disable_instance(fmribuf, 0) != 0) { 15336 free(fmribuf); 15337 return (0); 15338 } 15339 15340 while (enabled) { 15341 if (!inst_is_running(instance)) 15342 break; 15343 15344 (void) poll(NULL, 0, 5); 15345 enabled = enabled - 5; 15346 } 15347 15348 free(fmribuf); 15349 } 15350 15351 return (enabled); 15352 } 15353 15354 /* 15355 * Function to compare two service_manifest structures. 15356 */ 15357 /* ARGSUSED2 */ 15358 static int 15359 service_manifest_compare(const void *left, const void *right, void *unused) 15360 { 15361 service_manifest_t *l = (service_manifest_t *)left; 15362 service_manifest_t *r = (service_manifest_t *)right; 15363 int rc; 15364 15365 rc = strcmp(l->servicename, r->servicename); 15366 15367 return (rc); 15368 } 15369 15370 /* 15371 * Look for the provided service in the service to manifest 15372 * tree. If the service exists, and a manifest was provided 15373 * then add the manifest to that service. If the service 15374 * does not exist, then add the service and manifest to the 15375 * list. 15376 * 15377 * If the manifest is NULL, return the element if found. If 15378 * the service is not found return NULL. 15379 */ 15380 service_manifest_t * 15381 find_add_svc_mfst(const char *svnbuf, const char *mfst) 15382 { 15383 service_manifest_t elem; 15384 service_manifest_t *fnelem; 15385 uu_avl_index_t marker; 15386 15387 elem.servicename = svnbuf; 15388 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 15389 15390 if (mfst) { 15391 if (fnelem) { 15392 add_string(fnelem->mfstlist, strdup(mfst)); 15393 } else { 15394 fnelem = safe_malloc(sizeof (*fnelem)); 15395 fnelem->servicename = safe_strdup(svnbuf); 15396 if ((fnelem->mfstlist = 15397 uu_list_create(string_pool, NULL, 0)) == NULL) 15398 uu_die(gettext("Could not create property " 15399 "list: %s\n"), uu_strerror(uu_error())); 15400 15401 add_string(fnelem->mfstlist, safe_strdup(mfst)); 15402 15403 uu_avl_insert(service_manifest_tree, fnelem, marker); 15404 } 15405 } 15406 15407 return (fnelem); 15408 } 15409 15410 /* 15411 * Create the service to manifest avl tree. 15412 * 15413 * Walk each of the manifests currently installed in the supported 15414 * directories, /lib/svc/manifests and /var/svc/manifests. For 15415 * each of the manifests, inventory the services and add them to 15416 * the tree. 15417 * 15418 * Code that calls this function should make sure fileystem/minimal is online, 15419 * /var is available, since this function walks the /var/svc/manifest directory. 15420 */ 15421 static void 15422 create_manifest_tree(void) 15423 { 15424 manifest_info_t **entry; 15425 manifest_info_t **manifests; 15426 uu_list_walk_t *svcs; 15427 bundle_t *b; 15428 entity_t *mfsvc; 15429 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 15430 int c, status; 15431 15432 if (service_manifest_pool) 15433 return; 15434 15435 /* 15436 * Create the list pool for the service manifest list 15437 */ 15438 service_manifest_pool = uu_avl_pool_create("service_manifest", 15439 sizeof (service_manifest_t), 15440 offsetof(service_manifest_t, svcmfst_node), 15441 service_manifest_compare, UU_DEFAULT); 15442 if (service_manifest_pool == NULL) 15443 uu_die(gettext("service_manifest pool creation failed: %s\n"), 15444 uu_strerror(uu_error())); 15445 15446 /* 15447 * Create the list 15448 */ 15449 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 15450 UU_DEFAULT); 15451 if (service_manifest_tree == NULL) 15452 uu_die(gettext("service_manifest tree creation failed: %s\n"), 15453 uu_strerror(uu_error())); 15454 15455 /* 15456 * Walk the manifests adding the service(s) from each manifest. 15457 * 15458 * If a service already exists add the manifest to the manifest 15459 * list for that service. This covers the case of a service that 15460 * is supported by multiple manifest files. 15461 */ 15462 for (c = 0; dirs[c]; c++) { 15463 status = find_manifests(dirs[c], &manifests, CHECKEXT); 15464 if (status < 0) { 15465 uu_warn(gettext("file tree walk of %s encountered " 15466 "error %s\n"), dirs[c], strerror(errno)); 15467 15468 uu_avl_destroy(service_manifest_tree); 15469 service_manifest_tree = NULL; 15470 return; 15471 } 15472 15473 /* 15474 * If a manifest that was in the list is not found 15475 * then skip and go to the next manifest file. 15476 */ 15477 if (manifests != NULL) { 15478 for (entry = manifests; *entry != NULL; entry++) { 15479 b = internal_bundle_new(); 15480 if (lxml_get_bundle_file(b, (*entry)->mi_path, 15481 SVCCFG_OP_IMPORT) != 0) { 15482 internal_bundle_free(b); 15483 continue; 15484 } 15485 15486 svcs = uu_list_walk_start(b->sc_bundle_services, 15487 0); 15488 if (svcs == NULL) { 15489 internal_bundle_free(b); 15490 continue; 15491 } 15492 15493 while ((mfsvc = uu_list_walk_next(svcs)) != 15494 NULL) { 15495 /* Add manifest to service */ 15496 (void) find_add_svc_mfst(mfsvc->sc_name, 15497 (*entry)->mi_path); 15498 } 15499 15500 uu_list_walk_end(svcs); 15501 internal_bundle_free(b); 15502 } 15503 15504 free_manifest_array(manifests); 15505 } 15506 } 15507 } 15508 15509 /* 15510 * Check the manifest history file to see 15511 * if the service was ever installed from 15512 * one of the supported directories. 15513 * 15514 * Return Values : 15515 * -1 - if there's error reading manifest history file 15516 * 1 - if the service is not found 15517 * 0 - if the service is found 15518 */ 15519 static int 15520 check_mfst_history(const char *svcname) 15521 { 15522 struct stat st; 15523 caddr_t mfsthist_start; 15524 char *svnbuf; 15525 int fd; 15526 int r = 1; 15527 15528 fd = open(MFSTHISTFILE, O_RDONLY); 15529 if (fd == -1) { 15530 uu_warn(gettext("Unable to open the history file\n")); 15531 return (-1); 15532 } 15533 15534 if (fstat(fd, &st) == -1) { 15535 uu_warn(gettext("Unable to stat the history file\n")); 15536 return (-1); 15537 } 15538 15539 mfsthist_start = mmap(0, st.st_size, PROT_READ, 15540 MAP_PRIVATE, fd, 0); 15541 15542 (void) close(fd); 15543 if (mfsthist_start == MAP_FAILED || 15544 *(mfsthist_start + st.st_size) != '\0') { 15545 (void) munmap(mfsthist_start, st.st_size); 15546 return (-1); 15547 } 15548 15549 /* 15550 * The manifest history file is a space delimited list 15551 * of service and instance to manifest linkage. Adding 15552 * a space to the end of the service name so to get only 15553 * the service that is being searched for. 15554 */ 15555 svnbuf = uu_msprintf("%s ", svcname); 15556 if (svnbuf == NULL) 15557 uu_die(gettext("Out of memory")); 15558 15559 if (strstr(mfsthist_start, svnbuf) != NULL) 15560 r = 0; 15561 15562 (void) munmap(mfsthist_start, st.st_size); 15563 uu_free(svnbuf); 15564 return (r); 15565 } 15566 15567 /* 15568 * Take down each of the instances in the service 15569 * and remove them, then delete the service. 15570 */ 15571 static void 15572 teardown_service(scf_service_t *svc, const char *svnbuf) 15573 { 15574 scf_instance_t *instance; 15575 scf_iter_t *iter; 15576 int r; 15577 15578 safe_printf(gettext("Delete service %s as there are no " 15579 "supporting manifests\n"), svnbuf); 15580 15581 instance = scf_instance_create(g_hndl); 15582 iter = scf_iter_create(g_hndl); 15583 if (iter == NULL || instance == NULL) { 15584 uu_warn(gettext("Unable to create supporting entities to " 15585 "teardown the service\n")); 15586 uu_warn(gettext("scf error is : %s\n"), 15587 scf_strerror(scf_error())); 15588 scfdie(); 15589 } 15590 15591 if (scf_iter_service_instances(iter, svc) != 0) { 15592 switch (scf_error()) { 15593 case SCF_ERROR_CONNECTION_BROKEN: 15594 case SCF_ERROR_DELETED: 15595 goto out; 15596 15597 case SCF_ERROR_HANDLE_MISMATCH: 15598 case SCF_ERROR_NOT_BOUND: 15599 case SCF_ERROR_NOT_SET: 15600 default: 15601 bad_error("scf_iter_service_instances", 15602 scf_error()); 15603 } 15604 } 15605 15606 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 15607 if (r == -1) { 15608 uu_warn(gettext("Error - %s\n"), 15609 scf_strerror(scf_error())); 15610 goto out; 15611 } 15612 15613 (void) disable_instance(instance); 15614 } 15615 15616 /* 15617 * Delete the service... forcing the deletion in case 15618 * any of the instances did not disable. 15619 */ 15620 (void) lscf_service_delete(svc, 1); 15621 out: 15622 scf_instance_destroy(instance); 15623 scf_iter_destroy(iter); 15624 } 15625 15626 /* 15627 * Get the list of instances supported by the manifest 15628 * file. 15629 * 15630 * Return 0 if there are no instances. 15631 * 15632 * Return -1 if there are errors attempting to collect instances. 15633 * 15634 * Return the count of instances found if there are no errors. 15635 * 15636 */ 15637 static int 15638 check_instance_support(char *mfstfile, const char *svcname, 15639 uu_list_t *instances) 15640 { 15641 uu_list_walk_t *svcs, *insts; 15642 uu_list_t *ilist; 15643 bundle_t *b; 15644 entity_t *mfsvc, *mfinst; 15645 const char *svcn; 15646 int rminstcnt = 0; 15647 15648 15649 b = internal_bundle_new(); 15650 15651 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 15652 /* 15653 * Unable to process the manifest file for 15654 * instance support, so just return as 15655 * don't want to remove instances that could 15656 * not be accounted for that might exist here. 15657 */ 15658 internal_bundle_free(b); 15659 return (0); 15660 } 15661 15662 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 15663 if (svcs == NULL) { 15664 internal_bundle_free(b); 15665 return (0); 15666 } 15667 15668 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 15669 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 15670 15671 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 15672 if (strcmp(mfsvc->sc_name, svcn) == 0) 15673 break; 15674 } 15675 uu_list_walk_end(svcs); 15676 15677 if (mfsvc == NULL) { 15678 internal_bundle_free(b); 15679 return (-1); 15680 } 15681 15682 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 15683 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 15684 internal_bundle_free(b); 15685 return (0); 15686 } 15687 15688 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 15689 /* 15690 * Remove the instance from the instances list. 15691 * The unaccounted for instances will be removed 15692 * from the service once all manifests are 15693 * processed. 15694 */ 15695 (void) remove_string(instances, 15696 mfinst->sc_name); 15697 rminstcnt++; 15698 } 15699 15700 uu_list_walk_end(insts); 15701 internal_bundle_free(b); 15702 15703 return (rminstcnt); 15704 } 15705 15706 /* 15707 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 15708 * 'false' to indicate there's no manifest file(s) found for the service. 15709 */ 15710 static void 15711 svc_add_no_support(scf_service_t *svc) 15712 { 15713 char *pname; 15714 15715 /* Add no support */ 15716 cur_svc = svc; 15717 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 15718 return; 15719 15720 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 15721 if (pname == NULL) 15722 uu_die(gettext("Out of memory.\n")); 15723 15724 (void) lscf_addpropvalue(pname, "boolean:", "0"); 15725 15726 uu_free(pname); 15727 cur_svc = NULL; 15728 } 15729 15730 /* 15731 * This function handles all upgrade scenarios for a service that doesn't have 15732 * SCF_PG_MANIFESTFILES pg. The function creates and populates 15733 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 15734 * manifest(s) mapping. Manifests under supported directories are inventoried 15735 * and a property is added for each file that delivers configuration to the 15736 * service. A service that has no corresponding manifest files (deleted) are 15737 * removed from repository. 15738 * 15739 * Unsupported services: 15740 * 15741 * A service is considered unsupported if there is no corresponding manifest 15742 * in the supported directories for that service and the service isn't in the 15743 * history file list. The history file, MFSTHISTFILE, contains a list of all 15744 * services and instances that were delivered by Solaris before the introduction 15745 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 15746 * the path to the manifest file that defined the service or instance. 15747 * 15748 * Another type of unsupported services is 'handcrafted' services, 15749 * programmatically created services or services created by dependent entries 15750 * in other manifests. A handcrafted service is identified by its lack of any 15751 * instance containing last-import snapshot which is created during svccfg 15752 * import. 15753 * 15754 * This function sets a flag for unsupported services by setting services' 15755 * SCF_PG_MANIFESTFILES/support property to false. 15756 */ 15757 static void 15758 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 15759 { 15760 service_manifest_t *elem; 15761 uu_list_walk_t *mfwalk; 15762 string_list_t *mfile; 15763 uu_list_t *instances; 15764 const char *sname; 15765 char *pname; 15766 int r; 15767 15768 /* 15769 * Since there's no guarantee manifests under /var are available during 15770 * early import, don't perform any upgrade during early import. 15771 */ 15772 if (IGNORE_VAR) 15773 return; 15774 15775 if (service_manifest_tree == NULL) { 15776 create_manifest_tree(); 15777 } 15778 15779 /* 15780 * Find service's supporting manifest(s) after 15781 * stripping off the svc:/ prefix that is part 15782 * of the fmri that is not used in the service 15783 * manifest bundle list. 15784 */ 15785 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 15786 strlen(SCF_FMRI_SERVICE_PREFIX); 15787 elem = find_add_svc_mfst(sname, NULL); 15788 if (elem == NULL) { 15789 15790 /* 15791 * A handcrafted service, one that has no instance containing 15792 * last-import snapshot, should get unsupported flag. 15793 */ 15794 instances = create_instance_list(svc, 1); 15795 if (instances == NULL) { 15796 uu_warn(gettext("Unable to create instance list %s\n"), 15797 svcname); 15798 return; 15799 } 15800 15801 if (uu_list_numnodes(instances) == 0) { 15802 svc_add_no_support(svc); 15803 return; 15804 } 15805 15806 /* 15807 * If the service is in the history file, and its supporting 15808 * manifests are not found, we can safely delete the service 15809 * because its manifests are removed from the system. 15810 * 15811 * Services not found in the history file are not delivered by 15812 * Solaris and/or delivered outside supported directories, set 15813 * unsupported flag for these services. 15814 */ 15815 r = check_mfst_history(svcname); 15816 if (r == -1) 15817 return; 15818 15819 if (r) { 15820 /* Set unsupported flag for service */ 15821 svc_add_no_support(svc); 15822 } else { 15823 /* Delete the service */ 15824 teardown_service(svc, svcname); 15825 } 15826 15827 return; 15828 } 15829 15830 /* 15831 * Walk through the list of manifests and add them 15832 * to the service. 15833 * 15834 * Create a manifestfiles pg and add the property. 15835 */ 15836 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 15837 if (mfwalk == NULL) 15838 return; 15839 15840 cur_svc = svc; 15841 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 15842 if (r != 0) { 15843 cur_svc = NULL; 15844 return; 15845 } 15846 15847 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 15848 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 15849 mhash_filename_to_propname(mfile->str, 0)); 15850 if (pname == NULL) 15851 uu_die(gettext("Out of memory.\n")); 15852 15853 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 15854 uu_free(pname); 15855 } 15856 uu_list_walk_end(mfwalk); 15857 15858 cur_svc = NULL; 15859 } 15860 15861 /* 15862 * Take a service and process the manifest file entires to see if 15863 * there is continued support for the service and instances. If 15864 * not cleanup as appropriate. 15865 * 15866 * If a service does not have a manifest files entry flag it for 15867 * upgrade and return. 15868 * 15869 * For each manifestfiles property check if the manifest file is 15870 * under the supported /lib/svc/manifest or /var/svc/manifest path 15871 * and if not then return immediately as this service is not supported 15872 * by the cleanup mechanism and should be ignored. 15873 * 15874 * For each manifest file that is supported, check to see if the 15875 * file exists. If not then remove the manifest file property 15876 * from the service and the smf/manifest hash table. If the manifest 15877 * file exists then verify that it supports the instances that are 15878 * part of the service. 15879 * 15880 * Once all manifest files have been accounted for remove any instances 15881 * that are no longer supported in the service. 15882 * 15883 * Return values : 15884 * 0 - Successfully processed the service 15885 * non-zero - failed to process the service 15886 * 15887 * On most errors, will just return to wait and get the next service, 15888 * unless in case of unable to create the needed structures which is 15889 * most likely a fatal error that is not going to be recoverable. 15890 */ 15891 int 15892 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 15893 { 15894 struct mpg_mfile *mpntov; 15895 struct mpg_mfile **mpvarry = NULL; 15896 scf_service_t *svc; 15897 scf_propertygroup_t *mpg; 15898 scf_property_t *mp; 15899 scf_value_t *mv; 15900 scf_iter_t *mi; 15901 scf_instance_t *instance; 15902 uu_list_walk_t *insts; 15903 uu_list_t *instances = NULL; 15904 boolean_t activity = (boolean_t)act; 15905 char *mpnbuf; 15906 char *mpvbuf; 15907 char *pgpropbuf; 15908 int mfstcnt, rminstct, instct, mfstmax; 15909 int index; 15910 int r = 0; 15911 15912 assert(g_hndl != NULL); 15913 assert(wip->svc != NULL); 15914 assert(wip->fmri != NULL); 15915 15916 svc = wip->svc; 15917 15918 mpg = scf_pg_create(g_hndl); 15919 mp = scf_property_create(g_hndl); 15920 mi = scf_iter_create(g_hndl); 15921 mv = scf_value_create(g_hndl); 15922 instance = scf_instance_create(g_hndl); 15923 15924 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 15925 instance == NULL) { 15926 uu_warn(gettext("Unable to create the supporting entities\n")); 15927 uu_warn(gettext("scf error is : %s\n"), 15928 scf_strerror(scf_error())); 15929 scfdie(); 15930 } 15931 15932 /* 15933 * Get the manifestfiles property group to be parsed for 15934 * files existence. 15935 */ 15936 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 15937 switch (scf_error()) { 15938 case SCF_ERROR_NOT_FOUND: 15939 upgrade_svc_mfst_connection(svc, wip->fmri); 15940 break; 15941 case SCF_ERROR_DELETED: 15942 case SCF_ERROR_CONNECTION_BROKEN: 15943 goto out; 15944 15945 case SCF_ERROR_HANDLE_MISMATCH: 15946 case SCF_ERROR_NOT_BOUND: 15947 case SCF_ERROR_NOT_SET: 15948 default: 15949 bad_error("scf_iter_pg_properties", 15950 scf_error()); 15951 } 15952 15953 goto out; 15954 } 15955 15956 /* 15957 * Iterate through each of the manifestfiles properties 15958 * to determine what manifestfiles are available. 15959 * 15960 * If a manifest file is supported then increment the 15961 * count and therefore the service is safe. 15962 */ 15963 if (scf_iter_pg_properties(mi, mpg) != 0) { 15964 switch (scf_error()) { 15965 case SCF_ERROR_DELETED: 15966 case SCF_ERROR_CONNECTION_BROKEN: 15967 goto out; 15968 15969 case SCF_ERROR_HANDLE_MISMATCH: 15970 case SCF_ERROR_NOT_BOUND: 15971 case SCF_ERROR_NOT_SET: 15972 default: 15973 bad_error("scf_iter_pg_properties", 15974 scf_error()); 15975 } 15976 } 15977 15978 mfstcnt = 0; 15979 mfstmax = MFSTFILE_MAX; 15980 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 15981 while ((r = scf_iter_next_property(mi, mp)) != 0) { 15982 if (r == -1) 15983 bad_error(gettext("Unable to iterate through " 15984 "manifestfiles properties : %s"), 15985 scf_error()); 15986 15987 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 15988 mpnbuf = safe_malloc(max_scf_name_len + 1); 15989 mpvbuf = safe_malloc(max_scf_value_len + 1); 15990 mpntov->mpg = mpnbuf; 15991 mpntov->mfile = mpvbuf; 15992 mpntov->access = 1; 15993 if (scf_property_get_name(mp, mpnbuf, 15994 max_scf_name_len + 1) < 0) { 15995 uu_warn(gettext("Unable to get manifest file " 15996 "property : %s\n"), 15997 scf_strerror(scf_error())); 15998 15999 switch (scf_error()) { 16000 case SCF_ERROR_DELETED: 16001 case SCF_ERROR_CONNECTION_BROKEN: 16002 r = scferror2errno(scf_error()); 16003 goto out_free; 16004 16005 case SCF_ERROR_HANDLE_MISMATCH: 16006 case SCF_ERROR_NOT_BOUND: 16007 case SCF_ERROR_NOT_SET: 16008 default: 16009 bad_error("scf_iter_pg_properties", 16010 scf_error()); 16011 } 16012 } 16013 16014 /* 16015 * The support property is a boolean value that indicates 16016 * if the service is supported for manifest file deletion. 16017 * Currently at this time there is no code that sets this 16018 * value to true. So while we could just let this be caught 16019 * by the support check below, in the future this by be set 16020 * to true and require processing. So for that, go ahead 16021 * and check here, and just return if false. Otherwise, 16022 * fall through expecting that other support checks will 16023 * handle the entries. 16024 */ 16025 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 16026 uint8_t support; 16027 16028 if (scf_property_get_value(mp, mv) != 0 || 16029 scf_value_get_boolean(mv, &support) != 0) { 16030 uu_warn(gettext("Unable to get the manifest " 16031 "support value: %s\n"), 16032 scf_strerror(scf_error())); 16033 16034 switch (scf_error()) { 16035 case SCF_ERROR_DELETED: 16036 case SCF_ERROR_CONNECTION_BROKEN: 16037 r = scferror2errno(scf_error()); 16038 goto out_free; 16039 16040 case SCF_ERROR_HANDLE_MISMATCH: 16041 case SCF_ERROR_NOT_BOUND: 16042 case SCF_ERROR_NOT_SET: 16043 default: 16044 bad_error("scf_iter_pg_properties", 16045 scf_error()); 16046 } 16047 } 16048 16049 if (support == B_FALSE) 16050 goto out_free; 16051 } 16052 16053 /* 16054 * Anything with a manifest outside of the supported 16055 * directories, immediately bail out because that makes 16056 * this service non-supported. We don't even want 16057 * to do instance processing in this case because the 16058 * instances could be part of the non-supported manifest. 16059 */ 16060 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 16061 /* 16062 * Manifest is not in /lib/svc, so we need to 16063 * consider the /var/svc case. 16064 */ 16065 if (strncmp(mpnbuf, VARSVC_PR, 16066 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 16067 /* 16068 * Either the manifest is not in /var/svc or 16069 * /var is not yet mounted. We ignore the 16070 * manifest either because it is not in a 16071 * standard location or because we cannot 16072 * currently access the manifest. 16073 */ 16074 goto out_free; 16075 } 16076 } 16077 16078 /* 16079 * Get the value to of the manifest file for this entry 16080 * for access verification and instance support 16081 * verification if it still exists. 16082 * 16083 * During Early Manifest Import if the manifest is in 16084 * /var/svc then it may not yet be available for checking 16085 * so we must determine if /var/svc is available. If not 16086 * then defer until Late Manifest Import to cleanup. 16087 */ 16088 if (scf_property_get_value(mp, mv) != 0) { 16089 uu_warn(gettext("Unable to get the manifest file " 16090 "value: %s\n"), 16091 scf_strerror(scf_error())); 16092 16093 switch (scf_error()) { 16094 case SCF_ERROR_DELETED: 16095 case SCF_ERROR_CONNECTION_BROKEN: 16096 r = scferror2errno(scf_error()); 16097 goto out_free; 16098 16099 case SCF_ERROR_HANDLE_MISMATCH: 16100 case SCF_ERROR_NOT_BOUND: 16101 case SCF_ERROR_NOT_SET: 16102 default: 16103 bad_error("scf_property_get_value", 16104 scf_error()); 16105 } 16106 } 16107 16108 if (scf_value_get_astring(mv, mpvbuf, 16109 max_scf_value_len + 1) < 0) { 16110 uu_warn(gettext("Unable to get the manifest " 16111 "file : %s\n"), 16112 scf_strerror(scf_error())); 16113 16114 switch (scf_error()) { 16115 case SCF_ERROR_DELETED: 16116 case SCF_ERROR_CONNECTION_BROKEN: 16117 r = scferror2errno(scf_error()); 16118 goto out_free; 16119 16120 case SCF_ERROR_HANDLE_MISMATCH: 16121 case SCF_ERROR_NOT_BOUND: 16122 case SCF_ERROR_NOT_SET: 16123 default: 16124 bad_error("scf_value_get_astring", 16125 scf_error()); 16126 } 16127 } 16128 16129 mpvarry[mfstcnt] = mpntov; 16130 mfstcnt++; 16131 16132 /* 16133 * Check for the need to reallocate array 16134 */ 16135 if (mfstcnt >= (mfstmax - 1)) { 16136 struct mpg_mfile **newmpvarry; 16137 16138 mfstmax = mfstmax * 2; 16139 newmpvarry = realloc(mpvarry, 16140 sizeof (struct mpg_mfile *) * mfstmax); 16141 16142 if (newmpvarry == NULL) 16143 goto out_free; 16144 16145 mpvarry = newmpvarry; 16146 } 16147 16148 mpvarry[mfstcnt] = NULL; 16149 } 16150 16151 for (index = 0; mpvarry[index]; index++) { 16152 mpntov = mpvarry[index]; 16153 16154 /* 16155 * Check to see if the manifestfile is accessable, if so hand 16156 * this service and manifestfile off to be processed for 16157 * instance support. 16158 */ 16159 mpnbuf = mpntov->mpg; 16160 mpvbuf = mpntov->mfile; 16161 if (access(mpvbuf, F_OK) != 0) { 16162 mpntov->access = 0; 16163 activity++; 16164 mfstcnt--; 16165 /* Remove the entry from the service */ 16166 cur_svc = svc; 16167 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 16168 mpnbuf); 16169 if (pgpropbuf == NULL) 16170 uu_die(gettext("Out of memory.\n")); 16171 16172 lscf_delprop(pgpropbuf); 16173 cur_svc = NULL; 16174 16175 uu_free(pgpropbuf); 16176 } 16177 } 16178 16179 /* 16180 * If mfstcnt is 0, none of the manifests that supported the service 16181 * existed so remove the service. 16182 */ 16183 if (mfstcnt == 0) { 16184 teardown_service(svc, wip->fmri); 16185 16186 goto out_free; 16187 } 16188 16189 if (activity) { 16190 int nosvcsupport = 0; 16191 16192 /* 16193 * If the list of service instances is NULL then 16194 * create the list. 16195 */ 16196 instances = create_instance_list(svc, 1); 16197 if (instances == NULL) { 16198 uu_warn(gettext("Unable to create instance list %s\n"), 16199 wip->fmri); 16200 goto out_free; 16201 } 16202 16203 rminstct = uu_list_numnodes(instances); 16204 instct = rminstct; 16205 16206 for (index = 0; mpvarry[index]; index++) { 16207 mpntov = mpvarry[index]; 16208 if (mpntov->access == 0) 16209 continue; 16210 16211 mpnbuf = mpntov->mpg; 16212 mpvbuf = mpntov->mfile; 16213 r = check_instance_support(mpvbuf, wip->fmri, 16214 instances); 16215 if (r == -1) { 16216 nosvcsupport++; 16217 } else { 16218 rminstct -= r; 16219 } 16220 } 16221 16222 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 16223 teardown_service(svc, wip->fmri); 16224 16225 goto out_free; 16226 } 16227 } 16228 16229 /* 16230 * If there are instances left on the instance list, then 16231 * we must remove them. 16232 */ 16233 if (instances != NULL && uu_list_numnodes(instances)) { 16234 string_list_t *sp; 16235 16236 insts = uu_list_walk_start(instances, 0); 16237 while ((sp = uu_list_walk_next(insts)) != NULL) { 16238 /* 16239 * Remove the instance from the instances list. 16240 */ 16241 safe_printf(gettext("Delete instance %s from " 16242 "service %s\n"), sp->str, wip->fmri); 16243 if (scf_service_get_instance(svc, sp->str, 16244 instance) != SCF_SUCCESS) { 16245 (void) uu_warn("scf_error - %s\n", 16246 scf_strerror(scf_error())); 16247 16248 continue; 16249 } 16250 16251 (void) disable_instance(instance); 16252 16253 (void) lscf_instance_delete(instance, 1); 16254 } 16255 scf_instance_destroy(instance); 16256 uu_list_walk_end(insts); 16257 } 16258 16259 out_free: 16260 if (mpvarry) { 16261 struct mpg_mfile *fmpntov; 16262 16263 for (index = 0; mpvarry[index]; index++) { 16264 fmpntov = mpvarry[index]; 16265 if (fmpntov->mpg == mpnbuf) 16266 mpnbuf = NULL; 16267 free(fmpntov->mpg); 16268 16269 if (fmpntov->mfile == mpvbuf) 16270 mpvbuf = NULL; 16271 free(fmpntov->mfile); 16272 16273 if (fmpntov == mpntov) 16274 mpntov = NULL; 16275 free(fmpntov); 16276 } 16277 if (mpnbuf) 16278 free(mpnbuf); 16279 if (mpvbuf) 16280 free(mpvbuf); 16281 if (mpntov) 16282 free(mpntov); 16283 16284 free(mpvarry); 16285 } 16286 out: 16287 scf_pg_destroy(mpg); 16288 scf_property_destroy(mp); 16289 scf_iter_destroy(mi); 16290 scf_value_destroy(mv); 16291 16292 return (0); 16293 } 16294 16295 /* 16296 * Take the service and search for the manifestfiles property 16297 * in each of the property groups. If the manifest file 16298 * associated with the property does not exist then remove 16299 * the property group. 16300 */ 16301 int 16302 lscf_hash_cleanup() 16303 { 16304 scf_service_t *svc; 16305 scf_scope_t *scope; 16306 scf_propertygroup_t *pg; 16307 scf_property_t *prop; 16308 scf_value_t *val; 16309 scf_iter_t *iter; 16310 char *pgname; 16311 char *mfile; 16312 int r; 16313 16314 svc = scf_service_create(g_hndl); 16315 scope = scf_scope_create(g_hndl); 16316 pg = scf_pg_create(g_hndl); 16317 prop = scf_property_create(g_hndl); 16318 val = scf_value_create(g_hndl); 16319 iter = scf_iter_create(g_hndl); 16320 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 16321 svc == NULL || scope == NULL) { 16322 uu_warn(gettext("Unable to create a property group, or " 16323 "property\n")); 16324 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 16325 "pg is not NULL"); 16326 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 16327 "prop is not NULL"); 16328 uu_warn("%s\n", val == NULL ? "val is NULL" : 16329 "val is not NULL"); 16330 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 16331 "iter is not NULL"); 16332 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 16333 "svc is not NULL"); 16334 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 16335 "scope is not NULL"); 16336 uu_warn(gettext("scf error is : %s\n"), 16337 scf_strerror(scf_error())); 16338 scfdie(); 16339 } 16340 16341 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 16342 switch (scf_error()) { 16343 case SCF_ERROR_CONNECTION_BROKEN: 16344 case SCF_ERROR_NOT_FOUND: 16345 goto out; 16346 16347 case SCF_ERROR_HANDLE_MISMATCH: 16348 case SCF_ERROR_NOT_BOUND: 16349 case SCF_ERROR_INVALID_ARGUMENT: 16350 default: 16351 bad_error("scf_handle_get_scope", scf_error()); 16352 } 16353 } 16354 16355 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 16356 uu_warn(gettext("Unable to process the hash service, %s\n"), 16357 HASH_SVC); 16358 goto out; 16359 } 16360 16361 pgname = safe_malloc(max_scf_name_len + 1); 16362 mfile = safe_malloc(max_scf_value_len + 1); 16363 16364 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 16365 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 16366 scf_strerror(scf_error())); 16367 goto out; 16368 } 16369 16370 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 16371 if (r == -1) 16372 goto out; 16373 16374 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 16375 switch (scf_error()) { 16376 case SCF_ERROR_DELETED: 16377 return (ENODEV); 16378 16379 case SCF_ERROR_CONNECTION_BROKEN: 16380 return (ECONNABORTED); 16381 16382 case SCF_ERROR_NOT_SET: 16383 case SCF_ERROR_NOT_BOUND: 16384 default: 16385 bad_error("scf_pg_get_name", scf_error()); 16386 } 16387 } 16388 if (IGNORE_VAR) { 16389 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 16390 continue; 16391 } 16392 16393 /* 16394 * If unable to get the property continue as this is an 16395 * entry that has no location to check against. 16396 */ 16397 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 16398 continue; 16399 } 16400 16401 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 16402 uu_warn(gettext("Unable to get value from %s\n"), 16403 pgname); 16404 goto error_handle; 16405 } 16406 16407 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) == 16408 -1) { 16409 uu_warn(gettext("Unable to get astring from %s : %s\n"), 16410 pgname, scf_strerror(scf_error())); 16411 goto error_handle; 16412 } 16413 16414 if (access(mfile, F_OK) == 0) 16415 continue; 16416 16417 (void) scf_pg_delete(pg); 16418 16419 error_handle: 16420 switch (scf_error()) { 16421 case SCF_ERROR_DELETED: 16422 case SCF_ERROR_CONSTRAINT_VIOLATED: 16423 case SCF_ERROR_NOT_FOUND: 16424 case SCF_ERROR_NOT_SET: 16425 continue; 16426 16427 case SCF_ERROR_CONNECTION_BROKEN: 16428 r = scferror2errno(scf_error()); 16429 goto out; 16430 16431 case SCF_ERROR_HANDLE_MISMATCH: 16432 case SCF_ERROR_NOT_BOUND: 16433 default: 16434 bad_error("scf_value_get_astring", 16435 scf_error()); 16436 } 16437 } 16438 16439 out: 16440 scf_scope_destroy(scope); 16441 scf_service_destroy(svc); 16442 scf_pg_destroy(pg); 16443 scf_property_destroy(prop); 16444 scf_value_destroy(val); 16445 scf_iter_destroy(iter); 16446 free(pgname); 16447 free(mfile); 16448 16449 return (0); 16450 } 16451 16452 #ifndef NATIVE_BUILD 16453 /* ARGSUSED */ 16454 CPL_MATCH_FN(complete_select) 16455 { 16456 const char *arg0, *arg1, *arg1end; 16457 int word_start, err = 0, r; 16458 size_t len; 16459 char *buf; 16460 16461 lscf_prep_hndl(); 16462 16463 arg0 = line + strspn(line, " \t"); 16464 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 16465 16466 arg1 = arg0 + sizeof ("select") - 1; 16467 arg1 += strspn(arg1, " \t"); 16468 word_start = arg1 - line; 16469 16470 arg1end = arg1 + strcspn(arg1, " \t"); 16471 if (arg1end < line + word_end) 16472 return (0); 16473 16474 len = line + word_end - arg1; 16475 16476 buf = safe_malloc(max_scf_name_len + 1); 16477 16478 if (cur_snap != NULL) { 16479 return (0); 16480 } else if (cur_inst != NULL) { 16481 return (0); 16482 } else if (cur_svc != NULL) { 16483 scf_instance_t *inst; 16484 scf_iter_t *iter; 16485 16486 if ((inst = scf_instance_create(g_hndl)) == NULL || 16487 (iter = scf_iter_create(g_hndl)) == NULL) 16488 scfdie(); 16489 16490 if (scf_iter_service_instances(iter, cur_svc) != 0) 16491 scfdie(); 16492 16493 for (;;) { 16494 r = scf_iter_next_instance(iter, inst); 16495 if (r == 0) 16496 break; 16497 if (r != 1) 16498 scfdie(); 16499 16500 if (scf_instance_get_name(inst, buf, 16501 max_scf_name_len + 1) < 0) 16502 scfdie(); 16503 16504 if (strncmp(buf, arg1, len) == 0) { 16505 err = cpl_add_completion(cpl, line, word_start, 16506 word_end, buf + len, "", " "); 16507 if (err != 0) 16508 break; 16509 } 16510 } 16511 16512 scf_iter_destroy(iter); 16513 scf_instance_destroy(inst); 16514 16515 return (err); 16516 } else { 16517 scf_service_t *svc; 16518 scf_iter_t *iter; 16519 16520 assert(cur_scope != NULL); 16521 16522 if ((svc = scf_service_create(g_hndl)) == NULL || 16523 (iter = scf_iter_create(g_hndl)) == NULL) 16524 scfdie(); 16525 16526 if (scf_iter_scope_services(iter, cur_scope) != 0) 16527 scfdie(); 16528 16529 for (;;) { 16530 r = scf_iter_next_service(iter, svc); 16531 if (r == 0) 16532 break; 16533 if (r != 1) 16534 scfdie(); 16535 16536 if (scf_service_get_name(svc, buf, 16537 max_scf_name_len + 1) < 0) 16538 scfdie(); 16539 16540 if (strncmp(buf, arg1, len) == 0) { 16541 err = cpl_add_completion(cpl, line, word_start, 16542 word_end, buf + len, "", " "); 16543 if (err != 0) 16544 break; 16545 } 16546 } 16547 16548 scf_iter_destroy(iter); 16549 scf_service_destroy(svc); 16550 16551 return (err); 16552 } 16553 } 16554 16555 /* ARGSUSED */ 16556 CPL_MATCH_FN(complete_command) 16557 { 16558 uint32_t scope = 0; 16559 16560 if (cur_snap != NULL) 16561 scope = CS_SNAP; 16562 else if (cur_inst != NULL) 16563 scope = CS_INST; 16564 else if (cur_svc != NULL) 16565 scope = CS_SVC; 16566 else 16567 scope = CS_SCOPE; 16568 16569 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 16570 } 16571 #endif /* NATIVE_BUILD */ 16572