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