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 2009 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 49 #include <libxml/tree.h> 50 51 #include "svccfg.h" 52 #include "manifest_hash.h" 53 54 /* The colon namespaces in each entity (each followed by a newline). */ 55 #define COLON_NAMESPACES ":properties\n" 56 57 #define TEMP_FILE_PATTERN "/tmp/svccfg-XXXXXX" 58 59 /* These are characters which the lexer requires to be in double-quotes. */ 60 #define CHARS_TO_QUOTE " \t\n\\>=\"()" 61 62 #define HASH_SIZE 16 63 #define HASH_SVC "smf/manifest" 64 #define HASH_PG_TYPE "framework" 65 #define HASH_PG_FLAGS 0 66 #define HASH_PROP "md5sum" 67 68 /* 69 * Indentation used in the output of the describe subcommand. 70 */ 71 #define TMPL_VALUE_INDENT " " 72 #define TMPL_INDENT " " 73 #define TMPL_INDENT_2X " " 74 #define TMPL_CHOICE_INDENT " " 75 76 /* 77 * These are the classes of elements which may appear as children of service 78 * or instance elements in XML manifests. 79 */ 80 struct entity_elts { 81 xmlNodePtr create_default_instance; 82 xmlNodePtr single_instance; 83 xmlNodePtr restarter; 84 xmlNodePtr dependencies; 85 xmlNodePtr dependents; 86 xmlNodePtr method_context; 87 xmlNodePtr exec_methods; 88 xmlNodePtr property_groups; 89 xmlNodePtr instances; 90 xmlNodePtr stability; 91 xmlNodePtr template; 92 }; 93 94 /* 95 * Likewise for property_group elements. 96 */ 97 struct pg_elts { 98 xmlNodePtr stability; 99 xmlNodePtr propvals; 100 xmlNodePtr properties; 101 }; 102 103 /* 104 * Likewise for template elements. 105 */ 106 struct template_elts { 107 xmlNodePtr common_name; 108 xmlNodePtr description; 109 xmlNodePtr documentation; 110 }; 111 112 /* 113 * This structure is for snaplevel lists. They are convenient because libscf 114 * only allows traversing snaplevels in one direction. 115 */ 116 struct snaplevel { 117 uu_list_node_t list_node; 118 scf_snaplevel_t *sl; 119 }; 120 121 /* 122 * This is used for communication between lscf_service_export and 123 * export_callback. 124 */ 125 struct export_args { 126 const char *filename; 127 int flags; 128 }; 129 130 const char * const scf_pg_general = SCF_PG_GENERAL; 131 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK; 132 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED; 133 const char * const scf_property_external = "external"; 134 135 const char * const snap_initial = "initial"; 136 const char * const snap_lastimport = "last-import"; 137 const char * const snap_previous = "previous"; 138 const char * const snap_running = "running"; 139 140 scf_handle_t *g_hndl = NULL; /* only valid after lscf_prep_hndl() */ 141 142 ssize_t max_scf_fmri_len; 143 ssize_t max_scf_name_len; 144 ssize_t max_scf_pg_type_len; 145 ssize_t max_scf_value_len; 146 static size_t max_scf_len; 147 148 static scf_scope_t *cur_scope; 149 static scf_service_t *cur_svc = NULL; 150 static scf_instance_t *cur_inst = NULL; 151 static scf_snapshot_t *cur_snap = NULL; 152 static scf_snaplevel_t *cur_level = NULL; 153 154 static uu_list_pool_t *snaplevel_pool; 155 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */ 156 static uu_list_t *cur_levels; 157 static struct snaplevel *cur_elt; /* cur_elt->sl == cur_level */ 158 159 static FILE *tempfile = NULL; 160 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = ""; 161 162 static const char *emsg_entity_not_selected; 163 static const char *emsg_permission_denied; 164 static const char *emsg_create_xml; 165 static const char *emsg_cant_modify_snapshots; 166 static const char *emsg_read_only; 167 static const char *emsg_deleted; 168 static const char *emsg_invalid_pg_name; 169 static const char *emsg_invalid_prop_name; 170 static const char *emsg_no_such_pg; 171 static const char *emsg_fmri_invalid_pg_name; 172 static const char *emsg_fmri_invalid_pg_name_type; 173 static const char *emsg_pg_added; 174 static const char *emsg_pg_changed; 175 static const char *emsg_pg_deleted; 176 static const char *emsg_pg_mod_perm; 177 static const char *emsg_pg_add_perm; 178 static const char *emsg_pg_del_perm; 179 static const char *emsg_snap_perm; 180 static const char *emsg_dpt_dangling; 181 static const char *emsg_dpt_no_dep; 182 183 static int li_only; 184 static int no_refresh = 0; 185 186 /* import globals, to minimize allocations */ 187 static scf_scope_t *imp_scope = NULL; 188 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL; 189 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL; 190 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL; 191 static scf_snapshot_t *imp_rsnap = NULL; 192 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL; 193 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL; 194 static scf_property_t *imp_prop = NULL; 195 static scf_iter_t *imp_iter = NULL; 196 static scf_iter_t *imp_rpg_iter = NULL; 197 static scf_iter_t *imp_up_iter = NULL; 198 static scf_transaction_t *imp_tx = NULL; /* always reset this */ 199 static char *imp_str = NULL; 200 static size_t imp_str_sz; 201 static char *imp_tsname = NULL; 202 static char *imp_fe1 = NULL; /* for fmri_equal() */ 203 static char *imp_fe2 = NULL; 204 static uu_list_t *imp_deleted_dpts = NULL; /* pgroup_t's to refresh */ 205 206 /* upgrade_dependents() globals */ 207 static scf_instance_t *ud_inst = NULL; 208 static scf_snaplevel_t *ud_snpl = NULL; 209 static scf_propertygroup_t *ud_pg = NULL; 210 static scf_propertygroup_t *ud_cur_depts_pg = NULL; 211 static scf_propertygroup_t *ud_run_dpts_pg = NULL; 212 static int ud_run_dpts_pg_set = 0; 213 static scf_property_t *ud_prop = NULL; 214 static scf_property_t *ud_dpt_prop = NULL; 215 static scf_value_t *ud_val = NULL; 216 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL; 217 static scf_transaction_t *ud_tx = NULL; 218 static char *ud_ctarg = NULL; 219 static char *ud_oldtarg = NULL; 220 static char *ud_name = NULL; 221 222 /* export globals */ 223 static scf_instance_t *exp_inst; 224 static scf_propertygroup_t *exp_pg; 225 static scf_property_t *exp_prop; 226 static scf_value_t *exp_val; 227 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter; 228 static char *exp_str; 229 static size_t exp_str_sz; 230 231 static void scfdie_lineno(int lineno) __NORETURN; 232 233 static char *start_method_names[] = { 234 "start", 235 "inetd_start", 236 NULL 237 }; 238 239 static void 240 safe_printf(const char *fmt, ...) 241 { 242 va_list va; 243 244 va_start(va, fmt); 245 if (vprintf(fmt, va) < 0) 246 uu_die(gettext("Error writing to stdout")); 247 va_end(va); 248 } 249 250 /* 251 * For unexpected libscf errors. 252 */ 253 #ifdef NDEBUG 254 255 static void scfdie(void) __NORETURN; 256 257 static void 258 scfdie(void) 259 { 260 scf_error_t err = scf_error(); 261 262 if (err == SCF_ERROR_CONNECTION_BROKEN) 263 uu_die(gettext("Repository connection broken. Exiting.\n")); 264 265 uu_die(gettext("Unexpected fatal libscf error: %s. Exiting.\n"), 266 scf_strerror(err)); 267 } 268 269 #else 270 271 #define scfdie() scfdie_lineno(__LINE__) 272 273 static void 274 scfdie_lineno(int lineno) 275 { 276 scf_error_t err = scf_error(); 277 278 if (err == SCF_ERROR_CONNECTION_BROKEN) 279 uu_die(gettext("Repository connection broken. Exiting.\n")); 280 281 uu_die(gettext("Unexpected libscf error on line %d of " __FILE__ 282 ": %s.\n"), lineno, scf_strerror(err)); 283 } 284 285 #endif 286 287 static void 288 scfwarn(void) 289 { 290 warn(gettext("Unexpected libscf error: %s.\n"), 291 scf_strerror(scf_error())); 292 } 293 294 /* 295 * Clear a field of a structure. 296 */ 297 static int 298 clear_int(void *a, void *b) 299 { 300 /* LINTED */ 301 *(int *)((char *)a + (size_t)b) = 0; 302 303 return (UU_WALK_NEXT); 304 } 305 306 static int 307 scferror2errno(scf_error_t err) 308 { 309 switch (err) { 310 case SCF_ERROR_BACKEND_ACCESS: 311 return (EACCES); 312 313 case SCF_ERROR_BACKEND_READONLY: 314 return (EROFS); 315 316 case SCF_ERROR_CONNECTION_BROKEN: 317 return (ECONNABORTED); 318 319 case SCF_ERROR_CONSTRAINT_VIOLATED: 320 case SCF_ERROR_INVALID_ARGUMENT: 321 return (EINVAL); 322 323 case SCF_ERROR_DELETED: 324 return (ECANCELED); 325 326 case SCF_ERROR_EXISTS: 327 return (EEXIST); 328 329 case SCF_ERROR_NO_MEMORY: 330 return (ENOMEM); 331 332 case SCF_ERROR_NO_RESOURCES: 333 return (ENOSPC); 334 335 case SCF_ERROR_NOT_FOUND: 336 return (ENOENT); 337 338 case SCF_ERROR_PERMISSION_DENIED: 339 return (EPERM); 340 341 default: 342 #ifndef NDEBUG 343 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n", 344 __FILE__, __LINE__, err); 345 #else 346 (void) fprintf(stderr, "Unknown libscf error %d.\n", err); 347 #endif 348 abort(); 349 /* NOTREACHED */ 350 } 351 } 352 353 static int 354 entity_get_pg(void *ent, int issvc, const char *name, 355 scf_propertygroup_t *pg) 356 { 357 if (issvc) 358 return (scf_service_get_pg(ent, name, pg)); 359 else 360 return (scf_instance_get_pg(ent, name, pg)); 361 } 362 363 static void 364 entity_destroy(void *ent, int issvc) 365 { 366 if (issvc) 367 scf_service_destroy(ent); 368 else 369 scf_instance_destroy(ent); 370 } 371 372 static int 373 get_pg(const char *pg_name, scf_propertygroup_t *pg) 374 { 375 int ret; 376 377 if (cur_level != NULL) 378 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg); 379 else if (cur_inst != NULL) 380 ret = scf_instance_get_pg(cur_inst, pg_name, pg); 381 else 382 ret = scf_service_get_pg(cur_svc, pg_name, pg); 383 384 return (ret); 385 } 386 387 /* 388 * Find a snaplevel in a snapshot. If get_svc is true, find the service 389 * snaplevel. Otherwise find the instance snaplevel. 390 * 391 * Returns 392 * 0 - success 393 * ECONNABORTED - repository connection broken 394 * ECANCELED - instance containing snap was deleted 395 * ENOENT - snap has no snaplevels 396 * - requested snaplevel not found 397 */ 398 static int 399 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl) 400 { 401 if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) { 402 switch (scf_error()) { 403 case SCF_ERROR_CONNECTION_BROKEN: 404 case SCF_ERROR_DELETED: 405 case SCF_ERROR_NOT_FOUND: 406 return (scferror2errno(scf_error())); 407 408 case SCF_ERROR_HANDLE_MISMATCH: 409 case SCF_ERROR_NOT_BOUND: 410 case SCF_ERROR_NOT_SET: 411 default: 412 bad_error("scf_snapshot_get_base_snaplevel", 413 scf_error()); 414 } 415 } 416 417 for (;;) { 418 ssize_t ssz; 419 420 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0); 421 if (ssz >= 0) { 422 if (!get_svc) 423 return (0); 424 } else { 425 switch (scf_error()) { 426 case SCF_ERROR_CONSTRAINT_VIOLATED: 427 if (get_svc) 428 return (0); 429 break; 430 431 case SCF_ERROR_DELETED: 432 case SCF_ERROR_CONNECTION_BROKEN: 433 return (scferror2errno(scf_error())); 434 435 case SCF_ERROR_NOT_SET: 436 case SCF_ERROR_NOT_BOUND: 437 default: 438 bad_error("scf_snaplevel_get_instance_name", 439 scf_error()); 440 } 441 } 442 443 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) { 444 switch (scf_error()) { 445 case SCF_ERROR_NOT_FOUND: 446 case SCF_ERROR_CONNECTION_BROKEN: 447 case SCF_ERROR_DELETED: 448 return (scferror2errno(scf_error())); 449 450 case SCF_ERROR_HANDLE_MISMATCH: 451 case SCF_ERROR_NOT_BOUND: 452 case SCF_ERROR_NOT_SET: 453 case SCF_ERROR_INVALID_ARGUMENT: 454 default: 455 bad_error("scf_snaplevel_get_next_snaplevel", 456 scf_error()); 457 } 458 } 459 } 460 } 461 462 /* 463 * If issvc is 0, take ent to be a pointer to an scf_instance_t. If it has 464 * a running snapshot, and that snapshot has an instance snaplevel, set pg to 465 * the property group named name in it. If it doesn't have a running 466 * snapshot, set pg to the instance's current property group named name. 467 * 468 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk 469 * its instances. If one has a running snapshot with a service snaplevel, set 470 * pg to the property group named name in it. If no such snaplevel could be 471 * found, set pg to the service's current property group named name. 472 * 473 * iter, inst, snap, and snpl are required scratch objects. 474 * 475 * Returns 476 * 0 - success 477 * ECONNABORTED - repository connection broken 478 * ECANCELED - ent was deleted 479 * ENOENT - no such property group 480 * EINVAL - name is an invalid property group name 481 * EBADF - found running snapshot is missing a snaplevel 482 */ 483 static int 484 entity_get_running_pg(void *ent, int issvc, const char *name, 485 scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst, 486 scf_snapshot_t *snap, scf_snaplevel_t *snpl) 487 { 488 int r; 489 490 if (issvc) { 491 /* Search for an instance with a running snapshot. */ 492 if (scf_iter_service_instances(iter, ent) != 0) { 493 switch (scf_error()) { 494 case SCF_ERROR_DELETED: 495 case SCF_ERROR_CONNECTION_BROKEN: 496 return (scferror2errno(scf_error())); 497 498 case SCF_ERROR_NOT_SET: 499 case SCF_ERROR_NOT_BOUND: 500 case SCF_ERROR_HANDLE_MISMATCH: 501 default: 502 bad_error("scf_iter_service_instances", 503 scf_error()); 504 } 505 } 506 507 for (;;) { 508 r = scf_iter_next_instance(iter, inst); 509 if (r == 0) { 510 if (scf_service_get_pg(ent, name, pg) == 0) 511 return (0); 512 513 switch (scf_error()) { 514 case SCF_ERROR_DELETED: 515 case SCF_ERROR_NOT_FOUND: 516 case SCF_ERROR_INVALID_ARGUMENT: 517 case SCF_ERROR_CONNECTION_BROKEN: 518 return (scferror2errno(scf_error())); 519 520 case SCF_ERROR_NOT_BOUND: 521 case SCF_ERROR_HANDLE_MISMATCH: 522 case SCF_ERROR_NOT_SET: 523 default: 524 bad_error("scf_service_get_pg", 525 scf_error()); 526 } 527 } 528 if (r != 1) { 529 switch (scf_error()) { 530 case SCF_ERROR_DELETED: 531 case SCF_ERROR_CONNECTION_BROKEN: 532 return (scferror2errno(scf_error())); 533 534 case SCF_ERROR_INVALID_ARGUMENT: 535 case SCF_ERROR_NOT_SET: 536 case SCF_ERROR_NOT_BOUND: 537 case SCF_ERROR_HANDLE_MISMATCH: 538 default: 539 bad_error("scf_iter_next_instance", 540 scf_error()); 541 } 542 } 543 544 if (scf_instance_get_snapshot(inst, snap_running, 545 snap) == 0) 546 break; 547 548 switch (scf_error()) { 549 case SCF_ERROR_NOT_FOUND: 550 case SCF_ERROR_DELETED: 551 continue; 552 553 case SCF_ERROR_CONNECTION_BROKEN: 554 return (ECONNABORTED); 555 556 case SCF_ERROR_HANDLE_MISMATCH: 557 case SCF_ERROR_INVALID_ARGUMENT: 558 case SCF_ERROR_NOT_SET: 559 case SCF_ERROR_NOT_BOUND: 560 default: 561 bad_error("scf_instance_get_snapshot", 562 scf_error()); 563 } 564 } 565 } else { 566 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) { 567 switch (scf_error()) { 568 case SCF_ERROR_NOT_FOUND: 569 break; 570 571 case SCF_ERROR_DELETED: 572 case SCF_ERROR_CONNECTION_BROKEN: 573 return (scferror2errno(scf_error())); 574 575 case SCF_ERROR_NOT_BOUND: 576 case SCF_ERROR_HANDLE_MISMATCH: 577 case SCF_ERROR_INVALID_ARGUMENT: 578 case SCF_ERROR_NOT_SET: 579 default: 580 bad_error("scf_instance_get_snapshot", 581 scf_error()); 582 } 583 584 if (scf_instance_get_pg(ent, name, pg) == 0) 585 return (0); 586 587 switch (scf_error()) { 588 case SCF_ERROR_DELETED: 589 case SCF_ERROR_NOT_FOUND: 590 case SCF_ERROR_INVALID_ARGUMENT: 591 case SCF_ERROR_CONNECTION_BROKEN: 592 return (scferror2errno(scf_error())); 593 594 case SCF_ERROR_NOT_BOUND: 595 case SCF_ERROR_HANDLE_MISMATCH: 596 case SCF_ERROR_NOT_SET: 597 default: 598 bad_error("scf_instance_get_pg", scf_error()); 599 } 600 } 601 } 602 603 r = get_snaplevel(snap, issvc, snpl); 604 switch (r) { 605 case 0: 606 break; 607 608 case ECONNABORTED: 609 case ECANCELED: 610 return (r); 611 612 case ENOENT: 613 return (EBADF); 614 615 default: 616 bad_error("get_snaplevel", r); 617 } 618 619 if (scf_snaplevel_get_pg(snpl, name, pg) == 0) 620 return (0); 621 622 switch (scf_error()) { 623 case SCF_ERROR_DELETED: 624 case SCF_ERROR_INVALID_ARGUMENT: 625 case SCF_ERROR_CONNECTION_BROKEN: 626 case SCF_ERROR_NOT_FOUND: 627 return (scferror2errno(scf_error())); 628 629 case SCF_ERROR_NOT_BOUND: 630 case SCF_ERROR_HANDLE_MISMATCH: 631 case SCF_ERROR_NOT_SET: 632 default: 633 bad_error("scf_snaplevel_get_pg", scf_error()); 634 /* NOTREACHED */ 635 } 636 } 637 638 639 /* 640 * To be registered with atexit(). 641 */ 642 static void 643 remove_tempfile(void) 644 { 645 int ret; 646 647 if (tempfile != NULL) { 648 if (fclose(tempfile) == EOF) 649 warn(gettext("Could not close temporary file")); 650 tempfile = NULL; 651 } 652 653 if (tempfilename[0] != '\0') { 654 do { 655 ret = remove(tempfilename); 656 } while (ret == -1 && errno == EINTR); 657 if (ret == -1) 658 warn(gettext("Could not remove temporary file")); 659 tempfilename[0] = '\0'; 660 } 661 } 662 663 /* 664 * Launch private svc.configd(1M) for manipulating alternate repositories. 665 */ 666 static void 667 start_private_repository(engine_state_t *est) 668 { 669 int fd, stat; 670 struct door_info info; 671 pid_t pid; 672 673 /* 674 * 1. Create a temporary file for the door. 675 */ 676 if (est->sc_repo_doorname != NULL) 677 free((void *)est->sc_repo_doorname); 678 679 est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr"); 680 if (est->sc_repo_doorname == NULL) 681 uu_die(gettext("Could not acquire temporary filename")); 682 683 fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600); 684 if (fd < 0) 685 uu_die(gettext("Could not create temporary file for " 686 "repository server")); 687 688 (void) close(fd); 689 690 /* 691 * 2. Launch a configd with that door, using the specified 692 * repository. 693 */ 694 if ((est->sc_repo_pid = fork()) == 0) { 695 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p", 696 "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename, 697 NULL); 698 uu_die(gettext("Could not execute %s"), est->sc_repo_server); 699 } else if (est->sc_repo_pid == -1) 700 uu_die(gettext("Attempt to fork failed")); 701 702 do { 703 pid = waitpid(est->sc_repo_pid, &stat, 0); 704 } while (pid == -1 && errno == EINTR); 705 706 if (pid == -1) 707 uu_die(gettext("Could not waitpid() for repository server")); 708 709 if (!WIFEXITED(stat)) { 710 uu_die(gettext("Repository server failed (status %d).\n"), 711 stat); 712 } else if (WEXITSTATUS(stat) != 0) { 713 uu_die(gettext("Repository server failed (exit %d).\n"), 714 WEXITSTATUS(stat)); 715 } 716 717 /* 718 * See if it was successful by checking if the door is a door. 719 */ 720 721 fd = open(est->sc_repo_doorname, O_RDWR); 722 if (fd < 0) 723 uu_die(gettext("Could not open door \"%s\""), 724 est->sc_repo_doorname); 725 726 if (door_info(fd, &info) < 0) 727 uu_die(gettext("Unexpected door_info() error")); 728 729 if (close(fd) == -1) 730 warn(gettext("Could not close repository door"), 731 strerror(errno)); 732 733 est->sc_repo_pid = info.di_target; 734 } 735 736 void 737 lscf_cleanup(void) 738 { 739 /* 740 * In the case where we've launched a private svc.configd(1M) 741 * instance, we must terminate our child and remove the temporary 742 * rendezvous point. 743 */ 744 if (est->sc_repo_pid > 0) { 745 (void) kill(est->sc_repo_pid, SIGTERM); 746 (void) waitpid(est->sc_repo_pid, NULL, 0); 747 (void) unlink(est->sc_repo_doorname); 748 749 est->sc_repo_pid = 0; 750 } 751 } 752 753 void 754 unselect_cursnap(void) 755 { 756 void *cookie; 757 758 cur_level = NULL; 759 760 cookie = NULL; 761 while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) { 762 scf_snaplevel_destroy(cur_elt->sl); 763 free(cur_elt); 764 } 765 766 scf_snapshot_destroy(cur_snap); 767 cur_snap = NULL; 768 } 769 770 void 771 lscf_prep_hndl(void) 772 { 773 if (g_hndl != NULL) 774 return; 775 776 g_hndl = scf_handle_create(SCF_VERSION); 777 if (g_hndl == NULL) 778 scfdie(); 779 780 if (est->sc_repo_filename != NULL) 781 start_private_repository(est); 782 783 if (est->sc_repo_doorname != NULL) { 784 scf_value_t *repo_value; 785 int ret; 786 787 repo_value = scf_value_create(g_hndl); 788 if (repo_value == NULL) 789 scfdie(); 790 791 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname); 792 assert(ret == SCF_SUCCESS); 793 794 if (scf_handle_decorate(g_hndl, "door_path", repo_value) != 795 SCF_SUCCESS) 796 scfdie(); 797 798 scf_value_destroy(repo_value); 799 } 800 801 if (scf_handle_bind(g_hndl) != 0) 802 uu_die(gettext("Could not connect to repository server: %s.\n"), 803 scf_strerror(scf_error())); 804 805 cur_scope = scf_scope_create(g_hndl); 806 if (cur_scope == NULL) 807 scfdie(); 808 809 if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0) 810 scfdie(); 811 } 812 813 static void 814 repository_teardown(void) 815 { 816 if (g_hndl != NULL) { 817 if (cur_snap != NULL) 818 unselect_cursnap(); 819 scf_instance_destroy(cur_inst); 820 scf_service_destroy(cur_svc); 821 scf_scope_destroy(cur_scope); 822 scf_handle_destroy(g_hndl); 823 cur_inst = NULL; 824 cur_svc = NULL; 825 cur_scope = NULL; 826 g_hndl = NULL; 827 lscf_cleanup(); 828 } 829 } 830 831 void 832 lscf_set_repository(const char *repfile, int force) 833 { 834 repository_teardown(); 835 836 if (est->sc_repo_filename != NULL) { 837 free((void *)est->sc_repo_filename); 838 est->sc_repo_filename = NULL; 839 } 840 841 if ((force == 0) && (access(repfile, R_OK) != 0)) { 842 /* 843 * Repository file does not exist 844 * or has no read permission. 845 */ 846 warn(gettext("Cannot access \"%s\": %s\n"), 847 repfile, strerror(errno)); 848 } else { 849 est->sc_repo_filename = safe_strdup(repfile); 850 } 851 852 lscf_prep_hndl(); 853 } 854 855 void 856 lscf_init() 857 { 858 if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 || 859 (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 || 860 (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) < 861 0 || 862 (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0) 863 scfdie(); 864 865 max_scf_len = max_scf_fmri_len; 866 if (max_scf_name_len > max_scf_len) 867 max_scf_len = max_scf_name_len; 868 if (max_scf_pg_type_len > max_scf_len) 869 max_scf_len = max_scf_pg_type_len; 870 if (max_scf_value_len > max_scf_len) 871 max_scf_len = max_scf_value_len; 872 873 if (atexit(remove_tempfile) != 0) 874 uu_die(gettext("Could not register atexit() function")); 875 876 emsg_entity_not_selected = gettext("An entity is not selected.\n"); 877 emsg_permission_denied = gettext("Permission denied.\n"); 878 emsg_create_xml = gettext("Could not create XML node.\n"); 879 emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n"); 880 emsg_read_only = gettext("Backend read-only.\n"); 881 emsg_deleted = gettext("Current selection has been deleted.\n"); 882 emsg_invalid_pg_name = 883 gettext("Invalid property group name \"%s\".\n"); 884 emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n"); 885 emsg_no_such_pg = gettext("No such property group \"%s\".\n"); 886 emsg_fmri_invalid_pg_name = gettext("Service %s has property group " 887 "with invalid name \"%s\".\n"); 888 emsg_fmri_invalid_pg_name_type = gettext("Service %s has property " 889 "group with invalid name \"%s\" or type \"%s\".\n"); 890 emsg_pg_added = gettext("%s changed unexpectedly " 891 "(property group \"%s\" added).\n"); 892 emsg_pg_changed = gettext("%s changed unexpectedly " 893 "(property group \"%s\" changed).\n"); 894 emsg_pg_deleted = gettext("%s changed unexpectedly " 895 "(property group \"%s\" or an ancestor was deleted).\n"); 896 emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" " 897 "in %s (permission denied).\n"); 898 emsg_pg_add_perm = gettext("Could not create property group \"%s\" " 899 "in %s (permission denied).\n"); 900 emsg_pg_del_perm = gettext("Could not delete property group \"%s\" " 901 "in %s (permission denied).\n"); 902 emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s " 903 "(permission denied).\n"); 904 emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing " 905 "new dependent \"%s\" because it already exists). Warning: The " 906 "current dependent's target (%s) does not exist.\n"); 907 emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new " 908 "dependent \"%s\" because it already exists). Warning: The " 909 "current dependent's target (%s) does not have a dependency named " 910 "\"%s\" as expected.\n"); 911 912 string_pool = uu_list_pool_create("strings", sizeof (string_list_t), 913 offsetof(string_list_t, node), NULL, 0); 914 snaplevel_pool = uu_list_pool_create("snaplevels", 915 sizeof (struct snaplevel), offsetof(struct snaplevel, list_node), 916 NULL, 0); 917 } 918 919 920 static const char * 921 prop_to_typestr(const scf_property_t *prop) 922 { 923 scf_type_t ty; 924 925 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 926 scfdie(); 927 928 return (scf_type_to_string(ty)); 929 } 930 931 static scf_type_t 932 string_to_type(const char *type) 933 { 934 size_t len = strlen(type); 935 char *buf; 936 937 if (len == 0 || type[len - 1] != ':') 938 return (SCF_TYPE_INVALID); 939 940 buf = (char *)alloca(len + 1); 941 (void) strlcpy(buf, type, len + 1); 942 buf[len - 1] = 0; 943 944 return (scf_string_to_type(buf)); 945 } 946 947 static scf_value_t * 948 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes) 949 { 950 scf_value_t *v; 951 char *dup, *nstr; 952 size_t len; 953 954 v = scf_value_create(g_hndl); 955 if (v == NULL) 956 scfdie(); 957 958 len = strlen(str); 959 if (require_quotes && 960 (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) { 961 semerr(gettext("Multiple string values or string values " 962 "with spaces must be quoted with '\"'.\n")); 963 scf_value_destroy(v); 964 return (NULL); 965 } 966 967 nstr = dup = safe_strdup(str); 968 if (dup[0] == '\"') { 969 /* 970 * Strip out the first and the last quote. 971 */ 972 dup[len - 1] = '\0'; 973 nstr = dup + 1; 974 } 975 976 if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) { 977 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT); 978 semerr(gettext("Invalid \"%s\" value \"%s\".\n"), 979 scf_type_to_string(ty), nstr); 980 scf_value_destroy(v); 981 v = NULL; 982 } 983 free(dup); 984 return (v); 985 } 986 987 /* 988 * Print str to strm, quoting double-quotes and backslashes with backslashes. 989 * Optionally append a comment prefix ('#') to newlines ('\n'). 990 */ 991 static int 992 quote_and_print(const char *str, FILE *strm, int commentnl) 993 { 994 const char *cp; 995 996 for (cp = str; *cp != '\0'; ++cp) { 997 if (*cp == '"' || *cp == '\\') 998 (void) putc('\\', strm); 999 1000 (void) putc(*cp, strm); 1001 1002 if (commentnl && *cp == '\n') { 1003 (void) putc('#', strm); 1004 } 1005 } 1006 1007 return (ferror(strm)); 1008 } 1009 1010 /* 1011 * These wrappers around lowlevel functions provide consistent error checking 1012 * and warnings. 1013 */ 1014 static int 1015 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop) 1016 { 1017 if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS) 1018 return (0); 1019 1020 if (scf_error() != SCF_ERROR_NOT_FOUND) 1021 scfdie(); 1022 1023 if (g_verbose) { 1024 ssize_t len; 1025 char *fmri; 1026 1027 len = scf_pg_to_fmri(pg, NULL, 0); 1028 if (len < 0) 1029 scfdie(); 1030 1031 fmri = safe_malloc(len + 1); 1032 1033 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0) 1034 scfdie(); 1035 1036 warn(gettext("Expected property %s of property group %s is " 1037 "missing.\n"), propname, fmri); 1038 1039 free(fmri); 1040 } 1041 1042 return (-1); 1043 } 1044 1045 static int 1046 prop_check_type(scf_property_t *prop, scf_type_t ty) 1047 { 1048 scf_type_t pty; 1049 1050 if (scf_property_type(prop, &pty) != SCF_SUCCESS) 1051 scfdie(); 1052 1053 if (ty == pty) 1054 return (0); 1055 1056 if (g_verbose) { 1057 ssize_t len; 1058 char *fmri; 1059 const char *tystr; 1060 1061 len = scf_property_to_fmri(prop, NULL, 0); 1062 if (len < 0) 1063 scfdie(); 1064 1065 fmri = safe_malloc(len + 1); 1066 1067 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1068 scfdie(); 1069 1070 tystr = scf_type_to_string(ty); 1071 if (tystr == NULL) 1072 tystr = "?"; 1073 1074 warn(gettext("Property %s is not of expected type %s.\n"), 1075 fmri, tystr); 1076 1077 free(fmri); 1078 } 1079 1080 return (-1); 1081 } 1082 1083 static int 1084 prop_get_val(scf_property_t *prop, scf_value_t *val) 1085 { 1086 scf_error_t err; 1087 1088 if (scf_property_get_value(prop, val) == SCF_SUCCESS) 1089 return (0); 1090 1091 err = scf_error(); 1092 1093 if (err != SCF_ERROR_NOT_FOUND && 1094 err != SCF_ERROR_CONSTRAINT_VIOLATED && 1095 err != SCF_ERROR_PERMISSION_DENIED) 1096 scfdie(); 1097 1098 if (g_verbose) { 1099 ssize_t len; 1100 char *fmri, *emsg; 1101 1102 len = scf_property_to_fmri(prop, NULL, 0); 1103 if (len < 0) 1104 scfdie(); 1105 1106 fmri = safe_malloc(len + 1); 1107 1108 if (scf_property_to_fmri(prop, fmri, len + 1) < 0) 1109 scfdie(); 1110 1111 if (err == SCF_ERROR_NOT_FOUND) 1112 emsg = gettext("Property %s has no values; expected " 1113 "one.\n"); 1114 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED) 1115 emsg = gettext("Property %s has multiple values; " 1116 "expected one.\n"); 1117 else 1118 emsg = gettext("No permission to read property %s.\n"); 1119 1120 warn(emsg, fmri); 1121 1122 free(fmri); 1123 } 1124 1125 return (-1); 1126 } 1127 1128 1129 static boolean_t 1130 snaplevel_is_instance(const scf_snaplevel_t *level) 1131 { 1132 if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) { 1133 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) 1134 scfdie(); 1135 return (0); 1136 } else { 1137 return (1); 1138 } 1139 } 1140 1141 /* 1142 * Decode FMRI into a service or instance, and put the result in *ep. If 1143 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY. If the FMRI is 1144 * invalid, return SCF_ERROR_INVALID_ARGUMENT. If the FMRI does not specify 1145 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED. If the entity cannot be 1146 * found, return SCF_ERROR_NOT_FOUND. Otherwise return SCF_ERROR_NONE, point 1147 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to 1148 * whether *ep is a service. 1149 */ 1150 static scf_error_t 1151 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice) 1152 { 1153 char *fmri_copy; 1154 const char *sstr, *istr, *pgstr; 1155 scf_service_t *svc; 1156 scf_instance_t *inst; 1157 1158 fmri_copy = strdup(fmri); 1159 if (fmri_copy == NULL) 1160 return (SCF_ERROR_NO_MEMORY); 1161 1162 if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) != 1163 SCF_SUCCESS) { 1164 free(fmri_copy); 1165 return (SCF_ERROR_INVALID_ARGUMENT); 1166 } 1167 1168 free(fmri_copy); 1169 1170 if (sstr == NULL || pgstr != NULL) 1171 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1172 1173 if (istr == NULL) { 1174 svc = scf_service_create(h); 1175 if (svc == NULL) 1176 return (SCF_ERROR_NO_MEMORY); 1177 1178 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 1179 SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1180 if (scf_error() != SCF_ERROR_NOT_FOUND) 1181 scfdie(); 1182 1183 return (SCF_ERROR_NOT_FOUND); 1184 } 1185 1186 *ep = svc; 1187 *isservice = 1; 1188 } else { 1189 inst = scf_instance_create(h); 1190 if (inst == NULL) 1191 return (SCF_ERROR_NO_MEMORY); 1192 1193 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 1194 NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) { 1195 if (scf_error() != SCF_ERROR_NOT_FOUND) 1196 scfdie(); 1197 1198 return (SCF_ERROR_NOT_FOUND); 1199 } 1200 1201 *ep = inst; 1202 *isservice = 0; 1203 } 1204 1205 return (SCF_ERROR_NONE); 1206 } 1207 1208 /* 1209 * Create the entity named by fmri. Place a pointer to its libscf handle in 1210 * *ep, and set or clear *isservicep if it is a service or an instance. 1211 * Returns 1212 * SCF_ERROR_NONE - success 1213 * SCF_ERROR_NO_MEMORY - scf_*_create() failed 1214 * SCF_ERROR_INVALID_ARGUMENT - fmri is invalid 1215 * SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance 1216 * SCF_ERROR_NOT_FOUND - no such scope 1217 * SCF_ERROR_PERMISSION_DENIED 1218 * SCF_ERROR_BACKEND_READONLY 1219 * SCF_ERROR_BACKEND_ACCESS 1220 */ 1221 static scf_error_t 1222 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep) 1223 { 1224 char *fmri_copy; 1225 const char *scstr, *sstr, *istr, *pgstr; 1226 scf_scope_t *scope = NULL; 1227 scf_service_t *svc = NULL; 1228 scf_instance_t *inst = NULL; 1229 scf_error_t scfe; 1230 1231 fmri_copy = safe_strdup(fmri); 1232 1233 if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) != 1234 0) { 1235 free(fmri_copy); 1236 return (SCF_ERROR_INVALID_ARGUMENT); 1237 } 1238 1239 if (scstr == NULL || sstr == NULL || pgstr != NULL) { 1240 free(fmri_copy); 1241 return (SCF_ERROR_CONSTRAINT_VIOLATED); 1242 } 1243 1244 *ep = NULL; 1245 1246 if ((scope = scf_scope_create(h)) == NULL || 1247 (svc = scf_service_create(h)) == NULL || 1248 (inst = scf_instance_create(h)) == NULL) { 1249 scfe = SCF_ERROR_NO_MEMORY; 1250 goto out; 1251 } 1252 1253 get_scope: 1254 if (scf_handle_get_scope(h, scstr, scope) != 0) { 1255 switch (scf_error()) { 1256 case SCF_ERROR_CONNECTION_BROKEN: 1257 scfdie(); 1258 /* NOTREACHED */ 1259 1260 case SCF_ERROR_NOT_FOUND: 1261 scfe = SCF_ERROR_NOT_FOUND; 1262 goto out; 1263 1264 case SCF_ERROR_HANDLE_MISMATCH: 1265 case SCF_ERROR_NOT_BOUND: 1266 case SCF_ERROR_INVALID_ARGUMENT: 1267 default: 1268 bad_error("scf_handle_get_scope", scf_error()); 1269 } 1270 } 1271 1272 get_svc: 1273 if (scf_scope_get_service(scope, sstr, svc) != 0) { 1274 switch (scf_error()) { 1275 case SCF_ERROR_CONNECTION_BROKEN: 1276 scfdie(); 1277 /* NOTREACHED */ 1278 1279 case SCF_ERROR_DELETED: 1280 goto get_scope; 1281 1282 case SCF_ERROR_NOT_FOUND: 1283 break; 1284 1285 case SCF_ERROR_HANDLE_MISMATCH: 1286 case SCF_ERROR_INVALID_ARGUMENT: 1287 case SCF_ERROR_NOT_BOUND: 1288 case SCF_ERROR_NOT_SET: 1289 default: 1290 bad_error("scf_scope_get_service", scf_error()); 1291 } 1292 1293 if (scf_scope_add_service(scope, sstr, svc) != 0) { 1294 switch (scf_error()) { 1295 case SCF_ERROR_CONNECTION_BROKEN: 1296 scfdie(); 1297 /* NOTREACHED */ 1298 1299 case SCF_ERROR_DELETED: 1300 goto get_scope; 1301 1302 case SCF_ERROR_PERMISSION_DENIED: 1303 case SCF_ERROR_BACKEND_READONLY: 1304 case SCF_ERROR_BACKEND_ACCESS: 1305 scfe = scf_error(); 1306 goto out; 1307 1308 case SCF_ERROR_HANDLE_MISMATCH: 1309 case SCF_ERROR_INVALID_ARGUMENT: 1310 case SCF_ERROR_NOT_BOUND: 1311 case SCF_ERROR_NOT_SET: 1312 default: 1313 bad_error("scf_scope_get_service", scf_error()); 1314 } 1315 } 1316 } 1317 1318 if (istr == NULL) { 1319 scfe = SCF_ERROR_NONE; 1320 *ep = svc; 1321 *isservicep = 1; 1322 goto out; 1323 } 1324 1325 get_inst: 1326 if (scf_service_get_instance(svc, istr, inst) != 0) { 1327 switch (scf_error()) { 1328 case SCF_ERROR_CONNECTION_BROKEN: 1329 scfdie(); 1330 /* NOTREACHED */ 1331 1332 case SCF_ERROR_DELETED: 1333 goto get_svc; 1334 1335 case SCF_ERROR_NOT_FOUND: 1336 break; 1337 1338 case SCF_ERROR_HANDLE_MISMATCH: 1339 case SCF_ERROR_INVALID_ARGUMENT: 1340 case SCF_ERROR_NOT_BOUND: 1341 case SCF_ERROR_NOT_SET: 1342 default: 1343 bad_error("scf_service_get_instance", scf_error()); 1344 } 1345 1346 if (scf_service_add_instance(svc, istr, inst) != 0) { 1347 switch (scf_error()) { 1348 case SCF_ERROR_CONNECTION_BROKEN: 1349 scfdie(); 1350 /* NOTREACHED */ 1351 1352 case SCF_ERROR_DELETED: 1353 goto get_svc; 1354 1355 case SCF_ERROR_PERMISSION_DENIED: 1356 case SCF_ERROR_BACKEND_READONLY: 1357 case SCF_ERROR_BACKEND_ACCESS: 1358 scfe = scf_error(); 1359 goto out; 1360 1361 case SCF_ERROR_HANDLE_MISMATCH: 1362 case SCF_ERROR_INVALID_ARGUMENT: 1363 case SCF_ERROR_NOT_BOUND: 1364 case SCF_ERROR_NOT_SET: 1365 default: 1366 bad_error("scf_service_add_instance", 1367 scf_error()); 1368 } 1369 } 1370 } 1371 1372 scfe = SCF_ERROR_NONE; 1373 *ep = inst; 1374 *isservicep = 0; 1375 1376 out: 1377 if (*ep != inst) 1378 scf_instance_destroy(inst); 1379 if (*ep != svc) 1380 scf_service_destroy(svc); 1381 scf_scope_destroy(scope); 1382 free(fmri_copy); 1383 return (scfe); 1384 } 1385 1386 /* 1387 * Create or update a snapshot of inst. snap is a required scratch object. 1388 * 1389 * Returns 1390 * 0 - success 1391 * ECONNABORTED - repository connection broken 1392 * EPERM - permission denied 1393 * ENOSPC - configd is out of resources 1394 * ECANCELED - inst was deleted 1395 * -1 - unknown libscf error (message printed) 1396 */ 1397 static int 1398 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap) 1399 { 1400 again: 1401 if (scf_instance_get_snapshot(inst, name, snap) == 0) { 1402 if (_scf_snapshot_take_attach(inst, snap) != 0) { 1403 switch (scf_error()) { 1404 case SCF_ERROR_CONNECTION_BROKEN: 1405 case SCF_ERROR_PERMISSION_DENIED: 1406 case SCF_ERROR_NO_RESOURCES: 1407 return (scferror2errno(scf_error())); 1408 1409 case SCF_ERROR_NOT_SET: 1410 case SCF_ERROR_INVALID_ARGUMENT: 1411 default: 1412 bad_error("_scf_snapshot_take_attach", 1413 scf_error()); 1414 } 1415 } 1416 } else { 1417 switch (scf_error()) { 1418 case SCF_ERROR_NOT_FOUND: 1419 break; 1420 1421 case SCF_ERROR_DELETED: 1422 case SCF_ERROR_CONNECTION_BROKEN: 1423 return (scferror2errno(scf_error())); 1424 1425 case SCF_ERROR_HANDLE_MISMATCH: 1426 case SCF_ERROR_NOT_BOUND: 1427 case SCF_ERROR_INVALID_ARGUMENT: 1428 case SCF_ERROR_NOT_SET: 1429 default: 1430 bad_error("scf_instance_get_snapshot", scf_error()); 1431 } 1432 1433 if (_scf_snapshot_take_new(inst, name, snap) != 0) { 1434 switch (scf_error()) { 1435 case SCF_ERROR_EXISTS: 1436 goto again; 1437 1438 case SCF_ERROR_CONNECTION_BROKEN: 1439 case SCF_ERROR_NO_RESOURCES: 1440 case SCF_ERROR_PERMISSION_DENIED: 1441 return (scferror2errno(scf_error())); 1442 1443 default: 1444 scfwarn(); 1445 return (-1); 1446 1447 case SCF_ERROR_NOT_SET: 1448 case SCF_ERROR_INTERNAL: 1449 case SCF_ERROR_INVALID_ARGUMENT: 1450 case SCF_ERROR_HANDLE_MISMATCH: 1451 bad_error("_scf_snapshot_take_new", 1452 scf_error()); 1453 } 1454 } 1455 } 1456 1457 return (0); 1458 } 1459 1460 static int 1461 refresh_running_snapshot(void *entity) 1462 { 1463 scf_snapshot_t *snap; 1464 int r; 1465 1466 if ((snap = scf_snapshot_create(g_hndl)) == NULL) 1467 scfdie(); 1468 r = take_snap(entity, snap_running, snap); 1469 scf_snapshot_destroy(snap); 1470 1471 return (r); 1472 } 1473 1474 /* 1475 * Refresh entity. If isservice is zero, take entity to be an scf_instance_t *. 1476 * Otherwise take entity to be an scf_service_t * and refresh all of its child 1477 * instances. fmri is used for messages. inst, iter, and name_buf are used 1478 * for scratch space. Returns 1479 * 0 - success 1480 * ECONNABORTED - repository connection broken 1481 * ECANCELED - entity was deleted 1482 * EACCES - backend denied access 1483 * EPERM - permission denied 1484 * ENOSPC - repository server out of resources 1485 * -1 - _smf_refresh_instance_i() failed. scf_error() should be set. 1486 */ 1487 static int 1488 refresh_entity(int isservice, void *entity, const char *fmri, 1489 scf_instance_t *inst, scf_iter_t *iter, char *name_buf) 1490 { 1491 scf_error_t scfe; 1492 int r; 1493 1494 if (!isservice) { 1495 if (est->sc_repo_filename == NULL && 1496 est->sc_repo_doorname == NULL) { 1497 if (_smf_refresh_instance_i(entity) == 0) { 1498 if (g_verbose) 1499 warn(gettext("Refreshed %s.\n"), fmri); 1500 return (0); 1501 } 1502 1503 switch (scf_error()) { 1504 case SCF_ERROR_BACKEND_ACCESS: 1505 return (EACCES); 1506 1507 case SCF_ERROR_PERMISSION_DENIED: 1508 return (EPERM); 1509 1510 default: 1511 return (-1); 1512 } 1513 } else { 1514 r = refresh_running_snapshot(entity); 1515 switch (r) { 1516 case 0: 1517 break; 1518 1519 case ECONNABORTED: 1520 case ECANCELED: 1521 case EPERM: 1522 case ENOSPC: 1523 break; 1524 1525 default: 1526 bad_error("refresh_running_snapshot", 1527 scf_error()); 1528 } 1529 1530 return (r); 1531 } 1532 } 1533 1534 if (scf_iter_service_instances(iter, entity) != 0) { 1535 switch (scf_error()) { 1536 case SCF_ERROR_CONNECTION_BROKEN: 1537 return (ECONNABORTED); 1538 1539 case SCF_ERROR_DELETED: 1540 return (ECANCELED); 1541 1542 case SCF_ERROR_HANDLE_MISMATCH: 1543 case SCF_ERROR_NOT_BOUND: 1544 case SCF_ERROR_NOT_SET: 1545 default: 1546 bad_error("scf_iter_service_instances", scf_error()); 1547 } 1548 } 1549 1550 for (;;) { 1551 r = scf_iter_next_instance(iter, inst); 1552 if (r == 0) 1553 break; 1554 if (r != 1) { 1555 switch (scf_error()) { 1556 case SCF_ERROR_CONNECTION_BROKEN: 1557 return (ECONNABORTED); 1558 1559 case SCF_ERROR_DELETED: 1560 return (ECANCELED); 1561 1562 case SCF_ERROR_HANDLE_MISMATCH: 1563 case SCF_ERROR_NOT_BOUND: 1564 case SCF_ERROR_NOT_SET: 1565 case SCF_ERROR_INVALID_ARGUMENT: 1566 default: 1567 bad_error("scf_iter_next_instance", 1568 scf_error()); 1569 } 1570 } 1571 1572 if (est->sc_repo_filename != NULL || 1573 est->sc_repo_doorname != NULL) { 1574 r = refresh_running_snapshot(inst); 1575 switch (r) { 1576 case 0: 1577 continue; 1578 1579 case ECONNABORTED: 1580 case ECANCELED: 1581 case EPERM: 1582 case ENOSPC: 1583 break; 1584 default: 1585 bad_error("refresh_running_snapshot", 1586 scf_error()); 1587 } 1588 1589 return (r); 1590 1591 } 1592 1593 if (_smf_refresh_instance_i(inst) == 0) { 1594 if (g_verbose) { 1595 if (scf_instance_get_name(inst, name_buf, 1596 max_scf_name_len + 1) < 0) 1597 (void) strcpy(name_buf, "?"); 1598 1599 warn(gettext("Refreshed %s:%s.\n"), 1600 fmri, name_buf); 1601 } 1602 } else { 1603 if (scf_error() != SCF_ERROR_BACKEND_ACCESS || 1604 g_verbose) { 1605 scfe = scf_error(); 1606 1607 if (scf_instance_to_fmri(inst, name_buf, 1608 max_scf_name_len + 1) < 0) 1609 (void) strcpy(name_buf, "?"); 1610 1611 warn(gettext( 1612 "Refresh of %s:%s failed: %s.\n"), fmri, 1613 name_buf, scf_strerror(scfe)); 1614 } 1615 } 1616 } 1617 1618 return (0); 1619 } 1620 1621 static void 1622 private_refresh(void) 1623 { 1624 scf_instance_t *pinst = NULL; 1625 scf_iter_t *piter = NULL; 1626 ssize_t fmrilen; 1627 size_t bufsz; 1628 char *fmribuf; 1629 void *ent; 1630 int issvc; 1631 int r; 1632 1633 if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL) 1634 return; 1635 1636 assert(cur_svc != NULL); 1637 1638 bufsz = max_scf_fmri_len + 1; 1639 fmribuf = safe_malloc(bufsz); 1640 if (cur_inst) { 1641 issvc = 0; 1642 ent = cur_inst; 1643 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz); 1644 } else { 1645 issvc = 1; 1646 ent = cur_svc; 1647 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz); 1648 if ((pinst = scf_instance_create(g_hndl)) == NULL) 1649 scfdie(); 1650 1651 if ((piter = scf_iter_create(g_hndl)) == NULL) 1652 scfdie(); 1653 } 1654 if (fmrilen < 0) { 1655 free(fmribuf); 1656 if (scf_error() != SCF_ERROR_DELETED) 1657 scfdie(); 1658 1659 warn(emsg_deleted); 1660 return; 1661 } 1662 assert(fmrilen < bufsz); 1663 1664 r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL); 1665 switch (r) { 1666 case 0: 1667 break; 1668 1669 case ECONNABORTED: 1670 warn(gettext("Could not refresh %s " 1671 "(repository connection broken).\n"), fmribuf); 1672 break; 1673 1674 case ECANCELED: 1675 warn(emsg_deleted); 1676 break; 1677 1678 case EPERM: 1679 warn(gettext("Could not refresh %s " 1680 "(permission denied).\n"), fmribuf); 1681 break; 1682 1683 case ENOSPC: 1684 warn(gettext("Could not refresh %s " 1685 "(repository server out of resources).\n"), 1686 fmribuf); 1687 break; 1688 1689 case EACCES: 1690 default: 1691 bad_error("refresh_entity", scf_error()); 1692 } 1693 1694 if (issvc) { 1695 scf_instance_destroy(pinst); 1696 scf_iter_destroy(piter); 1697 } 1698 1699 free(fmribuf); 1700 } 1701 1702 1703 static int 1704 stash_scferror_err(scf_callback_t *cbp, scf_error_t err) 1705 { 1706 cbp->sc_err = scferror2errno(err); 1707 return (UU_WALK_ERROR); 1708 } 1709 1710 static int 1711 stash_scferror(scf_callback_t *cbp) 1712 { 1713 return (stash_scferror_err(cbp, scf_error())); 1714 } 1715 1716 /* 1717 * Import. These functions import a bundle into the repository. 1718 */ 1719 1720 /* 1721 * Add a transaction entry to lcbdata->sc_trans for this property_t. Uses 1722 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata. On success, 1723 * returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 1724 * lcbdata->sc_err to 1725 * ENOMEM - out of memory 1726 * ECONNABORTED - repository connection broken 1727 * ECANCELED - sc_trans's property group was deleted 1728 * EINVAL - p's name is invalid (error printed) 1729 * - p has an invalid value (error printed) 1730 */ 1731 static int 1732 lscf_property_import(void *v, void *pvt) 1733 { 1734 property_t *p = v; 1735 scf_callback_t *lcbdata = pvt; 1736 value_t *vp; 1737 scf_transaction_t *trans = lcbdata->sc_trans; 1738 scf_transaction_entry_t *entr; 1739 scf_value_t *val; 1740 scf_type_t tp; 1741 1742 if ((lcbdata->sc_flags & SCI_NOENABLED || 1743 lcbdata->sc_flags & SCI_DELAYENABLE) && 1744 strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) { 1745 lcbdata->sc_enable = p; 1746 return (UU_WALK_NEXT); 1747 } 1748 1749 entr = scf_entry_create(lcbdata->sc_handle); 1750 if (entr == NULL) { 1751 switch (scf_error()) { 1752 case SCF_ERROR_NO_MEMORY: 1753 return (stash_scferror(lcbdata)); 1754 1755 case SCF_ERROR_INVALID_ARGUMENT: 1756 default: 1757 bad_error("scf_entry_create", scf_error()); 1758 } 1759 } 1760 1761 tp = p->sc_value_type; 1762 1763 if (scf_transaction_property_new(trans, entr, 1764 p->sc_property_name, tp) != 0) { 1765 switch (scf_error()) { 1766 case SCF_ERROR_INVALID_ARGUMENT: 1767 semerr(emsg_invalid_prop_name, p->sc_property_name); 1768 scf_entry_destroy(entr); 1769 return (stash_scferror(lcbdata)); 1770 1771 case SCF_ERROR_EXISTS: 1772 break; 1773 1774 case SCF_ERROR_DELETED: 1775 case SCF_ERROR_CONNECTION_BROKEN: 1776 scf_entry_destroy(entr); 1777 return (stash_scferror(lcbdata)); 1778 1779 case SCF_ERROR_NOT_BOUND: 1780 case SCF_ERROR_HANDLE_MISMATCH: 1781 case SCF_ERROR_NOT_SET: 1782 default: 1783 bad_error("scf_transaction_property_new", scf_error()); 1784 } 1785 1786 if (scf_transaction_property_change_type(trans, entr, 1787 p->sc_property_name, tp) != 0) { 1788 switch (scf_error()) { 1789 case SCF_ERROR_DELETED: 1790 case SCF_ERROR_CONNECTION_BROKEN: 1791 scf_entry_destroy(entr); 1792 return (stash_scferror(lcbdata)); 1793 1794 case SCF_ERROR_INVALID_ARGUMENT: 1795 semerr(emsg_invalid_prop_name, 1796 p->sc_property_name); 1797 scf_entry_destroy(entr); 1798 return (stash_scferror(lcbdata)); 1799 1800 case SCF_ERROR_NOT_FOUND: 1801 case SCF_ERROR_NOT_SET: 1802 case SCF_ERROR_HANDLE_MISMATCH: 1803 case SCF_ERROR_NOT_BOUND: 1804 default: 1805 bad_error( 1806 "scf_transaction_property_change_type", 1807 scf_error()); 1808 } 1809 } 1810 } 1811 1812 for (vp = uu_list_first(p->sc_property_values); 1813 vp != NULL; 1814 vp = uu_list_next(p->sc_property_values, vp)) { 1815 val = scf_value_create(g_hndl); 1816 if (val == NULL) { 1817 switch (scf_error()) { 1818 case SCF_ERROR_NO_MEMORY: 1819 return (stash_scferror(lcbdata)); 1820 1821 case SCF_ERROR_INVALID_ARGUMENT: 1822 default: 1823 bad_error("scf_value_create", scf_error()); 1824 } 1825 } 1826 1827 switch (tp) { 1828 case SCF_TYPE_BOOLEAN: 1829 scf_value_set_boolean(val, vp->sc_u.sc_count); 1830 break; 1831 case SCF_TYPE_COUNT: 1832 scf_value_set_count(val, vp->sc_u.sc_count); 1833 break; 1834 case SCF_TYPE_INTEGER: 1835 scf_value_set_integer(val, vp->sc_u.sc_integer); 1836 break; 1837 default: 1838 assert(vp->sc_u.sc_string != NULL); 1839 if (scf_value_set_from_string(val, tp, 1840 vp->sc_u.sc_string) != 0) { 1841 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT) 1842 bad_error("scf_value_set_from_string", 1843 scf_error()); 1844 1845 warn(gettext("Value \"%s\" is not a valid " 1846 "%s.\n"), vp->sc_u.sc_string, 1847 scf_type_to_string(tp)); 1848 scf_value_destroy(val); 1849 return (stash_scferror(lcbdata)); 1850 } 1851 break; 1852 } 1853 1854 if (scf_entry_add_value(entr, val) != 0) 1855 bad_error("scf_entry_add_value", scf_error()); 1856 } 1857 1858 return (UU_WALK_NEXT); 1859 } 1860 1861 /* 1862 * Import a pgroup_t into the repository. Uses sc_handle, sc_parent, 1863 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP), 1864 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx. 1865 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 1866 * lcbdata->sc_err to 1867 * ECONNABORTED - repository connection broken 1868 * ENOMEM - out of memory 1869 * ENOSPC - svc.configd is out of resources 1870 * ECANCELED - sc_parent was deleted 1871 * EPERM - could not create property group (permission denied) (error printed) 1872 * - could not modify property group (permission denied) (error printed) 1873 * - could not delete property group (permission denied) (error printed) 1874 * EROFS - could not create property group (repository is read-only) 1875 * - could not delete property group (repository is read-only) 1876 * EACCES - could not create property group (backend access denied) 1877 * - could not delete property group (backend access denied) 1878 * EEXIST - could not create property group (already exists) 1879 * EINVAL - invalid property group name (error printed) 1880 * - invalid property name (error printed) 1881 * - invalid value (error printed) 1882 * EBUSY - new property group deleted (error printed) 1883 * - new property group changed (error printed) 1884 * - property group added (error printed) 1885 * - property group deleted (error printed) 1886 */ 1887 static int 1888 entity_pgroup_import(void *v, void *pvt) 1889 { 1890 pgroup_t *p = v; 1891 scf_callback_t cbdata; 1892 scf_callback_t *lcbdata = pvt; 1893 void *ent = lcbdata->sc_parent; 1894 int issvc = lcbdata->sc_service; 1895 int r; 1896 1897 const char * const pg_changed = gettext("%s changed unexpectedly " 1898 "(new property group \"%s\" changed).\n"); 1899 1900 /* Never import deleted property groups. */ 1901 if (p->sc_pgroup_delete) 1902 return (UU_WALK_NEXT); 1903 1904 if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) && 1905 strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) { 1906 lcbdata->sc_general = p; 1907 return (UU_WALK_NEXT); 1908 } 1909 1910 add_pg: 1911 if (issvc) 1912 r = scf_service_add_pg(ent, p->sc_pgroup_name, 1913 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 1914 else 1915 r = scf_instance_add_pg(ent, p->sc_pgroup_name, 1916 p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg); 1917 if (r != 0) { 1918 switch (scf_error()) { 1919 case SCF_ERROR_DELETED: 1920 case SCF_ERROR_CONNECTION_BROKEN: 1921 case SCF_ERROR_BACKEND_READONLY: 1922 case SCF_ERROR_BACKEND_ACCESS: 1923 case SCF_ERROR_NO_RESOURCES: 1924 return (stash_scferror(lcbdata)); 1925 1926 case SCF_ERROR_EXISTS: 1927 if (lcbdata->sc_flags & SCI_FORCE) 1928 break; 1929 return (stash_scferror(lcbdata)); 1930 1931 case SCF_ERROR_INVALID_ARGUMENT: 1932 warn(emsg_fmri_invalid_pg_name_type, 1933 lcbdata->sc_source_fmri, 1934 p->sc_pgroup_name, p->sc_pgroup_type); 1935 return (stash_scferror(lcbdata)); 1936 1937 case SCF_ERROR_PERMISSION_DENIED: 1938 warn(emsg_pg_add_perm, p->sc_pgroup_name, 1939 lcbdata->sc_target_fmri); 1940 return (stash_scferror(lcbdata)); 1941 1942 case SCF_ERROR_NOT_BOUND: 1943 case SCF_ERROR_HANDLE_MISMATCH: 1944 case SCF_ERROR_NOT_SET: 1945 default: 1946 bad_error("scf_service_add_pg", scf_error()); 1947 } 1948 1949 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) { 1950 switch (scf_error()) { 1951 case SCF_ERROR_CONNECTION_BROKEN: 1952 case SCF_ERROR_DELETED: 1953 return (stash_scferror(lcbdata)); 1954 1955 case SCF_ERROR_INVALID_ARGUMENT: 1956 warn(emsg_fmri_invalid_pg_name, 1957 lcbdata->sc_source_fmri, 1958 p->sc_pgroup_name); 1959 return (stash_scferror(lcbdata)); 1960 1961 case SCF_ERROR_NOT_FOUND: 1962 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 1963 p->sc_pgroup_name); 1964 lcbdata->sc_err = EBUSY; 1965 return (UU_WALK_ERROR); 1966 1967 case SCF_ERROR_NOT_BOUND: 1968 case SCF_ERROR_HANDLE_MISMATCH: 1969 case SCF_ERROR_NOT_SET: 1970 default: 1971 bad_error("entity_get_pg", scf_error()); 1972 } 1973 } 1974 1975 if (lcbdata->sc_flags & SCI_KEEP) 1976 goto props; 1977 1978 if (scf_pg_delete(imp_pg) != 0) { 1979 switch (scf_error()) { 1980 case SCF_ERROR_DELETED: 1981 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 1982 p->sc_pgroup_name); 1983 lcbdata->sc_err = EBUSY; 1984 return (UU_WALK_ERROR); 1985 1986 case SCF_ERROR_PERMISSION_DENIED: 1987 warn(emsg_pg_del_perm, p->sc_pgroup_name, 1988 lcbdata->sc_target_fmri); 1989 return (stash_scferror(lcbdata)); 1990 1991 case SCF_ERROR_BACKEND_READONLY: 1992 case SCF_ERROR_BACKEND_ACCESS: 1993 case SCF_ERROR_CONNECTION_BROKEN: 1994 return (stash_scferror(lcbdata)); 1995 1996 case SCF_ERROR_NOT_SET: 1997 default: 1998 bad_error("scf_pg_delete", scf_error()); 1999 } 2000 } 2001 2002 goto add_pg; 2003 } 2004 2005 props: 2006 2007 /* 2008 * Add properties to property group, if any. 2009 */ 2010 cbdata.sc_handle = lcbdata->sc_handle; 2011 cbdata.sc_parent = imp_pg; 2012 cbdata.sc_flags = lcbdata->sc_flags; 2013 cbdata.sc_trans = imp_tx; 2014 cbdata.sc_enable = NULL; 2015 2016 if (scf_transaction_start(imp_tx, imp_pg) != 0) { 2017 switch (scf_error()) { 2018 case SCF_ERROR_BACKEND_ACCESS: 2019 case SCF_ERROR_BACKEND_READONLY: 2020 case SCF_ERROR_CONNECTION_BROKEN: 2021 return (stash_scferror(lcbdata)); 2022 2023 case SCF_ERROR_DELETED: 2024 warn(pg_changed, lcbdata->sc_target_fmri, 2025 p->sc_pgroup_name); 2026 lcbdata->sc_err = EBUSY; 2027 return (UU_WALK_ERROR); 2028 2029 case SCF_ERROR_PERMISSION_DENIED: 2030 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2031 lcbdata->sc_target_fmri); 2032 return (stash_scferror(lcbdata)); 2033 2034 case SCF_ERROR_NOT_BOUND: 2035 case SCF_ERROR_NOT_SET: 2036 case SCF_ERROR_IN_USE: 2037 case SCF_ERROR_HANDLE_MISMATCH: 2038 default: 2039 bad_error("scf_transaction_start", scf_error()); 2040 } 2041 } 2042 2043 if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata, 2044 UU_DEFAULT) != 0) { 2045 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2046 bad_error("uu_list_walk", uu_error()); 2047 scf_transaction_reset(imp_tx); 2048 2049 lcbdata->sc_err = cbdata.sc_err; 2050 if (cbdata.sc_err == ECANCELED) { 2051 warn(pg_changed, lcbdata->sc_target_fmri, 2052 p->sc_pgroup_name); 2053 lcbdata->sc_err = EBUSY; 2054 } 2055 return (UU_WALK_ERROR); 2056 } 2057 2058 if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) { 2059 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE); 2060 2061 /* 2062 * take the snapshot running snapshot then 2063 * import the stored general/enable property 2064 */ 2065 r = take_snap(ent, snap_running, imp_rsnap); 2066 switch (r) { 2067 case 0: 2068 break; 2069 2070 case ECONNABORTED: 2071 warn(gettext("Could not take %s snapshot on import " 2072 "(repository connection broken).\n"), 2073 snap_running); 2074 lcbdata->sc_err = r; 2075 return (UU_WALK_ERROR); 2076 case ECANCELED: 2077 warn(emsg_deleted); 2078 lcbdata->sc_err = r; 2079 return (UU_WALK_ERROR); 2080 2081 case EPERM: 2082 warn(gettext("Could not take %s snapshot " 2083 "(permission denied).\n"), snap_running); 2084 lcbdata->sc_err = r; 2085 return (UU_WALK_ERROR); 2086 2087 case ENOSPC: 2088 warn(gettext("Could not take %s snapshot" 2089 "(repository server out of resources).\n"), 2090 snap_running); 2091 lcbdata->sc_err = r; 2092 return (UU_WALK_ERROR); 2093 2094 default: 2095 bad_error("take_snap", r); 2096 } 2097 2098 r = lscf_property_import(cbdata.sc_enable, &cbdata); 2099 if (r != UU_WALK_NEXT) { 2100 if (r != UU_WALK_ERROR) 2101 bad_error("lscf_property_import", r); 2102 return (EINVAL); 2103 } 2104 } 2105 2106 r = scf_transaction_commit(imp_tx); 2107 switch (r) { 2108 case 1: 2109 r = UU_WALK_NEXT; 2110 break; 2111 2112 case 0: 2113 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name); 2114 lcbdata->sc_err = EBUSY; 2115 r = UU_WALK_ERROR; 2116 break; 2117 2118 case -1: 2119 switch (scf_error()) { 2120 case SCF_ERROR_BACKEND_READONLY: 2121 case SCF_ERROR_BACKEND_ACCESS: 2122 case SCF_ERROR_CONNECTION_BROKEN: 2123 case SCF_ERROR_NO_RESOURCES: 2124 r = stash_scferror(lcbdata); 2125 break; 2126 2127 case SCF_ERROR_DELETED: 2128 warn(emsg_pg_deleted, lcbdata->sc_target_fmri, 2129 p->sc_pgroup_name); 2130 lcbdata->sc_err = EBUSY; 2131 r = UU_WALK_ERROR; 2132 break; 2133 2134 case SCF_ERROR_PERMISSION_DENIED: 2135 warn(emsg_pg_mod_perm, p->sc_pgroup_name, 2136 lcbdata->sc_target_fmri); 2137 r = stash_scferror(lcbdata); 2138 break; 2139 2140 case SCF_ERROR_NOT_SET: 2141 case SCF_ERROR_INVALID_ARGUMENT: 2142 case SCF_ERROR_NOT_BOUND: 2143 default: 2144 bad_error("scf_transaction_commit", scf_error()); 2145 } 2146 break; 2147 2148 default: 2149 bad_error("scf_transaction_commit", r); 2150 } 2151 2152 scf_transaction_destroy_children(imp_tx); 2153 2154 return (r); 2155 } 2156 2157 /* 2158 * Returns 2159 * 0 - success 2160 * ECONNABORTED - repository connection broken 2161 * ENOMEM - out of memory 2162 * ENOSPC - svc.configd is out of resources 2163 * ECANCELED - inst was deleted 2164 * EPERM - could not create property group (permission denied) (error printed) 2165 * - could not modify property group (permission denied) (error printed) 2166 * EROFS - could not create property group (repository is read-only) 2167 * EACCES - could not create property group (backend access denied) 2168 * EEXIST - could not create property group (already exists) 2169 * EINVAL - invalid property group name (error printed) 2170 * - invalid property name (error printed) 2171 * - invalid value (error printed) 2172 * EBUSY - new property group changed (error printed) 2173 */ 2174 static int 2175 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri, 2176 const entity_t *isvc, int flags) 2177 { 2178 scf_callback_t cbdata; 2179 2180 cbdata.sc_handle = scf_service_handle(svc); 2181 cbdata.sc_parent = svc; 2182 cbdata.sc_service = 1; 2183 cbdata.sc_general = 0; 2184 cbdata.sc_enable = 0; 2185 cbdata.sc_flags = flags; 2186 cbdata.sc_source_fmri = isvc->sc_fmri; 2187 cbdata.sc_target_fmri = target_fmri; 2188 2189 if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata, 2190 UU_DEFAULT) != 0) { 2191 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2192 bad_error("uu_list_walk", uu_error()); 2193 2194 return (cbdata.sc_err); 2195 } 2196 2197 return (0); 2198 } 2199 2200 /* 2201 * Returns 2202 * 0 - success 2203 * ECONNABORTED - repository connection broken 2204 * ENOMEM - out of memory 2205 * ENOSPC - svc.configd is out of resources 2206 * ECANCELED - inst was deleted 2207 * EPERM - could not create property group (permission denied) (error printed) 2208 * - could not modify property group (permission denied) (error printed) 2209 * EROFS - could not create property group (repository is read-only) 2210 * EACCES - could not create property group (backend access denied) 2211 * EEXIST - could not create property group (already exists) 2212 * EINVAL - invalid property group name (error printed) 2213 * - invalid property name (error printed) 2214 * - invalid value (error printed) 2215 * EBUSY - new property group changed (error printed) 2216 */ 2217 static int 2218 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri, 2219 const entity_t *iinst, int flags) 2220 { 2221 scf_callback_t cbdata; 2222 2223 cbdata.sc_handle = scf_instance_handle(inst); 2224 cbdata.sc_parent = inst; 2225 cbdata.sc_service = 0; 2226 cbdata.sc_general = NULL; 2227 cbdata.sc_enable = NULL; 2228 cbdata.sc_flags = flags; 2229 cbdata.sc_source_fmri = iinst->sc_fmri; 2230 cbdata.sc_target_fmri = target_fmri; 2231 2232 if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata, 2233 UU_DEFAULT) != 0) { 2234 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 2235 bad_error("uu_list_walk", uu_error()); 2236 2237 return (cbdata.sc_err); 2238 } 2239 2240 if ((flags & SCI_GENERALLAST) && cbdata.sc_general) { 2241 cbdata.sc_flags = flags & (~SCI_GENERALLAST); 2242 /* 2243 * If importing with the SCI_NOENABLED flag then 2244 * skip the delay, but if not then add the delay 2245 * of the enable property. 2246 */ 2247 if (!(cbdata.sc_flags & SCI_NOENABLED)) { 2248 cbdata.sc_flags |= SCI_DELAYENABLE; 2249 } 2250 2251 if (entity_pgroup_import(cbdata.sc_general, &cbdata) 2252 != UU_WALK_NEXT) 2253 return (cbdata.sc_err); 2254 } 2255 2256 return (0); 2257 } 2258 2259 /* 2260 * Report the reasons why we can't upgrade pg2 to pg1. 2261 */ 2262 static void 2263 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri, 2264 int new) 2265 { 2266 property_t *p1, *p2; 2267 2268 assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0); 2269 2270 if (!pg_attrs_equal(pg1, pg2, fmri, new)) 2271 return; 2272 2273 for (p1 = uu_list_first(pg1->sc_pgroup_props); 2274 p1 != NULL; 2275 p1 = uu_list_next(pg1->sc_pgroup_props, p1)) { 2276 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL); 2277 if (p2 != NULL) { 2278 (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name, 2279 new); 2280 continue; 2281 } 2282 2283 if (new) 2284 warn(gettext("Conflict upgrading %s (new property " 2285 "group \"%s\" is missing property \"%s\").\n"), 2286 fmri, pg1->sc_pgroup_name, p1->sc_property_name); 2287 else 2288 warn(gettext("Conflict upgrading %s (property " 2289 "\"%s/%s\" is missing).\n"), fmri, 2290 pg1->sc_pgroup_name, p1->sc_property_name); 2291 } 2292 2293 /* 2294 * Since pg1 should be from the manifest, any properties in pg2 which 2295 * aren't in pg1 shouldn't be reported as conflicts. 2296 */ 2297 } 2298 2299 /* 2300 * Add transaction entries to tx which will upgrade cur's pg according to old 2301 * & new. 2302 * 2303 * Returns 2304 * 0 - success 2305 * EINVAL - new has a property with an invalid name or value (message emitted) 2306 * ENOMEM - out of memory 2307 */ 2308 static int 2309 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new, 2310 pgroup_t *cur, int speak, const char *fmri) 2311 { 2312 property_t *p, *new_p, *cur_p; 2313 scf_transaction_entry_t *e; 2314 int r; 2315 int is_general; 2316 int is_protected; 2317 2318 if (uu_list_walk(new->sc_pgroup_props, clear_int, 2319 (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0) 2320 bad_error("uu_list_walk", uu_error()); 2321 2322 is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0; 2323 2324 for (p = uu_list_first(old->sc_pgroup_props); 2325 p != NULL; 2326 p = uu_list_next(old->sc_pgroup_props, p)) { 2327 /* p is a property in the old property group. */ 2328 2329 /* Protect live properties. */ 2330 is_protected = 0; 2331 if (is_general) { 2332 if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 2333 0 || 2334 strcmp(p->sc_property_name, 2335 SCF_PROPERTY_RESTARTER) == 0) 2336 is_protected = 1; 2337 } 2338 2339 /* Look for the same property in the new properties. */ 2340 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL); 2341 if (new_p != NULL) { 2342 new_p->sc_seen = 1; 2343 2344 /* 2345 * If the new property is the same as the old, don't do 2346 * anything (leave any user customizations). 2347 */ 2348 if (prop_equal(p, new_p, NULL, NULL, 0)) 2349 continue; 2350 2351 if (new_p->sc_property_override) 2352 goto upgrade; 2353 } 2354 2355 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL); 2356 if (cur_p == NULL) { 2357 /* 2358 * p has been deleted from the repository. If we were 2359 * going to delete it anyway, do nothing. Otherwise 2360 * report a conflict. 2361 */ 2362 if (new_p == NULL) 2363 continue; 2364 2365 if (is_protected) 2366 continue; 2367 2368 warn(gettext("Conflict upgrading %s " 2369 "(property \"%s/%s\" is missing).\n"), fmri, 2370 old->sc_pgroup_name, p->sc_property_name); 2371 continue; 2372 } 2373 2374 if (!prop_equal(p, cur_p, NULL, NULL, 0)) { 2375 /* 2376 * Conflict. Don't warn if the property is already the 2377 * way we want it, though. 2378 */ 2379 if (is_protected) 2380 continue; 2381 2382 if (new_p == NULL) 2383 (void) prop_equal(p, cur_p, fmri, 2384 old->sc_pgroup_name, 0); 2385 else 2386 (void) prop_equal(cur_p, new_p, fmri, 2387 old->sc_pgroup_name, 0); 2388 continue; 2389 } 2390 2391 if (is_protected) { 2392 if (speak) 2393 warn(gettext("%s: Refusing to upgrade " 2394 "\"%s/%s\" (live property).\n"), fmri, 2395 old->sc_pgroup_name, p->sc_property_name); 2396 continue; 2397 } 2398 2399 upgrade: 2400 /* p hasn't been customized in the repository. Upgrade it. */ 2401 if (new_p == NULL) { 2402 /* p was deleted. Delete from cur if unchanged. */ 2403 if (speak) 2404 warn(gettext( 2405 "%s: Deleting property \"%s/%s\".\n"), 2406 fmri, old->sc_pgroup_name, 2407 p->sc_property_name); 2408 2409 e = scf_entry_create(g_hndl); 2410 if (e == NULL) 2411 return (ENOMEM); 2412 2413 if (scf_transaction_property_delete(tx, e, 2414 p->sc_property_name) != 0) { 2415 switch (scf_error()) { 2416 case SCF_ERROR_DELETED: 2417 scf_entry_destroy(e); 2418 return (ECANCELED); 2419 2420 case SCF_ERROR_CONNECTION_BROKEN: 2421 scf_entry_destroy(e); 2422 return (ECONNABORTED); 2423 2424 case SCF_ERROR_NOT_FOUND: 2425 /* 2426 * This can happen if cur is from the 2427 * running snapshot (and it differs 2428 * from the live properties). 2429 */ 2430 scf_entry_destroy(e); 2431 break; 2432 2433 case SCF_ERROR_HANDLE_MISMATCH: 2434 case SCF_ERROR_NOT_BOUND: 2435 case SCF_ERROR_NOT_SET: 2436 case SCF_ERROR_INVALID_ARGUMENT: 2437 default: 2438 bad_error( 2439 "scf_transaction_property_delete", 2440 scf_error()); 2441 } 2442 } 2443 } else { 2444 scf_callback_t ctx; 2445 2446 if (speak) 2447 warn(gettext( 2448 "%s: Upgrading property \"%s/%s\".\n"), 2449 fmri, old->sc_pgroup_name, 2450 p->sc_property_name); 2451 2452 ctx.sc_handle = g_hndl; 2453 ctx.sc_trans = tx; 2454 ctx.sc_flags = 0; 2455 2456 r = lscf_property_import(new_p, &ctx); 2457 if (r != UU_WALK_NEXT) { 2458 if (r != UU_WALK_ERROR) 2459 bad_error("lscf_property_import", r); 2460 return (EINVAL); 2461 } 2462 } 2463 } 2464 2465 /* Go over the properties which were added. */ 2466 for (new_p = uu_list_first(new->sc_pgroup_props); 2467 new_p != NULL; 2468 new_p = uu_list_next(new->sc_pgroup_props, new_p)) { 2469 if (new_p->sc_seen) 2470 continue; 2471 2472 /* This is a new property. */ 2473 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL); 2474 if (cur_p == NULL) { 2475 scf_callback_t ctx; 2476 2477 ctx.sc_handle = g_hndl; 2478 ctx.sc_trans = tx; 2479 ctx.sc_flags = 0; 2480 2481 r = lscf_property_import(new_p, &ctx); 2482 if (r != UU_WALK_NEXT) { 2483 if (r != UU_WALK_ERROR) 2484 bad_error("lscf_property_import", r); 2485 return (EINVAL); 2486 } 2487 continue; 2488 } 2489 2490 /* 2491 * Report a conflict if the new property differs from the 2492 * current one. Unless it's general/enabled, since that's 2493 * never in the last-import snapshot. 2494 */ 2495 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) == 2496 0 && 2497 strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0) 2498 continue; 2499 2500 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1); 2501 } 2502 2503 return (0); 2504 } 2505 2506 /* 2507 * Upgrade pg according to old & new. 2508 * 2509 * Returns 2510 * 0 - success 2511 * ECONNABORTED - repository connection broken 2512 * ENOMEM - out of memory 2513 * ENOSPC - svc.configd is out of resources 2514 * ECANCELED - pg was deleted 2515 * EPERM - couldn't modify pg (permission denied) 2516 * EROFS - couldn't modify pg (backend read-only) 2517 * EACCES - couldn't modify pg (backend access denied) 2518 * EINVAL - new has a property with invalid name or value (error printed) 2519 * EBUSY - pg changed unexpectedly 2520 */ 2521 static int 2522 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old, 2523 pgroup_t *new, int speak, const char *fmri) 2524 { 2525 int r; 2526 2527 if (scf_transaction_start(imp_tx, pg) != 0) { 2528 switch (scf_error()) { 2529 case SCF_ERROR_CONNECTION_BROKEN: 2530 case SCF_ERROR_DELETED: 2531 case SCF_ERROR_PERMISSION_DENIED: 2532 case SCF_ERROR_BACKEND_READONLY: 2533 case SCF_ERROR_BACKEND_ACCESS: 2534 return (scferror2errno(scf_error())); 2535 2536 case SCF_ERROR_HANDLE_MISMATCH: 2537 case SCF_ERROR_IN_USE: 2538 case SCF_ERROR_NOT_BOUND: 2539 case SCF_ERROR_NOT_SET: 2540 default: 2541 bad_error("scf_transaction_start", scf_error()); 2542 } 2543 } 2544 2545 r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri); 2546 switch (r) { 2547 case 0: 2548 break; 2549 2550 case EINVAL: 2551 case ENOMEM: 2552 scf_transaction_destroy_children(imp_tx); 2553 return (r); 2554 2555 default: 2556 bad_error("add_upgrade_entries", r); 2557 } 2558 2559 r = scf_transaction_commit(imp_tx); 2560 2561 scf_transaction_destroy_children(imp_tx); 2562 2563 switch (r) { 2564 case 1: 2565 break; 2566 2567 case 0: 2568 return (EBUSY); 2569 2570 case -1: 2571 switch (scf_error()) { 2572 case SCF_ERROR_CONNECTION_BROKEN: 2573 case SCF_ERROR_NO_RESOURCES: 2574 case SCF_ERROR_PERMISSION_DENIED: 2575 case SCF_ERROR_BACKEND_READONLY: 2576 case SCF_ERROR_BACKEND_ACCESS: 2577 case SCF_ERROR_DELETED: 2578 return (scferror2errno(scf_error())); 2579 2580 case SCF_ERROR_NOT_BOUND: 2581 case SCF_ERROR_INVALID_ARGUMENT: 2582 case SCF_ERROR_NOT_SET: 2583 default: 2584 bad_error("scf_transaction_commit", scf_error()); 2585 } 2586 2587 default: 2588 bad_error("scf_transaction_commit", r); 2589 } 2590 2591 return (0); 2592 } 2593 2594 /* 2595 * Compares two entity FMRIs. Returns 2596 * 2597 * 1 - equal 2598 * 0 - not equal 2599 * -1 - f1 is invalid or not an entity 2600 * -2 - f2 is invalid or not an entity 2601 */ 2602 static int 2603 fmri_equal(const char *f1, const char *f2) 2604 { 2605 int r; 2606 const char *s1, *i1, *pg1; 2607 const char *s2, *i2, *pg2; 2608 2609 if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 2610 return (-1); 2611 if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0) 2612 return (-1); 2613 2614 if (s1 == NULL || pg1 != NULL) 2615 return (-1); 2616 2617 if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1) 2618 return (-2); 2619 if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0) 2620 return (-2); 2621 2622 if (s2 == NULL || pg2 != NULL) 2623 return (-2); 2624 2625 r = strcmp(s1, s2); 2626 if (r != 0) 2627 return (0); 2628 2629 if (i1 == NULL && i2 == NULL) 2630 return (1); 2631 2632 if (i1 == NULL || i2 == NULL) 2633 return (0); 2634 2635 return (strcmp(i1, i2) == 0); 2636 } 2637 2638 /* 2639 * Import a dependent by creating a dependency property group in the dependent 2640 * entity. If lcbdata->sc_trans is set, assume it's been started on the 2641 * dependents pg, and add an entry to create a new property for this 2642 * dependent. Uses sc_handle, sc_trans, and sc_fmri in lcbdata. 2643 * 2644 * On success, returns UU_WALK_NEXT. On error, returns UU_WALK_ERROR and sets 2645 * lcbdata->sc_err to 2646 * ECONNABORTED - repository connection broken 2647 * ENOMEM - out of memory 2648 * ENOSPC - configd is out of resources 2649 * EINVAL - target is invalid (error printed) 2650 * - target is not an entity (error printed) 2651 * - dependent has invalid name (error printed) 2652 * - invalid property name (error printed) 2653 * - invalid value (error printed) 2654 * - scope of target does not exist (error printed) 2655 * EPERM - couldn't create target (permission denied) (error printed) 2656 * - couldn't create dependency pg (permission denied) (error printed) 2657 * - couldn't modify dependency pg (permission denied) (error printed) 2658 * EROFS - couldn't create target (repository read-only) 2659 * - couldn't create dependency pg (repository read-only) 2660 * EACCES - couldn't create target (backend access denied) 2661 * - couldn't create dependency pg (backend access denied) 2662 * ECANCELED - sc_trans's pg was deleted 2663 * EALREADY - property for dependent already exists in sc_trans's pg 2664 * EEXIST - dependency pg already exists in target (error printed) 2665 * EBUSY - target deleted (error printed) 2666 * - property group changed during import (error printed) 2667 */ 2668 static int 2669 lscf_dependent_import(void *a1, void *pvt) 2670 { 2671 pgroup_t *pgrp = a1; 2672 scf_callback_t *lcbdata = pvt; 2673 2674 int isservice; 2675 int ret; 2676 scf_transaction_entry_t *e; 2677 scf_value_t *val; 2678 scf_callback_t dependent_cbdata; 2679 scf_error_t scfe; 2680 2681 /* 2682 * Decode the FMRI into dependent_cbdata->sc_parent. Do it here so if 2683 * it's invalid, we fail before modifying the repository. 2684 */ 2685 scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 2686 &dependent_cbdata.sc_parent, &isservice); 2687 switch (scfe) { 2688 case SCF_ERROR_NONE: 2689 break; 2690 2691 case SCF_ERROR_NO_MEMORY: 2692 return (stash_scferror_err(lcbdata, scfe)); 2693 2694 case SCF_ERROR_INVALID_ARGUMENT: 2695 semerr(gettext("The FMRI for the \"%s\" dependent is " 2696 "invalid.\n"), pgrp->sc_pgroup_name); 2697 return (stash_scferror_err(lcbdata, scfe)); 2698 2699 case SCF_ERROR_CONSTRAINT_VIOLATED: 2700 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent " 2701 "specifies neither a service nor an instance.\n"), 2702 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 2703 return (stash_scferror_err(lcbdata, scfe)); 2704 2705 case SCF_ERROR_NOT_FOUND: 2706 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri, 2707 &dependent_cbdata.sc_parent, &isservice); 2708 switch (scfe) { 2709 case SCF_ERROR_NONE: 2710 break; 2711 2712 case SCF_ERROR_NO_MEMORY: 2713 case SCF_ERROR_BACKEND_READONLY: 2714 case SCF_ERROR_BACKEND_ACCESS: 2715 return (stash_scferror_err(lcbdata, scfe)); 2716 2717 case SCF_ERROR_NOT_FOUND: 2718 semerr(gettext("The scope in FMRI \"%s\" for the " 2719 "\"%s\" dependent does not exist.\n"), 2720 pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name); 2721 lcbdata->sc_err = EINVAL; 2722 return (UU_WALK_ERROR); 2723 2724 case SCF_ERROR_PERMISSION_DENIED: 2725 warn(gettext( 2726 "Could not create %s (permission denied).\n"), 2727 pgrp->sc_pgroup_fmri); 2728 return (stash_scferror_err(lcbdata, scfe)); 2729 2730 case SCF_ERROR_INVALID_ARGUMENT: 2731 case SCF_ERROR_CONSTRAINT_VIOLATED: 2732 default: 2733 bad_error("create_entity", scfe); 2734 } 2735 break; 2736 2737 default: 2738 bad_error("fmri_to_entity", scfe); 2739 } 2740 2741 if (lcbdata->sc_trans != NULL) { 2742 e = scf_entry_create(lcbdata->sc_handle); 2743 if (e == NULL) { 2744 if (scf_error() != SCF_ERROR_NO_MEMORY) 2745 bad_error("scf_entry_create", scf_error()); 2746 2747 entity_destroy(dependent_cbdata.sc_parent, isservice); 2748 return (stash_scferror(lcbdata)); 2749 } 2750 2751 if (scf_transaction_property_new(lcbdata->sc_trans, e, 2752 pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) { 2753 switch (scf_error()) { 2754 case SCF_ERROR_INVALID_ARGUMENT: 2755 warn(gettext("Dependent of %s has invalid name " 2756 "\"%s\".\n"), pgrp->sc_parent->sc_fmri, 2757 pgrp->sc_pgroup_name); 2758 /* FALLTHROUGH */ 2759 2760 case SCF_ERROR_DELETED: 2761 case SCF_ERROR_CONNECTION_BROKEN: 2762 scf_entry_destroy(e); 2763 entity_destroy(dependent_cbdata.sc_parent, 2764 isservice); 2765 return (stash_scferror(lcbdata)); 2766 2767 case SCF_ERROR_EXISTS: 2768 scf_entry_destroy(e); 2769 entity_destroy(dependent_cbdata.sc_parent, 2770 isservice); 2771 lcbdata->sc_err = EALREADY; 2772 return (UU_WALK_ERROR); 2773 2774 case SCF_ERROR_NOT_BOUND: 2775 case SCF_ERROR_HANDLE_MISMATCH: 2776 case SCF_ERROR_NOT_SET: 2777 default: 2778 bad_error("scf_transaction_property_new", 2779 scf_error()); 2780 } 2781 } 2782 2783 val = scf_value_create(lcbdata->sc_handle); 2784 if (val == NULL) { 2785 if (scf_error() != SCF_ERROR_NO_MEMORY) 2786 bad_error("scf_value_create", scf_error()); 2787 2788 entity_destroy(dependent_cbdata.sc_parent, isservice); 2789 return (stash_scferror(lcbdata)); 2790 } 2791 2792 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 2793 pgrp->sc_pgroup_fmri) != 0) 2794 /* invalid should have been caught above */ 2795 bad_error("scf_value_set_from_string", scf_error()); 2796 2797 if (scf_entry_add_value(e, val) != 0) 2798 bad_error("scf_entry_add_value", scf_error()); 2799 } 2800 2801 /* Add the property group to the target entity. */ 2802 2803 dependent_cbdata.sc_handle = lcbdata->sc_handle; 2804 dependent_cbdata.sc_flags = 0; 2805 dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri; 2806 dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri; 2807 2808 ret = entity_pgroup_import(pgrp, &dependent_cbdata); 2809 2810 entity_destroy(dependent_cbdata.sc_parent, isservice); 2811 2812 if (ret == UU_WALK_NEXT) 2813 return (ret); 2814 2815 if (ret != UU_WALK_ERROR) 2816 bad_error("entity_pgroup_import", ret); 2817 2818 switch (dependent_cbdata.sc_err) { 2819 case ECANCELED: 2820 warn(gettext("%s deleted unexpectedly.\n"), 2821 pgrp->sc_pgroup_fmri); 2822 lcbdata->sc_err = EBUSY; 2823 break; 2824 2825 case EEXIST: 2826 warn(gettext("Could not create \"%s\" dependency in %s " 2827 "(already exists).\n"), pgrp->sc_pgroup_name, 2828 pgrp->sc_pgroup_fmri); 2829 /* FALLTHROUGH */ 2830 2831 default: 2832 lcbdata->sc_err = dependent_cbdata.sc_err; 2833 } 2834 2835 return (UU_WALK_ERROR); 2836 } 2837 2838 static int upgrade_dependent(const scf_property_t *, const entity_t *, 2839 const scf_snaplevel_t *, scf_transaction_t *); 2840 static int handle_dependent_conflict(const entity_t *, const scf_property_t *, 2841 const pgroup_t *); 2842 2843 /* 2844 * Upgrade uncustomized dependents of ent to those specified in ient. Read 2845 * the current dependent targets from running (the snaplevel of a running 2846 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or 2847 * scf_instance_t * according to ient, otherwise). Draw the ancestral 2848 * dependent targets and dependency properties from li_dpts_pg (the 2849 * "dependents" property group in snpl) and snpl (the snaplevel which 2850 * corresponds to ent in a last-import snapshot). If li_dpts_pg is NULL, then 2851 * snpl doesn't have a "dependents" property group, and any dependents in ient 2852 * are new. 2853 * 2854 * Returns 2855 * 0 - success 2856 * ECONNABORTED - repository connection broken 2857 * ENOMEM - out of memory 2858 * ENOSPC - configd is out of resources 2859 * ECANCELED - ent was deleted 2860 * ENODEV - the entity containing li_dpts_pg was deleted 2861 * EPERM - could not modify dependents pg (permission denied) (error printed) 2862 * - couldn't upgrade dependent (permission denied) (error printed) 2863 * - couldn't create dependent (permission denied) (error printed) 2864 * EROFS - could not modify dependents pg (repository read-only) 2865 * - couldn't upgrade dependent (repository read-only) 2866 * - couldn't create dependent (repository read-only) 2867 * EACCES - could not modify dependents pg (backend access denied) 2868 * - could not upgrade dependent (backend access denied) 2869 * - could not create dependent (backend access denied) 2870 * EBUSY - "dependents" pg of ent added, changed, or deleted (error printed) 2871 * - dependent target deleted (error printed) 2872 * - dependent pg changed (error printed) 2873 * EINVAL - new dependent is invalid (error printed) 2874 * EBADF - snpl is corrupt (error printed) 2875 * - snpl has corrupt pg (error printed) 2876 * - dependency pg in target is corrupt (error printed) 2877 * - target has corrupt snapshot (error printed) 2878 * EEXIST - dependency pg already existed in target service (error printed) 2879 */ 2880 static int 2881 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg, 2882 const scf_snaplevel_t *snpl, const entity_t *ient, 2883 const scf_snaplevel_t *running, void *ent) 2884 { 2885 pgroup_t *new_dpt_pgroup; 2886 scf_callback_t cbdata; 2887 int r, unseen, tx_started = 0; 2888 int have_cur_depts; 2889 2890 const char * const dependents = "dependents"; 2891 2892 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 2893 2894 if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0) 2895 /* Nothing to do. */ 2896 return (0); 2897 2898 /* Fetch the current version of the "dependents" property group. */ 2899 have_cur_depts = 1; 2900 if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) { 2901 switch (scf_error()) { 2902 case SCF_ERROR_NOT_FOUND: 2903 break; 2904 2905 case SCF_ERROR_DELETED: 2906 case SCF_ERROR_CONNECTION_BROKEN: 2907 return (scferror2errno(scf_error())); 2908 2909 case SCF_ERROR_NOT_SET: 2910 case SCF_ERROR_INVALID_ARGUMENT: 2911 case SCF_ERROR_HANDLE_MISMATCH: 2912 case SCF_ERROR_NOT_BOUND: 2913 default: 2914 bad_error("entity_get_pg", scf_error()); 2915 } 2916 2917 have_cur_depts = 0; 2918 } 2919 2920 /* Fetch the running version of the "dependents" property group. */ 2921 ud_run_dpts_pg_set = 0; 2922 if (running != NULL) 2923 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg); 2924 else 2925 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg); 2926 if (r == 0) { 2927 ud_run_dpts_pg_set = 1; 2928 } else { 2929 switch (scf_error()) { 2930 case SCF_ERROR_NOT_FOUND: 2931 break; 2932 2933 case SCF_ERROR_DELETED: 2934 case SCF_ERROR_CONNECTION_BROKEN: 2935 return (scferror2errno(scf_error())); 2936 2937 case SCF_ERROR_NOT_SET: 2938 case SCF_ERROR_INVALID_ARGUMENT: 2939 case SCF_ERROR_HANDLE_MISMATCH: 2940 case SCF_ERROR_NOT_BOUND: 2941 default: 2942 bad_error(running ? "scf_snaplevel_get_pg" : 2943 "entity_get_pg", scf_error()); 2944 } 2945 } 2946 2947 /* 2948 * Clear the seen fields of the dependents, so we can tell which ones 2949 * are new. 2950 */ 2951 if (uu_list_walk(ient->sc_dependents, clear_int, 2952 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 2953 bad_error("uu_list_walk", uu_error()); 2954 2955 if (li_dpts_pg != NULL) { 2956 /* 2957 * Each property in li_dpts_pg represents a dependent tag in 2958 * the old manifest. For each, call upgrade_dependent(), 2959 * which will change ud_cur_depts_pg or dependencies in other 2960 * services as appropriate. Note (a) that changes to 2961 * ud_cur_depts_pg are accumulated in ud_tx so they can all be 2962 * made en masse, and (b) it's ok if the entity doesn't have 2963 * a current version of the "dependents" property group, 2964 * because we'll just consider all dependents as customized 2965 * (by being deleted). 2966 */ 2967 2968 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) { 2969 switch (scf_error()) { 2970 case SCF_ERROR_DELETED: 2971 return (ENODEV); 2972 2973 case SCF_ERROR_CONNECTION_BROKEN: 2974 return (ECONNABORTED); 2975 2976 case SCF_ERROR_HANDLE_MISMATCH: 2977 case SCF_ERROR_NOT_BOUND: 2978 case SCF_ERROR_NOT_SET: 2979 default: 2980 bad_error("scf_iter_pg_properties", 2981 scf_error()); 2982 } 2983 } 2984 2985 if (have_cur_depts && 2986 scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 2987 switch (scf_error()) { 2988 case SCF_ERROR_BACKEND_ACCESS: 2989 case SCF_ERROR_BACKEND_READONLY: 2990 case SCF_ERROR_CONNECTION_BROKEN: 2991 return (scferror2errno(scf_error())); 2992 2993 case SCF_ERROR_DELETED: 2994 warn(emsg_pg_deleted, ient->sc_fmri, 2995 dependents); 2996 return (EBUSY); 2997 2998 case SCF_ERROR_PERMISSION_DENIED: 2999 warn(emsg_pg_mod_perm, dependents, 3000 ient->sc_fmri); 3001 return (scferror2errno(scf_error())); 3002 3003 case SCF_ERROR_HANDLE_MISMATCH: 3004 case SCF_ERROR_IN_USE: 3005 case SCF_ERROR_NOT_BOUND: 3006 case SCF_ERROR_NOT_SET: 3007 default: 3008 bad_error("scf_transaction_start", scf_error()); 3009 } 3010 } 3011 tx_started = have_cur_depts; 3012 3013 for (;;) { 3014 r = scf_iter_next_property(ud_iter, ud_dpt_prop); 3015 if (r == 0) 3016 break; 3017 if (r == 1) { 3018 r = upgrade_dependent(ud_dpt_prop, ient, snpl, 3019 tx_started ? ud_tx : NULL); 3020 switch (r) { 3021 case 0: 3022 continue; 3023 3024 case ECONNABORTED: 3025 case ENOMEM: 3026 case ENOSPC: 3027 case EBADF: 3028 case EBUSY: 3029 case EINVAL: 3030 case EPERM: 3031 case EROFS: 3032 case EACCES: 3033 case EEXIST: 3034 break; 3035 3036 case ECANCELED: 3037 r = ENODEV; 3038 break; 3039 3040 default: 3041 bad_error("upgrade_dependent", r); 3042 } 3043 3044 if (tx_started) 3045 scf_transaction_destroy_children(ud_tx); 3046 return (r); 3047 } 3048 if (r != -1) 3049 bad_error("scf_iter_next_property", r); 3050 3051 switch (scf_error()) { 3052 case SCF_ERROR_DELETED: 3053 r = ENODEV; 3054 break; 3055 3056 case SCF_ERROR_CONNECTION_BROKEN: 3057 r = ECONNABORTED; 3058 break; 3059 3060 case SCF_ERROR_NOT_SET: 3061 case SCF_ERROR_INVALID_ARGUMENT: 3062 case SCF_ERROR_NOT_BOUND: 3063 case SCF_ERROR_HANDLE_MISMATCH: 3064 default: 3065 bad_error("scf_iter_next_property", 3066 scf_error()); 3067 } 3068 3069 if (tx_started) 3070 scf_transaction_destroy_children(ud_tx); 3071 return (r); 3072 } 3073 } 3074 3075 /* import unseen dependents */ 3076 unseen = 0; 3077 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3078 new_dpt_pgroup != NULL; 3079 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3080 new_dpt_pgroup)) { 3081 if (!new_dpt_pgroup->sc_pgroup_seen) { 3082 unseen = 1; 3083 break; 3084 } 3085 } 3086 3087 /* If there are none, exit early. */ 3088 if (unseen == 0) 3089 goto commit; 3090 3091 /* Set up for lscf_dependent_import() */ 3092 cbdata.sc_handle = g_hndl; 3093 cbdata.sc_parent = ent; 3094 cbdata.sc_service = issvc; 3095 cbdata.sc_flags = 0; 3096 3097 if (!have_cur_depts) { 3098 /* 3099 * We have new dependents to import, so we need a "dependents" 3100 * property group. 3101 */ 3102 if (issvc) 3103 r = scf_service_add_pg(ent, dependents, 3104 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3105 else 3106 r = scf_instance_add_pg(ent, dependents, 3107 SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg); 3108 if (r != 0) { 3109 switch (scf_error()) { 3110 case SCF_ERROR_DELETED: 3111 case SCF_ERROR_CONNECTION_BROKEN: 3112 case SCF_ERROR_BACKEND_READONLY: 3113 case SCF_ERROR_BACKEND_ACCESS: 3114 case SCF_ERROR_NO_RESOURCES: 3115 return (scferror2errno(scf_error())); 3116 3117 case SCF_ERROR_EXISTS: 3118 warn(emsg_pg_added, ient->sc_fmri, dependents); 3119 return (EBUSY); 3120 3121 case SCF_ERROR_PERMISSION_DENIED: 3122 warn(emsg_pg_add_perm, dependents, 3123 ient->sc_fmri); 3124 return (scferror2errno(scf_error())); 3125 3126 case SCF_ERROR_NOT_BOUND: 3127 case SCF_ERROR_HANDLE_MISMATCH: 3128 case SCF_ERROR_INVALID_ARGUMENT: 3129 case SCF_ERROR_NOT_SET: 3130 default: 3131 bad_error("scf_service_add_pg", scf_error()); 3132 } 3133 } 3134 } 3135 3136 cbdata.sc_trans = ud_tx; 3137 3138 if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) { 3139 switch (scf_error()) { 3140 case SCF_ERROR_CONNECTION_BROKEN: 3141 case SCF_ERROR_BACKEND_ACCESS: 3142 case SCF_ERROR_BACKEND_READONLY: 3143 return (scferror2errno(scf_error())); 3144 3145 case SCF_ERROR_DELETED: 3146 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3147 return (EBUSY); 3148 3149 case SCF_ERROR_PERMISSION_DENIED: 3150 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3151 return (scferror2errno(scf_error())); 3152 3153 case SCF_ERROR_HANDLE_MISMATCH: 3154 case SCF_ERROR_IN_USE: 3155 case SCF_ERROR_NOT_BOUND: 3156 case SCF_ERROR_NOT_SET: 3157 default: 3158 bad_error("scf_transaction_start", scf_error()); 3159 } 3160 } 3161 tx_started = 1; 3162 3163 for (new_dpt_pgroup = uu_list_first(ient->sc_dependents); 3164 new_dpt_pgroup != NULL; 3165 new_dpt_pgroup = uu_list_next(ient->sc_dependents, 3166 new_dpt_pgroup)) { 3167 if (new_dpt_pgroup->sc_pgroup_seen) 3168 continue; 3169 3170 if (ud_run_dpts_pg_set) { 3171 /* 3172 * If the dependent is already there, then we have 3173 * a conflict. 3174 */ 3175 if (scf_pg_get_property(ud_run_dpts_pg, 3176 new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) { 3177 r = handle_dependent_conflict(ient, ud_prop, 3178 new_dpt_pgroup); 3179 switch (r) { 3180 case 0: 3181 continue; 3182 3183 case ECONNABORTED: 3184 case ENOMEM: 3185 case EBUSY: 3186 case EBADF: 3187 case EINVAL: 3188 scf_transaction_destroy_children(ud_tx); 3189 return (r); 3190 3191 default: 3192 bad_error("handle_dependent_conflict", 3193 r); 3194 } 3195 } else { 3196 switch (scf_error()) { 3197 case SCF_ERROR_NOT_FOUND: 3198 break; 3199 3200 case SCF_ERROR_INVALID_ARGUMENT: 3201 warn(emsg_fmri_invalid_pg_name, 3202 ient->sc_fmri, 3203 new_dpt_pgroup->sc_pgroup_name); 3204 scf_transaction_destroy_children(ud_tx); 3205 return (EINVAL); 3206 3207 case SCF_ERROR_DELETED: 3208 warn(emsg_pg_deleted, ient->sc_fmri, 3209 new_dpt_pgroup->sc_pgroup_name); 3210 scf_transaction_destroy_children(ud_tx); 3211 return (EBUSY); 3212 3213 case SCF_ERROR_CONNECTION_BROKEN: 3214 scf_transaction_destroy_children(ud_tx); 3215 return (ECONNABORTED); 3216 3217 case SCF_ERROR_NOT_BOUND: 3218 case SCF_ERROR_HANDLE_MISMATCH: 3219 case SCF_ERROR_NOT_SET: 3220 default: 3221 bad_error("scf_pg_get_property", 3222 scf_error()); 3223 } 3224 } 3225 } 3226 3227 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 3228 if (r != UU_WALK_NEXT) { 3229 if (r != UU_WALK_ERROR) 3230 bad_error("lscf_dependent_import", r); 3231 3232 if (cbdata.sc_err == EALREADY) { 3233 /* Collisions were handled preemptively. */ 3234 bad_error("lscf_dependent_import", 3235 cbdata.sc_err); 3236 } 3237 3238 scf_transaction_destroy_children(ud_tx); 3239 return (cbdata.sc_err); 3240 } 3241 } 3242 3243 commit: 3244 if (!tx_started) 3245 return (0); 3246 3247 r = scf_transaction_commit(ud_tx); 3248 3249 scf_transaction_destroy_children(ud_tx); 3250 3251 switch (r) { 3252 case 1: 3253 return (0); 3254 3255 case 0: 3256 warn(emsg_pg_changed, ient->sc_fmri, dependents); 3257 return (EBUSY); 3258 3259 case -1: 3260 break; 3261 3262 default: 3263 bad_error("scf_transaction_commit", r); 3264 } 3265 3266 switch (scf_error()) { 3267 case SCF_ERROR_CONNECTION_BROKEN: 3268 case SCF_ERROR_BACKEND_READONLY: 3269 case SCF_ERROR_BACKEND_ACCESS: 3270 case SCF_ERROR_NO_RESOURCES: 3271 return (scferror2errno(scf_error())); 3272 3273 case SCF_ERROR_DELETED: 3274 warn(emsg_pg_deleted, ient->sc_fmri, dependents); 3275 return (EBUSY); 3276 3277 case SCF_ERROR_PERMISSION_DENIED: 3278 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri); 3279 return (scferror2errno(scf_error())); 3280 3281 case SCF_ERROR_NOT_BOUND: 3282 case SCF_ERROR_INVALID_ARGUMENT: 3283 case SCF_ERROR_NOT_SET: 3284 default: 3285 bad_error("scf_transaction_destroy", scf_error()); 3286 /* NOTREACHED */ 3287 } 3288 } 3289 3290 /* 3291 * prop is taken to be a property in the "dependents" property group of snpl, 3292 * which is taken to be the snaplevel of a last-import snapshot corresponding 3293 * to ient. If prop is a valid dependents property, upgrade the dependent it 3294 * represents according to the repository & ient. If ud_run_dpts_pg_set is 3295 * true, then ud_run_dpts_pg is taken to be the "dependents" property group 3296 * of the entity ient represents (possibly in the running snapshot). If it 3297 * needs to be changed, an entry will be added to tx, if not NULL. 3298 * 3299 * Returns 3300 * 0 - success 3301 * ECONNABORTED - repository connection broken 3302 * ENOMEM - out of memory 3303 * ENOSPC - configd was out of resources 3304 * ECANCELED - snpl's entity was deleted 3305 * EINVAL - dependent target is invalid (error printed) 3306 * - dependent is invalid (error printed) 3307 * EBADF - snpl is corrupt (error printed) 3308 * - snpl has corrupt pg (error printed) 3309 * - dependency pg in target is corrupt (error printed) 3310 * - running snapshot in dependent is missing snaplevel (error printed) 3311 * EPERM - couldn't delete dependency pg (permission denied) (error printed) 3312 * - couldn't create dependent (permission denied) (error printed) 3313 * - couldn't modify dependent pg (permission denied) (error printed) 3314 * EROFS - couldn't delete dependency pg (repository read-only) 3315 * - couldn't create dependent (repository read-only) 3316 * EACCES - couldn't delete dependency pg (backend access denied) 3317 * - couldn't create dependent (backend access denied) 3318 * EBUSY - ud_run_dpts_pg was deleted (error printed) 3319 * - tx's pg was deleted (error printed) 3320 * - dependent pg was changed or deleted (error printed) 3321 * EEXIST - dependency pg already exists in new target (error printed) 3322 */ 3323 static int 3324 upgrade_dependent(const scf_property_t *prop, const entity_t *ient, 3325 const scf_snaplevel_t *snpl, scf_transaction_t *tx) 3326 { 3327 pgroup_t pgrp; 3328 scf_type_t ty; 3329 pgroup_t *new_dpt_pgroup; 3330 pgroup_t *old_dpt_pgroup = NULL; 3331 pgroup_t *current_pg; 3332 scf_callback_t cbdata; 3333 int tissvc; 3334 void *target_ent; 3335 scf_error_t serr; 3336 int r; 3337 scf_transaction_entry_t *ent; 3338 3339 const char * const cf_inval = gettext("Conflict upgrading %s " 3340 "(dependent \"%s\" has invalid dependents property).\n"); 3341 const char * const cf_missing = gettext("Conflict upgrading %s " 3342 "(dependent \"%s\" is missing).\n"); 3343 const char * const cf_newdpg = gettext("Conflict upgrading %s " 3344 "(dependent \"%s\" has new dependency property group).\n"); 3345 const char * const cf_newtarg = gettext("Conflict upgrading %s " 3346 "(dependent \"%s\" has new target).\n"); 3347 const char * const li_corrupt = 3348 gettext("%s: \"last-import\" snapshot is corrupt.\n"); 3349 const char * const upgrading = 3350 gettext("%s: Upgrading dependent \"%s\".\n"); 3351 const char * const r_no_lvl = gettext("%s: \"running\" snapshot is " 3352 "corrupt (missing snaplevel).\n"); 3353 3354 if (scf_property_type(prop, &ty) != 0) { 3355 switch (scf_error()) { 3356 case SCF_ERROR_DELETED: 3357 case SCF_ERROR_CONNECTION_BROKEN: 3358 return (scferror2errno(scf_error())); 3359 3360 case SCF_ERROR_NOT_BOUND: 3361 case SCF_ERROR_NOT_SET: 3362 default: 3363 bad_error("scf_property_type", scf_error()); 3364 } 3365 } 3366 3367 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3368 warn(li_corrupt, ient->sc_fmri); 3369 return (EBADF); 3370 } 3371 3372 /* 3373 * prop represents a dependent in the old manifest. It is named after 3374 * the dependent. 3375 */ 3376 if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) { 3377 switch (scf_error()) { 3378 case SCF_ERROR_DELETED: 3379 case SCF_ERROR_CONNECTION_BROKEN: 3380 return (scferror2errno(scf_error())); 3381 3382 case SCF_ERROR_NOT_BOUND: 3383 case SCF_ERROR_NOT_SET: 3384 default: 3385 bad_error("scf_property_get_name", scf_error()); 3386 } 3387 } 3388 3389 /* See if it's in the new manifest. */ 3390 pgrp.sc_pgroup_name = ud_name; 3391 new_dpt_pgroup = 3392 uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT); 3393 3394 /* If it's not, delete it... if it hasn't been customized. */ 3395 if (new_dpt_pgroup == NULL) { 3396 pgroup_t *dpt; 3397 3398 if (!ud_run_dpts_pg_set) 3399 return (0); 3400 3401 if (scf_property_get_value(prop, ud_val) != 0) { 3402 switch (scf_error()) { 3403 case SCF_ERROR_NOT_FOUND: 3404 case SCF_ERROR_CONSTRAINT_VIOLATED: 3405 warn(li_corrupt, ient->sc_fmri); 3406 return (EBADF); 3407 3408 case SCF_ERROR_DELETED: 3409 case SCF_ERROR_CONNECTION_BROKEN: 3410 return (scferror2errno(scf_error())); 3411 3412 case SCF_ERROR_HANDLE_MISMATCH: 3413 case SCF_ERROR_NOT_BOUND: 3414 case SCF_ERROR_NOT_SET: 3415 case SCF_ERROR_PERMISSION_DENIED: 3416 default: 3417 bad_error("scf_property_get_value", 3418 scf_error()); 3419 } 3420 } 3421 3422 if (scf_value_get_as_string(ud_val, ud_oldtarg, 3423 max_scf_value_len + 1) < 0) 3424 bad_error("scf_value_get_as_string", scf_error()); 3425 3426 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 3427 0) { 3428 switch (scf_error()) { 3429 case SCF_ERROR_NOT_FOUND: 3430 return (0); 3431 3432 case SCF_ERROR_CONNECTION_BROKEN: 3433 return (scferror2errno(scf_error())); 3434 3435 case SCF_ERROR_DELETED: 3436 warn(emsg_pg_deleted, ient->sc_fmri, 3437 "dependents"); 3438 return (EBUSY); 3439 3440 case SCF_ERROR_INVALID_ARGUMENT: 3441 case SCF_ERROR_NOT_BOUND: 3442 case SCF_ERROR_HANDLE_MISMATCH: 3443 case SCF_ERROR_NOT_SET: 3444 default: 3445 bad_error("scf_pg_get_property", scf_error()); 3446 } 3447 } 3448 if (scf_property_get_value(ud_prop, ud_val) != 0) { 3449 switch (scf_error()) { 3450 case SCF_ERROR_NOT_FOUND: 3451 case SCF_ERROR_CONSTRAINT_VIOLATED: 3452 warn(cf_inval, ient->sc_fmri, ud_name); 3453 return (0); 3454 3455 case SCF_ERROR_DELETED: 3456 case SCF_ERROR_CONNECTION_BROKEN: 3457 return (scferror2errno(scf_error())); 3458 3459 case SCF_ERROR_HANDLE_MISMATCH: 3460 case SCF_ERROR_NOT_BOUND: 3461 case SCF_ERROR_NOT_SET: 3462 case SCF_ERROR_PERMISSION_DENIED: 3463 default: 3464 bad_error("scf_property_get_value", 3465 scf_error()); 3466 } 3467 } 3468 3469 ty = scf_value_type(ud_val); 3470 assert(ty != SCF_TYPE_INVALID); 3471 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3472 warn(cf_inval, ient->sc_fmri, ud_name); 3473 return (0); 3474 } 3475 3476 if (scf_value_get_as_string(ud_val, ud_ctarg, 3477 max_scf_value_len + 1) < 0) 3478 bad_error("scf_value_get_as_string", scf_error()); 3479 3480 r = fmri_equal(ud_ctarg, ud_oldtarg); 3481 switch (r) { 3482 case 1: 3483 break; 3484 3485 case 0: 3486 case -1: /* warn? */ 3487 warn(cf_newtarg, ient->sc_fmri, ud_name); 3488 return (0); 3489 3490 case -2: 3491 warn(li_corrupt, ient->sc_fmri); 3492 return (EBADF); 3493 3494 default: 3495 bad_error("fmri_equal", r); 3496 } 3497 3498 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3499 switch (scf_error()) { 3500 case SCF_ERROR_NOT_FOUND: 3501 warn(li_corrupt, ient->sc_fmri); 3502 return (EBADF); 3503 3504 case SCF_ERROR_DELETED: 3505 case SCF_ERROR_CONNECTION_BROKEN: 3506 return (scferror2errno(scf_error())); 3507 3508 case SCF_ERROR_NOT_BOUND: 3509 case SCF_ERROR_HANDLE_MISMATCH: 3510 case SCF_ERROR_INVALID_ARGUMENT: 3511 case SCF_ERROR_NOT_SET: 3512 default: 3513 bad_error("scf_snaplevel_get_pg", scf_error()); 3514 } 3515 } 3516 3517 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3518 snap_lastimport); 3519 switch (r) { 3520 case 0: 3521 break; 3522 3523 case ECANCELED: 3524 case ECONNABORTED: 3525 case ENOMEM: 3526 case EBADF: 3527 return (r); 3528 3529 case EACCES: 3530 default: 3531 bad_error("load_pg", r); 3532 } 3533 3534 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 3535 switch (serr) { 3536 case SCF_ERROR_NONE: 3537 break; 3538 3539 case SCF_ERROR_NO_MEMORY: 3540 internal_pgroup_free(old_dpt_pgroup); 3541 return (ENOMEM); 3542 3543 case SCF_ERROR_NOT_FOUND: 3544 internal_pgroup_free(old_dpt_pgroup); 3545 goto delprop; 3546 3547 case SCF_ERROR_CONSTRAINT_VIOLATED: /* caught above */ 3548 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 3549 default: 3550 bad_error("fmri_to_entity", serr); 3551 } 3552 3553 r = entity_get_running_pg(target_ent, tissvc, ud_name, 3554 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 3555 switch (r) { 3556 case 0: 3557 break; 3558 3559 case ECONNABORTED: 3560 internal_pgroup_free(old_dpt_pgroup); 3561 return (r); 3562 3563 case ECANCELED: 3564 case ENOENT: 3565 internal_pgroup_free(old_dpt_pgroup); 3566 goto delprop; 3567 3568 case EBADF: 3569 warn(r_no_lvl, ud_ctarg); 3570 internal_pgroup_free(old_dpt_pgroup); 3571 return (r); 3572 3573 case EINVAL: 3574 default: 3575 bad_error("entity_get_running_pg", r); 3576 } 3577 3578 /* load it */ 3579 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 3580 switch (r) { 3581 case 0: 3582 break; 3583 3584 case ECANCELED: 3585 internal_pgroup_free(old_dpt_pgroup); 3586 goto delprop; 3587 3588 case ECONNABORTED: 3589 case ENOMEM: 3590 case EBADF: 3591 internal_pgroup_free(old_dpt_pgroup); 3592 return (r); 3593 3594 case EACCES: 3595 default: 3596 bad_error("load_pg", r); 3597 } 3598 3599 /* compare property groups */ 3600 if (!pg_equal(old_dpt_pgroup, current_pg)) { 3601 warn(cf_newdpg, ient->sc_fmri, ud_name); 3602 internal_pgroup_free(old_dpt_pgroup); 3603 internal_pgroup_free(current_pg); 3604 return (0); 3605 } 3606 3607 internal_pgroup_free(old_dpt_pgroup); 3608 internal_pgroup_free(current_pg); 3609 3610 if (g_verbose) 3611 warn(gettext("%s: Deleting dependent \"%s\".\n"), 3612 ient->sc_fmri, ud_name); 3613 3614 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 3615 switch (scf_error()) { 3616 case SCF_ERROR_NOT_FOUND: 3617 case SCF_ERROR_DELETED: 3618 internal_pgroup_free(old_dpt_pgroup); 3619 goto delprop; 3620 3621 case SCF_ERROR_CONNECTION_BROKEN: 3622 internal_pgroup_free(old_dpt_pgroup); 3623 return (ECONNABORTED); 3624 3625 case SCF_ERROR_NOT_SET: 3626 case SCF_ERROR_INVALID_ARGUMENT: 3627 case SCF_ERROR_HANDLE_MISMATCH: 3628 case SCF_ERROR_NOT_BOUND: 3629 default: 3630 bad_error("entity_get_pg", scf_error()); 3631 } 3632 } 3633 3634 if (scf_pg_delete(ud_pg) != 0) { 3635 switch (scf_error()) { 3636 case SCF_ERROR_DELETED: 3637 break; 3638 3639 case SCF_ERROR_CONNECTION_BROKEN: 3640 case SCF_ERROR_BACKEND_READONLY: 3641 case SCF_ERROR_BACKEND_ACCESS: 3642 return (scferror2errno(scf_error())); 3643 3644 case SCF_ERROR_PERMISSION_DENIED: 3645 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 3646 return (scferror2errno(scf_error())); 3647 3648 case SCF_ERROR_NOT_SET: 3649 default: 3650 bad_error("scf_pg_delete", scf_error()); 3651 } 3652 } 3653 3654 /* 3655 * This service was changed, so it must be refreshed. But 3656 * since it's not mentioned in the new manifest, we have to 3657 * record its FMRI here for use later. We record the name 3658 * & the entity (via sc_parent) in case we need to print error 3659 * messages during the refresh. 3660 */ 3661 dpt = internal_pgroup_new(); 3662 if (dpt == NULL) 3663 return (ENOMEM); 3664 dpt->sc_pgroup_name = strdup(ud_name); 3665 dpt->sc_pgroup_fmri = strdup(ud_ctarg); 3666 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL) 3667 return (ENOMEM); 3668 dpt->sc_parent = (entity_t *)ient; 3669 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0) 3670 uu_die(gettext("libuutil error: %s\n"), 3671 uu_strerror(uu_error())); 3672 3673 delprop: 3674 if (tx == NULL) 3675 return (0); 3676 3677 ent = scf_entry_create(g_hndl); 3678 if (ent == NULL) 3679 return (ENOMEM); 3680 3681 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) { 3682 scf_entry_destroy(ent); 3683 switch (scf_error()) { 3684 case SCF_ERROR_DELETED: 3685 warn(emsg_pg_deleted, ient->sc_fmri, 3686 "dependents"); 3687 return (EBUSY); 3688 3689 case SCF_ERROR_CONNECTION_BROKEN: 3690 return (scferror2errno(scf_error())); 3691 3692 case SCF_ERROR_NOT_FOUND: 3693 break; 3694 3695 case SCF_ERROR_HANDLE_MISMATCH: 3696 case SCF_ERROR_NOT_BOUND: 3697 case SCF_ERROR_INVALID_ARGUMENT: 3698 case SCF_ERROR_NOT_SET: 3699 default: 3700 bad_error("scf_transaction_property_delete", 3701 scf_error()); 3702 } 3703 } 3704 3705 return (0); 3706 } 3707 3708 new_dpt_pgroup->sc_pgroup_seen = 1; 3709 3710 /* 3711 * Decide whether the dependent has changed in the manifest. 3712 */ 3713 /* Compare the target. */ 3714 if (scf_property_get_value(prop, ud_val) != 0) { 3715 switch (scf_error()) { 3716 case SCF_ERROR_NOT_FOUND: 3717 case SCF_ERROR_CONSTRAINT_VIOLATED: 3718 warn(li_corrupt, ient->sc_fmri); 3719 return (EBADF); 3720 3721 case SCF_ERROR_DELETED: 3722 case SCF_ERROR_CONNECTION_BROKEN: 3723 return (scferror2errno(scf_error())); 3724 3725 case SCF_ERROR_HANDLE_MISMATCH: 3726 case SCF_ERROR_NOT_BOUND: 3727 case SCF_ERROR_NOT_SET: 3728 case SCF_ERROR_PERMISSION_DENIED: 3729 default: 3730 bad_error("scf_property_get_value", scf_error()); 3731 } 3732 } 3733 3734 if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) < 3735 0) 3736 bad_error("scf_value_get_as_string", scf_error()); 3737 3738 r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri); 3739 switch (r) { 3740 case 0: 3741 break; 3742 3743 case 1: 3744 /* Compare the dependency pgs. */ 3745 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) { 3746 switch (scf_error()) { 3747 case SCF_ERROR_NOT_FOUND: 3748 warn(li_corrupt, ient->sc_fmri); 3749 return (EBADF); 3750 3751 case SCF_ERROR_DELETED: 3752 case SCF_ERROR_CONNECTION_BROKEN: 3753 return (scferror2errno(scf_error())); 3754 3755 case SCF_ERROR_NOT_BOUND: 3756 case SCF_ERROR_HANDLE_MISMATCH: 3757 case SCF_ERROR_INVALID_ARGUMENT: 3758 case SCF_ERROR_NOT_SET: 3759 default: 3760 bad_error("scf_snaplevel_get_pg", scf_error()); 3761 } 3762 } 3763 3764 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 3765 snap_lastimport); 3766 switch (r) { 3767 case 0: 3768 break; 3769 3770 case ECANCELED: 3771 case ECONNABORTED: 3772 case ENOMEM: 3773 case EBADF: 3774 return (r); 3775 3776 case EACCES: 3777 default: 3778 bad_error("load_pg", r); 3779 } 3780 3781 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) { 3782 /* no change, leave customizations */ 3783 internal_pgroup_free(old_dpt_pgroup); 3784 return (0); 3785 } 3786 break; 3787 3788 case -1: 3789 warn(li_corrupt, ient->sc_fmri); 3790 return (EBADF); 3791 3792 case -2: 3793 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"), 3794 ud_name, new_dpt_pgroup->sc_pgroup_fmri); 3795 return (EINVAL); 3796 3797 default: 3798 bad_error("fmri_equal", r); 3799 } 3800 3801 /* 3802 * The dependent has changed in the manifest. Upgrade the current 3803 * properties if they haven't been customized. 3804 */ 3805 3806 /* 3807 * If new_dpt_pgroup->sc_override, then act as though the property 3808 * group hasn't been customized. 3809 */ 3810 if (new_dpt_pgroup->sc_pgroup_override) 3811 goto nocust; 3812 3813 if (!ud_run_dpts_pg_set) { 3814 warn(cf_missing, ient->sc_fmri, ud_name); 3815 r = 0; 3816 goto out; 3817 } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) { 3818 switch (scf_error()) { 3819 case SCF_ERROR_NOT_FOUND: 3820 warn(cf_missing, ient->sc_fmri, ud_name); 3821 r = 0; 3822 goto out; 3823 3824 case SCF_ERROR_CONNECTION_BROKEN: 3825 r = scferror2errno(scf_error()); 3826 goto out; 3827 3828 case SCF_ERROR_DELETED: 3829 warn(emsg_pg_deleted, ient->sc_fmri, "dependents"); 3830 r = EBUSY; 3831 goto out; 3832 3833 case SCF_ERROR_INVALID_ARGUMENT: 3834 case SCF_ERROR_NOT_BOUND: 3835 case SCF_ERROR_HANDLE_MISMATCH: 3836 case SCF_ERROR_NOT_SET: 3837 default: 3838 bad_error("scf_pg_get_property", scf_error()); 3839 } 3840 } 3841 3842 if (scf_property_get_value(ud_prop, ud_val) != 0) { 3843 switch (scf_error()) { 3844 case SCF_ERROR_NOT_FOUND: 3845 case SCF_ERROR_CONSTRAINT_VIOLATED: 3846 warn(cf_inval, ient->sc_fmri, ud_name); 3847 r = 0; 3848 goto out; 3849 3850 case SCF_ERROR_DELETED: 3851 case SCF_ERROR_CONNECTION_BROKEN: 3852 r = scferror2errno(scf_error()); 3853 goto out; 3854 3855 case SCF_ERROR_HANDLE_MISMATCH: 3856 case SCF_ERROR_NOT_BOUND: 3857 case SCF_ERROR_NOT_SET: 3858 case SCF_ERROR_PERMISSION_DENIED: 3859 default: 3860 bad_error("scf_property_get_value", scf_error()); 3861 } 3862 } 3863 3864 ty = scf_value_type(ud_val); 3865 assert(ty != SCF_TYPE_INVALID); 3866 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 3867 warn(cf_inval, ient->sc_fmri, ud_name); 3868 r = 0; 3869 goto out; 3870 } 3871 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 3872 0) 3873 bad_error("scf_value_get_as_string", scf_error()); 3874 3875 r = fmri_equal(ud_ctarg, ud_oldtarg); 3876 if (r == -1) { 3877 warn(cf_inval, ient->sc_fmri, ud_name); 3878 r = 0; 3879 goto out; 3880 } else if (r == -2) { 3881 warn(li_corrupt, ient->sc_fmri); 3882 r = EBADF; 3883 goto out; 3884 } else if (r == 0) { 3885 /* 3886 * Target has been changed. Only abort now if it's been 3887 * changed to something other than what's in the manifest. 3888 */ 3889 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 3890 if (r == -1) { 3891 warn(cf_inval, ient->sc_fmri, ud_name); 3892 r = 0; 3893 goto out; 3894 } else if (r == 0) { 3895 warn(cf_newtarg, ient->sc_fmri, ud_name); 3896 r = 0; 3897 goto out; 3898 } else if (r != 1) { 3899 /* invalid sc_pgroup_fmri caught above */ 3900 bad_error("fmri_equal", r); 3901 } 3902 3903 /* 3904 * Fetch the current dependency pg. If it's what the manifest 3905 * says, then no problem. 3906 */ 3907 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 3908 switch (serr) { 3909 case SCF_ERROR_NONE: 3910 break; 3911 3912 case SCF_ERROR_NOT_FOUND: 3913 warn(cf_missing, ient->sc_fmri, ud_name); 3914 r = 0; 3915 goto out; 3916 3917 case SCF_ERROR_NO_MEMORY: 3918 r = ENOMEM; 3919 goto out; 3920 3921 case SCF_ERROR_CONSTRAINT_VIOLATED: 3922 case SCF_ERROR_INVALID_ARGUMENT: 3923 default: 3924 bad_error("fmri_to_entity", serr); 3925 } 3926 3927 r = entity_get_running_pg(target_ent, tissvc, ud_name, 3928 ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl); 3929 switch (r) { 3930 case 0: 3931 break; 3932 3933 case ECONNABORTED: 3934 goto out; 3935 3936 case ECANCELED: 3937 case ENOENT: 3938 warn(cf_missing, ient->sc_fmri, ud_name); 3939 r = 0; 3940 goto out; 3941 3942 case EBADF: 3943 warn(r_no_lvl, ud_ctarg); 3944 goto out; 3945 3946 case EINVAL: 3947 default: 3948 bad_error("entity_get_running_pg", r); 3949 } 3950 3951 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 3952 switch (r) { 3953 case 0: 3954 break; 3955 3956 case ECANCELED: 3957 warn(cf_missing, ient->sc_fmri, ud_name); 3958 r = 0; 3959 goto out; 3960 3961 case ECONNABORTED: 3962 case ENOMEM: 3963 case EBADF: 3964 goto out; 3965 3966 case EACCES: 3967 default: 3968 bad_error("load_pg", r); 3969 } 3970 3971 if (!pg_equal(current_pg, new_dpt_pgroup)) 3972 warn(cf_newdpg, ient->sc_fmri, ud_name); 3973 internal_pgroup_free(current_pg); 3974 r = 0; 3975 goto out; 3976 } else if (r != 1) { 3977 bad_error("fmri_equal", r); 3978 } 3979 3980 nocust: 3981 /* 3982 * Target has not been customized. Check the dependency property 3983 * group. 3984 */ 3985 3986 if (old_dpt_pgroup == NULL) { 3987 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name, 3988 ud_pg) != 0) { 3989 switch (scf_error()) { 3990 case SCF_ERROR_NOT_FOUND: 3991 warn(li_corrupt, ient->sc_fmri); 3992 return (EBADF); 3993 3994 case SCF_ERROR_DELETED: 3995 case SCF_ERROR_CONNECTION_BROKEN: 3996 return (scferror2errno(scf_error())); 3997 3998 case SCF_ERROR_NOT_BOUND: 3999 case SCF_ERROR_HANDLE_MISMATCH: 4000 case SCF_ERROR_INVALID_ARGUMENT: 4001 case SCF_ERROR_NOT_SET: 4002 default: 4003 bad_error("scf_snaplevel_get_pg", scf_error()); 4004 } 4005 } 4006 4007 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri, 4008 snap_lastimport); 4009 switch (r) { 4010 case 0: 4011 break; 4012 4013 case ECANCELED: 4014 case ECONNABORTED: 4015 case ENOMEM: 4016 case EBADF: 4017 return (r); 4018 4019 case EACCES: 4020 default: 4021 bad_error("load_pg", r); 4022 } 4023 } 4024 4025 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc); 4026 switch (serr) { 4027 case SCF_ERROR_NONE: 4028 break; 4029 4030 case SCF_ERROR_NOT_FOUND: 4031 warn(cf_missing, ient->sc_fmri, ud_name); 4032 r = 0; 4033 goto out; 4034 4035 case SCF_ERROR_NO_MEMORY: 4036 r = ENOMEM; 4037 goto out; 4038 4039 case SCF_ERROR_CONSTRAINT_VIOLATED: 4040 case SCF_ERROR_INVALID_ARGUMENT: 4041 default: 4042 bad_error("fmri_to_entity", serr); 4043 } 4044 4045 r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg, 4046 ud_iter2, ud_inst, imp_snap, ud_snpl); 4047 switch (r) { 4048 case 0: 4049 break; 4050 4051 case ECONNABORTED: 4052 goto out; 4053 4054 case ECANCELED: 4055 case ENOENT: 4056 warn(cf_missing, ient->sc_fmri, ud_name); 4057 r = 0; 4058 goto out; 4059 4060 case EBADF: 4061 warn(r_no_lvl, ud_ctarg); 4062 goto out; 4063 4064 case EINVAL: 4065 default: 4066 bad_error("entity_get_running_pg", r); 4067 } 4068 4069 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4070 switch (r) { 4071 case 0: 4072 break; 4073 4074 case ECANCELED: 4075 warn(cf_missing, ient->sc_fmri, ud_name); 4076 goto out; 4077 4078 case ECONNABORTED: 4079 case ENOMEM: 4080 case EBADF: 4081 goto out; 4082 4083 case EACCES: 4084 default: 4085 bad_error("load_pg", r); 4086 } 4087 4088 if (!pg_equal(current_pg, old_dpt_pgroup)) { 4089 if (!pg_equal(current_pg, new_dpt_pgroup)) 4090 warn(cf_newdpg, ient->sc_fmri, ud_name); 4091 internal_pgroup_free(current_pg); 4092 r = 0; 4093 goto out; 4094 } 4095 4096 /* Uncustomized. Upgrade. */ 4097 4098 r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg); 4099 switch (r) { 4100 case 1: 4101 if (pg_equal(current_pg, new_dpt_pgroup)) { 4102 /* Already upgraded. */ 4103 internal_pgroup_free(current_pg); 4104 r = 0; 4105 goto out; 4106 } 4107 4108 internal_pgroup_free(current_pg); 4109 4110 /* upgrade current_pg */ 4111 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4112 switch (scf_error()) { 4113 case SCF_ERROR_CONNECTION_BROKEN: 4114 r = scferror2errno(scf_error()); 4115 goto out; 4116 4117 case SCF_ERROR_DELETED: 4118 warn(cf_missing, ient->sc_fmri, ud_name); 4119 r = 0; 4120 goto out; 4121 4122 case SCF_ERROR_NOT_FOUND: 4123 break; 4124 4125 case SCF_ERROR_INVALID_ARGUMENT: 4126 case SCF_ERROR_NOT_BOUND: 4127 case SCF_ERROR_NOT_SET: 4128 case SCF_ERROR_HANDLE_MISMATCH: 4129 default: 4130 bad_error("entity_get_pg", scf_error()); 4131 } 4132 4133 if (tissvc) 4134 r = scf_service_add_pg(target_ent, ud_name, 4135 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4136 else 4137 r = scf_instance_add_pg(target_ent, ud_name, 4138 SCF_GROUP_DEPENDENCY, 0, ud_pg); 4139 if (r != 0) { 4140 switch (scf_error()) { 4141 case SCF_ERROR_CONNECTION_BROKEN: 4142 case SCF_ERROR_NO_RESOURCES: 4143 case SCF_ERROR_BACKEND_READONLY: 4144 case SCF_ERROR_BACKEND_ACCESS: 4145 r = scferror2errno(scf_error()); 4146 goto out; 4147 4148 case SCF_ERROR_DELETED: 4149 warn(cf_missing, ient->sc_fmri, 4150 ud_name); 4151 r = 0; 4152 goto out; 4153 4154 case SCF_ERROR_PERMISSION_DENIED: 4155 warn(emsg_pg_deleted, ud_ctarg, 4156 ud_name); 4157 r = EPERM; 4158 goto out; 4159 4160 case SCF_ERROR_EXISTS: 4161 warn(emsg_pg_added, ud_ctarg, ud_name); 4162 r = EBUSY; 4163 goto out; 4164 4165 case SCF_ERROR_NOT_BOUND: 4166 case SCF_ERROR_HANDLE_MISMATCH: 4167 case SCF_ERROR_INVALID_ARGUMENT: 4168 case SCF_ERROR_NOT_SET: 4169 default: 4170 bad_error("entity_add_pg", scf_error()); 4171 } 4172 } 4173 } 4174 4175 r = load_pg(ud_pg, ¤t_pg, ud_ctarg, NULL); 4176 switch (r) { 4177 case 0: 4178 break; 4179 4180 case ECANCELED: 4181 warn(cf_missing, ient->sc_fmri, ud_name); 4182 goto out; 4183 4184 case ECONNABORTED: 4185 case ENOMEM: 4186 case EBADF: 4187 goto out; 4188 4189 case EACCES: 4190 default: 4191 bad_error("load_pg", r); 4192 } 4193 4194 if (g_verbose) 4195 warn(upgrading, ient->sc_fmri, ud_name); 4196 4197 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup, 4198 new_dpt_pgroup, 0, ient->sc_fmri); 4199 switch (r) { 4200 case 0: 4201 break; 4202 4203 case ECANCELED: 4204 warn(emsg_pg_deleted, ud_ctarg, ud_name); 4205 r = EBUSY; 4206 goto out; 4207 4208 case EPERM: 4209 warn(emsg_pg_mod_perm, ud_name, ud_ctarg); 4210 goto out; 4211 4212 case EBUSY: 4213 warn(emsg_pg_changed, ud_ctarg, ud_name); 4214 goto out; 4215 4216 case ECONNABORTED: 4217 case ENOMEM: 4218 case ENOSPC: 4219 case EROFS: 4220 case EACCES: 4221 case EINVAL: 4222 goto out; 4223 4224 default: 4225 bad_error("upgrade_pg", r); 4226 } 4227 break; 4228 4229 case 0: { 4230 scf_transaction_entry_t *ent; 4231 scf_value_t *val; 4232 4233 internal_pgroup_free(current_pg); 4234 4235 /* delete old pg */ 4236 if (g_verbose) 4237 warn(upgrading, ient->sc_fmri, ud_name); 4238 4239 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) { 4240 switch (scf_error()) { 4241 case SCF_ERROR_CONNECTION_BROKEN: 4242 r = scferror2errno(scf_error()); 4243 goto out; 4244 4245 case SCF_ERROR_DELETED: 4246 warn(cf_missing, ient->sc_fmri, ud_name); 4247 r = 0; 4248 goto out; 4249 4250 case SCF_ERROR_NOT_FOUND: 4251 break; 4252 4253 case SCF_ERROR_INVALID_ARGUMENT: 4254 case SCF_ERROR_NOT_BOUND: 4255 case SCF_ERROR_NOT_SET: 4256 case SCF_ERROR_HANDLE_MISMATCH: 4257 default: 4258 bad_error("entity_get_pg", scf_error()); 4259 } 4260 } else if (scf_pg_delete(ud_pg) != 0) { 4261 switch (scf_error()) { 4262 case SCF_ERROR_DELETED: 4263 break; 4264 4265 case SCF_ERROR_CONNECTION_BROKEN: 4266 case SCF_ERROR_BACKEND_READONLY: 4267 case SCF_ERROR_BACKEND_ACCESS: 4268 r = scferror2errno(scf_error()); 4269 goto out; 4270 4271 case SCF_ERROR_PERMISSION_DENIED: 4272 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri); 4273 r = scferror2errno(scf_error()); 4274 goto out; 4275 4276 case SCF_ERROR_NOT_SET: 4277 default: 4278 bad_error("scf_pg_delete", scf_error()); 4279 } 4280 } 4281 4282 /* import new one */ 4283 cbdata.sc_handle = g_hndl; 4284 cbdata.sc_trans = NULL; /* handled below */ 4285 4286 r = lscf_dependent_import(new_dpt_pgroup, &cbdata); 4287 if (r != UU_WALK_NEXT) { 4288 if (r != UU_WALK_ERROR) 4289 bad_error("lscf_dependent_import", r); 4290 4291 r = cbdata.sc_err; 4292 goto out; 4293 } 4294 4295 if (tx == NULL) 4296 break; 4297 4298 if ((ent = scf_entry_create(g_hndl)) == NULL || 4299 (val = scf_value_create(g_hndl)) == NULL) { 4300 if (scf_error() == SCF_ERROR_NO_MEMORY) 4301 return (ENOMEM); 4302 4303 bad_error("scf_entry_create", scf_error()); 4304 } 4305 4306 if (scf_transaction_property_change_type(tx, ent, ud_name, 4307 SCF_TYPE_FMRI) != 0) { 4308 switch (scf_error()) { 4309 case SCF_ERROR_CONNECTION_BROKEN: 4310 r = scferror2errno(scf_error()); 4311 goto out; 4312 4313 case SCF_ERROR_DELETED: 4314 warn(emsg_pg_deleted, ient->sc_fmri, 4315 "dependents"); 4316 r = EBUSY; 4317 goto out; 4318 4319 case SCF_ERROR_NOT_FOUND: 4320 break; 4321 4322 case SCF_ERROR_NOT_BOUND: 4323 case SCF_ERROR_HANDLE_MISMATCH: 4324 case SCF_ERROR_INVALID_ARGUMENT: 4325 case SCF_ERROR_NOT_SET: 4326 default: 4327 bad_error("scf_transaction_property_" 4328 "change_type", scf_error()); 4329 } 4330 4331 if (scf_transaction_property_new(tx, ent, ud_name, 4332 SCF_TYPE_FMRI) != 0) { 4333 switch (scf_error()) { 4334 case SCF_ERROR_CONNECTION_BROKEN: 4335 r = scferror2errno(scf_error()); 4336 goto out; 4337 4338 case SCF_ERROR_DELETED: 4339 warn(emsg_pg_deleted, ient->sc_fmri, 4340 "dependents"); 4341 r = EBUSY; 4342 goto out; 4343 4344 case SCF_ERROR_EXISTS: 4345 warn(emsg_pg_changed, ient->sc_fmri, 4346 "dependents"); 4347 r = EBUSY; 4348 goto out; 4349 4350 case SCF_ERROR_INVALID_ARGUMENT: 4351 case SCF_ERROR_HANDLE_MISMATCH: 4352 case SCF_ERROR_NOT_BOUND: 4353 case SCF_ERROR_NOT_SET: 4354 default: 4355 bad_error("scf_transaction_property_" 4356 "new", scf_error()); 4357 } 4358 } 4359 } 4360 4361 if (scf_value_set_from_string(val, SCF_TYPE_FMRI, 4362 new_dpt_pgroup->sc_pgroup_fmri) != 0) 4363 /* invalid sc_pgroup_fmri caught above */ 4364 bad_error("scf_value_set_from_string", 4365 scf_error()); 4366 4367 if (scf_entry_add_value(ent, val) != 0) 4368 bad_error("scf_entry_add_value", scf_error()); 4369 break; 4370 } 4371 4372 case -2: 4373 warn(li_corrupt, ient->sc_fmri); 4374 internal_pgroup_free(current_pg); 4375 r = EBADF; 4376 goto out; 4377 4378 case -1: 4379 default: 4380 /* invalid sc_pgroup_fmri caught above */ 4381 bad_error("fmri_equal", r); 4382 } 4383 4384 r = 0; 4385 4386 out: 4387 if (old_dpt_pgroup != NULL) 4388 internal_pgroup_free(old_dpt_pgroup); 4389 4390 return (r); 4391 } 4392 4393 /* 4394 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we 4395 * would import it, except it seems to exist in the service anyway. Compare 4396 * the existent dependent with the one we would import, and report any 4397 * differences (if there are none, be silent). prop is the property which 4398 * represents the existent dependent (in the dependents property group) in the 4399 * entity corresponding to ient. 4400 * 4401 * Returns 4402 * 0 - success (Sort of. At least, we can continue importing.) 4403 * ECONNABORTED - repository connection broken 4404 * EBUSY - ancestor of prop was deleted (error printed) 4405 * ENOMEM - out of memory 4406 * EBADF - corrupt property group (error printed) 4407 * EINVAL - new_dpt_pgroup has invalid target (error printed) 4408 */ 4409 static int 4410 handle_dependent_conflict(const entity_t * const ient, 4411 const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup) 4412 { 4413 int r; 4414 scf_type_t ty; 4415 scf_error_t scfe; 4416 void *tptr; 4417 int tissvc; 4418 pgroup_t *pgroup; 4419 4420 if (scf_property_get_value(prop, ud_val) != 0) { 4421 switch (scf_error()) { 4422 case SCF_ERROR_CONNECTION_BROKEN: 4423 return (scferror2errno(scf_error())); 4424 4425 case SCF_ERROR_DELETED: 4426 warn(emsg_pg_deleted, ient->sc_fmri, 4427 new_dpt_pgroup->sc_pgroup_name); 4428 return (EBUSY); 4429 4430 case SCF_ERROR_CONSTRAINT_VIOLATED: 4431 case SCF_ERROR_NOT_FOUND: 4432 warn(gettext("Conflict upgrading %s (not importing " 4433 "dependent \"%s\" because it already exists.) " 4434 "Warning: The \"%s/%2$s\" property has more or " 4435 "fewer than one value)).\n"), ient->sc_fmri, 4436 new_dpt_pgroup->sc_pgroup_name, "dependents"); 4437 return (0); 4438 4439 case SCF_ERROR_HANDLE_MISMATCH: 4440 case SCF_ERROR_NOT_BOUND: 4441 case SCF_ERROR_NOT_SET: 4442 case SCF_ERROR_PERMISSION_DENIED: 4443 default: 4444 bad_error("scf_property_get_value", 4445 scf_error()); 4446 } 4447 } 4448 4449 ty = scf_value_type(ud_val); 4450 assert(ty != SCF_TYPE_INVALID); 4451 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) { 4452 warn(gettext("Conflict upgrading %s (not importing dependent " 4453 "\"%s\" because it already exists). Warning: The " 4454 "\"%s/%s\" property has unexpected type \"%s\")).\n"), 4455 ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name, 4456 scf_type_to_string(ty), "dependents"); 4457 return (0); 4458 } 4459 4460 if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) < 4461 0) 4462 bad_error("scf_value_get_as_string", scf_error()); 4463 4464 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri); 4465 switch (r) { 4466 case 0: 4467 warn(gettext("Conflict upgrading %s (not importing dependent " 4468 "\"%s\" (target \"%s\") because it already exists with " 4469 "target \"%s\").\n"), ient->sc_fmri, 4470 new_dpt_pgroup->sc_pgroup_name, 4471 new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg); 4472 return (0); 4473 4474 case 1: 4475 break; 4476 4477 case -1: 4478 warn(gettext("Conflict upgrading %s (not importing dependent " 4479 "\"%s\" because it already exists). Warning: The current " 4480 "dependent's target (%s) is invalid.\n"), ient->sc_fmri, 4481 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4482 return (0); 4483 4484 case -2: 4485 warn(gettext("Dependent \"%s\" of %s has invalid target " 4486 "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri, 4487 new_dpt_pgroup->sc_pgroup_fmri); 4488 return (EINVAL); 4489 4490 default: 4491 bad_error("fmri_equal", r); 4492 } 4493 4494 /* compare dependency pgs in target */ 4495 scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc); 4496 switch (scfe) { 4497 case SCF_ERROR_NONE: 4498 break; 4499 4500 case SCF_ERROR_NO_MEMORY: 4501 return (ENOMEM); 4502 4503 case SCF_ERROR_NOT_FOUND: 4504 warn(emsg_dpt_dangling, ient->sc_fmri, 4505 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4506 return (0); 4507 4508 case SCF_ERROR_CONSTRAINT_VIOLATED: 4509 case SCF_ERROR_INVALID_ARGUMENT: 4510 default: 4511 bad_error("fmri_to_entity", scfe); 4512 } 4513 4514 r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name, 4515 ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl); 4516 switch (r) { 4517 case 0: 4518 break; 4519 4520 case ECONNABORTED: 4521 return (r); 4522 4523 case ECANCELED: 4524 warn(emsg_dpt_dangling, ient->sc_fmri, 4525 new_dpt_pgroup->sc_pgroup_name, ud_ctarg); 4526 return (0); 4527 4528 case EBADF: 4529 if (tissvc) 4530 warn(gettext("%s has an instance with a \"%s\" " 4531 "snapshot which is missing a snaplevel.\n"), 4532 ud_ctarg, "running"); 4533 else 4534 warn(gettext("%s has a \"%s\" snapshot which is " 4535 "missing a snaplevel.\n"), ud_ctarg, "running"); 4536 /* FALLTHROUGH */ 4537 4538 case ENOENT: 4539 warn(emsg_dpt_no_dep, ient->sc_fmri, 4540 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4541 new_dpt_pgroup->sc_pgroup_name); 4542 return (0); 4543 4544 case EINVAL: 4545 default: 4546 bad_error("entity_get_running_pg", r); 4547 } 4548 4549 pgroup = internal_pgroup_new(); 4550 if (pgroup == NULL) 4551 return (ENOMEM); 4552 4553 r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL); 4554 switch (r) { 4555 case 0: 4556 break; 4557 4558 case ECONNABORTED: 4559 case EBADF: 4560 case ENOMEM: 4561 internal_pgroup_free(pgroup); 4562 return (r); 4563 4564 case ECANCELED: 4565 warn(emsg_dpt_no_dep, ient->sc_fmri, 4566 new_dpt_pgroup->sc_pgroup_name, ud_ctarg, 4567 new_dpt_pgroup->sc_pgroup_name); 4568 internal_pgroup_free(pgroup); 4569 return (0); 4570 4571 case EACCES: 4572 default: 4573 bad_error("load_pg", r); 4574 } 4575 4576 /* report differences */ 4577 report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1); 4578 internal_pgroup_free(pgroup); 4579 return (0); 4580 } 4581 4582 /* 4583 * lipg is a property group in the last-import snapshot of ent, which is an 4584 * scf_service_t or an scf_instance_t (according to ient). If lipg is not in 4585 * ient's pgroups, delete it from ent if it hasn't been customized. If it is 4586 * in ents's property groups, compare and upgrade ent appropriately. 4587 * 4588 * Returns 4589 * 0 - success 4590 * ECONNABORTED - repository connection broken 4591 * ENOMEM - out of memory 4592 * ENOSPC - configd is out of resources 4593 * EINVAL - ient has invalid dependent (error printed) 4594 * - ient has invalid pgroup_t (error printed) 4595 * ECANCELED - ent has been deleted 4596 * ENODEV - entity containing lipg has been deleted 4597 * - entity containing running has been deleted 4598 * EPERM - could not delete pg (permission denied) (error printed) 4599 * - couldn't upgrade dependents (permission denied) (error printed) 4600 * - couldn't import pg (permission denied) (error printed) 4601 * - couldn't upgrade pg (permission denied) (error printed) 4602 * EROFS - could not delete pg (repository read-only) 4603 * - couldn't upgrade dependents (repository read-only) 4604 * - couldn't import pg (repository read-only) 4605 * - couldn't upgrade pg (repository read-only) 4606 * EACCES - could not delete pg (backend access denied) 4607 * - couldn't upgrade dependents (backend access denied) 4608 * - couldn't import pg (backend access denied) 4609 * - couldn't upgrade pg (backend access denied) 4610 * - couldn't read property (backend access denied) 4611 * EBUSY - property group was added (error printed) 4612 * - property group was deleted (error printed) 4613 * - property group changed (error printed) 4614 * - "dependents" pg was added, changed, or deleted (error printed) 4615 * - dependent target deleted (error printed) 4616 * - dependent pg changed (error printed) 4617 * EBADF - imp_snpl is corrupt (error printed) 4618 * - ent has bad pg (error printed) 4619 * EEXIST - dependent collision in target service (error printed) 4620 */ 4621 static int 4622 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent, 4623 const scf_snaplevel_t *running) 4624 { 4625 int r; 4626 pgroup_t *mpg, *lipg_i, *curpg_i, pgrp; 4627 scf_callback_t cbdata; 4628 4629 const char * const cf_pg_missing = 4630 gettext("Conflict upgrading %s (property group %s is missing)\n"); 4631 const char * const deleting = 4632 gettext("%s: Deleting property group \"%s\".\n"); 4633 4634 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 4635 4636 /* Skip dependent property groups. */ 4637 if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) { 4638 switch (scf_error()) { 4639 case SCF_ERROR_DELETED: 4640 return (ENODEV); 4641 4642 case SCF_ERROR_CONNECTION_BROKEN: 4643 return (ECONNABORTED); 4644 4645 case SCF_ERROR_NOT_SET: 4646 case SCF_ERROR_NOT_BOUND: 4647 default: 4648 bad_error("scf_pg_get_type", scf_error()); 4649 } 4650 } 4651 4652 if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) { 4653 if (scf_pg_get_property(lipg, "external", NULL) == 0) 4654 return (0); 4655 4656 switch (scf_error()) { 4657 case SCF_ERROR_NOT_FOUND: 4658 break; 4659 4660 case SCF_ERROR_CONNECTION_BROKEN: 4661 return (ECONNABORTED); 4662 4663 case SCF_ERROR_DELETED: 4664 return (ENODEV); 4665 4666 case SCF_ERROR_INVALID_ARGUMENT: 4667 case SCF_ERROR_NOT_BOUND: 4668 case SCF_ERROR_HANDLE_MISMATCH: 4669 case SCF_ERROR_NOT_SET: 4670 default: 4671 bad_error("scf_pg_get_property", scf_error()); 4672 } 4673 } 4674 4675 /* lookup pg in new properties */ 4676 if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) { 4677 switch (scf_error()) { 4678 case SCF_ERROR_DELETED: 4679 return (ENODEV); 4680 4681 case SCF_ERROR_CONNECTION_BROKEN: 4682 return (ECONNABORTED); 4683 4684 case SCF_ERROR_NOT_SET: 4685 case SCF_ERROR_NOT_BOUND: 4686 default: 4687 bad_error("scf_pg_get_name", scf_error()); 4688 } 4689 } 4690 4691 pgrp.sc_pgroup_name = imp_str; 4692 mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL); 4693 4694 if (mpg != NULL) 4695 mpg->sc_pgroup_seen = 1; 4696 4697 /* Special handling for dependents */ 4698 if (strcmp(imp_str, "dependents") == 0) 4699 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent)); 4700 4701 if (mpg == NULL || mpg->sc_pgroup_delete) { 4702 /* property group was deleted from manifest */ 4703 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 4704 switch (scf_error()) { 4705 case SCF_ERROR_NOT_FOUND: 4706 return (0); 4707 4708 case SCF_ERROR_DELETED: 4709 case SCF_ERROR_CONNECTION_BROKEN: 4710 return (scferror2errno(scf_error())); 4711 4712 case SCF_ERROR_INVALID_ARGUMENT: 4713 case SCF_ERROR_HANDLE_MISMATCH: 4714 case SCF_ERROR_NOT_BOUND: 4715 case SCF_ERROR_NOT_SET: 4716 default: 4717 bad_error("entity_get_pg", scf_error()); 4718 } 4719 } 4720 4721 if (mpg != NULL && mpg->sc_pgroup_delete) { 4722 if (g_verbose) 4723 warn(deleting, ient->sc_fmri, imp_str); 4724 if (scf_pg_delete(imp_pg2) == 0) 4725 return (0); 4726 4727 switch (scf_error()) { 4728 case SCF_ERROR_DELETED: 4729 return (0); 4730 4731 case SCF_ERROR_CONNECTION_BROKEN: 4732 case SCF_ERROR_BACKEND_READONLY: 4733 case SCF_ERROR_BACKEND_ACCESS: 4734 return (scferror2errno(scf_error())); 4735 4736 case SCF_ERROR_PERMISSION_DENIED: 4737 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri); 4738 return (scferror2errno(scf_error())); 4739 4740 case SCF_ERROR_NOT_SET: 4741 default: 4742 bad_error("scf_pg_delete", scf_error()); 4743 } 4744 } 4745 4746 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 4747 switch (r) { 4748 case 0: 4749 break; 4750 4751 case ECANCELED: 4752 return (ENODEV); 4753 4754 case ECONNABORTED: 4755 case ENOMEM: 4756 case EBADF: 4757 case EACCES: 4758 return (r); 4759 4760 default: 4761 bad_error("load_pg", r); 4762 } 4763 4764 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 4765 switch (r) { 4766 case 0: 4767 break; 4768 4769 case ECANCELED: 4770 case ECONNABORTED: 4771 case ENOMEM: 4772 case EBADF: 4773 case EACCES: 4774 internal_pgroup_free(lipg_i); 4775 return (r); 4776 4777 default: 4778 bad_error("load_pg", r); 4779 } 4780 4781 if (pg_equal(lipg_i, curpg_i)) { 4782 if (g_verbose) 4783 warn(deleting, ient->sc_fmri, imp_str); 4784 if (scf_pg_delete(imp_pg2) != 0) { 4785 switch (scf_error()) { 4786 case SCF_ERROR_DELETED: 4787 break; 4788 4789 case SCF_ERROR_CONNECTION_BROKEN: 4790 internal_pgroup_free(lipg_i); 4791 internal_pgroup_free(curpg_i); 4792 return (ECONNABORTED); 4793 4794 case SCF_ERROR_NOT_SET: 4795 case SCF_ERROR_NOT_BOUND: 4796 default: 4797 bad_error("scf_pg_delete", scf_error()); 4798 } 4799 } 4800 } else { 4801 report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0); 4802 } 4803 4804 internal_pgroup_free(lipg_i); 4805 internal_pgroup_free(curpg_i); 4806 4807 return (0); 4808 } 4809 4810 /* 4811 * Only dependent pgs can have override set, and we skipped those 4812 * above. 4813 */ 4814 assert(!mpg->sc_pgroup_override); 4815 4816 /* compare */ 4817 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport); 4818 switch (r) { 4819 case 0: 4820 break; 4821 4822 case ECANCELED: 4823 return (ENODEV); 4824 4825 case ECONNABORTED: 4826 case EBADF: 4827 case ENOMEM: 4828 case EACCES: 4829 return (r); 4830 4831 default: 4832 bad_error("load_pg", r); 4833 } 4834 4835 if (pg_equal(mpg, lipg_i)) { 4836 /* The manifest pg has not changed. Move on. */ 4837 r = 0; 4838 goto out; 4839 } 4840 4841 /* upgrade current properties according to lipg & mpg */ 4842 if (running != NULL) 4843 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2); 4844 else 4845 r = entity_get_pg(ent, issvc, imp_str, imp_pg2); 4846 if (r != 0) { 4847 switch (scf_error()) { 4848 case SCF_ERROR_CONNECTION_BROKEN: 4849 r = scferror2errno(scf_error()); 4850 goto out; 4851 4852 case SCF_ERROR_DELETED: 4853 if (running != NULL) 4854 r = ENODEV; 4855 else 4856 r = ECANCELED; 4857 goto out; 4858 4859 case SCF_ERROR_NOT_FOUND: 4860 break; 4861 4862 case SCF_ERROR_INVALID_ARGUMENT: 4863 case SCF_ERROR_HANDLE_MISMATCH: 4864 case SCF_ERROR_NOT_BOUND: 4865 case SCF_ERROR_NOT_SET: 4866 default: 4867 bad_error("entity_get_pg", scf_error()); 4868 } 4869 4870 warn(cf_pg_missing, ient->sc_fmri, imp_str); 4871 4872 r = 0; 4873 goto out; 4874 } 4875 4876 r = load_pg_attrs(imp_pg2, &curpg_i); 4877 switch (r) { 4878 case 0: 4879 break; 4880 4881 case ECANCELED: 4882 warn(cf_pg_missing, ient->sc_fmri, imp_str); 4883 r = 0; 4884 goto out; 4885 4886 case ECONNABORTED: 4887 case ENOMEM: 4888 goto out; 4889 4890 default: 4891 bad_error("load_pg_attrs", r); 4892 } 4893 4894 if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) { 4895 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0); 4896 internal_pgroup_free(curpg_i); 4897 r = 0; 4898 goto out; 4899 } 4900 4901 internal_pgroup_free(curpg_i); 4902 4903 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL); 4904 switch (r) { 4905 case 0: 4906 break; 4907 4908 case ECANCELED: 4909 warn(cf_pg_missing, ient->sc_fmri, imp_str); 4910 r = 0; 4911 goto out; 4912 4913 case ECONNABORTED: 4914 case EBADF: 4915 case ENOMEM: 4916 case EACCES: 4917 goto out; 4918 4919 default: 4920 bad_error("load_pg", r); 4921 } 4922 4923 if (pg_equal(lipg_i, curpg_i) && 4924 !pg_attrs_equal(lipg_i, mpg, NULL, 0)) { 4925 int do_delete = 1; 4926 4927 if (g_verbose) 4928 warn(gettext("%s: Upgrading property group \"%s\".\n"), 4929 ient->sc_fmri, mpg->sc_pgroup_name); 4930 4931 internal_pgroup_free(curpg_i); 4932 4933 if (running != NULL && 4934 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 4935 switch (scf_error()) { 4936 case SCF_ERROR_DELETED: 4937 r = ECANCELED; 4938 goto out; 4939 4940 case SCF_ERROR_NOT_FOUND: 4941 do_delete = 0; 4942 break; 4943 4944 case SCF_ERROR_CONNECTION_BROKEN: 4945 r = scferror2errno(scf_error()); 4946 goto out; 4947 4948 case SCF_ERROR_HANDLE_MISMATCH: 4949 case SCF_ERROR_INVALID_ARGUMENT: 4950 case SCF_ERROR_NOT_SET: 4951 case SCF_ERROR_NOT_BOUND: 4952 default: 4953 bad_error("entity_get_pg", scf_error()); 4954 } 4955 } 4956 4957 if (do_delete && scf_pg_delete(imp_pg2) != 0) { 4958 switch (scf_error()) { 4959 case SCF_ERROR_DELETED: 4960 break; 4961 4962 case SCF_ERROR_CONNECTION_BROKEN: 4963 case SCF_ERROR_BACKEND_READONLY: 4964 case SCF_ERROR_BACKEND_ACCESS: 4965 r = scferror2errno(scf_error()); 4966 goto out; 4967 4968 case SCF_ERROR_PERMISSION_DENIED: 4969 warn(emsg_pg_del_perm, mpg->sc_pgroup_name, 4970 ient->sc_fmri); 4971 r = scferror2errno(scf_error()); 4972 goto out; 4973 4974 case SCF_ERROR_NOT_SET: 4975 case SCF_ERROR_NOT_BOUND: 4976 default: 4977 bad_error("scf_pg_delete", scf_error()); 4978 } 4979 } 4980 4981 cbdata.sc_handle = g_hndl; 4982 cbdata.sc_parent = ent; 4983 cbdata.sc_service = issvc; 4984 cbdata.sc_flags = 0; 4985 cbdata.sc_source_fmri = ient->sc_fmri; 4986 cbdata.sc_target_fmri = ient->sc_fmri; 4987 4988 r = entity_pgroup_import(mpg, &cbdata); 4989 switch (r) { 4990 case UU_WALK_NEXT: 4991 r = 0; 4992 goto out; 4993 4994 case UU_WALK_ERROR: 4995 if (cbdata.sc_err == EEXIST) { 4996 warn(emsg_pg_added, ient->sc_fmri, 4997 mpg->sc_pgroup_name); 4998 r = EBUSY; 4999 } else { 5000 r = cbdata.sc_err; 5001 } 5002 goto out; 5003 5004 default: 5005 bad_error("entity_pgroup_import", r); 5006 } 5007 } 5008 5009 if (running != NULL && 5010 entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) { 5011 switch (scf_error()) { 5012 case SCF_ERROR_CONNECTION_BROKEN: 5013 case SCF_ERROR_DELETED: 5014 r = scferror2errno(scf_error()); 5015 goto out; 5016 5017 case SCF_ERROR_NOT_FOUND: 5018 break; 5019 5020 case SCF_ERROR_HANDLE_MISMATCH: 5021 case SCF_ERROR_INVALID_ARGUMENT: 5022 case SCF_ERROR_NOT_SET: 5023 case SCF_ERROR_NOT_BOUND: 5024 default: 5025 bad_error("entity_get_pg", scf_error()); 5026 } 5027 5028 cbdata.sc_handle = g_hndl; 5029 cbdata.sc_parent = ent; 5030 cbdata.sc_service = issvc; 5031 cbdata.sc_flags = SCI_FORCE; 5032 cbdata.sc_source_fmri = ient->sc_fmri; 5033 cbdata.sc_target_fmri = ient->sc_fmri; 5034 5035 r = entity_pgroup_import(mpg, &cbdata); 5036 switch (r) { 5037 case UU_WALK_NEXT: 5038 r = 0; 5039 goto out; 5040 5041 case UU_WALK_ERROR: 5042 if (cbdata.sc_err == EEXIST) { 5043 warn(emsg_pg_added, ient->sc_fmri, 5044 mpg->sc_pgroup_name); 5045 r = EBUSY; 5046 } else { 5047 r = cbdata.sc_err; 5048 } 5049 goto out; 5050 5051 default: 5052 bad_error("entity_pgroup_import", r); 5053 } 5054 } 5055 5056 r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri); 5057 internal_pgroup_free(curpg_i); 5058 switch (r) { 5059 case 0: 5060 ient->sc_import_state = IMPORT_PROP_BEGUN; 5061 break; 5062 5063 case ECANCELED: 5064 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name); 5065 r = EBUSY; 5066 break; 5067 5068 case EPERM: 5069 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri); 5070 break; 5071 5072 case EBUSY: 5073 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name); 5074 break; 5075 5076 case ECONNABORTED: 5077 case ENOMEM: 5078 case ENOSPC: 5079 case EROFS: 5080 case EACCES: 5081 case EINVAL: 5082 break; 5083 5084 default: 5085 bad_error("upgrade_pg", r); 5086 } 5087 5088 out: 5089 internal_pgroup_free(lipg_i); 5090 return (r); 5091 } 5092 5093 /* 5094 * Upgrade the properties of ent according to snpl & ient. 5095 * 5096 * Returns 5097 * 0 - success 5098 * ECONNABORTED - repository connection broken 5099 * ENOMEM - out of memory 5100 * ENOSPC - configd is out of resources 5101 * ECANCELED - ent was deleted 5102 * ENODEV - entity containing snpl was deleted 5103 * - entity containing running was deleted 5104 * EBADF - imp_snpl is corrupt (error printed) 5105 * - ent has corrupt pg (error printed) 5106 * - dependent has corrupt pg (error printed) 5107 * - dependent target has a corrupt snapshot (error printed) 5108 * EBUSY - pg was added, changed, or deleted (error printed) 5109 * - dependent target was deleted (error printed) 5110 * - dependent pg changed (error printed) 5111 * EINVAL - invalid property group name (error printed) 5112 * - invalid property name (error printed) 5113 * - invalid value (error printed) 5114 * - ient has invalid pgroup or dependent (error printed) 5115 * EPERM - could not create property group (permission denied) (error printed) 5116 * - could not modify property group (permission denied) (error printed) 5117 * - couldn't delete, upgrade, or import pg or dependent (error printed) 5118 * EROFS - could not create property group (repository read-only) 5119 * - couldn't delete, upgrade, or import pg or dependent 5120 * EACCES - could not create property group (backend access denied) 5121 * - couldn't delete, upgrade, or import pg or dependent 5122 * EEXIST - dependent collision in target service (error printed) 5123 */ 5124 static int 5125 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl, 5126 entity_t *ient) 5127 { 5128 pgroup_t *pg, *rpg; 5129 int r; 5130 uu_list_t *pgs = ient->sc_pgroups; 5131 5132 const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT); 5133 5134 /* clear sc_sceen for pgs */ 5135 if (uu_list_walk(pgs, clear_int, 5136 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0) 5137 bad_error("uu_list_walk", uu_error()); 5138 5139 if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) { 5140 switch (scf_error()) { 5141 case SCF_ERROR_DELETED: 5142 return (ENODEV); 5143 5144 case SCF_ERROR_CONNECTION_BROKEN: 5145 return (ECONNABORTED); 5146 5147 case SCF_ERROR_NOT_SET: 5148 case SCF_ERROR_NOT_BOUND: 5149 case SCF_ERROR_HANDLE_MISMATCH: 5150 default: 5151 bad_error("scf_iter_snaplevel_pgs", scf_error()); 5152 } 5153 } 5154 5155 for (;;) { 5156 r = scf_iter_next_pg(imp_up_iter, imp_pg); 5157 if (r == 0) 5158 break; 5159 if (r == 1) { 5160 r = process_old_pg(imp_pg, ient, ent, running); 5161 switch (r) { 5162 case 0: 5163 break; 5164 5165 case ECONNABORTED: 5166 case ENOMEM: 5167 case ENOSPC: 5168 case ECANCELED: 5169 case ENODEV: 5170 case EPERM: 5171 case EROFS: 5172 case EACCES: 5173 case EBADF: 5174 case EBUSY: 5175 case EINVAL: 5176 case EEXIST: 5177 return (r); 5178 5179 default: 5180 bad_error("process_old_pg", r); 5181 } 5182 continue; 5183 } 5184 if (r != -1) 5185 bad_error("scf_iter_next_pg", r); 5186 5187 switch (scf_error()) { 5188 case SCF_ERROR_DELETED: 5189 return (ENODEV); 5190 5191 case SCF_ERROR_CONNECTION_BROKEN: 5192 return (ECONNABORTED); 5193 5194 case SCF_ERROR_HANDLE_MISMATCH: 5195 case SCF_ERROR_NOT_BOUND: 5196 case SCF_ERROR_NOT_SET: 5197 case SCF_ERROR_INVALID_ARGUMENT: 5198 default: 5199 bad_error("scf_iter_next_pg", scf_error()); 5200 } 5201 } 5202 5203 for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) { 5204 if (pg->sc_pgroup_seen) 5205 continue; 5206 5207 /* pg is new */ 5208 5209 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) { 5210 r = upgrade_dependents(NULL, imp_snpl, ient, running, 5211 ent); 5212 switch (r) { 5213 case 0: 5214 break; 5215 5216 case ECONNABORTED: 5217 case ENOMEM: 5218 case ENOSPC: 5219 case ECANCELED: 5220 case ENODEV: 5221 case EBADF: 5222 case EBUSY: 5223 case EINVAL: 5224 case EPERM: 5225 case EROFS: 5226 case EACCES: 5227 case EEXIST: 5228 return (r); 5229 5230 default: 5231 bad_error("upgrade_dependents", r); 5232 } 5233 continue; 5234 } 5235 5236 if (running != NULL) 5237 r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name, 5238 imp_pg); 5239 else 5240 r = entity_get_pg(ent, issvc, pg->sc_pgroup_name, 5241 imp_pg); 5242 if (r != 0) { 5243 scf_callback_t cbdata; 5244 5245 switch (scf_error()) { 5246 case SCF_ERROR_NOT_FOUND: 5247 break; 5248 5249 case SCF_ERROR_CONNECTION_BROKEN: 5250 return (scferror2errno(scf_error())); 5251 5252 case SCF_ERROR_DELETED: 5253 if (running != NULL) 5254 return (ENODEV); 5255 else 5256 return (scferror2errno(scf_error())); 5257 5258 case SCF_ERROR_INVALID_ARGUMENT: 5259 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri, 5260 pg->sc_pgroup_name); 5261 return (EINVAL); 5262 5263 case SCF_ERROR_NOT_SET: 5264 case SCF_ERROR_HANDLE_MISMATCH: 5265 case SCF_ERROR_NOT_BOUND: 5266 default: 5267 bad_error("entity_get_pg", scf_error()); 5268 } 5269 5270 /* User doesn't have pg, so import it. */ 5271 5272 cbdata.sc_handle = g_hndl; 5273 cbdata.sc_parent = ent; 5274 cbdata.sc_service = issvc; 5275 cbdata.sc_flags = SCI_FORCE; 5276 cbdata.sc_source_fmri = ient->sc_fmri; 5277 cbdata.sc_target_fmri = ient->sc_fmri; 5278 5279 r = entity_pgroup_import(pg, &cbdata); 5280 switch (r) { 5281 case UU_WALK_NEXT: 5282 ient->sc_import_state = IMPORT_PROP_BEGUN; 5283 continue; 5284 5285 case UU_WALK_ERROR: 5286 if (cbdata.sc_err == EEXIST) { 5287 warn(emsg_pg_added, ient->sc_fmri, 5288 pg->sc_pgroup_name); 5289 return (EBUSY); 5290 } 5291 return (cbdata.sc_err); 5292 5293 default: 5294 bad_error("entity_pgroup_import", r); 5295 } 5296 } 5297 5298 /* report differences between pg & current */ 5299 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL); 5300 switch (r) { 5301 case 0: 5302 break; 5303 5304 case ECANCELED: 5305 warn(emsg_pg_deleted, ient->sc_fmri, 5306 pg->sc_pgroup_name); 5307 return (EBUSY); 5308 5309 case ECONNABORTED: 5310 case EBADF: 5311 case ENOMEM: 5312 case EACCES: 5313 return (r); 5314 5315 default: 5316 bad_error("load_pg", r); 5317 } 5318 report_pg_diffs(pg, rpg, ient->sc_fmri, 1); 5319 internal_pgroup_free(rpg); 5320 rpg = NULL; 5321 } 5322 5323 return (0); 5324 } 5325 5326 /* 5327 * Import an instance. If it doesn't exist, create it. If it has 5328 * a last-import snapshot, upgrade its properties. Finish by updating its 5329 * last-import snapshot. If it doesn't have a last-import snapshot then it 5330 * could have been created for a dependent tag in another manifest. Import the 5331 * new properties. If there's a conflict, don't override, like now? 5332 * 5333 * On success, returns UU_WALK_NEXT. On error returns UU_WALK_ERROR and sets 5334 * lcbdata->sc_err to 5335 * ECONNABORTED - repository connection broken 5336 * ENOMEM - out of memory 5337 * ENOSPC - svc.configd is out of resources 5338 * EEXIST - dependency collision in dependent service (error printed) 5339 * EPERM - couldn't create temporary instance (permission denied) 5340 * - couldn't import into temporary instance (permission denied) 5341 * - couldn't take snapshot (permission denied) 5342 * - couldn't upgrade properties (permission denied) 5343 * - couldn't import properties (permission denied) 5344 * - couldn't import dependents (permission denied) 5345 * EROFS - couldn't create temporary instance (repository read-only) 5346 * - couldn't import into temporary instance (repository read-only) 5347 * - couldn't upgrade properties (repository read-only) 5348 * - couldn't import properties (repository read-only) 5349 * - couldn't import dependents (repository read-only) 5350 * EACCES - couldn't create temporary instance (backend access denied) 5351 * - couldn't import into temporary instance (backend access denied) 5352 * - couldn't upgrade properties (backend access denied) 5353 * - couldn't import properties (backend access denied) 5354 * - couldn't import dependents (backend access denied) 5355 * EINVAL - invalid instance name (error printed) 5356 * - invalid pgroup_t's (error printed) 5357 * - invalid dependents (error printed) 5358 * EBUSY - temporary service deleted (error printed) 5359 * - temporary instance deleted (error printed) 5360 * - temporary instance changed (error printed) 5361 * - temporary instance already exists (error printed) 5362 * - instance deleted (error printed) 5363 * EBADF - instance has corrupt last-import snapshot (error printed) 5364 * - instance is corrupt (error printed) 5365 * - dependent has corrupt pg (error printed) 5366 * - dependent target has a corrupt snapshot (error printed) 5367 * -1 - unknown libscf error (error printed) 5368 */ 5369 static int 5370 lscf_instance_import(void *v, void *pvt) 5371 { 5372 entity_t *inst = v; 5373 scf_callback_t ctx; 5374 scf_callback_t *lcbdata = pvt; 5375 scf_service_t *rsvc = lcbdata->sc_parent; 5376 int r; 5377 scf_snaplevel_t *running; 5378 int flags = lcbdata->sc_flags; 5379 5380 const char * const emsg_tdel = 5381 gettext("Temporary instance svc:/%s:%s was deleted.\n"); 5382 const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s " 5383 "changed unexpectedly.\n"); 5384 const char * const emsg_del = gettext("%s changed unexpectedly " 5385 "(instance \"%s\" was deleted.)\n"); 5386 const char * const emsg_badsnap = gettext( 5387 "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n"); 5388 5389 /* 5390 * prepare last-import snapshot: 5391 * create temporary instance (service was precreated) 5392 * populate with properties from bundle 5393 * take snapshot 5394 */ 5395 if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) { 5396 switch (scf_error()) { 5397 case SCF_ERROR_CONNECTION_BROKEN: 5398 case SCF_ERROR_NO_RESOURCES: 5399 case SCF_ERROR_BACKEND_READONLY: 5400 case SCF_ERROR_BACKEND_ACCESS: 5401 return (stash_scferror(lcbdata)); 5402 5403 case SCF_ERROR_EXISTS: 5404 warn(gettext("Temporary service svc:/%s " 5405 "changed unexpectedly (instance \"%s\" added).\n"), 5406 imp_tsname, inst->sc_name); 5407 lcbdata->sc_err = EBUSY; 5408 return (UU_WALK_ERROR); 5409 5410 case SCF_ERROR_DELETED: 5411 warn(gettext("Temporary service svc:/%s " 5412 "was deleted unexpectedly.\n"), imp_tsname); 5413 lcbdata->sc_err = EBUSY; 5414 return (UU_WALK_ERROR); 5415 5416 case SCF_ERROR_INVALID_ARGUMENT: 5417 warn(gettext("Invalid instance name \"%s\".\n"), 5418 inst->sc_name); 5419 return (stash_scferror(lcbdata)); 5420 5421 case SCF_ERROR_PERMISSION_DENIED: 5422 warn(gettext("Could not create temporary instance " 5423 "\"%s\" in svc:/%s (permission denied).\n"), 5424 inst->sc_name, imp_tsname); 5425 return (stash_scferror(lcbdata)); 5426 5427 case SCF_ERROR_HANDLE_MISMATCH: 5428 case SCF_ERROR_NOT_BOUND: 5429 case SCF_ERROR_NOT_SET: 5430 default: 5431 bad_error("scf_service_add_instance", scf_error()); 5432 } 5433 } 5434 5435 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5436 inst->sc_name); 5437 if (r < 0) 5438 bad_error("snprintf", errno); 5439 5440 r = lscf_import_instance_pgs(imp_tinst, imp_str, inst, 5441 lcbdata->sc_flags | SCI_NOENABLED); 5442 switch (r) { 5443 case 0: 5444 break; 5445 5446 case ECANCELED: 5447 warn(emsg_tdel, imp_tsname, inst->sc_name); 5448 lcbdata->sc_err = EBUSY; 5449 r = UU_WALK_ERROR; 5450 goto deltemp; 5451 5452 case EEXIST: 5453 warn(emsg_tchg, imp_tsname, inst->sc_name); 5454 lcbdata->sc_err = EBUSY; 5455 r = UU_WALK_ERROR; 5456 goto deltemp; 5457 5458 case ECONNABORTED: 5459 goto connaborted; 5460 5461 case ENOMEM: 5462 case ENOSPC: 5463 case EPERM: 5464 case EROFS: 5465 case EACCES: 5466 case EINVAL: 5467 case EBUSY: 5468 lcbdata->sc_err = r; 5469 r = UU_WALK_ERROR; 5470 goto deltemp; 5471 5472 default: 5473 bad_error("lscf_import_instance_pgs", r); 5474 } 5475 5476 r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname, 5477 inst->sc_name); 5478 if (r < 0) 5479 bad_error("snprintf", errno); 5480 5481 ctx.sc_handle = lcbdata->sc_handle; 5482 ctx.sc_parent = imp_tinst; 5483 ctx.sc_service = 0; 5484 ctx.sc_source_fmri = inst->sc_fmri; 5485 ctx.sc_target_fmri = imp_str; 5486 if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx, 5487 UU_DEFAULT) != 0) { 5488 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5489 bad_error("uu_list_walk", uu_error()); 5490 5491 switch (ctx.sc_err) { 5492 case ECONNABORTED: 5493 goto connaborted; 5494 5495 case ECANCELED: 5496 warn(emsg_tdel, imp_tsname, inst->sc_name); 5497 lcbdata->sc_err = EBUSY; 5498 break; 5499 5500 case EEXIST: 5501 warn(emsg_tchg, imp_tsname, inst->sc_name); 5502 lcbdata->sc_err = EBUSY; 5503 break; 5504 5505 default: 5506 lcbdata->sc_err = ctx.sc_err; 5507 } 5508 r = UU_WALK_ERROR; 5509 goto deltemp; 5510 } 5511 5512 if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name, 5513 inst->sc_name, snap_lastimport, imp_tlisnap) != 0) { 5514 switch (scf_error()) { 5515 case SCF_ERROR_CONNECTION_BROKEN: 5516 goto connaborted; 5517 5518 case SCF_ERROR_NO_RESOURCES: 5519 r = stash_scferror(lcbdata); 5520 goto deltemp; 5521 5522 case SCF_ERROR_EXISTS: 5523 warn(emsg_tchg, imp_tsname, inst->sc_name); 5524 lcbdata->sc_err = EBUSY; 5525 r = UU_WALK_ERROR; 5526 goto deltemp; 5527 5528 case SCF_ERROR_PERMISSION_DENIED: 5529 warn(gettext("Could not take \"%s\" snapshot of %s " 5530 "(permission denied).\n"), snap_lastimport, 5531 imp_str); 5532 r = stash_scferror(lcbdata); 5533 goto deltemp; 5534 5535 default: 5536 scfwarn(); 5537 lcbdata->sc_err = -1; 5538 r = UU_WALK_ERROR; 5539 goto deltemp; 5540 5541 case SCF_ERROR_HANDLE_MISMATCH: 5542 case SCF_ERROR_INVALID_ARGUMENT: 5543 case SCF_ERROR_NOT_SET: 5544 bad_error("_scf_snapshot_take_new_named", scf_error()); 5545 } 5546 } 5547 5548 if (lcbdata->sc_flags & SCI_FRESH) 5549 goto fresh; 5550 5551 if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) { 5552 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 5553 imp_lisnap) != 0) { 5554 switch (scf_error()) { 5555 case SCF_ERROR_DELETED: 5556 warn(emsg_del, inst->sc_parent->sc_fmri, 5557 inst->sc_name); 5558 lcbdata->sc_err = EBUSY; 5559 r = UU_WALK_ERROR; 5560 goto deltemp; 5561 5562 case SCF_ERROR_NOT_FOUND: 5563 flags |= SCI_FORCE; 5564 goto nosnap; 5565 5566 case SCF_ERROR_CONNECTION_BROKEN: 5567 goto connaborted; 5568 5569 case SCF_ERROR_INVALID_ARGUMENT: 5570 case SCF_ERROR_HANDLE_MISMATCH: 5571 case SCF_ERROR_NOT_BOUND: 5572 case SCF_ERROR_NOT_SET: 5573 default: 5574 bad_error("scf_instance_get_snapshot", 5575 scf_error()); 5576 } 5577 } 5578 5579 /* upgrade */ 5580 5581 /* 5582 * compare new properties with last-import properties 5583 * upgrade current properties 5584 */ 5585 /* clear sc_sceen for pgs */ 5586 if (uu_list_walk(inst->sc_pgroups, clear_int, 5587 (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 5588 0) 5589 bad_error("uu_list_walk", uu_error()); 5590 5591 r = get_snaplevel(imp_lisnap, 0, imp_snpl); 5592 switch (r) { 5593 case 0: 5594 break; 5595 5596 case ECONNABORTED: 5597 goto connaborted; 5598 5599 case ECANCELED: 5600 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5601 lcbdata->sc_err = EBUSY; 5602 r = UU_WALK_ERROR; 5603 goto deltemp; 5604 5605 case ENOENT: 5606 warn(emsg_badsnap, snap_lastimport, inst->sc_fmri); 5607 lcbdata->sc_err = EBADF; 5608 r = UU_WALK_ERROR; 5609 goto deltemp; 5610 5611 default: 5612 bad_error("get_snaplevel", r); 5613 } 5614 5615 if (scf_instance_get_snapshot(imp_inst, snap_running, 5616 imp_rsnap) != 0) { 5617 switch (scf_error()) { 5618 case SCF_ERROR_DELETED: 5619 warn(emsg_del, inst->sc_parent->sc_fmri, 5620 inst->sc_name); 5621 lcbdata->sc_err = EBUSY; 5622 r = UU_WALK_ERROR; 5623 goto deltemp; 5624 5625 case SCF_ERROR_NOT_FOUND: 5626 break; 5627 5628 case SCF_ERROR_CONNECTION_BROKEN: 5629 goto connaborted; 5630 5631 case SCF_ERROR_INVALID_ARGUMENT: 5632 case SCF_ERROR_HANDLE_MISMATCH: 5633 case SCF_ERROR_NOT_BOUND: 5634 case SCF_ERROR_NOT_SET: 5635 default: 5636 bad_error("scf_instance_get_snapshot", 5637 scf_error()); 5638 } 5639 5640 running = NULL; 5641 } else { 5642 r = get_snaplevel(imp_rsnap, 0, imp_rsnpl); 5643 switch (r) { 5644 case 0: 5645 running = imp_rsnpl; 5646 break; 5647 5648 case ECONNABORTED: 5649 goto connaborted; 5650 5651 case ECANCELED: 5652 warn(emsg_del, inst->sc_parent->sc_fmri, 5653 inst->sc_name); 5654 lcbdata->sc_err = EBUSY; 5655 r = UU_WALK_ERROR; 5656 goto deltemp; 5657 5658 case ENOENT: 5659 warn(emsg_badsnap, snap_running, inst->sc_fmri); 5660 lcbdata->sc_err = EBADF; 5661 r = UU_WALK_ERROR; 5662 goto deltemp; 5663 5664 default: 5665 bad_error("get_snaplevel", r); 5666 } 5667 } 5668 5669 r = upgrade_props(imp_inst, running, imp_snpl, inst); 5670 switch (r) { 5671 case 0: 5672 break; 5673 5674 case ECANCELED: 5675 case ENODEV: 5676 warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name); 5677 lcbdata->sc_err = EBUSY; 5678 r = UU_WALK_ERROR; 5679 goto deltemp; 5680 5681 case ECONNABORTED: 5682 goto connaborted; 5683 5684 case ENOMEM: 5685 case ENOSPC: 5686 case EBADF: 5687 case EBUSY: 5688 case EINVAL: 5689 case EPERM: 5690 case EROFS: 5691 case EACCES: 5692 case EEXIST: 5693 lcbdata->sc_err = r; 5694 r = UU_WALK_ERROR; 5695 goto deltemp; 5696 5697 default: 5698 bad_error("upgrade_props", r); 5699 } 5700 5701 inst->sc_import_state = IMPORT_PROP_DONE; 5702 } else { 5703 switch (scf_error()) { 5704 case SCF_ERROR_CONNECTION_BROKEN: 5705 goto connaborted; 5706 5707 case SCF_ERROR_NOT_FOUND: 5708 break; 5709 5710 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5711 case SCF_ERROR_HANDLE_MISMATCH: 5712 case SCF_ERROR_NOT_BOUND: 5713 case SCF_ERROR_NOT_SET: 5714 default: 5715 bad_error("scf_service_get_instance", scf_error()); 5716 } 5717 5718 fresh: 5719 /* create instance */ 5720 if (scf_service_add_instance(rsvc, inst->sc_name, 5721 imp_inst) != 0) { 5722 switch (scf_error()) { 5723 case SCF_ERROR_CONNECTION_BROKEN: 5724 goto connaborted; 5725 5726 case SCF_ERROR_NO_RESOURCES: 5727 case SCF_ERROR_BACKEND_READONLY: 5728 case SCF_ERROR_BACKEND_ACCESS: 5729 r = stash_scferror(lcbdata); 5730 goto deltemp; 5731 5732 case SCF_ERROR_EXISTS: 5733 warn(gettext("%s changed unexpectedly " 5734 "(instance \"%s\" added).\n"), 5735 inst->sc_parent->sc_fmri, inst->sc_name); 5736 lcbdata->sc_err = EBUSY; 5737 r = UU_WALK_ERROR; 5738 goto deltemp; 5739 5740 case SCF_ERROR_PERMISSION_DENIED: 5741 warn(gettext("Could not create \"%s\" instance " 5742 "in %s (permission denied).\n"), 5743 inst->sc_name, inst->sc_parent->sc_fmri); 5744 r = stash_scferror(lcbdata); 5745 goto deltemp; 5746 5747 case SCF_ERROR_INVALID_ARGUMENT: /* caught above */ 5748 case SCF_ERROR_HANDLE_MISMATCH: 5749 case SCF_ERROR_NOT_BOUND: 5750 case SCF_ERROR_NOT_SET: 5751 default: 5752 bad_error("scf_service_add_instance", 5753 scf_error()); 5754 } 5755 } 5756 5757 nosnap: 5758 /* 5759 * Create a last-import snapshot to serve as an attachment 5760 * point for the real one from the temporary instance. Since 5761 * the contents is irrelevant, take it now, while the instance 5762 * is empty, to minimize svc.configd's work. 5763 */ 5764 if (_scf_snapshot_take_new(imp_inst, snap_lastimport, 5765 imp_lisnap) != 0) { 5766 switch (scf_error()) { 5767 case SCF_ERROR_CONNECTION_BROKEN: 5768 goto connaborted; 5769 5770 case SCF_ERROR_NO_RESOURCES: 5771 r = stash_scferror(lcbdata); 5772 goto deltemp; 5773 5774 case SCF_ERROR_EXISTS: 5775 warn(gettext("%s changed unexpectedly " 5776 "(snapshot \"%s\" added).\n"), 5777 inst->sc_fmri, snap_lastimport); 5778 lcbdata->sc_err = EBUSY; 5779 r = UU_WALK_ERROR; 5780 goto deltemp; 5781 5782 case SCF_ERROR_PERMISSION_DENIED: 5783 warn(gettext("Could not take \"%s\" snapshot " 5784 "of %s (permission denied).\n"), 5785 snap_lastimport, inst->sc_fmri); 5786 r = stash_scferror(lcbdata); 5787 goto deltemp; 5788 5789 default: 5790 scfwarn(); 5791 lcbdata->sc_err = -1; 5792 r = UU_WALK_ERROR; 5793 goto deltemp; 5794 5795 case SCF_ERROR_NOT_SET: 5796 case SCF_ERROR_INTERNAL: 5797 case SCF_ERROR_INVALID_ARGUMENT: 5798 case SCF_ERROR_HANDLE_MISMATCH: 5799 bad_error("_scf_snapshot_take_new", 5800 scf_error()); 5801 } 5802 } 5803 5804 if (li_only) 5805 goto lionly; 5806 5807 inst->sc_import_state = IMPORT_PROP_BEGUN; 5808 5809 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst, 5810 flags); 5811 switch (r) { 5812 case 0: 5813 break; 5814 5815 case ECONNABORTED: 5816 goto connaborted; 5817 5818 case ECANCELED: 5819 warn(gettext("%s changed unexpectedly " 5820 "(instance \"%s\" deleted).\n"), 5821 inst->sc_parent->sc_fmri, inst->sc_name); 5822 lcbdata->sc_err = EBUSY; 5823 r = UU_WALK_ERROR; 5824 goto deltemp; 5825 5826 case EEXIST: 5827 warn(gettext("%s changed unexpectedly " 5828 "(property group added).\n"), inst->sc_fmri); 5829 lcbdata->sc_err = EBUSY; 5830 r = UU_WALK_ERROR; 5831 goto deltemp; 5832 5833 default: 5834 lcbdata->sc_err = r; 5835 r = UU_WALK_ERROR; 5836 goto deltemp; 5837 5838 case EINVAL: /* caught above */ 5839 bad_error("lscf_import_instance_pgs", r); 5840 } 5841 5842 ctx.sc_parent = imp_inst; 5843 ctx.sc_service = 0; 5844 ctx.sc_trans = NULL; 5845 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import, 5846 &ctx, UU_DEFAULT) != 0) { 5847 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 5848 bad_error("uu_list_walk", uu_error()); 5849 5850 if (ctx.sc_err == ECONNABORTED) 5851 goto connaborted; 5852 lcbdata->sc_err = ctx.sc_err; 5853 r = UU_WALK_ERROR; 5854 goto deltemp; 5855 } 5856 5857 inst->sc_import_state = IMPORT_PROP_DONE; 5858 5859 if (g_verbose) 5860 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 5861 snap_initial, inst->sc_fmri); 5862 r = take_snap(imp_inst, snap_initial, imp_snap); 5863 switch (r) { 5864 case 0: 5865 break; 5866 5867 case ECONNABORTED: 5868 goto connaborted; 5869 5870 case ENOSPC: 5871 case -1: 5872 lcbdata->sc_err = r; 5873 r = UU_WALK_ERROR; 5874 goto deltemp; 5875 5876 case ECANCELED: 5877 warn(gettext("%s changed unexpectedly " 5878 "(instance %s deleted).\n"), 5879 inst->sc_parent->sc_fmri, inst->sc_name); 5880 lcbdata->sc_err = r; 5881 r = UU_WALK_ERROR; 5882 goto deltemp; 5883 5884 case EPERM: 5885 warn(emsg_snap_perm, snap_initial, inst->sc_fmri); 5886 lcbdata->sc_err = r; 5887 r = UU_WALK_ERROR; 5888 goto deltemp; 5889 5890 default: 5891 bad_error("take_snap", r); 5892 } 5893 } 5894 5895 lionly: 5896 if (lcbdata->sc_flags & SCI_NOSNAP) 5897 goto deltemp; 5898 5899 /* transfer snapshot from temporary instance */ 5900 if (g_verbose) 5901 warn(gettext("Taking \"%s\" snapshot for %s.\n"), 5902 snap_lastimport, inst->sc_fmri); 5903 if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) { 5904 switch (scf_error()) { 5905 case SCF_ERROR_CONNECTION_BROKEN: 5906 goto connaborted; 5907 5908 case SCF_ERROR_NO_RESOURCES: 5909 r = stash_scferror(lcbdata); 5910 goto deltemp; 5911 5912 case SCF_ERROR_PERMISSION_DENIED: 5913 warn(gettext("Could not take \"%s\" snapshot for %s " 5914 "(permission denied).\n"), snap_lastimport, 5915 inst->sc_fmri); 5916 r = stash_scferror(lcbdata); 5917 goto deltemp; 5918 5919 case SCF_ERROR_NOT_SET: 5920 case SCF_ERROR_HANDLE_MISMATCH: 5921 default: 5922 bad_error("_scf_snapshot_attach", scf_error()); 5923 } 5924 } 5925 5926 inst->sc_import_state = IMPORT_COMPLETE; 5927 5928 r = UU_WALK_NEXT; 5929 5930 deltemp: 5931 /* delete temporary instance */ 5932 if (scf_instance_delete(imp_tinst) != 0) { 5933 switch (scf_error()) { 5934 case SCF_ERROR_DELETED: 5935 break; 5936 5937 case SCF_ERROR_CONNECTION_BROKEN: 5938 goto connaborted; 5939 5940 case SCF_ERROR_NOT_SET: 5941 case SCF_ERROR_NOT_BOUND: 5942 default: 5943 bad_error("scf_instance_delete", scf_error()); 5944 } 5945 } 5946 5947 return (r); 5948 5949 connaborted: 5950 warn(gettext("Could not delete svc:/%s:%s " 5951 "(repository connection broken).\n"), imp_tsname, inst->sc_name); 5952 lcbdata->sc_err = ECONNABORTED; 5953 return (UU_WALK_ERROR); 5954 } 5955 5956 /* 5957 * If the service is missing, create it, import its properties, and import the 5958 * instances. Since the service is brand new, it should be empty, and if we 5959 * run into any existing entities (SCF_ERROR_EXISTS), abort. 5960 * 5961 * If the service exists, we want to upgrade its properties and import the 5962 * instances. Upgrade requires a last-import snapshot, though, which are 5963 * children of instances, so first we'll have to go through the instances 5964 * looking for a last-import snapshot. If we don't find one then we'll just 5965 * override-import the service properties (but don't delete existing 5966 * properties: another service might have declared us as a dependent). Before 5967 * we change anything, though, we want to take the previous snapshots. We 5968 * also give lscf_instance_import() a leg up on taking last-import snapshots 5969 * by importing the manifest's service properties into a temporary service. 5970 * 5971 * On success, returns UU_WALK_NEXT. On failure, returns UU_WALK_ERROR and 5972 * sets lcbdata->sc_err to 5973 * ECONNABORTED - repository connection broken 5974 * ENOMEM - out of memory 5975 * ENOSPC - svc.configd is out of resources 5976 * EPERM - couldn't create temporary service (error printed) 5977 * - couldn't import into temp service (error printed) 5978 * - couldn't create service (error printed) 5979 * - couldn't import dependent (error printed) 5980 * - couldn't take snapshot (error printed) 5981 * - couldn't create instance (error printed) 5982 * - couldn't create, modify, or delete pg (error printed) 5983 * - couldn't create, modify, or delete dependent (error printed) 5984 * - couldn't import instance (error printed) 5985 * EROFS - couldn't create temporary service (repository read-only) 5986 * - couldn't import into temporary service (repository read-only) 5987 * - couldn't create service (repository read-only) 5988 * - couldn't import dependent (repository read-only) 5989 * - couldn't create instance (repository read-only) 5990 * - couldn't create, modify, or delete pg or dependent 5991 * - couldn't import instance (repository read-only) 5992 * EACCES - couldn't create temporary service (backend access denied) 5993 * - couldn't import into temporary service (backend access denied) 5994 * - couldn't create service (backend access denied) 5995 * - couldn't import dependent (backend access denied) 5996 * - couldn't create instance (backend access denied) 5997 * - couldn't create, modify, or delete pg or dependent 5998 * - couldn't import instance (backend access denied) 5999 * EINVAL - service name is invalid (error printed) 6000 * - service name is too long (error printed) 6001 * - s has invalid pgroup (error printed) 6002 * - s has invalid dependent (error printed) 6003 * - instance name is invalid (error printed) 6004 * - instance entity_t is invalid (error printed) 6005 * EEXIST - couldn't create temporary service (already exists) (error printed) 6006 * - couldn't import dependent (dependency pg already exists) (printed) 6007 * - dependency collision in dependent service (error printed) 6008 * EBUSY - temporary service deleted (error printed) 6009 * - property group added to temporary service (error printed) 6010 * - new property group changed or was deleted (error printed) 6011 * - service was added unexpectedly (error printed) 6012 * - service was deleted unexpectedly (error printed) 6013 * - property group added to new service (error printed) 6014 * - instance added unexpectedly (error printed) 6015 * - instance deleted unexpectedly (error printed) 6016 * - dependent service deleted unexpectedly (error printed) 6017 * - pg was added, changed, or deleted (error printed) 6018 * - dependent pg changed (error printed) 6019 * - temporary instance added, changed, or deleted (error printed) 6020 * EBADF - a last-import snapshot is corrupt (error printed) 6021 * - the service is corrupt (error printed) 6022 * - a dependent is corrupt (error printed) 6023 * - an instance is corrupt (error printed) 6024 * - an instance has a corrupt last-import snapshot (error printed) 6025 * - dependent target has a corrupt snapshot (error printed) 6026 * -1 - unknown libscf error (error printed) 6027 */ 6028 static int 6029 lscf_service_import(void *v, void *pvt) 6030 { 6031 entity_t *s = v; 6032 scf_callback_t cbdata; 6033 scf_callback_t *lcbdata = pvt; 6034 scf_scope_t *scope = lcbdata->sc_parent; 6035 entity_t *inst, linst; 6036 int r; 6037 int fresh = 0; 6038 scf_snaplevel_t *running; 6039 int have_ge; 6040 6041 const char * const ts_deleted = gettext("Temporary service svc:/%s " 6042 "was deleted unexpectedly.\n"); 6043 const char * const ts_pg_added = gettext("Temporary service svc:/%s " 6044 "changed unexpectedly (property group added).\n"); 6045 const char * const s_deleted = 6046 gettext("%s was deleted unexpectedly.\n"); 6047 const char * const i_deleted = 6048 gettext("%s changed unexpectedly (instance \"%s\" deleted).\n"); 6049 const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s " 6050 "is corrupt (missing service snaplevel).\n"); 6051 6052 /* Validate the service name */ 6053 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6054 switch (scf_error()) { 6055 case SCF_ERROR_CONNECTION_BROKEN: 6056 return (stash_scferror(lcbdata)); 6057 6058 case SCF_ERROR_INVALID_ARGUMENT: 6059 warn(gettext("\"%s\" is an invalid service name. " 6060 "Cannot import.\n"), s->sc_name); 6061 return (stash_scferror(lcbdata)); 6062 6063 case SCF_ERROR_NOT_FOUND: 6064 break; 6065 6066 case SCF_ERROR_HANDLE_MISMATCH: 6067 case SCF_ERROR_NOT_BOUND: 6068 case SCF_ERROR_NOT_SET: 6069 default: 6070 bad_error("scf_scope_get_service", scf_error()); 6071 } 6072 } 6073 6074 /* create temporary service */ 6075 /* 6076 * the size of the buffer was reduced to max_scf_name_len to prevent 6077 * hitting bug 6681151. After the bug fix, the size of the buffer 6078 * should be restored to its original value (max_scf_name_len +1) 6079 */ 6080 r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name); 6081 if (r < 0) 6082 bad_error("snprintf", errno); 6083 if (r > max_scf_name_len) { 6084 warn(gettext( 6085 "Service name \"%s\" is too long. Cannot import.\n"), 6086 s->sc_name); 6087 lcbdata->sc_err = EINVAL; 6088 return (UU_WALK_ERROR); 6089 } 6090 6091 if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) { 6092 switch (scf_error()) { 6093 case SCF_ERROR_CONNECTION_BROKEN: 6094 case SCF_ERROR_NO_RESOURCES: 6095 case SCF_ERROR_BACKEND_READONLY: 6096 case SCF_ERROR_BACKEND_ACCESS: 6097 return (stash_scferror(lcbdata)); 6098 6099 case SCF_ERROR_EXISTS: 6100 warn(gettext( 6101 "Temporary service \"%s\" must be deleted before " 6102 "this manifest can be imported.\n"), imp_tsname); 6103 return (stash_scferror(lcbdata)); 6104 6105 case SCF_ERROR_PERMISSION_DENIED: 6106 warn(gettext("Could not create temporary service " 6107 "\"%s\" (permission denied).\n"), imp_tsname); 6108 return (stash_scferror(lcbdata)); 6109 6110 case SCF_ERROR_INVALID_ARGUMENT: 6111 case SCF_ERROR_HANDLE_MISMATCH: 6112 case SCF_ERROR_NOT_BOUND: 6113 case SCF_ERROR_NOT_SET: 6114 default: 6115 bad_error("scf_scope_add_service", scf_error()); 6116 } 6117 } 6118 6119 r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname); 6120 if (r < 0) 6121 bad_error("snprintf", errno); 6122 6123 cbdata.sc_handle = lcbdata->sc_handle; 6124 cbdata.sc_parent = imp_tsvc; 6125 cbdata.sc_service = 1; 6126 cbdata.sc_source_fmri = s->sc_fmri; 6127 cbdata.sc_target_fmri = imp_str; 6128 cbdata.sc_flags = 0; 6129 6130 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 6131 UU_DEFAULT) != 0) { 6132 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6133 bad_error("uu_list_walk", uu_error()); 6134 6135 lcbdata->sc_err = cbdata.sc_err; 6136 switch (cbdata.sc_err) { 6137 case ECONNABORTED: 6138 goto connaborted; 6139 6140 case ECANCELED: 6141 warn(ts_deleted, imp_tsname); 6142 lcbdata->sc_err = EBUSY; 6143 return (UU_WALK_ERROR); 6144 6145 case EEXIST: 6146 warn(ts_pg_added, imp_tsname); 6147 lcbdata->sc_err = EBUSY; 6148 return (UU_WALK_ERROR); 6149 } 6150 6151 r = UU_WALK_ERROR; 6152 goto deltemp; 6153 } 6154 6155 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 6156 UU_DEFAULT) != 0) { 6157 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6158 bad_error("uu_list_walk", uu_error()); 6159 6160 lcbdata->sc_err = cbdata.sc_err; 6161 switch (cbdata.sc_err) { 6162 case ECONNABORTED: 6163 goto connaborted; 6164 6165 case ECANCELED: 6166 warn(ts_deleted, imp_tsname); 6167 lcbdata->sc_err = EBUSY; 6168 return (UU_WALK_ERROR); 6169 6170 case EEXIST: 6171 warn(ts_pg_added, imp_tsname); 6172 lcbdata->sc_err = EBUSY; 6173 return (UU_WALK_ERROR); 6174 } 6175 6176 r = UU_WALK_ERROR; 6177 goto deltemp; 6178 } 6179 6180 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6181 switch (scf_error()) { 6182 case SCF_ERROR_NOT_FOUND: 6183 break; 6184 6185 case SCF_ERROR_CONNECTION_BROKEN: 6186 goto connaborted; 6187 6188 case SCF_ERROR_INVALID_ARGUMENT: 6189 case SCF_ERROR_HANDLE_MISMATCH: 6190 case SCF_ERROR_NOT_BOUND: 6191 case SCF_ERROR_NOT_SET: 6192 default: 6193 bad_error("scf_scope_get_service", scf_error()); 6194 } 6195 6196 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 6197 switch (scf_error()) { 6198 case SCF_ERROR_CONNECTION_BROKEN: 6199 goto connaborted; 6200 6201 case SCF_ERROR_NO_RESOURCES: 6202 case SCF_ERROR_BACKEND_READONLY: 6203 case SCF_ERROR_BACKEND_ACCESS: 6204 r = stash_scferror(lcbdata); 6205 goto deltemp; 6206 6207 case SCF_ERROR_EXISTS: 6208 warn(gettext("Scope \"%s\" changed unexpectedly" 6209 " (service \"%s\" added).\n"), 6210 SCF_SCOPE_LOCAL, s->sc_name); 6211 lcbdata->sc_err = EBUSY; 6212 goto deltemp; 6213 6214 case SCF_ERROR_PERMISSION_DENIED: 6215 warn(gettext("Could not create service \"%s\" " 6216 "(permission denied).\n"), s->sc_name); 6217 goto deltemp; 6218 6219 case SCF_ERROR_INVALID_ARGUMENT: 6220 case SCF_ERROR_HANDLE_MISMATCH: 6221 case SCF_ERROR_NOT_BOUND: 6222 case SCF_ERROR_NOT_SET: 6223 default: 6224 bad_error("scf_scope_add_service", scf_error()); 6225 } 6226 } 6227 6228 s->sc_import_state = IMPORT_PROP_BEGUN; 6229 6230 /* import service properties */ 6231 cbdata.sc_handle = lcbdata->sc_handle; 6232 cbdata.sc_parent = imp_svc; 6233 cbdata.sc_service = 1; 6234 cbdata.sc_flags = lcbdata->sc_flags; 6235 cbdata.sc_source_fmri = s->sc_fmri; 6236 cbdata.sc_target_fmri = s->sc_fmri; 6237 6238 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6239 &cbdata, UU_DEFAULT) != 0) { 6240 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6241 bad_error("uu_list_walk", uu_error()); 6242 6243 lcbdata->sc_err = cbdata.sc_err; 6244 switch (cbdata.sc_err) { 6245 case ECONNABORTED: 6246 goto connaborted; 6247 6248 case ECANCELED: 6249 warn(s_deleted, s->sc_fmri); 6250 lcbdata->sc_err = EBUSY; 6251 return (UU_WALK_ERROR); 6252 6253 case EEXIST: 6254 warn(gettext("%s changed unexpectedly " 6255 "(property group added).\n"), s->sc_fmri); 6256 lcbdata->sc_err = EBUSY; 6257 return (UU_WALK_ERROR); 6258 6259 case EINVAL: 6260 /* caught above */ 6261 bad_error("entity_pgroup_import", 6262 cbdata.sc_err); 6263 } 6264 6265 r = UU_WALK_ERROR; 6266 goto deltemp; 6267 } 6268 6269 cbdata.sc_trans = NULL; 6270 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 6271 &cbdata, UU_DEFAULT) != 0) { 6272 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6273 bad_error("uu_list_walk", uu_error()); 6274 6275 lcbdata->sc_err = cbdata.sc_err; 6276 if (cbdata.sc_err == ECONNABORTED) 6277 goto connaborted; 6278 r = UU_WALK_ERROR; 6279 goto deltemp; 6280 } 6281 6282 s->sc_import_state = IMPORT_PROP_DONE; 6283 6284 /* 6285 * This is a new service, so we can't take previous snapshots 6286 * or upgrade service properties. 6287 */ 6288 fresh = 1; 6289 goto instances; 6290 } 6291 6292 /* Clear sc_seen for the instances. */ 6293 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 6294 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 6295 bad_error("uu_list_walk", uu_error()); 6296 6297 /* 6298 * Take previous snapshots for all instances. Even for ones not 6299 * mentioned in the bundle, since we might change their service 6300 * properties. 6301 */ 6302 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6303 switch (scf_error()) { 6304 case SCF_ERROR_CONNECTION_BROKEN: 6305 goto connaborted; 6306 6307 case SCF_ERROR_DELETED: 6308 warn(s_deleted, s->sc_fmri); 6309 lcbdata->sc_err = EBUSY; 6310 r = UU_WALK_ERROR; 6311 goto deltemp; 6312 6313 case SCF_ERROR_HANDLE_MISMATCH: 6314 case SCF_ERROR_NOT_BOUND: 6315 case SCF_ERROR_NOT_SET: 6316 default: 6317 bad_error("scf_iter_service_instances", scf_error()); 6318 } 6319 } 6320 6321 for (;;) { 6322 r = scf_iter_next_instance(imp_iter, imp_inst); 6323 if (r == 0) 6324 break; 6325 if (r != 1) { 6326 switch (scf_error()) { 6327 case SCF_ERROR_DELETED: 6328 warn(s_deleted, s->sc_fmri); 6329 lcbdata->sc_err = EBUSY; 6330 r = UU_WALK_ERROR; 6331 goto deltemp; 6332 6333 case SCF_ERROR_CONNECTION_BROKEN: 6334 goto connaborted; 6335 6336 case SCF_ERROR_NOT_BOUND: 6337 case SCF_ERROR_HANDLE_MISMATCH: 6338 case SCF_ERROR_INVALID_ARGUMENT: 6339 case SCF_ERROR_NOT_SET: 6340 default: 6341 bad_error("scf_iter_next_instance", 6342 scf_error()); 6343 } 6344 } 6345 6346 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 6347 switch (scf_error()) { 6348 case SCF_ERROR_DELETED: 6349 continue; 6350 6351 case SCF_ERROR_CONNECTION_BROKEN: 6352 goto connaborted; 6353 6354 case SCF_ERROR_NOT_SET: 6355 case SCF_ERROR_NOT_BOUND: 6356 default: 6357 bad_error("scf_instance_get_name", scf_error()); 6358 } 6359 } 6360 6361 if (g_verbose) 6362 warn(gettext( 6363 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 6364 snap_previous, s->sc_name, imp_str); 6365 6366 r = take_snap(imp_inst, snap_previous, imp_snap); 6367 switch (r) { 6368 case 0: 6369 break; 6370 6371 case ECANCELED: 6372 continue; 6373 6374 case ECONNABORTED: 6375 goto connaborted; 6376 6377 case EPERM: 6378 warn(gettext("Could not take \"%s\" snapshot of " 6379 "svc:/%s:%s (permission denied).\n"), 6380 snap_previous, s->sc_name, imp_str); 6381 lcbdata->sc_err = r; 6382 return (UU_WALK_ERROR); 6383 6384 case ENOSPC: 6385 case -1: 6386 lcbdata->sc_err = r; 6387 r = UU_WALK_ERROR; 6388 goto deltemp; 6389 6390 default: 6391 bad_error("take_snap", r); 6392 } 6393 6394 linst.sc_name = imp_str; 6395 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 6396 &linst, NULL, NULL); 6397 if (inst != NULL) { 6398 inst->sc_import_state = IMPORT_PREVIOUS; 6399 inst->sc_seen = 1; 6400 } 6401 } 6402 6403 /* 6404 * Create the new instances and take previous snapshots of 6405 * them. This is not necessary, but it maximizes data preservation. 6406 */ 6407 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 6408 inst != NULL; 6409 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 6410 inst)) { 6411 if (inst->sc_seen) 6412 continue; 6413 6414 if (scf_service_add_instance(imp_svc, inst->sc_name, 6415 imp_inst) != 0) { 6416 switch (scf_error()) { 6417 case SCF_ERROR_CONNECTION_BROKEN: 6418 goto connaborted; 6419 6420 case SCF_ERROR_BACKEND_READONLY: 6421 case SCF_ERROR_BACKEND_ACCESS: 6422 case SCF_ERROR_NO_RESOURCES: 6423 r = stash_scferror(lcbdata); 6424 goto deltemp; 6425 6426 case SCF_ERROR_EXISTS: 6427 warn(gettext("%s changed unexpectedly " 6428 "(instance \"%s\" added).\n"), s->sc_fmri, 6429 inst->sc_name); 6430 lcbdata->sc_err = EBUSY; 6431 r = UU_WALK_ERROR; 6432 goto deltemp; 6433 6434 case SCF_ERROR_INVALID_ARGUMENT: 6435 warn(gettext("Service \"%s\" has instance with " 6436 "invalid name \"%s\".\n"), s->sc_name, 6437 inst->sc_name); 6438 r = stash_scferror(lcbdata); 6439 goto deltemp; 6440 6441 case SCF_ERROR_PERMISSION_DENIED: 6442 warn(gettext("Could not create instance \"%s\" " 6443 "in %s (permission denied).\n"), 6444 inst->sc_name, s->sc_fmri); 6445 r = stash_scferror(lcbdata); 6446 goto deltemp; 6447 6448 case SCF_ERROR_HANDLE_MISMATCH: 6449 case SCF_ERROR_NOT_BOUND: 6450 case SCF_ERROR_NOT_SET: 6451 default: 6452 bad_error("scf_service_add_instance", 6453 scf_error()); 6454 } 6455 } 6456 6457 if (g_verbose) 6458 warn(gettext("Taking \"%s\" snapshot for " 6459 "new service %s.\n"), snap_previous, inst->sc_fmri); 6460 r = take_snap(imp_inst, snap_previous, imp_snap); 6461 switch (r) { 6462 case 0: 6463 break; 6464 6465 case ECANCELED: 6466 warn(i_deleted, s->sc_fmri, inst->sc_name); 6467 lcbdata->sc_err = EBUSY; 6468 r = UU_WALK_ERROR; 6469 goto deltemp; 6470 6471 case ECONNABORTED: 6472 goto connaborted; 6473 6474 case EPERM: 6475 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 6476 lcbdata->sc_err = r; 6477 r = UU_WALK_ERROR; 6478 goto deltemp; 6479 6480 case ENOSPC: 6481 case -1: 6482 r = UU_WALK_ERROR; 6483 goto deltemp; 6484 6485 default: 6486 bad_error("take_snap", r); 6487 } 6488 } 6489 6490 s->sc_import_state = IMPORT_PREVIOUS; 6491 6492 /* 6493 * Upgrade service properties, if we can find a last-import snapshot. 6494 * Any will do because we don't support different service properties 6495 * in different manifests, so all snaplevels of the service in all of 6496 * the last-import snapshots of the instances should be the same. 6497 */ 6498 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6499 switch (scf_error()) { 6500 case SCF_ERROR_CONNECTION_BROKEN: 6501 goto connaborted; 6502 6503 case SCF_ERROR_DELETED: 6504 warn(s_deleted, s->sc_fmri); 6505 lcbdata->sc_err = EBUSY; 6506 r = UU_WALK_ERROR; 6507 goto deltemp; 6508 6509 case SCF_ERROR_HANDLE_MISMATCH: 6510 case SCF_ERROR_NOT_BOUND: 6511 case SCF_ERROR_NOT_SET: 6512 default: 6513 bad_error("scf_iter_service_instances", scf_error()); 6514 } 6515 } 6516 6517 have_ge = 0; 6518 li_only = 0; 6519 6520 for (;;) { 6521 r = scf_iter_next_instance(imp_iter, imp_inst); 6522 if (r == -1) { 6523 switch (scf_error()) { 6524 case SCF_ERROR_DELETED: 6525 warn(s_deleted, s->sc_fmri); 6526 lcbdata->sc_err = EBUSY; 6527 r = UU_WALK_ERROR; 6528 goto deltemp; 6529 6530 case SCF_ERROR_CONNECTION_BROKEN: 6531 goto connaborted; 6532 6533 case SCF_ERROR_NOT_BOUND: 6534 case SCF_ERROR_HANDLE_MISMATCH: 6535 case SCF_ERROR_INVALID_ARGUMENT: 6536 case SCF_ERROR_NOT_SET: 6537 default: 6538 bad_error("scf_iter_next_instance", 6539 scf_error()); 6540 } 6541 } 6542 6543 if (r == 0) { 6544 /* 6545 * Didn't find any last-import snapshots. Override- 6546 * import the properties. Unless one of the instances 6547 * has a general/enabled property, in which case we're 6548 * probably running a last-import-capable svccfg for 6549 * the first time, and we should only take the 6550 * last-import snapshot. 6551 */ 6552 if (have_ge) { 6553 li_only = 1; 6554 no_refresh = 1; 6555 break; 6556 } 6557 6558 s->sc_import_state = IMPORT_PROP_BEGUN; 6559 6560 cbdata.sc_handle = g_hndl; 6561 cbdata.sc_parent = imp_svc; 6562 cbdata.sc_service = 1; 6563 cbdata.sc_flags = SCI_FORCE; 6564 cbdata.sc_source_fmri = s->sc_fmri; 6565 cbdata.sc_target_fmri = s->sc_fmri; 6566 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6567 &cbdata, UU_DEFAULT) != 0) { 6568 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6569 bad_error("uu_list_walk", uu_error()); 6570 lcbdata->sc_err = cbdata.sc_err; 6571 switch (cbdata.sc_err) { 6572 case ECONNABORTED: 6573 goto connaborted; 6574 6575 case ECANCELED: 6576 warn(s_deleted, s->sc_fmri); 6577 lcbdata->sc_err = EBUSY; 6578 break; 6579 6580 case EINVAL: /* caught above */ 6581 case EEXIST: 6582 bad_error("entity_pgroup_import", 6583 cbdata.sc_err); 6584 } 6585 6586 r = UU_WALK_ERROR; 6587 goto deltemp; 6588 } 6589 6590 cbdata.sc_trans = NULL; 6591 if (uu_list_walk(s->sc_dependents, 6592 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 6593 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6594 bad_error("uu_list_walk", uu_error()); 6595 lcbdata->sc_err = cbdata.sc_err; 6596 if (cbdata.sc_err == ECONNABORTED) 6597 goto connaborted; 6598 r = UU_WALK_ERROR; 6599 goto deltemp; 6600 } 6601 break; 6602 } 6603 6604 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6605 imp_snap) != 0) { 6606 switch (scf_error()) { 6607 case SCF_ERROR_DELETED: 6608 continue; 6609 6610 case SCF_ERROR_NOT_FOUND: 6611 break; 6612 6613 case SCF_ERROR_CONNECTION_BROKEN: 6614 goto connaborted; 6615 6616 case SCF_ERROR_HANDLE_MISMATCH: 6617 case SCF_ERROR_NOT_BOUND: 6618 case SCF_ERROR_INVALID_ARGUMENT: 6619 case SCF_ERROR_NOT_SET: 6620 default: 6621 bad_error("scf_instance_get_snapshot", 6622 scf_error()); 6623 } 6624 6625 if (have_ge) 6626 continue; 6627 6628 /* 6629 * Check for a general/enabled property. This is how 6630 * we tell whether to import if there turn out to be 6631 * no last-import snapshots. 6632 */ 6633 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 6634 imp_pg) == 0) { 6635 if (scf_pg_get_property(imp_pg, 6636 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 6637 have_ge = 1; 6638 } else { 6639 switch (scf_error()) { 6640 case SCF_ERROR_DELETED: 6641 case SCF_ERROR_NOT_FOUND: 6642 continue; 6643 6644 case SCF_ERROR_INVALID_ARGUMENT: 6645 case SCF_ERROR_HANDLE_MISMATCH: 6646 case SCF_ERROR_CONNECTION_BROKEN: 6647 case SCF_ERROR_NOT_BOUND: 6648 case SCF_ERROR_NOT_SET: 6649 default: 6650 bad_error("scf_pg_get_property", 6651 scf_error()); 6652 } 6653 } 6654 } else { 6655 switch (scf_error()) { 6656 case SCF_ERROR_DELETED: 6657 case SCF_ERROR_NOT_FOUND: 6658 continue; 6659 6660 case SCF_ERROR_CONNECTION_BROKEN: 6661 goto connaborted; 6662 6663 case SCF_ERROR_NOT_BOUND: 6664 case SCF_ERROR_NOT_SET: 6665 case SCF_ERROR_INVALID_ARGUMENT: 6666 case SCF_ERROR_HANDLE_MISMATCH: 6667 default: 6668 bad_error("scf_instance_get_pg", 6669 scf_error()); 6670 } 6671 } 6672 continue; 6673 } 6674 6675 /* find service snaplevel */ 6676 r = get_snaplevel(imp_snap, 1, imp_snpl); 6677 switch (r) { 6678 case 0: 6679 break; 6680 6681 case ECONNABORTED: 6682 goto connaborted; 6683 6684 case ECANCELED: 6685 continue; 6686 6687 case ENOENT: 6688 if (scf_instance_get_name(imp_inst, imp_str, 6689 imp_str_sz) < 0) 6690 (void) strcpy(imp_str, "?"); 6691 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 6692 lcbdata->sc_err = EBADF; 6693 r = UU_WALK_ERROR; 6694 goto deltemp; 6695 6696 default: 6697 bad_error("get_snaplevel", r); 6698 } 6699 6700 if (scf_instance_get_snapshot(imp_inst, snap_running, 6701 imp_rsnap) != 0) { 6702 switch (scf_error()) { 6703 case SCF_ERROR_DELETED: 6704 continue; 6705 6706 case SCF_ERROR_NOT_FOUND: 6707 break; 6708 6709 case SCF_ERROR_CONNECTION_BROKEN: 6710 goto connaborted; 6711 6712 case SCF_ERROR_INVALID_ARGUMENT: 6713 case SCF_ERROR_HANDLE_MISMATCH: 6714 case SCF_ERROR_NOT_BOUND: 6715 case SCF_ERROR_NOT_SET: 6716 default: 6717 bad_error("scf_instance_get_snapshot", 6718 scf_error()); 6719 } 6720 running = NULL; 6721 } else { 6722 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 6723 switch (r) { 6724 case 0: 6725 running = imp_rsnpl; 6726 break; 6727 6728 case ECONNABORTED: 6729 goto connaborted; 6730 6731 case ECANCELED: 6732 continue; 6733 6734 case ENOENT: 6735 if (scf_instance_get_name(imp_inst, imp_str, 6736 imp_str_sz) < 0) 6737 (void) strcpy(imp_str, "?"); 6738 warn(badsnap, snap_running, s->sc_name, 6739 imp_str); 6740 lcbdata->sc_err = EBADF; 6741 r = UU_WALK_ERROR; 6742 goto deltemp; 6743 6744 default: 6745 bad_error("get_snaplevel", r); 6746 } 6747 } 6748 6749 if (g_verbose) { 6750 if (scf_instance_get_name(imp_inst, imp_str, 6751 imp_str_sz) < 0) 6752 (void) strcpy(imp_str, "?"); 6753 warn(gettext("Upgrading properties of %s according to " 6754 "instance \"%s\".\n"), s->sc_fmri, imp_str); 6755 } 6756 6757 /* upgrade service properties */ 6758 r = upgrade_props(imp_svc, running, imp_snpl, s); 6759 if (r == 0) 6760 break; 6761 6762 switch (r) { 6763 case ECONNABORTED: 6764 goto connaborted; 6765 6766 case ECANCELED: 6767 warn(s_deleted, s->sc_fmri); 6768 lcbdata->sc_err = EBUSY; 6769 break; 6770 6771 case ENODEV: 6772 if (scf_instance_get_name(imp_inst, imp_str, 6773 imp_str_sz) < 0) 6774 (void) strcpy(imp_str, "?"); 6775 warn(i_deleted, s->sc_fmri, imp_str); 6776 lcbdata->sc_err = EBUSY; 6777 break; 6778 6779 default: 6780 lcbdata->sc_err = r; 6781 } 6782 6783 r = UU_WALK_ERROR; 6784 goto deltemp; 6785 } 6786 6787 s->sc_import_state = IMPORT_PROP_DONE; 6788 6789 instances: 6790 /* import instances */ 6791 cbdata.sc_handle = lcbdata->sc_handle; 6792 cbdata.sc_parent = imp_svc; 6793 cbdata.sc_service = 1; 6794 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 6795 cbdata.sc_general = NULL; 6796 6797 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 6798 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 6799 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6800 bad_error("uu_list_walk", uu_error()); 6801 6802 lcbdata->sc_err = cbdata.sc_err; 6803 if (cbdata.sc_err == ECONNABORTED) 6804 goto connaborted; 6805 r = UU_WALK_ERROR; 6806 goto deltemp; 6807 } 6808 6809 s->sc_import_state = IMPORT_COMPLETE; 6810 r = UU_WALK_NEXT; 6811 6812 deltemp: 6813 /* delete temporary service */ 6814 if (scf_service_delete(imp_tsvc) != 0) { 6815 switch (scf_error()) { 6816 case SCF_ERROR_DELETED: 6817 break; 6818 6819 case SCF_ERROR_CONNECTION_BROKEN: 6820 goto connaborted; 6821 6822 case SCF_ERROR_EXISTS: 6823 warn(gettext( 6824 "Could not delete svc:/%s (instances exist).\n"), 6825 imp_tsname); 6826 break; 6827 6828 case SCF_ERROR_NOT_SET: 6829 case SCF_ERROR_NOT_BOUND: 6830 default: 6831 bad_error("scf_service_delete", scf_error()); 6832 } 6833 } 6834 6835 return (r); 6836 6837 connaborted: 6838 warn(gettext("Could not delete svc:/%s " 6839 "(repository connection broken).\n"), imp_tsname); 6840 lcbdata->sc_err = ECONNABORTED; 6841 return (UU_WALK_ERROR); 6842 } 6843 6844 static const char * 6845 import_progress(int st) 6846 { 6847 switch (st) { 6848 case 0: 6849 return (gettext("not reached.")); 6850 6851 case IMPORT_PREVIOUS: 6852 return (gettext("previous snapshot taken.")); 6853 6854 case IMPORT_PROP_BEGUN: 6855 return (gettext("some properties imported.")); 6856 6857 case IMPORT_PROP_DONE: 6858 return (gettext("properties imported.")); 6859 6860 case IMPORT_COMPLETE: 6861 return (gettext("imported.")); 6862 6863 case IMPORT_REFRESHED: 6864 return (gettext("refresh requested.")); 6865 6866 default: 6867 #ifndef NDEBUG 6868 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 6869 __FILE__, __LINE__, st); 6870 #endif 6871 abort(); 6872 /* NOTREACHED */ 6873 } 6874 } 6875 6876 /* 6877 * Returns 6878 * 0 - success 6879 * - fmri wasn't found (error printed) 6880 * - entity was deleted (error printed) 6881 * - backend denied access (error printed) 6882 * ENOMEM - out of memory (error printed) 6883 * ECONNABORTED - repository connection broken (error printed) 6884 * EPERM - permission denied (error printed) 6885 * -1 - unknown libscf error (error printed) 6886 */ 6887 static int 6888 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 6889 { 6890 scf_error_t serr; 6891 void *ent; 6892 int issvc; 6893 int r; 6894 6895 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 6896 const char *dpt_deleted = gettext("Could not refresh %s " 6897 "(dependent \"%s\" of %s) (deleted).\n"); 6898 6899 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 6900 switch (serr) { 6901 case SCF_ERROR_NONE: 6902 break; 6903 6904 case SCF_ERROR_NO_MEMORY: 6905 if (name == NULL) 6906 warn(gettext("Could not refresh %s (out of memory).\n"), 6907 fmri); 6908 else 6909 warn(gettext("Could not refresh %s " 6910 "(dependent \"%s\" of %s) (out of memory).\n"), 6911 fmri, name, d_fmri); 6912 return (ENOMEM); 6913 6914 case SCF_ERROR_NOT_FOUND: 6915 if (name == NULL) 6916 warn(deleted, fmri); 6917 else 6918 warn(dpt_deleted, fmri, name, d_fmri); 6919 return (0); 6920 6921 case SCF_ERROR_INVALID_ARGUMENT: 6922 case SCF_ERROR_CONSTRAINT_VIOLATED: 6923 default: 6924 bad_error("fmri_to_entity", serr); 6925 } 6926 6927 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 6928 switch (r) { 6929 case 0: 6930 break; 6931 6932 case ECONNABORTED: 6933 if (name != NULL) 6934 warn(gettext("Could not refresh %s " 6935 "(dependent \"%s\" of %s) " 6936 "(repository connection broken).\n"), fmri, name, 6937 d_fmri); 6938 return (r); 6939 6940 case ECANCELED: 6941 if (name == NULL) 6942 warn(deleted, fmri); 6943 else 6944 warn(dpt_deleted, fmri, name, d_fmri); 6945 return (0); 6946 6947 case EACCES: 6948 if (!g_verbose) 6949 return (0); 6950 if (name == NULL) 6951 warn(gettext("Could not refresh %s " 6952 "(backend access denied).\n"), fmri); 6953 else 6954 warn(gettext("Could not refresh %s " 6955 "(dependent \"%s\" of %s) " 6956 "(backend access denied).\n"), fmri, name, d_fmri); 6957 return (0); 6958 6959 case EPERM: 6960 if (name == NULL) 6961 warn(gettext("Could not refresh %s " 6962 "(permission denied).\n"), fmri); 6963 else 6964 warn(gettext("Could not refresh %s " 6965 "(dependent \"%s\" of %s) " 6966 "(permission denied).\n"), fmri, name, d_fmri); 6967 return (r); 6968 6969 case ENOSPC: 6970 if (name == NULL) 6971 warn(gettext("Could not refresh %s " 6972 "(repository server out of resources).\n"), 6973 fmri); 6974 else 6975 warn(gettext("Could not refresh %s " 6976 "(dependent \"%s\" of %s) " 6977 "(repository server out of resources).\n"), 6978 fmri, name, d_fmri); 6979 return (r); 6980 6981 case -1: 6982 scfwarn(); 6983 return (r); 6984 6985 default: 6986 bad_error("refresh_entity", r); 6987 } 6988 6989 if (issvc) 6990 scf_service_destroy(ent); 6991 else 6992 scf_instance_destroy(ent); 6993 6994 return (0); 6995 } 6996 6997 int 6998 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 6999 { 7000 scf_callback_t cbdata; 7001 int result = 0; 7002 entity_t *svc, *inst; 7003 uu_list_t *insts; 7004 int r; 7005 pgroup_t *old_dpt; 7006 void *cookie; 7007 int annotation_set = 0; 7008 7009 const char * const emsg_nomem = gettext("Out of memory.\n"); 7010 const char * const emsg_nores = 7011 gettext("svc.configd is out of resources.\n"); 7012 7013 lscf_prep_hndl(); 7014 7015 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 7016 max_scf_name_len : max_scf_fmri_len) + 1; 7017 7018 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 7019 (imp_svc = scf_service_create(g_hndl)) == NULL || 7020 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 7021 (imp_inst = scf_instance_create(g_hndl)) == NULL || 7022 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 7023 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 7024 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 7025 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 7026 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 7027 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7028 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 7029 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7030 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 7031 (imp_prop = scf_property_create(g_hndl)) == NULL || 7032 (imp_iter = scf_iter_create(g_hndl)) == NULL || 7033 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 7034 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 7035 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 7036 (imp_str = malloc(imp_str_sz)) == NULL || 7037 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 7038 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 7039 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 7040 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 7041 (ud_inst = scf_instance_create(g_hndl)) == NULL || 7042 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 7043 (ud_pg = scf_pg_create(g_hndl)) == NULL || 7044 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 7045 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 7046 (ud_prop = scf_property_create(g_hndl)) == NULL || 7047 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 7048 (ud_val = scf_value_create(g_hndl)) == NULL || 7049 (ud_iter = scf_iter_create(g_hndl)) == NULL || 7050 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 7051 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 7052 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 7053 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 7054 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 7055 if (scf_error() == SCF_ERROR_NO_RESOURCES) 7056 warn(emsg_nores); 7057 else 7058 warn(emsg_nomem); 7059 result = -1; 7060 goto out; 7061 } 7062 7063 r = load_init(); 7064 switch (r) { 7065 case 0: 7066 break; 7067 7068 case ENOMEM: 7069 warn(emsg_nomem); 7070 result = -1; 7071 goto out; 7072 7073 default: 7074 bad_error("load_init", r); 7075 } 7076 7077 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 7078 switch (scf_error()) { 7079 case SCF_ERROR_CONNECTION_BROKEN: 7080 warn(gettext("Repository connection broken.\n")); 7081 repository_teardown(); 7082 result = -1; 7083 goto out; 7084 7085 case SCF_ERROR_NOT_FOUND: 7086 case SCF_ERROR_INVALID_ARGUMENT: 7087 case SCF_ERROR_NOT_BOUND: 7088 case SCF_ERROR_HANDLE_MISMATCH: 7089 default: 7090 bad_error("scf_handle_get_scope", scf_error()); 7091 } 7092 } 7093 7094 /* Set up the auditing annotation. */ 7095 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 7096 annotation_set = 1; 7097 } else { 7098 switch (scf_error()) { 7099 case SCF_ERROR_CONNECTION_BROKEN: 7100 warn(gettext("Repository connection broken.\n")); 7101 repository_teardown(); 7102 result = -1; 7103 goto out; 7104 7105 case SCF_ERROR_INVALID_ARGUMENT: 7106 case SCF_ERROR_NOT_BOUND: 7107 case SCF_ERROR_NO_RESOURCES: 7108 case SCF_ERROR_INTERNAL: 7109 bad_error("_scf_set_annotation", scf_error()); 7110 /* NOTREACHED */ 7111 7112 default: 7113 /* 7114 * Do not terminate import because of inability to 7115 * generate annotation audit event. 7116 */ 7117 warn(gettext("_scf_set_annotation() unexpectedly " 7118 "failed with return code of %d\n"), scf_error()); 7119 break; 7120 } 7121 } 7122 7123 /* 7124 * Clear the sc_import_state's of all services & instances so we can 7125 * report how far we got if we fail. 7126 */ 7127 for (svc = uu_list_first(bndl->sc_bundle_services); 7128 svc != NULL; 7129 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7130 svc->sc_import_state = 0; 7131 7132 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 7133 clear_int, (void *)offsetof(entity_t, sc_import_state), 7134 UU_DEFAULT) != 0) 7135 bad_error("uu_list_walk", uu_error()); 7136 } 7137 7138 cbdata.sc_handle = g_hndl; 7139 cbdata.sc_parent = imp_scope; 7140 cbdata.sc_flags = flags; 7141 cbdata.sc_general = NULL; 7142 7143 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 7144 &cbdata, UU_DEFAULT) == 0) { 7145 /* Success. Refresh everything. */ 7146 7147 if (flags & SCI_NOREFRESH || no_refresh) { 7148 result = 0; 7149 goto out; 7150 } 7151 7152 for (svc = uu_list_first(bndl->sc_bundle_services); 7153 svc != NULL; 7154 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7155 pgroup_t *dpt; 7156 7157 insts = svc->sc_u.sc_service.sc_service_instances; 7158 7159 for (inst = uu_list_first(insts); 7160 inst != NULL; 7161 inst = uu_list_next(insts, inst)) { 7162 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 7163 switch (r) { 7164 case 0: 7165 break; 7166 7167 case ENOMEM: 7168 case ECONNABORTED: 7169 case EPERM: 7170 case -1: 7171 goto progress; 7172 7173 default: 7174 bad_error("imp_refresh_fmri", r); 7175 } 7176 7177 inst->sc_import_state = IMPORT_REFRESHED; 7178 7179 for (dpt = uu_list_first(inst->sc_dependents); 7180 dpt != NULL; 7181 dpt = uu_list_next(inst->sc_dependents, 7182 dpt)) 7183 if (imp_refresh_fmri( 7184 dpt->sc_pgroup_fmri, 7185 dpt->sc_pgroup_name, 7186 inst->sc_fmri) != 0) 7187 goto progress; 7188 } 7189 7190 for (dpt = uu_list_first(svc->sc_dependents); 7191 dpt != NULL; 7192 dpt = uu_list_next(svc->sc_dependents, dpt)) 7193 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 7194 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 7195 goto progress; 7196 } 7197 7198 for (old_dpt = uu_list_first(imp_deleted_dpts); 7199 old_dpt != NULL; 7200 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 7201 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 7202 old_dpt->sc_pgroup_name, 7203 old_dpt->sc_parent->sc_fmri) != 0) 7204 goto progress; 7205 7206 result = 0; 7207 goto out; 7208 } 7209 7210 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7211 bad_error("uu_list_walk", uu_error()); 7212 7213 printerr: 7214 /* If the error hasn't been printed yet, do so here. */ 7215 switch (cbdata.sc_err) { 7216 case ECONNABORTED: 7217 warn(gettext("Repository connection broken.\n")); 7218 break; 7219 7220 case ENOMEM: 7221 warn(emsg_nomem); 7222 break; 7223 7224 case ENOSPC: 7225 warn(emsg_nores); 7226 break; 7227 7228 case EROFS: 7229 warn(gettext("Repository is read-only.\n")); 7230 break; 7231 7232 case EACCES: 7233 warn(gettext("Repository backend denied access.\n")); 7234 break; 7235 7236 case EPERM: 7237 case EINVAL: 7238 case EEXIST: 7239 case EBUSY: 7240 case EBADF: 7241 case -1: 7242 break; 7243 7244 default: 7245 bad_error("lscf_service_import", cbdata.sc_err); 7246 } 7247 7248 progress: 7249 warn(gettext("Import of %s failed. Progress:\n"), filename); 7250 7251 for (svc = uu_list_first(bndl->sc_bundle_services); 7252 svc != NULL; 7253 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7254 insts = svc->sc_u.sc_service.sc_service_instances; 7255 7256 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 7257 import_progress(svc->sc_import_state)); 7258 7259 for (inst = uu_list_first(insts); 7260 inst != NULL; 7261 inst = uu_list_next(insts, inst)) 7262 warn(gettext(" Instance \"%s\": %s\n"), 7263 inst->sc_name, 7264 import_progress(inst->sc_import_state)); 7265 } 7266 7267 if (cbdata.sc_err == ECONNABORTED) 7268 repository_teardown(); 7269 7270 7271 result = -1; 7272 7273 out: 7274 if (annotation_set != 0) { 7275 /* Turn off annotation. It is no longer needed. */ 7276 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7277 } 7278 load_fini(); 7279 7280 free(ud_ctarg); 7281 free(ud_oldtarg); 7282 free(ud_name); 7283 ud_ctarg = ud_oldtarg = ud_name = NULL; 7284 7285 scf_transaction_destroy(ud_tx); 7286 ud_tx = NULL; 7287 scf_iter_destroy(ud_iter); 7288 scf_iter_destroy(ud_iter2); 7289 ud_iter = ud_iter2 = NULL; 7290 scf_value_destroy(ud_val); 7291 ud_val = NULL; 7292 scf_property_destroy(ud_prop); 7293 scf_property_destroy(ud_dpt_prop); 7294 ud_prop = ud_dpt_prop = NULL; 7295 scf_pg_destroy(ud_pg); 7296 scf_pg_destroy(ud_cur_depts_pg); 7297 scf_pg_destroy(ud_run_dpts_pg); 7298 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7299 scf_snaplevel_destroy(ud_snpl); 7300 ud_snpl = NULL; 7301 scf_instance_destroy(ud_inst); 7302 ud_inst = NULL; 7303 7304 free(imp_str); 7305 free(imp_tsname); 7306 free(imp_fe1); 7307 free(imp_fe2); 7308 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7309 7310 cookie = NULL; 7311 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7312 NULL) { 7313 free((char *)old_dpt->sc_pgroup_name); 7314 free((char *)old_dpt->sc_pgroup_fmri); 7315 internal_pgroup_free(old_dpt); 7316 } 7317 uu_list_destroy(imp_deleted_dpts); 7318 7319 scf_transaction_destroy(imp_tx); 7320 imp_tx = NULL; 7321 scf_iter_destroy(imp_iter); 7322 scf_iter_destroy(imp_rpg_iter); 7323 scf_iter_destroy(imp_up_iter); 7324 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7325 scf_property_destroy(imp_prop); 7326 imp_prop = NULL; 7327 scf_pg_destroy(imp_pg); 7328 scf_pg_destroy(imp_pg2); 7329 imp_pg = imp_pg2 = NULL; 7330 scf_snaplevel_destroy(imp_snpl); 7331 scf_snaplevel_destroy(imp_rsnpl); 7332 imp_snpl = imp_rsnpl = NULL; 7333 scf_snapshot_destroy(imp_snap); 7334 scf_snapshot_destroy(imp_lisnap); 7335 scf_snapshot_destroy(imp_tlisnap); 7336 scf_snapshot_destroy(imp_rsnap); 7337 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7338 scf_instance_destroy(imp_inst); 7339 scf_instance_destroy(imp_tinst); 7340 imp_inst = imp_tinst = NULL; 7341 scf_service_destroy(imp_svc); 7342 scf_service_destroy(imp_tsvc); 7343 imp_svc = imp_tsvc = NULL; 7344 scf_scope_destroy(imp_scope); 7345 imp_scope = NULL; 7346 7347 return (result); 7348 } 7349 7350 /* 7351 * _lscf_import_err() summarize the error handling returned by 7352 * lscf_import_{instance | service}_pgs 7353 * Return values are: 7354 * IMPORT_NEXT 7355 * IMPORT_OUT 7356 * IMPORT_BAD 7357 */ 7358 7359 #define IMPORT_BAD -1 7360 #define IMPORT_NEXT 0 7361 #define IMPORT_OUT 1 7362 7363 static int 7364 _lscf_import_err(int err, const char *fmri) 7365 { 7366 switch (err) { 7367 case 0: 7368 if (g_verbose) 7369 warn(gettext("%s updated.\n"), fmri); 7370 return (IMPORT_NEXT); 7371 7372 case ECONNABORTED: 7373 warn(gettext("Could not update %s " 7374 "(repository connection broken).\n"), fmri); 7375 return (IMPORT_OUT); 7376 7377 case ENOMEM: 7378 warn(gettext("Could not update %s (out of memory).\n"), fmri); 7379 return (IMPORT_OUT); 7380 7381 case ENOSPC: 7382 warn(gettext("Could not update %s " 7383 "(repository server out of resources).\n"), fmri); 7384 return (IMPORT_OUT); 7385 7386 case ECANCELED: 7387 warn(gettext( 7388 "Could not update %s (deleted).\n"), fmri); 7389 return (IMPORT_NEXT); 7390 7391 case EPERM: 7392 case EINVAL: 7393 case EBUSY: 7394 return (IMPORT_NEXT); 7395 7396 case EROFS: 7397 warn(gettext("Could not update %s (repository read-only).\n"), 7398 fmri); 7399 return (IMPORT_OUT); 7400 7401 case EACCES: 7402 warn(gettext("Could not update %s " 7403 "(backend access denied).\n"), fmri); 7404 return (IMPORT_NEXT); 7405 7406 case EEXIST: 7407 default: 7408 return (IMPORT_BAD); 7409 } 7410 7411 /*NOTREACHED*/ 7412 } 7413 7414 /* 7415 * Returns 7416 * 0 - success 7417 * -1 - lscf_import_instance_pgs() failed. 7418 */ 7419 int 7420 lscf_bundle_apply(bundle_t *bndl, const char *file) 7421 { 7422 entity_t *svc, *inst; 7423 scf_scope_t *rscope; 7424 scf_service_t *rsvc; 7425 scf_instance_t *rinst; 7426 scf_iter_t *iter; 7427 int annotation_set = 0; 7428 int r; 7429 7430 lscf_prep_hndl(); 7431 7432 if ((rscope = scf_scope_create(g_hndl)) == NULL || 7433 (rsvc = scf_service_create(g_hndl)) == NULL || 7434 (rinst = scf_instance_create(g_hndl)) == NULL || 7435 (iter = scf_iter_create(g_hndl)) == NULL || 7436 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7437 (imp_tx = scf_transaction_create(g_hndl)) == NULL) 7438 scfdie(); 7439 7440 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0) 7441 scfdie(); 7442 7443 /* 7444 * Set the strings to be used for the security audit annotation 7445 * event. 7446 */ 7447 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 7448 annotation_set = 1; 7449 } else { 7450 switch (scf_error()) { 7451 case SCF_ERROR_CONNECTION_BROKEN: 7452 warn(gettext("Repository connection broken.\n")); 7453 goto out; 7454 7455 case SCF_ERROR_INVALID_ARGUMENT: 7456 case SCF_ERROR_NOT_BOUND: 7457 case SCF_ERROR_NO_RESOURCES: 7458 case SCF_ERROR_INTERNAL: 7459 bad_error("_scf_set_annotation", scf_error()); 7460 /* NOTREACHED */ 7461 7462 default: 7463 /* 7464 * Do not abort apply operation because of 7465 * inability to create annotation audit event. 7466 */ 7467 warn(gettext("_scf_set_annotation() unexpectedly " 7468 "failed with return code of %d\n"), scf_error()); 7469 break; 7470 } 7471 } 7472 7473 for (svc = uu_list_first(bndl->sc_bundle_services); 7474 svc != NULL; 7475 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7476 int refresh = 0; 7477 7478 if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) { 7479 switch (scf_error()) { 7480 case SCF_ERROR_NOT_FOUND: 7481 if (g_verbose) 7482 warn(gettext("Ignoring nonexistent " 7483 "service %s.\n"), svc->sc_name); 7484 continue; 7485 7486 default: 7487 scfdie(); 7488 } 7489 } 7490 7491 /* 7492 * if we have pgs in the profile, we need to refresh ALL 7493 * instances of the service 7494 */ 7495 if (uu_list_numnodes(svc->sc_pgroups) != 0) { 7496 refresh = 1; 7497 r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc, 7498 SCI_FORCE | SCI_KEEP); 7499 switch (_lscf_import_err(r, svc->sc_fmri)) { 7500 case IMPORT_NEXT: 7501 break; 7502 7503 case IMPORT_OUT: 7504 goto out; 7505 7506 case IMPORT_BAD: 7507 default: 7508 bad_error("lscf_import_service_pgs", r); 7509 } 7510 } 7511 7512 for (inst = uu_list_first( 7513 svc->sc_u.sc_service.sc_service_instances); 7514 inst != NULL; 7515 inst = uu_list_next( 7516 svc->sc_u.sc_service.sc_service_instances, inst)) { 7517 if (scf_service_get_instance(rsvc, inst->sc_name, 7518 rinst) != 0) { 7519 switch (scf_error()) { 7520 case SCF_ERROR_NOT_FOUND: 7521 if (g_verbose) 7522 warn(gettext("Ignoring " 7523 "nonexistant instance " 7524 "%s:%s.\n"), 7525 inst->sc_parent->sc_name, 7526 inst->sc_name); 7527 continue; 7528 7529 default: 7530 scfdie(); 7531 } 7532 } 7533 7534 r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst, 7535 SCI_FORCE | SCI_KEEP); 7536 switch (_lscf_import_err(r, inst->sc_fmri)) { 7537 case IMPORT_NEXT: 7538 break; 7539 7540 case IMPORT_OUT: 7541 goto out; 7542 7543 case IMPORT_BAD: 7544 default: 7545 bad_error("lscf_import_instance_pgs", r); 7546 } 7547 7548 /* refresh only if there is no pgs in the service */ 7549 if (refresh == 0) 7550 (void) refresh_entity(0, rinst, inst->sc_fmri, 7551 NULL, NULL, NULL); 7552 } 7553 7554 if (refresh == 1) { 7555 char *name_buf = safe_malloc(max_scf_name_len + 1); 7556 7557 (void) refresh_entity(1, rsvc, svc->sc_name, rinst, 7558 iter, name_buf); 7559 free(name_buf); 7560 } 7561 } 7562 7563 out: 7564 if (annotation_set) { 7565 /* Remove security audit annotation strings. */ 7566 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7567 } 7568 7569 scf_transaction_destroy(imp_tx); 7570 imp_tx = NULL; 7571 scf_pg_destroy(imp_pg); 7572 imp_pg = NULL; 7573 7574 scf_iter_destroy(iter); 7575 scf_instance_destroy(rinst); 7576 scf_service_destroy(rsvc); 7577 scf_scope_destroy(rscope); 7578 return (0); 7579 } 7580 7581 7582 /* 7583 * Export. These functions create and output an XML tree of a service 7584 * description from the repository. This is largely the inverse of 7585 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 7586 * 7587 * - We must include any properties which are not represented specifically by 7588 * a service manifest, e.g., properties created by an admin post-import. To 7589 * do so we'll iterate through all properties and deal with each 7590 * apropriately. 7591 * 7592 * - Children of services and instances must must be in the order set by the 7593 * DTD, but we iterate over the properties in undefined order. The elements 7594 * are not easily (or efficiently) sortable by name. Since there's a fixed 7595 * number of classes of them, however, we'll keep the classes separate and 7596 * assemble them in order. 7597 */ 7598 7599 /* 7600 * Convenience function to handle xmlSetProp errors (and type casting). 7601 */ 7602 static void 7603 safe_setprop(xmlNodePtr n, const char *name, const char *val) 7604 { 7605 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 7606 uu_die(gettext("Could not set XML property.\n")); 7607 } 7608 7609 /* 7610 * Convenience function to set an XML attribute to the single value of an 7611 * astring property. If the value happens to be the default, don't set the 7612 * attribute. "dval" should be the default value supplied by the DTD, or 7613 * NULL for no default. 7614 */ 7615 static int 7616 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 7617 const char *name, const char *dval) 7618 { 7619 scf_value_t *val; 7620 ssize_t len; 7621 char *str; 7622 7623 val = scf_value_create(g_hndl); 7624 if (val == NULL) 7625 scfdie(); 7626 7627 if (prop_get_val(prop, val) != 0) { 7628 scf_value_destroy(val); 7629 return (-1); 7630 } 7631 7632 len = scf_value_get_as_string(val, NULL, 0); 7633 if (len < 0) 7634 scfdie(); 7635 7636 str = safe_malloc(len + 1); 7637 7638 if (scf_value_get_as_string(val, str, len + 1) < 0) 7639 scfdie(); 7640 7641 scf_value_destroy(val); 7642 7643 if (dval == NULL || strcmp(str, dval) != 0) 7644 safe_setprop(n, name, str); 7645 7646 free(str); 7647 7648 return (0); 7649 } 7650 7651 /* 7652 * As above, but the attribute is always set. 7653 */ 7654 static int 7655 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 7656 { 7657 return (set_attr_from_prop_default(prop, n, name, NULL)); 7658 } 7659 7660 /* 7661 * Dump the given document onto f, with "'s replaced by ''s. 7662 */ 7663 static int 7664 write_service_bundle(xmlDocPtr doc, FILE *f) 7665 { 7666 xmlChar *mem; 7667 int sz, i; 7668 7669 mem = NULL; 7670 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 7671 7672 if (mem == NULL) { 7673 semerr(gettext("Could not dump XML tree.\n")); 7674 return (-1); 7675 } 7676 7677 /* 7678 * Fortunately libxml produces " instead of ", so we can blindly 7679 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 7680 * ' code?! 7681 */ 7682 for (i = 0; i < sz; ++i) { 7683 char c = (char)mem[i]; 7684 7685 if (c == '"') 7686 (void) fputc('\'', f); 7687 else if (c == '\'') 7688 (void) fwrite("'", sizeof ("'") - 1, 1, f); 7689 else 7690 (void) fputc(c, f); 7691 } 7692 7693 return (0); 7694 } 7695 7696 /* 7697 * Create the DOM elements in elts necessary to (generically) represent prop 7698 * (i.e., a property or propval element). If the name of the property is 7699 * known, it should be passed as name_arg. Otherwise, pass NULL. 7700 */ 7701 static void 7702 export_property(scf_property_t *prop, const char *name_arg, 7703 struct pg_elts *elts, int flags) 7704 { 7705 const char *type; 7706 scf_error_t err = 0; 7707 xmlNodePtr pnode, lnode; 7708 char *lnname; 7709 int ret; 7710 7711 /* name */ 7712 if (name_arg != NULL) { 7713 (void) strcpy(exp_str, name_arg); 7714 } else { 7715 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 7716 scfdie(); 7717 } 7718 7719 /* type */ 7720 type = prop_to_typestr(prop); 7721 if (type == NULL) 7722 uu_die(gettext("Can't export property %s: unknown type.\n"), 7723 exp_str); 7724 7725 /* If we're exporting values, and there's just one, export it here. */ 7726 if (!(flags & SCE_ALL_VALUES)) 7727 goto empty; 7728 7729 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 7730 xmlNodePtr n; 7731 7732 /* Single value, so use propval */ 7733 n = xmlNewNode(NULL, (xmlChar *)"propval"); 7734 if (n == NULL) 7735 uu_die(emsg_create_xml); 7736 7737 safe_setprop(n, name_attr, exp_str); 7738 safe_setprop(n, type_attr, type); 7739 7740 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 7741 scfdie(); 7742 safe_setprop(n, value_attr, exp_str); 7743 7744 if (elts->propvals == NULL) 7745 elts->propvals = n; 7746 else 7747 (void) xmlAddSibling(elts->propvals, n); 7748 7749 return; 7750 } 7751 7752 err = scf_error(); 7753 7754 if (err == SCF_ERROR_PERMISSION_DENIED) { 7755 semerr(emsg_permission_denied); 7756 return; 7757 } 7758 7759 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 7760 err != SCF_ERROR_NOT_FOUND && 7761 err != SCF_ERROR_PERMISSION_DENIED) 7762 scfdie(); 7763 7764 empty: 7765 /* Multiple (or no) values, so use property */ 7766 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 7767 if (pnode == NULL) 7768 uu_die(emsg_create_xml); 7769 7770 safe_setprop(pnode, name_attr, exp_str); 7771 safe_setprop(pnode, type_attr, type); 7772 7773 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 7774 lnname = uu_msprintf("%s_list", type); 7775 if (lnname == NULL) 7776 uu_die(gettext("Could not create string")); 7777 7778 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 7779 if (lnode == NULL) 7780 uu_die(emsg_create_xml); 7781 7782 uu_free(lnname); 7783 7784 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 7785 scfdie(); 7786 7787 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 7788 1) { 7789 xmlNodePtr vn; 7790 7791 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 7792 NULL); 7793 if (vn == NULL) 7794 uu_die(emsg_create_xml); 7795 7796 if (scf_value_get_as_string(exp_val, exp_str, 7797 exp_str_sz) < 0) 7798 scfdie(); 7799 safe_setprop(vn, value_attr, exp_str); 7800 } 7801 if (ret != 0) 7802 scfdie(); 7803 } 7804 7805 if (elts->properties == NULL) 7806 elts->properties = pnode; 7807 else 7808 (void) xmlAddSibling(elts->properties, pnode); 7809 } 7810 7811 /* 7812 * Add a property_group element for this property group to elts. 7813 */ 7814 static void 7815 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 7816 { 7817 xmlNodePtr n; 7818 struct pg_elts elts; 7819 int ret; 7820 boolean_t read_protected; 7821 7822 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 7823 7824 /* name */ 7825 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7826 scfdie(); 7827 safe_setprop(n, name_attr, exp_str); 7828 7829 /* type */ 7830 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 7831 scfdie(); 7832 safe_setprop(n, type_attr, exp_str); 7833 7834 /* properties */ 7835 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7836 scfdie(); 7837 7838 (void) memset(&elts, 0, sizeof (elts)); 7839 7840 /* 7841 * If this property group is not read protected, we always want to 7842 * output all the values. Otherwise, we only output the values if the 7843 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 7844 */ 7845 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 7846 scfdie(); 7847 7848 if (!read_protected) 7849 flags |= SCE_ALL_VALUES; 7850 7851 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7852 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7853 scfdie(); 7854 7855 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 7856 xmlNodePtr m; 7857 7858 m = xmlNewNode(NULL, (xmlChar *)"stability"); 7859 if (m == NULL) 7860 uu_die(emsg_create_xml); 7861 7862 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 7863 elts.stability = m; 7864 continue; 7865 } 7866 7867 xmlFreeNode(m); 7868 } 7869 7870 export_property(exp_prop, NULL, &elts, flags); 7871 } 7872 if (ret == -1) 7873 scfdie(); 7874 7875 (void) xmlAddChild(n, elts.stability); 7876 (void) xmlAddChildList(n, elts.propvals); 7877 (void) xmlAddChildList(n, elts.properties); 7878 7879 if (eelts->property_groups == NULL) 7880 eelts->property_groups = n; 7881 else 7882 (void) xmlAddSibling(eelts->property_groups, n); 7883 } 7884 7885 /* 7886 * Create an XML node representing the dependency described by the given 7887 * property group and put it in eelts. Unless the dependency is not valid, in 7888 * which case create a generic property_group element which represents it and 7889 * put it in eelts. 7890 */ 7891 static void 7892 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 7893 { 7894 xmlNodePtr n; 7895 int err = 0, ret; 7896 struct pg_elts elts; 7897 7898 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 7899 if (n == NULL) 7900 uu_die(emsg_create_xml); 7901 7902 /* 7903 * If the external flag is present, skip this dependency because it 7904 * should have been created by another manifest. 7905 */ 7906 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 7907 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 7908 prop_get_val(exp_prop, exp_val) == 0) { 7909 uint8_t b; 7910 7911 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 7912 scfdie(); 7913 7914 if (b) 7915 return; 7916 } 7917 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 7918 scfdie(); 7919 7920 /* Get the required attributes. */ 7921 7922 /* name */ 7923 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7924 scfdie(); 7925 safe_setprop(n, name_attr, exp_str); 7926 7927 /* grouping */ 7928 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 7929 set_attr_from_prop(exp_prop, n, "grouping") != 0) 7930 err = 1; 7931 7932 /* restart_on */ 7933 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 7934 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 7935 err = 1; 7936 7937 /* type */ 7938 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 7939 set_attr_from_prop(exp_prop, n, type_attr) != 0) 7940 err = 1; 7941 7942 /* 7943 * entities: Not required, but if we create no children, it will be 7944 * created as empty on import, so fail if it's missing. 7945 */ 7946 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 7947 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 7948 scf_iter_t *eiter; 7949 int ret2; 7950 7951 eiter = scf_iter_create(g_hndl); 7952 if (eiter == NULL) 7953 scfdie(); 7954 7955 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 7956 scfdie(); 7957 7958 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 7959 xmlNodePtr ch; 7960 7961 if (scf_value_get_astring(exp_val, exp_str, 7962 exp_str_sz) < 0) 7963 scfdie(); 7964 7965 /* 7966 * service_fmri's must be first, so we can add them 7967 * here. 7968 */ 7969 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 7970 NULL); 7971 if (ch == NULL) 7972 uu_die(emsg_create_xml); 7973 7974 safe_setprop(ch, value_attr, exp_str); 7975 } 7976 if (ret2 == -1) 7977 scfdie(); 7978 7979 scf_iter_destroy(eiter); 7980 } else 7981 err = 1; 7982 7983 if (err) { 7984 xmlFreeNode(n); 7985 7986 export_pg(pg, eelts, 0); 7987 7988 return; 7989 } 7990 7991 /* Iterate through the properties & handle each. */ 7992 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7993 scfdie(); 7994 7995 (void) memset(&elts, 0, sizeof (elts)); 7996 7997 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7998 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7999 scfdie(); 8000 8001 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8002 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8003 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 8004 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8005 continue; 8006 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8007 xmlNodePtr m; 8008 8009 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8010 if (m == NULL) 8011 uu_die(emsg_create_xml); 8012 8013 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8014 elts.stability = m; 8015 continue; 8016 } 8017 8018 xmlFreeNode(m); 8019 } 8020 8021 export_property(exp_prop, exp_str, &elts, 0); 8022 } 8023 if (ret == -1) 8024 scfdie(); 8025 8026 (void) xmlAddChild(n, elts.stability); 8027 (void) xmlAddChildList(n, elts.propvals); 8028 (void) xmlAddChildList(n, elts.properties); 8029 8030 if (eelts->dependencies == NULL) 8031 eelts->dependencies = n; 8032 else 8033 (void) xmlAddSibling(eelts->dependencies, n); 8034 } 8035 8036 static xmlNodePtr 8037 export_method_environment(scf_propertygroup_t *pg) 8038 { 8039 xmlNodePtr env; 8040 int ret; 8041 int children = 0; 8042 8043 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 8044 return (NULL); 8045 8046 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 8047 if (env == NULL) 8048 uu_die(emsg_create_xml); 8049 8050 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 8051 scfdie(); 8052 8053 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 8054 scfdie(); 8055 8056 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 8057 xmlNodePtr ev; 8058 char *cp; 8059 8060 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 8061 scfdie(); 8062 8063 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 8064 warn(gettext("Invalid environment variable \"%s\".\n"), 8065 exp_str); 8066 continue; 8067 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 8068 warn(gettext("Invalid environment variable \"%s\"; " 8069 "\"SMF_\" prefix is reserved.\n"), exp_str); 8070 continue; 8071 } 8072 8073 *cp = '\0'; 8074 cp++; 8075 8076 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 8077 if (ev == NULL) 8078 uu_die(emsg_create_xml); 8079 8080 safe_setprop(ev, name_attr, exp_str); 8081 safe_setprop(ev, value_attr, cp); 8082 children++; 8083 } 8084 8085 if (ret != 0) 8086 scfdie(); 8087 8088 if (children == 0) { 8089 xmlFreeNode(env); 8090 return (NULL); 8091 } 8092 8093 return (env); 8094 } 8095 8096 /* 8097 * As above, but for a method property group. 8098 */ 8099 static void 8100 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 8101 { 8102 xmlNodePtr n, env; 8103 char *str; 8104 int err = 0, nonenv, ret; 8105 uint8_t use_profile; 8106 struct pg_elts elts; 8107 xmlNodePtr ctxt = NULL; 8108 8109 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 8110 8111 /* Get the required attributes. */ 8112 8113 /* name */ 8114 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8115 scfdie(); 8116 safe_setprop(n, name_attr, exp_str); 8117 8118 /* type */ 8119 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8120 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8121 err = 1; 8122 8123 /* exec */ 8124 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 8125 set_attr_from_prop(exp_prop, n, "exec") != 0) 8126 err = 1; 8127 8128 /* timeout */ 8129 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 8130 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 8131 prop_get_val(exp_prop, exp_val) == 0) { 8132 uint64_t c; 8133 8134 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 8135 scfdie(); 8136 8137 str = uu_msprintf("%llu", c); 8138 if (str == NULL) 8139 uu_die(gettext("Could not create string")); 8140 8141 safe_setprop(n, "timeout_seconds", str); 8142 free(str); 8143 } else 8144 err = 1; 8145 8146 if (err) { 8147 xmlFreeNode(n); 8148 8149 export_pg(pg, eelts, 0); 8150 8151 return; 8152 } 8153 8154 8155 /* 8156 * If we're going to have a method_context child, we need to know 8157 * before we iterate through the properties. Since method_context's 8158 * are optional, we don't want to complain about any properties 8159 * missing if none of them are there. Thus we can't use the 8160 * convenience functions. 8161 */ 8162 nonenv = 8163 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 8164 SCF_SUCCESS || 8165 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 8166 SCF_SUCCESS || 8167 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 8168 SCF_SUCCESS || 8169 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 8170 SCF_SUCCESS; 8171 8172 if (nonenv) { 8173 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 8174 if (ctxt == NULL) 8175 uu_die(emsg_create_xml); 8176 8177 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) == 8178 0 && 8179 set_attr_from_prop_default(exp_prop, ctxt, 8180 "working_directory", ":default") != 0) 8181 err = 1; 8182 8183 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 && 8184 set_attr_from_prop_default(exp_prop, ctxt, "project", 8185 ":default") != 0) 8186 err = 1; 8187 8188 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) == 8189 0 && 8190 set_attr_from_prop_default(exp_prop, ctxt, 8191 "resource_pool", ":default") != 0) 8192 err = 1; 8193 /* 8194 * We only want to complain about profile or credential 8195 * properties if we will use them. To determine that we must 8196 * examine USE_PROFILE. 8197 */ 8198 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 8199 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8200 prop_get_val(exp_prop, exp_val) == 0) { 8201 if (scf_value_get_boolean(exp_val, &use_profile) != 8202 SCF_SUCCESS) { 8203 scfdie(); 8204 } 8205 8206 if (use_profile) { 8207 xmlNodePtr prof; 8208 8209 prof = xmlNewChild(ctxt, NULL, 8210 (xmlChar *)"method_profile", NULL); 8211 if (prof == NULL) 8212 uu_die(emsg_create_xml); 8213 8214 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, 8215 exp_prop) != 0 || 8216 set_attr_from_prop(exp_prop, prof, 8217 name_attr) != 0) 8218 err = 1; 8219 } else { 8220 xmlNodePtr cred; 8221 8222 cred = xmlNewChild(ctxt, NULL, 8223 (xmlChar *)"method_credential", NULL); 8224 if (cred == NULL) 8225 uu_die(emsg_create_xml); 8226 8227 if (pg_get_prop(pg, SCF_PROPERTY_USER, 8228 exp_prop) != 0 || 8229 set_attr_from_prop(exp_prop, cred, 8230 "user") != 0) { 8231 err = 1; 8232 } 8233 8234 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, 8235 exp_prop) == 0 && 8236 set_attr_from_prop_default(exp_prop, cred, 8237 "group", ":default") != 0) 8238 err = 1; 8239 8240 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 8241 exp_prop) == 0 && 8242 set_attr_from_prop_default(exp_prop, cred, 8243 "supp_groups", ":default") != 0) 8244 err = 1; 8245 8246 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 8247 exp_prop) == 0 && 8248 set_attr_from_prop_default(exp_prop, cred, 8249 "privileges", ":default") != 0) 8250 err = 1; 8251 8252 if (pg_get_prop(pg, 8253 SCF_PROPERTY_LIMIT_PRIVILEGES, 8254 exp_prop) == 0 && 8255 set_attr_from_prop_default(exp_prop, cred, 8256 "limit_privileges", ":default") != 0) 8257 err = 1; 8258 } 8259 } 8260 } 8261 8262 if ((env = export_method_environment(pg)) != NULL) { 8263 if (ctxt == NULL) { 8264 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 8265 if (ctxt == NULL) 8266 uu_die(emsg_create_xml); 8267 } 8268 (void) xmlAddChild(ctxt, env); 8269 } 8270 8271 if (env != NULL || (nonenv && err == 0)) 8272 (void) xmlAddChild(n, ctxt); 8273 else 8274 xmlFreeNode(ctxt); 8275 8276 nonenv = (err == 0); 8277 8278 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8279 scfdie(); 8280 8281 (void) memset(&elts, 0, sizeof (elts)); 8282 8283 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8284 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8285 scfdie(); 8286 8287 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 8288 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 8289 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 8290 continue; 8291 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8292 xmlNodePtr m; 8293 8294 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8295 if (m == NULL) 8296 uu_die(emsg_create_xml); 8297 8298 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8299 elts.stability = m; 8300 continue; 8301 } 8302 8303 xmlFreeNode(m); 8304 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 8305 0 || 8306 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 8307 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 8308 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8309 if (nonenv) 8310 continue; 8311 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 8312 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 8313 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 8314 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 8315 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 8316 if (nonenv && !use_profile) 8317 continue; 8318 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8319 if (nonenv && use_profile) 8320 continue; 8321 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 8322 if (env != NULL) 8323 continue; 8324 } 8325 8326 export_property(exp_prop, exp_str, &elts, 0); 8327 } 8328 if (ret == -1) 8329 scfdie(); 8330 8331 (void) xmlAddChild(n, elts.stability); 8332 (void) xmlAddChildList(n, elts.propvals); 8333 (void) xmlAddChildList(n, elts.properties); 8334 8335 if (eelts->exec_methods == NULL) 8336 eelts->exec_methods = n; 8337 else 8338 (void) xmlAddSibling(eelts->exec_methods, n); 8339 } 8340 8341 static void 8342 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 8343 struct entity_elts *eelts) 8344 { 8345 xmlNodePtr pgnode; 8346 8347 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 8348 if (pgnode == NULL) 8349 uu_die(emsg_create_xml); 8350 8351 safe_setprop(pgnode, name_attr, name); 8352 safe_setprop(pgnode, type_attr, type); 8353 8354 (void) xmlAddChildList(pgnode, elts->propvals); 8355 (void) xmlAddChildList(pgnode, elts->properties); 8356 8357 if (eelts->property_groups == NULL) 8358 eelts->property_groups = pgnode; 8359 else 8360 (void) xmlAddSibling(eelts->property_groups, pgnode); 8361 } 8362 8363 /* 8364 * Process the general property group for a service. This is the one with the 8365 * goodies. 8366 */ 8367 static void 8368 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 8369 { 8370 struct pg_elts elts; 8371 int ret; 8372 8373 /* 8374 * In case there are properties which don't correspond to child 8375 * entities of the service entity, we'll set up a pg_elts structure to 8376 * put them in. 8377 */ 8378 (void) memset(&elts, 0, sizeof (elts)); 8379 8380 /* Walk the properties, looking for special ones. */ 8381 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8382 scfdie(); 8383 8384 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8385 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8386 scfdie(); 8387 8388 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 8389 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8390 prop_get_val(exp_prop, exp_val) == 0) { 8391 uint8_t b; 8392 8393 if (scf_value_get_boolean(exp_val, &b) != 8394 SCF_SUCCESS) 8395 scfdie(); 8396 8397 if (b) { 8398 selts->single_instance = 8399 xmlNewNode(NULL, 8400 (xmlChar *)"single_instance"); 8401 if (selts->single_instance == NULL) 8402 uu_die(emsg_create_xml); 8403 } 8404 8405 continue; 8406 } 8407 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8408 xmlNodePtr rnode, sfnode; 8409 8410 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8411 if (rnode == NULL) 8412 uu_die(emsg_create_xml); 8413 8414 sfnode = xmlNewChild(rnode, NULL, 8415 (xmlChar *)"service_fmri", NULL); 8416 if (sfnode == NULL) 8417 uu_die(emsg_create_xml); 8418 8419 if (set_attr_from_prop(exp_prop, sfnode, 8420 value_attr) == 0) { 8421 selts->restarter = rnode; 8422 continue; 8423 } 8424 8425 xmlFreeNode(rnode); 8426 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 8427 0) { 8428 xmlNodePtr s; 8429 8430 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8431 if (s == NULL) 8432 uu_die(emsg_create_xml); 8433 8434 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8435 selts->stability = s; 8436 continue; 8437 } 8438 8439 xmlFreeNode(s); 8440 } 8441 8442 export_property(exp_prop, exp_str, &elts, 0); 8443 } 8444 if (ret == -1) 8445 scfdie(); 8446 8447 if (elts.propvals != NULL || elts.properties != NULL) 8448 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 8449 selts); 8450 } 8451 8452 static void 8453 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 8454 { 8455 xmlNodePtr n, prof, cred, env; 8456 uint8_t use_profile; 8457 int ret, err = 0; 8458 8459 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 8460 8461 env = export_method_environment(pg); 8462 8463 /* Need to know whether we'll use a profile or not. */ 8464 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 8465 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8466 prop_get_val(exp_prop, exp_val) == 0) { 8467 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 8468 scfdie(); 8469 8470 if (use_profile) 8471 prof = 8472 xmlNewChild(n, NULL, (xmlChar *)"method_profile", 8473 NULL); 8474 else 8475 cred = 8476 xmlNewChild(n, NULL, (xmlChar *)"method_credential", 8477 NULL); 8478 } 8479 8480 if (env != NULL) 8481 (void) xmlAddChild(n, env); 8482 8483 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8484 scfdie(); 8485 8486 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8487 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8488 scfdie(); 8489 8490 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 8491 if (set_attr_from_prop(exp_prop, n, 8492 "working_directory") != 0) 8493 err = 1; 8494 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 8495 if (set_attr_from_prop(exp_prop, n, "project") != 0) 8496 err = 1; 8497 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 8498 if (set_attr_from_prop(exp_prop, n, 8499 "resource_pool") != 0) 8500 err = 1; 8501 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8502 /* EMPTY */ 8503 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 8504 if (use_profile || 8505 set_attr_from_prop(exp_prop, cred, "user") != 0) 8506 err = 1; 8507 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 8508 if (use_profile || 8509 set_attr_from_prop(exp_prop, cred, "group") != 0) 8510 err = 1; 8511 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 8512 if (use_profile || set_attr_from_prop(exp_prop, cred, 8513 "supp_groups") != 0) 8514 err = 1; 8515 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 8516 if (use_profile || set_attr_from_prop(exp_prop, cred, 8517 "privileges") != 0) 8518 err = 1; 8519 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 8520 0) { 8521 if (use_profile || set_attr_from_prop(exp_prop, cred, 8522 "limit_privileges") != 0) 8523 err = 1; 8524 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8525 if (!use_profile || set_attr_from_prop(exp_prop, 8526 prof, name_attr) != 0) 8527 err = 1; 8528 } else { 8529 /* Can't have generic properties in method_context's */ 8530 err = 1; 8531 } 8532 } 8533 if (ret == -1) 8534 scfdie(); 8535 8536 if (err && env == NULL) { 8537 xmlFreeNode(n); 8538 export_pg(pg, elts, 0); 8539 return; 8540 } 8541 8542 elts->method_context = n; 8543 } 8544 8545 /* 8546 * Given a dependency property group in the tfmri entity (target fmri), return 8547 * a dependent element which represents it. 8548 */ 8549 static xmlNodePtr 8550 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 8551 { 8552 uint8_t b; 8553 xmlNodePtr n, sf; 8554 int err = 0, ret; 8555 struct pg_elts pgelts; 8556 8557 /* 8558 * If external isn't set to true then exporting the service will 8559 * export this as a normal dependency, so we should stop to avoid 8560 * duplication. 8561 */ 8562 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 8563 scf_property_get_value(exp_prop, exp_val) != 0 || 8564 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 8565 if (g_verbose) { 8566 warn(gettext("Dependent \"%s\" cannot be exported " 8567 "properly because the \"%s\" property of the " 8568 "\"%s\" dependency of %s is not set to true.\n"), 8569 name, scf_property_external, name, tfmri); 8570 } 8571 8572 return (NULL); 8573 } 8574 8575 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 8576 if (n == NULL) 8577 uu_die(emsg_create_xml); 8578 8579 safe_setprop(n, name_attr, name); 8580 8581 /* Get the required attributes */ 8582 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8583 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8584 err = 1; 8585 8586 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8587 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8588 err = 1; 8589 8590 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8591 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 8592 prop_get_val(exp_prop, exp_val) == 0) { 8593 /* EMPTY */ 8594 } else 8595 err = 1; 8596 8597 if (err) { 8598 xmlFreeNode(n); 8599 return (NULL); 8600 } 8601 8602 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 8603 if (sf == NULL) 8604 uu_die(emsg_create_xml); 8605 8606 safe_setprop(sf, value_attr, tfmri); 8607 8608 /* 8609 * Now add elements for the other properties. 8610 */ 8611 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8612 scfdie(); 8613 8614 (void) memset(&pgelts, 0, sizeof (pgelts)); 8615 8616 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8617 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8618 scfdie(); 8619 8620 if (strcmp(exp_str, scf_property_external) == 0 || 8621 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8622 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8623 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8624 continue; 8625 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 8626 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 8627 prop_get_val(exp_prop, exp_val) == 0) { 8628 char type[sizeof ("service") + 1]; 8629 8630 if (scf_value_get_astring(exp_val, type, 8631 sizeof (type)) < 0) 8632 scfdie(); 8633 8634 if (strcmp(type, "service") == 0) 8635 continue; 8636 } 8637 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8638 xmlNodePtr s; 8639 8640 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8641 if (s == NULL) 8642 uu_die(emsg_create_xml); 8643 8644 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8645 pgelts.stability = s; 8646 continue; 8647 } 8648 8649 xmlFreeNode(s); 8650 } 8651 8652 export_property(exp_prop, exp_str, &pgelts, 0); 8653 } 8654 if (ret == -1) 8655 scfdie(); 8656 8657 (void) xmlAddChild(n, pgelts.stability); 8658 (void) xmlAddChildList(n, pgelts.propvals); 8659 (void) xmlAddChildList(n, pgelts.properties); 8660 8661 return (n); 8662 } 8663 8664 static void 8665 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 8666 { 8667 scf_propertygroup_t *opg; 8668 scf_iter_t *iter; 8669 char *type, *fmri; 8670 int ret; 8671 struct pg_elts pgelts; 8672 xmlNodePtr n; 8673 scf_error_t serr; 8674 8675 if ((opg = scf_pg_create(g_hndl)) == NULL || 8676 (iter = scf_iter_create(g_hndl)) == NULL) 8677 scfdie(); 8678 8679 /* Can't use exp_prop_iter due to export_dependent(). */ 8680 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 8681 scfdie(); 8682 8683 type = safe_malloc(max_scf_pg_type_len + 1); 8684 8685 /* Get an extra byte so we can tell if values are too long. */ 8686 fmri = safe_malloc(max_scf_fmri_len + 2); 8687 8688 (void) memset(&pgelts, 0, sizeof (pgelts)); 8689 8690 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 8691 void *entity; 8692 int isservice; 8693 scf_type_t ty; 8694 8695 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 8696 scfdie(); 8697 8698 if ((ty != SCF_TYPE_ASTRING && 8699 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 8700 prop_get_val(exp_prop, exp_val) != 0) { 8701 export_property(exp_prop, NULL, &pgelts, 0); 8702 continue; 8703 } 8704 8705 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8706 scfdie(); 8707 8708 if (scf_value_get_astring(exp_val, fmri, 8709 max_scf_fmri_len + 2) < 0) 8710 scfdie(); 8711 8712 /* Look for a dependency group in the target fmri. */ 8713 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 8714 switch (serr) { 8715 case SCF_ERROR_NONE: 8716 break; 8717 8718 case SCF_ERROR_NO_MEMORY: 8719 uu_die(gettext("Out of memory.\n")); 8720 /* NOTREACHED */ 8721 8722 case SCF_ERROR_INVALID_ARGUMENT: 8723 if (g_verbose) { 8724 if (scf_property_to_fmri(exp_prop, fmri, 8725 max_scf_fmri_len + 2) < 0) 8726 scfdie(); 8727 8728 warn(gettext("The value of %s is not a valid " 8729 "FMRI.\n"), fmri); 8730 } 8731 8732 export_property(exp_prop, exp_str, &pgelts, 0); 8733 continue; 8734 8735 case SCF_ERROR_CONSTRAINT_VIOLATED: 8736 if (g_verbose) { 8737 if (scf_property_to_fmri(exp_prop, fmri, 8738 max_scf_fmri_len + 2) < 0) 8739 scfdie(); 8740 8741 warn(gettext("The value of %s does not specify " 8742 "a service or an instance.\n"), fmri); 8743 } 8744 8745 export_property(exp_prop, exp_str, &pgelts, 0); 8746 continue; 8747 8748 case SCF_ERROR_NOT_FOUND: 8749 if (g_verbose) { 8750 if (scf_property_to_fmri(exp_prop, fmri, 8751 max_scf_fmri_len + 2) < 0) 8752 scfdie(); 8753 8754 warn(gettext("The entity specified by %s does " 8755 "not exist.\n"), fmri); 8756 } 8757 8758 export_property(exp_prop, exp_str, &pgelts, 0); 8759 continue; 8760 8761 default: 8762 #ifndef NDEBUG 8763 (void) fprintf(stderr, "%s:%d: %s() failed with " 8764 "unexpected error %d.\n", __FILE__, __LINE__, 8765 "fmri_to_entity", serr); 8766 #endif 8767 abort(); 8768 } 8769 8770 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 8771 if (scf_error() != SCF_ERROR_NOT_FOUND) 8772 scfdie(); 8773 8774 warn(gettext("Entity %s is missing dependency property " 8775 "group %s.\n"), fmri, exp_str); 8776 8777 export_property(exp_prop, NULL, &pgelts, 0); 8778 continue; 8779 } 8780 8781 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 8782 scfdie(); 8783 8784 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 8785 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 8786 scfdie(); 8787 8788 warn(gettext("Property group %s is not of " 8789 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 8790 8791 export_property(exp_prop, NULL, &pgelts, 0); 8792 continue; 8793 } 8794 8795 n = export_dependent(opg, exp_str, fmri); 8796 if (n == NULL) 8797 export_property(exp_prop, exp_str, &pgelts, 0); 8798 else { 8799 if (eelts->dependents == NULL) 8800 eelts->dependents = n; 8801 else 8802 (void) xmlAddSibling(eelts->dependents, 8803 n); 8804 } 8805 } 8806 if (ret == -1) 8807 scfdie(); 8808 8809 free(fmri); 8810 free(type); 8811 8812 scf_iter_destroy(iter); 8813 scf_pg_destroy(opg); 8814 8815 if (pgelts.propvals != NULL || pgelts.properties != NULL) 8816 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 8817 eelts); 8818 } 8819 8820 static void 8821 make_node(xmlNodePtr *nodep, const char *name) 8822 { 8823 if (*nodep == NULL) { 8824 *nodep = xmlNewNode(NULL, (xmlChar *)name); 8825 if (*nodep == NULL) 8826 uu_die(emsg_create_xml); 8827 } 8828 } 8829 8830 static xmlNodePtr 8831 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 8832 { 8833 int ret; 8834 xmlNodePtr parent = NULL; 8835 xmlNodePtr loctext = NULL; 8836 8837 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8838 scfdie(); 8839 8840 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8841 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 8842 prop_get_val(exp_prop, exp_val) != 0) 8843 continue; 8844 8845 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 8846 scfdie(); 8847 8848 make_node(&parent, parname); 8849 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 8850 (xmlChar *)exp_str); 8851 if (loctext == NULL) 8852 uu_die(emsg_create_xml); 8853 8854 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8855 scfdie(); 8856 8857 safe_setprop(loctext, "xml:lang", exp_str); 8858 } 8859 8860 if (ret == -1) 8861 scfdie(); 8862 8863 return (parent); 8864 } 8865 8866 static xmlNodePtr 8867 export_tm_manpage(scf_propertygroup_t *pg) 8868 { 8869 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 8870 if (manpage == NULL) 8871 uu_die(emsg_create_xml); 8872 8873 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 8874 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 8875 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 8876 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 8877 xmlFreeNode(manpage); 8878 return (NULL); 8879 } 8880 8881 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 8882 (void) set_attr_from_prop_default(exp_prop, 8883 manpage, "manpath", ":default"); 8884 8885 return (manpage); 8886 } 8887 8888 static xmlNodePtr 8889 export_tm_doc_link(scf_propertygroup_t *pg) 8890 { 8891 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 8892 if (doc_link == NULL) 8893 uu_die(emsg_create_xml); 8894 8895 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 8896 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 8897 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 8898 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 8899 xmlFreeNode(doc_link); 8900 return (NULL); 8901 } 8902 return (doc_link); 8903 } 8904 8905 /* 8906 * Process template information for a service or instances. 8907 */ 8908 static void 8909 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 8910 struct template_elts *telts) 8911 { 8912 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 8913 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 8914 xmlNodePtr child = NULL; 8915 8916 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 8917 scfdie(); 8918 8919 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 8920 telts->common_name = export_tm_loctext(pg, "common_name"); 8921 if (telts->common_name == NULL) 8922 export_pg(pg, elts, 0); 8923 return; 8924 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 8925 telts->description = export_tm_loctext(pg, "description"); 8926 if (telts->description == NULL) 8927 export_pg(pg, elts, 0); 8928 return; 8929 } 8930 8931 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 8932 child = export_tm_manpage(pg); 8933 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 8934 child = export_tm_doc_link(pg); 8935 } 8936 8937 if (child != NULL) { 8938 make_node(&telts->documentation, "documentation"); 8939 (void) xmlAddChild(telts->documentation, child); 8940 } else { 8941 export_pg(pg, elts, 0); 8942 } 8943 } 8944 8945 /* 8946 * Process the general property group for an instance. 8947 */ 8948 static void 8949 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 8950 struct entity_elts *elts) 8951 { 8952 uint8_t enabled; 8953 struct pg_elts pgelts; 8954 int ret; 8955 8956 /* enabled */ 8957 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 8958 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8959 prop_get_val(exp_prop, exp_val) == 0) { 8960 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 8961 scfdie(); 8962 } else { 8963 enabled = 0; 8964 } 8965 8966 safe_setprop(inode, enabled_attr, enabled ? true : false); 8967 8968 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8969 scfdie(); 8970 8971 (void) memset(&pgelts, 0, sizeof (pgelts)); 8972 8973 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8974 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8975 scfdie(); 8976 8977 if (strcmp(exp_str, scf_property_enabled) == 0) { 8978 continue; 8979 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8980 xmlNodePtr rnode, sfnode; 8981 8982 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8983 if (rnode == NULL) 8984 uu_die(emsg_create_xml); 8985 8986 sfnode = xmlNewChild(rnode, NULL, 8987 (xmlChar *)"service_fmri", NULL); 8988 if (sfnode == NULL) 8989 uu_die(emsg_create_xml); 8990 8991 if (set_attr_from_prop(exp_prop, sfnode, 8992 value_attr) == 0) { 8993 elts->restarter = rnode; 8994 continue; 8995 } 8996 8997 xmlFreeNode(rnode); 8998 } 8999 9000 export_property(exp_prop, exp_str, &pgelts, 0); 9001 } 9002 if (ret == -1) 9003 scfdie(); 9004 9005 if (pgelts.propvals != NULL || pgelts.properties != NULL) 9006 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 9007 elts); 9008 } 9009 9010 /* 9011 * Put an instance element for the given instance into selts. 9012 */ 9013 static void 9014 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 9015 { 9016 xmlNodePtr n; 9017 boolean_t isdefault; 9018 struct entity_elts elts; 9019 struct template_elts template_elts; 9020 int ret; 9021 9022 n = xmlNewNode(NULL, (xmlChar *)"instance"); 9023 if (n == NULL) 9024 uu_die(emsg_create_xml); 9025 9026 /* name */ 9027 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 9028 scfdie(); 9029 safe_setprop(n, name_attr, exp_str); 9030 isdefault = strcmp(exp_str, "default") == 0; 9031 9032 /* check existance of general pg (since general/enabled is required) */ 9033 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 9034 if (scf_error() != SCF_ERROR_NOT_FOUND) 9035 scfdie(); 9036 9037 if (g_verbose) { 9038 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 9039 scfdie(); 9040 9041 warn(gettext("Instance %s has no general property " 9042 "group; it will be marked disabled.\n"), exp_str); 9043 } 9044 9045 safe_setprop(n, enabled_attr, false); 9046 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 9047 strcmp(exp_str, scf_group_framework) != 0) { 9048 if (g_verbose) { 9049 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 9050 scfdie(); 9051 9052 warn(gettext("Property group %s is not of type " 9053 "framework; the instance will be marked " 9054 "disabled.\n"), exp_str); 9055 } 9056 9057 safe_setprop(n, enabled_attr, false); 9058 } 9059 9060 /* property groups */ 9061 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 9062 scfdie(); 9063 9064 (void) memset(&elts, 0, sizeof (elts)); 9065 (void) memset(&template_elts, 0, sizeof (template_elts)); 9066 9067 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 9068 uint32_t pgflags; 9069 9070 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 9071 scfdie(); 9072 9073 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 9074 continue; 9075 9076 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 9077 scfdie(); 9078 9079 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 9080 export_dependency(exp_pg, &elts); 9081 continue; 9082 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 9083 export_method(exp_pg, &elts); 9084 continue; 9085 } else if (strcmp(exp_str, scf_group_framework) == 0) { 9086 if (scf_pg_get_name(exp_pg, exp_str, 9087 max_scf_name_len + 1) < 0) 9088 scfdie(); 9089 9090 if (strcmp(exp_str, scf_pg_general) == 0) { 9091 export_inst_general(exp_pg, n, &elts); 9092 continue; 9093 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 9094 0) { 9095 export_method_context(exp_pg, &elts); 9096 continue; 9097 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 9098 export_dependents(exp_pg, &elts); 9099 continue; 9100 } 9101 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 9102 export_template(exp_pg, &elts, &template_elts); 9103 continue; 9104 } 9105 9106 /* Ordinary pg. */ 9107 export_pg(exp_pg, &elts, flags); 9108 } 9109 if (ret == -1) 9110 scfdie(); 9111 9112 if (template_elts.common_name != NULL) { 9113 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9114 (void) xmlAddChild(elts.template, template_elts.common_name); 9115 (void) xmlAddChild(elts.template, template_elts.description); 9116 (void) xmlAddChild(elts.template, template_elts.documentation); 9117 } else { 9118 xmlFreeNode(template_elts.description); 9119 xmlFreeNode(template_elts.documentation); 9120 } 9121 9122 if (isdefault && elts.restarter == NULL && 9123 elts.dependencies == NULL && elts.method_context == NULL && 9124 elts.exec_methods == NULL && elts.property_groups == NULL && 9125 elts.template == NULL) { 9126 xmlChar *eval; 9127 9128 /* This is a default instance */ 9129 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 9130 9131 xmlFreeNode(n); 9132 9133 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 9134 if (n == NULL) 9135 uu_die(emsg_create_xml); 9136 9137 safe_setprop(n, enabled_attr, (char *)eval); 9138 xmlFree(eval); 9139 9140 selts->create_default_instance = n; 9141 } else { 9142 /* Assemble the children in order. */ 9143 (void) xmlAddChild(n, elts.restarter); 9144 (void) xmlAddChildList(n, elts.dependencies); 9145 (void) xmlAddChildList(n, elts.dependents); 9146 (void) xmlAddChild(n, elts.method_context); 9147 (void) xmlAddChildList(n, elts.exec_methods); 9148 (void) xmlAddChildList(n, elts.property_groups); 9149 (void) xmlAddChild(n, elts.template); 9150 9151 if (selts->instances == NULL) 9152 selts->instances = n; 9153 else 9154 (void) xmlAddSibling(selts->instances, n); 9155 } 9156 } 9157 9158 /* 9159 * Return a service element for the given service. 9160 */ 9161 static xmlNodePtr 9162 export_service(scf_service_t *svc, int flags) 9163 { 9164 xmlNodePtr snode; 9165 struct entity_elts elts; 9166 struct template_elts template_elts; 9167 int ret; 9168 9169 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9170 if (snode == NULL) 9171 uu_die(emsg_create_xml); 9172 9173 /* Get & set name attribute */ 9174 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 9175 scfdie(); 9176 safe_setprop(snode, name_attr, exp_str); 9177 9178 safe_setprop(snode, type_attr, "service"); 9179 safe_setprop(snode, "version", "0"); 9180 9181 /* Acquire child elements. */ 9182 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 9183 scfdie(); 9184 9185 (void) memset(&elts, 0, sizeof (elts)); 9186 (void) memset(&template_elts, 0, sizeof (template_elts)); 9187 9188 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 9189 uint32_t pgflags; 9190 9191 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 9192 scfdie(); 9193 9194 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 9195 continue; 9196 9197 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 9198 scfdie(); 9199 9200 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 9201 export_dependency(exp_pg, &elts); 9202 continue; 9203 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 9204 export_method(exp_pg, &elts); 9205 continue; 9206 } else if (strcmp(exp_str, scf_group_framework) == 0) { 9207 if (scf_pg_get_name(exp_pg, exp_str, 9208 max_scf_name_len + 1) < 0) 9209 scfdie(); 9210 9211 if (strcmp(exp_str, scf_pg_general) == 0) { 9212 export_svc_general(exp_pg, &elts); 9213 continue; 9214 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 9215 0) { 9216 export_method_context(exp_pg, &elts); 9217 continue; 9218 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 9219 export_dependents(exp_pg, &elts); 9220 continue; 9221 } 9222 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 9223 export_template(exp_pg, &elts, &template_elts); 9224 continue; 9225 } 9226 9227 export_pg(exp_pg, &elts, flags); 9228 } 9229 if (ret == -1) 9230 scfdie(); 9231 9232 if (template_elts.common_name != NULL) { 9233 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9234 (void) xmlAddChild(elts.template, template_elts.common_name); 9235 (void) xmlAddChild(elts.template, template_elts.description); 9236 (void) xmlAddChild(elts.template, template_elts.documentation); 9237 } else { 9238 xmlFreeNode(template_elts.description); 9239 xmlFreeNode(template_elts.documentation); 9240 } 9241 9242 /* Iterate instances */ 9243 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 9244 scfdie(); 9245 9246 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 9247 export_instance(exp_inst, &elts, flags); 9248 if (ret == -1) 9249 scfdie(); 9250 9251 /* Now add all of the accumulated elements in order. */ 9252 (void) xmlAddChild(snode, elts.create_default_instance); 9253 (void) xmlAddChild(snode, elts.single_instance); 9254 (void) xmlAddChild(snode, elts.restarter); 9255 (void) xmlAddChildList(snode, elts.dependencies); 9256 (void) xmlAddChildList(snode, elts.dependents); 9257 (void) xmlAddChild(snode, elts.method_context); 9258 (void) xmlAddChildList(snode, elts.exec_methods); 9259 (void) xmlAddChildList(snode, elts.property_groups); 9260 (void) xmlAddChildList(snode, elts.instances); 9261 (void) xmlAddChild(snode, elts.stability); 9262 (void) xmlAddChild(snode, elts.template); 9263 9264 return (snode); 9265 } 9266 9267 static int 9268 export_callback(void *data, scf_walkinfo_t *wip) 9269 { 9270 FILE *f; 9271 xmlDocPtr doc; 9272 xmlNodePtr sb; 9273 int result; 9274 struct export_args *argsp = (struct export_args *)data; 9275 9276 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 9277 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9278 (exp_prop = scf_property_create(g_hndl)) == NULL || 9279 (exp_val = scf_value_create(g_hndl)) == NULL || 9280 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9281 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9282 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9283 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9284 scfdie(); 9285 9286 exp_str_sz = max_scf_len + 1; 9287 exp_str = safe_malloc(exp_str_sz); 9288 9289 if (argsp->filename != NULL) { 9290 errno = 0; 9291 f = fopen(argsp->filename, "wb"); 9292 if (f == NULL) { 9293 if (errno == 0) 9294 uu_die(gettext("Could not open \"%s\": no free " 9295 "stdio streams.\n"), argsp->filename); 9296 else 9297 uu_die(gettext("Could not open \"%s\""), 9298 argsp->filename); 9299 } 9300 } else 9301 f = stdout; 9302 9303 doc = xmlNewDoc((xmlChar *)"1.0"); 9304 if (doc == NULL) 9305 uu_die(gettext("Could not create XML document.\n")); 9306 9307 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9308 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9309 uu_die(emsg_create_xml); 9310 9311 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9312 if (sb == NULL) 9313 uu_die(emsg_create_xml); 9314 safe_setprop(sb, type_attr, "manifest"); 9315 safe_setprop(sb, name_attr, "export"); 9316 (void) xmlAddSibling(doc->children, sb); 9317 9318 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 9319 9320 result = write_service_bundle(doc, f); 9321 9322 free(exp_str); 9323 scf_iter_destroy(exp_val_iter); 9324 scf_iter_destroy(exp_prop_iter); 9325 scf_iter_destroy(exp_pg_iter); 9326 scf_iter_destroy(exp_inst_iter); 9327 scf_value_destroy(exp_val); 9328 scf_property_destroy(exp_prop); 9329 scf_pg_destroy(exp_pg); 9330 scf_instance_destroy(exp_inst); 9331 9332 xmlFreeDoc(doc); 9333 9334 if (f != stdout) 9335 (void) fclose(f); 9336 9337 return (result); 9338 } 9339 9340 /* 9341 * Get the service named by fmri, build an XML tree which represents it, and 9342 * dump it into filename (or stdout if filename is NULL). 9343 */ 9344 int 9345 lscf_service_export(char *fmri, const char *filename, int flags) 9346 { 9347 struct export_args args; 9348 int ret, err; 9349 9350 lscf_prep_hndl(); 9351 9352 bzero(&args, sizeof (args)); 9353 args.filename = filename; 9354 args.flags = flags; 9355 9356 err = 0; 9357 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 9358 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 9359 &args, &err, semerr)) != 0) { 9360 if (ret != -1) 9361 semerr(gettext("Failed to walk instances: %s\n"), 9362 scf_strerror(ret)); 9363 return (-1); 9364 } 9365 9366 /* 9367 * Error message has already been printed. 9368 */ 9369 if (err != 0) 9370 return (-1); 9371 9372 return (0); 9373 } 9374 9375 9376 /* 9377 * Archive 9378 */ 9379 9380 static xmlNodePtr 9381 make_archive(int flags) 9382 { 9383 xmlNodePtr sb; 9384 scf_scope_t *scope; 9385 scf_service_t *svc; 9386 scf_iter_t *iter; 9387 int r; 9388 9389 if ((scope = scf_scope_create(g_hndl)) == NULL || 9390 (svc = scf_service_create(g_hndl)) == NULL || 9391 (iter = scf_iter_create(g_hndl)) == NULL || 9392 (exp_inst = scf_instance_create(g_hndl)) == NULL || 9393 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9394 (exp_prop = scf_property_create(g_hndl)) == NULL || 9395 (exp_val = scf_value_create(g_hndl)) == NULL || 9396 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9397 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9398 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9399 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9400 scfdie(); 9401 9402 exp_str_sz = max_scf_len + 1; 9403 exp_str = safe_malloc(exp_str_sz); 9404 9405 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9406 if (sb == NULL) 9407 uu_die(emsg_create_xml); 9408 safe_setprop(sb, type_attr, "archive"); 9409 safe_setprop(sb, name_attr, "none"); 9410 9411 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 9412 scfdie(); 9413 if (scf_iter_scope_services(iter, scope) != 0) 9414 scfdie(); 9415 9416 for (;;) { 9417 r = scf_iter_next_service(iter, svc); 9418 if (r == 0) 9419 break; 9420 if (r != 1) 9421 scfdie(); 9422 9423 if (scf_service_get_name(svc, exp_str, 9424 max_scf_name_len + 1) < 0) 9425 scfdie(); 9426 9427 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 9428 continue; 9429 9430 xmlAddChild(sb, export_service(svc, flags)); 9431 } 9432 9433 free(exp_str); 9434 9435 scf_iter_destroy(exp_val_iter); 9436 scf_iter_destroy(exp_prop_iter); 9437 scf_iter_destroy(exp_pg_iter); 9438 scf_iter_destroy(exp_inst_iter); 9439 scf_value_destroy(exp_val); 9440 scf_property_destroy(exp_prop); 9441 scf_pg_destroy(exp_pg); 9442 scf_instance_destroy(exp_inst); 9443 scf_iter_destroy(iter); 9444 scf_service_destroy(svc); 9445 scf_scope_destroy(scope); 9446 9447 return (sb); 9448 } 9449 9450 int 9451 lscf_archive(const char *filename, int flags) 9452 { 9453 FILE *f; 9454 xmlDocPtr doc; 9455 int result; 9456 9457 lscf_prep_hndl(); 9458 9459 if (filename != NULL) { 9460 errno = 0; 9461 f = fopen(filename, "wb"); 9462 if (f == NULL) { 9463 if (errno == 0) 9464 uu_die(gettext("Could not open \"%s\": no free " 9465 "stdio streams.\n"), filename); 9466 else 9467 uu_die(gettext("Could not open \"%s\""), 9468 filename); 9469 } 9470 } else 9471 f = stdout; 9472 9473 doc = xmlNewDoc((xmlChar *)"1.0"); 9474 if (doc == NULL) 9475 uu_die(gettext("Could not create XML document.\n")); 9476 9477 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9478 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9479 uu_die(emsg_create_xml); 9480 9481 (void) xmlAddSibling(doc->children, make_archive(flags)); 9482 9483 result = write_service_bundle(doc, f); 9484 9485 xmlFreeDoc(doc); 9486 9487 if (f != stdout) 9488 (void) fclose(f); 9489 9490 return (result); 9491 } 9492 9493 9494 /* 9495 * "Extract" a profile. 9496 */ 9497 int 9498 lscf_profile_extract(const char *filename) 9499 { 9500 FILE *f; 9501 xmlDocPtr doc; 9502 xmlNodePtr sb, snode, inode; 9503 scf_scope_t *scope; 9504 scf_service_t *svc; 9505 scf_instance_t *inst; 9506 scf_propertygroup_t *pg; 9507 scf_property_t *prop; 9508 scf_value_t *val; 9509 scf_iter_t *siter, *iiter; 9510 int r, s; 9511 char *namebuf; 9512 uint8_t b; 9513 int result; 9514 9515 lscf_prep_hndl(); 9516 9517 if (filename != NULL) { 9518 errno = 0; 9519 f = fopen(filename, "wb"); 9520 if (f == NULL) { 9521 if (errno == 0) 9522 uu_die(gettext("Could not open \"%s\": no " 9523 "free stdio streams.\n"), filename); 9524 else 9525 uu_die(gettext("Could not open \"%s\""), 9526 filename); 9527 } 9528 } else 9529 f = stdout; 9530 9531 doc = xmlNewDoc((xmlChar *)"1.0"); 9532 if (doc == NULL) 9533 uu_die(gettext("Could not create XML document.\n")); 9534 9535 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9536 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9537 uu_die(emsg_create_xml); 9538 9539 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9540 if (sb == NULL) 9541 uu_die(emsg_create_xml); 9542 safe_setprop(sb, type_attr, "profile"); 9543 safe_setprop(sb, name_attr, "extract"); 9544 (void) xmlAddSibling(doc->children, sb); 9545 9546 if ((scope = scf_scope_create(g_hndl)) == NULL || 9547 (svc = scf_service_create(g_hndl)) == NULL || 9548 (inst = scf_instance_create(g_hndl)) == NULL || 9549 (pg = scf_pg_create(g_hndl)) == NULL || 9550 (prop = scf_property_create(g_hndl)) == NULL || 9551 (val = scf_value_create(g_hndl)) == NULL || 9552 (siter = scf_iter_create(g_hndl)) == NULL || 9553 (iiter = scf_iter_create(g_hndl)) == NULL) 9554 scfdie(); 9555 9556 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 9557 scfdie(); 9558 9559 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 9560 scfdie(); 9561 9562 namebuf = safe_malloc(max_scf_name_len + 1); 9563 9564 while ((r = scf_iter_next_service(siter, svc)) == 1) { 9565 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 9566 scfdie(); 9567 9568 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9569 if (snode == NULL) 9570 uu_die(emsg_create_xml); 9571 9572 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 9573 0) 9574 scfdie(); 9575 9576 safe_setprop(snode, name_attr, namebuf); 9577 9578 safe_setprop(snode, type_attr, "service"); 9579 safe_setprop(snode, "version", "0"); 9580 9581 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 9582 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 9583 SCF_SUCCESS) { 9584 if (scf_error() != SCF_ERROR_NOT_FOUND) 9585 scfdie(); 9586 9587 if (g_verbose) { 9588 ssize_t len; 9589 char *fmri; 9590 9591 len = 9592 scf_instance_to_fmri(inst, NULL, 0); 9593 if (len < 0) 9594 scfdie(); 9595 9596 fmri = safe_malloc(len + 1); 9597 9598 if (scf_instance_to_fmri(inst, fmri, 9599 len + 1) < 0) 9600 scfdie(); 9601 9602 warn("Instance %s has no \"%s\" " 9603 "property group.\n", fmri, 9604 scf_pg_general); 9605 9606 free(fmri); 9607 } 9608 9609 continue; 9610 } 9611 9612 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 9613 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 9614 prop_get_val(prop, val) != 0) 9615 continue; 9616 9617 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 9618 NULL); 9619 if (inode == NULL) 9620 uu_die(emsg_create_xml); 9621 9622 if (scf_instance_get_name(inst, namebuf, 9623 max_scf_name_len + 1) < 0) 9624 scfdie(); 9625 9626 safe_setprop(inode, name_attr, namebuf); 9627 9628 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 9629 scfdie(); 9630 9631 safe_setprop(inode, enabled_attr, b ? true : false); 9632 } 9633 if (s < 0) 9634 scfdie(); 9635 9636 if (snode->children != NULL) 9637 xmlAddChild(sb, snode); 9638 else 9639 xmlFreeNode(snode); 9640 } 9641 if (r < 0) 9642 scfdie(); 9643 9644 free(namebuf); 9645 9646 result = write_service_bundle(doc, f); 9647 9648 xmlFreeDoc(doc); 9649 9650 if (f != stdout) 9651 (void) fclose(f); 9652 9653 return (result); 9654 } 9655 9656 9657 /* 9658 * Entity manipulation commands 9659 */ 9660 9661 /* 9662 * Entity selection. If no entity is selected, then the current scope is in 9663 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 9664 * only cur_inst is NULL, and when an instance is selected, none are NULL. 9665 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 9666 * cur_inst will be non-NULL. 9667 */ 9668 9669 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 9670 static int 9671 select_inst(const char *name) 9672 { 9673 scf_instance_t *inst; 9674 scf_error_t err; 9675 9676 assert(cur_svc != NULL); 9677 9678 inst = scf_instance_create(g_hndl); 9679 if (inst == NULL) 9680 scfdie(); 9681 9682 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 9683 cur_inst = inst; 9684 return (0); 9685 } 9686 9687 err = scf_error(); 9688 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9689 scfdie(); 9690 9691 scf_instance_destroy(inst); 9692 return (1); 9693 } 9694 9695 /* Returns as above. */ 9696 static int 9697 select_svc(const char *name) 9698 { 9699 scf_service_t *svc; 9700 scf_error_t err; 9701 9702 assert(cur_scope != NULL); 9703 9704 svc = scf_service_create(g_hndl); 9705 if (svc == NULL) 9706 scfdie(); 9707 9708 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 9709 cur_svc = svc; 9710 return (0); 9711 } 9712 9713 err = scf_error(); 9714 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9715 scfdie(); 9716 9717 scf_service_destroy(svc); 9718 return (1); 9719 } 9720 9721 /* ARGSUSED */ 9722 static int 9723 select_callback(void *unused, scf_walkinfo_t *wip) 9724 { 9725 scf_instance_t *inst; 9726 scf_service_t *svc; 9727 scf_scope_t *scope; 9728 9729 if (wip->inst != NULL) { 9730 if ((scope = scf_scope_create(g_hndl)) == NULL || 9731 (svc = scf_service_create(g_hndl)) == NULL || 9732 (inst = scf_instance_create(g_hndl)) == NULL) 9733 scfdie(); 9734 9735 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9736 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9737 scfdie(); 9738 } else { 9739 assert(wip->svc != NULL); 9740 9741 if ((scope = scf_scope_create(g_hndl)) == NULL || 9742 (svc = scf_service_create(g_hndl)) == NULL) 9743 scfdie(); 9744 9745 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9746 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9747 scfdie(); 9748 9749 inst = NULL; 9750 } 9751 9752 /* Clear out the current selection */ 9753 assert(cur_scope != NULL); 9754 scf_scope_destroy(cur_scope); 9755 scf_service_destroy(cur_svc); 9756 scf_instance_destroy(cur_inst); 9757 9758 cur_scope = scope; 9759 cur_svc = svc; 9760 cur_inst = inst; 9761 9762 return (0); 9763 } 9764 9765 static int 9766 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 9767 { 9768 char **fmri = fmri_p; 9769 9770 *fmri = strdup(wip->fmri); 9771 if (*fmri == NULL) 9772 uu_die(gettext("Out of memory.\n")); 9773 9774 return (0); 9775 } 9776 9777 /* 9778 * validate [fmri] 9779 * Perform the validation of an FMRI instance. 9780 */ 9781 void 9782 lscf_validate_fmri(const char *fmri) 9783 { 9784 int ret = 0; 9785 size_t inst_sz; 9786 char *inst_fmri = NULL; 9787 scf_tmpl_errors_t *errs = NULL; 9788 char *snapbuf = NULL; 9789 9790 lscf_prep_hndl(); 9791 9792 if (fmri == NULL) { 9793 inst_sz = max_scf_fmri_len + 1; 9794 inst_fmri = safe_malloc(inst_sz); 9795 9796 if (cur_snap != NULL) { 9797 snapbuf = safe_malloc(max_scf_name_len + 1); 9798 if (scf_snapshot_get_name(cur_snap, snapbuf, 9799 max_scf_name_len + 1) < 0) 9800 scfdie(); 9801 } 9802 if (cur_inst == NULL) { 9803 semerr(gettext("No instance selected\n")); 9804 goto cleanup; 9805 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 9806 inst_sz) >= inst_sz) { 9807 /* sanity check. Should never get here */ 9808 uu_die(gettext("Unexpected error! file %s, line %d\n"), 9809 __FILE__, __LINE__); 9810 } 9811 } else { 9812 scf_error_t scf_err; 9813 int err = 0; 9814 9815 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 9816 validate_callback, &inst_fmri, &err, semerr)) != 0) { 9817 uu_warn("Failed to walk instances: %s\n", 9818 scf_strerror(scf_err)); 9819 goto cleanup; 9820 } 9821 if (err != 0) { 9822 /* error message displayed by scf_walk_fmri */ 9823 goto cleanup; 9824 } 9825 } 9826 9827 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 9828 SCF_TMPL_VALIDATE_FLAG_CURRENT); 9829 if (ret == -1) { 9830 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 9831 warn(gettext("Template data for %s is invalid. " 9832 "Consider reverting to a previous snapshot or " 9833 "restoring original configuration.\n"), inst_fmri); 9834 } else { 9835 uu_warn("%s: %s\n", 9836 gettext("Error validating the instance"), 9837 scf_strerror(scf_error())); 9838 } 9839 } else if (ret == 1 && errs != NULL) { 9840 scf_tmpl_error_t *err = NULL; 9841 char *msg; 9842 size_t len = 256; /* initial error buffer size */ 9843 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 9844 SCF_TMPL_STRERROR_HUMAN : 0; 9845 9846 msg = safe_malloc(len); 9847 9848 while ((err = scf_tmpl_next_error(errs)) != NULL) { 9849 int ret; 9850 9851 if ((ret = scf_tmpl_strerror(err, msg, len, 9852 flag)) >= len) { 9853 len = ret + 1; 9854 msg = realloc(msg, len); 9855 if (msg == NULL) 9856 uu_die(gettext( 9857 "Out of memory.\n")); 9858 (void) scf_tmpl_strerror(err, msg, len, 9859 flag); 9860 } 9861 (void) fprintf(stderr, "%s\n", msg); 9862 } 9863 if (msg != NULL) 9864 free(msg); 9865 } 9866 if (errs != NULL) 9867 scf_tmpl_errors_destroy(errs); 9868 9869 cleanup: 9870 free(inst_fmri); 9871 free(snapbuf); 9872 } 9873 9874 static void 9875 lscf_validate_file(const char *filename) 9876 { 9877 tmpl_errors_t *errs; 9878 9879 bundle_t *b = internal_bundle_new(); 9880 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 9881 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 9882 tmpl_errors_print(stderr, errs, ""); 9883 semerr(gettext("Validation failed.\n")); 9884 } 9885 tmpl_errors_destroy(errs); 9886 } 9887 (void) internal_bundle_free(b); 9888 } 9889 9890 /* 9891 * validate [fmri|file] 9892 */ 9893 void 9894 lscf_validate(const char *arg) 9895 { 9896 const char *str; 9897 9898 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 9899 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 9900 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 9901 lscf_validate_file(str); 9902 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 9903 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 9904 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 9905 lscf_validate_fmri(str); 9906 } else if (access(arg, R_OK | F_OK) == 0) { 9907 lscf_validate_file(arg); 9908 } else { 9909 lscf_validate_fmri(arg); 9910 } 9911 } 9912 9913 void 9914 lscf_select(const char *fmri) 9915 { 9916 int ret, err; 9917 9918 lscf_prep_hndl(); 9919 9920 if (cur_snap != NULL) { 9921 struct snaplevel *elt; 9922 char *buf; 9923 9924 /* Error unless name is that of the next level. */ 9925 elt = uu_list_next(cur_levels, cur_elt); 9926 if (elt == NULL) { 9927 semerr(gettext("No children.\n")); 9928 return; 9929 } 9930 9931 buf = safe_malloc(max_scf_name_len + 1); 9932 9933 if (scf_snaplevel_get_instance_name(elt->sl, buf, 9934 max_scf_name_len + 1) < 0) 9935 scfdie(); 9936 9937 if (strcmp(buf, fmri) != 0) { 9938 semerr(gettext("No such child.\n")); 9939 free(buf); 9940 return; 9941 } 9942 9943 free(buf); 9944 9945 cur_elt = elt; 9946 cur_level = elt->sl; 9947 return; 9948 } 9949 9950 /* 9951 * Special case for 'svc:', which takes the user to the scope level. 9952 */ 9953 if (strcmp(fmri, "svc:") == 0) { 9954 scf_instance_destroy(cur_inst); 9955 scf_service_destroy(cur_svc); 9956 cur_inst = NULL; 9957 cur_svc = NULL; 9958 return; 9959 } 9960 9961 /* 9962 * Special case for ':properties'. This appears as part of 'list' but 9963 * can't be selected. Give a more helpful error message in this case. 9964 */ 9965 if (strcmp(fmri, ":properties") == 0) { 9966 semerr(gettext(":properties is not an entity. Try 'listprop' " 9967 "to list properties.\n")); 9968 return; 9969 } 9970 9971 /* 9972 * First try the argument as relative to the current selection. 9973 */ 9974 if (cur_inst != NULL) { 9975 /* EMPTY */; 9976 } else if (cur_svc != NULL) { 9977 if (select_inst(fmri) != 1) 9978 return; 9979 } else { 9980 if (select_svc(fmri) != 1) 9981 return; 9982 } 9983 9984 err = 0; 9985 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 9986 select_callback, NULL, &err, semerr)) != 0) { 9987 semerr(gettext("Failed to walk instances: %s\n"), 9988 scf_strerror(ret)); 9989 } 9990 } 9991 9992 void 9993 lscf_unselect(void) 9994 { 9995 lscf_prep_hndl(); 9996 9997 if (cur_snap != NULL) { 9998 struct snaplevel *elt; 9999 10000 elt = uu_list_prev(cur_levels, cur_elt); 10001 if (elt == NULL) { 10002 semerr(gettext("No parent levels.\n")); 10003 } else { 10004 cur_elt = elt; 10005 cur_level = elt->sl; 10006 } 10007 } else if (cur_inst != NULL) { 10008 scf_instance_destroy(cur_inst); 10009 cur_inst = NULL; 10010 } else if (cur_svc != NULL) { 10011 scf_service_destroy(cur_svc); 10012 cur_svc = NULL; 10013 } else { 10014 semerr(gettext("Cannot unselect at scope level.\n")); 10015 } 10016 } 10017 10018 /* 10019 * Return the FMRI of the current selection, for the prompt. 10020 */ 10021 void 10022 lscf_get_selection_str(char *buf, size_t bufsz) 10023 { 10024 char *cp; 10025 ssize_t fmrilen, szret; 10026 boolean_t deleted = B_FALSE; 10027 10028 if (g_hndl == NULL) { 10029 (void) strlcpy(buf, "svc:", bufsz); 10030 return; 10031 } 10032 10033 if (cur_level != NULL) { 10034 assert(cur_snap != NULL); 10035 10036 /* [ snapshot ] FMRI [: instance ] */ 10037 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 10038 + 2 + max_scf_name_len + 1 + 1); 10039 10040 buf[0] = '['; 10041 10042 szret = scf_snapshot_get_name(cur_snap, buf + 1, 10043 max_scf_name_len + 1); 10044 if (szret < 0) { 10045 if (scf_error() != SCF_ERROR_DELETED) 10046 scfdie(); 10047 10048 goto snap_deleted; 10049 } 10050 10051 (void) strcat(buf, "]svc:/"); 10052 10053 cp = strchr(buf, '\0'); 10054 10055 szret = scf_snaplevel_get_service_name(cur_level, cp, 10056 max_scf_name_len + 1); 10057 if (szret < 0) { 10058 if (scf_error() != SCF_ERROR_DELETED) 10059 scfdie(); 10060 10061 goto snap_deleted; 10062 } 10063 10064 cp = strchr(cp, '\0'); 10065 10066 if (snaplevel_is_instance(cur_level)) { 10067 *cp++ = ':'; 10068 10069 if (scf_snaplevel_get_instance_name(cur_level, cp, 10070 max_scf_name_len + 1) < 0) { 10071 if (scf_error() != SCF_ERROR_DELETED) 10072 scfdie(); 10073 10074 goto snap_deleted; 10075 } 10076 } else { 10077 *cp++ = '['; 10078 *cp++ = ':'; 10079 10080 if (scf_instance_get_name(cur_inst, cp, 10081 max_scf_name_len + 1) < 0) { 10082 if (scf_error() != SCF_ERROR_DELETED) 10083 scfdie(); 10084 10085 goto snap_deleted; 10086 } 10087 10088 (void) strcat(buf, "]"); 10089 } 10090 10091 return; 10092 10093 snap_deleted: 10094 deleted = B_TRUE; 10095 free(buf); 10096 unselect_cursnap(); 10097 } 10098 10099 assert(cur_snap == NULL); 10100 10101 if (cur_inst != NULL) { 10102 assert(cur_svc != NULL); 10103 assert(cur_scope != NULL); 10104 10105 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 10106 if (fmrilen >= 0) { 10107 assert(fmrilen < bufsz); 10108 if (deleted) 10109 warn(emsg_deleted); 10110 return; 10111 } 10112 10113 if (scf_error() != SCF_ERROR_DELETED) 10114 scfdie(); 10115 10116 deleted = B_TRUE; 10117 10118 scf_instance_destroy(cur_inst); 10119 cur_inst = NULL; 10120 } 10121 10122 if (cur_svc != NULL) { 10123 assert(cur_scope != NULL); 10124 10125 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 10126 if (szret >= 0) { 10127 assert(szret < bufsz); 10128 if (deleted) 10129 warn(emsg_deleted); 10130 return; 10131 } 10132 10133 if (scf_error() != SCF_ERROR_DELETED) 10134 scfdie(); 10135 10136 deleted = B_TRUE; 10137 scf_service_destroy(cur_svc); 10138 cur_svc = NULL; 10139 } 10140 10141 assert(cur_scope != NULL); 10142 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 10143 10144 if (fmrilen < 0) 10145 scfdie(); 10146 10147 assert(fmrilen < bufsz); 10148 if (deleted) 10149 warn(emsg_deleted); 10150 } 10151 10152 /* 10153 * Entity listing. Entities and colon namespaces (e.g., :properties and 10154 * :statistics) are listed for the current selection. 10155 */ 10156 void 10157 lscf_list(const char *pattern) 10158 { 10159 scf_iter_t *iter; 10160 char *buf; 10161 int ret; 10162 10163 lscf_prep_hndl(); 10164 10165 if (cur_level != NULL) { 10166 struct snaplevel *elt; 10167 10168 (void) fputs(COLON_NAMESPACES, stdout); 10169 10170 elt = uu_list_next(cur_levels, cur_elt); 10171 if (elt == NULL) 10172 return; 10173 10174 /* 10175 * For now, we know that the next level is an instance. But 10176 * if we ever have multiple scopes, this could be complicated. 10177 */ 10178 buf = safe_malloc(max_scf_name_len + 1); 10179 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10180 max_scf_name_len + 1) >= 0) { 10181 (void) puts(buf); 10182 } else { 10183 if (scf_error() != SCF_ERROR_DELETED) 10184 scfdie(); 10185 } 10186 10187 free(buf); 10188 10189 return; 10190 } 10191 10192 if (cur_inst != NULL) { 10193 (void) fputs(COLON_NAMESPACES, stdout); 10194 return; 10195 } 10196 10197 iter = scf_iter_create(g_hndl); 10198 if (iter == NULL) 10199 scfdie(); 10200 10201 buf = safe_malloc(max_scf_name_len + 1); 10202 10203 if (cur_svc != NULL) { 10204 /* List the instances in this service. */ 10205 scf_instance_t *inst; 10206 10207 inst = scf_instance_create(g_hndl); 10208 if (inst == NULL) 10209 scfdie(); 10210 10211 if (scf_iter_service_instances(iter, cur_svc) == 0) { 10212 safe_printf(COLON_NAMESPACES); 10213 10214 for (;;) { 10215 ret = scf_iter_next_instance(iter, inst); 10216 if (ret == 0) 10217 break; 10218 if (ret != 1) { 10219 if (scf_error() != SCF_ERROR_DELETED) 10220 scfdie(); 10221 10222 break; 10223 } 10224 10225 if (scf_instance_get_name(inst, buf, 10226 max_scf_name_len + 1) >= 0) { 10227 if (pattern == NULL || 10228 fnmatch(pattern, buf, 0) == 0) 10229 (void) puts(buf); 10230 } else { 10231 if (scf_error() != SCF_ERROR_DELETED) 10232 scfdie(); 10233 } 10234 } 10235 } else { 10236 if (scf_error() != SCF_ERROR_DELETED) 10237 scfdie(); 10238 } 10239 10240 scf_instance_destroy(inst); 10241 } else { 10242 /* List the services in this scope. */ 10243 scf_service_t *svc; 10244 10245 assert(cur_scope != NULL); 10246 10247 svc = scf_service_create(g_hndl); 10248 if (svc == NULL) 10249 scfdie(); 10250 10251 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 10252 scfdie(); 10253 10254 for (;;) { 10255 ret = scf_iter_next_service(iter, svc); 10256 if (ret == 0) 10257 break; 10258 if (ret != 1) 10259 scfdie(); 10260 10261 if (scf_service_get_name(svc, buf, 10262 max_scf_name_len + 1) >= 0) { 10263 if (pattern == NULL || 10264 fnmatch(pattern, buf, 0) == 0) 10265 safe_printf("%s\n", buf); 10266 } else { 10267 if (scf_error() != SCF_ERROR_DELETED) 10268 scfdie(); 10269 } 10270 } 10271 10272 scf_service_destroy(svc); 10273 } 10274 10275 free(buf); 10276 scf_iter_destroy(iter); 10277 } 10278 10279 /* 10280 * Entity addition. Creates an empty entity in the current selection. 10281 */ 10282 void 10283 lscf_add(const char *name) 10284 { 10285 lscf_prep_hndl(); 10286 10287 if (cur_snap != NULL) { 10288 semerr(emsg_cant_modify_snapshots); 10289 } else if (cur_inst != NULL) { 10290 semerr(gettext("Cannot add entities to an instance.\n")); 10291 } else if (cur_svc != NULL) { 10292 10293 if (scf_service_add_instance(cur_svc, name, NULL) != 10294 SCF_SUCCESS) { 10295 switch (scf_error()) { 10296 case SCF_ERROR_INVALID_ARGUMENT: 10297 semerr(gettext("Invalid name.\n")); 10298 break; 10299 10300 case SCF_ERROR_EXISTS: 10301 semerr(gettext("Instance already exists.\n")); 10302 break; 10303 10304 case SCF_ERROR_PERMISSION_DENIED: 10305 semerr(emsg_permission_denied); 10306 break; 10307 10308 default: 10309 scfdie(); 10310 } 10311 } 10312 } else { 10313 assert(cur_scope != NULL); 10314 10315 if (scf_scope_add_service(cur_scope, name, NULL) != 10316 SCF_SUCCESS) { 10317 switch (scf_error()) { 10318 case SCF_ERROR_INVALID_ARGUMENT: 10319 semerr(gettext("Invalid name.\n")); 10320 break; 10321 10322 case SCF_ERROR_EXISTS: 10323 semerr(gettext("Service already exists.\n")); 10324 break; 10325 10326 case SCF_ERROR_PERMISSION_DENIED: 10327 semerr(emsg_permission_denied); 10328 break; 10329 10330 case SCF_ERROR_BACKEND_READONLY: 10331 semerr(emsg_read_only); 10332 break; 10333 10334 default: 10335 scfdie(); 10336 } 10337 } 10338 } 10339 } 10340 10341 /* return 1 if the entity has no persistent pgs, else return 0 */ 10342 static int 10343 entity_has_no_pgs(void *ent, int isservice) 10344 { 10345 scf_iter_t *iter = NULL; 10346 scf_propertygroup_t *pg = NULL; 10347 uint32_t flags; 10348 int err; 10349 int ret = 1; 10350 10351 if ((iter = scf_iter_create(g_hndl)) == NULL || 10352 (pg = scf_pg_create(g_hndl)) == NULL) 10353 scfdie(); 10354 10355 if (isservice) { 10356 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 10357 scfdie(); 10358 } else { 10359 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 10360 scfdie(); 10361 } 10362 10363 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 10364 if (scf_pg_get_flags(pg, &flags) != 0) 10365 scfdie(); 10366 10367 /* skip nonpersistent pgs */ 10368 if (flags & SCF_PG_FLAG_NONPERSISTENT) 10369 continue; 10370 10371 ret = 0; 10372 break; 10373 } 10374 10375 if (err == -1) 10376 scfdie(); 10377 10378 scf_pg_destroy(pg); 10379 scf_iter_destroy(iter); 10380 10381 return (ret); 10382 } 10383 10384 /* return 1 if the service has no instances, else return 0 */ 10385 static int 10386 svc_has_no_insts(scf_service_t *svc) 10387 { 10388 scf_instance_t *inst; 10389 scf_iter_t *iter; 10390 int r; 10391 int ret = 1; 10392 10393 if ((inst = scf_instance_create(g_hndl)) == NULL || 10394 (iter = scf_iter_create(g_hndl)) == NULL) 10395 scfdie(); 10396 10397 if (scf_iter_service_instances(iter, svc) != 0) 10398 scfdie(); 10399 10400 r = scf_iter_next_instance(iter, inst); 10401 if (r == 1) { 10402 ret = 0; 10403 } else if (r == 0) { 10404 ret = 1; 10405 } else if (r == -1) { 10406 scfdie(); 10407 } else { 10408 bad_error("scf_iter_next_instance", r); 10409 } 10410 10411 scf_iter_destroy(iter); 10412 scf_instance_destroy(inst); 10413 10414 return (ret); 10415 } 10416 10417 /* 10418 * Entity deletion. 10419 */ 10420 10421 /* 10422 * Delete the property group <fmri>/:properties/<name>. Returns 10423 * SCF_ERROR_NONE on success (or if the entity is not found), 10424 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 10425 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 10426 * denied. 10427 */ 10428 static scf_error_t 10429 delete_dependency_pg(const char *fmri, const char *name) 10430 { 10431 void *entity = NULL; 10432 int isservice; 10433 scf_propertygroup_t *pg = NULL; 10434 scf_error_t result; 10435 char *pgty; 10436 scf_service_t *svc = NULL; 10437 scf_instance_t *inst = NULL; 10438 scf_iter_t *iter = NULL; 10439 char *name_buf = NULL; 10440 10441 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10442 switch (result) { 10443 case SCF_ERROR_NONE: 10444 break; 10445 10446 case SCF_ERROR_NO_MEMORY: 10447 uu_die(gettext("Out of memory.\n")); 10448 /* NOTREACHED */ 10449 10450 case SCF_ERROR_INVALID_ARGUMENT: 10451 case SCF_ERROR_CONSTRAINT_VIOLATED: 10452 return (SCF_ERROR_INVALID_ARGUMENT); 10453 10454 case SCF_ERROR_NOT_FOUND: 10455 result = SCF_ERROR_NONE; 10456 goto out; 10457 10458 default: 10459 bad_error("fmri_to_entity", result); 10460 } 10461 10462 pg = scf_pg_create(g_hndl); 10463 if (pg == NULL) 10464 scfdie(); 10465 10466 if (entity_get_pg(entity, isservice, name, pg) != 0) { 10467 if (scf_error() != SCF_ERROR_NOT_FOUND) 10468 scfdie(); 10469 10470 result = SCF_ERROR_NONE; 10471 goto out; 10472 } 10473 10474 pgty = safe_malloc(max_scf_pg_type_len + 1); 10475 10476 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10477 scfdie(); 10478 10479 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 10480 result = SCF_ERROR_TYPE_MISMATCH; 10481 free(pgty); 10482 goto out; 10483 } 10484 10485 free(pgty); 10486 10487 if (scf_pg_delete(pg) != 0) { 10488 result = scf_error(); 10489 if (result != SCF_ERROR_PERMISSION_DENIED) 10490 scfdie(); 10491 goto out; 10492 } 10493 10494 /* 10495 * We have to handle the case where we've just deleted the last 10496 * property group of a "dummy" entity (instance or service). 10497 * A "dummy" entity is an entity only present to hold an 10498 * external dependency. 10499 * So, in the case we deleted the last property group then we 10500 * can also delete the entity. If the entity is an instance then 10501 * we must verify if this was the last instance for the service 10502 * and if it is, we can also delete the service if it doesn't 10503 * have any property group either. 10504 */ 10505 10506 result = SCF_ERROR_NONE; 10507 10508 if (isservice) { 10509 svc = (scf_service_t *)entity; 10510 10511 if ((inst = scf_instance_create(g_hndl)) == NULL || 10512 (iter = scf_iter_create(g_hndl)) == NULL) 10513 scfdie(); 10514 10515 name_buf = safe_malloc(max_scf_name_len + 1); 10516 } else { 10517 inst = (scf_instance_t *)entity; 10518 } 10519 10520 /* 10521 * If the entity is an instance and we've just deleted its last 10522 * property group then we should delete it. 10523 */ 10524 if (!isservice && entity_has_no_pgs(entity, isservice)) { 10525 /* find the service before deleting the inst. - needed later */ 10526 if ((svc = scf_service_create(g_hndl)) == NULL) 10527 scfdie(); 10528 10529 if (scf_instance_get_parent(inst, svc) != 0) 10530 scfdie(); 10531 10532 /* delete the instance */ 10533 if (scf_instance_delete(inst) != 0) { 10534 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10535 scfdie(); 10536 10537 result = SCF_ERROR_PERMISSION_DENIED; 10538 goto out; 10539 } 10540 /* no need to refresh the instance */ 10541 inst = NULL; 10542 } 10543 10544 /* 10545 * If the service has no more instances and pgs or we just deleted the 10546 * last instance and the service doesn't have anymore propery groups 10547 * then the service should be deleted. 10548 */ 10549 if (svc != NULL && 10550 svc_has_no_insts(svc) && 10551 entity_has_no_pgs((void *)svc, 1)) { 10552 if (scf_service_delete(svc) == 0) { 10553 if (isservice) { 10554 /* no need to refresh the service */ 10555 svc = NULL; 10556 } 10557 10558 goto out; 10559 } 10560 10561 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10562 scfdie(); 10563 10564 result = SCF_ERROR_PERMISSION_DENIED; 10565 } 10566 10567 /* if the entity has not been deleted, refresh it */ 10568 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 10569 (void) refresh_entity(isservice, entity, fmri, inst, iter, 10570 name_buf); 10571 } 10572 10573 out: 10574 if (isservice && (inst != NULL && iter != NULL)) { 10575 free(name_buf); 10576 scf_iter_destroy(iter); 10577 scf_instance_destroy(inst); 10578 } 10579 10580 if (!isservice && svc != NULL) { 10581 scf_service_destroy(svc); 10582 } 10583 10584 scf_pg_destroy(pg); 10585 if (entity != NULL) 10586 entity_destroy(entity, isservice); 10587 10588 return (result); 10589 } 10590 10591 static int 10592 delete_dependents(scf_propertygroup_t *pg) 10593 { 10594 char *pgty, *name, *fmri; 10595 scf_property_t *prop; 10596 scf_value_t *val; 10597 scf_iter_t *iter; 10598 int r; 10599 scf_error_t err; 10600 10601 /* Verify that the pg has the correct type. */ 10602 pgty = safe_malloc(max_scf_pg_type_len + 1); 10603 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10604 scfdie(); 10605 10606 if (strcmp(pgty, scf_group_framework) != 0) { 10607 if (g_verbose) { 10608 fmri = safe_malloc(max_scf_fmri_len + 1); 10609 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 10610 scfdie(); 10611 10612 warn(gettext("Property group %s is not of expected " 10613 "type %s.\n"), fmri, scf_group_framework); 10614 10615 free(fmri); 10616 } 10617 10618 free(pgty); 10619 return (-1); 10620 } 10621 10622 free(pgty); 10623 10624 /* map delete_dependency_pg onto the properties. */ 10625 if ((prop = scf_property_create(g_hndl)) == NULL || 10626 (val = scf_value_create(g_hndl)) == NULL || 10627 (iter = scf_iter_create(g_hndl)) == NULL) 10628 scfdie(); 10629 10630 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10631 scfdie(); 10632 10633 name = safe_malloc(max_scf_name_len + 1); 10634 fmri = safe_malloc(max_scf_fmri_len + 2); 10635 10636 while ((r = scf_iter_next_property(iter, prop)) == 1) { 10637 scf_type_t ty; 10638 10639 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 10640 scfdie(); 10641 10642 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 10643 scfdie(); 10644 10645 if ((ty != SCF_TYPE_ASTRING && 10646 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 10647 prop_get_val(prop, val) != 0) 10648 continue; 10649 10650 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 10651 scfdie(); 10652 10653 err = delete_dependency_pg(fmri, name); 10654 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 10655 if (scf_property_to_fmri(prop, fmri, 10656 max_scf_fmri_len + 2) < 0) 10657 scfdie(); 10658 10659 warn(gettext("Value of %s is not a valid FMRI.\n"), 10660 fmri); 10661 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 10662 warn(gettext("Property group \"%s\" of entity \"%s\" " 10663 "does not have dependency type.\n"), name, fmri); 10664 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 10665 warn(gettext("Could not delete property group \"%s\" " 10666 "of entity \"%s\" (permission denied).\n"), name, 10667 fmri); 10668 } 10669 } 10670 if (r == -1) 10671 scfdie(); 10672 10673 scf_value_destroy(val); 10674 scf_property_destroy(prop); 10675 10676 return (0); 10677 } 10678 10679 /* 10680 * Returns 1 if the instance may be running, and 0 otherwise. 10681 */ 10682 static int 10683 inst_is_running(scf_instance_t *inst) 10684 { 10685 scf_propertygroup_t *pg; 10686 scf_property_t *prop; 10687 scf_value_t *val; 10688 char buf[MAX_SCF_STATE_STRING_SZ]; 10689 int ret = 0; 10690 ssize_t szret; 10691 10692 if ((pg = scf_pg_create(g_hndl)) == NULL || 10693 (prop = scf_property_create(g_hndl)) == NULL || 10694 (val = scf_value_create(g_hndl)) == NULL) 10695 scfdie(); 10696 10697 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 10698 if (scf_error() != SCF_ERROR_NOT_FOUND) 10699 scfdie(); 10700 goto out; 10701 } 10702 10703 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 10704 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 10705 prop_get_val(prop, val) != 0) 10706 goto out; 10707 10708 szret = scf_value_get_astring(val, buf, sizeof (buf)); 10709 assert(szret >= 0); 10710 10711 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 10712 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 10713 10714 out: 10715 scf_value_destroy(val); 10716 scf_property_destroy(prop); 10717 scf_pg_destroy(pg); 10718 return (ret); 10719 } 10720 10721 static uint8_t 10722 pg_is_external_dependency(scf_propertygroup_t *pg) 10723 { 10724 char *type; 10725 scf_value_t *val; 10726 scf_property_t *prop; 10727 uint8_t b = B_FALSE; 10728 10729 type = safe_malloc(max_scf_pg_type_len + 1); 10730 10731 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 10732 scfdie(); 10733 10734 if ((prop = scf_property_create(g_hndl)) == NULL || 10735 (val = scf_value_create(g_hndl)) == NULL) 10736 scfdie(); 10737 10738 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 10739 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 10740 if (scf_property_get_value(prop, val) != 0) 10741 scfdie(); 10742 if (scf_value_get_boolean(val, &b) != 0) 10743 scfdie(); 10744 } 10745 } 10746 10747 free(type); 10748 (void) scf_value_destroy(val); 10749 (void) scf_property_destroy(prop); 10750 10751 return (b); 10752 } 10753 10754 #define DELETE_FAILURE -1 10755 #define DELETE_SUCCESS_NOEXTDEPS 0 10756 #define DELETE_SUCCESS_EXTDEPS 1 10757 10758 /* 10759 * lscf_instance_delete() deletes an instance. Before calling 10760 * scf_instance_delete(), though, we make sure the instance isn't 10761 * running and delete dependencies in other entities which the instance 10762 * declared as "dependents". If there are dependencies which were 10763 * created for other entities, then instead of deleting the instance we 10764 * make it "empty" by deleting all other property groups and all 10765 * snapshots. 10766 * 10767 * lscf_instance_delete() verifies that there is no external dependency pgs 10768 * before suppressing the instance. If there is, then we must not remove them 10769 * now in case the instance is re-created otherwise the dependencies would be 10770 * lost. The external dependency pgs will be removed if the dependencies are 10771 * removed. 10772 * 10773 * Returns: 10774 * DELETE_FAILURE on failure 10775 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 10776 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 10777 */ 10778 static int 10779 lscf_instance_delete(scf_instance_t *inst, int force) 10780 { 10781 scf_propertygroup_t *pg; 10782 scf_snapshot_t *snap; 10783 scf_iter_t *iter; 10784 int err; 10785 int external = 0; 10786 10787 /* If we're not forcing and the instance is running, refuse. */ 10788 if (!force && inst_is_running(inst)) { 10789 char *fmri; 10790 10791 fmri = safe_malloc(max_scf_fmri_len + 1); 10792 10793 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 10794 scfdie(); 10795 10796 semerr(gettext("Instance %s may be running. " 10797 "Use delete -f if it is not.\n"), fmri); 10798 10799 free(fmri); 10800 return (DELETE_FAILURE); 10801 } 10802 10803 pg = scf_pg_create(g_hndl); 10804 if (pg == NULL) 10805 scfdie(); 10806 10807 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 10808 (void) delete_dependents(pg); 10809 else if (scf_error() != SCF_ERROR_NOT_FOUND) 10810 scfdie(); 10811 10812 scf_pg_destroy(pg); 10813 10814 /* 10815 * If the instance has some external dependencies then we must 10816 * keep them in case the instance is reimported otherwise the 10817 * dependencies would be lost on reimport. 10818 */ 10819 if ((iter = scf_iter_create(g_hndl)) == NULL || 10820 (pg = scf_pg_create(g_hndl)) == NULL) 10821 scfdie(); 10822 10823 if (scf_iter_instance_pgs(iter, inst) < 0) 10824 scfdie(); 10825 10826 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 10827 if (pg_is_external_dependency(pg)) { 10828 external = 1; 10829 continue; 10830 } 10831 10832 if (scf_pg_delete(pg) != 0) { 10833 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10834 scfdie(); 10835 else { 10836 semerr(emsg_permission_denied); 10837 10838 (void) scf_iter_destroy(iter); 10839 (void) scf_pg_destroy(pg); 10840 return (DELETE_FAILURE); 10841 } 10842 } 10843 } 10844 10845 if (err == -1) 10846 scfdie(); 10847 10848 (void) scf_iter_destroy(iter); 10849 (void) scf_pg_destroy(pg); 10850 10851 if (external) { 10852 /* 10853 * All the pgs have been deleted for the instance except 10854 * the ones holding the external dependencies. 10855 * For the job to be complete, we must also delete the 10856 * snapshots associated with the instance. 10857 */ 10858 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 10859 NULL) 10860 scfdie(); 10861 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 10862 scfdie(); 10863 10864 if (scf_iter_instance_snapshots(iter, inst) == -1) 10865 scfdie(); 10866 10867 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 10868 if (_scf_snapshot_delete(snap) != 0) { 10869 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10870 scfdie(); 10871 10872 semerr(emsg_permission_denied); 10873 10874 (void) scf_iter_destroy(iter); 10875 (void) scf_snapshot_destroy(snap); 10876 return (DELETE_FAILURE); 10877 } 10878 } 10879 10880 if (err == -1) 10881 scfdie(); 10882 10883 (void) scf_iter_destroy(iter); 10884 (void) scf_snapshot_destroy(snap); 10885 return (DELETE_SUCCESS_EXTDEPS); 10886 } 10887 10888 if (scf_instance_delete(inst) != 0) { 10889 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10890 scfdie(); 10891 10892 semerr(emsg_permission_denied); 10893 10894 return (DELETE_FAILURE); 10895 } 10896 10897 return (DELETE_SUCCESS_NOEXTDEPS); 10898 } 10899 10900 /* 10901 * lscf_service_delete() deletes a service. Before calling 10902 * scf_service_delete(), though, we call lscf_instance_delete() for 10903 * each of the instances and delete dependencies in other entities 10904 * which were created as "dependents" of this service. If there are 10905 * dependencies which were created for other entities, then we delete 10906 * all other property groups in the service and leave it as "empty". 10907 * 10908 * lscf_service_delete() verifies that there is no external dependency 10909 * pgs at the instance & service level before suppressing the service. 10910 * If there is, then we must not remove them now in case the service 10911 * is re-imported otherwise the dependencies would be lost. The external 10912 * dependency pgs will be removed if the dependencies are removed. 10913 * 10914 * Returns: 10915 * DELETE_FAILURE on failure 10916 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 10917 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 10918 */ 10919 static int 10920 lscf_service_delete(scf_service_t *svc, int force) 10921 { 10922 int r; 10923 scf_instance_t *inst; 10924 scf_propertygroup_t *pg; 10925 scf_iter_t *iter; 10926 int ret; 10927 int external = 0; 10928 10929 if ((inst = scf_instance_create(g_hndl)) == NULL || 10930 (pg = scf_pg_create(g_hndl)) == NULL || 10931 (iter = scf_iter_create(g_hndl)) == NULL) 10932 scfdie(); 10933 10934 if (scf_iter_service_instances(iter, svc) != 0) 10935 scfdie(); 10936 10937 for (r = scf_iter_next_instance(iter, inst); 10938 r == 1; 10939 r = scf_iter_next_instance(iter, inst)) { 10940 10941 ret = lscf_instance_delete(inst, force); 10942 if (ret == DELETE_FAILURE) { 10943 scf_iter_destroy(iter); 10944 scf_pg_destroy(pg); 10945 scf_instance_destroy(inst); 10946 return (DELETE_FAILURE); 10947 } 10948 10949 /* 10950 * Record the fact that there is some external dependencies 10951 * at the instance level. 10952 */ 10953 if (ret == DELETE_SUCCESS_EXTDEPS) 10954 external |= 1; 10955 } 10956 10957 if (r != 0) 10958 scfdie(); 10959 10960 /* Delete dependency property groups in dependent services. */ 10961 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 10962 (void) delete_dependents(pg); 10963 else if (scf_error() != SCF_ERROR_NOT_FOUND) 10964 scfdie(); 10965 10966 scf_iter_destroy(iter); 10967 scf_pg_destroy(pg); 10968 scf_instance_destroy(inst); 10969 10970 /* 10971 * If the service has some external dependencies then we don't 10972 * want to remove them in case the service is re-imported. 10973 */ 10974 if ((pg = scf_pg_create(g_hndl)) == NULL || 10975 (iter = scf_iter_create(g_hndl)) == NULL) 10976 scfdie(); 10977 10978 if (scf_iter_service_pgs(iter, svc) < 0) 10979 scfdie(); 10980 10981 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 10982 if (pg_is_external_dependency(pg)) { 10983 external |= 2; 10984 continue; 10985 } 10986 10987 if (scf_pg_delete(pg) != 0) { 10988 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10989 scfdie(); 10990 else { 10991 semerr(emsg_permission_denied); 10992 10993 (void) scf_iter_destroy(iter); 10994 (void) scf_pg_destroy(pg); 10995 return (DELETE_FAILURE); 10996 } 10997 } 10998 } 10999 11000 if (r == -1) 11001 scfdie(); 11002 11003 (void) scf_iter_destroy(iter); 11004 (void) scf_pg_destroy(pg); 11005 11006 if (external != 0) 11007 return (DELETE_SUCCESS_EXTDEPS); 11008 11009 if (scf_service_delete(svc) == 0) 11010 return (DELETE_SUCCESS_NOEXTDEPS); 11011 11012 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 11013 scfdie(); 11014 11015 semerr(emsg_permission_denied); 11016 return (DELETE_FAILURE); 11017 } 11018 11019 static int 11020 delete_callback(void *data, scf_walkinfo_t *wip) 11021 { 11022 int force = (int)data; 11023 11024 if (wip->inst != NULL) 11025 (void) lscf_instance_delete(wip->inst, force); 11026 else 11027 (void) lscf_service_delete(wip->svc, force); 11028 11029 return (0); 11030 } 11031 11032 void 11033 lscf_delete(const char *fmri, int force) 11034 { 11035 scf_service_t *svc; 11036 scf_instance_t *inst; 11037 int ret; 11038 11039 lscf_prep_hndl(); 11040 11041 if (cur_snap != NULL) { 11042 if (!snaplevel_is_instance(cur_level)) { 11043 char *buf; 11044 11045 buf = safe_malloc(max_scf_name_len + 1); 11046 if (scf_instance_get_name(cur_inst, buf, 11047 max_scf_name_len + 1) >= 0) { 11048 if (strcmp(buf, fmri) == 0) { 11049 semerr(emsg_cant_modify_snapshots); 11050 free(buf); 11051 return; 11052 } 11053 } else if (scf_error() != SCF_ERROR_DELETED) { 11054 scfdie(); 11055 } 11056 free(buf); 11057 } 11058 } else if (cur_inst != NULL) { 11059 /* EMPTY */; 11060 } else if (cur_svc != NULL) { 11061 inst = scf_instance_create(g_hndl); 11062 if (inst == NULL) 11063 scfdie(); 11064 11065 if (scf_service_get_instance(cur_svc, fmri, inst) == 11066 SCF_SUCCESS) { 11067 (void) lscf_instance_delete(inst, force); 11068 scf_instance_destroy(inst); 11069 return; 11070 } 11071 11072 if (scf_error() != SCF_ERROR_NOT_FOUND && 11073 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 11074 scfdie(); 11075 11076 scf_instance_destroy(inst); 11077 } else { 11078 assert(cur_scope != NULL); 11079 11080 svc = scf_service_create(g_hndl); 11081 if (svc == NULL) 11082 scfdie(); 11083 11084 if (scf_scope_get_service(cur_scope, fmri, svc) == 11085 SCF_SUCCESS) { 11086 (void) lscf_service_delete(svc, force); 11087 scf_service_destroy(svc); 11088 return; 11089 } 11090 11091 if (scf_error() != SCF_ERROR_NOT_FOUND && 11092 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 11093 scfdie(); 11094 11095 scf_service_destroy(svc); 11096 } 11097 11098 /* 11099 * Match FMRI to entity. 11100 */ 11101 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 11102 delete_callback, (void *)force, NULL, semerr)) != 0) { 11103 semerr(gettext("Failed to walk instances: %s\n"), 11104 scf_strerror(ret)); 11105 } 11106 } 11107 11108 11109 11110 /* 11111 * :properties commands. These all end with "pg" or "prop" and generally 11112 * operate on the currently selected entity. 11113 */ 11114 11115 /* 11116 * Property listing. List the property groups, properties, their types and 11117 * their values for the currently selected entity. 11118 */ 11119 static void 11120 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 11121 { 11122 char *buf; 11123 uint32_t flags; 11124 11125 buf = safe_malloc(max_scf_pg_type_len + 1); 11126 11127 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 11128 scfdie(); 11129 11130 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 11131 scfdie(); 11132 11133 safe_printf("%-*s %s", namewidth, name, buf); 11134 11135 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11136 safe_printf("\tNONPERSISTENT"); 11137 11138 safe_printf("\n"); 11139 11140 free(buf); 11141 } 11142 11143 static boolean_t 11144 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 11145 { 11146 if (scf_property_get_value(prop, val) == 0) { 11147 return (B_FALSE); 11148 } else { 11149 switch (scf_error()) { 11150 case SCF_ERROR_NOT_FOUND: 11151 return (B_FALSE); 11152 case SCF_ERROR_PERMISSION_DENIED: 11153 case SCF_ERROR_CONSTRAINT_VIOLATED: 11154 return (B_TRUE); 11155 default: 11156 scfdie(); 11157 /*NOTREACHED*/ 11158 } 11159 } 11160 } 11161 11162 static void 11163 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 11164 { 11165 scf_iter_t *iter; 11166 scf_value_t *val; 11167 const char *type; 11168 int multiple_strings = 0; 11169 int ret; 11170 11171 if ((iter = scf_iter_create(g_hndl)) == NULL || 11172 (val = scf_value_create(g_hndl)) == NULL) 11173 scfdie(); 11174 11175 type = prop_to_typestr(prop); 11176 assert(type != NULL); 11177 11178 safe_printf("%-*s %-7s ", len, name, type); 11179 11180 if (prop_has_multiple_values(prop, val) && 11181 (scf_value_type(val) == SCF_TYPE_ASTRING || 11182 scf_value_type(val) == SCF_TYPE_USTRING)) 11183 multiple_strings = 1; 11184 11185 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11186 scfdie(); 11187 11188 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11189 char *buf; 11190 ssize_t vlen, szret; 11191 11192 vlen = scf_value_get_as_string(val, NULL, 0); 11193 if (vlen < 0) 11194 scfdie(); 11195 11196 buf = safe_malloc(vlen + 1); 11197 11198 szret = scf_value_get_as_string(val, buf, vlen + 1); 11199 if (szret < 0) 11200 scfdie(); 11201 assert(szret <= vlen); 11202 11203 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11204 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 11205 safe_printf(" \""); 11206 (void) quote_and_print(buf, stdout, 0); 11207 (void) putchar('"'); 11208 if (ferror(stdout)) { 11209 (void) putchar('\n'); 11210 uu_die(gettext("Error writing to stdout.\n")); 11211 } 11212 } else { 11213 safe_printf(" %s", buf); 11214 } 11215 11216 free(buf); 11217 } 11218 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11219 scfdie(); 11220 11221 if (putchar('\n') != '\n') 11222 uu_die(gettext("Could not output newline")); 11223 } 11224 11225 /* 11226 * Outputs template property group info for the describe subcommand. 11227 * If 'templates' == 2, verbose output is printed in the format expected 11228 * for describe -v, which includes all templates fields. If pg is 11229 * not NULL, we're describing the template data, not an existing property 11230 * group, and formatting should be appropriate for describe -t. 11231 */ 11232 static void 11233 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 11234 { 11235 char *buf; 11236 uint8_t required; 11237 scf_property_t *stability_prop; 11238 scf_value_t *stability_val; 11239 11240 if (templates == 0) 11241 return; 11242 11243 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 11244 (stability_val = scf_value_create(g_hndl)) == NULL) 11245 scfdie(); 11246 11247 if (templates == 2 && pg != NULL) { 11248 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 11249 stability_prop) == 0) { 11250 if (prop_check_type(stability_prop, 11251 SCF_TYPE_ASTRING) == 0 && 11252 prop_get_val(stability_prop, stability_val) == 0) { 11253 char *stability; 11254 11255 stability = safe_malloc(max_scf_value_len + 1); 11256 11257 if (scf_value_get_astring(stability_val, 11258 stability, max_scf_value_len + 1) == -1 && 11259 scf_error() != SCF_ERROR_NOT_FOUND) 11260 scfdie(); 11261 11262 safe_printf("%s%s: %s\n", TMPL_INDENT, 11263 gettext("stability"), stability); 11264 11265 free(stability); 11266 } 11267 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 11268 scfdie(); 11269 } 11270 11271 scf_property_destroy(stability_prop); 11272 scf_value_destroy(stability_val); 11273 11274 if (pgt == NULL) 11275 return; 11276 11277 if (pg == NULL || templates == 2) { 11278 /* print type info only if scf_tmpl_pg_name succeeds */ 11279 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 11280 if (pg != NULL) 11281 safe_printf("%s", TMPL_INDENT); 11282 safe_printf("%s: ", gettext("name")); 11283 safe_printf("%s\n", buf); 11284 free(buf); 11285 } 11286 11287 /* print type info only if scf_tmpl_pg_type succeeds */ 11288 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 11289 if (pg != NULL) 11290 safe_printf("%s", TMPL_INDENT); 11291 safe_printf("%s: ", gettext("type")); 11292 safe_printf("%s\n", buf); 11293 free(buf); 11294 } 11295 } 11296 11297 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 11298 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11299 required ? "true" : "false"); 11300 11301 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 11302 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 11303 buf); 11304 free(buf); 11305 } 11306 11307 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 11308 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11309 buf); 11310 free(buf); 11311 } 11312 11313 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 11314 if (templates == 2) 11315 safe_printf("%s%s: %s\n", TMPL_INDENT, 11316 gettext("description"), buf); 11317 else 11318 safe_printf("%s%s\n", TMPL_INDENT, buf); 11319 free(buf); 11320 } 11321 11322 } 11323 11324 /* 11325 * With as_value set to true, indent as appropriate for the value level. 11326 * If false, indent to appropriate level for inclusion in constraint 11327 * or choice printout. 11328 */ 11329 static void 11330 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 11331 int as_value) 11332 { 11333 char *buf; 11334 11335 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 11336 if (as_value == 0) 11337 safe_printf("%s", TMPL_CHOICE_INDENT); 11338 else 11339 safe_printf("%s", TMPL_INDENT); 11340 safe_printf("%s: %s\n", gettext("value common name"), buf); 11341 free(buf); 11342 } 11343 11344 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 11345 if (as_value == 0) 11346 safe_printf("%s", TMPL_CHOICE_INDENT); 11347 else 11348 safe_printf("%s", TMPL_INDENT); 11349 safe_printf("%s: %s\n", gettext("value description"), buf); 11350 free(buf); 11351 } 11352 } 11353 11354 static void 11355 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 11356 { 11357 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 11358 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11359 safe_printf("%s\n", val_buf); 11360 11361 print_template_value_details(prt, val_buf, 1); 11362 } 11363 11364 static void 11365 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 11366 { 11367 int i, printed = 0; 11368 scf_values_t values; 11369 scf_count_ranges_t c_ranges; 11370 scf_int_ranges_t i_ranges; 11371 11372 printed = 0; 11373 i = 0; 11374 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 11375 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11376 gettext("value constraints")); 11377 printed++; 11378 for (i = 0; i < values.value_count; ++i) { 11379 safe_printf("%s%s: %s\n", TMPL_INDENT, 11380 gettext("value name"), values.values_as_strings[i]); 11381 if (verbose == 1) 11382 print_template_value_details(prt, 11383 values.values_as_strings[i], 0); 11384 } 11385 11386 scf_values_destroy(&values); 11387 } 11388 11389 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 11390 if (printed++ == 0) 11391 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11392 gettext("value constraints")); 11393 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11394 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11395 gettext("range"), c_ranges.scr_min[i], 11396 c_ranges.scr_max[i]); 11397 } 11398 scf_count_ranges_destroy(&c_ranges); 11399 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11400 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 11401 if (printed++ == 0) 11402 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11403 gettext("value constraints")); 11404 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11405 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11406 gettext("range"), i_ranges.sir_min[i], 11407 i_ranges.sir_max[i]); 11408 } 11409 scf_int_ranges_destroy(&i_ranges); 11410 } 11411 } 11412 11413 static void 11414 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 11415 { 11416 int i = 0, printed = 0; 11417 scf_values_t values; 11418 scf_count_ranges_t c_ranges; 11419 scf_int_ranges_t i_ranges; 11420 11421 printed = 0; 11422 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 11423 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11424 gettext("value constraints")); 11425 printed++; 11426 for (i = 0; i < values.value_count; i++) { 11427 safe_printf("%s%s: %s\n", TMPL_INDENT, 11428 gettext("value name"), values.values_as_strings[i]); 11429 if (verbose == 1) 11430 print_template_value_details(prt, 11431 values.values_as_strings[i], 0); 11432 } 11433 11434 scf_values_destroy(&values); 11435 } 11436 11437 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 11438 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11439 if (printed++ == 0) 11440 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11441 gettext("value choices")); 11442 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11443 gettext("range"), c_ranges.scr_min[i], 11444 c_ranges.scr_max[i]); 11445 } 11446 scf_count_ranges_destroy(&c_ranges); 11447 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11448 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 11449 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11450 if (printed++ == 0) 11451 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11452 gettext("value choices")); 11453 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11454 gettext("range"), i_ranges.sir_min[i], 11455 i_ranges.sir_max[i]); 11456 } 11457 scf_int_ranges_destroy(&i_ranges); 11458 } 11459 } 11460 11461 static void 11462 list_values_by_template(scf_prop_tmpl_t *prt) 11463 { 11464 print_template_constraints(prt, 1); 11465 print_template_choices(prt, 1); 11466 } 11467 11468 static void 11469 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 11470 { 11471 char *val_buf; 11472 scf_iter_t *iter; 11473 scf_value_t *val; 11474 int ret; 11475 11476 if ((iter = scf_iter_create(g_hndl)) == NULL || 11477 (val = scf_value_create(g_hndl)) == NULL) 11478 scfdie(); 11479 11480 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11481 scfdie(); 11482 11483 val_buf = safe_malloc(max_scf_value_len + 1); 11484 11485 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11486 if (scf_value_get_as_string(val, val_buf, 11487 max_scf_value_len + 1) < 0) 11488 scfdie(); 11489 11490 print_template_value(prt, val_buf); 11491 } 11492 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11493 scfdie(); 11494 free(val_buf); 11495 11496 print_template_constraints(prt, 0); 11497 print_template_choices(prt, 0); 11498 11499 } 11500 11501 /* 11502 * Outputs property info for the describe subcommand 11503 * Verbose output if templates == 2, -v option of svccfg describe 11504 * Displays template data if prop is not NULL, -t option of svccfg describe 11505 */ 11506 static void 11507 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 11508 { 11509 char *buf; 11510 uint8_t u_buf; 11511 int i; 11512 uint64_t min, max; 11513 scf_values_t values; 11514 11515 if (prt == NULL || templates == 0) 11516 return; 11517 11518 if (prop == NULL) { 11519 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 11520 if (scf_tmpl_prop_name(prt, &buf) > 0) { 11521 safe_printf("%s\n", buf); 11522 free(buf); 11523 } else 11524 safe_printf("(%s)\n", gettext("any")); 11525 } 11526 11527 if (prop == NULL || templates == 2) { 11528 if (prop != NULL) 11529 safe_printf("%s", TMPL_INDENT); 11530 else 11531 safe_printf("%s", TMPL_VALUE_INDENT); 11532 safe_printf("%s: ", gettext("type")); 11533 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 11534 safe_printf("%s\n", buf); 11535 free(buf); 11536 } else 11537 safe_printf("(%s)\n", gettext("any")); 11538 } 11539 11540 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 11541 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11542 u_buf ? "true" : "false"); 11543 11544 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 11545 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11546 buf); 11547 free(buf); 11548 } 11549 11550 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 11551 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 11552 buf); 11553 free(buf); 11554 } 11555 11556 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 11557 safe_printf("%s%s\n", TMPL_INDENT, buf); 11558 free(buf); 11559 } 11560 11561 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 11562 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 11563 scf_tmpl_visibility_to_string(u_buf)); 11564 11565 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 11566 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11567 gettext("minimum number of values"), min); 11568 if (max == ULLONG_MAX) { 11569 safe_printf("%s%s: %s\n", TMPL_INDENT, 11570 gettext("maximum number of values"), 11571 gettext("unlimited")); 11572 } else { 11573 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11574 gettext("maximum number of values"), max); 11575 } 11576 } 11577 11578 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 11579 for (i = 0; i < values.value_count; i++) { 11580 if (i == 0) { 11581 safe_printf("%s%s:", TMPL_INDENT, 11582 gettext("internal separators")); 11583 } 11584 safe_printf(" \"%s\"", values.values_as_strings[i]); 11585 } 11586 safe_printf("\n"); 11587 } 11588 11589 if (templates != 2) 11590 return; 11591 11592 if (prop != NULL) 11593 list_values_tmpl(prt, prop); 11594 else 11595 list_values_by_template(prt); 11596 } 11597 11598 static char * 11599 read_astring(scf_propertygroup_t *pg, const char *prop_name) 11600 { 11601 char *rv; 11602 11603 rv = _scf_read_single_astring_from_pg(pg, prop_name); 11604 if (rv == NULL) { 11605 switch (scf_error()) { 11606 case SCF_ERROR_NOT_FOUND: 11607 break; 11608 default: 11609 scfdie(); 11610 } 11611 } 11612 return (rv); 11613 } 11614 11615 static void 11616 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 11617 { 11618 size_t doc_len; 11619 size_t man_len; 11620 char *pg_name; 11621 char *text = NULL; 11622 int rv; 11623 11624 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 11625 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 11626 pg_name = safe_malloc(max_scf_name_len + 1); 11627 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 11628 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 11629 scfdie(); 11630 } 11631 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 11632 /* Display doc_link and and uri */ 11633 safe_printf("%s%s:\n", TMPL_INDENT, 11634 gettext("doc_link")); 11635 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 11636 if (text != NULL) { 11637 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11638 TMPL_INDENT, gettext("name"), text); 11639 uu_free(text); 11640 } 11641 text = read_astring(pg, SCF_PROPERTY_TM_URI); 11642 if (text != NULL) { 11643 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 11644 gettext("uri"), text); 11645 uu_free(text); 11646 } 11647 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 11648 man_len) == 0) { 11649 /* Display manpage title, section and path */ 11650 safe_printf("%s%s:\n", TMPL_INDENT, 11651 gettext("manpage")); 11652 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 11653 if (text != NULL) { 11654 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11655 TMPL_INDENT, gettext("title"), text); 11656 uu_free(text); 11657 } 11658 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 11659 if (text != NULL) { 11660 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11661 TMPL_INDENT, gettext("section"), text); 11662 uu_free(text); 11663 } 11664 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 11665 if (text != NULL) { 11666 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11667 TMPL_INDENT, gettext("manpath"), text); 11668 uu_free(text); 11669 } 11670 } 11671 } 11672 if (rv == -1) 11673 scfdie(); 11674 11675 done: 11676 free(pg_name); 11677 } 11678 11679 static void 11680 list_entity_tmpl(int templates) 11681 { 11682 char *common_name = NULL; 11683 char *description = NULL; 11684 char *locale = NULL; 11685 scf_iter_t *iter; 11686 scf_propertygroup_t *pg; 11687 scf_property_t *prop; 11688 int r; 11689 scf_value_t *val; 11690 11691 if ((pg = scf_pg_create(g_hndl)) == NULL || 11692 (prop = scf_property_create(g_hndl)) == NULL || 11693 (val = scf_value_create(g_hndl)) == NULL || 11694 (iter = scf_iter_create(g_hndl)) == NULL) 11695 scfdie(); 11696 11697 locale = setlocale(LC_MESSAGES, NULL); 11698 11699 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 11700 common_name = safe_malloc(max_scf_value_len + 1); 11701 11702 /* Try both the current locale and the "C" locale. */ 11703 if (scf_pg_get_property(pg, locale, prop) == 0 || 11704 (scf_error() == SCF_ERROR_NOT_FOUND && 11705 scf_pg_get_property(pg, "C", prop) == 0)) { 11706 if (prop_get_val(prop, val) == 0 && 11707 scf_value_get_ustring(val, common_name, 11708 max_scf_value_len + 1) != -1) { 11709 safe_printf("%s%s: %s\n", TMPL_INDENT, 11710 gettext("common name"), common_name); 11711 } 11712 } 11713 } 11714 11715 /* 11716 * Do description, manpages, and doc links if templates == 2. 11717 */ 11718 if (templates == 2) { 11719 /* Get the description. */ 11720 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 11721 description = safe_malloc(max_scf_value_len + 1); 11722 11723 /* Try both the current locale and the "C" locale. */ 11724 if (scf_pg_get_property(pg, locale, prop) == 0 || 11725 (scf_error() == SCF_ERROR_NOT_FOUND && 11726 scf_pg_get_property(pg, "C", prop) == 0)) { 11727 if (prop_get_val(prop, val) == 0 && 11728 scf_value_get_ustring(val, description, 11729 max_scf_value_len + 1) != -1) { 11730 safe_printf("%s%s: %s\n", TMPL_INDENT, 11731 gettext("description"), 11732 description); 11733 } 11734 } 11735 } 11736 11737 /* Process doc_link & manpage elements. */ 11738 if (cur_level != NULL) { 11739 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 11740 SCF_GROUP_TEMPLATE); 11741 } else if (cur_inst != NULL) { 11742 r = scf_iter_instance_pgs_typed(iter, cur_inst, 11743 SCF_GROUP_TEMPLATE); 11744 } else { 11745 r = scf_iter_service_pgs_typed(iter, cur_svc, 11746 SCF_GROUP_TEMPLATE); 11747 } 11748 if (r == 0) { 11749 display_documentation(iter, pg); 11750 } 11751 } 11752 11753 free(common_name); 11754 free(description); 11755 scf_pg_destroy(pg); 11756 scf_property_destroy(prop); 11757 scf_value_destroy(val); 11758 scf_iter_destroy(iter); 11759 } 11760 11761 static void 11762 listtmpl(const char *pattern, int templates) 11763 { 11764 scf_pg_tmpl_t *pgt; 11765 scf_prop_tmpl_t *prt; 11766 char *snapbuf = NULL; 11767 char *fmribuf; 11768 char *pg_name = NULL, *prop_name = NULL; 11769 ssize_t prop_name_size; 11770 char *qual_prop_name; 11771 char *search_name; 11772 int listed = 0; 11773 11774 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 11775 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 11776 scfdie(); 11777 11778 fmribuf = safe_malloc(max_scf_name_len + 1); 11779 qual_prop_name = safe_malloc(max_scf_name_len + 1); 11780 11781 if (cur_snap != NULL) { 11782 snapbuf = safe_malloc(max_scf_name_len + 1); 11783 if (scf_snapshot_get_name(cur_snap, snapbuf, 11784 max_scf_name_len + 1) < 0) 11785 scfdie(); 11786 } 11787 11788 if (cur_inst != NULL) { 11789 if (scf_instance_to_fmri(cur_inst, fmribuf, 11790 max_scf_name_len + 1) < 0) 11791 scfdie(); 11792 } else if (cur_svc != NULL) { 11793 if (scf_service_to_fmri(cur_svc, fmribuf, 11794 max_scf_name_len + 1) < 0) 11795 scfdie(); 11796 } else 11797 abort(); 11798 11799 /* If pattern is specified, we want to list only those items. */ 11800 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) { 11801 listed = 0; 11802 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 11803 fnmatch(pattern, pg_name, 0) == 0)) { 11804 list_pg_tmpl(pgt, NULL, templates); 11805 listed++; 11806 } 11807 11808 scf_tmpl_prop_reset(prt); 11809 11810 while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) { 11811 search_name = NULL; 11812 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 11813 if ((prop_name_size > 0) && (pg_name != NULL)) { 11814 if (snprintf(qual_prop_name, 11815 max_scf_name_len + 1, "%s/%s", 11816 pg_name, prop_name) >= 11817 max_scf_name_len + 1) { 11818 prop_name_size = -1; 11819 } else { 11820 search_name = qual_prop_name; 11821 } 11822 } 11823 if (listed > 0 || pattern == NULL || 11824 (prop_name_size > 0 && 11825 fnmatch(pattern, search_name, 11826 FNM_PATHNAME) == 0)) 11827 list_prop_tmpl(prt, NULL, templates); 11828 if (prop_name != NULL) { 11829 free(prop_name); 11830 prop_name = NULL; 11831 } 11832 } 11833 if (pg_name != NULL) { 11834 free(pg_name); 11835 pg_name = NULL; 11836 } 11837 } 11838 11839 scf_tmpl_prop_destroy(prt); 11840 scf_tmpl_pg_destroy(pgt); 11841 free(snapbuf); 11842 free(fmribuf); 11843 free(qual_prop_name); 11844 } 11845 11846 static void 11847 listprop(const char *pattern, int only_pgs, int templates) 11848 { 11849 scf_propertygroup_t *pg; 11850 scf_property_t *prop; 11851 scf_iter_t *iter, *piter; 11852 char *pgnbuf, *prnbuf, *ppnbuf; 11853 scf_pg_tmpl_t *pgt, *pgtp; 11854 scf_prop_tmpl_t *prt; 11855 11856 void **objects; 11857 char **names; 11858 void **tmpls; 11859 int allocd, i; 11860 11861 int ret; 11862 ssize_t pgnlen, prnlen, szret; 11863 size_t max_len = 0; 11864 11865 if (cur_svc == NULL && cur_inst == NULL) { 11866 semerr(emsg_entity_not_selected); 11867 return; 11868 } 11869 11870 if ((pg = scf_pg_create(g_hndl)) == NULL || 11871 (prop = scf_property_create(g_hndl)) == NULL || 11872 (iter = scf_iter_create(g_hndl)) == NULL || 11873 (piter = scf_iter_create(g_hndl)) == NULL || 11874 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 11875 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 11876 scfdie(); 11877 11878 prnbuf = safe_malloc(max_scf_name_len + 1); 11879 11880 if (cur_level != NULL) 11881 ret = scf_iter_snaplevel_pgs(iter, cur_level); 11882 else if (cur_inst != NULL) 11883 ret = scf_iter_instance_pgs(iter, cur_inst); 11884 else 11885 ret = scf_iter_service_pgs(iter, cur_svc); 11886 if (ret != 0) { 11887 return; 11888 } 11889 11890 /* 11891 * We want to only list items which match pattern, and we want the 11892 * second column to line up, so during the first pass we'll save 11893 * matching items, their names, and their templates in objects, 11894 * names, and tmpls, computing the maximum name length as we go, 11895 * and then we'll print them out. 11896 * 11897 * Note: We always keep an extra slot available so the array can be 11898 * NULL-terminated. 11899 */ 11900 i = 0; 11901 allocd = 1; 11902 objects = safe_malloc(sizeof (*objects)); 11903 names = safe_malloc(sizeof (*names)); 11904 tmpls = safe_malloc(sizeof (*tmpls)); 11905 11906 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 11907 int new_pg = 0; 11908 int print_props = 0; 11909 pgtp = NULL; 11910 11911 pgnlen = scf_pg_get_name(pg, NULL, 0); 11912 if (pgnlen < 0) 11913 scfdie(); 11914 11915 pgnbuf = safe_malloc(pgnlen + 1); 11916 11917 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 11918 if (szret < 0) 11919 scfdie(); 11920 assert(szret <= pgnlen); 11921 11922 if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) { 11923 if (scf_error() != SCF_ERROR_NOT_FOUND) 11924 scfdie(); 11925 pgtp = NULL; 11926 } else { 11927 pgtp = pgt; 11928 } 11929 11930 if (pattern == NULL || 11931 fnmatch(pattern, pgnbuf, 0) == 0) { 11932 if (i+1 >= allocd) { 11933 allocd *= 2; 11934 objects = realloc(objects, 11935 sizeof (*objects) * allocd); 11936 names = 11937 realloc(names, sizeof (*names) * allocd); 11938 tmpls = realloc(tmpls, 11939 sizeof (*tmpls) * allocd); 11940 if (objects == NULL || names == NULL || 11941 tmpls == NULL) 11942 uu_die(gettext("Out of memory")); 11943 } 11944 objects[i] = pg; 11945 names[i] = pgnbuf; 11946 11947 if (pgtp == NULL) 11948 tmpls[i] = NULL; 11949 else 11950 tmpls[i] = pgt; 11951 11952 ++i; 11953 11954 if (pgnlen > max_len) 11955 max_len = pgnlen; 11956 11957 new_pg = 1; 11958 print_props = 1; 11959 } 11960 11961 if (only_pgs) { 11962 if (new_pg) { 11963 pg = scf_pg_create(g_hndl); 11964 if (pg == NULL) 11965 scfdie(); 11966 pgt = scf_tmpl_pg_create(g_hndl); 11967 if (pgt == NULL) 11968 scfdie(); 11969 } else 11970 free(pgnbuf); 11971 11972 continue; 11973 } 11974 11975 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 11976 scfdie(); 11977 11978 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 11979 prnlen = scf_property_get_name(prop, prnbuf, 11980 max_scf_name_len + 1); 11981 if (prnlen < 0) 11982 scfdie(); 11983 11984 /* Will prepend the property group name and a slash. */ 11985 prnlen += pgnlen + 1; 11986 11987 ppnbuf = safe_malloc(prnlen + 1); 11988 11989 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 11990 prnbuf) < 0) 11991 uu_die("snprintf"); 11992 11993 if (pattern == NULL || print_props == 1 || 11994 fnmatch(pattern, ppnbuf, 0) == 0) { 11995 if (i+1 >= allocd) { 11996 allocd *= 2; 11997 objects = realloc(objects, 11998 sizeof (*objects) * allocd); 11999 names = realloc(names, 12000 sizeof (*names) * allocd); 12001 tmpls = realloc(tmpls, 12002 sizeof (*tmpls) * allocd); 12003 if (objects == NULL || names == NULL || 12004 tmpls == NULL) 12005 uu_die(gettext( 12006 "Out of memory")); 12007 } 12008 12009 objects[i] = prop; 12010 names[i] = ppnbuf; 12011 12012 if (pgtp != NULL) { 12013 if (scf_tmpl_get_by_prop(pgt, prnbuf, 12014 prt, NULL) < 0) { 12015 if (scf_error() != 12016 SCF_ERROR_NOT_FOUND) 12017 scfdie(); 12018 tmpls[i] = NULL; 12019 } else { 12020 tmpls[i] = prt; 12021 } 12022 } else { 12023 tmpls[i] = NULL; 12024 } 12025 12026 ++i; 12027 12028 if (prnlen > max_len) 12029 max_len = prnlen; 12030 12031 prop = scf_property_create(g_hndl); 12032 prt = scf_tmpl_prop_create(g_hndl); 12033 } else { 12034 free(ppnbuf); 12035 } 12036 } 12037 12038 if (new_pg) { 12039 pg = scf_pg_create(g_hndl); 12040 if (pg == NULL) 12041 scfdie(); 12042 pgt = scf_tmpl_pg_create(g_hndl); 12043 if (pgt == NULL) 12044 scfdie(); 12045 } else 12046 free(pgnbuf); 12047 } 12048 if (ret != 0) 12049 scfdie(); 12050 12051 objects[i] = NULL; 12052 12053 scf_pg_destroy(pg); 12054 scf_tmpl_pg_destroy(pgt); 12055 scf_property_destroy(prop); 12056 scf_tmpl_prop_destroy(prt); 12057 12058 for (i = 0; objects[i] != NULL; ++i) { 12059 if (strchr(names[i], '/') == NULL) { 12060 /* property group */ 12061 pg = (scf_propertygroup_t *)objects[i]; 12062 pgt = (scf_pg_tmpl_t *)tmpls[i]; 12063 list_pg_info(pg, names[i], max_len); 12064 list_pg_tmpl(pgt, pg, templates); 12065 free(names[i]); 12066 scf_pg_destroy(pg); 12067 if (pgt != NULL) 12068 scf_tmpl_pg_destroy(pgt); 12069 } else { 12070 /* property */ 12071 prop = (scf_property_t *)objects[i]; 12072 prt = (scf_prop_tmpl_t *)tmpls[i]; 12073 list_prop_info(prop, names[i], max_len); 12074 list_prop_tmpl(prt, prop, templates); 12075 free(names[i]); 12076 scf_property_destroy(prop); 12077 if (prt != NULL) 12078 scf_tmpl_prop_destroy(prt); 12079 } 12080 } 12081 12082 free(names); 12083 free(objects); 12084 free(tmpls); 12085 } 12086 12087 void 12088 lscf_listpg(const char *pattern) 12089 { 12090 lscf_prep_hndl(); 12091 12092 listprop(pattern, 1, 0); 12093 } 12094 12095 /* 12096 * Property group and property creation, setting, and deletion. setprop (and 12097 * its alias, addprop) can either create a property group of a given type, or 12098 * it can create or set a property to a given type and list of values. 12099 */ 12100 void 12101 lscf_addpg(const char *name, const char *type, const char *flags) 12102 { 12103 scf_propertygroup_t *pg; 12104 int ret; 12105 uint32_t flgs = 0; 12106 const char *cp; 12107 12108 12109 lscf_prep_hndl(); 12110 12111 if (cur_snap != NULL) { 12112 semerr(emsg_cant_modify_snapshots); 12113 return; 12114 } 12115 12116 if (cur_inst == NULL && cur_svc == NULL) { 12117 semerr(emsg_entity_not_selected); 12118 return; 12119 } 12120 12121 if (flags != NULL) { 12122 for (cp = flags; *cp != '\0'; ++cp) { 12123 switch (*cp) { 12124 case 'P': 12125 flgs |= SCF_PG_FLAG_NONPERSISTENT; 12126 break; 12127 12128 case 'p': 12129 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 12130 break; 12131 12132 default: 12133 semerr(gettext("Invalid property group flag " 12134 "%c."), *cp); 12135 return; 12136 } 12137 } 12138 } 12139 12140 pg = scf_pg_create(g_hndl); 12141 if (pg == NULL) 12142 scfdie(); 12143 12144 if (cur_inst != NULL) 12145 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 12146 else 12147 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 12148 12149 if (ret != SCF_SUCCESS) { 12150 switch (scf_error()) { 12151 case SCF_ERROR_INVALID_ARGUMENT: 12152 semerr(gettext("Name, type, or flags are invalid.\n")); 12153 break; 12154 12155 case SCF_ERROR_EXISTS: 12156 semerr(gettext("Property group already exists.\n")); 12157 break; 12158 12159 case SCF_ERROR_PERMISSION_DENIED: 12160 semerr(emsg_permission_denied); 12161 break; 12162 12163 case SCF_ERROR_BACKEND_ACCESS: 12164 semerr(gettext("Backend refused access.\n")); 12165 break; 12166 12167 default: 12168 scfdie(); 12169 } 12170 } 12171 12172 scf_pg_destroy(pg); 12173 12174 private_refresh(); 12175 } 12176 12177 void 12178 lscf_delpg(char *name) 12179 { 12180 lscf_prep_hndl(); 12181 12182 if (cur_snap != NULL) { 12183 semerr(emsg_cant_modify_snapshots); 12184 return; 12185 } 12186 12187 if (cur_inst == NULL && cur_svc == NULL) { 12188 semerr(emsg_entity_not_selected); 12189 return; 12190 } 12191 12192 if (strchr(name, '/') != NULL) { 12193 semerr(emsg_invalid_pg_name, name); 12194 return; 12195 } 12196 12197 lscf_delprop(name); 12198 } 12199 12200 /* 12201 * scf_delhash() is used to remove the property group related to the 12202 * hash entry for a specific manifest in the repository. pgname will be 12203 * constructed from the location of the manifest file. If deathrow isn't 0, 12204 * manifest file doesn't need to exist (manifest string will be used as 12205 * an absolute path). 12206 */ 12207 void 12208 lscf_delhash(char *manifest, int deathrow) 12209 { 12210 char *pgname; 12211 12212 if (cur_snap != NULL || 12213 cur_inst != NULL || cur_svc != NULL) { 12214 warn(gettext("error, an entity is selected\n")); 12215 return; 12216 } 12217 12218 /* select smf/manifest */ 12219 lscf_select("smf/manifest"); 12220 /* 12221 * Translate the manifest file name to property name. In the deathrow 12222 * case, the manifest file does not need to exist. 12223 */ 12224 pgname = mhash_filename_to_propname(manifest, 12225 deathrow ? B_TRUE : B_FALSE); 12226 if (pgname == NULL) { 12227 warn(gettext("cannot resolve pathname for %s\n"), manifest); 12228 return; 12229 } 12230 /* delete the hash property name */ 12231 lscf_delpg(pgname); 12232 } 12233 12234 void 12235 lscf_listprop(const char *pattern) 12236 { 12237 lscf_prep_hndl(); 12238 12239 listprop(pattern, 0, 0); 12240 } 12241 12242 int 12243 lscf_setprop(const char *pgname, const char *type, const char *value, 12244 const uu_list_t *values) 12245 { 12246 scf_type_t ty, current_ty; 12247 scf_service_t *svc; 12248 scf_propertygroup_t *pg, *parent_pg; 12249 scf_property_t *prop, *parent_prop; 12250 scf_pg_tmpl_t *pgt; 12251 scf_prop_tmpl_t *prt; 12252 int ret, result = 0; 12253 scf_transaction_t *tx; 12254 scf_transaction_entry_t *e; 12255 scf_value_t *v; 12256 uu_list_walk_t *walk; 12257 string_list_t *sp; 12258 char *propname; 12259 int req_quotes = 0; 12260 12261 lscf_prep_hndl(); 12262 12263 if ((e = scf_entry_create(g_hndl)) == NULL || 12264 (svc = scf_service_create(g_hndl)) == NULL || 12265 (parent_pg = scf_pg_create(g_hndl)) == NULL || 12266 (pg = scf_pg_create(g_hndl)) == NULL || 12267 (parent_prop = scf_property_create(g_hndl)) == NULL || 12268 (prop = scf_property_create(g_hndl)) == NULL || 12269 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 12270 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12271 (tx = scf_transaction_create(g_hndl)) == NULL) 12272 scfdie(); 12273 12274 if (cur_snap != NULL) { 12275 semerr(emsg_cant_modify_snapshots); 12276 goto fail; 12277 } 12278 12279 if (cur_inst == NULL && cur_svc == NULL) { 12280 semerr(emsg_entity_not_selected); 12281 goto fail; 12282 } 12283 12284 propname = strchr(pgname, '/'); 12285 if (propname == NULL) { 12286 semerr(gettext("Property names must contain a `/'.\n")); 12287 goto fail; 12288 } 12289 12290 *propname = '\0'; 12291 ++propname; 12292 12293 if (type != NULL) { 12294 ty = string_to_type(type); 12295 if (ty == SCF_TYPE_INVALID) { 12296 semerr(gettext("Unknown type \"%s\".\n"), type); 12297 goto fail; 12298 } 12299 } 12300 12301 if (cur_inst != NULL) 12302 ret = scf_instance_get_pg(cur_inst, pgname, pg); 12303 else 12304 ret = scf_service_get_pg(cur_svc, pgname, pg); 12305 if (ret != SCF_SUCCESS) { 12306 switch (scf_error()) { 12307 case SCF_ERROR_NOT_FOUND: 12308 semerr(emsg_no_such_pg, pgname); 12309 goto fail; 12310 12311 case SCF_ERROR_INVALID_ARGUMENT: 12312 semerr(emsg_invalid_pg_name, pgname); 12313 goto fail; 12314 12315 default: 12316 scfdie(); 12317 break; 12318 } 12319 } 12320 12321 do { 12322 if (scf_pg_update(pg) == -1) 12323 scfdie(); 12324 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12325 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12326 scfdie(); 12327 12328 semerr(emsg_permission_denied); 12329 goto fail; 12330 } 12331 12332 ret = scf_pg_get_property(pg, propname, prop); 12333 if (ret == SCF_SUCCESS) { 12334 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 12335 scfdie(); 12336 12337 if (type == NULL) 12338 ty = current_ty; 12339 if (scf_transaction_property_change_type(tx, e, 12340 propname, ty) == -1) 12341 scfdie(); 12342 12343 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 12344 /* Infer the type, if possible. */ 12345 if (type == NULL) { 12346 /* 12347 * First check if we're an instance and the 12348 * property is set on the service. 12349 */ 12350 if (cur_inst != NULL && 12351 scf_instance_get_parent(cur_inst, 12352 svc) == 0 && 12353 scf_service_get_pg(cur_svc, pgname, 12354 parent_pg) == 0 && 12355 scf_pg_get_property(parent_pg, propname, 12356 parent_prop) == 0 && 12357 scf_property_type(parent_prop, 12358 ¤t_ty) == 0) { 12359 ty = current_ty; 12360 12361 /* Then check for a type set in a template. */ 12362 } else if (scf_tmpl_get_by_pg(pg, pgt, 12363 NULL) == 0 && 12364 scf_tmpl_get_by_prop(pgt, propname, prt, 12365 NULL) == 0 && 12366 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 12367 ty = current_ty; 12368 12369 /* If type can't be inferred, fail. */ 12370 } else { 12371 semerr(gettext("Type required for new " 12372 "properties.\n")); 12373 goto fail; 12374 } 12375 } 12376 if (scf_transaction_property_new(tx, e, propname, 12377 ty) == -1) 12378 scfdie(); 12379 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12380 semerr(emsg_invalid_prop_name, propname); 12381 goto fail; 12382 } else { 12383 scfdie(); 12384 } 12385 12386 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 12387 req_quotes = 1; 12388 12389 if (value != NULL) { 12390 v = string_to_value(value, ty, 0); 12391 12392 if (v == NULL) 12393 goto fail; 12394 12395 ret = scf_entry_add_value(e, v); 12396 assert(ret == SCF_SUCCESS); 12397 } else { 12398 assert(values != NULL); 12399 12400 walk = uu_list_walk_start((uu_list_t *)values, 12401 UU_DEFAULT); 12402 if (walk == NULL) 12403 uu_die(gettext("Could not walk list")); 12404 12405 for (sp = uu_list_walk_next(walk); sp != NULL; 12406 sp = uu_list_walk_next(walk)) { 12407 v = string_to_value(sp->str, ty, req_quotes); 12408 12409 if (v == NULL) { 12410 scf_entry_destroy_children(e); 12411 goto fail; 12412 } 12413 12414 ret = scf_entry_add_value(e, v); 12415 assert(ret == SCF_SUCCESS); 12416 } 12417 uu_list_walk_end(walk); 12418 } 12419 result = scf_transaction_commit(tx); 12420 12421 scf_transaction_reset(tx); 12422 scf_entry_destroy_children(e); 12423 } while (result == 0); 12424 12425 if (result < 0) { 12426 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12427 scfdie(); 12428 12429 semerr(emsg_permission_denied); 12430 goto fail; 12431 } 12432 12433 ret = 0; 12434 12435 private_refresh(); 12436 12437 goto cleanup; 12438 12439 fail: 12440 ret = -1; 12441 12442 cleanup: 12443 scf_transaction_destroy(tx); 12444 scf_entry_destroy(e); 12445 scf_service_destroy(svc); 12446 scf_pg_destroy(parent_pg); 12447 scf_pg_destroy(pg); 12448 scf_property_destroy(parent_prop); 12449 scf_property_destroy(prop); 12450 scf_tmpl_pg_destroy(pgt); 12451 scf_tmpl_prop_destroy(prt); 12452 12453 return (ret); 12454 } 12455 12456 void 12457 lscf_delprop(char *pgn) 12458 { 12459 char *slash, *pn; 12460 scf_propertygroup_t *pg; 12461 scf_transaction_t *tx; 12462 scf_transaction_entry_t *e; 12463 int ret; 12464 12465 12466 lscf_prep_hndl(); 12467 12468 if (cur_snap != NULL) { 12469 semerr(emsg_cant_modify_snapshots); 12470 return; 12471 } 12472 12473 if (cur_inst == NULL && cur_svc == NULL) { 12474 semerr(emsg_entity_not_selected); 12475 return; 12476 } 12477 12478 pg = scf_pg_create(g_hndl); 12479 if (pg == NULL) 12480 scfdie(); 12481 12482 slash = strchr(pgn, '/'); 12483 if (slash == NULL) { 12484 pn = NULL; 12485 } else { 12486 *slash = '\0'; 12487 pn = slash + 1; 12488 } 12489 12490 if (cur_inst != NULL) 12491 ret = scf_instance_get_pg(cur_inst, pgn, pg); 12492 else 12493 ret = scf_service_get_pg(cur_svc, pgn, pg); 12494 if (ret != SCF_SUCCESS) { 12495 switch (scf_error()) { 12496 case SCF_ERROR_NOT_FOUND: 12497 semerr(emsg_no_such_pg, pgn); 12498 break; 12499 12500 case SCF_ERROR_INVALID_ARGUMENT: 12501 semerr(emsg_invalid_pg_name, pgn); 12502 break; 12503 12504 default: 12505 scfdie(); 12506 } 12507 12508 scf_pg_destroy(pg); 12509 12510 return; 12511 } 12512 12513 if (pn == NULL) { 12514 /* Try to delete the property group. */ 12515 if (scf_pg_delete(pg) != SCF_SUCCESS) { 12516 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12517 scfdie(); 12518 12519 semerr(emsg_permission_denied); 12520 } else { 12521 private_refresh(); 12522 } 12523 12524 scf_pg_destroy(pg); 12525 return; 12526 } 12527 12528 e = scf_entry_create(g_hndl); 12529 tx = scf_transaction_create(g_hndl); 12530 12531 do { 12532 if (scf_pg_update(pg) == -1) 12533 scfdie(); 12534 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12535 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12536 scfdie(); 12537 12538 semerr(emsg_permission_denied); 12539 break; 12540 } 12541 12542 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 12543 if (scf_error() == SCF_ERROR_NOT_FOUND) { 12544 semerr(gettext("No such property %s/%s.\n"), 12545 pgn, pn); 12546 break; 12547 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12548 semerr(emsg_invalid_prop_name, pn); 12549 break; 12550 } else { 12551 scfdie(); 12552 } 12553 } 12554 12555 ret = scf_transaction_commit(tx); 12556 12557 if (ret == 0) 12558 scf_transaction_reset(tx); 12559 } while (ret == 0); 12560 12561 if (ret < 0) { 12562 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12563 scfdie(); 12564 12565 semerr(emsg_permission_denied); 12566 } else { 12567 private_refresh(); 12568 } 12569 12570 scf_transaction_destroy(tx); 12571 scf_entry_destroy(e); 12572 scf_pg_destroy(pg); 12573 } 12574 12575 /* 12576 * Property editing. 12577 */ 12578 12579 static int 12580 write_edit_script(FILE *strm) 12581 { 12582 char *fmribuf; 12583 ssize_t fmrilen; 12584 12585 scf_propertygroup_t *pg; 12586 scf_property_t *prop; 12587 scf_value_t *val; 12588 scf_type_t ty; 12589 int ret, result = 0; 12590 scf_iter_t *iter, *piter, *viter; 12591 char *buf, *tybuf, *pname; 12592 const char *emsg_write_error; 12593 12594 12595 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 12596 12597 12598 /* select fmri */ 12599 if (cur_inst != NULL) { 12600 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 12601 if (fmrilen < 0) 12602 scfdie(); 12603 fmribuf = safe_malloc(fmrilen + 1); 12604 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 12605 scfdie(); 12606 } else { 12607 assert(cur_svc != NULL); 12608 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 12609 if (fmrilen < 0) 12610 scfdie(); 12611 fmribuf = safe_malloc(fmrilen + 1); 12612 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 12613 scfdie(); 12614 } 12615 12616 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 12617 warn(emsg_write_error, strerror(errno)); 12618 free(fmribuf); 12619 return (-1); 12620 } 12621 12622 free(fmribuf); 12623 12624 12625 if ((pg = scf_pg_create(g_hndl)) == NULL || 12626 (prop = scf_property_create(g_hndl)) == NULL || 12627 (val = scf_value_create(g_hndl)) == NULL || 12628 (iter = scf_iter_create(g_hndl)) == NULL || 12629 (piter = scf_iter_create(g_hndl)) == NULL || 12630 (viter = scf_iter_create(g_hndl)) == NULL) 12631 scfdie(); 12632 12633 buf = safe_malloc(max_scf_name_len + 1); 12634 tybuf = safe_malloc(max_scf_pg_type_len + 1); 12635 pname = safe_malloc(max_scf_name_len + 1); 12636 12637 if (cur_inst != NULL) 12638 ret = scf_iter_instance_pgs(iter, cur_inst); 12639 else 12640 ret = scf_iter_service_pgs(iter, cur_svc); 12641 if (ret != SCF_SUCCESS) 12642 scfdie(); 12643 12644 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12645 int ret2; 12646 12647 /* 12648 * # delprop pg 12649 * # addpg pg type 12650 */ 12651 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 12652 scfdie(); 12653 12654 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 12655 scfdie(); 12656 12657 if (fprintf(strm, "# Property group \"%s\"\n" 12658 "# delprop %s\n" 12659 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 12660 warn(emsg_write_error, strerror(errno)); 12661 result = -1; 12662 goto out; 12663 } 12664 12665 /* # setprop pg/prop = (values) */ 12666 12667 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 12668 scfdie(); 12669 12670 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 12671 int first = 1; 12672 int ret3; 12673 int multiple; 12674 int is_str; 12675 scf_type_t bty; 12676 12677 if (scf_property_get_name(prop, pname, 12678 max_scf_name_len + 1) < 0) 12679 scfdie(); 12680 12681 if (scf_property_type(prop, &ty) != 0) 12682 scfdie(); 12683 12684 multiple = prop_has_multiple_values(prop, val); 12685 12686 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 12687 pname, scf_type_to_string(ty), multiple ? "(" : "") 12688 < 0) { 12689 warn(emsg_write_error, strerror(errno)); 12690 result = -1; 12691 goto out; 12692 } 12693 12694 (void) scf_type_base_type(ty, &bty); 12695 is_str = (bty == SCF_TYPE_ASTRING); 12696 12697 if (scf_iter_property_values(viter, prop) != 12698 SCF_SUCCESS) 12699 scfdie(); 12700 12701 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 12702 char *buf; 12703 ssize_t buflen; 12704 12705 buflen = scf_value_get_as_string(val, NULL, 0); 12706 if (buflen < 0) 12707 scfdie(); 12708 12709 buf = safe_malloc(buflen + 1); 12710 12711 if (scf_value_get_as_string(val, buf, 12712 buflen + 1) < 0) 12713 scfdie(); 12714 12715 if (first) 12716 first = 0; 12717 else { 12718 if (putc(' ', strm) != ' ') { 12719 warn(emsg_write_error, 12720 strerror(errno)); 12721 result = -1; 12722 goto out; 12723 } 12724 } 12725 12726 if ((is_str && multiple) || 12727 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 12728 (void) putc('"', strm); 12729 (void) quote_and_print(buf, strm, 1); 12730 (void) putc('"', strm); 12731 12732 if (ferror(strm)) { 12733 warn(emsg_write_error, 12734 strerror(errno)); 12735 result = -1; 12736 goto out; 12737 } 12738 } else { 12739 if (fprintf(strm, "%s", buf) < 0) { 12740 warn(emsg_write_error, 12741 strerror(errno)); 12742 result = -1; 12743 goto out; 12744 } 12745 } 12746 12747 free(buf); 12748 } 12749 if (ret3 < 0 && 12750 scf_error() != SCF_ERROR_PERMISSION_DENIED) 12751 scfdie(); 12752 12753 /* Write closing paren if mult-value property */ 12754 if ((multiple && putc(')', strm) == EOF) || 12755 12756 /* Write final newline */ 12757 fputc('\n', strm) == EOF) { 12758 warn(emsg_write_error, strerror(errno)); 12759 result = -1; 12760 goto out; 12761 } 12762 } 12763 if (ret2 < 0) 12764 scfdie(); 12765 12766 if (fputc('\n', strm) == EOF) { 12767 warn(emsg_write_error, strerror(errno)); 12768 result = -1; 12769 goto out; 12770 } 12771 } 12772 if (ret < 0) 12773 scfdie(); 12774 12775 out: 12776 free(pname); 12777 free(tybuf); 12778 free(buf); 12779 scf_iter_destroy(viter); 12780 scf_iter_destroy(piter); 12781 scf_iter_destroy(iter); 12782 scf_value_destroy(val); 12783 scf_property_destroy(prop); 12784 scf_pg_destroy(pg); 12785 12786 if (result == 0) { 12787 if (fflush(strm) != 0) { 12788 warn(emsg_write_error, strerror(errno)); 12789 return (-1); 12790 } 12791 } 12792 12793 return (result); 12794 } 12795 12796 int 12797 lscf_editprop() 12798 { 12799 char *buf, *editor; 12800 size_t bufsz; 12801 int tmpfd; 12802 char tempname[] = TEMP_FILE_PATTERN; 12803 12804 lscf_prep_hndl(); 12805 12806 if (cur_snap != NULL) { 12807 semerr(emsg_cant_modify_snapshots); 12808 return (-1); 12809 } 12810 12811 if (cur_svc == NULL && cur_inst == NULL) { 12812 semerr(emsg_entity_not_selected); 12813 return (-1); 12814 } 12815 12816 tmpfd = mkstemp(tempname); 12817 if (tmpfd == -1) { 12818 semerr(gettext("Could not create temporary file.\n")); 12819 return (-1); 12820 } 12821 12822 (void) strcpy(tempfilename, tempname); 12823 12824 tempfile = fdopen(tmpfd, "r+"); 12825 if (tempfile == NULL) { 12826 warn(gettext("Could not create temporary file.\n")); 12827 if (close(tmpfd) == -1) 12828 warn(gettext("Could not close temporary file: %s.\n"), 12829 strerror(errno)); 12830 12831 remove_tempfile(); 12832 12833 return (-1); 12834 } 12835 12836 if (write_edit_script(tempfile) == -1) { 12837 remove_tempfile(); 12838 return (-1); 12839 } 12840 12841 editor = getenv("EDITOR"); 12842 if (editor == NULL) 12843 editor = "vi"; 12844 12845 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 12846 buf = safe_malloc(bufsz); 12847 12848 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 12849 uu_die(gettext("Error creating editor command")); 12850 12851 if (system(buf) == -1) { 12852 semerr(gettext("Could not launch editor %s: %s\n"), editor, 12853 strerror(errno)); 12854 free(buf); 12855 remove_tempfile(); 12856 return (-1); 12857 } 12858 12859 free(buf); 12860 12861 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 12862 12863 remove_tempfile(); 12864 12865 return (0); 12866 } 12867 12868 static void 12869 add_string(uu_list_t *strlist, const char *str) 12870 { 12871 string_list_t *elem; 12872 elem = safe_malloc(sizeof (*elem)); 12873 uu_list_node_init(elem, &elem->node, string_pool); 12874 elem->str = safe_strdup(str); 12875 if (uu_list_append(strlist, elem) != 0) 12876 uu_die(gettext("libuutil error: %s\n"), 12877 uu_strerror(uu_error())); 12878 } 12879 12880 /* 12881 * Get all property values that don't match the given glob pattern, 12882 * if a pattern is specified. 12883 */ 12884 static void 12885 get_prop_values(scf_property_t *prop, uu_list_t *values, 12886 const char *pattern) 12887 { 12888 scf_iter_t *iter; 12889 scf_value_t *val; 12890 int ret; 12891 12892 if ((iter = scf_iter_create(g_hndl)) == NULL || 12893 (val = scf_value_create(g_hndl)) == NULL) 12894 scfdie(); 12895 12896 if (scf_iter_property_values(iter, prop) != 0) 12897 scfdie(); 12898 12899 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12900 char *buf; 12901 ssize_t vlen, szret; 12902 12903 vlen = scf_value_get_as_string(val, NULL, 0); 12904 if (vlen < 0) 12905 scfdie(); 12906 12907 buf = safe_malloc(vlen + 1); 12908 12909 szret = scf_value_get_as_string(val, buf, vlen + 1); 12910 if (szret < 0) 12911 scfdie(); 12912 assert(szret <= vlen); 12913 12914 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 12915 add_string(values, buf); 12916 12917 free(buf); 12918 } 12919 12920 if (ret == -1) 12921 scfdie(); 12922 12923 scf_value_destroy(val); 12924 scf_iter_destroy(iter); 12925 } 12926 12927 static int 12928 lscf_setpropvalue(const char *pgname, const char *type, 12929 const char *arg, int isadd, int isnotfoundok) 12930 { 12931 scf_type_t ty; 12932 scf_propertygroup_t *pg; 12933 scf_property_t *prop; 12934 int ret, result = 0; 12935 scf_transaction_t *tx; 12936 scf_transaction_entry_t *e; 12937 scf_value_t *v; 12938 string_list_t *sp; 12939 char *propname; 12940 uu_list_t *values; 12941 uu_list_walk_t *walk; 12942 void *cookie = NULL; 12943 char *pattern = NULL; 12944 12945 lscf_prep_hndl(); 12946 12947 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 12948 uu_die(gettext("Could not create property list: %s\n"), 12949 uu_strerror(uu_error())); 12950 12951 if (!isadd) 12952 pattern = safe_strdup(arg); 12953 12954 if ((e = scf_entry_create(g_hndl)) == NULL || 12955 (pg = scf_pg_create(g_hndl)) == NULL || 12956 (prop = scf_property_create(g_hndl)) == NULL || 12957 (tx = scf_transaction_create(g_hndl)) == NULL) 12958 scfdie(); 12959 12960 if (cur_snap != NULL) { 12961 semerr(emsg_cant_modify_snapshots); 12962 goto fail; 12963 } 12964 12965 if (cur_inst == NULL && cur_svc == NULL) { 12966 semerr(emsg_entity_not_selected); 12967 goto fail; 12968 } 12969 12970 propname = strchr(pgname, '/'); 12971 if (propname == NULL) { 12972 semerr(gettext("Property names must contain a `/'.\n")); 12973 goto fail; 12974 } 12975 12976 *propname = '\0'; 12977 ++propname; 12978 12979 if (type != NULL) { 12980 ty = string_to_type(type); 12981 if (ty == SCF_TYPE_INVALID) { 12982 semerr(gettext("Unknown type \"%s\".\n"), type); 12983 goto fail; 12984 } 12985 } 12986 12987 if (cur_inst != NULL) 12988 ret = scf_instance_get_pg(cur_inst, pgname, pg); 12989 else 12990 ret = scf_service_get_pg(cur_svc, pgname, pg); 12991 if (ret != 0) { 12992 switch (scf_error()) { 12993 case SCF_ERROR_NOT_FOUND: 12994 if (isnotfoundok) { 12995 result = 0; 12996 } else { 12997 semerr(emsg_no_such_pg, pgname); 12998 result = -1; 12999 } 13000 goto out; 13001 13002 case SCF_ERROR_INVALID_ARGUMENT: 13003 semerr(emsg_invalid_pg_name, pgname); 13004 goto fail; 13005 13006 default: 13007 scfdie(); 13008 } 13009 } 13010 13011 do { 13012 if (scf_pg_update(pg) == -1) 13013 scfdie(); 13014 if (scf_transaction_start(tx, pg) != 0) { 13015 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13016 scfdie(); 13017 13018 semerr(emsg_permission_denied); 13019 goto fail; 13020 } 13021 13022 ret = scf_pg_get_property(pg, propname, prop); 13023 if (ret == 0) { 13024 scf_type_t ptype; 13025 char *pat = pattern; 13026 13027 if (scf_property_type(prop, &ptype) != 0) 13028 scfdie(); 13029 13030 if (isadd) { 13031 if (type != NULL && ptype != ty) { 13032 semerr(gettext("Property \"%s\" is not " 13033 "of type \"%s\".\n"), propname, 13034 type); 13035 goto fail; 13036 } 13037 13038 pat = NULL; 13039 } else { 13040 size_t len = strlen(pat); 13041 if (len > 0 && pat[len - 1] == '\"') 13042 pat[len - 1] = '\0'; 13043 if (len > 0 && pat[0] == '\"') 13044 pat++; 13045 } 13046 13047 ty = ptype; 13048 13049 get_prop_values(prop, values, pat); 13050 13051 if (isadd) 13052 add_string(values, arg); 13053 13054 if (scf_transaction_property_change(tx, e, 13055 propname, ty) == -1) 13056 scfdie(); 13057 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 13058 if (isadd) { 13059 if (type == NULL) { 13060 semerr(gettext("Type required " 13061 "for new properties.\n")); 13062 goto fail; 13063 } 13064 13065 add_string(values, arg); 13066 13067 if (scf_transaction_property_new(tx, e, 13068 propname, ty) == -1) 13069 scfdie(); 13070 } else if (isnotfoundok) { 13071 result = 0; 13072 goto out; 13073 } else { 13074 semerr(gettext("No such property %s/%s.\n"), 13075 pgname, propname); 13076 result = -1; 13077 goto out; 13078 } 13079 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 13080 semerr(emsg_invalid_prop_name, propname); 13081 goto fail; 13082 } else { 13083 scfdie(); 13084 } 13085 13086 walk = uu_list_walk_start(values, UU_DEFAULT); 13087 if (walk == NULL) 13088 uu_die(gettext("Could not walk property list.\n")); 13089 13090 for (sp = uu_list_walk_next(walk); sp != NULL; 13091 sp = uu_list_walk_next(walk)) { 13092 v = string_to_value(sp->str, ty, 0); 13093 13094 if (v == NULL) { 13095 scf_entry_destroy_children(e); 13096 goto fail; 13097 } 13098 ret = scf_entry_add_value(e, v); 13099 assert(ret == 0); 13100 } 13101 uu_list_walk_end(walk); 13102 13103 result = scf_transaction_commit(tx); 13104 13105 scf_transaction_reset(tx); 13106 scf_entry_destroy_children(e); 13107 } while (result == 0); 13108 13109 if (result < 0) { 13110 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13111 scfdie(); 13112 13113 semerr(emsg_permission_denied); 13114 goto fail; 13115 } 13116 13117 result = 0; 13118 13119 private_refresh(); 13120 13121 out: 13122 scf_transaction_destroy(tx); 13123 scf_entry_destroy(e); 13124 scf_pg_destroy(pg); 13125 scf_property_destroy(prop); 13126 free(pattern); 13127 13128 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 13129 free(sp->str); 13130 free(sp); 13131 } 13132 13133 uu_list_destroy(values); 13134 13135 return (result); 13136 13137 fail: 13138 result = -1; 13139 goto out; 13140 } 13141 13142 int 13143 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 13144 { 13145 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 13146 } 13147 13148 int 13149 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 13150 { 13151 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 13152 } 13153 13154 /* 13155 * Look for a standard start method, first in the instance (if any), 13156 * then the service. 13157 */ 13158 static const char * 13159 start_method_name(int *in_instance) 13160 { 13161 scf_propertygroup_t *pg; 13162 char **p; 13163 int ret; 13164 scf_instance_t *inst = cur_inst; 13165 13166 if ((pg = scf_pg_create(g_hndl)) == NULL) 13167 scfdie(); 13168 13169 again: 13170 for (p = start_method_names; *p != NULL; p++) { 13171 if (inst != NULL) 13172 ret = scf_instance_get_pg(inst, *p, pg); 13173 else 13174 ret = scf_service_get_pg(cur_svc, *p, pg); 13175 13176 if (ret == 0) { 13177 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 13178 char *buf = safe_malloc(bufsz); 13179 13180 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 13181 free(buf); 13182 continue; 13183 } 13184 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 13185 free(buf); 13186 continue; 13187 } 13188 13189 free(buf); 13190 *in_instance = (inst != NULL); 13191 scf_pg_destroy(pg); 13192 return (*p); 13193 } 13194 13195 if (scf_error() == SCF_ERROR_NOT_FOUND) 13196 continue; 13197 13198 scfdie(); 13199 } 13200 13201 if (inst != NULL) { 13202 inst = NULL; 13203 goto again; 13204 } 13205 13206 scf_pg_destroy(pg); 13207 return (NULL); 13208 } 13209 13210 static int 13211 addpg(const char *name, const char *type) 13212 { 13213 scf_propertygroup_t *pg; 13214 int ret; 13215 13216 pg = scf_pg_create(g_hndl); 13217 if (pg == NULL) 13218 scfdie(); 13219 13220 if (cur_inst != NULL) 13221 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 13222 else 13223 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 13224 13225 if (ret != 0) { 13226 switch (scf_error()) { 13227 case SCF_ERROR_EXISTS: 13228 ret = 0; 13229 break; 13230 13231 case SCF_ERROR_PERMISSION_DENIED: 13232 semerr(emsg_permission_denied); 13233 break; 13234 13235 default: 13236 scfdie(); 13237 } 13238 } 13239 13240 scf_pg_destroy(pg); 13241 return (ret); 13242 } 13243 13244 int 13245 lscf_setenv(uu_list_t *args, int isunset) 13246 { 13247 int ret = 0; 13248 size_t i; 13249 int argc; 13250 char **argv = NULL; 13251 string_list_t *slp; 13252 char *pattern; 13253 char *prop; 13254 int do_service = 0; 13255 int do_instance = 0; 13256 const char *method = NULL; 13257 const char *name = NULL; 13258 const char *value = NULL; 13259 scf_instance_t *saved_cur_inst = cur_inst; 13260 13261 lscf_prep_hndl(); 13262 13263 argc = uu_list_numnodes(args); 13264 if (argc < 1) 13265 goto usage; 13266 13267 argv = calloc(argc + 1, sizeof (char *)); 13268 if (argv == NULL) 13269 uu_die(gettext("Out of memory.\n")); 13270 13271 for (slp = uu_list_first(args), i = 0; 13272 slp != NULL; 13273 slp = uu_list_next(args, slp), ++i) 13274 argv[i] = slp->str; 13275 13276 argv[i] = NULL; 13277 13278 opterr = 0; 13279 optind = 0; 13280 for (;;) { 13281 ret = getopt(argc, argv, "sim:"); 13282 if (ret == -1) 13283 break; 13284 13285 switch (ret) { 13286 case 's': 13287 do_service = 1; 13288 cur_inst = NULL; 13289 break; 13290 13291 case 'i': 13292 do_instance = 1; 13293 break; 13294 13295 case 'm': 13296 method = optarg; 13297 break; 13298 13299 case '?': 13300 goto usage; 13301 13302 default: 13303 bad_error("getopt", ret); 13304 } 13305 } 13306 13307 argc -= optind; 13308 if ((do_service && do_instance) || 13309 (isunset && argc != 1) || 13310 (!isunset && argc != 2)) 13311 goto usage; 13312 13313 name = argv[optind]; 13314 if (!isunset) 13315 value = argv[optind + 1]; 13316 13317 if (cur_snap != NULL) { 13318 semerr(emsg_cant_modify_snapshots); 13319 ret = -1; 13320 goto out; 13321 } 13322 13323 if (cur_inst == NULL && cur_svc == NULL) { 13324 semerr(emsg_entity_not_selected); 13325 ret = -1; 13326 goto out; 13327 } 13328 13329 if (do_instance && cur_inst == NULL) { 13330 semerr(gettext("No instance is selected.\n")); 13331 ret = -1; 13332 goto out; 13333 } 13334 13335 if (do_service && cur_svc == NULL) { 13336 semerr(gettext("No service is selected.\n")); 13337 ret = -1; 13338 goto out; 13339 } 13340 13341 if (method == NULL) { 13342 if (do_instance || do_service) { 13343 method = "method_context"; 13344 if (!isunset) { 13345 ret = addpg("method_context", 13346 SCF_GROUP_FRAMEWORK); 13347 if (ret != 0) 13348 goto out; 13349 } 13350 } else { 13351 int in_instance; 13352 method = start_method_name(&in_instance); 13353 if (method == NULL) { 13354 semerr(gettext( 13355 "Couldn't find start method; please " 13356 "specify a method with '-m'.\n")); 13357 ret = -1; 13358 goto out; 13359 } 13360 if (!in_instance) 13361 cur_inst = NULL; 13362 } 13363 } else { 13364 scf_propertygroup_t *pg; 13365 size_t bufsz; 13366 char *buf; 13367 int ret; 13368 13369 if ((pg = scf_pg_create(g_hndl)) == NULL) 13370 scfdie(); 13371 13372 if (cur_inst != NULL) 13373 ret = scf_instance_get_pg(cur_inst, method, pg); 13374 else 13375 ret = scf_service_get_pg(cur_svc, method, pg); 13376 13377 if (ret != 0) { 13378 scf_pg_destroy(pg); 13379 switch (scf_error()) { 13380 case SCF_ERROR_NOT_FOUND: 13381 semerr(gettext("Couldn't find the method " 13382 "\"%s\".\n"), method); 13383 goto out; 13384 13385 case SCF_ERROR_INVALID_ARGUMENT: 13386 semerr(gettext("Invalid method name \"%s\".\n"), 13387 method); 13388 goto out; 13389 13390 default: 13391 scfdie(); 13392 } 13393 } 13394 13395 bufsz = strlen(SCF_GROUP_METHOD) + 1; 13396 buf = safe_malloc(bufsz); 13397 13398 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 13399 strcmp(buf, SCF_GROUP_METHOD) != 0) { 13400 semerr(gettext("Property group \"%s\" is not of type " 13401 "\"method\".\n"), method); 13402 ret = -1; 13403 free(buf); 13404 scf_pg_destroy(pg); 13405 goto out; 13406 } 13407 13408 free(buf); 13409 scf_pg_destroy(pg); 13410 } 13411 13412 prop = uu_msprintf("%s/environment", method); 13413 pattern = uu_msprintf("%s=*", name); 13414 13415 if (prop == NULL || pattern == NULL) 13416 uu_die(gettext("Out of memory.\n")); 13417 13418 ret = lscf_delpropvalue(prop, pattern, !isunset); 13419 13420 if (ret == 0 && !isunset) { 13421 uu_free(pattern); 13422 uu_free(prop); 13423 prop = uu_msprintf("%s/environment", method); 13424 pattern = uu_msprintf("%s=%s", name, value); 13425 if (prop == NULL || pattern == NULL) 13426 uu_die(gettext("Out of memory.\n")); 13427 ret = lscf_addpropvalue(prop, "astring:", pattern); 13428 } 13429 uu_free(pattern); 13430 uu_free(prop); 13431 13432 out: 13433 cur_inst = saved_cur_inst; 13434 13435 free(argv); 13436 return (ret); 13437 usage: 13438 ret = -2; 13439 goto out; 13440 } 13441 13442 /* 13443 * Snapshot commands 13444 */ 13445 13446 void 13447 lscf_listsnap() 13448 { 13449 scf_snapshot_t *snap; 13450 scf_iter_t *iter; 13451 char *nb; 13452 int r; 13453 13454 lscf_prep_hndl(); 13455 13456 if (cur_inst == NULL) { 13457 semerr(gettext("Instance not selected.\n")); 13458 return; 13459 } 13460 13461 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13462 (iter = scf_iter_create(g_hndl)) == NULL) 13463 scfdie(); 13464 13465 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 13466 scfdie(); 13467 13468 nb = safe_malloc(max_scf_name_len + 1); 13469 13470 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 13471 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 13472 scfdie(); 13473 13474 (void) puts(nb); 13475 } 13476 if (r < 0) 13477 scfdie(); 13478 13479 free(nb); 13480 scf_iter_destroy(iter); 13481 scf_snapshot_destroy(snap); 13482 } 13483 13484 void 13485 lscf_selectsnap(const char *name) 13486 { 13487 scf_snapshot_t *snap; 13488 scf_snaplevel_t *level; 13489 13490 lscf_prep_hndl(); 13491 13492 if (cur_inst == NULL) { 13493 semerr(gettext("Instance not selected.\n")); 13494 return; 13495 } 13496 13497 if (cur_snap != NULL) { 13498 if (name != NULL) { 13499 char *cur_snap_name; 13500 boolean_t nochange; 13501 13502 cur_snap_name = safe_malloc(max_scf_name_len + 1); 13503 13504 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 13505 max_scf_name_len + 1) < 0) 13506 scfdie(); 13507 13508 nochange = strcmp(name, cur_snap_name) == 0; 13509 13510 free(cur_snap_name); 13511 13512 if (nochange) 13513 return; 13514 } 13515 13516 unselect_cursnap(); 13517 } 13518 13519 if (name == NULL) 13520 return; 13521 13522 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13523 (level = scf_snaplevel_create(g_hndl)) == NULL) 13524 scfdie(); 13525 13526 if (scf_instance_get_snapshot(cur_inst, name, snap) != 13527 SCF_SUCCESS) { 13528 switch (scf_error()) { 13529 case SCF_ERROR_INVALID_ARGUMENT: 13530 semerr(gettext("Invalid name \"%s\".\n"), name); 13531 break; 13532 13533 case SCF_ERROR_NOT_FOUND: 13534 semerr(gettext("No such snapshot \"%s\".\n"), name); 13535 break; 13536 13537 default: 13538 scfdie(); 13539 } 13540 13541 scf_snaplevel_destroy(level); 13542 scf_snapshot_destroy(snap); 13543 return; 13544 } 13545 13546 /* Load the snaplevels into our list. */ 13547 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 13548 if (cur_levels == NULL) 13549 uu_die(gettext("Could not create list: %s\n"), 13550 uu_strerror(uu_error())); 13551 13552 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 13553 if (scf_error() != SCF_ERROR_NOT_FOUND) 13554 scfdie(); 13555 13556 semerr(gettext("Snapshot has no snaplevels.\n")); 13557 13558 scf_snaplevel_destroy(level); 13559 scf_snapshot_destroy(snap); 13560 return; 13561 } 13562 13563 cur_snap = snap; 13564 13565 for (;;) { 13566 cur_elt = safe_malloc(sizeof (*cur_elt)); 13567 uu_list_node_init(cur_elt, &cur_elt->list_node, 13568 snaplevel_pool); 13569 cur_elt->sl = level; 13570 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 13571 uu_die(gettext("libuutil error: %s\n"), 13572 uu_strerror(uu_error())); 13573 13574 level = scf_snaplevel_create(g_hndl); 13575 if (level == NULL) 13576 scfdie(); 13577 13578 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 13579 level) != SCF_SUCCESS) { 13580 if (scf_error() != SCF_ERROR_NOT_FOUND) 13581 scfdie(); 13582 13583 scf_snaplevel_destroy(level); 13584 break; 13585 } 13586 } 13587 13588 cur_elt = uu_list_last(cur_levels); 13589 cur_level = cur_elt->sl; 13590 } 13591 13592 /* 13593 * Copies the properties & values in src to dst. Assumes src won't change. 13594 * Returns -1 if permission is denied, -2 if another transaction interrupts, 13595 * and 0 on success. 13596 * 13597 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 13598 * property, if it is copied and has type boolean. (See comment in 13599 * lscf_revert()). 13600 */ 13601 static int 13602 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 13603 uint8_t enabled) 13604 { 13605 scf_transaction_t *tx; 13606 scf_iter_t *iter, *viter; 13607 scf_property_t *prop; 13608 scf_value_t *v; 13609 char *nbuf; 13610 int r; 13611 13612 tx = scf_transaction_create(g_hndl); 13613 if (tx == NULL) 13614 scfdie(); 13615 13616 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 13617 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13618 scfdie(); 13619 13620 scf_transaction_destroy(tx); 13621 13622 return (-1); 13623 } 13624 13625 if ((iter = scf_iter_create(g_hndl)) == NULL || 13626 (prop = scf_property_create(g_hndl)) == NULL || 13627 (viter = scf_iter_create(g_hndl)) == NULL) 13628 scfdie(); 13629 13630 nbuf = safe_malloc(max_scf_name_len + 1); 13631 13632 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 13633 scfdie(); 13634 13635 for (;;) { 13636 scf_transaction_entry_t *e; 13637 scf_type_t ty; 13638 13639 r = scf_iter_next_property(iter, prop); 13640 if (r == -1) 13641 scfdie(); 13642 if (r == 0) 13643 break; 13644 13645 e = scf_entry_create(g_hndl); 13646 if (e == NULL) 13647 scfdie(); 13648 13649 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 13650 scfdie(); 13651 13652 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 13653 scfdie(); 13654 13655 if (scf_transaction_property_new(tx, e, nbuf, 13656 ty) != SCF_SUCCESS) 13657 scfdie(); 13658 13659 if ((enabled == 0 || enabled == 1) && 13660 strcmp(nbuf, scf_property_enabled) == 0 && 13661 ty == SCF_TYPE_BOOLEAN) { 13662 v = scf_value_create(g_hndl); 13663 if (v == NULL) 13664 scfdie(); 13665 13666 scf_value_set_boolean(v, enabled); 13667 13668 if (scf_entry_add_value(e, v) != 0) 13669 scfdie(); 13670 } else { 13671 if (scf_iter_property_values(viter, prop) != 0) 13672 scfdie(); 13673 13674 for (;;) { 13675 v = scf_value_create(g_hndl); 13676 if (v == NULL) 13677 scfdie(); 13678 13679 r = scf_iter_next_value(viter, v); 13680 if (r == -1) 13681 scfdie(); 13682 if (r == 0) { 13683 scf_value_destroy(v); 13684 break; 13685 } 13686 13687 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 13688 scfdie(); 13689 } 13690 } 13691 } 13692 13693 free(nbuf); 13694 scf_iter_destroy(viter); 13695 scf_property_destroy(prop); 13696 scf_iter_destroy(iter); 13697 13698 r = scf_transaction_commit(tx); 13699 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 13700 scfdie(); 13701 13702 scf_transaction_destroy_children(tx); 13703 scf_transaction_destroy(tx); 13704 13705 switch (r) { 13706 case 1: return (0); 13707 case 0: return (-2); 13708 case -1: return (-1); 13709 13710 default: 13711 abort(); 13712 } 13713 13714 /* NOTREACHED */ 13715 } 13716 13717 void 13718 lscf_revert(const char *snapname) 13719 { 13720 scf_snapshot_t *snap, *prev; 13721 scf_snaplevel_t *level, *nlevel; 13722 scf_iter_t *iter; 13723 scf_propertygroup_t *pg, *npg; 13724 scf_property_t *prop; 13725 scf_value_t *val; 13726 char *nbuf, *tbuf; 13727 uint8_t enabled; 13728 13729 lscf_prep_hndl(); 13730 13731 if (cur_inst == NULL) { 13732 semerr(gettext("Instance not selected.\n")); 13733 return; 13734 } 13735 13736 if (snapname != NULL) { 13737 snap = scf_snapshot_create(g_hndl); 13738 if (snap == NULL) 13739 scfdie(); 13740 13741 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 13742 SCF_SUCCESS) { 13743 switch (scf_error()) { 13744 case SCF_ERROR_INVALID_ARGUMENT: 13745 semerr(gettext("Invalid snapshot name " 13746 "\"%s\".\n"), snapname); 13747 break; 13748 13749 case SCF_ERROR_NOT_FOUND: 13750 semerr(gettext("No such snapshot.\n")); 13751 break; 13752 13753 default: 13754 scfdie(); 13755 } 13756 13757 scf_snapshot_destroy(snap); 13758 return; 13759 } 13760 } else { 13761 if (cur_snap != NULL) { 13762 snap = cur_snap; 13763 } else { 13764 semerr(gettext("No snapshot selected.\n")); 13765 return; 13766 } 13767 } 13768 13769 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 13770 (level = scf_snaplevel_create(g_hndl)) == NULL || 13771 (iter = scf_iter_create(g_hndl)) == NULL || 13772 (pg = scf_pg_create(g_hndl)) == NULL || 13773 (npg = scf_pg_create(g_hndl)) == NULL || 13774 (prop = scf_property_create(g_hndl)) == NULL || 13775 (val = scf_value_create(g_hndl)) == NULL) 13776 scfdie(); 13777 13778 nbuf = safe_malloc(max_scf_name_len + 1); 13779 tbuf = safe_malloc(max_scf_pg_type_len + 1); 13780 13781 /* Take the "previous" snapshot before we blow away the properties. */ 13782 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 13783 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 13784 scfdie(); 13785 } else { 13786 if (scf_error() != SCF_ERROR_NOT_FOUND) 13787 scfdie(); 13788 13789 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 13790 scfdie(); 13791 } 13792 13793 /* Save general/enabled, since we're probably going to replace it. */ 13794 enabled = 2; 13795 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 13796 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 13797 scf_property_get_value(prop, val) == 0) 13798 (void) scf_value_get_boolean(val, &enabled); 13799 13800 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 13801 if (scf_error() != SCF_ERROR_NOT_FOUND) 13802 scfdie(); 13803 13804 goto out; 13805 } 13806 13807 for (;;) { 13808 boolean_t isinst; 13809 uint32_t flags; 13810 int r; 13811 13812 /* Clear the properties from the corresponding entity. */ 13813 isinst = snaplevel_is_instance(level); 13814 13815 if (!isinst) 13816 r = scf_iter_service_pgs(iter, cur_svc); 13817 else 13818 r = scf_iter_instance_pgs(iter, cur_inst); 13819 if (r != SCF_SUCCESS) 13820 scfdie(); 13821 13822 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 13823 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 13824 scfdie(); 13825 13826 /* Skip nonpersistent pgs. */ 13827 if (flags & SCF_PG_FLAG_NONPERSISTENT) 13828 continue; 13829 13830 if (scf_pg_delete(pg) != SCF_SUCCESS) { 13831 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13832 scfdie(); 13833 13834 semerr(emsg_permission_denied); 13835 goto out; 13836 } 13837 } 13838 if (r == -1) 13839 scfdie(); 13840 13841 /* Copy the properties to the corresponding entity. */ 13842 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 13843 scfdie(); 13844 13845 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 13846 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 13847 scfdie(); 13848 13849 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 13850 0) 13851 scfdie(); 13852 13853 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 13854 scfdie(); 13855 13856 if (!isinst) 13857 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 13858 flags, npg); 13859 else 13860 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 13861 flags, npg); 13862 if (r != SCF_SUCCESS) { 13863 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13864 scfdie(); 13865 13866 semerr(emsg_permission_denied); 13867 goto out; 13868 } 13869 13870 if ((enabled == 0 || enabled == 1) && 13871 strcmp(nbuf, scf_pg_general) == 0) 13872 r = pg_copy(pg, npg, enabled); 13873 else 13874 r = pg_copy(pg, npg, 2); 13875 13876 switch (r) { 13877 case 0: 13878 break; 13879 13880 case -1: 13881 semerr(emsg_permission_denied); 13882 goto out; 13883 13884 case -2: 13885 semerr(gettext( 13886 "Interrupted by another change.\n")); 13887 goto out; 13888 13889 default: 13890 abort(); 13891 } 13892 } 13893 if (r == -1) 13894 scfdie(); 13895 13896 /* Get next level. */ 13897 nlevel = scf_snaplevel_create(g_hndl); 13898 if (nlevel == NULL) 13899 scfdie(); 13900 13901 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 13902 SCF_SUCCESS) { 13903 if (scf_error() != SCF_ERROR_NOT_FOUND) 13904 scfdie(); 13905 13906 scf_snaplevel_destroy(nlevel); 13907 break; 13908 } 13909 13910 scf_snaplevel_destroy(level); 13911 level = nlevel; 13912 } 13913 13914 if (snapname == NULL) { 13915 lscf_selectsnap(NULL); 13916 snap = NULL; /* cur_snap has been destroyed */ 13917 } 13918 13919 out: 13920 free(tbuf); 13921 free(nbuf); 13922 scf_value_destroy(val); 13923 scf_property_destroy(prop); 13924 scf_pg_destroy(npg); 13925 scf_pg_destroy(pg); 13926 scf_iter_destroy(iter); 13927 scf_snaplevel_destroy(level); 13928 scf_snapshot_destroy(prev); 13929 if (snap != cur_snap) 13930 scf_snapshot_destroy(snap); 13931 } 13932 13933 void 13934 lscf_refresh(void) 13935 { 13936 ssize_t fmrilen; 13937 size_t bufsz; 13938 char *fmribuf; 13939 int r; 13940 13941 lscf_prep_hndl(); 13942 13943 if (cur_inst == NULL) { 13944 semerr(gettext("Instance not selected.\n")); 13945 return; 13946 } 13947 13948 bufsz = max_scf_fmri_len + 1; 13949 fmribuf = safe_malloc(bufsz); 13950 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 13951 if (fmrilen < 0) { 13952 free(fmribuf); 13953 if (scf_error() != SCF_ERROR_DELETED) 13954 scfdie(); 13955 scf_instance_destroy(cur_inst); 13956 cur_inst = NULL; 13957 warn(emsg_deleted); 13958 return; 13959 } 13960 assert(fmrilen < bufsz); 13961 13962 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 13963 switch (r) { 13964 case 0: 13965 break; 13966 13967 case ECONNABORTED: 13968 warn(gettext("Could not refresh %s " 13969 "(repository connection broken).\n"), fmribuf); 13970 break; 13971 13972 case ECANCELED: 13973 warn(emsg_deleted); 13974 break; 13975 13976 case EPERM: 13977 warn(gettext("Could not refresh %s " 13978 "(permission denied).\n"), fmribuf); 13979 break; 13980 13981 case ENOSPC: 13982 warn(gettext("Could not refresh %s " 13983 "(repository server out of resources).\n"), 13984 fmribuf); 13985 break; 13986 13987 case EACCES: 13988 default: 13989 bad_error("refresh_entity", scf_error()); 13990 } 13991 13992 free(fmribuf); 13993 } 13994 13995 /* 13996 * describe [-v] [-t] [pg/prop] 13997 */ 13998 int 13999 lscf_describe(uu_list_t *args, int hasargs) 14000 { 14001 int ret = 0; 14002 size_t i; 14003 int argc; 14004 char **argv = NULL; 14005 string_list_t *slp; 14006 int do_verbose = 0; 14007 int do_templates = 0; 14008 char *pattern = NULL; 14009 14010 lscf_prep_hndl(); 14011 14012 if (hasargs != 0) { 14013 argc = uu_list_numnodes(args); 14014 if (argc < 1) 14015 goto usage; 14016 14017 argv = calloc(argc + 1, sizeof (char *)); 14018 if (argv == NULL) 14019 uu_die(gettext("Out of memory.\n")); 14020 14021 for (slp = uu_list_first(args), i = 0; 14022 slp != NULL; 14023 slp = uu_list_next(args, slp), ++i) 14024 argv[i] = slp->str; 14025 14026 argv[i] = NULL; 14027 14028 /* 14029 * We start optind = 0 because our list of arguments 14030 * starts at argv[0] 14031 */ 14032 optind = 0; 14033 opterr = 0; 14034 for (;;) { 14035 ret = getopt(argc, argv, "vt"); 14036 if (ret == -1) 14037 break; 14038 14039 switch (ret) { 14040 case 'v': 14041 do_verbose = 1; 14042 break; 14043 14044 case 't': 14045 do_templates = 1; 14046 break; 14047 14048 case '?': 14049 goto usage; 14050 14051 default: 14052 bad_error("getopt", ret); 14053 } 14054 } 14055 14056 pattern = argv[optind]; 14057 } 14058 14059 if (cur_inst == NULL && cur_svc == NULL) { 14060 semerr(emsg_entity_not_selected); 14061 ret = -1; 14062 goto out; 14063 } 14064 14065 /* 14066 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 14067 * output if their last parameter is set to 2. Less information is 14068 * produced if the parameter is set to 1. 14069 */ 14070 if (pattern == NULL) { 14071 if (do_verbose == 1) 14072 list_entity_tmpl(2); 14073 else 14074 list_entity_tmpl(1); 14075 } 14076 14077 if (do_templates == 0) { 14078 if (do_verbose == 1) 14079 listprop(pattern, 0, 2); 14080 else 14081 listprop(pattern, 0, 1); 14082 } else { 14083 if (do_verbose == 1) 14084 listtmpl(pattern, 2); 14085 else 14086 listtmpl(pattern, 1); 14087 } 14088 14089 ret = 0; 14090 out: 14091 if (argv != NULL) 14092 free(argv); 14093 return (ret); 14094 usage: 14095 ret = -2; 14096 goto out; 14097 } 14098 14099 #ifndef NATIVE_BUILD 14100 /* ARGSUSED */ 14101 CPL_MATCH_FN(complete_select) 14102 { 14103 const char *arg0, *arg1, *arg1end; 14104 int word_start, err = 0, r; 14105 size_t len; 14106 char *buf; 14107 14108 lscf_prep_hndl(); 14109 14110 arg0 = line + strspn(line, " \t"); 14111 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 14112 14113 arg1 = arg0 + sizeof ("select") - 1; 14114 arg1 += strspn(arg1, " \t"); 14115 word_start = arg1 - line; 14116 14117 arg1end = arg1 + strcspn(arg1, " \t"); 14118 if (arg1end < line + word_end) 14119 return (0); 14120 14121 len = line + word_end - arg1; 14122 14123 buf = safe_malloc(max_scf_name_len + 1); 14124 14125 if (cur_snap != NULL) { 14126 return (0); 14127 } else if (cur_inst != NULL) { 14128 return (0); 14129 } else if (cur_svc != NULL) { 14130 scf_instance_t *inst; 14131 scf_iter_t *iter; 14132 14133 if ((inst = scf_instance_create(g_hndl)) == NULL || 14134 (iter = scf_iter_create(g_hndl)) == NULL) 14135 scfdie(); 14136 14137 if (scf_iter_service_instances(iter, cur_svc) != 0) 14138 scfdie(); 14139 14140 for (;;) { 14141 r = scf_iter_next_instance(iter, inst); 14142 if (r == 0) 14143 break; 14144 if (r != 1) 14145 scfdie(); 14146 14147 if (scf_instance_get_name(inst, buf, 14148 max_scf_name_len + 1) < 0) 14149 scfdie(); 14150 14151 if (strncmp(buf, arg1, len) == 0) { 14152 err = cpl_add_completion(cpl, line, word_start, 14153 word_end, buf + len, "", " "); 14154 if (err != 0) 14155 break; 14156 } 14157 } 14158 14159 scf_iter_destroy(iter); 14160 scf_instance_destroy(inst); 14161 14162 return (err); 14163 } else { 14164 scf_service_t *svc; 14165 scf_iter_t *iter; 14166 14167 assert(cur_scope != NULL); 14168 14169 if ((svc = scf_service_create(g_hndl)) == NULL || 14170 (iter = scf_iter_create(g_hndl)) == NULL) 14171 scfdie(); 14172 14173 if (scf_iter_scope_services(iter, cur_scope) != 0) 14174 scfdie(); 14175 14176 for (;;) { 14177 r = scf_iter_next_service(iter, svc); 14178 if (r == 0) 14179 break; 14180 if (r != 1) 14181 scfdie(); 14182 14183 if (scf_service_get_name(svc, buf, 14184 max_scf_name_len + 1) < 0) 14185 scfdie(); 14186 14187 if (strncmp(buf, arg1, len) == 0) { 14188 err = cpl_add_completion(cpl, line, word_start, 14189 word_end, buf + len, "", " "); 14190 if (err != 0) 14191 break; 14192 } 14193 } 14194 14195 scf_iter_destroy(iter); 14196 scf_service_destroy(svc); 14197 14198 return (err); 14199 } 14200 } 14201 14202 /* ARGSUSED */ 14203 CPL_MATCH_FN(complete_command) 14204 { 14205 uint32_t scope = 0; 14206 14207 if (cur_snap != NULL) 14208 scope = CS_SNAP; 14209 else if (cur_inst != NULL) 14210 scope = CS_INST; 14211 else if (cur_svc != NULL) 14212 scope = CS_SVC; 14213 else 14214 scope = CS_SCOPE; 14215 14216 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 14217 } 14218 #endif /* NATIVE_BUILD */ 14219