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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 #include <alloca.h> 29 #include <assert.h> 30 #include <ctype.h> 31 #include <door.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <fnmatch.h> 35 #include <inttypes.h> 36 #include <libintl.h> 37 #include <libscf.h> 38 #include <libscf_priv.h> 39 #include <libtecla.h> 40 #include <libuutil.h> 41 #include <limits.h> 42 #include <locale.h> 43 #include <stdarg.h> 44 #include <string.h> 45 #include <strings.h> 46 #include <unistd.h> 47 #include <wait.h> 48 #include <poll.h> 49 50 #include <libxml/tree.h> 51 52 #include <sys/param.h> 53 54 #include <sys/stat.h> 55 #include <sys/mman.h> 56 57 #include "svccfg.h" 58 #include "manifest_hash.h" 59 #include "manifest_find.h" 60 61 /* The colon namespaces in each entity (each followed by a newline). */ 62 #define COLON_NAMESPACES ":properties\n" 63 64 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 65 66 /* These are characters which the lexer requires to be in double-quotes. */ 67 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 68 69 #define HASH_SIZE 16 70 #define HASH_PG_TYPE "framework" 71 #define HASH_PG_FLAGS 0 72 #define HASH_PROP "md5sum" 73 74 /* 75 * Indentation used in the output of the describe subcommand. 76 */ 77 #define TMPL_VALUE_INDENT " " 78 #define TMPL_INDENT " " 79 #define TMPL_INDENT_2X " " 80 #define TMPL_CHOICE_INDENT " " 81 82 /* 83 * Directory locations for manifests 84 */ 85 #define VARSVC_DIR "/var/svc/manifest" 86 #define LIBSVC_DIR "/lib/svc/manifest" 87 #define VARSVC_PR "var_svc_manifest" 88 #define LIBSVC_PR "lib_svc_manifest" 89 #define MFSTFILEPR "manifestfile" 90 91 #define SUPPORTPROP "support" 92 93 #define MFSTHISTFILE "/lib/svc/share/mfsthistory" 94 95 #define MFSTFILE_MAX 16 96 97 /* 98 * These are the classes of elements which may appear as children of service 99 * or instance elements in XML manifests. 100 */ 101 struct entity_elts { 102 xmlNodePtr create_default_instance; 103 xmlNodePtr single_instance; 104 xmlNodePtr restarter; 105 xmlNodePtr dependencies; 106 xmlNodePtr dependents; 107 xmlNodePtr method_context; 108 xmlNodePtr exec_methods; 109 xmlNodePtr property_groups; 110 xmlNodePtr instances; 111 xmlNodePtr stability; 112 xmlNodePtr template; 113 }; 114 115 /* 116 * Likewise for property_group elements. 117 */ 118 struct pg_elts { 119 xmlNodePtr stability; 120 xmlNodePtr propvals; 121 xmlNodePtr properties; 122 }; 123 124 /* 125 * Likewise for template elements. 126 */ 127 struct template_elts { 128 xmlNodePtr common_name; 129 xmlNodePtr description; 130 xmlNodePtr documentation; 131 }; 132 133 /* 134 * This structure is for snaplevel lists. They are convenient because libscf 135 * only allows traversing snaplevels in one direction. 136 */ 137 struct snaplevel { 138 uu_list_node_t list_node; 139 scf_snaplevel_t *sl; 140 }; 141 142 /* 143 * This is used for communication between lscf_service_export and 144 * export_callback. 145 */ 146 struct export_args { 147 const char *filename; 148 int flags; 149 }; 150 151 /* 152 * The service_manifest structure is used by the upgrade process 153 * to create a list of service to manifest linkages from the manifests 154 * in a set of given directories. 155 */ 156 typedef struct service_manifest { 157 const char *servicename; 158 uu_list_t *mfstlist; 159 size_t mfstlist_sz; 160 161 uu_avl_node_t svcmfst_node; 162 } service_manifest_t; 163 164 /* 165 * Structure to track the manifest file property group 166 * and the manifest file associated with that property 167 * group. Also, a flag to keep the access once it has 168 * been checked. 169 */ 170 struct mpg_mfile { 171 char *mpg; 172 char *mfile; 173 int access; 174 }; 175 176 const char * const scf_pg_general = SCF_PG_GENERAL; 177 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 178 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 179 const char * const scf_property_external = "external"; 180 181 const char * const snap_initial = "initial"; 182 const char * const snap_lastimport = "last-import"; 183 const char * const snap_previous = "previous"; 184 const char * const snap_running = "running"; 185 186 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 187 188 ssize_t max_scf_fmri_len; 189 ssize_t max_scf_name_len; 190 ssize_t max_scf_pg_type_len; 191 ssize_t max_scf_value_len; 192 static size_t max_scf_len; 193 194 static scf_scope_t *cur_scope; 195 static scf_service_t *cur_svc = NULL; 196 static scf_instance_t *cur_inst = NULL; 197 static scf_snapshot_t *cur_snap = NULL; 198 static scf_snaplevel_t *cur_level = NULL; 199 200 static uu_list_pool_t *snaplevel_pool; 201 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 202 static uu_list_t *cur_levels; 203 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 204 205 static FILE *tempfile = NULL; 206 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 207 208 static const char *emsg_entity_not_selected; 209 static const char *emsg_permission_denied; 210 static const char *emsg_create_xml; 211 static const char *emsg_cant_modify_snapshots; 212 static const char *emsg_read_only; 213 static const char *emsg_deleted; 214 static const char *emsg_invalid_pg_name; 215 static const char *emsg_invalid_prop_name; 216 static const char *emsg_no_such_pg; 217 static const char *emsg_fmri_invalid_pg_name; 218 static const char *emsg_fmri_invalid_pg_name_type; 219 static const char *emsg_pg_added; 220 static const char *emsg_pg_changed; 221 static const char *emsg_pg_deleted; 222 static const char *emsg_pg_mod_perm; 223 static const char *emsg_pg_add_perm; 224 static const char *emsg_pg_del_perm; 225 static const char *emsg_snap_perm; 226 static const char *emsg_dpt_dangling; 227 static const char *emsg_dpt_no_dep; 228 229 static int li_only = 0; 230 static int no_refresh = 0; 231 232 /* import globals, to minimize allocations */ 233 static scf_scope_t *imp_scope = NULL; 234 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 235 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 236 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 237 static scf_snapshot_t *imp_rsnap = NULL; 238 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 239 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 240 static scf_property_t *imp_prop = NULL; 241 static scf_iter_t *imp_iter = NULL; 242 static scf_iter_t *imp_rpg_iter = NULL; 243 static scf_iter_t *imp_up_iter = NULL; 244 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 245 static char *imp_str = NULL; 246 static size_t imp_str_sz; 247 static char *imp_tsname = NULL; 248 static char *imp_fe1 = NULL; /* for fmri_equal() */ 249 static char *imp_fe2 = NULL; 250 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 251 252 /* upgrade_dependents() globals */ 253 static scf_instance_t *ud_inst = NULL; 254 static scf_snaplevel_t *ud_snpl = NULL; 255 static scf_propertygroup_t *ud_pg = NULL; 256 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 257 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 258 static int ud_run_dpts_pg_set = 0; 259 static scf_property_t *ud_prop = NULL; 260 static scf_property_t *ud_dpt_prop = NULL; 261 static scf_value_t *ud_val = NULL; 262 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 263 static scf_transaction_t *ud_tx = NULL; 264 static char *ud_ctarg = NULL; 265 static char *ud_oldtarg = NULL; 266 static char *ud_name = NULL; 267 268 /* export globals */ 269 static scf_instance_t *exp_inst; 270 static scf_propertygroup_t *exp_pg; 271 static scf_property_t *exp_prop; 272 static scf_value_t *exp_val; 273 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 274 static char *exp_str; 275 static size_t exp_str_sz; 276 277 /* cleanup globals */ 278 static uu_avl_pool_t *service_manifest_pool = NULL; 279 static uu_avl_t *service_manifest_tree = NULL; 280 281 static void scfdie_lineno(int lineno) __NORETURN; 282 283 static char *start_method_names[] = { 284 "start", 285 "inetd_start", 286 NULL 287 }; 288 289 static void 290 safe_printf(const char *fmt, ...) 291 { 292 va_list va; 293 294 va_start(va, fmt); 295 if (vprintf(fmt, va) < 0) 296 uu_die(gettext("Error writing to stdout")); 297 va_end(va); 298 } 299 300 /* 301 * For unexpected libscf errors. 302 */ 303 #ifdef NDEBUG 304 305 static void scfdie(void) __NORETURN; 306 307 static void 308 scfdie(void) 309 { 310 scf_error_t err = scf_error(); 311 312 if (err == SCF_ERROR_CONNECTION_BROKEN) 313 uu_die(gettext("Repository connection broken. Exiting.\n")); 314 315 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 316 scf_strerror(err)); 317 } 318 319 #else 320 321 #define scfdie() scfdie_lineno(__LINE__) 322 323 static void 324 scfdie_lineno(int lineno) 325 { 326 scf_error_t err = scf_error(); 327 328 if (err == SCF_ERROR_CONNECTION_BROKEN) 329 uu_die(gettext("Repository connection broken. Exiting.\n")); 330 331 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 332 ": %s.\n"), lineno, scf_strerror(err)); 333 } 334 335 #endif 336 337 static void 338 scfwarn(void) 339 { 340 warn(gettext("Unexpected libscf error: %s.\n"), 341 scf_strerror(scf_error())); 342 } 343 344 /* 345 * Clear a field of a structure. 346 */ 347 static int 348 clear_int(void *a, void *b) 349 { 350 /* LINTED */ 351 *(int *)((char *)a + (size_t)b) = 0; 352 353 return (UU_WALK_NEXT); 354 } 355 356 static int 357 scferror2errno(scf_error_t err) 358 { 359 switch (err) { 360 case SCF_ERROR_BACKEND_ACCESS: 361 return (EACCES); 362 363 case SCF_ERROR_BACKEND_READONLY: 364 return (EROFS); 365 366 case SCF_ERROR_CONNECTION_BROKEN: 367 return (ECONNABORTED); 368 369 case SCF_ERROR_CONSTRAINT_VIOLATED: 370 case SCF_ERROR_INVALID_ARGUMENT: 371 return (EINVAL); 372 373 case SCF_ERROR_DELETED: 374 return (ECANCELED); 375 376 case SCF_ERROR_EXISTS: 377 return (EEXIST); 378 379 case SCF_ERROR_NO_MEMORY: 380 return (ENOMEM); 381 382 case SCF_ERROR_NO_RESOURCES: 383 return (ENOSPC); 384 385 case SCF_ERROR_NOT_FOUND: 386 return (ENOENT); 387 388 case SCF_ERROR_PERMISSION_DENIED: 389 return (EPERM); 390 391 default: 392 #ifndef NDEBUG 393 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 394 __FILE__, __LINE__, err); 395 #else 396 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 397 #endif 398 abort(); 399 /* NOTREACHED */ 400 } 401 } 402 403 static int 404 entity_get_pg(void *ent, int issvc, const char *name, 405 scf_propertygroup_t *pg) 406 { 407 if (issvc) 408 return (scf_service_get_pg(ent, name, pg)); 409 else 410 return (scf_instance_get_pg(ent, name, pg)); 411 } 412 413 static void 414 entity_destroy(void *ent, int issvc) 415 { 416 if (issvc) 417 scf_service_destroy(ent); 418 else 419 scf_instance_destroy(ent); 420 } 421 422 static int 423 get_pg(const char *pg_name, scf_propertygroup_t *pg) 424 { 425 int ret; 426 427 if (cur_level != NULL) 428 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 429 else if (cur_inst != NULL) 430 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 431 else 432 ret = scf_service_get_pg(cur_svc, pg_name, pg); 433 434 return (ret); 435 } 436 437 /* 438 * Find a snaplevel in a snapshot. If get_svc is true, find the service 439 * snaplevel. Otherwise find the instance snaplevel. 440 * 441 * Returns 442 * 0 - success 443 * ECONNABORTED - repository connection broken 444 * ECANCELED - instance containing snap was deleted 445 * ENOENT - snap has no snaplevels 446 * - requested snaplevel not found 447 */ 448 static int 449 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 450 { 451 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 452 switch (scf_error()) { 453 case SCF_ERROR_CONNECTION_BROKEN: 454 case SCF_ERROR_DELETED: 455 case SCF_ERROR_NOT_FOUND: 456 return (scferror2errno(scf_error())); 457 458 case SCF_ERROR_HANDLE_MISMATCH: 459 case SCF_ERROR_NOT_BOUND: 460 case SCF_ERROR_NOT_SET: 461 default: 462 bad_error("scf_snapshot_get_base_snaplevel", 463 scf_error()); 464 } 465 } 466 467 for (;;) { 468 ssize_t ssz; 469 470 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 471 if (ssz >= 0) { 472 if (!get_svc) 473 return (0); 474 } else { 475 switch (scf_error()) { 476 case SCF_ERROR_CONSTRAINT_VIOLATED: 477 if (get_svc) 478 return (0); 479 break; 480 481 case SCF_ERROR_DELETED: 482 case SCF_ERROR_CONNECTION_BROKEN: 483 return (scferror2errno(scf_error())); 484 485 case SCF_ERROR_NOT_SET: 486 case SCF_ERROR_NOT_BOUND: 487 default: 488 bad_error("scf_snaplevel_get_instance_name", 489 scf_error()); 490 } 491 } 492 493 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 494 switch (scf_error()) { 495 case SCF_ERROR_NOT_FOUND: 496 case SCF_ERROR_CONNECTION_BROKEN: 497 case SCF_ERROR_DELETED: 498 return (scferror2errno(scf_error())); 499 500 case SCF_ERROR_HANDLE_MISMATCH: 501 case SCF_ERROR_NOT_BOUND: 502 case SCF_ERROR_NOT_SET: 503 case SCF_ERROR_INVALID_ARGUMENT: 504 default: 505 bad_error("scf_snaplevel_get_next_snaplevel", 506 scf_error()); 507 } 508 } 509 } 510 } 511 512 /* 513 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 514 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 515 * the property group named name in it. If it doesn't have a running 516 * snapshot, set pg to the instance's current property group named name. 517 * 518 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 519 * its instances. If one has a running snapshot with a service snaplevel, set 520 * pg to the property group named name in it. If no such snaplevel could be 521 * found, set pg to the service's current property group named name. 522 * 523 * iter, inst, snap, and snpl are required scratch objects. 524 * 525 * Returns 526 * 0 - success 527 * ECONNABORTED - repository connection broken 528 * ECANCELED - ent was deleted 529 * ENOENT - no such property group 530 * EINVAL - name is an invalid property group name 531 * EBADF - found running snapshot is missing a snaplevel 532 */ 533 static int 534 entity_get_running_pg(void *ent, int issvc, const char *name, 535 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 536 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 537 { 538 int r; 539 540 if (issvc) { 541 /* Search for an instance with a running snapshot. */ 542 if (scf_iter_service_instances(iter, ent) != 0) { 543 switch (scf_error()) { 544 case SCF_ERROR_DELETED: 545 case SCF_ERROR_CONNECTION_BROKEN: 546 return (scferror2errno(scf_error())); 547 548 case SCF_ERROR_NOT_SET: 549 case SCF_ERROR_NOT_BOUND: 550 case SCF_ERROR_HANDLE_MISMATCH: 551 default: 552 bad_error("scf_iter_service_instances", 553 scf_error()); 554 } 555 } 556 557 for (;;) { 558 r = scf_iter_next_instance(iter, inst); 559 if (r == 0) { 560 if (scf_service_get_pg(ent, name, pg) == 0) 561 return (0); 562 563 switch (scf_error()) { 564 case SCF_ERROR_DELETED: 565 case SCF_ERROR_NOT_FOUND: 566 case SCF_ERROR_INVALID_ARGUMENT: 567 case SCF_ERROR_CONNECTION_BROKEN: 568 return (scferror2errno(scf_error())); 569 570 case SCF_ERROR_NOT_BOUND: 571 case SCF_ERROR_HANDLE_MISMATCH: 572 case SCF_ERROR_NOT_SET: 573 default: 574 bad_error("scf_service_get_pg", 575 scf_error()); 576 } 577 } 578 if (r != 1) { 579 switch (scf_error()) { 580 case SCF_ERROR_DELETED: 581 case SCF_ERROR_CONNECTION_BROKEN: 582 return (scferror2errno(scf_error())); 583 584 case SCF_ERROR_INVALID_ARGUMENT: 585 case SCF_ERROR_NOT_SET: 586 case SCF_ERROR_NOT_BOUND: 587 case SCF_ERROR_HANDLE_MISMATCH: 588 default: 589 bad_error("scf_iter_next_instance", 590 scf_error()); 591 } 592 } 593 594 if (scf_instance_get_snapshot(inst, snap_running, 595 snap) == 0) 596 break; 597 598 switch (scf_error()) { 599 case SCF_ERROR_NOT_FOUND: 600 case SCF_ERROR_DELETED: 601 continue; 602 603 case SCF_ERROR_CONNECTION_BROKEN: 604 return (ECONNABORTED); 605 606 case SCF_ERROR_HANDLE_MISMATCH: 607 case SCF_ERROR_INVALID_ARGUMENT: 608 case SCF_ERROR_NOT_SET: 609 case SCF_ERROR_NOT_BOUND: 610 default: 611 bad_error("scf_instance_get_snapshot", 612 scf_error()); 613 } 614 } 615 } else { 616 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 617 switch (scf_error()) { 618 case SCF_ERROR_NOT_FOUND: 619 break; 620 621 case SCF_ERROR_DELETED: 622 case SCF_ERROR_CONNECTION_BROKEN: 623 return (scferror2errno(scf_error())); 624 625 case SCF_ERROR_NOT_BOUND: 626 case SCF_ERROR_HANDLE_MISMATCH: 627 case SCF_ERROR_INVALID_ARGUMENT: 628 case SCF_ERROR_NOT_SET: 629 default: 630 bad_error("scf_instance_get_snapshot", 631 scf_error()); 632 } 633 634 if (scf_instance_get_pg(ent, name, pg) == 0) 635 return (0); 636 637 switch (scf_error()) { 638 case SCF_ERROR_DELETED: 639 case SCF_ERROR_NOT_FOUND: 640 case SCF_ERROR_INVALID_ARGUMENT: 641 case SCF_ERROR_CONNECTION_BROKEN: 642 return (scferror2errno(scf_error())); 643 644 case SCF_ERROR_NOT_BOUND: 645 case SCF_ERROR_HANDLE_MISMATCH: 646 case SCF_ERROR_NOT_SET: 647 default: 648 bad_error("scf_instance_get_pg", scf_error()); 649 } 650 } 651 } 652 653 r = get_snaplevel(snap, issvc, snpl); 654 switch (r) { 655 case 0: 656 break; 657 658 case ECONNABORTED: 659 case ECANCELED: 660 return (r); 661 662 case ENOENT: 663 return (EBADF); 664 665 default: 666 bad_error("get_snaplevel", r); 667 } 668 669 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 670 return (0); 671 672 switch (scf_error()) { 673 case SCF_ERROR_DELETED: 674 case SCF_ERROR_INVALID_ARGUMENT: 675 case SCF_ERROR_CONNECTION_BROKEN: 676 case SCF_ERROR_NOT_FOUND: 677 return (scferror2errno(scf_error())); 678 679 case SCF_ERROR_NOT_BOUND: 680 case SCF_ERROR_HANDLE_MISMATCH: 681 case SCF_ERROR_NOT_SET: 682 default: 683 bad_error("scf_snaplevel_get_pg", scf_error()); 684 /* NOTREACHED */ 685 } 686 } 687 688 /* 689 * To be registered with atexit(). 690 */ 691 static void 692 remove_tempfile(void) 693 { 694 int ret; 695 696 if (tempfile != NULL) { 697 if (fclose(tempfile) == EOF) 698 (void) warn(gettext("Could not close temporary file")); 699 tempfile = NULL; 700 } 701 702 if (tempfilename[0] != '\0') { 703 do { 704 ret = remove(tempfilename); 705 } while (ret == -1 && errno == EINTR); 706 if (ret == -1) 707 warn(gettext("Could not remove temporary file")); 708 tempfilename[0] = '\0'; 709 } 710 } 711 712 /* 713 * Launch private svc.configd(1M) for manipulating alternate repositories. 714 */ 715 static void 716 start_private_repository(engine_state_t *est) 717 { 718 int fd, stat; 719 struct door_info info; 720 pid_t pid; 721 722 /* 723 * 1. Create a temporary file for the door. 724 */ 725 if (est->sc_repo_doorname != NULL) 726 free((void *)est->sc_repo_doorname); 727 728 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 729 if (est->sc_repo_doorname == NULL) 730 uu_die(gettext("Could not acquire temporary filename")); 731 732 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 733 if (fd < 0) 734 uu_die(gettext("Could not create temporary file for " 735 "repository server")); 736 737 (void) close(fd); 738 739 /* 740 * 2. Launch a configd with that door, using the specified 741 * repository. 742 */ 743 if ((est->sc_repo_pid = fork()) == 0) { 744 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 745 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 746 NULL); 747 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 748 } else if (est->sc_repo_pid == -1) 749 uu_die(gettext("Attempt to fork failed")); 750 751 do { 752 pid = waitpid(est->sc_repo_pid, &stat, 0); 753 } while (pid == -1 && errno == EINTR); 754 755 if (pid == -1) 756 uu_die(gettext("Could not waitpid() for repository server")); 757 758 if (!WIFEXITED(stat)) { 759 uu_die(gettext("Repository server failed (status %d).\n"), 760 stat); 761 } else if (WEXITSTATUS(stat) != 0) { 762 uu_die(gettext("Repository server failed (exit %d).\n"), 763 WEXITSTATUS(stat)); 764 } 765 766 /* 767 * See if it was successful by checking if the door is a door. 768 */ 769 770 fd = open(est->sc_repo_doorname, O_RDWR); 771 if (fd < 0) 772 uu_die(gettext("Could not open door \"%s\""), 773 est->sc_repo_doorname); 774 775 if (door_info(fd, &info) < 0) 776 uu_die(gettext("Unexpected door_info() error")); 777 778 if (close(fd) == -1) 779 warn(gettext("Could not close repository door"), 780 strerror(errno)); 781 782 est->sc_repo_pid = info.di_target; 783 } 784 785 void 786 lscf_cleanup(void) 787 { 788 /* 789 * In the case where we've launched a private svc.configd(1M) 790 * instance, we must terminate our child and remove the temporary 791 * rendezvous point. 792 */ 793 if (est->sc_repo_pid > 0) { 794 (void) kill(est->sc_repo_pid, SIGTERM); 795 (void) waitpid(est->sc_repo_pid, NULL, 0); 796 (void) unlink(est->sc_repo_doorname); 797 798 est->sc_repo_pid = 0; 799 } 800 } 801 802 void 803 unselect_cursnap(void) 804 { 805 void *cookie; 806 807 cur_level = NULL; 808 809 cookie = NULL; 810 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 811 scf_snaplevel_destroy(cur_elt->sl); 812 free(cur_elt); 813 } 814 815 scf_snapshot_destroy(cur_snap); 816 cur_snap = NULL; 817 } 818 819 void 820 lscf_prep_hndl(void) 821 { 822 if (g_hndl != NULL) 823 return; 824 825 g_hndl = scf_handle_create(SCF_VERSION); 826 if (g_hndl == NULL) 827 scfdie(); 828 829 if (est->sc_repo_filename != NULL) 830 start_private_repository(est); 831 832 if (est->sc_repo_doorname != NULL) { 833 scf_value_t *repo_value; 834 int ret; 835 836 repo_value = scf_value_create(g_hndl); 837 if (repo_value == NULL) 838 scfdie(); 839 840 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 841 assert(ret == SCF_SUCCESS); 842 843 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 844 SCF_SUCCESS) 845 scfdie(); 846 847 scf_value_destroy(repo_value); 848 } 849 850 if (scf_handle_bind(g_hndl) != 0) 851 uu_die(gettext("Could not connect to repository server: %s.\n"), 852 scf_strerror(scf_error())); 853 854 cur_scope = scf_scope_create(g_hndl); 855 if (cur_scope == NULL) 856 scfdie(); 857 858 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 859 scfdie(); 860 } 861 862 static void 863 repository_teardown(void) 864 { 865 if (g_hndl != NULL) { 866 if (cur_snap != NULL) 867 unselect_cursnap(); 868 scf_instance_destroy(cur_inst); 869 scf_service_destroy(cur_svc); 870 scf_scope_destroy(cur_scope); 871 scf_handle_destroy(g_hndl); 872 cur_inst = NULL; 873 cur_svc = NULL; 874 cur_scope = NULL; 875 g_hndl = NULL; 876 lscf_cleanup(); 877 } 878 } 879 880 void 881 lscf_set_repository(const char *repfile, int force) 882 { 883 repository_teardown(); 884 885 if (est->sc_repo_filename != NULL) { 886 free((void *)est->sc_repo_filename); 887 est->sc_repo_filename = NULL; 888 } 889 890 if ((force == 0) && (access(repfile, R_OK) != 0)) { 891 /* 892 * Repository file does not exist 893 * or has no read permission. 894 */ 895 warn(gettext("Cannot access \"%s\": %s\n"), 896 repfile, strerror(errno)); 897 } else { 898 est->sc_repo_filename = safe_strdup(repfile); 899 } 900 901 lscf_prep_hndl(); 902 } 903 904 void 905 lscf_init() 906 { 907 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 908 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 909 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 910 0 || 911 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 912 scfdie(); 913 914 max_scf_len = max_scf_fmri_len; 915 if (max_scf_name_len > max_scf_len) 916 max_scf_len = max_scf_name_len; 917 if (max_scf_pg_type_len > max_scf_len) 918 max_scf_len = max_scf_pg_type_len; 919 if (max_scf_value_len > max_scf_len) 920 max_scf_len = max_scf_value_len; 921 922 if (atexit(remove_tempfile) != 0) 923 uu_die(gettext("Could not register atexit() function")); 924 925 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 926 emsg_permission_denied = gettext("Permission denied.\n"); 927 emsg_create_xml = gettext("Could not create XML node.\n"); 928 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 929 emsg_read_only = gettext("Backend read-only.\n"); 930 emsg_deleted = gettext("Current selection has been deleted.\n"); 931 emsg_invalid_pg_name = 932 gettext("Invalid property group name \"%s\".\n"); 933 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 934 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 935 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 936 "with invalid name \"%s\".\n"); 937 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 938 "group with invalid name \"%s\" or type \"%s\".\n"); 939 emsg_pg_added = gettext("%s changed unexpectedly " 940 "(property group \"%s\" added).\n"); 941 emsg_pg_changed = gettext("%s changed unexpectedly " 942 "(property group \"%s\" changed).\n"); 943 emsg_pg_deleted = gettext("%s changed unexpectedly " 944 "(property group \"%s\" or an ancestor was deleted).\n"); 945 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 946 "in %s (permission denied).\n"); 947 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 948 "in %s (permission denied).\n"); 949 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 950 "in %s (permission denied).\n"); 951 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 952 "(permission denied).\n"); 953 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 954 "new dependent \"%s\" because it already exists). Warning: The " 955 "current dependent's target (%s) does not exist.\n"); 956 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 957 "dependent \"%s\" because it already exists). Warning: The " 958 "current dependent's target (%s) does not have a dependency named " 959 "\"%s\" as expected.\n"); 960 961 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 962 offsetof(string_list_t, node), NULL, 0); 963 snaplevel_pool = uu_list_pool_create("snaplevels", 964 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 965 NULL, 0); 966 } 967 968 969 static const char * 970 prop_to_typestr(const scf_property_t *prop) 971 { 972 scf_type_t ty; 973 974 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 975 scfdie(); 976 977 return (scf_type_to_string(ty)); 978 } 979 980 static scf_type_t 981 string_to_type(const char *type) 982 { 983 size_t len = strlen(type); 984 char *buf; 985 986 if (len == 0 || type[len - 1] != ':') 987 return (SCF_TYPE_INVALID); 988 989 buf = (char *)alloca(len + 1); 990 (void) strlcpy(buf, type, len + 1); 991 buf[len - 1] = 0; 992 993 return (scf_string_to_type(buf)); 994 } 995 996 static scf_value_t * 997 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 998 { 999 scf_value_t *v; 1000 char *dup, *nstr; 1001 size_t len; 1002 1003 v = scf_value_create(g_hndl); 1004 if (v == NULL) 1005 scfdie(); 1006 1007 len = strlen(str); 1008 if (require_quotes && 1009 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 1010 semerr(gettext("Multiple string values or string values " 1011 "with spaces must be quoted with '\"'.\n")); 1012 scf_value_destroy(v); 1013 return (NULL); 1014 } 1015 1016 nstr = dup = safe_strdup(str); 1017 if (dup[0] == '\"') { 1018 /* 1019 * Strip out the first and the last quote. 1020 */ 1021 dup[len - 1] = '\0'; 1022 nstr = dup + 1; 1023 } 1024 1025 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 1026 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 1027 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 1028 scf_type_to_string(ty), nstr); 1029 scf_value_destroy(v); 1030 v = NULL; 1031 } 1032 free(dup); 1033 return (v); 1034 } 1035 1036 /* 1037 * Print str to strm, quoting double-quotes and backslashes with backslashes. 1038 * Optionally append a comment prefix ('#') to newlines ('\n'). 1039 */ 1040 static int 1041 quote_and_print(const char *str, FILE *strm, int commentnl) 1042 { 1043 const char *cp; 1044 1045 for (cp = str; *cp != '\0'; ++cp) { 1046 if (*cp == '"' || *cp == '\\') 1047 (void) putc('\\', strm); 1048 1049 (void) putc(*cp, strm); 1050 1051 if (commentnl && *cp == '\n') { 1052 (void) putc('#', strm); 1053 } 1054 } 1055 1056 return (ferror(strm)); 1057 } 1058 1059 /* 1060 * These wrappers around lowlevel functions provide consistent error checking 1061 * and warnings. 1062 */ 1063 static int 1064 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1065 { 1066 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1067 return (0); 1068 1069 if (scf_error() != SCF_ERROR_NOT_FOUND) 1070 scfdie(); 1071 1072 if (g_verbose) { 1073 ssize_t len; 1074 char *fmri; 1075 1076 len = scf_pg_to_fmri(pg, NULL, 0); 1077 if (len < 0) 1078 scfdie(); 1079 1080 fmri = safe_malloc(len + 1); 1081 1082 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1083 scfdie(); 1084 1085 warn(gettext("Expected property %s of property group %s is " 1086 "missing.\n"), propname, fmri); 1087 1088 free(fmri); 1089 } 1090 1091 return (-1); 1092 } 1093 1094 static int 1095 prop_check_type(scf_property_t *prop, scf_type_t ty) 1096 { 1097 scf_type_t pty; 1098 1099 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1100 scfdie(); 1101 1102 if (ty == pty) 1103 return (0); 1104 1105 if (g_verbose) { 1106 ssize_t len; 1107 char *fmri; 1108 const char *tystr; 1109 1110 len = scf_property_to_fmri(prop, NULL, 0); 1111 if (len < 0) 1112 scfdie(); 1113 1114 fmri = safe_malloc(len + 1); 1115 1116 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1117 scfdie(); 1118 1119 tystr = scf_type_to_string(ty); 1120 if (tystr == NULL) 1121 tystr = "?"; 1122 1123 warn(gettext("Property %s is not of expected type %s.\n"), 1124 fmri, tystr); 1125 1126 free(fmri); 1127 } 1128 1129 return (-1); 1130 } 1131 1132 static int 1133 prop_get_val(scf_property_t *prop, scf_value_t *val) 1134 { 1135 scf_error_t err; 1136 1137 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1138 return (0); 1139 1140 err = scf_error(); 1141 1142 if (err != SCF_ERROR_NOT_FOUND && 1143 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1144 err != SCF_ERROR_PERMISSION_DENIED) 1145 scfdie(); 1146 1147 if (g_verbose) { 1148 ssize_t len; 1149 char *fmri, *emsg; 1150 1151 len = scf_property_to_fmri(prop, NULL, 0); 1152 if (len < 0) 1153 scfdie(); 1154 1155 fmri = safe_malloc(len + 1); 1156 1157 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1158 scfdie(); 1159 1160 if (err == SCF_ERROR_NOT_FOUND) 1161 emsg = gettext("Property %s has no values; expected " 1162 "one.\n"); 1163 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1164 emsg = gettext("Property %s has multiple values; " 1165 "expected one.\n"); 1166 else 1167 emsg = gettext("No permission to read property %s.\n"); 1168 1169 warn(emsg, fmri); 1170 1171 free(fmri); 1172 } 1173 1174 return (-1); 1175 } 1176 1177 1178 static boolean_t 1179 snaplevel_is_instance(const scf_snaplevel_t *level) 1180 { 1181 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1182 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1183 scfdie(); 1184 return (0); 1185 } else { 1186 return (1); 1187 } 1188 } 1189 1190 /* 1191 * Decode FMRI into a service or instance, and put the result in *ep. If 1192 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1193 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1194 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1195 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1196 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1197 * whether *ep is a service. 1198 */ 1199 static scf_error_t 1200 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1201 { 1202 char *fmri_copy; 1203 const char *sstr, *istr, *pgstr; 1204 scf_service_t *svc; 1205 scf_instance_t *inst; 1206 1207 fmri_copy = strdup(fmri); 1208 if (fmri_copy == NULL) 1209 return (SCF_ERROR_NO_MEMORY); 1210 1211 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1212 SCF_SUCCESS) { 1213 free(fmri_copy); 1214 return (SCF_ERROR_INVALID_ARGUMENT); 1215 } 1216 1217 free(fmri_copy); 1218 1219 if (sstr == NULL || pgstr != NULL) 1220 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1221 1222 if (istr == NULL) { 1223 svc = scf_service_create(h); 1224 if (svc == NULL) 1225 return (SCF_ERROR_NO_MEMORY); 1226 1227 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1228 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1229 if (scf_error() != SCF_ERROR_NOT_FOUND) 1230 scfdie(); 1231 1232 return (SCF_ERROR_NOT_FOUND); 1233 } 1234 1235 *ep = svc; 1236 *isservice = 1; 1237 } else { 1238 inst = scf_instance_create(h); 1239 if (inst == NULL) 1240 return (SCF_ERROR_NO_MEMORY); 1241 1242 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1243 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1244 if (scf_error() != SCF_ERROR_NOT_FOUND) 1245 scfdie(); 1246 1247 return (SCF_ERROR_NOT_FOUND); 1248 } 1249 1250 *ep = inst; 1251 *isservice = 0; 1252 } 1253 1254 return (SCF_ERROR_NONE); 1255 } 1256 1257 /* 1258 * Create the entity named by fmri. Place a pointer to its libscf handle in 1259 * *ep, and set or clear *isservicep if it is a service or an instance. 1260 * Returns 1261 * SCF_ERROR_NONE - success 1262 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1263 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1264 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1265 * SCF_ERROR_NOT_FOUND - no such scope 1266 * SCF_ERROR_PERMISSION_DENIED 1267 * SCF_ERROR_BACKEND_READONLY 1268 * SCF_ERROR_BACKEND_ACCESS 1269 */ 1270 static scf_error_t 1271 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1272 { 1273 char *fmri_copy; 1274 const char *scstr, *sstr, *istr, *pgstr; 1275 scf_scope_t *scope = NULL; 1276 scf_service_t *svc = NULL; 1277 scf_instance_t *inst = NULL; 1278 scf_error_t scfe; 1279 1280 fmri_copy = safe_strdup(fmri); 1281 1282 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1283 0) { 1284 free(fmri_copy); 1285 return (SCF_ERROR_INVALID_ARGUMENT); 1286 } 1287 1288 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1289 free(fmri_copy); 1290 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1291 } 1292 1293 *ep = NULL; 1294 1295 if ((scope = scf_scope_create(h)) == NULL || 1296 (svc = scf_service_create(h)) == NULL || 1297 (inst = scf_instance_create(h)) == NULL) { 1298 scfe = SCF_ERROR_NO_MEMORY; 1299 goto out; 1300 } 1301 1302 get_scope: 1303 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1304 switch (scf_error()) { 1305 case SCF_ERROR_CONNECTION_BROKEN: 1306 scfdie(); 1307 /* NOTREACHED */ 1308 1309 case SCF_ERROR_NOT_FOUND: 1310 scfe = SCF_ERROR_NOT_FOUND; 1311 goto out; 1312 1313 case SCF_ERROR_HANDLE_MISMATCH: 1314 case SCF_ERROR_NOT_BOUND: 1315 case SCF_ERROR_INVALID_ARGUMENT: 1316 default: 1317 bad_error("scf_handle_get_scope", scf_error()); 1318 } 1319 } 1320 1321 get_svc: 1322 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1323 switch (scf_error()) { 1324 case SCF_ERROR_CONNECTION_BROKEN: 1325 scfdie(); 1326 /* NOTREACHED */ 1327 1328 case SCF_ERROR_DELETED: 1329 goto get_scope; 1330 1331 case SCF_ERROR_NOT_FOUND: 1332 break; 1333 1334 case SCF_ERROR_HANDLE_MISMATCH: 1335 case SCF_ERROR_INVALID_ARGUMENT: 1336 case SCF_ERROR_NOT_BOUND: 1337 case SCF_ERROR_NOT_SET: 1338 default: 1339 bad_error("scf_scope_get_service", scf_error()); 1340 } 1341 1342 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1343 switch (scf_error()) { 1344 case SCF_ERROR_CONNECTION_BROKEN: 1345 scfdie(); 1346 /* NOTREACHED */ 1347 1348 case SCF_ERROR_DELETED: 1349 goto get_scope; 1350 1351 case SCF_ERROR_PERMISSION_DENIED: 1352 case SCF_ERROR_BACKEND_READONLY: 1353 case SCF_ERROR_BACKEND_ACCESS: 1354 scfe = scf_error(); 1355 goto out; 1356 1357 case SCF_ERROR_HANDLE_MISMATCH: 1358 case SCF_ERROR_INVALID_ARGUMENT: 1359 case SCF_ERROR_NOT_BOUND: 1360 case SCF_ERROR_NOT_SET: 1361 default: 1362 bad_error("scf_scope_get_service", scf_error()); 1363 } 1364 } 1365 } 1366 1367 if (istr == NULL) { 1368 scfe = SCF_ERROR_NONE; 1369 *ep = svc; 1370 *isservicep = 1; 1371 goto out; 1372 } 1373 1374 get_inst: 1375 if (scf_service_get_instance(svc, istr, inst) != 0) { 1376 switch (scf_error()) { 1377 case SCF_ERROR_CONNECTION_BROKEN: 1378 scfdie(); 1379 /* NOTREACHED */ 1380 1381 case SCF_ERROR_DELETED: 1382 goto get_svc; 1383 1384 case SCF_ERROR_NOT_FOUND: 1385 break; 1386 1387 case SCF_ERROR_HANDLE_MISMATCH: 1388 case SCF_ERROR_INVALID_ARGUMENT: 1389 case SCF_ERROR_NOT_BOUND: 1390 case SCF_ERROR_NOT_SET: 1391 default: 1392 bad_error("scf_service_get_instance", scf_error()); 1393 } 1394 1395 if (scf_service_add_instance(svc, istr, inst) != 0) { 1396 switch (scf_error()) { 1397 case SCF_ERROR_CONNECTION_BROKEN: 1398 scfdie(); 1399 /* NOTREACHED */ 1400 1401 case SCF_ERROR_DELETED: 1402 goto get_svc; 1403 1404 case SCF_ERROR_PERMISSION_DENIED: 1405 case SCF_ERROR_BACKEND_READONLY: 1406 case SCF_ERROR_BACKEND_ACCESS: 1407 scfe = scf_error(); 1408 goto out; 1409 1410 case SCF_ERROR_HANDLE_MISMATCH: 1411 case SCF_ERROR_INVALID_ARGUMENT: 1412 case SCF_ERROR_NOT_BOUND: 1413 case SCF_ERROR_NOT_SET: 1414 default: 1415 bad_error("scf_service_add_instance", 1416 scf_error()); 1417 } 1418 } 1419 } 1420 1421 scfe = SCF_ERROR_NONE; 1422 *ep = inst; 1423 *isservicep = 0; 1424 1425 out: 1426 if (*ep != inst) 1427 scf_instance_destroy(inst); 1428 if (*ep != svc) 1429 scf_service_destroy(svc); 1430 scf_scope_destroy(scope); 1431 free(fmri_copy); 1432 return (scfe); 1433 } 1434 1435 /* 1436 * Create or update a snapshot of inst. snap is a required scratch object. 1437 * 1438 * Returns 1439 * 0 - success 1440 * ECONNABORTED - repository connection broken 1441 * EPERM - permission denied 1442 * ENOSPC - configd is out of resources 1443 * ECANCELED - inst was deleted 1444 * -1 - unknown libscf error (message printed) 1445 */ 1446 static int 1447 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1448 { 1449 again: 1450 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1451 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1452 switch (scf_error()) { 1453 case SCF_ERROR_CONNECTION_BROKEN: 1454 case SCF_ERROR_PERMISSION_DENIED: 1455 case SCF_ERROR_NO_RESOURCES: 1456 return (scferror2errno(scf_error())); 1457 1458 case SCF_ERROR_NOT_SET: 1459 case SCF_ERROR_INVALID_ARGUMENT: 1460 default: 1461 bad_error("_scf_snapshot_take_attach", 1462 scf_error()); 1463 } 1464 } 1465 } else { 1466 switch (scf_error()) { 1467 case SCF_ERROR_NOT_FOUND: 1468 break; 1469 1470 case SCF_ERROR_DELETED: 1471 case SCF_ERROR_CONNECTION_BROKEN: 1472 return (scferror2errno(scf_error())); 1473 1474 case SCF_ERROR_HANDLE_MISMATCH: 1475 case SCF_ERROR_NOT_BOUND: 1476 case SCF_ERROR_INVALID_ARGUMENT: 1477 case SCF_ERROR_NOT_SET: 1478 default: 1479 bad_error("scf_instance_get_snapshot", scf_error()); 1480 } 1481 1482 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1483 switch (scf_error()) { 1484 case SCF_ERROR_EXISTS: 1485 goto again; 1486 1487 case SCF_ERROR_CONNECTION_BROKEN: 1488 case SCF_ERROR_NO_RESOURCES: 1489 case SCF_ERROR_PERMISSION_DENIED: 1490 return (scferror2errno(scf_error())); 1491 1492 default: 1493 scfwarn(); 1494 return (-1); 1495 1496 case SCF_ERROR_NOT_SET: 1497 case SCF_ERROR_INTERNAL: 1498 case SCF_ERROR_INVALID_ARGUMENT: 1499 case SCF_ERROR_HANDLE_MISMATCH: 1500 bad_error("_scf_snapshot_take_new", 1501 scf_error()); 1502 } 1503 } 1504 } 1505 1506 return (0); 1507 } 1508 1509 static int 1510 refresh_running_snapshot(void *entity) 1511 { 1512 scf_snapshot_t *snap; 1513 int r; 1514 1515 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1516 scfdie(); 1517 r = take_snap(entity, snap_running, snap); 1518 scf_snapshot_destroy(snap); 1519 1520 return (r); 1521 } 1522 1523 /* 1524 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1525 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1526 * instances. fmri is used for messages. inst, iter, and name_buf are used 1527 * for scratch space. Returns 1528 * 0 - success 1529 * ECONNABORTED - repository connection broken 1530 * ECANCELED - entity was deleted 1531 * EACCES - backend denied access 1532 * EPERM - permission denied 1533 * ENOSPC - repository server out of resources 1534 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1535 */ 1536 static int 1537 refresh_entity(int isservice, void *entity, const char *fmri, 1538 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1539 { 1540 scf_error_t scfe; 1541 int r; 1542 1543 if (!isservice) { 1544 /* 1545 * Let restarter handles refreshing and making new running 1546 * snapshot only if operating on a live repository and not 1547 * running in early import. 1548 */ 1549 if (est->sc_repo_filename == NULL && 1550 est->sc_repo_doorname == NULL && 1551 est->sc_in_emi == 0) { 1552 if (_smf_refresh_instance_i(entity) == 0) { 1553 if (g_verbose) 1554 warn(gettext("Refreshed %s.\n"), fmri); 1555 return (0); 1556 } 1557 1558 switch (scf_error()) { 1559 case SCF_ERROR_BACKEND_ACCESS: 1560 return (EACCES); 1561 1562 case SCF_ERROR_PERMISSION_DENIED: 1563 return (EPERM); 1564 1565 default: 1566 return (-1); 1567 } 1568 } else { 1569 r = refresh_running_snapshot(entity); 1570 switch (r) { 1571 case 0: 1572 break; 1573 1574 case ECONNABORTED: 1575 case ECANCELED: 1576 case EPERM: 1577 case ENOSPC: 1578 break; 1579 1580 default: 1581 bad_error("refresh_running_snapshot", 1582 scf_error()); 1583 } 1584 1585 return (r); 1586 } 1587 } 1588 1589 if (scf_iter_service_instances(iter, entity) != 0) { 1590 switch (scf_error()) { 1591 case SCF_ERROR_CONNECTION_BROKEN: 1592 return (ECONNABORTED); 1593 1594 case SCF_ERROR_DELETED: 1595 return (ECANCELED); 1596 1597 case SCF_ERROR_HANDLE_MISMATCH: 1598 case SCF_ERROR_NOT_BOUND: 1599 case SCF_ERROR_NOT_SET: 1600 default: 1601 bad_error("scf_iter_service_instances", scf_error()); 1602 } 1603 } 1604 1605 for (;;) { 1606 r = scf_iter_next_instance(iter, inst); 1607 if (r == 0) 1608 break; 1609 if (r != 1) { 1610 switch (scf_error()) { 1611 case SCF_ERROR_CONNECTION_BROKEN: 1612 return (ECONNABORTED); 1613 1614 case SCF_ERROR_DELETED: 1615 return (ECANCELED); 1616 1617 case SCF_ERROR_HANDLE_MISMATCH: 1618 case SCF_ERROR_NOT_BOUND: 1619 case SCF_ERROR_NOT_SET: 1620 case SCF_ERROR_INVALID_ARGUMENT: 1621 default: 1622 bad_error("scf_iter_next_instance", 1623 scf_error()); 1624 } 1625 } 1626 1627 /* 1628 * Similarly, just take a new running snapshot if operating on 1629 * a non-live repository or running during early import. 1630 */ 1631 if (est->sc_repo_filename != NULL || 1632 est->sc_repo_doorname != NULL || 1633 est->sc_in_emi == 1) { 1634 r = refresh_running_snapshot(inst); 1635 switch (r) { 1636 case 0: 1637 continue; 1638 1639 case ECONNABORTED: 1640 case ECANCELED: 1641 case EPERM: 1642 case ENOSPC: 1643 break; 1644 default: 1645 bad_error("refresh_running_snapshot", 1646 scf_error()); 1647 } 1648 1649 return (r); 1650 1651 } 1652 1653 if (_smf_refresh_instance_i(inst) == 0) { 1654 if (g_verbose) { 1655 if (scf_instance_get_name(inst, name_buf, 1656 max_scf_name_len + 1) < 0) 1657 (void) strcpy(name_buf, "?"); 1658 1659 warn(gettext("Refreshed %s:%s.\n"), 1660 fmri, name_buf); 1661 } 1662 } else { 1663 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1664 g_verbose) { 1665 scfe = scf_error(); 1666 1667 if (scf_instance_to_fmri(inst, name_buf, 1668 max_scf_name_len + 1) < 0) 1669 (void) strcpy(name_buf, "?"); 1670 1671 warn(gettext( 1672 "Refresh of %s:%s failed: %s.\n"), fmri, 1673 name_buf, scf_strerror(scfe)); 1674 } 1675 } 1676 } 1677 1678 return (0); 1679 } 1680 1681 static void 1682 private_refresh(void) 1683 { 1684 scf_instance_t *pinst = NULL; 1685 scf_iter_t *piter = NULL; 1686 ssize_t fmrilen; 1687 size_t bufsz; 1688 char *fmribuf; 1689 void *ent; 1690 int issvc; 1691 int r; 1692 1693 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1694 return; 1695 1696 assert(cur_svc != NULL); 1697 1698 bufsz = max_scf_fmri_len + 1; 1699 fmribuf = safe_malloc(bufsz); 1700 if (cur_inst) { 1701 issvc = 0; 1702 ent = cur_inst; 1703 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1704 } else { 1705 issvc = 1; 1706 ent = cur_svc; 1707 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1708 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1709 scfdie(); 1710 1711 if ((piter = scf_iter_create(g_hndl)) == NULL) 1712 scfdie(); 1713 } 1714 if (fmrilen < 0) { 1715 free(fmribuf); 1716 if (scf_error() != SCF_ERROR_DELETED) 1717 scfdie(); 1718 1719 warn(emsg_deleted); 1720 return; 1721 } 1722 assert(fmrilen < bufsz); 1723 1724 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1725 switch (r) { 1726 case 0: 1727 break; 1728 1729 case ECONNABORTED: 1730 warn(gettext("Could not refresh %s " 1731 "(repository connection broken).\n"), fmribuf); 1732 break; 1733 1734 case ECANCELED: 1735 warn(emsg_deleted); 1736 break; 1737 1738 case EPERM: 1739 warn(gettext("Could not refresh %s " 1740 "(permission denied).\n"), fmribuf); 1741 break; 1742 1743 case ENOSPC: 1744 warn(gettext("Could not refresh %s " 1745 "(repository server out of resources).\n"), 1746 fmribuf); 1747 break; 1748 1749 case EACCES: 1750 default: 1751 bad_error("refresh_entity", scf_error()); 1752 } 1753 1754 if (issvc) { 1755 scf_instance_destroy(pinst); 1756 scf_iter_destroy(piter); 1757 } 1758 1759 free(fmribuf); 1760 } 1761 1762 1763 static int 1764 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1765 { 1766 cbp->sc_err = scferror2errno(err); 1767 return (UU_WALK_ERROR); 1768 } 1769 1770 static int 1771 stash_scferror(scf_callback_t *cbp) 1772 { 1773 return (stash_scferror_err(cbp, scf_error())); 1774 } 1775 1776 /* 1777 * Import. These functions import a bundle into the repository. 1778 */ 1779 1780 /* 1781 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 1782 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 1783 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 1784 * lcbdata->sc_err to 1785 * ENOMEM - out of memory 1786 * ECONNABORTED - repository connection broken 1787 * ECANCELED - sc_trans's property group was deleted 1788 * EINVAL - p's name is invalid (error printed) 1789 * - p has an invalid value (error printed) 1790 */ 1791 static int 1792 lscf_property_import(void *v, void *pvt) 1793 { 1794 property_t *p = v; 1795 scf_callback_t *lcbdata = pvt; 1796 value_t *vp; 1797 scf_transaction_t *trans = lcbdata->sc_trans; 1798 scf_transaction_entry_t *entr; 1799 scf_value_t *val; 1800 scf_type_t tp; 1801 1802 if ((lcbdata->sc_flags & SCI_NOENABLED || 1803 lcbdata->sc_flags & SCI_DELAYENABLE) && 1804 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 1805 lcbdata->sc_enable = p; 1806 return (UU_WALK_NEXT); 1807 } 1808 1809 entr = scf_entry_create(lcbdata->sc_handle); 1810 if (entr == NULL) { 1811 switch (scf_error()) { 1812 case SCF_ERROR_NO_MEMORY: 1813 return (stash_scferror(lcbdata)); 1814 1815 case SCF_ERROR_INVALID_ARGUMENT: 1816 default: 1817 bad_error("scf_entry_create", scf_error()); 1818 } 1819 } 1820 1821 tp = p->sc_value_type; 1822 1823 if (scf_transaction_property_new(trans, entr, 1824 p->sc_property_name, tp) != 0) { 1825 switch (scf_error()) { 1826 case SCF_ERROR_INVALID_ARGUMENT: 1827 semerr(emsg_invalid_prop_name, p->sc_property_name); 1828 scf_entry_destroy(entr); 1829 return (stash_scferror(lcbdata)); 1830 1831 case SCF_ERROR_EXISTS: 1832 break; 1833 1834 case SCF_ERROR_DELETED: 1835 case SCF_ERROR_CONNECTION_BROKEN: 1836 scf_entry_destroy(entr); 1837 return (stash_scferror(lcbdata)); 1838 1839 case SCF_ERROR_NOT_BOUND: 1840 case SCF_ERROR_HANDLE_MISMATCH: 1841 case SCF_ERROR_NOT_SET: 1842 default: 1843 bad_error("scf_transaction_property_new", scf_error()); 1844 } 1845 1846 if (scf_transaction_property_change_type(trans, entr, 1847 p->sc_property_name, tp) != 0) { 1848 switch (scf_error()) { 1849 case SCF_ERROR_DELETED: 1850 case SCF_ERROR_CONNECTION_BROKEN: 1851 scf_entry_destroy(entr); 1852 return (stash_scferror(lcbdata)); 1853 1854 case SCF_ERROR_INVALID_ARGUMENT: 1855 semerr(emsg_invalid_prop_name, 1856 p->sc_property_name); 1857 scf_entry_destroy(entr); 1858 return (stash_scferror(lcbdata)); 1859 1860 case SCF_ERROR_NOT_FOUND: 1861 case SCF_ERROR_NOT_SET: 1862 case SCF_ERROR_HANDLE_MISMATCH: 1863 case SCF_ERROR_NOT_BOUND: 1864 default: 1865 bad_error( 1866 "scf_transaction_property_change_type", 1867 scf_error()); 1868 } 1869 } 1870 } 1871 1872 for (vp = uu_list_first(p->sc_property_values); 1873 vp != NULL; 1874 vp = uu_list_next(p->sc_property_values, vp)) { 1875 val = scf_value_create(g_hndl); 1876 if (val == NULL) { 1877 switch (scf_error()) { 1878 case SCF_ERROR_NO_MEMORY: 1879 return (stash_scferror(lcbdata)); 1880 1881 case SCF_ERROR_INVALID_ARGUMENT: 1882 default: 1883 bad_error("scf_value_create", scf_error()); 1884 } 1885 } 1886 1887 switch (tp) { 1888 case SCF_TYPE_BOOLEAN: 1889 scf_value_set_boolean(val, vp->sc_u.sc_count); 1890 break; 1891 case SCF_TYPE_COUNT: 1892 scf_value_set_count(val, vp->sc_u.sc_count); 1893 break; 1894 case SCF_TYPE_INTEGER: 1895 scf_value_set_integer(val, vp->sc_u.sc_integer); 1896 break; 1897 default: 1898 assert(vp->sc_u.sc_string != NULL); 1899 if (scf_value_set_from_string(val, tp, 1900 vp->sc_u.sc_string) != 0) { 1901 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 1902 bad_error("scf_value_set_from_string", 1903 scf_error()); 1904 1905 warn(gettext("Value \"%s\" is not a valid " 1906 "%s.\n"), vp->sc_u.sc_string, 1907 scf_type_to_string(tp)); 1908 scf_value_destroy(val); 1909 return (stash_scferror(lcbdata)); 1910 } 1911 break; 1912 } 1913 1914 if (scf_entry_add_value(entr, val) != 0) 1915 bad_error("scf_entry_add_value", scf_error()); 1916 } 1917 1918 return (UU_WALK_NEXT); 1919 } 1920 1921 /* 1922 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 1923 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 1924 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 1925 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 1926 * lcbdata->sc_err to 1927 * ECONNABORTED - repository connection broken 1928 * ENOMEM - out of memory 1929 * ENOSPC - svc.configd is out of resources 1930 * ECANCELED - sc_parent was deleted 1931 * EPERM - could not create property group (permission denied) (error printed) 1932 * - could not modify property group (permission denied) (error printed) 1933 * - could not delete property group (permission denied) (error printed) 1934 * EROFS - could not create property group (repository is read-only) 1935 * - could not delete property group (repository is read-only) 1936 * EACCES - could not create property group (backend access denied) 1937 * - could not delete property group (backend access denied) 1938 * EEXIST - could not create property group (already exists) 1939 * EINVAL - invalid property group name (error printed) 1940 * - invalid property name (error printed) 1941 * - invalid value (error printed) 1942 * EBUSY - new property group deleted (error printed) 1943 * - new property group changed (error printed) 1944 * - property group added (error printed) 1945 * - property group deleted (error printed) 1946 */ 1947 static int 1948 entity_pgroup_import(void *v, void *pvt) 1949 { 1950 pgroup_t *p = v; 1951 scf_callback_t cbdata; 1952 scf_callback_t *lcbdata = pvt; 1953 void *ent = lcbdata->sc_parent; 1954 int issvc = lcbdata->sc_service; 1955 int r; 1956 1957 const char * const pg_changed = gettext("%s changed unexpectedly " 1958 "(new property group \"%s\" changed).\n"); 1959 1960 /* Never import deleted property groups. */ 1961 if (p->sc_pgroup_delete) 1962 return (UU_WALK_NEXT); 1963 1964 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 1965 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 1966 lcbdata->sc_general = p; 1967 return (UU_WALK_NEXT); 1968 } 1969 1970 add_pg: 1971 if (issvc) 1972 r = scf_service_add_pg(ent, p->sc_pgroup_name, 1973 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 1974 else 1975 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 1976 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 1977 if (r != 0) { 1978 switch (scf_error()) { 1979 case SCF_ERROR_DELETED: 1980 case SCF_ERROR_CONNECTION_BROKEN: 1981 case SCF_ERROR_BACKEND_READONLY: 1982 case SCF_ERROR_BACKEND_ACCESS: 1983 case SCF_ERROR_NO_RESOURCES: 1984 return (stash_scferror(lcbdata)); 1985 1986 case SCF_ERROR_EXISTS: 1987 if (lcbdata->sc_flags & SCI_FORCE) 1988 break; 1989 return (stash_scferror(lcbdata)); 1990 1991 case SCF_ERROR_INVALID_ARGUMENT: 1992 warn(emsg_fmri_invalid_pg_name_type, 1993 lcbdata->sc_source_fmri, 1994 p->sc_pgroup_name, p->sc_pgroup_type); 1995 return (stash_scferror(lcbdata)); 1996 1997 case SCF_ERROR_PERMISSION_DENIED: 1998 warn(emsg_pg_add_perm, p->sc_pgroup_name, 1999 lcbdata->sc_target_fmri); 2000 return (stash_scferror(lcbdata)); 2001 2002 case SCF_ERROR_NOT_BOUND: 2003 case SCF_ERROR_HANDLE_MISMATCH: 2004 case SCF_ERROR_NOT_SET: 2005 default: 2006 bad_error("scf_service_add_pg", scf_error()); 2007 } 2008 2009 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 2010 switch (scf_error()) { 2011 case SCF_ERROR_CONNECTION_BROKEN: 2012 case SCF_ERROR_DELETED: 2013 return (stash_scferror(lcbdata)); 2014 2015 case SCF_ERROR_INVALID_ARGUMENT: 2016 warn(emsg_fmri_invalid_pg_name, 2017 lcbdata->sc_source_fmri, 2018 p->sc_pgroup_name); 2019 return (stash_scferror(lcbdata)); 2020 2021 case SCF_ERROR_NOT_FOUND: 2022 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2023 p->sc_pgroup_name); 2024 lcbdata->sc_err = EBUSY; 2025 return (UU_WALK_ERROR); 2026 2027 case SCF_ERROR_NOT_BOUND: 2028 case SCF_ERROR_HANDLE_MISMATCH: 2029 case SCF_ERROR_NOT_SET: 2030 default: 2031 bad_error("entity_get_pg", scf_error()); 2032 } 2033 } 2034 2035 if (lcbdata->sc_flags & SCI_KEEP) 2036 goto props; 2037 2038 if (scf_pg_delete(imp_pg) != 0) { 2039 switch (scf_error()) { 2040 case SCF_ERROR_DELETED: 2041 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2042 p->sc_pgroup_name); 2043 lcbdata->sc_err = EBUSY; 2044 return (UU_WALK_ERROR); 2045 2046 case SCF_ERROR_PERMISSION_DENIED: 2047 warn(emsg_pg_del_perm, p->sc_pgroup_name, 2048 lcbdata->sc_target_fmri); 2049 return (stash_scferror(lcbdata)); 2050 2051 case SCF_ERROR_BACKEND_READONLY: 2052 case SCF_ERROR_BACKEND_ACCESS: 2053 case SCF_ERROR_CONNECTION_BROKEN: 2054 return (stash_scferror(lcbdata)); 2055 2056 case SCF_ERROR_NOT_SET: 2057 default: 2058 bad_error("scf_pg_delete", scf_error()); 2059 } 2060 } 2061 2062 goto add_pg; 2063 } 2064 2065 props: 2066 2067 /* 2068 * Add properties to property group, if any. 2069 */ 2070 cbdata.sc_handle = lcbdata->sc_handle; 2071 cbdata.sc_parent = imp_pg; 2072 cbdata.sc_flags = lcbdata->sc_flags; 2073 cbdata.sc_trans = imp_tx; 2074 cbdata.sc_enable = NULL; 2075 2076 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2077 switch (scf_error()) { 2078 case SCF_ERROR_BACKEND_ACCESS: 2079 case SCF_ERROR_BACKEND_READONLY: 2080 case SCF_ERROR_CONNECTION_BROKEN: 2081 return (stash_scferror(lcbdata)); 2082 2083 case SCF_ERROR_DELETED: 2084 warn(pg_changed, lcbdata->sc_target_fmri, 2085 p->sc_pgroup_name); 2086 lcbdata->sc_err = EBUSY; 2087 return (UU_WALK_ERROR); 2088 2089 case SCF_ERROR_PERMISSION_DENIED: 2090 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2091 lcbdata->sc_target_fmri); 2092 return (stash_scferror(lcbdata)); 2093 2094 case SCF_ERROR_NOT_BOUND: 2095 case SCF_ERROR_NOT_SET: 2096 case SCF_ERROR_IN_USE: 2097 case SCF_ERROR_HANDLE_MISMATCH: 2098 default: 2099 bad_error("scf_transaction_start", scf_error()); 2100 } 2101 } 2102 2103 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2104 UU_DEFAULT) != 0) { 2105 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2106 bad_error("uu_list_walk", uu_error()); 2107 scf_transaction_reset(imp_tx); 2108 2109 lcbdata->sc_err = cbdata.sc_err; 2110 if (cbdata.sc_err == ECANCELED) { 2111 warn(pg_changed, lcbdata->sc_target_fmri, 2112 p->sc_pgroup_name); 2113 lcbdata->sc_err = EBUSY; 2114 } 2115 return (UU_WALK_ERROR); 2116 } 2117 2118 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2119 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2120 2121 /* 2122 * take the snapshot running snapshot then 2123 * import the stored general/enable property 2124 */ 2125 r = take_snap(ent, snap_running, imp_rsnap); 2126 switch (r) { 2127 case 0: 2128 break; 2129 2130 case ECONNABORTED: 2131 warn(gettext("Could not take %s snapshot on import " 2132 "(repository connection broken).\n"), 2133 snap_running); 2134 lcbdata->sc_err = r; 2135 return (UU_WALK_ERROR); 2136 case ECANCELED: 2137 warn(emsg_deleted); 2138 lcbdata->sc_err = r; 2139 return (UU_WALK_ERROR); 2140 2141 case EPERM: 2142 warn(gettext("Could not take %s snapshot " 2143 "(permission denied).\n"), snap_running); 2144 lcbdata->sc_err = r; 2145 return (UU_WALK_ERROR); 2146 2147 case ENOSPC: 2148 warn(gettext("Could not take %s snapshot" 2149 "(repository server out of resources).\n"), 2150 snap_running); 2151 lcbdata->sc_err = r; 2152 return (UU_WALK_ERROR); 2153 2154 default: 2155 bad_error("take_snap", r); 2156 } 2157 2158 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2159 if (r != UU_WALK_NEXT) { 2160 if (r != UU_WALK_ERROR) 2161 bad_error("lscf_property_import", r); 2162 return (EINVAL); 2163 } 2164 } 2165 2166 r = scf_transaction_commit(imp_tx); 2167 switch (r) { 2168 case 1: 2169 r = UU_WALK_NEXT; 2170 break; 2171 2172 case 0: 2173 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2174 lcbdata->sc_err = EBUSY; 2175 r = UU_WALK_ERROR; 2176 break; 2177 2178 case -1: 2179 switch (scf_error()) { 2180 case SCF_ERROR_BACKEND_READONLY: 2181 case SCF_ERROR_BACKEND_ACCESS: 2182 case SCF_ERROR_CONNECTION_BROKEN: 2183 case SCF_ERROR_NO_RESOURCES: 2184 r = stash_scferror(lcbdata); 2185 break; 2186 2187 case SCF_ERROR_DELETED: 2188 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2189 p->sc_pgroup_name); 2190 lcbdata->sc_err = EBUSY; 2191 r = UU_WALK_ERROR; 2192 break; 2193 2194 case SCF_ERROR_PERMISSION_DENIED: 2195 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2196 lcbdata->sc_target_fmri); 2197 r = stash_scferror(lcbdata); 2198 break; 2199 2200 case SCF_ERROR_NOT_SET: 2201 case SCF_ERROR_INVALID_ARGUMENT: 2202 case SCF_ERROR_NOT_BOUND: 2203 default: 2204 bad_error("scf_transaction_commit", scf_error()); 2205 } 2206 break; 2207 2208 default: 2209 bad_error("scf_transaction_commit", r); 2210 } 2211 2212 scf_transaction_destroy_children(imp_tx); 2213 2214 return (r); 2215 } 2216 2217 /* 2218 * Returns 2219 * 0 - success 2220 * ECONNABORTED - repository connection broken 2221 * ENOMEM - out of memory 2222 * ENOSPC - svc.configd is out of resources 2223 * ECANCELED - inst was deleted 2224 * EPERM - could not create property group (permission denied) (error printed) 2225 * - could not modify property group (permission denied) (error printed) 2226 * EROFS - could not create property group (repository is read-only) 2227 * EACCES - could not create property group (backend access denied) 2228 * EEXIST - could not create property group (already exists) 2229 * EINVAL - invalid property group name (error printed) 2230 * - invalid property name (error printed) 2231 * - invalid value (error printed) 2232 * EBUSY - new property group changed (error printed) 2233 */ 2234 static int 2235 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2236 const entity_t *isvc, int flags) 2237 { 2238 scf_callback_t cbdata; 2239 2240 cbdata.sc_handle = scf_service_handle(svc); 2241 cbdata.sc_parent = svc; 2242 cbdata.sc_service = 1; 2243 cbdata.sc_general = 0; 2244 cbdata.sc_enable = 0; 2245 cbdata.sc_flags = flags; 2246 cbdata.sc_source_fmri = isvc->sc_fmri; 2247 cbdata.sc_target_fmri = target_fmri; 2248 2249 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2250 UU_DEFAULT) != 0) { 2251 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2252 bad_error("uu_list_walk", uu_error()); 2253 2254 return (cbdata.sc_err); 2255 } 2256 2257 return (0); 2258 } 2259 2260 /* 2261 * Returns 2262 * 0 - success 2263 * ECONNABORTED - repository connection broken 2264 * ENOMEM - out of memory 2265 * ENOSPC - svc.configd is out of resources 2266 * ECANCELED - inst was deleted 2267 * EPERM - could not create property group (permission denied) (error printed) 2268 * - could not modify property group (permission denied) (error printed) 2269 * EROFS - could not create property group (repository is read-only) 2270 * EACCES - could not create property group (backend access denied) 2271 * EEXIST - could not create property group (already exists) 2272 * EINVAL - invalid property group name (error printed) 2273 * - invalid property name (error printed) 2274 * - invalid value (error printed) 2275 * EBUSY - new property group changed (error printed) 2276 */ 2277 static int 2278 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2279 const entity_t *iinst, int flags) 2280 { 2281 scf_callback_t cbdata; 2282 2283 cbdata.sc_handle = scf_instance_handle(inst); 2284 cbdata.sc_parent = inst; 2285 cbdata.sc_service = 0; 2286 cbdata.sc_general = NULL; 2287 cbdata.sc_enable = NULL; 2288 cbdata.sc_flags = flags; 2289 cbdata.sc_source_fmri = iinst->sc_fmri; 2290 cbdata.sc_target_fmri = target_fmri; 2291 2292 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2293 UU_DEFAULT) != 0) { 2294 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2295 bad_error("uu_list_walk", uu_error()); 2296 2297 return (cbdata.sc_err); 2298 } 2299 2300 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2301 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2302 /* 2303 * If importing with the SCI_NOENABLED flag then 2304 * skip the delay, but if not then add the delay 2305 * of the enable property. 2306 */ 2307 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2308 cbdata.sc_flags |= SCI_DELAYENABLE; 2309 } 2310 2311 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2312 != UU_WALK_NEXT) 2313 return (cbdata.sc_err); 2314 } 2315 2316 return (0); 2317 } 2318 2319 /* 2320 * Report the reasons why we can't upgrade pg2 to pg1. 2321 */ 2322 static void 2323 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2324 int new) 2325 { 2326 property_t *p1, *p2; 2327 2328 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2329 2330 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2331 return; 2332 2333 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2334 p1 != NULL; 2335 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2336 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2337 if (p2 != NULL) { 2338 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2339 new); 2340 continue; 2341 } 2342 2343 if (new) 2344 warn(gettext("Conflict upgrading %s (new property " 2345 "group \"%s\" is missing property \"%s\").\n"), 2346 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2347 else 2348 warn(gettext("Conflict upgrading %s (property " 2349 "\"%s/%s\" is missing).\n"), fmri, 2350 pg1->sc_pgroup_name, p1->sc_property_name); 2351 } 2352 2353 /* 2354 * Since pg1 should be from the manifest, any properties in pg2 which 2355 * aren't in pg1 shouldn't be reported as conflicts. 2356 */ 2357 } 2358 2359 /* 2360 * Add transaction entries to tx which will upgrade cur's pg according to old 2361 * & new. 2362 * 2363 * Returns 2364 * 0 - success 2365 * EINVAL - new has a property with an invalid name or value (message emitted) 2366 * ENOMEM - out of memory 2367 */ 2368 static int 2369 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2370 pgroup_t *cur, int speak, const char *fmri) 2371 { 2372 property_t *p, *new_p, *cur_p; 2373 scf_transaction_entry_t *e; 2374 int r; 2375 int is_general; 2376 int is_protected; 2377 2378 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2379 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2380 bad_error("uu_list_walk", uu_error()); 2381 2382 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2383 2384 for (p = uu_list_first(old->sc_pgroup_props); 2385 p != NULL; 2386 p = uu_list_next(old->sc_pgroup_props, p)) { 2387 /* p is a property in the old property group. */ 2388 2389 /* Protect live properties. */ 2390 is_protected = 0; 2391 if (is_general) { 2392 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2393 0 || 2394 strcmp(p->sc_property_name, 2395 SCF_PROPERTY_RESTARTER) == 0) 2396 is_protected = 1; 2397 } 2398 2399 /* Look for the same property in the new properties. */ 2400 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2401 if (new_p != NULL) { 2402 new_p->sc_seen = 1; 2403 2404 /* 2405 * If the new property is the same as the old, don't do 2406 * anything (leave any user customizations). 2407 */ 2408 if (prop_equal(p, new_p, NULL, NULL, 0)) 2409 continue; 2410 2411 if (new_p->sc_property_override) 2412 goto upgrade; 2413 } 2414 2415 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2416 if (cur_p == NULL) { 2417 /* 2418 * p has been deleted from the repository. If we were 2419 * going to delete it anyway, do nothing. Otherwise 2420 * report a conflict. 2421 */ 2422 if (new_p == NULL) 2423 continue; 2424 2425 if (is_protected) 2426 continue; 2427 2428 warn(gettext("Conflict upgrading %s " 2429 "(property \"%s/%s\" is missing).\n"), fmri, 2430 old->sc_pgroup_name, p->sc_property_name); 2431 continue; 2432 } 2433 2434 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2435 /* 2436 * Conflict. Don't warn if the property is already the 2437 * way we want it, though. 2438 */ 2439 if (is_protected) 2440 continue; 2441 2442 if (new_p == NULL) 2443 (void) prop_equal(p, cur_p, fmri, 2444 old->sc_pgroup_name, 0); 2445 else 2446 (void) prop_equal(cur_p, new_p, fmri, 2447 old->sc_pgroup_name, 0); 2448 continue; 2449 } 2450 2451 if (is_protected) { 2452 if (speak) 2453 warn(gettext("%s: Refusing to upgrade " 2454 "\"%s/%s\" (live property).\n"), fmri, 2455 old->sc_pgroup_name, p->sc_property_name); 2456 continue; 2457 } 2458 2459 upgrade: 2460 /* p hasn't been customized in the repository. Upgrade it. */ 2461 if (new_p == NULL) { 2462 /* p was deleted. Delete from cur if unchanged. */ 2463 if (speak) 2464 warn(gettext( 2465 "%s: Deleting property \"%s/%s\".\n"), 2466 fmri, old->sc_pgroup_name, 2467 p->sc_property_name); 2468 2469 e = scf_entry_create(g_hndl); 2470 if (e == NULL) 2471 return (ENOMEM); 2472 2473 if (scf_transaction_property_delete(tx, e, 2474 p->sc_property_name) != 0) { 2475 switch (scf_error()) { 2476 case SCF_ERROR_DELETED: 2477 scf_entry_destroy(e); 2478 return (ECANCELED); 2479 2480 case SCF_ERROR_CONNECTION_BROKEN: 2481 scf_entry_destroy(e); 2482 return (ECONNABORTED); 2483 2484 case SCF_ERROR_NOT_FOUND: 2485 /* 2486 * This can happen if cur is from the 2487 * running snapshot (and it differs 2488 * from the live properties). 2489 */ 2490 scf_entry_destroy(e); 2491 break; 2492 2493 case SCF_ERROR_HANDLE_MISMATCH: 2494 case SCF_ERROR_NOT_BOUND: 2495 case SCF_ERROR_NOT_SET: 2496 case SCF_ERROR_INVALID_ARGUMENT: 2497 default: 2498 bad_error( 2499 "scf_transaction_property_delete", 2500 scf_error()); 2501 } 2502 } 2503 } else { 2504 scf_callback_t ctx; 2505 2506 if (speak) 2507 warn(gettext( 2508 "%s: Upgrading property \"%s/%s\".\n"), 2509 fmri, old->sc_pgroup_name, 2510 p->sc_property_name); 2511 2512 ctx.sc_handle = g_hndl; 2513 ctx.sc_trans = tx; 2514 ctx.sc_flags = 0; 2515 2516 r = lscf_property_import(new_p, &ctx); 2517 if (r != UU_WALK_NEXT) { 2518 if (r != UU_WALK_ERROR) 2519 bad_error("lscf_property_import", r); 2520 return (EINVAL); 2521 } 2522 } 2523 } 2524 2525 /* Go over the properties which were added. */ 2526 for (new_p = uu_list_first(new->sc_pgroup_props); 2527 new_p != NULL; 2528 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 2529 if (new_p->sc_seen) 2530 continue; 2531 2532 /* This is a new property. */ 2533 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 2534 if (cur_p == NULL) { 2535 scf_callback_t ctx; 2536 2537 ctx.sc_handle = g_hndl; 2538 ctx.sc_trans = tx; 2539 ctx.sc_flags = 0; 2540 2541 r = lscf_property_import(new_p, &ctx); 2542 if (r != UU_WALK_NEXT) { 2543 if (r != UU_WALK_ERROR) 2544 bad_error("lscf_property_import", r); 2545 return (EINVAL); 2546 } 2547 continue; 2548 } 2549 2550 /* 2551 * Report a conflict if the new property differs from the 2552 * current one. Unless it's general/enabled, since that's 2553 * never in the last-import snapshot. 2554 */ 2555 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 2556 0 && 2557 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 2558 continue; 2559 2560 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 2561 } 2562 2563 return (0); 2564 } 2565 2566 /* 2567 * Upgrade pg according to old & new. 2568 * 2569 * Returns 2570 * 0 - success 2571 * ECONNABORTED - repository connection broken 2572 * ENOMEM - out of memory 2573 * ENOSPC - svc.configd is out of resources 2574 * ECANCELED - pg was deleted 2575 * EPERM - couldn't modify pg (permission denied) 2576 * EROFS - couldn't modify pg (backend read-only) 2577 * EACCES - couldn't modify pg (backend access denied) 2578 * EINVAL - new has a property with invalid name or value (error printed) 2579 * EBUSY - pg changed unexpectedly 2580 */ 2581 static int 2582 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 2583 pgroup_t *new, int speak, const char *fmri) 2584 { 2585 int r; 2586 2587 if (scf_transaction_start(imp_tx, pg) != 0) { 2588 switch (scf_error()) { 2589 case SCF_ERROR_CONNECTION_BROKEN: 2590 case SCF_ERROR_DELETED: 2591 case SCF_ERROR_PERMISSION_DENIED: 2592 case SCF_ERROR_BACKEND_READONLY: 2593 case SCF_ERROR_BACKEND_ACCESS: 2594 return (scferror2errno(scf_error())); 2595 2596 case SCF_ERROR_HANDLE_MISMATCH: 2597 case SCF_ERROR_IN_USE: 2598 case SCF_ERROR_NOT_BOUND: 2599 case SCF_ERROR_NOT_SET: 2600 default: 2601 bad_error("scf_transaction_start", scf_error()); 2602 } 2603 } 2604 2605 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 2606 switch (r) { 2607 case 0: 2608 break; 2609 2610 case EINVAL: 2611 case ENOMEM: 2612 scf_transaction_destroy_children(imp_tx); 2613 return (r); 2614 2615 default: 2616 bad_error("add_upgrade_entries", r); 2617 } 2618 2619 r = scf_transaction_commit(imp_tx); 2620 2621 scf_transaction_destroy_children(imp_tx); 2622 2623 switch (r) { 2624 case 1: 2625 break; 2626 2627 case 0: 2628 return (EBUSY); 2629 2630 case -1: 2631 switch (scf_error()) { 2632 case SCF_ERROR_CONNECTION_BROKEN: 2633 case SCF_ERROR_NO_RESOURCES: 2634 case SCF_ERROR_PERMISSION_DENIED: 2635 case SCF_ERROR_BACKEND_READONLY: 2636 case SCF_ERROR_BACKEND_ACCESS: 2637 case SCF_ERROR_DELETED: 2638 return (scferror2errno(scf_error())); 2639 2640 case SCF_ERROR_NOT_BOUND: 2641 case SCF_ERROR_INVALID_ARGUMENT: 2642 case SCF_ERROR_NOT_SET: 2643 default: 2644 bad_error("scf_transaction_commit", scf_error()); 2645 } 2646 2647 default: 2648 bad_error("scf_transaction_commit", r); 2649 } 2650 2651 return (0); 2652 } 2653 2654 /* 2655 * Compares two entity FMRIs. Returns 2656 * 2657 * 1 - equal 2658 * 0 - not equal 2659 * -1 - f1 is invalid or not an entity 2660 * -2 - f2 is invalid or not an entity 2661 */ 2662 static int 2663 fmri_equal(const char *f1, const char *f2) 2664 { 2665 int r; 2666 const char *s1, *i1, *pg1; 2667 const char *s2, *i2, *pg2; 2668 2669 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 2670 return (-1); 2671 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 2672 return (-1); 2673 2674 if (s1 == NULL || pg1 != NULL) 2675 return (-1); 2676 2677 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 2678 return (-2); 2679 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 2680 return (-2); 2681 2682 if (s2 == NULL || pg2 != NULL) 2683 return (-2); 2684 2685 r = strcmp(s1, s2); 2686 if (r != 0) 2687 return (0); 2688 2689 if (i1 == NULL && i2 == NULL) 2690 return (1); 2691 2692 if (i1 == NULL || i2 == NULL) 2693 return (0); 2694 2695 return (strcmp(i1, i2) == 0); 2696 } 2697 2698 /* 2699 * Import a dependent by creating a dependency property group in the dependent 2700 * entity. If lcbdata->sc_trans is set, assume it's been started on the 2701 * dependents pg, and add an entry to create a new property for this 2702 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 2703 * 2704 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 2705 * lcbdata->sc_err to 2706 * ECONNABORTED - repository connection broken 2707 * ENOMEM - out of memory 2708 * ENOSPC - configd is out of resources 2709 * EINVAL - target is invalid (error printed) 2710 * - target is not an entity (error printed) 2711 * - dependent has invalid name (error printed) 2712 * - invalid property name (error printed) 2713 * - invalid value (error printed) 2714 * - scope of target does not exist (error printed) 2715 * EPERM - couldn't create target (permission denied) (error printed) 2716 * - couldn't create dependency pg (permission denied) (error printed) 2717 * - couldn't modify dependency pg (permission denied) (error printed) 2718 * EROFS - couldn't create target (repository read-only) 2719 * - couldn't create dependency pg (repository read-only) 2720 * EACCES - couldn't create target (backend access denied) 2721 * - couldn't create dependency pg (backend access denied) 2722 * ECANCELED - sc_trans's pg was deleted 2723 * EALREADY - property for dependent already exists in sc_trans's pg 2724 * EEXIST - dependency pg already exists in target (error printed) 2725 * EBUSY - target deleted (error printed) 2726 * - property group changed during import (error printed) 2727 */ 2728 static int 2729 lscf_dependent_import(void *a1, void *pvt) 2730 { 2731 pgroup_t *pgrp = a1; 2732 scf_callback_t *lcbdata = pvt; 2733 2734 int isservice; 2735 int ret; 2736 scf_transaction_entry_t *e; 2737 scf_value_t *val; 2738 scf_callback_t dependent_cbdata; 2739 scf_error_t scfe; 2740 2741 /* 2742 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 2743 * it's invalid, we fail before modifying the repository. 2744 */ 2745 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 2746 &dependent_cbdata.sc_parent, &isservice); 2747 switch (scfe) { 2748 case SCF_ERROR_NONE: 2749 break; 2750 2751 case SCF_ERROR_NO_MEMORY: 2752 return (stash_scferror_err(lcbdata, scfe)); 2753 2754 case SCF_ERROR_INVALID_ARGUMENT: 2755 semerr(gettext("The FMRI for the \"%s\" dependent is " 2756 "invalid.\n"), pgrp->sc_pgroup_name); 2757 return (stash_scferror_err(lcbdata, scfe)); 2758 2759 case SCF_ERROR_CONSTRAINT_VIOLATED: 2760 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 2761 "specifies neither a service nor an instance.\n"), 2762 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 2763 return (stash_scferror_err(lcbdata, scfe)); 2764 2765 case SCF_ERROR_NOT_FOUND: 2766 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 2767 &dependent_cbdata.sc_parent, &isservice); 2768 switch (scfe) { 2769 case SCF_ERROR_NONE: 2770 break; 2771 2772 case SCF_ERROR_NO_MEMORY: 2773 case SCF_ERROR_BACKEND_READONLY: 2774 case SCF_ERROR_BACKEND_ACCESS: 2775 return (stash_scferror_err(lcbdata, scfe)); 2776 2777 case SCF_ERROR_NOT_FOUND: 2778 semerr(gettext("The scope in FMRI \"%s\" for the " 2779 "\"%s\" dependent does not exist.\n"), 2780 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 2781 lcbdata->sc_err = EINVAL; 2782 return (UU_WALK_ERROR); 2783 2784 case SCF_ERROR_PERMISSION_DENIED: 2785 warn(gettext( 2786 "Could not create %s (permission denied).\n"), 2787 pgrp->sc_pgroup_fmri); 2788 return (stash_scferror_err(lcbdata, scfe)); 2789 2790 case SCF_ERROR_INVALID_ARGUMENT: 2791 case SCF_ERROR_CONSTRAINT_VIOLATED: 2792 default: 2793 bad_error("create_entity", scfe); 2794 } 2795 break; 2796 2797 default: 2798 bad_error("fmri_to_entity", scfe); 2799 } 2800 2801 if (lcbdata->sc_trans != NULL) { 2802 e = scf_entry_create(lcbdata->sc_handle); 2803 if (e == NULL) { 2804 if (scf_error() != SCF_ERROR_NO_MEMORY) 2805 bad_error("scf_entry_create", scf_error()); 2806 2807 entity_destroy(dependent_cbdata.sc_parent, isservice); 2808 return (stash_scferror(lcbdata)); 2809 } 2810 2811 if (scf_transaction_property_new(lcbdata->sc_trans, e, 2812 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 2813 switch (scf_error()) { 2814 case SCF_ERROR_INVALID_ARGUMENT: 2815 warn(gettext("Dependent of %s has invalid name " 2816 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 2817 pgrp->sc_pgroup_name); 2818 /* FALLTHROUGH */ 2819 2820 case SCF_ERROR_DELETED: 2821 case SCF_ERROR_CONNECTION_BROKEN: 2822 scf_entry_destroy(e); 2823 entity_destroy(dependent_cbdata.sc_parent, 2824 isservice); 2825 return (stash_scferror(lcbdata)); 2826 2827 case SCF_ERROR_EXISTS: 2828 scf_entry_destroy(e); 2829 entity_destroy(dependent_cbdata.sc_parent, 2830 isservice); 2831 lcbdata->sc_err = EALREADY; 2832 return (UU_WALK_ERROR); 2833 2834 case SCF_ERROR_NOT_BOUND: 2835 case SCF_ERROR_HANDLE_MISMATCH: 2836 case SCF_ERROR_NOT_SET: 2837 default: 2838 bad_error("scf_transaction_property_new", 2839 scf_error()); 2840 } 2841 } 2842 2843 val = scf_value_create(lcbdata->sc_handle); 2844 if (val == NULL) { 2845 if (scf_error() != SCF_ERROR_NO_MEMORY) 2846 bad_error("scf_value_create", scf_error()); 2847 2848 entity_destroy(dependent_cbdata.sc_parent, isservice); 2849 return (stash_scferror(lcbdata)); 2850 } 2851 2852 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 2853 pgrp->sc_pgroup_fmri) != 0) 2854 /* invalid should have been caught above */ 2855 bad_error("scf_value_set_from_string", scf_error()); 2856 2857 if (scf_entry_add_value(e, val) != 0) 2858 bad_error("scf_entry_add_value", scf_error()); 2859 } 2860 2861 /* Add the property group to the target entity. */ 2862 2863 dependent_cbdata.sc_handle = lcbdata->sc_handle; 2864 dependent_cbdata.sc_flags = 0; 2865 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 2866 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 2867 2868 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 2869 2870 entity_destroy(dependent_cbdata.sc_parent, isservice); 2871 2872 if (ret == UU_WALK_NEXT) 2873 return (ret); 2874 2875 if (ret != UU_WALK_ERROR) 2876 bad_error("entity_pgroup_import", ret); 2877 2878 switch (dependent_cbdata.sc_err) { 2879 case ECANCELED: 2880 warn(gettext("%s deleted unexpectedly.\n"), 2881 pgrp->sc_pgroup_fmri); 2882 lcbdata->sc_err = EBUSY; 2883 break; 2884 2885 case EEXIST: 2886 warn(gettext("Could not create \"%s\" dependency in %s " 2887 "(already exists).\n"), pgrp->sc_pgroup_name, 2888 pgrp->sc_pgroup_fmri); 2889 /* FALLTHROUGH */ 2890 2891 default: 2892 lcbdata->sc_err = dependent_cbdata.sc_err; 2893 } 2894 2895 return (UU_WALK_ERROR); 2896 } 2897 2898 static int upgrade_dependent(const scf_property_t *, const entity_t *, 2899 const scf_snaplevel_t *, scf_transaction_t *); 2900 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 2901 const pgroup_t *); 2902 2903 /* 2904 * Upgrade uncustomized dependents of ent to those specified in ient. Read 2905 * the current dependent targets from running (the snaplevel of a running 2906 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 2907 * scf_instance_t * according to ient, otherwise). Draw the ancestral 2908 * dependent targets and dependency properties from li_dpts_pg (the 2909 * "dependents" property group in snpl) and snpl (the snaplevel which 2910 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 2911 * snpl doesn't have a "dependents" property group, and any dependents in ient 2912 * are new. 2913 * 2914 * Returns 2915 * 0 - success 2916 * ECONNABORTED - repository connection broken 2917 * ENOMEM - out of memory 2918 * ENOSPC - configd is out of resources 2919 * ECANCELED - ent was deleted 2920 * ENODEV - the entity containing li_dpts_pg was deleted 2921 * EPERM - could not modify dependents pg (permission denied) (error printed) 2922 * - couldn't upgrade dependent (permission denied) (error printed) 2923 * - couldn't create dependent (permission denied) (error printed) 2924 * EROFS - could not modify dependents pg (repository read-only) 2925 * - couldn't upgrade dependent (repository read-only) 2926 * - couldn't create dependent (repository read-only) 2927 * EACCES - could not modify dependents pg (backend access denied) 2928 * - could not upgrade dependent (backend access denied) 2929 * - could not create dependent (backend access denied) 2930 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 2931 * - dependent target deleted (error printed) 2932 * - dependent pg changed (error printed) 2933 * EINVAL - new dependent is invalid (error printed) 2934 * EBADF - snpl is corrupt (error printed) 2935 * - snpl has corrupt pg (error printed) 2936 * - dependency pg in target is corrupt (error printed) 2937 * - target has corrupt snapshot (error printed) 2938 * EEXIST - dependency pg already existed in target service (error printed) 2939 */ 2940 static int 2941 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 2942 const scf_snaplevel_t *snpl, const entity_t *ient, 2943 const scf_snaplevel_t *running, void *ent) 2944 { 2945 pgroup_t *new_dpt_pgroup; 2946 scf_callback_t cbdata; 2947 int r, unseen, tx_started = 0; 2948 int have_cur_depts; 2949 2950 const char * const dependents = "dependents"; 2951 2952 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 2953 2954 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 2955 /* Nothing to do. */ 2956 return (0); 2957 2958 /* Fetch the current version of the "dependents" property group. */ 2959 have_cur_depts = 1; 2960 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 2961 switch (scf_error()) { 2962 case SCF_ERROR_NOT_FOUND: 2963 break; 2964 2965 case SCF_ERROR_DELETED: 2966 case SCF_ERROR_CONNECTION_BROKEN: 2967 return (scferror2errno(scf_error())); 2968 2969 case SCF_ERROR_NOT_SET: 2970 case SCF_ERROR_INVALID_ARGUMENT: 2971 case SCF_ERROR_HANDLE_MISMATCH: 2972 case SCF_ERROR_NOT_BOUND: 2973 default: 2974 bad_error("entity_get_pg", scf_error()); 2975 } 2976 2977 have_cur_depts = 0; 2978 } 2979 2980 /* Fetch the running version of the "dependents" property group. */ 2981 ud_run_dpts_pg_set = 0; 2982 if (running != NULL) 2983 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 2984 else 2985 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 2986 if (r == 0) { 2987 ud_run_dpts_pg_set = 1; 2988 } else { 2989 switch (scf_error()) { 2990 case SCF_ERROR_NOT_FOUND: 2991 break; 2992 2993 case SCF_ERROR_DELETED: 2994 case SCF_ERROR_CONNECTION_BROKEN: 2995 return (scferror2errno(scf_error())); 2996 2997 case SCF_ERROR_NOT_SET: 2998 case SCF_ERROR_INVALID_ARGUMENT: 2999 case SCF_ERROR_HANDLE_MISMATCH: 3000 case SCF_ERROR_NOT_BOUND: 3001 default: 3002 bad_error(running ? "scf_snaplevel_get_pg" : 3003 "entity_get_pg", scf_error()); 3004 } 3005 } 3006 3007 /* 3008 * Clear the seen fields of the dependents, so we can tell which ones 3009 * are new. 3010 */ 3011 if (uu_list_walk(ient->sc_dependents, clear_int, 3012 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 3013 bad_error("uu_list_walk", uu_error()); 3014 3015 if (li_dpts_pg != NULL) { 3016 /* 3017 * Each property in li_dpts_pg represents a dependent tag in 3018 * the old manifest. For each, call upgrade_dependent(), 3019 * which will change ud_cur_depts_pg or dependencies in other 3020 * services as appropriate. Note (a) that changes to 3021 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 3022 * made en masse, and (b) it's ok if the entity doesn't have 3023 * a current version of the "dependents" property group, 3024 * because we'll just consider all dependents as customized 3025 * (by being deleted). 3026 */ 3027 3028 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 3029 switch (scf_error()) { 3030 case SCF_ERROR_DELETED: 3031 return (ENODEV); 3032 3033 case SCF_ERROR_CONNECTION_BROKEN: 3034 return (ECONNABORTED); 3035 3036 case SCF_ERROR_HANDLE_MISMATCH: 3037 case SCF_ERROR_NOT_BOUND: 3038 case SCF_ERROR_NOT_SET: 3039 default: 3040 bad_error("scf_iter_pg_properties", 3041 scf_error()); 3042 } 3043 } 3044 3045 if (have_cur_depts && 3046 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3047 switch (scf_error()) { 3048 case SCF_ERROR_BACKEND_ACCESS: 3049 case SCF_ERROR_BACKEND_READONLY: 3050 case SCF_ERROR_CONNECTION_BROKEN: 3051 return (scferror2errno(scf_error())); 3052 3053 case SCF_ERROR_DELETED: 3054 warn(emsg_pg_deleted, ient->sc_fmri, 3055 dependents); 3056 return (EBUSY); 3057 3058 case SCF_ERROR_PERMISSION_DENIED: 3059 warn(emsg_pg_mod_perm, dependents, 3060 ient->sc_fmri); 3061 return (scferror2errno(scf_error())); 3062 3063 case SCF_ERROR_HANDLE_MISMATCH: 3064 case SCF_ERROR_IN_USE: 3065 case SCF_ERROR_NOT_BOUND: 3066 case SCF_ERROR_NOT_SET: 3067 default: 3068 bad_error("scf_transaction_start", scf_error()); 3069 } 3070 } 3071 tx_started = have_cur_depts; 3072 3073 for (;;) { 3074 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3075 if (r == 0) 3076 break; 3077 if (r == 1) { 3078 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3079 tx_started ? ud_tx : NULL); 3080 switch (r) { 3081 case 0: 3082 continue; 3083 3084 case ECONNABORTED: 3085 case ENOMEM: 3086 case ENOSPC: 3087 case EBADF: 3088 case EBUSY: 3089 case EINVAL: 3090 case EPERM: 3091 case EROFS: 3092 case EACCES: 3093 case EEXIST: 3094 break; 3095 3096 case ECANCELED: 3097 r = ENODEV; 3098 break; 3099 3100 default: 3101 bad_error("upgrade_dependent", r); 3102 } 3103 3104 if (tx_started) 3105 scf_transaction_destroy_children(ud_tx); 3106 return (r); 3107 } 3108 if (r != -1) 3109 bad_error("scf_iter_next_property", r); 3110 3111 switch (scf_error()) { 3112 case SCF_ERROR_DELETED: 3113 r = ENODEV; 3114 break; 3115 3116 case SCF_ERROR_CONNECTION_BROKEN: 3117 r = ECONNABORTED; 3118 break; 3119 3120 case SCF_ERROR_NOT_SET: 3121 case SCF_ERROR_INVALID_ARGUMENT: 3122 case SCF_ERROR_NOT_BOUND: 3123 case SCF_ERROR_HANDLE_MISMATCH: 3124 default: 3125 bad_error("scf_iter_next_property", 3126 scf_error()); 3127 } 3128 3129 if (tx_started) 3130 scf_transaction_destroy_children(ud_tx); 3131 return (r); 3132 } 3133 } 3134 3135 /* import unseen dependents */ 3136 unseen = 0; 3137 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3138 new_dpt_pgroup != NULL; 3139 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3140 new_dpt_pgroup)) { 3141 if (!new_dpt_pgroup->sc_pgroup_seen) { 3142 unseen = 1; 3143 break; 3144 } 3145 } 3146 3147 /* If there are none, exit early. */ 3148 if (unseen == 0) 3149 goto commit; 3150 3151 /* Set up for lscf_dependent_import() */ 3152 cbdata.sc_handle = g_hndl; 3153 cbdata.sc_parent = ent; 3154 cbdata.sc_service = issvc; 3155 cbdata.sc_flags = 0; 3156 3157 if (!have_cur_depts) { 3158 /* 3159 * We have new dependents to import, so we need a "dependents" 3160 * property group. 3161 */ 3162 if (issvc) 3163 r = scf_service_add_pg(ent, dependents, 3164 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3165 else 3166 r = scf_instance_add_pg(ent, dependents, 3167 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3168 if (r != 0) { 3169 switch (scf_error()) { 3170 case SCF_ERROR_DELETED: 3171 case SCF_ERROR_CONNECTION_BROKEN: 3172 case SCF_ERROR_BACKEND_READONLY: 3173 case SCF_ERROR_BACKEND_ACCESS: 3174 case SCF_ERROR_NO_RESOURCES: 3175 return (scferror2errno(scf_error())); 3176 3177 case SCF_ERROR_EXISTS: 3178 warn(emsg_pg_added, ient->sc_fmri, dependents); 3179 return (EBUSY); 3180 3181 case SCF_ERROR_PERMISSION_DENIED: 3182 warn(emsg_pg_add_perm, dependents, 3183 ient->sc_fmri); 3184 return (scferror2errno(scf_error())); 3185 3186 case SCF_ERROR_NOT_BOUND: 3187 case SCF_ERROR_HANDLE_MISMATCH: 3188 case SCF_ERROR_INVALID_ARGUMENT: 3189 case SCF_ERROR_NOT_SET: 3190 default: 3191 bad_error("scf_service_add_pg", scf_error()); 3192 } 3193 } 3194 } 3195 3196 cbdata.sc_trans = ud_tx; 3197 3198 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3199 switch (scf_error()) { 3200 case SCF_ERROR_CONNECTION_BROKEN: 3201 case SCF_ERROR_BACKEND_ACCESS: 3202 case SCF_ERROR_BACKEND_READONLY: 3203 return (scferror2errno(scf_error())); 3204 3205 case SCF_ERROR_DELETED: 3206 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3207 return (EBUSY); 3208 3209 case SCF_ERROR_PERMISSION_DENIED: 3210 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3211 return (scferror2errno(scf_error())); 3212 3213 case SCF_ERROR_HANDLE_MISMATCH: 3214 case SCF_ERROR_IN_USE: 3215 case SCF_ERROR_NOT_BOUND: 3216 case SCF_ERROR_NOT_SET: 3217 default: 3218 bad_error("scf_transaction_start", scf_error()); 3219 } 3220 } 3221 tx_started = 1; 3222 3223 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3224 new_dpt_pgroup != NULL; 3225 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3226 new_dpt_pgroup)) { 3227 if (new_dpt_pgroup->sc_pgroup_seen) 3228 continue; 3229 3230 if (ud_run_dpts_pg_set) { 3231 /* 3232 * If the dependent is already there, then we have 3233 * a conflict. 3234 */ 3235 if (scf_pg_get_property(ud_run_dpts_pg, 3236 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3237 r = handle_dependent_conflict(ient, ud_prop, 3238 new_dpt_pgroup); 3239 switch (r) { 3240 case 0: 3241 continue; 3242 3243 case ECONNABORTED: 3244 case ENOMEM: 3245 case EBUSY: 3246 case EBADF: 3247 case EINVAL: 3248 scf_transaction_destroy_children(ud_tx); 3249 return (r); 3250 3251 default: 3252 bad_error("handle_dependent_conflict", 3253 r); 3254 } 3255 } else { 3256 switch (scf_error()) { 3257 case SCF_ERROR_NOT_FOUND: 3258 break; 3259 3260 case SCF_ERROR_INVALID_ARGUMENT: 3261 warn(emsg_fmri_invalid_pg_name, 3262 ient->sc_fmri, 3263 new_dpt_pgroup->sc_pgroup_name); 3264 scf_transaction_destroy_children(ud_tx); 3265 return (EINVAL); 3266 3267 case SCF_ERROR_DELETED: 3268 warn(emsg_pg_deleted, ient->sc_fmri, 3269 new_dpt_pgroup->sc_pgroup_name); 3270 scf_transaction_destroy_children(ud_tx); 3271 return (EBUSY); 3272 3273 case SCF_ERROR_CONNECTION_BROKEN: 3274 scf_transaction_destroy_children(ud_tx); 3275 return (ECONNABORTED); 3276 3277 case SCF_ERROR_NOT_BOUND: 3278 case SCF_ERROR_HANDLE_MISMATCH: 3279 case SCF_ERROR_NOT_SET: 3280 default: 3281 bad_error("scf_pg_get_property", 3282 scf_error()); 3283 } 3284 } 3285 } 3286 3287 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3288 if (r != UU_WALK_NEXT) { 3289 if (r != UU_WALK_ERROR) 3290 bad_error("lscf_dependent_import", r); 3291 3292 if (cbdata.sc_err == EALREADY) { 3293 /* Collisions were handled preemptively. */ 3294 bad_error("lscf_dependent_import", 3295 cbdata.sc_err); 3296 } 3297 3298 scf_transaction_destroy_children(ud_tx); 3299 return (cbdata.sc_err); 3300 } 3301 } 3302 3303 commit: 3304 if (!tx_started) 3305 return (0); 3306 3307 r = scf_transaction_commit(ud_tx); 3308 3309 scf_transaction_destroy_children(ud_tx); 3310 3311 switch (r) { 3312 case 1: 3313 return (0); 3314 3315 case 0: 3316 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3317 return (EBUSY); 3318 3319 case -1: 3320 break; 3321 3322 default: 3323 bad_error("scf_transaction_commit", r); 3324 } 3325 3326 switch (scf_error()) { 3327 case SCF_ERROR_CONNECTION_BROKEN: 3328 case SCF_ERROR_BACKEND_READONLY: 3329 case SCF_ERROR_BACKEND_ACCESS: 3330 case SCF_ERROR_NO_RESOURCES: 3331 return (scferror2errno(scf_error())); 3332 3333 case SCF_ERROR_DELETED: 3334 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3335 return (EBUSY); 3336 3337 case SCF_ERROR_PERMISSION_DENIED: 3338 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3339 return (scferror2errno(scf_error())); 3340 3341 case SCF_ERROR_NOT_BOUND: 3342 case SCF_ERROR_INVALID_ARGUMENT: 3343 case SCF_ERROR_NOT_SET: 3344 default: 3345 bad_error("scf_transaction_destroy", scf_error()); 3346 /* NOTREACHED */ 3347 } 3348 } 3349 3350 /* 3351 * Used to add the manifests to the list of currently supported manifests. 3352 * We can modify the existing manifest list removing entries if the files 3353 * don't exist. 3354 * 3355 * Get the old list and the new file name 3356 * If the new file name is in the list return 3357 * If not then add the file to the list. 3358 * As we process the list check to see if the files in the old list exist 3359 * if not then remove the file from the list. 3360 * Commit the list of manifest file names. 3361 * 3362 */ 3363 static int 3364 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient, 3365 const scf_snaplevel_t *running, void *ent) 3366 { 3367 scf_propertygroup_t *ud_mfsts_pg = NULL; 3368 scf_property_t *ud_prop = NULL; 3369 scf_iter_t *ud_prop_iter; 3370 scf_value_t *fname_value; 3371 scf_callback_t cbdata; 3372 pgroup_t *mfst_pgroup; 3373 property_t *mfst_prop; 3374 property_t *old_prop; 3375 char *pname = malloc(MAXPATHLEN); 3376 char *fval = NULL; 3377 char *old_pname; 3378 char *old_fval; 3379 int no_upgrade_pg; 3380 int mfst_seen; 3381 int r; 3382 3383 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 3384 3385 /* 3386 * This should always be the service base on the code 3387 * path, and the fact that the manifests pg is a service 3388 * level property group only. 3389 */ 3390 ud_mfsts_pg = scf_pg_create(g_hndl); 3391 ud_prop = scf_property_create(g_hndl); 3392 ud_prop_iter = scf_iter_create(g_hndl); 3393 fname_value = scf_value_create(g_hndl); 3394 3395 /* Fetch the "manifests" property group */ 3396 no_upgrade_pg = 0; 3397 r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES, 3398 ud_mfsts_pg); 3399 if (r != 0) { 3400 switch (scf_error()) { 3401 case SCF_ERROR_NOT_FOUND: 3402 no_upgrade_pg = 1; 3403 break; 3404 3405 case SCF_ERROR_DELETED: 3406 case SCF_ERROR_CONNECTION_BROKEN: 3407 return (scferror2errno(scf_error())); 3408 3409 case SCF_ERROR_NOT_SET: 3410 case SCF_ERROR_INVALID_ARGUMENT: 3411 case SCF_ERROR_HANDLE_MISMATCH: 3412 case SCF_ERROR_NOT_BOUND: 3413 default: 3414 bad_error(running ? "scf_snaplevel_get_pg" : 3415 "entity_get_pg", scf_error()); 3416 } 3417 } 3418 3419 if (no_upgrade_pg) { 3420 cbdata.sc_handle = g_hndl; 3421 cbdata.sc_parent = ent; 3422 cbdata.sc_service = issvc; 3423 cbdata.sc_flags = SCI_FORCE; 3424 cbdata.sc_source_fmri = ient->sc_fmri; 3425 cbdata.sc_target_fmri = ient->sc_fmri; 3426 3427 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT) 3428 return (cbdata.sc_err); 3429 3430 return (0); 3431 } 3432 3433 /* Fetch the new manifests property group */ 3434 for (mfst_pgroup = uu_list_first(ient->sc_pgroups); 3435 mfst_pgroup != NULL; 3436 mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) { 3437 if (strcmp(mfst_pgroup->sc_pgroup_name, 3438 SCF_PG_MANIFESTFILES) == 0) 3439 break; 3440 } 3441 3442 if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) != 3443 SCF_SUCCESS) 3444 return (-1); 3445 3446 while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) { 3447 mfst_seen = 0; 3448 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0) 3449 continue; 3450 3451 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props); 3452 mfst_prop != NULL; 3453 mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props, 3454 mfst_prop)) { 3455 if (strcmp(mfst_prop->sc_property_name, pname) == 0) { 3456 mfst_seen = 1; 3457 } 3458 } 3459 3460 /* 3461 * If the manifest is not seen then add it to the new mfst 3462 * property list to get proccessed into the repo. 3463 */ 3464 if (mfst_seen == 0) { 3465 if (fval == NULL) 3466 fval = malloc(MAXPATHLEN); 3467 3468 /* 3469 * If we cannot get the value then there is no 3470 * reason to attempt to attach the value to 3471 * the property group 3472 */ 3473 if (fval != NULL && 3474 prop_get_val(ud_prop, fname_value) == 0 && 3475 scf_value_get_astring(fname_value, fval, 3476 MAXPATHLEN) != -1) { 3477 /* 3478 * If the filesystem/minimal service is 3479 * online check to see if the manifest is 3480 * there. If not then there is no need to 3481 * add it. 3482 * 3483 * If filesystem/minimal service is not 3484 * online, we go ahead and record the 3485 * manifest file name. We don't check for 3486 * its existence because it may be on a 3487 * file system that is not yet mounted. 3488 */ 3489 if ((est->sc_fs_minimal) && 3490 (access(fval, F_OK) == -1)) { 3491 continue; 3492 } 3493 3494 old_pname = safe_strdup(pname); 3495 old_fval = safe_strdup(fval); 3496 old_prop = internal_property_create(old_pname, 3497 SCF_TYPE_ASTRING, 1, old_fval); 3498 3499 /* 3500 * Already checked to see if the property exists 3501 * in the group, and it does not. 3502 */ 3503 (void) internal_attach_property(mfst_pgroup, 3504 old_prop); 3505 } 3506 } 3507 } 3508 free(fval); 3509 3510 cbdata.sc_handle = g_hndl; 3511 cbdata.sc_parent = ent; 3512 cbdata.sc_service = issvc; 3513 cbdata.sc_flags = SCI_FORCE; 3514 cbdata.sc_source_fmri = ient->sc_fmri; 3515 cbdata.sc_target_fmri = ient->sc_fmri; 3516 3517 if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT) 3518 return (cbdata.sc_err); 3519 3520 return (r); 3521 } 3522 3523 /* 3524 * prop is taken to be a property in the "dependents" property group of snpl, 3525 * which is taken to be the snaplevel of a last-import snapshot corresponding 3526 * to ient. If prop is a valid dependents property, upgrade the dependent it 3527 * represents according to the repository & ient. If ud_run_dpts_pg_set is 3528 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 3529 * of the entity ient represents (possibly in the running snapshot). If it 3530 * needs to be changed, an entry will be added to tx, if not NULL. 3531 * 3532 * Returns 3533 * 0 - success 3534 * ECONNABORTED - repository connection broken 3535 * ENOMEM - out of memory 3536 * ENOSPC - configd was out of resources 3537 * ECANCELED - snpl's entity was deleted 3538 * EINVAL - dependent target is invalid (error printed) 3539 * - dependent is invalid (error printed) 3540 * EBADF - snpl is corrupt (error printed) 3541 * - snpl has corrupt pg (error printed) 3542 * - dependency pg in target is corrupt (error printed) 3543 * - running snapshot in dependent is missing snaplevel (error printed) 3544 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 3545 * - couldn't create dependent (permission denied) (error printed) 3546 * - couldn't modify dependent pg (permission denied) (error printed) 3547 * EROFS - couldn't delete dependency pg (repository read-only) 3548 * - couldn't create dependent (repository read-only) 3549 * EACCES - couldn't delete dependency pg (backend access denied) 3550 * - couldn't create dependent (backend access denied) 3551 * EBUSY - ud_run_dpts_pg was deleted (error printed) 3552 * - tx's pg was deleted (error printed) 3553 * - dependent pg was changed or deleted (error printed) 3554 * EEXIST - dependency pg already exists in new target (error printed) 3555 */ 3556 static int 3557 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 3558 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 3559 { 3560 pgroup_t pgrp; 3561 scf_type_t ty; 3562 pgroup_t *new_dpt_pgroup; 3563 pgroup_t *old_dpt_pgroup = NULL; 3564 pgroup_t *current_pg; 3565 scf_callback_t cbdata; 3566 int tissvc; 3567 void *target_ent; 3568 scf_error_t serr; 3569 int r; 3570 scf_transaction_entry_t *ent; 3571 3572 const char * const cf_inval = gettext("Conflict upgrading %s " 3573 "(dependent \"%s\" has invalid dependents property).\n"); 3574 const char * const cf_missing = gettext("Conflict upgrading %s " 3575 "(dependent \"%s\" is missing).\n"); 3576 const char * const cf_newdpg = gettext("Conflict upgrading %s " 3577 "(dependent \"%s\" has new dependency property group).\n"); 3578 const char * const cf_newtarg = gettext("Conflict upgrading %s " 3579 "(dependent \"%s\" has new target).\n"); 3580 const char * const li_corrupt = 3581 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 3582 const char * const upgrading = 3583 gettext("%s: Upgrading dependent \"%s\".\n"); 3584 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 3585 "corrupt (missing snaplevel).\n"); 3586 3587 if (scf_property_type(prop, &ty) != 0) { 3588 switch (scf_error()) { 3589 case SCF_ERROR_DELETED: 3590 case SCF_ERROR_CONNECTION_BROKEN: 3591 return (scferror2errno(scf_error())); 3592 3593 case SCF_ERROR_NOT_BOUND: 3594 case SCF_ERROR_NOT_SET: 3595 default: 3596 bad_error("scf_property_type", scf_error()); 3597 } 3598 } 3599 3600 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3601 warn(li_corrupt, ient->sc_fmri); 3602 return (EBADF); 3603 } 3604 3605 /* 3606 * prop represents a dependent in the old manifest. It is named after 3607 * the dependent. 3608 */ 3609 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 3610 switch (scf_error()) { 3611 case SCF_ERROR_DELETED: 3612 case SCF_ERROR_CONNECTION_BROKEN: 3613 return (scferror2errno(scf_error())); 3614 3615 case SCF_ERROR_NOT_BOUND: 3616 case SCF_ERROR_NOT_SET: 3617 default: 3618 bad_error("scf_property_get_name", scf_error()); 3619 } 3620 } 3621 3622 /* See if it's in the new manifest. */ 3623 pgrp.sc_pgroup_name = ud_name; 3624 new_dpt_pgroup = 3625 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 3626 3627 /* If it's not, delete it... if it hasn't been customized. */ 3628 if (new_dpt_pgroup == NULL) { 3629 pgroup_t *dpt; 3630 3631 if (!ud_run_dpts_pg_set) 3632 return (0); 3633 3634 if (scf_property_get_value(prop, ud_val) != 0) { 3635 switch (scf_error()) { 3636 case SCF_ERROR_NOT_FOUND: 3637 case SCF_ERROR_CONSTRAINT_VIOLATED: 3638 warn(li_corrupt, ient->sc_fmri); 3639 return (EBADF); 3640 3641 case SCF_ERROR_DELETED: 3642 case SCF_ERROR_CONNECTION_BROKEN: 3643 return (scferror2errno(scf_error())); 3644 3645 case SCF_ERROR_HANDLE_MISMATCH: 3646 case SCF_ERROR_NOT_BOUND: 3647 case SCF_ERROR_NOT_SET: 3648 case SCF_ERROR_PERMISSION_DENIED: 3649 default: 3650 bad_error("scf_property_get_value", 3651 scf_error()); 3652 } 3653 } 3654 3655 if (scf_value_get_as_string(ud_val, ud_oldtarg, 3656 max_scf_value_len + 1) < 0) 3657 bad_error("scf_value_get_as_string", scf_error()); 3658 3659 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 3660 0) { 3661 switch (scf_error()) { 3662 case SCF_ERROR_NOT_FOUND: 3663 return (0); 3664 3665 case SCF_ERROR_CONNECTION_BROKEN: 3666 return (scferror2errno(scf_error())); 3667 3668 case SCF_ERROR_DELETED: 3669 warn(emsg_pg_deleted, ient->sc_fmri, 3670 "dependents"); 3671 return (EBUSY); 3672 3673 case SCF_ERROR_INVALID_ARGUMENT: 3674 case SCF_ERROR_NOT_BOUND: 3675 case SCF_ERROR_HANDLE_MISMATCH: 3676 case SCF_ERROR_NOT_SET: 3677 default: 3678 bad_error("scf_pg_get_property", scf_error()); 3679 } 3680 } 3681 if (scf_property_get_value(ud_prop, ud_val) != 0) { 3682 switch (scf_error()) { 3683 case SCF_ERROR_NOT_FOUND: 3684 case SCF_ERROR_CONSTRAINT_VIOLATED: 3685 warn(cf_inval, ient->sc_fmri, ud_name); 3686 return (0); 3687 3688 case SCF_ERROR_DELETED: 3689 case SCF_ERROR_CONNECTION_BROKEN: 3690 return (scferror2errno(scf_error())); 3691 3692 case SCF_ERROR_HANDLE_MISMATCH: 3693 case SCF_ERROR_NOT_BOUND: 3694 case SCF_ERROR_NOT_SET: 3695 case SCF_ERROR_PERMISSION_DENIED: 3696 default: 3697 bad_error("scf_property_get_value", 3698 scf_error()); 3699 } 3700 } 3701 3702 ty = scf_value_type(ud_val); 3703 assert(ty != SCF_TYPE_INVALID); 3704 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3705 warn(cf_inval, ient->sc_fmri, ud_name); 3706 return (0); 3707 } 3708 3709 if (scf_value_get_as_string(ud_val, ud_ctarg, 3710 max_scf_value_len + 1) < 0) 3711 bad_error("scf_value_get_as_string", scf_error()); 3712 3713 r = fmri_equal(ud_ctarg, ud_oldtarg); 3714 switch (r) { 3715 case 1: 3716 break; 3717 3718 case 0: 3719 case -1: /* warn? */ 3720 warn(cf_newtarg, ient->sc_fmri, ud_name); 3721 return (0); 3722 3723 case -2: 3724 warn(li_corrupt, ient->sc_fmri); 3725 return (EBADF); 3726 3727 default: 3728 bad_error("fmri_equal", r); 3729 } 3730 3731 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3732 switch (scf_error()) { 3733 case SCF_ERROR_NOT_FOUND: 3734 warn(li_corrupt, ient->sc_fmri); 3735 return (EBADF); 3736 3737 case SCF_ERROR_DELETED: 3738 case SCF_ERROR_CONNECTION_BROKEN: 3739 return (scferror2errno(scf_error())); 3740 3741 case SCF_ERROR_NOT_BOUND: 3742 case SCF_ERROR_HANDLE_MISMATCH: 3743 case SCF_ERROR_INVALID_ARGUMENT: 3744 case SCF_ERROR_NOT_SET: 3745 default: 3746 bad_error("scf_snaplevel_get_pg", scf_error()); 3747 } 3748 } 3749 3750 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3751 snap_lastimport); 3752 switch (r) { 3753 case 0: 3754 break; 3755 3756 case ECANCELED: 3757 case ECONNABORTED: 3758 case ENOMEM: 3759 case EBADF: 3760 return (r); 3761 3762 case EACCES: 3763 default: 3764 bad_error("load_pg", r); 3765 } 3766 3767 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 3768 switch (serr) { 3769 case SCF_ERROR_NONE: 3770 break; 3771 3772 case SCF_ERROR_NO_MEMORY: 3773 internal_pgroup_free(old_dpt_pgroup); 3774 return (ENOMEM); 3775 3776 case SCF_ERROR_NOT_FOUND: 3777 internal_pgroup_free(old_dpt_pgroup); 3778 goto delprop; 3779 3780 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 3781 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 3782 default: 3783 bad_error("fmri_to_entity", serr); 3784 } 3785 3786 r = entity_get_running_pg(target_ent, tissvc, ud_name, 3787 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 3788 switch (r) { 3789 case 0: 3790 break; 3791 3792 case ECONNABORTED: 3793 internal_pgroup_free(old_dpt_pgroup); 3794 return (r); 3795 3796 case ECANCELED: 3797 case ENOENT: 3798 internal_pgroup_free(old_dpt_pgroup); 3799 goto delprop; 3800 3801 case EBADF: 3802 warn(r_no_lvl, ud_ctarg); 3803 internal_pgroup_free(old_dpt_pgroup); 3804 return (r); 3805 3806 case EINVAL: 3807 default: 3808 bad_error("entity_get_running_pg", r); 3809 } 3810 3811 /* load it */ 3812 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 3813 switch (r) { 3814 case 0: 3815 break; 3816 3817 case ECANCELED: 3818 internal_pgroup_free(old_dpt_pgroup); 3819 goto delprop; 3820 3821 case ECONNABORTED: 3822 case ENOMEM: 3823 case EBADF: 3824 internal_pgroup_free(old_dpt_pgroup); 3825 return (r); 3826 3827 case EACCES: 3828 default: 3829 bad_error("load_pg", r); 3830 } 3831 3832 /* compare property groups */ 3833 if (!pg_equal(old_dpt_pgroup, current_pg)) { 3834 warn(cf_newdpg, ient->sc_fmri, ud_name); 3835 internal_pgroup_free(old_dpt_pgroup); 3836 internal_pgroup_free(current_pg); 3837 return (0); 3838 } 3839 3840 internal_pgroup_free(old_dpt_pgroup); 3841 internal_pgroup_free(current_pg); 3842 3843 if (g_verbose) 3844 warn(gettext("%s: Deleting dependent \"%s\".\n"), 3845 ient->sc_fmri, ud_name); 3846 3847 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 3848 switch (scf_error()) { 3849 case SCF_ERROR_NOT_FOUND: 3850 case SCF_ERROR_DELETED: 3851 internal_pgroup_free(old_dpt_pgroup); 3852 goto delprop; 3853 3854 case SCF_ERROR_CONNECTION_BROKEN: 3855 internal_pgroup_free(old_dpt_pgroup); 3856 return (ECONNABORTED); 3857 3858 case SCF_ERROR_NOT_SET: 3859 case SCF_ERROR_INVALID_ARGUMENT: 3860 case SCF_ERROR_HANDLE_MISMATCH: 3861 case SCF_ERROR_NOT_BOUND: 3862 default: 3863 bad_error("entity_get_pg", scf_error()); 3864 } 3865 } 3866 3867 if (scf_pg_delete(ud_pg) != 0) { 3868 switch (scf_error()) { 3869 case SCF_ERROR_DELETED: 3870 break; 3871 3872 case SCF_ERROR_CONNECTION_BROKEN: 3873 case SCF_ERROR_BACKEND_READONLY: 3874 case SCF_ERROR_BACKEND_ACCESS: 3875 return (scferror2errno(scf_error())); 3876 3877 case SCF_ERROR_PERMISSION_DENIED: 3878 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 3879 return (scferror2errno(scf_error())); 3880 3881 case SCF_ERROR_NOT_SET: 3882 default: 3883 bad_error("scf_pg_delete", scf_error()); 3884 } 3885 } 3886 3887 /* 3888 * This service was changed, so it must be refreshed. But 3889 * since it's not mentioned in the new manifest, we have to 3890 * record its FMRI here for use later. We record the name 3891 * & the entity (via sc_parent) in case we need to print error 3892 * messages during the refresh. 3893 */ 3894 dpt = internal_pgroup_new(); 3895 if (dpt == NULL) 3896 return (ENOMEM); 3897 dpt->sc_pgroup_name = strdup(ud_name); 3898 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 3899 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 3900 return (ENOMEM); 3901 dpt->sc_parent = (entity_t *)ient; 3902 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 3903 uu_die(gettext("libuutil error: %s\n"), 3904 uu_strerror(uu_error())); 3905 3906 delprop: 3907 if (tx == NULL) 3908 return (0); 3909 3910 ent = scf_entry_create(g_hndl); 3911 if (ent == NULL) 3912 return (ENOMEM); 3913 3914 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 3915 scf_entry_destroy(ent); 3916 switch (scf_error()) { 3917 case SCF_ERROR_DELETED: 3918 warn(emsg_pg_deleted, ient->sc_fmri, 3919 "dependents"); 3920 return (EBUSY); 3921 3922 case SCF_ERROR_CONNECTION_BROKEN: 3923 return (scferror2errno(scf_error())); 3924 3925 case SCF_ERROR_NOT_FOUND: 3926 break; 3927 3928 case SCF_ERROR_HANDLE_MISMATCH: 3929 case SCF_ERROR_NOT_BOUND: 3930 case SCF_ERROR_INVALID_ARGUMENT: 3931 case SCF_ERROR_NOT_SET: 3932 default: 3933 bad_error("scf_transaction_property_delete", 3934 scf_error()); 3935 } 3936 } 3937 3938 return (0); 3939 } 3940 3941 new_dpt_pgroup->sc_pgroup_seen = 1; 3942 3943 /* 3944 * Decide whether the dependent has changed in the manifest. 3945 */ 3946 /* Compare the target. */ 3947 if (scf_property_get_value(prop, ud_val) != 0) { 3948 switch (scf_error()) { 3949 case SCF_ERROR_NOT_FOUND: 3950 case SCF_ERROR_CONSTRAINT_VIOLATED: 3951 warn(li_corrupt, ient->sc_fmri); 3952 return (EBADF); 3953 3954 case SCF_ERROR_DELETED: 3955 case SCF_ERROR_CONNECTION_BROKEN: 3956 return (scferror2errno(scf_error())); 3957 3958 case SCF_ERROR_HANDLE_MISMATCH: 3959 case SCF_ERROR_NOT_BOUND: 3960 case SCF_ERROR_NOT_SET: 3961 case SCF_ERROR_PERMISSION_DENIED: 3962 default: 3963 bad_error("scf_property_get_value", scf_error()); 3964 } 3965 } 3966 3967 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 3968 0) 3969 bad_error("scf_value_get_as_string", scf_error()); 3970 3971 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 3972 switch (r) { 3973 case 0: 3974 break; 3975 3976 case 1: 3977 /* Compare the dependency pgs. */ 3978 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3979 switch (scf_error()) { 3980 case SCF_ERROR_NOT_FOUND: 3981 warn(li_corrupt, ient->sc_fmri); 3982 return (EBADF); 3983 3984 case SCF_ERROR_DELETED: 3985 case SCF_ERROR_CONNECTION_BROKEN: 3986 return (scferror2errno(scf_error())); 3987 3988 case SCF_ERROR_NOT_BOUND: 3989 case SCF_ERROR_HANDLE_MISMATCH: 3990 case SCF_ERROR_INVALID_ARGUMENT: 3991 case SCF_ERROR_NOT_SET: 3992 default: 3993 bad_error("scf_snaplevel_get_pg", scf_error()); 3994 } 3995 } 3996 3997 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3998 snap_lastimport); 3999 switch (r) { 4000 case 0: 4001 break; 4002 4003 case ECANCELED: 4004 case ECONNABORTED: 4005 case ENOMEM: 4006 case EBADF: 4007 return (r); 4008 4009 case EACCES: 4010 default: 4011 bad_error("load_pg", r); 4012 } 4013 4014 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 4015 /* no change, leave customizations */ 4016 internal_pgroup_free(old_dpt_pgroup); 4017 return (0); 4018 } 4019 break; 4020 4021 case -1: 4022 warn(li_corrupt, ient->sc_fmri); 4023 return (EBADF); 4024 4025 case -2: 4026 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 4027 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 4028 return (EINVAL); 4029 4030 default: 4031 bad_error("fmri_equal", r); 4032 } 4033 4034 /* 4035 * The dependent has changed in the manifest. Upgrade the current 4036 * properties if they haven't been customized. 4037 */ 4038 4039 /* 4040 * If new_dpt_pgroup->sc_override, then act as though the property 4041 * group hasn't been customized. 4042 */ 4043 if (new_dpt_pgroup->sc_pgroup_override) 4044 goto nocust; 4045 4046 if (!ud_run_dpts_pg_set) { 4047 warn(cf_missing, ient->sc_fmri, ud_name); 4048 r = 0; 4049 goto out; 4050 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 4051 switch (scf_error()) { 4052 case SCF_ERROR_NOT_FOUND: 4053 warn(cf_missing, ient->sc_fmri, ud_name); 4054 r = 0; 4055 goto out; 4056 4057 case SCF_ERROR_CONNECTION_BROKEN: 4058 r = scferror2errno(scf_error()); 4059 goto out; 4060 4061 case SCF_ERROR_DELETED: 4062 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 4063 r = EBUSY; 4064 goto out; 4065 4066 case SCF_ERROR_INVALID_ARGUMENT: 4067 case SCF_ERROR_NOT_BOUND: 4068 case SCF_ERROR_HANDLE_MISMATCH: 4069 case SCF_ERROR_NOT_SET: 4070 default: 4071 bad_error("scf_pg_get_property", scf_error()); 4072 } 4073 } 4074 4075 if (scf_property_get_value(ud_prop, ud_val) != 0) { 4076 switch (scf_error()) { 4077 case SCF_ERROR_NOT_FOUND: 4078 case SCF_ERROR_CONSTRAINT_VIOLATED: 4079 warn(cf_inval, ient->sc_fmri, ud_name); 4080 r = 0; 4081 goto out; 4082 4083 case SCF_ERROR_DELETED: 4084 case SCF_ERROR_CONNECTION_BROKEN: 4085 r = scferror2errno(scf_error()); 4086 goto out; 4087 4088 case SCF_ERROR_HANDLE_MISMATCH: 4089 case SCF_ERROR_NOT_BOUND: 4090 case SCF_ERROR_NOT_SET: 4091 case SCF_ERROR_PERMISSION_DENIED: 4092 default: 4093 bad_error("scf_property_get_value", scf_error()); 4094 } 4095 } 4096 4097 ty = scf_value_type(ud_val); 4098 assert(ty != SCF_TYPE_INVALID); 4099 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4100 warn(cf_inval, ient->sc_fmri, ud_name); 4101 r = 0; 4102 goto out; 4103 } 4104 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4105 0) 4106 bad_error("scf_value_get_as_string", scf_error()); 4107 4108 r = fmri_equal(ud_ctarg, ud_oldtarg); 4109 if (r == -1) { 4110 warn(cf_inval, ient->sc_fmri, ud_name); 4111 r = 0; 4112 goto out; 4113 } else if (r == -2) { 4114 warn(li_corrupt, ient->sc_fmri); 4115 r = EBADF; 4116 goto out; 4117 } else if (r == 0) { 4118 /* 4119 * Target has been changed. Only abort now if it's been 4120 * changed to something other than what's in the manifest. 4121 */ 4122 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4123 if (r == -1) { 4124 warn(cf_inval, ient->sc_fmri, ud_name); 4125 r = 0; 4126 goto out; 4127 } else if (r == 0) { 4128 warn(cf_newtarg, ient->sc_fmri, ud_name); 4129 r = 0; 4130 goto out; 4131 } else if (r != 1) { 4132 /* invalid sc_pgroup_fmri caught above */ 4133 bad_error("fmri_equal", r); 4134 } 4135 4136 /* 4137 * Fetch the current dependency pg. If it's what the manifest 4138 * says, then no problem. 4139 */ 4140 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4141 switch (serr) { 4142 case SCF_ERROR_NONE: 4143 break; 4144 4145 case SCF_ERROR_NOT_FOUND: 4146 warn(cf_missing, ient->sc_fmri, ud_name); 4147 r = 0; 4148 goto out; 4149 4150 case SCF_ERROR_NO_MEMORY: 4151 r = ENOMEM; 4152 goto out; 4153 4154 case SCF_ERROR_CONSTRAINT_VIOLATED: 4155 case SCF_ERROR_INVALID_ARGUMENT: 4156 default: 4157 bad_error("fmri_to_entity", serr); 4158 } 4159 4160 r = entity_get_running_pg(target_ent, tissvc, ud_name, 4161 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 4162 switch (r) { 4163 case 0: 4164 break; 4165 4166 case ECONNABORTED: 4167 goto out; 4168 4169 case ECANCELED: 4170 case ENOENT: 4171 warn(cf_missing, ient->sc_fmri, ud_name); 4172 r = 0; 4173 goto out; 4174 4175 case EBADF: 4176 warn(r_no_lvl, ud_ctarg); 4177 goto out; 4178 4179 case EINVAL: 4180 default: 4181 bad_error("entity_get_running_pg", r); 4182 } 4183 4184 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4185 switch (r) { 4186 case 0: 4187 break; 4188 4189 case ECANCELED: 4190 warn(cf_missing, ient->sc_fmri, ud_name); 4191 r = 0; 4192 goto out; 4193 4194 case ECONNABORTED: 4195 case ENOMEM: 4196 case EBADF: 4197 goto out; 4198 4199 case EACCES: 4200 default: 4201 bad_error("load_pg", r); 4202 } 4203 4204 if (!pg_equal(current_pg, new_dpt_pgroup)) 4205 warn(cf_newdpg, ient->sc_fmri, ud_name); 4206 internal_pgroup_free(current_pg); 4207 r = 0; 4208 goto out; 4209 } else if (r != 1) { 4210 bad_error("fmri_equal", r); 4211 } 4212 4213 nocust: 4214 /* 4215 * Target has not been customized. Check the dependency property 4216 * group. 4217 */ 4218 4219 if (old_dpt_pgroup == NULL) { 4220 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 4221 ud_pg) != 0) { 4222 switch (scf_error()) { 4223 case SCF_ERROR_NOT_FOUND: 4224 warn(li_corrupt, ient->sc_fmri); 4225 return (EBADF); 4226 4227 case SCF_ERROR_DELETED: 4228 case SCF_ERROR_CONNECTION_BROKEN: 4229 return (scferror2errno(scf_error())); 4230 4231 case SCF_ERROR_NOT_BOUND: 4232 case SCF_ERROR_HANDLE_MISMATCH: 4233 case SCF_ERROR_INVALID_ARGUMENT: 4234 case SCF_ERROR_NOT_SET: 4235 default: 4236 bad_error("scf_snaplevel_get_pg", scf_error()); 4237 } 4238 } 4239 4240 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4241 snap_lastimport); 4242 switch (r) { 4243 case 0: 4244 break; 4245 4246 case ECANCELED: 4247 case ECONNABORTED: 4248 case ENOMEM: 4249 case EBADF: 4250 return (r); 4251 4252 case EACCES: 4253 default: 4254 bad_error("load_pg", r); 4255 } 4256 } 4257 4258 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4259 switch (serr) { 4260 case SCF_ERROR_NONE: 4261 break; 4262 4263 case SCF_ERROR_NOT_FOUND: 4264 warn(cf_missing, ient->sc_fmri, ud_name); 4265 r = 0; 4266 goto out; 4267 4268 case SCF_ERROR_NO_MEMORY: 4269 r = ENOMEM; 4270 goto out; 4271 4272 case SCF_ERROR_CONSTRAINT_VIOLATED: 4273 case SCF_ERROR_INVALID_ARGUMENT: 4274 default: 4275 bad_error("fmri_to_entity", serr); 4276 } 4277 4278 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4279 ud_iter2, ud_inst, imp_snap, ud_snpl); 4280 switch (r) { 4281 case 0: 4282 break; 4283 4284 case ECONNABORTED: 4285 goto out; 4286 4287 case ECANCELED: 4288 case ENOENT: 4289 warn(cf_missing, ient->sc_fmri, ud_name); 4290 r = 0; 4291 goto out; 4292 4293 case EBADF: 4294 warn(r_no_lvl, ud_ctarg); 4295 goto out; 4296 4297 case EINVAL: 4298 default: 4299 bad_error("entity_get_running_pg", r); 4300 } 4301 4302 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4303 switch (r) { 4304 case 0: 4305 break; 4306 4307 case ECANCELED: 4308 warn(cf_missing, ient->sc_fmri, ud_name); 4309 goto out; 4310 4311 case ECONNABORTED: 4312 case ENOMEM: 4313 case EBADF: 4314 goto out; 4315 4316 case EACCES: 4317 default: 4318 bad_error("load_pg", r); 4319 } 4320 4321 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4322 if (!pg_equal(current_pg, new_dpt_pgroup)) 4323 warn(cf_newdpg, ient->sc_fmri, ud_name); 4324 internal_pgroup_free(current_pg); 4325 r = 0; 4326 goto out; 4327 } 4328 4329 /* Uncustomized. Upgrade. */ 4330 4331 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4332 switch (r) { 4333 case 1: 4334 if (pg_equal(current_pg, new_dpt_pgroup)) { 4335 /* Already upgraded. */ 4336 internal_pgroup_free(current_pg); 4337 r = 0; 4338 goto out; 4339 } 4340 4341 internal_pgroup_free(current_pg); 4342 4343 /* upgrade current_pg */ 4344 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4345 switch (scf_error()) { 4346 case SCF_ERROR_CONNECTION_BROKEN: 4347 r = scferror2errno(scf_error()); 4348 goto out; 4349 4350 case SCF_ERROR_DELETED: 4351 warn(cf_missing, ient->sc_fmri, ud_name); 4352 r = 0; 4353 goto out; 4354 4355 case SCF_ERROR_NOT_FOUND: 4356 break; 4357 4358 case SCF_ERROR_INVALID_ARGUMENT: 4359 case SCF_ERROR_NOT_BOUND: 4360 case SCF_ERROR_NOT_SET: 4361 case SCF_ERROR_HANDLE_MISMATCH: 4362 default: 4363 bad_error("entity_get_pg", scf_error()); 4364 } 4365 4366 if (tissvc) 4367 r = scf_service_add_pg(target_ent, ud_name, 4368 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4369 else 4370 r = scf_instance_add_pg(target_ent, ud_name, 4371 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4372 if (r != 0) { 4373 switch (scf_error()) { 4374 case SCF_ERROR_CONNECTION_BROKEN: 4375 case SCF_ERROR_NO_RESOURCES: 4376 case SCF_ERROR_BACKEND_READONLY: 4377 case SCF_ERROR_BACKEND_ACCESS: 4378 r = scferror2errno(scf_error()); 4379 goto out; 4380 4381 case SCF_ERROR_DELETED: 4382 warn(cf_missing, ient->sc_fmri, 4383 ud_name); 4384 r = 0; 4385 goto out; 4386 4387 case SCF_ERROR_PERMISSION_DENIED: 4388 warn(emsg_pg_deleted, ud_ctarg, 4389 ud_name); 4390 r = EPERM; 4391 goto out; 4392 4393 case SCF_ERROR_EXISTS: 4394 warn(emsg_pg_added, ud_ctarg, ud_name); 4395 r = EBUSY; 4396 goto out; 4397 4398 case SCF_ERROR_NOT_BOUND: 4399 case SCF_ERROR_HANDLE_MISMATCH: 4400 case SCF_ERROR_INVALID_ARGUMENT: 4401 case SCF_ERROR_NOT_SET: 4402 default: 4403 bad_error("entity_add_pg", scf_error()); 4404 } 4405 } 4406 } 4407 4408 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4409 switch (r) { 4410 case 0: 4411 break; 4412 4413 case ECANCELED: 4414 warn(cf_missing, ient->sc_fmri, ud_name); 4415 goto out; 4416 4417 case ECONNABORTED: 4418 case ENOMEM: 4419 case EBADF: 4420 goto out; 4421 4422 case EACCES: 4423 default: 4424 bad_error("load_pg", r); 4425 } 4426 4427 if (g_verbose) 4428 warn(upgrading, ient->sc_fmri, ud_name); 4429 4430 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4431 new_dpt_pgroup, 0, ient->sc_fmri); 4432 switch (r) { 4433 case 0: 4434 break; 4435 4436 case ECANCELED: 4437 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4438 r = EBUSY; 4439 goto out; 4440 4441 case EPERM: 4442 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4443 goto out; 4444 4445 case EBUSY: 4446 warn(emsg_pg_changed, ud_ctarg, ud_name); 4447 goto out; 4448 4449 case ECONNABORTED: 4450 case ENOMEM: 4451 case ENOSPC: 4452 case EROFS: 4453 case EACCES: 4454 case EINVAL: 4455 goto out; 4456 4457 default: 4458 bad_error("upgrade_pg", r); 4459 } 4460 break; 4461 4462 case 0: { 4463 scf_transaction_entry_t *ent; 4464 scf_value_t *val; 4465 4466 internal_pgroup_free(current_pg); 4467 4468 /* delete old pg */ 4469 if (g_verbose) 4470 warn(upgrading, ient->sc_fmri, ud_name); 4471 4472 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4473 switch (scf_error()) { 4474 case SCF_ERROR_CONNECTION_BROKEN: 4475 r = scferror2errno(scf_error()); 4476 goto out; 4477 4478 case SCF_ERROR_DELETED: 4479 warn(cf_missing, ient->sc_fmri, ud_name); 4480 r = 0; 4481 goto out; 4482 4483 case SCF_ERROR_NOT_FOUND: 4484 break; 4485 4486 case SCF_ERROR_INVALID_ARGUMENT: 4487 case SCF_ERROR_NOT_BOUND: 4488 case SCF_ERROR_NOT_SET: 4489 case SCF_ERROR_HANDLE_MISMATCH: 4490 default: 4491 bad_error("entity_get_pg", scf_error()); 4492 } 4493 } else if (scf_pg_delete(ud_pg) != 0) { 4494 switch (scf_error()) { 4495 case SCF_ERROR_DELETED: 4496 break; 4497 4498 case SCF_ERROR_CONNECTION_BROKEN: 4499 case SCF_ERROR_BACKEND_READONLY: 4500 case SCF_ERROR_BACKEND_ACCESS: 4501 r = scferror2errno(scf_error()); 4502 goto out; 4503 4504 case SCF_ERROR_PERMISSION_DENIED: 4505 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4506 r = scferror2errno(scf_error()); 4507 goto out; 4508 4509 case SCF_ERROR_NOT_SET: 4510 default: 4511 bad_error("scf_pg_delete", scf_error()); 4512 } 4513 } 4514 4515 /* import new one */ 4516 cbdata.sc_handle = g_hndl; 4517 cbdata.sc_trans = NULL; /* handled below */ 4518 4519 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 4520 if (r != UU_WALK_NEXT) { 4521 if (r != UU_WALK_ERROR) 4522 bad_error("lscf_dependent_import", r); 4523 4524 r = cbdata.sc_err; 4525 goto out; 4526 } 4527 4528 if (tx == NULL) 4529 break; 4530 4531 if ((ent = scf_entry_create(g_hndl)) == NULL || 4532 (val = scf_value_create(g_hndl)) == NULL) { 4533 if (scf_error() == SCF_ERROR_NO_MEMORY) 4534 return (ENOMEM); 4535 4536 bad_error("scf_entry_create", scf_error()); 4537 } 4538 4539 if (scf_transaction_property_change_type(tx, ent, ud_name, 4540 SCF_TYPE_FMRI) != 0) { 4541 switch (scf_error()) { 4542 case SCF_ERROR_CONNECTION_BROKEN: 4543 r = scferror2errno(scf_error()); 4544 goto out; 4545 4546 case SCF_ERROR_DELETED: 4547 warn(emsg_pg_deleted, ient->sc_fmri, 4548 "dependents"); 4549 r = EBUSY; 4550 goto out; 4551 4552 case SCF_ERROR_NOT_FOUND: 4553 break; 4554 4555 case SCF_ERROR_NOT_BOUND: 4556 case SCF_ERROR_HANDLE_MISMATCH: 4557 case SCF_ERROR_INVALID_ARGUMENT: 4558 case SCF_ERROR_NOT_SET: 4559 default: 4560 bad_error("scf_transaction_property_" 4561 "change_type", scf_error()); 4562 } 4563 4564 if (scf_transaction_property_new(tx, ent, ud_name, 4565 SCF_TYPE_FMRI) != 0) { 4566 switch (scf_error()) { 4567 case SCF_ERROR_CONNECTION_BROKEN: 4568 r = scferror2errno(scf_error()); 4569 goto out; 4570 4571 case SCF_ERROR_DELETED: 4572 warn(emsg_pg_deleted, ient->sc_fmri, 4573 "dependents"); 4574 r = EBUSY; 4575 goto out; 4576 4577 case SCF_ERROR_EXISTS: 4578 warn(emsg_pg_changed, ient->sc_fmri, 4579 "dependents"); 4580 r = EBUSY; 4581 goto out; 4582 4583 case SCF_ERROR_INVALID_ARGUMENT: 4584 case SCF_ERROR_HANDLE_MISMATCH: 4585 case SCF_ERROR_NOT_BOUND: 4586 case SCF_ERROR_NOT_SET: 4587 default: 4588 bad_error("scf_transaction_property_" 4589 "new", scf_error()); 4590 } 4591 } 4592 } 4593 4594 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 4595 new_dpt_pgroup->sc_pgroup_fmri) != 0) 4596 /* invalid sc_pgroup_fmri caught above */ 4597 bad_error("scf_value_set_from_string", 4598 scf_error()); 4599 4600 if (scf_entry_add_value(ent, val) != 0) 4601 bad_error("scf_entry_add_value", scf_error()); 4602 break; 4603 } 4604 4605 case -2: 4606 warn(li_corrupt, ient->sc_fmri); 4607 internal_pgroup_free(current_pg); 4608 r = EBADF; 4609 goto out; 4610 4611 case -1: 4612 default: 4613 /* invalid sc_pgroup_fmri caught above */ 4614 bad_error("fmri_equal", r); 4615 } 4616 4617 r = 0; 4618 4619 out: 4620 if (old_dpt_pgroup != NULL) 4621 internal_pgroup_free(old_dpt_pgroup); 4622 4623 return (r); 4624 } 4625 4626 /* 4627 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 4628 * would import it, except it seems to exist in the service anyway. Compare 4629 * the existent dependent with the one we would import, and report any 4630 * differences (if there are none, be silent). prop is the property which 4631 * represents the existent dependent (in the dependents property group) in the 4632 * entity corresponding to ient. 4633 * 4634 * Returns 4635 * 0 - success (Sort of. At least, we can continue importing.) 4636 * ECONNABORTED - repository connection broken 4637 * EBUSY - ancestor of prop was deleted (error printed) 4638 * ENOMEM - out of memory 4639 * EBADF - corrupt property group (error printed) 4640 * EINVAL - new_dpt_pgroup has invalid target (error printed) 4641 */ 4642 static int 4643 handle_dependent_conflict(const entity_t * const ient, 4644 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 4645 { 4646 int r; 4647 scf_type_t ty; 4648 scf_error_t scfe; 4649 void *tptr; 4650 int tissvc; 4651 pgroup_t *pgroup; 4652 4653 if (scf_property_get_value(prop, ud_val) != 0) { 4654 switch (scf_error()) { 4655 case SCF_ERROR_CONNECTION_BROKEN: 4656 return (scferror2errno(scf_error())); 4657 4658 case SCF_ERROR_DELETED: 4659 warn(emsg_pg_deleted, ient->sc_fmri, 4660 new_dpt_pgroup->sc_pgroup_name); 4661 return (EBUSY); 4662 4663 case SCF_ERROR_CONSTRAINT_VIOLATED: 4664 case SCF_ERROR_NOT_FOUND: 4665 warn(gettext("Conflict upgrading %s (not importing " 4666 "dependent \"%s\" because it already exists.) " 4667 "Warning: The \"%s/%2$s\" property has more or " 4668 "fewer than one value)).\n"), ient->sc_fmri, 4669 new_dpt_pgroup->sc_pgroup_name, "dependents"); 4670 return (0); 4671 4672 case SCF_ERROR_HANDLE_MISMATCH: 4673 case SCF_ERROR_NOT_BOUND: 4674 case SCF_ERROR_NOT_SET: 4675 case SCF_ERROR_PERMISSION_DENIED: 4676 default: 4677 bad_error("scf_property_get_value", 4678 scf_error()); 4679 } 4680 } 4681 4682 ty = scf_value_type(ud_val); 4683 assert(ty != SCF_TYPE_INVALID); 4684 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4685 warn(gettext("Conflict upgrading %s (not importing dependent " 4686 "\"%s\" because it already exists). Warning: The " 4687 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 4688 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 4689 scf_type_to_string(ty), "dependents"); 4690 return (0); 4691 } 4692 4693 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4694 0) 4695 bad_error("scf_value_get_as_string", scf_error()); 4696 4697 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4698 switch (r) { 4699 case 0: 4700 warn(gettext("Conflict upgrading %s (not importing dependent " 4701 "\"%s\" (target \"%s\") because it already exists with " 4702 "target \"%s\").\n"), ient->sc_fmri, 4703 new_dpt_pgroup->sc_pgroup_name, 4704 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 4705 return (0); 4706 4707 case 1: 4708 break; 4709 4710 case -1: 4711 warn(gettext("Conflict upgrading %s (not importing dependent " 4712 "\"%s\" because it already exists). Warning: The current " 4713 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 4714 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4715 return (0); 4716 4717 case -2: 4718 warn(gettext("Dependent \"%s\" of %s has invalid target " 4719 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 4720 new_dpt_pgroup->sc_pgroup_fmri); 4721 return (EINVAL); 4722 4723 default: 4724 bad_error("fmri_equal", r); 4725 } 4726 4727 /* compare dependency pgs in target */ 4728 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 4729 switch (scfe) { 4730 case SCF_ERROR_NONE: 4731 break; 4732 4733 case SCF_ERROR_NO_MEMORY: 4734 return (ENOMEM); 4735 4736 case SCF_ERROR_NOT_FOUND: 4737 warn(emsg_dpt_dangling, ient->sc_fmri, 4738 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4739 return (0); 4740 4741 case SCF_ERROR_CONSTRAINT_VIOLATED: 4742 case SCF_ERROR_INVALID_ARGUMENT: 4743 default: 4744 bad_error("fmri_to_entity", scfe); 4745 } 4746 4747 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 4748 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 4749 switch (r) { 4750 case 0: 4751 break; 4752 4753 case ECONNABORTED: 4754 return (r); 4755 4756 case ECANCELED: 4757 warn(emsg_dpt_dangling, ient->sc_fmri, 4758 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4759 return (0); 4760 4761 case EBADF: 4762 if (tissvc) 4763 warn(gettext("%s has an instance with a \"%s\" " 4764 "snapshot which is missing a snaplevel.\n"), 4765 ud_ctarg, "running"); 4766 else 4767 warn(gettext("%s has a \"%s\" snapshot which is " 4768 "missing a snaplevel.\n"), ud_ctarg, "running"); 4769 /* FALLTHROUGH */ 4770 4771 case ENOENT: 4772 warn(emsg_dpt_no_dep, ient->sc_fmri, 4773 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4774 new_dpt_pgroup->sc_pgroup_name); 4775 return (0); 4776 4777 case EINVAL: 4778 default: 4779 bad_error("entity_get_running_pg", r); 4780 } 4781 4782 pgroup = internal_pgroup_new(); 4783 if (pgroup == NULL) 4784 return (ENOMEM); 4785 4786 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 4787 switch (r) { 4788 case 0: 4789 break; 4790 4791 case ECONNABORTED: 4792 case EBADF: 4793 case ENOMEM: 4794 internal_pgroup_free(pgroup); 4795 return (r); 4796 4797 case ECANCELED: 4798 warn(emsg_dpt_no_dep, ient->sc_fmri, 4799 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4800 new_dpt_pgroup->sc_pgroup_name); 4801 internal_pgroup_free(pgroup); 4802 return (0); 4803 4804 case EACCES: 4805 default: 4806 bad_error("load_pg", r); 4807 } 4808 4809 /* report differences */ 4810 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 4811 internal_pgroup_free(pgroup); 4812 return (0); 4813 } 4814 4815 /* 4816 * lipg is a property group in the last-import snapshot of ent, which is an 4817 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 4818 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 4819 * in ents's property groups, compare and upgrade ent appropriately. 4820 * 4821 * Returns 4822 * 0 - success 4823 * ECONNABORTED - repository connection broken 4824 * ENOMEM - out of memory 4825 * ENOSPC - configd is out of resources 4826 * EINVAL - ient has invalid dependent (error printed) 4827 * - ient has invalid pgroup_t (error printed) 4828 * ECANCELED - ent has been deleted 4829 * ENODEV - entity containing lipg has been deleted 4830 * - entity containing running has been deleted 4831 * EPERM - could not delete pg (permission denied) (error printed) 4832 * - couldn't upgrade dependents (permission denied) (error printed) 4833 * - couldn't import pg (permission denied) (error printed) 4834 * - couldn't upgrade pg (permission denied) (error printed) 4835 * EROFS - could not delete pg (repository read-only) 4836 * - couldn't upgrade dependents (repository read-only) 4837 * - couldn't import pg (repository read-only) 4838 * - couldn't upgrade pg (repository read-only) 4839 * EACCES - could not delete pg (backend access denied) 4840 * - couldn't upgrade dependents (backend access denied) 4841 * - couldn't import pg (backend access denied) 4842 * - couldn't upgrade pg (backend access denied) 4843 * - couldn't read property (backend access denied) 4844 * EBUSY - property group was added (error printed) 4845 * - property group was deleted (error printed) 4846 * - property group changed (error printed) 4847 * - "dependents" pg was added, changed, or deleted (error printed) 4848 * - dependent target deleted (error printed) 4849 * - dependent pg changed (error printed) 4850 * EBADF - imp_snpl is corrupt (error printed) 4851 * - ent has bad pg (error printed) 4852 * EEXIST - dependent collision in target service (error printed) 4853 */ 4854 static int 4855 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 4856 const scf_snaplevel_t *running) 4857 { 4858 int r; 4859 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 4860 scf_callback_t cbdata; 4861 4862 const char * const cf_pg_missing = 4863 gettext("Conflict upgrading %s (property group %s is missing)\n"); 4864 const char * const deleting = 4865 gettext("%s: Deleting property group \"%s\".\n"); 4866 4867 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 4868 4869 /* Skip dependent property groups. */ 4870 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 4871 switch (scf_error()) { 4872 case SCF_ERROR_DELETED: 4873 return (ENODEV); 4874 4875 case SCF_ERROR_CONNECTION_BROKEN: 4876 return (ECONNABORTED); 4877 4878 case SCF_ERROR_NOT_SET: 4879 case SCF_ERROR_NOT_BOUND: 4880 default: 4881 bad_error("scf_pg_get_type", scf_error()); 4882 } 4883 } 4884 4885 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 4886 if (scf_pg_get_property(lipg, "external", NULL) == 0) 4887 return (0); 4888 4889 switch (scf_error()) { 4890 case SCF_ERROR_NOT_FOUND: 4891 break; 4892 4893 case SCF_ERROR_CONNECTION_BROKEN: 4894 return (ECONNABORTED); 4895 4896 case SCF_ERROR_DELETED: 4897 return (ENODEV); 4898 4899 case SCF_ERROR_INVALID_ARGUMENT: 4900 case SCF_ERROR_NOT_BOUND: 4901 case SCF_ERROR_HANDLE_MISMATCH: 4902 case SCF_ERROR_NOT_SET: 4903 default: 4904 bad_error("scf_pg_get_property", scf_error()); 4905 } 4906 } 4907 4908 /* lookup pg in new properties */ 4909 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 4910 switch (scf_error()) { 4911 case SCF_ERROR_DELETED: 4912 return (ENODEV); 4913 4914 case SCF_ERROR_CONNECTION_BROKEN: 4915 return (ECONNABORTED); 4916 4917 case SCF_ERROR_NOT_SET: 4918 case SCF_ERROR_NOT_BOUND: 4919 default: 4920 bad_error("scf_pg_get_name", scf_error()); 4921 } 4922 } 4923 4924 pgrp.sc_pgroup_name = imp_str; 4925 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 4926 4927 if (mpg != NULL) 4928 mpg->sc_pgroup_seen = 1; 4929 4930 /* Special handling for dependents */ 4931 if (strcmp(imp_str, "dependents") == 0) 4932 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 4933 4934 if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0) 4935 return (upgrade_manifestfiles(NULL, ient, running, ent)); 4936 4937 if (mpg == NULL || mpg->sc_pgroup_delete) { 4938 /* property group was deleted from manifest */ 4939 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 4940 switch (scf_error()) { 4941 case SCF_ERROR_NOT_FOUND: 4942 return (0); 4943 4944 case SCF_ERROR_DELETED: 4945 case SCF_ERROR_CONNECTION_BROKEN: 4946 return (scferror2errno(scf_error())); 4947 4948 case SCF_ERROR_INVALID_ARGUMENT: 4949 case SCF_ERROR_HANDLE_MISMATCH: 4950 case SCF_ERROR_NOT_BOUND: 4951 case SCF_ERROR_NOT_SET: 4952 default: 4953 bad_error("entity_get_pg", scf_error()); 4954 } 4955 } 4956 4957 if (mpg != NULL && mpg->sc_pgroup_delete) { 4958 if (g_verbose) 4959 warn(deleting, ient->sc_fmri, imp_str); 4960 if (scf_pg_delete(imp_pg2) == 0) 4961 return (0); 4962 4963 switch (scf_error()) { 4964 case SCF_ERROR_DELETED: 4965 return (0); 4966 4967 case SCF_ERROR_CONNECTION_BROKEN: 4968 case SCF_ERROR_BACKEND_READONLY: 4969 case SCF_ERROR_BACKEND_ACCESS: 4970 return (scferror2errno(scf_error())); 4971 4972 case SCF_ERROR_PERMISSION_DENIED: 4973 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 4974 return (scferror2errno(scf_error())); 4975 4976 case SCF_ERROR_NOT_SET: 4977 default: 4978 bad_error("scf_pg_delete", scf_error()); 4979 } 4980 } 4981 4982 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 4983 switch (r) { 4984 case 0: 4985 break; 4986 4987 case ECANCELED: 4988 return (ENODEV); 4989 4990 case ECONNABORTED: 4991 case ENOMEM: 4992 case EBADF: 4993 case EACCES: 4994 return (r); 4995 4996 default: 4997 bad_error("load_pg", r); 4998 } 4999 5000 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5001 switch (r) { 5002 case 0: 5003 break; 5004 5005 case ECANCELED: 5006 case ECONNABORTED: 5007 case ENOMEM: 5008 case EBADF: 5009 case EACCES: 5010 internal_pgroup_free(lipg_i); 5011 return (r); 5012 5013 default: 5014 bad_error("load_pg", r); 5015 } 5016 5017 if (pg_equal(lipg_i, curpg_i)) { 5018 if (g_verbose) 5019 warn(deleting, ient->sc_fmri, imp_str); 5020 if (scf_pg_delete(imp_pg2) != 0) { 5021 switch (scf_error()) { 5022 case SCF_ERROR_DELETED: 5023 break; 5024 5025 case SCF_ERROR_CONNECTION_BROKEN: 5026 internal_pgroup_free(lipg_i); 5027 internal_pgroup_free(curpg_i); 5028 return (ECONNABORTED); 5029 5030 case SCF_ERROR_NOT_SET: 5031 case SCF_ERROR_NOT_BOUND: 5032 default: 5033 bad_error("scf_pg_delete", scf_error()); 5034 } 5035 } 5036 } else { 5037 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 5038 } 5039 5040 internal_pgroup_free(lipg_i); 5041 internal_pgroup_free(curpg_i); 5042 5043 return (0); 5044 } 5045 5046 /* 5047 * Only dependent pgs can have override set, and we skipped those 5048 * above. 5049 */ 5050 assert(!mpg->sc_pgroup_override); 5051 5052 /* compare */ 5053 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 5054 switch (r) { 5055 case 0: 5056 break; 5057 5058 case ECANCELED: 5059 return (ENODEV); 5060 5061 case ECONNABORTED: 5062 case EBADF: 5063 case ENOMEM: 5064 case EACCES: 5065 return (r); 5066 5067 default: 5068 bad_error("load_pg", r); 5069 } 5070 5071 if (pg_equal(mpg, lipg_i)) { 5072 /* The manifest pg has not changed. Move on. */ 5073 r = 0; 5074 goto out; 5075 } 5076 5077 /* upgrade current properties according to lipg & mpg */ 5078 if (running != NULL) 5079 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 5080 else 5081 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 5082 if (r != 0) { 5083 switch (scf_error()) { 5084 case SCF_ERROR_CONNECTION_BROKEN: 5085 r = scferror2errno(scf_error()); 5086 goto out; 5087 5088 case SCF_ERROR_DELETED: 5089 if (running != NULL) 5090 r = ENODEV; 5091 else 5092 r = ECANCELED; 5093 goto out; 5094 5095 case SCF_ERROR_NOT_FOUND: 5096 break; 5097 5098 case SCF_ERROR_INVALID_ARGUMENT: 5099 case SCF_ERROR_HANDLE_MISMATCH: 5100 case SCF_ERROR_NOT_BOUND: 5101 case SCF_ERROR_NOT_SET: 5102 default: 5103 bad_error("entity_get_pg", scf_error()); 5104 } 5105 5106 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5107 5108 r = 0; 5109 goto out; 5110 } 5111 5112 r = load_pg_attrs(imp_pg2, &curpg_i); 5113 switch (r) { 5114 case 0: 5115 break; 5116 5117 case ECANCELED: 5118 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5119 r = 0; 5120 goto out; 5121 5122 case ECONNABORTED: 5123 case ENOMEM: 5124 goto out; 5125 5126 default: 5127 bad_error("load_pg_attrs", r); 5128 } 5129 5130 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 5131 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 5132 internal_pgroup_free(curpg_i); 5133 r = 0; 5134 goto out; 5135 } 5136 5137 internal_pgroup_free(curpg_i); 5138 5139 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 5140 switch (r) { 5141 case 0: 5142 break; 5143 5144 case ECANCELED: 5145 warn(cf_pg_missing, ient->sc_fmri, imp_str); 5146 r = 0; 5147 goto out; 5148 5149 case ECONNABORTED: 5150 case EBADF: 5151 case ENOMEM: 5152 case EACCES: 5153 goto out; 5154 5155 default: 5156 bad_error("load_pg", r); 5157 } 5158 5159 if (pg_equal(lipg_i, curpg_i) && 5160 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 5161 int do_delete = 1; 5162 5163 if (g_verbose) 5164 warn(gettext("%s: Upgrading property group \"%s\".\n"), 5165 ient->sc_fmri, mpg->sc_pgroup_name); 5166 5167 internal_pgroup_free(curpg_i); 5168 5169 if (running != NULL && 5170 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5171 switch (scf_error()) { 5172 case SCF_ERROR_DELETED: 5173 r = ECANCELED; 5174 goto out; 5175 5176 case SCF_ERROR_NOT_FOUND: 5177 do_delete = 0; 5178 break; 5179 5180 case SCF_ERROR_CONNECTION_BROKEN: 5181 r = scferror2errno(scf_error()); 5182 goto out; 5183 5184 case SCF_ERROR_HANDLE_MISMATCH: 5185 case SCF_ERROR_INVALID_ARGUMENT: 5186 case SCF_ERROR_NOT_SET: 5187 case SCF_ERROR_NOT_BOUND: 5188 default: 5189 bad_error("entity_get_pg", scf_error()); 5190 } 5191 } 5192 5193 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 5194 switch (scf_error()) { 5195 case SCF_ERROR_DELETED: 5196 break; 5197 5198 case SCF_ERROR_CONNECTION_BROKEN: 5199 case SCF_ERROR_BACKEND_READONLY: 5200 case SCF_ERROR_BACKEND_ACCESS: 5201 r = scferror2errno(scf_error()); 5202 goto out; 5203 5204 case SCF_ERROR_PERMISSION_DENIED: 5205 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 5206 ient->sc_fmri); 5207 r = scferror2errno(scf_error()); 5208 goto out; 5209 5210 case SCF_ERROR_NOT_SET: 5211 case SCF_ERROR_NOT_BOUND: 5212 default: 5213 bad_error("scf_pg_delete", scf_error()); 5214 } 5215 } 5216 5217 cbdata.sc_handle = g_hndl; 5218 cbdata.sc_parent = ent; 5219 cbdata.sc_service = issvc; 5220 cbdata.sc_flags = 0; 5221 cbdata.sc_source_fmri = ient->sc_fmri; 5222 cbdata.sc_target_fmri = ient->sc_fmri; 5223 5224 r = entity_pgroup_import(mpg, &cbdata); 5225 switch (r) { 5226 case UU_WALK_NEXT: 5227 r = 0; 5228 goto out; 5229 5230 case UU_WALK_ERROR: 5231 if (cbdata.sc_err == EEXIST) { 5232 warn(emsg_pg_added, ient->sc_fmri, 5233 mpg->sc_pgroup_name); 5234 r = EBUSY; 5235 } else { 5236 r = cbdata.sc_err; 5237 } 5238 goto out; 5239 5240 default: 5241 bad_error("entity_pgroup_import", r); 5242 } 5243 } 5244 5245 if (running != NULL && 5246 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5247 switch (scf_error()) { 5248 case SCF_ERROR_CONNECTION_BROKEN: 5249 case SCF_ERROR_DELETED: 5250 r = scferror2errno(scf_error()); 5251 goto out; 5252 5253 case SCF_ERROR_NOT_FOUND: 5254 break; 5255 5256 case SCF_ERROR_HANDLE_MISMATCH: 5257 case SCF_ERROR_INVALID_ARGUMENT: 5258 case SCF_ERROR_NOT_SET: 5259 case SCF_ERROR_NOT_BOUND: 5260 default: 5261 bad_error("entity_get_pg", scf_error()); 5262 } 5263 5264 cbdata.sc_handle = g_hndl; 5265 cbdata.sc_parent = ent; 5266 cbdata.sc_service = issvc; 5267 cbdata.sc_flags = SCI_FORCE; 5268 cbdata.sc_source_fmri = ient->sc_fmri; 5269 cbdata.sc_target_fmri = ient->sc_fmri; 5270 5271 r = entity_pgroup_import(mpg, &cbdata); 5272 switch (r) { 5273 case UU_WALK_NEXT: 5274 r = 0; 5275 goto out; 5276 5277 case UU_WALK_ERROR: 5278 if (cbdata.sc_err == EEXIST) { 5279 warn(emsg_pg_added, ient->sc_fmri, 5280 mpg->sc_pgroup_name); 5281 r = EBUSY; 5282 } else { 5283 r = cbdata.sc_err; 5284 } 5285 goto out; 5286 5287 default: 5288 bad_error("entity_pgroup_import", r); 5289 } 5290 } 5291 5292 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5293 internal_pgroup_free(curpg_i); 5294 switch (r) { 5295 case 0: 5296 ient->sc_import_state = IMPORT_PROP_BEGUN; 5297 break; 5298 5299 case ECANCELED: 5300 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5301 r = EBUSY; 5302 break; 5303 5304 case EPERM: 5305 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5306 break; 5307 5308 case EBUSY: 5309 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5310 break; 5311 5312 case ECONNABORTED: 5313 case ENOMEM: 5314 case ENOSPC: 5315 case EROFS: 5316 case EACCES: 5317 case EINVAL: 5318 break; 5319 5320 default: 5321 bad_error("upgrade_pg", r); 5322 } 5323 5324 out: 5325 internal_pgroup_free(lipg_i); 5326 return (r); 5327 } 5328 5329 /* 5330 * Upgrade the properties of ent according to snpl & ient. 5331 * 5332 * Returns 5333 * 0 - success 5334 * ECONNABORTED - repository connection broken 5335 * ENOMEM - out of memory 5336 * ENOSPC - configd is out of resources 5337 * ECANCELED - ent was deleted 5338 * ENODEV - entity containing snpl was deleted 5339 * - entity containing running was deleted 5340 * EBADF - imp_snpl is corrupt (error printed) 5341 * - ent has corrupt pg (error printed) 5342 * - dependent has corrupt pg (error printed) 5343 * - dependent target has a corrupt snapshot (error printed) 5344 * EBUSY - pg was added, changed, or deleted (error printed) 5345 * - dependent target was deleted (error printed) 5346 * - dependent pg changed (error printed) 5347 * EINVAL - invalid property group name (error printed) 5348 * - invalid property name (error printed) 5349 * - invalid value (error printed) 5350 * - ient has invalid pgroup or dependent (error printed) 5351 * EPERM - could not create property group (permission denied) (error printed) 5352 * - could not modify property group (permission denied) (error printed) 5353 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5354 * EROFS - could not create property group (repository read-only) 5355 * - couldn't delete, upgrade, or import pg or dependent 5356 * EACCES - could not create property group (backend access denied) 5357 * - couldn't delete, upgrade, or import pg or dependent 5358 * EEXIST - dependent collision in target service (error printed) 5359 */ 5360 static int 5361 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5362 entity_t *ient) 5363 { 5364 pgroup_t *pg, *rpg; 5365 int r; 5366 uu_list_t *pgs = ient->sc_pgroups; 5367 5368 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5369 5370 /* clear sc_sceen for pgs */ 5371 if (uu_list_walk(pgs, clear_int, 5372 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5373 bad_error("uu_list_walk", uu_error()); 5374 5375 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5376 switch (scf_error()) { 5377 case SCF_ERROR_DELETED: 5378 return (ENODEV); 5379 5380 case SCF_ERROR_CONNECTION_BROKEN: 5381 return (ECONNABORTED); 5382 5383 case SCF_ERROR_NOT_SET: 5384 case SCF_ERROR_NOT_BOUND: 5385 case SCF_ERROR_HANDLE_MISMATCH: 5386 default: 5387 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5388 } 5389 } 5390 5391 for (;;) { 5392 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5393 if (r == 0) 5394 break; 5395 if (r == 1) { 5396 r = process_old_pg(imp_pg, ient, ent, running); 5397 switch (r) { 5398 case 0: 5399 break; 5400 5401 case ECONNABORTED: 5402 case ENOMEM: 5403 case ENOSPC: 5404 case ECANCELED: 5405 case ENODEV: 5406 case EPERM: 5407 case EROFS: 5408 case EACCES: 5409 case EBADF: 5410 case EBUSY: 5411 case EINVAL: 5412 case EEXIST: 5413 return (r); 5414 5415 default: 5416 bad_error("process_old_pg", r); 5417 } 5418 continue; 5419 } 5420 if (r != -1) 5421 bad_error("scf_iter_next_pg", r); 5422 5423 switch (scf_error()) { 5424 case SCF_ERROR_DELETED: 5425 return (ENODEV); 5426 5427 case SCF_ERROR_CONNECTION_BROKEN: 5428 return (ECONNABORTED); 5429 5430 case SCF_ERROR_HANDLE_MISMATCH: 5431 case SCF_ERROR_NOT_BOUND: 5432 case SCF_ERROR_NOT_SET: 5433 case SCF_ERROR_INVALID_ARGUMENT: 5434 default: 5435 bad_error("scf_iter_next_pg", scf_error()); 5436 } 5437 } 5438 5439 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5440 if (pg->sc_pgroup_seen) 5441 continue; 5442 5443 /* pg is new */ 5444 5445 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5446 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5447 ent); 5448 switch (r) { 5449 case 0: 5450 break; 5451 5452 case ECONNABORTED: 5453 case ENOMEM: 5454 case ENOSPC: 5455 case ECANCELED: 5456 case ENODEV: 5457 case EBADF: 5458 case EBUSY: 5459 case EINVAL: 5460 case EPERM: 5461 case EROFS: 5462 case EACCES: 5463 case EEXIST: 5464 return (r); 5465 5466 default: 5467 bad_error("upgrade_dependents", r); 5468 } 5469 continue; 5470 } 5471 5472 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) { 5473 r = upgrade_manifestfiles(pg, ient, running, ent); 5474 switch (r) { 5475 case 0: 5476 break; 5477 5478 case ECONNABORTED: 5479 case ENOMEM: 5480 case ENOSPC: 5481 case ECANCELED: 5482 case ENODEV: 5483 case EBADF: 5484 case EBUSY: 5485 case EINVAL: 5486 case EPERM: 5487 case EROFS: 5488 case EACCES: 5489 case EEXIST: 5490 return (r); 5491 5492 default: 5493 bad_error("upgrade_manifestfiles", r); 5494 } 5495 continue; 5496 } 5497 5498 if (running != NULL) { 5499 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 5500 imp_pg); 5501 } else { 5502 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 5503 imp_pg); 5504 } 5505 if (r != 0) { 5506 scf_callback_t cbdata; 5507 5508 switch (scf_error()) { 5509 case SCF_ERROR_NOT_FOUND: 5510 break; 5511 5512 case SCF_ERROR_CONNECTION_BROKEN: 5513 return (scferror2errno(scf_error())); 5514 5515 case SCF_ERROR_DELETED: 5516 if (running != NULL) 5517 return (ENODEV); 5518 else 5519 return (scferror2errno(scf_error())); 5520 5521 case SCF_ERROR_INVALID_ARGUMENT: 5522 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 5523 pg->sc_pgroup_name); 5524 return (EINVAL); 5525 5526 case SCF_ERROR_NOT_SET: 5527 case SCF_ERROR_HANDLE_MISMATCH: 5528 case SCF_ERROR_NOT_BOUND: 5529 default: 5530 bad_error("entity_get_pg", scf_error()); 5531 } 5532 5533 /* User doesn't have pg, so import it. */ 5534 5535 cbdata.sc_handle = g_hndl; 5536 cbdata.sc_parent = ent; 5537 cbdata.sc_service = issvc; 5538 cbdata.sc_flags = SCI_FORCE; 5539 cbdata.sc_source_fmri = ient->sc_fmri; 5540 cbdata.sc_target_fmri = ient->sc_fmri; 5541 5542 r = entity_pgroup_import(pg, &cbdata); 5543 switch (r) { 5544 case UU_WALK_NEXT: 5545 ient->sc_import_state = IMPORT_PROP_BEGUN; 5546 continue; 5547 5548 case UU_WALK_ERROR: 5549 if (cbdata.sc_err == EEXIST) { 5550 warn(emsg_pg_added, ient->sc_fmri, 5551 pg->sc_pgroup_name); 5552 return (EBUSY); 5553 } 5554 return (cbdata.sc_err); 5555 5556 default: 5557 bad_error("entity_pgroup_import", r); 5558 } 5559 } 5560 5561 /* report differences between pg & current */ 5562 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 5563 switch (r) { 5564 case 0: 5565 break; 5566 5567 case ECANCELED: 5568 warn(emsg_pg_deleted, ient->sc_fmri, 5569 pg->sc_pgroup_name); 5570 return (EBUSY); 5571 5572 case ECONNABORTED: 5573 case EBADF: 5574 case ENOMEM: 5575 case EACCES: 5576 return (r); 5577 5578 default: 5579 bad_error("load_pg", r); 5580 } 5581 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 5582 internal_pgroup_free(rpg); 5583 rpg = NULL; 5584 } 5585 5586 return (0); 5587 } 5588 5589 /* 5590 * Import an instance. If it doesn't exist, create it. If it has 5591 * a last-import snapshot, upgrade its properties. Finish by updating its 5592 * last-import snapshot. If it doesn't have a last-import snapshot then it 5593 * could have been created for a dependent tag in another manifest. Import the 5594 * new properties. If there's a conflict, don't override, like now? 5595 * 5596 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 5597 * lcbdata->sc_err to 5598 * ECONNABORTED - repository connection broken 5599 * ENOMEM - out of memory 5600 * ENOSPC - svc.configd is out of resources 5601 * EEXIST - dependency collision in dependent service (error printed) 5602 * EPERM - couldn't create temporary instance (permission denied) 5603 * - couldn't import into temporary instance (permission denied) 5604 * - couldn't take snapshot (permission denied) 5605 * - couldn't upgrade properties (permission denied) 5606 * - couldn't import properties (permission denied) 5607 * - couldn't import dependents (permission denied) 5608 * EROFS - couldn't create temporary instance (repository read-only) 5609 * - couldn't import into temporary instance (repository read-only) 5610 * - couldn't upgrade properties (repository read-only) 5611 * - couldn't import properties (repository read-only) 5612 * - couldn't import dependents (repository read-only) 5613 * EACCES - couldn't create temporary instance (backend access denied) 5614 * - couldn't import into temporary instance (backend access denied) 5615 * - couldn't upgrade properties (backend access denied) 5616 * - couldn't import properties (backend access denied) 5617 * - couldn't import dependents (backend access denied) 5618 * EINVAL - invalid instance name (error printed) 5619 * - invalid pgroup_t's (error printed) 5620 * - invalid dependents (error printed) 5621 * EBUSY - temporary service deleted (error printed) 5622 * - temporary instance deleted (error printed) 5623 * - temporary instance changed (error printed) 5624 * - temporary instance already exists (error printed) 5625 * - instance deleted (error printed) 5626 * EBADF - instance has corrupt last-import snapshot (error printed) 5627 * - instance is corrupt (error printed) 5628 * - dependent has corrupt pg (error printed) 5629 * - dependent target has a corrupt snapshot (error printed) 5630 * -1 - unknown libscf error (error printed) 5631 */ 5632 static int 5633 lscf_instance_import(void *v, void *pvt) 5634 { 5635 entity_t *inst = v; 5636 scf_callback_t ctx; 5637 scf_callback_t *lcbdata = pvt; 5638 scf_service_t *rsvc = lcbdata->sc_parent; 5639 int r; 5640 scf_snaplevel_t *running; 5641 int flags = lcbdata->sc_flags; 5642 5643 const char * const emsg_tdel = 5644 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 5645 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 5646 "changed unexpectedly.\n"); 5647 const char * const emsg_del = gettext("%s changed unexpectedly " 5648 "(instance \"%s\" was deleted.)\n"); 5649 const char * const emsg_badsnap = gettext( 5650 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 5651 5652 /* 5653 * prepare last-import snapshot: 5654 * create temporary instance (service was precreated) 5655 * populate with properties from bundle 5656 * take snapshot 5657 */ 5658 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 5659 switch (scf_error()) { 5660 case SCF_ERROR_CONNECTION_BROKEN: 5661 case SCF_ERROR_NO_RESOURCES: 5662 case SCF_ERROR_BACKEND_READONLY: 5663 case SCF_ERROR_BACKEND_ACCESS: 5664 return (stash_scferror(lcbdata)); 5665 5666 case SCF_ERROR_EXISTS: 5667 warn(gettext("Temporary service svc:/%s " 5668 "changed unexpectedly (instance \"%s\" added).\n"), 5669 imp_tsname, inst->sc_name); 5670 lcbdata->sc_err = EBUSY; 5671 return (UU_WALK_ERROR); 5672 5673 case SCF_ERROR_DELETED: 5674 warn(gettext("Temporary service svc:/%s " 5675 "was deleted unexpectedly.\n"), imp_tsname); 5676 lcbdata->sc_err = EBUSY; 5677 return (UU_WALK_ERROR); 5678 5679 case SCF_ERROR_INVALID_ARGUMENT: 5680 warn(gettext("Invalid instance name \"%s\".\n"), 5681 inst->sc_name); 5682 return (stash_scferror(lcbdata)); 5683 5684 case SCF_ERROR_PERMISSION_DENIED: 5685 warn(gettext("Could not create temporary instance " 5686 "\"%s\" in svc:/%s (permission denied).\n"), 5687 inst->sc_name, imp_tsname); 5688 return (stash_scferror(lcbdata)); 5689 5690 case SCF_ERROR_HANDLE_MISMATCH: 5691 case SCF_ERROR_NOT_BOUND: 5692 case SCF_ERROR_NOT_SET: 5693 default: 5694 bad_error("scf_service_add_instance", scf_error()); 5695 } 5696 } 5697 5698 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5699 inst->sc_name); 5700 if (r < 0) 5701 bad_error("snprintf", errno); 5702 5703 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 5704 lcbdata->sc_flags | SCI_NOENABLED); 5705 switch (r) { 5706 case 0: 5707 break; 5708 5709 case ECANCELED: 5710 warn(emsg_tdel, imp_tsname, inst->sc_name); 5711 lcbdata->sc_err = EBUSY; 5712 r = UU_WALK_ERROR; 5713 goto deltemp; 5714 5715 case EEXIST: 5716 warn(emsg_tchg, imp_tsname, inst->sc_name); 5717 lcbdata->sc_err = EBUSY; 5718 r = UU_WALK_ERROR; 5719 goto deltemp; 5720 5721 case ECONNABORTED: 5722 goto connaborted; 5723 5724 case ENOMEM: 5725 case ENOSPC: 5726 case EPERM: 5727 case EROFS: 5728 case EACCES: 5729 case EINVAL: 5730 case EBUSY: 5731 lcbdata->sc_err = r; 5732 r = UU_WALK_ERROR; 5733 goto deltemp; 5734 5735 default: 5736 bad_error("lscf_import_instance_pgs", r); 5737 } 5738 5739 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5740 inst->sc_name); 5741 if (r < 0) 5742 bad_error("snprintf", errno); 5743 5744 ctx.sc_handle = lcbdata->sc_handle; 5745 ctx.sc_parent = imp_tinst; 5746 ctx.sc_service = 0; 5747 ctx.sc_source_fmri = inst->sc_fmri; 5748 ctx.sc_target_fmri = imp_str; 5749 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 5750 UU_DEFAULT) != 0) { 5751 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5752 bad_error("uu_list_walk", uu_error()); 5753 5754 switch (ctx.sc_err) { 5755 case ECONNABORTED: 5756 goto connaborted; 5757 5758 case ECANCELED: 5759 warn(emsg_tdel, imp_tsname, inst->sc_name); 5760 lcbdata->sc_err = EBUSY; 5761 break; 5762 5763 case EEXIST: 5764 warn(emsg_tchg, imp_tsname, inst->sc_name); 5765 lcbdata->sc_err = EBUSY; 5766 break; 5767 5768 default: 5769 lcbdata->sc_err = ctx.sc_err; 5770 } 5771 r = UU_WALK_ERROR; 5772 goto deltemp; 5773 } 5774 5775 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 5776 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 5777 switch (scf_error()) { 5778 case SCF_ERROR_CONNECTION_BROKEN: 5779 goto connaborted; 5780 5781 case SCF_ERROR_NO_RESOURCES: 5782 r = stash_scferror(lcbdata); 5783 goto deltemp; 5784 5785 case SCF_ERROR_EXISTS: 5786 warn(emsg_tchg, imp_tsname, inst->sc_name); 5787 lcbdata->sc_err = EBUSY; 5788 r = UU_WALK_ERROR; 5789 goto deltemp; 5790 5791 case SCF_ERROR_PERMISSION_DENIED: 5792 warn(gettext("Could not take \"%s\" snapshot of %s " 5793 "(permission denied).\n"), snap_lastimport, 5794 imp_str); 5795 r = stash_scferror(lcbdata); 5796 goto deltemp; 5797 5798 default: 5799 scfwarn(); 5800 lcbdata->sc_err = -1; 5801 r = UU_WALK_ERROR; 5802 goto deltemp; 5803 5804 case SCF_ERROR_HANDLE_MISMATCH: 5805 case SCF_ERROR_INVALID_ARGUMENT: 5806 case SCF_ERROR_NOT_SET: 5807 bad_error("_scf_snapshot_take_new_named", scf_error()); 5808 } 5809 } 5810 5811 if (lcbdata->sc_flags & SCI_FRESH) 5812 goto fresh; 5813 5814 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 5815 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 5816 imp_lisnap) != 0) { 5817 switch (scf_error()) { 5818 case SCF_ERROR_DELETED: 5819 warn(emsg_del, inst->sc_parent->sc_fmri, 5820 inst->sc_name); 5821 lcbdata->sc_err = EBUSY; 5822 r = UU_WALK_ERROR; 5823 goto deltemp; 5824 5825 case SCF_ERROR_NOT_FOUND: 5826 flags |= SCI_FORCE; 5827 goto nosnap; 5828 5829 case SCF_ERROR_CONNECTION_BROKEN: 5830 goto connaborted; 5831 5832 case SCF_ERROR_INVALID_ARGUMENT: 5833 case SCF_ERROR_HANDLE_MISMATCH: 5834 case SCF_ERROR_NOT_BOUND: 5835 case SCF_ERROR_NOT_SET: 5836 default: 5837 bad_error("scf_instance_get_snapshot", 5838 scf_error()); 5839 } 5840 } 5841 5842 /* upgrade */ 5843 5844 /* 5845 * compare new properties with last-import properties 5846 * upgrade current properties 5847 */ 5848 /* clear sc_sceen for pgs */ 5849 if (uu_list_walk(inst->sc_pgroups, clear_int, 5850 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 5851 0) 5852 bad_error("uu_list_walk", uu_error()); 5853 5854 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 5855 switch (r) { 5856 case 0: 5857 break; 5858 5859 case ECONNABORTED: 5860 goto connaborted; 5861 5862 case ECANCELED: 5863 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5864 lcbdata->sc_err = EBUSY; 5865 r = UU_WALK_ERROR; 5866 goto deltemp; 5867 5868 case ENOENT: 5869 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 5870 lcbdata->sc_err = EBADF; 5871 r = UU_WALK_ERROR; 5872 goto deltemp; 5873 5874 default: 5875 bad_error("get_snaplevel", r); 5876 } 5877 5878 if (scf_instance_get_snapshot(imp_inst, snap_running, 5879 imp_rsnap) != 0) { 5880 switch (scf_error()) { 5881 case SCF_ERROR_DELETED: 5882 warn(emsg_del, inst->sc_parent->sc_fmri, 5883 inst->sc_name); 5884 lcbdata->sc_err = EBUSY; 5885 r = UU_WALK_ERROR; 5886 goto deltemp; 5887 5888 case SCF_ERROR_NOT_FOUND: 5889 break; 5890 5891 case SCF_ERROR_CONNECTION_BROKEN: 5892 goto connaborted; 5893 5894 case SCF_ERROR_INVALID_ARGUMENT: 5895 case SCF_ERROR_HANDLE_MISMATCH: 5896 case SCF_ERROR_NOT_BOUND: 5897 case SCF_ERROR_NOT_SET: 5898 default: 5899 bad_error("scf_instance_get_snapshot", 5900 scf_error()); 5901 } 5902 5903 running = NULL; 5904 } else { 5905 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 5906 switch (r) { 5907 case 0: 5908 running = imp_rsnpl; 5909 break; 5910 5911 case ECONNABORTED: 5912 goto connaborted; 5913 5914 case ECANCELED: 5915 warn(emsg_del, inst->sc_parent->sc_fmri, 5916 inst->sc_name); 5917 lcbdata->sc_err = EBUSY; 5918 r = UU_WALK_ERROR; 5919 goto deltemp; 5920 5921 case ENOENT: 5922 warn(emsg_badsnap, snap_running, inst->sc_fmri); 5923 lcbdata->sc_err = EBADF; 5924 r = UU_WALK_ERROR; 5925 goto deltemp; 5926 5927 default: 5928 bad_error("get_snaplevel", r); 5929 } 5930 } 5931 5932 r = upgrade_props(imp_inst, running, imp_snpl, inst); 5933 switch (r) { 5934 case 0: 5935 break; 5936 5937 case ECANCELED: 5938 case ENODEV: 5939 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5940 lcbdata->sc_err = EBUSY; 5941 r = UU_WALK_ERROR; 5942 goto deltemp; 5943 5944 case ECONNABORTED: 5945 goto connaborted; 5946 5947 case ENOMEM: 5948 case ENOSPC: 5949 case EBADF: 5950 case EBUSY: 5951 case EINVAL: 5952 case EPERM: 5953 case EROFS: 5954 case EACCES: 5955 case EEXIST: 5956 lcbdata->sc_err = r; 5957 r = UU_WALK_ERROR; 5958 goto deltemp; 5959 5960 default: 5961 bad_error("upgrade_props", r); 5962 } 5963 5964 inst->sc_import_state = IMPORT_PROP_DONE; 5965 } else { 5966 switch (scf_error()) { 5967 case SCF_ERROR_CONNECTION_BROKEN: 5968 goto connaborted; 5969 5970 case SCF_ERROR_NOT_FOUND: 5971 break; 5972 5973 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5974 case SCF_ERROR_HANDLE_MISMATCH: 5975 case SCF_ERROR_NOT_BOUND: 5976 case SCF_ERROR_NOT_SET: 5977 default: 5978 bad_error("scf_service_get_instance", scf_error()); 5979 } 5980 5981 fresh: 5982 /* create instance */ 5983 if (scf_service_add_instance(rsvc, inst->sc_name, 5984 imp_inst) != 0) { 5985 switch (scf_error()) { 5986 case SCF_ERROR_CONNECTION_BROKEN: 5987 goto connaborted; 5988 5989 case SCF_ERROR_NO_RESOURCES: 5990 case SCF_ERROR_BACKEND_READONLY: 5991 case SCF_ERROR_BACKEND_ACCESS: 5992 r = stash_scferror(lcbdata); 5993 goto deltemp; 5994 5995 case SCF_ERROR_EXISTS: 5996 warn(gettext("%s changed unexpectedly " 5997 "(instance \"%s\" added).\n"), 5998 inst->sc_parent->sc_fmri, inst->sc_name); 5999 lcbdata->sc_err = EBUSY; 6000 r = UU_WALK_ERROR; 6001 goto deltemp; 6002 6003 case SCF_ERROR_PERMISSION_DENIED: 6004 warn(gettext("Could not create \"%s\" instance " 6005 "in %s (permission denied).\n"), 6006 inst->sc_name, inst->sc_parent->sc_fmri); 6007 r = stash_scferror(lcbdata); 6008 goto deltemp; 6009 6010 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 6011 case SCF_ERROR_HANDLE_MISMATCH: 6012 case SCF_ERROR_NOT_BOUND: 6013 case SCF_ERROR_NOT_SET: 6014 default: 6015 bad_error("scf_service_add_instance", 6016 scf_error()); 6017 } 6018 } 6019 6020 nosnap: 6021 /* 6022 * Create a last-import snapshot to serve as an attachment 6023 * point for the real one from the temporary instance. Since 6024 * the contents is irrelevant, take it now, while the instance 6025 * is empty, to minimize svc.configd's work. 6026 */ 6027 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 6028 imp_lisnap) != 0) { 6029 switch (scf_error()) { 6030 case SCF_ERROR_CONNECTION_BROKEN: 6031 goto connaborted; 6032 6033 case SCF_ERROR_NO_RESOURCES: 6034 r = stash_scferror(lcbdata); 6035 goto deltemp; 6036 6037 case SCF_ERROR_EXISTS: 6038 warn(gettext("%s changed unexpectedly " 6039 "(snapshot \"%s\" added).\n"), 6040 inst->sc_fmri, snap_lastimport); 6041 lcbdata->sc_err = EBUSY; 6042 r = UU_WALK_ERROR; 6043 goto deltemp; 6044 6045 case SCF_ERROR_PERMISSION_DENIED: 6046 warn(gettext("Could not take \"%s\" snapshot " 6047 "of %s (permission denied).\n"), 6048 snap_lastimport, inst->sc_fmri); 6049 r = stash_scferror(lcbdata); 6050 goto deltemp; 6051 6052 default: 6053 scfwarn(); 6054 lcbdata->sc_err = -1; 6055 r = UU_WALK_ERROR; 6056 goto deltemp; 6057 6058 case SCF_ERROR_NOT_SET: 6059 case SCF_ERROR_INTERNAL: 6060 case SCF_ERROR_INVALID_ARGUMENT: 6061 case SCF_ERROR_HANDLE_MISMATCH: 6062 bad_error("_scf_snapshot_take_new", 6063 scf_error()); 6064 } 6065 } 6066 6067 if (li_only) 6068 goto lionly; 6069 6070 inst->sc_import_state = IMPORT_PROP_BEGUN; 6071 6072 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 6073 flags); 6074 switch (r) { 6075 case 0: 6076 break; 6077 6078 case ECONNABORTED: 6079 goto connaborted; 6080 6081 case ECANCELED: 6082 warn(gettext("%s changed unexpectedly " 6083 "(instance \"%s\" deleted).\n"), 6084 inst->sc_parent->sc_fmri, inst->sc_name); 6085 lcbdata->sc_err = EBUSY; 6086 r = UU_WALK_ERROR; 6087 goto deltemp; 6088 6089 case EEXIST: 6090 warn(gettext("%s changed unexpectedly " 6091 "(property group added).\n"), inst->sc_fmri); 6092 lcbdata->sc_err = EBUSY; 6093 r = UU_WALK_ERROR; 6094 goto deltemp; 6095 6096 default: 6097 lcbdata->sc_err = r; 6098 r = UU_WALK_ERROR; 6099 goto deltemp; 6100 6101 case EINVAL: /* caught above */ 6102 bad_error("lscf_import_instance_pgs", r); 6103 } 6104 6105 ctx.sc_parent = imp_inst; 6106 ctx.sc_service = 0; 6107 ctx.sc_trans = NULL; 6108 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 6109 &ctx, UU_DEFAULT) != 0) { 6110 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6111 bad_error("uu_list_walk", uu_error()); 6112 6113 if (ctx.sc_err == ECONNABORTED) 6114 goto connaborted; 6115 lcbdata->sc_err = ctx.sc_err; 6116 r = UU_WALK_ERROR; 6117 goto deltemp; 6118 } 6119 6120 inst->sc_import_state = IMPORT_PROP_DONE; 6121 6122 if (g_verbose) 6123 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6124 snap_initial, inst->sc_fmri); 6125 r = take_snap(imp_inst, snap_initial, imp_snap); 6126 switch (r) { 6127 case 0: 6128 break; 6129 6130 case ECONNABORTED: 6131 goto connaborted; 6132 6133 case ENOSPC: 6134 case -1: 6135 lcbdata->sc_err = r; 6136 r = UU_WALK_ERROR; 6137 goto deltemp; 6138 6139 case ECANCELED: 6140 warn(gettext("%s changed unexpectedly " 6141 "(instance %s deleted).\n"), 6142 inst->sc_parent->sc_fmri, inst->sc_name); 6143 lcbdata->sc_err = r; 6144 r = UU_WALK_ERROR; 6145 goto deltemp; 6146 6147 case EPERM: 6148 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 6149 lcbdata->sc_err = r; 6150 r = UU_WALK_ERROR; 6151 goto deltemp; 6152 6153 default: 6154 bad_error("take_snap", r); 6155 } 6156 } 6157 6158 lionly: 6159 if (lcbdata->sc_flags & SCI_NOSNAP) 6160 goto deltemp; 6161 6162 /* transfer snapshot from temporary instance */ 6163 if (g_verbose) 6164 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 6165 snap_lastimport, inst->sc_fmri); 6166 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 6167 switch (scf_error()) { 6168 case SCF_ERROR_CONNECTION_BROKEN: 6169 goto connaborted; 6170 6171 case SCF_ERROR_NO_RESOURCES: 6172 r = stash_scferror(lcbdata); 6173 goto deltemp; 6174 6175 case SCF_ERROR_PERMISSION_DENIED: 6176 warn(gettext("Could not take \"%s\" snapshot for %s " 6177 "(permission denied).\n"), snap_lastimport, 6178 inst->sc_fmri); 6179 r = stash_scferror(lcbdata); 6180 goto deltemp; 6181 6182 case SCF_ERROR_NOT_SET: 6183 case SCF_ERROR_HANDLE_MISMATCH: 6184 default: 6185 bad_error("_scf_snapshot_attach", scf_error()); 6186 } 6187 } 6188 6189 inst->sc_import_state = IMPORT_COMPLETE; 6190 6191 r = UU_WALK_NEXT; 6192 6193 deltemp: 6194 /* delete temporary instance */ 6195 if (scf_instance_delete(imp_tinst) != 0) { 6196 switch (scf_error()) { 6197 case SCF_ERROR_DELETED: 6198 break; 6199 6200 case SCF_ERROR_CONNECTION_BROKEN: 6201 goto connaborted; 6202 6203 case SCF_ERROR_NOT_SET: 6204 case SCF_ERROR_NOT_BOUND: 6205 default: 6206 bad_error("scf_instance_delete", scf_error()); 6207 } 6208 } 6209 6210 return (r); 6211 6212 connaborted: 6213 warn(gettext("Could not delete svc:/%s:%s " 6214 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 6215 lcbdata->sc_err = ECONNABORTED; 6216 return (UU_WALK_ERROR); 6217 } 6218 6219 /* 6220 * If the service is missing, create it, import its properties, and import the 6221 * instances. Since the service is brand new, it should be empty, and if we 6222 * run into any existing entities (SCF_ERROR_EXISTS), abort. 6223 * 6224 * If the service exists, we want to upgrade its properties and import the 6225 * instances. Upgrade requires a last-import snapshot, though, which are 6226 * children of instances, so first we'll have to go through the instances 6227 * looking for a last-import snapshot. If we don't find one then we'll just 6228 * override-import the service properties (but don't delete existing 6229 * properties: another service might have declared us as a dependent). Before 6230 * we change anything, though, we want to take the previous snapshots. We 6231 * also give lscf_instance_import() a leg up on taking last-import snapshots 6232 * by importing the manifest's service properties into a temporary service. 6233 * 6234 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 6235 * sets lcbdata->sc_err to 6236 * ECONNABORTED - repository connection broken 6237 * ENOMEM - out of memory 6238 * ENOSPC - svc.configd is out of resources 6239 * EPERM - couldn't create temporary service (error printed) 6240 * - couldn't import into temp service (error printed) 6241 * - couldn't create service (error printed) 6242 * - couldn't import dependent (error printed) 6243 * - couldn't take snapshot (error printed) 6244 * - couldn't create instance (error printed) 6245 * - couldn't create, modify, or delete pg (error printed) 6246 * - couldn't create, modify, or delete dependent (error printed) 6247 * - couldn't import instance (error printed) 6248 * EROFS - couldn't create temporary service (repository read-only) 6249 * - couldn't import into temporary service (repository read-only) 6250 * - couldn't create service (repository read-only) 6251 * - couldn't import dependent (repository read-only) 6252 * - couldn't create instance (repository read-only) 6253 * - couldn't create, modify, or delete pg or dependent 6254 * - couldn't import instance (repository read-only) 6255 * EACCES - couldn't create temporary service (backend access denied) 6256 * - couldn't import into temporary service (backend access denied) 6257 * - couldn't create service (backend access denied) 6258 * - couldn't import dependent (backend access denied) 6259 * - couldn't create instance (backend access denied) 6260 * - couldn't create, modify, or delete pg or dependent 6261 * - couldn't import instance (backend access denied) 6262 * EINVAL - service name is invalid (error printed) 6263 * - service name is too long (error printed) 6264 * - s has invalid pgroup (error printed) 6265 * - s has invalid dependent (error printed) 6266 * - instance name is invalid (error printed) 6267 * - instance entity_t is invalid (error printed) 6268 * EEXIST - couldn't create temporary service (already exists) (error printed) 6269 * - couldn't import dependent (dependency pg already exists) (printed) 6270 * - dependency collision in dependent service (error printed) 6271 * EBUSY - temporary service deleted (error printed) 6272 * - property group added to temporary service (error printed) 6273 * - new property group changed or was deleted (error printed) 6274 * - service was added unexpectedly (error printed) 6275 * - service was deleted unexpectedly (error printed) 6276 * - property group added to new service (error printed) 6277 * - instance added unexpectedly (error printed) 6278 * - instance deleted unexpectedly (error printed) 6279 * - dependent service deleted unexpectedly (error printed) 6280 * - pg was added, changed, or deleted (error printed) 6281 * - dependent pg changed (error printed) 6282 * - temporary instance added, changed, or deleted (error printed) 6283 * EBADF - a last-import snapshot is corrupt (error printed) 6284 * - the service is corrupt (error printed) 6285 * - a dependent is corrupt (error printed) 6286 * - an instance is corrupt (error printed) 6287 * - an instance has a corrupt last-import snapshot (error printed) 6288 * - dependent target has a corrupt snapshot (error printed) 6289 * -1 - unknown libscf error (error printed) 6290 */ 6291 static int 6292 lscf_service_import(void *v, void *pvt) 6293 { 6294 entity_t *s = v; 6295 scf_callback_t cbdata; 6296 scf_callback_t *lcbdata = pvt; 6297 scf_scope_t *scope = lcbdata->sc_parent; 6298 entity_t *inst, linst; 6299 int r; 6300 int fresh = 0; 6301 scf_snaplevel_t *running; 6302 int have_ge = 0; 6303 6304 const char * const ts_deleted = gettext("Temporary service svc:/%s " 6305 "was deleted unexpectedly.\n"); 6306 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 6307 "changed unexpectedly (property group added).\n"); 6308 const char * const s_deleted = 6309 gettext("%s was deleted unexpectedly.\n"); 6310 const char * const i_deleted = 6311 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 6312 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 6313 "is corrupt (missing service snaplevel).\n"); 6314 6315 li_only = 0; 6316 /* Validate the service name */ 6317 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6318 switch (scf_error()) { 6319 case SCF_ERROR_CONNECTION_BROKEN: 6320 return (stash_scferror(lcbdata)); 6321 6322 case SCF_ERROR_INVALID_ARGUMENT: 6323 warn(gettext("\"%s\" is an invalid service name. " 6324 "Cannot import.\n"), s->sc_name); 6325 return (stash_scferror(lcbdata)); 6326 6327 case SCF_ERROR_NOT_FOUND: 6328 break; 6329 6330 case SCF_ERROR_HANDLE_MISMATCH: 6331 case SCF_ERROR_NOT_BOUND: 6332 case SCF_ERROR_NOT_SET: 6333 default: 6334 bad_error("scf_scope_get_service", scf_error()); 6335 } 6336 } 6337 6338 /* create temporary service */ 6339 /* 6340 * the size of the buffer was reduced to max_scf_name_len to prevent 6341 * hitting bug 6681151. After the bug fix, the size of the buffer 6342 * should be restored to its original value (max_scf_name_len +1) 6343 */ 6344 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 6345 if (r < 0) 6346 bad_error("snprintf", errno); 6347 if (r > max_scf_name_len) { 6348 warn(gettext( 6349 "Service name \"%s\" is too long. Cannot import.\n"), 6350 s->sc_name); 6351 lcbdata->sc_err = EINVAL; 6352 return (UU_WALK_ERROR); 6353 } 6354 6355 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 6356 switch (scf_error()) { 6357 case SCF_ERROR_CONNECTION_BROKEN: 6358 case SCF_ERROR_NO_RESOURCES: 6359 case SCF_ERROR_BACKEND_READONLY: 6360 case SCF_ERROR_BACKEND_ACCESS: 6361 return (stash_scferror(lcbdata)); 6362 6363 case SCF_ERROR_EXISTS: 6364 warn(gettext( 6365 "Temporary service \"%s\" must be deleted before " 6366 "this manifest can be imported.\n"), imp_tsname); 6367 return (stash_scferror(lcbdata)); 6368 6369 case SCF_ERROR_PERMISSION_DENIED: 6370 warn(gettext("Could not create temporary service " 6371 "\"%s\" (permission denied).\n"), imp_tsname); 6372 return (stash_scferror(lcbdata)); 6373 6374 case SCF_ERROR_INVALID_ARGUMENT: 6375 case SCF_ERROR_HANDLE_MISMATCH: 6376 case SCF_ERROR_NOT_BOUND: 6377 case SCF_ERROR_NOT_SET: 6378 default: 6379 bad_error("scf_scope_add_service", scf_error()); 6380 } 6381 } 6382 6383 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 6384 if (r < 0) 6385 bad_error("snprintf", errno); 6386 6387 cbdata.sc_handle = lcbdata->sc_handle; 6388 cbdata.sc_parent = imp_tsvc; 6389 cbdata.sc_service = 1; 6390 cbdata.sc_source_fmri = s->sc_fmri; 6391 cbdata.sc_target_fmri = imp_str; 6392 cbdata.sc_flags = 0; 6393 6394 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 6395 UU_DEFAULT) != 0) { 6396 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6397 bad_error("uu_list_walk", uu_error()); 6398 6399 lcbdata->sc_err = cbdata.sc_err; 6400 switch (cbdata.sc_err) { 6401 case ECONNABORTED: 6402 goto connaborted; 6403 6404 case ECANCELED: 6405 warn(ts_deleted, imp_tsname); 6406 lcbdata->sc_err = EBUSY; 6407 return (UU_WALK_ERROR); 6408 6409 case EEXIST: 6410 warn(ts_pg_added, imp_tsname); 6411 lcbdata->sc_err = EBUSY; 6412 return (UU_WALK_ERROR); 6413 } 6414 6415 r = UU_WALK_ERROR; 6416 goto deltemp; 6417 } 6418 6419 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 6420 UU_DEFAULT) != 0) { 6421 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6422 bad_error("uu_list_walk", uu_error()); 6423 6424 lcbdata->sc_err = cbdata.sc_err; 6425 switch (cbdata.sc_err) { 6426 case ECONNABORTED: 6427 goto connaborted; 6428 6429 case ECANCELED: 6430 warn(ts_deleted, imp_tsname); 6431 lcbdata->sc_err = EBUSY; 6432 return (UU_WALK_ERROR); 6433 6434 case EEXIST: 6435 warn(ts_pg_added, imp_tsname); 6436 lcbdata->sc_err = EBUSY; 6437 return (UU_WALK_ERROR); 6438 } 6439 6440 r = UU_WALK_ERROR; 6441 goto deltemp; 6442 } 6443 6444 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6445 switch (scf_error()) { 6446 case SCF_ERROR_NOT_FOUND: 6447 break; 6448 6449 case SCF_ERROR_CONNECTION_BROKEN: 6450 goto connaborted; 6451 6452 case SCF_ERROR_INVALID_ARGUMENT: 6453 case SCF_ERROR_HANDLE_MISMATCH: 6454 case SCF_ERROR_NOT_BOUND: 6455 case SCF_ERROR_NOT_SET: 6456 default: 6457 bad_error("scf_scope_get_service", scf_error()); 6458 } 6459 6460 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 6461 switch (scf_error()) { 6462 case SCF_ERROR_CONNECTION_BROKEN: 6463 goto connaborted; 6464 6465 case SCF_ERROR_NO_RESOURCES: 6466 case SCF_ERROR_BACKEND_READONLY: 6467 case SCF_ERROR_BACKEND_ACCESS: 6468 r = stash_scferror(lcbdata); 6469 goto deltemp; 6470 6471 case SCF_ERROR_EXISTS: 6472 warn(gettext("Scope \"%s\" changed unexpectedly" 6473 " (service \"%s\" added).\n"), 6474 SCF_SCOPE_LOCAL, s->sc_name); 6475 lcbdata->sc_err = EBUSY; 6476 goto deltemp; 6477 6478 case SCF_ERROR_PERMISSION_DENIED: 6479 warn(gettext("Could not create service \"%s\" " 6480 "(permission denied).\n"), s->sc_name); 6481 goto deltemp; 6482 6483 case SCF_ERROR_INVALID_ARGUMENT: 6484 case SCF_ERROR_HANDLE_MISMATCH: 6485 case SCF_ERROR_NOT_BOUND: 6486 case SCF_ERROR_NOT_SET: 6487 default: 6488 bad_error("scf_scope_add_service", scf_error()); 6489 } 6490 } 6491 6492 s->sc_import_state = IMPORT_PROP_BEGUN; 6493 6494 /* import service properties */ 6495 cbdata.sc_handle = lcbdata->sc_handle; 6496 cbdata.sc_parent = imp_svc; 6497 cbdata.sc_service = 1; 6498 cbdata.sc_flags = lcbdata->sc_flags; 6499 cbdata.sc_source_fmri = s->sc_fmri; 6500 cbdata.sc_target_fmri = s->sc_fmri; 6501 6502 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6503 &cbdata, UU_DEFAULT) != 0) { 6504 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6505 bad_error("uu_list_walk", uu_error()); 6506 6507 lcbdata->sc_err = cbdata.sc_err; 6508 switch (cbdata.sc_err) { 6509 case ECONNABORTED: 6510 goto connaborted; 6511 6512 case ECANCELED: 6513 warn(s_deleted, s->sc_fmri); 6514 lcbdata->sc_err = EBUSY; 6515 return (UU_WALK_ERROR); 6516 6517 case EEXIST: 6518 warn(gettext("%s changed unexpectedly " 6519 "(property group added).\n"), s->sc_fmri); 6520 lcbdata->sc_err = EBUSY; 6521 return (UU_WALK_ERROR); 6522 6523 case EINVAL: 6524 /* caught above */ 6525 bad_error("entity_pgroup_import", 6526 cbdata.sc_err); 6527 } 6528 6529 r = UU_WALK_ERROR; 6530 goto deltemp; 6531 } 6532 6533 cbdata.sc_trans = NULL; 6534 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 6535 &cbdata, UU_DEFAULT) != 0) { 6536 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6537 bad_error("uu_list_walk", uu_error()); 6538 6539 lcbdata->sc_err = cbdata.sc_err; 6540 if (cbdata.sc_err == ECONNABORTED) 6541 goto connaborted; 6542 r = UU_WALK_ERROR; 6543 goto deltemp; 6544 } 6545 6546 s->sc_import_state = IMPORT_PROP_DONE; 6547 6548 /* 6549 * This is a new service, so we can't take previous snapshots 6550 * or upgrade service properties. 6551 */ 6552 fresh = 1; 6553 goto instances; 6554 } 6555 6556 /* Clear sc_seen for the instances. */ 6557 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 6558 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 6559 bad_error("uu_list_walk", uu_error()); 6560 6561 /* 6562 * Take previous snapshots for all instances. Even for ones not 6563 * mentioned in the bundle, since we might change their service 6564 * properties. 6565 */ 6566 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6567 switch (scf_error()) { 6568 case SCF_ERROR_CONNECTION_BROKEN: 6569 goto connaborted; 6570 6571 case SCF_ERROR_DELETED: 6572 warn(s_deleted, s->sc_fmri); 6573 lcbdata->sc_err = EBUSY; 6574 r = UU_WALK_ERROR; 6575 goto deltemp; 6576 6577 case SCF_ERROR_HANDLE_MISMATCH: 6578 case SCF_ERROR_NOT_BOUND: 6579 case SCF_ERROR_NOT_SET: 6580 default: 6581 bad_error("scf_iter_service_instances", scf_error()); 6582 } 6583 } 6584 6585 for (;;) { 6586 r = scf_iter_next_instance(imp_iter, imp_inst); 6587 if (r == 0) 6588 break; 6589 if (r != 1) { 6590 switch (scf_error()) { 6591 case SCF_ERROR_DELETED: 6592 warn(s_deleted, s->sc_fmri); 6593 lcbdata->sc_err = EBUSY; 6594 r = UU_WALK_ERROR; 6595 goto deltemp; 6596 6597 case SCF_ERROR_CONNECTION_BROKEN: 6598 goto connaborted; 6599 6600 case SCF_ERROR_NOT_BOUND: 6601 case SCF_ERROR_HANDLE_MISMATCH: 6602 case SCF_ERROR_INVALID_ARGUMENT: 6603 case SCF_ERROR_NOT_SET: 6604 default: 6605 bad_error("scf_iter_next_instance", 6606 scf_error()); 6607 } 6608 } 6609 6610 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 6611 switch (scf_error()) { 6612 case SCF_ERROR_DELETED: 6613 continue; 6614 6615 case SCF_ERROR_CONNECTION_BROKEN: 6616 goto connaborted; 6617 6618 case SCF_ERROR_NOT_SET: 6619 case SCF_ERROR_NOT_BOUND: 6620 default: 6621 bad_error("scf_instance_get_name", scf_error()); 6622 } 6623 } 6624 6625 if (g_verbose) 6626 warn(gettext( 6627 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 6628 snap_previous, s->sc_name, imp_str); 6629 6630 r = take_snap(imp_inst, snap_previous, imp_snap); 6631 switch (r) { 6632 case 0: 6633 break; 6634 6635 case ECANCELED: 6636 continue; 6637 6638 case ECONNABORTED: 6639 goto connaborted; 6640 6641 case EPERM: 6642 warn(gettext("Could not take \"%s\" snapshot of " 6643 "svc:/%s:%s (permission denied).\n"), 6644 snap_previous, s->sc_name, imp_str); 6645 lcbdata->sc_err = r; 6646 return (UU_WALK_ERROR); 6647 6648 case ENOSPC: 6649 case -1: 6650 lcbdata->sc_err = r; 6651 r = UU_WALK_ERROR; 6652 goto deltemp; 6653 6654 default: 6655 bad_error("take_snap", r); 6656 } 6657 6658 linst.sc_name = imp_str; 6659 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 6660 &linst, NULL, NULL); 6661 if (inst != NULL) { 6662 inst->sc_import_state = IMPORT_PREVIOUS; 6663 inst->sc_seen = 1; 6664 } 6665 } 6666 6667 /* 6668 * Create the new instances and take previous snapshots of 6669 * them. This is not necessary, but it maximizes data preservation. 6670 */ 6671 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 6672 inst != NULL; 6673 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 6674 inst)) { 6675 if (inst->sc_seen) 6676 continue; 6677 6678 if (scf_service_add_instance(imp_svc, inst->sc_name, 6679 imp_inst) != 0) { 6680 switch (scf_error()) { 6681 case SCF_ERROR_CONNECTION_BROKEN: 6682 goto connaborted; 6683 6684 case SCF_ERROR_BACKEND_READONLY: 6685 case SCF_ERROR_BACKEND_ACCESS: 6686 case SCF_ERROR_NO_RESOURCES: 6687 r = stash_scferror(lcbdata); 6688 goto deltemp; 6689 6690 case SCF_ERROR_EXISTS: 6691 warn(gettext("%s changed unexpectedly " 6692 "(instance \"%s\" added).\n"), s->sc_fmri, 6693 inst->sc_name); 6694 lcbdata->sc_err = EBUSY; 6695 r = UU_WALK_ERROR; 6696 goto deltemp; 6697 6698 case SCF_ERROR_INVALID_ARGUMENT: 6699 warn(gettext("Service \"%s\" has instance with " 6700 "invalid name \"%s\".\n"), s->sc_name, 6701 inst->sc_name); 6702 r = stash_scferror(lcbdata); 6703 goto deltemp; 6704 6705 case SCF_ERROR_PERMISSION_DENIED: 6706 warn(gettext("Could not create instance \"%s\" " 6707 "in %s (permission denied).\n"), 6708 inst->sc_name, s->sc_fmri); 6709 r = stash_scferror(lcbdata); 6710 goto deltemp; 6711 6712 case SCF_ERROR_HANDLE_MISMATCH: 6713 case SCF_ERROR_NOT_BOUND: 6714 case SCF_ERROR_NOT_SET: 6715 default: 6716 bad_error("scf_service_add_instance", 6717 scf_error()); 6718 } 6719 } 6720 6721 if (g_verbose) 6722 warn(gettext("Taking \"%s\" snapshot for " 6723 "new service %s.\n"), snap_previous, inst->sc_fmri); 6724 r = take_snap(imp_inst, snap_previous, imp_snap); 6725 switch (r) { 6726 case 0: 6727 break; 6728 6729 case ECANCELED: 6730 warn(i_deleted, s->sc_fmri, inst->sc_name); 6731 lcbdata->sc_err = EBUSY; 6732 r = UU_WALK_ERROR; 6733 goto deltemp; 6734 6735 case ECONNABORTED: 6736 goto connaborted; 6737 6738 case EPERM: 6739 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 6740 lcbdata->sc_err = r; 6741 r = UU_WALK_ERROR; 6742 goto deltemp; 6743 6744 case ENOSPC: 6745 case -1: 6746 r = UU_WALK_ERROR; 6747 goto deltemp; 6748 6749 default: 6750 bad_error("take_snap", r); 6751 } 6752 } 6753 6754 s->sc_import_state = IMPORT_PREVIOUS; 6755 6756 /* 6757 * Upgrade service properties, if we can find a last-import snapshot. 6758 * Any will do because we don't support different service properties 6759 * in different manifests, so all snaplevels of the service in all of 6760 * the last-import snapshots of the instances should be the same. 6761 */ 6762 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6763 switch (scf_error()) { 6764 case SCF_ERROR_CONNECTION_BROKEN: 6765 goto connaborted; 6766 6767 case SCF_ERROR_DELETED: 6768 warn(s_deleted, s->sc_fmri); 6769 lcbdata->sc_err = EBUSY; 6770 r = UU_WALK_ERROR; 6771 goto deltemp; 6772 6773 case SCF_ERROR_HANDLE_MISMATCH: 6774 case SCF_ERROR_NOT_BOUND: 6775 case SCF_ERROR_NOT_SET: 6776 default: 6777 bad_error("scf_iter_service_instances", scf_error()); 6778 } 6779 } 6780 6781 for (;;) { 6782 r = scf_iter_next_instance(imp_iter, imp_inst); 6783 if (r == -1) { 6784 switch (scf_error()) { 6785 case SCF_ERROR_DELETED: 6786 warn(s_deleted, s->sc_fmri); 6787 lcbdata->sc_err = EBUSY; 6788 r = UU_WALK_ERROR; 6789 goto deltemp; 6790 6791 case SCF_ERROR_CONNECTION_BROKEN: 6792 goto connaborted; 6793 6794 case SCF_ERROR_NOT_BOUND: 6795 case SCF_ERROR_HANDLE_MISMATCH: 6796 case SCF_ERROR_INVALID_ARGUMENT: 6797 case SCF_ERROR_NOT_SET: 6798 default: 6799 bad_error("scf_iter_next_instance", 6800 scf_error()); 6801 } 6802 } 6803 6804 if (r == 0) { 6805 /* 6806 * Didn't find any last-import snapshots. Override- 6807 * import the properties. Unless one of the instances 6808 * has a general/enabled property, in which case we're 6809 * probably running a last-import-capable svccfg for 6810 * the first time, and we should only take the 6811 * last-import snapshot. 6812 */ 6813 if (have_ge) { 6814 li_only = 1; 6815 no_refresh = 1; 6816 break; 6817 } 6818 6819 s->sc_import_state = IMPORT_PROP_BEGUN; 6820 6821 cbdata.sc_handle = g_hndl; 6822 cbdata.sc_parent = imp_svc; 6823 cbdata.sc_service = 1; 6824 cbdata.sc_flags = SCI_FORCE; 6825 cbdata.sc_source_fmri = s->sc_fmri; 6826 cbdata.sc_target_fmri = s->sc_fmri; 6827 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6828 &cbdata, UU_DEFAULT) != 0) { 6829 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6830 bad_error("uu_list_walk", uu_error()); 6831 lcbdata->sc_err = cbdata.sc_err; 6832 switch (cbdata.sc_err) { 6833 case ECONNABORTED: 6834 goto connaborted; 6835 6836 case ECANCELED: 6837 warn(s_deleted, s->sc_fmri); 6838 lcbdata->sc_err = EBUSY; 6839 break; 6840 6841 case EINVAL: /* caught above */ 6842 case EEXIST: 6843 bad_error("entity_pgroup_import", 6844 cbdata.sc_err); 6845 } 6846 6847 r = UU_WALK_ERROR; 6848 goto deltemp; 6849 } 6850 6851 cbdata.sc_trans = NULL; 6852 if (uu_list_walk(s->sc_dependents, 6853 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 6854 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6855 bad_error("uu_list_walk", uu_error()); 6856 lcbdata->sc_err = cbdata.sc_err; 6857 if (cbdata.sc_err == ECONNABORTED) 6858 goto connaborted; 6859 r = UU_WALK_ERROR; 6860 goto deltemp; 6861 } 6862 break; 6863 } 6864 6865 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6866 imp_snap) != 0) { 6867 switch (scf_error()) { 6868 case SCF_ERROR_DELETED: 6869 continue; 6870 6871 case SCF_ERROR_NOT_FOUND: 6872 break; 6873 6874 case SCF_ERROR_CONNECTION_BROKEN: 6875 goto connaborted; 6876 6877 case SCF_ERROR_HANDLE_MISMATCH: 6878 case SCF_ERROR_NOT_BOUND: 6879 case SCF_ERROR_INVALID_ARGUMENT: 6880 case SCF_ERROR_NOT_SET: 6881 default: 6882 bad_error("scf_instance_get_snapshot", 6883 scf_error()); 6884 } 6885 6886 if (have_ge) 6887 continue; 6888 6889 /* 6890 * Check for a general/enabled property. This is how 6891 * we tell whether to import if there turn out to be 6892 * no last-import snapshots. 6893 */ 6894 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 6895 imp_pg) == 0) { 6896 if (scf_pg_get_property(imp_pg, 6897 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 6898 have_ge = 1; 6899 } else { 6900 switch (scf_error()) { 6901 case SCF_ERROR_DELETED: 6902 case SCF_ERROR_NOT_FOUND: 6903 continue; 6904 6905 case SCF_ERROR_INVALID_ARGUMENT: 6906 case SCF_ERROR_HANDLE_MISMATCH: 6907 case SCF_ERROR_CONNECTION_BROKEN: 6908 case SCF_ERROR_NOT_BOUND: 6909 case SCF_ERROR_NOT_SET: 6910 default: 6911 bad_error("scf_pg_get_property", 6912 scf_error()); 6913 } 6914 } 6915 } else { 6916 switch (scf_error()) { 6917 case SCF_ERROR_DELETED: 6918 case SCF_ERROR_NOT_FOUND: 6919 continue; 6920 6921 case SCF_ERROR_CONNECTION_BROKEN: 6922 goto connaborted; 6923 6924 case SCF_ERROR_NOT_BOUND: 6925 case SCF_ERROR_NOT_SET: 6926 case SCF_ERROR_INVALID_ARGUMENT: 6927 case SCF_ERROR_HANDLE_MISMATCH: 6928 default: 6929 bad_error("scf_instance_get_pg", 6930 scf_error()); 6931 } 6932 } 6933 continue; 6934 } 6935 6936 /* find service snaplevel */ 6937 r = get_snaplevel(imp_snap, 1, imp_snpl); 6938 switch (r) { 6939 case 0: 6940 break; 6941 6942 case ECONNABORTED: 6943 goto connaborted; 6944 6945 case ECANCELED: 6946 continue; 6947 6948 case ENOENT: 6949 if (scf_instance_get_name(imp_inst, imp_str, 6950 imp_str_sz) < 0) 6951 (void) strcpy(imp_str, "?"); 6952 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 6953 lcbdata->sc_err = EBADF; 6954 r = UU_WALK_ERROR; 6955 goto deltemp; 6956 6957 default: 6958 bad_error("get_snaplevel", r); 6959 } 6960 6961 if (scf_instance_get_snapshot(imp_inst, snap_running, 6962 imp_rsnap) != 0) { 6963 switch (scf_error()) { 6964 case SCF_ERROR_DELETED: 6965 continue; 6966 6967 case SCF_ERROR_NOT_FOUND: 6968 break; 6969 6970 case SCF_ERROR_CONNECTION_BROKEN: 6971 goto connaborted; 6972 6973 case SCF_ERROR_INVALID_ARGUMENT: 6974 case SCF_ERROR_HANDLE_MISMATCH: 6975 case SCF_ERROR_NOT_BOUND: 6976 case SCF_ERROR_NOT_SET: 6977 default: 6978 bad_error("scf_instance_get_snapshot", 6979 scf_error()); 6980 } 6981 running = NULL; 6982 } else { 6983 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 6984 switch (r) { 6985 case 0: 6986 running = imp_rsnpl; 6987 break; 6988 6989 case ECONNABORTED: 6990 goto connaborted; 6991 6992 case ECANCELED: 6993 continue; 6994 6995 case ENOENT: 6996 if (scf_instance_get_name(imp_inst, imp_str, 6997 imp_str_sz) < 0) 6998 (void) strcpy(imp_str, "?"); 6999 warn(badsnap, snap_running, s->sc_name, 7000 imp_str); 7001 lcbdata->sc_err = EBADF; 7002 r = UU_WALK_ERROR; 7003 goto deltemp; 7004 7005 default: 7006 bad_error("get_snaplevel", r); 7007 } 7008 } 7009 7010 if (g_verbose) { 7011 if (scf_instance_get_name(imp_inst, imp_str, 7012 imp_str_sz) < 0) 7013 (void) strcpy(imp_str, "?"); 7014 warn(gettext("Upgrading properties of %s according to " 7015 "instance \"%s\".\n"), s->sc_fmri, imp_str); 7016 } 7017 7018 /* upgrade service properties */ 7019 r = upgrade_props(imp_svc, running, imp_snpl, s); 7020 if (r == 0) 7021 break; 7022 7023 switch (r) { 7024 case ECONNABORTED: 7025 goto connaborted; 7026 7027 case ECANCELED: 7028 warn(s_deleted, s->sc_fmri); 7029 lcbdata->sc_err = EBUSY; 7030 break; 7031 7032 case ENODEV: 7033 if (scf_instance_get_name(imp_inst, imp_str, 7034 imp_str_sz) < 0) 7035 (void) strcpy(imp_str, "?"); 7036 warn(i_deleted, s->sc_fmri, imp_str); 7037 lcbdata->sc_err = EBUSY; 7038 break; 7039 7040 default: 7041 lcbdata->sc_err = r; 7042 } 7043 7044 r = UU_WALK_ERROR; 7045 goto deltemp; 7046 } 7047 7048 s->sc_import_state = IMPORT_PROP_DONE; 7049 7050 instances: 7051 /* import instances */ 7052 cbdata.sc_handle = lcbdata->sc_handle; 7053 cbdata.sc_parent = imp_svc; 7054 cbdata.sc_service = 1; 7055 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 7056 cbdata.sc_general = NULL; 7057 7058 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 7059 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 7060 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7061 bad_error("uu_list_walk", uu_error()); 7062 7063 lcbdata->sc_err = cbdata.sc_err; 7064 if (cbdata.sc_err == ECONNABORTED) 7065 goto connaborted; 7066 r = UU_WALK_ERROR; 7067 goto deltemp; 7068 } 7069 7070 s->sc_import_state = IMPORT_COMPLETE; 7071 r = UU_WALK_NEXT; 7072 7073 deltemp: 7074 /* delete temporary service */ 7075 if (scf_service_delete(imp_tsvc) != 0) { 7076 switch (scf_error()) { 7077 case SCF_ERROR_DELETED: 7078 break; 7079 7080 case SCF_ERROR_CONNECTION_BROKEN: 7081 goto connaborted; 7082 7083 case SCF_ERROR_EXISTS: 7084 warn(gettext( 7085 "Could not delete svc:/%s (instances exist).\n"), 7086 imp_tsname); 7087 break; 7088 7089 case SCF_ERROR_NOT_SET: 7090 case SCF_ERROR_NOT_BOUND: 7091 default: 7092 bad_error("scf_service_delete", scf_error()); 7093 } 7094 } 7095 7096 return (r); 7097 7098 connaborted: 7099 warn(gettext("Could not delete svc:/%s " 7100 "(repository connection broken).\n"), imp_tsname); 7101 lcbdata->sc_err = ECONNABORTED; 7102 return (UU_WALK_ERROR); 7103 } 7104 7105 static const char * 7106 import_progress(int st) 7107 { 7108 switch (st) { 7109 case 0: 7110 return (gettext("not reached.")); 7111 7112 case IMPORT_PREVIOUS: 7113 return (gettext("previous snapshot taken.")); 7114 7115 case IMPORT_PROP_BEGUN: 7116 return (gettext("some properties imported.")); 7117 7118 case IMPORT_PROP_DONE: 7119 return (gettext("properties imported.")); 7120 7121 case IMPORT_COMPLETE: 7122 return (gettext("imported.")); 7123 7124 case IMPORT_REFRESHED: 7125 return (gettext("refresh requested.")); 7126 7127 default: 7128 #ifndef NDEBUG 7129 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 7130 __FILE__, __LINE__, st); 7131 #endif 7132 abort(); 7133 /* NOTREACHED */ 7134 } 7135 } 7136 7137 /* 7138 * Returns 7139 * 0 - success 7140 * - fmri wasn't found (error printed) 7141 * - entity was deleted (error printed) 7142 * - backend denied access (error printed) 7143 * ENOMEM - out of memory (error printed) 7144 * ECONNABORTED - repository connection broken (error printed) 7145 * EPERM - permission denied (error printed) 7146 * -1 - unknown libscf error (error printed) 7147 */ 7148 static int 7149 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 7150 { 7151 scf_error_t serr; 7152 void *ent; 7153 int issvc; 7154 int r; 7155 7156 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 7157 const char *dpt_deleted = gettext("Could not refresh %s " 7158 "(dependent \"%s\" of %s) (deleted).\n"); 7159 7160 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 7161 switch (serr) { 7162 case SCF_ERROR_NONE: 7163 break; 7164 7165 case SCF_ERROR_NO_MEMORY: 7166 if (name == NULL) 7167 warn(gettext("Could not refresh %s (out of memory).\n"), 7168 fmri); 7169 else 7170 warn(gettext("Could not refresh %s " 7171 "(dependent \"%s\" of %s) (out of memory).\n"), 7172 fmri, name, d_fmri); 7173 return (ENOMEM); 7174 7175 case SCF_ERROR_NOT_FOUND: 7176 if (name == NULL) 7177 warn(deleted, fmri); 7178 else 7179 warn(dpt_deleted, fmri, name, d_fmri); 7180 return (0); 7181 7182 case SCF_ERROR_INVALID_ARGUMENT: 7183 case SCF_ERROR_CONSTRAINT_VIOLATED: 7184 default: 7185 bad_error("fmri_to_entity", serr); 7186 } 7187 7188 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 7189 switch (r) { 7190 case 0: 7191 break; 7192 7193 case ECONNABORTED: 7194 if (name != NULL) 7195 warn(gettext("Could not refresh %s " 7196 "(dependent \"%s\" of %s) " 7197 "(repository connection broken).\n"), fmri, name, 7198 d_fmri); 7199 return (r); 7200 7201 case ECANCELED: 7202 if (name == NULL) 7203 warn(deleted, fmri); 7204 else 7205 warn(dpt_deleted, fmri, name, d_fmri); 7206 return (0); 7207 7208 case EACCES: 7209 if (!g_verbose) 7210 return (0); 7211 if (name == NULL) 7212 warn(gettext("Could not refresh %s " 7213 "(backend access denied).\n"), fmri); 7214 else 7215 warn(gettext("Could not refresh %s " 7216 "(dependent \"%s\" of %s) " 7217 "(backend access denied).\n"), fmri, name, d_fmri); 7218 return (0); 7219 7220 case EPERM: 7221 if (name == NULL) 7222 warn(gettext("Could not refresh %s " 7223 "(permission denied).\n"), fmri); 7224 else 7225 warn(gettext("Could not refresh %s " 7226 "(dependent \"%s\" of %s) " 7227 "(permission denied).\n"), fmri, name, d_fmri); 7228 return (r); 7229 7230 case ENOSPC: 7231 if (name == NULL) 7232 warn(gettext("Could not refresh %s " 7233 "(repository server out of resources).\n"), 7234 fmri); 7235 else 7236 warn(gettext("Could not refresh %s " 7237 "(dependent \"%s\" of %s) " 7238 "(repository server out of resources).\n"), 7239 fmri, name, d_fmri); 7240 return (r); 7241 7242 case -1: 7243 scfwarn(); 7244 return (r); 7245 7246 default: 7247 bad_error("refresh_entity", r); 7248 } 7249 7250 if (issvc) 7251 scf_service_destroy(ent); 7252 else 7253 scf_instance_destroy(ent); 7254 7255 return (0); 7256 } 7257 7258 int 7259 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 7260 { 7261 scf_callback_t cbdata; 7262 int result = 0; 7263 entity_t *svc, *inst; 7264 uu_list_t *insts; 7265 int r; 7266 pgroup_t *old_dpt; 7267 void *cookie; 7268 int annotation_set = 0; 7269 7270 const char * const emsg_nomem = gettext("Out of memory.\n"); 7271 const char * const emsg_nores = 7272 gettext("svc.configd is out of resources.\n"); 7273 7274 lscf_prep_hndl(); 7275 7276 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 7277 max_scf_name_len : max_scf_fmri_len) + 1; 7278 7279 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 7280 (imp_svc = scf_service_create(g_hndl)) == NULL || 7281 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 7282 (imp_inst = scf_instance_create(g_hndl)) == NULL || 7283 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 7284 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 7285 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 7286 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 7287 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 7288 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7289 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 7290 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7291 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 7292 (imp_prop = scf_property_create(g_hndl)) == NULL || 7293 (imp_iter = scf_iter_create(g_hndl)) == NULL || 7294 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 7295 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 7296 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 7297 (imp_str = malloc(imp_str_sz)) == NULL || 7298 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 7299 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 7300 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 7301 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 7302 (ud_inst = scf_instance_create(g_hndl)) == NULL || 7303 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7304 (ud_pg = scf_pg_create(g_hndl)) == NULL || 7305 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 7306 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 7307 (ud_prop = scf_property_create(g_hndl)) == NULL || 7308 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 7309 (ud_val = scf_value_create(g_hndl)) == NULL || 7310 (ud_iter = scf_iter_create(g_hndl)) == NULL || 7311 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 7312 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 7313 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 7314 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 7315 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 7316 if (scf_error() == SCF_ERROR_NO_RESOURCES) 7317 warn(emsg_nores); 7318 else 7319 warn(emsg_nomem); 7320 result = -1; 7321 goto out; 7322 } 7323 7324 r = load_init(); 7325 switch (r) { 7326 case 0: 7327 break; 7328 7329 case ENOMEM: 7330 warn(emsg_nomem); 7331 result = -1; 7332 goto out; 7333 7334 default: 7335 bad_error("load_init", r); 7336 } 7337 7338 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 7339 switch (scf_error()) { 7340 case SCF_ERROR_CONNECTION_BROKEN: 7341 warn(gettext("Repository connection broken.\n")); 7342 repository_teardown(); 7343 result = -1; 7344 goto out; 7345 7346 case SCF_ERROR_NOT_FOUND: 7347 case SCF_ERROR_INVALID_ARGUMENT: 7348 case SCF_ERROR_NOT_BOUND: 7349 case SCF_ERROR_HANDLE_MISMATCH: 7350 default: 7351 bad_error("scf_handle_get_scope", scf_error()); 7352 } 7353 } 7354 7355 /* Set up the auditing annotation. */ 7356 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 7357 annotation_set = 1; 7358 } else { 7359 switch (scf_error()) { 7360 case SCF_ERROR_CONNECTION_BROKEN: 7361 warn(gettext("Repository connection broken.\n")); 7362 repository_teardown(); 7363 result = -1; 7364 goto out; 7365 7366 case SCF_ERROR_INVALID_ARGUMENT: 7367 case SCF_ERROR_NOT_BOUND: 7368 case SCF_ERROR_NO_RESOURCES: 7369 case SCF_ERROR_INTERNAL: 7370 bad_error("_scf_set_annotation", scf_error()); 7371 /* NOTREACHED */ 7372 7373 default: 7374 /* 7375 * Do not terminate import because of inability to 7376 * generate annotation audit event. 7377 */ 7378 warn(gettext("_scf_set_annotation() unexpectedly " 7379 "failed with return code of %d\n"), scf_error()); 7380 break; 7381 } 7382 } 7383 7384 /* 7385 * Clear the sc_import_state's of all services & instances so we can 7386 * report how far we got if we fail. 7387 */ 7388 for (svc = uu_list_first(bndl->sc_bundle_services); 7389 svc != NULL; 7390 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7391 svc->sc_import_state = 0; 7392 7393 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 7394 clear_int, (void *)offsetof(entity_t, sc_import_state), 7395 UU_DEFAULT) != 0) 7396 bad_error("uu_list_walk", uu_error()); 7397 } 7398 7399 cbdata.sc_handle = g_hndl; 7400 cbdata.sc_parent = imp_scope; 7401 cbdata.sc_flags = flags; 7402 cbdata.sc_general = NULL; 7403 7404 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 7405 &cbdata, UU_DEFAULT) == 0) { 7406 /* Success. Refresh everything. */ 7407 7408 if (flags & SCI_NOREFRESH || no_refresh) { 7409 no_refresh = 0; 7410 result = 0; 7411 goto out; 7412 } 7413 7414 for (svc = uu_list_first(bndl->sc_bundle_services); 7415 svc != NULL; 7416 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7417 pgroup_t *dpt; 7418 7419 insts = svc->sc_u.sc_service.sc_service_instances; 7420 7421 for (inst = uu_list_first(insts); 7422 inst != NULL; 7423 inst = uu_list_next(insts, inst)) { 7424 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 7425 switch (r) { 7426 case 0: 7427 break; 7428 7429 case ENOMEM: 7430 case ECONNABORTED: 7431 case EPERM: 7432 case -1: 7433 goto progress; 7434 7435 default: 7436 bad_error("imp_refresh_fmri", r); 7437 } 7438 7439 inst->sc_import_state = IMPORT_REFRESHED; 7440 7441 for (dpt = uu_list_first(inst->sc_dependents); 7442 dpt != NULL; 7443 dpt = uu_list_next(inst->sc_dependents, 7444 dpt)) 7445 if (imp_refresh_fmri( 7446 dpt->sc_pgroup_fmri, 7447 dpt->sc_pgroup_name, 7448 inst->sc_fmri) != 0) 7449 goto progress; 7450 } 7451 7452 for (dpt = uu_list_first(svc->sc_dependents); 7453 dpt != NULL; 7454 dpt = uu_list_next(svc->sc_dependents, dpt)) 7455 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 7456 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 7457 goto progress; 7458 } 7459 7460 for (old_dpt = uu_list_first(imp_deleted_dpts); 7461 old_dpt != NULL; 7462 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 7463 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 7464 old_dpt->sc_pgroup_name, 7465 old_dpt->sc_parent->sc_fmri) != 0) 7466 goto progress; 7467 7468 result = 0; 7469 goto out; 7470 } 7471 7472 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7473 bad_error("uu_list_walk", uu_error()); 7474 7475 printerr: 7476 /* If the error hasn't been printed yet, do so here. */ 7477 switch (cbdata.sc_err) { 7478 case ECONNABORTED: 7479 warn(gettext("Repository connection broken.\n")); 7480 break; 7481 7482 case ENOMEM: 7483 warn(emsg_nomem); 7484 break; 7485 7486 case ENOSPC: 7487 warn(emsg_nores); 7488 break; 7489 7490 case EROFS: 7491 warn(gettext("Repository is read-only.\n")); 7492 break; 7493 7494 case EACCES: 7495 warn(gettext("Repository backend denied access.\n")); 7496 break; 7497 7498 case EPERM: 7499 case EINVAL: 7500 case EEXIST: 7501 case EBUSY: 7502 case EBADF: 7503 case -1: 7504 break; 7505 7506 default: 7507 bad_error("lscf_service_import", cbdata.sc_err); 7508 } 7509 7510 progress: 7511 warn(gettext("Import of %s failed. Progress:\n"), filename); 7512 7513 for (svc = uu_list_first(bndl->sc_bundle_services); 7514 svc != NULL; 7515 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7516 insts = svc->sc_u.sc_service.sc_service_instances; 7517 7518 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 7519 import_progress(svc->sc_import_state)); 7520 7521 for (inst = uu_list_first(insts); 7522 inst != NULL; 7523 inst = uu_list_next(insts, inst)) 7524 warn(gettext(" Instance \"%s\": %s\n"), 7525 inst->sc_name, 7526 import_progress(inst->sc_import_state)); 7527 } 7528 7529 if (cbdata.sc_err == ECONNABORTED) 7530 repository_teardown(); 7531 7532 7533 result = -1; 7534 7535 out: 7536 if (annotation_set != 0) { 7537 /* Turn off annotation. It is no longer needed. */ 7538 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7539 } 7540 load_fini(); 7541 7542 free(ud_ctarg); 7543 free(ud_oldtarg); 7544 free(ud_name); 7545 ud_ctarg = ud_oldtarg = ud_name = NULL; 7546 7547 scf_transaction_destroy(ud_tx); 7548 ud_tx = NULL; 7549 scf_iter_destroy(ud_iter); 7550 scf_iter_destroy(ud_iter2); 7551 ud_iter = ud_iter2 = NULL; 7552 scf_value_destroy(ud_val); 7553 ud_val = NULL; 7554 scf_property_destroy(ud_prop); 7555 scf_property_destroy(ud_dpt_prop); 7556 ud_prop = ud_dpt_prop = NULL; 7557 scf_pg_destroy(ud_pg); 7558 scf_pg_destroy(ud_cur_depts_pg); 7559 scf_pg_destroy(ud_run_dpts_pg); 7560 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7561 scf_snaplevel_destroy(ud_snpl); 7562 ud_snpl = NULL; 7563 scf_instance_destroy(ud_inst); 7564 ud_inst = NULL; 7565 7566 free(imp_str); 7567 free(imp_tsname); 7568 free(imp_fe1); 7569 free(imp_fe2); 7570 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7571 7572 cookie = NULL; 7573 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7574 NULL) { 7575 free((char *)old_dpt->sc_pgroup_name); 7576 free((char *)old_dpt->sc_pgroup_fmri); 7577 internal_pgroup_free(old_dpt); 7578 } 7579 uu_list_destroy(imp_deleted_dpts); 7580 7581 scf_transaction_destroy(imp_tx); 7582 imp_tx = NULL; 7583 scf_iter_destroy(imp_iter); 7584 scf_iter_destroy(imp_rpg_iter); 7585 scf_iter_destroy(imp_up_iter); 7586 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7587 scf_property_destroy(imp_prop); 7588 imp_prop = NULL; 7589 scf_pg_destroy(imp_pg); 7590 scf_pg_destroy(imp_pg2); 7591 imp_pg = imp_pg2 = NULL; 7592 scf_snaplevel_destroy(imp_snpl); 7593 scf_snaplevel_destroy(imp_rsnpl); 7594 imp_snpl = imp_rsnpl = NULL; 7595 scf_snapshot_destroy(imp_snap); 7596 scf_snapshot_destroy(imp_lisnap); 7597 scf_snapshot_destroy(imp_tlisnap); 7598 scf_snapshot_destroy(imp_rsnap); 7599 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7600 scf_instance_destroy(imp_inst); 7601 scf_instance_destroy(imp_tinst); 7602 imp_inst = imp_tinst = NULL; 7603 scf_service_destroy(imp_svc); 7604 scf_service_destroy(imp_tsvc); 7605 imp_svc = imp_tsvc = NULL; 7606 scf_scope_destroy(imp_scope); 7607 imp_scope = NULL; 7608 7609 return (result); 7610 } 7611 7612 /* 7613 * _lscf_import_err() summarize the error handling returned by 7614 * lscf_import_{instance | service}_pgs 7615 * Return values are: 7616 * IMPORT_NEXT 7617 * IMPORT_OUT 7618 * IMPORT_BAD 7619 */ 7620 7621 #define IMPORT_BAD -1 7622 #define IMPORT_NEXT 0 7623 #define IMPORT_OUT 1 7624 7625 static int 7626 _lscf_import_err(int err, const char *fmri) 7627 { 7628 switch (err) { 7629 case 0: 7630 if (g_verbose) 7631 warn(gettext("%s updated.\n"), fmri); 7632 return (IMPORT_NEXT); 7633 7634 case ECONNABORTED: 7635 warn(gettext("Could not update %s " 7636 "(repository connection broken).\n"), fmri); 7637 return (IMPORT_OUT); 7638 7639 case ENOMEM: 7640 warn(gettext("Could not update %s (out of memory).\n"), fmri); 7641 return (IMPORT_OUT); 7642 7643 case ENOSPC: 7644 warn(gettext("Could not update %s " 7645 "(repository server out of resources).\n"), fmri); 7646 return (IMPORT_OUT); 7647 7648 case ECANCELED: 7649 warn(gettext( 7650 "Could not update %s (deleted).\n"), fmri); 7651 return (IMPORT_NEXT); 7652 7653 case EPERM: 7654 case EINVAL: 7655 case EBUSY: 7656 return (IMPORT_NEXT); 7657 7658 case EROFS: 7659 warn(gettext("Could not update %s (repository read-only).\n"), 7660 fmri); 7661 return (IMPORT_OUT); 7662 7663 case EACCES: 7664 warn(gettext("Could not update %s " 7665 "(backend access denied).\n"), fmri); 7666 return (IMPORT_NEXT); 7667 7668 case EEXIST: 7669 default: 7670 return (IMPORT_BAD); 7671 } 7672 7673 /*NOTREACHED*/ 7674 } 7675 7676 /* 7677 * Returns 7678 * 0 - success 7679 * -1 - lscf_import_instance_pgs() failed. 7680 */ 7681 int 7682 lscf_bundle_apply(bundle_t *bndl, const char *file) 7683 { 7684 entity_t *svc, *inst; 7685 scf_scope_t *rscope; 7686 scf_service_t *rsvc; 7687 scf_instance_t *rinst; 7688 scf_snapshot_t *rsnap; 7689 scf_iter_t *iter; 7690 int annotation_set = 0; 7691 int r; 7692 7693 lscf_prep_hndl(); 7694 7695 if ((rscope = scf_scope_create(g_hndl)) == NULL || 7696 (rsvc = scf_service_create(g_hndl)) == NULL || 7697 (rinst = scf_instance_create(g_hndl)) == NULL || 7698 (rsnap = scf_snapshot_create(g_hndl)) == NULL || 7699 (iter = scf_iter_create(g_hndl)) == NULL || 7700 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7701 (imp_prop = scf_property_create(g_hndl)) == NULL || 7702 (imp_tx = scf_transaction_create(g_hndl)) == NULL) 7703 scfdie(); 7704 7705 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0) 7706 scfdie(); 7707 7708 /* 7709 * Set the strings to be used for the security audit annotation 7710 * event. 7711 */ 7712 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 7713 annotation_set = 1; 7714 } else { 7715 switch (scf_error()) { 7716 case SCF_ERROR_CONNECTION_BROKEN: 7717 warn(gettext("Repository connection broken.\n")); 7718 goto out; 7719 7720 case SCF_ERROR_INVALID_ARGUMENT: 7721 case SCF_ERROR_NOT_BOUND: 7722 case SCF_ERROR_NO_RESOURCES: 7723 case SCF_ERROR_INTERNAL: 7724 bad_error("_scf_set_annotation", scf_error()); 7725 /* NOTREACHED */ 7726 7727 default: 7728 /* 7729 * Do not abort apply operation because of 7730 * inability to create annotation audit event. 7731 */ 7732 warn(gettext("_scf_set_annotation() unexpectedly " 7733 "failed with return code of %d\n"), scf_error()); 7734 break; 7735 } 7736 } 7737 7738 for (svc = uu_list_first(bndl->sc_bundle_services); 7739 svc != NULL; 7740 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7741 int refresh = 0; 7742 7743 if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) { 7744 switch (scf_error()) { 7745 case SCF_ERROR_NOT_FOUND: 7746 if (g_verbose) 7747 warn(gettext("Ignoring nonexistent " 7748 "service %s.\n"), svc->sc_name); 7749 continue; 7750 7751 default: 7752 scfdie(); 7753 } 7754 } 7755 7756 /* 7757 * if we have pgs in the profile, we need to refresh ALL 7758 * instances of the service 7759 */ 7760 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 7761 refresh = 1; 7762 r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc, 7763 SCI_FORCE | SCI_KEEP); 7764 switch (_lscf_import_err(r, svc->sc_fmri)) { 7765 case IMPORT_NEXT: 7766 break; 7767 7768 case IMPORT_OUT: 7769 goto out; 7770 7771 case IMPORT_BAD: 7772 default: 7773 bad_error("lscf_import_service_pgs", r); 7774 } 7775 } 7776 7777 for (inst = uu_list_first( 7778 svc->sc_u.sc_service.sc_service_instances); 7779 inst != NULL; 7780 inst = uu_list_next( 7781 svc->sc_u.sc_service.sc_service_instances, inst)) { 7782 if (scf_service_get_instance(rsvc, inst->sc_name, 7783 rinst) != 0) { 7784 switch (scf_error()) { 7785 case SCF_ERROR_NOT_FOUND: 7786 if (g_verbose) 7787 warn(gettext("Ignoring " 7788 "nonexistant instance " 7789 "%s:%s.\n"), 7790 inst->sc_parent->sc_name, 7791 inst->sc_name); 7792 continue; 7793 7794 default: 7795 scfdie(); 7796 } 7797 } 7798 7799 /* 7800 * If the instance does not have a general/enabled 7801 * property and no last-import snapshot then the 7802 * instance is not a fully installed instance and 7803 * should not have a profile applied to it. 7804 * 7805 * This could happen if a service/instance declares 7806 * a dependent on behalf of another service/instance. 7807 */ 7808 if (scf_instance_get_snapshot(rinst, snap_lastimport, 7809 rsnap) != 0) { 7810 if (scf_instance_get_pg(rinst, SCF_PG_GENERAL, 7811 imp_pg) != 0 || scf_pg_get_property(imp_pg, 7812 SCF_PROPERTY_ENABLED, imp_prop) != 0) { 7813 if (g_verbose) 7814 warn(gettext("Ignoreing " 7815 "partial instance " 7816 "%s:%s.\n"), 7817 inst->sc_parent->sc_name, 7818 inst->sc_name); 7819 continue; 7820 } 7821 } 7822 7823 r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst, 7824 SCI_FORCE | SCI_KEEP); 7825 switch (_lscf_import_err(r, inst->sc_fmri)) { 7826 case IMPORT_NEXT: 7827 break; 7828 7829 case IMPORT_OUT: 7830 goto out; 7831 7832 case IMPORT_BAD: 7833 default: 7834 bad_error("lscf_import_instance_pgs", r); 7835 } 7836 7837 /* refresh only if there is no pgs in the service */ 7838 if (refresh == 0) 7839 (void) refresh_entity(0, rinst, inst->sc_fmri, 7840 NULL, NULL, NULL); 7841 } 7842 7843 if (refresh == 1) { 7844 char *name_buf = safe_malloc(max_scf_name_len + 1); 7845 7846 (void) refresh_entity(1, rsvc, svc->sc_name, rinst, 7847 iter, name_buf); 7848 free(name_buf); 7849 } 7850 } 7851 7852 out: 7853 if (annotation_set) { 7854 /* Remove security audit annotation strings. */ 7855 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7856 } 7857 7858 scf_transaction_destroy(imp_tx); 7859 imp_tx = NULL; 7860 scf_pg_destroy(imp_pg); 7861 imp_pg = NULL; 7862 scf_property_destroy(imp_prop); 7863 imp_prop = NULL; 7864 7865 scf_snapshot_destroy(rsnap); 7866 scf_iter_destroy(iter); 7867 scf_instance_destroy(rinst); 7868 scf_service_destroy(rsvc); 7869 scf_scope_destroy(rscope); 7870 return (0); 7871 } 7872 7873 7874 /* 7875 * Export. These functions create and output an XML tree of a service 7876 * description from the repository. This is largely the inverse of 7877 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 7878 * 7879 * - We must include any properties which are not represented specifically by 7880 * a service manifest, e.g., properties created by an admin post-import. To 7881 * do so we'll iterate through all properties and deal with each 7882 * apropriately. 7883 * 7884 * - Children of services and instances must must be in the order set by the 7885 * DTD, but we iterate over the properties in undefined order. The elements 7886 * are not easily (or efficiently) sortable by name. Since there's a fixed 7887 * number of classes of them, however, we'll keep the classes separate and 7888 * assemble them in order. 7889 */ 7890 7891 /* 7892 * Convenience function to handle xmlSetProp errors (and type casting). 7893 */ 7894 static void 7895 safe_setprop(xmlNodePtr n, const char *name, const char *val) 7896 { 7897 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 7898 uu_die(gettext("Could not set XML property.\n")); 7899 } 7900 7901 /* 7902 * Convenience function to set an XML attribute to the single value of an 7903 * astring property. If the value happens to be the default, don't set the 7904 * attribute. "dval" should be the default value supplied by the DTD, or 7905 * NULL for no default. 7906 */ 7907 static int 7908 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 7909 const char *name, const char *dval) 7910 { 7911 scf_value_t *val; 7912 ssize_t len; 7913 char *str; 7914 7915 val = scf_value_create(g_hndl); 7916 if (val == NULL) 7917 scfdie(); 7918 7919 if (prop_get_val(prop, val) != 0) { 7920 scf_value_destroy(val); 7921 return (-1); 7922 } 7923 7924 len = scf_value_get_as_string(val, NULL, 0); 7925 if (len < 0) 7926 scfdie(); 7927 7928 str = safe_malloc(len + 1); 7929 7930 if (scf_value_get_as_string(val, str, len + 1) < 0) 7931 scfdie(); 7932 7933 scf_value_destroy(val); 7934 7935 if (dval == NULL || strcmp(str, dval) != 0) 7936 safe_setprop(n, name, str); 7937 7938 free(str); 7939 7940 return (0); 7941 } 7942 7943 /* 7944 * As above, but the attribute is always set. 7945 */ 7946 static int 7947 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 7948 { 7949 return (set_attr_from_prop_default(prop, n, name, NULL)); 7950 } 7951 7952 /* 7953 * Dump the given document onto f, with "'s replaced by ''s. 7954 */ 7955 static int 7956 write_service_bundle(xmlDocPtr doc, FILE *f) 7957 { 7958 xmlChar *mem; 7959 int sz, i; 7960 7961 mem = NULL; 7962 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 7963 7964 if (mem == NULL) { 7965 semerr(gettext("Could not dump XML tree.\n")); 7966 return (-1); 7967 } 7968 7969 /* 7970 * Fortunately libxml produces " instead of ", so we can blindly 7971 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 7972 * ' code?! 7973 */ 7974 for (i = 0; i < sz; ++i) { 7975 char c = (char)mem[i]; 7976 7977 if (c == '"') 7978 (void) fputc('\'', f); 7979 else if (c == '\'') 7980 (void) fwrite("'", sizeof ("'") - 1, 1, f); 7981 else 7982 (void) fputc(c, f); 7983 } 7984 7985 return (0); 7986 } 7987 7988 /* 7989 * Create the DOM elements in elts necessary to (generically) represent prop 7990 * (i.e., a property or propval element). If the name of the property is 7991 * known, it should be passed as name_arg. Otherwise, pass NULL. 7992 */ 7993 static void 7994 export_property(scf_property_t *prop, const char *name_arg, 7995 struct pg_elts *elts, int flags) 7996 { 7997 const char *type; 7998 scf_error_t err = 0; 7999 xmlNodePtr pnode, lnode; 8000 char *lnname; 8001 int ret; 8002 8003 /* name */ 8004 if (name_arg != NULL) { 8005 (void) strcpy(exp_str, name_arg); 8006 } else { 8007 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 8008 scfdie(); 8009 } 8010 8011 /* type */ 8012 type = prop_to_typestr(prop); 8013 if (type == NULL) 8014 uu_die(gettext("Can't export property %s: unknown type.\n"), 8015 exp_str); 8016 8017 /* If we're exporting values, and there's just one, export it here. */ 8018 if (!(flags & SCE_ALL_VALUES)) 8019 goto empty; 8020 8021 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 8022 xmlNodePtr n; 8023 8024 /* Single value, so use propval */ 8025 n = xmlNewNode(NULL, (xmlChar *)"propval"); 8026 if (n == NULL) 8027 uu_die(emsg_create_xml); 8028 8029 safe_setprop(n, name_attr, exp_str); 8030 safe_setprop(n, type_attr, type); 8031 8032 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8033 scfdie(); 8034 safe_setprop(n, value_attr, exp_str); 8035 8036 if (elts->propvals == NULL) 8037 elts->propvals = n; 8038 else 8039 (void) xmlAddSibling(elts->propvals, n); 8040 8041 return; 8042 } 8043 8044 err = scf_error(); 8045 8046 if (err == SCF_ERROR_PERMISSION_DENIED) { 8047 semerr(emsg_permission_denied); 8048 return; 8049 } 8050 8051 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 8052 err != SCF_ERROR_NOT_FOUND && 8053 err != SCF_ERROR_PERMISSION_DENIED) 8054 scfdie(); 8055 8056 empty: 8057 /* Multiple (or no) values, so use property */ 8058 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 8059 if (pnode == NULL) 8060 uu_die(emsg_create_xml); 8061 8062 safe_setprop(pnode, name_attr, exp_str); 8063 safe_setprop(pnode, type_attr, type); 8064 8065 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 8066 lnname = uu_msprintf("%s_list", type); 8067 if (lnname == NULL) 8068 uu_die(gettext("Could not create string")); 8069 8070 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 8071 if (lnode == NULL) 8072 uu_die(emsg_create_xml); 8073 8074 uu_free(lnname); 8075 8076 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 8077 scfdie(); 8078 8079 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 8080 1) { 8081 xmlNodePtr vn; 8082 8083 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 8084 NULL); 8085 if (vn == NULL) 8086 uu_die(emsg_create_xml); 8087 8088 if (scf_value_get_as_string(exp_val, exp_str, 8089 exp_str_sz) < 0) 8090 scfdie(); 8091 safe_setprop(vn, value_attr, exp_str); 8092 } 8093 if (ret != 0) 8094 scfdie(); 8095 } 8096 8097 if (elts->properties == NULL) 8098 elts->properties = pnode; 8099 else 8100 (void) xmlAddSibling(elts->properties, pnode); 8101 } 8102 8103 /* 8104 * Add a property_group element for this property group to elts. 8105 */ 8106 static void 8107 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 8108 { 8109 xmlNodePtr n; 8110 struct pg_elts elts; 8111 int ret; 8112 boolean_t read_protected; 8113 8114 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 8115 8116 /* name */ 8117 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8118 scfdie(); 8119 safe_setprop(n, name_attr, exp_str); 8120 8121 /* type */ 8122 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 8123 scfdie(); 8124 safe_setprop(n, type_attr, exp_str); 8125 8126 /* properties */ 8127 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8128 scfdie(); 8129 8130 (void) memset(&elts, 0, sizeof (elts)); 8131 8132 /* 8133 * If this property group is not read protected, we always want to 8134 * output all the values. Otherwise, we only output the values if the 8135 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 8136 */ 8137 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 8138 scfdie(); 8139 8140 if (!read_protected) 8141 flags |= SCE_ALL_VALUES; 8142 8143 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8144 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8145 scfdie(); 8146 8147 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8148 xmlNodePtr m; 8149 8150 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8151 if (m == NULL) 8152 uu_die(emsg_create_xml); 8153 8154 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8155 elts.stability = m; 8156 continue; 8157 } 8158 8159 xmlFreeNode(m); 8160 } 8161 8162 export_property(exp_prop, NULL, &elts, flags); 8163 } 8164 if (ret == -1) 8165 scfdie(); 8166 8167 (void) xmlAddChild(n, elts.stability); 8168 (void) xmlAddChildList(n, elts.propvals); 8169 (void) xmlAddChildList(n, elts.properties); 8170 8171 if (eelts->property_groups == NULL) 8172 eelts->property_groups = n; 8173 else 8174 (void) xmlAddSibling(eelts->property_groups, n); 8175 } 8176 8177 /* 8178 * Create an XML node representing the dependency described by the given 8179 * property group and put it in eelts. Unless the dependency is not valid, in 8180 * which case create a generic property_group element which represents it and 8181 * put it in eelts. 8182 */ 8183 static void 8184 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 8185 { 8186 xmlNodePtr n; 8187 int err = 0, ret; 8188 struct pg_elts elts; 8189 8190 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 8191 if (n == NULL) 8192 uu_die(emsg_create_xml); 8193 8194 /* 8195 * If the external flag is present, skip this dependency because it 8196 * should have been created by another manifest. 8197 */ 8198 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 8199 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8200 prop_get_val(exp_prop, exp_val) == 0) { 8201 uint8_t b; 8202 8203 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 8204 scfdie(); 8205 8206 if (b) 8207 return; 8208 } 8209 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 8210 scfdie(); 8211 8212 /* Get the required attributes. */ 8213 8214 /* name */ 8215 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8216 scfdie(); 8217 safe_setprop(n, name_attr, exp_str); 8218 8219 /* grouping */ 8220 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8221 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8222 err = 1; 8223 8224 /* restart_on */ 8225 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8226 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8227 err = 1; 8228 8229 /* type */ 8230 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8231 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8232 err = 1; 8233 8234 /* 8235 * entities: Not required, but if we create no children, it will be 8236 * created as empty on import, so fail if it's missing. 8237 */ 8238 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8239 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 8240 scf_iter_t *eiter; 8241 int ret2; 8242 8243 eiter = scf_iter_create(g_hndl); 8244 if (eiter == NULL) 8245 scfdie(); 8246 8247 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 8248 scfdie(); 8249 8250 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 8251 xmlNodePtr ch; 8252 8253 if (scf_value_get_astring(exp_val, exp_str, 8254 exp_str_sz) < 0) 8255 scfdie(); 8256 8257 /* 8258 * service_fmri's must be first, so we can add them 8259 * here. 8260 */ 8261 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 8262 NULL); 8263 if (ch == NULL) 8264 uu_die(emsg_create_xml); 8265 8266 safe_setprop(ch, value_attr, exp_str); 8267 } 8268 if (ret2 == -1) 8269 scfdie(); 8270 8271 scf_iter_destroy(eiter); 8272 } else 8273 err = 1; 8274 8275 if (err) { 8276 xmlFreeNode(n); 8277 8278 export_pg(pg, eelts, 0); 8279 8280 return; 8281 } 8282 8283 /* Iterate through the properties & handle each. */ 8284 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8285 scfdie(); 8286 8287 (void) memset(&elts, 0, sizeof (elts)); 8288 8289 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8290 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8291 scfdie(); 8292 8293 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8294 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8295 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 8296 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8297 continue; 8298 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8299 xmlNodePtr m; 8300 8301 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8302 if (m == NULL) 8303 uu_die(emsg_create_xml); 8304 8305 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8306 elts.stability = m; 8307 continue; 8308 } 8309 8310 xmlFreeNode(m); 8311 } 8312 8313 export_property(exp_prop, exp_str, &elts, 0); 8314 } 8315 if (ret == -1) 8316 scfdie(); 8317 8318 (void) xmlAddChild(n, elts.stability); 8319 (void) xmlAddChildList(n, elts.propvals); 8320 (void) xmlAddChildList(n, elts.properties); 8321 8322 if (eelts->dependencies == NULL) 8323 eelts->dependencies = n; 8324 else 8325 (void) xmlAddSibling(eelts->dependencies, n); 8326 } 8327 8328 static xmlNodePtr 8329 export_method_environment(scf_propertygroup_t *pg) 8330 { 8331 xmlNodePtr env; 8332 int ret; 8333 int children = 0; 8334 8335 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 8336 return (NULL); 8337 8338 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 8339 if (env == NULL) 8340 uu_die(emsg_create_xml); 8341 8342 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 8343 scfdie(); 8344 8345 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 8346 scfdie(); 8347 8348 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 8349 xmlNodePtr ev; 8350 char *cp; 8351 8352 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8353 scfdie(); 8354 8355 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 8356 warn(gettext("Invalid environment variable \"%s\".\n"), 8357 exp_str); 8358 continue; 8359 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 8360 warn(gettext("Invalid environment variable \"%s\"; " 8361 "\"SMF_\" prefix is reserved.\n"), exp_str); 8362 continue; 8363 } 8364 8365 *cp = '\0'; 8366 cp++; 8367 8368 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 8369 if (ev == NULL) 8370 uu_die(emsg_create_xml); 8371 8372 safe_setprop(ev, name_attr, exp_str); 8373 safe_setprop(ev, value_attr, cp); 8374 children++; 8375 } 8376 8377 if (ret != 0) 8378 scfdie(); 8379 8380 if (children == 0) { 8381 xmlFreeNode(env); 8382 return (NULL); 8383 } 8384 8385 return (env); 8386 } 8387 8388 /* 8389 * As above, but for a method property group. 8390 */ 8391 static void 8392 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 8393 { 8394 xmlNodePtr n, env; 8395 char *str; 8396 int err = 0, nonenv, ret; 8397 uint8_t use_profile; 8398 struct pg_elts elts; 8399 xmlNodePtr ctxt = NULL; 8400 8401 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 8402 8403 /* Get the required attributes. */ 8404 8405 /* name */ 8406 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8407 scfdie(); 8408 safe_setprop(n, name_attr, exp_str); 8409 8410 /* type */ 8411 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8412 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8413 err = 1; 8414 8415 /* exec */ 8416 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 8417 set_attr_from_prop(exp_prop, n, "exec") != 0) 8418 err = 1; 8419 8420 /* timeout */ 8421 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 8422 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 8423 prop_get_val(exp_prop, exp_val) == 0) { 8424 uint64_t c; 8425 8426 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 8427 scfdie(); 8428 8429 str = uu_msprintf("%llu", c); 8430 if (str == NULL) 8431 uu_die(gettext("Could not create string")); 8432 8433 safe_setprop(n, "timeout_seconds", str); 8434 free(str); 8435 } else 8436 err = 1; 8437 8438 if (err) { 8439 xmlFreeNode(n); 8440 8441 export_pg(pg, eelts, 0); 8442 8443 return; 8444 } 8445 8446 8447 /* 8448 * If we're going to have a method_context child, we need to know 8449 * before we iterate through the properties. Since method_context's 8450 * are optional, we don't want to complain about any properties 8451 * missing if none of them are there. Thus we can't use the 8452 * convenience functions. 8453 */ 8454 nonenv = 8455 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 8456 SCF_SUCCESS || 8457 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 8458 SCF_SUCCESS || 8459 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 8460 SCF_SUCCESS || 8461 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 8462 SCF_SUCCESS; 8463 8464 if (nonenv) { 8465 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 8466 if (ctxt == NULL) 8467 uu_die(emsg_create_xml); 8468 8469 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 8470 0 && 8471 set_attr_from_prop_default(exp_prop, ctxt, 8472 "working_directory", ":default") != 0) 8473 err = 1; 8474 8475 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 8476 set_attr_from_prop_default(exp_prop, ctxt, "project", 8477 ":default") != 0) 8478 err = 1; 8479 8480 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 8481 0 && 8482 set_attr_from_prop_default(exp_prop, ctxt, 8483 "resource_pool", ":default") != 0) 8484 err = 1; 8485 /* 8486 * We only want to complain about profile or credential 8487 * properties if we will use them. To determine that we must 8488 * examine USE_PROFILE. 8489 */ 8490 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 8491 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8492 prop_get_val(exp_prop, exp_val) == 0) { 8493 if (scf_value_get_boolean(exp_val, &use_profile) != 8494 SCF_SUCCESS) { 8495 scfdie(); 8496 } 8497 8498 if (use_profile) { 8499 xmlNodePtr prof; 8500 8501 prof = xmlNewChild(ctxt, NULL, 8502 (xmlChar *)"method_profile", NULL); 8503 if (prof == NULL) 8504 uu_die(emsg_create_xml); 8505 8506 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 8507 exp_prop) != 0 || 8508 set_attr_from_prop(exp_prop, prof, 8509 name_attr) != 0) 8510 err = 1; 8511 } else { 8512 xmlNodePtr cred; 8513 8514 cred = xmlNewChild(ctxt, NULL, 8515 (xmlChar *)"method_credential", NULL); 8516 if (cred == NULL) 8517 uu_die(emsg_create_xml); 8518 8519 if (pg_get_prop(pg, SCF_PROPERTY_USER, 8520 exp_prop) != 0 || 8521 set_attr_from_prop(exp_prop, cred, 8522 "user") != 0) { 8523 err = 1; 8524 } 8525 8526 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 8527 exp_prop) == 0 && 8528 set_attr_from_prop_default(exp_prop, cred, 8529 "group", ":default") != 0) 8530 err = 1; 8531 8532 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 8533 exp_prop) == 0 && 8534 set_attr_from_prop_default(exp_prop, cred, 8535 "supp_groups", ":default") != 0) 8536 err = 1; 8537 8538 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 8539 exp_prop) == 0 && 8540 set_attr_from_prop_default(exp_prop, cred, 8541 "privileges", ":default") != 0) 8542 err = 1; 8543 8544 if (pg_get_prop(pg, 8545 SCF_PROPERTY_LIMIT_PRIVILEGES, 8546 exp_prop) == 0 && 8547 set_attr_from_prop_default(exp_prop, cred, 8548 "limit_privileges", ":default") != 0) 8549 err = 1; 8550 } 8551 } 8552 } 8553 8554 if ((env = export_method_environment(pg)) != NULL) { 8555 if (ctxt == NULL) { 8556 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 8557 if (ctxt == NULL) 8558 uu_die(emsg_create_xml); 8559 } 8560 (void) xmlAddChild(ctxt, env); 8561 } 8562 8563 if (env != NULL || (nonenv && err == 0)) 8564 (void) xmlAddChild(n, ctxt); 8565 else 8566 xmlFreeNode(ctxt); 8567 8568 nonenv = (err == 0); 8569 8570 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8571 scfdie(); 8572 8573 (void) memset(&elts, 0, sizeof (elts)); 8574 8575 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8576 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8577 scfdie(); 8578 8579 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 8580 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 8581 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 8582 continue; 8583 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8584 xmlNodePtr m; 8585 8586 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8587 if (m == NULL) 8588 uu_die(emsg_create_xml); 8589 8590 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8591 elts.stability = m; 8592 continue; 8593 } 8594 8595 xmlFreeNode(m); 8596 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 8597 0 || 8598 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 8599 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 8600 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8601 if (nonenv) 8602 continue; 8603 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 8604 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 8605 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 8606 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 8607 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 8608 if (nonenv && !use_profile) 8609 continue; 8610 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8611 if (nonenv && use_profile) 8612 continue; 8613 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 8614 if (env != NULL) 8615 continue; 8616 } 8617 8618 export_property(exp_prop, exp_str, &elts, 0); 8619 } 8620 if (ret == -1) 8621 scfdie(); 8622 8623 (void) xmlAddChild(n, elts.stability); 8624 (void) xmlAddChildList(n, elts.propvals); 8625 (void) xmlAddChildList(n, elts.properties); 8626 8627 if (eelts->exec_methods == NULL) 8628 eelts->exec_methods = n; 8629 else 8630 (void) xmlAddSibling(eelts->exec_methods, n); 8631 } 8632 8633 static void 8634 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 8635 struct entity_elts *eelts) 8636 { 8637 xmlNodePtr pgnode; 8638 8639 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 8640 if (pgnode == NULL) 8641 uu_die(emsg_create_xml); 8642 8643 safe_setprop(pgnode, name_attr, name); 8644 safe_setprop(pgnode, type_attr, type); 8645 8646 (void) xmlAddChildList(pgnode, elts->propvals); 8647 (void) xmlAddChildList(pgnode, elts->properties); 8648 8649 if (eelts->property_groups == NULL) 8650 eelts->property_groups = pgnode; 8651 else 8652 (void) xmlAddSibling(eelts->property_groups, pgnode); 8653 } 8654 8655 /* 8656 * Process the general property group for a service. This is the one with the 8657 * goodies. 8658 */ 8659 static void 8660 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 8661 { 8662 struct pg_elts elts; 8663 int ret; 8664 8665 /* 8666 * In case there are properties which don't correspond to child 8667 * entities of the service entity, we'll set up a pg_elts structure to 8668 * put them in. 8669 */ 8670 (void) memset(&elts, 0, sizeof (elts)); 8671 8672 /* Walk the properties, looking for special ones. */ 8673 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8674 scfdie(); 8675 8676 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8677 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8678 scfdie(); 8679 8680 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 8681 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8682 prop_get_val(exp_prop, exp_val) == 0) { 8683 uint8_t b; 8684 8685 if (scf_value_get_boolean(exp_val, &b) != 8686 SCF_SUCCESS) 8687 scfdie(); 8688 8689 if (b) { 8690 selts->single_instance = 8691 xmlNewNode(NULL, 8692 (xmlChar *)"single_instance"); 8693 if (selts->single_instance == NULL) 8694 uu_die(emsg_create_xml); 8695 } 8696 8697 continue; 8698 } 8699 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8700 xmlNodePtr rnode, sfnode; 8701 8702 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8703 if (rnode == NULL) 8704 uu_die(emsg_create_xml); 8705 8706 sfnode = xmlNewChild(rnode, NULL, 8707 (xmlChar *)"service_fmri", NULL); 8708 if (sfnode == NULL) 8709 uu_die(emsg_create_xml); 8710 8711 if (set_attr_from_prop(exp_prop, sfnode, 8712 value_attr) == 0) { 8713 selts->restarter = rnode; 8714 continue; 8715 } 8716 8717 xmlFreeNode(rnode); 8718 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 8719 0) { 8720 xmlNodePtr s; 8721 8722 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8723 if (s == NULL) 8724 uu_die(emsg_create_xml); 8725 8726 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8727 selts->stability = s; 8728 continue; 8729 } 8730 8731 xmlFreeNode(s); 8732 } 8733 8734 export_property(exp_prop, exp_str, &elts, 0); 8735 } 8736 if (ret == -1) 8737 scfdie(); 8738 8739 if (elts.propvals != NULL || elts.properties != NULL) 8740 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 8741 selts); 8742 } 8743 8744 static void 8745 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 8746 { 8747 xmlNodePtr n, prof, cred, env; 8748 uint8_t use_profile; 8749 int ret, err = 0; 8750 8751 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 8752 8753 env = export_method_environment(pg); 8754 8755 /* Need to know whether we'll use a profile or not. */ 8756 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 8757 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8758 prop_get_val(exp_prop, exp_val) == 0) { 8759 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 8760 scfdie(); 8761 8762 if (use_profile) 8763 prof = 8764 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 8765 NULL); 8766 else 8767 cred = 8768 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 8769 NULL); 8770 } 8771 8772 if (env != NULL) 8773 (void) xmlAddChild(n, env); 8774 8775 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8776 scfdie(); 8777 8778 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8779 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8780 scfdie(); 8781 8782 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 8783 if (set_attr_from_prop(exp_prop, n, 8784 "working_directory") != 0) 8785 err = 1; 8786 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 8787 if (set_attr_from_prop(exp_prop, n, "project") != 0) 8788 err = 1; 8789 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 8790 if (set_attr_from_prop(exp_prop, n, 8791 "resource_pool") != 0) 8792 err = 1; 8793 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8794 /* EMPTY */ 8795 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 8796 if (use_profile || 8797 set_attr_from_prop(exp_prop, cred, "user") != 0) 8798 err = 1; 8799 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 8800 if (use_profile || 8801 set_attr_from_prop(exp_prop, cred, "group") != 0) 8802 err = 1; 8803 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 8804 if (use_profile || set_attr_from_prop(exp_prop, cred, 8805 "supp_groups") != 0) 8806 err = 1; 8807 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 8808 if (use_profile || set_attr_from_prop(exp_prop, cred, 8809 "privileges") != 0) 8810 err = 1; 8811 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 8812 0) { 8813 if (use_profile || set_attr_from_prop(exp_prop, cred, 8814 "limit_privileges") != 0) 8815 err = 1; 8816 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8817 if (!use_profile || set_attr_from_prop(exp_prop, 8818 prof, name_attr) != 0) 8819 err = 1; 8820 } else { 8821 /* Can't have generic properties in method_context's */ 8822 err = 1; 8823 } 8824 } 8825 if (ret == -1) 8826 scfdie(); 8827 8828 if (err && env == NULL) { 8829 xmlFreeNode(n); 8830 export_pg(pg, elts, 0); 8831 return; 8832 } 8833 8834 elts->method_context = n; 8835 } 8836 8837 /* 8838 * Given a dependency property group in the tfmri entity (target fmri), return 8839 * a dependent element which represents it. 8840 */ 8841 static xmlNodePtr 8842 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 8843 { 8844 uint8_t b; 8845 xmlNodePtr n, sf; 8846 int err = 0, ret; 8847 struct pg_elts pgelts; 8848 8849 /* 8850 * If external isn't set to true then exporting the service will 8851 * export this as a normal dependency, so we should stop to avoid 8852 * duplication. 8853 */ 8854 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 8855 scf_property_get_value(exp_prop, exp_val) != 0 || 8856 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 8857 if (g_verbose) { 8858 warn(gettext("Dependent \"%s\" cannot be exported " 8859 "properly because the \"%s\" property of the " 8860 "\"%s\" dependency of %s is not set to true.\n"), 8861 name, scf_property_external, name, tfmri); 8862 } 8863 8864 return (NULL); 8865 } 8866 8867 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 8868 if (n == NULL) 8869 uu_die(emsg_create_xml); 8870 8871 safe_setprop(n, name_attr, name); 8872 8873 /* Get the required attributes */ 8874 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8875 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8876 err = 1; 8877 8878 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8879 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8880 err = 1; 8881 8882 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8883 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 8884 prop_get_val(exp_prop, exp_val) == 0) { 8885 /* EMPTY */ 8886 } else 8887 err = 1; 8888 8889 if (err) { 8890 xmlFreeNode(n); 8891 return (NULL); 8892 } 8893 8894 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 8895 if (sf == NULL) 8896 uu_die(emsg_create_xml); 8897 8898 safe_setprop(sf, value_attr, tfmri); 8899 8900 /* 8901 * Now add elements for the other properties. 8902 */ 8903 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8904 scfdie(); 8905 8906 (void) memset(&pgelts, 0, sizeof (pgelts)); 8907 8908 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8909 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8910 scfdie(); 8911 8912 if (strcmp(exp_str, scf_property_external) == 0 || 8913 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8914 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8915 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8916 continue; 8917 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 8918 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 8919 prop_get_val(exp_prop, exp_val) == 0) { 8920 char type[sizeof ("service") + 1]; 8921 8922 if (scf_value_get_astring(exp_val, type, 8923 sizeof (type)) < 0) 8924 scfdie(); 8925 8926 if (strcmp(type, "service") == 0) 8927 continue; 8928 } 8929 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8930 xmlNodePtr s; 8931 8932 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8933 if (s == NULL) 8934 uu_die(emsg_create_xml); 8935 8936 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8937 pgelts.stability = s; 8938 continue; 8939 } 8940 8941 xmlFreeNode(s); 8942 } 8943 8944 export_property(exp_prop, exp_str, &pgelts, 0); 8945 } 8946 if (ret == -1) 8947 scfdie(); 8948 8949 (void) xmlAddChild(n, pgelts.stability); 8950 (void) xmlAddChildList(n, pgelts.propvals); 8951 (void) xmlAddChildList(n, pgelts.properties); 8952 8953 return (n); 8954 } 8955 8956 static void 8957 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 8958 { 8959 scf_propertygroup_t *opg; 8960 scf_iter_t *iter; 8961 char *type, *fmri; 8962 int ret; 8963 struct pg_elts pgelts; 8964 xmlNodePtr n; 8965 scf_error_t serr; 8966 8967 if ((opg = scf_pg_create(g_hndl)) == NULL || 8968 (iter = scf_iter_create(g_hndl)) == NULL) 8969 scfdie(); 8970 8971 /* Can't use exp_prop_iter due to export_dependent(). */ 8972 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 8973 scfdie(); 8974 8975 type = safe_malloc(max_scf_pg_type_len + 1); 8976 8977 /* Get an extra byte so we can tell if values are too long. */ 8978 fmri = safe_malloc(max_scf_fmri_len + 2); 8979 8980 (void) memset(&pgelts, 0, sizeof (pgelts)); 8981 8982 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 8983 void *entity; 8984 int isservice; 8985 scf_type_t ty; 8986 8987 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 8988 scfdie(); 8989 8990 if ((ty != SCF_TYPE_ASTRING && 8991 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 8992 prop_get_val(exp_prop, exp_val) != 0) { 8993 export_property(exp_prop, NULL, &pgelts, 0); 8994 continue; 8995 } 8996 8997 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8998 scfdie(); 8999 9000 if (scf_value_get_astring(exp_val, fmri, 9001 max_scf_fmri_len + 2) < 0) 9002 scfdie(); 9003 9004 /* Look for a dependency group in the target fmri. */ 9005 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 9006 switch (serr) { 9007 case SCF_ERROR_NONE: 9008 break; 9009 9010 case SCF_ERROR_NO_MEMORY: 9011 uu_die(gettext("Out of memory.\n")); 9012 /* NOTREACHED */ 9013 9014 case SCF_ERROR_INVALID_ARGUMENT: 9015 if (g_verbose) { 9016 if (scf_property_to_fmri(exp_prop, fmri, 9017 max_scf_fmri_len + 2) < 0) 9018 scfdie(); 9019 9020 warn(gettext("The value of %s is not a valid " 9021 "FMRI.\n"), fmri); 9022 } 9023 9024 export_property(exp_prop, exp_str, &pgelts, 0); 9025 continue; 9026 9027 case SCF_ERROR_CONSTRAINT_VIOLATED: 9028 if (g_verbose) { 9029 if (scf_property_to_fmri(exp_prop, fmri, 9030 max_scf_fmri_len + 2) < 0) 9031 scfdie(); 9032 9033 warn(gettext("The value of %s does not specify " 9034 "a service or an instance.\n"), fmri); 9035 } 9036 9037 export_property(exp_prop, exp_str, &pgelts, 0); 9038 continue; 9039 9040 case SCF_ERROR_NOT_FOUND: 9041 if (g_verbose) { 9042 if (scf_property_to_fmri(exp_prop, fmri, 9043 max_scf_fmri_len + 2) < 0) 9044 scfdie(); 9045 9046 warn(gettext("The entity specified by %s does " 9047 "not exist.\n"), fmri); 9048 } 9049 9050 export_property(exp_prop, exp_str, &pgelts, 0); 9051 continue; 9052 9053 default: 9054 #ifndef NDEBUG 9055 (void) fprintf(stderr, "%s:%d: %s() failed with " 9056 "unexpected error %d.\n", __FILE__, __LINE__, 9057 "fmri_to_entity", serr); 9058 #endif 9059 abort(); 9060 } 9061 9062 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 9063 if (scf_error() != SCF_ERROR_NOT_FOUND) 9064 scfdie(); 9065 9066 warn(gettext("Entity %s is missing dependency property " 9067 "group %s.\n"), fmri, exp_str); 9068 9069 export_property(exp_prop, NULL, &pgelts, 0); 9070 continue; 9071 } 9072 9073 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 9074 scfdie(); 9075 9076 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 9077 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 9078 scfdie(); 9079 9080 warn(gettext("Property group %s is not of " 9081 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 9082 9083 export_property(exp_prop, NULL, &pgelts, 0); 9084 continue; 9085 } 9086 9087 n = export_dependent(opg, exp_str, fmri); 9088 if (n == NULL) 9089 export_property(exp_prop, exp_str, &pgelts, 0); 9090 else { 9091 if (eelts->dependents == NULL) 9092 eelts->dependents = n; 9093 else 9094 (void) xmlAddSibling(eelts->dependents, 9095 n); 9096 } 9097 } 9098 if (ret == -1) 9099 scfdie(); 9100 9101 free(fmri); 9102 free(type); 9103 9104 scf_iter_destroy(iter); 9105 scf_pg_destroy(opg); 9106 9107 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9108 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 9109 eelts); 9110 } 9111 9112 static void 9113 make_node(xmlNodePtr *nodep, const char *name) 9114 { 9115 if (*nodep == NULL) { 9116 *nodep = xmlNewNode(NULL, (xmlChar *)name); 9117 if (*nodep == NULL) 9118 uu_die(emsg_create_xml); 9119 } 9120 } 9121 9122 static xmlNodePtr 9123 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 9124 { 9125 int ret; 9126 xmlNodePtr parent = NULL; 9127 xmlNodePtr loctext = NULL; 9128 9129 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9130 scfdie(); 9131 9132 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9133 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 9134 prop_get_val(exp_prop, exp_val) != 0) 9135 continue; 9136 9137 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 9138 scfdie(); 9139 9140 make_node(&parent, parname); 9141 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 9142 (xmlChar *)exp_str); 9143 if (loctext == NULL) 9144 uu_die(emsg_create_xml); 9145 9146 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9147 scfdie(); 9148 9149 safe_setprop(loctext, "xml:lang", exp_str); 9150 } 9151 9152 if (ret == -1) 9153 scfdie(); 9154 9155 return (parent); 9156 } 9157 9158 static xmlNodePtr 9159 export_tm_manpage(scf_propertygroup_t *pg) 9160 { 9161 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 9162 if (manpage == NULL) 9163 uu_die(emsg_create_xml); 9164 9165 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 9166 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 9167 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 9168 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 9169 xmlFreeNode(manpage); 9170 return (NULL); 9171 } 9172 9173 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 9174 (void) set_attr_from_prop_default(exp_prop, 9175 manpage, "manpath", ":default"); 9176 9177 return (manpage); 9178 } 9179 9180 static xmlNodePtr 9181 export_tm_doc_link(scf_propertygroup_t *pg) 9182 { 9183 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 9184 if (doc_link == NULL) 9185 uu_die(emsg_create_xml); 9186 9187 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 9188 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 9189 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 9190 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 9191 xmlFreeNode(doc_link); 9192 return (NULL); 9193 } 9194 return (doc_link); 9195 } 9196 9197 /* 9198 * Process template information for a service or instances. 9199 */ 9200 static void 9201 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 9202 struct template_elts *telts) 9203 { 9204 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 9205 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 9206 xmlNodePtr child = NULL; 9207 9208 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 9209 scfdie(); 9210 9211 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 9212 telts->common_name = export_tm_loctext(pg, "common_name"); 9213 if (telts->common_name == NULL) 9214 export_pg(pg, elts, 0); 9215 return; 9216 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 9217 telts->description = export_tm_loctext(pg, "description"); 9218 if (telts->description == NULL) 9219 export_pg(pg, elts, 0); 9220 return; 9221 } 9222 9223 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 9224 child = export_tm_manpage(pg); 9225 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 9226 child = export_tm_doc_link(pg); 9227 } 9228 9229 if (child != NULL) { 9230 make_node(&telts->documentation, "documentation"); 9231 (void) xmlAddChild(telts->documentation, child); 9232 } else { 9233 export_pg(pg, elts, 0); 9234 } 9235 } 9236 9237 /* 9238 * Process the general property group for an instance. 9239 */ 9240 static void 9241 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 9242 struct entity_elts *elts) 9243 { 9244 uint8_t enabled; 9245 struct pg_elts pgelts; 9246 int ret; 9247 9248 /* enabled */ 9249 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 9250 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 9251 prop_get_val(exp_prop, exp_val) == 0) { 9252 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 9253 scfdie(); 9254 } else { 9255 enabled = 0; 9256 } 9257 9258 safe_setprop(inode, enabled_attr, enabled ? true : false); 9259 9260 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 9261 scfdie(); 9262 9263 (void) memset(&pgelts, 0, sizeof (pgelts)); 9264 9265 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 9266 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 9267 scfdie(); 9268 9269 if (strcmp(exp_str, scf_property_enabled) == 0) { 9270 continue; 9271 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 9272 xmlNodePtr rnode, sfnode; 9273 9274 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 9275 if (rnode == NULL) 9276 uu_die(emsg_create_xml); 9277 9278 sfnode = xmlNewChild(rnode, NULL, 9279 (xmlChar *)"service_fmri", NULL); 9280 if (sfnode == NULL) 9281 uu_die(emsg_create_xml); 9282 9283 if (set_attr_from_prop(exp_prop, sfnode, 9284 value_attr) == 0) { 9285 elts->restarter = rnode; 9286 continue; 9287 } 9288 9289 xmlFreeNode(rnode); 9290 } 9291 9292 export_property(exp_prop, exp_str, &pgelts, 0); 9293 } 9294 if (ret == -1) 9295 scfdie(); 9296 9297 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9298 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 9299 elts); 9300 } 9301 9302 /* 9303 * Put an instance element for the given instance into selts. 9304 */ 9305 static void 9306 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 9307 { 9308 xmlNodePtr n; 9309 boolean_t isdefault; 9310 struct entity_elts elts; 9311 struct template_elts template_elts; 9312 int ret; 9313 9314 n = xmlNewNode(NULL, (xmlChar *)"instance"); 9315 if (n == NULL) 9316 uu_die(emsg_create_xml); 9317 9318 /* name */ 9319 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 9320 scfdie(); 9321 safe_setprop(n, name_attr, exp_str); 9322 isdefault = strcmp(exp_str, "default") == 0; 9323 9324 /* check existance of general pg (since general/enabled is required) */ 9325 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 9326 if (scf_error() != SCF_ERROR_NOT_FOUND) 9327 scfdie(); 9328 9329 if (g_verbose) { 9330 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 9331 scfdie(); 9332 9333 warn(gettext("Instance %s has no general property " 9334 "group; it will be marked disabled.\n"), exp_str); 9335 } 9336 9337 safe_setprop(n, enabled_attr, false); 9338 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 9339 strcmp(exp_str, scf_group_framework) != 0) { 9340 if (g_verbose) { 9341 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 9342 scfdie(); 9343 9344 warn(gettext("Property group %s is not of type " 9345 "framework; the instance will be marked " 9346 "disabled.\n"), exp_str); 9347 } 9348 9349 safe_setprop(n, enabled_attr, false); 9350 } 9351 9352 /* property groups */ 9353 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 9354 scfdie(); 9355 9356 (void) memset(&elts, 0, sizeof (elts)); 9357 (void) memset(&template_elts, 0, sizeof (template_elts)); 9358 9359 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 9360 uint32_t pgflags; 9361 9362 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 9363 scfdie(); 9364 9365 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 9366 continue; 9367 9368 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 9369 scfdie(); 9370 9371 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 9372 export_dependency(exp_pg, &elts); 9373 continue; 9374 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 9375 export_method(exp_pg, &elts); 9376 continue; 9377 } else if (strcmp(exp_str, scf_group_framework) == 0) { 9378 if (scf_pg_get_name(exp_pg, exp_str, 9379 max_scf_name_len + 1) < 0) 9380 scfdie(); 9381 9382 if (strcmp(exp_str, scf_pg_general) == 0) { 9383 export_inst_general(exp_pg, n, &elts); 9384 continue; 9385 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 9386 0) { 9387 export_method_context(exp_pg, &elts); 9388 continue; 9389 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 9390 export_dependents(exp_pg, &elts); 9391 continue; 9392 } 9393 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 9394 export_template(exp_pg, &elts, &template_elts); 9395 continue; 9396 } 9397 9398 /* Ordinary pg. */ 9399 export_pg(exp_pg, &elts, flags); 9400 } 9401 if (ret == -1) 9402 scfdie(); 9403 9404 if (template_elts.common_name != NULL) { 9405 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9406 (void) xmlAddChild(elts.template, template_elts.common_name); 9407 (void) xmlAddChild(elts.template, template_elts.description); 9408 (void) xmlAddChild(elts.template, template_elts.documentation); 9409 } else { 9410 xmlFreeNode(template_elts.description); 9411 xmlFreeNode(template_elts.documentation); 9412 } 9413 9414 if (isdefault && elts.restarter == NULL && 9415 elts.dependencies == NULL && elts.method_context == NULL && 9416 elts.exec_methods == NULL && elts.property_groups == NULL && 9417 elts.template == NULL) { 9418 xmlChar *eval; 9419 9420 /* This is a default instance */ 9421 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 9422 9423 xmlFreeNode(n); 9424 9425 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 9426 if (n == NULL) 9427 uu_die(emsg_create_xml); 9428 9429 safe_setprop(n, enabled_attr, (char *)eval); 9430 xmlFree(eval); 9431 9432 selts->create_default_instance = n; 9433 } else { 9434 /* Assemble the children in order. */ 9435 (void) xmlAddChild(n, elts.restarter); 9436 (void) xmlAddChildList(n, elts.dependencies); 9437 (void) xmlAddChildList(n, elts.dependents); 9438 (void) xmlAddChild(n, elts.method_context); 9439 (void) xmlAddChildList(n, elts.exec_methods); 9440 (void) xmlAddChildList(n, elts.property_groups); 9441 (void) xmlAddChild(n, elts.template); 9442 9443 if (selts->instances == NULL) 9444 selts->instances = n; 9445 else 9446 (void) xmlAddSibling(selts->instances, n); 9447 } 9448 } 9449 9450 /* 9451 * Return a service element for the given service. 9452 */ 9453 static xmlNodePtr 9454 export_service(scf_service_t *svc, int flags) 9455 { 9456 xmlNodePtr snode; 9457 struct entity_elts elts; 9458 struct template_elts template_elts; 9459 int ret; 9460 9461 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9462 if (snode == NULL) 9463 uu_die(emsg_create_xml); 9464 9465 /* Get & set name attribute */ 9466 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 9467 scfdie(); 9468 safe_setprop(snode, name_attr, exp_str); 9469 9470 safe_setprop(snode, type_attr, "service"); 9471 safe_setprop(snode, "version", "0"); 9472 9473 /* Acquire child elements. */ 9474 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 9475 scfdie(); 9476 9477 (void) memset(&elts, 0, sizeof (elts)); 9478 (void) memset(&template_elts, 0, sizeof (template_elts)); 9479 9480 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 9481 uint32_t pgflags; 9482 9483 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 9484 scfdie(); 9485 9486 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 9487 continue; 9488 9489 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 9490 scfdie(); 9491 9492 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 9493 export_dependency(exp_pg, &elts); 9494 continue; 9495 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 9496 export_method(exp_pg, &elts); 9497 continue; 9498 } else if (strcmp(exp_str, scf_group_framework) == 0) { 9499 if (scf_pg_get_name(exp_pg, exp_str, 9500 max_scf_name_len + 1) < 0) 9501 scfdie(); 9502 9503 if (strcmp(exp_str, scf_pg_general) == 0) { 9504 export_svc_general(exp_pg, &elts); 9505 continue; 9506 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 9507 0) { 9508 export_method_context(exp_pg, &elts); 9509 continue; 9510 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 9511 export_dependents(exp_pg, &elts); 9512 continue; 9513 } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) { 9514 continue; 9515 } 9516 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 9517 export_template(exp_pg, &elts, &template_elts); 9518 continue; 9519 } 9520 9521 export_pg(exp_pg, &elts, flags); 9522 } 9523 if (ret == -1) 9524 scfdie(); 9525 9526 if (template_elts.common_name != NULL) { 9527 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9528 (void) xmlAddChild(elts.template, template_elts.common_name); 9529 (void) xmlAddChild(elts.template, template_elts.description); 9530 (void) xmlAddChild(elts.template, template_elts.documentation); 9531 } else { 9532 xmlFreeNode(template_elts.description); 9533 xmlFreeNode(template_elts.documentation); 9534 } 9535 9536 /* Iterate instances */ 9537 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 9538 scfdie(); 9539 9540 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 9541 export_instance(exp_inst, &elts, flags); 9542 if (ret == -1) 9543 scfdie(); 9544 9545 /* Now add all of the accumulated elements in order. */ 9546 (void) xmlAddChild(snode, elts.create_default_instance); 9547 (void) xmlAddChild(snode, elts.single_instance); 9548 (void) xmlAddChild(snode, elts.restarter); 9549 (void) xmlAddChildList(snode, elts.dependencies); 9550 (void) xmlAddChildList(snode, elts.dependents); 9551 (void) xmlAddChild(snode, elts.method_context); 9552 (void) xmlAddChildList(snode, elts.exec_methods); 9553 (void) xmlAddChildList(snode, elts.property_groups); 9554 (void) xmlAddChildList(snode, elts.instances); 9555 (void) xmlAddChild(snode, elts.stability); 9556 (void) xmlAddChild(snode, elts.template); 9557 9558 return (snode); 9559 } 9560 9561 static int 9562 export_callback(void *data, scf_walkinfo_t *wip) 9563 { 9564 FILE *f; 9565 xmlDocPtr doc; 9566 xmlNodePtr sb; 9567 int result; 9568 struct export_args *argsp = (struct export_args *)data; 9569 9570 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 9571 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9572 (exp_prop = scf_property_create(g_hndl)) == NULL || 9573 (exp_val = scf_value_create(g_hndl)) == NULL || 9574 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9575 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9576 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9577 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9578 scfdie(); 9579 9580 exp_str_sz = max_scf_len + 1; 9581 exp_str = safe_malloc(exp_str_sz); 9582 9583 if (argsp->filename != NULL) { 9584 errno = 0; 9585 f = fopen(argsp->filename, "wb"); 9586 if (f == NULL) { 9587 if (errno == 0) 9588 uu_die(gettext("Could not open \"%s\": no free " 9589 "stdio streams.\n"), argsp->filename); 9590 else 9591 uu_die(gettext("Could not open \"%s\""), 9592 argsp->filename); 9593 } 9594 } else 9595 f = stdout; 9596 9597 doc = xmlNewDoc((xmlChar *)"1.0"); 9598 if (doc == NULL) 9599 uu_die(gettext("Could not create XML document.\n")); 9600 9601 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9602 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9603 uu_die(emsg_create_xml); 9604 9605 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9606 if (sb == NULL) 9607 uu_die(emsg_create_xml); 9608 safe_setprop(sb, type_attr, "manifest"); 9609 safe_setprop(sb, name_attr, "export"); 9610 (void) xmlAddSibling(doc->children, sb); 9611 9612 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 9613 9614 result = write_service_bundle(doc, f); 9615 9616 free(exp_str); 9617 scf_iter_destroy(exp_val_iter); 9618 scf_iter_destroy(exp_prop_iter); 9619 scf_iter_destroy(exp_pg_iter); 9620 scf_iter_destroy(exp_inst_iter); 9621 scf_value_destroy(exp_val); 9622 scf_property_destroy(exp_prop); 9623 scf_pg_destroy(exp_pg); 9624 scf_instance_destroy(exp_inst); 9625 9626 xmlFreeDoc(doc); 9627 9628 if (f != stdout) 9629 (void) fclose(f); 9630 9631 return (result); 9632 } 9633 9634 /* 9635 * Get the service named by fmri, build an XML tree which represents it, and 9636 * dump it into filename (or stdout if filename is NULL). 9637 */ 9638 int 9639 lscf_service_export(char *fmri, const char *filename, int flags) 9640 { 9641 struct export_args args; 9642 int ret, err; 9643 9644 lscf_prep_hndl(); 9645 9646 bzero(&args, sizeof (args)); 9647 args.filename = filename; 9648 args.flags = flags; 9649 9650 err = 0; 9651 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 9652 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 9653 &args, &err, semerr)) != 0) { 9654 if (ret != -1) 9655 semerr(gettext("Failed to walk instances: %s\n"), 9656 scf_strerror(ret)); 9657 return (-1); 9658 } 9659 9660 /* 9661 * Error message has already been printed. 9662 */ 9663 if (err != 0) 9664 return (-1); 9665 9666 return (0); 9667 } 9668 9669 9670 /* 9671 * Archive 9672 */ 9673 9674 static xmlNodePtr 9675 make_archive(int flags) 9676 { 9677 xmlNodePtr sb; 9678 scf_scope_t *scope; 9679 scf_service_t *svc; 9680 scf_iter_t *iter; 9681 int r; 9682 9683 if ((scope = scf_scope_create(g_hndl)) == NULL || 9684 (svc = scf_service_create(g_hndl)) == NULL || 9685 (iter = scf_iter_create(g_hndl)) == NULL || 9686 (exp_inst = scf_instance_create(g_hndl)) == NULL || 9687 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9688 (exp_prop = scf_property_create(g_hndl)) == NULL || 9689 (exp_val = scf_value_create(g_hndl)) == NULL || 9690 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9691 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9692 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9693 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9694 scfdie(); 9695 9696 exp_str_sz = max_scf_len + 1; 9697 exp_str = safe_malloc(exp_str_sz); 9698 9699 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9700 if (sb == NULL) 9701 uu_die(emsg_create_xml); 9702 safe_setprop(sb, type_attr, "archive"); 9703 safe_setprop(sb, name_attr, "none"); 9704 9705 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 9706 scfdie(); 9707 if (scf_iter_scope_services(iter, scope) != 0) 9708 scfdie(); 9709 9710 for (;;) { 9711 r = scf_iter_next_service(iter, svc); 9712 if (r == 0) 9713 break; 9714 if (r != 1) 9715 scfdie(); 9716 9717 if (scf_service_get_name(svc, exp_str, 9718 max_scf_name_len + 1) < 0) 9719 scfdie(); 9720 9721 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 9722 continue; 9723 9724 (void) xmlAddChild(sb, export_service(svc, flags)); 9725 } 9726 9727 free(exp_str); 9728 9729 scf_iter_destroy(exp_val_iter); 9730 scf_iter_destroy(exp_prop_iter); 9731 scf_iter_destroy(exp_pg_iter); 9732 scf_iter_destroy(exp_inst_iter); 9733 scf_value_destroy(exp_val); 9734 scf_property_destroy(exp_prop); 9735 scf_pg_destroy(exp_pg); 9736 scf_instance_destroy(exp_inst); 9737 scf_iter_destroy(iter); 9738 scf_service_destroy(svc); 9739 scf_scope_destroy(scope); 9740 9741 return (sb); 9742 } 9743 9744 int 9745 lscf_archive(const char *filename, int flags) 9746 { 9747 FILE *f; 9748 xmlDocPtr doc; 9749 int result; 9750 9751 lscf_prep_hndl(); 9752 9753 if (filename != NULL) { 9754 errno = 0; 9755 f = fopen(filename, "wb"); 9756 if (f == NULL) { 9757 if (errno == 0) 9758 uu_die(gettext("Could not open \"%s\": no free " 9759 "stdio streams.\n"), filename); 9760 else 9761 uu_die(gettext("Could not open \"%s\""), 9762 filename); 9763 } 9764 } else 9765 f = stdout; 9766 9767 doc = xmlNewDoc((xmlChar *)"1.0"); 9768 if (doc == NULL) 9769 uu_die(gettext("Could not create XML document.\n")); 9770 9771 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9772 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9773 uu_die(emsg_create_xml); 9774 9775 (void) xmlAddSibling(doc->children, make_archive(flags)); 9776 9777 result = write_service_bundle(doc, f); 9778 9779 xmlFreeDoc(doc); 9780 9781 if (f != stdout) 9782 (void) fclose(f); 9783 9784 return (result); 9785 } 9786 9787 9788 /* 9789 * "Extract" a profile. 9790 */ 9791 int 9792 lscf_profile_extract(const char *filename) 9793 { 9794 FILE *f; 9795 xmlDocPtr doc; 9796 xmlNodePtr sb, snode, inode; 9797 scf_scope_t *scope; 9798 scf_service_t *svc; 9799 scf_instance_t *inst; 9800 scf_propertygroup_t *pg; 9801 scf_property_t *prop; 9802 scf_value_t *val; 9803 scf_iter_t *siter, *iiter; 9804 int r, s; 9805 char *namebuf; 9806 uint8_t b; 9807 int result; 9808 9809 lscf_prep_hndl(); 9810 9811 if (filename != NULL) { 9812 errno = 0; 9813 f = fopen(filename, "wb"); 9814 if (f == NULL) { 9815 if (errno == 0) 9816 uu_die(gettext("Could not open \"%s\": no " 9817 "free stdio streams.\n"), filename); 9818 else 9819 uu_die(gettext("Could not open \"%s\""), 9820 filename); 9821 } 9822 } else 9823 f = stdout; 9824 9825 doc = xmlNewDoc((xmlChar *)"1.0"); 9826 if (doc == NULL) 9827 uu_die(gettext("Could not create XML document.\n")); 9828 9829 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9830 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9831 uu_die(emsg_create_xml); 9832 9833 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9834 if (sb == NULL) 9835 uu_die(emsg_create_xml); 9836 safe_setprop(sb, type_attr, "profile"); 9837 safe_setprop(sb, name_attr, "extract"); 9838 (void) xmlAddSibling(doc->children, sb); 9839 9840 if ((scope = scf_scope_create(g_hndl)) == NULL || 9841 (svc = scf_service_create(g_hndl)) == NULL || 9842 (inst = scf_instance_create(g_hndl)) == NULL || 9843 (pg = scf_pg_create(g_hndl)) == NULL || 9844 (prop = scf_property_create(g_hndl)) == NULL || 9845 (val = scf_value_create(g_hndl)) == NULL || 9846 (siter = scf_iter_create(g_hndl)) == NULL || 9847 (iiter = scf_iter_create(g_hndl)) == NULL) 9848 scfdie(); 9849 9850 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 9851 scfdie(); 9852 9853 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 9854 scfdie(); 9855 9856 namebuf = safe_malloc(max_scf_name_len + 1); 9857 9858 while ((r = scf_iter_next_service(siter, svc)) == 1) { 9859 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 9860 scfdie(); 9861 9862 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9863 if (snode == NULL) 9864 uu_die(emsg_create_xml); 9865 9866 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 9867 0) 9868 scfdie(); 9869 9870 safe_setprop(snode, name_attr, namebuf); 9871 9872 safe_setprop(snode, type_attr, "service"); 9873 safe_setprop(snode, "version", "0"); 9874 9875 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 9876 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 9877 SCF_SUCCESS) { 9878 if (scf_error() != SCF_ERROR_NOT_FOUND) 9879 scfdie(); 9880 9881 if (g_verbose) { 9882 ssize_t len; 9883 char *fmri; 9884 9885 len = 9886 scf_instance_to_fmri(inst, NULL, 0); 9887 if (len < 0) 9888 scfdie(); 9889 9890 fmri = safe_malloc(len + 1); 9891 9892 if (scf_instance_to_fmri(inst, fmri, 9893 len + 1) < 0) 9894 scfdie(); 9895 9896 warn("Instance %s has no \"%s\" " 9897 "property group.\n", fmri, 9898 scf_pg_general); 9899 9900 free(fmri); 9901 } 9902 9903 continue; 9904 } 9905 9906 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 9907 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 9908 prop_get_val(prop, val) != 0) 9909 continue; 9910 9911 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 9912 NULL); 9913 if (inode == NULL) 9914 uu_die(emsg_create_xml); 9915 9916 if (scf_instance_get_name(inst, namebuf, 9917 max_scf_name_len + 1) < 0) 9918 scfdie(); 9919 9920 safe_setprop(inode, name_attr, namebuf); 9921 9922 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 9923 scfdie(); 9924 9925 safe_setprop(inode, enabled_attr, b ? true : false); 9926 } 9927 if (s < 0) 9928 scfdie(); 9929 9930 if (snode->children != NULL) 9931 (void) xmlAddChild(sb, snode); 9932 else 9933 xmlFreeNode(snode); 9934 } 9935 if (r < 0) 9936 scfdie(); 9937 9938 free(namebuf); 9939 9940 result = write_service_bundle(doc, f); 9941 9942 xmlFreeDoc(doc); 9943 9944 if (f != stdout) 9945 (void) fclose(f); 9946 9947 return (result); 9948 } 9949 9950 9951 /* 9952 * Entity manipulation commands 9953 */ 9954 9955 /* 9956 * Entity selection. If no entity is selected, then the current scope is in 9957 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 9958 * only cur_inst is NULL, and when an instance is selected, none are NULL. 9959 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 9960 * cur_inst will be non-NULL. 9961 */ 9962 9963 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 9964 static int 9965 select_inst(const char *name) 9966 { 9967 scf_instance_t *inst; 9968 scf_error_t err; 9969 9970 assert(cur_svc != NULL); 9971 9972 inst = scf_instance_create(g_hndl); 9973 if (inst == NULL) 9974 scfdie(); 9975 9976 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 9977 cur_inst = inst; 9978 return (0); 9979 } 9980 9981 err = scf_error(); 9982 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9983 scfdie(); 9984 9985 scf_instance_destroy(inst); 9986 return (1); 9987 } 9988 9989 /* Returns as above. */ 9990 static int 9991 select_svc(const char *name) 9992 { 9993 scf_service_t *svc; 9994 scf_error_t err; 9995 9996 assert(cur_scope != NULL); 9997 9998 svc = scf_service_create(g_hndl); 9999 if (svc == NULL) 10000 scfdie(); 10001 10002 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 10003 cur_svc = svc; 10004 return (0); 10005 } 10006 10007 err = scf_error(); 10008 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 10009 scfdie(); 10010 10011 scf_service_destroy(svc); 10012 return (1); 10013 } 10014 10015 /* ARGSUSED */ 10016 static int 10017 select_callback(void *unused, scf_walkinfo_t *wip) 10018 { 10019 scf_instance_t *inst; 10020 scf_service_t *svc; 10021 scf_scope_t *scope; 10022 10023 if (wip->inst != NULL) { 10024 if ((scope = scf_scope_create(g_hndl)) == NULL || 10025 (svc = scf_service_create(g_hndl)) == NULL || 10026 (inst = scf_instance_create(g_hndl)) == NULL) 10027 scfdie(); 10028 10029 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 10030 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 10031 scfdie(); 10032 } else { 10033 assert(wip->svc != NULL); 10034 10035 if ((scope = scf_scope_create(g_hndl)) == NULL || 10036 (svc = scf_service_create(g_hndl)) == NULL) 10037 scfdie(); 10038 10039 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 10040 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 10041 scfdie(); 10042 10043 inst = NULL; 10044 } 10045 10046 /* Clear out the current selection */ 10047 assert(cur_scope != NULL); 10048 scf_scope_destroy(cur_scope); 10049 scf_service_destroy(cur_svc); 10050 scf_instance_destroy(cur_inst); 10051 10052 cur_scope = scope; 10053 cur_svc = svc; 10054 cur_inst = inst; 10055 10056 return (0); 10057 } 10058 10059 static int 10060 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 10061 { 10062 char **fmri = fmri_p; 10063 10064 *fmri = strdup(wip->fmri); 10065 if (*fmri == NULL) 10066 uu_die(gettext("Out of memory.\n")); 10067 10068 return (0); 10069 } 10070 10071 /* 10072 * validate [fmri] 10073 * Perform the validation of an FMRI instance. 10074 */ 10075 void 10076 lscf_validate_fmri(const char *fmri) 10077 { 10078 int ret = 0; 10079 size_t inst_sz; 10080 char *inst_fmri = NULL; 10081 scf_tmpl_errors_t *errs = NULL; 10082 char *snapbuf = NULL; 10083 10084 lscf_prep_hndl(); 10085 10086 if (fmri == NULL) { 10087 inst_sz = max_scf_fmri_len + 1; 10088 inst_fmri = safe_malloc(inst_sz); 10089 10090 if (cur_snap != NULL) { 10091 snapbuf = safe_malloc(max_scf_name_len + 1); 10092 if (scf_snapshot_get_name(cur_snap, snapbuf, 10093 max_scf_name_len + 1) < 0) 10094 scfdie(); 10095 } 10096 if (cur_inst == NULL) { 10097 semerr(gettext("No instance selected\n")); 10098 goto cleanup; 10099 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 10100 inst_sz) >= inst_sz) { 10101 /* sanity check. Should never get here */ 10102 uu_die(gettext("Unexpected error! file %s, line %d\n"), 10103 __FILE__, __LINE__); 10104 } 10105 } else { 10106 scf_error_t scf_err; 10107 int err = 0; 10108 10109 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 10110 validate_callback, &inst_fmri, &err, semerr)) != 0) { 10111 uu_warn("Failed to walk instances: %s\n", 10112 scf_strerror(scf_err)); 10113 goto cleanup; 10114 } 10115 if (err != 0) { 10116 /* error message displayed by scf_walk_fmri */ 10117 goto cleanup; 10118 } 10119 } 10120 10121 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 10122 SCF_TMPL_VALIDATE_FLAG_CURRENT); 10123 if (ret == -1) { 10124 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 10125 warn(gettext("Template data for %s is invalid. " 10126 "Consider reverting to a previous snapshot or " 10127 "restoring original configuration.\n"), inst_fmri); 10128 } else { 10129 uu_warn("%s: %s\n", 10130 gettext("Error validating the instance"), 10131 scf_strerror(scf_error())); 10132 } 10133 } else if (ret == 1 && errs != NULL) { 10134 scf_tmpl_error_t *err = NULL; 10135 char *msg; 10136 size_t len = 256; /* initial error buffer size */ 10137 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 10138 SCF_TMPL_STRERROR_HUMAN : 0; 10139 10140 msg = safe_malloc(len); 10141 10142 while ((err = scf_tmpl_next_error(errs)) != NULL) { 10143 int ret; 10144 10145 if ((ret = scf_tmpl_strerror(err, msg, len, 10146 flag)) >= len) { 10147 len = ret + 1; 10148 msg = realloc(msg, len); 10149 if (msg == NULL) 10150 uu_die(gettext( 10151 "Out of memory.\n")); 10152 (void) scf_tmpl_strerror(err, msg, len, 10153 flag); 10154 } 10155 (void) fprintf(stderr, "%s\n", msg); 10156 } 10157 if (msg != NULL) 10158 free(msg); 10159 } 10160 if (errs != NULL) 10161 scf_tmpl_errors_destroy(errs); 10162 10163 cleanup: 10164 free(inst_fmri); 10165 free(snapbuf); 10166 } 10167 10168 static void 10169 lscf_validate_file(const char *filename) 10170 { 10171 tmpl_errors_t *errs; 10172 10173 bundle_t *b = internal_bundle_new(); 10174 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 10175 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 10176 tmpl_errors_print(stderr, errs, ""); 10177 semerr(gettext("Validation failed.\n")); 10178 } 10179 tmpl_errors_destroy(errs); 10180 } 10181 (void) internal_bundle_free(b); 10182 } 10183 10184 /* 10185 * validate [fmri|file] 10186 */ 10187 void 10188 lscf_validate(const char *arg) 10189 { 10190 const char *str; 10191 10192 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 10193 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 10194 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 10195 lscf_validate_file(str); 10196 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 10197 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 10198 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 10199 lscf_validate_fmri(str); 10200 } else if (access(arg, R_OK | F_OK) == 0) { 10201 lscf_validate_file(arg); 10202 } else { 10203 lscf_validate_fmri(arg); 10204 } 10205 } 10206 10207 void 10208 lscf_select(const char *fmri) 10209 { 10210 int ret, err; 10211 10212 lscf_prep_hndl(); 10213 10214 if (cur_snap != NULL) { 10215 struct snaplevel *elt; 10216 char *buf; 10217 10218 /* Error unless name is that of the next level. */ 10219 elt = uu_list_next(cur_levels, cur_elt); 10220 if (elt == NULL) { 10221 semerr(gettext("No children.\n")); 10222 return; 10223 } 10224 10225 buf = safe_malloc(max_scf_name_len + 1); 10226 10227 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10228 max_scf_name_len + 1) < 0) 10229 scfdie(); 10230 10231 if (strcmp(buf, fmri) != 0) { 10232 semerr(gettext("No such child.\n")); 10233 free(buf); 10234 return; 10235 } 10236 10237 free(buf); 10238 10239 cur_elt = elt; 10240 cur_level = elt->sl; 10241 return; 10242 } 10243 10244 /* 10245 * Special case for 'svc:', which takes the user to the scope level. 10246 */ 10247 if (strcmp(fmri, "svc:") == 0) { 10248 scf_instance_destroy(cur_inst); 10249 scf_service_destroy(cur_svc); 10250 cur_inst = NULL; 10251 cur_svc = NULL; 10252 return; 10253 } 10254 10255 /* 10256 * Special case for ':properties'. This appears as part of 'list' but 10257 * can't be selected. Give a more helpful error message in this case. 10258 */ 10259 if (strcmp(fmri, ":properties") == 0) { 10260 semerr(gettext(":properties is not an entity. Try 'listprop' " 10261 "to list properties.\n")); 10262 return; 10263 } 10264 10265 /* 10266 * First try the argument as relative to the current selection. 10267 */ 10268 if (cur_inst != NULL) { 10269 /* EMPTY */; 10270 } else if (cur_svc != NULL) { 10271 if (select_inst(fmri) != 1) 10272 return; 10273 } else { 10274 if (select_svc(fmri) != 1) 10275 return; 10276 } 10277 10278 err = 0; 10279 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 10280 select_callback, NULL, &err, semerr)) != 0) { 10281 semerr(gettext("Failed to walk instances: %s\n"), 10282 scf_strerror(ret)); 10283 } 10284 } 10285 10286 void 10287 lscf_unselect(void) 10288 { 10289 lscf_prep_hndl(); 10290 10291 if (cur_snap != NULL) { 10292 struct snaplevel *elt; 10293 10294 elt = uu_list_prev(cur_levels, cur_elt); 10295 if (elt == NULL) { 10296 semerr(gettext("No parent levels.\n")); 10297 } else { 10298 cur_elt = elt; 10299 cur_level = elt->sl; 10300 } 10301 } else if (cur_inst != NULL) { 10302 scf_instance_destroy(cur_inst); 10303 cur_inst = NULL; 10304 } else if (cur_svc != NULL) { 10305 scf_service_destroy(cur_svc); 10306 cur_svc = NULL; 10307 } else { 10308 semerr(gettext("Cannot unselect at scope level.\n")); 10309 } 10310 } 10311 10312 /* 10313 * Return the FMRI of the current selection, for the prompt. 10314 */ 10315 void 10316 lscf_get_selection_str(char *buf, size_t bufsz) 10317 { 10318 char *cp; 10319 ssize_t fmrilen, szret; 10320 boolean_t deleted = B_FALSE; 10321 10322 if (g_hndl == NULL) { 10323 (void) strlcpy(buf, "svc:", bufsz); 10324 return; 10325 } 10326 10327 if (cur_level != NULL) { 10328 assert(cur_snap != NULL); 10329 10330 /* [ snapshot ] FMRI [: instance ] */ 10331 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 10332 + 2 + max_scf_name_len + 1 + 1); 10333 10334 buf[0] = '['; 10335 10336 szret = scf_snapshot_get_name(cur_snap, buf + 1, 10337 max_scf_name_len + 1); 10338 if (szret < 0) { 10339 if (scf_error() != SCF_ERROR_DELETED) 10340 scfdie(); 10341 10342 goto snap_deleted; 10343 } 10344 10345 (void) strcat(buf, "]svc:/"); 10346 10347 cp = strchr(buf, '\0'); 10348 10349 szret = scf_snaplevel_get_service_name(cur_level, cp, 10350 max_scf_name_len + 1); 10351 if (szret < 0) { 10352 if (scf_error() != SCF_ERROR_DELETED) 10353 scfdie(); 10354 10355 goto snap_deleted; 10356 } 10357 10358 cp = strchr(cp, '\0'); 10359 10360 if (snaplevel_is_instance(cur_level)) { 10361 *cp++ = ':'; 10362 10363 if (scf_snaplevel_get_instance_name(cur_level, cp, 10364 max_scf_name_len + 1) < 0) { 10365 if (scf_error() != SCF_ERROR_DELETED) 10366 scfdie(); 10367 10368 goto snap_deleted; 10369 } 10370 } else { 10371 *cp++ = '['; 10372 *cp++ = ':'; 10373 10374 if (scf_instance_get_name(cur_inst, cp, 10375 max_scf_name_len + 1) < 0) { 10376 if (scf_error() != SCF_ERROR_DELETED) 10377 scfdie(); 10378 10379 goto snap_deleted; 10380 } 10381 10382 (void) strcat(buf, "]"); 10383 } 10384 10385 return; 10386 10387 snap_deleted: 10388 deleted = B_TRUE; 10389 free(buf); 10390 unselect_cursnap(); 10391 } 10392 10393 assert(cur_snap == NULL); 10394 10395 if (cur_inst != NULL) { 10396 assert(cur_svc != NULL); 10397 assert(cur_scope != NULL); 10398 10399 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 10400 if (fmrilen >= 0) { 10401 assert(fmrilen < bufsz); 10402 if (deleted) 10403 warn(emsg_deleted); 10404 return; 10405 } 10406 10407 if (scf_error() != SCF_ERROR_DELETED) 10408 scfdie(); 10409 10410 deleted = B_TRUE; 10411 10412 scf_instance_destroy(cur_inst); 10413 cur_inst = NULL; 10414 } 10415 10416 if (cur_svc != NULL) { 10417 assert(cur_scope != NULL); 10418 10419 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 10420 if (szret >= 0) { 10421 assert(szret < bufsz); 10422 if (deleted) 10423 warn(emsg_deleted); 10424 return; 10425 } 10426 10427 if (scf_error() != SCF_ERROR_DELETED) 10428 scfdie(); 10429 10430 deleted = B_TRUE; 10431 scf_service_destroy(cur_svc); 10432 cur_svc = NULL; 10433 } 10434 10435 assert(cur_scope != NULL); 10436 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 10437 10438 if (fmrilen < 0) 10439 scfdie(); 10440 10441 assert(fmrilen < bufsz); 10442 if (deleted) 10443 warn(emsg_deleted); 10444 } 10445 10446 /* 10447 * Entity listing. Entities and colon namespaces (e.g., :properties and 10448 * :statistics) are listed for the current selection. 10449 */ 10450 void 10451 lscf_list(const char *pattern) 10452 { 10453 scf_iter_t *iter; 10454 char *buf; 10455 int ret; 10456 10457 lscf_prep_hndl(); 10458 10459 if (cur_level != NULL) { 10460 struct snaplevel *elt; 10461 10462 (void) fputs(COLON_NAMESPACES, stdout); 10463 10464 elt = uu_list_next(cur_levels, cur_elt); 10465 if (elt == NULL) 10466 return; 10467 10468 /* 10469 * For now, we know that the next level is an instance. But 10470 * if we ever have multiple scopes, this could be complicated. 10471 */ 10472 buf = safe_malloc(max_scf_name_len + 1); 10473 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10474 max_scf_name_len + 1) >= 0) { 10475 (void) puts(buf); 10476 } else { 10477 if (scf_error() != SCF_ERROR_DELETED) 10478 scfdie(); 10479 } 10480 10481 free(buf); 10482 10483 return; 10484 } 10485 10486 if (cur_inst != NULL) { 10487 (void) fputs(COLON_NAMESPACES, stdout); 10488 return; 10489 } 10490 10491 iter = scf_iter_create(g_hndl); 10492 if (iter == NULL) 10493 scfdie(); 10494 10495 buf = safe_malloc(max_scf_name_len + 1); 10496 10497 if (cur_svc != NULL) { 10498 /* List the instances in this service. */ 10499 scf_instance_t *inst; 10500 10501 inst = scf_instance_create(g_hndl); 10502 if (inst == NULL) 10503 scfdie(); 10504 10505 if (scf_iter_service_instances(iter, cur_svc) == 0) { 10506 safe_printf(COLON_NAMESPACES); 10507 10508 for (;;) { 10509 ret = scf_iter_next_instance(iter, inst); 10510 if (ret == 0) 10511 break; 10512 if (ret != 1) { 10513 if (scf_error() != SCF_ERROR_DELETED) 10514 scfdie(); 10515 10516 break; 10517 } 10518 10519 if (scf_instance_get_name(inst, buf, 10520 max_scf_name_len + 1) >= 0) { 10521 if (pattern == NULL || 10522 fnmatch(pattern, buf, 0) == 0) 10523 (void) puts(buf); 10524 } else { 10525 if (scf_error() != SCF_ERROR_DELETED) 10526 scfdie(); 10527 } 10528 } 10529 } else { 10530 if (scf_error() != SCF_ERROR_DELETED) 10531 scfdie(); 10532 } 10533 10534 scf_instance_destroy(inst); 10535 } else { 10536 /* List the services in this scope. */ 10537 scf_service_t *svc; 10538 10539 assert(cur_scope != NULL); 10540 10541 svc = scf_service_create(g_hndl); 10542 if (svc == NULL) 10543 scfdie(); 10544 10545 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 10546 scfdie(); 10547 10548 for (;;) { 10549 ret = scf_iter_next_service(iter, svc); 10550 if (ret == 0) 10551 break; 10552 if (ret != 1) 10553 scfdie(); 10554 10555 if (scf_service_get_name(svc, buf, 10556 max_scf_name_len + 1) >= 0) { 10557 if (pattern == NULL || 10558 fnmatch(pattern, buf, 0) == 0) 10559 safe_printf("%s\n", buf); 10560 } else { 10561 if (scf_error() != SCF_ERROR_DELETED) 10562 scfdie(); 10563 } 10564 } 10565 10566 scf_service_destroy(svc); 10567 } 10568 10569 free(buf); 10570 scf_iter_destroy(iter); 10571 } 10572 10573 /* 10574 * Entity addition. Creates an empty entity in the current selection. 10575 */ 10576 void 10577 lscf_add(const char *name) 10578 { 10579 lscf_prep_hndl(); 10580 10581 if (cur_snap != NULL) { 10582 semerr(emsg_cant_modify_snapshots); 10583 } else if (cur_inst != NULL) { 10584 semerr(gettext("Cannot add entities to an instance.\n")); 10585 } else if (cur_svc != NULL) { 10586 10587 if (scf_service_add_instance(cur_svc, name, NULL) != 10588 SCF_SUCCESS) { 10589 switch (scf_error()) { 10590 case SCF_ERROR_INVALID_ARGUMENT: 10591 semerr(gettext("Invalid name.\n")); 10592 break; 10593 10594 case SCF_ERROR_EXISTS: 10595 semerr(gettext("Instance already exists.\n")); 10596 break; 10597 10598 case SCF_ERROR_PERMISSION_DENIED: 10599 semerr(emsg_permission_denied); 10600 break; 10601 10602 default: 10603 scfdie(); 10604 } 10605 } 10606 } else { 10607 assert(cur_scope != NULL); 10608 10609 if (scf_scope_add_service(cur_scope, name, NULL) != 10610 SCF_SUCCESS) { 10611 switch (scf_error()) { 10612 case SCF_ERROR_INVALID_ARGUMENT: 10613 semerr(gettext("Invalid name.\n")); 10614 break; 10615 10616 case SCF_ERROR_EXISTS: 10617 semerr(gettext("Service already exists.\n")); 10618 break; 10619 10620 case SCF_ERROR_PERMISSION_DENIED: 10621 semerr(emsg_permission_denied); 10622 break; 10623 10624 case SCF_ERROR_BACKEND_READONLY: 10625 semerr(emsg_read_only); 10626 break; 10627 10628 default: 10629 scfdie(); 10630 } 10631 } 10632 } 10633 } 10634 10635 /* return 1 if the entity has no persistent pgs, else return 0 */ 10636 static int 10637 entity_has_no_pgs(void *ent, int isservice) 10638 { 10639 scf_iter_t *iter = NULL; 10640 scf_propertygroup_t *pg = NULL; 10641 uint32_t flags; 10642 int err; 10643 int ret = 1; 10644 10645 if ((iter = scf_iter_create(g_hndl)) == NULL || 10646 (pg = scf_pg_create(g_hndl)) == NULL) 10647 scfdie(); 10648 10649 if (isservice) { 10650 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 10651 scfdie(); 10652 } else { 10653 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 10654 scfdie(); 10655 } 10656 10657 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 10658 if (scf_pg_get_flags(pg, &flags) != 0) 10659 scfdie(); 10660 10661 /* skip nonpersistent pgs */ 10662 if (flags & SCF_PG_FLAG_NONPERSISTENT) 10663 continue; 10664 10665 ret = 0; 10666 break; 10667 } 10668 10669 if (err == -1) 10670 scfdie(); 10671 10672 scf_pg_destroy(pg); 10673 scf_iter_destroy(iter); 10674 10675 return (ret); 10676 } 10677 10678 /* return 1 if the service has no instances, else return 0 */ 10679 static int 10680 svc_has_no_insts(scf_service_t *svc) 10681 { 10682 scf_instance_t *inst; 10683 scf_iter_t *iter; 10684 int r; 10685 int ret = 1; 10686 10687 if ((inst = scf_instance_create(g_hndl)) == NULL || 10688 (iter = scf_iter_create(g_hndl)) == NULL) 10689 scfdie(); 10690 10691 if (scf_iter_service_instances(iter, svc) != 0) 10692 scfdie(); 10693 10694 r = scf_iter_next_instance(iter, inst); 10695 if (r == 1) { 10696 ret = 0; 10697 } else if (r == 0) { 10698 ret = 1; 10699 } else if (r == -1) { 10700 scfdie(); 10701 } else { 10702 bad_error("scf_iter_next_instance", r); 10703 } 10704 10705 scf_iter_destroy(iter); 10706 scf_instance_destroy(inst); 10707 10708 return (ret); 10709 } 10710 10711 /* 10712 * Entity deletion. 10713 */ 10714 10715 /* 10716 * Delete the property group <fmri>/:properties/<name>. Returns 10717 * SCF_ERROR_NONE on success (or if the entity is not found), 10718 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 10719 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 10720 * denied. 10721 */ 10722 static scf_error_t 10723 delete_dependency_pg(const char *fmri, const char *name) 10724 { 10725 void *entity = NULL; 10726 int isservice; 10727 scf_propertygroup_t *pg = NULL; 10728 scf_error_t result; 10729 char *pgty; 10730 scf_service_t *svc = NULL; 10731 scf_instance_t *inst = NULL; 10732 scf_iter_t *iter = NULL; 10733 char *name_buf = NULL; 10734 10735 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10736 switch (result) { 10737 case SCF_ERROR_NONE: 10738 break; 10739 10740 case SCF_ERROR_NO_MEMORY: 10741 uu_die(gettext("Out of memory.\n")); 10742 /* NOTREACHED */ 10743 10744 case SCF_ERROR_INVALID_ARGUMENT: 10745 case SCF_ERROR_CONSTRAINT_VIOLATED: 10746 return (SCF_ERROR_INVALID_ARGUMENT); 10747 10748 case SCF_ERROR_NOT_FOUND: 10749 result = SCF_ERROR_NONE; 10750 goto out; 10751 10752 default: 10753 bad_error("fmri_to_entity", result); 10754 } 10755 10756 pg = scf_pg_create(g_hndl); 10757 if (pg == NULL) 10758 scfdie(); 10759 10760 if (entity_get_pg(entity, isservice, name, pg) != 0) { 10761 if (scf_error() != SCF_ERROR_NOT_FOUND) 10762 scfdie(); 10763 10764 result = SCF_ERROR_NONE; 10765 goto out; 10766 } 10767 10768 pgty = safe_malloc(max_scf_pg_type_len + 1); 10769 10770 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10771 scfdie(); 10772 10773 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 10774 result = SCF_ERROR_TYPE_MISMATCH; 10775 free(pgty); 10776 goto out; 10777 } 10778 10779 free(pgty); 10780 10781 if (scf_pg_delete(pg) != 0) { 10782 result = scf_error(); 10783 if (result != SCF_ERROR_PERMISSION_DENIED) 10784 scfdie(); 10785 goto out; 10786 } 10787 10788 /* 10789 * We have to handle the case where we've just deleted the last 10790 * property group of a "dummy" entity (instance or service). 10791 * A "dummy" entity is an entity only present to hold an 10792 * external dependency. 10793 * So, in the case we deleted the last property group then we 10794 * can also delete the entity. If the entity is an instance then 10795 * we must verify if this was the last instance for the service 10796 * and if it is, we can also delete the service if it doesn't 10797 * have any property group either. 10798 */ 10799 10800 result = SCF_ERROR_NONE; 10801 10802 if (isservice) { 10803 svc = (scf_service_t *)entity; 10804 10805 if ((inst = scf_instance_create(g_hndl)) == NULL || 10806 (iter = scf_iter_create(g_hndl)) == NULL) 10807 scfdie(); 10808 10809 name_buf = safe_malloc(max_scf_name_len + 1); 10810 } else { 10811 inst = (scf_instance_t *)entity; 10812 } 10813 10814 /* 10815 * If the entity is an instance and we've just deleted its last 10816 * property group then we should delete it. 10817 */ 10818 if (!isservice && entity_has_no_pgs(entity, isservice)) { 10819 /* find the service before deleting the inst. - needed later */ 10820 if ((svc = scf_service_create(g_hndl)) == NULL) 10821 scfdie(); 10822 10823 if (scf_instance_get_parent(inst, svc) != 0) 10824 scfdie(); 10825 10826 /* delete the instance */ 10827 if (scf_instance_delete(inst) != 0) { 10828 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10829 scfdie(); 10830 10831 result = SCF_ERROR_PERMISSION_DENIED; 10832 goto out; 10833 } 10834 /* no need to refresh the instance */ 10835 inst = NULL; 10836 } 10837 10838 /* 10839 * If the service has no more instances and pgs or we just deleted the 10840 * last instance and the service doesn't have anymore propery groups 10841 * then the service should be deleted. 10842 */ 10843 if (svc != NULL && 10844 svc_has_no_insts(svc) && 10845 entity_has_no_pgs((void *)svc, 1)) { 10846 if (scf_service_delete(svc) == 0) { 10847 if (isservice) { 10848 /* no need to refresh the service */ 10849 svc = NULL; 10850 } 10851 10852 goto out; 10853 } 10854 10855 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10856 scfdie(); 10857 10858 result = SCF_ERROR_PERMISSION_DENIED; 10859 } 10860 10861 /* if the entity has not been deleted, refresh it */ 10862 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 10863 (void) refresh_entity(isservice, entity, fmri, inst, iter, 10864 name_buf); 10865 } 10866 10867 out: 10868 if (isservice && (inst != NULL && iter != NULL)) { 10869 free(name_buf); 10870 scf_iter_destroy(iter); 10871 scf_instance_destroy(inst); 10872 } 10873 10874 if (!isservice && svc != NULL) { 10875 scf_service_destroy(svc); 10876 } 10877 10878 scf_pg_destroy(pg); 10879 if (entity != NULL) 10880 entity_destroy(entity, isservice); 10881 10882 return (result); 10883 } 10884 10885 static int 10886 delete_dependents(scf_propertygroup_t *pg) 10887 { 10888 char *pgty, *name, *fmri; 10889 scf_property_t *prop; 10890 scf_value_t *val; 10891 scf_iter_t *iter; 10892 int r; 10893 scf_error_t err; 10894 10895 /* Verify that the pg has the correct type. */ 10896 pgty = safe_malloc(max_scf_pg_type_len + 1); 10897 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10898 scfdie(); 10899 10900 if (strcmp(pgty, scf_group_framework) != 0) { 10901 if (g_verbose) { 10902 fmri = safe_malloc(max_scf_fmri_len + 1); 10903 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 10904 scfdie(); 10905 10906 warn(gettext("Property group %s is not of expected " 10907 "type %s.\n"), fmri, scf_group_framework); 10908 10909 free(fmri); 10910 } 10911 10912 free(pgty); 10913 return (-1); 10914 } 10915 10916 free(pgty); 10917 10918 /* map delete_dependency_pg onto the properties. */ 10919 if ((prop = scf_property_create(g_hndl)) == NULL || 10920 (val = scf_value_create(g_hndl)) == NULL || 10921 (iter = scf_iter_create(g_hndl)) == NULL) 10922 scfdie(); 10923 10924 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10925 scfdie(); 10926 10927 name = safe_malloc(max_scf_name_len + 1); 10928 fmri = safe_malloc(max_scf_fmri_len + 2); 10929 10930 while ((r = scf_iter_next_property(iter, prop)) == 1) { 10931 scf_type_t ty; 10932 10933 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 10934 scfdie(); 10935 10936 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 10937 scfdie(); 10938 10939 if ((ty != SCF_TYPE_ASTRING && 10940 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 10941 prop_get_val(prop, val) != 0) 10942 continue; 10943 10944 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 10945 scfdie(); 10946 10947 err = delete_dependency_pg(fmri, name); 10948 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 10949 if (scf_property_to_fmri(prop, fmri, 10950 max_scf_fmri_len + 2) < 0) 10951 scfdie(); 10952 10953 warn(gettext("Value of %s is not a valid FMRI.\n"), 10954 fmri); 10955 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 10956 warn(gettext("Property group \"%s\" of entity \"%s\" " 10957 "does not have dependency type.\n"), name, fmri); 10958 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 10959 warn(gettext("Could not delete property group \"%s\" " 10960 "of entity \"%s\" (permission denied).\n"), name, 10961 fmri); 10962 } 10963 } 10964 if (r == -1) 10965 scfdie(); 10966 10967 scf_value_destroy(val); 10968 scf_property_destroy(prop); 10969 10970 return (0); 10971 } 10972 10973 /* 10974 * Returns 1 if the instance may be running, and 0 otherwise. 10975 */ 10976 static int 10977 inst_is_running(scf_instance_t *inst) 10978 { 10979 scf_propertygroup_t *pg; 10980 scf_property_t *prop; 10981 scf_value_t *val; 10982 char buf[MAX_SCF_STATE_STRING_SZ]; 10983 int ret = 0; 10984 ssize_t szret; 10985 10986 if ((pg = scf_pg_create(g_hndl)) == NULL || 10987 (prop = scf_property_create(g_hndl)) == NULL || 10988 (val = scf_value_create(g_hndl)) == NULL) 10989 scfdie(); 10990 10991 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 10992 if (scf_error() != SCF_ERROR_NOT_FOUND) 10993 scfdie(); 10994 goto out; 10995 } 10996 10997 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 10998 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 10999 prop_get_val(prop, val) != 0) 11000 goto out; 11001 11002 szret = scf_value_get_astring(val, buf, sizeof (buf)); 11003 assert(szret >= 0); 11004 11005 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 11006 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 11007 11008 out: 11009 scf_value_destroy(val); 11010 scf_property_destroy(prop); 11011 scf_pg_destroy(pg); 11012 return (ret); 11013 } 11014 11015 static uint8_t 11016 pg_is_external_dependency(scf_propertygroup_t *pg) 11017 { 11018 char *type; 11019 scf_value_t *val; 11020 scf_property_t *prop; 11021 uint8_t b = B_FALSE; 11022 11023 type = safe_malloc(max_scf_pg_type_len + 1); 11024 11025 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 11026 scfdie(); 11027 11028 if ((prop = scf_property_create(g_hndl)) == NULL || 11029 (val = scf_value_create(g_hndl)) == NULL) 11030 scfdie(); 11031 11032 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 11033 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 11034 if (scf_property_get_value(prop, val) != 0) 11035 scfdie(); 11036 if (scf_value_get_boolean(val, &b) != 0) 11037 scfdie(); 11038 } 11039 } 11040 11041 free(type); 11042 (void) scf_value_destroy(val); 11043 (void) scf_property_destroy(prop); 11044 11045 return (b); 11046 } 11047 11048 #define DELETE_FAILURE -1 11049 #define DELETE_SUCCESS_NOEXTDEPS 0 11050 #define DELETE_SUCCESS_EXTDEPS 1 11051 11052 /* 11053 * lscf_instance_delete() deletes an instance. Before calling 11054 * scf_instance_delete(), though, we make sure the instance isn't 11055 * running and delete dependencies in other entities which the instance 11056 * declared as "dependents". If there are dependencies which were 11057 * created for other entities, then instead of deleting the instance we 11058 * make it "empty" by deleting all other property groups and all 11059 * snapshots. 11060 * 11061 * lscf_instance_delete() verifies that there is no external dependency pgs 11062 * before suppressing the instance. If there is, then we must not remove them 11063 * now in case the instance is re-created otherwise the dependencies would be 11064 * lost. The external dependency pgs will be removed if the dependencies are 11065 * removed. 11066 * 11067 * Returns: 11068 * DELETE_FAILURE on failure 11069 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 11070 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 11071 */ 11072 static int 11073 lscf_instance_delete(scf_instance_t *inst, int force) 11074 { 11075 scf_propertygroup_t *pg; 11076 scf_snapshot_t *snap; 11077 scf_iter_t *iter; 11078 int err; 11079 int external = 0; 11080 11081 /* If we're not forcing and the instance is running, refuse. */ 11082 if (!force && inst_is_running(inst)) { 11083 char *fmri; 11084 11085 fmri = safe_malloc(max_scf_fmri_len + 1); 11086 11087 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 11088 scfdie(); 11089 11090 semerr(gettext("Instance %s may be running. " 11091 "Use delete -f if it is not.\n"), fmri); 11092 11093 free(fmri); 11094 return (DELETE_FAILURE); 11095 } 11096 11097 pg = scf_pg_create(g_hndl); 11098 if (pg == NULL) 11099 scfdie(); 11100 11101 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 11102 (void) delete_dependents(pg); 11103 else if (scf_error() != SCF_ERROR_NOT_FOUND) 11104 scfdie(); 11105 11106 scf_pg_destroy(pg); 11107 11108 /* 11109 * If the instance has some external dependencies then we must 11110 * keep them in case the instance is reimported otherwise the 11111 * dependencies would be lost on reimport. 11112 */ 11113 if ((iter = scf_iter_create(g_hndl)) == NULL || 11114 (pg = scf_pg_create(g_hndl)) == NULL) 11115 scfdie(); 11116 11117 if (scf_iter_instance_pgs(iter, inst) < 0) 11118 scfdie(); 11119 11120 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 11121 if (pg_is_external_dependency(pg)) { 11122 external = 1; 11123 continue; 11124 } 11125 11126 if (scf_pg_delete(pg) != 0) { 11127 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11128 scfdie(); 11129 else { 11130 semerr(emsg_permission_denied); 11131 11132 (void) scf_iter_destroy(iter); 11133 (void) scf_pg_destroy(pg); 11134 return (DELETE_FAILURE); 11135 } 11136 } 11137 } 11138 11139 if (err == -1) 11140 scfdie(); 11141 11142 (void) scf_iter_destroy(iter); 11143 (void) scf_pg_destroy(pg); 11144 11145 if (external) { 11146 /* 11147 * All the pgs have been deleted for the instance except 11148 * the ones holding the external dependencies. 11149 * For the job to be complete, we must also delete the 11150 * snapshots associated with the instance. 11151 */ 11152 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 11153 NULL) 11154 scfdie(); 11155 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 11156 scfdie(); 11157 11158 if (scf_iter_instance_snapshots(iter, inst) == -1) 11159 scfdie(); 11160 11161 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 11162 if (_scf_snapshot_delete(snap) != 0) { 11163 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11164 scfdie(); 11165 11166 semerr(emsg_permission_denied); 11167 11168 (void) scf_iter_destroy(iter); 11169 (void) scf_snapshot_destroy(snap); 11170 return (DELETE_FAILURE); 11171 } 11172 } 11173 11174 if (err == -1) 11175 scfdie(); 11176 11177 (void) scf_iter_destroy(iter); 11178 (void) scf_snapshot_destroy(snap); 11179 return (DELETE_SUCCESS_EXTDEPS); 11180 } 11181 11182 if (scf_instance_delete(inst) != 0) { 11183 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11184 scfdie(); 11185 11186 semerr(emsg_permission_denied); 11187 11188 return (DELETE_FAILURE); 11189 } 11190 11191 return (DELETE_SUCCESS_NOEXTDEPS); 11192 } 11193 11194 /* 11195 * lscf_service_delete() deletes a service. Before calling 11196 * scf_service_delete(), though, we call lscf_instance_delete() for 11197 * each of the instances and delete dependencies in other entities 11198 * which were created as "dependents" of this service. If there are 11199 * dependencies which were created for other entities, then we delete 11200 * all other property groups in the service and leave it as "empty". 11201 * 11202 * lscf_service_delete() verifies that there is no external dependency 11203 * pgs at the instance & service level before suppressing the service. 11204 * If there is, then we must not remove them now in case the service 11205 * is re-imported otherwise the dependencies would be lost. The external 11206 * dependency pgs will be removed if the dependencies are removed. 11207 * 11208 * Returns: 11209 * DELETE_FAILURE on failure 11210 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 11211 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 11212 */ 11213 static int 11214 lscf_service_delete(scf_service_t *svc, int force) 11215 { 11216 int r; 11217 scf_instance_t *inst; 11218 scf_propertygroup_t *pg; 11219 scf_iter_t *iter; 11220 int ret; 11221 int external = 0; 11222 11223 if ((inst = scf_instance_create(g_hndl)) == NULL || 11224 (pg = scf_pg_create(g_hndl)) == NULL || 11225 (iter = scf_iter_create(g_hndl)) == NULL) 11226 scfdie(); 11227 11228 if (scf_iter_service_instances(iter, svc) != 0) 11229 scfdie(); 11230 11231 for (r = scf_iter_next_instance(iter, inst); 11232 r == 1; 11233 r = scf_iter_next_instance(iter, inst)) { 11234 11235 ret = lscf_instance_delete(inst, force); 11236 if (ret == DELETE_FAILURE) { 11237 scf_iter_destroy(iter); 11238 scf_pg_destroy(pg); 11239 scf_instance_destroy(inst); 11240 return (DELETE_FAILURE); 11241 } 11242 11243 /* 11244 * Record the fact that there is some external dependencies 11245 * at the instance level. 11246 */ 11247 if (ret == DELETE_SUCCESS_EXTDEPS) 11248 external |= 1; 11249 } 11250 11251 if (r != 0) 11252 scfdie(); 11253 11254 /* Delete dependency property groups in dependent services. */ 11255 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 11256 (void) delete_dependents(pg); 11257 else if (scf_error() != SCF_ERROR_NOT_FOUND) 11258 scfdie(); 11259 11260 scf_iter_destroy(iter); 11261 scf_pg_destroy(pg); 11262 scf_instance_destroy(inst); 11263 11264 /* 11265 * If the service has some external dependencies then we don't 11266 * want to remove them in case the service is re-imported. 11267 */ 11268 if ((pg = scf_pg_create(g_hndl)) == NULL || 11269 (iter = scf_iter_create(g_hndl)) == NULL) 11270 scfdie(); 11271 11272 if (scf_iter_service_pgs(iter, svc) < 0) 11273 scfdie(); 11274 11275 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 11276 if (pg_is_external_dependency(pg)) { 11277 external |= 2; 11278 continue; 11279 } 11280 11281 if (scf_pg_delete(pg) != 0) { 11282 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11283 scfdie(); 11284 else { 11285 semerr(emsg_permission_denied); 11286 11287 (void) scf_iter_destroy(iter); 11288 (void) scf_pg_destroy(pg); 11289 return (DELETE_FAILURE); 11290 } 11291 } 11292 } 11293 11294 if (r == -1) 11295 scfdie(); 11296 11297 (void) scf_iter_destroy(iter); 11298 (void) scf_pg_destroy(pg); 11299 11300 if (external != 0) 11301 return (DELETE_SUCCESS_EXTDEPS); 11302 11303 if (scf_service_delete(svc) == 0) 11304 return (DELETE_SUCCESS_NOEXTDEPS); 11305 11306 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11307 scfdie(); 11308 11309 semerr(emsg_permission_denied); 11310 return (DELETE_FAILURE); 11311 } 11312 11313 static int 11314 delete_callback(void *data, scf_walkinfo_t *wip) 11315 { 11316 int force = (int)data; 11317 11318 if (wip->inst != NULL) 11319 (void) lscf_instance_delete(wip->inst, force); 11320 else 11321 (void) lscf_service_delete(wip->svc, force); 11322 11323 return (0); 11324 } 11325 11326 void 11327 lscf_delete(const char *fmri, int force) 11328 { 11329 scf_service_t *svc; 11330 scf_instance_t *inst; 11331 int ret; 11332 11333 lscf_prep_hndl(); 11334 11335 if (cur_snap != NULL) { 11336 if (!snaplevel_is_instance(cur_level)) { 11337 char *buf; 11338 11339 buf = safe_malloc(max_scf_name_len + 1); 11340 if (scf_instance_get_name(cur_inst, buf, 11341 max_scf_name_len + 1) >= 0) { 11342 if (strcmp(buf, fmri) == 0) { 11343 semerr(emsg_cant_modify_snapshots); 11344 free(buf); 11345 return; 11346 } 11347 } else if (scf_error() != SCF_ERROR_DELETED) { 11348 scfdie(); 11349 } 11350 free(buf); 11351 } 11352 } else if (cur_inst != NULL) { 11353 /* EMPTY */; 11354 } else if (cur_svc != NULL) { 11355 inst = scf_instance_create(g_hndl); 11356 if (inst == NULL) 11357 scfdie(); 11358 11359 if (scf_service_get_instance(cur_svc, fmri, inst) == 11360 SCF_SUCCESS) { 11361 (void) lscf_instance_delete(inst, force); 11362 scf_instance_destroy(inst); 11363 return; 11364 } 11365 11366 if (scf_error() != SCF_ERROR_NOT_FOUND && 11367 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 11368 scfdie(); 11369 11370 scf_instance_destroy(inst); 11371 } else { 11372 assert(cur_scope != NULL); 11373 11374 svc = scf_service_create(g_hndl); 11375 if (svc == NULL) 11376 scfdie(); 11377 11378 if (scf_scope_get_service(cur_scope, fmri, svc) == 11379 SCF_SUCCESS) { 11380 (void) lscf_service_delete(svc, force); 11381 scf_service_destroy(svc); 11382 return; 11383 } 11384 11385 if (scf_error() != SCF_ERROR_NOT_FOUND && 11386 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 11387 scfdie(); 11388 11389 scf_service_destroy(svc); 11390 } 11391 11392 /* 11393 * Match FMRI to entity. 11394 */ 11395 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11396 delete_callback, (void *)force, NULL, semerr)) != 0) { 11397 semerr(gettext("Failed to walk instances: %s\n"), 11398 scf_strerror(ret)); 11399 } 11400 } 11401 11402 11403 11404 /* 11405 * :properties commands. These all end with "pg" or "prop" and generally 11406 * operate on the currently selected entity. 11407 */ 11408 11409 /* 11410 * Property listing. List the property groups, properties, their types and 11411 * their values for the currently selected entity. 11412 */ 11413 static void 11414 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 11415 { 11416 char *buf; 11417 uint32_t flags; 11418 11419 buf = safe_malloc(max_scf_pg_type_len + 1); 11420 11421 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 11422 scfdie(); 11423 11424 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 11425 scfdie(); 11426 11427 safe_printf("%-*s %s", namewidth, name, buf); 11428 11429 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11430 safe_printf("\tNONPERSISTENT"); 11431 11432 safe_printf("\n"); 11433 11434 free(buf); 11435 } 11436 11437 static boolean_t 11438 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 11439 { 11440 if (scf_property_get_value(prop, val) == 0) { 11441 return (B_FALSE); 11442 } else { 11443 switch (scf_error()) { 11444 case SCF_ERROR_NOT_FOUND: 11445 return (B_FALSE); 11446 case SCF_ERROR_PERMISSION_DENIED: 11447 case SCF_ERROR_CONSTRAINT_VIOLATED: 11448 return (B_TRUE); 11449 default: 11450 scfdie(); 11451 /*NOTREACHED*/ 11452 } 11453 } 11454 } 11455 11456 static void 11457 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 11458 { 11459 scf_iter_t *iter; 11460 scf_value_t *val; 11461 const char *type; 11462 int multiple_strings = 0; 11463 int ret; 11464 11465 if ((iter = scf_iter_create(g_hndl)) == NULL || 11466 (val = scf_value_create(g_hndl)) == NULL) 11467 scfdie(); 11468 11469 type = prop_to_typestr(prop); 11470 assert(type != NULL); 11471 11472 safe_printf("%-*s %-7s ", len, name, type); 11473 11474 if (prop_has_multiple_values(prop, val) && 11475 (scf_value_type(val) == SCF_TYPE_ASTRING || 11476 scf_value_type(val) == SCF_TYPE_USTRING)) 11477 multiple_strings = 1; 11478 11479 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11480 scfdie(); 11481 11482 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11483 char *buf; 11484 ssize_t vlen, szret; 11485 11486 vlen = scf_value_get_as_string(val, NULL, 0); 11487 if (vlen < 0) 11488 scfdie(); 11489 11490 buf = safe_malloc(vlen + 1); 11491 11492 szret = scf_value_get_as_string(val, buf, vlen + 1); 11493 if (szret < 0) 11494 scfdie(); 11495 assert(szret <= vlen); 11496 11497 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11498 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 11499 safe_printf(" \""); 11500 (void) quote_and_print(buf, stdout, 0); 11501 (void) putchar('"'); 11502 if (ferror(stdout)) { 11503 (void) putchar('\n'); 11504 uu_die(gettext("Error writing to stdout.\n")); 11505 } 11506 } else { 11507 safe_printf(" %s", buf); 11508 } 11509 11510 free(buf); 11511 } 11512 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11513 scfdie(); 11514 11515 if (putchar('\n') != '\n') 11516 uu_die(gettext("Could not output newline")); 11517 } 11518 11519 /* 11520 * Outputs template property group info for the describe subcommand. 11521 * If 'templates' == 2, verbose output is printed in the format expected 11522 * for describe -v, which includes all templates fields. If pg is 11523 * not NULL, we're describing the template data, not an existing property 11524 * group, and formatting should be appropriate for describe -t. 11525 */ 11526 static void 11527 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 11528 { 11529 char *buf; 11530 uint8_t required; 11531 scf_property_t *stability_prop; 11532 scf_value_t *stability_val; 11533 11534 if (templates == 0) 11535 return; 11536 11537 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 11538 (stability_val = scf_value_create(g_hndl)) == NULL) 11539 scfdie(); 11540 11541 if (templates == 2 && pg != NULL) { 11542 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 11543 stability_prop) == 0) { 11544 if (prop_check_type(stability_prop, 11545 SCF_TYPE_ASTRING) == 0 && 11546 prop_get_val(stability_prop, stability_val) == 0) { 11547 char *stability; 11548 11549 stability = safe_malloc(max_scf_value_len + 1); 11550 11551 if (scf_value_get_astring(stability_val, 11552 stability, max_scf_value_len + 1) == -1 && 11553 scf_error() != SCF_ERROR_NOT_FOUND) 11554 scfdie(); 11555 11556 safe_printf("%s%s: %s\n", TMPL_INDENT, 11557 gettext("stability"), stability); 11558 11559 free(stability); 11560 } 11561 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 11562 scfdie(); 11563 } 11564 11565 scf_property_destroy(stability_prop); 11566 scf_value_destroy(stability_val); 11567 11568 if (pgt == NULL) 11569 return; 11570 11571 if (pg == NULL || templates == 2) { 11572 /* print type info only if scf_tmpl_pg_name succeeds */ 11573 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 11574 if (pg != NULL) 11575 safe_printf("%s", TMPL_INDENT); 11576 safe_printf("%s: ", gettext("name")); 11577 safe_printf("%s\n", buf); 11578 free(buf); 11579 } 11580 11581 /* print type info only if scf_tmpl_pg_type succeeds */ 11582 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 11583 if (pg != NULL) 11584 safe_printf("%s", TMPL_INDENT); 11585 safe_printf("%s: ", gettext("type")); 11586 safe_printf("%s\n", buf); 11587 free(buf); 11588 } 11589 } 11590 11591 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 11592 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11593 required ? "true" : "false"); 11594 11595 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 11596 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 11597 buf); 11598 free(buf); 11599 } 11600 11601 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 11602 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11603 buf); 11604 free(buf); 11605 } 11606 11607 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 11608 if (templates == 2) 11609 safe_printf("%s%s: %s\n", TMPL_INDENT, 11610 gettext("description"), buf); 11611 else 11612 safe_printf("%s%s\n", TMPL_INDENT, buf); 11613 free(buf); 11614 } 11615 11616 } 11617 11618 /* 11619 * With as_value set to true, indent as appropriate for the value level. 11620 * If false, indent to appropriate level for inclusion in constraint 11621 * or choice printout. 11622 */ 11623 static void 11624 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 11625 int as_value) 11626 { 11627 char *buf; 11628 11629 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 11630 if (as_value == 0) 11631 safe_printf("%s", TMPL_CHOICE_INDENT); 11632 else 11633 safe_printf("%s", TMPL_INDENT); 11634 safe_printf("%s: %s\n", gettext("value common name"), buf); 11635 free(buf); 11636 } 11637 11638 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 11639 if (as_value == 0) 11640 safe_printf("%s", TMPL_CHOICE_INDENT); 11641 else 11642 safe_printf("%s", TMPL_INDENT); 11643 safe_printf("%s: %s\n", gettext("value description"), buf); 11644 free(buf); 11645 } 11646 } 11647 11648 static void 11649 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 11650 { 11651 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 11652 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11653 safe_printf("%s\n", val_buf); 11654 11655 print_template_value_details(prt, val_buf, 1); 11656 } 11657 11658 static void 11659 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 11660 { 11661 int i, printed = 0; 11662 scf_values_t values; 11663 scf_count_ranges_t c_ranges; 11664 scf_int_ranges_t i_ranges; 11665 11666 printed = 0; 11667 i = 0; 11668 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 11669 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11670 gettext("value constraints")); 11671 printed++; 11672 for (i = 0; i < values.value_count; ++i) { 11673 safe_printf("%s%s: %s\n", TMPL_INDENT, 11674 gettext("value name"), values.values_as_strings[i]); 11675 if (verbose == 1) 11676 print_template_value_details(prt, 11677 values.values_as_strings[i], 0); 11678 } 11679 11680 scf_values_destroy(&values); 11681 } 11682 11683 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 11684 if (printed++ == 0) 11685 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11686 gettext("value constraints")); 11687 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11688 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11689 gettext("range"), c_ranges.scr_min[i], 11690 c_ranges.scr_max[i]); 11691 } 11692 scf_count_ranges_destroy(&c_ranges); 11693 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11694 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 11695 if (printed++ == 0) 11696 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11697 gettext("value constraints")); 11698 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11699 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11700 gettext("range"), i_ranges.sir_min[i], 11701 i_ranges.sir_max[i]); 11702 } 11703 scf_int_ranges_destroy(&i_ranges); 11704 } 11705 } 11706 11707 static void 11708 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 11709 { 11710 int i = 0, printed = 0; 11711 scf_values_t values; 11712 scf_count_ranges_t c_ranges; 11713 scf_int_ranges_t i_ranges; 11714 11715 printed = 0; 11716 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 11717 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11718 gettext("value constraints")); 11719 printed++; 11720 for (i = 0; i < values.value_count; i++) { 11721 safe_printf("%s%s: %s\n", TMPL_INDENT, 11722 gettext("value name"), values.values_as_strings[i]); 11723 if (verbose == 1) 11724 print_template_value_details(prt, 11725 values.values_as_strings[i], 0); 11726 } 11727 11728 scf_values_destroy(&values); 11729 } 11730 11731 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 11732 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11733 if (printed++ == 0) 11734 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11735 gettext("value choices")); 11736 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11737 gettext("range"), c_ranges.scr_min[i], 11738 c_ranges.scr_max[i]); 11739 } 11740 scf_count_ranges_destroy(&c_ranges); 11741 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11742 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 11743 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11744 if (printed++ == 0) 11745 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11746 gettext("value choices")); 11747 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11748 gettext("range"), i_ranges.sir_min[i], 11749 i_ranges.sir_max[i]); 11750 } 11751 scf_int_ranges_destroy(&i_ranges); 11752 } 11753 } 11754 11755 static void 11756 list_values_by_template(scf_prop_tmpl_t *prt) 11757 { 11758 print_template_constraints(prt, 1); 11759 print_template_choices(prt, 1); 11760 } 11761 11762 static void 11763 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 11764 { 11765 char *val_buf; 11766 scf_iter_t *iter; 11767 scf_value_t *val; 11768 int ret; 11769 11770 if ((iter = scf_iter_create(g_hndl)) == NULL || 11771 (val = scf_value_create(g_hndl)) == NULL) 11772 scfdie(); 11773 11774 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11775 scfdie(); 11776 11777 val_buf = safe_malloc(max_scf_value_len + 1); 11778 11779 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11780 if (scf_value_get_as_string(val, val_buf, 11781 max_scf_value_len + 1) < 0) 11782 scfdie(); 11783 11784 print_template_value(prt, val_buf); 11785 } 11786 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11787 scfdie(); 11788 free(val_buf); 11789 11790 print_template_constraints(prt, 0); 11791 print_template_choices(prt, 0); 11792 11793 } 11794 11795 /* 11796 * Outputs property info for the describe subcommand 11797 * Verbose output if templates == 2, -v option of svccfg describe 11798 * Displays template data if prop is not NULL, -t option of svccfg describe 11799 */ 11800 static void 11801 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 11802 { 11803 char *buf; 11804 uint8_t u_buf; 11805 int i; 11806 uint64_t min, max; 11807 scf_values_t values; 11808 11809 if (prt == NULL || templates == 0) 11810 return; 11811 11812 if (prop == NULL) { 11813 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 11814 if (scf_tmpl_prop_name(prt, &buf) > 0) { 11815 safe_printf("%s\n", buf); 11816 free(buf); 11817 } else 11818 safe_printf("(%s)\n", gettext("any")); 11819 } 11820 11821 if (prop == NULL || templates == 2) { 11822 if (prop != NULL) 11823 safe_printf("%s", TMPL_INDENT); 11824 else 11825 safe_printf("%s", TMPL_VALUE_INDENT); 11826 safe_printf("%s: ", gettext("type")); 11827 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 11828 safe_printf("%s\n", buf); 11829 free(buf); 11830 } else 11831 safe_printf("(%s)\n", gettext("any")); 11832 } 11833 11834 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 11835 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11836 u_buf ? "true" : "false"); 11837 11838 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 11839 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11840 buf); 11841 free(buf); 11842 } 11843 11844 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 11845 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 11846 buf); 11847 free(buf); 11848 } 11849 11850 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 11851 safe_printf("%s%s\n", TMPL_INDENT, buf); 11852 free(buf); 11853 } 11854 11855 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 11856 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 11857 scf_tmpl_visibility_to_string(u_buf)); 11858 11859 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 11860 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11861 gettext("minimum number of values"), min); 11862 if (max == ULLONG_MAX) { 11863 safe_printf("%s%s: %s\n", TMPL_INDENT, 11864 gettext("maximum number of values"), 11865 gettext("unlimited")); 11866 } else { 11867 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11868 gettext("maximum number of values"), max); 11869 } 11870 } 11871 11872 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 11873 for (i = 0; i < values.value_count; i++) { 11874 if (i == 0) { 11875 safe_printf("%s%s:", TMPL_INDENT, 11876 gettext("internal separators")); 11877 } 11878 safe_printf(" \"%s\"", values.values_as_strings[i]); 11879 } 11880 safe_printf("\n"); 11881 } 11882 11883 if (templates != 2) 11884 return; 11885 11886 if (prop != NULL) 11887 list_values_tmpl(prt, prop); 11888 else 11889 list_values_by_template(prt); 11890 } 11891 11892 static char * 11893 read_astring(scf_propertygroup_t *pg, const char *prop_name) 11894 { 11895 char *rv; 11896 11897 rv = _scf_read_single_astring_from_pg(pg, prop_name); 11898 if (rv == NULL) { 11899 switch (scf_error()) { 11900 case SCF_ERROR_NOT_FOUND: 11901 break; 11902 default: 11903 scfdie(); 11904 } 11905 } 11906 return (rv); 11907 } 11908 11909 static void 11910 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 11911 { 11912 size_t doc_len; 11913 size_t man_len; 11914 char *pg_name; 11915 char *text = NULL; 11916 int rv; 11917 11918 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 11919 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 11920 pg_name = safe_malloc(max_scf_name_len + 1); 11921 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 11922 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 11923 scfdie(); 11924 } 11925 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 11926 /* Display doc_link and and uri */ 11927 safe_printf("%s%s:\n", TMPL_INDENT, 11928 gettext("doc_link")); 11929 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 11930 if (text != NULL) { 11931 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11932 TMPL_INDENT, gettext("name"), text); 11933 uu_free(text); 11934 } 11935 text = read_astring(pg, SCF_PROPERTY_TM_URI); 11936 if (text != NULL) { 11937 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 11938 gettext("uri"), text); 11939 uu_free(text); 11940 } 11941 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 11942 man_len) == 0) { 11943 /* Display manpage title, section and path */ 11944 safe_printf("%s%s:\n", TMPL_INDENT, 11945 gettext("manpage")); 11946 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 11947 if (text != NULL) { 11948 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11949 TMPL_INDENT, gettext("title"), text); 11950 uu_free(text); 11951 } 11952 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 11953 if (text != NULL) { 11954 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11955 TMPL_INDENT, gettext("section"), text); 11956 uu_free(text); 11957 } 11958 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 11959 if (text != NULL) { 11960 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11961 TMPL_INDENT, gettext("manpath"), text); 11962 uu_free(text); 11963 } 11964 } 11965 } 11966 if (rv == -1) 11967 scfdie(); 11968 11969 done: 11970 free(pg_name); 11971 } 11972 11973 static void 11974 list_entity_tmpl(int templates) 11975 { 11976 char *common_name = NULL; 11977 char *description = NULL; 11978 char *locale = NULL; 11979 scf_iter_t *iter; 11980 scf_propertygroup_t *pg; 11981 scf_property_t *prop; 11982 int r; 11983 scf_value_t *val; 11984 11985 if ((pg = scf_pg_create(g_hndl)) == NULL || 11986 (prop = scf_property_create(g_hndl)) == NULL || 11987 (val = scf_value_create(g_hndl)) == NULL || 11988 (iter = scf_iter_create(g_hndl)) == NULL) 11989 scfdie(); 11990 11991 locale = setlocale(LC_MESSAGES, NULL); 11992 11993 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 11994 common_name = safe_malloc(max_scf_value_len + 1); 11995 11996 /* Try both the current locale and the "C" locale. */ 11997 if (scf_pg_get_property(pg, locale, prop) == 0 || 11998 (scf_error() == SCF_ERROR_NOT_FOUND && 11999 scf_pg_get_property(pg, "C", prop) == 0)) { 12000 if (prop_get_val(prop, val) == 0 && 12001 scf_value_get_ustring(val, common_name, 12002 max_scf_value_len + 1) != -1) { 12003 safe_printf("%s%s: %s\n", TMPL_INDENT, 12004 gettext("common name"), common_name); 12005 } 12006 } 12007 } 12008 12009 /* 12010 * Do description, manpages, and doc links if templates == 2. 12011 */ 12012 if (templates == 2) { 12013 /* Get the description. */ 12014 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 12015 description = safe_malloc(max_scf_value_len + 1); 12016 12017 /* Try both the current locale and the "C" locale. */ 12018 if (scf_pg_get_property(pg, locale, prop) == 0 || 12019 (scf_error() == SCF_ERROR_NOT_FOUND && 12020 scf_pg_get_property(pg, "C", prop) == 0)) { 12021 if (prop_get_val(prop, val) == 0 && 12022 scf_value_get_ustring(val, description, 12023 max_scf_value_len + 1) != -1) { 12024 safe_printf("%s%s: %s\n", TMPL_INDENT, 12025 gettext("description"), 12026 description); 12027 } 12028 } 12029 } 12030 12031 /* Process doc_link & manpage elements. */ 12032 if (cur_level != NULL) { 12033 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 12034 SCF_GROUP_TEMPLATE); 12035 } else if (cur_inst != NULL) { 12036 r = scf_iter_instance_pgs_typed(iter, cur_inst, 12037 SCF_GROUP_TEMPLATE); 12038 } else { 12039 r = scf_iter_service_pgs_typed(iter, cur_svc, 12040 SCF_GROUP_TEMPLATE); 12041 } 12042 if (r == 0) { 12043 display_documentation(iter, pg); 12044 } 12045 } 12046 12047 free(common_name); 12048 free(description); 12049 scf_pg_destroy(pg); 12050 scf_property_destroy(prop); 12051 scf_value_destroy(val); 12052 scf_iter_destroy(iter); 12053 } 12054 12055 static void 12056 listtmpl(const char *pattern, int templates) 12057 { 12058 scf_pg_tmpl_t *pgt; 12059 scf_prop_tmpl_t *prt; 12060 char *snapbuf = NULL; 12061 char *fmribuf; 12062 char *pg_name = NULL, *prop_name = NULL; 12063 ssize_t prop_name_size; 12064 char *qual_prop_name; 12065 char *search_name; 12066 int listed = 0; 12067 12068 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 12069 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 12070 scfdie(); 12071 12072 fmribuf = safe_malloc(max_scf_name_len + 1); 12073 qual_prop_name = safe_malloc(max_scf_name_len + 1); 12074 12075 if (cur_snap != NULL) { 12076 snapbuf = safe_malloc(max_scf_name_len + 1); 12077 if (scf_snapshot_get_name(cur_snap, snapbuf, 12078 max_scf_name_len + 1) < 0) 12079 scfdie(); 12080 } 12081 12082 if (cur_inst != NULL) { 12083 if (scf_instance_to_fmri(cur_inst, fmribuf, 12084 max_scf_name_len + 1) < 0) 12085 scfdie(); 12086 } else if (cur_svc != NULL) { 12087 if (scf_service_to_fmri(cur_svc, fmribuf, 12088 max_scf_name_len + 1) < 0) 12089 scfdie(); 12090 } else 12091 abort(); 12092 12093 /* If pattern is specified, we want to list only those items. */ 12094 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) { 12095 listed = 0; 12096 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 12097 fnmatch(pattern, pg_name, 0) == 0)) { 12098 list_pg_tmpl(pgt, NULL, templates); 12099 listed++; 12100 } 12101 12102 scf_tmpl_prop_reset(prt); 12103 12104 while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) { 12105 search_name = NULL; 12106 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 12107 if ((prop_name_size > 0) && (pg_name != NULL)) { 12108 if (snprintf(qual_prop_name, 12109 max_scf_name_len + 1, "%s/%s", 12110 pg_name, prop_name) >= 12111 max_scf_name_len + 1) { 12112 prop_name_size = -1; 12113 } else { 12114 search_name = qual_prop_name; 12115 } 12116 } 12117 if (listed > 0 || pattern == NULL || 12118 (prop_name_size > 0 && 12119 fnmatch(pattern, search_name, 12120 FNM_PATHNAME) == 0)) 12121 list_prop_tmpl(prt, NULL, templates); 12122 if (prop_name != NULL) { 12123 free(prop_name); 12124 prop_name = NULL; 12125 } 12126 } 12127 if (pg_name != NULL) { 12128 free(pg_name); 12129 pg_name = NULL; 12130 } 12131 } 12132 12133 scf_tmpl_prop_destroy(prt); 12134 scf_tmpl_pg_destroy(pgt); 12135 free(snapbuf); 12136 free(fmribuf); 12137 free(qual_prop_name); 12138 } 12139 12140 static void 12141 listprop(const char *pattern, int only_pgs, int templates) 12142 { 12143 scf_propertygroup_t *pg; 12144 scf_property_t *prop; 12145 scf_iter_t *iter, *piter; 12146 char *pgnbuf, *prnbuf, *ppnbuf; 12147 scf_pg_tmpl_t *pgt, *pgtp; 12148 scf_prop_tmpl_t *prt; 12149 12150 void **objects; 12151 char **names; 12152 void **tmpls; 12153 int allocd, i; 12154 12155 int ret; 12156 ssize_t pgnlen, prnlen, szret; 12157 size_t max_len = 0; 12158 12159 if (cur_svc == NULL && cur_inst == NULL) { 12160 semerr(emsg_entity_not_selected); 12161 return; 12162 } 12163 12164 if ((pg = scf_pg_create(g_hndl)) == NULL || 12165 (prop = scf_property_create(g_hndl)) == NULL || 12166 (iter = scf_iter_create(g_hndl)) == NULL || 12167 (piter = scf_iter_create(g_hndl)) == NULL || 12168 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12169 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 12170 scfdie(); 12171 12172 prnbuf = safe_malloc(max_scf_name_len + 1); 12173 12174 if (cur_level != NULL) 12175 ret = scf_iter_snaplevel_pgs(iter, cur_level); 12176 else if (cur_inst != NULL) 12177 ret = scf_iter_instance_pgs(iter, cur_inst); 12178 else 12179 ret = scf_iter_service_pgs(iter, cur_svc); 12180 if (ret != 0) { 12181 return; 12182 } 12183 12184 /* 12185 * We want to only list items which match pattern, and we want the 12186 * second column to line up, so during the first pass we'll save 12187 * matching items, their names, and their templates in objects, 12188 * names, and tmpls, computing the maximum name length as we go, 12189 * and then we'll print them out. 12190 * 12191 * Note: We always keep an extra slot available so the array can be 12192 * NULL-terminated. 12193 */ 12194 i = 0; 12195 allocd = 1; 12196 objects = safe_malloc(sizeof (*objects)); 12197 names = safe_malloc(sizeof (*names)); 12198 tmpls = safe_malloc(sizeof (*tmpls)); 12199 12200 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12201 int new_pg = 0; 12202 int print_props = 0; 12203 pgtp = NULL; 12204 12205 pgnlen = scf_pg_get_name(pg, NULL, 0); 12206 if (pgnlen < 0) 12207 scfdie(); 12208 12209 pgnbuf = safe_malloc(pgnlen + 1); 12210 12211 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 12212 if (szret < 0) 12213 scfdie(); 12214 assert(szret <= pgnlen); 12215 12216 if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) { 12217 if (scf_error() != SCF_ERROR_NOT_FOUND) 12218 scfdie(); 12219 pgtp = NULL; 12220 } else { 12221 pgtp = pgt; 12222 } 12223 12224 if (pattern == NULL || 12225 fnmatch(pattern, pgnbuf, 0) == 0) { 12226 if (i+1 >= allocd) { 12227 allocd *= 2; 12228 objects = realloc(objects, 12229 sizeof (*objects) * allocd); 12230 names = 12231 realloc(names, sizeof (*names) * allocd); 12232 tmpls = realloc(tmpls, 12233 sizeof (*tmpls) * allocd); 12234 if (objects == NULL || names == NULL || 12235 tmpls == NULL) 12236 uu_die(gettext("Out of memory")); 12237 } 12238 objects[i] = pg; 12239 names[i] = pgnbuf; 12240 12241 if (pgtp == NULL) 12242 tmpls[i] = NULL; 12243 else 12244 tmpls[i] = pgt; 12245 12246 ++i; 12247 12248 if (pgnlen > max_len) 12249 max_len = pgnlen; 12250 12251 new_pg = 1; 12252 print_props = 1; 12253 } 12254 12255 if (only_pgs) { 12256 if (new_pg) { 12257 pg = scf_pg_create(g_hndl); 12258 if (pg == NULL) 12259 scfdie(); 12260 pgt = scf_tmpl_pg_create(g_hndl); 12261 if (pgt == NULL) 12262 scfdie(); 12263 } else 12264 free(pgnbuf); 12265 12266 continue; 12267 } 12268 12269 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 12270 scfdie(); 12271 12272 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 12273 prnlen = scf_property_get_name(prop, prnbuf, 12274 max_scf_name_len + 1); 12275 if (prnlen < 0) 12276 scfdie(); 12277 12278 /* Will prepend the property group name and a slash. */ 12279 prnlen += pgnlen + 1; 12280 12281 ppnbuf = safe_malloc(prnlen + 1); 12282 12283 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 12284 prnbuf) < 0) 12285 uu_die("snprintf"); 12286 12287 if (pattern == NULL || print_props == 1 || 12288 fnmatch(pattern, ppnbuf, 0) == 0) { 12289 if (i+1 >= allocd) { 12290 allocd *= 2; 12291 objects = realloc(objects, 12292 sizeof (*objects) * allocd); 12293 names = realloc(names, 12294 sizeof (*names) * allocd); 12295 tmpls = realloc(tmpls, 12296 sizeof (*tmpls) * allocd); 12297 if (objects == NULL || names == NULL || 12298 tmpls == NULL) 12299 uu_die(gettext( 12300 "Out of memory")); 12301 } 12302 12303 objects[i] = prop; 12304 names[i] = ppnbuf; 12305 12306 if (pgtp != NULL) { 12307 if (scf_tmpl_get_by_prop(pgt, prnbuf, 12308 prt, NULL) < 0) { 12309 if (scf_error() != 12310 SCF_ERROR_NOT_FOUND) 12311 scfdie(); 12312 tmpls[i] = NULL; 12313 } else { 12314 tmpls[i] = prt; 12315 } 12316 } else { 12317 tmpls[i] = NULL; 12318 } 12319 12320 ++i; 12321 12322 if (prnlen > max_len) 12323 max_len = prnlen; 12324 12325 prop = scf_property_create(g_hndl); 12326 prt = scf_tmpl_prop_create(g_hndl); 12327 } else { 12328 free(ppnbuf); 12329 } 12330 } 12331 12332 if (new_pg) { 12333 pg = scf_pg_create(g_hndl); 12334 if (pg == NULL) 12335 scfdie(); 12336 pgt = scf_tmpl_pg_create(g_hndl); 12337 if (pgt == NULL) 12338 scfdie(); 12339 } else 12340 free(pgnbuf); 12341 } 12342 if (ret != 0) 12343 scfdie(); 12344 12345 objects[i] = NULL; 12346 12347 scf_pg_destroy(pg); 12348 scf_tmpl_pg_destroy(pgt); 12349 scf_property_destroy(prop); 12350 scf_tmpl_prop_destroy(prt); 12351 12352 for (i = 0; objects[i] != NULL; ++i) { 12353 if (strchr(names[i], '/') == NULL) { 12354 /* property group */ 12355 pg = (scf_propertygroup_t *)objects[i]; 12356 pgt = (scf_pg_tmpl_t *)tmpls[i]; 12357 list_pg_info(pg, names[i], max_len); 12358 list_pg_tmpl(pgt, pg, templates); 12359 free(names[i]); 12360 scf_pg_destroy(pg); 12361 if (pgt != NULL) 12362 scf_tmpl_pg_destroy(pgt); 12363 } else { 12364 /* property */ 12365 prop = (scf_property_t *)objects[i]; 12366 prt = (scf_prop_tmpl_t *)tmpls[i]; 12367 list_prop_info(prop, names[i], max_len); 12368 list_prop_tmpl(prt, prop, templates); 12369 free(names[i]); 12370 scf_property_destroy(prop); 12371 if (prt != NULL) 12372 scf_tmpl_prop_destroy(prt); 12373 } 12374 } 12375 12376 free(names); 12377 free(objects); 12378 free(tmpls); 12379 } 12380 12381 void 12382 lscf_listpg(const char *pattern) 12383 { 12384 lscf_prep_hndl(); 12385 12386 listprop(pattern, 1, 0); 12387 } 12388 12389 /* 12390 * Property group and property creation, setting, and deletion. setprop (and 12391 * its alias, addprop) can either create a property group of a given type, or 12392 * it can create or set a property to a given type and list of values. 12393 */ 12394 void 12395 lscf_addpg(const char *name, const char *type, const char *flags) 12396 { 12397 scf_propertygroup_t *pg; 12398 int ret; 12399 uint32_t flgs = 0; 12400 const char *cp; 12401 12402 12403 lscf_prep_hndl(); 12404 12405 if (cur_snap != NULL) { 12406 semerr(emsg_cant_modify_snapshots); 12407 return; 12408 } 12409 12410 if (cur_inst == NULL && cur_svc == NULL) { 12411 semerr(emsg_entity_not_selected); 12412 return; 12413 } 12414 12415 if (flags != NULL) { 12416 for (cp = flags; *cp != '\0'; ++cp) { 12417 switch (*cp) { 12418 case 'P': 12419 flgs |= SCF_PG_FLAG_NONPERSISTENT; 12420 break; 12421 12422 case 'p': 12423 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 12424 break; 12425 12426 default: 12427 semerr(gettext("Invalid property group flag " 12428 "%c."), *cp); 12429 return; 12430 } 12431 } 12432 } 12433 12434 pg = scf_pg_create(g_hndl); 12435 if (pg == NULL) 12436 scfdie(); 12437 12438 if (cur_inst != NULL) 12439 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 12440 else 12441 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 12442 12443 if (ret != SCF_SUCCESS) { 12444 switch (scf_error()) { 12445 case SCF_ERROR_INVALID_ARGUMENT: 12446 semerr(gettext("Name, type, or flags are invalid.\n")); 12447 break; 12448 12449 case SCF_ERROR_EXISTS: 12450 semerr(gettext("Property group already exists.\n")); 12451 break; 12452 12453 case SCF_ERROR_PERMISSION_DENIED: 12454 semerr(emsg_permission_denied); 12455 break; 12456 12457 case SCF_ERROR_BACKEND_ACCESS: 12458 semerr(gettext("Backend refused access.\n")); 12459 break; 12460 12461 default: 12462 scfdie(); 12463 } 12464 } 12465 12466 scf_pg_destroy(pg); 12467 12468 private_refresh(); 12469 } 12470 12471 void 12472 lscf_delpg(char *name) 12473 { 12474 lscf_prep_hndl(); 12475 12476 if (cur_snap != NULL) { 12477 semerr(emsg_cant_modify_snapshots); 12478 return; 12479 } 12480 12481 if (cur_inst == NULL && cur_svc == NULL) { 12482 semerr(emsg_entity_not_selected); 12483 return; 12484 } 12485 12486 if (strchr(name, '/') != NULL) { 12487 semerr(emsg_invalid_pg_name, name); 12488 return; 12489 } 12490 12491 lscf_delprop(name); 12492 } 12493 12494 /* 12495 * scf_delhash() is used to remove the property group related to the 12496 * hash entry for a specific manifest in the repository. pgname will be 12497 * constructed from the location of the manifest file. If deathrow isn't 0, 12498 * manifest file doesn't need to exist (manifest string will be used as 12499 * an absolute path). 12500 */ 12501 void 12502 lscf_delhash(char *manifest, int deathrow) 12503 { 12504 char *pgname; 12505 12506 if (cur_snap != NULL || 12507 cur_inst != NULL || cur_svc != NULL) { 12508 warn(gettext("error, an entity is selected\n")); 12509 return; 12510 } 12511 12512 /* select smf/manifest */ 12513 lscf_select(HASH_SVC); 12514 /* 12515 * Translate the manifest file name to property name. In the deathrow 12516 * case, the manifest file does not need to exist. 12517 */ 12518 pgname = mhash_filename_to_propname(manifest, 12519 deathrow ? B_TRUE : B_FALSE); 12520 if (pgname == NULL) { 12521 warn(gettext("cannot resolve pathname for %s\n"), manifest); 12522 return; 12523 } 12524 /* delete the hash property name */ 12525 lscf_delpg(pgname); 12526 } 12527 12528 void 12529 lscf_listprop(const char *pattern) 12530 { 12531 lscf_prep_hndl(); 12532 12533 listprop(pattern, 0, 0); 12534 } 12535 12536 int 12537 lscf_setprop(const char *pgname, const char *type, const char *value, 12538 const uu_list_t *values) 12539 { 12540 scf_type_t ty, current_ty; 12541 scf_service_t *svc; 12542 scf_propertygroup_t *pg, *parent_pg; 12543 scf_property_t *prop, *parent_prop; 12544 scf_pg_tmpl_t *pgt; 12545 scf_prop_tmpl_t *prt; 12546 int ret, result = 0; 12547 scf_transaction_t *tx; 12548 scf_transaction_entry_t *e; 12549 scf_value_t *v; 12550 uu_list_walk_t *walk; 12551 string_list_t *sp; 12552 char *propname; 12553 int req_quotes = 0; 12554 12555 lscf_prep_hndl(); 12556 12557 if ((e = scf_entry_create(g_hndl)) == NULL || 12558 (svc = scf_service_create(g_hndl)) == NULL || 12559 (parent_pg = scf_pg_create(g_hndl)) == NULL || 12560 (pg = scf_pg_create(g_hndl)) == NULL || 12561 (parent_prop = scf_property_create(g_hndl)) == NULL || 12562 (prop = scf_property_create(g_hndl)) == NULL || 12563 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 12564 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12565 (tx = scf_transaction_create(g_hndl)) == NULL) 12566 scfdie(); 12567 12568 if (cur_snap != NULL) { 12569 semerr(emsg_cant_modify_snapshots); 12570 goto fail; 12571 } 12572 12573 if (cur_inst == NULL && cur_svc == NULL) { 12574 semerr(emsg_entity_not_selected); 12575 goto fail; 12576 } 12577 12578 propname = strchr(pgname, '/'); 12579 if (propname == NULL) { 12580 semerr(gettext("Property names must contain a `/'.\n")); 12581 goto fail; 12582 } 12583 12584 *propname = '\0'; 12585 ++propname; 12586 12587 if (type != NULL) { 12588 ty = string_to_type(type); 12589 if (ty == SCF_TYPE_INVALID) { 12590 semerr(gettext("Unknown type \"%s\".\n"), type); 12591 goto fail; 12592 } 12593 } 12594 12595 if (cur_inst != NULL) 12596 ret = scf_instance_get_pg(cur_inst, pgname, pg); 12597 else 12598 ret = scf_service_get_pg(cur_svc, pgname, pg); 12599 if (ret != SCF_SUCCESS) { 12600 switch (scf_error()) { 12601 case SCF_ERROR_NOT_FOUND: 12602 semerr(emsg_no_such_pg, pgname); 12603 goto fail; 12604 12605 case SCF_ERROR_INVALID_ARGUMENT: 12606 semerr(emsg_invalid_pg_name, pgname); 12607 goto fail; 12608 12609 default: 12610 scfdie(); 12611 break; 12612 } 12613 } 12614 12615 do { 12616 if (scf_pg_update(pg) == -1) 12617 scfdie(); 12618 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12619 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12620 scfdie(); 12621 12622 semerr(emsg_permission_denied); 12623 goto fail; 12624 } 12625 12626 ret = scf_pg_get_property(pg, propname, prop); 12627 if (ret == SCF_SUCCESS) { 12628 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 12629 scfdie(); 12630 12631 if (type == NULL) 12632 ty = current_ty; 12633 if (scf_transaction_property_change_type(tx, e, 12634 propname, ty) == -1) 12635 scfdie(); 12636 12637 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 12638 /* Infer the type, if possible. */ 12639 if (type == NULL) { 12640 /* 12641 * First check if we're an instance and the 12642 * property is set on the service. 12643 */ 12644 if (cur_inst != NULL && 12645 scf_instance_get_parent(cur_inst, 12646 svc) == 0 && 12647 scf_service_get_pg(cur_svc, pgname, 12648 parent_pg) == 0 && 12649 scf_pg_get_property(parent_pg, propname, 12650 parent_prop) == 0 && 12651 scf_property_type(parent_prop, 12652 ¤t_ty) == 0) { 12653 ty = current_ty; 12654 12655 /* Then check for a type set in a template. */ 12656 } else if (scf_tmpl_get_by_pg(pg, pgt, 12657 NULL) == 0 && 12658 scf_tmpl_get_by_prop(pgt, propname, prt, 12659 NULL) == 0 && 12660 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 12661 ty = current_ty; 12662 12663 /* If type can't be inferred, fail. */ 12664 } else { 12665 semerr(gettext("Type required for new " 12666 "properties.\n")); 12667 goto fail; 12668 } 12669 } 12670 if (scf_transaction_property_new(tx, e, propname, 12671 ty) == -1) 12672 scfdie(); 12673 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12674 semerr(emsg_invalid_prop_name, propname); 12675 goto fail; 12676 } else { 12677 scfdie(); 12678 } 12679 12680 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 12681 req_quotes = 1; 12682 12683 if (value != NULL) { 12684 v = string_to_value(value, ty, 0); 12685 12686 if (v == NULL) 12687 goto fail; 12688 12689 ret = scf_entry_add_value(e, v); 12690 assert(ret == SCF_SUCCESS); 12691 } else { 12692 assert(values != NULL); 12693 12694 walk = uu_list_walk_start((uu_list_t *)values, 12695 UU_DEFAULT); 12696 if (walk == NULL) 12697 uu_die(gettext("Could not walk list")); 12698 12699 for (sp = uu_list_walk_next(walk); sp != NULL; 12700 sp = uu_list_walk_next(walk)) { 12701 v = string_to_value(sp->str, ty, req_quotes); 12702 12703 if (v == NULL) { 12704 scf_entry_destroy_children(e); 12705 goto fail; 12706 } 12707 12708 ret = scf_entry_add_value(e, v); 12709 assert(ret == SCF_SUCCESS); 12710 } 12711 uu_list_walk_end(walk); 12712 } 12713 result = scf_transaction_commit(tx); 12714 12715 scf_transaction_reset(tx); 12716 scf_entry_destroy_children(e); 12717 } while (result == 0); 12718 12719 if (result < 0) { 12720 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12721 scfdie(); 12722 12723 semerr(emsg_permission_denied); 12724 goto fail; 12725 } 12726 12727 ret = 0; 12728 12729 private_refresh(); 12730 12731 goto cleanup; 12732 12733 fail: 12734 ret = -1; 12735 12736 cleanup: 12737 scf_transaction_destroy(tx); 12738 scf_entry_destroy(e); 12739 scf_service_destroy(svc); 12740 scf_pg_destroy(parent_pg); 12741 scf_pg_destroy(pg); 12742 scf_property_destroy(parent_prop); 12743 scf_property_destroy(prop); 12744 scf_tmpl_pg_destroy(pgt); 12745 scf_tmpl_prop_destroy(prt); 12746 12747 return (ret); 12748 } 12749 12750 void 12751 lscf_delprop(char *pgn) 12752 { 12753 char *slash, *pn; 12754 scf_propertygroup_t *pg; 12755 scf_transaction_t *tx; 12756 scf_transaction_entry_t *e; 12757 int ret; 12758 12759 12760 lscf_prep_hndl(); 12761 12762 if (cur_snap != NULL) { 12763 semerr(emsg_cant_modify_snapshots); 12764 return; 12765 } 12766 12767 if (cur_inst == NULL && cur_svc == NULL) { 12768 semerr(emsg_entity_not_selected); 12769 return; 12770 } 12771 12772 pg = scf_pg_create(g_hndl); 12773 if (pg == NULL) 12774 scfdie(); 12775 12776 slash = strchr(pgn, '/'); 12777 if (slash == NULL) { 12778 pn = NULL; 12779 } else { 12780 *slash = '\0'; 12781 pn = slash + 1; 12782 } 12783 12784 if (cur_inst != NULL) 12785 ret = scf_instance_get_pg(cur_inst, pgn, pg); 12786 else 12787 ret = scf_service_get_pg(cur_svc, pgn, pg); 12788 if (ret != SCF_SUCCESS) { 12789 switch (scf_error()) { 12790 case SCF_ERROR_NOT_FOUND: 12791 semerr(emsg_no_such_pg, pgn); 12792 break; 12793 12794 case SCF_ERROR_INVALID_ARGUMENT: 12795 semerr(emsg_invalid_pg_name, pgn); 12796 break; 12797 12798 default: 12799 scfdie(); 12800 } 12801 12802 scf_pg_destroy(pg); 12803 12804 return; 12805 } 12806 12807 if (pn == NULL) { 12808 /* Try to delete the property group. */ 12809 if (scf_pg_delete(pg) != SCF_SUCCESS) { 12810 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12811 scfdie(); 12812 12813 semerr(emsg_permission_denied); 12814 } else { 12815 private_refresh(); 12816 } 12817 12818 scf_pg_destroy(pg); 12819 return; 12820 } 12821 12822 e = scf_entry_create(g_hndl); 12823 tx = scf_transaction_create(g_hndl); 12824 12825 do { 12826 if (scf_pg_update(pg) == -1) 12827 scfdie(); 12828 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12829 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12830 scfdie(); 12831 12832 semerr(emsg_permission_denied); 12833 break; 12834 } 12835 12836 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 12837 if (scf_error() == SCF_ERROR_NOT_FOUND) { 12838 semerr(gettext("No such property %s/%s.\n"), 12839 pgn, pn); 12840 break; 12841 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12842 semerr(emsg_invalid_prop_name, pn); 12843 break; 12844 } else { 12845 scfdie(); 12846 } 12847 } 12848 12849 ret = scf_transaction_commit(tx); 12850 12851 if (ret == 0) 12852 scf_transaction_reset(tx); 12853 } while (ret == 0); 12854 12855 if (ret < 0) { 12856 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12857 scfdie(); 12858 12859 semerr(emsg_permission_denied); 12860 } else { 12861 private_refresh(); 12862 } 12863 12864 scf_transaction_destroy(tx); 12865 scf_entry_destroy(e); 12866 scf_pg_destroy(pg); 12867 } 12868 12869 /* 12870 * Property editing. 12871 */ 12872 12873 static int 12874 write_edit_script(FILE *strm) 12875 { 12876 char *fmribuf; 12877 ssize_t fmrilen; 12878 12879 scf_propertygroup_t *pg; 12880 scf_property_t *prop; 12881 scf_value_t *val; 12882 scf_type_t ty; 12883 int ret, result = 0; 12884 scf_iter_t *iter, *piter, *viter; 12885 char *buf, *tybuf, *pname; 12886 const char *emsg_write_error; 12887 12888 12889 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 12890 12891 12892 /* select fmri */ 12893 if (cur_inst != NULL) { 12894 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 12895 if (fmrilen < 0) 12896 scfdie(); 12897 fmribuf = safe_malloc(fmrilen + 1); 12898 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 12899 scfdie(); 12900 } else { 12901 assert(cur_svc != NULL); 12902 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 12903 if (fmrilen < 0) 12904 scfdie(); 12905 fmribuf = safe_malloc(fmrilen + 1); 12906 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 12907 scfdie(); 12908 } 12909 12910 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 12911 warn(emsg_write_error, strerror(errno)); 12912 free(fmribuf); 12913 return (-1); 12914 } 12915 12916 free(fmribuf); 12917 12918 12919 if ((pg = scf_pg_create(g_hndl)) == NULL || 12920 (prop = scf_property_create(g_hndl)) == NULL || 12921 (val = scf_value_create(g_hndl)) == NULL || 12922 (iter = scf_iter_create(g_hndl)) == NULL || 12923 (piter = scf_iter_create(g_hndl)) == NULL || 12924 (viter = scf_iter_create(g_hndl)) == NULL) 12925 scfdie(); 12926 12927 buf = safe_malloc(max_scf_name_len + 1); 12928 tybuf = safe_malloc(max_scf_pg_type_len + 1); 12929 pname = safe_malloc(max_scf_name_len + 1); 12930 12931 if (cur_inst != NULL) 12932 ret = scf_iter_instance_pgs(iter, cur_inst); 12933 else 12934 ret = scf_iter_service_pgs(iter, cur_svc); 12935 if (ret != SCF_SUCCESS) 12936 scfdie(); 12937 12938 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12939 int ret2; 12940 12941 /* 12942 * # delprop pg 12943 * # addpg pg type 12944 */ 12945 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 12946 scfdie(); 12947 12948 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 12949 scfdie(); 12950 12951 if (fprintf(strm, "# Property group \"%s\"\n" 12952 "# delprop %s\n" 12953 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 12954 warn(emsg_write_error, strerror(errno)); 12955 result = -1; 12956 goto out; 12957 } 12958 12959 /* # setprop pg/prop = (values) */ 12960 12961 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 12962 scfdie(); 12963 12964 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 12965 int first = 1; 12966 int ret3; 12967 int multiple; 12968 int is_str; 12969 scf_type_t bty; 12970 12971 if (scf_property_get_name(prop, pname, 12972 max_scf_name_len + 1) < 0) 12973 scfdie(); 12974 12975 if (scf_property_type(prop, &ty) != 0) 12976 scfdie(); 12977 12978 multiple = prop_has_multiple_values(prop, val); 12979 12980 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 12981 pname, scf_type_to_string(ty), multiple ? "(" : "") 12982 < 0) { 12983 warn(emsg_write_error, strerror(errno)); 12984 result = -1; 12985 goto out; 12986 } 12987 12988 (void) scf_type_base_type(ty, &bty); 12989 is_str = (bty == SCF_TYPE_ASTRING); 12990 12991 if (scf_iter_property_values(viter, prop) != 12992 SCF_SUCCESS) 12993 scfdie(); 12994 12995 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 12996 char *buf; 12997 ssize_t buflen; 12998 12999 buflen = scf_value_get_as_string(val, NULL, 0); 13000 if (buflen < 0) 13001 scfdie(); 13002 13003 buf = safe_malloc(buflen + 1); 13004 13005 if (scf_value_get_as_string(val, buf, 13006 buflen + 1) < 0) 13007 scfdie(); 13008 13009 if (first) 13010 first = 0; 13011 else { 13012 if (putc(' ', strm) != ' ') { 13013 warn(emsg_write_error, 13014 strerror(errno)); 13015 result = -1; 13016 goto out; 13017 } 13018 } 13019 13020 if ((is_str && multiple) || 13021 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 13022 (void) putc('"', strm); 13023 (void) quote_and_print(buf, strm, 1); 13024 (void) putc('"', strm); 13025 13026 if (ferror(strm)) { 13027 warn(emsg_write_error, 13028 strerror(errno)); 13029 result = -1; 13030 goto out; 13031 } 13032 } else { 13033 if (fprintf(strm, "%s", buf) < 0) { 13034 warn(emsg_write_error, 13035 strerror(errno)); 13036 result = -1; 13037 goto out; 13038 } 13039 } 13040 13041 free(buf); 13042 } 13043 if (ret3 < 0 && 13044 scf_error() != SCF_ERROR_PERMISSION_DENIED) 13045 scfdie(); 13046 13047 /* Write closing paren if mult-value property */ 13048 if ((multiple && putc(')', strm) == EOF) || 13049 13050 /* Write final newline */ 13051 fputc('\n', strm) == EOF) { 13052 warn(emsg_write_error, strerror(errno)); 13053 result = -1; 13054 goto out; 13055 } 13056 } 13057 if (ret2 < 0) 13058 scfdie(); 13059 13060 if (fputc('\n', strm) == EOF) { 13061 warn(emsg_write_error, strerror(errno)); 13062 result = -1; 13063 goto out; 13064 } 13065 } 13066 if (ret < 0) 13067 scfdie(); 13068 13069 out: 13070 free(pname); 13071 free(tybuf); 13072 free(buf); 13073 scf_iter_destroy(viter); 13074 scf_iter_destroy(piter); 13075 scf_iter_destroy(iter); 13076 scf_value_destroy(val); 13077 scf_property_destroy(prop); 13078 scf_pg_destroy(pg); 13079 13080 if (result == 0) { 13081 if (fflush(strm) != 0) { 13082 warn(emsg_write_error, strerror(errno)); 13083 return (-1); 13084 } 13085 } 13086 13087 return (result); 13088 } 13089 13090 int 13091 lscf_editprop() 13092 { 13093 char *buf, *editor; 13094 size_t bufsz; 13095 int tmpfd; 13096 char tempname[] = TEMP_FILE_PATTERN; 13097 13098 lscf_prep_hndl(); 13099 13100 if (cur_snap != NULL) { 13101 semerr(emsg_cant_modify_snapshots); 13102 return (-1); 13103 } 13104 13105 if (cur_svc == NULL && cur_inst == NULL) { 13106 semerr(emsg_entity_not_selected); 13107 return (-1); 13108 } 13109 13110 tmpfd = mkstemp(tempname); 13111 if (tmpfd == -1) { 13112 semerr(gettext("Could not create temporary file.\n")); 13113 return (-1); 13114 } 13115 13116 (void) strcpy(tempfilename, tempname); 13117 13118 tempfile = fdopen(tmpfd, "r+"); 13119 if (tempfile == NULL) { 13120 warn(gettext("Could not create temporary file.\n")); 13121 if (close(tmpfd) == -1) 13122 warn(gettext("Could not close temporary file: %s.\n"), 13123 strerror(errno)); 13124 13125 remove_tempfile(); 13126 13127 return (-1); 13128 } 13129 13130 if (write_edit_script(tempfile) == -1) { 13131 remove_tempfile(); 13132 return (-1); 13133 } 13134 13135 editor = getenv("EDITOR"); 13136 if (editor == NULL) 13137 editor = "vi"; 13138 13139 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 13140 buf = safe_malloc(bufsz); 13141 13142 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 13143 uu_die(gettext("Error creating editor command")); 13144 13145 if (system(buf) == -1) { 13146 semerr(gettext("Could not launch editor %s: %s\n"), editor, 13147 strerror(errno)); 13148 free(buf); 13149 remove_tempfile(); 13150 return (-1); 13151 } 13152 13153 free(buf); 13154 13155 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 13156 13157 remove_tempfile(); 13158 13159 return (0); 13160 } 13161 13162 static void 13163 add_string(uu_list_t *strlist, const char *str) 13164 { 13165 string_list_t *elem; 13166 elem = safe_malloc(sizeof (*elem)); 13167 uu_list_node_init(elem, &elem->node, string_pool); 13168 elem->str = safe_strdup(str); 13169 if (uu_list_append(strlist, elem) != 0) 13170 uu_die(gettext("libuutil error: %s\n"), 13171 uu_strerror(uu_error())); 13172 } 13173 13174 static int 13175 remove_string(uu_list_t *strlist, const char *str) 13176 { 13177 uu_list_walk_t *elems; 13178 string_list_t *sp; 13179 13180 /* 13181 * Find the element that needs to be removed. 13182 */ 13183 elems = uu_list_walk_start(strlist, UU_DEFAULT); 13184 while ((sp = uu_list_walk_next(elems)) != NULL) { 13185 if (strcmp(sp->str, str) == 0) 13186 break; 13187 } 13188 uu_list_walk_end(elems); 13189 13190 /* 13191 * Returning 1 here as the value was not found, this 13192 * might not be an error. Leave it to the caller to 13193 * decide. 13194 */ 13195 if (sp == NULL) { 13196 return (1); 13197 } 13198 13199 uu_list_remove(strlist, sp); 13200 13201 free(sp->str); 13202 free(sp); 13203 13204 return (0); 13205 } 13206 13207 /* 13208 * Get all property values that don't match the given glob pattern, 13209 * if a pattern is specified. 13210 */ 13211 static void 13212 get_prop_values(scf_property_t *prop, uu_list_t *values, 13213 const char *pattern) 13214 { 13215 scf_iter_t *iter; 13216 scf_value_t *val; 13217 int ret; 13218 13219 if ((iter = scf_iter_create(g_hndl)) == NULL || 13220 (val = scf_value_create(g_hndl)) == NULL) 13221 scfdie(); 13222 13223 if (scf_iter_property_values(iter, prop) != 0) 13224 scfdie(); 13225 13226 while ((ret = scf_iter_next_value(iter, val)) == 1) { 13227 char *buf; 13228 ssize_t vlen, szret; 13229 13230 vlen = scf_value_get_as_string(val, NULL, 0); 13231 if (vlen < 0) 13232 scfdie(); 13233 13234 buf = safe_malloc(vlen + 1); 13235 13236 szret = scf_value_get_as_string(val, buf, vlen + 1); 13237 if (szret < 0) 13238 scfdie(); 13239 assert(szret <= vlen); 13240 13241 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 13242 add_string(values, buf); 13243 13244 free(buf); 13245 } 13246 13247 if (ret == -1) 13248 scfdie(); 13249 13250 scf_value_destroy(val); 13251 scf_iter_destroy(iter); 13252 } 13253 13254 static int 13255 lscf_setpropvalue(const char *pgname, const char *type, 13256 const char *arg, int isadd, int isnotfoundok) 13257 { 13258 scf_type_t ty; 13259 scf_propertygroup_t *pg; 13260 scf_property_t *prop; 13261 int ret, result = 0; 13262 scf_transaction_t *tx; 13263 scf_transaction_entry_t *e; 13264 scf_value_t *v; 13265 string_list_t *sp; 13266 char *propname; 13267 uu_list_t *values; 13268 uu_list_walk_t *walk; 13269 void *cookie = NULL; 13270 char *pattern = NULL; 13271 13272 lscf_prep_hndl(); 13273 13274 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 13275 uu_die(gettext("Could not create property list: %s\n"), 13276 uu_strerror(uu_error())); 13277 13278 if (!isadd) 13279 pattern = safe_strdup(arg); 13280 13281 if ((e = scf_entry_create(g_hndl)) == NULL || 13282 (pg = scf_pg_create(g_hndl)) == NULL || 13283 (prop = scf_property_create(g_hndl)) == NULL || 13284 (tx = scf_transaction_create(g_hndl)) == NULL) 13285 scfdie(); 13286 13287 if (cur_snap != NULL) { 13288 semerr(emsg_cant_modify_snapshots); 13289 goto fail; 13290 } 13291 13292 if (cur_inst == NULL && cur_svc == NULL) { 13293 semerr(emsg_entity_not_selected); 13294 goto fail; 13295 } 13296 13297 propname = strchr(pgname, '/'); 13298 if (propname == NULL) { 13299 semerr(gettext("Property names must contain a `/'.\n")); 13300 goto fail; 13301 } 13302 13303 *propname = '\0'; 13304 ++propname; 13305 13306 if (type != NULL) { 13307 ty = string_to_type(type); 13308 if (ty == SCF_TYPE_INVALID) { 13309 semerr(gettext("Unknown type \"%s\".\n"), type); 13310 goto fail; 13311 } 13312 } 13313 13314 if (cur_inst != NULL) 13315 ret = scf_instance_get_pg(cur_inst, pgname, pg); 13316 else 13317 ret = scf_service_get_pg(cur_svc, pgname, pg); 13318 if (ret != 0) { 13319 switch (scf_error()) { 13320 case SCF_ERROR_NOT_FOUND: 13321 if (isnotfoundok) { 13322 result = 0; 13323 } else { 13324 semerr(emsg_no_such_pg, pgname); 13325 result = -1; 13326 } 13327 goto out; 13328 13329 case SCF_ERROR_INVALID_ARGUMENT: 13330 semerr(emsg_invalid_pg_name, pgname); 13331 goto fail; 13332 13333 default: 13334 scfdie(); 13335 } 13336 } 13337 13338 do { 13339 if (scf_pg_update(pg) == -1) 13340 scfdie(); 13341 if (scf_transaction_start(tx, pg) != 0) { 13342 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13343 scfdie(); 13344 13345 semerr(emsg_permission_denied); 13346 goto fail; 13347 } 13348 13349 ret = scf_pg_get_property(pg, propname, prop); 13350 if (ret == 0) { 13351 scf_type_t ptype; 13352 char *pat = pattern; 13353 13354 if (scf_property_type(prop, &ptype) != 0) 13355 scfdie(); 13356 13357 if (isadd) { 13358 if (type != NULL && ptype != ty) { 13359 semerr(gettext("Property \"%s\" is not " 13360 "of type \"%s\".\n"), propname, 13361 type); 13362 goto fail; 13363 } 13364 13365 pat = NULL; 13366 } else { 13367 size_t len = strlen(pat); 13368 if (len > 0 && pat[len - 1] == '\"') 13369 pat[len - 1] = '\0'; 13370 if (len > 0 && pat[0] == '\"') 13371 pat++; 13372 } 13373 13374 ty = ptype; 13375 13376 get_prop_values(prop, values, pat); 13377 13378 if (isadd) 13379 add_string(values, arg); 13380 13381 if (scf_transaction_property_change(tx, e, 13382 propname, ty) == -1) 13383 scfdie(); 13384 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13385 if (isadd) { 13386 if (type == NULL) { 13387 semerr(gettext("Type required " 13388 "for new properties.\n")); 13389 goto fail; 13390 } 13391 13392 add_string(values, arg); 13393 13394 if (scf_transaction_property_new(tx, e, 13395 propname, ty) == -1) 13396 scfdie(); 13397 } else if (isnotfoundok) { 13398 result = 0; 13399 goto out; 13400 } else { 13401 semerr(gettext("No such property %s/%s.\n"), 13402 pgname, propname); 13403 result = -1; 13404 goto out; 13405 } 13406 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13407 semerr(emsg_invalid_prop_name, propname); 13408 goto fail; 13409 } else { 13410 scfdie(); 13411 } 13412 13413 walk = uu_list_walk_start(values, UU_DEFAULT); 13414 if (walk == NULL) 13415 uu_die(gettext("Could not walk property list.\n")); 13416 13417 for (sp = uu_list_walk_next(walk); sp != NULL; 13418 sp = uu_list_walk_next(walk)) { 13419 v = string_to_value(sp->str, ty, 0); 13420 13421 if (v == NULL) { 13422 scf_entry_destroy_children(e); 13423 goto fail; 13424 } 13425 ret = scf_entry_add_value(e, v); 13426 assert(ret == 0); 13427 } 13428 uu_list_walk_end(walk); 13429 13430 result = scf_transaction_commit(tx); 13431 13432 scf_transaction_reset(tx); 13433 scf_entry_destroy_children(e); 13434 } while (result == 0); 13435 13436 if (result < 0) { 13437 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13438 scfdie(); 13439 13440 semerr(emsg_permission_denied); 13441 goto fail; 13442 } 13443 13444 result = 0; 13445 13446 private_refresh(); 13447 13448 out: 13449 scf_transaction_destroy(tx); 13450 scf_entry_destroy(e); 13451 scf_pg_destroy(pg); 13452 scf_property_destroy(prop); 13453 free(pattern); 13454 13455 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 13456 free(sp->str); 13457 free(sp); 13458 } 13459 13460 uu_list_destroy(values); 13461 13462 return (result); 13463 13464 fail: 13465 result = -1; 13466 goto out; 13467 } 13468 13469 int 13470 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 13471 { 13472 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 13473 } 13474 13475 int 13476 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 13477 { 13478 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 13479 } 13480 13481 /* 13482 * Look for a standard start method, first in the instance (if any), 13483 * then the service. 13484 */ 13485 static const char * 13486 start_method_name(int *in_instance) 13487 { 13488 scf_propertygroup_t *pg; 13489 char **p; 13490 int ret; 13491 scf_instance_t *inst = cur_inst; 13492 13493 if ((pg = scf_pg_create(g_hndl)) == NULL) 13494 scfdie(); 13495 13496 again: 13497 for (p = start_method_names; *p != NULL; p++) { 13498 if (inst != NULL) 13499 ret = scf_instance_get_pg(inst, *p, pg); 13500 else 13501 ret = scf_service_get_pg(cur_svc, *p, pg); 13502 13503 if (ret == 0) { 13504 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 13505 char *buf = safe_malloc(bufsz); 13506 13507 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 13508 free(buf); 13509 continue; 13510 } 13511 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 13512 free(buf); 13513 continue; 13514 } 13515 13516 free(buf); 13517 *in_instance = (inst != NULL); 13518 scf_pg_destroy(pg); 13519 return (*p); 13520 } 13521 13522 if (scf_error() == SCF_ERROR_NOT_FOUND) 13523 continue; 13524 13525 scfdie(); 13526 } 13527 13528 if (inst != NULL) { 13529 inst = NULL; 13530 goto again; 13531 } 13532 13533 scf_pg_destroy(pg); 13534 return (NULL); 13535 } 13536 13537 static int 13538 addpg(const char *name, const char *type) 13539 { 13540 scf_propertygroup_t *pg; 13541 int ret; 13542 13543 pg = scf_pg_create(g_hndl); 13544 if (pg == NULL) 13545 scfdie(); 13546 13547 if (cur_inst != NULL) 13548 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 13549 else 13550 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 13551 13552 if (ret != 0) { 13553 switch (scf_error()) { 13554 case SCF_ERROR_EXISTS: 13555 ret = 0; 13556 break; 13557 13558 case SCF_ERROR_PERMISSION_DENIED: 13559 semerr(emsg_permission_denied); 13560 break; 13561 13562 default: 13563 scfdie(); 13564 } 13565 } 13566 13567 scf_pg_destroy(pg); 13568 return (ret); 13569 } 13570 13571 int 13572 lscf_setenv(uu_list_t *args, int isunset) 13573 { 13574 int ret = 0; 13575 size_t i; 13576 int argc; 13577 char **argv = NULL; 13578 string_list_t *slp; 13579 char *pattern; 13580 char *prop; 13581 int do_service = 0; 13582 int do_instance = 0; 13583 const char *method = NULL; 13584 const char *name = NULL; 13585 const char *value = NULL; 13586 scf_instance_t *saved_cur_inst = cur_inst; 13587 13588 lscf_prep_hndl(); 13589 13590 argc = uu_list_numnodes(args); 13591 if (argc < 1) 13592 goto usage; 13593 13594 argv = calloc(argc + 1, sizeof (char *)); 13595 if (argv == NULL) 13596 uu_die(gettext("Out of memory.\n")); 13597 13598 for (slp = uu_list_first(args), i = 0; 13599 slp != NULL; 13600 slp = uu_list_next(args, slp), ++i) 13601 argv[i] = slp->str; 13602 13603 argv[i] = NULL; 13604 13605 opterr = 0; 13606 optind = 0; 13607 for (;;) { 13608 ret = getopt(argc, argv, "sim:"); 13609 if (ret == -1) 13610 break; 13611 13612 switch (ret) { 13613 case 's': 13614 do_service = 1; 13615 cur_inst = NULL; 13616 break; 13617 13618 case 'i': 13619 do_instance = 1; 13620 break; 13621 13622 case 'm': 13623 method = optarg; 13624 break; 13625 13626 case '?': 13627 goto usage; 13628 13629 default: 13630 bad_error("getopt", ret); 13631 } 13632 } 13633 13634 argc -= optind; 13635 if ((do_service && do_instance) || 13636 (isunset && argc != 1) || 13637 (!isunset && argc != 2)) 13638 goto usage; 13639 13640 name = argv[optind]; 13641 if (!isunset) 13642 value = argv[optind + 1]; 13643 13644 if (cur_snap != NULL) { 13645 semerr(emsg_cant_modify_snapshots); 13646 ret = -1; 13647 goto out; 13648 } 13649 13650 if (cur_inst == NULL && cur_svc == NULL) { 13651 semerr(emsg_entity_not_selected); 13652 ret = -1; 13653 goto out; 13654 } 13655 13656 if (do_instance && cur_inst == NULL) { 13657 semerr(gettext("No instance is selected.\n")); 13658 ret = -1; 13659 goto out; 13660 } 13661 13662 if (do_service && cur_svc == NULL) { 13663 semerr(gettext("No service is selected.\n")); 13664 ret = -1; 13665 goto out; 13666 } 13667 13668 if (method == NULL) { 13669 if (do_instance || do_service) { 13670 method = "method_context"; 13671 if (!isunset) { 13672 ret = addpg("method_context", 13673 SCF_GROUP_FRAMEWORK); 13674 if (ret != 0) 13675 goto out; 13676 } 13677 } else { 13678 int in_instance; 13679 method = start_method_name(&in_instance); 13680 if (method == NULL) { 13681 semerr(gettext( 13682 "Couldn't find start method; please " 13683 "specify a method with '-m'.\n")); 13684 ret = -1; 13685 goto out; 13686 } 13687 if (!in_instance) 13688 cur_inst = NULL; 13689 } 13690 } else { 13691 scf_propertygroup_t *pg; 13692 size_t bufsz; 13693 char *buf; 13694 int ret; 13695 13696 if ((pg = scf_pg_create(g_hndl)) == NULL) 13697 scfdie(); 13698 13699 if (cur_inst != NULL) 13700 ret = scf_instance_get_pg(cur_inst, method, pg); 13701 else 13702 ret = scf_service_get_pg(cur_svc, method, pg); 13703 13704 if (ret != 0) { 13705 scf_pg_destroy(pg); 13706 switch (scf_error()) { 13707 case SCF_ERROR_NOT_FOUND: 13708 semerr(gettext("Couldn't find the method " 13709 "\"%s\".\n"), method); 13710 goto out; 13711 13712 case SCF_ERROR_INVALID_ARGUMENT: 13713 semerr(gettext("Invalid method name \"%s\".\n"), 13714 method); 13715 goto out; 13716 13717 default: 13718 scfdie(); 13719 } 13720 } 13721 13722 bufsz = strlen(SCF_GROUP_METHOD) + 1; 13723 buf = safe_malloc(bufsz); 13724 13725 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 13726 strcmp(buf, SCF_GROUP_METHOD) != 0) { 13727 semerr(gettext("Property group \"%s\" is not of type " 13728 "\"method\".\n"), method); 13729 ret = -1; 13730 free(buf); 13731 scf_pg_destroy(pg); 13732 goto out; 13733 } 13734 13735 free(buf); 13736 scf_pg_destroy(pg); 13737 } 13738 13739 prop = uu_msprintf("%s/environment", method); 13740 pattern = uu_msprintf("%s=*", name); 13741 13742 if (prop == NULL || pattern == NULL) 13743 uu_die(gettext("Out of memory.\n")); 13744 13745 ret = lscf_delpropvalue(prop, pattern, !isunset); 13746 13747 if (ret == 0 && !isunset) { 13748 uu_free(pattern); 13749 uu_free(prop); 13750 prop = uu_msprintf("%s/environment", method); 13751 pattern = uu_msprintf("%s=%s", name, value); 13752 if (prop == NULL || pattern == NULL) 13753 uu_die(gettext("Out of memory.\n")); 13754 ret = lscf_addpropvalue(prop, "astring:", pattern); 13755 } 13756 uu_free(pattern); 13757 uu_free(prop); 13758 13759 out: 13760 cur_inst = saved_cur_inst; 13761 13762 free(argv); 13763 return (ret); 13764 usage: 13765 ret = -2; 13766 goto out; 13767 } 13768 13769 /* 13770 * Snapshot commands 13771 */ 13772 13773 void 13774 lscf_listsnap() 13775 { 13776 scf_snapshot_t *snap; 13777 scf_iter_t *iter; 13778 char *nb; 13779 int r; 13780 13781 lscf_prep_hndl(); 13782 13783 if (cur_inst == NULL) { 13784 semerr(gettext("Instance not selected.\n")); 13785 return; 13786 } 13787 13788 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13789 (iter = scf_iter_create(g_hndl)) == NULL) 13790 scfdie(); 13791 13792 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 13793 scfdie(); 13794 13795 nb = safe_malloc(max_scf_name_len + 1); 13796 13797 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 13798 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 13799 scfdie(); 13800 13801 (void) puts(nb); 13802 } 13803 if (r < 0) 13804 scfdie(); 13805 13806 free(nb); 13807 scf_iter_destroy(iter); 13808 scf_snapshot_destroy(snap); 13809 } 13810 13811 void 13812 lscf_selectsnap(const char *name) 13813 { 13814 scf_snapshot_t *snap; 13815 scf_snaplevel_t *level; 13816 13817 lscf_prep_hndl(); 13818 13819 if (cur_inst == NULL) { 13820 semerr(gettext("Instance not selected.\n")); 13821 return; 13822 } 13823 13824 if (cur_snap != NULL) { 13825 if (name != NULL) { 13826 char *cur_snap_name; 13827 boolean_t nochange; 13828 13829 cur_snap_name = safe_malloc(max_scf_name_len + 1); 13830 13831 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 13832 max_scf_name_len + 1) < 0) 13833 scfdie(); 13834 13835 nochange = strcmp(name, cur_snap_name) == 0; 13836 13837 free(cur_snap_name); 13838 13839 if (nochange) 13840 return; 13841 } 13842 13843 unselect_cursnap(); 13844 } 13845 13846 if (name == NULL) 13847 return; 13848 13849 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13850 (level = scf_snaplevel_create(g_hndl)) == NULL) 13851 scfdie(); 13852 13853 if (scf_instance_get_snapshot(cur_inst, name, snap) != 13854 SCF_SUCCESS) { 13855 switch (scf_error()) { 13856 case SCF_ERROR_INVALID_ARGUMENT: 13857 semerr(gettext("Invalid name \"%s\".\n"), name); 13858 break; 13859 13860 case SCF_ERROR_NOT_FOUND: 13861 semerr(gettext("No such snapshot \"%s\".\n"), name); 13862 break; 13863 13864 default: 13865 scfdie(); 13866 } 13867 13868 scf_snaplevel_destroy(level); 13869 scf_snapshot_destroy(snap); 13870 return; 13871 } 13872 13873 /* Load the snaplevels into our list. */ 13874 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 13875 if (cur_levels == NULL) 13876 uu_die(gettext("Could not create list: %s\n"), 13877 uu_strerror(uu_error())); 13878 13879 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 13880 if (scf_error() != SCF_ERROR_NOT_FOUND) 13881 scfdie(); 13882 13883 semerr(gettext("Snapshot has no snaplevels.\n")); 13884 13885 scf_snaplevel_destroy(level); 13886 scf_snapshot_destroy(snap); 13887 return; 13888 } 13889 13890 cur_snap = snap; 13891 13892 for (;;) { 13893 cur_elt = safe_malloc(sizeof (*cur_elt)); 13894 uu_list_node_init(cur_elt, &cur_elt->list_node, 13895 snaplevel_pool); 13896 cur_elt->sl = level; 13897 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 13898 uu_die(gettext("libuutil error: %s\n"), 13899 uu_strerror(uu_error())); 13900 13901 level = scf_snaplevel_create(g_hndl); 13902 if (level == NULL) 13903 scfdie(); 13904 13905 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 13906 level) != SCF_SUCCESS) { 13907 if (scf_error() != SCF_ERROR_NOT_FOUND) 13908 scfdie(); 13909 13910 scf_snaplevel_destroy(level); 13911 break; 13912 } 13913 } 13914 13915 cur_elt = uu_list_last(cur_levels); 13916 cur_level = cur_elt->sl; 13917 } 13918 13919 /* 13920 * Copies the properties & values in src to dst. Assumes src won't change. 13921 * Returns -1 if permission is denied, -2 if another transaction interrupts, 13922 * and 0 on success. 13923 * 13924 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 13925 * property, if it is copied and has type boolean. (See comment in 13926 * lscf_revert()). 13927 */ 13928 static int 13929 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 13930 uint8_t enabled) 13931 { 13932 scf_transaction_t *tx; 13933 scf_iter_t *iter, *viter; 13934 scf_property_t *prop; 13935 scf_value_t *v; 13936 char *nbuf; 13937 int r; 13938 13939 tx = scf_transaction_create(g_hndl); 13940 if (tx == NULL) 13941 scfdie(); 13942 13943 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 13944 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13945 scfdie(); 13946 13947 scf_transaction_destroy(tx); 13948 13949 return (-1); 13950 } 13951 13952 if ((iter = scf_iter_create(g_hndl)) == NULL || 13953 (prop = scf_property_create(g_hndl)) == NULL || 13954 (viter = scf_iter_create(g_hndl)) == NULL) 13955 scfdie(); 13956 13957 nbuf = safe_malloc(max_scf_name_len + 1); 13958 13959 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 13960 scfdie(); 13961 13962 for (;;) { 13963 scf_transaction_entry_t *e; 13964 scf_type_t ty; 13965 13966 r = scf_iter_next_property(iter, prop); 13967 if (r == -1) 13968 scfdie(); 13969 if (r == 0) 13970 break; 13971 13972 e = scf_entry_create(g_hndl); 13973 if (e == NULL) 13974 scfdie(); 13975 13976 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 13977 scfdie(); 13978 13979 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 13980 scfdie(); 13981 13982 if (scf_transaction_property_new(tx, e, nbuf, 13983 ty) != SCF_SUCCESS) 13984 scfdie(); 13985 13986 if ((enabled == 0 || enabled == 1) && 13987 strcmp(nbuf, scf_property_enabled) == 0 && 13988 ty == SCF_TYPE_BOOLEAN) { 13989 v = scf_value_create(g_hndl); 13990 if (v == NULL) 13991 scfdie(); 13992 13993 scf_value_set_boolean(v, enabled); 13994 13995 if (scf_entry_add_value(e, v) != 0) 13996 scfdie(); 13997 } else { 13998 if (scf_iter_property_values(viter, prop) != 0) 13999 scfdie(); 14000 14001 for (;;) { 14002 v = scf_value_create(g_hndl); 14003 if (v == NULL) 14004 scfdie(); 14005 14006 r = scf_iter_next_value(viter, v); 14007 if (r == -1) 14008 scfdie(); 14009 if (r == 0) { 14010 scf_value_destroy(v); 14011 break; 14012 } 14013 14014 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 14015 scfdie(); 14016 } 14017 } 14018 } 14019 14020 free(nbuf); 14021 scf_iter_destroy(viter); 14022 scf_property_destroy(prop); 14023 scf_iter_destroy(iter); 14024 14025 r = scf_transaction_commit(tx); 14026 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 14027 scfdie(); 14028 14029 scf_transaction_destroy_children(tx); 14030 scf_transaction_destroy(tx); 14031 14032 switch (r) { 14033 case 1: return (0); 14034 case 0: return (-2); 14035 case -1: return (-1); 14036 14037 default: 14038 abort(); 14039 } 14040 14041 /* NOTREACHED */ 14042 } 14043 14044 void 14045 lscf_revert(const char *snapname) 14046 { 14047 scf_snapshot_t *snap, *prev; 14048 scf_snaplevel_t *level, *nlevel; 14049 scf_iter_t *iter; 14050 scf_propertygroup_t *pg, *npg; 14051 scf_property_t *prop; 14052 scf_value_t *val; 14053 char *nbuf, *tbuf; 14054 uint8_t enabled; 14055 14056 lscf_prep_hndl(); 14057 14058 if (cur_inst == NULL) { 14059 semerr(gettext("Instance not selected.\n")); 14060 return; 14061 } 14062 14063 if (snapname != NULL) { 14064 snap = scf_snapshot_create(g_hndl); 14065 if (snap == NULL) 14066 scfdie(); 14067 14068 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 14069 SCF_SUCCESS) { 14070 switch (scf_error()) { 14071 case SCF_ERROR_INVALID_ARGUMENT: 14072 semerr(gettext("Invalid snapshot name " 14073 "\"%s\".\n"), snapname); 14074 break; 14075 14076 case SCF_ERROR_NOT_FOUND: 14077 semerr(gettext("No such snapshot.\n")); 14078 break; 14079 14080 default: 14081 scfdie(); 14082 } 14083 14084 scf_snapshot_destroy(snap); 14085 return; 14086 } 14087 } else { 14088 if (cur_snap != NULL) { 14089 snap = cur_snap; 14090 } else { 14091 semerr(gettext("No snapshot selected.\n")); 14092 return; 14093 } 14094 } 14095 14096 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 14097 (level = scf_snaplevel_create(g_hndl)) == NULL || 14098 (iter = scf_iter_create(g_hndl)) == NULL || 14099 (pg = scf_pg_create(g_hndl)) == NULL || 14100 (npg = scf_pg_create(g_hndl)) == NULL || 14101 (prop = scf_property_create(g_hndl)) == NULL || 14102 (val = scf_value_create(g_hndl)) == NULL) 14103 scfdie(); 14104 14105 nbuf = safe_malloc(max_scf_name_len + 1); 14106 tbuf = safe_malloc(max_scf_pg_type_len + 1); 14107 14108 /* Take the "previous" snapshot before we blow away the properties. */ 14109 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 14110 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 14111 scfdie(); 14112 } else { 14113 if (scf_error() != SCF_ERROR_NOT_FOUND) 14114 scfdie(); 14115 14116 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 14117 scfdie(); 14118 } 14119 14120 /* Save general/enabled, since we're probably going to replace it. */ 14121 enabled = 2; 14122 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 14123 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 14124 scf_property_get_value(prop, val) == 0) 14125 (void) scf_value_get_boolean(val, &enabled); 14126 14127 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 14128 if (scf_error() != SCF_ERROR_NOT_FOUND) 14129 scfdie(); 14130 14131 goto out; 14132 } 14133 14134 for (;;) { 14135 boolean_t isinst; 14136 uint32_t flags; 14137 int r; 14138 14139 /* Clear the properties from the corresponding entity. */ 14140 isinst = snaplevel_is_instance(level); 14141 14142 if (!isinst) 14143 r = scf_iter_service_pgs(iter, cur_svc); 14144 else 14145 r = scf_iter_instance_pgs(iter, cur_inst); 14146 if (r != SCF_SUCCESS) 14147 scfdie(); 14148 14149 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 14150 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 14151 scfdie(); 14152 14153 /* Skip nonpersistent pgs. */ 14154 if (flags & SCF_PG_FLAG_NONPERSISTENT) 14155 continue; 14156 14157 if (scf_pg_delete(pg) != SCF_SUCCESS) { 14158 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14159 scfdie(); 14160 14161 semerr(emsg_permission_denied); 14162 goto out; 14163 } 14164 } 14165 if (r == -1) 14166 scfdie(); 14167 14168 /* Copy the properties to the corresponding entity. */ 14169 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 14170 scfdie(); 14171 14172 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 14173 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 14174 scfdie(); 14175 14176 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 14177 0) 14178 scfdie(); 14179 14180 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 14181 scfdie(); 14182 14183 if (!isinst) 14184 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 14185 flags, npg); 14186 else 14187 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 14188 flags, npg); 14189 if (r != SCF_SUCCESS) { 14190 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 14191 scfdie(); 14192 14193 semerr(emsg_permission_denied); 14194 goto out; 14195 } 14196 14197 if ((enabled == 0 || enabled == 1) && 14198 strcmp(nbuf, scf_pg_general) == 0) 14199 r = pg_copy(pg, npg, enabled); 14200 else 14201 r = pg_copy(pg, npg, 2); 14202 14203 switch (r) { 14204 case 0: 14205 break; 14206 14207 case -1: 14208 semerr(emsg_permission_denied); 14209 goto out; 14210 14211 case -2: 14212 semerr(gettext( 14213 "Interrupted by another change.\n")); 14214 goto out; 14215 14216 default: 14217 abort(); 14218 } 14219 } 14220 if (r == -1) 14221 scfdie(); 14222 14223 /* Get next level. */ 14224 nlevel = scf_snaplevel_create(g_hndl); 14225 if (nlevel == NULL) 14226 scfdie(); 14227 14228 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 14229 SCF_SUCCESS) { 14230 if (scf_error() != SCF_ERROR_NOT_FOUND) 14231 scfdie(); 14232 14233 scf_snaplevel_destroy(nlevel); 14234 break; 14235 } 14236 14237 scf_snaplevel_destroy(level); 14238 level = nlevel; 14239 } 14240 14241 if (snapname == NULL) { 14242 lscf_selectsnap(NULL); 14243 snap = NULL; /* cur_snap has been destroyed */ 14244 } 14245 14246 out: 14247 free(tbuf); 14248 free(nbuf); 14249 scf_value_destroy(val); 14250 scf_property_destroy(prop); 14251 scf_pg_destroy(npg); 14252 scf_pg_destroy(pg); 14253 scf_iter_destroy(iter); 14254 scf_snaplevel_destroy(level); 14255 scf_snapshot_destroy(prev); 14256 if (snap != cur_snap) 14257 scf_snapshot_destroy(snap); 14258 } 14259 14260 void 14261 lscf_refresh(void) 14262 { 14263 ssize_t fmrilen; 14264 size_t bufsz; 14265 char *fmribuf; 14266 int r; 14267 14268 lscf_prep_hndl(); 14269 14270 if (cur_inst == NULL) { 14271 semerr(gettext("Instance not selected.\n")); 14272 return; 14273 } 14274 14275 bufsz = max_scf_fmri_len + 1; 14276 fmribuf = safe_malloc(bufsz); 14277 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 14278 if (fmrilen < 0) { 14279 free(fmribuf); 14280 if (scf_error() != SCF_ERROR_DELETED) 14281 scfdie(); 14282 scf_instance_destroy(cur_inst); 14283 cur_inst = NULL; 14284 warn(emsg_deleted); 14285 return; 14286 } 14287 assert(fmrilen < bufsz); 14288 14289 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 14290 switch (r) { 14291 case 0: 14292 break; 14293 14294 case ECONNABORTED: 14295 warn(gettext("Could not refresh %s " 14296 "(repository connection broken).\n"), fmribuf); 14297 break; 14298 14299 case ECANCELED: 14300 warn(emsg_deleted); 14301 break; 14302 14303 case EPERM: 14304 warn(gettext("Could not refresh %s " 14305 "(permission denied).\n"), fmribuf); 14306 break; 14307 14308 case ENOSPC: 14309 warn(gettext("Could not refresh %s " 14310 "(repository server out of resources).\n"), 14311 fmribuf); 14312 break; 14313 14314 case EACCES: 14315 default: 14316 bad_error("refresh_entity", scf_error()); 14317 } 14318 14319 free(fmribuf); 14320 } 14321 14322 /* 14323 * describe [-v] [-t] [pg/prop] 14324 */ 14325 int 14326 lscf_describe(uu_list_t *args, int hasargs) 14327 { 14328 int ret = 0; 14329 size_t i; 14330 int argc; 14331 char **argv = NULL; 14332 string_list_t *slp; 14333 int do_verbose = 0; 14334 int do_templates = 0; 14335 char *pattern = NULL; 14336 14337 lscf_prep_hndl(); 14338 14339 if (hasargs != 0) { 14340 argc = uu_list_numnodes(args); 14341 if (argc < 1) 14342 goto usage; 14343 14344 argv = calloc(argc + 1, sizeof (char *)); 14345 if (argv == NULL) 14346 uu_die(gettext("Out of memory.\n")); 14347 14348 for (slp = uu_list_first(args), i = 0; 14349 slp != NULL; 14350 slp = uu_list_next(args, slp), ++i) 14351 argv[i] = slp->str; 14352 14353 argv[i] = NULL; 14354 14355 /* 14356 * We start optind = 0 because our list of arguments 14357 * starts at argv[0] 14358 */ 14359 optind = 0; 14360 opterr = 0; 14361 for (;;) { 14362 ret = getopt(argc, argv, "vt"); 14363 if (ret == -1) 14364 break; 14365 14366 switch (ret) { 14367 case 'v': 14368 do_verbose = 1; 14369 break; 14370 14371 case 't': 14372 do_templates = 1; 14373 break; 14374 14375 case '?': 14376 goto usage; 14377 14378 default: 14379 bad_error("getopt", ret); 14380 } 14381 } 14382 14383 pattern = argv[optind]; 14384 } 14385 14386 if (cur_inst == NULL && cur_svc == NULL) { 14387 semerr(emsg_entity_not_selected); 14388 ret = -1; 14389 goto out; 14390 } 14391 14392 /* 14393 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 14394 * output if their last parameter is set to 2. Less information is 14395 * produced if the parameter is set to 1. 14396 */ 14397 if (pattern == NULL) { 14398 if (do_verbose == 1) 14399 list_entity_tmpl(2); 14400 else 14401 list_entity_tmpl(1); 14402 } 14403 14404 if (do_templates == 0) { 14405 if (do_verbose == 1) 14406 listprop(pattern, 0, 2); 14407 else 14408 listprop(pattern, 0, 1); 14409 } else { 14410 if (do_verbose == 1) 14411 listtmpl(pattern, 2); 14412 else 14413 listtmpl(pattern, 1); 14414 } 14415 14416 ret = 0; 14417 out: 14418 if (argv != NULL) 14419 free(argv); 14420 return (ret); 14421 usage: 14422 ret = -2; 14423 goto out; 14424 } 14425 14426 /* 14427 * Creates a list of instance name strings associated with a service. If 14428 * wohandcrafted flag is set, get only instances that have a last-import 14429 * snapshot, instances that were imported via svccfg. 14430 */ 14431 static uu_list_t * 14432 create_instance_list(scf_service_t *svc, int wohandcrafted) 14433 { 14434 scf_snapshot_t *snap = NULL; 14435 scf_instance_t *inst; 14436 scf_iter_t *inst_iter; 14437 uu_list_t *instances; 14438 char *instname; 14439 int r; 14440 14441 inst_iter = scf_iter_create(g_hndl); 14442 inst = scf_instance_create(g_hndl); 14443 if (inst_iter == NULL || inst == NULL) { 14444 uu_warn(gettext("Could not create instance or iterator\n")); 14445 scfdie(); 14446 } 14447 14448 if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL) 14449 return (instances); 14450 14451 if (scf_iter_service_instances(inst_iter, svc) != 0) { 14452 switch (scf_error()) { 14453 case SCF_ERROR_CONNECTION_BROKEN: 14454 case SCF_ERROR_DELETED: 14455 uu_list_destroy(instances); 14456 instances = NULL; 14457 goto out; 14458 14459 case SCF_ERROR_HANDLE_MISMATCH: 14460 case SCF_ERROR_NOT_BOUND: 14461 case SCF_ERROR_NOT_SET: 14462 default: 14463 bad_error("scf_iter_service_instances", scf_error()); 14464 } 14465 } 14466 14467 instname = safe_malloc(max_scf_name_len + 1); 14468 while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) { 14469 if (r == -1) { 14470 (void) uu_warn(gettext("Unable to iterate through " 14471 "instances to create instance list : %s\n"), 14472 scf_strerror(scf_error())); 14473 14474 uu_list_destroy(instances); 14475 instances = NULL; 14476 goto out; 14477 } 14478 14479 /* 14480 * If the instance does not have a last-import snapshot 14481 * then do not add it to the list as it is a hand-crafted 14482 * instance that should not be managed. 14483 */ 14484 if (wohandcrafted) { 14485 if (snap == NULL && 14486 (snap = scf_snapshot_create(g_hndl)) == NULL) { 14487 uu_warn(gettext("Unable to create snapshot " 14488 "entity\n")); 14489 scfdie(); 14490 } 14491 14492 if (scf_instance_get_snapshot(inst, 14493 snap_lastimport, snap) != 0) { 14494 switch (scf_error()) { 14495 case SCF_ERROR_NOT_FOUND : 14496 case SCF_ERROR_DELETED: 14497 continue; 14498 14499 case SCF_ERROR_CONNECTION_BROKEN: 14500 uu_list_destroy(instances); 14501 instances = NULL; 14502 goto out; 14503 14504 case SCF_ERROR_HANDLE_MISMATCH: 14505 case SCF_ERROR_NOT_BOUND: 14506 case SCF_ERROR_NOT_SET: 14507 default: 14508 bad_error("scf_iter_service_instances", 14509 scf_error()); 14510 } 14511 } 14512 } 14513 14514 if (scf_instance_get_name(inst, instname, 14515 max_scf_name_len + 1) < 0) { 14516 switch (scf_error()) { 14517 case SCF_ERROR_NOT_FOUND : 14518 continue; 14519 14520 case SCF_ERROR_CONNECTION_BROKEN: 14521 case SCF_ERROR_DELETED: 14522 uu_list_destroy(instances); 14523 instances = NULL; 14524 goto out; 14525 14526 case SCF_ERROR_HANDLE_MISMATCH: 14527 case SCF_ERROR_NOT_BOUND: 14528 case SCF_ERROR_NOT_SET: 14529 default: 14530 bad_error("scf_iter_service_instances", 14531 scf_error()); 14532 } 14533 } 14534 14535 add_string(instances, instname); 14536 } 14537 14538 out: 14539 if (snap) 14540 scf_snapshot_destroy(snap); 14541 14542 scf_instance_destroy(inst); 14543 scf_iter_destroy(inst_iter); 14544 free(instname); 14545 return (instances); 14546 } 14547 14548 /* 14549 * disable an instance but wait for the instance to 14550 * move out of the running state. 14551 * 14552 * Returns 0 : if the instance did not disable 14553 * Returns non-zero : if the instance disabled. 14554 * 14555 */ 14556 static int 14557 disable_instance(scf_instance_t *instance) 14558 { 14559 char *fmribuf; 14560 int enabled = 10000; 14561 14562 if (inst_is_running(instance)) { 14563 fmribuf = safe_malloc(max_scf_name_len + 1); 14564 if (scf_instance_to_fmri(instance, fmribuf, 14565 max_scf_name_len + 1) < 0) { 14566 free(fmribuf); 14567 return (0); 14568 } 14569 14570 /* 14571 * If the instance cannot be disabled then return 14572 * failure to disable and let the caller decide 14573 * if that is of importance. 14574 */ 14575 if (smf_disable_instance(fmribuf, 0) != 0) { 14576 free(fmribuf); 14577 return (0); 14578 } 14579 14580 while (enabled) { 14581 if (!inst_is_running(instance)) 14582 break; 14583 14584 (void) poll(NULL, 0, 5); 14585 enabled = enabled - 5; 14586 } 14587 14588 free(fmribuf); 14589 } 14590 14591 return (enabled); 14592 } 14593 14594 /* 14595 * Function to compare two service_manifest structures. 14596 */ 14597 /* ARGSUSED2 */ 14598 static int 14599 service_manifest_compare(const void *left, const void *right, void *unused) 14600 { 14601 service_manifest_t *l = (service_manifest_t *)left; 14602 service_manifest_t *r = (service_manifest_t *)right; 14603 int rc; 14604 14605 rc = strcmp(l->servicename, r->servicename); 14606 14607 return (rc); 14608 } 14609 14610 /* 14611 * Look for the provided service in the service to manifest 14612 * tree. If the service exists, and a manifest was provided 14613 * then add the manifest to that service. If the service 14614 * does not exist, then add the service and manifest to the 14615 * list. 14616 * 14617 * If the manifest is NULL, return the element if found. If 14618 * the service is not found return NULL. 14619 */ 14620 service_manifest_t * 14621 find_add_svc_mfst(const char *svnbuf, const char *mfst) 14622 { 14623 service_manifest_t elem; 14624 service_manifest_t *fnelem; 14625 uu_avl_index_t marker; 14626 14627 elem.servicename = svnbuf; 14628 fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker); 14629 14630 if (mfst) { 14631 if (fnelem) { 14632 add_string(fnelem->mfstlist, strdup(mfst)); 14633 } else { 14634 fnelem = safe_malloc(sizeof (*fnelem)); 14635 fnelem->servicename = safe_strdup(svnbuf); 14636 if ((fnelem->mfstlist = 14637 uu_list_create(string_pool, NULL, 0)) == NULL) 14638 uu_die(gettext("Could not create property " 14639 "list: %s\n"), uu_strerror(uu_error())); 14640 14641 add_string(fnelem->mfstlist, safe_strdup(mfst)); 14642 14643 uu_avl_insert(service_manifest_tree, fnelem, marker); 14644 } 14645 } 14646 14647 return (fnelem); 14648 } 14649 14650 /* 14651 * Create the service to manifest avl tree. 14652 * 14653 * Walk each of the manifests currently installed in the supported 14654 * directories, /lib/svc/manifests and /var/svc/manifests. For 14655 * each of the manifests, inventory the services and add them to 14656 * the tree. 14657 * 14658 * Code that calls this function should make sure fileystem/minimal is online, 14659 * /var is available, since this function walks the /var/svc/manifest directory. 14660 */ 14661 static void 14662 create_manifest_tree(void) 14663 { 14664 manifest_info_t **entry; 14665 manifest_info_t **manifests; 14666 uu_list_walk_t *svcs; 14667 bundle_t *b; 14668 entity_t *mfsvc; 14669 char *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL}; 14670 int c, status; 14671 14672 if (service_manifest_pool) 14673 return; 14674 14675 /* 14676 * Create the list pool for the service manifest list 14677 */ 14678 service_manifest_pool = uu_avl_pool_create("service_manifest", 14679 sizeof (service_manifest_t), 14680 offsetof(service_manifest_t, svcmfst_node), 14681 service_manifest_compare, UU_DEFAULT); 14682 if (service_manifest_pool == NULL) 14683 uu_die(gettext("service_manifest pool creation failed: %s\n"), 14684 uu_strerror(uu_error())); 14685 14686 /* 14687 * Create the list 14688 */ 14689 service_manifest_tree = uu_avl_create(service_manifest_pool, NULL, 14690 UU_DEFAULT); 14691 if (service_manifest_tree == NULL) 14692 uu_die(gettext("service_manifest tree creation failed: %s\n"), 14693 uu_strerror(uu_error())); 14694 14695 /* 14696 * Walk the manifests adding the service(s) from each manifest. 14697 * 14698 * If a service already exists add the manifest to the manifest 14699 * list for that service. This covers the case of a service that 14700 * is supported by multiple manifest files. 14701 */ 14702 for (c = 0; dirs[c]; c++) { 14703 status = find_manifests(dirs[c], &manifests, CHECKEXT); 14704 if (status < 0) { 14705 uu_warn(gettext("file tree walk of %s encountered " 14706 "error %s\n"), dirs[c], strerror(errno)); 14707 14708 uu_avl_destroy(service_manifest_tree); 14709 service_manifest_tree = NULL; 14710 return; 14711 } 14712 14713 /* 14714 * If a manifest that was in the list is not found 14715 * then skip and go to the next manifest file. 14716 */ 14717 if (manifests != NULL) { 14718 for (entry = manifests; *entry != NULL; entry++) { 14719 b = internal_bundle_new(); 14720 if (lxml_get_bundle_file(b, (*entry)->mi_path, 14721 SVCCFG_OP_IMPORT) != 0) { 14722 internal_bundle_free(b); 14723 continue; 14724 } 14725 14726 svcs = uu_list_walk_start(b->sc_bundle_services, 14727 0); 14728 if (svcs == NULL) { 14729 internal_bundle_free(b); 14730 continue; 14731 } 14732 14733 while ((mfsvc = uu_list_walk_next(svcs)) != 14734 NULL) { 14735 /* Add manifest to service */ 14736 (void) find_add_svc_mfst(mfsvc->sc_name, 14737 (*entry)->mi_path); 14738 } 14739 14740 uu_list_walk_end(svcs); 14741 internal_bundle_free(b); 14742 } 14743 14744 free_manifest_array(manifests); 14745 } 14746 } 14747 } 14748 14749 /* 14750 * Check the manifest history file to see 14751 * if the service was ever installed from 14752 * one of the supported directories. 14753 * 14754 * Return Values : 14755 * -1 - if there's error reading manifest history file 14756 * 1 - if the service is not found 14757 * 0 - if the service is found 14758 */ 14759 static int 14760 check_mfst_history(const char *svcname) 14761 { 14762 struct stat st; 14763 caddr_t mfsthist_start; 14764 char *svnbuf; 14765 int fd; 14766 int r = 1; 14767 14768 fd = open(MFSTHISTFILE, O_RDONLY); 14769 if (fd == -1) { 14770 uu_warn(gettext("Unable to open the history file\n")); 14771 return (-1); 14772 } 14773 14774 if (fstat(fd, &st) == -1) { 14775 uu_warn(gettext("Unable to stat the history file\n")); 14776 return (-1); 14777 } 14778 14779 mfsthist_start = mmap(0, st.st_size, PROT_READ, 14780 MAP_PRIVATE, fd, 0); 14781 14782 (void) close(fd); 14783 if (mfsthist_start == MAP_FAILED || 14784 *(mfsthist_start + st.st_size) != '\0') { 14785 (void) munmap(mfsthist_start, st.st_size); 14786 return (-1); 14787 } 14788 14789 /* 14790 * The manifest history file is a space delimited list 14791 * of service and instance to manifest linkage. Adding 14792 * a space to the end of the service name so to get only 14793 * the service that is being searched for. 14794 */ 14795 svnbuf = uu_msprintf("%s ", svcname); 14796 if (svnbuf == NULL) 14797 uu_die(gettext("Out of memory")); 14798 14799 if (strstr(mfsthist_start, svnbuf) != NULL) 14800 r = 0; 14801 14802 (void) munmap(mfsthist_start, st.st_size); 14803 uu_free(svnbuf); 14804 return (r); 14805 } 14806 14807 /* 14808 * Take down each of the instances in the service 14809 * and remove them, then delete the service. 14810 */ 14811 static void 14812 teardown_service(scf_service_t *svc, const char *svnbuf) 14813 { 14814 scf_instance_t *instance; 14815 scf_iter_t *iter; 14816 int r; 14817 14818 safe_printf(gettext("Delete service %s as there are no " 14819 "supporting manifests\n"), svnbuf); 14820 14821 instance = scf_instance_create(g_hndl); 14822 iter = scf_iter_create(g_hndl); 14823 if (iter == NULL || instance == NULL) { 14824 uu_warn(gettext("Unable to create supporting entities to " 14825 "teardown the service\n")); 14826 uu_warn(gettext("scf error is : %s\n"), 14827 scf_strerror(scf_error())); 14828 scfdie(); 14829 } 14830 14831 if (scf_iter_service_instances(iter, svc) != 0) { 14832 switch (scf_error()) { 14833 case SCF_ERROR_CONNECTION_BROKEN: 14834 case SCF_ERROR_DELETED: 14835 goto out; 14836 14837 case SCF_ERROR_HANDLE_MISMATCH: 14838 case SCF_ERROR_NOT_BOUND: 14839 case SCF_ERROR_NOT_SET: 14840 default: 14841 bad_error("scf_iter_service_instances", 14842 scf_error()); 14843 } 14844 } 14845 14846 while ((r = scf_iter_next_instance(iter, instance)) != 0) { 14847 if (r == -1) { 14848 uu_warn(gettext("Error - %s\n"), 14849 scf_strerror(scf_error())); 14850 goto out; 14851 } 14852 14853 (void) disable_instance(instance); 14854 } 14855 14856 /* 14857 * Delete the service... forcing the deletion in case 14858 * any of the instances did not disable. 14859 */ 14860 (void) lscf_service_delete(svc, 1); 14861 out: 14862 scf_instance_destroy(instance); 14863 scf_iter_destroy(iter); 14864 } 14865 14866 /* 14867 * Get the list of instances supported by the manifest 14868 * file. 14869 * 14870 * Return 0 if there are no instances. 14871 * 14872 * Return -1 if there are errors attempting to collect instances. 14873 * 14874 * Return the count of instances found if there are no errors. 14875 * 14876 */ 14877 static int 14878 check_instance_support(char *mfstfile, const char *svcname, 14879 uu_list_t *instances) 14880 { 14881 uu_list_walk_t *svcs, *insts; 14882 uu_list_t *ilist; 14883 bundle_t *b; 14884 entity_t *mfsvc, *mfinst; 14885 const char *svcn; 14886 int rminstcnt = 0; 14887 14888 14889 b = internal_bundle_new(); 14890 14891 if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) { 14892 /* 14893 * Unable to process the manifest file for 14894 * instance support, so just return as 14895 * don't want to remove instances that could 14896 * not be accounted for that might exist here. 14897 */ 14898 internal_bundle_free(b); 14899 return (0); 14900 } 14901 14902 svcs = uu_list_walk_start(b->sc_bundle_services, 0); 14903 if (svcs == NULL) { 14904 internal_bundle_free(b); 14905 return (0); 14906 } 14907 14908 svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) + 14909 (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1); 14910 14911 while ((mfsvc = uu_list_walk_next(svcs)) != NULL) { 14912 if (strcmp(mfsvc->sc_name, svcn) == 0) 14913 break; 14914 } 14915 uu_list_walk_end(svcs); 14916 14917 if (mfsvc == NULL) { 14918 internal_bundle_free(b); 14919 return (-1); 14920 } 14921 14922 ilist = mfsvc->sc_u.sc_service.sc_service_instances; 14923 if ((insts = uu_list_walk_start(ilist, 0)) == NULL) { 14924 internal_bundle_free(b); 14925 return (0); 14926 } 14927 14928 while ((mfinst = uu_list_walk_next(insts)) != NULL) { 14929 /* 14930 * Remove the instance from the instances list. 14931 * The unaccounted for instances will be removed 14932 * from the service once all manifests are 14933 * processed. 14934 */ 14935 (void) remove_string(instances, 14936 mfinst->sc_name); 14937 rminstcnt++; 14938 } 14939 14940 uu_list_walk_end(insts); 14941 internal_bundle_free(b); 14942 14943 return (rminstcnt); 14944 } 14945 14946 /* 14947 * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to 14948 * 'false' to indicate there's no manifest file(s) found for the service. 14949 */ 14950 static void 14951 svc_add_no_support(scf_service_t *svc) 14952 { 14953 char *pname; 14954 14955 /* Add no support */ 14956 cur_svc = svc; 14957 if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK)) 14958 return; 14959 14960 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP); 14961 if (pname == NULL) 14962 uu_die(gettext("Out of memory.\n")); 14963 14964 (void) lscf_addpropvalue(pname, "boolean:", "0"); 14965 14966 uu_free(pname); 14967 cur_svc = NULL; 14968 } 14969 14970 /* 14971 * This function handles all upgrade scenarios for a service that doesn't have 14972 * SCF_PG_MANIFESTFILES pg. The function creates and populates 14973 * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to 14974 * manifest(s) mapping. Manifests under supported directories are inventoried 14975 * and a property is added for each file that delivers configuration to the 14976 * service. A service that has no corresponding manifest files (deleted) are 14977 * removed from repository. 14978 * 14979 * Unsupported services: 14980 * 14981 * A service is considered unsupported if there is no corresponding manifest 14982 * in the supported directories for that service and the service isn't in the 14983 * history file list. The history file, MFSTHISTFILE, contains a list of all 14984 * services and instances that were delivered by Solaris before the introduction 14985 * of the SCF_PG_MANIFESTFILES property group. The history file also contains 14986 * the path to the manifest file that defined the service or instance. 14987 * 14988 * Another type of unsupported services is 'handcrafted' services, 14989 * programmatically created services or services created by dependent entries 14990 * in other manifests. A handcrafted service is identified by its lack of any 14991 * instance containing last-import snapshot which is created during svccfg 14992 * import. 14993 * 14994 * This function sets a flag for unsupported services by setting services' 14995 * SCF_PG_MANIFESTFILES/support property to false. 14996 */ 14997 static void 14998 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname) 14999 { 15000 service_manifest_t *elem; 15001 uu_list_walk_t *mfwalk; 15002 string_list_t *mfile; 15003 uu_list_t *instances; 15004 const char *sname; 15005 char *pname; 15006 int r; 15007 15008 /* 15009 * Since there's no guarantee manifests under /var are available during 15010 * early import, don't perform any upgrade during early import. 15011 */ 15012 if (IGNORE_VAR) 15013 return; 15014 15015 if (service_manifest_tree == NULL) { 15016 create_manifest_tree(); 15017 } 15018 15019 /* 15020 * Find service's supporting manifest(s) after 15021 * stripping off the svc:/ prefix that is part 15022 * of the fmri that is not used in the service 15023 * manifest bundle list. 15024 */ 15025 sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) + 15026 strlen(SCF_FMRI_SERVICE_PREFIX); 15027 elem = find_add_svc_mfst(sname, NULL); 15028 if (elem == NULL) { 15029 15030 /* 15031 * A handcrafted service, one that has no instance containing 15032 * last-import snapshot, should get unsupported flag. 15033 */ 15034 instances = create_instance_list(svc, 1); 15035 if (instances == NULL) { 15036 uu_warn(gettext("Unable to create instance list %s\n"), 15037 svcname); 15038 return; 15039 } 15040 15041 if (uu_list_numnodes(instances) == 0) { 15042 svc_add_no_support(svc); 15043 return; 15044 } 15045 15046 /* 15047 * If the service is in the history file, and its supporting 15048 * manifests are not found, we can safely delete the service 15049 * because its manifests are removed from the system. 15050 * 15051 * Services not found in the history file are not delivered by 15052 * Solaris and/or delivered outside supported directories, set 15053 * unsupported flag for these services. 15054 */ 15055 r = check_mfst_history(svcname); 15056 if (r == -1) 15057 return; 15058 15059 if (r) { 15060 /* Set unsupported flag for service */ 15061 svc_add_no_support(svc); 15062 } else { 15063 /* Delete the service */ 15064 teardown_service(svc, svcname); 15065 } 15066 15067 return; 15068 } 15069 15070 /* 15071 * Walk through the list of manifests and add them 15072 * to the service. 15073 * 15074 * Create a manifestfiles pg and add the property. 15075 */ 15076 mfwalk = uu_list_walk_start(elem->mfstlist, 0); 15077 if (mfwalk == NULL) 15078 return; 15079 15080 cur_svc = svc; 15081 r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK); 15082 if (r != 0) { 15083 cur_svc = NULL; 15084 return; 15085 } 15086 15087 while ((mfile = uu_list_walk_next(mfwalk)) != NULL) { 15088 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 15089 mhash_filename_to_propname(mfile->str, 0)); 15090 if (pname == NULL) 15091 uu_die(gettext("Out of memory.\n")); 15092 15093 (void) lscf_addpropvalue(pname, "astring:", mfile->str); 15094 uu_free(pname); 15095 } 15096 uu_list_walk_end(mfwalk); 15097 15098 cur_svc = NULL; 15099 } 15100 15101 /* 15102 * Take a service and process the manifest file entires to see if 15103 * there is continued support for the service and instances. If 15104 * not cleanup as appropriate. 15105 * 15106 * If a service does not have a manifest files entry flag it for 15107 * upgrade and return. 15108 * 15109 * For each manifestfiles property check if the manifest file is 15110 * under the supported /lib/svc/manifest or /var/svc/manifest path 15111 * and if not then return immediately as this service is not supported 15112 * by the cleanup mechanism and should be ignored. 15113 * 15114 * For each manifest file that is supported, check to see if the 15115 * file exists. If not then remove the manifest file property 15116 * from the service and the smf/manifest hash table. If the manifest 15117 * file exists then verify that it supports the instances that are 15118 * part of the service. 15119 * 15120 * Once all manifest files have been accounted for remove any instances 15121 * that are no longer supported in the service. 15122 * 15123 * Return values : 15124 * 0 - Successfully processed the service 15125 * non-zero - failed to process the service 15126 * 15127 * On most errors, will just return to wait and get the next service, 15128 * unless in case of unable to create the needed structures which is 15129 * most likely a fatal error that is not going to be recoverable. 15130 */ 15131 int 15132 lscf_service_cleanup(void *act, scf_walkinfo_t *wip) 15133 { 15134 struct mpg_mfile *mpntov; 15135 struct mpg_mfile **mpvarry = NULL; 15136 scf_service_t *svc; 15137 scf_propertygroup_t *mpg; 15138 scf_property_t *mp; 15139 scf_value_t *mv; 15140 scf_iter_t *mi; 15141 scf_instance_t *instance; 15142 uu_list_walk_t *insts; 15143 uu_list_t *instances = NULL; 15144 boolean_t activity = (boolean_t)act; 15145 char *mpnbuf; 15146 char *mpvbuf; 15147 char *pgpropbuf; 15148 int mfstcnt, rminstct, instct, mfstmax; 15149 int index; 15150 int r = 0; 15151 15152 assert(g_hndl != NULL); 15153 assert(wip->svc != NULL); 15154 assert(wip->fmri != NULL); 15155 15156 svc = wip->svc; 15157 15158 mpg = scf_pg_create(g_hndl); 15159 mp = scf_property_create(g_hndl); 15160 mi = scf_iter_create(g_hndl); 15161 mv = scf_value_create(g_hndl); 15162 instance = scf_instance_create(g_hndl); 15163 15164 if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL || 15165 instance == NULL) { 15166 uu_warn(gettext("Unable to create the supporting entities\n")); 15167 uu_warn(gettext("scf error is : %s\n"), 15168 scf_strerror(scf_error())); 15169 scfdie(); 15170 } 15171 15172 /* 15173 * Get the manifestfiles property group to be parsed for 15174 * files existence. 15175 */ 15176 if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) { 15177 switch (scf_error()) { 15178 case SCF_ERROR_NOT_FOUND: 15179 upgrade_svc_mfst_connection(svc, wip->fmri); 15180 break; 15181 case SCF_ERROR_DELETED: 15182 case SCF_ERROR_CONNECTION_BROKEN: 15183 goto out; 15184 15185 case SCF_ERROR_HANDLE_MISMATCH: 15186 case SCF_ERROR_NOT_BOUND: 15187 case SCF_ERROR_NOT_SET: 15188 default: 15189 bad_error("scf_iter_pg_properties", 15190 scf_error()); 15191 } 15192 15193 goto out; 15194 } 15195 15196 /* 15197 * Iterate through each of the manifestfiles properties 15198 * to determine what manifestfiles are available. 15199 * 15200 * If a manifest file is supported then increment the 15201 * count and therefore the service is safe. 15202 */ 15203 if (scf_iter_pg_properties(mi, mpg) != 0) { 15204 switch (scf_error()) { 15205 case SCF_ERROR_DELETED: 15206 case SCF_ERROR_CONNECTION_BROKEN: 15207 goto out; 15208 15209 case SCF_ERROR_HANDLE_MISMATCH: 15210 case SCF_ERROR_NOT_BOUND: 15211 case SCF_ERROR_NOT_SET: 15212 default: 15213 bad_error("scf_iter_pg_properties", 15214 scf_error()); 15215 } 15216 } 15217 15218 mfstcnt = 0; 15219 mfstmax = MFSTFILE_MAX; 15220 mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX); 15221 while ((r = scf_iter_next_property(mi, mp)) != 0) { 15222 if (r == -1) 15223 bad_error(gettext("Unable to iterate through " 15224 "manifestfiles properties : %s"), 15225 scf_error()); 15226 15227 mpntov = safe_malloc(sizeof (struct mpg_mfile)); 15228 mpnbuf = safe_malloc(max_scf_name_len + 1); 15229 mpvbuf = safe_malloc(max_scf_value_len + 1); 15230 mpntov->mpg = mpnbuf; 15231 mpntov->mfile = mpvbuf; 15232 mpntov->access = 1; 15233 if (scf_property_get_name(mp, mpnbuf, 15234 max_scf_name_len + 1) < 0) { 15235 uu_warn(gettext("Unable to get manifest file " 15236 "property : %s\n"), 15237 scf_strerror(scf_error())); 15238 15239 switch (scf_error()) { 15240 case SCF_ERROR_DELETED: 15241 case SCF_ERROR_CONNECTION_BROKEN: 15242 r = scferror2errno(scf_error()); 15243 goto out_free; 15244 15245 case SCF_ERROR_HANDLE_MISMATCH: 15246 case SCF_ERROR_NOT_BOUND: 15247 case SCF_ERROR_NOT_SET: 15248 default: 15249 bad_error("scf_iter_pg_properties", 15250 scf_error()); 15251 } 15252 } 15253 15254 /* 15255 * The support property is a boolean value that indicates 15256 * if the service is supported for manifest file deletion. 15257 * Currently at this time there is no code that sets this 15258 * value to true. So while we could just let this be caught 15259 * by the support check below, in the future this by be set 15260 * to true and require processing. So for that, go ahead 15261 * and check here, and just return if false. Otherwise, 15262 * fall through expecting that other support checks will 15263 * handle the entries. 15264 */ 15265 if (strcmp(mpnbuf, SUPPORTPROP) == 0) { 15266 uint8_t support; 15267 15268 if (scf_property_get_value(mp, mv) != 0 || 15269 scf_value_get_boolean(mv, &support) != 0) { 15270 uu_warn(gettext("Unable to get the manifest " 15271 "support value: %s\n"), 15272 scf_strerror(scf_error())); 15273 15274 switch (scf_error()) { 15275 case SCF_ERROR_DELETED: 15276 case SCF_ERROR_CONNECTION_BROKEN: 15277 r = scferror2errno(scf_error()); 15278 goto out_free; 15279 15280 case SCF_ERROR_HANDLE_MISMATCH: 15281 case SCF_ERROR_NOT_BOUND: 15282 case SCF_ERROR_NOT_SET: 15283 default: 15284 bad_error("scf_iter_pg_properties", 15285 scf_error()); 15286 } 15287 } 15288 15289 if (support == B_FALSE) 15290 goto out_free; 15291 } 15292 15293 /* 15294 * Anything with a manifest outside of the supported 15295 * directories, immediately bail out because that makes 15296 * this service non-supported. We don't even want 15297 * to do instance processing in this case because the 15298 * instances could be part of the non-supported manifest. 15299 */ 15300 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) { 15301 /* 15302 * Manifest is not in /lib/svc, so we need to 15303 * consider the /var/svc case. 15304 */ 15305 if (strncmp(mpnbuf, VARSVC_PR, 15306 strlen(VARSVC_PR)) != 0 || IGNORE_VAR) { 15307 /* 15308 * Either the manifest is not in /var/svc or 15309 * /var is not yet mounted. We ignore the 15310 * manifest either because it is not in a 15311 * standard location or because we cannot 15312 * currently access the manifest. 15313 */ 15314 goto out_free; 15315 } 15316 } 15317 15318 /* 15319 * Get the value to of the manifest file for this entry 15320 * for access verification and instance support 15321 * verification if it still exists. 15322 * 15323 * During Early Manifest Import if the manifest is in 15324 * /var/svc then it may not yet be available for checking 15325 * so we must determine if /var/svc is available. If not 15326 * then defer until Late Manifest Import to cleanup. 15327 */ 15328 if (scf_property_get_value(mp, mv) != 0) { 15329 uu_warn(gettext("Unable to get the manifest file " 15330 "value: %s\n"), 15331 scf_strerror(scf_error())); 15332 15333 switch (scf_error()) { 15334 case SCF_ERROR_DELETED: 15335 case SCF_ERROR_CONNECTION_BROKEN: 15336 r = scferror2errno(scf_error()); 15337 goto out_free; 15338 15339 case SCF_ERROR_HANDLE_MISMATCH: 15340 case SCF_ERROR_NOT_BOUND: 15341 case SCF_ERROR_NOT_SET: 15342 default: 15343 bad_error("scf_property_get_value", 15344 scf_error()); 15345 } 15346 } 15347 15348 if (scf_value_get_astring(mv, mpvbuf, 15349 max_scf_value_len + 1) < 0) { 15350 uu_warn(gettext("Unable to get the manifest " 15351 "file : %s\n"), 15352 scf_strerror(scf_error())); 15353 15354 switch (scf_error()) { 15355 case SCF_ERROR_DELETED: 15356 case SCF_ERROR_CONNECTION_BROKEN: 15357 r = scferror2errno(scf_error()); 15358 goto out_free; 15359 15360 case SCF_ERROR_HANDLE_MISMATCH: 15361 case SCF_ERROR_NOT_BOUND: 15362 case SCF_ERROR_NOT_SET: 15363 default: 15364 bad_error("scf_value_get_astring", 15365 scf_error()); 15366 } 15367 } 15368 15369 mpvarry[mfstcnt] = mpntov; 15370 mfstcnt++; 15371 15372 /* 15373 * Check for the need to reallocate array 15374 */ 15375 if (mfstcnt >= (mfstmax - 1)) { 15376 struct mpg_mfile **newmpvarry; 15377 15378 mfstmax = mfstmax * 2; 15379 newmpvarry = realloc(mpvarry, 15380 sizeof (struct mpg_mfile *) * mfstmax); 15381 15382 if (newmpvarry == NULL) 15383 goto out_free; 15384 15385 mpvarry = newmpvarry; 15386 } 15387 15388 mpvarry[mfstcnt] = NULL; 15389 } 15390 15391 for (index = 0; mpvarry[index]; index++) { 15392 mpntov = mpvarry[index]; 15393 15394 /* 15395 * Check to see if the manifestfile is accessable, if so hand 15396 * this service and manifestfile off to be processed for 15397 * instance support. 15398 */ 15399 mpnbuf = mpntov->mpg; 15400 mpvbuf = mpntov->mfile; 15401 if (access(mpvbuf, F_OK) != 0) { 15402 mpntov->access = 0; 15403 activity++; 15404 mfstcnt--; 15405 /* Remove the entry from the service */ 15406 cur_svc = svc; 15407 pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, 15408 mpnbuf); 15409 if (pgpropbuf == NULL) 15410 uu_die(gettext("Out of memory.\n")); 15411 15412 lscf_delprop(pgpropbuf); 15413 cur_svc = NULL; 15414 15415 uu_free(pgpropbuf); 15416 } 15417 } 15418 15419 /* 15420 * If mfstcnt is 0, none of the manifests that supported the service 15421 * existed so remove the service. 15422 */ 15423 if (mfstcnt == 0) { 15424 teardown_service(svc, wip->fmri); 15425 15426 goto out_free; 15427 } 15428 15429 if (activity) { 15430 int nosvcsupport = 0; 15431 15432 /* 15433 * If the list of service instances is NULL then 15434 * create the list. 15435 */ 15436 instances = create_instance_list(svc, 1); 15437 if (instances == NULL) { 15438 uu_warn(gettext("Unable to create instance list %s\n"), 15439 wip->fmri); 15440 goto out_free; 15441 } 15442 15443 rminstct = uu_list_numnodes(instances); 15444 instct = rminstct; 15445 15446 for (index = 0; mpvarry[index]; index++) { 15447 mpntov = mpvarry[index]; 15448 if (mpntov->access == 0) 15449 continue; 15450 15451 mpnbuf = mpntov->mpg; 15452 mpvbuf = mpntov->mfile; 15453 r = check_instance_support(mpvbuf, wip->fmri, 15454 instances); 15455 if (r == -1) { 15456 nosvcsupport++; 15457 } else { 15458 rminstct -= r; 15459 } 15460 } 15461 15462 if (instct && instct == rminstct && nosvcsupport == mfstcnt) { 15463 teardown_service(svc, wip->fmri); 15464 15465 goto out_free; 15466 } 15467 } 15468 15469 /* 15470 * If there are instances left on the instance list, then 15471 * we must remove them. 15472 */ 15473 if (instances != NULL && uu_list_numnodes(instances)) { 15474 string_list_t *sp; 15475 15476 insts = uu_list_walk_start(instances, 0); 15477 while ((sp = uu_list_walk_next(insts)) != NULL) { 15478 /* 15479 * Remove the instance from the instances list. 15480 */ 15481 safe_printf(gettext("Delete instance %s from " 15482 "service %s\n"), sp->str, wip->fmri); 15483 if (scf_service_get_instance(svc, sp->str, 15484 instance) != SCF_SUCCESS) { 15485 (void) uu_warn("scf_error - %s\n", 15486 scf_strerror(scf_error())); 15487 15488 continue; 15489 } 15490 15491 (void) disable_instance(instance); 15492 15493 (void) lscf_instance_delete(instance, 1); 15494 } 15495 scf_instance_destroy(instance); 15496 uu_list_walk_end(insts); 15497 } 15498 15499 out_free: 15500 if (mpvarry) { 15501 struct mpg_mfile *fmpntov; 15502 15503 for (index = 0; mpvarry[index]; index++) { 15504 fmpntov = mpvarry[index]; 15505 if (fmpntov->mpg == mpnbuf) 15506 mpnbuf = NULL; 15507 free(fmpntov->mpg); 15508 15509 if (fmpntov->mfile == mpvbuf) 15510 mpvbuf = NULL; 15511 free(fmpntov->mfile); 15512 15513 if (fmpntov == mpntov) 15514 mpntov = NULL; 15515 free(fmpntov); 15516 } 15517 if (mpnbuf) 15518 free(mpnbuf); 15519 if (mpvbuf) 15520 free(mpvbuf); 15521 if (mpntov) 15522 free(mpntov); 15523 15524 free(mpvarry); 15525 } 15526 out: 15527 scf_pg_destroy(mpg); 15528 scf_property_destroy(mp); 15529 scf_iter_destroy(mi); 15530 scf_value_destroy(mv); 15531 15532 return (0); 15533 } 15534 15535 /* 15536 * Take the service and search for the manifestfiles property 15537 * in each of the property groups. If the manifest file 15538 * associated with the property does not exist then remove 15539 * the property group. 15540 */ 15541 int 15542 lscf_hash_cleanup() 15543 { 15544 scf_service_t *svc; 15545 scf_scope_t *scope; 15546 scf_propertygroup_t *pg; 15547 scf_property_t *prop; 15548 scf_value_t *val; 15549 scf_iter_t *iter; 15550 char *pgname; 15551 char *mfile; 15552 int r; 15553 15554 svc = scf_service_create(g_hndl); 15555 scope = scf_scope_create(g_hndl); 15556 pg = scf_pg_create(g_hndl); 15557 prop = scf_property_create(g_hndl); 15558 val = scf_value_create(g_hndl); 15559 iter = scf_iter_create(g_hndl); 15560 if (pg == NULL || prop == NULL || val == NULL || iter == NULL || 15561 svc == NULL || scope == NULL) { 15562 uu_warn(gettext("Unable to create a property group, or " 15563 "property\n")); 15564 uu_warn("%s\n", pg == NULL ? "pg is NULL" : 15565 "pg is not NULL"); 15566 uu_warn("%s\n", prop == NULL ? "prop is NULL" : 15567 "prop is not NULL"); 15568 uu_warn("%s\n", val == NULL ? "val is NULL" : 15569 "val is not NULL"); 15570 uu_warn("%s\n", iter == NULL ? "iter is NULL" : 15571 "iter is not NULL"); 15572 uu_warn("%s\n", svc == NULL ? "svc is NULL" : 15573 "svc is not NULL"); 15574 uu_warn("%s\n", scope == NULL ? "scope is NULL" : 15575 "scope is not NULL"); 15576 uu_warn(gettext("scf error is : %s\n"), 15577 scf_strerror(scf_error())); 15578 scfdie(); 15579 } 15580 15581 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) { 15582 switch (scf_error()) { 15583 case SCF_ERROR_CONNECTION_BROKEN: 15584 case SCF_ERROR_NOT_FOUND: 15585 goto out; 15586 15587 case SCF_ERROR_HANDLE_MISMATCH: 15588 case SCF_ERROR_NOT_BOUND: 15589 case SCF_ERROR_INVALID_ARGUMENT: 15590 default: 15591 bad_error("scf_handle_get_scope", scf_error()); 15592 } 15593 } 15594 15595 if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) { 15596 uu_warn(gettext("Unable to process the hash service, %s\n"), 15597 HASH_SVC); 15598 goto out; 15599 } 15600 15601 pgname = safe_malloc(max_scf_name_len + 1); 15602 mfile = safe_malloc(max_scf_value_len + 1); 15603 15604 if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) { 15605 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"), 15606 scf_strerror(scf_error())); 15607 goto out; 15608 } 15609 15610 while ((r = scf_iter_next_pg(iter, pg)) != 0) { 15611 if (r == -1) 15612 goto out; 15613 15614 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) { 15615 switch (scf_error()) { 15616 case SCF_ERROR_DELETED: 15617 return (ENODEV); 15618 15619 case SCF_ERROR_CONNECTION_BROKEN: 15620 return (ECONNABORTED); 15621 15622 case SCF_ERROR_NOT_SET: 15623 case SCF_ERROR_NOT_BOUND: 15624 default: 15625 bad_error("scf_pg_get_name", scf_error()); 15626 } 15627 } 15628 if (IGNORE_VAR) { 15629 if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0) 15630 continue; 15631 } 15632 15633 /* 15634 * If unable to get the property continue as this is an 15635 * entry that has no location to check against. 15636 */ 15637 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) { 15638 continue; 15639 } 15640 15641 if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 15642 uu_warn(gettext("Unable to get value from %s\n"), 15643 pgname); 15644 goto error_handle; 15645 } 15646 15647 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) == 15648 -1) { 15649 uu_warn(gettext("Unable to get astring from %s : %s\n"), 15650 pgname, scf_strerror(scf_error())); 15651 goto error_handle; 15652 } 15653 15654 if (access(mfile, F_OK) == 0) 15655 continue; 15656 15657 (void) scf_pg_delete(pg); 15658 15659 error_handle: 15660 switch (scf_error()) { 15661 case SCF_ERROR_DELETED: 15662 case SCF_ERROR_CONSTRAINT_VIOLATED: 15663 case SCF_ERROR_NOT_FOUND: 15664 case SCF_ERROR_NOT_SET: 15665 continue; 15666 15667 case SCF_ERROR_CONNECTION_BROKEN: 15668 r = scferror2errno(scf_error()); 15669 goto out; 15670 15671 case SCF_ERROR_HANDLE_MISMATCH: 15672 case SCF_ERROR_NOT_BOUND: 15673 default: 15674 bad_error("scf_value_get_astring", 15675 scf_error()); 15676 } 15677 } 15678 15679 out: 15680 scf_scope_destroy(scope); 15681 scf_service_destroy(svc); 15682 scf_pg_destroy(pg); 15683 scf_property_destroy(prop); 15684 scf_value_destroy(val); 15685 scf_iter_destroy(iter); 15686 free(pgname); 15687 free(mfile); 15688 15689 return (0); 15690 } 15691 15692 #ifndef NATIVE_BUILD 15693 /* ARGSUSED */ 15694 CPL_MATCH_FN(complete_select) 15695 { 15696 const char *arg0, *arg1, *arg1end; 15697 int word_start, err = 0, r; 15698 size_t len; 15699 char *buf; 15700 15701 lscf_prep_hndl(); 15702 15703 arg0 = line + strspn(line, " \t"); 15704 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 15705 15706 arg1 = arg0 + sizeof ("select") - 1; 15707 arg1 += strspn(arg1, " \t"); 15708 word_start = arg1 - line; 15709 15710 arg1end = arg1 + strcspn(arg1, " \t"); 15711 if (arg1end < line + word_end) 15712 return (0); 15713 15714 len = line + word_end - arg1; 15715 15716 buf = safe_malloc(max_scf_name_len + 1); 15717 15718 if (cur_snap != NULL) { 15719 return (0); 15720 } else if (cur_inst != NULL) { 15721 return (0); 15722 } else if (cur_svc != NULL) { 15723 scf_instance_t *inst; 15724 scf_iter_t *iter; 15725 15726 if ((inst = scf_instance_create(g_hndl)) == NULL || 15727 (iter = scf_iter_create(g_hndl)) == NULL) 15728 scfdie(); 15729 15730 if (scf_iter_service_instances(iter, cur_svc) != 0) 15731 scfdie(); 15732 15733 for (;;) { 15734 r = scf_iter_next_instance(iter, inst); 15735 if (r == 0) 15736 break; 15737 if (r != 1) 15738 scfdie(); 15739 15740 if (scf_instance_get_name(inst, buf, 15741 max_scf_name_len + 1) < 0) 15742 scfdie(); 15743 15744 if (strncmp(buf, arg1, len) == 0) { 15745 err = cpl_add_completion(cpl, line, word_start, 15746 word_end, buf + len, "", " "); 15747 if (err != 0) 15748 break; 15749 } 15750 } 15751 15752 scf_iter_destroy(iter); 15753 scf_instance_destroy(inst); 15754 15755 return (err); 15756 } else { 15757 scf_service_t *svc; 15758 scf_iter_t *iter; 15759 15760 assert(cur_scope != NULL); 15761 15762 if ((svc = scf_service_create(g_hndl)) == NULL || 15763 (iter = scf_iter_create(g_hndl)) == NULL) 15764 scfdie(); 15765 15766 if (scf_iter_scope_services(iter, cur_scope) != 0) 15767 scfdie(); 15768 15769 for (;;) { 15770 r = scf_iter_next_service(iter, svc); 15771 if (r == 0) 15772 break; 15773 if (r != 1) 15774 scfdie(); 15775 15776 if (scf_service_get_name(svc, buf, 15777 max_scf_name_len + 1) < 0) 15778 scfdie(); 15779 15780 if (strncmp(buf, arg1, len) == 0) { 15781 err = cpl_add_completion(cpl, line, word_start, 15782 word_end, buf + len, "", " "); 15783 if (err != 0) 15784 break; 15785 } 15786 } 15787 15788 scf_iter_destroy(iter); 15789 scf_service_destroy(svc); 15790 15791 return (err); 15792 } 15793 } 15794 15795 /* ARGSUSED */ 15796 CPL_MATCH_FN(complete_command) 15797 { 15798 uint32_t scope = 0; 15799 15800 if (cur_snap != NULL) 15801 scope = CS_SNAP; 15802 else if (cur_inst != NULL) 15803 scope = CS_INST; 15804 else if (cur_svc != NULL) 15805 scope = CS_SVC; 15806 else 15807 scope = CS_SCOPE; 15808 15809 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 15810 } 15811 #endif /* NATIVE_BUILD */ 15812