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