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