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