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 6082 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata, 6083 UU_DEFAULT) != 0) { 6084 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6085 bad_error("uu_list_walk", uu_error()); 6086 6087 lcbdata->sc_err = cbdata.sc_err; 6088 switch (cbdata.sc_err) { 6089 case ECONNABORTED: 6090 goto connaborted; 6091 6092 case ECANCELED: 6093 warn(ts_deleted, imp_tsname); 6094 lcbdata->sc_err = EBUSY; 6095 return (UU_WALK_ERROR); 6096 6097 case EEXIST: 6098 warn(ts_pg_added, imp_tsname); 6099 lcbdata->sc_err = EBUSY; 6100 return (UU_WALK_ERROR); 6101 } 6102 6103 r = UU_WALK_ERROR; 6104 goto deltemp; 6105 } 6106 6107 if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata, 6108 UU_DEFAULT) != 0) { 6109 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6110 bad_error("uu_list_walk", uu_error()); 6111 6112 lcbdata->sc_err = cbdata.sc_err; 6113 switch (cbdata.sc_err) { 6114 case ECONNABORTED: 6115 goto connaborted; 6116 6117 case ECANCELED: 6118 warn(ts_deleted, imp_tsname); 6119 lcbdata->sc_err = EBUSY; 6120 return (UU_WALK_ERROR); 6121 6122 case EEXIST: 6123 warn(ts_pg_added, imp_tsname); 6124 lcbdata->sc_err = EBUSY; 6125 return (UU_WALK_ERROR); 6126 } 6127 6128 r = UU_WALK_ERROR; 6129 goto deltemp; 6130 } 6131 6132 if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) { 6133 switch (scf_error()) { 6134 case SCF_ERROR_NOT_FOUND: 6135 break; 6136 6137 case SCF_ERROR_CONNECTION_BROKEN: 6138 goto connaborted; 6139 6140 case SCF_ERROR_INVALID_ARGUMENT: 6141 case SCF_ERROR_HANDLE_MISMATCH: 6142 case SCF_ERROR_NOT_BOUND: 6143 case SCF_ERROR_NOT_SET: 6144 default: 6145 bad_error("scf_scope_get_service", scf_error()); 6146 } 6147 6148 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) { 6149 switch (scf_error()) { 6150 case SCF_ERROR_CONNECTION_BROKEN: 6151 goto connaborted; 6152 6153 case SCF_ERROR_NO_RESOURCES: 6154 case SCF_ERROR_BACKEND_READONLY: 6155 case SCF_ERROR_BACKEND_ACCESS: 6156 r = stash_scferror(lcbdata); 6157 goto deltemp; 6158 6159 case SCF_ERROR_EXISTS: 6160 warn(gettext("Scope \"%s\" changed unexpectedly" 6161 " (service \"%s\" added).\n"), 6162 SCF_SCOPE_LOCAL, s->sc_name); 6163 lcbdata->sc_err = EBUSY; 6164 goto deltemp; 6165 6166 case SCF_ERROR_PERMISSION_DENIED: 6167 warn(gettext("Could not create service \"%s\" " 6168 "(permission denied).\n"), s->sc_name); 6169 goto deltemp; 6170 6171 case SCF_ERROR_INVALID_ARGUMENT: 6172 case SCF_ERROR_HANDLE_MISMATCH: 6173 case SCF_ERROR_NOT_BOUND: 6174 case SCF_ERROR_NOT_SET: 6175 default: 6176 bad_error("scf_scope_add_service", scf_error()); 6177 } 6178 } 6179 6180 s->sc_import_state = IMPORT_PROP_BEGUN; 6181 6182 /* import service properties */ 6183 cbdata.sc_handle = lcbdata->sc_handle; 6184 cbdata.sc_parent = imp_svc; 6185 cbdata.sc_service = 1; 6186 cbdata.sc_flags = lcbdata->sc_flags; 6187 cbdata.sc_source_fmri = s->sc_fmri; 6188 cbdata.sc_target_fmri = s->sc_fmri; 6189 6190 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6191 &cbdata, UU_DEFAULT) != 0) { 6192 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6193 bad_error("uu_list_walk", uu_error()); 6194 6195 lcbdata->sc_err = cbdata.sc_err; 6196 switch (cbdata.sc_err) { 6197 case ECONNABORTED: 6198 goto connaborted; 6199 6200 case ECANCELED: 6201 warn(s_deleted, s->sc_fmri); 6202 lcbdata->sc_err = EBUSY; 6203 return (UU_WALK_ERROR); 6204 6205 case EEXIST: 6206 warn(gettext("%s changed unexpectedly " 6207 "(property group added).\n"), s->sc_fmri); 6208 lcbdata->sc_err = EBUSY; 6209 return (UU_WALK_ERROR); 6210 6211 case EINVAL: 6212 /* caught above */ 6213 bad_error("entity_pgroup_import", 6214 cbdata.sc_err); 6215 } 6216 6217 r = UU_WALK_ERROR; 6218 goto deltemp; 6219 } 6220 6221 cbdata.sc_trans = NULL; 6222 if (uu_list_walk(s->sc_dependents, lscf_dependent_import, 6223 &cbdata, UU_DEFAULT) != 0) { 6224 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6225 bad_error("uu_list_walk", uu_error()); 6226 6227 lcbdata->sc_err = cbdata.sc_err; 6228 if (cbdata.sc_err == ECONNABORTED) 6229 goto connaborted; 6230 r = UU_WALK_ERROR; 6231 goto deltemp; 6232 } 6233 6234 s->sc_import_state = IMPORT_PROP_DONE; 6235 6236 /* 6237 * This is a new service, so we can't take previous snapshots 6238 * or upgrade service properties. 6239 */ 6240 fresh = 1; 6241 goto instances; 6242 } 6243 6244 /* Clear sc_seen for the instances. */ 6245 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int, 6246 (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0) 6247 bad_error("uu_list_walk", uu_error()); 6248 6249 /* 6250 * Take previous snapshots for all instances. Even for ones not 6251 * mentioned in the bundle, since we might change their service 6252 * properties. 6253 */ 6254 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6255 switch (scf_error()) { 6256 case SCF_ERROR_CONNECTION_BROKEN: 6257 goto connaborted; 6258 6259 case SCF_ERROR_DELETED: 6260 warn(s_deleted, s->sc_fmri); 6261 lcbdata->sc_err = EBUSY; 6262 r = UU_WALK_ERROR; 6263 goto deltemp; 6264 6265 case SCF_ERROR_HANDLE_MISMATCH: 6266 case SCF_ERROR_NOT_BOUND: 6267 case SCF_ERROR_NOT_SET: 6268 default: 6269 bad_error("scf_iter_service_instances", scf_error()); 6270 } 6271 } 6272 6273 for (;;) { 6274 r = scf_iter_next_instance(imp_iter, imp_inst); 6275 if (r == 0) 6276 break; 6277 if (r != 1) { 6278 switch (scf_error()) { 6279 case SCF_ERROR_DELETED: 6280 warn(s_deleted, s->sc_fmri); 6281 lcbdata->sc_err = EBUSY; 6282 r = UU_WALK_ERROR; 6283 goto deltemp; 6284 6285 case SCF_ERROR_CONNECTION_BROKEN: 6286 goto connaborted; 6287 6288 case SCF_ERROR_NOT_BOUND: 6289 case SCF_ERROR_HANDLE_MISMATCH: 6290 case SCF_ERROR_INVALID_ARGUMENT: 6291 case SCF_ERROR_NOT_SET: 6292 default: 6293 bad_error("scf_iter_next_instance", 6294 scf_error()); 6295 } 6296 } 6297 6298 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) { 6299 switch (scf_error()) { 6300 case SCF_ERROR_DELETED: 6301 continue; 6302 6303 case SCF_ERROR_CONNECTION_BROKEN: 6304 goto connaborted; 6305 6306 case SCF_ERROR_NOT_SET: 6307 case SCF_ERROR_NOT_BOUND: 6308 default: 6309 bad_error("scf_instance_get_name", scf_error()); 6310 } 6311 } 6312 6313 if (g_verbose) 6314 warn(gettext( 6315 "Taking \"%s\" snapshot for svc:/%s:%s.\n"), 6316 snap_previous, s->sc_name, imp_str); 6317 6318 r = take_snap(imp_inst, snap_previous, imp_snap); 6319 switch (r) { 6320 case 0: 6321 break; 6322 6323 case ECANCELED: 6324 continue; 6325 6326 case ECONNABORTED: 6327 goto connaborted; 6328 6329 case EPERM: 6330 warn(gettext("Could not take \"%s\" snapshot of " 6331 "svc:/%s:%s (permission denied).\n"), 6332 snap_previous, s->sc_name, imp_str); 6333 lcbdata->sc_err = r; 6334 return (UU_WALK_ERROR); 6335 6336 case ENOSPC: 6337 case -1: 6338 lcbdata->sc_err = r; 6339 r = UU_WALK_ERROR; 6340 goto deltemp; 6341 6342 default: 6343 bad_error("take_snap", r); 6344 } 6345 6346 linst.sc_name = imp_str; 6347 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances, 6348 &linst, NULL, NULL); 6349 if (inst != NULL) { 6350 inst->sc_import_state = IMPORT_PREVIOUS; 6351 inst->sc_seen = 1; 6352 } 6353 } 6354 6355 /* 6356 * Create the new instances and take previous snapshots of 6357 * them. This is not necessary, but it maximizes data preservation. 6358 */ 6359 for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances); 6360 inst != NULL; 6361 inst = uu_list_next(s->sc_u.sc_service.sc_service_instances, 6362 inst)) { 6363 if (inst->sc_seen) 6364 continue; 6365 6366 if (scf_service_add_instance(imp_svc, inst->sc_name, 6367 imp_inst) != 0) { 6368 switch (scf_error()) { 6369 case SCF_ERROR_CONNECTION_BROKEN: 6370 goto connaborted; 6371 6372 case SCF_ERROR_BACKEND_READONLY: 6373 case SCF_ERROR_BACKEND_ACCESS: 6374 case SCF_ERROR_NO_RESOURCES: 6375 r = stash_scferror(lcbdata); 6376 goto deltemp; 6377 6378 case SCF_ERROR_EXISTS: 6379 warn(gettext("%s changed unexpectedly " 6380 "(instance \"%s\" added).\n"), s->sc_fmri, 6381 inst->sc_name); 6382 lcbdata->sc_err = EBUSY; 6383 r = UU_WALK_ERROR; 6384 goto deltemp; 6385 6386 case SCF_ERROR_INVALID_ARGUMENT: 6387 warn(gettext("Service \"%s\" has instance with " 6388 "invalid name \"%s\".\n"), s->sc_name, 6389 inst->sc_name); 6390 r = stash_scferror(lcbdata); 6391 goto deltemp; 6392 6393 case SCF_ERROR_PERMISSION_DENIED: 6394 warn(gettext("Could not create instance \"%s\" " 6395 "in %s (permission denied).\n"), 6396 inst->sc_name, s->sc_fmri); 6397 r = stash_scferror(lcbdata); 6398 goto deltemp; 6399 6400 case SCF_ERROR_HANDLE_MISMATCH: 6401 case SCF_ERROR_NOT_BOUND: 6402 case SCF_ERROR_NOT_SET: 6403 default: 6404 bad_error("scf_service_add_instance", 6405 scf_error()); 6406 } 6407 } 6408 6409 if (g_verbose) 6410 warn(gettext("Taking \"%s\" snapshot for " 6411 "new service %s.\n"), snap_previous, inst->sc_fmri); 6412 r = take_snap(imp_inst, snap_previous, imp_snap); 6413 switch (r) { 6414 case 0: 6415 break; 6416 6417 case ECANCELED: 6418 warn(i_deleted, s->sc_fmri, inst->sc_name); 6419 lcbdata->sc_err = EBUSY; 6420 r = UU_WALK_ERROR; 6421 goto deltemp; 6422 6423 case ECONNABORTED: 6424 goto connaborted; 6425 6426 case EPERM: 6427 warn(emsg_snap_perm, snap_previous, inst->sc_fmri); 6428 lcbdata->sc_err = r; 6429 r = UU_WALK_ERROR; 6430 goto deltemp; 6431 6432 case ENOSPC: 6433 case -1: 6434 r = UU_WALK_ERROR; 6435 goto deltemp; 6436 6437 default: 6438 bad_error("take_snap", r); 6439 } 6440 } 6441 6442 s->sc_import_state = IMPORT_PREVIOUS; 6443 6444 /* 6445 * Upgrade service properties, if we can find a last-import snapshot. 6446 * Any will do because we don't support different service properties 6447 * in different manifests, so all snaplevels of the service in all of 6448 * the last-import snapshots of the instances should be the same. 6449 */ 6450 if (scf_iter_service_instances(imp_iter, imp_svc) != 0) { 6451 switch (scf_error()) { 6452 case SCF_ERROR_CONNECTION_BROKEN: 6453 goto connaborted; 6454 6455 case SCF_ERROR_DELETED: 6456 warn(s_deleted, s->sc_fmri); 6457 lcbdata->sc_err = EBUSY; 6458 r = UU_WALK_ERROR; 6459 goto deltemp; 6460 6461 case SCF_ERROR_HANDLE_MISMATCH: 6462 case SCF_ERROR_NOT_BOUND: 6463 case SCF_ERROR_NOT_SET: 6464 default: 6465 bad_error("scf_iter_service_instances", scf_error()); 6466 } 6467 } 6468 6469 have_ge = 0; 6470 li_only = 0; 6471 6472 for (;;) { 6473 r = scf_iter_next_instance(imp_iter, imp_inst); 6474 if (r == -1) { 6475 switch (scf_error()) { 6476 case SCF_ERROR_DELETED: 6477 warn(s_deleted, s->sc_fmri); 6478 lcbdata->sc_err = EBUSY; 6479 r = UU_WALK_ERROR; 6480 goto deltemp; 6481 6482 case SCF_ERROR_CONNECTION_BROKEN: 6483 goto connaborted; 6484 6485 case SCF_ERROR_NOT_BOUND: 6486 case SCF_ERROR_HANDLE_MISMATCH: 6487 case SCF_ERROR_INVALID_ARGUMENT: 6488 case SCF_ERROR_NOT_SET: 6489 default: 6490 bad_error("scf_iter_next_instance", 6491 scf_error()); 6492 } 6493 } 6494 6495 if (r == 0) { 6496 /* 6497 * Didn't find any last-import snapshots. Override- 6498 * import the properties. Unless one of the instances 6499 * has a general/enabled property, in which case we're 6500 * probably running a last-import-capable svccfg for 6501 * the first time, and we should only take the 6502 * last-import snapshot. 6503 */ 6504 if (have_ge) { 6505 li_only = 1; 6506 no_refresh = 1; 6507 break; 6508 } 6509 6510 s->sc_import_state = IMPORT_PROP_BEGUN; 6511 6512 cbdata.sc_handle = g_hndl; 6513 cbdata.sc_parent = imp_svc; 6514 cbdata.sc_service = 1; 6515 cbdata.sc_flags = SCI_FORCE; 6516 cbdata.sc_source_fmri = s->sc_fmri; 6517 cbdata.sc_target_fmri = s->sc_fmri; 6518 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, 6519 &cbdata, UU_DEFAULT) != 0) { 6520 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6521 bad_error("uu_list_walk", uu_error()); 6522 lcbdata->sc_err = cbdata.sc_err; 6523 switch (cbdata.sc_err) { 6524 case ECONNABORTED: 6525 goto connaborted; 6526 6527 case ECANCELED: 6528 warn(s_deleted, s->sc_fmri); 6529 lcbdata->sc_err = EBUSY; 6530 break; 6531 6532 case EINVAL: /* caught above */ 6533 case EEXIST: 6534 bad_error("entity_pgroup_import", 6535 cbdata.sc_err); 6536 } 6537 6538 r = UU_WALK_ERROR; 6539 goto deltemp; 6540 } 6541 6542 cbdata.sc_trans = NULL; 6543 if (uu_list_walk(s->sc_dependents, 6544 lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) { 6545 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6546 bad_error("uu_list_walk", uu_error()); 6547 lcbdata->sc_err = cbdata.sc_err; 6548 if (cbdata.sc_err == ECONNABORTED) 6549 goto connaborted; 6550 r = UU_WALK_ERROR; 6551 goto deltemp; 6552 } 6553 break; 6554 } 6555 6556 if (scf_instance_get_snapshot(imp_inst, snap_lastimport, 6557 imp_snap) != 0) { 6558 switch (scf_error()) { 6559 case SCF_ERROR_DELETED: 6560 continue; 6561 6562 case SCF_ERROR_NOT_FOUND: 6563 break; 6564 6565 case SCF_ERROR_CONNECTION_BROKEN: 6566 goto connaborted; 6567 6568 case SCF_ERROR_HANDLE_MISMATCH: 6569 case SCF_ERROR_NOT_BOUND: 6570 case SCF_ERROR_INVALID_ARGUMENT: 6571 case SCF_ERROR_NOT_SET: 6572 default: 6573 bad_error("scf_instance_get_snapshot", 6574 scf_error()); 6575 } 6576 6577 if (have_ge) 6578 continue; 6579 6580 /* 6581 * Check for a general/enabled property. This is how 6582 * we tell whether to import if there turn out to be 6583 * no last-import snapshots. 6584 */ 6585 if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL, 6586 imp_pg) == 0) { 6587 if (scf_pg_get_property(imp_pg, 6588 SCF_PROPERTY_ENABLED, imp_prop) == 0) { 6589 have_ge = 1; 6590 } else { 6591 switch (scf_error()) { 6592 case SCF_ERROR_DELETED: 6593 case SCF_ERROR_NOT_FOUND: 6594 continue; 6595 6596 case SCF_ERROR_INVALID_ARGUMENT: 6597 case SCF_ERROR_HANDLE_MISMATCH: 6598 case SCF_ERROR_CONNECTION_BROKEN: 6599 case SCF_ERROR_NOT_BOUND: 6600 case SCF_ERROR_NOT_SET: 6601 default: 6602 bad_error("scf_pg_get_property", 6603 scf_error()); 6604 } 6605 } 6606 } else { 6607 switch (scf_error()) { 6608 case SCF_ERROR_DELETED: 6609 case SCF_ERROR_NOT_FOUND: 6610 continue; 6611 6612 case SCF_ERROR_CONNECTION_BROKEN: 6613 goto connaborted; 6614 6615 case SCF_ERROR_NOT_BOUND: 6616 case SCF_ERROR_NOT_SET: 6617 case SCF_ERROR_INVALID_ARGUMENT: 6618 case SCF_ERROR_HANDLE_MISMATCH: 6619 default: 6620 bad_error("scf_instance_get_pg", 6621 scf_error()); 6622 } 6623 } 6624 continue; 6625 } 6626 6627 /* find service snaplevel */ 6628 r = get_snaplevel(imp_snap, 1, imp_snpl); 6629 switch (r) { 6630 case 0: 6631 break; 6632 6633 case ECONNABORTED: 6634 goto connaborted; 6635 6636 case ECANCELED: 6637 continue; 6638 6639 case ENOENT: 6640 if (scf_instance_get_name(imp_inst, imp_str, 6641 imp_str_sz) < 0) 6642 (void) strcpy(imp_str, "?"); 6643 warn(badsnap, snap_lastimport, s->sc_name, imp_str); 6644 lcbdata->sc_err = EBADF; 6645 r = UU_WALK_ERROR; 6646 goto deltemp; 6647 6648 default: 6649 bad_error("get_snaplevel", r); 6650 } 6651 6652 if (scf_instance_get_snapshot(imp_inst, snap_running, 6653 imp_rsnap) != 0) { 6654 switch (scf_error()) { 6655 case SCF_ERROR_DELETED: 6656 continue; 6657 6658 case SCF_ERROR_NOT_FOUND: 6659 break; 6660 6661 case SCF_ERROR_CONNECTION_BROKEN: 6662 goto connaborted; 6663 6664 case SCF_ERROR_INVALID_ARGUMENT: 6665 case SCF_ERROR_HANDLE_MISMATCH: 6666 case SCF_ERROR_NOT_BOUND: 6667 case SCF_ERROR_NOT_SET: 6668 default: 6669 bad_error("scf_instance_get_snapshot", 6670 scf_error()); 6671 } 6672 running = NULL; 6673 } else { 6674 r = get_snaplevel(imp_rsnap, 1, imp_rsnpl); 6675 switch (r) { 6676 case 0: 6677 running = imp_rsnpl; 6678 break; 6679 6680 case ECONNABORTED: 6681 goto connaborted; 6682 6683 case ECANCELED: 6684 continue; 6685 6686 case ENOENT: 6687 if (scf_instance_get_name(imp_inst, imp_str, 6688 imp_str_sz) < 0) 6689 (void) strcpy(imp_str, "?"); 6690 warn(badsnap, snap_running, s->sc_name, 6691 imp_str); 6692 lcbdata->sc_err = EBADF; 6693 r = UU_WALK_ERROR; 6694 goto deltemp; 6695 6696 default: 6697 bad_error("get_snaplevel", r); 6698 } 6699 } 6700 6701 if (g_verbose) { 6702 if (scf_instance_get_name(imp_inst, imp_str, 6703 imp_str_sz) < 0) 6704 (void) strcpy(imp_str, "?"); 6705 warn(gettext("Upgrading properties of %s according to " 6706 "instance \"%s\".\n"), s->sc_fmri, imp_str); 6707 } 6708 6709 /* upgrade service properties */ 6710 r = upgrade_props(imp_svc, running, imp_snpl, s); 6711 if (r == 0) 6712 break; 6713 6714 switch (r) { 6715 case ECONNABORTED: 6716 goto connaborted; 6717 6718 case ECANCELED: 6719 warn(s_deleted, s->sc_fmri); 6720 lcbdata->sc_err = EBUSY; 6721 break; 6722 6723 case ENODEV: 6724 if (scf_instance_get_name(imp_inst, imp_str, 6725 imp_str_sz) < 0) 6726 (void) strcpy(imp_str, "?"); 6727 warn(i_deleted, s->sc_fmri, imp_str); 6728 lcbdata->sc_err = EBUSY; 6729 break; 6730 6731 default: 6732 lcbdata->sc_err = r; 6733 } 6734 6735 r = UU_WALK_ERROR; 6736 goto deltemp; 6737 } 6738 6739 s->sc_import_state = IMPORT_PROP_DONE; 6740 6741 instances: 6742 /* import instances */ 6743 cbdata.sc_handle = lcbdata->sc_handle; 6744 cbdata.sc_parent = imp_svc; 6745 cbdata.sc_service = 1; 6746 cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0); 6747 cbdata.sc_general = NULL; 6748 6749 if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, 6750 lscf_instance_import, &cbdata, UU_DEFAULT) != 0) { 6751 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 6752 bad_error("uu_list_walk", uu_error()); 6753 6754 lcbdata->sc_err = cbdata.sc_err; 6755 if (cbdata.sc_err == ECONNABORTED) 6756 goto connaborted; 6757 r = UU_WALK_ERROR; 6758 goto deltemp; 6759 } 6760 6761 s->sc_import_state = IMPORT_COMPLETE; 6762 r = UU_WALK_NEXT; 6763 6764 deltemp: 6765 /* delete temporary service */ 6766 if (scf_service_delete(imp_tsvc) != 0) { 6767 switch (scf_error()) { 6768 case SCF_ERROR_DELETED: 6769 break; 6770 6771 case SCF_ERROR_CONNECTION_BROKEN: 6772 goto connaborted; 6773 6774 case SCF_ERROR_EXISTS: 6775 warn(gettext( 6776 "Could not delete svc:/%s (instances exist).\n"), 6777 imp_tsname); 6778 break; 6779 6780 case SCF_ERROR_NOT_SET: 6781 case SCF_ERROR_NOT_BOUND: 6782 default: 6783 bad_error("scf_service_delete", scf_error()); 6784 } 6785 } 6786 6787 return (r); 6788 6789 connaborted: 6790 warn(gettext("Could not delete svc:/%s " 6791 "(repository connection broken).\n"), imp_tsname); 6792 lcbdata->sc_err = ECONNABORTED; 6793 return (UU_WALK_ERROR); 6794 } 6795 6796 static const char * 6797 import_progress(int st) 6798 { 6799 switch (st) { 6800 case 0: 6801 return (gettext("not reached.")); 6802 6803 case IMPORT_PREVIOUS: 6804 return (gettext("previous snapshot taken.")); 6805 6806 case IMPORT_PROP_BEGUN: 6807 return (gettext("some properties imported.")); 6808 6809 case IMPORT_PROP_DONE: 6810 return (gettext("properties imported.")); 6811 6812 case IMPORT_COMPLETE: 6813 return (gettext("imported.")); 6814 6815 case IMPORT_REFRESHED: 6816 return (gettext("refresh requested.")); 6817 6818 default: 6819 #ifndef NDEBUG 6820 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n", 6821 __FILE__, __LINE__, st); 6822 #endif 6823 abort(); 6824 /* NOTREACHED */ 6825 } 6826 } 6827 6828 /* 6829 * Returns 6830 * 0 - success 6831 * - fmri wasn't found (error printed) 6832 * - entity was deleted (error printed) 6833 * - backend denied access (error printed) 6834 * ENOMEM - out of memory (error printed) 6835 * ECONNABORTED - repository connection broken (error printed) 6836 * EPERM - permission denied (error printed) 6837 * -1 - unknown libscf error (error printed) 6838 */ 6839 static int 6840 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri) 6841 { 6842 scf_error_t serr; 6843 void *ent; 6844 int issvc; 6845 int r; 6846 6847 const char *deleted = gettext("Could not refresh %s (deleted).\n"); 6848 const char *dpt_deleted = gettext("Could not refresh %s " 6849 "(dependent \"%s\" of %s) (deleted).\n"); 6850 6851 serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc); 6852 switch (serr) { 6853 case SCF_ERROR_NONE: 6854 break; 6855 6856 case SCF_ERROR_NO_MEMORY: 6857 if (name == NULL) 6858 warn(gettext("Could not refresh %s (out of memory).\n"), 6859 fmri); 6860 else 6861 warn(gettext("Could not refresh %s " 6862 "(dependent \"%s\" of %s) (out of memory).\n"), 6863 fmri, name, d_fmri); 6864 return (ENOMEM); 6865 6866 case SCF_ERROR_NOT_FOUND: 6867 if (name == NULL) 6868 warn(deleted, fmri); 6869 else 6870 warn(dpt_deleted, fmri, name, d_fmri); 6871 return (0); 6872 6873 case SCF_ERROR_INVALID_ARGUMENT: 6874 case SCF_ERROR_CONSTRAINT_VIOLATED: 6875 default: 6876 bad_error("fmri_to_entity", serr); 6877 } 6878 6879 r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str); 6880 switch (r) { 6881 case 0: 6882 break; 6883 6884 case ECONNABORTED: 6885 if (name != NULL) 6886 warn(gettext("Could not refresh %s " 6887 "(dependent \"%s\" of %s) " 6888 "(repository connection broken).\n"), fmri, name, 6889 d_fmri); 6890 return (r); 6891 6892 case ECANCELED: 6893 if (name == NULL) 6894 warn(deleted, fmri); 6895 else 6896 warn(dpt_deleted, fmri, name, d_fmri); 6897 return (0); 6898 6899 case EACCES: 6900 if (!g_verbose) 6901 return (0); 6902 if (name == NULL) 6903 warn(gettext("Could not refresh %s " 6904 "(backend access denied).\n"), fmri); 6905 else 6906 warn(gettext("Could not refresh %s " 6907 "(dependent \"%s\" of %s) " 6908 "(backend access denied).\n"), fmri, name, d_fmri); 6909 return (0); 6910 6911 case EPERM: 6912 if (name == NULL) 6913 warn(gettext("Could not refresh %s " 6914 "(permission denied).\n"), fmri); 6915 else 6916 warn(gettext("Could not refresh %s " 6917 "(dependent \"%s\" of %s) " 6918 "(permission denied).\n"), fmri, name, d_fmri); 6919 return (r); 6920 6921 case ENOSPC: 6922 if (name == NULL) 6923 warn(gettext("Could not refresh %s " 6924 "(repository server out of resources).\n"), 6925 fmri); 6926 else 6927 warn(gettext("Could not refresh %s " 6928 "(dependent \"%s\" of %s) " 6929 "(repository server out of resources).\n"), 6930 fmri, name, d_fmri); 6931 return (r); 6932 6933 case -1: 6934 scfwarn(); 6935 return (r); 6936 6937 default: 6938 bad_error("refresh_entity", r); 6939 } 6940 6941 if (issvc) 6942 scf_service_destroy(ent); 6943 else 6944 scf_instance_destroy(ent); 6945 6946 return (0); 6947 } 6948 6949 int 6950 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags) 6951 { 6952 scf_callback_t cbdata; 6953 int result = 0; 6954 entity_t *svc, *inst; 6955 uu_list_t *insts; 6956 int r; 6957 pgroup_t *old_dpt; 6958 void *cookie; 6959 int annotation_set = 0; 6960 6961 const char * const emsg_nomem = gettext("Out of memory.\n"); 6962 const char * const emsg_nores = 6963 gettext("svc.configd is out of resources.\n"); 6964 6965 lscf_prep_hndl(); 6966 6967 imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ? 6968 max_scf_name_len : max_scf_fmri_len) + 1; 6969 6970 if ((imp_scope = scf_scope_create(g_hndl)) == NULL || 6971 (imp_svc = scf_service_create(g_hndl)) == NULL || 6972 (imp_tsvc = scf_service_create(g_hndl)) == NULL || 6973 (imp_inst = scf_instance_create(g_hndl)) == NULL || 6974 (imp_tinst = scf_instance_create(g_hndl)) == NULL || 6975 (imp_snap = scf_snapshot_create(g_hndl)) == NULL || 6976 (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL || 6977 (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL || 6978 (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL || 6979 (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL || 6980 (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL || 6981 (imp_pg = scf_pg_create(g_hndl)) == NULL || 6982 (imp_pg2 = scf_pg_create(g_hndl)) == NULL || 6983 (imp_prop = scf_property_create(g_hndl)) == NULL || 6984 (imp_iter = scf_iter_create(g_hndl)) == NULL || 6985 (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL || 6986 (imp_up_iter = scf_iter_create(g_hndl)) == NULL || 6987 (imp_tx = scf_transaction_create(g_hndl)) == NULL || 6988 (imp_str = malloc(imp_str_sz)) == NULL || 6989 (imp_tsname = malloc(max_scf_name_len + 1)) == NULL || 6990 (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL || 6991 (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL || 6992 (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL || 6993 (ud_inst = scf_instance_create(g_hndl)) == NULL || 6994 (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL || 6995 (ud_pg = scf_pg_create(g_hndl)) == NULL || 6996 (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL || 6997 (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL || 6998 (ud_prop = scf_property_create(g_hndl)) == NULL || 6999 (ud_dpt_prop = scf_property_create(g_hndl)) == NULL || 7000 (ud_val = scf_value_create(g_hndl)) == NULL || 7001 (ud_iter = scf_iter_create(g_hndl)) == NULL || 7002 (ud_iter2 = scf_iter_create(g_hndl)) == NULL || 7003 (ud_tx = scf_transaction_create(g_hndl)) == NULL || 7004 (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL || 7005 (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL || 7006 (ud_name = malloc(max_scf_name_len + 1)) == NULL) { 7007 if (scf_error() == SCF_ERROR_NO_RESOURCES) 7008 warn(emsg_nores); 7009 else 7010 warn(emsg_nomem); 7011 result = -1; 7012 goto out; 7013 } 7014 7015 r = load_init(); 7016 switch (r) { 7017 case 0: 7018 break; 7019 7020 case ENOMEM: 7021 warn(emsg_nomem); 7022 result = -1; 7023 goto out; 7024 7025 default: 7026 bad_error("load_init", r); 7027 } 7028 7029 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) { 7030 switch (scf_error()) { 7031 case SCF_ERROR_CONNECTION_BROKEN: 7032 warn(gettext("Repository connection broken.\n")); 7033 repository_teardown(); 7034 result = -1; 7035 goto out; 7036 7037 case SCF_ERROR_NOT_FOUND: 7038 case SCF_ERROR_INVALID_ARGUMENT: 7039 case SCF_ERROR_NOT_BOUND: 7040 case SCF_ERROR_HANDLE_MISMATCH: 7041 default: 7042 bad_error("scf_handle_get_scope", scf_error()); 7043 } 7044 } 7045 7046 /* Set up the auditing annotation. */ 7047 if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) { 7048 annotation_set = 1; 7049 } else { 7050 switch (scf_error()) { 7051 case SCF_ERROR_CONNECTION_BROKEN: 7052 warn(gettext("Repository connection broken.\n")); 7053 repository_teardown(); 7054 result = -1; 7055 goto out; 7056 7057 case SCF_ERROR_INVALID_ARGUMENT: 7058 case SCF_ERROR_NOT_BOUND: 7059 case SCF_ERROR_NO_RESOURCES: 7060 case SCF_ERROR_INTERNAL: 7061 bad_error("_scf_set_annotation", scf_error()); 7062 /* NOTREACHED */ 7063 7064 default: 7065 /* 7066 * Do not terminate import because of inability to 7067 * generate annotation audit event. 7068 */ 7069 warn(gettext("_scf_set_annotation() unexpectedly " 7070 "failed with return code of %d\n"), scf_error()); 7071 break; 7072 } 7073 } 7074 7075 /* 7076 * Clear the sc_import_state's of all services & instances so we can 7077 * report how far we got if we fail. 7078 */ 7079 for (svc = uu_list_first(bndl->sc_bundle_services); 7080 svc != NULL; 7081 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7082 svc->sc_import_state = 0; 7083 7084 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances, 7085 clear_int, (void *)offsetof(entity_t, sc_import_state), 7086 UU_DEFAULT) != 0) 7087 bad_error("uu_list_walk", uu_error()); 7088 } 7089 7090 cbdata.sc_handle = g_hndl; 7091 cbdata.sc_parent = imp_scope; 7092 cbdata.sc_flags = flags; 7093 cbdata.sc_general = NULL; 7094 7095 if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import, 7096 &cbdata, UU_DEFAULT) == 0) { 7097 /* Success. Refresh everything. */ 7098 7099 if (flags & SCI_NOREFRESH || no_refresh) { 7100 result = 0; 7101 goto out; 7102 } 7103 7104 for (svc = uu_list_first(bndl->sc_bundle_services); 7105 svc != NULL; 7106 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7107 pgroup_t *dpt; 7108 7109 insts = svc->sc_u.sc_service.sc_service_instances; 7110 7111 for (inst = uu_list_first(insts); 7112 inst != NULL; 7113 inst = uu_list_next(insts, inst)) { 7114 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL); 7115 switch (r) { 7116 case 0: 7117 break; 7118 7119 case ENOMEM: 7120 case ECONNABORTED: 7121 case EPERM: 7122 case -1: 7123 goto progress; 7124 7125 default: 7126 bad_error("imp_refresh_fmri", r); 7127 } 7128 7129 inst->sc_import_state = IMPORT_REFRESHED; 7130 7131 for (dpt = uu_list_first(inst->sc_dependents); 7132 dpt != NULL; 7133 dpt = uu_list_next(inst->sc_dependents, 7134 dpt)) 7135 if (imp_refresh_fmri( 7136 dpt->sc_pgroup_fmri, 7137 dpt->sc_pgroup_name, 7138 inst->sc_fmri) != 0) 7139 goto progress; 7140 } 7141 7142 for (dpt = uu_list_first(svc->sc_dependents); 7143 dpt != NULL; 7144 dpt = uu_list_next(svc->sc_dependents, dpt)) 7145 if (imp_refresh_fmri(dpt->sc_pgroup_fmri, 7146 dpt->sc_pgroup_name, svc->sc_fmri) != 0) 7147 goto progress; 7148 } 7149 7150 for (old_dpt = uu_list_first(imp_deleted_dpts); 7151 old_dpt != NULL; 7152 old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) 7153 if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri, 7154 old_dpt->sc_pgroup_name, 7155 old_dpt->sc_parent->sc_fmri) != 0) 7156 goto progress; 7157 7158 result = 0; 7159 goto out; 7160 } 7161 7162 if (uu_error() != UU_ERROR_CALLBACK_FAILED) 7163 bad_error("uu_list_walk", uu_error()); 7164 7165 printerr: 7166 /* If the error hasn't been printed yet, do so here. */ 7167 switch (cbdata.sc_err) { 7168 case ECONNABORTED: 7169 warn(gettext("Repository connection broken.\n")); 7170 break; 7171 7172 case ENOMEM: 7173 warn(emsg_nomem); 7174 break; 7175 7176 case ENOSPC: 7177 warn(emsg_nores); 7178 break; 7179 7180 case EROFS: 7181 warn(gettext("Repository is read-only.\n")); 7182 break; 7183 7184 case EACCES: 7185 warn(gettext("Repository backend denied access.\n")); 7186 break; 7187 7188 case EPERM: 7189 case EINVAL: 7190 case EEXIST: 7191 case EBUSY: 7192 case EBADF: 7193 case -1: 7194 break; 7195 7196 default: 7197 bad_error("lscf_service_import", cbdata.sc_err); 7198 } 7199 7200 progress: 7201 warn(gettext("Import of %s failed. Progress:\n"), filename); 7202 7203 for (svc = uu_list_first(bndl->sc_bundle_services); 7204 svc != NULL; 7205 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7206 insts = svc->sc_u.sc_service.sc_service_instances; 7207 7208 warn(gettext(" Service \"%s\": %s\n"), svc->sc_name, 7209 import_progress(svc->sc_import_state)); 7210 7211 for (inst = uu_list_first(insts); 7212 inst != NULL; 7213 inst = uu_list_next(insts, inst)) 7214 warn(gettext(" Instance \"%s\": %s\n"), 7215 inst->sc_name, 7216 import_progress(inst->sc_import_state)); 7217 } 7218 7219 if (cbdata.sc_err == ECONNABORTED) 7220 repository_teardown(); 7221 7222 7223 result = -1; 7224 7225 out: 7226 if (annotation_set != 0) { 7227 /* Turn off annotation. It is no longer needed. */ 7228 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7229 } 7230 load_fini(); 7231 7232 free(ud_ctarg); 7233 free(ud_oldtarg); 7234 free(ud_name); 7235 ud_ctarg = ud_oldtarg = ud_name = NULL; 7236 7237 scf_transaction_destroy(ud_tx); 7238 ud_tx = NULL; 7239 scf_iter_destroy(ud_iter); 7240 scf_iter_destroy(ud_iter2); 7241 ud_iter = ud_iter2 = NULL; 7242 scf_value_destroy(ud_val); 7243 ud_val = NULL; 7244 scf_property_destroy(ud_prop); 7245 scf_property_destroy(ud_dpt_prop); 7246 ud_prop = ud_dpt_prop = NULL; 7247 scf_pg_destroy(ud_pg); 7248 scf_pg_destroy(ud_cur_depts_pg); 7249 scf_pg_destroy(ud_run_dpts_pg); 7250 ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL; 7251 scf_snaplevel_destroy(ud_snpl); 7252 ud_snpl = NULL; 7253 scf_instance_destroy(ud_inst); 7254 ud_inst = NULL; 7255 7256 free(imp_str); 7257 free(imp_tsname); 7258 free(imp_fe1); 7259 free(imp_fe2); 7260 imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL; 7261 7262 cookie = NULL; 7263 while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) != 7264 NULL) { 7265 free((char *)old_dpt->sc_pgroup_name); 7266 free((char *)old_dpt->sc_pgroup_fmri); 7267 internal_pgroup_free(old_dpt); 7268 } 7269 uu_list_destroy(imp_deleted_dpts); 7270 7271 scf_transaction_destroy(imp_tx); 7272 imp_tx = NULL; 7273 scf_iter_destroy(imp_iter); 7274 scf_iter_destroy(imp_rpg_iter); 7275 scf_iter_destroy(imp_up_iter); 7276 imp_iter = imp_rpg_iter = imp_up_iter = NULL; 7277 scf_property_destroy(imp_prop); 7278 imp_prop = NULL; 7279 scf_pg_destroy(imp_pg); 7280 scf_pg_destroy(imp_pg2); 7281 imp_pg = imp_pg2 = NULL; 7282 scf_snaplevel_destroy(imp_snpl); 7283 scf_snaplevel_destroy(imp_rsnpl); 7284 imp_snpl = imp_rsnpl = NULL; 7285 scf_snapshot_destroy(imp_snap); 7286 scf_snapshot_destroy(imp_lisnap); 7287 scf_snapshot_destroy(imp_tlisnap); 7288 scf_snapshot_destroy(imp_rsnap); 7289 imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL; 7290 scf_instance_destroy(imp_inst); 7291 scf_instance_destroy(imp_tinst); 7292 imp_inst = imp_tinst = NULL; 7293 scf_service_destroy(imp_svc); 7294 scf_service_destroy(imp_tsvc); 7295 imp_svc = imp_tsvc = NULL; 7296 scf_scope_destroy(imp_scope); 7297 imp_scope = NULL; 7298 7299 return (result); 7300 } 7301 7302 7303 /* 7304 * Returns 7305 * 0 - success 7306 * -1 - lscf_import_instance_pgs() failed. 7307 */ 7308 int 7309 lscf_bundle_apply(bundle_t *bndl, const char *file) 7310 { 7311 entity_t *svc, *inst; 7312 scf_scope_t *rscope; 7313 scf_service_t *rsvc; 7314 scf_instance_t *rinst; 7315 int annotation_set = 0; 7316 int r; 7317 7318 lscf_prep_hndl(); 7319 7320 if ((rscope = scf_scope_create(g_hndl)) == NULL || 7321 (rsvc = scf_service_create(g_hndl)) == NULL || 7322 (rinst = scf_instance_create(g_hndl)) == NULL || 7323 (imp_pg = scf_pg_create(g_hndl)) == NULL || 7324 (imp_tx = scf_transaction_create(g_hndl)) == NULL) 7325 scfdie(); 7326 7327 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0) 7328 scfdie(); 7329 7330 /* 7331 * Set the strings to be used for the security audit annotation 7332 * event. 7333 */ 7334 if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) { 7335 annotation_set = 1; 7336 } else { 7337 switch (scf_error()) { 7338 case SCF_ERROR_CONNECTION_BROKEN: 7339 warn(gettext("Repository connection broken.\n")); 7340 goto out; 7341 7342 case SCF_ERROR_INVALID_ARGUMENT: 7343 case SCF_ERROR_NOT_BOUND: 7344 case SCF_ERROR_NO_RESOURCES: 7345 case SCF_ERROR_INTERNAL: 7346 bad_error("_scf_set_annotation", scf_error()); 7347 /* NOTREACHED */ 7348 7349 default: 7350 /* 7351 * Do not abort apply operation because of 7352 * inability to create annotation audit event. 7353 */ 7354 warn(gettext("_scf_set_annotation() unexpectedly " 7355 "failed with return code of %d\n"), scf_error()); 7356 break; 7357 } 7358 } 7359 7360 for (svc = uu_list_first(bndl->sc_bundle_services); 7361 svc != NULL; 7362 svc = uu_list_next(bndl->sc_bundle_services, svc)) { 7363 if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) { 7364 switch (scf_error()) { 7365 case SCF_ERROR_NOT_FOUND: 7366 if (g_verbose) 7367 warn(gettext("Ignoring nonexistent " 7368 "service %s.\n"), svc->sc_name); 7369 continue; 7370 7371 default: 7372 scfdie(); 7373 } 7374 } 7375 7376 for (inst = uu_list_first( 7377 svc->sc_u.sc_service.sc_service_instances); 7378 inst != NULL; 7379 inst = uu_list_next( 7380 svc->sc_u.sc_service.sc_service_instances, inst)) { 7381 if (scf_service_get_instance(rsvc, inst->sc_name, 7382 rinst) != 0) { 7383 switch (scf_error()) { 7384 case SCF_ERROR_NOT_FOUND: 7385 if (g_verbose) 7386 warn(gettext("Ignoring " 7387 "nonexistant instance " 7388 "%s:%s.\n"), 7389 inst->sc_parent->sc_name, 7390 inst->sc_name); 7391 continue; 7392 7393 default: 7394 scfdie(); 7395 } 7396 } 7397 7398 r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst, 7399 SCI_FORCE | SCI_KEEP); 7400 switch (r) { 7401 case 0: 7402 if (g_verbose) 7403 warn(gettext("%s updated.\n"), 7404 inst->sc_fmri); 7405 break; 7406 7407 case ECONNABORTED: 7408 warn(gettext("Could not update %s " 7409 "(repository connection broken).\n"), 7410 inst->sc_fmri); 7411 goto out; 7412 7413 case ENOMEM: 7414 warn(gettext("Could not update %s " 7415 "(out of memory).\n"), inst->sc_fmri); 7416 goto out; 7417 7418 case ENOSPC: 7419 warn(gettext("Could not update %s " 7420 "(repository server out of resources).\n"), 7421 inst->sc_fmri); 7422 goto out; 7423 7424 case ECANCELED: 7425 warn(gettext( 7426 "Could not update %s (deleted).\n"), 7427 inst->sc_fmri); 7428 break; 7429 7430 case EPERM: 7431 case EINVAL: 7432 case EBUSY: 7433 break; 7434 7435 case EROFS: 7436 warn(gettext("Could not update %s " 7437 "(repository read-only).\n"), 7438 inst->sc_fmri); 7439 goto out; 7440 7441 case EACCES: 7442 warn(gettext("Could not update %s " 7443 "(backend access denied).\n"), 7444 inst->sc_fmri); 7445 break; 7446 7447 case EEXIST: 7448 default: 7449 bad_error("lscf_import_instance_pgs", r); 7450 } 7451 } 7452 } 7453 7454 out: 7455 if (annotation_set) { 7456 /* Remove security audit annotation strings. */ 7457 (void) _scf_set_annotation(g_hndl, NULL, NULL); 7458 } 7459 7460 scf_transaction_destroy(imp_tx); 7461 imp_tx = NULL; 7462 scf_pg_destroy(imp_pg); 7463 imp_pg = NULL; 7464 7465 scf_instance_destroy(rinst); 7466 scf_service_destroy(rsvc); 7467 scf_scope_destroy(rscope); 7468 return (0); 7469 } 7470 7471 7472 /* 7473 * Export. These functions create and output an XML tree of a service 7474 * description from the repository. This is largely the inverse of 7475 * lxml_get_bundle() in svccfg_xml.c, but with some kickers: 7476 * 7477 * - We must include any properties which are not represented specifically by 7478 * a service manifest, e.g., properties created by an admin post-import. To 7479 * do so we'll iterate through all properties and deal with each 7480 * apropriately. 7481 * 7482 * - Children of services and instances must must be in the order set by the 7483 * DTD, but we iterate over the properties in undefined order. The elements 7484 * are not easily (or efficiently) sortable by name. Since there's a fixed 7485 * number of classes of them, however, we'll keep the classes separate and 7486 * assemble them in order. 7487 */ 7488 7489 /* 7490 * Convenience function to handle xmlSetProp errors (and type casting). 7491 */ 7492 static void 7493 safe_setprop(xmlNodePtr n, const char *name, const char *val) 7494 { 7495 if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL) 7496 uu_die(gettext("Could not set XML property.\n")); 7497 } 7498 7499 /* 7500 * Convenience function to set an XML attribute to the single value of an 7501 * astring property. If the value happens to be the default, don't set the 7502 * attribute. "dval" should be the default value supplied by the DTD, or 7503 * NULL for no default. 7504 */ 7505 static int 7506 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n, 7507 const char *name, const char *dval) 7508 { 7509 scf_value_t *val; 7510 ssize_t len; 7511 char *str; 7512 7513 val = scf_value_create(g_hndl); 7514 if (val == NULL) 7515 scfdie(); 7516 7517 if (prop_get_val(prop, val) != 0) { 7518 scf_value_destroy(val); 7519 return (-1); 7520 } 7521 7522 len = scf_value_get_as_string(val, NULL, 0); 7523 if (len < 0) 7524 scfdie(); 7525 7526 str = safe_malloc(len + 1); 7527 7528 if (scf_value_get_as_string(val, str, len + 1) < 0) 7529 scfdie(); 7530 7531 scf_value_destroy(val); 7532 7533 if (dval == NULL || strcmp(str, dval) != 0) 7534 safe_setprop(n, name, str); 7535 7536 free(str); 7537 7538 return (0); 7539 } 7540 7541 /* 7542 * As above, but the attribute is always set. 7543 */ 7544 static int 7545 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name) 7546 { 7547 return (set_attr_from_prop_default(prop, n, name, NULL)); 7548 } 7549 7550 /* 7551 * Dump the given document onto f, with "'s replaced by ''s. 7552 */ 7553 static int 7554 write_service_bundle(xmlDocPtr doc, FILE *f) 7555 { 7556 xmlChar *mem; 7557 int sz, i; 7558 7559 mem = NULL; 7560 xmlDocDumpFormatMemory(doc, &mem, &sz, 1); 7561 7562 if (mem == NULL) { 7563 semerr(gettext("Could not dump XML tree.\n")); 7564 return (-1); 7565 } 7566 7567 /* 7568 * Fortunately libxml produces " instead of ", so we can blindly 7569 * replace all " with '. Cursed libxml2! Why must you #ifdef out the 7570 * ' code?! 7571 */ 7572 for (i = 0; i < sz; ++i) { 7573 char c = (char)mem[i]; 7574 7575 if (c == '"') 7576 (void) fputc('\'', f); 7577 else if (c == '\'') 7578 (void) fwrite("'", sizeof ("'") - 1, 1, f); 7579 else 7580 (void) fputc(c, f); 7581 } 7582 7583 return (0); 7584 } 7585 7586 /* 7587 * Create the DOM elements in elts necessary to (generically) represent prop 7588 * (i.e., a property or propval element). If the name of the property is 7589 * known, it should be passed as name_arg. Otherwise, pass NULL. 7590 */ 7591 static void 7592 export_property(scf_property_t *prop, const char *name_arg, 7593 struct pg_elts *elts, int flags) 7594 { 7595 const char *type; 7596 scf_error_t err = 0; 7597 xmlNodePtr pnode, lnode; 7598 char *lnname; 7599 int ret; 7600 7601 /* name */ 7602 if (name_arg != NULL) { 7603 (void) strcpy(exp_str, name_arg); 7604 } else { 7605 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0) 7606 scfdie(); 7607 } 7608 7609 /* type */ 7610 type = prop_to_typestr(prop); 7611 if (type == NULL) 7612 uu_die(gettext("Can't export property %s: unknown type.\n"), 7613 exp_str); 7614 7615 /* If we're exporting values, and there's just one, export it here. */ 7616 if (!(flags & SCE_ALL_VALUES)) 7617 goto empty; 7618 7619 if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) { 7620 xmlNodePtr n; 7621 7622 /* Single value, so use propval */ 7623 n = xmlNewNode(NULL, (xmlChar *)"propval"); 7624 if (n == NULL) 7625 uu_die(emsg_create_xml); 7626 7627 safe_setprop(n, name_attr, exp_str); 7628 safe_setprop(n, type_attr, type); 7629 7630 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 7631 scfdie(); 7632 safe_setprop(n, value_attr, exp_str); 7633 7634 if (elts->propvals == NULL) 7635 elts->propvals = n; 7636 else 7637 (void) xmlAddSibling(elts->propvals, n); 7638 7639 return; 7640 } 7641 7642 err = scf_error(); 7643 7644 if (err == SCF_ERROR_PERMISSION_DENIED) { 7645 semerr(emsg_permission_denied); 7646 return; 7647 } 7648 7649 if (err != SCF_ERROR_CONSTRAINT_VIOLATED && 7650 err != SCF_ERROR_NOT_FOUND && 7651 err != SCF_ERROR_PERMISSION_DENIED) 7652 scfdie(); 7653 7654 empty: 7655 /* Multiple (or no) values, so use property */ 7656 pnode = xmlNewNode(NULL, (xmlChar *)"property"); 7657 if (pnode == NULL) 7658 uu_die(emsg_create_xml); 7659 7660 safe_setprop(pnode, name_attr, exp_str); 7661 safe_setprop(pnode, type_attr, type); 7662 7663 if (err == SCF_ERROR_CONSTRAINT_VIOLATED) { 7664 lnname = uu_msprintf("%s_list", type); 7665 if (lnname == NULL) 7666 uu_die(gettext("Could not create string")); 7667 7668 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL); 7669 if (lnode == NULL) 7670 uu_die(emsg_create_xml); 7671 7672 uu_free(lnname); 7673 7674 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS) 7675 scfdie(); 7676 7677 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 7678 1) { 7679 xmlNodePtr vn; 7680 7681 vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node", 7682 NULL); 7683 if (vn == NULL) 7684 uu_die(emsg_create_xml); 7685 7686 if (scf_value_get_as_string(exp_val, exp_str, 7687 exp_str_sz) < 0) 7688 scfdie(); 7689 safe_setprop(vn, value_attr, exp_str); 7690 } 7691 if (ret != 0) 7692 scfdie(); 7693 } 7694 7695 if (elts->properties == NULL) 7696 elts->properties = pnode; 7697 else 7698 (void) xmlAddSibling(elts->properties, pnode); 7699 } 7700 7701 /* 7702 * Add a property_group element for this property group to elts. 7703 */ 7704 static void 7705 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags) 7706 { 7707 xmlNodePtr n; 7708 struct pg_elts elts; 7709 int ret; 7710 boolean_t read_protected; 7711 7712 n = xmlNewNode(NULL, (xmlChar *)"property_group"); 7713 7714 /* name */ 7715 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7716 scfdie(); 7717 safe_setprop(n, name_attr, exp_str); 7718 7719 /* type */ 7720 if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0) 7721 scfdie(); 7722 safe_setprop(n, type_attr, exp_str); 7723 7724 /* properties */ 7725 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7726 scfdie(); 7727 7728 (void) memset(&elts, 0, sizeof (elts)); 7729 7730 /* 7731 * If this property group is not read protected, we always want to 7732 * output all the values. Otherwise, we only output the values if the 7733 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a). 7734 */ 7735 if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS) 7736 scfdie(); 7737 7738 if (!read_protected) 7739 flags |= SCE_ALL_VALUES; 7740 7741 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7742 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7743 scfdie(); 7744 7745 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 7746 xmlNodePtr m; 7747 7748 m = xmlNewNode(NULL, (xmlChar *)"stability"); 7749 if (m == NULL) 7750 uu_die(emsg_create_xml); 7751 7752 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 7753 elts.stability = m; 7754 continue; 7755 } 7756 7757 xmlFreeNode(m); 7758 } 7759 7760 export_property(exp_prop, NULL, &elts, flags); 7761 } 7762 if (ret == -1) 7763 scfdie(); 7764 7765 (void) xmlAddChild(n, elts.stability); 7766 (void) xmlAddChildList(n, elts.propvals); 7767 (void) xmlAddChildList(n, elts.properties); 7768 7769 if (eelts->property_groups == NULL) 7770 eelts->property_groups = n; 7771 else 7772 (void) xmlAddSibling(eelts->property_groups, n); 7773 } 7774 7775 /* 7776 * Create an XML node representing the dependency described by the given 7777 * property group and put it in eelts. Unless the dependency is not valid, in 7778 * which case create a generic property_group element which represents it and 7779 * put it in eelts. 7780 */ 7781 static void 7782 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts) 7783 { 7784 xmlNodePtr n; 7785 int err = 0, ret; 7786 struct pg_elts elts; 7787 7788 n = xmlNewNode(NULL, (xmlChar *)"dependency"); 7789 if (n == NULL) 7790 uu_die(emsg_create_xml); 7791 7792 /* 7793 * If the external flag is present, skip this dependency because it 7794 * should have been created by another manifest. 7795 */ 7796 if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) { 7797 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 7798 prop_get_val(exp_prop, exp_val) == 0) { 7799 uint8_t b; 7800 7801 if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS) 7802 scfdie(); 7803 7804 if (b) 7805 return; 7806 } 7807 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 7808 scfdie(); 7809 7810 /* Get the required attributes. */ 7811 7812 /* name */ 7813 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 7814 scfdie(); 7815 safe_setprop(n, name_attr, exp_str); 7816 7817 /* grouping */ 7818 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 7819 set_attr_from_prop(exp_prop, n, "grouping") != 0) 7820 err = 1; 7821 7822 /* restart_on */ 7823 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 7824 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 7825 err = 1; 7826 7827 /* type */ 7828 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 7829 set_attr_from_prop(exp_prop, n, type_attr) != 0) 7830 err = 1; 7831 7832 /* 7833 * entities: Not required, but if we create no children, it will be 7834 * created as empty on import, so fail if it's missing. 7835 */ 7836 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 7837 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) { 7838 scf_iter_t *eiter; 7839 int ret2; 7840 7841 eiter = scf_iter_create(g_hndl); 7842 if (eiter == NULL) 7843 scfdie(); 7844 7845 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS) 7846 scfdie(); 7847 7848 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) { 7849 xmlNodePtr ch; 7850 7851 if (scf_value_get_astring(exp_val, exp_str, 7852 exp_str_sz) < 0) 7853 scfdie(); 7854 7855 /* 7856 * service_fmri's must be first, so we can add them 7857 * here. 7858 */ 7859 ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", 7860 NULL); 7861 if (ch == NULL) 7862 uu_die(emsg_create_xml); 7863 7864 safe_setprop(ch, value_attr, exp_str); 7865 } 7866 if (ret2 == -1) 7867 scfdie(); 7868 7869 scf_iter_destroy(eiter); 7870 } else 7871 err = 1; 7872 7873 if (err) { 7874 xmlFreeNode(n); 7875 7876 export_pg(pg, eelts, 0); 7877 7878 return; 7879 } 7880 7881 /* Iterate through the properties & handle each. */ 7882 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 7883 scfdie(); 7884 7885 (void) memset(&elts, 0, sizeof (elts)); 7886 7887 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 7888 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 7889 scfdie(); 7890 7891 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 7892 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 7893 strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 7894 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 7895 continue; 7896 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 7897 xmlNodePtr m; 7898 7899 m = xmlNewNode(NULL, (xmlChar *)"stability"); 7900 if (m == NULL) 7901 uu_die(emsg_create_xml); 7902 7903 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 7904 elts.stability = m; 7905 continue; 7906 } 7907 7908 xmlFreeNode(m); 7909 } 7910 7911 export_property(exp_prop, exp_str, &elts, 0); 7912 } 7913 if (ret == -1) 7914 scfdie(); 7915 7916 (void) xmlAddChild(n, elts.stability); 7917 (void) xmlAddChildList(n, elts.propvals); 7918 (void) xmlAddChildList(n, elts.properties); 7919 7920 if (eelts->dependencies == NULL) 7921 eelts->dependencies = n; 7922 else 7923 (void) xmlAddSibling(eelts->dependencies, n); 7924 } 7925 7926 static xmlNodePtr 7927 export_method_environment(scf_propertygroup_t *pg) 7928 { 7929 xmlNodePtr env; 7930 int ret; 7931 int children = 0; 7932 7933 if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0) 7934 return (NULL); 7935 7936 env = xmlNewNode(NULL, (xmlChar *)"method_environment"); 7937 if (env == NULL) 7938 uu_die(emsg_create_xml); 7939 7940 if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0) 7941 scfdie(); 7942 7943 if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS) 7944 scfdie(); 7945 7946 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) { 7947 xmlNodePtr ev; 7948 char *cp; 7949 7950 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0) 7951 scfdie(); 7952 7953 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) { 7954 warn(gettext("Invalid environment variable \"%s\".\n"), 7955 exp_str); 7956 continue; 7957 } else if (strncmp(exp_str, "SMF_", 4) == 0) { 7958 warn(gettext("Invalid environment variable \"%s\"; " 7959 "\"SMF_\" prefix is reserved.\n"), exp_str); 7960 continue; 7961 } 7962 7963 *cp = '\0'; 7964 cp++; 7965 7966 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL); 7967 if (ev == NULL) 7968 uu_die(emsg_create_xml); 7969 7970 safe_setprop(ev, name_attr, exp_str); 7971 safe_setprop(ev, value_attr, cp); 7972 children++; 7973 } 7974 7975 if (ret != 0) 7976 scfdie(); 7977 7978 if (children == 0) { 7979 xmlFreeNode(env); 7980 return (NULL); 7981 } 7982 7983 return (env); 7984 } 7985 7986 /* 7987 * As above, but for a method property group. 7988 */ 7989 static void 7990 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts) 7991 { 7992 xmlNodePtr n, env; 7993 char *str; 7994 int err = 0, nonenv, ret; 7995 uint8_t use_profile; 7996 struct pg_elts elts; 7997 xmlNodePtr ctxt; 7998 7999 n = xmlNewNode(NULL, (xmlChar *)"exec_method"); 8000 8001 /* Get the required attributes. */ 8002 8003 /* name */ 8004 if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0) 8005 scfdie(); 8006 safe_setprop(n, name_attr, exp_str); 8007 8008 /* type */ 8009 if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 || 8010 set_attr_from_prop(exp_prop, n, type_attr) != 0) 8011 err = 1; 8012 8013 /* exec */ 8014 if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 || 8015 set_attr_from_prop(exp_prop, n, "exec") != 0) 8016 err = 1; 8017 8018 /* timeout */ 8019 if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 && 8020 prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 && 8021 prop_get_val(exp_prop, exp_val) == 0) { 8022 uint64_t c; 8023 8024 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS) 8025 scfdie(); 8026 8027 str = uu_msprintf("%llu", c); 8028 if (str == NULL) 8029 uu_die(gettext("Could not create string")); 8030 8031 safe_setprop(n, "timeout_seconds", str); 8032 free(str); 8033 } else 8034 err = 1; 8035 8036 if (err) { 8037 xmlFreeNode(n); 8038 8039 export_pg(pg, eelts, 0); 8040 8041 return; 8042 } 8043 8044 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context"); 8045 if (ctxt == NULL) 8046 uu_die(emsg_create_xml); 8047 8048 /* 8049 * If we're going to have a method_context child, we need to know 8050 * before we iterate through the properties. Since method_context's 8051 * are optional, we don't want to complain about any properties 8052 * missing if none of them are there. Thus we can't use the 8053 * convenience functions. 8054 */ 8055 nonenv = 8056 scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) == 8057 SCF_SUCCESS || 8058 scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) == 8059 SCF_SUCCESS || 8060 scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) == 8061 SCF_SUCCESS || 8062 scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) == 8063 SCF_SUCCESS; 8064 8065 if (nonenv) { 8066 /* 8067 * We only want to complain about profile or credential 8068 * properties if we will use them. To determine that we must 8069 * examine USE_PROFILE. 8070 */ 8071 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 && 8072 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8073 prop_get_val(exp_prop, exp_val) == 0) { 8074 if (scf_value_get_boolean(exp_val, &use_profile) != 8075 SCF_SUCCESS) 8076 scfdie(); 8077 } else 8078 /* 8079 * USE_PROFILE is misconfigured. Since we should have 8080 * complained just now, we don't want to complain 8081 * about any of the other properties, so don't look 8082 * for them. 8083 */ 8084 nonenv = 0; 8085 } 8086 8087 if (nonenv) { 8088 8089 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) != 8090 0 || 8091 set_attr_from_prop_default(exp_prop, ctxt, 8092 "working_directory", ":default") != 0) 8093 err = 1; 8094 8095 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) != 0 || 8096 set_attr_from_prop_default(exp_prop, ctxt, "project", 8097 ":default") != 0) 8098 err = 1; 8099 8100 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) != 8101 0 || 8102 set_attr_from_prop_default(exp_prop, ctxt, 8103 "resource_pool", ":default") != 0) 8104 err = 1; 8105 8106 if (use_profile) { 8107 xmlNodePtr prof; 8108 8109 prof = xmlNewChild(ctxt, NULL, 8110 (xmlChar *)"method_profile", NULL); 8111 if (prof == NULL) 8112 uu_die(emsg_create_xml); 8113 8114 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, exp_prop) != 8115 0 || set_attr_from_prop(exp_prop, prof, 8116 name_attr) != 0) 8117 err = 1; 8118 } else { 8119 xmlNodePtr cred; 8120 8121 cred = xmlNewChild(ctxt, NULL, 8122 (xmlChar *)"method_credential", NULL); 8123 if (cred == NULL) 8124 uu_die(emsg_create_xml); 8125 8126 if (pg_get_prop(pg, SCF_PROPERTY_USER, exp_prop) != 0 || 8127 set_attr_from_prop(exp_prop, cred, "user") != 0) 8128 err = 1; 8129 8130 if (pg_get_prop(pg, SCF_PROPERTY_GROUP, exp_prop) != 8131 0 || 8132 set_attr_from_prop_default(exp_prop, cred, 8133 "group", ":default") != 0) 8134 err = 1; 8135 8136 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS, 8137 exp_prop) != 0 || 8138 set_attr_from_prop_default(exp_prop, cred, 8139 "supp_groups", ":default") != 0) 8140 err = 1; 8141 8142 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES, 8143 exp_prop) != 0 || 8144 set_attr_from_prop_default(exp_prop, cred, 8145 "privileges", ":default") != 0) 8146 err = 1; 8147 8148 if (pg_get_prop(pg, SCF_PROPERTY_LIMIT_PRIVILEGES, 8149 exp_prop) != 0 || 8150 set_attr_from_prop_default(exp_prop, cred, 8151 "limit_privileges", ":default") != 0) 8152 err = 1; 8153 } 8154 } 8155 8156 if ((env = export_method_environment(pg)) != NULL) 8157 (void) xmlAddChild(ctxt, env); 8158 8159 if (env != NULL || err == 0) 8160 (void) xmlAddChild(n, ctxt); 8161 else 8162 xmlFreeNode(ctxt); 8163 8164 nonenv = (err == 0); 8165 8166 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8167 scfdie(); 8168 8169 (void) memset(&elts, 0, sizeof (elts)); 8170 8171 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8172 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8173 scfdie(); 8174 8175 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 || 8176 strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 || 8177 strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) { 8178 continue; 8179 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8180 xmlNodePtr m; 8181 8182 m = xmlNewNode(NULL, (xmlChar *)"stability"); 8183 if (m == NULL) 8184 uu_die(emsg_create_xml); 8185 8186 if (set_attr_from_prop(exp_prop, m, value_attr) == 0) { 8187 elts.stability = m; 8188 continue; 8189 } 8190 8191 xmlFreeNode(m); 8192 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 8193 0 || 8194 strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 || 8195 strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 || 8196 strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8197 if (nonenv) 8198 continue; 8199 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 || 8200 strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 || 8201 strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 || 8202 strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 || 8203 strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) { 8204 if (nonenv && !use_profile) 8205 continue; 8206 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8207 if (nonenv && use_profile) 8208 continue; 8209 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) { 8210 if (env != NULL) 8211 continue; 8212 } 8213 8214 export_property(exp_prop, exp_str, &elts, 0); 8215 } 8216 if (ret == -1) 8217 scfdie(); 8218 8219 (void) xmlAddChild(n, elts.stability); 8220 (void) xmlAddChildList(n, elts.propvals); 8221 (void) xmlAddChildList(n, elts.properties); 8222 8223 if (eelts->exec_methods == NULL) 8224 eelts->exec_methods = n; 8225 else 8226 (void) xmlAddSibling(eelts->exec_methods, n); 8227 } 8228 8229 static void 8230 export_pg_elts(struct pg_elts *elts, const char *name, const char *type, 8231 struct entity_elts *eelts) 8232 { 8233 xmlNodePtr pgnode; 8234 8235 pgnode = xmlNewNode(NULL, (xmlChar *)"property_group"); 8236 if (pgnode == NULL) 8237 uu_die(emsg_create_xml); 8238 8239 safe_setprop(pgnode, name_attr, name); 8240 safe_setprop(pgnode, type_attr, type); 8241 8242 (void) xmlAddChildList(pgnode, elts->propvals); 8243 (void) xmlAddChildList(pgnode, elts->properties); 8244 8245 if (eelts->property_groups == NULL) 8246 eelts->property_groups = pgnode; 8247 else 8248 (void) xmlAddSibling(eelts->property_groups, pgnode); 8249 } 8250 8251 /* 8252 * Process the general property group for a service. This is the one with the 8253 * goodies. 8254 */ 8255 static void 8256 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts) 8257 { 8258 struct pg_elts elts; 8259 int ret; 8260 8261 /* 8262 * In case there are properties which don't correspond to child 8263 * entities of the service entity, we'll set up a pg_elts structure to 8264 * put them in. 8265 */ 8266 (void) memset(&elts, 0, sizeof (elts)); 8267 8268 /* Walk the properties, looking for special ones. */ 8269 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8270 scfdie(); 8271 8272 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8273 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8274 scfdie(); 8275 8276 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) { 8277 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8278 prop_get_val(exp_prop, exp_val) == 0) { 8279 uint8_t b; 8280 8281 if (scf_value_get_boolean(exp_val, &b) != 8282 SCF_SUCCESS) 8283 scfdie(); 8284 8285 if (b) { 8286 selts->single_instance = 8287 xmlNewNode(NULL, 8288 (xmlChar *)"single_instance"); 8289 if (selts->single_instance == NULL) 8290 uu_die(emsg_create_xml); 8291 } 8292 8293 continue; 8294 } 8295 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8296 xmlNodePtr rnode, sfnode; 8297 8298 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8299 if (rnode == NULL) 8300 uu_die(emsg_create_xml); 8301 8302 sfnode = xmlNewChild(rnode, NULL, 8303 (xmlChar *)"service_fmri", NULL); 8304 if (sfnode == NULL) 8305 uu_die(emsg_create_xml); 8306 8307 if (set_attr_from_prop(exp_prop, sfnode, 8308 value_attr) == 0) { 8309 selts->restarter = rnode; 8310 continue; 8311 } 8312 8313 xmlFreeNode(rnode); 8314 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) == 8315 0) { 8316 xmlNodePtr s; 8317 8318 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8319 if (s == NULL) 8320 uu_die(emsg_create_xml); 8321 8322 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8323 selts->stability = s; 8324 continue; 8325 } 8326 8327 xmlFreeNode(s); 8328 } 8329 8330 export_property(exp_prop, exp_str, &elts, 0); 8331 } 8332 if (ret == -1) 8333 scfdie(); 8334 8335 if (elts.propvals != NULL || elts.properties != NULL) 8336 export_pg_elts(&elts, scf_pg_general, scf_group_framework, 8337 selts); 8338 } 8339 8340 static void 8341 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts) 8342 { 8343 xmlNodePtr n, prof, cred, env; 8344 uint8_t use_profile; 8345 int ret, err = 0; 8346 8347 n = xmlNewNode(NULL, (xmlChar *)"method_context"); 8348 8349 env = export_method_environment(pg); 8350 8351 /* Need to know whether we'll use a profile or not. */ 8352 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) != 0 || 8353 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) != 0 || 8354 prop_get_val(exp_prop, exp_val) != 0) { 8355 if (env != NULL) { 8356 (void) xmlAddChild(n, env); 8357 elts->method_context = n; 8358 } else { 8359 xmlFreeNode(n); 8360 export_pg(pg, elts, 0); 8361 } 8362 return; 8363 } 8364 8365 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS) 8366 scfdie(); 8367 8368 if (use_profile) 8369 prof = xmlNewChild(n, NULL, (xmlChar *)"method_profile", NULL); 8370 else 8371 cred = 8372 xmlNewChild(n, NULL, (xmlChar *)"method_credential", NULL); 8373 8374 if (env != NULL) 8375 (void) xmlAddChild(n, env); 8376 8377 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8378 scfdie(); 8379 8380 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8381 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8382 scfdie(); 8383 8384 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) { 8385 if (set_attr_from_prop(exp_prop, n, 8386 "working_directory") != 0) 8387 err = 1; 8388 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) { 8389 if (set_attr_from_prop(exp_prop, n, "project") != 0) 8390 err = 1; 8391 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) { 8392 if (set_attr_from_prop(exp_prop, n, 8393 "resource_pool") != 0) 8394 err = 1; 8395 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) { 8396 /* EMPTY */ 8397 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) { 8398 if (use_profile || 8399 set_attr_from_prop(exp_prop, cred, "user") != 0) 8400 err = 1; 8401 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) { 8402 if (use_profile || 8403 set_attr_from_prop(exp_prop, cred, "group") != 0) 8404 err = 1; 8405 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) { 8406 if (use_profile || set_attr_from_prop(exp_prop, cred, 8407 "supp_groups") != 0) 8408 err = 1; 8409 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) { 8410 if (use_profile || set_attr_from_prop(exp_prop, cred, 8411 "privileges") != 0) 8412 err = 1; 8413 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 8414 0) { 8415 if (use_profile || set_attr_from_prop(exp_prop, cred, 8416 "limit_privileges") != 0) 8417 err = 1; 8418 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) { 8419 if (!use_profile || set_attr_from_prop(exp_prop, 8420 prof, name_attr) != 0) 8421 err = 1; 8422 } else { 8423 /* Can't have generic properties in method_context's */ 8424 err = 1; 8425 } 8426 } 8427 if (ret == -1) 8428 scfdie(); 8429 8430 if (err && env == NULL) { 8431 xmlFreeNode(n); 8432 export_pg(pg, elts, 0); 8433 return; 8434 } 8435 8436 elts->method_context = n; 8437 } 8438 8439 /* 8440 * Given a dependency property group in the tfmri entity (target fmri), return 8441 * a dependent element which represents it. 8442 */ 8443 static xmlNodePtr 8444 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri) 8445 { 8446 uint8_t b; 8447 xmlNodePtr n, sf; 8448 int err = 0, ret; 8449 struct pg_elts pgelts; 8450 8451 /* 8452 * If external isn't set to true then exporting the service will 8453 * export this as a normal dependency, so we should stop to avoid 8454 * duplication. 8455 */ 8456 if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 || 8457 scf_property_get_value(exp_prop, exp_val) != 0 || 8458 scf_value_get_boolean(exp_val, &b) != 0 || !b) { 8459 if (g_verbose) { 8460 warn(gettext("Dependent \"%s\" cannot be exported " 8461 "properly because the \"%s\" property of the " 8462 "\"%s\" dependency of %s is not set to true.\n"), 8463 name, scf_property_external, name, tfmri); 8464 } 8465 8466 return (NULL); 8467 } 8468 8469 n = xmlNewNode(NULL, (xmlChar *)"dependent"); 8470 if (n == NULL) 8471 uu_die(emsg_create_xml); 8472 8473 safe_setprop(n, name_attr, name); 8474 8475 /* Get the required attributes */ 8476 if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 || 8477 set_attr_from_prop(exp_prop, n, "restart_on") != 0) 8478 err = 1; 8479 8480 if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 || 8481 set_attr_from_prop(exp_prop, n, "grouping") != 0) 8482 err = 1; 8483 8484 if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 && 8485 prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 && 8486 prop_get_val(exp_prop, exp_val) == 0) { 8487 /* EMPTY */ 8488 } else 8489 err = 1; 8490 8491 if (err) { 8492 xmlFreeNode(n); 8493 return (NULL); 8494 } 8495 8496 sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL); 8497 if (sf == NULL) 8498 uu_die(emsg_create_xml); 8499 8500 safe_setprop(sf, value_attr, tfmri); 8501 8502 /* 8503 * Now add elements for the other properties. 8504 */ 8505 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8506 scfdie(); 8507 8508 (void) memset(&pgelts, 0, sizeof (pgelts)); 8509 8510 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8511 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8512 scfdie(); 8513 8514 if (strcmp(exp_str, scf_property_external) == 0 || 8515 strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 || 8516 strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 || 8517 strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) { 8518 continue; 8519 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) { 8520 if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 && 8521 prop_get_val(exp_prop, exp_val) == 0) { 8522 char type[sizeof ("service") + 1]; 8523 8524 if (scf_value_get_astring(exp_val, type, 8525 sizeof (type)) < 0) 8526 scfdie(); 8527 8528 if (strcmp(type, "service") == 0) 8529 continue; 8530 } 8531 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) { 8532 xmlNodePtr s; 8533 8534 s = xmlNewNode(NULL, (xmlChar *)"stability"); 8535 if (s == NULL) 8536 uu_die(emsg_create_xml); 8537 8538 if (set_attr_from_prop(exp_prop, s, value_attr) == 0) { 8539 pgelts.stability = s; 8540 continue; 8541 } 8542 8543 xmlFreeNode(s); 8544 } 8545 8546 export_property(exp_prop, exp_str, &pgelts, 0); 8547 } 8548 if (ret == -1) 8549 scfdie(); 8550 8551 (void) xmlAddChild(n, pgelts.stability); 8552 (void) xmlAddChildList(n, pgelts.propvals); 8553 (void) xmlAddChildList(n, pgelts.properties); 8554 8555 return (n); 8556 } 8557 8558 static void 8559 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts) 8560 { 8561 scf_propertygroup_t *opg; 8562 scf_iter_t *iter; 8563 char *type, *fmri; 8564 int ret; 8565 struct pg_elts pgelts; 8566 xmlNodePtr n; 8567 scf_error_t serr; 8568 8569 if ((opg = scf_pg_create(g_hndl)) == NULL || 8570 (iter = scf_iter_create(g_hndl)) == NULL) 8571 scfdie(); 8572 8573 /* Can't use exp_prop_iter due to export_dependent(). */ 8574 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 8575 scfdie(); 8576 8577 type = safe_malloc(max_scf_pg_type_len + 1); 8578 8579 /* Get an extra byte so we can tell if values are too long. */ 8580 fmri = safe_malloc(max_scf_fmri_len + 2); 8581 8582 (void) memset(&pgelts, 0, sizeof (pgelts)); 8583 8584 while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) { 8585 void *entity; 8586 int isservice; 8587 scf_type_t ty; 8588 8589 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS) 8590 scfdie(); 8591 8592 if ((ty != SCF_TYPE_ASTRING && 8593 prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) || 8594 prop_get_val(exp_prop, exp_val) != 0) { 8595 export_property(exp_prop, NULL, &pgelts, 0); 8596 continue; 8597 } 8598 8599 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8600 scfdie(); 8601 8602 if (scf_value_get_astring(exp_val, fmri, 8603 max_scf_fmri_len + 2) < 0) 8604 scfdie(); 8605 8606 /* Look for a dependency group in the target fmri. */ 8607 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 8608 switch (serr) { 8609 case SCF_ERROR_NONE: 8610 break; 8611 8612 case SCF_ERROR_NO_MEMORY: 8613 uu_die(gettext("Out of memory.\n")); 8614 /* NOTREACHED */ 8615 8616 case SCF_ERROR_INVALID_ARGUMENT: 8617 if (g_verbose) { 8618 if (scf_property_to_fmri(exp_prop, fmri, 8619 max_scf_fmri_len + 2) < 0) 8620 scfdie(); 8621 8622 warn(gettext("The value of %s is not a valid " 8623 "FMRI.\n"), fmri); 8624 } 8625 8626 export_property(exp_prop, exp_str, &pgelts, 0); 8627 continue; 8628 8629 case SCF_ERROR_CONSTRAINT_VIOLATED: 8630 if (g_verbose) { 8631 if (scf_property_to_fmri(exp_prop, fmri, 8632 max_scf_fmri_len + 2) < 0) 8633 scfdie(); 8634 8635 warn(gettext("The value of %s does not specify " 8636 "a service or an instance.\n"), fmri); 8637 } 8638 8639 export_property(exp_prop, exp_str, &pgelts, 0); 8640 continue; 8641 8642 case SCF_ERROR_NOT_FOUND: 8643 if (g_verbose) { 8644 if (scf_property_to_fmri(exp_prop, fmri, 8645 max_scf_fmri_len + 2) < 0) 8646 scfdie(); 8647 8648 warn(gettext("The entity specified by %s does " 8649 "not exist.\n"), fmri); 8650 } 8651 8652 export_property(exp_prop, exp_str, &pgelts, 0); 8653 continue; 8654 8655 default: 8656 #ifndef NDEBUG 8657 (void) fprintf(stderr, "%s:%d: %s() failed with " 8658 "unexpected error %d.\n", __FILE__, __LINE__, 8659 "fmri_to_entity", serr); 8660 #endif 8661 abort(); 8662 } 8663 8664 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) { 8665 if (scf_error() != SCF_ERROR_NOT_FOUND) 8666 scfdie(); 8667 8668 warn(gettext("Entity %s is missing dependency property " 8669 "group %s.\n"), fmri, exp_str); 8670 8671 export_property(exp_prop, NULL, &pgelts, 0); 8672 continue; 8673 } 8674 8675 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0) 8676 scfdie(); 8677 8678 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) { 8679 if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0) 8680 scfdie(); 8681 8682 warn(gettext("Property group %s is not of " 8683 "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY); 8684 8685 export_property(exp_prop, NULL, &pgelts, 0); 8686 continue; 8687 } 8688 8689 n = export_dependent(opg, exp_str, fmri); 8690 if (n == NULL) 8691 export_property(exp_prop, exp_str, &pgelts, 0); 8692 else { 8693 if (eelts->dependents == NULL) 8694 eelts->dependents = n; 8695 else 8696 (void) xmlAddSibling(eelts->dependents, 8697 n); 8698 } 8699 } 8700 if (ret == -1) 8701 scfdie(); 8702 8703 free(fmri); 8704 free(type); 8705 8706 scf_iter_destroy(iter); 8707 scf_pg_destroy(opg); 8708 8709 if (pgelts.propvals != NULL || pgelts.properties != NULL) 8710 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework, 8711 eelts); 8712 } 8713 8714 static void 8715 make_node(xmlNodePtr *nodep, const char *name) 8716 { 8717 if (*nodep == NULL) { 8718 *nodep = xmlNewNode(NULL, (xmlChar *)name); 8719 if (*nodep == NULL) 8720 uu_die(emsg_create_xml); 8721 } 8722 } 8723 8724 static xmlNodePtr 8725 export_tm_loctext(scf_propertygroup_t *pg, const char *parname) 8726 { 8727 int ret; 8728 xmlNodePtr parent = NULL; 8729 xmlNodePtr loctext = NULL; 8730 8731 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8732 scfdie(); 8733 8734 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8735 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 || 8736 prop_get_val(exp_prop, exp_val) != 0) 8737 continue; 8738 8739 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0) 8740 scfdie(); 8741 8742 make_node(&parent, parname); 8743 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext", 8744 (xmlChar *)exp_str); 8745 if (loctext == NULL) 8746 uu_die(emsg_create_xml); 8747 8748 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8749 scfdie(); 8750 8751 safe_setprop(loctext, "xml:lang", exp_str); 8752 } 8753 8754 if (ret == -1) 8755 scfdie(); 8756 8757 return (parent); 8758 } 8759 8760 static xmlNodePtr 8761 export_tm_manpage(scf_propertygroup_t *pg) 8762 { 8763 xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage"); 8764 if (manpage == NULL) 8765 uu_die(emsg_create_xml); 8766 8767 if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 || 8768 set_attr_from_prop(exp_prop, manpage, "title") != 0 || 8769 pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 || 8770 set_attr_from_prop(exp_prop, manpage, "section") != 0) { 8771 xmlFreeNode(manpage); 8772 return (NULL); 8773 } 8774 8775 if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0) 8776 (void) set_attr_from_prop_default(exp_prop, 8777 manpage, "manpath", ":default"); 8778 8779 return (manpage); 8780 } 8781 8782 static xmlNodePtr 8783 export_tm_doc_link(scf_propertygroup_t *pg) 8784 { 8785 xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link"); 8786 if (doc_link == NULL) 8787 uu_die(emsg_create_xml); 8788 8789 if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 || 8790 set_attr_from_prop(exp_prop, doc_link, "name") != 0 || 8791 pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 || 8792 set_attr_from_prop(exp_prop, doc_link, "uri") != 0) { 8793 xmlFreeNode(doc_link); 8794 return (NULL); 8795 } 8796 return (doc_link); 8797 } 8798 8799 /* 8800 * Process template information for a service or instances. 8801 */ 8802 static void 8803 export_template(scf_propertygroup_t *pg, struct entity_elts *elts, 8804 struct template_elts *telts) 8805 { 8806 size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX); 8807 size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX); 8808 xmlNodePtr child = NULL; 8809 8810 if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0) 8811 scfdie(); 8812 8813 if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) { 8814 telts->common_name = export_tm_loctext(pg, "common_name"); 8815 if (telts->common_name == NULL) 8816 export_pg(pg, elts, 0); 8817 return; 8818 } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) { 8819 telts->description = export_tm_loctext(pg, "description"); 8820 if (telts->description == NULL) 8821 export_pg(pg, elts, 0); 8822 return; 8823 } 8824 8825 if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) { 8826 child = export_tm_manpage(pg); 8827 } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) { 8828 child = export_tm_doc_link(pg); 8829 } 8830 8831 if (child != NULL) { 8832 make_node(&telts->documentation, "documentation"); 8833 (void) xmlAddChild(telts->documentation, child); 8834 } else { 8835 export_pg(pg, elts, 0); 8836 } 8837 } 8838 8839 /* 8840 * Process the general property group for an instance. 8841 */ 8842 static void 8843 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode, 8844 struct entity_elts *elts) 8845 { 8846 uint8_t enabled; 8847 struct pg_elts pgelts; 8848 int ret; 8849 8850 /* enabled */ 8851 if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 && 8852 prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 && 8853 prop_get_val(exp_prop, exp_val) == 0) { 8854 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS) 8855 scfdie(); 8856 } else { 8857 enabled = 0; 8858 } 8859 8860 safe_setprop(inode, enabled_attr, enabled ? true : false); 8861 8862 if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS) 8863 scfdie(); 8864 8865 (void) memset(&pgelts, 0, sizeof (pgelts)); 8866 8867 while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) { 8868 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0) 8869 scfdie(); 8870 8871 if (strcmp(exp_str, scf_property_enabled) == 0) { 8872 continue; 8873 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) { 8874 xmlNodePtr rnode, sfnode; 8875 8876 rnode = xmlNewNode(NULL, (xmlChar *)"restarter"); 8877 if (rnode == NULL) 8878 uu_die(emsg_create_xml); 8879 8880 sfnode = xmlNewChild(rnode, NULL, 8881 (xmlChar *)"service_fmri", NULL); 8882 if (sfnode == NULL) 8883 uu_die(emsg_create_xml); 8884 8885 if (set_attr_from_prop(exp_prop, sfnode, 8886 value_attr) == 0) { 8887 elts->restarter = rnode; 8888 continue; 8889 } 8890 8891 xmlFreeNode(rnode); 8892 } 8893 8894 export_property(exp_prop, exp_str, &pgelts, 0); 8895 } 8896 if (ret == -1) 8897 scfdie(); 8898 8899 if (pgelts.propvals != NULL || pgelts.properties != NULL) 8900 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework, 8901 elts); 8902 } 8903 8904 /* 8905 * Put an instance element for the given instance into selts. 8906 */ 8907 static void 8908 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags) 8909 { 8910 xmlNodePtr n; 8911 boolean_t isdefault; 8912 struct entity_elts elts; 8913 struct template_elts template_elts; 8914 int ret; 8915 8916 n = xmlNewNode(NULL, (xmlChar *)"instance"); 8917 if (n == NULL) 8918 uu_die(emsg_create_xml); 8919 8920 /* name */ 8921 if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0) 8922 scfdie(); 8923 safe_setprop(n, name_attr, exp_str); 8924 isdefault = strcmp(exp_str, "default") == 0; 8925 8926 /* check existance of general pg (since general/enabled is required) */ 8927 if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) { 8928 if (scf_error() != SCF_ERROR_NOT_FOUND) 8929 scfdie(); 8930 8931 if (g_verbose) { 8932 if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0) 8933 scfdie(); 8934 8935 warn(gettext("Instance %s has no general property " 8936 "group; it will be marked disabled.\n"), exp_str); 8937 } 8938 8939 safe_setprop(n, enabled_attr, false); 8940 } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 || 8941 strcmp(exp_str, scf_group_framework) != 0) { 8942 if (g_verbose) { 8943 if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0) 8944 scfdie(); 8945 8946 warn(gettext("Property group %s is not of type " 8947 "framework; the instance will be marked " 8948 "disabled.\n"), exp_str); 8949 } 8950 8951 safe_setprop(n, enabled_attr, false); 8952 } 8953 8954 /* property groups */ 8955 if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0) 8956 scfdie(); 8957 8958 (void) memset(&elts, 0, sizeof (elts)); 8959 (void) memset(&template_elts, 0, sizeof (template_elts)); 8960 8961 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 8962 uint32_t pgflags; 8963 8964 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 8965 scfdie(); 8966 8967 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 8968 continue; 8969 8970 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 8971 scfdie(); 8972 8973 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 8974 export_dependency(exp_pg, &elts); 8975 continue; 8976 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 8977 export_method(exp_pg, &elts); 8978 continue; 8979 } else if (strcmp(exp_str, scf_group_framework) == 0) { 8980 if (scf_pg_get_name(exp_pg, exp_str, 8981 max_scf_name_len + 1) < 0) 8982 scfdie(); 8983 8984 if (strcmp(exp_str, scf_pg_general) == 0) { 8985 export_inst_general(exp_pg, n, &elts); 8986 continue; 8987 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 8988 0) { 8989 export_method_context(exp_pg, &elts); 8990 continue; 8991 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 8992 export_dependents(exp_pg, &elts); 8993 continue; 8994 } 8995 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 8996 export_template(exp_pg, &elts, &template_elts); 8997 continue; 8998 } 8999 9000 /* Ordinary pg. */ 9001 export_pg(exp_pg, &elts, flags); 9002 } 9003 if (ret == -1) 9004 scfdie(); 9005 9006 if (template_elts.common_name != NULL) { 9007 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9008 (void) xmlAddChild(elts.template, template_elts.common_name); 9009 (void) xmlAddChild(elts.template, template_elts.description); 9010 (void) xmlAddChild(elts.template, template_elts.documentation); 9011 } else { 9012 xmlFreeNode(template_elts.description); 9013 xmlFreeNode(template_elts.documentation); 9014 } 9015 9016 if (isdefault && elts.restarter == NULL && 9017 elts.dependencies == NULL && elts.method_context == NULL && 9018 elts.exec_methods == NULL && elts.property_groups == NULL && 9019 elts.template == NULL) { 9020 xmlChar *eval; 9021 9022 /* This is a default instance */ 9023 eval = xmlGetProp(n, (xmlChar *)enabled_attr); 9024 9025 xmlFreeNode(n); 9026 9027 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance"); 9028 if (n == NULL) 9029 uu_die(emsg_create_xml); 9030 9031 safe_setprop(n, enabled_attr, (char *)eval); 9032 xmlFree(eval); 9033 9034 selts->create_default_instance = n; 9035 } else { 9036 /* Assemble the children in order. */ 9037 (void) xmlAddChild(n, elts.restarter); 9038 (void) xmlAddChildList(n, elts.dependencies); 9039 (void) xmlAddChildList(n, elts.dependents); 9040 (void) xmlAddChild(n, elts.method_context); 9041 (void) xmlAddChildList(n, elts.exec_methods); 9042 (void) xmlAddChildList(n, elts.property_groups); 9043 (void) xmlAddChild(n, elts.template); 9044 9045 if (selts->instances == NULL) 9046 selts->instances = n; 9047 else 9048 (void) xmlAddSibling(selts->instances, n); 9049 } 9050 } 9051 9052 /* 9053 * Return a service element for the given service. 9054 */ 9055 static xmlNodePtr 9056 export_service(scf_service_t *svc, int flags) 9057 { 9058 xmlNodePtr snode; 9059 struct entity_elts elts; 9060 struct template_elts template_elts; 9061 int ret; 9062 9063 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9064 if (snode == NULL) 9065 uu_die(emsg_create_xml); 9066 9067 /* Get & set name attribute */ 9068 if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0) 9069 scfdie(); 9070 safe_setprop(snode, name_attr, exp_str); 9071 9072 safe_setprop(snode, type_attr, "service"); 9073 safe_setprop(snode, "version", "0"); 9074 9075 /* Acquire child elements. */ 9076 if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS) 9077 scfdie(); 9078 9079 (void) memset(&elts, 0, sizeof (elts)); 9080 (void) memset(&template_elts, 0, sizeof (template_elts)); 9081 9082 while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) { 9083 uint32_t pgflags; 9084 9085 if (scf_pg_get_flags(exp_pg, &pgflags) != 0) 9086 scfdie(); 9087 9088 if (pgflags & SCF_PG_FLAG_NONPERSISTENT) 9089 continue; 9090 9091 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0) 9092 scfdie(); 9093 9094 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) { 9095 export_dependency(exp_pg, &elts); 9096 continue; 9097 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) { 9098 export_method(exp_pg, &elts); 9099 continue; 9100 } else if (strcmp(exp_str, scf_group_framework) == 0) { 9101 if (scf_pg_get_name(exp_pg, exp_str, 9102 max_scf_name_len + 1) < 0) 9103 scfdie(); 9104 9105 if (strcmp(exp_str, scf_pg_general) == 0) { 9106 export_svc_general(exp_pg, &elts); 9107 continue; 9108 } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) == 9109 0) { 9110 export_method_context(exp_pg, &elts); 9111 continue; 9112 } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) { 9113 export_dependents(exp_pg, &elts); 9114 continue; 9115 } 9116 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) { 9117 export_template(exp_pg, &elts, &template_elts); 9118 continue; 9119 } 9120 9121 export_pg(exp_pg, &elts, flags); 9122 } 9123 if (ret == -1) 9124 scfdie(); 9125 9126 if (template_elts.common_name != NULL) { 9127 elts.template = xmlNewNode(NULL, (xmlChar *)"template"); 9128 (void) xmlAddChild(elts.template, template_elts.common_name); 9129 (void) xmlAddChild(elts.template, template_elts.description); 9130 (void) xmlAddChild(elts.template, template_elts.documentation); 9131 } else { 9132 xmlFreeNode(template_elts.description); 9133 xmlFreeNode(template_elts.documentation); 9134 } 9135 9136 /* Iterate instances */ 9137 if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS) 9138 scfdie(); 9139 9140 while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1) 9141 export_instance(exp_inst, &elts, flags); 9142 if (ret == -1) 9143 scfdie(); 9144 9145 /* Now add all of the accumulated elements in order. */ 9146 (void) xmlAddChild(snode, elts.create_default_instance); 9147 (void) xmlAddChild(snode, elts.single_instance); 9148 (void) xmlAddChild(snode, elts.restarter); 9149 (void) xmlAddChildList(snode, elts.dependencies); 9150 (void) xmlAddChildList(snode, elts.dependents); 9151 (void) xmlAddChild(snode, elts.method_context); 9152 (void) xmlAddChildList(snode, elts.exec_methods); 9153 (void) xmlAddChildList(snode, elts.property_groups); 9154 (void) xmlAddChildList(snode, elts.instances); 9155 (void) xmlAddChild(snode, elts.stability); 9156 (void) xmlAddChild(snode, elts.template); 9157 9158 return (snode); 9159 } 9160 9161 static int 9162 export_callback(void *data, scf_walkinfo_t *wip) 9163 { 9164 FILE *f; 9165 xmlDocPtr doc; 9166 xmlNodePtr sb; 9167 int result; 9168 struct export_args *argsp = (struct export_args *)data; 9169 9170 if ((exp_inst = scf_instance_create(g_hndl)) == NULL || 9171 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9172 (exp_prop = scf_property_create(g_hndl)) == NULL || 9173 (exp_val = scf_value_create(g_hndl)) == NULL || 9174 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9175 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9176 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9177 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9178 scfdie(); 9179 9180 exp_str_sz = max_scf_len + 1; 9181 exp_str = safe_malloc(exp_str_sz); 9182 9183 if (argsp->filename != NULL) { 9184 errno = 0; 9185 f = fopen(argsp->filename, "wb"); 9186 if (f == NULL) { 9187 if (errno == 0) 9188 uu_die(gettext("Could not open \"%s\": no free " 9189 "stdio streams.\n"), argsp->filename); 9190 else 9191 uu_die(gettext("Could not open \"%s\""), 9192 argsp->filename); 9193 } 9194 } else 9195 f = stdout; 9196 9197 doc = xmlNewDoc((xmlChar *)"1.0"); 9198 if (doc == NULL) 9199 uu_die(gettext("Could not create XML document.\n")); 9200 9201 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9202 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9203 uu_die(emsg_create_xml); 9204 9205 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9206 if (sb == NULL) 9207 uu_die(emsg_create_xml); 9208 safe_setprop(sb, type_attr, "manifest"); 9209 safe_setprop(sb, name_attr, "export"); 9210 (void) xmlAddSibling(doc->children, sb); 9211 9212 (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags)); 9213 9214 result = write_service_bundle(doc, f); 9215 9216 free(exp_str); 9217 scf_iter_destroy(exp_val_iter); 9218 scf_iter_destroy(exp_prop_iter); 9219 scf_iter_destroy(exp_pg_iter); 9220 scf_iter_destroy(exp_inst_iter); 9221 scf_value_destroy(exp_val); 9222 scf_property_destroy(exp_prop); 9223 scf_pg_destroy(exp_pg); 9224 scf_instance_destroy(exp_inst); 9225 9226 xmlFreeDoc(doc); 9227 9228 if (f != stdout) 9229 (void) fclose(f); 9230 9231 return (result); 9232 } 9233 9234 /* 9235 * Get the service named by fmri, build an XML tree which represents it, and 9236 * dump it into filename (or stdout if filename is NULL). 9237 */ 9238 int 9239 lscf_service_export(char *fmri, const char *filename, int flags) 9240 { 9241 struct export_args args; 9242 int ret, err; 9243 9244 lscf_prep_hndl(); 9245 9246 bzero(&args, sizeof (args)); 9247 args.filename = filename; 9248 args.flags = flags; 9249 9250 err = 0; 9251 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 9252 SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback, 9253 &args, &err, semerr)) != 0) { 9254 if (ret != -1) 9255 semerr(gettext("Failed to walk instances: %s\n"), 9256 scf_strerror(ret)); 9257 return (-1); 9258 } 9259 9260 /* 9261 * Error message has already been printed. 9262 */ 9263 if (err != 0) 9264 return (-1); 9265 9266 return (0); 9267 } 9268 9269 9270 /* 9271 * Archive 9272 */ 9273 9274 static xmlNodePtr 9275 make_archive(int flags) 9276 { 9277 xmlNodePtr sb; 9278 scf_scope_t *scope; 9279 scf_service_t *svc; 9280 scf_iter_t *iter; 9281 int r; 9282 9283 if ((scope = scf_scope_create(g_hndl)) == NULL || 9284 (svc = scf_service_create(g_hndl)) == NULL || 9285 (iter = scf_iter_create(g_hndl)) == NULL || 9286 (exp_inst = scf_instance_create(g_hndl)) == NULL || 9287 (exp_pg = scf_pg_create(g_hndl)) == NULL || 9288 (exp_prop = scf_property_create(g_hndl)) == NULL || 9289 (exp_val = scf_value_create(g_hndl)) == NULL || 9290 (exp_inst_iter = scf_iter_create(g_hndl)) == NULL || 9291 (exp_pg_iter = scf_iter_create(g_hndl)) == NULL || 9292 (exp_prop_iter = scf_iter_create(g_hndl)) == NULL || 9293 (exp_val_iter = scf_iter_create(g_hndl)) == NULL) 9294 scfdie(); 9295 9296 exp_str_sz = max_scf_len + 1; 9297 exp_str = safe_malloc(exp_str_sz); 9298 9299 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9300 if (sb == NULL) 9301 uu_die(emsg_create_xml); 9302 safe_setprop(sb, type_attr, "archive"); 9303 safe_setprop(sb, name_attr, "none"); 9304 9305 if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) 9306 scfdie(); 9307 if (scf_iter_scope_services(iter, scope) != 0) 9308 scfdie(); 9309 9310 for (;;) { 9311 r = scf_iter_next_service(iter, svc); 9312 if (r == 0) 9313 break; 9314 if (r != 1) 9315 scfdie(); 9316 9317 if (scf_service_get_name(svc, exp_str, 9318 max_scf_name_len + 1) < 0) 9319 scfdie(); 9320 9321 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0) 9322 continue; 9323 9324 xmlAddChild(sb, export_service(svc, flags)); 9325 } 9326 9327 free(exp_str); 9328 9329 scf_iter_destroy(exp_val_iter); 9330 scf_iter_destroy(exp_prop_iter); 9331 scf_iter_destroy(exp_pg_iter); 9332 scf_iter_destroy(exp_inst_iter); 9333 scf_value_destroy(exp_val); 9334 scf_property_destroy(exp_prop); 9335 scf_pg_destroy(exp_pg); 9336 scf_instance_destroy(exp_inst); 9337 scf_iter_destroy(iter); 9338 scf_service_destroy(svc); 9339 scf_scope_destroy(scope); 9340 9341 return (sb); 9342 } 9343 9344 int 9345 lscf_archive(const char *filename, int flags) 9346 { 9347 FILE *f; 9348 xmlDocPtr doc; 9349 int result; 9350 9351 lscf_prep_hndl(); 9352 9353 if (filename != NULL) { 9354 errno = 0; 9355 f = fopen(filename, "wb"); 9356 if (f == NULL) { 9357 if (errno == 0) 9358 uu_die(gettext("Could not open \"%s\": no free " 9359 "stdio streams.\n"), filename); 9360 else 9361 uu_die(gettext("Could not open \"%s\""), 9362 filename); 9363 } 9364 } else 9365 f = stdout; 9366 9367 doc = xmlNewDoc((xmlChar *)"1.0"); 9368 if (doc == NULL) 9369 uu_die(gettext("Could not create XML document.\n")); 9370 9371 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9372 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9373 uu_die(emsg_create_xml); 9374 9375 (void) xmlAddSibling(doc->children, make_archive(flags)); 9376 9377 result = write_service_bundle(doc, f); 9378 9379 xmlFreeDoc(doc); 9380 9381 if (f != stdout) 9382 (void) fclose(f); 9383 9384 return (result); 9385 } 9386 9387 9388 /* 9389 * "Extract" a profile. 9390 */ 9391 int 9392 lscf_profile_extract(const char *filename) 9393 { 9394 FILE *f; 9395 xmlDocPtr doc; 9396 xmlNodePtr sb, snode, inode; 9397 scf_scope_t *scope; 9398 scf_service_t *svc; 9399 scf_instance_t *inst; 9400 scf_propertygroup_t *pg; 9401 scf_property_t *prop; 9402 scf_value_t *val; 9403 scf_iter_t *siter, *iiter; 9404 int r, s; 9405 char *namebuf; 9406 uint8_t b; 9407 int result; 9408 9409 lscf_prep_hndl(); 9410 9411 if (filename != NULL) { 9412 errno = 0; 9413 f = fopen(filename, "wb"); 9414 if (f == NULL) { 9415 if (errno == 0) 9416 uu_die(gettext("Could not open \"%s\": no " 9417 "free stdio streams.\n"), filename); 9418 else 9419 uu_die(gettext("Could not open \"%s\""), 9420 filename); 9421 } 9422 } else 9423 f = stdout; 9424 9425 doc = xmlNewDoc((xmlChar *)"1.0"); 9426 if (doc == NULL) 9427 uu_die(gettext("Could not create XML document.\n")); 9428 9429 if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL, 9430 (xmlChar *)MANIFEST_DTD_PATH) == NULL) 9431 uu_die(emsg_create_xml); 9432 9433 sb = xmlNewNode(NULL, (xmlChar *)"service_bundle"); 9434 if (sb == NULL) 9435 uu_die(emsg_create_xml); 9436 safe_setprop(sb, type_attr, "profile"); 9437 safe_setprop(sb, name_attr, "extract"); 9438 (void) xmlAddSibling(doc->children, sb); 9439 9440 if ((scope = scf_scope_create(g_hndl)) == NULL || 9441 (svc = scf_service_create(g_hndl)) == NULL || 9442 (inst = scf_instance_create(g_hndl)) == NULL || 9443 (pg = scf_pg_create(g_hndl)) == NULL || 9444 (prop = scf_property_create(g_hndl)) == NULL || 9445 (val = scf_value_create(g_hndl)) == NULL || 9446 (siter = scf_iter_create(g_hndl)) == NULL || 9447 (iiter = scf_iter_create(g_hndl)) == NULL) 9448 scfdie(); 9449 9450 if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS) 9451 scfdie(); 9452 9453 if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS) 9454 scfdie(); 9455 9456 namebuf = safe_malloc(max_scf_name_len + 1); 9457 9458 while ((r = scf_iter_next_service(siter, svc)) == 1) { 9459 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS) 9460 scfdie(); 9461 9462 snode = xmlNewNode(NULL, (xmlChar *)"service"); 9463 if (snode == NULL) 9464 uu_die(emsg_create_xml); 9465 9466 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) < 9467 0) 9468 scfdie(); 9469 9470 safe_setprop(snode, name_attr, namebuf); 9471 9472 safe_setprop(snode, type_attr, "service"); 9473 safe_setprop(snode, "version", "0"); 9474 9475 while ((s = scf_iter_next_instance(iiter, inst)) == 1) { 9476 if (scf_instance_get_pg(inst, scf_pg_general, pg) != 9477 SCF_SUCCESS) { 9478 if (scf_error() != SCF_ERROR_NOT_FOUND) 9479 scfdie(); 9480 9481 if (g_verbose) { 9482 ssize_t len; 9483 char *fmri; 9484 9485 len = 9486 scf_instance_to_fmri(inst, NULL, 0); 9487 if (len < 0) 9488 scfdie(); 9489 9490 fmri = safe_malloc(len + 1); 9491 9492 if (scf_instance_to_fmri(inst, fmri, 9493 len + 1) < 0) 9494 scfdie(); 9495 9496 warn("Instance %s has no \"%s\" " 9497 "property group.\n", fmri, 9498 scf_pg_general); 9499 9500 free(fmri); 9501 } 9502 9503 continue; 9504 } 9505 9506 if (pg_get_prop(pg, scf_property_enabled, prop) != 0 || 9507 prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 || 9508 prop_get_val(prop, val) != 0) 9509 continue; 9510 9511 inode = xmlNewChild(snode, NULL, (xmlChar *)"instance", 9512 NULL); 9513 if (inode == NULL) 9514 uu_die(emsg_create_xml); 9515 9516 if (scf_instance_get_name(inst, namebuf, 9517 max_scf_name_len + 1) < 0) 9518 scfdie(); 9519 9520 safe_setprop(inode, name_attr, namebuf); 9521 9522 if (scf_value_get_boolean(val, &b) != SCF_SUCCESS) 9523 scfdie(); 9524 9525 safe_setprop(inode, enabled_attr, b ? true : false); 9526 } 9527 if (s < 0) 9528 scfdie(); 9529 9530 if (snode->children != NULL) 9531 xmlAddChild(sb, snode); 9532 else 9533 xmlFreeNode(snode); 9534 } 9535 if (r < 0) 9536 scfdie(); 9537 9538 free(namebuf); 9539 9540 result = write_service_bundle(doc, f); 9541 9542 xmlFreeDoc(doc); 9543 9544 if (f != stdout) 9545 (void) fclose(f); 9546 9547 return (result); 9548 } 9549 9550 9551 /* 9552 * Entity manipulation commands 9553 */ 9554 9555 /* 9556 * Entity selection. If no entity is selected, then the current scope is in 9557 * cur_scope, and cur_svc and cur_inst are NULL. When a service is selected, 9558 * only cur_inst is NULL, and when an instance is selected, none are NULL. 9559 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and 9560 * cur_inst will be non-NULL. 9561 */ 9562 9563 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */ 9564 static int 9565 select_inst(const char *name) 9566 { 9567 scf_instance_t *inst; 9568 scf_error_t err; 9569 9570 assert(cur_svc != NULL); 9571 9572 inst = scf_instance_create(g_hndl); 9573 if (inst == NULL) 9574 scfdie(); 9575 9576 if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) { 9577 cur_inst = inst; 9578 return (0); 9579 } 9580 9581 err = scf_error(); 9582 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9583 scfdie(); 9584 9585 scf_instance_destroy(inst); 9586 return (1); 9587 } 9588 9589 /* Returns as above. */ 9590 static int 9591 select_svc(const char *name) 9592 { 9593 scf_service_t *svc; 9594 scf_error_t err; 9595 9596 assert(cur_scope != NULL); 9597 9598 svc = scf_service_create(g_hndl); 9599 if (svc == NULL) 9600 scfdie(); 9601 9602 if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) { 9603 cur_svc = svc; 9604 return (0); 9605 } 9606 9607 err = scf_error(); 9608 if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT) 9609 scfdie(); 9610 9611 scf_service_destroy(svc); 9612 return (1); 9613 } 9614 9615 /* ARGSUSED */ 9616 static int 9617 select_callback(void *unused, scf_walkinfo_t *wip) 9618 { 9619 scf_instance_t *inst; 9620 scf_service_t *svc; 9621 scf_scope_t *scope; 9622 9623 if (wip->inst != NULL) { 9624 if ((scope = scf_scope_create(g_hndl)) == NULL || 9625 (svc = scf_service_create(g_hndl)) == NULL || 9626 (inst = scf_instance_create(g_hndl)) == NULL) 9627 scfdie(); 9628 9629 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9630 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9631 scfdie(); 9632 } else { 9633 assert(wip->svc != NULL); 9634 9635 if ((scope = scf_scope_create(g_hndl)) == NULL || 9636 (svc = scf_service_create(g_hndl)) == NULL) 9637 scfdie(); 9638 9639 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc, 9640 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) 9641 scfdie(); 9642 9643 inst = NULL; 9644 } 9645 9646 /* Clear out the current selection */ 9647 assert(cur_scope != NULL); 9648 scf_scope_destroy(cur_scope); 9649 scf_service_destroy(cur_svc); 9650 scf_instance_destroy(cur_inst); 9651 9652 cur_scope = scope; 9653 cur_svc = svc; 9654 cur_inst = inst; 9655 9656 return (0); 9657 } 9658 9659 static int 9660 validate_callback(void *fmri_p, scf_walkinfo_t *wip) 9661 { 9662 char **fmri = fmri_p; 9663 9664 *fmri = strdup(wip->fmri); 9665 if (*fmri == NULL) 9666 uu_die(gettext("Out of memory.\n")); 9667 9668 return (0); 9669 } 9670 9671 /* 9672 * validate [fmri] 9673 * Perform the validation of an FMRI instance. 9674 */ 9675 void 9676 lscf_validate_fmri(const char *fmri) 9677 { 9678 int ret = 0; 9679 size_t inst_sz; 9680 char *inst_fmri = NULL; 9681 scf_tmpl_errors_t *errs = NULL; 9682 char *snapbuf = NULL; 9683 9684 lscf_prep_hndl(); 9685 9686 if (fmri == NULL) { 9687 inst_sz = max_scf_fmri_len + 1; 9688 inst_fmri = safe_malloc(inst_sz); 9689 9690 if (cur_snap != NULL) { 9691 snapbuf = safe_malloc(max_scf_name_len + 1); 9692 if (scf_snapshot_get_name(cur_snap, snapbuf, 9693 max_scf_name_len + 1) < 0) 9694 scfdie(); 9695 } 9696 if (cur_inst == NULL) { 9697 semerr(gettext("No instance selected\n")); 9698 goto cleanup; 9699 } else if (scf_instance_to_fmri(cur_inst, inst_fmri, 9700 inst_sz) >= inst_sz) { 9701 /* sanity check. Should never get here */ 9702 uu_die(gettext("Unexpected error! file %s, line %d\n"), 9703 __FILE__, __LINE__); 9704 } 9705 } else { 9706 scf_error_t scf_err; 9707 int err = 0; 9708 9709 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0, 9710 validate_callback, &inst_fmri, &err, semerr)) != 0) { 9711 uu_warn("Failed to walk instances: %s\n", 9712 scf_strerror(scf_err)); 9713 goto cleanup; 9714 } 9715 if (err != 0) 9716 /* error message displayed by scf_walk_fmri */ 9717 goto cleanup; 9718 } 9719 9720 ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs, 9721 SCF_TMPL_VALIDATE_FLAG_CURRENT); 9722 if (ret == -1) { 9723 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) { 9724 warn(gettext("Template data for %s is invalid. " 9725 "Consider reverting to a previous snapshot or " 9726 "restoring original configuration.\n"), inst_fmri); 9727 } else { 9728 uu_warn("%s: %s\n", 9729 gettext("Error validating the instance"), 9730 scf_strerror(scf_error())); 9731 } 9732 } else if (ret == 1 && errs != NULL) { 9733 scf_tmpl_error_t *err = NULL; 9734 char *msg; 9735 size_t len = 256; /* initial error buffer size */ 9736 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ? 9737 SCF_TMPL_STRERROR_HUMAN : 0; 9738 9739 msg = safe_malloc(len); 9740 9741 while ((err = scf_tmpl_next_error(errs)) != NULL) { 9742 int ret; 9743 9744 if ((ret = scf_tmpl_strerror(err, msg, len, 9745 flag)) >= len) { 9746 len = ret + 1; 9747 msg = realloc(msg, len); 9748 if (msg == NULL) 9749 uu_die(gettext( 9750 "Out of memory.\n")); 9751 (void) scf_tmpl_strerror(err, msg, len, 9752 flag); 9753 } 9754 (void) fprintf(stderr, "%s\n", msg); 9755 } 9756 if (msg != NULL) 9757 free(msg); 9758 } 9759 if (errs != NULL) 9760 scf_tmpl_errors_destroy(errs); 9761 cleanup: 9762 free(inst_fmri); 9763 free(snapbuf); 9764 } 9765 9766 static void 9767 lscf_validate_file(const char *filename) 9768 { 9769 tmpl_errors_t *errs; 9770 9771 bundle_t *b = internal_bundle_new(); 9772 if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) { 9773 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) { 9774 tmpl_errors_print(stderr, errs, ""); 9775 semerr(gettext("Validation failed.\n")); 9776 } 9777 tmpl_errors_destroy(errs); 9778 } 9779 (void) internal_bundle_free(b); 9780 } 9781 9782 /* 9783 * validate [fmri|file] 9784 */ 9785 void 9786 lscf_validate(const char *arg) 9787 { 9788 const char *str; 9789 9790 if (strncmp(arg, SCF_FMRI_FILE_PREFIX, 9791 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) { 9792 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1; 9793 lscf_validate_file(str); 9794 } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX, 9795 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) { 9796 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1; 9797 lscf_validate_fmri(str); 9798 } else if (access(arg, R_OK | F_OK) == 0) { 9799 lscf_validate_file(arg); 9800 } else { 9801 lscf_validate_fmri(arg); 9802 } 9803 } 9804 9805 void 9806 lscf_select(const char *fmri) 9807 { 9808 int ret, err; 9809 9810 lscf_prep_hndl(); 9811 9812 if (cur_snap != NULL) { 9813 struct snaplevel *elt; 9814 char *buf; 9815 9816 /* Error unless name is that of the next level. */ 9817 elt = uu_list_next(cur_levels, cur_elt); 9818 if (elt == NULL) { 9819 semerr(gettext("No children.\n")); 9820 return; 9821 } 9822 9823 buf = safe_malloc(max_scf_name_len + 1); 9824 9825 if (scf_snaplevel_get_instance_name(elt->sl, buf, 9826 max_scf_name_len + 1) < 0) 9827 scfdie(); 9828 9829 if (strcmp(buf, fmri) != 0) { 9830 semerr(gettext("No such child.\n")); 9831 free(buf); 9832 return; 9833 } 9834 9835 free(buf); 9836 9837 cur_elt = elt; 9838 cur_level = elt->sl; 9839 return; 9840 } 9841 9842 /* 9843 * Special case for 'svc:', which takes the user to the scope level. 9844 */ 9845 if (strcmp(fmri, "svc:") == 0) { 9846 scf_instance_destroy(cur_inst); 9847 scf_service_destroy(cur_svc); 9848 cur_inst = NULL; 9849 cur_svc = NULL; 9850 return; 9851 } 9852 9853 /* 9854 * Special case for ':properties'. This appears as part of 'list' but 9855 * can't be selected. Give a more helpful error message in this case. 9856 */ 9857 if (strcmp(fmri, ":properties") == 0) { 9858 semerr(gettext(":properties is not an entity. Try 'listprop' " 9859 "to list properties.\n")); 9860 return; 9861 } 9862 9863 /* 9864 * First try the argument as relative to the current selection. 9865 */ 9866 if (cur_inst != NULL) { 9867 /* EMPTY */; 9868 } else if (cur_svc != NULL) { 9869 if (select_inst(fmri) != 1) 9870 return; 9871 } else { 9872 if (select_svc(fmri) != 1) 9873 return; 9874 } 9875 9876 err = 0; 9877 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 9878 select_callback, NULL, &err, semerr)) != 0) { 9879 semerr(gettext("Failed to walk instances: %s\n"), 9880 scf_strerror(ret)); 9881 } 9882 } 9883 9884 void 9885 lscf_unselect(void) 9886 { 9887 lscf_prep_hndl(); 9888 9889 if (cur_snap != NULL) { 9890 struct snaplevel *elt; 9891 9892 elt = uu_list_prev(cur_levels, cur_elt); 9893 if (elt == NULL) { 9894 semerr(gettext("No parent levels.\n")); 9895 } else { 9896 cur_elt = elt; 9897 cur_level = elt->sl; 9898 } 9899 } else if (cur_inst != NULL) { 9900 scf_instance_destroy(cur_inst); 9901 cur_inst = NULL; 9902 } else if (cur_svc != NULL) { 9903 scf_service_destroy(cur_svc); 9904 cur_svc = NULL; 9905 } else { 9906 semerr(gettext("Cannot unselect at scope level.\n")); 9907 } 9908 } 9909 9910 /* 9911 * Return the FMRI of the current selection, for the prompt. 9912 */ 9913 void 9914 lscf_get_selection_str(char *buf, size_t bufsz) 9915 { 9916 char *cp; 9917 ssize_t fmrilen, szret; 9918 boolean_t deleted = B_FALSE; 9919 9920 if (g_hndl == NULL) { 9921 (void) strlcpy(buf, "svc:", bufsz); 9922 return; 9923 } 9924 9925 if (cur_level != NULL) { 9926 assert(cur_snap != NULL); 9927 9928 /* [ snapshot ] FMRI [: instance ] */ 9929 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len 9930 + 2 + max_scf_name_len + 1 + 1); 9931 9932 buf[0] = '['; 9933 9934 szret = scf_snapshot_get_name(cur_snap, buf + 1, 9935 max_scf_name_len + 1); 9936 if (szret < 0) { 9937 if (scf_error() != SCF_ERROR_DELETED) 9938 scfdie(); 9939 9940 goto snap_deleted; 9941 } 9942 9943 (void) strcat(buf, "]svc:/"); 9944 9945 cp = strchr(buf, '\0'); 9946 9947 szret = scf_snaplevel_get_service_name(cur_level, cp, 9948 max_scf_name_len + 1); 9949 if (szret < 0) { 9950 if (scf_error() != SCF_ERROR_DELETED) 9951 scfdie(); 9952 9953 goto snap_deleted; 9954 } 9955 9956 cp = strchr(cp, '\0'); 9957 9958 if (snaplevel_is_instance(cur_level)) { 9959 *cp++ = ':'; 9960 9961 if (scf_snaplevel_get_instance_name(cur_level, cp, 9962 max_scf_name_len + 1) < 0) { 9963 if (scf_error() != SCF_ERROR_DELETED) 9964 scfdie(); 9965 9966 goto snap_deleted; 9967 } 9968 } else { 9969 *cp++ = '['; 9970 *cp++ = ':'; 9971 9972 if (scf_instance_get_name(cur_inst, cp, 9973 max_scf_name_len + 1) < 0) { 9974 if (scf_error() != SCF_ERROR_DELETED) 9975 scfdie(); 9976 9977 goto snap_deleted; 9978 } 9979 9980 (void) strcat(buf, "]"); 9981 } 9982 9983 return; 9984 9985 snap_deleted: 9986 deleted = B_TRUE; 9987 free(buf); 9988 unselect_cursnap(); 9989 } 9990 9991 assert(cur_snap == NULL); 9992 9993 if (cur_inst != NULL) { 9994 assert(cur_svc != NULL); 9995 assert(cur_scope != NULL); 9996 9997 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz); 9998 if (fmrilen >= 0) { 9999 assert(fmrilen < bufsz); 10000 if (deleted) 10001 warn(emsg_deleted); 10002 return; 10003 } 10004 10005 if (scf_error() != SCF_ERROR_DELETED) 10006 scfdie(); 10007 10008 deleted = B_TRUE; 10009 10010 scf_instance_destroy(cur_inst); 10011 cur_inst = NULL; 10012 } 10013 10014 if (cur_svc != NULL) { 10015 assert(cur_scope != NULL); 10016 10017 szret = scf_service_to_fmri(cur_svc, buf, bufsz); 10018 if (szret >= 0) { 10019 assert(szret < bufsz); 10020 if (deleted) 10021 warn(emsg_deleted); 10022 return; 10023 } 10024 10025 if (scf_error() != SCF_ERROR_DELETED) 10026 scfdie(); 10027 10028 deleted = B_TRUE; 10029 scf_service_destroy(cur_svc); 10030 cur_svc = NULL; 10031 } 10032 10033 assert(cur_scope != NULL); 10034 fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz); 10035 10036 if (fmrilen < 0) 10037 scfdie(); 10038 10039 assert(fmrilen < bufsz); 10040 if (deleted) 10041 warn(emsg_deleted); 10042 } 10043 10044 /* 10045 * Entity listing. Entities and colon namespaces (e.g., :properties and 10046 * :statistics) are listed for the current selection. 10047 */ 10048 void 10049 lscf_list(const char *pattern) 10050 { 10051 scf_iter_t *iter; 10052 char *buf; 10053 int ret; 10054 10055 lscf_prep_hndl(); 10056 10057 if (cur_level != NULL) { 10058 struct snaplevel *elt; 10059 10060 (void) fputs(COLON_NAMESPACES, stdout); 10061 10062 elt = uu_list_next(cur_levels, cur_elt); 10063 if (elt == NULL) 10064 return; 10065 10066 /* 10067 * For now, we know that the next level is an instance. But 10068 * if we ever have multiple scopes, this could be complicated. 10069 */ 10070 buf = safe_malloc(max_scf_name_len + 1); 10071 if (scf_snaplevel_get_instance_name(elt->sl, buf, 10072 max_scf_name_len + 1) >= 0) { 10073 (void) puts(buf); 10074 } else { 10075 if (scf_error() != SCF_ERROR_DELETED) 10076 scfdie(); 10077 } 10078 10079 free(buf); 10080 10081 return; 10082 } 10083 10084 if (cur_inst != NULL) { 10085 (void) fputs(COLON_NAMESPACES, stdout); 10086 return; 10087 } 10088 10089 iter = scf_iter_create(g_hndl); 10090 if (iter == NULL) 10091 scfdie(); 10092 10093 buf = safe_malloc(max_scf_name_len + 1); 10094 10095 if (cur_svc != NULL) { 10096 /* List the instances in this service. */ 10097 scf_instance_t *inst; 10098 10099 inst = scf_instance_create(g_hndl); 10100 if (inst == NULL) 10101 scfdie(); 10102 10103 if (scf_iter_service_instances(iter, cur_svc) == 0) { 10104 safe_printf(COLON_NAMESPACES); 10105 10106 for (;;) { 10107 ret = scf_iter_next_instance(iter, inst); 10108 if (ret == 0) 10109 break; 10110 if (ret != 1) { 10111 if (scf_error() != SCF_ERROR_DELETED) 10112 scfdie(); 10113 10114 break; 10115 } 10116 10117 if (scf_instance_get_name(inst, buf, 10118 max_scf_name_len + 1) >= 0) { 10119 if (pattern == NULL || 10120 fnmatch(pattern, buf, 0) == 0) 10121 (void) puts(buf); 10122 } else { 10123 if (scf_error() != SCF_ERROR_DELETED) 10124 scfdie(); 10125 } 10126 } 10127 } else { 10128 if (scf_error() != SCF_ERROR_DELETED) 10129 scfdie(); 10130 } 10131 10132 scf_instance_destroy(inst); 10133 } else { 10134 /* List the services in this scope. */ 10135 scf_service_t *svc; 10136 10137 assert(cur_scope != NULL); 10138 10139 svc = scf_service_create(g_hndl); 10140 if (svc == NULL) 10141 scfdie(); 10142 10143 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS) 10144 scfdie(); 10145 10146 for (;;) { 10147 ret = scf_iter_next_service(iter, svc); 10148 if (ret == 0) 10149 break; 10150 if (ret != 1) 10151 scfdie(); 10152 10153 if (scf_service_get_name(svc, buf, 10154 max_scf_name_len + 1) >= 0) { 10155 if (pattern == NULL || 10156 fnmatch(pattern, buf, 0) == 0) 10157 safe_printf("%s\n", buf); 10158 } else { 10159 if (scf_error() != SCF_ERROR_DELETED) 10160 scfdie(); 10161 } 10162 } 10163 10164 scf_service_destroy(svc); 10165 } 10166 10167 free(buf); 10168 scf_iter_destroy(iter); 10169 } 10170 10171 /* 10172 * Entity addition. Creates an empty entity in the current selection. 10173 */ 10174 void 10175 lscf_add(const char *name) 10176 { 10177 lscf_prep_hndl(); 10178 10179 if (cur_snap != NULL) { 10180 semerr(emsg_cant_modify_snapshots); 10181 } else if (cur_inst != NULL) { 10182 semerr(gettext("Cannot add entities to an instance.\n")); 10183 } else if (cur_svc != NULL) { 10184 10185 if (scf_service_add_instance(cur_svc, name, NULL) != 10186 SCF_SUCCESS) { 10187 switch (scf_error()) { 10188 case SCF_ERROR_INVALID_ARGUMENT: 10189 semerr(gettext("Invalid name.\n")); 10190 break; 10191 10192 case SCF_ERROR_EXISTS: 10193 semerr(gettext("Instance already exists.\n")); 10194 break; 10195 10196 case SCF_ERROR_PERMISSION_DENIED: 10197 semerr(emsg_permission_denied); 10198 break; 10199 10200 default: 10201 scfdie(); 10202 } 10203 } 10204 } else { 10205 assert(cur_scope != NULL); 10206 10207 if (scf_scope_add_service(cur_scope, name, NULL) != 10208 SCF_SUCCESS) { 10209 switch (scf_error()) { 10210 case SCF_ERROR_INVALID_ARGUMENT: 10211 semerr(gettext("Invalid name.\n")); 10212 break; 10213 10214 case SCF_ERROR_EXISTS: 10215 semerr(gettext("Service already exists.\n")); 10216 break; 10217 10218 case SCF_ERROR_PERMISSION_DENIED: 10219 semerr(emsg_permission_denied); 10220 break; 10221 10222 case SCF_ERROR_BACKEND_READONLY: 10223 semerr(emsg_read_only); 10224 break; 10225 10226 default: 10227 scfdie(); 10228 } 10229 } 10230 } 10231 } 10232 10233 /* return 1 if the entity has no persistent pgs, else return 0 */ 10234 static int 10235 entity_has_no_pgs(void *ent, int isservice) 10236 { 10237 scf_iter_t *iter = NULL; 10238 scf_propertygroup_t *pg = NULL; 10239 uint32_t flags; 10240 int err; 10241 int ret = 1; 10242 10243 if ((iter = scf_iter_create(g_hndl)) == NULL || 10244 (pg = scf_pg_create(g_hndl)) == NULL) 10245 scfdie(); 10246 10247 if (isservice) { 10248 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0) 10249 scfdie(); 10250 } else { 10251 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0) 10252 scfdie(); 10253 } 10254 10255 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 10256 if (scf_pg_get_flags(pg, &flags) != 0) 10257 scfdie(); 10258 10259 /* skip nonpersistent pgs */ 10260 if (flags & SCF_PG_FLAG_NONPERSISTENT) 10261 continue; 10262 10263 ret = 0; 10264 break; 10265 } 10266 10267 if (err == -1) 10268 scfdie(); 10269 10270 scf_pg_destroy(pg); 10271 scf_iter_destroy(iter); 10272 10273 return (ret); 10274 } 10275 10276 /* return 1 if the service has no instances, else return 0 */ 10277 static int 10278 svc_has_no_insts(scf_service_t *svc) 10279 { 10280 scf_instance_t *inst; 10281 scf_iter_t *iter; 10282 int r; 10283 int ret = 1; 10284 10285 if ((inst = scf_instance_create(g_hndl)) == NULL || 10286 (iter = scf_iter_create(g_hndl)) == NULL) 10287 scfdie(); 10288 10289 if (scf_iter_service_instances(iter, svc) != 0) 10290 scfdie(); 10291 10292 r = scf_iter_next_instance(iter, inst); 10293 if (r == 1) { 10294 ret = 0; 10295 } else if (r == 0) { 10296 ret = 1; 10297 } else if (r == -1) { 10298 scfdie(); 10299 } else { 10300 bad_error("scf_iter_next_instance", r); 10301 } 10302 10303 scf_iter_destroy(iter); 10304 scf_instance_destroy(inst); 10305 10306 return (ret); 10307 } 10308 10309 /* 10310 * Entity deletion. 10311 */ 10312 10313 /* 10314 * Delete the property group <fmri>/:properties/<name>. Returns 10315 * SCF_ERROR_NONE on success (or if the entity is not found), 10316 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if 10317 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was 10318 * denied. 10319 */ 10320 static scf_error_t 10321 delete_dependency_pg(const char *fmri, const char *name) 10322 { 10323 void *entity = NULL; 10324 int isservice; 10325 scf_propertygroup_t *pg = NULL; 10326 scf_error_t result; 10327 char *pgty; 10328 scf_service_t *svc = NULL; 10329 scf_instance_t *inst = NULL; 10330 scf_iter_t *iter = NULL; 10331 char *name_buf = NULL; 10332 10333 result = fmri_to_entity(g_hndl, fmri, &entity, &isservice); 10334 switch (result) { 10335 case SCF_ERROR_NONE: 10336 break; 10337 10338 case SCF_ERROR_NO_MEMORY: 10339 uu_die(gettext("Out of memory.\n")); 10340 /* NOTREACHED */ 10341 10342 case SCF_ERROR_INVALID_ARGUMENT: 10343 case SCF_ERROR_CONSTRAINT_VIOLATED: 10344 return (SCF_ERROR_INVALID_ARGUMENT); 10345 10346 case SCF_ERROR_NOT_FOUND: 10347 result = SCF_ERROR_NONE; 10348 goto out; 10349 10350 default: 10351 bad_error("fmri_to_entity", result); 10352 } 10353 10354 pg = scf_pg_create(g_hndl); 10355 if (pg == NULL) 10356 scfdie(); 10357 10358 if (entity_get_pg(entity, isservice, name, pg) != 0) { 10359 if (scf_error() != SCF_ERROR_NOT_FOUND) 10360 scfdie(); 10361 10362 result = SCF_ERROR_NONE; 10363 goto out; 10364 } 10365 10366 pgty = safe_malloc(max_scf_pg_type_len + 1); 10367 10368 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10369 scfdie(); 10370 10371 if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) { 10372 result = SCF_ERROR_TYPE_MISMATCH; 10373 free(pgty); 10374 goto out; 10375 } 10376 10377 free(pgty); 10378 10379 if (scf_pg_delete(pg) != 0) { 10380 result = scf_error(); 10381 if (result != SCF_ERROR_PERMISSION_DENIED) 10382 scfdie(); 10383 goto out; 10384 } 10385 10386 /* 10387 * We have to handle the case where we've just deleted the last 10388 * property group of a "dummy" entity (instance or service). 10389 * A "dummy" entity is an entity only present to hold an 10390 * external dependency. 10391 * So, in the case we deleted the last property group then we 10392 * can also delete the entity. If the entity is an instance then 10393 * we must verify if this was the last instance for the service 10394 * and if it is, we can also delete the service if it doesn't 10395 * have any property group either. 10396 */ 10397 10398 result = SCF_ERROR_NONE; 10399 10400 if (isservice) { 10401 svc = (scf_service_t *)entity; 10402 10403 if ((inst = scf_instance_create(g_hndl)) == NULL || 10404 (iter = scf_iter_create(g_hndl)) == NULL) 10405 scfdie(); 10406 10407 name_buf = safe_malloc(max_scf_name_len + 1); 10408 } else { 10409 inst = (scf_instance_t *)entity; 10410 } 10411 10412 /* 10413 * If the entity is an instance and we've just deleted its last 10414 * property group then we should delete it. 10415 */ 10416 if (!isservice && entity_has_no_pgs(entity, isservice)) { 10417 /* find the service before deleting the inst. - needed later */ 10418 if ((svc = scf_service_create(g_hndl)) == NULL) 10419 scfdie(); 10420 10421 if (scf_instance_get_parent(inst, svc) != 0) 10422 scfdie(); 10423 10424 /* delete the instance */ 10425 if (scf_instance_delete(inst) != 0) { 10426 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10427 scfdie(); 10428 10429 result = SCF_ERROR_PERMISSION_DENIED; 10430 goto out; 10431 } 10432 /* no need to refresh the instance */ 10433 inst = NULL; 10434 } 10435 10436 /* 10437 * If the service has no more instances and pgs or we just deleted the 10438 * last instance and the service doesn't have anymore propery groups 10439 * then the service should be deleted. 10440 */ 10441 if (svc != NULL && 10442 svc_has_no_insts(svc) && 10443 entity_has_no_pgs((void *)svc, 1)) { 10444 if (scf_service_delete(svc) == 0) { 10445 if (isservice) { 10446 /* no need to refresh the service */ 10447 svc = NULL; 10448 } 10449 10450 goto out; 10451 } 10452 10453 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10454 scfdie(); 10455 10456 result = SCF_ERROR_PERMISSION_DENIED; 10457 } 10458 10459 /* if the entity has not been deleted, refresh it */ 10460 if ((isservice && svc != NULL) || (!isservice && inst != NULL)) { 10461 (void) refresh_entity(isservice, entity, fmri, inst, iter, 10462 name_buf); 10463 } 10464 10465 out: 10466 if (isservice && (inst != NULL && iter != NULL)) { 10467 free(name_buf); 10468 scf_iter_destroy(iter); 10469 scf_instance_destroy(inst); 10470 } 10471 10472 if (!isservice && svc != NULL) { 10473 scf_service_destroy(svc); 10474 } 10475 10476 scf_pg_destroy(pg); 10477 if (entity != NULL) 10478 entity_destroy(entity, isservice); 10479 10480 return (result); 10481 } 10482 10483 static int 10484 delete_dependents(scf_propertygroup_t *pg) 10485 { 10486 char *pgty, *name, *fmri; 10487 scf_property_t *prop; 10488 scf_value_t *val; 10489 scf_iter_t *iter; 10490 int r; 10491 scf_error_t err; 10492 10493 /* Verify that the pg has the correct type. */ 10494 pgty = safe_malloc(max_scf_pg_type_len + 1); 10495 if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0) 10496 scfdie(); 10497 10498 if (strcmp(pgty, scf_group_framework) != 0) { 10499 if (g_verbose) { 10500 fmri = safe_malloc(max_scf_fmri_len + 1); 10501 if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0) 10502 scfdie(); 10503 10504 warn(gettext("Property group %s is not of expected " 10505 "type %s.\n"), fmri, scf_group_framework); 10506 10507 free(fmri); 10508 } 10509 10510 free(pgty); 10511 return (-1); 10512 } 10513 10514 free(pgty); 10515 10516 /* map delete_dependency_pg onto the properties. */ 10517 if ((prop = scf_property_create(g_hndl)) == NULL || 10518 (val = scf_value_create(g_hndl)) == NULL || 10519 (iter = scf_iter_create(g_hndl)) == NULL) 10520 scfdie(); 10521 10522 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) 10523 scfdie(); 10524 10525 name = safe_malloc(max_scf_name_len + 1); 10526 fmri = safe_malloc(max_scf_fmri_len + 2); 10527 10528 while ((r = scf_iter_next_property(iter, prop)) == 1) { 10529 scf_type_t ty; 10530 10531 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0) 10532 scfdie(); 10533 10534 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 10535 scfdie(); 10536 10537 if ((ty != SCF_TYPE_ASTRING && 10538 prop_check_type(prop, SCF_TYPE_FMRI) != 0) || 10539 prop_get_val(prop, val) != 0) 10540 continue; 10541 10542 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0) 10543 scfdie(); 10544 10545 err = delete_dependency_pg(fmri, name); 10546 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) { 10547 if (scf_property_to_fmri(prop, fmri, 10548 max_scf_fmri_len + 2) < 0) 10549 scfdie(); 10550 10551 warn(gettext("Value of %s is not a valid FMRI.\n"), 10552 fmri); 10553 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) { 10554 warn(gettext("Property group \"%s\" of entity \"%s\" " 10555 "does not have dependency type.\n"), name, fmri); 10556 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) { 10557 warn(gettext("Could not delete property group \"%s\" " 10558 "of entity \"%s\" (permission denied).\n"), name, 10559 fmri); 10560 } 10561 } 10562 if (r == -1) 10563 scfdie(); 10564 10565 scf_value_destroy(val); 10566 scf_property_destroy(prop); 10567 10568 return (0); 10569 } 10570 10571 /* 10572 * Returns 1 if the instance may be running, and 0 otherwise. 10573 */ 10574 static int 10575 inst_is_running(scf_instance_t *inst) 10576 { 10577 scf_propertygroup_t *pg; 10578 scf_property_t *prop; 10579 scf_value_t *val; 10580 char buf[MAX_SCF_STATE_STRING_SZ]; 10581 int ret = 0; 10582 ssize_t szret; 10583 10584 if ((pg = scf_pg_create(g_hndl)) == NULL || 10585 (prop = scf_property_create(g_hndl)) == NULL || 10586 (val = scf_value_create(g_hndl)) == NULL) 10587 scfdie(); 10588 10589 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) { 10590 if (scf_error() != SCF_ERROR_NOT_FOUND) 10591 scfdie(); 10592 goto out; 10593 } 10594 10595 if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 || 10596 prop_check_type(prop, SCF_TYPE_ASTRING) != 0 || 10597 prop_get_val(prop, val) != 0) 10598 goto out; 10599 10600 szret = scf_value_get_astring(val, buf, sizeof (buf)); 10601 assert(szret >= 0); 10602 10603 ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 || 10604 strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0; 10605 10606 out: 10607 scf_value_destroy(val); 10608 scf_property_destroy(prop); 10609 scf_pg_destroy(pg); 10610 return (ret); 10611 } 10612 10613 static uint8_t 10614 pg_is_external_dependency(scf_propertygroup_t *pg) 10615 { 10616 char *type; 10617 scf_value_t *val; 10618 scf_property_t *prop; 10619 uint8_t b = B_FALSE; 10620 10621 type = safe_malloc(max_scf_pg_type_len + 1); 10622 10623 if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0) 10624 scfdie(); 10625 10626 if ((prop = scf_property_create(g_hndl)) == NULL || 10627 (val = scf_value_create(g_hndl)) == NULL) 10628 scfdie(); 10629 10630 if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) { 10631 if (pg_get_prop(pg, scf_property_external, prop) == 0) { 10632 if (scf_property_get_value(prop, val) != 0) 10633 scfdie(); 10634 if (scf_value_get_boolean(val, &b) != 0) 10635 scfdie(); 10636 } 10637 } 10638 10639 free(type); 10640 (void) scf_value_destroy(val); 10641 (void) scf_property_destroy(prop); 10642 10643 return (b); 10644 } 10645 10646 #define DELETE_FAILURE -1 10647 #define DELETE_SUCCESS_NOEXTDEPS 0 10648 #define DELETE_SUCCESS_EXTDEPS 1 10649 10650 /* 10651 * lscf_instance_delete() deletes an instance. Before calling 10652 * scf_instance_delete(), though, we make sure the instance isn't 10653 * running and delete dependencies in other entities which the instance 10654 * declared as "dependents". If there are dependencies which were 10655 * created for other entities, then instead of deleting the instance we 10656 * make it "empty" by deleting all other property groups and all 10657 * snapshots. 10658 * 10659 * lscf_instance_delete() verifies that there is no external dependency pgs 10660 * before suppressing the instance. If there is, then we must not remove them 10661 * now in case the instance is re-created otherwise the dependencies would be 10662 * lost. The external dependency pgs will be removed if the dependencies are 10663 * removed. 10664 * 10665 * Returns: 10666 * DELETE_FAILURE on failure 10667 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 10668 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 10669 */ 10670 static int 10671 lscf_instance_delete(scf_instance_t *inst, int force) 10672 { 10673 scf_propertygroup_t *pg; 10674 scf_snapshot_t *snap; 10675 scf_iter_t *iter; 10676 int err; 10677 int external = 0; 10678 10679 /* If we're not forcing and the instance is running, refuse. */ 10680 if (!force && inst_is_running(inst)) { 10681 char *fmri; 10682 10683 fmri = safe_malloc(max_scf_fmri_len + 1); 10684 10685 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0) 10686 scfdie(); 10687 10688 semerr(gettext("Instance %s may be running. " 10689 "Use delete -f if it is not.\n"), fmri); 10690 10691 free(fmri); 10692 return (DELETE_FAILURE); 10693 } 10694 10695 pg = scf_pg_create(g_hndl); 10696 if (pg == NULL) 10697 scfdie(); 10698 10699 if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0) 10700 (void) delete_dependents(pg); 10701 else if (scf_error() != SCF_ERROR_NOT_FOUND) 10702 scfdie(); 10703 10704 scf_pg_destroy(pg); 10705 10706 /* 10707 * If the instance has some external dependencies then we must 10708 * keep them in case the instance is reimported otherwise the 10709 * dependencies would be lost on reimport. 10710 */ 10711 if ((iter = scf_iter_create(g_hndl)) == NULL || 10712 (pg = scf_pg_create(g_hndl)) == NULL) 10713 scfdie(); 10714 10715 if (scf_iter_instance_pgs(iter, inst) < 0) 10716 scfdie(); 10717 10718 while ((err = scf_iter_next_pg(iter, pg)) == 1) { 10719 if (pg_is_external_dependency(pg)) { 10720 external = 1; 10721 continue; 10722 } 10723 10724 if (scf_pg_delete(pg) != 0) { 10725 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10726 scfdie(); 10727 else { 10728 semerr(emsg_permission_denied); 10729 10730 (void) scf_iter_destroy(iter); 10731 (void) scf_pg_destroy(pg); 10732 return (DELETE_FAILURE); 10733 } 10734 } 10735 } 10736 10737 if (err == -1) 10738 scfdie(); 10739 10740 (void) scf_iter_destroy(iter); 10741 (void) scf_pg_destroy(pg); 10742 10743 if (external) { 10744 /* 10745 * All the pgs have been deleted for the instance except 10746 * the ones holding the external dependencies. 10747 * For the job to be complete, we must also delete the 10748 * snapshots associated with the instance. 10749 */ 10750 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) == 10751 NULL) 10752 scfdie(); 10753 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL) 10754 scfdie(); 10755 10756 if (scf_iter_instance_snapshots(iter, inst) == -1) 10757 scfdie(); 10758 10759 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) { 10760 if (_scf_snapshot_delete(snap) != 0) { 10761 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10762 scfdie(); 10763 10764 semerr(emsg_permission_denied); 10765 10766 (void) scf_iter_destroy(iter); 10767 (void) scf_snapshot_destroy(snap); 10768 return (DELETE_FAILURE); 10769 } 10770 } 10771 10772 if (err == -1) 10773 scfdie(); 10774 10775 (void) scf_iter_destroy(iter); 10776 (void) scf_snapshot_destroy(snap); 10777 return (DELETE_SUCCESS_EXTDEPS); 10778 } 10779 10780 if (scf_instance_delete(inst) != 0) { 10781 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10782 scfdie(); 10783 10784 semerr(emsg_permission_denied); 10785 10786 return (DELETE_FAILURE); 10787 } 10788 10789 return (DELETE_SUCCESS_NOEXTDEPS); 10790 } 10791 10792 /* 10793 * lscf_service_delete() deletes a service. Before calling 10794 * scf_service_delete(), though, we call lscf_instance_delete() for 10795 * each of the instances and delete dependencies in other entities 10796 * which were created as "dependents" of this service. If there are 10797 * dependencies which were created for other entities, then we delete 10798 * all other property groups in the service and leave it as "empty". 10799 * 10800 * lscf_service_delete() verifies that there is no external dependency 10801 * pgs at the instance & service level before suppressing the service. 10802 * If there is, then we must not remove them now in case the service 10803 * is re-imported otherwise the dependencies would be lost. The external 10804 * dependency pgs will be removed if the dependencies are removed. 10805 * 10806 * Returns: 10807 * DELETE_FAILURE on failure 10808 * DELETE_SUCCESS_NOEXTDEPS on success - no external dependencies 10809 * DELETE_SUCCESS_EXTDEPS on success - external dependencies 10810 */ 10811 static int 10812 lscf_service_delete(scf_service_t *svc, int force) 10813 { 10814 int r; 10815 scf_instance_t *inst; 10816 scf_propertygroup_t *pg; 10817 scf_iter_t *iter; 10818 int ret; 10819 int external = 0; 10820 10821 if ((inst = scf_instance_create(g_hndl)) == NULL || 10822 (pg = scf_pg_create(g_hndl)) == NULL || 10823 (iter = scf_iter_create(g_hndl)) == NULL) 10824 scfdie(); 10825 10826 if (scf_iter_service_instances(iter, svc) != 0) 10827 scfdie(); 10828 10829 for (r = scf_iter_next_instance(iter, inst); 10830 r == 1; 10831 r = scf_iter_next_instance(iter, inst)) { 10832 10833 ret = lscf_instance_delete(inst, force); 10834 if (ret == DELETE_FAILURE) { 10835 scf_iter_destroy(iter); 10836 scf_pg_destroy(pg); 10837 scf_instance_destroy(inst); 10838 return (DELETE_FAILURE); 10839 } 10840 10841 /* 10842 * Record the fact that there is some external dependencies 10843 * at the instance level. 10844 */ 10845 if (ret == DELETE_SUCCESS_EXTDEPS) 10846 external |= 1; 10847 } 10848 10849 if (r != 0) 10850 scfdie(); 10851 10852 /* Delete dependency property groups in dependent services. */ 10853 if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0) 10854 (void) delete_dependents(pg); 10855 else if (scf_error() != SCF_ERROR_NOT_FOUND) 10856 scfdie(); 10857 10858 scf_iter_destroy(iter); 10859 scf_pg_destroy(pg); 10860 scf_instance_destroy(inst); 10861 10862 /* 10863 * If the service has some external dependencies then we don't 10864 * want to remove them in case the service is re-imported. 10865 */ 10866 if ((pg = scf_pg_create(g_hndl)) == NULL || 10867 (iter = scf_iter_create(g_hndl)) == NULL) 10868 scfdie(); 10869 10870 if (scf_iter_service_pgs(iter, svc) < 0) 10871 scfdie(); 10872 10873 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 10874 if (pg_is_external_dependency(pg)) { 10875 external |= 2; 10876 continue; 10877 } 10878 10879 if (scf_pg_delete(pg) != 0) { 10880 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10881 scfdie(); 10882 else { 10883 semerr(emsg_permission_denied); 10884 10885 (void) scf_iter_destroy(iter); 10886 (void) scf_pg_destroy(pg); 10887 return (DELETE_FAILURE); 10888 } 10889 } 10890 } 10891 10892 if (r == -1) 10893 scfdie(); 10894 10895 (void) scf_iter_destroy(iter); 10896 (void) scf_pg_destroy(pg); 10897 10898 if (external != 0) 10899 return (DELETE_SUCCESS_EXTDEPS); 10900 10901 if (scf_service_delete(svc) == 0) 10902 return (DELETE_SUCCESS_NOEXTDEPS); 10903 10904 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 10905 scfdie(); 10906 10907 semerr(emsg_permission_denied); 10908 return (DELETE_FAILURE); 10909 } 10910 10911 static int 10912 delete_callback(void *data, scf_walkinfo_t *wip) 10913 { 10914 int force = (int)data; 10915 10916 if (wip->inst != NULL) 10917 (void) lscf_instance_delete(wip->inst, force); 10918 else 10919 (void) lscf_service_delete(wip->svc, force); 10920 10921 return (0); 10922 } 10923 10924 void 10925 lscf_delete(const char *fmri, int force) 10926 { 10927 scf_service_t *svc; 10928 scf_instance_t *inst; 10929 int ret; 10930 10931 lscf_prep_hndl(); 10932 10933 if (cur_snap != NULL) { 10934 if (!snaplevel_is_instance(cur_level)) { 10935 char *buf; 10936 10937 buf = safe_malloc(max_scf_name_len + 1); 10938 if (scf_instance_get_name(cur_inst, buf, 10939 max_scf_name_len + 1) >= 0) { 10940 if (strcmp(buf, fmri) == 0) { 10941 semerr(emsg_cant_modify_snapshots); 10942 free(buf); 10943 return; 10944 } 10945 } else if (scf_error() != SCF_ERROR_DELETED) { 10946 scfdie(); 10947 } 10948 free(buf); 10949 } 10950 } else if (cur_inst != NULL) { 10951 /* EMPTY */; 10952 } else if (cur_svc != NULL) { 10953 inst = scf_instance_create(g_hndl); 10954 if (inst == NULL) 10955 scfdie(); 10956 10957 if (scf_service_get_instance(cur_svc, fmri, inst) == 10958 SCF_SUCCESS) { 10959 (void) lscf_instance_delete(inst, force); 10960 scf_instance_destroy(inst); 10961 return; 10962 } 10963 10964 if (scf_error() != SCF_ERROR_NOT_FOUND && 10965 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 10966 scfdie(); 10967 10968 scf_instance_destroy(inst); 10969 } else { 10970 assert(cur_scope != NULL); 10971 10972 svc = scf_service_create(g_hndl); 10973 if (svc == NULL) 10974 scfdie(); 10975 10976 if (scf_scope_get_service(cur_scope, fmri, svc) == 10977 SCF_SUCCESS) { 10978 (void) lscf_service_delete(svc, force); 10979 scf_service_destroy(svc); 10980 return; 10981 } 10982 10983 if (scf_error() != SCF_ERROR_NOT_FOUND && 10984 scf_error() != SCF_ERROR_INVALID_ARGUMENT) 10985 scfdie(); 10986 10987 scf_service_destroy(svc); 10988 } 10989 10990 /* 10991 * Match FMRI to entity. 10992 */ 10993 if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE, 10994 delete_callback, (void *)force, NULL, semerr)) != 0) { 10995 semerr(gettext("Failed to walk instances: %s\n"), 10996 scf_strerror(ret)); 10997 } 10998 } 10999 11000 11001 11002 /* 11003 * :properties commands. These all end with "pg" or "prop" and generally 11004 * operate on the currently selected entity. 11005 */ 11006 11007 /* 11008 * Property listing. List the property groups, properties, their types and 11009 * their values for the currently selected entity. 11010 */ 11011 static void 11012 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth) 11013 { 11014 char *buf; 11015 uint32_t flags; 11016 11017 buf = safe_malloc(max_scf_pg_type_len + 1); 11018 11019 if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0) 11020 scfdie(); 11021 11022 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 11023 scfdie(); 11024 11025 safe_printf("%-*s %s", namewidth, name, buf); 11026 11027 if (flags & SCF_PG_FLAG_NONPERSISTENT) 11028 safe_printf("\tNONPERSISTENT"); 11029 11030 safe_printf("\n"); 11031 11032 free(buf); 11033 } 11034 11035 static boolean_t 11036 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val) 11037 { 11038 if (scf_property_get_value(prop, val) == 0) { 11039 return (B_FALSE); 11040 } else { 11041 switch (scf_error()) { 11042 case SCF_ERROR_NOT_FOUND: 11043 return (B_FALSE); 11044 case SCF_ERROR_PERMISSION_DENIED: 11045 case SCF_ERROR_CONSTRAINT_VIOLATED: 11046 return (B_TRUE); 11047 default: 11048 scfdie(); 11049 /*NOTREACHED*/ 11050 } 11051 } 11052 } 11053 11054 static void 11055 list_prop_info(const scf_property_t *prop, const char *name, size_t len) 11056 { 11057 scf_iter_t *iter; 11058 scf_value_t *val; 11059 const char *type; 11060 int multiple_strings = 0; 11061 int ret; 11062 11063 if ((iter = scf_iter_create(g_hndl)) == NULL || 11064 (val = scf_value_create(g_hndl)) == NULL) 11065 scfdie(); 11066 11067 type = prop_to_typestr(prop); 11068 assert(type != NULL); 11069 11070 safe_printf("%-*s %-7s ", len, name, type); 11071 11072 if (prop_has_multiple_values(prop, val) && 11073 (scf_value_type(val) == SCF_TYPE_ASTRING || 11074 scf_value_type(val) == SCF_TYPE_USTRING)) 11075 multiple_strings = 1; 11076 11077 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11078 scfdie(); 11079 11080 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11081 char *buf; 11082 ssize_t vlen, szret; 11083 11084 vlen = scf_value_get_as_string(val, NULL, 0); 11085 if (vlen < 0) 11086 scfdie(); 11087 11088 buf = safe_malloc(vlen + 1); 11089 11090 szret = scf_value_get_as_string(val, buf, vlen + 1); 11091 if (szret < 0) 11092 scfdie(); 11093 assert(szret <= vlen); 11094 11095 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11096 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) { 11097 safe_printf(" \""); 11098 (void) quote_and_print(buf, stdout, 0); 11099 (void) putchar('"'); 11100 if (ferror(stdout)) { 11101 (void) putchar('\n'); 11102 uu_die(gettext("Error writing to stdout.\n")); 11103 } 11104 } else { 11105 safe_printf(" %s", buf); 11106 } 11107 11108 free(buf); 11109 } 11110 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11111 scfdie(); 11112 11113 if (putchar('\n') != '\n') 11114 uu_die(gettext("Could not output newline")); 11115 } 11116 11117 /* 11118 * Outputs template property group info for the describe subcommand. 11119 * If 'templates' == 2, verbose output is printed in the format expected 11120 * for describe -v, which includes all templates fields. If pg is 11121 * not NULL, we're describing the template data, not an existing property 11122 * group, and formatting should be appropriate for describe -t. 11123 */ 11124 static void 11125 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates) 11126 { 11127 char *buf; 11128 uint8_t required; 11129 scf_property_t *stability_prop; 11130 scf_value_t *stability_val; 11131 11132 if (templates == 0) 11133 return; 11134 11135 if ((stability_prop = scf_property_create(g_hndl)) == NULL || 11136 (stability_val = scf_value_create(g_hndl)) == NULL) 11137 scfdie(); 11138 11139 if (templates == 2 && pg != NULL) { 11140 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY, 11141 stability_prop) == 0) { 11142 if (prop_check_type(stability_prop, 11143 SCF_TYPE_ASTRING) == 0 && 11144 prop_get_val(stability_prop, stability_val) == 0) { 11145 char *stability; 11146 11147 stability = safe_malloc(max_scf_value_len + 1); 11148 11149 if (scf_value_get_astring(stability_val, 11150 stability, max_scf_value_len + 1) == -1 && 11151 scf_error() != SCF_ERROR_NOT_FOUND) 11152 scfdie(); 11153 11154 safe_printf("%s%s: %s\n", TMPL_INDENT, 11155 gettext("stability"), stability); 11156 11157 free(stability); 11158 } 11159 } else if (scf_error() != SCF_ERROR_NOT_FOUND) 11160 scfdie(); 11161 } 11162 11163 scf_property_destroy(stability_prop); 11164 scf_value_destroy(stability_val); 11165 11166 if (pgt == NULL) 11167 return; 11168 11169 if (pg == NULL || templates == 2) { 11170 /* print type info only if scf_tmpl_pg_name succeeds */ 11171 if (scf_tmpl_pg_name(pgt, &buf) != -1) { 11172 if (pg != NULL) 11173 safe_printf("%s", TMPL_INDENT); 11174 safe_printf("%s: ", gettext("name")); 11175 safe_printf("%s\n", buf); 11176 free(buf); 11177 } 11178 11179 /* print type info only if scf_tmpl_pg_type succeeds */ 11180 if (scf_tmpl_pg_type(pgt, &buf) != -1) { 11181 if (pg != NULL) 11182 safe_printf("%s", TMPL_INDENT); 11183 safe_printf("%s: ", gettext("type")); 11184 safe_printf("%s\n", buf); 11185 free(buf); 11186 } 11187 } 11188 11189 if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0) 11190 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11191 required ? "true" : "false"); 11192 11193 if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) { 11194 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"), 11195 buf); 11196 free(buf); 11197 } 11198 11199 if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) { 11200 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11201 buf); 11202 free(buf); 11203 } 11204 11205 if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) { 11206 if (templates == 2) 11207 safe_printf("%s%s: %s\n", TMPL_INDENT, 11208 gettext("description"), buf); 11209 else 11210 safe_printf("%s%s\n", TMPL_INDENT, buf); 11211 free(buf); 11212 } 11213 11214 } 11215 11216 /* 11217 * With as_value set to true, indent as appropriate for the value level. 11218 * If false, indent to appropriate level for inclusion in constraint 11219 * or choice printout. 11220 */ 11221 static void 11222 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf, 11223 int as_value) 11224 { 11225 char *buf; 11226 11227 if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) { 11228 if (as_value == 0) 11229 safe_printf("%s", TMPL_CHOICE_INDENT); 11230 else 11231 safe_printf("%s", TMPL_INDENT); 11232 safe_printf("%s: %s\n", gettext("value common name"), buf); 11233 free(buf); 11234 } 11235 11236 if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) { 11237 if (as_value == 0) 11238 safe_printf("%s", TMPL_CHOICE_INDENT); 11239 else 11240 safe_printf("%s", TMPL_INDENT); 11241 safe_printf("%s: %s\n", gettext("value description"), buf); 11242 free(buf); 11243 } 11244 } 11245 11246 static void 11247 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf) 11248 { 11249 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value")); 11250 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */ 11251 safe_printf("%s\n", val_buf); 11252 11253 print_template_value_details(prt, val_buf, 1); 11254 } 11255 11256 static void 11257 print_template_constraints(scf_prop_tmpl_t *prt, int verbose) 11258 { 11259 int i, printed = 0; 11260 scf_values_t values; 11261 scf_count_ranges_t c_ranges; 11262 scf_int_ranges_t i_ranges; 11263 11264 printed = 0; 11265 i = 0; 11266 if (scf_tmpl_value_name_constraints(prt, &values) == 0) { 11267 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11268 gettext("value constraints")); 11269 printed++; 11270 for (i = 0; i < values.value_count; ++i) { 11271 safe_printf("%s%s: %s\n", TMPL_INDENT, 11272 gettext("value name"), values.values_as_strings[i]); 11273 if (verbose == 1) 11274 print_template_value_details(prt, 11275 values.values_as_strings[i], 0); 11276 } 11277 11278 scf_values_destroy(&values); 11279 } 11280 11281 if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) { 11282 if (printed++ == 0) 11283 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11284 gettext("value constraints")); 11285 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11286 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11287 gettext("range"), c_ranges.scr_min[i], 11288 c_ranges.scr_max[i]); 11289 } 11290 scf_count_ranges_destroy(&c_ranges); 11291 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11292 scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) { 11293 if (printed++ == 0) 11294 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11295 gettext("value constraints")); 11296 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11297 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11298 gettext("range"), i_ranges.sir_min[i], 11299 i_ranges.sir_max[i]); 11300 } 11301 scf_int_ranges_destroy(&i_ranges); 11302 } 11303 } 11304 11305 static void 11306 print_template_choices(scf_prop_tmpl_t *prt, int verbose) 11307 { 11308 int i = 0, printed = 0; 11309 scf_values_t values; 11310 scf_count_ranges_t c_ranges; 11311 scf_int_ranges_t i_ranges; 11312 11313 printed = 0; 11314 if (scf_tmpl_value_name_choices(prt, &values) == 0) { 11315 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11316 gettext("value constraints")); 11317 printed++; 11318 for (i = 0; i < values.value_count; i++) { 11319 safe_printf("%s%s: %s\n", TMPL_INDENT, 11320 gettext("value name"), values.values_as_strings[i]); 11321 if (verbose == 1) 11322 print_template_value_details(prt, 11323 values.values_as_strings[i], 0); 11324 } 11325 11326 scf_values_destroy(&values); 11327 } 11328 11329 if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) { 11330 for (i = 0; i < c_ranges.scr_num_ranges; ++i) { 11331 if (printed++ == 0) 11332 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11333 gettext("value choices")); 11334 safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT, 11335 gettext("range"), c_ranges.scr_min[i], 11336 c_ranges.scr_max[i]); 11337 } 11338 scf_count_ranges_destroy(&c_ranges); 11339 } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED && 11340 scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) { 11341 for (i = 0; i < i_ranges.sir_num_ranges; ++i) { 11342 if (printed++ == 0) 11343 safe_printf("%s%s:\n", TMPL_VALUE_INDENT, 11344 gettext("value choices")); 11345 safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT, 11346 gettext("range"), i_ranges.sir_min[i], 11347 i_ranges.sir_max[i]); 11348 } 11349 scf_int_ranges_destroy(&i_ranges); 11350 } 11351 } 11352 11353 static void 11354 list_values_by_template(scf_prop_tmpl_t *prt) 11355 { 11356 print_template_constraints(prt, 1); 11357 print_template_choices(prt, 1); 11358 } 11359 11360 static void 11361 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop) 11362 { 11363 char *val_buf; 11364 scf_iter_t *iter; 11365 scf_value_t *val; 11366 int ret; 11367 11368 if ((iter = scf_iter_create(g_hndl)) == NULL || 11369 (val = scf_value_create(g_hndl)) == NULL) 11370 scfdie(); 11371 11372 if (scf_iter_property_values(iter, prop) != SCF_SUCCESS) 11373 scfdie(); 11374 11375 val_buf = safe_malloc(max_scf_value_len + 1); 11376 11377 while ((ret = scf_iter_next_value(iter, val)) == 1) { 11378 if (scf_value_get_as_string(val, val_buf, 11379 max_scf_value_len + 1) < 0) 11380 scfdie(); 11381 11382 print_template_value(prt, val_buf); 11383 } 11384 if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 11385 scfdie(); 11386 free(val_buf); 11387 11388 print_template_constraints(prt, 0); 11389 print_template_choices(prt, 0); 11390 11391 } 11392 11393 /* 11394 * Outputs property info for the describe subcommand 11395 * Verbose output if templates == 2, -v option of svccfg describe 11396 * Displays template data if prop is not NULL, -t option of svccfg describe 11397 */ 11398 static void 11399 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates) 11400 { 11401 char *buf; 11402 uint8_t u_buf; 11403 int i; 11404 uint64_t min, max; 11405 scf_values_t values; 11406 11407 if (prt == NULL || templates == 0) 11408 return; 11409 11410 if (prop == NULL) { 11411 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name")); 11412 if (scf_tmpl_prop_name(prt, &buf) > 0) { 11413 safe_printf("%s\n", buf); 11414 free(buf); 11415 } else 11416 safe_printf("(%s)\n", gettext("any")); 11417 } 11418 11419 if (prop == NULL || templates == 2) { 11420 if (prop != NULL) 11421 safe_printf("%s", TMPL_INDENT); 11422 else 11423 safe_printf("%s", TMPL_VALUE_INDENT); 11424 safe_printf("%s: ", gettext("type")); 11425 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) { 11426 safe_printf("%s\n", buf); 11427 free(buf); 11428 } else 11429 safe_printf("(%s)\n", gettext("any")); 11430 } 11431 11432 if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0) 11433 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"), 11434 u_buf ? "true" : "false"); 11435 11436 if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) { 11437 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"), 11438 buf); 11439 free(buf); 11440 } 11441 11442 if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) { 11443 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"), 11444 buf); 11445 free(buf); 11446 } 11447 11448 if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) { 11449 safe_printf("%s%s\n", TMPL_INDENT, buf); 11450 free(buf); 11451 } 11452 11453 if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0) 11454 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"), 11455 scf_tmpl_visibility_to_string(u_buf)); 11456 11457 if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) { 11458 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11459 gettext("minimum number of values"), min); 11460 if (max == ULLONG_MAX) { 11461 safe_printf("%s%s: %s\n", TMPL_INDENT, 11462 gettext("maximum number of values"), 11463 gettext("unlimited")); 11464 } else { 11465 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT, 11466 gettext("maximum number of values"), max); 11467 } 11468 } 11469 11470 if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) { 11471 for (i = 0; i < values.value_count; i++) { 11472 if (i == 0) { 11473 safe_printf("%s%s:", TMPL_INDENT, 11474 gettext("internal separators")); 11475 } 11476 safe_printf(" \"%s\"", values.values_as_strings[i]); 11477 } 11478 safe_printf("\n"); 11479 } 11480 11481 if (templates != 2) 11482 return; 11483 11484 if (prop != NULL) 11485 list_values_tmpl(prt, prop); 11486 else 11487 list_values_by_template(prt); 11488 } 11489 11490 static char * 11491 read_astring(scf_propertygroup_t *pg, const char *prop_name) 11492 { 11493 char *rv; 11494 11495 rv = _scf_read_single_astring_from_pg(pg, prop_name); 11496 if (rv == NULL) { 11497 switch (scf_error()) { 11498 case SCF_ERROR_NOT_FOUND: 11499 break; 11500 default: 11501 scfdie(); 11502 } 11503 } 11504 return (rv); 11505 } 11506 11507 static void 11508 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg) 11509 { 11510 size_t doc_len; 11511 size_t man_len; 11512 char *pg_name; 11513 char *text = NULL; 11514 int rv; 11515 11516 doc_len = strlen(SCF_PG_TM_DOC_PREFIX); 11517 man_len = strlen(SCF_PG_TM_MAN_PREFIX); 11518 pg_name = safe_malloc(max_scf_name_len + 1); 11519 while ((rv = scf_iter_next_pg(iter, pg)) == 1) { 11520 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) { 11521 scfdie(); 11522 } 11523 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) { 11524 /* Display doc_link and and uri */ 11525 safe_printf("%s%s:\n", TMPL_INDENT, 11526 gettext("doc_link")); 11527 text = read_astring(pg, SCF_PROPERTY_TM_NAME); 11528 if (text != NULL) { 11529 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11530 TMPL_INDENT, gettext("name"), text); 11531 uu_free(text); 11532 } 11533 text = read_astring(pg, SCF_PROPERTY_TM_URI); 11534 if (text != NULL) { 11535 safe_printf("%s%s: %s\n", TMPL_INDENT_2X, 11536 gettext("uri"), text); 11537 uu_free(text); 11538 } 11539 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX, 11540 man_len) == 0) { 11541 /* Display manpage title, section and path */ 11542 safe_printf("%s%s:\n", TMPL_INDENT, 11543 gettext("manpage")); 11544 text = read_astring(pg, SCF_PROPERTY_TM_TITLE); 11545 if (text != NULL) { 11546 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11547 TMPL_INDENT, gettext("title"), text); 11548 uu_free(text); 11549 } 11550 text = read_astring(pg, SCF_PROPERTY_TM_SECTION); 11551 if (text != NULL) { 11552 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11553 TMPL_INDENT, gettext("section"), text); 11554 uu_free(text); 11555 } 11556 text = read_astring(pg, SCF_PROPERTY_TM_MANPATH); 11557 if (text != NULL) { 11558 safe_printf("%s%s%s: %s\n", TMPL_INDENT, 11559 TMPL_INDENT, gettext("manpath"), text); 11560 uu_free(text); 11561 } 11562 } 11563 } 11564 if (rv == -1) 11565 scfdie(); 11566 11567 done: 11568 free(pg_name); 11569 } 11570 11571 static void 11572 list_entity_tmpl(int templates) 11573 { 11574 char *common_name = NULL; 11575 char *description = NULL; 11576 char *locale = NULL; 11577 scf_iter_t *iter; 11578 scf_propertygroup_t *pg; 11579 scf_property_t *prop; 11580 int r; 11581 scf_value_t *val; 11582 11583 if ((pg = scf_pg_create(g_hndl)) == NULL || 11584 (prop = scf_property_create(g_hndl)) == NULL || 11585 (val = scf_value_create(g_hndl)) == NULL || 11586 (iter = scf_iter_create(g_hndl)) == NULL) 11587 scfdie(); 11588 11589 locale = setlocale(LC_MESSAGES, NULL); 11590 11591 if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) { 11592 common_name = safe_malloc(max_scf_value_len + 1); 11593 11594 /* Try both the current locale and the "C" locale. */ 11595 if (scf_pg_get_property(pg, locale, prop) == 0 || 11596 (scf_error() == SCF_ERROR_NOT_FOUND && 11597 scf_pg_get_property(pg, "C", prop) == 0)) { 11598 if (prop_get_val(prop, val) == 0 && 11599 scf_value_get_ustring(val, common_name, 11600 max_scf_value_len + 1) != -1) { 11601 safe_printf("%s%s: %s\n", TMPL_INDENT, 11602 gettext("common name"), common_name); 11603 } 11604 } 11605 } 11606 11607 /* 11608 * Do description, manpages, and doc links if templates == 2. 11609 */ 11610 if (templates == 2) { 11611 /* Get the description. */ 11612 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) { 11613 description = safe_malloc(max_scf_value_len + 1); 11614 11615 /* Try both the current locale and the "C" locale. */ 11616 if (scf_pg_get_property(pg, locale, prop) == 0 || 11617 (scf_error() == SCF_ERROR_NOT_FOUND && 11618 scf_pg_get_property(pg, "C", prop) == 0)) { 11619 if (prop_get_val(prop, val) == 0 && 11620 scf_value_get_ustring(val, description, 11621 max_scf_value_len + 1) != -1) { 11622 safe_printf("%s%s: %s\n", TMPL_INDENT, 11623 gettext("description"), 11624 description); 11625 } 11626 } 11627 } 11628 11629 /* Process doc_link & manpage elements. */ 11630 if (cur_level != NULL) { 11631 r = scf_iter_snaplevel_pgs_typed(iter, cur_level, 11632 SCF_GROUP_TEMPLATE); 11633 } else if (cur_inst != NULL) { 11634 r = scf_iter_instance_pgs_typed(iter, cur_inst, 11635 SCF_GROUP_TEMPLATE); 11636 } else { 11637 r = scf_iter_service_pgs_typed(iter, cur_svc, 11638 SCF_GROUP_TEMPLATE); 11639 } 11640 if (r == 0) { 11641 display_documentation(iter, pg); 11642 } 11643 } 11644 11645 free(common_name); 11646 free(description); 11647 scf_pg_destroy(pg); 11648 scf_property_destroy(prop); 11649 scf_value_destroy(val); 11650 scf_iter_destroy(iter); 11651 } 11652 11653 static void 11654 listtmpl(const char *pattern, int templates) 11655 { 11656 scf_pg_tmpl_t *pgt; 11657 scf_prop_tmpl_t *prt; 11658 char *snapbuf = NULL; 11659 char *fmribuf; 11660 char *pg_name = NULL, *prop_name = NULL; 11661 ssize_t prop_name_size; 11662 char *qual_prop_name; 11663 char *search_name; 11664 int listed = 0; 11665 11666 if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 11667 (prt = scf_tmpl_prop_create(g_hndl)) == NULL) 11668 scfdie(); 11669 11670 fmribuf = safe_malloc(max_scf_name_len + 1); 11671 qual_prop_name = safe_malloc(max_scf_name_len + 1); 11672 11673 if (cur_snap != NULL) { 11674 snapbuf = safe_malloc(max_scf_name_len + 1); 11675 if (scf_snapshot_get_name(cur_snap, snapbuf, 11676 max_scf_name_len + 1) < 0) 11677 scfdie(); 11678 } 11679 11680 if (cur_inst != NULL) { 11681 if (scf_instance_to_fmri(cur_inst, fmribuf, 11682 max_scf_name_len + 1) < 0) 11683 scfdie(); 11684 } else if (cur_svc != NULL) { 11685 if (scf_service_to_fmri(cur_svc, fmribuf, 11686 max_scf_name_len + 1) < 0) 11687 scfdie(); 11688 } else 11689 abort(); 11690 11691 /* If pattern is specified, we want to list only those items. */ 11692 while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) { 11693 listed = 0; 11694 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 && 11695 fnmatch(pattern, pg_name, 0) == 0)) { 11696 list_pg_tmpl(pgt, NULL, templates); 11697 listed++; 11698 } 11699 11700 scf_tmpl_prop_reset(prt); 11701 11702 while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) { 11703 search_name = NULL; 11704 prop_name_size = scf_tmpl_prop_name(prt, &prop_name); 11705 if ((prop_name_size > 0) && (pg_name != NULL)) { 11706 if (snprintf(qual_prop_name, 11707 max_scf_name_len + 1, "%s/%s", 11708 pg_name, prop_name) >= 11709 max_scf_name_len + 1) { 11710 prop_name_size = -1; 11711 } else { 11712 search_name = qual_prop_name; 11713 } 11714 } 11715 if (listed > 0 || pattern == NULL || 11716 (prop_name_size > 0 && 11717 fnmatch(pattern, search_name, 11718 FNM_PATHNAME) == 0)) 11719 list_prop_tmpl(prt, NULL, templates); 11720 if (prop_name != NULL) { 11721 free(prop_name); 11722 prop_name = NULL; 11723 } 11724 } 11725 if (pg_name != NULL) { 11726 free(pg_name); 11727 pg_name = NULL; 11728 } 11729 } 11730 11731 scf_tmpl_prop_destroy(prt); 11732 scf_tmpl_pg_destroy(pgt); 11733 free(snapbuf); 11734 free(fmribuf); 11735 free(qual_prop_name); 11736 } 11737 11738 static void 11739 listprop(const char *pattern, int only_pgs, int templates) 11740 { 11741 scf_propertygroup_t *pg; 11742 scf_property_t *prop; 11743 scf_iter_t *iter, *piter; 11744 char *pgnbuf, *prnbuf, *ppnbuf; 11745 scf_pg_tmpl_t *pgt, *pgtp; 11746 scf_prop_tmpl_t *prt; 11747 11748 void **objects; 11749 char **names; 11750 void **tmpls; 11751 int allocd, i; 11752 11753 int ret; 11754 ssize_t pgnlen, prnlen, szret; 11755 size_t max_len = 0; 11756 11757 if (cur_svc == NULL && cur_inst == NULL) { 11758 semerr(emsg_entity_not_selected); 11759 return; 11760 } 11761 11762 if ((pg = scf_pg_create(g_hndl)) == NULL || 11763 (prop = scf_property_create(g_hndl)) == NULL || 11764 (iter = scf_iter_create(g_hndl)) == NULL || 11765 (piter = scf_iter_create(g_hndl)) == NULL || 11766 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 11767 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL) 11768 scfdie(); 11769 11770 prnbuf = safe_malloc(max_scf_name_len + 1); 11771 11772 if (cur_level != NULL) 11773 ret = scf_iter_snaplevel_pgs(iter, cur_level); 11774 else if (cur_inst != NULL) 11775 ret = scf_iter_instance_pgs(iter, cur_inst); 11776 else 11777 ret = scf_iter_service_pgs(iter, cur_svc); 11778 if (ret != 0) { 11779 return; 11780 } 11781 11782 /* 11783 * We want to only list items which match pattern, and we want the 11784 * second column to line up, so during the first pass we'll save 11785 * matching items, their names, and their templates in objects, 11786 * names, and tmpls, computing the maximum name length as we go, 11787 * and then we'll print them out. 11788 * 11789 * Note: We always keep an extra slot available so the array can be 11790 * NULL-terminated. 11791 */ 11792 i = 0; 11793 allocd = 1; 11794 objects = safe_malloc(sizeof (*objects)); 11795 names = safe_malloc(sizeof (*names)); 11796 tmpls = safe_malloc(sizeof (*tmpls)); 11797 11798 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 11799 int new_pg = 0; 11800 int print_props = 0; 11801 pgtp = NULL; 11802 11803 pgnlen = scf_pg_get_name(pg, NULL, 0); 11804 if (pgnlen < 0) 11805 scfdie(); 11806 11807 pgnbuf = safe_malloc(pgnlen + 1); 11808 11809 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1); 11810 if (szret < 0) 11811 scfdie(); 11812 assert(szret <= pgnlen); 11813 11814 if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) { 11815 if (scf_error() != SCF_ERROR_NOT_FOUND) 11816 scfdie(); 11817 pgtp = NULL; 11818 } else { 11819 pgtp = pgt; 11820 } 11821 11822 if (pattern == NULL || 11823 fnmatch(pattern, pgnbuf, 0) == 0) { 11824 if (i+1 >= allocd) { 11825 allocd *= 2; 11826 objects = realloc(objects, 11827 sizeof (*objects) * allocd); 11828 names = 11829 realloc(names, sizeof (*names) * allocd); 11830 tmpls = realloc(tmpls, 11831 sizeof (*tmpls) * allocd); 11832 if (objects == NULL || names == NULL || 11833 tmpls == NULL) 11834 uu_die(gettext("Out of memory")); 11835 } 11836 objects[i] = pg; 11837 names[i] = pgnbuf; 11838 11839 if (pgtp == NULL) 11840 tmpls[i] = NULL; 11841 else 11842 tmpls[i] = pgt; 11843 11844 ++i; 11845 11846 if (pgnlen > max_len) 11847 max_len = pgnlen; 11848 11849 new_pg = 1; 11850 print_props = 1; 11851 } 11852 11853 if (only_pgs) { 11854 if (new_pg) { 11855 pg = scf_pg_create(g_hndl); 11856 if (pg == NULL) 11857 scfdie(); 11858 pgt = scf_tmpl_pg_create(g_hndl); 11859 if (pgt == NULL) 11860 scfdie(); 11861 } else 11862 free(pgnbuf); 11863 11864 continue; 11865 } 11866 11867 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 11868 scfdie(); 11869 11870 while ((ret = scf_iter_next_property(piter, prop)) == 1) { 11871 prnlen = scf_property_get_name(prop, prnbuf, 11872 max_scf_name_len + 1); 11873 if (prnlen < 0) 11874 scfdie(); 11875 11876 /* Will prepend the property group name and a slash. */ 11877 prnlen += pgnlen + 1; 11878 11879 ppnbuf = safe_malloc(prnlen + 1); 11880 11881 if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf, 11882 prnbuf) < 0) 11883 uu_die("snprintf"); 11884 11885 if (pattern == NULL || print_props == 1 || 11886 fnmatch(pattern, ppnbuf, 0) == 0) { 11887 if (i+1 >= allocd) { 11888 allocd *= 2; 11889 objects = realloc(objects, 11890 sizeof (*objects) * allocd); 11891 names = realloc(names, 11892 sizeof (*names) * allocd); 11893 tmpls = realloc(tmpls, 11894 sizeof (*tmpls) * allocd); 11895 if (objects == NULL || names == NULL || 11896 tmpls == NULL) 11897 uu_die(gettext( 11898 "Out of memory")); 11899 } 11900 11901 objects[i] = prop; 11902 names[i] = ppnbuf; 11903 11904 if (pgtp != NULL) { 11905 if (scf_tmpl_get_by_prop(pgt, prnbuf, 11906 prt, NULL) < 0) { 11907 if (scf_error() != 11908 SCF_ERROR_NOT_FOUND) 11909 scfdie(); 11910 tmpls[i] = NULL; 11911 } else { 11912 tmpls[i] = prt; 11913 } 11914 } else { 11915 tmpls[i] = NULL; 11916 } 11917 11918 ++i; 11919 11920 if (prnlen > max_len) 11921 max_len = prnlen; 11922 11923 prop = scf_property_create(g_hndl); 11924 prt = scf_tmpl_prop_create(g_hndl); 11925 } else { 11926 free(ppnbuf); 11927 } 11928 } 11929 11930 if (new_pg) { 11931 pg = scf_pg_create(g_hndl); 11932 if (pg == NULL) 11933 scfdie(); 11934 pgt = scf_tmpl_pg_create(g_hndl); 11935 if (pgt == NULL) 11936 scfdie(); 11937 } else 11938 free(pgnbuf); 11939 } 11940 if (ret != 0) 11941 scfdie(); 11942 11943 objects[i] = NULL; 11944 11945 scf_pg_destroy(pg); 11946 scf_tmpl_pg_destroy(pgt); 11947 scf_property_destroy(prop); 11948 scf_tmpl_prop_destroy(prt); 11949 11950 for (i = 0; objects[i] != NULL; ++i) { 11951 if (strchr(names[i], '/') == NULL) { 11952 /* property group */ 11953 pg = (scf_propertygroup_t *)objects[i]; 11954 pgt = (scf_pg_tmpl_t *)tmpls[i]; 11955 list_pg_info(pg, names[i], max_len); 11956 list_pg_tmpl(pgt, pg, templates); 11957 free(names[i]); 11958 scf_pg_destroy(pg); 11959 if (pgt != NULL) 11960 scf_tmpl_pg_destroy(pgt); 11961 } else { 11962 /* property */ 11963 prop = (scf_property_t *)objects[i]; 11964 prt = (scf_prop_tmpl_t *)tmpls[i]; 11965 list_prop_info(prop, names[i], max_len); 11966 list_prop_tmpl(prt, prop, templates); 11967 free(names[i]); 11968 scf_property_destroy(prop); 11969 if (prt != NULL) 11970 scf_tmpl_prop_destroy(prt); 11971 } 11972 } 11973 11974 free(names); 11975 free(objects); 11976 free(tmpls); 11977 } 11978 11979 void 11980 lscf_listpg(const char *pattern) 11981 { 11982 lscf_prep_hndl(); 11983 11984 listprop(pattern, 1, 0); 11985 } 11986 11987 /* 11988 * Property group and property creation, setting, and deletion. setprop (and 11989 * its alias, addprop) can either create a property group of a given type, or 11990 * it can create or set a property to a given type and list of values. 11991 */ 11992 void 11993 lscf_addpg(const char *name, const char *type, const char *flags) 11994 { 11995 scf_propertygroup_t *pg; 11996 int ret; 11997 uint32_t flgs = 0; 11998 const char *cp; 11999 12000 12001 lscf_prep_hndl(); 12002 12003 if (cur_snap != NULL) { 12004 semerr(emsg_cant_modify_snapshots); 12005 return; 12006 } 12007 12008 if (cur_inst == NULL && cur_svc == NULL) { 12009 semerr(emsg_entity_not_selected); 12010 return; 12011 } 12012 12013 if (flags != NULL) { 12014 for (cp = flags; *cp != '\0'; ++cp) { 12015 switch (*cp) { 12016 case 'P': 12017 flgs |= SCF_PG_FLAG_NONPERSISTENT; 12018 break; 12019 12020 case 'p': 12021 flgs &= ~SCF_PG_FLAG_NONPERSISTENT; 12022 break; 12023 12024 default: 12025 semerr(gettext("Invalid property group flag " 12026 "%c."), *cp); 12027 return; 12028 } 12029 } 12030 } 12031 12032 pg = scf_pg_create(g_hndl); 12033 if (pg == NULL) 12034 scfdie(); 12035 12036 if (cur_inst != NULL) 12037 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg); 12038 else 12039 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg); 12040 12041 if (ret != SCF_SUCCESS) { 12042 switch (scf_error()) { 12043 case SCF_ERROR_INVALID_ARGUMENT: 12044 semerr(gettext("Name, type, or flags are invalid.\n")); 12045 break; 12046 12047 case SCF_ERROR_EXISTS: 12048 semerr(gettext("Property group already exists.\n")); 12049 break; 12050 12051 case SCF_ERROR_PERMISSION_DENIED: 12052 semerr(emsg_permission_denied); 12053 break; 12054 12055 case SCF_ERROR_BACKEND_ACCESS: 12056 semerr(gettext("Backend refused access.\n")); 12057 break; 12058 12059 default: 12060 scfdie(); 12061 } 12062 } 12063 12064 scf_pg_destroy(pg); 12065 12066 private_refresh(); 12067 } 12068 12069 void 12070 lscf_delpg(char *name) 12071 { 12072 lscf_prep_hndl(); 12073 12074 if (cur_snap != NULL) { 12075 semerr(emsg_cant_modify_snapshots); 12076 return; 12077 } 12078 12079 if (cur_inst == NULL && cur_svc == NULL) { 12080 semerr(emsg_entity_not_selected); 12081 return; 12082 } 12083 12084 if (strchr(name, '/') != NULL) { 12085 semerr(emsg_invalid_pg_name, name); 12086 return; 12087 } 12088 12089 lscf_delprop(name); 12090 } 12091 12092 /* 12093 * scf_delhash() is used to remove the property group related to the 12094 * hash entry for a specific manifest in the repository. pgname will be 12095 * constructed from the location of the manifest file. If deathrow isn't 0, 12096 * manifest file doesn't need to exist (manifest string will be used as 12097 * an absolute path). 12098 */ 12099 void 12100 lscf_delhash(char *manifest, int deathrow) 12101 { 12102 char *pgname; 12103 12104 if (cur_snap != NULL || 12105 cur_inst != NULL || cur_svc != NULL) { 12106 warn(gettext("error, an entity is selected\n")); 12107 return; 12108 } 12109 12110 /* select smf/manifest */ 12111 lscf_select("smf/manifest"); 12112 /* 12113 * Translate the manifest file name to property name. In the deathrow 12114 * case, the manifest file does not need to exist. 12115 */ 12116 pgname = mhash_filename_to_propname(manifest, 12117 deathrow ? B_TRUE : B_FALSE); 12118 if (pgname == NULL) { 12119 warn(gettext("cannot resolve pathname for %s\n"), manifest); 12120 return; 12121 } 12122 /* delete the hash property name */ 12123 lscf_delpg(pgname); 12124 } 12125 12126 void 12127 lscf_listprop(const char *pattern) 12128 { 12129 lscf_prep_hndl(); 12130 12131 listprop(pattern, 0, 0); 12132 } 12133 12134 int 12135 lscf_setprop(const char *pgname, const char *type, const char *value, 12136 const uu_list_t *values) 12137 { 12138 scf_type_t ty, current_ty; 12139 scf_service_t *svc; 12140 scf_propertygroup_t *pg, *parent_pg; 12141 scf_property_t *prop, *parent_prop; 12142 scf_pg_tmpl_t *pgt; 12143 scf_prop_tmpl_t *prt; 12144 int ret, result = 0; 12145 scf_transaction_t *tx; 12146 scf_transaction_entry_t *e; 12147 scf_value_t *v; 12148 uu_list_walk_t *walk; 12149 string_list_t *sp; 12150 char *propname; 12151 int req_quotes = 0; 12152 12153 lscf_prep_hndl(); 12154 12155 if ((e = scf_entry_create(g_hndl)) == NULL || 12156 (svc = scf_service_create(g_hndl)) == NULL || 12157 (parent_pg = scf_pg_create(g_hndl)) == NULL || 12158 (pg = scf_pg_create(g_hndl)) == NULL || 12159 (parent_prop = scf_property_create(g_hndl)) == NULL || 12160 (prop = scf_property_create(g_hndl)) == NULL || 12161 (pgt = scf_tmpl_pg_create(g_hndl)) == NULL || 12162 (prt = scf_tmpl_prop_create(g_hndl)) == NULL || 12163 (tx = scf_transaction_create(g_hndl)) == NULL) 12164 scfdie(); 12165 12166 if (cur_snap != NULL) { 12167 semerr(emsg_cant_modify_snapshots); 12168 goto fail; 12169 } 12170 12171 if (cur_inst == NULL && cur_svc == NULL) { 12172 semerr(emsg_entity_not_selected); 12173 goto fail; 12174 } 12175 12176 propname = strchr(pgname, '/'); 12177 if (propname == NULL) { 12178 semerr(gettext("Property names must contain a `/'.\n")); 12179 goto fail; 12180 } 12181 12182 *propname = '\0'; 12183 ++propname; 12184 12185 if (type != NULL) { 12186 ty = string_to_type(type); 12187 if (ty == SCF_TYPE_INVALID) { 12188 semerr(gettext("Unknown type \"%s\".\n"), type); 12189 goto fail; 12190 } 12191 } 12192 12193 if (cur_inst != NULL) 12194 ret = scf_instance_get_pg(cur_inst, pgname, pg); 12195 else 12196 ret = scf_service_get_pg(cur_svc, pgname, pg); 12197 if (ret != SCF_SUCCESS) { 12198 switch (scf_error()) { 12199 case SCF_ERROR_NOT_FOUND: 12200 semerr(emsg_no_such_pg, pgname); 12201 goto fail; 12202 12203 case SCF_ERROR_INVALID_ARGUMENT: 12204 semerr(emsg_invalid_pg_name, pgname); 12205 goto fail; 12206 12207 default: 12208 scfdie(); 12209 break; 12210 } 12211 } 12212 12213 do { 12214 if (scf_pg_update(pg) == -1) 12215 scfdie(); 12216 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12217 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12218 scfdie(); 12219 12220 semerr(emsg_permission_denied); 12221 goto fail; 12222 } 12223 12224 ret = scf_pg_get_property(pg, propname, prop); 12225 if (ret == SCF_SUCCESS) { 12226 if (scf_property_type(prop, ¤t_ty) != SCF_SUCCESS) 12227 scfdie(); 12228 12229 if (type == NULL) 12230 ty = current_ty; 12231 if (scf_transaction_property_change_type(tx, e, 12232 propname, ty) == -1) 12233 scfdie(); 12234 12235 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 12236 /* Infer the type, if possible. */ 12237 if (type == NULL) { 12238 /* 12239 * First check if we're an instance and the 12240 * property is set on the service. 12241 */ 12242 if (cur_inst != NULL && 12243 scf_instance_get_parent(cur_inst, 12244 svc) == 0 && 12245 scf_service_get_pg(cur_svc, pgname, 12246 parent_pg) == 0 && 12247 scf_pg_get_property(parent_pg, propname, 12248 parent_prop) == 0 && 12249 scf_property_type(parent_prop, 12250 ¤t_ty) == 0) { 12251 ty = current_ty; 12252 12253 /* Then check for a type set in a template. */ 12254 } else if (scf_tmpl_get_by_pg(pg, pgt, 12255 NULL) == 0 && 12256 scf_tmpl_get_by_prop(pgt, propname, prt, 12257 NULL) == 0 && 12258 scf_tmpl_prop_type(prt, ¤t_ty) == 0) { 12259 ty = current_ty; 12260 12261 /* If type can't be inferred, fail. */ 12262 } else { 12263 semerr(gettext("Type required for new " 12264 "properties.\n")); 12265 goto fail; 12266 } 12267 } 12268 if (scf_transaction_property_new(tx, e, propname, 12269 ty) == -1) 12270 scfdie(); 12271 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12272 semerr(emsg_invalid_prop_name, propname); 12273 goto fail; 12274 } else { 12275 scfdie(); 12276 } 12277 12278 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING) 12279 req_quotes = 1; 12280 12281 if (value != NULL) { 12282 v = string_to_value(value, ty, 0); 12283 12284 if (v == NULL) 12285 goto fail; 12286 12287 ret = scf_entry_add_value(e, v); 12288 assert(ret == SCF_SUCCESS); 12289 } else { 12290 assert(values != NULL); 12291 12292 walk = uu_list_walk_start((uu_list_t *)values, 12293 UU_DEFAULT); 12294 if (walk == NULL) 12295 uu_die(gettext("Could not walk list")); 12296 12297 for (sp = uu_list_walk_next(walk); sp != NULL; 12298 sp = uu_list_walk_next(walk)) { 12299 v = string_to_value(sp->str, ty, req_quotes); 12300 12301 if (v == NULL) { 12302 scf_entry_destroy_children(e); 12303 goto fail; 12304 } 12305 12306 ret = scf_entry_add_value(e, v); 12307 assert(ret == SCF_SUCCESS); 12308 } 12309 uu_list_walk_end(walk); 12310 } 12311 result = scf_transaction_commit(tx); 12312 12313 scf_transaction_reset(tx); 12314 scf_entry_destroy_children(e); 12315 } while (result == 0); 12316 12317 if (result < 0) { 12318 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12319 scfdie(); 12320 12321 semerr(emsg_permission_denied); 12322 goto fail; 12323 } 12324 12325 ret = 0; 12326 12327 private_refresh(); 12328 12329 goto cleanup; 12330 12331 fail: 12332 ret = -1; 12333 12334 cleanup: 12335 scf_transaction_destroy(tx); 12336 scf_entry_destroy(e); 12337 scf_service_destroy(svc); 12338 scf_pg_destroy(parent_pg); 12339 scf_pg_destroy(pg); 12340 scf_property_destroy(parent_prop); 12341 scf_property_destroy(prop); 12342 scf_tmpl_pg_destroy(pgt); 12343 scf_tmpl_prop_destroy(prt); 12344 12345 return (ret); 12346 } 12347 12348 void 12349 lscf_delprop(char *pgn) 12350 { 12351 char *slash, *pn; 12352 scf_propertygroup_t *pg; 12353 scf_transaction_t *tx; 12354 scf_transaction_entry_t *e; 12355 int ret; 12356 12357 12358 lscf_prep_hndl(); 12359 12360 if (cur_snap != NULL) { 12361 semerr(emsg_cant_modify_snapshots); 12362 return; 12363 } 12364 12365 if (cur_inst == NULL && cur_svc == NULL) { 12366 semerr(emsg_entity_not_selected); 12367 return; 12368 } 12369 12370 pg = scf_pg_create(g_hndl); 12371 if (pg == NULL) 12372 scfdie(); 12373 12374 slash = strchr(pgn, '/'); 12375 if (slash == NULL) { 12376 pn = NULL; 12377 } else { 12378 *slash = '\0'; 12379 pn = slash + 1; 12380 } 12381 12382 if (cur_inst != NULL) 12383 ret = scf_instance_get_pg(cur_inst, pgn, pg); 12384 else 12385 ret = scf_service_get_pg(cur_svc, pgn, pg); 12386 if (ret != SCF_SUCCESS) { 12387 switch (scf_error()) { 12388 case SCF_ERROR_NOT_FOUND: 12389 semerr(emsg_no_such_pg, pgn); 12390 break; 12391 12392 case SCF_ERROR_INVALID_ARGUMENT: 12393 semerr(emsg_invalid_pg_name, pgn); 12394 break; 12395 12396 default: 12397 scfdie(); 12398 } 12399 12400 scf_pg_destroy(pg); 12401 12402 return; 12403 } 12404 12405 if (pn == NULL) { 12406 /* Try to delete the property group. */ 12407 if (scf_pg_delete(pg) != SCF_SUCCESS) { 12408 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12409 scfdie(); 12410 12411 semerr(emsg_permission_denied); 12412 } else { 12413 private_refresh(); 12414 } 12415 12416 scf_pg_destroy(pg); 12417 return; 12418 } 12419 12420 e = scf_entry_create(g_hndl); 12421 tx = scf_transaction_create(g_hndl); 12422 12423 do { 12424 if (scf_pg_update(pg) == -1) 12425 scfdie(); 12426 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 12427 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12428 scfdie(); 12429 12430 semerr(emsg_permission_denied); 12431 break; 12432 } 12433 12434 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) { 12435 if (scf_error() == SCF_ERROR_NOT_FOUND) { 12436 semerr(gettext("No such property %s/%s.\n"), 12437 pgn, pn); 12438 break; 12439 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12440 semerr(emsg_invalid_prop_name, pn); 12441 break; 12442 } else { 12443 scfdie(); 12444 } 12445 } 12446 12447 ret = scf_transaction_commit(tx); 12448 12449 if (ret == 0) 12450 scf_transaction_reset(tx); 12451 } while (ret == 0); 12452 12453 if (ret < 0) { 12454 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12455 scfdie(); 12456 12457 semerr(emsg_permission_denied); 12458 } else { 12459 private_refresh(); 12460 } 12461 12462 scf_transaction_destroy(tx); 12463 scf_entry_destroy(e); 12464 scf_pg_destroy(pg); 12465 } 12466 12467 /* 12468 * Property editing. 12469 */ 12470 12471 static int 12472 write_edit_script(FILE *strm) 12473 { 12474 char *fmribuf; 12475 ssize_t fmrilen; 12476 12477 scf_propertygroup_t *pg; 12478 scf_property_t *prop; 12479 scf_value_t *val; 12480 scf_type_t ty; 12481 int ret, result = 0; 12482 scf_iter_t *iter, *piter, *viter; 12483 char *buf, *tybuf, *pname; 12484 const char *emsg_write_error; 12485 12486 12487 emsg_write_error = gettext("Error writing temoprary file: %s.\n"); 12488 12489 12490 /* select fmri */ 12491 if (cur_inst != NULL) { 12492 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0); 12493 if (fmrilen < 0) 12494 scfdie(); 12495 fmribuf = safe_malloc(fmrilen + 1); 12496 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0) 12497 scfdie(); 12498 } else { 12499 assert(cur_svc != NULL); 12500 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0); 12501 if (fmrilen < 0) 12502 scfdie(); 12503 fmribuf = safe_malloc(fmrilen + 1); 12504 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0) 12505 scfdie(); 12506 } 12507 12508 if (fprintf(strm, "select %s\n\n", fmribuf) < 0) { 12509 warn(emsg_write_error, strerror(errno)); 12510 free(fmribuf); 12511 return (-1); 12512 } 12513 12514 free(fmribuf); 12515 12516 12517 if ((pg = scf_pg_create(g_hndl)) == NULL || 12518 (prop = scf_property_create(g_hndl)) == NULL || 12519 (val = scf_value_create(g_hndl)) == NULL || 12520 (iter = scf_iter_create(g_hndl)) == NULL || 12521 (piter = scf_iter_create(g_hndl)) == NULL || 12522 (viter = scf_iter_create(g_hndl)) == NULL) 12523 scfdie(); 12524 12525 buf = safe_malloc(max_scf_name_len + 1); 12526 tybuf = safe_malloc(max_scf_pg_type_len + 1); 12527 pname = safe_malloc(max_scf_name_len + 1); 12528 12529 if (cur_inst != NULL) 12530 ret = scf_iter_instance_pgs(iter, cur_inst); 12531 else 12532 ret = scf_iter_service_pgs(iter, cur_svc); 12533 if (ret != SCF_SUCCESS) 12534 scfdie(); 12535 12536 while ((ret = scf_iter_next_pg(iter, pg)) == 1) { 12537 int ret2; 12538 12539 /* 12540 * # delprop pg 12541 * # addpg pg type 12542 */ 12543 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0) 12544 scfdie(); 12545 12546 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0) 12547 scfdie(); 12548 12549 if (fprintf(strm, "# Property group \"%s\"\n" 12550 "# delprop %s\n" 12551 "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) { 12552 warn(emsg_write_error, strerror(errno)); 12553 result = -1; 12554 goto out; 12555 } 12556 12557 /* # setprop pg/prop = (values) */ 12558 12559 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS) 12560 scfdie(); 12561 12562 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) { 12563 int first = 1; 12564 int ret3; 12565 int multiple; 12566 int is_str; 12567 scf_type_t bty; 12568 12569 if (scf_property_get_name(prop, pname, 12570 max_scf_name_len + 1) < 0) 12571 scfdie(); 12572 12573 if (scf_property_type(prop, &ty) != 0) 12574 scfdie(); 12575 12576 multiple = prop_has_multiple_values(prop, val); 12577 12578 if (fprintf(strm, "# setprop %s/%s = %s: %s", buf, 12579 pname, scf_type_to_string(ty), multiple ? "(" : "") 12580 < 0) { 12581 warn(emsg_write_error, strerror(errno)); 12582 result = -1; 12583 goto out; 12584 } 12585 12586 (void) scf_type_base_type(ty, &bty); 12587 is_str = (bty == SCF_TYPE_ASTRING); 12588 12589 if (scf_iter_property_values(viter, prop) != 12590 SCF_SUCCESS) 12591 scfdie(); 12592 12593 while ((ret3 = scf_iter_next_value(viter, val)) == 1) { 12594 char *buf; 12595 ssize_t buflen; 12596 12597 buflen = scf_value_get_as_string(val, NULL, 0); 12598 if (buflen < 0) 12599 scfdie(); 12600 12601 buf = safe_malloc(buflen + 1); 12602 12603 if (scf_value_get_as_string(val, buf, 12604 buflen + 1) < 0) 12605 scfdie(); 12606 12607 if (first) 12608 first = 0; 12609 else { 12610 if (putc(' ', strm) != ' ') { 12611 warn(emsg_write_error, 12612 strerror(errno)); 12613 result = -1; 12614 goto out; 12615 } 12616 } 12617 12618 if ((is_str && multiple) || 12619 strpbrk(buf, CHARS_TO_QUOTE) != NULL) { 12620 (void) putc('"', strm); 12621 (void) quote_and_print(buf, strm, 1); 12622 (void) putc('"', strm); 12623 12624 if (ferror(strm)) { 12625 warn(emsg_write_error, 12626 strerror(errno)); 12627 result = -1; 12628 goto out; 12629 } 12630 } else { 12631 if (fprintf(strm, "%s", buf) < 0) { 12632 warn(emsg_write_error, 12633 strerror(errno)); 12634 result = -1; 12635 goto out; 12636 } 12637 } 12638 12639 free(buf); 12640 } 12641 if (ret3 < 0 && 12642 scf_error() != SCF_ERROR_PERMISSION_DENIED) 12643 scfdie(); 12644 12645 /* Write closing paren if mult-value property */ 12646 if ((multiple && putc(')', strm) == EOF) || 12647 12648 /* Write final newline */ 12649 fputc('\n', strm) == EOF) { 12650 warn(emsg_write_error, strerror(errno)); 12651 result = -1; 12652 goto out; 12653 } 12654 } 12655 if (ret2 < 0) 12656 scfdie(); 12657 12658 if (fputc('\n', strm) == EOF) { 12659 warn(emsg_write_error, strerror(errno)); 12660 result = -1; 12661 goto out; 12662 } 12663 } 12664 if (ret < 0) 12665 scfdie(); 12666 12667 out: 12668 free(pname); 12669 free(tybuf); 12670 free(buf); 12671 scf_iter_destroy(viter); 12672 scf_iter_destroy(piter); 12673 scf_iter_destroy(iter); 12674 scf_value_destroy(val); 12675 scf_property_destroy(prop); 12676 scf_pg_destroy(pg); 12677 12678 if (result == 0) { 12679 if (fflush(strm) != 0) { 12680 warn(emsg_write_error, strerror(errno)); 12681 return (-1); 12682 } 12683 } 12684 12685 return (result); 12686 } 12687 12688 int 12689 lscf_editprop() 12690 { 12691 char *buf, *editor; 12692 size_t bufsz; 12693 int tmpfd; 12694 char tempname[] = TEMP_FILE_PATTERN; 12695 12696 lscf_prep_hndl(); 12697 12698 if (cur_snap != NULL) { 12699 semerr(emsg_cant_modify_snapshots); 12700 return (-1); 12701 } 12702 12703 if (cur_svc == NULL && cur_inst == NULL) { 12704 semerr(emsg_entity_not_selected); 12705 return (-1); 12706 } 12707 12708 tmpfd = mkstemp(tempname); 12709 if (tmpfd == -1) { 12710 semerr(gettext("Could not create temporary file.\n")); 12711 return (-1); 12712 } 12713 12714 (void) strcpy(tempfilename, tempname); 12715 12716 tempfile = fdopen(tmpfd, "r+"); 12717 if (tempfile == NULL) { 12718 warn(gettext("Could not create temporary file.\n")); 12719 if (close(tmpfd) == -1) 12720 warn(gettext("Could not close temporary file: %s.\n"), 12721 strerror(errno)); 12722 12723 remove_tempfile(); 12724 12725 return (-1); 12726 } 12727 12728 if (write_edit_script(tempfile) == -1) { 12729 remove_tempfile(); 12730 return (-1); 12731 } 12732 12733 editor = getenv("EDITOR"); 12734 if (editor == NULL) 12735 editor = "vi"; 12736 12737 bufsz = strlen(editor) + 1 + strlen(tempname) + 1; 12738 buf = safe_malloc(bufsz); 12739 12740 if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0) 12741 uu_die(gettext("Error creating editor command")); 12742 12743 if (system(buf) == -1) { 12744 semerr(gettext("Could not launch editor %s: %s\n"), editor, 12745 strerror(errno)); 12746 free(buf); 12747 remove_tempfile(); 12748 return (-1); 12749 } 12750 12751 free(buf); 12752 12753 (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE); 12754 12755 remove_tempfile(); 12756 12757 return (0); 12758 } 12759 12760 static void 12761 add_string(uu_list_t *strlist, const char *str) 12762 { 12763 string_list_t *elem; 12764 elem = safe_malloc(sizeof (*elem)); 12765 uu_list_node_init(elem, &elem->node, string_pool); 12766 elem->str = safe_strdup(str); 12767 if (uu_list_append(strlist, elem) != 0) 12768 uu_die(gettext("libuutil error: %s\n"), 12769 uu_strerror(uu_error())); 12770 } 12771 12772 /* 12773 * Get all property values that don't match the given glob pattern, 12774 * if a pattern is specified. 12775 */ 12776 static void 12777 get_prop_values(scf_property_t *prop, uu_list_t *values, 12778 const char *pattern) 12779 { 12780 scf_iter_t *iter; 12781 scf_value_t *val; 12782 int ret; 12783 12784 if ((iter = scf_iter_create(g_hndl)) == NULL || 12785 (val = scf_value_create(g_hndl)) == NULL) 12786 scfdie(); 12787 12788 if (scf_iter_property_values(iter, prop) != 0) 12789 scfdie(); 12790 12791 while ((ret = scf_iter_next_value(iter, val)) == 1) { 12792 char *buf; 12793 ssize_t vlen, szret; 12794 12795 vlen = scf_value_get_as_string(val, NULL, 0); 12796 if (vlen < 0) 12797 scfdie(); 12798 12799 buf = safe_malloc(vlen + 1); 12800 12801 szret = scf_value_get_as_string(val, buf, vlen + 1); 12802 if (szret < 0) 12803 scfdie(); 12804 assert(szret <= vlen); 12805 12806 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0) 12807 add_string(values, buf); 12808 12809 free(buf); 12810 } 12811 12812 if (ret == -1) 12813 scfdie(); 12814 12815 scf_value_destroy(val); 12816 scf_iter_destroy(iter); 12817 } 12818 12819 static int 12820 lscf_setpropvalue(const char *pgname, const char *type, 12821 const char *arg, int isadd, int isnotfoundok) 12822 { 12823 scf_type_t ty; 12824 scf_propertygroup_t *pg; 12825 scf_property_t *prop; 12826 int ret, result = 0; 12827 scf_transaction_t *tx; 12828 scf_transaction_entry_t *e; 12829 scf_value_t *v; 12830 string_list_t *sp; 12831 char *propname; 12832 uu_list_t *values; 12833 uu_list_walk_t *walk; 12834 void *cookie = NULL; 12835 char *pattern = NULL; 12836 12837 lscf_prep_hndl(); 12838 12839 if ((values = uu_list_create(string_pool, NULL, 0)) == NULL) 12840 uu_die(gettext("Could not create property list: %s\n"), 12841 uu_strerror(uu_error())); 12842 12843 if (!isadd) 12844 pattern = safe_strdup(arg); 12845 12846 if ((e = scf_entry_create(g_hndl)) == NULL || 12847 (pg = scf_pg_create(g_hndl)) == NULL || 12848 (prop = scf_property_create(g_hndl)) == NULL || 12849 (tx = scf_transaction_create(g_hndl)) == NULL) 12850 scfdie(); 12851 12852 if (cur_snap != NULL) { 12853 semerr(emsg_cant_modify_snapshots); 12854 goto fail; 12855 } 12856 12857 if (cur_inst == NULL && cur_svc == NULL) { 12858 semerr(emsg_entity_not_selected); 12859 goto fail; 12860 } 12861 12862 propname = strchr(pgname, '/'); 12863 if (propname == NULL) { 12864 semerr(gettext("Property names must contain a `/'.\n")); 12865 goto fail; 12866 } 12867 12868 *propname = '\0'; 12869 ++propname; 12870 12871 if (type != NULL) { 12872 ty = string_to_type(type); 12873 if (ty == SCF_TYPE_INVALID) { 12874 semerr(gettext("Unknown type \"%s\".\n"), type); 12875 goto fail; 12876 } 12877 } 12878 12879 if (cur_inst != NULL) 12880 ret = scf_instance_get_pg(cur_inst, pgname, pg); 12881 else 12882 ret = scf_service_get_pg(cur_svc, pgname, pg); 12883 if (ret != 0) { 12884 switch (scf_error()) { 12885 case SCF_ERROR_NOT_FOUND: 12886 if (isnotfoundok) { 12887 result = 0; 12888 } else { 12889 semerr(emsg_no_such_pg, pgname); 12890 result = -1; 12891 } 12892 goto out; 12893 12894 case SCF_ERROR_INVALID_ARGUMENT: 12895 semerr(emsg_invalid_pg_name, pgname); 12896 goto fail; 12897 12898 default: 12899 scfdie(); 12900 } 12901 } 12902 12903 do { 12904 if (scf_pg_update(pg) == -1) 12905 scfdie(); 12906 if (scf_transaction_start(tx, pg) != 0) { 12907 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 12908 scfdie(); 12909 12910 semerr(emsg_permission_denied); 12911 goto fail; 12912 } 12913 12914 ret = scf_pg_get_property(pg, propname, prop); 12915 if (ret == 0) { 12916 scf_type_t ptype; 12917 char *pat = pattern; 12918 12919 if (scf_property_type(prop, &ptype) != 0) 12920 scfdie(); 12921 12922 if (isadd) { 12923 if (type != NULL && ptype != ty) { 12924 semerr(gettext("Property \"%s\" is not " 12925 "of type \"%s\".\n"), propname, 12926 type); 12927 goto fail; 12928 } 12929 12930 pat = NULL; 12931 } else { 12932 size_t len = strlen(pat); 12933 if (len > 0 && pat[len - 1] == '\"') 12934 pat[len - 1] = '\0'; 12935 if (len > 0 && pat[0] == '\"') 12936 pat++; 12937 } 12938 12939 ty = ptype; 12940 12941 get_prop_values(prop, values, pat); 12942 12943 if (isadd) 12944 add_string(values, arg); 12945 12946 if (scf_transaction_property_change(tx, e, 12947 propname, ty) == -1) 12948 scfdie(); 12949 } else if (scf_error() == SCF_ERROR_NOT_FOUND) { 12950 if (isadd) { 12951 if (type == NULL) { 12952 semerr(gettext("Type required " 12953 "for new properties.\n")); 12954 goto fail; 12955 } 12956 12957 add_string(values, arg); 12958 12959 if (scf_transaction_property_new(tx, e, 12960 propname, ty) == -1) 12961 scfdie(); 12962 } else if (isnotfoundok) { 12963 result = 0; 12964 goto out; 12965 } else { 12966 semerr(gettext("No such property %s/%s.\n"), 12967 pgname, propname); 12968 result = -1; 12969 goto out; 12970 } 12971 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) { 12972 semerr(emsg_invalid_prop_name, propname); 12973 goto fail; 12974 } else { 12975 scfdie(); 12976 } 12977 12978 walk = uu_list_walk_start(values, UU_DEFAULT); 12979 if (walk == NULL) 12980 uu_die(gettext("Could not walk property list.\n")); 12981 12982 for (sp = uu_list_walk_next(walk); sp != NULL; 12983 sp = uu_list_walk_next(walk)) { 12984 v = string_to_value(sp->str, ty, 0); 12985 12986 if (v == NULL) { 12987 scf_entry_destroy_children(e); 12988 goto fail; 12989 } 12990 ret = scf_entry_add_value(e, v); 12991 assert(ret == 0); 12992 } 12993 uu_list_walk_end(walk); 12994 12995 result = scf_transaction_commit(tx); 12996 12997 scf_transaction_reset(tx); 12998 scf_entry_destroy_children(e); 12999 } while (result == 0); 13000 13001 if (result < 0) { 13002 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13003 scfdie(); 13004 13005 semerr(emsg_permission_denied); 13006 goto fail; 13007 } 13008 13009 result = 0; 13010 13011 private_refresh(); 13012 13013 out: 13014 scf_transaction_destroy(tx); 13015 scf_entry_destroy(e); 13016 scf_pg_destroy(pg); 13017 scf_property_destroy(prop); 13018 free(pattern); 13019 13020 while ((sp = uu_list_teardown(values, &cookie)) != NULL) { 13021 free(sp->str); 13022 free(sp); 13023 } 13024 13025 uu_list_destroy(values); 13026 13027 return (result); 13028 13029 fail: 13030 result = -1; 13031 goto out; 13032 } 13033 13034 int 13035 lscf_addpropvalue(const char *pgname, const char *type, const char *value) 13036 { 13037 return (lscf_setpropvalue(pgname, type, value, 1, 0)); 13038 } 13039 13040 int 13041 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok) 13042 { 13043 return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok)); 13044 } 13045 13046 /* 13047 * Look for a standard start method, first in the instance (if any), 13048 * then the service. 13049 */ 13050 static const char * 13051 start_method_name(int *in_instance) 13052 { 13053 scf_propertygroup_t *pg; 13054 char **p; 13055 int ret; 13056 scf_instance_t *inst = cur_inst; 13057 13058 if ((pg = scf_pg_create(g_hndl)) == NULL) 13059 scfdie(); 13060 13061 again: 13062 for (p = start_method_names; *p != NULL; p++) { 13063 if (inst != NULL) 13064 ret = scf_instance_get_pg(inst, *p, pg); 13065 else 13066 ret = scf_service_get_pg(cur_svc, *p, pg); 13067 13068 if (ret == 0) { 13069 size_t bufsz = strlen(SCF_GROUP_METHOD) + 1; 13070 char *buf = safe_malloc(bufsz); 13071 13072 if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) { 13073 free(buf); 13074 continue; 13075 } 13076 if (strcmp(buf, SCF_GROUP_METHOD) != 0) { 13077 free(buf); 13078 continue; 13079 } 13080 13081 free(buf); 13082 *in_instance = (inst != NULL); 13083 scf_pg_destroy(pg); 13084 return (*p); 13085 } 13086 13087 if (scf_error() == SCF_ERROR_NOT_FOUND) 13088 continue; 13089 13090 scfdie(); 13091 } 13092 13093 if (inst != NULL) { 13094 inst = NULL; 13095 goto again; 13096 } 13097 13098 scf_pg_destroy(pg); 13099 return (NULL); 13100 } 13101 13102 static int 13103 addpg(const char *name, const char *type) 13104 { 13105 scf_propertygroup_t *pg; 13106 int ret; 13107 13108 pg = scf_pg_create(g_hndl); 13109 if (pg == NULL) 13110 scfdie(); 13111 13112 if (cur_inst != NULL) 13113 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg); 13114 else 13115 ret = scf_service_add_pg(cur_svc, name, type, 0, pg); 13116 13117 if (ret != 0) { 13118 switch (scf_error()) { 13119 case SCF_ERROR_EXISTS: 13120 ret = 0; 13121 break; 13122 13123 case SCF_ERROR_PERMISSION_DENIED: 13124 semerr(emsg_permission_denied); 13125 break; 13126 13127 default: 13128 scfdie(); 13129 } 13130 } 13131 13132 scf_pg_destroy(pg); 13133 return (ret); 13134 } 13135 13136 int 13137 lscf_setenv(uu_list_t *args, int isunset) 13138 { 13139 int ret = 0; 13140 size_t i; 13141 int argc; 13142 char **argv = NULL; 13143 string_list_t *slp; 13144 char *pattern; 13145 char *prop; 13146 int do_service = 0; 13147 int do_instance = 0; 13148 const char *method = NULL; 13149 const char *name = NULL; 13150 const char *value = NULL; 13151 scf_instance_t *saved_cur_inst = cur_inst; 13152 13153 lscf_prep_hndl(); 13154 13155 argc = uu_list_numnodes(args); 13156 if (argc < 1) 13157 goto usage; 13158 13159 argv = calloc(argc + 1, sizeof (char *)); 13160 if (argv == NULL) 13161 uu_die(gettext("Out of memory.\n")); 13162 13163 for (slp = uu_list_first(args), i = 0; 13164 slp != NULL; 13165 slp = uu_list_next(args, slp), ++i) 13166 argv[i] = slp->str; 13167 13168 argv[i] = NULL; 13169 13170 opterr = 0; 13171 optind = 0; 13172 for (;;) { 13173 ret = getopt(argc, argv, "sim:"); 13174 if (ret == -1) 13175 break; 13176 13177 switch (ret) { 13178 case 's': 13179 do_service = 1; 13180 cur_inst = NULL; 13181 break; 13182 13183 case 'i': 13184 do_instance = 1; 13185 break; 13186 13187 case 'm': 13188 method = optarg; 13189 break; 13190 13191 case '?': 13192 goto usage; 13193 13194 default: 13195 bad_error("getopt", ret); 13196 } 13197 } 13198 13199 argc -= optind; 13200 if ((do_service && do_instance) || 13201 (isunset && argc != 1) || 13202 (!isunset && argc != 2)) 13203 goto usage; 13204 13205 name = argv[optind]; 13206 if (!isunset) 13207 value = argv[optind + 1]; 13208 13209 if (cur_snap != NULL) { 13210 semerr(emsg_cant_modify_snapshots); 13211 ret = -1; 13212 goto out; 13213 } 13214 13215 if (cur_inst == NULL && cur_svc == NULL) { 13216 semerr(emsg_entity_not_selected); 13217 ret = -1; 13218 goto out; 13219 } 13220 13221 if (do_instance && cur_inst == NULL) { 13222 semerr(gettext("No instance is selected.\n")); 13223 ret = -1; 13224 goto out; 13225 } 13226 13227 if (do_service && cur_svc == NULL) { 13228 semerr(gettext("No service is selected.\n")); 13229 ret = -1; 13230 goto out; 13231 } 13232 13233 if (method == NULL) { 13234 if (do_instance || do_service) { 13235 method = "method_context"; 13236 if (!isunset) { 13237 ret = addpg("method_context", 13238 SCF_GROUP_FRAMEWORK); 13239 if (ret != 0) 13240 goto out; 13241 } 13242 } else { 13243 int in_instance; 13244 method = start_method_name(&in_instance); 13245 if (method == NULL) { 13246 semerr(gettext( 13247 "Couldn't find start method; please " 13248 "specify a method with '-m'.\n")); 13249 ret = -1; 13250 goto out; 13251 } 13252 if (!in_instance) 13253 cur_inst = NULL; 13254 } 13255 } else { 13256 scf_propertygroup_t *pg; 13257 size_t bufsz; 13258 char *buf; 13259 int ret; 13260 13261 if ((pg = scf_pg_create(g_hndl)) == NULL) 13262 scfdie(); 13263 13264 if (cur_inst != NULL) 13265 ret = scf_instance_get_pg(cur_inst, method, pg); 13266 else 13267 ret = scf_service_get_pg(cur_svc, method, pg); 13268 13269 if (ret != 0) { 13270 scf_pg_destroy(pg); 13271 switch (scf_error()) { 13272 case SCF_ERROR_NOT_FOUND: 13273 semerr(gettext("Couldn't find the method " 13274 "\"%s\".\n"), method); 13275 goto out; 13276 13277 case SCF_ERROR_INVALID_ARGUMENT: 13278 semerr(gettext("Invalid method name \"%s\".\n"), 13279 method); 13280 goto out; 13281 13282 default: 13283 scfdie(); 13284 } 13285 } 13286 13287 bufsz = strlen(SCF_GROUP_METHOD) + 1; 13288 buf = safe_malloc(bufsz); 13289 13290 if (scf_pg_get_type(pg, buf, bufsz) < 0 || 13291 strcmp(buf, SCF_GROUP_METHOD) != 0) { 13292 semerr(gettext("Property group \"%s\" is not of type " 13293 "\"method\".\n"), method); 13294 ret = -1; 13295 free(buf); 13296 scf_pg_destroy(pg); 13297 goto out; 13298 } 13299 13300 free(buf); 13301 scf_pg_destroy(pg); 13302 } 13303 13304 prop = uu_msprintf("%s/environment", method); 13305 pattern = uu_msprintf("%s=*", name); 13306 13307 if (prop == NULL || pattern == NULL) 13308 uu_die(gettext("Out of memory.\n")); 13309 13310 ret = lscf_delpropvalue(prop, pattern, !isunset); 13311 13312 if (ret == 0 && !isunset) { 13313 uu_free(pattern); 13314 uu_free(prop); 13315 prop = uu_msprintf("%s/environment", method); 13316 pattern = uu_msprintf("%s=%s", name, value); 13317 if (prop == NULL || pattern == NULL) 13318 uu_die(gettext("Out of memory.\n")); 13319 ret = lscf_addpropvalue(prop, "astring:", pattern); 13320 } 13321 uu_free(pattern); 13322 uu_free(prop); 13323 13324 out: 13325 cur_inst = saved_cur_inst; 13326 13327 free(argv); 13328 return (ret); 13329 usage: 13330 ret = -2; 13331 goto out; 13332 } 13333 13334 /* 13335 * Snapshot commands 13336 */ 13337 13338 void 13339 lscf_listsnap() 13340 { 13341 scf_snapshot_t *snap; 13342 scf_iter_t *iter; 13343 char *nb; 13344 int r; 13345 13346 lscf_prep_hndl(); 13347 13348 if (cur_inst == NULL) { 13349 semerr(gettext("Instance not selected.\n")); 13350 return; 13351 } 13352 13353 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13354 (iter = scf_iter_create(g_hndl)) == NULL) 13355 scfdie(); 13356 13357 if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS) 13358 scfdie(); 13359 13360 nb = safe_malloc(max_scf_name_len + 1); 13361 13362 while ((r = scf_iter_next_snapshot(iter, snap)) == 1) { 13363 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0) 13364 scfdie(); 13365 13366 (void) puts(nb); 13367 } 13368 if (r < 0) 13369 scfdie(); 13370 13371 free(nb); 13372 scf_iter_destroy(iter); 13373 scf_snapshot_destroy(snap); 13374 } 13375 13376 void 13377 lscf_selectsnap(const char *name) 13378 { 13379 scf_snapshot_t *snap; 13380 scf_snaplevel_t *level; 13381 13382 lscf_prep_hndl(); 13383 13384 if (cur_inst == NULL) { 13385 semerr(gettext("Instance not selected.\n")); 13386 return; 13387 } 13388 13389 if (cur_snap != NULL) { 13390 if (name != NULL) { 13391 char *cur_snap_name; 13392 boolean_t nochange; 13393 13394 cur_snap_name = safe_malloc(max_scf_name_len + 1); 13395 13396 if (scf_snapshot_get_name(cur_snap, cur_snap_name, 13397 max_scf_name_len + 1) < 0) 13398 scfdie(); 13399 13400 nochange = strcmp(name, cur_snap_name) == 0; 13401 13402 free(cur_snap_name); 13403 13404 if (nochange) 13405 return; 13406 } 13407 13408 unselect_cursnap(); 13409 } 13410 13411 if (name == NULL) 13412 return; 13413 13414 if ((snap = scf_snapshot_create(g_hndl)) == NULL || 13415 (level = scf_snaplevel_create(g_hndl)) == NULL) 13416 scfdie(); 13417 13418 if (scf_instance_get_snapshot(cur_inst, name, snap) != 13419 SCF_SUCCESS) { 13420 switch (scf_error()) { 13421 case SCF_ERROR_INVALID_ARGUMENT: 13422 semerr(gettext("Invalid name \"%s\".\n"), name); 13423 break; 13424 13425 case SCF_ERROR_NOT_FOUND: 13426 semerr(gettext("No such snapshot \"%s\".\n"), name); 13427 break; 13428 13429 default: 13430 scfdie(); 13431 } 13432 13433 scf_snaplevel_destroy(level); 13434 scf_snapshot_destroy(snap); 13435 return; 13436 } 13437 13438 /* Load the snaplevels into our list. */ 13439 cur_levels = uu_list_create(snaplevel_pool, NULL, 0); 13440 if (cur_levels == NULL) 13441 uu_die(gettext("Could not create list: %s\n"), 13442 uu_strerror(uu_error())); 13443 13444 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 13445 if (scf_error() != SCF_ERROR_NOT_FOUND) 13446 scfdie(); 13447 13448 semerr(gettext("Snapshot has no snaplevels.\n")); 13449 13450 scf_snaplevel_destroy(level); 13451 scf_snapshot_destroy(snap); 13452 return; 13453 } 13454 13455 cur_snap = snap; 13456 13457 for (;;) { 13458 cur_elt = safe_malloc(sizeof (*cur_elt)); 13459 uu_list_node_init(cur_elt, &cur_elt->list_node, 13460 snaplevel_pool); 13461 cur_elt->sl = level; 13462 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0) 13463 uu_die(gettext("libuutil error: %s\n"), 13464 uu_strerror(uu_error())); 13465 13466 level = scf_snaplevel_create(g_hndl); 13467 if (level == NULL) 13468 scfdie(); 13469 13470 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl, 13471 level) != SCF_SUCCESS) { 13472 if (scf_error() != SCF_ERROR_NOT_FOUND) 13473 scfdie(); 13474 13475 scf_snaplevel_destroy(level); 13476 break; 13477 } 13478 } 13479 13480 cur_elt = uu_list_last(cur_levels); 13481 cur_level = cur_elt->sl; 13482 } 13483 13484 /* 13485 * Copies the properties & values in src to dst. Assumes src won't change. 13486 * Returns -1 if permission is denied, -2 if another transaction interrupts, 13487 * and 0 on success. 13488 * 13489 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED 13490 * property, if it is copied and has type boolean. (See comment in 13491 * lscf_revert()). 13492 */ 13493 static int 13494 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst, 13495 uint8_t enabled) 13496 { 13497 scf_transaction_t *tx; 13498 scf_iter_t *iter, *viter; 13499 scf_property_t *prop; 13500 scf_value_t *v; 13501 char *nbuf; 13502 int r; 13503 13504 tx = scf_transaction_create(g_hndl); 13505 if (tx == NULL) 13506 scfdie(); 13507 13508 if (scf_transaction_start(tx, dst) != SCF_SUCCESS) { 13509 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13510 scfdie(); 13511 13512 scf_transaction_destroy(tx); 13513 13514 return (-1); 13515 } 13516 13517 if ((iter = scf_iter_create(g_hndl)) == NULL || 13518 (prop = scf_property_create(g_hndl)) == NULL || 13519 (viter = scf_iter_create(g_hndl)) == NULL) 13520 scfdie(); 13521 13522 nbuf = safe_malloc(max_scf_name_len + 1); 13523 13524 if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS) 13525 scfdie(); 13526 13527 for (;;) { 13528 scf_transaction_entry_t *e; 13529 scf_type_t ty; 13530 13531 r = scf_iter_next_property(iter, prop); 13532 if (r == -1) 13533 scfdie(); 13534 if (r == 0) 13535 break; 13536 13537 e = scf_entry_create(g_hndl); 13538 if (e == NULL) 13539 scfdie(); 13540 13541 if (scf_property_type(prop, &ty) != SCF_SUCCESS) 13542 scfdie(); 13543 13544 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0) 13545 scfdie(); 13546 13547 if (scf_transaction_property_new(tx, e, nbuf, 13548 ty) != SCF_SUCCESS) 13549 scfdie(); 13550 13551 if ((enabled == 0 || enabled == 1) && 13552 strcmp(nbuf, scf_property_enabled) == 0 && 13553 ty == SCF_TYPE_BOOLEAN) { 13554 v = scf_value_create(g_hndl); 13555 if (v == NULL) 13556 scfdie(); 13557 13558 scf_value_set_boolean(v, enabled); 13559 13560 if (scf_entry_add_value(e, v) != 0) 13561 scfdie(); 13562 } else { 13563 if (scf_iter_property_values(viter, prop) != 0) 13564 scfdie(); 13565 13566 for (;;) { 13567 v = scf_value_create(g_hndl); 13568 if (v == NULL) 13569 scfdie(); 13570 13571 r = scf_iter_next_value(viter, v); 13572 if (r == -1) 13573 scfdie(); 13574 if (r == 0) { 13575 scf_value_destroy(v); 13576 break; 13577 } 13578 13579 if (scf_entry_add_value(e, v) != SCF_SUCCESS) 13580 scfdie(); 13581 } 13582 } 13583 } 13584 13585 free(nbuf); 13586 scf_iter_destroy(viter); 13587 scf_property_destroy(prop); 13588 scf_iter_destroy(iter); 13589 13590 r = scf_transaction_commit(tx); 13591 if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED) 13592 scfdie(); 13593 13594 scf_transaction_destroy_children(tx); 13595 scf_transaction_destroy(tx); 13596 13597 switch (r) { 13598 case 1: return (0); 13599 case 0: return (-2); 13600 case -1: return (-1); 13601 13602 default: 13603 abort(); 13604 } 13605 13606 /* NOTREACHED */ 13607 } 13608 13609 void 13610 lscf_revert(const char *snapname) 13611 { 13612 scf_snapshot_t *snap, *prev; 13613 scf_snaplevel_t *level, *nlevel; 13614 scf_iter_t *iter; 13615 scf_propertygroup_t *pg, *npg; 13616 scf_property_t *prop; 13617 scf_value_t *val; 13618 char *nbuf, *tbuf; 13619 uint8_t enabled; 13620 13621 lscf_prep_hndl(); 13622 13623 if (cur_inst == NULL) { 13624 semerr(gettext("Instance not selected.\n")); 13625 return; 13626 } 13627 13628 if (snapname != NULL) { 13629 snap = scf_snapshot_create(g_hndl); 13630 if (snap == NULL) 13631 scfdie(); 13632 13633 if (scf_instance_get_snapshot(cur_inst, snapname, snap) != 13634 SCF_SUCCESS) { 13635 switch (scf_error()) { 13636 case SCF_ERROR_INVALID_ARGUMENT: 13637 semerr(gettext("Invalid snapshot name " 13638 "\"%s\".\n"), snapname); 13639 break; 13640 13641 case SCF_ERROR_NOT_FOUND: 13642 semerr(gettext("No such snapshot.\n")); 13643 break; 13644 13645 default: 13646 scfdie(); 13647 } 13648 13649 scf_snapshot_destroy(snap); 13650 return; 13651 } 13652 } else { 13653 if (cur_snap != NULL) { 13654 snap = cur_snap; 13655 } else { 13656 semerr(gettext("No snapshot selected.\n")); 13657 return; 13658 } 13659 } 13660 13661 if ((prev = scf_snapshot_create(g_hndl)) == NULL || 13662 (level = scf_snaplevel_create(g_hndl)) == NULL || 13663 (iter = scf_iter_create(g_hndl)) == NULL || 13664 (pg = scf_pg_create(g_hndl)) == NULL || 13665 (npg = scf_pg_create(g_hndl)) == NULL || 13666 (prop = scf_property_create(g_hndl)) == NULL || 13667 (val = scf_value_create(g_hndl)) == NULL) 13668 scfdie(); 13669 13670 nbuf = safe_malloc(max_scf_name_len + 1); 13671 tbuf = safe_malloc(max_scf_pg_type_len + 1); 13672 13673 /* Take the "previous" snapshot before we blow away the properties. */ 13674 if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) { 13675 if (_scf_snapshot_take_attach(cur_inst, prev) != 0) 13676 scfdie(); 13677 } else { 13678 if (scf_error() != SCF_ERROR_NOT_FOUND) 13679 scfdie(); 13680 13681 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0) 13682 scfdie(); 13683 } 13684 13685 /* Save general/enabled, since we're probably going to replace it. */ 13686 enabled = 2; 13687 if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 && 13688 scf_pg_get_property(pg, scf_property_enabled, prop) == 0 && 13689 scf_property_get_value(prop, val) == 0) 13690 (void) scf_value_get_boolean(val, &enabled); 13691 13692 if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) { 13693 if (scf_error() != SCF_ERROR_NOT_FOUND) 13694 scfdie(); 13695 13696 goto out; 13697 } 13698 13699 for (;;) { 13700 boolean_t isinst; 13701 uint32_t flags; 13702 int r; 13703 13704 /* Clear the properties from the corresponding entity. */ 13705 isinst = snaplevel_is_instance(level); 13706 13707 if (!isinst) 13708 r = scf_iter_service_pgs(iter, cur_svc); 13709 else 13710 r = scf_iter_instance_pgs(iter, cur_inst); 13711 if (r != SCF_SUCCESS) 13712 scfdie(); 13713 13714 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 13715 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 13716 scfdie(); 13717 13718 /* Skip nonpersistent pgs. */ 13719 if (flags & SCF_PG_FLAG_NONPERSISTENT) 13720 continue; 13721 13722 if (scf_pg_delete(pg) != SCF_SUCCESS) { 13723 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13724 scfdie(); 13725 13726 semerr(emsg_permission_denied); 13727 goto out; 13728 } 13729 } 13730 if (r == -1) 13731 scfdie(); 13732 13733 /* Copy the properties to the corresponding entity. */ 13734 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS) 13735 scfdie(); 13736 13737 while ((r = scf_iter_next_pg(iter, pg)) == 1) { 13738 if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0) 13739 scfdie(); 13740 13741 if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) < 13742 0) 13743 scfdie(); 13744 13745 if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS) 13746 scfdie(); 13747 13748 if (!isinst) 13749 r = scf_service_add_pg(cur_svc, nbuf, tbuf, 13750 flags, npg); 13751 else 13752 r = scf_instance_add_pg(cur_inst, nbuf, tbuf, 13753 flags, npg); 13754 if (r != SCF_SUCCESS) { 13755 if (scf_error() != SCF_ERROR_PERMISSION_DENIED) 13756 scfdie(); 13757 13758 semerr(emsg_permission_denied); 13759 goto out; 13760 } 13761 13762 if ((enabled == 0 || enabled == 1) && 13763 strcmp(nbuf, scf_pg_general) == 0) 13764 r = pg_copy(pg, npg, enabled); 13765 else 13766 r = pg_copy(pg, npg, 2); 13767 13768 switch (r) { 13769 case 0: 13770 break; 13771 13772 case -1: 13773 semerr(emsg_permission_denied); 13774 goto out; 13775 13776 case -2: 13777 semerr(gettext( 13778 "Interrupted by another change.\n")); 13779 goto out; 13780 13781 default: 13782 abort(); 13783 } 13784 } 13785 if (r == -1) 13786 scfdie(); 13787 13788 /* Get next level. */ 13789 nlevel = scf_snaplevel_create(g_hndl); 13790 if (nlevel == NULL) 13791 scfdie(); 13792 13793 if (scf_snaplevel_get_next_snaplevel(level, nlevel) != 13794 SCF_SUCCESS) { 13795 if (scf_error() != SCF_ERROR_NOT_FOUND) 13796 scfdie(); 13797 13798 scf_snaplevel_destroy(nlevel); 13799 break; 13800 } 13801 13802 scf_snaplevel_destroy(level); 13803 level = nlevel; 13804 } 13805 13806 if (snapname == NULL) { 13807 lscf_selectsnap(NULL); 13808 snap = NULL; /* cur_snap has been destroyed */ 13809 } 13810 13811 out: 13812 free(tbuf); 13813 free(nbuf); 13814 scf_value_destroy(val); 13815 scf_property_destroy(prop); 13816 scf_pg_destroy(npg); 13817 scf_pg_destroy(pg); 13818 scf_iter_destroy(iter); 13819 scf_snaplevel_destroy(level); 13820 scf_snapshot_destroy(prev); 13821 if (snap != cur_snap) 13822 scf_snapshot_destroy(snap); 13823 } 13824 13825 void 13826 lscf_refresh(void) 13827 { 13828 ssize_t fmrilen; 13829 size_t bufsz; 13830 char *fmribuf; 13831 int r; 13832 13833 lscf_prep_hndl(); 13834 13835 if (cur_inst == NULL) { 13836 semerr(gettext("Instance not selected.\n")); 13837 return; 13838 } 13839 13840 bufsz = max_scf_fmri_len + 1; 13841 fmribuf = safe_malloc(bufsz); 13842 fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz); 13843 if (fmrilen < 0) { 13844 free(fmribuf); 13845 if (scf_error() != SCF_ERROR_DELETED) 13846 scfdie(); 13847 scf_instance_destroy(cur_inst); 13848 cur_inst = NULL; 13849 warn(emsg_deleted); 13850 return; 13851 } 13852 assert(fmrilen < bufsz); 13853 13854 r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL); 13855 switch (r) { 13856 case 0: 13857 break; 13858 13859 case ECONNABORTED: 13860 warn(gettext("Could not refresh %s " 13861 "(repository connection broken).\n"), fmribuf); 13862 break; 13863 13864 case ECANCELED: 13865 warn(emsg_deleted); 13866 break; 13867 13868 case EPERM: 13869 warn(gettext("Could not refresh %s " 13870 "(permission denied).\n"), fmribuf); 13871 break; 13872 13873 case ENOSPC: 13874 warn(gettext("Could not refresh %s " 13875 "(repository server out of resources).\n"), 13876 fmribuf); 13877 break; 13878 13879 case EACCES: 13880 default: 13881 bad_error("refresh_entity", scf_error()); 13882 } 13883 13884 free(fmribuf); 13885 } 13886 13887 /* 13888 * describe [-v] [-t] [pg/prop] 13889 */ 13890 int 13891 lscf_describe(uu_list_t *args, int hasargs) 13892 { 13893 int ret = 0; 13894 size_t i; 13895 int argc; 13896 char **argv = NULL; 13897 string_list_t *slp; 13898 int do_verbose = 0; 13899 int do_templates = 0; 13900 char *pattern = NULL; 13901 13902 lscf_prep_hndl(); 13903 13904 if (hasargs != 0) { 13905 argc = uu_list_numnodes(args); 13906 if (argc < 1) 13907 goto usage; 13908 13909 argv = calloc(argc + 1, sizeof (char *)); 13910 if (argv == NULL) 13911 uu_die(gettext("Out of memory.\n")); 13912 13913 for (slp = uu_list_first(args), i = 0; 13914 slp != NULL; 13915 slp = uu_list_next(args, slp), ++i) 13916 argv[i] = slp->str; 13917 13918 argv[i] = NULL; 13919 13920 /* 13921 * We start optind = 0 because our list of arguments 13922 * starts at argv[0] 13923 */ 13924 optind = 0; 13925 opterr = 0; 13926 for (;;) { 13927 ret = getopt(argc, argv, "vt"); 13928 if (ret == -1) 13929 break; 13930 13931 switch (ret) { 13932 case 'v': 13933 do_verbose = 1; 13934 break; 13935 13936 case 't': 13937 do_templates = 1; 13938 break; 13939 13940 case '?': 13941 goto usage; 13942 13943 default: 13944 bad_error("getopt", ret); 13945 } 13946 } 13947 13948 pattern = argv[optind]; 13949 } 13950 13951 if (cur_inst == NULL && cur_svc == NULL) { 13952 semerr(emsg_entity_not_selected); 13953 ret = -1; 13954 goto out; 13955 } 13956 13957 /* 13958 * list_entity_tmpl(), listprop() and listtmpl() produce verbose 13959 * output if their last parameter is set to 2. Less information is 13960 * produced if the parameter is set to 1. 13961 */ 13962 if (pattern == NULL) { 13963 if (do_verbose == 1) 13964 list_entity_tmpl(2); 13965 else 13966 list_entity_tmpl(1); 13967 } 13968 13969 if (do_templates == 0) { 13970 if (do_verbose == 1) 13971 listprop(pattern, 0, 2); 13972 else 13973 listprop(pattern, 0, 1); 13974 } else { 13975 if (do_verbose == 1) 13976 listtmpl(pattern, 2); 13977 else 13978 listtmpl(pattern, 1); 13979 } 13980 13981 ret = 0; 13982 out: 13983 if (argv != NULL) 13984 free(argv); 13985 return (ret); 13986 usage: 13987 ret = -2; 13988 goto out; 13989 } 13990 13991 #ifndef NATIVE_BUILD 13992 /* ARGSUSED */ 13993 CPL_MATCH_FN(complete_select) 13994 { 13995 const char *arg0, *arg1, *arg1end; 13996 int word_start, err = 0, r; 13997 size_t len; 13998 char *buf; 13999 14000 lscf_prep_hndl(); 14001 14002 arg0 = line + strspn(line, " \t"); 14003 assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0); 14004 14005 arg1 = arg0 + sizeof ("select") - 1; 14006 arg1 += strspn(arg1, " \t"); 14007 word_start = arg1 - line; 14008 14009 arg1end = arg1 + strcspn(arg1, " \t"); 14010 if (arg1end < line + word_end) 14011 return (0); 14012 14013 len = line + word_end - arg1; 14014 14015 buf = safe_malloc(max_scf_name_len + 1); 14016 14017 if (cur_snap != NULL) { 14018 return (0); 14019 } else if (cur_inst != NULL) { 14020 return (0); 14021 } else if (cur_svc != NULL) { 14022 scf_instance_t *inst; 14023 scf_iter_t *iter; 14024 14025 if ((inst = scf_instance_create(g_hndl)) == NULL || 14026 (iter = scf_iter_create(g_hndl)) == NULL) 14027 scfdie(); 14028 14029 if (scf_iter_service_instances(iter, cur_svc) != 0) 14030 scfdie(); 14031 14032 for (;;) { 14033 r = scf_iter_next_instance(iter, inst); 14034 if (r == 0) 14035 break; 14036 if (r != 1) 14037 scfdie(); 14038 14039 if (scf_instance_get_name(inst, buf, 14040 max_scf_name_len + 1) < 0) 14041 scfdie(); 14042 14043 if (strncmp(buf, arg1, len) == 0) { 14044 err = cpl_add_completion(cpl, line, word_start, 14045 word_end, buf + len, "", " "); 14046 if (err != 0) 14047 break; 14048 } 14049 } 14050 14051 scf_iter_destroy(iter); 14052 scf_instance_destroy(inst); 14053 14054 return (err); 14055 } else { 14056 scf_service_t *svc; 14057 scf_iter_t *iter; 14058 14059 assert(cur_scope != NULL); 14060 14061 if ((svc = scf_service_create(g_hndl)) == NULL || 14062 (iter = scf_iter_create(g_hndl)) == NULL) 14063 scfdie(); 14064 14065 if (scf_iter_scope_services(iter, cur_scope) != 0) 14066 scfdie(); 14067 14068 for (;;) { 14069 r = scf_iter_next_service(iter, svc); 14070 if (r == 0) 14071 break; 14072 if (r != 1) 14073 scfdie(); 14074 14075 if (scf_service_get_name(svc, buf, 14076 max_scf_name_len + 1) < 0) 14077 scfdie(); 14078 14079 if (strncmp(buf, arg1, len) == 0) { 14080 err = cpl_add_completion(cpl, line, word_start, 14081 word_end, buf + len, "", " "); 14082 if (err != 0) 14083 break; 14084 } 14085 } 14086 14087 scf_iter_destroy(iter); 14088 scf_service_destroy(svc); 14089 14090 return (err); 14091 } 14092 } 14093 14094 /* ARGSUSED */ 14095 CPL_MATCH_FN(complete_command) 14096 { 14097 uint32_t scope = 0; 14098 14099 if (cur_snap != NULL) 14100 scope = CS_SNAP; 14101 else if (cur_inst != NULL) 14102 scope = CS_INST; 14103 else if (cur_svc != NULL) 14104 scope = CS_SVC; 14105 else 14106 scope = CS_SCOPE; 14107 14108 return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0); 14109 } 14110 #endif /* NATIVE_BUILD */ 14111