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