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